diff --git a/lfs.c b/lfs.c index cfd7fe25..57012b2a 100644 --- a/lfs.c +++ b/lfs.c @@ -15,7 +15,6 @@ static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) { // do not zero, cheaper if cache is readonly or only going to be // written with identical data (during relocates) (void)lfs; - int heh; rcache->block = LFS_BLOCK_NULL; } @@ -2550,6 +2549,105 @@ lfs_ssize_t lfs_bd_progtag_(lfs_t *lfs, return hdiff; } +// TODO name dir->mdir for these low-level operations? +// TODO I don't think a mask works anymore, do we need this? +lfs_stag_t lfs_dir_getattrslice_(lfs_t *lfs, lfs_mdir__t *mdir, + lfs_tag_t tag, lfs_off_t off, void *buffer, lfs_size_t size, + lfs_size_t *pnsize) { + // it doesn't make sense to look up a non-radix-tree tag + LFS_ASSERT(lfs_tag_isradix_(tag)); + + // TODO handle synthetic move + + lfs_off_t roff = mdir->roff; + int bit = 28; // tag only uses the lower 28-bits + // iterate through tags + while (bit >= 0) { + lfs_tag_t rtag; + lfs_off_t rsize; + lfs_ssize_t rdiff = lfs_bd_readtag_(lfs, + NULL, &lfs->rcache, 2*sizeof(uint32_t), + mdir->pair[0], roff, &rtag, &rsize); + if (rdiff < 0) { + return rdiff; + } + + // TODO handle splices + + printf("%08x: rtag %08x %08x %08x\n", roff, rtag, (1 << bit), rsize); + + // found tag? + if (tag == rtag) { + lfs_size_t diff = 0; + if (off < rsize) { + diff = lfs_min(size, rsize-off); + int err = lfs_bd_read(lfs, + NULL, &lfs->rcache, diff, + mdir->pair[0], roff+rdiff+off, buffer, diff); + if (err) { + return err; + } + } + + if (pnsize) { + *pnsize = diff; + } + return rtag; + } + + // TODO better way to handle offsets? + rdiff += rsize; + + // iterate through alt-pointers + while (bit >= 0) { + lfs_tag_t ralt; + lfs_off_t nroff; + // TODO are hints correct both here and commit? + lfs_soff_t res = lfs_bd_readtag_(lfs, + NULL, &lfs->rcache, 2*sizeof(uint32_t), + mdir->pair[0], roff+rdiff, &ralt, &nroff); + if (res < 0) { + return res; + } + rdiff += res; + + // iterate through bits + while (bit >= 0) { + if (lfs_tag_isalt_(ralt) && + lfs_tag_alt_(ralt) > bit) { + // need new alt-pointer + goto next_alt; + } + + if ((tag ^ rtag) & (1 << bit)) { + if (lfs_tag_isalt_(ralt) && + lfs_tag_alt_(ralt) == bit) { + // follow alt-pointer + roff = nroff; + bit -= 1; + goto next_tag; + } else { + goto done; + } + } + + // next bit + bit -= 1; + } +next_alt:; + } +next_tag:; + } +done:; + + // not found + return LFS_ERR_NOENT; +} + +lfs_ssize_t lfs_dir_getattr_(lfs_t *lfs, lfs_mdir__t *mdir, + lfs_tag_t tag, void *buffer, lfs_size_t size, lfs_size_t *nsize) { + return lfs_dir_getattrslice_(lfs, mdir, tag, 0, buffer, size, nsize); +} // TODO should we just take mdir pointer? to a copy? we're carrying // around a lot of state @@ -2612,9 +2710,9 @@ lfs_ssize_t lfs_dir_commitattr_(lfs_t *lfs, lfs_off_t *proff, //printf("finding radices for 0x%08x!\n", tag); lfs_off_t roff = *proff; - // tags use only the lower 28-bits - for (int i = 0; i < 28 && roff; i++) { - // first get tag + int bit = 28; // tags use only the lower 28-bits + // iterate through tags + while (bit >= 0) { lfs_tag_t rtag; lfs_off_t rsize; lfs_ssize_t res = lfs_bd_readtag_(lfs, @@ -2625,8 +2723,8 @@ lfs_ssize_t lfs_dir_commitattr_(lfs_t *lfs, lfs_off_t *proff, } lfs_ssize_t rdiff = res + rsize; - while (true) { - // and alt-pointer + // iterate through alt-pointers + while (bit >= 0) { lfs_tag_t ralt; lfs_off_t nroff; res = lfs_bd_readtag_(lfs, @@ -2638,53 +2736,54 @@ lfs_ssize_t lfs_dir_commitattr_(lfs_t *lfs, lfs_off_t *proff, rdiff += res; // iterate through bits - for (; i < 28; i++) { - if ((tag ^ rtag) & (1 << (28-i))) { + while (bit >= 0) { + if ((tag ^ rtag) & (1 << bit)) { // different bit, new alt-pointer res = lfs_bd_progtag_(lfs, &lfs->pcache, &lfs->rcache, limit, crc, - block, off+diff, LFS_MKALT_(28-i), roff); + block, off+diff, LFS_MKALT_(bit), roff); if (res < 0) { return res; } diff += res; + } else if (lfs_tag_isalt_(ralt) && + lfs_tag_alt_(ralt) == bit) { + // same bit, copy alt-pointer + res = lfs_bd_progtag_(lfs, + &lfs->pcache, &lfs->rcache, limit, crc, + block, off+diff, ralt, nroff); + if (res < 0) { + return res; + } + diff += res; + } - // follow alt-pointer? + if (lfs_tag_isalt_(ralt) && + lfs_tag_alt_(ralt) > bit) { + // need new alt-pointer + goto next_alt; + } + + if ((tag ^ rtag) & (1 << bit)) { if (lfs_tag_isalt_(ralt) && - lfs_tag_alt_(ralt) == 28-i) { + lfs_tag_alt_(ralt) == bit) { + // follow alt-pointer roff = nroff; + bit -= 1; goto next_tag; } else { - roff = 0; - goto next_tag; - } - } else { - // same bit, copy alt-pointer - if (lfs_tag_isalt_(ralt) && - lfs_tag_alt_(ralt) == 28-i) { - //printf("copy alt 0x%08x 0x%08x\n", LFS_MKALT_(28-i), roff); - - res = lfs_bd_progtag_(lfs, - &lfs->pcache, &lfs->rcache, limit, crc, - block, off+diff, ralt, nroff); - if (res < 0) { - return res; - } - diff += res; - } - - if (lfs_tag_isalt_(ralt) && - lfs_tag_alt_(ralt) > 28-i) { - // need new alt-pointer - goto next_alt; + goto done; } } + + // next bit + bit -= 1; } next_alt:; } next_tag:; } - +done:; *proff = off; } @@ -2968,6 +3067,9 @@ relocate: LFS_ASSERT(false); // TODO } + // TODO finish commit? + lfs_pair_swap(mdir->pair); + return 0; } diff --git a/tests/test_mdirs.toml b/tests/test_mdirs.toml index ad89d05c..de2ca69e 100644 --- a/tests/test_mdirs.toml +++ b/tests/test_mdirs.toml @@ -15,24 +15,37 @@ code = ''' .tail = {0xffffffff, 0xffffffff}, }; - lfs_dir_compact_(&lfs, &mdir, LFS_MKATTRS_( - {LFS_MKTAG_(LFS_T_USERATTR, 0, 0), "0000", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 01, 0), "0001", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 2, 0), "0002", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 3, 0), "0003", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 4, 0), "0004", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 5, 0), "0005", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 6, 0), "0006", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 7, 0), "0007", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 8, 0), "0008", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 9, 0), "0009", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 10, 0), "0010", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 11, 0), "0011", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 12, 0), "0012", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 13, 0), "0013", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 14, 0), "0014", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 15, 0), "0015", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 0xaa, 0xaaaa), "0015", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 0xcc, 0xcccc), "0015", 4}, - {LFS_MKTAG_(LFS_T_USERATTR, 0xff, 0xffff), "0016", 4})) => 0; + + struct lfs_mattr_ attrs[] = { + {LFS_MKTAG_(LFS_T_USERATTR, 0, 0), "0000", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 1, 0), "0001", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 2, 0), "0002", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 3, 0), "0003", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 4, 0), "0004", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 5, 0), "0005", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 6, 0), "0006", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 7, 0), "0007", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 8, 0), "0008", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 9, 0), "0009", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 10, 0), "0010", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 11, 0), "0011", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 12, 0), "0012", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 13, 0), "0013", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 14, 0), "0014", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 15, 0), "0015", 4}, + {LFS_MKTAG_(LFS_T_USERATTR, 16, 0), "0016", 4} + }; + lfs_size_t attr_count = sizeof(attrs)/sizeof(attrs[0]); + + lfs_dir_compact_(&lfs, &mdir, attrs, attr_count) => 0; + + for (lfs_size_t i = 0; i < attr_count; i++) { + printf("looking up %08x\n", attrs[i].tag); + lfs_size_t nsize; + lfs_dir_getattr_(&lfs, &mdir, + attrs[i].tag, + buffer, sizeof(buffer), &nsize) => attrs[i].tag; + assert(nsize == attrs[i].size); + assert(memcmp(buffer, attrs[i].buffer, attrs[i].size) == 0); + } '''