]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
posix: add openat, fstatat, unlinkat syscalls (AT_FDCWD)
authorTulio A M Mendes <[email protected]>
Tue, 10 Feb 2026 01:50:22 +0000 (22:50 -0300)
committerTulio A M Mendes <[email protected]>
Tue, 10 Feb 2026 01:50:22 +0000 (22:50 -0300)
include/syscall.h
src/kernel/syscall.c
user/init.c

index 62464b0e7b56890d5e614e3e69a620923adab879..28e5e5e386e4cad95d928a54a5f4ff6806566626 100644 (file)
@@ -49,6 +49,10 @@ enum {
     SYSCALL_CHDIR = 32,
     SYSCALL_GETCWD = 33,
     SYSCALL_DUP3 = 35,
+
+    SYSCALL_OPENAT = 36,
+    SYSCALL_FSTATAT = 37,
+    SYSCALL_UNLINKAT = 38,
 };
 
 #endif
index a146fad974c60d6536264e9a6f2576713b019748..a04a6853cbdb4e91f38fb582ab595010c843a1de 100644 (file)
@@ -30,6 +30,10 @@ enum {
     FCNTL_F_SETFL = 4,
 };
 
+enum {
+    AT_FDCWD = -100,
+};
+
 static int path_resolve_user(const char* user_path, char* out, size_t out_sz);
 
 #if defined(__i386__)
@@ -759,6 +763,12 @@ static int syscall_stat_impl(const char* user_path, struct stat* user_st) {
     return 0;
 }
 
+static int syscall_fstatat_impl(int dirfd, const char* user_path, struct stat* user_st, uint32_t flags) {
+    (void)flags;
+    if (dirfd != AT_FDCWD) return -ENOSYS;
+    return syscall_stat_impl(user_path, user_st);
+}
+
 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;
@@ -839,6 +849,12 @@ static int syscall_open_impl(const char* user_path, uint32_t flags) {
     return fd;
 }
 
