ソースを参照

Changed type info to be retrieved from name tag instead of struct tag

Originally, I had type info encoded in the struct tag. This initially
made sense because the type info only directly impacts the struct tag.
However this was a case of focusing too much on the details instead of
the bigger picture.

A more file operations need to figure out the type of a file, but it's
only actually a small number of file operations that need to interact
with the file's structure. For the common case, providing the type of
the file early shortens operations by a full tag access.

Additionally, but storing the type in the file name tag, this opens up
the struct tag to use those bits for storing more struct descriptions.
Christopher Haster 7 年 前
コミット
c1103efb53
2 ファイル変更88 行追加120 行削除
  1. 86 117
      lfs.c
  2. 2 3
      lfs.h

+ 86 - 117
lfs.c

@@ -1402,27 +1402,30 @@ static int lfs_dir_getentry(lfs_t *lfs, lfs_mdir_t *dir,
 
 static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
         int16_t id, struct lfs_info *info) {
-    lfs_mattr_t attr;
-    int err = lfs_dir_getentry(lfs, dir, 0x703ff000,
+    lfs_mattr_t attr = {
+        lfs_mktag(LFS_STRUCT_NAME, id, lfs->name_size+1),
+        .u.buffer=info->name,
+    };
+
+    int err = lfs_dir_getbuffer(lfs, dir, 0x71fff000, &attr);
+    if (err) {
+        return err;
+    }
+
+    info->type = 0x38 & lfs_tag_subtype(attr.tag);
+
+    err = lfs_dir_getentry(lfs, dir, 0x703ff000,
             lfs_mktag(LFS_SCOPE_STRUCT, id, 0), &attr);
     if (err) {
         return err;
     }
 
-    info->type = lfs_tag_subtype(attr.tag);
     if (lfs_tag_struct(attr.tag) == LFS_STRUCT_CTZ) {
         info->size = attr.u.ctz.size;
     } else if (lfs_tag_struct(attr.tag) == LFS_STRUCT_INLINE) {
         info->size = lfs_tag_size(attr.tag);
     }
 
-    err = lfs_dir_getbuffer(lfs, dir, 0x71fff000, &(lfs_mattr_t){
-            lfs_mktag(LFS_STRUCT_NAME, id, lfs->name_size+1),
-            .u.buffer=info->name});
-    if (err) {
-        return err;
-    }
-
     return 0;
 }
 
@@ -1431,6 +1434,8 @@ struct lfs_dir_find {
     uint16_t len;
     int16_t id;
     int16_t tempid;
+    uint8_t findtype;
+    uint8_t tempfindtype;
 };
 
 static int lfs_dir_findscan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
@@ -1447,6 +1452,7 @@ static int lfs_dir_findscan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
         if (res) {
             // found a match
             find->tempid = lfs_tag_id(attr.tag);
+            find->tempfindtype = 0x38 & lfs_tag_subtype(attr.tag);
         }
     } else if (lfs_tag_type(attr.tag) == LFS_STRUCT_DELETE) {
         if (lfs_tag_id(attr.tag) == find->tempid) {
@@ -1456,6 +1462,7 @@ static int lfs_dir_findscan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
         }
     } else if (lfs_tag_type(attr.tag) == LFS_TYPE_CRC) {
         find->id = find->tempid;
+        find->findtype = find->tempfindtype;
     }
 
     return 0;
@@ -1463,7 +1470,7 @@ static int lfs_dir_findscan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
 
 // TODO drop others, make this only return id, also make get take in only entry to populate (with embedded tag)
 static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
