From 39562233bfc982c20deab9f041b0244e0c12af7d Mon Sep 17 00:00:00 2001 From: Ali Mashtizadeh Date: Fri, 5 Dec 2014 00:25:20 -0800 Subject: [PATCH] Support opening, reading and stating files from userlevel --- include/errno.h | 1 + include/syscall.h | 6 +++ lib/libc/syscall.c | 12 ++++++ sys/SConscript | 1 + sys/fs/o2fs/o2fs.c | 37 +++++++++++++++++++ sys/fs/o2fs/o2fs.h | 1 + sys/include/dirent.h | 18 +++++++++ sys/include/handle.h | 3 ++ sys/include/stat.h | 17 +++++++++ sys/include/syscall.h | 2 + sys/include/types.h | 2 + sys/include/vfs.h | 8 +++- sys/include/vfsuio.h | 10 +++++ sys/kern/syscall.c | 70 ++++++++++++++++++++++++++++++++++- sys/kern/vfs.c | 26 +++++++++++++ sys/kern/vfsuio.c | 85 +++++++++++++++++++++++++++++++++++++++++++ 16 files changed, 296 insertions(+), 3 deletions(-) create mode 100644 sys/include/dirent.h create mode 100644 sys/include/stat.h create mode 100644 sys/include/vfsuio.h create mode 100644 sys/kern/vfsuio.c diff --git a/include/errno.h b/include/errno.h index 4cba6a4..41c6d4b 100644 --- a/include/errno.h +++ b/include/errno.h @@ -8,6 +8,7 @@ #define EFAULT 0xBAD4 #define ENOMEM 0xBAD5 #define ENOENT 0xBAD6 +#define ENOTDIR 0xBAD7 #endif /* __ERRNO_H__ */ diff --git a/include/syscall.h b/include/syscall.h index 30c0e24..ee12c51 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -2,6 +2,8 @@ #ifndef __SYSCALL_H__ #define __SYSCALL_H__ +#include + uint64_t SystemTime(); void SystemExit(int status); uint64_t SystemGetPID(); @@ -19,6 +21,10 @@ int SystemFlush(uint64_t fd); uint64_t SystemOpen(const char *path, uint64_t flags); int SystemClose(uint64_t fd); +// Directory +int SystemStat(const char *path, struct stat *sb); +int SystemReadDir(uint64_t fd, char *buf, size_t length, uint64_t *offset); + // Threads int SystemThreadSleep(uint64_t time); diff --git a/lib/libc/syscall.c b/lib/libc/syscall.c index e99742d..26e0d8a 100644 --- a/lib/libc/syscall.c +++ b/lib/libc/syscall.c @@ -79,6 +79,18 @@ SystemClose(uint64_t fd) return syscall(SYSCALL_CLOSE, fd); } +int +SystemStat(const char *path, struct stat *sb) +{ + return syscall(SYSCALL_STAT, path, sb); +} + +int +SystemReadDir(uint64_t fd, char *buf, size_t length, uint64_t *offset) +{ + return syscall(SYSCALL_READDIR, fd, buf, length, offset); +} + int SystemThreadSleep(uint64_t time) { diff --git a/sys/SConscript b/sys/SConscript index 4e9902b..b46cb40 100644 --- a/sys/SConscript +++ b/sys/SConscript @@ -54,6 +54,7 @@ src_common = [ "kern/sysctl.c", "kern/thread.c", "kern/vfs.c", + "kern/vfsuio.c", "dev/ahci.c", "dev/console.c", "dev/pci.c", diff --git a/sys/fs/o2fs/o2fs.c b/sys/fs/o2fs/o2fs.c index 4af6b8b..7f29d60 100644 --- a/sys/fs/o2fs/o2fs.c +++ b/sys/fs/o2fs/o2fs.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -18,7 +19,10 @@ int O2FS_GetRoot(VFS *fs, VNode **dn); int O2FS_Lookup(VNode *dn, VNode **fn, const char *name); int O2FS_Open(VNode *fn); int O2FS_Close(VNode *fn); +int O2FS_Stat(VNode *fn, struct stat *statinfo); int O2FS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len); +int O2FS_Write(VNode *fn, void *buf, uint64_t off, uint64_t len); +int O2FS_ReadDir(VNode *fn, void *buf, uint64_t len, uint64_t *off); static VFSOp O2FSOperations = { .unmount = O2FS_Unmount, @@ -26,7 +30,10 @@ static VFSOp O2FSOperations = { .lookup = O2FS_Lookup, .open = O2FS_Open, .close = O2FS_Close, + .stat = O2FS_Stat, .read = O2FS_Read, + .write = O2FS_Write, + .readdir = O2FS_ReadDir, }; VFS * @@ -257,6 +264,23 @@ O2FS_Close(VNode *fn) return 0; } +int +O2FS_Stat(VNode *fn, struct stat *statinfo) +{ + VFS *vfs = fn->vfs; + DiskCacheEntry *sbEntry = (DiskCacheEntry *)vfs->fsptr; + SuperBlock *sb = sbEntry->buffer; + DiskCacheEntry *fileEntry = (DiskCacheEntry *)fn->fsptr; + BNode *fileBN = fileEntry->buffer; + + statinfo->st_size = fileBN->size; + // XXX: support other fields + statinfo->st_blocks = (fileBN->size + sb->blockSize - 1) / sb->blockSize; + statinfo->st_blksize = sb->blockSize; + + return 0; +} + int O2FS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len) { @@ -310,3 +334,16 @@ O2FS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len) return readBytes; } +int +O2FS_Write(VNode *fn, void *buf, uint64_t off, uint64_t len) +{ + NOT_IMPLEMENTED(); + return -EINVAL; +} + +int +O2FS_ReadDir(VNode *fn, void *buf, uint64_t len, uint64_t *off) +{ + return 0; +} + diff --git a/sys/fs/o2fs/o2fs.h b/sys/fs/o2fs/o2fs.h index 583bb76..18dd9b9 100644 --- a/sys/fs/o2fs/o2fs.h +++ b/sys/fs/o2fs/o2fs.h @@ -52,6 +52,7 @@ typedef struct SuperBlock uint64_t blockCount; uint64_t blockSize; + uint64_t version; /* Snapshot version */ ObjID root; /* Root Tree */ uint8_t hash[32]; diff --git a/sys/include/dirent.h b/sys/include/dirent.h new file mode 100644 index 0000000..22c229e --- /dev/null +++ b/sys/include/dirent.h @@ -0,0 +1,18 @@ + +#ifndef __SYS_DIRENT_H__ +#define __SYS_DIRENT_H__ + +#include + +#define NAME_MAX 256 + +struct dirent { + ino_t d_ino; + uint16_t d_reclen; + uint8_t d_type; + uint8_t d_namlen; + char d_name[NAME_MAX]; +}; + +#endif /* __SYS_DIRENT_H__ */ + diff --git a/sys/include/handle.h b/sys/include/handle.h index 5baa68b..392e2d0 100644 --- a/sys/include/handle.h +++ b/sys/include/handle.h @@ -3,6 +3,8 @@ #define __SYS_HANDLE_H__ #include +#include +#include struct Handle; typedef struct Handle Handle; @@ -14,6 +16,7 @@ typedef struct Handle { uint64_t fd; // FD Number uint64_t type; // Type uint64_t threadId; // Thread ID + VNode *vnode; // File VNode TAILQ_ENTRY(Handle) handleList; // Hash table int (*read)(Handle *, void *, uint64_t, uint64_t); // Read int (*write)(Handle *, void *, uint64_t, uint64_t); // Write diff --git a/sys/include/stat.h b/sys/include/stat.h new file mode 100644 index 0000000..3099661 --- /dev/null +++ b/sys/include/stat.h @@ -0,0 +1,17 @@ + +#ifndef __SYS_STAT_H__ +#define __SYS_STAT_H__ + +struct stat { + ino_t st_ino; + // mode + // uid + // gid + // timespec st_atim, st_mtim, st_ctim + off_t st_size; + size_t st_blocks; + size_t st_blksize; +}; + +#endif /* __SYS_STAT_H__ */ + diff --git a/sys/include/syscall.h b/sys/include/syscall.h index 28af8d9..3ce6bda 100644 --- a/sys/include/syscall.h +++ b/sys/include/syscall.h @@ -24,6 +24,8 @@ #define SYSCALL_MOVE 0x1A #define SYSCALL_DELETE 0x1B #define SYSCALL_SETLENGTH 0x1C +#define SYSCALL_STAT 0x1D +#define SYSCALL_READDIR 0x1E // Threading #define SYSCALL_THREADCREATE 0x30 diff --git a/sys/include/types.h b/sys/include/types.h index 61b1703..3216f5f 100644 --- a/sys/include/types.h +++ b/sys/include/types.h @@ -20,6 +20,8 @@ typedef int64_t ssize_t; typedef int64_t off_t; typedef int64_t fpos_t; +typedef uint64_t ino_t; + #define NULL ((void *)0) #endif /* __SYS_TYPES_H__ */ diff --git a/sys/include/vfs.h b/sys/include/vfs.h index f48d332..f54bfe0 100644 --- a/sys/include/vfs.h +++ b/sys/include/vfs.h @@ -3,6 +3,7 @@ #define __SYS_VFS_H__ #include +#include typedef struct VFSOp VFSOp; typedef struct VNode VNode; @@ -40,15 +41,20 @@ typedef struct VFSOp { int (*lookup)(VNode *dn, VNode **fn, const char *name); int (*open)(VNode *fn); int (*close)(VNode *fn); + int (*stat)(VNode *fn, struct stat *sb); int (*read)(VNode *fn, void *buf, uint64_t off, uint64_t len); + int (*write)(VNode *fn, void *buf, uint64_t off, uint64_t len); + int (*readdir)(VNode *fn, void *buf, uint64_t len, uint64_t *off); } VFSOp; int VFS_MountRoot(Disk *root); VNode *VFS_Lookup(const char *path); +// XXX: Release/Retain +int VFS_Stat(const char *path, struct stat *sb); int VFS_Open(VNode *fn); int VFS_Close(VNode *fn); int VFS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len); - +int VFS_ReadDir(VNode *fn, void *buf, uint64_t len, uint64_t *off); #endif /* __SYS_VFS_H__ */ diff --git a/sys/include/vfsuio.h b/sys/include/vfsuio.h new file mode 100644 index 0000000..b1136de --- /dev/null +++ b/sys/include/vfsuio.h @@ -0,0 +1,10 @@ + +#ifndef __SYS_VFSUIO_H__ +#define __SYS_VFSUIO_H__ + +#include + +int VFSUIO_Open(const char *path, Handle **handle); + +#endif /* __SYS_VFSUIO_H__ */ + diff --git a/sys/kern/syscall.c b/sys/kern/syscall.c index eed4a1d..84898e4 100644 --- a/sys/kern/syscall.c +++ b/sys/kern/syscall.c @@ -12,6 +12,7 @@ #include #include #include +#include Handle *Console_OpenHandle(); @@ -198,10 +199,16 @@ Syscall_Open(uint64_t user_path, uint64_t flags) Handle *handle = Console_OpenHandle(); return Handle_Add(cur, handle); } + + return -ENOENT; } - NOT_IMPLEMENTED(); - return 0; + Handle *handle; + status = VFSUIO_Open(path, &handle); + if (status != 0) + return status; + + return Handle_Add(cur, handle); } uint64_t @@ -216,6 +223,61 @@ Syscall_Close(uint64_t fd) return (handle->close)(handle); } +uint64_t +Syscall_Stat(uint64_t user_path, uint64_t user_stat) +{ + int status; + char path[512]; + struct stat sb; + + // XXX: Use CopyInStr + status = CopyIn(user_path, &path, sizeof(path)); + if (status != 0) { + return status; + } + + // VFS_Stat + status = VFS_Stat(path, &sb); + if (status != 0) { + return status; + } + + status = CopyOut(&sb, user_stat, sizeof(struct stat)); + if (status != 0) { + return status; + } + + return 0; +} + +uint64_t +Syscall_ReadDir(uint64_t fd, char *user_buf, size_t len, uintptr_t user_off) +{ + int status; + Thread *cur = Thread_Current(); + Handle *handle = Handle_Lookup(cur, fd); + uint64_t offset; + + if (handle == NULL) + return -EBADF; + + status = CopyIn(user_off, &offset, sizeof(offset)); + if (status != 0) + return status; + + if (handle->type != HANDLE_TYPE_FILE) + return -ENOTDIR; + status = VFS_ReadDir(handle->vnode, user_buf, len, &offset); + if (status != 0) + return status; + + status = CopyOut(&offset, user_off, sizeof(offset)); + if (status != 0) + return status; + + return 0; +} + uint64_t Syscall_ThreadSleep(uint64_t time) { @@ -258,6 +320,10 @@ Syscall_Entry(uint64_t syscall, uint64_t a1, uint64_t a2, return Syscall_Open(a1, a2); case SYSCALL_CLOSE: return Syscall_Close(a1); + case SYSCALL_STAT: + return Syscall_Stat(a1, a2); + case SYSCALL_READDIR: + return Syscall_ReadDir(a1, a2, a3, a4); case SYSCALL_THREADSLEEP: return Syscall_ThreadSleep(a1); default: diff --git a/sys/kern/vfs.c b/sys/kern/vfs.c index a99981a..0c8d6ff 100644 --- a/sys/kern/vfs.c +++ b/sys/kern/vfs.c @@ -2,12 +2,14 @@ #include #include #include +#include #include #include #include #include #include +#include extern VFS *O2FS_Mount(Disk *root); @@ -92,6 +94,18 @@ VFS_Lookup(const char *path) } } +int +VFS_Stat(const char *path, struct stat *sb) +{ + VNode *vn = VFS_Lookup(path); + if (vn == NULL) + return -ENOENT; + + vn->op->stat(vn, sb); + + // Release +} + int VFS_Open(VNode *fn) { @@ -110,3 +124,15 @@ VFS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len) return fn->op->read(fn, buf, off, len); } +int +VFS_Write(VNode *fn, void *buf, uint64_t off, uint64_t len) +{ + return fn->op->write(fn, buf, off, len); +} + +int +VFS_ReadDir(VNode *fn, void *buf, uint64_t len, uint64_t *off) +{ + return fn->op->readdir(fn, buf, len, off); +} + diff --git a/sys/kern/vfsuio.c b/sys/kern/vfsuio.c new file mode 100644 index 0000000..23d75e3 --- /dev/null +++ b/sys/kern/vfsuio.c @@ -0,0 +1,85 @@ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static int +VFSUIO_Read(Handle *handle, void *buf, uint64_t len, uint64_t off) +{ + ASSERT(handle->type == HANDLE_TYPE_FILE); + + // XXX: Need to pin memory + + return VFS_Read(handle->vnode, buf, len, off); +} + +static int +VFSUIO_Write(Handle *handle, void *buf, uint64_t len, uint64_t off) +{ + ASSERT(handle->type == HANDLE_TYPE_FILE); + + // XXX: Need to pin memory + + return -EINVAL; +} + +static int +VFSUIO_Flush(Handle *handle) +{ + ASSERT(handle->type == HANDLE_TYPE_FILE); + return -EINVAL; +} + +static int +VFSUIO_Close(Handle *handle) +{ + int status; + + ASSERT(handle->type == HANDLE_TYPE_FILE); + + status = VFS_Close(handle->vnode); + Handle_Free(handle); + + return status; +} + +int +VFSUIO_Open(const char *path, Handle **handle) +{ + int status; + + Handle *hdl = Handle_Alloc(); + if (!hdl) { + return -ENOMEM; + } + + VNode *vn = VFS_Lookup(path); + status = VFS_Open(vn); + if (status != 0) { + // XXX: Release VNode + Handle_Free(hdl); + return status; + } + + hdl->vnode = vn; + hdl->type = HANDLE_TYPE_FILE; + hdl->read = VFSUIO_Read; + hdl->write = VFSUIO_Write; + hdl->flush = VFSUIO_Flush; + hdl->close = VFSUIO_Close; + + *handle = hdl; + + return 0; +} + +