From 1dd4a04f96ecafa8f4cb5b012fd49be3cf898bc2 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Tue, 9 May 2023 23:08:33 +0800 Subject: [PATCH 01/20] feat: use VFS --- kernel/fs/fat32/fs.cpp | 150 +++++++++++++++++--------------------- kernel/fs/fs.cpp | 35 +++++++-- kernel/fs/vfs/fs.cpp | 28 +++++++ kernel/include/fs.h | 7 +- kernel/include/fs/fat32.h | 32 +++----- kernel/include/fs/local.h | 12 +++ kernel/include/fs/vfs.h | 88 ++++++++++++++++++++++ 7 files changed, 236 insertions(+), 116 deletions(-) create mode 100644 kernel/fs/vfs/fs.cpp create mode 100644 kernel/include/fs/local.h create mode 100644 kernel/include/fs/vfs.h diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index feae249b..11611bc9 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -1,4 +1,6 @@ #include <buf.h> +#include <fs/local.h> +#include <fs/vfs.h> #include <fs/fat32.h> #include <fmt.hpp> #include <sched.h> @@ -11,17 +13,14 @@ #define min(a, b) ((a) < (b) ? (a) : (b)) namespace FAT32 { -static SimpleAllocator<internal_dentry_t> dentry_allocator; -static SimpleAllocator<fdesp_t> fdesp_allocator; - static uint32_t sector_size; // in bytes static sector_t cluster_size; // in sectors static sector_t fat_size; // in sectors static sector_t total_sectors; static sector_t first_data_sector; static sector_t first_fat_sector; -static internal_dentry_t root_dentry; -fdesp_t root_fd; +static VFS::dentry_t root_dentry; +VFS::fdesp_t root_fd; sector_t first_sector_of_cluster(cluster_t clus) { return ((clus - 2) * cluster_size) + first_data_sector; @@ -74,16 +73,7 @@ char *namencat(char *dst, const uint16_t *src, size_t dstn, size_t srcn) { return dst; } -fdesp_t *get_fdesp(int fd, pcb_t *pcb) { - if (fd == AT_FDCWD) - fd = pcb->cwd; - for (auto it : pcb->fd_list) { - if (it->idx == fd) - return it; - } - fmt::warn("not a valid file descriptor\n"); - return nullptr; -} + // NOTE: must be called AFTER init_device() and init_interrupt() bool init() { @@ -133,12 +123,15 @@ bool init() { return false; } - strncpy(root_dentry.name, "/", 2); - root_dentry.cluster = __bpb.BPB_RootClus; - root_dentry.p.sector = 0; - root_dentry.p.offset = 0; - root_dentry.size = 0; - root_fd.dentry = &root_dentry; + root_dentry.d_ino = __bpb.BPB_RootClus; + root_dentry.d_off = 0; + root_dentry.d_reclen = 0; + root_dentry.d_type = DT_DIR; + strncpy(root_dentry.d_name, "/", 2); + root_fd.idx = -1; + root_fd.flags = O_DIRECTORY; + root_fd.ino = __bpb.BPB_RootClus; + root_fd.size = 0; root_fd.offset = 0; buf_release(buf); @@ -147,16 +140,16 @@ bool init() { // NOTE: the return value / params / usage of this API is under consideration /* lookup file or directory in dir - * param: in - cluster number of dir + * param: in - first cluster number of dir * param: what - name of file or directory - * return: cluster number file or directory, 0 if not found + * return: dentry of file or directory, 0 if not found */ -internal_dentry_t lookup(const internal_dentry_t in, const char *what) { +VFS::kstat_t lookup(const cluster_t first_clus, const char *what) { // See https://wiki.osdev.org/FAT#Reading_Directories - cluster_t clus = in.cluster; + // we simply use first clusuter number as inode number + cluster_t clus = first_clus; bool end = false; - char lfn_buf[INTERNEL_DENTRY_NAME_LEN] = {0}; - internal_dentry_t dentry = {0}; + char lfn_buf[DENTRY_NAME_LEN] = {0}; do { sector_t base_sec = first_sector_of_cluster(clus); for (sector_t sec = base_sec; !end && sec < base_sec + cluster_size; sec++) { @@ -172,22 +165,37 @@ internal_dentry_t lookup(const internal_dentry_t in, const char *what) { if (!(entry->lfnentry.seq & 0x01) && entry->lfnentry.type != 0x00) { fmt::err("unhandled long entry type: {}\n", (uint32_t) entry->lfnentry.type); buf_release(buf); - return dentry; + return {0}; } - namencat(lfn_buf, entry->lfnentry.name1, INTERNEL_DENTRY_NAME_LEN, LFN_NAME1_LEN); - namencat(lfn_buf, entry->lfnentry.name2, INTERNEL_DENTRY_NAME_LEN, LFN_NAME2_LEN); - namencat(lfn_buf, entry->lfnentry.name3, INTERNEL_DENTRY_NAME_LEN, LFN_NAME3_LEN); + namencat(lfn_buf, entry->lfnentry.name1, DENTRY_NAME_LEN, LFN_NAME1_LEN); + namencat(lfn_buf, entry->lfnentry.name2, DENTRY_NAME_LEN, LFN_NAME2_LEN); + namencat(lfn_buf, entry->lfnentry.name3, DENTRY_NAME_LEN, LFN_NAME3_LEN); } else { char *name = lfn_buf[0] ? lfn_buf : (char *) entry->dentry.name; - size_t len = lfn_buf[0] ? strnlen(lfn_buf, INTERNEL_DENTRY_NAME_LEN) : 8; + size_t len = lfn_buf[0] ? strnlen(lfn_buf, DENTRY_NAME_LEN) : 8; + // fmt::debug("...name: {}\n", Slice<const char>(name, len)); if (strncmp(name, what, len) == 0 && what[len] == '\0') { - strncpy(dentry.name, name, len); - dentry.cluster = (uint32_t) entry->dentry.clus_hi << 16 | entry->dentry.clus_lo; - dentry.size = entry->dentry.size; - dentry.p.sector = sec; - dentry.p.offset = i; + VFS::kstat_t stat; + stat.st_dev = DEV_VIRTIO_BLK; + stat.st_ino = (uint32_t) entry->dentry.clus_hi << 16 | entry->dentry.clus_lo; + stat.st_mode = entry->dentry.attr & FAT32_DENTRY_ATTR_DIRECTORY ? S_IFDIR : 0; + stat.st_mode |= S_IRWXU | S_IRWXG | S_IRWXO; // 0777 + stat.st_nlink = 1; + stat.st_uid = 0; + stat.st_gid = 0; + stat.st_rdev = DEV_VIRTIO_BLK; + stat.st_size = entry->dentry.size; + stat.st_blksize = sector_size; + stat.st_blocks = entry->dentry.size / sector_size + (entry->dentry.size % sector_size != 0); + // FIXME: access / modify / create time + stat.st_atime_sec = 0; + stat.st_atime_nsec = 0; + stat.st_mtime_sec = 0; + stat.st_mtime_nsec = 0; + stat.st_ctime_sec = 0; + stat.st_ctime_nsec = 0; buf_release(buf); - return dentry; + return stat; } lfn_buf[0] = '\0'; @@ -196,57 +204,59 @@ internal_dentry_t lookup(const internal_dentry_t in, const char *what) { buf_release(buf); } } while (!end && (clus = next_cluster(clus))); - return dentry; + return {0}; } // lookup in root dir -internal_dentry_t lookup(const char *name) { - return lookup(root_dentry, name); +VFS::kstat_t lookup(const char *name) { + return lookup(root_dentry.d_ino, name); } int openat(int dirfd, const char *pathname, int flags) { pcb_t *pcb = get_current_proc(); - fdesp_t *dir = pathname[0] == '/' ? &root_fd : get_fdesp(dirfd, pcb); + VFS::fdesp_t *dir = pathname[0] == '/' ? &root_fd : VFS::get_fdesp(dirfd, pcb); assert(dir); - internal_dentry_t *new_entry = dentry_allocator.create(); - *new_entry = *dir->dentry; + cluster_t clus = dir->ino; const char *p = pathname[0] == '/' ? pathname + 1 : pathname; - char name_buf[INTERNEL_DENTRY_NAME_LEN] = {0}; + char name_buf[DENTRY_NAME_LEN] = {0}; + VFS::kstat_t stat; while (*p) { int i=0; - while (*p && *p != '/' && i<INTERNEL_DENTRY_NAME_LEN) name_buf[i++] = *p++; - if (i == INTERNEL_DENTRY_NAME_LEN) + while (*p && *p != '/' && i<DENTRY_NAME_LEN) name_buf[i++] = *p++; + if (i == DENTRY_NAME_LEN) fmt::warn("pathname exceed MAX_NAME_LEN\n"); - *new_entry = lookup(*new_entry, name_buf); + stat = lookup(clus, name_buf); + clus = stat.st_ino; // FIXME: O_CREATE? - if (new_entry->cluster == 0) return -1; + if (clus == 0) return -1; // not found + if (*p && (stat.st_mode & S_IFMT) != S_IFDIR) return -1; // not diretory if (*p) p++; } - fdesp_t *new_fd = fdesp_allocator.create(); - new_fd->dentry = new_entry; + VFS::fdesp_t *new_fd = VFS::alloc_fdesp(); new_fd->idx = pcb->nfd++; new_fd->flags = flags; + new_fd->ino = clus; + new_fd->size = stat.st_size; new_fd->offset = 0; pcb->fd_list.push_back(new_fd); return new_fd->idx; } ssize_t read(int fd, void *buf, size_t count) { - fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); + VFS::fdesp_t *fdesp = VFS::get_fdesp(fd, get_current_proc()); assert(fdesp); if (fdesp->flags & O_WRONLY) return 0; - internal_dentry_t *dentry = fdesp->dentry; size_t off = fdesp->offset; - if (off > dentry->size || off + count < off) return 0; - if (off + count > dentry->size) count = dentry->size - off; - location_t loc = locate(dentry->cluster, off); + if (off > fdesp->size || off + count < off) return 0; + if (off + count > fdesp->size) count = fdesp->size - off; + location_t loc = locate(fdesp->ino, off); size_t nread = 0; do { fmt::debug("loading cluster: {}\n", loc.cluster); sector_t base_sec = first_sector_of_cluster(loc.cluster); - for (sector_t sec = base_sec + loc.sector; off < dentry->size && sec < base_sec + cluster_size; sec++) { + for (sector_t sec = base_sec + loc.sector; off < fdesp->size && sec < base_sec + cluster_size; sec++) { buf_t *_buf = buf_read(DEV_VIRTIO_BLK, sec); size_t n = min(count - nread, sector_size - loc.offset); memcpy((char *) buf + nread, _buf->data + loc.offset, n); @@ -256,37 +266,13 @@ ssize_t read(int fd, void *buf, size_t count) { loc.offset = 0; } loc.sector = 0; - } while (off < dentry->size && nread < count && (loc.cluster = next_cluster(loc.cluster))); + } while (off < fdesp->size && nread < count && (loc.cluster = next_cluster(loc.cluster))); fdesp->offset += nread; return (ssize_t) nread; } -ssize_t lseek(int fd, ssize_t offset, int whence) { - fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); - assert(fdesp); - switch (whence) { - case SEEK_SET: fdesp->offset = offset; break; - case SEEK_CUR: fdesp->offset += offset; break; - case SEEK_END: fdesp->offset = fdesp->dentry->size + offset; break; - default: fmt::warn("invalid whence\n"); return -1; - } - return fdesp->offset; -} - -int close(int fd) { - pcb_t *pcb = get_current_proc(); - for (auto it = pcb->fd_list.begin(); it != pcb->fd_list.end(); ++ it) { - if ((*it)->idx == fd) { - pcb->fd_list.erase(it); - fdesp_allocator.destroy(*it); - return 0; - } - } - return -1; -} - // TODO } // namespace fat32 diff --git a/kernel/fs/fs.cpp b/kernel/fs/fs.cpp index 1abc99f1..a701154f 100644 --- a/kernel/fs/fs.cpp +++ b/kernel/fs/fs.cpp @@ -2,8 +2,11 @@ #include <driver/uart.h> #include <stdint.h> #include <stddef.h> +#include <sched.h> #include <fs.h> #include <fs/fat32.h> +#include <fs/vfs.h> +#include <fs/local.h> #include <fmt.hpp> void init_fs() { @@ -21,20 +24,20 @@ int fs_open(const char *pathname, int flags) { } ssize_t fs_read(int fd, void *buf, size_t len) { + if (len == 0) + return 0; switch (fd) { case STDIN: - if (len) { - *(char *)buf = UART::getchar(); - return 1; - } else { - return 0; - } + *(char *)buf = UART::getchar(); + return 1; default: return FAT32::read(fd, buf, len); } } ssize_t fs_write(int fd, const void *buf, size_t len) { + if (len == 0) + return 0; switch (fd) { case STDOUT: case STDERR: for (size_t i=0; i<len; i++) @@ -49,11 +52,27 @@ ssize_t fs_write(int fd, const void *buf, size_t len) { ssize_t fs_lseek(int fd, ssize_t offset, int whence) { if (fd == STDIN || fd == STDOUT || fd == STDERR) return 0; - return FAT32::lseek(fd, offset, whence); + VFS::fdesp_t *fdesp = VFS::get_fdesp(fd, get_current_proc()); + assert(fdesp); + switch (whence) { + case SEEK_SET: fdesp->offset = offset; break; + case SEEK_CUR: fdesp->offset += offset; break; + case SEEK_END: fdesp->offset = fdesp->size + offset; break; + default: fmt::warn("invalid whence\n"); return -1; + } + return fdesp->offset; } int fs_close(int fd) { if (fd == STDIN || fd == STDOUT || fd == STDERR) return 0; - return FAT32::close(fd); + pcb_t *pcb = get_current_proc(); + for (auto it = pcb->fd_list.begin(); it != pcb->fd_list.end(); ++ it) { + if ((*it)->idx == fd) { + pcb->fd_list.erase(it); + VFS::free_fdesp(*it); + return 0; + } + } + return -1; } diff --git a/kernel/fs/vfs/fs.cpp b/kernel/fs/vfs/fs.cpp new file mode 100644 index 00000000..51d3d11f --- /dev/null +++ b/kernel/fs/vfs/fs.cpp @@ -0,0 +1,28 @@ +#include <assert.h> +#include <sched.h> +#include <fs.h> +#include <fs/vfs.h> +#include <fmt.hpp> + +namespace VFS { +static SimpleAllocator<fdesp_t> fdesp_allocator; + +fdesp_t *alloc_fdesp() { + return fdesp_allocator.create(); +} + +void free_fdesp(fdesp_t *fd) { + fdesp_allocator.destroy(fd); +} + +fdesp_t *get_fdesp(int fd, pcb_t *pcb) { + if (fd == AT_FDCWD) + fd = pcb->cwd; + for (auto it : pcb->fd_list) { + if (it->idx == fd) + return it; + } + fmt::warn("not a valid file descriptor\n"); + return nullptr; +} +} // namespace VFS diff --git a/kernel/include/fs.h b/kernel/include/fs.h index fcd571b1..e2e9ddc1 100644 --- a/kernel/include/fs.h +++ b/kernel/include/fs.h @@ -3,7 +3,7 @@ #include <stdint.h> #include <stddef.h> -#include <fs/fat32.h> +#include <fs/vfs.h> #define STDIN 0 #define STDOUT 1 @@ -23,9 +23,8 @@ #define RESV_FD 3 // stdin, stdout, stderr -// FIXME: replace these ? -typedef FAT32::internal_dentry_t dentry_t; -typedef FAT32::fdesp_t fdesp_t; +typedef VFS::dentry_t dentry_t; +typedef VFS::fdesp_t fdesp_t; void init_fs(); int fs_openat(int dirfd, const char *pathname, int flags); diff --git a/kernel/include/fs/fat32.h b/kernel/include/fs/fat32.h index affac6a7..01fc75dd 100644 --- a/kernel/include/fs/fat32.h +++ b/kernel/include/fs/fat32.h @@ -4,6 +4,8 @@ #include <stdint.h> #include <stddef.h> +#include <fs/vfs.h> + typedef uint32_t cluster_t; typedef uint32_t sector_t; @@ -55,6 +57,12 @@ struct dentry_date_t { uint16_t day : 5; }; +#define FAT32_DENTRY_ATTR_READ_ONLY 0x01 +#define FAT32_DENTRY_ATTR_HIDDEN 0x02 +#define FAT32_DENTRY_ATTR_SYSTEM 0x04 +#define FAT32_DENTRY_ATTR_VOLUMN_ID 0x08 +#define FAT32_DENTRY_ATTR_DIRECTORY 0x10 + #pragma pack(1) // standard directory entry struct dentry_t { @@ -109,31 +117,11 @@ struct location_t { size_t offset; // offset(bytes) in sector, 0 <= offset < sector_size }; -#define INTERNEL_DENTRY_NAME_LEN 64 -struct internal_dentry_t { - char name[INTERNEL_DENTRY_NAME_LEN]; - cluster_t cluster; - size_t size; - struct { - sector_t sector; - uint32_t offset; - } p; -}; - -struct fdesp_t { - int idx; - int flags; - internal_dentry_t *dentry; - size_t offset; -}; - bool init(); -internal_dentry_t lookup(internal_dentry_t dir, const char *name); -internal_dentry_t lookup(const char *name); +VFS::kstat_t lookup(const cluster_t first_clus, const char *name); +VFS::kstat_t lookup(const char *name); int openat(int dirfd, const char *pathname, int flags); ssize_t read(int fd, void *buf, size_t count); -ssize_t lseek(int fd, ssize_t offset, int whence); -int close(int fd); } // namespace FAT32 diff --git a/kernel/include/fs/local.h b/kernel/include/fs/local.h new file mode 100644 index 00000000..7b57bd71 --- /dev/null +++ b/kernel/include/fs/local.h @@ -0,0 +1,12 @@ +#ifndef __FS_LOCAL_H__ +#define __FS_LOCAL_H__ + +#include <sched.h> + +namespace VFS { +fdesp_t *alloc_fdesp(); +void free_fdesp(fdesp_t *fd); +fdesp_t *get_fdesp(int fd, pcb_t *pcb); +} // namespace VFS + +#endif diff --git a/kernel/include/fs/vfs.h b/kernel/include/fs/vfs.h new file mode 100644 index 00000000..0f37fd12 --- /dev/null +++ b/kernel/include/fs/vfs.h @@ -0,0 +1,88 @@ +#ifndef __VFS_H__ +#define __VFS_H__ + +#include <stdint.h> + +namespace VFS { +typedef unsigned int mode_t; +typedef long int off_t; + +// kstat.st_mode / inode.i_mode +#define S_IFMT 0170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 +#define S_IRWXU 0000700 +#define S_IRUSR 0000400 +#define S_IWUSR 0000200 +#define S_IXUSR 0000100 +#define S_IRWXG 0000070 +#define S_IRGRP 0000040 +#define S_IWGRP 0000020 +#define S_IXGRP 0000010 +#define S_IRWXO 0000007 +#define S_IROTH 0000004 +#define S_IWOTH 0000002 +#define S_IXOTH 0000001 + +struct kstat { + uint64_t st_dev; + uint64_t st_ino; + mode_t st_mode; + uint32_t st_nlink; + uint32_t st_uid; + uint32_t st_gid; + uint64_t st_rdev; + unsigned long __pad; + off_t st_size; + uint32_t st_blksize; + int __pad2; + uint64_t st_blocks; + long st_atime_sec; + long st_atime_nsec; + long st_mtime_sec; + long st_mtime_nsec; + long st_ctime_sec; + long st_ctime_nsec; + unsigned __unused[2]; +}; +typedef struct kstat kstat_t; + +// dentry_t.d_type +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 + +#define DENTRY_NAME_LEN (128 - 24) +struct linux_dirent64 { + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[DENTRY_NAME_LEN]; +}; +typedef struct linux_dirent64 dentry_t; + +struct fdesp_t { + int idx; + int flags; + uint64_t ino; + size_t size; + size_t offset; +}; + +} // namespace VFS + +#endif -- GitLab From 6eca2f0758f238e4c5d93e3f095c94a10ed8dbbc Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 12:43:22 +0800 Subject: [PATCH 02/20] feat: remove VFS namespace for xxx_fdesp() --- kernel/fs/fat32/fs.cpp | 6 +++--- kernel/fs/{vfs/fs.cpp => fdesp.cpp} | 10 ++++------ kernel/fs/fs.cpp | 4 ++-- kernel/include/fs.h | 1 + kernel/include/fs/local.h | 2 -- 5 files changed, 10 insertions(+), 13 deletions(-) rename kernel/fs/{vfs/fs.cpp => fdesp.cpp} (86%) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index 11611bc9..cc9dfd37 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -214,7 +214,7 @@ VFS::kstat_t lookup(const char *name) { int openat(int dirfd, const char *pathname, int flags) { pcb_t *pcb = get_current_proc(); - VFS::fdesp_t *dir = pathname[0] == '/' ? &root_fd : VFS::get_fdesp(dirfd, pcb); + VFS::fdesp_t *dir = pathname[0] == '/' ? &root_fd : get_fdesp(dirfd, pcb); assert(dir); cluster_t clus = dir->ino; const char *p = pathname[0] == '/' ? pathname + 1 : pathname; @@ -232,7 +232,7 @@ int openat(int dirfd, const char *pathname, int flags) { if (*p && (stat.st_mode & S_IFMT) != S_IFDIR) return -1; // not diretory if (*p) p++; } - VFS::fdesp_t *new_fd = VFS::alloc_fdesp(); + VFS::fdesp_t *new_fd = alloc_fdesp(); new_fd->idx = pcb->nfd++; new_fd->flags = flags; new_fd->ino = clus; @@ -243,7 +243,7 @@ int openat(int dirfd, const char *pathname, int flags) { } ssize_t read(int fd, void *buf, size_t count) { - VFS::fdesp_t *fdesp = VFS::get_fdesp(fd, get_current_proc()); + VFS::fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); assert(fdesp); if (fdesp->flags & O_WRONLY) return 0; diff --git a/kernel/fs/vfs/fs.cpp b/kernel/fs/fdesp.cpp similarity index 86% rename from kernel/fs/vfs/fs.cpp rename to kernel/fs/fdesp.cpp index 51d3d11f..b63ead1d 100644 --- a/kernel/fs/vfs/fs.cpp +++ b/kernel/fs/fdesp.cpp @@ -1,10 +1,9 @@ -#include <assert.h> -#include <sched.h> -#include <fs.h> +#include <fs/local.h> #include <fs/vfs.h> +#include <mem.hpp> #include <fmt.hpp> +#include <sched.h> -namespace VFS { static SimpleAllocator<fdesp_t> fdesp_allocator; fdesp_t *alloc_fdesp() { @@ -24,5 +23,4 @@ fdesp_t *get_fdesp(int fd, pcb_t *pcb) { } fmt::warn("not a valid file descriptor\n"); return nullptr; -} -} // namespace VFS +} \ No newline at end of file diff --git a/kernel/fs/fs.cpp b/kernel/fs/fs.cpp index a701154f..8c32c351 100644 --- a/kernel/fs/fs.cpp +++ b/kernel/fs/fs.cpp @@ -52,7 +52,7 @@ ssize_t fs_write(int fd, const void *buf, size_t len) { ssize_t fs_lseek(int fd, ssize_t offset, int whence) { if (fd == STDIN || fd == STDOUT || fd == STDERR) return 0; - VFS::fdesp_t *fdesp = VFS::get_fdesp(fd, get_current_proc()); + fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); assert(fdesp); switch (whence) { case SEEK_SET: fdesp->offset = offset; break; @@ -70,7 +70,7 @@ int fs_close(int fd) { for (auto it = pcb->fd_list.begin(); it != pcb->fd_list.end(); ++ it) { if ((*it)->idx == fd) { pcb->fd_list.erase(it); - VFS::free_fdesp(*it); + free_fdesp(*it); return 0; } } diff --git a/kernel/include/fs.h b/kernel/include/fs.h index e2e9ddc1..c1080474 100644 --- a/kernel/include/fs.h +++ b/kernel/include/fs.h @@ -25,6 +25,7 @@ typedef VFS::dentry_t dentry_t; typedef VFS::fdesp_t fdesp_t; +typedef VFS::kstat_t kstat_t; void init_fs(); int fs_openat(int dirfd, const char *pathname, int flags); diff --git a/kernel/include/fs/local.h b/kernel/include/fs/local.h index 7b57bd71..dd4c270f 100644 --- a/kernel/include/fs/local.h +++ b/kernel/include/fs/local.h @@ -3,10 +3,8 @@ #include <sched.h> -namespace VFS { fdesp_t *alloc_fdesp(); void free_fdesp(fdesp_t *fd); fdesp_t *get_fdesp(int fd, pcb_t *pcb); -} // namespace VFS #endif -- GitLab From 20c0be642a7bf8677bd4fa230ebed9c2caff0de7 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 12:45:33 +0800 Subject: [PATCH 03/20] style: add prefix for FAT32 msgs --- kernel/fs/fat32/fs.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index cc9dfd37..19b66b94 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -40,7 +40,7 @@ cluster_t next_cluster(cluster_t clus) { if (table_value >= 0x0FFFFFF8) { return 0; } else if (table_value == 0x0FFFFFF7) { - fmt::err("bad cluster\n"); + fmt::err("FAT32: bad cluster\n"); return 0; } else { return table_value; @@ -65,7 +65,7 @@ char *namencat(char *dst, const uint16_t *src, size_t dstn, size_t srcn) { while (i < dstn && dst[i] != '\0') i++; while (i < dstn && j < srcn && src[j] != '\0' && src[j] != 0xFFFF) { if (src[j] >= 0x80) { - fmt::warn("non-ASCII character in file name\n"); + fmt::warn("FAT32: non-ASCII character in file name\n"); } dst[i++] = (char) src[j++]; } @@ -89,7 +89,7 @@ bool init() { BPB __bpb = *(BPB *) buf->data; if (memcmp(__bpb.BS_FilSysType, (void *) "FAT32 ", 8) != 0 || __bpb.BS_BootSig != 0x29 || __bpb.BS_TrailSig != 0xAA55) { - fmt::err("Invalid FAT32 file system\n"); + fmt::err("FAT32: Invalid FAT32 file system\n"); buf_release(buf); return false; } @@ -100,7 +100,7 @@ bool init() { // on FAT32, RootDirSectors must be 0 uint32_t root_dir_sectors = (__bpb.BPB_RootEntCnt * 32 + sector_size - 1) / sector_size; if (root_dir_sectors != 0) { - fmt::err("root_dir_sectors is not 0\n"); + fmt::err("FAT32: root_dir_sectors is not 0\n"); buf_release(buf); return false; } @@ -114,11 +114,11 @@ bool init() { uint32_t data_sectors = total_sectors - first_data_sector; uint32_t count_of_clusters = data_sectors / cluster_size; if (count_of_clusters < 4085) { - fmt::err("Volume is FAT12\n"); + fmt::err("FAT32: Volume is FAT12\n"); buf_release(buf); return false; } else if (count_of_clusters < 65525) { - fmt::err("Volume is FAT16\n"); + fmt::err("FAT32: Volume is FAT16\n"); buf_release(buf); return false; } @@ -163,7 +163,7 @@ VFS::kstat_t lookup(const cluster_t first_clus, const char *what) { continue; } else if (entry->raw[11] == 0x0F) { if (!(entry->lfnentry.seq & 0x01) && entry->lfnentry.type != 0x00) { - fmt::err("unhandled long entry type: {}\n", (uint32_t) entry->lfnentry.type); + fmt::err("FAT32: unhandled long entry type: {}\n", (uint32_t) entry->lfnentry.type); buf_release(buf); return {0}; } @@ -173,7 +173,7 @@ VFS::kstat_t lookup(const cluster_t first_clus, const char *what) { } else { char *name = lfn_buf[0] ? lfn_buf : (char *) entry->dentry.name; size_t len = lfn_buf[0] ? strnlen(lfn_buf, DENTRY_NAME_LEN) : 8; - // fmt::debug("...name: {}\n", Slice<const char>(name, len)); + // fmt::debug("FAT32: ... name: {}\n", Slice<const char>(name, len)); if (strncmp(name, what, len) == 0 && what[len] == '\0') { VFS::kstat_t stat; stat.st_dev = DEV_VIRTIO_BLK; @@ -224,7 +224,7 @@ int openat(int dirfd, const char *pathname, int flags) { int i=0; while (*p && *p != '/' && i<DENTRY_NAME_LEN) name_buf[i++] = *p++; if (i == DENTRY_NAME_LEN) - fmt::warn("pathname exceed MAX_NAME_LEN\n"); + fmt::warn("FAT32: pathname exceed MAX_NAME_LEN\n"); stat = lookup(clus, name_buf); clus = stat.st_ino; // FIXME: O_CREATE? @@ -254,7 +254,7 @@ ssize_t read(int fd, void *buf, size_t count) { size_t nread = 0; do { - fmt::debug("loading cluster: {}\n", loc.cluster); + fmt::debug("FAT32: loading cluster: {}\n", loc.cluster); sector_t base_sec = first_sector_of_cluster(loc.cluster); for (sector_t sec = base_sec + loc.sector; off < fdesp->size && sec < base_sec + cluster_size; sec++) { buf_t *_buf = buf_read(DEV_VIRTIO_BLK, sec); -- GitLab From 14bafe8dfc07306792c5d79955005774b7c7541c Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 12:46:07 +0800 Subject: [PATCH 04/20] feat: do not read if count == 0 --- kernel/fs/fat32/fs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index 19b66b94..639f0786 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -250,6 +250,7 @@ ssize_t read(int fd, void *buf, size_t count) { size_t off = fdesp->offset; if (off > fdesp->size || off + count < off) return 0; if (off + count > fdesp->size) count = fdesp->size - off; + if (count == 0) return 0; location_t loc = locate(fdesp->ino, off); size_t nread = 0; -- GitLab From 5cd08eb3a5ae23bbde8964fc3642024f181a5070 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 12:46:54 +0800 Subject: [PATCH 05/20] fix: use stat.st_nlink as mark of found --- kernel/fs/fat32/fs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index 639f0786..96235b9b 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -228,7 +228,7 @@ int openat(int dirfd, const char *pathname, int flags) { stat = lookup(clus, name_buf); clus = stat.st_ino; // FIXME: O_CREATE? - if (clus == 0) return -1; // not found + if (stat.st_nlink == 0) return -1; // not found if (*p && (stat.st_mode & S_IFMT) != S_IFDIR) return -1; // not diretory if (*p) p++; } -- GitLab From f407d01882863951fd29a1187494194c71f6b1e2 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 14:22:05 +0800 Subject: [PATCH 06/20] feat: add kstat to fdesp --- kernel/fs/fat32/fs.cpp | 25 ++++++++++--------------- kernel/fs/fdesp.cpp | 6 ++++-- kernel/fs/fs.cpp | 6 +++--- kernel/include/fs/vfs.h | 3 +-- kernel/loader/loader.cpp | 3 +++ 5 files changed, 21 insertions(+), 22 deletions(-) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index 96235b9b..2a625f4a 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -73,8 +73,6 @@ char *namencat(char *dst, const uint16_t *src, size_t dstn, size_t srcn) { return dst; } - - // NOTE: must be called AFTER init_device() and init_interrupt() bool init() { // static checks @@ -130,9 +128,8 @@ bool init() { strncpy(root_dentry.d_name, "/", 2); root_fd.idx = -1; root_fd.flags = O_DIRECTORY; - root_fd.ino = __bpb.BPB_RootClus; - root_fd.size = 0; root_fd.offset = 0; + root_fd.stat.st_ino = __bpb.BPB_RootClus; buf_release(buf); return true; @@ -216,17 +213,16 @@ int openat(int dirfd, const char *pathname, int flags) { pcb_t *pcb = get_current_proc(); VFS::fdesp_t *dir = pathname[0] == '/' ? &root_fd : get_fdesp(dirfd, pcb); assert(dir); - cluster_t clus = dir->ino; + VFS::kstat_t stat = dir->stat; const char *p = pathname[0] == '/' ? pathname + 1 : pathname; char name_buf[DENTRY_NAME_LEN] = {0}; - VFS::kstat_t stat; while (*p) { int i=0; while (*p && *p != '/' && i<DENTRY_NAME_LEN) name_buf[i++] = *p++; + fmt::debug("FAT32: looking for {}\n", Slice<const char>(name_buf, i)); if (i == DENTRY_NAME_LEN) fmt::warn("FAT32: pathname exceed MAX_NAME_LEN\n"); - stat = lookup(clus, name_buf); - clus = stat.st_ino; + stat = lookup(stat.st_ino, name_buf); // FIXME: O_CREATE? if (stat.st_nlink == 0) return -1; // not found if (*p && (stat.st_mode & S_IFMT) != S_IFDIR) return -1; // not diretory @@ -235,8 +231,7 @@ int openat(int dirfd, const char *pathname, int flags) { VFS::fdesp_t *new_fd = alloc_fdesp(); new_fd->idx = pcb->nfd++; new_fd->flags = flags; - new_fd->ino = clus; - new_fd->size = stat.st_size; + new_fd->stat = stat; new_fd->offset = 0; pcb->fd_list.push_back(new_fd); return new_fd->idx; @@ -248,16 +243,16 @@ ssize_t read(int fd, void *buf, size_t count) { if (fdesp->flags & O_WRONLY) return 0; size_t off = fdesp->offset; - if (off > fdesp->size || off + count < off) return 0; - if (off + count > fdesp->size) count = fdesp->size - off; + if (off > fdesp->stat.st_size || off + count < off) return 0; + if (off + count > fdesp->stat.st_size) count = fdesp->stat.st_size - off; if (count == 0) return 0; - location_t loc = locate(fdesp->ino, off); + location_t loc = locate(fdesp->stat.st_ino, off); size_t nread = 0; do { fmt::debug("FAT32: loading cluster: {}\n", loc.cluster); sector_t base_sec = first_sector_of_cluster(loc.cluster); - for (sector_t sec = base_sec + loc.sector; off < fdesp->size && sec < base_sec + cluster_size; sec++) { + for (sector_t sec = base_sec + loc.sector; off < fdesp->stat.st_size && sec < base_sec + cluster_size; sec++) { buf_t *_buf = buf_read(DEV_VIRTIO_BLK, sec); size_t n = min(count - nread, sector_size - loc.offset); memcpy((char *) buf + nread, _buf->data + loc.offset, n); @@ -267,7 +262,7 @@ ssize_t read(int fd, void *buf, size_t count) { loc.offset = 0; } loc.sector = 0; - } while (off < fdesp->size && nread < count && (loc.cluster = next_cluster(loc.cluster))); + } while (off < fdesp->stat.st_size && nread < count && (loc.cluster = next_cluster(loc.cluster))); fdesp->offset += nread; diff --git a/kernel/fs/fdesp.cpp b/kernel/fs/fdesp.cpp index b63ead1d..6a8d0aa0 100644 --- a/kernel/fs/fdesp.cpp +++ b/kernel/fs/fdesp.cpp @@ -15,12 +15,14 @@ void free_fdesp(fdesp_t *fd) { } fdesp_t *get_fdesp(int fd, pcb_t *pcb) { - if (fd == AT_FDCWD) + if (fd == AT_FDCWD) { + fmt::debug("fs: AT_FDCWD = {}\n", pcb->cwd); fd = pcb->cwd; + } for (auto it : pcb->fd_list) { if (it->idx == fd) return it; } - fmt::warn("not a valid file descriptor\n"); + fmt::warn("fs: not a valid file descriptor\n"); return nullptr; } \ No newline at end of file diff --git a/kernel/fs/fs.cpp b/kernel/fs/fs.cpp index 8c32c351..4aa34463 100644 --- a/kernel/fs/fs.cpp +++ b/kernel/fs/fs.cpp @@ -44,7 +44,7 @@ ssize_t fs_write(int fd, const void *buf, size_t len) { UART::putchar(((const char *)buf)[i]); return len; default: - fmt::panic("fs_write: not implemented\n"); + fmt::panic("fs: fs_write not implemented\n"); // return FAT32::write(fd, buf, len); } } @@ -57,8 +57,8 @@ ssize_t fs_lseek(int fd, ssize_t offset, int whence) { switch (whence) { case SEEK_SET: fdesp->offset = offset; break; case SEEK_CUR: fdesp->offset += offset; break; - case SEEK_END: fdesp->offset = fdesp->size + offset; break; - default: fmt::warn("invalid whence\n"); return -1; + case SEEK_END: fdesp->offset = fdesp->stat.st_size + offset; break; + default: fmt::warn("fs: invalid whence\n"); return -1; } return fdesp->offset; } diff --git a/kernel/include/fs/vfs.h b/kernel/include/fs/vfs.h index 0f37fd12..a94fab97 100644 --- a/kernel/include/fs/vfs.h +++ b/kernel/include/fs/vfs.h @@ -78,9 +78,8 @@ typedef struct linux_dirent64 dentry_t; struct fdesp_t { int idx; int flags; - uint64_t ino; - size_t size; size_t offset; + kstat_t stat; }; } // namespace VFS diff --git a/kernel/loader/loader.cpp b/kernel/loader/loader.cpp index 690ccf74..e3e9df4d 100644 --- a/kernel/loader/loader.cpp +++ b/kernel/loader/loader.cpp @@ -5,11 +5,14 @@ #include <fs.h> #include <vm.h> #include <stdlib.h> +#include <string.h> uint64_t loader(const char *name, pcb_t *proc) { int fd = fs_open(name, 0); + fmt::info("loader: loading {}({})\n", Slice<const char>(name, strnlen(name, 64)), fd); + Elf64_Ehdr ehdr; assert(fs_read(fd, &ehdr, sizeof(ehdr)) == sizeof(ehdr)); assert(*reinterpret_cast<uint32_t*> (ehdr.e_ident) == *reinterpret_cast<uint32_t*> (const_cast<char*> ("\x7f" "ELF"))); -- GitLab From c6a51056b75a0c7bf2f37f0b348c886ed367e594 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 14:22:35 +0800 Subject: [PATCH 07/20] feat: check O_DIRECTORY --- kernel/fs/fat32/fs.cpp | 1 + kernel/scheduler/sched.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index 2a625f4a..95390046 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -228,6 +228,7 @@ int openat(int dirfd, const char *pathname, int flags) { if (*p && (stat.st_mode & S_IFMT) != S_IFDIR) return -1; // not diretory if (*p) p++; } + if ((stat.st_mode & S_IFMT) == S_IFDIR && !(flags & O_DIRECTORY)) return -1; // not file VFS::fdesp_t *new_fd = alloc_fdesp(); new_fd->idx = pcb->nfd++; new_fd->flags = flags; diff --git a/kernel/scheduler/sched.cpp b/kernel/scheduler/sched.cpp index 8e061703..4be407ea 100644 --- a/kernel/scheduler/sched.cpp +++ b/kernel/scheduler/sched.cpp @@ -88,7 +88,7 @@ void init_pcb(hartid_t hartid) { void init_pcb_cwd() { pcb_t *proc = get_current_proc(); - proc->cwd = fs_open("/", 0); + proc->cwd = fs_open("/", O_DIRECTORY | O_RDONLY); } extern "C" void ret_from_interrupt(); -- GitLab From c7862ac4d8fc67afa7eb10906a7b2a95cce67917 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 14:29:57 +0800 Subject: [PATCH 08/20] fix: sign compare --- kernel/fs/fat32/fs.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index 95390046..4c3af3ec 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -244,8 +244,8 @@ ssize_t read(int fd, void *buf, size_t count) { if (fdesp->flags & O_WRONLY) return 0; size_t off = fdesp->offset; - if (off > fdesp->stat.st_size || off + count < off) return 0; - if (off + count > fdesp->stat.st_size) count = fdesp->stat.st_size - off; + if (off > (size_t) fdesp->stat.st_size || off + count < off) return 0; + if (off + count > (size_t) fdesp->stat.st_size) count = (size_t) fdesp->stat.st_size - off; if (count == 0) return 0; location_t loc = locate(fdesp->stat.st_ino, off); @@ -253,7 +253,7 @@ ssize_t read(int fd, void *buf, size_t count) { do { fmt::debug("FAT32: loading cluster: {}\n", loc.cluster); sector_t base_sec = first_sector_of_cluster(loc.cluster); - for (sector_t sec = base_sec + loc.sector; off < fdesp->stat.st_size && sec < base_sec + cluster_size; sec++) { + for (sector_t sec = base_sec + loc.sector; off < (size_t) fdesp->stat.st_size && sec < base_sec + cluster_size; sec++) { buf_t *_buf = buf_read(DEV_VIRTIO_BLK, sec); size_t n = min(count - nread, sector_size - loc.offset); memcpy((char *) buf + nread, _buf->data + loc.offset, n); @@ -263,7 +263,7 @@ ssize_t read(int fd, void *buf, size_t count) { loc.offset = 0; } loc.sector = 0; - } while (off < fdesp->stat.st_size && nread < count && (loc.cluster = next_cluster(loc.cluster))); + } while (off < (size_t) fdesp->stat.st_size && nread < count && (loc.cluster = next_cluster(loc.cluster))); fdesp->offset += nread; -- GitLab From ad07fb944c1ae0f0ab437fc387155b2afbe1a582 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 14:31:26 +0800 Subject: [PATCH 09/20] fix: return -1 on failure --- kernel/fs/fat32/fs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index 4c3af3ec..7d79c9ce 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -212,7 +212,7 @@ VFS::kstat_t lookup(const char *name) { int openat(int dirfd, const char *pathname, int flags) { pcb_t *pcb = get_current_proc(); VFS::fdesp_t *dir = pathname[0] == '/' ? &root_fd : get_fdesp(dirfd, pcb); - assert(dir); + if (!dir) return -1; VFS::kstat_t stat = dir->stat; const char *p = pathname[0] == '/' ? pathname + 1 : pathname; char name_buf[DENTRY_NAME_LEN] = {0}; @@ -240,7 +240,7 @@ int openat(int dirfd, const char *pathname, int flags) { ssize_t read(int fd, void *buf, size_t count) { VFS::fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); - assert(fdesp); + if (!fdesp) return -1; if (fdesp->flags & O_WRONLY) return 0; size_t off = fdesp->offset; -- GitLab From 3b09cde0e64559a746fe49cf6074fdf1fa679c19 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 14:35:14 +0800 Subject: [PATCH 10/20] feat: fs_fstat --- kernel/fs/fs.cpp | 30 ++++++++++++++++++++++++++++++ kernel/include/fs.h | 1 + kernel/syscall/syscall.cpp | 3 +-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/kernel/fs/fs.cpp b/kernel/fs/fs.cpp index 4aa34463..98a26dd7 100644 --- a/kernel/fs/fs.cpp +++ b/kernel/fs/fs.cpp @@ -2,6 +2,7 @@ #include <driver/uart.h> #include <stdint.h> #include <stddef.h> +#include <string.h> #include <sched.h> #include <fs.h> #include <fs/fat32.h> @@ -63,6 +64,35 @@ ssize_t fs_lseek(int fd, ssize_t offset, int whence) { return fdesp->offset; } +int fs_fstat(int fd, kstat_t *statbuf) { + if (fd == STDIN || fd == STDOUT || fd == STDERR) { + kstat_t __chrstat = { + .st_dev = 0, + .st_ino = 0, + .st_mode = S_IFCHR, + .st_nlink = 1, + .st_uid = 0, + .st_gid = 0, + .st_rdev = 0, + .st_size = 0, + .st_blksize = 0, + .st_blocks = 0, + .st_atime_sec = 0, + .st_atime_nsec = 0, + .st_mtime_sec = 0, + .st_mtime_nsec = 0, + .st_ctime_sec = 0, + .st_ctime_nsec = 0, + }; + memcpy(statbuf, &__chrstat, sizeof(kstat_t)); + return 0; + } + fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); + if (!fdesp) return -1; + memcpy(statbuf, &fdesp->stat, sizeof(kstat_t)); + return 0; +} + int fs_close(int fd) { if (fd == STDIN || fd == STDOUT || fd == STDERR) return 0; diff --git a/kernel/include/fs.h b/kernel/include/fs.h index c1080474..44701fe8 100644 --- a/kernel/include/fs.h +++ b/kernel/include/fs.h @@ -33,6 +33,7 @@ int fs_open(const char *pathname, int flags); ssize_t fs_read(int fd, void *buf, size_t len); ssize_t fs_write(int fd, const void *buf, size_t len); ssize_t fs_lseek(int fd, ssize_t offset, int whence); +int fs_fstat(int fd, kstat_t *statbuf); int fs_close(int fd); #endif diff --git a/kernel/syscall/syscall.cpp b/kernel/syscall/syscall.cpp index 4ace838f..b5b1ef81 100644 --- a/kernel/syscall/syscall.cpp +++ b/kernel/syscall/syscall.cpp @@ -423,8 +423,7 @@ static void sys_fstatat(Context *c) { } static void sys_fstat(Context *c) { - fmt::err("unimplemented syscall fstat\n"); - exit(1); + a0 = fs_fstat(a0, (kstat_t *) a1); } static void sys_sync(Context *c) { -- GitLab From a09faf768a882fa73412e4b6c6de7aace586914f Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 14:59:56 +0800 Subject: [PATCH 11/20] fix: clear name_buf --- kernel/fs/fat32/fs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index 7d79c9ce..c367676e 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -215,9 +215,9 @@ int openat(int dirfd, const char *pathname, int flags) { if (!dir) return -1; VFS::kstat_t stat = dir->stat; const char *p = pathname[0] == '/' ? pathname + 1 : pathname; - char name_buf[DENTRY_NAME_LEN] = {0}; while (*p) { - int i=0; + char name_buf[DENTRY_NAME_LEN] = {0}; + int i = 0; while (*p && *p != '/' && i<DENTRY_NAME_LEN) name_buf[i++] = *p++; fmt::debug("FAT32: looking for {}\n", Slice<const char>(name_buf, i)); if (i == DENTRY_NAME_LEN) -- GitLab From 99b0ac4be5a77ca257062a36ac71db64070c5fdb Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 15:02:37 +0800 Subject: [PATCH 12/20] feat: handle name entry & support . and .. --- kernel/fs/fat32/fs.cpp | 43 ++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index c367676e..5470f303 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -130,6 +130,8 @@ bool init() { root_fd.flags = O_DIRECTORY; root_fd.offset = 0; root_fd.stat.st_ino = __bpb.BPB_RootClus; + root_fd.stat.st_nlink = 1; + root_fd.stat.st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; buf_release(buf); return true; @@ -146,7 +148,7 @@ VFS::kstat_t lookup(const cluster_t first_clus, const char *what) { // we simply use first clusuter number as inode number cluster_t clus = first_clus; bool end = false; - char lfn_buf[DENTRY_NAME_LEN] = {0}; + char name_buf[DENTRY_NAME_LEN] = {0}; do { sector_t base_sec = first_sector_of_cluster(clus); for (sector_t sec = base_sec; !end && sec < base_sec + cluster_size; sec++) { @@ -164,14 +166,36 @@ VFS::kstat_t lookup(const cluster_t first_clus, const char *what) { buf_release(buf); return {0}; } - namencat(lfn_buf, entry->lfnentry.name1, DENTRY_NAME_LEN, LFN_NAME1_LEN); - namencat(lfn_buf, entry->lfnentry.name2, DENTRY_NAME_LEN, LFN_NAME2_LEN); - namencat(lfn_buf, entry->lfnentry.name3, DENTRY_NAME_LEN, LFN_NAME3_LEN); + namencat(name_buf, entry->lfnentry.name1, DENTRY_NAME_LEN, LFN_NAME1_LEN); + namencat(name_buf, entry->lfnentry.name2, DENTRY_NAME_LEN, LFN_NAME2_LEN); + namencat(name_buf, entry->lfnentry.name3, DENTRY_NAME_LEN, LFN_NAME3_LEN); } else { - char *name = lfn_buf[0] ? lfn_buf : (char *) entry->dentry.name; - size_t len = lfn_buf[0] ? strnlen(lfn_buf, DENTRY_NAME_LEN) : 8; - // fmt::debug("FAT32: ... name: {}\n", Slice<const char>(name, len)); - if (strncmp(name, what, len) == 0 && what[len] == '\0') { + size_t len; + if (name_buf[0]) { + len = strnlen(name_buf, DENTRY_NAME_LEN); + } else { + for (len=0; len<8; len++) { + if (entry->dentry.name[len] == 0x20) + break; + name_buf[len] = entry->dentry.name[len]; + } + if (entry->dentry.ext[0] != 0x20) { + name_buf[len++] = '.'; + } + for (int i=0; i<3; i++) { + if (entry->dentry.ext[i] == 0x20) + break; + name_buf[len++] = entry->dentry.ext[i]; + } + } + // fmt::debug("FAT32: ... name: {}, clus: {}\n", Slice<const char>(name_buf, len), (uint32_t) entry->dentry.clus_hi << 16 | entry->dentry.clus_lo); + if (strncmp(name_buf, what, len+1) == 0) { + if (strncmp(name_buf, "..", 3) == 0 && ((uint32_t) entry->dentry.clus_hi << 16 | entry->dentry.clus_lo) == 0) { + // NOTE: if name==".." and clus==0, it's root dir + // but root dir's actual clus is not 0 + // so we use root_fd.stat instead + return root_fd.stat; + } VFS::kstat_t stat; stat.st_dev = DEV_VIRTIO_BLK; stat.st_ino = (uint32_t) entry->dentry.clus_hi << 16 | entry->dentry.clus_lo; @@ -194,8 +218,7 @@ VFS::kstat_t lookup(const cluster_t first_clus, const char *what) { buf_release(buf); return stat; } - - lfn_buf[0] = '\0'; + name_buf[0] = '\0'; } } buf_release(buf); -- GitLab From 91e1ba71fc62ad3dc3e94ba95c836b53a313d5fb Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 15:24:39 +0800 Subject: [PATCH 13/20] feat: fs_chdir --- kernel/fs/fs.cpp | 10 ++++++++++ kernel/include/fs.h | 1 + kernel/syscall/syscall.cpp | 5 +++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/kernel/fs/fs.cpp b/kernel/fs/fs.cpp index 98a26dd7..bcd34941 100644 --- a/kernel/fs/fs.cpp +++ b/kernel/fs/fs.cpp @@ -16,6 +16,15 @@ void init_fs() { fmt::info(" SUCCESS\n"); } +int fs_chdir(const char *path) { + int newdir = fs_open(path, O_DIRECTORY); + if (newdir < 0) return -1; + pcb_t *pcb = get_current_proc(); + fs_close(pcb->cwd); + pcb->cwd = newdir; + return 0; +} + int fs_openat(int dirfd, const char *pathname, int flags) { return FAT32::openat(dirfd, pathname, flags); } @@ -104,5 +113,6 @@ int fs_close(int fd) { return 0; } } + fmt::warn("fs: close failed\n"); return -1; } diff --git a/kernel/include/fs.h b/kernel/include/fs.h index 44701fe8..7cd462a7 100644 --- a/kernel/include/fs.h +++ b/kernel/include/fs.h @@ -28,6 +28,7 @@ typedef VFS::fdesp_t fdesp_t; typedef VFS::kstat_t kstat_t; void init_fs(); +int fs_chdir(const char *path); int fs_openat(int dirfd, const char *pathname, int flags); int fs_open(const char *pathname, int flags); ssize_t fs_read(int fd, void *buf, size_t len); diff --git a/kernel/syscall/syscall.cpp b/kernel/syscall/syscall.cpp index b5b1ef81..18c5d642 100644 --- a/kernel/syscall/syscall.cpp +++ b/kernel/syscall/syscall.cpp @@ -267,8 +267,9 @@ static void sys_faccessat(Context *c) { } static void sys_chdir(Context *c) { - fmt::err("unimplemented syscall chdir\n"); - exit(1); + enable_interrupt(); + a0 = fs_chdir((const char *) a0); + disable_interrupt(); } static void sys_fchdir(Context *c) { -- GitLab From 3679fe5918f55aadbb8c390bfd41f89cdcb8c2ea Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 17:11:18 +0800 Subject: [PATCH 14/20] feat: fs_dup & fs_dup3 --- kernel/fs/fdesp.cpp | 1 - kernel/fs/fs.cpp | 32 ++++++++++++++++++++++++++++++++ kernel/include/fs.h | 2 ++ kernel/syscall/syscall.cpp | 6 ++---- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/kernel/fs/fdesp.cpp b/kernel/fs/fdesp.cpp index 6a8d0aa0..609c0714 100644 --- a/kernel/fs/fdesp.cpp +++ b/kernel/fs/fdesp.cpp @@ -23,6 +23,5 @@ fdesp_t *get_fdesp(int fd, pcb_t *pcb) { if (it->idx == fd) return it; } - fmt::warn("fs: not a valid file descriptor\n"); return nullptr; } \ No newline at end of file diff --git a/kernel/fs/fs.cpp b/kernel/fs/fs.cpp index bcd34941..903870a5 100644 --- a/kernel/fs/fs.cpp +++ b/kernel/fs/fs.cpp @@ -16,6 +16,38 @@ void init_fs() { fmt::info(" SUCCESS\n"); } +int fs_dup(int fd) { + pcb_t *pcb = get_current_proc(); + fdesp_t *fdesp = get_fdesp(fd, pcb); + if (!fdesp) return -1; + + fdesp_t *newfdesp = alloc_fdesp(); + if (!newfdesp) return -1; + + memcpy(newfdesp, fdesp, sizeof(fdesp_t)); + newfdesp->idx = pcb->nfd++; + pcb->fd_list.push_back(newfdesp); + return newfdesp->idx; +} + +int fs_dup3(int oldfd, int newfd, int flags) { + if (oldfd == newfd) return -1; + + pcb_t *pcb = get_current_proc(); + fdesp_t *fdesp = get_fdesp(oldfd, pcb); + if (!fdesp) return -1; + + fdesp_t *newfdesp = get_fdesp(newfd, pcb); + if (!newfdesp) newfdesp = alloc_fdesp(); + if (!newfdesp) return -1; + + memcpy(newfdesp, fdesp, sizeof(fdesp_t)); + newfdesp->idx = newfd; + newfdesp->flags |= flags; + pcb->fd_list.push_back(newfdesp); + return newfdesp->idx; +} + int fs_chdir(const char *path) { int newdir = fs_open(path, O_DIRECTORY); if (newdir < 0) return -1; diff --git a/kernel/include/fs.h b/kernel/include/fs.h index 7cd462a7..be5b6f3b 100644 --- a/kernel/include/fs.h +++ b/kernel/include/fs.h @@ -28,6 +28,8 @@ typedef VFS::fdesp_t fdesp_t; typedef VFS::kstat_t kstat_t; void init_fs(); +int fs_dup(int fd); +int fs_dup3(int oldfd, int newfd, int flags); int fs_chdir(const char *path); int fs_openat(int dirfd, const char *pathname, int flags); int fs_open(const char *pathname, int flags); diff --git a/kernel/syscall/syscall.cpp b/kernel/syscall/syscall.cpp index 18c5d642..dd86e649 100644 --- a/kernel/syscall/syscall.cpp +++ b/kernel/syscall/syscall.cpp @@ -137,13 +137,11 @@ static void sys_epoll_pwait(Context *c) { } static void sys_dup(Context *c) { - fmt::err("unimplemented syscall dup\n"); - exit(1); + a0 = fs_dup(a0); } static void sys_dup3(Context *c) { - fmt::err("unimplemented syscall dup3\n"); - exit(1); + a0 = fs_dup3(a0, a1, a2); } static void sys_fcntl(Context *c) { -- GitLab From 923761c09a3b4864e8f243802ae0a9b195cd7000 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 19:26:40 +0800 Subject: [PATCH 15/20] feat: add unimplemented APIs --- kernel/fs/fat32/fs.cpp | 5 +++++ kernel/fs/pipe.cpp | 15 +++++++++++++++ kernel/include/fs/fat32.h | 1 + kernel/include/fs/pipe.h | 11 +++++++++++ 4 files changed, 32 insertions(+) create mode 100644 kernel/fs/pipe.cpp create mode 100644 kernel/include/fs/pipe.h diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index 5470f303..ff4b9b03 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -293,6 +293,11 @@ ssize_t read(int fd, void *buf, size_t count) { return (ssize_t) nread; } +ssize_t write(int fd, const void *buf, size_t count) { + fmt::err("fat32: write not implemented\n"); + return -1; +} + // TODO } // namespace fat32 diff --git a/kernel/fs/pipe.cpp b/kernel/fs/pipe.cpp new file mode 100644 index 00000000..92ba98e1 --- /dev/null +++ b/kernel/fs/pipe.cpp @@ -0,0 +1,15 @@ +#include <stdint.h> +#include <stddef.h> +#include <fmt.hpp> + +namespace PIPE { +ssize_t read(int fd, void *buf, size_t len) { + fmt::err("pipe: read not implemented\n"); + return -1; +} + +ssize_t write(int fd, const void *buf, size_t len) { + fmt::err("pipe: write not implemented\n"); + return -1; +} +} // namespace PIPE diff --git a/kernel/include/fs/fat32.h b/kernel/include/fs/fat32.h index 01fc75dd..bbc3e19b 100644 --- a/kernel/include/fs/fat32.h +++ b/kernel/include/fs/fat32.h @@ -122,6 +122,7 @@ VFS::kstat_t lookup(const cluster_t first_clus, const char *name); VFS::kstat_t lookup(const char *name); int openat(int dirfd, const char *pathname, int flags); ssize_t read(int fd, void *buf, size_t count); +ssize_t write(int fd, const void *buf, size_t count); } // namespace FAT32 diff --git a/kernel/include/fs/pipe.h b/kernel/include/fs/pipe.h new file mode 100644 index 00000000..595bae2c --- /dev/null +++ b/kernel/include/fs/pipe.h @@ -0,0 +1,11 @@ +#ifndef __FS_PIPE_H__ +#define __FS_PIPE_H__ + +#include <stddef.h> + +namespace PIPE { +ssize_t read(int fd, void *buf, size_t len); +ssize_t write(int fd, const void *buf, size_t len); +} // namespace PIPE + +#endif -- GitLab From ca0e46ecefcf4e463d97de312bd9019642f77e6b Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 19:27:30 +0800 Subject: [PATCH 16/20] feat: add fdesp for reserved fds(stdin/out/err) --- kernel/fs/fdesp.cpp | 41 ++++++++++++++++++++++++++++++++----- kernel/fs/fs.cpp | 50 +++++++++++++++++++-------------------------- 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/kernel/fs/fdesp.cpp b/kernel/fs/fdesp.cpp index 609c0714..31fe120f 100644 --- a/kernel/fs/fdesp.cpp +++ b/kernel/fs/fdesp.cpp @@ -6,6 +6,30 @@ static SimpleAllocator<fdesp_t> fdesp_allocator; +static fdesp_t fdesp_stdin = { + .idx = STDIN, + .flags = O_RDONLY, + .stat = { + .st_mode = S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, + }, +}; + +static fdesp_t fdesp_stdout = { + .idx = STDOUT, + .flags = O_WRONLY, + .stat = { + .st_mode = S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, + }, +}; + +static fdesp_t fdesp_stderr = { + .idx = STDERR, + .flags = O_WRONLY, + .stat = { + .st_mode = S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, + }, +}; + fdesp_t *alloc_fdesp() { return fdesp_allocator.create(); } @@ -15,13 +39,20 @@ void free_fdesp(fdesp_t *fd) { } fdesp_t *get_fdesp(int fd, pcb_t *pcb) { - if (fd == AT_FDCWD) { + switch (fd) { + case STDIN: return &fdesp_stdin; + case STDOUT: return &fdesp_stdout; + case STDERR: return &fdesp_stderr; + case AT_FDCWD: fmt::debug("fs: AT_FDCWD = {}\n", pcb->cwd); fd = pcb->cwd; + // do not break here and run as default + default: + for (auto it : pcb->fd_list) { + if (it->idx == fd) + return it; + } } - for (auto it : pcb->fd_list) { - if (it->idx == fd) - return it; - } + // not found; return nullptr; } \ No newline at end of file diff --git a/kernel/fs/fs.cpp b/kernel/fs/fs.cpp index 903870a5..42ad5288 100644 --- a/kernel/fs/fs.cpp +++ b/kernel/fs/fs.cpp @@ -7,6 +7,7 @@ #include <fs.h> #include <fs/fat32.h> #include <fs/vfs.h> +#include <fs/pipe.h> #include <fs/local.h> #include <fmt.hpp> @@ -68,26 +69,39 @@ int fs_open(const char *pathname, int flags) { ssize_t fs_read(int fd, void *buf, size_t len) { if (len == 0) return 0; - switch (fd) { - case STDIN: + fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); + if (!fdesp) return -1; + switch (fdesp->stat.st_mode & S_IFMT) { + case S_IFCHR: *(char *)buf = UART::getchar(); return 1; - default: + case S_IFIFO: + return PIPE::read(fd, buf, len); + case S_IFDIR: case 0: return FAT32::read(fd, buf, len); + default: + fmt::warn("fs: read mode unknown\n"); + return -1; } } ssize_t fs_write(int fd, const void *buf, size_t len) { if (len == 0) return 0; - switch (fd) { - case STDOUT: case STDERR: + fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); + if (!fdesp) return -1; + switch (fdesp->stat.st_mode & S_IFMT) { + case S_IFCHR: for (size_t i=0; i<len; i++) UART::putchar(((const char *)buf)[i]); return len; + case S_IFIFO: + return PIPE::write(fd, buf, len); + case S_IFDIR: case 0: + return FAT32::write(fd, buf, len); default: - fmt::panic("fs: fs_write not implemented\n"); - // return FAT32::write(fd, buf, len); + fmt::warn("fs: read mode unknown\n"); + return -1; } } @@ -106,28 +120,6 @@ ssize_t fs_lseek(int fd, ssize_t offset, int whence) { } int fs_fstat(int fd, kstat_t *statbuf) { - if (fd == STDIN || fd == STDOUT || fd == STDERR) { - kstat_t __chrstat = { - .st_dev = 0, - .st_ino = 0, - .st_mode = S_IFCHR, - .st_nlink = 1, - .st_uid = 0, - .st_gid = 0, - .st_rdev = 0, - .st_size = 0, - .st_blksize = 0, - .st_blocks = 0, - .st_atime_sec = 0, - .st_atime_nsec = 0, - .st_mtime_sec = 0, - .st_mtime_nsec = 0, - .st_ctime_sec = 0, - .st_ctime_nsec = 0, - }; - memcpy(statbuf, &__chrstat, sizeof(kstat_t)); - return 0; - } fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); if (!fdesp) return -1; memcpy(statbuf, &fdesp->stat, sizeof(kstat_t)); -- GitLab From 149e6adf5840723a38db9fab5fe17cfb545c16f9 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 19:33:32 +0800 Subject: [PATCH 17/20] feat: check fdesp->flags in fs & pass fdesp instead of fd --- kernel/fs/fat32/fs.cpp | 13 ++++--------- kernel/fs/fs.cpp | 17 +++++++++++------ kernel/fs/pipe.cpp | 5 +++-- kernel/include/fs/fat32.h | 6 +++--- kernel/include/fs/pipe.h | 4 ++-- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index ff4b9b03..592d47c9 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -232,10 +232,9 @@ VFS::kstat_t lookup(const char *name) { return lookup(root_dentry.d_ino, name); } -int openat(int dirfd, const char *pathname, int flags) { +int openat(VFS::fdesp_t *dir, const char *pathname, int flags) { pcb_t *pcb = get_current_proc(); - VFS::fdesp_t *dir = pathname[0] == '/' ? &root_fd : get_fdesp(dirfd, pcb); - if (!dir) return -1; + if (pathname[0] == '/') dir = &root_fd; VFS::kstat_t stat = dir->stat; const char *p = pathname[0] == '/' ? pathname + 1 : pathname; while (*p) { @@ -261,11 +260,7 @@ int openat(int dirfd, const char *pathname, int flags) { return new_fd->idx; } -ssize_t read(int fd, void *buf, size_t count) { - VFS::fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); - if (!fdesp) return -1; - if (fdesp->flags & O_WRONLY) return 0; - +ssize_t read(VFS::fdesp_t *fdesp, void *buf, size_t count) { size_t off = fdesp->offset; if (off > (size_t) fdesp->stat.st_size || off + count < off) return 0; if (off + count > (size_t) fdesp->stat.st_size) count = (size_t) fdesp->stat.st_size - off; @@ -293,7 +288,7 @@ ssize_t read(int fd, void *buf, size_t count) { return (ssize_t) nread; } -ssize_t write(int fd, const void *buf, size_t count) { +ssize_t write(VFS::fdesp_t *fdesp, const void *buf, size_t count) { fmt::err("fat32: write not implemented\n"); return -1; } diff --git a/kernel/fs/fs.cpp b/kernel/fs/fs.cpp index 42ad5288..d1d36968 100644 --- a/kernel/fs/fs.cpp +++ b/kernel/fs/fs.cpp @@ -59,11 +59,14 @@ int fs_chdir(const char *path) { } int fs_openat(int dirfd, const char *pathname, int flags) { - return FAT32::openat(dirfd, pathname, flags); + fdesp_t *dir = get_fdesp(dirfd, get_current_proc()); + if (!dir && pathname[0] != '/') + return -1; + return FAT32::openat(dir, pathname, flags); } int fs_open(const char *pathname, int flags) { - return FAT32::openat(AT_FDCWD, pathname, flags); + return fs_openat(AT_FDCWD, pathname, flags); } ssize_t fs_read(int fd, void *buf, size_t len) { @@ -71,14 +74,15 @@ ssize_t fs_read(int fd, void *buf, size_t len) { return 0; fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); if (!fdesp) return -1; + if (fdesp->flags & O_WRONLY || fdesp->flags & O_DIRECTORY) return -1; switch (fdesp->stat.st_mode & S_IFMT) { case S_IFCHR: *(char *)buf = UART::getchar(); return 1; case S_IFIFO: - return PIPE::read(fd, buf, len); + return PIPE::read(fdesp, buf, len); case S_IFDIR: case 0: - return FAT32::read(fd, buf, len); + return FAT32::read(fdesp, buf, len); default: fmt::warn("fs: read mode unknown\n"); return -1; @@ -90,15 +94,16 @@ ssize_t fs_write(int fd, const void *buf, size_t len) { return 0; fdesp_t *fdesp = get_fdesp(fd, get_current_proc()); if (!fdesp) return -1; + if (fdesp->flags & O_RDONLY || fdesp->flags & O_DIRECTORY) return -1; switch (fdesp->stat.st_mode & S_IFMT) { case S_IFCHR: for (size_t i=0; i<len; i++) UART::putchar(((const char *)buf)[i]); return len; case S_IFIFO: - return PIPE::write(fd, buf, len); + return PIPE::write(fdesp, buf, len); case S_IFDIR: case 0: - return FAT32::write(fd, buf, len); + return FAT32::write(fdesp, buf, len); default: fmt::warn("fs: read mode unknown\n"); return -1; diff --git a/kernel/fs/pipe.cpp b/kernel/fs/pipe.cpp index 92ba98e1..a3312f12 100644 --- a/kernel/fs/pipe.cpp +++ b/kernel/fs/pipe.cpp @@ -1,14 +1,15 @@ #include <stdint.h> #include <stddef.h> #include <fmt.hpp> +#include <fs.h> namespace PIPE { -ssize_t read(int fd, void *buf, size_t len) { +ssize_t read(fdesp_t *fdesp, void *buf, size_t len) { fmt::err("pipe: read not implemented\n"); return -1; } -ssize_t write(int fd, const void *buf, size_t len) { +ssize_t write(fdesp_t *fdesp, const void *buf, size_t len) { fmt::err("pipe: write not implemented\n"); return -1; } diff --git a/kernel/include/fs/fat32.h b/kernel/include/fs/fat32.h index bbc3e19b..ef74f625 100644 --- a/kernel/include/fs/fat32.h +++ b/kernel/include/fs/fat32.h @@ -120,9 +120,9 @@ struct location_t { bool init(); VFS::kstat_t lookup(const cluster_t first_clus, const char *name); VFS::kstat_t lookup(const char *name); -int openat(int dirfd, const char *pathname, int flags); -ssize_t read(int fd, void *buf, size_t count); -ssize_t write(int fd, const void *buf, size_t count); +int openat(VFS::fdesp_t *dir, const char *pathname, int flags); +ssize_t read(VFS::fdesp_t *fdesp, void *buf, size_t count); +ssize_t write(VFS::fdesp_t *fdesp, const void *buf, size_t count); } // namespace FAT32 diff --git a/kernel/include/fs/pipe.h b/kernel/include/fs/pipe.h index 595bae2c..39e8aa8f 100644 --- a/kernel/include/fs/pipe.h +++ b/kernel/include/fs/pipe.h @@ -4,8 +4,8 @@ #include <stddef.h> namespace PIPE { -ssize_t read(int fd, void *buf, size_t len); -ssize_t write(int fd, const void *buf, size_t len); +ssize_t read(fdesp_t *fdesp, void *buf, size_t len); +ssize_t write(fdesp_t *fdesp, const void *buf, size_t len); } // namespace PIPE #endif -- GitLab From afd182e2c544a87ebbf701728067fff2cea88cfe Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 19:44:43 +0800 Subject: [PATCH 18/20] refactor: fs_open --- kernel/fs/fs.cpp | 4 ---- kernel/include/fs.h | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/kernel/fs/fs.cpp b/kernel/fs/fs.cpp index d1d36968..10131a62 100644 --- a/kernel/fs/fs.cpp +++ b/kernel/fs/fs.cpp @@ -65,10 +65,6 @@ int fs_openat(int dirfd, const char *pathname, int flags) { return FAT32::openat(dir, pathname, flags); } -int fs_open(const char *pathname, int flags) { - return fs_openat(AT_FDCWD, pathname, flags); -} - ssize_t fs_read(int fd, void *buf, size_t len) { if (len == 0) return 0; diff --git a/kernel/include/fs.h b/kernel/include/fs.h index be5b6f3b..db944fb9 100644 --- a/kernel/include/fs.h +++ b/kernel/include/fs.h @@ -32,7 +32,9 @@ int fs_dup(int fd); int fs_dup3(int oldfd, int newfd, int flags); int fs_chdir(const char *path); int fs_openat(int dirfd, const char *pathname, int flags); -int fs_open(const char *pathname, int flags); +static inline int fs_open(const char *pathname, int flags) { + return fs_openat(AT_FDCWD, pathname, flags); +} ssize_t fs_read(int fd, void *buf, size_t len); ssize_t fs_write(int fd, const void *buf, size_t len); ssize_t fs_lseek(int fd, ssize_t offset, int whence); -- GitLab From 3397efe6daac2a7f1a772f7a8e74eefb5a0b9ad7 Mon Sep 17 00:00:00 2001 From: xu_zh <xuzhihao20@mails.ucas.ac.cn> Date: Wed, 10 May 2023 19:51:28 +0800 Subject: [PATCH 19/20] refactor: remove unused API --- kernel/fs/fat32/fs.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/kernel/fs/fat32/fs.cpp b/kernel/fs/fat32/fs.cpp index 592d47c9..27340970 100644 --- a/kernel/fs/fat32/fs.cpp +++ b/kernel/fs/fat32/fs.cpp @@ -227,11 +227,6 @@ VFS::kstat_t lookup(const cluster_t first_clus, const char *what) { return {0}; } -// lookup in root dir -VFS::kstat_t lookup(const char *name) { - return lookup(root_dentry.d_ino, name); -} - int openat(VFS::fdesp_t *dir, const char *pathname, int flags) { pcb_t *pcb = get_current_proc(); if (pathname[0] == '/') dir = &root_fd; -- GitLab From 0892fb8f672bb6ca6e375d10c1916c5809496c92 Mon Sep 17 00:00:00 2001 From: ngc7331 <xuzhihao20@mails.ucas.ac.cn> Date: Thu, 11 May 2023 11:03:04 +0800 Subject: [PATCH 20/20] feat: pipe open & close --- kernel/fs/fdesp.cpp | 13 ++++++ kernel/fs/fs.cpp | 35 +++++++++++++++- kernel/fs/pipe.cpp | 81 ++++++++++++++++++++++++++++++++++++++ kernel/include/fs.h | 1 + kernel/include/fs/local.h | 1 + kernel/include/fs/pipe.h | 13 ++++++ kernel/syscall/syscall.cpp | 3 +- 7 files changed, 144 insertions(+), 3 deletions(-) diff --git a/kernel/fs/fdesp.cpp b/kernel/fs/fdesp.cpp index 31fe120f..24e04068 100644 --- a/kernel/fs/fdesp.cpp +++ b/kernel/fs/fdesp.cpp @@ -34,6 +34,19 @@ fdesp_t *alloc_fdesp() { return fdesp_allocator.create(); } +int alloc2_fdesp(fdesp_t *fdesp[2]) { + fdesp[0] = fdesp_allocator.create(); + if (!fdesp[0]) { + return -1; + } + fdesp[1] = fdesp_allocator.create(); + if (!fdesp[1]) { + fdesp_allocator.destroy(fdesp[0]); + return -1; + } + return 0; +} + void free_fdesp(fdesp_t *fd) { fdesp_allocator.destroy(fd); } diff --git a/kernel/fs/fs.cpp b/kernel/fs/fs.cpp index 10131a62..cd5536f9 100644 --- a/kernel/fs/fs.cpp +++ b/kernel/fs/fs.cpp @@ -17,6 +17,30 @@ void init_fs() { fmt::info(" SUCCESS\n"); } +int fs_pipe2(int fd[2], int flags) { + if (flags != 0) { + fmt::err("fs: pipe2: flags not supported\n"); + return -1; + } + fdesp_t *fdesp[2]; + if (alloc2_fdesp(fdesp) != 0) { + fmt::err("fs: pipe2: alloc2_fdesp failed\n"); + return -1; + } + pcb_t *pcb = get_current_proc(); + fdesp[0]->idx = pcb->nfd++; + fdesp[1]->idx = pcb->nfd++; + if (PIPE::open(fdesp) != 0) { + fmt::err("fs: pipe2: PIPE::create failed\n"); + free_fdesp(fdesp[0]); + free_fdesp(fdesp[1]); + return -1; + } + pcb->fd_list.push_back(fdesp[0]); + pcb->fd_list.push_back(fdesp[1]); + return 0; +} + int fs_dup(int fd) { pcb_t *pcb = get_current_proc(); fdesp_t *fdesp = get_fdesp(fd, pcb); @@ -131,8 +155,17 @@ int fs_close(int fd) { if (fd == STDIN || fd == STDOUT || fd == STDERR) return 0; pcb_t *pcb = get_current_proc(); + fdesp_t *fdesp = get_fdesp(fd, pcb); + if (!fdesp) { + fmt::warn("fs: close: invalid fd\n"); + return -1; + } + if ((fdesp->stat.st_mode & S_IFMT) == S_IFIFO && PIPE::close(fdesp) != 0) { + fmt::warn("fs: close pipe failed\n"); + return -1; + } for (auto it = pcb->fd_list.begin(); it != pcb->fd_list.end(); ++ it) { - if ((*it)->idx == fd) { + if (*it == fdesp) { pcb->fd_list.erase(it); free_fdesp(*it); return 0; diff --git a/kernel/fs/pipe.cpp b/kernel/fs/pipe.cpp index a3312f12..fa89f334 100644 --- a/kernel/fs/pipe.cpp +++ b/kernel/fs/pipe.cpp @@ -2,8 +2,74 @@ #include <stddef.h> #include <fmt.hpp> #include <fs.h> +#include <fs/pipe.h> +#include <mem.hpp> +#include <string.h> +#include <list.h> namespace PIPE { +static list::list<pipe_t *> pipe_list; +static SimpleAllocator<pipe_t> pipe_allocator; +static int npipe = 0; + +int open(fdesp_t *fdesp[2]) { + pipe_t *pipe = pipe_allocator.create(); + if (!pipe) return -1; + pipe->idx = npipe++; + pipe->n[0] = 0; + pipe->n[1] = 0; + pipe->closed[0] = false; + pipe->closed[1] = false; + pipe->fd[0] = fdesp[0]->idx; + pipe->fd[1] = fdesp[1]->idx; + memset(pipe->data, 0, PIPE_SIZE); + pipe_list.push_back(pipe); + + // fdesp[0] as read end + fdesp[0]->flags = O_RDONLY; + fdesp[0]->offset = 0; + fdesp[0]->stat = { + .st_ino = 0, + .st_mode = S_IFIFO | S_IRWXU | S_IRWXG | S_IRWXO, + .st_nlink = 1, + .st_uid = 0, + .st_gid = 0, + .st_rdev = 0, + .st_size = PIPE_SIZE, + .st_blksize = PIPE_SIZE, + .st_blocks = 1, + .st_atime_sec = 0, + .st_atime_nsec = 0, + .st_mtime_sec = 0, + .st_mtime_nsec = 0, + .st_ctime_sec = 0, + }; + fdesp[0]->stat.st_dev = pipe->idx; // use pipe->idx as device number + + // fdesp[1] as write end + fdesp[1]->flags = O_WRONLY; + fdesp[1]->offset = 0; + fdesp[1]->stat = { + .st_ino = 0, + .st_mode = S_IFIFO | S_IRWXU | S_IRWXG | S_IRWXO, + .st_nlink = 1, + .st_uid = 0, + .st_gid = 0, + .st_rdev = 0, + .st_size = PIPE_SIZE, + .st_blksize = PIPE_SIZE, + .st_blocks = 1, + .st_atime_sec = 0, + .st_atime_nsec = 0, + .st_mtime_sec = 0, + .st_mtime_nsec = 0, + .st_ctime_sec = 0, + }; + fdesp[1]->stat.st_dev = pipe->idx; // use pipe->idx as device number + + return 0; +} + ssize_t read(fdesp_t *fdesp, void *buf, size_t len) { fmt::err("pipe: read not implemented\n"); return -1; @@ -13,4 +79,19 @@ ssize_t write(fdesp_t *fdesp, const void *buf, size_t len) { fmt::err("pipe: write not implemented\n"); return -1; } + +int close(fdesp_t *fdesp) { + int side = fdesp->flags & O_WRONLY ? 1 : 0; + for (auto it = pipe_list.begin(); it != pipe_list.end(); ++it) { + if ((uint64_t) (*it)->idx == fdesp->stat.st_dev) { + (*it)->closed[side] = true; + if ((*it)->closed[0] && (*it)->closed[1]) { + pipe_allocator.destroy(*it); + pipe_list.erase(it); + } + return 0; + } + } + return -1; +} } // namespace PIPE diff --git a/kernel/include/fs.h b/kernel/include/fs.h index db944fb9..ba878efe 100644 --- a/kernel/include/fs.h +++ b/kernel/include/fs.h @@ -28,6 +28,7 @@ typedef VFS::fdesp_t fdesp_t; typedef VFS::kstat_t kstat_t; void init_fs(); +int fs_pipe2(int fd[2], int flags); int fs_dup(int fd); int fs_dup3(int oldfd, int newfd, int flags); int fs_chdir(const char *path); diff --git a/kernel/include/fs/local.h b/kernel/include/fs/local.h index dd4c270f..b6cf7f54 100644 --- a/kernel/include/fs/local.h +++ b/kernel/include/fs/local.h @@ -4,6 +4,7 @@ #include <sched.h> fdesp_t *alloc_fdesp(); +int alloc2_fdesp(fdesp_t *fdesp[2]); void free_fdesp(fdesp_t *fd); fdesp_t *get_fdesp(int fd, pcb_t *pcb); diff --git a/kernel/include/fs/pipe.h b/kernel/include/fs/pipe.h index 39e8aa8f..33a73937 100644 --- a/kernel/include/fs/pipe.h +++ b/kernel/include/fs/pipe.h @@ -3,9 +3,22 @@ #include <stddef.h> +#define PIPE_SIZE 512 + namespace PIPE { +struct pipe_t { + int idx; + size_t n[2]; + bool closed[2]; + int fd[2]; + char data[PIPE_SIZE]; +}; + +int open(fdesp_t *fdesp[2]); ssize_t read(fdesp_t *fdesp, void *buf, size_t len); ssize_t write(fdesp_t *fdesp, const void *buf, size_t len); +int close(fdesp_t *fdesp); + } // namespace PIPE #endif diff --git a/kernel/syscall/syscall.cpp b/kernel/syscall/syscall.cpp index dd86e649..dd070dc6 100644 --- a/kernel/syscall/syscall.cpp +++ b/kernel/syscall/syscall.cpp @@ -316,8 +316,7 @@ static void sys_vhangup(Context *c) { } static void sys_pipe2(Context *c) { - fmt::err("unimplemented syscall pipe2\n"); - exit(1); + a0 = fs_pipe2((int *) a0, a1); } static void sys_quotactl(Context *c) { -- GitLab