kv: Added LFS3_KVONLY to opt-out of advanced file operations
One of the ideas behind the key-value API is that it is potentially much
cheaper than a full file API. With the key-value API, we get the
guarantee that all data must fit in RAM, and avoid headaches like
random reads/writes and needing to broadcast file state.
For an example of just how much complexity is avoided, the see the
difference between lfs3_file_flushonce_ vs the mess that is
lfs3_file_flush_ + lfs3_file_crystallize + lfs3_file_graft.
However, littlefs is designed around files, and a couple design
decisions hold back how much code saving is possible:
1. littlefs's shrubs are designed around being enrolled in the omdir
linked-list, so internally we still have most of the file open/close
code lumbering around.
2. Directories and traversals still exist, so we'd need the omdir
linked-list anyways, and we still need to broadcast _some_ changes.
3. Despite being intended for small amounts of data, lfs3_set/get can
still be used to create arbitrarily large files. So we still need all
of the bshrub/btree logic.
Which we still need for the mtree anyways, so this isn't really that
much of a downside.
It also may be possible to save more code by aggressively rewriting the
_entire_ read/write path for lfs3_set/get, to not reuse any of the
existing file logic in LFS3_KVONLY mode. But I decided against this due
to concerns around maintainability.
The duplicate lfs3_file_read + lfs3_file_readonce and lfs3_file_flush_ +
lfs3_file_flushonce_ are already enough of a concern.
Anyways, here's LFS3_KVONLY:
code stack ctx
default: 37824 2416 636
kvonly: 30936 (-18.2%) 2168 (-10.3%) 636 (+0.0%)
LFS3_RDONLY + LFS3_KVONLY is also interesting:
code stack ctx
rdonly: 10776 856 508
rdonly+kvonly: 9904 (-8.1%) 888 (+3.7%) 508 (+0.0%)
---
This also added some noise to the default build's code, mainly due to
tweaks in lfs3_file_readnext to allow better reuse in LFS3_KVONLY:
code stack ctx
before: 37824 2416 636
after: 37860 (+0.1%) 2416 (+0.0%) 636 (+0.0%)
This commit is contained in:
@@ -6940,11 +6940,21 @@ static inline bool lfs3_o_isunsync(uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool lfs3_o_isuncryst(uint32_t flags) {
|
static inline bool lfs3_o_isuncryst(uint32_t flags) {
|
||||||
|
(void)flags;
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
return flags & LFS3_o_UNCRYST;
|
return flags & LFS3_o_UNCRYST;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool lfs3_o_isungraft(uint32_t flags) {
|
static inline bool lfs3_o_isungraft(uint32_t flags) {
|
||||||
|
(void)flags;
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
return flags & LFS3_o_UNGRAFT;
|
return flags & LFS3_o_UNGRAFT;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool lfs3_o_isunflush(uint32_t flags) {
|
static inline bool lfs3_o_isunflush(uint32_t flags) {
|
||||||
@@ -9169,6 +9179,7 @@ static int lfs3_mdir_commit(lfs3_t *lfs3, lfs3_mdir_t *mdir,
|
|||||||
for (lfs3_omdir_t *o = lfs3->omdirs; o; o = o->next) {
|
for (lfs3_omdir_t *o = lfs3->omdirs; o; o = o->next) {
|
||||||
// if we moved a shrub, we also need to discard any related
|
// if we moved a shrub, we also need to discard any related
|
||||||
// leaves that moved
|
// leaves that moved
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
if (lfs3_o_type(o->flags) == LFS3_TYPE_REG
|
if (lfs3_o_type(o->flags) == LFS3_TYPE_REG
|
||||||
&& lfs3_bptr_block(&((lfs3_file_t*)o)->leaf.bptr)
|
&& lfs3_bptr_block(&((lfs3_file_t*)o)->leaf.bptr)
|
||||||
== ((lfs3_bshrub_t*)o)->shrub.blocks[0]
|
== ((lfs3_bshrub_t*)o)->shrub.blocks[0]
|
||||||
@@ -9176,6 +9187,7 @@ static int lfs3_mdir_commit(lfs3_t *lfs3, lfs3_mdir_t *mdir,
|
|||||||
!= ((lfs3_bshrub_t*)o)->shrub.blocks[0]) {
|
!= ((lfs3_bshrub_t*)o)->shrub.blocks[0]) {
|
||||||
lfs3_file_discardleaf((lfs3_file_t*)o);
|
lfs3_file_discardleaf((lfs3_file_t*)o);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// update the shrub
|
// update the shrub
|
||||||
if (lfs3_o_isbshrub(o->flags)) {
|
if (lfs3_o_isbshrub(o->flags)) {
|
||||||
@@ -9744,6 +9756,7 @@ static int lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_traversal_t *t,
|
|||||||
lfs3_t_settstate(&t->b.o.flags, LFS3_TSTATE_OBTREE);
|
lfs3_t_settstate(&t->b.o.flags, LFS3_TSTATE_OBTREE);
|
||||||
|
|
||||||
// wait, do we have an ungrafted leaf?
|
// wait, do we have an ungrafted leaf?
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
if (lfs3_o_isungraft(file->b.o.flags)) {
|
if (lfs3_o_isungraft(file->b.o.flags)) {
|
||||||
if (tag_) {
|
if (tag_) {
|
||||||
*tag_ = LFS3_TAG_BLOCK;
|
*tag_ = LFS3_TAG_BLOCK;
|
||||||
@@ -9751,6 +9764,7 @@ static int lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_traversal_t *t,
|
|||||||
*bptr = file->leaf.bptr;
|
*bptr = file->leaf.bptr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -11226,6 +11240,7 @@ int lfs3_setattr(lfs3_t *lfs3, const char *path, uint8_t type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update any opened files tracking custom attrs
|
// update any opened files tracking custom attrs
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
for (lfs3_omdir_t *o = lfs3->omdirs; o; o = o->next) {
|
for (lfs3_omdir_t *o = lfs3->omdirs; o; o = o->next) {
|
||||||
if (!(lfs3_o_type(o->flags) == LFS3_TYPE_REG
|
if (!(lfs3_o_type(o->flags) == LFS3_TYPE_REG
|
||||||
&& o->mdir.mid == mdir.mid
|
&& o->mdir.mid == mdir.mid
|
||||||
@@ -11247,7 +11262,7 @@ int lfs3_setattr(lfs3_t *lfs3, const char *path, uint8_t type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -11279,6 +11294,7 @@ int lfs3_removeattr(lfs3_t *lfs3, const char *path, uint8_t type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update any opened files tracking custom attrs
|
// update any opened files tracking custom attrs
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
for (lfs3_omdir_t *o = lfs3->omdirs; o; o = o->next) {
|
for (lfs3_omdir_t *o = lfs3->omdirs; o; o = o->next) {
|
||||||
if (!(lfs3_o_type(o->flags) == LFS3_TYPE_REG
|
if (!(lfs3_o_type(o->flags) == LFS3_TYPE_REG
|
||||||
&& o->mdir.mid == mdir.mid
|
&& o->mdir.mid == mdir.mid
|
||||||
@@ -11298,6 +11314,7 @@ int lfs3_removeattr(lfs3_t *lfs3, const char *path, uint8_t type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -11309,18 +11326,23 @@ int lfs3_removeattr(lfs3_t *lfs3, const char *path, uint8_t type) {
|
|||||||
/// File operations ///
|
/// File operations ///
|
||||||
|
|
||||||
// file helpers
|
// file helpers
|
||||||
|
|
||||||
static inline void lfs3_file_discardcache(lfs3_file_t *file) {
|
static inline void lfs3_file_discardcache(lfs3_file_t *file) {
|
||||||
file->b.o.flags &= ~LFS3_o_UNFLUSH;
|
file->b.o.flags &= ~LFS3_o_UNFLUSH;
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
file->cache.pos = 0;
|
file->cache.pos = 0;
|
||||||
|
#endif
|
||||||
file->cache.size = 0;
|
file->cache.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
static inline void lfs3_file_discardleaf(lfs3_file_t *file) {
|
static inline void lfs3_file_discardleaf(lfs3_file_t *file) {
|
||||||
file->b.o.flags &= ~LFS3_o_UNCRYST & ~LFS3_o_UNGRAFT;
|
file->b.o.flags &= ~LFS3_o_UNCRYST & ~LFS3_o_UNGRAFT;
|
||||||
file->leaf.pos = 0;
|
file->leaf.pos = 0;
|
||||||
file->leaf.weight = 0;
|
file->leaf.weight = 0;
|
||||||
lfs3_bptr_discard(&file->leaf.bptr);
|
lfs3_bptr_discard(&file->leaf.bptr);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void lfs3_file_discardbshrub(lfs3_file_t *file) {
|
static inline void lfs3_file_discardbshrub(lfs3_file_t *file) {
|
||||||
lfs3_bshrub_init(&file->b);
|
lfs3_bshrub_init(&file->b);
|
||||||
@@ -11334,14 +11356,18 @@ static inline lfs3_size_t lfs3_file_cachesize(lfs3_t *lfs3,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline lfs3_off_t lfs3_file_weight_(const lfs3_file_t *file) {
|
static inline lfs3_off_t lfs3_file_weight_(const lfs3_file_t *file) {
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
return lfs3_max(
|
return lfs3_max(
|
||||||
file->leaf.pos + file->leaf.weight,
|
file->leaf.pos + file->leaf.weight,
|
||||||
file->b.shrub.weight);
|
file->b.shrub.weight);
|
||||||
|
#else
|
||||||
|
return file->b.shrub.weight;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline lfs3_off_t lfs3_file_size_(const lfs3_file_t *file) {
|
static inline lfs3_off_t lfs3_file_size_(const lfs3_file_t *file) {
|
||||||
return lfs3_max(
|
return lfs3_max(
|
||||||
file->cache.pos + file->cache.size,
|
LFS3_IFDEF_KVONLY(0, file->cache.pos) + file->cache.size,
|
||||||
lfs3_file_weight_(file));
|
lfs3_file_weight_(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11353,9 +11379,13 @@ static void lfs3_file_init(lfs3_file_t *file, uint32_t flags,
|
|||||||
const struct lfs3_file_config *cfg) {
|
const struct lfs3_file_config *cfg) {
|
||||||
file->cfg = cfg;
|
file->cfg = cfg;
|
||||||
file->b.o.flags = lfs3_o_typeflags(LFS3_TYPE_REG) | flags;
|
file->b.o.flags = lfs3_o_typeflags(LFS3_TYPE_REG) | flags;
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
file->pos = 0;
|
file->pos = 0;
|
||||||
|
#endif
|
||||||
lfs3_file_discardcache(file);
|
lfs3_file_discardcache(file);
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_file_discardleaf(file);
|
lfs3_file_discardleaf(file);
|
||||||
|
#endif
|
||||||
lfs3_file_discardbshrub(file);
|
lfs3_file_discardbshrub(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11407,6 +11437,7 @@ static int lfs3_file_fetch(lfs3_t *lfs3, lfs3_file_t *file, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try to fetch any custom attributes
|
// try to fetch any custom attributes
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
for (lfs3_size_t i = 0; i < file->cfg->attr_count; i++) {
|
for (lfs3_size_t i = 0; i < file->cfg->attr_count; i++) {
|
||||||
// skip writeonly attrs
|
// skip writeonly attrs
|
||||||
if (lfs3_o_iswronly(file->cfg->attrs[i].flags)) {
|
if (lfs3_o_iswronly(file->cfg->attrs[i].flags)) {
|
||||||
@@ -11450,14 +11481,17 @@ static int lfs3_file_fetch(lfs3_t *lfs3, lfs3_file_t *file, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// needed in lfs3_file_opencfg
|
// needed in lfs3_file_opencfg
|
||||||
static void lfs3_file_close_(lfs3_t *lfs3, const lfs3_file_t *file);
|
static void lfs3_file_close_(lfs3_t *lfs3, const lfs3_file_t *file);
|
||||||
|
#ifndef LFS3_RDONLY
|
||||||
static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
const lfs3_name_t *name);
|
const lfs3_name_t *name);
|
||||||
|
#endif
|
||||||
static int lfs3_file_ck(lfs3_t *lfs3, const lfs3_file_t *file,
|
static int lfs3_file_ck(lfs3_t *lfs3, const lfs3_file_t *file,
|
||||||
uint32_t flags);
|
uint32_t flags);
|
||||||
|
|
||||||
@@ -11487,15 +11521,21 @@ int lfs3_file_opencfg_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
if (lfs3_o_iswrset(file->b.o.flags)) {
|
if (lfs3_o_iswrset(file->b.o.flags)) {
|
||||||
file->b.o.flags |= LFS3_o_UNFLUSH;
|
file->b.o.flags |= LFS3_o_UNFLUSH;
|
||||||
file->cache.buffer = file->cfg->cache_buffer;
|
file->cache.buffer = file->cfg->cache_buffer;
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
file->cache.pos = 0;
|
file->cache.pos = 0;
|
||||||
|
#endif
|
||||||
file->cache.size = file->cfg->cache_size;
|
file->cache.size = file->cfg->cache_size;
|
||||||
} else if (file->cfg->cache_buffer) {
|
} else if (file->cfg->cache_buffer) {
|
||||||
file->cache.buffer = file->cfg->cache_buffer;
|
file->cache.buffer = file->cfg->cache_buffer;
|
||||||
} else {
|
} else {
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
file->cache.buffer = lfs3_malloc(lfs3_file_cachesize(lfs3, file));
|
file->cache.buffer = lfs3_malloc(lfs3_file_cachesize(lfs3, file));
|
||||||
if (!file->cache.buffer) {
|
if (!file->cache.buffer) {
|
||||||
return LFS3_ERR_NOMEM;
|
return LFS3_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
LFS3_UNREACHABLE();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookup our parent
|
// lookup our parent
|
||||||
@@ -11565,6 +11605,7 @@ int lfs3_file_opencfg_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// need to create an entry?
|
// need to create an entry?
|
||||||
|
#ifndef LFS3_RDONLY
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
// small file wrset? can we atomically commit everything in one
|
// small file wrset? can we atomically commit everything in one
|
||||||
// commit? currently this is only possible via lfs3_set
|
// commit? currently this is only possible via lfs3_set
|
||||||
@@ -11608,6 +11649,7 @@ int lfs3_file_opencfg_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// fetch the file struct and custom attrs
|
// fetch the file struct and custom attrs
|
||||||
err = lfs3_file_fetch(lfs3, file, file->b.o.flags);
|
err = lfs3_file_fetch(lfs3, file, file->b.o.flags);
|
||||||
@@ -11616,6 +11658,7 @@ int lfs3_file_opencfg_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check metadata/data for errors?
|
// check metadata/data for errors?
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
if (lfs3_t_isckmeta(file->b.o.flags)
|
if (lfs3_t_isckmeta(file->b.o.flags)
|
||||||
|| lfs3_t_isckdata(file->b.o.flags)) {
|
|| lfs3_t_isckdata(file->b.o.flags)) {
|
||||||
err = lfs3_file_ck(lfs3, file, file->b.o.flags);
|
err = lfs3_file_ck(lfs3, file, file->b.o.flags);
|
||||||
@@ -11623,6 +11666,7 @@ int lfs3_file_opencfg_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// add to tracked mdirs
|
// add to tracked mdirs
|
||||||
lfs3_omdir_open(lfs3, &file->b.o);
|
lfs3_omdir_open(lfs3, &file->b.o);
|
||||||
@@ -11661,6 +11705,7 @@ int lfs3_file_opencfg(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
LFS3_ASSERT(!lfs3_o_isrdonly(flags) || !lfs3_o_iscreat(flags));
|
LFS3_ASSERT(!lfs3_o_isrdonly(flags) || !lfs3_o_iscreat(flags));
|
||||||
LFS3_ASSERT(!lfs3_o_isrdonly(flags) || !lfs3_o_isexcl(flags));
|
LFS3_ASSERT(!lfs3_o_isrdonly(flags) || !lfs3_o_isexcl(flags));
|
||||||
LFS3_ASSERT(!lfs3_o_isrdonly(flags) || !lfs3_o_istrunc(flags));
|
LFS3_ASSERT(!lfs3_o_isrdonly(flags) || !lfs3_o_istrunc(flags));
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
for (lfs3_size_t i = 0; i < cfg->attr_count; i++) {
|
for (lfs3_size_t i = 0; i < cfg->attr_count; i++) {
|
||||||
// these flags require a writable attr
|
// these flags require a writable attr
|
||||||
LFS3_ASSERT(!lfs3_o_isrdonly(cfg->attrs[i].flags)
|
LFS3_ASSERT(!lfs3_o_isrdonly(cfg->attrs[i].flags)
|
||||||
@@ -11668,6 +11713,7 @@ int lfs3_file_opencfg(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
LFS3_ASSERT(!lfs3_o_isrdonly(cfg->attrs[i].flags)
|
LFS3_ASSERT(!lfs3_o_isrdonly(cfg->attrs[i].flags)
|
||||||
|| !lfs3_o_isexcl(cfg->attrs[i].flags));
|
|| !lfs3_o_isexcl(cfg->attrs[i].flags));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return lfs3_file_opencfg_(lfs3, file, path, flags,
|
return lfs3_file_opencfg_(lfs3, file, path, flags,
|
||||||
cfg);
|
cfg);
|
||||||
@@ -11684,6 +11730,7 @@ int lfs3_file_open(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
|
|
||||||
// clean up resources
|
// clean up resources
|
||||||
static void lfs3_file_close_(lfs3_t *lfs3, const lfs3_file_t *file) {
|
static void lfs3_file_close_(lfs3_t *lfs3, const lfs3_file_t *file) {
|
||||||
|
(void)lfs3;
|
||||||
// clean up memory
|
// clean up memory
|
||||||
if (!file->cfg->cache_buffer) {
|
if (!file->cfg->cache_buffer) {
|
||||||
lfs3_free(file->cache.buffer);
|
lfs3_free(file->cache.buffer);
|
||||||
@@ -11692,12 +11739,12 @@ static void lfs3_file_close_(lfs3_t *lfs3, const lfs3_file_t *file) {
|
|||||||
// are we orphaning a file?
|
// are we orphaning a file?
|
||||||
//
|
//
|
||||||
// make sure we check _after_ removing ourselves
|
// make sure we check _after_ removing ourselves
|
||||||
|
#ifndef LFS3_RDONLY
|
||||||
if (lfs3_o_isuncreat(file->b.o.flags)
|
if (lfs3_o_isuncreat(file->b.o.flags)
|
||||||
&& !lfs3_omdir_ismidopen(lfs3, file->b.o.mdir.mid, -1)) {
|
&& !lfs3_omdir_ismidopen(lfs3, file->b.o.mdir.mid, -1)) {
|
||||||
// this can only happen in a rdwr filesystem
|
// this can only happen in a rdwr filesystem
|
||||||
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags));
|
LFS3_ASSERT(!lfs3_m_isrdonly(lfs3->flags));
|
||||||
|
|
||||||
#ifndef LFS3_RDONLY
|
|
||||||
// this gets a bit messy, since we're not able to write to the
|
// this gets a bit messy, since we're not able to write to the
|
||||||
// filesystem if we're rdonly or desynced, fortunately we have
|
// filesystem if we're rdonly or desynced, fortunately we have
|
||||||
// a few tricks
|
// a few tricks
|
||||||
@@ -11710,11 +11757,14 @@ static void lfs3_file_close_(lfs3_t *lfs3, const lfs3_file_t *file) {
|
|||||||
} else {
|
} else {
|
||||||
lfs3->flags |= LFS3_I_MKCONSISTENT;
|
lfs3->flags |= LFS3_I_MKCONSISTENT;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// needed in lfs3_file_close
|
// needed in lfs3_file_close
|
||||||
|
#ifdef LFS3_KVONLY
|
||||||
|
static
|
||||||
|
#endif
|
||||||
int lfs3_file_sync(lfs3_t *lfs3, lfs3_file_t *file);
|
int lfs3_file_sync(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
|
||||||
int lfs3_file_close(lfs3_t *lfs3, lfs3_file_t *file) {
|
int lfs3_file_close(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
@@ -11738,7 +11788,7 @@ int lfs3_file_close(lfs3_t *lfs3, lfs3_file_t *file) {
|
|||||||
|
|
||||||
// low-level file reading
|
// low-level file reading
|
||||||
|
|
||||||
static int lfs3_file_lookup_(lfs3_t *lfs3, const lfs3_file_t *file,
|
static int lfs3_file_lookupnext_(lfs3_t *lfs3, const lfs3_file_t *file,
|
||||||
lfs3_bid_t bid,
|
lfs3_bid_t bid,
|
||||||
lfs3_bid_t *bid_, lfs3_bid_t *weight_, lfs3_bptr_t *bptr_) {
|
lfs3_bid_t *bid_, lfs3_bid_t *weight_, lfs3_bptr_t *bptr_) {
|
||||||
lfs3_tag_t tag;
|
lfs3_tag_t tag;
|
||||||
@@ -11772,7 +11822,8 @@ static int lfs3_file_lookup_(lfs3_t *lfs3, const lfs3_file_t *file,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lfs3_file_lookup(lfs3_t *lfs3, const lfs3_file_t *file,
|
#ifndef LFS3_KVONLY
|
||||||
|
static int lfs3_file_lookupnext(lfs3_t *lfs3, const lfs3_file_t *file,
|
||||||
lfs3_bid_t bid,
|
lfs3_bid_t bid,
|
||||||
lfs3_bid_t *bid_, lfs3_bid_t *weight_, lfs3_bptr_t *bptr_) {
|
lfs3_bid_t *bid_, lfs3_bid_t *weight_, lfs3_bptr_t *bptr_) {
|
||||||
// hits our leaf?
|
// hits our leaf?
|
||||||
@@ -11804,7 +11855,7 @@ static int lfs3_file_lookup(lfs3_t *lfs3, const lfs3_file_t *file,
|
|||||||
// lookup on disk
|
// lookup on disk
|
||||||
lfs3_bid_t bid__;
|
lfs3_bid_t bid__;
|
||||||
lfs3_bid_t weight__;
|
lfs3_bid_t weight__;
|
||||||
int err = lfs3_file_lookup_(lfs3, file, bid,
|
int err = lfs3_file_lookupnext_(lfs3, file, bid,
|
||||||
&bid__, &weight__, bptr_);
|
&bid__, &weight__, bptr_);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
@@ -11840,37 +11891,48 @@ static int lfs3_file_lookup(lfs3_t *lfs3, const lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// needed in lfs3_file_read_
|
// needed in lfs3_file_readnext
|
||||||
static int lfs3_file_crystallize(lfs3_t *lfs3, lfs3_file_t *file);
|
static int lfs3_file_crystallize(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
|
||||||
static lfs3_ssize_t lfs3_file_read_(lfs3_t *lfs3, lfs3_file_t *file,
|
static lfs3_ssize_t lfs3_file_readnext(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
lfs3_off_t pos, uint8_t *buffer, lfs3_size_t size) {
|
lfs3_off_t pos, uint8_t *buffer, lfs3_size_t size) {
|
||||||
// need to fetch a new leaf?
|
// hit our leaf?
|
||||||
if (!(pos >= file->leaf.pos
|
lfs3_bid_t bid;
|
||||||
|
lfs3_bid_t weight;
|
||||||
|
lfs3_bptr_t bptr;
|
||||||
|
if (LFS3_IFDEF_KVONLY(
|
||||||
|
false,
|
||||||
|
pos >= file->leaf.pos
|
||||||
&& pos < file->leaf.pos + file->leaf.weight)) {
|
&& pos < file->leaf.pos + file->leaf.weight)) {
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
|
bid = file->leaf.pos + (file->leaf.weight-1);
|
||||||
|
weight = file->leaf.weight;
|
||||||
|
bptr = file->leaf.bptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// need to fetch a new leaf?
|
||||||
|
} else {
|
||||||
// leaf in use? we need to crystallize/graft it
|
// leaf in use? we need to crystallize/graft it
|
||||||
//
|
//
|
||||||
// it would be easier to just call lfs3_file_flush here, but
|
// it would be easier to just call lfs3_file_flush here, but
|
||||||
// we don't want to drag in the extra stack usage
|
// we don't want to drag in the extra stack usage
|
||||||
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
if (lfs3_o_isungraft(file->b.o.flags)
|
if (lfs3_o_isungraft(file->b.o.flags)
|
||||||
|| lfs3_o_isuncryst(file->b.o.flags)) {
|
|| lfs3_o_isuncryst(file->b.o.flags)) {
|
||||||
// readonly files can't be uncrystallized/ungrafted
|
// readonly files can't be uncrystallized/ungrafted
|
||||||
LFS3_ASSERT(!lfs3_o_isrdonly(file->b.o.flags));
|
LFS3_ASSERT(!lfs3_o_isrdonly(file->b.o.flags));
|
||||||
|
|
||||||
#ifndef LFS3_RDONLY
|
|
||||||
int err = lfs3_file_crystallize(lfs3, file);
|
int err = lfs3_file_crystallize(lfs3, file);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// fetch a leaf
|
// fetch a leaf
|
||||||
lfs3_bid_t bid;
|
int err = lfs3_file_lookupnext_(lfs3, file, pos,
|
||||||
lfs3_bid_t weight;
|
|
||||||
lfs3_bptr_t bptr;
|
|
||||||
int err = lfs3_file_lookup_(lfs3, file, pos,
|
|
||||||
&bid, &weight, &bptr);
|
&bid, &weight, &bptr);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
@@ -11887,22 +11949,24 @@ static lfs3_ssize_t lfs3_file_read_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
file->leaf.pos = bid - (weight-1);
|
file->leaf.pos = bid - (weight-1);
|
||||||
file->leaf.weight = weight;
|
file->leaf.weight = weight;
|
||||||
file->leaf.bptr = bptr;
|
file->leaf.bptr = bptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// any data on disk?
|
// any data on disk?
|
||||||
lfs3_off_t pos_ = pos;
|
lfs3_off_t pos_ = pos;
|
||||||
if (pos_ < file->leaf.pos + lfs3_bptr_size(&file->leaf.bptr)) {
|
if (pos_ < bid-(weight-1) + lfs3_bptr_size(&bptr)) {
|
||||||
// note one important side-effect here is a strict
|
// note one important side-effect here is a strict
|
||||||
// data hint
|
// data hint
|
||||||
lfs3_ssize_t d = lfs3_min(
|
lfs3_ssize_t d = lfs3_min(
|
||||||
size,
|
size,
|
||||||
lfs3_bptr_size(&file->leaf.bptr)
|
lfs3_bptr_size(&bptr)
|
||||||
- (pos_ - file->leaf.pos));
|
- (pos_ - (bid-(weight-1))));
|
||||||
lfs3_data_t slice = LFS3_DATA_SLICE(file->leaf.bptr.data,
|
lfs3_data_t slice = LFS3_DATA_SLICE(bptr.data,
|
||||||
pos_ - file->leaf.pos,
|
pos_ - (bid-(weight-1)),
|
||||||
d);
|
d);
|
||||||
d = lfs3_data_read(lfs3, &slice,
|
d = lfs3_data_read(lfs3, &slice,
|
||||||
buffer, d);
|
buffer, d);
|
||||||
@@ -11918,7 +11982,7 @@ static lfs3_ssize_t lfs3_file_read_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
// found a hole? fill with zeros
|
// found a hole? fill with zeros
|
||||||
lfs3_ssize_t d = lfs3_min(
|
lfs3_ssize_t d = lfs3_min(
|
||||||
size,
|
size,
|
||||||
file->leaf.pos+file->leaf.weight - pos_);
|
bid+1 - pos_);
|
||||||
lfs3_memset(buffer, 0, d);
|
lfs3_memset(buffer, 0, d);
|
||||||
|
|
||||||
pos_ += d;
|
pos_ += d;
|
||||||
@@ -11930,6 +11994,37 @@ static lfs3_ssize_t lfs3_file_read_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
|
|
||||||
// high-level file reading
|
// high-level file reading
|
||||||
|
|
||||||
|
#ifdef LFS3_KVONLY
|
||||||
|
// a simpler read if we only read files once
|
||||||
|
static lfs3_ssize_t lfs3_file_readonce(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
|
void *buffer, lfs3_size_t size) {
|
||||||
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
|
// can't read from writeonly files
|
||||||
|
LFS3_ASSERT(!lfs3_o_iswronly(file->b.o.flags));
|
||||||
|
LFS3_ASSERT(size <= 0x7fffffff);
|
||||||
|
|
||||||
|
lfs3_off_t pos_ = 0;
|
||||||
|
uint8_t *buffer_ = buffer;
|
||||||
|
while (size > 0 && pos_ < lfs3_file_size_(file)) {
|
||||||
|
// read from the bshrub/btree
|
||||||
|
lfs3_ssize_t d_ = lfs3_file_readnext(lfs3, file,
|
||||||
|
pos_, buffer_, size);
|
||||||
|
if (d_ < 0) {
|
||||||
|
LFS3_ASSERT(d_ != LFS3_ERR_NOENT);
|
||||||
|
return d_;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos_ += d_;
|
||||||
|
buffer_ += d_;
|
||||||
|
size -= d_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return amount read
|
||||||
|
return pos_;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_ssize_t lfs3_file_read(lfs3_t *lfs3, lfs3_file_t *file,
|
lfs3_ssize_t lfs3_file_read(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
void *buffer, lfs3_size_t size) {
|
void *buffer, lfs3_size_t size) {
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
@@ -11969,7 +12064,7 @@ lfs3_ssize_t lfs3_file_read(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
if (pos_ < lfs3_file_weight_(file)) {
|
if (pos_ < lfs3_file_weight_(file)) {
|
||||||
// bypass cache?
|
// bypass cache?
|
||||||
if ((lfs3_size_t)d >= lfs3_file_cachesize(lfs3, file)) {
|
if ((lfs3_size_t)d >= lfs3_file_cachesize(lfs3, file)) {
|
||||||
lfs3_ssize_t d_ = lfs3_file_read_(lfs3, file,
|
lfs3_ssize_t d_ = lfs3_file_readnext(lfs3, file,
|
||||||
pos_, buffer_, d);
|
pos_, buffer_, d);
|
||||||
if (d_ < 0) {
|
if (d_ < 0) {
|
||||||
LFS3_ASSERT(d_ != LFS3_ERR_NOENT);
|
LFS3_ASSERT(d_ != LFS3_ERR_NOENT);
|
||||||
@@ -11996,7 +12091,7 @@ lfs3_ssize_t lfs3_file_read(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// try to fill our cache with some data
|
// try to fill our cache with some data
|
||||||
lfs3_ssize_t d_ = lfs3_file_read_(lfs3, file,
|
lfs3_ssize_t d_ = lfs3_file_readnext(lfs3, file,
|
||||||
pos_, file->cache.buffer, d);
|
pos_, file->cache.buffer, d);
|
||||||
if (d_ < 0) {
|
if (d_ < 0) {
|
||||||
LFS3_ASSERT(d != LFS3_ERR_NOENT);
|
LFS3_ASSERT(d != LFS3_ERR_NOENT);
|
||||||
@@ -12020,6 +12115,7 @@ lfs3_ssize_t lfs3_file_read(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
file->pos = pos_;
|
file->pos = pos_;
|
||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// low-level file writing
|
// low-level file writing
|
||||||
|
|
||||||
@@ -12032,7 +12128,7 @@ static int lfs3_file_commit(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// graft bptr/fragments into our bshrub/btree
|
// graft bptr/fragments into our bshrub/btree
|
||||||
#ifndef LFS3_RDONLY
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
static int lfs3_file_graft(lfs3_t *lfs3, lfs3_file_t *file,
|
static int lfs3_file_graft(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
lfs3_off_t pos, lfs3_off_t weight, lfs3_soff_t delta,
|
lfs3_off_t pos, lfs3_off_t weight, lfs3_soff_t delta,
|
||||||
// data_count=-1 => single bptr
|
// data_count=-1 => single bptr
|
||||||
@@ -12080,7 +12176,7 @@ static int lfs3_file_graft(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
while (pos < file->b.shrub.weight) {
|
while (pos < file->b.shrub.weight) {
|
||||||
lfs3_bid_t weight_;
|
lfs3_bid_t weight_;
|
||||||
lfs3_bptr_t bptr_;
|
lfs3_bptr_t bptr_;
|
||||||
int err = lfs3_file_lookup_(lfs3, file, pos,
|
int err = lfs3_file_lookupnext_(lfs3, file, pos,
|
||||||
&bid, &weight_, &bptr_);
|
&bid, &weight_, &bptr_);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS3_ASSERT(err != LFS3_ERR_NOENT);
|
LFS3_ASSERT(err != LFS3_ERR_NOENT);
|
||||||
@@ -12302,7 +12398,7 @@ static int lfs3_file_graft(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LFS3_RDONLY
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
static int lfs3_file_crystallize_(lfs3_t *lfs3, lfs3_file_t *file,
|
static int lfs3_file_crystallize_(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
lfs3_off_t block_pos, lfs3_soff_t crystal_min, lfs3_soff_t crystal_max,
|
lfs3_off_t block_pos, lfs3_soff_t crystal_min, lfs3_soff_t crystal_max,
|
||||||
lfs3_off_t pos, const uint8_t *buffer, lfs3_size_t size) {
|
lfs3_off_t pos, const uint8_t *buffer, lfs3_size_t size) {
|
||||||
@@ -12391,7 +12487,7 @@ static int lfs3_file_crystallize_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
lfs3_bid_t bid__;
|
lfs3_bid_t bid__;
|
||||||
lfs3_bid_t weight__;
|
lfs3_bid_t weight__;
|
||||||
lfs3_bptr_t bptr__;
|
lfs3_bptr_t bptr__;
|
||||||
int err = lfs3_file_lookup(lfs3, file, pos_,
|
int err = lfs3_file_lookupnext(lfs3, file, pos_,
|
||||||
&bid__, &weight__, &bptr__);
|
&bid__, &weight__, &bptr__);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS3_ASSERT(err != LFS3_ERR_NOENT);
|
LFS3_ASSERT(err != LFS3_ERR_NOENT);
|
||||||
@@ -12531,7 +12627,7 @@ static int lfs3_file_crystallize_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LFS3_RDONLY
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
static int lfs3_file_crystallize(lfs3_t *lfs3, lfs3_file_t *file) {
|
static int lfs3_file_crystallize(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
bool flushable = (
|
bool flushable = (
|
||||||
file->cache.pos
|
file->cache.pos
|
||||||
@@ -12581,7 +12677,91 @@ static int lfs3_file_crystallize(lfs3_t *lfs3, lfs3_file_t *file) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LFS3_RDONLY
|
#if defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
|
// a simpler flush if we only flush files once
|
||||||
|
static int lfs3_file_flushonce_(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
|
const uint8_t *buffer, lfs3_size_t size) {
|
||||||
|
lfs3_off_t pos = 0;
|
||||||
|
while (size > 0) {
|
||||||
|
// enough data for a block?
|
||||||
|
if (size > lfs3->cfg->crystal_thresh) {
|
||||||
|
// align down for prog alignment
|
||||||
|
lfs3_ssize_t d = lfs3_aligndown(
|
||||||
|
lfs3_min(size, lfs3->cfg->block_size),
|
||||||
|
lfs3->cfg->prog_size);
|
||||||
|
|
||||||
|
relocate:;
|
||||||
|
// allocate a new block
|
||||||
|
lfs3_sblock_t block = lfs3_alloc(lfs3, true);
|
||||||
|
if (block < 0) {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// write our data
|
||||||
|
uint32_t cksum = 0;
|
||||||
|
int err = lfs3_bd_prog(lfs3, block, 0, buffer, d,
|
||||||
|
&cksum, true);
|
||||||
|
if (err) {
|
||||||
|
// bad prog? try another block
|
||||||
|
if (err == LFS3_ERR_CORRUPT) {
|
||||||
|
goto relocate;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// finalize our write
|
||||||
|
err = lfs3_bd_flush(lfs3,
|
||||||
|
&cksum, true);
|
||||||
|
if (err) {
|
||||||
|
// bad prog? try another block
|
||||||
|
if (err == LFS3_ERR_CORRUPT) {
|
||||||
|
goto relocate;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a block pointer
|
||||||
|
lfs3_bptr_t bptr;
|
||||||
|
lfs3_bptr_init(&bptr,
|
||||||
|
LFS3_DATA_DISK(block, 0, d),
|
||||||
|
d,
|
||||||
|
cksum);
|
||||||
|
|
||||||
|
// and commit to bshrub/btree
|
||||||
|
err = lfs3_file_commit(lfs3, file, pos, LFS3_RATTRS(
|
||||||
|
LFS3_RATTR_BPTR(LFS3_TAG_BLOCK, +d, &bptr)));
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += d;
|
||||||
|
buffer += d;
|
||||||
|
size -= d;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback to writing fragments
|
||||||
|
lfs3_ssize_t d = lfs3_min(size, lfs3->cfg->fragment_size);
|
||||||
|
|
||||||
|
// commit to bshrub/btree
|
||||||
|
int err = lfs3_file_commit(lfs3, file, pos, LFS3_RATTRS(
|
||||||
|
LFS3_RATTR_DATA(
|
||||||
|
LFS3_TAG_DATA, +d,
|
||||||
|
&LFS3_DATA_BUF(buffer, d))));
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += d;
|
||||||
|
buffer += d;
|
||||||
|
size -= d;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
static int lfs3_file_flush_(lfs3_t *lfs3, lfs3_file_t *file,
|
static int lfs3_file_flush_(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
lfs3_off_t pos, const uint8_t *buffer, lfs3_size_t size) {
|
lfs3_off_t pos, const uint8_t *buffer, lfs3_size_t size) {
|
||||||
// we can skip some btree lookups if we know we are aligned from a
|
// we can skip some btree lookups if we know we are aligned from a
|
||||||
@@ -12621,7 +12801,7 @@ static int lfs3_file_flush_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update buffer state
|
// update buffer state
|
||||||
lfs3_soff_t d = lfs3_max(
|
lfs3_ssize_t d = lfs3_max(
|
||||||
file->leaf.pos + lfs3_bptr_size(&file->leaf.bptr),
|
file->leaf.pos + lfs3_bptr_size(&file->leaf.bptr),
|
||||||
pos) - pos;
|
pos) - pos;
|
||||||
pos += d;
|
pos += d;
|
||||||
@@ -12661,7 +12841,7 @@ static int lfs3_file_flush_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
lfs3_bid_t bid;
|
lfs3_bid_t bid;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_bptr_t bptr;
|
lfs3_bptr_t bptr;
|
||||||
int err = lfs3_file_lookup(lfs3, file, poke,
|
int err = lfs3_file_lookupnext(lfs3, file, poke,
|
||||||
&bid, &weight, &bptr);
|
&bid, &weight, &bptr);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS3_ASSERT(err != LFS3_ERR_NOENT);
|
LFS3_ASSERT(err != LFS3_ERR_NOENT);
|
||||||
@@ -12694,7 +12874,7 @@ static int lfs3_file_flush_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
lfs3_bid_t bid;
|
lfs3_bid_t bid;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_bptr_t bptr;
|
lfs3_bptr_t bptr;
|
||||||
int err = lfs3_file_lookup(lfs3, file, poke,
|
int err = lfs3_file_lookupnext(lfs3, file, poke,
|
||||||
&bid, &weight, &bptr);
|
&bid, &weight, &bptr);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS3_ASSERT(err != LFS3_ERR_NOENT);
|
LFS3_ASSERT(err != LFS3_ERR_NOENT);
|
||||||
@@ -12749,7 +12929,7 @@ static int lfs3_file_flush_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update buffer state, this may or may not make progress
|
// update buffer state, this may or may not make progress
|
||||||
lfs3_soff_t d = lfs3_max(
|
lfs3_ssize_t d = lfs3_max(
|
||||||
file->leaf.pos + lfs3_bptr_size(&file->leaf.bptr),
|
file->leaf.pos + lfs3_bptr_size(&file->leaf.bptr),
|
||||||
pos) - pos;
|
pos) - pos;
|
||||||
pos += d;
|
pos += d;
|
||||||
@@ -12782,7 +12962,7 @@ static int lfs3_file_flush_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
lfs3_bid_t bid;
|
lfs3_bid_t bid;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_bptr_t bptr;
|
lfs3_bptr_t bptr;
|
||||||
int err = lfs3_file_lookup(lfs3, file,
|
int err = lfs3_file_lookupnext(lfs3, file,
|
||||||
lfs3_min(
|
lfs3_min(
|
||||||
crystal_start-1,
|
crystal_start-1,
|
||||||
file->b.shrub.weight-1),
|
file->b.shrub.weight-1),
|
||||||
@@ -12820,7 +13000,7 @@ static int lfs3_file_flush_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update buffer state, this may or may not make progress
|
// update buffer state, this may or may not make progress
|
||||||
lfs3_soff_t d = lfs3_max(
|
lfs3_ssize_t d = lfs3_max(
|
||||||
file->leaf.pos + lfs3_bptr_size(&file->leaf.bptr),
|
file->leaf.pos + lfs3_bptr_size(&file->leaf.bptr),
|
||||||
pos) - pos;
|
pos) - pos;
|
||||||
pos += d;
|
pos += d;
|
||||||
@@ -12887,7 +13067,7 @@ fragment:;
|
|||||||
lfs3_bid_t bid;
|
lfs3_bid_t bid;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_bptr_t bptr;
|
lfs3_bptr_t bptr;
|
||||||
int err = lfs3_file_lookup(lfs3, file,
|
int err = lfs3_file_lookupnext(lfs3, file,
|
||||||
fragment_start-1,
|
fragment_start-1,
|
||||||
&bid, &weight, &bptr);
|
&bid, &weight, &bptr);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -12934,7 +13114,7 @@ fragment:;
|
|||||||
lfs3_bid_t bid;
|
lfs3_bid_t bid;
|
||||||
lfs3_bid_t weight;
|
lfs3_bid_t weight;
|
||||||
lfs3_bptr_t bptr;
|
lfs3_bptr_t bptr;
|
||||||
int err = lfs3_file_lookup(lfs3, file,
|
int err = lfs3_file_lookupnext(lfs3, file,
|
||||||
fragment_end,
|
fragment_end,
|
||||||
&bid, &weight, &bptr);
|
&bid, &weight, &bptr);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -12998,7 +13178,7 @@ fragment:;
|
|||||||
|
|
||||||
// high-level file writing
|
// high-level file writing
|
||||||
|
|
||||||
#ifndef LFS3_RDONLY
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
lfs3_ssize_t lfs3_file_write(lfs3_t *lfs3, lfs3_file_t *file,
|
lfs3_ssize_t lfs3_file_write(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
const void *buffer, lfs3_size_t size) {
|
const void *buffer, lfs3_size_t size) {
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
@@ -13149,6 +13329,9 @@ failed:;
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LFS3_KVONLY
|
||||||
|
static
|
||||||
|
#endif
|
||||||
int lfs3_file_flush(lfs3_t *lfs3, lfs3_file_t *file) {
|
int lfs3_file_flush(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
(void)lfs3;
|
(void)lfs3;
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
@@ -13174,22 +13357,32 @@ int lfs3_file_flush(lfs3_t *lfs3, lfs3_file_t *file) {
|
|||||||
|
|
||||||
// flush our cache
|
// flush our cache
|
||||||
if (lfs3_o_isunflush(file->b.o.flags)) {
|
if (lfs3_o_isunflush(file->b.o.flags)) {
|
||||||
|
#ifdef LFS3_KVONLY
|
||||||
|
err = lfs3_file_flushonce_(lfs3, file,
|
||||||
|
file->cache.buffer, file->cache.size);
|
||||||
|
if (err) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
#else
|
||||||
err = lfs3_file_flush_(lfs3, file,
|
err = lfs3_file_flush_(lfs3, file,
|
||||||
file->cache.pos, file->cache.buffer, file->cache.size);
|
file->cache.pos, file->cache.buffer, file->cache.size);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// mark as flushed
|
// mark as flushed
|
||||||
file->b.o.flags &= ~LFS3_o_UNFLUSH;
|
file->b.o.flags &= ~LFS3_o_UNFLUSH;
|
||||||
}
|
}
|
||||||
|
|
||||||
// and crystallize/graft our leaf
|
// and crystallize/graft our leaf
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
err = lfs3_file_crystallize(lfs3, file);
|
err = lfs3_file_crystallize(lfs3, file);
|
||||||
if (err) {
|
if (err) {
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -13207,7 +13400,7 @@ LFS3_NOINLINE
|
|||||||
static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
const lfs3_name_t *name) {
|
const lfs3_name_t *name) {
|
||||||
// build a commit of any pending file metadata
|
// build a commit of any pending file metadata
|
||||||
lfs3_rattr_t rattrs[4];
|
lfs3_rattr_t rattrs[LFS3_IFDEF_KVONLY(3, 4)];
|
||||||
lfs3_size_t rattr_count = 0;
|
lfs3_size_t rattr_count = 0;
|
||||||
lfs3_data_t name_data;
|
lfs3_data_t name_data;
|
||||||
lfs3_rattr_t shrub_rattrs[1];
|
lfs3_rattr_t shrub_rattrs[1];
|
||||||
@@ -13255,11 +13448,15 @@ static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
|| lfs3_o_isuncryst(file->b.o.flags)
|
|| lfs3_o_isuncryst(file->b.o.flags)
|
||||||
|| lfs3_o_isungraft(file->b.o.flags)) {
|
|| lfs3_o_isungraft(file->b.o.flags)) {
|
||||||
// this only works if the file is entirely in our cache
|
// this only works if the file is entirely in our cache
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
LFS3_ASSERT(file->cache.pos == 0);
|
LFS3_ASSERT(file->cache.pos == 0);
|
||||||
|
#endif
|
||||||
LFS3_ASSERT(file->cache.size == lfs3_file_size_(file));
|
LFS3_ASSERT(file->cache.size == lfs3_file_size_(file));
|
||||||
|
|
||||||
// discard any lingering bshrub state
|
// discard any lingering bshrub state
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_file_discardleaf(file);
|
lfs3_file_discardleaf(file);
|
||||||
|
#endif
|
||||||
lfs3_file_discardbshrub(file);
|
lfs3_file_discardbshrub(file);
|
||||||
|
|
||||||
// build a small shrub commit
|
// build a small shrub commit
|
||||||
@@ -13321,6 +13518,7 @@ static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
// this gets real messy, since users can change custom attributes
|
// this gets real messy, since users can change custom attributes
|
||||||
// whenever they want without informing littlefs, the best we can do
|
// whenever they want without informing littlefs, the best we can do
|
||||||
// is read from disk to manually check if any attributes changed
|
// is read from disk to manually check if any attributes changed
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
bool attrs = lfs3_o_isunsync(file->b.o.flags);
|
bool attrs = lfs3_o_isunsync(file->b.o.flags);
|
||||||
if (!attrs) {
|
if (!attrs) {
|
||||||
for (lfs3_size_t i = 0; i < file->cfg->attr_count; i++) {
|
for (lfs3_size_t i = 0; i < file->cfg->attr_count; i++) {
|
||||||
@@ -13357,6 +13555,7 @@ static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
rattrs[rattr_count++] = LFS3_RATTR_ATTRS(
|
rattrs[rattr_count++] = LFS3_RATTR_ATTRS(
|
||||||
file->cfg->attrs, file->cfg->attr_count);
|
file->cfg->attrs, file->cfg->attr_count);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// pending metadata? looks like we need to write to disk
|
// pending metadata? looks like we need to write to disk
|
||||||
if (rattr_count > 0) {
|
if (rattr_count > 0) {
|
||||||
@@ -13372,6 +13571,7 @@ static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
|
|
||||||
// update in-device state
|
// update in-device state
|
||||||
for (lfs3_omdir_t *o = lfs3->omdirs; o; o = o->next) {
|
for (lfs3_omdir_t *o = lfs3->omdirs; o; o = o->next) {
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
if (lfs3_o_type(o->flags) == LFS3_TYPE_REG
|
if (lfs3_o_type(o->flags) == LFS3_TYPE_REG
|
||||||
&& o->mdir.mid == file->b.o.mdir.mid
|
&& o->mdir.mid == file->b.o.mdir.mid
|
||||||
// don't double update
|
// don't double update
|
||||||
@@ -13441,9 +13641,11 @@ static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// clobber entangled traversals
|
// clobber entangled traversals
|
||||||
} else if (lfs3_o_type(o->flags) == LFS3_type_TRAVERSAL
|
if (lfs3_o_type(o->flags) == LFS3_type_TRAVERSAL
|
||||||
&& o->mdir.mid == file->b.o.mdir.mid) {
|
&& o->mdir.mid == file->b.o.mdir.mid) {
|
||||||
lfs3_traversal_clobber(lfs3, (lfs3_traversal_t*)o);
|
lfs3_traversal_clobber(lfs3, (lfs3_traversal_t*)o);
|
||||||
}
|
}
|
||||||
@@ -13459,6 +13661,9 @@ static int lfs3_file_sync_(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LFS3_KVONLY
|
||||||
|
static
|
||||||
|
#endif
|
||||||
int lfs3_file_sync(lfs3_t *lfs3, lfs3_file_t *file) {
|
int lfs3_file_sync(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
(void)lfs3;
|
(void)lfs3;
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
@@ -13511,6 +13716,7 @@ failed:;
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_desync(lfs3_t *lfs3, lfs3_file_t *file) {
|
int lfs3_file_desync(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
(void)lfs3;
|
(void)lfs3;
|
||||||
(void)file;
|
(void)file;
|
||||||
@@ -13522,7 +13728,9 @@ int lfs3_file_desync(lfs3_t *lfs3, lfs3_file_t *file) {
|
|||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_resync(lfs3_t *lfs3, lfs3_file_t *file) {
|
int lfs3_file_resync(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
(void)lfs3;
|
(void)lfs3;
|
||||||
(void)file;
|
(void)file;
|
||||||
@@ -13563,9 +13771,11 @@ failed:;
|
|||||||
return err;
|
return err;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// other file operations
|
// other file operations
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_soff_t lfs3_file_seek(lfs3_t *lfs3, lfs3_file_t *file,
|
lfs3_soff_t lfs3_file_seek(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
lfs3_soff_t off, uint8_t whence) {
|
lfs3_soff_t off, uint8_t whence) {
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
@@ -13593,14 +13803,18 @@ lfs3_soff_t lfs3_file_seek(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
file->pos = pos_;
|
file->pos = pos_;
|
||||||
return pos_;
|
return pos_;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_soff_t lfs3_file_tell(lfs3_t *lfs3, lfs3_file_t *file) {
|
lfs3_soff_t lfs3_file_tell(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
(void)lfs3;
|
(void)lfs3;
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
|
|
||||||
return file->pos;
|
return file->pos;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_soff_t lfs3_file_rewind(lfs3_t *lfs3, lfs3_file_t *file) {
|
lfs3_soff_t lfs3_file_rewind(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
(void)lfs3;
|
(void)lfs3;
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
@@ -13608,15 +13822,18 @@ lfs3_soff_t lfs3_file_rewind(lfs3_t *lfs3, lfs3_file_t *file) {
|
|||||||
file->pos = 0;
|
file->pos = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_soff_t lfs3_file_size(lfs3_t *lfs3, lfs3_file_t *file) {
|
lfs3_soff_t lfs3_file_size(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
(void)lfs3;
|
(void)lfs3;
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
|
|
||||||
return lfs3_file_size_(file);
|
return lfs3_file_size_(file);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef LFS3_RDONLY
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
int lfs3_file_truncate(lfs3_t *lfs3, lfs3_file_t *file, lfs3_off_t size_) {
|
int lfs3_file_truncate(lfs3_t *lfs3, lfs3_file_t *file, lfs3_off_t size_) {
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
// can't write to readonly files
|
// can't write to readonly files
|
||||||
@@ -13698,7 +13915,7 @@ failed:;
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef LFS3_RDONLY
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
int lfs3_file_fruncate(lfs3_t *lfs3, lfs3_file_t *file, lfs3_off_t size_) {
|
int lfs3_file_fruncate(lfs3_t *lfs3, lfs3_file_t *file, lfs3_off_t size_) {
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
// can't write to readonly files
|
// can't write to readonly files
|
||||||
@@ -13846,13 +14063,16 @@ static int lfs3_file_traverse_(lfs3_t *lfs3, const lfs3_bshrub_t *bshrub,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
static int lfs3_file_traverse(lfs3_t *lfs3, const lfs3_file_t *file,
|
static int lfs3_file_traverse(lfs3_t *lfs3, const lfs3_file_t *file,
|
||||||
lfs3_btraversal_t *bt,
|
lfs3_btraversal_t *bt,
|
||||||
lfs3_bid_t *bid_, lfs3_tag_t *tag_, lfs3_bptr_t *bptr) {
|
lfs3_bid_t *bid_, lfs3_tag_t *tag_, lfs3_bptr_t *bptr) {
|
||||||
return lfs3_file_traverse_(lfs3, &file->b, bt,
|
return lfs3_file_traverse_(lfs3, &file->b, bt,
|
||||||
bid_, tag_, bptr);
|
bid_, tag_, bptr);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
static int lfs3_file_ck(lfs3_t *lfs3, const lfs3_file_t *file,
|
static int lfs3_file_ck(lfs3_t *lfs3, const lfs3_file_t *file,
|
||||||
uint32_t flags) {
|
uint32_t flags) {
|
||||||
// validate ungrafted data block?
|
// validate ungrafted data block?
|
||||||
@@ -13909,7 +14129,9 @@ static int lfs3_file_ck(lfs3_t *lfs3, const lfs3_file_t *file,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_ckmeta(lfs3_t *lfs3, lfs3_file_t *file) {
|
int lfs3_file_ckmeta(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
// can't read from writeonly files
|
// can't read from writeonly files
|
||||||
@@ -13918,7 +14140,9 @@ int lfs3_file_ckmeta(lfs3_t *lfs3, lfs3_file_t *file) {
|
|||||||
return lfs3_file_ck(lfs3, file,
|
return lfs3_file_ck(lfs3, file,
|
||||||
LFS3_T_RDONLY | LFS3_T_CKMETA);
|
LFS3_T_RDONLY | LFS3_T_CKMETA);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_ckdata(lfs3_t *lfs3, lfs3_file_t *file) {
|
int lfs3_file_ckdata(lfs3_t *lfs3, lfs3_file_t *file) {
|
||||||
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
LFS3_ASSERT(lfs3_omdir_isopen(lfs3, &file->b.o));
|
||||||
// can't read from writeonly files
|
// can't read from writeonly files
|
||||||
@@ -13927,6 +14151,7 @@ int lfs3_file_ckdata(lfs3_t *lfs3, lfs3_file_t *file) {
|
|||||||
return lfs3_file_ck(lfs3, file,
|
return lfs3_file_ck(lfs3, file,
|
||||||
LFS3_T_RDONLY | LFS3_T_CKMETA | LFS3_T_CKDATA);
|
LFS3_T_RDONLY | LFS3_T_CKMETA | LFS3_T_CKDATA);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -13954,7 +14179,11 @@ lfs3_ssize_t lfs3_get(lfs3_t *lfs3, const char *path,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef LFS3_KVONLY
|
||||||
|
lfs3_ssize_t size_ = lfs3_file_readonce(lfs3, &file, buffer, size);
|
||||||
|
#else
|
||||||
lfs3_ssize_t size_ = lfs3_file_read(lfs3, &file, buffer, size);
|
lfs3_ssize_t size_ = lfs3_file_read(lfs3, &file, buffer, size);
|
||||||
|
#endif
|
||||||
|
|
||||||
// unconditionally close
|
// unconditionally close
|
||||||
err = lfs3_file_close(lfs3, &file);
|
err = lfs3_file_close(lfs3, &file);
|
||||||
|
|||||||
@@ -627,10 +627,14 @@ struct lfs3_file_config {
|
|||||||
// these attributes will be kept up to date with the attributes on-disk.
|
// these attributes will be kept up to date with the attributes on-disk.
|
||||||
// If writeable, these attributes will be written to disk atomically on
|
// If writeable, these attributes will be written to disk atomically on
|
||||||
// every file sync or close.
|
// every file sync or close.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
struct lfs3_attr *attrs;
|
struct lfs3_attr *attrs;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Number of custom attributes in the list
|
// Number of custom attributes in the list
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_size_t attr_count;
|
lfs3_size_t attr_count;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -734,7 +738,9 @@ typedef struct lfs3_file {
|
|||||||
const struct lfs3_file_config *cfg;
|
const struct lfs3_file_config *cfg;
|
||||||
|
|
||||||
// current file position
|
// current file position
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_off_t pos;
|
lfs3_off_t pos;
|
||||||
|
#endif
|
||||||
|
|
||||||
// in-RAM cache
|
// in-RAM cache
|
||||||
//
|
//
|
||||||
@@ -742,15 +748,19 @@ typedef struct lfs3_file {
|
|||||||
struct {
|
struct {
|
||||||
lfs3_off_t size;
|
lfs3_off_t size;
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_off_t pos;
|
lfs3_off_t pos;
|
||||||
|
#endif
|
||||||
} cache;
|
} cache;
|
||||||
|
|
||||||
// on-disk leaf bptr
|
// on-disk leaf bptr
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
struct {
|
struct {
|
||||||
lfs3_off_t pos;
|
lfs3_off_t pos;
|
||||||
lfs3_off_t weight;
|
lfs3_off_t weight;
|
||||||
lfs3_bptr_t bptr;
|
lfs3_bptr_t bptr;
|
||||||
} leaf;
|
} leaf;
|
||||||
|
#endif
|
||||||
} lfs3_file_t;
|
} lfs3_file_t;
|
||||||
|
|
||||||
// littlefs directory type
|
// littlefs directory type
|
||||||
@@ -999,7 +1009,7 @@ int lfs3_removeattr(lfs3_t *lfs3, const char *path, uint8_t type);
|
|||||||
// are values from the enum lfs3_open_flags that are bitwise-ored together.
|
// are values from the enum lfs3_open_flags that are bitwise-ored together.
|
||||||
//
|
//
|
||||||
// Returns a negative error code on failure.
|
// Returns a negative error code on failure.
|
||||||
#ifndef LFS3_NO_MALLOC
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_NO_MALLOC)
|
||||||
int lfs3_file_open(lfs3_t *lfs3, lfs3_file_t *file,
|
int lfs3_file_open(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
const char *path, uint32_t flags);
|
const char *path, uint32_t flags);
|
||||||
#endif
|
#endif
|
||||||
@@ -1014,9 +1024,11 @@ int lfs3_file_open(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
// the config struct must be zeroed for defaults and backwards compatibility.
|
// 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.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_opencfg(lfs3_t *lfs3, lfs3_file_t *file,
|
int lfs3_file_opencfg(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
const char *path, uint32_t flags,
|
const char *path, uint32_t flags,
|
||||||
const struct lfs3_file_config *cfg);
|
const struct lfs3_file_config *cfg);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Close a file
|
// Close a file
|
||||||
//
|
//
|
||||||
@@ -1029,7 +1041,9 @@ int lfs3_file_opencfg(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
// return 0.
|
// return 0.
|
||||||
//
|
//
|
||||||
// Returns a negative error code on failure.
|
// Returns a negative error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_close(lfs3_t *lfs3, lfs3_file_t *file);
|
int lfs3_file_close(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Synchronize a file on storage
|
// Synchronize a file on storage
|
||||||
//
|
//
|
||||||
@@ -1039,7 +1053,9 @@ int lfs3_file_close(lfs3_t *lfs3, lfs3_file_t *file);
|
|||||||
// now recieve file updates and syncs on close.
|
// now recieve file updates and syncs on close.
|
||||||
//
|
//
|
||||||
// Returns a negative error code on failure.
|
// Returns a negative error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_sync(lfs3_t *lfs3, lfs3_file_t *file);
|
int lfs3_file_sync(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Flush any buffered data
|
// Flush any buffered data
|
||||||
//
|
//
|
||||||
@@ -1048,7 +1064,9 @@ int lfs3_file_sync(lfs3_t *lfs3, lfs3_file_t *file);
|
|||||||
// read operations.
|
// read operations.
|
||||||
//
|
//
|
||||||
// Returns a negative error code on failure.
|
// Returns a negative error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_flush(lfs3_t *lfs3, lfs3_file_t *file);
|
int lfs3_file_flush(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Mark a file as desynchronized
|
// Mark a file as desynchronized
|
||||||
//
|
//
|
||||||
@@ -1063,7 +1081,9 @@ int lfs3_file_flush(lfs3_t *lfs3, lfs3_file_t *file);
|
|||||||
// lfs3_file_resync reverses this, marking the file as synchronized again.
|
// lfs3_file_resync reverses this, marking the file as synchronized again.
|
||||||
//
|
//
|
||||||
// Returns a negative error code on failure.
|
// Returns a negative error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_desync(lfs3_t *lfs3, lfs3_file_t *file);
|
int lfs3_file_desync(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Discard unsynchronized changes and mark a file as synchronized
|
// Discard unsynchronized changes and mark a file as synchronized
|
||||||
//
|
//
|
||||||
@@ -1071,14 +1091,18 @@ int lfs3_file_desync(lfs3_t *lfs3, lfs3_file_t *file);
|
|||||||
// may read from disk to figure out file state.
|
// may read from disk to figure out file state.
|
||||||
//
|
//
|
||||||
// Returns a negative error code on failure.
|
// Returns a negative error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_resync(lfs3_t *lfs3, lfs3_file_t *file);
|
int lfs3_file_resync(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Read data from file
|
// Read data from file
|
||||||
//
|
//
|
||||||
// Takes a buffer and size indicating where to store the read data.
|
// Takes a buffer and size indicating where to store the read data.
|
||||||
// Returns the number of bytes read, or a negative error code on failure.
|
// Returns the number of bytes read, or a negative error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_ssize_t lfs3_file_read(lfs3_t *lfs3, lfs3_file_t *file,
|
lfs3_ssize_t lfs3_file_read(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
void *buffer, lfs3_size_t size);
|
void *buffer, lfs3_size_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Write data to file
|
// Write data to file
|
||||||
//
|
//
|
||||||
@@ -1086,7 +1110,7 @@ lfs3_ssize_t lfs3_file_read(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
// actually be updated on the storage until either sync or close is called.
|
// actually be updated on the storage until either sync or close is called.
|
||||||
//
|
//
|
||||||
// Returns the number of bytes written, or a negative error code on failure.
|
// Returns the number of bytes written, or a negative error code on failure.
|
||||||
#ifndef LFS3_RDONLY
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
lfs3_ssize_t lfs3_file_write(lfs3_t *lfs3, lfs3_file_t *file,
|
lfs3_ssize_t lfs3_file_write(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
const void *buffer, lfs3_size_t size);
|
const void *buffer, lfs3_size_t size);
|
||||||
#endif
|
#endif
|
||||||
@@ -1095,8 +1119,10 @@ lfs3_ssize_t lfs3_file_write(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
//
|
//
|
||||||
// The change in position is determined by the offset and whence flag.
|
// The change in position is determined by the offset and whence flag.
|
||||||
// Returns the new position of the file, or a negative error code on failure.
|
// Returns the new position of the file, or a negative error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_soff_t lfs3_file_seek(lfs3_t *lfs3, lfs3_file_t *file,
|
lfs3_soff_t lfs3_file_seek(lfs3_t *lfs3, lfs3_file_t *file,
|
||||||
lfs3_soff_t off, uint8_t whence);
|
lfs3_soff_t off, uint8_t whence);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Truncate/grow the size of the file to the specified size
|
// Truncate/grow the size of the file to the specified size
|
||||||
//
|
//
|
||||||
@@ -1104,7 +1130,7 @@ lfs3_soff_t lfs3_file_seek(lfs3_t *lfs3, lfs3_file_t *file,
|
|||||||
// as if the file was filled with zeros.
|
// as if the file was filled with zeros.
|
||||||
//
|
//
|
||||||
// Returns a negative error code on failure.
|
// Returns a negative error code on failure.
|
||||||
#ifndef LFS3_RDONLY
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
int lfs3_file_truncate(lfs3_t *lfs3, lfs3_file_t *file, lfs3_off_t size);
|
int lfs3_file_truncate(lfs3_t *lfs3, lfs3_file_t *file, lfs3_off_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1114,7 +1140,7 @@ int lfs3_file_truncate(lfs3_t *lfs3, lfs3_file_t *file, lfs3_off_t size);
|
|||||||
// as if the file was filled with zeros.
|
// as if the file was filled with zeros.
|
||||||
//
|
//
|
||||||
// Returns a negative error code on failure.
|
// Returns a negative error code on failure.
|
||||||
#ifndef LFS3_RDONLY
|
#if !defined(LFS3_KVONLY) && !defined(LFS3_RDONLY)
|
||||||
int lfs3_file_fruncate(lfs3_t *lfs3, lfs3_file_t *file, lfs3_off_t size);
|
int lfs3_file_fruncate(lfs3_t *lfs3, lfs3_file_t *file, lfs3_off_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1122,31 +1148,41 @@ int lfs3_file_fruncate(lfs3_t *lfs3, lfs3_file_t *file, lfs3_off_t size);
|
|||||||
//
|
//
|
||||||
// Equivalent to lfs3_file_seek(lfs3, file, 0, LFS3_SEEK_CUR)
|
// Equivalent to lfs3_file_seek(lfs3, file, 0, LFS3_SEEK_CUR)
|
||||||
// Returns the position of the file, or a negative error code on failure.
|
// Returns the position of the file, or a negative error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_soff_t lfs3_file_tell(lfs3_t *lfs3, lfs3_file_t *file);
|
lfs3_soff_t lfs3_file_tell(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Change the position of the file to the beginning of the file
|
// Change the position of the file to the beginning of the file
|
||||||
//
|
//
|
||||||
// Equivalent to lfs3_file_seek(lfs3, file, 0, LFS3_SEEK_SET)
|
// Equivalent to lfs3_file_seek(lfs3, file, 0, LFS3_SEEK_SET)
|
||||||
// Returns a negative error code on failure.
|
// Returns a negative error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_rewind(lfs3_t *lfs3, lfs3_file_t *file);
|
int lfs3_file_rewind(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Return the size of the file
|
// Return the size of the file
|
||||||
//
|
//
|
||||||
// Similar to lfs3_file_seek(lfs3, file, 0, LFS3_SEEK_END)
|
// Similar to lfs3_file_seek(lfs3, file, 0, LFS3_SEEK_END)
|
||||||
// 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.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
lfs3_soff_t lfs3_file_size(lfs3_t *lfs3, lfs3_file_t *file);
|
lfs3_soff_t lfs3_file_size(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Check a file for metadata errors
|
// Check a file for metadata errors
|
||||||
//
|
//
|
||||||
// Returns LFS3_ERR_CORRUPT if a checksum mismatch is found, or a negative
|
// Returns LFS3_ERR_CORRUPT if a checksum mismatch is found, or a negative
|
||||||
// error code on failure.
|
// error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_ckmeta(lfs3_t *lfs3, lfs3_file_t *file);
|
int lfs3_file_ckmeta(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Check a file for metadata + data errors
|
// Check a file for metadata + data errors
|
||||||
//
|
//
|
||||||
// Returns LFS3_ERR_CORRUPT if a checksum mismatch is found, or a negative
|
// Returns LFS3_ERR_CORRUPT if a checksum mismatch is found, or a negative
|
||||||
// error code on failure.
|
// error code on failure.
|
||||||
|
#ifndef LFS3_KVONLY
|
||||||
int lfs3_file_ckdata(lfs3_t *lfs3, lfs3_file_t *file);
|
int lfs3_file_ckdata(lfs3_t *lfs3, lfs3_file_t *file);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/// Directory operations ///
|
/// Directory operations ///
|
||||||
|
|||||||
@@ -53,6 +53,9 @@
|
|||||||
#ifdef LFS3_YES_RDONLY
|
#ifdef LFS3_YES_RDONLY
|
||||||
#define LFS3_RDONLY
|
#define LFS3_RDONLY
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef LFS3_YES_KVONLY
|
||||||
|
#define LFS3_KVONLY
|
||||||
|
#endif
|
||||||
#ifdef LFS3_YES_REVDBG
|
#ifdef LFS3_YES_REVDBG
|
||||||
#define LFS3_REVDBG
|
#define LFS3_REVDBG
|
||||||
#endif
|
#endif
|
||||||
@@ -197,6 +200,12 @@
|
|||||||
#define LFS3_IFDEF_RDONLY(a, b) (b)
|
#define LFS3_IFDEF_RDONLY(a, b) (b)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LFS3_KVONLY
|
||||||
|
#define LFS3_IFDEF_KVONLY(a, b) (a)
|
||||||
|
#else
|
||||||
|
#define LFS3_IFDEF_KVONLY(a, b) (b)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LFS3_REVDBG
|
#ifdef LFS3_REVDBG
|
||||||
#define LFS3_IFDEF_REVDBG(a, b) (a)
|
#define LFS3_IFDEF_REVDBG(a, b) (a)
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -827,6 +827,7 @@ code = '''
|
|||||||
|
|
||||||
# test kv files can be read as normal files
|
# test kv files can be read as normal files
|
||||||
[cases.test_kv_interop_reads]
|
[cases.test_kv_interop_reads]
|
||||||
|
ifndef = 'LFS3_KVONLY'
|
||||||
code = '''
|
code = '''
|
||||||
lfs3_t lfs3;
|
lfs3_t lfs3;
|
||||||
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
@@ -929,6 +930,7 @@ code = '''
|
|||||||
|
|
||||||
# test normal files can be read a kv files
|
# test normal files can be read a kv files
|
||||||
[cases.test_kv_interop_writes]
|
[cases.test_kv_interop_writes]
|
||||||
|
ifndef = 'LFS3_KVONLY'
|
||||||
code = '''
|
code = '''
|
||||||
lfs3_t lfs3;
|
lfs3_t lfs3;
|
||||||
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
@@ -981,6 +983,7 @@ code = '''
|
|||||||
# test kv files broadcast sync updates
|
# test kv files broadcast sync updates
|
||||||
[cases.test_kv_interop_sync]
|
[cases.test_kv_interop_sync]
|
||||||
defines.STICKYNOTES = [false, true]
|
defines.STICKYNOTES = [false, true]
|
||||||
|
ifndef = 'LFS3_KVONLY'
|
||||||
code = '''
|
code = '''
|
||||||
lfs3_t lfs3;
|
lfs3_t lfs3;
|
||||||
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
@@ -1068,6 +1071,7 @@ code = '''
|
|||||||
# test kv files don't interfere with desync files
|
# test kv files don't interfere with desync files
|
||||||
[cases.test_kv_interop_desync]
|
[cases.test_kv_interop_desync]
|
||||||
defines.STICKYNOTES = [false, true]
|
defines.STICKYNOTES = [false, true]
|
||||||
|
ifndef = 'LFS3_KVONLY'
|
||||||
code = '''
|
code = '''
|
||||||
lfs3_t lfs3;
|
lfs3_t lfs3;
|
||||||
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
@@ -1159,6 +1163,7 @@ code = '''
|
|||||||
# test kv files work with resyncing files
|
# test kv files work with resyncing files
|
||||||
[cases.test_kv_interop_resync]
|
[cases.test_kv_interop_resync]
|
||||||
defines.STICKYNOTES = [false, true]
|
defines.STICKYNOTES = [false, true]
|
||||||
|
ifndef = 'LFS3_KVONLY'
|
||||||
code = '''
|
code = '''
|
||||||
lfs3_t lfs3;
|
lfs3_t lfs3;
|
||||||
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
@@ -1269,6 +1274,7 @@ defines.SIZE = 4
|
|||||||
defines.OPS = ['4*N', '40*N']
|
defines.OPS = ['4*N', '40*N']
|
||||||
defines.SEED = 'range(20)'
|
defines.SEED = 'range(20)'
|
||||||
fuzz = 'SEED'
|
fuzz = 'SEED'
|
||||||
|
ifndef = 'LFS3_KVONLY'
|
||||||
code = '''
|
code = '''
|
||||||
lfs3_t lfs3;
|
lfs3_t lfs3;
|
||||||
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
@@ -1427,6 +1433,7 @@ defines.SIZE = 40000
|
|||||||
defines.OPS = ['4*N', '40*N']
|
defines.OPS = ['4*N', '40*N']
|
||||||
defines.SEED = 'range(20)'
|
defines.SEED = 'range(20)'
|
||||||
fuzz = 'SEED'
|
fuzz = 'SEED'
|
||||||
|
ifndef = 'LFS3_KVONLY'
|
||||||
code = '''
|
code = '''
|
||||||
lfs3_t lfs3;
|
lfs3_t lfs3;
|
||||||
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user