Skip to content

Commit 15d1560

Browse files
committed
Added support for custom attributes leveraging the new metadata logging
Now that littlefs has been rebuilt almost from the ground up with the intention to support custom attributes, adding in custom attribute support is relatively easy. The highest bit in the 9-bit type structure indicates that an attribute is a user-specified custom attribute. The user then has a full 8-bits to specify the attribute type. Other than that, custom attributes are treated the same as system-level attributes. Also made some tweaks to custom attributes: - Adopted the opencfg for file-level attributes provided by dpgeorge - Changed setattrs/getattrs to the simpler setattr/getattr functions users will probably be more familiar with. Note that multiple attributes can still be committed atomically with files, though not with directories. - Changed LFS_ATTRS_MAX -> LFS_ATTR_MAX since there's no longer a global limit on the sum of attribute sizes, which was rather confusing. Though they are still limited by what can fit in a metadata-pair.
1 parent 3914cdf commit 15d1560

File tree

4 files changed

+337
-227
lines changed

4 files changed

+337
-227
lines changed

Makefile

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ size: $(OBJ)
3333
$(SIZE) -t $^
3434

3535
.SUFFIXES:
36-
test: test_format test_dirs test_files test_seek test_truncate test_entries \
37-
test_interspersed test_alloc test_paths test_attrs \
38-
test_orphan test_move test_corrupt
36+
test: test_format test_dirs test_files test_seek test_truncate \
37+
test_entries test_interspersed test_alloc test_paths test_attrs \
38+
test_move test_orphan test_corrupt
3939
test_%: tests/test_%.sh
4040
ifdef QUIET
4141
@./$< | sed -n '/^[-=]/p'

lfs.c

