#include #include #include #include #define SFS_HEADER_START_LBA 8 #define SFS_HEADER_REGION_SECTORS 1024 #define SFS_HEADERS_PER_SECTOR 8 #define TOTAL_SECTORS 32768 #define SFS_DATA_START_LBA (TOTAL_SECTORS / 4) #pragma pack(push, 1) typedef struct sfs_file_header { uint16_t magic; /* 0xBEEF */ /* 32 chars for the filename itself, 4 chars for the file's extension, and 1 char for the null zero. */ char filename[37]; uint64_t data_beginning; /* Actually a 48 bit LBA mind you */ uint32_t num_sectors; /* Number of sectors after data_beginning that are this file's data */ uint8_t padding[13]; /* Padding to 64 bytes total */ } sfs_file_header_t; #pragma pack(pop) uint8_t buffer[512] = { 0 }; /* Global allocator pointer to the next free sector in the data region */ uint64_t sfs_next_free_data_sector = SFS_DATA_START_LBA; int32_t sfs_init(void) { uint8_t sector_buf[512]; for (uint64_t lba = SFS_HEADER_START_LBA; lba < SFS_HEADER_START_LBA + SFS_HEADER_REGION_SECTORS; ++lba) { if (read_sector(lba, sector_buf) != 0) { return -1; } sfs_file_header_t* hdr = (sfs_file_header_t*)sector_buf; if (hdr->magic == 0xBEEF) { uint64_t end = hdr->data_beginning + hdr->num_sectors; if (end > sfs_next_free_data_sector) { sfs_next_free_data_sector = end; } } /* TODO: support multiple headers per sector, loop through all 512/64 = 8 headers here */ } return 0; } bool sfs_get_formatted_name(const char* raw_name, char output[37]) { size_t len = strlen(raw_name); if (len > 36 || strchr(raw_name, '/') || strchr(raw_name, '*') || strchr(raw_name, '\\')) { return false; } memset(output, ' ', 36); output[36] = '\0'; memcpy(output, raw_name, len); return true; } int32_t sfs_create_file(const char* _name, int32_t size_bytes) { if (size_bytes < 0) { return -1; } char name[37]; if (!sfs_get_formatted_name(_name, name)) { return -2; } uint32_t sectors_needed = (size_bytes + 511) / 512; uint8_t sector_buf[512]; for (uint64_t lba = SFS_HEADER_START_LBA; lba < SFS_HEADER_START_LBA + SFS_HEADER_REGION_SECTORS; ++lba) { if (read_sector(lba, sector_buf) != 0) { return -3; } for (int i = 0; i < SFS_HEADERS_PER_SECTOR; ++i) { sfs_file_header_t* hdr = ((sfs_file_header_t*)sector_buf) + i; if (hdr->magic != 0xBEEF) { hdr->magic = 0xBEEF; memcpy(hdr->filename, name, 37); hdr->data_beginning = sfs_next_free_data_sector; hdr->num_sectors = sectors_needed; sfs_next_free_data_sector += sectors_needed; if (write_sector(lba, sector_buf) != 0) { return -4; } return 0; } } } return -5; } /* num is number of bytes Note: if a negative value is passed for num, then read the whole file */ int32_t sfs_read_file(char* _name, void* buffer, int32_t num) { char name[37] = { '\0' }; if (!sfs_get_formatted_name(_name, name)) { return -1; } memclr(buffer, sizeof(buffer)); /* Zero out buffer */ uint64_t j = SFS_HEADER_START_LBA; if (read_sector(j, buffer) != 0) { return -2; } sfs_file_header_t file; memcpy(&file, buffer, sizeof(file)); if (file.magic != 0xBEEF) { return -3; } while (strncmp(file.filename, name, 37) != 0) { memclr(buffer, sizeof(buffer)); if (read_sector(++j, buffer) != 0) { return -4; } memcpy(&file, buffer, sizeof(file)); if (file.magic != 0xBEEF) { return -5; } } /* File found, now to read data */ uint32_t sectors_to_read = file.num_sectors; if (num >= 0) { uint32_t max_sectors = (num + 511) / 512; if (max_sectors < sectors_to_read) { sectors_to_read = max_sectors; } } for (uint32_t i = 0; i < sectors_to_read; ++i) { if (read_sector((uint64_t)(file.data_beginning) + i, (uint8_t*)buffer + i * 512) != 0) { return -6; /* read error */ } } return sectors_to_read * 512; memclr(buffer, sizeof(buffer)); return 0; } /* Writes num bytes to an existing file. If the file exists, it will be resized (grown/shrunk) to fit num bytes. Returns number of bytes written (rounded up to sectors), or a negative error code. */ int32_t sfs_write_file(char* _name, const void* buffer, int32_t num) { if (num < 0) { return -1; } char name[37] = { '\0' }; if (!sfs_get_formatted_name(_name, name)) { return -2; } uint8_t sector_buf[512]; uint64_t header_lba = SFS_HEADER_START_LBA; sfs_file_header_t file; while (1) { if (read_sector(header_lba, sector_buf) != 0) { return -3; } memcpy(&file, sector_buf, sizeof(file)); if (file.magic != 0xBEEF) { return -4; } if (strncmp(file.filename, name, 37) == 0) { break; } ++header_lba; } uint32_t sectors_needed = (num + 511) / 512; if (sectors_needed != file.num_sectors) { file.num_sectors = sectors_needed; file.data_beginning = sfs_next_free_data_sector; sfs_next_free_data_sector += sectors_needed; } file.magic = 0xBEEF; memcpy(sector_buf, &file, sizeof(file)); if (write_sector(header_lba, sector_buf) != 0) { return -5; } for (uint32_t i = 0; i < sectors_needed; ++i) { uint8_t temp[512] = {0}; if (i == sectors_needed - 1 && (num % 512 != 0)) { memcpy(temp, (const uint8_t*)buffer + i * 512, num % 512); } else { memcpy(temp, (const uint8_t*)buffer + i * 512, 512); } if (write_sector(file.data_beginning + i, temp) != 0) { return -6; } } return sectors_needed * 512; }