mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 00:38:29 +01:00
WIP Moved findscan into fetch as primitive
This commit is contained in:
207
lfs.c
207
lfs.c
@@ -507,8 +507,11 @@ static int lfs_commit_commit(lfs_t *lfs,
|
||||
attr.u.dir, NULL);
|
||||
}
|
||||
|
||||
uint16_t id = lfs_tag_id(attr.tag) - commit->filter.begin;
|
||||
attr.tag = lfs_mktag(0, id, 0) | (attr.tag & 0xffc00fff);
|
||||
if (lfs_tag_id(attr.tag) != 0x3ff) {
|
||||
// TODO eh?
|
||||
uint16_t id = lfs_tag_id(attr.tag) - commit->filter.begin;
|
||||
attr.tag = lfs_mktag(0, id, 0) | (attr.tag & 0xffc00fff);
|
||||
}
|
||||
|
||||
// check if we fit
|
||||
lfs_size_t size = lfs_tag_size(attr.tag);
|
||||
@@ -757,12 +760,14 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
static int lfs_dir_find(lfs_t *lfs,
|
||||
lfs_mdir_t *dir, const lfs_block_t pair[2],
|
||||
int (*cb)(lfs_t *lfs, void *data, lfs_mattr_t attr), void *data) {
|
||||
uint32_t findmask, lfs_tag_t findtag,
|
||||
const void *findbuffer, lfs_tag_t *foundtag) {
|
||||
dir->pair[0] = pair[0];
|
||||
dir->pair[1] = pair[1];
|
||||
dir->stop_at_commit = false;
|
||||
*foundtag = 0xffffffff;
|
||||
|
||||
// find the block with the most recent revision
|
||||
uint32_t rev[2];
|
||||
@@ -794,12 +799,14 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
lfs_crc(&crc, &dir->rev, sizeof(dir->rev));
|
||||
dir->rev = lfs_fromle32(dir->rev);
|
||||
|
||||
lfs_mdir_t temp = *dir;
|
||||
lfs_mdir_t tempdir = *dir;
|
||||
lfs_tag_t tempfoundtag = *foundtag;
|
||||
|
||||
while (true) {
|
||||
// extract next tag
|
||||
lfs_tag_t tag;
|
||||
int err = lfs_bd_read(lfs, temp.pair[0], off, &tag, sizeof(tag));
|
||||
int err = lfs_bd_read(lfs, tempdir.pair[0],
|
||||
off, &tag, sizeof(tag));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -809,19 +816,8 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
|
||||
// next commit not yet programmed
|
||||
if (lfs_tag_type(ptag) == LFS_TYPE_CRC && !lfs_tag_isvalid(tag)) {
|
||||
// synthetic move
|
||||
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
|
||||
&& cb) {
|
||||
int err = cb(lfs, data, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_TYPE_DELETE,
|
||||
lfs->globals.move.id, 0)});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
dir->erased = true;
|
||||
return 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
// check we're in valid range
|
||||
@@ -829,93 +825,75 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("tag r %#010x (%x:%x %03x %03x %03x)\n", tag, temp.pair[0], off+sizeof(tag), lfs_tag_type(tag), lfs_tag_id(tag), lfs_tag_size(tag));
|
||||
if (lfs_tag_type(tag) == LFS_TYPE_CRC) {
|
||||
// check the crc attr
|
||||
uint32_t dcrc;
|
||||
int err = lfs_bd_read(lfs, temp.pair[0],
|
||||
int err = lfs_bd_read(lfs, tempdir.pair[0],
|
||||
off+sizeof(tag), &dcrc, sizeof(dcrc));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (crc != lfs_fromle32(dcrc)) {
|
||||
if (off == sizeof(temp.rev)) {
|
||||
if (off == sizeof(tempdir.rev)) {
|
||||
// try other block
|
||||
break;
|
||||
} else {
|
||||
// snythetic move
|
||||
// TODO combine with above?
|
||||
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
|
||||
&& cb) {
|
||||
int err = cb(lfs, data, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_TYPE_DELETE,
|
||||
lfs->globals.move.id, 0)});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// consider what we have good enough
|
||||
dir->erased = false;
|
||||
return 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
temp.off = off + sizeof(tag)+lfs_tag_size(tag);
|
||||
temp.etag = tag;
|
||||
tempdir.off = off + sizeof(tag)+lfs_tag_size(tag);
|
||||
tempdir.etag = tag;
|
||||
crc = 0xffffffff;
|
||||
*dir = temp;
|
||||
|
||||
// TODO simplify this?
|
||||
if (cb) {
|
||||
err = cb(lfs, data, (lfs_mattr_t){
|
||||
(tag | 0x80000000),
|
||||
.u.d.block=temp.pair[0],
|
||||
.u.d.off=off+sizeof(tag)});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
*dir = tempdir;
|
||||
*foundtag = tempfoundtag;
|
||||
} else {
|
||||
// TODO crc before callback???
|
||||
err = lfs_bd_crc(lfs, temp.pair[0],
|
||||
err = lfs_bd_crc(lfs, tempdir.pair[0],
|
||||
off+sizeof(tag), lfs_tag_size(tag), &crc);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (lfs_tag_id(tag) < 0x3ff &&
|
||||
lfs_tag_id(tag) >= tempdir.count) {
|
||||
tempdir.count = lfs_tag_id(tag)+1;
|
||||
}
|
||||
|
||||
if (lfs_tag_subtype(tag) == LFS_TYPE_TAIL) {
|
||||
temp.split = (lfs_tag_type(tag) & 1);
|
||||
err = lfs_bd_read(lfs, temp.pair[0], off+sizeof(tag),
|
||||
temp.tail, sizeof(temp.tail));
|
||||
tempdir.split = (lfs_tag_type(tag) & 1);
|
||||
err = lfs_bd_read(lfs, tempdir.pair[0], off+sizeof(tag),
|
||||
tempdir.tail, sizeof(tempdir.tail));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else if (lfs_tag_type(tag) == LFS_TYPE_GLOBALS) {
|
||||
err = lfs_bd_read(lfs, temp.pair[0], off+sizeof(tag),
|
||||
&temp.globals, sizeof(temp.globals));
|
||||
err = lfs_bd_read(lfs, tempdir.pair[0], off+sizeof(tag),
|
||||
&tempdir.globals, sizeof(tempdir.globals));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
if (lfs_tag_id(tag) < 0x3ff &&
|
||||
lfs_tag_id(tag) >= temp.count) {
|
||||
temp.count = lfs_tag_id(tag)+1;
|
||||
} else if (lfs_tag_type(tag) == LFS_TYPE_DELETE) {
|
||||
tempdir.count -= 1;
|
||||
|
||||
if (lfs_tag_id(tag) == lfs_tag_id(tempfoundtag)) {
|
||||
tempfoundtag = 0xffffffff;
|
||||
} else if (lfs_tag_id(tempfoundtag) < 0x3ff &&
|
||||
lfs_tag_id(tag) < lfs_tag_id(tempfoundtag)) {
|
||||
tempfoundtag -= lfs_mktag(0, 1, 0);
|
||||
}
|
||||
} else if ((tag & findmask) == (findtag & findmask)) {
|
||||
int res = lfs_bd_cmp(lfs, tempdir.pair[0], off+sizeof(tag),
|
||||
findbuffer, lfs_tag_size(tag));
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (lfs_tag_type(tag) == LFS_TYPE_DELETE) {
|
||||
temp.count -= 1;
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
err = cb(lfs, data, (lfs_mattr_t){
|
||||
(tag | 0x80000000),
|
||||
.u.d.block=temp.pair[0],
|
||||
.u.d.off=off+sizeof(tag)});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
if (res) {
|
||||
// found a match
|
||||
tempfoundtag = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -931,11 +909,34 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
|
||||
LFS_ERROR("Corrupted dir pair at %d %d", dir->pair[0], dir->pair[1]);
|
||||
return LFS_ERR_CORRUPT;
|
||||
|
||||
done:
|
||||
// synthetic move
|
||||
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0) {
|
||||
if (lfs->globals.move.id == lfs_tag_id(*foundtag)) {
|
||||
*foundtag = 0xffffffff;
|
||||
} else if (lfs_tag_id(*foundtag) < 0x3ff &&
|
||||
lfs->globals.move.id < lfs_tag_id(*foundtag)) {
|
||||
*foundtag -= lfs_mktag(0, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (*foundtag == 0xffffffff) {
|
||||
return LFS_ERR_NOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfs_dir_fetch(lfs_t *lfs,
|
||||
lfs_mdir_t *dir, const lfs_block_t pair[2]) {
|
||||
return lfs_dir_fetchwith(lfs, dir, pair, NULL, NULL);
|
||||
int err = lfs_dir_find(lfs, dir, pair,
|
||||
0xffffffff, 0xffffffff, NULL, &(lfs_tag_t){0});
|
||||
if (err && err != LFS_ERR_NOENT) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfs_dir_traverse(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
@@ -1115,6 +1116,8 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list,
|
||||
break;
|
||||
|
||||
split:
|
||||
// TODO update dirs that get split here?
|
||||
|
||||
// commit no longer fits, need to split dir,
|
||||
// drop caches and create tail
|
||||
lfs->pcache.block = 0xffffffff;
|
||||
@@ -1414,66 +1417,6 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lfs_dir_find {
|
||||
uint32_t mask;
|
||||
lfs_tag_t tag;
|
||||
const void *buffer;
|
||||
lfs_tag_t foundtag;
|
||||
lfs_tag_t temptag;
|
||||
};
|
||||
|
||||
static int lfs_dir_findscan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
|
||||
struct lfs_dir_find *find = p;
|
||||
|
||||
if ((attr.tag & find->mask) == (find->tag & find->mask)) {
|
||||
int res = lfs_bd_cmp(lfs, attr.u.d.block, attr.u.d.off,
|
||||
find->buffer, lfs_tag_size(attr.tag));
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (res) {
|
||||
// found a match
|
||||
find->temptag = attr.tag;
|
||||
}
|
||||
} else if (lfs_tag_type(attr.tag) == LFS_TYPE_DELETE) {
|
||||
if (lfs_tag_id(attr.tag) == lfs_tag_id(find->temptag)) {
|
||||
find->temptag = 0xffffffff;
|
||||
} else if (lfs_tag_id(find->temptag) < 0x3ff &&
|
||||
lfs_tag_id(attr.tag) < lfs_tag_id(find->temptag)) {
|
||||
find->temptag -= lfs_mktag(0, 1, 0);
|
||||
}
|
||||
} else if (lfs_tag_type(attr.tag) == LFS_TYPE_CRC) {
|
||||
find->foundtag = find->temptag;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, const lfs_block_t *pair,
|
||||
uint32_t mask, lfs_tag_t tag,
|
||||
const void *buffer, lfs_tag_t *foundtag) {
|
||||
struct lfs_dir_find find = {
|
||||
.mask = mask,
|
||||
.tag = tag,
|
||||
.buffer = buffer,
|
||||
.foundtag = 0xffffffff,
|
||||
.temptag = 0xffffffff,
|
||||
};
|
||||
|
||||
int err = lfs_dir_fetchwith(lfs, dir, pair, lfs_dir_findscan, &find);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (find.foundtag == 0xffffffff) {
|
||||
return LFS_ERR_NOENT;
|
||||
}
|
||||
|
||||
*foundtag = find.foundtag;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// TODO drop others, make this only return id, also make get take in only entry to populate (with embedded tag)
|
||||
static int lfs_dir_lookup(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
|
||||
Reference in New Issue
Block a user