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:
+778
-3
@@ -1146,9 +1146,8 @@ code = '''
|
||||
LFSR_DATA_BUF(path, lfsr_path_namelen(path))))) => 0;
|
||||
lfsr_unmount(&lfs) => 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;
|
||||
// mount
|
||||
lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0;
|
||||
|
||||
// our file should appear as an unknown type
|
||||
struct lfs_info info;
|
||||
@@ -1182,9 +1181,785 @@ code = '''
|
||||
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
||||
lfsr_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
// open/mkdir should error
|
||||
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;
|
||||
'''
|
||||
|
||||
[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/thai") => LFS_ERR_NOTDIR;
|
||||
|
||||
// note write operations should normally be rejected during mount
|
||||
// by wcompat flags
|
||||
// rename paths
|
||||
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
|
||||
lfsr_stat(&lfs, "coffee/drip", &info) => 0;
|
||||
assert(strcmp(info.name, "drip") == 0);
|
||||
lfsr_stat(&lfs, "espresso/espresso", &info) => 0;
|
||||
assert(strcmp(info.name, "espresso") == 0);
|
||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||
lfsr_stat(&lfs, "coffee/coldbrew", &info) => 0;
|
||||
assert(strcmp(info.name, "coldbrew") == 0);
|
||||
lfsr_stat(&lfs, "espresso/americano", &info) => 0;
|
||||
assert(strcmp(info.name, "americano") == 0);
|
||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||
lfsr_stat(&lfs, "coffee/turkish", &info) => 0;
|
||||
assert(strcmp(info.name, "turkish") == 0);
|
||||
lfsr_stat(&lfs, "espresso/macchiato", &info) => 0;
|
||||
assert(strcmp(info.name, "macchiato") == 0);
|
||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||
lfsr_stat(&lfs, "coffee/tubruk", &info) => 0;
|
||||
assert(strcmp(info.name, "tubruk") == 0);
|
||||
lfsr_stat(&lfs, "espresso/latte", &info) => 0;
|
||||
assert(strcmp(info.name, "latte") == 0);
|
||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||
lfsr_stat(&lfs, "coffee/vietnamese", &info) => 0;
|
||||
assert(strcmp(info.name, "vietnamese") == 0);
|
||||
lfsr_stat(&lfs, "espresso/cappuccino", &info) => 0;
|
||||
assert(strcmp(info.name, "cappuccino") == 0);
|
||||
assert(info.type == LFS_TYPE_UNKNOWN);
|
||||
lfsr_stat(&lfs, "coffee/thai", &info) => 0;
|
||||
assert(strcmp(info.name, "thai") == 0);
|
||||
lfsr_stat(&lfs, "espresso/mocha", &info) => 0;
|
||||
assert(strcmp(info.name, "mocha") == 0);
|
||||
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;
|
||||
'''
|
||||
|
||||
@@ -4857,10 +4898,104 @@ code = '''
|
||||
lfsr_file_close(&lfs, &file) => 0;
|
||||
}
|
||||
|
||||
// note write operations should normally be rejected during mount
|
||||
// by wcompat flags
|
||||
// rename paths
|
||||
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
|
||||
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;
|
||||
assert(strcmp(info.name, "drip") == 0);
|
||||
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/thai//////") => LFS_ERR_NOTDIR;
|
||||
|
||||
// note write operations should normally be rejected during mount
|
||||
// by wcompat flags
|
||||
// rename paths
|
||||
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
|
||||
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 == LFS_TYPE_UNKNOWN);
|
||||
@@ -5153,10 +5382,104 @@ code = '''
|
||||
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/././././.") => LFS_ERR_NOTDIR;
|
||||
lfsr_dir_open(&lfs, &dir, "coffee/thai/./././././.") => LFS_ERR_NOTDIR;
|
||||
|
||||
// note write operations should normally be rejected during mount
|
||||
// by wcompat flags
|
||||
// rename paths
|
||||
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
|
||||
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 == LFS_TYPE_UNKNOWN);
|
||||
@@ -5281,11 +5604,109 @@ code = '''
|
||||
lfsr_dir_open(&lfs, &dir, "coffee/vietnamese/../../../../..") => LFS_ERR_INVAL;
|
||||
lfsr_dir_open(&lfs, &dir, "coffee/thai/../../../../../..") => LFS_ERR_INVAL;
|
||||
|
||||
// note write operations should normally be rejected during mount
|
||||
// by wcompat flags
|
||||
// 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_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
|
||||
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 == LFS_TYPE_UNKNOWN);
|
||||
lfsr_stat(&lfs, "coffee/coldbrew", &info) => 0;
|
||||
|
||||
Reference in New Issue
Block a user