Allowed modification of unknown file types
This drops the requirement that all file types are introduced with a
related wcompat flag. Instead, the wcompat flag is only required if
modification _would_ leak resources, and we treat unknown file types as
though they are regular files.
This allows modification of unknown file types without the risk of
breaking anything.
To compare with before the unknown-type rework:
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 allowed but must not leak resources if
> modified. If an unknown file type would leak resources, it should set
> a related wcompat flag to only allow mounting RDONLY.
Note this includes directories, which can leak bookmarks if removed, so
filesystems using directories should set the LFSR_WCOMPAT_DIR flag.
But we no longer need the LFSR_WCOMPAT_REG/LFSR_WCOMPAT_STICKYNOTE
flags.
---
The real tricky part was getting lfsr_rename to work with unknown types,
as this broke the invariant that we only ever commit tags we know about.
Fixing this required:
- Fetching the non-unknown-mapped tag in lfsr_rename
- Mapping all name tags to LFSR_TAG_NAME in lfsr_rbyd_appendrattr_
- Adopting LFSR_RATTR_NAME for bookmark name tags
This was broken by the above lfsr_rbyd_appendrattr_ change, but it's
probably good to handle these the same as other name tags anyways.
This adds a bit of code, but not enough that I think this isn't worth
it (or worth a build-time option):
code stack ctx
before: 35924 2440 640
after: 35992 (+0.0%) 2440 (+0.0%) 640 (+0.0%)
This commit is contained in:
@@ -2331,7 +2331,12 @@ static inline lfsr_tag_t lfsr_rattr_dtag(lfsr_rattr_t rattr) {
|
|||||||
// lazily tag encoding can be bypassed with explicit data, this is
|
// lazily tag encoding can be bypassed with explicit data, this is
|
||||||
// necessary to allow copies during compaction, relocation, etc
|
// necessary to allow copies during compaction, relocation, etc
|
||||||
if (rattr.count >= 0) {
|
if (rattr.count >= 0) {
|
||||||
return rattr.tag;
|
// map all name tags to LFSR_TAG_NAME for simplicity
|
||||||
|
if (lfsr_tag_suptype(rattr.tag) == LFSR_TAG_NAME) {
|
||||||
|
return LFSR_TAG_NAME;
|
||||||
|
} else {
|
||||||
|
return rattr.tag;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return LFSR_TAG_DATA;
|
return LFSR_TAG_DATA;
|
||||||
}
|
}
|
||||||
@@ -3452,7 +3457,7 @@ static lfsr_data_t lfsr_data_frombtree(const lfsr_btree_t *btree,
|
|||||||
static lfsr_data_t lfsr_data_frommptr(const lfs_block_t mptr[static 2],
|
static lfsr_data_t lfsr_data_frommptr(const lfs_block_t mptr[static 2],
|
||||||
uint8_t buffer[static LFSR_MPTR_DSIZE]);
|
uint8_t buffer[static LFSR_MPTR_DSIZE]);
|
||||||
|
|
||||||
// our core rbyd append algorithm
|
// encode rattrs
|
||||||
static int lfsr_rbyd_appendrattr_(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
static int lfsr_rbyd_appendrattr_(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
||||||
lfsr_rattr_t rattr) {
|
lfsr_rattr_t rattr) {
|
||||||
// tag must not be internal at this point
|
// tag must not be internal at this point
|
||||||
@@ -3507,7 +3512,6 @@ static int lfsr_rbyd_appendrattr_(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
|||||||
// leb128?
|
// leb128?
|
||||||
case LFSR_TAG_NAMELIMIT:;
|
case LFSR_TAG_NAMELIMIT:;
|
||||||
case LFSR_TAG_FILELIMIT:;
|
case LFSR_TAG_FILELIMIT:;
|
||||||
case LFSR_TAG_BOOKMARK:;
|
|
||||||
case LFSR_TAG_DID:;
|
case LFSR_TAG_DID:;
|
||||||
// leb128s should not exceed 31-bits
|
// leb128s should not exceed 31-bits
|
||||||
LFS_ASSERT(rattr.u.leb128 <= 0x7fffffff);
|
LFS_ASSERT(rattr.u.leb128 <= 0x7fffffff);
|
||||||
@@ -3530,9 +3534,6 @@ static int lfsr_rbyd_appendrattr_(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
|||||||
|
|
||||||
// name?
|
// name?
|
||||||
case LFSR_TAG_NAME:;
|
case LFSR_TAG_NAME:;
|
||||||
case LFSR_TAG_REG:;
|
|
||||||
case LFSR_TAG_DIR:;
|
|
||||||
case LFSR_TAG_STICKYNOTE:;
|
|
||||||
const lfsr_name_t *name = rattr.u.etc;
|
const lfsr_name_t *name = rattr.u.etc;
|
||||||
ctx.u.name.datas[0] = lfsr_data_fromleb128(name->did, ctx.u.name.buf);
|
ctx.u.name.datas[0] = lfsr_data_fromleb128(name->did, ctx.u.name.buf);
|
||||||
ctx.u.name.datas[1] = LFSR_DATA_BUF(name->name, name->name_len);
|
ctx.u.name.datas[1] = LFSR_DATA_BUF(name->name, name->name_len);
|
||||||
@@ -3772,7 +3773,7 @@ static void lfsr_rbyd_p_recolor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// core rbyd algorithm
|
// our core rbyd append algorithm
|
||||||
static int lfsr_rbyd_appendrattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
static int lfsr_rbyd_appendrattr(lfs_t *lfs, lfsr_rbyd_t *rbyd,
|
||||||
lfsr_srid_t rid, lfsr_rattr_t rattr) {
|
lfsr_srid_t rid, lfsr_rattr_t rattr) {
|
||||||
// must fetch before mutating!
|
// must fetch before mutating!
|
||||||
@@ -10300,8 +10301,8 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
|
|||||||
// commit our bookmark and a grm to self-remove in case of powerloss
|
// commit our bookmark and a grm to self-remove in case of powerloss
|
||||||
lfs_alloc_ckpoint(lfs);
|
lfs_alloc_ckpoint(lfs);
|
||||||
err = lfsr_mdir_commit(lfs, &mdir, LFSR_RATTRS(
|
err = lfsr_mdir_commit(lfs, &mdir, LFSR_RATTRS(
|
||||||
LFSR_RATTR_LEB128(
|
LFSR_RATTR_NAME(
|
||||||
LFSR_TAG_BOOKMARK, +1, did_)));
|
LFSR_TAG_BOOKMARK, +1, did_, NULL, 0)));
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -10635,6 +10636,16 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (old_tag == LFSR_TAG_UNKNOWN) {
|
||||||
|
// lookup the actual tag
|
||||||
|
err = lfsr_rbyd_lookup(lfs, &old_mdir.rbyd,
|
||||||
|
lfsr_mrid(lfs, old_mdir.mid), LFSR_TAG_MASK8 | LFSR_TAG_NAME,
|
||||||
|
&old_tag, NULL);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// mark old entry for removal with a grm
|
// mark old entry for removal with a grm
|
||||||
lfsr_grm_push(lfs, old_mdir.mid);
|
lfsr_grm_push(lfs, old_mdir.mid);
|
||||||
|
|
||||||
@@ -13602,17 +13613,13 @@ static int lfs_deinit(lfs_t *lfs) {
|
|||||||
|
|
||||||
#define LFSR_WCOMPAT_NONSTANDARD 0x00000001 // Non-standard filesystem format
|
#define LFSR_WCOMPAT_NONSTANDARD 0x00000001 // Non-standard filesystem format
|
||||||
#define LFSR_WCOMPAT_RDONLY 0x00000002 // Writing is disallowed
|
#define LFSR_WCOMPAT_RDONLY 0x00000002 // Writing is disallowed
|
||||||
#define LFSR_WCOMPAT_REG 0x00000010 // Regular files in use
|
#define LFSR_WCOMPAT_DIR 0x00000010 // Directory 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
|
#define LFSR_WCOMPAT_GCKSUM 0x00001000 // Global-checksum in use
|
||||||
// internal
|
// internal
|
||||||
#define LFSR_wcompat_OVERFLOW 0x80000000 // Can't represent all flags
|
#define LFSR_wcompat_OVERFLOW 0x80000000 // Can't represent all flags
|
||||||
|
|
||||||
#define LFSR_WCOMPAT_COMPAT \
|
#define LFSR_WCOMPAT_COMPAT \
|
||||||
(LFSR_WCOMPAT_REG \
|
(LFSR_WCOMPAT_DIR \
|
||||||
| LFSR_WCOMPAT_DIR \
|
|
||||||
| LFSR_WCOMPAT_STICKYNOTE \
|
|
||||||
| LFSR_WCOMPAT_GCKSUM)
|
| LFSR_WCOMPAT_GCKSUM)
|
||||||
|
|
||||||
#define LFSR_OCOMPAT_NONSTANDARD 0x00000001 // Non-standard filesystem format
|
#define LFSR_OCOMPAT_NONSTANDARD 0x00000001 // Non-standard filesystem format
|
||||||
@@ -14294,9 +14301,9 @@ static int lfsr_formatinited(lfs_t *lfs) {
|
|||||||
LFSR_RATTR_LEB128(
|
LFSR_RATTR_LEB128(
|
||||||
LFSR_TAG_FILELIMIT, 0,
|
LFSR_TAG_FILELIMIT, 0,
|
||||||
lfs->file_limit),
|
lfs->file_limit),
|
||||||
LFSR_RATTR_LEB128(
|
LFSR_RATTR_NAME(
|
||||||
LFSR_TAG_BOOKMARK, +1,
|
LFSR_TAG_BOOKMARK, +1,
|
||||||
0)));
|
0, NULL, 0)));
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-5
@@ -185,12 +185,8 @@ FLAGS = [
|
|||||||
0x00000001, "Non-standard filesystem format" ),
|
0x00000001, "Non-standard filesystem format" ),
|
||||||
('WCOMPAT', 'RDONLY',
|
('WCOMPAT', 'RDONLY',
|
||||||
0x00000002, "Writing is disallowed" ),
|
0x00000002, "Writing is disallowed" ),
|
||||||
('WCOMPAT', 'REG',
|
|
||||||
0x00000010, "Regular file types in use" ),
|
|
||||||
('WCOMPAT', 'DIR',
|
('WCOMPAT', 'DIR',
|
||||||
0x00000020, "Directory file types in use" ),
|
0x00000010, "Directory file types in use" ),
|
||||||
('WCOMPAT', 'STICKYNOTE',
|
|
||||||
0x00000040, "Stickynote file types in use" ),
|
|
||||||
('WCOMPAT', 'GCKSUM',
|
('WCOMPAT', 'GCKSUM',
|
||||||
0x00001000, "Global-checksum in use" ),
|
0x00001000, "Global-checksum in use" ),
|
||||||
('wcompat', 'OVERFLOW',
|
('wcompat', 'OVERFLOW',
|
||||||
|
|||||||
+778
-3
@@ -1146,9 +1146,8 @@ code = '''
|
|||||||
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
||||||
lfsr_unmount(&lfs) => 0;
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
// mount, note the LFS_M_RDONLY, new types should be added with
|
// mount
|
||||||
// new wcompat flags to prevent resource leaks
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
lfsr_mount(&lfs, LFS_M_RDONLY, CFG) => 0;
|
|
||||||
|
|
||||||
// our file should appear as an unknown type
|
// our file should appear as an unknown type
|
||||||
struct lfs_info info;
|
struct lfs_info info;
|
||||||
@@ -1182,9 +1181,785 @@ code = '''
|
|||||||
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
lfsr_dir_close(&lfs, &dir) => 0;
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
// open/mkdir should error
|
||||||
lfsr_file_open(&lfs, &file, "b",
|
lfsr_file_open(&lfs, &file, "b",
|
||||||
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
|
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;
|
lfsr_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
[cases.test_mount_incompat_unknown_type_rm]
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
// create a superblock
|
||||||
|
lfs_t lfs;
|
||||||
|
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||||
|
|
||||||
|
// create some files
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "a",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi a!", strlen("hi a!")) => strlen("hi a!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "b",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"oh no!", strlen("oh no!")) => strlen("oh no!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "c",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi c!", strlen("hi c!")) => strlen("hi c!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// change a file's type to something unknown
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
const char *path = "b";
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
lfsr_did_t did;
|
||||||
|
lfsr_mtree_pathlookup(&lfs, &path,
|
||||||
|
&mdir, NULL, &did) => 0;
|
||||||
|
lfsr_mdir_commit(&lfs, &mdir, LFSR_RATTRS(
|
||||||
|
LFSR_RATTR_CAT(
|
||||||
|
LFSR_TAG_MASK8 | (LFSR_TAG_NAME + 0x13), 0,
|
||||||
|
lfsr_data_fromleb128(did, (uint8_t[LFSR_LEB128_DSIZE]){0}),
|
||||||
|
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// mount
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, 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 == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_t dir;
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi c!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
// removing unknown files should still work, if this would leak
|
||||||
|
// resources the new type should set a wcompat flag
|
||||||
|
lfsr_remove(&lfs, "b") => 0;
|
||||||
|
|
||||||
|
// check that things look reasonable
|
||||||
|
lfsr_stat(&lfs, "b", &info) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi c!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_mount_incompat_unknown_type_mv_src]
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
// create a superblock
|
||||||
|
lfs_t lfs;
|
||||||
|
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||||
|
|
||||||
|
// create some files
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "a",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi a!", strlen("hi a!")) => strlen("hi a!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "b",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"oh no!", strlen("oh no!")) => strlen("oh no!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "c",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi c!", strlen("hi c!")) => strlen("hi c!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// change a file's type to something unknown
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
const char *path = "b";
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
lfsr_did_t did;
|
||||||
|
lfsr_mtree_pathlookup(&lfs, &path,
|
||||||
|
&mdir, NULL, &did) => 0;
|
||||||
|
lfsr_mdir_commit(&lfs, &mdir, LFSR_RATTRS(
|
||||||
|
LFSR_RATTR_CAT(
|
||||||
|
LFSR_TAG_MASK8 | (LFSR_TAG_NAME + 0x13), 0,
|
||||||
|
lfsr_data_fromleb128(did, (uint8_t[LFSR_LEB128_DSIZE]){0}),
|
||||||
|
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// mount
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, 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 == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_t dir;
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi c!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
// renaming unknown files should still work, if this would leak
|
||||||
|
// resources the new type should set a wcompat flag
|
||||||
|
lfsr_rename(&lfs, "b", "c") => 0;
|
||||||
|
|
||||||
|
// check that things look reasonable after renaming/removing
|
||||||
|
lfsr_stat(&lfs, "c", &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_mount_incompat_unknown_type_mv_dst]
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
// create a superblock
|
||||||
|
lfs_t lfs;
|
||||||
|
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||||
|
|
||||||
|
// create some files
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "a",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi a!", strlen("hi a!")) => strlen("hi a!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "b",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"oh no!", strlen("oh no!")) => strlen("oh no!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "c",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi c!", strlen("hi c!")) => strlen("hi c!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// change a file's type to something unknown
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
const char *path = "b";
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
lfsr_did_t did;
|
||||||
|
lfsr_mtree_pathlookup(&lfs, &path,
|
||||||
|
&mdir, NULL, &did) => 0;
|
||||||
|
lfsr_mdir_commit(&lfs, &mdir, LFSR_RATTRS(
|
||||||
|
LFSR_RATTR_CAT(
|
||||||
|
LFSR_TAG_MASK8 | (LFSR_TAG_NAME + 0x13), 0,
|
||||||
|
lfsr_data_fromleb128(did, (uint8_t[LFSR_LEB128_DSIZE]){0}),
|
||||||
|
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// mount
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, 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 == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_t dir;
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi c!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
// renaming unknown files should still work, if this would leak
|
||||||
|
// resources the new type should set a wcompat flag
|
||||||
|
lfsr_rename(&lfs, "c", "b") => 0;
|
||||||
|
|
||||||
|
// check that things look reasonable after renaming/removing
|
||||||
|
lfsr_stat(&lfs, "b", &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi c!"));
|
||||||
|
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi c!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_mount_incompat_unknown_type_mv_src_dst]
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
// create a superblock
|
||||||
|
lfs_t lfs;
|
||||||
|
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||||
|
|
||||||
|
// create some files
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "a",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi a!", strlen("hi a!")) => strlen("hi a!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "b",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"oh no!", strlen("oh no!")) => strlen("oh no!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "c",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"oh hi!", strlen("oh hi!")) => strlen("oh hi!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// change a file's type to something unknown
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
const char *path = "b";
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
lfsr_did_t did;
|
||||||
|
lfsr_mtree_pathlookup(&lfs, &path,
|
||||||
|
&mdir, NULL, &did) => 0;
|
||||||
|
lfsr_mdir_commit(&lfs, &mdir, LFSR_RATTRS(
|
||||||
|
LFSR_RATTR_CAT(
|
||||||
|
LFSR_TAG_MASK8 | (LFSR_TAG_NAME + 0x13), 0,
|
||||||
|
lfsr_data_fromleb128(did, (uint8_t[LFSR_LEB128_DSIZE]){0}),
|
||||||
|
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
||||||
|
path = "c";
|
||||||
|
lfsr_mtree_pathlookup(&lfs, &path,
|
||||||
|
&mdir, NULL, &did) => 0;
|
||||||
|
lfsr_mdir_commit(&lfs, &mdir, LFSR_RATTRS(
|
||||||
|
LFSR_RATTR_CAT(
|
||||||
|
LFSR_TAG_MASK8 | (LFSR_TAG_NAME + 0x13), 0,
|
||||||
|
lfsr_data_fromleb128(did, (uint8_t[LFSR_LEB128_DSIZE]){0}),
|
||||||
|
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// mount
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, 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 == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_t dir;
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
// renaming unknown files should still work, if this would leak
|
||||||
|
// resources the new type should set a wcompat flag
|
||||||
|
lfsr_rename(&lfs, "b", "c") => 0;
|
||||||
|
|
||||||
|
// check that things look reasonable after renaming/removing
|
||||||
|
lfsr_stat(&lfs, "c", &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_mount_incompat_unknown_type_mv_noop]
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
// create a superblock
|
||||||
|
lfs_t lfs;
|
||||||
|
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||||
|
|
||||||
|
// create some files
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "a",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi a!", strlen("hi a!")) => strlen("hi a!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "b",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"oh no!", strlen("oh no!")) => strlen("oh no!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "c",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi c!", strlen("hi c!")) => strlen("hi c!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// change a file's type to something unknown
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
const char *path = "b";
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
lfsr_did_t did;
|
||||||
|
lfsr_mtree_pathlookup(&lfs, &path,
|
||||||
|
&mdir, NULL, &did) => 0;
|
||||||
|
lfsr_mdir_commit(&lfs, &mdir, LFSR_RATTRS(
|
||||||
|
LFSR_RATTR_CAT(
|
||||||
|
LFSR_TAG_MASK8 | (LFSR_TAG_NAME + 0x13), 0,
|
||||||
|
lfsr_data_fromleb128(did, (uint8_t[LFSR_LEB128_DSIZE]){0}),
|
||||||
|
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// mount
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, 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 == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_t dir;
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi c!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
// renaming unknown files should still work, if this would leak
|
||||||
|
// resources the new type should set a wcompat flag
|
||||||
|
lfsr_rename(&lfs, "b", "b") => 0;
|
||||||
|
|
||||||
|
// check that things look reasonable after renaming/removing
|
||||||
|
lfsr_stat(&lfs, "b", &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi c!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_mount_incompat_unknown_type_mv_notdir]
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
// create a superblock
|
||||||
|
lfs_t lfs;
|
||||||
|
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||||
|
|
||||||
|
// create some files
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "a",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi a!", strlen("hi a!")) => strlen("hi a!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "b",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"oh no!", strlen("oh no!")) => strlen("oh no!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_mkdir(&lfs, "c") => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// change a file's type to something unknown
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
const char *path = "b";
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
lfsr_did_t did;
|
||||||
|
lfsr_mtree_pathlookup(&lfs, &path,
|
||||||
|
&mdir, NULL, &did) => 0;
|
||||||
|
lfsr_mdir_commit(&lfs, &mdir, LFSR_RATTRS(
|
||||||
|
LFSR_RATTR_CAT(
|
||||||
|
LFSR_TAG_MASK8 | (LFSR_TAG_NAME + 0x13), 0,
|
||||||
|
lfsr_data_fromleb128(did, (uint8_t[LFSR_LEB128_DSIZE]){0}),
|
||||||
|
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// mount
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, 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 == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_t dir;
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
// renaming unknown files should still work, if this would leak
|
||||||
|
// resources the new type should set a wcompat flag
|
||||||
|
lfsr_rename(&lfs, "c", "b") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// check that things look reasonable after renaming/removing
|
||||||
|
lfsr_stat(&lfs, "b", &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|
||||||
|
[cases.test_mount_incompat_unknown_type_mv_isdir]
|
||||||
|
in = 'lfs.c'
|
||||||
|
code = '''
|
||||||
|
// create a superblock
|
||||||
|
lfs_t lfs;
|
||||||
|
lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0;
|
||||||
|
|
||||||
|
// create some files
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
lfsr_file_t file;
|
||||||
|
lfsr_file_open(&lfs, &file, "a",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"hi a!", strlen("hi a!")) => strlen("hi a!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_file_open(&lfs, &file, "b",
|
||||||
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
||||||
|
lfsr_file_write(&lfs, &file,
|
||||||
|
"oh no!", strlen("oh no!")) => strlen("oh no!");
|
||||||
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
|
lfsr_mkdir(&lfs, "c") => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// change a file's type to something unknown
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||||
|
const char *path = "b";
|
||||||
|
lfsr_mdir_t mdir;
|
||||||
|
lfsr_did_t did;
|
||||||
|
lfsr_mtree_pathlookup(&lfs, &path,
|
||||||
|
&mdir, NULL, &did) => 0;
|
||||||
|
lfsr_mdir_commit(&lfs, &mdir, LFSR_RATTRS(
|
||||||
|
LFSR_RATTR_CAT(
|
||||||
|
LFSR_TAG_MASK8 | (LFSR_TAG_NAME + 0x13), 0,
|
||||||
|
lfsr_data_fromleb128(did, (uint8_t[LFSR_LEB128_DSIZE]){0}),
|
||||||
|
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
|
||||||
|
// mount
|
||||||
|
lfsr_mount(&lfs, LFS_M_RDWR, 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 == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_t dir;
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
// renaming unknown files should still work, if this would leak
|
||||||
|
// resources the new type should set a wcompat flag
|
||||||
|
lfsr_rename(&lfs, "b", "c") => LFS_ERR_ISDIR;
|
||||||
|
|
||||||
|
// check that things look reasonable after renaming/removing
|
||||||
|
lfsr_stat(&lfs, "b", &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
|
||||||
|
lfsr_dir_open(&lfs, &dir, "/") => 0;
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, ".") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "..") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "a") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_REG);
|
||||||
|
assert(info.size == strlen("hi a!"));
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "b") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||||
|
assert(strcmp(info.name, "c") == 0);
|
||||||
|
assert(info.type == LFS_TYPE_DIR);
|
||||||
|
assert(info.size == 0);
|
||||||
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_dir_close(&lfs, &dir) => 0;
|
||||||
|
|
||||||
|
lfsr_unmount(&lfs) => 0;
|
||||||
|
'''
|
||||||
|
|||||||
+443
-22
@@ -4656,29 +4656,70 @@ code = '''
|
|||||||
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese") => LFS_ERR_NOTDIR;
|
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese") => LFS_ERR_NOTDIR;
|
||||||
lfsr_dir_open(&lfs, &dir, "coffee/thai") => LFS_ERR_NOTDIR;
|
lfsr_dir_open(&lfs, &dir, "coffee/thai") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
// note write operations should normally be rejected during mount
|
// rename paths
|
||||||
// by wcompat flags
|
lfsr_mkdir(&lfs, "espresso") => 0;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/drip",
|
||||||
|
"espresso/espresso") => 0;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/coldbrew",
|
||||||
|
"espresso/americano") => 0;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/turkish",
|
||||||
|
"espresso/macchiato") => 0;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/tubruk",
|
||||||
|
"espresso/latte") => 0;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/vietnamese",
|
||||||
|
"espresso/cappuccino") => 0;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/thai",
|
||||||
|
"espresso/mocha") => 0;
|
||||||
|
|
||||||
// stat paths
|
// stat paths
|
||||||
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
|
lfsr_stat(&lfs, "espresso/espresso", &info) => 0;
|
||||||
assert(strcmp(info.name, "drip") == 0);
|
assert(strcmp(info.name, "espresso") == 0);
|
||||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
lfsr_stat(&lfs, "coffee/coldbrew", &info) => 0;
|
lfsr_stat(&lfs, "espresso/americano", &info) => 0;
|
||||||
assert(strcmp(info.name, "coldbrew") == 0);
|
assert(strcmp(info.name, "americano") == 0);
|
||||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
lfsr_stat(&lfs, "coffee/turkish", &info) => 0;
|
lfsr_stat(&lfs, "espresso/macchiato", &info) => 0;
|
||||||
assert(strcmp(info.name, "turkish") == 0);
|
assert(strcmp(info.name, "macchiato") == 0);
|
||||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
lfsr_stat(&lfs, "coffee/tubruk", &info) => 0;
|
lfsr_stat(&lfs, "espresso/latte", &info) => 0;
|
||||||
assert(strcmp(info.name, "tubruk") == 0);
|
assert(strcmp(info.name, "latte") == 0);
|
||||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
lfsr_stat(&lfs, "coffee/vietnamese", &info) => 0;
|
lfsr_stat(&lfs, "espresso/cappuccino", &info) => 0;
|
||||||
assert(strcmp(info.name, "vietnamese") == 0);
|
assert(strcmp(info.name, "cappuccino") == 0);
|
||||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
lfsr_stat(&lfs, "coffee/thai", &info) => 0;
|
lfsr_stat(&lfs, "espresso/mocha", &info) => 0;
|
||||||
assert(strcmp(info.name, "thai") == 0);
|
assert(strcmp(info.name, "mocha") == 0);
|
||||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
|
|
||||||
|
lfsr_stat(&lfs, "coffee/drip", &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_stat(&lfs, "coffee/coldbrew", &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_stat(&lfs, "coffee/turkish", &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_stat(&lfs, "coffee/tubruk", &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_stat(&lfs, "coffee/vietnamese", &info) => LFS_ERR_NOENT;
|
||||||
|
lfsr_stat(&lfs, "coffee/thai", &info) => LFS_ERR_NOENT;
|
||||||
|
|
||||||
|
// remove paths
|
||||||
|
lfsr_remove(&lfs, "espresso/espresso") => 0;
|
||||||
|
lfsr_remove(&lfs, "espresso/americano") => 0;
|
||||||
|
lfsr_remove(&lfs, "espresso/macchiato") => 0;
|
||||||
|
lfsr_remove(&lfs, "espresso/latte") => 0;
|
||||||
|
lfsr_remove(&lfs, "espresso/cappuccino") => 0;
|
||||||
|
lfsr_remove(&lfs, "espresso/mocha") => 0;
|
||||||
|
|
||||||
|
// 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_unmount(&lfs) => 0;
|
lfsr_unmount(&lfs) => 0;
|
||||||
'''
|
'''
|
||||||
|
|
||||||
@@ -4857,10 +4898,104 @@ code = '''
|
|||||||
lfsr_file_close(&lfs, &file) => 0;
|
lfsr_file_close(&lfs, &file) => 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// note write operations should normally be rejected during mount
|
// rename paths
|
||||||
// by wcompat flags
|
lfsr_mkdir(&lfs, "espresso") => 0;
|
||||||
|
// bad source
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"drip/coffee",
|
||||||
|
"espresso/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coldbrew/coffee",
|
||||||
|
"espresso/americano") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"turkish/coffee",
|
||||||
|
"espresso/macchiato") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"tubruk/coffee",
|
||||||
|
"espresso/latte") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"vietnamese/coffee",
|
||||||
|
"espresso/cappuccino") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"thai/coffee",
|
||||||
|
"espresso/mocha") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// bad destination
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/drip",
|
||||||
|
"drip/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/coldbrew",
|
||||||
|
"coldbrew/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/turkish",
|
||||||
|
"turkish/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/tubruk",
|
||||||
|
"tubruk/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/vietnamese",
|
||||||
|
"vietnamese/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/thai",
|
||||||
|
"thai/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// bad source and bad destination
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"drip/coffee",
|
||||||
|
"drip/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coldbrew/coffee",
|
||||||
|
"coldbrew/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"turkish/coffee",
|
||||||
|
"turkish/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"tubruk/coffee",
|
||||||
|
"tubruk/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"vietnamese/coffee",
|
||||||
|
"vietnamese/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"thai/coffee",
|
||||||
|
"thai/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// here's a weird one, what happens if our rename is also a noop?
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"drip/coffee",
|
||||||
|
"drip/coffee") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coldbrew/coffee",
|
||||||
|
"coldbrew/coffee") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"turkish/coffee",
|
||||||
|
"turkish/coffee") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"tubruk/coffee",
|
||||||
|
"tubruk/coffee") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"vietnamese/coffee",
|
||||||
|
"vietnamese/coffee") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"thai/coffee",
|
||||||
|
"thai/coffee") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// remove paths
|
||||||
|
lfsr_stat(&lfs, "drip/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_stat(&lfs, "coldbrew/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_stat(&lfs, "turkish/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_stat(&lfs, "tubruk/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_stat(&lfs, "vietnamese/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_stat(&lfs, "thai/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
// stat paths
|
// stat paths
|
||||||
|
lfsr_stat(&lfs, "drip/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_stat(&lfs, "coldbrew/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_stat(&lfs, "turkish/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_stat(&lfs, "tubruk/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_stat(&lfs, "vietnamese/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_stat(&lfs, "thai/espresso", &info) => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
|
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
|
||||||
assert(strcmp(info.name, "drip") == 0);
|
assert(strcmp(info.name, "drip") == 0);
|
||||||
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
|
assert(info.type == ((DIR) ? LFS_TYPE_DIR : LFS_TYPE_REG));
|
||||||
@@ -5005,10 +5140,104 @@ code = '''
|
|||||||
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/////") => LFS_ERR_NOTDIR;
|
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/////") => LFS_ERR_NOTDIR;
|
||||||
lfsr_dir_open(&lfs, &dir, "coffee/thai//////") => LFS_ERR_NOTDIR;
|
lfsr_dir_open(&lfs, &dir, "coffee/thai//////") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
// note write operations should normally be rejected during mount
|
// rename paths
|
||||||
// by wcompat flags
|
lfsr_mkdir(&lfs, "espresso") => 0;
|
||||||
|
// bad source
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/drip//////",
|
||||||
|
"espresso/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/coldbrew/////",
|
||||||
|
"espresso/americano") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/turkish////",
|
||||||
|
"espresso/macchiato") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/tubruk///",
|
||||||
|
"espresso/latte") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/vietnamese//",
|
||||||
|
"espresso/cappuccino") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/thai/",
|
||||||
|
"espresso/mocha") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// bad destination
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/drip",
|
||||||
|
"espresso/espresso/") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/coldbrew",
|
||||||
|
"espresso/americano//") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/turkish",
|
||||||
|
"espresso/macchiato///") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/tubruk",
|
||||||
|
"espresso/latte////") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/vietnamese",
|
||||||
|
"espresso/cappuccino/////") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/thai",
|
||||||
|
"espresso/mocha//////") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// bad source and bad destination
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/drip//////",
|
||||||
|
"espresso/espresso/") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/coldbrew/////",
|
||||||
|
"espresso/americano//") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/turkish////",
|
||||||
|
"espresso/macchiato///") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/tubruk///",
|
||||||
|
"espresso/latte////") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/vietnamese//",
|
||||||
|
"espresso/cappuccino/////") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/thai/",
|
||||||
|
"espresso/mocha//////") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// here's a weird one, what happens if our rename is also a noop?
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/drip//////",
|
||||||
|
"coffee/drip//////") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/coldbrew/////",
|
||||||
|
"coffee/coldbrew/////") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/turkish////",
|
||||||
|
"coffee/turkish////") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/tubruk///",
|
||||||
|
"coffee/tubruk///") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/vietnamese//",
|
||||||
|
"coffee/vietnamese//") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/thai/",
|
||||||
|
"coffee/thai/") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// remove paths
|
||||||
|
lfsr_remove(&lfs, "coffee/drip/") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_remove(&lfs, "coffee/coldbrew//") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_remove(&lfs, "coffee/turkish///") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_remove(&lfs, "coffee/tubruk////") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_remove(&lfs, "coffee/vietnamese/////") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_remove(&lfs, "coffee/thai//////") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
// stat paths
|
// 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;
|
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
|
||||||
assert(strcmp(info.name, "drip") == 0);
|
assert(strcmp(info.name, "drip") == 0);
|
||||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
@@ -5153,10 +5382,104 @@ code = '''
|
|||||||
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/././././.") => LFS_ERR_NOTDIR;
|
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/././././.") => LFS_ERR_NOTDIR;
|
||||||
lfsr_dir_open(&lfs, &dir, "coffee/thai/./././././.") => LFS_ERR_NOTDIR;
|
lfsr_dir_open(&lfs, &dir, "coffee/thai/./././././.") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
// note write operations should normally be rejected during mount
|
// rename paths
|
||||||
// by wcompat flags
|
lfsr_mkdir(&lfs, "espresso") => 0;
|
||||||
|
// bad source
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/drip/./././././.",
|
||||||
|
"espresso/espresso") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/coldbrew/././././.",
|
||||||
|
"espresso/americano") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/turkish/./././.",
|
||||||
|
"espresso/macchiato") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/tubruk/././.",
|
||||||
|
"espresso/latte") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/vietnamese/./.",
|
||||||
|
"espresso/cappuccino") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/thai/.",
|
||||||
|
"espresso/mocha") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// bad destination
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/drip",
|
||||||
|
"espresso/espresso/.") => LFS_ERR_NOENT;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/coldbrew",
|
||||||
|
"espresso/americano/./.") => LFS_ERR_NOENT;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/turkish",
|
||||||
|
"espresso/macchiato/././.") => LFS_ERR_NOENT;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/tubruk",
|
||||||
|
"espresso/latte/./././.") => LFS_ERR_NOENT;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/vietnamese",
|
||||||
|
"espresso/cappuccino/././././.") => LFS_ERR_NOENT;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/thai",
|
||||||
|
"espresso/mocha/./././././.") => LFS_ERR_NOENT;
|
||||||
|
|
||||||
|
// bad source and bad destination
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/drip/./././././.",
|
||||||
|
"espresso/espresso/.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/coldbrew/././././.",
|
||||||
|
"espresso/americano/./.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/turkish/./././.",
|
||||||
|
"espresso/macchiato/././.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/tubruk/././.",
|
||||||
|
"espresso/latte/./././.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/vietnamese/./.",
|
||||||
|
"espresso/cappuccino/././././.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/thai/.",
|
||||||
|
"espresso/mocha/./././././.") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// here's a weird one, what happens if our rename is also a noop?
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/drip/./././././.",
|
||||||
|
"coffee/drip/./././././.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/coldbrew/././././.",
|
||||||
|
"coffee/coldbrew/././././.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/turkish/./././.",
|
||||||
|
"coffee/turkish/./././.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/tubruk/././.",
|
||||||
|
"coffee/tubruk/././.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/vietnamese/./.",
|
||||||
|
"coffee/vietnamese/./.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_rename(&lfs,
|
||||||
|
"coffee/thai/.",
|
||||||
|
"coffee/thai/.") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
|
// remove paths
|
||||||
|
lfsr_remove(&lfs, "coffee/drip/.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_remove(&lfs, "coffee/coldbrew/./.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_remove(&lfs, "coffee/turkish/././.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_remove(&lfs, "coffee/tubruk/./././.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_remove(&lfs, "coffee/vietnamese/././././.") => LFS_ERR_NOTDIR;
|
||||||
|
lfsr_remove(&lfs, "coffee/thai/./././././.") => LFS_ERR_NOTDIR;
|
||||||
|
|
||||||
// stat paths
|
// 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;
|
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
|
||||||
assert(strcmp(info.name, "drip") == 0);
|
assert(strcmp(info.name, "drip") == 0);
|
||||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
@@ -5281,11 +5604,109 @@ code = '''
|
|||||||
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/../../../../..") => LFS_ERR_INVAL;
|
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/../../../../..") => LFS_ERR_INVAL;
|
||||||
lfsr_dir_open(&lfs, &dir, "coffee/thai/../../../../../..") => LFS_ERR_INVAL;
|
lfsr_dir_open(&lfs, &dir, "coffee/thai/../../../../../..") => LFS_ERR_INVAL;
|
||||||
|
|
||||||
// note write operations should normally be rejected during mount
|
// rename paths
|
||||||
// by wcompat flags
|
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_ISDIR;
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
// stat paths
|
// 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;
|
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
|
||||||
|
|
||||||
assert(strcmp(info.name, "drip") == 0);
|
assert(strcmp(info.name, "drip") == 0);
|
||||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||||
lfsr_stat(&lfs, "coffee/coldbrew", &info) => 0;
|
lfsr_stat(&lfs, "coffee/coldbrew", &info) => 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user