From 9fe2331ca75994f413ea85994e03c4dbcde6317a Mon Sep 17 00:00:00 2001 From: Ruslan Isaev Date: Tue, 13 Jan 2026 23:29:16 +0300 Subject: [PATCH] syscalls: implement stat and fstat syscalls --- Makefile | 6 ++ include/string.h | 1 + src/tasking/syscalls.c | 217 +++++++++++++++++++++++++++++++++++++---- src/utils/string.c | 10 ++ 4 files changed, 215 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 13ec643..c9041ea 100644 --- a/Makefile +++ b/Makefile @@ -69,6 +69,12 @@ iso: cp grubshit/zsh katauos/katau/zsh cp grubshit/ksh katauos/katau/ksh + cp grubshit/ls katauos/katau/ls + cp grubshit/stat katauos/katau/stat + cp grubshit/stat.c katauos/katau/stat.c + cp grubshit/main katauos/main + cp grubshit/video.dat katauos/katau/video.dat + sudo umount tmp/ grub-mkrescue -o boot.iso katauos/ diff --git a/include/string.h b/include/string.h index 2f76470..99599c8 100644 --- a/include/string.h +++ b/include/string.h @@ -12,5 +12,6 @@ char *strcat(char *dest, const char *src); char *strcpy(char *dest, const char *src); char *strtok(char *str, const char *delim); char *strrchr(const char *s, int c); +int strcmp(const char* s1, const char* s2); #endif diff --git a/src/tasking/syscalls.c b/src/tasking/syscalls.c index 503f973..5b9af8f 100644 --- a/src/tasking/syscalls.c +++ b/src/tasking/syscalls.c @@ -102,6 +102,8 @@ int sys_fork(TrapFrame *tf) child->state = Ready; child->ring = current->ring; child->pagedir = new_pd; + child->cwd = malloc(sizeof(l9660_dir)); + memcpy(child->cwd, current->cwd, sizeof(l9660_dir)); void *kstack_physical = alloc_page(); if (!kstack_physical) { @@ -281,30 +283,27 @@ int sys_open(TrapFrame *tf) int flags = tf->ecx; int fd = -1; - const char* mode_str = flags_to_mode_str(flags); - - //debug_log("\n====filename: %s\n", filename); - //debug_log("\n====mode_str: %s\n", mode_str); - - for(int i = 3; i < MAX_OPEN_FILES; i++) - { - //debug_log("\n====i: %X\n", i); - if(current->file_descriptors[i] == NULL) - { - current->file_descriptors[i] = (l9660_file*)malloc(sizeof(l9660_file)); // Kernel malloc - l9660_openat(current->file_descriptors[i], root_dir, filename); - //debug_log("\n====FILE_DESCRIPTOR: %X\n", i); - int result = 0;//fat_fopen(current->file_descriptors[i], filename, mode_str); - if (result < 0) { - free(current->file_descriptors[i]); // Free on failure - current->file_descriptors[i] = NULL; - return result; - } + for(int i = 3; i < MAX_OPEN_FILES; i++) { + if(current->file_descriptors[i] == NULL) { fd = i; break; } } + if (fd == -1) return -23; // -ENFILE + l9660_file* file = (l9660_file*)malloc(sizeof(l9660_file)); + if (!file) return -12; // -ENOMEM + + l9660_dir temp_dir = *current->cwd; + l9660_seekdir(&temp_dir, 0); + int status = follow_path(filename, file, &temp_dir); + + if (status != L9660_OK) { + free(file); + return -2; // -ENOENT + } + + current->file_descriptors[fd] = file; return fd; } @@ -661,6 +660,178 @@ uint32_t sys_nanosleep(TrapFrame *tf) return 0; } +struct stat { + uint32_t st_dev; + uint32_t st_ino; + uint16_t st_mode; /* mode is 16-bit in standard 32-bit ABI */ + uint16_t st_nlink; /* nlink is 16-bit */ + uint16_t st_uid; /* uid is 16-bit */ + uint16_t st_gid; /* gid is 16-bit */ + uint32_t st_rdev; + uint32_t st_size; + uint32_t st_blksize; + uint32_t st_blocks; + uint32_t st_atime; + uint32_t st_atime_nsec; + uint32_t st_mtime; + uint32_t st_mtime_nsec; + uint32_t st_ctime; + uint32_t st_ctime_nsec; + uint32_t __unused4; + uint32_t __unused5; +}; + +/* File type flags (st_mode) */ +#define S_IFMT 0xF000 /* Format mask */ +#define S_IFSOCK 0xC000 /* Socket */ +#define S_IFLNK 0xA000 /* Symbolic link */ +#define S_IFREG 0x8000 /* Regular file */ +#define S_IFBLK 0x6000 /* Block device */ +#define S_IFDIR 0x4000 /* Directory */ +#define S_IFCHR 0x2000 /* Character device */ +#define S_IFIFO 0x1000 /* FIFO */ + +/* Permissions (simplified) */ +#define S_IRWXU 00700 /* User rwx */ +#define S_IRUSR 00400 /* User read */ +#define S_IWUSR 00200 /* User write */ +#define S_IXUSR 00100 /* User execute */ + +#ifdef L9660_BIG_ENDIAN +#define READ32(v) (((v).be[3]) | ((v).be[2] << 8) | ((v).be[1]) << 16 | ((v).be[0] << 24)) +#else +#define READ32(v) (((v).le[0]) | ((v).le[1] << 8) | ((v).le[2]) << 16 | ((v).le[3] << 24)) +#endif + +int find_entry_info(l9660_dir* parent, const char* name, uint32_t* sector, uint32_t* size) { + l9660_dirent* dent; + l9660_status status; + + // Rewind directory to start + l9660_seekdir(parent, 0); + + while (true) { + status = l9660_readdir(parent, &dent); + if (status != L9660_OK || dent == NULL) break; + + // Compare names (dent->name is NOT null-terminated) + size_t name_len = strlen(name); + if (name_len == dent->name_len && memcmp(dent->name, name, name_len) == 0) { + *sector = READ32(dent->sector); + *size = READ32(dent->size); + return 0; // Found + } + } + return -1; // Not found +} + +int sys_fstat(TrapFrame *tf) +{ + int fd = tf->ebx; + struct stat *st = (struct stat*)tf->ecx; + + if (!st) return -14; // -EFAULT + memset(st, 0, sizeof(struct stat)); + + //if stdin, stdout or stderr + if (fd >= 0 && fd < 3) { + st->st_mode = S_IFCHR | 0666; // Character device + st->st_rdev = fd; + st->st_nlink = 1; + st->st_blksize = 1024; + return 0; + } + + if (fd >= MAX_OPEN_FILES || current->file_descriptors[fd] == NULL) { + return -EBADF; + } + + l9660_file* file = current->file_descriptors[fd]; + + st->st_dev = 0; + st->st_ino = file->first_sector;//use first sector as inode + st->st_mode = S_IFREG | 0777; // Regular file + st->st_nlink = 1; + + //get size properly + uint32_t old_pos = l9660_tell(file); + l9660_seek(file, L9660_SEEK_END, 0); + st->st_size = l9660_tell(file); + l9660_seek(file, L9660_SEEK_SET, old_pos); + + st->st_blksize = 2048; + st->st_blocks = DivRoundUp(st->st_size, 512); + + return 0; +} + +int sys_stat(TrapFrame *tf) +{ + const char* path = (const char*)tf->ebx; + struct stat *st = (struct stat*)tf->ecx; + + if (!path || !st) return -14; // -EFAULT + memset(st, 0, sizeof(struct stat)); + + if (strcmp(path, "/") == 0) { + st->st_mode = S_IFDIR | 0755; + st->st_ino = root_dir->file.first_sector; + st->st_size = 2048; + return 0; + } + + l9660_file file; + l9660_dir parent_dir = *current->cwd; + + int status = follow_path(path, &file, &parent_dir); + + if (status == L9660_OK) { + // It is a FILE + st->st_mode = S_IFREG | 0777; + st->st_ino = file.first_sector; + + l9660_seek(&file, L9660_SEEK_END, 0); + st->st_size = l9660_tell(&file); + } + else if (status == L9660_ENOTFILE) { + // It is likely a DIRECTORY + // follow_path failed because the last component was a dir, not a file. + // 'parent_dir' now points to the directory CONTAINING the target. + + // We need to extract the target name from the path. + // e.g., "/boot/grub" -> parent is "/boot", target name is "grub" + const char* name = strrchr(path, '/'); + if (name) name++; // Skip slash + else name = path; // No slash, just name + + // Handle trailing slash (e.g. "boot/") + char name_buf[64]; + if (*name == '\0') { + // This is tricky without modifying the string. + // Simplification: assume path didn't end in slash or handle separately. + return -2; + } + + uint32_t sector = 0, size = 0; + if (find_entry_info(&parent_dir, name, §or, &size) == 0) { + st->st_mode = S_IFDIR | 0755; + st->st_ino = sector; + st->st_size = size; + } else { + return -2; // -ENOENT + } + } + else { + return -2; // -ENOENT + } + + st->st_nlink = 1; + st->st_blksize = 2048; + st->st_blocks = DivRoundUp(st->st_size, 512); + + return 0; +} + void handle_syscall(TrapFrame *tf) { /* @@ -725,6 +896,14 @@ void handle_syscall(TrapFrame *tf) tf->eax = sys_nanosleep(tf); break; + case 0x6a://stat + tf->eax = sys_stat(tf); + break; + + case 0x6c://fstat + tf->eax = sys_fstat(tf); + break; + default: debug_log("unknown syscall: %X\n", tf->eax); tf->eax = -38;//-ENOSYS diff --git a/src/utils/string.c b/src/utils/string.c index 268ce3f..5ac8349 100644 --- a/src/utils/string.c +++ b/src/utils/string.c @@ -160,4 +160,14 @@ char *strrchr(const char *s, int c) { if (*s++ == '\0') return (char *)p; } +} + +int strcmp(const char* s1, const char* s2) +{ + while(*s1 && (*s1 == *s2)) + { + s1++; + s2++; + } + return *(const unsigned char*)s1 - *(const unsigned char*)s2; } \ No newline at end of file