From 560003b6e320b88839894a64e203f1ca7e60f676 Mon Sep 17 00:00:00 2001 From: Ruslan Isaev Date: Sat, 31 Jan 2026 20:51:47 +0300 Subject: [PATCH] syscalls: implement statx syscall --- Makefile | 1 + src/tasking/syscalls.c | 216 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+) diff --git a/Makefile b/Makefile index c9041ea..f50e6c4 100644 --- a/Makefile +++ b/Makefile @@ -74,6 +74,7 @@ iso: cp grubshit/stat.c katauos/katau/stat.c cp grubshit/main katauos/main cp grubshit/video.dat katauos/katau/video.dat + cp grubshit/statx katauos/katau/statx sudo umount tmp/ grub-mkrescue -o boot.iso katauos/ diff --git a/src/tasking/syscalls.c b/src/tasking/syscalls.c index 02e486c..13a629e 100644 --- a/src/tasking/syscalls.c +++ b/src/tasking/syscalls.c @@ -837,6 +837,218 @@ int sys_stat(TrapFrame *tf) return 0; } +#ifndef _UINT64_T +typedef unsigned long long uint64_t; +#define _UINT64_T +#endif +#ifndef _INT64_T +typedef long long int64_t; +#define _INT64_T +#endif + +/* statx flags */ +#define AT_FDCWD -100 +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_NO_AUTOMOUNT 0x800 +#define AT_EMPTY_PATH 0x1000 + +/* statx mask bits */ +#define STATX_TYPE 0x00000001U +#define STATX_MODE 0x00000002U +#define STATX_NLINK 0x00000004U +#define STATX_UID 0x00000008U +#define STATX_GID 0x00000010U +#define STATX_ATIME 0x00000020U +#define STATX_MTIME 0x00000040U +#define STATX_CTIME 0x00000080U +#define STATX_INO 0x00000100U +#define STATX_SIZE 0x00000200U +#define STATX_BLOCKS 0x00000400U +#define STATX_BASIC_STATS 0x000007FFU + +struct statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t __reserved; +}; + +struct statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t __spare0[1]; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct statx_timestamp stx_atime; + struct statx_timestamp stx_btime; + struct statx_timestamp stx_ctime; + struct statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t __spare2[14]; +}; + +//#define STATX_DEBUG_LOG + +int sys_statx(TrapFrame *tf) +{ + int dirfd = tf->ebx; + const char* pathname = (const char*)tf->ecx; + int flags = tf->edx; + unsigned int mask = tf->esi; + struct statx *buf = (struct statx*)tf->edi; + +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] Called. FD=%x, Path='%s', Flags=%X, Mask=%X\n", + dirfd, pathname ? pathname : "NULL", flags, mask); +#endif + + if (!buf) return -14; // -EFAULT + memset(buf, 0, sizeof(struct statx)); + + //handle AT_EMPTY_PATH: stat the file descriptor directly + if ((flags & AT_EMPTY_PATH) && (pathname == NULL || pathname[0] == '\0')) { +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] AT_EMPTY_PATH detected. Using FD %x\n", dirfd); +#endif + + if (dirfd < 0 || dirfd >= MAX_OPEN_FILES || (current->file_descriptors[dirfd] == NULL && dirfd > STDERR_FILENO) ) { +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] Error: Bad FD %x\n", dirfd); +#endif + return -EBADF; + } + + l9660_file* file = current->file_descriptors[dirfd]; + + buf->stx_mask = STATX_BASIC_STATS; + buf->stx_blksize = 2048; + buf->stx_ino = file->first_sector; + buf->stx_nlink = 1; + //assume regular file because we can't conveniently check if it's a dir or just a file + buf->stx_mode = S_IFREG | 0777; + + uint32_t old_pos = l9660_tell(file); + l9660_seek(file, L9660_SEEK_END, 0); + uint32_t size = l9660_tell(file); + l9660_seek(file, L9660_SEEK_SET, old_pos); + + buf->stx_size = size; + buf->stx_blocks = DivRoundUp(size, 512); + +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] Success (FD). Size=%x, Ino=%x\n", (uint32_t)buf->stx_size, (uint32_t)buf->stx_ino); +#endif + return 0; + } + + // 2. Determine starting directory + l9660_dir start_dir; + + if (pathname && pathname[0] == '/') { + // Absolute path +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] Absolute path detected.\n"); +#endif + start_dir = *current->cwd; // follow_path handles root internally if path starts with / + } + else if (dirfd == AT_FDCWD) { + // Relative to CWD +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] Relative to CWD.\n"); +#endif + start_dir = *current->cwd; + } + else { + // Relative to a directory FD +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] Relative to FD %x.\n", dirfd); +#endif + if (dirfd < 0 || dirfd >= MAX_OPEN_FILES || current->file_descriptors[dirfd] == NULL) { + return -EBADF; + } + // Assuming the FD points to a directory structure + start_dir = *(l9660_dir*)current->file_descriptors[dirfd]; + } + + // 3. Resolve Path + l9660_file file; + l9660_dir traverse_dir = start_dir; + + int status = follow_path(pathname, &file, &traverse_dir); + + if (status == L9660_OK) { + // Found a FILE +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] Path resolved to FILE.\n"); +#endif + buf->stx_mask = STATX_BASIC_STATS; + buf->stx_blksize = 2048; + buf->stx_ino = file.first_sector; + buf->stx_mode = S_IFREG | 0777; + buf->stx_nlink = 1; + + l9660_seek(&file, L9660_SEEK_END, 0); + uint32_t size = l9660_tell(&file); + buf->stx_size = size; + buf->stx_blocks = DivRoundUp(size, 512); +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] File Size: %x bytes\n", size); +#endif + } + else if (status == L9660_ENOTFILE) { + // Found a DIRECTORY (or path led to one) + // Extract the last component name to find details in the parent +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] Path resolved to DIRECTORY.\n"); +#endif + const char* name = strrchr(pathname, '/'); + if (name) name++; + else name = pathname; + + // Handle case where path ends in slash or is empty/dot + if (*name == '\0' || strcmp(name, ".") == 0) { + buf->stx_ino = traverse_dir.file.first_sector; + buf->stx_size = 2048; + } else { + uint32_t sector = 0, size = 0; + if (find_entry_info(&traverse_dir, name, §or, &size) == 0) { + buf->stx_ino = sector; + buf->stx_size = size; + } else { +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] Error: Directory entry '%s' not found in parent.\n", name); +#endif + return -2; // -ENOENT + } + } + + buf->stx_mask = STATX_BASIC_STATS; + buf->stx_blksize = 2048; + buf->stx_mode = S_IFDIR | 0755; + buf->stx_nlink = 1; + buf->stx_blocks = DivRoundUp((uint32_t)buf->stx_size, 512); + } + else { +#ifdef STATX_DEBUG_LOG + debug_log("[STATX] Error: Path not found (status=%x)\n", status); +#endif + return -2; // -ENOENT + } + + return 0; +} + void handle_syscall(TrapFrame *tf) { /* @@ -909,6 +1121,10 @@ void handle_syscall(TrapFrame *tf) tf->eax = sys_fstat(tf); break; + case 0x17f: // statx + tf->eax = sys_statx(tf); + break; + default: debug_log("unknown syscall: %X\n", tf->eax); tf->eax = -38;//-ENOSYS