diff --git a/lib/littlefs/README.md b/lib/littlefs/README.md index 1f0aacbf98..ca21a05f42 100644 --- a/lib/littlefs/README.md +++ b/lib/littlefs/README.md @@ -2,7 +2,7 @@ littlefs library ================ The upstream source for the files in this directory is -https://github.com/ARMmbed/littlefs +https://github.com/littlefs-project/littlefs To generate the separate files with lfs1 and lfs2 prefixes run the following commands in the top-level directory of the littlefs repository (replace the @@ -13,7 +13,7 @@ version tags with the latest/desired ones, and set `$MPY_DIR`): cp lfs1*.[ch] $MPY_DIR/lib/littlefs git reset --hard HEAD - git checkout v2.1.3 + git checkout v2.3.0 python2 ./scripts/prefix.py lfs2 cp lfs2*.[ch] $MPY_DIR/lib/littlefs git reset --hard HEAD diff --git a/lib/littlefs/lfs2.c b/lib/littlefs/lfs2.c index 6bae806ceb..31f3c603e7 100644 --- a/lib/littlefs/lfs2.c +++ b/lib/littlefs/lfs2.c @@ -118,24 +118,29 @@ static int lfs2_bd_cmp(lfs2_t *lfs2, lfs2_block_t block, lfs2_off_t off, const void *buffer, lfs2_size_t size) { const uint8_t *data = buffer; + lfs2_size_t diff = 0; - for (lfs2_off_t i = 0; i < size; i++) { - uint8_t dat; - int err = lfs2_bd_read(lfs2, + for (lfs2_off_t i = 0; i < size; i += diff) { + uint8_t dat[8]; + + diff = lfs2_min(size-i, sizeof(dat)); + int res = lfs2_bd_read(lfs2, 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]) ? LFS2_CMP_LT : LFS2_CMP_GT; + res = memcmp(dat, data + i, diff); + if (res) { + return res < 0 ? LFS2_CMP_LT : LFS2_CMP_GT; } } return LFS2_CMP_EQ; } +#ifndef LFS2_READONLY static int lfs2_bd_flush(lfs2_t *lfs2, lfs2_cache_t *pcache, lfs2_cache_t *rcache, bool validate) { if (pcache->block != LFS2_BLOCK_NULL && pcache->block != LFS2_BLOCK_INLINE) { @@ -168,7 +173,9 @@ static int lfs2_bd_flush(lfs2_t *lfs2, return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_bd_sync(lfs2_t *lfs2, lfs2_cache_t *pcache, lfs2_cache_t *rcache, bool validate) { lfs2_cache_drop(lfs2, rcache); @@ -182,7 +189,9 @@ static int lfs2_bd_sync(lfs2_t *lfs2, LFS2_ASSERT(err <= 0); return err; } +#endif +#ifndef LFS2_READONLY static int lfs2_bd_prog(lfs2_t *lfs2, lfs2_cache_t *pcache, lfs2_cache_t *rcache, bool validate, lfs2_block_t block, lfs2_off_t off, @@ -228,13 +237,16 @@ static int lfs2_bd_prog(lfs2_t *lfs2, return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_bd_erase(lfs2_t *lfs2, lfs2_block_t block) { LFS2_ASSERT(block < lfs2->cfg->block_count); int err = lfs2->cfg->erase(lfs2->cfg, block); LFS2_ASSERT(err <= 0); return err; } +#endif /// Small type-level utilities /// @@ -388,10 +400,12 @@ static void lfs2_ctz_fromle32(struct lfs2_ctz *ctz) { ctz->size = lfs2_fromle32(ctz->size); } +#ifndef LFS2_READONLY static void lfs2_ctz_tole32(struct lfs2_ctz *ctz) { ctz->head = lfs2_tole32(ctz->head); ctz->size = lfs2_tole32(ctz->size); } +#endif static inline void lfs2_superblock_fromle32(lfs2_superblock_t *superblock) { superblock->version = lfs2_fromle32(superblock->version); @@ -411,15 +425,46 @@ static inline void lfs2_superblock_tole32(lfs2_superblock_t *superblock) { superblock->attr_max = lfs2_tole32(superblock->attr_max); } +static inline bool lfs2_mlist_isopen(struct lfs2_mlist *head, + struct lfs2_mlist *node) { + for (struct lfs2_mlist **p = &head; *p; p = &(*p)->next) { + if (*p == (struct lfs2_mlist*)node) { + return true; + } + } + + return false; +} + +static inline void lfs2_mlist_remove(lfs2_t *lfs2, struct lfs2_mlist *mlist) { + for (struct lfs2_mlist **p = &lfs2->mlist; *p; p = &(*p)->next) { + if (*p == mlist) { + *p = (*p)->next; + break; + } + } +} + +static inline void lfs2_mlist_append(lfs2_t *lfs2, struct lfs2_mlist *mlist) { + mlist->next = lfs2->mlist; + lfs2->mlist = mlist; +} + /// Internal operations predeclared here /// +#ifndef LFS2_READONLY static int lfs2_dir_commit(lfs2_t *lfs2, lfs2_mdir_t *dir, const struct lfs2_mattr *attrs, int attrcount); static int lfs2_dir_compact(lfs2_t *lfs2, lfs2_mdir_t *dir, const struct lfs2_mattr *attrs, int attrcount, lfs2_mdir_t *source, uint16_t begin, uint16_t end); + +static lfs2_ssize_t lfs2_file_rawwrite(lfs2_t *lfs2, lfs2_file_t *file, + const void *buffer, lfs2_size_t size); +static int lfs2_file_rawsync(lfs2_t *lfs2, lfs2_file_t *file); static int lfs2_file_outline(lfs2_t *lfs2, lfs2_file_t *file); static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file); + static void lfs2_fs_preporphans(lfs2_t *lfs2, int8_t orphans); static void lfs2_fs_prepmove(lfs2_t *lfs2, uint16_t id, const lfs2_block_t pair[2]); @@ -429,17 +474,32 @@ static lfs2_stag_t lfs2_fs_parent(lfs2_t *lfs2, const lfs2_block_t dir[2], lfs2_mdir_t *parent); static int lfs2_fs_relocate(lfs2_t *lfs2, const lfs2_block_t oldpair[2], lfs2_block_t newpair[2]); -int lfs2_fs_traverseraw(lfs2_t *lfs2, - int (*cb)(void *data, lfs2_block_t block), void *data, - bool includeorphans); static int lfs2_fs_forceconsistency(lfs2_t *lfs2); -static int lfs2_deinit(lfs2_t *lfs2); +#endif + #ifdef LFS2_MIGRATE static int lfs21_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data); #endif +static int lfs2_dir_rawrewind(lfs2_t *lfs2, lfs2_dir_t *dir); + +static lfs2_ssize_t lfs2_file_rawread(lfs2_t *lfs2, lfs2_file_t *file, + void *buffer, lfs2_size_t size); +static int lfs2_file_rawclose(lfs2_t *lfs2, lfs2_file_t *file); +static lfs2_soff_t lfs2_file_rawsize(lfs2_t *lfs2, lfs2_file_t *file); + +static lfs2_ssize_t lfs2_fs_rawsize(lfs2_t *lfs2); +static int lfs2_fs_rawtraverse(lfs2_t *lfs2, + int (*cb)(void *data, lfs2_block_t block), void *data, + bool includeorphans); + +static int lfs2_deinit(lfs2_t *lfs2); +static int lfs2_rawunmount(lfs2_t *lfs2); + + /// Block allocator /// +#ifndef LFS2_READONLY static int lfs2_alloc_lookahead(void *p, lfs2_block_t block) { lfs2_t *lfs2 = (lfs2_t*)p; lfs2_block_t off = ((block - lfs2->free.off) @@ -451,20 +511,24 @@ static int lfs2_alloc_lookahead(void *p, lfs2_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 lfs2_alloc_ack(lfs2_t *lfs2) { lfs2->free.ack = lfs2->cfg->block_count; } -// Invalidate the lookahead buffer. This is done during mounting and -// failed traversals -static void lfs2_alloc_reset(lfs2_t *lfs2) { - lfs2->free.off = lfs2->seed % lfs2->cfg->block_size; +// drop the lookahead buffer, this is done during mounting and failed +// traversals in order to avoid invalid lookahead state +static void lfs2_alloc_drop(lfs2_t *lfs2) { lfs2->free.size = 0; lfs2->free.i = 0; lfs2_alloc_ack(lfs2); } +#ifndef LFS2_READONLY static int lfs2_alloc(lfs2_t *lfs2, lfs2_block_t *block) { while (true) { while (lfs2->free.i != lfs2->free.size) { @@ -503,13 +567,14 @@ static int lfs2_alloc(lfs2_t *lfs2, lfs2_block_t *block) { // find mask of free blocks from tree memset(lfs2->free.buffer, 0, lfs2->cfg->lookahead_size); - int err = lfs2_fs_traverseraw(lfs2, lfs2_alloc_lookahead, lfs2, true); + int err = lfs2_fs_rawtraverse(lfs2, lfs2_alloc_lookahead, lfs2, true); if (err) { - lfs2_alloc_reset(lfs2); + lfs2_alloc_drop(lfs2); return err; } } } +#endif /// Metadata pair and directory operations /// static lfs2_stag_t lfs2_dir_getslice(lfs2_t *lfs2, const lfs2_mdir_t *dir, @@ -642,6 +707,7 @@ static int lfs2_dir_getread(lfs2_t *lfs2, const lfs2_mdir_t *dir, return 0; } +#ifndef LFS2_READONLY static int lfs2_dir_traverse_filter(void *p, lfs2_tag_t tag, const void *buffer) { lfs2_tag_t *filtertag = p; @@ -669,7 +735,9 @@ static int lfs2_dir_traverse_filter(void *p, return false; } +#endif +#ifndef LFS2_READONLY static int lfs2_dir_traverse(lfs2_t *lfs2, const lfs2_mdir_t *dir, lfs2_off_t off, lfs2_tag_t ptag, const struct lfs2_mattr *attrs, int attrcount, @@ -763,6 +831,7 @@ static int lfs2_dir_traverse(lfs2_t *lfs2, } } } +#endif static lfs2_stag_t lfs2_dir_fetchmatch(lfs2_t *lfs2, lfs2_mdir_t *dir, const lfs2_block_t pair[2], @@ -870,8 +939,10 @@ static lfs2_stag_t lfs2_dir_fetchmatch(lfs2_t *lfs2, ptag ^= (lfs2_tag_t)(lfs2_tag_chunk(tag) & 1U) << 31; // toss our crc into the filesystem seed for - // pseudorandom numbers - lfs2->seed ^= crc; + // pseudorandom numbers, note we use another crc here + // as a collection function because it is sufficiently + // random and convenient + lfs2->seed = lfs2_crc(lfs2->seed, &crc, sizeof(crc)); // update with what's found so far besttag = tempbesttag; @@ -1200,6 +1271,7 @@ struct lfs2_commit { lfs2_off_t end; }; +#ifndef LFS2_READONLY static int lfs2_dir_commitprog(lfs2_t *lfs2, struct lfs2_commit *commit, const void *buffer, lfs2_size_t size) { int err = lfs2_bd_prog(lfs2, @@ -1214,7 +1286,9 @@ static int lfs2_dir_commitprog(lfs2_t *lfs2, struct lfs2_commit *commit, commit->off += size; return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_dir_commitattr(lfs2_t *lfs2, struct lfs2_commit *commit, lfs2_tag_t tag, const void *buffer) { // check if we fit @@ -1259,14 +1333,17 @@ static int lfs2_dir_commitattr(lfs2_t *lfs2, struct lfs2_commit *commit, commit->ptag = tag & 0x7fffffff; return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_dir_commitcrc(lfs2_t *lfs2, struct lfs2_commit *commit) { - const lfs2_off_t off1 = commit->off; - const uint32_t crc1 = commit->crc; // align to program units - const lfs2_off_t end = lfs2_alignup(off1 + 2*sizeof(uint32_t), + const lfs2_off_t end = lfs2_alignup(commit->off + 2*sizeof(uint32_t), lfs2->cfg->prog_size); + lfs2_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 lfs2_dir_commitcrc(lfs2_t *lfs2, struct lfs2_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)+lfs2_tag_size(tag); commit->ptag = tag ^ ((lfs2_tag_t)reset << 31); commit->crc = 0xffffffff; // reset crc for next "commit" @@ -1315,7 +1398,7 @@ static int lfs2_dir_commitcrc(lfs2_t *lfs2, struct lfs2_commit *commit) { // successful commit, check checksums to make sure lfs2_off_t off = commit->begin; - lfs2_off_t noff = off1 + sizeof(uint32_t); + lfs2_off_t noff = off1; while (off < end) { uint32_t crc = 0xffffffff; for (lfs2_off_t i = off; i < noff+sizeof(uint32_t); i++) { @@ -1352,7 +1435,9 @@ static int lfs2_dir_commitcrc(lfs2_t *lfs2, struct lfs2_commit *commit) { return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_dir_alloc(lfs2_t *lfs2, lfs2_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 lfs2_dir_alloc(lfs2_t *lfs2, lfs2_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 lfs2_dir_compact for why our modulus + // is tweaked this way + if (lfs2->cfg->block_cycles > 0) { + dir->rev = lfs2_alignup(dir->rev, ((lfs2->cfg->block_cycles+1)|1)); + } // set defaults dir->off = sizeof(dir->rev); @@ -1390,7 +1479,9 @@ static int lfs2_dir_alloc(lfs2_t *lfs2, lfs2_mdir_t *dir) { // don't write out yet, let caller take care of that return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_dir_drop(lfs2_t *lfs2, lfs2_mdir_t *dir, lfs2_mdir_t *tail) { // steal state int err = lfs2_dir_getgstate(lfs2, tail, &lfs2->gdelta); @@ -1409,7 +1500,9 @@ static int lfs2_dir_drop(lfs2_t *lfs2, lfs2_mdir_t *dir, lfs2_mdir_t *tail) { return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_dir_split(lfs2_t *lfs2, lfs2_mdir_t *dir, const struct lfs2_mattr *attrs, int attrcount, lfs2_mdir_t *source, uint16_t split, uint16_t end) { @@ -1442,7 +1535,9 @@ static int lfs2_dir_split(lfs2_t *lfs2, return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_dir_commit_size(void *p, lfs2_tag_t tag, const void *buffer) { lfs2_size_t *size = p; (void)buffer; @@ -1450,17 +1545,23 @@ static int lfs2_dir_commit_size(void *p, lfs2_tag_t tag, const void *buffer) { *size += lfs2_tag_dsize(tag); return 0; } +#endif +#ifndef LFS2_READONLY struct lfs2_dir_commit_commit { lfs2_t *lfs2; struct lfs2_commit *commit; }; +#endif +#ifndef LFS2_READONLY static int lfs2_dir_commit_commit(void *p, lfs2_tag_t tag, const void *buffer) { struct lfs2_dir_commit_commit *commit = p; return lfs2_dir_commitattr(commit->lfs2, commit->commit, tag, buffer); } +#endif +#ifndef LFS2_READONLY static int lfs2_dir_compact(lfs2_t *lfs2, lfs2_mdir_t *dir, const struct lfs2_mattr *attrs, int attrcount, lfs2_mdir_t *source, uint16_t begin, uint16_t end) { @@ -1525,7 +1626,7 @@ static int lfs2_dir_compact(lfs2_t *lfs2, if (lfs2_pair_cmp(dir->pair, (const lfs2_block_t[2]){0, 1}) == 0) { // oh no! we're writing too much to the superblock, // should we expand? - lfs2_ssize_t res = lfs2_fs_size(lfs2); + lfs2_ssize_t res = lfs2_fs_rawsize(lfs2); if (res < 0) { return res; } @@ -1715,7 +1816,9 @@ relocate: return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_dir_commit(lfs2_t *lfs2, lfs2_mdir_t *dir, const struct lfs2_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 lfs2_mkdir(lfs2_t *lfs2, const char *path) { - LFS2_TRACE("lfs2_mkdir(%p, \"%s\")", (void*)lfs2, path); +#ifndef LFS2_READONLY +static int lfs2_rawmkdir(lfs2_t *lfs2, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs2_fs_forceconsistency(lfs2); if (err) { - LFS2_TRACE("lfs2_mkdir -> %d", err); return err; } @@ -1920,14 +2023,12 @@ int lfs2_mkdir(lfs2_t *lfs2, const char *path) { uint16_t id; err = lfs2_dir_find(lfs2, &cwd.m, &path, &id); if (!(err == LFS2_ERR_NOENT && id != 0x3ff)) { - LFS2_TRACE("lfs2_mkdir -> %d", (err < 0) ? err : LFS2_ERR_EXIST); return (err < 0) ? err : LFS2_ERR_EXIST; } // check that name fits lfs2_size_t nlen = strlen(path); if (nlen > lfs2->name_max) { - LFS2_TRACE("lfs2_mkdir -> %d", LFS2_ERR_NAMETOOLONG); return LFS2_ERR_NAMETOOLONG; } @@ -1936,7 +2037,6 @@ int lfs2_mkdir(lfs2_t *lfs2, const char *path) { lfs2_mdir_t dir; err = lfs2_dir_alloc(lfs2, &dir); if (err) { - LFS2_TRACE("lfs2_mkdir -> %d", err); return err; } @@ -1945,7 +2045,6 @@ int lfs2_mkdir(lfs2_t *lfs2, const char *path) { while (pred.split) { err = lfs2_dir_fetch(lfs2, &pred, pred.tail); if (err) { - LFS2_TRACE("lfs2_mkdir -> %d", err); return err; } } @@ -1956,7 +2055,6 @@ int lfs2_mkdir(lfs2_t *lfs2, const char *path) { {LFS2_MKTAG(LFS2_TYPE_SOFTTAIL, 0x3ff, 8), pred.tail})); lfs2_pair_fromle32(pred.tail); if (err) { - LFS2_TRACE("lfs2_mkdir -> %d", err); return err; } @@ -1979,7 +2077,6 @@ int lfs2_mkdir(lfs2_t *lfs2, const char *path) { lfs2_pair_fromle32(dir.pair); if (err) { lfs2->mlist = cwd.next; - LFS2_TRACE("lfs2_mkdir -> %d", err); return err; } @@ -1997,24 +2094,20 @@ int lfs2_mkdir(lfs2_t *lfs2, const char *path) { LFS2_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); lfs2_pair_fromle32(dir.pair); if (err) { - LFS2_TRACE("lfs2_mkdir -> %d", err); return err; } - LFS2_TRACE("lfs2_mkdir -> %d", 0); return 0; } +#endif -int lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { - LFS2_TRACE("lfs2_dir_open(%p, %p, \"%s\")", (void*)lfs2, (void*)dir, path); +static int lfs2_dir_rawopen(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { lfs2_stag_t tag = lfs2_dir_find(lfs2, &dir->m, &path, NULL); if (tag < 0) { - LFS2_TRACE("lfs2_dir_open -> %"PRId32, tag); return tag; } if (lfs2_tag_type3(tag) != LFS2_TYPE_DIR) { - LFS2_TRACE("lfs2_dir_open -> %d", LFS2_ERR_NOTDIR); return LFS2_ERR_NOTDIR; } @@ -2028,7 +2121,6 @@ int lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { lfs2_stag_t res = lfs2_dir_get(lfs2, &dir->m, LFS2_MKTAG(0x700, 0x3ff, 0), LFS2_MKTAG(LFS2_TYPE_STRUCT, lfs2_tag_id(tag), 8), pair); if (res < 0) { - LFS2_TRACE("lfs2_dir_open -> %"PRId32, res); return res; } lfs2_pair_fromle32(pair); @@ -2037,7 +2129,6 @@ int lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { // fetch first pair int err = lfs2_dir_fetch(lfs2, &dir->m, pair); if (err) { - LFS2_TRACE("lfs2_dir_open -> %d", err); return err; } @@ -2049,30 +2140,19 @@ int lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { // add to list of mdirs dir->type = LFS2_TYPE_DIR; - dir->next = (lfs2_dir_t*)lfs2->mlist; - lfs2->mlist = (struct lfs2_mlist*)dir; + lfs2_mlist_append(lfs2, (struct lfs2_mlist *)dir); - LFS2_TRACE("lfs2_dir_open -> %d", 0); return 0; } -int lfs2_dir_close(lfs2_t *lfs2, lfs2_dir_t *dir) { - LFS2_TRACE("lfs2_dir_close(%p, %p)", (void*)lfs2, (void*)dir); +static int lfs2_dir_rawclose(lfs2_t *lfs2, lfs2_dir_t *dir) { // remove from list of mdirs - for (struct lfs2_mlist **p = &lfs2->mlist; *p; p = &(*p)->next) { - if (*p == (struct lfs2_mlist*)dir) { - *p = (*p)->next; - break; - } - } + lfs2_mlist_remove(lfs2, (struct lfs2_mlist *)dir); - LFS2_TRACE("lfs2_dir_close -> %d", 0); return 0; } -int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { - LFS2_TRACE("lfs2_dir_read(%p, %p, %p)", - (void*)lfs2, (void*)dir, (void*)info); +static int lfs2_dir_rawread(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { memset(info, 0, sizeof(*info)); // special offset for '.' and '..' @@ -2080,26 +2160,22 @@ int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { info->type = LFS2_TYPE_DIR; strcpy(info->name, "."); dir->pos += 1; - LFS2_TRACE("lfs2_dir_read -> %d", true); return true; } else if (dir->pos == 1) { info->type = LFS2_TYPE_DIR; strcpy(info->name, ".."); dir->pos += 1; - LFS2_TRACE("lfs2_dir_read -> %d", true); return true; } while (true) { if (dir->id == dir->m.count) { if (!dir->m.split) { - LFS2_TRACE("lfs2_dir_read -> %d", false); return false; } int err = lfs2_dir_fetch(lfs2, &dir->m, dir->m.tail); if (err) { - LFS2_TRACE("lfs2_dir_read -> %d", err); return err; } @@ -2108,7 +2184,6 @@ int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { int err = lfs2_dir_getinfo(lfs2, &dir->m, dir->id, info); if (err && err != LFS2_ERR_NOENT) { - LFS2_TRACE("lfs2_dir_read -> %d", err); return err; } @@ -2119,17 +2194,13 @@ int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { } dir->pos += 1; - LFS2_TRACE("lfs2_dir_read -> %d", true); return true; } -int lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { - LFS2_TRACE("lfs2_dir_seek(%p, %p, %"PRIu32")", - (void*)lfs2, (void*)dir, off); +static int lfs2_dir_rawseek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { // simply walk from head dir - int err = lfs2_dir_rewind(lfs2, dir); + int err = lfs2_dir_rawrewind(lfs2, dir); if (err) { - LFS2_TRACE("lfs2_dir_seek -> %d", err); return err; } @@ -2148,13 +2219,11 @@ int lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { if (dir->id == dir->m.count) { if (!dir->m.split) { - LFS2_TRACE("lfs2_dir_seek -> %d", LFS2_ERR_INVAL); return LFS2_ERR_INVAL; } err = lfs2_dir_fetch(lfs2, &dir->m, dir->m.tail); if (err) { - LFS2_TRACE("lfs2_dir_seek -> %d", err); return err; } @@ -2162,29 +2231,23 @@ int lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { } } - LFS2_TRACE("lfs2_dir_seek -> %d", 0); return 0; } -lfs2_soff_t lfs2_dir_tell(lfs2_t *lfs2, lfs2_dir_t *dir) { - LFS2_TRACE("lfs2_dir_tell(%p, %p)", (void*)lfs2, (void*)dir); +static lfs2_soff_t lfs2_dir_rawtell(lfs2_t *lfs2, lfs2_dir_t *dir) { (void)lfs2; - LFS2_TRACE("lfs2_dir_tell -> %"PRId32, dir->pos); return dir->pos; } -int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir) { - LFS2_TRACE("lfs2_dir_rewind(%p, %p)", (void*)lfs2, (void*)dir); +static int lfs2_dir_rawrewind(lfs2_t *lfs2, lfs2_dir_t *dir) { // reload the head dir int err = lfs2_dir_fetch(lfs2, &dir->m, dir->head); if (err) { - LFS2_TRACE("lfs2_dir_rewind -> %d", err); return err; } dir->id = 0; dir->pos = 0; - LFS2_TRACE("lfs2_dir_rewind -> %d", 0); return 0; } @@ -2237,6 +2300,7 @@ static int lfs2_ctz_find(lfs2_t *lfs2, return 0; } +#ifndef LFS2_READONLY static int lfs2_ctz_extend(lfs2_t *lfs2, lfs2_cache_t *pcache, lfs2_cache_t *rcache, lfs2_block_t head, lfs2_size_t size, @@ -2334,6 +2398,7 @@ relocate: lfs2_cache_drop(lfs2, pcache); } } +#endif static int lfs2_ctz_traverse(lfs2_t *lfs2, const lfs2_cache_t *pcache, lfs2_cache_t *rcache, @@ -2380,27 +2445,25 @@ static int lfs2_ctz_traverse(lfs2_t *lfs2, /// Top level file operations /// -int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, +static int lfs2_file_rawopencfg(lfs2_t *lfs2, lfs2_file_t *file, const char *path, int flags, const struct lfs2_file_config *cfg) { - LFS2_TRACE("lfs2_file_opencfg(%p, %p, \"%s\", %x, %p {" - ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", - (void*)lfs2, (void*)file, path, flags, - (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); - +#ifndef LFS2_READONLY // deorphan if we haven't yet, needed at most once after poweron - if ((flags & 3) != LFS2_O_RDONLY) { + if ((flags & LFS2_O_WRONLY) == LFS2_O_WRONLY) { int err = lfs2_fs_forceconsistency(lfs2); if (err) { - LFS2_TRACE("lfs2_file_opencfg -> %d", err); return err; } } +#else + LFS2_ASSERT((flags & LFS2_O_RDONLY) == LFS2_O_RDONLY); +#endif // setup simple file details int err; file->cfg = cfg; - file->flags = flags | LFS2_F_OPENED; + file->flags = flags; file->pos = 0; file->off = 0; file->cache.buffer = NULL; @@ -2414,9 +2477,13 @@ int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, // get id, add to list of mdirs to catch update changes file->type = LFS2_TYPE_REG; - file->next = (lfs2_file_t*)lfs2->mlist; - lfs2->mlist = (struct lfs2_mlist*)file; + lfs2_mlist_append(lfs2, (struct lfs2_mlist *)file); +#ifdef LFS2_READONLY + if (tag == LFS2_ERR_NOENT) { + err = LFS2_ERR_NOENT; + goto cleanup; +#else if (tag == LFS2_ERR_NOENT) { if (!(flags & LFS2_O_CREAT)) { err = LFS2_ERR_NOENT; @@ -2432,9 +2499,9 @@ int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, // get next slot and create entry to remember name err = lfs2_dir_commit(lfs2, &file->m, LFS2_MKATTRS( - {LFS2_MKTAG(LFS2_TYPE_CREATE, file->id, 0)}, + {LFS2_MKTAG(LFS2_TYPE_CREATE, file->id, 0), NULL}, {LFS2_MKTAG(LFS2_TYPE_REG, file->id, nlen), path}, - {LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, file->id, 0)})); + {LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, file->id, 0), NULL})); if (err) { err = LFS2_ERR_NAMETOOLONG; goto cleanup; @@ -2444,13 +2511,16 @@ int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, } else if (flags & LFS2_O_EXCL) { err = LFS2_ERR_EXIST; goto cleanup; +#endif } else if (lfs2_tag_type3(tag) != LFS2_TYPE_REG) { err = LFS2_ERR_ISDIR; goto cleanup; +#ifndef LFS2_READONLY } else if (flags & LFS2_O_TRUNC) { // truncate if requested tag = LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, file->id, 0); file->flags |= LFS2_F_DIRTY; +#endif } else { // try to load what's on disk, if it's inlined we'll fix it later tag = lfs2_dir_get(lfs2, &file->m, LFS2_MKTAG(0x700, 0x3ff, 0), @@ -2464,7 +2534,8 @@ int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, // fetch attrs for (unsigned i = 0; i < file->cfg->attr_count; i++) { - if ((file->flags & 3) != LFS2_O_WRONLY) { + // if opened for read / read-write operations + if ((file->flags & LFS2_O_RDONLY) == LFS2_O_RDONLY) { lfs2_stag_t res = lfs2_dir_get(lfs2, &file->m, LFS2_MKTAG(0x7ff, 0x3ff, 0), LFS2_MKTAG(LFS2_TYPE_USERATTR + file->cfg->attrs[i].type, @@ -2476,7 +2547,9 @@ int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, } } - if ((file->flags & 3) != LFS2_O_RDONLY) { +#ifndef LFS2_READONLY + // if opened for write / read-write operations + if ((file->flags & LFS2_O_WRONLY) == LFS2_O_WRONLY) { if (file->cfg->attrs[i].size > lfs2->attr_max) { err = LFS2_ERR_NOSPC; goto cleanup; @@ -2484,6 +2557,7 @@ int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, file->flags |= LFS2_F_DIRTY; } +#endif } // allocate buffer if needed @@ -2523,54 +2597,45 @@ int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, } } - LFS2_TRACE("lfs2_file_opencfg -> %d", 0); return 0; cleanup: // clean up lingering resources +#ifndef LFS2_READONLY file->flags |= LFS2_F_ERRED; - lfs2_file_close(lfs2, file); - LFS2_TRACE("lfs2_file_opencfg -> %d", err); +#endif + lfs2_file_rawclose(lfs2, file); return err; } -int lfs2_file_open(lfs2_t *lfs2, lfs2_file_t *file, +static int lfs2_file_rawopen(lfs2_t *lfs2, lfs2_file_t *file, const char *path, int flags) { - LFS2_TRACE("lfs2_file_open(%p, %p, \"%s\", %x)", - (void*)lfs2, (void*)file, path, flags); static const struct lfs2_file_config defaults = {0}; - int err = lfs2_file_opencfg(lfs2, file, path, flags, &defaults); - LFS2_TRACE("lfs2_file_open -> %d", err); + int err = lfs2_file_rawopencfg(lfs2, file, path, flags, &defaults); return err; } -int lfs2_file_close(lfs2_t *lfs2, lfs2_file_t *file) { - LFS2_TRACE("lfs2_file_close(%p, %p)", (void*)lfs2, (void*)file); - LFS2_ASSERT(file->flags & LFS2_F_OPENED); - - int err = lfs2_file_sync(lfs2, file); +static int lfs2_file_rawclose(lfs2_t *lfs2, lfs2_file_t *file) { +#ifndef LFS2_READONLY + int err = lfs2_file_rawsync(lfs2, file); +#else + int err = 0; +#endif // remove from list of mdirs - for (struct lfs2_mlist **p = &lfs2->mlist; *p; p = &(*p)->next) { - if (*p == (struct lfs2_mlist*)file) { - *p = (*p)->next; - break; - } - } + lfs2_mlist_remove(lfs2, (struct lfs2_mlist*)file); // clean up memory if (!file->cfg->buffer) { lfs2_free(file->cache.buffer); } - file->flags &= ~LFS2_F_OPENED; - LFS2_TRACE("lfs2_file_close -> %d", err); return err; } -static int lfs2_file_relocate(lfs2_t *lfs2, lfs2_file_t *file) { - LFS2_ASSERT(file->flags & LFS2_F_OPENED); +#ifndef LFS2_READONLY +static int lfs2_file_relocate(lfs2_t *lfs2, lfs2_file_t *file) { while (true) { // just relocate what exists into new block lfs2_block_t nblock; @@ -2638,7 +2703,9 @@ relocate: lfs2_cache_drop(lfs2, &lfs2->pcache); } } +#endif +#ifndef LFS2_READONLY static int lfs2_file_outline(lfs2_t *lfs2, lfs2_file_t *file) { file->off = file->pos; lfs2_alloc_ack(lfs2); @@ -2650,10 +2717,10 @@ static int lfs2_file_outline(lfs2_t *lfs2, lfs2_file_t *file) { file->flags &= ~LFS2_F_INLINE; return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file) { - LFS2_ASSERT(file->flags & LFS2_F_OPENED); - if (file->flags & LFS2_F_READING) { if (!(file->flags & LFS2_F_INLINE)) { lfs2_cache_drop(lfs2, &file->cache); @@ -2669,7 +2736,7 @@ static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file) { lfs2_file_t orig = { .ctz.head = file->ctz.head, .ctz.size = file->ctz.size, - .flags = LFS2_O_RDONLY | LFS2_F_OPENED, + .flags = LFS2_O_RDONLY, .pos = file->pos, .cache = lfs2->rcache, }; @@ -2679,12 +2746,12 @@ static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file) { // copy over a byte at a time, leave it up to caching // to make this efficient uint8_t data; - lfs2_ssize_t res = lfs2_file_read(lfs2, &orig, &data, 1); + lfs2_ssize_t res = lfs2_file_rawread(lfs2, &orig, &data, 1); if (res < 0) { return res; } - res = lfs2_file_write(lfs2, file, &data, 1); + res = lfs2_file_rawwrite(lfs2, file, &data, 1); if (res < 0) { return res; } @@ -2730,24 +2797,22 @@ relocate: return 0; } +#endif -int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file) { - LFS2_TRACE("lfs2_file_sync(%p, %p)", (void*)lfs2, (void*)file); - LFS2_ASSERT(file->flags & LFS2_F_OPENED); - +#ifndef LFS2_READONLY +static int lfs2_file_rawsync(lfs2_t *lfs2, lfs2_file_t *file) { if (file->flags & LFS2_F_ERRED) { // it's not safe to do anything if our file errored - LFS2_TRACE("lfs2_file_sync -> %d", 0); return 0; } int err = lfs2_file_flush(lfs2, file); if (err) { file->flags |= LFS2_F_ERRED; - LFS2_TRACE("lfs2_file_sync -> %d", err); return err; } + if ((file->flags & LFS2_F_DIRTY) && !lfs2_pair_isnull(file->m.pair)) { // update dir entry @@ -2777,39 +2842,35 @@ int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file) { file->cfg->attr_count), file->cfg->attrs})); if (err) { file->flags |= LFS2_F_ERRED; - LFS2_TRACE("lfs2_file_sync -> %d", err); return err; } file->flags &= ~LFS2_F_DIRTY; } - LFS2_TRACE("lfs2_file_sync -> %d", 0); return 0; } +#endif -lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_ssize_t lfs2_file_rawread(lfs2_t *lfs2, lfs2_file_t *file, void *buffer, lfs2_size_t size) { - LFS2_TRACE("lfs2_file_read(%p, %p, %p, %"PRIu32")", - (void*)lfs2, (void*)file, buffer, size); - LFS2_ASSERT(file->flags & LFS2_F_OPENED); - LFS2_ASSERT((file->flags & 3) != LFS2_O_WRONLY); + LFS2_ASSERT((file->flags & LFS2_O_RDONLY) == LFS2_O_RDONLY); uint8_t *data = buffer; lfs2_size_t nsize = size; +#ifndef LFS2_READONLY if (file->flags & LFS2_F_WRITING) { // flush out any writes int err = lfs2_file_flush(lfs2, file); if (err) { - LFS2_TRACE("lfs2_file_read -> %d", err); return err; } } +#endif if (file->pos >= file->ctz.size) { // eof if past end - LFS2_TRACE("lfs2_file_read -> %d", 0); return 0; } @@ -2825,7 +2886,6 @@ lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, file->ctz.head, file->ctz.size, file->pos, &file->block, &file->off); if (err) { - LFS2_TRACE("lfs2_file_read -> %d", err); return err; } } else { @@ -2845,7 +2905,6 @@ lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, file->id, 0), file->off, data, diff); if (err) { - LFS2_TRACE("lfs2_file_read -> %d", err); return err; } } else { @@ -2853,7 +2912,6 @@ lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, NULL, &file->cache, lfs2->cfg->block_size, file->block, file->off, data, diff); if (err) { - LFS2_TRACE("lfs2_file_read -> %d", err); return err; } } @@ -2864,16 +2922,13 @@ lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, nsize -= diff; } - LFS2_TRACE("lfs2_file_read -> %"PRId32, size); return size; } -lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, +#ifndef LFS2_READONLY +static lfs2_ssize_t lfs2_file_rawwrite(lfs2_t *lfs2, lfs2_file_t *file, const void *buffer, lfs2_size_t size) { - LFS2_TRACE("lfs2_file_write(%p, %p, %p, %"PRIu32")", - (void*)lfs2, (void*)file, buffer, size); - LFS2_ASSERT(file->flags & LFS2_F_OPENED); - LFS2_ASSERT((file->flags & 3) != LFS2_O_RDONLY); + LFS2_ASSERT((file->flags & LFS2_O_WRONLY) == LFS2_O_WRONLY); const uint8_t *data = buffer; lfs2_size_t nsize = size; @@ -2882,7 +2937,6 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, // drop any reads int err = lfs2_file_flush(lfs2, file); if (err) { - LFS2_TRACE("lfs2_file_write -> %d", err); return err; } } @@ -2893,7 +2947,6 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, if (file->pos + size > lfs2->file_max) { // Larger than file limit? - LFS2_TRACE("lfs2_file_write -> %d", LFS2_ERR_FBIG); return LFS2_ERR_FBIG; } @@ -2903,9 +2956,8 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, file->pos = file->ctz.size; while (file->pos < pos) { - lfs2_ssize_t res = lfs2_file_write(lfs2, file, &(uint8_t){0}, 1); + lfs2_ssize_t res = lfs2_file_rawwrite(lfs2, file, &(uint8_t){0}, 1); if (res < 0) { - LFS2_TRACE("lfs2_file_write -> %"PRId32, res); return res; } } @@ -2919,7 +2971,6 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, int err = lfs2_file_outline(lfs2, file); if (err) { file->flags |= LFS2_F_ERRED; - LFS2_TRACE("lfs2_file_write -> %d", err); return err; } } @@ -2936,7 +2987,6 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, file->pos-1, &file->block, &file->off); if (err) { file->flags |= LFS2_F_ERRED; - LFS2_TRACE("lfs2_file_write -> %d", err); return err; } @@ -2951,7 +3001,6 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, &file->block, &file->off); if (err) { file->flags |= LFS2_F_ERRED; - LFS2_TRACE("lfs2_file_write -> %d", err); return err; } } else { @@ -2972,7 +3021,6 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, goto relocate; } file->flags |= LFS2_F_ERRED; - LFS2_TRACE("lfs2_file_write -> %d", err); return err; } @@ -2981,7 +3029,6 @@ relocate: err = lfs2_file_relocate(lfs2, file); if (err) { file->flags |= LFS2_F_ERRED; - LFS2_TRACE("lfs2_file_write -> %d", err); return err; } } @@ -2995,22 +3042,19 @@ relocate: } file->flags &= ~LFS2_F_ERRED; - LFS2_TRACE("lfs2_file_write -> %"PRId32, size); return size; } +#endif -lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_soff_t lfs2_file_rawseek(lfs2_t *lfs2, lfs2_file_t *file, lfs2_soff_t off, int whence) { - LFS2_TRACE("lfs2_file_seek(%p, %p, %"PRId32", %d)", - (void*)lfs2, (void*)file, off, whence); - LFS2_ASSERT(file->flags & LFS2_F_OPENED); - +#ifndef LFS2_READONLY // write out everything beforehand, may be noop if rdonly int err = lfs2_file_flush(lfs2, file); if (err) { - LFS2_TRACE("lfs2_file_seek -> %d", err); return err; } +#endif // find new pos lfs2_off_t npos = file->pos; @@ -3024,34 +3068,28 @@ lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file, if (npos > lfs2->file_max) { // file position out of range - LFS2_TRACE("lfs2_file_seek -> %d", LFS2_ERR_INVAL); return LFS2_ERR_INVAL; } // update pos file->pos = npos; - LFS2_TRACE("lfs2_file_seek -> %"PRId32, npos); return npos; } -int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { - LFS2_TRACE("lfs2_file_truncate(%p, %p, %"PRIu32")", - (void*)lfs2, (void*)file, size); - LFS2_ASSERT(file->flags & LFS2_F_OPENED); - LFS2_ASSERT((file->flags & 3) != LFS2_O_RDONLY); +#ifndef LFS2_READONLY +static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { + LFS2_ASSERT((file->flags & LFS2_O_WRONLY) == LFS2_O_WRONLY); if (size > LFS2_FILE_MAX) { - LFS2_TRACE("lfs2_file_truncate -> %d", LFS2_ERR_INVAL); return LFS2_ERR_INVAL; } lfs2_off_t pos = file->pos; - lfs2_off_t oldsize = lfs2_file_size(lfs2, file); + lfs2_off_t oldsize = lfs2_file_rawsize(lfs2, file); if (size < oldsize) { // need to flush since directly changing metadata int err = lfs2_file_flush(lfs2, file); if (err) { - LFS2_TRACE("lfs2_file_truncate -> %d", err); return err; } @@ -3060,7 +3098,6 @@ int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { file->ctz.head, file->ctz.size, size, &file->block, &file->off); if (err) { - LFS2_TRACE("lfs2_file_truncate -> %d", err); return err; } @@ -3070,97 +3107,80 @@ int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { } else if (size > oldsize) { // flush+seek if not already at end if (file->pos != oldsize) { - lfs2_soff_t res = lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_END); + lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, 0, LFS2_SEEK_END); if (res < 0) { - LFS2_TRACE("lfs2_file_truncate -> %"PRId32, res); return (int)res; } } // fill with zeros while (file->pos < size) { - lfs2_ssize_t res = lfs2_file_write(lfs2, file, &(uint8_t){0}, 1); + lfs2_ssize_t res = lfs2_file_rawwrite(lfs2, file, &(uint8_t){0}, 1); if (res < 0) { - LFS2_TRACE("lfs2_file_truncate -> %"PRId32, res); return (int)res; } } } // restore pos - lfs2_soff_t res = lfs2_file_seek(lfs2, file, pos, LFS2_SEEK_SET); + lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, pos, LFS2_SEEK_SET); if (res < 0) { - LFS2_TRACE("lfs2_file_truncate -> %"PRId32, res); return (int)res; } - LFS2_TRACE("lfs2_file_truncate -> %d", 0); return 0; } +#endif -lfs2_soff_t lfs2_file_tell(lfs2_t *lfs2, lfs2_file_t *file) { - LFS2_TRACE("lfs2_file_tell(%p, %p)", (void*)lfs2, (void*)file); - LFS2_ASSERT(file->flags & LFS2_F_OPENED); +static lfs2_soff_t lfs2_file_rawtell(lfs2_t *lfs2, lfs2_file_t *file) { (void)lfs2; - LFS2_TRACE("lfs2_file_tell -> %"PRId32, file->pos); return file->pos; } -int lfs2_file_rewind(lfs2_t *lfs2, lfs2_file_t *file) { - LFS2_TRACE("lfs2_file_rewind(%p, %p)", (void*)lfs2, (void*)file); - lfs2_soff_t res = lfs2_file_seek(lfs2, file, 0, LFS2_SEEK_SET); +static int lfs2_file_rawrewind(lfs2_t *lfs2, lfs2_file_t *file) { + lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, 0, LFS2_SEEK_SET); if (res < 0) { - LFS2_TRACE("lfs2_file_rewind -> %"PRId32, res); return (int)res; } - LFS2_TRACE("lfs2_file_rewind -> %d", 0); return 0; } -lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file) { - LFS2_TRACE("lfs2_file_size(%p, %p)", (void*)lfs2, (void*)file); - LFS2_ASSERT(file->flags & LFS2_F_OPENED); +static lfs2_soff_t lfs2_file_rawsize(lfs2_t *lfs2, lfs2_file_t *file) { (void)lfs2; + +#ifndef LFS2_READONLY if (file->flags & LFS2_F_WRITING) { - LFS2_TRACE("lfs2_file_size -> %"PRId32, - lfs2_max(file->pos, file->ctz.size)); return lfs2_max(file->pos, file->ctz.size); - } else { - LFS2_TRACE("lfs2_file_size -> %"PRId32, file->ctz.size); - return file->ctz.size; } +#endif + + return file->ctz.size; } /// General fs operations /// -int lfs2_stat(lfs2_t *lfs2, const char *path, struct lfs2_info *info) { - LFS2_TRACE("lfs2_stat(%p, \"%s\", %p)", (void*)lfs2, path, (void*)info); +static int lfs2_rawstat(lfs2_t *lfs2, const char *path, struct lfs2_info *info) { lfs2_mdir_t cwd; lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); if (tag < 0) { - LFS2_TRACE("lfs2_stat -> %"PRId32, tag); return (int)tag; } - int err = lfs2_dir_getinfo(lfs2, &cwd, lfs2_tag_id(tag), info); - LFS2_TRACE("lfs2_stat -> %d", err); - return err; + return lfs2_dir_getinfo(lfs2, &cwd, lfs2_tag_id(tag), info); } -int lfs2_remove(lfs2_t *lfs2, const char *path) { - LFS2_TRACE("lfs2_remove(%p, \"%s\")", (void*)lfs2, path); +#ifndef LFS2_READONLY +static int lfs2_rawremove(lfs2_t *lfs2, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs2_fs_forceconsistency(lfs2); if (err) { - LFS2_TRACE("lfs2_remove -> %d", err); return err; } lfs2_mdir_t cwd; lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); if (tag < 0 || lfs2_tag_id(tag) == 0x3ff) { - LFS2_TRACE("lfs2_remove -> %"PRId32, (tag < 0) ? tag : LFS2_ERR_INVAL); return (tag < 0) ? (int)tag : LFS2_ERR_INVAL; } @@ -3172,19 +3192,16 @@ int lfs2_remove(lfs2_t *lfs2, const char *path) { lfs2_stag_t res = lfs2_dir_get(lfs2, &cwd, LFS2_MKTAG(0x700, 0x3ff, 0), LFS2_MKTAG(LFS2_TYPE_STRUCT, lfs2_tag_id(tag), 8), pair); if (res < 0) { - LFS2_TRACE("lfs2_remove -> %"PRId32, res); return (int)res; } lfs2_pair_fromle32(pair); err = lfs2_dir_fetch(lfs2, &dir.m, pair); if (err) { - LFS2_TRACE("lfs2_remove -> %d", err); return err; } if (dir.m.count > 0 || dir.m.split) { - LFS2_TRACE("lfs2_remove -> %d", LFS2_ERR_NOTEMPTY); return LFS2_ERR_NOTEMPTY; } @@ -3200,10 +3217,9 @@ int lfs2_remove(lfs2_t *lfs2, const char *path) { // delete the entry err = lfs2_dir_commit(lfs2, &cwd, LFS2_MKATTRS( - {LFS2_MKTAG(LFS2_TYPE_DELETE, lfs2_tag_id(tag), 0)})); + {LFS2_MKTAG(LFS2_TYPE_DELETE, lfs2_tag_id(tag), 0), NULL})); if (err) { lfs2->mlist = dir.next; - LFS2_TRACE("lfs2_remove -> %d", err); return err; } @@ -3214,28 +3230,24 @@ int lfs2_remove(lfs2_t *lfs2, const char *path) { err = lfs2_fs_pred(lfs2, dir.m.pair, &cwd); if (err) { - LFS2_TRACE("lfs2_remove -> %d", err); return err; } err = lfs2_dir_drop(lfs2, &cwd, &dir.m); if (err) { - LFS2_TRACE("lfs2_remove -> %d", err); return err; } } - LFS2_TRACE("lfs2_remove -> %d", 0); return 0; } +#endif -int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { - LFS2_TRACE("lfs2_rename(%p, \"%s\", \"%s\")", (void*)lfs2, oldpath, newpath); - +#ifndef LFS2_READONLY +static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs2_fs_forceconsistency(lfs2); if (err) { - LFS2_TRACE("lfs2_rename -> %d", err); return err; } @@ -3243,8 +3255,6 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { lfs2_mdir_t oldcwd; lfs2_stag_t oldtag = lfs2_dir_find(lfs2, &oldcwd, &oldpath, NULL); if (oldtag < 0 || lfs2_tag_id(oldtag) == 0x3ff) { - LFS2_TRACE("lfs2_rename -> %"PRId32, - (oldtag < 0) ? oldtag : LFS2_ERR_INVAL); return (oldtag < 0) ? (int)oldtag : LFS2_ERR_INVAL; } @@ -3254,8 +3264,6 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { lfs2_stag_t prevtag = lfs2_dir_find(lfs2, &newcwd, &newpath, &newid); if ((prevtag < 0 || lfs2_tag_id(prevtag) == 0x3ff) && !(prevtag == LFS2_ERR_NOENT && newid != 0x3ff)) { - LFS2_TRACE("lfs2_rename -> %"PRId32, - (prevtag < 0) ? prevtag : LFS2_ERR_INVAL); return (prevtag < 0) ? (int)prevtag : LFS2_ERR_INVAL; } @@ -3269,7 +3277,6 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { // check that name fits lfs2_size_t nlen = strlen(newpath); if (nlen > lfs2->name_max) { - LFS2_TRACE("lfs2_rename -> %d", LFS2_ERR_NAMETOOLONG); return LFS2_ERR_NAMETOOLONG; } @@ -3280,11 +3287,9 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { newoldid += 1; } } else if (lfs2_tag_type3(prevtag) != lfs2_tag_type3(oldtag)) { - LFS2_TRACE("lfs2_rename -> %d", LFS2_ERR_ISDIR); return LFS2_ERR_ISDIR; } else if (samepair && newid == newoldid) { // we're renaming to ourselves?? - LFS2_TRACE("lfs2_rename -> %d", 0); return 0; } else if (lfs2_tag_type3(prevtag) == LFS2_TYPE_DIR) { // must be empty before removal @@ -3292,7 +3297,6 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { lfs2_stag_t res = lfs2_dir_get(lfs2, &newcwd, LFS2_MKTAG(0x700, 0x3ff, 0), LFS2_MKTAG(LFS2_TYPE_STRUCT, newid, 8), prevpair); if (res < 0) { - LFS2_TRACE("lfs2_rename -> %"PRId32, res); return (int)res; } lfs2_pair_fromle32(prevpair); @@ -3300,12 +3304,10 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { // must be empty before removal err = lfs2_dir_fetch(lfs2, &prevdir.m, prevpair); if (err) { - LFS2_TRACE("lfs2_rename -> %d", err); return err; } if (prevdir.m.count > 0 || prevdir.m.split) { - LFS2_TRACE("lfs2_rename -> %d", LFS2_ERR_NOTEMPTY); return LFS2_ERR_NOTEMPTY; } @@ -3326,15 +3328,14 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { // move over all attributes err = lfs2_dir_commit(lfs2, &newcwd, LFS2_MKATTRS( {LFS2_MKTAG_IF(prevtag != LFS2_ERR_NOENT, - LFS2_TYPE_DELETE, newid, 0)}, - {LFS2_MKTAG(LFS2_TYPE_CREATE, newid, 0)}, + LFS2_TYPE_DELETE, newid, 0), NULL}, + {LFS2_MKTAG(LFS2_TYPE_CREATE, newid, 0), NULL}, {LFS2_MKTAG(lfs2_tag_type3(oldtag), newid, strlen(newpath)), newpath}, {LFS2_MKTAG(LFS2_FROM_MOVE, newid, lfs2_tag_id(oldtag)), &oldcwd}, {LFS2_MKTAG_IF(samepair, - LFS2_TYPE_DELETE, newoldid, 0)})); + LFS2_TYPE_DELETE, newoldid, 0), NULL})); if (err) { lfs2->mlist = prevdir.next; - LFS2_TRACE("lfs2_rename -> %d", err); return err; } @@ -3344,10 +3345,9 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { // prep gstate and delete move id lfs2_fs_prepmove(lfs2, 0x3ff, NULL); err = lfs2_dir_commit(lfs2, &oldcwd, LFS2_MKATTRS( - {LFS2_MKTAG(LFS2_TYPE_DELETE, lfs2_tag_id(oldtag), 0)})); + {LFS2_MKTAG(LFS2_TYPE_DELETE, lfs2_tag_id(oldtag), 0), NULL})); if (err) { lfs2->mlist = prevdir.next; - LFS2_TRACE("lfs2_rename -> %d", err); return err; } } @@ -3359,29 +3359,24 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { err = lfs2_fs_pred(lfs2, prevdir.m.pair, &newcwd); if (err) { - LFS2_TRACE("lfs2_rename -> %d", err); return err; } err = lfs2_dir_drop(lfs2, &newcwd, &prevdir.m); if (err) { - LFS2_TRACE("lfs2_rename -> %d", err); return err; } } - LFS2_TRACE("lfs2_rename -> %d", 0); return 0; } +#endif -lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, +static lfs2_ssize_t lfs2_rawgetattr(lfs2_t *lfs2, const char *path, uint8_t type, void *buffer, lfs2_size_t size) { - LFS2_TRACE("lfs2_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", - (void*)lfs2, path, type, buffer, size); lfs2_mdir_t cwd; lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); if (tag < 0) { - LFS2_TRACE("lfs2_getattr -> %"PRId32, tag); return tag; } @@ -3391,7 +3386,6 @@ lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, id = 0; int err = lfs2_dir_fetch(lfs2, &cwd, lfs2->root); if (err) { - LFS2_TRACE("lfs2_getattr -> %d", err); return err; } } @@ -3402,19 +3396,16 @@ lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, buffer); if (tag < 0) { if (tag == LFS2_ERR_NOENT) { - LFS2_TRACE("lfs2_getattr -> %d", LFS2_ERR_NOATTR); return LFS2_ERR_NOATTR; } - LFS2_TRACE("lfs2_getattr -> %"PRId32, tag); return tag; } - size = lfs2_tag_size(tag); - LFS2_TRACE("lfs2_getattr -> %"PRId32, size); - return size; + return lfs2_tag_size(tag); } +#ifndef LFS2_READONLY static int lfs2_commitattr(lfs2_t *lfs2, const char *path, uint8_t type, const void *buffer, lfs2_size_t size) { lfs2_mdir_t cwd; @@ -3436,27 +3427,24 @@ static int lfs2_commitattr(lfs2_t *lfs2, const char *path, return lfs2_dir_commit(lfs2, &cwd, LFS2_MKATTRS( {LFS2_MKTAG(LFS2_TYPE_USERATTR + type, id, size), buffer})); } +#endif -int lfs2_setattr(lfs2_t *lfs2, const char *path, +#ifndef LFS2_READONLY +static int lfs2_rawsetattr(lfs2_t *lfs2, const char *path, uint8_t type, const void *buffer, lfs2_size_t size) { - LFS2_TRACE("lfs2_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", - (void*)lfs2, path, type, buffer, size); if (size > lfs2->attr_max) { - LFS2_TRACE("lfs2_setattr -> %d", LFS2_ERR_NOSPC); return LFS2_ERR_NOSPC; } - int err = lfs2_commitattr(lfs2, path, type, buffer, size); - LFS2_TRACE("lfs2_setattr -> %d", err); - return err; + return lfs2_commitattr(lfs2, path, type, buffer, size); } +#endif -int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type) { - LFS2_TRACE("lfs2_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs2, path, type); - int err = lfs2_commitattr(lfs2, path, type, NULL, 0x3ff); - LFS2_TRACE("lfs2_removeattr -> %d", err); - return err; +#ifndef LFS2_READONLY +static int lfs2_rawremoveattr(lfs2_t *lfs2, const char *path, uint8_t type) { + return lfs2_commitattr(lfs2, path, type, NULL, 0x3ff); } +#endif /// Filesystem operations /// @@ -3584,28 +3572,12 @@ static int lfs2_deinit(lfs2_t *lfs2) { return 0; } -int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *cfg) { - LFS2_TRACE("lfs2_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*)lfs2, (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 LFS2_READONLY +static int lfs2_rawformat(lfs2_t *lfs2, const struct lfs2_config *cfg) { int err = 0; { err = lfs2_init(lfs2, cfg); if (err) { - LFS2_TRACE("lfs2_format -> %d", err); return err; } @@ -3636,7 +3608,7 @@ int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *cfg) { lfs2_superblock_tole32(&superblock); err = lfs2_dir_commit(lfs2, &root, LFS2_MKATTRS( - {LFS2_MKTAG(LFS2_TYPE_CREATE, 0, 0)}, + {LFS2_MKTAG(LFS2_TYPE_CREATE, 0, 0), NULL}, {LFS2_MKTAG(LFS2_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, {LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)), &superblock})); @@ -3661,30 +3633,14 @@ int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *cfg) { cleanup: lfs2_deinit(lfs2); - LFS2_TRACE("lfs2_format -> %d", err); return err; -} -int lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *cfg) { - LFS2_TRACE("lfs2_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*)lfs2, (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); +} +#endif + +static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { int err = lfs2_init(lfs2, cfg); if (err) { - LFS2_TRACE("lfs2_mount -> %d", err); return err; } @@ -3797,28 +3753,25 @@ int lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *cfg) { lfs2->gstate.tag += !lfs2_tag_isvalid(lfs2->gstate.tag); lfs2->gdisk = lfs2->gstate; - // setup free lookahead - lfs2_alloc_reset(lfs2); + // setup free lookahead, to distribute allocations uniformly across + // boots, we start the allocator at a random location + lfs2->free.off = lfs2->seed % lfs2->cfg->block_count; + lfs2_alloc_drop(lfs2); - LFS2_TRACE("lfs2_mount -> %d", 0); return 0; cleanup: - lfs2_unmount(lfs2); - LFS2_TRACE("lfs2_mount -> %d", err); + lfs2_rawunmount(lfs2); return err; } -int lfs2_unmount(lfs2_t *lfs2) { - LFS2_TRACE("lfs2_unmount(%p)", (void*)lfs2); - int err = lfs2_deinit(lfs2); - LFS2_TRACE("lfs2_unmount -> %d", err); - return err; +static int lfs2_rawunmount(lfs2_t *lfs2) { + return lfs2_deinit(lfs2); } /// Filesystem filesystem operations /// -int lfs2_fs_traverseraw(lfs2_t *lfs2, +int lfs2_fs_rawtraverse(lfs2_t *lfs2, int (*cb)(void *data, lfs2_block_t block), void *data, bool includeorphans) { // iterate over metadata pairs @@ -3888,6 +3841,7 @@ int lfs2_fs_traverseraw(lfs2_t *lfs2, } } +#ifndef LFS2_READONLY // iterate over any open files for (lfs2_file_t *f = (lfs2_file_t*)lfs2->mlist; f; f = f->next) { if (f->type != LFS2_TYPE_REG) { @@ -3910,19 +3864,12 @@ int lfs2_fs_traverseraw(lfs2_t *lfs2, } } } +#endif return 0; } -int lfs2_fs_traverse(lfs2_t *lfs2, - int (*cb)(void *data, lfs2_block_t block), void *data) { - LFS2_TRACE("lfs2_fs_traverse(%p, %p, %p)", - (void*)lfs2, (void*)(uintptr_t)cb, data); - int err = lfs2_fs_traverseraw(lfs2, cb, data, true); - LFS2_TRACE("lfs2_fs_traverse -> %d", 0); - return err; -} - +#ifndef LFS2_READONLY static int lfs2_fs_pred(lfs2_t *lfs2, const lfs2_block_t pair[2], lfs2_mdir_t *pdir) { // iterate over all directory directory entries @@ -3948,12 +3895,16 @@ static int lfs2_fs_pred(lfs2_t *lfs2, return LFS2_ERR_NOENT; } +#endif +#ifndef LFS2_READONLY struct lfs2_fs_parent_match { lfs2_t *lfs2; const lfs2_block_t pair[2]; }; +#endif +#ifndef LFS2_READONLY static int lfs2_fs_parent_match(void *data, lfs2_tag_t tag, const void *buffer) { struct lfs2_fs_parent_match *find = data; @@ -3972,7 +3923,9 @@ static int lfs2_fs_parent_match(void *data, lfs2_pair_fromle32(child); return (lfs2_pair_cmp(child, find->pair) == 0) ? LFS2_CMP_EQ : LFS2_CMP_LT; } +#endif +#ifndef LFS2_READONLY static lfs2_stag_t lfs2_fs_parent(lfs2_t *lfs2, const lfs2_block_t pair[2], lfs2_mdir_t *parent) { // use fetchmatch with callback to find pairs @@ -3999,7 +3952,9 @@ static lfs2_stag_t lfs2_fs_parent(lfs2_t *lfs2, const lfs2_block_t pair[2], return LFS2_ERR_NOENT; } +#endif +#ifndef LFS2_READONLY static int lfs2_fs_relocate(lfs2_t *lfs2, const lfs2_block_t oldpair[2], lfs2_block_t newpair[2]) { // update internal root @@ -4050,7 +4005,7 @@ static int lfs2_fs_relocate(lfs2_t *lfs2, lfs2_pair_tole32(newpair); int err = lfs2_dir_commit(lfs2, &parent, LFS2_MKATTRS( {LFS2_MKTAG_IF(moveid != 0x3ff, - LFS2_TYPE_DELETE, moveid, 0)}, + LFS2_TYPE_DELETE, moveid, 0), NULL}, {tag, newpair})); lfs2_pair_fromle32(newpair); if (err) { @@ -4084,7 +4039,7 @@ static int lfs2_fs_relocate(lfs2_t *lfs2, lfs2_pair_tole32(newpair); err = lfs2_dir_commit(lfs2, &parent, LFS2_MKATTRS( {LFS2_MKTAG_IF(moveid != 0x3ff, - LFS2_TYPE_DELETE, moveid, 0)}, + LFS2_TYPE_DELETE, moveid, 0), NULL}, {LFS2_MKTAG(LFS2_TYPE_TAIL + parent.split, 0x3ff, 8), newpair})); lfs2_pair_fromle32(newpair); if (err) { @@ -4094,14 +4049,18 @@ static int lfs2_fs_relocate(lfs2_t *lfs2, return 0; } +#endif +#ifndef LFS2_READONLY static void lfs2_fs_preporphans(lfs2_t *lfs2, int8_t orphans) { LFS2_ASSERT(lfs2_tag_size(lfs2->gstate.tag) > 0 || orphans >= 0); lfs2->gstate.tag += orphans; lfs2->gstate.tag = ((lfs2->gstate.tag & ~LFS2_MKTAG(0x800, 0, 0)) | ((uint32_t)lfs2_gstate_hasorphans(&lfs2->gstate) << 31)); } +#endif +#ifndef LFS2_READONLY static void lfs2_fs_prepmove(lfs2_t *lfs2, uint16_t id, const lfs2_block_t pair[2]) { lfs2->gstate.tag = ((lfs2->gstate.tag & ~LFS2_MKTAG(0x7ff, 0x3ff, 0)) | @@ -4109,7 +4068,9 @@ static void lfs2_fs_prepmove(lfs2_t *lfs2, lfs2->gstate.pair[0] = (id != 0x3ff) ? pair[0] : 0; lfs2->gstate.pair[1] = (id != 0x3ff) ? pair[1] : 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_fs_demove(lfs2_t *lfs2) { if (!lfs2_gstate_hasmove(&lfs2->gdisk)) { return 0; @@ -4132,14 +4093,16 @@ static int lfs2_fs_demove(lfs2_t *lfs2) { uint16_t moveid = lfs2_tag_id(lfs2->gdisk.tag); lfs2_fs_prepmove(lfs2, 0x3ff, NULL); err = lfs2_dir_commit(lfs2, &movedir, LFS2_MKATTRS( - {LFS2_MKTAG(LFS2_TYPE_DELETE, moveid, 0)})); + {LFS2_MKTAG(LFS2_TYPE_DELETE, moveid, 0), NULL})); if (err) { return err; } return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_fs_deorphan(lfs2_t *lfs2) { if (!lfs2_gstate_hasorphans(&lfs2->gstate)) { return 0; @@ -4213,7 +4176,9 @@ static int lfs2_fs_deorphan(lfs2_t *lfs2) { lfs2_fs_preporphans(lfs2, -lfs2_gstate_getorphans(&lfs2->gstate)); return 0; } +#endif +#ifndef LFS2_READONLY static int lfs2_fs_forceconsistency(lfs2_t *lfs2) { int err = lfs2_fs_demove(lfs2); if (err) { @@ -4227,6 +4192,7 @@ static int lfs2_fs_forceconsistency(lfs2_t *lfs2) { return 0; } +#endif static int lfs2_fs_size_count(void *p, lfs2_block_t block) { (void)block; @@ -4235,16 +4201,13 @@ static int lfs2_fs_size_count(void *p, lfs2_block_t block) { return 0; } -lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2) { - LFS2_TRACE("lfs2_fs_size(%p)", (void*)lfs2); +static lfs2_ssize_t lfs2_fs_rawsize(lfs2_t *lfs2) { lfs2_size_t size = 0; - int err = lfs2_fs_traverseraw(lfs2, lfs2_fs_size_count, &size, false); + int err = lfs2_fs_rawtraverse(lfs2, lfs2_fs_size_count, &size, false); if (err) { - LFS2_TRACE("lfs2_fs_size -> %d", err); return err; } - LFS2_TRACE("lfs2_fs_size -> %d", err); return size; } @@ -4669,27 +4632,10 @@ static int lfs21_unmount(lfs2_t *lfs2) { } /// v1 migration /// -int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { - LFS2_TRACE("lfs2_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*)lfs2, (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 lfs2_rawmigrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { struct lfs21 lfs21; int err = lfs21_mount(lfs2, &lfs21, cfg); if (err) { - LFS2_TRACE("lfs2_migrate -> %d", err); return err; } @@ -4906,8 +4852,539 @@ int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { cleanup: lfs21_unmount(lfs2); - LFS2_TRACE("lfs2_migrate -> %d", err); return err; } #endif + + +/// Public API wrappers /// + +// Here we can add tracing/thread safety easily + +// Thread-safe wrappers if enabled +#ifdef LFS2_THREADSAFE +#define LFS2_LOCK(cfg) cfg->lock(cfg) +#define LFS2_UNLOCK(cfg) cfg->unlock(cfg) +#else +#define LFS2_LOCK(cfg) ((void)cfg, 0) +#define LFS2_UNLOCK(cfg) ((void)cfg) +#endif + +// Public API +#ifndef LFS2_READONLY +int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *cfg) { + int err = LFS2_LOCK(cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_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*)lfs2, (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 = lfs2_rawformat(lfs2, cfg); + + LFS2_TRACE("lfs2_format -> %d", err); + LFS2_UNLOCK(cfg); + return err; +} +#endif + +int lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *cfg) { + int err = LFS2_LOCK(cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_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*)lfs2, (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 = lfs2_rawmount(lfs2, cfg); + + LFS2_TRACE("lfs2_mount -> %d", err); + LFS2_UNLOCK(cfg); + return err; +} + +int lfs2_unmount(lfs2_t *lfs2) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_unmount(%p)", (void*)lfs2); + + err = lfs2_rawunmount(lfs2); + + LFS2_TRACE("lfs2_unmount -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +#ifndef LFS2_READONLY +int lfs2_remove(lfs2_t *lfs2, const char *path) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_remove(%p, \"%s\")", (void*)lfs2, path); + + err = lfs2_rawremove(lfs2, path); + + LFS2_TRACE("lfs2_remove -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} +#endif + +#ifndef LFS2_READONLY +int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_rename(%p, \"%s\", \"%s\")", (void*)lfs2, oldpath, newpath); + + err = lfs2_rawrename(lfs2, oldpath, newpath); + + LFS2_TRACE("lfs2_rename -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} +#endif + +int lfs2_stat(lfs2_t *lfs2, const char *path, struct lfs2_info *info) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_stat(%p, \"%s\", %p)", (void*)lfs2, path, (void*)info); + + err = lfs2_rawstat(lfs2, path, info); + + LFS2_TRACE("lfs2_stat -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, + uint8_t type, void *buffer, lfs2_size_t size) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", + (void*)lfs2, path, type, buffer, size); + + lfs2_ssize_t res = lfs2_rawgetattr(lfs2, path, type, buffer, size); + + LFS2_TRACE("lfs2_getattr -> %"PRId32, res); + LFS2_UNLOCK(lfs2->cfg); + return res; +} + +#ifndef LFS2_READONLY +int lfs2_setattr(lfs2_t *lfs2, const char *path, + uint8_t type, const void *buffer, lfs2_size_t size) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", + (void*)lfs2, path, type, buffer, size); + + err = lfs2_rawsetattr(lfs2, path, type, buffer, size); + + LFS2_TRACE("lfs2_setattr -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} +#endif + +#ifndef LFS2_READONLY +int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs2, path, type); + + err = lfs2_rawremoveattr(lfs2, path, type); + + LFS2_TRACE("lfs2_removeattr -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} +#endif + +int lfs2_file_open(lfs2_t *lfs2, lfs2_file_t *file, const char *path, int flags) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_open(%p, %p, \"%s\", %x)", + (void*)lfs2, (void*)file, path, flags); + LFS2_ASSERT(!lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); + + err = lfs2_file_rawopen(lfs2, file, path, flags); + + LFS2_TRACE("lfs2_file_open -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, + const char *path, int flags, + const struct lfs2_file_config *cfg) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_opencfg(%p, %p, \"%s\", %x, %p {" + ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", + (void*)lfs2, (void*)file, path, flags, + (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); + LFS2_ASSERT(!lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); + + err = lfs2_file_rawopencfg(lfs2, file, path, flags, cfg); + + LFS2_TRACE("lfs2_file_opencfg -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +int lfs2_file_close(lfs2_t *lfs2, lfs2_file_t *file) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_close(%p, %p)", (void*)lfs2, (void*)file); + LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); + + err = lfs2_file_rawclose(lfs2, file); + + LFS2_TRACE("lfs2_file_close -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +#ifndef LFS2_READONLY +int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_sync(%p, %p)", (void*)lfs2, (void*)file); + LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); + + err = lfs2_file_rawsync(lfs2, file); + + LFS2_TRACE("lfs2_file_sync -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} +#endif + +lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, + void *buffer, lfs2_size_t size) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_read(%p, %p, %p, %"PRIu32")", + (void*)lfs2, (void*)file, buffer, size); + LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); + + lfs2_ssize_t res = lfs2_file_rawread(lfs2, file, buffer, size); + + LFS2_TRACE("lfs2_file_read -> %"PRId32, res); + LFS2_UNLOCK(lfs2->cfg); + return res; +} + +#ifndef LFS2_READONLY +lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, + const void *buffer, lfs2_size_t size) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_write(%p, %p, %p, %"PRIu32")", + (void*)lfs2, (void*)file, buffer, size); + LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); + + lfs2_ssize_t res = lfs2_file_rawwrite(lfs2, file, buffer, size); + + LFS2_TRACE("lfs2_file_write -> %"PRId32, res); + LFS2_UNLOCK(lfs2->cfg); + return res; +} +#endif + +lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file, + lfs2_soff_t off, int whence) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_seek(%p, %p, %"PRId32", %d)", + (void*)lfs2, (void*)file, off, whence); + LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); + + lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, off, whence); + + LFS2_TRACE("lfs2_file_seek -> %"PRId32, res); + LFS2_UNLOCK(lfs2->cfg); + return res; +} + +#ifndef LFS2_READONLY +int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_truncate(%p, %p, %"PRIu32")", + (void*)lfs2, (void*)file, size); + LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); + + err = lfs2_file_rawtruncate(lfs2, file, size); + + LFS2_TRACE("lfs2_file_truncate -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} +#endif + +lfs2_soff_t lfs2_file_tell(lfs2_t *lfs2, lfs2_file_t *file) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_tell(%p, %p)", (void*)lfs2, (void*)file); + LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); + + lfs2_soff_t res = lfs2_file_rawtell(lfs2, file); + + LFS2_TRACE("lfs2_file_tell -> %"PRId32, res); + LFS2_UNLOCK(lfs2->cfg); + return res; +} + +int lfs2_file_rewind(lfs2_t *lfs2, lfs2_file_t *file) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_rewind(%p, %p)", (void*)lfs2, (void*)file); + + err = lfs2_file_rawrewind(lfs2, file); + + LFS2_TRACE("lfs2_file_rewind -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_file_size(%p, %p)", (void*)lfs2, (void*)file); + LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); + + lfs2_soff_t res = lfs2_file_rawsize(lfs2, file); + + LFS2_TRACE("lfs2_file_size -> %"PRId32, res); + LFS2_UNLOCK(lfs2->cfg); + return res; +} + +#ifndef LFS2_READONLY +int lfs2_mkdir(lfs2_t *lfs2, const char *path) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_mkdir(%p, \"%s\")", (void*)lfs2, path); + + err = lfs2_rawmkdir(lfs2, path); + + LFS2_TRACE("lfs2_mkdir -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} +#endif + +int lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_dir_open(%p, %p, \"%s\")", (void*)lfs2, (void*)dir, path); + LFS2_ASSERT(!lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)dir)); + + err = lfs2_dir_rawopen(lfs2, dir, path); + + LFS2_TRACE("lfs2_dir_open -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +int lfs2_dir_close(lfs2_t *lfs2, lfs2_dir_t *dir) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_dir_close(%p, %p)", (void*)lfs2, (void*)dir); + + err = lfs2_dir_rawclose(lfs2, dir); + + LFS2_TRACE("lfs2_dir_close -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_dir_read(%p, %p, %p)", + (void*)lfs2, (void*)dir, (void*)info); + + err = lfs2_dir_rawread(lfs2, dir, info); + + LFS2_TRACE("lfs2_dir_read -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +int lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_dir_seek(%p, %p, %"PRIu32")", + (void*)lfs2, (void*)dir, off); + + err = lfs2_dir_rawseek(lfs2, dir, off); + + LFS2_TRACE("lfs2_dir_seek -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +lfs2_soff_t lfs2_dir_tell(lfs2_t *lfs2, lfs2_dir_t *dir) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_dir_tell(%p, %p)", (void*)lfs2, (void*)dir); + + lfs2_soff_t res = lfs2_dir_rawtell(lfs2, dir); + + LFS2_TRACE("lfs2_dir_tell -> %"PRId32, res); + LFS2_UNLOCK(lfs2->cfg); + return res; +} + +int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_dir_rewind(%p, %p)", (void*)lfs2, (void*)dir); + + err = lfs2_dir_rawrewind(lfs2, dir); + + LFS2_TRACE("lfs2_dir_rewind -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_fs_size(%p)", (void*)lfs2); + + lfs2_ssize_t res = lfs2_fs_rawsize(lfs2); + + LFS2_TRACE("lfs2_fs_size -> %"PRId32, res); + LFS2_UNLOCK(lfs2->cfg); + return res; +} + +int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void *, lfs2_block_t), void *data) { + int err = LFS2_LOCK(lfs2->cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_fs_traverse(%p, %p, %p)", + (void*)lfs2, (void*)(uintptr_t)cb, data); + + err = lfs2_fs_rawtraverse(lfs2, cb, data, true); + + LFS2_TRACE("lfs2_fs_traverse -> %d", err); + LFS2_UNLOCK(lfs2->cfg); + return err; +} + +#ifdef LFS2_MIGRATE +int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { + int err = LFS2_LOCK(cfg); + if (err) { + return err; + } + LFS2_TRACE("lfs2_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*)lfs2, (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 = lfs2_rawmigrate(lfs2, cfg); + + LFS2_TRACE("lfs2_migrate -> %d", err); + LFS2_UNLOCK(cfg); + return err; +} +#endif + diff --git a/lib/littlefs/lfs2.h b/lib/littlefs/lfs2.h index c89af79cab..e2afc7792c 100644 --- a/lib/littlefs/lfs2.h +++ b/lib/littlefs/lfs2.h @@ -9,6 +9,7 @@ #include #include +#include "lfs2_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 LFS2_VERSION 0x00020002 +#define LFS2_VERSION 0x00020003 #define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16)) #define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0)) @@ -123,20 +124,25 @@ enum lfs2_type { enum lfs2_open_flags { // open flags LFS2_O_RDONLY = 1, // Open a file as read only +#ifndef LFS2_READONLY LFS2_O_WRONLY = 2, // Open a file as write only LFS2_O_RDWR = 3, // Open a file as read and write LFS2_O_CREAT = 0x0100, // Create a file if it does not exist LFS2_O_EXCL = 0x0200, // Fail if a file already exists LFS2_O_TRUNC = 0x0400, // Truncate the existing file to zero size LFS2_O_APPEND = 0x0800, // Move to end of file on every write +#endif // internally used flags +#ifndef LFS2_READONLY LFS2_F_DIRTY = 0x010000, // File does not match storage LFS2_F_WRITING = 0x020000, // File has been written since last flush +#endif LFS2_F_READING = 0x040000, // File has been read since last flush - LFS2_F_ERRED = 0x080000, // An error occured during write +#ifndef LFS2_READONLY + LFS2_F_ERRED = 0x080000, // An error occurred during write +#endif LFS2_F_INLINE = 0x100000, // Currently inlined in directory entry - LFS2_F_OPENED = 0x200000, // File has been opened }; // File seek flags @@ -174,6 +180,16 @@ struct lfs2_config { // are propogated to the user. int (*sync)(const struct lfs2_config *c); +#ifdef LFS2_THREADSAFE + // Lock the underlying block device. Negative error codes + // are propogated to the user. + int (*lock)(const struct lfs2_config *c); + + // Unlock the underlying block device. Negative error codes + // are propogated to the user. + int (*unlock)(const struct lfs2_config *c); +#endif + // Minimum size of a block read. All read operations will be a // multiple of this value. lfs2_size_t read_size; @@ -399,6 +415,7 @@ typedef struct lfs2 { /// Filesystem functions /// +#ifndef LFS2_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 lfs2 { // // Returns a negative error code on failure. int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *config); +#endif // Mounts a littlefs // @@ -426,12 +444,15 @@ int lfs2_unmount(lfs2_t *lfs2); /// General operations /// +#ifndef LFS2_READONLY // Removes a file or directory // // If removing a directory, the directory must be empty. // Returns a negative error code on failure. int lfs2_remove(lfs2_t *lfs2, const char *path); +#endif +#ifndef LFS2_READONLY // Rename or move a file or directory // // If the destination exists, it must match the source in type. @@ -439,6 +460,7 @@ int lfs2_remove(lfs2_t *lfs2, const char *path); // // Returns a negative error code on failure. int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath); +#endif // Find info about a file or directory // @@ -461,6 +483,7 @@ int lfs2_stat(lfs2_t *lfs2, const char *path, struct lfs2_info *info); lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, uint8_t type, void *buffer, lfs2_size_t size); +#ifndef LFS2_READONLY // Set custom attributes // // Custom attributes are uniquely identified by an 8-bit type and limited @@ -470,13 +493,16 @@ lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, // Returns a negative error code on failure. int lfs2_setattr(lfs2_t *lfs2, const char *path, uint8_t type, const void *buffer, lfs2_size_t size); +#endif +#ifndef LFS2_READONLY // Removes a custom attribute // // If an attribute is not found, nothing happens. // // Returns a negative error code on failure. int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type); +#endif /// File operations /// @@ -525,6 +551,7 @@ int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file); lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, void *buffer, lfs2_size_t size); +#ifndef LFS2_READONLY // Write data to file // // Takes a buffer and size indicating the data to write. The file will not @@ -533,6 +560,7 @@ lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, // Returns the number of bytes written, or a negative error code on failure. lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, const void *buffer, lfs2_size_t size); +#endif // Change the position of the file // @@ -541,10 +569,12 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file, lfs2_soff_t off, int whence); +#ifndef LFS2_READONLY // Truncates the size of the file to the specified size // // Returns a negative error code on failure. int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size); +#endif // Return the position of the file // @@ -567,10 +597,12 @@ lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file); /// Directory operations /// +#ifndef LFS2_READONLY // Create a directory // // Returns a negative error code on failure. int lfs2_mkdir(lfs2_t *lfs2, const char *path); +#endif // Open a directory // @@ -632,6 +664,7 @@ lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2); // Returns a negative error code on failure. int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data); +#ifndef LFS2_READONLY #ifdef LFS2_MIGRATE // Attempts to migrate a previous version of littlefs // @@ -646,6 +679,7 @@ int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data); // Returns a negative error code on failure. int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg); #endif +#endif #ifdef __cplusplus