mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-11-01 00:38:29 +01:00 
			
		
		
		
	WIP switched back to deorphan for remove
Utilizing moves wouldn't have worked for rename anyways, and it requires additional code for much less traveled code path (directory removes)
This commit is contained in:
		
							
								
								
									
										364
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										364
									
								
								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 @@ relocate: | ||||
|         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,13 @@ static int lfs_relocate(lfs_t *lfs, | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_deorphan(lfs_t *lfs) { | ||||
|     lfs->deorphaned = true; | ||||
|     if (lfs_pairisnull(lfs->root)) { | ||||
| int lfs_scan(lfs_t *lfs) { | ||||
|     if (lfs_pairisnull(lfs->root)) { // TODO rm me | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     lfs_mdir_t pdir = {.split = true}; | ||||
|     lfs_mdir_t dir = {.tail = {0, 1}}; | ||||
|     lfs_entry_t idelete = {{0xffffffff, 0xffffffff}, 0xffff}; | ||||
|     lfs_globals_t globals = {{{0xffffffff, 0xffffffff}, 0x3ff}}; | ||||
|  | ||||
|     // iterate over all directory directory entries | ||||
|     while (!lfs_pairisnull(dir.tail)) { | ||||
| @@ -3619,9 +3755,71 @@ int lfs_deorphan(lfs_t *lfs) { | ||||
|         } | ||||
|  | ||||
|         // xor together indirect deletes | ||||
|         idelete.pair[0] ^= dir.idelete.pair[0]; | ||||
|         idelete.pair[1] ^= dir.idelete.pair[1]; | ||||
|         idelete.id      ^= dir.idelete.id; | ||||
|         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)) { // 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}}; | ||||
|  | ||||
|     // iterate over all directory directory entries | ||||
|     while (!lfs_pairisnull(dir.tail)) { | ||||
|         int err = lfs_dir_fetch(lfs, &dir, dir.tail); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         // check head blocks for orphans | ||||
|         if (!pdir.split) { | ||||
| @@ -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; | ||||
| } | ||||
| /* | ||||
|   | ||||
							
								
								
									
										23
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								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; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user