Changed how dir offsets in tell/seek are encoded

This is an attempt to fix issues with dir seeking in a filesystem
undergoing changes. The problem with the previous dstart-relative
position encoding is that if we deleted/created new entries outside of
our current directory, we didn't if they were inside or outside of the
current directory, so we couldn't always update our position correctly.

Instead of using a dstart-relative position, this solution crams both
the mid and rid into a single 31-bit integer. Things get a bit tight
here, so we use the current block_size as a heuristic for how many
possible rids we can ever have in a single mdir. The idea is the larger
the rid encoding needs to be, the smaller the mid encoding needs to be,
and we should, _roughly_, approach the same encoding limitation we would
have to dstart-relative position anyways.

Making some assumptions about the maximum possible number of rids in a
block gives us at most ~block_size/8 rids per mdir.

So for 4096 byte blocks (note the exact encoding is dynamic):

  sbbbbbbb bbbbbbbb bbbbbbbr rrrrrrrr
  ^'-----------+----------''----+---'
  '------------|----------------|----- sign bit (used for errors)
               '----------------|----- 22-bit metadata bid
                                '----- 9-bit metadata rid

Note this introduced as new, significant limitation on the number of
total mdirs in the system. Normally I would be against this solution for
that reason, however if we adopt this encoding elsewhere in the system it
may improve some RAM cost and in general simplify things by being able to
store any mid in a single integer. More work needs to be done here...

