فهرست منبع

feat(gblibc): add fstat()

greatbridf 2 سال پیش
والد
کامیت
db73e41887

+ 1 - 0
gblibc/CMakeLists.txt

@@ -16,6 +16,7 @@ add_library(gblibc STATIC
     src/init.c
     src/internal.c
     src/alloca.c
+    src/stat.c
 )
 
 add_library(crt0 OBJECT

+ 22 - 0
gblibc/include/bits/alltypes.h

@@ -0,0 +1,22 @@
+#ifndef __GBLIBC_BITS_ALLTYPES_H_
+#define __GBLIBC_BITS_ALLTYPES_H_
+
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef size_t blksize_t;
+typedef size_t blkcnt_t;
+
+struct timespec {
+    time_t tv_sec;
+    long tv_nsec;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 34 - 0
gblibc/include/sys/stat.h

@@ -0,0 +1,34 @@
+#ifndef __GBLIBC_SYS_STAT_H
+#define __GBLIBC_SYS_STAT_H
+
+#include <bits/alltypes.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct stat {
+    dev_t st_dev;
+    ino_t st_ino;
+    uint16_t st_mode;
+    uint16_t st_nlink;
+    uint16_t st_uid;
+    uint16_t st_gid;
+    dev_t st_rdev;
+    off_t st_size;
+    blksize_t st_blksize;
+    blkcnt_t st_blocks;
+
+    struct timespec st_atim;
+    struct timespec st_mtim;
+    struct timespec st_ctim;
+};
+
+int fstat(int fd, struct stat* statbuf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 3 - 0
gblibc/include/sys/types.h

@@ -10,6 +10,9 @@ extern "C" {
 typedef int pid_t;
 typedef uint32_t ino_t;
 typedef int32_t off_t;
+typedef uint32_t dev_t;
+
+#define INVALID_DEVICE (~(dev_t)0)
 
 #ifdef __cplusplus
 }

+ 16 - 0
gblibc/include/time.h

@@ -0,0 +1,16 @@
+#ifndef __GBLIBC_TIME_H
+#define __GBLIBC_TIME_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef size_t time_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 1 - 0
gblibc/private-include/syscall.h

@@ -7,6 +7,7 @@
 #define SYS_write (1)
 #define SYS_open (2)
 #define SYS_close (3)
+#define SYS_fstat (5)
 #define SYS_brk (12)
 #define SYS_ioctl (16)
 #define SYS_pipe (22)

+ 13 - 0
gblibc/src/stat.c

@@ -0,0 +1,13 @@
+#include <errno.h>
+#include <syscall.h>
+#include <sys/stat.h>
+
+int fstat(int fd, struct stat* statbuf)
+{
+    int ret = syscall2(SYS_fstat, fd, (uint32_t)statbuf);
+    if (ret < 0) {
+        errno = -ret;
+        return -1;
+    }
+    return ret;
+}

+ 1 - 1
include/fs/fat.hpp

@@ -167,7 +167,7 @@ public:
     ~fat32();
 
     virtual size_t inode_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n) override;
-    virtual int inode_stat(dentry* ent, stat* st) override;
+    virtual int inode_stat(inode* ind, user_stat* st) override;
     virtual int inode_readdir(fs::inode* dir, size_t offset, fs::vfs::filldir_func callback) override;
 };
 

+ 45 - 23
include/kernel/vfs.hpp

@@ -3,6 +3,7 @@
 #include <assert.h>
 #include <kernel/event/evtqueue.hpp>
 #include <stdint.h>
+#include <sys/types.h>
 #include <types/allocator.hpp>
 #include <types/buffer.hpp>
 #include <types/cplusplus.hpp>
@@ -57,15 +58,6 @@ struct inode {
     size_t size;
 };
 
-#define SN_INVALID (0xffffffff)
-union node_t {
-    uint32_t v;
-    struct {
-        uint32_t major : 16;
-        uint32_t minor : 16;
-    } in;
-};
-
 struct special_node;
 
 typedef size_t (*special_node_read)(special_node* sn, char* buf, size_t buf_size, size_t offset, size_t n);
@@ -82,14 +74,6 @@ struct special_node {
     uint32_t data2;
 };
 
