Browse Source

Pulled in fixes for additional path corner cases

Pulled in 015b86b. Merging this now avoids duplicate effort restructuring
the path lookup logic.
Christopher Haster 7 years ago
parent
commit
3914cdf39f
2 changed files with 53 additions and 38 deletions
  1. 37 38
      lfs.c
  2. 16 0
      tests/test_paths.sh

+ 37 - 38
lfs.c

@@ -1273,21 +1273,19 @@ static int32_t lfs_dir_get(lfs_t *lfs, lfs_mdir_t *dir,
 }
 
 static int32_t lfs_dir_lookup(lfs_t *lfs, lfs_mdir_t *dir, const char **path) {
-    lfs_block_t pair[2] = {lfs->root[0], lfs->root[1]};
+    // we reduce path to a single name if we can find it
     const char *name = *path;
-    lfs_size_t namelen;
-    int32_t tag;
+    *path = NULL;
+
+    // default to root dir
+    int32_t tag = LFS_MKTAG(LFS_TYPE_DIR, 0x3ff, 0);
+    lfs_block_t pair[2] = {lfs->root[0], lfs->root[1]};
 
     while (true) {
-    nextname:
+nextname:
         // skip slashes
         name += strspn(name, "/");
-        namelen = strcspn(name, "/");
-
-        if (name[0] == '\0') {
-            // special case for root dir
-            return LFS_MKTAG(LFS_TYPE_DIR, 0x3ff, 0);
-        }
+        lfs_size_t namelen = strcspn(name, "/");
 
         // skip '.' and root '..'
         if ((namelen == 1 && memcmp(name, ".", 1) == 0) ||
@@ -1320,10 +1318,31 @@ static int32_t lfs_dir_lookup(lfs_t *lfs, lfs_mdir_t *dir, const char **path) {
             suffix += sufflen;
         }
 
-        // update what we've found
-        *path = name;
+        // found path
+        if (name[0] == '\0') {
+            return tag;
+        }
 
-        // find path
+        // update what we've found if path is only a name
+        if (strchr(name, '/') == NULL) {
+            *path = name;
+        }
+
+        // only continue if we hit a directory
+        if (lfs_tagtype(tag) != LFS_TYPE_DIR) {
+            return LFS_ERR_NOTDIR;
+        }
+
+        // grab the entry data
+        if (lfs_tagid(tag) != 0x3ff) {
+            int32_t res = lfs_dir_get(lfs, dir, 0x7c3ff000,
+                    LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tagid(tag), 8), pair);
+            if (res < 0) {
+                return res;
+            }
+        }
+
+        // find entry matching name
         while (true) {
             tag = lfs_dir_find(lfs, dir, pair, 0x7c000fff,
                     LFS_MKTAG(LFS_TYPE_NAME, 0, namelen), name);
@@ -1337,6 +1356,7 @@ static int32_t lfs_dir_lookup(lfs_t *lfs, lfs_mdir_t *dir, const char **path) {
             }
 
             if (!dir->split) {
+                // couldn't find it
                 return LFS_ERR_NOENT;
             }
 
@@ -1344,26 +1364,8 @@ static int32_t lfs_dir_lookup(lfs_t *lfs, lfs_mdir_t *dir, const char **path) {
             pair[1] = dir->tail[1];
         }
 
+        // to next name
         name += namelen;
-        name += strspn(name, "/");
-        if (name[0] == '\0') {
-            return tag;
-        }
-
-        // don't continue on if we didn't hit a directory
-        // TODO update with what's on master?
-        if (lfs_tagtype(tag) != LFS_TYPE_DIR) {
-            return LFS_ERR_NOTDIR;
-        }
-
-        // TODO optimize grab for inline files and like?
-        // TODO would this mean more code?
-        // grab the entry data
-        int32_t res = lfs_dir_get(lfs, dir, 0x7c3ff000,
-                LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tagid(tag), 8), pair);
-        if (res < 0) {
-            return res;
-        }
     }
 }
 
@@ -1408,11 +1410,8 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
 
     lfs_mdir_t cwd;
     int32_t res = lfs_dir_lookup(lfs, &cwd, &path);
-    if (res != LFS_ERR_NOENT || strchr(path, '/') != NULL) {
-        if (res >= 0) {
-            return LFS_ERR_EXIST;
-        }
-        return res;
+    if (res != LFS_ERR_NOENT || !path) {
+        return (res < 0) ? res : LFS_ERR_EXIST;
     }
 
     // check that name fits
@@ -1806,7 +1805,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
     // allocate entry for file if it doesn't exist
     lfs_mdir_t cwd;
     int32_t tag = lfs_dir_lookup(lfs, &cwd, &path);
-    if (tag < 0 && (tag != LFS_ERR_NOENT || strchr(path, '/') != NULL)) {
+    if (tag < 0 && (tag != LFS_ERR_NOENT || !path)) {
         return tag;
     }
 

+ 16 - 0
tests/test_paths.sh

@@ -90,6 +90,22 @@ tests/test.py << TEST
     lfs_unmount(&lfs) => 0;
 TEST
 
+echo "--- Trailing dot path tests ---"
+tests/test.py << TEST
+    lfs_mount(&lfs, &cfg) => 0;
+    lfs_stat(&lfs, "tea/hottea/", &info) => 0;
+    strcmp(info.name, "hottea") => 0;
+    lfs_stat(&lfs, "tea/hottea/.", &info) => 0;
+    strcmp(info.name, "hottea") => 0;
+    lfs_stat(&lfs, "tea/hottea/./.", &info) => 0;
+    strcmp(info.name, "hottea") => 0;
+    lfs_stat(&lfs, "tea/hottea/..", &info) => 0;
+    strcmp(info.name, "tea") => 0;
+    lfs_stat(&lfs, "tea/hottea/../.", &info) => 0;
+    strcmp(info.name, "tea") => 0;
+    lfs_unmount(&lfs) => 0;
+TEST
+
 echo "--- Root dot dot path tests ---"
 tests/test.py << TEST
     lfs_mount(&lfs, &cfg) => 0;