diff --git a/kernel/include/kernel/fs.h b/kernel/include/kernel/fs.h index 8145687..74ac690 100644 --- a/kernel/include/kernel/fs.h +++ b/kernel/include/kernel/fs.h @@ -45,7 +45,8 @@ typedef struct fs_t { /* TODO: require null termination of entries */ sos_directory_entry_t* (*readdir)(struct fs_t*, uint32_t, uint32_t); inode_t* (*get_fs_inode)(struct fs_t*, uint32_t); - int32_t (*close)(fs_t*, uint32_t) + int32_t (*close)(fs_t*, uint32_t); + int32_t (*stat)(fs_t*, uint32_t, stat_t*); } fs_t; typedef inode_t* (*fs_get_fs_inode_t)(struct fs_t*, uint32_t); @@ -56,6 +57,7 @@ typedef int32_t (*fs_unlink_t)(struct fs_t*, uint32_t, uint32_t); typedef int32_t (*fs_rename_t)(struct fs_t*, uint32_t, uint32_t, uint32_t); typedef uint32_t (*fs_create_t)(struct fs_t*, const char*, uint32_t, uint32_t); typedef int32_t (*fs_close_t)(struct fs_t*, uint32_t); +typedef int32_t (*fs_stat_t)(struct fs_t*, uint32_t, stat_t*); void init_fs(fs_t* fs); void fs_mount(const char* mount_point, fs_t* fs); @@ -67,4 +69,5 @@ int32_t fs_rename(const char* oldp, const char* newp); int32_t fs_close(inode_t* in); uint32_t fs_read(inode_t* in, uint32_t offset, uint8_t* buf, uint32_t size); uint32_t fs_write(inode_t* in, uint8_t* buf, uint32_t size); -uint32_t fs_readdir(inode_t* in, uint32_t offset, sos_directory_entry_t* d_ent, uint32_t size); \ No newline at end of file +uint32_t fs_readdir(inode_t* in, uint32_t offset, sos_directory_entry_t* d_ent, uint32_t size); +int32_t fs_stat(const char* path, stat_t* buf); \ No newline at end of file diff --git a/kernel/include/kernel/uapi/uapi_fs.h b/kernel/include/kernel/uapi/uapi_fs.h index f6b1024..c7b12bb 100644 --- a/kernel/include/kernel/uapi/uapi_fs.h +++ b/kernel/include/kernel/uapi/uapi_fs.h @@ -30,4 +30,12 @@ typedef struct { uint8_t name_len_low; uint8_t type; char name[]; -} sos_directory_entry_t; \ No newline at end of file +} sos_directory_entry_t; + +typedef struct stat_t { + uint32_t st_dev; + uint32_t st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_size; +} stat_t; \ No newline at end of file diff --git a/kernel/include/kernel/uapi/uapi_syscall.h b/kernel/include/kernel/uapi/uapi_syscall.h index 07a3499..df9b42e 100644 --- a/kernel/include/kernel/uapi/uapi_syscall.h +++ b/kernel/include/kernel/uapi/uapi_syscall.h @@ -25,7 +25,8 @@ #define SYS_UNLINK 19 #define SYS_RENAME 20 #define SYS_MAKETTY 21 -#define SYS_MAX 22 // First invalid syscall number +#define SYS_STAT 22 +#define SYS_MAX 23 // First invalid syscall number #define SYS_INFO_UPTIME 1 #define SYS_INFO_MEMORY 2 diff --git a/kernel/src/misc/ext2.c b/kernel/src/misc/ext2.c index dbb8e73..4d06102 100644 --- a/kernel/src/misc/ext2.c +++ b/kernel/src/misc/ext2.c @@ -161,7 +161,8 @@ uint32_t ext2_read(ext2_fs_t* fs, uint32_t inode, uint32_t offset, uint8_t* buf, uint32_t ext2_append(ext2_fs_t* fs, uint32_t inode, uint8_t* data, uint32_t size); sos_directory_entry_t* ext2_readdir(ext2_fs_t* fs, uint32_t inode, uint32_t offset); inode_t* ext2_get_fs_inode(ext2_fs_t* fs, uint32_t inode); -int32_t ext2_close(fs_t* fs, uint32_t ino); +int32_t ext2_close(ext2_fs_t* fs, uint32_t ino); +int32_t ext2_stat(ext2_fs_t* fs, uint32_t ino, stat_t* stat); static void read_block(ext2_fs_t* fs, uint32_t block, uint8_t* buf); static void write_block(ext2_fs_t* fs, uint32_t block, uint8_t* buf); @@ -212,6 +213,7 @@ fs_t* init_ext2(uint8_t* data, uint32_t len) { e2fs->fs.readdir = (fs_readdir_t) ext2_readdir; e2fs->fs.unlink = (fs_unlink_t) ext2_unlink; e2fs->fs.close = (fs_close_t) ext2_close; + e2fs->fs.stat = (fs_stat_t) ext2_stat; e2fs->fs.uid = e2fs->sb->id[0]; e2fs->fs.root = (folder_inode_t*) ext2_get_fs_inode(e2fs, EXT2_ROOT_INODE); @@ -463,13 +465,29 @@ inode_t* ext2_get_fs_inode(ext2_fs_t* fs, uint32_t inode) { return fs_in; } -int32_t ext2_close(fs_t* fs, uint32_t ino) { +int32_t ext2_close(ext2_fs_t* fs, uint32_t ino) { UNUSED(fs); UNUSED(ino); return 0; } +int32_t ext2_stat(ext2_fs_t* fs, uint32_t ino, stat_t* stat) { + ext2_inode_t* in = get_inode(fs, ino); + + if (!in) { + return -1; + } + + stat->st_dev = fs->fs.uid; + stat->st_ino = ino; + stat->st_mode = in->type_perms; + stat->st_nlink = in->hardlinks_count; + stat->st_size = in->size_lower; + + return 0; +} + /* Utility functions */ /* Reads the content of the given block. diff --git a/kernel/src/misc/fs.c b/kernel/src/misc/fs.c index e5ce2b2..edd9986 100644 --- a/kernel/src/misc/fs.c +++ b/kernel/src/misc/fs.c @@ -333,6 +333,17 @@ int32_t fs_rename(const char* oldp, const char* newp) { return 0; } +int32_t fs_stat(const char* path, stat_t* buf) { + printk("stat: %s", path); + inode_t* in = fs_open(path, O_RDONLY); + + if (!in) { + return -1; + } + + return FS(in)->stat(FS(in), in->inode_no, buf); +} + /* A process has released its grip on a file: notify the fs. */ int32_t fs_close(inode_t* in) { diff --git a/kernel/src/sys/syscall.c b/kernel/src/sys/syscall.c index 8c47112..0c8dfc9 100644 --- a/kernel/src/sys/syscall.c +++ b/kernel/src/sys/syscall.c @@ -38,6 +38,7 @@ static void syscall_getcwd(registers_t* regs); static void syscall_unlink(registers_t* regs); static void syscall_rename(registers_t* regs); static void syscall_maketty(registers_t* regs); +static void syscall_stat(registers_t* regs); handler_t syscall_handlers[SYSCALL_NUM] = { 0 }; @@ -65,6 +66,7 @@ void init_syscall() { syscall_handlers[SYS_UNLINK] = syscall_unlink; syscall_handlers[SYS_RENAME] = syscall_rename; syscall_handlers[SYS_MAKETTY] = syscall_maketty; + syscall_handlers[SYS_STAT] = syscall_stat; } static void syscall_handler(registers_t* regs) { @@ -275,4 +277,11 @@ static void syscall_maketty(registers_t* regs) { proc_add_fd(entry); regs->eax = 0; +} + +static void syscall_stat(registers_t* regs) { + const char* path = (const char*) regs->ebx; + stat_t* buf = (stat_t*) regs->ecx; + + regs->eax = fs_stat(path, buf); } \ No newline at end of file diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h index ddff6ce..cd5c0c1 100644 --- a/libc/include/sys/stat.h +++ b/libc/include/sys/stat.h @@ -4,6 +4,15 @@ typedef uint32_t mode_t; +struct stat { + uint32_t st_dev; + uint32_t st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_size; +}; + #ifndef _KERNEL_ int mkdir(const char* pathname, mode_t mode); +int stat(const char* path, struct stat* buf); #endif \ No newline at end of file diff --git a/libc/include/unistd.h b/libc/include/unistd.h index cb9760b..ba54b4a 100644 --- a/libc/include/unistd.h +++ b/libc/include/unistd.h @@ -1,8 +1,9 @@ #pragma once -#include #include +#include + #define STDOUT_FILENO FS_STDOUT_FILENO #ifndef _KERNEL_ diff --git a/libc/src/unix/stat.c b/libc/src/unix/stat.c index e66f08e..bf74b65 100644 --- a/libc/src/unix/stat.c +++ b/libc/src/unix/stat.c @@ -31,4 +31,21 @@ int unlink(const char* path) { return syscall1(SYS_UNLINK, (uintptr_t) path); } +int stat(const char* path, struct stat* buf) { + stat_t statbuf; + int ret = syscall2(SYS_STAT, (uintptr_t) path, (uintptr_t) &statbuf); + + if (ret) { + return ret; + } + + buf->st_dev = statbuf.st_dev; + buf->st_ino = statbuf.st_ino; + buf->st_mode = statbuf.st_mode; + buf->st_nlink = statbuf.st_nlink; + buf->st_size = statbuf.st_size; + + return 0; +} + #endif \ No newline at end of file