diff --git a/.gitignore b/.gitignore index 7db5ec6..8420e88 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,3 @@ limine 2/Makefile limine 2/limine limine 2/limine.dSYM/Contents/Resources/DWARF/limine limine 2/limine.exe -disk.img \ No newline at end of file diff --git a/Makefile b/Makefile index 1c1f214..9302bf7 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,6 @@ ISO_DIR = iso_root KERNEL_ELF = $(BUILD_DIR)/brewos.elf ISO_IMAGE = brewos.iso -DISK_IMG = disk.img C_SOURCES = $(wildcard $(SRC_DIR)/*.c) CLI_APP_SOURCES = $(wildcard $(SRC_DIR)/cli_apps/*.c) @@ -38,7 +37,7 @@ LIMINE_URL_BASE = https://github.com/limine-bootloader/limine/raw/v$(LIMINE_VERS .PHONY: all clean run limine-setup -all: $(ISO_IMAGE) $(DISK_IMG) +all: $(ISO_IMAGE) # Ensure build directories exist $(BUILD_DIR): @@ -113,19 +112,10 @@ $(ISO_IMAGE): $(KERNEL_ELF) limine.cfg limine-setup # Install Limine to ISO (for BIOS boot) ./limine/limine bios-install $(ISO_IMAGE) -# Create 512MB FAT32 Disk Image -$(DISK_IMG): - @if [ ! -f $(DISK_IMG) ]; then \ - echo "Creating 512MB FAT32 disk image..."; \ - hdiutil create -size 512m -fs "MS-DOS FAT32" -layout NONE -type UDTO -o disk_temp; \ - mv disk_temp.cdr $(DISK_IMG); \ - fi - clean: - rm -rf $(BUILD_DIR) $(ISO_DIR) $(ISO_IMAGE) $(DISK_IMG) + rm -rf $(BUILD_DIR) $(ISO_DIR) $(ISO_IMAGE) -run: $(ISO_IMAGE) $(DISK_IMG) +run: $(ISO_IMAGE) qemu-system-x86_64 -m 2G -serial stdio -cdrom $(ISO_IMAGE) -boot d \ -audiodev coreaudio,id=audio0 -machine pcspk-audiodev=audio0 \ - -netdev user,id=net0,hostfwd=udp::12345-:12345 -device e1000,netdev=net0 \ - -drive file=$(DISK_IMG),format=raw,media=disk,index=1 + -netdev user,id=net0,hostfwd=udp::12345-:12345 -device e1000,netdev=net0 diff --git a/README.md b/README.md index 59dadbb..fbeb795 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Brew OS 1.40 Alpha +# Brew OS 1.20 Alpha ## Brewkernel is now BrewOS! Brewkernel will from now on be deprecated as it's core became too messy. I have built a less bloated kernel and wrote a DE above it, which is why it is now an OS instead of a kernel (in my opinion). @@ -9,8 +9,7 @@ Brew Kernel is a simple x86_64 hobbyist operating system. It features a DE (and WM), a FAT32 filesystem, customizable UI and much much more! ## Features --Disk saving -- Basic Networking Stack (UDP, TCP) +- Basic Networking Stack - Brew WM - Fat 32 FS - 64-bit long mode support diff --git a/brewos.iso b/brewos.iso index 8dfbf5f..79f39b4 100644 Binary files a/brewos.iso and b/brewos.iso differ diff --git a/build/about.o b/build/about.o index d896358..2481993 100644 Binary files a/build/about.o and b/build/about.o differ diff --git a/build/ata.o b/build/ata.o deleted file mode 100644 index df8464b..0000000 Binary files a/build/ata.o and /dev/null differ diff --git a/build/brewos.elf b/build/brewos.elf index fbc1d89..c33e912 100755 Binary files a/build/brewos.elf and b/build/brewos.elf differ diff --git a/build/calculator.o b/build/calculator.o index 8bd59ae..032a0a9 100644 Binary files a/build/calculator.o and b/build/calculator.o differ diff --git a/build/cli_apps/about.o b/build/cli_apps/about.o index 45fb4fc..19001a8 100644 Binary files a/build/cli_apps/about.o and b/build/cli_apps/about.o differ diff --git a/build/cli_apps/beep.o b/build/cli_apps/beep.o index af3a888..27522fa 100644 Binary files a/build/cli_apps/beep.o and b/build/cli_apps/beep.o differ diff --git a/build/cli_apps/blind.o b/build/cli_apps/blind.o index ce7040f..0b3e866 100644 Binary files a/build/cli_apps/blind.o and b/build/cli_apps/blind.o differ diff --git a/build/cli_apps/cc.o b/build/cli_apps/cc.o index 0508aff..3f0d347 100644 Binary files a/build/cli_apps/cc.o and b/build/cli_apps/cc.o differ diff --git a/build/cli_apps/clear.o b/build/cli_apps/clear.o index 93b8647..ff6ff00 100644 Binary files a/build/cli_apps/clear.o and b/build/cli_apps/clear.o differ diff --git a/build/cli_apps/cli_utils.o b/build/cli_apps/cli_utils.o index b0a0698..eb10a93 100644 Binary files a/build/cli_apps/cli_utils.o and b/build/cli_apps/cli_utils.o differ diff --git a/build/cli_apps/cowsay.o b/build/cli_apps/cowsay.o index 394f050..9f174a8 100644 Binary files a/build/cli_apps/cowsay.o and b/build/cli_apps/cowsay.o differ diff --git a/build/cli_apps/date.o b/build/cli_apps/date.o index 3d81c8c..58b1106 100644 Binary files a/build/cli_apps/date.o and b/build/cli_apps/date.o differ diff --git a/build/cli_apps/exit.o b/build/cli_apps/exit.o index 7bf49a1..64d31fc 100644 Binary files a/build/cli_apps/exit.o and b/build/cli_apps/exit.o differ diff --git a/build/cli_apps/fs_commands.o b/build/cli_apps/fs_commands.o index 36f89d8..9c32906 100644 Binary files a/build/cli_apps/fs_commands.o and b/build/cli_apps/fs_commands.o differ diff --git a/build/cli_apps/help.o b/build/cli_apps/help.o index 521e7fd..5a6069a 100644 Binary files a/build/cli_apps/help.o and b/build/cli_apps/help.o differ diff --git a/build/cli_apps/license.o b/build/cli_apps/license.o index f0c77af..2c9dad6 100644 Binary files a/build/cli_apps/license.o and b/build/cli_apps/license.o differ diff --git a/build/cli_apps/man.o b/build/cli_apps/man.o index 0affd3d..3470d6e 100644 Binary files a/build/cli_apps/man.o and b/build/cli_apps/man.o differ diff --git a/build/cli_apps/math.o b/build/cli_apps/math.o index 368dc97..b0e6922 100644 Binary files a/build/cli_apps/math.o and b/build/cli_apps/math.o differ diff --git a/build/cli_apps/memcmd.o b/build/cli_apps/memcmd.o index 5b519e3..254256b 100644 Binary files a/build/cli_apps/memcmd.o and b/build/cli_apps/memcmd.o differ diff --git a/build/cli_apps/meminfo.o b/build/cli_apps/meminfo.o index 4e8abd6..b639223 100644 Binary files a/build/cli_apps/meminfo.o and b/build/cli_apps/meminfo.o differ diff --git a/build/cli_apps/net.o b/build/cli_apps/net.o index 8d73995..c49162d 100644 Binary files a/build/cli_apps/net.o and b/build/cli_apps/net.o differ diff --git a/build/cli_apps/pci_list.o b/build/cli_apps/pci_list.o index c763bf7..df733a7 100644 Binary files a/build/cli_apps/pci_list.o and b/build/cli_apps/pci_list.o differ diff --git a/build/cli_apps/readtheman.o b/build/cli_apps/readtheman.o index 4756727..320bef1 100644 Binary files a/build/cli_apps/readtheman.o and b/build/cli_apps/readtheman.o differ diff --git a/build/cli_apps/reboot.o b/build/cli_apps/reboot.o index 30f00d2..2734c35 100644 Binary files a/build/cli_apps/reboot.o and b/build/cli_apps/reboot.o differ diff --git a/build/cli_apps/shutdown.o b/build/cli_apps/shutdown.o index 816d506..16fa3ce 100644 Binary files a/build/cli_apps/shutdown.o and b/build/cli_apps/shutdown.o differ diff --git a/build/cli_apps/txtedit.o b/build/cli_apps/txtedit.o index 90dc5e0..b3ad107 100644 Binary files a/build/cli_apps/txtedit.o and b/build/cli_apps/txtedit.o differ diff --git a/build/cli_apps/uptime.o b/build/cli_apps/uptime.o index f31e93b..e155568 100644 Binary files a/build/cli_apps/uptime.o and b/build/cli_apps/uptime.o differ diff --git a/build/cmd.o b/build/cmd.o index 10e8bff..ae4a6d9 100644 Binary files a/build/cmd.o and b/build/cmd.o differ diff --git a/build/control_panel.o b/build/control_panel.o index c73de00..b33233f 100644 Binary files a/build/control_panel.o and b/build/control_panel.o differ diff --git a/build/dns.o b/build/dns.o index 367ccb7..fccdc31 100644 Binary files a/build/dns.o and b/build/dns.o differ diff --git a/build/e1000.o b/build/e1000.o index d07f92f..efe2821 100644 Binary files a/build/e1000.o and b/build/e1000.o differ diff --git a/build/editor.o b/build/editor.o index 8c56a10..b2b2b1f 100644 Binary files a/build/editor.o and b/build/editor.o differ diff --git a/build/explorer.o b/build/explorer.o index 8546b00..7b522d1 100644 Binary files a/build/explorer.o and b/build/explorer.o differ diff --git a/build/fat32.o b/build/fat32.o index 0b853e1..9b608cc 100644 Binary files a/build/fat32.o and b/build/fat32.o differ diff --git a/build/graphics.o b/build/graphics.o index 1da4256..e063cc7 100644 Binary files a/build/graphics.o and b/build/graphics.o differ diff --git a/build/http.o b/build/http.o index c377d61..b6d5e81 100644 Binary files a/build/http.o and b/build/http.o differ diff --git a/build/icmp.o b/build/icmp.o index 365e546..0f25c43 100644 Binary files a/build/icmp.o and b/build/icmp.o differ diff --git a/build/idt.o b/build/idt.o index f4bec80..4f13af2 100644 Binary files a/build/idt.o and b/build/idt.o differ diff --git a/build/licensewr.o b/build/licensewr.o index b731e0d..48e9b82 100644 Binary files a/build/licensewr.o and b/build/licensewr.o differ diff --git a/build/main.o b/build/main.o index 115c4f8..3c87b9b 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/build/markdown.o b/build/markdown.o index 492a232..21e749e 100644 Binary files a/build/markdown.o and b/build/markdown.o differ diff --git a/build/memory_manager.o b/build/memory_manager.o index 717c032..efb2b26 100644 Binary files a/build/memory_manager.o and b/build/memory_manager.o differ diff --git a/build/minesweeper.o b/build/minesweeper.o index d07457d..afcb07c 100644 Binary files a/build/minesweeper.o and b/build/minesweeper.o differ diff --git a/build/network.o b/build/network.o index 8b348ba..b42e845 100644 Binary files a/build/network.o and b/build/network.o differ diff --git a/build/notepad.o b/build/notepad.o index c5cb440..30d99db 100644 Binary files a/build/notepad.o and b/build/notepad.o differ diff --git a/build/pci.o b/build/pci.o index 804b336..284b0aa 100644 Binary files a/build/pci.o and b/build/pci.o differ diff --git a/build/platform.o b/build/platform.o index c4e7752..e63f482 100644 Binary files a/build/platform.o and b/build/platform.o differ diff --git a/build/ps2.o b/build/ps2.o index c6ed361..f2832c9 100644 Binary files a/build/ps2.o and b/build/ps2.o differ diff --git a/build/rtc.o b/build/rtc.o index 685e094..88921b4 100644 Binary files a/build/rtc.o and b/build/rtc.o differ diff --git a/build/tcp.o b/build/tcp.o index e1f91d5..5509d88 100644 Binary files a/build/tcp.o and b/build/tcp.o differ diff --git a/build/vm.o b/build/vm.o index 627cbba..7a4f913 100644 Binary files a/build/vm.o and b/build/vm.o differ diff --git a/build/wm.o b/build/wm.o index 8a60e98..84b9702 100644 Binary files a/build/wm.o and b/build/wm.o differ diff --git a/iso_root/brewos.elf b/iso_root/brewos.elf index fbc1d89..c33e912 100755 Binary files a/iso_root/brewos.elf and b/iso_root/brewos.elf differ diff --git a/src/kernel/about.c b/src/kernel/about.c index fecd481..a3c3a3e 100644 --- a/src/kernel/about.c +++ b/src/kernel/about.c @@ -35,8 +35,8 @@ static void about_paint(Window *win) { // Version info draw_string(offset_x, offset_y + 105, "BrewOS", COLOR_BLACK); - draw_string(offset_x, offset_y + 120, "BrewOS Version 1.40", COLOR_BLACK); - draw_string(offset_x, offset_y + 135, "Kernel Version 2.4.0", COLOR_BLACK); + draw_string(offset_x, offset_y + 120, "BrewOS Version 1.30", COLOR_BLACK); + draw_string(offset_x, offset_y + 135, "Kernel Version 2.3.0", COLOR_BLACK); // Copyright draw_string(offset_x, offset_y + 150, "(C) 2026 boreddevnl.", COLOR_BLACK); diff --git a/src/kernel/ata.c b/src/kernel/ata.c deleted file mode 100644 index 298f4e3..0000000 --- a/src/kernel/ata.c +++ /dev/null @@ -1,124 +0,0 @@ -#include "ata.h" - -#define ATA_DATA 0x1F0 -#define ATA_ERROR 0x1F1 -#define ATA_SEC_CNT 0x1F2 -#define ATA_LBA_LO 0x1F3 -#define ATA_LBA_MID 0x1F4 -#define ATA_LBA_HI 0x1F5 -#define ATA_DRIVE_HEAD 0x1F6 -#define ATA_STATUS 0x1F7 -#define ATA_CMD 0x1F7 - -#define CMD_READ_PIO 0x20 -#define CMD_WRITE_PIO 0x30 -#define CMD_IDENTIFY 0xEC - -// IO Port Helpers -static inline void outb(uint16_t port, uint8_t val) { - __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port)); -} - -static inline uint8_t inb(uint16_t port) { - uint8_t ret; - __asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port)); - return ret; -} - -static inline void insw(uint16_t port, void *addr, uint32_t cnt) { - __asm__ volatile ("rep insw" : "+D"(addr), "+c"(cnt) : "d"(port) : "memory"); -} - -static inline void outsw(uint16_t port, const void *addr, uint32_t cnt) { - __asm__ volatile ("rep outsw" : "+S"(addr), "+c"(cnt) : "d"(port) : "memory"); -} - -static void ata_wait_bsy(void) { - while (inb(ATA_STATUS) & 0x80); -} - -static void ata_wait_drq(void) { - while (!(inb(ATA_STATUS) & 0x08)); -} - -// Select drive (0 = Master, 1 = Slave) -static void ata_select_drive(int drive) { - outb(ATA_DRIVE_HEAD, 0xE0 | (drive << 4)); - // Small delay - inb(ATA_STATUS); - inb(ATA_STATUS); - inb(ATA_STATUS); - inb(ATA_STATUS); -} - -bool ata_init(void) { - // Simple probe: Try to identify Primary Slave (where we put disk.img in QEMU index=1) - // Note: QEMU index=0 is usually the CDROM if -boot d is used, or Primary Master. - // We will try to read from the drive to verify it exists. - ata_select_drive(1); // Select Slave - outb(ATA_SEC_CNT, 0); - outb(ATA_LBA_LO, 0); - outb(ATA_LBA_MID, 0); - outb(ATA_LBA_HI, 0); - outb(ATA_CMD, CMD_IDENTIFY); - - uint8_t status = inb(ATA_STATUS); - if (status == 0) return false; // No drive - - // Poll until BSY clears - while(inb(ATA_STATUS) & 0x80); - - // Check for ATAPI signature (we don't want the CDROM) - if (inb(ATA_LBA_MID) != 0 || inb(ATA_LBA_HI) != 0) { - return false; // Not ATA - } - - // Read 256 words of identify data to clear buffer - uint16_t buffer[256]; - ata_wait_drq(); - insw(ATA_DATA, buffer, 256); - - return true; -} - -int ata_read_sectors(uint32_t lba, uint8_t count, void* buffer) { - ata_wait_bsy(); - ata_select_drive(1); // Always using Slave for storage - - outb(ATA_SEC_CNT, count); - outb(ATA_LBA_LO, (uint8_t)lba); - outb(ATA_LBA_MID, (uint8_t)(lba >> 8)); - outb(ATA_LBA_HI, (uint8_t)(lba >> 16)); - outb(ATA_DRIVE_HEAD, 0xE0 | (1 << 4) | ((lba >> 24) & 0x0F)); - outb(ATA_CMD, CMD_READ_PIO); - - uint16_t *buf = (uint16_t*)buffer; - for (int i = 0; i < count; i++) { - ata_wait_bsy(); - ata_wait_drq(); - insw(ATA_DATA, buf, 256); - buf += 256; - } - return 0; -} - -int ata_write_sectors(uint32_t lba, uint8_t count, const void* buffer) { - ata_wait_bsy(); - ata_select_drive(1); - - outb(ATA_SEC_CNT, count); - outb(ATA_LBA_LO, (uint8_t)lba); - outb(ATA_LBA_MID, (uint8_t)(lba >> 8)); - outb(ATA_LBA_HI, (uint8_t)(lba >> 16)); - outb(ATA_DRIVE_HEAD, 0xE0 | (1 << 4) | ((lba >> 24) & 0x0F)); - outb(ATA_CMD, CMD_WRITE_PIO); - - const uint16_t *buf = (const uint16_t*)buffer; - for (int i = 0; i < count; i++) { - ata_wait_bsy(); - ata_wait_drq(); - outsw(ATA_DATA, buf, 256); - buf += 256; - } - return 0; -} \ No newline at end of file diff --git a/src/kernel/ata.h b/src/kernel/ata.h deleted file mode 100644 index d8ff49b..0000000 --- a/src/kernel/ata.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once -#include -#include - -// Initialize ATA driver and find the FAT32 disk -bool ata_init(void); - -// Read/Write sectors (LBA28) -// Returns 0 on success, non-zero on error -int ata_read_sectors(uint32_t lba, uint8_t count, void* buffer); -int ata_write_sectors(uint32_t lba, uint8_t count, const void* buffer); \ No newline at end of file diff --git a/src/kernel/cli_apps/about.c b/src/kernel/cli_apps/about.c index 60c73cb..93df31c 100644 --- a/src/kernel/cli_apps/about.c +++ b/src/kernel/cli_apps/about.c @@ -2,6 +2,6 @@ void cli_cmd_brewver(char *args) { (void)args; - cli_write("BrewOS v1.40 Alpha\n"); - cli_write("BrewOS Kernel V2.4.0 Pre-Alpha\n"); + cli_write("BrewOS v1.30 Alpha\n"); + cli_write("BrewOS Kernel V2.3.0 Pre-Alpha\n"); } diff --git a/src/kernel/cli_apps/cc.c b/src/kernel/cli_apps/cc.c index e66e770..2cbcf31 100644 --- a/src/kernel/cli_apps/cc.c +++ b/src/kernel/cli_apps/cc.c @@ -618,21 +618,11 @@ static void program() { } void cli_cmd_cc(char *args) { - // Skip leading whitespace - while (args && *args == ' ') args++; - if (!args || !*args) { cmd_write("Usage: cc \n"); return; } - // Trim trailing whitespace - int len = cli_strlen(args); - while (len > 0 && (args[len-1] == ' ' || args[len-1] == '\t' || args[len-1] == '\n')) { - args[len-1] = 0; - len--; - } - FAT32_FileHandle *fh = fat32_open(args, "r"); if (!fh) { cmd_write("Error: Cannot open source file.\n"); @@ -646,8 +636,8 @@ void cli_cmd_cc(char *args) { return; } - int read_len = fat32_read(fh, source, MAX_SOURCE - 1); - source[read_len] = 0; + int len = fat32_read(fh, source, MAX_SOURCE - 1); + source[len] = 0; fat32_close(fh); lexer(source); diff --git a/src/kernel/cli_apps/fs_commands.c b/src/kernel/cli_apps/fs_commands.c index 0860b6a..f8bc464 100644 --- a/src/kernel/cli_apps/fs_commands.c +++ b/src/kernel/cli_apps/fs_commands.c @@ -210,9 +210,6 @@ void cli_cmd_echo(char *args) { } void cli_cmd_cat(char *args) { - // Skip leading whitespace - while (args && *args == ' ') args++; - if (!args || args[0] == 0) { cli_write("Usage: cat \n"); return; @@ -256,7 +253,7 @@ void cli_cmd_touch(char *args) { char filename[256]; int i = 0; - while (args[i] && args[i] != ' ' && args[i] != '\t' && args[i] != '\n') { + while (args[i] && args[i] != ' ' && args[i] != '\t') { filename[i] = args[i]; i++; } diff --git a/src/kernel/cmd.c b/src/kernel/cmd.c index faf7cfb..511fbf3 100644 --- a/src/kernel/cmd.c +++ b/src/kernel/cmd.c @@ -328,45 +328,6 @@ void pager_set_mode(void) { current_mode = MODE_PAGER; } -// Internal LS command to avoid stack overflow in external module -static void internal_cmd_ls(char *args) { - char path[256]; - if (args && *args) { - int i=0; - while(args[i] && i < 255) { path[i] = args[i]; i++; } - path[i] = 0; - } else { - path[0] = '.'; path[1] = 0; - } - - int max_files = 64; - FAT32_FileInfo *files = (FAT32_FileInfo*)kmalloc(max_files * sizeof(FAT32_FileInfo)); - if (!files) { - cmd_write("Error: Out of memory\n"); - return; - } - - int count = fat32_list_directory(path, files, max_files); - - for (int i = 0; i < count; i++) { - if (files[i].is_directory) { - cmd_write("[DIR] "); - } else { - cmd_write("[FILE] "); - } - - cmd_write(files[i].name); - if (!files[i].is_directory) { - cmd_write(" "); - cmd_write_int(files[i].size); - cmd_write("b"); - } - cmd_write("\n"); - } - - kfree(files); -} - // --- Commands (now delegated to cli_apps/) --- // Command dispatch table @@ -413,8 +374,8 @@ static const CommandEntry commands[] = { {"cd", cli_cmd_cd}, {"PWD", cli_cmd_pwd}, {"pwd", cli_cmd_pwd}, - {"LS", internal_cmd_ls}, - {"ls", internal_cmd_ls}, + {"LS", cli_cmd_ls}, + {"ls", cli_cmd_ls}, {"MKDIR", cli_cmd_mkdir}, {"mkdir", cli_cmd_mkdir}, {"RM", cli_cmd_rm}, @@ -934,14 +895,12 @@ void cmd_reset(void) { } static void create_test_files(void) { - if (!fat32_exists("Documents")) fat32_mkdir("Documents"); - if (!fat32_exists("Projects")) fat32_mkdir("Projects"); - if (!fat32_exists("Documents/Important")) fat32_mkdir("Documents/Important"); - if (!fat32_exists("Apps")) fat32_mkdir("Apps"); + fat32_mkdir("Documents"); + fat32_mkdir("Projects"); + fat32_mkdir("Documents/Important"); + fat32_mkdir("Apps"); - FAT32_FileHandle *fh; - // Always try to write README to ensure content exists (fixes empty file issue) - fh = fat32_open("README.md", "w"); + FAT32_FileHandle *fh = fat32_open("README.md", "w"); if (fh) { const char *content = "# Brew OS 1.01 Alpha\n\n" @@ -1033,8 +992,8 @@ static void create_test_files(void) { "The above attribution requirements are informational and intended to\n" "ensure proper credit is given. They do not alter or supersede the\n" "terms of the GNU General Public License (GPL), which governs this work.\n"; - fat32_write(fh, (void *)content, cmd_strlen(content)); - fat32_close(fh); + fat32_write(fh, (void *)content, cmd_strlen(content)); + fat32_close(fh); } fh = fat32_open("Apps/README.md", "w"); @@ -1042,7 +1001,7 @@ static void create_test_files(void) { const char *content = "# All compiled C files in this directory are openable from any other directory by typing in the name of the compiled file by typing in the name of the compiled file.\n\n" "The c file 'wordofgod.c' contains a C program similar to one in TempleOS, which Terry A. Davis (RIP) saw as 'words from god' telling him what to do with his kernel.\n" - "I made this file as a tribute to him, as he also inspired me to create this project in '24. If you want to run it you simply do cc (or compc) wordgod.c and then run ./wordgod \n"; + "I made this file as a tribute to him, as he also inspired me to create this project in '24. If you want to run it you simply do cc (or compc) wordofgod.c and then run ./wordofgod \n"; fat32_write(fh, (void *)content, cmd_strlen(content)); fat32_close(fh); } @@ -1065,60 +1024,74 @@ static void create_test_files(void) { fh = fat32_open("Apps/wordofgod.c", "w"); if (fh) { - // Buffer the entire file content to write in one go - // This prevents issues with multiple small writes causing truncation - char *buf = (char*)kmalloc(8192); - if (buf) { - int p = 0; - const char *strs[] = { - "int main(){int l;l=malloc(1200);", - "poke(l+0,\"In \");poke(l+4,\"the \");poke(l+8,\"beginning \");poke(l+12,\"God \");poke(l+16,\"created \");poke(l+20,\"heaven \");poke(l+24,\"and \");poke(l+28,\"earth \");poke(l+32,\"light \");poke(l+36,\"darkness \");", - "poke(l+40,\"day \");poke(l+44,\"night \");poke(l+48,\"waters \");poke(l+52,\"firmament \");poke(l+56,\"evening \");poke(l+60,\"morning \");poke(l+64,\"land \");poke(l+68,\"seas \");poke(l+72,\"grass \");poke(l+76,\"herb \");", - "poke(l+80,\"seed \");poke(l+84,\"fruit \");poke(l+88,\"tree \");poke(l+92,\"sun \");poke(l+96,\"moon \");poke(l+100,\"stars \");poke(l+104,\"signs \");poke(l+108,\"seasons \");poke(l+112,\"days \");poke(l+116,\"years \");", - "poke(l+120,\"creature \");poke(l+124,\"life \");poke(l+128,\"fowl \");poke(l+132,\"whales \");poke(l+136,\"cattle \");poke(l+140,\"creeping \");poke(l+144,\"beast \");poke(l+148,\"man \");poke(l+152,\"image \");poke(l+156,\"likeness \");", - "poke(l+160,\"dominion \");poke(l+164,\"fish \");poke(l+168,\"air \");poke(l+172,\"every \");poke(l+176,\"CIA \");poke(l+180,\"meat \");poke(l+184,\"holy \");poke(l+188,\"rest \");poke(l+192,\"dust \");poke(l+196,\"breath \");", - "poke(l+200,\"soul \");poke(l+204,\"garden \");poke(l+208,\"east \");poke(l+212,\"Eden \");poke(l+216,\"ground \");poke(l+220,\"sight \");poke(l+224,\"good \");poke(l+228,\"evil \");poke(l+232,\"river \");poke(l+236,\"gold \");", - "poke(l+240,\"stone \");poke(l+244,\"woman \");poke(l+248,\"wife \");poke(l+252,\"flesh \");poke(l+256,\"bone \");poke(l+260,\"naked \");poke(l+264,\"serpent \");poke(l+268,\"subtle \");poke(l+272,\"eat \");poke(l+276,\"eyes \");", - "poke(l+280,\"wise \");poke(l+284,\"cool \");poke(l+288,\"voice \");poke(l+292,\"fear \");poke(l+296,\"hid \");poke(l+300,\"cursed \");poke(l+304,\"belly \");poke(l+308,\"enmity \");poke(l+312,\"sorrow \");poke(l+316,\"conception \");", - "poke(l+320,\"children \");poke(l+324,\"desire \");poke(l+328,\"husband \");poke(l+332,\"thorns \");poke(l+336,\"thistles \");poke(l+340,\"sweat \");poke(l+344,\"bread \");poke(l+348,\"mother \");poke(l+352,\"skin \");poke(l+356,\"coats \");", - "poke(l+360,\"cherubims \");poke(l+364,\"sword \");poke(l+368,\"gate \");poke(l+372,\"offering \");poke(l+376,\"respect \");poke(l+380,\"sin \");poke(l+384,\"door \");poke(l+388,\"blood \");poke(l+392,\"brother \");poke(l+396,\"keeper \");", - "poke(l+400,\"voice \");poke(l+404,\"heard \");poke(l+408,\"walking \");poke(l+412,\"cool \");poke(l+416,\"day \");poke(l+420,\"where \");poke(l+424,\"art \");poke(l+428,\"thou \");poke(l+432,\"told \");poke(l+436,\"thee \");", - "poke(l+440,\"hast \");poke(l+444,\"eaten \");poke(l+448,\"tree \");poke(l+452,\"whereof \");poke(l+456,\"commanded \");poke(l+460,\"shouldest \");poke(l+464,\"not \");poke(l+468,\"eat \");poke(l+472,\"gave \");poke(l+476,\"me \");", - "poke(l+480,\"beguiled \");poke(l+484,\"belly \");poke(l+488,\"go \");poke(l+492,\"dust \");poke(l+496,\"shalt \");poke(l+500,\"eat \");poke(l+504,\"days \");poke(l+508,\"life \");poke(l+512,\"put \");poke(l+516,\"enmity \");", - "poke(l+520,\"between \");poke(l+524,\"seed \");poke(l+528,\"bruise \");poke(l+532,\"head \");poke(l+536,\"heel \");poke(l+540,\"multiply \");poke(l+544,\"sorrow \");poke(l+548,\"conception \");poke(l+552,\"forth \");poke(l+556,\"children \");", - "poke(l+560,\"desire \");poke(l+564,\"rule \");poke(l+568,\"over \");poke(l+572,\"sake \");poke(l+576,\"sweat \");poke(l+580,\"face \");poke(l+584,\"till \");poke(l+588,\"return \");poke(l+592,\"ground \");poke(l+596,\"taken \");", - "poke(l+600,\"mother \");poke(l+604,\"living \");poke(l+608,\"coats \");poke(l+612,\"skins \");poke(l+616,\"clothed \");poke(l+620,\"become \");poke(l+624,\"one \");poke(l+628,\"us \");poke(l+632,\"know \");poke(l+636,\"good \");", - "poke(l+640,\"evil \");poke(l+644,\"lest \");poke(l+648,\"put \");poke(l+652,\"hand \");poke(l+656,\"take \");poke(l+660,\"live \");poke(l+664,\"ever \");poke(l+668,\"sent \");poke(l+672,\"garden \");poke(l+676,\"eden \");", - "poke(l+680,\"flaming \");poke(l+684,\"sword \");poke(l+688,\"turned \");poke(l+692,\"way \");poke(l+696,\"knew \");poke(l+700,\"conceived \");poke(l+704,\"bare \");poke(l+708,\"cain \");poke(l+712,\"said \");poke(l+716,\"gotten \");", - "poke(l+720,\"lord \");poke(l+724,\"again \");poke(l+728,\"abel \");poke(l+732,\"sheep \");poke(l+736,\"tiller \");poke(l+740,\"process \");poke(l+744,\"time \");poke(l+748,\"pass \");poke(l+752,\"brought \");poke(l+756,\"fruit \");", - "poke(l+760,\"offering \");poke(l+764,\"firstlings \");poke(l+768,\"flock \");poke(l+772,\"fat \");poke(l+776,\"thereof \");poke(l+780,\"respect \");poke(l+784,\"wroth \");poke(l+788,\"countenance \");poke(l+792,\"fallen \");poke(l+796,\"well \");", - "poke(l+800,\"accepted \");poke(l+804,\"not \");poke(l+808,\"sin \");poke(l+812,\"lieth \");poke(l+816,\"door \");poke(l+820,\"unto \");poke(l+824,\"rule \");poke(l+828,\"talked \");poke(l+832,\"field \");poke(l+836,\"rose \");", - "poke(l+840,\"slew \");poke(l+844,\"done \");poke(l+848,\"crieth \");poke(l+852,\"mouth \");poke(l+856,\"receive \");poke(l+860,\"strength \");poke(l+864,\"fugitive \");poke(l+868,\"vagabond \");poke(l+872,\"punishment \");poke(l+876,\"greater \");", - "poke(l+880,\"bear \");poke(l+884,\"driven \");poke(l+888,\"hid \");poke(l+892,\"findeth \");poke(l+896,\"slay \");poke(l+900,\"vengeance \");poke(l+904,\"sevenfold \");poke(l+908,\"mark \");poke(l+912,\"finding \");poke(l+916,\"kill \");", - "poke(l+920,\"presence \");poke(l+924,\"dwelt \");poke(l+928,\"nod \");poke(l+932,\"enoch \");poke(l+936,\"city \");poke(l+940,\"irad \");poke(l+944,\"mehujael \");poke(l+948,\"methusael \");poke(l+952,\"lamech \");poke(l+956,\"adah \");", - "poke(l+960,\"zillah \");poke(l+964,\"jabal \");poke(l+968,\"tent \");poke(l+972,\"cattle \");poke(l+976,\"jubal \");poke(l+980,\"harp \");poke(l+984,\"organ \");poke(l+988,\"tubalcain \");poke(l+992,\"brass \");poke(l+996,\"iron \");", - "poke(l+1000,\"naamah \");poke(l+1004,\"wives \");poke(l+1008,\"hear \");poke(l+1012,\"speech \");poke(l+1016,\"hearken \");poke(l+1020,\"young \");poke(l+1024,\"hurt \");poke(l+1028,\"wounding \");poke(l+1032,\"avenged \");poke(l+1036,\"seventy \");", - "poke(l+1040,\"seth \");poke(l+1044,\"appointed \");poke(l+1048,\"enos \");poke(l+1052,\"began \");poke(l+1056,\"call \");poke(l+1060,\"name \");poke(l+1064,\"generations \");poke(l+1068,\"adam \");poke(l+1072,\"likeness \");poke(l+1076,\"blessed \");", - "poke(l+1080,\"begat \");poke(l+1084,\"sons \");poke(l+1088,\"daughters \");poke(l+1092,\"lived \");poke(l+1096,\"died \");poke(l+1100,\"cainan \");poke(l+1104,\"mahalaleel \");poke(l+1108,\"jared \");poke(l+1112,\"walked \");poke(l+1116,\"three \");", - "poke(l+1120,\"hundred \");poke(l+1124,\"sixty \");poke(l+1128,\"five \");poke(l+1132,\"methuselah \");poke(l+1136,\"lamech \");poke(l+1140,\"noah \");poke(l+1144,\"comfort \");poke(l+1148,\"work \");poke(l+1152,\"toil \");poke(l+1156,\"hands \");", - "poke(l+1160,\"shem \");poke(l+1164,\"ham \");poke(l+1168,\"japheth \");poke(l+1172,\"men \");poke(l+1176,\"daughters \");poke(l+1180,\"born \");poke(l+1184,\"fair \");poke(l+1188,\"chose \");poke(l+1192,\"spirit \");poke(l+1196,\"strive \");", - "int c;int r;r=abs(rand());r=r-(r/5)*5;c=14+r;int i;i=0;while(i @@ -279,9 +278,7 @@ static void explorer_set_folder_color(const char *folder_path, uint32_t color) { static void explorer_load_directory(const char *path) { explorer_strcpy(current_path, path); - FAT32_FileInfo *entries = (FAT32_FileInfo*)kmalloc(EXPLORER_MAX_FILES * sizeof(FAT32_FileInfo)); - if (!entries) return; - + FAT32_FileInfo entries[EXPLORER_MAX_FILES]; int count = fat32_list_directory(path, entries, EXPLORER_MAX_FILES); item_count = 0; @@ -309,7 +306,6 @@ static void explorer_load_directory(const char *path) { item_count++; } - kfree(entries); selected_item = -1; } diff --git a/src/kernel/fat32.c b/src/kernel/fat32.c index 6b752a2..2b5c6f9 100644 --- a/src/kernel/fat32.c +++ b/src/kernel/fat32.c @@ -1,28 +1,37 @@ #include "fat32.h" -#include "ata.h" -#include "memory_manager.h" #include #include -#include -// === Disk-based FAT32 Implementation === +// === Memory-based FAT32 Implementation === +// This is a simplified FAT32 for the OS kernel +// It allocates everything in RAM instead of using a real disk +#define MAX_FILES 256 +#define MAX_CLUSTERS 1024 #define MAX_OPEN_HANDLES 32 -#define SECTOR_SIZE 512 -// Globals -static uint32_t fat_start_lba; -static uint32_t data_start_lba; -static uint32_t sectors_per_cluster; -static uint32_t sectors_per_fat; -static uint32_t root_cluster; -static uint32_t bytes_per_cluster; -static uint32_t total_clusters; +// In-memory FAT table +static uint32_t fat_table[MAX_CLUSTERS]; +static uint8_t cluster_data[MAX_CLUSTERS][FAT32_CLUSTER_SIZE]; +// File/Directory tracking +typedef struct { + char full_path[FAT32_MAX_PATH]; + char filename[FAT32_MAX_FILENAME]; + uint32_t start_cluster; + uint32_t size; + uint32_t attributes; + bool used; + char parent_path[FAT32_MAX_PATH]; +} FileEntry; + +static FileEntry files[MAX_FILES]; +static uint32_t next_cluster = 3; // Start after reserved clusters 0, 1, 2 static FAT32_FileHandle open_handles[MAX_OPEN_HANDLES]; static char current_dir[FAT32_MAX_PATH] = "/"; // === Helper Functions === + static size_t fs_strlen(const char *str) { size_t len = 0; while (str[len]) len++; @@ -42,44 +51,61 @@ static int fs_strcmp(const char *s1, const char *s2) { return *(const unsigned char*)s1 - *(const unsigned char*)s2; } -static int fs_toupper(char c) { - if (c >= 'a' && c <= 'z') return c - 32; - return c; -} - -static int fs_strcasecmp(const char *s1, const char *s2) { - while (*s1 && fs_toupper(*s1) == fs_toupper(*s2)) { - s1++; - s2++; - } - return (unsigned char)fs_toupper(*s1) - (unsigned char)fs_toupper(*s2); -} - -static void fs_memset(void *dest, int val, size_t len) { - uint8_t *ptr = (uint8_t*)dest; - while (len--) *ptr++ = (uint8_t)val; -} - -static void fs_memcpy(void *dest, const void *src, size_t len) { - uint8_t *d = (uint8_t*)dest; - const uint8_t *s = (const uint8_t*)src; - while (len--) *d++ = *s++; -} - -static int fs_memcmp(const void *ptr1, const void *ptr2, size_t num) { - const unsigned char *p1 = (const unsigned char *)ptr1; - const unsigned char *p2 = (const unsigned char *)ptr2; - for (size_t i = 0; i < num; i++) { - if (p1[i] != p2[i]) return p1[i] - p2[i]; - } - return 0; -} - static void fs_strcat(char *dest, const char *src) { while (*dest) dest++; fs_strcpy(dest, src); } +static bool fs_ends_with(const char *str, const char *suffix) { + int str_len = fs_strlen(str); + int suffix_len = fs_strlen(suffix); + if (suffix_len > str_len) return false; + return fs_strcmp(str + str_len - suffix_len, suffix) == 0; +} + +// Extract filename from path +static void extract_filename(const char *path, char *filename) { + int len = fs_strlen(path); + int i = len - 1; + + // Skip trailing slashes + while (i > 0 && path[i] == '/') i--; + + // Find last slash + int start = i; + while (start >= 0 && path[start] != '/') start--; + start++; + + // Copy filename + int j = 0; + for (int k = start; k <= i; k++) { + filename[j++] = path[k]; + } + filename[j] = 0; +} + +// Extract parent path +static void extract_parent_path(const char *path, char *parent) { + int len = fs_strlen(path); + int i = len - 1; + + // Skip trailing slashes + while (i > 0 && path[i] == '/') i--; + + // Find last slash + while (i > 0 && path[i] != '/') i--; + + if (i == 0) { + parent[0] = '/'; + parent[1] = 0; + } else { + for (int j = 0; j < i; j++) { + parent[j] = path[j]; + } + parent[i] = 0; + } +} + // Normalize path (remove .., ., etc) void fat32_normalize_path(const char *path, char *normalized) { char temp[FAT32_MAX_PATH]; @@ -141,6 +167,29 @@ void fat32_normalize_path(const char *path, char *normalized) { fs_strcpy(normalized, temp); } +// Find file entry by path +static FileEntry* find_file(const char *path) { + char normalized[FAT32_MAX_PATH]; + fat32_normalize_path(path, normalized); + + for (int i = 0; i < MAX_FILES; i++) { + if (files[i].used && fs_strcmp(files[i].full_path, normalized) == 0) { + return &files[i]; + } + } + return NULL; +} + +// Find first unused file entry +static FileEntry* find_free_entry(void) { + for (int i = 0; i < MAX_FILES; i++) { + if (!files[i].used) { + return &files[i]; + } + } + return NULL; +} + // Find free handle static FAT32_FileHandle* find_free_handle(void) { for (int i = 0; i < MAX_OPEN_HANDLES; i++) { @@ -151,615 +200,101 @@ static FAT32_FileHandle* find_free_handle(void) { return NULL; } -// === Disk Access Helpers === - -static uint32_t cluster_to_lba(uint32_t cluster) { - return data_start_lba + (cluster - 2) * sectors_per_cluster; -} - -static uint32_t get_fat_entry(uint32_t cluster) { - uint32_t sector = fat_start_lba + (cluster * 4) / SECTOR_SIZE; - uint32_t offset = (cluster * 4) % SECTOR_SIZE; - - uint8_t buf[SECTOR_SIZE]; - ata_read_sectors(sector, 1, buf); - - uint32_t entry = *(uint32_t*)&buf[offset]; - return entry & 0x0FFFFFFF; -} - -static void set_fat_entry(uint32_t cluster, uint32_t value) { - uint32_t sector = fat_start_lba + (cluster * 4) / SECTOR_SIZE; - uint32_t offset = (cluster * 4) % SECTOR_SIZE; - - uint8_t buf[SECTOR_SIZE]; - ata_read_sectors(sector, 1, buf); - - *(uint32_t*)&buf[offset] = (value & 0x0FFFFFFF); - - // Write to FAT1 - ata_write_sectors(sector, 1, buf); - - // Write to FAT2 (Mirroring) - ata_write_sectors(sector + sectors_per_fat, 1, buf); -} - -static uint32_t find_free_cluster(void) { - // Start searching from cluster 3 (2 is root usually) - // Simple linear search - for (uint32_t i = 3; i < total_clusters; i++) { - if (get_fat_entry(i) == 0) { - return i; - } - } - return 0; // Disk full -} - -static void clear_cluster(uint32_t cluster) { - uint8_t zeros[SECTOR_SIZE] = {0}; - uint32_t lba = cluster_to_lba(cluster); - for (uint32_t i = 0; i < sectors_per_cluster; i++) { - ata_write_sectors(lba + i, 1, zeros); - } -} - -// Convert 8.3 name to string -static void fat_name_to_str(const char *name, const char *ext, uint8_t nt_res, char *dest) { - int i, j = 0; - bool name_lower = (nt_res & 0x08) != 0; - bool ext_lower = (nt_res & 0x10) != 0; - - for (i = 0; i < 8 && name[i] != ' '; i++) { - char c = name[i]; - if (name_lower && c >= 'A' && c <= 'Z') c += 32; - dest[j++] = c; - } - if (ext[0] != ' ') { - dest[j++] = '.'; - for (i = 0; i < 3 && ext[i] != ' '; i++) { - char c = ext[i]; - if (ext_lower && c >= 'A' && c <= 'Z') c += 32; - dest[j++] = c; - } - } - dest[j] = 0; -} - -// Convert string to 8.3 name -static void str_to_fat_name(const char *str, char *name, char *ext, uint8_t *nt_res) { - // Pad with spaces - for(int i=0; i<8; i++) name[i] = ' '; - for(int i=0; i<3; i++) ext[i] = ' '; - - *nt_res = 0; - bool all_lower_name = true; - bool all_lower_ext = true; - bool has_ext = false; - - int i = 0; - int j = 0; - - // Copy name - while(str[i] && str[i] != '.' && j < 8) { - char c = str[i++]; - if (c >= 'A' && c <= 'Z') all_lower_name = false; - if (c >= 'a' && c <= 'z') c -= 32; - name[j++] = c; - } - - // Skip to extension - while(str[i] && str[i] != '.') { - if (str[i] >= 'A' && str[i] <= 'Z') all_lower_name = false; - i++; - } - - if(str[i] == '.') { - has_ext = true; - i++; - j = 0; - while(str[i] && j < 3) { - char c = str[i++]; - if (c >= 'A' && c <= 'Z') all_lower_ext = false; - if (c >= 'a' && c <= 'z') c -= 32; - ext[j++] = c; - } - } - - if (all_lower_name) *nt_res |= 0x08; - if (all_lower_ext && has_ext) *nt_res |= 0x10; -} - -typedef struct { - uint8_t order; - uint16_t name1[5]; - uint8_t attr; - uint8_t type; - uint8_t checksum; - uint16_t name2[6]; - uint16_t zero; - uint16_t name3[2]; -} __attribute__((packed)) FAT32_LFNEntry; - -static void extract_lfn_part(FAT32_LFNEntry *lfn, char *buffer) { - int idx = 0; - for(int i=0; i<5; i++) { - uint16_t c = lfn->name1[i]; - if (c == 0) { buffer[idx] = 0; return; } - if (c < 128) buffer[idx++] = (char)c; - else buffer[idx++] = '?'; - } - for(int i=0; i<6; i++) { - uint16_t c = lfn->name2[i]; - if (c == 0) { buffer[idx] = 0; return; } - if (c < 128) buffer[idx++] = (char)c; - else buffer[idx++] = '?'; - } - for(int i=0; i<2; i++) { - uint16_t c = lfn->name3[i]; - if (c == 0) { buffer[idx] = 0; return; } - if (c < 128) buffer[idx++] = (char)c; - else buffer[idx++] = '?'; - } - buffer[idx] = 0; -} - -// Calculate checksum for LFN -static uint8_t lfn_checksum(const uint8_t *short_name) { - uint8_t sum = 0; - for (int i = 0; i < 11; i++) { - sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + short_name[i]; - } - return sum; -} - -// Check if a character is valid for a strict 8.3 Short File Name -static bool is_valid_sfn_char(char c) { - if (c >= 'A' && c <= 'Z') return true; - if (c >= '0' && c <= '9') return true; - // Standard allowed special chars in SFN - if (c == ' ' || c == '$' || c == '%' || c == '-' || c == '_' || c == '@' || - c == '~' || c == '`' || c == '!' || c == '(' || c == ')' || c == '{' || - c == '}' || c == '^' || c == '#' || c == '&') return true; - return false; -} - -// Determine if a filename requires LFN entries -static bool needs_lfn(const char *name) { - int len = fs_strlen(name); - if (len > 12) return true; // Exceeds 8.3 length - - int dot_pos = -1; - for (int i = 0; i < len; i++) { - if (name[i] == '.') { - if (dot_pos != -1) return true; // More than one dot - dot_pos = i; - } else { - if (!is_valid_sfn_char(name[i])) return true; // Invalid char (including lowercase) - } - } - - if (dot_pos == -1) { - if (len > 8) return true; - } else { - if (dot_pos > 8) return true; // Name part > 8 - if (len - dot_pos - 1 > 3) return true; // Ext part > 3 - } - - return false; -} - -// Check if a specific SFN exists in the directory (to avoid collisions) -static bool sfn_exists(uint32_t dir_cluster, const char *sfn_name, const char *sfn_ext) { - uint32_t current_cluster = dir_cluster; - uint8_t *buf = (uint8_t*)kmalloc(bytes_per_cluster); - if (!buf) return false; - - while (current_cluster >= 2 && current_cluster < 0x0FFFFFF8) { - uint32_t lba = cluster_to_lba(current_cluster); - ata_read_sectors(lba, sectors_per_cluster, buf); - - int entries_per_cluster = bytes_per_cluster / sizeof(FAT32_DirEntry); - FAT32_DirEntry *entries = (FAT32_DirEntry*)buf; - - for (int i = 0; i < entries_per_cluster; i++) { - if (entries[i].filename[0] == 0) { kfree(buf); return false; } - if (entries[i].filename[0] == 0xE5) continue; - if (entries[i].attributes == 0x0F) continue; - - if (fs_memcmp(entries[i].filename, sfn_name, 8) == 0 && - fs_memcmp(entries[i].extension, sfn_ext, 3) == 0) { - kfree(buf); - return true; - } - } - current_cluster = get_fat_entry(current_cluster); - } - kfree(buf); - return false; -} - -// Generate a unique SFN (e.g., FILE~1, FILE~2) -static void generate_unique_sfn(uint32_t dir_cluster, const char *long_name, char *out_name, char *out_ext) { - // 1. Create Basis: Uppercase, skip dots/spaces, max 6 chars - char basis[7]; - int bi = 0; - for (int i = 0; long_name[i] && bi < 6; i++) { - char c = long_name[i]; - if (c == '.') break; // Stop at extension - if (c != ' ') { - if (c >= 'a' && c <= 'z') c -= 32; - basis[bi++] = c; - } - } - basis[bi] = 0; - - // 2. Extract Extension: Uppercase, max 3 chars - char ext[4] = " "; - const char *dot = long_name; - while (*dot && *dot != '.') dot++; - if (*dot == '.') { - dot++; - int ei = 0; - while (dot[ei] && ei < 3) { - char c = dot[ei]; - if (c >= 'a' && c <= 'z') c -= 32; - ext[ei] = c; - ei++; - } - } - - // 3. Try numeric tails ~1 to ~9 (and beyond if needed, simplified to ~9 for now) - for (int i = 1; i <= 9; i++) { - fs_memset(out_name, ' ', 8); - fs_memset(out_ext, ' ', 3); - - // Copy basis - for(int k=0; k= 2 && current_cluster < 0x0FFFFFF8) { - uint32_t lba = cluster_to_lba(current_cluster); - ata_read_sectors(lba, sectors_per_cluster, buf); - - int entries_per_cluster = bytes_per_cluster / sizeof(FAT32_DirEntry); - FAT32_DirEntry *entries = (FAT32_DirEntry*)buf; - - char lfn_name[256]; - fs_memset(lfn_name, 0, 256); - bool has_lfn = false; - - for (int i = 0; i < entries_per_cluster; i++) { - if (entries[i].filename[0] == 0) { kfree(buf); return false; } // End of dir - if (entries[i].filename[0] == 0xE5) { has_lfn = false; continue; } // Deleted - - if (entries[i].attributes == 0x0F) { - FAT32_LFNEntry *lfn = (FAT32_LFNEntry*)&entries[i]; - if (lfn->order & 0x40) { - fs_memset(lfn_name, 0, 256); - has_lfn = true; - } - if (has_lfn) { - int order = lfn->order & 0x3F; - char part[14]; - extract_lfn_part(lfn, part); - int pos = (order - 1) * 13; - if (pos < 255) { - int part_len = fs_strlen(part); - for(int k=0; kattributes = ATTR_DIRECTORY; - entry->start_cluster_low = root_cluster & 0xFFFF; - entry->start_cluster_high = root_cluster >> 16; - return true; - } - - char *p = normalized; - if (*p == '/') p++; - - while (*p) { - char component[256]; - int i = 0; - while (*p && *p != '/' && i < 255) component[i++] = *p++; - component[i] = 0; - if (*p == '/') p++; - - if (!find_in_directory(current_cluster, component, entry, NULL, NULL)) { - return false; - } - - if (*p) { - if (!(entry->attributes & ATTR_DIRECTORY)) return false; - current_cluster = (entry->start_cluster_high << 16) | entry->start_cluster_low; - } - } - return true; -} - -// Create a new entry in a directory -static bool create_entry(uint32_t dir_cluster, const char *name, uint8_t attributes, uint32_t *created_cluster) { - FAT32_DirEntry new_entry; - // Prepare entry - fs_memset(&new_entry, 0, sizeof(FAT32_DirEntry)); - new_entry.attributes = attributes; - - bool need_lfn = needs_lfn(name); - int name_len = fs_strlen(name); - - if (need_lfn) { - // Generate unique SFN (e.g. FILE~1) - char sfn_name[8], sfn_ext[3]; - generate_unique_sfn(dir_cluster, name, sfn_name, sfn_ext); - - fs_memcpy(new_entry.filename, sfn_name, 8); - fs_memcpy(new_entry.extension, sfn_ext, 3); - new_entry.reserved = 0; // No NT case flags for SFN when LFN exists - } else { - // Fits in 8.3, use standard conversion - str_to_fat_name(name, (char*)new_entry.filename, (char*)new_entry.extension, &new_entry.reserved); - } - - // Allocate a cluster for the file content (if not empty file) - // For now, we start with 0 size and 0 cluster - new_entry.start_cluster_high = 0; - new_entry.start_cluster_low = 0; - new_entry.file_size = 0; - - if (attributes & ATTR_DIRECTORY) { - uint32_t clus = find_free_cluster(); - if (clus == 0) return false; - set_fat_entry(clus, 0x0FFFFFFF); - clear_cluster(clus); - new_entry.start_cluster_high = (clus >> 16); - new_entry.start_cluster_low = (clus & 0xFFFF); - if (created_cluster) *created_cluster = clus; - } - - // Calculate LFN entries needed - int lfn_count = 0; - if (need_lfn) { - lfn_count = (name_len + 12) / 13; - } - int entries_needed = 1 + lfn_count; - - // Find free slot in directory - uint32_t current_cluster = dir_cluster; - uint8_t *buf = (uint8_t*)kmalloc(bytes_per_cluster); - if (!buf) return false; - - while (true) { - uint32_t lba = cluster_to_lba(current_cluster); - ata_read_sectors(lba, sectors_per_cluster, buf); - - FAT32_DirEntry *entries = (FAT32_DirEntry*)buf; - int entries_per_cluster = bytes_per_cluster / sizeof(FAT32_DirEntry); - - for (int i = 0; i < entries_per_cluster; i++) { - // Check if we have 'entries_needed' contiguous free slots - bool found = true; - if (i + entries_needed > entries_per_cluster) { - found = false; // Split across clusters not implemented for simplicity - } else { - for (int k = 0; k < entries_needed; k++) { - if (entries[i+k].filename[0] != 0 && entries[i+k].filename[0] != 0xE5) { - found = false; - break; - } - } - } - - if (found) { - // Write LFN entries first (in reverse order) - if (need_lfn) { - uint8_t checksum = lfn_checksum(new_entry.filename); - for (int k = 0; k < lfn_count; k++) { - FAT32_LFNEntry *lfn = (FAT32_LFNEntry*)&entries[i + lfn_count - 1 - k]; - fs_memset(lfn, 0, sizeof(FAT32_LFNEntry)); - - lfn->order = (k + 1) | (k == lfn_count - 1 ? 0x40 : 0); - lfn->attr = 0x0F; - lfn->type = 0; - lfn->checksum = checksum; - - int char_idx = k * 13; - // Name 1 (5 chars) - for(int m=0; m<5; m++) { - if (char_idx < name_len) lfn->name1[m] = (uint8_t)name[char_idx++]; - else if (char_idx == name_len) { lfn->name1[m] = 0; char_idx++; } - else lfn->name1[m] = 0xFFFF; - } - // Name 2 (6 chars) - for(int m=0; m<6; m++) { - if (char_idx < name_len) lfn->name2[m] = (uint8_t)name[char_idx++]; - else if (char_idx == name_len) { lfn->name2[m] = 0; char_idx++; } - else lfn->name2[m] = 0xFFFF; - } - // Name 3 (2 chars) - for(int m=0; m<2; m++) { - if (char_idx < name_len) lfn->name3[m] = (uint8_t)name[char_idx++]; - else if (char_idx == name_len) { lfn->name3[m] = 0; char_idx++; } - else lfn->name3[m] = 0xFFFF; - } - } - } - entries[i + lfn_count] = new_entry; - ata_write_sectors(lba, sectors_per_cluster, buf); - kfree(buf); - return true; - } - } - - uint32_t next = get_fat_entry(current_cluster); - if (next >= 0x0FFFFFF8) { - // Extend directory - uint32_t new_clus = find_free_cluster(); - if (new_clus == 0) { kfree(buf); return false; } - set_fat_entry(current_cluster, new_clus); - set_fat_entry(new_clus, 0x0FFFFFFF); - clear_cluster(new_clus); - current_cluster = new_clus; - } else { - current_cluster = next; - } - } +// Allocate cluster +static uint32_t allocate_cluster(void) { + if (next_cluster >= MAX_CLUSTERS) return 0; + uint32_t cluster = next_cluster++; + fat_table[cluster] = 0xFFFFFFFF; // End of chain + return cluster; } // === Public API === void fat32_init(void) { - if (!ata_init()) { - // Fallback or panic if no disk found - return; + // Initialize FAT table + for (int i = 0; i < MAX_CLUSTERS; i++) { + fat_table[i] = 0; + } + fat_table[0] = 0xFFFFFFF8; // Media descriptor + fat_table[1] = 0xFFFFFFFF; // Bad sector marker + + // Create root directory entry + FileEntry *root = find_free_entry(); + if (root) { + root->used = true; + root->filename[0] = 0; + fs_strcpy(root->full_path, "/"); + root->start_cluster = 2; // Root cluster + root->size = 0; + root->attributes = ATTR_DIRECTORY; + fat_table[2] = 0xFFFFFFFF; // Root is EOF } - uint8_t buf[SECTOR_SIZE]; - ata_read_sectors(0, 1, buf); - - FAT32_BootSector *bpb = (FAT32_BootSector*)buf; - - // Basic BPB parsing - fat_start_lba = bpb->reserved_sectors; - sectors_per_cluster = bpb->sectors_per_cluster; - sectors_per_fat = bpb->sectors_per_fat_32; - root_cluster = bpb->root_cluster; - data_start_lba = fat_start_lba + (bpb->num_fats * bpb->sectors_per_fat_32); - bytes_per_cluster = sectors_per_cluster * SECTOR_SIZE; - total_clusters = bpb->total_sectors_32 / sectors_per_cluster; + next_cluster = 3; + current_dir[0] = '/'; + current_dir[1] = 0; } FAT32_FileHandle* fat32_open(const char *path, const char *mode) { - FAT32_DirEntry entry; - uint32_t dir_sector = 0, dir_offset = 0; - - // We need to find the entry AND its location on disk char normalized[FAT32_MAX_PATH]; fat32_normalize_path(path, normalized); - // Split path into parent and filename - char parent_path[FAT32_MAX_PATH]; - char filename[256]; - int len = fs_strlen(normalized); - int split = len; - while(split > 0 && normalized[split] != '/') split--; + FileEntry *entry = find_file(normalized); - if (split == 0) { - fs_strcpy(parent_path, "/"); - fs_strcpy(filename, normalized + (normalized[0] == '/' ? 1 : 0)); - } else { - for(int i=0; iattributes & ATTR_DIRECTORY)) { + return NULL; // File not found or is directory + } + } else if (mode[0] == 'w' || (mode[0] == 'a')) { + // Write/append mode - create if not exists + if (!entry) { + entry = find_free_entry(); + if (!entry) return NULL; + + entry->used = true; + fs_strcpy(entry->full_path, normalized); + extract_filename(normalized, entry->filename); + extract_parent_path(normalized, entry->parent_path); + entry->start_cluster = allocate_cluster(); + if (!entry->start_cluster) return NULL; + entry->size = 0; + entry->attributes = 0; // Regular file + } + + if (mode[0] == 'w') { + entry->size = 0; // Truncate + } } // Find free handle FAT32_FileHandle *handle = find_free_handle(); if (!handle) return NULL; - uint32_t start_cluster = (entry.start_cluster_high << 16) | entry.start_cluster_low; - handle->valid = true; - handle->cluster = start_cluster; - handle->start_cluster = start_cluster; + handle->cluster = entry->start_cluster; + handle->start_cluster = entry->start_cluster; handle->position = 0; - handle->size = entry.file_size; - handle->dir_sector = dir_sector; - handle->dir_offset = dir_offset; + handle->size = entry->size; if (mode[0] == 'r') { handle->mode = 0; } else if (mode[0] == 'w') { handle->mode = 1; - handle->size = 0; // Truncate logic would go here - // Note: We should update the size on disk to 0 here, but we do it on write/close } else { handle->mode = 2; // append - handle->position = entry.file_size; - // Fast forward cluster + handle->position = entry->size; + + // Walk to the correct cluster for the current position + uint32_t current_cluster = handle->start_cluster; uint32_t pos = 0; - while (pos + bytes_per_cluster <= handle->position) { - uint32_t next = get_fat_entry(handle->cluster); - if (next >= 0x0FFFFFF8) break; - handle->cluster = next; - pos += bytes_per_cluster; + while (pos + FAT32_CLUSTER_SIZE <= handle->position) { + uint32_t next = fat_table[current_cluster]; + if (next >= 0xFFFFFFF8) break; + current_cluster = next; + pos += FAT32_CLUSTER_SIZE; } + handle->cluster = current_cluster; } return handle; @@ -780,33 +315,32 @@ int fat32_read(FAT32_FileHandle *handle, void *buffer, int size) { uint8_t *buf = (uint8_t *)buffer; while (bytes_read < size && handle->position < handle->size) { - uint32_t offset_in_cluster = handle->position % bytes_per_cluster; + uint32_t offset_in_cluster = handle->position % FAT32_CLUSTER_SIZE; int to_read = size - bytes_read; int available = handle->size - handle->position; if (to_read > available) { to_read = available; } - if ((uint32_t)to_read > bytes_per_cluster - offset_in_cluster) { - to_read = bytes_per_cluster - offset_in_cluster; + if (to_read > FAT32_CLUSTER_SIZE - offset_in_cluster) { + to_read = FAT32_CLUSTER_SIZE - offset_in_cluster; } - // Read whole cluster to temp buffer (inefficient but simple) - uint8_t *cluster_buf = (uint8_t*)kmalloc(bytes_per_cluster); - if (!cluster_buf) return -1; - ata_read_sectors(cluster_to_lba(handle->cluster), sectors_per_cluster, cluster_buf); + if (handle->cluster >= MAX_CLUSTERS) { + break; + } + uint8_t *src = cluster_data[handle->cluster] + offset_in_cluster; for (int i = 0; i < to_read; i++) { - buf[bytes_read + i] = cluster_buf[offset_in_cluster + i]; + buf[bytes_read + i] = src[i]; } - kfree(cluster_buf); bytes_read += to_read; handle->position += to_read; // Move to next cluster if needed - if (handle->position % bytes_per_cluster == 0 && handle->position < handle->size) { - handle->cluster = get_fat_entry(handle->cluster); + if (handle->position % FAT32_CLUSTER_SIZE == 0 && handle->position < handle->size) { + handle->cluster = fat_table[handle->cluster]; } } @@ -814,73 +348,65 @@ int fat32_read(FAT32_FileHandle *handle, void *buffer, int size) { } int fat32_write(FAT32_FileHandle *handle, const void *buffer, int size) { - if (!handle || !handle->valid || handle->mode == 0) return -1; - - const uint8_t *buf = (const uint8_t*)buffer; + if (!handle || !handle->valid || (handle->mode != 1 && handle->mode != 2)) { + return -1; + } + int bytes_written = 0; - - // Allocate first cluster if needed - if (handle->cluster == 0) { - uint32_t new_clus = find_free_cluster(); - if (new_clus == 0) return 0; - set_fat_entry(new_clus, 0x0FFFFFFF); - clear_cluster(new_clus); - handle->cluster = new_clus; - handle->start_cluster = new_clus; - - // Update directory entry start cluster - uint8_t sec_buf[SECTOR_SIZE]; - ata_read_sectors(handle->dir_sector, 1, sec_buf); - FAT32_DirEntry *ent = (FAT32_DirEntry*)(sec_buf + handle->dir_offset); - ent->start_cluster_high = (new_clus >> 16); - ent->start_cluster_low = (new_clus & 0xFFFF); - ata_write_sectors(handle->dir_sector, 1, sec_buf); + const uint8_t *buf = (const uint8_t *)buffer; + + // Check if we are at a cluster boundary from a previous write + if (handle->position > 0 && (handle->position % FAT32_CLUSTER_SIZE) == 0) { + uint32_t next = fat_table[handle->cluster]; + if (next >= 0xFFFFFFF8) { + next = allocate_cluster(); + if (!next) return 0; + fat_table[handle->cluster] = next; + } + handle->cluster = next; } while (bytes_written < size) { - uint32_t offset_in_cluster = handle->position % bytes_per_cluster; + uint32_t offset_in_cluster = handle->position % FAT32_CLUSTER_SIZE; int to_write = size - bytes_written; - if ((uint32_t)to_write > bytes_per_cluster - offset_in_cluster) { - to_write = bytes_per_cluster - offset_in_cluster; + + if (to_write > FAT32_CLUSTER_SIZE - offset_in_cluster) { + to_write = FAT32_CLUSTER_SIZE - offset_in_cluster; } - - // Read-Modify-Write cluster - uint8_t *cluster_buf = (uint8_t*)kmalloc(bytes_per_cluster); - if (!cluster_buf) return -1; - uint32_t lba = cluster_to_lba(handle->cluster); - ata_read_sectors(lba, sectors_per_cluster, cluster_buf); - for(int i=0; icluster >= MAX_CLUSTERS) { + break; + } - ata_write_sectors(lba, sectors_per_cluster, cluster_buf); - kfree(cluster_buf); + uint8_t *dest = cluster_data[handle->cluster] + offset_in_cluster; + for (int i = 0; i < to_write; i++) { + dest[i] = buf[bytes_written + i]; + } bytes_written += to_write; handle->position += to_write; - if (handle->position > handle->size) handle->size = handle->position; - - if (handle->position % bytes_per_cluster == 0 && bytes_written < size) { - uint32_t next = get_fat_entry(handle->cluster); - if (next >= 0x0FFFFFF8) { - uint32_t new_clus = find_free_cluster(); - if (new_clus == 0) break; // Disk full - set_fat_entry(handle->cluster, new_clus); - set_fat_entry(new_clus, 0x0FFFFFFF); - clear_cluster(new_clus); - handle->cluster = new_clus; - } else { - handle->cluster = next; - } + + if (handle->position > handle->size) { + handle->size = handle->position; + } + + // Move to next cluster if needed + if (offset_in_cluster + to_write >= FAT32_CLUSTER_SIZE && bytes_written < size) { + uint32_t next = allocate_cluster(); + if (!next) break; + fat_table[handle->cluster] = next; + handle->cluster = next; } } - - // Update file size in directory entry - uint8_t sec_buf[SECTOR_SIZE]; - ata_read_sectors(handle->dir_sector, 1, sec_buf); - FAT32_DirEntry *ent = (FAT32_DirEntry*)(sec_buf + handle->dir_offset); - ent->file_size = handle->size; - ata_write_sectors(handle->dir_sector, 1, sec_buf); - + + // Update file entry + for (int i = 0; i < MAX_FILES; i++) { + if (files[i].used && files[i].start_cluster == handle->start_cluster) { + files[i].size = handle->size; + break; + } + } + return bytes_written; } @@ -908,117 +434,81 @@ int fat32_seek(FAT32_FileHandle *handle, int offset, int whence) { } bool fat32_mkdir(const char *path) { - FAT32_DirEntry dummy; - if (resolve_path(path, &dummy)) return false; // Already exists - char normalized[FAT32_MAX_PATH]; fat32_normalize_path(path, normalized); - // Split path - char parent_path[FAT32_MAX_PATH]; - char dirname[256]; - int len = fs_strlen(normalized); - int split = len; - while(split > 0 && normalized[split] != '/') split--; - - if (split == 0) { - fs_strcpy(parent_path, "/"); - fs_strcpy(dirname, normalized + (normalized[0] == '/' ? 1 : 0)); - } else { - for(int i=0; iused = true; + fs_strcpy(entry->full_path, normalized); + extract_filename(normalized, entry->filename); + extract_parent_path(normalized, entry->parent_path); + entry->start_cluster = allocate_cluster(); + entry->size = 0; + entry->attributes = ATTR_DIRECTORY; + + return true; } bool fat32_rmdir(const char *path) { - (void)path; - return false; // Not implemented + char normalized[FAT32_MAX_PATH]; + fat32_normalize_path(path, normalized); + + FileEntry *entry = find_file(normalized); + if (!entry || !(entry->attributes & ATTR_DIRECTORY)) { + return false; + } + + entry->used = false; + return true; } bool fat32_delete(const char *path) { - (void)path; - return false; // Not implemented + char normalized[FAT32_MAX_PATH]; + fat32_normalize_path(path, normalized); + + FileEntry *entry = find_file(normalized); + if (!entry || (entry->attributes & ATTR_DIRECTORY)) { + return false; + } + + entry->used = false; + return true; } bool fat32_exists(const char *path) { - FAT32_DirEntry entry; - return resolve_path(path, &entry); + return find_file(path) != NULL; } bool fat32_is_directory(const char *path) { - FAT32_DirEntry entry; - return resolve_path(path, &entry) && (entry.attributes & ATTR_DIRECTORY); + FileEntry *entry = find_file(path); + return entry && (entry->attributes & ATTR_DIRECTORY); } int fat32_list_directory(const char *path, FAT32_FileInfo *entries, int max_entries) { - FAT32_DirEntry dir_entry; - if (!resolve_path(path, &dir_entry) || !(dir_entry.attributes & ATTR_DIRECTORY)) { - return 0; - } + char normalized[FAT32_MAX_PATH]; + fat32_normalize_path(path, normalized); - uint32_t current_cluster = (dir_entry.start_cluster_high << 16) | dir_entry.start_cluster_low; - if (current_cluster == 0) current_cluster = root_cluster; + FileEntry *dir = find_file(normalized); + if (!dir || !(dir->attributes & ATTR_DIRECTORY)) { + return 0; // Not a directory + } int count = 0; - uint8_t *buf = (uint8_t*)kmalloc(bytes_per_cluster); - if (!buf) return 0; - - char lfn_name[256]; - fs_memset(lfn_name, 0, 256); - bool has_lfn = false; - - while (current_cluster >= 2 && current_cluster < 0x0FFFFFF8 && count < max_entries) { - ata_read_sectors(cluster_to_lba(current_cluster), sectors_per_cluster, buf); - FAT32_DirEntry *d = (FAT32_DirEntry*)buf; - int entries_per_cluster = bytes_per_cluster / sizeof(FAT32_DirEntry); - - for (int i = 0; i < entries_per_cluster && count < max_entries; i++) { - if (d[i].filename[0] == 0) { kfree(buf); return count; } - if (d[i].filename[0] == 0xE5) { has_lfn = false; continue; } - - if (d[i].attributes == 0x0F) { - FAT32_LFNEntry *lfn = (FAT32_LFNEntry*)&d[i]; - if (lfn->order & 0x40) { - fs_memset(lfn_name, 0, 256); - has_lfn = true; - } - if (has_lfn) { - int order = lfn->order & 0x3F; - char part[14]; - extract_lfn_part(lfn, part); - int pos = (order - 1) * 13; - if (pos < 255) { - int part_len = fs_strlen(part); - for(int k=0; kattributes & ATTR_DIRECTORY)) { return false; } diff --git a/src/kernel/fat32.h b/src/kernel/fat32.h index 47dc18e..f4eb119 100644 --- a/src/kernel/fat32.h +++ b/src/kernel/fat32.h @@ -83,8 +83,6 @@ typedef struct { uint32_t size; // File size uint32_t mode; // 0=read, 1=write, 2=append bool valid; // Is this handle valid? - uint32_t dir_sector; // Sector containing the directory entry - uint32_t dir_offset; // Offset within that sector } FAT32_FileHandle; // Directory Entry Info (for listing)