-struct stat {
-    ino_t st_ino;
-    node_t st_rdev;
-    size_t st_size;
-    blksize_t st_blksize;
-    blkcnt_t st_blocks;
-};
-
 struct PACKED user_dirent {
     ino_t d_ino; // inode number
     uint32_t d_off; // ignored
@@ -98,6 +82,44 @@ struct PACKED user_dirent {
     // uint8_t d_type; // file type, with offset of (d_reclen - 1)
 };
 
+struct user_timespec {
+    time_t tv_sec;
+    long tv_nsec;
+};
+
+struct user_stat {
+    dev_t st_dev;
+    ino_t st_ino;
+    int32_t st_mode;
+    size_t st_nlink;
+    int32_t st_uid;
+    int32_t st_gid;
+    dev_t st_rdev;
+    off_t st_size;
+    blksize_t st_blksize;
+    blkcnt_t st_blocks;
+
+    user_timespec st_atim;
+    user_timespec st_mtim;
+    user_timespec st_ctim;
+};
+
+constexpr unsigned int major(dev_t dev)
+{
+    return dev >> (sizeof(dev_t) * 8 / 2);
+}
+
+constexpr unsigned int minor(dev_t dev)
+{
+    return dev & ((1 << (sizeof(dev_t) * 8 / 2)) - 1);
+}
+
+constexpr dev_t makedev(unsigned int major, unsigned int minor)
+{
+    return (major << (sizeof(dev_t) * 8 / 2))
+        | (minor & ((1 << (sizeof(dev_t) * 8 / 2)) - 1));
+}
+
 class vfs {
 public:
     struct dentry {
@@ -181,11 +203,11 @@ public:
     virtual size_t inode_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
     virtual size_t inode_write(inode* file, const char* buf, size_t offset, size_t n);
     virtual int inode_mkfile(dentry* dir, const char* filename);
-    virtual int inode_mknode(dentry* dir, const char* filename, union node_t sn);
+    virtual int inode_mknode(dentry* dir, const char* filename, dev_t dev);
     virtual int inode_rmfile(dentry* dir, const char* filename);
     virtual int inode_mkdir(dentry* dir, const char* dirname);
-    virtual int inode_stat(dentry* dir, stat* stat);
-    virtual node_t inode_getnode(inode* file);
+    virtual int inode_stat(inode* ind, user_stat* stat);
+    virtual dev_t inode_devid(inode* file);
 
     // parameter 'length' in callback:
     // if 0, 'name' should be null terminated
@@ -267,11 +289,11 @@ vfs* register_fs(vfs* fs);
 size_t vfs_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
 size_t vfs_write(inode* file, const char* buf, size_t offset, size_t n);
 int vfs_mkfile(fs::vfs::dentry* dir, const char* filename);
-int vfs_mknode(fs::vfs::dentry* dir, const char* filename, node_t sn);
+int vfs_mknode(fs::vfs::dentry* dir, const char* filename, dev_t dev);
 int vfs_rmfile(fs::vfs::dentry* dir, const char* filename);
 int vfs_mkdir(fs::vfs::dentry* dir, const char* dirname);
-int vfs_stat(const char* filename, stat* stat);
-int vfs_stat(fs::vfs::dentry* ent, stat* stat);
+int vfs_stat(const char* filename, user_stat* stat);
+int vfs_stat(fs::vfs::dentry* ent, user_stat* stat);
 
 // @return pointer to the dentry if found, nullptr if not
 fs::vfs::dentry* vfs_open(const char* path);

+ 8 - 4
src/fs/fat.cpp

@@ -237,12 +237,16 @@ size_t fat32::inode_read(inode* file, char* buf, size_t buf_size, size_t offset,
     return orig_n - n;
 }
 
-int fat32::inode_stat(dentry* ent, stat* st)
+int fat32::inode_stat(inode* ind, user_stat* st)
 {
-    st->st_size = ent->ind->size;
+    memset(st, 0x00, sizeof(user_stat));
+    st->st_mode = ind->perm;
+    st->st_dev = device->fs->inode_devid(device);
+    st->st_nlink = ind->flags.in.directory ? 2 : 1;
+    st->st_size = ind->size;
     st->st_blksize = 4096;
-    st->st_blocks = (ent->ind->size + 4095) / 4096;
-    st->st_ino = ent->ind->ino;
+    st->st_blocks = (ind->size + 511) / 512;
+    st->st_ino = ind->ino;
     return GB_OK;
 }
 } // namespace fs::fat

+ 1 - 1
src/kernel/hw/ata.cpp

@@ -195,7 +195,7 @@ static inline void mbr_part_probe(fs::inode* drive, uint16_t major, uint16_t min
             nullptr,
             part.lba_start, part.cnt);
 
-        fs::vfs_mknode(dev, "hda1", { .in { .major = 2, .minor = 1 } });
+        fs::vfs_mknode(dev, "hda1", fs::makedev(2, 1));
     }
 }
 

+ 19 - 2
src/kernel/syscall.cpp

@@ -398,8 +398,8 @@ constexpr bool is_tty(fs::file* file)
     if (!ind->flags.in.special_node)
         return false;
 
