From 84563b945a9b4843530e21cf24b3b14ec0773d8c Mon Sep 17 00:00:00 2001 From: Freywar Ulvnaudgari Date: Wed, 15 Jul 2026 21:39:17 +0300 Subject: [PATCH] Add file removal, `rm` --- build.sh | 1 + meson.build | 39 ++++++++++++++++++++ src/kernel/fat16.c | 88 ++++++++++++++++++++++++++++++++++++++------ src/kernel/fat16.h | 2 + src/kernel/fs.c | 4 ++ src/kernel/fs.h | 2 + src/kernel/path.c | 9 +++++ src/kernel/path.h | 2 + src/kernel/syscall.c | 7 ++++ src/lib/syscall.h | 1 + src/user/app/rm/rm.c | 26 +++++++++++++ src/user/syscall.asm | 6 +++ src/user/syscall.h | 2 + 13 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 src/user/app/rm/rm.c diff --git a/build.sh b/build.sh index 91b686b..0273fab 100755 --- a/build.sh +++ b/build.sh @@ -23,3 +23,4 @@ mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/ls ::bin/ls mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/cat ::bin/cat mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/cp ::bin/cp mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/mkdir ::bin/mkdir +mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/rm ::bin/rm diff --git a/meson.build b/meson.build index 7ee109a..194d863 100644 --- a/meson.build +++ b/meson.build @@ -388,3 +388,42 @@ custom_target( command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'], build_by_default: true, ) + +rm_start = custom_target( + 'rm_start', + input: 'src/user/start.asm', + output: 'rm_start.o', + command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'], +) + +rm_syscall = custom_target( + 'rm_syscall', + input: 'src/user/syscall.asm', + output: 'rm_syscall.o', + command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'], +) + +rm_elf = executable( + 'rm.elf', + sources: [rm_start, rm_syscall, lib_sources, 'src/user/app/rm/rm.c'], + c_args: [ + '-ffreestanding', + '-nostdlib', + '-fno-stack-protector', + '-mcmodel=large', + '-DVERSION="' + meson.project_version() + '"', + ], + link_args: [ + '-T', meson.project_source_root() / 'src/user/linker.ld', + '-nostdlib', + ], + link_depends: 'src/user/linker.ld', +) + +custom_target( + 'rm', + input: rm_elf, + output: 'rm', + command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'], + build_by_default: true, +) diff --git a/src/kernel/fat16.c b/src/kernel/fat16.c index 4959420..e0ef97c 100644 --- a/src/kernel/fat16.c +++ b/src/kernel/fat16.c @@ -42,21 +42,20 @@ typedef struct { uint32_t size; uint16_t dir_cluster; uint16_t dir_index; - uint8_t valid; + uint8_t removed; } fat16_inode_t; static fat16_inode_t inodes[MAX_INODES]; static fat16_inode_t *inode_create(uint16_t first_cluster, uint32_t size, uint16_t dir_cluster, uint16_t dir_index) { for (uint64_t i = 0; i < MAX_INODES; i++) { - if (!inodes[i].valid) { + if (!inodes[i].refs) { inodes[i] = (fat16_inode_t){ .refs = 1, .first_cluster = first_cluster, .size = size, .dir_cluster = dir_cluster, .dir_index = dir_index, - .valid = 1, }; return &inodes[i]; } @@ -66,7 +65,7 @@ static fat16_inode_t *inode_create(uint16_t first_cluster, uint32_t size, uint16 static fat16_inode_t *inode_get(uint32_t dir_cluster, uint16_t dir_index) { for (uint64_t i = 0; i < MAX_INODES; i++) { - if (inodes[i].valid && inodes[i].dir_cluster == dir_cluster && inodes[i].dir_index == dir_index) { + if (inodes[i].refs && inodes[i].dir_cluster == dir_cluster && inodes[i].dir_index == dir_index) { return &inodes[i]; } } @@ -84,14 +83,8 @@ static fat16_inode_t *inode_use(uint16_t first_cluster, uint32_t size, uint16_t } static void inode_free(fat16_inode_t *inode) { - inode->refs--; - if (!inode->refs) { - for (uint64_t i = 0; i < MAX_INODES; i++) { - if (&inodes[i] == inode) { - inodes[i].valid = 0; - break; - } - } + if (inode->refs) { + inode->refs--; } } @@ -263,6 +256,10 @@ fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name, uint64_t return NUL; } + if (((fat16_node_t *)directory)->inode->removed) { + return NUL; + } + uint16_t dir_cluster = ((fat16_node_t *)directory)->inode->first_cluster; char name_8_3[12]; @@ -350,6 +347,10 @@ fs_node_t *fat16_open_at(const fs_node_t *directory, uint16_t index, uint64_t fl return NUL; } + if (((fat16_node_t *)directory)->inode->removed) { + return NUL; + } + uint16_t dir_cluster = ((fat16_node_t *)directory)->inode->first_cluster; fat16_dir_entry_t *entries; @@ -403,6 +404,10 @@ uint64_t fat16_read(const fs_node_t *file, uint32_t offset, uint32_t bytes, void return (uint64_t)-1; } + if (fat_file->inode->removed) { + return 0; + } + if (offset >= fat_file->inode->size) { return 0; } @@ -460,6 +465,10 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_ return (uint64_t)-1; } + if (fat_file->inode->removed) { + return 0; + } + ensure_fat(); if (!fat_file->inode->first_cluster) { @@ -540,6 +549,10 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) { return (uint64_t)-1; } + if (fat_file->inode->removed) { + return 0; + } + if (file->size == size) { return size; } else if (file->size < size) { @@ -585,6 +598,57 @@ uint64_t fat16_truncate(fs_node_t *file, uint32_t size) { return (uint64_t)-1; } +uint64_t fat16_remove(fs_node_t *file) { + fat16_node_t *fat_file = (fat16_node_t *)file; + + if (fat_file->base.type != FAT16) { + return (uint64_t)-1; + } + + if (fat_file->inode->removed) { + return 0; + } + + if (file->is_dir) { + fat16_dir_entry_t *subentries; + uint16_t subentries_count = read_directory(fat_file->inode->first_cluster, &subentries); + uint16_t ei = 0, vi = 0; + while (ei < subentries_count && subentries[ei].name[0]) { + if ((uint8_t)subentries[ei].name[0] != 0xE5 && (uint8_t)subentries[ei].attributes != 0x0F) { + vi++; + } + ei++; + } + memory_free(subentries); + if (vi > 2) { + return (uint64_t)-1; + } + } + + fat_file->inode->removed = 1; + + if (fat_file->inode->first_cluster) { + ensure_fat(); + uint64_t next_cluster = fat_file->inode->first_cluster; + do { + uint32_t swap = fat[next_cluster]; + fat[next_cluster] = 0; + next_cluster = swap; + } while (next_cluster < 0xFFF8); + flush_fat(); + } + + fat16_dir_entry_t *entries; + uint16_t entries_count = read_directory(fat_file->inode->dir_cluster, &entries); + entries[fat_file->inode->dir_index].name[0] = 0xE5; + entries[fat_file->inode->dir_index].first_cluster = 0; + entries[fat_file->inode->dir_index].size = 0; + write_directory(fat_file->inode->dir_cluster, entries, entries_count); + memory_free(entries); + + return 1; +} + typedef struct { stream_t stream; fs_node_t *node; diff --git a/src/kernel/fat16.h b/src/kernel/fat16.h index 83f87fd..9284a33 100644 --- a/src/kernel/fat16.h +++ b/src/kernel/fat16.h @@ -21,6 +21,8 @@ uint64_t fat16_write(fs_node_t *file, uint32_t offset, const void *from, uint32_ uint64_t fat16_truncate(fs_node_t *file, uint32_t size); +uint64_t fat16_remove(fs_node_t *file); + void fat16_close(fs_node_t *node); void fat16_unmount(fs_node_t *fs); diff --git a/src/kernel/fs.c b/src/kernel/fs.c index a504d28..c7f184f 100644 --- a/src/kernel/fs.c +++ b/src/kernel/fs.c @@ -33,6 +33,10 @@ void fs_truncate(fs_node_t *file, uint32_t size) { fat16_truncate(file, size); } +void fs_remove(fs_node_t *file) { + fat16_remove(file); +} + void fs_close(fs_node_t *node) { fat16_close(node); } diff --git a/src/kernel/fs.h b/src/kernel/fs.h index fe1b48a..284ef0a 100644 --- a/src/kernel/fs.h +++ b/src/kernel/fs.h @@ -27,6 +27,8 @@ void fs_write(fs_node_t *file, uint32_t offset, const void *from, uint32_t bytes void fs_truncate(fs_node_t *file, uint32_t size); +void fs_remove(fs_node_t *file); + void fs_close(fs_node_t *node); void fs_unmount(fs_node_t *fs); diff --git a/src/kernel/path.c b/src/kernel/path.c index 5f674ee..1db78e8 100644 --- a/src/kernel/path.c +++ b/src/kernel/path.c @@ -74,3 +74,12 @@ void path_close(path_t *path) { } memory_free(path); } + +void path_remove(const fs_node_t *root, const path_t *source, const char *path) { + path_t *p = path_open(root, source, path, OPEN_FILE | OPEN_DIRECTORY); + if (!p || !p->depth) { + return; + } + fs_remove(p->stack[p->depth - 1]); + path_close(p); +} diff --git a/src/kernel/path.h b/src/kernel/path.h index fad9a76..694cbc8 100644 --- a/src/kernel/path.h +++ b/src/kernel/path.h @@ -17,3 +17,5 @@ fs_node_t *path_open_node(const fs_node_t *root, const path_t *source, const cha stream_t *path_open_stream(const fs_node_t *root, const path_t *source, const char *path, uint64_t flags); void path_close(path_t *path); + +void path_remove(const fs_node_t *root, const path_t *source, const char *path); diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 1f20bad..072acd6 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -185,6 +185,11 @@ static uint64_t truncate(uint64_t fd, uint64_t size) { return current_process->fds[fd]->truncate(current_process->fds[fd], size); } +static uint64_t remove(const char *path) { + path_remove(current_process->root, current_process->cwd, path); + return 0; +} + static void exit(exit_code_t code) { current_process->state = PROCESS_ZOMBIE; current_process->code = code; @@ -219,6 +224,8 @@ uint64_t syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t return close(arg1); case SYSCALL_TRUNCATE: return truncate(arg1, arg2); + case SYSCALL_REMOVE: + return remove((char *)arg1); case SYSCALL_EXIT: exit(arg1); return 0; diff --git a/src/lib/syscall.h b/src/lib/syscall.h index cf22976..2bba0f0 100644 --- a/src/lib/syscall.h +++ b/src/lib/syscall.h @@ -7,6 +7,7 @@ #define SYSCALL_OPEN 6 #define SYSCALL_CLOSE 7 #define SYSCALL_TRUNCATE 8 +#define SYSCALL_REMOVE 9 #define SYSCALL_EXIT 60 #define OPEN_CREATE 0b0001 diff --git a/src/user/app/rm/rm.c b/src/user/app/rm/rm.c new file mode 100644 index 0000000..f954f33 --- /dev/null +++ b/src/user/app/rm/rm.c @@ -0,0 +1,26 @@ +#include "src/lib/syscall.h" +#include "src/lib/util.h" +#include "src/user/syscall.h" + +#define BLOCK_SIZE 65536 + +#define PRINT_S(s) write(1, s, sizeof(s) - 1); +#define PRINT_D(s) write(1, s, string_length(s)); + +exit_code_t main(uint64_t argc, const char **argv) { + if (argc < 2) { + PRINT_S("rm: requires one or more arguments\n"); + return EXIT_CODE_GENERAL_FAILURE; + } + + uint64_t code = EXIT_CODE_OK; + for (uint64_t i = 1; i < argc; i++) { + exit_code_t c = remove(argv[i]); + if (c != EXIT_CODE_OK) { + PRINT_S("rm: coult not remove file\n"); + code = c; + } + } + + return code; +} diff --git a/src/user/syscall.asm b/src/user/syscall.asm index 564bd37..407341e 100644 --- a/src/user/syscall.asm +++ b/src/user/syscall.asm @@ -54,6 +54,12 @@ truncate: syscall ret +global remove +remove: + mov rax, 9 + syscall + ret + global exit exit: mov rax, 60 diff --git a/src/user/syscall.h b/src/user/syscall.h index 8dbf829..7b05f70 100644 --- a/src/user/syscall.h +++ b/src/user/syscall.h @@ -20,4 +20,6 @@ uint64_t close(uint64_t fd); uint64_t truncate(uint64_t fd, uint64_t size); +uint64_t remove(const char *path); + void exit(exit_code_t code);