From 17589d72cfdebd4d9a5831a6bb20bf4fa3483758 Mon Sep 17 00:00:00 2001 From: xamidev Date: Thu, 9 Apr 2026 16:08:19 +0200 Subject: [PATCH] tar_file_read --- .gitignore | 3 +- Makefile | 13 ++- calyx/hello | Bin 0 -> 74 bytes calyx/pedicel | Bin 0 -> 66 bytes calyx/welcome.txt | 1 + include/config.h | 3 + include/fs/tar.h | 36 ++++++++ include/string/string.h | 1 + limine.conf | 3 +- src/fs/tar.c | 182 ++++++++++++++++++++++++++++++++++++++++ src/fs/vfs.c | 16 ++++ src/kmain.c | 21 +++-- src/string/string.c | 14 ++++ 13 files changed, 278 insertions(+), 15 deletions(-) create mode 100644 calyx/hello create mode 100644 calyx/pedicel create mode 100644 calyx/welcome.txt create mode 100644 include/fs/tar.h create mode 100644 src/fs/tar.c create mode 100644 src/fs/vfs.c diff --git a/.gitignore b/.gitignore index 3db12c3..539ef61 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ symbols.S *.log build/ compile_commands.json -.cache/ \ No newline at end of file +.cache/ +*.tar \ No newline at end of file diff --git a/Makefile b/Makefile index ffefdfc..d945719 100644 --- a/Makefile +++ b/Makefile @@ -43,14 +43,13 @@ limine/limine: git clone https://github.com/limine-bootloader/limine.git --branch=v9.x-binary --depth=1 $(MAKE) -C limine -build-iso: limine/limine $(ELFFILE) +build-iso: limine/limine $(ELFFILE) initfs rm -rf iso_root mkdir -p iso_root/boot cp -v $(ELFFILE) iso_root/boot mkdir -p iso_root/boot/limine cp -v limine.conf iso_root/boot/limine - cp $(BUILDDIR)/hello iso_root/boot/ - cp $(BUILDDIR)/pedicel iso_root/boot/ + cp calyx.tar iso_root/boot/ mkdir -p iso_root/EFI/BOOT cp -v limine/limine-bios.sys limine/limine-bios-cd.bin limine/limine-uefi-cd.bin iso_root/boot/limine/ cp -v limine/BOOTX64.EFI iso_root/EFI/BOOT/ @@ -62,6 +61,12 @@ build-iso: limine/limine $(ELFFILE) iso_root -o pepper.iso ./limine/limine bios-install pepper.iso +.PHONY: initfs +initfs: + cp $(BUILDDIR)/hello calyx/ + cp $(BUILDDIR)/pedicel calyx/ + tar cvf calyx.tar -C ./calyx . + .PHONY: debug debug: /usr/bin/qemu-system-x86_64 -drive file=pepper.iso -s -S -d int -D qemu.log -no-reboot -no-shutdown & @@ -78,4 +83,4 @@ run: build-iso .PHONY: clean clean: - rm -rf $(BUILDDIR) symbols.map symbols.S $(ELFFILE) iso_root pepper.iso limine + rm -rf $(BUILDDIR) symbols.map symbols.S $(ELFFILE) iso_root pepper.iso limine calyx.tar diff --git a/calyx/hello b/calyx/hello new file mode 100644 index 0000000000000000000000000000000000000000..306042683fb43ce286db3d81c7d5a75c7297c96b GIT binary patch literal 74 zcmdnN$iTp`A4GWcnu-IdU5Y^BY{L#4kT?(n*{}aGFl1yZq!s1oDwGzd7Ud-7r6^cw UDwL-xq-3TjWR@u8Cgw2!0Kg0s_y7O^ literal 0 HcmV?d00001 diff --git a/calyx/pedicel b/calyx/pedicel new file mode 100644 index 0000000000000000000000000000000000000000..8a4d3395d407a3e3839f0e10a29e3bc956f6abbe GIT binary patch literal 66 zcmdnN$iTp`A4GWcnu-IdU6MfJY{L#4kT?(n*{}aGFmUmP7N-^|6cpvB7bWH@7%3DN Mq$Xx(=A| + * @brief Tape archive (TAR) filesystem definitions + * @license GPL-3.0-only + */ + +#ifndef TAR_H +#define TAR_H + +#include +#include + +struct tar_header +{ + char filename[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag[1]; +}; + +struct tar_file +{ + void* address; + uint64_t size; +}; + +unsigned int tar_parse(uint64_t address); +int tar_init_fs(struct limine_file* file); +struct tar_header* tar_file_lookup(const char* filename); +void tar_file_read(struct tar_header* header, uint8_t* buf); + +#endif \ No newline at end of file diff --git a/include/string/string.h b/include/string/string.h index 78859ec..df2cfd7 100644 --- a/include/string/string.h +++ b/include/string/string.h @@ -13,5 +13,6 @@ char *strcpy(char *dest, const char *src); char *strcat(char *dest, const char *src); void strncpy(char* dst, const char* src, size_t n); int strncmp(const char* s1, const char* s2, size_t n); +size_t strlen(const char *str); #endif \ No newline at end of file diff --git a/limine.conf b/limine.conf index 7988d0b..314ec4b 100644 --- a/limine.conf +++ b/limine.conf @@ -6,5 +6,4 @@ interface_branding: Welcome to the PepperOS disk! comment: Default configuration (warning: spicy) path: boot():/boot/pepperk - module_path: boot():/boot/hello - module_path: boot():/boot/pedicel \ No newline at end of file + module_path: boot():/boot/calyx.tar \ No newline at end of file diff --git a/src/fs/tar.c b/src/fs/tar.c new file mode 100644 index 0000000..839f551 --- /dev/null +++ b/src/fs/tar.c @@ -0,0 +1,182 @@ +/* + * @author xamidev + * @brief Tape archive (TAR) initial filesystem routines + * @license GPL-3.0-only + */ + + + /* + TODO: + + implement open, read, write, close for tar + + eventually seek, stat, etc. would be nice to handle some more syscalls + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct tar_header* headers[CALYXFS_FILES_MAX] = {0}; + +struct tar_file archive; + +#define TAR_BLOCK_SIZE 512 + +// To get file content, just use file_offset[file]+header_size +// uint64_t file_offsets[CALYXFS_FILES_MAX] = {0}; + +/* + * tar_getsize - Get the size of a file contained in a tar archive + * @in: size attribute of a tar header + * + * Return: + * - Size of file in bytes + */ +unsigned int tar_getsize(const char *in) +{ + unsigned int size = 0; + unsigned int count = 1; + + for (unsigned int j = 11; j > 0; j--, count *= 8) { + size += ((in[j - 1] - '0') * count); + } + return size; +} + +/* + * tar_parse - Parse a TAR file + * @address: address of TAR file start in memory + * + * This function goes through all headers in a TAR file + * and populates the header array so we can work with + * the files contained in the archive. + * + * Return: + * - number of files parsed/found + */ +unsigned int tar_parse(uint64_t address) +{ + unsigned int i; + for (i = 0; i < CALYXFS_FILES_MAX; i++) { + struct tar_header *header = (struct tar_header*)address; + + if (header->filename[0] == '\0') { + break; + } + unsigned int size = tar_getsize(header->size); + headers[i] = header; + + DEBUG("found file %s of size %u", header->filename, size); + uint64_t file_blocks = (size + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE; + address += TAR_BLOCK_SIZE + (file_blocks * TAR_BLOCK_SIZE); + } + + return i; +} + +/* + * tar_init_fs - Initialize the TAR filesystem + * @file: pointer to Limine file structure (corresponding + * to the loaded boot module) + * + * This function initializes the tar_file object + * to the values of the found TAR archive, namely + * its address and its size. + * + * It then parses the archive using tar_parse, + * so it can be looked up later. + * + * Return: + * %0 - on success + */ +int tar_init_fs(struct limine_file* file) +{ + DEBUG("calyxfs found at 0x%p (size=%u)", file->address, file->size); + archive.address = file->address; + archive.size = file->size; + tar_parse((uint64_t)archive.address); + return 0; +} + +/* + * tar_is_zeroed - Checks if a TAR header is zero + * @header: pointer to TAR header + * + * Return: + * True - TAR header is zeroed out + * False - TAR header contains something + */ +bool tar_is_zeroed(struct tar_header* header) +{ + struct tar_header zeroed = {0}; + return memcmp(header, &zeroed, sizeof(struct tar_header)) == 0; +} + +/* + * tar_file_lookup - Find a file + * + * This functions looks up the @filename in the tar + * archive. + * + * Return: + * - Address of TAR header for the found file + * %0 - file not found + */ +struct tar_header* tar_file_lookup(const char* filename) +{ + if (!filename || !archive.address) { + return 0; + } + + int zero_counter = 0; + struct tar_header* curr = archive.address; + + while (zero_counter < 2) { + if (tar_is_zeroed(curr)) { + zero_counter++; + curr = (struct tar_header*)((uint8_t*)curr + TAR_BLOCK_SIZE); + continue; + } + + zero_counter = 0; + + if (strncmp(filename, curr->filename, sizeof(curr->filename)) == 0) { + DEBUG("found file %s", filename); + return curr; + } + + uint64_t sz = tar_getsize(curr->size); + uint64_t file_blocks = (sz + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE; + curr = (struct tar_header*)((uint8_t*)curr + TAR_BLOCK_SIZE + (file_blocks * TAR_BLOCK_SIZE)); + } + + return 0; +} + +/* + * tar_file_read - Read a file contained in TAR archive + * @header: Header of given file + * @buf: data out buffer + * + * This function reads the file, using its @header, to + * the @buf buffer. It needs to be big enough to contain + * the file, or else a buffer overrun might happen. + */ +void tar_file_read(struct tar_header* header, uint8_t* buf) +{ + if (!header || !buf) { + return; + } + + uint32_t sz = tar_getsize(header->size); + void* file_ptr = (void*)((uint8_t*)header + TAR_BLOCK_SIZE); + + memcpy(buf, (void*)file_ptr, sz); +} \ No newline at end of file diff --git a/src/fs/vfs.c b/src/fs/vfs.c new file mode 100644 index 0000000..68c6ff1 --- /dev/null +++ b/src/fs/vfs.c @@ -0,0 +1,16 @@ +/* + * @author xamidev + * @brief Virtual filesystem (VFS) layer + * @license GPL-3.0-only + */ + +/* +Around here we'll want to have some file operations struct with +function pointers (read, write, open, close) for different filesystems. + +At init, the function pointers will be assigned to the corresponding +filesystem-dependent functions. + +That way we have a nice abstraction layer and can just do calls no matter +the underlying fs. +*/ \ No newline at end of file diff --git a/src/kmain.c b/src/kmain.c index 6f2b862..9470bfe 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -25,6 +25,7 @@ #include #include #include +#include // Limine version used __attribute__((used, section(".limine_requests"))) @@ -120,16 +121,20 @@ void kmain() idle_proc = process_create("idle", (void*)idle_main, 0); if (!boot_ctx.module) { - panic(NULL, "could not load 'hello' executable :("); + panic(NULL, "could not load calyx filesystem!"); } - if (boot_ctx.module->module_count == 2) { - file = boot_ctx.module->modules[0]; - DEBUG("file: addr=%p size=%u", file->address, file->size); - process_create_user(file, "hello"); - file = boot_ctx.module->modules[1]; - process_create_user(file, "pedicel"); - } + file = boot_ctx.module->modules[0]; + tar_init_fs(file); + + /* DANGER ZONE (tests)*/ + struct tar_header* header = tar_file_lookup("./welcome.txt"); + + uint8_t buf[1000] = {0}; + tar_file_read(header, buf); + DEBUG("-BEGIN BUFFER-%s-END BUFFER-", buf); + /* END DANGER ZONE */ + scheduler_init(); printf(PEPPEROS_SPLASH); diff --git a/src/string/string.c b/src/string/string.c index 6b51c58..77e60b2 100644 --- a/src/string/string.c +++ b/src/string/string.c @@ -98,4 +98,18 @@ int strncmp(const char* s1, const char* s2, size_t n) else { return ( *(unsigned char *)s1 - *(unsigned char *)s2 ); } +} + +/* + * strlen - Get a string's length (BSD implementation) + * @str: null-terminated string + * + * Return: + * - length of the string in bytes + */ +size_t strlen(const char *str) +{ + const char *s; + for (s = str; *s; ++s); + return (s - str); } \ No newline at end of file