mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 08:48:31 +01:00
Compare commits
5 Commits
v2.4.1
...
open-file-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7820e653e | ||
|
|
deeaa17317 | ||
|
|
026833214a | ||
|
|
b19a51c044 | ||
|
|
d97d66adf5 |
258
lfs.c
258
lfs.c
@@ -24,6 +24,14 @@ static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) {
|
|||||||
pcache->block = LFS_BLOCK_NULL;
|
pcache->block = LFS_BLOCK_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void lfs_cache_copy(lfs_t *lfs,
|
||||||
|
lfs_cache_t *dcache, const lfs_cache_t *scache) {
|
||||||
|
memcpy(dcache->buffer, scache->buffer, lfs->cfg->cache_size);
|
||||||
|
dcache->block = scache->block;
|
||||||
|
dcache->off = scache->off;
|
||||||
|
dcache->size = scache->size;
|
||||||
|
}
|
||||||
|
|
||||||
static int lfs_bd_read(lfs_t *lfs,
|
static int lfs_bd_read(lfs_t *lfs,
|
||||||
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
|
const lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_size_t hint,
|
||||||
lfs_block_t block, lfs_off_t off,
|
lfs_block_t block, lfs_off_t off,
|
||||||
@@ -630,8 +638,6 @@ static lfs_stag_t lfs_dir_getslice(lfs_t *lfs, const lfs_mdir_t *dir,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset((uint8_t*)gbuffer + diff, 0, gsize - diff);
|
|
||||||
|
|
||||||
return tag + gdiff;
|
return tag + gdiff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -815,8 +821,12 @@ static int lfs_dir_traverse(lfs_t *lfs,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) {
|
} else if (lfs_tag_type3(tag) == LFS_FROM_USERATTRS) {
|
||||||
|
const struct lfs_attr *a = buffer;
|
||||||
for (unsigned i = 0; i < lfs_tag_size(tag); i++) {
|
for (unsigned i = 0; i < lfs_tag_size(tag); i++) {
|
||||||
const struct lfs_attr *a = buffer;
|
if (a[i].size > lfs->attr_max) {
|
||||||
|
return LFS_ERR_NOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
int err = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a[i].type,
|
int err = cb(data, LFS_MKTAG(LFS_TYPE_USERATTR + a[i].type,
|
||||||
lfs_tag_id(tag) + diff, a[i].size), a[i].buffer);
|
lfs_tag_id(tag) + diff, a[i].size), a[i].buffer);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -1080,7 +1090,7 @@ static int lfs_dir_fetch(lfs_t *lfs,
|
|||||||
|
|
||||||
static int lfs_dir_getgstate(lfs_t *lfs, const lfs_mdir_t *dir,
|
static int lfs_dir_getgstate(lfs_t *lfs, const lfs_mdir_t *dir,
|
||||||
lfs_gstate_t *gstate) {
|
lfs_gstate_t *gstate) {
|
||||||
lfs_gstate_t temp;
|
lfs_gstate_t temp = {0};
|
||||||
lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x7ff, 0, 0),
|
lfs_stag_t res = lfs_dir_get(lfs, dir, LFS_MKTAG(0x7ff, 0, 0),
|
||||||
LFS_MKTAG(LFS_TYPE_MOVESTATE, 0, sizeof(temp)), &temp);
|
LFS_MKTAG(LFS_TYPE_MOVESTATE, 0, sizeof(temp)), &temp);
|
||||||
if (res < 0 && res != LFS_ERR_NOENT) {
|
if (res < 0 && res != LFS_ERR_NOENT) {
|
||||||
@@ -1106,10 +1116,11 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
lfs_stag_t tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x780, 0x3ff, 0),
|
lfs_stag_t tag = lfs_dir_get(lfs, dir, LFS_MKTAG(0x780, 0x3ff, 0),
|
||||||
LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max+1), info->name);
|
LFS_MKTAG(LFS_TYPE_NAME, id, lfs->name_max), info->name);
|
||||||
if (tag < 0) {
|
if (tag < 0) {
|
||||||
return (int)tag;
|
return (int)tag;
|
||||||
}
|
}
|
||||||
|
info->name[lfs_tag_size(tag)] = '\0';
|
||||||
|
|
||||||
info->type = lfs_tag_type3(tag);
|
info->type = lfs_tag_type3(tag);
|
||||||
|
|
||||||
@@ -1173,6 +1184,11 @@ static lfs_stag_t lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
|
|||||||
dir->tail[0] = lfs->root[0];
|
dir->tail[0] = lfs->root[0];
|
||||||
dir->tail[1] = lfs->root[1];
|
dir->tail[1] = lfs->root[1];
|
||||||
|
|
||||||
|
// NULL path == root
|
||||||
|
if (!name) {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
nextname:
|
nextname:
|
||||||
// skip slashes
|
// skip slashes
|
||||||
@@ -1821,7 +1837,7 @@ relocate:
|
|||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
|
static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
|
||||||
const struct lfs_mattr *attrs, int attrcount) {
|
const struct lfs_mattr *attrs, int attrcount) {
|
||||||
// check for any inline files that aren't RAM backed and
|
// check for any open inline files that aren't RAM backed and
|
||||||
// forcefully evict them, needed for filesystem consistency
|
// forcefully evict them, needed for filesystem consistency
|
||||||
for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) {
|
for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) {
|
||||||
if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 &&
|
if (dir != &f->m && lfs_pair_cmp(f->m.pair, dir->pair) == 0 &&
|
||||||
@@ -2013,6 +2029,7 @@ compact:
|
|||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
|
static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
|
||||||
// deorphan if we haven't yet, needed at most once after poweron
|
// deorphan if we haven't yet, needed at most once after poweron
|
||||||
|
LFS_ASSERT(path);
|
||||||
int err = lfs_fs_forceconsistency(lfs);
|
int err = lfs_fs_forceconsistency(lfs);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
@@ -2450,14 +2467,14 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file,
|
|||||||
const struct lfs_file_config *cfg) {
|
const struct lfs_file_config *cfg) {
|
||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
// deorphan if we haven't yet, needed at most once after poweron
|
// deorphan if we haven't yet, needed at most once after poweron
|
||||||
if ((flags & LFS_O_WRONLY) == LFS_O_WRONLY) {
|
if (flags & LFS_O_WRONLY) {
|
||||||
int err = lfs_fs_forceconsistency(lfs);
|
int err = lfs_fs_forceconsistency(lfs);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
LFS_ASSERT((flags & LFS_O_RDONLY) == LFS_O_RDONLY);
|
LFS_ASSERT(flags & LFS_O_RDONLY);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// setup simple file details
|
// setup simple file details
|
||||||
@@ -2468,7 +2485,7 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file,
|
|||||||
file->off = 0;
|
file->off = 0;
|
||||||
file->cache.buffer = NULL;
|
file->cache.buffer = NULL;
|
||||||
|
|
||||||
// allocate entry for file if it doesn't exist
|
// find path
|
||||||
lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id);
|
lfs_stag_t tag = lfs_dir_find(lfs, &file->m, &path, &file->id);
|
||||||
if (tag < 0 && !(tag == LFS_ERR_NOENT && file->id != 0x3ff)) {
|
if (tag < 0 && !(tag == LFS_ERR_NOENT && file->id != 0x3ff)) {
|
||||||
err = tag;
|
err = tag;
|
||||||
@@ -2476,19 +2493,22 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get id, add to list of mdirs to catch update changes
|
// get id, add to list of mdirs to catch update changes
|
||||||
file->type = LFS_TYPE_REG;
|
if (!(flags & LFS_O_SNAPSHOT)) {
|
||||||
lfs_mlist_append(lfs, (struct lfs_mlist *)file);
|
file->type = LFS_TYPE_REG;
|
||||||
|
lfs_mlist_append(lfs, (struct lfs_mlist *)file);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
if (tag == LFS_ERR_NOENT) {
|
if ((flags & LFS_O_CREAT) && (flags & LFS_O_SNAPSHOT) &&
|
||||||
err = LFS_ERR_NOENT;
|
(tag == LFS_ERR_NOENT || lfs_tag_type3(tag) != LFS_TYPE_REG)) {
|
||||||
|
// special case for "temporary" files
|
||||||
|
tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0);
|
||||||
|
} else if ((flags & LFS_O_EXCL) && tag != LFS_ERR_NOENT) {
|
||||||
|
err = LFS_ERR_EXIST;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
#else
|
} else if ((flags & LFS_O_CREAT) && tag == LFS_ERR_NOENT) {
|
||||||
if (tag == LFS_ERR_NOENT) {
|
// allocate entry for file if it doesn't exist
|
||||||
if (!(flags & LFS_O_CREAT)) {
|
LFS_ASSERT(path);
|
||||||
err = LFS_ERR_NOENT;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check that name fits
|
// check that name fits
|
||||||
lfs_size_t nlen = strlen(path);
|
lfs_size_t nlen = strlen(path);
|
||||||
@@ -2501,63 +2521,57 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file,
|
|||||||
err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS(
|
err = lfs_dir_commit(lfs, &file->m, LFS_MKATTRS(
|
||||||
{LFS_MKTAG(LFS_TYPE_CREATE, file->id, 0), NULL},
|
{LFS_MKTAG(LFS_TYPE_CREATE, file->id, 0), NULL},
|
||||||
{LFS_MKTAG(LFS_TYPE_REG, file->id, nlen), path},
|
{LFS_MKTAG(LFS_TYPE_REG, file->id, nlen), path},
|
||||||
{LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), NULL}));
|
{LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0), NULL},
|
||||||
|
{LFS_MKTAG(LFS_FROM_USERATTRS, file->id,
|
||||||
|
file->cfg->attr_count), file->cfg->attrs}));
|
||||||
if (err) {
|
if (err) {
|
||||||
err = LFS_ERR_NAMETOOLONG;
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0);
|
tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0);
|
||||||
} else if (flags & LFS_O_EXCL) {
|
} else /**/
|
||||||
err = LFS_ERR_EXIST;
|
#endif /**/
|
||||||
|
/*********/
|
||||||
|
/**/ if (tag == LFS_ERR_NOENT) {
|
||||||
|
err = LFS_ERR_NOENT;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
#endif
|
|
||||||
} else if (lfs_tag_type3(tag) != LFS_TYPE_REG) {
|
} else if (lfs_tag_type3(tag) != LFS_TYPE_REG) {
|
||||||
err = LFS_ERR_ISDIR;
|
err = LFS_ERR_ISDIR;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
#ifndef LFS_READONLY
|
|
||||||
} else if (flags & LFS_O_TRUNC) {
|
|
||||||
// truncate if requested
|
|
||||||
tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, file->id, 0);
|
|
||||||
file->flags |= LFS_F_DIRTY;
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
// try to load what's on disk, if it's inlined we'll fix it later
|
|
||||||
tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0),
|
|
||||||
LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz);
|
|
||||||
if (tag < 0) {
|
|
||||||
err = tag;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
lfs_ctz_fromle32(&file->ctz);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch attrs
|
|
||||||
for (unsigned i = 0; i < file->cfg->attr_count; i++) {
|
|
||||||
// if opened for read / read-write operations
|
|
||||||
if ((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY) {
|
|
||||||
lfs_stag_t res = lfs_dir_get(lfs, &file->m,
|
|
||||||
LFS_MKTAG(0x7ff, 0x3ff, 0),
|
|
||||||
LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type,
|
|
||||||
file->id, file->cfg->attrs[i].size),
|
|
||||||
file->cfg->attrs[i].buffer);
|
|
||||||
if (res < 0 && res != LFS_ERR_NOENT) {
|
|
||||||
err = res;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
// if opened for write / read-write operations
|
if (flags & LFS_O_TRUNC) {
|
||||||
if ((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY) {
|
// truncate if requested
|
||||||
if (file->cfg->attrs[i].size > lfs->attr_max) {
|
// always mark dirty in case we have custom attributes
|
||||||
err = LFS_ERR_NOSPC;
|
tag = LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, 0);
|
||||||
|
file->flags |= LFS_F_DIRTY;
|
||||||
|
} else /**/
|
||||||
|
#endif /*********/
|
||||||
|
/**/ {
|
||||||
|
// try to load what's on disk, if it's inlined we'll fix it later
|
||||||
|
tag = lfs_dir_get(lfs, &file->m, LFS_MKTAG(0x700, 0x3ff, 0),
|
||||||
|
LFS_MKTAG(LFS_TYPE_STRUCT, file->id, 8), &file->ctz);
|
||||||
|
if (tag < 0) {
|
||||||
|
err = tag;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
lfs_ctz_fromle32(&file->ctz);
|
||||||
file->flags |= LFS_F_DIRTY;
|
}
|
||||||
|
|
||||||
|
// fetch attrs if opened for read / read-write operations
|
||||||
|
if (flags & LFS_O_RDONLY) {
|
||||||
|
for (lfs_size_t i = 0; i < file->cfg->attr_count; i++) {
|
||||||
|
lfs_stag_t res = lfs_dir_get(lfs, &file->m,
|
||||||
|
LFS_MKTAG(0x7ff, 0x3ff, 0),
|
||||||
|
LFS_MKTAG(LFS_TYPE_USERATTR + file->cfg->attrs[i].type,
|
||||||
|
file->id, file->cfg->attrs[i].size),
|
||||||
|
file->cfg->attrs[i].buffer);
|
||||||
|
if (res < 0 && res != LFS_ERR_NOENT) {
|
||||||
|
err = res;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate buffer if needed
|
// allocate buffer if needed
|
||||||
@@ -2602,7 +2616,7 @@ static int lfs_file_rawopencfg(lfs_t *lfs, lfs_file_t *file,
|
|||||||
cleanup:
|
cleanup:
|
||||||
// clean up lingering resources
|
// clean up lingering resources
|
||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
file->flags |= LFS_F_ERRED;
|
file->flags |= LFS_F_ZOMBIE;
|
||||||
#endif
|
#endif
|
||||||
lfs_file_rawclose(lfs, file);
|
lfs_file_rawclose(lfs, file);
|
||||||
return err;
|
return err;
|
||||||
@@ -2616,10 +2630,9 @@ static int lfs_file_rawopen(lfs_t *lfs, lfs_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file) {
|
static int lfs_file_rawclose(lfs_t *lfs, lfs_file_t *file) {
|
||||||
#ifndef LFS_READONLY
|
|
||||||
int err = lfs_file_rawsync(lfs, file);
|
|
||||||
#else
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
#ifndef LFS_READONLY
|
||||||
|
err = lfs_file_rawsync(lfs, file);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// remove from list of mdirs
|
// remove from list of mdirs
|
||||||
@@ -2801,17 +2814,21 @@ relocate:
|
|||||||
|
|
||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) {
|
static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) {
|
||||||
if (file->flags & LFS_F_ERRED) {
|
if (file->flags & LFS_F_ZOMBIE) {
|
||||||
// it's not safe to do anything if our file errored
|
// it's not safe to do anything if our file errored
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int err = lfs_file_flush(lfs, file);
|
int err = lfs_file_flush(lfs, file);
|
||||||
if (err) {
|
if (err) {
|
||||||
file->flags |= LFS_F_ERRED;
|
file->flags |= LFS_F_ZOMBIE;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (file->flags & LFS_O_SNAPSHOT) {
|
||||||
|
// we do flush snapshot files, but we don't commit, so stop here
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if ((file->flags & LFS_F_DIRTY) &&
|
if ((file->flags & LFS_F_DIRTY) &&
|
||||||
!lfs_pair_isnull(file->m.pair)) {
|
!lfs_pair_isnull(file->m.pair)) {
|
||||||
@@ -2841,10 +2858,41 @@ static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) {
|
|||||||
{LFS_MKTAG(LFS_FROM_USERATTRS, file->id,
|
{LFS_MKTAG(LFS_FROM_USERATTRS, file->id,
|
||||||
file->cfg->attr_count), file->cfg->attrs}));
|
file->cfg->attr_count), file->cfg->attrs}));
|
||||||
if (err) {
|
if (err) {
|
||||||
file->flags |= LFS_F_ERRED;
|
file->flags |= LFS_F_ZOMBIE;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update readable handles referencing this file device-side
|
||||||
|
for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) {
|
||||||
|
if (f != file &&
|
||||||
|
f->type == LFS_TYPE_REG &&
|
||||||
|
lfs_pair_cmp(f->m.pair, file->m.pair) == 0 &&
|
||||||
|
f->id == file->id &&
|
||||||
|
// only readable handles because wronly files
|
||||||
|
// may reference attributes in ROM
|
||||||
|
(f->flags & LFS_O_RDONLY)) {
|
||||||
|
// sync disk structure
|
||||||
|
f->ctz = file->ctz;
|
||||||
|
// copying the cache is required for inline files
|
||||||
|
lfs_cache_copy(lfs, &f->cache, &file->cache);
|
||||||
|
|
||||||
|
// sync attrs
|
||||||
|
for (lfs_size_t i = 0; i < f->cfg->attr_count; i++) {
|
||||||
|
for (lfs_size_t j = 0; j < file->cfg->attr_count; j++) {
|
||||||
|
if (f->cfg->attrs[i].type == file->cfg->attrs[i].type) {
|
||||||
|
memcpy(f->cfg->attrs[i].buffer,
|
||||||
|
file->cfg->attrs[i].buffer,
|
||||||
|
lfs_min(
|
||||||
|
f->cfg->attrs[i].size,
|
||||||
|
file->cfg->attrs[i].size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f->flags &= ~(LFS_F_DIRTY | LFS_F_WRITING | LFS_F_READING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
file->flags &= ~LFS_F_DIRTY;
|
file->flags &= ~LFS_F_DIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2854,7 +2902,7 @@ static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file) {
|
|||||||
|
|
||||||
static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file,
|
static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file,
|
||||||
void *buffer, lfs_size_t size) {
|
void *buffer, lfs_size_t size) {
|
||||||
LFS_ASSERT((file->flags & LFS_O_RDONLY) == LFS_O_RDONLY);
|
LFS_ASSERT(file->flags & LFS_O_RDONLY);
|
||||||
|
|
||||||
uint8_t *data = buffer;
|
uint8_t *data = buffer;
|
||||||
lfs_size_t nsize = size;
|
lfs_size_t nsize = size;
|
||||||
@@ -2928,7 +2976,7 @@ static lfs_ssize_t lfs_file_rawread(lfs_t *lfs, lfs_file_t *file,
|
|||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
||||||
const void *buffer, lfs_size_t size) {
|
const void *buffer, lfs_size_t size) {
|
||||||
LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY);
|
LFS_ASSERT(file->flags & LFS_O_WRONLY);
|
||||||
|
|
||||||
const uint8_t *data = buffer;
|
const uint8_t *data = buffer;
|
||||||
lfs_size_t nsize = size;
|
lfs_size_t nsize = size;
|
||||||
@@ -2970,7 +3018,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
|||||||
// inline file doesn't fit anymore
|
// inline file doesn't fit anymore
|
||||||
int err = lfs_file_outline(lfs, file);
|
int err = lfs_file_outline(lfs, file);
|
||||||
if (err) {
|
if (err) {
|
||||||
file->flags |= LFS_F_ERRED;
|
file->flags |= LFS_F_ZOMBIE;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2986,7 +3034,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
|||||||
file->ctz.head, file->ctz.size,
|
file->ctz.head, file->ctz.size,
|
||||||
file->pos-1, &file->block, &file->off);
|
file->pos-1, &file->block, &file->off);
|
||||||
if (err) {
|
if (err) {
|
||||||
file->flags |= LFS_F_ERRED;
|
file->flags |= LFS_F_ZOMBIE;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3000,7 +3048,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
|||||||
file->block, file->pos,
|
file->block, file->pos,
|
||||||
&file->block, &file->off);
|
&file->block, &file->off);
|
||||||
if (err) {
|
if (err) {
|
||||||
file->flags |= LFS_F_ERRED;
|
file->flags |= LFS_F_ZOMBIE;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -3020,7 +3068,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
|||||||
if (err == LFS_ERR_CORRUPT) {
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
goto relocate;
|
goto relocate;
|
||||||
}
|
}
|
||||||
file->flags |= LFS_F_ERRED;
|
file->flags |= LFS_F_ZOMBIE;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3028,7 +3076,7 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
|
|||||||
relocate:
|
relocate:
|
||||||
err = lfs_file_relocate(lfs, file);
|
err = lfs_file_relocate(lfs, file);
|
||||||
if (err) {
|
if (err) {
|
||||||
file->flags |= LFS_F_ERRED;
|
file->flags |= LFS_F_ZOMBIE;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3041,7 +3089,7 @@ relocate:
|
|||||||
lfs_alloc_ack(lfs);
|
lfs_alloc_ack(lfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
file->flags &= ~LFS_F_ERRED;
|
file->flags &= ~LFS_F_ZOMBIE;
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -3078,7 +3126,7 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
|
|||||||
|
|
||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
||||||
LFS_ASSERT((file->flags & LFS_O_WRONLY) == LFS_O_WRONLY);
|
LFS_ASSERT(file->flags & LFS_O_WRONLY);
|
||||||
|
|
||||||
if (size > LFS_FILE_MAX) {
|
if (size > LFS_FILE_MAX) {
|
||||||
return LFS_ERR_INVAL;
|
return LFS_ERR_INVAL;
|
||||||
@@ -3424,8 +3472,34 @@ static int lfs_commitattr(lfs_t *lfs, const char *path,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lfs_dir_commit(lfs, &cwd, LFS_MKATTRS(
|
int err = lfs_dir_commit(lfs, &cwd, LFS_MKATTRS(
|
||||||
{LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer}));
|
{LFS_MKTAG(LFS_TYPE_USERATTR + type, id, size), buffer}));
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lfs_tag_type3(tag) == LFS_TYPE_REG && size != 0x3ff) {
|
||||||
|
// sync attrs with any files open for reading, this follows
|
||||||
|
// the behavior of lfs_file_sync with attributes
|
||||||
|
for (lfs_file_t *f = (lfs_file_t*)lfs->mlist; f; f = f->next) {
|
||||||
|
if (f->type == LFS_TYPE_REG &&
|
||||||
|
lfs_pair_cmp(f->m.pair, cwd.pair) == 0 &&
|
||||||
|
f->id == id &&
|
||||||
|
// only readable handles because wronly files
|
||||||
|
// may reference attributes in ROM
|
||||||
|
(f->flags & LFS_O_RDONLY)) {
|
||||||
|
// sync attrs
|
||||||
|
for (lfs_size_t i = 0; i < f->cfg->attr_count; i++) {
|
||||||
|
if (f->cfg->attrs[i].type == type) {
|
||||||
|
memcpy(f->cfg->attrs[i].buffer, buffer,
|
||||||
|
lfs_min(f->cfg->attrs[i].size, size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -5084,7 +5158,8 @@ int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file);
|
LFS_TRACE("lfs_file_close(%p, %p)", (void*)lfs, (void*)file);
|
||||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) ||
|
||||||
|
lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||||
|
|
||||||
err = lfs_file_rawclose(lfs, file);
|
err = lfs_file_rawclose(lfs, file);
|
||||||
|
|
||||||
@@ -5100,7 +5175,8 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file);
|
LFS_TRACE("lfs_file_sync(%p, %p)", (void*)lfs, (void*)file);
|
||||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) ||
|
||||||
|
lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||||
|
|
||||||
err = lfs_file_rawsync(lfs, file);
|
err = lfs_file_rawsync(lfs, file);
|
||||||
|
|
||||||
@@ -5118,7 +5194,8 @@ lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
|
|||||||
}
|
}
|
||||||
LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")",
|
LFS_TRACE("lfs_file_read(%p, %p, %p, %"PRIu32")",
|
||||||
(void*)lfs, (void*)file, buffer, size);
|
(void*)lfs, (void*)file, buffer, size);
|
||||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) ||
|
||||||
|
lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||||
|
|
||||||
lfs_ssize_t res = lfs_file_rawread(lfs, file, buffer, size);
|
lfs_ssize_t res = lfs_file_rawread(lfs, file, buffer, size);
|
||||||
|
|
||||||
@@ -5136,7 +5213,8 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
|
|||||||
}
|
}
|
||||||
LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")",
|
LFS_TRACE("lfs_file_write(%p, %p, %p, %"PRIu32")",
|
||||||
(void*)lfs, (void*)file, buffer, size);
|
(void*)lfs, (void*)file, buffer, size);
|
||||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) ||
|
||||||
|
lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||||
|
|
||||||
lfs_ssize_t res = lfs_file_rawwrite(lfs, file, buffer, size);
|
lfs_ssize_t res = lfs_file_rawwrite(lfs, file, buffer, size);
|
||||||
|
|
||||||
@@ -5154,7 +5232,8 @@ lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
|
|||||||
}
|
}
|
||||||
LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)",
|
LFS_TRACE("lfs_file_seek(%p, %p, %"PRId32", %d)",
|
||||||
(void*)lfs, (void*)file, off, whence);
|
(void*)lfs, (void*)file, off, whence);
|
||||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) ||
|
||||||
|
lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||||
|
|
||||||
lfs_soff_t res = lfs_file_rawseek(lfs, file, off, whence);
|
lfs_soff_t res = lfs_file_rawseek(lfs, file, off, whence);
|
||||||
|
|
||||||
@@ -5171,7 +5250,8 @@ int lfs_file_truncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
|
|||||||
}
|
}
|
||||||
LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")",
|
LFS_TRACE("lfs_file_truncate(%p, %p, %"PRIu32")",
|
||||||
(void*)lfs, (void*)file, size);
|
(void*)lfs, (void*)file, size);
|
||||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) ||
|
||||||
|
lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||||
|
|
||||||
err = lfs_file_rawtruncate(lfs, file, size);
|
err = lfs_file_rawtruncate(lfs, file, size);
|
||||||
|
|
||||||
@@ -5187,7 +5267,8 @@ lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file);
|
LFS_TRACE("lfs_file_tell(%p, %p)", (void*)lfs, (void*)file);
|
||||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) ||
|
||||||
|
lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||||
|
|
||||||
lfs_soff_t res = lfs_file_rawtell(lfs, file);
|
lfs_soff_t res = lfs_file_rawtell(lfs, file);
|
||||||
|
|
||||||
@@ -5216,7 +5297,8 @@ lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file);
|
LFS_TRACE("lfs_file_size(%p, %p)", (void*)lfs, (void*)file);
|
||||||
LFS_ASSERT(lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
LFS_ASSERT((file->flags & LFS_O_SNAPSHOT) ||
|
||||||
|
lfs_mlist_isopen(lfs->mlist, (struct lfs_mlist*)file));
|
||||||
|
|
||||||
lfs_soff_t res = lfs_file_rawsize(lfs, file);
|
lfs_soff_t res = lfs_file_rawsize(lfs, file);
|
||||||
|
|
||||||
|
|||||||
50
lfs.h
50
lfs.h
@@ -123,26 +123,30 @@ enum lfs_type {
|
|||||||
// File open flags
|
// File open flags
|
||||||
enum lfs_open_flags {
|
enum lfs_open_flags {
|
||||||
// open flags
|
// open flags
|
||||||
LFS_O_RDONLY = 1, // Open a file as read only
|
LFS_O_RDONLY = 1, // Open a file as read only
|
||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
LFS_O_WRONLY = 2, // Open a file as write only
|
LFS_O_WRONLY = 2, // Open a file as write only
|
||||||
LFS_O_RDWR = 3, // Open a file as read and write
|
LFS_O_RDWR = 3, // Open a file as read and write
|
||||||
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
|
#endif
|
||||||
LFS_O_EXCL = 0x0200, // Fail if a file already exists
|
|
||||||
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
#ifndef LFS_READONLY
|
||||||
LFS_O_APPEND = 0x0800, // Move to end of file on every write
|
LFS_O_CREAT = 0x0100, // Create a file if it does not exist
|
||||||
|
LFS_O_EXCL = 0x0200, // Fail if a file already exists
|
||||||
|
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
||||||
|
LFS_O_APPEND = 0x0800, // Move to end of file on every write
|
||||||
|
LFS_O_SNAPSHOT = 0x1000, // Open a temporary snapshot, ignore changes
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// internally used flags
|
// internally used flags
|
||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
LFS_F_DIRTY = 0x010000, // File does not match storage
|
LFS_F_DIRTY = 0x010000, // File does not match storage
|
||||||
LFS_F_WRITING = 0x020000, // File has been written since last flush
|
|
||||||
#endif
|
#endif
|
||||||
LFS_F_READING = 0x040000, // File has been read since last flush
|
LFS_F_READING = 0x020000, // File has been read since last flush
|
||||||
#ifndef LFS_READONLY
|
#ifndef LFS_READONLY
|
||||||
LFS_F_ERRED = 0x080000, // An error occurred during write
|
LFS_F_WRITING = 0x040000, // File has been written since last flush
|
||||||
|
LFS_F_ZOMBIE = 0x080000, // An error occurred during write
|
||||||
#endif
|
#endif
|
||||||
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
|
LFS_F_INLINE = 0x100000, // Currently inlined in directory entry
|
||||||
};
|
};
|
||||||
|
|
||||||
// File seek flags
|
// File seek flags
|
||||||
@@ -294,16 +298,15 @@ struct lfs_file_config {
|
|||||||
void *buffer;
|
void *buffer;
|
||||||
|
|
||||||
// Optional list of custom attributes related to the file. If the file
|
// Optional list of custom attributes related to the file. If the file
|
||||||
// is opened with read access, these attributes will be read from disk
|
// is opened for reading, these attributes will be read from disk during
|
||||||
// during the open call. If the file is opened with write access, the
|
// open. If the file is open for writing, these attribute will be atomically
|
||||||
// attributes will be written to disk every file sync or close. This
|
// written to disk when the file is written to disk. Note that these
|
||||||
// write occurs atomically with update to the file's contents.
|
// attributes are not written unless the file is modified.
|
||||||
//
|
//
|
||||||
// Custom attributes are uniquely identified by an 8-bit type and limited
|
// Custom attributes are uniquely identified by an 8-bit type and limited
|
||||||
// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller
|
// to LFS_ATTR_MAX bytes. If the stored attribute is larger than the
|
||||||
// than the buffer, it will be padded with zeros. If the stored attribute
|
// provided buffer, it will be silently truncated. If no attribute is
|
||||||
// is larger, then it will be silently truncated. If the attribute is not
|
// found, and the file is open for writing, it will be created implicitly.
|
||||||
// found, it will be created implicitly.
|
|
||||||
struct lfs_attr *attrs;
|
struct lfs_attr *attrs;
|
||||||
|
|
||||||
// Number of custom attributes in the list
|
// Number of custom attributes in the list
|
||||||
@@ -471,10 +474,9 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info);
|
|||||||
// Get a custom attribute
|
// Get a custom attribute
|
||||||
//
|
//
|
||||||
// Custom attributes are uniquely identified by an 8-bit type and limited
|
// Custom attributes are uniquely identified by an 8-bit type and limited
|
||||||
// to LFS_ATTR_MAX bytes. When read, if the stored attribute is smaller than
|
// to LFS_ATTR_MAX bytes. If the stored attribute is larger than the
|
||||||
// the buffer, it will be padded with zeros. If the stored attribute is larger,
|
// provided buffer, it will be silently truncated. If no attribute is found,
|
||||||
// then it will be silently truncated. If no attribute is found, the error
|
// the error LFS_ERR_NOATTR is returned and the buffer is filled with zeros.
|
||||||
// LFS_ERR_NOATTR is returned and the buffer is filled with zeros.
|
|
||||||
//
|
//
|
||||||
// Returns the size of the attribute, or a negative error code on failure.
|
// Returns the size of the attribute, or a negative error code on failure.
|
||||||
// Note, the returned size is the size of the attribute on disk, irrespective
|
// Note, the returned size is the size of the attribute on disk, irrespective
|
||||||
|
|||||||
@@ -16,41 +16,39 @@ code = '''
|
|||||||
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6;
|
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6;
|
||||||
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
|
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "bbbbbb", 6) => 0;
|
assert(memcmp(buffer+4, "bbbbbb", 6) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
|
|
||||||
lfs_setattr(&lfs, "hello", 'B', "", 0) => 0;
|
lfs_setattr(&lfs, "hello", 'B', "", 0) => 0;
|
||||||
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 0;
|
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 0;
|
||||||
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
|
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
|
||||||
|
|
||||||
lfs_removeattr(&lfs, "hello", 'B') => 0;
|
lfs_removeattr(&lfs, "hello", 'B') => 0;
|
||||||
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => LFS_ERR_NOATTR;
|
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => LFS_ERR_NOATTR;
|
||||||
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
|
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
|
||||||
|
|
||||||
lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0;
|
lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0;
|
||||||
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6;
|
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6;
|
||||||
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
|
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "dddddd", 6) => 0;
|
assert(memcmp(buffer+4, "dddddd", 6) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
|
|
||||||
lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0;
|
lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0;
|
||||||
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 3;
|
lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 3;
|
||||||
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
|
lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "eee\0\0\0", 6) => 0;
|
assert(memcmp(buffer+4, "eee", 3) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
|
|
||||||
lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC;
|
lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC;
|
||||||
lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0;
|
lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0;
|
||||||
@@ -65,13 +63,13 @@ code = '''
|
|||||||
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9;
|
lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9;
|
||||||
lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5;
|
lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "fffffffff", 9) => 0;
|
assert(memcmp(buffer+4, "fffffffff", 9) == 0);
|
||||||
memcmp(buffer+13, "ccccc", 5) => 0;
|
assert(memcmp(buffer+13, "ccccc", 5) == 0);
|
||||||
|
|
||||||
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0;
|
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0;
|
||||||
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello");
|
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello");
|
||||||
memcmp(buffer, "hello", strlen("hello")) => 0;
|
assert(memcmp(buffer, "hello", strlen("hello")) == 0);
|
||||||
lfs_file_close(&lfs, &file);
|
lfs_file_close(&lfs, &file);
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
@@ -94,41 +92,39 @@ code = '''
|
|||||||
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6;
|
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6;
|
||||||
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
|
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "bbbbbb", 6) => 0;
|
assert(memcmp(buffer+4, "bbbbbb", 6) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
|
|
||||||
lfs_setattr(&lfs, "/", 'B', "", 0) => 0;
|
lfs_setattr(&lfs, "/", 'B', "", 0) => 0;
|
||||||
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 0;
|
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 0;
|
||||||
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
|
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
|
||||||
|
|
||||||
lfs_removeattr(&lfs, "/", 'B') => 0;
|
lfs_removeattr(&lfs, "/", 'B') => 0;
|
||||||
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => LFS_ERR_NOATTR;
|
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => LFS_ERR_NOATTR;
|
||||||
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
|
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
|
||||||
|
|
||||||
lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0;
|
lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0;
|
||||||
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6;
|
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6;
|
||||||
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
|
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "dddddd", 6) => 0;
|
assert(memcmp(buffer+4, "dddddd", 6) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
|
|
||||||
lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0;
|
lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0;
|
||||||
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 3;
|
lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 3;
|
||||||
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
|
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "eee\0\0\0", 6) => 0;
|
assert(memcmp(buffer+4, "eee", 3) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
|
|
||||||
lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC;
|
lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC;
|
||||||
lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0;
|
lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0;
|
||||||
@@ -142,13 +138,13 @@ code = '''
|
|||||||
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
|
||||||
lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9;
|
lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9;
|
||||||
lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5;
|
lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "fffffffff", 9) => 0;
|
assert(memcmp(buffer+4, "fffffffff", 9) == 0);
|
||||||
memcmp(buffer+13, "ccccc", 5) => 0;
|
assert(memcmp(buffer+13, "ccccc", 5) == 0);
|
||||||
|
|
||||||
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0;
|
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0;
|
||||||
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello");
|
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello");
|
||||||
memcmp(buffer, "hello", strlen("hello")) => 0;
|
assert(memcmp(buffer, "hello", strlen("hello")) == 0);
|
||||||
lfs_file_close(&lfs, &file);
|
lfs_file_close(&lfs, &file);
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
@@ -176,52 +172,55 @@ code = '''
|
|||||||
memcpy(buffer, "aaaa", 4);
|
memcpy(buffer, "aaaa", 4);
|
||||||
memcpy(buffer+4, "bbbbbb", 6);
|
memcpy(buffer+4, "bbbbbb", 6);
|
||||||
memcpy(buffer+10, "ccccc", 5);
|
memcpy(buffer+10, "ccccc", 5);
|
||||||
|
lfs_file_write(&lfs, &file, "hi", 2) => 2;
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
memset(buffer, 0, 15);
|
memset(buffer, 0, 15);
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
|
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "bbbbbb", 6) => 0;
|
assert(memcmp(buffer+4, "bbbbbb", 6) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
|
|
||||||
attrs1[1].size = 0;
|
attrs1[1].size = 0;
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
|
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
|
||||||
|
lfs_file_write(&lfs, &file, "hi", 2) => 2;
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
memset(buffer, 0, 15);
|
memset(buffer, 0, 15);
|
||||||
attrs1[1].size = 6;
|
attrs1[1].size = 6;
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
|
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
|
||||||
|
|
||||||
attrs1[1].size = 6;
|
attrs1[1].size = 6;
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
|
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
|
||||||
memcpy(buffer+4, "dddddd", 6);
|
memcpy(buffer+4, "dddddd", 6);
|
||||||
|
lfs_file_write(&lfs, &file, "hi", 2) => 2;
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
memset(buffer, 0, 15);
|
memset(buffer, 0, 15);
|
||||||
attrs1[1].size = 6;
|
attrs1[1].size = 6;
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
|
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "dddddd", 6) => 0;
|
assert(memcmp(buffer+4, "dddddd", 6) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
|
|
||||||
attrs1[1].size = 3;
|
attrs1[1].size = 3;
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
|
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0;
|
||||||
memcpy(buffer+4, "eee", 3);
|
memcpy(buffer+4, "eee", 3);
|
||||||
|
lfs_file_write(&lfs, &file, "hi", 2) => 2;
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
memset(buffer, 0, 15);
|
memset(buffer, 0, 15);
|
||||||
attrs1[1].size = 6;
|
attrs1[1].size = 6;
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
|
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "eee\0\0\0", 6) => 0;
|
assert(memcmp(buffer+4, "eee", 3) == 0);
|
||||||
memcmp(buffer+10, "ccccc", 5) => 0;
|
assert(memcmp(buffer+10, "ccccc", 5) == 0);
|
||||||
|
|
||||||
attrs1[0].size = LFS_ATTR_MAX+1;
|
attrs1[0].size = LFS_ATTR_MAX+1;
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1)
|
lfs_file_opencfg(&lfs, &file, "hello/hello2",
|
||||||
=> LFS_ERR_NOSPC;
|
LFS_O_WRONLY | LFS_O_CREAT, &cfg1) => LFS_ERR_NOSPC;
|
||||||
|
|
||||||
struct lfs_attr attrs2[] = {
|
struct lfs_attr attrs2[] = {
|
||||||
{'A', buffer, 4},
|
{'A', buffer, 4},
|
||||||
@@ -231,6 +230,7 @@ code = '''
|
|||||||
struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3};
|
struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3};
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0;
|
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0;
|
||||||
memcpy(buffer+4, "fffffffff", 9);
|
memcpy(buffer+4, "fffffffff", 9);
|
||||||
|
lfs_file_write(&lfs, &file, "hi", 2) => 2;
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
attrs1[0].size = 4;
|
attrs1[0].size = 4;
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
|
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0;
|
||||||
@@ -249,13 +249,13 @@ code = '''
|
|||||||
|
|
||||||
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0;
|
lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0;
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
memcmp(buffer, "aaaa", 4) => 0;
|
assert(memcmp(buffer, "aaaa", 4) == 0);
|
||||||
memcmp(buffer+4, "fffffffff", 9) => 0;
|
assert(memcmp(buffer+4, "fffffffff", 9) == 0);
|
||||||
memcmp(buffer+13, "ccccc", 5) => 0;
|
assert(memcmp(buffer+13, "ccccc", 5) == 0);
|
||||||
|
|
||||||
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0;
|
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0;
|
||||||
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello");
|
lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello");
|
||||||
memcmp(buffer, "hello", strlen("hello")) => 0;
|
assert(memcmp(buffer, "hillo", strlen("hello")) == 0);
|
||||||
lfs_file_close(&lfs, &file);
|
lfs_file_close(&lfs, &file);
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
@@ -287,17 +287,16 @@ code = '''
|
|||||||
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 9;
|
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 9;
|
||||||
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 5;
|
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 5;
|
||||||
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR;
|
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR;
|
||||||
memcmp(buffer, "fffffffff", 9) => 0;
|
assert(memcmp(buffer, "fffffffff", 9) == 0);
|
||||||
memcmp(buffer+9, "ccccc\0\0\0\0", 9) => 0;
|
assert(memcmp(buffer+9, "ccccc", 5) == 0);
|
||||||
memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0;
|
|
||||||
|
|
||||||
|
lfs_file_write(&lfs, &file, "hi", 2) => 2;
|
||||||
lfs_file_sync(&lfs, &file) => 0;
|
lfs_file_sync(&lfs, &file) => 0;
|
||||||
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 4;
|
lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 4;
|
||||||
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 0;
|
lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 0;
|
||||||
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4;
|
lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4;
|
||||||
memcmp(buffer, "gggg\0\0\0\0\0", 9) => 0;
|
assert(memcmp(buffer, "gggg", 4) == 0);
|
||||||
memcmp(buffer+9, "\0\0\0\0\0\0\0\0\0", 9) => 0;
|
assert(memcmp(buffer+18, "hhhh", 4) == 0);
|
||||||
memcmp(buffer+18, "hhhh\0\0\0\0\0", 9) => 0;
|
|
||||||
|
|
||||||
lfs_file_close(&lfs, &file) => 0;
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|||||||
@@ -242,3 +242,695 @@ code = '''
|
|||||||
|
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
[[case]] # open same file reading from separate file handles
|
||||||
|
define.READERS = 3
|
||||||
|
define.SIZE = [10, 100, 1000, 10000]
|
||||||
|
define.RDMODE = ['LFS_O_RDONLY', 'LFS_O_RDWR']
|
||||||
|
code = '''
|
||||||
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &file, "shared", LFS_O_CREAT | LFS_O_WRONLY) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// open all files
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_t readers[READERS];
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
lfs_file_open(&lfs, &readers[i], "shared", RDMODE) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform operations while all readers are open
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
lfs_file_close(&lfs, &readers[i]) => 0;
|
||||||
|
}
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # open same file reading and writing from separate file handles
|
||||||
|
define.READERS = 3
|
||||||
|
define.SIZE = [10, 100, 1000, 10000]
|
||||||
|
define.RDMODE = ['LFS_O_RDONLY', 'LFS_O_RDWR']
|
||||||
|
define.WRMODE = ['LFS_O_WRONLY', 'LFS_O_RDWR']
|
||||||
|
code = '''
|
||||||
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
const char nums[] = "0123456789";
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &file, "shared", LFS_O_CREAT | LFS_O_WRONLY) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// open all files
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_t writer;
|
||||||
|
lfs_file_t readers[READERS];
|
||||||
|
lfs_file_open(&lfs, &writer, "shared", WRMODE) => 0;
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
lfs_file_open(&lfs, &readers[i], "shared", RDMODE) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform operations while all readers are open
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &writer, &nums[j % 10], 1) => 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
for (int j = 0; j < SIZE/2; j++) {
|
||||||
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sync, now write should reflect in all open files
|
||||||
|
lfs_file_sync(&lfs, &writer) => 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
for (int j = SIZE/2; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// double check our writer reflects its own changes
|
||||||
|
if (WRMODE == LFS_O_RDWR) {
|
||||||
|
lfs_file_rewind(&lfs, &writer) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &writer, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
lfs_file_close(&lfs, &readers[i]) => 0;
|
||||||
|
}
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # check that attributes are updated in open files
|
||||||
|
define.READERS = 3
|
||||||
|
define.SIZE = 10
|
||||||
|
define.RDMODE = ['LFS_O_RDONLY', 'LFS_O_RDWR']
|
||||||
|
define.WRMODE = ['LFS_O_WRONLY', 'LFS_O_RDWR']
|
||||||
|
code = '''
|
||||||
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
const char nums[] = "0123456789";
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
const struct lfs_file_config filecfg = {
|
||||||
|
.attr_count = 3,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', "a", 1},
|
||||||
|
{'B', "bb", 2},
|
||||||
|
{'C', "ccc", 3},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_opencfg(&lfs, &file, "shared",
|
||||||
|
LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// open all files
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_t writer;
|
||||||
|
const struct lfs_file_config writercfg = {
|
||||||
|
.attr_count = 3,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[1]){0}, 1},
|
||||||
|
{'B', &(uint8_t[2]){0}, 2},
|
||||||
|
{'C', &(uint8_t[3]){0}, 3}}};
|
||||||
|
lfs_file_t readers[READERS];
|
||||||
|
const struct lfs_file_config readercfgs[READERS] = {
|
||||||
|
{ .attr_count = 3,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[1]){0}, 1},
|
||||||
|
{'B', &(uint8_t[2]){0}, 2},
|
||||||
|
{'C', &(uint8_t[3]){0}, 3}}},
|
||||||
|
{ .attr_count = 3,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[1]){0}, 1},
|
||||||
|
{'B', &(uint8_t[2]){0}, 2},
|
||||||
|
{'C', &(uint8_t[3]){0}, 3}}},
|
||||||
|
{ .attr_count = 3,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[1]){0}, 1},
|
||||||
|
{'B', &(uint8_t[2]){0}, 2},
|
||||||
|
{'C', &(uint8_t[3]){0}, 3}}}};
|
||||||
|
lfs_file_opencfg(&lfs, &writer, "shared",
|
||||||
|
WRMODE, &writercfg) => 0;
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
lfs_file_opencfg(&lfs, &readers[i], "shared",
|
||||||
|
RDMODE, &readercfgs[i]) => 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform operations while all readers are open
|
||||||
|
writercfg.attrs[0].size = 1;
|
||||||
|
memcpy(writercfg.attrs[0].buffer, "0", 1);
|
||||||
|
writercfg.attrs[1].size = 2;
|
||||||
|
memcpy(writercfg.attrs[1].buffer, "11", 2);
|
||||||
|
writercfg.attrs[2].size = 3;
|
||||||
|
memcpy(writercfg.attrs[2].buffer, "222", 3);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &writer, &nums[j % 10], 1) => 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
assert(readercfgs[i].attrs[0].size == 1);
|
||||||
|
assert(memcmp(readercfgs[i].attrs[0].buffer, "a", 1) == 0);
|
||||||
|
assert(readercfgs[i].attrs[1].size == 2);
|
||||||
|
assert(memcmp(readercfgs[i].attrs[1].buffer, "bb", 2) == 0);
|
||||||
|
assert(readercfgs[i].attrs[2].size == 3);
|
||||||
|
assert(memcmp(readercfgs[i].attrs[2].buffer, "ccc", 3) == 0);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sync, now write should reflect in all open files
|
||||||
|
lfs_file_sync(&lfs, &writer) => 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
assert(readercfgs[i].attrs[0].size == 1);
|
||||||
|
assert(memcmp(readercfgs[i].attrs[0].buffer, "0", 1) == 0);
|
||||||
|
assert(readercfgs[i].attrs[1].size == 2);
|
||||||
|
assert(memcmp(readercfgs[i].attrs[1].buffer, "11", 2) == 0);
|
||||||
|
assert(readercfgs[i].attrs[2].size == 3);
|
||||||
|
assert(memcmp(readercfgs[i].attrs[2].buffer, "222", 3) == 0);
|
||||||
|
lfs_file_rewind(&lfs, &readers[i]) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// double check our writer reflects its own changes
|
||||||
|
if (WRMODE == LFS_O_RDWR) {
|
||||||
|
assert(writercfg.attrs[0].size == 1);
|
||||||
|
assert(memcmp(writercfg.attrs[0].buffer, "0", 1) == 0);
|
||||||
|
assert(writercfg.attrs[1].size == 2);
|
||||||
|
assert(memcmp(writercfg.attrs[1].buffer, "11", 2) == 0);
|
||||||
|
assert(writercfg.attrs[2].size == 3);
|
||||||
|
assert(memcmp(writercfg.attrs[2].buffer, "222", 3) == 0);
|
||||||
|
lfs_file_rewind(&lfs, &writer) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &writer, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now try explicit lfs_setattr calls, this should still update open files
|
||||||
|
lfs_setattr(&lfs, "shared", 'A', "A", 1) => 0;
|
||||||
|
lfs_setattr(&lfs, "shared", 'B', "BB", 2) => 0;
|
||||||
|
lfs_setattr(&lfs, "shared", 'C', "CCC", 3) => 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
assert(readercfgs[i].attrs[0].size == 1);
|
||||||
|
assert(memcmp(readercfgs[i].attrs[0].buffer, "A", 1) == 0);
|
||||||
|
assert(readercfgs[i].attrs[1].size == 2);
|
||||||
|
assert(memcmp(readercfgs[i].attrs[1].buffer, "BB", 2) == 0);
|
||||||
|
assert(readercfgs[i].attrs[2].size == 3);
|
||||||
|
assert(memcmp(readercfgs[i].attrs[2].buffer, "CCC", 3) == 0);
|
||||||
|
lfs_file_rewind(&lfs, &readers[i]) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WRMODE == LFS_O_RDWR) {
|
||||||
|
assert(writercfg.attrs[0].size == 1);
|
||||||
|
assert(memcmp(writercfg.attrs[0].buffer, "A", 1) == 0);
|
||||||
|
assert(writercfg.attrs[1].size == 2);
|
||||||
|
assert(memcmp(writercfg.attrs[1].buffer, "BB", 2) == 0);
|
||||||
|
assert(writercfg.attrs[2].size == 3);
|
||||||
|
assert(memcmp(writercfg.attrs[2].buffer, "CCC", 3) == 0);
|
||||||
|
lfs_file_rewind(&lfs, &writer) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &writer, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
} else if (WRMODE == LFS_O_WRONLY) {
|
||||||
|
// this should NOT update wronly attributes, these may be
|
||||||
|
// stored in read-only memory
|
||||||
|
assert(writercfg.attrs[0].size == 1);
|
||||||
|
assert(memcmp(writercfg.attrs[0].buffer, "0", 1) == 0);
|
||||||
|
assert(writercfg.attrs[1].size == 2);
|
||||||
|
assert(memcmp(writercfg.attrs[1].buffer, "11", 2) == 0);
|
||||||
|
assert(writercfg.attrs[2].size == 3);
|
||||||
|
assert(memcmp(writercfg.attrs[2].buffer, "222", 3) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < READERS; i++) {
|
||||||
|
lfs_file_close(&lfs, &readers[i]) => 0;
|
||||||
|
}
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # simple snapshot for reading
|
||||||
|
define.SIZE = [10, 100, 1000, 10000]
|
||||||
|
code = '''
|
||||||
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
const char nums[] = "0123456789";
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
const struct lfs_file_config filecfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', "abcd", 4},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_opencfg(&lfs, &file, "open_me",
|
||||||
|
LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// open reader/writer/snapshot
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_t reader;
|
||||||
|
const struct lfs_file_config readercfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[4]){0}, 4}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_t writer;
|
||||||
|
const struct lfs_file_config writercfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[4]){0}, 4}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_t snapshot;
|
||||||
|
const struct lfs_file_config snapshotcfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[4]){0}, 4}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &writer, "open_me",
|
||||||
|
LFS_O_WRONLY, &writercfg) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &snapshot, "open_me",
|
||||||
|
LFS_O_RDONLY | LFS_O_SNAPSHOT, &snapshotcfg) => 0;
|
||||||
|
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE/2; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(memcmp(snapshotcfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE/2; j++) {
|
||||||
|
lfs_file_read(&lfs, &snapshot, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write file
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &writer, &nums[j % 10], 1) => 1;
|
||||||
|
}
|
||||||
|
memcpy(writercfg.attrs[0].buffer, "0123", 4);
|
||||||
|
lfs_file_sync(&lfs, &writer) => 0;
|
||||||
|
|
||||||
|
// reader should change
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "0123", 4) == 0);
|
||||||
|
for (int j = SIZE/2; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// snapshot should remain unchanged
|
||||||
|
assert(memcmp(snapshotcfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = SIZE/2; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &snapshot, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_file_close(&lfs, &writer) => 0;
|
||||||
|
lfs_file_close(&lfs, &snapshot) => 0;
|
||||||
|
|
||||||
|
// disk should change
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "0123", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "0123", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # simple snapshot for writing
|
||||||
|
define.SIZE = [10, 100, 1000, 10000]
|
||||||
|
code = '''
|
||||||
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
const char nums[] = "0123456789";
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
const struct lfs_file_config filecfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', "abcd", 4},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_opencfg(&lfs, &file, "open_me",
|
||||||
|
LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// open reader/snapshot
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_t reader;
|
||||||
|
const struct lfs_file_config readercfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[4]){0}, 4}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_t snapshot;
|
||||||
|
const struct lfs_file_config snapshotcfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[4]){0}, 4}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &snapshot, "open_me",
|
||||||
|
LFS_O_RDWR | LFS_O_SNAPSHOT, &snapshotcfg) => 0;
|
||||||
|
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE/2; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(memcmp(snapshotcfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &snapshot, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// modify snapshot
|
||||||
|
lfs_file_rewind(&lfs, &snapshot) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &snapshot, &nums[j % 10], 1) => 1;
|
||||||
|
}
|
||||||
|
memcpy(snapshotcfg.attrs[0].buffer, "0123", 4);
|
||||||
|
|
||||||
|
lfs_file_rewind(&lfs, &snapshot) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &snapshot, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_file_sync(&lfs, &snapshot) => 0;
|
||||||
|
|
||||||
|
// reader should not change
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = SIZE/2; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// snapshot should changed
|
||||||
|
assert(memcmp(snapshotcfg.attrs[0].buffer, "0123", 4) == 0);
|
||||||
|
lfs_file_rewind(&lfs, &snapshot) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &snapshot, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_file_close(&lfs, &snapshot) => 0;
|
||||||
|
|
||||||
|
// disk should not change
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # temporary files
|
||||||
|
define.SIZE = [10, 100, 1000, 10000]
|
||||||
|
define.TMP_PATH = 'range(4)'
|
||||||
|
code = '''
|
||||||
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
const char nums[] = "0123456789";
|
||||||
|
const char caps[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
const struct lfs_file_config filecfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', "abcd", 4},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_opencfg(&lfs, &file, "open_me",
|
||||||
|
LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &file, "dont_open_me",
|
||||||
|
LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &file) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// open reader/writer/temp
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_t reader;
|
||||||
|
const struct lfs_file_config readercfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[4]){0}, 4}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_t writer;
|
||||||
|
const struct lfs_file_config writercfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[4]){0}, 4}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_t tmp;
|
||||||
|
const struct lfs_file_config tmpcfg = {
|
||||||
|
.attr_count = 1,
|
||||||
|
.attrs = (struct lfs_attr[]){
|
||||||
|
{'A', &(uint8_t[4]){0}, 4}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &writer, "open_me",
|
||||||
|
LFS_O_WRONLY, &writercfg) => 0;
|
||||||
|
const char *tmp_paths[] = {NULL, "/", "/tmp", "/open_me.tmp"};
|
||||||
|
lfs_file_opencfg(&lfs, &tmp, tmp_paths[TMP_PATH],
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_SNAPSHOT, &tmpcfg) => 0;
|
||||||
|
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE/3; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(memcmp(tmpcfg.attrs[0].buffer, "\0\0\0\0", 4) == 0);
|
||||||
|
assert(lfs_file_size(&lfs, &tmp) == 0);
|
||||||
|
|
||||||
|
// write to tmp
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &tmp, &nums[j % 10], 1) => 1;
|
||||||
|
}
|
||||||
|
memcpy(tmpcfg.attrs[0].buffer, "0123", 4);
|
||||||
|
|
||||||
|
lfs_file_rewind(&lfs, &tmp) => 0;
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &tmp, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_file_sync(&lfs, &tmp) => 0;
|
||||||
|
|
||||||
|
// reader should not change
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = SIZE/3; j < 2*SIZE/3; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tmp should change
|
||||||
|
assert(memcmp(tmpcfg.attrs[0].buffer, "0123", 4) == 0);
|
||||||
|
lfs_file_rewind(&lfs, &tmp) => 0;
|
||||||
|
for (int j = 0; j < SIZE/2; j++) {
|
||||||
|
lfs_file_read(&lfs, &tmp, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write to file
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_write(&lfs, &writer, &caps[j % 26], 1) => 1;
|
||||||
|
}
|
||||||
|
memcpy(writercfg.attrs[0].buffer, "ABCD", 4);
|
||||||
|
lfs_file_sync(&lfs, &writer) => 0;
|
||||||
|
|
||||||
|
// reader should change
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "ABCD", 4) == 0);
|
||||||
|
for (int j = 2*SIZE/3; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == caps[j % 26]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tmp should not change
|
||||||
|
assert(memcmp(tmpcfg.attrs[0].buffer, "0123", 4) == 0);
|
||||||
|
for (int j = SIZE/2; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &tmp, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == nums[j % 10]);
|
||||||
|
}
|
||||||
|
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_file_close(&lfs, &writer) => 0;
|
||||||
|
lfs_file_close(&lfs, &tmp) => 0;
|
||||||
|
|
||||||
|
// tmp should not appear on disk
|
||||||
|
lfs_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(strcmp(info.name, "dont_open_me") == 0);
|
||||||
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(strcmp(info.name, "open_me") == 0);
|
||||||
|
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
lfs_dir_close(&lfs, &dir) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "ABCD", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == caps[j % 26]);
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "dont_open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(strcmp(info.name, "dont_open_me") == 0);
|
||||||
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(strcmp(info.name, "open_me") == 0);
|
||||||
|
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
lfs_dir_close(&lfs, &dir) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "ABCD", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == caps[j % 26]);
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_file_opencfg(&lfs, &reader, "dont_open_me",
|
||||||
|
LFS_O_RDONLY, &readercfg) => 0;
|
||||||
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
||||||
|
for (int j = 0; j < SIZE; j++) {
|
||||||
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
||||||
|
assert(buffer[0] == alphas[j % 26]);
|
||||||
|
}
|
||||||
|
lfs_file_close(&lfs, &reader) => 0;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[[case]] # test snapshot open errors
|
||||||
|
code = '''
|
||||||
|
lfs_format(&lfs, &cfg) => 0;
|
||||||
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
|
lfs_file_open(&lfs, &file, NULL,
|
||||||
|
LFS_O_RDWR | LFS_O_SNAPSHOT) => LFS_ERR_ISDIR;
|
||||||
|
lfs_file_open(&lfs, &file, "/",
|
||||||
|
LFS_O_RDWR | LFS_O_SNAPSHOT) => LFS_ERR_ISDIR;
|
||||||
|
lfs_file_open(&lfs, &file, "/tmp",
|
||||||
|
LFS_O_RDWR | LFS_O_SNAPSHOT) => LFS_ERR_NOENT;
|
||||||
|
lfs_file_open(&lfs, &file, "/tmp/",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_SNAPSHOT) => LFS_ERR_NOENT;
|
||||||
|
lfs_file_open(&lfs, &file, "/tmp/tmp",
|
||||||
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_SNAPSHOT) => LFS_ERR_NOENT;
|
||||||
|
lfs_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|||||||
@@ -95,9 +95,9 @@ code = '''
|
|||||||
|
|
||||||
lfs_mkdir(&lfs, "coffee/../milk") => 0;
|
lfs_mkdir(&lfs, "coffee/../milk") => 0;
|
||||||
lfs_stat(&lfs, "coffee/../milk", &info) => 0;
|
lfs_stat(&lfs, "coffee/../milk", &info) => 0;
|
||||||
strcmp(info.name, "milk") => 0;
|
assert(strcmp(info.name, "milk") == 0);
|
||||||
lfs_stat(&lfs, "milk", &info) => 0;
|
lfs_stat(&lfs, "milk", &info) => 0;
|
||||||
strcmp(info.name, "milk") => 0;
|
assert(strcmp(info.name, "milk") == 0);
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -129,9 +129,9 @@ code = '''
|
|||||||
lfs_mount(&lfs, &cfg) => 0;
|
lfs_mount(&lfs, &cfg) => 0;
|
||||||
lfs_mkdir(&lfs, ".milk") => 0;
|
lfs_mkdir(&lfs, ".milk") => 0;
|
||||||
lfs_stat(&lfs, ".milk", &info) => 0;
|
lfs_stat(&lfs, ".milk", &info) => 0;
|
||||||
strcmp(info.name, ".milk") => 0;
|
assert(strcmp(info.name, ".milk") == 0);
|
||||||
lfs_stat(&lfs, "tea/.././.milk", &info) => 0;
|
lfs_stat(&lfs, "tea/.././.milk", &info) => 0;
|
||||||
strcmp(info.name, ".milk") => 0;
|
assert(strcmp(info.name, ".milk") == 0);
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -149,13 +149,13 @@ code = '''
|
|||||||
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
|
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
|
||||||
|
|
||||||
lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0;
|
lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0;
|
||||||
strcmp(info.name, "hottea") => 0;
|
assert(strcmp(info.name, "hottea") == 0);
|
||||||
|
|
||||||
lfs_mkdir(&lfs, "coffee/../../../../../../milk") => 0;
|
lfs_mkdir(&lfs, "coffee/../../../../../../milk") => 0;
|
||||||
lfs_stat(&lfs, "coffee/../../../../../../milk", &info) => 0;
|
lfs_stat(&lfs, "coffee/../../../../../../milk", &info) => 0;
|
||||||
strcmp(info.name, "milk") => 0;
|
assert(strcmp(info.name, "milk") == 0);
|
||||||
lfs_stat(&lfs, "milk", &info) => 0;
|
lfs_stat(&lfs, "milk", &info) => 0;
|
||||||
strcmp(info.name, "milk") => 0;
|
assert(strcmp(info.name, "milk") == 0);
|
||||||
lfs_unmount(&lfs) => 0;
|
lfs_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user