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