c7820e653e
LFS_O_SNAPSHOT brings back some of littlefs's idiosyncratic behavior removed in the changes to open file syncing in a form that may be more useful for users. LFS_O_SNAPSHOT allows you to open a "snapshot" of a file. This is a cheap, local copy of a file who's changes are not reflected on disk. Internally, snapshot files use the same mechanism as pending writes. A separate, copy-on-write CTZ skip-list is created, with read-only references to the existing data blocks until a write occurs. The difference is that snapshot files are not enrolled in the mlist, meaning they won't get updates from open file syncs, and during close their contents are simply discarded. As an extra benefit, LFS_O_CREAT | LFS_O_SNAPSHOT is equivalent to Linux's O_TMPFILE, making it easy to create temporary, unnamed files. This may be useful for embedded development, where unnamed flash-backed buffers may provide a slower, but larger, alternative to RAM-backed buffers.
937 lines
31 KiB
TOML
937 lines
31 KiB
TOML
|
|
[[case]] # interspersed file test
|
|
define.SIZE = [10, 100]
|
|
define.FILES = [4, 10, 26]
|
|
code = '''
|
|
lfs_file_t files[FILES];
|
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (int j = 0; j < FILES; j++) {
|
|
sprintf(path, "%c", alphas[j]);
|
|
lfs_file_open(&lfs, &files[j], path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
}
|
|
|
|
for (int i = 0; i < SIZE; i++) {
|
|
for (int j = 0; j < FILES; j++) {
|
|
lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1;
|
|
}
|
|
}
|
|
|
|
for (int j = 0; j < FILES; j++) {
|
|
lfs_file_close(&lfs, &files[j]);
|
|
}
|
|
|
|
lfs_dir_open(&lfs, &dir, "/") => 0;
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
for (int j = 0; j < FILES; j++) {
|
|
sprintf(path, "%c", alphas[j]);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, path) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
}
|
|
lfs_dir_read(&lfs, &dir, &info) => 0;
|
|
lfs_dir_close(&lfs, &dir) => 0;
|
|
|
|
for (int j = 0; j < FILES; j++) {
|
|
sprintf(path, "%c", alphas[j]);
|
|
lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0;
|
|
}
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
for (int j = 0; j < FILES; j++) {
|
|
lfs_file_read(&lfs, &files[j], buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j]);
|
|
}
|
|
}
|
|
|
|
for (int j = 0; j < FILES; j++) {
|
|
lfs_file_close(&lfs, &files[j]);
|
|
}
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[[case]] # interspersed remove file test
|
|
define.SIZE = [10, 100]
|
|
define.FILES = [4, 10, 26]
|
|
code = '''
|
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
for (int j = 0; j < FILES; j++) {
|
|
sprintf(path, "%c", alphas[j]);
|
|
lfs_file_open(&lfs, &file, path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
|
|
for (int i = 0; i < SIZE; i++) {
|
|
lfs_file_write(&lfs, &file, &alphas[j], 1) => 1;
|
|
}
|
|
lfs_file_close(&lfs, &file);
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
for (int j = 0; j < FILES; j++) {
|
|
lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1;
|
|
lfs_file_sync(&lfs, &file) => 0;
|
|
|
|
sprintf(path, "%c", alphas[j]);
|
|
lfs_remove(&lfs, path) => 0;
|
|
}
|
|
lfs_file_close(&lfs, &file);
|
|
|
|
lfs_dir_open(&lfs, &dir, "/") => 0;
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, "zzz") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == FILES);
|
|
lfs_dir_read(&lfs, &dir, &info) => 0;
|
|
lfs_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfs_file_open(&lfs, &file, "zzz", LFS_O_RDONLY) => 0;
|
|
for (int i = 0; i < FILES; i++) {
|
|
lfs_file_read(&lfs, &file, buffer, 1) => 1;
|
|
assert(buffer[0] == '~');
|
|
}
|
|
lfs_file_close(&lfs, &file);
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[[case]] # remove inconveniently test
|
|
define.SIZE = [10, 100]
|
|
code = '''
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_t files[3];
|
|
lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
lfs_file_open(&lfs, &files[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0;
|
|
|
|
for (int i = 0; i < SIZE/2; i++) {
|
|
lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1;
|
|
lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1;
|
|
lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1;
|
|
}
|
|
|
|
lfs_remove(&lfs, "f") => 0;
|
|
|
|
for (int i = 0; i < SIZE/2; i++) {
|
|
lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1;
|
|
lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1;
|
|
lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1;
|
|
}
|
|
|
|
lfs_file_close(&lfs, &files[0]);
|
|
lfs_file_close(&lfs, &files[1]);
|
|
lfs_file_close(&lfs, &files[2]);
|
|
|
|
lfs_dir_open(&lfs, &dir, "/") => 0;
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, "e") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, "g") == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
lfs_dir_read(&lfs, &dir, &info) => 0;
|
|
lfs_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0;
|
|
lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0;
|
|
for (int i = 0; i < SIZE; i++) {
|
|
lfs_file_read(&lfs, &files[0], buffer, 1) => 1;
|
|
assert(buffer[0] == 'e');
|
|
lfs_file_read(&lfs, &files[1], buffer, 1) => 1;
|
|
assert(buffer[0] == 'g');
|
|
}
|
|
lfs_file_close(&lfs, &files[0]);
|
|
lfs_file_close(&lfs, &files[1]);
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[[case]] # reentrant interspersed file test
|
|
define.SIZE = [10, 100]
|
|
define.FILES = [4, 10, 26]
|
|
reentrant = true
|
|
code = '''
|
|
lfs_file_t files[FILES];
|
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
|
|
|
err = lfs_mount(&lfs, &cfg);
|
|
if (err) {
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
}
|
|
|
|
for (int j = 0; j < FILES; j++) {
|
|
sprintf(path, "%c", alphas[j]);
|
|
lfs_file_open(&lfs, &files[j], path,
|
|
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
|
|
}
|
|
|
|
for (int i = 0; i < SIZE; i++) {
|
|
for (int j = 0; j < FILES; j++) {
|
|
size = lfs_file_size(&lfs, &files[j]);
|
|
assert((int)size >= 0);
|
|
if ((int)size <= i) {
|
|
lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1;
|
|
lfs_file_sync(&lfs, &files[j]) => 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int j = 0; j < FILES; j++) {
|
|
lfs_file_close(&lfs, &files[j]);
|
|
}
|
|
|
|
lfs_dir_open(&lfs, &dir, "/") => 0;
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, ".") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
for (int j = 0; j < FILES; j++) {
|
|
sprintf(path, "%c", alphas[j]);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(strcmp(info.name, path) == 0);
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(info.size == SIZE);
|
|
}
|
|
lfs_dir_read(&lfs, &dir, &info) => 0;
|
|
lfs_dir_close(&lfs, &dir) => 0;
|
|
|
|
for (int j = 0; j < FILES; j++) {
|
|
sprintf(path, "%c", alphas[j]);
|
|
lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0;
|
|
}
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
for (int j = 0; j < FILES; j++) {
|
|
lfs_file_read(&lfs, &files[j], buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j]);
|
|
}
|
|
}
|
|
|
|
for (int j = 0; j < FILES; j++) {
|
|
lfs_file_close(&lfs, &files[j]);
|
|
}
|
|
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[[case]] # open same file reading from separate file handles
|
|
define.READERS = 3
|
|
define.SIZE = [10, 100, 1000, 10000]
|
|
define.RDMODE = ['LFS_O_RDONLY', 'LFS_O_RDWR']
|
|
code = '''
|
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "shared", LFS_O_CREAT | LFS_O_WRONLY) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
// open all files
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_t readers[READERS];
|
|
for (int i = 0; i < READERS; i++) {
|
|
lfs_file_open(&lfs, &readers[i], "shared", RDMODE) => 0;
|
|
}
|
|
|
|
// perform operations while all readers are open
|
|
for (int i = 0; i < READERS; i++) {
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < READERS; i++) {
|
|
lfs_file_close(&lfs, &readers[i]) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[[case]] # open same file reading and writing from separate file handles
|
|
define.READERS = 3
|
|
define.SIZE = [10, 100, 1000, 10000]
|
|
define.RDMODE = ['LFS_O_RDONLY', 'LFS_O_RDWR']
|
|
define.WRMODE = ['LFS_O_WRONLY', 'LFS_O_RDWR']
|
|
code = '''
|
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
|
const char nums[] = "0123456789";
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, "shared", LFS_O_CREAT | LFS_O_WRONLY) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
// open all files
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_t writer;
|
|
lfs_file_t readers[READERS];
|
|
lfs_file_open(&lfs, &writer, "shared", WRMODE) => 0;
|
|
for (int i = 0; i < READERS; i++) {
|
|
lfs_file_open(&lfs, &readers[i], "shared", RDMODE) => 0;
|
|
}
|
|
|
|
// perform operations while all readers are open
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &writer, &nums[j % 10], 1) => 1;
|
|
}
|
|
|
|
for (int i = 0; i < READERS; i++) {
|
|
for (int j = 0; j < SIZE/2; j++) {
|
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
}
|
|
|
|
// sync, now write should reflect in all open files
|
|
lfs_file_sync(&lfs, &writer) => 0;
|
|
|
|
for (int i = 0; i < READERS; i++) {
|
|
for (int j = SIZE/2; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
}
|
|
|
|
// double check our writer reflects its own changes
|
|
if (WRMODE == LFS_O_RDWR) {
|
|
lfs_file_rewind(&lfs, &writer) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &writer, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < READERS; i++) {
|
|
lfs_file_close(&lfs, &readers[i]) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[[case]] # check that attributes are updated in open files
|
|
define.READERS = 3
|
|
define.SIZE = 10
|
|
define.RDMODE = ['LFS_O_RDONLY', 'LFS_O_RDWR']
|
|
define.WRMODE = ['LFS_O_WRONLY', 'LFS_O_RDWR']
|
|
code = '''
|
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
|
const char nums[] = "0123456789";
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
const struct lfs_file_config filecfg = {
|
|
.attr_count = 3,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', "a", 1},
|
|
{'B', "bb", 2},
|
|
{'C', "ccc", 3},
|
|
},
|
|
};
|
|
lfs_file_opencfg(&lfs, &file, "shared",
|
|
LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
// open all files
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_t writer;
|
|
const struct lfs_file_config writercfg = {
|
|
.attr_count = 3,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[1]){0}, 1},
|
|
{'B', &(uint8_t[2]){0}, 2},
|
|
{'C', &(uint8_t[3]){0}, 3}}};
|
|
lfs_file_t readers[READERS];
|
|
const struct lfs_file_config readercfgs[READERS] = {
|
|
{ .attr_count = 3,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[1]){0}, 1},
|
|
{'B', &(uint8_t[2]){0}, 2},
|
|
{'C', &(uint8_t[3]){0}, 3}}},
|
|
{ .attr_count = 3,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[1]){0}, 1},
|
|
{'B', &(uint8_t[2]){0}, 2},
|
|
{'C', &(uint8_t[3]){0}, 3}}},
|
|
{ .attr_count = 3,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[1]){0}, 1},
|
|
{'B', &(uint8_t[2]){0}, 2},
|
|
{'C', &(uint8_t[3]){0}, 3}}}};
|
|
lfs_file_opencfg(&lfs, &writer, "shared",
|
|
WRMODE, &writercfg) => 0;
|
|
for (int i = 0; i < READERS; i++) {
|
|
lfs_file_opencfg(&lfs, &readers[i], "shared",
|
|
RDMODE, &readercfgs[i]) => 0;
|
|
}
|
|
|
|
// perform operations while all readers are open
|
|
writercfg.attrs[0].size = 1;
|
|
memcpy(writercfg.attrs[0].buffer, "0", 1);
|
|
writercfg.attrs[1].size = 2;
|
|
memcpy(writercfg.attrs[1].buffer, "11", 2);
|
|
writercfg.attrs[2].size = 3;
|
|
memcpy(writercfg.attrs[2].buffer, "222", 3);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &writer, &nums[j % 10], 1) => 1;
|
|
}
|
|
|
|
for (int i = 0; i < READERS; i++) {
|
|
assert(readercfgs[i].attrs[0].size == 1);
|
|
assert(memcmp(readercfgs[i].attrs[0].buffer, "a", 1) == 0);
|
|
assert(readercfgs[i].attrs[1].size == 2);
|
|
assert(memcmp(readercfgs[i].attrs[1].buffer, "bb", 2) == 0);
|
|
assert(readercfgs[i].attrs[2].size == 3);
|
|
assert(memcmp(readercfgs[i].attrs[2].buffer, "ccc", 3) == 0);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
}
|
|
|
|
// sync, now write should reflect in all open files
|
|
lfs_file_sync(&lfs, &writer) => 0;
|
|
|
|
for (int i = 0; i < READERS; i++) {
|
|
assert(readercfgs[i].attrs[0].size == 1);
|
|
assert(memcmp(readercfgs[i].attrs[0].buffer, "0", 1) == 0);
|
|
assert(readercfgs[i].attrs[1].size == 2);
|
|
assert(memcmp(readercfgs[i].attrs[1].buffer, "11", 2) == 0);
|
|
assert(readercfgs[i].attrs[2].size == 3);
|
|
assert(memcmp(readercfgs[i].attrs[2].buffer, "222", 3) == 0);
|
|
lfs_file_rewind(&lfs, &readers[i]) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
}
|
|
|
|
// double check our writer reflects its own changes
|
|
if (WRMODE == LFS_O_RDWR) {
|
|
assert(writercfg.attrs[0].size == 1);
|
|
assert(memcmp(writercfg.attrs[0].buffer, "0", 1) == 0);
|
|
assert(writercfg.attrs[1].size == 2);
|
|
assert(memcmp(writercfg.attrs[1].buffer, "11", 2) == 0);
|
|
assert(writercfg.attrs[2].size == 3);
|
|
assert(memcmp(writercfg.attrs[2].buffer, "222", 3) == 0);
|
|
lfs_file_rewind(&lfs, &writer) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &writer, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
}
|
|
|
|
// now try explicit lfs_setattr calls, this should still update open files
|
|
lfs_setattr(&lfs, "shared", 'A', "A", 1) => 0;
|
|
lfs_setattr(&lfs, "shared", 'B', "BB", 2) => 0;
|
|
lfs_setattr(&lfs, "shared", 'C', "CCC", 3) => 0;
|
|
|
|
for (int i = 0; i < READERS; i++) {
|
|
assert(readercfgs[i].attrs[0].size == 1);
|
|
assert(memcmp(readercfgs[i].attrs[0].buffer, "A", 1) == 0);
|
|
assert(readercfgs[i].attrs[1].size == 2);
|
|
assert(memcmp(readercfgs[i].attrs[1].buffer, "BB", 2) == 0);
|
|
assert(readercfgs[i].attrs[2].size == 3);
|
|
assert(memcmp(readercfgs[i].attrs[2].buffer, "CCC", 3) == 0);
|
|
lfs_file_rewind(&lfs, &readers[i]) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &readers[i], buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
}
|
|
|
|
if (WRMODE == LFS_O_RDWR) {
|
|
assert(writercfg.attrs[0].size == 1);
|
|
assert(memcmp(writercfg.attrs[0].buffer, "A", 1) == 0);
|
|
assert(writercfg.attrs[1].size == 2);
|
|
assert(memcmp(writercfg.attrs[1].buffer, "BB", 2) == 0);
|
|
assert(writercfg.attrs[2].size == 3);
|
|
assert(memcmp(writercfg.attrs[2].buffer, "CCC", 3) == 0);
|
|
lfs_file_rewind(&lfs, &writer) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &writer, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
} else if (WRMODE == LFS_O_WRONLY) {
|
|
// this should NOT update wronly attributes, these may be
|
|
// stored in read-only memory
|
|
assert(writercfg.attrs[0].size == 1);
|
|
assert(memcmp(writercfg.attrs[0].buffer, "0", 1) == 0);
|
|
assert(writercfg.attrs[1].size == 2);
|
|
assert(memcmp(writercfg.attrs[1].buffer, "11", 2) == 0);
|
|
assert(writercfg.attrs[2].size == 3);
|
|
assert(memcmp(writercfg.attrs[2].buffer, "222", 3) == 0);
|
|
}
|
|
|
|
for (int i = 0; i < READERS; i++) {
|
|
lfs_file_close(&lfs, &readers[i]) => 0;
|
|
}
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[[case]] # simple snapshot for reading
|
|
define.SIZE = [10, 100, 1000, 10000]
|
|
code = '''
|
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
|
const char nums[] = "0123456789";
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
const struct lfs_file_config filecfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', "abcd", 4},
|
|
},
|
|
};
|
|
lfs_file_opencfg(&lfs, &file, "open_me",
|
|
LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
// open reader/writer/snapshot
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_t reader;
|
|
const struct lfs_file_config readercfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[4]){0}, 4}
|
|
},
|
|
};
|
|
lfs_file_t writer;
|
|
const struct lfs_file_config writercfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[4]){0}, 4}
|
|
},
|
|
};
|
|
lfs_file_t snapshot;
|
|
const struct lfs_file_config snapshotcfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[4]){0}, 4}
|
|
},
|
|
};
|
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
lfs_file_opencfg(&lfs, &writer, "open_me",
|
|
LFS_O_WRONLY, &writercfg) => 0;
|
|
lfs_file_opencfg(&lfs, &snapshot, "open_me",
|
|
LFS_O_RDONLY | LFS_O_SNAPSHOT, &snapshotcfg) => 0;
|
|
|
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = 0; j < SIZE/2; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
|
|
assert(memcmp(snapshotcfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = 0; j < SIZE/2; j++) {
|
|
lfs_file_read(&lfs, &snapshot, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
|
|
// write file
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &writer, &nums[j % 10], 1) => 1;
|
|
}
|
|
memcpy(writercfg.attrs[0].buffer, "0123", 4);
|
|
lfs_file_sync(&lfs, &writer) => 0;
|
|
|
|
// reader should change
|
|
assert(memcmp(readercfg.attrs[0].buffer, "0123", 4) == 0);
|
|
for (int j = SIZE/2; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
|
|
// snapshot should remain unchanged
|
|
assert(memcmp(snapshotcfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = SIZE/2; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &snapshot, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_file_close(&lfs, &writer) => 0;
|
|
lfs_file_close(&lfs, &snapshot) => 0;
|
|
|
|
// disk should change
|
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
assert(memcmp(readercfg.attrs[0].buffer, "0123", 4) == 0);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
assert(memcmp(readercfg.attrs[0].buffer, "0123", 4) == 0);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[[case]] # simple snapshot for writing
|
|
define.SIZE = [10, 100, 1000, 10000]
|
|
code = '''
|
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
|
const char nums[] = "0123456789";
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
const struct lfs_file_config filecfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', "abcd", 4},
|
|
},
|
|
};
|
|
lfs_file_opencfg(&lfs, &file, "open_me",
|
|
LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
// open reader/snapshot
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_t reader;
|
|
const struct lfs_file_config readercfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[4]){0}, 4}
|
|
},
|
|
};
|
|
lfs_file_t snapshot;
|
|
const struct lfs_file_config snapshotcfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[4]){0}, 4}
|
|
},
|
|
};
|
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
lfs_file_opencfg(&lfs, &snapshot, "open_me",
|
|
LFS_O_RDWR | LFS_O_SNAPSHOT, &snapshotcfg) => 0;
|
|
|
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = 0; j < SIZE/2; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
|
|
assert(memcmp(snapshotcfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &snapshot, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
|
|
// modify snapshot
|
|
lfs_file_rewind(&lfs, &snapshot) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &snapshot, &nums[j % 10], 1) => 1;
|
|
}
|
|
memcpy(snapshotcfg.attrs[0].buffer, "0123", 4);
|
|
|
|
lfs_file_rewind(&lfs, &snapshot) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &snapshot, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
|
|
lfs_file_sync(&lfs, &snapshot) => 0;
|
|
|
|
// reader should not change
|
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = SIZE/2; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
|
|
// snapshot should changed
|
|
assert(memcmp(snapshotcfg.attrs[0].buffer, "0123", 4) == 0);
|
|
lfs_file_rewind(&lfs, &snapshot) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &snapshot, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_file_close(&lfs, &snapshot) => 0;
|
|
|
|
// disk should not change
|
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[[case]] # temporary files
|
|
define.SIZE = [10, 100, 1000, 10000]
|
|
define.TMP_PATH = 'range(4)'
|
|
code = '''
|
|
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
|
const char nums[] = "0123456789";
|
|
const char caps[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
const struct lfs_file_config filecfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', "abcd", 4},
|
|
},
|
|
};
|
|
lfs_file_opencfg(&lfs, &file, "open_me",
|
|
LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_file_opencfg(&lfs, &file, "dont_open_me",
|
|
LFS_O_CREAT | LFS_O_WRONLY, &filecfg) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &file, &alphas[j % 26], 1) => 1;
|
|
}
|
|
lfs_file_close(&lfs, &file) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
// open reader/writer/temp
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_t reader;
|
|
const struct lfs_file_config readercfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[4]){0}, 4}
|
|
},
|
|
};
|
|
lfs_file_t writer;
|
|
const struct lfs_file_config writercfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[4]){0}, 4}
|
|
},
|
|
};
|
|
lfs_file_t tmp;
|
|
const struct lfs_file_config tmpcfg = {
|
|
.attr_count = 1,
|
|
.attrs = (struct lfs_attr[]){
|
|
{'A', &(uint8_t[4]){0}, 4}
|
|
},
|
|
};
|
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
lfs_file_opencfg(&lfs, &writer, "open_me",
|
|
LFS_O_WRONLY, &writercfg) => 0;
|
|
const char *tmp_paths[] = {NULL, "/", "/tmp", "/open_me.tmp"};
|
|
lfs_file_opencfg(&lfs, &tmp, tmp_paths[TMP_PATH],
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_SNAPSHOT, &tmpcfg) => 0;
|
|
|
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = 0; j < SIZE/3; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
|
|
assert(memcmp(tmpcfg.attrs[0].buffer, "\0\0\0\0", 4) == 0);
|
|
assert(lfs_file_size(&lfs, &tmp) == 0);
|
|
|
|
// write to tmp
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &tmp, &nums[j % 10], 1) => 1;
|
|
}
|
|
memcpy(tmpcfg.attrs[0].buffer, "0123", 4);
|
|
|
|
lfs_file_rewind(&lfs, &tmp) => 0;
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &tmp, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
|
|
lfs_file_sync(&lfs, &tmp) => 0;
|
|
|
|
// reader should not change
|
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = SIZE/3; j < 2*SIZE/3; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
|
|
// tmp should change
|
|
assert(memcmp(tmpcfg.attrs[0].buffer, "0123", 4) == 0);
|
|
lfs_file_rewind(&lfs, &tmp) => 0;
|
|
for (int j = 0; j < SIZE/2; j++) {
|
|
lfs_file_read(&lfs, &tmp, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
|
|
// write to file
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_write(&lfs, &writer, &caps[j % 26], 1) => 1;
|
|
}
|
|
memcpy(writercfg.attrs[0].buffer, "ABCD", 4);
|
|
lfs_file_sync(&lfs, &writer) => 0;
|
|
|
|
// reader should change
|
|
assert(memcmp(readercfg.attrs[0].buffer, "ABCD", 4) == 0);
|
|
for (int j = 2*SIZE/3; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == caps[j % 26]);
|
|
}
|
|
|
|
// tmp should not change
|
|
assert(memcmp(tmpcfg.attrs[0].buffer, "0123", 4) == 0);
|
|
for (int j = SIZE/2; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &tmp, buffer, 1) => 1;
|
|
assert(buffer[0] == nums[j % 10]);
|
|
}
|
|
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_file_close(&lfs, &writer) => 0;
|
|
lfs_file_close(&lfs, &tmp) => 0;
|
|
|
|
// tmp should not appear on disk
|
|
lfs_dir_open(&lfs, &dir, "/") => 0;
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(strcmp(info.name, ".") == 0);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(strcmp(info.name, "..") == 0);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(strcmp(info.name, "dont_open_me") == 0);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(strcmp(info.name, "open_me") == 0);
|
|
lfs_dir_read(&lfs, &dir, &info) => 0;
|
|
lfs_dir_close(&lfs, &dir) => 0;
|
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
assert(memcmp(readercfg.attrs[0].buffer, "ABCD", 4) == 0);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == caps[j % 26]);
|
|
}
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_file_opencfg(&lfs, &reader, "dont_open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_dir_open(&lfs, &dir, "/") => 0;
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(strcmp(info.name, ".") == 0);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(strcmp(info.name, "..") == 0);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(strcmp(info.name, "dont_open_me") == 0);
|
|
lfs_dir_read(&lfs, &dir, &info) => 1;
|
|
assert(info.type == LFS_TYPE_REG);
|
|
assert(strcmp(info.name, "open_me") == 0);
|
|
lfs_dir_read(&lfs, &dir, &info) => 0;
|
|
lfs_dir_close(&lfs, &dir) => 0;
|
|
lfs_file_opencfg(&lfs, &reader, "open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
assert(memcmp(readercfg.attrs[0].buffer, "ABCD", 4) == 0);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == caps[j % 26]);
|
|
}
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_file_opencfg(&lfs, &reader, "dont_open_me",
|
|
LFS_O_RDONLY, &readercfg) => 0;
|
|
assert(memcmp(readercfg.attrs[0].buffer, "abcd", 4) == 0);
|
|
for (int j = 0; j < SIZE; j++) {
|
|
lfs_file_read(&lfs, &reader, buffer, 1) => 1;
|
|
assert(buffer[0] == alphas[j % 26]);
|
|
}
|
|
lfs_file_close(&lfs, &reader) => 0;
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[[case]] # test snapshot open errors
|
|
code = '''
|
|
lfs_format(&lfs, &cfg) => 0;
|
|
lfs_mount(&lfs, &cfg) => 0;
|
|
lfs_file_open(&lfs, &file, NULL,
|
|
LFS_O_RDWR | LFS_O_SNAPSHOT) => LFS_ERR_ISDIR;
|
|
lfs_file_open(&lfs, &file, "/",
|
|
LFS_O_RDWR | LFS_O_SNAPSHOT) => LFS_ERR_ISDIR;
|
|
lfs_file_open(&lfs, &file, "/tmp",
|
|
LFS_O_RDWR | LFS_O_SNAPSHOT) => LFS_ERR_NOENT;
|
|
lfs_file_open(&lfs, &file, "/tmp/",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_SNAPSHOT) => LFS_ERR_NOENT;
|
|
lfs_file_open(&lfs, &file, "/tmp/tmp",
|
|
LFS_O_RDWR | LFS_O_CREAT | LFS_O_SNAPSHOT) => LFS_ERR_NOENT;
|
|
lfs_unmount(&lfs) => 0;
|
|
'''
|