mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	More progress integrating journaling
- Integrated into lfs_file_t_, duplicating functions where necessary - Added lfs_dir_fetchwith_ as common parent to both lfs_dir_fetch_ and lfs_dir_find_ - Added similar parent with lfs_dir_commitwith_ - Made matching find/get operations with getbuffer/getentry and findbuffer/findentry - lfs_dir_alloc now populates tail, since almost all directory block allocations need to populate tail
This commit is contained in:
		
							
								
								
									
										640
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										640
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -637,7 +637,8 @@ static int lfs_commit_crc(lfs_t *lfs, struct lfs_commit *commit) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*static*/ int lfs_dir_alloc_(lfs_t *lfs, lfs_dir_t_ *dir) { | /*static*/ int lfs_dir_alloc_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|  |         const lfs_block_t tail[2]) { | ||||||
|     // allocate pair of dir blocks (backwards, so we write to block 1 first) |     // allocate pair of dir blocks (backwards, so we write to block 1 first) | ||||||
|     for (int i = 0; i < 2; i++) { |     for (int i = 0; i < 2; i++) { | ||||||
|         int err = lfs_alloc(lfs, &dir->pair[(i+1)%2]); |         int err = lfs_alloc(lfs, &dir->pair[(i+1)%2]); | ||||||
| @@ -658,8 +659,8 @@ static int lfs_commit_crc(lfs_t *lfs, struct lfs_commit *commit) { | |||||||
|     dir->off = sizeof(dir->rev); |     dir->off = sizeof(dir->rev); | ||||||
|     dir->etag = 0; |     dir->etag = 0; | ||||||
|     dir->count = 0; |     dir->count = 0; | ||||||
|     dir->tail[0] = 0xffffffff; |     dir->tail[0] = tail[0]; | ||||||
|     dir->tail[1] = 0xffffffff; |     dir->tail[1] = tail[1]; | ||||||
|     dir->erased = false; |     dir->erased = false; | ||||||
|     dir->split = false; |     dir->split = false; | ||||||
|  |  | ||||||
| @@ -667,7 +668,7 @@ static int lfs_commit_crc(lfs_t *lfs, struct lfs_commit *commit) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*static*/ int lfs_dir_fetch_(lfs_t *lfs, | /*static*/ int lfs_dir_fetchwith_(lfs_t *lfs, | ||||||
|         lfs_dir_t_ *dir, const lfs_block_t pair[2], |         lfs_dir_t_ *dir, const lfs_block_t pair[2], | ||||||
|         int (*cb)(lfs_t *lfs, void *data, lfs_entry_t_ entry), |         int (*cb)(lfs_t *lfs, void *data, lfs_entry_t_ entry), | ||||||
|         void *data) { |         void *data) { | ||||||
| @@ -762,7 +763,9 @@ static int lfs_commit_crc(lfs_t *lfs, struct lfs_commit *commit) { | |||||||
|                     dir->count = lfs_tag_id(tag)+1; |                     dir->count = lfs_tag_id(tag)+1; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 if (lfs_tag_type(tag) == LFS_TYPE_TAIL_) { |                 if (lfs_tag_type(tag) == LFS_TYPE_SOFTTAIL_ || | ||||||
|  |                         lfs_tag_type(tag) == LFS_TYPE_HARDTAIL_) { | ||||||
|  |                     dir->split = lfs_tag_type(tag) == LFS_TYPE_HARDTAIL_; | ||||||
|                     err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag), |                     err = lfs_bd_read(lfs, dir->pair[0], off+sizeof(tag), | ||||||
|                             dir->tail, sizeof(dir->tail)); |                             dir->tail, sizeof(dir->tail)); | ||||||
|                     if (err) { |                     if (err) { | ||||||
| @@ -792,6 +795,11 @@ static int lfs_commit_crc(lfs_t *lfs, struct lfs_commit *commit) { | |||||||
|     return LFS_ERR_CORRUPT; |     return LFS_ERR_CORRUPT; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /*static*/ int lfs_dir_fetch_(lfs_t *lfs, | ||||||
|  |         lfs_dir_t_ *dir, const lfs_block_t pair[2]) { | ||||||
|  |     return lfs_dir_fetchwith_(lfs, dir, pair, NULL, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
| static int lfs_dir_traverse_(lfs_t *lfs, lfs_dir_t_ *dir, | static int lfs_dir_traverse_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|         int (*cb)(lfs_t *lfs, void *data, lfs_entry_t_ entry), |         int (*cb)(lfs_t *lfs, void *data, lfs_entry_t_ entry), | ||||||
|         void *data) { |         void *data) { | ||||||
| @@ -800,49 +808,6 @@ static int lfs_dir_traverse_(lfs_t *lfs, lfs_dir_t_ *dir, | |||||||
|             cb, data); |             cb, data); | ||||||
| } | } | ||||||
|  |  | ||||||
| struct lfs_dir_getter { |  | ||||||
|     uint32_t mask; |  | ||||||
|     lfs_entry_t_ entry; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static int lfs_dir_getter(lfs_t *lfs, void *p, lfs_entry_t_ entry) { |  | ||||||
|     struct lfs_dir_getter *get = p; |  | ||||||
|     if ((entry.tag & get->mask) == (get->entry.tag & get->mask)) { |  | ||||||
|         int err = lfs_bd_read(lfs, entry.u.d.block, entry.u.d.off, |  | ||||||
|                 get->entry.u.buffer, lfs_min(lfs_tag_size(entry.tag), |  | ||||||
|                     lfs_tag_size(get->entry.tag))); |  | ||||||
|         if (err) { |  | ||||||
|             return err; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         get->entry.tag |= entry.tag & ~0x80000fff; |  | ||||||
|         if (lfs_tag_size(entry.tag) > lfs_tag_size(get->entry.tag)) { |  | ||||||
|             return LFS_ERR_RANGE; |  | ||||||
|         } else { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /*static*/ int lfs_dir_get_(lfs_t *lfs, lfs_dir_t_ *dir, |  | ||||||
|         uint32_t mask, lfs_entry_t_ *entry) { |  | ||||||
|     struct lfs_dir_getter get = {mask, *entry}; |  | ||||||
|     memset(get.entry.u.buffer, 0, lfs_tag_size(get.entry.tag)); |  | ||||||
|     int res = lfs_dir_traverse_(lfs, dir, lfs_dir_getter, &get); |  | ||||||
|     entry->tag = get.entry.tag; |  | ||||||
|     if (res < 0) { |  | ||||||
|         return res; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (!res) { |  | ||||||
|         return LFS_ERR_NOENT; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| struct lfs_dir_mover { | struct lfs_dir_mover { | ||||||
|     // traversal things |     // traversal things | ||||||
|     lfs_dir_t_ *dir; |     lfs_dir_t_ *dir; | ||||||
| @@ -964,7 +929,8 @@ int lfs_dir_mover(lfs_t *lfs, void *p, struct lfs_commit *commit) { | |||||||
|                 // TODO le32 |                 // TODO le32 | ||||||
|                 commit.end = lfs->cfg->block_size - 2*sizeof(uint32_t), |                 commit.end = lfs->cfg->block_size - 2*sizeof(uint32_t), | ||||||
|                 err = lfs_commit_commit(lfs, &commit, (lfs_entry_t_){ |                 err = lfs_commit_commit(lfs, &commit, (lfs_entry_t_){ | ||||||
|                         lfs_mktag(LFS_TYPE_TAIL_, 0x1ff, sizeof(dir->tail)), |                         lfs_mktag(LFS_TYPE_SOFTTAIL_ + dir->split, | ||||||
|  |                             0x1ff, sizeof(dir->tail)), | ||||||
|                         .u.buffer=dir->tail}); |                         .u.buffer=dir->tail}); | ||||||
|                 if (err) { |                 if (err) { | ||||||
|                     if (err == LFS_ERR_CORRUPT) { |                     if (err == LFS_ERR_CORRUPT) { | ||||||
| @@ -999,14 +965,11 @@ split: | |||||||
|         lfs->pcache.block = 0xffffffff; |         lfs->pcache.block = 0xffffffff; | ||||||
|  |  | ||||||
|         lfs_dir_t_ tail; |         lfs_dir_t_ tail; | ||||||
|         int err = lfs_dir_alloc_(lfs, &tail); |         int err = lfs_dir_alloc_(lfs, &tail, dir->tail); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         tail.tail[0] = dir->tail[0]; |  | ||||||
|         tail.tail[1] = dir->tail[1]; |  | ||||||
|  |  | ||||||
|         err = lfs_dir_compact_(lfs, &tail, lfs_dir_mover, &mover); |         err = lfs_dir_compact_(lfs, &tail, lfs_dir_mover, &mover); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
| @@ -1061,7 +1024,7 @@ relocate: | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*static*/ int lfs_dir_commit_(lfs_t *lfs, lfs_dir_t_ *dir, | /*static*/ int lfs_dir_commitwith_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|         int (*cb)(lfs_t *lfs, void *data, struct lfs_commit *commit), |         int (*cb)(lfs_t *lfs, void *data, struct lfs_commit *commit), | ||||||
|         void *data) { |         void *data) { | ||||||
|     if (!dir->erased) { |     if (!dir->erased) { | ||||||
| @@ -1101,43 +1064,13 @@ relocate: | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| //struct lfs_dir_commit_regions { | struct lfs_dir_committer { | ||||||
| //    const lfs_entry_t_ *regions; |  | ||||||
| //    int count; |  | ||||||
| //}; |  | ||||||
| // |  | ||||||
| //int lfs_dir_commit_regions(lfs_t *lfs, void *p, struct lfs_commit *commit) { |  | ||||||
| //    struct lfs_dir_commit_regions *entry = p; |  | ||||||
| //    for (int i = 0; i < entry->count; i++) { |  | ||||||
| //        int err = lfs_commit_commit(lfs, commit, entry->regions[i]); |  | ||||||
| //        if (err) { |  | ||||||
| //            return err; |  | ||||||
| //        } |  | ||||||
| //    } |  | ||||||
| // |  | ||||||
| //    return 0; |  | ||||||
| //} |  | ||||||
| // |  | ||||||
| // TODO rm me, just for testing |  | ||||||
| ///*static*/ int lfs_dir_compact_(lfs_t *lfs, lfs_dir_t_ *dir, |  | ||||||
| //        const lfs_entry_t_ *regions, int count) { |  | ||||||
| //    return lfs_dir_compact_(lfs, dir, lfs_dir_commit_regions, |  | ||||||
| //        &(struct lfs_dir_commit_regions){regions, count}); |  | ||||||
| //} |  | ||||||
| // |  | ||||||
| ///*static*/ int lfs_dir_commit_(lfs_t *lfs, lfs_dir_t_ *dir, |  | ||||||
| //        const lfs_entry_t_ *regions, int count) { |  | ||||||
| //    return lfs_dir_commit_(lfs, dir, lfs_dir_commit_regions, |  | ||||||
| //        &(struct lfs_dir_commit_regions){regions, count}); |  | ||||||
| //} |  | ||||||
|  |  | ||||||
| struct lfs_dir_setter { |  | ||||||
|     const lfs_entry_t_ *regions; |     const lfs_entry_t_ *regions; | ||||||
|     int count; |     int count; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| int lfs_dir_setter(lfs_t *lfs, void *p, struct lfs_commit *commit) { | int lfs_dir_committer(lfs_t *lfs, void *p, struct lfs_commit *commit) { | ||||||
|     struct lfs_dir_setter *set = p; |     struct lfs_dir_committer *set = p; | ||||||
|     for (int i = 0; i < set->count; i++) { |     for (int i = 0; i < set->count; i++) { | ||||||
|         int err = lfs_commit_commit(lfs, commit, set->regions[i]); |         int err = lfs_commit_commit(lfs, commit, set->regions[i]); | ||||||
|         if (err) { |         if (err) { | ||||||
| @@ -1148,20 +1081,12 @@ int lfs_dir_setter(lfs_t *lfs, void *p, struct lfs_commit *commit) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*static*/ int lfs_dir_set_(lfs_t *lfs, lfs_dir_t_ *dir, | /*static*/ int lfs_dir_commit_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|         const lfs_entry_t_ *regions, int count) { |         const lfs_entry_t_ *regions, int count) { | ||||||
|     return lfs_dir_commit_(lfs, dir, lfs_dir_setter, |     return lfs_dir_commitwith_(lfs, dir, lfs_dir_committer, | ||||||
|         &(struct lfs_dir_setter){regions, count}); |         &(struct lfs_dir_committer){regions, count}); | ||||||
| } | } | ||||||
|  |  | ||||||
| struct lfs_dir_finder { |  | ||||||
|     const char *name; |  | ||||||
|     lfs_size_t len; |  | ||||||
|  |  | ||||||
|     int16_t id; |  | ||||||
|     lfs_entry_t_ *entry; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| /*static*/ int lfs_dir_add(lfs_t *lfs, lfs_dir_t_ *dir, uint16_t *id) { | /*static*/ int lfs_dir_add(lfs_t *lfs, lfs_dir_t_ *dir, uint16_t *id) { | ||||||
|     *id = dir->count; |     *id = dir->count; | ||||||
|     dir->count += 1; |     dir->count += 1; | ||||||
| @@ -1171,10 +1096,80 @@ struct lfs_dir_finder { | |||||||
| /*static*/ int lfs_dir_drop(lfs_t *lfs, lfs_dir_t_ *dir, uint16_t id) { | /*static*/ int lfs_dir_drop(lfs_t *lfs, lfs_dir_t_ *dir, uint16_t id) { | ||||||
|     dir->count -= 1; |     dir->count -= 1; | ||||||
|     // TODO compact during traverse when compacting? |     // TODO compact during traverse when compacting? | ||||||
|     return lfs_dir_set_(lfs, dir, (lfs_entry_t_[]){{ |     return lfs_dir_commit_(lfs, dir, (lfs_entry_t_[]){{ | ||||||
|             lfs_mktag(LFS_TYPE_DROP_, id, 0)}}, 1); |             lfs_mktag(LFS_TYPE_DROP_, id, 0)}}, 1); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | struct lfs_dir_getter { | ||||||
|  |     uint32_t mask; | ||||||
|  |     lfs_tag_t tag; | ||||||
|  |     lfs_entry_t_ *entry; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int lfs_dir_getter(lfs_t *lfs, void *p, lfs_entry_t_ entry) { | ||||||
|  |     struct lfs_dir_getter *get = p; | ||||||
|  |     if ((entry.tag & get->mask) == (get->tag & get->mask)) { | ||||||
|  |         if (get->entry) { | ||||||
|  |             *get->entry = entry; | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*static*/ int lfs_dir_get_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|  |         uint32_t mask, lfs_tag_t tag, lfs_entry_t_ *entry) { | ||||||
|  |     int res = lfs_dir_traverse_(lfs, dir, lfs_dir_getter, | ||||||
|  |             &(struct lfs_dir_getter){mask, tag, entry}); | ||||||
|  |     if (res < 0) { | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!res) { | ||||||
|  |         return LFS_ERR_NOENT; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*static*/ int lfs_dir_getbuffer_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|  |         uint32_t mask, lfs_tag_t tag, lfs_entry_t_ *entry) { | ||||||
|  |     void *buffer = entry->u.buffer; | ||||||
|  |     lfs_size_t size = lfs_tag_size(tag); | ||||||
|  |     int err = lfs_dir_get_(lfs, dir, mask, tag, entry); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     lfs_size_t diff = lfs_min(size, lfs_tag_size(entry->tag)); | ||||||
|  |     memset((uint8_t*)buffer + diff, 0, size - diff); | ||||||
|  |     err = lfs_bd_read(lfs, entry->u.d.block, entry->u.d.off, buffer, diff); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (lfs_tag_size(entry->tag) > size) { | ||||||
|  |         return LFS_ERR_RANGE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*static*/ int lfs_dir_getentry_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|  |         uint32_t mask, lfs_tag_t tag, lfs_entry_t_ *entry) { | ||||||
|  |     entry->u.buffer = &entry->u; | ||||||
|  |     return lfs_dir_getbuffer_(lfs, dir, mask, tag, entry); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct lfs_dir_finder { | ||||||
|  |     const char *name; | ||||||
|  |     lfs_size_t len; | ||||||
|  |  | ||||||
|  |     int16_t id; | ||||||
|  |     lfs_entry_t_ *entry; | ||||||
|  | }; | ||||||
|  |  | ||||||
| static int lfs_dir_finder(lfs_t *lfs, void *p, lfs_entry_t_ entry) { | static int lfs_dir_finder(lfs_t *lfs, void *p, lfs_entry_t_ entry) { | ||||||
|     struct lfs_dir_finder *find = p; |     struct lfs_dir_finder *find = p; | ||||||
|  |  | ||||||
| @@ -1194,26 +1189,15 @@ static int lfs_dir_finder(lfs_t *lfs, void *p, lfs_entry_t_ entry) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (find->id >= 0 && lfs_tag_id(entry.tag) == find->id && |     if (find->id >= 0 && lfs_tag_id(entry.tag) == find->id && | ||||||
|             (lfs_tag_type(entry.tag) & 0x1c0) == LFS_TYPE_REG_) { |             lfs_tag_supertype(entry.tag) == LFS_TYPE_REG_) { | ||||||
|         // TODO combine regions and entries? |         *find->entry = entry; | ||||||
|         find->entry->tag = ~0x80000000 & entry.tag; |  | ||||||
|         if (lfs_tag_type(entry.tag) & 0x00f) { |  | ||||||
|             int err = lfs_bd_read(lfs, entry.u.d.block, entry.u.d.off, |  | ||||||
|                     &find->entry->u, sizeof(find->entry->u)); |  | ||||||
|             if (err) { |  | ||||||
|                 return err; |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             find->entry->u.d.block = entry.u.d.block; |  | ||||||
|             find->entry->u.d.off = entry.u.d.off; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| /*static*/ int lfs_dir_find_(lfs_t *lfs, lfs_dir_t_ *dir, | /*static*/ int lfs_dir_find_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|         lfs_entry_t_ *entry, const char **path) { |         const char **path, lfs_entry_t_ *entry) { | ||||||
|     struct lfs_dir_finder find = { |     struct lfs_dir_finder find = { | ||||||
|         .name = *path, |         .name = *path, | ||||||
|         .entry = entry, |         .entry = entry, | ||||||
| @@ -1275,7 +1259,7 @@ static int lfs_dir_finder(lfs_t *lfs, void *p, lfs_entry_t_ entry) { | |||||||
|         // find path |         // find path | ||||||
|         while (true) { |         while (true) { | ||||||
|             find.id = -1; |             find.id = -1; | ||||||
|             int err = lfs_dir_fetch_(lfs, dir, entry->u.pair, |             int err = lfs_dir_fetchwith_(lfs, dir, entry->u.pair, | ||||||
|                     lfs_dir_finder, &find); |                     lfs_dir_finder, &find); | ||||||
|             if (err) { |             if (err) { | ||||||
|                 return err; |                 return err; | ||||||
| @@ -1319,6 +1303,36 @@ static int lfs_dir_finder(lfs_t *lfs, void *p, lfs_entry_t_ entry) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /*static*/ int lfs_dir_findbuffer_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|  |         const char **path, lfs_entry_t_ *entry) { | ||||||
|  |     void *buffer = entry->u.buffer; | ||||||
|  |     lfs_size_t size = lfs_tag_size(entry->tag); | ||||||
|  |     int err = lfs_dir_find_(lfs, dir, path, entry); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     lfs_size_t diff = lfs_min(size, lfs_tag_size(entry->tag)); | ||||||
|  |     memset((uint8_t*)buffer + diff, 0, size - diff); | ||||||
|  |     err = lfs_bd_read(lfs, entry->u.d.block, entry->u.d.off, buffer, diff); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (lfs_tag_size(entry->tag) > size) { | ||||||
|  |         return LFS_ERR_RANGE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /*static*/ int lfs_dir_findentry_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|  |         const char **path, lfs_entry_t_ *entry) { | ||||||
|  |     entry->tag = sizeof(entry->u); | ||||||
|  |     entry->u.buffer = &entry->u; | ||||||
|  |     return lfs_dir_findbuffer_(lfs, dir, path, entry); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| ////////////////////////////////////////////////////////// | ////////////////////////////////////////////////////////// | ||||||
|  |  | ||||||
| @@ -2124,8 +2138,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | |||||||
|  |  | ||||||
|     // fetch parent directory |     // fetch parent directory | ||||||
|     lfs_dir_t_ cwd; |     lfs_dir_t_ cwd; | ||||||
|     lfs_entry_t_ entry; |     int err = lfs_dir_findentry_(lfs, &cwd, &path, &(lfs_entry_t_){0}); | ||||||
|     int err = lfs_dir_find_(lfs, &cwd, &entry, &path); |  | ||||||
|     if (err != LFS_ERR_NOENT || strchr(path, '/') != NULL) { |     if (err != LFS_ERR_NOENT || strchr(path, '/') != NULL) { | ||||||
|         if (!err) { |         if (!err) { | ||||||
|             return LFS_ERR_EXIST; |             return LFS_ERR_EXIST; | ||||||
| @@ -2143,14 +2156,12 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | |||||||
|     lfs_alloc_ack(lfs); |     lfs_alloc_ack(lfs); | ||||||
|  |  | ||||||
|     lfs_dir_t_ dir; |     lfs_dir_t_ dir; | ||||||
|     err = lfs_dir_alloc_(lfs, &dir); // TODO add tail to this function? |     err = lfs_dir_alloc_(lfs, &dir, cwd.tail); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|     dir.tail[0] = cwd.tail[0]; |  | ||||||
|     dir.tail[1] = cwd.tail[1]; |  | ||||||
|  |  | ||||||
|     err = lfs_dir_set_(lfs, &dir, NULL, 0); |     err = lfs_dir_commit_(lfs, &dir, NULL, 0); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -2162,8 +2173,8 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | |||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     err = lfs_dir_set_(lfs, &cwd, (lfs_entry_t_[]){ |     err = lfs_dir_commit_(lfs, &cwd, (lfs_entry_t_[]){ | ||||||
|             {lfs_mktag(LFS_TYPE_NAME_, id, nlen), .u.buffer=path}, |             {lfs_mktag(LFS_TYPE_NAME_, id, nlen), .u.buffer=(void*)path}, | ||||||
|             {lfs_mktag(LFS_TYPE_DIR_ | LFS_STRUCT_DIR_, id, |             {lfs_mktag(LFS_TYPE_DIR_ | LFS_STRUCT_DIR_, id, | ||||||
|                 sizeof(dir.pair)), .u.buffer=dir.pair}}, 2); |                 sizeof(dir.pair)), .u.buffer=dir.pair}}, 2); | ||||||
|  |  | ||||||
| @@ -2242,7 +2253,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | |||||||
|  |  | ||||||
| int lfs_dir_open_(lfs_t *lfs, lfs_dir_t_ *dir, const char *path) { | int lfs_dir_open_(lfs_t *lfs, lfs_dir_t_ *dir, const char *path) { | ||||||
|     lfs_entry_t_ entry; |     lfs_entry_t_ entry; | ||||||
|     int err = lfs_dir_find_(lfs, dir, &entry, &path); |     int err = lfs_dir_findentry_(lfs, dir, &path, &entry); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -2251,7 +2262,7 @@ int lfs_dir_open_(lfs_t *lfs, lfs_dir_t_ *dir, const char *path) { | |||||||
|         return LFS_ERR_NOTDIR; |         return LFS_ERR_NOTDIR; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     err = lfs_dir_fetch_(lfs, dir, entry.u.pair, NULL, NULL); |     err = lfs_dir_fetch_(lfs, dir, entry.u.pair); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -2284,24 +2295,23 @@ int lfs_dir_close_(lfs_t *lfs, lfs_dir_t_ *dir) { | |||||||
| // TODO move me? | // TODO move me? | ||||||
| static int lfs_dir_getinfo_(lfs_t *lfs, lfs_dir_t_ *dir, | static int lfs_dir_getinfo_(lfs_t *lfs, lfs_dir_t_ *dir, | ||||||
|         uint16_t id, struct lfs_info *info) { |         uint16_t id, struct lfs_info *info) { | ||||||
|     lfs_entry_t_ entry = {lfs_mktag(LFS_TYPE_REG, id, 8), .u.buffer=&entry.u}; |     lfs_entry_t_ entry; | ||||||
|     int err = lfs_dir_get_(lfs, dir, 0x701ff000, &entry); |     int err = lfs_dir_getentry_(lfs, dir, | ||||||
|  |             0x701ff000, lfs_mktag(LFS_TYPE_REG, id, 8), &entry); | ||||||
|     if (err && err != LFS_ERR_RANGE) { |     if (err && err != LFS_ERR_RANGE) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     info->type = lfs_tag_subtype(entry.tag); |     info->type = lfs_tag_subtype(entry.tag); | ||||||
|     if (lfs_tag_type(entry.tag) == |     if (lfs_tag_type(entry.tag) == (LFS_TYPE_REG_ | LFS_STRUCT_CTZ_)) { | ||||||
|             (LFS_TYPE_REG_ | LFS_STRUCT_CTZ_)) { |  | ||||||
|         info->size = entry.u.ctz.size; |         info->size = entry.u.ctz.size; | ||||||
|     } else if (lfs_tag_type(entry.tag) == |     } else if (lfs_tag_type(entry.tag) == (LFS_TYPE_REG_ | LFS_STRUCT_INLINE_)) { | ||||||
|             (LFS_TYPE_REG_ | LFS_STRUCT_INLINE_)) { |  | ||||||
|         info->size = lfs_tag_size(entry.tag); |         info->size = lfs_tag_size(entry.tag); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     err = lfs_dir_get_(lfs, dir, 0x7ffff000, &(lfs_entry_t_){ |     err = lfs_dir_getbuffer_(lfs, dir, | ||||||
|             lfs_mktag(LFS_TYPE_NAME_, id, lfs->cfg->name_size), |             0x7ffff000, lfs_mktag(LFS_TYPE_NAME_, id, lfs->cfg->name_size+1), | ||||||
|             .u.buffer=info->name}); |             &(lfs_entry_t_){.u.buffer=info->name}); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -2331,7 +2341,7 @@ int lfs_dir_read_(lfs_t *lfs, lfs_dir_t_ *dir, struct lfs_info *info) { | |||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             int err = lfs_dir_fetch_(lfs, dir, dir->tail, NULL, NULL); |             int err = lfs_dir_fetch_(lfs, dir, dir->tail); | ||||||
|             if (err) { |             if (err) { | ||||||
|                 return err; |                 return err; | ||||||
|             } |             } | ||||||
| @@ -2687,6 +2697,119 @@ static int lfs_ctz_traverse(lfs_t *lfs, | |||||||
|  |  | ||||||
|  |  | ||||||
| /// Top level file operations /// | /// Top level file operations /// | ||||||
|  | int lfs_file_open_(lfs_t *lfs, lfs_file_t_ *file, | ||||||
|  |         const char *path, int flags) { | ||||||
|  |     // deorphan if we haven't yet, needed at most once after poweron | ||||||
|  |     if ((flags & 3) != LFS_O_RDONLY && !lfs->deorphaned) { | ||||||
|  |         int err = lfs_deorphan_(lfs); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // allocate entry for file if it doesn't exist | ||||||
|  |     lfs_dir_t_ cwd; | ||||||
|  |     lfs_entry_t_ entry; | ||||||
|  |     int err = lfs_dir_find_(lfs, &cwd, &path, &entry); | ||||||
|  |     if (err && (err != LFS_ERR_NOENT || strchr(path, '/') != NULL)) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (err == LFS_ERR_NOENT) { | ||||||
|  |         if (!(flags & LFS_O_CREAT)) { | ||||||
|  |             return LFS_ERR_NOENT; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // check that name fits | ||||||
|  |         lfs_size_t nlen = strlen(path); | ||||||
|  |         if (nlen > lfs->name_size) { | ||||||
|  |             return LFS_ERR_NAMETOOLONG; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // get next slot and create entry to remember name | ||||||
|  |         uint16_t id; | ||||||
|  |         err = lfs_dir_add(lfs, &cwd, &id); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         err = lfs_dir_commit_(lfs, &cwd, (lfs_entry_t_[]){ | ||||||
|  |                 {lfs_mktag(LFS_TYPE_NAME_, id, nlen), .u.buffer=(void*)path}, | ||||||
|  |                 {lfs_mktag(LFS_TYPE_REG_ | LFS_STRUCT_INLINE_, id, 0)}}, 2); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |     } else if (lfs_tag_subtype(entry.tag) != LFS_TYPE_REG_) { | ||||||
|  |         return LFS_ERR_ISDIR; | ||||||
|  |     } else if (flags & LFS_O_EXCL) { | ||||||
|  |         return LFS_ERR_EXIST; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // allocate buffer if needed | ||||||
|  |     file->cache.block = 0xffffffff; | ||||||
|  |     if (lfs->cfg->file_buffer) { | ||||||
|  |         file->cache.buffer = lfs->cfg->file_buffer; | ||||||
|  |     } else if ((file->flags & 3) == LFS_O_RDONLY) { | ||||||
|  |         file->cache.buffer = lfs_malloc(lfs->cfg->read_size); | ||||||
|  |         if (!file->cache.buffer) { | ||||||
|  |             return LFS_ERR_NOMEM; | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         file->cache.buffer = lfs_malloc(lfs->cfg->prog_size); | ||||||
|  |         if (!file->cache.buffer) { | ||||||
|  |             return LFS_ERR_NOMEM; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // setup file struct | ||||||
|  |     file->pair[0] = cwd.pair[0]; | ||||||
|  |     file->pair[1] = cwd.pair[1]; | ||||||
|  |     file->id = lfs_tag_id(entry.tag); | ||||||
|  |     file->flags = flags; | ||||||
|  |     file->pos = 0; | ||||||
|  |  | ||||||
|  |     if (lfs_tag_struct(entry.tag) == LFS_STRUCT_INLINE_) { | ||||||
|  |         // load inline files | ||||||
|  |         file->head = 0xfffffffe; | ||||||
|  |         file->size = lfs_tag_size(entry.tag); | ||||||
|  |         file->flags |= LFS_F_INLINE; | ||||||
|  |         file->cache.block = file->head; | ||||||
|  |         file->cache.off = 0; | ||||||
|  |         err = lfs_bd_read(lfs, entry.u.d.block, entry.u.d.off, | ||||||
|  |                 file->cache.buffer, file->size); | ||||||
|  |         if (err) { | ||||||
|  |             lfs_free(file->cache.buffer); | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         // use ctz list from entry | ||||||
|  |         err = lfs_bd_read(lfs, entry.u.d.block, entry.u.d.off, | ||||||
|  |                 &entry.u, sizeof(entry.u)); | ||||||
|  |         // TODO move to disk struct directly? | ||||||
|  |         file->head = entry.u.ctz.head; | ||||||
|  |         file->size = entry.u.ctz.size; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // truncate if requested | ||||||
|  |     if (flags & LFS_O_TRUNC) { | ||||||
|  |         if (file->size != 0) { | ||||||
|  |             file->flags |= LFS_F_DIRTY; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         file->head = 0xfffffffe; | ||||||
|  |         file->size = 0; | ||||||
|  |         file->flags |= LFS_F_INLINE; | ||||||
|  |         file->cache.block = file->head; | ||||||
|  |         file->cache.off = 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // add to list of files | ||||||
|  |     file->next = lfs->files; | ||||||
|  |     lfs->files = file; | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||||
|         const char *path, int flags) { |         const char *path, int flags) { | ||||||
|     // deorphan if we haven't yet, needed at most once after poweron |     // deorphan if we haven't yet, needed at most once after poweron | ||||||
| @@ -2827,6 +2950,52 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | |||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int lfs_file_relocate_(lfs_t *lfs, lfs_file_t_ *file) { | ||||||
|  | relocate:; | ||||||
|  |     // just relocate what exists into new block | ||||||
|  |     lfs_block_t nblock; | ||||||
|  |     int err = lfs_alloc(lfs, &nblock); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     err = lfs_bd_erase(lfs, nblock); | ||||||
|  |     if (err) { | ||||||
|  |         if (err == LFS_ERR_CORRUPT) { | ||||||
|  |             goto relocate; | ||||||
|  |         } | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // either read from dirty cache or disk | ||||||
|  |     for (lfs_off_t i = 0; i < file->off; i++) { | ||||||
|  |         uint8_t data; | ||||||
|  |         err = lfs_cache_read(lfs, &lfs->rcache, &file->cache, | ||||||
|  |                 file->block, i, &data, 1); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         err = lfs_cache_prog(lfs, &lfs->pcache, &lfs->rcache, | ||||||
|  |                 nblock, i, &data, 1); | ||||||
|  |         if (err) { | ||||||
|  |             if (err == LFS_ERR_CORRUPT) { | ||||||
|  |                 goto relocate; | ||||||
|  |             } | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // copy over new state of file | ||||||
|  |     memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size); | ||||||
|  |     file->cache.block = lfs->pcache.block; | ||||||
|  |     file->cache.off = lfs->pcache.off; | ||||||
|  |     lfs->pcache.block = 0xffffffff; | ||||||
|  |  | ||||||
|  |     file->block = nblock; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) { | ||||||
| relocate:; | relocate:; | ||||||
|     // just relocate what exists into new block |     // just relocate what exists into new block | ||||||
| @@ -2873,6 +3042,80 @@ relocate:; | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int lfs_file_flush_(lfs_t *lfs, lfs_file_t_ *file) { | ||||||
|  |     if (file->flags & LFS_F_READING) { | ||||||
|  |         file->flags &= ~LFS_F_READING; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (file->flags & LFS_F_WRITING) { | ||||||
|  |         lfs_off_t pos = file->pos; | ||||||
|  |  | ||||||
|  |         if (!(file->flags & LFS_F_INLINE)) { | ||||||
|  |             // copy over anything after current branch | ||||||
|  |             lfs_file_t_ orig = { | ||||||
|  |                 .head = file->head, | ||||||
|  |                 .size = file->size, | ||||||
|  |                 .flags = LFS_O_RDONLY, | ||||||
|  |                 .pos = file->pos, | ||||||
|  |                 .cache = lfs->rcache, | ||||||
|  |             }; | ||||||
|  |             lfs->rcache.block = 0xffffffff; | ||||||
|  |  | ||||||
|  |             while (file->pos < file->size) { | ||||||
|  |                 // copy over a byte at a time, leave it up to caching | ||||||
|  |                 // to make this efficient | ||||||
|  |                 uint8_t data; | ||||||
|  |                 lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1); | ||||||
|  |                 if (res < 0) { | ||||||
|  |                     return res; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 res = lfs_file_write(lfs, file, &data, 1); | ||||||
|  |                 if (res < 0) { | ||||||
|  |                     return res; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // keep our reference to the rcache in sync | ||||||
|  |                 if (lfs->rcache.block != 0xffffffff) { | ||||||
|  |                     orig.cache.block = 0xffffffff; | ||||||
|  |                     lfs->rcache.block = 0xffffffff; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // write out what we have | ||||||
|  |             while (true) { | ||||||
|  |                 int err = lfs_cache_flush(lfs, &file->cache, &lfs->rcache); | ||||||
|  |                 if (err) { | ||||||
|  |                     if (err == LFS_ERR_CORRUPT) { | ||||||
|  |                         goto relocate; | ||||||
|  |                     } | ||||||
|  |                     return err; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 break; | ||||||
|  | relocate: | ||||||
|  |                 LFS_DEBUG("Bad block at %d", file->block); | ||||||
|  |                 err = lfs_file_relocate_(lfs, file); | ||||||
|  |                 if (err) { | ||||||
|  |                     return err; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             file->size = lfs_max(file->pos, file->size); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // actual file updates | ||||||
|  |         file->head = file->block; | ||||||
|  |         file->size = file->pos; | ||||||
|  |         file->flags &= ~LFS_F_WRITING; | ||||||
|  |         file->flags |= LFS_F_DIRTY; | ||||||
|  |  | ||||||
|  |         file->pos = pos; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) { | ||||||
|     if (file->flags & LFS_F_READING) { |     if (file->flags & LFS_F_READING) { | ||||||
|         file->flags &= ~LFS_F_READING; |         file->flags &= ~LFS_F_READING; | ||||||
| @@ -2947,6 +3190,68 @@ relocate: | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int lfs_file_sync_(lfs_t *lfs, lfs_file_t_ *file) { | ||||||
|  |     int err = lfs_file_flush_(lfs, file); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if ((file->flags & LFS_F_DIRTY) && | ||||||
|  |             !(file->flags & LFS_F_ERRED) && | ||||||
|  |             !lfs_pairisnull(file->pair)) { | ||||||
|  |         // update dir entry | ||||||
|  |         // TODO keep list of dirs including these guys for no | ||||||
|  |         // need of another reload? | ||||||
|  |         lfs_dir_t_ cwd; | ||||||
|  |         err = lfs_dir_fetch_(lfs, &cwd, file->pair); | ||||||
|  |         if (err) { | ||||||
|  |             return err; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // either update the references or inline the whole file | ||||||
|  |         // TODO handle attributes | ||||||
|  | //        if (!(file->flags & LFS_F_INLINE)) { | ||||||
|  | //            entry.d.type = LFS_STRUCT_CTZ | LFS_TYPE_REG; | ||||||
|  | //            entry.d.u.file.head = file->head; | ||||||
|  | //            entry.d.u.file.size = file->size; | ||||||
|  | // | ||||||
|  | //            lfs_entry_tole32(&entry.d); | ||||||
|  | //            buffer = (const uint8_t *)&entry.d + 4; | ||||||
|  | //            size = sizeof(entry.d) - 4; | ||||||
|  | //        } else { | ||||||
|  | //            entry.d.type = LFS_STRUCT_INLINE | LFS_TYPE_REG; | ||||||
|  | // | ||||||
|  | //            buffer = file->cache.buffer; | ||||||
|  | //            size = file->size; | ||||||
|  | //        } | ||||||
|  | // | ||||||
|  | //        // get new alen from disk | ||||||
|  | //        lfs_ssize_t newalen = lfs_dir_checkattrs(lfs, &cwd, &entry, | ||||||
|  | //                file->attrs, file->attrcount); | ||||||
|  | //        if (newalen < 0) { | ||||||
|  | //            return newalen; | ||||||
|  | //        } | ||||||
|  | // | ||||||
|  | //        entry.d.elen = size & 0xff; | ||||||
|  | //        entry.d.alen = (newalen & 0x3f) | ((size >> 2) & 0xc0); | ||||||
|  | // | ||||||
|  | //        // write out update | ||||||
|  | //        err = lfs_dir_set(lfs, &cwd, &entry, (struct lfs_region[]){ | ||||||
|  | //                {LFS_FROM_MEM, 0, 4, &entry.d, 4}, | ||||||
|  | //                {LFS_FROM_MEM, 4, oldelen, buffer, size}, | ||||||
|  | //                {LFS_FROM_ATTRS, 4+oldelen, oldalen, | ||||||
|  | //                    &(struct lfs_region_attrs){file->attrs, file->attrcount}, | ||||||
|  | //                    newalen}}, 3); | ||||||
|  | //        if (err) { | ||||||
|  | //            return err; | ||||||
|  | //        } | ||||||
|  |  | ||||||
|  |         file->flags &= ~LFS_F_DIRTY; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | ||||||
|     int err = lfs_file_flush(lfs, file); |     int err = lfs_file_flush(lfs, file); | ||||||
|     if (err) { |     if (err) { | ||||||
| @@ -3738,14 +4043,16 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|  |  | ||||||
|     // create superblock dir |     // create superblock dir | ||||||
|     lfs_dir_t_ dir; |     lfs_dir_t_ dir; | ||||||
|     err = lfs_dir_alloc_(lfs, &dir); |     err = lfs_dir_alloc_(lfs, &dir, | ||||||
|  |             (const lfs_block_t[2]){0xffffffff, 0xffffffff}); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // write root directory |     // write root directory | ||||||
|     lfs_dir_t_ root; |     lfs_dir_t_ root; | ||||||
|     err = lfs_dir_alloc_(lfs, &root); |     err = lfs_dir_alloc_(lfs, &root, | ||||||
|  |             (const lfs_block_t[2]){0xffffffff, 0xffffffff}); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -3775,16 +4082,15 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     dir.count += 1; |     dir.count += 1; | ||||||
|     err = lfs_dir_set_(lfs, &dir, (lfs_entry_t_[]){ |     err = lfs_dir_commit_(lfs, &dir, (lfs_entry_t_[]){ | ||||||
|             {lfs_mktag(LFS_TYPE_SUPERBLOCK_, 0, sizeof(superblock)), |             {lfs_mktag(LFS_TYPE_SUPERBLOCK_ | LFS_STRUCT_DIR_, 0, | ||||||
|                 .u.buffer=&superblock}}, 1); |                 sizeof(superblock)), .u.buffer=&superblock}}, 1); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // sanity check that fetch works |     // sanity check that fetch works | ||||||
|     err = lfs_dir_fetch_(lfs, &dir, (const lfs_block_t[2]){0, 1}, |     err = lfs_dir_fetch_(lfs, &dir, (const lfs_block_t[2]){0, 1}); | ||||||
|             NULL, NULL); |  | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -3806,8 +4112,7 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|  |  | ||||||
|     // load superblock |     // load superblock | ||||||
|     lfs_dir_t_ dir; |     lfs_dir_t_ dir; | ||||||
|     err = lfs_dir_fetch_(lfs, &dir, (const lfs_block_t[2]){0, 1}, |     err = lfs_dir_fetch_(lfs, &dir, (const lfs_block_t[2]){0, 1}); | ||||||
|             NULL, NULL); |  | ||||||
|     if (err) { |     if (err) { | ||||||
|         if (err == LFS_ERR_CORRUPT) { |         if (err == LFS_ERR_CORRUPT) { | ||||||
|             LFS_ERROR("Invalid superblock at %d %d", 0, 1); |             LFS_ERROR("Invalid superblock at %d %d", 0, 1); | ||||||
| @@ -3816,9 +4121,9 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     lfs_superblock_t_ superblock; |     lfs_superblock_t_ superblock; | ||||||
|     err = lfs_dir_get_(lfs, &dir, 0x7ffff000, &(lfs_entry_t_){ |     err = lfs_dir_getbuffer_(lfs, &dir, | ||||||
|             lfs_mktag(LFS_TYPE_SUPERBLOCK_, 0, sizeof(superblock)), |             0x7ffff000, lfs_mktag(LFS_TYPE_SUPERBLOCK_ | LFS_STRUCT_DIR_, 0, | ||||||
|             .u.buffer=&superblock}); |                 sizeof(superblock)), &(lfs_entry_t_){.u.buffer=&superblock}); | ||||||
|     if (err && err != LFS_ERR_RANGE) { |     if (err && err != LFS_ERR_RANGE) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -3895,15 +4200,15 @@ int lfs_traverse_(lfs_t *lfs, | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // iterate through ids in directory |         // iterate through ids in directory | ||||||
|         int err = lfs_dir_fetch_(lfs, &dir, dir.tail, NULL, NULL); |         int err = lfs_dir_fetch_(lfs, &dir, dir.tail); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         for (int i = 0; i < dir.count; i++) { |         for (int i = 0; i < dir.count; i++) { | ||||||
|             lfs_entry_t_ entry = {lfs_mktag(LFS_TYPE_REG_, i, 8), |             lfs_entry_t_ entry; | ||||||
|                     .u.buffer=entry.u.pair}; |             int err = lfs_dir_getentry_(lfs, &dir, | ||||||
|             int err = lfs_dir_get_(lfs, &dir, 0x701ff000, &entry); |                     0x701ff000, lfs_mktag(LFS_TYPE_REG_, i, 8), &entry); | ||||||
|             if (err) { |             if (err) { | ||||||
|                 if (err == LFS_ERR_NOENT) { |                 if (err == LFS_ERR_NOENT) { | ||||||
|                     continue; |                     continue; | ||||||
| @@ -4027,7 +4332,7 @@ static int lfs_pred_(lfs_t *lfs, const lfs_block_t pair[2], lfs_dir_t_ *pdir) { | |||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         int err = lfs_dir_fetch_(lfs, pdir, pdir->tail, NULL, NULL); |         int err = lfs_dir_fetch_(lfs, pdir, pdir->tail); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
| @@ -4068,15 +4373,14 @@ static int lfs_parent_(lfs_t *lfs, const lfs_block_t pair[2], | |||||||
|  |  | ||||||
|     // iterate over all directory directory entries |     // iterate over all directory directory entries | ||||||
|     while (!lfs_pairisnull(parent->tail)) { |     while (!lfs_pairisnull(parent->tail)) { | ||||||
|         int err = lfs_dir_fetch_(lfs, parent, parent->tail, NULL, NULL); |         int err = lfs_dir_fetch_(lfs, parent, parent->tail); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         for (int i = 0; i < parent->count; i++) { |         for (int i = 0; i < parent->count; i++) { | ||||||
|             entry->tag = lfs_mktag(LFS_STRUCT_DIR_, i, 8); |             int err = lfs_dir_getentry_(lfs, parent, | ||||||
|             entry->u.buffer = &entry->u; |                     0x43dff000, lfs_mktag(LFS_STRUCT_DIR_, i, 8), entry); | ||||||
|             int err = lfs_dir_get_(lfs, parent, 0x43dff000, entry); |  | ||||||
|             if (err && err != LFS_ERR_RANGE) { |             if (err && err != LFS_ERR_RANGE) { | ||||||
|                 if (err == LFS_ERR_NOENT) { |                 if (err == LFS_ERR_NOENT) { | ||||||
|                     continue; |                     continue; | ||||||
| @@ -4132,23 +4436,22 @@ static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2], | |||||||
| static int lfs_moved_(lfs_t *lfs, const lfs_block_t pair[2]) { | static int lfs_moved_(lfs_t *lfs, const lfs_block_t pair[2]) { | ||||||
|     // skip superblock |     // skip superblock | ||||||
|     lfs_dir_t_ dir; |     lfs_dir_t_ dir; | ||||||
|     int err = lfs_dir_fetch_(lfs, &dir, (const lfs_block_t[2]){0, 1}, |     int err = lfs_dir_fetch_(lfs, &dir, (const lfs_block_t[2]){0, 1}); | ||||||
|             NULL, NULL); |  | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // iterate over all directory directory entries |     // iterate over all directory directory entries | ||||||
|     while (!lfs_pairisnull(dir.tail)) { |     while (!lfs_pairisnull(dir.tail)) { | ||||||
|         int err = lfs_dir_fetch_(lfs, &dir, dir.tail, NULL, NULL); |         int err = lfs_dir_fetch_(lfs, &dir, dir.tail); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         for (int i = 0; i < dir.count; i++) { |         for (int i = 0; i < dir.count; i++) { | ||||||
|             lfs_entry_t_ entry = {lfs_mktag(LFS_STRUCT_DIR_, i, 8), |             lfs_entry_t_ entry; | ||||||
|                     .u.buffer=&entry.u}; |             int err = lfs_dir_getentry_(lfs, &dir, | ||||||
|             int err = lfs_dir_get_(lfs, &dir, 0x43dff000, &entry); |                     0x43dff000, lfs_mktag(LFS_STRUCT_DIR_, i, 8), &entry); | ||||||
|             if (err) { |             if (err) { | ||||||
|                 if (err == LFS_ERR_NOENT) { |                 if (err == LFS_ERR_NOENT) { | ||||||
|                     continue; |                     continue; | ||||||
| @@ -4156,8 +4459,8 @@ static int lfs_moved_(lfs_t *lfs, const lfs_block_t pair[2]) { | |||||||
|                 return err; |                 return err; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             err = lfs_dir_get_(lfs, &dir, 0x7ffff000, &(lfs_entry_t_){ |             err = lfs_dir_get_(lfs, &dir, | ||||||
|                     lfs_mktag(LFS_TYPE_MOVE_, i, 0)}); |                     0x7ffff000, lfs_mktag(LFS_TYPE_MOVE_, i, 0), NULL); | ||||||
|             if (err != LFS_ERR_NOENT) { |             if (err != LFS_ERR_NOENT) { | ||||||
|                 if (!err) { |                 if (!err) { | ||||||
|                     continue; |                     continue; | ||||||
| @@ -4265,6 +4568,7 @@ static int lfs_relocate(lfs_t *lfs, | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TODO use this in lfs_move? | ||||||
| int lfs_deorphan_check(lfs_t *lfs, void *p, lfs_entry_t_ entry) { | int lfs_deorphan_check(lfs_t *lfs, void *p, lfs_entry_t_ entry) { | ||||||
|     int16_t *id = p; |     int16_t *id = p; | ||||||
|  |  | ||||||
| @@ -4295,7 +4599,7 @@ int lfs_deorphan_(lfs_t *lfs) { | |||||||
|     // iterate over all directory directory entries |     // iterate over all directory directory entries | ||||||
|     while (!lfs_pairisnull(dir.tail)) { |     while (!lfs_pairisnull(dir.tail)) { | ||||||
|         int16_t moveid = -1; |         int16_t moveid = -1; | ||||||
|         int err = lfs_dir_fetch_(lfs, &dir, dir.tail, |         int err = lfs_dir_fetchwith_(lfs, &dir, dir.tail, | ||||||
|                 lfs_deorphan_check, &moveid); |                 lfs_deorphan_check, &moveid); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
| @@ -4318,8 +4622,8 @@ int lfs_deorphan_(lfs_t *lfs) { | |||||||
|  |  | ||||||
|                 pdir.tail[0] = dir.tail[0]; |                 pdir.tail[0] = dir.tail[0]; | ||||||
|                 pdir.tail[1] = dir.tail[1]; |                 pdir.tail[1] = dir.tail[1]; | ||||||
|                 err = lfs_dir_set_(lfs, &pdir, &(lfs_entry_t_){ |                 err = lfs_dir_commit_(lfs, &pdir, &(lfs_entry_t_){ | ||||||
|                         lfs_mktag(LFS_TYPE_TAIL_, 0x1ff, sizeof(pdir.tail)), |                         lfs_mktag(LFS_TYPE_SOFTTAIL_, 0x1ff, sizeof(pdir.tail)), | ||||||
|                         .u.buffer=pdir.tail}, 1); |                         .u.buffer=pdir.tail}, 1); | ||||||
|                 if (err) { |                 if (err) { | ||||||
|                     return err; |                     return err; | ||||||
| @@ -4335,8 +4639,8 @@ int lfs_deorphan_(lfs_t *lfs) { | |||||||
|  |  | ||||||
|                 pdir.tail[0] = entry.u.pair[0]; |                 pdir.tail[0] = entry.u.pair[0]; | ||||||
|                 pdir.tail[1] = entry.u.pair[1]; |                 pdir.tail[1] = entry.u.pair[1]; | ||||||
|                 err = lfs_dir_set_(lfs, &pdir, &(lfs_entry_t_){ |                 err = lfs_dir_commit_(lfs, &pdir, &(lfs_entry_t_){ | ||||||
|                         lfs_mktag(LFS_TYPE_TAIL_, 0x1ff, sizeof(pdir.tail)), |                         lfs_mktag(LFS_TYPE_SOFTTAIL_, 0x1ff, sizeof(pdir.tail)), | ||||||
|                         .u.buffer=pdir.tail}, 1); |                         .u.buffer=pdir.tail}, 1); | ||||||
|                 if (err) { |                 if (err) { | ||||||
|                     return err; |                     return err; | ||||||
|   | |||||||
							
								
								
									
										37
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -106,32 +106,25 @@ enum lfs_type { | |||||||
|     LFS_STRUCT_INLINE   = 0x30, |     LFS_STRUCT_INLINE   = 0x30, | ||||||
|     LFS_STRUCT_MOVED    = 0x80, |     LFS_STRUCT_MOVED    = 0x80, | ||||||
|  |  | ||||||
|     // file type |     // file types | ||||||
|     LFS_TYPE_REG_        = 0x040, |     LFS_TYPE_REG_        = 0x040, | ||||||
|     LFS_TYPE_DIR_        = 0x050, |     LFS_TYPE_DIR_        = 0x050, | ||||||
|  |  | ||||||
|  |     // internally used types | ||||||
|     LFS_TYPE_NAME_       = 0x010, |     LFS_TYPE_NAME_       = 0x010, | ||||||
|     LFS_TYPE_MOVE_       = 0x080, |     LFS_TYPE_MOVE_       = 0x080, | ||||||
|     LFS_TYPE_DROP_       = 0x090, |     LFS_TYPE_DROP_       = 0x090, | ||||||
|  |  | ||||||
|     LFS_TYPE_SUPERBLOCK_ = 0x0c8, |     LFS_TYPE_SUPERBLOCK_ = 0x0a0, | ||||||
|     LFS_TYPE_TAIL_       = 0x0d0, |     LFS_TYPE_SOFTTAIL_   = 0x0c0, | ||||||
|  |     LFS_TYPE_HARDTAIL_   = 0x0d0, | ||||||
|     LFS_TYPE_CRC_        = 0x0e0, |     LFS_TYPE_CRC_        = 0x0e0, | ||||||
|  |  | ||||||
|     // on disk structure |     // on disk structure | ||||||
|     LFS_STRUCT_ATTR_     = 0x100, |     LFS_STRUCT_ATTR_     = 0x100, | ||||||
|     LFS_STRUCT_INLINE_   = 0x000, |     LFS_STRUCT_INLINE_   = 0x000, | ||||||
|     LFS_STRUCT_CTZ_      = 0x00c, |     LFS_STRUCT_CTZ_      = 0x004, | ||||||
|     LFS_STRUCT_DIR_      = 0x008, |     LFS_STRUCT_DIR_      = 0x008, | ||||||
|  |  | ||||||
| //    LFS_TYPE_DIR_        = 0x002, |  | ||||||
| //    LFS_TYPE_SUPERBLOCK_ = 0xff2, |  | ||||||
|  |  | ||||||
| //    LFS_MASK_ID_         = 0xff000000, |  | ||||||
| //    LFS_MASK_TYPE_       = 0x00fff000, |  | ||||||
| //    LFS_MASK_ATTR_       = 0x00ff0000, |  | ||||||
| //    LFS_MASK_STRUCT_     = 0x0000f000, |  | ||||||
| //    LFS_MASK_SIZE_       = 0x00000fff, |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // File open flags | // File open flags | ||||||
| @@ -345,6 +338,24 @@ typedef struct lfs_file { | |||||||
|     int attrcount; |     int attrcount; | ||||||
| } lfs_file_t; | } lfs_file_t; | ||||||
|  |  | ||||||
|  | typedef struct lfs_file_ { | ||||||
|  |     struct lfs_file *next; | ||||||
|  |     lfs_block_t pair[2]; | ||||||
|  |     uint16_t id; | ||||||
|  |  | ||||||
|  |     lfs_block_t head; | ||||||
|  |     lfs_size_t size; | ||||||
|  |  | ||||||
|  |     uint32_t flags; | ||||||
|  |     lfs_off_t pos; | ||||||
|  |     lfs_block_t block; | ||||||
|  |     lfs_off_t off; | ||||||
|  |     lfs_cache_t cache; | ||||||
|  |  | ||||||
|  |     const struct lfs_attr *attrs; | ||||||
|  |     int attrcount; | ||||||
|  | } lfs_file_t_; | ||||||
|  |  | ||||||
| typedef struct lfs_dir { | typedef struct lfs_dir { | ||||||
|     struct lfs_dir *next; |     struct lfs_dir *next; | ||||||
|     lfs_block_t pair[2]; |     lfs_block_t pair[2]; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user