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.
This commit is contained in:
Christopher Haster
2017-04-14 18:27:06 -05:00
parent c25c893219
commit 1f13006e36
2 changed files with 42 additions and 3 deletions

View File

@@ -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
./$<

43
lfs.c
View File

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