Added detection/handling of unknown file types
This adds a couple things so our unknown file types don't just cause our
filesystem to fall over:
- lfsr_mount now prints a warning on any unknown file types found at
mount time. Since we're already iterating over all files to find
orphans, this is basically free.
- Added LFS_TYPE_UNKNOWN to represent files with an unknown/unsupported
type. This is now returned by lfsr_stat/lfsr_dir_read for files of any
unknow type.
- Added LFS_ERR_NOTSUP. This is now returned by functions that attempt
to modify a file of unknown type, and my have more use cases in the
future.
It's tempting to allow remove/rename on unknown file types, but since
we don't know what data structures these may be referencing, doing so
would likely leak storage. Or worse. Shrubs for example would just
explode if you only moved the metadata entry.
This also adds test_incompat_unknown to test these cases.
Code changes are minimal, though there are a number of extra conditions
to check for unknown file types. The lfsr_mount condition is
particularly fun as it should be completely optimized out when debug
statements are disabled:
code stack
before: 33670 2592
after: 33710 (+0.1%) 2592 (+0.0%)
This commit is contained in:
@@ -316,3 +316,109 @@ code = '''
|
||||
lfsr_mount(&lfs, CFG) => LFS_ERR_INVAL;
|
||||
'''
|
||||
|
||||
# test what happens if we find an unknown file type
|
||||
[cases.test_incompat_unknown]
|
||||
in = 'lfs.c'
|
||||
code = '''
|
||||
// create a superblock
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, CFG) => 0;
|
||||
|
||||
// create some files
|
||||
lfsr_mount(&lfs, 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, "hi b!", strlen("hi b!")) => strlen("hi b!");
|
||||
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, CFG) => 0;
|
||||
lfsr_mdir_t mdir;
|
||||
lfsr_did_t did;
|
||||
const char *name;
|
||||
lfs_size_t name_size;
|
||||
lfsr_mtree_pathlookup(&lfs, &lfs.mtree, "b",
|
||||
&mdir, NULL,
|
||||
&did, &name, &name_size) => LFS_ERR_EXIST;
|
||||
lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
|
||||
LFSR_ATTR_NAME(
|
||||
LFSR_TAG_SUB | (LFSR_TAG_NAME + 0x13), 0,
|
||||
did, name, name_size))) => 0;
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
|
||||
// mount
|
||||
lfsr_mount(&lfs, CFG) => 0;
|
||||
|
||||
// our file should appear as unknown
|
||||
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/renaming unknown files should return NOTSUP, we could
|
||||
// remove the metadata entry, but we would probably leak stuff
|
||||
lfsr_remove(&lfs, "b") => LFS_ERR_NOTSUP;
|
||||
lfsr_rename(&lfs, "b", "d") => LFS_ERR_NOTSUP;
|
||||
lfsr_rename(&lfs, "b", "c") => LFS_ERR_NOTSUP;
|
||||
lfsr_rename(&lfs, "a", "b") => LFS_ERR_NOTSUP;
|
||||
|
||||
lfsr_file_open(&lfs, &file, "b",
|
||||
LFS_O_RDONLY) => LFS_ERR_NOTSUP;
|
||||
lfsr_file_open(&lfs, &file, "b",
|
||||
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTSUP;
|
||||
|
||||
lfsr_mkdir(&lfs, "b") => LFS_ERR_EXIST;
|
||||
|
||||
// we should also not try to use unknown files as dirs, which can
|
||||
// be a bit tricky
|
||||
lfsr_stat(&lfs, "b/d", &info) => LFS_ERR_NOTDIR;
|
||||
lfsr_remove(&lfs, "b/e") => LFS_ERR_NOTDIR;
|
||||
lfsr_rename(&lfs, "b/e", "d") => LFS_ERR_NOTDIR;
|
||||
lfsr_rename(&lfs, "b/e", "c") => LFS_ERR_NOTDIR;
|
||||
lfsr_rename(&lfs, "a", "b/e") => LFS_ERR_NOTDIR;
|
||||
|
||||
lfsr_file_open(&lfs, &file, "b/e",
|
||||
LFS_O_RDONLY) => LFS_ERR_NOTDIR;
|
||||
lfsr_file_open(&lfs, &file, "b/e",
|
||||
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOTDIR;
|
||||
|
||||
lfsr_mkdir(&lfs, "b/e") => LFS_ERR_NOTDIR;
|
||||
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
Reference in New Issue
Block a user