syscalls: implement statx syscall
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user