mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 16:14:16 +01:00 
			
		
		
		
	WIP Added support for custom attributes 1
This commit is contained in:
		
							
								
								
									
										6
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Makefile
									
									
									
									
									
								
							| @@ -33,9 +33,9 @@ size: $(OBJ) | |||||||
| 	$(SIZE) -t $^ | 	$(SIZE) -t $^ | ||||||
|  |  | ||||||
| .SUFFIXES: | .SUFFIXES: | ||||||
| test: test_format test_dirs test_files test_seek test_truncate test_entries \ | test: test_format test_dirs test_files test_seek test_truncate \ | ||||||
| 	test_interspersed test_alloc test_paths test_attrs \ | 	test_entries test_interspersed test_alloc test_paths test_attrs \ | ||||||
| 	test_orphan test_move test_corrupt | 	test_move test_orphan test_corrupt | ||||||
| test_%: tests/test_%.sh | test_%: tests/test_%.sh | ||||||
| ifdef QUIET | ifdef QUIET | ||||||
| 	@./$< | sed -n '/^[-=]/p' | 	@./$< | sed -n '/^[-=]/p' | ||||||
|   | |||||||
							
								
								
									
										181
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										181
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -364,7 +364,7 @@ static void lfs_alloc_ack(lfs_t *lfs) { | |||||||
| //    d->block_count = lfs_fromle32(d->block_count); | //    d->block_count = lfs_fromle32(d->block_count); | ||||||
| //    d->version     = lfs_fromle32(d->version); | //    d->version     = lfs_fromle32(d->version); | ||||||
| //    d->inline_size = lfs_fromle32(d->inline_size); | //    d->inline_size = lfs_fromle32(d->inline_size); | ||||||
| //    d->attrs_size  = lfs_fromle32(d->attrs_size); | //    d->attr_size  = lfs_fromle32(d->attr_size); | ||||||
| //    d->name_size   = lfs_fromle32(d->name_size); | //    d->name_size   = lfs_fromle32(d->name_size); | ||||||
| //} | //} | ||||||
| // | // | ||||||
| @@ -375,7 +375,7 @@ static void lfs_alloc_ack(lfs_t *lfs) { | |||||||
| //    d->block_count = lfs_tole32(d->block_count); | //    d->block_count = lfs_tole32(d->block_count); | ||||||
| //    d->version     = lfs_tole32(d->version); | //    d->version     = lfs_tole32(d->version); | ||||||
| //    d->inline_size = lfs_tole32(d->inline_size); | //    d->inline_size = lfs_tole32(d->inline_size); | ||||||
| //    d->attrs_size  = lfs_tole32(d->attrs_size); | //    d->attr_size  = lfs_tole32(d->attr_size); | ||||||
| //    d->name_size   = lfs_tole32(d->name_size); | //    d->name_size   = lfs_tole32(d->name_size); | ||||||
| //} | //} | ||||||
|  |  | ||||||
| @@ -430,7 +430,7 @@ static inline bool lfs_pairsync( | |||||||
|     (((uint32_t)(type) << 22) | ((uint32_t)(id) << 12) | (uint32_t)(size)) |     (((uint32_t)(type) << 22) | ((uint32_t)(id) << 12) | (uint32_t)(size)) | ||||||
|  |  | ||||||
| #define LFS_MKATTR(type, id, buffer, size, next) \ | #define LFS_MKATTR(type, id, buffer, size, next) \ | ||||||
|     &(const lfs_mattr_t){(next), LFS_MKTAG(type, id, size), (buffer)} |     &(const lfs_mattr_t){LFS_MKTAG(type, id, size), (buffer), (next)} | ||||||
|  |  | ||||||
| static inline bool lfs_tagisvalid(uint32_t tag) { | static inline bool lfs_tagisvalid(uint32_t tag) { | ||||||
|     return !(tag & 0x80000000); |     return !(tag & 0x80000000); | ||||||
| @@ -1378,9 +1378,6 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     info->type = lfs_tagtype(tag); |     info->type = lfs_tagtype(tag); | ||||||
|     if (lfs_tagsize(tag) > lfs->name_size) { |  | ||||||
|         return LFS_ERR_RANGE; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     struct lfs_ctz ctz; |     struct lfs_ctz ctz; | ||||||
|     tag = lfs_dir_get(lfs, dir, 0x7c3ff000, |     tag = lfs_dir_get(lfs, dir, 0x7c3ff000, | ||||||
| @@ -1410,7 +1407,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | |||||||
|  |  | ||||||
|     lfs_mdir_t cwd; |     lfs_mdir_t cwd; | ||||||
|     int32_t res = lfs_dir_lookup(lfs, &cwd, &path); |     int32_t res = lfs_dir_lookup(lfs, &cwd, &path); | ||||||
|     if (res != LFS_ERR_NOENT || !path) { |     if (!(res == LFS_ERR_NOENT && path)) { | ||||||
|         return (res < 0) ? res : LFS_ERR_EXIST; |         return (res < 0) ? res : LFS_ERR_EXIST; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1792,8 +1789,9 @@ static int lfs_ctztraverse(lfs_t *lfs, | |||||||
|  |  | ||||||
|  |  | ||||||
| /// Top level file operations /// | /// Top level file operations /// | ||||||
| int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | ||||||
|         const char *path, int flags) { |         const char *path, int flags, | ||||||
|  |         const struct lfs_file_config *cfg) { | ||||||
|     // deorphan if we haven't yet, needed at most once after poweron |     // deorphan if we haven't yet, needed at most once after poweron | ||||||
|     if ((flags & 3) != LFS_O_RDONLY && !lfs->deorphaned) { |     if ((flags & 3) != LFS_O_RDONLY && !lfs->deorphaned) { | ||||||
|         int err = lfs_deorphan(lfs); |         int err = lfs_deorphan(lfs); | ||||||
| @@ -1805,7 +1803,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | |||||||
|     // allocate entry for file if it doesn't exist |     // allocate entry for file if it doesn't exist | ||||||
|     lfs_mdir_t cwd; |     lfs_mdir_t cwd; | ||||||
|     int32_t tag = lfs_dir_lookup(lfs, &cwd, &path); |     int32_t tag = lfs_dir_lookup(lfs, &cwd, &path); | ||||||
|     if (tag < 0 && (tag != LFS_ERR_NOENT || !path)) { |     if (tag < 0 && !(tag == LFS_ERR_NOENT && path)) { | ||||||
|         return tag; |         return tag; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1859,6 +1857,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // setup file struct |     // setup file struct | ||||||
|  |     file->cfg = cfg; | ||||||
|     file->pair[0] = cwd.pair[0]; |     file->pair[0] = cwd.pair[0]; | ||||||
|     file->pair[1] = cwd.pair[1]; |     file->pair[1] = cwd.pair[1]; | ||||||
|     file->id = lfs_tagid(tag); |     file->id = lfs_tagid(tag); | ||||||
| @@ -1866,9 +1865,40 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | |||||||
|     file->pos = 0; |     file->pos = 0; | ||||||
|     file->attrs = NULL; |     file->attrs = NULL; | ||||||
|  |  | ||||||
|  |     if (cfg) { | ||||||
|  |         // fetch attrs | ||||||
|  |         file->attrs = (lfs_mattr_t*)cfg->attrs; | ||||||
|  |  | ||||||
|  |         for (lfs_mattr_t *b = file->attrs; b; b = (lfs_mattr_t*)b->next) { | ||||||
|  |             struct lfs_attr *a = (struct lfs_attr*)b; | ||||||
|  |             if (a->size > lfs->attr_size) { | ||||||
|  |                 return LFS_ERR_NOSPC; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             b->tag = LFS_MKTAG(0x100 | a->type, file->id, a->size); | ||||||
|  |             if ((file->flags & 3) != LFS_O_WRONLY) { | ||||||
|  |                 int32_t res = lfs_dir_get(lfs, &cwd, 0x7ffff000, | ||||||
|  |                         b->tag, a->buffer); | ||||||
|  |                 if (res < 0 && res != LFS_ERR_NOENT) { | ||||||
|  |                     return res; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             b->buffer = a->buffer; | ||||||
|  |             b->next = (lfs_mattr_t*)a->next; | ||||||
|  |  | ||||||
|  |             if ((file->flags & 3) != LFS_O_RDONLY) { | ||||||
|  |                 // TODO hmm | ||||||
|  |                 file->flags |= LFS_F_DIRTY; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // allocate buffer if needed |     // allocate buffer if needed | ||||||
|     file->cache.block = 0xffffffff; |     file->cache.block = 0xffffffff; | ||||||
|     if (lfs->cfg->file_buffer) { |     if (file->cfg && file->cfg->buffer) { | ||||||
|  |         file->cache.buffer = file->cfg->buffer; | ||||||
|  |     } else if (lfs->cfg->file_buffer) { | ||||||
|         file->cache.buffer = lfs->cfg->file_buffer; |         file->cache.buffer = lfs->cfg->file_buffer; | ||||||
|     } else if ((file->flags & 3) == LFS_O_RDONLY) { |     } else if ((file->flags & 3) == LFS_O_RDONLY) { | ||||||
|         file->cache.buffer = lfs_malloc(lfs->cfg->read_size); |         file->cache.buffer = lfs_malloc(lfs->cfg->read_size); | ||||||
| @@ -1909,6 +1939,11 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||||
|  |         const char *path, int flags) { | ||||||
|  |     return lfs_file_opencfg(lfs, file, path, flags, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
| int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | ||||||
|     int err = lfs_file_sync(lfs, file); |     int err = lfs_file_sync(lfs, file); | ||||||
|  |  | ||||||
| @@ -1921,10 +1956,21 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // clean up memory |     // clean up memory | ||||||
|     if (!lfs->cfg->file_buffer) { |     if (!(file->cfg && file->cfg->buffer) && !lfs->cfg->file_buffer) { | ||||||
|         lfs_free(file->cache.buffer); |         lfs_free(file->cache.buffer); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // fix attr structures | ||||||
|  |     // TODO this is a hack? | ||||||
|  |     for (struct lfs_attr *b = (struct lfs_attr*)file->attrs; b; b = b->next) { | ||||||
|  |         lfs_mattr_t *a = (lfs_mattr_t*)b; | ||||||
|  |  | ||||||
|  |         b->next = (struct lfs_attr*)a->next; | ||||||
|  |         b->size = lfs_tagsize(a->tag); | ||||||
|  |         b->buffer = (void*)a->buffer; | ||||||
|  |         b->type = 0xff & lfs_tagtype(a->tag); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return err; |     return err; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -2066,6 +2112,11 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | |||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // update all ids in case we've moved | ||||||
|  |         for (lfs_mattr_t *a = file->attrs; a; a = (lfs_mattr_t*)a->next) { | ||||||
|  |             a->tag = (a->tag & 0xffc00fff) | LFS_MKTAG(0, file->id, 0); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // either update the references or inline the whole file |         // either update the references or inline the whole file | ||||||
|         if (!(file->flags & LFS_F_INLINE)) { |         if (!(file->flags & LFS_F_INLINE)) { | ||||||
|             int err = lfs_dir_commit(lfs, &cwd, |             int err = lfs_dir_commit(lfs, &cwd, | ||||||
| @@ -2688,7 +2739,91 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| //int lfs_getattrs(lfs_t *lfs, const char *path, | lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, | ||||||
|  |         uint8_t type, void *buffer, lfs_size_t size) { | ||||||
|  |     // TODO need me? | ||||||
|  |     memset(buffer, 0, size); | ||||||
|  |  | ||||||
|  |     lfs_mdir_t cwd; | ||||||
|  |     int32_t res = lfs_dir_lookup(lfs, &cwd, &path); | ||||||
|  |     if (res < 0) { | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     res = lfs_dir_get(lfs, &cwd, 0x7ffff000, | ||||||
|  |             LFS_MKTAG(0x100 | type, lfs_tagid(res), | ||||||
|  |                 lfs_min(size, lfs->attr_size)), buffer); | ||||||
|  |     if (res < 0) { | ||||||
|  |         if (res == LFS_ERR_NOENT) { | ||||||
|  |             return LFS_ERR_NOATTR; | ||||||
|  |         } | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return lfs_tagsize(res); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lfs_setattr(lfs_t *lfs, const char *path, | ||||||
|  |         uint8_t type, const void *buffer, lfs_size_t size) { | ||||||
|  |     if (size > lfs->attr_size) { | ||||||
|  |         return LFS_ERR_NOSPC; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     lfs_mdir_t cwd; | ||||||
|  |     int32_t res = lfs_dir_lookup(lfs, &cwd, &path); | ||||||
|  |     if (res < 0) { | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return lfs_dir_commit(lfs, &cwd, | ||||||
|  |         LFS_MKATTR(0x100 | type, lfs_tagid(res), buffer, size, | ||||||
|  |         NULL)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | lfs_ssize_t lfs_fs_getattr(lfs_t *lfs, | ||||||
|  |         uint8_t type, void *buffer, lfs_size_t size) { | ||||||
|  |     // TODO need me? | ||||||
|  |     memset(buffer, 0, size); | ||||||
|  |  | ||||||
|  |     lfs_mdir_t superdir; | ||||||
|  |     int err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1}); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int32_t res = lfs_dir_get(lfs, &superdir, 0x7ffff000, | ||||||
|  |             LFS_MKTAG(0x100 | type, 0, | ||||||
|  |                 lfs_min(size, lfs->attr_size)), buffer); | ||||||
|  |     if (res < 0) { | ||||||
|  |         if (res == LFS_ERR_NOENT) { | ||||||
|  |             return LFS_ERR_NOATTR; | ||||||
|  |         } | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return lfs_tagsize(res); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int lfs_fs_setattr(lfs_t *lfs, | ||||||
|  |         uint8_t type, const void *buffer, lfs_size_t size) { | ||||||
|  |     if (size > lfs->attr_size) { | ||||||
|  |         return LFS_ERR_NOSPC; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     lfs_mdir_t superdir; | ||||||
|  |     int err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1}); | ||||||
|  |     if (err) { | ||||||
|  |         return err; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return lfs_dir_commit(lfs, &superdir, | ||||||
|  |         LFS_MKATTR(0x100 | type, 0, buffer, size, | ||||||
|  |         NULL)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // | ||||||
|  | // | ||||||
| //        const struct lfs_attr *attrs, int count) { | //        const struct lfs_attr *attrs, int count) { | ||||||
| //    lfs_mdir_t cwd; | //    lfs_mdir_t cwd; | ||||||
| //    int err = lfs_dir_fetch(lfs, &cwd, lfs->root); | //    int err = lfs_dir_fetch(lfs, &cwd, lfs->root); | ||||||
| @@ -2777,10 +2912,10 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|         lfs->inline_size = lfs_min(LFS_INLINE_MAX, lfs->cfg->read_size); |         lfs->inline_size = lfs_min(LFS_INLINE_MAX, lfs->cfg->read_size); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_ASSERT(lfs->cfg->attrs_size <= LFS_ATTRS_MAX); |     LFS_ASSERT(lfs->cfg->attr_size <= LFS_ATTR_MAX); | ||||||
|     lfs->attrs_size = lfs->cfg->attrs_size; |     lfs->attr_size = lfs->cfg->attr_size; | ||||||
|     if (!lfs->attrs_size) { |     if (!lfs->attr_size) { | ||||||
|         lfs->attrs_size = LFS_ATTRS_MAX; |         lfs->attr_size = LFS_ATTR_MAX; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     LFS_ASSERT(lfs->cfg->name_size <= LFS_NAME_MAX); |     LFS_ASSERT(lfs->cfg->name_size <= LFS_NAME_MAX); | ||||||
| @@ -2873,7 +3008,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|         .block_size  = lfs->cfg->block_size, |         .block_size  = lfs->cfg->block_size, | ||||||
|         .block_count = lfs->cfg->block_count, |         .block_count = lfs->cfg->block_count, | ||||||
|         .inline_size = lfs->inline_size, |         .inline_size = lfs->inline_size, | ||||||
|         .attrs_size  = lfs->attrs_size, |         .attr_size   = lfs->attr_size, | ||||||
|         .name_size   = lfs->name_size, |         .name_size   = lfs->name_size, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
| @@ -2954,14 +3089,14 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|         lfs->inline_size = superblock.inline_size; |         lfs->inline_size = superblock.inline_size; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (superblock.attrs_size) { |     if (superblock.attr_size) { | ||||||
|         if (superblock.attrs_size > lfs->attrs_size) { |         if (superblock.attr_size > lfs->attr_size) { | ||||||
|             LFS_ERROR("Unsupported attrs size (%d > %d)", |             LFS_ERROR("Unsupported attr size (%d > %d)", | ||||||
|                     superblock.attrs_size, lfs->attrs_size); |                     superblock.attr_size, lfs->attr_size); | ||||||
|             return LFS_ERR_INVAL; |             return LFS_ERR_INVAL; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         lfs->attrs_size = superblock.attrs_size; |         lfs->attr_size = superblock.attr_size; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (superblock.name_size) { |     if (superblock.name_size) { | ||||||
|   | |||||||
							
								
								
									
										112
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -52,18 +52,18 @@ typedef uint32_t lfs_block_t; | |||||||
|  |  | ||||||
| // Maximum inline file size in bytes. Large inline files require a larger | // Maximum inline file size in bytes. Large inline files require a larger | ||||||
| // read and prog cache, but if a file can be inline it does not need its own | // read and prog cache, but if a file can be inline it does not need its own | ||||||
| // data block. LFS_ATTRS_MAX + LFS_INLINE_MAX must be <= 0xffff. Stored in | // data block. LFS_ATTR_MAX + LFS_INLINE_MAX must be <= 0xffff. Stored in | ||||||
| // superblock and must be respected by other littlefs drivers. | // superblock and must be respected by other littlefs drivers. | ||||||
| #ifndef LFS_INLINE_MAX | #ifndef LFS_INLINE_MAX | ||||||
| #define LFS_INLINE_MAX 0x3ff | #define LFS_INLINE_MAX 0x3ff | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // Maximum size of all attributes per file in bytes, may be redefined but a | // Maximum size of all attributes per file in bytes, may be redefined but a | ||||||
| // a smaller LFS_ATTRS_MAX has no benefit. LFS_ATTRS_MAX + LFS_INLINE_MAX | // a smaller LFS_ATTR_MAX has no benefit. LFS_ATTR_MAX + LFS_INLINE_MAX | ||||||
| // must be <= 0xffff. Stored in superblock and must be respected by other | // must be <= 0xffff. Stored in superblock and must be respected by other | ||||||
| // littlefs drivers. | // littlefs drivers. | ||||||
| #ifndef LFS_ATTRS_MAX | #ifndef LFS_ATTR_MAX | ||||||
| #define LFS_ATTRS_MAX 0x3f | #define LFS_ATTR_MAX 0x3f | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // Max name size in bytes, may be redefined to reduce the size of the | // Max name size in bytes, may be redefined to reduce the size of the | ||||||
| @@ -89,8 +89,7 @@ enum lfs_error { | |||||||
|     LFS_ERR_NOSPC       = -28,  // No space left on device |     LFS_ERR_NOSPC       = -28,  // No space left on device | ||||||
|     LFS_ERR_NOMEM       = -12,  // No more memory available |     LFS_ERR_NOMEM       = -12,  // No more memory available | ||||||
|     LFS_ERR_NAMETOOLONG = -36,  // File name too long |     LFS_ERR_NAMETOOLONG = -36,  // File name too long | ||||||
|     LFS_ERR_NODATA      = -61,  // No data/attr available |     LFS_ERR_NOATTR      = -61,  // No data/attr available | ||||||
|     LFS_ERR_RANGE       = -34,  // Result not representable |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // File types | // File types | ||||||
| @@ -223,10 +222,10 @@ struct lfs_config { | |||||||
|     lfs_size_t inline_size; |     lfs_size_t inline_size; | ||||||
|  |  | ||||||
|     // Optional upper limit on attributes per file in bytes. No downside for |     // Optional upper limit on attributes per file in bytes. No downside for | ||||||
|     // larger attributes size but must be less than LFS_ATTRS_MAX. Defaults to |     // larger attributes size but must be less than LFS_ATTR_MAX. Defaults to | ||||||
|     // LFS_ATTRS_MAX when zero.Stored in superblock and must be respected by |     // LFS_ATTR_MAX when zero.Stored in superblock and must be respected by | ||||||
|     // other littlefs drivers. |     // other littlefs drivers. | ||||||
|     lfs_size_t attrs_size; |     lfs_size_t attr_size; | ||||||
|  |  | ||||||
|     // Optional upper limit on length of file names in bytes. No downside for |     // Optional upper limit on length of file names in bytes. No downside for | ||||||
|     // larger names except the size of the info struct which is controlled by |     // larger names except the size of the info struct which is controlled by | ||||||
| @@ -235,7 +234,6 @@ struct lfs_config { | |||||||
|     lfs_size_t name_size; |     lfs_size_t name_size; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| // File info structure | // File info structure | ||||||
| struct lfs_info { | struct lfs_info { | ||||||
|     // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR |     // Type of the file, either LFS_TYPE_REG or LFS_TYPE_DIR | ||||||
| @@ -256,16 +254,30 @@ struct lfs_attr { | |||||||
|     // Pointer to buffer containing the attribute |     // Pointer to buffer containing the attribute | ||||||
|     void *buffer; |     void *buffer; | ||||||
|  |  | ||||||
|     // Size of attribute in bytes, limited to LFS_ATTRS_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 | ||||||
|  | struct lfs_file_config { | ||||||
|  |     // Optional, statically allocated buffer for files. Must be program sized. | ||||||
|  |     // If NULL, malloc will be used by default. | ||||||
|  |     void *buffer; | ||||||
|  |  | ||||||
|  |     // Optional, custom attributes | ||||||
|  |     // TODO document more | ||||||
|  |     struct lfs_attr *attrs; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| /// littlefs data structures /// | /// littlefs data structures /// | ||||||
| typedef struct lfs_mattr { | typedef struct lfs_mattr { | ||||||
|     const struct lfs_mattr *next; |  | ||||||
|     int32_t tag; |     int32_t tag; | ||||||
|     const void *buffer; |     const void *buffer; | ||||||
|  |     const struct lfs_mattr *next; | ||||||
| } lfs_mattr_t; | } lfs_mattr_t; | ||||||
|  |  | ||||||
| typedef struct lfs_globals { | typedef struct lfs_globals { | ||||||
| @@ -302,13 +314,13 @@ typedef struct lfs_file { | |||||||
|         lfs_size_t size; |         lfs_size_t size; | ||||||
|     } ctz; |     } ctz; | ||||||
|  |  | ||||||
|  |     const struct lfs_file_config *cfg; | ||||||
|  |     struct lfs_mattr *attrs; | ||||||
|     uint32_t flags; |     uint32_t flags; | ||||||
|     lfs_off_t pos; |     lfs_off_t pos; | ||||||
|     lfs_block_t block; |     lfs_block_t block; | ||||||
|     lfs_off_t off; |     lfs_off_t off; | ||||||
|     lfs_cache_t cache; |     lfs_cache_t cache; | ||||||
|  |  | ||||||
|     lfs_mattr_t *attrs; |  | ||||||
| } lfs_file_t; | } lfs_file_t; | ||||||
|  |  | ||||||
| typedef struct lfs_dir { | typedef struct lfs_dir { | ||||||
| @@ -328,7 +340,7 @@ typedef struct lfs_superblock { | |||||||
|     lfs_size_t block_count; |     lfs_size_t block_count; | ||||||
|  |  | ||||||
|     lfs_size_t inline_size; |     lfs_size_t inline_size; | ||||||
|     lfs_size_t attrs_size; |     lfs_size_t attr_size; | ||||||
|     lfs_size_t name_size; |     lfs_size_t name_size; | ||||||
| } lfs_superblock_t; | } lfs_superblock_t; | ||||||
|  |  | ||||||
| @@ -358,7 +370,7 @@ typedef struct lfs { | |||||||
|     lfs_globals_t diff; |     lfs_globals_t diff; | ||||||
|  |  | ||||||
|     lfs_size_t inline_size; |     lfs_size_t inline_size; | ||||||
|     lfs_size_t attrs_size; |     lfs_size_t attr_size; | ||||||
|     lfs_size_t name_size; |     lfs_size_t name_size; | ||||||
| } lfs_t; | } lfs_t; | ||||||
|  |  | ||||||
| @@ -368,7 +380,8 @@ typedef struct lfs { | |||||||
| // Format a block device with the littlefs | // Format a block device with the littlefs | ||||||
| // | // | ||||||
| // Requires a littlefs object and config struct. This clobbers the littlefs | // Requires a littlefs object and config struct. This clobbers the littlefs | ||||||
| // object, and does not leave the filesystem mounted. | // object, and does not leave the filesystem mounted. The config struct must | ||||||
|  | // be zeroed for defaults and backwards compatibility. | ||||||
| // | // | ||||||
| // Returns a negative error code on failure. | // Returns a negative error code on failure. | ||||||
| int lfs_format(lfs_t *lfs, const struct lfs_config *config); | int lfs_format(lfs_t *lfs, const struct lfs_config *config); | ||||||
| @@ -377,7 +390,8 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *config); | |||||||
| // | // | ||||||
| // Requires a littlefs object and config struct. Multiple filesystems | // Requires a littlefs object and config struct. Multiple filesystems | ||||||
| // may be mounted simultaneously with multiple littlefs objects. Both | // may be mounted simultaneously with multiple littlefs objects. Both | ||||||
| // lfs and config must be allocated while mounted. | // lfs and config must be allocated while mounted. The config struct must | ||||||
|  | // be zeroed for defaults and backwards compatibility. | ||||||
| // | // | ||||||
| // Returns a negative error code on failure. | // Returns a negative error code on failure. | ||||||
| int lfs_mount(lfs_t *lfs, const struct lfs_config *config); | int lfs_mount(lfs_t *lfs, const struct lfs_config *config); | ||||||
| @@ -416,9 +430,10 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info); | |||||||
| // smaller than the buffer, it is padded with zeros. It the stored attribute | // smaller than the buffer, it is padded with zeros. It the stored attribute | ||||||
| // is larger than the buffer, LFS_ERR_RANGE is returned. | // is larger than the buffer, LFS_ERR_RANGE is returned. | ||||||
| // | // | ||||||
|  | // TODO doc | ||||||
| // Returns a negative error code on failure. | // Returns a negative error code on failure. | ||||||
| int lfs_getattrs(lfs_t *lfs, const char *path, | lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, | ||||||
|         const struct lfs_attr *attrs, int count); |         uint8_t type, void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
| // Set custom attributes | // Set custom attributes | ||||||
| // | // | ||||||
| @@ -426,23 +441,38 @@ int lfs_getattrs(lfs_t *lfs, const char *path, | |||||||
| // disk based on their type id. Unspecified attributes are left unmodified. | // disk based on their type id. Unspecified attributes are left unmodified. | ||||||
| // Specifying an attribute with zero size deletes the attribute. | // Specifying an attribute with zero size deletes the attribute. | ||||||
| // | // | ||||||
|  | // TODO doc | ||||||
| // Returns a negative error code on failure. | // Returns a negative error code on failure. | ||||||
| int lfs_setattrs(lfs_t *lfs, const char *path, | int lfs_setattr(lfs_t *lfs, const char *path, | ||||||
|         const struct lfs_attr *attrs, int count); |         uint8_t type, const void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
|  |  | ||||||
| /// File operations /// | /// File operations /// | ||||||
|  |  | ||||||
| // Open a file | // Open a file | ||||||
| // | // | ||||||
| // The mode that the file is opened in is determined | // The mode that the file is opened in is determined by the flags, which | ||||||
| // by the flags, which are values from the enum lfs_open_flags | // are values from the enum lfs_open_flags that are bitwise-ored together. | ||||||
| // that are bitwise-ored together. |  | ||||||
| // | // | ||||||
| // Returns a negative error code on failure. | // Returns a negative error code on failure. | ||||||
| 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); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Open a file with extra configuration | ||||||
|  | // | ||||||
|  | // The mode that the file is opened in is determined by the flags, which | ||||||
|  | // are values from the enum lfs_open_flags that are bitwise-ored together. | ||||||
|  | // | ||||||
|  | // The config struct provides additional config options per file as described | ||||||
|  | // above. The config struct must be allocated while the file is open, and the | ||||||
|  | // config struct must be zeroed for defaults and backwards compatibility. | ||||||
|  | // | ||||||
|  | // Returns a negative error code on failure. | ||||||
|  | int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | ||||||
|  |         const char *path, int flags, | ||||||
|  |         const struct lfs_file_config *config); | ||||||
|  |  | ||||||
| // Close a file | // Close a file | ||||||
| // | // | ||||||
| // Any pending writes are written out to storage as though | // Any pending writes are written out to storage as though | ||||||
| @@ -503,30 +533,6 @@ int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file); | |||||||
| // Returns the size of the file, or a negative error code on failure. | // Returns the size of the file, or a negative error code on failure. | ||||||
| lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); | lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file); | ||||||
|  |  | ||||||
| // Get custom attributes attached to a file |  | ||||||
| // |  | ||||||
| // Attributes are looked up based on the type id. If the stored attribute is |  | ||||||
| // smaller than the buffer, it is padded with zeros. It the stored attribute |  | ||||||
| // is larger than the buffer, LFS_ERR_RANGE is returned. |  | ||||||
| // |  | ||||||
| // Returns a negative error code on failure. |  | ||||||
| int lfs_file_getattrs(lfs_t *lfs, lfs_file_t *file, |  | ||||||
|         const struct lfs_attr *attrs, int count); |  | ||||||
|  |  | ||||||
| // Set custom attributes on a file |  | ||||||
| // |  | ||||||
| // The array of attributes will be used to update the attributes stored on |  | ||||||
| // disk based on their type id. Unspecified attributes are left unmodified. |  | ||||||
| // Specifying an attribute with zero size deletes the attribute. |  | ||||||
| // |  | ||||||
| // Note: Attributes are not written out until a call to lfs_file_sync |  | ||||||
| // or lfs_file_close and must be allocated until the file is closed or |  | ||||||
| // lfs_file_setattrs is called with a count of zero. |  | ||||||
| // |  | ||||||
| // Returns a negative error code on failure. |  | ||||||
| int lfs_file_setattrs(lfs_t *lfs, lfs_file_t *file, |  | ||||||
|         const struct lfs_attr *attrs, int count); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /// Directory operations /// | /// Directory operations /// | ||||||
|  |  | ||||||
| @@ -583,8 +589,10 @@ int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir); | |||||||
| // smaller than the buffer, it is padded with zeros. It the stored attribute | // smaller than the buffer, it is padded with zeros. It the stored attribute | ||||||
| // is larger than the buffer, LFS_ERR_RANGE is returned. | // is larger than the buffer, LFS_ERR_RANGE is returned. | ||||||
| // | // | ||||||
|  | // TODO doc | ||||||
| // Returns a negative error code on failure. | // Returns a negative error code on failure. | ||||||
| int lfs_fs_getattrs(lfs_t *lfs, const struct lfs_attr *attrs, int count); | lfs_ssize_t lfs_fs_getattr(lfs_t *lfs, | ||||||
|  |         uint8_t type, void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
| // Set custom attributes on the filesystem | // Set custom attributes on the filesystem | ||||||
| // | // | ||||||
| @@ -594,8 +602,10 @@ int lfs_fs_getattrs(lfs_t *lfs, const struct lfs_attr *attrs, int count); | |||||||
| // | // | ||||||
| // Note: Filesystem level attributes are not available for wear-leveling | // Note: Filesystem level attributes are not available for wear-leveling | ||||||
| // | // | ||||||
|  | // TODO doc | ||||||
| // Returns a negative error code on failure. | // Returns a negative error code on failure. | ||||||
| int lfs_fs_setattrs(lfs_t *lfs, const struct lfs_attr *attrs, int count); | int lfs_fs_setattr(lfs_t *lfs, | ||||||
|  |         uint8_t type, const void *buffer, lfs_size_t size); | ||||||
|  |  | ||||||
| // Finds the current size of the filesystem | // Finds the current size of the filesystem | ||||||
| // | // | ||||||
|   | |||||||
| @@ -19,65 +19,53 @@ TEST | |||||||
| echo "--- Set/get attribute ---" | echo "--- Set/get attribute ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_setattr(&lfs, "hello", 'A', "aaaa",   4) => 0; | ||||||
|             {'A', "aaaa",   4}, |     lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; | ||||||
|             {'B', "bbbbbb", 6}, |     lfs_setattr(&lfs, "hello", 'C', "ccccc",  5) => 0; | ||||||
|             {'C', "ccccc",  5}}, 3) => 0; |     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 6; | ||||||
|             {'A', buffer,    4}, |     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",   4) => 0; |     memcmp(buffer,    "aaaa",   4) => 0; | ||||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; |     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |     memcmp(buffer+10, "ccccc",  5) => 0; | ||||||
|  |  | ||||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_setattr(&lfs, "hello", 'B', "", 0) => 0; | ||||||
|             {'B', "", 0}}, 1) => 0; |     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 0; | ||||||
|             {'A', buffer,    4}, |     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => 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; | ||||||
|  |  | ||||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; | ||||||
|             {'B', "dddddd", 6}}, 1) => 0; |     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 6; | ||||||
|             {'A', buffer,    4}, |     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => 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; | ||||||
|  |  | ||||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0; | ||||||
|             {'B', "eee", 3}}, 1) => 0; |     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 3; | ||||||
|             {'A', buffer,    4}, |     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => 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; | ||||||
|  |  | ||||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; | ||||||
|             {'A', buffer, LFS_ATTRS_MAX+1}}, 1) => LFS_ERR_NOSPC; |     lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0; | ||||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||||
|             {'B', "fffffffff", 9}}, 1) => 0; |     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 9; | ||||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||||
|             {'A', buffer,    4}, |  | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => LFS_ERR_RANGE; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ |     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||||
|             {'A', buffer,    4}, |     lfs_getattr(&lfs, "hello", 'B', buffer+4,  9) => 9; | ||||||
|             {'B', buffer+4,  9}, |     lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5; | ||||||
|             {'C', buffer+13, 5}}, 3) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",      4) => 0; |     memcmp(buffer,    "aaaa",      4) => 0; | ||||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; |     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||||
|     memcmp(buffer+13, "ccccc",     5) => 0; |     memcmp(buffer+13, "ccccc",     5) => 0; | ||||||
| @@ -92,64 +80,52 @@ TEST | |||||||
| echo "--- Set/get fs attribute ---" | echo "--- Set/get fs attribute ---" | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_setattr(&lfs, 'A', "aaaa",   4) => 0; | ||||||
|             {'A', "aaaa",   4}, |     lfs_fs_setattr(&lfs, 'B', "bbbbbb", 6) => 0; | ||||||
|             {'B', "bbbbbb", 6}, |     lfs_fs_setattr(&lfs, 'C', "ccccc",  5) => 0; | ||||||
|             {'C', "ccccc",  5}}, 3) => 0; |     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_getattr(&lfs, 'B', buffer+4,  6) => 6; | ||||||
|             {'A', buffer,    4}, |     lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",   4) => 0; |     memcmp(buffer,    "aaaa",   4) => 0; | ||||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; |     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |     memcmp(buffer+10, "ccccc",  5) => 0; | ||||||
|  |  | ||||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_setattr(&lfs, 'B', "", 0) => 0; | ||||||
|             {'B', "", 0}}, 1) => 0; |     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_getattr(&lfs, 'B', buffer+4,  6) => 0; | ||||||
|             {'A', buffer,    4}, |     lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => 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; | ||||||
|  |  | ||||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_setattr(&lfs, 'B', "dddddd", 6) => 0; | ||||||
|             {'B', "dddddd", 6}}, 1) => 0; |     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_getattr(&lfs, 'B', buffer+4,  6) => 6; | ||||||
|             {'A', buffer,    4}, |     lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => 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; | ||||||
|  |  | ||||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_setattr(&lfs, 'B', "eee", 3) => 0; | ||||||
|             {'B', "eee", 3}}, 1) => 0; |     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_getattr(&lfs, 'B', buffer+4,  6) => 3; | ||||||
|             {'A', buffer,    4}, |     lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => 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; | ||||||
|  |  | ||||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_setattr(&lfs, 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; | ||||||
|             {'A', buffer, LFS_ATTRS_MAX+1}}, 1) => LFS_ERR_NOSPC; |     lfs_fs_setattr(&lfs, 'B', "fffffffff", 9) => 0; | ||||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||||
|             {'B', "fffffffff", 9}}, 1) => 0; |     lfs_fs_getattr(&lfs, 'B', buffer+4,  6) => 9; | ||||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; | ||||||
|             {'A', buffer,    4}, |  | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => LFS_ERR_RANGE; |  | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ |     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||||
|             {'A', buffer,    4}, |     lfs_fs_getattr(&lfs, 'B', buffer+4,  9) => 9; | ||||||
|             {'B', buffer+4,  9}, |     lfs_fs_getattr(&lfs, 'C', buffer+13, 5) => 5; | ||||||
|             {'C', buffer+13, 5}}, 3) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",      4) => 0; |     memcmp(buffer,    "aaaa",      4) => 0; | ||||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; |     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||||
|     memcmp(buffer+13, "ccccc",     5) => 0; |     memcmp(buffer+13, "ccccc",     5) => 0; | ||||||
| @@ -164,78 +140,90 @@ 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; | ||||||
|     lfs_file_open(&lfs, &file[0], "hello/hello", LFS_O_WRONLY) => 0; |     struct lfs_file_config cfg1 = { | ||||||
|  |         .attrs = | ||||||
|  |             &(struct lfs_attr){'A', buffer,    4, | ||||||
|  |             &(struct lfs_attr){'B', buffer+4,  6, | ||||||
|  |             &(struct lfs_attr){'C', buffer+10, 5}}} | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     struct lfs_attr attr[3]; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||||
|     attr[0] = (struct lfs_attr){'A', "aaaa",   4}; |     memcpy(buffer,    "aaaa",   4); | ||||||
|     attr[1] = (struct lfs_attr){'B', "bbbbbb", 6}; |     memcpy(buffer+4,  "bbbbbb", 6); | ||||||
|     attr[2] = (struct lfs_attr){'C', "ccccc",  5}; |     memcpy(buffer+10, "ccccc",  5); | ||||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 3) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|     lfs_file_getattrs(&lfs, &file[0], (struct lfs_attr[]){ |     memset(buffer, 0, 15); | ||||||
|             {'A', buffer,    4}, |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||||
|             {'B', buffer+4,  6}, |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|             {'C', buffer+10, 5}}, 3) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",   4) => 0; |     memcmp(buffer,    "aaaa",   4) => 0; | ||||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; |     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |     memcmp(buffer+10, "ccccc",  5) => 0; | ||||||
|     lfs_file_sync(&lfs, &file[0]) => 0; |  | ||||||
|  |  | ||||||
|     attr[0] = (struct lfs_attr){'B', "", 0}; |     cfg1.attrs->next->size = 0; | ||||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||||
|     lfs_file_getattrs(&lfs, &file[0], (struct lfs_attr[]){ |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|             {'A', buffer,    4}, |     memset(buffer, 0, 15); | ||||||
|             {'B', buffer+4,  6}, |     cfg1.attrs->next->size = 6; | ||||||
|             {'C', buffer+10, 5}}, 3) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 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; | ||||||
|     lfs_file_sync(&lfs, &file[0]) => 0; |  | ||||||
|  |  | ||||||
|     attr[0] = (struct lfs_attr){'B', "dddddd", 6}; |     cfg1.attrs->next->size = 6; | ||||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 1) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||||
|     lfs_file_getattrs(&lfs, &file[0], (struct lfs_attr[]){ |     memcpy(buffer+4,  "dddddd", 6); | ||||||
|             {'A', buffer,    4}, |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|             {'B', buffer+4,  6}, |     memset(buffer, 0, 15); | ||||||
|             {'C', buffer+10, 5}}, 3) => 0; |     cfg1.attrs->next->size = 6; | ||||||
|  |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 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; | ||||||
|     lfs_file_sync(&lfs, &file[0]) => 0; |  | ||||||
|  |  | ||||||
|     attr[0] = (struct lfs_attr){'B', "eee", 3}; |     cfg1.attrs->next->size = 3; | ||||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 1); |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||||
|     lfs_file_getattrs(&lfs, &file[0], (struct lfs_attr[]){ |     memcpy(buffer+4,  "eee", 3); | ||||||
|             {'A', buffer,    4}, |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|             {'B', buffer+4,  6}, |     memset(buffer, 0, 15); | ||||||
|             {'C', buffer+10, 5}}, 3) => 0; |     cfg1.attrs->next->size = 6; | ||||||
|  |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 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; | ||||||
|     lfs_file_sync(&lfs, &file[0]) => 0; |  | ||||||
|  |  | ||||||
|     attr[0] = (struct lfs_attr){'A', buffer, LFS_ATTRS_MAX+1}; |     cfg1.attrs->size = LFS_ATTR_MAX+1; | ||||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 1) => LFS_ERR_NOSPC; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) | ||||||
|     attr[0] = (struct lfs_attr){'B', "fffffffff", 9}; |         => LFS_ERR_NOSPC; | ||||||
|     lfs_file_open(&lfs, &file[1], "hello/hello", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_setattrs(&lfs, &file[1], attr, 1) => LFS_ERR_BADF; |  | ||||||
|     lfs_file_close(&lfs, &file[1]) => 0; |  | ||||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 1) => 0; |  | ||||||
|     lfs_file_getattrs(&lfs, &file[0], (struct lfs_attr[]){ |  | ||||||
|             {'A', buffer,    4}, |  | ||||||
|             {'B', buffer+4,  6}, |  | ||||||
|             {'C', buffer+10, 5}}, 3) => LFS_ERR_RANGE; |  | ||||||
|  |  | ||||||
|  |     struct lfs_file_config cfg2 = { | ||||||
|  |         .attrs = | ||||||
|  |             &(struct lfs_attr){'A', buffer,    4, | ||||||
|  |             &(struct lfs_attr){'B', buffer+4,  9, | ||||||
|  |             &(struct lfs_attr){'C', buffer+13, 5}}} | ||||||
|  |     }; | ||||||
|  |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDWR, &cfg2) => 0; | ||||||
|  |     memcpy(buffer+4,  "fffffffff", 9); | ||||||
|     lfs_file_close(&lfs, &file[0]) => 0; |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|  |     cfg1.attrs->size = 4; | ||||||
|  |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg1) => 0; | ||||||
|  |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |     lfs_unmount(&lfs) => 0; | ||||||
| TEST | TEST | ||||||
| tests/test.py << TEST | tests/test.py << TEST | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |     lfs_mount(&lfs, &cfg) => 0; | ||||||
|     lfs_file_open(&lfs, &file[0], "hello/hello", LFS_O_RDONLY) => 0; |     struct lfs_file_config cfg2 = { | ||||||
|  |         .attrs = | ||||||
|  |             &(struct lfs_attr){'A', buffer,    4, | ||||||
|  |             &(struct lfs_attr){'B', buffer+4,  9, | ||||||
|  |             &(struct lfs_attr){'C', buffer+13, 5}}} | ||||||
|  |     }; | ||||||
|  |  | ||||||
|     lfs_file_getattrs(&lfs, &file[0], (struct lfs_attr[]){ |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg2) => 0; | ||||||
|             {'A', buffer,    4}, |     lfs_file_close(&lfs, &file[0]) => 0; | ||||||
|             {'B', buffer+4,  9}, |  | ||||||
|             {'C', buffer+13, 5}}, 3) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",      4) => 0; |     memcmp(buffer,    "aaaa",      4) => 0; | ||||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; |     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||||
|     memcmp(buffer+13, "ccccc",     5) => 0; |     memcmp(buffer+13, "ccccc",     5) => 0; | ||||||
| @@ -250,36 +238,26 @@ 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; | ||||||
|     lfs_file_open(&lfs, &file[0], "hello/hello", LFS_O_RDWR) => 0; |     struct lfs_file_config cfg1 = { | ||||||
|      |         .attrs = | ||||||
|     struct lfs_attr attr[] = { |             &(struct lfs_attr){'B', "gggg", 4, | ||||||
|         {'B', "gggg", 4}, |             &(struct lfs_attr){'C', "",     0, | ||||||
|         {'C', "",     0}, |             &(struct lfs_attr){'D', "hhhh", 4}}} | ||||||
|         {'D', "hhhh", 4}, |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 3) => 0; |     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||||
|     lfs_file_getattrs(&lfs, &file[0], (struct lfs_attr[]){ |  | ||||||
|             {'B', buffer,    9}, |  | ||||||
|             {'C', buffer+9,  9}, |  | ||||||
|             {'D', buffer+18, 9}}, 3) => 0; |  | ||||||
|     memcmp(buffer,    "gggg\0\0\0\0\0",     9) => 0; |  | ||||||
|     memcmp(buffer+9,  "\0\0\0\0\0\0\0\0\0", 9) => 0; |  | ||||||
|     memcmp(buffer+18, "hhhh\0\0\0\0\0",     9) => 0; |  | ||||||
|  |  | ||||||
|     lfs_getattrs(&lfs, "hello/hello", (struct lfs_attr[]){ |     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 9; | ||||||
|             {'B', buffer,    9}, |     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 5; | ||||||
|             {'C', buffer+9,  9}, |     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; | ||||||
|             {'D', buffer+18, 9}}, 3) => 0; |  | ||||||
|     memcmp(buffer,    "fffffffff",          9) => 0; |     memcmp(buffer,    "fffffffff",          9) => 0; | ||||||
|     memcmp(buffer+9,  "ccccc\0\0\0\0",      9) => 0; |     memcmp(buffer+9,  "ccccc\0\0\0\0",      9) => 0; | ||||||
|     memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; |     memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; | ||||||
|  |  | ||||||
|     lfs_file_sync(&lfs, &file[0]) => 0; |     lfs_file_sync(&lfs, &file[0]) => 0; | ||||||
|     lfs_getattrs(&lfs, "hello/hello", (struct lfs_attr[]){ |     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 4; | ||||||
|             {'B', buffer,    9}, |     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 0; | ||||||
|             {'C', buffer+9,  9}, |     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4; | ||||||
|             {'D', buffer+18, 9}}, 3) => 0; |  | ||||||
|     memcmp(buffer,    "gggg\0\0\0\0\0",     9) => 0; |     memcmp(buffer,    "gggg\0\0\0\0\0",     9) => 0; | ||||||
|     memcmp(buffer+9,  "\0\0\0\0\0\0\0\0\0", 9) => 0; |     memcmp(buffer+9,  "\0\0\0\0\0\0\0\0\0", 9) => 0; | ||||||
|     memcmp(buffer+18, "hhhh\0\0\0\0\0",     9) => 0; |     memcmp(buffer+18, "hhhh\0\0\0\0\0",     9) => 0; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user