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 $^ | ||||
|  | ||||
| .SUFFIXES: | ||||
| test: test_format test_dirs test_files test_seek test_truncate test_entries \ | ||||
| 	test_interspersed test_alloc test_paths test_attrs \ | ||||
| 	test_orphan test_move test_corrupt | ||||
| test: test_format test_dirs test_files test_seek test_truncate \ | ||||
| 	test_entries test_interspersed test_alloc test_paths test_attrs \ | ||||
| 	test_move test_orphan test_corrupt | ||||
| test_%: tests/test_%.sh | ||||
| ifdef QUIET | ||||
| 	@./$< | 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->version     = lfs_fromle32(d->version); | ||||
| //    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); | ||||
| //} | ||||
| // | ||||
| @@ -375,7 +375,7 @@ static void lfs_alloc_ack(lfs_t *lfs) { | ||||
| //    d->block_count = lfs_tole32(d->block_count); | ||||
| //    d->version     = lfs_tole32(d->version); | ||||
| //    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); | ||||
| //} | ||||
|  | ||||
| @@ -430,7 +430,7 @@ static inline bool lfs_pairsync( | ||||
|     (((uint32_t)(type) << 22) | ((uint32_t)(id) << 12) | (uint32_t)(size)) | ||||
|  | ||||
| #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) { | ||||
|     return !(tag & 0x80000000); | ||||
| @@ -1378,9 +1378,6 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir, | ||||
|     } | ||||
|  | ||||
|     info->type = lfs_tagtype(tag); | ||||
|     if (lfs_tagsize(tag) > lfs->name_size) { | ||||
|         return LFS_ERR_RANGE; | ||||
|     } | ||||
|  | ||||
|     struct lfs_ctz ctz; | ||||
|     tag = lfs_dir_get(lfs, dir, 0x7c3ff000, | ||||
| @@ -1410,7 +1407,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | ||||
|  | ||||
|     lfs_mdir_t cwd; | ||||
|     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; | ||||
|     } | ||||
|  | ||||
| @@ -1792,8 +1789,9 @@ static int lfs_ctztraverse(lfs_t *lfs, | ||||
|  | ||||
|  | ||||
| /// Top level file operations /// | ||||
| int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
|         const char *path, int flags) { | ||||
| int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|         const char *path, int flags, | ||||
|         const struct lfs_file_config *cfg) { | ||||
|     // 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); | ||||
| @@ -1805,7 +1803,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
|     // allocate entry for file if it doesn't exist | ||||
|     lfs_mdir_t cwd; | ||||
|     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; | ||||
|     } | ||||
|  | ||||
| @@ -1859,6 +1857,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
|     } | ||||
|  | ||||
|     // setup file struct | ||||
|     file->cfg = cfg; | ||||
|     file->pair[0] = cwd.pair[0]; | ||||
|     file->pair[1] = cwd.pair[1]; | ||||
|     file->id = lfs_tagid(tag); | ||||
| @@ -1866,9 +1865,40 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
|     file->pos = 0; | ||||
|     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 | ||||
|     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; | ||||
|     } else if ((file->flags & 3) == LFS_O_RDONLY) { | ||||
|         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; | ||||
| } | ||||
|  | ||||
| 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 err = lfs_file_sync(lfs, file); | ||||
|  | ||||
| @@ -1921,10 +1956,21 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) { | ||||
|     } | ||||
|  | ||||
|     // clean up memory | ||||
|     if (!lfs->cfg->file_buffer) { | ||||
|     if (!(file->cfg && file->cfg->buffer) && !lfs->cfg->file_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; | ||||
| } | ||||
|  | ||||
| @@ -2066,6 +2112,11 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { | ||||
|             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 | ||||
|         if (!(file->flags & LFS_F_INLINE)) { | ||||
|             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; | ||||
| } | ||||
|  | ||||
| //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) { | ||||
| //    lfs_mdir_t cwd; | ||||
| //    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_ASSERT(lfs->cfg->attrs_size <= LFS_ATTRS_MAX); | ||||
|     lfs->attrs_size = lfs->cfg->attrs_size; | ||||
|     if (!lfs->attrs_size) { | ||||
|         lfs->attrs_size = LFS_ATTRS_MAX; | ||||
|     LFS_ASSERT(lfs->cfg->attr_size <= LFS_ATTR_MAX); | ||||
|     lfs->attr_size = lfs->cfg->attr_size; | ||||
|     if (!lfs->attr_size) { | ||||
|         lfs->attr_size = LFS_ATTR_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_count = lfs->cfg->block_count, | ||||
|         .inline_size = lfs->inline_size, | ||||
|         .attrs_size  = lfs->attrs_size, | ||||
|         .attr_size   = lfs->attr_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; | ||||
|     } | ||||
|  | ||||
|     if (superblock.attrs_size) { | ||||
|         if (superblock.attrs_size > lfs->attrs_size) { | ||||
|             LFS_ERROR("Unsupported attrs size (%d > %d)", | ||||
|                     superblock.attrs_size, lfs->attrs_size); | ||||
|     if (superblock.attr_size) { | ||||
|         if (superblock.attr_size > lfs->attr_size) { | ||||
|             LFS_ERROR("Unsupported attr size (%d > %d)", | ||||
|                     superblock.attr_size, lfs->attr_size); | ||||
|             return LFS_ERR_INVAL; | ||||
|         } | ||||
|  | ||||
|         lfs->attrs_size = superblock.attrs_size; | ||||
|         lfs->attr_size = superblock.attr_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 | ||||
| // 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. | ||||
| #ifndef LFS_INLINE_MAX | ||||
| #define LFS_INLINE_MAX 0x3ff | ||||
| #endif | ||||
|  | ||||
| // 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 | ||||
| // littlefs drivers. | ||||
| #ifndef LFS_ATTRS_MAX | ||||
| #define LFS_ATTRS_MAX 0x3f | ||||
| #ifndef LFS_ATTR_MAX | ||||
| #define LFS_ATTR_MAX 0x3f | ||||
| #endif | ||||
|  | ||||
| // 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_NOMEM       = -12,  // No more memory available | ||||
|     LFS_ERR_NAMETOOLONG = -36,  // File name too long | ||||
|     LFS_ERR_NODATA      = -61,  // No data/attr available | ||||
|     LFS_ERR_RANGE       = -34,  // Result not representable | ||||
|     LFS_ERR_NOATTR      = -61,  // No data/attr available | ||||
| }; | ||||
|  | ||||
| // File types | ||||
| @@ -223,10 +222,10 @@ struct lfs_config { | ||||
|     lfs_size_t inline_size; | ||||
|  | ||||
|     // 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 | ||||
|     // LFS_ATTRS_MAX when zero.Stored in superblock and must be respected by | ||||
|     // larger attributes size but must be less than LFS_ATTR_MAX. Defaults to | ||||
|     // LFS_ATTR_MAX when zero.Stored in superblock and must be respected by | ||||
|     // 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 | ||||
|     // 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; | ||||
| }; | ||||
|  | ||||
|  | ||||
| // File info structure | ||||
| struct lfs_info { | ||||
|     // 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 | ||||
|     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; | ||||
|  | ||||
|     // 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 /// | ||||
| typedef struct lfs_mattr { | ||||
|     const struct lfs_mattr *next; | ||||
|     int32_t tag; | ||||
|     const void *buffer; | ||||
|     const struct lfs_mattr *next; | ||||
| } lfs_mattr_t; | ||||
|  | ||||
| typedef struct lfs_globals { | ||||
| @@ -302,13 +314,13 @@ typedef struct lfs_file { | ||||
|         lfs_size_t size; | ||||
|     } ctz; | ||||
|  | ||||
|     const struct lfs_file_config *cfg; | ||||
|     struct lfs_mattr *attrs; | ||||
|     uint32_t flags; | ||||
|     lfs_off_t pos; | ||||
|     lfs_block_t block; | ||||
|     lfs_off_t off; | ||||
|     lfs_cache_t cache; | ||||
|  | ||||
|     lfs_mattr_t *attrs; | ||||
| } lfs_file_t; | ||||
|  | ||||
| typedef struct lfs_dir { | ||||
| @@ -328,7 +340,7 @@ typedef struct lfs_superblock { | ||||
|     lfs_size_t block_count; | ||||
|  | ||||
|     lfs_size_t inline_size; | ||||
|     lfs_size_t attrs_size; | ||||
|     lfs_size_t attr_size; | ||||
|     lfs_size_t name_size; | ||||
| } lfs_superblock_t; | ||||
|  | ||||
| @@ -358,7 +370,7 @@ typedef struct lfs { | ||||
|     lfs_globals_t diff; | ||||
|  | ||||
|     lfs_size_t inline_size; | ||||
|     lfs_size_t attrs_size; | ||||
|     lfs_size_t attr_size; | ||||
|     lfs_size_t name_size; | ||||
| } lfs_t; | ||||
|  | ||||
| @@ -368,7 +380,8 @@ typedef struct lfs { | ||||
| // Format a block device with 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. | ||||
| 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 | ||||
| // 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. | ||||
| 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 | ||||
| // is larger than the buffer, LFS_ERR_RANGE is returned. | ||||
| // | ||||
| // TODO doc | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_getattrs(lfs_t *lfs, const char *path, | ||||
|         const struct lfs_attr *attrs, int count); | ||||
| lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path, | ||||
|         uint8_t type, void *buffer, lfs_size_t size); | ||||
|  | ||||
| // 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. | ||||
| // Specifying an attribute with zero size deletes the attribute. | ||||
| // | ||||
| // TODO doc | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_setattrs(lfs_t *lfs, const char *path, | ||||
|         const struct lfs_attr *attrs, int count); | ||||
| int lfs_setattr(lfs_t *lfs, const char *path, | ||||
|         uint8_t type, const void *buffer, lfs_size_t size); | ||||
|  | ||||
|  | ||||
| /// File operations /// | ||||
|  | ||||
| // Open a file | ||||
| // | ||||
| // 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 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. | ||||
| // | ||||
| // Returns a negative error code on failure. | ||||
| int lfs_file_open(lfs_t *lfs, lfs_file_t *file, | ||||
|         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 | ||||
| // | ||||
| // 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. | ||||
| 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 /// | ||||
|  | ||||
| @@ -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 | ||||
| // is larger than the buffer, LFS_ERR_RANGE is returned. | ||||
| // | ||||
| // TODO doc | ||||
| // 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 | ||||
| // | ||||
| @@ -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 | ||||
| // | ||||
| // TODO doc | ||||
| // 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 | ||||
| // | ||||
|   | ||||
| @@ -19,65 +19,53 @@ TEST | ||||
| echo "--- Set/get attribute ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'A', "aaaa",   4}, | ||||
|             {'B', "bbbbbb", 6}, | ||||
|             {'C', "ccccc",  5}}, 3) => 0; | ||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => 0; | ||||
|     lfs_setattr(&lfs, "hello", 'A', "aaaa",   4) => 0; | ||||
|     lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; | ||||
|     lfs_setattr(&lfs, "hello", 'C', "ccccc",  5) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 6; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|  | ||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'B', "", 0}}, 1) => 0; | ||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => 0; | ||||
|     lfs_setattr(&lfs, "hello", 'B', "", 0) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",         4) => 0; | ||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",        5) => 0; | ||||
|  | ||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'B', "dddddd", 6}}, 1) => 0; | ||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => 0; | ||||
|     lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 6; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|  | ||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'B', "eee", 3}}, 1) => 0; | ||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => 0; | ||||
|     lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 3; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",     5) => 0; | ||||
|  | ||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'A', buffer, LFS_ATTRS_MAX+1}}, 1) => LFS_ERR_NOSPC; | ||||
|     lfs_setattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'B', "fffffffff", 9}}, 1) => 0; | ||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => LFS_ERR_RANGE; | ||||
|     lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; | ||||
|     lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 9; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; | ||||
|  | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_getattrs(&lfs, "hello", (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  9}, | ||||
|             {'C', buffer+13, 5}}, 3) => 0; | ||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; | ||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  9) => 9; | ||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||
|     memcmp(buffer+13, "ccccc",     5) => 0; | ||||
| @@ -92,64 +80,52 @@ TEST | ||||
| echo "--- Set/get fs attribute ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'A', "aaaa",   4}, | ||||
|             {'B', "bbbbbb", 6}, | ||||
|             {'C', "ccccc",  5}}, 3) => 0; | ||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => 0; | ||||
|     lfs_fs_setattr(&lfs, 'A', "aaaa",   4) => 0; | ||||
|     lfs_fs_setattr(&lfs, 'B', "bbbbbb", 6) => 0; | ||||
|     lfs_fs_setattr(&lfs, 'C', "ccccc",  5) => 0; | ||||
|     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||
|     lfs_fs_getattr(&lfs, 'B', buffer+4,  6) => 6; | ||||
|     lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|  | ||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'B', "", 0}}, 1) => 0; | ||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => 0; | ||||
|     lfs_fs_setattr(&lfs, 'B', "", 0) => 0; | ||||
|     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||
|     lfs_fs_getattr(&lfs, 'B', buffer+4,  6) => 0; | ||||
|     lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",         4) => 0; | ||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",        5) => 0; | ||||
|  | ||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'B', "dddddd", 6}}, 1) => 0; | ||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => 0; | ||||
|     lfs_fs_setattr(&lfs, 'B', "dddddd", 6) => 0; | ||||
|     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||
|     lfs_fs_getattr(&lfs, 'B', buffer+4,  6) => 6; | ||||
|     lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",   4) => 0; | ||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|  | ||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'B', "eee", 3}}, 1) => 0; | ||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => 0; | ||||
|     lfs_fs_setattr(&lfs, 'B', "eee", 3) => 0; | ||||
|     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||
|     lfs_fs_getattr(&lfs, 'B', buffer+4,  6) => 3; | ||||
|     lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",     5) => 0; | ||||
|  | ||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'A', buffer, LFS_ATTRS_MAX+1}}, 1) => LFS_ERR_NOSPC; | ||||
|     lfs_fs_setattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'B', "fffffffff", 9}}, 1) => 0; | ||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => LFS_ERR_RANGE; | ||||
|     lfs_fs_setattr(&lfs, 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; | ||||
|     lfs_fs_setattr(&lfs, 'B', "fffffffff", 9) => 0; | ||||
|     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||
|     lfs_fs_getattr(&lfs, 'B', buffer+4,  6) => 9; | ||||
|     lfs_fs_getattr(&lfs, 'C', buffer+10, 5) => 5; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_fs_getattrs(&lfs, (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  9}, | ||||
|             {'C', buffer+13, 5}}, 3) => 0; | ||||
|     lfs_fs_getattr(&lfs, 'A', buffer,    4) => 4; | ||||
|     lfs_fs_getattr(&lfs, 'B', buffer+4,  9) => 9; | ||||
|     lfs_fs_getattr(&lfs, 'C', buffer+13, 5) => 5; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||
|     memcmp(buffer+13, "ccccc",     5) => 0; | ||||
| @@ -164,78 +140,90 @@ TEST | ||||
| echo "--- Set/get file attribute ---" | ||||
| tests/test.py << TEST | ||||
|     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]; | ||||
|     attr[0] = (struct lfs_attr){'A', "aaaa",   4}; | ||||
|     attr[1] = (struct lfs_attr){'B', "bbbbbb", 6}; | ||||
|     attr[2] = (struct lfs_attr){'C', "ccccc",  5}; | ||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 3) => 0; | ||||
|     lfs_file_getattrs(&lfs, &file[0], (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => 0; | ||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     memcpy(buffer,    "aaaa",   4); | ||||
|     memcpy(buffer+4,  "bbbbbb", 6); | ||||
|     memcpy(buffer+10, "ccccc",  5); | ||||
|     lfs_file_close(&lfs, &file[0]) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     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+4,  "bbbbbb", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|     lfs_file_sync(&lfs, &file[0]) => 0; | ||||
|  | ||||
|     attr[0] = (struct lfs_attr){'B', "", 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) => 0; | ||||
|     cfg1.attrs->next->size = 0; | ||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     lfs_file_close(&lfs, &file[0]) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     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+4,  "\0\0\0\0\0\0", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",        5) => 0; | ||||
|     lfs_file_sync(&lfs, &file[0]) => 0; | ||||
|  | ||||
|     attr[0] = (struct lfs_attr){'B', "dddddd", 6}; | ||||
|     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) => 0; | ||||
|     cfg1.attrs->next->size = 6; | ||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     memcpy(buffer+4,  "dddddd", 6); | ||||
|     lfs_file_close(&lfs, &file[0]) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     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+4,  "dddddd", 6) => 0; | ||||
|     memcmp(buffer+10, "ccccc",  5) => 0; | ||||
|     lfs_file_sync(&lfs, &file[0]) => 0; | ||||
|  | ||||
|     attr[0] = (struct lfs_attr){'B', "eee", 3}; | ||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 1); | ||||
|     lfs_file_getattrs(&lfs, &file[0], (struct lfs_attr[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  6}, | ||||
|             {'C', buffer+10, 5}}, 3) => 0; | ||||
|     cfg1.attrs->next->size = 3; | ||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|     memcpy(buffer+4,  "eee", 3); | ||||
|     lfs_file_close(&lfs, &file[0]) => 0; | ||||
|     memset(buffer, 0, 15); | ||||
|     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+4,  "eee\0\0\0", 6) => 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}; | ||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 1) => LFS_ERR_NOSPC; | ||||
|     attr[0] = (struct lfs_attr){'B', "fffffffff", 9}; | ||||
|     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; | ||||
|     cfg1.attrs->size = LFS_ATTR_MAX+1; | ||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) | ||||
|         => LFS_ERR_NOSPC; | ||||
|  | ||||
|     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; | ||||
|     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; | ||||
| TEST | ||||
| tests/test.py << TEST | ||||
|     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[]){ | ||||
|             {'A', buffer,    4}, | ||||
|             {'B', buffer+4,  9}, | ||||
|             {'C', buffer+13, 5}}, 3) => 0; | ||||
|     lfs_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_RDONLY, &cfg2) => 0; | ||||
|     lfs_file_close(&lfs, &file[0]) => 0; | ||||
|     memcmp(buffer,    "aaaa",      4) => 0; | ||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; | ||||
|     memcmp(buffer+13, "ccccc",     5) => 0; | ||||
| @@ -250,36 +238,26 @@ TEST | ||||
| echo "--- Deferred file attributes ---" | ||||
| tests/test.py << TEST | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_file_open(&lfs, &file[0], "hello/hello", LFS_O_RDWR) => 0; | ||||
|      | ||||
|     struct lfs_attr attr[] = { | ||||
|         {'B', "gggg", 4}, | ||||
|         {'C', "",     0}, | ||||
|         {'D', "hhhh", 4}, | ||||
|     struct lfs_file_config cfg1 = { | ||||
|         .attrs = | ||||
|             &(struct lfs_attr){'B', "gggg", 4, | ||||
|             &(struct lfs_attr){'C', "",     0, | ||||
|             &(struct lfs_attr){'D', "hhhh", 4}}} | ||||
|     }; | ||||
|  | ||||
|     lfs_file_setattrs(&lfs, &file[0], attr, 3) => 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_file_opencfg(&lfs, &file[0], "hello/hello", LFS_O_WRONLY, &cfg1) => 0; | ||||
|  | ||||
|     lfs_getattrs(&lfs, "hello/hello", (struct lfs_attr[]){ | ||||
|             {'B', buffer,    9}, | ||||
|             {'C', buffer+9,  9}, | ||||
|             {'D', buffer+18, 9}}, 3) => 0; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 9; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 5; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; | ||||
|     memcmp(buffer,    "fffffffff",          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; | ||||
|  | ||||
|     lfs_file_sync(&lfs, &file[0]) => 0; | ||||
|     lfs_getattrs(&lfs, "hello/hello", (struct lfs_attr[]){ | ||||
|             {'B', buffer,    9}, | ||||
|             {'C', buffer+9,  9}, | ||||
|             {'D', buffer+18, 9}}, 3) => 0; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 4; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 0; | ||||
|     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4; | ||||
|     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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user