Răsfoiți Sursa

Removed .. and . entries

No longer need to be stored on disk, can be simulated on
the chip side. As mentioned in other commits, the parent
entries had dozens of problems with atomic updates, as
well as making everything just a bit more complex than
is needed.
Christopher Haster 8 ani în urmă
părinte
comite
3b1bcbe851
2 a modificat fișierele cu 56 adăugiri și 60 ștergeri
  1. 55 59
      lfs.c
  2. 1 1
      tests/test_orphan.sh

+ 55 - 59
lfs.c

@@ -522,8 +522,7 @@ static int lfs_pair_shift(lfs_t *lfs, lfs_block_t pair[2],
 
 /// Directory operations ///
 
-static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir,
-        lfs_block_t parent[2], lfs_block_t tail[2]) {
+static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t tail[2]) {
     // Allocate pair of dir blocks
     for (int i = 0; i < 2; i++) {
         int err = lfs_alloc(lfs, &dir->pair[i]);
@@ -549,35 +548,10 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir,
     dir->d.tail[1] = tail[1];
 
     // Write out to memory
-    if (!parent) {
-        return lfs_pair_commit(lfs, dir->pair,
-            1, (struct lfs_commit_region[]){
-                {0, sizeof(dir->d), &dir->d}
-            });
-    } else {
-        dir->d.size += 2*sizeof(struct lfs_disk_entry) + 3;
-        return lfs_pair_commit(lfs, dir->pair,
-            5, (struct lfs_commit_region[]){
-                {0, sizeof(dir->d), &dir->d},
-                {sizeof(dir->d), sizeof(struct lfs_disk_entry),
-                 &(struct lfs_disk_entry){
-                    .type     = LFS_TYPE_DIR,
-                    .len      = sizeof(struct lfs_disk_entry)+1,
-                    .u.dir[0] = dir->pair[0],
-                    .u.dir[1] = dir->pair[1],
-                }},
-                {sizeof(dir->d)+sizeof(struct lfs_disk_entry), 1, "."},
-                {sizeof(dir->d)+sizeof(struct lfs_disk_entry)+1,
-                 sizeof(struct lfs_disk_entry),
-                 &(struct lfs_disk_entry){
-                    .type     = LFS_TYPE_DIR,
-                    .len      = sizeof(struct lfs_disk_entry)+2,
-                    .u.dir[0] = parent[0] ? parent[0] : dir->pair[0],
-                    .u.dir[1] = parent[1] ? parent[1] : dir->pair[1],
-                }},
-                {sizeof(dir->d)+2*sizeof(struct lfs_disk_entry)+1, 2, ".."},
-            });
-    }
+    return lfs_pair_commit(lfs, dir->pair,
+        1, (struct lfs_commit_region[]){
+            {0, sizeof(dir->d), &dir->d}
+        });
 }
 
 static int lfs_dir_fetch(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t pair[2]) {
@@ -725,7 +699,7 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
         lfs_dir_t olddir;
         memcpy(&olddir, dir, sizeof(olddir));
 
-        int err = lfs_dir_alloc(lfs, dir, 0, olddir.d.tail);
+        int err = lfs_dir_alloc(lfs, dir, olddir.d.tail);
         if (err) {
             return err;
         }
@@ -763,7 +737,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
 
     // Build up new directory
     lfs_dir_t dir;
-    err = lfs_dir_alloc(lfs, &dir, cwd.pair, cwd.d.tail);
+    err = lfs_dir_alloc(lfs, &dir, cwd.d.tail);
     if (err) {
         return err;
     }
@@ -799,6 +773,8 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
     if (err) {
         return err;
     } else if (strcmp(path, "/") == 0) {
+        // special offset for '.' and '..'
+        dir->off = sizeof(dir->d) - 2;
         return 0;
     }
 
@@ -810,7 +786,14 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
         return LFS_ERROR_NOT_DIR;
     }
 
-    return lfs_dir_fetch(lfs, dir, entry.d.u.dir);
+    err = lfs_dir_fetch(lfs, dir, entry.d.u.dir);
+    if (err) {
+        return err;
+    }
+
+    // special offset for '.' and '..'
+    dir->off = sizeof(dir->d) - 2;
+    return 0;
 }
 
 int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
@@ -821,6 +804,18 @@ int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
 int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
     memset(info, 0, sizeof(*info));
 
