syscalls: implement statx syscall

This commit is contained in:
2026-01-31 20:51:47 +03:00
parent 93fe3a179b
commit 560003b6e3
2 changed files with 217 additions and 0 deletions
+216
View File
@@ -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, &sector, &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