浏览代码

Fixed handling of root as target for create operations

Before this patch, when calling lfs_mkdir or lfs_file_open with root
as the target, littlefs wouldn't find the path properly and happily
run into undefined behaviour.

The fix is to populate a directory entry for root in the lfs_dir_find
function. As an added plus, this allowed several special cases around
root to be completely dropped.
Christopher Haster 7 年之前
父节点
当前提交
d9c36371e7
共有 2 个文件被更改,包括 26 次插入22 次删除
  1. 22 22
      lfs.c
  2. 4 0
      tests/test_paths.sh

+ 22 - 22
lfs.c

@@ -780,6 +780,19 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
         pathname += strspn(pathname, "/");
         pathname += strspn(pathname, "/");
         pathlen = strcspn(pathname, "/");
         pathlen = strcspn(pathname, "/");
 
 
+        // special case for root dir
+        if (pathname[0] == '\0') {
+            *entry = (lfs_entry_t){
+                .d.type = LFS_TYPE_DIR,
+                .d.elen = sizeof(entry->d) - 4,
+                .d.alen = 0,
+                .d.nlen = 0,
+                .d.u.dir[0] = lfs->root[0],
+                .d.u.dir[1] = lfs->root[1],
+            };
+            return 0;
+        }
+
         // skip '.' and root '..'
         // skip '.' and root '..'
         if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) ||
         if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) ||
             (pathlen == 2 && memcmp(pathname, "..", 2) == 0)) {
             (pathlen == 2 && memcmp(pathname, "..", 2) == 0)) {
@@ -936,15 +949,6 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
         return err;
         return err;
     }
     }
 
 
-    // check for root, can only be something like '/././../.'
-    if (strspn(path, "/.") == strlen(path)) {
-        dir->head[0] = dir->pair[0];
-        dir->head[1] = dir->pair[1];
-        dir->pos = sizeof(dir->d) - 2;
-        dir->off = sizeof(dir->d);
-        return 0;
-    }
-
     lfs_entry_t entry;
     lfs_entry_t entry;
     err = lfs_dir_find(lfs, dir, &entry, &path);
     err = lfs_dir_find(lfs, dir, &entry, &path);
     if (err) {
     if (err) {
@@ -1799,14 +1803,6 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) {
 
 
 /// General fs operations ///
 /// General fs operations ///
 int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
 int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
-    // check for root, can only be something like '/././../.'
-    if (strspn(path, "/.") == strlen(path)) {
-        memset(info, 0, sizeof(*info));
-        info->type = LFS_TYPE_DIR;
-        strcpy(info->name, "/");
-        return 0;
-    }
-
     lfs_dir_t cwd;
     lfs_dir_t cwd;
     int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
     int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
     if (err) {
     if (err) {
@@ -1825,11 +1821,15 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
         info->size = entry.d.u.file.size;
         info->size = entry.d.u.file.size;
     }
     }
 
 
-    err = lfs_bd_read(lfs, cwd.pair[0],
-            entry.off + 4+entry.d.elen+entry.d.alen,
-            info->name, entry.d.nlen);
-    if (err) {
-        return err;
+    if (lfs_paircmp(entry.d.u.dir, lfs->root) == 0) {
+        strcpy(info->name, "/");
+    } else {
+        err = lfs_bd_read(lfs, cwd.pair[0],
+                entry.off + 4+entry.d.elen+entry.d.alen,
+                info->name, entry.d.nlen);
+        if (err) {
+            return err;
+        }
     }
     }
 
 
     return 0;
     return 0;

+ 4 - 0
tests/test_paths.sh

@@ -108,6 +108,10 @@ tests/test.py << TEST
     lfs_stat(&lfs, "/", &info) => 0;
     lfs_stat(&lfs, "/", &info) => 0;
     info.type => LFS_TYPE_DIR;
     info.type => LFS_TYPE_DIR;
     strcmp(info.name, "/") => 0;
     strcmp(info.name, "/") => 0;
+
+    lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST;
+    lfs_file_open(&lfs, &file[0], "/", LFS_O_WRONLY | LFS_O_CREAT)
+        => LFS_ERR_ISDIR;
     lfs_unmount(&lfs) => 0;
     lfs_unmount(&lfs) => 0;
 TEST
 TEST