From 8872f25b4438d837c55aae55ce8a21aef02896cc Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Mon, 9 Feb 2026 21:41:56 -0300 Subject: [PATCH] diskfs: add mkdir/unlink syscalls --- include/diskfs.h | 3 ++ include/syscall.h | 3 ++ src/kernel/diskfs.c | 56 +++++++++++++++++++++++++++++++++++++ src/kernel/syscall.c | 60 ++++++++++++++++++++++++++++++++++++++++ user/init.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 188 insertions(+) diff --git a/include/diskfs.h b/include/diskfs.h index 2d05498..63d6000 100644 --- a/include/diskfs.h +++ b/include/diskfs.h @@ -11,4 +11,7 @@ fs_node_t* diskfs_create_root(void); // flags: supports O_CREAT (0x40) and O_TRUNC (0x200) semantics (minimal). int diskfs_open_file(const char* rel_path, uint32_t flags, fs_node_t** out_node); +int diskfs_mkdir(const char* rel_path); +int diskfs_unlink(const char* rel_path); + #endif diff --git a/include/syscall.h b/include/syscall.h index 042cb1e..5dbddcf 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -37,6 +37,9 @@ enum { SYSCALL_SIGACTION = 25, SYSCALL_SIGPROCMASK = 26, SYSCALL_SIGRETURN = 27, + + SYSCALL_MKDIR = 28, + SYSCALL_UNLINK = 29, }; #endif diff --git a/src/kernel/diskfs.c b/src/kernel/diskfs.c index e552d34..72faa14 100644 --- a/src/kernel/diskfs.c +++ b/src/kernel/diskfs.c @@ -522,6 +522,62 @@ int diskfs_open_file(const char* rel_path, uint32_t flags, fs_node_t** out_node) return 0; } +int diskfs_mkdir(const char* rel_path) { + if (!g_ready) return -ENODEV; + if (!rel_path || rel_path[0] == 0) return -EINVAL; + + struct diskfs_super sb; + if (diskfs_super_load(&sb) < 0) return -EIO; + + uint16_t ino = 0; + uint16_t parent = 0; + char last[DISKFS_NAME_MAX]; + last[0] = 0; + int rc = diskfs_lookup_path(&sb, rel_path, &ino, &parent, last, sizeof(last)); + if (rc == 0) { + return -EEXIST; + } + if (rc != -ENOENT) return rc; + if (last[0] == 0) return -EINVAL; + + if (parent >= DISKFS_MAX_INODES) return -EIO; + if (sb.inodes[parent].type != DISKFS_INODE_DIR) return -ENOTDIR; + + for (uint16_t i = 1; i < DISKFS_MAX_INODES; i++) { + if (sb.inodes[i].type != DISKFS_INODE_FREE) continue; + sb.inodes[i].type = DISKFS_INODE_DIR; + sb.inodes[i].parent = parent; + memset(sb.inodes[i].name, 0, sizeof(sb.inodes[i].name)); + diskfs_strlcpy(sb.inodes[i].name, last, sizeof(sb.inodes[i].name)); + sb.inodes[i].start_lba = 0; + sb.inodes[i].size_bytes = 0; + sb.inodes[i].cap_sectors = 0; + return diskfs_super_store(&sb); + } + + return -ENOSPC; +} + +int diskfs_unlink(const char* rel_path) { + if (!g_ready) return -ENODEV; + if (!rel_path || rel_path[0] == 0) return -EINVAL; + + struct diskfs_super sb; + if (diskfs_super_load(&sb) < 0) return -EIO; + + uint16_t ino = 0; + int rc = diskfs_lookup_path(&sb, rel_path, &ino, 0, 0, 0); + if (rc < 0) return rc; + if (ino == 0) return -EPERM; + if (ino >= DISKFS_MAX_INODES) return -EIO; + + if (sb.inodes[ino].type == DISKFS_INODE_DIR) return -EISDIR; + if (sb.inodes[ino].type != DISKFS_INODE_FILE) return -ENOENT; + + memset(&sb.inodes[ino], 0, sizeof(sb.inodes[ino])); + return diskfs_super_store(&sb); +} + fs_node_t* diskfs_create_root(void) { if (!g_ready) { if (ata_pio_init_primary_master() == 0) { diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index c25cbb3..f255edd 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -788,6 +788,54 @@ static int syscall_open_impl(const char* user_path, uint32_t flags) { return fd; } +static int syscall_mkdir_impl(const char* user_path) { + if (!user_path) 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; + } + } + + if (path[0] == '/' && path[1] == 'd' && path[2] == 'i' && path[3] == 's' && path[4] == 'k' && path[5] == '/') { + const char* rel = path + 6; + if (rel[0] == 0) return -EINVAL; + return diskfs_mkdir(rel); + } + + return -ENOSYS; +} + +static int syscall_unlink_impl(const char* user_path) { + if (!user_path) 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; + } + } + + if (path[0] == '/' && path[1] == 'd' && path[2] == 'i' && path[3] == 's' && path[4] == 'k' && path[5] == '/') { + const char* rel = path + 6; + if (rel[0] == 0) return -EINVAL; + return diskfs_unlink(rel); + } + + return -ENOSYS; +} + 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; @@ -1197,6 +1245,18 @@ static void syscall_handler(struct registers* regs) { return; } + if (syscall_no == SYSCALL_MKDIR) { + const char* path = (const char*)regs->ebx; + regs->eax = (uint32_t)syscall_mkdir_impl(path); + return; + } + + if (syscall_no == SYSCALL_UNLINK) { + const char* path = (const char*)regs->ebx; + regs->eax = (uint32_t)syscall_unlink_impl(path); + return; + } + regs->eax = (uint32_t)-ENOSYS; } diff --git a/user/init.c b/user/init.c index b2bed6b..bce209b 100644 --- a/user/init.c +++ b/user/init.c @@ -62,6 +62,9 @@ enum { SYSCALL_SIGACTION = 25, SYSCALL_SIGPROCMASK = 26, SYSCALL_SIGRETURN = 27, + + SYSCALL_MKDIR = 28, + SYSCALL_UNLINK = 29, }; enum { @@ -394,6 +397,28 @@ static int sys_open(const char* path, uint32_t flags) { return __syscall_fix(ret); } +static int sys_mkdir(const char* path) { + int ret; + __asm__ volatile( + "int $0x80" + : "=a"(ret) + : "a"(SYSCALL_MKDIR), "b"(path) + : "memory" + ); + return __syscall_fix(ret); +} + +static int sys_unlink(const char* path) { + int ret; + __asm__ volatile( + "int $0x80" + : "=a"(ret) + : "a"(SYSCALL_UNLINK), "b"(path) + : "memory" + ); + return __syscall_fix(ret); +} + static int sys_read(int fd, void* buf, uint32_t len) { int ret; __asm__ volatile( @@ -1506,6 +1531,47 @@ void _start(void) { sys_write(1, " OK\n", (uint32_t)(sizeof(" OK\n") - 1)); } + // B3: diskfs mkdir/unlink smoke + { + int r = sys_mkdir("/disk/dir"); + if (r < 0 && r != -17) { + sys_write(1, "[init] mkdir /disk/dir failed\n", + (uint32_t)(sizeof("[init] mkdir /disk/dir failed\n") - 1)); + sys_exit(1); + } + + int fd = sys_open("/disk/dir/file", O_CREAT | O_TRUNC); + if (fd < 0) { + sys_write(1, "[init] open /disk/dir/file failed\n", + (uint32_t)(sizeof("[init] open /disk/dir/file failed\n") - 1)); + sys_exit(1); + } + static const char msg2[] = "ok"; + if (sys_write(fd, msg2, 2) != 2) { + sys_write(1, "[init] write /disk/dir/file failed\n", + (uint32_t)(sizeof("[init] write /disk/dir/file failed\n") - 1)); + sys_exit(1); + } + (void)sys_close(fd); + + r = sys_unlink("/disk/dir/file"); + if (r < 0) { + sys_write(1, "[init] unlink /disk/dir/file failed\n", + (uint32_t)(sizeof("[init] unlink /disk/dir/file failed\n") - 1)); + sys_exit(1); + } + + fd = sys_open("/disk/dir/file", 0); + if (fd >= 0) { + sys_write(1, "[init] unlink did not remove file\n", + (uint32_t)(sizeof("[init] unlink did not remove file\n") - 1)); + sys_exit(1); + } + + sys_write(1, "[init] diskfs mkdir/unlink OK\n", + (uint32_t)(sizeof("[init] diskfs mkdir/unlink OK\n") - 1)); + } + enum { NCHILD = 100 }; int children[NCHILD]; for (int i = 0; i < NCHILD; i++) { -- 2.43.0