mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 00:32:38 +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; | ||||
|  | ||||
|     // 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; | ||||
|         int err = lfs_dir_fetch(lfs, &pdir, lfs->cwd); | ||||
|         if (err) { | ||||
| @@ -1418,6 +1418,179 @@ int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|     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) { | ||||
|     lfs_dir_t cwd; | ||||
|     int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user