# Custom attribute tests after = ['test_files', 'test_fsync', 'test_forphans'] ## 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 => directory # FILETYPE=2 => root defines.FILETYPE = [0, 1, 2] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // create a file? if (FILETYPE == 0) { path = "cat"; lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else if (FILETYPE == 1) { path = "armadillo"; lfsr_mkdir(&lfs, path) => 0; // do nothing for root } else { path = "/"; } // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, path, 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, path, 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, path, 'c', c, strlen(c)) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, path, 'a') => strlen(a); lfsr_sizeattr(&lfs, path, 'b') => strlen(b); lfsr_sizeattr(&lfs, path, 'c') => strlen(c); // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => strlen(a); assert(memcmp(rbuf, a, strlen(a)) == 0); lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => strlen(b); assert(memcmp(rbuf, b, strlen(b)) == 0); lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => strlen(c); assert(memcmp(rbuf, c, strlen(c)) == 0); } lfsr_unmount(&lfs) => 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 => directory # FILETYPE=2 => root defines.FILETYPE = [0, 1, 2] defines.BUFSIZE = [1, 4, 7] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // create a file? if (FILETYPE == 0) { path = "cat"; lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else if (FILETYPE == 1) { path = "armadillo"; lfsr_mkdir(&lfs, path) => 0; // do nothing for root } else { path = "/"; } // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, path, 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, path, 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, path, 'c', c, strlen(c)) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, path, 'a') => strlen(a); lfsr_sizeattr(&lfs, path, 'b') => strlen(b); lfsr_sizeattr(&lfs, path, 'c') => strlen(c); // mark rbuf so we can detect overflow uint8_t rbuf[256]; rbuf[BUFSIZE] = '!'; // try reading truncated attrs lfsr_getattr(&lfs, path, 'a', rbuf, BUFSIZE) => BUFSIZE; assert(memcmp(rbuf, a, BUFSIZE) == 0); assert(rbuf[BUFSIZE] == '!'); lfsr_getattr(&lfs, path, 'b', rbuf, BUFSIZE) => BUFSIZE; assert(memcmp(rbuf, b, BUFSIZE) == 0); assert(rbuf[BUFSIZE] == '!'); lfsr_getattr(&lfs, path, 'c', rbuf, BUFSIZE) => BUFSIZE; assert(memcmp(rbuf, c, BUFSIZE) == 0); assert(rbuf[BUFSIZE] == '!'); // try reading the full attrs lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => strlen(a); assert(memcmp(rbuf, a, strlen(a)) == 0); lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => strlen(b); assert(memcmp(rbuf, b, strlen(b)) == 0); lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => strlen(c); assert(memcmp(rbuf, c, strlen(c)) == 0); } lfsr_unmount(&lfs) => 0; ''' # test ENOATTR works [cases.test_attrs_setattr_noattr] # type of file to attach attrs to # FILETYPE=0 => regular file # FILETYPE=1 => directory # FILETYPE=2 => root defines.FILETYPE = [0, 1, 2] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // create a file? if (FILETYPE == 0) { path = "cat"; lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else if (FILETYPE == 1) { path = "armadillo"; lfsr_mkdir(&lfs, path) => 0; // do nothing for root } else { path = "/"; } // try getting the attr sizes lfsr_sizeattr(&lfs, path, 'a') => LFS_ERR_NOATTR; lfsr_sizeattr(&lfs, path, 'b') => LFS_ERR_NOATTR; lfsr_sizeattr(&lfs, path, 'c') => LFS_ERR_NOATTR; // try reading attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // make sure setattr didn't quietly create attrs // try getting the attr sizes lfsr_sizeattr(&lfs, path, 'a') => LFS_ERR_NOATTR; lfsr_sizeattr(&lfs, path, 'b') => LFS_ERR_NOATTR; lfsr_sizeattr(&lfs, path, 'c') => LFS_ERR_NOATTR; // try reading attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; } lfsr_unmount(&lfs) => 0; ''' # test that updating attrs works [cases.test_attrs_setattr_update] # type of file to attach attrs to # FILETYPE=0 => regular file # FILETYPE=1 => directory # FILETYPE=2 => root defines.FILETYPE = [0, 1, 2] # update based on this mask defines.MASK = 'range(0x8)' code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // create a file? if (FILETYPE == 0) { path = "cat"; lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else if (FILETYPE == 1) { path = "armadillo"; lfsr_mkdir(&lfs, path) => 0; // do nothing for root } else { path = "/"; } // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, path, 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, path, 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, path, 'c', c, strlen(c)) => 0; // rewrite some attrs const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips."; if (MASK & 0x1) { lfsr_setattr(&lfs, path, 'a', a_, strlen(a_)) => 0; } const char *b_ = "Three slash four cup butter or margarine."; if (MASK & 0x2) { lfsr_setattr(&lfs, path, 'b', b_, strlen(b_)) => 0; } const char *c_ = "One and two third cups granulated sugar."; if (MASK & 0x4) { lfsr_setattr(&lfs, path, 'c', c_, strlen(c_)) => 0; } for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes if (MASK & 0x1) { lfsr_sizeattr(&lfs, path, 'a') => strlen(a_); } else { lfsr_sizeattr(&lfs, path, 'a') => strlen(a); } if (MASK & 0x2) { lfsr_sizeattr(&lfs, path, 'b') => strlen(b_); } else { lfsr_sizeattr(&lfs, path, 'b') => strlen(b); } if (MASK & 0x4) { lfsr_sizeattr(&lfs, path, 'c') => strlen(c_); } else { lfsr_sizeattr(&lfs, path, 'c') => strlen(c); } // try reading attrs uint8_t rbuf[256]; if (MASK & 0x1) { lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => strlen(a_); assert(memcmp(rbuf, a_, strlen(a_)) == 0); } else { lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => strlen(a); assert(memcmp(rbuf, a, strlen(a)) == 0); } if (MASK & 0x2) { lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => strlen(b_); assert(memcmp(rbuf, b_, strlen(b_)) == 0); } else { lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => strlen(b); assert(memcmp(rbuf, b, strlen(b)) == 0); } if (MASK & 0x4) { lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => strlen(c_); assert(memcmp(rbuf, c_, strlen(c_)) == 0); } else { lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => strlen(c); assert(memcmp(rbuf, c, strlen(c)) == 0); } } lfsr_unmount(&lfs) => 0; ''' # test removing attrs [cases.test_attrs_removeattr] # type of file to attach attrs to # FILETYPE=0 => regular file # FILETYPE=1 => directory # FILETYPE=2 => root defines.FILETYPE = [0, 1, 2] # remove based on this mask defines.MASK = 'range(0x8)' code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // create a file? if (FILETYPE == 0) { path = "cat"; lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else if (FILETYPE == 1) { path = "armadillo"; lfsr_mkdir(&lfs, path) => 0; // do nothing for root } else { path = "/"; } // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, path, 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, path, 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, path, 'c', c, strlen(c)) => 0; // remove some attrs if (MASK & 0x1) { lfsr_removeattr(&lfs, path, 'a') => 0; } if (MASK & 0x2) { lfsr_removeattr(&lfs, path, 'b') => 0; } if (MASK & 0x4) { lfsr_removeattr(&lfs, path, 'c') => 0; } for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes if (MASK & 0x1) { lfsr_sizeattr(&lfs, path, 'a') => LFS_ERR_NOATTR; } else { lfsr_sizeattr(&lfs, path, 'a') => strlen(a); } if (MASK & 0x2) { lfsr_sizeattr(&lfs, path, 'b') => LFS_ERR_NOATTR; } else { lfsr_sizeattr(&lfs, path, 'b') => strlen(b); } if (MASK & 0x4) { lfsr_sizeattr(&lfs, path, 'c') => LFS_ERR_NOATTR; } else { lfsr_sizeattr(&lfs, path, 'c') => strlen(c); } // try reading the full attrs uint8_t rbuf[256]; if (MASK & 0x1) { lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; } else { lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => strlen(a); assert(memcmp(rbuf, a, strlen(a)) == 0); } if (MASK & 0x2) { lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; } else { lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => strlen(b); assert(memcmp(rbuf, b, strlen(b)) == 0); } if (MASK & 0x4) { lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; } else { lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => strlen(c); assert(memcmp(rbuf, c, strlen(c)) == 0); } } lfsr_unmount(&lfs) => 0; ''' # test the full range of attrs [cases.test_attrs_all] # type of file to attach attrs to # FILETYPE=0 => regular file # FILETYPE=1 => directory # FILETYPE=2 => root defines.FILETYPE = [0, 1, 2] defines.SIZE = 4 code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // create a file? if (FILETYPE == 0) { path = "cat"; lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else if (FILETYPE == 1) { path = "armadillo"; lfsr_mkdir(&lfs, path) => 0; // do nothing for root } else { path = "/"; } // try creating every attr, this tests encoding quirks uint32_t prng = 42; for (uint16_t a = 0; a < 0x100; a++) { // create the attr uint8_t wbuf[SIZE]; for (lfs_size_t i = 0; i < SIZE; i++) { wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26); } lfsr_setattr(&lfs, path, a, wbuf, SIZE) => 0; // try getting the attr size lfsr_sizeattr(&lfs, path, a) => SIZE; // try reading the attr uint8_t rbuf[256]; lfsr_getattr(&lfs, path, a, rbuf, sizeof(rbuf)) => SIZE; assert(memcmp(rbuf, wbuf, SIZE) == 0); // remove the attr lfsr_removeattr(&lfs, path, a) => 0; } lfsr_unmount(&lfs) => 0; ''' # test creating a bunch of attrs [cases.test_attrs_many] # type of file to attach attrs to # FILETYPE=0 => regular file # FILETYPE=1 => directory # FILETYPE=2 => root defines.FILETYPE = [0, 1, 2] defines.M = 40 defines.SIZE = 4 defines.COMPACT = [false, true] defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // create a file? if (FILETYPE == 0) { path = "cat"; lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else if (FILETYPE == 1) { path = "armadillo"; lfsr_mkdir(&lfs, 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 (lfs_size_t i = 0; i < SIZE; i++) { wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26); } lfsr_setattr(&lfs, path, a, wbuf, SIZE) => 0; } // try compacting? if (COMPACT) { lfsr_fs_gc(&lfs, -1, LFS_GC_COMPACT) => 0; } for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes for (uint16_t a = 0; a < M; a++) { lfsr_sizeattr(&lfs, path, a) => SIZE; } // try reading the attrs prng = 42; for (uint16_t a = 0; a < M; a++) { uint8_t wbuf[SIZE]; for (lfs_size_t i = 0; i < SIZE; i++) { wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26); } uint8_t rbuf[256]; lfsr_getattr(&lfs, path, a, rbuf, sizeof(rbuf)) => SIZE; assert(memcmp(rbuf, wbuf, SIZE) == 0); } } lfsr_unmount(&lfs) => 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 => directory defines.FILETYPE = [0, 1] defines.N = 64 defines.M = 4 defines.SIZE = 4 defines.COMPACT = [false, true] defines.GC_COMPACT_THRESH = 'BLOCK_SIZE/2' code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create N files uint32_t prng = 42; for (lfs_size_t i = 0; i < N; i++) { char path[256]; // create a file? if (FILETYPE == 0) { sprintf(path, "cat%03x", i); lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else { sprintf(path, "armadillo%03x", i); lfsr_mkdir(&lfs, path) => 0; } // create M attrs for (uint16_t a = 0; a < M; a++) { uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } lfsr_setattr(&lfs, path, a, wbuf, SIZE) => 0; } } // try compacting? if (COMPACT) { lfsr_fs_gc(&lfs, -1, LFS_GC_COMPACT) => 0; } for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } prng = 42; for (lfs_size_t x = 0; x < N; x++) { char path[256]; // file? if (FILETYPE == 0) { sprintf(path, "cat%03x", x); // dir? } else { sprintf(path, "armadillo%03x", x); } // try getting the attr sizes for (uint16_t a = 0; a < M; a++) { lfsr_sizeattr(&lfs, path, a) => SIZE; } // try reading the attrs for (uint16_t a = 0; a < M; a++) { uint8_t wbuf[SIZE]; for (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26); } uint8_t rbuf[256]; lfsr_getattr(&lfs, path, a, rbuf, sizeof(rbuf)) => SIZE; assert(memcmp(rbuf, wbuf, SIZE) == 0); } } } lfsr_unmount(&lfs) => 0; ''' # fuzz attrs [cases.test_attrs_fuzz] # type of file to attach attrs to # FILETYPE=0 => regular file # FILETYPE=1 => directory # FILETYPE=2 => root defines.FILETYPE = [0, 1, 2] defines.M = 10 defines.SIZE = 4 defines.OPS = '4*M' defines.SEED = 'range(20)' fuzz = 'SEED' code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // create a file? if (FILETYPE == 0) { path = "cat"; lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else if (FILETYPE == 1) { path = "armadillo"; lfsr_mkdir(&lfs, 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 (lfs_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 (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26); } lfsr_setattr(&lfs, 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]) { lfsr_removeattr(&lfs, path, a) => 0; } else { lfsr_removeattr(&lfs, path, a) => LFS_ERR_NOATTR; } // update our sim sim_prngs[a] = 0; } } for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting each attr size for (uint16_t a = 0; a < M; a++) { if (sim_prngs[a]) { lfsr_sizeattr(&lfs, path, a) => SIZE; } else { lfsr_sizeattr(&lfs, path, a) => LFS_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 (lfs_size_t i = 0; i < SIZE; i++) { wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26); } uint8_t rbuf[256]; lfsr_getattr(&lfs, path, a, rbuf, sizeof(rbuf)) => SIZE; assert(memcmp(rbuf, wbuf, SIZE) == 0); } else { uint8_t rbuf[256]; lfsr_getattr(&lfs, path, a, rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; } } } // clean up sim/lfs free(sim_prngs); lfsr_unmount(&lfs) => 0; ''' # fuzz attrs on multiple files [cases.test_attrs_fuzz_fuzz] # type of file to attach attrs to # FILETYPE=0 => regular file # FILETYPE=1 => directory defines.FILETYPE = [0, 1] defines.N = 64 defines.M = 4 defines.SIZE = 4 defines.OPS = '4*N*M' defines.SEED = 'range(20)' fuzz = 'SEED' code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create N files for (lfs_size_t i = 0; i < N; i++) { char path[256]; // create a file? if (FILETYPE == 0) { sprintf(path, "cat%03x", i); lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else { sprintf(path, "armadillo%03x", i); lfsr_mkdir(&lfs, 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 (lfs_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 lfs_size_t x = TEST_PRNG(&prng) % N; char path[256]; // file? if (FILETYPE == 0) { sprintf(path, "cat%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 (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26); } lfsr_setattr(&lfs, path, a, wbuf, SIZE) => 0; // update our sim sim_prngs[x*M+a] = wprng; // remove an attr? } else if (op == 1) { // choose a file lfs_size_t x = TEST_PRNG(&prng) % N; char path[256]; // file? if (FILETYPE == 0) { sprintf(path, "cat%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]) { lfsr_removeattr(&lfs, path, a) => 0; } else { lfsr_removeattr(&lfs, path, a) => LFS_ERR_NOATTR; } // update our sim sim_prngs[x*M+a] = 0; } } for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } for (lfs_size_t x = 0; x < N; x++) { char path[256]; // file? if (FILETYPE == 0) { sprintf(path, "cat%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]) { lfsr_sizeattr(&lfs, path, a) => SIZE; } else { lfsr_sizeattr(&lfs, path, a) => LFS_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 (lfs_size_t i = 0; i < SIZE; i++) { wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26); } uint8_t rbuf[256]; lfsr_getattr(&lfs, path, a, rbuf, sizeof(rbuf)) => SIZE; assert(memcmp(rbuf, wbuf, SIZE) == 0); } else { uint8_t rbuf[256]; lfsr_getattr(&lfs, path, a, rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; } } } } // clean up sim/lfs free(sim_prngs); lfsr_unmount(&lfs) => 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 => directory defines.FILETYPE = [0, 1] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // create a file? if (FILETYPE == 0) { path = "cat"; lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else { path = "armadillo"; lfsr_mkdir(&lfs, path) => 0; } // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, path, 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, path, 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, path, 'c', c, strlen(c)) => 0; // remove the file lfsr_remove(&lfs, path) => 0; // create the file again // file? if (FILETYPE == 0) { lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "miao", strlen("miao")) => strlen("miao"); lfsr_file_close(&lfs, &file) => 0; // dir? } else { lfsr_mkdir(&lfs, path) => 0; } for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, path, 'a') => LFS_ERR_NOATTR; lfsr_sizeattr(&lfs, path, 'b') => LFS_ERR_NOATTR; lfsr_sizeattr(&lfs, path, 'c') => LFS_ERR_NOATTR; // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; } lfsr_unmount(&lfs) => 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 => directory defines.FILETYPE = [0, 1] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // create a file? if (FILETYPE == 0) { path = "cat"; lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else { path = "armadillo"; lfsr_mkdir(&lfs, path) => 0; } // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, path, 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, path, 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, path, 'c', c, strlen(c)) => 0; // create another file and move it onto our file // file? if (FILETYPE == 0) { lfsr_file_t file; lfsr_file_open(&lfs, &file, "beaver", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "miao", strlen("miao")) => strlen("miao"); lfsr_file_close(&lfs, &file) => 0; // dir? } else { lfsr_mkdir(&lfs, "beaver") => 0; } lfsr_rename(&lfs, "beaver", path) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, path, 'a') => LFS_ERR_NOATTR; lfsr_sizeattr(&lfs, path, 'b') => LFS_ERR_NOATTR; lfsr_sizeattr(&lfs, path, 'c') => LFS_ERR_NOATTR; // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; } lfsr_unmount(&lfs) => 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 => directory defines.FILETYPE = [0, 1] defines.REPLACE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; const char *path; // file? if (FILETYPE == 0) { path = "cat"; // dir? } else { path = "armadillo"; } // if replacing create a file to replace if (REPLACE) { // create a file? if (FILETYPE == 0) { lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else { lfsr_mkdir(&lfs, path) => 0; } } // create a file? if (FILETYPE == 0) { lfsr_file_t file; lfsr_file_open(&lfs, &file, "beaver", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "miao", strlen("miao")) => strlen("miao"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else { lfsr_mkdir(&lfs, "beaver") => 0; } // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, "beaver", 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, "beaver", 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, "beaver", 'c', c, strlen(c)) => 0; // move file lfsr_rename(&lfs, "beaver", path) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, path, 'a') => strlen(a); lfsr_sizeattr(&lfs, path, 'b') => strlen(b); lfsr_sizeattr(&lfs, path, 'c') => strlen(c); // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, path, 'a', rbuf, sizeof(rbuf)) => strlen(a); assert(memcmp(rbuf, a, strlen(a)) == 0); lfsr_getattr(&lfs, path, 'b', rbuf, sizeof(rbuf)) => strlen(b); assert(memcmp(rbuf, b, strlen(b)) == 0); lfsr_getattr(&lfs, path, 'c', rbuf, sizeof(rbuf)) => strlen(c); assert(memcmp(rbuf, c, strlen(c)) == 0); } lfsr_unmount(&lfs) => 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 => directory defines.FILETYPE = [0, 1] defines.N = 64 defines.M = 4 defines.SIZE = 4 defines.OPS = '4*N*M' defines.SEED = 'range(20)' fuzz = 'SEED' code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create N files for (lfs_size_t i = 0; i < N; i++) { char path[256]; // create a file? if (FILETYPE == 0) { sprintf(path, "cat%03x", i); lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else { sprintf(path, "armadillo%03x", i); lfsr_mkdir(&lfs, 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 (lfs_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 lfs_size_t x = TEST_PRNG(&prng) % N; char path[256]; // file? if (FILETYPE == 0) { sprintf(path, "cat%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 (lfs_size_t j = 0; j < SIZE; j++) { wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26); } lfsr_setattr(&lfs, path, a, wbuf, SIZE) => 0; // update our sim sim_prngs[x*M+a] = wprng; // remove an attr? } else if (op == 1) { // choose a file lfs_size_t x = TEST_PRNG(&prng) % N; char path[256]; // file? if (FILETYPE == 0) { sprintf(path, "cat%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]) { lfsr_removeattr(&lfs, path, a) => 0; } else { lfsr_removeattr(&lfs, path, a) => LFS_ERR_NOATTR; } // update our sim sim_prngs[x*M+a] = 0; // remove a file? } else if (op == 2) { // choose a file lfs_size_t x = TEST_PRNG(&prng) % N; char path[256]; // file? if (FILETYPE == 0) { sprintf(path, "cat%03x", x); // dir? } else { sprintf(path, "armadillo%03x", x); } // remove the file lfsr_remove(&lfs, path) => 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); lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "miao", strlen("miao")) => strlen("miao"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else { sprintf(path, "armadillo%03x", x); lfsr_mkdir(&lfs, 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 lfs_size_t x = TEST_PRNG(&prng) % N; lfs_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); // dir? } else { sprintf(path, "armadillo%03x", x); sprintf(path_, "armadillo%03x", y); } // rename the file lfsr_rename(&lfs, path, path_) => 0; if (x != y) { // but recreate the file so we always have something to // attach attrs to // create a file? if (FILETYPE == 0) { sprintf(path, "cat%03x", x); lfsr_file_t file; lfsr_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "nyan", strlen("nyan")) => strlen("nyan"); lfsr_file_close(&lfs, &file) => 0; // create a dir? } else { sprintf(path, "armadillo%03x", x); lfsr_mkdir(&lfs, 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)); } } } for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } for (lfs_size_t x = 0; x < N; x++) { char path[256]; // file? if (FILETYPE == 0) { sprintf(path, "cat%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]) { lfsr_sizeattr(&lfs, path, a) => SIZE; } else { lfsr_sizeattr(&lfs, path, a) => LFS_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 (lfs_size_t i = 0; i < SIZE; i++) { wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26); } uint8_t rbuf[256]; lfsr_getattr(&lfs, path, a, rbuf, sizeof(rbuf)) => SIZE; assert(memcmp(rbuf, wbuf, SIZE) == 0); } else { uint8_t rbuf[256]; lfsr_getattr(&lfs, path, a, rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; } } } } // clean up sim/lfs free(sim_prngs); lfsr_unmount(&lfs) => 0; ''' ## Tests involving file-attached attrs # test that file-attached attrs are read correctly [cases.test_attrs_fattr_get] defines.MODE = ['LFS_A_RDONLY', 'LFS_A_RDWR'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, "cat", 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, "cat", 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, "cat", 'c', c, strlen(c)) => 0; // try opening a file with these attrs uint8_t a_buf[256]; lfs_ssize_t a_size = -1; uint8_t b_buf[256]; lfs_ssize_t b_size = -1; uint8_t c_buf[256]; lfs_ssize_t c_size = -1; struct lfs_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 lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &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); lfsr_file_close(&lfs, &file) => 0; lfsr_unmount(&lfs) => 0; ''' # test that truncate attrs will work [cases.test_attrs_fattr_trunc] defines.MODE = ['LFS_A_RDONLY', 'LFS_A_RDWR'] defines.MUTSIZE = [false, true] defines.BUFSIZE = [1, 4, 7] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, "cat", 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, "cat", 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, "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] = '!'; lfs_ssize_t a_size = -1; uint8_t b_buf[256]; b_buf[BUFSIZE] = '!'; lfs_ssize_t b_size = -1; uint8_t c_buf[256]; c_buf[BUFSIZE] = '!'; lfs_ssize_t c_size = -1; struct lfs_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 lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &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] == '!'); lfsr_file_close(&lfs, &file) => 0; lfsr_unmount(&lfs) => 0; ''' # test that missing attrs are read correctly [cases.test_attrs_fattr_noattr] defines.MODE = ['LFS_A_RDONLY', 'LFS_A_RDWR'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // try opening a file with missing attrs uint8_t a_buf[256]; lfs_ssize_t a_size = -1; uint8_t b_buf[256]; lfs_ssize_t b_size = -1; uint8_t c_buf[256]; lfs_ssize_t c_size = -1; struct lfs_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 lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &file, "cat", MODE, &filecfg) => 0; // did we read the attrs correctly? if (MUTSIZE) { assert(a_size == LFS_ERR_NOATTR); } if (MUTSIZE) { assert(b_size == LFS_ERR_NOATTR); } if (MUTSIZE) { assert(c_size == LFS_ERR_NOATTR); } lfsr_file_close(&lfs, &file) => 0; lfsr_unmount(&lfs) => 0; ''' # catch LFS_O_TRUNC mistakes, this has created issues before [cases.test_attrs_fattr_otrunc] defines.MODE = ['LFS_A_RDWR'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, "cat", 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, "cat", 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, "cat", 'c', c, strlen(c)) => 0; // try opening a file with these attrs uint8_t a_buf[256]; lfs_ssize_t a_size = -1; uint8_t b_buf[256]; lfs_ssize_t b_size = -1; uint8_t c_buf[256]; lfs_ssize_t c_size = -1; struct lfs_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 lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &file, "cat", MODE | LFS_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); lfsr_file_close(&lfs, &file) => 0; lfsr_unmount(&lfs) => 0; ''' # orphan files should zero attributes [cases.test_attrs_fattr_orphan] defines.MODE = ['LFS_A_RDWR'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // _don't_ create a file // try opening a file with these attrs uint8_t a_buf[256]; lfs_ssize_t a_size = -1; uint8_t b_buf[256]; lfs_ssize_t b_size = -1; uint8_t c_buf[256]; lfs_ssize_t c_size = -1; struct lfs_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 lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_t file; lfsr_file_opencfg(&lfs, &file, "cat", MODE | LFS_O_CREAT, &filecfg) => 0; // did we read the attrs correctly? if (MUTSIZE) { assert(a_size == LFS_ERR_NOATTR); } if (MUTSIZE) { assert(b_size == LFS_ERR_NOATTR); } if (MUTSIZE) { assert(c_size == LFS_ERR_NOATTR); } lfsr_file_close(&lfs, &file) => 0; lfsr_unmount(&lfs) => 0; ''' # test that file-attached attrs are written correctly [cases.test_attrs_fattr_set] defines.MODE = ['LFS_A_WRONLY', 'LFS_A_RDWR'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &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]; lfs_ssize_t a_size; uint8_t b_buf[256]; lfs_ssize_t b_size; uint8_t c_buf[256]; lfs_ssize_t c_size; struct lfs_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 lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &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 lfsr_file_write(&lfs, &file, "miao", strlen("miao")) => strlen("miao"); lfsr_file_close(&lfs, &file) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, "cat", 'a') => strlen(a); lfsr_sizeattr(&lfs, "cat", 'b') => strlen(b); lfsr_sizeattr(&lfs, "cat", 'c') => strlen(c); // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a); assert(memcmp(rbuf, a, strlen(a)) == 0); lfsr_getattr(&lfs, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b); assert(memcmp(rbuf, b, strlen(b)) == 0); lfsr_getattr(&lfs, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c); assert(memcmp(rbuf, c, strlen(c)) == 0); } lfsr_unmount(&lfs) => 0; ''' # test that we can update existing attrs [cases.test_attrs_fattr_update] defines.MODE = ['LFS_A_WRONLY', 'LFS_A_RDWR'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, "cat", 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, "cat", 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, "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]; lfs_ssize_t a_size; uint8_t b_buf[256]; lfs_ssize_t b_size; uint8_t c_buf[256]; lfs_ssize_t c_size; struct lfs_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 lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &file, "cat", MODE, &filecfg) => 0; if (MODE == LFS_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 lfsr_file_write(&lfs, &file, "miao", strlen("miao")) => strlen("miao"); lfsr_file_close(&lfs, &file) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, "cat", 'a') => strlen(a_); lfsr_sizeattr(&lfs, "cat", 'b') => strlen(b_); lfsr_sizeattr(&lfs, "cat", 'c') => strlen(c_); // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a_); assert(memcmp(rbuf, a_, strlen(a_)) == 0); lfsr_getattr(&lfs, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b_); assert(memcmp(rbuf, b_, strlen(b_)) == 0); lfsr_getattr(&lfs, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c_); assert(memcmp(rbuf, c_, strlen(c_)) == 0); } lfsr_unmount(&lfs) => 0; ''' # test that we can remove attrs [cases.test_attrs_fattr_remove] defines.MODE = ['LFS_A_WRONLY', 'LFS_A_RDWR'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, "cat", 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, "cat", 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, "cat", 'c', c, strlen(c)) => 0; // try opening a file with attrs uint8_t a_buf[256]; lfs_ssize_t a_size; uint8_t b_buf[256]; lfs_ssize_t b_size; uint8_t c_buf[256]; lfs_ssize_t c_size; struct lfs_attr attrs[] = { { .type = 'a', .flags = MODE, .buffer = a_buf, .buffer_size = (MUTSIZE) ? (lfs_ssize_t)sizeof(a_buf) : LFS_ERR_NOATTR, .size = (MUTSIZE) ? &a_size : NULL, }, { .type = 'b', .flags = MODE, .buffer = b_buf, .buffer_size = (MUTSIZE) ? (lfs_ssize_t)sizeof(b_buf) : LFS_ERR_NOATTR, .size = (MUTSIZE) ? &b_size : NULL, }, { .type = 'c', .flags = MODE, .buffer = c_buf, .buffer_size = (MUTSIZE) ? (lfs_ssize_t)sizeof(c_buf) : LFS_ERR_NOATTR, .size = (MUTSIZE) ? &c_size : NULL, } }; struct lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &file, "cat", MODE, &filecfg) => 0; if (MODE == LFS_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 = LFS_ERR_NOATTR; b_size = LFS_ERR_NOATTR; c_size = LFS_ERR_NOATTR; // write and close our file to write the attrs out to disk lfsr_file_write(&lfs, &file, "miao", strlen("miao")) => strlen("miao"); lfsr_file_close(&lfs, &file) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, "cat", 'a') => LFS_ERR_NOATTR; lfsr_sizeattr(&lfs, "cat", 'b') => LFS_ERR_NOATTR; lfsr_sizeattr(&lfs, "cat", 'c') => LFS_ERR_NOATTR; // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, "cat", 'a', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; lfsr_getattr(&lfs, "cat", 'b', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; lfsr_getattr(&lfs, "cat", 'c', rbuf, sizeof(rbuf)) => LFS_ERR_NOATTR; } lfsr_unmount(&lfs) => 0; ''' # test that wronly attrs are not read from disk [cases.test_attrs_fattr_wronly] defines.MODE = ['LFS_A_WRONLY'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, "cat", 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, "cat", 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, "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_)); lfs_ssize_t a_size = strlen(a_); uint8_t b_buf[256]; memcpy(b_buf, b_, strlen(b_)); lfs_ssize_t b_size = strlen(b_); uint8_t c_buf[256]; memcpy(c_buf, c_, strlen(c_)); lfs_ssize_t c_size = strlen(c_); struct lfs_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 lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &file, "cat", LFS_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 lfsr_file_write(&lfs, &file, "miao", strlen("miao")) => strlen("miao"); lfsr_file_close(&lfs, &file) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, "cat", 'a') => strlen(a_); lfsr_sizeattr(&lfs, "cat", 'b') => strlen(b_); lfsr_sizeattr(&lfs, "cat", 'c') => strlen(c_); // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a_); assert(memcmp(rbuf, a_, strlen(a_)) == 0); lfsr_getattr(&lfs, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b_); assert(memcmp(rbuf, b_, strlen(b_)) == 0); lfsr_getattr(&lfs, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c_); assert(memcmp(rbuf, c_, strlen(c_)) == 0); } lfsr_unmount(&lfs) => 0; ''' # test that rdonly attrs have no effect on disk [cases.test_attrs_fattr_rdonly] defines.MODE = ['LFS_A_RDONLY'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, "cat", 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, "cat", 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, "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]; lfs_ssize_t a_size; uint8_t b_buf[256]; lfs_ssize_t b_size; uint8_t c_buf[256]; lfs_ssize_t c_size; struct lfs_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 lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &file, "cat", LFS_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 lfsr_file_write(&lfs, &file, "miao", strlen("miao")) => strlen("miao"); lfsr_file_close(&lfs, &file) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, "cat", 'a') => strlen(a); lfsr_sizeattr(&lfs, "cat", 'b') => strlen(b); lfsr_sizeattr(&lfs, "cat", 'c') => strlen(c); // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a); assert(memcmp(rbuf, a, strlen(a)) == 0); lfsr_getattr(&lfs, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b); assert(memcmp(rbuf, b, strlen(b)) == 0); lfsr_getattr(&lfs, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c); assert(memcmp(rbuf, c, strlen(c)) == 0); } lfsr_unmount(&lfs) => 0; ''' # test that attrs are written correctly even if there are no file changes [cases.test_attrs_fattr_noop] defines.MODE = ['LFS_A_WRONLY', 'LFS_A_RDWR'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, "cat", 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, "cat", 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, "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]; lfs_ssize_t a_size; uint8_t b_buf[256]; lfs_ssize_t b_size; uint8_t c_buf[256]; lfs_ssize_t c_size; struct lfs_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 lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &file, "cat", MODE, &filecfg) => 0; if (MODE == LFS_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! lfsr_file_close(&lfs, &file) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, "cat", 'a') => strlen(a_); lfsr_sizeattr(&lfs, "cat", 'b') => strlen(b_); lfsr_sizeattr(&lfs, "cat", 'c') => strlen(c_); // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a_); assert(memcmp(rbuf, a_, strlen(a_)) == 0); lfsr_getattr(&lfs, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b_); assert(memcmp(rbuf, b_, strlen(b_)) == 0); lfsr_getattr(&lfs, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c_); assert(memcmp(rbuf, c_, strlen(c_)) == 0); } lfsr_unmount(&lfs) => 0; ''' # test that lazy attrs aren't written _until_ there are file changes [cases.test_attrs_fattr_lazy] defines.MODE = ['LFS_A_WRONLY', 'LFS_A_RDWR'] defines.MUTSIZE = [false, true] code = ''' lfs_t lfs; lfsr_format(&lfs, LFS_F_RDWR, CFG) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; // create a file lfsr_file_t file; lfsr_file_open(&lfs, &file, "cat", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfsr_file_write(&lfs, &file, "meow", strlen("meow")) => strlen("meow"); lfsr_file_close(&lfs, &file) => 0; // create some attrs const char *a = "One 18.25 ounce package chocolate cake mix."; lfsr_setattr(&lfs, "cat", 'a', a, strlen(a)) => 0; const char *b = "One can prepared coconut pecan frosting."; lfsr_setattr(&lfs, "cat", 'b', b, strlen(b)) => 0; const char *c = "Three slash four cup vegetable oil."; lfsr_setattr(&lfs, "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]; lfs_ssize_t a_size; uint8_t b_buf[256]; lfs_ssize_t b_size; uint8_t c_buf[256]; lfs_ssize_t c_size; struct lfs_attr attrs[] = { { .type = 'a', .flags = MODE | LFS_A_LAZY, .buffer = a_buf, .buffer_size = (MUTSIZE) ? sizeof(a_buf) : strlen(a_), .size = (MUTSIZE) ? &a_size : NULL, }, { .type = 'b', .flags = MODE | LFS_A_LAZY, .buffer = b_buf, .buffer_size = (MUTSIZE) ? sizeof(b_buf) : strlen(b_), .size = (MUTSIZE) ? &b_size : NULL, }, { .type = 'c', .flags = MODE | LFS_A_LAZY, .buffer = c_buf, .buffer_size = (MUTSIZE) ? sizeof(c_buf) : strlen(c_), .size = (MUTSIZE) ? &c_size : NULL, } }; struct lfs_file_config filecfg = { .attrs = attrs, .attr_count = 3, }; lfsr_file_opencfg(&lfs, &file, "cat", MODE, &filecfg) => 0; if (MODE == LFS_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 lfsr_file_sync(&lfs, &file) => 0; // try getting the attr sizes lfsr_sizeattr(&lfs, "cat", 'a') => strlen(a); lfsr_sizeattr(&lfs, "cat", 'b') => strlen(b); lfsr_sizeattr(&lfs, "cat", 'c') => strlen(c); // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a); assert(memcmp(rbuf, a, strlen(a)) == 0); lfsr_getattr(&lfs, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b); assert(memcmp(rbuf, b, strlen(b)) == 0); lfsr_getattr(&lfs, "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 lfsr_file_write(&lfs, &file, "miao", strlen("miao")) => strlen("miao"); lfsr_file_close(&lfs, &file) => 0; for (int remount = 0; remount < 2; remount++) { // remount? if (remount) { lfsr_unmount(&lfs) => 0; lfsr_mount(&lfs, LFS_M_RDWR, CFG) => 0; } // try getting the attr sizes lfsr_sizeattr(&lfs, "cat", 'a') => strlen(a_); lfsr_sizeattr(&lfs, "cat", 'b') => strlen(b_); lfsr_sizeattr(&lfs, "cat", 'c') => strlen(c_); // try reading the attrs uint8_t rbuf[256]; lfsr_getattr(&lfs, "cat", 'a', rbuf, sizeof(rbuf)) => strlen(a_); assert(memcmp(rbuf, a_, strlen(a_)) == 0); lfsr_getattr(&lfs, "cat", 'b', rbuf, sizeof(rbuf)) => strlen(b_); assert(memcmp(rbuf, b_, strlen(b_)) == 0); lfsr_getattr(&lfs, "cat", 'c', rbuf, sizeof(rbuf)) => strlen(c_); assert(memcmp(rbuf, c_, strlen(c_)) == 0); } lfsr_unmount(&lfs) => 0; ''' # TODO #[cases.test_attrs_fattr_all] #[cases.test_attrs_fattr_many] #[cases.test_attrs_fattr_many_many] #[cases.test_attrs_fattr_fuzz] #[cases.test_attrs_fattr_fuzz_fuzz] #[cases.test_attrs_fattr_broadcast] #[cases.test_attrs_fattr_remove_broadcast] #[cases.test_attrs_fattr_setattr_broadcast] #[cases.test_attrs_fattr_removeattr_broadcast] #[cases.test_attrs_fattr_wronly_broadcast] #[cases.test_attrs_fattr_rdonly_broadcast] #[cases.test_attrs_fattr_desync_broadcast] #[cases.test_attrs_fattr_resync] #[cases.test_attrs_fattr_zombie_resync] TODO do we test file zombie resync? #[cases.test_attrs_fattr_pl] ? #[cases.test_attrs_fattr_orphan] ? #[cases.test_attrs_get_set] #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # lfs_mkdir(&lfs, "hello") => 0; # lfs_file_t file; # lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; # lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); # lfs_file_close(&lfs, &file); # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # uint8_t buffer[1024]; # memset(buffer, 0, sizeof(buffer)); # lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0; # lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; # lfs_setattr(&lfs, "hello", 'C', "ccccc", 5) => 0; # lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6; # lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "bbbbbb", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # lfs_setattr(&lfs, "hello", 'B', "", 0) => 0; # lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 0; # lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # lfs_removeattr(&lfs, "hello", 'B') => 0; # lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => LFS_ERR_NOATTR; # lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; # lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 6; # lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "dddddd", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0; # lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 3; # lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "eee\0\0\0", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; # lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0; # lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "hello", 'B', buffer+4, 6) => 9; # lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; # # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # memset(buffer, 0, sizeof(buffer)); # lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9; # lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "fffffffff", 9) => 0; # memcmp(buffer+13, "ccccc", 5) => 0; # # lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; # lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); # memcmp(buffer, "hello", strlen("hello")) => 0; # lfs_file_close(&lfs, &file); # lfs_unmount(&lfs) => 0; #''' # #[cases.test_attrs_get_set_root] #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # lfs_mkdir(&lfs, "hello") => 0; # lfs_file_t file; # lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; # lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); # lfs_file_close(&lfs, &file); # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # uint8_t buffer[1024]; # memset(buffer, 0, sizeof(buffer)); # lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0; # lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; # lfs_setattr(&lfs, "/", 'C', "ccccc", 5) => 0; # lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; # lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "bbbbbb", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # lfs_setattr(&lfs, "/", 'B', "", 0) => 0; # lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 0; # lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # lfs_removeattr(&lfs, "/", 'B') => 0; # lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => LFS_ERR_NOATTR; # lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; # lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 6; # lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "dddddd", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0; # lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 3; # lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "eee\0\0\0", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; # lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0; # lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "/", 'B', buffer+4, 6) => 9; # lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # memset(buffer, 0, sizeof(buffer)); # lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; # lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9; # lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "fffffffff", 9) => 0; # memcmp(buffer+13, "ccccc", 5) => 0; # # lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; # lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); # memcmp(buffer, "hello", strlen("hello")) => 0; # lfs_file_close(&lfs, &file); # lfs_unmount(&lfs) => 0; #''' # #[cases.test_attrs_get_set_file] #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # lfs_mkdir(&lfs, "hello") => 0; # lfs_file_t file; # lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; # lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); # lfs_file_close(&lfs, &file); # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # uint8_t buffer[1024]; # memset(buffer, 0, sizeof(buffer)); # struct lfs_attr attrs1[] = { # {'A', buffer, 4}, # {'B', buffer+4, 6}, # {'C', buffer+10, 5}, # }; # struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; # # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; # memcpy(buffer, "aaaa", 4); # memcpy(buffer+4, "bbbbbb", 6); # memcpy(buffer+10, "ccccc", 5); # lfs_file_close(&lfs, &file) => 0; # memset(buffer, 0, 15); # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; # lfs_file_close(&lfs, &file) => 0; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "bbbbbb", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # attrs1[1].size = 0; # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; # lfs_file_close(&lfs, &file) => 0; # memset(buffer, 0, 15); # attrs1[1].size = 6; # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; # lfs_file_close(&lfs, &file) => 0; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "\0\0\0\0\0\0", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # attrs1[1].size = 6; # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; # memcpy(buffer+4, "dddddd", 6); # lfs_file_close(&lfs, &file) => 0; # memset(buffer, 0, 15); # attrs1[1].size = 6; # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; # lfs_file_close(&lfs, &file) => 0; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "dddddd", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # attrs1[1].size = 3; # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; # memcpy(buffer+4, "eee", 3); # lfs_file_close(&lfs, &file) => 0; # memset(buffer, 0, 15); # attrs1[1].size = 6; # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; # lfs_file_close(&lfs, &file) => 0; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "eee\0\0\0", 6) => 0; # memcmp(buffer+10, "ccccc", 5) => 0; # # attrs1[0].size = LFS_ATTR_MAX+1; # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) # => LFS_ERR_NOSPC; # # struct lfs_attr attrs2[] = { # {'A', buffer, 4}, # {'B', buffer+4, 9}, # {'C', buffer+13, 5}, # }; # struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0; # memcpy(buffer+4, "fffffffff", 9); # lfs_file_close(&lfs, &file) => 0; # attrs1[0].size = 4; # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; # lfs_file_close(&lfs, &file) => 0; # # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # memset(buffer, 0, sizeof(buffer)); # struct lfs_attr attrs3[] = { # {'A', buffer, 4}, # {'B', buffer+4, 9}, # {'C', buffer+13, 5}, # }; # struct lfs_file_config cfg3 = {.attrs=attrs3, .attr_count=3}; # # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg3) => 0; # lfs_file_close(&lfs, &file) => 0; # memcmp(buffer, "aaaa", 4) => 0; # memcmp(buffer+4, "fffffffff", 9) => 0; # memcmp(buffer+13, "ccccc", 5) => 0; # # lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; # lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); # memcmp(buffer, "hello", strlen("hello")) => 0; # lfs_file_close(&lfs, &file); # lfs_unmount(&lfs) => 0; #''' # #[cases.test_attrs_deferred_file] #code = ''' # lfs_t lfs; # lfs_format(&lfs, cfg) => 0; # lfs_mount(&lfs, cfg) => 0; # lfs_mkdir(&lfs, "hello") => 0; # lfs_file_t file; # lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; # lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); # lfs_file_close(&lfs, &file); # lfs_unmount(&lfs) => 0; # # lfs_mount(&lfs, cfg) => 0; # lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff", 9) => 0; # lfs_setattr(&lfs, "hello/hello", 'C', "ccccc", 5) => 0; # # uint8_t buffer[1024]; # memset(buffer, 0, sizeof(buffer)); # struct lfs_attr attrs1[] = { # {'B', "gggg", 4}, # {'C', "", 0}, # {'D', "hhhh", 4}, # }; # struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; # # lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; # # lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 9; # lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 5; # lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; # memcmp(buffer, "fffffffff", 9) => 0; # memcmp(buffer+9, "ccccc\0\0\0\0", 9) => 0; # memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; # # lfs_file_sync(&lfs, &file) => 0; # lfs_getattr(&lfs, "hello/hello", 'B', buffer, 9) => 4; # lfs_getattr(&lfs, "hello/hello", 'C', buffer+9, 9) => 0; # lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4; # memcmp(buffer, "gggg\0\0\0\0\0", 9) => 0; # memcmp(buffer+9, "\0\0\0\0\0\0\0\0\0", 9) => 0; # memcmp(buffer+18, "hhhh\0\0\0\0\0", 9) => 0; # # lfs_file_close(&lfs, &file) => 0; # lfs_unmount(&lfs) => 0; #'''