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; }