-        const char **path, uint16_t *id) {
+        const char **path, uint16_t *id, uint8_t *type) {
     lfs_mattr_t attr = {
         .u.pair[0] = lfs->root[0],
         .u.pair[1] = lfs->root[1],
@@ -1482,6 +1489,8 @@ static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
         // special case for root dir
         if (find.name[0] == '\0') {
             // Return ISDIR when we hit root
+            // TODO change this to -1 or 0x3ff?
+            *type = LFS_TYPE_DIR;
             return LFS_ERR_ISDIR;
         }
 
@@ -1544,12 +1553,19 @@ static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
         }
 
         *id = find.id;
+        *type = find.findtype;
         find.name += find.len;
         find.name += strspn(find.name, "/");
         if (find.name[0] == '\0') {
             return 0;
         }
 
+        // don't continue on if we didn't hit a directory
+        // TODO update with what's on master?
+        if (find.findtype != 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
@@ -1558,12 +1574,6 @@ static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
         if (err) {
             return err;
         }
-
-        // continue on if we hit a directory
-        // TODO update with what's on master?
-        if (lfs_tag_subtype(attr.tag) != LFS_TYPE_DIR) {
-            return LFS_ERR_NOTDIR;
-        }
     }
 }
 
@@ -1578,7 +1588,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
     }
 
     lfs_mdir_t cwd;
-    int err = lfs_dir_find(lfs, &cwd, &path, &(uint16_t){0});
+    int err = lfs_dir_find(lfs, &cwd, &path, &(uint16_t){0}, &(uint8_t){0});
     if (err != LFS_ERR_NOENT || strchr(path, '/') != NULL) {
         if (!err || err == LFS_ERR_ISDIR) {
             return LFS_ERR_EXIST;
@@ -1618,7 +1628,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
     err = lfs_dir_commit(lfs, &cwd, &(lfs_mattrlist_t){
             {lfs_mktag(LFS_STRUCT_NAME | LFS_TYPE_DIR, id, nlen),
                 .u.buffer=(void*)path}, &(lfs_mattrlist_t){
-            {lfs_mktag(LFS_STRUCT_DIR | LFS_TYPE_DIR, id, sizeof(dir.pair)),
+            {lfs_mktag(LFS_STRUCT_DIR, id, sizeof(dir.pair)),
                 .u.buffer=dir.pair}, &(lfs_mattrlist_t){
             {lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(cwd.tail)),
                 .u.buffer=cwd.tail}}}});
@@ -1630,11 +1640,16 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
 
 int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
     uint16_t id;
-    int err = lfs_dir_find(lfs, &dir->m, &path, &id);
+    uint8_t type;
+    int err = lfs_dir_find(lfs, &dir->m, &path, &id, &type);
     if (err && err != LFS_ERR_ISDIR) {
         return err;
     }
 
+    if (type != LFS_TYPE_DIR) {
+        return LFS_ERR_NOTDIR;
+    }
+
     lfs_mattr_t attr;
     if (err == LFS_ERR_ISDIR) {
         // handle root dir separately
@@ -1647,10 +1662,6 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
         if (err) {
             return err;
         }
-
-        if (lfs_tag_subtype(attr.tag) != LFS_TYPE_DIR) {
-            return LFS_ERR_NOTDIR;
-        }
     }
 
     // fetch first pair
@@ -1982,8 +1993,10 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
     // allocate entry for file if it doesn't exist
     lfs_mdir_t cwd;
     uint16_t id;
-    int err = lfs_dir_find(lfs, &cwd, &path, &id);
-    if (err && (err != LFS_ERR_NOENT || strchr(path, '/') != NULL)) {
+    uint8_t type;
+    int err = lfs_dir_find(lfs, &cwd, &path, &id, &type);
+    if (err && (err != LFS_ERR_NOENT || strchr(path, '/') != NULL) &&
+            err != LFS_ERR_ISDIR) {
         return err;
     }
 
@@ -2009,7 +2022,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
         err = lfs_dir_commit(lfs, &cwd, &(lfs_mattrlist_t){
                 {lfs_mktag(LFS_STRUCT_NAME | LFS_TYPE_REG, id, nlen),
                     .u.buffer=(void*)path}, &(lfs_mattrlist_t){
-                {lfs_mktag(LFS_STRUCT_INLINE | LFS_TYPE_REG, id, 0)}}});
+                {lfs_mktag(LFS_STRUCT_INLINE, id, 0)}}});
         if (err) {
             return err;
         }
@@ -2022,9 +2035,9 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
             cwd.pair[1] = cwd.tail[1];
         }
 