+155-26
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ static void lfs_alloc_ack(lfs_t *lfs) {
364364
// d->block_count = lfs_fromle32(d->block_count);
365365
// d->version = lfs_fromle32(d->version);
366366
// d->inline_size = lfs_fromle32(d->inline_size);
367-
// d->attrs_size = lfs_fromle32(d->attrs_size);
367+
// d->attr_size = lfs_fromle32(d->attr_size);
368368
// d->name_size = lfs_fromle32(d->name_size);
369369
//}
370370
//
@@ -375,7 +375,7 @@ static void lfs_alloc_ack(lfs_t *lfs) {
375375
// d->block_count = lfs_tole32(d->block_count);
376376
// d->version = lfs_tole32(d->version);
377377
// d->inline_size = lfs_tole32(d->inline_size);
378-
// d->attrs_size = lfs_tole32(d->attrs_size);
378+
// d->attr_size = lfs_tole32(d->attr_size);
379379
// d->name_size = lfs_tole32(d->name_size);
380380
//}
381381

@@ -430,7 +430,7 @@ static inline bool lfs_pairsync(
430430
(((uint32_t)(type) << 22) | ((uint32_t)(id) << 12) | (uint32_t)(size))
431431

432432
#define LFS_MKATTR(type, id, buffer, size, next) \
433-
&(const lfs_mattr_t){(next), LFS_MKTAG(type, id, size), (buffer)}
433+
&(const lfs_mattr_t){LFS_MKTAG(type, id, size), (buffer), (next)}
434434

435435
static inline bool lfs_tagisvalid(uint32_t tag) {
436436
return !(tag & 0x80000000);
@@ -526,13 +526,20 @@ static int32_t lfs_commitget(lfs_t *lfs, lfs_block_t block, lfs_off_t off,
526526
return LFS_ERR_NOENT;
527527
}
528528

529+
static int lfs_commitattrs(lfs_t *lfs, struct lfs_commit *commit,
530+
uint16_t id, const struct lfs_attr *attrs);
531+
529532
static int lfs_commitmove(lfs_t *lfs, struct lfs_commit *commit,
530533
uint16_t fromid, uint16_t toid,
531534
const lfs_mdir_t *dir, const lfs_mattr_t *attrs);
532535

533536
static int lfs_commitattr(lfs_t *lfs, struct lfs_commit *commit,
534537
uint32_t tag, const void *buffer) {
535-
if (lfs_tagtype(tag) == LFS_FROM_MOVE) {
538+
if (lfs_tagtype(tag) == LFS_FROM_ATTRS) {
539+
// special case for custom attributes
540+
return lfs_commitattrs(lfs, commit,
541+
lfs_tagid(tag), buffer);
542+
} else if (lfs_tagtype(tag) == LFS_FROM_MOVE) {
536543
// special case for moves
537544
return lfs_commitmove(lfs, commit,
538545
lfs_tagsize(tag), lfs_tagid(tag),
@@ -586,6 +593,19 @@ static int lfs_commitattr(lfs_t *lfs, struct lfs_commit *commit,
586593
return 0;
587594
}
588595

596+
static int lfs_commitattrs(lfs_t *lfs, struct lfs_commit *commit,
597+
uint16_t id, const struct lfs_attr *attrs) {
598+
for (const struct lfs_attr *a = attrs; a; a = a->next) {
599+
int err = lfs_commitattr(lfs, commit,
600+
LFS_MKTAG(0x100 | a->type, id, a->size), a->buffer);
601+
if (err) {
602+
return err;
603+
}
604+
}
605+
606+
return 0;
607+
}
608+
589609
static int lfs_commitmove(lfs_t *lfs, struct lfs_commit *commit,
590610
uint16_t fromid, uint16_t toid,
591611
const lfs_mdir_t *dir, const lfs_mattr_t *attrs) {
@@ -1378,9 +1398,6 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
13781398
}
13791399

13801400
info->type = lfs_tagtype(tag);
1381-
if (lfs_tagsize(tag) > lfs->name_size) {
1382-
return LFS_ERR_RANGE;
1383-
}
13841401

13851402
struct lfs_ctz ctz;
13861403
tag = lfs_dir_get(lfs, dir, 0x7c3ff000,
@@ -1410,7 +1427,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) {
14101427

14111428
lfs_mdir_t cwd;
14121429
int32_t res = lfs_dir_lookup(lfs, &cwd, &path);
1413-
if (res != LFS_ERR_NOENT || !path) {
1430+
if (!(res == LFS_ERR_NOENT && path)) {
14141431
return (res < 0) ? res : LFS_ERR_EXIST;
14151432
}
14161433

@@ -1792,8 +1809,9 @@ static int lfs_ctztraverse(lfs_t *lfs,
17921809

17931810

17941811
/// Top level file operations ///
1795-
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
1796-
const char *path, int flags) {
1812+
int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file,
1813+
const char *path, int flags,
1814+
const struct lfs_file_config *cfg) {
17971815
// deorphan if we haven't yet, needed at most once after poweron
17981816
if ((flags & 3) != LFS_O_RDONLY && !lfs->deorphaned) {
17991817
int err = lfs_deorphan(lfs);
@@ -1805,7 +1823,7 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
18051823
// allocate entry for file if it doesn't exist
18061824
lfs_mdir_t cwd;
18071825
int32_t tag = lfs_dir_lookup(lfs, &cwd, &path);
1808-
if (tag < 0 && (tag != LFS_ERR_NOENT || !path)) {
1826+
if (tag < 0 && !(tag == LFS_ERR_NOENT && path)) {
18091827
return tag;
18101828
}
18111829

@@ -1859,16 +1877,42 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
18591877
}
18601878

18611879
// setup file struct
1880+
file->cfg = cfg;
18621881
file->pair[0] = cwd.pair[0];
18631882
file->pair[1] = cwd.pair[1];
18641883
file->id = lfs_tagid(tag);
18651884
file->flags = flags;
18661885
file->pos = 0;
18671886
file->attrs = NULL;
18681887

1888+
if (cfg && cfg->attrs) {
1889+
// fetch attrs
1890+
for (const struct lfs_attr *a = cfg->attrs; a; a = a->next) {
1891+
if ((file->flags & 3) != LFS_O_WRONLY) {
1892+
int32_t res = lfs_dir_get(lfs, &cwd, 0x7ffff000,
1893+
LFS_MKTAG(0x100 | a->type, file->id, a->size), a->buffer);
1894+
if (res < 0 && res != LFS_ERR_NOENT) {
1895+
return res;
1896+
}
1897+
}
1898+
1899+
if ((file->flags & 3) != LFS_O_RDONLY) {
1900+
if (a->size > lfs->attr_size) {
1901+
return LFS_ERR_NOSPC;
1902+
}
1903+
1904+
file->flags |= LFS_F_DIRTY;
1905+
}
1906+
}
1907+
1908+
file->attrs = cfg->attrs;
1909+
}
1910+
18691911
// allocate buffer if needed
18701912
file->cache.block = 0xffffffff;
1871-
if (lfs->cfg->file_buffer) {
1913+
if (file->cfg && file->cfg->buffer) {
1914+
file->cache.buffer = file->cfg->buffer;
1915+
} else if (lfs->cfg->file_buffer) {
18721916
file->cache.buffer = lfs->cfg->file_buffer;
18731917
} else if ((file->flags & 3) == LFS_O_RDONLY) {
18741918
file->cache.buffer = lfs_malloc(lfs->cfg->read_size);
@@ -1909,6 +1953,11 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
19091953
return 0;
19101954
}
19111955

1956+
int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
1957+
const char *path, int flags) {
1958+
return lfs_file_opencfg(lfs, file, path, flags, NULL);
1959+
}
1960+
19121961
int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
19131962
int err = lfs_file_sync(lfs, file);
19141963

@@ -1921,7 +1970,7 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
19211970
}
19221971

19231972
// clean up memory
1924-
if (!lfs->cfg->file_buffer) {
1973+
if (!(file->cfg && file->cfg->buffer) && !lfs->cfg->file_buffer) {
19251974
lfs_free(file->cache.buffer);
19261975
}
19271976

@@ -2071,15 +2120,17 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
20712120
int err = lfs_dir_commit(lfs, &cwd,
20722121
LFS_MKATTR(LFS_TYPE_CTZSTRUCT, file->id,
20732122
&file->ctz.head, sizeof(file->ctz),
2074-
file->attrs));
2123+
LFS_MKATTR(LFS_FROM_ATTRS, file->id, file->attrs, 0,
2124+
NULL)));
20752125
if (err) {
20762126
return err;
20772127
}
20782128
} else {
20792129
int err = lfs_dir_commit(lfs, &cwd,
20802130
LFS_MKATTR(LFS_TYPE_INLINESTRUCT, file->id,
20812131
file->cache.buffer, file->ctz.size,
2082-
file->attrs));
2132+
LFS_MKATTR(LFS_FROM_ATTRS, file->id, file->attrs, 0,
2133+
NULL)));
20832134
if (err) {
20842135
return err;
20852136
}
@@ -2688,7 +2739,85 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
26882739
return 0;
26892740
}
26902741

2691-
//int lfs_getattrs(lfs_t *lfs, const char *path,
2742+
lfs_ssize_t lfs_getattr(lfs_t *lfs, const char *path,
2743+
uint8_t type, void *buffer, lfs_size_t size) {
2744+
lfs_mdir_t cwd;
2745+
int32_t res = lfs_dir_lookup(lfs, &cwd, &path);
2746+
if (res < 0) {
2747+
return res;
2748+
}
2749+
2750+
res = lfs_dir_get(lfs, &cwd, 0x7ffff000,
2751+
LFS_MKTAG(0x100 | type, lfs_tagid(res),
2752+
lfs_min(size, lfs->attr_size)), buffer);
2753+
if (res < 0) {
2754+
if (res == LFS_ERR_NOENT) {
2755+
return LFS_ERR_NOATTR;
2756+
}
2757+
return res;
2758+
}
2759+
2760+
return lfs_tagsize(res);
2761+
}
2762+
2763+
int lfs_setattr(lfs_t *lfs, const char *path,
2764+
uint8_t type, const void *buffer, lfs_size_t size) {
2765+
if (size > lfs->attr_size) {
2766+
return LFS_ERR_NOSPC;
2767+
}
2768+
2769+
lfs_mdir_t cwd;
2770+
int32_t res = lfs_dir_lookup(lfs, &cwd, &path);
2771+
if (res < 0) {
2772+
return res;
2773+
}
2774+
2775+
return lfs_dir_commit(lfs, &cwd,
2776+
LFS_MKATTR(0x100 | type, lfs_tagid(res), buffer, size,
2777+
NULL));
2778+
}
2779+
2780+
lfs_ssize_t lfs_fs_getattr(lfs_t *lfs,
2781+
uint8_t type, void *buffer, lfs_size_t size) {
2782+
lfs_mdir_t superdir;
2783+
int err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1});
2784+
if (err) {
2785+
return err;
2786+
}
2787+
2788+
int32_t res = lfs_dir_get(lfs, &superdir, 0x7ffff000,
2789+
LFS_MKTAG(0x100 | type, 0,
2790+
lfs_min(size, lfs->attr_size)), buffer);
2791+
if (res < 0) {
2792+
if (res == LFS_ERR_NOENT) {
2793+
return LFS_ERR_NOATTR;
2794+
}
2795+
return res;
2796+
}
2797+
2798+
return lfs_tagsize(res);
2799+
}
2800+
2801+
int lfs_fs_setattr(lfs_t *lfs,
2802+
uint8_t type, const void *buffer, lfs_size_t size) {
2803+
if (size > lfs->attr_size) {
2804+
return LFS_ERR_NOSPC;
2805+
}
2806+
2807+
lfs_mdir_t superdir;
2808+
int err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1});
2809+
if (err) {
2810+
return err;
2811+
}
2812+
2813+
return lfs_dir_commit(lfs, &superdir,
2814+
LFS_MKATTR(0x100 | type, 0, buffer, size,
2815+
NULL));
2816+
}
2817+
2818+
//
2819+
//
2820+
//
26922821
// const struct lfs_attr *attrs, int count) {
26932822
// lfs_mdir_t cwd;
26942823
// int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
@@ -2777,10 +2906,10 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
27772906
lfs->inline_size = lfs_min(LFS_INLINE_MAX, lfs->cfg->read_size);
27782907
}
27792908

2780-
LFS_ASSERT(lfs->cfg->attrs_size <= LFS_ATTRS_MAX);
2781-
lfs->attrs_size = lfs->cfg->attrs_size;
2782-
if (!lfs->attrs_size) {
2783-
lfs->attrs_size = LFS_ATTRS_MAX;
2909+
LFS_ASSERT(lfs->cfg->attr_size <= LFS_ATTR_MAX);
2910+
lfs->attr_size = lfs->cfg->attr_size;
2911+
if (!lfs->attr_size) {
2912+
lfs->attr_size = LFS_ATTR_MAX;
27842913
}
27852914

27862915
LFS_ASSERT(lfs->cfg->name_size <= LFS_NAME_MAX);
@@ -2873,7 +3002,7 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
28733002
.block_size = lfs->cfg->block_size,
28743003
.block_count = lfs->cfg->block_count,
28753004
.inline_size = lfs->inline_size,
2876-
.attrs_size = lfs->attrs_size,
3005+
.attr_size = lfs->attr_size,
28773006
.name_size = lfs->name_size,
28783007
};
28793008

@@ -2954,14 +3083,14 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
29543083
lfs->inline_size = superblock.inline_size;
29553084
}
29563085

2957-
if (superblock.attrs_size) {
2958-
if (superblock.attrs_size > lfs->attrs_size) {
2959-
LFS_ERROR("Unsupported attrs size (%d > %d)",
2960-
superblock.attrs_size, lfs->attrs_size);
3086+
if (superblock.attr_size) {
3087+
if (superblock.attr_size > lfs->attr_size) {
3088+
LFS_ERROR("Unsupported attr size (%d > %d)",
3089+
superblock.attr_size, lfs->attr_size);
29613090
return LFS_ERR_INVAL;
29623091
}
29633092

2964-
lfs->attrs_size = superblock.attrs_size;
3093+
lfs->attr_size = superblock.attr_size;
29653094
}
29663095

29673096
if (superblock.name_size) {

0 commit comments

Comments
 (0)