From 3a70619f416357b824450eff166e84308c04e9f9 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sun, 29 Jul 2018 15:03:23 -0500 Subject: [PATCH] WIP Added support for custom attributes 1 --- Makefile | 6 +- lfs.c | 181 +++++++++++++++++++++++++---- lfs.h | 112 +++++++++--------- tests/test_attrs.sh | 270 ++++++++++++++++++++------------------------ 4 files changed, 346 insertions(+), 223 deletions(-) diff --git a/Makefile b/Makefile index 55c95db..21cc1c9 100644 --- a/Makefile +++ b/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' diff --git a/lfs.c b/lfs.c index bccb27e..ae5f2b6 100644 --- a/lfs.c +++ b/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) { diff --git a/lfs.h b/lfs.h index bd79e9b..cbb499c 100644 --- a/lfs.h +++ b/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 // diff --git a/tests/test_attrs.sh b/tests/test_attrs.sh index 286b909..2af05e1 100755 --- a/tests/test_attrs.sh +++ b/tests/test_attrs.sh @@ -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;