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:
@@ -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,
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user