Reworked how unknown file types are handled

This changes how we approach unknown file types.

Before:

> Unknown file types are allowed and may leak resources if modified,
> so attempted modification (rename/remove) will error with
> LFS_ERR_NOTSUP.

Now:

> Unknown file types are only allowed in RDONLY mode. This avoids the
> whole leaking resources headache.

Additionally, unknown types are now mapped to LFS_TYPE_UNKNOWN, instead
of just being forwarded to the user. This allows us to add internal
types/tags to the LFSR_TAG_NAME type space without worrying about
conflicts with future types:

- reg             -> LFS_TYPE_REG
- dir             -> LFS_TYPE_DIR
- stickynote      -> LFS_TYPE_STICKYNOTE
- everything else -> LFS_TYPE_UNKNOWN

Thinking about potential future types, it seems most (symlinks,
compressed files, etc) can be better implemented via custom attributes.
Using custom attributes doesn't mean the filesystem _can't_ inject
special behavior, and custom attributes allow for perfect backwards
compatibility.

So with future types less likely, forwarding type info to users is less
important (and potentially error prone). Instead, allowing on-disk +
internal types to be represented densely is much more useful.

And it avoids setting an upper bound on future types prematurely.

---

This also includes a minor rcompat/wcompat rework. Since we're probably
going to end up with 32-bit rcompat flags anyways, might as well make
them more human-readable (nibble-aligned):

  LFS_RCOMPAT_NONSTANDARD  0x00000001  Non-standard filesystem format
  LFS_RCOMPAT_WRONLY       0x00000002  Reading is disallowed
  LFS_RCOMPAT_BMOSS        0x00000010  Files may use inlined data
  LFS_RCOMPAT_BSPROUT      0x00000020  Files may use block pointers
  LFS_RCOMPAT_BSHRUB       0x00000040  Files may use inlined btrees
  LFS_RCOMPAT_BTREE        0x00000080  Files may use btrees
  LFS_RCOMPAT_MMOSS        0x00000100  May use an inlined mdir
  LFS_RCOMPAT_MSPROUT      0x00000200  May use an mdir pointer
  LFS_RCOMPAT_MSHRUB       0x00000400  May use an inlined mtree
  LFS_RCOMPAT_MTREE        0x00000800  May use an mdir btree
  LFS_RCOMPAT_GRM          0x00001000  Global-remove in use

  LFS_WCOMPAT_NONSTANDARD  0x00000001  Non-standard filesystem format
  LFS_WCOMPAT_RDONLY       0x00000002  Writing is disallowed
  LFS_WCOMPAT_REG          0x00000010  Regular file types in use
  LFS_WCOMPAT_DIR          0x00000020  Directory file types in use
  LFS_WCOMPAT_STICKYNOTE   0x00000040  Stickynote file types in use
  LFS_WCOMPAT_GCKSUM       0x00001000  Global-checksum in use

---

Code changes:

           code          stack          ctx
  before: 35928           2440          640
  after:  35924 (-0.0%)   2440 (+0.0%)  640 (+0.0%)
