diff --git a/lfs.c b/lfs.c index 611f6728..638f72c7 100644 --- a/lfs.c +++ b/lfs.c @@ -1172,7 +1172,7 @@ tryagain:; lfs_rtag_t alt; lfs_off_t jump; lfs_ssize_t delta = lfs_rbyd_readtag(lfs, - &lfs->pcache, &lfs->rcache, 2*4, + &lfs->pcache, &lfs->rcache, lfs->cfg->block_size, rbyd->block, branch, &alt, &jump, NULL); if (delta < 0) { return delta; @@ -1216,6 +1216,34 @@ tryagain:; } } +static lfs_ssize_t lfs_rbyd_get(lfs_t *lfs, const lfs_rbyd_t *rbyd, + lfs_rtag_t tag, void *buffer, lfs_size_t size) { + lfs_off_t found_off; + lfs_size_t found_size; + lfs_srtag_t found_tag = lfs_rbyd_lookup(lfs, rbyd, tag, + &found_off, &found_size); + if (found_tag < 0) { + return found_tag; + } + + // lookup finds the next-smallest tag, here we fail if it's not + // an exact match + if ((lfs_tag_t)found_tag != tag) { + return LFS_ERR_NOENT; + } + + // note that it's highly likely the data is in our cache now + lfs_size_t delta = lfs_min(size, found_size); + int err = lfs_bd_read(lfs, + &lfs->pcache, &lfs->rcache, delta, + rbyd->block, found_off, buffer, delta); + if (err) { + return err; + } + + return found_size; +} + static int lfs_rbyd_prog(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, lfs_block_t block, lfs_off_t off, @@ -1438,7 +1466,7 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd, lfs_rtag_t alt; lfs_off_t jump; lfs_ssize_t delta = lfs_rbyd_readtag(lfs, - &lfs->pcache, &lfs->rcache, 2*4, + &lfs->pcache, &lfs->rcache, lfs->cfg->block_size, block, branch, &alt, &jump, NULL); if (delta < 0) { return delta; diff --git a/tests/test_rbyd.toml b/tests/test_rbyd.toml index b919cb19..ae24eb9b 100644 --- a/tests/test_rbyd.toml +++ b/tests/test_rbyd.toml @@ -230,6 +230,151 @@ code = ''' => LFS_ERR_NOENT; ''' +[cases.test_rbyd_get] +in = 'lfs.c' +code = ''' + lfs_t lfs; + lfs_init(&lfs, cfg) => 0; + + lfs_rbyd_t init_rbyd = { + .block = 0, + .trunk = 0, + .off = 0, + .rev = 1, + .crc = 0, + .count = 0, + .erased = true, + }; + lfs_rbyd_t rbyd; + uint8_t buffer[4]; + + // try an empty commit + rbyd = init_rbyd; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; + + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => LFS_ERR_NOENT; + + // commit with one attribute + rbyd = init_rbyd; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(UATTR, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; + + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => 4; + assert(memcmp(buffer, &(uint32_t){0xaaaaaaaa}, 4) == 0); + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) + => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => 4; + assert(memcmp(buffer, &(uint32_t){0xaaaaaaaa}, 4) == 0); + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) + => LFS_ERR_NOENT; + + // commit with two attributes + rbyd = init_rbyd; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(UATTR, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(UATTR, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL))) => 0; + + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => 4; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) + => 4; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), buffer, 4) + => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => 4; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) + => 4; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), buffer, 4) + => LFS_ERR_NOENT; +''' + +[cases.test_rbyd_multi_get] +in = 'lfs.c' +code = ''' + lfs_t lfs; + lfs_init(&lfs, cfg) => 0; + + lfs_rbyd_t init_rbyd = { + .block = 0, + .trunk = 0, + .off = 0, + .rev = 1, + .crc = 0, + .count = 0, + .erased = true, + }; + lfs_rbyd_t rbyd; + uint8_t buffer[4]; + + // try an empty commit + rbyd = init_rbyd; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; + + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => LFS_ERR_NOENT; + + // commit with one attribute + rbyd = init_rbyd; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(UATTR, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; + + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => 4; + assert(memcmp(buffer, &(uint32_t){0xaaaaaaaa}, 4) == 0); + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) + => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => 4; + assert(memcmp(buffer, &(uint32_t){0xaaaaaaaa}, 4) == 0); + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) + => LFS_ERR_NOENT; + + // commit with two attributes + rbyd = init_rbyd; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(UATTR, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(UATTR, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL)) => 0; + + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => 4; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) + => 4; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), buffer, 4) + => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) + => 4; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) + => 4; + lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), buffer, 4) + => LFS_ERR_NOENT; +''' + [cases.test_rbyd_traverse] in = 'lfs.c' code = '''