diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 055b54a0..2bbec095 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,7 +20,7 @@ jobs: github.event.workflow_run.head_sha == github.sha}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: ref: ${{github.event.workflow_run.head_sha}} # need workflow access since we push branches @@ -30,26 +30,29 @@ jobs: fetch-depth: 0 # try to get results from tests - - uses: dawidd6/action-download-artifact@v2 + - uses: actions/download-artifact@v4 continue-on-error: true with: - workflow: ${{github.event.workflow_run.name}} - run_id: ${{github.event.workflow_run.id}} - name: sizes + github-token: ${{secrets.GITHUB_TOKEN}} + run-id: ${{github.event.workflow_run.id}} + pattern: '{sizes,sizes-*}' + merge-multiple: true path: sizes - - uses: dawidd6/action-download-artifact@v2 + - uses: actions/download-artifact@v4 continue-on-error: true with: - workflow: ${{github.event.workflow_run.name}} - run_id: ${{github.event.workflow_run.id}} - name: cov + github-token: ${{secrets.GITHUB_TOKEN}} + run-id: ${{github.event.workflow_run.id}} + pattern: '{cov,cov-*}' + merge-multiple: true path: cov - - uses: dawidd6/action-download-artifact@v2 + - uses: actions/download-artifact@v4 continue-on-error: true with: - workflow: ${{github.event.workflow_run.name}} - run_id: ${{github.event.workflow_run.id}} - name: bench + github-token: ${{secrets.GITHUB_TOKEN}} + run-id: ${{github.event.workflow_run.id}} + pattern: '{bench,bench-*}' + merge-multiple: true path: bench - name: find-version diff --git a/.github/workflows/status.yml b/.github/workflows/status.yml index e6e983a5..e631b07d 100644 --- a/.github/workflows/status.yml +++ b/.github/workflows/status.yml @@ -13,12 +13,13 @@ jobs: status: runs-on: ubuntu-latest steps: - - uses: dawidd6/action-download-artifact@v2 + - uses: actions/download-artifact@v4 continue-on-error: true with: - workflow: ${{github.event.workflow_run.name}} - run_id: ${{github.event.workflow_run.id}} - name: status + github-token: ${{secrets.GITHUB_TOKEN}} + run-id: ${{github.event.workflow_run.id}} + pattern: '{status,status-*}' + merge-multiple: true path: status - name: update-status continue-on-error: true @@ -67,12 +68,13 @@ jobs: steps: # generated comment? - - uses: dawidd6/action-download-artifact@v2 + - uses: actions/download-artifact@v4 continue-on-error: true with: - workflow: ${{github.event.workflow_run.name}} - run_id: ${{github.event.workflow_run.id}} - name: comment + github-token: ${{secrets.GITHUB_TOKEN}} + run-id: ${{github.event.workflow_run.id}} + pattern: '{comment,comment-*}' + merge-multiple: true path: comment - name: update-comment continue-on-error: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db3413bb..73e5aa6d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: arch: [x86_64, thumb, mips, powerpc] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install run: | # need a few things @@ -235,9 +235,9 @@ jobs: # create size statuses - name: upload-sizes - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: sizes + name: sizes-${{matrix.arch}} path: sizes - name: status-sizes run: | @@ -273,16 +273,16 @@ jobs: }' | tee status/$(basename $f .csv).json done - name: upload-status-sizes - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: status + name: status-sizes-${{matrix.arch}} path: status retention-days: 1 # create cov statuses - name: upload-cov if: ${{matrix.arch == 'x86_64'}} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: cov path: cov @@ -317,11 +317,11 @@ jobs: target_step: env.STEP, }' | tee status/$(basename $f .csv)-$s.json done - - name: upload-status-sizes + - name: upload-status-cov if: ${{matrix.arch == 'x86_64'}} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: status + name: status-cov path: status retention-days: 1 @@ -336,7 +336,7 @@ jobs: pls: [1, 2] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install run: | # need a few things @@ -361,7 +361,7 @@ jobs: test-no-intrinsics: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install run: | # need a few things @@ -378,7 +378,7 @@ jobs: test-multiversion: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install run: | # need a few things @@ -395,7 +395,7 @@ jobs: test-lfs2_0: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install run: | # need a few things @@ -414,7 +414,7 @@ jobs: test-valgrind: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install run: | # need a few things @@ -436,7 +436,7 @@ jobs: test-clang: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install run: | # need a few things @@ -459,7 +459,7 @@ jobs: bench: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install run: | # need a few things @@ -491,7 +491,7 @@ jobs: # create bench statuses - name: upload-bench - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: bench path: bench @@ -525,9 +525,9 @@ jobs: }' | tee status/$(basename $f .csv)-$s.json done - name: upload-status-bench - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: - name: status + name: status-bench path: status retention-days: 1 @@ -535,10 +535,10 @@ jobs: test-compat: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 if: ${{github.event_name == 'pull_request'}} # checkout the current pr target into lfsp - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 if: ${{github.event_name == 'pull_request'}} with: ref: ${{github.event.pull_request.base.ref}} @@ -572,7 +572,7 @@ jobs: runs-on: ubuntu-latest if: ${{!endsWith(github.ref, '-prefix')}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install run: | # need a few things @@ -582,7 +582,7 @@ jobs: gcc --version python3 --version fusermount -V - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: repository: littlefs-project/littlefs-fuse ref: v2 @@ -622,7 +622,7 @@ jobs: runs-on: ubuntu-latest if: ${{!endsWith(github.ref, '-prefix')}} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: install run: | # need a few things @@ -632,12 +632,12 @@ jobs: gcc --version python3 --version fusermount -V - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: repository: littlefs-project/littlefs-fuse ref: v2 path: v2 - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: repository: littlefs-project/littlefs-fuse ref: v1 @@ -694,7 +694,7 @@ jobs: runs-on: ubuntu-latest needs: [test, bench] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 if: ${{github.event_name == 'pull_request'}} - name: install if: ${{github.event_name == 'pull_request'}} @@ -704,23 +704,26 @@ jobs: pip3 install toml gcc --version python3 --version - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 if: ${{github.event_name == 'pull_request'}} continue-on-error: true with: - name: sizes + pattern: '{sizes,sizes-*}' + merge-multiple: true path: sizes - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 if: ${{github.event_name == 'pull_request'}} continue-on-error: true with: - name: cov + pattern: '{cov,cov-*}' + merge-multiple: true path: cov - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 if: ${{github.event_name == 'pull_request'}} continue-on-error: true with: - name: bench + pattern: '{bench,bench-*}' + merge-multiple: true path: bench # try to find results from tests @@ -862,7 +865,7 @@ jobs: body: $comment, }' | tee comment/comment.json - name: upload-comment - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: comment path: comment diff --git a/README.md b/README.md index 5a75df3b..a1dc7437 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,12 @@ License Identifiers that are here available: http://spdx.org/licenses/ filesystem over USB. Allows mounting littlefs on a host PC without additional drivers. +- [ramcrc32bd] - An example block device using littlefs's 32-bit CRC for + error-correction. + +- [ramrsbd] - An example block device using Reed-Solomon codes for + error-correction. + - [Mbed OS] - The easiest way to get started with littlefs is to jump into Mbed which already has block device drivers for most forms of embedded storage. littlefs is available in Mbed OS as the [LittleFileSystem] class. @@ -281,6 +287,8 @@ License Identifiers that are here available: http://spdx.org/licenses/ [mklfs]: https://github.com/whitecatboard/Lua-RTOS-ESP32/tree/master/components/mklfs/src [mklittlefs]: https://github.com/earlephilhower/mklittlefs [pico-littlefs-usb]: https://github.com/oyama/pico-littlefs-usb +[ramcrc32bd]: https://github.com/geky/ramcrc32bd +[ramrsbd]: https://github.com/geky/ramrsbd [Mbed OS]: https://github.com/armmbed/mbed-os [LittleFileSystem]: https://os.mbed.com/docs/mbed-os/latest/apis/littlefilesystem.html [SPIFFS]: https://github.com/pellepl/spiffs diff --git a/lfs.c b/lfs.c index d35d5d6d..e92381ae 100644 --- a/lfs.c +++ b/lfs.c @@ -282,6 +282,21 @@ static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { /// Small type-level utilities /// + +// some operations on paths +static inline lfs_size_t lfs_path_namelen(const char *path) { + return strcspn(path, "/"); +} + +static inline bool lfs_path_islast(const char *path) { + lfs_size_t namelen = lfs_path_namelen(path); + return path[namelen + strspn(path + namelen, "/")] == '\0'; +} + +static inline bool lfs_path_isdir(const char *path) { + return path[lfs_path_namelen(path)] != '\0'; +} + // operations on block pairs static inline void lfs_pair_swap(lfs_block_t pair[2]) { lfs_block_t t = pair[0]; @@ -1461,32 +1476,46 @@ static int lfs_dir_find_match(void *data, return LFS_CMP_EQ; } +// lfs_dir_find tries to set path and id even if file is not found +// +// returns: +// - 0 if file is found +// - LFS_ERR_NOENT if file or parent is not found +// - LFS_ERR_NOTDIR if parent is not a dir static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, const char **path, uint16_t *id) { // we reduce path to a single name if we can find it const char *name = *path; - if (id) { - *id = 0x3ff; - } // default to root dir lfs_stag_t tag = LFS_MKTAG(LFS_TYPE_DIR, 0x3ff, 0); dir->tail[0] = lfs->root[0]; dir->tail[1] = lfs->root[1]; + // empty paths are not allowed + if (*name == '\0') { + return LFS_ERR_INVAL; + } + while (true) { nextname: - // skip slashes - name += strspn(name, "/"); + // skip slashes if we're a directory + if (lfs_tag_type3(tag) == LFS_TYPE_DIR) { + name += strspn(name, "/"); + } lfs_size_t namelen = strcspn(name, "/"); - // skip '.' and root '..' - if ((namelen == 1 && memcmp(name, ".", 1) == 0) || - (namelen == 2 && memcmp(name, "..", 2) == 0)) { + // skip '.' + if (namelen == 1 && memcmp(name, ".", 1) == 0) { name += namelen; goto nextname; } + // error on unmatched '..', trying to go above root? + if (namelen == 2 && memcmp(name, "..", 2) == 0) { + return LFS_ERR_INVAL; + } + // skip if matched by '..' in name const char *suffix = name + namelen; lfs_size_t sufflen; @@ -1498,7 +1527,9 @@ static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, break; } - if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { + if (sufflen == 1 && memcmp(suffix, ".", 1) == 0) { + // noop + } else if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { depth -= 1; if (depth == 0) { name = suffix + sufflen; @@ -1512,14 +1543,14 @@ static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, } // found path - if (name[0] == '\0') { + if (*name == '\0') { return tag; } // update what we've found so far *path = name; - // only continue if we hit a directory + // only continue if we're a directory if (lfs_tag_type3(tag) != LFS_TYPE_DIR) { return LFS_ERR_NOTDIR; } @@ -1539,8 +1570,7 @@ static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, tag = lfs_dir_fetchmatch(lfs, dir, dir->tail, LFS_MKTAG(0x780, 0, 0), LFS_MKTAG(LFS_TYPE_NAME, 0, namelen), - // are we last name? - (strchr(name, '/') == NULL) ? id : NULL, + id, lfs_dir_find_match, &(struct lfs_dir_find_match){ lfs, name, namelen}); if (tag < 0) { @@ -2128,13 +2158,14 @@ static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir, // And we cap at half a block to avoid degenerate cases with // nearly-full metadata blocks. // + lfs_size_t metadata_max = (lfs->cfg->metadata_max) + ? lfs->cfg->metadata_max + : lfs->cfg->block_size; if (end - split < 0xff && size <= lfs_min( - lfs->cfg->block_size - 40, + metadata_max - 40, lfs_alignup( - (lfs->cfg->metadata_max - ? lfs->cfg->metadata_max - : lfs->cfg->block_size)/2, + metadata_max/2, lfs->cfg->prog_size))) { break; } @@ -2603,12 +2634,12 @@ static int lfs_mkdir_(lfs_t *lfs, const char *path) { cwd.next = lfs->mlist; uint16_t id; err = lfs_dir_find(lfs, &cwd.m, &path, &id); - if (!(err == LFS_ERR_NOENT && id != 0x3ff)) { + if (!(err == LFS_ERR_NOENT && lfs_path_islast(path))) { return (err < 0) ? err : LFS_ERR_EXIST; } // check that name fits - lfs_size_t nlen = strlen(path); + lfs_size_t nlen = lfs_path_namelen(path); if (nlen > lfs->name_max) { return LFS_ERR_NAMETOOLONG; } @@ -3057,7 +3088,7 @@ static int lfs_file_opencfg_(lfs_t *lfs, lfs_file_t *file, // allocate entry for file if it doesn't exist lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id); - if (tag < 0 && !(tag == LFS_ERR_NOENT && file->id != 0x3ff)) { + if (tag < 0 && !(tag == LFS_ERR_NOENT && lfs_path_islast(path))) { err = tag; goto cleanup; } @@ -3077,8 +3108,14 @@ static int lfs_file_opencfg_(lfs_t *lfs, lfs_file_t *file, goto cleanup; } + // don't allow trailing slashes + if (lfs_path_isdir(path)) { + err = LFS_ERR_NOTDIR; + goto cleanup; + } + // check that name fits - lfs_size_t nlen = strlen(path); + lfs_size_t nlen = lfs_path_namelen(path); if (nlen > lfs->name_max) { err = LFS_ERR_NAMETOOLONG; goto cleanup; @@ -3664,22 +3701,16 @@ static lfs_ssize_t lfs_file_write_(lfs_t *lfs, lfs_file_t *file, static lfs_soff_t lfs_file_seek_(lfs_t *lfs, lfs_file_t *file, lfs_soff_t off, int whence) { // find new pos + // + // fortunately for us, littlefs is limited to 31-bit file sizes, so we + // don't have to worry too much about integer overflow lfs_off_t npos = file->pos; if (whence == LFS_SEEK_SET) { npos = off; } else if (whence == LFS_SEEK_CUR) { - if ((lfs_soff_t)file->pos + off < 0) { - return LFS_ERR_INVAL; - } else { - npos = file->pos + off; - } + npos = file->pos + (lfs_off_t)off; } else if (whence == LFS_SEEK_END) { - lfs_soff_t res = lfs_file_size_(lfs, file) + off; - if (res < 0) { - return LFS_ERR_INVAL; - } else { - npos = res; - } + npos = (lfs_off_t)lfs_file_size_(lfs, file) + (lfs_off_t)off; } if (npos > lfs->file_max) { @@ -3842,6 +3873,12 @@ static int lfs_stat_(lfs_t *lfs, const char *path, struct lfs_info *info) { return (int)tag; } + // only allow trailing slashes on dirs + if (strchr(path, '/') != NULL + && lfs_tag_type3(tag) != LFS_TYPE_DIR) { + return LFS_ERR_NOTDIR; + } + return lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info); } @@ -3944,7 +3981,7 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) { uint16_t newid; lfs_stag_t prevtag = lfs_dir_find(lfs, &newcwd, &newpath, &newid); if ((prevtag < 0 || lfs_tag_id(prevtag) == 0x3ff) && - !(prevtag == LFS_ERR_NOENT && newid != 0x3ff)) { + !(prevtag == LFS_ERR_NOENT && lfs_path_islast(newpath))) { return (prevtag < 0) ? (int)prevtag : LFS_ERR_INVAL; } @@ -3955,8 +3992,14 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) { struct lfs_mlist prevdir; prevdir.next = lfs->mlist; if (prevtag == LFS_ERR_NOENT) { + // if we're a file, don't allow trailing slashes + if (lfs_path_isdir(newpath) + && lfs_tag_type3(oldtag) != LFS_TYPE_DIR) { + return LFS_ERR_NOTDIR; + } + // check that name fits - lfs_size_t nlen = strlen(newpath); + lfs_size_t nlen = lfs_path_namelen(newpath); if (nlen > lfs->name_max) { return LFS_ERR_NAMETOOLONG; } @@ -4016,7 +4059,8 @@ static int lfs_rename_(lfs_t *lfs, const char *oldpath, const char *newpath) { {LFS_MKTAG_IF(prevtag != LFS_ERR_NOENT, LFS_TYPE_DELETE, newid, 0), NULL}, {LFS_MKTAG(LFS_TYPE_CREATE, newid, 0), NULL}, - {LFS_MKTAG(lfs_tag_type3(oldtag), newid, strlen(newpath)), newpath}, + {LFS_MKTAG(lfs_tag_type3(oldtag), + newid, lfs_path_namelen(newpath)), newpath}, {LFS_MKTAG(LFS_FROM_MOVE, newid, lfs_tag_id(oldtag)), &oldcwd}, {LFS_MKTAG_IF(samepair, LFS_TYPE_DELETE, newoldid, 0), NULL})); @@ -4173,6 +4217,14 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { // which littlefs currently does not support LFS_ASSERT((bool)0x80000000); + // check that the required io functions are provided + LFS_ASSERT(lfs->cfg->read != NULL); +#ifndef LFS_READONLY + LFS_ASSERT(lfs->cfg->prog != NULL); + LFS_ASSERT(lfs->cfg->erase != NULL); + LFS_ASSERT(lfs->cfg->sync != NULL); +#endif + // validate that the lfs-cfg sizes were initiated properly before // performing any arithmetic logics with them LFS_ASSERT(lfs->cfg->read_size != 0); @@ -4209,6 +4261,15 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { LFS_ASSERT(lfs->cfg->compact_thresh == (lfs_size_t)-1 || lfs->cfg->compact_thresh <= lfs->cfg->block_size); + // check that metadata_max is a multiple of read_size and prog_size, + // and a factor of the block_size + LFS_ASSERT(!lfs->cfg->metadata_max + || lfs->cfg->metadata_max % lfs->cfg->read_size == 0); + LFS_ASSERT(!lfs->cfg->metadata_max + || lfs->cfg->metadata_max % lfs->cfg->prog_size == 0); + LFS_ASSERT(!lfs->cfg->metadata_max + || lfs->cfg->block_size % lfs->cfg->metadata_max == 0); + // setup read cache if (lfs->cfg->read_buffer) { lfs->rcache.buffer = lfs->cfg->read_buffer; @@ -4396,6 +4457,30 @@ static int lfs_format_(lfs_t *lfs, const struct lfs_config *cfg) { } #endif +struct lfs_tortoise_t { + lfs_block_t pair[2]; + lfs_size_t i; + lfs_size_t period; +}; + +static int lfs_tortoise_detectcycles( + const lfs_mdir_t *dir, struct lfs_tortoise_t *tortoise) { + // detect cycles with Brent's algorithm + if (lfs_pair_issync(dir->tail, tortoise->pair)) { + LFS_WARN("Cycle detected in tail list"); + return LFS_ERR_CORRUPT; + } + if (tortoise->i == tortoise->period) { + tortoise->pair[0] = dir->tail[0]; + tortoise->pair[1] = dir->tail[1]; + tortoise->i = 0; + tortoise->period *= 2; + } + tortoise->i += 1; + + return LFS_ERR_OK; +} + static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) { int err = lfs_init(lfs, cfg); if (err) { @@ -4404,23 +4489,16 @@ static int lfs_mount_(lfs_t *lfs, const struct lfs_config *cfg) { // scan directory blocks for superblock and any global updates lfs_mdir_t dir = {.tail = {0, 1}}; - lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; - lfs_size_t tortoise_i = 1; - lfs_size_t tortoise_period = 1; + struct lfs_tortoise_t tortoise = { + .pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}, + .i = 1, + .period = 1, + }; while (!lfs_pair_isnull(dir.tail)) { - // detect cycles with Brent's algorithm - if (lfs_pair_issync(dir.tail, tortoise)) { - LFS_WARN("Cycle detected in tail list"); - err = LFS_ERR_CORRUPT; + err = lfs_tortoise_detectcycles(&dir, &tortoise); + if (err < 0) { goto cleanup; } - if (tortoise_i == tortoise_period) { - tortoise[0] = dir.tail[0]; - tortoise[1] = dir.tail[1]; - tortoise_i = 0; - tortoise_period *= 2; - } - tortoise_i += 1; // fetch next block in tail list lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail, @@ -4633,22 +4711,17 @@ int lfs_fs_traverse_(lfs_t *lfs, } #endif - lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; - lfs_size_t tortoise_i = 1; - lfs_size_t tortoise_period = 1; + struct lfs_tortoise_t tortoise = { + .pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}, + .i = 1, + .period = 1, + }; + int err = LFS_ERR_OK; while (!lfs_pair_isnull(dir.tail)) { - // detect cycles with Brent's algorithm - if (lfs_pair_issync(dir.tail, tortoise)) { - LFS_WARN("Cycle detected in tail list"); + err = lfs_tortoise_detectcycles(&dir, &tortoise); + if (err < 0) { return LFS_ERR_CORRUPT; } - if (tortoise_i == tortoise_period) { - tortoise[0] = dir.tail[0]; - tortoise[1] = dir.tail[1]; - tortoise_i = 0; - tortoise_period *= 2; - } - tortoise_i += 1; for (int i = 0; i < 2; i++) { int err = cb(data, dir.tail[i]); @@ -4727,22 +4800,17 @@ static int lfs_fs_pred(lfs_t *lfs, // iterate over all directory directory entries pdir->tail[0] = 0; pdir->tail[1] = 1; - lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; - lfs_size_t tortoise_i = 1; - lfs_size_t tortoise_period = 1; + struct lfs_tortoise_t tortoise = { + .pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}, + .i = 1, + .period = 1, + }; + int err = LFS_ERR_OK; while (!lfs_pair_isnull(pdir->tail)) { - // detect cycles with Brent's algorithm - if (lfs_pair_issync(pdir->tail, tortoise)) { - LFS_WARN("Cycle detected in tail list"); + err = lfs_tortoise_detectcycles(pdir, &tortoise); + if (err < 0) { return LFS_ERR_CORRUPT; } - if (tortoise_i == tortoise_period) { - tortoise[0] = pdir->tail[0]; - tortoise[1] = pdir->tail[1]; - tortoise_i = 0; - tortoise_period *= 2; - } - tortoise_i += 1; if (lfs_pair_cmp(pdir->tail, pair) == 0) { return 0; @@ -4792,22 +4860,17 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2], // use fetchmatch with callback to find pairs parent->tail[0] = 0; parent->tail[1] = 1; - lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; - lfs_size_t tortoise_i = 1; - lfs_size_t tortoise_period = 1; + struct lfs_tortoise_t tortoise = { + .pair = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}, + .i = 1, + .period = 1, + }; + int err = LFS_ERR_OK; while (!lfs_pair_isnull(parent->tail)) { - // detect cycles with Brent's algorithm - if (lfs_pair_issync(parent->tail, tortoise)) { - LFS_WARN("Cycle detected in tail list"); - return LFS_ERR_CORRUPT; - } - if (tortoise_i == tortoise_period) { - tortoise[0] = parent->tail[0]; - tortoise[1] = parent->tail[1]; - tortoise_i = 0; - tortoise_period *= 2; + err = lfs_tortoise_detectcycles(parent, &tortoise); + if (err < 0) { + return err; } - tortoise_i += 1; lfs_stag_t tag = lfs_dir_fetchmatch(lfs, parent, parent->tail, LFS_MKTAG(0x7ff, 0, 0x3ff), @@ -5890,7 +5953,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { ".read=%p, .prog=%p, .erase=%p, .sync=%p, " ".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".block_cycles=%"PRId32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " ".name_max=%"PRIu32", .file_max=%"PRIu32", " @@ -5920,7 +5983,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { ".read=%p, .prog=%p, .erase=%p, .sync=%p, " ".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".block_cycles=%"PRId32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " ".name_max=%"PRIu32", .file_max=%"PRIu32", " @@ -6057,7 +6120,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) { return err; } LFS_TRACE("lfs_file_open(%p, %p, \"%s\", %x)", - (void*)lfs, (void*)file, path, flags); + (void*)lfs, (void*)file, path, (unsigned)flags); LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); err = lfs_file_open_(lfs, file, path, flags); @@ -6077,7 +6140,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, } LFS_TRACE("lfs_file_opencfg(%p, %p, \"%s\", %x, %p {" ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", - (void*)lfs, (void*)file, path, flags, + (void*)lfs, (void*)file, path, (unsigned)flags, (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); @@ -6439,7 +6502,7 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { ".read=%p, .prog=%p, .erase=%p, .sync=%p, " ".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".block_cycles=%"PRId32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " ".name_max=%"PRIu32", .file_max=%"PRIu32", " diff --git a/lfs.h b/lfs.h index 84738973..45315603 100644 --- a/lfs.h +++ b/lfs.h @@ -21,7 +21,7 @@ extern "C" // Software library version // Major (top-nibble), incremented on backwards incompatible changes // Minor (bottom-nibble), incremented on feature additions -#define LFS_VERSION 0x00020009 +#define LFS_VERSION 0x0002000a #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) diff --git a/lfs_util.h b/lfs_util.h index 4e577009..0aec4885 100644 --- a/lfs_util.h +++ b/lfs_util.h @@ -8,6 +8,9 @@ #ifndef LFS_UTIL_H #define LFS_UTIL_H +#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) +#define LFS_STRINGIZE2(x) #x + // Users can override lfs_util.h with their own configuration by defining // LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h). // @@ -15,11 +18,26 @@ // provided by the config file. To start, I would suggest copying lfs_util.h // and modifying as needed. #ifdef LFS_CONFIG -#define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) -#define LFS_STRINGIZE2(x) #x #include LFS_STRINGIZE(LFS_CONFIG) #else +// Alternatively, users can provide a header file which defines +// macros and other things consumed by littlefs. +// +// For example, provide my_defines.h, which contains +// something like: +// +// #include +// extern void *my_malloc(size_t sz); +// #define LFS_MALLOC(sz) my_malloc(sz) +// +// And build littlefs with the header by defining LFS_DEFINES. +// (-DLFS_DEFINES=my_defines.h) + +#ifdef LFS_DEFINES +#include LFS_STRINGIZE(LFS_DEFINES) +#endif + // System includes #include #include diff --git a/runners/bench_runner.c b/runners/bench_runner.c index 387889d1..d49f9761 100644 --- a/runners/bench_runner.c +++ b/runners/bench_runner.c @@ -1322,6 +1322,7 @@ void perm_run( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .metadata_max = METADATA_MAX, .inline_max = INLINE_MAX, }; diff --git a/runners/bench_runner.h b/runners/bench_runner.h index 174733c1..848b5e8f 100644 --- a/runners/bench_runner.h +++ b/runners/bench_runner.h @@ -96,12 +96,13 @@ intmax_t bench_define(size_t define); #define CACHE_SIZE_i 6 #define LOOKAHEAD_SIZE_i 7 #define COMPACT_THRESH_i 8 -#define INLINE_MAX_i 9 -#define BLOCK_CYCLES_i 10 -#define ERASE_VALUE_i 11 -#define ERASE_CYCLES_i 12 -#define BADBLOCK_BEHAVIOR_i 13 -#define POWERLOSS_BEHAVIOR_i 14 +#define METADATA_MAX_i 9 +#define INLINE_MAX_i 10 +#define BLOCK_CYCLES_i 11 +#define ERASE_VALUE_i 12 +#define ERASE_CYCLES_i 13 +#define BADBLOCK_BEHAVIOR_i 14 +#define POWERLOSS_BEHAVIOR_i 15 #define READ_SIZE bench_define(READ_SIZE_i) #define PROG_SIZE bench_define(PROG_SIZE_i) @@ -112,6 +113,7 @@ intmax_t bench_define(size_t define); #define CACHE_SIZE bench_define(CACHE_SIZE_i) #define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i) #define COMPACT_THRESH bench_define(COMPACT_THRESH_i) +#define METADATA_MAX bench_define(METADATA_MAX_i) #define INLINE_MAX bench_define(INLINE_MAX_i) #define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i) #define ERASE_VALUE bench_define(ERASE_VALUE_i) @@ -129,6 +131,7 @@ intmax_t bench_define(size_t define); BENCH_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ BENCH_DEF(LOOKAHEAD_SIZE, 16) \ BENCH_DEF(COMPACT_THRESH, 0) \ + BENCH_DEF(METADATA_MAX, 0) \ BENCH_DEF(INLINE_MAX, 0) \ BENCH_DEF(BLOCK_CYCLES, -1) \ BENCH_DEF(ERASE_VALUE, 0xff) \ @@ -137,7 +140,7 @@ intmax_t bench_define(size_t define); BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP) #define BENCH_GEOMETRY_DEFINE_COUNT 4 -#define BENCH_IMPLICIT_DEFINE_COUNT 15 +#define BENCH_IMPLICIT_DEFINE_COUNT 16 #endif diff --git a/runners/test_runner.c b/runners/test_runner.c index ff526730..37cd1e7d 100644 --- a/runners/test_runner.c +++ b/runners/test_runner.c @@ -1347,6 +1347,7 @@ static void run_powerloss_none( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .metadata_max = METADATA_MAX, .inline_max = INLINE_MAX, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, @@ -1425,6 +1426,7 @@ static void run_powerloss_linear( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .metadata_max = METADATA_MAX, .inline_max = INLINE_MAX, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, @@ -1520,6 +1522,7 @@ static void run_powerloss_log( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .metadata_max = METADATA_MAX, .inline_max = INLINE_MAX, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, @@ -1613,6 +1616,7 @@ static void run_powerloss_cycles( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .metadata_max = METADATA_MAX, .inline_max = INLINE_MAX, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, @@ -1804,6 +1808,7 @@ static void run_powerloss_exhaustive( .cache_size = CACHE_SIZE, .lookahead_size = LOOKAHEAD_SIZE, .compact_thresh = COMPACT_THRESH, + .metadata_max = METADATA_MAX, .inline_max = INLINE_MAX, #ifdef LFS_MULTIVERSION .disk_version = DISK_VERSION, diff --git a/runners/test_runner.h b/runners/test_runner.h index 0f0e594e..ecdf9c11 100644 --- a/runners/test_runner.h +++ b/runners/test_runner.h @@ -89,13 +89,14 @@ intmax_t test_define(size_t define); #define CACHE_SIZE_i 6 #define LOOKAHEAD_SIZE_i 7 #define COMPACT_THRESH_i 8 -#define INLINE_MAX_i 9 -#define BLOCK_CYCLES_i 10 -#define ERASE_VALUE_i 11 -#define ERASE_CYCLES_i 12 -#define BADBLOCK_BEHAVIOR_i 13 -#define POWERLOSS_BEHAVIOR_i 14 -#define DISK_VERSION_i 15 +#define METADATA_MAX_i 9 +#define INLINE_MAX_i 10 +#define BLOCK_CYCLES_i 11 +#define ERASE_VALUE_i 12 +#define ERASE_CYCLES_i 13 +#define BADBLOCK_BEHAVIOR_i 14 +#define POWERLOSS_BEHAVIOR_i 15 +#define DISK_VERSION_i 16 #define READ_SIZE TEST_DEFINE(READ_SIZE_i) #define PROG_SIZE TEST_DEFINE(PROG_SIZE_i) @@ -106,6 +107,7 @@ intmax_t test_define(size_t define); #define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i) #define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i) #define COMPACT_THRESH TEST_DEFINE(COMPACT_THRESH_i) +#define METADATA_MAX TEST_DEFINE(METADATA_MAX_i) #define INLINE_MAX TEST_DEFINE(INLINE_MAX_i) #define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i) #define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i) @@ -124,6 +126,7 @@ intmax_t test_define(size_t define); TEST_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \ TEST_DEF(LOOKAHEAD_SIZE, 16) \ TEST_DEF(COMPACT_THRESH, 0) \ + TEST_DEF(METADATA_MAX, 0) \ TEST_DEF(INLINE_MAX, 0) \ TEST_DEF(BLOCK_CYCLES, -1) \ TEST_DEF(ERASE_VALUE, 0xff) \ @@ -133,7 +136,7 @@ intmax_t test_define(size_t define); TEST_DEF(DISK_VERSION, 0) #define TEST_GEOMETRY_DEFINE_COUNT 4 -#define TEST_IMPLICIT_DEFINE_COUNT 16 +#define TEST_IMPLICIT_DEFINE_COUNT 17 #endif diff --git a/scripts/prettyasserts.py b/scripts/prettyasserts.py index 3a62d360..925c14f0 100755 --- a/scripts/prettyasserts.py +++ b/scripts/prettyasserts.py @@ -86,6 +86,13 @@ def write_header(f, limit=LIMIT): f.writeln("}") f.writeln() f.writeln("__attribute__((unused))") + f.writeln("static void __pretty_assert_print_ptr(") + f.writeln(" const void *v, size_t size) {") + f.writeln(" (void)size;") + f.writeln(" printf(\"%p\", v);") + f.writeln("}") + f.writeln() + f.writeln("__attribute__((unused))") f.writeln("static void __pretty_assert_print_mem(") f.writeln(" const void *v, size_t size) {") f.writeln(" const uint8_t *v_ = v;") @@ -183,6 +190,23 @@ def write_header(f, limit=LIMIT): f.writeln(" _rh, strlen(_rh)); \\") f.writeln(" } \\") f.writeln("} while (0)") + for op, cmp in sorted(CMP.items()): + # Only EQ and NE are supported when compared to NULL. + if cmp not in ['eq', 'ne']: + continue + f.writeln("#define __PRETTY_ASSERT_PTR_%s(lh, rh) do { \\" + % cmp.upper()) + f.writeln(" const void *_lh = (const void*)(uintptr_t)lh; \\") + f.writeln(" const void *_rh = (const void*)(uintptr_t)rh; \\") + f.writeln(" if (!(_lh %s _rh)) { \\" % op) + f.writeln(" __pretty_assert_fail( \\") + f.writeln(" __FILE__, __LINE__, \\") + f.writeln(" __pretty_assert_print_ptr, \"%s\", \\" + % cmp) + f.writeln(" (const void*){_lh}, 0, \\") + f.writeln(" (const void*){_rh}, 0); \\") + f.writeln(" } \\") + f.writeln("} while (0)") f.writeln() f.writeln() @@ -301,6 +325,8 @@ def p_assert(p): cmp = p.expect('cmp') ; p.accept('ws') rh = p_expr(p) ; p.accept('ws') p.expect(')') + if rh == 'NULL' or lh == 'NULL': + return mkassert('ptr', CMP[cmp], lh, rh) return mkassert('int', CMP[cmp], lh, rh) except ParseFailure: p.pop(state) diff --git a/tests/test_paths.toml b/tests/test_paths.toml index 97a519ea..29574fa1 100644 --- a/tests/test_paths.toml +++ b/tests/test_paths.toml @@ -1,336 +1,7398 @@ # simple path test -[cases.test_paths_normal] +[cases.test_paths_simple] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/turkish") => 0; + lfs_mkdir(&lfs, "coffee/tubruk") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths struct lfs_info info; - lfs_stat(&lfs, "tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "/tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/drip") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/coldbrew") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/turkish") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/tubruk") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/vietnamese") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/thai") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/drip") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/coldbrew") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/turkish") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/tubruk") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/vietnamese") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/thai") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + lfs_rename(&lfs, + "coffee/drip", + "espresso/espresso") => 0; + lfs_rename(&lfs, + "coffee/coldbrew", + "espresso/americano") => 0; + lfs_rename(&lfs, + "coffee/turkish", + "espresso/macchiato") => 0; + lfs_rename(&lfs, + "coffee/tubruk", + "espresso/latte") => 0; + lfs_rename(&lfs, + "coffee/vietnamese", + "espresso/cappuccino") => 0; + lfs_rename(&lfs, + "coffee/thai", + "espresso/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => 0; + assert(strcmp(info.name, "espresso") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "espresso/americano", &info) => 0; + assert(strcmp(info.name, "americano") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "espresso/macchiato", &info) => 0; + assert(strcmp(info.name, "macchiato") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "espresso/latte", &info) => 0; + assert(strcmp(info.name, "latte") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "espresso/cappuccino", &info) => 0; + assert(strcmp(info.name, "cappuccino") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "espresso/mocha", &info) => 0; + assert(strcmp(info.name, "mocha") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "coffee/drip", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/coldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/turkish", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/tubruk", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/vietnamese", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/thai", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "espresso/espresso") => 0; + lfs_remove(&lfs, "espresso/americano") => 0; + lfs_remove(&lfs, "espresso/macchiato") => 0; + lfs_remove(&lfs, "espresso/latte") => 0; + lfs_remove(&lfs, "espresso/cappuccino") => 0; + lfs_remove(&lfs, "espresso/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; - lfs_mkdir(&lfs, "/milk") => 0; - lfs_stat(&lfs, "/milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); - lfs_stat(&lfs, "milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); lfs_unmount(&lfs) => 0; ''' -# redundant slashes -[cases.test_paths_redundant_slashes] +# absolute path test +# +# littlefs does not provide cd, so these are the same as relative paths +[cases.test_paths_absolute] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "/coffee/drip") => 0; + lfs_mkdir(&lfs, "/coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "/coffee/turkish") => 0; + lfs_mkdir(&lfs, "/coffee/tubruk") => 0; + lfs_mkdir(&lfs, "/coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "/coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths struct lfs_info info; - lfs_stat(&lfs, "/tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "//tea//hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "///tea///hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); + lfs_stat(&lfs, "/coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/coldbrew", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/turkish", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/tubruk", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/vietnamese", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/thai", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/coldbrew", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/turkish", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/tubruk", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/vietnamese", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/thai", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/drip") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/coldbrew") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/turkish") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/tubruk") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/vietnamese") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/thai") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/drip") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/coldbrew") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/turkish") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/tubruk") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/vietnamese") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/thai") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + lfs_rename(&lfs, + "coffee/drip", + "/espresso/espresso") => 0; + lfs_rename(&lfs, + "coffee/coldbrew", + "/espresso/americano") => 0; + lfs_rename(&lfs, + "/coffee/turkish", + "espresso/macchiato") => 0; + lfs_rename(&lfs, + "/coffee/tubruk", + "espresso/latte") => 0; + lfs_rename(&lfs, + "/coffee/vietnamese", + "/espresso/cappuccino") => 0; + lfs_rename(&lfs, + "/coffee/thai", + "/espresso/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/espresso/espresso", &info) => 0; + assert(strcmp(info.name, "espresso") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "espresso/americano", &info) => 0; + assert(strcmp(info.name, "americano") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/macchiato", &info) => 0; + assert(strcmp(info.name, "macchiato") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "espresso/latte", &info) => 0; + assert(strcmp(info.name, "latte") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/cappuccino", &info) => 0; + assert(strcmp(info.name, "cappuccino") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "espresso/mocha", &info) => 0; + assert(strcmp(info.name, "mocha") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "/coffee/drip", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/coldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/turkish", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/tubruk", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/vietnamese", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/thai", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "/espresso/espresso") => 0; + lfs_remove(&lfs, "/espresso/americano") => 0; + lfs_remove(&lfs, "/espresso/macchiato") => 0; + lfs_remove(&lfs, "/espresso/latte") => 0; + lfs_remove(&lfs, "/espresso/cappuccino") => 0; + lfs_remove(&lfs, "/espresso/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; - lfs_mkdir(&lfs, "////milk") => 0; - lfs_stat(&lfs, "////milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); - lfs_stat(&lfs, "milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); lfs_unmount(&lfs) => 0; ''' -# dot path test -[cases.test_paths_dot] +# redundant slashes +[cases.test_paths_redundant_slashes] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "/coffee/drip") => 0; + lfs_mkdir(&lfs, "//coffee//coldbrew") => 0; + lfs_mkdir(&lfs, "///coffee///turkish") => 0; + lfs_mkdir(&lfs, "////coffee////tubruk") => 0; + lfs_mkdir(&lfs, "/////coffee/////vietnamese") => 0; + lfs_mkdir(&lfs, "//////coffee//////thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "//coffee//coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "///coffee///turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "////coffee////tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/////coffee/////vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "//////coffee//////thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths struct lfs_info info; - lfs_stat(&lfs, "./tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "/./tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "/././tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "/./tea/./hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); + lfs_stat(&lfs, "//////coffee//////drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/////coffee/////coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "////coffee////turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "///coffee///tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "//coffee//vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "//coffee//coldbrew", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "///coffee///turkish", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "////coffee////tubruk", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/////coffee/////vietnamese", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "//////coffee//////thai", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "//coffee//coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "///coffee///turkish", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "////coffee////tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/////coffee/////vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "//////coffee//////thai", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "//coffee//coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "///coffee///turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "////coffee////tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/////coffee/////vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "//////coffee//////thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "//coffee//coldbrew", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "///coffee///turkish", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "////coffee////tubruk", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/////coffee/////vietnamese", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "//////coffee//////thai", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "//coffee//coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "///coffee///turkish", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "////coffee////tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/////coffee/////vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "//////coffee//////thai", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "//coffee//coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "///coffee///turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "////coffee////tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/////coffee/////vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "//////coffee//////thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/drip") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "//coffee//coldbrew") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "///coffee///turkish") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "////coffee////tubruk") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/////coffee/////vietnamese") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "//////coffee//////thai") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/drip") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "//coffee//coldbrew") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "///coffee///turkish") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "////coffee////tubruk") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/////coffee/////vietnamese") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "//////coffee//////thai") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + lfs_rename(&lfs, + "//////coffee//////drip", + "/espresso/espresso") => 0; + lfs_rename(&lfs, + "/////coffee/////coldbrew", + "//espresso//americano") => 0; + lfs_rename(&lfs, + "////coffee////turkish", + "///espresso///macchiato") => 0; + lfs_rename(&lfs, + "///coffee///tubruk", + "////espresso////latte") => 0; + lfs_rename(&lfs, + "//coffee//vietnamese", + "/////espresso/////cappuccino") => 0; + lfs_rename(&lfs, + "/coffee/thai", + "//////espresso//////mocha") => 0; + + // stat paths + lfs_stat(&lfs, "//////espresso//////espresso", &info) => 0; + assert(strcmp(info.name, "espresso") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/////espresso/////americano", &info) => 0; + assert(strcmp(info.name, "americano") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "////espresso////macchiato", &info) => 0; + assert(strcmp(info.name, "macchiato") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "///espresso///latte", &info) => 0; + assert(strcmp(info.name, "latte") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "//espresso//cappuccino", &info) => 0; + assert(strcmp(info.name, "cappuccino") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/mocha", &info) => 0; + assert(strcmp(info.name, "mocha") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "//////coffee//////drip", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/////coffee/////coldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "////coffee////turkish", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "///coffee///tubruk", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "//coffee//vietnamese", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/thai", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "/espresso/espresso") => 0; + lfs_remove(&lfs, "//espresso//americano") => 0; + lfs_remove(&lfs, "///espresso///macchiato") => 0; + lfs_remove(&lfs, "////espresso////latte") => 0; + lfs_remove(&lfs, "/////espresso/////cappuccino") => 0; + lfs_remove(&lfs, "//////espresso//////mocha") => 0; + + // stat paths + lfs_stat(&lfs, "//////espresso//////espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/////espresso/////americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "////espresso////macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "///espresso///latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "//espresso//cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/mocha", &info) => LFS_ERR_NOENT; - lfs_mkdir(&lfs, "/./milk") => 0; - lfs_stat(&lfs, "/./milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); - lfs_stat(&lfs, "milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); lfs_unmount(&lfs) => 0; ''' -# dot dot path test -[cases.test_paths_dot_dot] +# test trailing slashes +# +# trailing slashes are only allowed on directories +[cases.test_paths_trailing_slashes] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; + + // create paths lfs_mkdir(&lfs, "coffee") => 0; - lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; - lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; - lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip/") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew//") => 0; + lfs_mkdir(&lfs, "coffee/turkish///") => 0; + lfs_mkdir(&lfs, "coffee/tubruk////") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese/////") => 0; + lfs_mkdir(&lfs, "coffee/thai//////") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip/", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew//", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/turkish///", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/thai//////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + // still create so we have something to test + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths struct lfs_info info; - lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "coffee/coldcoffee/../../tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "coffee/../coffee/../tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); + if (DIR) { + lfs_stat(&lfs, "coffee/drip//////", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/coldbrew/////", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/turkish////", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/tubruk///", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/vietnamese//", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/thai/", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == LFS_TYPE_DIR); + } else { + lfs_stat(&lfs, "coffee/drip//////", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coffee/coldbrew/////", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coffee/turkish////", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coffee/tubruk///", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coffee/vietnamese//", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coffee/thai/", &info) => LFS_ERR_NOTDIR; + } + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip/", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew//", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/turkish///", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk////", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/////", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/thai//////", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "coffee/drip/", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew//", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/turkish///", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk////", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/////", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/thai//////", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "coffee/drip/", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/coldbrew//", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/turkish///", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/tubruk////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/vietnamese/////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/thai//////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip/", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew//", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/turkish///", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk////", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/////", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/thai//////", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + + lfs_file_open(&lfs, &file, "coffee/drip/", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew//", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/turkish///", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk////", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/////", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/thai//////", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + + lfs_file_open(&lfs, &file, "coffee/drip/", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew//", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/turkish///", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/thai//////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/drip/") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/coldbrew//") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/turkish///") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/tubruk////") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/vietnamese/////") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/thai//////") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/drip/") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/coldbrew//") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/turkish///") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/tubruk////") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/vietnamese/////") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/thai//////") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + if (DIR) { + lfs_rename(&lfs, + "coffee/drip//////", + "espresso/espresso/") => 0; + lfs_rename(&lfs, + "coffee/coldbrew/////", + "espresso/americano//") => 0; + lfs_rename(&lfs, + "coffee/turkish////", + "espresso/macchiato///") => 0; + lfs_rename(&lfs, + "coffee/tubruk///", + "espresso/latte////") => 0; + lfs_rename(&lfs, + "coffee/vietnamese//", + "espresso/cappuccino/////") => 0; + lfs_rename(&lfs, + "coffee/thai/", + "espresso/mocha//////") => 0; + + // stat paths + lfs_stat(&lfs, "espresso/espresso//////", &info) => 0; + assert(strcmp(info.name, "espresso") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "espresso/americano/////", &info) => 0; + assert(strcmp(info.name, "americano") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "espresso/macchiato////", &info) => 0; + assert(strcmp(info.name, "macchiato") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "espresso/latte///", &info) => 0; + assert(strcmp(info.name, "latte") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "espresso/cappuccino//", &info) => 0; + assert(strcmp(info.name, "cappuccino") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "espresso/mocha/", &info) => 0; + assert(strcmp(info.name, "mocha") == 0); + assert(info.type == LFS_TYPE_DIR); + + lfs_stat(&lfs, "coffee/drip//////", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/coldbrew/////", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/turkish////", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/tubruk///", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/vietnamese//", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/thai/", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "espresso/espresso/") => 0; + lfs_remove(&lfs, "espresso/americano//") => 0; + lfs_remove(&lfs, "espresso/macchiato///") => 0; + lfs_remove(&lfs, "espresso/latte////") => 0; + lfs_remove(&lfs, "espresso/cappuccino/////") => 0; + lfs_remove(&lfs, "espresso/mocha//////") => 0; + + // stat paths + lfs_stat(&lfs, "espresso/espresso//////", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano/////", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato////", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte///", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino//", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha/", &info) => LFS_ERR_NOENT; + + } else { + // bad source + lfs_rename(&lfs, + "coffee/drip//////", + "espresso/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/coldbrew/////", + "espresso/americano") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/turkish////", + "espresso/macchiato") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/tubruk///", + "espresso/latte") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/vietnamese//", + "espresso/cappuccino") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/thai/", + "espresso/mocha") => LFS_ERR_NOTDIR; + + // bad destination + lfs_rename(&lfs, + "coffee/drip", + "espresso/espresso/") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/coldbrew", + "espresso/americano//") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/turkish", + "espresso/macchiato///") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/tubruk", + "espresso/latte////") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/vietnamese", + "espresso/cappuccino/////") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/thai", + "espresso/mocha//////") => LFS_ERR_NOTDIR; + + // bad source and bad destination + lfs_rename(&lfs, + "coffee/drip//////", + "espresso/espresso/") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/coldbrew/////", + "espresso/americano//") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/turkish////", + "espresso/macchiato///") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/tubruk///", + "espresso/latte////") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/vietnamese//", + "espresso/cappuccino/////") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/thai/", + "espresso/mocha//////") => LFS_ERR_NOTDIR; + + // remove paths + lfs_remove(&lfs, "coffee/drip/") => LFS_ERR_NOTDIR; + lfs_remove(&lfs, "coffee/coldbrew//") => LFS_ERR_NOTDIR; + lfs_remove(&lfs, "coffee/turkish///") => LFS_ERR_NOTDIR; + lfs_remove(&lfs, "coffee/tubruk////") => LFS_ERR_NOTDIR; + lfs_remove(&lfs, "coffee/vietnamese/////") => LFS_ERR_NOTDIR; + lfs_remove(&lfs, "coffee/thai//////") => LFS_ERR_NOTDIR; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; + + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == LFS_TYPE_REG); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == LFS_TYPE_REG); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == LFS_TYPE_REG); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == LFS_TYPE_REG); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == LFS_TYPE_REG); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == LFS_TYPE_REG); + } - lfs_mkdir(&lfs, "coffee/../milk") => 0; - lfs_stat(&lfs, "coffee/../milk", &info) => 0; - strcmp(info.name, "milk") => 0; - lfs_stat(&lfs, "milk", &info) => 0; - strcmp(info.name, "milk") => 0; lfs_unmount(&lfs) => 0; ''' -# trailing dot path test -[cases.test_paths_trailing_dot] +# dot path tests +[cases.test_paths_dots] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "/coffee/drip") => 0; + lfs_mkdir(&lfs, "/./coffee/./coldbrew") => 0; + lfs_mkdir(&lfs, "/././coffee/././turkish") => 0; + lfs_mkdir(&lfs, "/./././coffee/./././tubruk") => 0; + lfs_mkdir(&lfs, "/././././coffee/././././vietnamese") => 0; + lfs_mkdir(&lfs, "/./././././coffee/./././././thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/./coffee/./coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/././coffee/././turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/./././coffee/./././tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/././././coffee/././././vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/./././././coffee/./././././thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths struct lfs_info info; - lfs_stat(&lfs, "tea/hottea/", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "tea/hottea/.", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "tea/hottea/./.", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "tea/hottea/..", &info) => 0; - assert(strcmp(info.name, "tea") == 0); - lfs_stat(&lfs, "tea/hottea/../.", &info) => 0; - assert(strcmp(info.name, "tea") == 0); + lfs_stat(&lfs, "/./././././coffee/./././././drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/././././coffee/././././coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/./././coffee/./././turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/././coffee/././tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/./coffee/./vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/./coffee/./coldbrew", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/././coffee/././turkish", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/./././coffee/./././tubruk", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/././././coffee/././././vietnamese", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/./././././coffee/./././././thai", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/./coffee/./coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/././coffee/././turkish", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/./././coffee/./././tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/././././coffee/././././vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/./././././coffee/./././././thai", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/./coffee/./coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/././coffee/././turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/./././coffee/./././tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/././././coffee/././././vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/./././././coffee/./././././thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/./coffee/./coldbrew", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/././coffee/././turkish", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/./././coffee/./././tubruk", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/././././coffee/././././vietnamese", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/./././././coffee/./././././thai", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/./coffee/./coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/././coffee/././turkish", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/./././coffee/./././tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/././././coffee/././././vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/./././././coffee/./././././thai", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/./coffee/./coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/././coffee/././turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/./././coffee/./././tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/././././coffee/././././vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/./././././coffee/./././././thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/drip") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/./coffee/./coldbrew") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/././coffee/././turkish") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/./././coffee/./././tubruk") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/././././coffee/././././vietnamese") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/./././././coffee/./././././thai") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/drip") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/./coffee/./coldbrew") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/././coffee/././turkish") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/./././coffee/./././tubruk") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/././././coffee/././././vietnamese") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/./././././coffee/./././././thai") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + lfs_rename(&lfs, + "/./././././coffee/./././././drip", + "/espresso/espresso") => 0; + lfs_rename(&lfs, + "/././././coffee/././././coldbrew", + "/./espresso/./americano") => 0; + lfs_rename(&lfs, + "/./././coffee/./././turkish", + "/././espresso/././macchiato") => 0; + lfs_rename(&lfs, + "/././coffee/././tubruk", + "/./././espresso/./././latte") => 0; + lfs_rename(&lfs, + "/./coffee/./vietnamese", + "/././././espresso/././././cappuccino") => 0; + lfs_rename(&lfs, + "/coffee/thai", + "/./././././espresso/./././././mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/./././././espresso/./././././espresso", &info) => 0; + assert(strcmp(info.name, "espresso") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/././././espresso/././././americano", &info) => 0; + assert(strcmp(info.name, "americano") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/./././espresso/./././macchiato", &info) => 0; + assert(strcmp(info.name, "macchiato") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/././espresso/././latte", &info) => 0; + assert(strcmp(info.name, "latte") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/./espresso/./cappuccino", &info) => 0; + assert(strcmp(info.name, "cappuccino") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/mocha", &info) => 0; + assert(strcmp(info.name, "mocha") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "/./././././coffee/./././././drip", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/././././coffee/././././coldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/./././coffee/./././turkish", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/././coffee/././tubruk", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/./coffee/./vietnamese", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/thai", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "/espresso/espresso") => 0; + lfs_remove(&lfs, "/./espresso/./americano") => 0; + lfs_remove(&lfs, "/././espresso/././macchiato") => 0; + lfs_remove(&lfs, "/./././espresso/./././latte") => 0; + lfs_remove(&lfs, "/././././espresso/././././cappuccino") => 0; + lfs_remove(&lfs, "/./././././espresso/./././././mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/./././././espresso/./././././espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/././././espresso/././././americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/./././espresso/./././macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/././espresso/././latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/./espresso/./cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/mocha", &info) => LFS_ERR_NOENT; + lfs_unmount(&lfs) => 0; ''' -# leading dot path test -[cases.test_paths_leading_dot] +# test trailing dots, these get a bit weird +# +# POSIX deviations: +# +# - We accept modifications of directories with trailing dots: +# - littlefs: remove("a/.") => 0 +# - POSIX: remove("a/.") => EBUSY +# Reason: Not worth implementing. +# +[cases.test_paths_trailing_dots] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, ".milk") => 0; + + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip/.") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "coffee/coldbrew/./.") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "coffee/turkish/././.") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "coffee/tubruk/./././.") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "coffee/vietnamese/././././.") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "coffee/thai/./././././.") => LFS_ERR_NOENT; + + // still create so we have something to test + lfs_mkdir(&lfs, "coffee/drip") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/turkish") => 0; + lfs_mkdir(&lfs, "coffee/tubruk") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "coffee/thai") => 0; + + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip/.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/coldbrew/./.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/turkish/././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tubruk/./././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/vietnamese/././././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/thai/./././././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + + // still create so we have something to test + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths struct lfs_info info; - lfs_stat(&lfs, ".milk", &info) => 0; - strcmp(info.name, ".milk") => 0; - lfs_stat(&lfs, "tea/.././.milk", &info) => 0; - strcmp(info.name, ".milk") => 0; + if (DIR) { + lfs_stat(&lfs, "coffee/drip/./././././.", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/coldbrew/././././.", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/turkish/./././.", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/tubruk/././.", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/vietnamese/./.", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/thai/.", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == LFS_TYPE_DIR); + } else { + lfs_stat(&lfs, "coffee/drip/./././././.", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coffee/coldbrew/././././.", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coffee/turkish/./././.", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coffee/tubruk/././.", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coffee/vietnamese/./.", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coffee/thai/.", &info) => LFS_ERR_NOTDIR; + } + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip/.", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew/./.", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/turkish/././.", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk/./././.", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/././././.", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/thai/./././././.", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "coffee/drip/.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew/./.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/turkish/././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk/./././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/././././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/thai/./././././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "coffee/drip/.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/coldbrew/./.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/turkish/././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/tubruk/./././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/vietnamese/././././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/thai/./././././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip/.", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew/./.", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/turkish/././.", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk/./././.", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/././././.", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/thai/./././././.", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + + lfs_file_open(&lfs, &file, "coffee/drip/.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew/./.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/turkish/././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk/./././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/././././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/thai/./././././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + + lfs_file_open(&lfs, &file, "coffee/drip/.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew/./.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/turkish/././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tubruk/./././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/vietnamese/././././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/thai/./././././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/drip/.") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/coldbrew/./.") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/turkish/././.") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/tubruk/./././.") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/vietnamese/././././.") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/thai/./././././.") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/drip/.") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/coldbrew/./.") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/turkish/././.") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/tubruk/./././.") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/vietnamese/././././.") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/thai/./././././.") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + if (DIR) { + // bad destination + lfs_rename(&lfs, + "coffee/drip", + "espresso/espresso/.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/coldbrew", + "espresso/americano/./.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/turkish", + "espresso/macchiato/././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tubruk", + "espresso/latte/./././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/vietnamese", + "espresso/cappuccino/././././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai", + "espresso/mocha/./././././.") => LFS_ERR_NOENT; + + // bad source and bad destination + lfs_rename(&lfs, + "coffee/drip/./././././.", + "espresso/espresso/.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/coldbrew/././././.", + "espresso/americano/./.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/turkish/./././.", + "espresso/macchiato/././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tubruk/././.", + "espresso/latte/./././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/vietnamese/./.", + "espresso/cappuccino/././././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai/.", + "espresso/mocha/./././././.") => LFS_ERR_NOENT; + + // this one works + lfs_rename(&lfs, + "coffee/drip/./././././.", + "espresso/espresso") => 0; + lfs_rename(&lfs, + "coffee/coldbrew/././././.", + "espresso/americano") => 0; + lfs_rename(&lfs, + "coffee/turkish/./././.", + "espresso/macchiato") => 0; + lfs_rename(&lfs, + "coffee/tubruk/././.", + "espresso/latte") => 0; + lfs_rename(&lfs, + "coffee/vietnamese/./.", + "espresso/cappuccino") => 0; + lfs_rename(&lfs, + "coffee/thai/.", + "espresso/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "espresso/espresso/./././././.", &info) => 0; + assert(strcmp(info.name, "espresso") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "espresso/americano/././././.", &info) => 0; + assert(strcmp(info.name, "americano") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "espresso/macchiato/./././.", &info) => 0; + assert(strcmp(info.name, "macchiato") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "espresso/latte/././.", &info) => 0; + assert(strcmp(info.name, "latte") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "espresso/cappuccino/./.", &info) => 0; + assert(strcmp(info.name, "cappuccino") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "espresso/mocha/.", &info) => 0; + assert(strcmp(info.name, "mocha") == 0); + assert(info.type == LFS_TYPE_DIR); + + lfs_stat(&lfs, "coffee/drip/./././././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/coldbrew/././././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/turkish/./././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/tubruk/././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/vietnamese/./.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/thai/.", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "espresso/espresso/.") => 0; + lfs_remove(&lfs, "espresso/americano/./.") => 0; + lfs_remove(&lfs, "espresso/macchiato/././.") => 0; + lfs_remove(&lfs, "espresso/latte/./././.") => 0; + lfs_remove(&lfs, "espresso/cappuccino/././././.") => 0; + lfs_remove(&lfs, "espresso/mocha/./././././.") => 0; + + // stat paths + lfs_stat(&lfs, "espresso/espresso/./././././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano/././././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato/./././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte/././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino/./.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha/.", &info) => LFS_ERR_NOENT; + + } else { + // bad source + lfs_rename(&lfs, + "coffee/drip/./././././.", + "espresso/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/coldbrew/././././.", + "espresso/americano") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/turkish/./././.", + "espresso/macchiato") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/tubruk/././.", + "espresso/latte") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/vietnamese/./.", + "espresso/cappuccino") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/thai/.", + "espresso/mocha") => LFS_ERR_NOTDIR; + + // bad destination + lfs_rename(&lfs, + "coffee/drip", + "espresso/espresso/.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/coldbrew", + "espresso/americano/./.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/turkish", + "espresso/macchiato/././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tubruk", + "espresso/latte/./././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/vietnamese", + "espresso/cappuccino/././././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai", + "espresso/mocha/./././././.") => LFS_ERR_NOENT; + + // bad source and bad destination + lfs_rename(&lfs, + "coffee/drip/./././././.", + "espresso/espresso/.") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/coldbrew/././././.", + "espresso/americano/./.") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/turkish/./././.", + "espresso/macchiato/././.") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/tubruk/././.", + "espresso/latte/./././.") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/vietnamese/./.", + "espresso/cappuccino/././././.") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/thai/.", + "espresso/mocha/./././././.") => LFS_ERR_NOTDIR; + + // remove paths + lfs_remove(&lfs, "coffee/drip/.") => LFS_ERR_NOTDIR; + lfs_remove(&lfs, "coffee/coldbrew/./.") => LFS_ERR_NOTDIR; + lfs_remove(&lfs, "coffee/turkish/././.") => LFS_ERR_NOTDIR; + lfs_remove(&lfs, "coffee/tubruk/./././.") => LFS_ERR_NOTDIR; + lfs_remove(&lfs, "coffee/vietnamese/././././.") => LFS_ERR_NOTDIR; + lfs_remove(&lfs, "coffee/thai/./././././.") => LFS_ERR_NOTDIR; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; + + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == LFS_TYPE_REG); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == LFS_TYPE_REG); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == LFS_TYPE_REG); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == LFS_TYPE_REG); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == LFS_TYPE_REG); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == LFS_TYPE_REG); + } + lfs_unmount(&lfs) => 0; ''' -# root dot dot path test -[cases.test_paths_root_dot_dot] +# dot dot path tests +[cases.test_paths_dotdots] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; + + // create paths + lfs_mkdir(&lfs, "no") => 0; + lfs_mkdir(&lfs, "no/no") => 0; lfs_mkdir(&lfs, "coffee") => 0; - lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; - lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; - lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; + lfs_mkdir(&lfs, "coffee/no") => 0; + if (DIR) { + lfs_mkdir(&lfs, "/coffee/drip") => 0; + lfs_mkdir(&lfs, "/no/../coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "/coffee/no/../turkish") => 0; + lfs_mkdir(&lfs, "/no/no/../../coffee/tubruk") => 0; + lfs_mkdir(&lfs, "/no/no/../../coffee/no/../vietnamese") => 0; + lfs_mkdir(&lfs, "/no/no/../../no/no/../../coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/no/../turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/no/../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/../../no/no/../../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + // stat paths struct lfs_info info; - lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; - strcmp(info.name, "hottea") => 0; + lfs_stat(&lfs, "/no/no/../../no/no/../../coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/no/../../coffee/no/../coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/no/../../coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/no/../tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/../coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/../coffee/coldbrew", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/no/../turkish", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/tubruk", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/no/../vietnamese", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/../../no/no/../../coffee/thai", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/no/../turkish", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/no/../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/../../no/no/../../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/no/../turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/no/../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/../../no/no/../../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/../coffee/coldbrew", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/no/../turkish", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/tubruk", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/no/../vietnamese", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/../../no/no/../../coffee/thai", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/no/../turkish", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/no/../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/../../no/no/../../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/no/../turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/../../coffee/no/../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/../../no/no/../../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/drip") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/no/../coffee/coldbrew") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/no/../turkish") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/no/no/../../coffee/tubruk") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/no/no/../../coffee/no/../vietnamese") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/no/no/../../no/no/../../coffee/thai") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/drip") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/no/../coffee/coldbrew") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/no/../turkish") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/no/no/../../coffee/tubruk") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/no/no/../../coffee/no/../vietnamese") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/no/no/../../no/no/../../coffee/thai") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + lfs_rename(&lfs, + "/no/no/../../no/no/../../coffee/drip", + "/espresso/espresso") => 0; + lfs_rename(&lfs, + "/no/no/../../coffee/no/../coldbrew", + "/no/../espresso/americano") => 0; + lfs_rename(&lfs, + "/no/no/../../coffee/turkish", + "/espresso/no/../macchiato") => 0; + lfs_rename(&lfs, + "/coffee/no/../tubruk", + "/no/no/../../espresso/latte") => 0; + lfs_rename(&lfs, + "/no/../coffee/vietnamese", + "/no/no/../../espresso/no/../cappuccino") => 0; + lfs_rename(&lfs, + "/coffee/thai", + "/no/no/../../no/no/../../espresso/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/no/no/../../no/no/../../espresso/espresso", &info) => 0; + assert(strcmp(info.name, "espresso") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/no/../../espresso/no/../americano", &info) => 0; + assert(strcmp(info.name, "americano") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/no/../../espresso/macchiato", &info) => 0; + assert(strcmp(info.name, "macchiato") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/no/../latte", &info) => 0; + assert(strcmp(info.name, "latte") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/../espresso/cappuccino", &info) => 0; + assert(strcmp(info.name, "cappuccino") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/mocha", &info) => 0; + assert(strcmp(info.name, "mocha") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "/no/no/../../no/no/../../coffee/drip", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/no/../../coffee/no/../coldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/no/../../coffee/turkish", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/no/../tubruk", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/../coffee/vietnamese", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/thai", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "/espresso/espresso") => 0; + lfs_remove(&lfs, "/no/../espresso/americano") => 0; + lfs_remove(&lfs, "/espresso/no/../macchiato") => 0; + lfs_remove(&lfs, "/no/no/../../espresso/latte") => 0; + lfs_remove(&lfs, "/no/no/../../espresso/no/../cappuccino") => 0; + lfs_remove(&lfs, "/no/no/../../no/no/../../espresso/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/no/no/../../no/no/../../espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/no/../../espresso/no/../americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/no/../../espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/no/../latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/../espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/mocha", &info) => LFS_ERR_NOENT; - lfs_mkdir(&lfs, "coffee/../../../../../../milk") => 0; - lfs_stat(&lfs, "coffee/../../../../../../milk", &info) => 0; - strcmp(info.name, "milk") => 0; - lfs_stat(&lfs, "milk", &info) => 0; - strcmp(info.name, "milk") => 0; lfs_unmount(&lfs) => 0; ''' -# invalid path tests -[cases.test_paths_invalid] +# test trailing dot dots, these get really weird +# +# POSIX deviations: +# +# - We do not check for existance of directories followed by dotdots: +# - littlefs: stat("a/missing/..") => 0 +# - POSIX: stat("a/missing/..") => ENOENT +# Reason: Difficult to implement non-recursively. +# +# - We accept modifications of directories with trailing dotdots: +# - littlefs: rename("a/b/..", "c") => 0 +# - POSIX: rename("a/b/..", "c") => EBUSY +# Reason: Not worth implementing. +# +[cases.test_paths_trailing_dotdots] +defines.DIR = [false, true] code = ''' lfs_t lfs; - lfs_format(&lfs, cfg); + lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; - struct lfs_info info; - lfs_stat(&lfs, "dirt", &info) => LFS_ERR_NOENT; - lfs_stat(&lfs, "dirt/ground", &info) => LFS_ERR_NOENT; - lfs_stat(&lfs, "dirt/ground/earth", &info) => LFS_ERR_NOENT; - lfs_remove(&lfs, "dirt") => LFS_ERR_NOENT; - lfs_remove(&lfs, "dirt/ground") => LFS_ERR_NOENT; - lfs_remove(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip/..") => LFS_ERR_EXIST; + lfs_mkdir(&lfs, "coffee/coldbrew/../..") => LFS_ERR_EXIST; + lfs_mkdir(&lfs, "coffee/turkish/../../..") => LFS_ERR_INVAL; + lfs_mkdir(&lfs, "coffee/tubruk/../../../..") => LFS_ERR_INVAL; + lfs_mkdir(&lfs, "coffee/vietnamese/../../../../..") => LFS_ERR_INVAL; + lfs_mkdir(&lfs, "coffee/thai/../../../../../..") => LFS_ERR_INVAL; + + // still create so we have something to test + lfs_mkdir(&lfs, "coffee/drip") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/turkish") => 0; + lfs_mkdir(&lfs, "coffee/tubruk") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "coffee/thai") => 0; - lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip/..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/coldbrew/../..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/turkish/../../..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/tubruk/../../../..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/vietnamese/../../../../..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/thai/../../../../../..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + + // still create so we have something to test + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "coffee/drip/../../../../../..", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "coffee/coldbrew/../../../../..", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "coffee/turkish/../../../..", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "coffee/tubruk/../../..", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "coffee/vietnamese/../..", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/thai/..", &info) => 0; + assert(strcmp(info.name, "coffee") == 0); + assert(info.type == LFS_TYPE_DIR); + + // file open paths, only works on files! lfs_file_t file; - lfs_file_open(&lfs, &file, "dirt/ground", LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_NOENT; - lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "dirt/ground/earth", LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/drip/..", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew/../..", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/turkish/../../..", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/tubruk/../../../..", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/vietnamese/../../../../..", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/thai/../../../../../..", + LFS_O_RDONLY) => LFS_ERR_INVAL; + + lfs_file_open(&lfs, &file, "coffee/drip/..", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew/../..", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/turkish/../../..", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/tubruk/../../../..", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/vietnamese/../../../../..", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/thai/../../../../../..", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + + lfs_file_open(&lfs, &file, "coffee/drip/..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/coldbrew/../..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/turkish/../../..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/tubruk/../../../..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/vietnamese/../../../../..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/thai/../../../../../..", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + + // dir open paths, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/drip/..") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/coldbrew/../..") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/turkish/../../..") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "coffee/tubruk/../../../..") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "coffee/vietnamese/../../../../..") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "coffee/thai/../../../../../..") => LFS_ERR_INVAL; + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + // bad source + lfs_rename(&lfs, + "coffee/drip/../../../../../..", + "espresso/espresso") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/coldbrew/../../../../..", + "espresso/americano") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/turkish/../../../..", + "espresso/macchiato") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/tubruk/../../..", + "espresso/latte") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/vietnamese/../..", + "espresso/cappuccino") => LFS_ERR_INVAL; + // this one works + lfs_rename(&lfs, + "coffee/thai/..", + "espresso/mocha") => 0; + lfs_rename(&lfs, + "espresso/mocha", + "coffee") => 0; + + // bad destination + if (DIR) { + // this one works + lfs_rename(&lfs, + "coffee/drip", + "espresso/espresso/..") => 0; + lfs_rename(&lfs, + "espresso", + "coffee/drip") => 0; + } else { + lfs_rename(&lfs, + "coffee/drip", + "espresso/espresso/..") => LFS_ERR_ISDIR; + } + lfs_rename(&lfs, + "coffee/coldbrew", + "espresso/americano/../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/turkish", + "espresso/macchiato/../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/tubruk", + "espresso/latte/../../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/vietnamese", + "espresso/cappuccino/../../../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/thai", + "espresso/mocha/../../../../../..") => LFS_ERR_INVAL; + + // bad source and bad destination + lfs_rename(&lfs, + "coffee/drip/../../../../../..", + "espresso/espresso/..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/coldbrew/../../../../..", + "espresso/americano/../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/turkish/../../../..", + "espresso/macchiato/../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/tubruk/../../..", + "espresso/latte/../../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/vietnamese/../..", + "espresso/cappuccino/../../../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/thai/..", + "espresso/mocha/../../../../../..") => LFS_ERR_INVAL; + + // remove paths + lfs_remove(&lfs, "coffee/drip/..") => LFS_ERR_NOTEMPTY; + lfs_remove(&lfs, "coffee/coldbrew/../..") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee/turkish/../../..") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee/tubruk/../../../..") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee/vietnamese/../../../../..") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee/thai/../../../../../..") => LFS_ERR_INVAL; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; + + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_unmount(&lfs) => 0; ''' -# root operations -[cases.test_paths_root] +# dot dot dot path tests +[cases.test_paths_dot_dotdots] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "no") => 0; + lfs_mkdir(&lfs, "no/no") => 0; + lfs_mkdir(&lfs, "coffee") => 0; + lfs_mkdir(&lfs, "coffee/no") => 0; + if (DIR) { + lfs_mkdir(&lfs, "/coffee/drip") => 0; + lfs_mkdir(&lfs, "/no/./../coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "/coffee/no/./../turkish") => 0; + lfs_mkdir(&lfs, "/no/no/./.././../coffee/tubruk") => 0; + lfs_mkdir(&lfs, "/no/no/./.././../coffee/no/./../vietnamese") => 0; + lfs_mkdir(&lfs, "/no/no/./.././../no/no/./.././../coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/./../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/no/./../turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/no/./../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/./.././../no/no/./.././../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths struct lfs_info info; - lfs_stat(&lfs, "/", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "/no/no/./.././../no/no/./.././../coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/no/./.././../coffee/no/./../coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/no/./.././../coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/no/./../tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/./../coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); - lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; - lfs_file_t file; - lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_ISDIR; + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/./../coffee/coldbrew", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/no/./../turkish", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/tubruk", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/no/./../vietnamese", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/./.././../no/no/./.././../coffee/thai", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/./../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/no/./../turkish", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/no/./../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/no/no/./.././../no/no/./.././../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/./../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/no/./../turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/no/./../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/./.././../no/no/./.././../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/./../coffee/coldbrew", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/no/./../turkish", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/tubruk", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/no/./../vietnamese", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/./.././../no/no/./.././../coffee/thai", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/./../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/no/./../turkish", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/no/./../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/no/no/./.././../no/no/./.././../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/./../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/no/./../turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/./.././../coffee/no/./../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/no/no/./.././../no/no/./.././../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/drip") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/no/./../coffee/coldbrew") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/no/./../turkish") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/no/no/./.././../coffee/tubruk") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/no/no/./.././../coffee/no/./../vietnamese") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/no/no/./.././../no/no/./.././../coffee/thai") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/drip") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/no/./../coffee/coldbrew") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/no/./../turkish") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/no/no/./.././../coffee/tubruk") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/no/no/./.././../coffee/no/./../vietnamese") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/no/no/./.././../no/no/./.././../coffee/thai") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + lfs_rename(&lfs, + "/no/no/./.././../no/no/./.././../coffee/drip", + "/espresso/espresso") => 0; + lfs_rename(&lfs, + "/no/no/./.././../coffee/no/./../coldbrew", + "/no/./../espresso/americano") => 0; + lfs_rename(&lfs, + "/no/no/./.././../coffee/turkish", + "/espresso/no/./../macchiato") => 0; + lfs_rename(&lfs, + "/coffee/no/./../tubruk", + "/no/no/./.././../espresso/latte") => 0; + lfs_rename(&lfs, + "/no/./../coffee/vietnamese", + "/no/no/./.././../espresso/no/./../cappuccino") => 0; + lfs_rename(&lfs, + "/coffee/thai", + "/no/no/./.././../no/no/./.././../espresso/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/no/no/./.././../no/no/./.././../espresso/espresso", &info) => 0; + assert(strcmp(info.name, "espresso") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/no/./.././../espresso/no/./../americano", &info) => 0; + assert(strcmp(info.name, "americano") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/no/./.././../espresso/macchiato", &info) => 0; + assert(strcmp(info.name, "macchiato") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/no/./../latte", &info) => 0; + assert(strcmp(info.name, "latte") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/no/./../espresso/cappuccino", &info) => 0; + assert(strcmp(info.name, "cappuccino") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/mocha", &info) => 0; + assert(strcmp(info.name, "mocha") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "/no/no/./.././../no/no/./.././../coffee/drip", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/no/./.././../coffee/no/./../coldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/no/./.././../coffee/turkish", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/no/./../tubruk", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/./../coffee/vietnamese", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/thai", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "/espresso/espresso") => 0; + lfs_remove(&lfs, "/no/./../espresso/americano") => 0; + lfs_remove(&lfs, "/espresso/no/./../macchiato") => 0; + lfs_remove(&lfs, "/no/no/./.././../espresso/latte") => 0; + lfs_remove(&lfs, "/no/no/./.././../espresso/no/./../cappuccino") => 0; + lfs_remove(&lfs, "/no/no/./.././../no/no/./.././../espresso/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/no/no/./.././../no/no/./.././../espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/no/./.././../espresso/no/./../americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/no/./.././../espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/no/./../latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/no/./../espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/mocha", &info) => LFS_ERR_NOENT; - lfs_remove(&lfs, "/") => LFS_ERR_INVAL; lfs_unmount(&lfs) => 0; ''' -# root representations -[cases.test_paths_root_reprs] +# dot dot dot path tests +[cases.test_paths_dotdotdots] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + lfs_mkdir(&lfs, "coffee/...") => 0; + if (DIR) { + lfs_mkdir(&lfs, "/coffee/.../drip") => 0; + lfs_mkdir(&lfs, "/coffee/.../coldbrew") => 0; + lfs_mkdir(&lfs, "/coffee/.../turkish") => 0; + lfs_mkdir(&lfs, "/coffee/.../tubruk") => 0; + lfs_mkdir(&lfs, "/coffee/.../vietnamese") => 0; + lfs_mkdir(&lfs, "/coffee/.../thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/.../drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths struct lfs_info info; - lfs_stat(&lfs, "/", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_stat(&lfs, "", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_stat(&lfs, ".", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_stat(&lfs, "..", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_stat(&lfs, "//", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_stat(&lfs, "./", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "/coffee/.../drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/.../coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/.../turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/.../tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/.../vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/.../thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/.../drip", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.../coldbrew", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.../turkish", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.../tubruk", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.../vietnamese", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.../thai", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/.../drip", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.../coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.../turkish", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.../tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.../thai", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/.../drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.../coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.../turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.../tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.../thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/.../drip", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../coldbrew", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../turkish", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../tubruk", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../vietnamese", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../thai", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/.../drip", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../turkish", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.../thai", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/.../drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.../coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.../turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.../tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.../vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.../thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/.../drip") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/.../coldbrew") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/.../turkish") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/.../tubruk") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/.../vietnamese") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/.../thai") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/.../drip") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/.../coldbrew") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/.../turkish") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/.../tubruk") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/.../vietnamese") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/.../thai") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + lfs_mkdir(&lfs, "espresso/...") => 0; + lfs_rename(&lfs, + "/coffee/.../drip", + "/espresso/.../espresso") => 0; + lfs_rename(&lfs, + "/coffee/.../coldbrew", + "/espresso/.../americano") => 0; + lfs_rename(&lfs, + "/coffee/.../turkish", + "/espresso/.../macchiato") => 0; + lfs_rename(&lfs, + "/coffee/.../tubruk", + "/espresso/.../latte") => 0; + lfs_rename(&lfs, + "/coffee/.../vietnamese", + "/espresso/.../cappuccino") => 0; + lfs_rename(&lfs, + "/coffee/.../thai", + "/espresso/.../mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/espresso/.../espresso", &info) => 0; + assert(strcmp(info.name, "espresso") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/.../americano", &info) => 0; + assert(strcmp(info.name, "americano") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/.../macchiato", &info) => 0; + assert(strcmp(info.name, "macchiato") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/.../latte", &info) => 0; + assert(strcmp(info.name, "latte") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/.../cappuccino", &info) => 0; + assert(strcmp(info.name, "cappuccino") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/.../mocha", &info) => 0; + assert(strcmp(info.name, "mocha") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "coffee/.../drip", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/.../coldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/.../turkish", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/.../tubruk", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/.../vietnamese", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/.../thai", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "/espresso/.../espresso") => 0; + lfs_remove(&lfs, "/espresso/.../americano") => 0; + lfs_remove(&lfs, "/espresso/.../macchiato") => 0; + lfs_remove(&lfs, "/espresso/.../latte") => 0; + lfs_remove(&lfs, "/espresso/.../cappuccino") => 0; + lfs_remove(&lfs, "/espresso/.../mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/espresso/.../espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/.../americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/.../macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/.../latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/.../cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/.../mocha", &info) => LFS_ERR_NOENT; + lfs_unmount(&lfs) => 0; ''' -# superblock conflict test -[cases.test_paths_superblock_conflict] +# leading dot path test +[cases.test_paths_leading_dots] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "/coffee/.drip") => 0; + lfs_mkdir(&lfs, "/coffee/..coldbrew") => 0; + lfs_mkdir(&lfs, "/coffee/...turkish") => 0; + lfs_mkdir(&lfs, "/coffee/....tubruk") => 0; + lfs_mkdir(&lfs, "/coffee/.....vietnamese") => 0; + lfs_mkdir(&lfs, "/coffee/......thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/.drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/..coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/...turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/....tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.....vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/......thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths struct lfs_info info; - lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; - lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT; + lfs_stat(&lfs, "/coffee/.drip", &info) => 0; + assert(strcmp(info.name, ".drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/..coldbrew", &info) => 0; + assert(strcmp(info.name, "..coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/...turkish", &info) => 0; + assert(strcmp(info.name, "...turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/....tubruk", &info) => 0; + assert(strcmp(info.name, "....tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/.....vietnamese", &info) => 0; + assert(strcmp(info.name, ".....vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/coffee/......thai", &info) => 0; + assert(strcmp(info.name, "......thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/.drip", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/..coldbrew", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/...turkish", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/....tubruk", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.....vietnamese", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/......thai", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/.drip", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/..coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/...turkish", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/....tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/.....vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/coffee/......thai", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/coffee/.drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/..coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/...turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/....tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.....vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/......thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/coffee/.drip", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/..coldbrew", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/...turkish", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/....tubruk", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.....vietnamese", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/......thai", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/.drip", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/..coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/...turkish", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/....tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/.....vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "/coffee/......thai", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "/coffee/.drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/..coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/...turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/....tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/.....vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/coffee/......thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/.drip") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/..coldbrew") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/...turkish") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/....tubruk") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/.....vietnamese") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/coffee/......thai") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/coffee/.drip") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/..coldbrew") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/...turkish") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/....tubruk") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/.....vietnamese") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "/coffee/......thai") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + lfs_rename(&lfs, + "/coffee/.drip", + "/espresso/.espresso") => 0; + lfs_rename(&lfs, + "/coffee/..coldbrew", + "/espresso/..americano") => 0; + lfs_rename(&lfs, + "/coffee/...turkish", + "/espresso/...macchiato") => 0; + lfs_rename(&lfs, + "/coffee/....tubruk", + "/espresso/....latte") => 0; + lfs_rename(&lfs, + "/coffee/.....vietnamese", + "/espresso/.....cappuccino") => 0; + lfs_rename(&lfs, + "/coffee/......thai", + "/espresso/......mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/espresso/.espresso", &info) => 0; + assert(strcmp(info.name, ".espresso") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/..americano", &info) => 0; + assert(strcmp(info.name, "..americano") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/...macchiato", &info) => 0; + assert(strcmp(info.name, "...macchiato") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/....latte", &info) => 0; + assert(strcmp(info.name, "....latte") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/.....cappuccino", &info) => 0; + assert(strcmp(info.name, ".....cappuccino") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "/espresso/......mocha", &info) => 0; + assert(strcmp(info.name, "......mocha") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "coffee/.drip", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/..coldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/...turkish", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/....tubruk", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/.....vietnamese", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/......thai", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "/espresso/.espresso") => 0; + lfs_remove(&lfs, "/espresso/..americano") => 0; + lfs_remove(&lfs, "/espresso/...macchiato") => 0; + lfs_remove(&lfs, "/espresso/....latte") => 0; + lfs_remove(&lfs, "/espresso/.....cappuccino") => 0; + lfs_remove(&lfs, "/espresso/......mocha") => 0; + + // stat paths + lfs_stat(&lfs, "/espresso/.espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/..americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/...macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/....latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/.....cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "/espresso/......mocha", &info) => LFS_ERR_NOENT; - lfs_mkdir(&lfs, "littlefs") => 0; - lfs_stat(&lfs, "littlefs", &info) => 0; - assert(strcmp(info.name, "littlefs") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_remove(&lfs, "littlefs") => 0; - lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; lfs_unmount(&lfs) => 0; ''' -# max path test -[cases.test_paths_max] +# root dot dot path test +[cases.test_paths_root_dotdots] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "no") => 0; lfs_mkdir(&lfs, "coffee") => 0; - lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; - lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; - lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "/../coffee/drip") => LFS_ERR_INVAL; + lfs_mkdir(&lfs, "/../../coffee/coldbrew") => LFS_ERR_INVAL; + lfs_mkdir(&lfs, "/../../../coffee/turkish") => LFS_ERR_INVAL; + lfs_mkdir(&lfs, "/no/../../coffee/tubruk") => LFS_ERR_INVAL; + lfs_mkdir(&lfs, "/no/../../../coffee/vietnamese") => LFS_ERR_INVAL; + lfs_mkdir(&lfs, "/no/../../../../coffee/thai") => LFS_ERR_INVAL; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/../coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/../../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/../../../coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../../coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../../../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + } - char path[1024]; - memset(path, 'w', LFS_NAME_MAX+1); - path[LFS_NAME_MAX+1] = '\0'; - lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; + // ok, actually create paths + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/turkish") => 0; + lfs_mkdir(&lfs, "coffee/tubruk") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "/no/../../../../coffee/drip", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "/no/../../../coffee/coldbrew", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "/no/../../coffee/turkish", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "/../../../coffee/tubruk", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "/../../coffee/vietnamese", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "/../coffee/thai", &info) => LFS_ERR_INVAL; + + // file open paths, only works on files! lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_NAMETOOLONG; + lfs_file_open(&lfs, &file, "/../coffee/drip", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/../../coffee/coldbrew", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/../../../coffee/turkish", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../coffee/tubruk", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../../coffee/vietnamese", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../../../coffee/thai", + LFS_O_RDONLY) => LFS_ERR_INVAL; + + lfs_file_open(&lfs, &file, "/../coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/../../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/../../../coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../../coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../../../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + + lfs_file_open(&lfs, &file, "/../coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/../../coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/../../../coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../../coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "/no/../../../../coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + + // dir open paths, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/../coffee/drip") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "/../../coffee/coldbrew") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "/../../../coffee/turkish") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "/no/../../coffee/tubruk") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "/no/../../../coffee/vietnamese") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "/no/../../../../coffee/thai") => LFS_ERR_INVAL; + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + // bad source + lfs_rename(&lfs, + "/no/../../../../coffee/drip", + "espresso/espresso") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/no/../../../coffee/coldbrew", + "espresso/americano") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/no/../../coffee/turkish", + "espresso/macchiato") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/../../../coffee/tubruk", + "espresso/latte") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/../../coffee/vietnamese", + "espresso/cappuccino") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/../coffee/thai", + "espresso/mocha") => LFS_ERR_INVAL; + + // bad destination + lfs_rename(&lfs, + "coffee/drip", + "/../espresso/espresso") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/coldbrew", + "/../../espresso/americano") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/turkish", + "/../../../espresso/macchiato") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/tubruk", + "/no/../../espresso/latte") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/vietnamese", + "/no/../../../espresso/cappuccino") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/thai", + "/no/../../../../espresso/mocha") => LFS_ERR_INVAL; + + // bad source and bad destination + lfs_rename(&lfs, + "/no/../../../../coffee/drip", + "/../espresso/espresso") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/no/../../../coffee/coldbrew", + "/../../espresso/americano") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/no/../../coffee/turkish", + "/../../../espresso/macchiato") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/../../../coffee/tubruk", + "/no/../../espresso/latte") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/../../coffee/vietnamese", + "/no/../../../espresso/cappuccino") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/../coffee/thai", + "/no/../../../../espresso/mocha") => LFS_ERR_INVAL; + + // here's a weird one, what happens if our rename is also a noop? + lfs_rename(&lfs, + "/no/../../../../coffee/drip", + "/no/../../../../coffee/drip") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/no/../../../coffee/coldbrew", + "/no/../../../coffee/coldbrew") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/no/../../coffee/turkish", + "/no/../../coffee/turkish") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/../../../coffee/tubruk", + "/../../../coffee/tubruk") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/../../coffee/vietnamese", + "/../../coffee/vietnamese") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "/../coffee/thai", + "/../coffee/thai") => LFS_ERR_INVAL; + + // remove paths + lfs_remove(&lfs, "/../espresso/espresso") => LFS_ERR_INVAL; + lfs_remove(&lfs, "/../../espresso/americano") => LFS_ERR_INVAL; + lfs_remove(&lfs, "/../../../espresso/macchiato") => LFS_ERR_INVAL; + lfs_remove(&lfs, "/no/../../espresso/latte") => LFS_ERR_INVAL; + lfs_remove(&lfs, "/no/../../../espresso/cappuccino") => LFS_ERR_INVAL; + lfs_remove(&lfs, "/no/../../../../espresso/mocha") => LFS_ERR_INVAL; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; + + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); - memcpy(path, "coffee/", strlen("coffee/")); - memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX+1); - path[strlen("coffee/")+LFS_NAME_MAX+1] = '\0'; - lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; - lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_NAMETOOLONG; lfs_unmount(&lfs) => 0; ''' -# really big path test -[cases.test_paths_really_big] +# trailing noent tests +[cases.test_paths_noent] +defines.DIR = [false, true] code = ''' lfs_t lfs; lfs_format(&lfs, cfg) => 0; lfs_mount(&lfs, cfg) => 0; + + // create paths lfs_mkdir(&lfs, "coffee") => 0; - lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; - lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; - lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/turkish") => 0; + lfs_mkdir(&lfs, "coffee/tubruk") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } - char path[1024]; - memset(path, 'w', LFS_NAME_MAX); - path[LFS_NAME_MAX] = '\0'; - lfs_mkdir(&lfs, path) => 0; - lfs_remove(&lfs, path) => 0; + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "coffee/_rip", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/c_ldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/tu_kish", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/tub_uk", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/_vietnamese", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/thai_", &info) => LFS_ERR_NOENT; + + // file open paths, only works on files! lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_remove(&lfs, path) => 0; + lfs_file_open(&lfs, &file, "coffee/_rip", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/c_ldbrew", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tu_kish", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tub_uk", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/_vietnamese", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/thai_", + LFS_O_RDONLY) => LFS_ERR_NOENT; + + // dir open paths, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/_rip") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/c_ldbrew") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/tu_kish") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/tub_uk") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/_vietnamese") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/thai_") => LFS_ERR_NOENT; + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + lfs_rename(&lfs, + "coffee/_rip", + "espresso/espresso") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew", + "espresso/americano") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish", + "espresso/macchiato") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk", + "espresso/latte") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese", + "espresso/cappuccino") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_", + "espresso/mocha") => LFS_ERR_NOENT; + + // here's a weird one, what happens if our rename is also a noop? + lfs_rename(&lfs, + "coffee/_rip", + "coffee/_rip") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew", + "coffee/c_ldbrew") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish", + "coffee/tu_kish") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk", + "coffee/tub_uk") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese", + "coffee/_vietnamese") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_", + "coffee/thai_") => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "coffee/_rip") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/c_ldbrew") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/tu_kish") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/tub_uk") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/_vietnamese") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/thai_") => LFS_ERR_NOENT; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; + + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); - memcpy(path, "coffee/", strlen("coffee/")); - memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX); - path[strlen("coffee/")+LFS_NAME_MAX] = '\0'; - lfs_mkdir(&lfs, path) => 0; - lfs_remove(&lfs, path) => 0; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_remove(&lfs, path) => 0; lfs_unmount(&lfs) => 0; ''' +# parent noent tests +[cases.test_paths_noent_parent] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "_offee/drip") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "c_ffee/coldbrew") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "co_fee/turkish") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "cof_ee/tubruk") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "_coffee/vietnamese") => LFS_ERR_NOENT; + lfs_mkdir(&lfs, "coffee_/thai") => LFS_ERR_NOENT; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "_offee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "c_ffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "co_fee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "cof_ee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "_coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee_/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + } + + // ok, actually create paths + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/turkish") => 0; + lfs_mkdir(&lfs, "coffee/tubruk") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "_offee/drip", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "c_ffee/coldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "co_fee/turkish", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "cof_ee/tubruk", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "_coffee/vietnamese", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee_/thai", &info) => LFS_ERR_NOENT; + + // file open paths, only works on files! + lfs_file_t file; + lfs_file_open(&lfs, &file, "_offee/drip", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "c_ffee/coldbrew", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "co_fee/turkish", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "cof_ee/tubruk", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "_coffee/vietnamese", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee_/thai", + LFS_O_RDONLY) => LFS_ERR_NOENT; + + lfs_file_open(&lfs, &file, "_offee/drip", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "c_ffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "co_fee/turkish", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "cof_ee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "_coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee_/thai", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + + lfs_file_open(&lfs, &file, "_offee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "c_ffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "co_fee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "cof_ee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "_coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee_/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + + // dir open paths, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "_offee/drip") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "c_ffee/coldbrew") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "co_fee/turkish") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "cof_ee/tubruk") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "_coffee/vietnamese") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee_/thai") => LFS_ERR_NOENT; + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + // bad source + lfs_rename(&lfs, + "_offee/drip", + "espresso/espresso") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "c_ffee/coldbrew", + "espresso/americano") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "co_fee/turkish", + "espresso/macchiato") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "cof_ee/tubruk", + "espresso/latte") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "_coffee/vietnamese", + "espresso/cappuccino") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee_/thai", + "espresso/mocha") => LFS_ERR_NOENT; + + // bad destination + lfs_rename(&lfs, + "coffee/drip", + "_spresso/espresso") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/coldbrew", + "e_presso/americano") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/turkish", + "es_resso/macchiato") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tubruk", + "esp_esso/latte") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/vietnamese", + "_espresso/cappuccino") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai", + "espresso_/mocha") => LFS_ERR_NOENT; + + // bad source and bad destination + lfs_rename(&lfs, + "_offee/drip", + "_spresso/espresso") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "c_ffee/coldbrew", + "e_presso/americano") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "co_fee/turkish", + "es_resso/macchiato") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "cof_ee/tubruk", + "esp_esso/latte") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "_coffee/vietnamese", + "_espresso/cappuccino") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee_/thai", + "espresso_/mocha") => LFS_ERR_NOENT; + + // here's a weird one, what happens if our rename is also a noop? + lfs_rename(&lfs, + "_offee/drip", + "_offee/drip") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "c_ffee/coldbrew", + "c_ffee/coldbrew") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "co_fee/turkish", + "co_fee/turkish") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "cof_ee/tubruk", + "cof_ee/tubruk") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "_coffee/vietnamese", + "_coffee/vietnamese") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee_/thai", + "coffee_/thai") => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "_offee/drip") => LFS_ERR_NOENT; + lfs_remove(&lfs, "c_ffee/coldbrew") => LFS_ERR_NOENT; + lfs_remove(&lfs, "co_fee/turkish") => LFS_ERR_NOENT; + lfs_remove(&lfs, "cof_ee/tubruk") => LFS_ERR_NOENT; + lfs_remove(&lfs, "_coffee/vietnamese") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee_/thai") => LFS_ERR_NOENT; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; + + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_unmount(&lfs) => 0; +''' + +# parent notdir tests +[cases.test_paths_notdir_parent] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_file_t file; + lfs_file_open(&lfs, &file, "drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + + if (DIR) { + lfs_mkdir(&lfs, "drip/coffee") => LFS_ERR_NOTDIR; + lfs_mkdir(&lfs, "coldbrew/coffee") => LFS_ERR_NOTDIR; + lfs_mkdir(&lfs, "turkish/coffee") => LFS_ERR_NOTDIR; + lfs_mkdir(&lfs, "tubruk/coffee") => LFS_ERR_NOTDIR; + lfs_mkdir(&lfs, "vietnamese/coffee") => LFS_ERR_NOTDIR; + lfs_mkdir(&lfs, "thai/coffee") => LFS_ERR_NOTDIR; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "drip/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coldbrew/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "turkish/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "tubruk/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "vietnamese/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "thai/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "drip/coffee", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coldbrew/coffee", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "turkish/coffee", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "tubruk/coffee", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "vietnamese/coffee", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "thai/coffee", &info) => LFS_ERR_NOTDIR; + + // file open paths, only works on files! + lfs_file_open(&lfs, &file, "drip/coffee", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coldbrew/coffee", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "turkish/coffee", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "tubruk/coffee", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "vietnamese/coffee", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "thai/coffee", + LFS_O_RDONLY) => LFS_ERR_NOTDIR; + + lfs_file_open(&lfs, &file, "drip/coffee", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coldbrew/coffee", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "turkish/coffee", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "tubruk/coffee", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "vietnamese/coffee", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "thai/coffee", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + + lfs_file_open(&lfs, &file, "drip/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coldbrew/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "turkish/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "tubruk/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "vietnamese/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "thai/coffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + + // dir open paths, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "drip/coffee") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coldbrew/coffee") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "turkish/coffee") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "tubruk/coffee") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "vietnamese/coffee") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "thai/coffee") => LFS_ERR_NOTDIR; + + // make some normal paths so we have something to rename + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/turkish") => 0; + lfs_mkdir(&lfs, "coffee/tubruk") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + // bad source + lfs_rename(&lfs, + "drip/coffee", + "espresso/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coldbrew/coffee", + "espresso/americano") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "turkish/coffee", + "espresso/macchiato") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "tubruk/coffee", + "espresso/latte") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "vietnamese/coffee", + "espresso/cappuccino") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "thai/coffee", + "espresso/mocha") => LFS_ERR_NOTDIR; + + // bad destination + lfs_rename(&lfs, + "coffee/drip", + "drip/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/coldbrew", + "coldbrew/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/turkish", + "turkish/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/tubruk", + "tubruk/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/vietnamese", + "vietnamese/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coffee/thai", + "thai/espresso") => LFS_ERR_NOTDIR; + + // bad source and bad destination + lfs_rename(&lfs, + "drip/coffee", + "drip/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coldbrew/coffee", + "coldbrew/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "turkish/coffee", + "turkish/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "tubruk/coffee", + "tubruk/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "vietnamese/coffee", + "vietnamese/espresso") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "thai/coffee", + "thai/espresso") => LFS_ERR_NOTDIR; + + // here's a weird one, what happens if our rename is also a noop? + lfs_rename(&lfs, + "drip/coffee", + "drip/coffee") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "coldbrew/coffee", + "coldbrew/coffee") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "turkish/coffee", + "turkish/coffee") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "tubruk/coffee", + "tubruk/coffee") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "vietnamese/coffee", + "vietnamese/coffee") => LFS_ERR_NOTDIR; + lfs_rename(&lfs, + "thai/coffee", + "thai/coffee") => LFS_ERR_NOTDIR; + + // remove paths + lfs_stat(&lfs, "drip/espresso", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coldbrew/espresso", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "turkish/espresso", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "tubruk/espresso", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "vietnamese/espresso", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "thai/espresso", &info) => LFS_ERR_NOTDIR; + + // stat paths + lfs_stat(&lfs, "drip/espresso", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "coldbrew/espresso", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "turkish/espresso", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "tubruk/espresso", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "vietnamese/espresso", &info) => LFS_ERR_NOTDIR; + lfs_stat(&lfs, "thai/espresso", &info) => LFS_ERR_NOTDIR; + + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_unmount(&lfs) => 0; +''' + +# noent tests with trailing slashes +[cases.test_paths_noent_trailing_slashes] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/turkish") => 0; + lfs_mkdir(&lfs, "coffee/tubruk") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "coffee/_rip//////", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/c_ldbrew/////", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/tu_kish////", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/tub_uk///", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/_vietnamese//", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/thai_/", &info) => LFS_ERR_NOENT; + + // file open paths, only works on files! + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/_rip/", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/c_ldbrew//", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tu_kish///", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tub_uk////", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/_vietnamese/////", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/thai_//////", + LFS_O_RDONLY) => LFS_ERR_NOENT; + + lfs_file_open(&lfs, &file, "coffee/_rip/", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/c_ldbrew//", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tu_kish///", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tub_uk////", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/_vietnamese/////", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/thai_//////", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR; + + lfs_file_open(&lfs, &file, "coffee/_rip/", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/c_ldbrew//", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tu_kish///", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/tub_uk////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/_vietnamese/////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + lfs_file_open(&lfs, &file, "coffee/thai_//////", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR; + + // dir open paths, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/_rip/") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/c_ldbrew//") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/tu_kish///") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/tub_uk////") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/_vietnamese/////") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/thai_//////") => LFS_ERR_NOENT; + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + // bad source + lfs_rename(&lfs, + "coffee/_rip//////", + "espresso/espresso") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew/////", + "espresso/americano") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish////", + "espresso/macchiato") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk///", + "espresso/latte") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese//", + "espresso/cappuccino") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_/", + "espresso/mocha") => LFS_ERR_NOENT; + + // bad destination + lfs_rename(&lfs, + "coffee/_rip", + "espresso/espresso/") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew", + "espresso/americano//") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish", + "espresso/macchiato///") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk", + "espresso/latte////") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese", + "espresso/cappuccino/////") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_", + "espresso/mocha//////") => LFS_ERR_NOENT; + + // bad source and bad destination + lfs_rename(&lfs, + "coffee/_rip//////", + "espresso/espresso/") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew/////", + "espresso/americano//") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish////", + "espresso/macchiato///") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk///", + "espresso/latte////") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese//", + "espresso/cappuccino/////") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_/", + "espresso/mocha//////") => LFS_ERR_NOENT; + + // here's a weird one, what happens if our rename is also a noop? + lfs_rename(&lfs, + "coffee/_rip//////", + "coffee/_rip//////") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew/////", + "coffee/c_ldbrew/////") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish////", + "coffee/tu_kish////") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk///", + "coffee/tub_uk///") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese//", + "coffee/_vietnamese//") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_/", + "coffee/thai_/") => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "coffee/_rip/") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/c_ldbrew//") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/tu_kish///") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/tub_uk////") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/_vietnamese/////") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/thai_//////") => LFS_ERR_NOENT; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; + + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_unmount(&lfs) => 0; +''' + +# noent tests with trailing dots +[cases.test_paths_noent_trailing_dots] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/turkish") => 0; + lfs_mkdir(&lfs, "coffee/tubruk") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "coffee/_rip/./././././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/c_ldbrew/././././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/tu_kish/./././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/tub_uk/././.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/_vietnamese/./.", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/thai_/.", &info) => LFS_ERR_NOENT; + + // file open paths, only works on files! + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/_rip/.", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/c_ldbrew/./.", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tu_kish/././.", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tub_uk/./././.", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/_vietnamese/././././.", + LFS_O_RDONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/thai_/./././././.", + LFS_O_RDONLY) => LFS_ERR_NOENT; + + lfs_file_open(&lfs, &file, "coffee/_rip/.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/c_ldbrew/./.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tu_kish/././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tub_uk/./././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/_vietnamese/././././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/thai_/./././././.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; + + lfs_file_open(&lfs, &file, "coffee/_rip/.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/c_ldbrew/./.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tu_kish/././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/tub_uk/./././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/_vietnamese/././././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "coffee/thai_/./././././.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOENT; + + // dir open paths, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/_rip/.") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/c_ldbrew/./.") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/tu_kish/././.") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/tub_uk/./././.") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/_vietnamese/././././.") => LFS_ERR_NOENT; + lfs_dir_open(&lfs, &dir, "coffee/thai_/./././././.") => LFS_ERR_NOENT; + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + // bad source + lfs_rename(&lfs, + "coffee/_rip/./././././.", + "espresso/espresso") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew/././././.", + "espresso/americano") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish/./././.", + "espresso/macchiato") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk/././.", + "espresso/latte") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese/./.", + "espresso/cappuccino") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_/.", + "espresso/mocha") => LFS_ERR_NOENT; + + // bad destination + lfs_rename(&lfs, + "coffee/_rip", + "espresso/espresso/.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew", + "espresso/americano/./.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish", + "espresso/macchiato/././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk", + "espresso/latte/./././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese", + "espresso/cappuccino/././././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_", + "espresso/mocha/./././././.") => LFS_ERR_NOENT; + + // bad source and bad destination + lfs_rename(&lfs, + "coffee/_rip/./././././.", + "espresso/espresso/.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew/././././.", + "espresso/americano/./.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish/./././.", + "espresso/macchiato/././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk/././.", + "espresso/latte/./././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese/./.", + "espresso/cappuccino/././././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_/.", + "espresso/mocha/./././././.") => LFS_ERR_NOENT; + + // here's a weird one, what happens if our rename is also a noop? + lfs_rename(&lfs, + "coffee/_rip/./././././.", + "coffee/_rip/./././././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew/././././.", + "coffee/c_ldbrew/././././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish/./././.", + "coffee/tu_kish/./././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk/././.", + "coffee/tub_uk/././.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese/./.", + "coffee/_vietnamese/./.") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_/.", + "coffee/thai_/.") => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "coffee/_rip/.") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/c_ldbrew/./.") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/tu_kish/././.") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/tub_uk/./././.") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/_vietnamese/././././.") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coffee/thai_/./././././.") => LFS_ERR_NOENT; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; + + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_unmount(&lfs) => 0; +''' + +# noent tests with trailing dotdots +[cases.test_paths_noent_trailing_dotdots] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/turkish") => 0; + lfs_mkdir(&lfs, "coffee/tubruk") => 0; + lfs_mkdir(&lfs, "coffee/vietnamese") => 0; + lfs_mkdir(&lfs, "coffee/thai") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/turkish", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/tubruk", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/vietnamese", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/thai", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "coffee/_rip/../../../../../..", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "coffee/c_ldbrew/../../../../..", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "coffee/tu_kish/../../../..", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "coffee/tub_uk/../../..", &info) => LFS_ERR_INVAL; + lfs_stat(&lfs, "coffee/_vietnamese/../..", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "coffee/thai_/..", &info) => 0; + assert(strcmp(info.name, "coffee") == 0); + assert(info.type == LFS_TYPE_DIR); + + // file open paths, only works on files! + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/_rip/..", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/c_ldbrew/../..", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/tu_kish/../../..", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/tub_uk/../../../..", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/_vietnamese/../../../../..", + LFS_O_RDONLY) => LFS_ERR_INVAL; + lfs_file_open(&lfs, &file, "coffee/thai_/../../../../../..", + LFS_O_RDONLY) => LFS_ERR_INVAL; + + // dir open paths, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/_rip/..") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/c_ldbrew/../..") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/tu_kish/../../..") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "coffee/tub_uk/../../../..") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "coffee/_vietnamese/../../../../..") => LFS_ERR_INVAL; + lfs_dir_open(&lfs, &dir, "coffee/thai_/../../../../../..") => LFS_ERR_INVAL; + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + // bad source + lfs_rename(&lfs, + "coffee/_rip/../../../../../..", + "espresso/espresso") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/c_ldbrew/../../../../..", + "espresso/americano") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/tu_kish/../../../..", + "espresso/macchiato") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/tub_uk/../../..", + "espresso/latte") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/_vietnamese/../..", + "espresso/cappuccino") => LFS_ERR_INVAL; + // this one works + lfs_rename(&lfs, + "coffee/thai_/..", + "espresso/mocha") => 0; + lfs_rename(&lfs, + "espresso/mocha", + "coffee") => 0; + + // bad destination + lfs_rename(&lfs, + "coffee/_rip", + "espresso/espresso/..") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/c_ldbrew", + "espresso/americano/../..") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tu_kish", + "espresso/macchiato/../../..") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/tub_uk", + "espresso/latte/../../../..") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/_vietnamese", + "espresso/cappuccino/../../../../..") => LFS_ERR_NOENT; + lfs_rename(&lfs, + "coffee/thai_", + "espresso/mocha/../../../../../..") => LFS_ERR_NOENT; + + // bad source and bad destination + lfs_rename(&lfs, + "coffee/_rip/../../../../../..", + "espresso/espresso/..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/c_ldbrew/../../../../..", + "espresso/americano/../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/tu_kish/../../../..", + "espresso/macchiato/../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/tub_uk/../../..", + "espresso/latte/../../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/_vietnamese/../..", + "espresso/cappuccino/../../../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/thai_/..", + "espresso/mocha/../../../../../..") => LFS_ERR_INVAL; + + // here's a weird one, what happens if our rename is also a noop? + lfs_rename(&lfs, + "coffee/_rip/../../../../../..", + "coffee/_rip/../../../../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/c_ldbrew/../../../../..", + "coffee/c_ldbrew/../../../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/tu_kish/../../../..", + "coffee/tu_kish/../../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/tub_uk/../../..", + "coffee/tub_uk/../../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/_vietnamese/../..", + "coffee/_vietnamese/../..") => LFS_ERR_INVAL; + lfs_rename(&lfs, + "coffee/thai_/..", + "coffee/thai_/..") => 0; + + // remove paths + lfs_remove(&lfs, "coffee/_rip/..") => LFS_ERR_NOTEMPTY; + lfs_remove(&lfs, "coffee/c_ldbrew/../..") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee/tu_kish/../../..") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee/tub_uk/../../../..") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee/_vietnamese/../../../../..") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee/thai_/../../../../../..") => LFS_ERR_INVAL; + + // stat paths + lfs_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT; + + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/turkish", &info) => 0; + assert(strcmp(info.name, "turkish") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/tubruk", &info) => 0; + assert(strcmp(info.name, "tubruk") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/vietnamese", &info) => 0; + assert(strcmp(info.name, "vietnamese") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/thai", &info) => 0; + assert(strcmp(info.name, "thai") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_unmount(&lfs) => 0; +''' + +# test an empty path, this should error +[cases.test_paths_empty] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; + + // create empty, this should error + if (DIR) { + lfs_mkdir(&lfs, "") => LFS_ERR_INVAL; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + } + + // stat empty + lfs_stat(&lfs, "", &info) => LFS_ERR_INVAL; + + // file open empty, only works on files! + lfs_file_t file; + lfs_file_open(&lfs, &file, "", + LFS_O_RDONLY) => LFS_ERR_INVAL; + + lfs_file_open(&lfs, &file, "", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_INVAL; + + lfs_file_open(&lfs, &file, "", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_INVAL; + + // dir open empty, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "") => LFS_ERR_INVAL; + lfs_dir_close(&lfs, &dir) => 0; + + // rename empty, this should error + lfs_rename(&lfs, "", "coffee") => LFS_ERR_INVAL; + + lfs_mkdir(&lfs, "coffee") => 0; + lfs_rename(&lfs, "coffee", "") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee") => 0; + + lfs_rename(&lfs, "", "") => LFS_ERR_INVAL; + + // stat empty + lfs_stat(&lfs, "", &info) => LFS_ERR_INVAL; + + // remove empty, this should error + lfs_remove(&lfs, "") => LFS_ERR_INVAL; + + // stat empty + lfs_stat(&lfs, "", &info) => LFS_ERR_INVAL; + + lfs_unmount(&lfs) => 0; +''' + +# root operations +# +# POSIX deviations: +# +# - Root modifications return EINVAL instead of EBUSY: +# - littlefs: remove("/") => EINVAL +# - POSIX: remove("/") => EBUSY +# Reason: This would be the only use of EBUSY in the system. +# +[cases.test_paths_root] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; + + // create root, this should error + if (DIR) { + lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + } + + // stat root + lfs_stat(&lfs, "/", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + + // file open root, only works on files! + lfs_file_t file; + lfs_file_open(&lfs, &file, "/", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + + // dir open root, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_close(&lfs, &dir) => 0; + + // rename root, this should error + lfs_rename(&lfs, "/", "coffee") => LFS_ERR_INVAL; + + lfs_mkdir(&lfs, "coffee") => 0; + lfs_rename(&lfs, "coffee", "/") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee") => 0; + + lfs_rename(&lfs, "/", "/") => LFS_ERR_INVAL; + + // stat root + lfs_stat(&lfs, "/", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + + // remove root, this should error + lfs_remove(&lfs, "/") => LFS_ERR_INVAL; + + // stat root + lfs_stat(&lfs, "/", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + + lfs_unmount(&lfs) => 0; +''' + +# other root representations +[cases.test_paths_root_aliases] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; + + // create root, this should error + if (DIR) { + lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; + lfs_mkdir(&lfs, ".") => LFS_ERR_EXIST; + lfs_mkdir(&lfs, "./") => LFS_ERR_EXIST; + lfs_mkdir(&lfs, "/.") => LFS_ERR_EXIST; + lfs_mkdir(&lfs, "//") => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "/", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, ".", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "./", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "//", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + } + + // stat root + lfs_stat(&lfs, "/", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, ".", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "./", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "/.", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "//", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + + // file open root, only works on files! + lfs_file_t file; + lfs_file_open(&lfs, &file, "/", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, ".", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "./", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/.", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "//", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, ".", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "./", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/.", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "//", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "/", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, ".", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "./", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/.", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "//", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + + // dir open root, only works on dirs! + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, ".") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "./") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "/.") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "//") => 0; + lfs_dir_close(&lfs, &dir) => 0; + + // rename root, this should error + lfs_rename(&lfs, "/", "coffee") => LFS_ERR_INVAL; + lfs_rename(&lfs, ".", "coffee") => LFS_ERR_INVAL; + lfs_rename(&lfs, "./", "coffee") => LFS_ERR_INVAL; + lfs_rename(&lfs, "/.", "coffee") => LFS_ERR_INVAL; + lfs_rename(&lfs, "//", "coffee") => LFS_ERR_INVAL; + + lfs_mkdir(&lfs, "coffee") => 0; + lfs_rename(&lfs, "coffee", "/") => LFS_ERR_INVAL; + lfs_rename(&lfs, "coffee", ".") => LFS_ERR_INVAL; + lfs_rename(&lfs, "coffee", "./") => LFS_ERR_INVAL; + lfs_rename(&lfs, "coffee", "/.") => LFS_ERR_INVAL; + lfs_rename(&lfs, "coffee", "//") => LFS_ERR_INVAL; + lfs_remove(&lfs, "coffee") => 0; + + lfs_rename(&lfs, "/", "/") => LFS_ERR_INVAL; + lfs_rename(&lfs, ".", ".") => LFS_ERR_INVAL; + lfs_rename(&lfs, "..", "..") => LFS_ERR_INVAL; + lfs_rename(&lfs, "./", "./") => LFS_ERR_INVAL; + lfs_rename(&lfs, "/.", "/.") => LFS_ERR_INVAL; + lfs_rename(&lfs, "//", "//") => LFS_ERR_INVAL; + + // stat root + lfs_stat(&lfs, "/", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, ".", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "./", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "/.", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "//", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + + // remove root, this should error + lfs_remove(&lfs, "/") => LFS_ERR_INVAL; + lfs_remove(&lfs, ".") => LFS_ERR_INVAL; + lfs_remove(&lfs, "./") => LFS_ERR_INVAL; + lfs_remove(&lfs, "/.") => LFS_ERR_INVAL; + lfs_remove(&lfs, "//") => LFS_ERR_INVAL; + + // stat root + lfs_stat(&lfs, "/", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, ".", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "./", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "/.", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + lfs_stat(&lfs, "//", &info) => 0; + assert(strcmp(info.name, "/") == 0); + assert(info.type == LFS_TYPE_DIR); + + lfs_unmount(&lfs) => 0; +''' + +# superblock magic shouldn't appear as a file +[cases.test_paths_magic_noent] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // stat littlefs, which shouldn't exist + struct lfs_info info; + lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; + + // file open littlefs, which shouldn't exist + lfs_file_t file; + lfs_file_open(&lfs, &file, "littlefs", + LFS_O_RDONLY) => LFS_ERR_NOENT; + + // dir open littlefs, which shouldn't exist + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "littlefs") => LFS_ERR_NOENT; + + // rename littlefs, which shouldn't exist + lfs_rename(&lfs, "littlefs", "coffee") => LFS_ERR_NOENT; + + // remove littlefs, which shouldn't exist + lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT; + + // stat littlefs, which shouldn't exist + lfs_stat(&lfs, "coffee", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# superblock magic shouldn't conflict with files, that would be silly +[cases.test_paths_magic_conflict] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create littlefs + if (DIR) { + lfs_mkdir(&lfs, "littlefs") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "littlefs", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat littlefs + struct lfs_info info; + lfs_stat(&lfs, "littlefs", &info) => 0; + assert(strcmp(info.name, "littlefs") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open littlefs, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "littlefs", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "littlefs", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "littlefs", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "littlefs", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "littlefs", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "littlefs", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open littlefs, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "littlefs") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "littlefs") => LFS_ERR_NOTDIR; + } + + // rename littlefs + lfs_rename(&lfs, "littlefs", "coffee") => 0; + lfs_rename(&lfs, "coffee", "littlefs") => 0; + + // stat littlefs + lfs_stat(&lfs, "littlefs", &info) => 0; + assert(strcmp(info.name, "littlefs") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "coffee", &info) => LFS_ERR_NOENT; + + // remove littlefs + lfs_remove(&lfs, "littlefs") => 0; + + // stat littlefs + lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# test name too long +[cases.test_paths_nametoolong] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + char a_name[512]; + memset(a_name, 'a', LFS_NAME_MAX+1); + a_name[LFS_NAME_MAX+1] = '\0'; + + // create names that are too long, should error + char path[1024]; + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + sprintf(path, "coffee/%s", a_name); + lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; + } else { + lfs_file_t file; + sprintf(path, "coffee/%s", a_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NAMETOOLONG; + } + + // stat paths + struct lfs_info info; + sprintf(path, "coffee/%s", a_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + + // file open paths, only works on files! + lfs_file_t file; + sprintf(path, "coffee/%s", a_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => LFS_ERR_NOENT; + + // dir open paths, only works on dirs! + lfs_dir_t dir; + sprintf(path, "coffee/%s", a_name); + lfs_dir_open(&lfs, &dir, path) => LFS_ERR_NOENT; + + // rename paths + lfs_mkdir(&lfs, "espresso") => 0; + sprintf(path, "coffee/%s", a_name); + lfs_rename(&lfs, path, "espresso/espresso") => LFS_ERR_NOENT; + + // renaming with too long a destination is tricky! + if (DIR) { + lfs_mkdir(&lfs, "coffee/drip") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/drip", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + sprintf(path, "espresso/%s", a_name); + lfs_rename(&lfs, "coffee/drip", path) => LFS_ERR_NAMETOOLONG; + + // stat paths + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + sprintf(path, "espresso/%s", a_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + + // remove paths + sprintf(path, "espresso/%s", a_name); + lfs_remove(&lfs, path) => LFS_ERR_NOENT; + + // stat paths + lfs_stat(&lfs, "coffee/drip", &info) => 0; + assert(strcmp(info.name, "drip") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + sprintf(path, "espresso/%s", a_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# test name really long but not too long +[cases.test_paths_namejustlongenough] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + char a_name[512]; + memset(a_name, 'a', LFS_NAME_MAX); + a_name[LFS_NAME_MAX] = '\0'; + char b_name[512]; + memset(b_name, 'b', LFS_NAME_MAX); + b_name[LFS_NAME_MAX] = '\0'; + char c_name[512]; + memset(c_name, 'c', LFS_NAME_MAX); + c_name[LFS_NAME_MAX] = '\0'; + char d_name[512]; + memset(d_name, 'd', LFS_NAME_MAX); + d_name[LFS_NAME_MAX] = '\0'; + char e_name[512]; + memset(e_name, 'e', LFS_NAME_MAX); + e_name[LFS_NAME_MAX] = '\0'; + char f_name[512]; + memset(f_name, 'f', LFS_NAME_MAX); + f_name[LFS_NAME_MAX] = '\0'; + char g_name[512]; + memset(g_name, 'g', LFS_NAME_MAX); + g_name[LFS_NAME_MAX] = '\0'; + char h_name[512]; + memset(h_name, 'h', LFS_NAME_MAX); + h_name[LFS_NAME_MAX] = '\0'; + char i_name[512]; + memset(i_name, 'i', LFS_NAME_MAX); + i_name[LFS_NAME_MAX] = '\0'; + char j_name[512]; + memset(j_name, 'j', LFS_NAME_MAX); + j_name[LFS_NAME_MAX] = '\0'; + char k_name[512]; + memset(k_name, 'k', LFS_NAME_MAX); + k_name[LFS_NAME_MAX] = '\0'; + char l_name[512]; + memset(l_name, 'l', LFS_NAME_MAX); + l_name[LFS_NAME_MAX] = '\0'; + + // create names that aren't too long + lfs_mkdir(&lfs, c_name) => 0; + char path[1024]; + if (DIR) { + sprintf(path, "%s/%s", c_name, a_name); + lfs_mkdir(&lfs, path) => 0; + sprintf(path, "%s/%s", c_name, b_name); + lfs_mkdir(&lfs, path) => 0; + sprintf(path, "%s/%s", c_name, c_name); + lfs_mkdir(&lfs, path) => 0; + sprintf(path, "%s/%s", c_name, d_name); + lfs_mkdir(&lfs, path) => 0; + sprintf(path, "%s/%s", c_name, e_name); + lfs_mkdir(&lfs, path) => 0; + sprintf(path, "%s/%s", c_name, f_name); + lfs_mkdir(&lfs, path) => 0; + } else { + lfs_file_t file; + sprintf(path, "%s/%s", c_name, a_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, b_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, c_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, d_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, e_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, f_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + sprintf(path, "%s/%s", c_name, a_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, a_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + sprintf(path, "%s/%s", c_name, b_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, b_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + sprintf(path, "%s/%s", c_name, c_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, c_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + sprintf(path, "%s/%s", c_name, d_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, d_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + sprintf(path, "%s/%s", c_name, e_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, e_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + sprintf(path, "%s/%s", c_name, f_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, f_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + sprintf(path, "%s/%s", c_name, a_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => LFS_ERR_ISDIR; + sprintf(path, "%s/%s", c_name, b_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => LFS_ERR_ISDIR; + sprintf(path, "%s/%s", c_name, c_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => LFS_ERR_ISDIR; + sprintf(path, "%s/%s", c_name, d_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => LFS_ERR_ISDIR; + sprintf(path, "%s/%s", c_name, e_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => LFS_ERR_ISDIR; + sprintf(path, "%s/%s", c_name, f_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + sprintf(path, "%s/%s", c_name, a_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + sprintf(path, "%s/%s", c_name, b_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + sprintf(path, "%s/%s", c_name, c_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + sprintf(path, "%s/%s", c_name, d_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + sprintf(path, "%s/%s", c_name, e_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + sprintf(path, "%s/%s", c_name, f_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + sprintf(path, "%s/%s", c_name, a_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + sprintf(path, "%s/%s", c_name, b_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + sprintf(path, "%s/%s", c_name, c_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + sprintf(path, "%s/%s", c_name, d_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + sprintf(path, "%s/%s", c_name, e_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + sprintf(path, "%s/%s", c_name, f_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + sprintf(path, "%s/%s", c_name, a_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, b_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, c_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, d_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, e_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, f_name); + lfs_file_open(&lfs, &file, path, + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + sprintf(path, "%s/%s", c_name, a_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, b_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, c_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, d_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, e_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + sprintf(path, "%s/%s", c_name, f_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + sprintf(path, "%s/%s", c_name, a_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + sprintf(path, "%s/%s", c_name, b_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + sprintf(path, "%s/%s", c_name, c_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + sprintf(path, "%s/%s", c_name, d_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + sprintf(path, "%s/%s", c_name, e_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + sprintf(path, "%s/%s", c_name, f_name); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + sprintf(path, "%s/%s", c_name, a_name); + lfs_dir_open(&lfs, &dir, path) => 0; + lfs_dir_close(&lfs, &dir) => 0; + sprintf(path, "%s/%s", c_name, b_name); + lfs_dir_open(&lfs, &dir, path) => 0; + lfs_dir_close(&lfs, &dir) => 0; + sprintf(path, "%s/%s", c_name, c_name); + lfs_dir_open(&lfs, &dir, path) => 0; + lfs_dir_close(&lfs, &dir) => 0; + sprintf(path, "%s/%s", c_name, d_name); + lfs_dir_open(&lfs, &dir, path) => 0; + lfs_dir_close(&lfs, &dir) => 0; + sprintf(path, "%s/%s", c_name, e_name); + lfs_dir_open(&lfs, &dir, path) => 0; + lfs_dir_close(&lfs, &dir) => 0; + sprintf(path, "%s/%s", c_name, f_name); + lfs_dir_open(&lfs, &dir, path) => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + sprintf(path, "%s/%s", c_name, a_name); + lfs_dir_open(&lfs, &dir, path) => LFS_ERR_NOTDIR; + sprintf(path, "%s/%s", c_name, b_name); + lfs_dir_open(&lfs, &dir, path) => LFS_ERR_NOTDIR; + sprintf(path, "%s/%s", c_name, c_name); + lfs_dir_open(&lfs, &dir, path) => LFS_ERR_NOTDIR; + sprintf(path, "%s/%s", c_name, d_name); + lfs_dir_open(&lfs, &dir, path) => LFS_ERR_NOTDIR; + sprintf(path, "%s/%s", c_name, e_name); + lfs_dir_open(&lfs, &dir, path) => LFS_ERR_NOTDIR; + sprintf(path, "%s/%s", c_name, f_name); + lfs_dir_open(&lfs, &dir, path) => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, e_name) => 0; + char path_[1024]; + sprintf(path, "%s/%s", c_name, a_name); + sprintf(path_, "%s/%s", e_name, g_name); + lfs_rename(&lfs, path, path_) => 0; + sprintf(path, "%s/%s", c_name, b_name); + sprintf(path_, "%s/%s", e_name, h_name); + lfs_rename(&lfs, path, path_) => 0; + sprintf(path, "%s/%s", c_name, c_name); + sprintf(path_, "%s/%s", e_name, i_name); + lfs_rename(&lfs, path, path_) => 0; + sprintf(path, "%s/%s", c_name, d_name); + sprintf(path_, "%s/%s", e_name, j_name); + lfs_rename(&lfs, path, path_) => 0; + sprintf(path, "%s/%s", c_name, e_name); + sprintf(path_, "%s/%s", e_name, k_name); + lfs_rename(&lfs, path, path_) => 0; + sprintf(path, "%s/%s", c_name, f_name); + sprintf(path_, "%s/%s", e_name, l_name); + lfs_rename(&lfs, path, path_) => 0; + + // stat paths + sprintf(path, "%s/%s", e_name, g_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, g_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + sprintf(path, "%s/%s", e_name, h_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, h_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + sprintf(path, "%s/%s", e_name, i_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, i_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + sprintf(path, "%s/%s", e_name, j_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, j_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + sprintf(path, "%s/%s", e_name, k_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, k_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + sprintf(path, "%s/%s", e_name, l_name); + lfs_stat(&lfs, path, &info) => 0; + assert(strcmp(info.name, l_name) == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + sprintf(path, "%s/%s", c_name, a_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + sprintf(path, "%s/%s", c_name, b_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + sprintf(path, "%s/%s", c_name, c_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + sprintf(path, "%s/%s", c_name, d_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + sprintf(path, "%s/%s", c_name, e_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + sprintf(path, "%s/%s", c_name, f_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + + // remove paths + sprintf(path, "%s/%s", e_name, g_name); + lfs_remove(&lfs, path) => 0; + sprintf(path, "%s/%s", e_name, h_name); + lfs_remove(&lfs, path) => 0; + sprintf(path, "%s/%s", e_name, i_name); + lfs_remove(&lfs, path) => 0; + sprintf(path, "%s/%s", e_name, j_name); + lfs_remove(&lfs, path) => 0; + sprintf(path, "%s/%s", e_name, k_name); + lfs_remove(&lfs, path) => 0; + sprintf(path, "%s/%s", e_name, l_name); + lfs_remove(&lfs, path) => 0; + + // stat paths + sprintf(path, "%s/%s", e_name, g_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + sprintf(path, "%s/%s", e_name, h_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + sprintf(path, "%s/%s", e_name, i_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + sprintf(path, "%s/%s", e_name, j_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + sprintf(path, "%s/%s", e_name, k_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + sprintf(path, "%s/%s", e_name, l_name); + lfs_stat(&lfs, path, &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# a quick utf8 test, utf8 is easy to support +[cases.test_paths_utf8] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "coffee") => 0; + if (DIR) { + lfs_mkdir(&lfs, "coffee/dripcoffee") => 0; + lfs_mkdir(&lfs, "coffee/coldbrew") => 0; + lfs_mkdir(&lfs, "coffee/türkkahvesi") => 0; + lfs_mkdir(&lfs, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀") => 0; + lfs_mkdir(&lfs, "coffee/càphêđá") => 0; + lfs_mkdir(&lfs, "coffee/โอเลี้ยง") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/dripcoffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/türkkahvesi", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/càphêđá", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/โอเลี้ยง", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "coffee/dripcoffee", &info) => 0; + assert(strcmp(info.name, "dripcoffee") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/coldbrew", &info) => 0; + assert(strcmp(info.name, "coldbrew") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/türkkahvesi", &info) => 0; + assert(strcmp(info.name, "türkkahvesi") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀", &info) => 0; + assert(strcmp(info.name, "ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/càphêđá", &info) => 0; + assert(strcmp(info.name, "càphêđá") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "coffee/โอเลี้ยง", &info) => 0; + assert(strcmp(info.name, "โอเลี้ยง") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/dripcoffee", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/türkkahvesi", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/càphêđá", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/โอเลี้ยง", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "coffee/dripcoffee", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/türkkahvesi", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/càphêđá", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "coffee/โอเลี้ยง", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "coffee/dripcoffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/türkkahvesi", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/càphêđá", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/โอเลี้ยง", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "coffee/dripcoffee", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/türkkahvesi", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/càphêđá", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/โอเลี้ยง", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "coffee/dripcoffee", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/türkkahvesi", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/càphêđá", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "coffee/โอเลี้ยง", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "coffee/dripcoffee", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/coldbrew", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/türkkahvesi", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/càphêđá", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "coffee/โอเลี้ยง", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/dripcoffee") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/coldbrew") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/türkkahvesi") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/càphêđá") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "coffee/โอเลี้ยง") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "coffee/dripcoffee") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/coldbrew") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/türkkahvesi") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/càphêđá") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "coffee/โอเลี้ยง") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "caffè") => 0; + lfs_rename(&lfs, + "coffee/dripcoffee", + "caffè/espresso") => 0; + lfs_rename(&lfs, + "coffee/coldbrew", + "caffè/americano") => 0; + lfs_rename(&lfs, + "coffee/türkkahvesi", + "caffè/macchiato") => 0; + lfs_rename(&lfs, + "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀", + "caffè/latte") => 0; + lfs_rename(&lfs, + "coffee/càphêđá", + "caffè/cappuccino") => 0; + lfs_rename(&lfs, + "coffee/โอเลี้ยง", + "caffè/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "caffè/espresso", &info) => 0; + assert(strcmp(info.name, "espresso") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "caffè/americano", &info) => 0; + assert(strcmp(info.name, "americano") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "caffè/macchiato", &info) => 0; + assert(strcmp(info.name, "macchiato") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "caffè/latte", &info) => 0; + assert(strcmp(info.name, "latte") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "caffè/cappuccino", &info) => 0; + assert(strcmp(info.name, "cappuccino") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "caffè/mocha", &info) => 0; + assert(strcmp(info.name, "mocha") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "coffee/dripcoffee", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/coldbrew", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/türkkahvesi", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/ꦏꦺꦴꦥꦶꦠꦸꦧꦿꦸꦏ꧀", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/càphêđá", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "coffee/โอเลี้ยง", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "caffè/espresso") => 0; + lfs_remove(&lfs, "caffè/americano") => 0; + lfs_remove(&lfs, "caffè/macchiato") => 0; + lfs_remove(&lfs, "caffè/latte") => 0; + lfs_remove(&lfs, "caffè/cappuccino") => 0; + lfs_remove(&lfs, "caffè/mocha") => 0; + + // stat paths + lfs_stat(&lfs, "caffè/espresso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "caffè/americano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "caffè/macchiato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "caffè/latte", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "caffè/cappuccino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "caffè/mocha", &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# more utf8 tests +[cases.test_paths_utf8_ipa] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "ˈkɔ.fi") => 0; + if (DIR) { + lfs_mkdir(&lfs, "ˈkɔ.fi/dɹɪpˈkɔ.fi") => 0; + lfs_mkdir(&lfs, "ˈkɔ.fi/koʊldbɹuː") => 0; + lfs_mkdir(&lfs, "ˈkɔ.fi/tyɾckɑhvɛˈsi") => 0; + lfs_mkdir(&lfs, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚") => 0; + lfs_mkdir(&lfs, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥") => 0; + lfs_mkdir(&lfs, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/dɹɪpˈkɔ.fi", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/koʊldbɹuː", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/tyɾckɑhvɛˈsi", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "ˈkɔ.fi/dɹɪpˈkɔ.fi", &info) => 0; + assert(strcmp(info.name, "dɹɪpˈkɔ.fi") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "ˈkɔ.fi/koʊldbɹuː", &info) => 0; + assert(strcmp(info.name, "koʊldbɹuː") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "ˈkɔ.fi/tyɾckɑhvɛˈsi", &info) => 0; + assert(strcmp(info.name, "tyɾckɑhvɛˈsi") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚", &info) => 0; + assert(strcmp(info.name, "ˈko.piˈt̪up̚.rʊk̚") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥", &info) => 0; + assert(strcmp(info.name, "kaː˨˩fe˧˧ɗaː˧˥") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥", &info) => 0; + assert(strcmp(info.name, "ʔoː˧.lia̯ŋ˦˥") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/dɹɪpˈkɔ.fi", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/koʊldbɹuː", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/tyɾckɑhvɛˈsi", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "ˈkɔ.fi/dɹɪpˈkɔ.fi", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/koʊldbɹuː", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/tyɾckɑhvɛˈsi", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "ˈkɔ.fi/dɹɪpˈkɔ.fi", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/koʊldbɹuː", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/tyɾckɑhvɛˈsi", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/dɹɪpˈkɔ.fi", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/koʊldbɹuː", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/tyɾckɑhvɛˈsi", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "ˈkɔ.fi/dɹɪpˈkɔ.fi", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/koʊldbɹuː", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/tyɾckɑhvɛˈsi", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "ˈkɔ.fi/dɹɪpˈkɔ.fi", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/koʊldbɹuː", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/tyɾckɑhvɛˈsi", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/dɹɪpˈkɔ.fi") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/koʊldbɹuː") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/tyɾckɑhvɛˈsi") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/dɹɪpˈkɔ.fi") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/koʊldbɹuː") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/tyɾckɑhvɛˈsi") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "kafˈfɛ") => 0; + lfs_rename(&lfs, + "ˈkɔ.fi/dɹɪpˈkɔ.fi", + "kafˈfɛ/eˈsprɛsso") => 0; + lfs_rename(&lfs, + "ˈkɔ.fi/koʊldbɹuː", + "kafˈfɛ/ameriˈkano") => 0; + lfs_rename(&lfs, + "ˈkɔ.fi/tyɾckɑhvɛˈsi", + "kafˈfɛ/makˈkjato") => 0; + lfs_rename(&lfs, + "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚", + "kafˈfɛ/ˈlat.te") => 0; + lfs_rename(&lfs, + "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥", + "kafˈfɛ/kapputˈt͡ʃino") => 0; + lfs_rename(&lfs, + "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥", + "kafˈfɛ/ˈmoʊkə") => 0; + + // stat paths + lfs_stat(&lfs, "kafˈfɛ/eˈsprɛsso", &info) => 0; + assert(strcmp(info.name, "eˈsprɛsso") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "kafˈfɛ/ameriˈkano", &info) => 0; + assert(strcmp(info.name, "ameriˈkano") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "kafˈfɛ/makˈkjato", &info) => 0; + assert(strcmp(info.name, "makˈkjato") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "kafˈfɛ/ˈlat.te", &info) => 0; + assert(strcmp(info.name, "ˈlat.te") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "kafˈfɛ/kapputˈt͡ʃino", &info) => 0; + assert(strcmp(info.name, "kapputˈt͡ʃino") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "kafˈfɛ/ˈmoʊkə", &info) => 0; + assert(strcmp(info.name, "ˈmoʊkə") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "ˈkɔ.fi/dɹɪpˈkɔ.fi", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "ˈkɔ.fi/koʊldbɹuː", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "ˈkɔ.fi/tyɾckɑhvɛˈsi", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "ˈkɔ.fi/ˈko.piˈt̪up̚.rʊk̚", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "ˈkɔ.fi/kaː˨˩fe˧˧ɗaː˧˥", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "ˈkɔ.fi/ʔoː˧.lia̯ŋ˦˥", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "kafˈfɛ/eˈsprɛsso") => 0; + lfs_remove(&lfs, "kafˈfɛ/ameriˈkano") => 0; + lfs_remove(&lfs, "kafˈfɛ/makˈkjato") => 0; + lfs_remove(&lfs, "kafˈfɛ/ˈlat.te") => 0; + lfs_remove(&lfs, "kafˈfɛ/kapputˈt͡ʃino") => 0; + lfs_remove(&lfs, "kafˈfɛ/ˈmoʊkə") => 0; + + // stat paths + lfs_stat(&lfs, "kafˈfɛ/eˈsprɛsso", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "kafˈfɛ/ameriˈkano", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "kafˈfɛ/makˈkjato", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "kafˈfɛ/ˈlat.te", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "kafˈfɛ/kapputˈt͡ʃino", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "kafˈfɛ/ˈmoʊkə", &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# test spaces have no problems +[cases.test_paths_spaces] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "c o f f e e") => 0; + if (DIR) { + lfs_mkdir(&lfs, "c o f f e e/d r i p") => 0; + lfs_mkdir(&lfs, "c o f f e e/c o l d b r e w") => 0; + lfs_mkdir(&lfs, "c o f f e e/t u r k i s h") => 0; + lfs_mkdir(&lfs, "c o f f e e/t u b r u k") => 0; + lfs_mkdir(&lfs, "c o f f e e/v i e t n a m e s e") => 0; + lfs_mkdir(&lfs, "c o f f e e/t h a i") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "c o f f e e/d r i p", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/c o l d b r e w", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/t u r k i s h", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/t u b r u k", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/v i e t n a m e s e", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/t h a i", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "c o f f e e/d r i p", &info) => 0; + assert(strcmp(info.name, "d r i p") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "c o f f e e/c o l d b r e w", &info) => 0; + assert(strcmp(info.name, "c o l d b r e w") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "c o f f e e/t u r k i s h", &info) => 0; + assert(strcmp(info.name, "t u r k i s h") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "c o f f e e/t u b r u k", &info) => 0; + assert(strcmp(info.name, "t u b r u k") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "c o f f e e/v i e t n a m e s e", &info) => 0; + assert(strcmp(info.name, "v i e t n a m e s e") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "c o f f e e/t h a i", &info) => 0; + assert(strcmp(info.name, "t h a i") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "c o f f e e/d r i p", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "c o f f e e/c o l d b r e w", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "c o f f e e/t u r k i s h", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "c o f f e e/t u b r u k", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "c o f f e e/v i e t n a m e s e", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "c o f f e e/t h a i", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "c o f f e e/d r i p", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "c o f f e e/c o l d b r e w", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "c o f f e e/t u r k i s h", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "c o f f e e/t u b r u k", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "c o f f e e/v i e t n a m e s e", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "c o f f e e/t h a i", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "c o f f e e/d r i p", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "c o f f e e/c o l d b r e w", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "c o f f e e/t u r k i s h", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "c o f f e e/t u b r u k", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "c o f f e e/v i e t n a m e s e", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "c o f f e e/t h a i", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "c o f f e e/d r i p", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/c o l d b r e w", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/t u r k i s h", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/t u b r u k", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/v i e t n a m e s e", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/t h a i", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "c o f f e e/d r i p", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/c o l d b r e w", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/t u r k i s h", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/t u b r u k", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/v i e t n a m e s e", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "c o f f e e/t h a i", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "c o f f e e/d r i p", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "c o f f e e/c o l d b r e w", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "c o f f e e/t u r k i s h", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "c o f f e e/t u b r u k", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "c o f f e e/v i e t n a m e s e", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "c o f f e e/t h a i", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "c o f f e e/d r i p") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "c o f f e e/c o l d b r e w") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "c o f f e e/t u r k i s h") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "c o f f e e/t u b r u k") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "c o f f e e/v i e t n a m e s e") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "c o f f e e/t h a i") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "c o f f e e/d r i p") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "c o f f e e/c o l d b r e w") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "c o f f e e/t u r k i s h") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "c o f f e e/t u b r u k") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "c o f f e e/v i e t n a m e s e") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "c o f f e e/t h a i") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "e s p r e s s o") => 0; + lfs_rename(&lfs, + "c o f f e e/d r i p", + "e s p r e s s o/e s p r e s s o") => 0; + lfs_rename(&lfs, + "c o f f e e/c o l d b r e w", + "e s p r e s s o/a m e r i c a n o") => 0; + lfs_rename(&lfs, + "c o f f e e/t u r k i s h", + "e s p r e s s o/m a c c h i a t o") => 0; + lfs_rename(&lfs, + "c o f f e e/t u b r u k", + "e s p r e s s o/l a t t e") => 0; + lfs_rename(&lfs, + "c o f f e e/v i e t n a m e s e", + "e s p r e s s o/c a p p u c c i n o") => 0; + lfs_rename(&lfs, + "c o f f e e/t h a i", + "e s p r e s s o/m o c h a") => 0; + + // stat paths + lfs_stat(&lfs, "e s p r e s s o/e s p r e s s o", &info) => 0; + assert(strcmp(info.name, "e s p r e s s o") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "e s p r e s s o/a m e r i c a n o", &info) => 0; + assert(strcmp(info.name, "a m e r i c a n o") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "e s p r e s s o/m a c c h i a t o", &info) => 0; + assert(strcmp(info.name, "m a c c h i a t o") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "e s p r e s s o/l a t t e", &info) => 0; + assert(strcmp(info.name, "l a t t e") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "e s p r e s s o/c a p p u c c i n o", &info) => 0; + assert(strcmp(info.name, "c a p p u c c i n o") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "e s p r e s s o/m o c h a", &info) => 0; + assert(strcmp(info.name, "m o c h a") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "c o f f e e/d r i p", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "c o f f e e/c o l d b r e w", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "c o f f e e/t u r k i s h", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "c o f f e e/t u b r u k", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "c o f f e e/v i e t n a m e s e", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "c o f f e e/t h a i", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "e s p r e s s o/e s p r e s s o") => 0; + lfs_remove(&lfs, "e s p r e s s o/a m e r i c a n o") => 0; + lfs_remove(&lfs, "e s p r e s s o/m a c c h i a t o") => 0; + lfs_remove(&lfs, "e s p r e s s o/l a t t e") => 0; + lfs_remove(&lfs, "e s p r e s s o/c a p p u c c i n o") => 0; + lfs_remove(&lfs, "e s p r e s s o/m o c h a") => 0; + + // stat paths + lfs_stat(&lfs, "e s p r e s s o/e s p r e s s o", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "e s p r e s s o/a m e r i c a n o", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "e s p r e s s o/m a c c h i a t o", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "e s p r e s s o/l a t t e", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "e s p r e s s o/c a p p u c c i n o", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "e s p r e s s o/m o c h a", &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# test with only spaces +# +# please don't do this +[cases.test_paths_oopsallspaces] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, " ") => 0; + if (DIR) { + lfs_mkdir(&lfs, " / ") => 0; + lfs_mkdir(&lfs, " / ") => 0; + lfs_mkdir(&lfs, " / ") => 0; + lfs_mkdir(&lfs, " / ") => 0; + lfs_mkdir(&lfs, " / ") => 0; + lfs_mkdir(&lfs, " / ") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, " / ", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, " / ") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, " / ") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, " / ") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, " / ") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, " / ") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, " / ") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, " / ") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, " / ") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, " / ") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, " / ") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, " / ") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, " / ") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, " ") => 0; + lfs_rename(&lfs, + " / ", + " / ") => 0; + lfs_rename(&lfs, + " / ", + " / ") => 0; + lfs_rename(&lfs, + " / ", + " / ") => 0; + lfs_rename(&lfs, + " / ", + " / ") => 0; + lfs_rename(&lfs, + " / ", + " / ") => 0; + lfs_rename(&lfs, + " / ", + " / ") => 0; + + // stat paths + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, " / ", &info) => 0; + assert(strcmp(info.name, " ") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, " / ") => 0; + lfs_remove(&lfs, " / ") => 0; + lfs_remove(&lfs, " / ") => 0; + lfs_remove(&lfs, " / ") => 0; + lfs_remove(&lfs, " / ") => 0; + lfs_remove(&lfs, " / ") => 0; + + // stat paths + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, " / ", &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# test with only ascii control characters +# +# littlefs only cares about "./" and NULL +[cases.test_paths_nonprintable] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "\x0c") => 0; + if (DIR) { + lfs_mkdir(&lfs, "\x0c/\x01") => 0; + lfs_mkdir(&lfs, "\x0c/\x02") => 0; + lfs_mkdir(&lfs, "\x0c/\x03") => 0; + lfs_mkdir(&lfs, "\x0c/\x04") => 0; + lfs_mkdir(&lfs, "\x0c/\x05") => 0; + lfs_mkdir(&lfs, "\x0c/\x06") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\x0c/\x01", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x02", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x03", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x04", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x05", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x06", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "\x0c/\x01", &info) => 0; + assert(strcmp(info.name, "\x01") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x0c/\x02", &info) => 0; + assert(strcmp(info.name, "\x02") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x0c/\x03", &info) => 0; + assert(strcmp(info.name, "\x03") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x0c/\x04", &info) => 0; + assert(strcmp(info.name, "\x04") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x0c/\x05", &info) => 0; + assert(strcmp(info.name, "\x05") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x0c/\x06", &info) => 0; + assert(strcmp(info.name, "\x06") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\x0c/\x01", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x0c/\x02", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x0c/\x03", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x0c/\x04", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x0c/\x05", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x0c/\x06", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "\x0c/\x01", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x0c/\x02", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x0c/\x03", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x0c/\x04", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x0c/\x05", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x0c/\x06", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "\x0c/\x01", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x0c/\x02", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x0c/\x03", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x0c/\x04", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x0c/\x05", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x0c/\x06", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\x0c/\x01", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x02", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x03", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x04", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x05", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x06", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "\x0c/\x01", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x02", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x03", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x04", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x05", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x0c/\x06", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "\x0c/\x01", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x0c/\x02", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x0c/\x03", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x0c/\x04", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x0c/\x05", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x0c/\x06", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "\x0c/\x01") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\x0c/\x02") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\x0c/\x03") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\x0c/\x04") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\x0c/\x05") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\x0c/\x06") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "\x0c/\x01") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\x0c/\x02") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\x0c/\x03") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\x0c/\x04") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\x0c/\x05") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\x0c/\x06") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "\x0e") => 0; + lfs_rename(&lfs, + "\x0c/\x01", + "\x0e/\x1a") => 0; + lfs_rename(&lfs, + "\x0c/\x02", + "\x0e/\x1b") => 0; + lfs_rename(&lfs, + "\x0c/\x03", + "\x0e/\x1c") => 0; + lfs_rename(&lfs, + "\x0c/\x04", + "\x0e/\x1d") => 0; + lfs_rename(&lfs, + "\x0c/\x05", + "\x0e/\x1e") => 0; + lfs_rename(&lfs, + "\x0c/\x06", + "\x0e/\x1f") => 0; + + // stat paths + lfs_stat(&lfs, "\x0e/\x1a", &info) => 0; + assert(strcmp(info.name, "\x1a") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x0e/\x1b", &info) => 0; + assert(strcmp(info.name, "\x1b") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x0e/\x1c", &info) => 0; + assert(strcmp(info.name, "\x1c") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x0e/\x1d", &info) => 0; + assert(strcmp(info.name, "\x1d") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x0e/\x1e", &info) => 0; + assert(strcmp(info.name, "\x1e") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x0e/\x1f", &info) => 0; + assert(strcmp(info.name, "\x1f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "\x0c/\x01", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x0c/\x02", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x0c/\x03", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x0c/\x04", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x0c/\x05", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x0c/\x06", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "\x0e/\x1a") => 0; + lfs_remove(&lfs, "\x0e/\x1b") => 0; + lfs_remove(&lfs, "\x0e/\x1c") => 0; + lfs_remove(&lfs, "\x0e/\x1d") => 0; + lfs_remove(&lfs, "\x0e/\x1e") => 0; + lfs_remove(&lfs, "\x0e/\x1f") => 0; + + // stat paths + lfs_stat(&lfs, "\x0e/\x1a", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x0e/\x1b", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x0e/\x1c", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x0e/\x1d", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x0e/\x1e", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x0e/\x1f", &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# test with only ascii DELs +# +# I don't know why you'd do this +[cases.test_paths_oopsalldels] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "\x7f") => 0; + if (DIR) { + lfs_mkdir(&lfs, "\x7f/\x7f") => 0; + lfs_mkdir(&lfs, "\x7f/\x7f\x7f") => 0; + lfs_mkdir(&lfs, "\x7f/\x7f\x7f\x7f") => 0; + lfs_mkdir(&lfs, "\x7f/\x7f\x7f\x7f\x7f") => 0; + lfs_mkdir(&lfs, "\x7f/\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_mkdir(&lfs, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\x7f/\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "\x7f/\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x7f/\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x7f/\x7f\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x7f/\x7f\x7f\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x7f/\x7f\x7f\x7f\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f\x7f\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f\x7f\x7f\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\x7f/\x7f", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "\x7f/\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "\x7f/\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\x7f/\x7f", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "\x7f/\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "\x7f/\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f\x7f") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f\x7f\x7f") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f\x7f\x7f\x7f") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f\x7f") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f\x7f\x7f") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f\x7f\x7f\x7f") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f\x7f\x7f\x7f\x7f") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "\x7f\x7f") => 0; + lfs_rename(&lfs, + "\x7f/\x7f", + "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_rename(&lfs, + "\x7f/\x7f\x7f", + "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_rename(&lfs, + "\x7f/\x7f\x7f\x7f", + "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_rename(&lfs, + "\x7f/\x7f\x7f\x7f\x7f", + "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_rename(&lfs, + "\x7f/\x7f\x7f\x7f\x7f\x7f", + "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_rename(&lfs, + "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", + "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + + // stat paths + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f\x7f\x7f\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f\x7f\x7f\x7f\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f", &info) => 0; + assert(strcmp(info.name, "\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "\x7f/\x7f", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x7f/\x7f\x7f", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x7f/\x7f\x7f\x7f", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x7f/\x7f\x7f\x7f\x7f", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x7f/\x7f\x7f\x7f\x7f\x7f", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_remove(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_remove(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_remove(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_remove(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + lfs_remove(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f") => 0; + + // stat paths + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\x7f\x7f/\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f\x7f", &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# test with invalid utf8 sequences +# +# Don't do this! These filenames are not utf8 and will probably break +# external tools. +# +[cases.test_paths_nonutf8] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "\xc0") => 0; + if (DIR) { + lfs_mkdir(&lfs, "\xc0/\xa0") => 0; + lfs_mkdir(&lfs, "\xc0/\xb0") => 0; + lfs_mkdir(&lfs, "\xc0/\xc0") => 0; + lfs_mkdir(&lfs, "\xc0/\xd0") => 0; + lfs_mkdir(&lfs, "\xc0/\xe0") => 0; + lfs_mkdir(&lfs, "\xc0/\xf0") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\xc0/\xa0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xb0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xc0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xd0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xe0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xf0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "\xc0/\xa0", &info) => 0; + assert(strcmp(info.name, "\xa0") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xc0/\xb0", &info) => 0; + assert(strcmp(info.name, "\xb0") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xc0/\xc0", &info) => 0; + assert(strcmp(info.name, "\xc0") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xc0/\xd0", &info) => 0; + assert(strcmp(info.name, "\xd0") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xc0/\xe0", &info) => 0; + assert(strcmp(info.name, "\xe0") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xc0/\xf0", &info) => 0; + assert(strcmp(info.name, "\xf0") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\xc0/\xa0", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xc0/\xb0", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xc0/\xc0", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xc0/\xd0", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xc0/\xe0", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xc0/\xf0", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "\xc0/\xa0", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xc0/\xb0", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xc0/\xc0", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xc0/\xd0", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xc0/\xe0", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xc0/\xf0", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "\xc0/\xa0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xc0/\xb0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xc0/\xc0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xc0/\xd0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xc0/\xe0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xc0/\xf0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\xc0/\xa0", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xb0", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xc0", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xd0", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xe0", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xf0", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "\xc0/\xa0", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xb0", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xc0", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xd0", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xe0", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xc0/\xf0", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "\xc0/\xa0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xc0/\xb0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xc0/\xc0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xc0/\xd0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xc0/\xe0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xc0/\xf0", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "\xc0/\xa0") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\xc0/\xb0") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\xc0/\xc0") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\xc0/\xd0") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\xc0/\xe0") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\xc0/\xf0") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "\xc0/\xa0") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\xc0/\xb0") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\xc0/\xc0") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\xc0/\xd0") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\xc0/\xe0") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\xc0/\xf0") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "\xe0") => 0; + lfs_rename(&lfs, + "\xc0/\xa0", + "\xe0/\xaf") => 0; + lfs_rename(&lfs, + "\xc0/\xb0", + "\xe0/\xbf") => 0; + lfs_rename(&lfs, + "\xc0/\xc0", + "\xe0/\xcf") => 0; + lfs_rename(&lfs, + "\xc0/\xd0", + "\xe0/\xdf") => 0; + lfs_rename(&lfs, + "\xc0/\xe0", + "\xe0/\xef") => 0; + lfs_rename(&lfs, + "\xc0/\xf0", + "\xe0/\xff") => 0; + + // stat paths + lfs_stat(&lfs, "\xe0/\xaf", &info) => 0; + assert(strcmp(info.name, "\xaf") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xe0/\xbf", &info) => 0; + assert(strcmp(info.name, "\xbf") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xe0/\xcf", &info) => 0; + assert(strcmp(info.name, "\xcf") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xe0/\xdf", &info) => 0; + assert(strcmp(info.name, "\xdf") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xe0/\xef", &info) => 0; + assert(strcmp(info.name, "\xef") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xe0/\xff", &info) => 0; + assert(strcmp(info.name, "\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "\xc0/\xa0", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xc0/\xb0", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xc0/\xc0", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xc0/\xd0", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xc0/\xe0", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xc0/\xf0", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "\xe0/\xaf") => 0; + lfs_remove(&lfs, "\xe0/\xbf") => 0; + lfs_remove(&lfs, "\xe0/\xcf") => 0; + lfs_remove(&lfs, "\xe0/\xdf") => 0; + lfs_remove(&lfs, "\xe0/\xef") => 0; + lfs_remove(&lfs, "\xe0/\xff") => 0; + + // stat paths + lfs_stat(&lfs, "\xe0/\xaf", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xe0/\xbf", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xe0/\xcf", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xe0/\xdf", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xe0/\xef", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xe0/\xff", &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' + +# test with only "\xff" characters +# +# Don't do this! These filenames are not utf8 and will probably break +# external tools. +# +[cases.test_paths_oopsallffs] +defines.DIR = [false, true] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + + // create paths + lfs_mkdir(&lfs, "\xff") => 0; + if (DIR) { + lfs_mkdir(&lfs, "\xff/\xff") => 0; + lfs_mkdir(&lfs, "\xff/\xff\xff") => 0; + lfs_mkdir(&lfs, "\xff/\xff\xff\xff") => 0; + lfs_mkdir(&lfs, "\xff/\xff\xff\xff\xff") => 0; + lfs_mkdir(&lfs, "\xff/\xff\xff\xff\xff\xff") => 0; + lfs_mkdir(&lfs, "\xff/\xff\xff\xff\xff\xff\xff") => 0; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\xff/\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + // stat paths + struct lfs_info info; + lfs_stat(&lfs, "\xff/\xff", &info) => 0; + assert(strcmp(info.name, "\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xff/\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xff/\xff\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xff/\xff\xff\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xff/\xff\xff\xff\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff\xff\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xff/\xff\xff\xff\xff\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff\xff\xff\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + // file open paths, only works on files! + if (DIR) { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\xff/\xff", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xff/\xff\xff", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff\xff", + LFS_O_RDONLY) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "\xff/\xff", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xff/\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_file_open(&lfs, &file, "\xff/\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xff/\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } else { + lfs_file_t file; + lfs_file_open(&lfs, &file, "\xff/\xff", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff\xff", + LFS_O_RDONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "\xff/\xff", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT) => 0; + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "\xff/\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xff/\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "\xff/\xff\xff\xff\xff\xff\xff", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + } + + // dir open paths, only works on dirs! + if (DIR) { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "\xff/\xff") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\xff/\xff\xff") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\xff/\xff\xff\xff") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\xff/\xff\xff\xff\xff") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\xff/\xff\xff\xff\xff\xff") => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_dir_open(&lfs, &dir, "\xff/\xff\xff\xff\xff\xff\xff") => 0; + lfs_dir_close(&lfs, &dir) => 0; + } else { + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "\xff/\xff") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\xff/\xff\xff") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\xff/\xff\xff\xff") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\xff/\xff\xff\xff\xff") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\xff/\xff\xff\xff\xff\xff") => LFS_ERR_NOTDIR; + lfs_dir_open(&lfs, &dir, "\xff/\xff\xff\xff\xff\xff\xff") => LFS_ERR_NOTDIR; + } + + // rename paths + lfs_mkdir(&lfs, "\xff\xff") => 0; + lfs_rename(&lfs, + "\xff/\xff", + "\xff\xff/\xff\xff\xff\xff\xff\xff") => 0; + lfs_rename(&lfs, + "\xff/\xff\xff", + "\xff\xff/\xff\xff\xff\xff\xff\xff\xff") => 0; + lfs_rename(&lfs, + "\xff/\xff\xff\xff", + "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff") => 0; + lfs_rename(&lfs, + "\xff/\xff\xff\xff\xff", + "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff") => 0; + lfs_rename(&lfs, + "\xff/\xff\xff\xff\xff\xff", + "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") => 0; + lfs_rename(&lfs, + "\xff/\xff\xff\xff\xff\xff\xff", + "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") => 0; + + // stat paths + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff\xff\xff\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff\xff\xff\xff\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff\xff\xff\xff\xff\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff\xff\xff\xff\xff\xff\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", &info) => 0; + assert(strcmp(info.name, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") == 0); + assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG)); + + lfs_stat(&lfs, "\xff/\xff", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xff/\xff\xff", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xff/\xff\xff\xff", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xff/\xff\xff\xff\xff", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xff/\xff\xff\xff\xff\xff", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xff/\xff\xff\xff\xff\xff\xff", &info) => LFS_ERR_NOENT; + + // remove paths + lfs_remove(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff") => 0; + lfs_remove(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff") => 0; + lfs_remove(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff") => 0; + lfs_remove(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff") => 0; + lfs_remove(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") => 0; + lfs_remove(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff") => 0; + + // stat paths + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", &info) => LFS_ERR_NOENT; + lfs_stat(&lfs, "\xff\xff/\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", &info) => LFS_ERR_NOENT; + + lfs_unmount(&lfs) => 0; +''' diff --git a/tests/test_seek.toml b/tests/test_seek.toml index 9b3768d7..33fb5785 100644 --- a/tests/test_seek.toml +++ b/tests/test_seek.toml @@ -405,3 +405,111 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; ''' + + +# test possible overflow/underflow conditions +# +# note these need -fsanitize=undefined to consistently detect +# overflow/underflow conditions + +[cases.test_seek_filemax] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; + lfs_file_open(&lfs, &file, "kitty", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; + uint8_t buffer[1024]; + strcpy((char*)buffer, "kittycatcat"); + size_t size = strlen((char*)buffer); + lfs_file_write(&lfs, &file, buffer, size) => size; + + // seek with LFS_SEEK_SET + lfs_file_seek(&lfs, &file, LFS_FILE_MAX, LFS_SEEK_SET) => LFS_FILE_MAX; + + // seek with LFS_SEEK_CUR + lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => LFS_FILE_MAX; + + // the file hasn't changed size, so seek end takes us back to the offset=0 + lfs_file_seek(&lfs, &file, +10, LFS_SEEK_END) => size+10; + + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' + +[cases.test_seek_underflow] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; + lfs_file_open(&lfs, &file, "kitty", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; + uint8_t buffer[1024]; + strcpy((char*)buffer, "kittycatcat"); + size_t size = strlen((char*)buffer); + lfs_file_write(&lfs, &file, buffer, size) => size; + + // underflow with LFS_SEEK_CUR, should error + lfs_file_seek(&lfs, &file, -(size+10), LFS_SEEK_CUR) => LFS_ERR_INVAL; + lfs_file_seek(&lfs, &file, -LFS_FILE_MAX, LFS_SEEK_CUR) => LFS_ERR_INVAL; + lfs_file_seek(&lfs, &file, -(size+LFS_FILE_MAX), LFS_SEEK_CUR) + => LFS_ERR_INVAL; + + // underflow with LFS_SEEK_END, should error + lfs_file_seek(&lfs, &file, -(size+10), LFS_SEEK_END) => LFS_ERR_INVAL; + lfs_file_seek(&lfs, &file, -LFS_FILE_MAX, LFS_SEEK_END) => LFS_ERR_INVAL; + lfs_file_seek(&lfs, &file, -(size+LFS_FILE_MAX), LFS_SEEK_END) + => LFS_ERR_INVAL; + + // file pointer should not have changed + lfs_file_tell(&lfs, &file) => size; + + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' + +[cases.test_seek_overflow] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; + lfs_file_open(&lfs, &file, "kitty", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; + uint8_t buffer[1024]; + strcpy((char*)buffer, "kittycatcat"); + size_t size = strlen((char*)buffer); + lfs_file_write(&lfs, &file, buffer, size) => size; + + // seek to LFS_FILE_MAX + lfs_file_seek(&lfs, &file, LFS_FILE_MAX, LFS_SEEK_SET) => LFS_FILE_MAX; + + // overflow with LFS_SEEK_CUR, should error + lfs_file_seek(&lfs, &file, +10, LFS_SEEK_CUR) => LFS_ERR_INVAL; + lfs_file_seek(&lfs, &file, +LFS_FILE_MAX, LFS_SEEK_CUR) => LFS_ERR_INVAL; + + // LFS_SEEK_SET/END don't care about the current file position, but we can + // still overflow with a large offset + + // overflow with LFS_SEEK_SET, should error + lfs_file_seek(&lfs, &file, + +((uint32_t)LFS_FILE_MAX+10), + LFS_SEEK_SET) => LFS_ERR_INVAL; + lfs_file_seek(&lfs, &file, + +((uint32_t)LFS_FILE_MAX+(uint32_t)LFS_FILE_MAX), + LFS_SEEK_SET) => LFS_ERR_INVAL; + + // overflow with LFS_SEEK_END, should error + lfs_file_seek(&lfs, &file, +(LFS_FILE_MAX-size+10), LFS_SEEK_END) + => LFS_ERR_INVAL; + lfs_file_seek(&lfs, &file, +(LFS_FILE_MAX-size+LFS_FILE_MAX), LFS_SEEK_END) + => LFS_ERR_INVAL; + + // file pointer should not have changed + lfs_file_tell(&lfs, &file) => LFS_FILE_MAX; + + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' diff --git a/tests/test_superblocks.toml b/tests/test_superblocks.toml index e93f02eb..5911c9b0 100644 --- a/tests/test_superblocks.toml +++ b/tests/test_superblocks.toml @@ -523,3 +523,30 @@ code = ''' assert(memcmp(buffer, "hello!", 6) == 0); lfs_unmount(&lfs) => 0; ''' + +# test that metadata_max does not cause problems for superblock compaction +[cases.test_superblocks_metadata_max] +defines.METADATA_MAX = [ + 'lfs_max(512, PROG_SIZE)', + 'lfs_max(BLOCK_SIZE/2, PROG_SIZE)', + 'BLOCK_SIZE' +] +defines.N = [10, 100, 1000] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + for (int i = 0; i < N; i++) { + lfs_file_t file; + char name[256]; + sprintf(name, "hello%03x", i); + lfs_file_open(&lfs, &file, name, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + struct lfs_info info; + lfs_stat(&lfs, name, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_REG); + } + lfs_unmount(&lfs) => 0; +'''