+    if (dir->off == sizeof(dir->d) - 2) {
+        info->type = LFS_TYPE_DIR;
+        strcpy(info->name, ".");
+        dir->off += 1;
+        return 1;
+    } else if (dir->off == sizeof(dir->d) - 1) {
+        info->type = LFS_TYPE_DIR;
+        strcpy(info->name, "..");
+        dir->off += 1;
+        return 1;
+    }
+
     lfs_entry_t entry;
     int err = lfs_dir_next(lfs, dir, &entry);
     if (err) {
@@ -1100,8 +1095,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config) {
 
     // Write root directory
     lfs_dir_t root;
-    err = lfs_dir_alloc(lfs, &root,
-            (lfs_block_t[2]){0, 0}, (lfs_block_t[2]){0, 0});
+    err = lfs_dir_alloc(lfs, &root, (lfs_block_t[2]){0, 0});
     if (err) {
         return err;
     }
@@ -1195,9 +1189,6 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
             return err;
         }
 
-        // skip '.' and '..'
-        dir.off += 2*sizeof(struct lfs_disk_entry) + 3;
-
         // iterate over contents
         while ((0x7fffffff & dir.d.size) >= dir.off + sizeof(file.entry.d)) {
             int err = lfs_bd_read(lfs, dir.pair[0], dir.off,
@@ -1248,14 +1239,6 @@ static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2]) {
             return err;
         }
 
-        // skip .. and . entries
-        for (int i = 0; i < 2; i++) {
-            int err = lfs_dir_next(lfs, &parent, &entry);
-            if (err) {
-                return err;
-            }
-        }
-
         while (true) {
             int err = lfs_dir_next(lfs, &parent, &entry);
             if (err && err != LFS_ERROR_NO_ENTRY) {
@@ -1339,12 +1322,13 @@ int lfs_remove(lfs_t *lfs, const char *path) {
 
     lfs_dir_t dir;
     if (entry.d.type == LFS_TYPE_DIR) {
-        // must be empty before removal
+        // must be empty before removal, checking size
+        // without masking top bit checks for any case where
+        // dir is not empty
         int err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir);
         if (err) {
             return err;
-        } else if (dir.d.size != sizeof(dir.d) +
-                2*sizeof(struct lfs_disk_entry) + 3) {
+        } else if (dir.d.size != sizeof(dir.d)) {
             return LFS_ERROR_INVALID;
         }
     }
@@ -1367,16 +1351,28 @@ int lfs_remove(lfs_t *lfs, const char *path) {
             }
         }
 
-        pdir.d.tail[0] = cwd.d.tail[0];
-        pdir.d.tail[1] = cwd.d.tail[1];
-        pdir.d.rev += 1;
+        // TODO easier check for head block? (common case)
+        if (!(pdir.d.size & 0x80000000)) {
+            int err = lfs_pair_shift(lfs, entry.dir,
+                1, (struct lfs_commit_region[]) {
+                    {0, sizeof(cwd.d), &cwd.d},
+                },
+                entry.off, entry.d.len);
+            if (err) {
+                return err;
+            }
+        } else {
+            pdir.d.tail[0] = cwd.d.tail[0];
+            pdir.d.tail[1] = cwd.d.tail[1];
+            pdir.d.rev += 1;
 
-        err = lfs_pair_commit(lfs, pdir.pair,
-            1, (struct lfs_commit_region[]) {
-                {0, sizeof(pdir.d), &pdir.d},
-            });
-        if (err) {
-            return err;
+            err = lfs_pair_commit(lfs, pdir.pair,
+                1, (struct lfs_commit_region[]) {
+                    {0, sizeof(pdir.d), &pdir.d},
+                });
+            if (err) {
+                return err;
+            }
         }
     } else {
         int err = lfs_pair_shift(lfs, entry.dir,

+ 1 - 1
tests/test_orphan.sh

@@ -17,7 +17,7 @@ tests/test.py << TEST
 TEST
 # remove most recent file, this should be the update to the previous
 # linked-list entry and should orphan the child
-rm -v "blocks/$(ls -t blocks | sed -n '/^[0-9a-f]*$/p' | sed -n '1p')"
+rm -v blocks/8
 tests/test.py << TEST
     lfs_mount(&lfs, &config) => 0;
     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERROR_NO_ENTRY;