This approach needs some fleshing out and has its own issues (the
offset returned by tell quickly becomes out of date if the filesystem
is modified, but is that really a problem?), but it improves over the
previous implementation by making tell always correct at that moment.
This commit is contained in:
Christopher Haster
2023-07-27 16:08:07 -05:00
parent e0f416f6ca
commit edd12e1f93
3 changed files with 180 additions and 81 deletions
+111 -35
View File
@@ -5056,6 +5056,54 @@ static int lfsr_btree_traversal_next(lfs_t *lfs,
/// Metadata pair operations ///
// mids are a tuple of bid (index in the mtree) and rid (index in the mdir)
// shoved into an integer
//
// We want to maximize our encoding space, so we conservatively carve out
// only enough space to fit the maximum possible number of rids in an mdir.
// In theory, as the mdirs get larger, we need fewer mdirs for a filesystem of
// a given word size.
//
// - Each file neads 1 tag minimum
// - Each tag needs ~2 alts with our current compaction strategy
// - Each tag/alt encodes to a minimum of 4 bytes
//
// This gives us ~1*3*4 or ~12 bytes per rid minimum. Rounding down to the
// nearest power of 2 gives us ~block_size/8 rids per block at most.
//
#define LFSR_MID(_lfs, _bid, _rid) \
(((_bid) << lfs_nlog2((_lfs)->cfg->block_size/8)) \
| ((_rid) & ((1 << lfs_nlog2((_lfs)->cfg->block_size/8))-1)))
// reserved values to represent "." and ".." entries
//
// note these need to be positive values to fit in the lfsr_soff_t returned
// by lfsr_dir_tell
//
// TODO is this really the best way to carve out space for these entries?
// TODO do we need an mdir_limit in the superconfig? since this makes
// mid=max problematic
enum {
LFSR_MID_DOT = 0x7fffffff & -2,
LFSR_MID_DOTDOT = 0x7fffffff & -1,
};
static inline lfs_ssize_t lfsr_mid_bid(lfs_t *lfs, lfsr_mid_t mid) {
// TODO can we get rid of this?
// adjust mid if mtree is inlined
if (lfsr_mtree_isinlined(lfs)) {
return LFSR_MID_MROOT;
}
// TODO should this be stored in lfs_t?
return mid >> lfs_nlog2(lfs->cfg->block_size/8);
}
static inline lfs_size_t lfsr_mid_rid(lfs_t *lfs, lfsr_mid_t mid) {
// TODO should this be stored in lfs_t?
return mid & ((1 << lfs_nlog2(lfs->cfg->block_size/8))-1);
}
// mptr things
typedef struct lfsr_mptr {
lfs_block_t blocks[2];
@@ -7798,7 +7846,7 @@ int lfsr_dir_open(lfs_t *lfs, lfsr_dir_t *dir, const char *path) {
}
}
// leave it up to rewind to initialize pos/mid/rid
// leave it up to rewind to initialize mid/dots
err = lfsr_dir_rewind(lfs, dir);
if (err) {
return err;
@@ -7818,16 +7866,16 @@ int lfsr_dir_close(lfs_t *lfs, lfsr_dir_t *dir) {
int lfsr_dir_read(lfs_t *lfs, lfsr_dir_t *dir, struct lfs_info *info) {
memset(info, 0, sizeof(struct lfs_info));
// handle "." and ".." specially
if (dir->pos == 0) {
// handle dots specially
if (dir->dots == 0) {
info->type = LFS_TYPE_DIR;
strcpy(info->name, ".");
dir->pos += 1;
dir->dots += 1;
return 0;
} else if (dir->pos == 1) {
} else if (dir->dots == 1) {
info->type = LFS_TYPE_DIR;
strcpy(info->name, "..");
dir->pos += 1;
dir->dots += 1;
return 0;
}
@@ -7847,67 +7895,95 @@ int lfsr_dir_read(lfs_t *lfs, lfsr_dir_t *dir, struct lfs_info *info) {
return err;
}
// found another directory's dstart? we must be done
if (tag == LFSR_TAG_DSTART) {
return LFS_ERR_NOENT;
}
// fill in our info struct
info->type = lfsr_tag_filetype(tag);
LFS_ASSERT(lfsr_data_size(data) <= LFS_NAME_MAX);
lfs_ssize_t d = lfsr_data_readleb128(lfs, data, 0, &(uint32_t){0});
lfs_size_t did;
lfs_ssize_t d = lfsr_data_readleb128(lfs, data, 0, &did);
if (d < 0) {
return d;
}
// did mismatch? we must be done
if (did != dir->did) {
return LFS_ERR_NOENT;
}
// get file name from the name entry
LFS_ASSERT(lfsr_data_size(data)-d <= LFS_NAME_MAX);
d = lfsr_data_read(lfs, data, d, info->name, LFS_NAME_MAX);
if (d < 0) {
return d;
}
info->name[d] = '\0';
// TODO size once we actually have regular files
// get file type from the tag
info->type = lfsr_tag_filetype(tag);
// TODO get size once we actually have regular files
// eagerly look up the next entry
err = lfsr_mtree_seek(lfs, &dir->mdir.mdir, &dir->mdir.rid, 1);
if (err && err != LFS_ERR_NOENT) {
return err;
}
dir->pos += 1;
return 0;
}
int lfsr_dir_seek(lfs_t *lfs, lfsr_dir_t *dir, lfs_off_t off) {
// first rewind
int err = lfsr_dir_rewind(lfs, dir);
// off should never be negative, most likely an error went unchecked
//
// TODO is this the right approach? should we just assert if we detect
// a modified directory during seek?
// Note that aside from negative offsets, all other offset are accepted.
// This makes it so seeking to an outdated offset in the case of concurrent
// modification is at least not an assert, though it may repeat files in
// the directory.
LFS_ASSERT((lfs_soff_t)off > 0);
// handle dots specially
if (off == LFSR_MID_DOT || off == LFSR_MID_DOTDOT) {
int err = lfsr_dir_rewind(lfs, dir);
if (err) {
return err;
}
dir->dots = off - LFSR_MID_DOT;
return 0;
}
dir->dots = 2;
// find our mdir
lfs_ssize_t mid = lfsr_mid_bid(lfs, off);
int err = lfsr_mtree_lookup(lfs,
lfs_smin32(mid, (lfs_ssize_t)lfsr_mtree_weight(lfs)-1),
&dir->mdir.mdir);
if (err) {
return err;
}
// then seek to the requested offset, we leave it up to lfsr_mtree_seek
// to make this efficient
//
// note the -2 to adjust for "." and ".." entries
if (off > 2) {
err = lfsr_mtree_seek(lfs, &dir->mdir.mdir, &dir->mdir.rid, off - 2);
if (err && err != LFS_ERR_NOENT) {
return err;
}
// and update our rid, clamping to rbyd weight
lfs_ssize_t rid = lfsr_mid_rid(lfs, off);
if (mid > dir->mdir.mdir.mid
|| rid >= (lfs_ssize_t)dir->mdir.mdir.rbyd.weight) {
dir->mdir.rid = dir->mdir.mdir.rbyd.weight;
} else {
dir->mdir.rid = rid;
}
dir->pos = off;
return 0;
}
lfs_soff_t lfsr_dir_tell(lfs_t *lfs, lfsr_dir_t *dir) {
(void)lfs;
return dir->pos;
if (dir->dots == 0) {
return LFSR_MID_DOT;
} else if (dir->dots == 1) {
return LFSR_MID_DOTDOT;
} else {
return LFSR_MID(lfs, lfs_smax32(dir->mdir.mdir.mid, 0), dir->mdir.rid);
}
}
int lfsr_dir_rewind(lfs_t *lfs, lfsr_dir_t *dir) {
// reset pos
dir->pos = 0;
// reset dots
dir->dots = 0;
// lookup our dstart in the mtree
int err = lfsr_mtree_dnamelookup(lfs, dir->did, NULL, 0,
+6 -1
View File
@@ -47,6 +47,11 @@ typedef uint32_t lfs_block_t;
typedef uint16_t lfsr_tag_t;
typedef int16_t lfsr_stag_t;
// mids are a tuple of bid (index in the mtree) and rid (index in the mdir)
// shoved into an integer
typedef lfs_size_t lfsr_mid_t;
typedef lfs_ssize_t lfsr_smid_t;
// Maximum name size in bytes, may be redefined to reduce the size of the
// info struct. Limited to <= 1022. Stored in superblock and must be
// respected by other littlefs drivers.
@@ -425,7 +430,7 @@ typedef struct lfs_dir {
typedef struct lfsr_dir {
lfsr_openedmdir_t mdir;
lfs_size_t did;
lfs_off_t pos;
uint8_t dots;
} lfsr_dir_t;
// littlefs file type
+63 -45
View File
@@ -5081,31 +5081,37 @@ code = '''
// read our directory
//
// Note tell's value is not guaranteed! We can test the exact value only
// because these tests are tightly bound to the current littlefs version.
// we can't really make many assumptions about tell's value, so just
// check for no errors
//
lfsr_dir_t dir;
lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0;
lfsr_dir_tell(&lfs, &dir) => 0;
lfs_soff_t off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
struct lfs_info info;
lfsr_dir_read(&lfs, &dir, &info) => 0;
off = lfsr_dir_read(&lfs, &dir, &info);
assert(off >= 0);
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t i = 0; i < N; i++) {
lfsr_dir_tell(&lfs, &dir) => 2 + i;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
char name[256];
sprintf(name, "dir%04d", i);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
lfsr_dir_tell(&lfs, &dir) => 2 + N;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_tell(&lfs, &dir) => 2 + N;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
lfsr_dir_close(&lfs, &dir) => 0;
lfsr_unmount(&lfs) => 0;
@@ -5134,48 +5140,58 @@ code = '''
lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0;
// read our directory once
lfsr_dir_tell(&lfs, &dir) => 0;
lfs_soff_t off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
struct lfs_info info;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t i = 0; i < N; i++) {
lfsr_dir_tell(&lfs, &dir) => 2 + i;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
char name[256];
sprintf(name, "dir%04d", i);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
lfsr_dir_tell(&lfs, &dir) => 2 + N;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_tell(&lfs, &dir) => 2 + N;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
// now read it again
lfsr_dir_rewind(&lfs, &dir) => 0;
lfsr_dir_tell(&lfs, &dir) => 0;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t i = 0; i < N; i++) {
lfsr_dir_tell(&lfs, &dir) => 2 + i;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
char name[256];
sprintf(name, "dir%04d", i);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
lfsr_dir_tell(&lfs, &dir) => 2 + N;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_tell(&lfs, &dir) => 2 + N;
off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
lfsr_dir_close(&lfs, &dir) => 0;
@@ -5205,45 +5221,53 @@ code = '''
lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0;
// read our directory once
lfsr_dir_tell(&lfs, &dir) => 0;
lfs_soff_t offs[2+N+2];
offs[0] = lfsr_dir_tell(&lfs, &dir);
assert(offs[0] >= 0);
struct lfs_info info;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
offs[1] = lfsr_dir_tell(&lfs, &dir);
assert(offs[1] >= 0);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t i = 0; i < N; i++) {
lfsr_dir_tell(&lfs, &dir) => 2 + i;
offs[2+i] = lfsr_dir_tell(&lfs, &dir);
assert(offs[2+i] >= 0);
char name[256];
sprintf(name, "dir%04d", i);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
lfsr_dir_tell(&lfs, &dir) => 2 + N;
offs[2+N+0] = lfsr_dir_tell(&lfs, &dir);
assert(offs[2+N+0] >= 0);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_tell(&lfs, &dir) => 2 + N;
offs[2+N+1] = lfsr_dir_tell(&lfs, &dir);
assert(offs[2+N+1] >= 0);
// now try to seek to each entry explicitly
lfsr_dir_seek(&lfs, &dir, 0) => 0;
lfsr_dir_seek(&lfs, &dir, offs[0]) => 0;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_seek(&lfs, &dir, 1) => 0;
lfsr_dir_seek(&lfs, &dir, offs[1]) => 0;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t i = 0; i < N; i++) {
lfsr_dir_seek(&lfs, &dir, 2 + i) => 0;
lfsr_dir_seek(&lfs, &dir, offs[2+i]) => 0;
char name[256];
sprintf(name, "dir%04d", i);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
lfsr_dir_seek(&lfs, &dir, 2 + N) => 0;
lfsr_dir_seek(&lfs, &dir, offs[2+N+0]) => 0;
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_seek(&lfs, &dir, offs[2+N+1]) => 0;
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
@@ -5289,7 +5313,6 @@ code = '''
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -5297,6 +5320,8 @@ code = '''
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfs_soff_t off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 0);
// reading again should still return noent
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
@@ -5304,10 +5329,10 @@ code = '''
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
// seeking past the end of the directory should still return noent
lfsr_dir_seek(&lfs, &dir, 4) => 0;
lfsr_dir_seek(&lfs, &dir, off) => 0;
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_seek(&lfs, &dir, 40) => 0;
lfsr_dir_seek(&lfs, &dir, off + 1000) => 0;
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
@@ -5319,7 +5344,6 @@ code = '''
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -5379,7 +5403,6 @@ code = '''
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -5402,7 +5425,7 @@ code = '''
// updated correctly
if (SEEK) {
lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 2);
assert(off >= 0);
lfsr_dir_rewind(&lfs, &dir) => 0;
lfsr_dir_seek(&lfs, &dir, off) => 0;
}
@@ -5468,7 +5491,6 @@ code = '''
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -5491,7 +5513,7 @@ code = '''
// updated correctly
if (SEEK) {
lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 2);
assert(off >= 0);
lfsr_dir_rewind(&lfs, &dir) => 0;
lfsr_dir_seek(&lfs, &dir, off) => 0;
}
@@ -5569,7 +5591,6 @@ code = '''
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -5599,7 +5620,7 @@ code = '''
// updated correctly
if (SEEK) {
lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 2);
assert(off >= 0);
lfsr_dir_rewind(&lfs, &dir) => 0;
lfsr_dir_seek(&lfs, &dir, off) => 0;
}
@@ -5677,7 +5698,6 @@ code = '''
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -5704,7 +5724,7 @@ code = '''
// updated correctly
if (SEEK) {
lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 2);
assert(off >= 0);
lfsr_dir_rewind(&lfs, &dir) => 0;
lfsr_dir_seek(&lfs, &dir, off) => 0;
}
@@ -5778,7 +5798,6 @@ code = '''
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -5805,7 +5824,7 @@ code = '''
// updated correctly
if (SEEK) {
lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 2);
assert(off >= 0);
lfsr_dir_rewind(&lfs, &dir) => 0;
lfsr_dir_seek(&lfs, &dir, off) => 0;
}
@@ -5887,7 +5906,6 @@ code = '''
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_tell(&lfs, &dir) => 1;
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -5927,7 +5945,7 @@ code = '''
// updated correctly
if (SEEK) {
lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 2);
assert(off >= 0);
lfsr_dir_rewind(&lfs, &dir) => 0;
lfsr_dir_seek(&lfs, &dir, off) => 0;
}
@@ -6043,7 +6061,7 @@ code = '''
// updated correctly
if (SEEK) {
lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir);
assert(off == 2);
assert(off >= 0);
lfsr_dir_rewind(&lfs, &dir) => 0;
lfsr_dir_seek(&lfs, &dir, off) => 0;
}
@@ -6198,7 +6216,7 @@ code = '''
// updated correctly
if (SEEK) {
lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir);
assert(off >= 2);
assert(off >= 0);
lfsr_dir_rewind(&lfs, &dir) => 0;
lfsr_dir_seek(&lfs, &dir, off) => 0;
}