-    fs::node_t nd = ind->fs->inode_getnode(ind);
-    if (nd.in.major != 1 || nd.in.minor != 0)
+    dev_t dev = ind->fs->inode_devid(ind);
+    if (fs::major(dev) != 1 || fs::minor(dev) != 0)
         return false;
 
     return true;
@@ -480,6 +480,22 @@ int _syscall_brk(interrupt_stack* data)
     return (int)brk;
 }
 
+int _syscall_fstat(interrupt_stack* data)
+{
+    int fd = data->s_regs.edi;
+    auto* buf = (fs::user_stat*)data->s_regs.esi;
+
+    auto* file = current_process->files[fd];
+    if (!file || file->type != fs::file::types::ind)
+        return -EBADF;
+
+    auto* inode = file->ptr.ind;
+    // TODO: use copy_to_user
+    assert(inode->fs->inode_stat(inode, buf) == GB_OK);
+
+    return 0;
+}
+
 extern "C" void syscall_entry(interrupt_stack* data)
 {
     int syscall_no = data->s_regs.eax;
@@ -502,6 +518,7 @@ void init_syscall(void)
     syscall_handlers[1] = _syscall_write;
     syscall_handlers[2] = _syscall_open;
     syscall_handlers[3] = _syscall_close;
+    syscall_handlers[5] = _syscall_fstat;
     syscall_handlers[12] = _syscall_brk;
     syscall_handlers[16] = _syscall_ioctl;
     syscall_handlers[22] = _syscall_pipe;

+ 41 - 33
src/kernel/vfs.cpp

@@ -197,7 +197,7 @@ int fs::vfs::inode_mkfile(dentry*, const char*)
     assert(false);
     return GB_FAILED;
 }
-int fs::vfs::inode_mknode(dentry*, const char*, node_t)
+int fs::vfs::inode_mknode(dentry*, const char*, dev_t)
 {
     assert(false);
     return GB_FAILED;
@@ -212,15 +212,15 @@ int fs::vfs::inode_mkdir(dentry*, const char*)
     assert(false);
     return GB_FAILED;
 }
-int fs::vfs::inode_stat(dentry*, stat*)
+int fs::vfs::inode_stat(fs::inode*, user_stat*)
 {
     assert(false);
     return GB_FAILED;
 }
-fs::node_t fs::vfs::inode_getnode(fs::inode*)
+dev_t fs::vfs::inode_devid(fs::inode*)
 {
     assert(false);
-    return { SN_INVALID };
+    return INVALID_DEVICE;
 }
 
 class tmpfs : public virtual fs::vfs {
@@ -337,9 +337,9 @@ public:
         return GB_OK;
     }
 
-    virtual int inode_mknode(dentry* dir, const char* filename, fs::node_t sn) override
+    virtual int inode_mknode(dentry* dir, const char* filename, dev_t dev) override
     {
-        auto& node = *cache_inode({ .v = INODE_NODE }, 0777, 0, _savedata(sn.v));
+        auto& node = *cache_inode({ .v = INODE_NODE }, 0777, 0, _savedata(dev));
         mklink(dir->ind, &node, filename);
         dir->append(get_inode(node.ino), filename, true);
         return GB_OK;
@@ -392,34 +392,40 @@ public:
         return n;
     }
 
-    virtual int inode_stat(dentry* dir, fs::stat* stat) override
+    virtual int inode_stat(fs::inode* file_inode, fs::user_stat* stat) override
     {
-        auto* file_inode = dir->ind;
-
+        // TODO: fill in these fields with REAL DATA
+        stat->st_dev = 0;
         stat->st_ino = file_inode->ino;
+        stat->st_mode = file_inode->perm;
+        stat->st_uid = 0;
+        stat->st_gid = 0;
         stat->st_size = file_inode->size;
+        stat->st_blocks = file_inode->size / 512;
+        stat->st_atim = {};
+        stat->st_ctim = {};
+        stat->st_mtim = {};
         if (file_inode->flags.in.file) {
-            stat->st_rdev.v = 0;
-            stat->st_blksize = 1;
-            stat->st_blocks = file_inode->size;
+            stat->st_nlink = 1;
+            stat->st_rdev = 0;
+            stat->st_blksize = 512;
         }
         if (file_inode->flags.in.directory) {
-            stat->st_rdev.v = 0;
+            stat->st_nlink = 2;
+            stat->st_rdev = 0;
             stat->st_blksize = sizeof(fe_t);
-            stat->st_blocks = file_inode->size;
         }
         if (file_inode->flags.in.special_node) {
-            stat->st_rdev.v = as_val(_getdata(file_inode->ino));
+            stat->st_rdev = as_val(_getdata(file_inode->ino));
             stat->st_blksize = 0;
-            stat->st_blocks = 0;
         }
 
         return GB_OK;
     }
 