This commit is contained in:
Christopher Haster
2025-04-24 02:09:28 -05:00
parent 7dd473df82
commit 09c3749d7a
5 changed files with 252 additions and 679 deletions
+69 -67
View File
@@ -1116,6 +1116,10 @@ enum lfsr_tag {
LFSR_TAG_STICKYNOTE = 0x0203,
LFSR_TAG_BOOKMARK = 0x0204,
// in-device only name tags, these should never get written to disk
LFSR_TAG_TRAVERSAL = 0x0205,
LFSR_TAG_UNKNOWN = 0x0206,
// struct tags
LFSR_TAG_STRUCT = 0x0300,
LFSR_TAG_DATA = 0x0300,
@@ -7088,7 +7092,8 @@ static void lfsr_omdir_close(lfs_t *lfs, lfsr_omdir_t *o) {
}
// check if a given mid is open
static bool lfsr_omdir_ismidopen(lfs_t *lfs, lfsr_smid_t mid, uint32_t mask) {
static bool lfsr_omdir_ismidopen(const lfs_t *lfs,
lfsr_smid_t mid, uint32_t mask) {
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
// we really only care about regular open files here, all
// others are either transient (dirs) or fake (orphans)
@@ -7112,7 +7117,7 @@ static void lfsr_traversal_clobber(lfs_t *lfs, lfsr_traversal_t *t);
static void lfsr_omdir_clobber(lfs_t *lfs, const lfsr_omdir_t *o,
bool dirty) {
for (lfsr_omdir_t *o_ = lfs->omdirs; o_; o_ = o_->next) {
if (lfsr_o_type(o_->flags) == LFS_TYPE_TRAVERSAL) {
if (lfsr_o_type(o_->flags) == LFS_type_TRAVERSAL) {
o_->flags |= (dirty) ? LFS_t_DIRTY : 0;
if (o && ((lfsr_traversal_t*)o_)->ot == o) {
@@ -7518,6 +7523,30 @@ static int lfsr_data_fetchmdir(lfs_t *lfs,
return lfsr_mdir_fetch(lfs, mdir, mid, mdir->rbyd.blocks);
}
static lfsr_tag_t lfsr_mdir_nametag(const lfs_t *lfs, const lfsr_mdir_t *mdir,
lfsr_smid_t mid, lfsr_tag_t tag) {
(void)mdir;
// intercept pending grms here and pretend they're orphaned
// stickynotes
//
// fortunately pending grms/orphaned stickynotes have roughly the
// same semantics, and it's easier to manage the implied mid gap in
// higher-levels
if (lfsr_grm_ismidrm(lfs, mid)) {
return LFSR_TAG_STICKYNOTE;
// map unknown types -> LFSR_TAG_UNKNOWN, this simplifies higher
// levels and prevents collisions with internal types
//
// Note future types should probably come with WCOMPAT flags, and be
// at least reported on non-supporting filesystems
} else if (tag < LFSR_TAG_REG || tag > LFSR_TAG_BOOKMARK) {
return LFSR_TAG_UNKNOWN;
}
return tag;
}
static int lfsr_mdir_lookupnext(lfs_t *lfs, const lfsr_mdir_t *mdir,
lfsr_tag_t tag,
lfsr_tag_t *tag_, lfsr_data_t *data_) {
@@ -7536,15 +7565,9 @@ static int lfsr_mdir_lookupnext(lfs_t *lfs, const lfsr_mdir_t *mdir,
return LFS_ERR_NOENT;
}
// intercept pending grms here and pretend they're orphaned
// stickynotes
//
// fortunately pending grms/orphaned stickynotes have roughly the
// same semantics, and it's easier to manage the implied mid gap in
// higher-levels
if (lfsr_tag_suptype(tag__) == LFSR_TAG_NAME
&& lfsr_grm_ismidrm(lfs, mdir->mid)) {
tag__ = LFSR_TAG_STICKYNOTE;
// map name tags to understood types
if (lfsr_tag_suptype(tag__) == LFSR_TAG_NAME) {
tag__ = lfsr_mdir_nametag(lfs, mdir, mdir->mid, tag__);
}
if (tag_) {
@@ -8980,7 +9003,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
if (lfsr_mdir_cmp(&mroot_, &lfs->mroot) != 0
|| lfsr_btree_cmp(&mtree_, &lfs->mtree) != 0) {
for (lfsr_omdir_t *o = lfs->omdirs; o; o = o->next) {
if (lfsr_o_type(o->flags) == LFS_TYPE_TRAVERSAL
if (lfsr_o_type(o->flags) == LFS_type_TRAVERSAL
&& o->mdir.mid == -1
// don't clobber the current mdir, assume upper layers
// know what they're doing
@@ -9109,15 +9132,8 @@ static int lfsr_mdir_namelookup(lfs_t *lfs, const lfsr_mdir_t *mdir,
mdir->mid,
(cmp < LFS_CMP_EQ) ? rid+1 : rid);
// intercept pending grms here and pretend they're orphaned
// stickynotes
//
// fortunately pending grms/orphaned stickynotes have roughly the
// same semantics, and it's easier to manage the implied mid gap in
// higher-levels
if (lfsr_grm_ismidrm(lfs, mid)) {
tag = LFSR_TAG_STICKYNOTE;
}
// map name tags to understood types
tag = lfsr_mdir_nametag(lfs, mdir, mid, tag);
if (mid_) {
*mid_ = mid;
@@ -9231,7 +9247,6 @@ static inline bool lfsr_path_isdir(const char *path) {
// - LFS_ERR_NOENT, lfsr_path_islast(path) => file not found
// - LFS_ERR_NOENT, !lfsr_path_islast(path) => parent not found
// - LFS_ERR_NOTDIR => parent not a dir
// - LFS_ERR_NOTSUP => parent of unknown type
//
// if not found, mdir_/did_ will at least be set up with what should be
// the parent
@@ -9315,9 +9330,7 @@ static int lfsr_mtree_pathlookup(lfs_t *lfs, const char **path,
&& !lfsr_omdir_ismidopen(lfs, mdir.mid,
~(LFS_o_ZOMBIE | LFS_O_DESYNC)))
? LFS_ERR_NOENT
: (tag == LFSR_TAG_REG || tag == LFSR_TAG_STICKYNOTE)
? LFS_ERR_NOTDIR
: LFS_ERR_NOTSUP;
: LFS_ERR_NOTDIR;
}
// read the next did from the mdir if this is not the root
@@ -9384,7 +9397,7 @@ enum {
};
static void lfsr_traversal_init(lfsr_traversal_t *t, uint32_t flags) {
t->b.o.flags = lfsr_o_settype(0, LFS_TYPE_TRAVERSAL)
t->b.o.flags = lfsr_o_settype(0, LFS_type_TRAVERSAL)
| lfsr_t_settstate(0, LFSR_TSTATE_MROOTANCHOR)
| flags;
t->b.o.mdir.mid = -1;
@@ -10417,12 +10430,6 @@ int lfsr_remove(lfs_t *lfs, const char *path) {
~(LFS_o_ZOMBIE | LFS_O_DESYNC))) {
return LFS_ERR_NOENT;
}
// we can't remove unknown types or else we may leak resources
if (tag != LFSR_TAG_REG
&& tag != LFSR_TAG_DIR
&& tag != LFSR_TAG_STICKYNOTE) {
return LFS_ERR_NOTSUP;
}
// trying to remove the root dir?
if (mdir.mid == -1) {
@@ -10501,7 +10508,7 @@ int lfsr_remove(lfs_t *lfs, const char *path) {
}
// clobber entangled traversals
} else if (lfsr_o_type(o->flags) == LFS_TYPE_TRAVERSAL) {
} else if (lfsr_o_type(o->flags) == LFS_type_TRAVERSAL) {
if (lfsr_o_iszombie(o->flags)) {
o->flags &= ~LFS_o_ZOMBIE;
o->mdir.mid -= 1;
@@ -10545,12 +10552,6 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
~(LFS_o_ZOMBIE | LFS_O_DESYNC))) {
return LFS_ERR_NOENT;
}
// we can't rename unknown types or else we may leak resources
if (old_tag != LFSR_TAG_REG
&& old_tag != LFSR_TAG_DIR
&& old_tag != LFSR_TAG_STICKYNOTE) {
return LFS_ERR_NOTSUP;
}
// trying to rename the root?
if (old_mdir.mid == -1) {
@@ -10603,12 +10604,6 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
~(LFS_o_ZOMBIE | LFS_O_DESYNC)))) {
return LFS_ERR_NOTDIR;
}
// we can't rename unknown types or else we may leak resources
if (new_tag != LFSR_TAG_REG
&& new_tag != LFSR_TAG_DIR
&& new_tag != LFSR_TAG_STICKYNOTE) {
return LFS_ERR_NOTSUP;
}
// renaming to ourself is a noop
if (old_mdir.mid == new_mdir.mid) {
@@ -10695,7 +10690,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
}
// clobber entangled traversals
} else if (lfsr_o_type(o->flags) == LFS_TYPE_TRAVERSAL
} else if (lfsr_o_type(o->flags) == LFS_type_TRAVERSAL
&& ((exists && o->mdir.mid == new_mdir.mid)
|| o->mdir.mid == lfs->grm.mids[0])) {
lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o);
@@ -11424,10 +11419,11 @@ int lfsr_file_opencfg(lfs_t *lfs, lfsr_file_t *file,
}
// wrong type?
if (tag != LFSR_TAG_REG && tag != LFSR_TAG_STICKYNOTE) {
return (tag == LFSR_TAG_DIR)
? LFS_ERR_ISDIR
: LFS_ERR_NOTSUP;
if (tag == LFSR_TAG_DIR) {
return LFS_ERR_ISDIR;
}
if (tag == LFSR_TAG_UNKNOWN) {
return LFS_ERR_NOTSUP;
}
}
@@ -12920,7 +12916,7 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
}
// clobber entangled traversals
} else if (lfsr_o_type(o->flags) == LFS_TYPE_TRAVERSAL
} else if (lfsr_o_type(o->flags) == LFS_type_TRAVERSAL
&& o->mdir.mid == file->b.o.mdir.mid) {
lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o);
}
@@ -13579,39 +13575,45 @@ static int lfs_deinit(lfs_t *lfs) {
//
// - RCOMPAT => Must understand to read the filesystem
// - WCOMPAT => Must understand to write to the filesystem
// - OCOMPAT => Don't need to understand, we don't really use these
// - OCOMPAT => No understanding necessary, we don't really use these
//
// note, "understanding" does not necessarily mean support
//
#define LFSR_RCOMPAT_NONSTANDARD 0x00000001 // Non-standard filesystem format
#define LFSR_RCOMPAT_WRONLY 0x00000002 // Reading is disallowed
#define LFSR_RCOMPAT_GRM 0x00000004 // Global-remove in use
#define LFSR_RCOMPAT_MMOSS 0x00000010 // May use an inlined mdir
#define LFSR_RCOMPAT_MSPROUT 0x00000020 // May use an mdir pointer
#define LFSR_RCOMPAT_MSHRUB 0x00000040 // May use an inlined mtree
#define LFSR_RCOMPAT_MTREE 0x00000080 // May use an mtree
#define LFSR_RCOMPAT_BMOSS 0x00000100 // Files may use inlined data
#define LFSR_RCOMPAT_BSPROUT 0x00000200 // Files may use block pointers
#define LFSR_RCOMPAT_BSHRUB 0x00000400 // Files may use inlined btrees
#define LFSR_RCOMPAT_BTREE 0x00000800 // Files may use btrees
#define LFSR_RCOMPAT_BMOSS 0x00000010 // Files may use inlined data
#define LFSR_RCOMPAT_BSPROUT 0x00000020 // Files may use block pointers
#define LFSR_RCOMPAT_BSHRUB 0x00000040 // Files may use inlined btrees
#define LFSR_RCOMPAT_BTREE 0x00000080 // Files may use btrees
#define LFSR_RCOMPAT_MMOSS 0x00000100 // May use an inlined mdir
#define LFSR_RCOMPAT_MSPROUT 0x00000200 // May use an mdir pointer
#define LFSR_RCOMPAT_MSHRUB 0x00000400 // May use an inlined mtree
#define LFSR_RCOMPAT_MTREE 0x00000800 // May use an mtree
#define LFSR_RCOMPAT_GRM 0x00001000 // Global-remove in use
// internal
#define LFSR_rcompat_OVERFLOW 0x80000000 // Can't represent all flags
#define LFSR_RCOMPAT_COMPAT \
(LFSR_RCOMPAT_GRM \
(LFSR_RCOMPAT_BSHRUB \
| LFSR_RCOMPAT_BTREE \
| LFSR_RCOMPAT_MMOSS \
| LFSR_RCOMPAT_MTREE \
| LFSR_RCOMPAT_BSHRUB \
| LFSR_RCOMPAT_BTREE)
| LFSR_RCOMPAT_GRM)
#define LFSR_WCOMPAT_NONSTANDARD 0x00000001 // Non-standard filesystem format
#define LFSR_WCOMPAT_RDONLY 0x00000002 // Writing is disallowed
#define LFSR_WCOMPAT_GCKSUM 0x00000004 // Global-checksum in use
#define LFSR_WCOMPAT_REG 0x00000010 // Regular files in use
#define LFSR_WCOMPAT_DIR 0x00000020 // Directory files in use
#define LFSR_WCOMPAT_STICKYNOTE 0x00000040 // Stickynote files in use
#define LFSR_WCOMPAT_GCKSUM 0x00001000 // Global-checksum in use
// internal
#define LFSR_wcompat_OVERFLOW 0x80000000 // Can't represent all flags
#define LFSR_WCOMPAT_COMPAT \
(LFSR_WCOMPAT_GCKSUM)
(LFSR_WCOMPAT_REG \
| LFSR_WCOMPAT_DIR \
| LFSR_WCOMPAT_STICKYNOTE \
| LFSR_WCOMPAT_GCKSUM)
#define LFSR_OCOMPAT_NONSTANDARD 0x00000001 // Non-standard filesystem format
// internal
@@ -14886,7 +14888,7 @@ int lfsr_traversal_open(lfs_t *lfs, lfsr_traversal_t *t, uint32_t flags) {
LFS_ASSERT(!lfsr_t_ismtreeonly(flags) || !lfsr_t_isckdata(flags));
// setup traversal state
t->b.o.flags = lfsr_o_settype(flags, LFS_TYPE_TRAVERSAL);
t->b.o.flags = lfsr_o_settype(flags, LFS_type_TRAVERSAL);
// let rewind initialize/reset things
int err = lfsr_traversal_rewind_(lfs, t);
+11 -5
View File
@@ -109,15 +109,21 @@ enum lfs_error {
};
// File types
//
// LFS_TYPE_UNKNOWN will always be the largest, including internal
// types, and can be used to deliminate user defined types at higher
// levels
//
enum lfs_type {
// file types
LFS_TYPE_REG = 1,
LFS_TYPE_DIR = 2,
LFS_TYPE_STICKYNOTE = 3,
LFS_TYPE_REG = 1, // A regular file
LFS_TYPE_DIR = 2, // A directory file
LFS_TYPE_STICKYNOTE = 3, // An uncommitted file
LFS_TYPE_UNKNOWN = 6, // Unknown file type
// internally used types, don't use these
LFS_TYPE_BOOKMARK = 4,
LFS_TYPE_TRAVERSAL = 9,
LFS_type_BOOKMARK = 4, // Directory bookmark
LFS_type_TRAVERSAL = 5, // An open traversal object
};
// File open flags
+25 -17
View File
@@ -41,7 +41,8 @@ FLAGS = [
('^', 'DIR', 0x20000000, "Type = directory" ),
('^', 'STICKYNOTE',0x30000000, "Type = stickynote" ),
('^', 'BOOKMARK', 0x40000000, "Type = bookmark" ),
('^', 'TRAVERSAL', 0x90000000, "Type = traversal" ),
('^', 'TRAVERSAL', 0x50000000, "Type = traversal" ),
('^', 'UNKNOWN', 0x60000000, "Type = unknown" ),
('o', 'UNFLUSH', 0x01000000, "File's data does not match disk" ),
('o', 'UNSYNC', 0x02000000, "File's metadata does not match disk" ),
('o', 'UNCREAT', 0x04000000, "File does not exist yet" ),
@@ -132,7 +133,8 @@ FLAGS = [
('^', 'DIR', 0x20000000, "Type = directory" ),
('^', 'STICKYNOTE',0x30000000, "Type = stickynote" ),
('^', 'BOOKMARK', 0x40000000, "Type = bookmark" ),
('^', 'TRAVERSAL', 0x90000000, "Type = traversal" ),
('^', 'TRAVERSAL', 0x50000000, "Type = traversal" ),
('^', 'UNKNOWN', 0x60000000, "Type = unknown" ),
('t', 'TSTATE', 0x0000000f, "The traversal's current tstate" ),
('^', 'MROOTANCHOR',
0x00000000, "Tstate = mroot-anchor" ),
@@ -157,24 +159,24 @@ FLAGS = [
0x00000001, "Non-standard filesystem format" ),
('RCOMPAT', 'WRONLY',
0x00000002, "Reading is disallowed" ),
('RCOMPAT', 'GRM',
0x00000004, "Global-remove in use" ),
('RCOMPAT', 'MMOSS',
0x00000010, "May use an inlined mdir" ),
('RCOMPAT', 'MSPROUT',
0x00000020, "May use an mdir pointer" ),
('RCOMPAT', 'MSHRUB',
0x00000040, "May use an inlined mtree" ),
('RCOMPAT', 'MTREE',
0x00000080, "May use an mdir btree" ),
('RCOMPAT', 'BMOSS',
0x00000100, "Files may use inlined data" ),
0x00000010, "Files may use inlined data" ),
('RCOMPAT', 'BSPROUT',
0x00000200, "Files may use block pointers" ),
0x00000020, "Files may use block pointers" ),
('RCOMPAT', 'BSHRUB',
0x00000400, "Files may use inlined btrees" ),
0x00000040, "Files may use inlined btrees" ),
('RCOMPAT', 'BTREE',
0x00000800, "Files may use btrees" ),
0x00000080, "Files may use btrees" ),
('RCOMPAT', 'MMOSS',
0x00000100, "May use an inlined mdir" ),
('RCOMPAT', 'MSPROUT',
0x00000200, "May use an mdir pointer" ),
('RCOMPAT', 'MSHRUB',
0x00000400, "May use an inlined mtree" ),
('RCOMPAT', 'MTREE',
0x00000800, "May use an mdir btree" ),
('RCOMPAT', 'GRM',
0x00001000, "Global-remove in use" ),
('rcompat', 'OVERFLOW',
0x80000000, "Can't represent all flags" ),
@@ -183,8 +185,14 @@ FLAGS = [
0x00000001, "Non-standard filesystem format" ),
('WCOMPAT', 'RDONLY',
0x00000002, "Writing is disallowed" ),
('WCOMPAT', 'REG',
0x00000010, "Regular file types in use" ),
('WCOMPAT', 'DIR',
0x00000020, "Directory file types in use" ),
('WCOMPAT', 'STICKYNOTE',
0x00000040, "Stickynote file types in use" ),
('WCOMPAT', 'GCKSUM',
0x00000004, "Global-checksum in use" ),
0x00001000, "Global-checksum in use" ),
('wcompat', 'OVERFLOW',
0x80000000, "Can't represent all flags" ),
+5 -15
View File
@@ -1146,14 +1146,15 @@ code = '''
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
lfsr_unmount(&lfs) => 0;
// mount
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
// mount, note the LFS_M_RDONLY, new types should be added with
// new wcompat flags to prevent resource leaks
lfsr_mount(&lfs, LFS_M_RDONLY, CFG) => 0;
// our file should appear as an unknown type
struct lfs_info info;
lfsr_stat(&lfs, "b", &info) => 0;
assert(strcmp(info.name, "b") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
assert(info.size == 0);
lfsr_dir_t dir;
@@ -1172,7 +1173,7 @@ code = '''
assert(info.size == strlen("hi a!"));
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "b") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
assert(info.size == 0);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "c") == 0);
@@ -1181,19 +1182,8 @@ code = '''
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// removing/renaming unknown files should return NOTSUP, we could
// remove the metadata entry, but we would probably leak stuff
lfsr_remove(&lfs, "b") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs, "b", "d") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs, "b", "c") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs, "a", "b") => LFS_ERR_NOTSUP;
lfsr_file_open(&lfs, &file, "b",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
lfsr_file_open(&lfs, &file, "b",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
lfsr_mkdir(&lfs, "b") => LFS_ERR_EXIST;
lfsr_unmount(&lfs) => 0;
'''
+142 -575
View File
@@ -4615,22 +4615,22 @@ code = '''
struct lfs_info info;
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
assert(strcmp(info.name, "drip") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/coldbrew", &info) => 0;
assert(strcmp(info.name, "coldbrew") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/turkish", &info) => 0;
assert(strcmp(info.name, "turkish") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/tubruk", &info) => 0;
assert(strcmp(info.name, "tubruk") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/vietnamese", &info) => 0;
assert(strcmp(info.name, "vietnamese") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/thai", &info) => 0;
assert(strcmp(info.name, "thai") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
// file open paths, only works on files!
lfsr_file_t file;
@@ -4656,81 +4656,28 @@ code = '''
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/thai") => LFS_ERR_NOTDIR;
// rename paths
lfsr_mkdir(&lfs, "espresso") => 0;
lfsr_rename(&lfs,
"coffee/drip",
"espresso/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew",
"espresso/americano") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish",
"espresso/macchiato") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk",
"espresso/latte") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese",
"espresso/cappuccino") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai",
"espresso/mocha") => LFS_ERR_NOTSUP;
// here's a weird one, what happens if our rename is also a noop?
lfsr_rename(&lfs,
"coffee/drip",
"coffee/drip") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew",
"coffee/coldbrew") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish",
"coffee/turkish") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk",
"coffee/tubruk") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese",
"coffee/vietnamese") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai",
"coffee/thai") => LFS_ERR_NOTSUP;
// remove paths
lfsr_remove(&lfs, "coffee/drip") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/coldbrew") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/turkish") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/tubruk") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/vietnamese") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/thai") => LFS_ERR_NOTSUP;
// note write operations should normally be rejected during mount
// by wcompat flags
// stat paths
lfsr_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
assert(strcmp(info.name, "drip") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/coldbrew", &info) => 0;
assert(strcmp(info.name, "coldbrew") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/turkish", &info) => 0;
assert(strcmp(info.name, "turkish") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/tubruk", &info) => 0;
assert(strcmp(info.name, "tubruk") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/vietnamese", &info) => 0;
assert(strcmp(info.name, "vietnamese") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/thai", &info) => 0;
assert(strcmp(info.name, "thai") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_unmount(&lfs) => 0;
'''
@@ -4798,86 +4745,86 @@ code = '''
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
if (DIR) {
lfsr_mkdir(&lfs, "drip/coffee") => LFS_ERR_NOTSUP;
lfsr_mkdir(&lfs, "coldbrew/coffee") => LFS_ERR_NOTSUP;
lfsr_mkdir(&lfs, "turkish/coffee") => LFS_ERR_NOTSUP;
lfsr_mkdir(&lfs, "tubruk/coffee") => LFS_ERR_NOTSUP;
lfsr_mkdir(&lfs, "vietnamese/coffee") => LFS_ERR_NOTSUP;
lfsr_mkdir(&lfs, "thai/coffee") => LFS_ERR_NOTSUP;
lfsr_mkdir(&lfs, "drip/coffee") => LFS_ERR_NOTDIR;
lfsr_mkdir(&lfs, "coldbrew/coffee") => LFS_ERR_NOTDIR;
lfsr_mkdir(&lfs, "turkish/coffee") => LFS_ERR_NOTDIR;
lfsr_mkdir(&lfs, "tubruk/coffee") => LFS_ERR_NOTDIR;
lfsr_mkdir(&lfs, "vietnamese/coffee") => LFS_ERR_NOTDIR;
lfsr_mkdir(&lfs, "thai/coffee") => LFS_ERR_NOTDIR;
} else {
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "drip/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coldbrew/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "turkish/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "tubruk/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "vietnamese/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "thai/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
}
// stat paths
struct lfs_info info;
lfsr_stat(&lfs, "drip/coffee", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coldbrew/coffee", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "turkish/coffee", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "tubruk/coffee", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "vietnamese/coffee", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "thai/coffee", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "drip/coffee", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coldbrew/coffee", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "turkish/coffee", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "tubruk/coffee", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "vietnamese/coffee", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "thai/coffee", &info) => LFS_ERR_NOTDIR;
// file open paths, only works on files!
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "drip/coffee",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coldbrew/coffee",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "turkish/coffee",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "tubruk/coffee",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "vietnamese/coffee",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "thai/coffee",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "drip/coffee",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coldbrew/coffee",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "turkish/coffee",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "tubruk/coffee",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "vietnamese/coffee",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "thai/coffee",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "drip/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coldbrew/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "turkish/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "tubruk/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "vietnamese/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "thai/coffee",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
// dir open paths, only works on dirs!
lfsr_dir_t dir;
lfsr_dir_open(&lfs, &dir, "drip/coffee") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coldbrew/coffee") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "turkish/coffee") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "tubruk/coffee") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "vietnamese/coffee") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "thai/coffee") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "drip/coffee") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coldbrew/coffee") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "turkish/coffee") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "tubruk/coffee") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "vietnamese/coffee") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "thai/coffee") => LFS_ERR_NOTDIR;
// make some normal paths so we have something to rename
lfsr_mkdir(&lfs, "coffee") => 0;
@@ -4910,104 +4857,10 @@ code = '''
lfsr_file_close(&lfs, &file) => 0;
}
// rename paths
lfsr_mkdir(&lfs, "espresso") => 0;
// bad source
lfsr_rename(&lfs,
"drip/coffee",
"espresso/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coldbrew/coffee",
"espresso/americano") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"turkish/coffee",
"espresso/macchiato") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"tubruk/coffee",
"espresso/latte") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"vietnamese/coffee",
"espresso/cappuccino") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"thai/coffee",
"espresso/mocha") => LFS_ERR_NOTSUP;
// bad destination
lfsr_rename(&lfs,
"coffee/drip",
"drip/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew",
"coldbrew/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish",
"turkish/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk",
"tubruk/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese",
"vietnamese/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai",
"thai/espresso") => LFS_ERR_NOTSUP;
// bad source and bad destination
lfsr_rename(&lfs,
"drip/coffee",
"drip/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coldbrew/coffee",
"coldbrew/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"turkish/coffee",
"turkish/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"tubruk/coffee",
"tubruk/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"vietnamese/coffee",
"vietnamese/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"thai/coffee",
"thai/espresso") => LFS_ERR_NOTSUP;
// here's a weird one, what happens if our rename is also a noop?
lfsr_rename(&lfs,
"drip/coffee",
"drip/coffee") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coldbrew/coffee",
"coldbrew/coffee") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"turkish/coffee",
"turkish/coffee") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"tubruk/coffee",
"tubruk/coffee") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"vietnamese/coffee",
"vietnamese/coffee") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"thai/coffee",
"thai/coffee") => LFS_ERR_NOTSUP;
// remove paths
lfsr_stat(&lfs, "drip/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coldbrew/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "turkish/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "tubruk/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "vietnamese/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "thai/espresso", &info) => LFS_ERR_NOTSUP;
// note write operations should normally be rejected during mount
// by wcompat flags
// stat paths
lfsr_stat(&lfs, "drip/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coldbrew/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "turkish/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "tubruk/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "vietnamese/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "thai/espresso", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
assert(strcmp(info.name, "drip") == 0);
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
@@ -5095,179 +4948,85 @@ code = '''
// stat paths
struct lfs_info info;
lfsr_stat(&lfs, "coffee/drip//////", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/coldbrew/////", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/turkish////", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/tubruk///", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/vietnamese//", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/thai/", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/drip//////", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coffee/coldbrew/////", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coffee/turkish////", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coffee/tubruk///", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coffee/vietnamese//", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coffee/thai/", &info) => LFS_ERR_NOTDIR;
// file open paths, only works on files!
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "coffee/drip/",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/coldbrew//",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/turkish///",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/tubruk////",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/vietnamese/////",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/thai//////",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/drip/",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/coldbrew//",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/turkish///",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/tubruk////",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/vietnamese/////",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/thai//////",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/drip/",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/coldbrew//",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/turkish///",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/tubruk////",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/vietnamese/////",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/thai//////",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
// dir open paths, only works on dirs!
lfsr_dir_t dir;
lfsr_dir_open(&lfs, &dir, "coffee/drip/") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/coldbrew//") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/turkish///") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/tubruk////") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/////") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/thai//////") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/drip/") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/coldbrew//") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/turkish///") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/tubruk////") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/////") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/thai//////") => LFS_ERR_NOTDIR;
// rename paths
lfsr_mkdir(&lfs, "espresso") => 0;
// bad source
lfsr_rename(&lfs,
"coffee/drip//////",
"espresso/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew/////",
"espresso/americano") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish////",
"espresso/macchiato") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk///",
"espresso/latte") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese//",
"espresso/cappuccino") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai/",
"espresso/mocha") => LFS_ERR_NOTSUP;
// bad destination
lfsr_rename(&lfs,
"coffee/drip",
"espresso/espresso/") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew",
"espresso/americano//") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish",
"espresso/macchiato///") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk",
"espresso/latte////") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese",
"espresso/cappuccino/////") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai",
"espresso/mocha//////") => LFS_ERR_NOTSUP;
// bad source and bad destination
lfsr_rename(&lfs,
"coffee/drip//////",
"espresso/espresso/") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew/////",
"espresso/americano//") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish////",
"espresso/macchiato///") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk///",
"espresso/latte////") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese//",
"espresso/cappuccino/////") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai/",
"espresso/mocha//////") => LFS_ERR_NOTSUP;
// here's a weird one, what happens if our rename is also a noop?
lfsr_rename(&lfs,
"coffee/drip//////",
"coffee/drip//////") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew/////",
"coffee/coldbrew/////") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish////",
"coffee/turkish////") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk///",
"coffee/tubruk///") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese//",
"coffee/vietnamese//") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai/",
"coffee/thai/") => LFS_ERR_NOTSUP;
// remove paths
lfsr_remove(&lfs, "coffee/drip/") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/coldbrew//") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/turkish///") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/tubruk////") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/vietnamese/////") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/thai//////") => LFS_ERR_NOTSUP;
// note write operations should normally be rejected during mount
// by wcompat flags
// stat paths
lfsr_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
assert(strcmp(info.name, "drip") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/coldbrew", &info) => 0;
assert(strcmp(info.name, "coldbrew") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/turkish", &info) => 0;
assert(strcmp(info.name, "turkish") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/tubruk", &info) => 0;
assert(strcmp(info.name, "tubruk") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/vietnamese", &info) => 0;
assert(strcmp(info.name, "vietnamese") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/thai", &info) => 0;
assert(strcmp(info.name, "thai") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_unmount(&lfs) => 0;
'''
@@ -5337,179 +5096,85 @@ code = '''
// stat paths
struct lfs_info info;
lfsr_stat(&lfs, "coffee/drip/./././././.", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/coldbrew/././././.", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/turkish/./././.", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/tubruk/././.", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/vietnamese/./.", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/thai/.", &info) => LFS_ERR_NOTSUP;
lfsr_stat(&lfs, "coffee/drip/./././././.", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coffee/coldbrew/././././.", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coffee/turkish/./././.", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coffee/tubruk/././.", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coffee/vietnamese/./.", &info) => LFS_ERR_NOTDIR;
lfsr_stat(&lfs, "coffee/thai/.", &info) => LFS_ERR_NOTDIR;
// file open paths, only works on files!
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "coffee/drip/.",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/coldbrew/./.",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/turkish/././.",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/tubruk/./././.",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/vietnamese/././././.",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/thai/./././././.",
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/drip/.",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/coldbrew/./.",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/turkish/././.",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/tubruk/./././.",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/vietnamese/././././.",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/thai/./././././.",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/drip/.",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/coldbrew/./.",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/turkish/././.",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/tubruk/./././.",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/vietnamese/././././.",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
lfsr_file_open(&lfs, &file, "coffee/thai/./././././.",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTSUP;
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_NOTDIR;
// dir open paths, only works on dirs!
lfsr_dir_t dir;
lfsr_dir_open(&lfs, &dir, "coffee/drip/.") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/coldbrew/./.") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/turkish/././.") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/tubruk/./././.") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/././././.") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/thai/./././././.") => LFS_ERR_NOTSUP;
lfsr_dir_open(&lfs, &dir, "coffee/drip/.") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/coldbrew/./.") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/turkish/././.") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/tubruk/./././.") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/././././.") => LFS_ERR_NOTDIR;
lfsr_dir_open(&lfs, &dir, "coffee/thai/./././././.") => LFS_ERR_NOTDIR;
// rename paths
lfsr_mkdir(&lfs, "espresso") => 0;
// bad source
lfsr_rename(&lfs,
"coffee/drip/./././././.",
"espresso/espresso") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew/././././.",
"espresso/americano") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish/./././.",
"espresso/macchiato") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk/././.",
"espresso/latte") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese/./.",
"espresso/cappuccino") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai/.",
"espresso/mocha") => LFS_ERR_NOTSUP;
// bad destination
lfsr_rename(&lfs,
"coffee/drip",
"espresso/espresso/.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew",
"espresso/americano/./.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish",
"espresso/macchiato/././.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk",
"espresso/latte/./././.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese",
"espresso/cappuccino/././././.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai",
"espresso/mocha/./././././.") => LFS_ERR_NOTSUP;
// bad source and bad destination
lfsr_rename(&lfs,
"coffee/drip/./././././.",
"espresso/espresso/.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew/././././.",
"espresso/americano/./.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish/./././.",
"espresso/macchiato/././.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk/././.",
"espresso/latte/./././.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese/./.",
"espresso/cappuccino/././././.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai/.",
"espresso/mocha/./././././.") => LFS_ERR_NOTSUP;
// here's a weird one, what happens if our rename is also a noop?
lfsr_rename(&lfs,
"coffee/drip/./././././.",
"coffee/drip/./././././.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew/././././.",
"coffee/coldbrew/././././.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish/./././.",
"coffee/turkish/./././.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk/././.",
"coffee/tubruk/././.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese/./.",
"coffee/vietnamese/./.") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai/.",
"coffee/thai/.") => LFS_ERR_NOTSUP;
// remove paths
lfsr_remove(&lfs, "coffee/drip/.") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/coldbrew/./.") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/turkish/././.") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/tubruk/./././.") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/vietnamese/././././.") => LFS_ERR_NOTSUP;
lfsr_remove(&lfs, "coffee/thai/./././././.") => LFS_ERR_NOTSUP;
// note write operations should normally be rejected during mount
// by wcompat flags
// stat paths
lfsr_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
assert(strcmp(info.name, "drip") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/coldbrew", &info) => 0;
assert(strcmp(info.name, "coldbrew") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/turkish", &info) => 0;
assert(strcmp(info.name, "turkish") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/tubruk", &info) => 0;
assert(strcmp(info.name, "tubruk") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/vietnamese", &info) => 0;
assert(strcmp(info.name, "vietnamese") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/thai", &info) => 0;
assert(strcmp(info.name, "thai") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_unmount(&lfs) => 0;
'''
@@ -5616,126 +5281,28 @@ code = '''
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/../../../../..") => LFS_ERR_INVAL;
lfsr_dir_open(&lfs, &dir, "coffee/thai/../../../../../..") => LFS_ERR_INVAL;
// rename paths
lfsr_mkdir(&lfs, "espresso") => 0;
// bad source
lfsr_rename(&lfs,
"coffee/drip/../../../../../..",
"espresso/espresso") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/coldbrew/../../../../..",
"espresso/americano") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/turkish/../../../..",
"espresso/macchiato") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/tubruk/../../..",
"espresso/latte") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/vietnamese/../..",
"espresso/cappuccino") => LFS_ERR_INVAL;
// this one works
lfsr_rename(&lfs,
"coffee/thai/..",
"espresso/mocha") => 0;
lfsr_rename(&lfs,
"espresso/mocha",
"coffee") => 0;
// bad destination
lfsr_rename(&lfs,
"coffee/drip",
"espresso/espresso/..") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/coldbrew",
"espresso/americano/../..") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/turkish",
"espresso/macchiato/../../..") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/tubruk",
"espresso/latte/../../../..") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/vietnamese",
"espresso/cappuccino/../../../../..") => LFS_ERR_NOTSUP;
lfsr_rename(&lfs,
"coffee/thai",
"espresso/mocha/../../../../../..") => LFS_ERR_NOTSUP;
// bad source and bad destination
lfsr_rename(&lfs,
"coffee/drip/../../../../../..",
"espresso/espresso/..") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/coldbrew/../../../../..",
"espresso/americano/../..") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/turkish/../../../..",
"espresso/macchiato/../../..") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/tubruk/../../..",
"espresso/latte/../../../..") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/vietnamese/../..",
"espresso/cappuccino/../../../../..") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/thai/..",
"espresso/mocha/../../../../../..") => LFS_ERR_INVAL;
// here's a weird one, what happens if our rename is also a noop?
lfsr_rename(&lfs,
"coffee/drip/../../../../../..",
"coffee/drip/../../../../../..") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/coldbrew/../../../../..",
"coffee/coldbrew/../../../../..") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/turkish/../../../..",
"coffee/turkish/../../../..") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/tubruk/../../..",
"coffee/tubruk/../../..") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/vietnamese/../..",
"coffee/vietnamese/../..") => LFS_ERR_INVAL;
lfsr_rename(&lfs,
"coffee/thai/..",
"coffee/thai/..") => 0;
// remove paths
lfsr_remove(&lfs, "coffee/drip/..") => LFS_ERR_NOTEMPTY;
lfsr_remove(&lfs, "coffee/coldbrew/../..") => LFS_ERR_INVAL;
lfsr_remove(&lfs, "coffee/turkish/../../..") => LFS_ERR_INVAL;
lfsr_remove(&lfs, "coffee/tubruk/../../../..") => LFS_ERR_INVAL;
lfsr_remove(&lfs, "coffee/vietnamese/../../../../..") => LFS_ERR_INVAL;
lfsr_remove(&lfs, "coffee/thai/../../../../../..") => LFS_ERR_INVAL;
// note write operations should normally be rejected during mount
// by wcompat flags
// stat paths
lfsr_stat(&lfs, "espresso/espresso", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/americano", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/macchiato", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/latte", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/cappuccino", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "espresso/mocha", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
assert(strcmp(info.name, "drip") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/coldbrew", &info) => 0;
assert(strcmp(info.name, "coldbrew") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/turkish", &info) => 0;
assert(strcmp(info.name, "turkish") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/tubruk", &info) => 0;
assert(strcmp(info.name, "tubruk") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/vietnamese", &info) => 0;
assert(strcmp(info.name, "vietnamese") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_stat(&lfs, "coffee/thai", &info) => 0;
assert(strcmp(info.name, "thai") == 0);
assert(info.type == 0x13);
assert(info.type == LFS_TYPE_UNKNOWN);
lfsr_unmount(&lfs) => 0;
'''