Skip to content

Commit ca01b72

Browse files
committed
Added path iteration and chained directories
All path iteration all goes through the lfs_dir_find function, which manages the syntax of paths and updates the path pointer to just the name stored in the dir entry. Also added directory chaining, which allows more than one block per directory. This is a simple linked list.
1 parent 390ca33 commit ca01b72

File tree

4 files changed

+267
-60
lines changed

4 files changed

+267
-60
lines changed

lfs.c

Lines changed: 113 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ static int lfs_pair_commit(lfs_t *lfs, lfs_block_t pair[2],
310310

311311
/// Directory operations ///
312312

313-
static int lfs_dir_create(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t parent[2]) {
313+
static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t parent[2]) {
314314
// Allocate pair of dir blocks
315315
for (int i = 0; i < 2; i++) {
316316
int err = lfs_alloc(lfs, &dir->pair[i]);
@@ -328,7 +328,7 @@ static int lfs_dir_create(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t parent[2]) {
328328
dir->d.rev += 1;
329329

330330
// Calculate total size
331-
dir->d.size = sizeof(dir->d) + 2*sizeof(struct lfs_disk_entry) + 3;
331+
dir->d.size = sizeof(dir->d);
332332
dir->off = sizeof(dir->d);
333333

334334
// Other defaults
@@ -337,27 +337,35 @@ static int lfs_dir_create(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t parent[2]) {
337337
dir->d.free = lfs->free;
338338

339339
// Write out to memory
340-
return lfs_pair_commit(lfs, dir->pair,
341-
5, (struct lfs_commit_region[]){
342-
{0, sizeof(dir->d), &dir->d},
343-
{sizeof(dir->d), sizeof(struct lfs_disk_entry),
344-
&(struct lfs_disk_entry){
345-
.type = LFS_TYPE_DIR,
346-
.len = sizeof(struct lfs_disk_entry)+1,
347-
.u.dir[0] = dir->pair[0],
348-
.u.dir[1] = dir->pair[1],
349-
}},
350-
{sizeof(dir->d)+sizeof(struct lfs_disk_entry), 1, "."},
351-
{sizeof(dir->d)+sizeof(struct lfs_disk_entry)+1,
352-
sizeof(struct lfs_disk_entry),
353-
&(struct lfs_disk_entry){
354-
.type = LFS_TYPE_DIR,
355-
.len = sizeof(struct lfs_disk_entry)+2,
356-
.u.dir[0] = parent ? parent[0] : dir->pair[0],
357-
.u.dir[1] = parent ? parent[1] : dir->pair[1],
358-
}},
359-
{sizeof(dir->d)+2*sizeof(struct lfs_disk_entry)+1, 2, ".."},
360-
});
340+
if (!parent) {
341+
return lfs_pair_commit(lfs, dir->pair,
342+
1, (struct lfs_commit_region[]){
343+
{0, sizeof(dir->d), &dir->d}
344+
});
345+
} else {
346+
dir->d.size += 2*sizeof(struct lfs_disk_entry) + 3;
347+
return lfs_pair_commit(lfs, dir->pair,
348+
5, (struct lfs_commit_region[]){
349+
{0, sizeof(dir->d), &dir->d},
350+
{sizeof(dir->d), sizeof(struct lfs_disk_entry),
351+
&(struct lfs_disk_entry){
352+
.type = LFS_TYPE_DIR,
353+
.len = sizeof(struct lfs_disk_entry)+1,
354+
.u.dir[0] = dir->pair[0],
355+
.u.dir[1] = dir->pair[1],
356+
}},
357+
{sizeof(dir->d)+sizeof(struct lfs_disk_entry), 1, "."},
358+
{sizeof(dir->d)+sizeof(struct lfs_disk_entry)+1,
359+
sizeof(struct lfs_disk_entry),
360+
&(struct lfs_disk_entry){
361+
.type = LFS_TYPE_DIR,
362+
.len = sizeof(struct lfs_disk_entry)+2,
363+
.u.dir[0] = parent[0] ? parent[0] : dir->pair[0],
364+
.u.dir[1] = parent[1] ? parent[1] : dir->pair[1],
365+
}},
366+
{sizeof(dir->d)+2*sizeof(struct lfs_disk_entry)+1, 2, ".."},
367+
});
368+
}
361369
}
362370

363371
static int lfs_dir_fetch(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t pair[2]) {
@@ -373,13 +381,20 @@ static int lfs_dir_fetch(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t pair[2]) {
373381

374382
static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
375383
while (true) {
376-
// TODO iterate down list
377-
entry->dir[0] = dir->pair[0];
378-
entry->dir[1] = dir->pair[1];
379-
entry->off = dir->off;
380-
381384
if (dir->d.size - dir->off < sizeof(entry->d)) {
382-
return LFS_ERROR_NO_ENTRY;
385+
if (!dir->d.tail[0]) {
386+
entry->dir[0] = dir->pair[0];
387+
entry->dir[1] = dir->pair[1];
388+
entry->off = dir->off;
389+
return LFS_ERROR_NO_ENTRY;
390+
}
391+
392+
int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
393+
if (err) {
394+
return err;
395+
}
396+
397+
dir->off = sizeof(dir->d);
383398
}
384399

385400
int err = lfs_bd_read(lfs, dir->pair[0], dir->off,
@@ -389,51 +404,92 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
389404
}
390405

391406
dir->off += entry->d.len;
392-
393-
// Skip any unknown entries
394-
if ((entry->d.type & 0xf) == 1 || (entry->d.type & 0xf) == 2) {
407+
if (entry->d.type == LFS_TYPE_REG || entry->d.type == LFS_TYPE_DIR) {
408+
entry->dir[0] = dir->pair[0];
409+
entry->dir[1] = dir->pair[1];
410+
entry->off = dir->off - entry->d.len;
395411
return 0;
396412
}
397413
}
398414
}
399415

400416
static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
401-
const char *path, lfs_entry_t *entry) {
402-
// TODO follow directories
403-
lfs_size_t pathlen = strcspn(path, "/");
417+
const char **path, lfs_entry_t *entry) {
404418
while (true) {
405-
int err = lfs_dir_next(lfs, dir, entry);
406-
if (err) {
407-
return err;
419+
const char *pathname = *path;
420+
lfs_size_t pathlen = strcspn(pathname, "/");
421+
while (true) {
422+
int err = lfs_dir_next(lfs, dir, entry);
423+
if (err) {
424+
return err;
425+
}
426+
427+
if (entry->d.len - sizeof(entry->d) != pathlen) {
428+
continue;
429+
}
430+
431+
int ret = lfs_bd_cmp(lfs, entry->dir[0],
432+
entry->off + sizeof(entry->d), pathlen, pathname);
433+
if (ret < 0) {
434+
return ret;
435+
}
436+
437+
// Found match
438+
if (ret == true) {
439+
break;
440+
}
408441
}
409442

410-
if (entry->d.len - sizeof(entry->d) != pathlen) {
411-
continue;
443+
pathname += pathlen;
444+
pathname += strspn(pathname, "/");
445+
if (pathname[0] == '\0') {
446+
return 0;
412447
}
413448

414-
int ret = lfs_bd_cmp(lfs, entry->dir[0],
415-
entry->off + sizeof(entry->d), pathlen, path);
416-
if (ret < 0) {
417-
return ret;
449+
if (entry->d.type != LFS_TYPE_DIR) {
450+
return LFS_ERROR_NOT_DIR;
418451
}
419452

420-
// Found match
421-
if (ret == true) {
422-
return 0;
453+
int err = lfs_dir_fetch(lfs, dir, entry->d.u.dir);
454+
if (err) {
455+
return err;
423456
}
457+
458+
*path = pathname;
424459
}
460+
461+
return 0;
425462
}
426463

427464
static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
428-
const char *path, lfs_entry_t *entry) {
465+
const char **path, lfs_entry_t *entry) {
429466
int err = lfs_dir_find(lfs, dir, path, entry);
430467
if (err != LFS_ERROR_NO_ENTRY) {
431468
return err ? err : LFS_ERROR_EXISTS;
432469
}
433470

434471
// Check if we fit
435-
if (dir->d.size + strlen(path) > lfs->block_size - 4) {
436-
return -1; // TODO make fit
472+
if (dir->d.size + sizeof(entry->d) + strlen(*path) > lfs->block_size - 4) {
473+
lfs_dir_t olddir;
474+
memcpy(&olddir, dir, sizeof(olddir));
475+
476+
int err = lfs_dir_alloc(lfs, dir, 0);
477+
if (err) {
478+
return err;
479+
}
480+
481+
entry->dir[0] = dir->pair[0];
482+
entry->dir[1] = dir->pair[1];
483+
entry->off = dir->off;
484+
485+
olddir.d.rev += 1;
486+
olddir.d.tail[0] = dir->pair[0];
487+
olddir.d.tail[1] = dir->pair[1];
488+
olddir.d.free = lfs->free;
489+
return lfs_pair_commit(lfs, olddir.pair,
490+
1, (struct lfs_commit_region[]){
491+
{0, sizeof(olddir.d), &olddir.d}
492+
});
437493
}
438494

439495
return 0;
@@ -448,14 +504,14 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
448504
}
449505

450506
lfs_entry_t entry;
451-
err = lfs_dir_append(lfs, &cwd, path, &entry);
507+
err = lfs_dir_append(lfs, &cwd, &path, &entry);
452508
if (err) {
453509
return err;
454510
}
455511

456512
// Build up new directory
457513
lfs_dir_t dir;
458-
err = lfs_dir_create(lfs, &dir, cwd.pair);
514+
err = lfs_dir_alloc(lfs, &dir, cwd.pair);
459515
if (err) {
460516
return err;
461517
}
@@ -494,7 +550,7 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
494550
}
495551

496552
lfs_entry_t entry;
497-
err = lfs_dir_find(lfs, dir, path, &entry);
553+
err = lfs_dir_find(lfs, dir, &path, &entry);
498554
if (err) {
499555
return err;
500556
} else if (entry.d.type != LFS_TYPE_DIR) {
@@ -546,12 +602,12 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
546602
}
547603

548604
if (flags & LFS_O_CREAT) {
549-
err = lfs_dir_append(lfs, &cwd, path, &file->entry);
605+
err = lfs_dir_append(lfs, &cwd, &path, &file->entry);
550606
if (err && err != LFS_ERROR_EXISTS) {
551607
return err;
552608
}
553609
} else {
554-
err = lfs_dir_find(lfs, &cwd, path, &file->entry);
610+
err = lfs_dir_find(lfs, &cwd, &path, &file->entry);
555611
if (err) {
556612
return err;
557613
}
@@ -789,11 +845,11 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config) {
789845

790846
// Create free list
791847
lfs->free.begin = 2;
792-
lfs->free.end = lfs->block_count;
848+
lfs->free.end = lfs->block_count-1;
793849

794850
// Write root directory
795851
lfs_dir_t root;
796-
err = lfs_dir_create(lfs, &root, 0);
852+
err = lfs_dir_alloc(lfs, &root, (lfs_block_t[2]){0, 0});
797853
if (err) {
798854
return err;
799855
}

tests/test.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ def generate(test):
1010
template = file.read()
1111

1212
lines = []
13-
1413
for line in re.split('(?<=[;{}])\n', test.read()):
15-
match = re.match('( *)(.*)=>(.*);', line, re.MULTILINE)
14+
match = re.match('(?: *\n)*( *)(.*)=>(.*);', line, re.MULTILINE)
1615
if match:
1716
tab, test, expect = match.groups()
1817
lines.append(tab+'res = {test};'.format(test=test.strip()))
@@ -33,13 +32,17 @@ def execute():
3332
subprocess.check_call(["./lfs"])
3433

3534
def main(test=None):
36-
if test:
35+
if test and not test.startswith('-'):
3736
with open(test) as file:
3837
generate(file)
3938
else:
4039
generate(sys.stdin)
4140

4241
compile()
42+
43+
if test == '-s':
44+
sys.exit(1)
45+
4346
execute()
4447

4548
if __name__ == "__main__":

tests/test_dirs.sh

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/bin/bash
22
set -eu
33

4+
LARGESIZE=128
5+
46
echo "=== Directory tests ==="
57
rm -rf blocks
68
tests/test.py << TEST
@@ -62,5 +64,65 @@ tests/test.py << TEST
6264
lfs_unmount(&lfs) => 0;
6365
TEST
6466

67+
echo "--- Nested directories ---"
68+
tests/test.py << TEST
69+
lfs_mount(&lfs, &config) => 0;
70+
lfs_mkdir(&lfs, "potato/baked") => 0;
71+
lfs_mkdir(&lfs, "potato/sweet") => 0;
72+
lfs_mkdir(&lfs, "potato/fried") => 0;
73+
lfs_unmount(&lfs) => 0;
74+
TEST
75+
tests/test.py << TEST
76+
lfs_mount(&lfs, &config) => 0;
77+
lfs_dir_open(&lfs, &dir[0], "potato") => 0;
78+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
79+
strcmp(info.name, ".") => 0;
80+
info.type => LFS_TYPE_DIR;
81+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
82+
strcmp(info.name, "..") => 0;
83+
info.type => LFS_TYPE_DIR;
84+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
85+
strcmp(info.name, "baked") => 0;
86+
info.type => LFS_TYPE_DIR;
87+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
88+
strcmp(info.name, "sweet") => 0;
89+
info.type => LFS_TYPE_DIR;
90+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
91+
strcmp(info.name, "fried") => 0;
92+
info.type => LFS_TYPE_DIR;
93+
lfs_dir_read(&lfs, &dir[0], &info) => 0;
94+
lfs_dir_close(&lfs, &dir[0]) => 0;
95+
lfs_unmount(&lfs) => 0;
96+
TEST
97+
98+
echo "--- Multi-block directory ---"
99+
tests/test.py << TEST
100+
lfs_mount(&lfs, &config) => 0;
101+
lfs_mkdir(&lfs, "cactus") => 0;
102+
for (int i = 0; i < $LARGESIZE; i++) {
103+
sprintf((char*)buffer, "cactus/test%d", i);
104+
lfs_mkdir(&lfs, (char*)buffer) => 0;
105+
}
106+
lfs_unmount(&lfs) => 0;
107+
TEST
108+
tests/test.py << TEST
109+
lfs_mount(&lfs, &config) => 0;
110+
lfs_dir_open(&lfs, &dir[0], "cactus") => 0;
111+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
112+
strcmp(info.name, ".") => 0;
113+
info.type => LFS_TYPE_DIR;
114+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
115+
strcmp(info.name, "..") => 0;
116+
info.type => LFS_TYPE_DIR;
117+
for (int i = 0; i < $LARGESIZE; i++) {
118+
sprintf((char*)buffer, "test%d", i);
119+
lfs_dir_read(&lfs, &dir[0], &info) => 1;
120+
strcmp(info.name, (char*)buffer) => 0;
121+
info.type => LFS_TYPE_DIR;
122+
}
123+
lfs_dir_read(&lfs, &dir[0], &info) => 0;
124+
lfs_unmount(&lfs) => 0;
125+
TEST
126+
65127
echo "--- Results ---"
66128
tests/stats.py

0 commit comments

Comments
 (0)