syscalls: implement stat and fstat syscalls
This commit is contained in:
+198
-19
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user