Browse Source

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.
Christopher Haster 8 năm trước cách đây
mục cha
commit
1f13006e36
2 tập tin đã thay đổi với 42 bổ sung3 xóa
  1. 1 1
      Makefile
  2. 41 2
      lfs.c

+ 1 - 1
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
 	./$<
 

+ 41 - 2
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;
         }