+static int syscall_openat_impl(int dirfd, const char* user_path, uint32_t flags, uint32_t mode) {
+    (void)mode;
+    if (dirfd != AT_FDCWD) return -ENOSYS;
+    return syscall_open_impl(user_path, flags);
+}
+
 static int syscall_fcntl_impl(int fd, int cmd, uint32_t arg) {
     struct file* f = fd_get(fd);
     if (!f) return -EBADF;
@@ -1029,6 +1045,12 @@ static int syscall_unlink_impl(const char* user_path) {
     return -ENOSYS;
 }
 
+static int syscall_unlinkat_impl(int dirfd, const char* user_path, uint32_t flags) {
+    (void)flags;
+    if (dirfd != AT_FDCWD) return -ENOSYS;
+    return syscall_unlink_impl(user_path);
+}
+
 static int syscall_read_impl(int fd, void* user_buf, uint32_t len) {
     if (len > 1024 * 1024) return -EINVAL;
     if (user_range_ok(user_buf, (size_t)len) == 0) return -EFAULT;
@@ -1286,6 +1308,15 @@ static void syscall_handler(struct registers* regs) {
         return;
     }
 
+    if (syscall_no == SYSCALL_OPENAT) {
+        int dirfd = (int)regs->ebx;
+        const char* path = (const char*)regs->ecx;
+        uint32_t flags = (uint32_t)regs->edx;
+        uint32_t mode = (uint32_t)regs->esi;
+        regs->eax = (uint32_t)syscall_openat_impl(dirfd, path, flags, mode);
+        return;
+    }
+
     if (syscall_no == SYSCALL_CHDIR) {
         const char* path = (const char*)regs->ebx;
         regs->eax = (uint32_t)syscall_chdir_impl(path);
@@ -1381,8 +1412,17 @@ static void syscall_handler(struct registers* regs) {
 
     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);
+        struct stat* user_st = (struct stat*)regs->ecx;
+        regs->eax = (uint32_t)syscall_stat_impl(path, user_st);
+        return;
+    }
+
+    if (syscall_no == SYSCALL_FSTATAT) {
+        int dirfd = (int)regs->ebx;
+        const char* path = (const char*)regs->ecx;
+        struct stat* user_st = (struct stat*)regs->edx;
+        uint32_t flags = (uint32_t)regs->esi;
+        regs->eax = (uint32_t)syscall_fstatat_impl(dirfd, path, user_st, flags);
         return;
     }
 
@@ -1525,6 +1565,14 @@ static void syscall_handler(struct registers* regs) {
         return;
     }
 
+    if (syscall_no == SYSCALL_UNLINKAT) {
+        int dirfd = (int)regs->ebx;
+        const char* path = (const char*)regs->ecx;
+        uint32_t flags = (uint32_t)regs->edx;
+        regs->eax = (uint32_t)syscall_unlinkat_impl(dirfd, path, flags);
+        return;
+    }
+
     if (syscall_no == SYSCALL_GETDENTS) {
         int fd = (int)regs->ebx;
         void* buf = (void*)regs->ecx;
index 15fe228d642afb3a8287a61d964227095aca791c..4b1e73db4790fb65f7629ead62bbf9c3d28ace56 100644 (file)
@@ -74,6 +74,14 @@ enum {
     SYSCALL_CHDIR = 32,
     SYSCALL_GETCWD = 33,
     SYSCALL_DUP3 = 35,
+
+    SYSCALL_OPENAT = 36,
+    SYSCALL_FSTATAT = 37,
+    SYSCALL_UNLINKAT = 38,
+};
+
+enum {
+    AT_FDCWD = -100,
 };
 
 enum {
@@ -162,6 +170,39 @@ static int sys_write(int fd, const void* buf, uint32_t len) {
     return __syscall_fix(ret);
 }
 
+static int sys_openat(int dirfd, const char* path, uint32_t flags, uint32_t mode) {
+    int ret;
+    __asm__ volatile(
+        "int $0x80"
+        : "=a"(ret)
+        : "a"(SYSCALL_OPENAT), "b"(dirfd), "c"(path), "d"(flags), "S"(mode)
+        : "memory"
+    );
+    return __syscall_fix(ret);
+}
+
+static int sys_fstatat(int dirfd, const char* path, struct stat* st, uint32_t flags) {
+    int ret;
+    __asm__ volatile(
+        "int $0x80"
+        : "=a"(ret)
+        : "a"(SYSCALL_FSTATAT), "b"(dirfd), "c"(path), "d"(st), "S"(flags)
+        : "memory"
+    );
+    return __syscall_fix(ret);
+}
+
+static int sys_unlinkat(int dirfd, const char* path, uint32_t flags) {
+    int ret;
+    __asm__ volatile(
+        "int $0x80"
+        : "=a"(ret)
+        : "a"(SYSCALL_UNLINKAT), "b"(dirfd), "c"(path), "d"(flags)
+        : "memory"
+    );
+    return __syscall_fix(ret);
+}
+
 static int sys_pipe2(int fds[2], uint32_t flags) {
     int ret;
     __asm__ volatile(
@@ -1921,6 +1962,39 @@ void _start(void) {
                   (uint32_t)(sizeof("[init] chdir/getcwd OK\n") - 1));
     }
 
+    // B8: *at() syscalls smoke (AT_FDCWD)
+    {
+        int fd = sys_openat(AT_FDCWD, "atfile", O_CREAT | O_TRUNC, 0);
+        if (fd < 0) {
+            sys_write(1, "[init] openat failed\n",
+                      (uint32_t)(sizeof("[init] openat failed\n") - 1));
+            sys_exit(1);
+        }
+        (void)sys_close(fd);
+
+        struct stat st;
+        if (sys_fstatat(AT_FDCWD, "atfile", &st, 0) < 0) {
+            sys_write(1, "[init] fstatat failed\n",
+                      (uint32_t)(sizeof("[init] fstatat failed\n") - 1));
+            sys_exit(1);
+        }
+
+        if (sys_unlinkat(AT_FDCWD, "atfile", 0) < 0) {
+            sys_write(1, "[init] unlinkat failed\n",
+                      (uint32_t)(sizeof("[init] unlinkat failed\n") - 1));
+            sys_exit(1);
+        }
+
+        if (sys_stat("atfile", &st) >= 0) {
+            sys_write(1, "[init] unlinkat did not remove file\n",
+                      (uint32_t)(sizeof("[init] unlinkat did not remove file\n") - 1));
+            sys_exit(1);
+        }
+
+        sys_write(1, "[init] *at OK\n",
+                  (uint32_t)(sizeof("[init] *at OK\n") - 1));
+    }
+
     enum { NCHILD = 100 };
     int children[NCHILD];
     for (int i = 0; i < NCHILD; i++) {