tape-kernel 1.0
a modular modern independent kernel
Loading...
Searching...
No Matches
fs.c
Go to the documentation of this file.
1//fs.c -- filesystem tooling
2#include "fs.h"
3#include "ide.h"
4#include "../mem/heap.h"
5#include "../lib/err.h"
6#include "../lib/utils.h"
7
8#define FS_TABLE_LBA 1 //set lable
9
10/**
11 * @brief the fs_entry_t type
12 *
13 * fs_entry_t is made up of name and lba
14 * @param name, the filename string
15 * @param lba, the logical block address on disk
16 *
17 * @see files[], fsfind(), fsadd()
18 */
19typedef struct {
20 char *name;
23
24static fs_entry_t files[MAX_FILES]; //create files and ints that are static
25static int file_count = 0;
27static uint32_t lba_map[MAX_FILES]; //track which LBAs are in use
28
29/**
30 * @brief fsinit initializes the filesystem table from disk
31 *
32 * fsinit is a function that reads the filesystem table from the disk,
33 * parses all existing file entries, and rebuilds the lba map
34 * @param heap, the arena to allocate filename strings from
35 *
36 * using fsinit is done with
37 * @code{.c}
38 * #include "../fs/fs.h" //or just fs.h
39 * fsinit(fs_arena);
40 * @endcode
41 *
42 * @see ffsinit(), fsadd(), fslist()
43 */
44void __fsinit(arena_t *heap) {
45 uint8_t sector[512]; //create sectors and fs_heap for simplicity
46 fs_heap = heap;
47
48 //clear lba map (add these 3 lines)
49 for (int i = 0; i < MAX_FILES; i++) {
50 lba_map[i] = 0;
51 }
52
53 irsec(FS_TABLE_LBA, sector);
54
55 //check if table exists (magic 'FS' descriptor)
56 if (sector[0] == 'F' && sector[1] == 'S') { //check for it
57 file_count = sector[2]; //create the file count
58 for (int i = 0; i < file_count && i < MAX_FILES; i++) { //do the following aslong as we arent making more then max files and file count is over tmp ctr
59 int ofst = 3 + i * 36; //calc offset
60 files[i].name = alc(fs_heap, 32); //make the file in array counter name section be the allocation of alc fsheap 32
61 for (int j = 0; j < 32; j++) { //do 32 times
62 files[i].name[j] = (char)sector[ofst + j]; //files i for name j is sector offset + j
63 }
64 files[i].lba = (sector[ofst + 32] << 24) | //the file array for lba is the bit calculations for actual sector area
65 (sector[ofst + 33] << 16) |
66 (sector[ofst + 34] << 8) |
67 sector[ofst + 35];
68 }
69
70 //rebuild map from existing files
71 for (int i = 0; i < file_count; i++) {
72 uint32_t lba = files[i].lba;
73 //calc which index this lba corresponds to
74 //lba 100 = index 0, lba 102 = index 1, lba 104 = index 2, etc
75 if (lba >= 100 && ((lba - 100) % 2) == 0) { //if lba over or equal 100 and lba - 100 % 2 is 0 then
76 uint32_t idx = (lba - 100) / 2; //populate idx
77 if (idx < MAX_FILES) { //ensure under max files
78 lba_map[idx] = lba;
79 }
80 }
81 }
82 }
83}
84
85/**
86 * @brief fsadd adds a new file entry to the filesystem
87 *
88 * fsadd is a function that registers a file name and lba into the
89 * in-memory file table and persists it to disk
90 * @param heap, the arena to allocate the filename from
91 * @param name, the name of the file to add
92 * @param lba, the logical block address where the file lives
93 *
94 * using fsadd is done with
95 * @code{.c}
96 * #include "../fs/fs.h" //or just fs.h
97 * fsadd(fs_arena, "myfile.txt", 100);
98 * @endcode
99 *
100 * @see fsinit(), fsfind(), fsdelete()
101 */
102void __fsadd(arena_t *heap, const char *name, uint32_t lba) {
103 assert(file_count < MAX_FILES, "fs: too many files"); //err han
104 assert(heap != NULL, "fsadd: heap is NULL");
105
106 files[file_count].name = alc(heap, 32); //file count name is the heap, we strcpy the file name to name, and make lba lba, then increment
107 strcpy(files[file_count].name, name);
108 files[file_count].lba = lba;
109 file_count++;
110
111 //save to disk
112 uint8_t sector[512]; //create sector
113 for (int i = 0; i < 512; i++) sector[i] = 0; //make sector i 0 to fully reset sector, data overwrite
114 sector[0] = 'F'; //make sec 0 F and 1 S for the magic label
115 sector[1] = 'S';
116 sector[2] = (uint8_t)file_count; //make the second one the count
117
118 for (int i = 0; i < file_count; i++) { //do infinitley aslong as i is less than file count
119 int offset = 3 + i * 36; //calc
120 for (int j = 0; j < 32 && files[i].name[j]; j++) { //do 32 times aslong as its under file name j
121 sector[offset + j] = (uint8_t)files[i].name[j]; //setup ofst
122 }
123 sector[offset + 32] = (uint8_t)(files[i].lba >> 24) & 0xFF; //setup sector positions
124 sector[offset + 33] = (files[i].lba >> 16) & 0xFF;
125 sector[offset + 34] = (files[i].lba >> 8) & 0xFF;
126 sector[offset + 35] = files[i].lba & 0xFF;
127 }
128
129 iwrt(FS_TABLE_LBA, sector); //write the sector and table to ide
130}
131
132/**
133 * @brief fsfind searches the filesystem for a file by name
134 *
135 * fsfind is a function that looks up a file in the in-memory table
136 * and returns its lba if found
137 * @param name, the filename to search for
138 *
139 * using fsfind is done with
140 * @code{.c}
141 * #include "../fs/fs.h" //or just fs.h
142 * uint32_t lba = fsfind("myfile.txt");
143 * if (lba == 0) {
144 * //file doesnt exist
145 * }
146 * @endcode
147 *
148 * @see fslist(), fsread(), fs_entry_t
149 */
150uint32_t __fsfind(const char *name) {
151 for (int i = 0; i < file_count; i++) { //do aslong as file count is under i
152 if (strcmp(files[i].name, name) == 0) { //compare names
153 return files[i].lba; //if it matches return, else exit
154 }
155 }
156 return 0;
157}
158
159/**
160 * @brief fslist returns a newline-separated listing of all files
161 *
162 * fslist is a function that builds a string containing all filenames
163 * in the in-memory filesystem table separated by newlines
164 *
165 * using fslist is done with
166 * @code{.c}
167 * #include "../fs/fs.h" //or just fs.h
168 * char *listing = fslist();
169 * prt(0, 0, listing, 0x0F);
170 * @endcode
171 *
172 * @see fsfind(), fsread()
173 */
174char *__fslist(void) {
175 static char buff[512];
176 int pos = 0; //make pos and buffer
177
178 if (file_count == 0) {
179 buff[0] = '\0';
180 return buff;
181 }
182
183 for (int i = 0; i < file_count; i++) { //youve seen this alot, you get it
184 for (int j = 0; files[i].name[j]; j++) {
185 if (pos < 511) buff[pos++] = files[i].name[j]; //if pos is under 511 we make buf pos ++ name so its always 512 or over
186 }
187 if (pos < 511) buff[pos++] = '\n'; //read above but for newline and if nothing there worked
188 }
189 buff[pos] = '\0'; //null term
190
191 return buff;
192}
193
194/**
195 * @brief fsnextlba finds the next unused lba for a new file
196 *
197 * fsnextlba is a function that scans the lba map for a free slot
198 * and returns an unused lba starting from sector 100
199 *
200 * using fsnextlba is done with
201 * @code{.c}
202 * #include "../fs/fs.h" //or just fs.h
203 * uint32_t new_lba = fsnextlba();
204 * @endcode
205 *
206 * @see fswrite(), fswriteb()
207 */
209 //find first unused lba
210 for (int i = 0; i < MAX_FILES; i++) {
211 if (lba_map[i] == 0) {
212 uint32_t new_lba = 100 + (uint32_t)(i * 2); //start at sector 100, each file gets its own sector
213 lba_map[i] = new_lba;
214 return new_lba;
215 }
216 }
217 //if we get here, no free lba
218 assert(0, "fsnextlba: no free lbas available");
219 return 0;
220}
221
222/**
223 * @brief fsread reads a files contents from disk into memory
224 *
225 * fsread is a function that looks up a file by name, reads its sector
226 * from disk, and returns the contents as a string
227 * @param name, the filename to read
228 *
229 * using fsread is done with
230 * @code{.c}
231 * #include "../fs/fs.h" //or just fs.h
232 * char *content = fsread("myfile.txt");
233 * if (content != NULL) {
234 * prt(0, 0, content, 0x0F);
235 * }
236 * @endcode
237 *
238 * @see fswrite(), fsfind(), irsec()
239 */
240char *__fsread(const char *name) {
241 uint32_t lba = fsfind(name); //set lba to the fsfind
242 if (lba == 0) return NULL; //if lba none return null
243
244 static char content[512]; //make content and sector
245 uint8_t sector[512];
246
247 irsec(lba, sector); //read lba and sector
248
249 //copy sector content to string - preserve all characters
250 int i;
251 for (i = 0; i < 511 && sector[i] != 0; i++) {
252 content[i] = (char)sector[i]; //keep raw byte, prefer no filtering
253 }
254 content[i] = '\0'; //null term
255
256 return content;
257}
258
259/**
260 * @brief fswrite writes text content to a file on disk
261 *
262 * fswrite is a function that writes a text string to a file, creating
263 * the file entry if it doesnt exist yet
264 * @param heap, the arena to allocate from if a new file entry is created
265 * @param name, the filename to write to
266 * @param content, the text string to write
267 *
268 * using fswrite is done with
269 * @code{.c}
270 * #include "../fs/fs.h" //or just fs.h
271 * fswrite(fs_arena, "hello.txt", "hello, world!");
272 * @endcode
273 *
274 * @see fsread(), fswriteb(), iwrt()
275 */
276int __fswrite(arena_t *heap, const char *name, const char *content) {
277 uint32_t lba = fsfind(name); //make lba
278
279 //if file exists, use its lba
280 if (lba == 0) {
281 //file doesn't exist, get next free lba
282 lba = fsnextlba();
283 }
284
285 //write content to disk
286 uint8_t sector[512]; //sector
287 for (int i = 0; i < 512; i++) sector[i] = 0; //do 512 times, resets sector
288 for (int i = 0; content[i] && i < 511; i++) sector[i] = (uint8_t)content[i]; //writes content
289
290 iwrt(lba, sector); //use ide to write
291
292 //if file didn't exist add to filesystem
293 if (fsfind(name) == 0) {
294 fsadd(heap, name, lba); //add
295 }
296
297 return (int)lba; //ret
298}
299
300/**
301 * @brief fsdelete removes a file from the filesystem
302 *
303 * fsdelete is a function that finds a file by name, zeros out its
304 * data sector on disk, marks its lba as free, and removes it from
305 * the in-memory file table
306 * @param name, the filename to delete
307 *
308 * using fsdelete is done with
309 * @code{.c}
310 * #include "../fs/fs.h" //or just fs.h
311 * fsdelete("oldfile.txt");
312 * @endcode
313 *
314 * @see fsadd(), fsfind(), fswrite()
315 */
316void __fsdelete(const char *name) {
317 int index = -1; //current neg 1
318
319 //find the file
320 for (int i = 0; i < file_count; i++) { //do until out of files
321 if (strcmp(files[i].name, name) == 0) { //compare name, if 0 set index to i and break
322 index = i;
323 break;
324 }
325 }
326
327 assert(index != -1, "fsdelete: file not found"); //if index never changed it doesnt exist
328
329 //mark lba as free
330 for (int i = 0; i < MAX_FILES; i++) {
331 if (lba_map[i] == files[index].lba) {
332 lba_map[i] = 0;
333 break;
334 }
335 }
336
337 //shift remaining files left
338 for (int i = index; i < file_count - 1; i++) {
339 files[i].name = files[i+1].name;
340 files[i].lba = files[i+1].lba;
341 }
342
343 file_count--;
344
345 //rebuild the filesystem table on disk
346 uint8_t sector[512];
347 for (int i = 0; i < 512; i++) sector[i] = 0;
348 sector[0] = 'F'; //rebuild F and S
349 sector[1] = 'S';
350 sector[2] = (uint8_t)file_count;
351
352 for (int i = 0; i < file_count; i++) {
353 int offset = 3 + i * 36;
354 for (int j = 0; j < 32 && files[i].name[j]; j++) {
355 sector[offset + j] = (uint8_t)files[i].name[j];
356 } //do all this offset bullshit
357 sector[offset + 32] = (uint8_t)(files[i].lba >> 24) & 0xFF;
358 sector[offset + 33] = (files[i].lba >> 16) & 0xFF;
359 sector[offset + 34] = (files[i].lba >> 8) & 0xFF;
360 sector[offset + 35] = files[i].lba & 0xFF;
361 }
362
363 iwrt(FS_TABLE_LBA, sector); //write it
364
365 //zero out the actual file data sector
366 uint8_t zero_sector[512]; //make sector
367 for (int i = 0; i < 512; i++) zero_sector[i] = 0;
368 iwrt(files[index].lba, zero_sector); //write final say
369}
370
371/**
372 * @brief fswriteb writes raw byte data to a file on disk
373 *
374 * fswriteb is a function that writes raw bytes to a file sector,
375 * limited to 511 bytes per sector, creating the file entry if needed
376 * @param heap, the arena to allocate from if a new file entry is created
377 * @param name, the filename to write to
378 * @param data, the raw byte buffer to write
379 * @param size, the number of bytes to write
380 *
381 * using fswriteb is done with
382 * @code{.c}
383 * #include "../fs/fs.h" //or just fs.h
384 * uint8_t mydata[256];
385 * fswriteb(fs_arena, "data.bin", mydata, 256);
386 * @endcode
387 *
388 * @see fsreadb(), fswrite(), iwrt()
389 */
390int __fswriteb(arena_t *heap, const char *name, uint8_t *data, uint32_t size) {
391 uint32_t lba = fsfind(name);
392
393 if (lba == 0) { //get next lba
394 lba = fsnextlba();
395 }
396
397 //write entire sector
398 uint8_t sector[512];
399 for (int i = 0; i < 512; i++) sector[i] = 0;
400
401 uint32_t btw = (size > 511) ? 511 : size; //limit to 511 bytes per sector
402 for (uint32_t i = 0; i < btw; i++) {
403 sector[i] = data[i];
404 }
405
406 iwrt(lba, sector);
407
408 if (fsfind(name) == 0) {
409 fsadd(heap, name, lba);
410 }
411
412 return (int)lba;
413}
414
415/**
416 * @brief fsreadb reads raw byte data from a file off disk
417 *
418 * fsreadb is a function that reads raw bytes from a file sector
419 * into a provided buffer
420 * @param name, the filename to read
421 * @param buffer, the buffer to store the raw bytes in
422 * @param max_size, the maximum number of bytes to read
423 *
424 * using fsreadb is done with
425 * @code{.c}
426 * #include "../fs/fs.h" //or just fs.h
427 * uint8_t buffer[512];
428 * int bytes_read = fsreadb("data.bin", buffer, 512);
429 * @endcode
430 *
431 * @see fswriteb(), fsread(), irsec()
432 */
433int __fsreadb(const char *name, uint8_t *buffer, uint32_t max_size) {
434 uint32_t lba = fsfind(name);
435 if (lba == 0) return 0;
436
437 uint8_t sector[512];
438 irsec(lba, sector);
439
440 uint32_t btr = (max_size > 512) ? 512 : max_size;
441 for (uint32_t i = 0; i < btr; i++) { //make buff sec
442 buffer[i] = sector[i];
443 }
444
445 return (int)btr; //return number of bytes read
446}
447
448
#define assert
Definition err.h:4
char * __fsread(const char *name)
fsread reads a files contents from disk into memory
Definition fs.c:240
static fs_entry_t files[32]
Definition fs.c:24
char * __fslist(void)
fslist returns a newline-separated listing of all files
Definition fs.c:174
void __fsinit(arena_t *heap)
fsinit initializes the filesystem table from disk
Definition fs.c:44
void __fsdelete(const char *name)
fsdelete removes a file from the filesystem
Definition fs.c:316
#define FS_TABLE_LBA
Definition fs.c:8
uint32_t __fsnextlba(void)
fsnextlba finds the next unused lba for a new file
Definition fs.c:208
uint32_t __fsfind(const char *name)
fsfind searches the filesystem for a file by name
Definition fs.c:150
int __fswriteb(arena_t *heap, const char *name, uint8_t *data, uint32_t size)
fswriteb writes raw byte data to a file on disk
Definition fs.c:390
static arena_t * fs_heap
Definition fs.c:26
int __fswrite(arena_t *heap, const char *name, const char *content)
fswrite writes text content to a file on disk
Definition fs.c:276
static uint32_t lba_map[32]
Definition fs.c:27
static int file_count
Definition fs.c:25
int __fsreadb(const char *name, uint8_t *buffer, uint32_t max_size)
fsreadb reads raw byte data from a file off disk
Definition fs.c:433
void __fsadd(arena_t *heap, const char *name, uint32_t lba)
fsadd adds a new file entry to the filesystem
Definition fs.c:102
#define MAX_FILES
Definition fs.h:7
#define fsfind
Definition fs.h:11
#define fsadd
Definition fs.h:10
#define fsnextlba
Definition fs.h:13
#define alc
Definition heap.h:25
#define iwrt
Definition ide.h:19
#define irsec
Definition ide.h:18
the arena_t type
Definition heap.h:17
the fs_entry_t type
Definition fs.c:19
uint32_t lba
Definition fs.c:21
char * name
Definition fs.c:20
#define NULL
Definition types.h:38
unsigned int uint32_t
Definition types.h:30
unsigned char uint8_t
Definition types.h:28
int strcmp(const char *a, const char *b)
Definition utils.c:15
void strcpy(char *dest, const char *src)
Definition utils.c:21