diff options
author | Christopher Haster <chaster@utexas.edu> | 2020-12-08 05:50:31 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-08 05:50:31 +0300 |
commit | 1a59954ec64ca168828a15242cc6de94ac75f9d1 (patch) | |
tree | 98f9b1592ae6870845d314311a8319c2c211b2a9 | |
parent | 4c9146ea539f72749d6cc3ea076372a81b12cb11 (diff) | |
parent | 6a7012774d8bf750f08f13fee43200b9d44df9f3 (diff) |
Merge pull request #495 from littlefs-project/develv2.3.0
Minor release: v2.3
-rw-r--r-- | .travis.yml | 32 | ||||
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | bd/lfs_testbd.c | 4 | ||||
-rw-r--r-- | lfs.c | 1147 | ||||
-rw-r--r-- | lfs.h | 40 | ||||
-rwxr-xr-x | scripts/readtree.py | 2 |
6 files changed, 890 insertions, 341 deletions
diff --git a/.travis.yml b/.travis.yml index 78d964a..4b59af8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -208,6 +208,38 @@ jobs: script: - make test TFLAGS+="-k --valgrind" + # test compilation in read-only mode + - stage: test + env: + - NAME=littlefs-readonly + - CC="arm-linux-gnueabi-gcc --static -mthumb" + - CFLAGS="-Werror -DLFS_READONLY" + if: branch !~ -prefix$ + install: + - *install-common + - sudo apt-get install + gcc-arm-linux-gnueabi + libc6-dev-armel-cross + - arm-linux-gnueabi-gcc --version + # report-size will compile littlefs and report the size + script: [*report-size] + + # test compilation in thread-safe mode + - stage: test + env: + - NAME=littlefs-threadsafe + - CC="arm-linux-gnueabi-gcc --static -mthumb" + - CFLAGS="-Werror -DLFS_THREADSAFE" + if: branch !~ -prefix$ + install: + - *install-common + - sudo apt-get install + gcc-arm-linux-gnueabi + libc6-dev-armel-cross + - arm-linux-gnueabi-gcc --version + # report-size will compile littlefs and report the size + script: [*report-size] + # self-host with littlefs-fuse for fuzz test - stage: test env: @@ -221,6 +221,11 @@ License Identifiers that are here available: http://spdx.org/licenses/ - [littlefs-js] - A javascript wrapper for littlefs. I'm not sure why you would want this, but it is handy for demos. You can see it in action [here][littlefs-js-demo]. + +- [littlefs-python] - A Python wrapper for littlefs. The project allows you + to create images of the filesystem on your PC. Check if littlefs will fit + your needs, create images for a later download to the target memory or + inspect the content of a binary image of the target memory. - [mklfs] - A command line tool built by the [Lua RTOS] guys for making littlefs images from a host PC. Supports Windows, Mac OS, and Linux. @@ -250,3 +255,4 @@ License Identifiers that are here available: http://spdx.org/licenses/ [LittleFileSystem]: https://os.mbed.com/docs/mbed-os/v5.12/apis/littlefilesystem.html [SPIFFS]: https://github.com/pellepl/spiffs [Dhara]: https://github.com/dlbeer/dhara +[littlefs-python]: https://pypi.org/project/littlefs-python/ diff --git a/bd/lfs_testbd.c b/bd/lfs_testbd.c index 1ec6fb9..9d3f40c 100644 --- a/bd/lfs_testbd.c +++ b/bd/lfs_testbd.c @@ -207,7 +207,7 @@ int lfs_testbd_prog(const struct lfs_config *cfg, lfs_block_t block, bd->power_cycles -= 1; if (bd->power_cycles == 0) { // sync to make sure we persist the last changes - assert(lfs_testbd_rawsync(cfg) == 0); + LFS_ASSERT(lfs_testbd_rawsync(cfg) == 0); // simulate power loss exit(33); } @@ -254,7 +254,7 @@ int lfs_testbd_erase(const struct lfs_config *cfg, lfs_block_t block) { bd->power_cycles -= 1; if (bd->power_cycles == 0) { // sync to make sure we persist the last changes - assert(lfs_testbd_rawsync(cfg) == 0); + LFS_ASSERT(lfs_testbd_rawsync(cfg) == 0); // simulate power loss exit(33); } @@ -118,24 +118,29 @@ static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) { const uint8_t *data = buffer; + lfs_size_t diff = 0; - for (lfs_off_t i = 0; i < size; i++) { - uint8_t dat; - int err = lfs_bd_read(lfs, + for (lfs_off_t i = 0; i < size; i += diff) { + uint8_t dat[8]; + + diff = lfs_min(size-i, sizeof(dat)); + int res = lfs_bd_read(lfs, pcache, rcache, hint-i, - block, off+i, &dat, 1); - if (err) { - return err; + block, off+i, &dat, diff); + if (res) { + return res; } - if (dat != data[i]) { - return (dat < data[i]) ? LFS_CMP_LT : LFS_CMP_GT; + res = memcmp(dat, data + i, diff); + if (res) { + return res < 0 ? LFS_CMP_LT : LFS_CMP_GT; } } return LFS_CMP_EQ; } +#ifndef LFS_READONLY static int lfs_bd_flush(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { if (pcache->block != LFS_BLOCK_NULL && pcache->block != LFS_BLOCK_INLINE) { @@ -168,7 +173,9 @@ static int lfs_bd_flush(lfs_t *lfs, return 0; } +#endif +#ifndef LFS_READONLY static int lfs_bd_sync(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate) { lfs_cache_drop(lfs, rcache); @@ -182,7 +189,9 @@ static int lfs_bd_sync(lfs_t *lfs, LFS_ASSERT(err <= 0); return err; } +#endif +#ifndef LFS_READONLY static int lfs_bd_prog(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, bool validate, lfs_block_t block, lfs_off_t off, @@ -228,13 +237,16 @@ static int lfs_bd_prog(lfs_t *lfs, return 0; } +#endif +#ifndef LFS_READONLY static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) { LFS_ASSERT(block < lfs->cfg->block_count); int err = lfs->cfg->erase(lfs->cfg, block); LFS_ASSERT(err <= 0); return err; } +#endif /// Small type-level utilities /// @@ -388,10 +400,12 @@ static void lfs_ctz_fromle32(struct lfs_ctz *ctz) { ctz->size = lfs_fromle32(ctz->size); } +#ifndef LFS_READONLY static void lfs_ctz_tole32(struct lfs_ctz *ctz) { ctz->head = lfs_tole32(ctz->head); ctz->size = lfs_tole32(ctz->size); } +#endif static inline void lfs_superblock_fromle32(lfs_superblock_t *superblock) { superblock->version = lfs_fromle32(superblock->version); @@ -411,15 +425,46 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { superblock->attr_max = lfs_tole32(superblock->attr_max); } +static inline bool lfs_mlist_isopen(struct lfs_mlist *head, + struct lfs_mlist *node) { + for (struct lfs_mlist **p = &head; *p; p = &(*p)->next) { + if (*p == (struct lfs_mlist*)node) { + return true; + } + } + + return false; +} + +static inline void lfs_mlist_remove(lfs_t *lfs, struct lfs_mlist *mlist) { + for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { + if (*p == mlist) { + *p = (*p)->next; + break; + } + } +} + +static inline void lfs_mlist_append(lfs_t *lfs, struct lfs_mlist *mlist) { + mlist->next = lfs->mlist; + lfs->mlist = mlist; +} + /// Internal operations predeclared here /// +#ifndef LFS_READONLY static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount); static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, lfs_mdir_t *source, uint16_t begin, uint16_t end); + +static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, + const void *buffer, lfs_size_t size); +static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file); static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file); static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file); + static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans); static void lfs_fs_prepmove(lfs_t *lfs, uint16_t id, const lfs_block_t pair[2]); @@ -429,17 +474,32 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t dir[2], lfs_mdir_t *parent); static int lfs_fs_relocate(lfs_t *lfs, const lfs_block_t oldpair[2], lfs_block_t newpair[2]); -int lfs_fs_traverseraw(lfs_t *lfs, - int (*cb)(void *data, lfs_block_t block), void *data, - bool includeorphans); static int lfs_fs_forceconsistency(lfs_t *lfs); -static int lfs_deinit(lfs_t *lfs); +#endif + #ifdef LFS_MIGRATE static int lfs1_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); #endif +static int lfs_dir_rawrewind(lfs_t *lfs, lfs_dir_t *dir); + +static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file, + void *buffer, lfs_size_t size); +static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file); +static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file); + +static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs); +static int lfs_fs_rawtraverse(lfs_t *lfs, + int (*cb)(void *data, lfs_block_t block), void *data, + bool includeorphans); + +static int lfs_deinit(lfs_t *lfs); +static int lfs_rawunmount(lfs_t *lfs); + + /// Block allocator /// +#ifndef LFS_READONLY static int lfs_alloc_lookahead(void *p, lfs_block_t block) { lfs_t *lfs = (lfs_t*)p; lfs_block_t off = ((block - lfs->free.off) @@ -451,20 +511,24 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) { return 0; } +#endif +// indicate allocated blocks have been committed into the filesystem, this +// is to prevent blocks from being garbage collected in the middle of a +// commit operation static void lfs_alloc_ack(lfs_t *lfs) { lfs->free.ack = lfs->cfg->block_count; } -// Invalidate the lookahead buffer. This is done during mounting and -// failed traversals -static void lfs_alloc_reset(lfs_t *lfs) { - lfs->free.off = lfs->seed % lfs->cfg->block_size; +// drop the lookahead buffer, this is done during mounting and failed +// traversals in order to avoid invalid lookahead state +static void lfs_alloc_drop(lfs_t *lfs) { lfs->free.size = 0; lfs->free.i = 0; lfs_alloc_ack(lfs); } +#ifndef LFS_READONLY static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { while (true) { while (lfs->free.i != lfs->free.size) { @@ -503,13 +567,14 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { // find mask of free blocks from tree memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); - int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true); + int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true); if (err) { - lfs_alloc_reset(lfs); + lfs_alloc_drop(lfs); return err; } } } +#endif /// Metadata pair and directory operations /// static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir, @@ -642,6 +707,7 @@ static int lfs_dir_getread(lfs_t *lfs, const lfs_mdir_t *dir, return 0; } +#ifndef LFS_READONLY static int lfs_dir_traverse_filter(void *p, lfs_tag_t tag, const void *buffer) { lfs_tag_t *filtertag = p; @@ -669,7 +735,9 @@ static int lfs_dir_traverse_filter(void *p, return false; } +#endif +#ifndef LFS_READONLY static int lfs_dir_traverse(lfs_t *lfs, const lfs_mdir_t *dir, lfs_off_t off, lfs_tag_t ptag, const struct lfs_mattr *attrs, int attrcount, @@ -763,6 +831,7 @@ static int lfs_dir_traverse(lfs_t *lfs, } } } +#endif static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, lfs_mdir_t *dir, const lfs_block_t pair[2], @@ -870,8 +939,10 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, ptag ^= (lfs_tag_t)(lfs_tag_chunk(tag) & 1U) << 31; // toss our crc into the filesystem seed for - // pseudorandom numbers - lfs->seed ^= crc; + // pseudorandom numbers, note we use another crc here + // as a collection function because it is sufficiently + // random and convenient + lfs->seed = lfs_crc(lfs->seed, &crc, sizeof(crc)); // update with what's found so far besttag = tempbesttag; @@ -1200,6 +1271,7 @@ struct lfs_commit { lfs_off_t end; }; +#ifndef LFS_READONLY static int lfs_dir_commitprog(lfs_t *lfs, struct lfs_commit *commit, const void *buffer, lfs_size_t size) { int err = lfs_bd_prog(lfs, @@ -1214,7 +1286,9 @@ static int lfs_dir_commitprog(lfs_t *lfs, struct lfs_commit *commit, commit->off += size; return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit, lfs_tag_t tag, const void *buffer) { // check if we fit @@ -1259,14 +1333,17 @@ static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit, commit->ptag = tag & 0x7fffffff; return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { - const lfs_off_t off1 = commit->off; - const uint32_t crc1 = commit->crc; // align to program units - const lfs_off_t end = lfs_alignup(off1 + 2*sizeof(uint32_t), + const lfs_off_t end = lfs_alignup(commit->off + 2*sizeof(uint32_t), lfs->cfg->prog_size); + lfs_off_t off1 = 0; + uint32_t crc1 = 0; + // create crc tags to fill up remainder of commit, note that // padding is not crced, which lets fetches skip padding but // makes committing a bit more complicated @@ -1302,6 +1379,12 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { return err; } + // keep track of non-padding checksum to verify + if (off1 == 0) { + off1 = commit->off + sizeof(uint32_t); + crc1 = commit->crc; + } + commit->off += sizeof(tag)+lfs_tag_size(tag); commit->ptag = tag ^ ((lfs_tag_t)reset << 31); commit->crc = 0xffffffff; // reset crc for next "commit" @@ -1315,7 +1398,7 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { // successful commit, check checksums to make sure lfs_off_t off = commit->begin; - lfs_off_t noff = off1 + sizeof(uint32_t); + lfs_off_t noff = off1; while (off < end) { uint32_t crc = 0xffffffff; for (lfs_off_t i = off; i < noff+sizeof(uint32_t); i++) { @@ -1352,7 +1435,9 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { // allocate pair of dir blocks (backwards, so we write block 1 first) for (int i = 0; i < 2; i++) { @@ -1375,8 +1460,12 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { return err; } - // make sure we don't immediately evict - dir->rev += dir->rev & 1; + // to make sure we don't immediately evict, align the new revision count + // to our block_cycles modulus, see lfs_dir_compact for why our modulus + // is tweaked this way + if (lfs->cfg->block_cycles > 0) { + dir->rev = lfs_alignup(dir->rev, ((lfs->cfg->block_cycles+1)|1)); + } // set defaults dir->off = sizeof(dir->rev); @@ -1390,7 +1479,9 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { // don't write out yet, let caller take care of that return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_drop(lfs_t *lfs, lfs_mdir_t *dir, lfs_mdir_t *tail) { // steal state int err = lfs_dir_getgstate(lfs, tail, &lfs->gdelta); @@ -1409,7 +1500,9 @@ static int lfs_dir_drop(lfs_t *lfs, lfs_mdir_t *dir, lfs_mdir_t *tail) { return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_split(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, lfs_mdir_t *source, uint16_t split, uint16_t end) { @@ -1442,7 +1535,9 @@ static int lfs_dir_split(lfs_t *lfs, return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_commit_size(void *p, lfs_tag_t tag, const void *buffer) { lfs_size_t *size = p; (void)buffer; @@ -1450,17 +1545,23 @@ static int lfs_dir_commit_size(void *p, lfs_tag_t tag, const void *buffer) { *size += lfs_tag_dsize(tag); return 0; } +#endif +#ifndef LFS_READONLY struct lfs_dir_commit_commit { lfs_t *lfs; struct lfs_commit *commit; }; +#endif +#ifndef LFS_READONLY static int lfs_dir_commit_commit(void *p, lfs_tag_t tag, const void *buffer) { struct lfs_dir_commit_commit *commit = p; return lfs_dir_commitattr(commit->lfs, commit->commit, tag, buffer); } +#endif +#ifndef LFS_READONLY static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, lfs_mdir_t *source, uint16_t begin, uint16_t end) { @@ -1525,7 +1626,7 @@ static int lfs_dir_compact(lfs_t *lfs, if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { // oh no! we're writing too much to the superblock, // should we expand? - lfs_ssize_t res = lfs_fs_size(lfs); + lfs_ssize_t res = lfs_fs_rawsize(lfs); if (res < 0) { return res; } @@ -1715,7 +1816,9 @@ relocate: return 0; } +#endif +#ifndef LFS_READONLY static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount) { // check for any inline files that aren't RAM backed and @@ -1903,15 +2006,15 @@ compact: return 0; } +#endif /// Top level directory operations /// -int lfs_mkdir(lfs_t *lfs, const char *path) { - LFS_TRACE("lfs_mkdir(%p, \"%s\")", (void*)lfs, path); +#ifndef LFS_READONLY +static int lfs_rawmkdir(lfs_t *lfs, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs_fs_forceconsistency(lfs); if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); return err; } @@ -1920,14 +2023,12 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { uint16_t id; err = lfs_dir_find(lfs, &cwd.m, &path, &id); if (!(err == LFS_ERR_NOENT && id != 0x3ff)) { - LFS_TRACE("lfs_mkdir -> %d", (err < 0) ? err : LFS_ERR_EXIST); return (err < 0) ? err : LFS_ERR_EXIST; } // check that name fits lfs_size_t nlen = strlen(path); if (nlen > lfs->name_max) { - LFS_TRACE("lfs_mkdir -> %d", LFS_ERR_NAMETOOLONG); return LFS_ERR_NAMETOOLONG; } @@ -1936,7 +2037,6 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { lfs_mdir_t dir; err = lfs_dir_alloc(lfs, &dir); if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); return err; } @@ -1945,7 +2045,6 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { while (pred.split) { err = lfs_dir_fetch(lfs, &pred, pred.tail); if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); return err; } } @@ -1956,7 +2055,6 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pred.tail})); lfs_pair_fromle32(pred.tail); if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); return err; } @@ -1979,7 +2077,6 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { lfs_pair_fromle32(dir.pair); if (err) { lfs->mlist = cwd.next; - LFS_TRACE("lfs_mkdir -> %d", err); return err; } @@ -1997,24 +2094,20 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); lfs_pair_fromle32(dir.pair); if (err) { - LFS_TRACE("lfs_mkdir -> %d", err); return err; } - LFS_TRACE("lfs_mkdir -> %d", 0); return 0; } +#endif -int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { - LFS_TRACE("lfs_dir_open(%p, %p, \"%s\")", (void*)lfs, (void*)dir, path); +static int lfs_dir_rawopen(lfs_t *lfs, lfs_dir_t *dir, const char *path) { lfs_stag_t tag = lfs_dir_find(lfs, &dir->m, &path, NULL); if (tag < 0) { - LFS_TRACE("lfs_dir_open -> %"PRId32, tag); return tag; } if (lfs_tag_type3(tag) != LFS_TYPE_DIR) { - LFS_TRACE("lfs_dir_open -> %d", LFS_ERR_NOTDIR); return LFS_ERR_NOTDIR; } @@ -2028,7 +2121,6 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { lfs_stag_t res = lfs_dir_get(lfs, &dir->m, LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair); if (res < 0) { - LFS_TRACE("lfs_dir_open -> %"PRId32, res); return res; } lfs_pair_fromle32(pair); @@ -2037,7 +2129,6 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { // fetch first pair int err = lfs_dir_fetch(lfs, &dir->m, pair); if (err) { - LFS_TRACE("lfs_dir_open -> %d", err); return err; } @@ -2049,30 +2140,19 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { // add to list of mdirs dir->type = LFS_TYPE_DIR; - dir->next = (lfs_dir_t*)lfs->mlist; - lfs->mlist = (struct lfs_mlist*)dir; + lfs_mlist_append(lfs, (struct lfs_mlist *)dir); - LFS_TRACE("lfs_dir_open -> %d", 0); return 0; } -int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) { - LFS_TRACE("lfs_dir_close(%p, %p)", (void*)lfs, (void*)dir); +static int lfs_dir_rawclose(lfs_t *lfs, lfs_dir_t *dir) { // remove from list of mdirs - for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { - if (*p == (struct lfs_mlist*)dir) { - *p = (*p)->next; - break; - } - } + lfs_mlist_remove(lfs, (struct lfs_mlist *)dir); - LFS_TRACE("lfs_dir_close -> %d", 0); return 0; } -int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { - LFS_TRACE("lfs_dir_read(%p, %p, %p)", - (void*)lfs, (void*)dir, (void*)info); +static int lfs_dir_rawread(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { memset(info, 0, sizeof(*info)); // special offset for '.' and '..' @@ -2080,26 +2160,22 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { info->type = LFS_TYPE_DIR; strcpy(info->name, "."); dir->pos += 1; - LFS_TRACE("lfs_dir_read -> %d", true); return true; } else if (dir->pos == 1) { info->type = LFS_TYPE_DIR; strcpy(info->name, ".."); dir->pos += 1; - LFS_TRACE("lfs_dir_read -> %d", true); return true; } while (true) { if (dir->id == dir->m.count) { if (!dir->m.split) { - LFS_TRACE("lfs_dir_read -> %d", false); return false; } int err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); if (err) { - LFS_TRACE("lfs_dir_read -> %d", err); return err; } @@ -2108,7 +2184,6 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { int err = lfs_dir_getinfo(lfs, &dir->m, dir->id, info); if (err && err != LFS_ERR_NOENT) { - LFS_TRACE("lfs_dir_read -> %d", err); return err; } @@ -2119,17 +2194,13 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { } dir->pos += 1; - LFS_TRACE("lfs_dir_read -> %d", true); return true; } -int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { - LFS_TRACE("lfs_dir_seek(%p, %p, %"PRIu32")", - (void*)lfs, (void*)dir, off); +static int lfs_dir_rawseek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { // simply walk from head dir - int err = lfs_dir_rewind(lfs, dir); + int err = lfs_dir_rawrewind(lfs, dir); if (err) { - LFS_TRACE("lfs_dir_seek -> %d", err); return err; } @@ -2148,13 +2219,11 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { if (dir->id == dir->m.count) { if (!dir->m.split) { - LFS_TRACE("lfs_dir_seek -> %d", LFS_ERR_INVAL); return LFS_ERR_INVAL; } err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); if (err) { - LFS_TRACE("lfs_dir_seek -> %d", err); return err; } @@ -2162,29 +2231,23 @@ int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { } } - LFS_TRACE("lfs_dir_seek -> %d", 0); return 0; } -lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) { - LFS_TRACE("lfs_dir_tell(%p, %p)", (void*)lfs, (void*)dir); +static lfs_soff_t lfs_dir_rawtell(lfs_t *lfs, lfs_dir_t *dir) { (void)lfs; - LFS_TRACE("lfs_dir_tell -> %"PRId32, dir->pos); return dir->pos; } -int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { - LFS_TRACE("lfs_dir_rewind(%p, %p)", (void*)lfs, (void*)dir); +static int lfs_dir_rawrewind(lfs_t *lfs, lfs_dir_t *dir) { // reload the head dir int err = lfs_dir_fetch(lfs, &dir->m, dir->head); if (err) { - LFS_TRACE("lfs_dir_rewind -> %d", err); return err; } dir->id = 0; dir->pos = 0; - LFS_TRACE("lfs_dir_rewind -> %d", 0); return 0; } @@ -2237,6 +2300,7 @@ static int lfs_ctz_find(lfs_t *lfs, return 0; } +#ifndef LFS_READONLY static int lfs_ctz_extend(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_block_t head, lfs_size_t size, @@ -2334,6 +2398,7 @@ relocate: lfs_cache_drop(lfs, pcache); } } +#endif static int lfs_ctz_traverse(lfs_t *lfs, const lfs_cache_t *pcache, lfs_cache_t *rcache, @@ -2380,27 +2445,25 @@ static int lfs_ctz_traverse(lfs_t *lfs, /// Top level file operations /// -int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, +static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, const char *path, int flags, const struct lfs_file_config *cfg) { - LFS_TRACE("lfs_file_opencfg(%p, %p, \"%s\", %x, %p {" - ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", - (void*)lfs, (void*)file, path, flags, - (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); - +#ifndef LFS_READONLY // deorphan if we haven't yet, needed at most once after poweron - if ((flags & 3) != LFS_O_RDONLY) { + if ((flags & LFS_O_WRONLY) == LFS_O_WRONLY) { int err = lfs_fs_forceconsistency(lfs); if (err) { - LFS_TRACE("lfs_file_opencfg -> %d", err); return err; } } +#else + LFS_ASSERT((flags & LFS_O_RDONLY) == LFS_O_RDONLY); +#endif // setup simple file details int err; file->cfg = cfg; - file->flags = flags | LFS_F_OPENED; + file->flags = flags; file->pos = 0; file->off = 0; file->cache.buffer = NULL; @@ -2414,9 +2477,13 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, // get id, add to list of mdirs to catch update changes file->type = LFS_TYPE_REG; - file->next = (lfs_file_t*)lfs->mlist; - lfs->mlist = (struct lfs_mlist*)file; + lfs_mlist_append(lfs, (struct lfs_mlist *)file); +#ifdef LFS_READONLY + if (tag == LFS_ERR_NOENT) { + err = LFS_ERR_NOENT; + goto cleanup; +#else if (tag == LFS_ERR_NOENT) { if (!(flags & LFS_O_CREAT)) { err = LFS_ERR_NOENT; @@ -2444,13 +2511,16 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, } else if (flags & LFS_O_EXCL) { err = LFS_ERR_EXIST; goto cleanup; +#endif } else if (lfs_tag_type3(tag) != LFS_TYPE_REG) { err = LFS_ERR_ISDIR; goto cleanup; +#ifndef LFS_READONLY } else if (flags & LFS_O_TRUNC) { // truncate if requested tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0); file->flags |= LFS_F_DIRTY; +#endif } else { // try to load what's on disk, if it's inlined we'll fix it later tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0), @@ -2464,7 +2534,8 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, // fetch attrs for (unsigned i = 0; i < file->cfg->attr_count; i++) { - if ((file->flags & 3) != LFS_O_WRONLY) { + // if opened for read / read-write operations + if ((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY) { lfs_stag_t res = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x7ff, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type, @@ -2476,7 +2547,9 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, } } - if ((file->flags & 3) != LFS_O_RDONLY) { +#ifndef LFS_READONLY + // if opened for write / read-write operations + if ((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY) { if (file->cfg->attrs[i].size > lfs->attr_max) { err = LFS_ERR_NOSPC; goto cleanup; @@ -2484,6 +2557,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, file->flags |= LFS_F_DIRTY; } +#endif } // allocate buffer if needed @@ -2523,54 +2597,45 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, } } - LFS_TRACE("lfs_file_opencfg -> %d", 0); return 0; cleanup: // clean up lingering resources +#ifndef LFS_READONLY file->flags |= LFS_F_ERRED; - lfs_file_close(lfs, file); - LFS_TRACE("lfs_file_opencfg -> %d", err); +#endif + lfs_file_rawclose(lfs, file); return err; } -int lfs_file_open(lfs_t *lfs, lfs_file_t *file, +static int lfs_file_rawopen(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) { - LFS_TRACE("lfs_file_open(%p, %p, \"%s\", %x)", - (void*)lfs, (void*)file, path, flags); static const struct lfs_file_config defaults = {0}; - int err = lfs_file_opencfg(lfs, file, path, flags, &defaults); - LFS_TRACE("lfs_file_open -> %d", err); + int err = lfs_file_rawopencfg(lfs, file, path, flags, &defaults); return err; } -int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); - - int err = lfs_file_sync(lfs, file); +static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file) { +#ifndef LFS_READONLY + int err = lfs_file_rawsync(lfs, file); +#else + int err = 0; +#endif // remove from list of mdirs - for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) { - if (*p == (struct lfs_mlist*)file) { - *p = (*p)->next; - break; - } - } + lfs_mlist_remove(lfs, (struct lfs_mlist*)file); // clean up memory if (!file->cfg->buffer) { lfs_free(file->cache.buffer); } - file->flags &= ~LFS_F_OPENED; - LFS_TRACE("lfs_file_close -> %d", err); return err; } -static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { - LFS_ASSERT(file->flags & LFS_F_OPENED); +#ifndef LFS_READONLY +static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { while (true) { // just relocate what exists into new block lfs_block_t nblock; @@ -2638,7 +2703,9 @@ relocate: lfs_cache_drop(lfs, &lfs->pcache); } } +#endif +#ifndef LFS_READONLY static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { file->off = file->pos; lfs_alloc_ack(lfs); @@ -2650,10 +2717,10 @@ static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file) { file->flags &= ~LFS_F_INLINE; return 0; } +#endif +#ifndef LFS_READONLY static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { - LFS_ASSERT(file->flags & LFS_F_OPENED); - if (file->flags & LFS_F_READING) { if (!(file->flags & LFS_F_INLINE)) { lfs_cache_drop(lfs, &file->cache); @@ -2669,7 +2736,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { lfs_file_t orig = { .ctz.head = file->ctz.head, .ctz.size = file->ctz.size, - .flags = LFS_O_RDONLY | LFS_F_OPENED, + .flags = LFS_O_RDONLY, .pos = file->pos, .cache = lfs->rcache, }; @@ -2679,12 +2746,12 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { // copy over a byte at a time, leave it up to caching // to make this efficient uint8_t data; - lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1); + lfs_ssize_t res = lfs_file_rawread(lfs, &orig, &data, 1); if (res < 0) { return res; } - res = lfs_file_write(lfs, file, &data, 1); + res = lfs_file_rawwrite(lfs, file, &data, 1); if (res < 0) { return res; } @@ -2730,24 +2797,22 @@ relocate: return 0; } +#endif -int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); - +#ifndef LFS_READONLY +static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) { if (file->flags & LFS_F_ERRED) { // it's not safe to do anything if our file errored - LFS_TRACE("lfs_file_sync -> %d", 0); return 0; } int err = lfs_file_flush(lfs, file); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_sync -> %d", err); return err; } + if ((file->flags & LFS_F_DIRTY) && !lfs_pair_isnull(file->m.pair)) { // update dir entry @@ -2777,39 +2842,35 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { file->cfg->attr_count), file->cfg->attrs})); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_sync -> %d", err); return err; } file->flags &= ~LFS_F_DIRTY; } - LFS_TRACE("lfs_file_sync -> %d", 0); return 0; } +#endif -lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, +static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file, void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")", - (void*)lfs, (void*)file, buffer, size); - LFS_ASSERT(file->flags & LFS_F_OPENED); - LFS_ASSERT((file->flags & 3) != LFS_O_WRONLY); + LFS_ASSERT((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY); uint8_t *data = buffer; lfs_size_t nsize = size; +#ifndef LFS_READONLY if (file->flags & LFS_F_WRITING) { // flush out any writes int err = lfs_file_flush(lfs, file); if (err) { - LFS_TRACE("lfs_file_read -> %d", err); return err; } } +#endif if (file->pos >= file->ctz.size) { // eof if past end - LFS_TRACE("lfs_file_read -> %d", 0); return 0; } @@ -2825,7 +2886,6 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, file->ctz.head, file->ctz.size, file->pos, &file->block, &file->off); if (err) { - LFS_TRACE("lfs_file_read -> %d", err); return err; } } else { @@ -2845,7 +2905,6 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), file->off, data, diff); if (err) { - LFS_TRACE("lfs_file_read -> %d", err); return err; } } else { @@ -2853,7 +2912,6 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, NULL, &file->cache, lfs->cfg->block_size, file->block, file->off, data, diff); if (err) { - LFS_TRACE("lfs_file_read -> %d", err); return err; } } @@ -2864,16 +2922,13 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, nsize -= diff; } - LFS_TRACE("lfs_file_read -> %"PRId32, size); return size; } -lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, +#ifndef LFS_READONLY +static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")", - (void*)lfs, (void*)file, buffer, size); - LFS_ASSERT(file->flags & LFS_F_OPENED); - LFS_ASSERT((file->flags & 3) != LFS_O_RDONLY); + LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY); const uint8_t *data = buffer; lfs_size_t nsize = size; @@ -2882,7 +2937,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, // drop any reads int err = lfs_file_flush(lfs, file); if (err) { - LFS_TRACE("lfs_file_write -> %d", err); return err; } } @@ -2893,7 +2947,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, if (file->pos + size > lfs->file_max) { // Larger than file limit? - LFS_TRACE("lfs_file_write -> %d", LFS_ERR_FBIG); return LFS_ERR_FBIG; } @@ -2903,9 +2956,8 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, file->pos = file->ctz.size; while (file->pos < pos) { - lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); + lfs_ssize_t res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1); if (res < 0) { - LFS_TRACE("lfs_file_write -> %"PRId32, res); return res; } } @@ -2919,7 +2971,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, int err = lfs_file_outline(lfs, file); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); return err; } } @@ -2936,7 +2987,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, file->pos-1, &file->block, &file->off); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); return err; } @@ -2951,7 +3001,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, &file->block, &file->off); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); return err; } } else { @@ -2972,7 +3021,6 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, goto relocate; } file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); return err; } @@ -2981,7 +3029,6 @@ relocate: err = lfs_file_relocate(lfs, file); if (err) { file->flags |= LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %d", err); return err; } } @@ -2995,22 +3042,19 @@ relocate: } file->flags &= ~LFS_F_ERRED; - LFS_TRACE("lfs_file_write -> %"PRId32, size); return size; } +#endif -lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, +static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, lfs_soff_t off, int whence) { - LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)", - (void*)lfs, (void*)file, off, whence); - LFS_ASSERT(file->flags & LFS_F_OPENED); - +#ifndef LFS_READONLY // write out everything beforehand, may be noop if rdonly int err = lfs_file_flush(lfs, file); if (err) { - LFS_TRACE("lfs_file_seek -> %d", err); return err; } +#endif // find new pos lfs_off_t npos = file->pos; @@ -3024,34 +3068,28 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, if (npos > lfs->file_max) { // file position out of range - LFS_TRACE("lfs_file_seek -> %d", LFS_ERR_INVAL); return LFS_ERR_INVAL; } // update pos file->pos = npos; - LFS_TRACE("lfs_file_seek -> %"PRId32, npos); return npos; } -int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { - LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")", - (void*)lfs, (void*)file, size); - LFS_ASSERT(file->flags & LFS_F_OPENED); - LFS_ASSERT((file->flags & 3) != LFS_O_RDONLY); +#ifndef LFS_READONLY +static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { + LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY); if (size > LFS_FILE_MAX) { - LFS_TRACE("lfs_file_truncate -> %d", LFS_ERR_INVAL); return LFS_ERR_INVAL; } lfs_off_t pos = file->pos; - lfs_off_t oldsize = lfs_file_size(lfs, file); + lfs_off_t oldsize = lfs_file_rawsize(lfs, file); if (size < oldsize) { // need to flush since directly changing metadata int err = lfs_file_flush(lfs, file); if (err) { - LFS_TRACE("lfs_file_truncate -> %d", err); return err; } @@ -3060,7 +3098,6 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { file->ctz.head, file->ctz.size, size, &file->block, &file->off); if (err) { - LFS_TRACE("lfs_file_truncate -> %d", err); return err; } @@ -3070,97 +3107,80 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { } else if (size > oldsize) { // flush+seek if not already at end if (file->pos != oldsize) { - lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_END); + lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END); if (res < 0) { - LFS_TRACE("lfs_file_truncate -> %"PRId32, res); return (int)res; } } // fill with zeros while (file->pos < size) { - lfs_ssize_t res = lfs_file_write(lfs, file, &(uint8_t){0}, 1); + lfs_ssize_t res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1); if (res < 0) { - LFS_TRACE("lfs_file_truncate -> %"PRId32, res); return (int)res; } } } // restore pos - lfs_soff_t res = lfs_file_seek(lfs, file, pos, LFS_SEEK_SET); + lfs_soff_t res = lfs_file_rawseek(lfs, file, pos, LFS_SEEK_SET); if (res < 0) { - LFS_TRACE("lfs_file_truncate -> %"PRId32, res); return (int)res; } - LFS_TRACE("lfs_file_truncate -> %d", 0); return 0; } +#endif -lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); +static lfs_soff_t lfs_file_rawtell(lfs_t *lfs, lfs_file_t *file) { (void)lfs; - LFS_TRACE("lfs_file_tell -> %"PRId32, file->pos); return file->pos; } -int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_rewind(%p, %p)", (void*)lfs, (void*)file); - lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_SET); +static int lfs_file_rawrewind(lfs_t *lfs, lfs_file_t *file) { + lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET); if (res < 0) { - LFS_TRACE("lfs_file_rewind -> %"PRId32, res); return (int)res; } - LFS_TRACE("lfs_file_rewind -> %d", 0); return 0; } -lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { - LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file); - LFS_ASSERT(file->flags & LFS_F_OPENED); +static lfs_soff_t lfs_file_rawsize(lfs_t *lfs, lfs_file_t *file) { (void)lfs; + +#ifndef LFS_READONLY if (file->flags & LFS_F_WRITING) { - LFS_TRACE("lfs_file_size -> %"PRId32, - lfs_max(file->pos, file->ctz.size)); return lfs_max(file->pos, file->ctz.size); - } else { - LFS_TRACE("lfs_file_size -> %"PRId32, file->ctz.size); - return file->ctz.size; } +#endif + + return file->ctz.size; } /// General fs operations /// -int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { - LFS_TRACE("lfs_stat(%p, \"%s\", %p)", (void*)lfs, path, (void*)info); +static int lfs_rawstat(lfs_t *lfs, const char *path, struct lfs_info *info) { lfs_mdir_t cwd; lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); if (tag < 0) { - LFS_TRACE("lfs_stat -> %"PRId32, tag); return (int)tag; } - int err = lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info); - LFS_TRACE("lfs_stat -> %d", err); - return err; + return lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info); } -int lfs_remove(lfs_t *lfs, const char *path) { - LFS_TRACE("lfs_remove(%p, \"%s\")", (void*)lfs, path); +#ifndef LFS_READONLY +static int lfs_rawremove(lfs_t *lfs, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs_fs_forceconsistency(lfs); if (err) { - LFS_TRACE("lfs_remove -> %d", err); return err; } lfs_mdir_t cwd; lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); if (tag < 0 || lfs_tag_id(tag) == 0x3ff) { - LFS_TRACE("lfs_remove -> %"PRId32, (tag < 0) ? tag : LFS_ERR_INVAL); return (tag < 0) ? (int)tag : LFS_ERR_INVAL; } @@ -3172,19 +3192,16 @@ int lfs_remove(lfs_t *lfs, const char *path) { lfs_stag_t res = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), pair); if (res < 0) { - LFS_TRACE("lfs_remove -> %"PRId32, res); return (int)res; } lfs_pair_fromle32(pair); err = lfs_dir_fetch(lfs, &dir.m, pair); if (err) { - LFS_TRACE("lfs_remove -> %d", err); return err; } if (dir.m.count > 0 || dir.m.split) { - LFS_TRACE("lfs_remove -> %d", LFS_ERR_NOTEMPTY); return LFS_ERR_NOTEMPTY; } @@ -3203,7 +3220,6 @@ int lfs_remove(lfs_t *lfs, const char *path) { {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(tag), 0), NULL})); if (err) { lfs->mlist = dir.next; - LFS_TRACE("lfs_remove -> %d", err); return err; } @@ -3214,28 +3230,24 @@ int lfs_remove(lfs_t *lfs, const char *path) { err = lfs_fs_pred(lfs, dir.m.pair, &cwd); if (err) { - LFS_TRACE("lfs_remove -> %d", err); return err; } err = lfs_dir_drop(lfs, &cwd, &dir.m); if (err) { - LFS_TRACE("lfs_remove -> %d", err); return err; } } - LFS_TRACE("lfs_remove -> %d", 0); return 0; } +#endif -int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { - LFS_TRACE("lfs_rename(%p, \"%s\", \"%s\")", (void*)lfs, oldpath, newpath); - +#ifndef LFS_READONLY +static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs_fs_forceconsistency(lfs); if (err) { - LFS_TRACE("lfs_rename -> %d", err); return err; } @@ -3243,8 +3255,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { lfs_mdir_t oldcwd; lfs_stag_t oldtag = lfs_dir_find(lfs, &oldcwd, &oldpath, NULL); if (oldtag < 0 || lfs_tag_id(oldtag) == 0x3ff) { - LFS_TRACE("lfs_rename -> %"PRId32, - (oldtag < 0) ? oldtag : LFS_ERR_INVAL); return (oldtag < 0) ? (int)oldtag : LFS_ERR_INVAL; } @@ -3254,8 +3264,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { 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)) { - LFS_TRACE("lfs_rename -> %"PRId32, - (prevtag < 0) ? prevtag : LFS_ERR_INVAL); return (prevtag < 0) ? (int)prevtag : LFS_ERR_INVAL; } @@ -3269,7 +3277,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { // check that name fits lfs_size_t nlen = strlen(newpath); if (nlen > lfs->name_max) { - LFS_TRACE("lfs_rename -> %d", LFS_ERR_NAMETOOLONG); return LFS_ERR_NAMETOOLONG; } @@ -3280,11 +3287,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { newoldid += 1; } } else if (lfs_tag_type3(prevtag) != lfs_tag_type3(oldtag)) { - LFS_TRACE("lfs_rename -> %d", LFS_ERR_ISDIR); return LFS_ERR_ISDIR; } else if (samepair && newid == newoldid) { // we're renaming to ourselves?? - LFS_TRACE("lfs_rename -> %d", 0); return 0; } else if (lfs_tag_type3(prevtag) == LFS_TYPE_DIR) { // must be empty before removal @@ -3292,7 +3297,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { lfs_stag_t res = lfs_dir_get(lfs, &newcwd, LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_STRUCT, newid, 8), prevpair); if (res < 0) { - LFS_TRACE("lfs_rename -> %"PRId32, res); return (int)res; } lfs_pair_fromle32(prevpair); @@ -3300,12 +3304,10 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { // must be empty before removal err = lfs_dir_fetch(lfs, &prevdir.m, prevpair); if (err) { - LFS_TRACE("lfs_rename -> %d", err); return err; } if (prevdir.m.count > 0 || prevdir.m.split) { - LFS_TRACE("lfs_rename -> %d", LFS_ERR_NOTEMPTY); return LFS_ERR_NOTEMPTY; } @@ -3334,7 +3336,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { LFS_TYPE_DELETE, newoldid, 0), NULL})); if (err) { lfs->mlist = prevdir.next; - LFS_TRACE("lfs_rename -> %d", err); return err; } @@ -3347,7 +3348,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(oldtag), 0), NULL})); if (err) { lfs->mlist = prevdir.next; - LFS_TRACE("lfs_rename -> %d", err); return err; } } @@ -3359,29 +3359,24 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { err = lfs_fs_pred(lfs, prevdir.m.pair, &newcwd); if (err) { - LFS_TRACE("lfs_rename -> %d", err); return err; } err = lfs_dir_drop(lfs, &newcwd, &prevdir.m); if (err) { - LFS_TRACE("lfs_rename -> %d", err); return err; } } - LFS_TRACE("lfs_rename -> %d", 0); return 0; } +#endif -lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, +static lfs_ssize_t lfs_rawgetattr(lfs_t *lfs, const char *path, uint8_t type, void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", - (void*)lfs, path, type, buffer, size); lfs_mdir_t cwd; lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); if (tag < 0) { - LFS_TRACE("lfs_getattr -> %"PRId32, tag); return tag; } @@ -3391,7 +3386,6 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, id = 0; int err = lfs_dir_fetch(lfs, &cwd, lfs->root); if (err) { - LFS_TRACE("lfs_getattr -> %d", err); return err; } } @@ -3402,19 +3396,16 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, buffer); if (tag < 0) { if (tag == LFS_ERR_NOENT) { - LFS_TRACE("lfs_getattr -> %d", LFS_ERR_NOATTR); return LFS_ERR_NOATTR; } - LFS_TRACE("lfs_getattr -> %"PRId32, tag); return tag; } - size = lfs_tag_size(tag); - LFS_TRACE("lfs_getattr -> %"PRId32, size); - return size; + return lfs_tag_size(tag); } +#ifndef LFS_READONLY static int lfs_commitattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size) { lfs_mdir_t cwd; @@ -3436,27 +3427,24 @@ static int lfs_commitattr(lfs_t *lfs, const char *path, return lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( {LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer})); } +#endif -int lfs_setattr(lfs_t *lfs, const char *path, +#ifndef LFS_READONLY +static int lfs_rawsetattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size) { - LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", - (void*)lfs, path, type, buffer, size); if (size > lfs->attr_max) { - LFS_TRACE("lfs_setattr -> %d", LFS_ERR_NOSPC); return LFS_ERR_NOSPC; } - int err = lfs_commitattr(lfs, path, type, buffer, size); - LFS_TRACE("lfs_setattr -> %d", err); - return err; + return lfs_commitattr(lfs, path, type, buffer, size); } +#endif -int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) { - LFS_TRACE("lfs_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs, path, type); - int err = lfs_commitattr(lfs, path, type, NULL, 0x3ff); - LFS_TRACE("lfs_removeattr -> %d", err); - return err; +#ifndef LFS_READONLY +static int lfs_rawremoveattr(lfs_t *lfs, const char *path, uint8_t type) { + return lfs_commitattr(lfs, path, type, NULL, 0x3ff); } +#endif /// Filesystem operations /// @@ -3584,28 +3572,12 @@ static int lfs_deinit(lfs_t *lfs) { return 0; } -int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { - LFS_TRACE("lfs_format(%p, %p {.context=%p, " - ".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", " - ".lookahead_size=%"PRIu32", .read_buffer=%p, " - ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", - (void*)lfs, (void*)cfg, cfg->context, - (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, - (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, - cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, - cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); +#ifndef LFS_READONLY +static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) { int err = 0; { err = lfs_init(lfs, cfg); if (err) { - LFS_TRACE("lfs_format -> %d", err); return err; } @@ -3661,30 +3633,14 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { cleanup: lfs_deinit(lfs); - LFS_TRACE("lfs_format -> %d", err); return err; + } +#endif -int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { - LFS_TRACE("lfs_mount(%p, %p {.context=%p, " - ".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", " - ".lookahead_size=%"PRIu32", .read_buffer=%p, " - ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", - (void*)lfs, (void*)cfg, cfg->context, - (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, - (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, - cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, - cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); +static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) { int err = lfs_init(lfs, cfg); if (err) { - LFS_TRACE("lfs_mount -> %d", err); return err; } @@ -3797,28 +3753,25 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { lfs->gstate.tag += !lfs_tag_isvalid(lfs->gstate.tag); lfs->gdisk = lfs->gstate; - // setup free lookahead - lfs_alloc_reset(lfs); + // setup free lookahead, to distribute allocations uniformly across + // boots, we start the allocator at a random location + lfs->free.off = lfs->seed % lfs->cfg->block_count; + lfs_alloc_drop(lfs); - LFS_TRACE("lfs_mount -> %d", 0); return 0; cleanup: - lfs_unmount(lfs); - LFS_TRACE("lfs_mount -> %d", err); + lfs_rawunmount(lfs); return err; } -int lfs_unmount(lfs_t *lfs) { - LFS_TRACE("lfs_unmount(%p)", (void*)lfs); - int err = lfs_deinit(lfs); - LFS_TRACE("lfs_unmount -> %d", err); - return err; +static int lfs_rawunmount(lfs_t *lfs) { + return lfs_deinit(lfs); } /// Filesystem filesystem operations /// -int lfs_fs_traverseraw(lfs_t *lfs, +int lfs_fs_rawtraverse(lfs_t *lfs, int (*cb)(void *data, lfs_block_t block), void *data, bool includeorphans) { // iterate over metadata pairs @@ -3888,6 +3841,7 @@ int lfs_fs_traverseraw(lfs_t *lfs, } } +#ifndef LFS_READONLY // iterate over any open files for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { if (f->type != LFS_TYPE_REG) { @@ -3910,19 +3864,12 @@ int lfs_fs_traverseraw(lfs_t *lfs, } } } +#endif return 0; } -int lfs_fs_traverse(lfs_t *lfs, - int (*cb)(void *data, lfs_block_t block), void *data) { - LFS_TRACE("lfs_fs_traverse(%p, %p, %p)", - (void*)lfs, (void*)(uintptr_t)cb, data); - int err = lfs_fs_traverseraw(lfs, cb, data, true); - LFS_TRACE("lfs_fs_traverse -> %d", 0); - return err; -} - +#ifndef LFS_READONLY static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t pair[2], lfs_mdir_t *pdir) { // iterate over all directory directory entries @@ -3948,12 +3895,16 @@ static int lfs_fs_pred(lfs_t *lfs, return LFS_ERR_NOENT; } +#endif +#ifndef LFS_READONLY struct lfs_fs_parent_match { lfs_t *lfs; const lfs_block_t pair[2]; }; +#endif +#ifndef LFS_READONLY static int lfs_fs_parent_match(void *data, lfs_tag_t tag, const void *buffer) { struct lfs_fs_parent_match *find = data; @@ -3972,7 +3923,9 @@ static int lfs_fs_parent_match(void *data, lfs_pair_fromle32(child); return (lfs_pair_cmp(child, find->pair) == 0) ? LFS_CMP_EQ : LFS_CMP_LT; } +#endif +#ifndef LFS_READONLY static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2], lfs_mdir_t *parent) { // use fetchmatch with callback to find pairs @@ -3999,7 +3952,9 @@ static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t pair[2], return LFS_ERR_NOENT; } +#endif +#ifndef LFS_READONLY static int lfs_fs_relocate(lfs_t *lfs, const lfs_block_t oldpair[2], lfs_block_t newpair[2]) { // update internal root @@ -4094,14 +4049,18 @@ static int lfs_fs_relocate(lfs_t *lfs, return 0; } +#endif +#ifndef LFS_READONLY static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) { LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0 || orphans >= 0); lfs->gstate.tag += orphans; lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x800, 0, 0)) | ((uint32_t)lfs_gstate_hasorphans(&lfs->gstate) << 31)); } +#endif +#ifndef LFS_READONLY static void lfs_fs_prepmove(lfs_t *lfs, uint16_t id, const lfs_block_t pair[2]) { lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x7ff, 0x3ff, 0)) | @@ -4109,7 +4068,9 @@ static void lfs_fs_prepmove(lfs_t *lfs, lfs->gstate.pair[0] = (id != 0x3ff) ? pair[0] : 0; lfs->gstate.pair[1] = (id != 0x3ff) ? pair[1] : 0; } +#endif +#ifndef LFS_READONLY static int lfs_fs_demove(lfs_t *lfs) { if (!lfs_gstate_hasmove(&lfs->gdisk)) { return 0; @@ -4139,7 +4100,9 @@ static int lfs_fs_demove(lfs_t *lfs) { return 0; } +#endif +#ifndef LFS_READONLY static int lfs_fs_deorphan(lfs_t *lfs) { if (!lfs_gstate_hasorphans(&lfs->gstate)) { return 0; @@ -4213,7 +4176,9 @@ static int lfs_fs_deorphan(lfs_t *lfs) { lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate)); return 0; } +#endif +#ifndef LFS_READONLY static int lfs_fs_forceconsistency(lfs_t *lfs) { int err = lfs_fs_demove(lfs); if (err) { @@ -4227,6 +4192,7 @@ static int lfs_fs_forceconsistency(lfs_t *lfs) { return 0; } +#endif static int lfs_fs_size_count(void *p, lfs_block_t block) { (void)block; @@ -4235,16 +4201,13 @@ static int lfs_fs_size_count(void *p, lfs_block_t block) { return 0; } -lfs_ssize_t lfs_fs_size(lfs_t *lfs) { - LFS_TRACE("lfs_fs_size(%p)", (void*)lfs); +static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) { lfs_size_t size = 0; - int err = lfs_fs_traverseraw(lfs, lfs_fs_size_count, &size, false); + int err = lfs_fs_rawtraverse(lfs, lfs_fs_size_count, &size, false); if (err) { - LFS_TRACE("lfs_fs_size -> %d", err); return err; } - LFS_TRACE("lfs_fs_size -> %d", err); return size; } @@ -4669,27 +4632,10 @@ static int lfs1_unmount(lfs_t *lfs) { } /// v1 migration /// -int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { - LFS_TRACE("lfs_migrate(%p, %p {.context=%p, " - ".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", " - ".lookahead_size=%"PRIu32", .read_buffer=%p, " - ".prog_buffer=%p, .lookahead_buffer=%p, " - ".name_max=%"PRIu32", .file_max=%"PRIu32", " - ".attr_max=%"PRIu32"})", - (void*)lfs, (void*)cfg, cfg->context, - (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, - (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, - cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, - cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, - cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, - cfg->name_max, cfg->file_max, cfg->attr_max); +static int lfs_rawmigrate(lfs_t *lfs, const struct lfs_config *cfg) { struct lfs1 lfs1; int err = lfs1_mount(lfs, &lfs1, cfg); if (err) { - LFS_TRACE("lfs_migrate -> %d", err); return err; } @@ -4906,8 +4852,539 @@ int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { cleanup: lfs1_unmount(lfs); - LFS_TRACE("lfs_migrate -> %d", err); return err; } #endif + + +/// Public API wrappers /// + +// Here we can add tracing/thread safety easily + +// Thread-safe wrappers if enabled +#ifdef LFS_THREADSAFE +#define LFS_LOCK(cfg) cfg->lock(cfg) +#define LFS_UNLOCK(cfg) cfg->unlock(cfg) +#else +#define LFS_LOCK(cfg) ((void)cfg, 0) +#define LFS_UNLOCK(cfg) ((void)cfg) +#endif + +// Public API +#ifndef LFS_READONLY +int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { + int err = LFS_LOCK(cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_format(%p, %p {.context=%p, " + ".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", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + + err = lfs_rawformat(lfs, cfg); + + LFS_TRACE("lfs_format -> %d", err); + LFS_UNLOCK(cfg); + return err; +} +#endif + +int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { + int err = LFS_LOCK(cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_mount(%p, %p {.context=%p, " + ".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", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + + err = lfs_rawmount(lfs, cfg); + + LFS_TRACE("lfs_mount -> %d", err); + LFS_UNLOCK(cfg); + return err; +} + +int lfs_unmount(lfs_t *lfs) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_unmount(%p)", (void*)lfs); + + err = lfs_rawunmount(lfs); + + LFS_TRACE("lfs_unmount -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +#ifndef LFS_READONLY +int lfs_remove(lfs_t *lfs, const char *path) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_remove(%p, \"%s\")", (void*)lfs, path); + + err = lfs_rawremove(lfs, path); + + LFS_TRACE("lfs_remove -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +#ifndef LFS_READONLY +int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_rename(%p, \"%s\", \"%s\")", (void*)lfs, oldpath, newpath); + + err = lfs_rawrename(lfs, oldpath, newpath); + + LFS_TRACE("lfs_rename -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_stat(%p, \"%s\", %p)", (void*)lfs, path, (void*)info); + + err = lfs_rawstat(lfs, path, info); + + LFS_TRACE("lfs_stat -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, + uint8_t type, void *buffer, lfs_size_t size) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", + (void*)lfs, path, type, buffer, size); + + lfs_ssize_t res = lfs_rawgetattr(lfs, path, type, buffer, size); + + LFS_TRACE("lfs_getattr -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +#ifndef LFS_READONLY +int lfs_setattr(lfs_t *lfs, const char *path, + uint8_t type, const void *buffer, lfs_size_t size) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", + (void*)lfs, path, type, buffer, size); + + err = lfs_rawsetattr(lfs, path, type, buffer, size); + + LFS_TRACE("lfs_setattr -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +#ifndef LFS_READONLY +int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs, path, type); + + err = lfs_rawremoveattr(lfs, path, type); + + LFS_TRACE("lfs_removeattr -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +int lfs_file_open(lfs_t *lfs, lfs_file_t *file, const char *path, int flags) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_open(%p, %p, \"%s\", %x)", + (void*)lfs, (void*)file, path, flags); + LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + err = lfs_file_rawopen(lfs, file, path, flags); + + LFS_TRACE("lfs_file_open -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, + const char *path, int flags, + const struct lfs_file_config *cfg) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_opencfg(%p, %p, \"%s\", %x, %p {" + ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", + (void*)lfs, (void*)file, path, flags, + (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); + LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + err = lfs_file_rawopencfg(lfs, file, path, flags, cfg); + + LFS_TRACE("lfs_file_opencfg -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + err = lfs_file_rawclose(lfs, file); + + LFS_TRACE("lfs_file_close -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +#ifndef LFS_READONLY +int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + err = lfs_file_rawsync(lfs, file); + + LFS_TRACE("lfs_file_sync -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, + void *buffer, lfs_size_t size) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")", + (void*)lfs, (void*)file, buffer, size); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + lfs_ssize_t res = lfs_file_rawread(lfs, file, buffer, size); + + LFS_TRACE("lfs_file_read -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +#ifndef LFS_READONLY +lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, + const void *buffer, lfs_size_t size) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")", + (void*)lfs, (void*)file, buffer, size); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + lfs_ssize_t res = lfs_file_rawwrite(lfs, file, buffer, size); + + LFS_TRACE("lfs_file_write -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} +#endif + +lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, + lfs_soff_t off, int whence) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)", + (void*)lfs, (void*)file, off, whence); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + lfs_soff_t res = lfs_file_rawseek(lfs, file, off, whence); + + LFS_TRACE("lfs_file_seek -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +#ifndef LFS_READONLY +int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")", + (void*)lfs, (void*)file, size); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + err = lfs_file_rawtruncate(lfs, file, size); + + LFS_TRACE("lfs_file_truncate -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + lfs_soff_t res = lfs_file_rawtell(lfs, file); + + LFS_TRACE("lfs_file_tell -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_rewind(%p, %p)", (void*)lfs, (void*)file); + + err = lfs_file_rawrewind(lfs, file); + + LFS_TRACE("lfs_file_rewind -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file); + LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file)); + + lfs_soff_t res = lfs_file_rawsize(lfs, file); + + LFS_TRACE("lfs_file_size -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +#ifndef LFS_READONLY +int lfs_mkdir(lfs_t *lfs, const char *path) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_mkdir(%p, \"%s\")", (void*)lfs, path); + + err = lfs_rawmkdir(lfs, path); + + LFS_TRACE("lfs_mkdir -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} +#endif + +int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_open(%p, %p, \"%s\")", (void*)lfs, (void*)dir, path); + LFS_ASSERT(!lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)dir)); + + err = lfs_dir_rawopen(lfs, dir, path); + + LFS_TRACE("lfs_dir_open -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_close(%p, %p)", (void*)lfs, (void*)dir); + + err = lfs_dir_rawclose(lfs, dir); + + LFS_TRACE("lfs_dir_close -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_read(%p, %p, %p)", + (void*)lfs, (void*)dir, (void*)info); + + err = lfs_dir_rawread(lfs, dir, info); + + LFS_TRACE("lfs_dir_read -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_seek(%p, %p, %"PRIu32")", + (void*)lfs, (void*)dir, off); + + err = lfs_dir_rawseek(lfs, dir, off); + + LFS_TRACE("lfs_dir_seek -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_tell(%p, %p)", (void*)lfs, (void*)dir); + + lfs_soff_t res = lfs_dir_rawtell(lfs, dir); + + LFS_TRACE("lfs_dir_tell -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_dir_rewind(%p, %p)", (void*)lfs, (void*)dir); + + err = lfs_dir_rawrewind(lfs, dir); + + LFS_TRACE("lfs_dir_rewind -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +lfs_ssize_t lfs_fs_size(lfs_t *lfs) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_fs_size(%p)", (void*)lfs); + + lfs_ssize_t res = lfs_fs_rawsize(lfs); + + LFS_TRACE("lfs_fs_size -> %"PRId32, res); + LFS_UNLOCK(lfs->cfg); + return res; +} + +int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void *, lfs_block_t), void *data) { + int err = LFS_LOCK(lfs->cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_fs_traverse(%p, %p, %p)", + (void*)lfs, (void*)(uintptr_t)cb, data); + + err = lfs_fs_rawtraverse(lfs, cb, data, true); + + LFS_TRACE("lfs_fs_traverse -> %d", err); + LFS_UNLOCK(lfs->cfg); + return err; +} + +#ifdef LFS_MIGRATE +int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg) { + int err = LFS_LOCK(cfg); + if (err) { + return err; + } + LFS_TRACE("lfs_migrate(%p, %p {.context=%p, " + ".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", " + ".lookahead_size=%"PRIu32", .read_buffer=%p, " + ".prog_buffer=%p, .lookahead_buffer=%p, " + ".name_max=%"PRIu32", .file_max=%"PRIu32", " + ".attr_max=%"PRIu32"})", + (void*)lfs, (void*)cfg, cfg->context, + (void*)(uintptr_t)cfg->read, (void*)(uintptr_t)cfg->prog, + (void*)(uintptr_t)cfg->erase, (void*)(uintptr_t)cfg->sync, + cfg->read_size, cfg->prog_size, cfg->block_size, cfg->block_count, + cfg->block_cycles, cfg->cache_size, cfg->lookahead_size, + cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, + cfg->name_max, cfg->file_max, cfg->attr_max); + + err = lfs_rawmigrate(lfs, cfg); + + LFS_TRACE("lfs_migrate -> %d", err); + LFS_UNLOCK(cfg); + return err; +} +#endif + @@ -9,6 +9,7 @@ #include <stdint.h> #include <stdbool.h> +#include "lfs_util.h" #ifdef __cplusplus extern "C" @@ -21,7 +22,7 @@ extern "C" // Software library version // Major (top-nibble), incremented on backwards incompatible changes // Minor (bottom-nibble), incremented on feature additions -#define LFS_VERSION 0x00020002 +#define LFS_VERSION 0x00020003 #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16)) #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >> 0)) @@ -123,20 +124,25 @@ enum lfs_type { enum lfs_open_flags { // open flags LFS_O_RDONLY = 1, // Open a file as read only +#ifndef LFS_READONLY LFS_O_WRONLY = 2, // Open a file as write only LFS_O_RDWR = 3, // Open a file as read and write LFS_O_CREAT = 0x0100, // Create a file if it does not exist LFS_O_EXCL = 0x0200, // Fail if a file already exists LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size LFS_O_APPEND = 0x0800, // Move to end of file on every write +#endif // internally used flags +#ifndef LFS_READONLY LFS_F_DIRTY = 0x010000, // File does not match storage LFS_F_WRITING = 0x020000, // File has been written since last flush +#endif LFS_F_READING = 0x040000, // File has been read since last flush - LFS_F_ERRED = 0x080000, // An error occured during write +#ifndef LFS_READONLY + LFS_F_ERRED = 0x080000, // An error occurred during write +#endif LFS_F_INLINE = 0x100000, // Currently inlined in directory entry - LFS_F_OPENED = 0x200000, // File has been opened }; // File seek flags @@ -174,6 +180,16 @@ struct lfs_config { // are propogated to the user. int (*sync)(const struct lfs_config *c); +#ifdef LFS_THREADSAFE + // Lock the underlying block device. Negative error codes + // are propogated to the user. + int (*lock)(const struct lfs_config *c); + + // Unlock the underlying block device. Negative error codes + // are propogated to the user. + int (*unlock)(const struct lfs_config *c); +#endif + // Minimum size of a block read. All read operations will be a // multiple of this value. lfs_size_t read_size; @@ -399,6 +415,7 @@ typedef struct lfs { /// Filesystem functions /// +#ifndef LFS_READONLY // Format a block device with the littlefs // // Requires a littlefs object and config struct. This clobbers the littlefs @@ -407,6 +424,7 @@ typedef struct lfs { // // Returns a negative error code on failure. int lfs_format(lfs_t *lfs, const struct lfs_config *config); +#endif // Mounts a littlefs // @@ -426,12 +444,15 @@ int lfs_unmount(lfs_t *lfs); /// General operations /// +#ifndef LFS_READONLY // Removes a file or directory // // If removing a directory, the directory must be empty. // Returns a negative error code on failure. int lfs_remove(lfs_t *lfs, const char *path); +#endif +#ifndef LFS_READONLY // Rename or move a file or directory // // If the destination exists, it must match the source in type. @@ -439,6 +460,7 @@ int lfs_remove(lfs_t *lfs, const char *path); // // Returns a negative error code on failure. int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); +#endif // Find info about a file or directory // @@ -461,6 +483,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, uint8_t type, void *buffer, lfs_size_t size); +#ifndef LFS_READONLY // Set custom attributes // // Custom attributes are uniquely identified by an 8-bit type and limited @@ -470,13 +493,16 @@ lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, // Returns a negative error code on failure. int lfs_setattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size); +#endif +#ifndef LFS_READONLY // Removes a custom attribute // // If an attribute is not found, nothing happens. // // Returns a negative error code on failure. int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); +#endif /// File operations /// @@ -525,6 +551,7 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file); lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, void *buffer, lfs_size_t size); +#ifndef LFS_READONLY // Write data to file // // Takes a buffer and size indicating the data to write. The file will not @@ -533,6 +560,7 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, // Returns the number of bytes written, or a negative error code on failure. lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, const void *buffer, lfs_size_t size); +#endif // Change the position of the file // @@ -541,10 +569,12 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file, lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, lfs_soff_t off, int whence); +#ifndef LFS_READONLY // Truncates the size of the file to the specified size // // Returns a negative error code on failure. int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size); +#endif // Return the position of the file // @@ -567,10 +597,12 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); /// Directory operations /// +#ifndef LFS_READONLY // Create a directory // // Returns a negative error code on failure. int lfs_mkdir(lfs_t *lfs, const char *path); +#endif // Open a directory // @@ -632,6 +664,7 @@ lfs_ssize_t lfs_fs_size(lfs_t *lfs); // Returns a negative error code on failure. int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); +#ifndef LFS_READONLY #ifdef LFS_MIGRATE // Attempts to migrate a previous version of littlefs // @@ -646,6 +679,7 @@ int lfs_fs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data); // Returns a negative error code on failure. int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); #endif +#endif #ifdef __cplusplus diff --git a/scripts/readtree.py b/scripts/readtree.py index 36135ab..be514e3 100755 --- a/scripts/readtree.py +++ b/scripts/readtree.py @@ -106,7 +106,7 @@ def main(args): struct.unpack('<HH', superblock[1].data[0:4].ljust(4, b'\xff')))) print("%-47s%s" % ("littlefs v%s.%s" % version, "data (truncated, if it fits)" - if not any([args.no_truncate, args.tags, args.log, args.all]) else "")) + if not any([args.no_truncate, args.log, args.all]) else "")) # print gstate print("gstate 0x%s" % ''.join('%02x' % c for c in gstate)) |