mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	Compare commits
	
		
			12 Commits
		
	
	
		
			v2.4.1
			...
			resizable-
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 04b1103de1 | ||
|  | 87df75d009 | ||
|  | 1ea3d04d9c | ||
|  | 126f6d334e | ||
|  | 385b74944d | ||
|  | 3a10f5c29b | ||
|  | 96cca2f5b6 | ||
|  | 32f43462ea | ||
|  | efc634f3ed | ||
|  | 2f7adc3461 | ||
|  | e934a22c3a | ||
|  | 5937fd79dd | 
							
								
								
									
										443
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										443
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -386,10 +386,6 @@ static inline bool lfs_pairsync( | ||||
|            (paira[0] == pairb[1] && paira[1] == pairb[0]); | ||||
| } | ||||
|  | ||||
| static inline lfs_size_t lfs_entry_size(const lfs_entry_t *entry) { | ||||
|     return 4 + entry->d.elen + entry->d.alen + entry->d.nlen; | ||||
| } | ||||
|  | ||||
| static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) { | ||||
|     // allocate pair of dir blocks | ||||
|     for (int i = 0; i < 2; i++) { | ||||
| @@ -473,27 +469,93 @@ static int lfs_dir_fetch(lfs_t *lfs, | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| struct lfs_region { | ||||
|     lfs_off_t oldoff; | ||||
|     lfs_size_t oldlen; | ||||
|     const void *newdata; | ||||
|     lfs_size_t newlen; | ||||
| struct lfs_commit { | ||||
|     uint32_t crc; | ||||
|     lfs_block_t block; | ||||
|     lfs_off_t off; | ||||
| }; | ||||
|  | ||||
| static int lfs_commit(lfs_t *lfs, struct lfs_commit *c, | ||||
|         const void *data, lfs_size_t size) { | ||||
|     lfs_crc(&c->crc, data, size); | ||||
|     int err = lfs_bd_prog(lfs, c->block, c->off, data, size); | ||||
|     c->off += size; | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| struct lfs_region { | ||||
|     lfs_off_t off; | ||||
|     lfs_ssize_t diff; | ||||
|  | ||||
|     int (*commit)(lfs_t *lfs, struct lfs_commit *c, | ||||
|             const void *data, lfs_size_t size); | ||||
|     const void *data; | ||||
|     lfs_size_t size; | ||||
|     struct lfs_region *next; | ||||
| }; | ||||
|  | ||||
| static int lfs_commit_mem(lfs_t *lfs, struct lfs_commit *c, | ||||
|         const void *data, lfs_size_t size) { | ||||
|     return lfs_commit(lfs, c, data, size); | ||||
| } | ||||
|  | ||||
| struct lfs_commit_disk { | ||||
|     lfs_block_t block; | ||||
|     lfs_off_t off; | ||||
|     struct lfs_region *regions; | ||||
| }; | ||||
|  | ||||
| static int lfs_commit_disk(lfs_t *lfs, struct lfs_commit *c, | ||||
|         const void *p, lfs_size_t size) { | ||||
|     const struct lfs_commit_disk *d = p; | ||||
|  | ||||
|     struct lfs_region *r = d->regions; | ||||
|     lfs_off_t off = 0; | ||||
|     while (true) { | ||||
|         if (r && r->off == off) { | ||||
|             lfs_off_t orig = c->off; | ||||
|             int err = r->commit(lfs, c, r->data, r->size); | ||||
|             if (err) { | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
|             off += (c->off - orig) - r->diff; | ||||
|             r = r->next; | ||||
|         } else if (off < size) { | ||||
|             uint8_t data; | ||||
|             int err = lfs_bd_read(lfs, d->block, d->off + off, &data, 1); | ||||
|             if (err) { | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
|             err = lfs_commit(lfs, c, &data, 1); | ||||
|             if (err) { | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
|             off += 1; | ||||
|         } else { | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         const struct lfs_region *regions, int count) { | ||||
|         struct lfs_region *regions) { | ||||
|     // state for copying over | ||||
|     const lfs_block_t oldpair[2] = {dir->pair[1], dir->pair[0]}; | ||||
|     lfs_size_t oldsize = (0x7fffffff & dir->d.size) - 4; | ||||
|     bool relocated = false; | ||||
|  | ||||
|     // increment revision count | ||||
|     dir->d.rev += 1; | ||||
|  | ||||
|     // keep pairs in order such that pair[0] is most recent | ||||
|     lfs_pairswap(dir->pair); | ||||
|     for (int i = 0; i < count; i++) { | ||||
|         dir->d.size += regions[i].newlen - regions[i].oldlen; | ||||
|     for (struct lfs_region *r = regions; r; r = r->next) { | ||||
|         dir->d.size += r->diff; | ||||
|     } | ||||
|  | ||||
|     const lfs_block_t oldpair[2] = {dir->pair[0], dir->pair[1]}; | ||||
|     bool relocated = false; | ||||
|  | ||||
|     while (true) { | ||||
|         if (true) { | ||||
|             int err = lfs_bd_erase(lfs, dir->pair[0]); | ||||
| @@ -504,10 +566,19 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
|             uint32_t crc = 0xffffffff; | ||||
|             struct lfs_commit c = { | ||||
|                 .crc = 0xffffffff, | ||||
|                 .block = dir->pair[0], | ||||
|                 .off = 0, | ||||
|             }; | ||||
|  | ||||
|             lfs_dir_tole32(&dir->d); | ||||
|             lfs_crc(&crc, &dir->d, sizeof(dir->d)); | ||||
|             err = lfs_bd_prog(lfs, dir->pair[0], 0, &dir->d, sizeof(dir->d)); | ||||
|             err = lfs_commit_disk(lfs, &c, &(struct lfs_commit_disk){ | ||||
|                     oldpair[1], 0, | ||||
|                     &(struct lfs_region){ | ||||
|                         0, 0, | ||||
|                         lfs_commit_mem, &dir->d, sizeof(dir->d), | ||||
|                         regions}}, oldsize); | ||||
|             lfs_dir_fromle32(&dir->d); | ||||
|             if (err) { | ||||
|                 if (err == LFS_ERR_CORRUPT) { | ||||
| @@ -516,48 +587,9 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
|             int i = 0; | ||||
|             lfs_off_t oldoff = sizeof(dir->d); | ||||
|             lfs_off_t newoff = sizeof(dir->d); | ||||
|             while (newoff < (0x7fffffff & dir->d.size)-4) { | ||||
|                 if (i < count && regions[i].oldoff == oldoff) { | ||||
|                     lfs_crc(&crc, regions[i].newdata, regions[i].newlen); | ||||
|                     err = lfs_bd_prog(lfs, dir->pair[0], | ||||
|                             newoff, regions[i].newdata, regions[i].newlen); | ||||
|                     if (err) { | ||||
|                         if (err == LFS_ERR_CORRUPT) { | ||||
|                             goto relocate; | ||||
|                         } | ||||
|                         return err; | ||||
|                     } | ||||
|  | ||||
|                     oldoff += regions[i].oldlen; | ||||
|                     newoff += regions[i].newlen; | ||||
|                     i += 1; | ||||
|                 } else { | ||||
|                     uint8_t data; | ||||
|                     err = lfs_bd_read(lfs, oldpair[1], oldoff, &data, 1); | ||||
|                     if (err) { | ||||
|                         return err; | ||||
|                     } | ||||
|  | ||||
|                     lfs_crc(&crc, &data, 1); | ||||
|                     err = lfs_bd_prog(lfs, dir->pair[0], newoff, &data, 1); | ||||
|                     if (err) { | ||||
|                         if (err == LFS_ERR_CORRUPT) { | ||||
|                             goto relocate; | ||||
|                         } | ||||
|                         return err; | ||||
|                     } | ||||
|  | ||||
|                     oldoff += 1; | ||||
|                     newoff += 1; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             crc = lfs_tole32(crc); | ||||
|             err = lfs_bd_prog(lfs, dir->pair[0], newoff, &crc, 4); | ||||
|             crc = lfs_fromle32(crc); | ||||
|             c.crc = lfs_tole32(c.crc); | ||||
|             err = lfs_bd_prog(lfs, dir->pair[0], c.off, &c.crc, 4); | ||||
|             c.crc = lfs_fromle32(c.crc); | ||||
|             if (err) { | ||||
|                 if (err == LFS_ERR_CORRUPT) { | ||||
|                     goto relocate; | ||||
| @@ -581,12 +613,13 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir, | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
|             if (ncrc != crc) { | ||||
|             if (ncrc != c.crc) { | ||||
|                 goto relocate; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         break; | ||||
|  | ||||
| relocate: | ||||
|         //commit was corrupted | ||||
|         LFS_DEBUG("Bad block at %d", dir->pair[0]); | ||||
| @@ -629,29 +662,18 @@ relocate: | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         lfs_entry_t *entry, const void *data) { | ||||
|     lfs_entry_tole32(&entry->d); | ||||
|     int err = lfs_dir_commit(lfs, dir, (struct lfs_region[]){ | ||||
|             {entry->off, sizeof(entry->d), &entry->d, sizeof(entry->d)}, | ||||
|             {entry->off+sizeof(entry->d), entry->d.nlen, data, entry->d.nlen} | ||||
|         }, data ? 2 : 1); | ||||
|     lfs_entry_fromle32(&entry->d); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         lfs_entry_t *entry, const void *data) { | ||||
|         lfs_entry_t *entry, struct lfs_region *regions) { | ||||
|     // check if we fit, if top bit is set we do not and move on | ||||
|     while (true) { | ||||
|         if (dir->d.size + lfs_entry_size(entry) <= lfs->cfg->block_size) { | ||||
|         if ((0x7fffffff & dir->d.size) + entry->size <= lfs->cfg->block_size) { | ||||
|             entry->off = dir->d.size - 4; | ||||
|             for (struct lfs_region *r = regions; r; r = r->next) { | ||||
|                 r->off += entry->off; | ||||
|             } | ||||
|  | ||||
|             lfs_entry_tole32(&entry->d); | ||||
|             int err = lfs_dir_commit(lfs, dir, (struct lfs_region[]){ | ||||
|                     {entry->off, 0, &entry->d, sizeof(entry->d)}, | ||||
|                     {entry->off, 0, data, entry->d.nlen} | ||||
|                 }, 2); | ||||
|             int err = lfs_dir_commit(lfs, dir, regions); | ||||
|             lfs_entry_fromle32(&entry->d); | ||||
|             return err; | ||||
|         } | ||||
| @@ -667,11 +689,12 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir, | ||||
|             dir->d.tail[0] = olddir.d.tail[0]; | ||||
|             dir->d.tail[1] = olddir.d.tail[1]; | ||||
|             entry->off = dir->d.size - 4; | ||||
|             for (struct lfs_region *r = regions; r; r = r->next) { | ||||
|                 r->off += entry->off; | ||||
|             } | ||||
|  | ||||
|             lfs_entry_tole32(&entry->d); | ||||
|             err = lfs_dir_commit(lfs, dir, (struct lfs_region[]){ | ||||
|                     {entry->off, 0, &entry->d, sizeof(entry->d)}, | ||||
|                     {entry->off, 0, data, entry->d.nlen} | ||||
|                 }, 2); | ||||
|             err = lfs_dir_commit(lfs, dir, regions); | ||||
|             lfs_entry_fromle32(&entry->d); | ||||
|             if (err) { | ||||
|                 return err; | ||||
| @@ -680,7 +703,7 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir, | ||||
|             olddir.d.size |= 0x80000000; | ||||
|             olddir.d.tail[0] = dir->pair[0]; | ||||
|             olddir.d.tail[1] = dir->pair[1]; | ||||
|             return lfs_dir_commit(lfs, &olddir, NULL, 0); | ||||
|             return lfs_dir_commit(lfs, &olddir, NULL); | ||||
|         } | ||||
|  | ||||
|         int err = lfs_dir_fetch(lfs, dir, dir->d.tail); | ||||
| @@ -690,10 +713,10 @@ static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir, | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | ||||
| static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         const lfs_entry_t *entry) { | ||||
|     // check if we should just drop the directory block | ||||
|     if ((dir->d.size & 0x7fffffff) == sizeof(dir->d)+4 | ||||
|             + lfs_entry_size(entry)) { | ||||
|     if ((dir->d.size & 0x7fffffff) == sizeof(dir->d)+4 + entry->size) { | ||||
|         lfs_dir_t pdir; | ||||
|         int res = lfs_pred(lfs, dir->pair, &pdir); | ||||
|         if (res < 0) { | ||||
| @@ -704,14 +727,15 @@ static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | ||||
|             pdir.d.size &= dir->d.size | 0x7fffffff; | ||||
|             pdir.d.tail[0] = dir->d.tail[0]; | ||||
|             pdir.d.tail[1] = dir->d.tail[1]; | ||||
|             return lfs_dir_commit(lfs, &pdir, NULL, 0); | ||||
|             return lfs_dir_commit(lfs, &pdir, NULL); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // shift out the entry | ||||
|     int err = lfs_dir_commit(lfs, dir, (struct lfs_region[]){ | ||||
|             {entry->off, lfs_entry_size(entry), NULL, 0}, | ||||
|         }, 1); | ||||
|     int err = lfs_dir_commit(lfs, dir, | ||||
|             &(struct lfs_region){ | ||||
|                 entry->off, -entry->size, | ||||
|                 lfs_commit_mem, NULL, 0}); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -723,7 +747,7 @@ static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | ||||
|                 f->pair[0] = 0xffffffff; | ||||
|                 f->pair[1] = 0xffffffff; | ||||
|             } else if (f->poff > entry->off) { | ||||
|                 f->poff -= lfs_entry_size(entry); | ||||
|                 f->poff -= entry->size; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -731,8 +755,8 @@ static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | ||||
|     for (lfs_dir_t *d = lfs->dirs; d; d = d->next) { | ||||
|         if (lfs_paircmp(d->pair, dir->pair) == 0) { | ||||
|             if (d->off > entry->off) { | ||||
|                 d->off -= lfs_entry_size(entry); | ||||
|                 d->pos -= lfs_entry_size(entry); | ||||
|                 d->off -= entry->size; | ||||
|                 d->pos -= entry->size; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -740,6 +764,82 @@ static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int lfs_dir_update(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         lfs_entry_t *entry, struct lfs_region *regions) { | ||||
|     lfs_ssize_t diff = 0; | ||||
|     for (struct lfs_region *r = regions; r; r = r->next) { | ||||
|         diff += r->diff; | ||||
|     } | ||||
|  | ||||
|     // do we still fit? | ||||
|     if ((0x7fffffff & dir->d.size) + diff <= lfs->cfg->block_size) { | ||||
|         for (struct lfs_region *r = regions; r; r = r->next) { | ||||
|             r->off += entry->off; | ||||
|         } | ||||
|  | ||||
|         lfs_entry_tole32(&entry->d); | ||||
|         int err = lfs_dir_commit(lfs, dir, regions); | ||||
|         lfs_entry_fromle32(&entry->d); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         // shift over any files/directories that are affected | ||||
|         for (lfs_file_t *f = lfs->files; f; f = f->next) { | ||||
|             if (lfs_paircmp(f->pair, dir->pair) == 0) { | ||||
|                 if (f->poff > entry->off) { | ||||
|                     f->poff += diff; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (lfs_dir_t *d = lfs->dirs; d; d = d->next) { | ||||
|             if (lfs_paircmp(d->pair, dir->pair) == 0) { | ||||
|                 if (d->off > entry->off) { | ||||
|                     d->off += diff; | ||||
|                     d->pos += diff; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } else { | ||||
|         lfs_dir_t olddir = *dir; | ||||
|         lfs_entry_t oldentry = { | ||||
|             .off = entry->off, | ||||
|             .size = entry->size - diff, | ||||
|             .d.type = entry->d.type | LFS_STRUCT_MOVED, | ||||
|         }; | ||||
|  | ||||
|         // mark as moving | ||||
|         int err = lfs_dir_commit(lfs, &olddir, | ||||
|                 &(struct lfs_region){ | ||||
|                     oldentry.off, 0, | ||||
|                     lfs_commit_mem, &oldentry.d.type, 1}); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         // append updated entry | ||||
|         lfs_entry_tole32(&entry->d); | ||||
|         err = lfs_dir_append(lfs, dir, entry, | ||||
|                 &(struct lfs_region){ | ||||
|                     0, +entry->size, | ||||
|                     lfs_commit_disk, &(struct lfs_commit_disk){ | ||||
|                         olddir.pair[0], entry->off, regions}, oldentry.size}); | ||||
|         lfs_entry_fromle32(&entry->d); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         // remove old entry | ||||
|         err = lfs_dir_remove(lfs, dir, &oldentry); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | ||||
|     while (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)-4) { | ||||
|         if (!(0x80000000 & dir->d.size)) { | ||||
| @@ -764,8 +864,9 @@ static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) { | ||||
|     } | ||||
|  | ||||
|     entry->off = dir->off; | ||||
|     dir->off += lfs_entry_size(entry); | ||||
|     dir->pos += lfs_entry_size(entry); | ||||
|     entry->size = 4 + entry->d.elen + entry->d.alen + entry->d.nlen; | ||||
|     dir->off += entry->size; | ||||
|     dir->pos += entry->size; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| @@ -783,10 +884,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         // special case for root dir | ||||
|         if (pathname[0] == '\0') { | ||||
|             *entry = (lfs_entry_t){ | ||||
|                 .d.type = LFS_TYPE_DIR, | ||||
|                 .d.elen = sizeof(entry->d) - 4, | ||||
|                 .d.alen = 0, | ||||
|                 .d.nlen = 0, | ||||
|                 .d.type = LFS_STRUCT_DIR | LFS_TYPE_DIR, | ||||
|                 .d.u.dir[0] = lfs->root[0], | ||||
|                 .d.u.dir[1] = lfs->root[1], | ||||
|             }; | ||||
| @@ -834,14 +932,14 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir, | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
|             if (((0x7f & entry->d.type) != LFS_TYPE_REG && | ||||
|                  (0x7f & entry->d.type) != LFS_TYPE_DIR) || | ||||
|             if (((0x7f & entry->d.type) != (LFS_STRUCT_CTZ | LFS_TYPE_REG) && | ||||
|                  (0x7f & entry->d.type) != (LFS_STRUCT_DIR | LFS_TYPE_DIR)) || | ||||
|                 entry->d.nlen != pathlen) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             int res = lfs_bd_cmp(lfs, dir->pair[0], | ||||
|                     entry->off + 4+entry->d.elen+entry->d.alen, | ||||
|                     entry->off + entry->size - pathlen, | ||||
|                     pathname, pathlen); | ||||
|             if (res < 0) { | ||||
|                 return res; | ||||
| @@ -854,13 +952,13 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         } | ||||
|  | ||||
|         // check that entry has not been moved | ||||
|         if (entry->d.type & 0x80) { | ||||
|         if (entry->d.type & LFS_STRUCT_MOVED) { | ||||
|             int moved = lfs_moved(lfs, &entry->d.u); | ||||
|             if (moved < 0 || moved) { | ||||
|                 return (moved < 0) ? moved : LFS_ERR_NOENT; | ||||
|             } | ||||
|  | ||||
|             entry->d.type &= ~0x80; | ||||
|             entry->d.type &= ~LFS_STRUCT_MOVED; | ||||
|         } | ||||
|  | ||||
|         pathname += pathlen; | ||||
| @@ -870,7 +968,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir, | ||||
|         } | ||||
|  | ||||
|         // continue on if we hit a directory | ||||
|         if (entry->d.type != LFS_TYPE_DIR) { | ||||
|         if ((0xf & entry->d.type) != LFS_TYPE_DIR) { | ||||
|             return LFS_ERR_NOTDIR; | ||||
|         } | ||||
|  | ||||
| @@ -916,22 +1014,29 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | ||||
|     dir.d.tail[0] = cwd.d.tail[0]; | ||||
|     dir.d.tail[1] = cwd.d.tail[1]; | ||||
|  | ||||
|     err = lfs_dir_commit(lfs, &dir, NULL, 0); | ||||
|     err = lfs_dir_commit(lfs, &dir, NULL); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     entry.d.type = LFS_TYPE_DIR; | ||||
|     entry.d.type = LFS_STRUCT_DIR | LFS_TYPE_DIR; | ||||
|     entry.d.elen = sizeof(entry.d) - 4; | ||||
|     entry.d.alen = 0; | ||||
|     entry.d.nlen = strlen(path); | ||||
|     entry.d.u.dir[0] = dir.pair[0]; | ||||
|     entry.d.u.dir[1] = dir.pair[1]; | ||||
|     entry.size = 4 + entry.d.elen + entry.d.alen + entry.d.nlen; | ||||
|  | ||||
|     cwd.d.tail[0] = dir.pair[0]; | ||||
|     cwd.d.tail[1] = dir.pair[1]; | ||||
|  | ||||
|     err = lfs_dir_append(lfs, &cwd, &entry, path); | ||||
|     err = lfs_dir_append(lfs, &cwd, &entry, | ||||
|             &(struct lfs_region){ | ||||
|                 0, +sizeof(entry.d), | ||||
|                 lfs_commit_mem, &entry.d, sizeof(entry.d), | ||||
|             &(struct lfs_region){ | ||||
|                 0, +entry.d.nlen, | ||||
|                 lfs_commit_mem, path, entry.d.nlen}}); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -953,7 +1058,7 @@ int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) { | ||||
|     err = lfs_dir_find(lfs, dir, &entry, &path); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } else if (entry.d.type != LFS_TYPE_DIR) { | ||||
|     } else if (entry.d.type != (LFS_STRUCT_DIR | LFS_TYPE_DIR)) { | ||||
|         return LFS_ERR_NOTDIR; | ||||
|     } | ||||
|  | ||||
| @@ -1011,13 +1116,13 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { | ||||
|             return (err == LFS_ERR_NOENT) ? 0 : err; | ||||
|         } | ||||
|  | ||||
|         if ((0x7f & entry.d.type) != LFS_TYPE_REG && | ||||
|             (0x7f & entry.d.type) != LFS_TYPE_DIR) { | ||||
|         if ((0x7f & entry.d.type) != (LFS_STRUCT_CTZ | LFS_TYPE_REG) && | ||||
|             (0x7f & entry.d.type) != (LFS_STRUCT_DIR | LFS_TYPE_DIR)) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         // check that entry has not been moved | ||||
|         if (entry.d.type & 0x80) { | ||||
|         if (entry.d.type & LFS_STRUCT_MOVED) { | ||||
|             int moved = lfs_moved(lfs, &entry.d.u); | ||||
|             if (moved < 0) { | ||||
|                 return moved; | ||||
| @@ -1027,19 +1132,19 @@ int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             entry.d.type &= ~0x80; | ||||
|             entry.d.type &= ~LFS_STRUCT_MOVED; | ||||
|         } | ||||
|  | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     info->type = entry.d.type; | ||||
|     info->type = 0xf & entry.d.type; | ||||
|     if (info->type == LFS_TYPE_REG) { | ||||
|         info->size = entry.d.u.file.size; | ||||
|     } | ||||
|  | ||||
|     int err = lfs_bd_read(lfs, dir->pair[0], | ||||
|             entry.off + 4+entry.d.elen+entry.d.alen, | ||||
|             entry.off + entry.size - entry.d.nlen, | ||||
|             info->name, entry.d.nlen); | ||||
|     if (err) { | ||||
|         return err; | ||||
| @@ -1309,17 +1414,25 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
|         } | ||||
|  | ||||
|         // create entry to remember name | ||||
|         entry.d.type = LFS_TYPE_REG; | ||||
|         entry.d.type = LFS_STRUCT_CTZ | LFS_TYPE_REG; | ||||
|         entry.d.elen = sizeof(entry.d) - 4; | ||||
|         entry.d.alen = 0; | ||||
|         entry.d.nlen = strlen(path); | ||||
|         entry.d.u.file.head = 0xffffffff; | ||||
|         entry.d.u.file.size = 0; | ||||
|         err = lfs_dir_append(lfs, &cwd, &entry, path); | ||||
|         entry.size = 4 + entry.d.elen + entry.d.alen + entry.d.nlen; | ||||
|  | ||||
|         err = lfs_dir_append(lfs, &cwd, &entry, | ||||
|                 &(struct lfs_region){ | ||||
|                     0, +sizeof(entry.d), | ||||
|                     lfs_commit_mem, &entry.d, sizeof(entry.d), | ||||
|                 &(struct lfs_region){ | ||||
|                     0, +entry.d.nlen, | ||||
|                     lfs_commit_mem, path, entry.d.nlen}}); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|     } else if (entry.d.type == LFS_TYPE_DIR) { | ||||
|     } else if ((0xf & entry.d.type) == LFS_TYPE_DIR) { | ||||
|         return LFS_ERR_ISDIR; | ||||
|     } else if (flags & LFS_O_EXCL) { | ||||
|         return LFS_ERR_EXIST; | ||||
| @@ -1527,11 +1640,16 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         LFS_ASSERT(entry.d.type == LFS_TYPE_REG); | ||||
|         LFS_ASSERT(entry.d.type == (LFS_STRUCT_CTZ | LFS_TYPE_REG)); | ||||
|         entry.d.u.file.head = file->head; | ||||
|         entry.d.u.file.size = file->size; | ||||
|  | ||||
|         err = lfs_dir_update(lfs, &cwd, &entry, NULL); | ||||
|         lfs_entry_tole32(&entry.d); | ||||
|         err = lfs_dir_update(lfs, &cwd, &entry, | ||||
|             &(struct lfs_region){ | ||||
|                 0, 0, | ||||
|                 lfs_commit_mem, &entry.d, sizeof(entry.d)}); | ||||
|         lfs_entry_fromle32(&entry.d); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -1816,7 +1934,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { | ||||
|     } | ||||
|  | ||||
|     memset(info, 0, sizeof(*info)); | ||||
|     info->type = entry.d.type; | ||||
|     info->type = 0xf & entry.d.type; | ||||
|     if (info->type == LFS_TYPE_REG) { | ||||
|         info->size = entry.d.u.file.size; | ||||
|     } | ||||
| @@ -1825,7 +1943,7 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { | ||||
|         strcpy(info->name, "/"); | ||||
|     } else { | ||||
|         err = lfs_bd_read(lfs, cwd.pair[0], | ||||
|                 entry.off + 4+entry.d.elen+entry.d.alen, | ||||
|                 entry.off + entry.size - entry.d.nlen, | ||||
|                 info->name, entry.d.nlen); | ||||
|         if (err) { | ||||
|             return err; | ||||
| @@ -1857,7 +1975,7 @@ int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|     } | ||||
|  | ||||
|     lfs_dir_t dir; | ||||
|     if (entry.d.type == LFS_TYPE_DIR) { | ||||
|     if ((0xf & entry.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 | ||||
| @@ -1876,7 +1994,7 @@ int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|     } | ||||
|  | ||||
|     // if we were a directory, find pred, replace tail | ||||
|     if (entry.d.type == LFS_TYPE_DIR) { | ||||
|     if ((0xf & entry.d.type) == LFS_TYPE_DIR) { | ||||
|         int res = lfs_pred(lfs, dir.pair, &cwd); | ||||
|         if (res < 0) { | ||||
|             return res; | ||||
| @@ -1886,7 +2004,7 @@ int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|         cwd.d.tail[0] = dir.d.tail[0]; | ||||
|         cwd.d.tail[1] = dir.d.tail[1]; | ||||
|  | ||||
|         err = lfs_dir_commit(lfs, &cwd, NULL, 0); | ||||
|         err = lfs_dir_commit(lfs, &cwd, NULL); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -1939,7 +2057,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|     } | ||||
|  | ||||
|     lfs_dir_t dir; | ||||
|     if (prevexists && preventry.d.type == LFS_TYPE_DIR) { | ||||
|     if (prevexists && (0xf & 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 | ||||
| @@ -1952,8 +2070,11 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|     } | ||||
|  | ||||
|     // mark as moving | ||||
|     oldentry.d.type |= 0x80; | ||||
|     err = lfs_dir_update(lfs, &oldcwd, &oldentry, NULL); | ||||
|     oldentry.d.type |= LFS_STRUCT_MOVED; | ||||
|     err = lfs_dir_update(lfs, &oldcwd, &oldentry, | ||||
|             &(struct lfs_region){ | ||||
|                 0, 0, | ||||
|                 lfs_commit_mem, &oldentry.d.type, 1}); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -1966,16 +2087,28 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|     // move to new location | ||||
|     lfs_entry_t newentry = preventry; | ||||
|     newentry.d = oldentry.d; | ||||
|     newentry.d.type &= ~0x80; | ||||
|     newentry.d.type &= ~LFS_STRUCT_MOVED; | ||||
|     newentry.d.nlen = strlen(newpath); | ||||
|  | ||||
|     if (prevexists) { | ||||
|         err = lfs_dir_update(lfs, &newcwd, &newentry, newpath); | ||||
|         err = lfs_dir_update(lfs, &newcwd, &newentry, | ||||
|                 &(struct lfs_region){ | ||||
|                     0, 0, | ||||
|                     lfs_commit_mem, &newentry.d, sizeof(newentry.d), | ||||
|                 &(struct lfs_region){ | ||||
|                     sizeof(newentry.d), 0, | ||||
|                     lfs_commit_mem, newpath, newentry.d.nlen}}); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|     } else { | ||||
|         err = lfs_dir_append(lfs, &newcwd, &newentry, newpath); | ||||
|         err = lfs_dir_append(lfs, &newcwd, &newentry, | ||||
|                 &(struct lfs_region){ | ||||
|                     0, +sizeof(newentry.d), | ||||
|                     lfs_commit_mem, &newentry.d, sizeof(newentry.d), | ||||
|                 &(struct lfs_region){ | ||||
|                     0, +newentry.d.nlen, | ||||
|                     lfs_commit_mem, newpath, newentry.d.nlen}}); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -1993,7 +2126,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|     } | ||||
|  | ||||
|     // if we were a directory, find pred, replace tail | ||||
|     if (prevexists && preventry.d.type == LFS_TYPE_DIR) { | ||||
|     if (prevexists && (0xf & preventry.d.type) == LFS_TYPE_DIR) { | ||||
|         int res = lfs_pred(lfs, dir.pair, &newcwd); | ||||
|         if (res < 0) { | ||||
|             return res; | ||||
| @@ -2003,7 +2136,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|         newcwd.d.tail[0] = dir.d.tail[0]; | ||||
|         newcwd.d.tail[1] = dir.d.tail[1]; | ||||
|  | ||||
|         err = lfs_dir_commit(lfs, &newcwd, NULL, 0); | ||||
|         err = lfs_dir_commit(lfs, &newcwd, NULL); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -2113,7 +2246,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     err = lfs_dir_commit(lfs, &root, NULL, 0); | ||||
|     err = lfs_dir_commit(lfs, &root, NULL); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -2123,8 +2256,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|  | ||||
|     // write superblocks | ||||
|     lfs_superblock_t superblock = { | ||||
|         .off = sizeof(superdir.d), | ||||
|         .d.type = LFS_TYPE_SUPERBLOCK, | ||||
|         .d.type = LFS_STRUCT_DIR | LFS_TYPE_SUPERBLOCK, | ||||
|         .d.elen = sizeof(superblock.d) - sizeof(superblock.d.magic) - 4, | ||||
|         .d.nlen = sizeof(superblock.d.magic), | ||||
|         .d.version = LFS_DISK_VERSION, | ||||
| @@ -2141,10 +2273,9 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     lfs_superblock_tole32(&superblock.d); | ||||
|     bool valid = false; | ||||
|     for (int i = 0; i < 2; i++) { | ||||
|         err = lfs_dir_commit(lfs, &superdir, (struct lfs_region[]){ | ||||
|                 {sizeof(superdir.d), sizeof(superblock.d), | ||||
|                  &superblock.d, sizeof(superblock.d)} | ||||
|             }, 1); | ||||
|         err = lfs_dir_commit(lfs, &superdir, &(struct lfs_region){ | ||||
|                 sizeof(superdir.d), 0, | ||||
|                 lfs_commit_mem, &superblock.d, sizeof(superblock.d)}); | ||||
|         if (err && err != LFS_ERR_CORRUPT) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -2226,8 +2357,6 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { | ||||
|     } | ||||
|  | ||||
|     // iterate over metadata pairs | ||||
|     lfs_dir_t dir; | ||||
|     lfs_entry_t entry; | ||||
|     lfs_block_t cwd[2] = {0, 1}; | ||||
|  | ||||
|     while (true) { | ||||
| @@ -2238,12 +2367,14 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         lfs_dir_t dir; | ||||
|         int err = lfs_dir_fetch(lfs, &dir, cwd); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         // iterate over contents | ||||
|         lfs_entry_t entry; | ||||
|         while (dir.off + sizeof(entry.d) <= (0x7fffffff & dir.d.size)-4) { | ||||
|             err = lfs_bd_read(lfs, dir.pair[0], dir.off, | ||||
|                     &entry.d, sizeof(entry.d)); | ||||
| @@ -2252,8 +2383,8 @@ int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) { | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
|             dir.off += lfs_entry_size(&entry); | ||||
|             if ((0x70 & entry.d.type) == (0x70 & LFS_TYPE_REG)) { | ||||
|             dir.off += 4 + entry.d.elen + entry.d.alen + entry.d.nlen; | ||||
|             if ((0x70 & entry.d.type) == LFS_STRUCT_CTZ) { | ||||
|                 err = lfs_ctz_traverse(lfs, &lfs->rcache, NULL, | ||||
|                         entry.d.u.file.head, entry.d.u.file.size, cb, data); | ||||
|                 if (err) { | ||||
| @@ -2343,7 +2474,7 @@ static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2], | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             if (((0x70 & entry->d.type) == (0x70 & LFS_TYPE_DIR)) && | ||||
|             if (((0x70 & entry->d.type) == LFS_STRUCT_DIR) && | ||||
|                  lfs_paircmp(entry->d.u.dir, dir) == 0) { | ||||
|                 return true; | ||||
|             } | ||||
| @@ -2383,7 +2514,7 @@ static int lfs_moved(lfs_t *lfs, const void *e) { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             if (!(0x80 & entry.d.type) && | ||||
|             if (!(LFS_STRUCT_MOVED & entry.d.type) && | ||||
|                  memcmp(&entry.d.u, e, sizeof(entry.d.u)) == 0) { | ||||
|                 return true; | ||||
|             } | ||||
| @@ -2408,7 +2539,10 @@ static int lfs_relocate(lfs_t *lfs, | ||||
|         entry.d.u.dir[0] = newpair[0]; | ||||
|         entry.d.u.dir[1] = newpair[1]; | ||||
|  | ||||
|         int err = lfs_dir_update(lfs, &parent, &entry, NULL); | ||||
|         int err = lfs_dir_update(lfs, &parent, &entry, | ||||
|                 &(struct lfs_region){ | ||||
|                     0, 0, | ||||
|                     lfs_commit_mem, &entry.d, sizeof(entry.d)}); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -2435,7 +2569,7 @@ static int lfs_relocate(lfs_t *lfs, | ||||
|         parent.d.tail[0] = newpair[0]; | ||||
|         parent.d.tail[1] = newpair[1]; | ||||
|  | ||||
|         return lfs_dir_commit(lfs, &parent, NULL, 0); | ||||
|         return lfs_dir_commit(lfs, &parent, NULL); | ||||
|     } | ||||
|  | ||||
|     // couldn't find dir, must be new | ||||
| @@ -2477,7 +2611,7 @@ int lfs_deorphan(lfs_t *lfs) { | ||||
|                 pdir.d.tail[0] = cwd.d.tail[0]; | ||||
|                 pdir.d.tail[1] = cwd.d.tail[1]; | ||||
|  | ||||
|                 err = lfs_dir_commit(lfs, &pdir, NULL, 0); | ||||
|                 err = lfs_dir_commit(lfs, &pdir, NULL); | ||||
|                 if (err) { | ||||
|                     return err; | ||||
|                 } | ||||
| @@ -2493,7 +2627,7 @@ int lfs_deorphan(lfs_t *lfs) { | ||||
|                 pdir.d.tail[0] = entry.d.u.dir[0]; | ||||
|                 pdir.d.tail[1] = entry.d.u.dir[1]; | ||||
|  | ||||
|                 err = lfs_dir_commit(lfs, &pdir, NULL, 0); | ||||
|                 err = lfs_dir_commit(lfs, &pdir, NULL); | ||||
|                 if (err) { | ||||
|                     return err; | ||||
|                 } | ||||
| @@ -2515,7 +2649,7 @@ int lfs_deorphan(lfs_t *lfs) { | ||||
|             } | ||||
|  | ||||
|             // found moved entry | ||||
|             if (entry.d.type & 0x80) { | ||||
|             if (entry.d.type & LFS_STRUCT_MOVED) { | ||||
|                 int moved = lfs_moved(lfs, &entry.d.u); | ||||
|                 if (moved < 0) { | ||||
|                     return moved; | ||||
| @@ -2531,8 +2665,11 @@ int lfs_deorphan(lfs_t *lfs) { | ||||
|                 } else { | ||||
|                     LFS_DEBUG("Found partial move %d %d", | ||||
|                             entry.d.u.dir[0], entry.d.u.dir[1]); | ||||
|                     entry.d.type &= ~0x80; | ||||
|                     err = lfs_dir_update(lfs, &cwd, &entry, NULL); | ||||
|                     entry.d.type &= ~LFS_STRUCT_MOVED; | ||||
|                     err = lfs_dir_update(lfs, &cwd, &entry, | ||||
|                             &(struct lfs_region){ | ||||
|                                 0, 0, | ||||
|                                 lfs_commit_mem, &entry.d, sizeof(entry.d)}); | ||||
|                     if (err) { | ||||
|                         return err; | ||||
|                     } | ||||
|   | ||||
							
								
								
									
										15
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -74,9 +74,15 @@ enum lfs_error { | ||||
|  | ||||
| // File types | ||||
| enum lfs_type { | ||||
|     LFS_TYPE_REG        = 0x11, | ||||
|     LFS_TYPE_DIR        = 0x22, | ||||
|     LFS_TYPE_SUPERBLOCK = 0x2e, | ||||
|     // file type | ||||
|     LFS_TYPE_REG        = 0x01, | ||||
|     LFS_TYPE_DIR        = 0x02, | ||||
|     LFS_TYPE_SUPERBLOCK = 0x0e, | ||||
|  | ||||
|     // on disk structure | ||||
|     LFS_STRUCT_CTZ      = 0x10, | ||||
|     LFS_STRUCT_DIR      = 0x20, | ||||
|     LFS_STRUCT_MOVED    = 0x80, | ||||
| }; | ||||
|  | ||||
| // File open flags | ||||
| @@ -190,6 +196,7 @@ struct lfs_info { | ||||
| /// littlefs data structures /// | ||||
| typedef struct lfs_entry { | ||||
|     lfs_off_t off; | ||||
|     lfs_size_t size; | ||||
|  | ||||
|     struct lfs_disk_entry { | ||||
|         uint8_t type; | ||||
| @@ -243,8 +250,6 @@ typedef struct lfs_dir { | ||||
| } lfs_dir_t; | ||||
|  | ||||
| typedef struct lfs_superblock { | ||||
|     lfs_off_t off; | ||||
|  | ||||
|     struct lfs_disk_superblock { | ||||
|         uint8_t type; | ||||
|         uint8_t elen; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user