syscalls: implement stat and fstat syscalls

This commit is contained in:
2026-01-13 23:29:16 +03:00
parent 4cef109e90
commit 9fe2331ca7
4 changed files with 215 additions and 19 deletions
+6
View File
@@ -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/
+1
View File
@@ -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
+198 -19
View File
@@ -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, &sector, &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
+10
View File
@@ -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;
}