1010#include <stdbool.h>
1111
1212
13+ static int lfs_diff (uint32_t a , uint32_t b ) {
14+ return (int )(unsigned )(a - b );
15+ }
16+
1317static uint32_t lfs_crc (const uint8_t * data , lfs_size_t size , uint32_t crc ) {
1418 static const uint32_t rtable [16 ] = {
1519 0x00000000 , 0x1db71064 , 0x3b6e20c8 , 0x26d930ac ,
@@ -26,6 +30,27 @@ static uint32_t lfs_crc(const uint8_t *data, lfs_size_t size, uint32_t crc) {
2630 return crc ;
2731}
2832
33+ static lfs_error_t lfs_bd_cmp (lfs_t * lfs ,
34+ lfs_ino_t ino , lfs_off_t off , lfs_size_t size , const void * d ) {
35+ const uint8_t * data = d ;
36+
37+ for (int i = 0 ; i < size ; i ++ ) {
38+ uint8_t c ;
39+ int err = lfs -> ops -> read (lfs -> bd , (void * )& c , ino , off + i , 1 );
40+ if (err ) {
41+ return err ;
42+ }
43+
44+ if (c != data [i ]) {
45+ return false;
46+ }
47+ }
48+
49+ return true;
50+ }
51+
52+
53+
2954static lfs_error_t lfs_alloc (lfs_t * lfs , lfs_ino_t * ino );
3055static lfs_error_t lfs_free (lfs_t * lfs , lfs_ino_t ino );
3156
@@ -147,40 +172,14 @@ lfs_error_t lfs_check(lfs_t *lfs, lfs_ino_t block) {
147172 return (crc != 0 ) ? LFS_ERROR_CORRUPT : LFS_ERROR_OK ;
148173}
149174
150- lfs_error_t lfs_block_load (lfs_t * lfs ,
151- const lfs_ino_t pair [2 ], lfs_ino_t * ino ) {
152- lfs_word_t rev [2 ];
153- for (int i = 0 ; i < 2 ; i ++ ) {
154- int err = lfs -> ops -> read (lfs -> bd , (void * )& rev [i ], pair [i ], 0 , 4 );
155- if (err ) {
156- return err ;
157- }
158- }
159-
160- for (int i = 0 ; i < 2 ; i ++ ) {
161- lfs_ino_t check = pair [(rev [1 ] > rev [0 ]) ? 1 - i : i ];
162- int err = lfs_check (lfs , check );
163- if (err == LFS_ERROR_CORRUPT ) {
164- continue ;
165- } else if (err ) {
166- return err ;
167- }
168-
169- return check ;
170- }
171-
172- LFS_ERROR ("Corrupted dir at %d %d" , pair [0 ], pair [1 ]);
173- return LFS_ERROR_CORRUPT ;
174- }
175-
176- struct lfs_read_region {
175+ struct lfs_fetch_region {
177176 lfs_off_t off ;
178177 lfs_size_t size ;
179178 void * data ;
180179};
181180
182- lfs_error_t lfs_pair_read (lfs_t * lfs , lfs_ino_t pair [2 ],
183- int count , const struct lfs_read_region * regions ) {
181+ lfs_error_t lfs_pair_fetch (lfs_t * lfs , lfs_ino_t pair [2 ],
182+ int count , const struct lfs_fetch_region * regions ) {
184183 int checked = 0 ;
185184 int rev = 0 ;
186185 for (int i = 0 ; i < 2 ; i ++ ) {
@@ -192,12 +191,13 @@ lfs_error_t lfs_pair_read(lfs_t *lfs, lfs_ino_t pair[2],
192191 }
193192
194193 // TODO diff these
195- if (checked > 0 && rev > nrev ) {
194+ if (checked > 0 && lfs_diff ( nrev , rev ) < 0 ) {
196195 continue ;
197196 }
198197
199- err = lfs_check (lfs , pair [i ]);
198+ err = lfs_check (lfs , pair [0 ]);
200199 if (err == LFS_ERROR_CORRUPT ) {
200+ lfs_swap (& pair [0 ], & pair [1 ]);
201201 continue ;
202202 } else if (err ) {
203203 return err ;
@@ -223,14 +223,14 @@ lfs_error_t lfs_pair_read(lfs_t *lfs, lfs_ino_t pair[2],
223223 return 0 ;
224224}
225225
226- struct lfs_write_region {
226+ struct lfs_commit_region {
227227 lfs_off_t off ;
228228 lfs_size_t size ;
229229 const void * data ;
230230};
231231
232- lfs_error_t lfs_pair_write (lfs_t * lfs , lfs_ino_t pair [2 ],
233- int count , const struct lfs_write_region * regions ) {
232+ lfs_error_t lfs_pair_commit (lfs_t * lfs , lfs_ino_t pair [2 ],
233+ int count , const struct lfs_commit_region * regions ) {
234234 uint32_t crc = 0xffffffff ;
235235 int err = lfs -> ops -> erase (lfs -> bd ,
236236 pair [0 ], 0 , lfs -> info .erase_size );
@@ -281,7 +281,7 @@ lfs_error_t lfs_pair_write(lfs_t *lfs, lfs_ino_t pair[2],
281281 return 0 ;
282282}
283283
284- static lfs_error_t lfs_dir_make (lfs_t * lfs , lfs_dir_t * dir ) {
284+ lfs_error_t lfs_dir_make (lfs_t * lfs , lfs_dir_t * dir , lfs_ino_t parent [ 2 ] ) {
285285 // Allocate pair of dir blocks
286286 for (int i = 0 ; i < 2 ; i ++ ) {
287287 int err = lfs_alloc (lfs , & dir -> pair [i ]);
@@ -292,30 +292,193 @@ static lfs_error_t lfs_dir_make(lfs_t *lfs, lfs_dir_t *dir) {
292292
293293 // Rather than clobbering one of the blocks we just pretend
294294 // the revision may be valid
295- int err = lfs -> ops -> read (lfs -> bd , (void * )& dir -> d .rev ,
296- dir -> pair [1 ], 0 , 4 );
295+ int err = lfs -> ops -> read (lfs -> bd , (void * )& dir -> d .rev , dir -> pair [1 ], 0 , 4 );
297296 if (err ) {
298297 return err ;
299298 }
300299 dir -> d .rev += 1 ;
301300
302301 // Other defaults
302+ dir -> i = sizeof (struct lfs_disk_dir );
303303 dir -> d .size = sizeof (struct lfs_disk_dir );
304304 dir -> d .tail [0 ] = 0 ;
305305 dir -> d .tail [1 ] = 0 ;
306- dir -> d .parent [0 ] = 0 ;
307- dir -> d .parent [1 ] = 0 ;
308306
309307 // TODO sort this out
310308 dir -> d .free = lfs -> free .d ;
311309
312- // Write out to memory
313- return lfs_pair_write (lfs , dir -> pair ,
314- 1 , (struct lfs_write_region [1 ]){
310+ if (parent ) {
311+ // Create '..' entry
312+ lfs_entry_t entry = {
313+ .d .type = LFS_TYPE_DIR ,
314+ .d .len = sizeof (entry .d ) + 2 ,
315+ .d .u .dir [0 ] = parent [0 ],
316+ .d .u .dir [1 ] = parent [1 ],
317+ };
318+
319+ dir -> d .size += entry .d .len ;
320+
321+ // Write out to memory
322+ return lfs_pair_commit (lfs , dir -> pair ,
323+ 3 , (struct lfs_commit_region [3 ]){
324+ {0 , sizeof (dir -> d ), & dir -> d },
325+ {sizeof (dir -> d ), sizeof (entry .d ), & entry .d },
326+ {sizeof (dir -> d )+ sizeof (entry .d ), 2 , ".." },
327+ });
328+ } else {
329+ return lfs_pair_commit (lfs , dir -> pair ,
330+ 1 , (struct lfs_commit_region [1 ]){
331+ {0 , sizeof (dir -> d ), & dir -> d },
332+ });
333+ }
334+ }
335+
336+ lfs_error_t lfs_dir_fetch (lfs_t * lfs , lfs_dir_t * dir , lfs_ino_t pair [2 ]) {
337+ dir -> pair [0 ] = pair [0 ];
338+ dir -> pair [1 ] = pair [1 ];
339+ dir -> i = sizeof (dir -> d );
340+
341+ int err = lfs_pair_fetch (lfs , dir -> pair ,
342+ 1 , (struct lfs_fetch_region [1 ]) {
315343 {0 , sizeof (dir -> d ), & dir -> d }
316344 });
345+
346+ if (err == LFS_ERROR_CORRUPT ) {
347+ LFS_ERROR ("Corrupted dir at %d %d" , pair [0 ], pair [1 ]);
348+ }
349+
350+ return err ;
317351}
318352
353+ lfs_error_t lfs_dir_next (lfs_t * lfs , lfs_dir_t * dir , lfs_entry_t * entry ) {
354+ while (true) {
355+ // TODO iterate down list
356+ entry -> dir [0 ] = dir -> pair [0 ];
357+ entry -> dir [1 ] = dir -> pair [1 ];
358+ entry -> off = dir -> i ;
359+
360+ if (dir -> d .size - dir -> i < sizeof (entry -> d )) {
361+ return LFS_ERROR_NO_ENTRY ;
362+ }
363+
364+ int err = lfs -> ops -> read (lfs -> bd , (void * )& entry -> d ,
365+ dir -> pair [1 ], dir -> i , sizeof (entry -> d ));
366+ if (err ) {
367+ return err ;
368+ }
369+
370+ dir -> i += entry -> d .len ;
371+
372+ // Skip any unknown entries
373+ if (entry -> d .type == 1 || entry -> d .type == 2 ) {
374+ return 0 ;
375+ }
376+ }
377+ }
378+
379+ lfs_error_t lfs_dir_find (lfs_t * lfs , lfs_dir_t * dir ,
380+ const char * path , lfs_entry_t * entry ) {
381+ // TODO follow directories
382+ lfs_size_t pathlen = strcspn (path , "/" );
383+ while (true) {
384+ int err = lfs_dir_next (lfs , dir , entry );
385+ if (err ) {
386+ return err ;
387+ }
388+
389+ if (entry -> d .len - sizeof (entry -> d ) != pathlen ) {
390+ continue ;
391+ }
392+
393+ int ret = lfs_bd_cmp (lfs , entry -> dir [1 ],
394+ entry -> off + sizeof (entry -> d ), pathlen , path );
395+ if (ret < 0 ) {
396+ return ret ;
397+ }
398+
399+ // Found match
400+ if (ret == true) {
401+ return 0 ;
402+ }
403+ }
404+ }
405+
406+ lfs_error_t lfs_dir_alloc (lfs_t * lfs , lfs_dir_t * dir ,
407+ const char * path , lfs_entry_t * entry , uint16_t len ) {
408+ int err = lfs_dir_find (lfs , dir , path , entry );
409+ if (err != LFS_ERROR_NO_ENTRY ) {
410+ return err ? err : LFS_ERROR_EXISTS ;
411+ }
412+
413+ // Check if we fit
414+ if (dir -> d .size + len > lfs -> info .erase_size - 4 ) {
415+ return -1 ; // TODO make fit
416+ }
417+
418+ return 0 ;
419+ }
420+
421+ lfs_error_t lfs_dir_open (lfs_t * lfs , lfs_dir_t * dir , const char * path ) {
422+ int err = lfs_dir_fetch (lfs , dir , lfs -> cwd );
423+ if (err ) {
424+ return err ;
425+ }
426+
427+ lfs_entry_t entry ;
428+ err = lfs_dir_find (lfs , dir , path , & entry );
429+ if (err ) {
430+ return err ;
431+ } else if (entry .d .type != LFS_TYPE_DIR ) {
432+ return LFS_ERROR_NOT_DIR ;
433+ }
434+
435+ return lfs_dir_fetch (lfs , dir , entry .d .u .dir );
436+ }
437+
438+ lfs_error_t lfs_dir_close (lfs_t * lfs , lfs_dir_t * dir ) {
439+ // Do nothing, dir is always synchronized
440+ return 0 ;
441+ }
442+
443+ lfs_error_t lfs_mkdir (lfs_t * lfs , const char * path ) {
444+ // Allocate entry for directory
445+ lfs_dir_t cwd ;
446+ int err = lfs_dir_fetch (lfs , & cwd , lfs -> cwd );
447+ if (err ) {
448+ return err ;
449+ }
450+
451+ lfs_entry_t entry ;
452+ err = lfs_dir_alloc (lfs , & cwd , path ,
453+ & entry , sizeof (entry .d )+ strlen (path ));
454+ if (err ) {
455+ return err ;
456+ }
457+
458+ // Build up new directory
459+ lfs_dir_t dir ;
460+ err = lfs_dir_make (lfs , & dir , cwd .pair ); // TODO correct parent?
461+ if (err ) {
462+ return err ;
463+ }
464+
465+ entry .d .type = 2 ;
466+ entry .d .len = sizeof (entry .d ) + strlen (path );
467+ entry .d .u .dir [0 ] = dir .pair [0 ];
468+ entry .d .u .dir [1 ] = dir .pair [1 ];
469+
470+ cwd .d .rev += 1 ;
471+ cwd .d .size += entry .d .len ;
472+
473+ return lfs_pair_commit (lfs , entry .dir ,
474+ 3 , (struct lfs_commit_region [3 ]) {
475+ {0 , sizeof (cwd .d ), & cwd .d },
476+ {entry .off , sizeof (entry .d ), & entry .d },
477+ {entry .off + sizeof (entry .d ), entry .d .len - sizeof (entry .d ), path }
478+ });
479+ }
480+
481+
319482
320483// Little filesystem operations
321484lfs_error_t lfs_create (lfs_t * lfs , lfs_bd_t * bd , const struct lfs_bd_ops * ops ) {
@@ -361,13 +524,16 @@ lfs_error_t lfs_format(lfs_t *lfs) {
361524 }
362525 }
363526
364- lfs_dir_t root ;
365527 {
366528 // Write root directory
367- int err = lfs_dir_make (lfs , & root );
529+ lfs_dir_t root ;
530+ int err = lfs_dir_make (lfs , & root , 0 );
368531 if (err ) {
369532 return err ;
370533 }
534+
535+ lfs -> cwd [0 ] = root .pair [0 ];
536+ lfs -> cwd [1 ] = root .pair [1 ];
371537 }
372538
373539 {
@@ -376,16 +542,16 @@ lfs_error_t lfs_format(lfs_t *lfs) {
376542 .pair = {0 , 1 },
377543 .d .rev = 1 ,
378544 .d .size = sizeof (struct lfs_disk_superblock ),
379- .d .root = {root . pair [0 ], root . pair [1 ]},
545+ .d .root = {lfs -> cwd [0 ], lfs -> cwd [1 ]},
380546 .d .magic = {"littlefs" },
381547 .d .block_size = info .erase_size ,
382548 .d .block_count = info .total_size / info .erase_size ,
383549 };
384550
385551 for (int i = 0 ; i < 2 ; i ++ ) {
386552 lfs_ino_t block = superblock .pair [0 ];
387- int err = lfs_pair_write (lfs , superblock .pair ,
388- 1 , (struct lfs_write_region [1 ]){
553+ int err = lfs_pair_commit (lfs , superblock .pair ,
554+ 1 , (struct lfs_commit_region [1 ]){
389555 {0 , sizeof (superblock .d ), & superblock .d }
390556 });
391557
@@ -400,3 +566,32 @@ lfs_error_t lfs_format(lfs_t *lfs) {
400566 return 0 ;
401567}
402568
569+ lfs_error_t lfs_mount (lfs_t * lfs ) {
570+ struct lfs_bd_info info ;
571+ lfs_error_t err = lfs -> ops -> info (lfs -> bd , & info );
572+ if (err ) {
573+ return err ;
574+ }
575+
576+ lfs_superblock_t superblock ;
577+ err = lfs_pair_fetch (lfs ,
578+ (lfs_ino_t [2 ]){0 , 1 },
579+ 1 , (struct lfs_fetch_region [1 ]){
580+ {0 , sizeof (superblock .d ), & superblock .d }
581+ });
582+
583+ if ((err == LFS_ERROR_CORRUPT ||
584+ memcmp (superblock .d .magic , "littlefs" , 8 ) != 0 )) {
585+ LFS_ERROR ("Invalid superblock at %d %d\n" , 0 , 1 );
586+ return LFS_ERROR_CORRUPT ;
587+ }
588+
589+ printf ("superblock %d %d\n" ,
590+ superblock .d .block_size ,
591+ superblock .d .block_count );
592+
593+ lfs -> cwd [0 ] = superblock .d .root [0 ];
594+ lfs -> cwd [1 ] = superblock .d .root [1 ];
595+
596+ return err ;
597+ }
0 commit comments