Disk improvements

This commit is contained in:
boreddevnl 2026-03-01 17:10:41 +01:00
parent 8bd70faa89
commit 5cf552fd14
12 changed files with 558 additions and 126 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
disk.img

Binary file not shown.

View file

@ -309,7 +309,7 @@ static int ramfs_read(FAT32_FileHandle *handle, void *buffer, int size) {
int to_read = size - bytes_read;
int available = handle->size - handle->position;
if (to_read > available) to_read = available;
if (to_read > FAT32_CLUSTER_SIZE - offset_in_cluster) to_read = FAT32_CLUSTER_SIZE - offset_in_cluster;
if (to_read > (int)(FAT32_CLUSTER_SIZE - offset_in_cluster)) to_read = FAT32_CLUSTER_SIZE - offset_in_cluster;
if (handle->cluster >= MAX_CLUSTERS) break;
@ -342,7 +342,7 @@ static int ramfs_write(FAT32_FileHandle *handle, const void *buffer, int size) {
while (bytes_written < size) {
uint32_t offset_in_cluster = handle->position % FAT32_CLUSTER_SIZE;
int to_write = size - bytes_written;
if (to_write > FAT32_CLUSTER_SIZE - offset_in_cluster) to_write = FAT32_CLUSTER_SIZE - offset_in_cluster;
if (to_write > (int)(FAT32_CLUSTER_SIZE - offset_in_cluster)) to_write = FAT32_CLUSTER_SIZE - offset_in_cluster;
if (handle->cluster >= MAX_CLUSTERS) break;
@ -514,13 +514,7 @@ static FAT32_FileHandle* realfs_open(char drive, const char *path, const char *m
const char *p = path;
if (*p == '/') p++;
fs_serial_str("[FAT32] realfs_open drive=");
fs_serial_char(drive);
fs_serial_str(" path='");
fs_serial_str(path);
fs_serial_str("' mode=");
fs_serial_char(mode[0]);
fs_serial_str("\n");
if (*p == 0) {
// Root dir
@ -559,6 +553,7 @@ static FAT32_FileHandle* realfs_open(char drive, const char *path, const char *m
found = false;
uint32_t search_cluster = current_cluster;
uint8_t *cluster_buf = (uint8_t*)kmalloc(vol->sectors_per_cluster * 512);
if (!cluster_buf) return NULL;
while (search_cluster < 0x0FFFFFF8) {
if (realfs_read_cluster(vol, search_cluster, cluster_buf) != 0) break;
@ -594,13 +589,6 @@ static FAT32_FileHandle* realfs_open(char drive, const char *path, const char *m
if (match) {
uint32_t cluster = (entry[e].start_cluster_high << 16) | entry[e].start_cluster_low;
fs_serial_str("[FAT32] MATCH '");
fs_serial_str(name);
fs_serial_str("' cluster=");
fs_serial_num(cluster);
fs_serial_str(" size=");
fs_serial_num(entry[e].file_size);
fs_serial_str("\n");
uint32_t lba = vol->cluster_begin_lba + (search_cluster - 2) * vol->sectors_per_cluster;
int sect_in_cluster = (e * 32) / 512;
@ -644,52 +632,53 @@ static FAT32_FileHandle* realfs_open(char drive, const char *path, const char *m
int count = (vol->sectors_per_cluster * 512) / 32;
for (int e = 0; e < count; e++) {
if (entries[e].filename[0] == 0 || entries[e].filename[0] == 0xE5) {
uint32_t lba = vol->cluster_begin_lba + (search_cluster - 2) * vol->sectors_per_cluster;
int sect_in_cluster = (e * 32) / 512;
free_sector = lba + sect_in_cluster;
free_offset = (e * 32) % 512;
found_free = true;
break;
}
if (entries[e].filename[0] == 0 || entries[e].filename[0] == 0xE5) {
uint32_t lba = vol->cluster_begin_lba + (search_cluster - 2) * vol->sectors_per_cluster;
int sect_in_cluster = (e * 32) / 512;
free_sector = lba + sect_in_cluster;
free_offset = (e * 32) % 512;
found_free = true;
break;
}
}
if (!found_free) search_cluster = realfs_next_cluster(vol, search_cluster);
}
if (found_free) {
uint8_t *sect_buf = (uint8_t*)kmalloc(512);
vol->disk->read_sector(vol->disk, free_sector, sect_buf);
FAT32_DirEntry *d = (FAT32_DirEntry*)(sect_buf + free_offset);
for(int k=0; k<8; k++) d->filename[k] = dos_name[k];
for(int k=0; k<3; k++) d->extension[k] = dos_name[8+k];
d->attributes = ATTR_ARCHIVE;
d->start_cluster_high = 0;
d->start_cluster_low = 0;
d->file_size = 0;
// Write to disk
if (vol->disk->write_sector(vol->disk, free_sector, sect_buf) != 0) {
// Write failed, free the buffer and return NULL
if (sect_buf) {
vol->disk->read_sector(vol->disk, free_sector, sect_buf);
FAT32_DirEntry *d = (FAT32_DirEntry*)(sect_buf + free_offset);
for(int k=0; k<8; k++) d->filename[k] = dos_name[k];
for(int k=0; k<3; k++) d->extension[k] = dos_name[8+k];
d->attributes = ATTR_ARCHIVE;
d->start_cluster_high = 0;
d->start_cluster_low = 0;
d->file_size = 0;
// Write to disk
if (vol->disk->write_sector(vol->disk, free_sector, sect_buf) != 0) {
kfree(sect_buf);
kfree(cluster_buf);
return NULL;
}
kfree(sect_buf);
kfree(cluster_buf);
return NULL;
}
kfree(sect_buf);
FAT32_FileHandle *fh = ramfs_find_free_handle();
if (fh) {
fh->valid = true;
fh->drive = drive;
fh->start_cluster = 0;
fh->cluster = 0;
fh->position = 0;
fh->size = 0;
fh->mode = 1; // Write
fh->dir_sector = free_sector;
fh->dir_offset = free_offset;
kfree(cluster_buf);
return fh;
FAT32_FileHandle *fh = ramfs_find_free_handle();
if (fh) {
fh->valid = true;
fh->drive = drive;
fh->start_cluster = 0;
fh->cluster = 0;
fh->position = 0;
fh->size = 0;
fh->mode = (mode[0] == 'a' ? 2 : 1);
fh->dir_sector = free_sector;
fh->dir_offset = free_offset;
kfree(cluster_buf);
return fh;
}
}
}
kfree(cluster_buf);
@ -710,9 +699,22 @@ static FAT32_FileHandle* realfs_open(char drive, const char *path, const char *m
fh->cluster = current_cluster;
fh->position = 0;
fh->size = file_size;
fh->mode = (mode[0] == 'w' ? 1 : 0); // Only R/W supported
fh->mode = (mode[0] == 'w' ? 1 : (mode[0] == 'a' ? 2 : 0));
fh->dir_sector = entry_sector;
fh->dir_offset = entry_offset;
if (mode[0] == 'a') {
fh->position = fh->size;
// Seek to EOF cluster
uint32_t cluster_size = vol->sectors_per_cluster * 512;
uint32_t pos = 0;
while (pos + cluster_size <= fh->position) {
uint32_t next = realfs_next_cluster(vol, fh->cluster);
if (next >= 0x0FFFFFF8) break;
fh->cluster = next;
pos += cluster_size;
}
}
return fh;
}
@ -736,7 +738,7 @@ static int realfs_read(FAT32_FileHandle *handle, void *buffer, int size) {
uint32_t offset = handle->position % cluster_size;
int to_copy = size - bytes_read;
int available = cluster_size - offset;
if (handle->size - handle->position < available) available = handle->size - handle->position;
if ((int)(handle->size - handle->position) < available) available = handle->size - handle->position;
if (to_copy > available) to_copy = available;
for (int i = 0; i < to_copy; i++) {
@ -808,22 +810,25 @@ static int realfs_write(FAT32_FileHandle *handle, const void *buffer, int size)
handle->start_cluster = new_cluster;
handle->cluster = new_cluster;
// Mark new cluster as EOF in FAT
// Mark new cluster as EOF in FAT, preserve high bits
uint32_t fat_sector = vol->fat_begin_lba + (new_cluster * 4) / 512;
uint32_t fat_offset = (new_cluster * 4) % 512;
uint8_t *fat_buf = (uint8_t*)kmalloc(512);
if (vol->disk->read_sector(vol->disk, fat_sector, fat_buf) == 0) {
*(uint32_t*)&fat_buf[fat_offset] = 0x0FFFFFF8; // EOF marker
if (fat_buf && vol->disk->read_sector(vol->disk, fat_sector, fat_buf) == 0) {
uint32_t old_val = *(uint32_t*)&fat_buf[fat_offset];
*(uint32_t*)&fat_buf[fat_offset] = (old_val & 0xF0000000) | 0x0FFFFFF8; // EOF
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
}
kfree(fat_buf);
if (fat_buf) kfree(fat_buf);
// Initialize the new cluster with zeros to avoid garbage
uint32_t cluster_size_bytes = vol->sectors_per_cluster * 512;
uint8_t *cbuf = (uint8_t*)kmalloc(cluster_size_bytes);
for(uint32_t i=0; i<cluster_size_bytes; i++) cbuf[i] = 0;
realfs_write_cluster(vol, new_cluster, cbuf);
kfree(cbuf);
if (cbuf) {
for(uint32_t i=0; i<cluster_size_bytes; i++) cbuf[i] = 0;
realfs_write_cluster(vol, new_cluster, cbuf);
kfree(cbuf);
}
// Update directory entry immediately with the allocated cluster and initial size
if (handle->dir_sector != 0 && handle->dir_offset != 0xFFFFFFFF && handle->dir_offset < 512) {
@ -875,36 +880,41 @@ static int realfs_write(FAT32_FileHandle *handle, const void *buffer, int size)
if (handle->position % cluster_size == 0 && bytes_written < size) {
uint32_t next = realfs_next_cluster(vol, handle->cluster);
if (next >= 0x0FFFFFF8) {
// If next is 0 (unallocated) or EOC, we must allocate a new cluster
if (next < 2 || next >= 0x0FFFFFF8) {
uint32_t new_cluster = realfs_allocate_cluster(vol);
if (new_cluster == 0) break;
// Link current cluster to new cluster in FAT
// Link current cluster to new cluster in FAT, preserve high bits
uint32_t fat_sector = vol->fat_begin_lba + (handle->cluster * 4) / 512;
uint32_t fat_offset = (handle->cluster * 4) % 512;
uint8_t *fat_buf = (uint8_t*)kmalloc(512);
if (vol->disk->read_sector(vol->disk, fat_sector, fat_buf) == 0) {
*(uint32_t*)&fat_buf[fat_offset] = new_cluster;
if (fat_buf && vol->disk->read_sector(vol->disk, fat_sector, fat_buf) == 0) {
uint32_t old_val = *(uint32_t*)&fat_buf[fat_offset];
*(uint32_t*)&fat_buf[fat_offset] = (old_val & 0xF0000000) | (new_cluster & 0x0FFFFFFF);
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
}
kfree(fat_buf);
if (fat_buf) kfree(fat_buf);
// Mark new cluster as EOF in FAT
// Mark new cluster as EOF in FAT, preserve high bits
fat_sector = vol->fat_begin_lba + (new_cluster * 4) / 512;
fat_offset = (new_cluster * 4) % 512;
fat_buf = (uint8_t*)kmalloc(512);
if (vol->disk->read_sector(vol->disk, fat_sector, fat_buf) == 0) {
*(uint32_t*)&fat_buf[fat_offset] = 0x0FFFFFF8; // EOF marker
if (fat_buf && vol->disk->read_sector(vol->disk, fat_sector, fat_buf) == 0) {
uint32_t old_val = *(uint32_t*)&fat_buf[fat_offset];
*(uint32_t*)&fat_buf[fat_offset] = (old_val & 0xF0000000) | 0x0FFFFFF8; // EOF
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
}
kfree(fat_buf);
if (fat_buf) kfree(fat_buf);
// Init new cluster
uint8_t *cbuf = (uint8_t*)kmalloc(cluster_size);
for(uint32_t i=0; i<cluster_size; i++) cbuf[i] = 0;
realfs_write_cluster(vol, new_cluster, cbuf);
kfree(cbuf);
if (cbuf) {
for(uint32_t k=0; k<cluster_size; k++) cbuf[k] = 0;
realfs_write_cluster(vol, new_cluster, cbuf);
kfree(cbuf);
}
next = new_cluster;
}
@ -1339,13 +1349,151 @@ int fat32_seek(FAT32_FileHandle *handle, int offset, int whence) {
return new_position;
}
static bool realfs_mkdir(char drive, const char *path) {
int vol_idx = drive - 'A';
if (!volumes[vol_idx].mounted) {
if (!realfs_mount(drive)) return false;
}
FAT32_Volume *vol = &volumes[vol_idx];
// Find parent directory and name of new directory
char parent_path[FAT32_MAX_PATH];
char dirname[FAT32_MAX_FILENAME];
extract_parent_path(path, parent_path);
extract_filename(path, dirname);
// Open parent directory
FAT32_FileHandle *parent_fh = realfs_open(drive, parent_path, "r");
if (!parent_fh) return false;
uint32_t parent_cluster = parent_fh->start_cluster;
fat32_close(parent_fh);
// Check if it already exists
FAT32_FileHandle *check_fh = realfs_open(drive, path, "r");
if (check_fh) {
fat32_close(check_fh);
return false;
}
// Allocate cluster for new directory
uint32_t new_cluster = realfs_allocate_cluster(vol);
if (new_cluster == 0) return false;
// Initialize new directory cluster with . and .. entries
uint32_t cluster_size = vol->sectors_per_cluster * 512;
uint8_t *cluster_buf = (uint8_t*)kmalloc(cluster_size);
if (!cluster_buf) return false;
for (uint32_t i = 0; i < cluster_size; i++) cluster_buf[i] = 0;
FAT32_DirEntry *dot = (FAT32_DirEntry*)cluster_buf;
FAT32_DirEntry *dotdot = (FAT32_DirEntry*)(cluster_buf + 32);
// . entry
for (int i = 0; i < 8; i++) dot->filename[i] = ' ';
for (int i = 0; i < 3; i++) dot->extension[i] = ' ';
dot->filename[0] = '.';
dot->attributes = ATTR_DIRECTORY;
dot->start_cluster_high = (new_cluster >> 16);
dot->start_cluster_low = (new_cluster & 0xFFFF);
// .. entry
for (int i = 0; i < 8; i++) dotdot->filename[i] = ' ';
for (int i = 0; i < 3; i++) dotdot->extension[i] = ' ';
dotdot->filename[0] = '.'; dotdot->filename[1] = '.';
dotdot->attributes = ATTR_DIRECTORY;
dotdot->start_cluster_high = (parent_cluster >> 16);
dotdot->start_cluster_low = (parent_cluster & 0xFFFF);
if (realfs_write_cluster(vol, new_cluster, cluster_buf) != 0) {
kfree(cluster_buf);
return false;
}
kfree(cluster_buf);
// Find free entry in parent directory
uint32_t search_cluster = parent_cluster;
uint8_t *sect_buf = (uint8_t*)kmalloc(512);
bool found_free = false;
uint32_t free_sector = 0;
uint32_t free_offset = 0;
uint8_t *dir_cluster_buf = (uint8_t*)kmalloc(cluster_size);
if (!dir_cluster_buf) {
kfree(sect_buf);
return false;
}
while (search_cluster < 0x0FFFFFF8 && !found_free) {
if (realfs_read_cluster(vol, search_cluster, dir_cluster_buf) != 0) break;
FAT32_DirEntry *entries = (FAT32_DirEntry*)dir_cluster_buf;
int count = cluster_size / 32;
for (int e = 0; e < count; e++) {
if (entries[e].filename[0] == 0 || entries[e].filename[0] == 0xE5) {
uint32_t lba = vol->cluster_begin_lba + (search_cluster - 2) * vol->sectors_per_cluster;
free_sector = lba + (e * 32) / 512;
free_offset = (e * 32) % 512;
found_free = true;
break;
}
}
if (!found_free) {
uint32_t next = realfs_next_cluster(vol, search_cluster);
if (next >= 0x0FFFFFF8) {
// Need to expand directory?
uint32_t expanded = realfs_allocate_cluster(vol);
if (expanded == 0) break;
// Link, preserve high bits
uint32_t fat_sector = vol->fat_begin_lba + (search_cluster * 4) / 512;
uint32_t fat_offset = (search_cluster * 4) % 512;
if (vol->disk->read_sector(vol->disk, fat_sector, sect_buf) == 0) {
uint32_t old_val = *(uint32_t*)&sect_buf[fat_offset];
*(uint32_t*)&sect_buf[fat_offset] = (old_val & 0xF0000000) | (expanded & 0x0FFFFFFF);
vol->disk->write_sector(vol->disk, fat_sector, sect_buf);
}
// Zero out new cluster
for(uint32_t k=0; k<cluster_size; k++) dir_cluster_buf[k] = 0;
realfs_write_cluster(vol, expanded, dir_cluster_buf);
next = expanded;
}
search_cluster = next;
}
}
kfree(dir_cluster_buf);
if (found_free) {
vol->disk->read_sector(vol->disk, free_sector, sect_buf);
FAT32_DirEntry *d = (FAT32_DirEntry*)(sect_buf + free_offset);
char dos_name[11];
to_dos_filename(dirname, dos_name);
for (int k = 0; k < 8; k++) d->filename[k] = dos_name[k];
for (int k = 0; k < 3; k++) d->extension[k] = dos_name[8+k];
d->attributes = ATTR_DIRECTORY;
d->start_cluster_high = (new_cluster >> 16);
d->start_cluster_low = (new_cluster & 0xFFFF);
d->file_size = 0;
vol->disk->write_sector(vol->disk, free_sector, sect_buf);
}
kfree(sect_buf);
return found_free;
}
bool fat32_mkdir(const char *path) {
if (parse_drive_from_path(&path) != 'A') return false; // RAMFS only for now
const char *p = path;
char drive = parse_drive_from_path(&p);
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
if (drive != 'A') {
bool res = realfs_mkdir(drive, p);
wm_notify_fs_change();
asm volatile("push %0; popfq" : : "r"(rflags));
return res;
}
char normalized[FAT32_MAX_PATH];
fat32_normalize_path(path, normalized);
fat32_normalize_path(p, normalized);
if (ramfs_find_file(normalized)) {
asm volatile("push %0; popfq" : : "r"(rflags));
@ -1428,6 +1576,48 @@ bool fat32_delete(const char *path) {
return result;
}
int fat32_get_info(const char *path, FAT32_FileInfo *info) {
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
const char *p = path;
char drive = parse_drive_from_path(&p);
int result = -1;
if (drive == 'A') {
char normalized[FAT32_MAX_PATH];
fat32_normalize_path(p, normalized);
FileEntry *entry = ramfs_find_file(normalized);
if (entry) {
fs_strcpy(info->name, entry->filename);
info->size = entry->size;
info->is_directory = (entry->attributes & ATTR_DIRECTORY) != 0;
info->start_cluster = entry->start_cluster;
result = 0;
}
} else {
FAT32_FileHandle *fh = realfs_open(drive, p, "r");
if (fh) {
extract_filename(p, info->name);
info->size = fh->size;
info->start_cluster = fh->start_cluster;
if (fs_strcmp(p, "/") == 0 || fs_strcmp(p, "") == 0) {
info->is_directory = 1;
} else {
info->is_directory = fat32_is_directory(path);
}
fat32_close(fh);
result = 0;
}
}
asm volatile("push %0; popfq" : : "r"(rflags));
return result;
}
bool fat32_exists(const char *path) {
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
@ -1539,10 +1729,7 @@ int fat32_list_directory(const char *path, FAT32_FileInfo *entries, int max_entr
char normalized[FAT32_MAX_PATH];
fat32_normalize_path(p, normalized);
extern void serial_write(const char *str);
serial_write("[DEBUG] fat32_list_directory (RAMFS) path: ");
serial_write(normalized);
serial_write("\n");
for (int i = 0; i < MAX_FILES && count < max_entries; i++) {
if (files[i].used && fs_strcmp(files[i].parent_path, normalized) == 0) {
@ -1553,10 +1740,6 @@ int fat32_list_directory(const char *path, FAT32_FileInfo *entries, int max_entr
count++;
}
}
serial_write("[DEBUG] fat32_list_directory (RAMFS) found count: ");
extern void serial_write_num(uint32_t n);
serial_write_num(count);
serial_write("\n");
} else {
count = realfs_list_directory(drive, p, entries, max_entries);
}

View file

@ -468,6 +468,12 @@ static uint64_t syscall_handler_inner(uint64_t syscall_num, uint64_t arg1, uint6
const char *path = (const char *)arg2;
if (!path) return -1;
return fat32_delete(path) ? 0 : -1;
} else if (cmd == FS_CMD_GET_INFO) {
const char *path = (const char *)arg2;
FAT32_FileInfo *info = (FAT32_FileInfo *)arg3;
if (!path || !info) return -1;
extern int fat32_get_info(const char *path, FAT32_FileInfo *info);
return (uint64_t)fat32_get_info(path, info);
} else if (cmd == FS_CMD_MKDIR) {
const char *path = (const char *)arg2;
if (!path) return -1;

View file

@ -37,6 +37,7 @@ typedef struct registers_t registers_t;
#define FS_CMD_EXISTS 11
#define FS_CMD_GETCWD 12
#define FS_CMD_CHDIR 13
#define FS_CMD_GET_INFO 14
void syscall_init(void);
uint64_t syscall_handler_c(registers_t *regs);

View file

@ -4,33 +4,163 @@
#include <stdlib.h>
#include <syscall.h>
int main(int argc, char **argv) {
if (argc < 3) {
printf("Usage: cp <source> <dest>\n");
return 1;
typedef int bool;
#define true 1
#define false 0
void combine_path(char *dest, const char *path1, const char *path2) {
int i = 0;
while (path1[i]) {
dest[i] = path1[i];
i++;
}
if (i > 0 && dest[i-1] != '/') {
dest[i++] = '/';
}
int j = 0;
while (path2[j]) {
dest[i++] = path2[j++];
}
dest[i] = 0;
}
const char* get_basename(const char *path) {
const char *last_slash = NULL;
int len = 0;
while (path[len]) {
if (path[len] == '/') last_slash = path + len;
len++;
}
int fd_in = sys_open(argv[1], "r");
if (fd_in < 0) {
printf("Error: Cannot open source %s\n", argv[1]);
return 1;
if (!last_slash) return path;
// If it ends with a slash, skip it and find the previous one
if (last_slash[1] == '\0') {
if (len <= 1) return path; // root "/"
int i = len - 2;
while (i >= 0 && path[i] != '/') i--;
if (i < 0) return path;
return path + i + 1;
}
int fd_out = sys_open(argv[2], "w");
if (fd_out < 0) {
printf("Error: Cannot create destination %s\n", argv[2]);
return last_slash + 1;
}
void copy_recursive(const char *src, const char *dst) {
FAT32_FileInfo info;
if (sys_get_file_info(src, &info) < 0) {
printf("Error: Cannot get info for %s\n", src);
return;
}
if (info.is_directory) {
if (sys_mkdir(dst) < 0) {
// Might already exist
}
FAT32_FileInfo entries[64];
int count = sys_list(src, entries, 64);
for (int i = 0; i < count; i++) {
if (strcmp(entries[i].name, ".") == 0 || strcmp(entries[i].name, "..") == 0) continue;
char sub_src[512], sub_dst[512];
combine_path(sub_src, src, entries[i].name);
combine_path(sub_dst, dst, entries[i].name);
copy_recursive(sub_src, sub_dst);
}
} else {
int fd_in = sys_open(src, "r");
if (fd_in < 0) {
printf("Error: Cannot open source %s\n", src);
return;
}
int fd_out = sys_open(dst, "w");
if (fd_out < 0) {
printf("Error: Cannot create destination %s\n", dst);
sys_close(fd_in);
return;
}
char buffer[4096];
int bytes;
while ((bytes = sys_read(fd_in, buffer, sizeof(buffer))) > 0) {
sys_write_fs(fd_out, buffer, bytes);
}
sys_close(fd_in);
sys_close(fd_out);
}
}
int main(int argc, char **argv) {
bool recursive = false;
char *src_path = NULL;
char *dst_path = NULL;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-r") == 0) {
recursive = true;
} else if (!src_path) {
src_path = argv[i];
} else if (!dst_path) {
dst_path = argv[i];
}
}
if (!src_path || !dst_path) {
printf("Usage: cp [-r] <source> <dest>\n");
return 1;
}
char buffer[4096];
int bytes;
while ((bytes = sys_read(fd_in, buffer, sizeof(buffer))) > 0) {
sys_write_fs(fd_out, buffer, bytes);
FAT32_FileInfo info_src;
if (sys_get_file_info(src_path, &info_src) < 0) {
printf("Error: Source %s does not exist\n", src_path);
return 1;
}
if (info_src.is_directory && !recursive) {
printf("Error: %s is a directory (use -r to copy recursively)\n", src_path);
return 1;
}
char actual_dst[512];
FAT32_FileInfo info_dst;
if (sys_get_file_info(dst_path, &info_dst) == 0 && info_dst.is_directory) {
// If destination is a directory, copy INTO it
const char *base = get_basename(src_path);
// Clean up trailing slash from basename if any (get_basename handles it mostly)
char clean_base[256];
int k = 0;
while (base[k] && base[k] != '/') {
clean_base[k] = base[k];
k++;
}
clean_base[k] = 0;
combine_path(actual_dst, dst_path, clean_base);
} else {
strcpy(actual_dst, dst_path);
}
if (recursive) {
copy_recursive(src_path, actual_dst);
} else {
int fd_in = sys_open(src_path, "r");
if (fd_in < 0) {
printf("Error: Cannot open source %s\n", src_path);
return 1;
}
int fd_out = sys_open(actual_dst, "w");
if (fd_out < 0) {
printf("Error: Cannot create destination %s\n", actual_dst);
sys_close(fd_in);
return 1;
}
char buffer[4096];
int bytes;
while ((bytes = sys_read(fd_in, buffer, sizeof(buffer))) > 0) {
sys_write_fs(fd_out, buffer, bytes);
}
sys_close(fd_in);
sys_close(fd_out);
}
sys_close(fd_in);
sys_close(fd_out);
return 0;
}

View file

@ -109,6 +109,10 @@ int sys_list(const char *path, FAT32_FileInfo *entries, int max_entries) {
return (int)syscall4(SYS_FS, FS_CMD_LIST, (uint64_t)path, (uint64_t)entries, (uint64_t)max_entries);
}
int sys_get_file_info(const char *path, FAT32_FileInfo *info) {
return (int)syscall3(SYS_FS, FS_CMD_GET_INFO, (uint64_t)path, (uint64_t)info);
}
int sys_delete(const char *path) {
return (int)syscall2(SYS_FS, FS_CMD_DELETE, (uint64_t)path);
}

View file

@ -27,6 +27,7 @@
#define FS_CMD_EXISTS 11
#define FS_CMD_GETCWD 12
#define FS_CMD_CHDIR 13
#define FS_CMD_GET_INFO 14
// System Commands (via SYS_SYSTEM)
#define SYSTEM_CMD_SET_BG_COLOR 1
@ -100,6 +101,7 @@ typedef struct {
} FAT32_FileInfo;
int sys_list(const char *path, FAT32_FileInfo *entries, int max_entries);
int sys_get_file_info(const char *path, FAT32_FileInfo *info);
// Network API
typedef struct { uint8_t bytes[6]; } net_mac_address_t;

View file

@ -20,6 +20,24 @@ int main(int argc, char **argv) {
}
}
FAT32_FileInfo info;
if (sys_get_file_info(path, &info) < 0) {
sys_set_text_color(error_color);
printf("Error: Path '%s' does not exist\n", path);
sys_set_text_color(default_color);
return 1;
}
if (!info.is_directory) {
sys_set_text_color(file_color);
printf("[FILE] %s", info.name);
sys_set_text_color(size_color);
printf(" (%d bytes)\n", info.size);
sys_set_text_color(default_color);
printf("\nTotal: 1 items\n");
return 0;
}
FAT32_FileInfo entries[128];
int count = sys_list(path, entries, 128);

View file

@ -4,37 +4,125 @@
#include <stdlib.h>
#include <syscall.h>
void combine_path(char *dest, const char *path1, const char *path2) {
int i = 0;
while (path1[i]) {
dest[i] = path1[i];
i++;
}
if (i > 0 && dest[i-1] != '/') {
dest[i++] = '/';
}
int j = 0;
while (path2[j]) {
dest[i++] = path2[j++];
}
dest[i] = 0;
}
const char* get_basename(const char *path) {
const char *last_slash = NULL;
int len = 0;
while (path[len]) {
if (path[len] == '/') last_slash = path + len;
len++;
}
if (!last_slash) return path;
if (last_slash[1] == '\0') {
if (len <= 1) return path;
int i = len - 2;
while (i >= 0 && path[i] != '/') i--;
if (i < 0) return path;
return path + i + 1;
}
return last_slash + 1;
}
void copy_recursive(const char *src, const char *dst) {
FAT32_FileInfo info;
if (sys_get_file_info(src, &info) < 0) return;
if (info.is_directory) {
sys_mkdir(dst);
FAT32_FileInfo entries[64];
int count = sys_list(src, entries, 64);
for (int i = 0; i < count; i++) {
if (strcmp(entries[i].name, ".") == 0 || strcmp(entries[i].name, "..") == 0) continue;
char sub_src[512], sub_dst[512];
combine_path(sub_src, src, entries[i].name);
combine_path(sub_dst, dst, entries[i].name);
copy_recursive(sub_src, sub_dst);
}
} else {
int fd_in = sys_open(src, "r");
if (fd_in < 0) return;
int fd_out = sys_open(dst, "w");
if (fd_out < 0) { sys_close(fd_in); return; }
char buffer[4096];
int bytes;
while ((bytes = sys_read(fd_in, buffer, sizeof(buffer))) > 0) {
sys_write_fs(fd_out, buffer, bytes);
}
sys_close(fd_in);
sys_close(fd_out);
}
}
void delete_recursive(const char *path) {
FAT32_FileInfo info;
if (sys_get_file_info(path, &info) < 0) return;
if (info.is_directory) {
FAT32_FileInfo entries[64];
int count = sys_list(path, entries, 64);
for (int i = 0; i < count; i++) {
if (strcmp(entries[i].name, ".") == 0 || strcmp(entries[i].name, "..") == 0) continue;
char sub_path[512];
combine_path(sub_path, path, entries[i].name);
delete_recursive(sub_path);
}
sys_delete(path);
} else {
sys_delete(path);
}
}
int main(int argc, char **argv) {
if (argc < 3) {
printf("Usage: mv <source> <dest>\n");
return 1;
}
int fd_in = sys_open(argv[1], "r");
if (fd_in < 0) {
printf("Error: Cannot open source %s\n", argv[1]);
char *src_path = argv[1];
char *dst_path = argv[2];
FAT32_FileInfo info_src;
if (sys_get_file_info(src_path, &info_src) < 0) {
printf("Error: Cannot open source %s\n", src_path);
return 1;
}
int fd_out = sys_open(argv[2], "w");
if (fd_out < 0) {
printf("Error: Cannot create destination %s\n", argv[2]);
sys_close(fd_in);
return 1;
}
char buffer[4096];
int bytes;
while ((bytes = sys_read(fd_in, buffer, sizeof(buffer))) > 0) {
sys_write_fs(fd_out, buffer, bytes);
}
sys_close(fd_in);
sys_close(fd_out);
if (sys_delete(argv[1]) != 0) {
printf("Warning: Failed to delete source %s after copy\n", argv[1]);
char actual_dst[512];
FAT32_FileInfo info_dst;
if (sys_get_file_info(dst_path, &info_dst) == 0 && info_dst.is_directory) {
const char *base = get_basename(src_path);
char clean_base[256];
int k = 0;
while (base[k] && base[k] != '/') {
clean_base[k] = base[k];
k++;
}
clean_base[k] = 0;
combine_path(actual_dst, dst_path, clean_base);
} else {
strcpy(actual_dst, dst_path);
}
copy_recursive(src_path, actual_dst);
delete_recursive(src_path);
return 0;
}