-        attr.tag = lfs_mktag(LFS_STRUCT_INLINE | LFS_TYPE_REG, id, 0);
+        attr.tag = lfs_mktag(LFS_STRUCT_INLINE, id, 0);
     } else {
-        if (id == -1) {
+        if (type != LFS_TYPE_REG) {
             return LFS_ERR_ISDIR;
         } else if (flags & LFS_O_EXCL) {
             return LFS_ERR_EXIST;
@@ -2035,10 +2048,6 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
         if (err) {
             return err;
         }
-
-        if (lfs_tag_subtype(attr.tag) != LFS_TYPE_REG) {
-            return LFS_ERR_ISDIR;
-        }
     }
 
     // setup file struct
@@ -2267,7 +2276,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
         // either update the references or inline the whole file
         if (!(file->flags & LFS_F_INLINE)) {
             int err = lfs_dir_commit(lfs, &cwd, &(lfs_mattrlist_t){
-                    {lfs_mktag(LFS_STRUCT_CTZ | LFS_TYPE_REG,
+                    {lfs_mktag(LFS_STRUCT_CTZ,
                         file->id, 2*sizeof(uint32_t)), .u.buffer=&file->head},
                     file->attrs});
             if (err) {
@@ -2275,7 +2284,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
             }
         } else {
             int err = lfs_dir_commit(lfs, &cwd, &(lfs_mattrlist_t){
-                    {lfs_mktag(LFS_STRUCT_INLINE | LFS_TYPE_REG,
+                    {lfs_mktag(LFS_STRUCT_INLINE,
                         file->id, file->size), .u.buffer=file->cache.buffer},
                     file->attrs});
             if (err) {
@@ -2660,7 +2669,8 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) {
 int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
     lfs_mdir_t cwd;
     uint16_t id;
-    int err = lfs_dir_find(lfs, &cwd, &path, &id);
+    // TODO pass to getinfo?
+    int err = lfs_dir_find(lfs, &cwd, &path, &id, &(uint8_t){0});
     if (err && err != LFS_ERR_ISDIR) {
         return err;
     }
@@ -2691,22 +2701,22 @@ int lfs_remove(lfs_t *lfs, const char *path) {
     }
 
     uint16_t id;
-    err = lfs_dir_find(lfs, &cwd, &path, &id);
-    if (err) {
-        return err;
-    }
-
-    // grab entry to see if we're dealing with a dir
-    lfs_mattr_t attr;
-    err = lfs_dir_getentry(lfs, &cwd, 0x703ff000,
-            lfs_mktag(LFS_SCOPE_STRUCT, id, 0), &attr);
+    uint8_t type;
+    err = lfs_dir_find(lfs, &cwd, &path, &id, &type);
     if (err) {
         return err;
     }
 
     lfs_mdir_t dir;
-    if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
+    if (type == LFS_TYPE_DIR) {
         // must be empty before removal
+        lfs_mattr_t attr;
+        err = lfs_dir_getentry(lfs, &cwd, 0x703ff000,
+                lfs_mktag(LFS_SCOPE_STRUCT, id, 0), &attr);
+        if (err) {
+            return err;
+        }
+
         err = lfs_dir_fetch(lfs, &dir, attr.u.pair);
         if (err) {
             return err;
@@ -2716,38 +2726,6 @@ int lfs_remove(lfs_t *lfs, const char *path) {
         if (dir.count > 0 || dir.split) {
             return LFS_ERR_NOTEMPTY;
         }
-//
-//        // unlink from tail chain and create move to fix
-//        lfs->diff.move.pair[0] = cwd.pair[0] ^ lfs->globals.move.pair[0];
-//        lfs->diff.move.pair[1] = cwd.pair[1] ^ lfs->globals.move.pair[1];
-//        lfs->diff.move.id      = id          ^ lfs->globals.move.id;
-//
-//        // xor over our child's global state
-//        lfs->diff = lfs_globals_xor(&lfs->diff, &dir.globals);
-//        lfs->globals = lfs_globals_xor(&lfs->globals, &dir.globals);
-//
-//        // find pred and remove
-//        // TODO handle dropped block?
-//        lfs_mdir_t pred;
-//        int res = lfs_pred(lfs, dir.pair, &pred);
-//        if (res < 0) {
-//            return res;
-//        }
-//
-//        LFS_ASSERT(res); // must have pred
-//        pred.tail[0] = dir.tail[0];
-//        pred.tail[1] = dir.tail[1];
-//        err = lfs_dir_commit(lfs, &pred, &(lfs_mattrlist_t){
-//                {lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(pred.tail)),
-//                    .u.buffer=pred.tail}});
-//        if (err) {
-//            return err;
-//        }
-//
-//        // mark global state to clear move entry
-//        lfs->diff.move.pair[0] = 0xffffffff ^ lfs->globals.move.pair[0];
-//        lfs->diff.move.pair[1] = 0xffffffff ^ lfs->globals.move.pair[1];
-//        lfs->diff.move.id      = 0x3ff      ^ lfs->globals.move.id;
     }
 
     // delete the entry
@@ -2756,15 +2734,7 @@ int lfs_remove(lfs_t *lfs, const char *path) {
         return err;
     }
 
-//    // if we were a directory, fix the move we just created
-//    if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
-//        err = lfs_deorphan(lfs);
-//        if (err) {
-//            return err;
-//        }
-//    }
-
-    if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
+    if (type == LFS_TYPE_DIR) {
         int res = lfs_pred(lfs, dir.pair, &cwd);
         if (res < 0) {
             return res;
@@ -2793,14 +2763,8 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
     // find old entry
     lfs_mdir_t oldcwd;
     uint16_t oldid;
-    int err = lfs_dir_find(lfs, &oldcwd, &oldpath, &oldid);
-    if (err) {
-        return err;
-    }
-
-    lfs_mattr_t oldattr;
-    err = lfs_dir_getentry(lfs, &oldcwd, 0x703ff000,
-            lfs_mktag(LFS_SCOPE_STRUCT, oldid, 0), &oldattr);
+    uint8_t oldtype;
+    int err = lfs_dir_find(lfs, &oldcwd, &oldpath, &oldid, &oldtype);
     if (err) {
         return err;
     }
@@ -2808,7 +2772,8 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
     // find new entry
     lfs_mdir_t newcwd;
     uint16_t newid;
-    err = lfs_dir_find(lfs, &newcwd, &newpath, &newid);
+    uint8_t prevtype;
+    err = lfs_dir_find(lfs, &newcwd, &newpath, &newid, &prevtype);
     if (err && err != LFS_ERR_NOENT) {
         return err;
     }
@@ -2816,21 +2781,22 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
     bool prevexists = (err != LFS_ERR_NOENT);
     //bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0);
 
-    lfs_mattr_t prevattr;
     lfs_mdir_t prevdir;
     if (prevexists) {
-        // get prev entry, check that we have same type
-        err = lfs_dir_getentry(lfs, &newcwd, 0x703ff000,
-                lfs_mktag(LFS_SCOPE_STRUCT, newid, 0), &prevattr);
-        if (err) {
-            return err;
-        }
-
-        if (lfs_tag_subtype(prevattr.tag) != lfs_tag_subtype(oldattr.tag)) {
+        // check that we have same type
+        if (prevtype != oldtype) {
             return LFS_ERR_ISDIR;
         }
 
-        if (lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) {
+        if (prevtype == LFS_TYPE_DIR) {
+            // must be empty before removal
+            lfs_mattr_t prevattr;
+            err = lfs_dir_getentry(lfs, &newcwd, 0x703ff000,
+                    lfs_mktag(LFS_SCOPE_STRUCT, newid, 0), &prevattr);
+            if (err) {
+                return err;
+            }
+
             // must be empty before removal
             err = lfs_dir_fetch(lfs, &prevdir, prevattr.u.pair);
             if (err) {
@@ -2862,8 +2828,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
 
     // move over all attributes
     err = lfs_dir_commit(lfs, &newcwd, &(lfs_mattrlist_t){
-            {lfs_mktag(LFS_STRUCT_NAME | lfs_tag_subtype(oldattr.tag),
-                newid, strlen(newpath)),
+            {lfs_mktag(LFS_STRUCT_NAME | oldtype, newid, strlen(newpath)),
                 .u.buffer=(void*)newpath}, &(lfs_mattrlist_t){
             {lfs_mktag(LFS_FROM_MOVE, newid, oldid),
                 .u.dir=&oldcwd}}});
@@ -2877,7 +2842,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
         return err;
     }
 
-    if (prevexists && lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) {
+    if (prevexists && prevtype == LFS_TYPE_DIR) {
         int res = lfs_pred(lfs, prevdir.pair, &newcwd);
         if (res < 0) {
             return res;
@@ -3104,8 +3069,6 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
 
     // write one superblock
     lfs_superblock_t superblock = {
-        .root[0] = lfs->root[0],
-        .root[1] = lfs->root[1],
         .magic = {"littlefs"},
         .version = LFS_DISK_VERSION,
 
@@ -3118,8 +3081,10 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
 
     dir.count += 1;
     err = lfs_dir_commit(lfs, &dir, &(lfs_mattrlist_t){
-            {lfs_mktag(LFS_TYPE_SUPERBLOCK | LFS_STRUCT_DIR,
-                0, sizeof(superblock)), .u.buffer=&superblock}});
+            {lfs_mktag(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)),
+                .u.buffer=&superblock}, &(lfs_mattrlist_t){
+            {lfs_mktag(LFS_STRUCT_DIR, 0, sizeof(lfs->root)),
+                .u.buffer=lfs->root}}});
     if (err) {
         return err;
     }
@@ -3156,7 +3121,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
     }
 
     lfs_superblock_t superblock;
-    err = lfs_dir_getbuffer(lfs, &dir, 0x7e3ff000, &(lfs_mattr_t){
+    err = lfs_dir_getbuffer(lfs, &dir, 0x7ffff000, &(lfs_mattr_t){
             lfs_mktag(LFS_TYPE_SUPERBLOCK, 0, sizeof(superblock)),
             .u.buffer=&superblock});
     if (err && err != LFS_ERR_RANGE) {
@@ -3176,6 +3141,13 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
         return LFS_ERR_INVAL;
     }
 
+    err = lfs_dir_getbuffer(lfs, &dir, 0x7ffff000, &(lfs_mattr_t){
+            lfs_mktag(LFS_STRUCT_DIR, 0, sizeof(lfs->root)),
+            .u.buffer=lfs->root});
+    if (err) {
+        return err;
+    }
+
     if (superblock.inline_size) {
         if (superblock.inline_size > lfs->inline_size) {
             LFS_ERROR("Unsupported inline size (%d > %d)",
@@ -3206,9 +3178,6 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
         lfs->name_size = superblock.name_size;
     }
 
-    lfs->root[0] = superblock.root[0];
-    lfs->root[1] = superblock.root[1];
-
     err = lfs_scan(lfs);
     if (err) {
         return err;

+ 2 - 3
lfs.h

@@ -98,7 +98,7 @@ enum lfs_type {
     // file types
     LFS_TYPE_REG        = 0x008,
     LFS_TYPE_DIR        = 0x010,
-    LFS_TYPE_SUPERBLOCK = 0x038,
+    LFS_TYPE_SUPERBLOCK = 0x042,
 
     // internally used entry structures
     LFS_STRUCT_CTZ      = 0x001,
@@ -316,8 +316,8 @@ typedef struct lfs_mdir {
     uint16_t count;
     bool erased;
     bool split;
-    lfs_globals_t globals;
     bool stop_at_commit; // TODO hmmm
+    lfs_globals_t globals;
 } lfs_mdir_t;
 
 typedef struct lfs_cache {
@@ -352,7 +352,6 @@ typedef struct lfs_dir {
 } lfs_dir_t;
 
 typedef struct lfs_superblock {
-    lfs_block_t root[2];
     char magic[8];
     uint32_t version;