a75537faff
This adds a couple functions that treat files as simple key-value pairs:
- lfs3_get - Read a file
- lfs3_size - Get the size of a file
- lfs3_set - Write a file
- lfs3_remove - Remove a file (this one already exists!)
The idea is the only real difference between a filesystem and key-value
store in the microcontroller space is the API, and the key-value API
_is_ much easier to use.
It also opens the door to making the file API opt-out in the future to
trade code cost for feature set. littlefs will probably never be
competitive with other microcontroller-scale key-value stores, but it
may be interesting for systems already using littlefs for other storage.
And don't worry, these are still files, so they can always be opened
with the full file API when more advanced operations are needed.
These APIs also matches the custom attribute APIs, which makes sense
because they're both key-values. Any mismatch should be considered an
API bug, because the best user interface is a consistent one.
This new API is tested in tests/test_kv.toml.
---
At the moment the implementation is naive, just sitting on top of the
file API. This works remarkably well thanks to littlefs's cache
bypassing logic, but does have some downsides:
- lfs3_set always writes two commits: one for the stickynote and one for
the file sync.
Unfortunately this is a fundamental limitation of littlefs's file API.
One nice benefit of lfs3_set is in theory we can bypass this
limitation, but not if we just sit on top of the file API.
- There may be code savings from more tightly integrating the key-value
code.
This also highlighted an awkward corner case with per-file cache
configuration in which the buffer needs to be non-null even if zero. Not
the end of the world, but just a bit awkward. Maybe this deserves
revisiting in the config API rework?
---
Code changes were relatively minimal given that this is a whole new API,
unfortunately the stack took quite a hit:
code stack ctx
before: 37352 2280 636
after: 37644 (+0.8%) 2448 (+7.4%) 636 (+0.0%)
The stack surprised me, but in hindsight it makes sense. In sitting on
top of the reset of the codebase, the key-value API adds very little
code, but every stack allocation in these functions add to the stack
hot-path.
This isn't the end of the world, and it's actually probably a good thing
to have an lfs3_file_t allocated in the stack hot-path. lfs3_file_t's
size has been a bit difficult to track thanks to struct lfs3_info
dominating ctx measurements...
5046 lines
161 KiB
TOML
5046 lines
161 KiB
TOML
# Custom attribute tests
|
|
after = ['test_files', 'test_fsync', 'test_stickynotes']
|
|
|
|
|
|
## General setattr/getattr tests
|
|
|
|
# test some simple attr operations
|
|
[cases.test_attrs_setattr]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
# FILETYPE=3 => root
|
|
defines.FILETYPE = [0, 1, 2, 3]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
lfs3_file_t file;
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
path = "snail";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else if (FILETYPE == 2) {
|
|
path = "armadillo";
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
|
|
// do nothing for root
|
|
} else {
|
|
path = "/";
|
|
}
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, path, 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, path, 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, path, 'c', c, strlen(c)) => 0;
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, path, 'a') => strlen(a);
|
|
lfs3_sizeattr(&lfs3, path, 'b') => strlen(b);
|
|
lfs3_sizeattr(&lfs3, path, 'c') => strlen(c);
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, sizeof(rbuf)) => strlen(a);
|
|
assert(memcmp(rbuf, a, strlen(a)) == 0);
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, sizeof(rbuf)) => strlen(b);
|
|
assert(memcmp(rbuf, b, strlen(b)) == 0);
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, sizeof(rbuf)) => strlen(c);
|
|
assert(memcmp(rbuf, c, strlen(c)) == 0);
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test truncated getattr calls still work
|
|
[cases.test_attrs_setattr_trunc]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
# FILETYPE=3 => root
|
|
defines.FILETYPE = [0, 1, 2, 3]
|
|
defines.BUFSIZE = [1, 4, 7]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
lfs3_file_t file;
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
path = "snail";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else if (FILETYPE == 2) {
|
|
path = "armadillo";
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
|
|
// do nothing for root
|
|
} else {
|
|
path = "/";
|
|
}
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, path, 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, path, 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, path, 'c', c, strlen(c)) => 0;
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, path, 'a') => strlen(a);
|
|
lfs3_sizeattr(&lfs3, path, 'b') => strlen(b);
|
|
lfs3_sizeattr(&lfs3, path, 'c') => strlen(c);
|
|
|
|
// mark rbuf so we can detect overflow
|
|
uint8_t rbuf[256];
|
|
rbuf[BUFSIZE] = '!';
|
|
// try reading truncated attrs
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, BUFSIZE) => BUFSIZE;
|
|
assert(memcmp(rbuf, a, BUFSIZE) == 0);
|
|
assert(rbuf[BUFSIZE] == '!');
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, BUFSIZE) => BUFSIZE;
|
|
assert(memcmp(rbuf, b, BUFSIZE) == 0);
|
|
assert(rbuf[BUFSIZE] == '!');
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, BUFSIZE) => BUFSIZE;
|
|
assert(memcmp(rbuf, c, BUFSIZE) == 0);
|
|
assert(rbuf[BUFSIZE] == '!');
|
|
|
|
// try reading the full attrs
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, sizeof(rbuf)) => strlen(a);
|
|
assert(memcmp(rbuf, a, strlen(a)) == 0);
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, sizeof(rbuf)) => strlen(b);
|
|
assert(memcmp(rbuf, b, strlen(b)) == 0);
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, sizeof(rbuf)) => strlen(c);
|
|
assert(memcmp(rbuf, c, strlen(c)) == 0);
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test ENOATTR works
|
|
[cases.test_attrs_setattr_noattr]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
# FILETYPE=3 => root
|
|
defines.FILETYPE = [0, 1, 2, 3]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
lfs3_file_t file;
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
path = "snail";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else if (FILETYPE == 2) {
|
|
path = "armadillo";
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
|
|
// do nothing for root
|
|
} else {
|
|
path = "/";
|
|
}
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, path, 'a') => LFS3_ERR_NOATTR;
|
|
lfs3_sizeattr(&lfs3, path, 'b') => LFS3_ERR_NOATTR;
|
|
lfs3_sizeattr(&lfs3, path, 'c') => LFS3_ERR_NOATTR;
|
|
|
|
// try reading attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that updating attrs works
|
|
[cases.test_attrs_setattr_update]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
# FILETYPE=3 => root
|
|
defines.FILETYPE = [0, 1, 2, 3]
|
|
# update based on this mask
|
|
defines.MASK = 'range(0x8)'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
lfs3_file_t file;
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
path = "snail";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else if (FILETYPE == 2) {
|
|
path = "armadillo";
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
|
|
// do nothing for root
|
|
} else {
|
|
path = "/";
|
|
}
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, path, 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, path, 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, path, 'c', c, strlen(c)) => 0;
|
|
|
|
// rewrite some attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
if (MASK & 0x1) {
|
|
lfs3_setattr(&lfs3, path, 'a', a_, strlen(a_)) => 0;
|
|
}
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
if (MASK & 0x2) {
|
|
lfs3_setattr(&lfs3, path, 'b', b_, strlen(b_)) => 0;
|
|
}
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
if (MASK & 0x4) {
|
|
lfs3_setattr(&lfs3, path, 'c', c_, strlen(c_)) => 0;
|
|
}
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
if (MASK & 0x1) {
|
|
lfs3_sizeattr(&lfs3, path, 'a') => strlen(a_);
|
|
} else {
|
|
lfs3_sizeattr(&lfs3, path, 'a') => strlen(a);
|
|
}
|
|
if (MASK & 0x2) {
|
|
lfs3_sizeattr(&lfs3, path, 'b') => strlen(b_);
|
|
} else {
|
|
lfs3_sizeattr(&lfs3, path, 'b') => strlen(b);
|
|
}
|
|
if (MASK & 0x4) {
|
|
lfs3_sizeattr(&lfs3, path, 'c') => strlen(c_);
|
|
} else {
|
|
lfs3_sizeattr(&lfs3, path, 'c') => strlen(c);
|
|
}
|
|
|
|
// try reading attrs
|
|
uint8_t rbuf[256];
|
|
if (MASK & 0x1) {
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, sizeof(rbuf)) => strlen(a_);
|
|
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
|
|
} else {
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, sizeof(rbuf)) => strlen(a);
|
|
assert(memcmp(rbuf, a, strlen(a)) == 0);
|
|
}
|
|
if (MASK & 0x2) {
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, sizeof(rbuf)) => strlen(b_);
|
|
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
|
|
} else {
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, sizeof(rbuf)) => strlen(b);
|
|
assert(memcmp(rbuf, b, strlen(b)) == 0);
|
|
}
|
|
if (MASK & 0x4) {
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, sizeof(rbuf)) => strlen(c_);
|
|
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
|
|
} else {
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, sizeof(rbuf)) => strlen(c);
|
|
assert(memcmp(rbuf, c, strlen(c)) == 0);
|
|
}
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test removing attrs
|
|
[cases.test_attrs_removeattr]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
# FILETYPE=3 => root
|
|
defines.FILETYPE = [0, 1, 2, 3]
|
|
# remove based on this mask
|
|
defines.MASK = 'range(0x8)'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
lfs3_file_t file;
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
path = "snail";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else if (FILETYPE == 2) {
|
|
path = "armadillo";
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
|
|
// do nothing for root
|
|
} else {
|
|
path = "/";
|
|
}
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, path, 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, path, 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, path, 'c', c, strlen(c)) => 0;
|
|
|
|
// remove some attrs
|
|
if (MASK & 0x1) {
|
|
lfs3_removeattr(&lfs3, path, 'a') => 0;
|
|
}
|
|
if (MASK & 0x2) {
|
|
lfs3_removeattr(&lfs3, path, 'b') => 0;
|
|
}
|
|
if (MASK & 0x4) {
|
|
lfs3_removeattr(&lfs3, path, 'c') => 0;
|
|
}
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
if (MASK & 0x1) {
|
|
lfs3_sizeattr(&lfs3, path, 'a') => LFS3_ERR_NOATTR;
|
|
} else {
|
|
lfs3_sizeattr(&lfs3, path, 'a') => strlen(a);
|
|
}
|
|
if (MASK & 0x2) {
|
|
lfs3_sizeattr(&lfs3, path, 'b') => LFS3_ERR_NOATTR;
|
|
} else {
|
|
lfs3_sizeattr(&lfs3, path, 'b') => strlen(b);
|
|
}
|
|
if (MASK & 0x4) {
|
|
lfs3_sizeattr(&lfs3, path, 'c') => LFS3_ERR_NOATTR;
|
|
} else {
|
|
lfs3_sizeattr(&lfs3, path, 'c') => strlen(c);
|
|
}
|
|
|
|
// try reading the full attrs
|
|
uint8_t rbuf[256];
|
|
if (MASK & 0x1) {
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, sizeof(rbuf))
|
|
=> LFS3_ERR_NOATTR;
|
|
} else {
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, sizeof(rbuf))
|
|
=> strlen(a);
|
|
assert(memcmp(rbuf, a, strlen(a)) == 0);
|
|
}
|
|
if (MASK & 0x2) {
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, sizeof(rbuf))
|
|
=> LFS3_ERR_NOATTR;
|
|
} else {
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, sizeof(rbuf))
|
|
=> strlen(b);
|
|
assert(memcmp(rbuf, b, strlen(b)) == 0);
|
|
}
|
|
if (MASK & 0x4) {
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, sizeof(rbuf))
|
|
=> LFS3_ERR_NOATTR;
|
|
} else {
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, sizeof(rbuf))
|
|
=> strlen(c);
|
|
assert(memcmp(rbuf, c, strlen(c)) == 0);
|
|
}
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
# test the full range of attrs
|
|
[cases.test_attrs_all]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
# FILETYPE=3 => root
|
|
defines.FILETYPE = [0, 1, 2, 3]
|
|
defines.SIZE = 4
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
lfs3_file_t file;
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
path = "snail";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else if (FILETYPE == 2) {
|
|
path = "armadillo";
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
|
|
// do nothing for root
|
|
} else {
|
|
path = "/";
|
|
}
|
|
|
|
// try creating every attr, this tests any encoding quirks
|
|
uint32_t prng = 42;
|
|
for (uint16_t a = 0; a < 0x100; a++) {
|
|
// create the attr
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_setattr(&lfs3, path, a, wbuf, SIZE) => 0;
|
|
|
|
// try getting the attr size
|
|
lfs3_sizeattr(&lfs3, path, a) => SIZE;
|
|
// try reading the attr
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, a, rbuf, sizeof(rbuf)) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
|
|
// remove the attr
|
|
lfs3_removeattr(&lfs3, path, a) => 0;
|
|
}
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test creating a bunch of attrs
|
|
[cases.test_attrs_many]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
# FILETYPE=3 => root
|
|
defines.FILETYPE = [0, 1, 2, 3]
|
|
defines.M = 40
|
|
defines.SIZE = 4
|
|
defines.COMPACT = [false, true]
|
|
defines.GC_FLAGS = 'LFS3_GC_COMPACT'
|
|
defines.GC_STEPS = -1
|
|
defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2'
|
|
if = 'LFS3_IFDEF_GC(true, !COMPACT)'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
lfs3_file_t file;
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
path = "snail";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else if (FILETYPE == 2) {
|
|
path = "armadillo";
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
|
|
// do nothing for root
|
|
} else {
|
|
path = "/";
|
|
}
|
|
|
|
// create M attrs
|
|
uint32_t prng = 42;
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_setattr(&lfs3, path, a, wbuf, SIZE) => 0;
|
|
}
|
|
|
|
// try compacting?
|
|
#ifdef LFS3_GC
|
|
if (COMPACT) {
|
|
lfs3_fs_gc(&lfs3) => 0;
|
|
}
|
|
#endif
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
lfs3_sizeattr(&lfs3, path, a) => SIZE;
|
|
}
|
|
// try reading the attrs
|
|
prng = 42;
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, a, rbuf, sizeof(rbuf)) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test creating a bunch of attrs on a bunch of files
|
|
[cases.test_attrs_many_many]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
defines.FILETYPE = [0, 1, 2]
|
|
defines.N = 64
|
|
defines.M = 4
|
|
defines.SIZE = 4
|
|
defines.COMPACT = [false, true]
|
|
defines.GC_FLAGS = 'LFS3_GC_COMPACT'
|
|
defines.GC_STEPS = -1
|
|
defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2'
|
|
if = 'LFS3_IFDEF_GC(true, !COMPACT)'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create N files
|
|
uint32_t prng = 42;
|
|
lfs3_file_t files[N];
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
char path[256];
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", i);
|
|
lfs3_file_open(&lfs3, &files[i], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &files[i], "meow", strlen("meow"))
|
|
=> strlen("meow");
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", i);
|
|
lfs3_file_open(&lfs3, &files[i], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &files[i],
|
|
"snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", i);
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
}
|
|
|
|
// create M attrs
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_setattr(&lfs3, path, a, wbuf, SIZE) => 0;
|
|
}
|
|
}
|
|
|
|
// try compacting?
|
|
#ifdef LFS3_GC
|
|
if (COMPACT) {
|
|
lfs3_fs_gc(&lfs3) => 0;
|
|
}
|
|
#endif
|
|
|
|
if (FILETYPE == 1) {
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
}
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
prng = 42;
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
char path[256];
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
// dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
lfs3_sizeattr(&lfs3, path, a) => SIZE;
|
|
}
|
|
// try reading the attrs
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, a, rbuf, sizeof(rbuf)) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# fuzz attrs
|
|
[cases.test_attrs_fuzz]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
# FILETYPE=3 => root
|
|
defines.FILETYPE = [0, 1, 2, 3]
|
|
defines.M = 10
|
|
defines.SIZE = 4
|
|
defines.OPS = '4*M'
|
|
defines.SEED = 'range(20)'
|
|
fuzz = 'SEED'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
lfs3_file_t file;
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
path = "snail";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else if (FILETYPE == 2) {
|
|
path = "armadillo";
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
|
|
// do nothing for root
|
|
} else {
|
|
path = "/";
|
|
}
|
|
|
|
// set up a simulation to compare against
|
|
uint32_t *sim_prngs = malloc(M*sizeof(uint32_t));
|
|
memset(sim_prngs, 0, M*sizeof(uint32_t));
|
|
|
|
uint32_t prng = SEED;
|
|
for (lfs3_size_t i = 0; i < OPS; i++) {
|
|
// choose which operation to do
|
|
uint8_t op = TEST_PRNG(&prng) % 2;
|
|
|
|
// create an attr?
|
|
if (op == 0) {
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
// choose a prng
|
|
uint32_t wprng = TEST_PRNG(&prng);
|
|
|
|
// create the attr
|
|
uint32_t wprng_ = wprng;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
lfs3_setattr(&lfs3, path, a, wbuf, SIZE) => 0;
|
|
|
|
// update our sim
|
|
sim_prngs[a] = wprng;
|
|
|
|
// remove an attr?
|
|
} else if (op == 1) {
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
|
|
// remove the attr
|
|
if (sim_prngs[a]) {
|
|
lfs3_removeattr(&lfs3, path, a) => 0;
|
|
} else {
|
|
lfs3_removeattr(&lfs3, path, a) => LFS3_ERR_NOATTR;
|
|
}
|
|
|
|
// update our sim
|
|
sim_prngs[a] = 0;
|
|
}
|
|
}
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting each attr size
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[a]) {
|
|
lfs3_sizeattr(&lfs3, path, a) => SIZE;
|
|
} else {
|
|
lfs3_sizeattr(&lfs3, path, a) => LFS3_ERR_NOATTR;
|
|
}
|
|
}
|
|
// try reading each attr
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[a]) {
|
|
uint32_t wprng_ = sim_prngs[a];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, a, rbuf, sizeof(rbuf)) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
} else {
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, a, rbuf, sizeof(rbuf))
|
|
=> LFS3_ERR_NOATTR;
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean up sim/lfs3
|
|
free(sim_prngs);
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# fuzz attrs on multiple files
|
|
[cases.test_attrs_fuzz_fuzz]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
defines.FILETYPE = [0, 1, 2]
|
|
defines.N = 64
|
|
defines.M = 4
|
|
defines.SIZE = 4
|
|
defines.OPS = '4*N*M'
|
|
defines.SEED = 'range(20)'
|
|
fuzz = 'SEED'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create N files
|
|
lfs3_file_t files[N];
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
char path[256];
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", i);
|
|
lfs3_file_open(&lfs3, &files[i], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &files[i], "meow", strlen("meow"))
|
|
=> strlen("meow");
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", i);
|
|
lfs3_file_open(&lfs3, &files[i], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &files[i],
|
|
"snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", i);
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
}
|
|
}
|
|
|
|
// set up a simulation to compare against
|
|
uint32_t *sim_prngs = malloc(N*M*sizeof(uint32_t));
|
|
memset(sim_prngs, 0, N*M*sizeof(uint32_t));
|
|
|
|
uint32_t prng = SEED;
|
|
for (lfs3_size_t i = 0; i < OPS; i++) {
|
|
// choose which operation to do
|
|
uint8_t op = TEST_PRNG(&prng) % 2;
|
|
|
|
// create an attr?
|
|
if (op == 0) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
char path[256];
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
// dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
}
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
// choose a prng
|
|
uint32_t wprng = TEST_PRNG(&prng);
|
|
|
|
// create the attr
|
|
uint32_t wprng_ = wprng;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
lfs3_setattr(&lfs3, path, a, wbuf, SIZE) => 0;
|
|
|
|
// update our sim
|
|
sim_prngs[x*M+a] = wprng;
|
|
|
|
// remove an attr?
|
|
} else if (op == 1) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
char path[256];
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
// dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
}
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
|
|
// remove the attr
|
|
if (sim_prngs[x*M+a]) {
|
|
lfs3_removeattr(&lfs3, path, a) => 0;
|
|
} else {
|
|
lfs3_removeattr(&lfs3, path, a) => LFS3_ERR_NOATTR;
|
|
}
|
|
|
|
// update our sim
|
|
sim_prngs[x*M+a] = 0;
|
|
}
|
|
}
|
|
|
|
if (FILETYPE == 1) {
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
}
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
char path[256];
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
// dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
}
|
|
|
|
// try getting each attr size
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[x*M+a]) {
|
|
lfs3_sizeattr(&lfs3, path, a) => SIZE;
|
|
} else {
|
|
lfs3_sizeattr(&lfs3, path, a) => LFS3_ERR_NOATTR;
|
|
}
|
|
}
|
|
// try reading each attr
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[x*M+a]) {
|
|
uint32_t wprng_ = sim_prngs[x*M+a];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, a, rbuf, sizeof(rbuf)) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
} else {
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, a, rbuf, sizeof(rbuf))
|
|
=> LFS3_ERR_NOATTR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean up sim/lfs3
|
|
free(sim_prngs);
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
# test that removing a file removes all attrs
|
|
[cases.test_attrs_rm]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
defines.FILETYPE = [0, 1, 2]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
lfs3_file_t file;
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
path = "snail";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else {
|
|
path = "armadillo";
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
}
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, path, 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, path, 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, path, 'c', c, strlen(c)) => 0;
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, path) => 0;
|
|
|
|
// create the file again
|
|
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "miao", strlen("miao"))
|
|
=> strlen("miao");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_,
|
|
"bruit d'escargot", strlen("bruit d'escargot"))
|
|
=> strlen("bruit d'escargot");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// dir?
|
|
} else {
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
}
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, path, 'a') => LFS3_ERR_NOATTR;
|
|
lfs3_sizeattr(&lfs3, path, 'b') => LFS3_ERR_NOATTR;
|
|
lfs3_sizeattr(&lfs3, path, 'c') => LFS3_ERR_NOATTR;
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that moving onto a file removes all attrs
|
|
[cases.test_attrs_mv_dst]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
defines.FILETYPE = [0, 1, 2]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
lfs3_file_t file;
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
path = "snail";
|
|
lfs3_file_open(&lfs3, &file, path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "snailnoise", strlen("snailnoise"))
|
|
=> strlen("snailnoise");
|
|
|
|
// create a dir?
|
|
} else {
|
|
path = "armadillo";
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
}
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, path, 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, path, 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, path, 'c', c, strlen(c)) => 0;
|
|
|
|
// create another file and move it onto our file
|
|
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_,
|
|
"beaver", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "miao", strlen("miao"))
|
|
=> strlen("miao");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_,
|
|
"beaver", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_,
|
|
"bruit d'escargot", strlen("bruit d'escargot"))
|
|
=> strlen("bruit d'escargot");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// dir?
|
|
} else {
|
|
lfs3_mkdir(&lfs3, "beaver") => 0;
|
|
}
|
|
|
|
lfs3_rename(&lfs3, "beaver", path) => 0;
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, path, 'a') => LFS3_ERR_NOATTR;
|
|
lfs3_sizeattr(&lfs3, path, 'b') => LFS3_ERR_NOATTR;
|
|
lfs3_sizeattr(&lfs3, path, 'c') => LFS3_ERR_NOATTR;
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that moves bring over all attrs
|
|
[cases.test_attrs_mv_src]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
defines.FILETYPE = [0, 1, 2]
|
|
defines.REPLACE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
const char *path;
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
path = "cat";
|
|
// stickynote?
|
|
} else if (FILETYPE == 0) {
|
|
path = "snail";
|
|
// dir?
|
|
} else {
|
|
path = "armadillo";
|
|
}
|
|
|
|
// if replacing create a file to replace
|
|
if (REPLACE) {
|
|
// from file?
|
|
if (FILETYPE == 0) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_,
|
|
path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow"))
|
|
=> strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// from stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_,
|
|
path, LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "snail noise", strlen("snail noise"))
|
|
=> strlen("snail noise");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// from dir?
|
|
} else {
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
}
|
|
}
|
|
|
|
// create a file?
|
|
lfs3_file_t file;
|
|
if (FILETYPE == 0) {
|
|
lfs3_file_open(&lfs3, &file, "beaver",
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "miao", strlen("miao"))
|
|
=> strlen("miao");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
lfs3_file_open(&lfs3, &file,
|
|
"beaver", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file,
|
|
"bruit d'escargot", strlen("bruit d'escargot"))
|
|
=> strlen("bruit d'escargot");
|
|
|
|
// create a dir?
|
|
} else {
|
|
lfs3_mkdir(&lfs3, "beaver") => 0;
|
|
}
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "beaver", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "beaver", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "beaver", 'c', c, strlen(c)) => 0;
|
|
|
|
// move file
|
|
lfs3_rename(&lfs3, "beaver", path) => 0;
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, path, 'a') => strlen(a);
|
|
lfs3_sizeattr(&lfs3, path, 'b') => strlen(b);
|
|
lfs3_sizeattr(&lfs3, path, 'c') => strlen(c);
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, 'a', rbuf, sizeof(rbuf)) => strlen(a);
|
|
assert(memcmp(rbuf, a, strlen(a)) == 0);
|
|
lfs3_getattr(&lfs3, path, 'b', rbuf, sizeof(rbuf)) => strlen(b);
|
|
assert(memcmp(rbuf, b, strlen(b)) == 0);
|
|
lfs3_getattr(&lfs3, path, 'c', rbuf, sizeof(rbuf)) => strlen(c);
|
|
assert(memcmp(rbuf, c, strlen(c)) == 0);
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# fuzz attrs mixed with file moves and removes
|
|
[cases.test_attrs_mvrm_fuzz_fuzz]
|
|
# type of file to attach attrs to
|
|
# FILETYPE=0 => regular file
|
|
# FILETYPE=1 => stickynote
|
|
# FILETYPE=2 => directory
|
|
defines.FILETYPE = [0, 1, 2]
|
|
defines.N = 64
|
|
defines.M = 4
|
|
defines.SIZE = 4
|
|
defines.OPS = '4*N*M'
|
|
defines.SEED = 'range(20)'
|
|
fuzz = 'SEED'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create N files
|
|
lfs3_file_t files[N];
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
char path[256];
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", i);
|
|
lfs3_file_open(&lfs3, &files[i], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &files[i], "meow", strlen("meow"))
|
|
=> strlen("meow");
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", i);
|
|
lfs3_file_open(&lfs3, &files[i], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &files[i],
|
|
"snail noise", strlen("snail noise"))
|
|
=> strlen("snail noise");
|
|
|
|
// create a dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", i);
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
}
|
|
}
|
|
|
|
// set up a simulation to compare against
|
|
uint32_t *sim_prngs = malloc(N*M*sizeof(uint32_t));
|
|
memset(sim_prngs, 0, N*M*sizeof(uint32_t));
|
|
|
|
uint32_t prng = SEED;
|
|
for (lfs3_size_t i = 0; i < OPS; i++) {
|
|
// choose which operation to do
|
|
uint8_t op = TEST_PRNG(&prng) % 4;
|
|
|
|
// create an attr?
|
|
if (op == 0) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
char path[256];
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
// dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
}
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
// choose a prng
|
|
uint32_t wprng = TEST_PRNG(&prng);
|
|
|
|
// create the attr
|
|
uint32_t wprng_ = wprng;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
lfs3_setattr(&lfs3, path, a, wbuf, SIZE) => 0;
|
|
|
|
// update our sim
|
|
sim_prngs[x*M+a] = wprng;
|
|
|
|
// remove an attr?
|
|
} else if (op == 1) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
char path[256];
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
// dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
}
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
|
|
// remove the attr
|
|
if (sim_prngs[x*M+a]) {
|
|
lfs3_removeattr(&lfs3, path, a) => 0;
|
|
} else {
|
|
lfs3_removeattr(&lfs3, path, a) => LFS3_ERR_NOATTR;
|
|
}
|
|
|
|
// update our sim
|
|
sim_prngs[x*M+a] = 0;
|
|
|
|
// remove a file?
|
|
} else if (op == 2) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
char path[256];
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
// dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
}
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, path) => 0;
|
|
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_close(&lfs3, &files[x]) => 0;
|
|
}
|
|
|
|
// but recreate the file so we always have something to
|
|
// attach attrs to
|
|
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
lfs3_file_open(&lfs3, &files[x], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &files[x], "miao", strlen("miao"))
|
|
=> strlen("miao");
|
|
lfs3_file_close(&lfs3, &files[x]) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
lfs3_file_open(&lfs3, &files[x], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &files[x],
|
|
"bruit d'escargot", strlen("bruit d'escargot"))
|
|
=> strlen("bruit d'escargot");
|
|
|
|
// create a dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
}
|
|
|
|
// update our sim
|
|
memset(&sim_prngs[x*M], 0, M*sizeof(uint32_t));
|
|
|
|
// rename a file?
|
|
} else if (op == 3) {
|
|
// choose two files
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
lfs3_size_t y = TEST_PRNG(&prng) % N;
|
|
char path[256];
|
|
char path_[256];
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
sprintf(path_, "cat%03x", y);
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
sprintf(path_, "snail%03x", y);
|
|
// dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
sprintf(path_, "armadillo%03x", y);
|
|
}
|
|
|
|
// rename the file
|
|
lfs3_rename(&lfs3, path, path_) => 0;
|
|
|
|
if (x != y) {
|
|
if (FILETYPE == 1) {
|
|
lfs3_file_t wait;
|
|
lfs3_file_open(&lfs3, &wait, path_,
|
|
LFS3_O_WRONLY) => 0;
|
|
lfs3_file_desync(&lfs3, &files[x]) => 0;
|
|
lfs3_file_close(&lfs3, &files[x]) => 0;
|
|
lfs3_file_close(&lfs3, &files[y]) => 0;
|
|
lfs3_file_open(&lfs3, &files[y], path_,
|
|
LFS3_O_WRONLY) => 0;
|
|
lfs3_file_desync(&lfs3, &wait) => 0;
|
|
lfs3_file_close(&lfs3, &wait) => 0;
|
|
}
|
|
|
|
// but recreate the file so we always have something to
|
|
// attach attrs to
|
|
|
|
// create a file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
lfs3_file_open(&lfs3, &files[x], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &files[x], "nyan", strlen("nyan"))
|
|
=> strlen("nyan");
|
|
lfs3_file_close(&lfs3, &files[x]) => 0;
|
|
|
|
// create a stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
lfs3_file_open(&lfs3, &files[x], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
|
lfs3_file_write(&lfs3, &files[x],
|
|
"swara keong", strlen("swara keong"))
|
|
=> strlen("swara keong");
|
|
|
|
// create a dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
lfs3_mkdir(&lfs3, path) => 0;
|
|
}
|
|
|
|
// update our sim
|
|
memcpy(&sim_prngs[y*M], &sim_prngs[x*M], M*sizeof(uint32_t));
|
|
memset(&sim_prngs[x*M], 0, M*sizeof(uint32_t));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FILETYPE == 1) {
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
lfs3_file_close(&lfs3, &files[i]) => 0;
|
|
}
|
|
}
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
char path[256];
|
|
// file?
|
|
if (FILETYPE == 0) {
|
|
sprintf(path, "cat%03x", x);
|
|
// stickynote?
|
|
} else if (FILETYPE == 1) {
|
|
sprintf(path, "snail%03x", x);
|
|
// dir?
|
|
} else {
|
|
sprintf(path, "armadillo%03x", x);
|
|
}
|
|
|
|
// try getting each attr size
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[x*M+a]) {
|
|
lfs3_sizeattr(&lfs3, path, a) => SIZE;
|
|
} else {
|
|
lfs3_sizeattr(&lfs3, path, a) => LFS3_ERR_NOATTR;
|
|
}
|
|
}
|
|
// try reading each attr
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[x*M+a]) {
|
|
uint32_t wprng_ = sim_prngs[x*M+a];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, a, rbuf, sizeof(rbuf)) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
} else {
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, a, rbuf, sizeof(rbuf))
|
|
=> LFS3_ERR_NOATTR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean up sim/lfs3
|
|
free(sim_prngs);
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
## Tests involving file-attached attrs
|
|
|
|
# test that file-attached attrs are read correctly
|
|
[cases.test_attrs_fattr_get]
|
|
defines.MODE = ['LFS3_A_RDONLY', 'LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// try opening a file with these attrs
|
|
uint8_t a_buf[256];
|
|
lfs3_ssize_t a_size = -1;
|
|
uint8_t b_buf[256];
|
|
lfs3_ssize_t b_size = -1;
|
|
uint8_t c_buf[256];
|
|
lfs3_ssize_t c_size = -1;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = sizeof(a_buf),
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = sizeof(b_buf),
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = sizeof(c_buf),
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", MODE, &filecfg) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf, a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf, b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf, c, strlen(c)) == 0);
|
|
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that truncate attrs will work
|
|
[cases.test_attrs_fattr_trunc]
|
|
defines.MODE = ['LFS3_A_RDONLY', 'LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
defines.BUFSIZE = [1, 4, 7]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// try opening a file with these attrs, marking bufs so we can
|
|
// detect overflow
|
|
uint8_t a_buf[256];
|
|
a_buf[BUFSIZE] = '!';
|
|
lfs3_ssize_t a_size = -1;
|
|
uint8_t b_buf[256];
|
|
b_buf[BUFSIZE] = '!';
|
|
lfs3_ssize_t b_size = -1;
|
|
uint8_t c_buf[256];
|
|
c_buf[BUFSIZE] = '!';
|
|
lfs3_ssize_t c_size = -1;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = BUFSIZE,
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = BUFSIZE,
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = BUFSIZE,
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", MODE, &filecfg) => 0;
|
|
|
|
// did we read the attrs correctly? no overflow?
|
|
if (MUTSIZE) {
|
|
assert(a_size == BUFSIZE);
|
|
}
|
|
assert(memcmp(a_buf, a, BUFSIZE) == 0);
|
|
assert(a_buf[BUFSIZE] == '!');
|
|
if (MUTSIZE) {
|
|
assert(b_size == BUFSIZE);
|
|
}
|
|
assert(memcmp(b_buf, b, BUFSIZE) == 0);
|
|
assert(a_buf[BUFSIZE] == '!');
|
|
if (MUTSIZE) {
|
|
assert(c_size == BUFSIZE);
|
|
}
|
|
assert(memcmp(c_buf, c, BUFSIZE) == 0);
|
|
assert(a_buf[BUFSIZE] == '!');
|
|
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that missing attrs are read correctly
|
|
[cases.test_attrs_fattr_noattr]
|
|
defines.MODE = ['LFS3_A_RDONLY', 'LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// try opening a file with missing attrs
|
|
uint8_t a_buf[256];
|
|
lfs3_ssize_t a_size = -1;
|
|
uint8_t b_buf[256];
|
|
lfs3_ssize_t b_size = -1;
|
|
uint8_t c_buf[256];
|
|
lfs3_ssize_t c_size = -1;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = sizeof(a_buf),
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = sizeof(b_buf),
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = sizeof(c_buf),
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", MODE, &filecfg) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size == LFS3_ERR_NOATTR);
|
|
}
|
|
if (MUTSIZE) {
|
|
assert(b_size == LFS3_ERR_NOATTR);
|
|
}
|
|
if (MUTSIZE) {
|
|
assert(c_size == LFS3_ERR_NOATTR);
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# catch LFS3_O_TRUNC mistakes, this has created issues before
|
|
[cases.test_attrs_fattr_otrunc]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// try opening a file with these attrs
|
|
uint8_t a_buf[256];
|
|
lfs3_ssize_t a_size = -1;
|
|
uint8_t b_buf[256];
|
|
lfs3_ssize_t b_size = -1;
|
|
uint8_t c_buf[256];
|
|
lfs3_ssize_t c_size = -1;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = sizeof(a_buf),
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = sizeof(b_buf),
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = sizeof(c_buf),
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat",
|
|
MODE | LFS3_O_TRUNC, &filecfg) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf, a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf, b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf, c, strlen(c)) == 0);
|
|
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# uncreat files should zero attributes
|
|
[cases.test_attrs_fattr_uncreat]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// _don't_ create a file
|
|
|
|
// try opening a file with these attrs
|
|
uint8_t a_buf[256];
|
|
lfs3_ssize_t a_size = -1;
|
|
uint8_t b_buf[256];
|
|
lfs3_ssize_t b_size = -1;
|
|
uint8_t c_buf[256];
|
|
lfs3_ssize_t c_size = -1;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = sizeof(a_buf),
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = sizeof(b_buf),
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = sizeof(c_buf),
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_t file;
|
|
lfs3_file_opencfg(&lfs3, &file, "cat",
|
|
MODE | LFS3_O_CREAT, &filecfg) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size == LFS3_ERR_NOATTR);
|
|
}
|
|
if (MUTSIZE) {
|
|
assert(b_size == LFS3_ERR_NOATTR);
|
|
}
|
|
if (MUTSIZE) {
|
|
assert(c_size == LFS3_ERR_NOATTR);
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that file-attached attrs are written correctly
|
|
[cases.test_attrs_fattr_set]
|
|
defines.MODE = ['LFS3_A_WRONLY', 'LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
|
|
// try opening a file with attrs
|
|
uint8_t a_buf[256];
|
|
lfs3_ssize_t a_size;
|
|
uint8_t b_buf[256];
|
|
lfs3_ssize_t b_size;
|
|
uint8_t c_buf[256];
|
|
lfs3_ssize_t c_size;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(a_buf) : strlen(a),
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(b_buf) : strlen(b),
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(c_buf) : strlen(c),
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", MODE, &filecfg) => 0;
|
|
|
|
// set the attrs
|
|
memcpy(a_buf, a, strlen(a));
|
|
memcpy(b_buf, b, strlen(b));
|
|
memcpy(c_buf, c, strlen(c));
|
|
a_size = strlen(a);
|
|
b_size = strlen(b);
|
|
c_size = strlen(c);
|
|
|
|
// write and close our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file, "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, "cat", 'a') => strlen(a);
|
|
lfs3_sizeattr(&lfs3, "cat", 'b') => strlen(b);
|
|
lfs3_sizeattr(&lfs3, "cat", 'c') => strlen(c);
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a);
|
|
assert(memcmp(rbuf, a, strlen(a)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b);
|
|
assert(memcmp(rbuf, b, strlen(b)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c);
|
|
assert(memcmp(rbuf, c, strlen(c)) == 0);
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that we can update existing attrs
|
|
[cases.test_attrs_fattr_update]
|
|
defines.MODE = ['LFS3_A_WRONLY', 'LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// try opening a file with attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
uint8_t a_buf[256];
|
|
lfs3_ssize_t a_size;
|
|
uint8_t b_buf[256];
|
|
lfs3_ssize_t b_size;
|
|
uint8_t c_buf[256];
|
|
lfs3_ssize_t c_size;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(a_buf) : strlen(a_),
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(b_buf) : strlen(b_),
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(c_buf) : strlen(c_),
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", MODE, &filecfg) => 0;
|
|
|
|
if (MODE == LFS3_A_RDWR && MUTSIZE) {
|
|
// did we read the attrs correctly?
|
|
assert(a_size == strlen(a));
|
|
assert(memcmp(a_buf, a, strlen(a)) == 0);
|
|
assert(b_size == strlen(b));
|
|
assert(memcmp(b_buf, b, strlen(b)) == 0);
|
|
assert(c_size == strlen(c));
|
|
assert(memcmp(c_buf, c, strlen(c)) == 0);
|
|
}
|
|
|
|
// update the attrs with new values
|
|
memcpy(a_buf, a_, strlen(a_));
|
|
memcpy(b_buf, b_, strlen(b_));
|
|
memcpy(c_buf, c_, strlen(c_));
|
|
a_size = strlen(a_);
|
|
b_size = strlen(b_);
|
|
c_size = strlen(c_);
|
|
|
|
// write and close our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file, "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, "cat", 'a') => strlen(a_);
|
|
lfs3_sizeattr(&lfs3, "cat", 'b') => strlen(b_);
|
|
lfs3_sizeattr(&lfs3, "cat", 'c') => strlen(c_);
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a_);
|
|
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b_);
|
|
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c_);
|
|
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that we can remove attrs
|
|
[cases.test_attrs_fattr_remove]
|
|
defines.MODE = ['LFS3_A_WRONLY', 'LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// try opening a file with attrs
|
|
uint8_t a_buf[256];
|
|
lfs3_ssize_t a_size;
|
|
uint8_t b_buf[256];
|
|
lfs3_ssize_t b_size;
|
|
uint8_t c_buf[256];
|
|
lfs3_ssize_t c_size;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = (MUTSIZE)
|
|
? (lfs3_ssize_t)sizeof(a_buf)
|
|
: LFS3_ERR_NOATTR,
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = (MUTSIZE)
|
|
? (lfs3_ssize_t)sizeof(b_buf)
|
|
: LFS3_ERR_NOATTR,
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = (MUTSIZE)
|
|
? (lfs3_ssize_t)sizeof(c_buf)
|
|
: LFS3_ERR_NOATTR,
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", MODE, &filecfg) => 0;
|
|
|
|
if (MODE == LFS3_A_RDWR && MUTSIZE) {
|
|
// did we read the attrs correctly?
|
|
assert(a_size == strlen(a));
|
|
assert(memcmp(a_buf, a, strlen(a)) == 0);
|
|
assert(b_size == strlen(b));
|
|
assert(memcmp(b_buf, b, strlen(b)) == 0);
|
|
assert(c_size == strlen(c));
|
|
assert(memcmp(c_buf, c, strlen(c)) == 0);
|
|
}
|
|
|
|
// mark the attrs as removed
|
|
a_size = LFS3_ERR_NOATTR;
|
|
b_size = LFS3_ERR_NOATTR;
|
|
c_size = LFS3_ERR_NOATTR;
|
|
|
|
// write and close our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file, "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, "cat", 'a') => LFS3_ERR_NOATTR;
|
|
lfs3_sizeattr(&lfs3, "cat", 'b') => LFS3_ERR_NOATTR;
|
|
lfs3_sizeattr(&lfs3, "cat", 'c') => LFS3_ERR_NOATTR;
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, "cat", 'a', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
lfs3_getattr(&lfs3, "cat", 'b', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
lfs3_getattr(&lfs3, "cat", 'c', rbuf, sizeof(rbuf)) => LFS3_ERR_NOATTR;
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that wronly attrs are not read from disk
|
|
[cases.test_attrs_fattr_wronly]
|
|
defines.MODE = ['LFS3_A_WRONLY']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// try opening a file with new wronly attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
uint8_t a_buf[256];
|
|
memcpy(a_buf, a_, strlen(a_));
|
|
lfs3_ssize_t a_size = strlen(a_);
|
|
uint8_t b_buf[256];
|
|
memcpy(b_buf, b_, strlen(b_));
|
|
lfs3_ssize_t b_size = strlen(b_);
|
|
uint8_t c_buf[256];
|
|
memcpy(c_buf, c_, strlen(c_));
|
|
lfs3_ssize_t c_size = strlen(c_);
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(a_buf) : strlen(a_),
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(b_buf) : strlen(b_),
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(c_buf) : strlen(c_),
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", LFS3_O_RDWR, &filecfg) => 0;
|
|
|
|
// open should have had no effect on our wronly attrs
|
|
assert(a_size == strlen(a_));
|
|
assert(memcmp(a_buf, a_, strlen(a_)) == 0);
|
|
assert(b_size == strlen(b_));
|
|
assert(memcmp(b_buf, b_, strlen(b_)) == 0);
|
|
assert(c_size == strlen(c_));
|
|
assert(memcmp(c_buf, c_, strlen(c_)) == 0);
|
|
|
|
// write and close our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file, "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, "cat", 'a') => strlen(a_);
|
|
lfs3_sizeattr(&lfs3, "cat", 'b') => strlen(b_);
|
|
lfs3_sizeattr(&lfs3, "cat", 'c') => strlen(c_);
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a_);
|
|
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b_);
|
|
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c_);
|
|
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that rdonly attrs have no effect on disk
|
|
[cases.test_attrs_fattr_rdonly]
|
|
defines.MODE = ['LFS3_A_RDONLY']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// try opening a file with rdonly attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
uint8_t a_buf[256];
|
|
lfs3_ssize_t a_size;
|
|
uint8_t b_buf[256];
|
|
lfs3_ssize_t b_size;
|
|
uint8_t c_buf[256];
|
|
lfs3_ssize_t c_size;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(a_buf) : strlen(a_),
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(b_buf) : strlen(b_),
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(c_buf) : strlen(c_),
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", LFS3_O_RDWR, &filecfg) => 0;
|
|
|
|
if (MUTSIZE) {
|
|
// did we read the attrs correctly?
|
|
assert(a_size == strlen(a));
|
|
assert(memcmp(a_buf, a, strlen(a)) == 0);
|
|
assert(b_size == strlen(b));
|
|
assert(memcmp(b_buf, b, strlen(b)) == 0);
|
|
assert(c_size == strlen(c));
|
|
assert(memcmp(c_buf, c, strlen(c)) == 0);
|
|
}
|
|
|
|
// update the attrs with new values
|
|
memcpy(a_buf, a_, strlen(a_));
|
|
memcpy(b_buf, b_, strlen(b_));
|
|
memcpy(c_buf, c_, strlen(c_));
|
|
a_size = strlen(a_);
|
|
b_size = strlen(b_);
|
|
c_size = strlen(c_);
|
|
|
|
// write and close our file, this should have no effect on attrs
|
|
lfs3_file_write(&lfs3, &file, "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, "cat", 'a') => strlen(a);
|
|
lfs3_sizeattr(&lfs3, "cat", 'b') => strlen(b);
|
|
lfs3_sizeattr(&lfs3, "cat", 'c') => strlen(c);
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a);
|
|
assert(memcmp(rbuf, a, strlen(a)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b);
|
|
assert(memcmp(rbuf, b, strlen(b)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c);
|
|
assert(memcmp(rbuf, c, strlen(c)) == 0);
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that attrs are written correctly even if there are no file changes
|
|
[cases.test_attrs_fattr_noop]
|
|
defines.MODE = ['LFS3_A_WRONLY', 'LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// try opening a file with attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
uint8_t a_buf[256];
|
|
lfs3_ssize_t a_size;
|
|
uint8_t b_buf[256];
|
|
lfs3_ssize_t b_size;
|
|
uint8_t c_buf[256];
|
|
lfs3_ssize_t c_size;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(a_buf) : strlen(a_),
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(b_buf) : strlen(b_),
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(c_buf) : strlen(c_),
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", MODE, &filecfg) => 0;
|
|
|
|
if (MODE == LFS3_A_RDWR && MUTSIZE) {
|
|
// did we read the attrs correctly?
|
|
assert(a_size == strlen(a));
|
|
assert(memcmp(a_buf, a, strlen(a)) == 0);
|
|
assert(b_size == strlen(b));
|
|
assert(memcmp(b_buf, b, strlen(b)) == 0);
|
|
assert(c_size == strlen(c));
|
|
assert(memcmp(c_buf, c, strlen(c)) == 0);
|
|
}
|
|
|
|
// update the attrs with new values
|
|
memcpy(a_buf, a_, strlen(a_));
|
|
memcpy(b_buf, b_, strlen(b_));
|
|
memcpy(c_buf, c_, strlen(c_));
|
|
a_size = strlen(a_);
|
|
b_size = strlen(b_);
|
|
c_size = strlen(c_);
|
|
|
|
// close our file without any data changes, this should still update
|
|
// our attrs!
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, "cat", 'a') => strlen(a_);
|
|
lfs3_sizeattr(&lfs3, "cat", 'b') => strlen(b_);
|
|
lfs3_sizeattr(&lfs3, "cat", 'c') => strlen(c_);
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a_);
|
|
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b_);
|
|
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c_);
|
|
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that lazy attrs aren't written _until_ there are file changes
|
|
[cases.test_attrs_fattr_lazy]
|
|
defines.MODE = ['LFS3_A_WRONLY', 'LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// try opening a file with attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
uint8_t a_buf[256];
|
|
lfs3_ssize_t a_size;
|
|
uint8_t b_buf[256];
|
|
lfs3_ssize_t b_size;
|
|
uint8_t c_buf[256];
|
|
lfs3_ssize_t c_size;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.type = 'a',
|
|
.flags = MODE | LFS3_A_LAZY,
|
|
.buffer = a_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(a_buf) : strlen(a_),
|
|
.size = (MUTSIZE) ? &a_size : NULL,
|
|
},
|
|
{
|
|
.type = 'b',
|
|
.flags = MODE | LFS3_A_LAZY,
|
|
.buffer = b_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(b_buf) : strlen(b_),
|
|
.size = (MUTSIZE) ? &b_size : NULL,
|
|
},
|
|
{
|
|
.type = 'c',
|
|
.flags = MODE | LFS3_A_LAZY,
|
|
.buffer = c_buf,
|
|
.buffer_size = (MUTSIZE) ? sizeof(c_buf) : strlen(c_),
|
|
.size = (MUTSIZE) ? &c_size : NULL,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", MODE, &filecfg) => 0;
|
|
|
|
if (MODE == LFS3_A_RDWR && MUTSIZE) {
|
|
// did we read the attrs correctly?
|
|
assert(a_size == strlen(a));
|
|
assert(memcmp(a_buf, a, strlen(a)) == 0);
|
|
assert(b_size == strlen(b));
|
|
assert(memcmp(b_buf, b, strlen(b)) == 0);
|
|
assert(c_size == strlen(c));
|
|
assert(memcmp(c_buf, c, strlen(c)) == 0);
|
|
}
|
|
|
|
// update the attrs with new values
|
|
memcpy(a_buf, a_, strlen(a_));
|
|
memcpy(b_buf, b_, strlen(b_));
|
|
memcpy(c_buf, c_, strlen(c_));
|
|
a_size = strlen(a_);
|
|
b_size = strlen(b_);
|
|
c_size = strlen(c_);
|
|
|
|
// sync our file without any data changes, this should have no
|
|
// effect because our attrs are lazy
|
|
lfs3_file_sync(&lfs3, &file) => 0;
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, "cat", 'a') => strlen(a);
|
|
lfs3_sizeattr(&lfs3, "cat", 'b') => strlen(b);
|
|
lfs3_sizeattr(&lfs3, "cat", 'c') => strlen(c);
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a);
|
|
assert(memcmp(rbuf, a, strlen(a)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b);
|
|
assert(memcmp(rbuf, b, strlen(b)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c);
|
|
assert(memcmp(rbuf, c, strlen(c)) == 0);
|
|
|
|
// now write some data and close our file, this should update
|
|
// the attrs now
|
|
lfs3_file_write(&lfs3, &file, "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// try getting the attr sizes
|
|
lfs3_sizeattr(&lfs3, "cat", 'a') => strlen(a_);
|
|
lfs3_sizeattr(&lfs3, "cat", 'b') => strlen(b_);
|
|
lfs3_sizeattr(&lfs3, "cat", 'c') => strlen(c_);
|
|
// try reading the attrs
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a_);
|
|
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b_);
|
|
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
|
|
lfs3_getattr(&lfs3, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c_);
|
|
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
# test that attr updates are broadcast to other file handles
|
|
[cases.test_attrs_fattr_broadcast]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// open a couple files with these attrs
|
|
uint8_t a_buf[3][256];
|
|
lfs3_ssize_t a_size[3];
|
|
uint8_t b_buf[3][256];
|
|
lfs3_ssize_t b_size[3];
|
|
uint8_t c_buf[3][256];
|
|
lfs3_ssize_t c_size[3];
|
|
struct lfs3_attr attrs[3][3];
|
|
struct lfs3_file_config filecfg[3];
|
|
lfs3_file_t file[3];
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
attrs[i][0] = (struct lfs3_attr){
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf[i],
|
|
.buffer_size = sizeof(a_buf[i]),
|
|
.size = (MUTSIZE) ? &a_size[i] : NULL,
|
|
};
|
|
attrs[i][1] = (struct lfs3_attr){
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf[i],
|
|
.buffer_size = sizeof(b_buf[i]),
|
|
.size = (MUTSIZE) ? &b_size[i] : NULL,
|
|
};
|
|
attrs[i][2] = (struct lfs3_attr){
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf[i],
|
|
.buffer_size = sizeof(c_buf[i]),
|
|
.size = (MUTSIZE) ? &c_size[i] : NULL,
|
|
};
|
|
filecfg[i] = (struct lfs3_file_config){
|
|
.attrs = attrs[i],
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// update _one_ file's attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
memcpy(a_buf[1], a_, strlen(a_));
|
|
memcpy(b_buf[1], b_, strlen(b_));
|
|
memcpy(c_buf[1], c_, strlen(c_));
|
|
a_size[1] = strlen(a_);
|
|
b_size[1] = strlen(b_);
|
|
c_size[1] = strlen(c_);
|
|
|
|
// write and sync our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file[1], "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_sync(&lfs3, &file[1]) => 0;
|
|
|
|
// were attrs broadcasted to the other files?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a_));
|
|
}
|
|
assert(memcmp(a_buf[i], a_, strlen(a_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b_));
|
|
}
|
|
assert(memcmp(b_buf[i], b_, strlen(b_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c_));
|
|
}
|
|
assert(memcmp(c_buf[i], c_, strlen(c_)) == 0);
|
|
}
|
|
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that attr removes are broadcast to other file handles
|
|
[cases.test_attrs_fattr_remove_broadcast]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// open a couple files with these attrs
|
|
uint8_t a_buf[3][256];
|
|
lfs3_ssize_t a_size[3];
|
|
uint8_t b_buf[3][256];
|
|
lfs3_ssize_t b_size[3];
|
|
uint8_t c_buf[3][256];
|
|
lfs3_ssize_t c_size[3];
|
|
struct lfs3_attr attrs[3][3];
|
|
struct lfs3_file_config filecfg[3];
|
|
lfs3_file_t file[3];
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
attrs[i][0] = (struct lfs3_attr){
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf[i],
|
|
.buffer_size = sizeof(a_buf[i]),
|
|
.size = (MUTSIZE) ? &a_size[i] : NULL,
|
|
};
|
|
attrs[i][1] = (struct lfs3_attr){
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf[i],
|
|
.buffer_size = sizeof(b_buf[i]),
|
|
.size = (MUTSIZE) ? &b_size[i] : NULL,
|
|
};
|
|
attrs[i][2] = (struct lfs3_attr){
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf[i],
|
|
.buffer_size = sizeof(c_buf[i]),
|
|
.size = (MUTSIZE) ? &c_size[i] : NULL,
|
|
};
|
|
filecfg[i] = (struct lfs3_file_config){
|
|
.attrs = attrs[i],
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// remove _one_ file's attrs
|
|
a_size[1] = LFS3_ERR_NOATTR;
|
|
b_size[1] = LFS3_ERR_NOATTR;
|
|
c_size[1] = LFS3_ERR_NOATTR;
|
|
|
|
// write and sync our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file[1], "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_sync(&lfs3, &file[1]) => 0;
|
|
|
|
// were attrs broadcasted to the other files?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == LFS3_ERR_NOATTR);
|
|
}
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == LFS3_ERR_NOATTR);
|
|
}
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == LFS3_ERR_NOATTR);
|
|
}
|
|
}
|
|
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that setattr can also broadcast
|
|
[cases.test_attrs_fattr_setattr_broadcast]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// open a couple files with these attrs
|
|
uint8_t a_buf[3][256];
|
|
lfs3_ssize_t a_size[3];
|
|
uint8_t b_buf[3][256];
|
|
lfs3_ssize_t b_size[3];
|
|
uint8_t c_buf[3][256];
|
|
lfs3_ssize_t c_size[3];
|
|
struct lfs3_attr attrs[3][3];
|
|
struct lfs3_file_config filecfg[3];
|
|
lfs3_file_t file[3];
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
attrs[i][0] = (struct lfs3_attr){
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf[i],
|
|
.buffer_size = sizeof(a_buf[i]),
|
|
.size = (MUTSIZE) ? &a_size[i] : NULL,
|
|
};
|
|
attrs[i][1] = (struct lfs3_attr){
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf[i],
|
|
.buffer_size = sizeof(b_buf[i]),
|
|
.size = (MUTSIZE) ? &b_size[i] : NULL,
|
|
};
|
|
attrs[i][2] = (struct lfs3_attr){
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf[i],
|
|
.buffer_size = sizeof(c_buf[i]),
|
|
.size = (MUTSIZE) ? &c_size[i] : NULL,
|
|
};
|
|
filecfg[i] = (struct lfs3_file_config){
|
|
.attrs = attrs[i],
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// update attrs with setattr
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a_, strlen(a_)) => 0;
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b_, strlen(b_)) => 0;
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c_, strlen(c_)) => 0;
|
|
|
|
// were attrs broadcasted to the other files?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a_));
|
|
}
|
|
assert(memcmp(a_buf[i], a_, strlen(a_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b_));
|
|
}
|
|
assert(memcmp(b_buf[i], b_, strlen(b_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c_));
|
|
}
|
|
assert(memcmp(c_buf[i], c_, strlen(c_)) == 0);
|
|
}
|
|
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that attr removes are broadcast to other file handles
|
|
[cases.test_attrs_fattr_removeattr_broadcast]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// open a couple files with these attrs
|
|
uint8_t a_buf[3][256];
|
|
lfs3_ssize_t a_size[3];
|
|
uint8_t b_buf[3][256];
|
|
lfs3_ssize_t b_size[3];
|
|
uint8_t c_buf[3][256];
|
|
lfs3_ssize_t c_size[3];
|
|
struct lfs3_attr attrs[3][3];
|
|
struct lfs3_file_config filecfg[3];
|
|
lfs3_file_t file[3];
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
attrs[i][0] = (struct lfs3_attr){
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf[i],
|
|
.buffer_size = sizeof(a_buf[i]),
|
|
.size = (MUTSIZE) ? &a_size[i] : NULL,
|
|
};
|
|
attrs[i][1] = (struct lfs3_attr){
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf[i],
|
|
.buffer_size = sizeof(b_buf[i]),
|
|
.size = (MUTSIZE) ? &b_size[i] : NULL,
|
|
};
|
|
attrs[i][2] = (struct lfs3_attr){
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf[i],
|
|
.buffer_size = sizeof(c_buf[i]),
|
|
.size = (MUTSIZE) ? &c_size[i] : NULL,
|
|
};
|
|
filecfg[i] = (struct lfs3_file_config){
|
|
.attrs = attrs[i],
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// remove attrs with lfs3_removeattr
|
|
lfs3_removeattr(&lfs3, "cat", 'a') => 0;
|
|
lfs3_removeattr(&lfs3, "cat", 'b') => 0;
|
|
lfs3_removeattr(&lfs3, "cat", 'c') => 0;
|
|
|
|
// were attrs broadcasted to the other files?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == LFS3_ERR_NOATTR);
|
|
}
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == LFS3_ERR_NOATTR);
|
|
}
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == LFS3_ERR_NOATTR);
|
|
}
|
|
}
|
|
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that attr broadcasts do _not_ update wronly attrs
|
|
[cases.test_attrs_fattr_wronly_no_receive]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// open a couple files with these attrs
|
|
uint8_t a_buf[3][256];
|
|
lfs3_ssize_t a_size[3];
|
|
uint8_t b_buf[3][256];
|
|
lfs3_ssize_t b_size[3];
|
|
uint8_t c_buf[3][256];
|
|
lfs3_ssize_t c_size[3];
|
|
struct lfs3_attr attrs[3][3];
|
|
struct lfs3_file_config filecfg[3];
|
|
lfs3_file_t file[3];
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
attrs[i][0] = (struct lfs3_attr){
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf[i],
|
|
.buffer_size = sizeof(a_buf[i]),
|
|
.size = (MUTSIZE) ? &a_size[i] : NULL,
|
|
};
|
|
attrs[i][1] = (struct lfs3_attr){
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf[i],
|
|
.buffer_size = sizeof(b_buf[i]),
|
|
.size = (MUTSIZE) ? &b_size[i] : NULL,
|
|
};
|
|
attrs[i][2] = (struct lfs3_attr){
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf[i],
|
|
.buffer_size = sizeof(c_buf[i]),
|
|
.size = (MUTSIZE) ? &c_size[i] : NULL,
|
|
};
|
|
filecfg[i] = (struct lfs3_file_config){
|
|
.attrs = attrs[i],
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// make one attr set wronly
|
|
attrs[0][0].flags = LFS3_A_WRONLY;
|
|
attrs[0][1].flags = LFS3_A_WRONLY;
|
|
attrs[0][2].flags = LFS3_A_WRONLY;
|
|
|
|
// update another file's attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
memcpy(a_buf[2], a_, strlen(a_));
|
|
memcpy(b_buf[2], b_, strlen(b_));
|
|
memcpy(c_buf[2], c_, strlen(c_));
|
|
a_size[2] = strlen(a_);
|
|
b_size[2] = strlen(b_);
|
|
c_size[2] = strlen(c_);
|
|
|
|
// write and sync our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file[2], "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_sync(&lfs3, &file[2]) => 0;
|
|
|
|
// were attrs broadcasted to the other files? but not our wronly attrs?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (i == 0) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
} else {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a_));
|
|
}
|
|
assert(memcmp(a_buf[i], a_, strlen(a_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b_));
|
|
}
|
|
assert(memcmp(b_buf[i], b_, strlen(b_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c_));
|
|
}
|
|
assert(memcmp(c_buf[i], c_, strlen(c_)) == 0);
|
|
}
|
|
}
|
|
|
|
// update attrs with setattr
|
|
const char *a__ = "Two cups all-purpose flower.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a__, strlen(a__)) => 0;
|
|
const char *b__ = "Dont forget garnishes such as:";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b__, strlen(b__)) => 0;
|
|
const char *c__ = "Fish-shaped crackers.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c__, strlen(c__)) => 0;
|
|
|
|
// were attrs broadcasted to the other files? but not our wronly attrs?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (i == 0) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
} else {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a__));
|
|
}
|
|
assert(memcmp(a_buf[i], a__, strlen(a__)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b__));
|
|
}
|
|
assert(memcmp(b_buf[i], b__, strlen(b__)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c__));
|
|
}
|
|
assert(memcmp(c_buf[i], c__, strlen(c__)) == 0);
|
|
}
|
|
}
|
|
|
|
// if we sync our wronly file we should get the original attrs back
|
|
lfs3_file_sync(&lfs3, &file[0]) => 0;
|
|
|
|
// were attrs broadcasted to the other files?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that attr broadcasts do _not_ broadcast rdonly attrs
|
|
[cases.test_attrs_fattr_rdonly_no_broadcast]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// open a couple files with these attrs
|
|
uint8_t a_buf[3][256];
|
|
lfs3_ssize_t a_size[3];
|
|
uint8_t b_buf[3][256];
|
|
lfs3_ssize_t b_size[3];
|
|
uint8_t c_buf[3][256];
|
|
lfs3_ssize_t c_size[3];
|
|
struct lfs3_attr attrs[3][3];
|
|
struct lfs3_file_config filecfg[3];
|
|
lfs3_file_t file[3];
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
attrs[i][0] = (struct lfs3_attr){
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf[i],
|
|
.buffer_size = sizeof(a_buf[i]),
|
|
.size = (MUTSIZE) ? &a_size[i] : NULL,
|
|
};
|
|
attrs[i][1] = (struct lfs3_attr){
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf[i],
|
|
.buffer_size = sizeof(b_buf[i]),
|
|
.size = (MUTSIZE) ? &b_size[i] : NULL,
|
|
};
|
|
attrs[i][2] = (struct lfs3_attr){
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf[i],
|
|
.buffer_size = sizeof(c_buf[i]),
|
|
.size = (MUTSIZE) ? &c_size[i] : NULL,
|
|
};
|
|
filecfg[i] = (struct lfs3_file_config){
|
|
.attrs = attrs[i],
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// make one attr set rdonly
|
|
attrs[0][0].flags = LFS3_A_RDONLY;
|
|
attrs[0][1].flags = LFS3_A_RDONLY;
|
|
attrs[0][2].flags = LFS3_A_RDONLY;
|
|
|
|
// change the rdonly file's attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
memcpy(a_buf[0], a_, strlen(a_));
|
|
memcpy(b_buf[0], b_, strlen(b_));
|
|
memcpy(c_buf[0], c_, strlen(c_));
|
|
a_size[0] = strlen(a_);
|
|
b_size[0] = strlen(b_);
|
|
c_size[0] = strlen(c_);
|
|
|
|
// write and sync our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file[0], "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_sync(&lfs3, &file[0]) => 0;
|
|
|
|
// rdonly attrs should not have been broadcasted
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (i == 0) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a_));
|
|
}
|
|
assert(memcmp(a_buf[i], a_, strlen(a_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b_));
|
|
}
|
|
assert(memcmp(b_buf[i], b_, strlen(b_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c_));
|
|
}
|
|
assert(memcmp(c_buf[i], c_, strlen(c_)) == 0);
|
|
} else {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
}
|
|
|
|
// sync any file to update our rdonly attrs
|
|
lfs3_file_sync(&lfs3, &file[2]) => 0;
|
|
|
|
// reset attrs?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that desync files do _not_ receive attr broadcasts
|
|
[cases.test_attrs_fattr_desync_no_receive]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// open a couple files with these attrs
|
|
uint8_t a_buf[3][256];
|
|
lfs3_ssize_t a_size[3];
|
|
uint8_t b_buf[3][256];
|
|
lfs3_ssize_t b_size[3];
|
|
uint8_t c_buf[3][256];
|
|
lfs3_ssize_t c_size[3];
|
|
struct lfs3_attr attrs[3][3];
|
|
struct lfs3_file_config filecfg[3];
|
|
lfs3_file_t file[3];
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
attrs[i][0] = (struct lfs3_attr){
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf[i],
|
|
.buffer_size = sizeof(a_buf[i]),
|
|
.size = (MUTSIZE) ? &a_size[i] : NULL,
|
|
};
|
|
attrs[i][1] = (struct lfs3_attr){
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf[i],
|
|
.buffer_size = sizeof(b_buf[i]),
|
|
.size = (MUTSIZE) ? &b_size[i] : NULL,
|
|
};
|
|
attrs[i][2] = (struct lfs3_attr){
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf[i],
|
|
.buffer_size = sizeof(c_buf[i]),
|
|
.size = (MUTSIZE) ? &c_size[i] : NULL,
|
|
};
|
|
filecfg[i] = (struct lfs3_file_config){
|
|
.attrs = attrs[i],
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// make one file desync
|
|
lfs3_file_desync(&lfs3, &file[0]) => 0;
|
|
|
|
// update another file's attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
memcpy(a_buf[2], a_, strlen(a_));
|
|
memcpy(b_buf[2], b_, strlen(b_));
|
|
memcpy(c_buf[2], c_, strlen(c_));
|
|
a_size[2] = strlen(a_);
|
|
b_size[2] = strlen(b_);
|
|
c_size[2] = strlen(c_);
|
|
|
|
// write and sync our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file[2], "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_sync(&lfs3, &file[2]) => 0;
|
|
|
|
// were attrs broadcasted to the other files? but not our desync file?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (i == 0) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
} else {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a_));
|
|
}
|
|
assert(memcmp(a_buf[i], a_, strlen(a_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b_));
|
|
}
|
|
assert(memcmp(b_buf[i], b_, strlen(b_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c_));
|
|
}
|
|
assert(memcmp(c_buf[i], c_, strlen(c_)) == 0);
|
|
}
|
|
}
|
|
|
|
// update attrs with setattr
|
|
const char *a__ = "Two cups all-purpose flower.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a__, strlen(a__)) => 0;
|
|
const char *b__ = "Dont forget garnishes such as:";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b__, strlen(b__)) => 0;
|
|
const char *c__ = "Fish-shaped crackers.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c__, strlen(c__)) => 0;
|
|
|
|
// were attrs broadcasted to the other files? but not our desync file?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (i == 0) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
} else {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a__));
|
|
}
|
|
assert(memcmp(a_buf[i], a__, strlen(a__)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b__));
|
|
}
|
|
assert(memcmp(b_buf[i], b__, strlen(b__)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c__));
|
|
}
|
|
assert(memcmp(c_buf[i], c__, strlen(c__)) == 0);
|
|
}
|
|
}
|
|
|
|
// syncing the desync file should broadcast the original attrs
|
|
lfs3_file_sync(&lfs3, &file[0]) => 0;
|
|
|
|
// were attrs broadcasted to the other files?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that resync files will reread attrs
|
|
[cases.test_attrs_fattr_resync_receive]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// open a couple files with these attrs
|
|
uint8_t a_buf[3][256];
|
|
lfs3_ssize_t a_size[3];
|
|
uint8_t b_buf[3][256];
|
|
lfs3_ssize_t b_size[3];
|
|
uint8_t c_buf[3][256];
|
|
lfs3_ssize_t c_size[3];
|
|
struct lfs3_attr attrs[3][3];
|
|
struct lfs3_file_config filecfg[3];
|
|
lfs3_file_t file[3];
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
attrs[i][0] = (struct lfs3_attr){
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf[i],
|
|
.buffer_size = sizeof(a_buf[i]),
|
|
.size = (MUTSIZE) ? &a_size[i] : NULL,
|
|
};
|
|
attrs[i][1] = (struct lfs3_attr){
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf[i],
|
|
.buffer_size = sizeof(b_buf[i]),
|
|
.size = (MUTSIZE) ? &b_size[i] : NULL,
|
|
};
|
|
attrs[i][2] = (struct lfs3_attr){
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf[i],
|
|
.buffer_size = sizeof(c_buf[i]),
|
|
.size = (MUTSIZE) ? &c_size[i] : NULL,
|
|
};
|
|
filecfg[i] = (struct lfs3_file_config){
|
|
.attrs = attrs[i],
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// make one file desync
|
|
lfs3_file_desync(&lfs3, &file[0]) => 0;
|
|
|
|
// update another file's attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
memcpy(a_buf[2], a_, strlen(a_));
|
|
memcpy(b_buf[2], b_, strlen(b_));
|
|
memcpy(c_buf[2], c_, strlen(c_));
|
|
a_size[2] = strlen(a_);
|
|
b_size[2] = strlen(b_);
|
|
c_size[2] = strlen(c_);
|
|
|
|
// write and sync our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file[2], "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_sync(&lfs3, &file[2]) => 0;
|
|
|
|
// were attrs broadcasted to the other files? but not our desync file?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (i == 0) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
} else {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a_));
|
|
}
|
|
assert(memcmp(a_buf[i], a_, strlen(a_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b_));
|
|
}
|
|
assert(memcmp(b_buf[i], b_, strlen(b_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c_));
|
|
}
|
|
assert(memcmp(c_buf[i], c_, strlen(c_)) == 0);
|
|
}
|
|
}
|
|
|
|
// resync the desync file
|
|
lfs3_file_resync(&lfs3, &file[0]) => 0;
|
|
|
|
// reread attrs?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a_));
|
|
}
|
|
assert(memcmp(a_buf[i], a_, strlen(a_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b_));
|
|
}
|
|
assert(memcmp(b_buf[i], b_, strlen(b_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c_));
|
|
}
|
|
assert(memcmp(c_buf[i], c_, strlen(c_)) == 0);
|
|
}
|
|
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that zombie files do _not_ broadcast attrs
|
|
[cases.test_attrs_fattr_zombie_no_broadcast]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// open a couple files with these attrs
|
|
uint8_t a_buf[3][256];
|
|
lfs3_ssize_t a_size[3];
|
|
uint8_t b_buf[3][256];
|
|
lfs3_ssize_t b_size[3];
|
|
uint8_t c_buf[3][256];
|
|
lfs3_ssize_t c_size[3];
|
|
struct lfs3_attr attrs[3][3];
|
|
struct lfs3_file_config filecfg[3];
|
|
lfs3_file_t file[3];
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
attrs[i][0] = (struct lfs3_attr){
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf[i],
|
|
.buffer_size = sizeof(a_buf[i]),
|
|
.size = (MUTSIZE) ? &a_size[i] : NULL,
|
|
};
|
|
attrs[i][1] = (struct lfs3_attr){
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf[i],
|
|
.buffer_size = sizeof(b_buf[i]),
|
|
.size = (MUTSIZE) ? &b_size[i] : NULL,
|
|
};
|
|
attrs[i][2] = (struct lfs3_attr){
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf[i],
|
|
.buffer_size = sizeof(c_buf[i]),
|
|
.size = (MUTSIZE) ? &c_size[i] : NULL,
|
|
};
|
|
filecfg[i] = (struct lfs3_file_config){
|
|
.attrs = attrs[i],
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "cat") => 0;
|
|
|
|
// update one file's attrs
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
memcpy(a_buf[1], a_, strlen(a_));
|
|
memcpy(b_buf[1], b_, strlen(b_));
|
|
memcpy(c_buf[1], c_, strlen(c_));
|
|
a_size[1] = strlen(a_);
|
|
b_size[1] = strlen(b_);
|
|
c_size[1] = strlen(c_);
|
|
|
|
// attempting to sync the zombie file is a noop
|
|
lfs3_file_sync(&lfs3, &file[1]) => 0;
|
|
|
|
// attempting to resync the zombie file should error
|
|
lfs3_file_resync(&lfs3, &file[1]) => LFS3_ERR_NOENT;
|
|
|
|
// other file unaffected?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (i == 1) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a_));
|
|
}
|
|
assert(memcmp(a_buf[i], a_, strlen(a_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b_));
|
|
}
|
|
assert(memcmp(b_buf[i], b_, strlen(b_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c_));
|
|
}
|
|
assert(memcmp(c_buf[i], c_, strlen(c_)) == 0);
|
|
} else {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
}
|
|
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that zombie files do _not_ receive attr broadcasts
|
|
[cases.test_attrs_fattr_zombie_no_receive]
|
|
defines.MODE = ['LFS3_A_RDWR']
|
|
defines.MUTSIZE = [false, true]
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file_;
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
// create some attrs
|
|
const char *a = "One 18.25 ounce package chocolate cake mix.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a, strlen(a)) => 0;
|
|
const char *b = "One can prepared coconut pecan frosting.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b, strlen(b)) => 0;
|
|
const char *c = "Three slash four cup vegetable oil.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c, strlen(c)) => 0;
|
|
|
|
// open a couple files with these attrs
|
|
uint8_t a_buf[3][256];
|
|
lfs3_ssize_t a_size[3];
|
|
uint8_t b_buf[3][256];
|
|
lfs3_ssize_t b_size[3];
|
|
uint8_t c_buf[3][256];
|
|
lfs3_ssize_t c_size[3];
|
|
struct lfs3_attr attrs[3][3];
|
|
struct lfs3_file_config filecfg[3];
|
|
lfs3_file_t file[3];
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
attrs[i][0] = (struct lfs3_attr){
|
|
.type = 'a',
|
|
.flags = MODE,
|
|
.buffer = a_buf[i],
|
|
.buffer_size = sizeof(a_buf[i]),
|
|
.size = (MUTSIZE) ? &a_size[i] : NULL,
|
|
};
|
|
attrs[i][1] = (struct lfs3_attr){
|
|
.type = 'b',
|
|
.flags = MODE,
|
|
.buffer = b_buf[i],
|
|
.buffer_size = sizeof(b_buf[i]),
|
|
.size = (MUTSIZE) ? &b_size[i] : NULL,
|
|
};
|
|
attrs[i][2] = (struct lfs3_attr){
|
|
.type = 'c',
|
|
.flags = MODE,
|
|
.buffer = c_buf[i],
|
|
.buffer_size = sizeof(c_buf[i]),
|
|
.size = (MUTSIZE) ? &c_size[i] : NULL,
|
|
};
|
|
filecfg[i] = (struct lfs3_file_config){
|
|
.attrs = attrs[i],
|
|
.attr_count = 3,
|
|
};
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, "cat") => 0;
|
|
|
|
// recreate the file
|
|
lfs3_file_open(&lfs3, &file_, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file_, "miao", strlen("miao")) => strlen("miao");
|
|
lfs3_file_close(&lfs3, &file_) => 0;
|
|
|
|
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a_, strlen(a_)) => 0;
|
|
const char *b_ = "Three slash four cup butter or margarine.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b_, strlen(b_)) => 0;
|
|
const char *c_ = "One and two third cups granulated sugar.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c_, strlen(c_)) => 0;
|
|
|
|
// make sure no attrs were broadcasted to our zombies
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
}
|
|
|
|
// reopen a couple files with these attrs
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
// leave one file a zombie
|
|
if (i == 0) {
|
|
continue;
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
lfs3_file_opencfg(&lfs3, &file[i], "cat", MODE, &filecfg[i]) => 0;
|
|
|
|
// did we read the attrs correctly?
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a_));
|
|
}
|
|
assert(memcmp(a_buf[i], a_, strlen(a_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b_));
|
|
}
|
|
assert(memcmp(b_buf[i], b_, strlen(b_)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c_));
|
|
}
|
|
assert(memcmp(c_buf[i], c_, strlen(c_)) == 0);
|
|
}
|
|
|
|
// update another file's attrs
|
|
const char *a__ = "Two cups all-purpose flower.";
|
|
const char *b__ = "Dont forget garnishes such as:";
|
|
const char *c__ = "Fish-shaped crackers.";
|
|
memcpy(a_buf[2], a__, strlen(a__));
|
|
memcpy(b_buf[2], b__, strlen(b__));
|
|
memcpy(c_buf[2], c__, strlen(c__));
|
|
a_size[2] = strlen(a__);
|
|
b_size[2] = strlen(b__);
|
|
c_size[2] = strlen(c__);
|
|
|
|
// write and sync our file to write the attrs out to disk
|
|
lfs3_file_write(&lfs3, &file[2], "nyan", strlen("nyan")) => strlen("nyan");
|
|
lfs3_file_sync(&lfs3, &file[2]) => 0;
|
|
|
|
// were attrs broadcasted to the other files? but not our zombie file?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (i == 0) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
} else {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a__));
|
|
}
|
|
assert(memcmp(a_buf[i], a__, strlen(a__)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b__));
|
|
}
|
|
assert(memcmp(b_buf[i], b__, strlen(b__)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c__));
|
|
}
|
|
assert(memcmp(c_buf[i], c__, strlen(c__)) == 0);
|
|
}
|
|
}
|
|
|
|
// update attrs with setattr
|
|
const char *a___ = "Fish-shaped candies.";
|
|
lfs3_setattr(&lfs3, "cat", 'a', a___, strlen(a___)) => 0;
|
|
const char *b___ = "Fish-shaped solid waste.";
|
|
lfs3_setattr(&lfs3, "cat", 'b', b___, strlen(b___)) => 0;
|
|
const char *c___ = "Fish-shaped dirt.";
|
|
lfs3_setattr(&lfs3, "cat", 'c', c___, strlen(c___)) => 0;
|
|
|
|
// were attrs broadcasted to the other files? but not our zombie file?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (i == 0) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a));
|
|
}
|
|
assert(memcmp(a_buf[i], a, strlen(a)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b));
|
|
}
|
|
assert(memcmp(b_buf[i], b, strlen(b)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c));
|
|
}
|
|
assert(memcmp(c_buf[i], c, strlen(c)) == 0);
|
|
} else {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a___));
|
|
}
|
|
assert(memcmp(a_buf[i], a___, strlen(a___)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b___));
|
|
}
|
|
assert(memcmp(b_buf[i], b___, strlen(b___)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c___));
|
|
}
|
|
assert(memcmp(c_buf[i], c___, strlen(c___)) == 0);
|
|
}
|
|
}
|
|
|
|
// attempting to sync the zombie file is a noop
|
|
lfs3_file_sync(&lfs3, &file[0]) => 0;
|
|
|
|
// attempting to resync the zombie file should error
|
|
lfs3_file_resync(&lfs3, &file[0]) => LFS3_ERR_NOENT;
|
|
|
|
// other file unaffected?
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
if (i != 0) {
|
|
if (MUTSIZE) {
|
|
assert(a_size[i] == strlen(a___));
|
|
}
|
|
assert(memcmp(a_buf[i], a___, strlen(a___)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(b_size[i] == strlen(b___));
|
|
}
|
|
assert(memcmp(b_buf[i], b___, strlen(b___)) == 0);
|
|
if (MUTSIZE) {
|
|
assert(c_size[i] == strlen(c___));
|
|
}
|
|
assert(memcmp(c_buf[i], c___, strlen(c___)) == 0);
|
|
}
|
|
}
|
|
|
|
for (lfs3_size_t i = 0; i < 3; i++) {
|
|
lfs3_file_close(&lfs3, &file[i]) => 0;
|
|
}
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
|
|
# test the full range of attrs
|
|
[cases.test_attrs_fattr_all]
|
|
defines.SIZE = 4
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create a file
|
|
lfs3_file_t file;
|
|
lfs3_file_open(&lfs3, &file, "cat", LFS3_O_WRONLY | LFS3_O_CREAT) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow")) => strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// setup our attr
|
|
uint8_t a_buf[SIZE];
|
|
lfs3_ssize_t a_size = -1;
|
|
struct lfs3_attr attrs[] = {
|
|
{
|
|
.flags = LFS3_A_RDWR,
|
|
.buffer = a_buf,
|
|
.buffer_size = sizeof(a_buf),
|
|
.size = &a_size,
|
|
}
|
|
};
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = 1,
|
|
};
|
|
|
|
// try creating every attr, this tests any encoding quirks
|
|
uint32_t prng = 42;
|
|
for (uint16_t a = 0; a < 0x100; a++) {
|
|
attrs[0].type = a;
|
|
|
|
// create the attr via open
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", LFS3_A_RDWR, &filecfg) => 0;
|
|
memcpy(a_buf, wbuf, SIZE);
|
|
a_size = SIZE;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// try getting the attr size
|
|
lfs3_sizeattr(&lfs3, "cat", a) => SIZE;
|
|
// try reading the attr
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, "cat", a, rbuf, sizeof(rbuf)) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
|
|
// clobber our in-RAM attr and try reading via open
|
|
memset(a_buf, 0xcc, sizeof(a_buf));
|
|
lfs3_file_opencfg(&lfs3, &file, "cat", LFS3_A_RDWR, &filecfg) => 0;
|
|
assert(a_size == SIZE);
|
|
assert(memcmp(a_buf, wbuf, SIZE) == 0);
|
|
|
|
// remove the attr
|
|
a_size = LFS3_ERR_NOATTR;
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// make sure attr is removed
|
|
lfs3_sizeattr(&lfs3, "cat", a) => LFS3_ERR_NOATTR;
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test creating a bunch of attrs on a bunch of files
|
|
[cases.test_attrs_fattr_many_many]
|
|
defines.N = 64
|
|
defines.M = 4
|
|
defines.SIZE = 4
|
|
defines.COMPACT = [false, true]
|
|
defines.GC_FLAGS = 'LFS3_GC_COMPACT'
|
|
defines.GC_STEPS = -1
|
|
defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2'
|
|
if = 'LFS3_IFDEF_GC(true, !COMPACT)'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
// create N files with M attrs
|
|
uint32_t prng = 42;
|
|
for (lfs3_size_t i = 0; i < N; i++) {
|
|
char path[256];
|
|
sprintf(path, "cat%03x", i);
|
|
uint8_t a_buf[M][SIZE];
|
|
struct lfs3_attr attrs[M];
|
|
for (lfs3_size_t j = 0; j < M; j++) {
|
|
for (lfs3_size_t k = 0; k < SIZE; k++) {
|
|
a_buf[j][k] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
attrs[j] = (struct lfs3_attr){
|
|
.type = j,
|
|
.flags = LFS3_A_WRONLY,
|
|
.buffer = a_buf[j],
|
|
.buffer_size = SIZE,
|
|
};
|
|
}
|
|
struct lfs3_file_config filecfg = {
|
|
.attrs = attrs,
|
|
.attr_count = M,
|
|
};
|
|
lfs3_file_t file;
|
|
lfs3_file_opencfg(&lfs3, &file, path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT, &filecfg) => 0;
|
|
lfs3_file_write(&lfs3, &file, "meow", strlen("meow"))
|
|
=> strlen("meow");
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
|
|
// try compacting?
|
|
#ifdef LFS3_GC
|
|
if (COMPACT) {
|
|
lfs3_fs_gc(&lfs3) => 0;
|
|
}
|
|
#endif
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
prng = 42;
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
char path[256];
|
|
sprintf(path, "cat%03x", x);
|
|
|
|
// try getting the attr sizes
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
lfs3_sizeattr(&lfs3, path, a) => SIZE;
|
|
}
|
|
// try reading the attrs
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
|
|
}
|
|
uint8_t rbuf[256];
|
|
lfs3_getattr(&lfs3, path, a, rbuf, sizeof(rbuf)) => SIZE;
|
|
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# fuzz attrs on multiple files
|
|
[cases.test_attrs_fattr_fuzz_fuzz]
|
|
defines.N = 64
|
|
defines.M = 4
|
|
defines.SIZE = 4
|
|
defines.OPS = '4*N*M'
|
|
defines.SEED = 'range(20)'
|
|
fuzz = 'SEED'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
uint8_t a_buf[N][M][SIZE];
|
|
lfs3_ssize_t a_size[N][M];
|
|
struct lfs3_attr attrs[N][M];
|
|
struct lfs3_file_config filecfg[N];
|
|
lfs3_file_t file[N];
|
|
|
|
// create N files
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
char path[256];
|
|
sprintf(path, "cat%03x", x);
|
|
for (lfs3_size_t a = 0; a < M; a++) {
|
|
attrs[x][a] = (struct lfs3_attr){
|
|
.type = a,
|
|
.flags = LFS3_A_RDWR,
|
|
.buffer = a_buf[x][a],
|
|
.buffer_size = SIZE,
|
|
.size = &a_size[x][a],
|
|
};
|
|
}
|
|
filecfg[x] = (struct lfs3_file_config){
|
|
.attrs = attrs[x],
|
|
.attr_count = M,
|
|
};
|
|
|
|
lfs3_file_opencfg(&lfs3, &file[x], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL,
|
|
&filecfg[x]) => 0;
|
|
lfs3_file_write(&lfs3, &file[x], "meow", strlen("meow"))
|
|
=> strlen("meow");
|
|
lfs3_file_sync(&lfs3, &file[x]) => 0;
|
|
}
|
|
|
|
// set up a simulation to compare against
|
|
uint32_t *sim_prngs = malloc(N*M*sizeof(uint32_t));
|
|
memset(sim_prngs, 0, N*M*sizeof(uint32_t));
|
|
|
|
uint32_t prng = SEED;
|
|
for (lfs3_size_t i = 0; i < OPS; i++) {
|
|
// choose which operation to do
|
|
uint8_t op = TEST_PRNG(&prng) % 2;
|
|
|
|
// create an attr?
|
|
if (op == 0) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
// choose a prng
|
|
uint32_t wprng = TEST_PRNG(&prng);
|
|
|
|
// update the attr
|
|
uint32_t wprng_ = wprng;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
memcpy(a_buf[x][a], wbuf, SIZE);
|
|
a_size[x][a] = SIZE;
|
|
lfs3_file_sync(&lfs3, &file[x]) => 0;
|
|
|
|
// update our sim
|
|
sim_prngs[x*M+a] = wprng;
|
|
|
|
// remove an attr?
|
|
} else if (op == 1) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
|
|
// remove the attr
|
|
a_size[x][a] = LFS3_ERR_NOATTR;
|
|
lfs3_file_sync(&lfs3, &file[x]) => 0;
|
|
|
|
// update our sim
|
|
sim_prngs[x*M+a] = 0;
|
|
}
|
|
}
|
|
|
|
// check attrs on all file handles
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[x*M+a]) {
|
|
assert(a_size[x][a] == SIZE);
|
|
uint32_t wprng_ = sim_prngs[x*M+a];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
assert(memcmp(a_buf[x][a], wbuf, SIZE) == 0);
|
|
} else {
|
|
assert(a_size[x][a] == LFS3_ERR_NOATTR);
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean up sim/lfs3
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
lfs3_file_close(&lfs3, &file[x]) => 0;
|
|
}
|
|
free(sim_prngs);
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# fuzz attrs on multiple overlapping files
|
|
[cases.test_attrs_fattr_fuzz_fuzz_fuzz]
|
|
defines.N = 64
|
|
defines.H = 4
|
|
defines.M = 4
|
|
defines.SIZE = 4
|
|
defines.OPS = '4*N*M'
|
|
defines.SEED = 'range(20)'
|
|
fuzz = 'SEED'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
uint8_t a_buf[N][H][M][SIZE];
|
|
lfs3_ssize_t a_size[N][H][M];
|
|
struct lfs3_attr attrs[N][H][M];
|
|
struct lfs3_file_config filecfg[N][H];
|
|
lfs3_file_t file[N][H];
|
|
|
|
// create N files
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
char path[256];
|
|
sprintf(path, "cat%03x", x);
|
|
for (lfs3_size_t y = 0; y < H; y++) {
|
|
for (lfs3_size_t a = 0; a < M; a++) {
|
|
attrs[x][y][a] = (struct lfs3_attr){
|
|
.type = a,
|
|
.flags = LFS3_A_RDWR,
|
|
.buffer = a_buf[x][y][a],
|
|
.buffer_size = SIZE,
|
|
.size = &a_size[x][y][a],
|
|
};
|
|
}
|
|
filecfg[x][y] = (struct lfs3_file_config){
|
|
.attrs = attrs[x][y],
|
|
.attr_count = M,
|
|
};
|
|
|
|
lfs3_file_opencfg(&lfs3, &file[x][y], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT,
|
|
&filecfg[x][y]) => 0;
|
|
lfs3_file_write(&lfs3, &file[x][y], "meow", strlen("meow"))
|
|
=> strlen("meow");
|
|
lfs3_file_sync(&lfs3, &file[x][y]) => 0;
|
|
}
|
|
}
|
|
|
|
// set up a simulation to compare against
|
|
uint32_t *sim_prngs = malloc(N*M*sizeof(uint32_t));
|
|
memset(sim_prngs, 0, N*M*sizeof(uint32_t));
|
|
|
|
uint32_t prng = SEED;
|
|
for (lfs3_size_t i = 0; i < OPS; i++) {
|
|
// choose which operation to do
|
|
uint8_t op = TEST_PRNG(&prng) % 2;
|
|
|
|
// create an attr?
|
|
if (op == 0) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
// choose a file handle
|
|
lfs3_size_t y = TEST_PRNG(&prng) % H;
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
// choose a prng
|
|
uint32_t wprng = TEST_PRNG(&prng);
|
|
|
|
// update the attr
|
|
uint32_t wprng_ = wprng;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
memcpy(a_buf[x][y][a], wbuf, SIZE);
|
|
a_size[x][y][a] = SIZE;
|
|
lfs3_file_sync(&lfs3, &file[x][y]) => 0;
|
|
|
|
// update our sim
|
|
sim_prngs[x*M+a] = wprng;
|
|
|
|
// remove an attr?
|
|
} else if (op == 1) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
// choose a file handle
|
|
lfs3_size_t y = TEST_PRNG(&prng) % H;
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
|
|
// remove the attr
|
|
a_size[x][y][a] = LFS3_ERR_NOATTR;
|
|
lfs3_file_sync(&lfs3, &file[x][y]) => 0;
|
|
|
|
// update our sim
|
|
sim_prngs[x*M+a] = 0;
|
|
}
|
|
}
|
|
|
|
// check attrs on all file handles
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
for (lfs3_size_t y = 0; y < H; y++) {
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[x*M+a]) {
|
|
assert(a_size[x][y][a] == SIZE);
|
|
uint32_t wprng_ = sim_prngs[x*M+a];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
assert(memcmp(a_buf[x][y][a], wbuf, SIZE) == 0);
|
|
} else {
|
|
assert(a_size[x][y][a] == LFS3_ERR_NOATTR);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean up sim/lfs3
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
for (lfs3_size_t y = 0; y < M; y++) {
|
|
lfs3_file_close(&lfs3, &file[x][y]) => 0;
|
|
}
|
|
}
|
|
free(sim_prngs);
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# fuzz file-attached attrs mixed with file moves and removes
|
|
[cases.test_attrs_fattr_mvrm_fuzz_fuzz]
|
|
defines.N = 64
|
|
defines.M = 4
|
|
defines.SIZE = 4
|
|
defines.OPS = '4*N*M'
|
|
defines.SEED = 'range(20)'
|
|
fuzz = 'SEED'
|
|
code = '''
|
|
lfs3_t lfs3;
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
|
|
uint8_t a_buf[N][M][SIZE];
|
|
lfs3_ssize_t a_size[N][M];
|
|
struct lfs3_attr attrs[N][M];
|
|
struct lfs3_file_config filecfg[N];
|
|
lfs3_file_t file[N];
|
|
|
|
// create N files
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
char path[256];
|
|
sprintf(path, "cat%03x", x);
|
|
for (lfs3_size_t a = 0; a < M; a++) {
|
|
attrs[x][a] = (struct lfs3_attr){
|
|
.type = a,
|
|
.flags = LFS3_A_RDWR,
|
|
.buffer = a_buf[x][a],
|
|
.buffer_size = SIZE,
|
|
.size = &a_size[x][a],
|
|
};
|
|
}
|
|
filecfg[x] = (struct lfs3_file_config){
|
|
.attrs = attrs[x],
|
|
.attr_count = M,
|
|
};
|
|
|
|
lfs3_file_opencfg(&lfs3, &file[x], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL,
|
|
&filecfg[x]) => 0;
|
|
lfs3_file_write(&lfs3, &file[x], "meow", strlen("meow"))
|
|
=> strlen("meow");
|
|
lfs3_file_sync(&lfs3, &file[x]) => 0;
|
|
}
|
|
|
|
// set up a simulation to compare against
|
|
uint32_t *sim_prngs = malloc(N*M*sizeof(uint32_t));
|
|
memset(sim_prngs, 0, N*M*sizeof(uint32_t));
|
|
|
|
uint32_t prng = SEED;
|
|
for (lfs3_size_t i = 0; i < OPS; i++) {
|
|
// choose which operation to do
|
|
uint8_t op = TEST_PRNG(&prng) % 4;
|
|
|
|
// create an attr?
|
|
if (op == 0) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
// choose a prng
|
|
uint32_t wprng = TEST_PRNG(&prng);
|
|
|
|
// update the attr
|
|
uint32_t wprng_ = wprng;
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
memcpy(a_buf[x][a], wbuf, SIZE);
|
|
a_size[x][a] = SIZE;
|
|
lfs3_file_sync(&lfs3, &file[x]) => 0;
|
|
|
|
// update our sim
|
|
sim_prngs[x*M+a] = wprng;
|
|
|
|
// remove an attr?
|
|
} else if (op == 1) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
// choose an attr
|
|
uint8_t a = TEST_PRNG(&prng) % M;
|
|
|
|
// remove the attr
|
|
a_size[x][a] = LFS3_ERR_NOATTR;
|
|
lfs3_file_sync(&lfs3, &file[x]) => 0;
|
|
|
|
// update our sim
|
|
sim_prngs[x*M+a] = 0;
|
|
|
|
// remove a file?
|
|
} else if (op == 2) {
|
|
// choose a file
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
char path[256];
|
|
sprintf(path, "cat%03x", x);
|
|
|
|
// remove the file
|
|
lfs3_remove(&lfs3, path) => 0;
|
|
|
|
// check that remove had no affect on open attrs
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[x*M+a]) {
|
|
assert(a_size[x][a] == SIZE);
|
|
uint32_t wprng_ = sim_prngs[x*M+a];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
assert(memcmp(a_buf[x][a], wbuf, SIZE) == 0);
|
|
} else {
|
|
assert(a_size[x][a] == LFS3_ERR_NOATTR);
|
|
}
|
|
}
|
|
|
|
// but recreate the file so we always have something to
|
|
// attach attrs to
|
|
lfs3_file_close(&lfs3, &file[x]) => 0;
|
|
sprintf(path, "cat%03x", x);
|
|
lfs3_file_opencfg(&lfs3, &file[x], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL,
|
|
&filecfg[x]) => 0;
|
|
lfs3_file_write(&lfs3, &file[x], "miao", strlen("miao"))
|
|
=> strlen("miao");
|
|
lfs3_file_sync(&lfs3, &file[x]) => 0;
|
|
|
|
// update our sim
|
|
memset(&sim_prngs[x*M], 0, M*sizeof(uint32_t));
|
|
|
|
// rename a file?
|
|
} else if (op == 3) {
|
|
// choose two files
|
|
lfs3_size_t x = TEST_PRNG(&prng) % N;
|
|
lfs3_size_t y = TEST_PRNG(&prng) % N;
|
|
char path[256];
|
|
char path_[256];
|
|
sprintf(path, "cat%03x", x);
|
|
sprintf(path_, "cat%03x", y);
|
|
|
|
// rename the file
|
|
lfs3_rename(&lfs3, path, path_) => 0;
|
|
|
|
// check that rename had no affect on open attrs
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[x*M+a]) {
|
|
assert(a_size[x][a] == SIZE);
|
|
uint32_t wprng_ = sim_prngs[x*M+a];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
assert(memcmp(a_buf[x][a], wbuf, SIZE) == 0);
|
|
} else {
|
|
assert(a_size[x][a] == LFS3_ERR_NOATTR);
|
|
}
|
|
}
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[y*M+a]) {
|
|
assert(a_size[y][a] == SIZE);
|
|
uint32_t wprng_ = sim_prngs[y*M+a];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
assert(memcmp(a_buf[y][a], wbuf, SIZE) == 0);
|
|
} else {
|
|
assert(a_size[y][a] == LFS3_ERR_NOATTR);
|
|
}
|
|
}
|
|
|
|
if (x != y) {
|
|
// but recreate the file so we always have something to
|
|
// attach attrs to
|
|
lfs3_file_close(&lfs3, &file[y]) => 0;
|
|
sprintf(path, "cat%03x", y);
|
|
lfs3_file_opencfg(&lfs3, &file[y], path,
|
|
LFS3_O_WRONLY,
|
|
&filecfg[y]) => 0;
|
|
lfs3_file_close(&lfs3, &file[x]) => 0;
|
|
sprintf(path, "cat%03x", x);
|
|
lfs3_file_opencfg(&lfs3, &file[x], path,
|
|
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL,
|
|
&filecfg[x]) => 0;
|
|
lfs3_file_write(&lfs3, &file[x], "nyan", strlen("nyan"))
|
|
=> strlen("nyan");
|
|
lfs3_file_sync(&lfs3, &file[x]) => 0;
|
|
|
|
// update our sim
|
|
memcpy(&sim_prngs[y*M], &sim_prngs[x*M], M*sizeof(uint32_t));
|
|
memset(&sim_prngs[x*M], 0, M*sizeof(uint32_t));
|
|
}
|
|
}
|
|
}
|
|
|
|
// check attrs on all file handles
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
for (uint16_t a = 0; a < M; a++) {
|
|
if (sim_prngs[x*M+a]) {
|
|
assert(a_size[x][a] == SIZE);
|
|
uint32_t wprng_ = sim_prngs[x*M+a];
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t i = 0; i < SIZE; i++) {
|
|
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
|
|
}
|
|
assert(memcmp(a_buf[x][a], wbuf, SIZE) == 0);
|
|
} else {
|
|
assert(a_size[x][a] == LFS3_ERR_NOATTR);
|
|
}
|
|
}
|
|
}
|
|
|
|
// clean up sim/lfs3
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
lfs3_file_close(&lfs3, &file[x]) => 0;
|
|
}
|
|
free(sim_prngs);
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|
|
# test that file-attached attrs are actually atomic
|
|
[cases.test_attrs_fattr_pl_fuzz_fuzz]
|
|
defines.N = 64
|
|
defines.M = 4
|
|
defines.SIZE = 4
|
|
defines.OPS = '4*N*M'
|
|
defines.SEED = 'range(20)'
|
|
fuzz = 'SEED'
|
|
reentrant = true
|
|
code = '''
|
|
// format once per test
|
|
lfs3_t lfs3;
|
|
int err = lfs3_mount(&lfs3, LFS3_M_RDWR, CFG);
|
|
if (err) {
|
|
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// keep some test state on disk to survive powerloss
|
|
typedef struct fuzz_state {
|
|
lfs3_size_t i;
|
|
uint32_t prng;
|
|
} fuzz_state_t;
|
|
|
|
lfs3_file_t state_file;
|
|
lfs3_file_open(&lfs3, &state_file,
|
|
"state", LFS3_O_RDWR | LFS3_O_CREAT) => 0;
|
|
fuzz_state_t state;
|
|
if (lfs3_file_size(&lfs3, &state_file) == 0) {
|
|
state.i = 0;
|
|
state.prng = SEED;
|
|
} else {
|
|
lfs3_file_read(&lfs3, &state_file, &state, sizeof(state))
|
|
=> sizeof(state);
|
|
}
|
|
|
|
for (; state.i < OPS; state.i++) {
|
|
// choose a random file
|
|
lfs3_size_t x = TEST_PRNG(&state.prng) % N;
|
|
char path[256];
|
|
sprintf(path, "cat%03x", x);
|
|
|
|
// the invariant we hold here is that attrs are some increment
|
|
// of the file data mod 26, this should catch any issues with
|
|
// atomically updating attrs attached to files
|
|
|
|
// try to open the file with attrs
|
|
uint8_t a_buf[M][SIZE];
|
|
lfs3_ssize_t a_size[M];
|
|
struct lfs3_attr attrs[M];
|
|
struct lfs3_file_config filecfg;
|
|
lfs3_file_t file;
|
|
for (lfs3_size_t a = 0; a < M; a++) {
|
|
attrs[a] = (struct lfs3_attr){
|
|
.type = a,
|
|
.flags = LFS3_A_RDWR,
|
|
.buffer = a_buf[a],
|
|
.buffer_size = SIZE,
|
|
.size = &a_size[a],
|
|
};
|
|
}
|
|
filecfg = (struct lfs3_file_config){
|
|
.attrs = attrs,
|
|
.attr_count = M,
|
|
};
|
|
|
|
lfs3_file_opencfg(&lfs3, &file, path, LFS3_O_RDWR | LFS3_O_CREAT,
|
|
&filecfg) => 0;
|
|
|
|
// if the file exists, check our invariant
|
|
if (lfs3_file_size(&lfs3, &file) > 0) {
|
|
uint8_t wbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &file, wbuf, SIZE) => SIZE;
|
|
|
|
for (lfs3_size_t a = 0; a < M; a++) {
|
|
assert(a_size[a] == SIZE);
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
assert(a_buf[a][j] == 'a' + (((wbuf[j]-'a') + a) % 26));
|
|
}
|
|
}
|
|
}
|
|
|
|
// choose a new seed and rewrite our file
|
|
uint32_t wprng = TEST_PRNG(&state.prng);
|
|
uint8_t wbuf[SIZE];
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
wbuf[j] = 'a' + (TEST_PRNG(&wprng) % 26);
|
|
}
|
|
lfs3_file_rewind(&lfs3, &file) => 0;
|
|
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
|
|
|
// and update attrs
|
|
for (lfs3_size_t a = 0; a < M; a++) {
|
|
a_size[a] = SIZE;
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
a_buf[a][j] = 'a' + (((wbuf[j]-'a') + a) % 26);
|
|
}
|
|
}
|
|
|
|
// and sync/close
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
|
|
// update our state file
|
|
lfs3_file_rewind(&lfs3, &state_file) => 0;
|
|
lfs3_file_write(&lfs3, &state_file, &state, sizeof(state))
|
|
=> sizeof(state);
|
|
lfs3_file_sync(&lfs3, &state_file) => 0;
|
|
}
|
|
|
|
// go ahead and close our state file in case we remount
|
|
lfs3_file_close(&lfs3, &state_file) => 0;
|
|
|
|
for (int remount = 0; remount < 2; remount++) {
|
|
// remount?
|
|
if (remount) {
|
|
lfs3_unmount(&lfs3) => 0;
|
|
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
|
|
}
|
|
|
|
// check that our invariant was held in all files
|
|
for (lfs3_size_t x = 0; x < N; x++) {
|
|
char path[256];
|
|
sprintf(path, "cat%03x", x);
|
|
uint8_t a_buf[M][SIZE];
|
|
lfs3_ssize_t a_size[M];
|
|
struct lfs3_attr attrs[M];
|
|
struct lfs3_file_config filecfg;
|
|
lfs3_file_t file;
|
|
for (lfs3_size_t a = 0; a < M; a++) {
|
|
attrs[a] = (struct lfs3_attr){
|
|
.type = a,
|
|
.flags = LFS3_A_RDWR,
|
|
.buffer = a_buf[a],
|
|
.buffer_size = SIZE,
|
|
.size = &a_size[a],
|
|
};
|
|
}
|
|
filecfg = (struct lfs3_file_config){
|
|
.attrs = attrs,
|
|
.attr_count = M,
|
|
};
|
|
|
|
int err = lfs3_file_opencfg(&lfs3, &file, path, LFS3_O_RDONLY,
|
|
&filecfg);
|
|
assert(!err || err == LFS3_ERR_NOENT);
|
|
if (err == LFS3_ERR_NOENT) {
|
|
continue;
|
|
}
|
|
|
|
// if the file exists, check our invariant
|
|
uint8_t wbuf[SIZE];
|
|
lfs3_file_read(&lfs3, &file, wbuf, SIZE) => SIZE;
|
|
|
|
for (lfs3_size_t a = 0; a < M; a++) {
|
|
assert(a_size[a] == SIZE);
|
|
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
|
assert(a_buf[a][j] == 'a' + (((wbuf[j]-'a') + a) % 26));
|
|
}
|
|
}
|
|
|
|
lfs3_file_close(&lfs3, &file) => 0;
|
|
}
|
|
}
|
|
|
|
lfs3_unmount(&lfs3) => 0;
|
|
'''
|
|
|