diff --git a/lfs.c b/lfs.c index 6ff4c808f6b..bccb27ee56d 100644 --- a/lfs.c +++ b/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; } diff --git a/tests/test_paths.sh b/tests/test_paths.sh index 33843296b55..ea5eb216a7a 100755 --- a/tests/test_paths.sh +++ b/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;