diff --git a/kernel/fs/portlfs/portlfs.c b/kernel/fs/portlfs/portlfs.c index d4d0da3..3fdb625 100644 --- a/kernel/fs/portlfs/portlfs.c +++ b/kernel/fs/portlfs/portlfs.c @@ -160,6 +160,52 @@ struct VfsObj *littlefs_open(struct VfsMountPoint *vmp, const char *path, uint32 return vobj; } +int32_t littlefs_fetchdirent(struct VfsMountPoint *vmp, const char *path, IoctlDirent *direntbuf, size_t idx) { + size_t i = 0; + struct lfs_info statinfo; + int ok; + + spinlock_acquire(&vmp->spinlock); + + ok = lfs_stat(&vmp->fs.littlefs.instance, path, &statinfo); + if (ok < 0) { + spinlock_release(&vmp->spinlock); + return E_BADIO; + } + + if (statinfo.type != LFS_TYPE_DIR) { + spinlock_release(&vmp->spinlock); + return E_BADIO; + } + + lfs_dir_t dir; + ok = lfs_dir_open(&vmp->fs.littlefs.instance, &dir, path); + if (ok < 0) { + spinlock_release(&vmp->spinlock); + return E_BADIO; + } + + struct lfs_info entinfo; + while (lfs_dir_read(&vmp->fs.littlefs.instance, &dir, &entinfo) > 0) { + if (i == idx) { + if (entinfo.type == LFS_TYPE_REG) { + direntbuf->stat.type = IOCTLSTAT_FILE; + direntbuf->stat.size = entinfo.size; + } else if (entinfo.type == LFS_TYPE_DIR) { + direntbuf->stat.type = IOCTLSTAT_DIR; + } + + hal_memcpy(direntbuf->name, entinfo.name, sizeof(direntbuf->name)); + break; + } + i++; + } + + lfs_dir_close(&vmp->fs.littlefs.instance, &dir); + + spinlock_release(&vmp->spinlock); +} + int portlfs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) { VfsMountPoint *vmp = c->context; vmp->backingsd->read(vmp->backingsd, buffer, size, block * LITTLEFS_BLOCK_SIZE + off); diff --git a/kernel/fs/portlfs/portlfs.h b/kernel/fs/portlfs/portlfs.h index bab3560..81dd302 100644 --- a/kernel/fs/portlfs/portlfs.h +++ b/kernel/fs/portlfs/portlfs.h @@ -4,6 +4,7 @@ #include #include #include "fs/littlefs/lfs.h" +#include "sysdefs/ioctl.h" #define LITTLEFS_BLOCK_SIZE 4096 @@ -18,6 +19,7 @@ typedef struct { int32_t littlefs_cleanup(struct VfsMountPoint *vmp); struct VfsObj *littlefs_open(struct VfsMountPoint *vmp, const char *path, uint32_t flags); int32_t littlefs_stat(struct VfsMountPoint *vmp, const char *path, struct VfsStat *statbuf); +int32_t littlefs_fetchdirent(struct VfsMountPoint *vmp, const char *path, IoctlDirent *direntbuf, size_t idx); int portlfs_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size); int portlfs_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size); diff --git a/kernel/syscall/ioctl.c b/kernel/syscall/ioctl.c index b47d6e1..85d316d 100644 --- a/kernel/syscall/ioctl.c +++ b/kernel/syscall/ioctl.c @@ -161,6 +161,29 @@ int32_t SYSCALL5(sys_ioctl, ioh1, cmd1, arg1, arg2, arg3) { iostat->size = stat1.size; iostat->type = stat1.type; } break; + case IOCTL_FETCHDIRENT: { + const char *opath = (const char *)arg1; + + if (opath == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + IoctlDirent *direntbuf = (IoctlDirent *)arg2; + if (direntbuf == NULL) { + ret = E_INVALIDARGUMENT; + goto done; + } + + size_t idx = (size_t)arg3; + + char mp[IOCTL_MP_MAX]; + char path[IOCTL_PATH_MAX]; + + path_parse(opath, mp, path); + + ret = vfs_fetchdirent(mp, path, direntbuf, idx); + } break; default: { ret = E_INVALIDARGUMENT; goto done; diff --git a/kernel/vfs/vfs.c b/kernel/vfs/vfs.c index 81aae66..57d7c0f 100644 --- a/kernel/vfs/vfs.c +++ b/kernel/vfs/vfs.c @@ -47,6 +47,7 @@ void vfs_init_littlefs(VfsMountPoint *mp, bool format) { mp->cleanup = &littlefs_cleanup; mp->open = &littlefs_open; mp->stat = &littlefs_stat; + mp->fetchdirent = &littlefs_fetchdirent; } int32_t vfs_stat(char *mountpoint, const char *path, VfsStat *stat) { @@ -63,6 +64,20 @@ int32_t vfs_stat(char *mountpoint, const char *path, VfsStat *stat) { return mp->stat(mp, path, stat); } +int32_t vfs_fetchdirent(char *mountpoint, const char *path, IoctlDirent *direntbuf, size_t idx) { + VfsMountPoint *mp = NULL; + + spinlock_acquire(&VFS_TABLE.spinlock); + HSHTB_GET(&VFS_TABLE, mountpoints, mountpoint, label, mp); + spinlock_release(&VFS_TABLE.spinlock); + + if (mp == NULL) { + return E_NOENTRY; + } + + return mp->fetchdirent(mp, path, direntbuf, idx); +} + int32_t vfs_mount(char *mountpoint, int32_t fstype, StoreDev *backingsd, bool format) { VfsMountPoint *mp = NULL; diff --git a/kernel/vfs/vfs.h b/kernel/vfs/vfs.h index 55ab16a..241d7df 100644 --- a/kernel/vfs/vfs.h +++ b/kernel/vfs/vfs.h @@ -7,6 +7,7 @@ #include "spinlock/spinlock.h" #include "fs/portlfs/portlfs.h" #include "storedev/storedev.h" +#include "sysdefs/ioctl.h" #define VFS_MOUNTPOINT_LABEL_MAX 128 #define VFS_MOUNTPOINTS_MAX 30 @@ -58,6 +59,7 @@ typedef struct VfsMountPoint { VfsObj *(*open)(struct VfsMountPoint *vmp, const char *path, uint32_t flags); int32_t (*cleanup)(struct VfsMountPoint *vmp); int32_t (*stat)(struct VfsMountPoint *vmp, const char *path, struct VfsStat *statbuf); + int32_t (*fetchdirent)(struct VfsMountPoint *vmp, const char *path, IoctlDirent *direntbuf, size_t idx); union { LittleFs littlefs; @@ -78,5 +80,6 @@ int32_t vfs_mount(char *mountpoint, int32_t fstype, StoreDev *backingsd, bool fo void vfs_close(VfsObj *vobj); VfsObj *vfs_open(char *mountpoint, const char *path, uint32_t flags); int32_t vfs_stat(char *mountpoint, const char *path, VfsStat *stat); +int32_t vfs_fetchdirent(char *mountpoint, const char *path, IoctlDirent *direntbuf, size_t idx); #endif // VFS_VFS_H_ diff --git a/user/fs/fetch.c b/user/fs/fetch.c index a7ab388..01e287b 100644 --- a/user/fs/fetch.c +++ b/user/fs/fetch.c @@ -37,6 +37,23 @@ void fs_fetch(void) { ufree(buf); ioctl(ioh, IOCTL_CLOSEF, 0, 0, 0); } else if (statbuf.type == IOCTLSTAT_DIR) { - uprintf("entries = %zu\n", statbuf.size); + IoctlDirent *dirents = (IoctlDirent *)umalloc(statbuf.size * sizeof(*dirents)); + + for (size_t i = 0; i < statbuf.size; i++) { + ioctl(IOCTL_NOHANDLE, IOCTL_FETCHDIRENT, (uint64_t)path, (uint64_t)&dirents[i], i); + + IoctlDirent *dirent = &dirents[i]; + + char membuf[20]; + + uprintf("%-30s %-15s %-1s", + dirent->name, + dirent->stat.type == IOCTLSTAT_FILE ? human_size(dirent->stat.size, membuf, 20) : "-", + dirent->stat.type == IOCTLSTAT_FILE ? "F" : "D" + ); + uprintf("\n"); + } + + ufree(dirents); } }