diff --git a/lfs.c b/lfs.c index b8d29150..521bc070 100644 --- a/lfs.c +++ b/lfs.c @@ -187,26 +187,26 @@ static int lfs_bd_cmp(lfs_t *lfs, return LFS_CMP_EQ; } -static int lfs_bd_crc(lfs_t *lfs, - const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, - lfs_block_t block, lfs_off_t off, lfs_size_t size, uint32_t *crc) { - lfs_size_t diff = 0; - - for (lfs_off_t i = 0; i < size; i += diff) { - uint8_t dat[8]; - diff = lfs_min(size-i, sizeof(dat)); - int err = lfs_bd_read(lfs, - pcache, rcache, hint-i, - block, off+i, &dat, diff); - if (err) { - return err; - } - - *crc = lfs_crc(*crc, &dat, diff); - } - - return 0; -} +//static int lfs_bd_crc(lfs_t *lfs, +// const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, +// lfs_block_t block, lfs_off_t off, lfs_size_t size, uint32_t *crc) { +// lfs_size_t diff = 0; +// +// for (lfs_off_t i = 0; i < size; i += diff) { +// uint8_t dat[8]; +// diff = lfs_min(size-i, sizeof(dat)); +// int err = lfs_bd_read(lfs, +// pcache, rcache, hint-i, +// block, off+i, &dat, diff); +// if (err) { +// return err; +// } +// +// *crc = lfs_crc(*crc, &dat, diff); +// } +// +// return 0; +//} static int lfs_bd_crc32c(lfs_t *lfs, const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint, @@ -492,95 +492,95 @@ static int lfsr_bd_erase(lfs_t *lfs, lfs_block_t block) { /// 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)); -} +//// 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)); +//} // 16-bit metadata tags enum lfsr_tag_type { @@ -1140,19 +1140,20 @@ static lfs_ssize_t lfsr_bd_progdata(lfs_t *lfs, // operations on attribute lists -struct lfs_mattr { - lfs_tag_t tag; - const void *buffer; -}; -struct lfs_diskoff { - lfs_block_t block; - lfs_off_t off; -}; - -#define LFS_MKATTRS(...) \ - (struct lfs_mattr[]){__VA_ARGS__}, \ - sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr) +//struct lfs_mattr { +// lfs_tag_t tag; +// const void *buffer; +//}; +// +//struct lfs_diskoff { +// lfs_block_t block; +// lfs_off_t off; +//}; +// +//#define LFS_MKATTRS(...) +// (struct lfs_mattr[]){__VA_ARGS__}, +// sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr) typedef struct lfsr_attr { lfs_ssize_t id; @@ -1228,54 +1229,54 @@ typedef struct lfsr_find { -// 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 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 { @@ -1338,130 +1339,131 @@ static lfs_ssize_t lfsr_fcrc_fromdisk(lfs_t *lfs, lfsr_fcrc_t *fcrc, return d; } -// 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; -} +//// 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); +//#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); +//static int lfs_rawunmount(lfs_t *lfs); /// Block allocator /// -#ifndef LFS_READONLY -static int lfs_alloc_lookahead(void *p, lfs_block_t block) { - lfs_t *lfs = (lfs_t*)p; - lfs_block_t off = ((block - lfs->free.off) - + lfs->cfg->block_count) % lfs->cfg->block_count; - if (off < lfs->free.size) { - lfs->free.buffer[off / 32] |= 1U << (off % 32); - } - - return 0; -} -#endif +//#ifndef LFS_READONLY +//static int lfs_alloc_lookahead(void *p, lfs_block_t block) { +// lfs_t *lfs = (lfs_t*)p; +// lfs_block_t off = ((block - lfs->free.off) +// + lfs->cfg->block_count) % lfs->cfg->block_count; +// +// if (off < lfs->free.size) { +// lfs->free.buffer[off / 32] |= 1U << (off % 32); +// } +// +// return 0; +//} +//#endif // indicate allocated blocks have been committed into the filesystem, this // is to prevent blocks from being garbage collected in the middle of a @@ -1470,13 +1472,13 @@ static void lfs_alloc_ack(lfs_t *lfs) { lfs->free.ack = lfs->cfg->block_count; } -// drop the lookahead buffer, this is done during mounting and failed -// traversals in order to avoid invalid lookahead state -static void lfs_alloc_drop(lfs_t *lfs) { - lfs->free.size = 0; - lfs->free.i = 0; - lfs_alloc_ack(lfs); -} +//// drop the lookahead buffer, this is done during mounting and failed +//// traversals in order to avoid invalid lookahead state +//static void lfs_alloc_drop(lfs_t *lfs) { +// lfs->free.size = 0; +// lfs->free.i = 0; +// lfs_alloc_ack(lfs); +//} #ifndef LFS_READONLY static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { @@ -1499,30 +1501,34 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { lfs->free.ack -= 1; } - printf("debug: lfs_alloc: %x\n", *block); return 0; } } - // check if we have looked at all blocks since last ack - if (lfs->free.ack == 0) { - LFS_ERROR("No more free space %"PRIu32, - lfs->free.i + lfs->free.off); - return LFS_ERR_NOSPC; - } + // TODO implement this eventually + LFS_ERROR("No more free space %"PRIu32, + lfs->free.i + lfs->free.off); + return LFS_ERR_NOSPC; - lfs->free.off = (lfs->free.off + lfs->free.size) - % lfs->cfg->block_count; - lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, lfs->free.ack); - lfs->free.i = 0; - - // find mask of free blocks from tree - memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); - int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true); - if (err) { - lfs_alloc_drop(lfs); - return err; - } +// // check if we have looked at all blocks since last ack +// if (lfs->free.ack == 0) { +// LFS_ERROR("No more free space %"PRIu32, +// lfs->free.i + lfs->free.off); +// return LFS_ERR_NOSPC; +// } +// +// lfs->free.off = (lfs->free.off + lfs->free.size) +// % lfs->cfg->block_count; +// lfs->free.size = lfs_min(8*lfs->cfg->lookahead_size, lfs->free.ack); +// lfs->free.i = 0; +// +// // find mask of free blocks from tree +// memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); +// int err = lfs_fs_rawtraverse(lfs, lfs_alloc_lookahead, lfs, true); +// if (err) { +// lfs_alloc_drop(lfs); +// return err; +// } } } #endif @@ -7134,3375 +7140,3375 @@ int lfsr_format(lfs_t *lfs, const struct lfs_config *cfg) { -/// 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: +///// 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; // -// traverse with commit -// '-> traverse with move -// '-> traverse with filter +// 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->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 // -#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->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 - /// Filesystem operations /// static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { @@ -10633,1844 +10639,1844 @@ static int lfs_deinit(lfs_t *lfs) { return 0; } -#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 +//#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 diff --git a/tests/test_alloc.toml b/tests/test_alloc.toml index 205efbb1..fe67cba8 100644 --- a/tests/test_alloc.toml +++ b/tests/test_alloc.toml @@ -1,717 +1,717 @@ -# allocator tests -# note for these to work there are a number constraints on the device geometry -if = 'BLOCK_CYCLES == -1' - -# parallel allocation test -[cases.test_alloc_parallel] -defines.FILES = 3 -defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' -code = ''' - const char *names[] = {"bacon", "eggs", "pancakes"}; - lfs_file_t files[FILES]; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "breakfast") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int n = 0; n < FILES; n++) { - char path[1024]; - sprintf(path, "breakfast/%s", names[n]); - lfs_file_open(&lfs, &files[n], path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - } - for (int n = 0; n < FILES; n++) { - size_t size = strlen(names[n]); - for (lfs_size_t i = 0; i < SIZE; i += size) { - lfs_file_write(&lfs, &files[n], names[n], size) => size; - } - } - for (int n = 0; n < FILES; n++) { - lfs_file_close(&lfs, &files[n]) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int n = 0; n < FILES; n++) { - char path[1024]; - sprintf(path, "breakfast/%s", names[n]); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - size_t size = strlen(names[n]); - for (lfs_size_t i = 0; i < SIZE; i += size) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, size) => size; - assert(memcmp(buffer, names[n], size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; -''' - -# serial allocation test -[cases.test_alloc_serial] -defines.FILES = 3 -defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' -code = ''' - const char *names[] = {"bacon", "eggs", "pancakes"}; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "breakfast") => 0; - lfs_unmount(&lfs) => 0; - - for (int n = 0; n < FILES; n++) { - lfs_mount(&lfs, cfg) => 0; - char path[1024]; - sprintf(path, "breakfast/%s", names[n]); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size_t size = strlen(names[n]); - uint8_t buffer[1024]; - memcpy(buffer, names[n], size); - for (int i = 0; i < SIZE; i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - } - - lfs_mount(&lfs, cfg) => 0; - for (int n = 0; n < FILES; n++) { - char path[1024]; - sprintf(path, "breakfast/%s", names[n]); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - size_t size = strlen(names[n]); - for (int i = 0; i < SIZE; i += size) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, size) => size; - assert(memcmp(buffer, names[n], size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; -''' - -# parallel allocation reuse test -[cases.test_alloc_parallel_reuse] -defines.FILES = 3 -defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' -defines.CYCLES = [1, 10] -code = ''' - const char *names[] = {"bacon", "eggs", "pancakes"}; - lfs_file_t files[FILES]; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - for (int c = 0; c < CYCLES; c++) { - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "breakfast") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int n = 0; n < FILES; n++) { - char path[1024]; - sprintf(path, "breakfast/%s", names[n]); - lfs_file_open(&lfs, &files[n], path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - } - for (int n = 0; n < FILES; n++) { - size_t size = strlen(names[n]); - for (int i = 0; i < SIZE; i += size) { - lfs_file_write(&lfs, &files[n], names[n], size) => size; - } - } - for (int n = 0; n < FILES; n++) { - lfs_file_close(&lfs, &files[n]) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int n = 0; n < FILES; n++) { - char path[1024]; - sprintf(path, "breakfast/%s", names[n]); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - size_t size = strlen(names[n]); - for (int i = 0; i < SIZE; i += size) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, size) => size; - assert(memcmp(buffer, names[n], size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int n = 0; n < FILES; n++) { - char path[1024]; - sprintf(path, "breakfast/%s", names[n]); - lfs_remove(&lfs, path) => 0; - } - lfs_remove(&lfs, "breakfast") => 0; - lfs_unmount(&lfs) => 0; - } -''' - -# serial allocation reuse test -[cases.test_alloc_serial_reuse] -defines.FILES = 3 -defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' -defines.CYCLES = [1, 10] -code = ''' - const char *names[] = {"bacon", "eggs", "pancakes"}; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - for (int c = 0; c < CYCLES; c++) { - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "breakfast") => 0; - lfs_unmount(&lfs) => 0; - - for (int n = 0; n < FILES; n++) { - lfs_mount(&lfs, cfg) => 0; - char path[1024]; - sprintf(path, "breakfast/%s", names[n]); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size_t size = strlen(names[n]); - uint8_t buffer[1024]; - memcpy(buffer, names[n], size); - for (int i = 0; i < SIZE; i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - } - - lfs_mount(&lfs, cfg) => 0; - for (int n = 0; n < FILES; n++) { - char path[1024]; - sprintf(path, "breakfast/%s", names[n]); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - size_t size = strlen(names[n]); - for (int i = 0; i < SIZE; i += size) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, size) => size; - assert(memcmp(buffer, names[n], size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int n = 0; n < FILES; n++) { - char path[1024]; - sprintf(path, "breakfast/%s", names[n]); - lfs_remove(&lfs, path) => 0; - } - lfs_remove(&lfs, "breakfast") => 0; - lfs_unmount(&lfs) => 0; - } -''' - -# exhaustion test -[cases.test_alloc_exhaustion] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); - size_t size = strlen("exhaustion"); - uint8_t buffer[1024]; - memcpy(buffer, "exhaustion", size); - lfs_file_write(&lfs, &file, buffer, size) => size; - lfs_file_sync(&lfs, &file) => 0; - - size = strlen("blahblahblahblah"); - memcpy(buffer, "blahblahblahblah", size); - lfs_ssize_t res; - while (true) { - res = lfs_file_write(&lfs, &file, buffer, size); - if (res < 0) { - break; - } - - res => size; - } - res => LFS_ERR_NOSPC; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); - size = strlen("exhaustion"); - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "exhaustion", size) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# exhaustion wraparound test -[cases.test_alloc_exhaustion_wraparound] -defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - lfs_file_t file; - lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); - size_t size = strlen("buffering"); - uint8_t buffer[1024]; - memcpy(buffer, "buffering", size); - for (int i = 0; i < SIZE; i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - lfs_remove(&lfs, "padding") => 0; - - lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); - size = strlen("exhaustion"); - memcpy(buffer, "exhaustion", size); - lfs_file_write(&lfs, &file, buffer, size) => size; - lfs_file_sync(&lfs, &file) => 0; - - size = strlen("blahblahblahblah"); - memcpy(buffer, "blahblahblahblah", size); - lfs_ssize_t res; - while (true) { - res = lfs_file_write(&lfs, &file, buffer, size); - if (res < 0) { - break; - } - - res => size; - } - res => LFS_ERR_NOSPC; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); - size = strlen("exhaustion"); - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "exhaustion", size) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_remove(&lfs, "exhaustion") => 0; - lfs_unmount(&lfs) => 0; -''' - -# dir exhaustion test -[cases.test_alloc_dir_exhaustion] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // find out max file size - lfs_mkdir(&lfs, "exhaustiondir") => 0; - size_t size = strlen("blahblahblahblah"); - uint8_t buffer[1024]; - memcpy(buffer, "blahblahblahblah", size); - lfs_file_t file; - lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); - int count = 0; - int err; - while (true) { - err = lfs_file_write(&lfs, &file, buffer, size); - if (err < 0) { - break; - } - - count += 1; - } - err => LFS_ERR_NOSPC; - lfs_file_close(&lfs, &file) => 0; - - lfs_remove(&lfs, "exhaustion") => 0; - lfs_remove(&lfs, "exhaustiondir") => 0; - - // see if dir fits with max file size - lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); - for (int i = 0; i < count; i++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - lfs_mkdir(&lfs, "exhaustiondir") => 0; - lfs_remove(&lfs, "exhaustiondir") => 0; - lfs_remove(&lfs, "exhaustion") => 0; - - // see if dir fits with > max file size - lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); - for (int i = 0; i < count+1; i++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; - - lfs_remove(&lfs, "exhaustion") => 0; - lfs_unmount(&lfs) => 0; -''' - -# what if we have a bad block during an allocation scan? -[cases.test_alloc_bad_blocks] -in = "lfs.c" -defines.ERASE_CYCLES = 0xffffffff -defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_READERROR' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - // first fill to exhaustion to find available space - lfs_file_t file; - lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; - uint8_t buffer[1024]; - strcpy((char*)buffer, "waka"); - size_t size = strlen("waka"); - lfs_size_t filesize = 0; - while (true) { - lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); - assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); - if (res == LFS_ERR_NOSPC) { - break; - } - filesize += size; - } - lfs_file_close(&lfs, &file) => 0; - // now fill all but a couple of blocks of the filesystem with data - filesize -= 3*BLOCK_SIZE; - lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; - strcpy((char*)buffer, "waka"); - size = strlen("waka"); - for (lfs_size_t i = 0; i < filesize/size; i++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - // also save head of file so we can error during lookahead scan - lfs_block_t fileblock = file.ctz.head; - lfs_unmount(&lfs) => 0; - - // remount to force an alloc scan - lfs_mount(&lfs, cfg) => 0; - - // but mark the head of our file as a "bad block", this is force our - // scan to bail early - lfs_emubd_setwear(cfg, fileblock, 0xffffffff) => 0; - lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; - strcpy((char*)buffer, "chomp"); - size = strlen("chomp"); - while (true) { - lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); - assert(res == (lfs_ssize_t)size || res == LFS_ERR_CORRUPT); - if (res == LFS_ERR_CORRUPT) { - break; - } - } - lfs_file_close(&lfs, &file) => 0; - - // now reverse the "bad block" and try to write the file again until we - // run out of space - lfs_emubd_setwear(cfg, fileblock, 0) => 0; - lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; - strcpy((char*)buffer, "chomp"); - size = strlen("chomp"); - while (true) { - lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); - assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); - if (res == LFS_ERR_NOSPC) { - break; - } - } - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; - - // check that the disk isn't hurt - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0; - strcpy((char*)buffer, "waka"); - size = strlen("waka"); - for (lfs_size_t i = 0; i < filesize/size; i++) { - uint8_t rbuffer[4]; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(memcmp(rbuffer, buffer, size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - - -# Below, I don't like these tests. They're fragile and depend _heavily_ -# on the geometry of the block device. But they are valuable. Eventually they -# should be removed and replaced with generalized tests. - -# chained dir exhaustion test -[cases.test_alloc_chained_dir_exhaustion] -if = 'BLOCK_SIZE == 512' -defines.BLOCK_COUNT = 1024 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // find out max file size - lfs_mkdir(&lfs, "exhaustiondir") => 0; - for (int i = 0; i < 10; i++) { - char path[1024]; - sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); - lfs_mkdir(&lfs, path) => 0; - } - size_t size = strlen("blahblahblahblah"); - uint8_t buffer[1024]; - memcpy(buffer, "blahblahblahblah", size); - lfs_file_t file; - lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); - int count = 0; - int err; - while (true) { - err = lfs_file_write(&lfs, &file, buffer, size); - if (err < 0) { - break; - } - - count += 1; - } - err => LFS_ERR_NOSPC; - lfs_file_close(&lfs, &file) => 0; - - lfs_remove(&lfs, "exhaustion") => 0; - lfs_remove(&lfs, "exhaustiondir") => 0; - for (int i = 0; i < 10; i++) { - char path[1024]; - sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); - lfs_remove(&lfs, path) => 0; - } - - // see that chained dir fails - lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); - for (int i = 0; i < count+1; i++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_sync(&lfs, &file) => 0; - - for (int i = 0; i < 10; i++) { - char path[1024]; - sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); - lfs_mkdir(&lfs, path) => 0; - } - - lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; - - // shorten file to try a second chained dir - while (true) { - err = lfs_mkdir(&lfs, "exhaustiondir"); - if (err != LFS_ERR_NOSPC) { - break; - } - - lfs_ssize_t filesize = lfs_file_size(&lfs, &file); - filesize > 0 => true; - - lfs_file_truncate(&lfs, &file, filesize - size) => 0; - lfs_file_sync(&lfs, &file) => 0; - } - err => 0; - - lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# split dir test -[cases.test_alloc_split_dir] -if = 'BLOCK_SIZE == 512' -defines.BLOCK_COUNT = 1024 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // create one block hole for half a directory - lfs_file_t file; - lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; - for (lfs_size_t i = 0; i < cfg->block_size; i += 2) { - uint8_t buffer[1024]; - memcpy(&buffer[i], "hi", 2); - } - uint8_t buffer[1024]; - lfs_file_write(&lfs, &file, buffer, cfg->block_size) => cfg->block_size; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); - size_t size = strlen("blahblahblahblah"); - memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; - i < (cfg->block_count-4)*(cfg->block_size-8); - i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - // remount to force reset of lookahead - lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, cfg) => 0; - - // open hole - lfs_remove(&lfs, "bump") => 0; - - lfs_mkdir(&lfs, "splitdir") => 0; - lfs_file_open(&lfs, &file, "splitdir/bump", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - for (lfs_size_t i = 0; i < cfg->block_size; i += 2) { - memcpy(&buffer[i], "hi", 2); - } - lfs_file_write(&lfs, &file, buffer, 2*cfg->block_size) => LFS_ERR_NOSPC; - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' - -# outdated lookahead test -[cases.test_alloc_outdated_lookahead] -if = 'BLOCK_SIZE == 512' -defines.BLOCK_COUNT = 1024 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // fill completely with two files - lfs_file_t file; - lfs_file_open(&lfs, &file, "exhaustion1", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - size_t size = strlen("blahblahblahblah"); - uint8_t buffer[1024]; - memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; - i < ((cfg->block_count-2)/2)*(cfg->block_size-8); - i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "exhaustion2", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - size = strlen("blahblahblahblah"); - memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; - i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8); - i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - // remount to force reset of lookahead - lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, cfg) => 0; - - // rewrite one file - lfs_file_open(&lfs, &file, "exhaustion1", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_sync(&lfs, &file) => 0; - size = strlen("blahblahblahblah"); - memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; - i < ((cfg->block_count-2)/2)*(cfg->block_size-8); - i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - // rewrite second file, this requires lookahead does not - // use old population - lfs_file_open(&lfs, &file, "exhaustion2", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_sync(&lfs, &file) => 0; - size = strlen("blahblahblahblah"); - memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; - i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8); - i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' - -# outdated lookahead and split dir test -[cases.test_alloc_outdated_lookahead_split_dir] -if = 'BLOCK_SIZE == 512' -defines.BLOCK_COUNT = 1024 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // fill completely with two files - lfs_file_t file; - lfs_file_open(&lfs, &file, "exhaustion1", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - size_t size = strlen("blahblahblahblah"); - uint8_t buffer[1024]; - memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; - i < ((cfg->block_count-2)/2)*(cfg->block_size-8); - i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "exhaustion2", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - size = strlen("blahblahblahblah"); - memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; - i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8); - i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - // remount to force reset of lookahead - lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, cfg) => 0; - - // rewrite one file with a hole of one block - lfs_file_open(&lfs, &file, "exhaustion1", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_sync(&lfs, &file) => 0; - size = strlen("blahblahblahblah"); - memcpy(buffer, "blahblahblahblah", size); - for (lfs_size_t i = 0; - i < ((cfg->block_count-2)/2 - 1)*(cfg->block_size-8); - i += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - // try to allocate a directory, should fail! - lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC; - - // file should not fail - lfs_file_open(&lfs, &file, "notasplit", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "hi", 2) => 2; - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' +## allocator tests +## note for these to work there are a number constraints on the device geometry +#if = 'BLOCK_CYCLES == -1' +# +## parallel allocation test +#[cases.test_alloc_parallel] +#defines.FILES = 3 +#defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' +#code = ''' +# const char *names[] = {"bacon", "eggs", "pancakes"}; +# lfs_file_t files[FILES]; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "breakfast") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int n = 0; n < FILES; n++) { +# char path[1024]; +# sprintf(path, "breakfast/%s", names[n]); +# lfs_file_open(&lfs, &files[n], path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# } +# for (int n = 0; n < FILES; n++) { +# size_t size = strlen(names[n]); +# for (lfs_size_t i = 0; i < SIZE; i += size) { +# lfs_file_write(&lfs, &files[n], names[n], size) => size; +# } +# } +# for (int n = 0; n < FILES; n++) { +# lfs_file_close(&lfs, &files[n]) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int n = 0; n < FILES; n++) { +# char path[1024]; +# sprintf(path, "breakfast/%s", names[n]); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# size_t size = strlen(names[n]); +# for (lfs_size_t i = 0; i < SIZE; i += size) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# assert(memcmp(buffer, names[n], size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +#''' +# +## serial allocation test +#[cases.test_alloc_serial] +#defines.FILES = 3 +#defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' +#code = ''' +# const char *names[] = {"bacon", "eggs", "pancakes"}; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "breakfast") => 0; +# lfs_unmount(&lfs) => 0; +# +# for (int n = 0; n < FILES; n++) { +# lfs_mount(&lfs, cfg) => 0; +# char path[1024]; +# sprintf(path, "breakfast/%s", names[n]); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# size_t size = strlen(names[n]); +# uint8_t buffer[1024]; +# memcpy(buffer, names[n], size); +# for (int i = 0; i < SIZE; i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# } +# +# lfs_mount(&lfs, cfg) => 0; +# for (int n = 0; n < FILES; n++) { +# char path[1024]; +# sprintf(path, "breakfast/%s", names[n]); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# size_t size = strlen(names[n]); +# for (int i = 0; i < SIZE; i += size) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# assert(memcmp(buffer, names[n], size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +#''' +# +## parallel allocation reuse test +#[cases.test_alloc_parallel_reuse] +#defines.FILES = 3 +#defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' +#defines.CYCLES = [1, 10] +#code = ''' +# const char *names[] = {"bacon", "eggs", "pancakes"}; +# lfs_file_t files[FILES]; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# for (int c = 0; c < CYCLES; c++) { +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "breakfast") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int n = 0; n < FILES; n++) { +# char path[1024]; +# sprintf(path, "breakfast/%s", names[n]); +# lfs_file_open(&lfs, &files[n], path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# } +# for (int n = 0; n < FILES; n++) { +# size_t size = strlen(names[n]); +# for (int i = 0; i < SIZE; i += size) { +# lfs_file_write(&lfs, &files[n], names[n], size) => size; +# } +# } +# for (int n = 0; n < FILES; n++) { +# lfs_file_close(&lfs, &files[n]) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int n = 0; n < FILES; n++) { +# char path[1024]; +# sprintf(path, "breakfast/%s", names[n]); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# size_t size = strlen(names[n]); +# for (int i = 0; i < SIZE; i += size) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# assert(memcmp(buffer, names[n], size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int n = 0; n < FILES; n++) { +# char path[1024]; +# sprintf(path, "breakfast/%s", names[n]); +# lfs_remove(&lfs, path) => 0; +# } +# lfs_remove(&lfs, "breakfast") => 0; +# lfs_unmount(&lfs) => 0; +# } +#''' +# +## serial allocation reuse test +#[cases.test_alloc_serial_reuse] +#defines.FILES = 3 +#defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' +#defines.CYCLES = [1, 10] +#code = ''' +# const char *names[] = {"bacon", "eggs", "pancakes"}; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# for (int c = 0; c < CYCLES; c++) { +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "breakfast") => 0; +# lfs_unmount(&lfs) => 0; +# +# for (int n = 0; n < FILES; n++) { +# lfs_mount(&lfs, cfg) => 0; +# char path[1024]; +# sprintf(path, "breakfast/%s", names[n]); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# size_t size = strlen(names[n]); +# uint8_t buffer[1024]; +# memcpy(buffer, names[n], size); +# for (int i = 0; i < SIZE; i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# } +# +# lfs_mount(&lfs, cfg) => 0; +# for (int n = 0; n < FILES; n++) { +# char path[1024]; +# sprintf(path, "breakfast/%s", names[n]); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# size_t size = strlen(names[n]); +# for (int i = 0; i < SIZE; i += size) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# assert(memcmp(buffer, names[n], size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int n = 0; n < FILES; n++) { +# char path[1024]; +# sprintf(path, "breakfast/%s", names[n]); +# lfs_remove(&lfs, path) => 0; +# } +# lfs_remove(&lfs, "breakfast") => 0; +# lfs_unmount(&lfs) => 0; +# } +#''' +# +## exhaustion test +#[cases.test_alloc_exhaustion] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); +# size_t size = strlen("exhaustion"); +# uint8_t buffer[1024]; +# memcpy(buffer, "exhaustion", size); +# lfs_file_write(&lfs, &file, buffer, size) => size; +# lfs_file_sync(&lfs, &file) => 0; +# +# size = strlen("blahblahblahblah"); +# memcpy(buffer, "blahblahblahblah", size); +# lfs_ssize_t res; +# while (true) { +# res = lfs_file_write(&lfs, &file, buffer, size); +# if (res < 0) { +# break; +# } +# +# res => size; +# } +# res => LFS_ERR_NOSPC; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); +# size = strlen("exhaustion"); +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "exhaustion", size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## exhaustion wraparound test +#[cases.test_alloc_exhaustion_wraparound] +#defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); +# size_t size = strlen("buffering"); +# uint8_t buffer[1024]; +# memcpy(buffer, "buffering", size); +# for (int i = 0; i < SIZE; i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_remove(&lfs, "padding") => 0; +# +# lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); +# size = strlen("exhaustion"); +# memcpy(buffer, "exhaustion", size); +# lfs_file_write(&lfs, &file, buffer, size) => size; +# lfs_file_sync(&lfs, &file) => 0; +# +# size = strlen("blahblahblahblah"); +# memcpy(buffer, "blahblahblahblah", size); +# lfs_ssize_t res; +# while (true) { +# res = lfs_file_write(&lfs, &file, buffer, size); +# if (res < 0) { +# break; +# } +# +# res => size; +# } +# res => LFS_ERR_NOSPC; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); +# size = strlen("exhaustion"); +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "exhaustion", size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_remove(&lfs, "exhaustion") => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## dir exhaustion test +#[cases.test_alloc_dir_exhaustion] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // find out max file size +# lfs_mkdir(&lfs, "exhaustiondir") => 0; +# size_t size = strlen("blahblahblahblah"); +# uint8_t buffer[1024]; +# memcpy(buffer, "blahblahblahblah", size); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); +# int count = 0; +# int err; +# while (true) { +# err = lfs_file_write(&lfs, &file, buffer, size); +# if (err < 0) { +# break; +# } +# +# count += 1; +# } +# err => LFS_ERR_NOSPC; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_remove(&lfs, "exhaustion") => 0; +# lfs_remove(&lfs, "exhaustiondir") => 0; +# +# // see if dir fits with max file size +# lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); +# for (int i = 0; i < count; i++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_mkdir(&lfs, "exhaustiondir") => 0; +# lfs_remove(&lfs, "exhaustiondir") => 0; +# lfs_remove(&lfs, "exhaustion") => 0; +# +# // see if dir fits with > max file size +# lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); +# for (int i = 0; i < count+1; i++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; +# +# lfs_remove(&lfs, "exhaustion") => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## what if we have a bad block during an allocation scan? +#[cases.test_alloc_bad_blocks] +#in = "lfs.c" +#defines.ERASE_CYCLES = 0xffffffff +#defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_READERROR' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# // first fill to exhaustion to find available space +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# uint8_t buffer[1024]; +# strcpy((char*)buffer, "waka"); +# size_t size = strlen("waka"); +# lfs_size_t filesize = 0; +# while (true) { +# lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); +# assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); +# if (res == LFS_ERR_NOSPC) { +# break; +# } +# filesize += size; +# } +# lfs_file_close(&lfs, &file) => 0; +# // now fill all but a couple of blocks of the filesystem with data +# filesize -= 3*BLOCK_SIZE; +# lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# strcpy((char*)buffer, "waka"); +# size = strlen("waka"); +# for (lfs_size_t i = 0; i < filesize/size; i++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# // also save head of file so we can error during lookahead scan +# lfs_block_t fileblock = file.ctz.head; +# lfs_unmount(&lfs) => 0; +# +# // remount to force an alloc scan +# lfs_mount(&lfs, cfg) => 0; +# +# // but mark the head of our file as a "bad block", this is force our +# // scan to bail early +# lfs_emubd_setwear(cfg, fileblock, 0xffffffff) => 0; +# lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# strcpy((char*)buffer, "chomp"); +# size = strlen("chomp"); +# while (true) { +# lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); +# assert(res == (lfs_ssize_t)size || res == LFS_ERR_CORRUPT); +# if (res == LFS_ERR_CORRUPT) { +# break; +# } +# } +# lfs_file_close(&lfs, &file) => 0; +# +# // now reverse the "bad block" and try to write the file again until we +# // run out of space +# lfs_emubd_setwear(cfg, fileblock, 0) => 0; +# lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# strcpy((char*)buffer, "chomp"); +# size = strlen("chomp"); +# while (true) { +# lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); +# assert(res == (lfs_ssize_t)size || res == LFS_ERR_NOSPC); +# if (res == LFS_ERR_NOSPC) { +# break; +# } +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +# +# // check that the disk isn't hurt +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0; +# strcpy((char*)buffer, "waka"); +# size = strlen("waka"); +# for (lfs_size_t i = 0; i < filesize/size; i++) { +# uint8_t rbuffer[4]; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(memcmp(rbuffer, buffer, size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +# +## Below, I don't like these tests. They're fragile and depend _heavily_ +## on the geometry of the block device. But they are valuable. Eventually they +## should be removed and replaced with generalized tests. +# +## chained dir exhaustion test +#[cases.test_alloc_chained_dir_exhaustion] +#if = 'BLOCK_SIZE == 512' +#defines.BLOCK_COUNT = 1024 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // find out max file size +# lfs_mkdir(&lfs, "exhaustiondir") => 0; +# for (int i = 0; i < 10; i++) { +# char path[1024]; +# sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); +# lfs_mkdir(&lfs, path) => 0; +# } +# size_t size = strlen("blahblahblahblah"); +# uint8_t buffer[1024]; +# memcpy(buffer, "blahblahblahblah", size); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); +# int count = 0; +# int err; +# while (true) { +# err = lfs_file_write(&lfs, &file, buffer, size); +# if (err < 0) { +# break; +# } +# +# count += 1; +# } +# err => LFS_ERR_NOSPC; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_remove(&lfs, "exhaustion") => 0; +# lfs_remove(&lfs, "exhaustiondir") => 0; +# for (int i = 0; i < 10; i++) { +# char path[1024]; +# sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); +# lfs_remove(&lfs, path) => 0; +# } +# +# // see that chained dir fails +# lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); +# for (int i = 0; i < count+1; i++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_sync(&lfs, &file) => 0; +# +# for (int i = 0; i < 10; i++) { +# char path[1024]; +# sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); +# lfs_mkdir(&lfs, path) => 0; +# } +# +# lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; +# +# // shorten file to try a second chained dir +# while (true) { +# err = lfs_mkdir(&lfs, "exhaustiondir"); +# if (err != LFS_ERR_NOSPC) { +# break; +# } +# +# lfs_ssize_t filesize = lfs_file_size(&lfs, &file); +# filesize > 0 => true; +# +# lfs_file_truncate(&lfs, &file, filesize - size) => 0; +# lfs_file_sync(&lfs, &file) => 0; +# } +# err => 0; +# +# lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## split dir test +#[cases.test_alloc_split_dir] +#if = 'BLOCK_SIZE == 512' +#defines.BLOCK_COUNT = 1024 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // create one block hole for half a directory +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# for (lfs_size_t i = 0; i < cfg->block_size; i += 2) { +# uint8_t buffer[1024]; +# memcpy(&buffer[i], "hi", 2); +# } +# uint8_t buffer[1024]; +# lfs_file_write(&lfs, &file, buffer, cfg->block_size) => cfg->block_size; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); +# size_t size = strlen("blahblahblahblah"); +# memcpy(buffer, "blahblahblahblah", size); +# for (lfs_size_t i = 0; +# i < (cfg->block_count-4)*(cfg->block_size-8); +# i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# // remount to force reset of lookahead +# lfs_unmount(&lfs) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // open hole +# lfs_remove(&lfs, "bump") => 0; +# +# lfs_mkdir(&lfs, "splitdir") => 0; +# lfs_file_open(&lfs, &file, "splitdir/bump", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# for (lfs_size_t i = 0; i < cfg->block_size; i += 2) { +# memcpy(&buffer[i], "hi", 2); +# } +# lfs_file_write(&lfs, &file, buffer, 2*cfg->block_size) => LFS_ERR_NOSPC; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' +# +## outdated lookahead test +#[cases.test_alloc_outdated_lookahead] +#if = 'BLOCK_SIZE == 512' +#defines.BLOCK_COUNT = 1024 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // fill completely with two files +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "exhaustion1", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# size_t size = strlen("blahblahblahblah"); +# uint8_t buffer[1024]; +# memcpy(buffer, "blahblahblahblah", size); +# for (lfs_size_t i = 0; +# i < ((cfg->block_count-2)/2)*(cfg->block_size-8); +# i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "exhaustion2", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# size = strlen("blahblahblahblah"); +# memcpy(buffer, "blahblahblahblah", size); +# for (lfs_size_t i = 0; +# i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8); +# i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# // remount to force reset of lookahead +# lfs_unmount(&lfs) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // rewrite one file +# lfs_file_open(&lfs, &file, "exhaustion1", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_sync(&lfs, &file) => 0; +# size = strlen("blahblahblahblah"); +# memcpy(buffer, "blahblahblahblah", size); +# for (lfs_size_t i = 0; +# i < ((cfg->block_count-2)/2)*(cfg->block_size-8); +# i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# // rewrite second file, this requires lookahead does not +# // use old population +# lfs_file_open(&lfs, &file, "exhaustion2", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_sync(&lfs, &file) => 0; +# size = strlen("blahblahblahblah"); +# memcpy(buffer, "blahblahblahblah", size); +# for (lfs_size_t i = 0; +# i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8); +# i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' +# +## outdated lookahead and split dir test +#[cases.test_alloc_outdated_lookahead_split_dir] +#if = 'BLOCK_SIZE == 512' +#defines.BLOCK_COUNT = 1024 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // fill completely with two files +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "exhaustion1", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# size_t size = strlen("blahblahblahblah"); +# uint8_t buffer[1024]; +# memcpy(buffer, "blahblahblahblah", size); +# for (lfs_size_t i = 0; +# i < ((cfg->block_count-2)/2)*(cfg->block_size-8); +# i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "exhaustion2", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# size = strlen("blahblahblahblah"); +# memcpy(buffer, "blahblahblahblah", size); +# for (lfs_size_t i = 0; +# i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8); +# i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# // remount to force reset of lookahead +# lfs_unmount(&lfs) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // rewrite one file with a hole of one block +# lfs_file_open(&lfs, &file, "exhaustion1", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_sync(&lfs, &file) => 0; +# size = strlen("blahblahblahblah"); +# memcpy(buffer, "blahblahblahblah", size); +# for (lfs_size_t i = 0; +# i < ((cfg->block_count-2)/2 - 1)*(cfg->block_size-8); +# i += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# // try to allocate a directory, should fail! +# lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC; +# +# // file should not fail +# lfs_file_open(&lfs, &file, "notasplit", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "hi", 2) => 2; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' diff --git a/tests/test_attrs.toml b/tests/test_attrs.toml index 3c69001c..86115efd 100644 --- a/tests/test_attrs.toml +++ b/tests/test_attrs.toml @@ -1,316 +1,316 @@ -[cases.test_attrs_get_set] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "hello") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); - lfs_file_close(&lfs, &file); - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - uint8_t buffer[1024]; - memset(buffer, 0, sizeof(buffer)); - lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0; - lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; - lfs_setattr(&lfs, "hello", 'C', "ccccc", 5) => 0; - lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6; - lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "bbbbbb", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - lfs_setattr(&lfs, "hello", 'B', "", 0) => 0; - lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 0; - lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - lfs_removeattr(&lfs, "hello", 'B') => 0; - lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => LFS_ERR_NOATTR; - lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; - lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6; - lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "dddddd", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0; - lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 3; - lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "eee\0\0\0", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; - lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0; - lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 9; - lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; - - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - memset(buffer, 0, sizeof(buffer)); - lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9; - lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "fffffffff", 9) => 0; - memcmp(buffer+13, "ccccc", 5) => 0; - - lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); - memcmp(buffer, "hello", strlen("hello")) => 0; - lfs_file_close(&lfs, &file); - lfs_unmount(&lfs) => 0; -''' - -[cases.test_attrs_get_set_root] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "hello") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); - lfs_file_close(&lfs, &file); - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - uint8_t buffer[1024]; - memset(buffer, 0, sizeof(buffer)); - lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0; - lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; - lfs_setattr(&lfs, "/", 'C', "ccccc", 5) => 0; - lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; - lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "bbbbbb", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - lfs_setattr(&lfs, "/", 'B', "", 0) => 0; - lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 0; - lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - lfs_removeattr(&lfs, "/", 'B') => 0; - lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => LFS_ERR_NOATTR; - lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; - lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; - lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "dddddd", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0; - lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 3; - lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "eee\0\0\0", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; - lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0; - lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 9; - lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - memset(buffer, 0, sizeof(buffer)); - lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; - lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9; - lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "fffffffff", 9) => 0; - memcmp(buffer+13, "ccccc", 5) => 0; - - lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); - memcmp(buffer, "hello", strlen("hello")) => 0; - lfs_file_close(&lfs, &file); - lfs_unmount(&lfs) => 0; -''' - -[cases.test_attrs_get_set_file] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "hello") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); - lfs_file_close(&lfs, &file); - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - uint8_t buffer[1024]; - memset(buffer, 0, sizeof(buffer)); - struct lfs_attr attrs1[] = { - {'A', buffer, 4}, - {'B', buffer+4, 6}, - {'C', buffer+10, 5}, - }; - struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; - - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; - memcpy(buffer, "aaaa", 4); - memcpy(buffer+4, "bbbbbb", 6); - memcpy(buffer+10, "ccccc", 5); - lfs_file_close(&lfs, &file) => 0; - memset(buffer, 0, 15); - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; - lfs_file_close(&lfs, &file) => 0; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "bbbbbb", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - attrs1[1].size = 0; - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; - lfs_file_close(&lfs, &file) => 0; - memset(buffer, 0, 15); - attrs1[1].size = 6; - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; - lfs_file_close(&lfs, &file) => 0; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - attrs1[1].size = 6; - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; - memcpy(buffer+4, "dddddd", 6); - lfs_file_close(&lfs, &file) => 0; - memset(buffer, 0, 15); - attrs1[1].size = 6; - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; - lfs_file_close(&lfs, &file) => 0; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "dddddd", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - attrs1[1].size = 3; - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; - memcpy(buffer+4, "eee", 3); - lfs_file_close(&lfs, &file) => 0; - memset(buffer, 0, 15); - attrs1[1].size = 6; - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; - lfs_file_close(&lfs, &file) => 0; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "eee\0\0\0", 6) => 0; - memcmp(buffer+10, "ccccc", 5) => 0; - - attrs1[0].size = LFS_ATTR_MAX+1; - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) - => LFS_ERR_NOSPC; - - struct lfs_attr attrs2[] = { - {'A', buffer, 4}, - {'B', buffer+4, 9}, - {'C', buffer+13, 5}, - }; - struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0; - memcpy(buffer+4, "fffffffff", 9); - lfs_file_close(&lfs, &file) => 0; - attrs1[0].size = 4; - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - memset(buffer, 0, sizeof(buffer)); - struct lfs_attr attrs3[] = { - {'A', buffer, 4}, - {'B', buffer+4, 9}, - {'C', buffer+13, 5}, - }; - struct lfs_file_config cfg3 = {.attrs=attrs3, .attr_count=3}; - - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0; - lfs_file_close(&lfs, &file) => 0; - memcmp(buffer, "aaaa", 4) => 0; - memcmp(buffer+4, "fffffffff", 9) => 0; - memcmp(buffer+13, "ccccc", 5) => 0; - - lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); - memcmp(buffer, "hello", strlen("hello")) => 0; - lfs_file_close(&lfs, &file); - lfs_unmount(&lfs) => 0; -''' - -[cases.test_attrs_deferred_file] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "hello") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); - lfs_file_close(&lfs, &file); - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff", 9) => 0; - lfs_setattr(&lfs, "hello/hello", 'C', "ccccc", 5) => 0; - - uint8_t buffer[1024]; - memset(buffer, 0, sizeof(buffer)); - struct lfs_attr attrs1[] = { - {'B', "gggg", 4}, - {'C', "", 0}, - {'D', "hhhh", 4}, - }; - struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; - - lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; - - lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 9; - lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 5; - lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; - memcmp(buffer, "fffffffff", 9) => 0; - memcmp(buffer+9, "ccccc\0\0\0\0", 9) => 0; - memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; - - lfs_file_sync(&lfs, &file) => 0; - lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 4; - lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 0; - lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4; - memcmp(buffer, "gggg\0\0\0\0\0", 9) => 0; - memcmp(buffer+9, "\0\0\0\0\0\0\0\0\0", 9) => 0; - memcmp(buffer+18, "hhhh\0\0\0\0\0", 9) => 0; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' +#[cases.test_attrs_get_set] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "hello") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); +# lfs_file_close(&lfs, &file); +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# uint8_t buffer[1024]; +# memset(buffer, 0, sizeof(buffer)); +# lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0; +# lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; +# lfs_setattr(&lfs, "hello", 'C', "ccccc", 5) => 0; +# lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6; +# lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "bbbbbb", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# lfs_setattr(&lfs, "hello", 'B', "", 0) => 0; +# lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 0; +# lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# lfs_removeattr(&lfs, "hello", 'B') => 0; +# lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => LFS_ERR_NOATTR; +# lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; +# lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6; +# lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "dddddd", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0; +# lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 3; +# lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "eee\0\0\0", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; +# lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0; +# lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 9; +# lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; +# +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# memset(buffer, 0, sizeof(buffer)); +# lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9; +# lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "fffffffff", 9) => 0; +# memcmp(buffer+13, "ccccc", 5) => 0; +# +# lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); +# memcmp(buffer, "hello", strlen("hello")) => 0; +# lfs_file_close(&lfs, &file); +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_attrs_get_set_root] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "hello") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); +# lfs_file_close(&lfs, &file); +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# uint8_t buffer[1024]; +# memset(buffer, 0, sizeof(buffer)); +# lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0; +# lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; +# lfs_setattr(&lfs, "/", 'C', "ccccc", 5) => 0; +# lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; +# lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "bbbbbb", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# lfs_setattr(&lfs, "/", 'B', "", 0) => 0; +# lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 0; +# lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# lfs_removeattr(&lfs, "/", 'B') => 0; +# lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => LFS_ERR_NOATTR; +# lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; +# lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; +# lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "dddddd", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0; +# lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 3; +# lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "eee\0\0\0", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; +# lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0; +# lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 9; +# lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# memset(buffer, 0, sizeof(buffer)); +# lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; +# lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9; +# lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "fffffffff", 9) => 0; +# memcmp(buffer+13, "ccccc", 5) => 0; +# +# lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); +# memcmp(buffer, "hello", strlen("hello")) => 0; +# lfs_file_close(&lfs, &file); +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_attrs_get_set_file] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "hello") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); +# lfs_file_close(&lfs, &file); +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# uint8_t buffer[1024]; +# memset(buffer, 0, sizeof(buffer)); +# struct lfs_attr attrs1[] = { +# {'A', buffer, 4}, +# {'B', buffer+4, 6}, +# {'C', buffer+10, 5}, +# }; +# struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; +# +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; +# memcpy(buffer, "aaaa", 4); +# memcpy(buffer+4, "bbbbbb", 6); +# memcpy(buffer+10, "ccccc", 5); +# lfs_file_close(&lfs, &file) => 0; +# memset(buffer, 0, 15); +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; +# lfs_file_close(&lfs, &file) => 0; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "bbbbbb", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# attrs1[1].size = 0; +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; +# lfs_file_close(&lfs, &file) => 0; +# memset(buffer, 0, 15); +# attrs1[1].size = 6; +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; +# lfs_file_close(&lfs, &file) => 0; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# attrs1[1].size = 6; +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; +# memcpy(buffer+4, "dddddd", 6); +# lfs_file_close(&lfs, &file) => 0; +# memset(buffer, 0, 15); +# attrs1[1].size = 6; +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; +# lfs_file_close(&lfs, &file) => 0; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "dddddd", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# attrs1[1].size = 3; +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; +# memcpy(buffer+4, "eee", 3); +# lfs_file_close(&lfs, &file) => 0; +# memset(buffer, 0, 15); +# attrs1[1].size = 6; +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; +# lfs_file_close(&lfs, &file) => 0; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "eee\0\0\0", 6) => 0; +# memcmp(buffer+10, "ccccc", 5) => 0; +# +# attrs1[0].size = LFS_ATTR_MAX+1; +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) +# => LFS_ERR_NOSPC; +# +# struct lfs_attr attrs2[] = { +# {'A', buffer, 4}, +# {'B', buffer+4, 9}, +# {'C', buffer+13, 5}, +# }; +# struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0; +# memcpy(buffer+4, "fffffffff", 9); +# lfs_file_close(&lfs, &file) => 0; +# attrs1[0].size = 4; +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# memset(buffer, 0, sizeof(buffer)); +# struct lfs_attr attrs3[] = { +# {'A', buffer, 4}, +# {'B', buffer+4, 9}, +# {'C', buffer+13, 5}, +# }; +# struct lfs_file_config cfg3 = {.attrs=attrs3, .attr_count=3}; +# +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0; +# lfs_file_close(&lfs, &file) => 0; +# memcmp(buffer, "aaaa", 4) => 0; +# memcmp(buffer+4, "fffffffff", 9) => 0; +# memcmp(buffer+13, "ccccc", 5) => 0; +# +# lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); +# memcmp(buffer, "hello", strlen("hello")) => 0; +# lfs_file_close(&lfs, &file); +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_attrs_deferred_file] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "hello") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); +# lfs_file_close(&lfs, &file); +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff", 9) => 0; +# lfs_setattr(&lfs, "hello/hello", 'C', "ccccc", 5) => 0; +# +# uint8_t buffer[1024]; +# memset(buffer, 0, sizeof(buffer)); +# struct lfs_attr attrs1[] = { +# {'B', "gggg", 4}, +# {'C', "", 0}, +# {'D', "hhhh", 4}, +# }; +# struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; +# +# lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; +# +# lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 9; +# lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 5; +# lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; +# memcmp(buffer, "fffffffff", 9) => 0; +# memcmp(buffer+9, "ccccc\0\0\0\0", 9) => 0; +# memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; +# +# lfs_file_sync(&lfs, &file) => 0; +# lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 4; +# lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 0; +# lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4; +# memcmp(buffer, "gggg\0\0\0\0\0", 9) => 0; +# memcmp(buffer+9, "\0\0\0\0\0\0\0\0\0", 9) => 0; +# memcmp(buffer+18, "hhhh\0\0\0\0\0", 9) => 0; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' diff --git a/tests/test_badblocks.toml b/tests/test_badblocks.toml index b50b3933..2859da5e 100644 --- a/tests/test_badblocks.toml +++ b/tests/test_badblocks.toml @@ -1,260 +1,260 @@ -# bad blocks with block cycles should be tested in test_relocations -if = '(int32_t)BLOCK_CYCLES == -1' - -[cases.test_badblocks_single] -defines.BLOCK_COUNT = 256 # small bd so test runs faster -defines.ERASE_CYCLES = 0xffffffff -defines.ERASE_VALUE = [0x00, 0xff, -1] -defines.BADBLOCK_BEHAVIOR = [ - 'LFS_EMUBD_BADBLOCK_PROGERROR', - 'LFS_EMUBD_BADBLOCK_ERASEERROR', - 'LFS_EMUBD_BADBLOCK_READERROR', - 'LFS_EMUBD_BADBLOCK_PROGNOOP', - 'LFS_EMUBD_BADBLOCK_ERASENOOP', -] -defines.NAMEMULT = 64 -defines.FILEMULT = 1 -code = ''' - for (lfs_block_t badblock = 2; badblock < BLOCK_COUNT; badblock++) { - lfs_emubd_setwear(cfg, badblock-1, 0) => 0; - lfs_emubd_setwear(cfg, badblock, 0xffffffff) => 0; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 1; i < 10; i++) { - uint8_t buffer[1024]; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j] = '0'+i; - } - buffer[NAMEMULT] = '\0'; - lfs_mkdir(&lfs, (char*)buffer) => 0; - - buffer[NAMEMULT] = '/'; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j+NAMEMULT+1] = '0'+i; - } - buffer[2*NAMEMULT+1] = '\0'; - lfs_file_t file; - lfs_file_open(&lfs, &file, (char*)buffer, - LFS_O_WRONLY | LFS_O_CREAT) => 0; - - lfs_size_t size = NAMEMULT; - for (int j = 0; j < i*FILEMULT; j++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 1; i < 10; i++) { - uint8_t buffer[1024]; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j] = '0'+i; - } - buffer[NAMEMULT] = '\0'; - struct lfs_info info; - lfs_stat(&lfs, (char*)buffer, &info) => 0; - info.type => LFS_TYPE_DIR; - - buffer[NAMEMULT] = '/'; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j+NAMEMULT+1] = '0'+i; - } - buffer[2*NAMEMULT+1] = '\0'; - lfs_file_t file; - lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; - - int size = NAMEMULT; - for (int j = 0; j < i*FILEMULT; j++) { - uint8_t rbuffer[1024]; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(buffer, rbuffer, size) => 0; - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - } -''' - -[cases.test_badblocks_region_corruption] # (causes cascading failures) -defines.BLOCK_COUNT = 256 # small bd so test runs faster -defines.ERASE_CYCLES = 0xffffffff -defines.ERASE_VALUE = [0x00, 0xff, -1] -defines.BADBLOCK_BEHAVIOR = [ - 'LFS_EMUBD_BADBLOCK_PROGERROR', - 'LFS_EMUBD_BADBLOCK_ERASEERROR', - 'LFS_EMUBD_BADBLOCK_READERROR', - 'LFS_EMUBD_BADBLOCK_PROGNOOP', - 'LFS_EMUBD_BADBLOCK_ERASENOOP', -] -defines.NAMEMULT = 64 -defines.FILEMULT = 1 -code = ''' - for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) { - lfs_emubd_setwear(cfg, i+2, 0xffffffff) => 0; - } - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 1; i < 10; i++) { - uint8_t buffer[1024]; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j] = '0'+i; - } - buffer[NAMEMULT] = '\0'; - lfs_mkdir(&lfs, (char*)buffer) => 0; - - buffer[NAMEMULT] = '/'; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j+NAMEMULT+1] = '0'+i; - } - buffer[2*NAMEMULT+1] = '\0'; - lfs_file_t file; - lfs_file_open(&lfs, &file, (char*)buffer, - LFS_O_WRONLY | LFS_O_CREAT) => 0; - - lfs_size_t size = NAMEMULT; - for (int j = 0; j < i*FILEMULT; j++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 1; i < 10; i++) { - uint8_t buffer[1024]; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j] = '0'+i; - } - buffer[NAMEMULT] = '\0'; - struct lfs_info info; - lfs_stat(&lfs, (char*)buffer, &info) => 0; - info.type => LFS_TYPE_DIR; - - buffer[NAMEMULT] = '/'; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j+NAMEMULT+1] = '0'+i; - } - buffer[2*NAMEMULT+1] = '\0'; - lfs_file_t file; - lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; - - lfs_size_t size = NAMEMULT; - for (int j = 0; j < i*FILEMULT; j++) { - uint8_t rbuffer[1024]; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(buffer, rbuffer, size) => 0; - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; -''' - -[cases.test_badblocks_alternating_corruption] # (causes cascading failures) -defines.BLOCK_COUNT = 256 # small bd so test runs faster -defines.ERASE_CYCLES = 0xffffffff -defines.ERASE_VALUE = [0x00, 0xff, -1] -defines.BADBLOCK_BEHAVIOR = [ - 'LFS_EMUBD_BADBLOCK_PROGERROR', - 'LFS_EMUBD_BADBLOCK_ERASEERROR', - 'LFS_EMUBD_BADBLOCK_READERROR', - 'LFS_EMUBD_BADBLOCK_PROGNOOP', - 'LFS_EMUBD_BADBLOCK_ERASENOOP', -] -defines.NAMEMULT = 64 -defines.FILEMULT = 1 -code = ''' - for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) { - lfs_emubd_setwear(cfg, (2*i) + 2, 0xffffffff) => 0; - } - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 1; i < 10; i++) { - uint8_t buffer[1024]; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j] = '0'+i; - } - buffer[NAMEMULT] = '\0'; - lfs_mkdir(&lfs, (char*)buffer) => 0; - - buffer[NAMEMULT] = '/'; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j+NAMEMULT+1] = '0'+i; - } - buffer[2*NAMEMULT+1] = '\0'; - lfs_file_t file; - lfs_file_open(&lfs, &file, (char*)buffer, - LFS_O_WRONLY | LFS_O_CREAT) => 0; - - lfs_size_t size = NAMEMULT; - for (int j = 0; j < i*FILEMULT; j++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 1; i < 10; i++) { - uint8_t buffer[1024]; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j] = '0'+i; - } - buffer[NAMEMULT] = '\0'; - struct lfs_info info; - lfs_stat(&lfs, (char*)buffer, &info) => 0; - info.type => LFS_TYPE_DIR; - - buffer[NAMEMULT] = '/'; - for (int j = 0; j < NAMEMULT; j++) { - buffer[j+NAMEMULT+1] = '0'+i; - } - buffer[2*NAMEMULT+1] = '\0'; - lfs_file_t file; - lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; - - lfs_size_t size = NAMEMULT; - for (int j = 0; j < i*FILEMULT; j++) { - uint8_t rbuffer[1024]; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(buffer, rbuffer, size) => 0; - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; -''' - -# other corner cases -[cases.test_badblocks_superblocks] # (corrupt 1 or 0) -defines.ERASE_CYCLES = 0xffffffff -defines.ERASE_VALUE = [0x00, 0xff, -1] -defines.BADBLOCK_BEHAVIOR = [ - 'LFS_EMUBD_BADBLOCK_PROGERROR', - 'LFS_EMUBD_BADBLOCK_ERASEERROR', - 'LFS_EMUBD_BADBLOCK_READERROR', - 'LFS_EMUBD_BADBLOCK_PROGNOOP', - 'LFS_EMUBD_BADBLOCK_ERASENOOP', -] -code = ''' - lfs_emubd_setwear(cfg, 0, 0xffffffff) => 0; - lfs_emubd_setwear(cfg, 1, 0xffffffff) => 0; - - lfs_t lfs; - lfs_format(&lfs, cfg) => LFS_ERR_NOSPC; - lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; -''' +## bad blocks with block cycles should be tested in test_relocations +#if = '(int32_t)BLOCK_CYCLES == -1' +# +#[cases.test_badblocks_single] +#defines.BLOCK_COUNT = 256 # small bd so test runs faster +#defines.ERASE_CYCLES = 0xffffffff +#defines.ERASE_VALUE = [0x00, 0xff, -1] +#defines.BADBLOCK_BEHAVIOR = [ +# 'LFS_EMUBD_BADBLOCK_PROGERROR', +# 'LFS_EMUBD_BADBLOCK_ERASEERROR', +# 'LFS_EMUBD_BADBLOCK_READERROR', +# 'LFS_EMUBD_BADBLOCK_PROGNOOP', +# 'LFS_EMUBD_BADBLOCK_ERASENOOP', +#] +#defines.NAMEMULT = 64 +#defines.FILEMULT = 1 +#code = ''' +# for (lfs_block_t badblock = 2; badblock < BLOCK_COUNT; badblock++) { +# lfs_emubd_setwear(cfg, badblock-1, 0) => 0; +# lfs_emubd_setwear(cfg, badblock, 0xffffffff) => 0; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 1; i < 10; i++) { +# uint8_t buffer[1024]; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j] = '0'+i; +# } +# buffer[NAMEMULT] = '\0'; +# lfs_mkdir(&lfs, (char*)buffer) => 0; +# +# buffer[NAMEMULT] = '/'; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j+NAMEMULT+1] = '0'+i; +# } +# buffer[2*NAMEMULT+1] = '\0'; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, (char*)buffer, +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# +# lfs_size_t size = NAMEMULT; +# for (int j = 0; j < i*FILEMULT; j++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 1; i < 10; i++) { +# uint8_t buffer[1024]; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j] = '0'+i; +# } +# buffer[NAMEMULT] = '\0'; +# struct lfs_info info; +# lfs_stat(&lfs, (char*)buffer, &info) => 0; +# info.type => LFS_TYPE_DIR; +# +# buffer[NAMEMULT] = '/'; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j+NAMEMULT+1] = '0'+i; +# } +# buffer[2*NAMEMULT+1] = '\0'; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; +# +# int size = NAMEMULT; +# for (int j = 0; j < i*FILEMULT; j++) { +# uint8_t rbuffer[1024]; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(buffer, rbuffer, size) => 0; +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# } +#''' +# +#[cases.test_badblocks_region_corruption] # (causes cascading failures) +#defines.BLOCK_COUNT = 256 # small bd so test runs faster +#defines.ERASE_CYCLES = 0xffffffff +#defines.ERASE_VALUE = [0x00, 0xff, -1] +#defines.BADBLOCK_BEHAVIOR = [ +# 'LFS_EMUBD_BADBLOCK_PROGERROR', +# 'LFS_EMUBD_BADBLOCK_ERASEERROR', +# 'LFS_EMUBD_BADBLOCK_READERROR', +# 'LFS_EMUBD_BADBLOCK_PROGNOOP', +# 'LFS_EMUBD_BADBLOCK_ERASENOOP', +#] +#defines.NAMEMULT = 64 +#defines.FILEMULT = 1 +#code = ''' +# for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) { +# lfs_emubd_setwear(cfg, i+2, 0xffffffff) => 0; +# } +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 1; i < 10; i++) { +# uint8_t buffer[1024]; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j] = '0'+i; +# } +# buffer[NAMEMULT] = '\0'; +# lfs_mkdir(&lfs, (char*)buffer) => 0; +# +# buffer[NAMEMULT] = '/'; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j+NAMEMULT+1] = '0'+i; +# } +# buffer[2*NAMEMULT+1] = '\0'; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, (char*)buffer, +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# +# lfs_size_t size = NAMEMULT; +# for (int j = 0; j < i*FILEMULT; j++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 1; i < 10; i++) { +# uint8_t buffer[1024]; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j] = '0'+i; +# } +# buffer[NAMEMULT] = '\0'; +# struct lfs_info info; +# lfs_stat(&lfs, (char*)buffer, &info) => 0; +# info.type => LFS_TYPE_DIR; +# +# buffer[NAMEMULT] = '/'; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j+NAMEMULT+1] = '0'+i; +# } +# buffer[2*NAMEMULT+1] = '\0'; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; +# +# lfs_size_t size = NAMEMULT; +# for (int j = 0; j < i*FILEMULT; j++) { +# uint8_t rbuffer[1024]; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(buffer, rbuffer, size) => 0; +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_badblocks_alternating_corruption] # (causes cascading failures) +#defines.BLOCK_COUNT = 256 # small bd so test runs faster +#defines.ERASE_CYCLES = 0xffffffff +#defines.ERASE_VALUE = [0x00, 0xff, -1] +#defines.BADBLOCK_BEHAVIOR = [ +# 'LFS_EMUBD_BADBLOCK_PROGERROR', +# 'LFS_EMUBD_BADBLOCK_ERASEERROR', +# 'LFS_EMUBD_BADBLOCK_READERROR', +# 'LFS_EMUBD_BADBLOCK_PROGNOOP', +# 'LFS_EMUBD_BADBLOCK_ERASENOOP', +#] +#defines.NAMEMULT = 64 +#defines.FILEMULT = 1 +#code = ''' +# for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) { +# lfs_emubd_setwear(cfg, (2*i) + 2, 0xffffffff) => 0; +# } +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 1; i < 10; i++) { +# uint8_t buffer[1024]; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j] = '0'+i; +# } +# buffer[NAMEMULT] = '\0'; +# lfs_mkdir(&lfs, (char*)buffer) => 0; +# +# buffer[NAMEMULT] = '/'; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j+NAMEMULT+1] = '0'+i; +# } +# buffer[2*NAMEMULT+1] = '\0'; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, (char*)buffer, +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# +# lfs_size_t size = NAMEMULT; +# for (int j = 0; j < i*FILEMULT; j++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 1; i < 10; i++) { +# uint8_t buffer[1024]; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j] = '0'+i; +# } +# buffer[NAMEMULT] = '\0'; +# struct lfs_info info; +# lfs_stat(&lfs, (char*)buffer, &info) => 0; +# info.type => LFS_TYPE_DIR; +# +# buffer[NAMEMULT] = '/'; +# for (int j = 0; j < NAMEMULT; j++) { +# buffer[j+NAMEMULT+1] = '0'+i; +# } +# buffer[2*NAMEMULT+1] = '\0'; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; +# +# lfs_size_t size = NAMEMULT; +# for (int j = 0; j < i*FILEMULT; j++) { +# uint8_t rbuffer[1024]; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(buffer, rbuffer, size) => 0; +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +#''' +# +## other corner cases +#[cases.test_badblocks_superblocks] # (corrupt 1 or 0) +#defines.ERASE_CYCLES = 0xffffffff +#defines.ERASE_VALUE = [0x00, 0xff, -1] +#defines.BADBLOCK_BEHAVIOR = [ +# 'LFS_EMUBD_BADBLOCK_PROGERROR', +# 'LFS_EMUBD_BADBLOCK_ERASEERROR', +# 'LFS_EMUBD_BADBLOCK_READERROR', +# 'LFS_EMUBD_BADBLOCK_PROGNOOP', +# 'LFS_EMUBD_BADBLOCK_ERASENOOP', +#] +#code = ''' +# lfs_emubd_setwear(cfg, 0, 0xffffffff) => 0; +# lfs_emubd_setwear(cfg, 1, 0xffffffff) => 0; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => LFS_ERR_NOSPC; +# lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; +#''' diff --git a/tests/test_dirs.toml b/tests/test_dirs.toml index 956bc486..bda62e1b 100644 --- a/tests/test_dirs.toml +++ b/tests/test_dirs.toml @@ -1,932 +1,932 @@ -[cases.test_dirs_root] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_dirs_many_creation] -defines.N = 'range(3, 100, 3)' -if = 'N < BLOCK_COUNT/2' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "dir%03d", i); - lfs_mkdir(&lfs, path) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "dir%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_dirs_many_removal] -defines.N = 'range(3, 100, 11)' -if = 'N < BLOCK_COUNT/2' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "removeme%03d", i); - lfs_mkdir(&lfs, path) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "removeme%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs); - - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "removeme%03d", i); - lfs_remove(&lfs, path) => 0; - } - lfs_unmount(&lfs); - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_dirs_many_rename] -defines.N = 'range(3, 100, 11)' -if = 'N < BLOCK_COUNT/2' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "test%03d", i); - lfs_mkdir(&lfs, path) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "test%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs); - - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - char oldpath[128]; - char newpath[128]; - sprintf(oldpath, "test%03d", i); - sprintf(newpath, "tedd%03d", i); - lfs_rename(&lfs, oldpath, newpath) => 0; - } - lfs_unmount(&lfs); - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "tedd%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs); -''' - -[cases.test_dirs_many_reentrant] -defines.N = [5, 11] -if = 'BLOCK_COUNT >= 4*N' -reentrant = true -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "hi%03d", i); - err = lfs_mkdir(&lfs, path); - assert(err == 0 || err == LFS_ERR_EXIST); - } - - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "hello%03d", i); - err = lfs_remove(&lfs, path); - assert(err == 0 || err == LFS_ERR_NOENT); - } - - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "hi%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - for (int i = 0; i < N; i++) { - char oldpath[128]; - char newpath[128]; - sprintf(oldpath, "hi%03d", i); - sprintf(newpath, "hello%03d", i); - // YES this can overwrite an existing newpath - lfs_rename(&lfs, oldpath, newpath) => 0; - } - - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "hello%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "hello%03d", i); - lfs_remove(&lfs, path) => 0; - } - - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_dirs_file_creation] -defines.N = 'range(3, 100, 11)' -if = 'N < BLOCK_COUNT/2' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "file%03d", i); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "file%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_REG); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs); -''' - -[cases.test_dirs_file_removal] -defines.N = 'range(3, 100, 11)' -if = 'N < BLOCK_COUNT/2' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "removeme%03d", i); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "removeme%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_REG); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs); - - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "removeme%03d", i); - lfs_remove(&lfs, path) => 0; - } - lfs_unmount(&lfs); - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_dirs_file_rename] -defines.N = 'range(3, 100, 11)' -if = 'N < BLOCK_COUNT/2' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "test%03d", i); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "test%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_REG); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs); - - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - char oldpath[128]; - char newpath[128]; - sprintf(oldpath, "test%03d", i); - sprintf(newpath, "tedd%03d", i); - lfs_rename(&lfs, oldpath, newpath) => 0; - } - lfs_unmount(&lfs); - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "tedd%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_REG); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs); -''' - -[cases.test_dirs_file_reentrant] -defines.N = [5, 25] -if = 'N < BLOCK_COUNT/2' -reentrant = true -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "hi%03d", i); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; - lfs_file_close(&lfs, &file) => 0; - } - - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "hello%03d", i); - err = lfs_remove(&lfs, path); - assert(err == 0 || err == LFS_ERR_NOENT); - } - - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "hi%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_REG); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - for (int i = 0; i < N; i++) { - char oldpath[128]; - char newpath[128]; - sprintf(oldpath, "hi%03d", i); - sprintf(newpath, "hello%03d", i); - // YES this can overwrite an existing newpath - lfs_rename(&lfs, oldpath, newpath) => 0; - } - - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "hello%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_REG); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "hello%03d", i); - lfs_remove(&lfs, path) => 0; - } - - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_dirs_nested] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "potato") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "burito", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "potato/baked") => 0; - lfs_mkdir(&lfs, "potato/sweet") => 0; - lfs_mkdir(&lfs, "potato/fried") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "potato") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "baked") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "fried") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "sweet") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - - // try removing? - lfs_mount(&lfs, cfg) => 0; - lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; - lfs_unmount(&lfs) => 0; - - // try renaming? - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "potato", "coldpotato") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "coldpotato", "warmpotato") => 0; - lfs_rename(&lfs, "warmpotato", "hotpotato") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_remove(&lfs, "potato") => LFS_ERR_NOENT; - lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; - lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT; - lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; - lfs_unmount(&lfs) => 0; - - // try cross-directory renaming - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "coldpotato") => 0; - lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0; - lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; - lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; - lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; - lfs_rename(&lfs, "hotpotato/fried", "coldpotato/fried") => 0; - lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; - lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; - lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; - lfs_rename(&lfs, "hotpotato/sweet", "coldpotato/sweet") => 0; - lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; - lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; - lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "hotpotato") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "baked") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "fried") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "sweet") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - - // final remove - lfs_mount(&lfs, cfg) => 0; - lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; - lfs_remove(&lfs, "hotpotato/baked") => 0; - lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; - lfs_remove(&lfs, "hotpotato/fried") => 0; - lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; - lfs_remove(&lfs, "hotpotato/sweet") => 0; - lfs_remove(&lfs, "hotpotato") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - info.type => LFS_TYPE_DIR; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "burito") == 0); - info.type => LFS_TYPE_REG; - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_dirs_recursive_remove] -defines.N = [10, 100] -if = 'N < BLOCK_COUNT/2' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "prickly-pear") => 0; - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "prickly-pear/cactus%03d", i); - lfs_mkdir(&lfs, path) => 0; - } - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "cactus%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, path) == 0); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs); - - lfs_mount(&lfs, cfg) => 0; - lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; - - lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - for (int i = 0; i < N; i++) { - char path[1024]; - sprintf(path, "cactus%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, path) == 0); - sprintf(path, "prickly-pear/%s", info.name); - lfs_remove(&lfs, path) => 0; - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_remove(&lfs, "prickly-pear") => 0; - lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_dirs_other_errors] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "potato") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "burito", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - - lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; - lfs_mkdir(&lfs, "burito") => LFS_ERR_EXIST; - lfs_file_open(&lfs, &file, "burito", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; - lfs_file_open(&lfs, &file, "potato", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "tomato") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "burito") => LFS_ERR_NOTDIR; - lfs_file_open(&lfs, &file, "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "potato", LFS_O_RDONLY) => LFS_ERR_ISDIR; - lfs_file_open(&lfs, &file, "tomato", LFS_O_WRONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "potato", LFS_O_WRONLY) => LFS_ERR_ISDIR; - lfs_file_open(&lfs, &file, "potato", - LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; - - lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; - lfs_file_open(&lfs, &file, "/", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; - lfs_file_open(&lfs, &file, "/", LFS_O_RDONLY) => LFS_ERR_ISDIR; - lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY) => LFS_ERR_ISDIR; - lfs_file_open(&lfs, &file, "/", - LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; - - // check that errors did not corrupt directory - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_REG); - assert(strcmp(info.name, "burito") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "potato") == 0); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_unmount(&lfs) => 0; - - // or on disk - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_REG); - assert(strcmp(info.name, "burito") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "potato") == 0); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_dirs_seek] -defines.COUNT = [4, 128, 132] -if = 'COUNT < BLOCK_COUNT/2' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "hello") => 0; - for (int i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "hello/kitty%03d", i); - lfs_mkdir(&lfs, path) => 0; - } - lfs_unmount(&lfs) => 0; - - for (int j = 2; j < COUNT; j++) { - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "hello") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - - lfs_soff_t pos; - for (int i = 0; i < j; i++) { - char path[1024]; - sprintf(path, "kitty%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, path) == 0); - assert(info.type == LFS_TYPE_DIR); - pos = lfs_dir_tell(&lfs, &dir); - assert(pos >= 0); - } - - lfs_dir_seek(&lfs, &dir, pos) => 0; - char path[1024]; - sprintf(path, "kitty%03d", j); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, path) == 0); - assert(info.type == LFS_TYPE_DIR); - - lfs_dir_rewind(&lfs, &dir) => 0; - sprintf(path, "kitty%03u", 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, path) == 0); - assert(info.type == LFS_TYPE_DIR); - - lfs_dir_seek(&lfs, &dir, pos) => 0; - sprintf(path, "kitty%03d", j); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, path) == 0); - assert(info.type == LFS_TYPE_DIR); - - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - } -''' - -[cases.test_dirs_toot_seek] -defines.COUNT = [4, 128, 132] -if = 'COUNT < BLOCK_COUNT/2' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "hi%03d", i); - lfs_mkdir(&lfs, path) => 0; - } - lfs_unmount(&lfs) => 0; - - for (int j = 2; j < COUNT; j++) { - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - - lfs_soff_t pos; - for (int i = 0; i < j; i++) { - char path[1024]; - sprintf(path, "hi%03d", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, path) == 0); - assert(info.type == LFS_TYPE_DIR); - pos = lfs_dir_tell(&lfs, &dir); - assert(pos >= 0); - } - - lfs_dir_seek(&lfs, &dir, pos) => 0; - char path[1024]; - sprintf(path, "hi%03d", j); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, path) == 0); - assert(info.type == LFS_TYPE_DIR); - - lfs_dir_rewind(&lfs, &dir) => 0; - sprintf(path, "hi%03u", 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, path) == 0); - assert(info.type == LFS_TYPE_DIR); - - lfs_dir_seek(&lfs, &dir, pos) => 0; - sprintf(path, "hi%03d", j); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, path) == 0); - assert(info.type == LFS_TYPE_DIR); - - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - } -''' - +#[cases.test_dirs_root] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_dirs_many_creation] +#defines.N = 'range(3, 100, 3)' +#if = 'N < BLOCK_COUNT/2' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "dir%03d", i); +# lfs_mkdir(&lfs, path) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "dir%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_dirs_many_removal] +#defines.N = 'range(3, 100, 11)' +#if = 'N < BLOCK_COUNT/2' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "removeme%03d", i); +# lfs_mkdir(&lfs, path) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "removeme%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs); +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "removeme%03d", i); +# lfs_remove(&lfs, path) => 0; +# } +# lfs_unmount(&lfs); +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_dirs_many_rename] +#defines.N = 'range(3, 100, 11)' +#if = 'N < BLOCK_COUNT/2' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "test%03d", i); +# lfs_mkdir(&lfs, path) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "test%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs); +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# char oldpath[128]; +# char newpath[128]; +# sprintf(oldpath, "test%03d", i); +# sprintf(newpath, "tedd%03d", i); +# lfs_rename(&lfs, oldpath, newpath) => 0; +# } +# lfs_unmount(&lfs); +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "tedd%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs); +#''' +# +#[cases.test_dirs_many_reentrant] +#defines.N = [5, 11] +#if = 'BLOCK_COUNT >= 4*N' +#reentrant = true +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "hi%03d", i); +# err = lfs_mkdir(&lfs, path); +# assert(err == 0 || err == LFS_ERR_EXIST); +# } +# +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "hello%03d", i); +# err = lfs_remove(&lfs, path); +# assert(err == 0 || err == LFS_ERR_NOENT); +# } +# +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "hi%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# for (int i = 0; i < N; i++) { +# char oldpath[128]; +# char newpath[128]; +# sprintf(oldpath, "hi%03d", i); +# sprintf(newpath, "hello%03d", i); +# // YES this can overwrite an existing newpath +# lfs_rename(&lfs, oldpath, newpath) => 0; +# } +# +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "hello%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "hello%03d", i); +# lfs_remove(&lfs, path) => 0; +# } +# +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_dirs_file_creation] +#defines.N = 'range(3, 100, 11)' +#if = 'N < BLOCK_COUNT/2' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "file%03d", i); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "file%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_REG); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs); +#''' +# +#[cases.test_dirs_file_removal] +#defines.N = 'range(3, 100, 11)' +#if = 'N < BLOCK_COUNT/2' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "removeme%03d", i); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "removeme%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_REG); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs); +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "removeme%03d", i); +# lfs_remove(&lfs, path) => 0; +# } +# lfs_unmount(&lfs); +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_dirs_file_rename] +#defines.N = 'range(3, 100, 11)' +#if = 'N < BLOCK_COUNT/2' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "test%03d", i); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "test%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_REG); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs); +# +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# char oldpath[128]; +# char newpath[128]; +# sprintf(oldpath, "test%03d", i); +# sprintf(newpath, "tedd%03d", i); +# lfs_rename(&lfs, oldpath, newpath) => 0; +# } +# lfs_unmount(&lfs); +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "tedd%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_REG); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs); +#''' +# +#[cases.test_dirs_file_reentrant] +#defines.N = [5, 25] +#if = 'N < BLOCK_COUNT/2' +#reentrant = true +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "hi%03d", i); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; +# lfs_file_close(&lfs, &file) => 0; +# } +# +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "hello%03d", i); +# err = lfs_remove(&lfs, path); +# assert(err == 0 || err == LFS_ERR_NOENT); +# } +# +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "hi%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_REG); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# for (int i = 0; i < N; i++) { +# char oldpath[128]; +# char newpath[128]; +# sprintf(oldpath, "hi%03d", i); +# sprintf(newpath, "hello%03d", i); +# // YES this can overwrite an existing newpath +# lfs_rename(&lfs, oldpath, newpath) => 0; +# } +# +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "hello%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_REG); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "hello%03d", i); +# lfs_remove(&lfs, path) => 0; +# } +# +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_dirs_nested] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "potato") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "burito", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "potato/baked") => 0; +# lfs_mkdir(&lfs, "potato/sweet") => 0; +# lfs_mkdir(&lfs, "potato/fried") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "potato") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "baked") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "fried") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "sweet") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# +# // try removing? +# lfs_mount(&lfs, cfg) => 0; +# lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; +# lfs_unmount(&lfs) => 0; +# +# // try renaming? +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "potato", "coldpotato") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "coldpotato", "warmpotato") => 0; +# lfs_rename(&lfs, "warmpotato", "hotpotato") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_remove(&lfs, "potato") => LFS_ERR_NOENT; +# lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; +# lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT; +# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; +# lfs_unmount(&lfs) => 0; +# +# // try cross-directory renaming +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "coldpotato") => 0; +# lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0; +# lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; +# lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; +# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; +# lfs_rename(&lfs, "hotpotato/fried", "coldpotato/fried") => 0; +# lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; +# lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; +# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; +# lfs_rename(&lfs, "hotpotato/sweet", "coldpotato/sweet") => 0; +# lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; +# lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; +# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "hotpotato") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "baked") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "fried") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "sweet") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# +# // final remove +# lfs_mount(&lfs, cfg) => 0; +# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; +# lfs_remove(&lfs, "hotpotato/baked") => 0; +# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; +# lfs_remove(&lfs, "hotpotato/fried") => 0; +# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; +# lfs_remove(&lfs, "hotpotato/sweet") => 0; +# lfs_remove(&lfs, "hotpotato") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# info.type => LFS_TYPE_DIR; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "burito") == 0); +# info.type => LFS_TYPE_REG; +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_dirs_recursive_remove] +#defines.N = [10, 100] +#if = 'N < BLOCK_COUNT/2' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "prickly-pear") => 0; +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "prickly-pear/cactus%03d", i); +# lfs_mkdir(&lfs, path) => 0; +# } +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "cactus%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, path) == 0); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs); +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; +# +# lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# for (int i = 0; i < N; i++) { +# char path[1024]; +# sprintf(path, "cactus%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, path) == 0); +# sprintf(path, "prickly-pear/%s", info.name); +# lfs_remove(&lfs, path) => 0; +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_remove(&lfs, "prickly-pear") => 0; +# lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_dirs_other_errors] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "potato") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "burito", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# +# lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; +# lfs_mkdir(&lfs, "burito") => LFS_ERR_EXIST; +# lfs_file_open(&lfs, &file, "burito", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; +# lfs_file_open(&lfs, &file, "potato", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "tomato") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "burito") => LFS_ERR_NOTDIR; +# lfs_file_open(&lfs, &file, "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "potato", LFS_O_RDONLY) => LFS_ERR_ISDIR; +# lfs_file_open(&lfs, &file, "tomato", LFS_O_WRONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "potato", LFS_O_WRONLY) => LFS_ERR_ISDIR; +# lfs_file_open(&lfs, &file, "potato", +# LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; +# +# lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; +# lfs_file_open(&lfs, &file, "/", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; +# lfs_file_open(&lfs, &file, "/", LFS_O_RDONLY) => LFS_ERR_ISDIR; +# lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY) => LFS_ERR_ISDIR; +# lfs_file_open(&lfs, &file, "/", +# LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; +# +# // check that errors did not corrupt directory +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_REG); +# assert(strcmp(info.name, "burito") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "potato") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_unmount(&lfs) => 0; +# +# // or on disk +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, ".") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "..") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_REG); +# assert(strcmp(info.name, "burito") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(info.type == LFS_TYPE_DIR); +# assert(strcmp(info.name, "potato") == 0); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_dirs_seek] +#defines.COUNT = [4, 128, 132] +#if = 'COUNT < BLOCK_COUNT/2' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "hello") => 0; +# for (int i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "hello/kitty%03d", i); +# lfs_mkdir(&lfs, path) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# for (int j = 2; j < COUNT; j++) { +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "hello") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# lfs_soff_t pos; +# for (int i = 0; i < j; i++) { +# char path[1024]; +# sprintf(path, "kitty%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, path) == 0); +# assert(info.type == LFS_TYPE_DIR); +# pos = lfs_dir_tell(&lfs, &dir); +# assert(pos >= 0); +# } +# +# lfs_dir_seek(&lfs, &dir, pos) => 0; +# char path[1024]; +# sprintf(path, "kitty%03d", j); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, path) == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# lfs_dir_rewind(&lfs, &dir) => 0; +# sprintf(path, "kitty%03u", 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, path) == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# lfs_dir_seek(&lfs, &dir, pos) => 0; +# sprintf(path, "kitty%03d", j); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, path) == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# } +#''' +# +#[cases.test_dirs_toot_seek] +#defines.COUNT = [4, 128, 132] +#if = 'COUNT < BLOCK_COUNT/2' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "hi%03d", i); +# lfs_mkdir(&lfs, path) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# for (int j = 2; j < COUNT; j++) { +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# lfs_soff_t pos; +# for (int i = 0; i < j; i++) { +# char path[1024]; +# sprintf(path, "hi%03d", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, path) == 0); +# assert(info.type == LFS_TYPE_DIR); +# pos = lfs_dir_tell(&lfs, &dir); +# assert(pos >= 0); +# } +# +# lfs_dir_seek(&lfs, &dir, pos) => 0; +# char path[1024]; +# sprintf(path, "hi%03d", j); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, path) == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# lfs_dir_rewind(&lfs, &dir) => 0; +# sprintf(path, "hi%03u", 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, path) == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# lfs_dir_seek(&lfs, &dir, pos) => 0; +# sprintf(path, "hi%03d", j); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, path) == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# } +#''' +# diff --git a/tests/test_entries.toml b/tests/test_entries.toml index 7aa551e0..8febc1b9 100644 --- a/tests/test_entries.toml +++ b/tests/test_entries.toml @@ -1,642 +1,642 @@ -# These tests are for some specific corner cases with neighboring inline files. -# Note that these tests are intended for 512 byte inline sizes. They should -# still pass with other inline sizes but wouldn't be testing anything. - -defines.CACHE_SIZE = 512 -if = 'CACHE_SIZE % PROG_SIZE == 0 && CACHE_SIZE == 512' - -[cases.test_entries_grow] -code = ''' - uint8_t wbuffer[1024]; - uint8_t rbuffer[1024]; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // write hi0 20 - char path[1024]; - lfs_size_t size; - sprintf(path, "hi0"); size = 20; - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi1 20 - sprintf(path, "hi1"); size = 20; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi2 20 - sprintf(path, "hi2"); size = 20; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi3 20 - sprintf(path, "hi3"); size = 20; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - - // read hi1 20 - sprintf(path, "hi1"); size = 20; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // write hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - - // read hi0 20 - sprintf(path, "hi0"); size = 20; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi2 20 - sprintf(path, "hi2"); size = 20; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi3 20 - sprintf(path, "hi3"); size = 20; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' - -[cases.test_entries_shrink] -code = ''' - uint8_t wbuffer[1024]; - uint8_t rbuffer[1024]; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // write hi0 20 - char path[1024]; - lfs_size_t size; - sprintf(path, "hi0"); size = 20; - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi2 20 - sprintf(path, "hi2"); size = 20; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi3 20 - sprintf(path, "hi3"); size = 20; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - - // read hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // write hi1 20 - sprintf(path, "hi1"); size = 20; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - - // read hi0 20 - sprintf(path, "hi0"); size = 20; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi1 20 - sprintf(path, "hi1"); size = 20; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi2 20 - sprintf(path, "hi2"); size = 20; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi3 20 - sprintf(path, "hi3"); size = 20; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' - -[cases.test_entries_spill] -code = ''' - uint8_t wbuffer[1024]; - uint8_t rbuffer[1024]; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // write hi0 200 - char path[1024]; - lfs_size_t size; - sprintf(path, "hi0"); size = 200; - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi2 200 - sprintf(path, "hi2"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi3 200 - sprintf(path, "hi3"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - - // read hi0 200 - sprintf(path, "hi0"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi2 200 - sprintf(path, "hi2"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi3 200 - sprintf(path, "hi3"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' - -[cases.test_entries_push_spill] -code = ''' - uint8_t wbuffer[1024]; - uint8_t rbuffer[1024]; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // write hi0 200 - char path[1024]; - lfs_size_t size; - sprintf(path, "hi0"); size = 200; - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi1 20 - sprintf(path, "hi1"); size = 20; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi2 200 - sprintf(path, "hi2"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi3 200 - sprintf(path, "hi3"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - - // read hi1 20 - sprintf(path, "hi1"); size = 20; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // write hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - - // read hi0 200 - sprintf(path, "hi0"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi2 200 - sprintf(path, "hi2"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi3 200 - sprintf(path, "hi3"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' - -[cases.test_entries_push_spill_two] -code = ''' - uint8_t wbuffer[1024]; - uint8_t rbuffer[1024]; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // write hi0 200 - char path[1024]; - lfs_size_t size; - sprintf(path, "hi0"); size = 200; - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi1 20 - sprintf(path, "hi1"); size = 20; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi2 200 - sprintf(path, "hi2"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi3 200 - sprintf(path, "hi3"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi4 200 - sprintf(path, "hi4"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - - // read hi1 20 - sprintf(path, "hi1"); size = 20; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // write hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - - // read hi0 200 - sprintf(path, "hi0"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi2 200 - sprintf(path, "hi2"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi3 200 - sprintf(path, "hi3"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi4 200 - sprintf(path, "hi4"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' - -[cases.test_entries_drop] -code = ''' - uint8_t wbuffer[1024]; - uint8_t rbuffer[1024]; - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // write hi0 200 - char path[1024]; - lfs_size_t size; - sprintf(path, "hi0"); size = 200; - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi1 200 - sprintf(path, "hi1"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi2 200 - sprintf(path, "hi2"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - // write hi3 200 - sprintf(path, "hi3"); size = 200; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_close(&lfs, &file) => 0; - - lfs_remove(&lfs, "hi1") => 0; - struct lfs_info info; - lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT; - // read hi0 200 - sprintf(path, "hi0"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi2 200 - sprintf(path, "hi2"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi3 200 - sprintf(path, "hi3"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - - lfs_remove(&lfs, "hi2") => 0; - lfs_stat(&lfs, "hi2", &info) => LFS_ERR_NOENT; - // read hi0 200 - sprintf(path, "hi0"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - // read hi3 200 - sprintf(path, "hi3"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - - lfs_remove(&lfs, "hi3") => 0; - lfs_stat(&lfs, "hi3", &info) => LFS_ERR_NOENT; - // read hi0 200 - sprintf(path, "hi0"); size = 200; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => size; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - - lfs_remove(&lfs, "hi0") => 0; - lfs_stat(&lfs, "hi0", &info) => LFS_ERR_NOENT; - - lfs_unmount(&lfs) => 0; -''' - -[cases.test_entries_create_too_big] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - char path[1024]; - memset(path, 'm', 200); - path[200] = '\0'; - - lfs_size_t size = 400; - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - uint8_t wbuffer[1024]; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_close(&lfs, &file) => 0; - - size = 400; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - uint8_t rbuffer[1024]; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_entries_resize_too_big] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - char path[1024]; - memset(path, 'm', 200); - path[200] = '\0'; - - lfs_size_t size = 40; - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - uint8_t wbuffer[1024]; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_close(&lfs, &file) => 0; - - size = 40; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - uint8_t rbuffer[1024]; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - - size = 400; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - memset(wbuffer, 'c', size); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_close(&lfs, &file) => 0; - - size = 400; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - memcmp(rbuffer, wbuffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' +## These tests are for some specific corner cases with neighboring inline files. +## Note that these tests are intended for 512 byte inline sizes. They should +## still pass with other inline sizes but wouldn't be testing anything. +# +#defines.CACHE_SIZE = 512 +#if = 'CACHE_SIZE % PROG_SIZE == 0 && CACHE_SIZE == 512' +# +#[cases.test_entries_grow] +#code = ''' +# uint8_t wbuffer[1024]; +# uint8_t rbuffer[1024]; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // write hi0 20 +# char path[1024]; +# lfs_size_t size; +# sprintf(path, "hi0"); size = 20; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi1 20 +# sprintf(path, "hi1"); size = 20; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi2 20 +# sprintf(path, "hi2"); size = 20; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi3 20 +# sprintf(path, "hi3"); size = 20; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# // read hi1 20 +# sprintf(path, "hi1"); size = 20; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // write hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# // read hi0 20 +# sprintf(path, "hi0"); size = 20; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi2 20 +# sprintf(path, "hi2"); size = 20; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi3 20 +# sprintf(path, "hi3"); size = 20; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_entries_shrink] +#code = ''' +# uint8_t wbuffer[1024]; +# uint8_t rbuffer[1024]; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // write hi0 20 +# char path[1024]; +# lfs_size_t size; +# sprintf(path, "hi0"); size = 20; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi2 20 +# sprintf(path, "hi2"); size = 20; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi3 20 +# sprintf(path, "hi3"); size = 20; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# // read hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // write hi1 20 +# sprintf(path, "hi1"); size = 20; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# // read hi0 20 +# sprintf(path, "hi0"); size = 20; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi1 20 +# sprintf(path, "hi1"); size = 20; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi2 20 +# sprintf(path, "hi2"); size = 20; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi3 20 +# sprintf(path, "hi3"); size = 20; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_entries_spill] +#code = ''' +# uint8_t wbuffer[1024]; +# uint8_t rbuffer[1024]; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // write hi0 200 +# char path[1024]; +# lfs_size_t size; +# sprintf(path, "hi0"); size = 200; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi2 200 +# sprintf(path, "hi2"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi3 200 +# sprintf(path, "hi3"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# // read hi0 200 +# sprintf(path, "hi0"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi2 200 +# sprintf(path, "hi2"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi3 200 +# sprintf(path, "hi3"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_entries_push_spill] +#code = ''' +# uint8_t wbuffer[1024]; +# uint8_t rbuffer[1024]; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // write hi0 200 +# char path[1024]; +# lfs_size_t size; +# sprintf(path, "hi0"); size = 200; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi1 20 +# sprintf(path, "hi1"); size = 20; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi2 200 +# sprintf(path, "hi2"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi3 200 +# sprintf(path, "hi3"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# // read hi1 20 +# sprintf(path, "hi1"); size = 20; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // write hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# // read hi0 200 +# sprintf(path, "hi0"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi2 200 +# sprintf(path, "hi2"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi3 200 +# sprintf(path, "hi3"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_entries_push_spill_two] +#code = ''' +# uint8_t wbuffer[1024]; +# uint8_t rbuffer[1024]; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // write hi0 200 +# char path[1024]; +# lfs_size_t size; +# sprintf(path, "hi0"); size = 200; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi1 20 +# sprintf(path, "hi1"); size = 20; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi2 200 +# sprintf(path, "hi2"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi3 200 +# sprintf(path, "hi3"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi4 200 +# sprintf(path, "hi4"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# // read hi1 20 +# sprintf(path, "hi1"); size = 20; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // write hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# // read hi0 200 +# sprintf(path, "hi0"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi2 200 +# sprintf(path, "hi2"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi3 200 +# sprintf(path, "hi3"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi4 200 +# sprintf(path, "hi4"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_entries_drop] +#code = ''' +# uint8_t wbuffer[1024]; +# uint8_t rbuffer[1024]; +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // write hi0 200 +# char path[1024]; +# lfs_size_t size; +# sprintf(path, "hi0"); size = 200; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi1 200 +# sprintf(path, "hi1"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi2 200 +# sprintf(path, "hi2"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# // write hi3 200 +# sprintf(path, "hi3"); size = 200; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_remove(&lfs, "hi1") => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT; +# // read hi0 200 +# sprintf(path, "hi0"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi2 200 +# sprintf(path, "hi2"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi3 200 +# sprintf(path, "hi3"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_remove(&lfs, "hi2") => 0; +# lfs_stat(&lfs, "hi2", &info) => LFS_ERR_NOENT; +# // read hi0 200 +# sprintf(path, "hi0"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# // read hi3 200 +# sprintf(path, "hi3"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_remove(&lfs, "hi3") => 0; +# lfs_stat(&lfs, "hi3", &info) => LFS_ERR_NOENT; +# // read hi0 200 +# sprintf(path, "hi0"); size = 200; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_remove(&lfs, "hi0") => 0; +# lfs_stat(&lfs, "hi0", &info) => LFS_ERR_NOENT; +# +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_entries_create_too_big] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# char path[1024]; +# memset(path, 'm', 200); +# path[200] = '\0'; +# +# lfs_size_t size = 400; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# uint8_t wbuffer[1024]; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# size = 400; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# uint8_t rbuffer[1024]; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_entries_resize_too_big] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# char path[1024]; +# memset(path, 'm', 200); +# path[200] = '\0'; +# +# lfs_size_t size = 40; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# uint8_t wbuffer[1024]; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# size = 40; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# uint8_t rbuffer[1024]; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# size = 400; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# memset(wbuffer, 'c', size); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# size = 400; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# memcmp(rbuffer, wbuffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' diff --git a/tests/test_evil.toml b/tests/test_evil.toml index 4acd5ef0..d7aebc32 100644 --- a/tests/test_evil.toml +++ b/tests/test_evil.toml @@ -1,306 +1,306 @@ -# Tests for recovering from conditions which shouldn't normally -# happen during normal operation of littlefs - -# invalid pointer tests (outside of block_count) - -[cases.test_evil_invalid_tail_pointer] -defines.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL'] -defines.INVALSET = [0x3, 0x1, 0x2] -in = "lfs.c" -code = ''' - // create littlefs - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - // change tail-pointer to invalid pointers - lfs_init(&lfs, cfg) => 0; - lfs_mdir_t mdir; - lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; - lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), - (lfs_block_t[2]){ - (INVALSET & 0x1) ? 0xcccccccc : 0, - (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0; - lfs_deinit(&lfs) => 0; - - // test that mount fails gracefully - lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; -''' - -[cases.test_evil_invalid_dir_pointer] -defines.INVALSET = [0x3, 0x1, 0x2] -in = "lfs.c" -code = ''' - // create littlefs - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - // make a dir - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "dir_here") => 0; - lfs_unmount(&lfs) => 0; - - // change the dir pointer to be invalid - lfs_init(&lfs, cfg) => 0; - lfs_mdir_t mdir; - lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; - // make sure id 1 == our directory - uint8_t buffer[1024]; - lfs_dir_get(&lfs, &mdir, - LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("dir_here")), buffer) - => LFS_MKTAG(LFS_TYPE_DIR, 1, strlen("dir_here")); - assert(memcmp((char*)buffer, "dir_here", strlen("dir_here")) == 0); - // change dir pointer - lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, 8), - (lfs_block_t[2]){ - (INVALSET & 0x1) ? 0xcccccccc : 0, - (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0; - lfs_deinit(&lfs) => 0; - - // test that accessing our bad dir fails, note there's a number - // of ways to access the dir, some can fail, but some don't - lfs_mount(&lfs, cfg) => 0; - struct lfs_info info; - lfs_stat(&lfs, "dir_here", &info) => 0; - assert(strcmp(info.name, "dir_here") == 0); - assert(info.type == LFS_TYPE_DIR); - - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "dir_here") => LFS_ERR_CORRUPT; - lfs_stat(&lfs, "dir_here/file_here", &info) => LFS_ERR_CORRUPT; - lfs_dir_open(&lfs, &dir, "dir_here/dir_here") => LFS_ERR_CORRUPT; - lfs_file_t file; - lfs_file_open(&lfs, &file, "dir_here/file_here", - LFS_O_RDONLY) => LFS_ERR_CORRUPT; - lfs_file_open(&lfs, &file, "dir_here/file_here", - LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_CORRUPT; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_evil_invalid_file_pointer] -in = "lfs.c" -defines.SIZE = [10, 1000, 100000] # faked file size -code = ''' - // create littlefs - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - // make a file - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "file_here", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // change the file pointer to be invalid - lfs_init(&lfs, cfg) => 0; - lfs_mdir_t mdir; - lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; - // make sure id 1 == our file - uint8_t buffer[1024]; - lfs_dir_get(&lfs, &mdir, - LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) - => LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here")); - assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0); - // change file pointer - lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)), - &(struct lfs_ctz){0xcccccccc, lfs_tole32(SIZE)}})) => 0; - lfs_deinit(&lfs) => 0; - - // test that accessing our bad file fails, note there's a number - // of ways to access the dir, some can fail, but some don't - lfs_mount(&lfs, cfg) => 0; - struct lfs_info info; - lfs_stat(&lfs, "file_here", &info) => 0; - assert(strcmp(info.name, "file_here") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == SIZE); - - lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT; - lfs_file_close(&lfs, &file) => 0; - - // any allocs that traverse CTZ must unfortunately must fail - if (SIZE > 2*BLOCK_SIZE) { - lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; - } - lfs_unmount(&lfs) => 0; -''' - -[cases.test_evil_invalid_ctz_pointer] # invalid pointer in CTZ skip-list test -defines.SIZE = ['2*BLOCK_SIZE', '3*BLOCK_SIZE', '4*BLOCK_SIZE'] -in = "lfs.c" -code = ''' - // create littlefs - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - // make a file - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "file_here", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - for (int i = 0; i < SIZE; i++) { - char c = 'c'; - lfs_file_write(&lfs, &file, &c, 1) => 1; - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - // change pointer in CTZ skip-list to be invalid - lfs_init(&lfs, cfg) => 0; - lfs_mdir_t mdir; - lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; - // make sure id 1 == our file and get our CTZ structure - uint8_t buffer[4*BLOCK_SIZE]; - lfs_dir_get(&lfs, &mdir, - LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) - => LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here")); - assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0); - struct lfs_ctz ctz; - lfs_dir_get(&lfs, &mdir, - LFS_MKTAG(0x700, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_STRUCT, 1, sizeof(struct lfs_ctz)), &ctz) - => LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)); - lfs_ctz_fromle32(&ctz); - // rewrite block to contain bad pointer - uint8_t bbuffer[BLOCK_SIZE]; - cfg->read(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0; - uint32_t bad = lfs_tole32(0xcccccccc); - memcpy(&bbuffer[0], &bad, sizeof(bad)); - memcpy(&bbuffer[4], &bad, sizeof(bad)); - cfg->erase(cfg, ctz.head) => 0; - cfg->prog(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0; - lfs_deinit(&lfs) => 0; - - // test that accessing our bad file fails, note there's a number - // of ways to access the dir, some can fail, but some don't - lfs_mount(&lfs, cfg) => 0; - struct lfs_info info; - lfs_stat(&lfs, "file_here", &info) => 0; - assert(strcmp(info.name, "file_here") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == SIZE); - - lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT; - lfs_file_close(&lfs, &file) => 0; - - // any allocs that traverse CTZ must unfortunately must fail - if (SIZE > 2*BLOCK_SIZE) { - lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; - } - lfs_unmount(&lfs) => 0; -''' - - -[cases.test_evil_invalid_gstate_pointer] -defines.INVALSET = [0x3, 0x1, 0x2] -in = "lfs.c" -code = ''' - // create littlefs - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - // create an invalid gstate - lfs_init(&lfs, cfg) => 0; - lfs_mdir_t mdir; - lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; - lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){ - (INVALSET & 0x1) ? 0xcccccccc : 0, - (INVALSET & 0x2) ? 0xcccccccc : 0}); - lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0; - lfs_deinit(&lfs) => 0; - - // test that mount fails gracefully - // mount may not fail, but our first alloc should fail when - // we try to fix the gstate - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT; - lfs_unmount(&lfs) => 0; -''' - -# cycle detection/recovery tests - -[cases.test_evil_mdir_loop] # metadata-pair threaded-list loop test -in = "lfs.c" -code = ''' - // create littlefs - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - // change tail-pointer to point to ourself - lfs_init(&lfs, cfg) => 0; - lfs_mdir_t mdir; - lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; - lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), - (lfs_block_t[2]){0, 1}})) => 0; - lfs_deinit(&lfs) => 0; - - // test that mount fails gracefully - lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; -''' - -[cases.test_evil_mdir_loop2] # metadata-pair threaded-list 2-length loop test -in = "lfs.c" -code = ''' - // create littlefs with child dir - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "child") => 0; - lfs_unmount(&lfs) => 0; - - // find child - lfs_init(&lfs, cfg) => 0; - lfs_mdir_t mdir; - lfs_block_t pair[2]; - lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; - lfs_dir_get(&lfs, &mdir, - LFS_MKTAG(0x7ff, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) - => LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)); - lfs_pair_fromle32(pair); - // change tail-pointer to point to root - lfs_dir_fetch(&lfs, &mdir, pair) => 0; - lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), - (lfs_block_t[2]){0, 1}})) => 0; - lfs_deinit(&lfs) => 0; - - // test that mount fails gracefully - lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; -''' - -[cases.test_evil_mdir_loop_child] # metadata-pair threaded-list 1-length child loop test -in = "lfs.c" -code = ''' - // create littlefs with child dir - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "child") => 0; - lfs_unmount(&lfs) => 0; - - // find child - lfs_init(&lfs, cfg) => 0; - lfs_mdir_t mdir; - lfs_block_t pair[2]; - lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; - lfs_dir_get(&lfs, &mdir, - LFS_MKTAG(0x7ff, 0x3ff, 0), - LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) - => LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)); - lfs_pair_fromle32(pair); - // change tail-pointer to point to ourself - lfs_dir_fetch(&lfs, &mdir, pair) => 0; - lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( - {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0; - lfs_deinit(&lfs) => 0; - - // test that mount fails gracefully - lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; -''' +## Tests for recovering from conditions which shouldn't normally +## happen during normal operation of littlefs +# +## invalid pointer tests (outside of block_count) +# +#[cases.test_evil_invalid_tail_pointer] +#defines.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL'] +#defines.INVALSET = [0x3, 0x1, 0x2] +#in = "lfs.c" +#code = ''' +# // create littlefs +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# // change tail-pointer to invalid pointers +# lfs_init(&lfs, cfg) => 0; +# lfs_mdir_t mdir; +# lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; +# lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( +# {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), +# (lfs_block_t[2]){ +# (INVALSET & 0x1) ? 0xcccccccc : 0, +# (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0; +# lfs_deinit(&lfs) => 0; +# +# // test that mount fails gracefully +# lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; +#''' +# +#[cases.test_evil_invalid_dir_pointer] +#defines.INVALSET = [0x3, 0x1, 0x2] +#in = "lfs.c" +#code = ''' +# // create littlefs +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# // make a dir +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "dir_here") => 0; +# lfs_unmount(&lfs) => 0; +# +# // change the dir pointer to be invalid +# lfs_init(&lfs, cfg) => 0; +# lfs_mdir_t mdir; +# lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; +# // make sure id 1 == our directory +# uint8_t buffer[1024]; +# lfs_dir_get(&lfs, &mdir, +# LFS_MKTAG(0x700, 0x3ff, 0), +# LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("dir_here")), buffer) +# => LFS_MKTAG(LFS_TYPE_DIR, 1, strlen("dir_here")); +# assert(memcmp((char*)buffer, "dir_here", strlen("dir_here")) == 0); +# // change dir pointer +# lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( +# {LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, 8), +# (lfs_block_t[2]){ +# (INVALSET & 0x1) ? 0xcccccccc : 0, +# (INVALSET & 0x2) ? 0xcccccccc : 0}})) => 0; +# lfs_deinit(&lfs) => 0; +# +# // test that accessing our bad dir fails, note there's a number +# // of ways to access the dir, some can fail, but some don't +# lfs_mount(&lfs, cfg) => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "dir_here", &info) => 0; +# assert(strcmp(info.name, "dir_here") == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "dir_here") => LFS_ERR_CORRUPT; +# lfs_stat(&lfs, "dir_here/file_here", &info) => LFS_ERR_CORRUPT; +# lfs_dir_open(&lfs, &dir, "dir_here/dir_here") => LFS_ERR_CORRUPT; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "dir_here/file_here", +# LFS_O_RDONLY) => LFS_ERR_CORRUPT; +# lfs_file_open(&lfs, &file, "dir_here/file_here", +# LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_CORRUPT; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_evil_invalid_file_pointer] +#in = "lfs.c" +#defines.SIZE = [10, 1000, 100000] # faked file size +#code = ''' +# // create littlefs +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# // make a file +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "file_here", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // change the file pointer to be invalid +# lfs_init(&lfs, cfg) => 0; +# lfs_mdir_t mdir; +# lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; +# // make sure id 1 == our file +# uint8_t buffer[1024]; +# lfs_dir_get(&lfs, &mdir, +# LFS_MKTAG(0x700, 0x3ff, 0), +# LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) +# => LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here")); +# assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0); +# // change file pointer +# lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( +# {LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)), +# &(struct lfs_ctz){0xcccccccc, lfs_tole32(SIZE)}})) => 0; +# lfs_deinit(&lfs) => 0; +# +# // test that accessing our bad file fails, note there's a number +# // of ways to access the dir, some can fail, but some don't +# lfs_mount(&lfs, cfg) => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "file_here", &info) => 0; +# assert(strcmp(info.name, "file_here") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == SIZE); +# +# lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT; +# lfs_file_close(&lfs, &file) => 0; +# +# // any allocs that traverse CTZ must unfortunately must fail +# if (SIZE > 2*BLOCK_SIZE) { +# lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; +# } +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_evil_invalid_ctz_pointer] # invalid pointer in CTZ skip-list test +#defines.SIZE = ['2*BLOCK_SIZE', '3*BLOCK_SIZE', '4*BLOCK_SIZE'] +#in = "lfs.c" +#code = ''' +# // create littlefs +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# // make a file +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "file_here", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# for (int i = 0; i < SIZE; i++) { +# char c = 'c'; +# lfs_file_write(&lfs, &file, &c, 1) => 1; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# // change pointer in CTZ skip-list to be invalid +# lfs_init(&lfs, cfg) => 0; +# lfs_mdir_t mdir; +# lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; +# // make sure id 1 == our file and get our CTZ structure +# uint8_t buffer[4*BLOCK_SIZE]; +# lfs_dir_get(&lfs, &mdir, +# LFS_MKTAG(0x700, 0x3ff, 0), +# LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) +# => LFS_MKTAG(LFS_TYPE_REG, 1, strlen("file_here")); +# assert(memcmp((char*)buffer, "file_here", strlen("file_here")) == 0); +# struct lfs_ctz ctz; +# lfs_dir_get(&lfs, &mdir, +# LFS_MKTAG(0x700, 0x3ff, 0), +# LFS_MKTAG(LFS_TYPE_STRUCT, 1, sizeof(struct lfs_ctz)), &ctz) +# => LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)); +# lfs_ctz_fromle32(&ctz); +# // rewrite block to contain bad pointer +# uint8_t bbuffer[BLOCK_SIZE]; +# cfg->read(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0; +# uint32_t bad = lfs_tole32(0xcccccccc); +# memcpy(&bbuffer[0], &bad, sizeof(bad)); +# memcpy(&bbuffer[4], &bad, sizeof(bad)); +# cfg->erase(cfg, ctz.head) => 0; +# cfg->prog(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0; +# lfs_deinit(&lfs) => 0; +# +# // test that accessing our bad file fails, note there's a number +# // of ways to access the dir, some can fail, but some don't +# lfs_mount(&lfs, cfg) => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "file_here", &info) => 0; +# assert(strcmp(info.name, "file_here") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == SIZE); +# +# lfs_file_open(&lfs, &file, "file_here", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, SIZE) => LFS_ERR_CORRUPT; +# lfs_file_close(&lfs, &file) => 0; +# +# // any allocs that traverse CTZ must unfortunately must fail +# if (SIZE > 2*BLOCK_SIZE) { +# lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; +# } +# lfs_unmount(&lfs) => 0; +#''' +# +# +#[cases.test_evil_invalid_gstate_pointer] +#defines.INVALSET = [0x3, 0x1, 0x2] +#in = "lfs.c" +#code = ''' +# // create littlefs +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# // create an invalid gstate +# lfs_init(&lfs, cfg) => 0; +# lfs_mdir_t mdir; +# lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; +# lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){ +# (INVALSET & 0x1) ? 0xcccccccc : 0, +# (INVALSET & 0x2) ? 0xcccccccc : 0}); +# lfs_dir_commit(&lfs, &mdir, NULL, 0) => 0; +# lfs_deinit(&lfs) => 0; +# +# // test that mount fails gracefully +# // mount may not fail, but our first alloc should fail when +# // we try to fix the gstate +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT; +# lfs_unmount(&lfs) => 0; +#''' +# +## cycle detection/recovery tests +# +#[cases.test_evil_mdir_loop] # metadata-pair threaded-list loop test +#in = "lfs.c" +#code = ''' +# // create littlefs +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# // change tail-pointer to point to ourself +# lfs_init(&lfs, cfg) => 0; +# lfs_mdir_t mdir; +# lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; +# lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( +# {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), +# (lfs_block_t[2]){0, 1}})) => 0; +# lfs_deinit(&lfs) => 0; +# +# // test that mount fails gracefully +# lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; +#''' +# +#[cases.test_evil_mdir_loop2] # metadata-pair threaded-list 2-length loop test +#in = "lfs.c" +#code = ''' +# // create littlefs with child dir +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "child") => 0; +# lfs_unmount(&lfs) => 0; +# +# // find child +# lfs_init(&lfs, cfg) => 0; +# lfs_mdir_t mdir; +# lfs_block_t pair[2]; +# lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; +# lfs_dir_get(&lfs, &mdir, +# LFS_MKTAG(0x7ff, 0x3ff, 0), +# LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) +# => LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)); +# lfs_pair_fromle32(pair); +# // change tail-pointer to point to root +# lfs_dir_fetch(&lfs, &mdir, pair) => 0; +# lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( +# {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), +# (lfs_block_t[2]){0, 1}})) => 0; +# lfs_deinit(&lfs) => 0; +# +# // test that mount fails gracefully +# lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; +#''' +# +#[cases.test_evil_mdir_loop_child] # metadata-pair threaded-list 1-length child loop test +#in = "lfs.c" +#code = ''' +# // create littlefs with child dir +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "child") => 0; +# lfs_unmount(&lfs) => 0; +# +# // find child +# lfs_init(&lfs, cfg) => 0; +# lfs_mdir_t mdir; +# lfs_block_t pair[2]; +# lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; +# lfs_dir_get(&lfs, &mdir, +# LFS_MKTAG(0x7ff, 0x3ff, 0), +# LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)), pair) +# => LFS_MKTAG(LFS_TYPE_DIRSTRUCT, 1, sizeof(pair)); +# lfs_pair_fromle32(pair); +# // change tail-pointer to point to ourself +# lfs_dir_fetch(&lfs, &mdir, pair) => 0; +# lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( +# {LFS_MKTAG(LFS_TYPE_HARDTAIL, 0x3ff, 8), pair})) => 0; +# lfs_deinit(&lfs) => 0; +# +# // test that mount fails gracefully +# lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; +#''' diff --git a/tests/test_exhaustion.toml b/tests/test_exhaustion.toml index 2cf6aed1..c1be95da 100644 --- a/tests/test_exhaustion.toml +++ b/tests/test_exhaustion.toml @@ -1,505 +1,505 @@ -# test running a filesystem to exhaustion -[cases.test_exhaustion_normal] -defines.ERASE_CYCLES = 10 -defines.BLOCK_COUNT = 256 # small bd so test runs faster -defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' -defines.BADBLOCK_BEHAVIOR = [ - 'LFS_EMUBD_BADBLOCK_PROGERROR', - 'LFS_EMUBD_BADBLOCK_ERASEERROR', - 'LFS_EMUBD_BADBLOCK_READERROR', - 'LFS_EMUBD_BADBLOCK_PROGNOOP', - 'LFS_EMUBD_BADBLOCK_ERASENOOP', -] -defines.FILES = 10 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "roadrunner") => 0; - lfs_unmount(&lfs) => 0; - - uint32_t cycle = 0; - while (true) { - lfs_mount(&lfs, cfg) => 0; - for (uint32_t i = 0; i < FILES; i++) { - // chose name, roughly random seed, and random 2^n size - char path[1024]; - sprintf(path, "roadrunner/test%d", i); - uint32_t prng = cycle * i; - lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); - - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - - for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (TEST_PRNG(&prng) % 26); - lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); - assert(res == 1 || res == LFS_ERR_NOSPC); - if (res == LFS_ERR_NOSPC) { - int err = lfs_file_close(&lfs, &file); - assert(err == 0 || err == LFS_ERR_NOSPC); - lfs_unmount(&lfs) => 0; - goto exhausted; - } - } - - int err = lfs_file_close(&lfs, &file); - assert(err == 0 || err == LFS_ERR_NOSPC); - if (err == LFS_ERR_NOSPC) { - lfs_unmount(&lfs) => 0; - goto exhausted; - } - } - - for (uint32_t i = 0; i < FILES; i++) { - // check for errors - char path[1024]; - sprintf(path, "roadrunner/test%d", i); - uint32_t prng = cycle * i; - lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); - - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (TEST_PRNG(&prng) % 26); - char r; - lfs_file_read(&lfs, &file, &r, 1) => 1; - assert(r == c); - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - cycle += 1; - } - -exhausted: - // should still be readable - lfs_mount(&lfs, cfg) => 0; - for (uint32_t i = 0; i < FILES; i++) { - // check for errors - char path[1024]; - sprintf(path, "roadrunner/test%d", i); - struct lfs_info info; - lfs_stat(&lfs, path, &info) => 0; - } - lfs_unmount(&lfs) => 0; - - LFS_WARN("completed %d cycles", cycle); -''' - -# test running a filesystem to exhaustion -# which also requires expanding superblocks -[cases.test_exhaustion_superblocks] -defines.ERASE_CYCLES = 10 -defines.BLOCK_COUNT = 256 # small bd so test runs faster -defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' -defines.BADBLOCK_BEHAVIOR = [ - 'LFS_EMUBD_BADBLOCK_PROGERROR', - 'LFS_EMUBD_BADBLOCK_ERASEERROR', - 'LFS_EMUBD_BADBLOCK_READERROR', - 'LFS_EMUBD_BADBLOCK_PROGNOOP', - 'LFS_EMUBD_BADBLOCK_ERASENOOP', -] -defines.FILES = 10 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - uint32_t cycle = 0; - while (true) { - lfs_mount(&lfs, cfg) => 0; - for (uint32_t i = 0; i < FILES; i++) { - // chose name, roughly random seed, and random 2^n size - char path[1024]; - sprintf(path, "test%d", i); - uint32_t prng = cycle * i; - lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); - - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - - for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (TEST_PRNG(&prng) % 26); - lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); - assert(res == 1 || res == LFS_ERR_NOSPC); - if (res == LFS_ERR_NOSPC) { - int err = lfs_file_close(&lfs, &file); - assert(err == 0 || err == LFS_ERR_NOSPC); - lfs_unmount(&lfs) => 0; - goto exhausted; - } - } - - int err = lfs_file_close(&lfs, &file); - assert(err == 0 || err == LFS_ERR_NOSPC); - if (err == LFS_ERR_NOSPC) { - lfs_unmount(&lfs) => 0; - goto exhausted; - } - } - - for (uint32_t i = 0; i < FILES; i++) { - // check for errors - char path[1024]; - sprintf(path, "test%d", i); - uint32_t prng = cycle * i; - lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); - - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (TEST_PRNG(&prng) % 26); - char r; - lfs_file_read(&lfs, &file, &r, 1) => 1; - assert(r == c); - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - cycle += 1; - } - -exhausted: - // should still be readable - lfs_mount(&lfs, cfg) => 0; - for (uint32_t i = 0; i < FILES; i++) { - // check for errors - char path[1024]; - struct lfs_info info; - sprintf(path, "test%d", i); - lfs_stat(&lfs, path, &info) => 0; - } - lfs_unmount(&lfs) => 0; - - LFS_WARN("completed %d cycles", cycle); -''' - -# These are a sort of high-level litmus test for wear-leveling. One definition -# of wear-leveling is that increasing a block device's space translates directly -# into increasing the block devices lifetime. This is something we can actually -# check for. - -# wear-level test running a filesystem to exhaustion -[cases.test_exhuastion_wear_leveling] -defines.ERASE_CYCLES = 20 -defines.BLOCK_COUNT = 256 # small bd so test runs faster -defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' -defines.FILES = 10 -code = ''' - uint32_t run_cycles[2]; - const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT}; - - for (int run = 0; run < 2; run++) { - for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) { - lfs_emubd_setwear(cfg, b, - (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0; - } - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "roadrunner") => 0; - lfs_unmount(&lfs) => 0; - - uint32_t cycle = 0; - while (true) { - lfs_mount(&lfs, cfg) => 0; - for (uint32_t i = 0; i < FILES; i++) { - // chose name, roughly random seed, and random 2^n size - char path[1024]; - sprintf(path, "roadrunner/test%d", i); - uint32_t prng = cycle * i; - lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); - - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - - for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (TEST_PRNG(&prng) % 26); - lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); - assert(res == 1 || res == LFS_ERR_NOSPC); - if (res == LFS_ERR_NOSPC) { - int err = lfs_file_close(&lfs, &file); - assert(err == 0 || err == LFS_ERR_NOSPC); - lfs_unmount(&lfs) => 0; - goto exhausted; - } - } - - int err = lfs_file_close(&lfs, &file); - assert(err == 0 || err == LFS_ERR_NOSPC); - if (err == LFS_ERR_NOSPC) { - lfs_unmount(&lfs) => 0; - goto exhausted; - } - } - - for (uint32_t i = 0; i < FILES; i++) { - // check for errors - char path[1024]; - sprintf(path, "roadrunner/test%d", i); - uint32_t prng = cycle * i; - lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); - - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (TEST_PRNG(&prng) % 26); - char r; - lfs_file_read(&lfs, &file, &r, 1) => 1; - assert(r == c); - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - cycle += 1; - } - -exhausted: - // should still be readable - lfs_mount(&lfs, cfg) => 0; - for (uint32_t i = 0; i < FILES; i++) { - // check for errors - char path[1024]; - struct lfs_info info; - sprintf(path, "roadrunner/test%d", i); - lfs_stat(&lfs, path, &info) => 0; - } - lfs_unmount(&lfs) => 0; - - run_cycles[run] = cycle; - LFS_WARN("completed %d blocks %d cycles", - run_block_count[run], run_cycles[run]); - } - - // check we increased the lifetime by 2x with ~10% error - LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); -''' - -# wear-level test + expanding superblock -[cases.test_exhaustion_wear_leveling_superblocks] -defines.ERASE_CYCLES = 20 -defines.BLOCK_COUNT = 256 # small bd so test runs faster -defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' -defines.FILES = 10 -code = ''' - uint32_t run_cycles[2]; - const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT}; - - for (int run = 0; run < 2; run++) { - for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) { - lfs_emubd_setwear(cfg, b, - (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0; - } - - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - uint32_t cycle = 0; - while (true) { - lfs_mount(&lfs, cfg) => 0; - for (uint32_t i = 0; i < FILES; i++) { - // chose name, roughly random seed, and random 2^n size - char path[1024]; - sprintf(path, "test%d", i); - uint32_t prng = cycle * i; - lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); - - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - - for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (TEST_PRNG(&prng) % 26); - lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); - assert(res == 1 || res == LFS_ERR_NOSPC); - if (res == LFS_ERR_NOSPC) { - int err = lfs_file_close(&lfs, &file); - assert(err == 0 || err == LFS_ERR_NOSPC); - lfs_unmount(&lfs) => 0; - goto exhausted; - } - } - - int err = lfs_file_close(&lfs, &file); - assert(err == 0 || err == LFS_ERR_NOSPC); - if (err == LFS_ERR_NOSPC) { - lfs_unmount(&lfs) => 0; - goto exhausted; - } - } - - for (uint32_t i = 0; i < FILES; i++) { - // check for errors - char path[1024]; - sprintf(path, "test%d", i); - uint32_t prng = cycle * i; - lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); - - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (TEST_PRNG(&prng) % 26); - char r; - lfs_file_read(&lfs, &file, &r, 1) => 1; - assert(r == c); - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - cycle += 1; - } - -exhausted: - // should still be readable - lfs_mount(&lfs, cfg) => 0; - for (uint32_t i = 0; i < FILES; i++) { - // check for errors - char path[1024]; - struct lfs_info info; - sprintf(path, "test%d", i); - lfs_stat(&lfs, path, &info) => 0; - } - lfs_unmount(&lfs) => 0; - - run_cycles[run] = cycle; - LFS_WARN("completed %d blocks %d cycles", - run_block_count[run], run_cycles[run]); - } - - // check we increased the lifetime by 2x with ~10% error - LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); -''' - -# test that we wear blocks roughly evenly -[cases.test_exhaustion_wear_distribution] -defines.ERASE_CYCLES = 0xffffffff -defines.BLOCK_COUNT = 256 # small bd so test runs faster -defines.BLOCK_CYCLES = [5, 4, 3, 2, 1] -defines.CYCLES = 100 -defines.FILES = 10 -if = 'BLOCK_CYCLES < CYCLES/10' -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "roadrunner") => 0; - lfs_unmount(&lfs) => 0; - - uint32_t cycle = 0; - while (cycle < CYCLES) { - lfs_mount(&lfs, cfg) => 0; - for (uint32_t i = 0; i < FILES; i++) { - // chose name, roughly random seed, and random 2^n size - char path[1024]; - sprintf(path, "roadrunner/test%d", i); - uint32_t prng = cycle * i; - lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2); - - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - - for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (TEST_PRNG(&prng) % 26); - lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); - assert(res == 1 || res == LFS_ERR_NOSPC); - if (res == LFS_ERR_NOSPC) { - int err = lfs_file_close(&lfs, &file); - assert(err == 0 || err == LFS_ERR_NOSPC); - lfs_unmount(&lfs) => 0; - goto exhausted; - } - } - - int err = lfs_file_close(&lfs, &file); - assert(err == 0 || err == LFS_ERR_NOSPC); - if (err == LFS_ERR_NOSPC) { - lfs_unmount(&lfs) => 0; - goto exhausted; - } - } - - for (uint32_t i = 0; i < FILES; i++) { - // check for errors - char path[1024]; - sprintf(path, "roadrunner/test%d", i); - uint32_t prng = cycle * i; - lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2); - - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (TEST_PRNG(&prng) % 26); - char r; - lfs_file_read(&lfs, &file, &r, 1) => 1; - assert(r == c); - } - - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - - cycle += 1; - } - -exhausted: - // should still be readable - lfs_mount(&lfs, cfg) => 0; - for (uint32_t i = 0; i < FILES; i++) { - // check for errors - char path[1024]; - struct lfs_info info; - sprintf(path, "roadrunner/test%d", i); - lfs_stat(&lfs, path, &info) => 0; - } - lfs_unmount(&lfs) => 0; - - LFS_WARN("completed %d cycles", cycle); - - // check the wear on our block device - lfs_emubd_wear_t minwear = -1; - lfs_emubd_wear_t totalwear = 0; - lfs_emubd_wear_t maxwear = 0; - // skip 0 and 1 as superblock movement is intentionally avoided - for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) { - lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b); - printf("%08x: wear %d\n", b, wear); - assert(wear >= 0); - if (wear < minwear) { - minwear = wear; - } - if (wear > maxwear) { - maxwear = wear; - } - totalwear += wear; - } - lfs_emubd_wear_t avgwear = totalwear / BLOCK_COUNT; - LFS_WARN("max wear: %d cycles", maxwear); - LFS_WARN("avg wear: %d cycles", totalwear / (int)BLOCK_COUNT); - LFS_WARN("min wear: %d cycles", minwear); - - // find standard deviation^2 - lfs_emubd_wear_t dev2 = 0; - for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) { - lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b); - assert(wear >= 0); - lfs_emubd_swear_t diff = wear - avgwear; - dev2 += diff*diff; - } - dev2 /= totalwear; - LFS_WARN("std dev^2: %d", dev2); - assert(dev2 < 8); -''' - +## test running a filesystem to exhaustion +#[cases.test_exhaustion_normal] +#defines.ERASE_CYCLES = 10 +#defines.BLOCK_COUNT = 256 # small bd so test runs faster +#defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' +#defines.BADBLOCK_BEHAVIOR = [ +# 'LFS_EMUBD_BADBLOCK_PROGERROR', +# 'LFS_EMUBD_BADBLOCK_ERASEERROR', +# 'LFS_EMUBD_BADBLOCK_READERROR', +# 'LFS_EMUBD_BADBLOCK_PROGNOOP', +# 'LFS_EMUBD_BADBLOCK_ERASENOOP', +#] +#defines.FILES = 10 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "roadrunner") => 0; +# lfs_unmount(&lfs) => 0; +# +# uint32_t cycle = 0; +# while (true) { +# lfs_mount(&lfs, cfg) => 0; +# for (uint32_t i = 0; i < FILES; i++) { +# // chose name, roughly random seed, and random 2^n size +# char path[1024]; +# sprintf(path, "roadrunner/test%d", i); +# uint32_t prng = cycle * i; +# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# +# for (lfs_size_t j = 0; j < size; j++) { +# char c = 'a' + (TEST_PRNG(&prng) % 26); +# lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); +# assert(res == 1 || res == LFS_ERR_NOSPC); +# if (res == LFS_ERR_NOSPC) { +# int err = lfs_file_close(&lfs, &file); +# assert(err == 0 || err == LFS_ERR_NOSPC); +# lfs_unmount(&lfs) => 0; +# goto exhausted; +# } +# } +# +# int err = lfs_file_close(&lfs, &file); +# assert(err == 0 || err == LFS_ERR_NOSPC); +# if (err == LFS_ERR_NOSPC) { +# lfs_unmount(&lfs) => 0; +# goto exhausted; +# } +# } +# +# for (uint32_t i = 0; i < FILES; i++) { +# // check for errors +# char path[1024]; +# sprintf(path, "roadrunner/test%d", i); +# uint32_t prng = cycle * i; +# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# for (lfs_size_t j = 0; j < size; j++) { +# char c = 'a' + (TEST_PRNG(&prng) % 26); +# char r; +# lfs_file_read(&lfs, &file, &r, 1) => 1; +# assert(r == c); +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# cycle += 1; +# } +# +#exhausted: +# // should still be readable +# lfs_mount(&lfs, cfg) => 0; +# for (uint32_t i = 0; i < FILES; i++) { +# // check for errors +# char path[1024]; +# sprintf(path, "roadrunner/test%d", i); +# struct lfs_info info; +# lfs_stat(&lfs, path, &info) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# LFS_WARN("completed %d cycles", cycle); +#''' +# +## test running a filesystem to exhaustion +## which also requires expanding superblocks +#[cases.test_exhaustion_superblocks] +#defines.ERASE_CYCLES = 10 +#defines.BLOCK_COUNT = 256 # small bd so test runs faster +#defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' +#defines.BADBLOCK_BEHAVIOR = [ +# 'LFS_EMUBD_BADBLOCK_PROGERROR', +# 'LFS_EMUBD_BADBLOCK_ERASEERROR', +# 'LFS_EMUBD_BADBLOCK_READERROR', +# 'LFS_EMUBD_BADBLOCK_PROGNOOP', +# 'LFS_EMUBD_BADBLOCK_ERASENOOP', +#] +#defines.FILES = 10 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# uint32_t cycle = 0; +# while (true) { +# lfs_mount(&lfs, cfg) => 0; +# for (uint32_t i = 0; i < FILES; i++) { +# // chose name, roughly random seed, and random 2^n size +# char path[1024]; +# sprintf(path, "test%d", i); +# uint32_t prng = cycle * i; +# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# +# for (lfs_size_t j = 0; j < size; j++) { +# char c = 'a' + (TEST_PRNG(&prng) % 26); +# lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); +# assert(res == 1 || res == LFS_ERR_NOSPC); +# if (res == LFS_ERR_NOSPC) { +# int err = lfs_file_close(&lfs, &file); +# assert(err == 0 || err == LFS_ERR_NOSPC); +# lfs_unmount(&lfs) => 0; +# goto exhausted; +# } +# } +# +# int err = lfs_file_close(&lfs, &file); +# assert(err == 0 || err == LFS_ERR_NOSPC); +# if (err == LFS_ERR_NOSPC) { +# lfs_unmount(&lfs) => 0; +# goto exhausted; +# } +# } +# +# for (uint32_t i = 0; i < FILES; i++) { +# // check for errors +# char path[1024]; +# sprintf(path, "test%d", i); +# uint32_t prng = cycle * i; +# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# for (lfs_size_t j = 0; j < size; j++) { +# char c = 'a' + (TEST_PRNG(&prng) % 26); +# char r; +# lfs_file_read(&lfs, &file, &r, 1) => 1; +# assert(r == c); +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# cycle += 1; +# } +# +#exhausted: +# // should still be readable +# lfs_mount(&lfs, cfg) => 0; +# for (uint32_t i = 0; i < FILES; i++) { +# // check for errors +# char path[1024]; +# struct lfs_info info; +# sprintf(path, "test%d", i); +# lfs_stat(&lfs, path, &info) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# LFS_WARN("completed %d cycles", cycle); +#''' +# +## These are a sort of high-level litmus test for wear-leveling. One definition +## of wear-leveling is that increasing a block device's space translates directly +## into increasing the block devices lifetime. This is something we can actually +## check for. +# +## wear-level test running a filesystem to exhaustion +#[cases.test_exhuastion_wear_leveling] +#defines.ERASE_CYCLES = 20 +#defines.BLOCK_COUNT = 256 # small bd so test runs faster +#defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' +#defines.FILES = 10 +#code = ''' +# uint32_t run_cycles[2]; +# const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT}; +# +# for (int run = 0; run < 2; run++) { +# for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) { +# lfs_emubd_setwear(cfg, b, +# (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0; +# } +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "roadrunner") => 0; +# lfs_unmount(&lfs) => 0; +# +# uint32_t cycle = 0; +# while (true) { +# lfs_mount(&lfs, cfg) => 0; +# for (uint32_t i = 0; i < FILES; i++) { +# // chose name, roughly random seed, and random 2^n size +# char path[1024]; +# sprintf(path, "roadrunner/test%d", i); +# uint32_t prng = cycle * i; +# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# +# for (lfs_size_t j = 0; j < size; j++) { +# char c = 'a' + (TEST_PRNG(&prng) % 26); +# lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); +# assert(res == 1 || res == LFS_ERR_NOSPC); +# if (res == LFS_ERR_NOSPC) { +# int err = lfs_file_close(&lfs, &file); +# assert(err == 0 || err == LFS_ERR_NOSPC); +# lfs_unmount(&lfs) => 0; +# goto exhausted; +# } +# } +# +# int err = lfs_file_close(&lfs, &file); +# assert(err == 0 || err == LFS_ERR_NOSPC); +# if (err == LFS_ERR_NOSPC) { +# lfs_unmount(&lfs) => 0; +# goto exhausted; +# } +# } +# +# for (uint32_t i = 0; i < FILES; i++) { +# // check for errors +# char path[1024]; +# sprintf(path, "roadrunner/test%d", i); +# uint32_t prng = cycle * i; +# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# for (lfs_size_t j = 0; j < size; j++) { +# char c = 'a' + (TEST_PRNG(&prng) % 26); +# char r; +# lfs_file_read(&lfs, &file, &r, 1) => 1; +# assert(r == c); +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# cycle += 1; +# } +# +#exhausted: +# // should still be readable +# lfs_mount(&lfs, cfg) => 0; +# for (uint32_t i = 0; i < FILES; i++) { +# // check for errors +# char path[1024]; +# struct lfs_info info; +# sprintf(path, "roadrunner/test%d", i); +# lfs_stat(&lfs, path, &info) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# run_cycles[run] = cycle; +# LFS_WARN("completed %d blocks %d cycles", +# run_block_count[run], run_cycles[run]); +# } +# +# // check we increased the lifetime by 2x with ~10% error +# LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); +#''' +# +## wear-level test + expanding superblock +#[cases.test_exhaustion_wear_leveling_superblocks] +#defines.ERASE_CYCLES = 20 +#defines.BLOCK_COUNT = 256 # small bd so test runs faster +#defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' +#defines.FILES = 10 +#code = ''' +# uint32_t run_cycles[2]; +# const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT}; +# +# for (int run = 0; run < 2; run++) { +# for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) { +# lfs_emubd_setwear(cfg, b, +# (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0; +# } +# +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# uint32_t cycle = 0; +# while (true) { +# lfs_mount(&lfs, cfg) => 0; +# for (uint32_t i = 0; i < FILES; i++) { +# // chose name, roughly random seed, and random 2^n size +# char path[1024]; +# sprintf(path, "test%d", i); +# uint32_t prng = cycle * i; +# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# +# for (lfs_size_t j = 0; j < size; j++) { +# char c = 'a' + (TEST_PRNG(&prng) % 26); +# lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); +# assert(res == 1 || res == LFS_ERR_NOSPC); +# if (res == LFS_ERR_NOSPC) { +# int err = lfs_file_close(&lfs, &file); +# assert(err == 0 || err == LFS_ERR_NOSPC); +# lfs_unmount(&lfs) => 0; +# goto exhausted; +# } +# } +# +# int err = lfs_file_close(&lfs, &file); +# assert(err == 0 || err == LFS_ERR_NOSPC); +# if (err == LFS_ERR_NOSPC) { +# lfs_unmount(&lfs) => 0; +# goto exhausted; +# } +# } +# +# for (uint32_t i = 0; i < FILES; i++) { +# // check for errors +# char path[1024]; +# sprintf(path, "test%d", i); +# uint32_t prng = cycle * i; +# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# for (lfs_size_t j = 0; j < size; j++) { +# char c = 'a' + (TEST_PRNG(&prng) % 26); +# char r; +# lfs_file_read(&lfs, &file, &r, 1) => 1; +# assert(r == c); +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# cycle += 1; +# } +# +#exhausted: +# // should still be readable +# lfs_mount(&lfs, cfg) => 0; +# for (uint32_t i = 0; i < FILES; i++) { +# // check for errors +# char path[1024]; +# struct lfs_info info; +# sprintf(path, "test%d", i); +# lfs_stat(&lfs, path, &info) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# run_cycles[run] = cycle; +# LFS_WARN("completed %d blocks %d cycles", +# run_block_count[run], run_cycles[run]); +# } +# +# // check we increased the lifetime by 2x with ~10% error +# LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); +#''' +# +## test that we wear blocks roughly evenly +#[cases.test_exhaustion_wear_distribution] +#defines.ERASE_CYCLES = 0xffffffff +#defines.BLOCK_COUNT = 256 # small bd so test runs faster +#defines.BLOCK_CYCLES = [5, 4, 3, 2, 1] +#defines.CYCLES = 100 +#defines.FILES = 10 +#if = 'BLOCK_CYCLES < CYCLES/10' +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "roadrunner") => 0; +# lfs_unmount(&lfs) => 0; +# +# uint32_t cycle = 0; +# while (cycle < CYCLES) { +# lfs_mount(&lfs, cfg) => 0; +# for (uint32_t i = 0; i < FILES; i++) { +# // chose name, roughly random seed, and random 2^n size +# char path[1024]; +# sprintf(path, "roadrunner/test%d", i); +# uint32_t prng = cycle * i; +# lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2); +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# +# for (lfs_size_t j = 0; j < size; j++) { +# char c = 'a' + (TEST_PRNG(&prng) % 26); +# lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); +# assert(res == 1 || res == LFS_ERR_NOSPC); +# if (res == LFS_ERR_NOSPC) { +# int err = lfs_file_close(&lfs, &file); +# assert(err == 0 || err == LFS_ERR_NOSPC); +# lfs_unmount(&lfs) => 0; +# goto exhausted; +# } +# } +# +# int err = lfs_file_close(&lfs, &file); +# assert(err == 0 || err == LFS_ERR_NOSPC); +# if (err == LFS_ERR_NOSPC) { +# lfs_unmount(&lfs) => 0; +# goto exhausted; +# } +# } +# +# for (uint32_t i = 0; i < FILES; i++) { +# // check for errors +# char path[1024]; +# sprintf(path, "roadrunner/test%d", i); +# uint32_t prng = cycle * i; +# lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2); +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# for (lfs_size_t j = 0; j < size; j++) { +# char c = 'a' + (TEST_PRNG(&prng) % 26); +# char r; +# lfs_file_read(&lfs, &file, &r, 1) => 1; +# assert(r == c); +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# cycle += 1; +# } +# +#exhausted: +# // should still be readable +# lfs_mount(&lfs, cfg) => 0; +# for (uint32_t i = 0; i < FILES; i++) { +# // check for errors +# char path[1024]; +# struct lfs_info info; +# sprintf(path, "roadrunner/test%d", i); +# lfs_stat(&lfs, path, &info) => 0; +# } +# lfs_unmount(&lfs) => 0; +# +# LFS_WARN("completed %d cycles", cycle); +# +# // check the wear on our block device +# lfs_emubd_wear_t minwear = -1; +# lfs_emubd_wear_t totalwear = 0; +# lfs_emubd_wear_t maxwear = 0; +# // skip 0 and 1 as superblock movement is intentionally avoided +# for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) { +# lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b); +# printf("%08x: wear %d\n", b, wear); +# assert(wear >= 0); +# if (wear < minwear) { +# minwear = wear; +# } +# if (wear > maxwear) { +# maxwear = wear; +# } +# totalwear += wear; +# } +# lfs_emubd_wear_t avgwear = totalwear / BLOCK_COUNT; +# LFS_WARN("max wear: %d cycles", maxwear); +# LFS_WARN("avg wear: %d cycles", totalwear / (int)BLOCK_COUNT); +# LFS_WARN("min wear: %d cycles", minwear); +# +# // find standard deviation^2 +# lfs_emubd_wear_t dev2 = 0; +# for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) { +# lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b); +# assert(wear >= 0); +# lfs_emubd_swear_t diff = wear - avgwear; +# dev2 += diff*diff; +# } +# dev2 /= totalwear; +# LFS_WARN("std dev^2: %d", dev2); +# assert(dev2 < 8); +#''' +# diff --git a/tests/test_files.toml b/tests/test_files.toml index afb0811f..e70817da 100644 --- a/tests/test_files.toml +++ b/tests/test_files.toml @@ -1,516 +1,516 @@ - -[cases.test_files_simple] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "hello", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - lfs_size_t size = strlen("Hello World!")+1; - uint8_t buffer[1024]; - strcpy((char*)buffer, "Hello World!"); - lfs_file_write(&lfs, &file, buffer, size) => size; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, size) => size; - assert(strcmp((char*)buffer, "Hello World!") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_files_large] -defines.SIZE = [32, 8192, 262144, 0, 7, 8193] -defines.CHUNKSIZE = [31, 16, 33, 1, 1023] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - // write - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "avacado", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - uint32_t prng = 1; - uint8_t buffer[1024]; - for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); - for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = TEST_PRNG(&prng) & 0xff; - } - lfs_file_write(&lfs, &file, buffer, chunk) => chunk; - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // read - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => SIZE; - prng = 1; - for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_files_rewrite] -defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] -defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] -defines.CHUNKSIZE = [31, 16, 1] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - // write - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - uint8_t buffer[1024]; - lfs_file_open(&lfs, &file, "avacado", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - uint32_t prng = 1; - for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); - for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = TEST_PRNG(&prng) & 0xff; - } - lfs_file_write(&lfs, &file, buffer, chunk) => chunk; - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // read - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => SIZE1; - prng = 1; - for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // rewrite - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0; - prng = 2; - for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); - for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = TEST_PRNG(&prng) & 0xff; - } - lfs_file_write(&lfs, &file, buffer, chunk) => chunk; - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // read - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2); - prng = 2; - for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - if (SIZE1 > SIZE2) { - prng = 1; - for (lfs_size_t b = 0; b < SIZE2; b++) { - TEST_PRNG(&prng); - } - for (lfs_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - } - lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_files_append] -defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] -defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] -defines.CHUNKSIZE = [31, 16, 1] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - // write - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - uint8_t buffer[1024]; - lfs_file_open(&lfs, &file, "avacado", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - uint32_t prng = 1; - for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); - for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = TEST_PRNG(&prng) & 0xff; - } - lfs_file_write(&lfs, &file, buffer, chunk) => chunk; - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // read - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => SIZE1; - prng = 1; - for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // append - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0; - prng = 2; - for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); - for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = TEST_PRNG(&prng) & 0xff; - } - lfs_file_write(&lfs, &file, buffer, chunk) => chunk; - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // read - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => SIZE1 + SIZE2; - prng = 1; - for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - prng = 2; - for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_files_truncate] -defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] -defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] -defines.CHUNKSIZE = [31, 16, 1] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - // write - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - uint8_t buffer[1024]; - lfs_file_open(&lfs, &file, "avacado", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - uint32_t prng = 1; - for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); - for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = TEST_PRNG(&prng) & 0xff; - } - lfs_file_write(&lfs, &file, buffer, chunk) => chunk; - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // read - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => SIZE1; - prng = 1; - for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // truncate - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0; - prng = 2; - for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); - for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = TEST_PRNG(&prng) & 0xff; - } - lfs_file_write(&lfs, &file, buffer, chunk) => chunk; - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // read - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => SIZE2; - prng = 2; - for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_files_reentrant_write] -defines.SIZE = [32, 0, 7, 2049] -defines.CHUNKSIZE = [31, 16, 65] -reentrant = true -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - - lfs_file_t file; - uint8_t buffer[1024]; - err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); - assert(err == LFS_ERR_NOENT || err == 0); - if (err == 0) { - // can only be 0 (new file) or full size - lfs_size_t size = lfs_file_size(&lfs, &file); - assert(size == 0 || size == SIZE); - lfs_file_close(&lfs, &file) => 0; - } - - // write - lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT) => 0; - uint32_t prng = 1; - for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); - for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = TEST_PRNG(&prng) & 0xff; - } - lfs_file_write(&lfs, &file, buffer, chunk) => chunk; - } - lfs_file_close(&lfs, &file) => 0; - - // read - lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => SIZE; - prng = 1; - for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_files_reentrant_write_sync] -defines = [ - # append (O(n)) - {MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]}, - # truncate (O(n^2)) - {MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]}, - # rewrite (O(n^2)) - {MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]}, -] -reentrant = true -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - - lfs_file_t file; - uint8_t buffer[1024]; - err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); - assert(err == LFS_ERR_NOENT || err == 0); - if (err == 0) { - // with syncs we could be any size, but it at least must be valid data - lfs_size_t size = lfs_file_size(&lfs, &file); - assert(size <= SIZE); - uint32_t prng = 1; - for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, size-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - lfs_file_close(&lfs, &file) => 0; - } - - // write - lfs_file_open(&lfs, &file, "avacado", - LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0; - lfs_size_t size = lfs_file_size(&lfs, &file); - assert(size <= SIZE); - uint32_t prng = 1; - lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0; - for (lfs_size_t b = 0; b < skip; b++) { - TEST_PRNG(&prng); - } - for (lfs_size_t i = skip; i < SIZE; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); - for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = TEST_PRNG(&prng) & 0xff; - } - lfs_file_write(&lfs, &file, buffer, chunk) => chunk; - lfs_file_sync(&lfs, &file) => 0; - } - lfs_file_close(&lfs, &file) => 0; - - // read - lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => SIZE; - prng = 1; - for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { - lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); - lfs_file_read(&lfs, &file, buffer, chunk) => chunk; - for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); - } - } - lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_files_many] -defines.N = 300 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - // create N files of 7 bytes - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - lfs_file_t file; - char path[1024]; - sprintf(path, "file_%03d", i); - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - char wbuffer[1024]; - lfs_size_t size = 7; - sprintf(wbuffer, "Hi %03d", i); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_close(&lfs, &file) => 0; - - char rbuffer[1024]; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(strcmp(rbuffer, wbuffer) == 0); - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; -''' - -[cases.test_files_many_power_cycle] -defines.N = 300 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - // create N files of 7 bytes - lfs_mount(&lfs, cfg) => 0; - for (int i = 0; i < N; i++) { - lfs_file_t file; - char path[1024]; - sprintf(path, "file_%03d", i); - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - char wbuffer[1024]; - lfs_size_t size = 7; - sprintf(wbuffer, "Hi %03d", i); - lfs_file_write(&lfs, &file, wbuffer, size) => size; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - char rbuffer[1024]; - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(strcmp(rbuffer, wbuffer) == 0); - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; -''' - -[cases.test_files_many_power_loss] -defines.N = 300 -reentrant = true -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - // create N files of 7 bytes - for (int i = 0; i < N; i++) { - lfs_file_t file; - char path[1024]; - sprintf(path, "file_%03d", i); - err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT); - char wbuffer[1024]; - lfs_size_t size = 7; - sprintf(wbuffer, "Hi %03d", i); - if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) { - lfs_file_write(&lfs, &file, wbuffer, size) => size; - } - lfs_file_close(&lfs, &file) => 0; - - char rbuffer[1024]; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(strcmp(rbuffer, wbuffer) == 0); - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; -''' +# +#[cases.test_files_simple] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "hello", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# lfs_size_t size = strlen("Hello World!")+1; +# uint8_t buffer[1024]; +# strcpy((char*)buffer, "Hello World!"); +# lfs_file_write(&lfs, &file, buffer, size) => size; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# assert(strcmp((char*)buffer, "Hello World!") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_files_large] +#defines.SIZE = [32, 8192, 262144, 0, 7, 8193] +#defines.CHUNKSIZE = [31, 16, 33, 1, 1023] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# // write +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "avacado", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# uint32_t prng = 1; +# uint8_t buffer[1024]; +# for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); +# for (lfs_size_t b = 0; b < chunk; b++) { +# buffer[b] = TEST_PRNG(&prng) & 0xff; +# } +# lfs_file_write(&lfs, &file, buffer, chunk) => chunk; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // read +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => SIZE; +# prng = 1; +# for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_files_rewrite] +#defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] +#defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] +#defines.CHUNKSIZE = [31, 16, 1] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# // write +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# uint8_t buffer[1024]; +# lfs_file_open(&lfs, &file, "avacado", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# uint32_t prng = 1; +# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); +# for (lfs_size_t b = 0; b < chunk; b++) { +# buffer[b] = TEST_PRNG(&prng) & 0xff; +# } +# lfs_file_write(&lfs, &file, buffer, chunk) => chunk; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // read +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => SIZE1; +# prng = 1; +# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // rewrite +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0; +# prng = 2; +# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); +# for (lfs_size_t b = 0; b < chunk; b++) { +# buffer[b] = TEST_PRNG(&prng) & 0xff; +# } +# lfs_file_write(&lfs, &file, buffer, chunk) => chunk; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // read +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2); +# prng = 2; +# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# if (SIZE1 > SIZE2) { +# prng = 1; +# for (lfs_size_t b = 0; b < SIZE2; b++) { +# TEST_PRNG(&prng); +# } +# for (lfs_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# } +# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_files_append] +#defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] +#defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] +#defines.CHUNKSIZE = [31, 16, 1] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# // write +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# uint8_t buffer[1024]; +# lfs_file_open(&lfs, &file, "avacado", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# uint32_t prng = 1; +# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); +# for (lfs_size_t b = 0; b < chunk; b++) { +# buffer[b] = TEST_PRNG(&prng) & 0xff; +# } +# lfs_file_write(&lfs, &file, buffer, chunk) => chunk; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // read +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => SIZE1; +# prng = 1; +# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // append +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0; +# prng = 2; +# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); +# for (lfs_size_t b = 0; b < chunk; b++) { +# buffer[b] = TEST_PRNG(&prng) & 0xff; +# } +# lfs_file_write(&lfs, &file, buffer, chunk) => chunk; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // read +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => SIZE1 + SIZE2; +# prng = 1; +# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# prng = 2; +# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_files_truncate] +#defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] +#defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] +#defines.CHUNKSIZE = [31, 16, 1] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# // write +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# uint8_t buffer[1024]; +# lfs_file_open(&lfs, &file, "avacado", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# uint32_t prng = 1; +# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); +# for (lfs_size_t b = 0; b < chunk; b++) { +# buffer[b] = TEST_PRNG(&prng) & 0xff; +# } +# lfs_file_write(&lfs, &file, buffer, chunk) => chunk; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // read +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => SIZE1; +# prng = 1; +# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // truncate +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# prng = 2; +# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); +# for (lfs_size_t b = 0; b < chunk; b++) { +# buffer[b] = TEST_PRNG(&prng) & 0xff; +# } +# lfs_file_write(&lfs, &file, buffer, chunk) => chunk; +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // read +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => SIZE2; +# prng = 2; +# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_files_reentrant_write] +#defines.SIZE = [32, 0, 7, 2049] +#defines.CHUNKSIZE = [31, 16, 65] +#reentrant = true +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# +# lfs_file_t file; +# uint8_t buffer[1024]; +# err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); +# assert(err == LFS_ERR_NOENT || err == 0); +# if (err == 0) { +# // can only be 0 (new file) or full size +# lfs_size_t size = lfs_file_size(&lfs, &file); +# assert(size == 0 || size == SIZE); +# lfs_file_close(&lfs, &file) => 0; +# } +# +# // write +# lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# uint32_t prng = 1; +# for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); +# for (lfs_size_t b = 0; b < chunk; b++) { +# buffer[b] = TEST_PRNG(&prng) & 0xff; +# } +# lfs_file_write(&lfs, &file, buffer, chunk) => chunk; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# // read +# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => SIZE; +# prng = 1; +# for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_files_reentrant_write_sync] +#defines = [ +# # append (O(n)) +# {MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]}, +# # truncate (O(n^2)) +# {MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]}, +# # rewrite (O(n^2)) +# {MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]}, +#] +#reentrant = true +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# +# lfs_file_t file; +# uint8_t buffer[1024]; +# err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); +# assert(err == LFS_ERR_NOENT || err == 0); +# if (err == 0) { +# // with syncs we could be any size, but it at least must be valid data +# lfs_size_t size = lfs_file_size(&lfs, &file); +# assert(size <= SIZE); +# uint32_t prng = 1; +# for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, size-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# lfs_file_close(&lfs, &file) => 0; +# } +# +# // write +# lfs_file_open(&lfs, &file, "avacado", +# LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0; +# lfs_size_t size = lfs_file_size(&lfs, &file); +# assert(size <= SIZE); +# uint32_t prng = 1; +# lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0; +# for (lfs_size_t b = 0; b < skip; b++) { +# TEST_PRNG(&prng); +# } +# for (lfs_size_t i = skip; i < SIZE; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); +# for (lfs_size_t b = 0; b < chunk; b++) { +# buffer[b] = TEST_PRNG(&prng) & 0xff; +# } +# lfs_file_write(&lfs, &file, buffer, chunk) => chunk; +# lfs_file_sync(&lfs, &file) => 0; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# // read +# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => SIZE; +# prng = 1; +# for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { +# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); +# lfs_file_read(&lfs, &file, buffer, chunk) => chunk; +# for (lfs_size_t b = 0; b < chunk; b++) { +# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); +# } +# } +# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_files_many] +#defines.N = 300 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# // create N files of 7 bytes +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# lfs_file_t file; +# char path[1024]; +# sprintf(path, "file_%03d", i); +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# char wbuffer[1024]; +# lfs_size_t size = 7; +# sprintf(wbuffer, "Hi %03d", i); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_close(&lfs, &file) => 0; +# +# char rbuffer[1024]; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(strcmp(rbuffer, wbuffer) == 0); +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_files_many_power_cycle] +#defines.N = 300 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# // create N files of 7 bytes +# lfs_mount(&lfs, cfg) => 0; +# for (int i = 0; i < N; i++) { +# lfs_file_t file; +# char path[1024]; +# sprintf(path, "file_%03d", i); +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# char wbuffer[1024]; +# lfs_size_t size = 7; +# sprintf(wbuffer, "Hi %03d", i); +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# char rbuffer[1024]; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(strcmp(rbuffer, wbuffer) == 0); +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_files_many_power_loss] +#defines.N = 300 +#reentrant = true +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# // create N files of 7 bytes +# for (int i = 0; i < N; i++) { +# lfs_file_t file; +# char path[1024]; +# sprintf(path, "file_%03d", i); +# err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT); +# char wbuffer[1024]; +# lfs_size_t size = 7; +# sprintf(wbuffer, "Hi %03d", i); +# if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) { +# lfs_file_write(&lfs, &file, wbuffer, size) => size; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# char rbuffer[1024]; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(strcmp(rbuffer, wbuffer) == 0); +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +#''' diff --git a/tests/test_interspersed.toml b/tests/test_interspersed.toml index d7143f61..d30d1738 100644 --- a/tests/test_interspersed.toml +++ b/tests/test_interspersed.toml @@ -1,270 +1,270 @@ - -[cases.test_interspersed_files] -defines.SIZE = [10, 100] -defines.FILES = [4, 10, 26] -code = ''' - lfs_t lfs; - lfs_file_t files[FILES]; - const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - for (int j = 0; j < FILES; j++) { - char path[1024]; - sprintf(path, "%c", alphas[j]); - lfs_file_open(&lfs, &files[j], path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - } - - for (int i = 0; i < SIZE; i++) { - for (int j = 0; j < FILES; j++) { - lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1; - } - } - - for (int j = 0; j < FILES; j++) { - lfs_file_close(&lfs, &files[j]); - } - - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (int j = 0; j < FILES; j++) { - char path[1024]; - sprintf(path, "%c", alphas[j]); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, path) == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == SIZE); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - for (int j = 0; j < FILES; j++) { - char path[1024]; - sprintf(path, "%c", alphas[j]); - lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0; - } - - for (int i = 0; i < 10; i++) { - for (int j = 0; j < FILES; j++) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &files[j], buffer, 1) => 1; - assert(buffer[0] == alphas[j]); - } - } - - for (int j = 0; j < FILES; j++) { - lfs_file_close(&lfs, &files[j]); - } - - lfs_unmount(&lfs) => 0; -''' - -[cases.test_interspersed_remove_files] -defines.SIZE = [10, 100] -defines.FILES = [4, 10, 26] -code = ''' - lfs_t lfs; - const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - for (int j = 0; j < FILES; j++) { - char path[1024]; - sprintf(path, "%c", alphas[j]); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - for (int i = 0; i < SIZE; i++) { - lfs_file_write(&lfs, &file, &alphas[j], 1) => 1; - } - lfs_file_close(&lfs, &file); - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0; - for (int j = 0; j < FILES; j++) { - lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1; - lfs_file_sync(&lfs, &file) => 0; - - char path[1024]; - sprintf(path, "%c", alphas[j]); - lfs_remove(&lfs, path) => 0; - } - lfs_file_close(&lfs, &file); - - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "zzz") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == FILES); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "zzz", LFS_O_RDONLY) => 0; - for (int i = 0; i < FILES; i++) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, 1) => 1; - assert(buffer[0] == '~'); - } - lfs_file_close(&lfs, &file); - - lfs_unmount(&lfs) => 0; -''' - -[cases.test_interspersed_remove_inconveniently] -defines.SIZE = [10, 100] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t files[3]; - lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_open(&lfs, &files[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0; - - for (int i = 0; i < SIZE/2; i++) { - lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; - lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; - lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; - } - - lfs_remove(&lfs, "f") => 0; - - for (int i = 0; i < SIZE/2; i++) { - lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; - lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; - lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; - } - - lfs_file_close(&lfs, &files[0]); - lfs_file_close(&lfs, &files[1]); - lfs_file_close(&lfs, &files[2]); - - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "e") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == SIZE); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "g") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == SIZE); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0; - lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0; - for (int i = 0; i < SIZE; i++) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &files[0], buffer, 1) => 1; - assert(buffer[0] == 'e'); - lfs_file_read(&lfs, &files[1], buffer, 1) => 1; - assert(buffer[0] == 'g'); - } - lfs_file_close(&lfs, &files[0]); - lfs_file_close(&lfs, &files[1]); - - lfs_unmount(&lfs) => 0; -''' - -[cases.test_interspersed_reentrant_files] -defines.SIZE = [10, 100] -defines.FILES = [4, 10, 26] -reentrant = true -code = ''' - lfs_t lfs; - lfs_file_t files[FILES]; - const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; - - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - - for (int j = 0; j < FILES; j++) { - char path[1024]; - sprintf(path, "%c", alphas[j]); - lfs_file_open(&lfs, &files[j], path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - } - - for (int i = 0; i < SIZE; i++) { - for (int j = 0; j < FILES; j++) { - lfs_ssize_t size = lfs_file_size(&lfs, &files[j]); - assert(size >= 0); - if ((int)size <= i) { - lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1; - lfs_file_sync(&lfs, &files[j]) => 0; - } - } - } - - for (int j = 0; j < FILES; j++) { - lfs_file_close(&lfs, &files[j]); - } - - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/") => 0; - struct lfs_info info; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (int j = 0; j < FILES; j++) { - char path[1024]; - sprintf(path, "%c", alphas[j]); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, path) == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == SIZE); - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - for (int j = 0; j < FILES; j++) { - char path[1024]; - sprintf(path, "%c", alphas[j]); - lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0; - } - - for (int i = 0; i < 10; i++) { - for (int j = 0; j < FILES; j++) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &files[j], buffer, 1) => 1; - assert(buffer[0] == alphas[j]); - } - } - - for (int j = 0; j < FILES; j++) { - lfs_file_close(&lfs, &files[j]); - } - - lfs_unmount(&lfs) => 0; -''' +# +#[cases.test_interspersed_files] +#defines.SIZE = [10, 100] +#defines.FILES = [4, 10, 26] +#code = ''' +# lfs_t lfs; +# lfs_file_t files[FILES]; +# const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# for (int j = 0; j < FILES; j++) { +# char path[1024]; +# sprintf(path, "%c", alphas[j]); +# lfs_file_open(&lfs, &files[j], path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# } +# +# for (int i = 0; i < SIZE; i++) { +# for (int j = 0; j < FILES; j++) { +# lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1; +# } +# } +# +# for (int j = 0; j < FILES; j++) { +# lfs_file_close(&lfs, &files[j]); +# } +# +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# for (int j = 0; j < FILES; j++) { +# char path[1024]; +# sprintf(path, "%c", alphas[j]); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, path) == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == SIZE); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# for (int j = 0; j < FILES; j++) { +# char path[1024]; +# sprintf(path, "%c", alphas[j]); +# lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0; +# } +# +# for (int i = 0; i < 10; i++) { +# for (int j = 0; j < FILES; j++) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &files[j], buffer, 1) => 1; +# assert(buffer[0] == alphas[j]); +# } +# } +# +# for (int j = 0; j < FILES; j++) { +# lfs_file_close(&lfs, &files[j]); +# } +# +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_interspersed_remove_files] +#defines.SIZE = [10, 100] +#defines.FILES = [4, 10, 26] +#code = ''' +# lfs_t lfs; +# const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# for (int j = 0; j < FILES; j++) { +# char path[1024]; +# sprintf(path, "%c", alphas[j]); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +# for (int i = 0; i < SIZE; i++) { +# lfs_file_write(&lfs, &file, &alphas[j], 1) => 1; +# } +# lfs_file_close(&lfs, &file); +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# for (int j = 0; j < FILES; j++) { +# lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1; +# lfs_file_sync(&lfs, &file) => 0; +# +# char path[1024]; +# sprintf(path, "%c", alphas[j]); +# lfs_remove(&lfs, path) => 0; +# } +# lfs_file_close(&lfs, &file); +# +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "zzz") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == FILES); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "zzz", LFS_O_RDONLY) => 0; +# for (int i = 0; i < FILES; i++) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, 1) => 1; +# assert(buffer[0] == '~'); +# } +# lfs_file_close(&lfs, &file); +# +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_interspersed_remove_inconveniently] +#defines.SIZE = [10, 100] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t files[3]; +# lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_open(&lfs, &files[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# +# for (int i = 0; i < SIZE/2; i++) { +# lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; +# lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; +# lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; +# } +# +# lfs_remove(&lfs, "f") => 0; +# +# for (int i = 0; i < SIZE/2; i++) { +# lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; +# lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; +# lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; +# } +# +# lfs_file_close(&lfs, &files[0]); +# lfs_file_close(&lfs, &files[1]); +# lfs_file_close(&lfs, &files[2]); +# +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "e") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == SIZE); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "g") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == SIZE); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0; +# lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0; +# for (int i = 0; i < SIZE; i++) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &files[0], buffer, 1) => 1; +# assert(buffer[0] == 'e'); +# lfs_file_read(&lfs, &files[1], buffer, 1) => 1; +# assert(buffer[0] == 'g'); +# } +# lfs_file_close(&lfs, &files[0]); +# lfs_file_close(&lfs, &files[1]); +# +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_interspersed_reentrant_files] +#defines.SIZE = [10, 100] +#defines.FILES = [4, 10, 26] +#reentrant = true +#code = ''' +# lfs_t lfs; +# lfs_file_t files[FILES]; +# const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; +# +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# +# for (int j = 0; j < FILES; j++) { +# char path[1024]; +# sprintf(path, "%c", alphas[j]); +# lfs_file_open(&lfs, &files[j], path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# } +# +# for (int i = 0; i < SIZE; i++) { +# for (int j = 0; j < FILES; j++) { +# lfs_ssize_t size = lfs_file_size(&lfs, &files[j]); +# assert(size >= 0); +# if ((int)size <= i) { +# lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1; +# lfs_file_sync(&lfs, &files[j]) => 0; +# } +# } +# } +# +# for (int j = 0; j < FILES; j++) { +# lfs_file_close(&lfs, &files[j]); +# } +# +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# struct lfs_info info; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# for (int j = 0; j < FILES; j++) { +# char path[1024]; +# sprintf(path, "%c", alphas[j]); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, path) == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == SIZE); +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# for (int j = 0; j < FILES; j++) { +# char path[1024]; +# sprintf(path, "%c", alphas[j]); +# lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0; +# } +# +# for (int i = 0; i < 10; i++) { +# for (int j = 0; j < FILES; j++) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &files[j], buffer, 1) => 1; +# assert(buffer[0] == alphas[j]); +# } +# } +# +# for (int j = 0; j < FILES; j++) { +# lfs_file_close(&lfs, &files[j]); +# } +# +# lfs_unmount(&lfs) => 0; +#''' diff --git a/tests/test_move.toml b/tests/test_move.toml index 0537f486..ea913b90 100644 --- a/tests/test_move.toml +++ b/tests/test_move.toml @@ -1,1897 +1,1897 @@ -[cases.test_move_file] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "a") => 0; - lfs_mkdir(&lfs, "b") => 0; - lfs_mkdir(&lfs, "c") => 0; - lfs_mkdir(&lfs, "d") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; - lfs_file_write(&lfs, &file, "hola\n", 5) => 5; - lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; - lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hello", "c/hello") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hello") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 5+8+6); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0; - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, 5) => 5; - memcmp(buffer, "hola\n", 5) => 0; - lfs_file_read(&lfs, &file, buffer, 8) => 8; - memcmp(buffer, "bonjour\n", 8) => 0; - lfs_file_read(&lfs, &file, buffer, 6) => 6; - memcmp(buffer, "ohayo\n", 6) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_move_nop] # yes this is legal -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "hi") => 0; - lfs_rename(&lfs, "hi", "hi") => 0; - lfs_mkdir(&lfs, "hi/hi") => 0; - lfs_rename(&lfs, "hi/hi", "hi/hi") => 0; - lfs_mkdir(&lfs, "hi/hi/hi") => 0; - lfs_rename(&lfs, "hi/hi/hi", "hi/hi/hi") => 0; - struct lfs_info info; - lfs_stat(&lfs, "hi/hi/hi", &info) => 0; - assert(strcmp(info.name, "hi") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_unmount(&lfs) => 0; -''' - -[cases.test_move_file_corrupt_source] -in = "lfs.c" -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "a") => 0; - lfs_mkdir(&lfs, "b") => 0; - lfs_mkdir(&lfs, "c") => 0; - lfs_mkdir(&lfs, "d") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; - lfs_file_write(&lfs, &file, "hola\n", 5) => 5; - lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; - lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hello", "c/hello") => 0; - lfs_unmount(&lfs) => 0; - - // corrupt the source - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_block_t block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - uint8_t buffer[BLOCK_SIZE]; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - int off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hello") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 5+8+6); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 5) => 5; - memcmp(buffer, "hola\n", 5) => 0; - lfs_file_read(&lfs, &file, buffer, 8) => 8; - memcmp(buffer, "bonjour\n", 8) => 0; - lfs_file_read(&lfs, &file, buffer, 6) => 6; - memcmp(buffer, "ohayo\n", 6) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -# move file corrupt source and dest -[cases.test_move_file_corrupt_source_dest] -in = "lfs.c" -if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "a") => 0; - lfs_mkdir(&lfs, "b") => 0; - lfs_mkdir(&lfs, "c") => 0; - lfs_mkdir(&lfs, "d") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; - lfs_file_write(&lfs, &file, "hola\n", 5) => 5; - lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; - lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hello", "c/hello") => 0; - lfs_unmount(&lfs) => 0; - - // corrupt the source - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_block_t block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - uint8_t buffer[BLOCK_SIZE]; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - int off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - // corrupt the destination - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hello") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 5+8+6); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 5) => 5; - memcmp(buffer, "hola\n", 5) => 0; - lfs_file_read(&lfs, &file, buffer, 8) => 8; - memcmp(buffer, "bonjour\n", 8) => 0; - lfs_file_read(&lfs, &file, buffer, 6) => 6; - memcmp(buffer, "ohayo\n", 6) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_move_file_after_corrupt] -in = "lfs.c" -if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "a") => 0; - lfs_mkdir(&lfs, "b") => 0; - lfs_mkdir(&lfs, "c") => 0; - lfs_mkdir(&lfs, "d") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; - lfs_file_write(&lfs, &file, "hola\n", 5) => 5; - lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; - lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hello", "c/hello") => 0; - lfs_unmount(&lfs) => 0; - - // corrupt the source - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_block_t block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - uint8_t buffer[BLOCK_SIZE]; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - int off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - // corrupt the destination - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - // continue move - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hello", "c/hello") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hello") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 5+8+6); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 5) => 5; - memcmp(buffer, "hola\n", 5) => 0; - lfs_file_read(&lfs, &file, buffer, 8) => 8; - memcmp(buffer, "bonjour\n", 8) => 0; - lfs_file_read(&lfs, &file, buffer, 6) => 6; - memcmp(buffer, "ohayo\n", 6) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_move_reentrant_file] -reentrant = true -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - err = lfs_mkdir(&lfs, "a"); - assert(!err || err == LFS_ERR_EXIST); - err = lfs_mkdir(&lfs, "b"); - assert(!err || err == LFS_ERR_EXIST); - err = lfs_mkdir(&lfs, "c"); - assert(!err || err == LFS_ERR_EXIST); - err = lfs_mkdir(&lfs, "d"); - assert(!err || err == LFS_ERR_EXIST); - lfs_unmount(&lfs) => 0; - - while (true) { - lfs_mount(&lfs, cfg) => 0; - // there should never exist _2_ hello files - int count = 0; - struct lfs_info info; - if (lfs_stat(&lfs, "a/hello", &info) == 0) { - assert(strcmp(info.name, "hello") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 5+8+6 || info.size == 0); - count += 1; - } - if (lfs_stat(&lfs, "b/hello", &info) == 0) { - assert(strcmp(info.name, "hello") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 5+8+6); - count += 1; - } - if (lfs_stat(&lfs, "c/hello", &info) == 0) { - assert(strcmp(info.name, "hello") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 5+8+6); - count += 1; - } - if (lfs_stat(&lfs, "d/hello", &info) == 0) { - assert(strcmp(info.name, "hello") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 5+8+6); - count += 1; - } - assert(count <= 1); - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - if (lfs_stat(&lfs, "a/hello", &info) == 0 && info.size > 0) { - lfs_rename(&lfs, "a/hello", "b/hello") => 0; - } else if (lfs_stat(&lfs, "b/hello", &info) == 0) { - lfs_rename(&lfs, "b/hello", "c/hello") => 0; - } else if (lfs_stat(&lfs, "c/hello", &info) == 0) { - lfs_rename(&lfs, "c/hello", "d/hello") => 0; - } else if (lfs_stat(&lfs, "d/hello", &info) == 0) { - // success - lfs_unmount(&lfs) => 0; - break; - } else { - // create file - lfs_file_t file; - lfs_file_open(&lfs, &file, "a/hello", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "hola\n", 5) => 5; - lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; - lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; - lfs_file_close(&lfs, &file) => 0; - } - lfs_unmount(&lfs) => 0; - } - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "d") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hello") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 5+8+6); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_t file; - lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, 5) => 5; - memcmp(buffer, "hola\n", 5) => 0; - lfs_file_read(&lfs, &file, buffer, 8) => 8; - memcmp(buffer, "bonjour\n", 8) => 0; - lfs_file_read(&lfs, &file, buffer, 6) => 6; - memcmp(buffer, "ohayo\n", 6) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_move_dir] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "a") => 0; - lfs_mkdir(&lfs, "b") => 0; - lfs_mkdir(&lfs, "c") => 0; - lfs_mkdir(&lfs, "d") => 0; - lfs_mkdir(&lfs, "a/hi") => 0; - lfs_mkdir(&lfs, "a/hi/hola") => 0; - lfs_mkdir(&lfs, "a/hi/bonjour") => 0; - lfs_mkdir(&lfs, "a/hi/ohayo") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hi", "c/hi") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hi") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "c/hi") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "bonjour") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hola") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "ohayo") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_move_dir_corrupt_source] -in = "lfs.c" -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "a") => 0; - lfs_mkdir(&lfs, "b") => 0; - lfs_mkdir(&lfs, "c") => 0; - lfs_mkdir(&lfs, "d") => 0; - lfs_mkdir(&lfs, "a/hi") => 0; - lfs_mkdir(&lfs, "a/hi/hola") => 0; - lfs_mkdir(&lfs, "a/hi/bonjour") => 0; - lfs_mkdir(&lfs, "a/hi/ohayo") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hi", "c/hi") => 0; - lfs_unmount(&lfs) => 0; - - // corrupt the source - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_block_t block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - uint8_t buffer[BLOCK_SIZE]; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - int off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hi") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "c/hi") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "bonjour") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hola") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "ohayo") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_move_dir_corrupt_source_dest] -in = "lfs.c" -if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "a") => 0; - lfs_mkdir(&lfs, "b") => 0; - lfs_mkdir(&lfs, "c") => 0; - lfs_mkdir(&lfs, "d") => 0; - lfs_mkdir(&lfs, "a/hi") => 0; - lfs_mkdir(&lfs, "a/hi/hola") => 0; - lfs_mkdir(&lfs, "a/hi/bonjour") => 0; - lfs_mkdir(&lfs, "a/hi/ohayo") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hi", "c/hi") => 0; - lfs_unmount(&lfs) => 0; - - // corrupt the source - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_block_t block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - uint8_t buffer[BLOCK_SIZE]; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - int off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - // corrupt the destination - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hi") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "a/hi") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "bonjour") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hola") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "ohayo") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "c/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_move_dir_after_corrupt] -in = "lfs.c" -if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "a") => 0; - lfs_mkdir(&lfs, "b") => 0; - lfs_mkdir(&lfs, "c") => 0; - lfs_mkdir(&lfs, "d") => 0; - lfs_mkdir(&lfs, "a/hi") => 0; - lfs_mkdir(&lfs, "a/hi/hola") => 0; - lfs_mkdir(&lfs, "a/hi/bonjour") => 0; - lfs_mkdir(&lfs, "a/hi/ohayo") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hi", "c/hi") => 0; - lfs_unmount(&lfs) => 0; - - // corrupt the source - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_block_t block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - uint8_t buffer[BLOCK_SIZE]; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - int off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - // corrupt the destination - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - // continue move - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hi", "c/hi") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "c") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hi") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "c/hi") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "bonjour") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hola") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "ohayo") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_reentrant_dir] -reentrant = true -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - err = lfs_mkdir(&lfs, "a"); - assert(!err || err == LFS_ERR_EXIST); - err = lfs_mkdir(&lfs, "b"); - assert(!err || err == LFS_ERR_EXIST); - err = lfs_mkdir(&lfs, "c"); - assert(!err || err == LFS_ERR_EXIST); - err = lfs_mkdir(&lfs, "d"); - assert(!err || err == LFS_ERR_EXIST); - lfs_unmount(&lfs) => 0; - - while (true) { - lfs_mount(&lfs, cfg) => 0; - // there should never exist _2_ hi directories - int count = 0; - struct lfs_info info; - if (lfs_stat(&lfs, "a/hi", &info) == 0) { - assert(strcmp(info.name, "hi") == 0); - assert(info.type == LFS_TYPE_DIR); - count += 1; - } - if (lfs_stat(&lfs, "b/hi", &info) == 0) { - assert(strcmp(info.name, "hi") == 0); - assert(info.type == LFS_TYPE_DIR); - count += 1; - } - if (lfs_stat(&lfs, "c/hi", &info) == 0) { - assert(strcmp(info.name, "hi") == 0); - assert(info.type == LFS_TYPE_DIR); - count += 1; - } - if (lfs_stat(&lfs, "d/hi", &info) == 0) { - assert(strcmp(info.name, "hi") == 0); - assert(info.type == LFS_TYPE_DIR); - count += 1; - } - assert(count <= 1); - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - if (lfs_stat(&lfs, "a/hi", &info) == 0) { - lfs_rename(&lfs, "a/hi", "b/hi") => 0; - } else if (lfs_stat(&lfs, "b/hi", &info) == 0) { - lfs_rename(&lfs, "b/hi", "c/hi") => 0; - } else if (lfs_stat(&lfs, "c/hi", &info) == 0) { - lfs_rename(&lfs, "c/hi", "d/hi") => 0; - } else if (lfs_stat(&lfs, "d/hi", &info) == 0) { - lfs_unmount(&lfs) => 0; - break; // success - } else { - // create dir and rename for atomicity - err = lfs_mkdir(&lfs, "temp"); - assert(!err || err == LFS_ERR_EXIST); - err = lfs_mkdir(&lfs, "temp/hola"); - assert(!err || err == LFS_ERR_EXIST); - err = lfs_mkdir(&lfs, "temp/bonjour"); - assert(!err || err == LFS_ERR_EXIST); - err = lfs_mkdir(&lfs, "temp/ohayo"); - assert(!err || err == LFS_ERR_EXIST); - lfs_rename(&lfs, "temp", "a/hi") => 0; - } - lfs_unmount(&lfs) => 0; - } - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "a") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_dir_open(&lfs, &dir, "d") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hi") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "c/hi") => LFS_ERR_NOENT; - lfs_dir_open(&lfs, &dir, "d/hi") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "bonjour") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "hola") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "ohayo") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -''' - -[cases.test_move_state_stealing] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "a") => 0; - lfs_mkdir(&lfs, "b") => 0; - lfs_mkdir(&lfs, "c") => 0; - lfs_mkdir(&lfs, "d") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; - lfs_file_write(&lfs, &file, "hola\n", 5) => 5; - lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; - lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "a/hello", "b/hello") => 0; - lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "b/hello", "c/hello") => 0; - lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_rename(&lfs, "c/hello", "d/hello") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, 5) => 5; - memcmp(buffer, "hola\n", 5) => 0; - lfs_file_read(&lfs, &file, buffer, 8) => 8; - memcmp(buffer, "bonjour\n", 8) => 0; - lfs_file_read(&lfs, &file, buffer, 6) => 6; - memcmp(buffer, "ohayo\n", 6) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_remove(&lfs, "b") => 0; - lfs_remove(&lfs, "c") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - struct lfs_info info; - lfs_stat(&lfs, "a", &info) => 0; - lfs_stat(&lfs, "b", &info) => LFS_ERR_NOENT; - lfs_stat(&lfs, "c", &info) => LFS_ERR_NOENT; - lfs_stat(&lfs, "d", &info) => 0; - lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 5) => 5; - memcmp(buffer, "hola\n", 5) => 0; - lfs_file_read(&lfs, &file, buffer, 8) => 8; - memcmp(buffer, "bonjour\n", 8) => 0; - lfs_file_read(&lfs, &file, buffer, 6) => 6; - memcmp(buffer, "ohayo\n", 6) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# Other specific corner cases - -# create + delete in same commit with neighbors -[cases.test_move_create_delete_same] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // littlefs keeps files sorted, so we know the order these will be in - lfs_file_t file; - lfs_file_open(&lfs, &file, "/1.move_me", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "/0.before", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.1", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "/2.in_between", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.2", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "/4.after", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.3", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_t files[3]; - lfs_file_open(&lfs, &files[0], "0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[1], "2.in_between", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[2], "4.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_write(&lfs, &files[0], "test.4", 7) => 7; - lfs_file_write(&lfs, &files[1], "test.5", 7) => 7; - lfs_file_write(&lfs, &files[2], "test.6", 7) => 7; - - // rename file while everything is open, this triggers both - // a create and delete simultaneously - lfs_rename(&lfs, "/1.move_me", "/3.move_me") => 0; - - lfs_file_close(&lfs, &files[0]) => 0; - lfs_file_close(&lfs, &files[1]) => 0; - lfs_file_close(&lfs, &files[2]) => 0; - - // check that nothing was corrupted - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.in_between") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "3.move_me") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "4.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.4") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.5") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.6") == 0); - lfs_file_close(&lfs, &file) => 0; - - // now move back - lfs_file_open(&lfs, &files[0], "0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[1], "2.in_between", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[2], "4.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_write(&lfs, &files[0], "test.7", 7) => 7; - lfs_file_write(&lfs, &files[1], "test.8", 7) => 7; - lfs_file_write(&lfs, &files[2], "test.9", 7) => 7; - - // rename file while everything is open, this triggers both - // a create and delete simultaneously - lfs_rename(&lfs, "/3.move_me", "/1.move_me") => 0; - - lfs_file_close(&lfs, &files[0]) => 0; - lfs_file_close(&lfs, &files[1]) => 0; - lfs_file_close(&lfs, &files[2]) => 0; - - // and check that nothing was corrupted again - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "1.move_me") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.in_between") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "4.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.7") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.8") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.9") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# create + delete + delete in same commit with neighbors -[cases.test_move_create_delete_delete_same] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // littlefs keeps files sorted, so we know the order these will be in - lfs_file_t file; - lfs_file_open(&lfs, &file, "/1.move_me", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/3.move_me", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "remove me", - sizeof("remove me")) => sizeof("remove me"); - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "/0.before", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.1", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "/2.in_between", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.2", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "/4.after", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.3", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_t files[3]; - lfs_file_open(&lfs, &files[0], "0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[1], "2.in_between", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[2], "4.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_write(&lfs, &files[0], "test.4", 7) => 7; - lfs_file_write(&lfs, &files[1], "test.5", 7) => 7; - lfs_file_write(&lfs, &files[2], "test.6", 7) => 7; - - // rename file while everything is open, this triggers both - // a create and delete simultaneously - lfs_rename(&lfs, "/1.move_me", "/3.move_me") => 0; - - lfs_file_close(&lfs, &files[0]) => 0; - lfs_file_close(&lfs, &files[1]) => 0; - lfs_file_close(&lfs, &files[2]) => 0; - - // check that nothing was corrupted - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.in_between") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "3.move_me") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "4.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.4") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.5") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.6") == 0); - lfs_file_close(&lfs, &file) => 0; - - // now move back - lfs_file_open(&lfs, &file, "/1.move_me", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "remove me", - sizeof("remove me")) => sizeof("remove me"); - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &files[0], "0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[1], "2.in_between", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[2], "4.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_write(&lfs, &files[0], "test.7", 7) => 7; - lfs_file_write(&lfs, &files[1], "test.8", 7) => 7; - lfs_file_write(&lfs, &files[2], "test.9", 7) => 7; - - // rename file while everything is open, this triggers both - // a create and delete simultaneously - lfs_rename(&lfs, "/3.move_me", "/1.move_me") => 0; - - lfs_file_close(&lfs, &files[0]) => 0; - lfs_file_close(&lfs, &files[1]) => 0; - lfs_file_close(&lfs, &files[2]) => 0; - - // and check that nothing was corrupted again - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "1.move_me") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.in_between") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "4.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.7") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.8") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.9") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# create + delete in different dirs with neighbors -[cases.test_move_create_delete_different] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - // littlefs keeps files sorted, so we know the order these will be in - lfs_mkdir(&lfs, "/dir.1") => 0; - lfs_mkdir(&lfs, "/dir.2") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "/dir.1/1.move_me", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/dir.2/1.move_me", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "remove me", - sizeof("remove me")) => sizeof("remove me"); - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "/dir.1/0.before", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.1", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/dir.1/2.after", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.2", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "/dir.2/0.before", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.3", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/dir.2/2.after", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.4", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_t files[4]; - lfs_file_open(&lfs, &files[0], "/dir.1/0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[1], "/dir.1/2.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[2], "/dir.2/0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[3], "/dir.2/2.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_write(&lfs, &files[0], "test.5", 7) => 7; - lfs_file_write(&lfs, &files[1], "test.6", 7) => 7; - lfs_file_write(&lfs, &files[2], "test.7", 7) => 7; - lfs_file_write(&lfs, &files[3], "test.8", 7) => 7; - - // rename file while everything is open, this triggers both - // a create and delete as it overwrites the destination file - lfs_rename(&lfs, "/dir.1/1.move_me", "/dir.2/1.move_me") => 0; - - lfs_file_close(&lfs, &files[0]) => 0; - lfs_file_close(&lfs, &files[1]) => 0; - lfs_file_close(&lfs, &files[2]) => 0; - lfs_file_close(&lfs, &files[3]) => 0; - - // check that nothing was corrupted - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "dir.1") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "dir.2") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "/dir.1") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "/dir.2") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "1.move_me") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "/dir.1/0.before", LFS_O_RDONLY) => 0; - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.5") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/dir.1/2.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.6") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/dir.2/0.before", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.7") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/dir.2/2.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.8") == 0); - lfs_file_close(&lfs, &file) => 0; - - // now move back - lfs_file_open(&lfs, &file, "/dir.1/1.move_me", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "remove me", - sizeof("remove me")) => sizeof("remove me"); - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &files[0], "/dir.1/0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[1], "/dir.1/2.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[2], "/dir.2/0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[3], "/dir.2/2.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_write(&lfs, &files[0], "test.9", 7) => 7; - lfs_file_write(&lfs, &files[1], "test.a", 7) => 7; - lfs_file_write(&lfs, &files[2], "test.b", 7) => 7; - lfs_file_write(&lfs, &files[3], "test.c", 7) => 7; - - // rename file while everything is open, this triggers both - // a create and delete simultaneously - lfs_rename(&lfs, "/dir.2/1.move_me", "/dir.1/1.move_me") => 0; - - lfs_file_close(&lfs, &files[0]) => 0; - lfs_file_close(&lfs, &files[1]) => 0; - lfs_file_close(&lfs, &files[2]) => 0; - lfs_file_close(&lfs, &files[3]) => 0; - - // and check that nothing was corrupted again - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "dir.1") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "dir.2") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "/dir.1") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "1.move_me") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "/dir.2") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "/dir.1/0.before", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.9") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/dir.1/2.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.a") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/dir.2/0.before", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.b") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/dir.2/2.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.c") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# move fix in relocation -[cases.test_move_fix_relocation] -in = "lfs.c" -defines.RELOCATIONS = 'range(4)' -defines.ERASE_CYCLES = 0xffffffff -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - lfs_mkdir(&lfs, "/parent") => 0; - lfs_mkdir(&lfs, "/parent/child") => 0; - - lfs_file_t file; - lfs_file_open(&lfs, &file, "/parent/1.move_me", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "move me", - sizeof("move me")) => sizeof("move me"); - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "/parent/0.before", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.1", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/2.after", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.2", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/child/0.before", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.3", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/child/2.after", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.4", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_t files[4]; - lfs_file_open(&lfs, &files[0], "/parent/0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[1], "/parent/2.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[2], "/parent/child/0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[3], "/parent/child/2.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_write(&lfs, &files[0], "test.5", 7) => 7; - lfs_file_write(&lfs, &files[1], "test.6", 7) => 7; - lfs_file_write(&lfs, &files[2], "test.7", 7) => 7; - lfs_file_write(&lfs, &files[3], "test.8", 7) => 7; - - // force specific directories to relocate - if (RELOCATIONS & 0x1) { - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/parent"); - lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; - lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; - lfs_dir_close(&lfs, &dir) => 0; - } - if (RELOCATIONS & 0x2) { - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/parent/child"); - lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; - lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; - lfs_dir_close(&lfs, &dir) => 0; - } - - // ok, now we move the file, this creates a move that needs to be - // fixed, possibly in a metadata-pair that needs to be relocated - // - // the worst case is if we need to relocate and we need to implicit - // fix the move in our parent before it falls out of date - lfs_rename(&lfs, "/parent/1.move_me", "/parent/child/1.move_me") => 0; - - lfs_file_close(&lfs, &files[0]) => 0; - lfs_file_close(&lfs, &files[1]) => 0; - lfs_file_close(&lfs, &files[2]) => 0; - lfs_file_close(&lfs, &files[3]) => 0; - - // check that nothing was corrupted - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "/parent") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "child") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "/parent/child") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "1.move_me") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == sizeof("move me")); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "/parent/0.before", LFS_O_RDONLY) => 0; - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.5") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/2.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.6") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/child/0.before", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.7") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/child/2.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.8") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# move fix in relocation with predecessor -[cases.test_move_fix_relocation_predecessor] -in = "lfs.c" -defines.RELOCATIONS = 'range(8)' -defines.ERASE_CYCLES = 0xffffffff -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - lfs_mkdir(&lfs, "/parent") => 0; - lfs_mkdir(&lfs, "/parent/child") => 0; - lfs_mkdir(&lfs, "/parent/sibling") => 0; - - lfs_file_t file; - lfs_file_open(&lfs, &file, "/parent/sibling/1.move_me", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "move me", - sizeof("move me")) => sizeof("move me"); - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "/parent/sibling/0.before", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.1", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/sibling/2.after", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.2", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/child/0.before", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.3", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/child/2.after", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_write(&lfs, &file, "test.4", 7) => 7; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_t files[4]; - lfs_file_open(&lfs, &files[0], "/parent/sibling/0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[1], "/parent/sibling/2.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[2], "/parent/child/0.before", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_open(&lfs, &files[3], "/parent/child/2.after", - LFS_O_WRONLY | LFS_O_TRUNC) => 0; - lfs_file_write(&lfs, &files[0], "test.5", 7) => 7; - lfs_file_write(&lfs, &files[1], "test.6", 7) => 7; - lfs_file_write(&lfs, &files[2], "test.7", 7) => 7; - lfs_file_write(&lfs, &files[3], "test.8", 7) => 7; - - // force specific directories to relocate - if (RELOCATIONS & 0x1) { - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/parent"); - lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; - lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; - lfs_dir_close(&lfs, &dir) => 0; - } - if (RELOCATIONS & 0x2) { - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/parent/sibling"); - lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; - lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; - lfs_dir_close(&lfs, &dir) => 0; - } - if (RELOCATIONS & 0x4) { - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "/parent/child"); - lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; - lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; - lfs_dir_close(&lfs, &dir) => 0; - } - - // ok, now we move the file, this creates a move that needs to be - // fixed, possibly in a metadata-pair that needs to be relocated - // - // and now relocations can force us to need to fix our move in either - // the parent or child before things break - lfs_rename(&lfs, - "/parent/sibling/1.move_me", - "/parent/child/1.move_me") => 0; - - lfs_file_close(&lfs, &files[0]) => 0; - lfs_file_close(&lfs, &files[1]) => 0; - lfs_file_close(&lfs, &files[2]) => 0; - lfs_file_close(&lfs, &files[3]) => 0; - - // check that nothing was corrupted - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "/parent") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "child") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "sibling") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "/parent/sibling") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_dir_open(&lfs, &dir, "/parent/child") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "0.before") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "1.move_me") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == sizeof("move me")); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(strcmp(info.name, "2.after") == 0); - assert(info.type == LFS_TYPE_REG); - assert(info.size == 7); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - lfs_file_open(&lfs, &file, "/parent/sibling/0.before", LFS_O_RDONLY) => 0; - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.5") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/sibling/2.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.6") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/child/0.before", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.7") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_file_open(&lfs, &file, "/parent/child/2.after", LFS_O_RDONLY) => 0; - lfs_file_read(&lfs, &file, buffer, 7) => 7; - assert(strcmp((char*)buffer, "test.8") == 0); - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' +#[cases.test_move_file] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "a") => 0; +# lfs_mkdir(&lfs, "b") => 0; +# lfs_mkdir(&lfs, "c") => 0; +# lfs_mkdir(&lfs, "d") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; +# lfs_file_write(&lfs, &file, "hola\n", 5) => 5; +# lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; +# lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hello", "c/hello") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hello") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 5+8+6); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0; +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, 5) => 5; +# memcmp(buffer, "hola\n", 5) => 0; +# lfs_file_read(&lfs, &file, buffer, 8) => 8; +# memcmp(buffer, "bonjour\n", 8) => 0; +# lfs_file_read(&lfs, &file, buffer, 6) => 6; +# memcmp(buffer, "ohayo\n", 6) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_move_nop] # yes this is legal +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "hi") => 0; +# lfs_rename(&lfs, "hi", "hi") => 0; +# lfs_mkdir(&lfs, "hi/hi") => 0; +# lfs_rename(&lfs, "hi/hi", "hi/hi") => 0; +# lfs_mkdir(&lfs, "hi/hi/hi") => 0; +# lfs_rename(&lfs, "hi/hi/hi", "hi/hi/hi") => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "hi/hi/hi", &info) => 0; +# assert(strcmp(info.name, "hi") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_move_file_corrupt_source] +#in = "lfs.c" +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "a") => 0; +# lfs_mkdir(&lfs, "b") => 0; +# lfs_mkdir(&lfs, "c") => 0; +# lfs_mkdir(&lfs, "d") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; +# lfs_file_write(&lfs, &file, "hola\n", 5) => 5; +# lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; +# lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hello", "c/hello") => 0; +# lfs_unmount(&lfs) => 0; +# +# // corrupt the source +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_block_t block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# uint8_t buffer[BLOCK_SIZE]; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# int off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hello") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 5+8+6); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 5) => 5; +# memcmp(buffer, "hola\n", 5) => 0; +# lfs_file_read(&lfs, &file, buffer, 8) => 8; +# memcmp(buffer, "bonjour\n", 8) => 0; +# lfs_file_read(&lfs, &file, buffer, 6) => 6; +# memcmp(buffer, "ohayo\n", 6) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +## move file corrupt source and dest +#[cases.test_move_file_corrupt_source_dest] +#in = "lfs.c" +#if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "a") => 0; +# lfs_mkdir(&lfs, "b") => 0; +# lfs_mkdir(&lfs, "c") => 0; +# lfs_mkdir(&lfs, "d") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; +# lfs_file_write(&lfs, &file, "hola\n", 5) => 5; +# lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; +# lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hello", "c/hello") => 0; +# lfs_unmount(&lfs) => 0; +# +# // corrupt the source +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_block_t block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# uint8_t buffer[BLOCK_SIZE]; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# int off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# // corrupt the destination +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hello") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 5+8+6); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 5) => 5; +# memcmp(buffer, "hola\n", 5) => 0; +# lfs_file_read(&lfs, &file, buffer, 8) => 8; +# memcmp(buffer, "bonjour\n", 8) => 0; +# lfs_file_read(&lfs, &file, buffer, 6) => 6; +# memcmp(buffer, "ohayo\n", 6) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_move_file_after_corrupt] +#in = "lfs.c" +#if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "a") => 0; +# lfs_mkdir(&lfs, "b") => 0; +# lfs_mkdir(&lfs, "c") => 0; +# lfs_mkdir(&lfs, "d") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; +# lfs_file_write(&lfs, &file, "hola\n", 5) => 5; +# lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; +# lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hello", "c/hello") => 0; +# lfs_unmount(&lfs) => 0; +# +# // corrupt the source +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_block_t block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# uint8_t buffer[BLOCK_SIZE]; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# int off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# // corrupt the destination +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# // continue move +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hello", "c/hello") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hello") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 5+8+6); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 5) => 5; +# memcmp(buffer, "hola\n", 5) => 0; +# lfs_file_read(&lfs, &file, buffer, 8) => 8; +# memcmp(buffer, "bonjour\n", 8) => 0; +# lfs_file_read(&lfs, &file, buffer, 6) => 6; +# memcmp(buffer, "ohayo\n", 6) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_move_reentrant_file] +#reentrant = true +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# err = lfs_mkdir(&lfs, "a"); +# assert(!err || err == LFS_ERR_EXIST); +# err = lfs_mkdir(&lfs, "b"); +# assert(!err || err == LFS_ERR_EXIST); +# err = lfs_mkdir(&lfs, "c"); +# assert(!err || err == LFS_ERR_EXIST); +# err = lfs_mkdir(&lfs, "d"); +# assert(!err || err == LFS_ERR_EXIST); +# lfs_unmount(&lfs) => 0; +# +# while (true) { +# lfs_mount(&lfs, cfg) => 0; +# // there should never exist _2_ hello files +# int count = 0; +# struct lfs_info info; +# if (lfs_stat(&lfs, "a/hello", &info) == 0) { +# assert(strcmp(info.name, "hello") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 5+8+6 || info.size == 0); +# count += 1; +# } +# if (lfs_stat(&lfs, "b/hello", &info) == 0) { +# assert(strcmp(info.name, "hello") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 5+8+6); +# count += 1; +# } +# if (lfs_stat(&lfs, "c/hello", &info) == 0) { +# assert(strcmp(info.name, "hello") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 5+8+6); +# count += 1; +# } +# if (lfs_stat(&lfs, "d/hello", &info) == 0) { +# assert(strcmp(info.name, "hello") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 5+8+6); +# count += 1; +# } +# assert(count <= 1); +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# if (lfs_stat(&lfs, "a/hello", &info) == 0 && info.size > 0) { +# lfs_rename(&lfs, "a/hello", "b/hello") => 0; +# } else if (lfs_stat(&lfs, "b/hello", &info) == 0) { +# lfs_rename(&lfs, "b/hello", "c/hello") => 0; +# } else if (lfs_stat(&lfs, "c/hello", &info) == 0) { +# lfs_rename(&lfs, "c/hello", "d/hello") => 0; +# } else if (lfs_stat(&lfs, "d/hello", &info) == 0) { +# // success +# lfs_unmount(&lfs) => 0; +# break; +# } else { +# // create file +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "a/hello", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "hola\n", 5) => 5; +# lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; +# lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_unmount(&lfs) => 0; +# } +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "d") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hello") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 5+8+6); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, 5) => 5; +# memcmp(buffer, "hola\n", 5) => 0; +# lfs_file_read(&lfs, &file, buffer, 8) => 8; +# memcmp(buffer, "bonjour\n", 8) => 0; +# lfs_file_read(&lfs, &file, buffer, 6) => 6; +# memcmp(buffer, "ohayo\n", 6) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_move_dir] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "a") => 0; +# lfs_mkdir(&lfs, "b") => 0; +# lfs_mkdir(&lfs, "c") => 0; +# lfs_mkdir(&lfs, "d") => 0; +# lfs_mkdir(&lfs, "a/hi") => 0; +# lfs_mkdir(&lfs, "a/hi/hola") => 0; +# lfs_mkdir(&lfs, "a/hi/bonjour") => 0; +# lfs_mkdir(&lfs, "a/hi/ohayo") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hi", "c/hi") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hi") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "c/hi") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "bonjour") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hola") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "ohayo") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_move_dir_corrupt_source] +#in = "lfs.c" +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "a") => 0; +# lfs_mkdir(&lfs, "b") => 0; +# lfs_mkdir(&lfs, "c") => 0; +# lfs_mkdir(&lfs, "d") => 0; +# lfs_mkdir(&lfs, "a/hi") => 0; +# lfs_mkdir(&lfs, "a/hi/hola") => 0; +# lfs_mkdir(&lfs, "a/hi/bonjour") => 0; +# lfs_mkdir(&lfs, "a/hi/ohayo") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hi", "c/hi") => 0; +# lfs_unmount(&lfs) => 0; +# +# // corrupt the source +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_block_t block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# uint8_t buffer[BLOCK_SIZE]; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# int off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hi") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "c/hi") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "bonjour") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hola") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "ohayo") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_move_dir_corrupt_source_dest] +#in = "lfs.c" +#if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "a") => 0; +# lfs_mkdir(&lfs, "b") => 0; +# lfs_mkdir(&lfs, "c") => 0; +# lfs_mkdir(&lfs, "d") => 0; +# lfs_mkdir(&lfs, "a/hi") => 0; +# lfs_mkdir(&lfs, "a/hi/hola") => 0; +# lfs_mkdir(&lfs, "a/hi/bonjour") => 0; +# lfs_mkdir(&lfs, "a/hi/ohayo") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hi", "c/hi") => 0; +# lfs_unmount(&lfs) => 0; +# +# // corrupt the source +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_block_t block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# uint8_t buffer[BLOCK_SIZE]; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# int off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# // corrupt the destination +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hi") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "a/hi") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "bonjour") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hola") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "ohayo") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "c/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_move_dir_after_corrupt] +#in = "lfs.c" +#if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "a") => 0; +# lfs_mkdir(&lfs, "b") => 0; +# lfs_mkdir(&lfs, "c") => 0; +# lfs_mkdir(&lfs, "d") => 0; +# lfs_mkdir(&lfs, "a/hi") => 0; +# lfs_mkdir(&lfs, "a/hi/hola") => 0; +# lfs_mkdir(&lfs, "a/hi/bonjour") => 0; +# lfs_mkdir(&lfs, "a/hi/ohayo") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hi", "c/hi") => 0; +# lfs_unmount(&lfs) => 0; +# +# // corrupt the source +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_block_t block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# uint8_t buffer[BLOCK_SIZE]; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# int off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# // corrupt the destination +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# // continue move +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hi", "c/hi") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "c") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hi") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "c/hi") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "bonjour") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hola") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "ohayo") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_reentrant_dir] +#reentrant = true +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# err = lfs_mkdir(&lfs, "a"); +# assert(!err || err == LFS_ERR_EXIST); +# err = lfs_mkdir(&lfs, "b"); +# assert(!err || err == LFS_ERR_EXIST); +# err = lfs_mkdir(&lfs, "c"); +# assert(!err || err == LFS_ERR_EXIST); +# err = lfs_mkdir(&lfs, "d"); +# assert(!err || err == LFS_ERR_EXIST); +# lfs_unmount(&lfs) => 0; +# +# while (true) { +# lfs_mount(&lfs, cfg) => 0; +# // there should never exist _2_ hi directories +# int count = 0; +# struct lfs_info info; +# if (lfs_stat(&lfs, "a/hi", &info) == 0) { +# assert(strcmp(info.name, "hi") == 0); +# assert(info.type == LFS_TYPE_DIR); +# count += 1; +# } +# if (lfs_stat(&lfs, "b/hi", &info) == 0) { +# assert(strcmp(info.name, "hi") == 0); +# assert(info.type == LFS_TYPE_DIR); +# count += 1; +# } +# if (lfs_stat(&lfs, "c/hi", &info) == 0) { +# assert(strcmp(info.name, "hi") == 0); +# assert(info.type == LFS_TYPE_DIR); +# count += 1; +# } +# if (lfs_stat(&lfs, "d/hi", &info) == 0) { +# assert(strcmp(info.name, "hi") == 0); +# assert(info.type == LFS_TYPE_DIR); +# count += 1; +# } +# assert(count <= 1); +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# if (lfs_stat(&lfs, "a/hi", &info) == 0) { +# lfs_rename(&lfs, "a/hi", "b/hi") => 0; +# } else if (lfs_stat(&lfs, "b/hi", &info) == 0) { +# lfs_rename(&lfs, "b/hi", "c/hi") => 0; +# } else if (lfs_stat(&lfs, "c/hi", &info) == 0) { +# lfs_rename(&lfs, "c/hi", "d/hi") => 0; +# } else if (lfs_stat(&lfs, "d/hi", &info) == 0) { +# lfs_unmount(&lfs) => 0; +# break; // success +# } else { +# // create dir and rename for atomicity +# err = lfs_mkdir(&lfs, "temp"); +# assert(!err || err == LFS_ERR_EXIST); +# err = lfs_mkdir(&lfs, "temp/hola"); +# assert(!err || err == LFS_ERR_EXIST); +# err = lfs_mkdir(&lfs, "temp/bonjour"); +# assert(!err || err == LFS_ERR_EXIST); +# err = lfs_mkdir(&lfs, "temp/ohayo"); +# assert(!err || err == LFS_ERR_EXIST); +# lfs_rename(&lfs, "temp", "a/hi") => 0; +# } +# lfs_unmount(&lfs) => 0; +# } +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "a") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_dir_open(&lfs, &dir, "d") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hi") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "c/hi") => LFS_ERR_NOENT; +# lfs_dir_open(&lfs, &dir, "d/hi") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "bonjour") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "hola") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "ohayo") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_move_state_stealing] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "a") => 0; +# lfs_mkdir(&lfs, "b") => 0; +# lfs_mkdir(&lfs, "c") => 0; +# lfs_mkdir(&lfs, "d") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; +# lfs_file_write(&lfs, &file, "hola\n", 5) => 5; +# lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; +# lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "a/hello", "b/hello") => 0; +# lfs_unmount(&lfs) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "b/hello", "c/hello") => 0; +# lfs_unmount(&lfs) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_rename(&lfs, "c/hello", "d/hello") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, 5) => 5; +# memcmp(buffer, "hola\n", 5) => 0; +# lfs_file_read(&lfs, &file, buffer, 8) => 8; +# memcmp(buffer, "bonjour\n", 8) => 0; +# lfs_file_read(&lfs, &file, buffer, 6) => 6; +# memcmp(buffer, "ohayo\n", 6) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_remove(&lfs, "b") => 0; +# lfs_remove(&lfs, "c") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "a", &info) => 0; +# lfs_stat(&lfs, "b", &info) => LFS_ERR_NOENT; +# lfs_stat(&lfs, "c", &info) => LFS_ERR_NOENT; +# lfs_stat(&lfs, "d", &info) => 0; +# lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 5) => 5; +# memcmp(buffer, "hola\n", 5) => 0; +# lfs_file_read(&lfs, &file, buffer, 8) => 8; +# memcmp(buffer, "bonjour\n", 8) => 0; +# lfs_file_read(&lfs, &file, buffer, 6) => 6; +# memcmp(buffer, "ohayo\n", 6) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## Other specific corner cases +# +## create + delete in same commit with neighbors +#[cases.test_move_create_delete_same] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // littlefs keeps files sorted, so we know the order these will be in +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "/1.move_me", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "/0.before", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.1", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "/2.in_between", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.2", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "/4.after", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.3", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_t files[3]; +# lfs_file_open(&lfs, &files[0], "0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[1], "2.in_between", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[2], "4.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_write(&lfs, &files[0], "test.4", 7) => 7; +# lfs_file_write(&lfs, &files[1], "test.5", 7) => 7; +# lfs_file_write(&lfs, &files[2], "test.6", 7) => 7; +# +# // rename file while everything is open, this triggers both +# // a create and delete simultaneously +# lfs_rename(&lfs, "/1.move_me", "/3.move_me") => 0; +# +# lfs_file_close(&lfs, &files[0]) => 0; +# lfs_file_close(&lfs, &files[1]) => 0; +# lfs_file_close(&lfs, &files[2]) => 0; +# +# // check that nothing was corrupted +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.in_between") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "3.move_me") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "4.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.4") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.5") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.6") == 0); +# lfs_file_close(&lfs, &file) => 0; +# +# // now move back +# lfs_file_open(&lfs, &files[0], "0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[1], "2.in_between", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[2], "4.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_write(&lfs, &files[0], "test.7", 7) => 7; +# lfs_file_write(&lfs, &files[1], "test.8", 7) => 7; +# lfs_file_write(&lfs, &files[2], "test.9", 7) => 7; +# +# // rename file while everything is open, this triggers both +# // a create and delete simultaneously +# lfs_rename(&lfs, "/3.move_me", "/1.move_me") => 0; +# +# lfs_file_close(&lfs, &files[0]) => 0; +# lfs_file_close(&lfs, &files[1]) => 0; +# lfs_file_close(&lfs, &files[2]) => 0; +# +# // and check that nothing was corrupted again +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "1.move_me") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.in_between") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "4.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.7") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.8") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.9") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## create + delete + delete in same commit with neighbors +#[cases.test_move_create_delete_delete_same] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // littlefs keeps files sorted, so we know the order these will be in +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "/1.move_me", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/3.move_me", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "remove me", +# sizeof("remove me")) => sizeof("remove me"); +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "/0.before", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.1", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "/2.in_between", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.2", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "/4.after", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.3", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_t files[3]; +# lfs_file_open(&lfs, &files[0], "0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[1], "2.in_between", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[2], "4.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_write(&lfs, &files[0], "test.4", 7) => 7; +# lfs_file_write(&lfs, &files[1], "test.5", 7) => 7; +# lfs_file_write(&lfs, &files[2], "test.6", 7) => 7; +# +# // rename file while everything is open, this triggers both +# // a create and delete simultaneously +# lfs_rename(&lfs, "/1.move_me", "/3.move_me") => 0; +# +# lfs_file_close(&lfs, &files[0]) => 0; +# lfs_file_close(&lfs, &files[1]) => 0; +# lfs_file_close(&lfs, &files[2]) => 0; +# +# // check that nothing was corrupted +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.in_between") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "3.move_me") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "4.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.4") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.5") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.6") == 0); +# lfs_file_close(&lfs, &file) => 0; +# +# // now move back +# lfs_file_open(&lfs, &file, "/1.move_me", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "remove me", +# sizeof("remove me")) => sizeof("remove me"); +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &files[0], "0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[1], "2.in_between", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[2], "4.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_write(&lfs, &files[0], "test.7", 7) => 7; +# lfs_file_write(&lfs, &files[1], "test.8", 7) => 7; +# lfs_file_write(&lfs, &files[2], "test.9", 7) => 7; +# +# // rename file while everything is open, this triggers both +# // a create and delete simultaneously +# lfs_rename(&lfs, "/3.move_me", "/1.move_me") => 0; +# +# lfs_file_close(&lfs, &files[0]) => 0; +# lfs_file_close(&lfs, &files[1]) => 0; +# lfs_file_close(&lfs, &files[2]) => 0; +# +# // and check that nothing was corrupted again +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "1.move_me") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.in_between") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "4.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.7") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/2.in_between", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.8") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/4.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.9") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## create + delete in different dirs with neighbors +#[cases.test_move_create_delete_different] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# // littlefs keeps files sorted, so we know the order these will be in +# lfs_mkdir(&lfs, "/dir.1") => 0; +# lfs_mkdir(&lfs, "/dir.2") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "/dir.1/1.move_me", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/dir.2/1.move_me", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "remove me", +# sizeof("remove me")) => sizeof("remove me"); +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "/dir.1/0.before", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.1", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/dir.1/2.after", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.2", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "/dir.2/0.before", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.3", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/dir.2/2.after", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.4", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_t files[4]; +# lfs_file_open(&lfs, &files[0], "/dir.1/0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[1], "/dir.1/2.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[2], "/dir.2/0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[3], "/dir.2/2.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_write(&lfs, &files[0], "test.5", 7) => 7; +# lfs_file_write(&lfs, &files[1], "test.6", 7) => 7; +# lfs_file_write(&lfs, &files[2], "test.7", 7) => 7; +# lfs_file_write(&lfs, &files[3], "test.8", 7) => 7; +# +# // rename file while everything is open, this triggers both +# // a create and delete as it overwrites the destination file +# lfs_rename(&lfs, "/dir.1/1.move_me", "/dir.2/1.move_me") => 0; +# +# lfs_file_close(&lfs, &files[0]) => 0; +# lfs_file_close(&lfs, &files[1]) => 0; +# lfs_file_close(&lfs, &files[2]) => 0; +# lfs_file_close(&lfs, &files[3]) => 0; +# +# // check that nothing was corrupted +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "dir.1") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "dir.2") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "/dir.1") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "/dir.2") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "1.move_me") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "/dir.1/0.before", LFS_O_RDONLY) => 0; +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.5") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/dir.1/2.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.6") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/dir.2/0.before", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.7") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/dir.2/2.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.8") == 0); +# lfs_file_close(&lfs, &file) => 0; +# +# // now move back +# lfs_file_open(&lfs, &file, "/dir.1/1.move_me", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "remove me", +# sizeof("remove me")) => sizeof("remove me"); +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &files[0], "/dir.1/0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[1], "/dir.1/2.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[2], "/dir.2/0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[3], "/dir.2/2.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_write(&lfs, &files[0], "test.9", 7) => 7; +# lfs_file_write(&lfs, &files[1], "test.a", 7) => 7; +# lfs_file_write(&lfs, &files[2], "test.b", 7) => 7; +# lfs_file_write(&lfs, &files[3], "test.c", 7) => 7; +# +# // rename file while everything is open, this triggers both +# // a create and delete simultaneously +# lfs_rename(&lfs, "/dir.2/1.move_me", "/dir.1/1.move_me") => 0; +# +# lfs_file_close(&lfs, &files[0]) => 0; +# lfs_file_close(&lfs, &files[1]) => 0; +# lfs_file_close(&lfs, &files[2]) => 0; +# lfs_file_close(&lfs, &files[3]) => 0; +# +# // and check that nothing was corrupted again +# lfs_dir_open(&lfs, &dir, "/") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "dir.1") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "dir.2") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "/dir.1") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "1.move_me") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 0); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "/dir.2") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "/dir.1/0.before", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.9") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/dir.1/2.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.a") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/dir.2/0.before", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.b") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/dir.2/2.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.c") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## move fix in relocation +#[cases.test_move_fix_relocation] +#in = "lfs.c" +#defines.RELOCATIONS = 'range(4)' +#defines.ERASE_CYCLES = 0xffffffff +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# lfs_mkdir(&lfs, "/parent") => 0; +# lfs_mkdir(&lfs, "/parent/child") => 0; +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "/parent/1.move_me", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "move me", +# sizeof("move me")) => sizeof("move me"); +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "/parent/0.before", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.1", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/2.after", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.2", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/child/0.before", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.3", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/child/2.after", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.4", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_t files[4]; +# lfs_file_open(&lfs, &files[0], "/parent/0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[1], "/parent/2.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[2], "/parent/child/0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[3], "/parent/child/2.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_write(&lfs, &files[0], "test.5", 7) => 7; +# lfs_file_write(&lfs, &files[1], "test.6", 7) => 7; +# lfs_file_write(&lfs, &files[2], "test.7", 7) => 7; +# lfs_file_write(&lfs, &files[3], "test.8", 7) => 7; +# +# // force specific directories to relocate +# if (RELOCATIONS & 0x1) { +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/parent"); +# lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; +# lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# } +# if (RELOCATIONS & 0x2) { +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/parent/child"); +# lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; +# lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# } +# +# // ok, now we move the file, this creates a move that needs to be +# // fixed, possibly in a metadata-pair that needs to be relocated +# // +# // the worst case is if we need to relocate and we need to implicit +# // fix the move in our parent before it falls out of date +# lfs_rename(&lfs, "/parent/1.move_me", "/parent/child/1.move_me") => 0; +# +# lfs_file_close(&lfs, &files[0]) => 0; +# lfs_file_close(&lfs, &files[1]) => 0; +# lfs_file_close(&lfs, &files[2]) => 0; +# lfs_file_close(&lfs, &files[3]) => 0; +# +# // check that nothing was corrupted +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "/parent") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "child") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "/parent/child") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "1.move_me") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == sizeof("move me")); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "/parent/0.before", LFS_O_RDONLY) => 0; +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.5") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/2.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.6") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/child/0.before", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.7") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/child/2.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.8") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## move fix in relocation with predecessor +#[cases.test_move_fix_relocation_predecessor] +#in = "lfs.c" +#defines.RELOCATIONS = 'range(8)' +#defines.ERASE_CYCLES = 0xffffffff +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# lfs_mkdir(&lfs, "/parent") => 0; +# lfs_mkdir(&lfs, "/parent/child") => 0; +# lfs_mkdir(&lfs, "/parent/sibling") => 0; +# +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "/parent/sibling/1.move_me", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "move me", +# sizeof("move me")) => sizeof("move me"); +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "/parent/sibling/0.before", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.1", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/sibling/2.after", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.2", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/child/0.before", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.3", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/child/2.after", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_write(&lfs, &file, "test.4", 7) => 7; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_t files[4]; +# lfs_file_open(&lfs, &files[0], "/parent/sibling/0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[1], "/parent/sibling/2.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[2], "/parent/child/0.before", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_open(&lfs, &files[3], "/parent/child/2.after", +# LFS_O_WRONLY | LFS_O_TRUNC) => 0; +# lfs_file_write(&lfs, &files[0], "test.5", 7) => 7; +# lfs_file_write(&lfs, &files[1], "test.6", 7) => 7; +# lfs_file_write(&lfs, &files[2], "test.7", 7) => 7; +# lfs_file_write(&lfs, &files[3], "test.8", 7) => 7; +# +# // force specific directories to relocate +# if (RELOCATIONS & 0x1) { +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/parent"); +# lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; +# lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# } +# if (RELOCATIONS & 0x2) { +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/parent/sibling"); +# lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; +# lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# } +# if (RELOCATIONS & 0x4) { +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "/parent/child"); +# lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; +# lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# } +# +# // ok, now we move the file, this creates a move that needs to be +# // fixed, possibly in a metadata-pair that needs to be relocated +# // +# // and now relocations can force us to need to fix our move in either +# // the parent or child before things break +# lfs_rename(&lfs, +# "/parent/sibling/1.move_me", +# "/parent/child/1.move_me") => 0; +# +# lfs_file_close(&lfs, &files[0]) => 0; +# lfs_file_close(&lfs, &files[1]) => 0; +# lfs_file_close(&lfs, &files[2]) => 0; +# lfs_file_close(&lfs, &files[3]) => 0; +# +# // check that nothing was corrupted +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "/parent") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "child") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "sibling") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "/parent/sibling") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_dir_open(&lfs, &dir, "/parent/child") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, ".") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "..") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "0.before") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "1.move_me") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == sizeof("move me")); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# assert(strcmp(info.name, "2.after") == 0); +# assert(info.type == LFS_TYPE_REG); +# assert(info.size == 7); +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# lfs_file_open(&lfs, &file, "/parent/sibling/0.before", LFS_O_RDONLY) => 0; +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.5") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/sibling/2.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.6") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/child/0.before", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.7") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_file_open(&lfs, &file, "/parent/child/2.after", LFS_O_RDONLY) => 0; +# lfs_file_read(&lfs, &file, buffer, 7) => 7; +# assert(strcmp((char*)buffer, "test.8") == 0); +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' diff --git a/tests/test_orphans.toml b/tests/test_orphans.toml index b6b182ec..4691f5b2 100644 --- a/tests/test_orphans.toml +++ b/tests/test_orphans.toml @@ -1,129 +1,129 @@ -[cases.test_orphans_normal] -in = "lfs.c" -if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "parent") => 0; - lfs_mkdir(&lfs, "parent/orphan") => 0; - lfs_mkdir(&lfs, "parent/child") => 0; - lfs_remove(&lfs, "parent/orphan") => 0; - lfs_unmount(&lfs) => 0; - - // corrupt the child's most recent commit, this should be the update - // to the linked-list entry, which should orphan the orphan. Note this - // makes a lot of assumptions about the remove operation. - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "parent/child") => 0; - lfs_block_t block = dir.m.pair[0]; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - uint8_t buffer[BLOCK_SIZE]; - cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - int off = BLOCK_SIZE-1; - while (off >= 0 && buffer[off] == ERASE_VALUE) { - off -= 1; - } - memset(&buffer[off-3], BLOCK_SIZE, 3); - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; - cfg->sync(cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - struct lfs_info info; - lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; - lfs_stat(&lfs, "parent/child", &info) => 0; - lfs_fs_size(&lfs) => 8; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; - lfs_stat(&lfs, "parent/child", &info) => 0; - lfs_fs_size(&lfs) => 8; - // this mkdir should both create a dir and deorphan, so size - // should be unchanged - lfs_mkdir(&lfs, "parent/otherchild") => 0; - lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; - lfs_stat(&lfs, "parent/child", &info) => 0; - lfs_stat(&lfs, "parent/otherchild", &info) => 0; - lfs_fs_size(&lfs) => 8; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; - lfs_stat(&lfs, "parent/child", &info) => 0; - lfs_stat(&lfs, "parent/otherchild", &info) => 0; - lfs_fs_size(&lfs) => 8; - lfs_unmount(&lfs) => 0; -''' - -# reentrant testing for orphans, basically just spam mkdir/remove -[cases.test_orphans_reentrant] -reentrant = true -# TODO fix this case, caused by non-DAG trees -if = '!(DEPTH == 3 && CACHE_SIZE != 64)' -defines = [ - {FILES=6, DEPTH=1, CYCLES=20}, - {FILES=26, DEPTH=1, CYCLES=20}, - {FILES=3, DEPTH=3, CYCLES=20}, -] -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - - uint32_t prng = 1; - const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; - for (unsigned i = 0; i < CYCLES; i++) { - // create random path - char full_path[256]; - for (unsigned d = 0; d < DEPTH; d++) { - sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); - } - - // if it does not exist, we create it, else we destroy - struct lfs_info info; - int res = lfs_stat(&lfs, full_path, &info); - if (res == LFS_ERR_NOENT) { - // create each directory in turn, ignore if dir already exists - for (unsigned d = 0; d < DEPTH; d++) { - char path[1024]; - strcpy(path, full_path); - path[2*d+2] = '\0'; - err = lfs_mkdir(&lfs, path); - assert(!err || err == LFS_ERR_EXIST); - } - - for (unsigned d = 0; d < DEPTH; d++) { - char path[1024]; - strcpy(path, full_path); - path[2*d+2] = '\0'; - lfs_stat(&lfs, path, &info) => 0; - assert(strcmp(info.name, &path[2*d+1]) == 0); - assert(info.type == LFS_TYPE_DIR); - } - } else { - // is valid dir? - assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); - assert(info.type == LFS_TYPE_DIR); - - // try to delete path in reverse order, ignore if dir is not empty - for (int d = DEPTH-1; d >= 0; d--) { - char path[1024]; - strcpy(path, full_path); - path[2*d+2] = '\0'; - err = lfs_remove(&lfs, path); - assert(!err || err == LFS_ERR_NOTEMPTY); - } - - lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; - } - } - lfs_unmount(&lfs) => 0; -''' - +#[cases.test_orphans_normal] +#in = "lfs.c" +#if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "parent") => 0; +# lfs_mkdir(&lfs, "parent/orphan") => 0; +# lfs_mkdir(&lfs, "parent/child") => 0; +# lfs_remove(&lfs, "parent/orphan") => 0; +# lfs_unmount(&lfs) => 0; +# +# // corrupt the child's most recent commit, this should be the update +# // to the linked-list entry, which should orphan the orphan. Note this +# // makes a lot of assumptions about the remove operation. +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "parent/child") => 0; +# lfs_block_t block = dir.m.pair[0]; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# uint8_t buffer[BLOCK_SIZE]; +# cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# int off = BLOCK_SIZE-1; +# while (off >= 0 && buffer[off] == ERASE_VALUE) { +# off -= 1; +# } +# memset(&buffer[off-3], BLOCK_SIZE, 3); +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; +# cfg->sync(cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; +# lfs_stat(&lfs, "parent/child", &info) => 0; +# lfs_fs_size(&lfs) => 8; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; +# lfs_stat(&lfs, "parent/child", &info) => 0; +# lfs_fs_size(&lfs) => 8; +# // this mkdir should both create a dir and deorphan, so size +# // should be unchanged +# lfs_mkdir(&lfs, "parent/otherchild") => 0; +# lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; +# lfs_stat(&lfs, "parent/child", &info) => 0; +# lfs_stat(&lfs, "parent/otherchild", &info) => 0; +# lfs_fs_size(&lfs) => 8; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; +# lfs_stat(&lfs, "parent/child", &info) => 0; +# lfs_stat(&lfs, "parent/otherchild", &info) => 0; +# lfs_fs_size(&lfs) => 8; +# lfs_unmount(&lfs) => 0; +#''' +# +## reentrant testing for orphans, basically just spam mkdir/remove +#[cases.test_orphans_reentrant] +#reentrant = true +## TODO fix this case, caused by non-DAG trees +#if = '!(DEPTH == 3 && CACHE_SIZE != 64)' +#defines = [ +# {FILES=6, DEPTH=1, CYCLES=20}, +# {FILES=26, DEPTH=1, CYCLES=20}, +# {FILES=3, DEPTH=3, CYCLES=20}, +#] +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# +# uint32_t prng = 1; +# const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; +# for (unsigned i = 0; i < CYCLES; i++) { +# // create random path +# char full_path[256]; +# for (unsigned d = 0; d < DEPTH; d++) { +# sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); +# } +# +# // if it does not exist, we create it, else we destroy +# struct lfs_info info; +# int res = lfs_stat(&lfs, full_path, &info); +# if (res == LFS_ERR_NOENT) { +# // create each directory in turn, ignore if dir already exists +# for (unsigned d = 0; d < DEPTH; d++) { +# char path[1024]; +# strcpy(path, full_path); +# path[2*d+2] = '\0'; +# err = lfs_mkdir(&lfs, path); +# assert(!err || err == LFS_ERR_EXIST); +# } +# +# for (unsigned d = 0; d < DEPTH; d++) { +# char path[1024]; +# strcpy(path, full_path); +# path[2*d+2] = '\0'; +# lfs_stat(&lfs, path, &info) => 0; +# assert(strcmp(info.name, &path[2*d+1]) == 0); +# assert(info.type == LFS_TYPE_DIR); +# } +# } else { +# // is valid dir? +# assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# // try to delete path in reverse order, ignore if dir is not empty +# for (int d = DEPTH-1; d >= 0; d--) { +# char path[1024]; +# strcpy(path, full_path); +# path[2*d+2] = '\0'; +# err = lfs_remove(&lfs, path); +# assert(!err || err == LFS_ERR_NOTEMPTY); +# } +# +# lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; +# } +# } +# lfs_unmount(&lfs) => 0; +#''' +# diff --git a/tests/test_paths.toml b/tests/test_paths.toml index 97a519ea..3e082067 100644 --- a/tests/test_paths.toml +++ b/tests/test_paths.toml @@ -1,336 +1,336 @@ - -# simple path test -[cases.test_paths_normal] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; - - struct lfs_info info; - lfs_stat(&lfs, "tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "/tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - - lfs_mkdir(&lfs, "/milk") => 0; - lfs_stat(&lfs, "/milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); - lfs_stat(&lfs, "milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); - lfs_unmount(&lfs) => 0; -''' - -# redundant slashes -[cases.test_paths_redundant_slashes] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; - - struct lfs_info info; - lfs_stat(&lfs, "/tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "//tea//hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "///tea///hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - - lfs_mkdir(&lfs, "////milk") => 0; - lfs_stat(&lfs, "////milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); - lfs_stat(&lfs, "milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); - lfs_unmount(&lfs) => 0; -''' - -# dot path test -[cases.test_paths_dot] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; - - struct lfs_info info; - lfs_stat(&lfs, "./tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "/./tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "/././tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "/./tea/./hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - - lfs_mkdir(&lfs, "/./milk") => 0; - lfs_stat(&lfs, "/./milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); - lfs_stat(&lfs, "milk", &info) => 0; - assert(strcmp(info.name, "milk") == 0); - lfs_unmount(&lfs) => 0; -''' - -# dot dot path test -[cases.test_paths_dot_dot] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; - lfs_mkdir(&lfs, "coffee") => 0; - lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; - lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; - lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; - - struct lfs_info info; - lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "coffee/coldcoffee/../../tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "coffee/../coffee/../tea/hottea", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - - lfs_mkdir(&lfs, "coffee/../milk") => 0; - lfs_stat(&lfs, "coffee/../milk", &info) => 0; - strcmp(info.name, "milk") => 0; - lfs_stat(&lfs, "milk", &info) => 0; - strcmp(info.name, "milk") => 0; - lfs_unmount(&lfs) => 0; -''' - -# trailing dot path test -[cases.test_paths_trailing_dot] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; - - struct lfs_info info; - lfs_stat(&lfs, "tea/hottea/", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "tea/hottea/.", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "tea/hottea/./.", &info) => 0; - assert(strcmp(info.name, "hottea") == 0); - lfs_stat(&lfs, "tea/hottea/..", &info) => 0; - assert(strcmp(info.name, "tea") == 0); - lfs_stat(&lfs, "tea/hottea/../.", &info) => 0; - assert(strcmp(info.name, "tea") == 0); - lfs_unmount(&lfs) => 0; -''' - -# leading dot path test -[cases.test_paths_leading_dot] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, ".milk") => 0; - struct lfs_info info; - lfs_stat(&lfs, ".milk", &info) => 0; - strcmp(info.name, ".milk") => 0; - lfs_stat(&lfs, "tea/.././.milk", &info) => 0; - strcmp(info.name, ".milk") => 0; - lfs_unmount(&lfs) => 0; -''' - -# root dot dot path test -[cases.test_paths_root_dot_dot] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "tea") => 0; - lfs_mkdir(&lfs, "tea/hottea") => 0; - lfs_mkdir(&lfs, "tea/warmtea") => 0; - lfs_mkdir(&lfs, "tea/coldtea") => 0; - lfs_mkdir(&lfs, "coffee") => 0; - lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; - lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; - lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; - - struct lfs_info info; - lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; - strcmp(info.name, "hottea") => 0; - - lfs_mkdir(&lfs, "coffee/../../../../../../milk") => 0; - lfs_stat(&lfs, "coffee/../../../../../../milk", &info) => 0; - strcmp(info.name, "milk") => 0; - lfs_stat(&lfs, "milk", &info) => 0; - strcmp(info.name, "milk") => 0; - lfs_unmount(&lfs) => 0; -''' - -# invalid path tests -[cases.test_paths_invalid] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg); - lfs_mount(&lfs, cfg) => 0; - struct lfs_info info; - lfs_stat(&lfs, "dirt", &info) => LFS_ERR_NOENT; - lfs_stat(&lfs, "dirt/ground", &info) => LFS_ERR_NOENT; - lfs_stat(&lfs, "dirt/ground/earth", &info) => LFS_ERR_NOENT; - - lfs_remove(&lfs, "dirt") => LFS_ERR_NOENT; - lfs_remove(&lfs, "dirt/ground") => LFS_ERR_NOENT; - lfs_remove(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; - - lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; - lfs_file_t file; - lfs_file_open(&lfs, &file, "dirt/ground", LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_NOENT; - lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; - lfs_file_open(&lfs, &file, "dirt/ground/earth", LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -# root operations -[cases.test_paths_root] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - struct lfs_info info; - lfs_stat(&lfs, "/", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - - lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; - lfs_file_t file; - lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_ISDIR; - - lfs_remove(&lfs, "/") => LFS_ERR_INVAL; - lfs_unmount(&lfs) => 0; -''' - -# root representations -[cases.test_paths_root_reprs] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - struct lfs_info info; - lfs_stat(&lfs, "/", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_stat(&lfs, "", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_stat(&lfs, ".", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_stat(&lfs, "..", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_stat(&lfs, "//", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_stat(&lfs, "./", &info) => 0; - assert(strcmp(info.name, "/") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_unmount(&lfs) => 0; -''' - -# superblock conflict test -[cases.test_paths_superblock_conflict] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - struct lfs_info info; - lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; - lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT; - - lfs_mkdir(&lfs, "littlefs") => 0; - lfs_stat(&lfs, "littlefs", &info) => 0; - assert(strcmp(info.name, "littlefs") == 0); - assert(info.type == LFS_TYPE_DIR); - lfs_remove(&lfs, "littlefs") => 0; - lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; - lfs_unmount(&lfs) => 0; -''' - -# max path test -[cases.test_paths_max] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "coffee") => 0; - lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; - lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; - lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; - - char path[1024]; - memset(path, 'w', LFS_NAME_MAX+1); - path[LFS_NAME_MAX+1] = '\0'; - lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_NAMETOOLONG; - - memcpy(path, "coffee/", strlen("coffee/")); - memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX+1); - path[strlen("coffee/")+LFS_NAME_MAX+1] = '\0'; - lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; - lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) - => LFS_ERR_NAMETOOLONG; - lfs_unmount(&lfs) => 0; -''' - -# really big path test -[cases.test_paths_really_big] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "coffee") => 0; - lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; - lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; - lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; - - char path[1024]; - memset(path, 'w', LFS_NAME_MAX); - path[LFS_NAME_MAX] = '\0'; - lfs_mkdir(&lfs, path) => 0; - lfs_remove(&lfs, path) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_remove(&lfs, path) => 0; - - memcpy(path, "coffee/", strlen("coffee/")); - memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX); - path[strlen("coffee/")+LFS_NAME_MAX] = '\0'; - lfs_mkdir(&lfs, path) => 0; - lfs_remove(&lfs, path) => 0; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_remove(&lfs, path) => 0; - lfs_unmount(&lfs) => 0; -''' - +# +## simple path test +#[cases.test_paths_normal] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "tea") => 0; +# lfs_mkdir(&lfs, "tea/hottea") => 0; +# lfs_mkdir(&lfs, "tea/warmtea") => 0; +# lfs_mkdir(&lfs, "tea/coldtea") => 0; +# +# struct lfs_info info; +# lfs_stat(&lfs, "tea/hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "/tea/hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# +# lfs_mkdir(&lfs, "/milk") => 0; +# lfs_stat(&lfs, "/milk", &info) => 0; +# assert(strcmp(info.name, "milk") == 0); +# lfs_stat(&lfs, "milk", &info) => 0; +# assert(strcmp(info.name, "milk") == 0); +# lfs_unmount(&lfs) => 0; +#''' +# +## redundant slashes +#[cases.test_paths_redundant_slashes] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "tea") => 0; +# lfs_mkdir(&lfs, "tea/hottea") => 0; +# lfs_mkdir(&lfs, "tea/warmtea") => 0; +# lfs_mkdir(&lfs, "tea/coldtea") => 0; +# +# struct lfs_info info; +# lfs_stat(&lfs, "/tea/hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "//tea//hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "///tea///hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# +# lfs_mkdir(&lfs, "////milk") => 0; +# lfs_stat(&lfs, "////milk", &info) => 0; +# assert(strcmp(info.name, "milk") == 0); +# lfs_stat(&lfs, "milk", &info) => 0; +# assert(strcmp(info.name, "milk") == 0); +# lfs_unmount(&lfs) => 0; +#''' +# +## dot path test +#[cases.test_paths_dot] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "tea") => 0; +# lfs_mkdir(&lfs, "tea/hottea") => 0; +# lfs_mkdir(&lfs, "tea/warmtea") => 0; +# lfs_mkdir(&lfs, "tea/coldtea") => 0; +# +# struct lfs_info info; +# lfs_stat(&lfs, "./tea/hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "/./tea/hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "/././tea/hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "/./tea/./hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# +# lfs_mkdir(&lfs, "/./milk") => 0; +# lfs_stat(&lfs, "/./milk", &info) => 0; +# assert(strcmp(info.name, "milk") == 0); +# lfs_stat(&lfs, "milk", &info) => 0; +# assert(strcmp(info.name, "milk") == 0); +# lfs_unmount(&lfs) => 0; +#''' +# +## dot dot path test +#[cases.test_paths_dot_dot] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "tea") => 0; +# lfs_mkdir(&lfs, "tea/hottea") => 0; +# lfs_mkdir(&lfs, "tea/warmtea") => 0; +# lfs_mkdir(&lfs, "tea/coldtea") => 0; +# lfs_mkdir(&lfs, "coffee") => 0; +# lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; +# lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; +# lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; +# +# struct lfs_info info; +# lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "coffee/coldcoffee/../../tea/hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "coffee/../coffee/../tea/hottea", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# +# lfs_mkdir(&lfs, "coffee/../milk") => 0; +# lfs_stat(&lfs, "coffee/../milk", &info) => 0; +# strcmp(info.name, "milk") => 0; +# lfs_stat(&lfs, "milk", &info) => 0; +# strcmp(info.name, "milk") => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## trailing dot path test +#[cases.test_paths_trailing_dot] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "tea") => 0; +# lfs_mkdir(&lfs, "tea/hottea") => 0; +# lfs_mkdir(&lfs, "tea/warmtea") => 0; +# lfs_mkdir(&lfs, "tea/coldtea") => 0; +# +# struct lfs_info info; +# lfs_stat(&lfs, "tea/hottea/", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "tea/hottea/.", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "tea/hottea/./.", &info) => 0; +# assert(strcmp(info.name, "hottea") == 0); +# lfs_stat(&lfs, "tea/hottea/..", &info) => 0; +# assert(strcmp(info.name, "tea") == 0); +# lfs_stat(&lfs, "tea/hottea/../.", &info) => 0; +# assert(strcmp(info.name, "tea") == 0); +# lfs_unmount(&lfs) => 0; +#''' +# +## leading dot path test +#[cases.test_paths_leading_dot] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, ".milk") => 0; +# struct lfs_info info; +# lfs_stat(&lfs, ".milk", &info) => 0; +# strcmp(info.name, ".milk") => 0; +# lfs_stat(&lfs, "tea/.././.milk", &info) => 0; +# strcmp(info.name, ".milk") => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## root dot dot path test +#[cases.test_paths_root_dot_dot] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "tea") => 0; +# lfs_mkdir(&lfs, "tea/hottea") => 0; +# lfs_mkdir(&lfs, "tea/warmtea") => 0; +# lfs_mkdir(&lfs, "tea/coldtea") => 0; +# lfs_mkdir(&lfs, "coffee") => 0; +# lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; +# lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; +# lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; +# +# struct lfs_info info; +# lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; +# strcmp(info.name, "hottea") => 0; +# +# lfs_mkdir(&lfs, "coffee/../../../../../../milk") => 0; +# lfs_stat(&lfs, "coffee/../../../../../../milk", &info) => 0; +# strcmp(info.name, "milk") => 0; +# lfs_stat(&lfs, "milk", &info) => 0; +# strcmp(info.name, "milk") => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## invalid path tests +#[cases.test_paths_invalid] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg); +# lfs_mount(&lfs, cfg) => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "dirt", &info) => LFS_ERR_NOENT; +# lfs_stat(&lfs, "dirt/ground", &info) => LFS_ERR_NOENT; +# lfs_stat(&lfs, "dirt/ground/earth", &info) => LFS_ERR_NOENT; +# +# lfs_remove(&lfs, "dirt") => LFS_ERR_NOENT; +# lfs_remove(&lfs, "dirt/ground") => LFS_ERR_NOENT; +# lfs_remove(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; +# +# lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "dirt/ground", LFS_O_WRONLY | LFS_O_CREAT) +# => LFS_ERR_NOENT; +# lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; +# lfs_file_open(&lfs, &file, "dirt/ground/earth", LFS_O_WRONLY | LFS_O_CREAT) +# => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +## root operations +#[cases.test_paths_root] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "/", &info) => 0; +# assert(strcmp(info.name, "/") == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT) +# => LFS_ERR_ISDIR; +# +# lfs_remove(&lfs, "/") => LFS_ERR_INVAL; +# lfs_unmount(&lfs) => 0; +#''' +# +## root representations +#[cases.test_paths_root_reprs] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "/", &info) => 0; +# assert(strcmp(info.name, "/") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_stat(&lfs, "", &info) => 0; +# assert(strcmp(info.name, "/") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_stat(&lfs, ".", &info) => 0; +# assert(strcmp(info.name, "/") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_stat(&lfs, "..", &info) => 0; +# assert(strcmp(info.name, "/") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_stat(&lfs, "//", &info) => 0; +# assert(strcmp(info.name, "/") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_stat(&lfs, "./", &info) => 0; +# assert(strcmp(info.name, "/") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_unmount(&lfs) => 0; +#''' +# +## superblock conflict test +#[cases.test_paths_superblock_conflict] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# struct lfs_info info; +# lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; +# lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT; +# +# lfs_mkdir(&lfs, "littlefs") => 0; +# lfs_stat(&lfs, "littlefs", &info) => 0; +# assert(strcmp(info.name, "littlefs") == 0); +# assert(info.type == LFS_TYPE_DIR); +# lfs_remove(&lfs, "littlefs") => 0; +# lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; +# lfs_unmount(&lfs) => 0; +#''' +# +## max path test +#[cases.test_paths_max] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "coffee") => 0; +# lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; +# lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; +# lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; +# +# char path[1024]; +# memset(path, 'w', LFS_NAME_MAX+1); +# path[LFS_NAME_MAX+1] = '\0'; +# lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) +# => LFS_ERR_NAMETOOLONG; +# +# memcpy(path, "coffee/", strlen("coffee/")); +# memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX+1); +# path[strlen("coffee/")+LFS_NAME_MAX+1] = '\0'; +# lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; +# lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) +# => LFS_ERR_NAMETOOLONG; +# lfs_unmount(&lfs) => 0; +#''' +# +## really big path test +#[cases.test_paths_really_big] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "coffee") => 0; +# lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; +# lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; +# lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; +# +# char path[1024]; +# memset(path, 'w', LFS_NAME_MAX); +# path[LFS_NAME_MAX] = '\0'; +# lfs_mkdir(&lfs, path) => 0; +# lfs_remove(&lfs, path) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_remove(&lfs, path) => 0; +# +# memcpy(path, "coffee/", strlen("coffee/")); +# memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX); +# path[strlen("coffee/")+LFS_NAME_MAX] = '\0'; +# lfs_mkdir(&lfs, path) => 0; +# lfs_remove(&lfs, path) => 0; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_remove(&lfs, path) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# diff --git a/tests/test_powerloss.toml b/tests/test_powerloss.toml index 06f8661d..be07538b 100644 --- a/tests/test_powerloss.toml +++ b/tests/test_powerloss.toml @@ -1,182 +1,182 @@ -# There are already a number of tests that test general operations under -# power-loss (see the reentrant attribute). These tests are for explicitly -# testing specific corner cases. - -# only a revision count -[cases.test_powerloss_only_rev] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "notebook") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "notebook/paper", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - char buffer[256]; - strcpy(buffer, "hello"); - lfs_size_t size = strlen("hello"); - for (int i = 0; i < 5; i++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - lfs_file_sync(&lfs, &file) => 0; - } - lfs_file_close(&lfs, &file) => 0; - - char rbuffer[256]; - lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; - for (int i = 0; i < 5; i++) { - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(memcmp(rbuffer, buffer, size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // get pair/rev count - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "notebook") => 0; - lfs_block_t pair[2] = {dir.m.pair[0], dir.m.pair[1]}; - uint32_t rev = dir.m.rev; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - - // write just the revision count - uint8_t bbuffer[BLOCK_SIZE]; - cfg->read(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0; - - memcpy(bbuffer, &(uint32_t){lfs_tole32(rev+1)}, sizeof(uint32_t)); - - cfg->erase(cfg, pair[1]) => 0; - cfg->prog(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0; - - lfs_mount(&lfs, cfg) => 0; - - // can read? - lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; - for (int i = 0; i < 5; i++) { - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(memcmp(rbuffer, buffer, size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - - // can write? - lfs_file_open(&lfs, &file, "notebook/paper", - LFS_O_WRONLY | LFS_O_APPEND) => 0; - strcpy(buffer, "goodbye"); - size = strlen("goodbye"); - for (int i = 0; i < 5; i++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - lfs_file_sync(&lfs, &file) => 0; - } - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; - strcpy(buffer, "hello"); - size = strlen("hello"); - for (int i = 0; i < 5; i++) { - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(memcmp(rbuffer, buffer, size) == 0); - } - strcpy(buffer, "goodbye"); - size = strlen("goodbye"); - for (int i = 0; i < 5; i++) { - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(memcmp(rbuffer, buffer, size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' - -# partial prog, may not be byte in order! -[cases.test_powerloss_partial_prog] -if = "PROG_SIZE < BLOCK_SIZE" -defines.BYTE_OFF = ["0", "PROG_SIZE-1", "PROG_SIZE/2"] -defines.BYTE_VALUE = [0x33, 0xcc] -in = "lfs.c" -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_mkdir(&lfs, "notebook") => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "notebook/paper", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - char buffer[256]; - strcpy(buffer, "hello"); - lfs_size_t size = strlen("hello"); - for (int i = 0; i < 5; i++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - lfs_file_sync(&lfs, &file) => 0; - } - lfs_file_close(&lfs, &file) => 0; - - char rbuffer[256]; - lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; - for (int i = 0; i < 5; i++) { - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(memcmp(rbuffer, buffer, size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // imitate a partial prog, value should not matter, if littlefs - // doesn't notice the partial prog testbd will assert - - // get offset to next prog - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - lfs_dir_open(&lfs, &dir, "notebook") => 0; - lfs_block_t block = dir.m.pair[0]; - lfs_off_t off = dir.m.off; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; - - // tweak byte - uint8_t bbuffer[BLOCK_SIZE]; - cfg->read(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0; - - bbuffer[off + BYTE_OFF] = BYTE_VALUE; - - cfg->erase(cfg, block) => 0; - cfg->prog(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0; - - lfs_mount(&lfs, cfg) => 0; - - // can read? - lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; - for (int i = 0; i < 5; i++) { - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(memcmp(rbuffer, buffer, size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - - // can write? - lfs_file_open(&lfs, &file, "notebook/paper", - LFS_O_WRONLY | LFS_O_APPEND) => 0; - strcpy(buffer, "goodbye"); - size = strlen("goodbye"); - for (int i = 0; i < 5; i++) { - lfs_file_write(&lfs, &file, buffer, size) => size; - lfs_file_sync(&lfs, &file) => 0; - } - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; - strcpy(buffer, "hello"); - size = strlen("hello"); - for (int i = 0; i < 5; i++) { - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(memcmp(rbuffer, buffer, size) == 0); - } - strcpy(buffer, "goodbye"); - size = strlen("goodbye"); - for (int i = 0; i < 5; i++) { - lfs_file_read(&lfs, &file, rbuffer, size) => size; - assert(memcmp(rbuffer, buffer, size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' +## There are already a number of tests that test general operations under +## power-loss (see the reentrant attribute). These tests are for explicitly +## testing specific corner cases. +# +## only a revision count +#[cases.test_powerloss_only_rev] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "notebook") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "notebook/paper", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# char buffer[256]; +# strcpy(buffer, "hello"); +# lfs_size_t size = strlen("hello"); +# for (int i = 0; i < 5; i++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# lfs_file_sync(&lfs, &file) => 0; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# char rbuffer[256]; +# lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; +# for (int i = 0; i < 5; i++) { +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(memcmp(rbuffer, buffer, size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // get pair/rev count +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "notebook") => 0; +# lfs_block_t pair[2] = {dir.m.pair[0], dir.m.pair[1]}; +# uint32_t rev = dir.m.rev; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# +# // write just the revision count +# uint8_t bbuffer[BLOCK_SIZE]; +# cfg->read(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0; +# +# memcpy(bbuffer, &(uint32_t){lfs_tole32(rev+1)}, sizeof(uint32_t)); +# +# cfg->erase(cfg, pair[1]) => 0; +# cfg->prog(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# +# // can read? +# lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; +# for (int i = 0; i < 5; i++) { +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(memcmp(rbuffer, buffer, size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# +# // can write? +# lfs_file_open(&lfs, &file, "notebook/paper", +# LFS_O_WRONLY | LFS_O_APPEND) => 0; +# strcpy(buffer, "goodbye"); +# size = strlen("goodbye"); +# for (int i = 0; i < 5; i++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# lfs_file_sync(&lfs, &file) => 0; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; +# strcpy(buffer, "hello"); +# size = strlen("hello"); +# for (int i = 0; i < 5; i++) { +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(memcmp(rbuffer, buffer, size) == 0); +# } +# strcpy(buffer, "goodbye"); +# size = strlen("goodbye"); +# for (int i = 0; i < 5; i++) { +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(memcmp(rbuffer, buffer, size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' +# +## partial prog, may not be byte in order! +#[cases.test_powerloss_partial_prog] +#if = "PROG_SIZE < BLOCK_SIZE" +#defines.BYTE_OFF = ["0", "PROG_SIZE-1", "PROG_SIZE/2"] +#defines.BYTE_VALUE = [0x33, 0xcc] +#in = "lfs.c" +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_mkdir(&lfs, "notebook") => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "notebook/paper", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# char buffer[256]; +# strcpy(buffer, "hello"); +# lfs_size_t size = strlen("hello"); +# for (int i = 0; i < 5; i++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# lfs_file_sync(&lfs, &file) => 0; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# char rbuffer[256]; +# lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; +# for (int i = 0; i < 5; i++) { +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(memcmp(rbuffer, buffer, size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // imitate a partial prog, value should not matter, if littlefs +# // doesn't notice the partial prog testbd will assert +# +# // get offset to next prog +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# lfs_dir_open(&lfs, &dir, "notebook") => 0; +# lfs_block_t block = dir.m.pair[0]; +# lfs_off_t off = dir.m.off; +# lfs_dir_close(&lfs, &dir) => 0; +# lfs_unmount(&lfs) => 0; +# +# // tweak byte +# uint8_t bbuffer[BLOCK_SIZE]; +# cfg->read(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0; +# +# bbuffer[off + BYTE_OFF] = BYTE_VALUE; +# +# cfg->erase(cfg, block) => 0; +# cfg->prog(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# +# // can read? +# lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; +# for (int i = 0; i < 5; i++) { +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(memcmp(rbuffer, buffer, size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# +# // can write? +# lfs_file_open(&lfs, &file, "notebook/paper", +# LFS_O_WRONLY | LFS_O_APPEND) => 0; +# strcpy(buffer, "goodbye"); +# size = strlen("goodbye"); +# for (int i = 0; i < 5; i++) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# lfs_file_sync(&lfs, &file) => 0; +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; +# strcpy(buffer, "hello"); +# size = strlen("hello"); +# for (int i = 0; i < 5; i++) { +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(memcmp(rbuffer, buffer, size) == 0); +# } +# strcpy(buffer, "goodbye"); +# size = strlen("goodbye"); +# for (int i = 0; i < 5; i++) { +# lfs_file_read(&lfs, &file, rbuffer, size) => size; +# assert(memcmp(rbuffer, buffer, size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' diff --git a/tests/test_relocations.toml b/tests/test_relocations.toml index d20cb8cf..c83c8596 100644 --- a/tests/test_relocations.toml +++ b/tests/test_relocations.toml @@ -1,343 +1,343 @@ -# specific corner cases worth explicitly testing for -[cases.test_relocations_dangling_split_dir] -defines.ITERATIONS = 20 -defines.COUNT = 10 -defines.BLOCK_CYCLES = [8, 1] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - // fill up filesystem so only ~16 blocks are left - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; - uint8_t buffer[512]; - memset(buffer, 0, 512); - while (BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { - lfs_file_write(&lfs, &file, buffer, 512) => 512; - } - lfs_file_close(&lfs, &file) => 0; - // make a child dir to use in bounded space - lfs_mkdir(&lfs, "child") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (unsigned j = 0; j < ITERATIONS; j++) { - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); - lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; - lfs_file_close(&lfs, &file) => 0; - } - - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "child") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - lfs_dir_read(&lfs, &dir, &info) => 1; - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "test%03d_loooooooooooooooooong_name", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - strcmp(info.name, path) => 0; - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - if (j == (unsigned)ITERATIONS-1) { - break; - } - - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); - lfs_remove(&lfs, path) => 0; - } - } - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "child") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - lfs_dir_read(&lfs, &dir, &info) => 1; - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "test%03d_loooooooooooooooooong_name", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - strcmp(info.name, path) => 0; - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); - lfs_remove(&lfs, path) => 0; - } - lfs_unmount(&lfs) => 0; -''' - -[cases.test_relocations_outdated_head] -defines.ITERATIONS = 20 -defines.COUNT = 10 -defines.BLOCK_CYCLES = [8, 1] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - // fill up filesystem so only ~16 blocks are left - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; - uint8_t buffer[512]; - memset(buffer, 0, 512); - while (BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { - lfs_file_write(&lfs, &file, buffer, 512) => 512; - } - lfs_file_close(&lfs, &file) => 0; - // make a child dir to use in bounded space - lfs_mkdir(&lfs, "child") => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - for (unsigned j = 0; j < ITERATIONS; j++) { - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); - lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; - lfs_file_close(&lfs, &file) => 0; - } - - lfs_dir_t dir; - struct lfs_info info; - lfs_dir_open(&lfs, &dir, "child") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - lfs_dir_read(&lfs, &dir, &info) => 1; - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "test%03d_loooooooooooooooooong_name", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - strcmp(info.name, path) => 0; - info.size => 0; - - sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); - lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; - lfs_file_write(&lfs, &file, "hi", 2) => 2; - lfs_file_close(&lfs, &file) => 0; - } - lfs_dir_read(&lfs, &dir, &info) => 0; - - lfs_dir_rewind(&lfs, &dir) => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - lfs_dir_read(&lfs, &dir, &info) => 1; - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "test%03d_loooooooooooooooooong_name", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - strcmp(info.name, path) => 0; - info.size => 2; - - sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); - lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; - lfs_file_write(&lfs, &file, "hi", 2) => 2; - lfs_file_close(&lfs, &file) => 0; - } - lfs_dir_read(&lfs, &dir, &info) => 0; - - lfs_dir_rewind(&lfs, &dir) => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - lfs_dir_read(&lfs, &dir, &info) => 1; - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "test%03d_loooooooooooooooooong_name", i); - lfs_dir_read(&lfs, &dir, &info) => 1; - strcmp(info.name, path) => 0; - info.size => 2; - } - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); - lfs_remove(&lfs, path) => 0; - } - } - lfs_unmount(&lfs) => 0; -''' - -# reentrant testing for relocations, this is the same as the -# orphan testing, except here we also set block_cycles so that -# almost every tree operation needs a relocation -[cases.test_relocations_reentrant] -reentrant = true -# TODO fix this case, caused by non-DAG trees -# NOTE the second condition is required -if = '!(DEPTH == 3 && CACHE_SIZE != 64) && 2*FILES < BLOCK_COUNT' -defines = [ - {FILES=6, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, - {FILES=26, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, - {FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1}, -] -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - - uint32_t prng = 1; - const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; - for (unsigned i = 0; i < CYCLES; i++) { - // create random path - char full_path[256]; - for (unsigned d = 0; d < DEPTH; d++) { - sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); - } - - // if it does not exist, we create it, else we destroy - struct lfs_info info; - int res = lfs_stat(&lfs, full_path, &info); - if (res == LFS_ERR_NOENT) { - // create each directory in turn, ignore if dir already exists - for (unsigned d = 0; d < DEPTH; d++) { - char path[1024]; - strcpy(path, full_path); - path[2*d+2] = '\0'; - err = lfs_mkdir(&lfs, path); - assert(!err || err == LFS_ERR_EXIST); - } - - for (unsigned d = 0; d < DEPTH; d++) { - char path[1024]; - strcpy(path, full_path); - path[2*d+2] = '\0'; - lfs_stat(&lfs, path, &info) => 0; - assert(strcmp(info.name, &path[2*d+1]) == 0); - assert(info.type == LFS_TYPE_DIR); - } - } else { - // is valid dir? - assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); - assert(info.type == LFS_TYPE_DIR); - - // try to delete path in reverse order, ignore if dir is not empty - for (unsigned d = DEPTH-1; d+1 > 0; d--) { - char path[1024]; - strcpy(path, full_path); - path[2*d+2] = '\0'; - err = lfs_remove(&lfs, path); - assert(!err || err == LFS_ERR_NOTEMPTY); - } - - lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; - } - } - lfs_unmount(&lfs) => 0; -''' - -# reentrant testing for relocations, but now with random renames! -[cases.test_relocations_reentrant_renames] -reentrant = true -# TODO fix this case, caused by non-DAG trees -# NOTE the second condition is required -if = '!(DEPTH == 3 && CACHE_SIZE != 64) && 2*FILES < BLOCK_COUNT' -defines = [ - {FILES=6, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, - {FILES=26, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, - {FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1}, -] -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - - uint32_t prng = 1; - const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; - for (unsigned i = 0; i < CYCLES; i++) { - // create random path - char full_path[256]; - for (unsigned d = 0; d < DEPTH; d++) { - sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); - } - - // if it does not exist, we create it, else we destroy - struct lfs_info info; - int res = lfs_stat(&lfs, full_path, &info); - assert(!res || res == LFS_ERR_NOENT); - if (res == LFS_ERR_NOENT) { - // create each directory in turn, ignore if dir already exists - for (unsigned d = 0; d < DEPTH; d++) { - char path[1024]; - strcpy(path, full_path); - path[2*d+2] = '\0'; - err = lfs_mkdir(&lfs, path); - assert(!err || err == LFS_ERR_EXIST); - } - - for (unsigned d = 0; d < DEPTH; d++) { - char path[1024]; - strcpy(path, full_path); - path[2*d+2] = '\0'; - lfs_stat(&lfs, path, &info) => 0; - assert(strcmp(info.name, &path[2*d+1]) == 0); - assert(info.type == LFS_TYPE_DIR); - } - } else { - assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); - assert(info.type == LFS_TYPE_DIR); - - // create new random path - char new_path[256]; - for (unsigned d = 0; d < DEPTH; d++) { - sprintf(&new_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); - } - - // if new path does not exist, rename, otherwise destroy - res = lfs_stat(&lfs, new_path, &info); - assert(!res || res == LFS_ERR_NOENT); - if (res == LFS_ERR_NOENT) { - // stop once some dir is renamed - for (unsigned d = 0; d < DEPTH; d++) { - char path[1024]; - strcpy(&path[2*d], &full_path[2*d]); - path[2*d+2] = '\0'; - strcpy(&path[128+2*d], &new_path[2*d]); - path[128+2*d+2] = '\0'; - err = lfs_rename(&lfs, path, path+128); - assert(!err || err == LFS_ERR_NOTEMPTY); - if (!err) { - strcpy(path, path+128); - } - } - - for (unsigned d = 0; d < DEPTH; d++) { - char path[1024]; - strcpy(path, new_path); - path[2*d+2] = '\0'; - lfs_stat(&lfs, path, &info) => 0; - assert(strcmp(info.name, &path[2*d+1]) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; - } else { - // try to delete path in reverse order, - // ignore if dir is not empty - for (unsigned d = DEPTH-1; d+1 > 0; d--) { - char path[1024]; - strcpy(path, full_path); - path[2*d+2] = '\0'; - err = lfs_remove(&lfs, path); - assert(!err || err == LFS_ERR_NOTEMPTY); - } - - lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; - } - } - } - lfs_unmount(&lfs) => 0; -''' +## specific corner cases worth explicitly testing for +#[cases.test_relocations_dangling_split_dir] +#defines.ITERATIONS = 20 +#defines.COUNT = 10 +#defines.BLOCK_CYCLES = [8, 1] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# // fill up filesystem so only ~16 blocks are left +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; +# uint8_t buffer[512]; +# memset(buffer, 0, 512); +# while (BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { +# lfs_file_write(&lfs, &file, buffer, 512) => 512; +# } +# lfs_file_close(&lfs, &file) => 0; +# // make a child dir to use in bounded space +# lfs_mkdir(&lfs, "child") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (unsigned j = 0; j < ITERATIONS; j++) { +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); +# lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; +# lfs_file_close(&lfs, &file) => 0; +# } +# +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "child") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "test%03d_loooooooooooooooooong_name", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# strcmp(info.name, path) => 0; +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# if (j == (unsigned)ITERATIONS-1) { +# break; +# } +# +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); +# lfs_remove(&lfs, path) => 0; +# } +# } +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "child") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "test%03d_loooooooooooooooooong_name", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# strcmp(info.name, path) => 0; +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); +# lfs_remove(&lfs, path) => 0; +# } +# lfs_unmount(&lfs) => 0; +#''' +# +#[cases.test_relocations_outdated_head] +#defines.ITERATIONS = 20 +#defines.COUNT = 10 +#defines.BLOCK_CYCLES = [8, 1] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# // fill up filesystem so only ~16 blocks are left +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; +# uint8_t buffer[512]; +# memset(buffer, 0, 512); +# while (BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { +# lfs_file_write(&lfs, &file, buffer, 512) => 512; +# } +# lfs_file_close(&lfs, &file) => 0; +# // make a child dir to use in bounded space +# lfs_mkdir(&lfs, "child") => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# for (unsigned j = 0; j < ITERATIONS; j++) { +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); +# lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; +# lfs_file_close(&lfs, &file) => 0; +# } +# +# lfs_dir_t dir; +# struct lfs_info info; +# lfs_dir_open(&lfs, &dir, "child") => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "test%03d_loooooooooooooooooong_name", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# strcmp(info.name, path) => 0; +# info.size => 0; +# +# sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); +# lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; +# lfs_file_write(&lfs, &file, "hi", 2) => 2; +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# +# lfs_dir_rewind(&lfs, &dir) => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "test%03d_loooooooooooooooooong_name", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# strcmp(info.name, path) => 0; +# info.size => 2; +# +# sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); +# lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; +# lfs_file_write(&lfs, &file, "hi", 2) => 2; +# lfs_file_close(&lfs, &file) => 0; +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# +# lfs_dir_rewind(&lfs, &dir) => 0; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# lfs_dir_read(&lfs, &dir, &info) => 1; +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "test%03d_loooooooooooooooooong_name", i); +# lfs_dir_read(&lfs, &dir, &info) => 1; +# strcmp(info.name, path) => 0; +# info.size => 2; +# } +# lfs_dir_read(&lfs, &dir, &info) => 0; +# lfs_dir_close(&lfs, &dir) => 0; +# +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); +# lfs_remove(&lfs, path) => 0; +# } +# } +# lfs_unmount(&lfs) => 0; +#''' +# +## reentrant testing for relocations, this is the same as the +## orphan testing, except here we also set block_cycles so that +## almost every tree operation needs a relocation +#[cases.test_relocations_reentrant] +#reentrant = true +## TODO fix this case, caused by non-DAG trees +## NOTE the second condition is required +#if = '!(DEPTH == 3 && CACHE_SIZE != 64) && 2*FILES < BLOCK_COUNT' +#defines = [ +# {FILES=6, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, +# {FILES=26, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, +# {FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1}, +#] +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# +# uint32_t prng = 1; +# const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; +# for (unsigned i = 0; i < CYCLES; i++) { +# // create random path +# char full_path[256]; +# for (unsigned d = 0; d < DEPTH; d++) { +# sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); +# } +# +# // if it does not exist, we create it, else we destroy +# struct lfs_info info; +# int res = lfs_stat(&lfs, full_path, &info); +# if (res == LFS_ERR_NOENT) { +# // create each directory in turn, ignore if dir already exists +# for (unsigned d = 0; d < DEPTH; d++) { +# char path[1024]; +# strcpy(path, full_path); +# path[2*d+2] = '\0'; +# err = lfs_mkdir(&lfs, path); +# assert(!err || err == LFS_ERR_EXIST); +# } +# +# for (unsigned d = 0; d < DEPTH; d++) { +# char path[1024]; +# strcpy(path, full_path); +# path[2*d+2] = '\0'; +# lfs_stat(&lfs, path, &info) => 0; +# assert(strcmp(info.name, &path[2*d+1]) == 0); +# assert(info.type == LFS_TYPE_DIR); +# } +# } else { +# // is valid dir? +# assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# // try to delete path in reverse order, ignore if dir is not empty +# for (unsigned d = DEPTH-1; d+1 > 0; d--) { +# char path[1024]; +# strcpy(path, full_path); +# path[2*d+2] = '\0'; +# err = lfs_remove(&lfs, path); +# assert(!err || err == LFS_ERR_NOTEMPTY); +# } +# +# lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; +# } +# } +# lfs_unmount(&lfs) => 0; +#''' +# +## reentrant testing for relocations, but now with random renames! +#[cases.test_relocations_reentrant_renames] +#reentrant = true +## TODO fix this case, caused by non-DAG trees +## NOTE the second condition is required +#if = '!(DEPTH == 3 && CACHE_SIZE != 64) && 2*FILES < BLOCK_COUNT' +#defines = [ +# {FILES=6, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, +# {FILES=26, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, +# {FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1}, +#] +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# +# uint32_t prng = 1; +# const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; +# for (unsigned i = 0; i < CYCLES; i++) { +# // create random path +# char full_path[256]; +# for (unsigned d = 0; d < DEPTH; d++) { +# sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); +# } +# +# // if it does not exist, we create it, else we destroy +# struct lfs_info info; +# int res = lfs_stat(&lfs, full_path, &info); +# assert(!res || res == LFS_ERR_NOENT); +# if (res == LFS_ERR_NOENT) { +# // create each directory in turn, ignore if dir already exists +# for (unsigned d = 0; d < DEPTH; d++) { +# char path[1024]; +# strcpy(path, full_path); +# path[2*d+2] = '\0'; +# err = lfs_mkdir(&lfs, path); +# assert(!err || err == LFS_ERR_EXIST); +# } +# +# for (unsigned d = 0; d < DEPTH; d++) { +# char path[1024]; +# strcpy(path, full_path); +# path[2*d+2] = '\0'; +# lfs_stat(&lfs, path, &info) => 0; +# assert(strcmp(info.name, &path[2*d+1]) == 0); +# assert(info.type == LFS_TYPE_DIR); +# } +# } else { +# assert(strcmp(info.name, &full_path[2*(DEPTH-1)+1]) == 0); +# assert(info.type == LFS_TYPE_DIR); +# +# // create new random path +# char new_path[256]; +# for (unsigned d = 0; d < DEPTH; d++) { +# sprintf(&new_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); +# } +# +# // if new path does not exist, rename, otherwise destroy +# res = lfs_stat(&lfs, new_path, &info); +# assert(!res || res == LFS_ERR_NOENT); +# if (res == LFS_ERR_NOENT) { +# // stop once some dir is renamed +# for (unsigned d = 0; d < DEPTH; d++) { +# char path[1024]; +# strcpy(&path[2*d], &full_path[2*d]); +# path[2*d+2] = '\0'; +# strcpy(&path[128+2*d], &new_path[2*d]); +# path[128+2*d+2] = '\0'; +# err = lfs_rename(&lfs, path, path+128); +# assert(!err || err == LFS_ERR_NOTEMPTY); +# if (!err) { +# strcpy(path, path+128); +# } +# } +# +# for (unsigned d = 0; d < DEPTH; d++) { +# char path[1024]; +# strcpy(path, new_path); +# path[2*d+2] = '\0'; +# lfs_stat(&lfs, path, &info) => 0; +# assert(strcmp(info.name, &path[2*d+1]) == 0); +# assert(info.type == LFS_TYPE_DIR); +# } +# +# lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; +# } else { +# // try to delete path in reverse order, +# // ignore if dir is not empty +# for (unsigned d = DEPTH-1; d+1 > 0; d--) { +# char path[1024]; +# strcpy(path, full_path); +# path[2*d+2] = '\0'; +# err = lfs_remove(&lfs, path); +# assert(!err || err == LFS_ERR_NOTEMPTY); +# } +# +# lfs_stat(&lfs, full_path, &info) => LFS_ERR_NOENT; +# } +# } +# } +# lfs_unmount(&lfs) => 0; +#''' diff --git a/tests/test_seek.toml b/tests/test_seek.toml index b976057b..98f6c14d 100644 --- a/tests/test_seek.toml +++ b/tests/test_seek.toml @@ -1,403 +1,403 @@ - -# simple file seek -[cases.test_seek_read] -defines = [ - {COUNT=132, SKIP=4}, - {COUNT=132, SKIP=128}, - {COUNT=200, SKIP=10}, - {COUNT=200, SKIP=100}, - {COUNT=4, SKIP=1}, - {COUNT=4, SKIP=2}, -] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "kitty", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size_t size = strlen("kittycatcat"); - uint8_t buffer[1024]; - memcpy(buffer, "kittycatcat", size); - for (int j = 0; j < COUNT; j++) { - lfs_file_write(&lfs, &file, buffer, size); - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0; - - lfs_soff_t pos = -1; - size = strlen("kittycatcat"); - for (int i = 0; i < SKIP; i++) { - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - pos = lfs_file_tell(&lfs, &file); - } - assert(pos >= 0); - - lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - lfs_file_rewind(&lfs, &file) => 0; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - lfs_file_seek(&lfs, &file, size, LFS_SEEK_CUR) => 3*size; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - lfs_file_seek(&lfs, &file, -size, LFS_SEEK_CUR) => pos; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - size = lfs_file_size(&lfs, &file); - lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# simple file seek and write -[cases.test_seek_write] -defines = [ - {COUNT=132, SKIP=4}, - {COUNT=132, SKIP=128}, - {COUNT=200, SKIP=10}, - {COUNT=200, SKIP=100}, - {COUNT=4, SKIP=1}, - {COUNT=4, SKIP=2}, -] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "kitty", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size_t size = strlen("kittycatcat"); - uint8_t buffer[1024]; - memcpy(buffer, "kittycatcat", size); - for (int j = 0; j < COUNT; j++) { - lfs_file_write(&lfs, &file, buffer, size); - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; - - lfs_soff_t pos = -1; - size = strlen("kittycatcat"); - for (int i = 0; i < SKIP; i++) { - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - pos = lfs_file_tell(&lfs, &file); - } - assert(pos >= 0); - - memcpy(buffer, "doggodogdog", size); - lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; - lfs_file_write(&lfs, &file, buffer, size) => size; - - lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "doggodogdog", size) => 0; - - lfs_file_rewind(&lfs, &file) => 0; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "doggodogdog", size) => 0; - - lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - size = lfs_file_size(&lfs, &file); - lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# boundary seek and writes -[cases.test_seek_boundary_write] -defines.COUNT = 132 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "kitty", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size_t size = strlen("kittycatcat"); - uint8_t buffer[1024]; - memcpy(buffer, "kittycatcat", size); - for (int j = 0; j < COUNT; j++) { - lfs_file_write(&lfs, &file, buffer, size); - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; - - size = strlen("hedgehoghog"); - const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019, 1441}; - - for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { - lfs_soff_t off = offsets[i]; - memcpy(buffer, "hedgehoghog", size); - lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; - lfs_file_write(&lfs, &file, buffer, size) => size; - lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "hedgehoghog", size) => 0; - - lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "hedgehoghog", size) => 0; - - lfs_file_sync(&lfs, &file) => 0; - - lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "kittycatcat", size) => 0; - - lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "hedgehoghog", size) => 0; - } - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# out of bounds seek -[cases.test_seek_out_of_bounds] -defines = [ - {COUNT=132, SKIP=4}, - {COUNT=132, SKIP=128}, - {COUNT=200, SKIP=10}, - {COUNT=200, SKIP=100}, - {COUNT=4, SKIP=2}, - {COUNT=4, SKIP=3}, -] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "kitty", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size_t size = strlen("kittycatcat"); - uint8_t buffer[1024]; - memcpy(buffer, "kittycatcat", size); - for (int j = 0; j < COUNT; j++) { - lfs_file_write(&lfs, &file, buffer, size); - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; - - size = strlen("kittycatcat"); - lfs_file_size(&lfs, &file) => COUNT*size; - lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size, - LFS_SEEK_SET) => (COUNT+SKIP)*size; - lfs_file_read(&lfs, &file, buffer, size) => 0; - - memcpy(buffer, "porcupineee", size); - lfs_file_write(&lfs, &file, buffer, size) => size; - - lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size, - LFS_SEEK_SET) => (COUNT+SKIP)*size; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "porcupineee", size) => 0; - - lfs_file_seek(&lfs, &file, COUNT*size, - LFS_SEEK_SET) => COUNT*size; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0; - - lfs_file_seek(&lfs, &file, -((COUNT+SKIP)*size), - LFS_SEEK_CUR) => LFS_ERR_INVAL; - lfs_file_tell(&lfs, &file) => (COUNT+1)*size; - - lfs_file_seek(&lfs, &file, -((COUNT+2*SKIP)*size), - LFS_SEEK_END) => LFS_ERR_INVAL; - lfs_file_tell(&lfs, &file) => (COUNT+1)*size; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# inline write and seek -[cases.test_seek_inline_write] -defines.SIZE = [2, 4, 128, 132] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "tinykitty", - LFS_O_RDWR | LFS_O_CREAT) => 0; - int j = 0; - int k = 0; - - uint8_t buffer[1024]; - memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26); - for (unsigned i = 0; i < SIZE; i++) { - lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; - lfs_file_tell(&lfs, &file) => i+1; - lfs_file_size(&lfs, &file) => i+1; - } - - lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; - lfs_file_tell(&lfs, &file) => 0; - lfs_file_size(&lfs, &file) => SIZE; - for (unsigned i = 0; i < SIZE; i++) { - uint8_t c; - lfs_file_read(&lfs, &file, &c, 1) => 1; - c => buffer[k++ % 26]; - } - - lfs_file_sync(&lfs, &file) => 0; - lfs_file_tell(&lfs, &file) => SIZE; - lfs_file_size(&lfs, &file) => SIZE; - - lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; - for (unsigned i = 0; i < SIZE; i++) { - lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; - lfs_file_tell(&lfs, &file) => i+1; - lfs_file_size(&lfs, &file) => SIZE; - lfs_file_sync(&lfs, &file) => 0; - lfs_file_tell(&lfs, &file) => i+1; - lfs_file_size(&lfs, &file) => SIZE; - if (i < SIZE-2) { - uint8_t c[3]; - lfs_file_seek(&lfs, &file, -1, LFS_SEEK_CUR) => i; - lfs_file_read(&lfs, &file, &c, 3) => 3; - lfs_file_tell(&lfs, &file) => i+3; - lfs_file_size(&lfs, &file) => SIZE; - lfs_file_seek(&lfs, &file, i+1, LFS_SEEK_SET) => i+1; - lfs_file_tell(&lfs, &file) => i+1; - lfs_file_size(&lfs, &file) => SIZE; - } - } - - lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; - lfs_file_tell(&lfs, &file) => 0; - lfs_file_size(&lfs, &file) => SIZE; - for (unsigned i = 0; i < SIZE; i++) { - uint8_t c; - lfs_file_read(&lfs, &file, &c, 1) => 1; - c => buffer[k++ % 26]; - } - - lfs_file_sync(&lfs, &file) => 0; - lfs_file_tell(&lfs, &file) => SIZE; - lfs_file_size(&lfs, &file) => SIZE; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# file seek and write with power-loss -[cases.test_seek_reentrant_write] -# must be power-of-2 for quadratic probing to be exhaustive -defines.COUNT = [4, 64, 128] -reentrant = true -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - lfs_file_t file; - uint8_t buffer[1024]; - err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY); - assert(!err || err == LFS_ERR_NOENT); - if (!err) { - if (lfs_file_size(&lfs, &file) != 0) { - lfs_file_size(&lfs, &file) => 11*COUNT; - for (int j = 0; j < COUNT; j++) { - memset(buffer, 0, 11+1); - lfs_file_read(&lfs, &file, buffer, 11) => 11; - assert(memcmp(buffer, "kittycatcat", 11) == 0 || - memcmp(buffer, "doggodogdog", 11) == 0); - } - } - lfs_file_close(&lfs, &file) => 0; - } - - lfs_file_open(&lfs, &file, "kitty", LFS_O_WRONLY | LFS_O_CREAT) => 0; - if (lfs_file_size(&lfs, &file) == 0) { - for (int j = 0; j < COUNT; j++) { - strcpy((char*)buffer, "kittycatcat"); - size_t size = strlen((char*)buffer); - lfs_file_write(&lfs, &file, buffer, size) => size; - } - } - lfs_file_close(&lfs, &file) => 0; - - strcpy((char*)buffer, "doggodogdog"); - size_t size = strlen((char*)buffer); - - lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; - lfs_file_size(&lfs, &file) => COUNT*size; - // seek and write using quadratic probing to touch all - // 11-byte words in the file - lfs_off_t off = 0; - for (int j = 0; j < COUNT; j++) { - off = (5*off + 1) % COUNT; - lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; - lfs_file_read(&lfs, &file, buffer, size) => size; - assert(memcmp(buffer, "kittycatcat", size) == 0 || - memcmp(buffer, "doggodogdog", size) == 0); - if (memcmp(buffer, "doggodogdog", size) != 0) { - lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; - strcpy((char*)buffer, "doggodogdog"); - lfs_file_write(&lfs, &file, buffer, size) => size; - lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; - lfs_file_read(&lfs, &file, buffer, size) => size; - assert(memcmp(buffer, "doggodogdog", size) == 0); - lfs_file_sync(&lfs, &file) => 0; - lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; - lfs_file_read(&lfs, &file, buffer, size) => size; - assert(memcmp(buffer, "doggodogdog", size) == 0); - } - } - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; - lfs_file_size(&lfs, &file) => COUNT*size; - for (int j = 0; j < COUNT; j++) { - lfs_file_read(&lfs, &file, buffer, size) => size; - assert(memcmp(buffer, "doggodogdog", size) == 0); - } - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' +# +## simple file seek +#[cases.test_seek_read] +#defines = [ +# {COUNT=132, SKIP=4}, +# {COUNT=132, SKIP=128}, +# {COUNT=200, SKIP=10}, +# {COUNT=200, SKIP=100}, +# {COUNT=4, SKIP=1}, +# {COUNT=4, SKIP=2}, +#] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "kitty", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# size_t size = strlen("kittycatcat"); +# uint8_t buffer[1024]; +# memcpy(buffer, "kittycatcat", size); +# for (int j = 0; j < COUNT; j++) { +# lfs_file_write(&lfs, &file, buffer, size); +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0; +# +# lfs_soff_t pos = -1; +# size = strlen("kittycatcat"); +# for (int i = 0; i < SKIP; i++) { +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# pos = lfs_file_tell(&lfs, &file); +# } +# assert(pos >= 0); +# +# lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# lfs_file_rewind(&lfs, &file) => 0; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# lfs_file_seek(&lfs, &file, size, LFS_SEEK_CUR) => 3*size; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# lfs_file_seek(&lfs, &file, -size, LFS_SEEK_CUR) => pos; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# size = lfs_file_size(&lfs, &file); +# lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## simple file seek and write +#[cases.test_seek_write] +#defines = [ +# {COUNT=132, SKIP=4}, +# {COUNT=132, SKIP=128}, +# {COUNT=200, SKIP=10}, +# {COUNT=200, SKIP=100}, +# {COUNT=4, SKIP=1}, +# {COUNT=4, SKIP=2}, +#] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "kitty", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# size_t size = strlen("kittycatcat"); +# uint8_t buffer[1024]; +# memcpy(buffer, "kittycatcat", size); +# for (int j = 0; j < COUNT; j++) { +# lfs_file_write(&lfs, &file, buffer, size); +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; +# +# lfs_soff_t pos = -1; +# size = strlen("kittycatcat"); +# for (int i = 0; i < SKIP; i++) { +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# pos = lfs_file_tell(&lfs, &file); +# } +# assert(pos >= 0); +# +# memcpy(buffer, "doggodogdog", size); +# lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; +# lfs_file_write(&lfs, &file, buffer, size) => size; +# +# lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "doggodogdog", size) => 0; +# +# lfs_file_rewind(&lfs, &file) => 0; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "doggodogdog", size) => 0; +# +# lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# size = lfs_file_size(&lfs, &file); +# lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## boundary seek and writes +#[cases.test_seek_boundary_write] +#defines.COUNT = 132 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "kitty", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# size_t size = strlen("kittycatcat"); +# uint8_t buffer[1024]; +# memcpy(buffer, "kittycatcat", size); +# for (int j = 0; j < COUNT; j++) { +# lfs_file_write(&lfs, &file, buffer, size); +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; +# +# size = strlen("hedgehoghog"); +# const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019, 1441}; +# +# for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { +# lfs_soff_t off = offsets[i]; +# memcpy(buffer, "hedgehoghog", size); +# lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; +# lfs_file_write(&lfs, &file, buffer, size) => size; +# lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "hedgehoghog", size) => 0; +# +# lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "hedgehoghog", size) => 0; +# +# lfs_file_sync(&lfs, &file) => 0; +# +# lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "kittycatcat", size) => 0; +# +# lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "hedgehoghog", size) => 0; +# } +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## out of bounds seek +#[cases.test_seek_out_of_bounds] +#defines = [ +# {COUNT=132, SKIP=4}, +# {COUNT=132, SKIP=128}, +# {COUNT=200, SKIP=10}, +# {COUNT=200, SKIP=100}, +# {COUNT=4, SKIP=2}, +# {COUNT=4, SKIP=3}, +#] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "kitty", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; +# size_t size = strlen("kittycatcat"); +# uint8_t buffer[1024]; +# memcpy(buffer, "kittycatcat", size); +# for (int j = 0; j < COUNT; j++) { +# lfs_file_write(&lfs, &file, buffer, size); +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; +# +# size = strlen("kittycatcat"); +# lfs_file_size(&lfs, &file) => COUNT*size; +# lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size, +# LFS_SEEK_SET) => (COUNT+SKIP)*size; +# lfs_file_read(&lfs, &file, buffer, size) => 0; +# +# memcpy(buffer, "porcupineee", size); +# lfs_file_write(&lfs, &file, buffer, size) => size; +# +# lfs_file_seek(&lfs, &file, (COUNT+SKIP)*size, +# LFS_SEEK_SET) => (COUNT+SKIP)*size; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "porcupineee", size) => 0; +# +# lfs_file_seek(&lfs, &file, COUNT*size, +# LFS_SEEK_SET) => COUNT*size; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0; +# +# lfs_file_seek(&lfs, &file, -((COUNT+SKIP)*size), +# LFS_SEEK_CUR) => LFS_ERR_INVAL; +# lfs_file_tell(&lfs, &file) => (COUNT+1)*size; +# +# lfs_file_seek(&lfs, &file, -((COUNT+2*SKIP)*size), +# LFS_SEEK_END) => LFS_ERR_INVAL; +# lfs_file_tell(&lfs, &file) => (COUNT+1)*size; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## inline write and seek +#[cases.test_seek_inline_write] +#defines.SIZE = [2, 4, 128, 132] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "tinykitty", +# LFS_O_RDWR | LFS_O_CREAT) => 0; +# int j = 0; +# int k = 0; +# +# uint8_t buffer[1024]; +# memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26); +# for (unsigned i = 0; i < SIZE; i++) { +# lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; +# lfs_file_tell(&lfs, &file) => i+1; +# lfs_file_size(&lfs, &file) => i+1; +# } +# +# lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; +# lfs_file_tell(&lfs, &file) => 0; +# lfs_file_size(&lfs, &file) => SIZE; +# for (unsigned i = 0; i < SIZE; i++) { +# uint8_t c; +# lfs_file_read(&lfs, &file, &c, 1) => 1; +# c => buffer[k++ % 26]; +# } +# +# lfs_file_sync(&lfs, &file) => 0; +# lfs_file_tell(&lfs, &file) => SIZE; +# lfs_file_size(&lfs, &file) => SIZE; +# +# lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; +# for (unsigned i = 0; i < SIZE; i++) { +# lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; +# lfs_file_tell(&lfs, &file) => i+1; +# lfs_file_size(&lfs, &file) => SIZE; +# lfs_file_sync(&lfs, &file) => 0; +# lfs_file_tell(&lfs, &file) => i+1; +# lfs_file_size(&lfs, &file) => SIZE; +# if (i < SIZE-2) { +# uint8_t c[3]; +# lfs_file_seek(&lfs, &file, -1, LFS_SEEK_CUR) => i; +# lfs_file_read(&lfs, &file, &c, 3) => 3; +# lfs_file_tell(&lfs, &file) => i+3; +# lfs_file_size(&lfs, &file) => SIZE; +# lfs_file_seek(&lfs, &file, i+1, LFS_SEEK_SET) => i+1; +# lfs_file_tell(&lfs, &file) => i+1; +# lfs_file_size(&lfs, &file) => SIZE; +# } +# } +# +# lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; +# lfs_file_tell(&lfs, &file) => 0; +# lfs_file_size(&lfs, &file) => SIZE; +# for (unsigned i = 0; i < SIZE; i++) { +# uint8_t c; +# lfs_file_read(&lfs, &file, &c, 1) => 1; +# c => buffer[k++ % 26]; +# } +# +# lfs_file_sync(&lfs, &file) => 0; +# lfs_file_tell(&lfs, &file) => SIZE; +# lfs_file_size(&lfs, &file) => SIZE; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## file seek and write with power-loss +#[cases.test_seek_reentrant_write] +## must be power-of-2 for quadratic probing to be exhaustive +#defines.COUNT = [4, 64, 128] +#reentrant = true +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# lfs_file_t file; +# uint8_t buffer[1024]; +# err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY); +# assert(!err || err == LFS_ERR_NOENT); +# if (!err) { +# if (lfs_file_size(&lfs, &file) != 0) { +# lfs_file_size(&lfs, &file) => 11*COUNT; +# for (int j = 0; j < COUNT; j++) { +# memset(buffer, 0, 11+1); +# lfs_file_read(&lfs, &file, buffer, 11) => 11; +# assert(memcmp(buffer, "kittycatcat", 11) == 0 || +# memcmp(buffer, "doggodogdog", 11) == 0); +# } +# } +# lfs_file_close(&lfs, &file) => 0; +# } +# +# lfs_file_open(&lfs, &file, "kitty", LFS_O_WRONLY | LFS_O_CREAT) => 0; +# if (lfs_file_size(&lfs, &file) == 0) { +# for (int j = 0; j < COUNT; j++) { +# strcpy((char*)buffer, "kittycatcat"); +# size_t size = strlen((char*)buffer); +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# } +# lfs_file_close(&lfs, &file) => 0; +# +# strcpy((char*)buffer, "doggodogdog"); +# size_t size = strlen((char*)buffer); +# +# lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; +# lfs_file_size(&lfs, &file) => COUNT*size; +# // seek and write using quadratic probing to touch all +# // 11-byte words in the file +# lfs_off_t off = 0; +# for (int j = 0; j < COUNT; j++) { +# off = (5*off + 1) % COUNT; +# lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# assert(memcmp(buffer, "kittycatcat", size) == 0 || +# memcmp(buffer, "doggodogdog", size) == 0); +# if (memcmp(buffer, "doggodogdog", size) != 0) { +# lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; +# strcpy((char*)buffer, "doggodogdog"); +# lfs_file_write(&lfs, &file, buffer, size) => size; +# lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# assert(memcmp(buffer, "doggodogdog", size) == 0); +# lfs_file_sync(&lfs, &file) => 0; +# lfs_file_seek(&lfs, &file, off*size, LFS_SEEK_SET) => off*size; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# assert(memcmp(buffer, "doggodogdog", size) == 0); +# } +# } +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; +# lfs_file_size(&lfs, &file) => COUNT*size; +# for (int j = 0; j < COUNT; j++) { +# lfs_file_read(&lfs, &file, buffer, size) => size; +# assert(memcmp(buffer, "doggodogdog", size) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' diff --git a/tests/test_superblocks.toml b/tests/test_superblocks.toml index d9bde57a..95da01b9 100644 --- a/tests/test_superblocks.toml +++ b/tests/test_superblocks.toml @@ -1,77 +1,17 @@ -# simple format test -[cases.test_superblocks_format] -code = ''' - lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; -''' - -# simple mount/unmount test -[cases.test_superblocks_mount] -code = ''' - lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; - lfsr_unmount(&lfs) => 0; -''' - -# reentrant format -[cases.test_superblocks_reentrant_format] -reentrant = true -code = ''' - lfs_t lfs; - int err = lfsr_mount(&lfs, cfg); - if (err) { - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; - } - lfsr_unmount(&lfs) => 0; -''' - -# invalid mount -[cases.test_superblocks_invalid] -code = ''' - lfs_t lfs; - lfsr_mount(&lfs, cfg) => LFS_ERR_INVAL; -''' - -# superblock cycle detection -[cases.test_superblocks_cycle] -in = 'lfs.c' -code = ''' - // create a cycle - lfs_t lfs; - lfsr_format(&lfs, cfg) => 0; - lfsr_mount(&lfs, cfg) => 0; - uint8_t buf[LFSR_MPAIR_DSIZE]; - lfs_ssize_t d = lfsr_mpair_todisk(&lfs, - lfsr_mdir_mpair(&lfs.mroot), buf); - assert(d >= 0); - lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( - LFSR_ATTR(-1, MROOT, 0, buf, d))) => 0; - lfsr_unmount(&lfs) => 0; - - // now detect the cycle - lfsr_mount(&lfs, cfg) => LFS_ERR_CORRUPT; -''' - - - - - -## simple formatting test +## simple format test #[cases.test_superblocks_format] #code = ''' # lfs_t lfs; -# lfs_format(&lfs, cfg) => 0; +# lfsr_format(&lfs, cfg) => 0; #''' # -## mount/unmount +## simple mount/unmount test #[cases.test_superblocks_mount] #code = ''' # lfs_t lfs; -# lfs_format(&lfs, cfg) => 0; -# lfs_mount(&lfs, cfg) => 0; -# lfs_unmount(&lfs) => 0; +# lfsr_format(&lfs, cfg) => 0; +# lfsr_mount(&lfs, cfg) => 0; +# lfsr_unmount(&lfs) => 0; #''' # ## reentrant format @@ -79,133 +19,193 @@ code = ''' #reentrant = true #code = ''' # lfs_t lfs; -# int err = lfs_mount(&lfs, cfg); +# int err = lfsr_mount(&lfs, cfg); # if (err) { -# lfs_format(&lfs, cfg) => 0; -# lfs_mount(&lfs, cfg) => 0; +# lfsr_format(&lfs, cfg) => 0; +# lfsr_mount(&lfs, cfg) => 0; # } -# lfs_unmount(&lfs) => 0; +# lfsr_unmount(&lfs) => 0; #''' # ## invalid mount -#[cases.test_superblocks_invalid_mount] +#[cases.test_superblocks_invalid] #code = ''' # lfs_t lfs; -# lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; +# lfsr_mount(&lfs, cfg) => LFS_ERR_INVAL; #''' # -## expanding superblock -#[cases.test_superblocks_expand] -#defines.BLOCK_CYCLES = [32, 33, 1] -#defines.N = [10, 100, 1000] +## superblock cycle detection +#[cases.test_superblocks_cycle] +#in = 'lfs.c' #code = ''' +# // create a cycle # lfs_t lfs; -# lfs_format(&lfs, cfg) => 0; -# lfs_mount(&lfs, cfg) => 0; -# for (int i = 0; i < N; i++) { -# lfs_file_t file; -# lfs_file_open(&lfs, &file, "dummy", -# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; -# lfs_file_close(&lfs, &file) => 0; -# struct lfs_info info; -# lfs_stat(&lfs, "dummy", &info) => 0; -# assert(strcmp(info.name, "dummy") == 0); -# assert(info.type == LFS_TYPE_REG); -# lfs_remove(&lfs, "dummy") => 0; -# } -# lfs_unmount(&lfs) => 0; +# lfsr_format(&lfs, cfg) => 0; +# lfsr_mount(&lfs, cfg) => 0; +# uint8_t buf[LFSR_MPAIR_DSIZE]; +# lfs_ssize_t d = lfsr_mpair_todisk(&lfs, +# lfsr_mdir_mpair(&lfs.mroot), buf); +# assert(d >= 0); +# lfsr_mdir_commit(&lfs, &lfs.mroot, &(lfs_ssize_t){-1}, LFSR_ATTRS( +# LFSR_ATTR(-1, MROOT, 0, buf, d))) => 0; +# lfsr_unmount(&lfs) => 0; # -# // one last check after power-cycle -# lfs_mount(&lfs, cfg) => 0; -# lfs_file_t file; -# lfs_file_open(&lfs, &file, "dummy", -# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; -# lfs_file_close(&lfs, &file) => 0; -# struct lfs_info info; -# lfs_stat(&lfs, "dummy", &info) => 0; -# assert(strcmp(info.name, "dummy") == 0); -# assert(info.type == LFS_TYPE_REG); -# lfs_unmount(&lfs) => 0; +# // now detect the cycle +# lfsr_mount(&lfs, cfg) => LFS_ERR_CORRUPT; #''' # -## expanding superblock with power cycle -#[cases.test_superblocks_expand_power_cycle] -#defines.BLOCK_CYCLES = [32, 33, 1] -#defines.N = [10, 100, 1000] -#code = ''' -# lfs_t lfs; -# lfs_format(&lfs, cfg) => 0; -# for (int i = 0; i < N; i++) { -# lfs_mount(&lfs, cfg) => 0; -# // remove lingering dummy? -# struct lfs_info info; -# int err = lfs_stat(&lfs, "dummy", &info); -# assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); -# if (!err) { -# assert(strcmp(info.name, "dummy") == 0); -# assert(info.type == LFS_TYPE_REG); -# lfs_remove(&lfs, "dummy") => 0; -# } # -# lfs_file_t file; -# lfs_file_open(&lfs, &file, "dummy", -# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; -# lfs_file_close(&lfs, &file) => 0; -# lfs_stat(&lfs, "dummy", &info) => 0; -# assert(strcmp(info.name, "dummy") == 0); -# assert(info.type == LFS_TYPE_REG); -# lfs_unmount(&lfs) => 0; -# } # -# // one last check after power-cycle -# lfs_mount(&lfs, cfg) => 0; -# struct lfs_info info; -# lfs_stat(&lfs, "dummy", &info) => 0; -# assert(strcmp(info.name, "dummy") == 0); -# assert(info.type == LFS_TYPE_REG); -# lfs_unmount(&lfs) => 0; -#''' # -## reentrant expanding superblock -#[cases.test_superblocks_reentrant_expand] -#defines.BLOCK_CYCLES = [2, 1] -#defines.N = 24 -#reentrant = true -#code = ''' -# lfs_t lfs; -# int err = lfs_mount(&lfs, cfg); -# if (err) { -# lfs_format(&lfs, cfg) => 0; -# lfs_mount(&lfs, cfg) => 0; -# } # -# for (int i = 0; i < N; i++) { -# // remove lingering dummy? -# struct lfs_info info; -# err = lfs_stat(&lfs, "dummy", &info); -# assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); -# if (!err) { -# assert(strcmp(info.name, "dummy") == 0); -# assert(info.type == LFS_TYPE_REG); -# lfs_remove(&lfs, "dummy") => 0; -# } -# -# lfs_file_t file; -# lfs_file_open(&lfs, &file, "dummy", -# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; -# lfs_file_close(&lfs, &file) => 0; -# lfs_stat(&lfs, "dummy", &info) => 0; -# assert(strcmp(info.name, "dummy") == 0); -# assert(info.type == LFS_TYPE_REG); -# } -# -# lfs_unmount(&lfs) => 0; -# -# // one last check after power-cycle -# lfs_mount(&lfs, cfg) => 0; -# struct lfs_info info; -# lfs_stat(&lfs, "dummy", &info) => 0; -# assert(strcmp(info.name, "dummy") == 0); -# assert(info.type == LFS_TYPE_REG); -# lfs_unmount(&lfs) => 0; -#''' +### simple formatting test +##[cases.test_superblocks_format] +##code = ''' +## lfs_t lfs; +## lfs_format(&lfs, cfg) => 0; +##''' +## +### mount/unmount +##[cases.test_superblocks_mount] +##code = ''' +## lfs_t lfs; +## lfs_format(&lfs, cfg) => 0; +## lfs_mount(&lfs, cfg) => 0; +## lfs_unmount(&lfs) => 0; +##''' +## +### reentrant format +##[cases.test_superblocks_reentrant_format] +##reentrant = true +##code = ''' +## lfs_t lfs; +## int err = lfs_mount(&lfs, cfg); +## if (err) { +## lfs_format(&lfs, cfg) => 0; +## lfs_mount(&lfs, cfg) => 0; +## } +## lfs_unmount(&lfs) => 0; +##''' +## +### invalid mount +##[cases.test_superblocks_invalid_mount] +##code = ''' +## lfs_t lfs; +## lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; +##''' +## +### expanding superblock +##[cases.test_superblocks_expand] +##defines.BLOCK_CYCLES = [32, 33, 1] +##defines.N = [10, 100, 1000] +##code = ''' +## lfs_t lfs; +## lfs_format(&lfs, cfg) => 0; +## lfs_mount(&lfs, cfg) => 0; +## for (int i = 0; i < N; i++) { +## lfs_file_t file; +## lfs_file_open(&lfs, &file, "dummy", +## LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +## lfs_file_close(&lfs, &file) => 0; +## struct lfs_info info; +## lfs_stat(&lfs, "dummy", &info) => 0; +## assert(strcmp(info.name, "dummy") == 0); +## assert(info.type == LFS_TYPE_REG); +## lfs_remove(&lfs, "dummy") => 0; +## } +## lfs_unmount(&lfs) => 0; +## +## // one last check after power-cycle +## lfs_mount(&lfs, cfg) => 0; +## lfs_file_t file; +## lfs_file_open(&lfs, &file, "dummy", +## LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +## lfs_file_close(&lfs, &file) => 0; +## struct lfs_info info; +## lfs_stat(&lfs, "dummy", &info) => 0; +## assert(strcmp(info.name, "dummy") == 0); +## assert(info.type == LFS_TYPE_REG); +## lfs_unmount(&lfs) => 0; +##''' +## +### expanding superblock with power cycle +##[cases.test_superblocks_expand_power_cycle] +##defines.BLOCK_CYCLES = [32, 33, 1] +##defines.N = [10, 100, 1000] +##code = ''' +## lfs_t lfs; +## lfs_format(&lfs, cfg) => 0; +## for (int i = 0; i < N; i++) { +## lfs_mount(&lfs, cfg) => 0; +## // remove lingering dummy? +## struct lfs_info info; +## int err = lfs_stat(&lfs, "dummy", &info); +## assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); +## if (!err) { +## assert(strcmp(info.name, "dummy") == 0); +## assert(info.type == LFS_TYPE_REG); +## lfs_remove(&lfs, "dummy") => 0; +## } +## +## lfs_file_t file; +## lfs_file_open(&lfs, &file, "dummy", +## LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +## lfs_file_close(&lfs, &file) => 0; +## lfs_stat(&lfs, "dummy", &info) => 0; +## assert(strcmp(info.name, "dummy") == 0); +## assert(info.type == LFS_TYPE_REG); +## lfs_unmount(&lfs) => 0; +## } +## +## // one last check after power-cycle +## lfs_mount(&lfs, cfg) => 0; +## struct lfs_info info; +## lfs_stat(&lfs, "dummy", &info) => 0; +## assert(strcmp(info.name, "dummy") == 0); +## assert(info.type == LFS_TYPE_REG); +## lfs_unmount(&lfs) => 0; +##''' +## +### reentrant expanding superblock +##[cases.test_superblocks_reentrant_expand] +##defines.BLOCK_CYCLES = [2, 1] +##defines.N = 24 +##reentrant = true +##code = ''' +## lfs_t lfs; +## int err = lfs_mount(&lfs, cfg); +## if (err) { +## lfs_format(&lfs, cfg) => 0; +## lfs_mount(&lfs, cfg) => 0; +## } +## +## for (int i = 0; i < N; i++) { +## // remove lingering dummy? +## struct lfs_info info; +## err = lfs_stat(&lfs, "dummy", &info); +## assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); +## if (!err) { +## assert(strcmp(info.name, "dummy") == 0); +## assert(info.type == LFS_TYPE_REG); +## lfs_remove(&lfs, "dummy") => 0; +## } +## +## lfs_file_t file; +## lfs_file_open(&lfs, &file, "dummy", +## LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; +## lfs_file_close(&lfs, &file) => 0; +## lfs_stat(&lfs, "dummy", &info) => 0; +## assert(strcmp(info.name, "dummy") == 0); +## assert(info.type == LFS_TYPE_REG); +## } +## +## lfs_unmount(&lfs) => 0; +## +## // one last check after power-cycle +## lfs_mount(&lfs, cfg) => 0; +## struct lfs_info info; +## lfs_stat(&lfs, "dummy", &info) => 0; +## assert(strcmp(info.name, "dummy") == 0); +## assert(info.type == LFS_TYPE_REG); +## lfs_unmount(&lfs) => 0; +##''' diff --git a/tests/test_truncate.toml b/tests/test_truncate.toml index a0da50e8..7644a216 100644 --- a/tests/test_truncate.toml +++ b/tests/test_truncate.toml @@ -1,477 +1,477 @@ -# simple truncate -[cases.test_truncate_simple] -defines.MEDIUMSIZE = [32, 2048] -defines.LARGESIZE = 8192 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "baldynoop", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - - uint8_t buffer[1024]; - strcpy((char*)buffer, "hair"); - size_t size = strlen((char*)buffer); - for (lfs_off_t j = 0; j < LARGESIZE; j += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_size(&lfs, &file) => LARGESIZE; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; - lfs_file_size(&lfs, &file) => LARGESIZE; - - lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - - size = strlen("hair"); - for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "hair", size) => 0; - } - lfs_file_read(&lfs, &file, buffer, size) => 0; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# truncate and read -[cases.test_truncate_read] -defines.MEDIUMSIZE = [32, 2048] -defines.LARGESIZE = 8192 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "baldyread", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - - uint8_t buffer[1024]; - strcpy((char*)buffer, "hair"); - size_t size = strlen((char*)buffer); - for (lfs_off_t j = 0; j < LARGESIZE; j += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_size(&lfs, &file) => LARGESIZE; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0; - lfs_file_size(&lfs, &file) => LARGESIZE; - - lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - - size = strlen("hair"); - for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "hair", size) => 0; - } - lfs_file_read(&lfs, &file, buffer, size) => 0; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - - size = strlen("hair"); - for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "hair", size) => 0; - } - lfs_file_read(&lfs, &file, buffer, size) => 0; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# write, truncate, and read -[cases.test_truncate_write_read] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "sequence", - LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; - - uint8_t buffer[1024]; - size_t size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2); - lfs_size_t qsize = size / 4; - uint8_t *wb = buffer; - uint8_t *rb = buffer + size; - for (lfs_off_t j = 0; j < size; ++j) { - wb[j] = j; - } - - /* Spread sequence over size */ - lfs_file_write(&lfs, &file, wb, size) => size; - lfs_file_size(&lfs, &file) => size; - lfs_file_tell(&lfs, &file) => size; - - lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; - lfs_file_tell(&lfs, &file) => 0; - - /* Chop off the last quarter */ - lfs_size_t trunc = size - qsize; - lfs_file_truncate(&lfs, &file, trunc) => 0; - lfs_file_tell(&lfs, &file) => 0; - lfs_file_size(&lfs, &file) => trunc; - - /* Read should produce first 3/4 */ - lfs_file_read(&lfs, &file, rb, size) => trunc; - memcmp(rb, wb, trunc) => 0; - - /* Move to 1/4 */ - lfs_file_size(&lfs, &file) => trunc; - lfs_file_seek(&lfs, &file, qsize, LFS_SEEK_SET) => qsize; - lfs_file_tell(&lfs, &file) => qsize; - - /* Chop to 1/2 */ - trunc -= qsize; - lfs_file_truncate(&lfs, &file, trunc) => 0; - lfs_file_tell(&lfs, &file) => qsize; - lfs_file_size(&lfs, &file) => trunc; - - /* Read should produce second quarter */ - lfs_file_read(&lfs, &file, rb, size) => trunc - qsize; - memcmp(rb, wb + qsize, trunc - qsize) => 0; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# truncate and write -[cases.test_truncate_write] -defines.MEDIUMSIZE = [32, 2048] -defines.LARGESIZE = 8192 -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "baldywrite", - LFS_O_WRONLY | LFS_O_CREAT) => 0; - - uint8_t buffer[1024]; - strcpy((char*)buffer, "hair"); - size_t size = strlen((char*)buffer); - for (lfs_off_t j = 0; j < LARGESIZE; j += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_size(&lfs, &file) => LARGESIZE; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0; - lfs_file_size(&lfs, &file) => LARGESIZE; - - lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - - strcpy((char*)buffer, "bald"); - size = strlen((char*)buffer); - for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - - size = strlen("bald"); - for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "bald", size) => 0; - } - lfs_file_read(&lfs, &file, buffer, size) => 0; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' - -# truncate write under powerloss -[cases.test_truncate_reentrant_write] -defines.SMALLSIZE = [4, 512] -defines.MEDIUMSIZE = [32, 1024] -defines.LARGESIZE = 2048 -reentrant = true -code = ''' - lfs_t lfs; - int err = lfs_mount(&lfs, cfg); - if (err) { - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - } - lfs_file_t file; - err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY); - assert(!err || err == LFS_ERR_NOENT); - if (!err) { - size_t size = lfs_file_size(&lfs, &file); - assert(size == 0 || - size == (size_t)LARGESIZE || - size == (size_t)MEDIUMSIZE || - size == (size_t)SMALLSIZE); - for (lfs_off_t j = 0; j < size; j += 4) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, 4) => 4; - assert(memcmp(buffer, "hair", 4) == 0 || - memcmp(buffer, "bald", 4) == 0 || - memcmp(buffer, "comb", 4) == 0); - } - lfs_file_close(&lfs, &file) => 0; - } - - lfs_file_open(&lfs, &file, "baldy", - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - lfs_file_size(&lfs, &file) => 0; - uint8_t buffer[1024]; - strcpy((char*)buffer, "hair"); - size_t size = strlen((char*)buffer); - for (lfs_off_t j = 0; j < LARGESIZE; j += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_size(&lfs, &file) => LARGESIZE; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0; - lfs_file_size(&lfs, &file) => LARGESIZE; - lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - strcpy((char*)buffer, "bald"); - size = strlen((char*)buffer); - for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - lfs_file_close(&lfs, &file) => 0; - - lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0; - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - lfs_file_truncate(&lfs, &file, SMALLSIZE) => 0; - lfs_file_size(&lfs, &file) => SMALLSIZE; - strcpy((char*)buffer, "comb"); - size = strlen((char*)buffer); - for (lfs_off_t j = 0; j < SMALLSIZE; j += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_size(&lfs, &file) => SMALLSIZE; - lfs_file_close(&lfs, &file) => 0; - - lfs_unmount(&lfs) => 0; -''' - -# more aggressive general truncation tests -[cases.test_truncate_aggressive] -defines.CONFIG = 'range(6)' -defines.SMALLSIZE = 32 -defines.MEDIUMSIZE = 2048 -defines.LARGESIZE = 8192 -code = ''' - lfs_t lfs; - #define COUNT 5 - const struct { - lfs_off_t startsizes[COUNT]; - lfs_off_t startseeks[COUNT]; - lfs_off_t hotsizes[COUNT]; - lfs_off_t coldsizes[COUNT]; - } configs[] = { - // cold shrinking - {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - { 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}}, - // cold expanding - {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - { 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}}, - // warm shrinking truncate - {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - { 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}, - { 0, 0, 0, 0, 0}}, - // warm expanding truncate - {{ 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}, - { 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}, - {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}}, - // mid-file shrinking truncate - {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - { LARGESIZE, LARGESIZE, LARGESIZE, LARGESIZE, LARGESIZE}, - { 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}, - { 0, 0, 0, 0, 0}}, - // mid-file expanding truncate - {{ 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}, - { 0, 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE}, - {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, - {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}}, - }; - - const lfs_off_t *startsizes = configs[CONFIG].startsizes; - const lfs_off_t *startseeks = configs[CONFIG].startseeks; - const lfs_off_t *hotsizes = configs[CONFIG].hotsizes; - const lfs_off_t *coldsizes = configs[CONFIG].coldsizes; - - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "hairyhead%d", i); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, - LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; - - uint8_t buffer[1024]; - strcpy((char*)buffer, "hair"); - size_t size = strlen((char*)buffer); - for (lfs_off_t j = 0; j < startsizes[i]; j += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - } - lfs_file_size(&lfs, &file) => startsizes[i]; - - if (startseeks[i] != startsizes[i]) { - lfs_file_seek(&lfs, &file, - startseeks[i], LFS_SEEK_SET) => startseeks[i]; - } - - lfs_file_truncate(&lfs, &file, hotsizes[i]) => 0; - lfs_file_size(&lfs, &file) => hotsizes[i]; - - lfs_file_close(&lfs, &file) => 0; - } - - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "hairyhead%d", i); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0; - lfs_file_size(&lfs, &file) => hotsizes[i]; - - size_t size = strlen("hair"); - lfs_off_t j = 0; - for (; j < startsizes[i] && j < hotsizes[i]; j += size) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "hair", size) => 0; - } - - for (; j < hotsizes[i]; j += size) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "\0\0\0\0", size) => 0; - } - - lfs_file_truncate(&lfs, &file, coldsizes[i]) => 0; - lfs_file_size(&lfs, &file) => coldsizes[i]; - - lfs_file_close(&lfs, &file) => 0; - } - - lfs_unmount(&lfs) => 0; - - lfs_mount(&lfs, cfg) => 0; - - for (unsigned i = 0; i < COUNT; i++) { - char path[1024]; - sprintf(path, "hairyhead%d", i); - lfs_file_t file; - lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - lfs_file_size(&lfs, &file) => coldsizes[i]; - - size_t size = strlen("hair"); - lfs_off_t j = 0; - for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; - j += size) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "hair", size) => 0; - } - - for (; j < coldsizes[i]; j += size) { - uint8_t buffer[1024]; - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "\0\0\0\0", size) => 0; - } - - lfs_file_close(&lfs, &file) => 0; - } - - lfs_unmount(&lfs) => 0; -''' - -# noop truncate -[cases.test_truncate_nop] -defines.MEDIUMSIZE = [32, 2048] -code = ''' - lfs_t lfs; - lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, cfg) => 0; - lfs_file_t file; - lfs_file_open(&lfs, &file, "baldynoop", - LFS_O_RDWR | LFS_O_CREAT) => 0; - - uint8_t buffer[1024]; - strcpy((char*)buffer, "hair"); - size_t size = strlen((char*)buffer); - for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { - lfs_file_write(&lfs, &file, buffer, size) => size; - - // this truncate should do nothing - lfs_file_truncate(&lfs, &file, j+size) => 0; - } - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - - lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; - // should do nothing again - lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - - for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "hair", size) => 0; - } - lfs_file_read(&lfs, &file, buffer, size) => 0; - - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; - - // still there after reboot? - lfs_mount(&lfs, cfg) => 0; - lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; - lfs_file_size(&lfs, &file) => MEDIUMSIZE; - for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { - lfs_file_read(&lfs, &file, buffer, size) => size; - memcmp(buffer, "hair", size) => 0; - } - lfs_file_read(&lfs, &file, buffer, size) => 0; - lfs_file_close(&lfs, &file) => 0; - lfs_unmount(&lfs) => 0; -''' +## simple truncate +#[cases.test_truncate_simple] +#defines.MEDIUMSIZE = [32, 2048] +#defines.LARGESIZE = 8192 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "baldynoop", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# +# uint8_t buffer[1024]; +# strcpy((char*)buffer, "hair"); +# size_t size = strlen((char*)buffer); +# for (lfs_off_t j = 0; j < LARGESIZE; j += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_size(&lfs, &file) => LARGESIZE; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; +# lfs_file_size(&lfs, &file) => LARGESIZE; +# +# lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# +# size = strlen("hair"); +# for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "hair", size) => 0; +# } +# lfs_file_read(&lfs, &file, buffer, size) => 0; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## truncate and read +#[cases.test_truncate_read] +#defines.MEDIUMSIZE = [32, 2048] +#defines.LARGESIZE = 8192 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "baldyread", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# +# uint8_t buffer[1024]; +# strcpy((char*)buffer, "hair"); +# size_t size = strlen((char*)buffer); +# for (lfs_off_t j = 0; j < LARGESIZE; j += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_size(&lfs, &file) => LARGESIZE; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0; +# lfs_file_size(&lfs, &file) => LARGESIZE; +# +# lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# +# size = strlen("hair"); +# for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "hair", size) => 0; +# } +# lfs_file_read(&lfs, &file, buffer, size) => 0; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# +# size = strlen("hair"); +# for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "hair", size) => 0; +# } +# lfs_file_read(&lfs, &file, buffer, size) => 0; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## write, truncate, and read +#[cases.test_truncate_write_read] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "sequence", +# LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# +# uint8_t buffer[1024]; +# size_t size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2); +# lfs_size_t qsize = size / 4; +# uint8_t *wb = buffer; +# uint8_t *rb = buffer + size; +# for (lfs_off_t j = 0; j < size; ++j) { +# wb[j] = j; +# } +# +# /* Spread sequence over size */ +# lfs_file_write(&lfs, &file, wb, size) => size; +# lfs_file_size(&lfs, &file) => size; +# lfs_file_tell(&lfs, &file) => size; +# +# lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; +# lfs_file_tell(&lfs, &file) => 0; +# +# /* Chop off the last quarter */ +# lfs_size_t trunc = size - qsize; +# lfs_file_truncate(&lfs, &file, trunc) => 0; +# lfs_file_tell(&lfs, &file) => 0; +# lfs_file_size(&lfs, &file) => trunc; +# +# /* Read should produce first 3/4 */ +# lfs_file_read(&lfs, &file, rb, size) => trunc; +# memcmp(rb, wb, trunc) => 0; +# +# /* Move to 1/4 */ +# lfs_file_size(&lfs, &file) => trunc; +# lfs_file_seek(&lfs, &file, qsize, LFS_SEEK_SET) => qsize; +# lfs_file_tell(&lfs, &file) => qsize; +# +# /* Chop to 1/2 */ +# trunc -= qsize; +# lfs_file_truncate(&lfs, &file, trunc) => 0; +# lfs_file_tell(&lfs, &file) => qsize; +# lfs_file_size(&lfs, &file) => trunc; +# +# /* Read should produce second quarter */ +# lfs_file_read(&lfs, &file, rb, size) => trunc - qsize; +# memcmp(rb, wb + qsize, trunc - qsize) => 0; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## truncate and write +#[cases.test_truncate_write] +#defines.MEDIUMSIZE = [32, 2048] +#defines.LARGESIZE = 8192 +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "baldywrite", +# LFS_O_WRONLY | LFS_O_CREAT) => 0; +# +# uint8_t buffer[1024]; +# strcpy((char*)buffer, "hair"); +# size_t size = strlen((char*)buffer); +# for (lfs_off_t j = 0; j < LARGESIZE; j += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_size(&lfs, &file) => LARGESIZE; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0; +# lfs_file_size(&lfs, &file) => LARGESIZE; +# +# lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# +# strcpy((char*)buffer, "bald"); +# size = strlen((char*)buffer); +# for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# +# size = strlen("bald"); +# for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "bald", size) => 0; +# } +# lfs_file_read(&lfs, &file, buffer, size) => 0; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#''' +# +## truncate write under powerloss +#[cases.test_truncate_reentrant_write] +#defines.SMALLSIZE = [4, 512] +#defines.MEDIUMSIZE = [32, 1024] +#defines.LARGESIZE = 2048 +#reentrant = true +#code = ''' +# lfs_t lfs; +# int err = lfs_mount(&lfs, cfg); +# if (err) { +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# } +# lfs_file_t file; +# err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY); +# assert(!err || err == LFS_ERR_NOENT); +# if (!err) { +# size_t size = lfs_file_size(&lfs, &file); +# assert(size == 0 || +# size == (size_t)LARGESIZE || +# size == (size_t)MEDIUMSIZE || +# size == (size_t)SMALLSIZE); +# for (lfs_off_t j = 0; j < size; j += 4) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, 4) => 4; +# assert(memcmp(buffer, "hair", 4) == 0 || +# memcmp(buffer, "bald", 4) == 0 || +# memcmp(buffer, "comb", 4) == 0); +# } +# lfs_file_close(&lfs, &file) => 0; +# } +# +# lfs_file_open(&lfs, &file, "baldy", +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# lfs_file_size(&lfs, &file) => 0; +# uint8_t buffer[1024]; +# strcpy((char*)buffer, "hair"); +# size_t size = strlen((char*)buffer); +# for (lfs_off_t j = 0; j < LARGESIZE; j += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_size(&lfs, &file) => LARGESIZE; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0; +# lfs_file_size(&lfs, &file) => LARGESIZE; +# lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# strcpy((char*)buffer, "bald"); +# size = strlen((char*)buffer); +# for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_file_open(&lfs, &file, "baldy", LFS_O_RDWR) => 0; +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# lfs_file_truncate(&lfs, &file, SMALLSIZE) => 0; +# lfs_file_size(&lfs, &file) => SMALLSIZE; +# strcpy((char*)buffer, "comb"); +# size = strlen((char*)buffer); +# for (lfs_off_t j = 0; j < SMALLSIZE; j += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_size(&lfs, &file) => SMALLSIZE; +# lfs_file_close(&lfs, &file) => 0; +# +# lfs_unmount(&lfs) => 0; +#''' +# +## more aggressive general truncation tests +#[cases.test_truncate_aggressive] +#defines.CONFIG = 'range(6)' +#defines.SMALLSIZE = 32 +#defines.MEDIUMSIZE = 2048 +#defines.LARGESIZE = 8192 +#code = ''' +# lfs_t lfs; +# #define COUNT 5 +# const struct { +# lfs_off_t startsizes[COUNT]; +# lfs_off_t startseeks[COUNT]; +# lfs_off_t hotsizes[COUNT]; +# lfs_off_t coldsizes[COUNT]; +# } configs[] = { +# // cold shrinking +# {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# { 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}}, +# // cold expanding +# {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# { 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}}, +# // warm shrinking truncate +# {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# { 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}, +# { 0, 0, 0, 0, 0}}, +# // warm expanding truncate +# {{ 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}, +# { 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}, +# {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}}, +# // mid-file shrinking truncate +# {{2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# { LARGESIZE, LARGESIZE, LARGESIZE, LARGESIZE, LARGESIZE}, +# { 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}, +# { 0, 0, 0, 0, 0}}, +# // mid-file expanding truncate +# {{ 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE, 2*LARGESIZE}, +# { 0, 0, SMALLSIZE, MEDIUMSIZE, LARGESIZE}, +# {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}, +# {2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE, 2*LARGESIZE}}, +# }; +# +# const lfs_off_t *startsizes = configs[CONFIG].startsizes; +# const lfs_off_t *startseeks = configs[CONFIG].startseeks; +# const lfs_off_t *hotsizes = configs[CONFIG].hotsizes; +# const lfs_off_t *coldsizes = configs[CONFIG].coldsizes; +# +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "hairyhead%d", i); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, +# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; +# +# uint8_t buffer[1024]; +# strcpy((char*)buffer, "hair"); +# size_t size = strlen((char*)buffer); +# for (lfs_off_t j = 0; j < startsizes[i]; j += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# } +# lfs_file_size(&lfs, &file) => startsizes[i]; +# +# if (startseeks[i] != startsizes[i]) { +# lfs_file_seek(&lfs, &file, +# startseeks[i], LFS_SEEK_SET) => startseeks[i]; +# } +# +# lfs_file_truncate(&lfs, &file, hotsizes[i]) => 0; +# lfs_file_size(&lfs, &file) => hotsizes[i]; +# +# lfs_file_close(&lfs, &file) => 0; +# } +# +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "hairyhead%d", i); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0; +# lfs_file_size(&lfs, &file) => hotsizes[i]; +# +# size_t size = strlen("hair"); +# lfs_off_t j = 0; +# for (; j < startsizes[i] && j < hotsizes[i]; j += size) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "hair", size) => 0; +# } +# +# for (; j < hotsizes[i]; j += size) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "\0\0\0\0", size) => 0; +# } +# +# lfs_file_truncate(&lfs, &file, coldsizes[i]) => 0; +# lfs_file_size(&lfs, &file) => coldsizes[i]; +# +# lfs_file_close(&lfs, &file) => 0; +# } +# +# lfs_unmount(&lfs) => 0; +# +# lfs_mount(&lfs, cfg) => 0; +# +# for (unsigned i = 0; i < COUNT; i++) { +# char path[1024]; +# sprintf(path, "hairyhead%d", i); +# lfs_file_t file; +# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; +# lfs_file_size(&lfs, &file) => coldsizes[i]; +# +# size_t size = strlen("hair"); +# lfs_off_t j = 0; +# for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; +# j += size) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "hair", size) => 0; +# } +# +# for (; j < coldsizes[i]; j += size) { +# uint8_t buffer[1024]; +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "\0\0\0\0", size) => 0; +# } +# +# lfs_file_close(&lfs, &file) => 0; +# } +# +# lfs_unmount(&lfs) => 0; +#''' +# +## noop truncate +#[cases.test_truncate_nop] +#defines.MEDIUMSIZE = [32, 2048] +#code = ''' +# lfs_t lfs; +# lfs_format(&lfs, cfg) => 0; +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_t file; +# lfs_file_open(&lfs, &file, "baldynoop", +# LFS_O_RDWR | LFS_O_CREAT) => 0; +# +# uint8_t buffer[1024]; +# strcpy((char*)buffer, "hair"); +# size_t size = strlen((char*)buffer); +# for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { +# lfs_file_write(&lfs, &file, buffer, size) => size; +# +# // this truncate should do nothing +# lfs_file_truncate(&lfs, &file, j+size) => 0; +# } +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# +# lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; +# // should do nothing again +# lfs_file_truncate(&lfs, &file, MEDIUMSIZE) => 0; +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# +# for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "hair", size) => 0; +# } +# lfs_file_read(&lfs, &file, buffer, size) => 0; +# +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +# +# // still there after reboot? +# lfs_mount(&lfs, cfg) => 0; +# lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; +# lfs_file_size(&lfs, &file) => MEDIUMSIZE; +# for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { +# lfs_file_read(&lfs, &file, buffer, size) => size; +# memcmp(buffer, "hair", size) => 0; +# } +# lfs_file_read(&lfs, &file, buffer, size) => 0; +# lfs_file_close(&lfs, &file) => 0; +# lfs_unmount(&lfs) => 0; +#'''