From cebf7aa0fec09c04a4b9b2ddacec50809269e37d Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 1 Jul 2018 22:29:42 -0500 Subject: [PATCH] Switched back to simple deorphan-step on directory remove Originally I tried to reuse the indirect delete to accomplish truely atomic directory removes, however this fell apart when it came to implementing directory removes as a side-effect of renames. A single indirect-delete simply can't handle renames with removes as a side effects. When copying an entry to its destination, we need to atomically delete both the old entry, and the source of our copy. We can't delete both with only a single indirect-delete. It is possible to accomplish this with two indirect-deletes, but this is such an uncommon case that it's really not worth supporting efficiently due to how expensive globals are. I also dropped indirect-deletes for normal directory removes. I may add it back later, but at the moment it's extra code cost for that's not traveled very often. As a result, restructured the indirect delete handling to be a bit more generic, now with a multipurpose lfs_globals_t struct instead of the delete specific lfs_entry_t struct. Also worked on integrating xored-globals, now with several primitive global operations to manage fetching/updating globals on disk. --- lfs.c | 362 ++++++++++++++++++++++++++++++++++----------- lfs.h | 23 ++- tests/test_move.sh | 32 +++- 3 files changed, 322 insertions(+), 95 deletions(-) diff --git a/lfs.c b/lfs.c index 8386238dd55..6680e0eab91 100644 --- a/lfs.c +++ b/lfs.c @@ -267,6 +267,8 @@ static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2], static int lfs_moved(lfs_t *lfs, lfs_mdir_t *fromdir, uint16_t fromid); static int lfs_relocate(lfs_t *lfs, const lfs_block_t oldpair[2], const lfs_block_t newpair[2]); +int lfs_scan(lfs_t *lfs); +int lfs_fixmove(lfs_t *lfs); int lfs_deorphan(lfs_t *lfs); @@ -458,6 +460,22 @@ static inline lfs_size_t lfs_tag_size(lfs_tag_t tag) { return tag & 0x00000fff; } +// operations on globals +static lfs_globals_t lfs_globals_xor( + const lfs_globals_t *a, const lfs_globals_t *b) { + lfs_globals_t res; + res.move.pair[0] = a->move.pair[0] ^ b->move.pair[0]; + res.move.pair[1] = a->move.pair[1] ^ b->move.pair[1]; + res.move.id = a->move.id ^ b->move.id; + return res; +} + +static bool lfs_globals_iszero(const lfs_globals_t *a) { + return (a->move.pair[0] == 0 && a->move.pair[1] == 0 && a->move.id == 0); +} + + +// commit logic struct lfs_commit { lfs_block_t block; lfs_off_t off; @@ -701,6 +719,23 @@ static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit, return 0; } +static int lfs_commit_globals(lfs_t *lfs, struct lfs_commit *commit, + const lfs_globals_t *source, const lfs_globals_t *diff) { + lfs_globals_t res = lfs_globals_xor(source, diff); + + if (!lfs_globals_iszero(&res)) { + int err = lfs_commit_commit(lfs, commit, (lfs_mattr_t){ + lfs_mktag(LFS_TYPE_IDELETE, + res.move.id, sizeof(res.move.pair)), + .u.buffer=res.move.pair}); + if (err) { + return err; + } + } + + return 0; +} + static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir, bool split, const lfs_block_t tail[2]) { // allocate pair of dir blocks (backwards, so we write to block 1 first) @@ -727,7 +762,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir, dir->tail[1] = tail[1]; dir->erased = false; dir->split = split; - dir->idelete = (lfs_entry_t){{0, 0}, 0}; + dir->globals = (lfs_globals_t){0}; // don't write out yet, let caller take care of that return 0; @@ -764,7 +799,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs, dir->tail[1] = 0xffffffff; dir->count = 0; dir->split = false; - dir->idelete = (lfs_entry_t){{0, 0}, 0}; + dir->globals = (lfs_globals_t){0}; dir->moveid = -1; dir->rev = lfs_tole32(rev[0]); @@ -786,9 +821,12 @@ static int lfs_dir_fetchwith(lfs_t *lfs, // next commit not yet programmed if (lfs_tag_type(ptag) == LFS_TYPE_CRC && !lfs_tag_valid(tag)) { - if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0 && cb) { + // synthetic move + if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0 + && cb) { int err = cb(lfs, data, (lfs_mattr_t){ - lfs_mktag(LFS_STRUCT_DELETE, lfs->idelete.id, 0)}); + lfs_mktag(LFS_STRUCT_DELETE, + lfs->globals.move.id, 0)}); if (err) { return err; } @@ -818,12 +856,13 @@ static int lfs_dir_fetchwith(lfs_t *lfs, // try other block break; } else { + // snythetic move // TODO combine with above? - if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0 + if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0 && cb) { int err = cb(lfs, data, (lfs_mattr_t){ lfs_mktag(LFS_STRUCT_DELETE, - lfs->idelete.id, 0)}); + lfs->globals.move.id, 0)}); if (err) { return err; } @@ -855,8 +894,10 @@ static int lfs_dir_fetchwith(lfs_t *lfs, return err; } } else if (lfs_tag_type(tag) == LFS_TYPE_IDELETE) { + temp.globals.move.id = lfs_tag_id(tag); err = lfs_bd_read(lfs, temp.pair[0], off+sizeof(tag), - &temp.idelete, sizeof(temp.idelete)); + &temp.globals.move.pair, + sizeof(temp.globals.move.pair)); if (err) { return err; } @@ -864,7 +905,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs, // TODO handle moves correctly? temp.moveid = lfs_tag_id(tag); } else { - if (lfs_tag_id(tag) < 0x3ff && + if (lfs_tag_scope(tag) <= LFS_SCOPE_ENTRY && lfs_tag_id(tag) >= temp.count) { temp.count = lfs_tag_id(tag)+1; } @@ -918,9 +959,10 @@ static int lfs_dir_traverse(lfs_t *lfs, lfs_mdir_t *dir, lfs_off_t off = dir->off; lfs_tag_t tag = dir->etag; - if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0) { + // synthetic move + if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0) { int err = cb(lfs, data, (lfs_mattr_t){ - lfs_mktag(LFS_STRUCT_DELETE, lfs->idelete.id, 0)}); + lfs_mktag(LFS_STRUCT_DELETE, lfs->globals.move.id, 0)}); if (err) { return err; } @@ -1031,29 +1073,29 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list, ack = id; } + // reopen the reserved space at the end + // TODO can I just commit these first? commit.end = lfs->cfg->block_size - 2*sizeof(uint32_t); - if (!lfs_pairisnull(dir->tail)) { - // TODO le32 - err = lfs_commit_commit(lfs, &commit, (lfs_mattr_t){ - lfs_mktag(LFS_STRUCT_TAIL + dir->split*0x8, - 0x3ff, sizeof(dir->tail)), - .u.buffer=dir->tail}); + + if (!relocated) { + err = lfs_commit_globals(lfs, &commit, + &dir->globals, &lfs->diff); if (err) { - if (err == LFS_ERR_CORRUPT) { + if (err == LFS_ERR_NOSPC) { + goto split; + } else if (err == LFS_ERR_CORRUPT) { goto relocate; } return err; } } - if (!(dir->idelete.pair[0] == 0 && - dir->idelete.pair[0] == 0 && - dir->idelete.id == 0)) { + if (!lfs_pairisnull(dir->tail)) { // TODO le32 err = lfs_commit_commit(lfs, &commit, (lfs_mattr_t){ - lfs_mktag(LFS_TYPE_IDELETE, - 0x3ff, sizeof(dir->idelete)), - .u.buffer=&dir->idelete}); + lfs_mktag(LFS_STRUCT_TAIL + dir->split*0x8, + 0x3ff, sizeof(dir->tail)), + .u.buffer=dir->tail}); if (err) { if (err == LFS_ERR_CORRUPT) { goto relocate; @@ -1131,6 +1173,9 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list, if (err) { return err; } + } else { + lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff); + lfs->diff = (lfs_globals_t){0}; } return 0; @@ -1162,6 +1207,16 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list) { return err; } + if (!lfs_globals_iszero(&lfs->diff)) { + err = lfs_commit_globals(lfs, &commit, &dir->globals, &lfs->diff); + if (err) { + if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { + goto compact; + } + return err; + } + } + err = lfs_commit_crc(lfs, &commit); if (err) { if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { @@ -1173,6 +1228,8 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list) { // successful commit, lets update dir dir->off = commit.off; dir->etag = commit.ptag; + lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff); + lfs->diff = (lfs_globals_t){0}; break; compact: @@ -1212,9 +1269,13 @@ static int lfs_dir_delete(lfs_t *lfs, lfs_mdir_t *dir, uint16_t id) { } if (res && pdir.split) { + // steal tail, and global state pdir.split = dir->split; pdir.tail[0] = dir->tail[0]; pdir.tail[1] = dir->tail[1]; + lfs->diff = dir->globals; + lfs->globals = lfs_globals_xor(&lfs->globals, &dir->globals); + int err = lfs_dir_commit(lfs, &pdir, &(lfs_mattrlist_t){ {lfs_mktag(LFS_STRUCT_TAIL + pdir.split*0x8, 0x3ff, sizeof(pdir.tail)), @@ -2661,17 +2722,50 @@ int lfs_remove(lfs_t *lfs, const char *path) { return err; } + lfs_mdir_t dir; if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) { - lfs_mdir_t dir; // must be empty before removal err = lfs_dir_fetch(lfs, &dir, attr.u.pair); if (err) { return err; } + // TODO lfs_dir_empty? if (dir.count > 0 || dir.split) { return LFS_ERR_NOTEMPTY; } +// +// // unlink from tail chain and create move to fix +// lfs->diff.move.pair[0] = cwd.pair[0] ^ lfs->globals.move.pair[0]; +// lfs->diff.move.pair[1] = cwd.pair[1] ^ lfs->globals.move.pair[1]; +// lfs->diff.move.id = id ^ lfs->globals.move.id; +// +// // xor over our child's global state +// lfs->diff = lfs_globals_xor(&lfs->diff, &dir.globals); +// lfs->globals = lfs_globals_xor(&lfs->globals, &dir.globals); +// +// // find pred and remove +// // TODO handle dropped block? +// lfs_mdir_t pred; +// int res = lfs_pred(lfs, dir.pair, &pred); +// if (res < 0) { +// return res; +// } +// +// LFS_ASSERT(res); // must have pred +// pred.tail[0] = dir.tail[0]; +// pred.tail[1] = dir.tail[1]; +// err = lfs_dir_commit(lfs, &pred, &(lfs_mattrlist_t){ +// {lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(pred.tail)), +// .u.buffer=pred.tail}}); +// if (err) { +// return err; +// } +// +// // mark global state to clear move entry +// lfs->diff.move.pair[0] = 0xffffffff ^ lfs->globals.move.pair[0]; +// lfs->diff.move.pair[1] = 0xffffffff ^ lfs->globals.move.pair[1]; +// lfs->diff.move.id = 0x3ff ^ lfs->globals.move.id; } // delete the entry @@ -2680,31 +2774,28 @@ int lfs_remove(lfs_t *lfs, const char *path) { return err; } - // if we were a directory, find pred, replace tail - // TODO can this just deorphan? - if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) { - err = lfs_deorphan(lfs); - if (err) { - return err; - } - } - +// // if we were a directory, fix the move we just created // if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) { -// int res = lfs_pred(lfs, dir.pair, &cwd); -// if (res < 0) { -// return res; -// } -// -// LFS_ASSERT(res); // must have pred -// cwd.tail[0] = dir.tail[0]; -// cwd.tail[1] = dir.tail[1]; -// -// err = lfs_dir_commit(lfs, &cwd, NULL, 0); +// err = lfs_deorphan(lfs); // if (err) { // return err; // } // } + if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) { + int res = lfs_pred(lfs, dir.pair, &cwd); + if (res < 0) { + return res; + } + + LFS_ASSERT(res); // must have pred + cwd.tail[0] = dir.tail[0]; + cwd.tail[1] = dir.tail[1]; + err = lfs_dir_commit(lfs, &cwd, &(lfs_mattrlist_t){ + {lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(cwd.tail)), + .u.buffer=cwd.tail}}); + } + return 0; } @@ -2741,8 +2832,10 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { } bool prevexists = (err != LFS_ERR_NOENT); - bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0); + //bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0); + lfs_mattr_t prevattr; + lfs_mdir_t prevdir; if (prevexists) { // get prev entry, check that we have same type err = lfs_dir_getentry(lfs, &newcwd, 0x703ff000, @@ -2756,7 +2849,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { } if (lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) { - lfs_mdir_t prevdir; // must be empty before removal err = lfs_dir_fetch(lfs, &prevdir, prevattr.u.pair); if (err) { @@ -2781,19 +2873,24 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { } } - // mark as moving - //printf("RENAME MOVE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid); - err = lfs_dir_commit(lfs, &oldcwd, &(lfs_mattrlist_t){ - {lfs_mktag(LFS_STRUCT_MOVE, oldid, 0)}}); - if (err) { - return err; - } - - if (samepair) { - // update pair if newcwd == oldcwd - newcwd = oldcwd; - } + // create move to fix later + lfs->diff.move.pair[0] = oldcwd.pair[0] ^ lfs->globals.move.pair[0]; + lfs->diff.move.pair[1] = oldcwd.pair[1] ^ lfs->globals.move.pair[1]; + lfs->diff.move.id = oldid ^ lfs->globals.move.id; +// // mark as moving +// //printf("RENAME MOVE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid); +// err = lfs_dir_commit(lfs, &oldcwd, &(lfs_mattrlist_t){ +// {lfs_mktag(LFS_STRUCT_MOVE, oldid, 0)}}); +// if (err) { +// return err; +// } +// +// if (samepair) { +// // update pair if newcwd == oldcwd +// newcwd = oldcwd; +// } +// // TODO check that all complaints are fixed // // move to new location // // TODO NAME????? @@ -2813,6 +2910,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { // return err; // } + // move over all attributes err = lfs_dir_commit(lfs, &newcwd, &(lfs_mattrlist_t){ {lfs_mktag(LFS_STRUCT_NAME | lfs_tag_subtype(oldattr.tag), newid, strlen(newpath)), @@ -2823,28 +2921,53 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { return err; } - if (samepair) { - // update pair if newcwd == oldcwd - oldcwd = newcwd; - } - - // remove old entry - //printf("RENAME DELETE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid); - err = lfs_dir_delete(lfs, &oldcwd, oldid); + // clean up after ourselves + err = lfs_fixmove(lfs); if (err) { return err; } - // if we were a directory, find pred, replace tail - // TODO can this just deorphan? if (prevexists && lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) { - err = lfs_deorphan(lfs); - if (err) { - return err; + int res = lfs_pred(lfs, prevdir.pair, &newcwd); + if (res < 0) { + return res; } + + LFS_ASSERT(res); // must have pred + newcwd.tail[0] = prevdir.tail[0]; + newcwd.tail[1] = prevdir.tail[1]; + err = lfs_dir_commit(lfs, &newcwd, &(lfs_mattrlist_t){ + {lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(newcwd.tail)), + .u.buffer=newcwd.tail}}); } return 0; + + +// if (samepair) { +// // update pair if newcwd == oldcwd +// oldcwd = newcwd; +// } +// +// err = fix +// +// // remove old entry +// //printf("RENAME DELETE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid); +// err = lfs_dir_delete(lfs, &oldcwd, oldid); +// if (err) { +// return err; +// } +// +// // if we were a directory, find pred, replace tail +// // TODO can this just deorphan? +// if (prevexists && lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) { +// err = lfs_deorphan(lfs); +// if (err) { +// return err; +// } +// } +// + return 0; } //int lfs_getattrs(lfs_t *lfs, const char *path, @@ -2954,7 +3077,17 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { lfs->files = NULL; lfs->dirs = NULL; lfs->deorphaned = false; - lfs->idelete = (lfs_entry_t){{0xffffffff, 0xffffffff}, 0xffff}; + lfs->globals.move.pair[0] = 0xffffffff; + lfs->globals.move.pair[1] = 0xffffffff; + lfs->globals.move.id = 0x3ff; + lfs->diff = (lfs_globals_t){0}; + + // scan for any global updates + // TODO rm me? need to grab any inits + int err = lfs_scan(lfs); + if (err) { + return err; + } return 0; } @@ -3122,6 +3255,11 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { lfs->root[0] = superblock.root[0]; lfs->root[1] = superblock.root[1]; + err = lfs_scan(lfs); + if (err) { + return err; + } + return 0; } @@ -3601,15 +3739,80 @@ static int lfs_relocate(lfs_t *lfs, return 0; } +int lfs_scan(lfs_t *lfs) { + if (lfs_pairisnull(lfs->root)) { // TODO rm me + return 0; + } + + lfs_mdir_t dir = {.tail = {0, 1}}; + lfs_globals_t globals = {{{0xffffffff, 0xffffffff}, 0x3ff}}; + + // iterate over all directory directory entries + while (!lfs_pairisnull(dir.tail)) { + int err = lfs_dir_fetch(lfs, &dir, dir.tail); + if (err) { + return err; + } + + // xor together indirect deletes + globals = lfs_globals_xor(&globals, &dir.globals); + } + + // update littlefs with globals + lfs->globals = globals; + lfs->diff = (lfs_globals_t){0}; + if (!lfs_pairisnull(lfs->globals.move.pair)) { + LFS_DEBUG("Found move %d %d %d", + lfs->globals.move.pair[0], + lfs->globals.move.pair[1], + lfs->globals.move.id); + } + + return 0; +} + +int lfs_fixmove(lfs_t *lfs) { + LFS_DEBUG("Fixing move %d %d %d", // TODO move to just deorphan + lfs->globals.move.pair[0], + lfs->globals.move.pair[1], + lfs->globals.move.id); + + // mark global state to clear move entry + lfs->diff.move.pair[0] = 0xffffffff ^ lfs->globals.move.pair[0]; + lfs->diff.move.pair[1] = 0xffffffff ^ lfs->globals.move.pair[1]; + lfs->diff.move.id = 0x3ff ^ lfs->globals.move.id; + + // fetch and delete the moved entry + lfs_mdir_t movedir; + int err = lfs_dir_fetch(lfs, &movedir, lfs->globals.move.pair); + if (err) { + return err; + } + + err = lfs_dir_delete(lfs, &movedir, lfs->globals.move.id); + if (err) { + return err; + } + + return 0; +} + int lfs_deorphan(lfs_t *lfs) { lfs->deorphaned = true; - if (lfs_pairisnull(lfs->root)) { + if (lfs_pairisnull(lfs->root)) { // TODO rm me? return 0; } + // Fix bad moves + if (!lfs_pairisnull(lfs->globals.move.pair)) { + int err = lfs_fixmove(lfs); + if (err) { + return err; + } + } + lfs_mdir_t pdir = {.split = true}; lfs_mdir_t dir = {.tail = {0, 1}}; - lfs_entry_t idelete = {{0xffffffff, 0xffffffff}, 0xffff}; // iterate over all directory directory entries while (!lfs_pairisnull(dir.tail)) { @@ -3618,11 +3821,6 @@ int lfs_deorphan(lfs_t *lfs) { return err; } - // xor together indirect deletes - idelete.pair[0] ^= dir.idelete.pair[0]; - idelete.pair[1] ^= dir.idelete.pair[1]; - idelete.id ^= dir.idelete.id; - // check head blocks for orphans if (!pdir.split) { // check if we have a parent @@ -3671,7 +3869,7 @@ int lfs_deorphan(lfs_t *lfs) { } // check entries for moves - if (dir.moveid >= 0) { + //if (dir.moveid >= 0) { // TODO moves and stuff // TODO need to load entry to find it // // found moved entry @@ -3698,15 +3896,11 @@ int lfs_deorphan(lfs_t *lfs) { // return err; // } // } - } + //} memcpy(&pdir, &dir, sizeof(pdir)); } - // update littlefs with current move - // TODO do this here? needs to be before reads also - lfs->idelete = idelete; - return 0; } /* diff --git a/lfs.h b/lfs.h index fdde961aae7..1a9e2dd8359 100644 --- a/lfs.h +++ b/lfs.h @@ -129,7 +129,7 @@ enum lfs_type { // internal sources LFS_FROM_REGION = 0x000, LFS_FROM_DISK = 0x200, - LFS_FROM_MOVE = 0x004, + LFS_FROM_MOVE = 0x0ff, }; // File open flags @@ -296,10 +296,17 @@ typedef struct lfs_mattrlist { struct lfs_mattrlist *next; } lfs_mattrlist_t; -typedef struct lfs_entry { - lfs_block_t pair[2]; - uint16_t id; -} lfs_entry_t; +//typedef struct lfs_entry { +// lfs_block_t pair[2]; +// uint16_t id; +//} lfs_entry_t; + +typedef struct lfs_globals { + struct lfs_move { + lfs_block_t pair[2]; + uint16_t id; + } move; +} lfs_globals_t; typedef struct lfs_mdir { lfs_block_t pair[2]; @@ -310,7 +317,7 @@ typedef struct lfs_mdir { uint16_t count; bool erased; bool split; - lfs_entry_t idelete; + lfs_globals_t globals; bool stop_at_commit; // TODO hmmm uint16_t moveid; // TODO rm me } lfs_mdir_t; @@ -380,8 +387,8 @@ typedef struct lfs { lfs_free_t free; bool deorphaned; - lfs_entry_t idelete; - lfs_entry_t diff; + lfs_globals_t globals; + lfs_globals_t diff; lfs_size_t inline_size; lfs_size_t attrs_size; diff --git a/tests/test_move.sh b/tests/test_move.sh index ff02553d31c..11dfecc1456 100755 --- a/tests/test_move.sh +++ b/tests/test_move.sh @@ -59,7 +59,7 @@ tests/test.py << TEST lfs_rename(&lfs, "b/hello", "c/hello") => 0; lfs_unmount(&lfs) => 0; TEST -truncate -s-7 blocks/6 +truncate -s-11 blocks/6 tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; lfs_dir_open(&lfs, &dir[0], "b") => 0; @@ -86,8 +86,8 @@ tests/test.py << TEST lfs_rename(&lfs, "c/hello", "d/hello") => 0; lfs_unmount(&lfs) => 0; TEST -truncate -s-7 blocks/8 -truncate -s-7 blocks/a +truncate -s-11 blocks/8 +truncate -s-11 blocks/a tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0; lfs_dir_open(&lfs, &dir[0], "c") => 0; @@ -108,6 +108,32 @@ tests/test.py << TEST lfs_unmount(&lfs) => 0; TEST +echo "--- Move file after corrupt ---" +tests/test.py -s << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_rename(&lfs, "c/hello", "d/hello") => 0; + lfs_unmount(&lfs) => 0; +TEST +tests/test.py << TEST + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir[0], "c") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, ".") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "..") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 0; + lfs_dir_close(&lfs, &dir[0]) => 0; + lfs_dir_open(&lfs, &dir[0], "d") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, ".") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "..") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 1; + strcmp(info.name, "hello") => 0; + lfs_dir_read(&lfs, &dir[0], &info) => 0; + lfs_unmount(&lfs) => 0; +TEST + echo "--- Move dir ---" tests/test.py << TEST lfs_mount(&lfs, &cfg) => 0;