mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	Changed custom attribute descriptors to used arrays
While linked-lists do have some minor benefits, arrays are more idiomatic in C and may provide a more intuitive API. Initially the linked-list approach was more beneficial than it is now, since it allowed custom attributes to be chained to internal linked lists of attributes. However, this was dropped because exposing the internal attribute list in this way created a rather messy user interface that required strictly encoding the attributes with the on-disk tag format. Minor downside, users can no longer introduce custom attributes in different layers (think OS vs app). Minor upside, the code size and stack usage was reduced a bit. Fortunately, this API can always be changed in the future without breaking anything (except maybe API compatibility).
This commit is contained in:
		
							
								
								
									
										164
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										164
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -320,17 +320,17 @@ static inline lfs_size_t lfs_tag_dsize(lfs_tag_t tag) { | |||||||
| struct lfs_mattr { | struct lfs_mattr { | ||||||
|     lfs_tag_t tag; |     lfs_tag_t tag; | ||||||
|     const void *buffer; |     const void *buffer; | ||||||
|     const struct lfs_mattr *next; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #define LFS_MKATTR(type, id, buffer, size, next) \ |  | ||||||
|     &(const struct lfs_mattr){LFS_MKTAG(type, id, size), (buffer), (next)} |  | ||||||
|  |  | ||||||
| struct lfs_diskoff { | struct lfs_diskoff { | ||||||
|     lfs_block_t block; |     lfs_block_t block; | ||||||
|     lfs_off_t off; |     lfs_off_t off; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #define LFS_MKATTRS(...) \ | ||||||
|  |     (struct lfs_mattr[]){__VA_ARGS__}, \ | ||||||
|  |     sizeof((struct lfs_mattr[]){__VA_ARGS__}) / sizeof(struct lfs_mattr) | ||||||
|  |  | ||||||
| // operations on global state | // operations on global state | ||||||
| static inline void lfs_gstate_xor(struct lfs_gstate *a, | static inline void lfs_gstate_xor(struct lfs_gstate *a, | ||||||
|         const struct lfs_gstate *b) { |         const struct lfs_gstate *b) { | ||||||
| @@ -409,7 +409,7 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) { | |||||||
|  |  | ||||||
| /// Internal operations predeclared here /// | /// Internal operations predeclared here /// | ||||||
| static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | ||||||
|         const struct lfs_mattr *attrs); |         const struct lfs_mattr *attrs, int attrcount); | ||||||
| static int lfs_dir_compact(lfs_t *lfs, | static int lfs_dir_compact(lfs_t *lfs, | ||||||
|         lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, |         lfs_mdir_t *dir, const struct lfs_mattr *attrs, int attrcount, | ||||||
|         lfs_mdir_t *source, uint16_t begin, uint16_t end); |         lfs_mdir_t *source, uint16_t begin, uint16_t end); | ||||||
| @@ -600,13 +600,9 @@ static int lfs_dir_traverse(lfs_t *lfs, | |||||||
|             buffer = &disk; |             buffer = &disk; | ||||||
|             ptag = tag; |             ptag = tag; | ||||||
|         } else if (attrcount > 0) { |         } else if (attrcount > 0) { | ||||||
|             const struct lfs_mattr *a = attrs; |             tag = attrs[0].tag; | ||||||
|             for (int j = 0; j < attrcount-1; j++) { |             buffer = attrs[0].buffer; | ||||||
|                 a = a->next; |             attrs += 1; | ||||||
|             } |  | ||||||
|  |  | ||||||
|             tag = a->tag; |  | ||||||
|             buffer = a->buffer; |  | ||||||
|             attrcount -= 1; |             attrcount -= 1; | ||||||
|         } else if (!hasseenmove && |         } else if (!hasseenmove && | ||||||
|                 lfs_gstate_hasmovehere(&lfs->gpending, dir->pair)) { |                 lfs_gstate_hasmovehere(&lfs->gpending, dir->pair)) { | ||||||
| @@ -647,7 +643,9 @@ static int lfs_dir_traverse(lfs_t *lfs, | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // handle special cases for mcu-side operations |         // handle special cases for mcu-side operations | ||||||
|         if (lfs_tag_type3(tag) == LFS_FROM_MOVE) { |         if (lfs_tag_type3(tag) == LFS_FROM_NOOP) { | ||||||
|  |             // do nothing | ||||||
|  |         } else if (lfs_tag_type3(tag) == LFS_FROM_MOVE) { | ||||||
|             uint16_t fromid = lfs_tag_size(tag); |             uint16_t fromid = lfs_tag_size(tag); | ||||||
|             uint16_t toid = lfs_tag_id(tag); |             uint16_t toid = lfs_tag_id(tag); | ||||||
|             int err = lfs_dir_traverse(lfs, |             int err = lfs_dir_traverse(lfs, | ||||||
| @@ -660,9 +658,10 @@ static int lfs_dir_traverse(lfs_t *lfs, | |||||||
|                 return err; |                 return err; | ||||||
|             } |             } | ||||||
|         } else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) { |         } else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) { | ||||||
|             for (const struct lfs_attr *a = buffer; a; a = a->next) { |             for (unsigned i = 0; i < lfs_tag_size(tag); i++) { | ||||||
|                 int err = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a->type, |                 const struct lfs_attr *a = buffer; | ||||||
|                         lfs_tag_id(tag) + diff, a->size), a->buffer); |                 int err = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a[i].type, | ||||||
|  |                         lfs_tag_id(tag) + diff, a[i].size), a[i].buffer); | ||||||
|                 if (err) { |                 if (err) { | ||||||
|                     return err; |                     return err; | ||||||
|                 } |                 } | ||||||
| @@ -1266,9 +1265,8 @@ static int lfs_dir_drop(lfs_t *lfs, lfs_mdir_t *dir, lfs_mdir_t *tail) { | |||||||
|  |  | ||||||
|     // steal tail |     // steal tail | ||||||
|     lfs_pair_tole32(tail->tail); |     lfs_pair_tole32(tail->tail); | ||||||
|     err = lfs_dir_commit(lfs, dir, |     err = lfs_dir_commit(lfs, dir, LFS_MKATTRS( | ||||||
|             LFS_MKATTR(LFS_TYPE_TAIL + tail->split, 0x3ff, tail->tail, 8, |             {LFS_MKTAG(LFS_TYPE_TAIL + tail->split, 0x3ff, 8), tail->tail})); | ||||||
|             NULL)); |  | ||||||
|     lfs_pair_fromle32(tail->tail); |     lfs_pair_fromle32(tail->tail); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
| @@ -1557,27 +1555,24 @@ relocate: | |||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | ||||||
|         const struct lfs_mattr *attrs) { |         const struct lfs_mattr *attrs, int attrcount) { | ||||||
|     // calculate changes to the directory |     // calculate changes to the directory | ||||||
|     lfs_tag_t deletetag = 0xffffffff; |     lfs_tag_t deletetag = 0xffffffff; | ||||||
|     lfs_tag_t createtag = 0xffffffff; |     lfs_tag_t createtag = 0xffffffff; | ||||||
|     int attrcount = 0; |     for (int i = 0; i < attrcount; i++) { | ||||||
|     for (const struct lfs_mattr *a = attrs; a; a = a->next) { |         if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_CREATE) { | ||||||
|         if (lfs_tag_type3(a->tag) == LFS_TYPE_CREATE) { |             createtag = attrs[i].tag; | ||||||
|             createtag = a->tag; |  | ||||||
|             dir->count += 1; |             dir->count += 1; | ||||||
|         } else if (lfs_tag_type3(a->tag) == LFS_TYPE_DELETE) { |         } else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_DELETE) { | ||||||
|             deletetag = a->tag; |             deletetag = attrs[i].tag; | ||||||
|             LFS_ASSERT(dir->count > 0); |             LFS_ASSERT(dir->count > 0); | ||||||
|             dir->count -= 1; |             dir->count -= 1; | ||||||
|         } else if (lfs_tag_type1(a->tag) == LFS_TYPE_TAIL) { |         } else if (lfs_tag_type1(attrs[i].tag) == LFS_TYPE_TAIL) { | ||||||
|             dir->tail[0] = ((lfs_block_t*)a->buffer)[0]; |             dir->tail[0] = ((lfs_block_t*)attrs[i].buffer)[0]; | ||||||
|             dir->tail[1] = ((lfs_block_t*)a->buffer)[1]; |             dir->tail[1] = ((lfs_block_t*)attrs[i].buffer)[1]; | ||||||
|             dir->split = (lfs_tag_chunk(a->tag) & 1); |             dir->split = (lfs_tag_chunk(attrs[i].tag) & 1); | ||||||
|             lfs_pair_fromle32(dir->tail); |             lfs_pair_fromle32(dir->tail); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         attrcount += 1; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // do we have a pending move? |     // do we have a pending move? | ||||||
| @@ -1755,9 +1750,8 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | |||||||
|  |  | ||||||
|     // setup dir |     // setup dir | ||||||
|     lfs_pair_tole32(pred.tail); |     lfs_pair_tole32(pred.tail); | ||||||
|     err = lfs_dir_commit(lfs, &dir, |     err = lfs_dir_commit(lfs, &dir, LFS_MKATTRS( | ||||||
|             LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, pred.tail, 8, |             {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pred.tail})); | ||||||
|             NULL)); |  | ||||||
|     lfs_pair_fromle32(pred.tail); |     lfs_pair_fromle32(pred.tail); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
| @@ -1768,9 +1762,8 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | |||||||
|         // update tails, this creates a desync |         // update tails, this creates a desync | ||||||
|         lfs_fs_preporphans(lfs, +1); |         lfs_fs_preporphans(lfs, +1); | ||||||
|         lfs_pair_tole32(dir.pair); |         lfs_pair_tole32(dir.pair); | ||||||
|         err = lfs_dir_commit(lfs, &pred, |         err = lfs_dir_commit(lfs, &pred, LFS_MKATTRS( | ||||||
|                 LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, dir.pair, 8, |                 {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), dir.pair})); | ||||||
|                 NULL)); |  | ||||||
|         lfs_pair_fromle32(dir.pair); |         lfs_pair_fromle32(dir.pair); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
| @@ -1780,14 +1773,13 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | |||||||
|  |  | ||||||
|     // now insert into our parent block |     // now insert into our parent block | ||||||
|     lfs_pair_tole32(dir.pair); |     lfs_pair_tole32(dir.pair); | ||||||
|     err = lfs_dir_commit(lfs, &cwd, |     err = lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( | ||||||
|             LFS_MKATTR(LFS_TYPE_DIRSTRUCT, id, dir.pair, sizeof(dir.pair), |             {LFS_MKTAG(LFS_TYPE_CREATE, id, 0)}, | ||||||
|             LFS_MKATTR(LFS_TYPE_DIR, id, path, nlen, |             {LFS_MKTAG(LFS_TYPE_DIR, id, nlen), path}, | ||||||
|             LFS_MKATTR(LFS_TYPE_CREATE, id, NULL, 0, |             {LFS_MKTAG(LFS_TYPE_DIRSTRUCT, id, 8), dir.pair}, | ||||||
|             (!cwd.split) |             {!cwd.split | ||||||
|                 ? LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, dir.pair, 8, |                 ? LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8) | ||||||
|                   NULL) |                 : LFS_MKTAG(LFS_FROM_NOOP, 0, 0), dir.pair})); | ||||||
|                 : NULL)))); |  | ||||||
|     lfs_pair_fromle32(dir.pair); |     lfs_pair_fromle32(dir.pair); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
| @@ -2188,11 +2180,10 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // get next slot and create entry to remember name |         // get next slot and create entry to remember name | ||||||
|         err = lfs_dir_commit(lfs, &file->m, |         err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( | ||||||
|                 LFS_MKATTR(LFS_TYPE_INLINESTRUCT, file->id, NULL, 0, |                 {LFS_MKTAG(LFS_TYPE_CREATE, file->id, 0)}, | ||||||
|                 LFS_MKATTR(LFS_TYPE_REG, file->id, path, nlen, |                 {LFS_MKTAG(LFS_TYPE_REG, file->id, nlen), path}, | ||||||
|                 LFS_MKATTR(LFS_TYPE_CREATE, file->id, NULL, 0, |                 {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0)})); | ||||||
|                 NULL)))); |  | ||||||
|         if (err) { |         if (err) { | ||||||
|             err = LFS_ERR_NAMETOOLONG; |             err = LFS_ERR_NAMETOOLONG; | ||||||
|             goto cleanup; |             goto cleanup; | ||||||
| @@ -2221,12 +2212,13 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // fetch attrs |     // fetch attrs | ||||||
|     for (const struct lfs_attr *a = file->cfg->attrs; a; a = a->next) { |     for (unsigned i = 0; i < file->cfg->attr_count; i++) { | ||||||
|         if ((file->flags & 3) != LFS_O_WRONLY) { |         if ((file->flags & 3) != LFS_O_WRONLY) { | ||||||
|             lfs_stag_t res = lfs_dir_get(lfs, &file->m, |             lfs_stag_t res = lfs_dir_get(lfs, &file->m, | ||||||
|                     LFS_MKTAG(0x7ff, 0x3ff, 0), |                     LFS_MKTAG(0x7ff, 0x3ff, 0), | ||||||
|                     LFS_MKTAG(LFS_TYPE_USERATTR + a->type, file->id, a->size), |                     LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type, | ||||||
|                     a->buffer); |                         file->id, file->cfg->attrs[i].size), | ||||||
|  |                         file->cfg->attrs[i].buffer); | ||||||
|             if (res < 0 && res != LFS_ERR_NOENT) { |             if (res < 0 && res != LFS_ERR_NOENT) { | ||||||
|                 err = res; |                 err = res; | ||||||
|                 goto cleanup; |                 goto cleanup; | ||||||
| @@ -2234,7 +2226,7 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if ((file->flags & 3) != LFS_O_RDONLY) { |         if ((file->flags & 3) != LFS_O_RDONLY) { | ||||||
|             if (a->size > lfs->attr_max) { |             if (file->cfg->attrs[i].size > lfs->attr_max) { | ||||||
|                 err = LFS_ERR_NOSPC; |                 err = LFS_ERR_NOSPC; | ||||||
|                 goto cleanup; |                 goto cleanup; | ||||||
|             } |             } | ||||||
| @@ -2476,11 +2468,10 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             // commit file data and attributes |             // commit file data and attributes | ||||||
|             err = lfs_dir_commit(lfs, &file->m, |             err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS( | ||||||
|                     LFS_MKATTR(LFS_FROM_USERATTRS, |                     {LFS_MKTAG(type, file->id, size), buffer}, | ||||||
|                         file->id, file->cfg->attrs, 0, |                     {LFS_MKTAG(LFS_FROM_USERATTRS, file->id, | ||||||
|                     LFS_MKATTR(type, file->id, buffer, size, |                         file->cfg->attr_count), file->cfg->attrs})); | ||||||
|                     NULL))); |  | ||||||
|             if (err) { |             if (err) { | ||||||
|                 if (err == LFS_ERR_NOSPC && (file->flags & LFS_F_INLINE)) { |                 if (err == LFS_ERR_NOSPC && (file->flags & LFS_F_INLINE)) { | ||||||
|                     goto relocate; |                     goto relocate; | ||||||
| @@ -2850,9 +2841,8 @@ int lfs_remove(lfs_t *lfs, const char *path) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // delete the entry |     // delete the entry | ||||||
|     err = lfs_dir_commit(lfs, &cwd, |     err = lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( | ||||||
|             LFS_MKATTR(LFS_TYPE_DELETE, lfs_tag_id(tag), NULL, 0, |             {LFS_MKTAG(LFS_TYPE_DELETE, lfs_tag_id(tag), 0)})); | ||||||
|             NULL)); |  | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -2943,13 +2933,14 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | |||||||
|     lfs_fs_prepmove(lfs, newoldtagid, oldcwd.pair); |     lfs_fs_prepmove(lfs, newoldtagid, oldcwd.pair); | ||||||
|  |  | ||||||
|     // move over all attributes |     // move over all attributes | ||||||
|     err = lfs_dir_commit(lfs, &newcwd, |     err = lfs_dir_commit(lfs, &newcwd, LFS_MKATTRS( | ||||||
|             LFS_MKATTR(LFS_FROM_MOVE, newid, &oldcwd, lfs_tag_id(oldtag), |             {prevtag != LFS_ERR_NOENT | ||||||
|             LFS_MKATTR(lfs_tag_type3(oldtag), newid, newpath, strlen(newpath), |                 ? LFS_MKTAG(LFS_TYPE_DELETE, newid, 0) | ||||||
|             LFS_MKATTR(LFS_TYPE_CREATE, newid, NULL, 0, |                 : LFS_MKTAG(LFS_FROM_NOOP, 0, 0)}, | ||||||
|             (prevtag != LFS_ERR_NOENT) |             {LFS_MKTAG(LFS_TYPE_CREATE, newid, 0)}, | ||||||
|                 ? LFS_MKATTR(LFS_TYPE_DELETE, newid, NULL, 0, NULL) |             {LFS_MKTAG(lfs_tag_type3(oldtag), newid, strlen(newpath)), | ||||||
|                 : NULL)))); |                 newpath}, | ||||||
|  |             {LFS_MKTAG(LFS_FROM_MOVE, newid, lfs_tag_id(oldtag)), &oldcwd})); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -2957,7 +2948,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | |||||||
|     // let commit clean up after move (if we're different! otherwise move |     // let commit clean up after move (if we're different! otherwise move | ||||||
|     // logic already fixed it for us) |     // logic already fixed it for us) | ||||||
|     if (lfs_pair_cmp(oldcwd.pair, newcwd.pair) != 0) { |     if (lfs_pair_cmp(oldcwd.pair, newcwd.pair) != 0) { | ||||||
|         err = lfs_dir_commit(lfs, &oldcwd, NULL); |         err = lfs_dir_commit(lfs, &oldcwd, NULL, 0); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
| @@ -3031,9 +3022,8 @@ static int lfs_commitattr(lfs_t *lfs, const char *path, | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return lfs_dir_commit(lfs, &cwd, |     return lfs_dir_commit(lfs, &cwd, LFS_MKATTRS( | ||||||
|             LFS_MKATTR(LFS_TYPE_USERATTR + type, id, buffer, size, |             {LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer})); | ||||||
|             NULL)); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| int lfs_setattr(lfs_t *lfs, const char *path, | int lfs_setattr(lfs_t *lfs, const char *path, | ||||||
| @@ -3198,12 +3188,11 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         lfs_superblock_tole32(&superblock); |         lfs_superblock_tole32(&superblock); | ||||||
|         err = lfs_dir_commit(lfs, &root, |         err = lfs_dir_commit(lfs, &root, LFS_MKATTRS(  | ||||||
|                 LFS_MKATTR(LFS_TYPE_INLINESTRUCT, 0, |                 {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0)}, | ||||||
|                     &superblock, sizeof(superblock), |                 {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"}, | ||||||
|                 LFS_MKATTR(LFS_TYPE_SUPERBLOCK, 0, "littlefs", 8, |                 {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), | ||||||
|                 LFS_MKATTR(LFS_TYPE_CREATE, 0, NULL, 0, |                     &superblock})); | ||||||
|                 NULL)))); |  | ||||||
|         if (err) { |         if (err) { | ||||||
|             goto cleanup; |             goto cleanup; | ||||||
|         } |         } | ||||||
| @@ -3516,8 +3505,7 @@ static int lfs_fs_relocate(lfs_t *lfs, | |||||||
|         lfs_fs_preporphans(lfs, +1); |         lfs_fs_preporphans(lfs, +1); | ||||||
|  |  | ||||||
|         lfs_pair_tole32(newpair); |         lfs_pair_tole32(newpair); | ||||||
|         int err = lfs_dir_commit(lfs, &parent, |         int err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS({tag, newpair})); | ||||||
|                 &(struct lfs_mattr){.tag=tag, .buffer=newpair}); |  | ||||||
|         lfs_pair_fromle32(newpair); |         lfs_pair_fromle32(newpair); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
| @@ -3537,9 +3525,8 @@ static int lfs_fs_relocate(lfs_t *lfs, | |||||||
|     if (err != LFS_ERR_NOENT) { |     if (err != LFS_ERR_NOENT) { | ||||||
|         // replace bad pair, either we clean up desync, or no desync occured |         // replace bad pair, either we clean up desync, or no desync occured | ||||||
|         lfs_pair_tole32(newpair); |         lfs_pair_tole32(newpair); | ||||||
|         err = lfs_dir_commit(lfs, &parent, |         err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS( | ||||||
|                 LFS_MKATTR(LFS_TYPE_TAIL + parent.split, 0x3ff, newpair, 8, |                 {LFS_MKTAG(LFS_TYPE_TAIL + parent.split, 0x3ff, 8), newpair})); | ||||||
|                 NULL)); |  | ||||||
|         lfs_pair_fromle32(newpair); |         lfs_pair_fromle32(newpair); | ||||||
|         if (err) { |         if (err) { | ||||||
|             return err; |             return err; | ||||||
| @@ -3600,7 +3587,7 @@ static int lfs_fs_demove(lfs_t *lfs) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // rely on cancel logic inside commit |     // rely on cancel logic inside commit | ||||||
|     err = lfs_dir_commit(lfs, &movedir, NULL); |     err = lfs_dir_commit(lfs, &movedir, NULL, 0); | ||||||
|     if (err) { |     if (err) { | ||||||
|         return err; |         return err; | ||||||
|     } |     } | ||||||
| @@ -3660,9 +3647,8 @@ static int lfs_fs_deorphan(lfs_t *lfs) { | |||||||
|                         pair[0], pair[1]); |                         pair[0], pair[1]); | ||||||
|  |  | ||||||
|                 lfs_pair_tole32(pair); |                 lfs_pair_tole32(pair); | ||||||
|                 err = lfs_dir_commit(lfs, &pdir, |                 err = lfs_dir_commit(lfs, &pdir, LFS_MKATTRS( | ||||||
|                         LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, pair, 8, |                         {LFS_MKTAG(LFS_TYPE_SOFTTAIL, 0x3ff, 8), pair})); | ||||||
|                         NULL)); |  | ||||||
|                 lfs_pair_fromle32(pair); |                 lfs_pair_fromle32(pair); | ||||||
|                 if (err) { |                 if (err) { | ||||||
|                     return err; |                     return err; | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -123,6 +123,7 @@ enum lfs_type { | |||||||
|     LFS_TYPE_MOVESTATE      = 0x7ff, |     LFS_TYPE_MOVESTATE      = 0x7ff, | ||||||
|  |  | ||||||
|     // internal chip sources |     // internal chip sources | ||||||
|  |     LFS_FROM_NOOP           = 0x000, | ||||||
|     LFS_FROM_MOVE           = 0x101, |     LFS_FROM_MOVE           = 0x101, | ||||||
|     LFS_FROM_USERATTRS      = 0x102, |     LFS_FROM_USERATTRS      = 0x102, | ||||||
| }; | }; | ||||||
| @@ -268,7 +269,8 @@ struct lfs_info { | |||||||
|     char name[LFS_NAME_MAX+1]; |     char name[LFS_NAME_MAX+1]; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Custom attribute structure | // Custom attribute structure, used to describe custom attributes | ||||||
|  | // committed atomically during file writes. | ||||||
| struct lfs_attr { | struct lfs_attr { | ||||||
|     // 8-bit type of attribute, provided by user and used to |     // 8-bit type of attribute, provided by user and used to | ||||||
|     // identify the attribute |     // identify the attribute | ||||||
| @@ -279,9 +281,6 @@ struct lfs_attr { | |||||||
|  |  | ||||||
|     // Size of attribute in bytes, limited to LFS_ATTR_MAX |     // Size of attribute in bytes, limited to LFS_ATTR_MAX | ||||||
|     lfs_size_t size; |     lfs_size_t size; | ||||||
|  |  | ||||||
|     // Pointer to next attribute in linked list |  | ||||||
|     struct lfs_attr *next; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Optional configuration provided during lfs_file_opencfg | // Optional configuration provided during lfs_file_opencfg | ||||||
| @@ -290,8 +289,8 @@ struct lfs_file_config { | |||||||
|     // By default lfs_malloc is used to allocate this buffer. |     // By default lfs_malloc is used to allocate this buffer. | ||||||
|     void *buffer; |     void *buffer; | ||||||
|  |  | ||||||
|     // Optional linked list of custom attributes related to the file. If the |     // Optional list of custom attributes related to the file. If the file | ||||||
|     // file is opened with read access, the attributes will be read from |     // is opened with read access, these attributes will be read from disk | ||||||
|     // during the open call. If the file is opened with write access, the |     // during the open call. If the file is opened with write access, the | ||||||
|     // attributes will be written to disk every file sync or close. This |     // attributes will be written to disk every file sync or close. This | ||||||
|     // write occurs atomically with update to the file's contents. |     // write occurs atomically with update to the file's contents. | ||||||
| @@ -302,6 +301,9 @@ struct lfs_file_config { | |||||||
|     // is larger, then it will be silently truncated. If the attribute is not |     // is larger, then it will be silently truncated. If the attribute is not | ||||||
|     // found, it will be created implicitly. |     // found, it will be created implicitly. | ||||||
|     struct lfs_attr *attrs; |     struct lfs_attr *attrs; | ||||||
|  |  | ||||||
|  |     // Number of custom attributes in the list | ||||||
|  |     lfs_size_t attr_count; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -156,10 +156,12 @@ TEST | |||||||
| echo "--- Set/get file attribute ---" | echo "--- Set/get file attribute ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     struct lfs_attr a1 = {'A', buffer,    4}; |     struct lfs_attr attrs1[] = { | ||||||
|     struct lfs_attr b1 = {'B', buffer+4,  6, &a1}; |         {'A', buffer,    4}, | ||||||
|     struct lfs_attr c1 = {'C', buffer+10, 5, &b1}; |         {'B', buffer+4,  6}, | ||||||
|     struct lfs_file_config cfg1 = {.attrs = &c1}; |         {'C', buffer+10, 5}, | ||||||
|  |     }; | ||||||
|  |     struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; | ||||||
|  |  | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||||
|     memcpy(buffer,    "aaaa",   4); |     memcpy(buffer,    "aaaa",   4); | ||||||
| @@ -173,53 +175,55 @@ tests/test.py << TEST | |||||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; |     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |     memcmp(buffer+10, "ccccc",  5) => 0; | ||||||
|  |  | ||||||
|     b1.size = 0; |     attrs1[1].size = 0; | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|     memset(buffer, 0, 15); |     memset(buffer, 0, 15); | ||||||
|     b1.size = 6; |     attrs1[1].size = 6; | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|     memcmp(buffer,    "aaaa",         4) => 0; |     memcmp(buffer,    "aaaa",         4) => 0; | ||||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; |     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||||
|     memcmp(buffer+10, "ccccc",        5) => 0; |     memcmp(buffer+10, "ccccc",        5) => 0; | ||||||
|  |  | ||||||
|     b1.size = 6; |     attrs1[1].size = 6; | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||||
|     memcpy(buffer+4,  "dddddd", 6); |     memcpy(buffer+4,  "dddddd", 6); | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|     memset(buffer, 0, 15); |     memset(buffer, 0, 15); | ||||||
|     b1.size = 6; |     attrs1[1].size = 6; | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|     memcmp(buffer,    "aaaa",   4) => 0; |     memcmp(buffer,    "aaaa",   4) => 0; | ||||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; |     memcmp(buffer+4,  "dddddd", 6) => 0; | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |     memcmp(buffer+10, "ccccc",  5) => 0; | ||||||
|  |  | ||||||
|     b1.size = 3; |     attrs1[1].size = 3; | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||||
|     memcpy(buffer+4,  "eee", 3); |     memcpy(buffer+4,  "eee", 3); | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|     memset(buffer, 0, 15); |     memset(buffer, 0, 15); | ||||||
|     b1.size = 6; |     attrs1[1].size = 6; | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|     memcmp(buffer,    "aaaa",      4) => 0; |     memcmp(buffer,    "aaaa",      4) => 0; | ||||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; |     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; | ||||||
|     memcmp(buffer+10, "ccccc",     5) => 0; |     memcmp(buffer+10, "ccccc",     5) => 0; | ||||||
|  |  | ||||||
|     a1.size = LFS_ATTR_MAX+1; |     attrs1[0].size = LFS_ATTR_MAX+1; | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) | ||||||
|         => LFS_ERR_NOSPC; |         => LFS_ERR_NOSPC; | ||||||
|  |  | ||||||
|     struct lfs_attr a2 = {'A', buffer,    4}; |     struct lfs_attr attrs2[] = { | ||||||
|     struct lfs_attr b2 = {'B', buffer+4,  9, &a2}; |         {'A', buffer,    4}, | ||||||
|     struct lfs_attr c2 = {'C', buffer+13, 5, &b2}; |         {'B', buffer+4,  9}, | ||||||
|     struct lfs_file_config cfg2 = {.attrs = &c2}; |         {'C', buffer+13, 5}, | ||||||
|  |     }; | ||||||
|  |     struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDWR, &cfg2) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDWR, &cfg2) => 0; | ||||||
|     memcpy(buffer+4,  "fffffffff", 9); |     memcpy(buffer+4,  "fffffffff", 9); | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|     a1.size = 4; |     attrs1[0].size = 4; | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|  |  | ||||||
| @@ -227,10 +231,12 @@ tests/test.py << TEST | |||||||
| TEST | TEST | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     struct lfs_attr a2 = {'A', buffer,    4}; |     struct lfs_attr attrs2[] = { | ||||||
|     struct lfs_attr b2 = {'B', buffer+4,  9, &a2}; |         {'A', buffer,    4}, | ||||||
|     struct lfs_attr c2 = {'C', buffer+13, 5, &b2}; |         {'B', buffer+4,  9}, | ||||||
|     struct lfs_file_config cfg2 = {.attrs = &c2}; |         {'C', buffer+13, 5}, | ||||||
|  |     }; | ||||||
|  |     struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; | ||||||
|  |  | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg2) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg2) => 0; | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
| @@ -248,10 +254,12 @@ TEST | |||||||
| echo "--- Deferred file attributes ---" | echo "--- Deferred file attributes ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     struct lfs_attr a1 = {'B', "gggg", 4}; |     struct lfs_attr attrs1[] = { | ||||||
|     struct lfs_attr b1 = {'C', "",     0, &a1}; |         {'B', "gggg", 4}, | ||||||
|     struct lfs_attr c1 = {'D', "hhhh", 4, &b1}; |         {'C', "",     0}, | ||||||
|     struct lfs_file_config cfg1 = {.attrs = &c1}; |         {'D', "hhhh", 4}, | ||||||
|  |     }; | ||||||
|  |     struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; | ||||||
|  |  | ||||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user