소스 검색

Fixed issue with superblock breaking lfs_dir_seek

The superblock entry takes up id 0 in the root directory (not all
entries are files, though currently the superblock is the only
exception). Normally, reading a directory correctly skips the
superblock and only reports non-superblock files.

However, this doesn't work perfectly for lfs_dir_seek, which tries
to be clever to not touch the disk.

Fortunately, we can fix this by adding an offset for the superblock.
This will only work while the superblock is the only non-file entry,
otherwise we would need to touch the disk to properly seek in a
directory (though we already touch the disk a bit to get dir-tails
during seeks).

Found by jhartika
Christopher Haster 6 년 전
부모
커밋
0197b18100
2개의 변경된 파일84개의 추가작업 그리고 4개의 파일을 삭제
  1. 10 4
      lfs.c
  2. 74 0
      tests/test_seek.sh

+ 10 - 4
lfs.c

@@ -2068,10 +2068,14 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
     dir->pos = lfs_min(2, off);
     off -= dir->pos;
 
-    while (off != 0) {
-        dir->id = lfs_min(dir->m.count, off);
-        dir->pos += dir->id;
-        off -= dir->id;
+    // skip superblock entry
+    dir->id = (off > 0 && lfs_pair_cmp(dir->head, lfs->root) == 0);
+
+    while (off > 0) {
+        int diff = lfs_min(dir->m.count - dir->id, off);
+        dir->id += diff;
+        dir->pos += diff;
+        off -= diff;
 
         if (dir->id == dir->m.count) {
             if (!dir->m.split) {
@@ -2084,6 +2088,8 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
                 LFS_TRACE("lfs_dir_seek -> %d", err);
                 return err;
             }
+
+            dir->id = 0;
         }
     }
 

+ 74 - 0
tests/test_seek.sh

@@ -428,4 +428,78 @@ scripts/test.py << TEST
 TEST
 done
 
+echo "--- Root seek test ---"
+./scripts/test.py << TEST
+    lfs_mount(&lfs, &cfg) => 0;
+    for (int i = 3; i < $MEDIUMSIZE; i++) {
+        sprintf(path, "hi%03d", i);
+        lfs_mkdir(&lfs, path) => 0;
+    }
+
+    lfs_dir_open(&lfs, &dir, "/") => 0;
+    for (int i = 0; i < $MEDIUMSIZE; i++) {
+        if (i == 0) {
+            sprintf(path, ".");
+        } else if (i == 1) {
+            sprintf(path, "..");
+        } else if (i == 2) {
+            sprintf(path, "hello");
+        } else {
+            sprintf(path, "hi%03d", i);
+        }
+        lfs_dir_read(&lfs, &dir, &info) => 1;
+        strcmp(path, info.name) => 0;
+    }
+    lfs_dir_read(&lfs, &dir, &info) => 0;
+    lfs_dir_close(&lfs, &dir) => 0;
+
+    for (int j = 0; j < $MEDIUMSIZE; j++) {
+        lfs_soff_t off = -1;
+
+        lfs_dir_open(&lfs, &dir, "/") => 0;
+        for (int i = 0; i < $MEDIUMSIZE; i++) {
+            if (i == 0) {
+                sprintf(path, ".");
+            } else if (i == 1) {
+                sprintf(path, "..");
+            } else if (i == 2) {
+                sprintf(path, "hello");
+            } else {
+                sprintf(path, "hi%03d", i);
+            }
+
+            if (i == j) {
+                off = lfs_dir_tell(&lfs, &dir);
+                off >= 0 => true;
+            }
+
+            lfs_dir_read(&lfs, &dir, &info) => 1;
+            strcmp(path, info.name) => 0;
+        }
+        lfs_dir_read(&lfs, &dir, &info) => 0;
+        lfs_dir_close(&lfs, &dir) => 0;
+
+        lfs_dir_open(&lfs, &dir, "/") => 0;
+        lfs_dir_seek(&lfs, &dir, off) => 0;
+        for (int i = j; i < $MEDIUMSIZE; i++) {
+            if (i == 0) {
+                sprintf(path, ".");
+            } else if (i == 1) {
+                sprintf(path, "..");
+            } else if (i == 2) {
+                sprintf(path, "hello");
+            } else {
+                sprintf(path, "hi%03d", i);
+            }
+
+            lfs_dir_read(&lfs, &dir, &info) => 1;
+            strcmp(path, info.name) => 0;
+        }
+        lfs_dir_read(&lfs, &dir, &info) => 0;
+        lfs_dir_close(&lfs, &dir) => 0;
+    }
+
+    lfs_unmount(&lfs) => 0;
+TEST
+
 scripts/results.py