Skip to content

Commit 1f13006

Browse files
committed
Added dir navigation without needing parent entries
This should be the last step to removing the need for parent entries. Parent entries cause all sort of problems with atomic directory updates, especially related to moving/deleting directories. I couldn't figure out a parser for '..' entries without, O(n^2) runtime, a stack, or modifying the path itself. Since the goal is constant memory consumption, I went with the O(n^2) runtime solution, but this may need to be optimized later.
1 parent c25c893 commit 1f13006

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ size: $(OBJ)
3131
$(SIZE) -t $^
3232

3333
.SUFFIXES:
34-
test: test_format test_dirs test_files test_alloc test_orphan
34+
test: test_format test_dirs test_files test_alloc test_orphan test_paths
3535
test_%: tests/test_%.sh
3636
./$<
3737

lfs.c

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -627,9 +627,47 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
627627

628628
static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
629629
const char **path, lfs_entry_t *entry) {
630+
const char *pathname = *path;
631+
size_t pathlen;
632+
630633
while (true) {
631-
const char *pathname = *path;
632-
lfs_size_t pathlen = strcspn(pathname, "/");
634+
nextname:
635+
// skip slashes
636+
pathname += strspn(pathname, "/");
637+
pathlen = strcspn(pathname, "/");
638+
639+
// skip '.' and root '..'
640+
if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) ||
641+
(pathlen == 2 && memcmp(pathname, "..", 2) == 0)) {
642+
pathname += pathlen;
643+
goto nextname;
644+
}
645+
646+
// skip if matched by '..' in name
647+
const char *suffix = pathname + pathlen;
648+
size_t sufflen;
649+
int depth = 1;
650+
while (true) {
651+
suffix += strspn(suffix, "/");
652+
sufflen = strcspn(suffix, "/");
653+
if (sufflen == 0) {
654+
break;
655+
}
656+
657+
if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) {
658+
depth -= 1;
659+
if (depth == 0) {
660+
pathname = suffix + sufflen;
661+
goto nextname;
662+
}
663+
} else {
664+
depth += 1;
665+
}
666+
667+
suffix += sufflen;
668+
}
669+
670+
// find path
633671
while (true) {
634672
int err = lfs_dir_next(lfs, dir, entry);
635673
if (err) {
@@ -658,6 +696,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
658696
return 0;
659697
}
660698

699+
// continue on if we hit a directory
661700
if (entry->d.type != LFS_TYPE_DIR) {
662701
return LFS_ERROR_NOT_DIR;
663702
}

0 commit comments

Comments
 (0)