From 1f13006e36dec7d2616de61ae707b7c7089c2846 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 14 Apr 2017 18:27:06 -0500 Subject: [PATCH] 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. --- Makefile | 2 +- lfs.c | 43 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 1c94a8f..93ba9bb 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ size: $(OBJ) $(SIZE) -t $^ .SUFFIXES: -test: test_format test_dirs test_files test_alloc test_orphan +test: test_format test_dirs test_files test_alloc test_orphan test_paths test_%: tests/test_%.sh ./$< diff --git a/lfs.c b/lfs.c index 2154e03..6f96fe3 100644 --- a/lfs.c +++ b/lfs.c @@ -627,9 +627,47 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir, const char **path, lfs_entry_t *entry) { + const char *pathname = *path; + size_t pathlen; + while (true) { - const char *pathname = *path; - lfs_size_t pathlen = strcspn(pathname, "/"); + nextname: + // skip slashes + pathname += strspn(pathname, "/"); + pathlen = strcspn(pathname, "/"); + + // skip '.' and root '..' + if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) || + (pathlen == 2 && memcmp(pathname, "..", 2) == 0)) { + pathname += pathlen; + goto nextname; + } + + // skip if matched by '..' in name + const char *suffix = pathname + pathlen; + size_t sufflen; + int depth = 1; + while (true) { + suffix += strspn(suffix, "/"); + sufflen = strcspn(suffix, "/"); + if (sufflen == 0) { + break; + } + + if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { + depth -= 1; + if (depth == 0) { + pathname = suffix + sufflen; + goto nextname; + } + } else { + depth += 1; + } + + suffix += sufflen; + } + + // find path while (true) { int err = lfs_dir_next(lfs, dir, entry); if (err) { @@ -658,6 +696,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir, return 0; } + // continue on if we hit a directory if (entry->d.type != LFS_TYPE_DIR) { return LFS_ERROR_NOT_DIR; }