From 039bdf91b49b18175ebde9acb9a40653543da877 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 7 Jul 2023 13:53:39 -0500 Subject: [PATCH] Added lfsr_stat and integrated into dir tests lfsr_stat is really a directory operation underneath, so it's good to add to our testing while we are building up the dir tests. It's interesting to note lfsr_stat and lfsr_dir_read are less deduplicatable than their previous versions, since lfsr_stat can get most of it's info from lfsr_mtree_pathlookup. Though there will probably need to be some code sharing when we get to files with sizes. --- lfs.c | 77 +++++++++---- lfs.h | 1 + tests/t5_dirs.toml | 273 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 322 insertions(+), 29 deletions(-) diff --git a/lfs.c b/lfs.c index 3f837ea0..4d687d78 100644 --- a/lfs.c +++ b/lfs.c @@ -674,6 +674,10 @@ static inline uint8_t lfsr_tag_subtype(lfsr_tag_t tag) { return tag & 0x00ff; } +static inline uint8_t lfsr_tag_filetype(lfsr_tag_t tag) { + return tag - LFSR_TAG_REG; +} + static inline bool lfsr_tag_isvalid(lfsr_tag_t tag) { return !(tag & 0x8000); } @@ -5874,24 +5878,27 @@ static int lfsr_mtree_pathlookup(lfs_t *lfs, const char *path, return err; } - // keep track of what we've seen so far - if (mdir_) { - *mdir_ = mdir; - } - if (rid_) { - *rid_ = rid; - } - if (tag_) { - *tag_ = tag; - } - if (did_) { - *did_ = did; - } - if (name_) { - *name_ = name; - } - if (name_size_) { - *name_size_ = name_size; + // keep track of what we've seen, but only if we're the last name + // in our path + if (strchr(name, '/') == NULL) { + if (mdir_) { + *mdir_ = mdir; + } + if (rid_) { + *rid_ = rid; + } + if (tag_) { + *tag_ = tag; + } + if (did_) { + *did_ = did; + } + if (name_) { + *name_ = name; + } + if (name_size_) { + *name_size_ = name_size; + } } // error if not found, note we update things first so mdir/rid @@ -6712,7 +6719,7 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) { int err = lfsr_mtree_pathlookup(lfs, path, &parent.mdir, &parent.rid, NULL, &parent_did, &name, &name_size); - if (err && err != LFS_ERR_NOENT) { + if (err && (err != LFS_ERR_NOENT || parent.rid == -1)) { return err; } @@ -6847,6 +6854,34 @@ int lfsr_dir_close(lfs_t *lfs, lfsr_dir_t *dir) { return 0; } +int lfsr_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { + memset(info, 0, sizeof(struct lfs_info)); + + // lookup our entry + lfsr_mdir_t mdir; + lfs_ssize_t rid; + lfsr_tag_t tag; + const char *name; + lfs_size_t name_size; + int err = lfsr_mtree_pathlookup(lfs, path, + &mdir, &rid, &tag, + NULL, &name, &name_size); + if (err) { + return err; + } + + // fill out our info struct + info->type = lfsr_tag_filetype(tag); + + LFS_ASSERT(name_size <= LFS_NAME_MAX); + memcpy(info->name, name, name_size); + info->name[name_size] = '\0'; + + // TODO size once we have actual files + + return 0; +} + int lfsr_dir_read(lfs_t *lfs, lfsr_dir_t *dir, struct lfs_info *info) { memset(info, 0, sizeof(struct lfs_info)); @@ -6896,9 +6931,9 @@ int lfsr_dir_read(lfs_t *lfs, lfsr_dir_t *dir, struct lfs_info *info) { } // fill in our info struct - info->type = tag - LFSR_TAG_REG; + info->type = lfsr_tag_filetype(tag); - LFS_ASSERT(lfsr_data_size(data) <= lfs->name_max); + LFS_ASSERT(lfsr_data_size(data) <= LFS_NAME_MAX); lfs_ssize_t d = lfsr_data_readleb128(lfs, data, 0, &(uint32_t){0}); if (d < 0) { return d; diff --git a/lfs.h b/lfs.h index 20b38559..a8d48533 100644 --- a/lfs.h +++ b/lfs.h @@ -548,6 +548,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); // Fills out the info structure, based on the specified file or directory. // Returns a negative error code on failure. int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); +int lfsr_stat(lfs_t *lfs, const char *path, struct lfs_info *info); // Get a custom attribute // diff --git a/tests/t5_dirs.toml b/tests/t5_dirs.toml index 36bdbeb0..5d161be2 100644 --- a/tests/t5_dirs.toml +++ b/tests/t5_dirs.toml @@ -9,10 +9,52 @@ code = ''' // make a directory lfsr_mkdir(&lfs, "ardvark") => 0; - // check that our mkdir worked + // check that our mkdir worked with stat + struct lfs_info info; + lfsr_stat(&lfs, "ardvark", &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + + // and with dir_read lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + lfsr_unmount(&lfs) => 0; +''' + +# test that noent errors work +[cases.t5_dirs_noent] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // make a directory + lfsr_mkdir(&lfs, "ardvark") => 0; + + // try to read a nonsense path struct lfs_info info; + lfsr_stat(&lfs, "no", &info) => LFS_ERR_NOENT; + + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, "no") => LFS_ERR_NOENT; + + // and check that this didn't interfere with our original directory + lfsr_stat(&lfs, "ardvark", &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + + lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -40,10 +82,52 @@ code = ''' // make the same directory, should error lfsr_mkdir(&lfs, "ardvark") => LFS_ERR_EXIST; - // cand check that this didn't interfere with our original directory + // and check that this didn't interfere with our original directory + struct lfs_info info; + lfsr_stat(&lfs, "ardvark", &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + lfsr_unmount(&lfs) => 0; +''' + +# test that creating a directory with an invalid path errors +[cases.t5_dirs_mkdir_noent] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, cfg) => 0; + lfsr_mount(&lfs, cfg) => 0; + + // make a directory + lfsr_mkdir(&lfs, "ardvark") => 0; + + // make a nonsense directory, should error + lfsr_mkdir(&lfs, "no/hmm") => LFS_ERR_NOENT; + + // make a nonsense child directory, should error + lfsr_mkdir(&lfs, "ardvark/no/hmm") => LFS_ERR_NOENT; + + // and check that this didn't interfere with our original directory struct lfs_info info; + lfsr_stat(&lfs, "ardvark", &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, "/") => 0; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -70,9 +154,19 @@ code = ''' lfsr_mkdir(&lfs, "cantaloupe") => 0; // check that our mkdir worked + struct lfs_info info; + lfsr_stat(&lfs, "ardvark", &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "batman", &info) => 0; + assert(strcmp(info.name, "batman") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "cantaloupe", &info) => 0; + assert(strcmp(info.name, "cantaloupe") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -105,9 +199,19 @@ code = ''' lfsr_mkdir(&lfs, "ardvark/batman/cantaloupe") => 0; // check that our mkdirs worked + struct lfs_info info; + lfsr_stat(&lfs, "ardvark", &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "ardvark/batman", &info) => 0; + assert(strcmp(info.name, "batman") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "ardvark/batman/cantaloupe", &info) => 0; + assert(strcmp(info.name, "cantaloupe") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -161,6 +265,15 @@ code = ''' } // check that our mkdir worked + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; @@ -203,6 +316,25 @@ code = ''' } // check that our mkdirs worked + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + + for (lfs_size_t j = 0; j < N; j++) { + char name[256]; + sprintf(name, "dir%04d/child%04d", i, j); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => 0; + sprintf(name, "child%04d", j); + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + } + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; @@ -271,6 +403,35 @@ code = ''' } // check that our mkdirs worked + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + + for (lfs_size_t j = 0; j < N; j++) { + char name[256]; + sprintf(name, "dir%04d/child%04d", i, j); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => 0; + sprintf(name, "child%04d", j); + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + + for (lfs_size_t k = 0; k < N; k++) { + char name[256]; + sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => 0; + sprintf(name, "grandchild%04d", k); + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + } + } + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; @@ -348,6 +509,17 @@ code = ''' } // check that our mkdir worked + memset(name, 0, sizeof(name)); + for (lfs_size_t i = 0; i < N; i++) { + sprintf(&name[strlen(name)], "/dir%04d", i); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => 0; + char name2[256]; + sprintf(name2, "dir%04d", i); + assert(strcmp(info.name, name2) == 0); + assert(info.type == LFS_TYPE_DIR); + } + memset(name, 0, sizeof(name)); for (lfs_size_t i = 0; i < N; i++) { sprintf(&name[strlen(name)], "/dir%04d", i); @@ -424,6 +596,15 @@ code = ''' } // test that our directories match our simulation + for (lfs_size_t j = 0; j < sim_size; j++) { + char name[256]; + sprintf(name, "dir%04d", sim[j]); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; struct lfs_info info; @@ -472,9 +653,28 @@ code = ''' lfsr_mkdir(&lfs, "f_lUoVuhJH") => 0; // check that our mkdirs worked + struct lfs_info info; + lfsr_stat(&lfs, "a_SNmwMTHH", &info) => 0; + assert(strcmp(info.name, "a_SNmwMTHH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "b_skvjpWJH", &info) => 0; + assert(strcmp(info.name, "b_skvjpWJH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "c_OnOQhVPH", &info) => 0; + assert(strcmp(info.name, "c_OnOQhVPH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "d_puMpPjRH", &info) => 0; + assert(strcmp(info.name, "d_puMpPjRH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "e_LptKHkHH", &info) => 0; + assert(strcmp(info.name, "e_LptKHkHH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "f_lUoVuhJH", &info) => 0; + assert(strcmp(info.name, "f_lUoVuhJH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -527,9 +727,28 @@ code = ''' lfsr_mkdir(&lfs, "f_vknsvNRH") => 0; // check that our mkdirs worked + struct lfs_info info; + lfsr_stat(&lfs, "a_IplRNrPH", &info) => 0; + assert(strcmp(info.name, "a_IplRNrPH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "b_iUwOsqRH", &info) => 0; + assert(strcmp(info.name, "b_iUwOsqRH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "c_UPNtkpHH", &info) => 0; + assert(strcmp(info.name, "c_UPNtkpHH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "d_jKLUSLJH", &info) => 0; + assert(strcmp(info.name, "d_jKLUSLJH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "e_VNunKMPH", &info) => 0; + assert(strcmp(info.name, "e_VNunKMPH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "f_vknsvNRH", &info) => 0; + assert(strcmp(info.name, "f_vknsvNRH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -584,9 +803,28 @@ code = ''' lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; // check that our mkdirs worked + struct lfs_info info; + lfsr_stat(&lfs, "a_iomlVKPH", &info) => 0; + assert(strcmp(info.name, "a_iomlVKPH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "b_IJvqkHRH", &info) => 0; + assert(strcmp(info.name, "b_IJvqkHRH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "c_uOOJsIHH", &info) => 0; + assert(strcmp(info.name, "c_uOOJsIHH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "d_JTMkKuJH", &info) => 0; + assert(strcmp(info.name, "d_JTMkKuJH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "e_vQtPStPH", &info) => 0; + assert(strcmp(info.name, "e_vQtPStPH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "f_VtoMnwRH", &info) => 0; + assert(strcmp(info.name, "f_VtoMnwRH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -641,9 +879,28 @@ code = ''' lfsr_mkdir(&lfs, "f_pNtQTPJH") => 0; // check that our mkdirs worked + struct lfs_info info; + lfsr_stat(&lfs, "a_IOtUptRH", &info) => 0; + assert(strcmp(info.name, "a_IOtUptRH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "b_nquQsKHH", &info) => 0; + assert(strcmp(info.name, "b_nquQsKHH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "c_vwQtKjHH", &info) => 0; + assert(strcmp(info.name, "c_vwQtKjHH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "d_sVrvrWHH", &info) => 0; + assert(strcmp(info.name, "d_sVrvrWHH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "e_thrRIsRH", &info) => 0; + assert(strcmp(info.name, "e_thrRIsRH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_stat(&lfs, "f_pNtQTPJH", &info) => 0; + assert(strcmp(info.name, "f_pNtQTPJH") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_t dir; lfsr_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; lfsr_dir_read(&lfs, &dir, &info) => 0; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR);