2025-07-01 20:39:38 -05:00
|
|
|
#include <drivers/ide.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
|
|
#include <fs/sfs.h>
|
|
|
|
|
|
|
|
|
|
|
2025-07-07 10:41:05 -05:00
|
|
|
#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)
|
|
|
|
|
|
2025-07-01 20:39:38 -05:00
|
|
|
|
|
|
|
|
#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)
|
|
|
|
|
|
|
|
|
|
|
2025-07-07 10:41:05 -05:00
|
|
|
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;
|
2025-07-01 20:39:38 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-07 10:41:05 -05:00
|
|
|
int32_t sfs_init(void)
|
2025-07-01 20:39:38 -05:00
|
|
|
{
|
2025-07-07 10:41:05 -05:00
|
|
|
uint8_t sector_buf[512];
|
2025-07-01 20:39:38 -05:00
|
|
|
|
2025-07-07 10:41:05 -05:00
|
|
|
for (uint64_t lba = SFS_HEADER_START_LBA; lba < SFS_HEADER_START_LBA + SFS_HEADER_REGION_SECTORS; ++lba)
|
2025-07-01 20:39:38 -05:00
|
|
|
{
|
2025-07-07 10:41:05 -05:00
|
|
|
if (read_sector(lba, sector_buf) != 0)
|
2025-07-01 20:39:38 -05:00
|
|
|
{
|
2025-07-07 10:41:05 -05:00
|
|
|
return -1;
|
2025-07-01 20:39:38 -05:00
|
|
|
}
|
2025-07-07 10:41:05 -05:00
|
|
|
|
|
|
|
|
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 */
|
2025-07-01 20:39:38 -05:00
|
|
|
}
|
2025-07-07 10:41:05 -05:00
|
|
|
|
2025-07-01 20:39:38 -05:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-07 10:41:05 -05:00
|
|
|
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;
|
|
|
|
|
}
|
2025-07-01 20:39:38 -05:00
|
|
|
|
2025-07-07 10:41:05 -05:00
|
|
|
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
|
2025-07-01 20:39:38 -05:00
|
|
|
Note: if a negative value is passed for num, then read the whole file
|
|
|
|
|
*/
|
2025-07-07 10:41:05 -05:00
|
|
|
int32_t sfs_read_file(char* _name, void* buffer, int32_t num)
|
2025-07-01 20:39:38 -05:00
|
|
|
{
|
|
|
|
|
char name[37] = { '\0' };
|
|
|
|
|
|
2025-07-07 10:41:05 -05:00
|
|
|
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)
|
2025-07-01 20:39:38 -05:00
|
|
|
{
|
2025-07-07 10:41:05 -05:00
|
|
|
if (read_sector((uint64_t)(file.data_beginning) + i, (uint8_t*)buffer + i * 512) != 0)
|
|
|
|
|
{
|
|
|
|
|
return -6; /* read error */
|
|
|
|
|
}
|
2025-07-01 20:39:38 -05:00
|
|
|
}
|
2025-07-07 10:41:05 -05:00
|
|
|
|
|
|
|
|
return sectors_to_read * 512;
|
2025-07-01 20:39:38 -05:00
|
|
|
|
2025-07-07 10:41:05 -05:00
|
|
|
memclr(buffer, sizeof(buffer));
|
2025-07-01 20:39:38 -05:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2025-07-07 10:41:05 -05:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
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;
|
|
|
|
|
}
|