Skip to content

Commit 53674cb

Browse files
committed
Added limited support for directories
This comes with a lot of scafolding put into place around the core of the filesystem. Added operations: - append an entry to a directory - find an entry in a directory - iterate over entries in a directory Some to do: - Chaining multiple directory blocks - Recursion on directory operations
1 parent 106b06a commit 53674cb

File tree

2 files changed

+261
-63
lines changed

2 files changed

+261
-63
lines changed

lfs.c

Lines changed: 242 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
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+
1317
static 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+
2954
static lfs_error_t lfs_alloc(lfs_t *lfs, lfs_ino_t *ino);
3055
static 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
321484
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) {
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

Comments
 (0)