mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Added support for renaming dirs/files
This commit is contained in:
		
							
								
								
									
										175
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										175
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -1337,7 +1337,7 @@ int lfs_remove(lfs_t *lfs, const char *path) { | |||||||
|     cwd.d.size -= entry.d.len; |     cwd.d.size -= entry.d.len; | ||||||
|  |  | ||||||
|     // either shift out the one entry or remove the whole dir block |     // either shift out the one entry or remove the whole dir block | ||||||
|     if (cwd.d.size == sizeof(dir.d)) { |     if (cwd.d.size == sizeof(cwd.d)) { | ||||||
|         lfs_dir_t pdir; |         lfs_dir_t pdir; | ||||||
|         int err = lfs_dir_fetch(lfs, &pdir, lfs->cwd); |         int err = lfs_dir_fetch(lfs, &pdir, lfs->cwd); | ||||||
|         if (err) { |         if (err) { | ||||||
| @@ -1418,6 +1418,179 @@ int lfs_remove(lfs_t *lfs, const char *path) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||||
|  |     // Find old entry | ||||||
|  |     lfs_dir_t oldcwd; | ||||||
|  |     int err = lfs_dir_fetch(lfs, &oldcwd, lfs->cwd); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     lfs_entry_t oldentry; | ||||||
|  |     err = lfs_dir_find(lfs, &oldcwd, &oldpath, &oldentry); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Allocate new entry | ||||||
|  |     lfs_dir_t newcwd; | ||||||
|  |     err = lfs_dir_fetch(lfs, &newcwd, lfs->cwd); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     lfs_entry_t preventry; | ||||||
|  |     err = lfs_dir_append(lfs, &newcwd, &newpath, &preventry); | ||||||
|  |     if (err && err != LFS_ERROR_EXISTS) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |     bool prevexists = (err == LFS_ERROR_EXISTS); | ||||||
|  |  | ||||||
|  |     // must have same type | ||||||
|  |     if (prevexists && preventry.d.type != oldentry.d.type) { | ||||||
|  |         return LFS_ERROR_INVALID; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     lfs_dir_t dir; | ||||||
|  |     if (prevexists && preventry.d.type == LFS_TYPE_DIR) { | ||||||
|  |         // must be empty before removal, checking size | ||||||
|  |         // without masking top bit checks for any case where | ||||||
|  |         // dir is not empty | ||||||
|  |         int err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } else if (dir.d.size != sizeof(dir.d)) { | ||||||
|  |             return LFS_ERROR_INVALID; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Move to new location | ||||||
|  |     lfs_entry_t newentry = preventry; | ||||||
|  |     newentry.d = oldentry.d; | ||||||
|  |     newentry.d.len = sizeof(newentry.d) + strlen(newpath); | ||||||
|  |  | ||||||
|  |     newcwd.d.rev += 1; | ||||||
|  |     if (!prevexists) { | ||||||
|  |         newcwd.d.size += newentry.d.len; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     err = lfs_pair_commit(lfs, newentry.dir, | ||||||
|  |         3, (struct lfs_commit_region[3]) { | ||||||
|  |             {0, sizeof(newcwd.d), &newcwd.d}, | ||||||
|  |             {newentry.off, | ||||||
|  |              sizeof(newentry.d), | ||||||
|  |              &newentry.d}, | ||||||
|  |             {newentry.off+sizeof(newentry.d), | ||||||
|  |              newentry.d.len - sizeof(newentry.d), | ||||||
|  |              newpath} | ||||||
|  |         }); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // fetch again in case newcwd == oldcwd | ||||||
|  |     // TODO handle this better? | ||||||
|  |     err = lfs_dir_fetch(lfs, &oldcwd, oldcwd.pair); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     err = lfs_dir_find(lfs, &oldcwd, &oldpath, &oldentry); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Remove from old location | ||||||
|  |     // TODO abstract this out for rename + remove? | ||||||
|  |     oldcwd.d.rev += 1; | ||||||
|  |     oldcwd.d.size -= oldentry.d.len; | ||||||
|  |  | ||||||
|  |     // either shift out the one entry or remove the whole dir block | ||||||
|  |     if (oldcwd.d.size == sizeof(oldcwd.d)) { | ||||||
|  |         lfs_dir_t pdir; | ||||||
|  |         int err = lfs_dir_fetch(lfs, &pdir, lfs->cwd); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         while (lfs_paircmp(pdir.d.tail, oldcwd.pair) != 0) { | ||||||
|  |             int err = lfs_dir_fetch(lfs, &pdir, pdir.d.tail); | ||||||
|  |             if (err) { | ||||||
|  |                 return err; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // TODO easier check for head block? (common case) | ||||||
|  |         if (!(pdir.d.size & 0x80000000)) { | ||||||
|  |             int err = lfs_pair_shift(lfs, oldentry.dir, | ||||||
|  |                 1, (struct lfs_commit_region[]) { | ||||||
|  |                     {0, sizeof(oldcwd.d), &oldcwd.d}, | ||||||
|  |                 }, | ||||||
|  |                 oldentry.off, oldentry.d.len); | ||||||
|  |             if (err) { | ||||||
|  |                 return err; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             pdir.d.tail[0] = oldcwd.d.tail[0]; | ||||||
|  |             pdir.d.tail[1] = oldcwd.d.tail[1]; | ||||||
|  |             pdir.d.rev += 1; | ||||||
|  |  | ||||||
|  |             err = lfs_pair_commit(lfs, pdir.pair, | ||||||
|  |                 1, (struct lfs_commit_region[]) { | ||||||
|  |                     {0, sizeof(pdir.d), &pdir.d}, | ||||||
|  |                 }); | ||||||
|  |             if (err) { | ||||||
|  |                 return err; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         int err = lfs_pair_shift(lfs, oldentry.dir, | ||||||
|  |             1, (struct lfs_commit_region[]) { | ||||||
|  |                 {0, sizeof(oldcwd.d), &oldcwd.d}, | ||||||
|  |             }, | ||||||
|  |             oldentry.off, oldentry.d.len); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // TODO abstract this out for rename + remove? | ||||||
|  |     if (prevexists && preventry.d.type == LFS_TYPE_DIR) { | ||||||
|  |         // remove dest from the dir list | ||||||
|  |         // this may create an orphan, which must be deorphaned | ||||||
|  |         lfs_dir_t pdir; | ||||||
|  |         int err = lfs_dir_fetch(lfs, &pdir, lfs->root); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         while (pdir.d.tail[0]) { | ||||||
|  |             if (lfs_paircmp(pdir.d.tail, preventry.d.u.dir) == 0) { | ||||||
|  |                 pdir.d.tail[0] = dir.d.tail[0]; | ||||||
|  |                 pdir.d.tail[1] = dir.d.tail[1]; | ||||||
|  |                 pdir.d.rev += 1; | ||||||
|  |  | ||||||
|  |                 int err = lfs_pair_commit(lfs, pdir.pair, | ||||||
|  |                     1, (struct lfs_commit_region[]) { | ||||||
|  |                         {0, sizeof(pdir.d), &pdir.d}, | ||||||
|  |                     }); | ||||||
|  |                 if (err) { | ||||||
|  |                     return err; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             int err = lfs_dir_fetch(lfs, &pdir, pdir.d.tail); | ||||||
|  |             if (err) { | ||||||
|  |                 return err; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { | int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { | ||||||
|     lfs_dir_t cwd; |     lfs_dir_t cwd; | ||||||
|     int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd); |     int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd); | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -138,6 +138,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *config); | |||||||
| int lfs_unmount(lfs_t *lfs); | int lfs_unmount(lfs_t *lfs); | ||||||
|  |  | ||||||
| int lfs_remove(lfs_t *lfs, const char *path); | int lfs_remove(lfs_t *lfs, const char *path); | ||||||
|  | int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath); | ||||||
| int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); | int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); | ||||||
|  |  | ||||||
| int lfs_mkdir(lfs_t *lfs, const char *path); | int lfs_mkdir(lfs_t *lfs, const char *path); | ||||||
|   | |||||||
| @@ -123,7 +123,7 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
| echo "--- Directory deletion ---" | echo "--- Directory remove ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &config) => 0; |     lfs_mount(&lfs, &config) => 0; | ||||||
|     lfs_remove(&lfs, "potato") => LFS_ERROR_INVALID; |     lfs_remove(&lfs, "potato") => LFS_ERROR_INVALID; | ||||||
| @@ -180,5 +180,107 @@ tests/test.py << TEST | |||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
|  |  | ||||||
|  | echo "--- Directory rename ---" | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &config) => 0; | ||||||
|  |     lfs_mkdir(&lfs, "coldpotato") => 0; | ||||||
|  |     lfs_mkdir(&lfs, "coldpotato/baked") => 0; | ||||||
|  |     lfs_mkdir(&lfs, "coldpotato/sweet") => 0; | ||||||
|  |     lfs_mkdir(&lfs, "coldpotato/fried") => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &config) => 0; | ||||||
|  |     lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &config) => 0; | ||||||
|  |     lfs_dir_open(&lfs, &dir[0], "hotpotato") => 0; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, ".") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "..") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "baked") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "sweet") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "fried") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 0; | ||||||
|  |     lfs_dir_close(&lfs, &dir[0]) => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &config) => 0; | ||||||
|  |     lfs_mkdir(&lfs, "warmpotato") => 0; | ||||||
|  |     lfs_mkdir(&lfs, "warmpotato/mushy") => 0; | ||||||
|  |     lfs_rename(&lfs, "hotpotato", "warmpotato") => LFS_ERROR_INVALID; | ||||||
|  |  | ||||||
|  |     lfs_remove(&lfs, "warmpotato/mushy") => 0; | ||||||
|  |     lfs_rename(&lfs, "hotpotato", "warmpotato") => 0; | ||||||
|  |  | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &config) => 0; | ||||||
|  |     lfs_dir_open(&lfs, &dir[0], "warmpotato") => 0; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, ".") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "..") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "baked") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "sweet") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "fried") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 0; | ||||||
|  |     lfs_dir_close(&lfs, &dir[0]) => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &config) => 0; | ||||||
|  |     lfs_mkdir(&lfs, "coldpotato") => 0; | ||||||
|  |     lfs_rename(&lfs, "warmpotato/baked", "coldpotato/baked") => 0; | ||||||
|  |     lfs_rename(&lfs, "warmpotato/sweet", "coldpotato/sweet") => 0; | ||||||
|  |     lfs_rename(&lfs, "warmpotato/fried", "coldpotato/fried") => 0; | ||||||
|  |     lfs_remove(&lfs, "coldpotato") => LFS_ERROR_INVALID; | ||||||
|  |     lfs_remove(&lfs, "warmpotato") => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  | tests/test.py << TEST | ||||||
|  |     lfs_mount(&lfs, &config) => 0; | ||||||
|  |     lfs_dir_open(&lfs, &dir[0], "coldpotato") => 0; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, ".") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "..") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "baked") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "sweet") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 1; | ||||||
|  |     strcmp(info.name, "fried") => 0; | ||||||
|  |     info.type => LFS_TYPE_DIR; | ||||||
|  |     lfs_dir_read(&lfs, &dir[0], &info) => 0; | ||||||
|  |     lfs_dir_close(&lfs, &dir[0]) => 0; | ||||||
|  |     lfs_unmount(&lfs) => 0; | ||||||
|  | TEST | ||||||
|  |  | ||||||
| echo "--- Results ---" | echo "--- Results ---" | ||||||
| tests/stats.py | tests/stats.py | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user