From: Tulio A M Mendes Date: Sat, 7 Feb 2026 22:13:42 +0000 (-0300) Subject: fs: add lseek/stat/fstat and minimal errno X-Git-Url: https://projects.tadryanom.me/sitemap.xml?a=commitdiff_plain;h=147b75759c7f1a498acf4cbe53646d2e2cd42fb7;p=AdrOS.git fs: add lseek/stat/fstat and minimal errno --- diff --git a/include/errno.h b/include/errno.h new file mode 100644 index 0000000..ead6079 --- /dev/null +++ b/include/errno.h @@ -0,0 +1,12 @@ +#ifndef ERRNO_H +#define ERRNO_H + +#define EPERM 1 +#define ENOENT 2 +#define EIO 5 +#define EBADF 9 +#define EFAULT 14 +#define EINVAL 22 +#define ESPIPE 29 + +#endif diff --git a/include/stat.h b/include/stat.h new file mode 100644 index 0000000..710dc91 --- /dev/null +++ b/include/stat.h @@ -0,0 +1,18 @@ +#ifndef STAT_H +#define STAT_H + +#include + +#define S_IFMT 0170000 +#define S_IFREG 0100000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 + +struct stat { + uint32_t st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_size; +}; + +#endif diff --git a/include/syscall.h b/include/syscall.h index d05ae3e..b716ac1 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -18,6 +18,10 @@ enum { // Temporary: spawn a kernel-thread child for waitpid testing. SYSCALL_SPAWN = 8, + + SYSCALL_LSEEK = 9, + SYSCALL_FSTAT = 10, + SYSCALL_STAT = 11, }; #endif diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 2e34c8b..ae219dc 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -7,6 +7,9 @@ #include "uart_console.h" #include "uaccess.h" +#include "errno.h" +#include "stat.h" + #include "hal/cpu.h" #include @@ -17,6 +20,21 @@ struct file { uint32_t flags; }; +static int stat_from_node(const fs_node_t* node, struct stat* st) { + if (!node || !st) return -EFAULT; + + st->st_ino = node->inode; + st->st_nlink = 1; + st->st_size = node->length; + + uint32_t mode = 0; + if (node->flags == FS_DIRECTORY) mode |= S_IFDIR; + else if (node->flags == FS_CHARDEVICE) mode |= S_IFCHR; + else mode |= S_IFREG; + st->st_mode = mode; + return 0; +} + static int fd_alloc(struct file* f) { if (!current_process || !f) return -1; @@ -46,6 +64,72 @@ static int fd_close(int fd) { return 0; } +static int syscall_stat_impl(const char* user_path, struct stat* user_st) { + if (!user_path || !user_st) return -EFAULT; + if (user_range_ok(user_st, sizeof(*user_st)) == 0) return -EFAULT; + + char path[128]; + for (size_t i = 0; i < sizeof(path); i++) { + if (copy_from_user(&path[i], &user_path[i], 1) < 0) { + return -EFAULT; + } + if (path[i] == 0) break; + if (i + 1 == sizeof(path)) { + path[sizeof(path) - 1] = 0; + break; + } + } + + fs_node_t* node = vfs_lookup(path); + if (!node) return -ENOENT; + + struct stat st; + int rc = stat_from_node(node, &st); + if (rc < 0) return rc; + if (copy_to_user(user_st, &st, sizeof(st)) < 0) return -EFAULT; + return 0; +} + +static int syscall_fstat_impl(int fd, struct stat* user_st) { + if (!user_st) return -EFAULT; + if (user_range_ok(user_st, sizeof(*user_st)) == 0) return -EFAULT; + + struct file* f = fd_get(fd); + if (!f || !f->node) return -EBADF; + + struct stat st; + int rc = stat_from_node(f->node, &st); + if (rc < 0) return rc; + if (copy_to_user(user_st, &st, sizeof(st)) < 0) return -EFAULT; + return 0; +} + +static int syscall_lseek_impl(int fd, int32_t offset, int whence) { + if (fd == 0 || fd == 1 || fd == 2) return -ESPIPE; + + struct file* f = fd_get(fd); + if (!f || !f->node) return -EBADF; + if (f->node->flags != FS_FILE) return -ESPIPE; + + int64_t base = 0; + if (whence == 0) { + base = 0; + } else if (whence == 1) { + base = (int64_t)f->offset; + } else if (whence == 2) { + base = (int64_t)f->node->length; + } else { + return -EINVAL; + } + + int64_t noff = base + (int64_t)offset; + if (noff < 0) return -EINVAL; + if (noff > (int64_t)f->node->length) return -EINVAL; + + f->offset = (uint32_t)noff; + return (int)f->offset; +} + static int syscall_open_impl(const char* user_path, uint32_t flags) { (void)flags; if (!user_path) return -1; @@ -64,7 +148,7 @@ static int syscall_open_impl(const char* user_path, uint32_t flags) { fs_node_t* node = vfs_lookup(path); if (!node) return -1; - if ((node->flags & FS_FILE) == 0) return -1; + if (node->flags != FS_FILE) return -1; struct file* f = (struct file*)kmalloc(sizeof(*f)); if (!f) return -1; @@ -211,6 +295,28 @@ static void syscall_handler(struct registers* regs) { return; } + if (syscall_no == SYSCALL_LSEEK) { + int fd = (int)regs->ebx; + int32_t off = (int32_t)regs->ecx; + int whence = (int)regs->edx; + regs->eax = (uint32_t)syscall_lseek_impl(fd, off, whence); + return; + } + + if (syscall_no == SYSCALL_FSTAT) { + int fd = (int)regs->ebx; + struct stat* st = (struct stat*)regs->ecx; + regs->eax = (uint32_t)syscall_fstat_impl(fd, st); + return; + } + + if (syscall_no == SYSCALL_STAT) { + const char* path = (const char*)regs->ebx; + struct stat* st = (struct stat*)regs->ecx; + regs->eax = (uint32_t)syscall_stat_impl(path, st); + return; + } + regs->eax = (uint32_t)-1; } diff --git a/user/init.c b/user/init.c index 1245dc8..8d1ecd0 100644 --- a/user/init.c +++ b/user/init.c @@ -8,6 +8,25 @@ enum { SYSCALL_CLOSE = 6, SYSCALL_WAITPID = 7, SYSCALL_SPAWN = 8, + SYSCALL_LSEEK = 9, + SYSCALL_FSTAT = 10, + SYSCALL_STAT = 11, +}; + +enum { + SEEK_SET = 0, + SEEK_CUR = 1, + SEEK_END = 2, +}; + +#define S_IFMT 0170000 +#define S_IFREG 0100000 + +struct stat { + uint32_t st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_size; }; static int sys_write(int fd, const void* buf, uint32_t len) { @@ -76,6 +95,39 @@ static int sys_close(int fd) { return ret; } +static int sys_lseek(int fd, int32_t offset, int whence) { + int ret; + __asm__ volatile( + "int $0x80" + : "=a"(ret) + : "a"(SYSCALL_LSEEK), "b"(fd), "c"(offset), "d"(whence) + : "memory" + ); + return ret; +} + +static int sys_fstat(int fd, struct stat* st) { + int ret; + __asm__ volatile( + "int $0x80" + : "=a"(ret) + : "a"(SYSCALL_FSTAT), "b"(fd), "c"(st) + : "memory" + ); + return ret; +} + +static int sys_stat(const char* path, struct stat* st) { + int ret; + __asm__ volatile( + "int $0x80" + : "=a"(ret) + : "a"(SYSCALL_STAT), "b"(path), "c"(st) + : "memory" + ); + return ret; +} + __attribute__((noreturn)) static void sys_exit(int code) { __asm__ volatile( "int $0x80\n" @@ -102,23 +154,73 @@ void _start(void) { static const char path[] = "/bin/init.elf"; int fd = sys_open(path, 0); if (fd < 0) { - static const char emsg[] = "[init] open(/bin/init.elf) failed\n"; - (void)sys_write(1, emsg, (uint32_t)(sizeof(emsg) - 1)); + sys_write(1, "[init] open failed\n", 18); sys_exit(1); } uint8_t hdr[4]; int rd = sys_read(fd, hdr, (uint32_t)sizeof(hdr)); - (void)sys_close(fd); + if (sys_close(fd) < 0) { + sys_write(1, "[init] close failed\n", 19); + sys_exit(1); + } if (rd == 4 && hdr[0] == 0x7F && hdr[1] == 'E' && hdr[2] == 'L' && hdr[3] == 'F') { - static const char ok[] = "[init] open/read/close OK (ELF magic)\n"; - (void)sys_write(1, ok, (uint32_t)(sizeof(ok) - 1)); + sys_write(1, "[init] open/read/close OK (ELF magic)\n", + (uint32_t)(sizeof("[init] open/read/close OK (ELF magic)\n") - 1)); } else { - static const char bad[] = "[init] read failed or bad header\n"; - (void)sys_write(1, bad, (uint32_t)(sizeof(bad) - 1)); + sys_write(1, "[init] read failed or bad header\n", 30); + sys_exit(1); + } + + fd = sys_open("/bin/init.elf", 0); + if (fd < 0) { + sys_write(1, "[init] open2 failed\n", 19); + sys_exit(1); } + struct stat st; + if (sys_fstat(fd, &st) < 0) { + sys_write(1, "[init] fstat failed\n", 19); + sys_exit(1); + } + + if ((st.st_mode & S_IFMT) != S_IFREG || st.st_size == 0) { + sys_write(1, "[init] fstat bad\n", 16); + sys_exit(1); + } + + if (sys_lseek(fd, 0, SEEK_SET) < 0) { + sys_write(1, "[init] lseek set failed\n", 24); + sys_exit(1); + } + + uint8_t m2[4]; + if (sys_read(fd, m2, 4) != 4) { + sys_write(1, "[init] read2 failed\n", 19); + sys_exit(1); + } + if (m2[0] != 0x7F || m2[1] != 'E' || m2[2] != 'L' || m2[3] != 'F') { + sys_write(1, "[init] lseek/read mismatch\n", 27); + sys_exit(1); + } + + if (sys_close(fd) < 0) { + sys_write(1, "[init] close2 failed\n", 20); + sys_exit(1); + } + + if (sys_stat("/bin/init.elf", &st) < 0) { + sys_write(1, "[init] stat failed\n", 18); + sys_exit(1); + } + if ((st.st_mode & S_IFMT) != S_IFREG || st.st_size == 0) { + sys_write(1, "[init] stat bad\n", 15); + sys_exit(1); + } + + sys_write(1, "[init] lseek/stat/fstat OK\n", 27); + enum { NCHILD = 100 }; int children[NCHILD]; for (int i = 0; i < NCHILD; i++) {