浏览代码

feat(vfs): query file stat

greatbridf 2 年之前
父节点
当前提交
4660803811
共有 3 个文件被更改,包括 91 次插入10 次删除
  1. 4 0
      include/kernel/errno.h
  2. 17 1
      include/kernel/vfs.h
  3. 70 9
      src/kernel/vfs.cpp

+ 4 - 0
include/kernel/errno.h

@@ -17,3 +17,7 @@ extern uint32_t* _get_errno(void);
 #define ENOMEM 0
 #define ENOTFOUND 1
 #define EEXIST (1 << 1)
+#define ENOENT (1 << 2)
+#define EINVAL (1 << 3)
+#define EISDIR (1 << 4)
+#define ENOTDIR (1 << 5)

+ 17 - 1
include/kernel/vfs.h

@@ -9,6 +9,7 @@ extern "C" {
 struct inode;
 struct inode_flags;
 struct inode_ops;
+struct stat;
 struct dirent;
 
 typedef size_t (*inode_read)(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
@@ -18,6 +19,11 @@ typedef struct inode* (*inode_findinode)(struct inode* dir, const char* filename
 typedef int (*inode_mkfile)(struct inode* dir, const char* filename);
 typedef int (*inode_rmfile)(struct inode* dir, const char* filename);
 typedef int (*inode_mkdir)(struct inode* dir, const char* dirname);
+typedef int (*inode_stat)(struct inode* dir, struct stat* stat, const char* dirname);
+
+typedef uint32_t ino_t;
+typedef uint32_t blksize_t;
+typedef uint32_t blkcnt_t;
 
 struct inode_flags {
     uint32_t file : 1;
@@ -33,6 +39,7 @@ struct inode_ops {
     inode_mkfile mkfile;
     inode_rmfile rmfile;
     inode_mkdir mkdir;
+    inode_stat stat;
 };
 
 struct fs_info {
@@ -44,10 +51,16 @@ struct inode {
     struct inode_flags flags;
     uint32_t perm;
     void* impl;
-    uint32_t ino;
+    ino_t ino;
     struct fs_info* fs;
 };
 
+struct stat {
+    ino_t st_ino;
+    blksize_t st_blksize;
+    blkcnt_t st_blocks;
+};
+
 struct dirent {
     char name[128];
     uint32_t ino;
@@ -68,6 +81,9 @@ int vfs_mkdir(struct inode* dir, const char* dirname);
 // @return pointer to the inode if found, nullptr if not
 struct inode* vfs_open(const char* path);
 
+// @return GB_OK if succeed, GB_FAILED if failed and set errno
+int vfs_stat(struct stat* stat, const char* path);
+
 #ifdef __cplusplus
 }
 #endif

+ 70 - 9
src/kernel/vfs.cpp

@@ -1,14 +1,17 @@
+#include <kernel/errno.h>
 #include <kernel/mem.h>
 #include <kernel/stdio.h>
 #include <kernel/tty.h>
 #include <kernel/vfs.h>
 #include <types/allocator.hpp>
 #include <types/list.hpp>
+#include <types/string.hpp>
 #include <types/vector.hpp>
 
 using types::allocator_traits;
 using types::kernel_allocator;
 using types::list;
+using types::string;
 using types::vector;
 
 struct tmpfs_file_entry {
@@ -60,6 +63,7 @@ public:
     size_t write(struct inode* file, const char* buf, size_t offset, size_t n);
     int readdir(struct inode* dir, struct dirent* entry, size_t i);
     struct inode* findinode(struct inode* dir, const char* filename);
+    int stat(struct inode* dir, struct stat* stat, const char* filename);
 
     struct inode* root_inode(void)
     {
@@ -105,6 +109,11 @@ int tmpfs_mkdir(struct inode* dir, const char* dirname)
     fs->mkdir(dir, dirname);
     return GB_OK;
 }
+int tmpfs_stat(struct inode* dir, struct stat* stat, const char* filename)
+{
+    auto* fs = static_cast<tmpfs*>(dir->fs->impl);
+    return fs->stat(dir, stat, filename);
+}
 
 static const struct inode_ops tmpfs_inode_ops = {
     .read = tmpfs_read,
@@ -114,6 +123,7 @@ static const struct inode_ops tmpfs_inode_ops = {
     .mkfile = tmpfs_mkfile,
     .rmfile = 0,
     .mkdir = tmpfs_mkdir,
+    .stat = tmpfs_stat,
 };
 
 tmpfs::tmpfs(size_t limit)
@@ -194,13 +204,17 @@ size_t tmpfs::write(struct inode* file, const char* buf, size_t offset, size_t n
 
 int tmpfs::readdir(struct inode* dir, struct dirent* entry, size_t i)
 {
-    if (dir->flags.directory != 1)
+    if (dir->flags.directory != 1) {
+        errno = ENOTDIR;
         return GB_FAILED;
+    }
 
     auto* fes = static_cast<vector<struct tmpfs_file_entry>*>(dir->impl);
 
-    if (i >= fes->size())
+    if (i >= fes->size()) {
+        errno = ENOENT;
         return GB_FAILED;
+    }
 
     entry->ino = fes->at(i).ino;
     snprintf(entry->name, sizeof(entry->name), fes->at(i).filename);
@@ -225,6 +239,25 @@ struct inode* tmpfs::findinode(struct inode* dir, const char* filename)
     return nullptr;
 }
 
+int tmpfs::stat(struct inode* dir, struct stat* stat, const char* filename)
+{
+    // for later use
+    // auto* fes = static_cast<vector<struct tmpfs_file_entry>*>(dir->impl);
+
+    auto* file_inode = vfs_findinode(dir, filename);
+
+    if (!file_inode) {
+        errno = ENOENT;
+        return GB_FAILED;
+    }
+
+    stat->st_blksize = 1;
+    stat->st_blocks = static_cast<vector<char>*>(file_inode->impl)->size();
+    stat->st_ino = file_inode->ino;
+
+    return GB_OK;
+}
+
 size_t vfs_read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
 {
     if (file->fs->ops->read) {
@@ -284,23 +317,24 @@ int vfs_mkdir(struct inode* dir, const char* dirname)
 
 struct inode* vfs_open(const char* path)
 {
+    if (path[0] == '/' && path[1] == 0x00) {
+        return fs_root;
+    }
+
     struct inode* cur = fs_root;
     size_t n = 0;
-    char buf[128] {};
     switch (*(path++)) {
     // absolute path
     case '/':
         while (true) {
             if (path[n] == 0x00) {
-                strncpy(buf, path, n);
-                buf[n] = 0x00;
-                cur = vfs_findinode(cur, buf);
+                string fname(path, n);
+                cur = vfs_findinode(cur, fname.c_str());
                 return cur;
             }
             if (path[n] == '/') {
-                strncpy(buf, path, n);
-                buf[n] = 0x00;
-                cur = vfs_findinode(cur, buf);
+                string fname(path, n);
+                cur = vfs_findinode(cur, fname.c_str());
                 if (path[n + 1] == 0x00) {
                     return cur;
                 } else {
@@ -324,6 +358,30 @@ struct inode* vfs_open(const char* path)
     return nullptr;
 }
 
+int vfs_stat(struct stat* stat, const char* _path)
+{
+    string path(_path);
+    auto iter = path.back();
+    while (*(iter - 1) != '/')
+        --iter;
+    string filename(&*iter);
+    string parent_path = path.substr(0, &*iter - path.data());
+
+    auto* dir_inode = vfs_open(parent_path.c_str());
+
+    if (!dir_inode) {
+        errno = ENOENT;
+        return GB_FAILED;
+    }
+
+    if (dir_inode->fs->ops->stat) {
+        return dir_inode->fs->ops->stat(dir_inode, stat, filename.c_str());
+    } else {
+        errno = EINVAL;
+        return GB_FAILED;
+    }
+}
+
 struct inode* fs_root;
 static tmpfs* rootfs;
 
@@ -339,4 +397,7 @@ void init_vfs(void)
     auto* init = vfs_open("/init");
     const char* str = "#/bin/sh\nexec /bin/sh\n";
     vfs_write(init, str, 0, strlen(str));
+
+    struct stat _stat { };
+    vfs_stat(&_stat, "/init");
 }