From 8bf2904d7483397f88957694b78815fa6c128c7e Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 23 Oct 2022 14:41:45 +0200 Subject: [PATCH] libc: Implement a basic subset of dirent.h --- apps/src/ls.c | 24 +++++--------- kernel/include/fs/VFS.h | 4 ++- libs/libc/include/dirent.h | 43 ++++++++++++++++++++++++ libs/libc/include/luna/dirent.h | 3 +- libs/libc/include/luna/os-limits.h | 2 ++ libs/libc/src/dirent.cpp | 53 ++++++++++++++++++++++++++++++ 6 files changed, 112 insertions(+), 17 deletions(-) create mode 100644 libs/libc/include/dirent.h create mode 100644 libs/libc/src/dirent.cpp diff --git a/apps/src/ls.c b/apps/src/ls.c index 83ebaabb..6ecdd29b 100644 --- a/apps/src/ls.c +++ b/apps/src/ls.c @@ -1,28 +1,22 @@ +#include #include -#include #include #include int main() { - int dirfd = open("/bin", O_RDONLY); - if (dirfd < 0) + DIR* dp = opendir("/bin"); + if (!dp) { - perror("open"); + perror("opendir"); return 1; } - struct luna_dirent dirent[5]; - ssize_t nread; do { - nread = getdents(dirfd, dirent, 5); - if (nread < 0) - { - perror("getdents"); - return 1; - } - for (int i = 0; i < nread; i++) { printf("%s\n", dirent[i].name); } - } while (nread == 5); + struct dirent* ent = readdir(dp); + if (!ent) break; + printf("%s\n", ent->d_name); + } while (1); - close(dirfd); + closedir(dp); return 0; } \ No newline at end of file diff --git a/kernel/include/fs/VFS.h b/kernel/include/fs/VFS.h index cb1b6b1e..fbca4841 100644 --- a/kernel/include/fs/VFS.h +++ b/kernel/include/fs/VFS.h @@ -10,6 +10,8 @@ typedef long ssize_t; #define VFS_MOUNTPOINT 0x1 +#define NAME_MAX 64 + namespace VFS { struct Node; @@ -23,7 +25,7 @@ namespace VFS struct Node { - char name[64]; + char name[NAME_MAX]; uint64_t inode; uint64_t length; int type; diff --git a/libs/libc/include/dirent.h b/libs/libc/include/dirent.h new file mode 100644 index 00000000..c4192d5e --- /dev/null +++ b/libs/libc/include/dirent.h @@ -0,0 +1,43 @@ +#ifndef _DIRENT_H +#define _DIRENT_H + +#include +#include + +struct dirent +{ + ino_t d_ino; + off_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[NAME_MAX]; +}; + +typedef struct +{ + int d_dirfd; +} DIR; + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Opens the directory at path and returns a handle to it, or NULL on error. */ + DIR* opendir(const char* path); + + /* Returns a new directory handle associated with the file descriptor fd. */ + DIR* fdopendir(int fd); + + /* Closes the directory stream. */ + int closedir(DIR* stream); + + /* Reads an entry from the directory stream. The contents of the pointer returned may be overwritten by subsequent + * calls to readdir(). */ + struct dirent* readdir(DIR* stream); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/libs/libc/include/luna/dirent.h b/libs/libc/include/luna/dirent.h index c9c2555c..6b7f3237 100644 --- a/libs/libc/include/luna/dirent.h +++ b/libs/libc/include/luna/dirent.h @@ -1,12 +1,13 @@ #ifndef _LUNA_DIRENT_H #define _LUNA_DIRENT_H +#include #include struct luna_dirent { ino_t inode; - char name[64]; + char name[NAME_MAX]; size_t total; off_t offset; }; diff --git a/libs/libc/include/luna/os-limits.h b/libs/libc/include/luna/os-limits.h index fbf222f0..4d1ebb27 100644 --- a/libs/libc/include/luna/os-limits.h +++ b/libs/libc/include/luna/os-limits.h @@ -4,6 +4,8 @@ #define OPEN_MAX 32 #define ATEXIT_MAX 32 +#define NAME_MAX 64 + #define PAGESIZE 4096 #define PAGE_SIZE 4096 diff --git a/libs/libc/src/dirent.cpp b/libs/libc/src/dirent.cpp new file mode 100644 index 00000000..5924abf0 --- /dev/null +++ b/libs/libc/src/dirent.cpp @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" +{ + DIR* opendir(const char* path) + { + int dirfd = open(path, O_RDONLY); // FIXME: Implement O_DIRECTORY and use that. + if (dirfd < 0) return NULL; + return fdopendir(dirfd); + } + + DIR* fdopendir(int fd) + { + if (fd < 0) return NULL; + DIR* result = (DIR*)malloc(sizeof(DIR)); + if (!result) return NULL; + result->d_dirfd = fd; + return result; + } + + int closedir(DIR* stream) + { + int status = close(stream->d_dirfd); + if (status < 0) + { + int savederr = errno; + free(stream); + errno = savederr; // free might reset errno. We don't want that. + } + else { free(stream); } + return status; + } + + struct dirent* readdir(DIR* stream) + { + static struct dirent result; + struct luna_dirent ent; + ssize_t nread = getdents(stream->d_dirfd, &ent, 1); // FIXME: Use a buffer to avoid too many system calls. + if (nread <= 0) return NULL; // Either EOF or error. + result.d_ino = ent.inode; + result.d_reclen = sizeof(result); + result.d_off = ent.offset; + result.d_type = 0; + strlcpy(result.d_name, ent.name, NAME_MAX); + return &result; + } +} \ No newline at end of file