Merge branch 'master' of github.com:jtsiomb/pcboot
[bootcensus] / src / libc / dirent.c
diff --git a/src/libc/dirent.c b/src/libc/dirent.c
new file mode 100644 (file)
index 0000000..1af59fe
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018-2019  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY, without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "dirent.h"
+#include "fs.h"
+
+struct DIR {
+       struct fs_node *fsn;
+       struct dirent dent;
+};
+
+DIR *opendir(const char *path)
+{
+       DIR *dir;
+       struct fs_node *node;
+
+       if(!path) {
+               errno = EINVAL;
+               return 0;
+       }
+
+       if(!(node = fs_open(path, 0))) {
+               errno = ENOENT;
+               return 0;
+       }
+       if(node->type != FSNODE_DIR) {
+               errno = ENOTDIR;
+               fs_close(node);
+               return 0;
+       }
+
+       if(!(dir = malloc(sizeof *dir))) {
+               errno = ENOMEM;
+               fs_close(node);
+               return 0;
+       }
+       dir->fsn = node;
+
+       return dir;
+}
+
+int closedir(DIR *dir)
+{
+       if(!dir) {
+               errno = EINVAL;
+               return -1;
+       }
+       fs_close(dir->fsn);
+       free(dir);
+       return 0;
+}
+
+void rewinddir(DIR *dir)
+{
+       if(!dir) {
+               errno = EINVAL;
+               return;
+       }
+       fs_rewinddir(dir->fsn);
+}
+
+struct dirent *readdir(DIR *dir)
+{
+       struct fs_dirent *fsdent;
+
+       if(!dir) {
+               errno = EINVAL;
+               return 0;
+       }
+       if(!(fsdent = fs_readdir(dir->fsn))) {
+               return 0;
+       }
+
+       strcpy(dir->dent.d_name, fsdent->name);
+       dir->dent.d_type = fsdent->type == FSNODE_DIR ? DT_DIR : DT_REG;
+       dir->dent.d_fsize = fsdent->fsize;
+       return &dir->dent;
+}