| 
									
										
										
										
											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; | 
					
						
							|  |  |  | } |