-    virtual fs::node_t inode_getnode(fs::inode* file) override
+    virtual dev_t inode_devid(fs::inode* file) override
     {
-        return { as_val(_getdata(file->ino)) };
+        return as_val(_getdata(file->ino));
     }
 };
 
@@ -429,12 +435,12 @@ static fs::special_node sns[8][8];
 size_t fs::vfs_read(fs::inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
 {
     if (file->flags.in.special_node) {
-        fs::node_t sn = file->fs->inode_getnode(file);
-        if (sn.v == SN_INVALID) {
+        dev_t dev = file->fs->inode_devid(file);
+        if (dev == INVALID_DEVICE) {
             errno = EINVAL;
             return 0xffffffff;
         }
-        auto* ptr = &sns[sn.in.major][sn.in.minor];
+        auto* ptr = &sns[major(dev)][minor(dev)];
         auto* ops = &ptr->ops;
         if (ops && ops->read)
             return ops->read(ptr, buf, buf_size, offset, n);
@@ -449,12 +455,12 @@ size_t fs::vfs_read(fs::inode* file, char* buf, size_t buf_size, size_t offset,
 size_t fs::vfs_write(fs::inode* file, const char* buf, size_t offset, size_t n)
 {
     if (file->flags.in.special_node) {
-        fs::node_t sn = file->fs->inode_getnode(file);
-        if (sn.v == SN_INVALID) {
+        dev_t dev = file->fs->inode_devid(file);
+        if (dev == INVALID_DEVICE) {
             errno = EINVAL;
             return 0xffffffff;
         }
-        auto* ptr = &sns[sn.in.major][sn.in.minor];
+        auto* ptr = &sns[major(dev)][minor(dev)];
         auto* ops = &ptr->ops;
         if (ops && ops->write)
             return ops->write(ptr, buf, offset, n);
@@ -470,9 +476,9 @@ int fs::vfs_mkfile(fs::vfs::dentry* dir, const char* filename)
 {
     return dir->ind->fs->inode_mkfile(dir, filename);
 }
-int fs::vfs_mknode(fs::vfs::dentry* dir, const char* filename, fs::node_t sn)
+int fs::vfs_mknode(fs::vfs::dentry* dir, const char* filename, dev_t dev)
 {
-    return dir->ind->fs->inode_mknode(dir, filename, sn);
+    return dir->ind->fs->inode_mknode(dir, filename, dev);
 }
 int fs::vfs_rmfile(fs::vfs::dentry* dir, const char* filename)
 {
@@ -532,16 +538,16 @@ fs::vfs::dentry* fs::vfs_open(const char* path)
     }
     return nullptr;
 }
-int fs::vfs_stat(const char* filename, stat* stat)
+int fs::vfs_stat(const char* filename, user_stat* stat)
 {
     auto ent = vfs_open(filename);
     if (!ent)
         return GB_FAILED;
     return vfs_stat(ent, stat);
 }
-int fs::vfs_stat(fs::vfs::dentry* ent, stat* stat)
+int fs::vfs_stat(fs::vfs::dentry* ent, user_stat* stat)
 {
-    return ent->ind->fs->inode_stat(ent, stat);
+    return ent->ind->fs->inode_stat(ent->ind, stat);
 }
 fs::vfs::dentry* fs::vfs_open_proc(const char* path)
 {
@@ -718,11 +724,12 @@ void init_vfs(void)
     vfs_write(init->ind, str, 0, strlen(str));
 
     auto* dev = vfs_open("/dev");
-    vfs_mknode(dev, "null", { .in { .major = 0, .minor = 0 } });
-    vfs_mknode(dev, "console", { .in { .major = 1, .minor = 0 } });
-    vfs_mknode(dev, "hda", { .in { .major = 2, .minor = 0 } });
+    vfs_mknode(dev, "null", makedev(0, 0));
+    vfs_mknode(dev, "console", makedev(1, 0));
+    vfs_mknode(dev, "hda", makedev(2, 0));
 
-    stat _stat {};
+#ifndef NDEBUG
+    user_stat _stat {};
 
     vfs_stat("/init", &_stat);
     vfs_stat("/", &_stat);
@@ -730,4 +737,5 @@ void init_vfs(void)
     vfs_stat("/dev/null", &_stat);
     vfs_stat("/dev/console", &_stat);
     vfs_stat("/dev/hda", &_stat);
+#endif
 }