10
10
#include <stdbool.h>
11
11
12
12
13
+ static int lfs_diff (uint32_t a , uint32_t b ) {
14
+ return (int )(unsigned )(a - b );
15
+ }
16
+
13
17
static uint32_t lfs_crc (const uint8_t * data , lfs_size_t size , uint32_t crc ) {
14
18
static const uint32_t rtable [16 ] = {
15
19
0x00000000 , 0x1db71064 , 0x3b6e20c8 , 0x26d930ac ,
@@ -26,6 +30,27 @@ static uint32_t lfs_crc(const uint8_t *data, lfs_size_t size, uint32_t crc) {
26
30
return crc ;
27
31
}
28
32
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
+
29
54
static lfs_error_t lfs_alloc (lfs_t * lfs , lfs_ino_t * ino );
30
55
static lfs_error_t lfs_free (lfs_t * lfs , lfs_ino_t ino );
31
56
@@ -147,40 +172,14 @@ lfs_error_t lfs_check(lfs_t *lfs, lfs_ino_t block) {
147
172
return (crc != 0 ) ? LFS_ERROR_CORRUPT : LFS_ERROR_OK ;
148
173
}
149
174
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 {
177
176
lfs_off_t off ;
178
177
lfs_size_t size ;
179
178
void * data ;
180
179
};
181
180
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 ) {
184
183
int checked = 0 ;
185
184
int rev = 0 ;
186
185
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],
192
191
}
193
192
194
193
// TODO diff these
195
- if (checked > 0 && rev > nrev ) {
194
+ if (checked > 0 && lfs_diff ( nrev , rev ) < 0 ) {
196
195
continue ;
197
196
}
198
197
199
- err = lfs_check (lfs , pair [i ]);
198
+ err = lfs_check (lfs , pair [0 ]);
200
199
if (err == LFS_ERROR_CORRUPT ) {
200
+ lfs_swap (& pair [0 ], & pair [1 ]);
201
201
continue ;
202
202
} else if (err ) {
203
203
return err ;
@@ -223,14 +223,14 @@ lfs_error_t lfs_pair_read(lfs_t *lfs, lfs_ino_t pair[2],
223
223
return 0 ;
224
224
}
225
225
226
- struct lfs_write_region {
226
+ struct lfs_commit_region {
227
227
lfs_off_t off ;
228
228
lfs_size_t size ;
229
229
const void * data ;
230
230
};
231
231
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 ) {
234
234
uint32_t crc = 0xffffffff ;
235
235
int err = lfs -> ops -> erase (lfs -> bd ,
236
236
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],
281
281
return 0 ;
282
282
}
283
283
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 ] ) {
285
285
// Allocate pair of dir blocks
286
286
for (int i = 0 ; i < 2 ; i ++ ) {
287
287
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) {
292
292
293
293
// Rather than clobbering one of the blocks we just pretend
294
294
// 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 );
297
296
if (err ) {
298
297
return err ;
299
298
}
300
299
dir -> d .rev += 1 ;
301
300
302
301
// Other defaults
302
+ dir -> i = sizeof (struct lfs_disk_dir );
303
303
dir -> d .size = sizeof (struct lfs_disk_dir );
304
304
dir -> d .tail [0 ] = 0 ;
305
305
dir -> d .tail [1 ] = 0 ;
306
- dir -> d .parent [0 ] = 0 ;
307
- dir -> d .parent [1 ] = 0 ;
308
306
309
307
// TODO sort this out
310
308
dir -> d .free = lfs -> free .d ;
311
309
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 ]) {
315
343
{0 , sizeof (dir -> d ), & dir -> d }
316
344
});
345
+
346
+ if (err == LFS_ERROR_CORRUPT ) {
347
+ LFS_ERROR ("Corrupted dir at %d %d" , pair [0 ], pair [1 ]);
348
+ }
349
+
350
+ return err ;
317
351
}
318
352
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
+
319
482
320
483
// Little filesystem operations
321
484
lfs_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) {
361
524
}
362
525
}
363
526
364
- lfs_dir_t root ;
365
527
{
366
528
// 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 );
368
531
if (err ) {
369
532
return err ;
370
533
}
534
+
535
+ lfs -> cwd [0 ] = root .pair [0 ];
536
+ lfs -> cwd [1 ] = root .pair [1 ];
371
537
}
372
538
373
539
{
@@ -376,16 +542,16 @@ lfs_error_t lfs_format(lfs_t *lfs) {
376
542
.pair = {0 , 1 },
377
543
.d .rev = 1 ,
378
544
.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 ]},
380
546
.d .magic = {"littlefs" },
381
547
.d .block_size = info .erase_size ,
382
548
.d .block_count = info .total_size / info .erase_size ,
383
549
};
384
550
385
551
for (int i = 0 ; i < 2 ; i ++ ) {
386
552
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 ]){
389
555
{0 , sizeof (superblock .d ), & superblock .d }
390
556
});
391
557
@@ -400,3 +566,32 @@ lfs_error_t lfs_format(lfs_t *lfs) {
400
566
return 0 ;
401
567
}
402
568
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