diff --git a/lfs.c b/lfs.c index 8f5f3a32..fe52b2b4 100644 --- a/lfs.c +++ b/lfs.c @@ -9,18 +9,6 @@ #include "lfs_util.h" -//// TODO do we still need these? -//// some constants used throughout the code -//#define LFS_BLOCK_NULL ((lfs_block_t)-1) -//#define LFS_BLOCK_INLINE ((lfs_block_t)-2) - -// TODO do we still need these? -enum { - LFS_OK_RELOCATED = 1, - LFS_OK_DROPPED = 2, - LFS_OK_ORPHANED = 3, -}; - // internally used disk-comparison enum // // note LT < EQ < GT @@ -700,7 +688,6 @@ static int lfsr_bd_set(lfs_t *lfs, lfs_block_t block, lfs_size_t off, } - // lfsr_ptail_t stuff // // ptail tracks the most recent trunk's parity so we can parity-check @@ -994,99 +981,6 @@ static int lfsr_bd_cpyck(lfs_t *lfs, - -/// Small type-level utilities /// - -//// operations on block pairs -//static inline void lfs_pair_swap(lfs_block_t pair[2]) { -// lfs_block_t t = pair[0]; -// pair[0] = pair[1]; -// pair[1] = t; -//} -// -//static inline bool lfs_pair_isnull(const lfs_block_t pair[2]) { -// return pair[0] == LFS_BLOCK_NULL || pair[1] == LFS_BLOCK_NULL; -//} -// -//static inline int lfs_pair_cmp( -// const lfs_block_t paira[2], -// const lfs_block_t pairb[2]) { -// return !(paira[0] == pairb[0] || paira[1] == pairb[1] || -// paira[0] == pairb[1] || paira[1] == pairb[0]); -//} -// -//static inline bool lfs_pair_issync( -// const lfs_block_t paira[2], -// const lfs_block_t pairb[2]) { -// return (paira[0] == pairb[0] && paira[1] == pairb[1]) || -// (paira[0] == pairb[1] && paira[1] == pairb[0]); -//} -// -//static inline void lfs_pair_fromle32(lfs_block_t pair[2]) { -// pair[0] = lfs_fromle32(pair[0]); -// pair[1] = lfs_fromle32(pair[1]); -//} -// -//#ifndef LFS_READONLY -//static inline void lfs_pair_tole32(lfs_block_t pair[2]) { -// pair[0] = lfs_tole32(pair[0]); -// pair[1] = lfs_tole32(pair[1]); -//} -//#endif -// -//// operations on 32-bit entry tags -//typedef uint32_t lfs_tag_t; -//typedef int32_t lfs_stag_t; -// -//#define LFS_MKTAG(type, id, size) -// (((lfs_tag_t)(type) << 20) | ((lfs_tag_t)(id) << 10) | (lfs_tag_t)(size)) -// -//#define LFS_MKTAG_IF(cond, type, id, size) -// ((cond) ? LFS_MKTAG(type, id, size) : LFS_MKTAG(LFS_FROM_NOOP, 0, 0)) -// -//#define LFS_MKTAG_IF_ELSE(cond, type1, id1, size1, type2, id2, size2) -// ((cond) ? LFS_MKTAG(type1, id1, size1) : LFS_MKTAG(type2, id2, size2)) -// -//static inline bool lfs_tag_isvalid(lfs_tag_t tag) { -// return !(tag & 0x80000000); -//} -// -//static inline bool lfs_tag_isdelete(lfs_tag_t tag) { -// return ((int32_t)(tag << 22) >> 22) == -1; -//} -// -//static inline uint16_t lfs_tag_type1(lfs_tag_t tag) { -// return (tag & 0x70000000) >> 20; -//} -// -//static inline uint16_t lfs_tag_type2(lfs_tag_t tag) { -// return (tag & 0x78000000) >> 20; -//} -// -//static inline uint16_t lfs_tag_type3(lfs_tag_t tag) { -// return (tag & 0x7ff00000) >> 20; -//} -// -//static inline uint8_t lfs_tag_chunk(lfs_tag_t tag) { -// return (tag & 0x0ff00000) >> 20; -//} -// -//static inline int8_t lfs_tag_splice(lfs_tag_t tag) { -// return (int8_t)lfs_tag_chunk(tag); -//} -// -//static inline uint16_t lfs_tag_id(lfs_tag_t tag) { -// return (tag & 0x000ffc00) >> 10; -//} -// -//static inline lfs_size_t lfs_tag_size(lfs_tag_t tag) { -// return tag & 0x000003ff; -//} -// -//static inline lfs_size_t lfs_tag_dsize(lfs_tag_t tag) { -// return sizeof(tag) + lfs_tag_size(tag + lfs_tag_isdelete(tag)); -//} - /// lfsr_tag_t stuff /// // 16-bit metadata tags @@ -2377,7 +2271,6 @@ static inline lfs_size_t lfsr_rattr_dsize(lfsr_rattr_t rattr) { } - // operations on custom attribute lists // // a slightly different struct because it's user facing @@ -2412,117 +2305,7 @@ static lfs_scmp_t lfsr_attr_cmp(lfs_t *lfs, const struct lfs_attr *attr, } - -//struct lfsr_attr_from { -// const lfsr_rbyd_t *rbyd; -// const struct lfsr_attr *attrs; -// lfs_size_t start; -//}; -// -//#define LFSR_ATTR_FROM(_id, _rbyd, _attrs, _start, _stop, _next) -// LFSR_ATTR(FROM, _id, -// (&(const struct lfsr_attr_from){_rbyd, _attrs, _start}), -// (_stop)-(_start), _next) -// -//#define LFS_MKRATTR_(...) -// (&(const struct lfsr_attr){__VA_ARGS__}) -// -//#define LFS_MKRATTR(type1, type2, id, buffer, size, next) -// (&(const struct lfsr_attr){ -// LFS_MKRTAG(type1, type2, id), -// buffer, size, next}) -// -//#define LFS_MKRRMATTR(type1, type2, id, next) -// (&(const struct lfsr_attr){ -// LFS_MKRRMTAG(type1, type2, id), -// NULL, 0, next}) - - - -//// find state when looking up by name -//typedef struct lfsr_find { -// // what to search for -// const char *name; -// lfs_size_t name_size; -// -// // if found, the tag/id will be placed in found_tag/found_id, -// // otherwise found_tag will be zero and found_id will be set to -// // the largest, smaller id (a good place to insert) -// lfs_ssize_t predicted_id; -// lfs_ssize_t found_id; -// lfsr_tag_t predicted_tag; -// lfsr_tag_t found_tag; -//} lfsr_find_t; - - - -//// operations on global state -//static inline void lfs_gstate_xor(lfs_gstate_t *a, const lfs_gstate_t *b) { -// for (int i = 0; i < 3; i++) { -// ((uint32_t*)a)[i] ^= ((const uint32_t*)b)[i]; -// } -//} -// -//static inline bool lfs_gstate_iszero(const lfs_gstate_t *a) { -// for (int i = 0; i < 3; i++) { -// if (((uint32_t*)a)[i] != 0) { -// return false; -// } -// } -// return true; -//} -// -//#ifndef LFS_READONLY -//static inline bool lfs_gstate_hasorphans(const lfs_gstate_t *a) { -// return lfs_tag_size(a->tag); -//} -// -//static inline uint8_t lfs_gstate_getorphans(const lfs_gstate_t *a) { -// return lfs_tag_size(a->tag); -//} -// -//static inline bool lfs_gstate_hasmove(const lfs_gstate_t *a) { -// return lfs_tag_type1(a->tag); -//} -//#endif -// -//static inline bool lfs_gstate_hasmovehere(const lfs_gstate_t *a, -// const lfs_block_t *pair) { -// return lfs_tag_type1(a->tag) && lfs_pair_cmp(a->pair, pair) == 0; -//} -// -//static inline void lfs_gstate_fromle32(lfs_gstate_t *a) { -// a->tag = lfs_fromle32(a->tag); -// a->pair[0] = lfs_fromle32(a->pair[0]); -// a->pair[1] = lfs_fromle32(a->pair[1]); -//} -// -//#ifndef LFS_READONLY -//static inline void lfs_gstate_tole32(lfs_gstate_t *a) { -// a->tag = lfs_tole32(a->tag); -// a->pair[0] = lfs_tole32(a->pair[0]); -// a->pair[1] = lfs_tole32(a->pair[1]); -//} -//#endif -// -//// operations on forward-CRCs used to track erased state -//struct lfs_fcrc { -// lfs_size_t size; -// uint32_t crc; -//}; -// -//static void lfs_fcrc_fromle32(struct lfs_fcrc *fcrc) { -// fcrc->size = lfs_fromle32(fcrc->size); -// fcrc->crc = lfs_fromle32(fcrc->crc); -//} -// -//#ifndef LFS_READONLY -//static void lfs_fcrc_tole32(struct lfs_fcrc *fcrc) { -// fcrc->size = lfs_tole32(fcrc->size); -// fcrc->crc = lfs_tole32(fcrc->crc); -//} -//#endif - +// operations on erased-state checksums // erased-state checksum typedef struct lfsr_ecksum { @@ -2568,6 +2351,7 @@ static int lfsr_data_readecksum(lfs_t *lfs, lfsr_data_t *data, } + /// block pointer things /// #define LFSR_BPTR_ONDISK LFSR_DATA_ONDISK @@ -2762,115 +2546,6 @@ static int lfsr_bptr_ck(lfs_t *lfs, const lfsr_bptr_t *bptr) { -//// other endianness operations -//static void lfs_ctz_fromle32(struct lfs_ctz *ctz) { -// ctz->head = lfs_fromle32(ctz->head); -// 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); -// superblock->block_size = lfs_fromle32(superblock->block_size); -// superblock->block_count = lfs_fromle32(superblock->block_count); -// superblock->name_max = lfs_fromle32(superblock->name_max); -// superblock->file_max = lfs_fromle32(superblock->file_max); -// superblock->attr_max = lfs_fromle32(superblock->attr_max); -//} -// -//#ifndef LFS_READONLY -//static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { -// superblock->version = lfs_tole32(superblock->version); -// superblock->block_size = lfs_tole32(superblock->block_size); -// superblock->block_count = lfs_tole32(superblock->block_count); -// superblock->name_max = lfs_tole32(superblock->name_max); -// superblock->file_max = lfs_tole32(superblock->file_max); -// superblock->attr_max = lfs_tole32(superblock->attr_max); -//} -//#endif -// -//#ifndef LFS_NO_ASSERT -//static 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; -//} -//#endif -// -//static 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 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_flushedwrite(lfs_t *lfs, lfs_file_t *file, -// const void *buffer, lfs_size_t size); -//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 int lfs_fs_deorphan(lfs_t *lfs, bool powerloss); -//static int 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]); -//static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t dir[2], -// lfs_mdir_t *pdir); -//static lfs_stag_t lfs_fs_parent(lfs_t *lfs, const lfs_block_t dir[2], -// lfs_mdir_t *parent); -//static int lfs_fs_forceconsistency(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_flushedread(lfs_t *lfs, lfs_file_t *file, -// void *buffer, lfs_size_t size); -//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); - /// Red-black-yellow Dhara tree operations /// @@ -5129,6 +4804,7 @@ static lfs_scmp_t lfsr_rbyd_namelookup(lfs_t *lfs, const lfsr_rbyd_t *rbyd, + /// B-tree operations /// // create an empty btree @@ -6433,6 +6109,7 @@ static int lfsr_btree_traverse(lfs_t *lfs, const lfsr_btree_t *btree, + /// B-shrub operations /// // shrub things @@ -6948,6 +6625,7 @@ static int lfsr_data_readmptr(lfs_t *lfs, lfsr_data_t *data, } + /// various flag things /// // open flags @@ -7463,6 +7141,7 @@ static int lfsr_fs_consumegdelta(lfs_t *lfs, const lfsr_mdir_t *mdir) { } + /// Revision count things /// // in mdirs, our revision count is broken down into three parts: @@ -11108,6 +10787,7 @@ int lfsr_dir_rewind(lfs_t *lfs, lfsr_dir_t *dir) { + /// Custom attribute stuff /// static int lfsr_lookupattr(lfs_t *lfs, const char *path, uint8_t type, @@ -13770,7 +13450,6 @@ int lfsr_file_ckdata(lfs_t *lfs, lfsr_file_t *file) { - /// High-level filesystem operations /// // needed in lfs_init @@ -13818,18 +13497,6 @@ static int lfs_init(lfs_t *lfs, uint32_t flags, // block_size is currently limited to 28-bits LFS_ASSERT(lfs->cfg->block_size <= 0x0fffffff); -// // check that the block size is large enough to fit ctz pointers -// LFS_ASSERT(4*lfs_npw2(0xffffffff / (lfs->cfg->block_size-2*4)) -// <= lfs->cfg->block_size); -// -// // block_cycles = 0 is no longer supported. -// // -// // block_cycles is the number of erase cycles before littlefs evicts -// // metadata logs as a part of wear leveling. Suggested values are in the -// // range of 100-1000, or set block_cycles to -1 to disable block-level -// // wear-leveling. -// LFS_ASSERT(lfs->cfg->block_cycles != 0); - #ifdef LFS_GC // unknown gc flags? LFS_ASSERT((lfs->cfg->gc_flags & ~( @@ -13938,18 +13605,6 @@ static int lfs_init(lfs_t *lfs, uint32_t flags, lfs->file_limit = LFS_FILE_MAX; } - // setup default state - -// lfs->root[0] = LFS_BLOCK_NULL; -// lfs->root[1] = LFS_BLOCK_NULL; -// lfs->mlist = NULL; -// lfs->gdisk = (lfs_gstate_t){0}; -// lfs->gstate = (lfs_gstate_t){0}; -// lfs->gdelta = (lfs_gstate_t){0}; -//#ifdef LFS_MIGRATE -// lfs->lfs1 = NULL; -//#endif - // TODO do we need to recalculate these after mount? // find the number of bits to use for recycle counters @@ -14093,6 +13748,7 @@ static int lfs_deinit(lfs_t *lfs) { } + /// Mount/unmount /// // compatibility flags @@ -14758,6 +14414,7 @@ int lfsr_unmount(lfs_t *lfs) { } + /// Format /// static int lfsr_formatinited(lfs_t *lfs) { @@ -15392,6 +15049,7 @@ failed:; } + /// High-level filesystem traversal /// // needed in lfsr_traversal_open @@ -15565,5228 +15223,4 @@ int lfsr_traversal_rewind(lfs_t *lfs, lfsr_traversal_t *t) { - - - - - - - - - - - - - - - -///// Metadata pair and directory operations /// -//static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir, -// lfs_tag_t gmask, lfs_tag_t gtag, -// lfs_off_t goff, void *gbuffer, lfs_size_t gsize) { -// lfs_off_t off = dir->off; -// lfs_tag_t ntag = dir->etag; -// lfs_stag_t gdiff = 0; -// -// if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair) && -// lfs_tag_id(gmask) != 0 && -// lfs_tag_id(lfs->gdisk.tag) <= lfs_tag_id(gtag)) { -// // synthetic moves -// gdiff -= LFS_MKTAG(0, 1, 0); -// } -// -// // iterate over dir block backwards (for faster lookups) -// while (off >= sizeof(lfs_tag_t) + lfs_tag_dsize(ntag)) { -// off -= lfs_tag_dsize(ntag); -// lfs_tag_t tag = ntag; -// int err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, sizeof(ntag), -// dir->pair[0], off, &ntag, sizeof(ntag)); -// if (err) { -// return err; -// } -// -// ntag = (lfs_frombe32(ntag) ^ tag) & 0x7fffffff; -// -// if (lfs_tag_id(gmask) != 0 && -// lfs_tag_type1(tag) == LFS_TYPE_SPLICE && -// lfs_tag_id(tag) <= lfs_tag_id(gtag - gdiff)) { -// if (tag == (LFS_MKTAG(LFS_TYPE_CREATE, 0, 0) | -// (LFS_MKTAG(0, 0x3ff, 0) & (gtag - gdiff)))) { -// // found where we were created -// return LFS_ERR_NOENT; -// } -// -// // move around splices -// gdiff += LFS_MKTAG(0, lfs_tag_splice(tag), 0); -// } -// -// if ((gmask & tag) == (gmask & (gtag - gdiff))) { -// if (lfs_tag_isdelete(tag)) { -// return LFS_ERR_NOENT; -// } -// -// lfs_size_t diff = lfs_min(lfs_tag_size(tag), gsize); -// err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, diff, -// dir->pair[0], off+sizeof(tag)+goff, gbuffer, diff); -// if (err) { -// return err; -// } -// -// memset((uint8_t*)gbuffer + diff, 0, gsize - diff); -// -// return tag + gdiff; -// } -// } -// -// return LFS_ERR_NOENT; -//} -// -//static lfs_stag_t lfs_dir_get(lfs_t *lfs, const lfs_mdir_t *dir, -// lfs_tag_t gmask, lfs_tag_t gtag, void *buffer) { -// return lfs_dir_getslice(lfs, dir, -// gmask, gtag, -// 0, buffer, lfs_tag_size(gtag)); -//} -// -//static int lfs_dir_getread(lfs_t *lfs, const lfs_mdir_t *dir, -// const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, -// lfs_tag_t gmask, lfs_tag_t gtag, -// lfs_off_t off, void *buffer, lfs_size_t size) { -// uint8_t *data = buffer; -// if (off+size > lfs->cfg->block_size) { -// return LFS_ERR_CORRUPT; -// } -// -// while (size > 0) { -// lfs_size_t diff = size; -// -// if (pcache && pcache->block == LFS_BLOCK_INLINE && -// off < pcache->off + pcache->size) { -// if (off >= pcache->off) { -// // is already in pcache? -// diff = lfs_min(diff, pcache->size - (off-pcache->off)); -// memcpy(data, &pcache->buffer[off-pcache->off], diff); -// -// data += diff; -// off += diff; -// size -= diff; -// continue; -// } -// -// // pcache takes priority -// diff = lfs_min(diff, pcache->off-off); -// } -// -// if (rcache->block == LFS_BLOCK_INLINE && -// off < rcache->off + rcache->size) { -// if (off >= rcache->off) { -// // is already in rcache? -// diff = lfs_min(diff, rcache->size - (off-rcache->off)); -// memcpy(data, &rcache->buffer[off-rcache->off], diff); -// -// data += diff; -// off += diff; -// size -= diff; -// continue; -// } -// -// // rcache takes priority -// diff = lfs_min(diff, rcache->off-off); -// } -// -// // load to cache, first condition can no longer fail -// rcache->block = LFS_BLOCK_INLINE; -// rcache->off = lfs_aligndown(off, lfs->cfg->read_size); -// rcache->size = lfs_min(lfs_alignup(off+hint, lfs->cfg->read_size), -// lfs->cfg->cache_size); -// int err = lfs_dir_getslice(lfs, dir, gmask, gtag, -// rcache->off, rcache->buffer, rcache->size); -// if (err < 0) { -// return err; -// } -// } -// -// 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; -// (void)buffer; -// -// // which mask depends on unique bit in tag structure -// uint32_t mask = (tag & LFS_MKTAG(0x100, 0, 0)) -// ? LFS_MKTAG(0x7ff, 0x3ff, 0) -// : LFS_MKTAG(0x700, 0x3ff, 0); -// -// // check for redundancy -// if ((mask & tag) == (mask & *filtertag) || -// lfs_tag_isdelete(*filtertag) || -// (LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) == ( -// LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | -// (LFS_MKTAG(0, 0x3ff, 0) & *filtertag))) { -// *filtertag = LFS_MKTAG(LFS_FROM_NOOP, 0, 0); -// return true; -// } -// -// // check if we need to adjust for created/deleted tags -// if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE && -// lfs_tag_id(tag) <= lfs_tag_id(*filtertag)) { -// *filtertag += LFS_MKTAG(0, lfs_tag_splice(tag), 0); -// } -// -// return false; -//} -//#endif -// -//#ifndef LFS_READONLY -//// maximum recursive depth of lfs_dir_traverse, the deepest call: -//// -//// traverse with commit -//// '-> traverse with move -//// '-> traverse with filter -//// -//#define LFS_DIR_TRAVERSE_DEPTH 3 -// -//struct lfs_dir_traverse { -// const lfs_mdir_t *dir; -// lfs_off_t off; -// lfs_tag_t ptag; -// const struct lfs_mattr *attrs; -// int attrcount; -// -// lfs_tag_t tmask; -// lfs_tag_t ttag; -// uint16_t begin; -// uint16_t end; -// int16_t diff; -// -// int (*cb)(void *data, lfs_tag_t tag, const void *buffer); -// void *data; -// -// lfs_tag_t tag; -// const void *buffer; -// struct lfs_diskoff disk; -//}; -// -//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, -// lfs_tag_t tmask, lfs_tag_t ttag, -// uint16_t begin, uint16_t end, int16_t diff, -// int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) { -// // This function in inherently recursive, but bounded. To allow tool-based -// // analysis without unnecessary code-cost we use an explicit stack -// struct lfs_dir_traverse stack[LFS_DIR_TRAVERSE_DEPTH-1]; -// unsigned sp = 0; -// int res; -// -// // iterate over directory and attrs -// lfs_tag_t tag; -// const void *buffer; -// struct lfs_diskoff disk; -// while (true) { -// { -// if (off+lfs_tag_dsize(ptag) < dir->off) { -// off += lfs_tag_dsize(ptag); -// int err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, sizeof(tag), -// dir->pair[0], off, &tag, sizeof(tag)); -// if (err) { -// return err; -// } -// -// tag = (lfs_frombe32(tag) ^ ptag) | 0x80000000; -// disk.block = dir->pair[0]; -// disk.off = off+sizeof(lfs_tag_t); -// buffer = &disk; -// ptag = tag; -// } else if (attrcount > 0) { -// tag = attrs[0].tag; -// buffer = attrs[0].buffer; -// attrs += 1; -// attrcount -= 1; -// } else { -// // finished traversal, pop from stack? -// res = 0; -// break; -// } -// -// // do we need to filter? -// lfs_tag_t mask = LFS_MKTAG(0x7ff, 0, 0); -// if ((mask & tmask & tag) != (mask & tmask & ttag)) { -// continue; -// } -// -// if (lfs_tag_id(tmask) != 0) { -// LFS_ASSERT(sp < LFS_DIR_TRAVERSE_DEPTH); -// // recurse, scan for duplicates, and update tag based on -// // creates/deletes -// stack[sp] = (struct lfs_dir_traverse){ -// .dir = dir, -// .off = off, -// .ptag = ptag, -// .attrs = attrs, -// .attrcount = attrcount, -// .tmask = tmask, -// .ttag = ttag, -// .begin = begin, -// .end = end, -// .diff = diff, -// .cb = cb, -// .data = data, -// .tag = tag, -// .buffer = buffer, -// .disk = disk, -// }; -// sp += 1; -// -// tmask = 0; -// ttag = 0; -// begin = 0; -// end = 0; -// diff = 0; -// cb = lfs_dir_traverse_filter; -// data = &stack[sp-1].tag; -// continue; -// } -// } -// -//popped: -// // in filter range? -// if (lfs_tag_id(tmask) != 0 && -// !(lfs_tag_id(tag) >= begin && lfs_tag_id(tag) < end)) { -// continue; -// } -// -// // handle special cases for mcu-side operations -// if (lfs_tag_type3(tag) == LFS_FROM_NOOP) { -// // do nothing -// } else if (lfs_tag_type3(tag) == LFS_FROM_MOVE) { -// // Without this condition, lfs_dir_traverse can exhibit an -// // extremely expensive O(n^3) of nested loops when renaming. -// // This happens because lfs_dir_traverse tries to filter tags by -// // the tags in the source directory, triggering a second -// // lfs_dir_traverse with its own filter operation. -// // -// // traverse with commit -// // '-> traverse with filter -// // '-> traverse with move -// // '-> traverse with filter -// // -// // However we don't actually care about filtering the second set of -// // tags, since duplicate tags have no effect when filtering. -// // -// // This check skips this unnecessary recursive filtering explicitly, -// // reducing this runtime from O(n^3) to O(n^2). -// if (cb == lfs_dir_traverse_filter) { -// continue; -// } -// -// // recurse into move -// stack[sp] = (struct lfs_dir_traverse){ -// .dir = dir, -// .off = off, -// .ptag = ptag, -// .attrs = attrs, -// .attrcount = attrcount, -// .tmask = tmask, -// .ttag = ttag, -// .begin = begin, -// .end = end, -// .diff = diff, -// .cb = cb, -// .data = data, -// .tag = LFS_MKTAG(LFS_FROM_NOOP, 0, 0), -// }; -// sp += 1; -// -// uint16_t fromid = lfs_tag_size(tag); -// uint16_t toid = lfs_tag_id(tag); -// dir = buffer; -// off = 0; -// ptag = 0xffffffff; -// attrs = NULL; -// attrcount = 0; -// tmask = LFS_MKTAG(0x600, 0x3ff, 0); -// ttag = LFS_MKTAG(LFS_TYPE_STRUCT, 0, 0); -// begin = fromid; -// end = fromid+1; -// diff = toid-fromid+diff; -// } else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) { -// for (unsigned i = 0; i < lfs_tag_size(tag); i++) { -// const struct lfs_attr *a = buffer; -// res = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a[i].type, -// lfs_tag_id(tag) + diff, a[i].size), a[i].buffer); -// if (res < 0) { -// return res; -// } -// -// if (res) { -// break; -// } -// } -// } else { -// res = cb(data, tag + LFS_MKTAG(0, diff, 0), buffer); -// if (res < 0) { -// return res; -// } -// -// if (res) { -// break; -// } -// } -// } -// -// if (sp > 0) { -// // pop from the stack and return, fortunately all pops share -// // a destination -// dir = stack[sp-1].dir; -// off = stack[sp-1].off; -// ptag = stack[sp-1].ptag; -// attrs = stack[sp-1].attrs; -// attrcount = stack[sp-1].attrcount; -// tmask = stack[sp-1].tmask; -// ttag = stack[sp-1].ttag; -// begin = stack[sp-1].begin; -// end = stack[sp-1].end; -// diff = stack[sp-1].diff; -// cb = stack[sp-1].cb; -// data = stack[sp-1].data; -// tag = stack[sp-1].tag; -// buffer = stack[sp-1].buffer; -// disk = stack[sp-1].disk; -// sp -= 1; -// goto popped; -// } else { -// return res; -// } -//} -//#endif -// -//static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, -// lfs_mdir_t *dir, const lfs_block_t pair[2], -// lfs_tag_t fmask, lfs_tag_t ftag, uint16_t *id, -// int (*cb)(void *data, lfs_tag_t tag, const void *buffer), void *data) { -// // we can find tag very efficiently during a fetch, since we're already -// // scanning the entire directory -// lfs_stag_t besttag = -1; -// -// // if either block address is invalid we return LFS_ERR_CORRUPT here, -// // otherwise later writes to the pair could fail -// if (pair[0] >= lfs->cfg->block_count || pair[1] >= lfs->cfg->block_count) { -// return LFS_ERR_CORRUPT; -// } -// -// // find the block with the most recent revision -// uint32_t revs[2] = {0, 0}; -// int r = 0; -// for (int i = 0; i < 2; i++) { -// int err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, sizeof(revs[i]), -// pair[i], 0, &revs[i], sizeof(revs[i])); -// revs[i] = lfs_fromle32(revs[i]); -// if (err && err != LFS_ERR_CORRUPT) { -// return err; -// } -// -// if (err != LFS_ERR_CORRUPT && -// lfs_scmp(revs[i], revs[(i+1)%2]) > 0) { -// r = i; -// } -// } -// -// dir->pair[0] = pair[(r+0)%2]; -// dir->pair[1] = pair[(r+1)%2]; -// dir->rev = revs[(r+0)%2]; -// dir->off = 0; // nonzero = found some commits -// -// // now scan tags to fetch the actual dir and find possible match -// for (int i = 0; i < 2; i++) { -// lfs_off_t off = 0; -// lfs_tag_t ptag = 0xffffffff; -// -// uint16_t tempcount = 0; -// lfs_block_t temptail[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; -// bool tempsplit = false; -// lfs_stag_t tempbesttag = besttag; -// -// // assume not erased until proven otherwise -// bool maybeerased = false; -// bool hasfcrc = false; -// struct lfs_fcrc fcrc; -// -// dir->rev = lfs_tole32(dir->rev); -// uint32_t crc = lfs_crc(0xffffffff, &dir->rev, sizeof(dir->rev)); -// dir->rev = lfs_fromle32(dir->rev); -// -// while (true) { -// // extract next tag -// lfs_tag_t tag; -// off += lfs_tag_dsize(ptag); -// int err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, lfs->cfg->block_size, -// dir->pair[0], off, &tag, sizeof(tag)); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// // can't continue? -// break; -// } -// return err; -// } -// -// crc = lfs_crc(crc, &tag, sizeof(tag)); -// tag = lfs_frombe32(tag) ^ ptag; -// -// // next commit not yet programmed? -// if (!lfs_tag_isvalid(tag)) { -// maybeerased = true; -// break; -// // out of range? -// } else if (off + lfs_tag_dsize(tag) > lfs->cfg->block_size) { -// break; -// } -// -// ptag = tag; -// -// if (lfs_tag_type2(tag) == LFS_TYPE_CCRC) { -// // check the crc attr -// uint32_t dcrc; -// err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, lfs->cfg->block_size, -// dir->pair[0], off+sizeof(tag), &dcrc, sizeof(dcrc)); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// break; -// } -// return err; -// } -// dcrc = lfs_fromle32(dcrc); -// -// if (crc != dcrc) { -// break; -// } -// -// // reset the next bit if we need to -// ptag ^= (lfs_tag_t)(lfs_tag_chunk(tag) & 1U) << 31; -// -// // toss our crc into the filesystem seed for -// // 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; -// dir->off = off + lfs_tag_dsize(tag); -// dir->etag = ptag; -// dir->count = tempcount; -// dir->tail[0] = temptail[0]; -// dir->tail[1] = temptail[1]; -// dir->split = tempsplit; -// -// // reset crc -// crc = 0xffffffff; -// continue; -// } -// -// // fcrc is only valid when last tag was a crc -// hasfcrc = false; -// -// // crc the entry first, hopefully leaving it in the cache -// err = lfs_bd_crc(lfs, -// NULL, &lfs->rcache, lfs->cfg->block_size, -// dir->pair[0], off+sizeof(tag), -// lfs_tag_dsize(tag)-sizeof(tag), &crc); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// break; -// } -// return err; -// } -// -// // directory modification tags? -// if (lfs_tag_type1(tag) == LFS_TYPE_NAME) { -// // increase count of files if necessary -// if (lfs_tag_id(tag) >= tempcount) { -// tempcount = lfs_tag_id(tag) + 1; -// } -// } else if (lfs_tag_type1(tag) == LFS_TYPE_SPLICE) { -// tempcount += lfs_tag_splice(tag); -// -// if (tag == (LFS_MKTAG(LFS_TYPE_DELETE, 0, 0) | -// (LFS_MKTAG(0, 0x3ff, 0) & tempbesttag))) { -// tempbesttag |= 0x80000000; -// } else if (tempbesttag != -1 && -// lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) { -// tempbesttag += LFS_MKTAG(0, lfs_tag_splice(tag), 0); -// } -// } else if (lfs_tag_type1(tag) == LFS_TYPE_TAIL) { -// tempsplit = (lfs_tag_chunk(tag) & 1); -// -// err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, lfs->cfg->block_size, -// dir->pair[0], off+sizeof(tag), &temptail, 8); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// break; -// } -// return err; -// } -// lfs_pair_fromle32(temptail); -// } else if (lfs_tag_type3(tag) == LFS_TYPE_FCRC) { -// err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, lfs->cfg->block_size, -// dir->pair[0], off+sizeof(tag), -// &fcrc, sizeof(fcrc)); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// break; -// } -// } -// -// lfs_fcrc_fromle32(&fcrc); -// hasfcrc = true; -// } -// -// // found a match for our fetcher? -// if ((fmask & tag) == (fmask & ftag)) { -// int res = cb(data, tag, &(struct lfs_diskoff){ -// dir->pair[0], off+sizeof(tag)}); -// if (res < 0) { -// if (res == LFS_ERR_CORRUPT) { -// break; -// } -// return res; -// } -// -// if (res == LFS_CMP_EQ) { -// // found a match -// tempbesttag = tag; -// } else if ((LFS_MKTAG(0x7ff, 0x3ff, 0) & tag) == -// (LFS_MKTAG(0x7ff, 0x3ff, 0) & tempbesttag)) { -// // found an identical tag, but contents didn't match -// // this must mean that our besttag has been overwritten -// tempbesttag = -1; -// } else if (res == LFS_CMP_GT && -// lfs_tag_id(tag) <= lfs_tag_id(tempbesttag)) { -// // found a greater match, keep track to keep things sorted -// tempbesttag = tag | 0x80000000; -// } -// } -// } -// -// // found no valid commits? -// if (dir->off == 0) { -// // try the other block? -// lfs_pair_swap(dir->pair); -// dir->rev = revs[(r+1)%2]; -// continue; -// } -// -// // did we end on a valid commit? we may have an erased block -// dir->erased = false; -// if (maybeerased && hasfcrc && dir->off % lfs->cfg->prog_size == 0) { -// // check for an fcrc matching the next prog's erased state, if -// // this failed most likely a previous prog was interrupted, we -// // need a new erase -// uint32_t fcrc_ = 0xffffffff; -// int err = lfs_bd_crc(lfs, -// NULL, &lfs->rcache, lfs->cfg->block_size, -// dir->pair[0], dir->off, fcrc.size, &fcrc_); -// if (err && err != LFS_ERR_CORRUPT) { -// return err; -// } -// -// // found beginning of erased part? -// dir->erased = (fcrc_ == fcrc.crc); -// } -// -// // synthetic move -// if (lfs_gstate_hasmovehere(&lfs->gdisk, dir->pair)) { -// if (lfs_tag_id(lfs->gdisk.tag) == lfs_tag_id(besttag)) { -// besttag |= 0x80000000; -// } else if (besttag != -1 && -// lfs_tag_id(lfs->gdisk.tag) < lfs_tag_id(besttag)) { -// besttag -= LFS_MKTAG(0, 1, 0); -// } -// } -// -// // found tag? or found best id? -// if (id) { -// *id = lfs_min(lfs_tag_id(besttag), dir->count); -// } -// -// if (lfs_tag_isvalid(besttag)) { -// return besttag; -// } else if (lfs_tag_id(besttag) < dir->count) { -// return LFS_ERR_NOENT; -// } else { -// return 0; -// } -// } -// -// LFS_ERROR("Corrupted dir pair at {0x%"PRIx32", 0x%"PRIx32"}", -// dir->pair[0], dir->pair[1]); -// return LFS_ERR_CORRUPT; -//} -// -//static int lfs_dir_fetch(lfs_t *lfs, -// lfs_mdir_t *dir, const lfs_block_t pair[2]) { -// // note, mask=-1, tag=-1 can never match a tag since this -// // pattern has the invalid bit set -// return (int)lfs_dir_fetchmatch(lfs, dir, pair, -// (lfs_tag_t)-1, (lfs_tag_t)-1, NULL, NULL, NULL); -//} -// -//static int lfs_dir_getgstate(lfs_t *lfs, const lfs_mdir_t *dir, -// lfs_gstate_t *gstate) { -// lfs_gstate_t temp; -// lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x7ff, 0, 0), -// LFS_MKTAG(LFS_TYPE_MOVESTATE, 0, sizeof(temp)), &temp); -// if (res < 0 && res != LFS_ERR_NOENT) { -// return res; -// } -// -// if (res != LFS_ERR_NOENT) { -// // xor together to find resulting gstate -// lfs_gstate_fromle32(&temp); -// lfs_gstate_xor(gstate, &temp); -// } -// -// return 0; -//} -// -//static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir, -// uint16_t id, struct lfs_info *info) { -// if (id == 0x3ff) { -// // special case for root -// strcpy(info->name, "/"); -// info->type = LFS_TYPE_DIR; -// return 0; -// } -// -// lfs_stag_t tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x780, 0x3ff, 0), -// LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max+1), info->name); -// if (tag < 0) { -// return (int)tag; -// } -// -// info->type = lfs_tag_type3(tag); -// -// struct lfs_ctz ctz; -// tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0x3ff, 0), -// LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz); -// if (tag < 0) { -// return (int)tag; -// } -// lfs_ctz_fromle32(&ctz); -// -// if (lfs_tag_type3(tag) == LFS_TYPE_CTZSTRUCT) { -// info->size = ctz.size; -// } else if (lfs_tag_type3(tag) == LFS_TYPE_INLINESTRUCT) { -// info->size = lfs_tag_size(tag); -// } -// -// return 0; -//} -// -//struct lfs_dir_find_match { -// lfs_t *lfs; -// const void *name; -// lfs_size_t size; -//}; -// -//static int lfs_dir_find_match(void *data, -// lfs_tag_t tag, const void *buffer) { -// struct lfs_dir_find_match *name = data; -// lfs_t *lfs = name->lfs; -// const struct lfs_diskoff *disk = buffer; -// -// // compare with disk -// lfs_size_t diff = lfs_min(name->size, lfs_tag_size(tag)); -// int res = lfs_bd_cmp(lfs, -// NULL, &lfs->rcache, diff, -// disk->block, disk->off, name->name, diff); -// if (res != LFS_CMP_EQ) { -// return res; -// } -// -// // only equal if our size is still the same -// if (name->size != lfs_tag_size(tag)) { -// return (name->size < lfs_tag_size(tag)) ? LFS_CMP_LT : LFS_CMP_GT; -// } -// -// // found a match! -// return LFS_CMP_EQ; -//} -// -//static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, -// const char **path, uint16_t *id) { -// // we reduce path to a single name if we can find it -// const char *name = *path; -// if (id) { -// *id = 0x3ff; -// } -// -// // default to root dir -// lfs_stag_t tag = LFS_MKTAG(LFS_TYPE_DIR, 0x3ff, 0); -// dir->tail[0] = lfs->root[0]; -// dir->tail[1] = lfs->root[1]; -// -// while (true) { -//nextname: -// // skip slashes -// name += strspn(name, "/"); -// lfs_size_t namelen = strcspn(name, "/"); -// -// // skip '.' and root '..' -// if ((namelen == 1 && memcmp(name, ".", 1) == 0) || -// (namelen == 2 && memcmp(name, "..", 2) == 0)) { -// name += namelen; -// goto nextname; -// } -// -// // skip if matched by '..' in name -// const char *suffix = name + namelen; -// lfs_size_t sufflen; -// int depth = 1; -// while (true) { -// suffix += strspn(suffix, "/"); -// sufflen = strcspn(suffix, "/"); -// if (sufflen == 0) { -// break; -// } -// -// if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { -// depth -= 1; -// if (depth == 0) { -// name = suffix + sufflen; -// goto nextname; -// } -// } else { -// depth += 1; -// } -// -// suffix += sufflen; -// } -// -// // found path -// if (name[0] == '\0') { -// return tag; -// } -// -// // update what we've found so far -// *path = name; -// -// // only continue if we hit a directory -// if (lfs_tag_type3(tag) != LFS_TYPE_DIR) { -// return LFS_ERR_NOTDIR; -// } -// -// // grab the entry data -// if (lfs_tag_id(tag) != 0x3ff) { -// lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x700, 0x3ff, 0), -// LFS_MKTAG(LFS_TYPE_STRUCT, lfs_tag_id(tag), 8), dir->tail); -// if (res < 0) { -// return res; -// } -// lfs_pair_fromle32(dir->tail); -// } -// -// // find entry matching name -// while (true) { -// tag = lfs_dir_fetchmatch(lfs, dir, dir->tail, -// LFS_MKTAG(0x780, 0, 0), -// LFS_MKTAG(LFS_TYPE_NAME, 0, namelen), -// // are we last name? -// (strchr(name, '/') == NULL) ? id : NULL, -// lfs_dir_find_match, &(struct lfs_dir_find_match){ -// lfs, name, namelen}); -// if (tag < 0) { -// return tag; -// } -// -// if (tag) { -// break; -// } -// -// if (!dir->split) { -// return LFS_ERR_NOENT; -// } -// } -// -// // to next name -// name += namelen; -// } -//} -// -//// commit logic -//struct lfs_commit { -// lfs_block_t block; -// lfs_off_t off; -// lfs_tag_t ptag; -// uint32_t crc; -// -// lfs_off_t begin; -// 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, -// &lfs->pcache, &lfs->rcache, false, -// commit->block, commit->off , -// (const uint8_t*)buffer, size); -// if (err) { -// return err; -// } -// -// commit->crc = lfs_crc(commit->crc, buffer, size); -// 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 -// lfs_size_t dsize = lfs_tag_dsize(tag); -// if (commit->off + dsize > commit->end) { -// return LFS_ERR_NOSPC; -// } -// -// // write out tag -// lfs_tag_t ntag = lfs_tobe32((tag & 0x7fffffff) ^ commit->ptag); -// int err = lfs_dir_commitprog(lfs, commit, &ntag, sizeof(ntag)); -// if (err) { -// return err; -// } -// -// if (!(tag & 0x80000000)) { -// // from memory -// err = lfs_dir_commitprog(lfs, commit, buffer, dsize-sizeof(tag)); -// if (err) { -// return err; -// } -// } else { -// // from disk -// const struct lfs_diskoff *disk = buffer; -// for (lfs_off_t i = 0; i < dsize-sizeof(tag); i++) { -// // rely on caching to make this efficient -// uint8_t dat; -// err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, dsize-sizeof(tag)-i, -// disk->block, disk->off+i, &dat, 1); -// if (err) { -// return err; -// } -// -// err = lfs_dir_commitprog(lfs, commit, &dat, 1); -// if (err) { -// return err; -// } -// } -// } -// -// commit->ptag = tag & 0x7fffffff; -// return 0; -//} -//#endif -// -//#ifndef LFS_READONLY -// -//static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { -// // align to program units -// // -// // this gets a bit complex as we have two types of crcs: -// // - 5-word crc with fcrc to check following prog (middle of block) -// // - 2-word crc with no following prog (end of block) -// const lfs_off_t end = lfs_alignup( -// lfs_min(commit->off + 5*sizeof(uint32_t), lfs->cfg->block_size), -// 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 -// while (commit->off < end) { -// lfs_off_t noff = ( -// lfs_min(end - (commit->off+sizeof(lfs_tag_t)), 0x3fe) -// + (commit->off+sizeof(lfs_tag_t))); -// // too large for crc tag? need padding commits -// if (noff < end) { -// noff = lfs_min(noff, end - 5*sizeof(uint32_t)); -// } -// -// // space for fcrc? -// uint8_t eperturb = -1; -// if (noff >= end && noff <= lfs->cfg->block_size - lfs->cfg->prog_size) { -// // first read the leading byte, this always contains a bit -// // we can perturb to avoid writes that don't change the fcrc -// int err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, lfs->cfg->prog_size, -// commit->block, noff, &eperturb, 1); -// if (err && err != LFS_ERR_CORRUPT) { -// return err; -// } -// -// // find the expected fcrc, don't bother avoiding a reread -// // of the eperturb, it should still be in our cache -// struct lfs_fcrc fcrc = {.size=lfs->cfg->prog_size, .crc=0xffffffff}; -// err = lfs_bd_crc(lfs, -// NULL, &lfs->rcache, lfs->cfg->prog_size, -// commit->block, noff, fcrc.size, &fcrc.crc); -// if (err && err != LFS_ERR_CORRUPT) { -// return err; -// } -// -// lfs_fcrc_tole32(&fcrc); -// err = lfs_dir_commitattr(lfs, commit, -// LFS_MKTAG(LFS_TYPE_FCRC, 0x3ff, sizeof(struct lfs_fcrc)), -// &fcrc); -// if (err) { -// return err; -// } -// } -// -// // build commit crc -// struct { -// lfs_tag_t tag; -// uint32_t crc; -// } ccrc; -// lfs_tag_t ntag = LFS_MKTAG( -// LFS_TYPE_CCRC + (((uint8_t)~eperturb) >> 7), 0x3ff, -// noff - (commit->off+sizeof(lfs_tag_t))); -// ccrc.tag = lfs_tobe32(ntag ^ commit->ptag); -// commit->crc = lfs_crc(commit->crc, &ccrc.tag, sizeof(lfs_tag_t)); -// ccrc.crc = lfs_tole32(commit->crc); -// -// int err = lfs_bd_prog(lfs, -// &lfs->pcache, &lfs->rcache, false, -// commit->block, commit->off, &ccrc, sizeof(ccrc)); -// if (err) { -// return err; -// } -// -// // keep track of non-padding checksum to verify -// if (off1 == 0) { -// off1 = commit->off + sizeof(lfs_tag_t); -// crc1 = commit->crc; -// } -// -// commit->off = noff; -// // perturb valid bit? -// commit->ptag = ntag ^ ((0x80 & ~eperturb) << 24); -// // reset crc for next commit -// commit->crc = 0xffffffff; -// -// // manually flush here since we don't prog the padding, this confuses -// // the caching layer -// if (noff >= end || noff >= lfs->pcache.off + lfs->cfg->cache_size) { -// // flush buffers -// int err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false); -// if (err) { -// return err; -// } -// } -// } -// -// // successful commit, check checksums to make sure -// // -// // note that we don't need to check padding commits, worst -// // case if they are corrupted we would have had to compact anyways -// lfs_off_t off = commit->begin; -// uint32_t crc = 0xffffffff; -// int err = lfs_bd_crc(lfs, -// NULL, &lfs->rcache, off1+sizeof(uint32_t), -// commit->block, off, off1-off, &crc); -// if (err) { -// return err; -// } -// -// // check non-padding commits against known crc -// if (crc != crc1) { -// return LFS_ERR_CORRUPT; -// } -// -// // make sure to check crc in case we happen to pick -// // up an unrelated crc (frozen block?) -// err = lfs_bd_crc(lfs, -// NULL, &lfs->rcache, sizeof(uint32_t), -// commit->block, off1, sizeof(uint32_t), &crc); -// if (err) { -// return err; -// } -// -// if (crc != 0) { -// return LFS_ERR_CORRUPT; -// } -// -// 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++) { -// int err = lfs_alloc(lfs, &dir->pair[(i+1)%2]); -// if (err) { -// return err; -// } -// } -// -// // zero for reproducibility in case initial block is unreadable -// dir->rev = 0; -// -// // rather than clobbering one of the blocks we just pretend -// // the revision may be valid -// int err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, sizeof(dir->rev), -// dir->pair[0], 0, &dir->rev, sizeof(dir->rev)); -// dir->rev = lfs_fromle32(dir->rev); -// if (err && err != LFS_ERR_CORRUPT) { -// return err; -// } -// -// // 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); -// dir->etag = 0xffffffff; -// dir->count = 0; -// dir->tail[0] = LFS_BLOCK_NULL; -// dir->tail[1] = LFS_BLOCK_NULL; -// dir->erased = false; -// dir->split = false; -// -// // 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); -// if (err) { -// return err; -// } -// -// // steal tail -// lfs_pair_tole32(tail->tail); -// err = lfs_dir_commit(lfs, dir, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_TAIL + tail->split, 0x3ff, 8), tail->tail})); -// lfs_pair_fromle32(tail->tail); -// if (err) { -// return err; -// } -// -// 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) { -// // create tail metadata pair -// lfs_mdir_t tail; -// int err = lfs_dir_alloc(lfs, &tail); -// if (err) { -// return err; -// } -// -// tail.split = dir->split; -// tail.tail[0] = dir->tail[0]; -// tail.tail[1] = dir->tail[1]; -// -// // note we don't care about LFS_OK_RELOCATED -// int res = lfs_dir_compact(lfs, &tail, attrs, attrcount, source, split, end); -// if (res < 0) { -// return res; -// } -// -// dir->tail[0] = tail.pair[0]; -// dir->tail[1] = tail.pair[1]; -// dir->split = true; -// -// // update root if needed -// if (lfs_pair_cmp(dir->pair, lfs->root) == 0 && split == 0) { -// lfs->root[0] = tail.pair[0]; -// lfs->root[1] = tail.pair[1]; -// } -// -// 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; -// -// *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 bool lfs_dir_needsrelocation(lfs_t *lfs, lfs_mdir_t *dir) { -// // If our revision count == n * block_cycles, we should force a relocation, -// // this is how littlefs wear-levels at the metadata-pair level. Note that we -// // actually use (block_cycles+1)|1, this is to avoid two corner cases: -// // 1. block_cycles = 1, which would prevent relocations from terminating -// // 2. block_cycles = 2n, which, due to aliasing, would only ever relocate -// // one metadata block in the pair, effectively making this useless -// return (lfs->cfg->block_cycles > 0 -// && ((dir->rev + 1) % ((lfs->cfg->block_cycles+1)|1) == 0)); -//} -//#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) { -// // save some state in case block is bad -// bool relocated = false; -// bool tired = lfs_dir_needsrelocation(lfs, dir); -// -// // increment revision count -// dir->rev += 1; -// -// // do not proactively relocate blocks during migrations, this -// // can cause a number of failure states such: clobbering the -// // v1 superblock if we relocate root, and invalidating directory -// // pointers if we relocate the head of a directory. On top of -// // this, relocations increase the overall complexity of -// // lfs_migration, which is already a delicate operation. -//#ifdef LFS_MIGRATE -// if (lfs->lfs1) { -// tired = false; -// } -//#endif -// -// if (tired && lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) != 0) { -// // we're writing too much, time to relocate -// goto relocate; -// } -// -// // begin loop to commit compaction to blocks until a compact sticks -// while (true) { -// { -// // setup commit state -// struct lfs_commit commit = { -// .block = dir->pair[1], -// .off = 0, -// .ptag = 0xffffffff, -// .crc = 0xffffffff, -// -// .begin = 0, -// .end = (lfs->cfg->metadata_max ? -// lfs->cfg->metadata_max : lfs->cfg->block_size) - 8, -// }; -// -// // erase block to write to -// int err = lfs_bd_erase(lfs, dir->pair[1]); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// -// // write out header -// dir->rev = lfs_tole32(dir->rev); -// err = lfs_dir_commitprog(lfs, &commit, -// &dir->rev, sizeof(dir->rev)); -// dir->rev = lfs_fromle32(dir->rev); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// -// // traverse the directory, this time writing out all unique tags -// err = lfs_dir_traverse(lfs, -// source, 0, 0xffffffff, attrs, attrcount, -// LFS_MKTAG(0x400, 0x3ff, 0), -// LFS_MKTAG(LFS_TYPE_NAME, 0, 0), -// begin, end, -begin, -// lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){ -// lfs, &commit}); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// -// // commit tail, which may be new after last size check -// if (!lfs_pair_isnull(dir->tail)) { -// lfs_pair_tole32(dir->tail); -// err = lfs_dir_commitattr(lfs, &commit, -// LFS_MKTAG(LFS_TYPE_TAIL + dir->split, 0x3ff, 8), -// dir->tail); -// lfs_pair_fromle32(dir->tail); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// } -// -// // bring over gstate? -// lfs_gstate_t delta = {0}; -// if (!relocated) { -// lfs_gstate_xor(&delta, &lfs->gdisk); -// lfs_gstate_xor(&delta, &lfs->gstate); -// } -// lfs_gstate_xor(&delta, &lfs->gdelta); -// delta.tag &= ~LFS_MKTAG(0, 0, 0x3ff); -// -// err = lfs_dir_getgstate(lfs, dir, &delta); -// if (err) { -// return err; -// } -// -// if (!lfs_gstate_iszero(&delta)) { -// lfs_gstate_tole32(&delta); -// err = lfs_dir_commitattr(lfs, &commit, -// LFS_MKTAG(LFS_TYPE_MOVESTATE, 0x3ff, -// sizeof(delta)), &delta); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// } -// -// // complete commit with crc -// err = lfs_dir_commitcrc(lfs, &commit); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// -// // successful compaction, swap dir pair to indicate most recent -// LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0); -// lfs_pair_swap(dir->pair); -// dir->count = end - begin; -// dir->off = commit.off; -// dir->etag = commit.ptag; -// // update gstate -// lfs->gdelta = (lfs_gstate_t){0}; -// if (!relocated) { -// lfs->gdisk = lfs->gstate; -// } -// } -// break; -// -//relocate: -// // commit was corrupted, drop caches and prepare to relocate block -// relocated = true; -// lfs_cache_drop(lfs, &lfs->pcache); -// if (!tired) { -// LFS_DEBUG("Bad block at 0x%"PRIx32, dir->pair[1]); -// } -// -// // can't relocate superblock, filesystem is now frozen -// if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { -// LFS_WARN("Superblock 0x%"PRIx32" has become unwritable", -// dir->pair[1]); -// return LFS_ERR_NOSPC; -// } -// -// // relocate half of pair -// int err = lfs_alloc(lfs, &dir->pair[1]); -// if (err && (err != LFS_ERR_NOSPC || !tired)) { -// return err; -// } -// -// tired = false; -// continue; -// } -// -// return relocated ? LFS_OK_RELOCATED : 0; -//} -//#endif -// -//#ifndef LFS_READONLY -//static int lfs_dir_splittingcompact(lfs_t *lfs, lfs_mdir_t *dir, -// const struct lfs_mattr *attrs, int attrcount, -// lfs_mdir_t *source, uint16_t begin, uint16_t end) { -// while (true) { -// // find size of first split, we do this by halving the split until -// // the metadata is guaranteed to fit -// // -// // Note that this isn't a true binary search, we never increase the -// // split size. This may result in poorly distributed metadata but isn't -// // worth the extra code size or performance hit to fix. -// lfs_size_t split = begin; -// while (end - split > 1) { -// lfs_size_t size = 0; -// int err = lfs_dir_traverse(lfs, -// source, 0, 0xffffffff, attrs, attrcount, -// LFS_MKTAG(0x400, 0x3ff, 0), -// LFS_MKTAG(LFS_TYPE_NAME, 0, 0), -// split, end, -split, -// lfs_dir_commit_size, &size); -// if (err) { -// return err; -// } -// -// // space is complicated, we need room for: -// // -// // - tail: 4+2*4 = 12 bytes -// // - gstate: 4+3*4 = 16 bytes -// // - move delete: 4 = 4 bytes -// // - crc: 4+4 = 8 bytes -// // total = 40 bytes -// // -// // And we cap at half a block to avoid degenerate cases with -// // nearly-full metadata blocks. -// // -// if (end - split < 0xff -// && size <= lfs_min( -// lfs->cfg->block_size - 40, -// lfs_alignup( -// (lfs->cfg->metadata_max -// ? lfs->cfg->metadata_max -// : lfs->cfg->block_size)/2, -// lfs->cfg->prog_size))) { -// break; -// } -// -// split = split + ((end - split) / 2); -// } -// -// if (split == begin) { -// // no split needed -// break; -// } -// -// // split into two metadata pairs and continue -// int err = lfs_dir_split(lfs, dir, attrs, attrcount, -// source, split, end); -// if (err && err != LFS_ERR_NOSPC) { -// return err; -// } -// -// if (err) { -// // we can't allocate a new block, try to compact with degraded -// // performance -// LFS_WARN("Unable to split {0x%"PRIx32", 0x%"PRIx32"}", -// dir->pair[0], dir->pair[1]); -// break; -// } else { -// end = split; -// } -// } -// -// if (lfs_dir_needsrelocation(lfs, dir) -// && 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 size = lfs_fs_rawsize(lfs); -// if (size < 0) { -// return size; -// } -// -// // do we have extra space? littlefs can't reclaim this space -// // by itself, so expand cautiously -// if ((lfs_size_t)size < lfs->cfg->block_count/2) { -// LFS_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev); -// int err = lfs_dir_split(lfs, dir, attrs, attrcount, -// source, begin, end); -// if (err && err != LFS_ERR_NOSPC) { -// return err; -// } -// -// if (err) { -// // welp, we tried, if we ran out of space there's not much -// // we can do, we'll error later if we've become frozen -// LFS_WARN("Unable to expand superblock"); -// } else { -// end = begin; -// } -// } -// } -// -// return lfs_dir_compact(lfs, dir, attrs, attrcount, source, begin, end); -//} -//#endif -// -//#ifndef LFS_READONLY -//static int lfs_dir_relocatingcommit(lfs_t *lfs, lfs_mdir_t *dir, -// const lfs_block_t pair[2], -// const struct lfs_mattr *attrs, int attrcount, -// lfs_mdir_t *pdir) { -// int state = 0; -// -// // calculate changes to the directory -// bool hasdelete = false; -// for (int i = 0; i < attrcount; i++) { -// if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_CREATE) { -// dir->count += 1; -// } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE) { -// LFS_ASSERT(dir->count > 0); -// dir->count -= 1; -// hasdelete = true; -// } else if (lfs_tag_type1(attrs[i].tag) == LFS_TYPE_TAIL) { -// dir->tail[0] = ((lfs_block_t*)attrs[i].buffer)[0]; -// dir->tail[1] = ((lfs_block_t*)attrs[i].buffer)[1]; -// dir->split = (lfs_tag_chunk(attrs[i].tag) & 1); -// lfs_pair_fromle32(dir->tail); -// } -// } -// -// // should we actually drop the directory block? -// if (hasdelete && dir->count == 0) { -// LFS_ASSERT(pdir); -// int err = lfs_fs_pred(lfs, dir->pair, pdir); -// if (err && err != LFS_ERR_NOENT) { -// return err; -// } -// -// if (err != LFS_ERR_NOENT && pdir->split) { -// state = LFS_OK_DROPPED; -// goto fixmlist; -// } -// } -// -// if (dir->erased) { -// // try to commit -// struct lfs_commit commit = { -// .block = dir->pair[0], -// .off = dir->off, -// .ptag = dir->etag, -// .crc = 0xffffffff, -// -// .begin = dir->off, -// .end = (lfs->cfg->metadata_max ? -// lfs->cfg->metadata_max : lfs->cfg->block_size) - 8, -// }; -// -// // traverse attrs that need to be written out -// lfs_pair_tole32(dir->tail); -// int err = lfs_dir_traverse(lfs, -// dir, dir->off, dir->etag, attrs, attrcount, -// 0, 0, 0, 0, 0, -// lfs_dir_commit_commit, &(struct lfs_dir_commit_commit){ -// lfs, &commit}); -// lfs_pair_fromle32(dir->tail); -// if (err) { -// if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { -// goto compact; -// } -// return err; -// } -// -// // commit any global diffs if we have any -// lfs_gstate_t delta = {0}; -// lfs_gstate_xor(&delta, &lfs->gstate); -// lfs_gstate_xor(&delta, &lfs->gdisk); -// lfs_gstate_xor(&delta, &lfs->gdelta); -// delta.tag &= ~LFS_MKTAG(0, 0, 0x3ff); -// if (!lfs_gstate_iszero(&delta)) { -// err = lfs_dir_getgstate(lfs, dir, &delta); -// if (err) { -// return err; -// } -// -// lfs_gstate_tole32(&delta); -// err = lfs_dir_commitattr(lfs, &commit, -// LFS_MKTAG(LFS_TYPE_MOVESTATE, 0x3ff, -// sizeof(delta)), &delta); -// if (err) { -// if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { -// goto compact; -// } -// return err; -// } -// } -// -// // finalize commit with the crc -// err = lfs_dir_commitcrc(lfs, &commit); -// if (err) { -// if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { -// goto compact; -// } -// return err; -// } -// -// // successful commit, update dir -// LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0); -// dir->off = commit.off; -// dir->etag = commit.ptag; -// // and update gstate -// lfs->gdisk = lfs->gstate; -// lfs->gdelta = (lfs_gstate_t){0}; -// -// goto fixmlist; -// } -// -//compact: -// // fall back to compaction -// lfs_cache_drop(lfs, &lfs->pcache); -// -// state = lfs_dir_splittingcompact(lfs, dir, attrs, attrcount, -// dir, 0, dir->count); -// if (state < 0) { -// return state; -// } -// -// goto fixmlist; -// -//fixmlist:; -// // this complicated bit of logic is for fixing up any active -// // metadata-pairs that we may have affected -// // -// // note we have to make two passes since the mdir passed to -// // lfs_dir_commit could also be in this list, and even then -// // we need to copy the pair so they don't get clobbered if we refetch -// // our mdir. -// lfs_block_t oldpair[2] = {pair[0], pair[1]}; -// for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) { -// if (lfs_pair_cmp(d->m.pair, oldpair) == 0) { -// d->m = *dir; -// if (d->m.pair != pair) { -// for (int i = 0; i < attrcount; i++) { -// if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE && -// d->id == lfs_tag_id(attrs[i].tag)) { -// d->m.pair[0] = LFS_BLOCK_NULL; -// d->m.pair[1] = LFS_BLOCK_NULL; -// } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE && -// d->id > lfs_tag_id(attrs[i].tag)) { -// d->id -= 1; -// if (d->type == LFS_TYPE_DIR) { -// ((lfs_dir_t*)d)->pos -= 1; -// } -// } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_CREATE && -// d->id >= lfs_tag_id(attrs[i].tag)) { -// d->id += 1; -// if (d->type == LFS_TYPE_DIR) { -// ((lfs_dir_t*)d)->pos += 1; -// } -// } -// } -// } -// -// while (d->id >= d->m.count && d->m.split) { -// // we split and id is on tail now -// d->id -= d->m.count; -// int err = lfs_dir_fetch(lfs, &d->m, d->m.tail); -// if (err) { -// return err; -// } -// } -// } -// } -// -// return state; -//} -//#endif -// -//#ifndef LFS_READONLY -//static int lfs_dir_orphaningcommit(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 -// // forcefully evict them, needed for filesystem consistency -// for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) { -// if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 && -// f->type == LFS_TYPE_REG && (f->flags & LFS_F_INLINE) && -// f->ctz.size > lfs->cfg->cache_size) { -// int err = lfs_file_outline(lfs, f); -// if (err) { -// return err; -// } -// -// err = lfs_file_flush(lfs, f); -// if (err) { -// return err; -// } -// } -// } -// -// lfs_block_t lpair[2] = {dir->pair[0], dir->pair[1]}; -// lfs_mdir_t ldir = *dir; -// lfs_mdir_t pdir; -// int state = lfs_dir_relocatingcommit(lfs, &ldir, dir->pair, -// attrs, attrcount, &pdir); -// if (state < 0) { -// return state; -// } -// -// // update if we're not in mlist, note we may have already been -// // updated if we are in mlist -// if (lfs_pair_cmp(dir->pair, lpair) == 0) { -// *dir = ldir; -// } -// -// // commit was successful, but may require other changes in the -// // filesystem, these would normally be tail recursive, but we have -// // flattened them here avoid unbounded stack usage -// -// // need to drop? -// if (state == LFS_OK_DROPPED) { -// // steal state -// int err = lfs_dir_getgstate(lfs, dir, &lfs->gdelta); -// if (err) { -// return err; -// } -// -// // steal tail, note that this can't create a recursive drop -// lpair[0] = pdir.pair[0]; -// lpair[1] = pdir.pair[1]; -// lfs_pair_tole32(dir->tail); -// state = lfs_dir_relocatingcommit(lfs, &pdir, lpair, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_TAIL + dir->split, 0x3ff, 8), -// dir->tail}), -// NULL); -// lfs_pair_fromle32(dir->tail); -// if (state < 0) { -// return state; -// } -// -// ldir = pdir; -// } -// -// // need to relocate? -// bool orphans = false; -// while (state == LFS_OK_RELOCATED) { -// LFS_DEBUG("Relocating {0x%"PRIx32", 0x%"PRIx32"} " -// "-> {0x%"PRIx32", 0x%"PRIx32"}", -// lpair[0], lpair[1], ldir.pair[0], ldir.pair[1]); -// state = 0; -// -// // update internal root -// if (lfs_pair_cmp(lpair, lfs->root) == 0) { -// lfs->root[0] = ldir.pair[0]; -// lfs->root[1] = ldir.pair[1]; -// } -// -// // update internally tracked dirs -// for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) { -// if (lfs_pair_cmp(lpair, d->m.pair) == 0) { -// d->m.pair[0] = ldir.pair[0]; -// d->m.pair[1] = ldir.pair[1]; -// } -// -// if (d->type == LFS_TYPE_DIR && -// lfs_pair_cmp(lpair, ((lfs_dir_t*)d)->head) == 0) { -// ((lfs_dir_t*)d)->head[0] = ldir.pair[0]; -// ((lfs_dir_t*)d)->head[1] = ldir.pair[1]; -// } -// } -// -// // find parent -// lfs_stag_t tag = lfs_fs_parent(lfs, lpair, &pdir); -// if (tag < 0 && tag != LFS_ERR_NOENT) { -// return tag; -// } -// -// bool hasparent = (tag != LFS_ERR_NOENT); -// if (tag != LFS_ERR_NOENT) { -// // note that if we have a parent, we must have a pred, so this will -// // always create an orphan -// int err = lfs_fs_preporphans(lfs, +1); -// if (err) { -// return err; -// } -// -// // fix pending move in this pair? this looks like an optimization but -// // is in fact _required_ since relocating may outdate the move. -// uint16_t moveid = 0x3ff; -// if (lfs_gstate_hasmovehere(&lfs->gstate, pdir.pair)) { -// moveid = lfs_tag_id(lfs->gstate.tag); -// LFS_DEBUG("Fixing move while relocating " -// "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n", -// pdir.pair[0], pdir.pair[1], moveid); -// lfs_fs_prepmove(lfs, 0x3ff, NULL); -// if (moveid < lfs_tag_id(tag)) { -// tag -= LFS_MKTAG(0, 1, 0); -// } -// } -// -// lfs_block_t ppair[2] = {pdir.pair[0], pdir.pair[1]}; -// lfs_pair_tole32(ldir.pair); -// state = lfs_dir_relocatingcommit(lfs, &pdir, ppair, LFS_MKATTRS( -// {LFS_MKTAG_IF(moveid != 0x3ff, -// LFS_TYPE_DELETE, moveid, 0), NULL}, -// {tag, ldir.pair}), -// NULL); -// lfs_pair_fromle32(ldir.pair); -// if (state < 0) { -// return state; -// } -// -// if (state == LFS_OK_RELOCATED) { -// lpair[0] = ppair[0]; -// lpair[1] = ppair[1]; -// ldir = pdir; -// orphans = true; -// continue; -// } -// } -// -// // find pred -// int err = lfs_fs_pred(lfs, lpair, &pdir); -// if (err && err != LFS_ERR_NOENT) { -// return err; -// } -// LFS_ASSERT(!(hasparent && err == LFS_ERR_NOENT)); -// -// // if we can't find dir, it must be new -// if (err != LFS_ERR_NOENT) { -// if (lfs_gstate_hasorphans(&lfs->gstate)) { -// // next step, clean up orphans -// err = lfs_fs_preporphans(lfs, -hasparent); -// if (err) { -// return err; -// } -// } -// -// // fix pending move in this pair? this looks like an optimization -// // but is in fact _required_ since relocating may outdate the move. -// uint16_t moveid = 0x3ff; -// if (lfs_gstate_hasmovehere(&lfs->gstate, pdir.pair)) { -// moveid = lfs_tag_id(lfs->gstate.tag); -// LFS_DEBUG("Fixing move while relocating " -// "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n", -// pdir.pair[0], pdir.pair[1], moveid); -// lfs_fs_prepmove(lfs, 0x3ff, NULL); -// } -// -// // replace bad pair, either we clean up desync, or no desync occured -// lpair[0] = pdir.pair[0]; -// lpair[1] = pdir.pair[1]; -// lfs_pair_tole32(ldir.pair); -// state = lfs_dir_relocatingcommit(lfs, &pdir, lpair, LFS_MKATTRS( -// {LFS_MKTAG_IF(moveid != 0x3ff, -// LFS_TYPE_DELETE, moveid, 0), NULL}, -// {LFS_MKTAG(LFS_TYPE_TAIL + pdir.split, 0x3ff, 8), -// ldir.pair}), -// NULL); -// lfs_pair_fromle32(ldir.pair); -// if (state < 0) { -// return state; -// } -// -// ldir = pdir; -// } -// } -// -// return orphans ? LFS_OK_ORPHANED : 0; -//} -//#endif -// -//#ifndef LFS_READONLY -//static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, -// const struct lfs_mattr *attrs, int attrcount) { -// int orphans = lfs_dir_orphaningcommit(lfs, dir, attrs, attrcount); -// if (orphans < 0) { -// return orphans; -// } -// -// if (orphans) { -// // make sure we've removed all orphans, this is a noop if there -// // are none, but if we had nested blocks failures we may have -// // created some -// int err = lfs_fs_deorphan(lfs, false); -// if (err) { -// return err; -// } -// } -// -// return 0; -//} -//#endif -// -// -///// Top level directory operations /// -//#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) { -// return err; -// } -// -// struct lfs_mlist cwd; -// cwd.next = lfs->mlist; -// uint16_t id; -// err = lfs_dir_find(lfs, &cwd.m, &path, &id); -// if (!(err == LFS_ERR_NOENT && id != 0x3ff)) { -// return (err < 0) ? err : LFS_ERR_EXIST; -// } -// -// // check that name fits -// lfs_size_t nlen = strlen(path); -// if (nlen > lfs->name_max) { -// return LFS_ERR_NAMETOOLONG; -// } -// -// // build up new directory -// lfs_alloc_ack(lfs); -// lfs_mdir_t dir; -// err = lfs_dir_alloc(lfs, &dir); -// if (err) { -// return err; -// } -// -// // find end of list -// lfs_mdir_t pred = cwd.m; -// while (pred.split) { -// err = lfs_dir_fetch(lfs, &pred, pred.tail); -// if (err) { -// return err; -// } -// } -// -// // setup dir -// lfs_pair_tole32(pred.tail); -// err = lfs_dir_commit(lfs, &dir, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pred.tail})); -// lfs_pair_fromle32(pred.tail); -// if (err) { -// return err; -// } -// -// // current block not end of list? -// if (cwd.m.split) { -// // update tails, this creates a desync -// err = lfs_fs_preporphans(lfs, +1); -// if (err) { -// return err; -// } -// -// // it's possible our predecessor has to be relocated, and if -// // our parent is our predecessor's predecessor, this could have -// // caused our parent to go out of date, fortunately we can hook -// // ourselves into littlefs to catch this -// cwd.type = 0; -// cwd.id = 0; -// lfs->mlist = &cwd; -// -// lfs_pair_tole32(dir.pair); -// err = lfs_dir_commit(lfs, &pred, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); -// lfs_pair_fromle32(dir.pair); -// if (err) { -// lfs->mlist = cwd.next; -// return err; -// } -// -// lfs->mlist = cwd.next; -// err = lfs_fs_preporphans(lfs, -1); -// if (err) { -// return err; -// } -// } -// -// // now insert into our parent block -// lfs_pair_tole32(dir.pair); -// err = lfs_dir_commit(lfs, &cwd.m, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_CREATE, id, 0), NULL}, -// {LFS_MKTAG(LFS_TYPE_DIR, id, nlen), path}, -// {LFS_MKTAG(LFS_TYPE_DIRSTRUCT, id, 8), dir.pair}, -// {LFS_MKTAG_IF(!cwd.m.split, -// LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); -// lfs_pair_fromle32(dir.pair); -// if (err) { -// return err; -// } -// -// return 0; -//} -//#endif -// -//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) { -// return tag; -// } -// -// if (lfs_tag_type3(tag) != LFS_TYPE_DIR) { -// return LFS_ERR_NOTDIR; -// } -// -// lfs_block_t pair[2]; -// if (lfs_tag_id(tag) == 0x3ff) { -// // handle root dir separately -// pair[0] = lfs->root[0]; -// pair[1] = lfs->root[1]; -// } else { -// // get dir pair from parent -// 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) { -// return res; -// } -// lfs_pair_fromle32(pair); -// } -// -// // fetch first pair -// int err = lfs_dir_fetch(lfs, &dir->m, pair); -// if (err) { -// return err; -// } -// -// // setup entry -// dir->head[0] = dir->m.pair[0]; -// dir->head[1] = dir->m.pair[1]; -// dir->id = 0; -// dir->pos = 0; -// -// // add to list of mdirs -// dir->type = LFS_TYPE_DIR; -// lfs_mlist_append(lfs, (struct lfs_mlist *)dir); -// -// return 0; -//} -// -//static int lfs_dir_rawclose(lfs_t *lfs, lfs_dir_t *dir) { -// // remove from list of mdirs -// lfs_mlist_remove(lfs, (struct lfs_mlist *)dir); -// -// return 0; -//} -// -//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 '..' -// if (dir->pos == 0) { -// info->type = LFS_TYPE_DIR; -// strcpy(info->name, "."); -// dir->pos += 1; -// return true; -// } else if (dir->pos == 1) { -// info->type = LFS_TYPE_DIR; -// strcpy(info->name, ".."); -// dir->pos += 1; -// return true; -// } -// -// while (true) { -// if (dir->id == dir->m.count) { -// if (!dir->m.split) { -// return false; -// } -// -// int err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); -// if (err) { -// return err; -// } -// -// dir->id = 0; -// } -// -// int err = lfs_dir_getinfo(lfs, &dir->m, dir->id, info); -// if (err && err != LFS_ERR_NOENT) { -// return err; -// } -// -// dir->id += 1; -// if (err != LFS_ERR_NOENT) { -// break; -// } -// } -// -// dir->pos += 1; -// return true; -//} -// -//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_rawrewind(lfs, dir); -// if (err) { -// return err; -// } -// -// // first two for ./.. -// dir->pos = lfs_min(2, off); -// off -= dir->pos; -// -// // skip superblock entry -// dir->id = (off > 0 && lfs_pair_cmp(dir->head, lfs->root) == 0); -// -// while (off > 0) { -// int diff = lfs_min(dir->m.count - dir->id, off); -// dir->id += diff; -// dir->pos += diff; -// off -= diff; -// -// if (dir->id == dir->m.count) { -// if (!dir->m.split) { -// return LFS_ERR_INVAL; -// } -// -// err = lfs_dir_fetch(lfs, &dir->m, dir->m.tail); -// if (err) { -// return err; -// } -// -// dir->id = 0; -// } -// } -// -// return 0; -//} -// -//static lfs_soff_t lfs_dir_rawtell(lfs_t *lfs, lfs_dir_t *dir) { -// (void)lfs; -// return dir->pos; -//} -// -//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) { -// return err; -// } -// -// dir->id = 0; -// dir->pos = 0; -// return 0; -//} -// -// -///// File index list operations /// -//static int lfs_ctz_index(lfs_t *lfs, lfs_off_t *off) { -// lfs_off_t size = *off; -// lfs_off_t b = lfs->cfg->block_size - 2*4; -// lfs_off_t i = size / b; -// if (i == 0) { -// return 0; -// } -// -// i = (size - 4*(lfs_popc(i-1)+2)) / b; -// *off = size - b*i - 4*lfs_popc(i); -// return i; -//} -// -//static int lfs_ctz_find(lfs_t *lfs, -// const lfs_cache_t *pcache, lfs_cache_t *rcache, -// lfs_block_t head, lfs_size_t size, -// lfs_size_t pos, lfs_block_t *block, lfs_off_t *off) { -// if (size == 0) { -// *block = LFS_BLOCK_NULL; -// *off = 0; -// return 0; -// } -// -// lfs_off_t current = lfs_ctz_index(lfs, &(lfs_off_t){size-1}); -// lfs_off_t target = lfs_ctz_index(lfs, &pos); -// -// while (current > target) { -// lfs_size_t skip = lfs_min( -// lfs_npw2(current-target+1) - 1, -// lfs_ctz(current)); -// -// int err = lfs_bd_read(lfs, -// pcache, rcache, sizeof(head), -// head, 4*skip, &head, sizeof(head)); -// head = lfs_fromle32(head); -// if (err) { -// return err; -// } -// -// current -= 1 << skip; -// } -// -// *block = head; -// *off = pos; -// 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, -// lfs_block_t *block, lfs_off_t *off) { -// while (true) { -// // go ahead and grab a block -// lfs_block_t nblock; -// int err = lfs_alloc(lfs, &nblock); -// if (err) { -// return err; -// } -// -// { -// err = lfs_bd_erase(lfs, nblock); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// -// if (size == 0) { -// *block = nblock; -// *off = 0; -// return 0; -// } -// -// lfs_size_t noff = size - 1; -// lfs_off_t index = lfs_ctz_index(lfs, &noff); -// noff = noff + 1; -// -// // just copy out the last block if it is incomplete -// if (noff != lfs->cfg->block_size) { -// for (lfs_off_t i = 0; i < noff; i++) { -// uint8_t data; -// err = lfs_bd_read(lfs, -// NULL, rcache, noff-i, -// head, i, &data, 1); -// if (err) { -// return err; -// } -// -// err = lfs_bd_prog(lfs, -// pcache, rcache, true, -// nblock, i, &data, 1); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// } -// -// *block = nblock; -// *off = noff; -// return 0; -// } -// -// // append block -// index += 1; -// lfs_size_t skips = lfs_ctz(index) + 1; -// lfs_block_t nhead = head; -// for (lfs_off_t i = 0; i < skips; i++) { -// nhead = lfs_tole32(nhead); -// err = lfs_bd_prog(lfs, pcache, rcache, true, -// nblock, 4*i, &nhead, 4); -// nhead = lfs_fromle32(nhead); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// -// if (i != skips-1) { -// err = lfs_bd_read(lfs, -// NULL, rcache, sizeof(nhead), -// nhead, 4*i, &nhead, sizeof(nhead)); -// nhead = lfs_fromle32(nhead); -// if (err) { -// return err; -// } -// } -// } -// -// *block = nblock; -// *off = 4*skips; -// return 0; -// } -// -//relocate: -// LFS_DEBUG("Bad block at 0x%"PRIx32, nblock); -// -// // just clear cache and try a new block -// lfs_cache_drop(lfs, pcache); -// } -//} -//#endif -// -//static int lfs_ctz_traverse(lfs_t *lfs, -// const lfs_cache_t *pcache, lfs_cache_t *rcache, -// lfs_block_t head, lfs_size_t size, -// int (*cb)(void*, lfs_block_t), void *data) { -// if (size == 0) { -// return 0; -// } -// -// lfs_off_t index = lfs_ctz_index(lfs, &(lfs_off_t){size-1}); -// -// while (true) { -// int err = cb(data, head); -// if (err) { -// return err; -// } -// -// if (index == 0) { -// return 0; -// } -// -// lfs_block_t heads[2]; -// int count = 2 - (index & 1); -// err = lfs_bd_read(lfs, -// pcache, rcache, count*sizeof(head), -// head, 0, &heads, count*sizeof(head)); -// heads[0] = lfs_fromle32(heads[0]); -// heads[1] = lfs_fromle32(heads[1]); -// if (err) { -// return err; -// } -// -// for (int i = 0; i < count-1; i++) { -// err = cb(data, heads[i]); -// if (err) { -// return err; -// } -// } -// -// head = heads[count-1]; -// index -= count; -// } -//} -// -// -///// Top level file operations /// -//static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file, -// const char *path, int flags, -// const struct lfs_file_config *cfg) { -//#ifndef LFS_READONLY -// // deorphan if we haven't yet, needed at most once after poweron -// if ((flags & LFS_O_WRONLY) == LFS_O_WRONLY) { -// int err = lfs_fs_forceconsistency(lfs); -// if (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; -// file->pos = 0; -// file->off = 0; -// file->cache.buffer = NULL; -// -// // allocate entry for file if it doesn't exist -// lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id); -// if (tag < 0 && !(tag == LFS_ERR_NOENT && file->id != 0x3ff)) { -// err = tag; -// goto cleanup; -// } -// -// // get id, add to list of mdirs to catch update changes -// file->m.type = LFS_TYPE_REG; -// 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; -// goto cleanup; -// } -// -// // check that name fits -// lfs_size_t nlen = strlen(path); -// if (nlen > lfs->name_max) { -// err = LFS_ERR_NAMETOOLONG; -// goto cleanup; -// } -// -// // get next slot and create entry to remember name -// err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_CREATE, file->id, 0), NULL}, -// {LFS_MKTAG(LFS_TYPE_REG, file->id, nlen), path}, -// {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), NULL})); -// -// // it may happen that the file name doesn't fit in the metadata blocks, e.g., a 256 byte file name will -// // not fit in a 128 byte block. -// err = (err == LFS_ERR_NOSPC) ? LFS_ERR_NAMETOOLONG : err; -// if (err) { -// goto cleanup; -// } -// -// tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0); -// } 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), -// LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz); -// if (tag < 0) { -// err = tag; -// goto cleanup; -// } -// lfs_ctz_fromle32(&file->ctz); -// } -// -// // fetch attrs -// for (unsigned i = 0; i < file->cfg->attr_count; i++) { -// // 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, -// file->id, file->cfg->attrs[i].size), -// file->cfg->attrs[i].buffer); -// if (res < 0 && res != LFS_ERR_NOENT) { -// err = res; -// goto cleanup; -// } -// } -// -//#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; -// } -// -// file->flags |= LFS_F_DIRTY; -// } -//#endif -// } -// -// // allocate buffer if needed -// if (file->cfg->buffer) { -// file->cache.buffer = file->cfg->buffer; -// } else { -// file->cache.buffer = lfs_malloc(lfs->cfg->cache_size); -// if (!file->cache.buffer) { -// err = LFS_ERR_NOMEM; -// goto cleanup; -// } -// } -// -// // zero to avoid information leak -// lfs_cache_zero(lfs, &file->cache); -// -// if (lfs_tag_type3(tag) == LFS_TYPE_INLINESTRUCT) { -// // load inline files -// file->ctz.head = LFS_BLOCK_INLINE; -// file->ctz.size = lfs_tag_size(tag); -// file->flags |= LFS_F_INLINE; -// file->cache.block = file->ctz.head; -// file->cache.off = 0; -// file->cache.size = lfs->cfg->cache_size; -// -// // don't always read (may be new/trunc file) -// if (file->ctz.size > 0) { -// lfs_stag_t res = lfs_dir_get(lfs, &file->m, -// LFS_MKTAG(0x700, 0x3ff, 0), -// LFS_MKTAG(LFS_TYPE_STRUCT, file->id, -// lfs_min(file->cache.size, 0x3fe)), -// file->cache.buffer); -// if (res < 0) { -// err = res; -// goto cleanup; -// } -// } -// } -// -// return 0; -// -//cleanup: -// // clean up lingering resources -//#ifndef LFS_READONLY -// file->flags |= LFS_F_ERRED; -//#endif -// lfs_file_rawclose(lfs, file); -// return err; -//} -// -//#ifndef LFS_NO_MALLOC -//static int lfs_file_rawopen(lfs_t *lfs, lfs_file_t *file, -// const char *path, int flags) { -// static const struct lfs_file_config defaults = {0}; -// int err = lfs_file_rawopencfg(lfs, file, path, flags, &defaults); -// return err; -//} -//#endif -// -//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 -// lfs_mlist_remove(lfs, (struct lfs_mlist*)file); -// -// // clean up memory -// if (!file->cfg->buffer) { -// lfs_free(file->cache.buffer); -// } -// -// return err; -//} -// -// -//#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; -// int err = lfs_alloc(lfs, &nblock); -// if (err) { -// return err; -// } -// -// err = lfs_bd_erase(lfs, nblock); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// -// // either read from dirty cache or disk -// for (lfs_off_t i = 0; i < file->off; i++) { -// uint8_t data; -// if (file->flags & LFS_F_INLINE) { -// err = lfs_dir_getread(lfs, &file->m, -// // note we evict inline files before they can be dirty -// NULL, &file->cache, file->off-i, -// LFS_MKTAG(0xfff, 0x1ff, 0), -// LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), -// i, &data, 1); -// if (err) { -// return err; -// } -// } else { -// err = lfs_bd_read(lfs, -// &file->cache, &lfs->rcache, file->off-i, -// file->block, i, &data, 1); -// if (err) { -// return err; -// } -// } -// -// err = lfs_bd_prog(lfs, -// &lfs->pcache, &lfs->rcache, true, -// nblock, i, &data, 1); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// } -// -// // copy over new state of file -// memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->cache_size); -// file->cache.block = lfs->pcache.block; -// file->cache.off = lfs->pcache.off; -// file->cache.size = lfs->pcache.size; -// lfs_cache_zero(lfs, &lfs->pcache); -// -// file->block = nblock; -// file->flags |= LFS_F_WRITING; -// return 0; -// -//relocate: -// LFS_DEBUG("Bad block at 0x%"PRIx32, nblock); -// -// // just clear cache and try a new block -// 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); -// int err = lfs_file_relocate(lfs, file); -// if (err) { -// return err; -// } -// -// file->flags &= ~LFS_F_INLINE; -// return 0; -//} -//#endif -// -//static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { -// if (file->flags & LFS_F_READING) { -// if (!(file->flags & LFS_F_INLINE)) { -// lfs_cache_drop(lfs, &file->cache); -// } -// file->flags &= ~LFS_F_READING; -// } -// -//#ifndef LFS_READONLY -// if (file->flags & LFS_F_WRITING) { -// lfs_off_t pos = file->pos; -// -// if (!(file->flags & LFS_F_INLINE)) { -// // copy over anything after current branch -// lfs_file_t orig = { -// .ctz.head = file->ctz.head, -// .ctz.size = file->ctz.size, -// .flags = LFS_O_RDONLY, -// .pos = file->pos, -// .cache = lfs->rcache, -// }; -// lfs_cache_drop(lfs, &lfs->rcache); -// -// while (file->pos < file->ctz.size) { -// // 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_flushedread(lfs, &orig, &data, 1); -// if (res < 0) { -// return res; -// } -// -// res = lfs_file_flushedwrite(lfs, file, &data, 1); -// if (res < 0) { -// return res; -// } -// -// // keep our reference to the rcache in sync -// if (lfs->rcache.block != LFS_BLOCK_NULL) { -// lfs_cache_drop(lfs, &orig.cache); -// lfs_cache_drop(lfs, &lfs->rcache); -// } -// } -// -// // write out what we have -// while (true) { -// int err = lfs_bd_flush(lfs, &file->cache, &lfs->rcache, true); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// return err; -// } -// -// break; -// -//relocate: -// LFS_DEBUG("Bad block at 0x%"PRIx32, file->block); -// err = lfs_file_relocate(lfs, file); -// if (err) { -// return err; -// } -// } -// } else { -// file->pos = lfs_max(file->pos, file->ctz.size); -// } -// -// // actual file updates -// file->ctz.head = file->block; -// file->ctz.size = file->pos; -// file->flags &= ~LFS_F_WRITING; -// file->flags |= LFS_F_DIRTY; -// -// file->pos = pos; -// } -//#endif -// -// return 0; -//} -// -//#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 -// return 0; -// } -// -// int err = lfs_file_flush(lfs, file); -// if (err) { -// file->flags |= LFS_F_ERRED; -// return err; -// } -// -// -// if ((file->flags & LFS_F_DIRTY) && -// !lfs_pair_isnull(file->m.pair)) { -// // update dir entry -// uint16_t type; -// const void *buffer; -// lfs_size_t size; -// struct lfs_ctz ctz; -// if (file->flags & LFS_F_INLINE) { -// // inline the whole file -// type = LFS_TYPE_INLINESTRUCT; -// buffer = file->cache.buffer; -// size = file->ctz.size; -// } else { -// // update the ctz reference -// type = LFS_TYPE_CTZSTRUCT; -// // copy ctz so alloc will work during a relocate -// ctz = file->ctz; -// lfs_ctz_tole32(&ctz); -// buffer = &ctz; -// size = sizeof(ctz); -// } -// -// // commit file data and attributes -// err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( -// {LFS_MKTAG(type, file->id, size), buffer}, -// {LFS_MKTAG(LFS_FROM_USERATTRS, file->id, -// file->cfg->attr_count), file->cfg->attrs})); -// if (err) { -// file->flags |= LFS_F_ERRED; -// return err; -// } -// -// file->flags &= ~LFS_F_DIRTY; -// } -// -// return 0; -//} -//#endif -// -//static lfs_ssize_t lfs_file_flushedread(lfs_t *lfs, lfs_file_t *file, -// void *buffer, lfs_size_t size) { -// uint8_t *data = buffer; -// lfs_size_t nsize = size; -// -// if (file->pos >= file->ctz.size) { -// // eof if past end -// return 0; -// } -// -// size = lfs_min(size, file->ctz.size - file->pos); -// nsize = size; -// -// while (nsize > 0) { -// // check if we need a new block -// if (!(file->flags & LFS_F_READING) || -// file->off == lfs->cfg->block_size) { -// if (!(file->flags & LFS_F_INLINE)) { -// int err = lfs_ctz_find(lfs, NULL, &file->cache, -// file->ctz.head, file->ctz.size, -// file->pos, &file->block, &file->off); -// if (err) { -// return err; -// } -// } else { -// file->block = LFS_BLOCK_INLINE; -// file->off = file->pos; -// } -// -// file->flags |= LFS_F_READING; -// } -// -// // read as much as we can in current block -// lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); -// if (file->flags & LFS_F_INLINE) { -// int err = lfs_dir_getread(lfs, &file->m, -// NULL, &file->cache, lfs->cfg->block_size, -// LFS_MKTAG(0xfff, 0x1ff, 0), -// LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), -// file->off, data, diff); -// if (err) { -// return err; -// } -// } else { -// int err = lfs_bd_read(lfs, -// NULL, &file->cache, lfs->cfg->block_size, -// file->block, file->off, data, diff); -// if (err) { -// return err; -// } -// } -// -// file->pos += diff; -// file->off += diff; -// data += diff; -// nsize -= diff; -// } -// -// return size; -//} -// -//static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file, -// void *buffer, lfs_size_t size) { -// LFS_ASSERT((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY); -// -//#ifndef LFS_READONLY -// if (file->flags & LFS_F_WRITING) { -// // flush out any writes -// int err = lfs_file_flush(lfs, file); -// if (err) { -// return err; -// } -// } -//#endif -// -// return lfs_file_flushedread(lfs, file, buffer, size); -//} -// -// -//#ifndef LFS_READONLY -//static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file, -// const void *buffer, lfs_size_t size) { -// const uint8_t *data = buffer; -// lfs_size_t nsize = size; -// -// if ((file->flags & LFS_F_INLINE) && -// lfs_max(file->pos+nsize, file->ctz.size) > -// lfs_min(0x3fe, lfs_min( -// lfs->cfg->cache_size, -// (lfs->cfg->metadata_max ? -// lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) { -// // inline file doesn't fit anymore -// int err = lfs_file_outline(lfs, file); -// if (err) { -// file->flags |= LFS_F_ERRED; -// return err; -// } -// } -// -// while (nsize > 0) { -// // check if we need a new block -// if (!(file->flags & LFS_F_WRITING) || -// file->off == lfs->cfg->block_size) { -// if (!(file->flags & LFS_F_INLINE)) { -// if (!(file->flags & LFS_F_WRITING) && file->pos > 0) { -// // find out which block we're extending from -// int err = lfs_ctz_find(lfs, NULL, &file->cache, -// file->ctz.head, file->ctz.size, -// file->pos-1, &file->block, &file->off); -// if (err) { -// file->flags |= LFS_F_ERRED; -// return err; -// } -// -// // mark cache as dirty since we may have read data into it -// lfs_cache_zero(lfs, &file->cache); -// } -// -// // extend file with new blocks -// lfs_alloc_ack(lfs); -// int err = lfs_ctz_extend(lfs, &file->cache, &lfs->rcache, -// file->block, file->pos, -// &file->block, &file->off); -// if (err) { -// file->flags |= LFS_F_ERRED; -// return err; -// } -// } else { -// file->block = LFS_BLOCK_INLINE; -// file->off = file->pos; -// } -// -// file->flags |= LFS_F_WRITING; -// } -// -// // program as much as we can in current block -// lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->off); -// while (true) { -// int err = lfs_bd_prog(lfs, &file->cache, &lfs->rcache, true, -// file->block, file->off, data, diff); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// goto relocate; -// } -// file->flags |= LFS_F_ERRED; -// return err; -// } -// -// break; -//relocate: -// err = lfs_file_relocate(lfs, file); -// if (err) { -// file->flags |= LFS_F_ERRED; -// return err; -// } -// } -// -// file->pos += diff; -// file->off += diff; -// data += diff; -// nsize -= diff; -// -// lfs_alloc_ack(lfs); -// } -// -// return size; -//} -// -//static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file, -// const void *buffer, lfs_size_t size) { -// LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY); -// -// if (file->flags & LFS_F_READING) { -// // drop any reads -// int err = lfs_file_flush(lfs, file); -// if (err) { -// return err; -// } -// } -// -// if ((file->flags & LFS_O_APPEND) && file->pos < file->ctz.size) { -// file->pos = file->ctz.size; -// } -// -// if (file->pos + size > lfs->file_max) { -// // Larger than file limit? -// return LFS_ERR_FBIG; -// } -// -// if (!(file->flags & LFS_F_WRITING) && file->pos > file->ctz.size) { -// // fill with zeros -// lfs_off_t pos = file->pos; -// file->pos = file->ctz.size; -// -// while (file->pos < pos) { -// lfs_ssize_t res = lfs_file_flushedwrite(lfs, file, &(uint8_t){0}, 1); -// if (res < 0) { -// return res; -// } -// } -// } -// -// lfs_ssize_t nsize = lfs_file_flushedwrite(lfs, file, buffer, size); -// if (nsize < 0) { -// return nsize; -// } -// -// file->flags &= ~LFS_F_ERRED; -// return nsize; -//} -//#endif -// -//static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file, -// lfs_soff_t off, int whence) { -// // find new pos -// lfs_off_t npos = file->pos; -// if (whence == LFS_SEEK_SET) { -// npos = off; -// } else if (whence == LFS_SEEK_CUR) { -// if ((lfs_soff_t)file->pos + off < 0) { -// return LFS_ERR_INVAL; -// } else { -// npos = file->pos + off; -// } -// } else if (whence == LFS_SEEK_END) { -// lfs_soff_t res = lfs_file_rawsize(lfs, file) + off; -// if (res < 0) { -// return LFS_ERR_INVAL; -// } else { -// npos = res; -// } -// } -// -// if (npos > lfs->file_max) { -// // file position out of range -// return LFS_ERR_INVAL; -// } -// -// if (file->pos == npos) { -// // noop - position has not changed -// return npos; -// } -// -// // if we're only reading and our new offset is still in the file's cache -// // we can avoid flushing and needing to reread the data -// if ( -//#ifndef LFS_READONLY -// !(file->flags & LFS_F_WRITING) -//#else -// true -//#endif -// ) { -// int oindex = lfs_ctz_index(lfs, &(lfs_off_t){file->pos}); -// lfs_off_t noff = npos; -// int nindex = lfs_ctz_index(lfs, &noff); -// if (oindex == nindex -// && noff >= file->cache.off -// && noff < file->cache.off + file->cache.size) { -// file->pos = npos; -// file->off = noff; -// return npos; -// } -// } -// -// // write out everything beforehand, may be noop if rdonly -// int err = lfs_file_flush(lfs, file); -// if (err) { -// return err; -// } -// -// // update pos -// file->pos = npos; -// return npos; -//} -// -//#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) { -// return LFS_ERR_INVAL; -// } -// -// lfs_off_t pos = file->pos; -// 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) { -// return err; -// } -// -// // lookup new head in ctz skip list -// err = lfs_ctz_find(lfs, NULL, &file->cache, -// file->ctz.head, file->ctz.size, -// size, &file->block, &file->off); -// if (err) { -// return err; -// } -// -// // need to set pos/block/off consistently so seeking back to -// // the old position does not get confused -// file->pos = size; -// file->ctz.head = file->block; -// file->ctz.size = size; -// file->flags |= LFS_F_DIRTY | LFS_F_READING; -// } else if (size > oldsize) { -// // flush+seek if not already at end -// lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END); -// if (res < 0) { -// return (int)res; -// } -// -// // fill with zeros -// while (file->pos < size) { -// res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1); -// if (res < 0) { -// return (int)res; -// } -// } -// } -// -// // restore pos -// lfs_soff_t res = lfs_file_rawseek(lfs, file, pos, LFS_SEEK_SET); -// if (res < 0) { -// return (int)res; -// } -// -// return 0; -//} -//#endif -// -//static lfs_soff_t lfs_file_rawtell(lfs_t *lfs, lfs_file_t *file) { -// (void)lfs; -// return file->pos; -//} -// -//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) { -// return (int)res; -// } -// -// return 0; -//} -// -//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) { -// return lfs_max(file->pos, file->ctz.size); -// } -//#endif -// -// return file->ctz.size; -//} -// -// -///// General fs operations /// -//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) { -// return (int)tag; -// } -// -// return lfs_dir_getinfo(lfs, &cwd, lfs_tag_id(tag), info); -//} -// -//#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) { -// 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) { -// return (tag < 0) ? (int)tag : LFS_ERR_INVAL; -// } -// -// struct lfs_mlist dir; -// dir.next = lfs->mlist; -// if (lfs_tag_type3(tag) == LFS_TYPE_DIR) { -// // must be empty before removal -// lfs_block_t pair[2]; -// 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) { -// return (int)res; -// } -// lfs_pair_fromle32(pair); -// -// err = lfs_dir_fetch(lfs, &dir.m, pair); -// if (err) { -// return err; -// } -// -// if (dir.m.count > 0 || dir.m.split) { -// return LFS_ERR_NOTEMPTY; -// } -// -// // mark fs as orphaned -// err = lfs_fs_preporphans(lfs, +1); -// if (err) { -// return err; -// } -// -// // I know it's crazy but yes, dir can be changed by our parent's -// // commit (if predecessor is child) -// dir.type = 0; -// dir.id = 0; -// lfs->mlist = &dir; -// } -// -// // delete the entry -// err = lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(tag), 0), NULL})); -// if (err) { -// lfs->mlist = dir.next; -// return err; -// } -// -// lfs->mlist = dir.next; -// if (lfs_tag_type3(tag) == LFS_TYPE_DIR) { -// // fix orphan -// err = lfs_fs_preporphans(lfs, -1); -// if (err) { -// return err; -// } -// -// err = lfs_fs_pred(lfs, dir.m.pair, &cwd); -// if (err) { -// return err; -// } -// -// err = lfs_dir_drop(lfs, &cwd, &dir.m); -// if (err) { -// return err; -// } -// } -// -// return 0; -//} -//#endif -// -//#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) { -// return err; -// } -// -// // find old entry -// lfs_mdir_t oldcwd; -// lfs_stag_t oldtag = lfs_dir_find(lfs, &oldcwd, &oldpath, NULL); -// if (oldtag < 0 || lfs_tag_id(oldtag) == 0x3ff) { -// return (oldtag < 0) ? (int)oldtag : LFS_ERR_INVAL; -// } -// -// // find new entry -// lfs_mdir_t newcwd; -// uint16_t newid; -// lfs_stag_t prevtag = lfs_dir_find(lfs, &newcwd, &newpath, &newid); -// if ((prevtag < 0 || lfs_tag_id(prevtag) == 0x3ff) && -// !(prevtag == LFS_ERR_NOENT && newid != 0x3ff)) { -// return (prevtag < 0) ? (int)prevtag : LFS_ERR_INVAL; -// } -// -// // if we're in the same pair there's a few special cases... -// bool samepair = (lfs_pair_cmp(oldcwd.pair, newcwd.pair) == 0); -// uint16_t newoldid = lfs_tag_id(oldtag); -// -// struct lfs_mlist prevdir; -// prevdir.next = lfs->mlist; -// if (prevtag == LFS_ERR_NOENT) { -// // check that name fits -// lfs_size_t nlen = strlen(newpath); -// if (nlen > lfs->name_max) { -// return LFS_ERR_NAMETOOLONG; -// } -// -// // there is a small chance we are being renamed in the same -// // directory/ to an id less than our old id, the global update -// // to handle this is a bit messy -// if (samepair && newid <= newoldid) { -// newoldid += 1; -// } -// } else if (lfs_tag_type3(prevtag) != lfs_tag_type3(oldtag)) { -// return LFS_ERR_ISDIR; -// } else if (samepair && newid == newoldid) { -// // we're renaming to ourselves?? -// return 0; -// } else if (lfs_tag_type3(prevtag) == LFS_TYPE_DIR) { -// // must be empty before removal -// lfs_block_t prevpair[2]; -// 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) { -// return (int)res; -// } -// lfs_pair_fromle32(prevpair); -// -// // must be empty before removal -// err = lfs_dir_fetch(lfs, &prevdir.m, prevpair); -// if (err) { -// return err; -// } -// -// if (prevdir.m.count > 0 || prevdir.m.split) { -// return LFS_ERR_NOTEMPTY; -// } -// -// // mark fs as orphaned -// err = lfs_fs_preporphans(lfs, +1); -// if (err) { -// return err; -// } -// -// // I know it's crazy but yes, dir can be changed by our parent's -// // commit (if predecessor is child) -// prevdir.type = 0; -// prevdir.id = 0; -// lfs->mlist = &prevdir; -// } -// -// if (!samepair) { -// lfs_fs_prepmove(lfs, newoldid, oldcwd.pair); -// } -// -// // move over all attributes -// err = lfs_dir_commit(lfs, &newcwd, LFS_MKATTRS( -// {LFS_MKTAG_IF(prevtag != LFS_ERR_NOENT, -// LFS_TYPE_DELETE, newid, 0), NULL}, -// {LFS_MKTAG(LFS_TYPE_CREATE, newid, 0), NULL}, -// {LFS_MKTAG(lfs_tag_type3(oldtag), newid, strlen(newpath)), newpath}, -// {LFS_MKTAG(LFS_FROM_MOVE, newid, lfs_tag_id(oldtag)), &oldcwd}, -// {LFS_MKTAG_IF(samepair, -// LFS_TYPE_DELETE, newoldid, 0), NULL})); -// if (err) { -// lfs->mlist = prevdir.next; -// return err; -// } -// -// // let commit clean up after move (if we're different! otherwise move -// // logic already fixed it for us) -// if (!samepair && lfs_gstate_hasmove(&lfs->gstate)) { -// // prep gstate and delete move id -// lfs_fs_prepmove(lfs, 0x3ff, NULL); -// err = lfs_dir_commit(lfs, &oldcwd, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(oldtag), 0), NULL})); -// if (err) { -// lfs->mlist = prevdir.next; -// return err; -// } -// } -// -// lfs->mlist = prevdir.next; -// if (prevtag != LFS_ERR_NOENT -// && lfs_tag_type3(prevtag) == LFS_TYPE_DIR) { -// // fix orphan -// err = lfs_fs_preporphans(lfs, -1); -// if (err) { -// return err; -// } -// -// err = lfs_fs_pred(lfs, prevdir.m.pair, &newcwd); -// if (err) { -// return err; -// } -// -// err = lfs_dir_drop(lfs, &newcwd, &prevdir.m); -// if (err) { -// return err; -// } -// } -// -// return 0; -//} -//#endif -// -//static lfs_ssize_t lfs_rawgetattr(lfs_t *lfs, const char *path, -// uint8_t type, void *buffer, lfs_size_t size) { -// lfs_mdir_t cwd; -// lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); -// if (tag < 0) { -// return tag; -// } -// -// uint16_t id = lfs_tag_id(tag); -// if (id == 0x3ff) { -// // special case for root -// id = 0; -// int err = lfs_dir_fetch(lfs, &cwd, lfs->root); -// if (err) { -// return err; -// } -// } -// -// tag = lfs_dir_get(lfs, &cwd, LFS_MKTAG(0x7ff, 0x3ff, 0), -// LFS_MKTAG(LFS_TYPE_USERATTR + type, -// id, lfs_min(size, lfs->attr_max)), -// buffer); -// if (tag < 0) { -// if (tag == LFS_ERR_NOENT) { -// return LFS_ERR_NOATTR; -// } -// -// return tag; -// } -// -// 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; -// lfs_stag_t tag = lfs_dir_find(lfs, &cwd, &path, NULL); -// if (tag < 0) { -// return tag; -// } -// -// uint16_t id = lfs_tag_id(tag); -// if (id == 0x3ff) { -// // special case for root -// id = 0; -// int err = lfs_dir_fetch(lfs, &cwd, lfs->root); -// if (err) { -// return err; -// } -// } -// -// return lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer})); -//} -//#endif -// -//#ifndef LFS_READONLY -//static int lfs_rawsetattr(lfs_t *lfs, const char *path, -// uint8_t type, const void *buffer, lfs_size_t size) { -// if (size > lfs->attr_max) { -// return LFS_ERR_NOSPC; -// } -// -// return lfs_commitattr(lfs, path, type, buffer, size); -//} -//#endif -// -//#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 -// -//#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) { -// return err; -// } -// -// // create free lookahead -// memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); -// lfs->free.off = 0; -// lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, -// lfs->cfg->block_count); -// lfs->free.i = 0; -// lfs_alloc_ack(lfs); -// -// // create root dir -// lfs_mdir_t root; -// err = lfs_dir_alloc(lfs, &root); -// if (err) { -// goto cleanup; -// } -// -// // write one superblock -// lfs_superblock_t superblock = { -// .version = LFS_DISK_VERSION, -// .block_size = lfs->cfg->block_size, -// .block_count = lfs->cfg->block_count, -// .name_max = lfs->name_max, -// .file_max = lfs->file_max, -// .attr_max = lfs->attr_max, -// }; -// -// lfs_superblock_tole32(&superblock); -// err = lfs_dir_commit(lfs, &root, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL}, -// {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, -// {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), -// &superblock})); -// if (err) { -// goto cleanup; -// } -// -// // force compaction to prevent accidentally mounting any -// // older version of littlefs that may live on disk -// root.erased = false; -// err = lfs_dir_commit(lfs, &root, NULL, 0); -// if (err) { -// goto cleanup; -// } -// -// // sanity check that fetch works -// err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1}); -// if (err) { -// goto cleanup; -// } -// } -// -//cleanup: -// lfs_deinit(lfs); -// return err; -// -//} -//#endif -// -//static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) { -// int err = lfs_init(lfs, cfg); -// if (err) { -// return err; -// } -// -// // scan directory blocks for superblock and any global updates -// lfs_mdir_t dir = {.tail = {0, 1}}; -// lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; -// lfs_size_t tortoise_i = 1; -// lfs_size_t tortoise_period = 1; -// while (!lfs_pair_isnull(dir.tail)) { -// // detect cycles with Brent's algorithm -// if (lfs_pair_issync(dir.tail, tortoise)) { -// LFS_ERROR("Cycle detected in tail list"); -// err = LFS_ERR_CORRUPT; -// goto cleanup; -// } -// if (tortoise_i == tortoise_period) { -// tortoise[0] = dir.tail[0]; -// tortoise[1] = dir.tail[1]; -// tortoise_i = 0; -// tortoise_period *= 2; -// } -// tortoise_i += 1; -// -// // fetch next block in tail list -// lfs_stag_t tag = lfs_dir_fetchmatch(lfs, &dir, dir.tail, -// LFS_MKTAG(0x7ff, 0x3ff, 0), -// LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), -// NULL, -// lfs_dir_find_match, &(struct lfs_dir_find_match){ -// lfs, "littlefs", 8}); -// if (tag < 0) { -// err = tag; -// goto cleanup; -// } -// -// // has superblock? -// if (tag && !lfs_tag_isdelete(tag)) { -// // update root -// lfs->root[0] = dir.pair[0]; -// lfs->root[1] = dir.pair[1]; -// -// // grab superblock -// lfs_superblock_t superblock; -// tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x7ff, 0x3ff, 0), -// LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), -// &superblock); -// if (tag < 0) { -// err = tag; -// goto cleanup; -// } -// lfs_superblock_fromle32(&superblock); -// -// // check version -// uint16_t major_version = (0xffff & (superblock.version >> 16)); -// uint16_t minor_version = (0xffff & (superblock.version >> 0)); -// if ((major_version != LFS_DISK_VERSION_MAJOR || -// minor_version > LFS_DISK_VERSION_MINOR)) { -// LFS_ERROR("Invalid version v%"PRIu16".%"PRIu16, -// major_version, minor_version); -// err = LFS_ERR_INVAL; -// goto cleanup; -// } -// -// // check superblock configuration -// if (superblock.name_max) { -// if (superblock.name_max > lfs->name_max) { -// LFS_ERROR("Unsupported name_max (%"PRIu32" > %"PRIu32")", -// superblock.name_max, lfs->name_max); -// err = LFS_ERR_INVAL; -// goto cleanup; -// } -// -// lfs->name_max = superblock.name_max; -// } -// -// if (superblock.file_max) { -// if (superblock.file_max > lfs->file_max) { -// LFS_ERROR("Unsupported file_max (%"PRIu32" > %"PRIu32")", -// superblock.file_max, lfs->file_max); -// err = LFS_ERR_INVAL; -// goto cleanup; -// } -// -// lfs->file_max = superblock.file_max; -// } -// -// if (superblock.attr_max) { -// if (superblock.attr_max > lfs->attr_max) { -// LFS_ERROR("Unsupported attr_max (%"PRIu32" > %"PRIu32")", -// superblock.attr_max, lfs->attr_max); -// err = LFS_ERR_INVAL; -// goto cleanup; -// } -// -// lfs->attr_max = superblock.attr_max; -// } -// -// if (superblock.block_count != lfs->cfg->block_count) { -// LFS_ERROR("Invalid block count (%"PRIu32" != %"PRIu32")", -// superblock.block_count, lfs->cfg->block_count); -// err = LFS_ERR_INVAL; -// goto cleanup; -// } -// -// if (superblock.block_size != lfs->cfg->block_size) { -// LFS_ERROR("Invalid block size (%"PRIu32" != %"PRIu32")", -// superblock.block_size, lfs->cfg->block_size); -// err = LFS_ERR_INVAL; -// goto cleanup; -// } -// } -// -// // has gstate? -// err = lfs_dir_getgstate(lfs, &dir, &lfs->gstate); -// if (err) { -// goto cleanup; -// } -// } -// -// // found superblock? -// if (lfs_pair_isnull(lfs->root)) { -// err = LFS_ERR_INVAL; -// goto cleanup; -// } -// -// // update littlefs with gstate -// if (!lfs_gstate_iszero(&lfs->gstate)) { -// LFS_DEBUG("Found pending gstate 0x%08"PRIx32"%08"PRIx32"%08"PRIx32, -// lfs->gstate.tag, -// lfs->gstate.pair[0], -// lfs->gstate.pair[1]); -// } -// lfs->gstate.tag += !lfs_tag_isvalid(lfs->gstate.tag); -// lfs->gdisk = lfs->gstate; -// -// // 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); -// -// return 0; -// -//cleanup: -// lfs_rawunmount(lfs); -// return err; -//} -// -//static int lfs_rawunmount(lfs_t *lfs) { -// return lfs_deinit(lfs); -//} -// -// -///// Filesystem filesystem operations /// -//int lfs_fs_rawtraverse(lfs_t *lfs, -// int (*cb)(void *data, lfs_block_t block), void *data, -// bool includeorphans) { -// // iterate over metadata pairs -// lfs_mdir_t dir = {.tail = {0, 1}}; -// -//#ifdef LFS_MIGRATE -// // also consider v1 blocks during migration -// if (lfs->lfs1) { -// int err = lfs1_traverse(lfs, cb, data); -// if (err) { -// return err; -// } -// -// dir.tail[0] = lfs->root[0]; -// dir.tail[1] = lfs->root[1]; -// } -//#endif -// -// lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; -// lfs_size_t tortoise_i = 1; -// lfs_size_t tortoise_period = 1; -// while (!lfs_pair_isnull(dir.tail)) { -// // detect cycles with Brent's algorithm -// if (lfs_pair_issync(dir.tail, tortoise)) { -// LFS_WARN("Cycle detected in tail list"); -// return LFS_ERR_CORRUPT; -// } -// if (tortoise_i == tortoise_period) { -// tortoise[0] = dir.tail[0]; -// tortoise[1] = dir.tail[1]; -// tortoise_i = 0; -// tortoise_period *= 2; -// } -// tortoise_i += 1; -// -// for (int i = 0; i < 2; i++) { -// int err = cb(data, dir.tail[i]); -// if (err) { -// return err; -// } -// } -// -// // iterate through ids in directory -// int err = lfs_dir_fetch(lfs, &dir, dir.tail); -// if (err) { -// return err; -// } -// -// for (uint16_t id = 0; id < dir.count; id++) { -// struct lfs_ctz ctz; -// lfs_stag_t tag = lfs_dir_get(lfs, &dir, LFS_MKTAG(0x700, 0x3ff, 0), -// LFS_MKTAG(LFS_TYPE_STRUCT, id, sizeof(ctz)), &ctz); -// if (tag < 0) { -// if (tag == LFS_ERR_NOENT) { -// continue; -// } -// return tag; -// } -// lfs_ctz_fromle32(&ctz); -// -// if (lfs_tag_type3(tag) == LFS_TYPE_CTZSTRUCT) { -// err = lfs_ctz_traverse(lfs, NULL, &lfs->rcache, -// ctz.head, ctz.size, cb, data); -// if (err) { -// return err; -// } -// } else if (includeorphans && -// lfs_tag_type3(tag) == LFS_TYPE_DIRSTRUCT) { -// for (int i = 0; i < 2; i++) { -// err = cb(data, (&ctz.head)[i]); -// if (err) { -// return err; -// } -// } -// } -// } -// } -// -//#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) { -// continue; -// } -// -// if ((f->flags & LFS_F_DIRTY) && !(f->flags & LFS_F_INLINE)) { -// int err = lfs_ctz_traverse(lfs, &f->cache, &lfs->rcache, -// f->ctz.head, f->ctz.size, cb, data); -// if (err) { -// return err; -// } -// } -// -// if ((f->flags & LFS_F_WRITING) && !(f->flags & LFS_F_INLINE)) { -// int err = lfs_ctz_traverse(lfs, &f->cache, &lfs->rcache, -// f->block, f->pos, cb, data); -// if (err) { -// return err; -// } -// } -// } -//#endif -// -// return 0; -//} -// -//#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 -// pdir->tail[0] = 0; -// pdir->tail[1] = 1; -// lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; -// lfs_size_t tortoise_i = 1; -// lfs_size_t tortoise_period = 1; -// while (!lfs_pair_isnull(pdir->tail)) { -// // detect cycles with Brent's algorithm -// if (lfs_pair_issync(pdir->tail, tortoise)) { -// LFS_WARN("Cycle detected in tail list"); -// return LFS_ERR_CORRUPT; -// } -// if (tortoise_i == tortoise_period) { -// tortoise[0] = pdir->tail[0]; -// tortoise[1] = pdir->tail[1]; -// tortoise_i = 0; -// tortoise_period *= 2; -// } -// tortoise_i += 1; -// -// if (lfs_pair_cmp(pdir->tail, pair) == 0) { -// return 0; -// } -// -// int err = lfs_dir_fetch(lfs, pdir, pdir->tail); -// if (err) { -// return err; -// } -// } -// -// 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; -// lfs_t *lfs = find->lfs; -// const struct lfs_diskoff *disk = buffer; -// (void)tag; -// -// lfs_block_t child[2]; -// int err = lfs_bd_read(lfs, -// &lfs->pcache, &lfs->rcache, lfs->cfg->block_size, -// disk->block, disk->off, &child, sizeof(child)); -// if (err) { -// return err; -// } -// -// 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 -// parent->tail[0] = 0; -// parent->tail[1] = 1; -// lfs_block_t tortoise[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; -// lfs_size_t tortoise_i = 1; -// lfs_size_t tortoise_period = 1; -// while (!lfs_pair_isnull(parent->tail)) { -// // detect cycles with Brent's algorithm -// if (lfs_pair_issync(parent->tail, tortoise)) { -// LFS_WARN("Cycle detected in tail list"); -// return LFS_ERR_CORRUPT; -// } -// if (tortoise_i == tortoise_period) { -// tortoise[0] = parent->tail[0]; -// tortoise[1] = parent->tail[1]; -// tortoise_i = 0; -// tortoise_period *= 2; -// } -// tortoise_i += 1; -// -// lfs_stag_t tag = lfs_dir_fetchmatch(lfs, parent, parent->tail, -// LFS_MKTAG(0x7ff, 0, 0x3ff), -// LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 0, 8), -// NULL, -// lfs_fs_parent_match, &(struct lfs_fs_parent_match){ -// lfs, {pair[0], pair[1]}}); -// if (tag && tag != LFS_ERR_NOENT) { -// return tag; -// } -// } -// -// return LFS_ERR_NOENT; -//} -//#endif -// -//#ifndef LFS_READONLY -//static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) { -// LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0x000 || orphans >= 0); -// LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) < 0x3ff || 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)); -// -// return 0; -//} -//#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)) | -// ((id != 0x3ff) ? LFS_MKTAG(LFS_TYPE_DELETE, id, 0) : 0)); -// 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; -// } -// -// // Fix bad moves -// LFS_DEBUG("Fixing move {0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16, -// lfs->gdisk.pair[0], -// lfs->gdisk.pair[1], -// lfs_tag_id(lfs->gdisk.tag)); -// -// // no other gstate is supported at this time, so if we found something else -// // something most likely went wrong in gstate calculation -// LFS_ASSERT(lfs_tag_type3(lfs->gdisk.tag) == LFS_TYPE_DELETE); -// -// // fetch and delete the moved entry -// lfs_mdir_t movedir; -// int err = lfs_dir_fetch(lfs, &movedir, lfs->gdisk.pair); -// if (err) { -// return err; -// } -// -// // prep gstate and delete move id -// uint16_t moveid = lfs_tag_id(lfs->gdisk.tag); -// lfs_fs_prepmove(lfs, 0x3ff, NULL); -// err = lfs_dir_commit(lfs, &movedir, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_DELETE, moveid, 0), NULL})); -// if (err) { -// return err; -// } -// -// return 0; -//} -//#endif -// -//#ifndef LFS_READONLY -//static int lfs_fs_deorphan(lfs_t *lfs, bool powerloss) { -// if (!lfs_gstate_hasorphans(&lfs->gstate)) { -// return 0; -// } -// -// int8_t found = 0; -// -// // Check for orphans in two separate passes: -// // - 1 for half-orphans (relocations) -// // - 2 for full-orphans (removes/renames) -// // -// // Two separate passes are needed as half-orphans can contain outdated -// // references to full-orphans, effectively hiding them from the deorphan -// // search. -// // -// int pass = 0; -// while (pass < 2) { -// // Fix any orphans -// lfs_mdir_t pdir = {.split = true, .tail = {0, 1}}; -// lfs_mdir_t dir; -// bool moreorphans = false; -// -// // iterate over all directory directory entries -// while (!lfs_pair_isnull(pdir.tail)) { -// int err = lfs_dir_fetch(lfs, &dir, pdir.tail); -// if (err) { -// return err; -// } -// -// // check head blocks for orphans -// if (!pdir.split) { -// // check if we have a parent -// lfs_mdir_t parent; -// lfs_stag_t tag = lfs_fs_parent(lfs, pdir.tail, &parent); -// if (tag < 0 && tag != LFS_ERR_NOENT) { -// return tag; -// } -// -// if (pass == 0 && tag != LFS_ERR_NOENT) { -// lfs_block_t pair[2]; -// lfs_stag_t state = lfs_dir_get(lfs, &parent, -// LFS_MKTAG(0x7ff, 0x3ff, 0), tag, pair); -// if (state < 0) { -// return state; -// } -// lfs_pair_fromle32(pair); -// -// if (!lfs_pair_issync(pair, pdir.tail)) { -// // we have desynced -// LFS_DEBUG("Fixing half-orphan " -// "{0x%"PRIx32", 0x%"PRIx32"} " -// "-> {0x%"PRIx32", 0x%"PRIx32"}", -// pdir.tail[0], pdir.tail[1], pair[0], pair[1]); -// -// // fix pending move in this pair? this looks like an -// // optimization but is in fact _required_ since -// // relocating may outdate the move. -// uint16_t moveid = 0x3ff; -// if (lfs_gstate_hasmovehere(&lfs->gstate, pdir.pair)) { -// moveid = lfs_tag_id(lfs->gstate.tag); -// LFS_DEBUG("Fixing move while fixing orphans " -// "{0x%"PRIx32", 0x%"PRIx32"} 0x%"PRIx16"\n", -// pdir.pair[0], pdir.pair[1], moveid); -// lfs_fs_prepmove(lfs, 0x3ff, NULL); -// } -// -// lfs_pair_tole32(pair); -// state = lfs_dir_orphaningcommit(lfs, &pdir, LFS_MKATTRS( -// {LFS_MKTAG_IF(moveid != 0x3ff, -// LFS_TYPE_DELETE, moveid, 0), NULL}, -// {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), -// pair})); -// lfs_pair_fromle32(pair); -// if (state < 0) { -// return state; -// } -// -// found += 1; -// -// // did our commit create more orphans? -// if (state == LFS_OK_ORPHANED) { -// moreorphans = true; -// } -// -// // refetch tail -// continue; -// } -// } -// -// // note we only check for full orphans if we may have had a -// // power-loss, otherwise orphans are created intentionally -// // during operations such as lfs_mkdir -// if (pass == 1 && tag == LFS_ERR_NOENT && powerloss) { -// // we are an orphan -// LFS_DEBUG("Fixing orphan {0x%"PRIx32", 0x%"PRIx32"}", -// pdir.tail[0], pdir.tail[1]); -// -// // steal state -// err = lfs_dir_getgstate(lfs, &dir, &lfs->gdelta); -// if (err) { -// return err; -// } -// -// // steal tail -// lfs_pair_tole32(dir.tail); -// int state = lfs_dir_orphaningcommit(lfs, &pdir, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_TAIL + dir.split, 0x3ff, 8), -// dir.tail})); -// lfs_pair_fromle32(dir.tail); -// if (state < 0) { -// return state; -// } -// -// found += 1; -// -// // did our commit create more orphans? -// if (state == LFS_OK_ORPHANED) { -// moreorphans = true; -// } -// -// // refetch tail -// continue; -// } -// } -// -// pdir = dir; -// } -// -// pass = moreorphans ? 0 : pass+1; -// } -// -// // mark orphans as fixed -// return lfs_fs_preporphans(lfs, -lfs_min( -// lfs_gstate_getorphans(&lfs->gstate), -// found)); -//} -//#endif -// -//#ifndef LFS_READONLY -//static int lfs_fs_forceconsistency(lfs_t *lfs) { -// int err = lfs_fs_demove(lfs); -// if (err) { -// return err; -// } -// -// err = lfs_fs_deorphan(lfs, true); -// if (err) { -// return err; -// } -// -// return 0; -//} -//#endif -// -//static int lfs_fs_size_count(void *p, lfs_block_t block) { -// (void)block; -// lfs_size_t *size = p; -// *size += 1; -// return 0; -//} -// -//static lfs_ssize_t lfs_fs_rawsize(lfs_t *lfs) { -// lfs_size_t size = 0; -// int err = lfs_fs_rawtraverse(lfs, lfs_fs_size_count, &size, false); -// if (err) { -// return err; -// } -// -// return size; -//} -// -//#ifdef LFS_MIGRATE -//////// Migration from littelfs v1 below this ////// -// -///// Version info /// -// -//// Software library version -//// Major (top-nibble), incremented on backwards incompatible changes -//// Minor (bottom-nibble), incremented on feature additions -//#define LFS1_VERSION 0x00010007 -//#define LFS1_VERSION_MAJOR (0xffff & (LFS1_VERSION >> 16)) -//#define LFS1_VERSION_MINOR (0xffff & (LFS1_VERSION >> 0)) -// -//// Version of On-disk data structures -//// Major (top-nibble), incremented on backwards incompatible changes -//// Minor (bottom-nibble), incremented on feature additions -//#define LFS1_DISK_VERSION 0x00010001 -//#define LFS1_DISK_VERSION_MAJOR (0xffff & (LFS1_DISK_VERSION >> 16)) -//#define LFS1_DISK_VERSION_MINOR (0xffff & (LFS1_DISK_VERSION >> 0)) -// -// -///// v1 Definitions /// -// -//// File types -//enum lfs1_type { -// LFS1_TYPE_REG = 0x11, -// LFS1_TYPE_DIR = 0x22, -// LFS1_TYPE_SUPERBLOCK = 0x2e, -//}; -// -//typedef struct lfs1 { -// lfs_block_t root[2]; -//} lfs1_t; -// -//typedef struct lfs1_entry { -// lfs_off_t off; -// -// struct lfs1_disk_entry { -// uint8_t type; -// uint8_t elen; -// uint8_t alen; -// uint8_t nlen; -// union { -// struct { -// lfs_block_t head; -// lfs_size_t size; -// } file; -// lfs_block_t dir[2]; -// } u; -// } d; -//} lfs1_entry_t; -// -//typedef struct lfs1_dir { -// struct lfs1_dir *next; -// lfs_block_t pair[2]; -// lfs_off_t off; -// -// lfs_block_t head[2]; -// lfs_off_t pos; -// -// struct lfs1_disk_dir { -// uint32_t rev; -// lfs_size_t size; -// lfs_block_t tail[2]; -// } d; -//} lfs1_dir_t; -// -//typedef struct lfs1_superblock { -// lfs_off_t off; -// -// struct lfs1_disk_superblock { -// uint8_t type; -// uint8_t elen; -// uint8_t alen; -// uint8_t nlen; -// lfs_block_t root[2]; -// uint32_t block_size; -// uint32_t block_count; -// uint32_t version; -// char magic[8]; -// } d; -//} lfs1_superblock_t; -// -// -///// Low-level wrappers v1->v2 /// -//static void lfs1_crc(uint32_t *crc, const void *buffer, size_t size) { -// *crc = lfs_crc(*crc, buffer, size); -//} -// -//static int lfs1_bd_read(lfs_t *lfs, lfs_block_t block, -// lfs_off_t off, void *buffer, lfs_size_t size) { -// // if we ever do more than writes to alternating pairs, -// // this may need to consider pcache -// return lfs_bd_read(lfs, &lfs->pcache, &lfs->rcache, size, -// block, off, buffer, size); -//} -// -//static int lfs1_bd_crc(lfs_t *lfs, lfs_block_t block, -// lfs_off_t off, lfs_size_t size, uint32_t *crc) { -// for (lfs_off_t i = 0; i < size; i++) { -// uint8_t c; -// int err = lfs1_bd_read(lfs, block, off+i, &c, 1); -// if (err) { -// return err; -// } -// -// lfs1_crc(crc, &c, 1); -// } -// -// return 0; -//} -// -// -///// Endian swapping functions /// -//static void lfs1_dir_fromle32(struct lfs1_disk_dir *d) { -// d->rev = lfs_fromle32(d->rev); -// d->size = lfs_fromle32(d->size); -// d->tail[0] = lfs_fromle32(d->tail[0]); -// d->tail[1] = lfs_fromle32(d->tail[1]); -//} -// -//static void lfs1_dir_tole32(struct lfs1_disk_dir *d) { -// d->rev = lfs_tole32(d->rev); -// d->size = lfs_tole32(d->size); -// d->tail[0] = lfs_tole32(d->tail[0]); -// d->tail[1] = lfs_tole32(d->tail[1]); -//} -// -//static void lfs1_entry_fromle32(struct lfs1_disk_entry *d) { -// d->u.dir[0] = lfs_fromle32(d->u.dir[0]); -// d->u.dir[1] = lfs_fromle32(d->u.dir[1]); -//} -// -//static void lfs1_entry_tole32(struct lfs1_disk_entry *d) { -// d->u.dir[0] = lfs_tole32(d->u.dir[0]); -// d->u.dir[1] = lfs_tole32(d->u.dir[1]); -//} -// -//static void lfs1_superblock_fromle32(struct lfs1_disk_superblock *d) { -// d->root[0] = lfs_fromle32(d->root[0]); -// d->root[1] = lfs_fromle32(d->root[1]); -// d->block_size = lfs_fromle32(d->block_size); -// d->block_count = lfs_fromle32(d->block_count); -// d->version = lfs_fromle32(d->version); -//} -// -// -/////// Metadata pair and directory operations /// -//static inline lfs_size_t lfs1_entry_size(const lfs1_entry_t *entry) { -// return 4 + entry->d.elen + entry->d.alen + entry->d.nlen; -//} -// -//static int lfs1_dir_fetch(lfs_t *lfs, -// lfs1_dir_t *dir, const lfs_block_t pair[2]) { -// // copy out pair, otherwise may be aliasing dir -// const lfs_block_t tpair[2] = {pair[0], pair[1]}; -// bool valid = false; -// -// // check both blocks for the most recent revision -// for (int i = 0; i < 2; i++) { -// struct lfs1_disk_dir test; -// int err = lfs1_bd_read(lfs, tpair[i], 0, &test, sizeof(test)); -// lfs1_dir_fromle32(&test); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// continue; -// } -// return err; -// } -// -// if (valid && lfs_scmp(test.rev, dir->d.rev) < 0) { -// continue; -// } -// -// if ((0x7fffffff & test.size) < sizeof(test)+4 || -// (0x7fffffff & test.size) > lfs->cfg->block_size) { -// continue; -// } -// -// uint32_t crc = 0xffffffff; -// lfs1_dir_tole32(&test); -// lfs1_crc(&crc, &test, sizeof(test)); -// lfs1_dir_fromle32(&test); -// err = lfs1_bd_crc(lfs, tpair[i], sizeof(test), -// (0x7fffffff & test.size) - sizeof(test), &crc); -// if (err) { -// if (err == LFS_ERR_CORRUPT) { -// continue; -// } -// return err; -// } -// -// if (crc != 0) { -// continue; -// } -// -// valid = true; -// -// // setup dir in case it's valid -// dir->pair[0] = tpair[(i+0) % 2]; -// dir->pair[1] = tpair[(i+1) % 2]; -// dir->off = sizeof(dir->d); -// dir->d = test; -// } -// -// if (!valid) { -// LFS_ERROR("Corrupted dir pair at {0x%"PRIx32", 0x%"PRIx32"}", -// tpair[0], tpair[1]); -// return LFS_ERR_CORRUPT; -// } -// -// return 0; -//} -// -//static int lfs1_dir_next(lfs_t *lfs, lfs1_dir_t *dir, lfs1_entry_t *entry) { -// while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) { -// if (!(0x80000000 & dir->d.size)) { -// entry->off = dir->off; -// return LFS_ERR_NOENT; -// } -// -// int err = lfs1_dir_fetch(lfs, dir, dir->d.tail); -// if (err) { -// return err; -// } -// -// dir->off = sizeof(dir->d); -// dir->pos += sizeof(dir->d) + 4; -// } -// -// int err = lfs1_bd_read(lfs, dir->pair[0], dir->off, -// &entry->d, sizeof(entry->d)); -// lfs1_entry_fromle32(&entry->d); -// if (err) { -// return err; -// } -// -// entry->off = dir->off; -// dir->off += lfs1_entry_size(entry); -// dir->pos += lfs1_entry_size(entry); -// return 0; -//} -// -///// littlefs v1 specific operations /// -//int lfs1_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { -// if (lfs_pair_isnull(lfs->lfs1->root)) { -// return 0; -// } -// -// // iterate over metadata pairs -// lfs1_dir_t dir; -// lfs1_entry_t entry; -// lfs_block_t cwd[2] = {0, 1}; -// -// while (true) { -// for (int i = 0; i < 2; i++) { -// int err = cb(data, cwd[i]); -// if (err) { -// return err; -// } -// } -// -// int err = lfs1_dir_fetch(lfs, &dir, cwd); -// if (err) { -// return err; -// } -// -// // iterate over contents -// while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) { -// err = lfs1_bd_read(lfs, dir.pair[0], dir.off, -// &entry.d, sizeof(entry.d)); -// lfs1_entry_fromle32(&entry.d); -// if (err) { -// return err; -// } -// -// dir.off += lfs1_entry_size(&entry); -// if ((0x70 & entry.d.type) == (0x70 & LFS1_TYPE_REG)) { -// err = lfs_ctz_traverse(lfs, NULL, &lfs->rcache, -// entry.d.u.file.head, entry.d.u.file.size, cb, data); -// if (err) { -// return err; -// } -// } -// } -// -// // we also need to check if we contain a threaded v2 directory -// lfs_mdir_t dir2 = {.split=true, .tail={cwd[0], cwd[1]}}; -// while (dir2.split) { -// err = lfs_dir_fetch(lfs, &dir2, dir2.tail); -// if (err) { -// break; -// } -// -// for (int i = 0; i < 2; i++) { -// err = cb(data, dir2.pair[i]); -// if (err) { -// return err; -// } -// } -// } -// -// cwd[0] = dir.d.tail[0]; -// cwd[1] = dir.d.tail[1]; -// -// if (lfs_pair_isnull(cwd)) { -// break; -// } -// } -// -// return 0; -//} -// -//static int lfs1_moved(lfs_t *lfs, const void *e) { -// if (lfs_pair_isnull(lfs->lfs1->root)) { -// return 0; -// } -// -// // skip superblock -// lfs1_dir_t cwd; -// int err = lfs1_dir_fetch(lfs, &cwd, (const lfs_block_t[2]){0, 1}); -// if (err) { -// return err; -// } -// -// // iterate over all directory directory entries -// lfs1_entry_t entry; -// while (!lfs_pair_isnull(cwd.d.tail)) { -// err = lfs1_dir_fetch(lfs, &cwd, cwd.d.tail); -// if (err) { -// return err; -// } -// -// while (true) { -// err = lfs1_dir_next(lfs, &cwd, &entry); -// if (err && err != LFS_ERR_NOENT) { -// return err; -// } -// -// if (err == LFS_ERR_NOENT) { -// break; -// } -// -// if (!(0x80 & entry.d.type) && -// memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0) { -// return true; -// } -// } -// } -// -// return false; -//} -// -///// Filesystem operations /// -//static int lfs1_mount(lfs_t *lfs, struct lfs1 *lfs1, -// const struct lfs_config *cfg) { -// int err = 0; -// { -// err = lfs_init(lfs, cfg); -// if (err) { -// return err; -// } -// -// lfs->lfs1 = lfs1; -// lfs->lfs1->root[0] = LFS_BLOCK_NULL; -// lfs->lfs1->root[1] = LFS_BLOCK_NULL; -// -// // setup free lookahead -// lfs->free.off = 0; -// lfs->free.size = 0; -// lfs->free.i = 0; -// lfs_alloc_ack(lfs); -// -// // load superblock -// lfs1_dir_t dir; -// lfs1_superblock_t superblock; -// err = lfs1_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1}); -// if (err && err != LFS_ERR_CORRUPT) { -// goto cleanup; -// } -// -// if (!err) { -// err = lfs1_bd_read(lfs, dir.pair[0], sizeof(dir.d), -// &superblock.d, sizeof(superblock.d)); -// lfs1_superblock_fromle32(&superblock.d); -// if (err) { -// goto cleanup; -// } -// -// lfs->lfs1->root[0] = superblock.d.root[0]; -// lfs->lfs1->root[1] = superblock.d.root[1]; -// } -// -// if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) { -// LFS_ERROR("Invalid superblock at {0x%"PRIx32", 0x%"PRIx32"}", -// 0, 1); -// err = LFS_ERR_CORRUPT; -// goto cleanup; -// } -// -// uint16_t major_version = (0xffff & (superblock.d.version >> 16)); -// uint16_t minor_version = (0xffff & (superblock.d.version >> 0)); -// if ((major_version != LFS1_DISK_VERSION_MAJOR || -// minor_version > LFS1_DISK_VERSION_MINOR)) { -// LFS_ERROR("Invalid version v%d.%d", major_version, minor_version); -// err = LFS_ERR_INVAL; -// goto cleanup; -// } -// -// return 0; -// } -// -//cleanup: -// lfs_deinit(lfs); -// return err; -//} -// -//static int lfs1_unmount(lfs_t *lfs) { -// return lfs_deinit(lfs); -//} -// -///// v1 migration /// -//static int lfs_rawmigrate(lfs_t *lfs, const struct lfs_config *cfg) { -// struct lfs1 lfs1; -// int err = lfs1_mount(lfs, &lfs1, cfg); -// if (err) { -// return err; -// } -// -// { -// // iterate through each directory, copying over entries -// // into new directory -// lfs1_dir_t dir1; -// lfs_mdir_t dir2; -// dir1.d.tail[0] = lfs->lfs1->root[0]; -// dir1.d.tail[1] = lfs->lfs1->root[1]; -// while (!lfs_pair_isnull(dir1.d.tail)) { -// // iterate old dir -// err = lfs1_dir_fetch(lfs, &dir1, dir1.d.tail); -// if (err) { -// goto cleanup; -// } -// -// // create new dir and bind as temporary pretend root -// err = lfs_dir_alloc(lfs, &dir2); -// if (err) { -// goto cleanup; -// } -// -// dir2.rev = dir1.d.rev; -// dir1.head[0] = dir1.pair[0]; -// dir1.head[1] = dir1.pair[1]; -// lfs->root[0] = dir2.pair[0]; -// lfs->root[1] = dir2.pair[1]; -// -// err = lfs_dir_commit(lfs, &dir2, NULL, 0); -// if (err) { -// goto cleanup; -// } -// -// while (true) { -// lfs1_entry_t entry1; -// err = lfs1_dir_next(lfs, &dir1, &entry1); -// if (err && err != LFS_ERR_NOENT) { -// goto cleanup; -// } -// -// if (err == LFS_ERR_NOENT) { -// break; -// } -// -// // check that entry has not been moved -// if (entry1.d.type & 0x80) { -// int moved = lfs1_moved(lfs, &entry1.d.u); -// if (moved < 0) { -// err = moved; -// goto cleanup; -// } -// -// if (moved) { -// continue; -// } -// -// entry1.d.type &= ~0x80; -// } -// -// // also fetch name -// char name[LFS_NAME_MAX+1]; -// memset(name, 0, sizeof(name)); -// err = lfs1_bd_read(lfs, dir1.pair[0], -// entry1.off + 4+entry1.d.elen+entry1.d.alen, -// name, entry1.d.nlen); -// if (err) { -// goto cleanup; -// } -// -// bool isdir = (entry1.d.type == LFS1_TYPE_DIR); -// -// // create entry in new dir -// err = lfs_dir_fetch(lfs, &dir2, lfs->root); -// if (err) { -// goto cleanup; -// } -// -// uint16_t id; -// err = lfs_dir_find(lfs, &dir2, &(const char*){name}, &id); -// if (!(err == LFS_ERR_NOENT && id != 0x3ff)) { -// err = (err < 0) ? err : LFS_ERR_EXIST; -// goto cleanup; -// } -// -// lfs1_entry_tole32(&entry1.d); -// err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_CREATE, id, 0), NULL}, -// {LFS_MKTAG_IF_ELSE(isdir, -// LFS_TYPE_DIR, id, entry1.d.nlen, -// LFS_TYPE_REG, id, entry1.d.nlen), -// name}, -// {LFS_MKTAG_IF_ELSE(isdir, -// LFS_TYPE_DIRSTRUCT, id, sizeof(entry1.d.u), -// LFS_TYPE_CTZSTRUCT, id, sizeof(entry1.d.u)), -// &entry1.d.u})); -// lfs1_entry_fromle32(&entry1.d); -// if (err) { -// goto cleanup; -// } -// } -// -// if (!lfs_pair_isnull(dir1.d.tail)) { -// // find last block and update tail to thread into fs -// err = lfs_dir_fetch(lfs, &dir2, lfs->root); -// if (err) { -// goto cleanup; -// } -// -// while (dir2.split) { -// err = lfs_dir_fetch(lfs, &dir2, dir2.tail); -// if (err) { -// goto cleanup; -// } -// } -// -// lfs_pair_tole32(dir2.pair); -// err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir1.d.tail})); -// lfs_pair_fromle32(dir2.pair); -// if (err) { -// goto cleanup; -// } -// } -// -// // Copy over first block to thread into fs. Unfortunately -// // if this fails there is not much we can do. -// LFS_DEBUG("Migrating {0x%"PRIx32", 0x%"PRIx32"} " -// "-> {0x%"PRIx32", 0x%"PRIx32"}", -// lfs->root[0], lfs->root[1], dir1.head[0], dir1.head[1]); -// -// err = lfs_bd_erase(lfs, dir1.head[1]); -// if (err) { -// goto cleanup; -// } -// -// err = lfs_dir_fetch(lfs, &dir2, lfs->root); -// if (err) { -// goto cleanup; -// } -// -// for (lfs_off_t i = 0; i < dir2.off; i++) { -// uint8_t dat; -// err = lfs_bd_read(lfs, -// NULL, &lfs->rcache, dir2.off, -// dir2.pair[0], i, &dat, 1); -// if (err) { -// goto cleanup; -// } -// -// err = lfs_bd_prog(lfs, -// &lfs->pcache, &lfs->rcache, true, -// dir1.head[1], i, &dat, 1); -// if (err) { -// goto cleanup; -// } -// } -// -// err = lfs_bd_flush(lfs, &lfs->pcache, &lfs->rcache, true); -// if (err) { -// goto cleanup; -// } -// } -// -// // Create new superblock. This marks a successful migration! -// err = lfs1_dir_fetch(lfs, &dir1, (const lfs_block_t[2]){0, 1}); -// if (err) { -// goto cleanup; -// } -// -// dir2.pair[0] = dir1.pair[0]; -// dir2.pair[1] = dir1.pair[1]; -// dir2.rev = dir1.d.rev; -// dir2.off = sizeof(dir2.rev); -// dir2.etag = 0xffffffff; -// dir2.count = 0; -// dir2.tail[0] = lfs->lfs1->root[0]; -// dir2.tail[1] = lfs->lfs1->root[1]; -// dir2.erased = false; -// dir2.split = true; -// -// lfs_superblock_t superblock = { -// .version = LFS_DISK_VERSION, -// .block_size = lfs->cfg->block_size, -// .block_count = lfs->cfg->block_count, -// .name_max = lfs->name_max, -// .file_max = lfs->file_max, -// .attr_max = lfs->attr_max, -// }; -// -// lfs_superblock_tole32(&superblock); -// err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS( -// {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL}, -// {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, -// {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), -// &superblock})); -// if (err) { -// goto cleanup; -// } -// -// // sanity check that fetch works -// err = lfs_dir_fetch(lfs, &dir2, (const lfs_block_t[2]){0, 1}); -// if (err) { -// goto cleanup; -// } -// -// // force compaction to prevent accidentally mounting v1 -// dir2.erased = false; -// err = lfs_dir_commit(lfs, &dir2, NULL, 0); -// if (err) { -// goto cleanup; -// } -// } -// -//cleanup: -// lfs1_unmount(lfs); -// 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 -// -//#ifndef LFS_NO_MALLOC -//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; -//} -//#endif -// -//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 - +// that's it! you've reached the end! go home! diff --git a/lfs.h b/lfs.h index 0d76d206..5f07dc7a 100644 --- a/lfs.h +++ b/lfs.h @@ -69,22 +69,6 @@ typedef int32_t lfsr_sdid_t; #define LFS_FILE_MAX 2147483647 #endif -// TODO rm me -//// Maximum size of custom attributes in bytes, may be redefined, but there is -//// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. -//#ifndef LFS_ATTR_MAX -//#define LFS_ATTR_MAX 1022 -//#endif -// -//// TODO document -//#ifndef LFS_UATTR_MAX -//#define LFS_UATTR_MAX 255 -//#endif -// -//#ifndef LFS_SATTR_MAX -//#define LFS_SATTR_MAX 255 -//#endif - // Possible error codes, these are negative to allow // valid positive return values @@ -436,25 +420,6 @@ struct lfs_config { // in superblock and must be respected by other littlefs drivers. lfs_size_t file_limit; -// TODO rm me -// // Optional upper limit on custom attributes in bytes. No downside for -// // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to -// // LFS_ATTR_MAX when zero. -// lfs_size_t attr_max; -// -// // Optional upper limit on total space given to metadata pairs in bytes. On -// // devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB) -// // can help bound the metadata compaction time. Must be <= block_size. -// // Defaults to block_size when zero. -// lfs_size_t metadata_max; -// -// // Maximum size of inlined files in bytes. Inlined files decrease storage -// // requirements, but may impact metadata-related performance. Must be <= -// // block_size/4. -// // -// // 0 disables inline files. -// lfs_size_t inline_size; - // TODO these are pretty low-level details, should we have reasonable // defaults? need to benchmark. @@ -534,20 +499,6 @@ struct lfs_tinfo { lfs_block_t block; }; -//// Custom attribute structure, used to describe custom attributes -//// committed atomically during file writes. -//struct lfs_attr { -// // 8-bit type of attribute, provided by user and used to -// // identify the attribute -// uint8_t type; -// -// // Pointer to buffer containing the attribute -// void *buffer; -// -// // Size of attribute in bytes, limited to LFS_ATTR_MAX -// lfs_size_t size; -//}; - // Custom attribute structure, used to describe custom attributes // committed atomically during file writes. struct lfs_attr { @@ -586,22 +537,6 @@ struct lfs_file_config { // accesses. Defaults to file_cache_size. lfs_size_t cache_size; -// // Optional list of custom attributes related to the file. If the file -// // is opened with read access, these attributes will be read from disk -// // during the open call. If the file is opened with write access, the -// // attributes will be written to disk every file sync or close. This -// // write occurs atomically with update to the file's contents. -// // -// // Custom attributes are uniquely identified by an 8-bit type and limited -// // to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller -// // than the buffer, it will be padded with zeros. If the stored attribute -// // is larger, then it will be silently truncated. If the attribute is not -// // found, it will be created implicitly. -// struct lfs_attr *attrs; -// -// // Number of custom attributes in the list -// lfs_size_t attr_count; - // Optional list of custom attributes attached to the file. If readable, // these attributes will be kept up to date with the attributes on-disk. // If writeable, these attributes will be written to disk atomically on @@ -615,24 +550,6 @@ struct lfs_file_config { /// internal littlefs data structures /// -//typedef struct lfs_cache { -// lfs_block_t block; -// lfs_size_t off; -// lfs_size_t size; -// uint8_t *buffer; -//} lfs_cache_t; - -//typedef struct lfs_mdir { -// lfs_block_t pair[2]; -// uint32_t rev; -// lfs_off_t off; -// uint32_t etag; -// uint16_t count; -// bool erased; -// bool split; -// lfs_block_t tail[2]; -//} lfs_mdir_t; - // either an on-disk or in-RAM data pointer // // note, it's tempting to make this fancier, but we benefit quite a lot @@ -721,27 +638,6 @@ typedef struct lfsr_bshrub { } lfsr_bshrub_t; // littlefs file type - -//typedef struct lfs_file { -// struct lfs_file *next; -// uint16_t id; -// uint8_t type; -// lfs_mdir_t m; -// -// struct lfs_ctz { -// lfs_block_t head; -// lfs_size_t size; -// } ctz; -// -// uint32_t flags; -// lfs_off_t pos; -// lfs_block_t block; -// lfs_off_t off; -// lfs_cache_t cache; -// -// const struct lfs_file_config *cfg; -//} lfs_file_t; - typedef struct lfsr_file { // btree/bshrub stuff is in here lfsr_bshrub_t b; @@ -768,25 +664,12 @@ typedef struct lfsr_file { } lfsr_file_t; // littlefs directory type - -//typedef struct lfs_dir { -// struct lfs_dir *next; -// uint16_t id; -// uint8_t type; -// lfs_mdir_t m; -// -// lfs_off_t pos; -// lfs_block_t head[2]; -//} lfs_dir_t; - typedef struct lfsr_dir { lfsr_omdir_t o; lfsr_did_t did; lfs_off_t pos; } lfsr_dir_t; -// littlefs traversal type - typedef struct lfsr_btraversal { lfsr_bid_t bid; const lfsr_rbyd_t *branch; @@ -794,6 +677,7 @@ typedef struct lfsr_btraversal { lfsr_rbyd_t rbyd; } lfsr_btraversal_t; +// littlefs traversal type typedef struct lfsr_traversal { // mdir/bshrub/btree state, this also includes our traversal // state machine @@ -817,21 +701,6 @@ typedef struct lfsr_traversal { lfs_sblock_t blocks[2]; } lfsr_traversal_t; - -//typedef struct lfs_superblock { -// uint32_t version; -// lfs_size_t block_size; -// lfs_size_t block_count; -// lfs_size_t name_max; -// lfs_size_t file_max; -// lfs_size_t attr_max; -//} lfs_superblock_t; -// -//typedef struct lfs_gstate { -// uint32_t tag; -// lfs_block_t pair[2]; -//} lfs_gstate_t; - // grm encoding: // .- -+- -+- -+- -+- -. mids: 2 leb128s <=2x5 bytes // ' mids ' total: <=10 bytes @@ -845,6 +714,7 @@ typedef struct lfsr_grm { lfsr_smid_t queue[2]; } lfsr_grm_t; + // The littlefs filesystem type typedef struct lfs { const struct lfs_config *cfg; @@ -922,7 +792,6 @@ typedef struct lfs { // be zeroed for defaults and backwards compatibility. // // Returns a negative error code on failure. -//int lfs_format(lfs_t *lfs, const struct lfs_config *config); int lfsr_format(lfs_t *lfs, uint32_t flags, const struct lfs_config *cfg); #endif @@ -935,7 +804,6 @@ int lfsr_format(lfs_t *lfs, uint32_t flags, // be zeroed for defaults and backwards compatibility. // // Returns a negative error code on failure. -//int lfs_mount(lfs_t *lfs, const struct lfs_config *config); int lfsr_mount(lfs_t *lfs, uint32_t flags, const struct lfs_config *cfg); @@ -943,7 +811,6 @@ int lfsr_mount(lfs_t *lfs, uint32_t flags, // // Does nothing besides releasing any allocated resources. // Returns a negative error code on failure. -//int lfs_unmount(lfs_t *lfs); int lfsr_unmount(lfs_t *lfs); /// General operations /// @@ -953,7 +820,6 @@ int lfsr_unmount(lfs_t *lfs); // // 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); int lfsr_remove(lfs_t *lfs, const char *path); #endif @@ -964,7 +830,6 @@ int lfsr_remove(lfs_t *lfs, const char *path); // If the destination is a directory, the directory must be empty. // // Returns a negative error code on failure. -//int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path); #endif @@ -972,7 +837,6 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path); // // Fills out the info structure, based on the specified file or directory. // Returns a negative error code on failure. -//int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); int lfsr_stat(lfs_t *lfs, const char *path, struct lfs_info *info); // Get a custom attribute @@ -980,8 +844,6 @@ int lfsr_stat(lfs_t *lfs, const char *path, struct lfs_info *info); // Returns the number of bytes read, or a negative error code on failure. // Note this may be less than the on-disk attr size if the buffer is not // large enough. -//lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, -// uint8_t type, void *buffer, lfs_size_t size); lfs_ssize_t lfsr_getattr(lfs_t *lfs, const char *path, uint8_t type, void *buffer, lfs_size_t size); @@ -994,8 +856,6 @@ lfs_ssize_t lfsr_sizeattr(lfs_t *lfs, const char *path, uint8_t type); // Set a custom attributes // // 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); int lfsr_setattr(lfs_t *lfs, const char *path, uint8_t type, const void *buffer, lfs_size_t size); #endif @@ -1004,7 +864,6 @@ int lfsr_setattr(lfs_t *lfs, const char *path, uint8_t type, // Removes a custom attribute // // Returns a negative error code on failure. -//int lfs_removeattr(lfs_t *lfs, const char *path, uint8_t type); int lfsr_removeattr(lfs_t *lfs, const char *path, uint8_t type); #endif @@ -1018,8 +877,6 @@ int lfsr_removeattr(lfs_t *lfs, const char *path, uint8_t type); // are values from the enum lfs_open_flags that are bitwise-ored together. // // Returns a negative error code on failure. -//int lfs_file_open(lfs_t *lfs, lfs_file_t *file, -// const char *path, int flags); int lfsr_file_open(lfs_t *lfs, lfsr_file_t *file, const char *path, uint32_t flags); @@ -1037,9 +894,6 @@ int lfsr_file_open(lfs_t *lfs, lfsr_file_t *file, // the config struct must be zeroed for defaults and backwards compatibility. // // Returns a negative error code on failure. -//int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, -// const char *path, int flags, -// const struct lfs_file_config *config); int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file, const char *path, uint32_t flags, const struct lfs_file_config *cfg); @@ -1055,7 +909,6 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file, // return 0. // // Returns a negative error code on failure. -//int lfs_file_close(lfs_t *lfs, lfs_file_t *file); int lfsr_file_close(lfs_t *lfs, lfsr_file_t *file); // Synchronize a file on storage @@ -1066,7 +919,6 @@ int lfsr_file_close(lfs_t *lfs, lfsr_file_t *file); // now recieve file updates and syncs on close. // // Returns a negative error code on failure. -//int lfs_file_sync(lfs_t *lfs, lfs_file_t *file); int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file); // Flush any buffered data @@ -1105,8 +957,6 @@ int lfsr_file_resync(lfs_t *lfs, lfsr_file_t *file); // // Takes a buffer and size indicating where to store the read data. // Returns the number of bytes read, or a negative error code on failure. -//lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file, -// void *buffer, lfs_size_t size); lfs_ssize_t lfsr_file_read(lfs_t *lfs, lfsr_file_t *file, void *buffer, lfs_size_t size); @@ -1117,8 +967,6 @@ lfs_ssize_t lfsr_file_read(lfs_t *lfs, lfsr_file_t *file, // actually be updated on the storage until either sync or close is called. // // 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); lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file, const void *buffer, lfs_size_t size); #endif @@ -1127,8 +975,6 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file, // // The change in position is determined by the offset and whence flag. // Returns the new position of the file, or a negative error code on failure. -//lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file, -// lfs_soff_t off, int whence); lfs_soff_t lfsr_file_seek(lfs_t *lfs, lfsr_file_t *file, lfs_soff_t off, uint8_t whence); @@ -1139,7 +985,6 @@ lfs_soff_t lfsr_file_seek(lfs_t *lfs, lfsr_file_t *file, // as if the file was filled with zeros. // // Returns a negative error code on failure. -//int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size); int lfsr_file_truncate(lfs_t *lfs, lfsr_file_t *file, lfs_off_t size); #endif @@ -1157,21 +1002,18 @@ int lfsr_file_fruncate(lfs_t *lfs, lfsr_file_t *file, lfs_off_t size); // // Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_CUR) // Returns the position of the file, or a negative error code on failure. -//lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file); lfs_soff_t lfsr_file_tell(lfs_t *lfs, lfsr_file_t *file); // Change the position of the file to the beginning of the file // // Equivalent to lfs_file_seek(lfs, file, 0, LFS_SEEK_SET) // Returns a negative error code on failure. -//int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); int lfsr_file_rewind(lfs_t *lfs, lfsr_file_t *file); // Return the size of the file // // Similar to lfs_file_seek(lfs, file, 0, LFS_SEEK_END) // Returns the size of the file, or a negative error code on failure. -//lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); lfs_soff_t lfsr_file_size(lfs_t *lfs, lfsr_file_t *file); // Check a file for metadata errors @@ -1193,7 +1035,6 @@ int lfsr_file_ckdata(lfs_t *lfs, lfsr_file_t *file); // Create a directory // // Returns a negative error code on failure. -//int lfs_mkdir(lfs_t *lfs, const char *path); int lfsr_mkdir(lfs_t *lfs, const char *path); #endif @@ -1201,14 +1042,12 @@ int lfsr_mkdir(lfs_t *lfs, const char *path); // // Once open a directory can be used with read to iterate over files. // Returns a negative error code on failure. -//int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path); int lfsr_dir_open(lfs_t *lfs, lfsr_dir_t *dir, const char *path); // Close a directory // // Releases any allocated resources. // Returns a negative error code on failure. -//int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir); int lfsr_dir_close(lfs_t *lfs, lfsr_dir_t *dir); // Read an entry in the directory @@ -1216,7 +1055,6 @@ int lfsr_dir_close(lfs_t *lfs, lfsr_dir_t *dir); // Fills out the info structure, based on the specified file or directory. // Returns 0 on success, LFS_ERR_NOENT at the end of directory, or a // negative error code on failure. -//int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info); int lfsr_dir_read(lfs_t *lfs, lfsr_dir_t *dir, struct lfs_info *info); // Change the position of the directory @@ -1225,7 +1063,6 @@ int lfsr_dir_read(lfs_t *lfs, lfsr_dir_t *dir, struct lfs_info *info); // an absolute offset in the directory seek. // // Returns a negative error code on failure. -//int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off); int lfsr_dir_seek(lfs_t *lfs, lfsr_dir_t *dir, lfs_soff_t off); // Return the position of the directory @@ -1234,13 +1071,11 @@ int lfsr_dir_seek(lfs_t *lfs, lfsr_dir_t *dir, lfs_soff_t off); // sense, but does indicate the current position in the directory iteration. // // Returns the position of the directory, or a negative error code on failure. -//lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir); lfs_soff_t lfsr_dir_tell(lfs_t *lfs, lfsr_dir_t *dir); // Change the position of the directory to the beginning of the directory // // Returns a negative error code on failure. -//int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); int lfsr_dir_rewind(lfs_t *lfs, lfsr_dir_t *dir); @@ -1289,18 +1124,8 @@ int lfsr_fs_stat(lfs_t *lfs, struct lfs_fsinfo *fsinfo); // usage may be larger than the filesystem actually is. // // Returns the number of allocated blocks, or a negative error code on failure. -//lfs_ssize_t lfs_fs_size(lfs_t *lfs); lfs_ssize_t lfsr_fs_usage(lfs_t *lfs); -// Traverse through all blocks in use by the filesystem -// -// The provided callback will be called with each block address that is -// currently in use by the filesystem. This can be used to determine which -// blocks are in use or how much of the storage is available. -// -// 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 // Attempt to make the filesystem consistent and ready for writing // @@ -1381,22 +1206,5 @@ int lfsr_fs_unck(lfs_t *lfs, uint32_t flags); int lfsr_fs_grow(lfs_t *lfs, lfs_size_t block_count); #endif -#ifndef LFS_READONLY -#ifdef LFS_MIGRATE -// Attempts to migrate a previous version of littlefs -// -// Behaves similarly to the lfs_format function. Attempts to mount -// the previous version of littlefs and update the filesystem so it can be -// mounted with the current version of littlefs. -// -// Requires a littlefs object and config struct. This clobbers the littlefs -// object, and does not leave the filesystem mounted. The config struct must -// be zeroed for defaults and backwards compatibility. -// -// Returns a negative error code on failure. -//int lfs_migrate(lfs_t *lfs, const struct lfs_config *cfg); -#endif -#endif - #endif