test_compat.toml 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360
  1. # Test for compatibility between different littlefs versions
  2. #
  3. # Note, these tests are a bit special. They expect to be linked against two
  4. # different versions of littlefs:
  5. # - lfs => the new/current version of littlefs
  6. # - lfsp => the previous version of littlefs
  7. #
  8. # If lfsp is not linked, and LFSP is not defined, these tests will alias
  9. # the relevant lfs types/functions as necessary so at least the tests can
  10. # themselves be tested locally.
  11. #
  12. # But to get value from these tests, it's expected that the previous version
  13. # of littlefs be linked in during CI, with the help of scripts/changeprefix.py
  14. #
  15. # alias littlefs symbols as needed
  16. #
  17. # there may be a better way to do this, but oh well, explicit aliases works
  18. code = '''
  19. #ifdef LFSP
  20. #define STRINGIZE(x) STRINGIZE_(x)
  21. #define STRINGIZE_(x) #x
  22. #include STRINGIZE(LFSP)
  23. #else
  24. #define LFSP_VERSION LFS_VERSION
  25. #define LFSP_VERSION_MAJOR LFS_VERSION_MAJOR
  26. #define LFSP_VERSION_MINOR LFS_VERSION_MINOR
  27. #define lfsp_t lfs_t
  28. #define lfsp_config lfs_config
  29. #define lfsp_format lfs_format
  30. #define lfsp_mount lfs_mount
  31. #define lfsp_unmount lfs_unmount
  32. #define lfsp_dir_t lfs_dir_t
  33. #define lfsp_info lfs_info
  34. #define LFSP_TYPE_REG LFS_TYPE_REG
  35. #define LFSP_TYPE_DIR LFS_TYPE_DIR
  36. #define lfsp_mkdir lfs_mkdir
  37. #define lfsp_dir_open lfs_dir_open
  38. #define lfsp_dir_read lfs_dir_read
  39. #define lfsp_dir_close lfs_dir_close
  40. #define lfsp_file_t lfs_file_t
  41. #define LFSP_O_RDONLY LFS_O_RDONLY
  42. #define LFSP_O_WRONLY LFS_O_WRONLY
  43. #define LFSP_O_CREAT LFS_O_CREAT
  44. #define LFSP_O_EXCL LFS_O_EXCL
  45. #define LFSP_SEEK_SET LFS_SEEK_SET
  46. #define lfsp_file_open lfs_file_open
  47. #define lfsp_file_write lfs_file_write
  48. #define lfsp_file_read lfs_file_read
  49. #define lfsp_file_seek lfs_file_seek
  50. #define lfsp_file_close lfs_file_close
  51. #endif
  52. '''
  53. ## forward-compatibility tests ##
  54. # test we can mount in a new version
  55. [cases.test_compat_forward_mount]
  56. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  57. code = '''
  58. // create the previous version
  59. struct lfsp_config cfgp;
  60. memcpy(&cfgp, cfg, sizeof(cfgp));
  61. lfsp_t lfsp;
  62. lfsp_format(&lfsp, &cfgp) => 0;
  63. // confirm the previous mount works
  64. lfsp_mount(&lfsp, &cfgp) => 0;
  65. lfsp_unmount(&lfsp) => 0;
  66. // now test the new mount
  67. lfs_t lfs;
  68. lfs_mount(&lfs, cfg) => 0;
  69. lfs_unmount(&lfs) => 0;
  70. '''
  71. # test we can read dirs in a new version
  72. [cases.test_compat_forward_read_dirs]
  73. defines.COUNT = 5
  74. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  75. code = '''
  76. // create the previous version
  77. struct lfsp_config cfgp;
  78. memcpy(&cfgp, cfg, sizeof(cfgp));
  79. lfsp_t lfsp;
  80. lfsp_format(&lfsp, &cfgp) => 0;
  81. // write COUNT dirs
  82. lfsp_mount(&lfsp, &cfgp) => 0;
  83. for (lfs_size_t i = 0; i < COUNT; i++) {
  84. char name[8];
  85. sprintf(name, "dir%03d", i);
  86. lfsp_mkdir(&lfsp, name) => 0;
  87. }
  88. lfsp_unmount(&lfsp) => 0;
  89. // mount the new version
  90. lfs_t lfs;
  91. lfs_mount(&lfs, cfg) => 0;
  92. // can we list the directories?
  93. lfs_dir_t dir;
  94. lfs_dir_open(&lfs, &dir, "/") => 0;
  95. struct lfs_info info;
  96. lfs_dir_read(&lfs, &dir, &info) => 1;
  97. assert(info.type == LFS_TYPE_DIR);
  98. assert(strcmp(info.name, ".") == 0);
  99. lfs_dir_read(&lfs, &dir, &info) => 1;
  100. assert(info.type == LFS_TYPE_DIR);
  101. assert(strcmp(info.name, "..") == 0);
  102. for (lfs_size_t i = 0; i < COUNT; i++) {
  103. lfs_dir_read(&lfs, &dir, &info) => 1;
  104. assert(info.type == LFS_TYPE_DIR);
  105. char name[8];
  106. sprintf(name, "dir%03d", i);
  107. assert(strcmp(info.name, name) == 0);
  108. }
  109. lfs_dir_read(&lfs, &dir, &info) => 0;
  110. lfs_dir_close(&lfs, &dir) => 0;
  111. lfs_unmount(&lfs) => 0;
  112. '''
  113. # test we can read files in a new version
  114. [cases.test_compat_forward_read_files]
  115. defines.COUNT = 5
  116. defines.SIZE = [4, 32, 512, 8192]
  117. defines.CHUNK = 4
  118. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  119. code = '''
  120. // create the previous version
  121. struct lfsp_config cfgp;
  122. memcpy(&cfgp, cfg, sizeof(cfgp));
  123. lfsp_t lfsp;
  124. lfsp_format(&lfsp, &cfgp) => 0;
  125. // write COUNT files
  126. lfsp_mount(&lfsp, &cfgp) => 0;
  127. uint32_t prng = 42;
  128. for (lfs_size_t i = 0; i < COUNT; i++) {
  129. lfsp_file_t file;
  130. char name[8];
  131. sprintf(name, "file%03d", i);
  132. lfsp_file_open(&lfsp, &file, name,
  133. LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0;
  134. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  135. uint8_t chunk[CHUNK];
  136. for (lfs_size_t k = 0; k < CHUNK; k++) {
  137. chunk[k] = TEST_PRNG(&prng) & 0xff;
  138. }
  139. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  140. }
  141. lfsp_file_close(&lfsp, &file) => 0;
  142. }
  143. lfsp_unmount(&lfsp) => 0;
  144. // mount the new version
  145. lfs_t lfs;
  146. lfs_mount(&lfs, cfg) => 0;
  147. // can we list the files?
  148. lfs_dir_t dir;
  149. lfs_dir_open(&lfs, &dir, "/") => 0;
  150. struct lfs_info info;
  151. lfs_dir_read(&lfs, &dir, &info) => 1;
  152. assert(info.type == LFS_TYPE_DIR);
  153. assert(strcmp(info.name, ".") == 0);
  154. lfs_dir_read(&lfs, &dir, &info) => 1;
  155. assert(info.type == LFS_TYPE_DIR);
  156. assert(strcmp(info.name, "..") == 0);
  157. for (lfs_size_t i = 0; i < COUNT; i++) {
  158. lfs_dir_read(&lfs, &dir, &info) => 1;
  159. assert(info.type == LFS_TYPE_REG);
  160. char name[8];
  161. sprintf(name, "file%03d", i);
  162. assert(strcmp(info.name, name) == 0);
  163. assert(info.size == SIZE);
  164. }
  165. lfs_dir_read(&lfs, &dir, &info) => 0;
  166. // now can we read the files?
  167. prng = 42;
  168. for (lfs_size_t i = 0; i < COUNT; i++) {
  169. lfs_file_t file;
  170. char name[8];
  171. sprintf(name, "file%03d", i);
  172. lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
  173. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  174. uint8_t chunk[CHUNK];
  175. lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK;
  176. for (lfs_size_t k = 0; k < CHUNK; k++) {
  177. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  178. }
  179. }
  180. lfs_file_close(&lfs, &file) => 0;
  181. }
  182. lfs_unmount(&lfs) => 0;
  183. '''
  184. # test we can read files in dirs in a new version
  185. [cases.test_compat_forward_read_files_in_dirs]
  186. defines.COUNT = 5
  187. defines.SIZE = [4, 32, 512, 8192]
  188. defines.CHUNK = 4
  189. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  190. code = '''
  191. // create the previous version
  192. struct lfsp_config cfgp;
  193. memcpy(&cfgp, cfg, sizeof(cfgp));
  194. lfsp_t lfsp;
  195. lfsp_format(&lfsp, &cfgp) => 0;
  196. // write COUNT files+dirs
  197. lfsp_mount(&lfsp, &cfgp) => 0;
  198. uint32_t prng = 42;
  199. for (lfs_size_t i = 0; i < COUNT; i++) {
  200. char name[16];
  201. sprintf(name, "dir%03d", i);
  202. lfsp_mkdir(&lfsp, name) => 0;
  203. lfsp_file_t file;
  204. sprintf(name, "dir%03d/file%03d", i, i);
  205. lfsp_file_open(&lfsp, &file, name,
  206. LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0;
  207. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  208. uint8_t chunk[CHUNK];
  209. for (lfs_size_t k = 0; k < CHUNK; k++) {
  210. chunk[k] = TEST_PRNG(&prng) & 0xff;
  211. }
  212. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  213. }
  214. lfsp_file_close(&lfsp, &file) => 0;
  215. }
  216. lfsp_unmount(&lfsp) => 0;
  217. // mount the new version
  218. lfs_t lfs;
  219. lfs_mount(&lfs, cfg) => 0;
  220. // can we list the directories?
  221. lfs_dir_t dir;
  222. lfs_dir_open(&lfs, &dir, "/") => 0;
  223. struct lfs_info info;
  224. lfs_dir_read(&lfs, &dir, &info) => 1;
  225. assert(info.type == LFS_TYPE_DIR);
  226. assert(strcmp(info.name, ".") == 0);
  227. lfs_dir_read(&lfs, &dir, &info) => 1;
  228. assert(info.type == LFS_TYPE_DIR);
  229. assert(strcmp(info.name, "..") == 0);
  230. for (lfs_size_t i = 0; i < COUNT; i++) {
  231. lfs_dir_read(&lfs, &dir, &info) => 1;
  232. assert(info.type == LFS_TYPE_DIR);
  233. char name[8];
  234. sprintf(name, "dir%03d", i);
  235. assert(strcmp(info.name, name) == 0);
  236. }
  237. lfs_dir_read(&lfs, &dir, &info) => 0;
  238. lfs_dir_close(&lfs, &dir) => 0;
  239. // can we list the files?
  240. for (lfs_size_t i = 0; i < COUNT; i++) {
  241. char name[8];
  242. sprintf(name, "dir%03d", i);
  243. lfs_dir_t dir;
  244. lfs_dir_open(&lfs, &dir, name) => 0;
  245. struct lfs_info info;
  246. lfs_dir_read(&lfs, &dir, &info) => 1;
  247. assert(info.type == LFS_TYPE_DIR);
  248. assert(strcmp(info.name, ".") == 0);
  249. lfs_dir_read(&lfs, &dir, &info) => 1;
  250. assert(info.type == LFS_TYPE_DIR);
  251. assert(strcmp(info.name, "..") == 0);
  252. lfs_dir_read(&lfs, &dir, &info) => 1;
  253. assert(info.type == LFS_TYPE_REG);
  254. sprintf(name, "file%03d", i);
  255. assert(strcmp(info.name, name) == 0);
  256. assert(info.size == SIZE);
  257. lfs_dir_read(&lfs, &dir, &info) => 0;
  258. lfs_dir_close(&lfs, &dir) => 0;
  259. }
  260. // now can we read the files?
  261. prng = 42;
  262. for (lfs_size_t i = 0; i < COUNT; i++) {
  263. lfs_file_t file;
  264. char name[16];
  265. sprintf(name, "dir%03d/file%03d", i, i);
  266. lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
  267. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  268. uint8_t chunk[CHUNK];
  269. lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK;
  270. for (lfs_size_t k = 0; k < CHUNK; k++) {
  271. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  272. }
  273. }
  274. lfs_file_close(&lfs, &file) => 0;
  275. }
  276. lfs_unmount(&lfs) => 0;
  277. '''
  278. # test we can write dirs in a new version
  279. [cases.test_compat_forward_write_dirs]
  280. defines.COUNT = 10
  281. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  282. code = '''
  283. // create the previous version
  284. struct lfsp_config cfgp;
  285. memcpy(&cfgp, cfg, sizeof(cfgp));
  286. lfsp_t lfsp;
  287. lfsp_format(&lfsp, &cfgp) => 0;
  288. // write COUNT/2 dirs
  289. lfsp_mount(&lfsp, &cfgp) => 0;
  290. for (lfs_size_t i = 0; i < COUNT/2; i++) {
  291. char name[8];
  292. sprintf(name, "dir%03d", i);
  293. lfsp_mkdir(&lfsp, name) => 0;
  294. }
  295. lfsp_unmount(&lfsp) => 0;
  296. // mount the new version
  297. lfs_t lfs;
  298. lfs_mount(&lfs, cfg) => 0;
  299. // write another COUNT/2 dirs
  300. for (lfs_size_t i = COUNT/2; i < COUNT; i++) {
  301. char name[8];
  302. sprintf(name, "dir%03d", i);
  303. lfs_mkdir(&lfs, name) => 0;
  304. }
  305. // can we list the directories?
  306. lfs_dir_t dir;
  307. lfs_dir_open(&lfs, &dir, "/") => 0;
  308. struct lfs_info info;
  309. lfs_dir_read(&lfs, &dir, &info) => 1;
  310. assert(info.type == LFS_TYPE_DIR);
  311. assert(strcmp(info.name, ".") == 0);
  312. lfs_dir_read(&lfs, &dir, &info) => 1;
  313. assert(info.type == LFS_TYPE_DIR);
  314. assert(strcmp(info.name, "..") == 0);
  315. for (lfs_size_t i = 0; i < COUNT; i++) {
  316. lfs_dir_read(&lfs, &dir, &info) => 1;
  317. assert(info.type == LFS_TYPE_DIR);
  318. char name[8];
  319. sprintf(name, "dir%03d", i);
  320. assert(strcmp(info.name, name) == 0);
  321. }
  322. lfs_dir_read(&lfs, &dir, &info) => 0;
  323. lfs_dir_close(&lfs, &dir) => 0;
  324. lfs_unmount(&lfs) => 0;
  325. '''
  326. # test we can write files in a new version
  327. [cases.test_compat_forward_write_files]
  328. defines.COUNT = 5
  329. defines.SIZE = [4, 32, 512, 8192]
  330. defines.CHUNK = 2
  331. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  332. code = '''
  333. // create the previous version
  334. struct lfsp_config cfgp;
  335. memcpy(&cfgp, cfg, sizeof(cfgp));
  336. lfsp_t lfsp;
  337. lfsp_format(&lfsp, &cfgp) => 0;
  338. // write half COUNT files
  339. lfsp_mount(&lfsp, &cfgp) => 0;
  340. uint32_t prng = 42;
  341. for (lfs_size_t i = 0; i < COUNT; i++) {
  342. // write half
  343. lfsp_file_t file;
  344. char name[8];
  345. sprintf(name, "file%03d", i);
  346. lfsp_file_open(&lfsp, &file, name,
  347. LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0;
  348. for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) {
  349. uint8_t chunk[CHUNK];
  350. for (lfs_size_t k = 0; k < CHUNK; k++) {
  351. chunk[k] = TEST_PRNG(&prng) & 0xff;
  352. }
  353. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  354. }
  355. lfsp_file_close(&lfsp, &file) => 0;
  356. // skip the other half but keep our prng reproducible
  357. for (lfs_size_t j = SIZE/2; j < SIZE; j++) {
  358. TEST_PRNG(&prng);
  359. }
  360. }
  361. lfsp_unmount(&lfsp) => 0;
  362. // mount the new version
  363. lfs_t lfs;
  364. lfs_mount(&lfs, cfg) => 0;
  365. // write half COUNT files
  366. prng = 42;
  367. for (lfs_size_t i = 0; i < COUNT; i++) {
  368. // skip half but keep our prng reproducible
  369. for (lfs_size_t j = 0; j < SIZE/2; j++) {
  370. TEST_PRNG(&prng);
  371. }
  372. // write the other half
  373. lfs_file_t file;
  374. char name[8];
  375. sprintf(name, "file%03d", i);
  376. lfs_file_open(&lfs, &file, name, LFS_O_WRONLY) => 0;
  377. lfs_file_seek(&lfs, &file, SIZE/2, LFS_SEEK_SET) => SIZE/2;
  378. for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) {
  379. uint8_t chunk[CHUNK];
  380. for (lfs_size_t k = 0; k < CHUNK; k++) {
  381. chunk[k] = TEST_PRNG(&prng) & 0xff;
  382. }
  383. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  384. }
  385. lfs_file_close(&lfs, &file) => 0;
  386. }
  387. // can we list the files?
  388. lfs_dir_t dir;
  389. lfs_dir_open(&lfs, &dir, "/") => 0;
  390. struct lfs_info info;
  391. lfs_dir_read(&lfs, &dir, &info) => 1;
  392. assert(info.type == LFS_TYPE_DIR);
  393. assert(strcmp(info.name, ".") == 0);
  394. lfs_dir_read(&lfs, &dir, &info) => 1;
  395. assert(info.type == LFS_TYPE_DIR);
  396. assert(strcmp(info.name, "..") == 0);
  397. for (lfs_size_t i = 0; i < COUNT; i++) {
  398. lfs_dir_read(&lfs, &dir, &info) => 1;
  399. assert(info.type == LFS_TYPE_REG);
  400. char name[8];
  401. sprintf(name, "file%03d", i);
  402. assert(strcmp(info.name, name) == 0);
  403. assert(info.size == SIZE);
  404. }
  405. lfs_dir_read(&lfs, &dir, &info) => 0;
  406. // now can we read the files?
  407. prng = 42;
  408. for (lfs_size_t i = 0; i < COUNT; i++) {
  409. lfs_file_t file;
  410. char name[8];
  411. sprintf(name, "file%03d", i);
  412. lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
  413. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  414. uint8_t chunk[CHUNK];
  415. lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK;
  416. for (lfs_size_t k = 0; k < CHUNK; k++) {
  417. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  418. }
  419. }
  420. lfs_file_close(&lfs, &file) => 0;
  421. }
  422. lfs_unmount(&lfs) => 0;
  423. '''
  424. # test we can write files in dirs in a new version
  425. [cases.test_compat_forward_write_files_in_dirs]
  426. defines.COUNT = 5
  427. defines.SIZE = [4, 32, 512, 8192]
  428. defines.CHUNK = 2
  429. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  430. code = '''
  431. // create the previous version
  432. struct lfsp_config cfgp;
  433. memcpy(&cfgp, cfg, sizeof(cfgp));
  434. lfsp_t lfsp;
  435. lfsp_format(&lfsp, &cfgp) => 0;
  436. // write half COUNT files
  437. lfsp_mount(&lfsp, &cfgp) => 0;
  438. uint32_t prng = 42;
  439. for (lfs_size_t i = 0; i < COUNT; i++) {
  440. char name[16];
  441. sprintf(name, "dir%03d", i);
  442. lfsp_mkdir(&lfsp, name) => 0;
  443. // write half
  444. lfsp_file_t file;
  445. sprintf(name, "dir%03d/file%03d", i, i);
  446. lfsp_file_open(&lfsp, &file, name,
  447. LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0;
  448. for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) {
  449. uint8_t chunk[CHUNK];
  450. for (lfs_size_t k = 0; k < CHUNK; k++) {
  451. chunk[k] = TEST_PRNG(&prng) & 0xff;
  452. }
  453. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  454. }
  455. lfsp_file_close(&lfsp, &file) => 0;
  456. // skip the other half but keep our prng reproducible
  457. for (lfs_size_t j = SIZE/2; j < SIZE; j++) {
  458. TEST_PRNG(&prng);
  459. }
  460. }
  461. lfsp_unmount(&lfsp) => 0;
  462. // mount the new version
  463. lfs_t lfs;
  464. lfs_mount(&lfs, cfg) => 0;
  465. // write half COUNT files
  466. prng = 42;
  467. for (lfs_size_t i = 0; i < COUNT; i++) {
  468. // skip half but keep our prng reproducible
  469. for (lfs_size_t j = 0; j < SIZE/2; j++) {
  470. TEST_PRNG(&prng);
  471. }
  472. // write the other half
  473. lfs_file_t file;
  474. char name[16];
  475. sprintf(name, "dir%03d/file%03d", i, i);
  476. lfs_file_open(&lfs, &file, name, LFS_O_WRONLY) => 0;
  477. lfs_file_seek(&lfs, &file, SIZE/2, LFS_SEEK_SET) => SIZE/2;
  478. for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) {
  479. uint8_t chunk[CHUNK];
  480. for (lfs_size_t k = 0; k < CHUNK; k++) {
  481. chunk[k] = TEST_PRNG(&prng) & 0xff;
  482. }
  483. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  484. }
  485. lfs_file_close(&lfs, &file) => 0;
  486. }
  487. // can we list the directories?
  488. lfs_dir_t dir;
  489. lfs_dir_open(&lfs, &dir, "/") => 0;
  490. struct lfs_info info;
  491. lfs_dir_read(&lfs, &dir, &info) => 1;
  492. assert(info.type == LFS_TYPE_DIR);
  493. assert(strcmp(info.name, ".") == 0);
  494. lfs_dir_read(&lfs, &dir, &info) => 1;
  495. assert(info.type == LFS_TYPE_DIR);
  496. assert(strcmp(info.name, "..") == 0);
  497. for (lfs_size_t i = 0; i < COUNT; i++) {
  498. lfs_dir_read(&lfs, &dir, &info) => 1;
  499. assert(info.type == LFS_TYPE_DIR);
  500. char name[8];
  501. sprintf(name, "dir%03d", i);
  502. assert(strcmp(info.name, name) == 0);
  503. }
  504. lfs_dir_read(&lfs, &dir, &info) => 0;
  505. lfs_dir_close(&lfs, &dir) => 0;
  506. // can we list the files?
  507. for (lfs_size_t i = 0; i < COUNT; i++) {
  508. char name[8];
  509. sprintf(name, "dir%03d", i);
  510. lfs_dir_t dir;
  511. lfs_dir_open(&lfs, &dir, name) => 0;
  512. struct lfs_info info;
  513. lfs_dir_read(&lfs, &dir, &info) => 1;
  514. assert(info.type == LFS_TYPE_DIR);
  515. assert(strcmp(info.name, ".") == 0);
  516. lfs_dir_read(&lfs, &dir, &info) => 1;
  517. assert(info.type == LFS_TYPE_DIR);
  518. assert(strcmp(info.name, "..") == 0);
  519. lfs_dir_read(&lfs, &dir, &info) => 1;
  520. assert(info.type == LFS_TYPE_REG);
  521. sprintf(name, "file%03d", i);
  522. assert(strcmp(info.name, name) == 0);
  523. assert(info.size == SIZE);
  524. lfs_dir_read(&lfs, &dir, &info) => 0;
  525. lfs_dir_close(&lfs, &dir) => 0;
  526. }
  527. // now can we read the files?
  528. prng = 42;
  529. for (lfs_size_t i = 0; i < COUNT; i++) {
  530. lfs_file_t file;
  531. char name[16];
  532. sprintf(name, "dir%03d/file%03d", i, i);
  533. lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
  534. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  535. uint8_t chunk[CHUNK];
  536. lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK;
  537. for (lfs_size_t k = 0; k < CHUNK; k++) {
  538. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  539. }
  540. }
  541. lfs_file_close(&lfs, &file) => 0;
  542. }
  543. lfs_unmount(&lfs) => 0;
  544. '''
  545. ## backwards-compatibility tests ##
  546. # test we can mount in an old version
  547. [cases.test_compat_backward_mount]
  548. if = 'LFS_VERSION == LFSP_VERSION'
  549. code = '''
  550. // create the new version
  551. lfs_t lfs;
  552. lfs_format(&lfs, cfg) => 0;
  553. // confirm the new mount works
  554. lfs_mount(&lfs, cfg) => 0;
  555. lfs_unmount(&lfs) => 0;
  556. // now test the previous mount
  557. struct lfsp_config cfgp;
  558. memcpy(&cfgp, cfg, sizeof(cfgp));
  559. lfsp_t lfsp;
  560. lfsp_mount(&lfsp, &cfgp) => 0;
  561. lfsp_unmount(&lfsp) => 0;
  562. '''
  563. # test we can read dirs in an old version
  564. [cases.test_compat_backward_read_dirs]
  565. defines.COUNT = 5
  566. if = 'LFS_VERSION == LFSP_VERSION'
  567. code = '''
  568. // create the new version
  569. lfs_t lfs;
  570. lfs_format(&lfs, cfg) => 0;
  571. // write COUNT dirs
  572. lfs_mount(&lfs, cfg) => 0;
  573. for (lfs_size_t i = 0; i < COUNT; i++) {
  574. char name[8];
  575. sprintf(name, "dir%03d", i);
  576. lfs_mkdir(&lfs, name) => 0;
  577. }
  578. lfs_unmount(&lfs) => 0;
  579. // mount the new version
  580. struct lfsp_config cfgp;
  581. memcpy(&cfgp, cfg, sizeof(cfgp));
  582. lfsp_t lfsp;
  583. lfsp_mount(&lfsp, &cfgp) => 0;
  584. // can we list the directories?
  585. lfsp_dir_t dir;
  586. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  587. struct lfsp_info info;
  588. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  589. assert(info.type == LFSP_TYPE_DIR);
  590. assert(strcmp(info.name, ".") == 0);
  591. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  592. assert(info.type == LFSP_TYPE_DIR);
  593. assert(strcmp(info.name, "..") == 0);
  594. for (lfs_size_t i = 0; i < COUNT; i++) {
  595. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  596. assert(info.type == LFSP_TYPE_DIR);
  597. char name[8];
  598. sprintf(name, "dir%03d", i);
  599. assert(strcmp(info.name, name) == 0);
  600. }
  601. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  602. lfsp_dir_close(&lfsp, &dir) => 0;
  603. lfsp_unmount(&lfsp) => 0;
  604. '''
  605. # test we can read files in an old version
  606. [cases.test_compat_backward_read_files]
  607. defines.COUNT = 5
  608. defines.SIZE = [4, 32, 512, 8192]
  609. defines.CHUNK = 4
  610. if = 'LFS_VERSION == LFSP_VERSION'
  611. code = '''
  612. // create the new version
  613. lfs_t lfs;
  614. lfs_format(&lfs, cfg) => 0;
  615. // write COUNT files
  616. lfs_mount(&lfs, cfg) => 0;
  617. uint32_t prng = 42;
  618. for (lfs_size_t i = 0; i < COUNT; i++) {
  619. lfs_file_t file;
  620. char name[8];
  621. sprintf(name, "file%03d", i);
  622. lfs_file_open(&lfs, &file, name,
  623. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  624. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  625. uint8_t chunk[CHUNK];
  626. for (lfs_size_t k = 0; k < CHUNK; k++) {
  627. chunk[k] = TEST_PRNG(&prng) & 0xff;
  628. }
  629. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  630. }
  631. lfs_file_close(&lfs, &file) => 0;
  632. }
  633. lfs_unmount(&lfs) => 0;
  634. // mount the previous version
  635. struct lfsp_config cfgp;
  636. memcpy(&cfgp, cfg, sizeof(cfgp));
  637. lfsp_t lfsp;
  638. lfsp_mount(&lfsp, &cfgp) => 0;
  639. // can we list the files?
  640. lfsp_dir_t dir;
  641. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  642. struct lfsp_info info;
  643. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  644. assert(info.type == LFSP_TYPE_DIR);
  645. assert(strcmp(info.name, ".") == 0);
  646. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  647. assert(info.type == LFSP_TYPE_DIR);
  648. assert(strcmp(info.name, "..") == 0);
  649. for (lfs_size_t i = 0; i < COUNT; i++) {
  650. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  651. assert(info.type == LFSP_TYPE_REG);
  652. char name[8];
  653. sprintf(name, "file%03d", i);
  654. assert(strcmp(info.name, name) == 0);
  655. assert(info.size == SIZE);
  656. }
  657. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  658. // now can we read the files?
  659. prng = 42;
  660. for (lfs_size_t i = 0; i < COUNT; i++) {
  661. lfsp_file_t file;
  662. char name[8];
  663. sprintf(name, "file%03d", i);
  664. lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0;
  665. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  666. uint8_t chunk[CHUNK];
  667. lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK;
  668. for (lfs_size_t k = 0; k < CHUNK; k++) {
  669. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  670. }
  671. }
  672. lfsp_file_close(&lfsp, &file) => 0;
  673. }
  674. lfsp_unmount(&lfsp) => 0;
  675. '''
  676. # test we can read files in dirs in an old version
  677. [cases.test_compat_backward_read_files_in_dirs]
  678. defines.COUNT = 5
  679. defines.SIZE = [4, 32, 512, 8192]
  680. defines.CHUNK = 4
  681. if = 'LFS_VERSION == LFSP_VERSION'
  682. code = '''
  683. // create the new version
  684. lfs_t lfs;
  685. lfs_format(&lfs, cfg) => 0;
  686. // write COUNT files+dirs
  687. lfs_mount(&lfs, cfg) => 0;
  688. uint32_t prng = 42;
  689. for (lfs_size_t i = 0; i < COUNT; i++) {
  690. char name[16];
  691. sprintf(name, "dir%03d", i);
  692. lfs_mkdir(&lfs, name) => 0;
  693. lfs_file_t file;
  694. sprintf(name, "dir%03d/file%03d", i, i);
  695. lfs_file_open(&lfs, &file, name,
  696. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  697. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  698. uint8_t chunk[CHUNK];
  699. for (lfs_size_t k = 0; k < CHUNK; k++) {
  700. chunk[k] = TEST_PRNG(&prng) & 0xff;
  701. }
  702. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  703. }
  704. lfs_file_close(&lfs, &file) => 0;
  705. }
  706. lfs_unmount(&lfs) => 0;
  707. // mount the previous version
  708. struct lfsp_config cfgp;
  709. memcpy(&cfgp, cfg, sizeof(cfgp));
  710. lfsp_t lfsp;
  711. lfsp_mount(&lfsp, &cfgp) => 0;
  712. // can we list the directories?
  713. lfsp_dir_t dir;
  714. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  715. struct lfsp_info info;
  716. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  717. assert(info.type == LFSP_TYPE_DIR);
  718. assert(strcmp(info.name, ".") == 0);
  719. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  720. assert(info.type == LFSP_TYPE_DIR);
  721. assert(strcmp(info.name, "..") == 0);
  722. for (lfs_size_t i = 0; i < COUNT; i++) {
  723. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  724. assert(info.type == LFSP_TYPE_DIR);
  725. char name[8];
  726. sprintf(name, "dir%03d", i);
  727. assert(strcmp(info.name, name) == 0);
  728. }
  729. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  730. lfsp_dir_close(&lfsp, &dir) => 0;
  731. // can we list the files?
  732. for (lfs_size_t i = 0; i < COUNT; i++) {
  733. char name[8];
  734. sprintf(name, "dir%03d", i);
  735. lfsp_dir_t dir;
  736. lfsp_dir_open(&lfsp, &dir, name) => 0;
  737. struct lfsp_info info;
  738. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  739. assert(info.type == LFSP_TYPE_DIR);
  740. assert(strcmp(info.name, ".") == 0);
  741. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  742. assert(info.type == LFSP_TYPE_DIR);
  743. assert(strcmp(info.name, "..") == 0);
  744. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  745. assert(info.type == LFSP_TYPE_REG);
  746. sprintf(name, "file%03d", i);
  747. assert(strcmp(info.name, name) == 0);
  748. assert(info.size == SIZE);
  749. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  750. lfsp_dir_close(&lfsp, &dir) => 0;
  751. }
  752. // now can we read the files?
  753. prng = 42;
  754. for (lfs_size_t i = 0; i < COUNT; i++) {
  755. lfsp_file_t file;
  756. char name[16];
  757. sprintf(name, "dir%03d/file%03d", i, i);
  758. lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0;
  759. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  760. uint8_t chunk[CHUNK];
  761. lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK;
  762. for (lfs_size_t k = 0; k < CHUNK; k++) {
  763. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  764. }
  765. }
  766. lfsp_file_close(&lfsp, &file) => 0;
  767. }
  768. lfsp_unmount(&lfsp) => 0;
  769. '''
  770. # test we can write dirs in an old version
  771. [cases.test_compat_backward_write_dirs]
  772. defines.COUNT = 10
  773. if = 'LFS_VERSION == LFSP_VERSION'
  774. code = '''
  775. // create the new version
  776. lfs_t lfs;
  777. lfs_format(&lfs, cfg) => 0;
  778. // write COUNT/2 dirs
  779. lfs_mount(&lfs, cfg) => 0;
  780. for (lfs_size_t i = 0; i < COUNT/2; i++) {
  781. char name[8];
  782. sprintf(name, "dir%03d", i);
  783. lfs_mkdir(&lfs, name) => 0;
  784. }
  785. lfs_unmount(&lfs) => 0;
  786. // mount the previous version
  787. struct lfsp_config cfgp;
  788. memcpy(&cfgp, cfg, sizeof(cfgp));
  789. lfsp_t lfsp;
  790. lfsp_mount(&lfsp, &cfgp) => 0;
  791. // write another COUNT/2 dirs
  792. for (lfs_size_t i = COUNT/2; i < COUNT; i++) {
  793. char name[8];
  794. sprintf(name, "dir%03d", i);
  795. lfsp_mkdir(&lfsp, name) => 0;
  796. }
  797. // can we list the directories?
  798. lfsp_dir_t dir;
  799. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  800. struct lfsp_info info;
  801. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  802. assert(info.type == LFSP_TYPE_DIR);
  803. assert(strcmp(info.name, ".") == 0);
  804. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  805. assert(info.type == LFSP_TYPE_DIR);
  806. assert(strcmp(info.name, "..") == 0);
  807. for (lfs_size_t i = 0; i < COUNT; i++) {
  808. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  809. assert(info.type == LFSP_TYPE_DIR);
  810. char name[8];
  811. sprintf(name, "dir%03d", i);
  812. assert(strcmp(info.name, name) == 0);
  813. }
  814. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  815. lfsp_dir_close(&lfsp, &dir) => 0;
  816. lfsp_unmount(&lfsp) => 0;
  817. '''
  818. # test we can write files in an old version
  819. [cases.test_compat_backward_write_files]
  820. defines.COUNT = 5
  821. defines.SIZE = [4, 32, 512, 8192]
  822. defines.CHUNK = 2
  823. if = 'LFS_VERSION == LFSP_VERSION'
  824. code = '''
  825. // create the previous version
  826. lfs_t lfs;
  827. lfs_format(&lfs, cfg) => 0;
  828. // write half COUNT files
  829. lfs_mount(&lfs, cfg) => 0;
  830. uint32_t prng = 42;
  831. for (lfs_size_t i = 0; i < COUNT; i++) {
  832. // write half
  833. lfs_file_t file;
  834. char name[8];
  835. sprintf(name, "file%03d", i);
  836. lfs_file_open(&lfs, &file, name,
  837. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  838. for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) {
  839. uint8_t chunk[CHUNK];
  840. for (lfs_size_t k = 0; k < CHUNK; k++) {
  841. chunk[k] = TEST_PRNG(&prng) & 0xff;
  842. }
  843. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  844. }
  845. lfs_file_close(&lfs, &file) => 0;
  846. // skip the other half but keep our prng reproducible
  847. for (lfs_size_t j = SIZE/2; j < SIZE; j++) {
  848. TEST_PRNG(&prng);
  849. }
  850. }
  851. lfs_unmount(&lfs) => 0;
  852. // mount the new version
  853. struct lfsp_config cfgp;
  854. memcpy(&cfgp, cfg, sizeof(cfgp));
  855. lfsp_t lfsp;
  856. lfsp_mount(&lfsp, &cfgp) => 0;
  857. // write half COUNT files
  858. prng = 42;
  859. for (lfs_size_t i = 0; i < COUNT; i++) {
  860. // skip half but keep our prng reproducible
  861. for (lfs_size_t j = 0; j < SIZE/2; j++) {
  862. TEST_PRNG(&prng);
  863. }
  864. // write the other half
  865. lfsp_file_t file;
  866. char name[8];
  867. sprintf(name, "file%03d", i);
  868. lfsp_file_open(&lfsp, &file, name, LFSP_O_WRONLY) => 0;
  869. lfsp_file_seek(&lfsp, &file, SIZE/2, LFSP_SEEK_SET) => SIZE/2;
  870. for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) {
  871. uint8_t chunk[CHUNK];
  872. for (lfs_size_t k = 0; k < CHUNK; k++) {
  873. chunk[k] = TEST_PRNG(&prng) & 0xff;
  874. }
  875. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  876. }
  877. lfsp_file_close(&lfsp, &file) => 0;
  878. }
  879. // can we list the files?
  880. lfsp_dir_t dir;
  881. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  882. struct lfsp_info info;
  883. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  884. assert(info.type == LFSP_TYPE_DIR);
  885. assert(strcmp(info.name, ".") == 0);
  886. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  887. assert(info.type == LFSP_TYPE_DIR);
  888. assert(strcmp(info.name, "..") == 0);
  889. for (lfs_size_t i = 0; i < COUNT; i++) {
  890. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  891. assert(info.type == LFSP_TYPE_REG);
  892. char name[8];
  893. sprintf(name, "file%03d", i);
  894. assert(strcmp(info.name, name) == 0);
  895. assert(info.size == SIZE);
  896. }
  897. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  898. // now can we read the files?
  899. prng = 42;
  900. for (lfs_size_t i = 0; i < COUNT; i++) {
  901. lfsp_file_t file;
  902. char name[8];
  903. sprintf(name, "file%03d", i);
  904. lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0;
  905. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  906. uint8_t chunk[CHUNK];
  907. lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK;
  908. for (lfs_size_t k = 0; k < CHUNK; k++) {
  909. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  910. }
  911. }
  912. lfsp_file_close(&lfsp, &file) => 0;
  913. }
  914. lfsp_unmount(&lfsp) => 0;
  915. '''
  916. # test we can write files in dirs in an old version
  917. [cases.test_compat_backward_write_files_in_dirs]
  918. defines.COUNT = 5
  919. defines.SIZE = [4, 32, 512, 8192]
  920. defines.CHUNK = 2
  921. if = 'LFS_VERSION == LFSP_VERSION'
  922. code = '''
  923. // create the previous version
  924. lfs_t lfs;
  925. lfs_format(&lfs, cfg) => 0;
  926. // write half COUNT files
  927. lfs_mount(&lfs, cfg) => 0;
  928. uint32_t prng = 42;
  929. for (lfs_size_t i = 0; i < COUNT; i++) {
  930. char name[16];
  931. sprintf(name, "dir%03d", i);
  932. lfs_mkdir(&lfs, name) => 0;
  933. // write half
  934. lfs_file_t file;
  935. sprintf(name, "dir%03d/file%03d", i, i);
  936. lfs_file_open(&lfs, &file, name,
  937. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  938. for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) {
  939. uint8_t chunk[CHUNK];
  940. for (lfs_size_t k = 0; k < CHUNK; k++) {
  941. chunk[k] = TEST_PRNG(&prng) & 0xff;
  942. }
  943. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  944. }
  945. lfs_file_close(&lfs, &file) => 0;
  946. // skip the other half but keep our prng reproducible
  947. for (lfs_size_t j = SIZE/2; j < SIZE; j++) {
  948. TEST_PRNG(&prng);
  949. }
  950. }
  951. lfs_unmount(&lfs) => 0;
  952. // mount the new version
  953. struct lfsp_config cfgp;
  954. memcpy(&cfgp, cfg, sizeof(cfgp));
  955. lfsp_t lfsp;
  956. lfsp_mount(&lfsp, &cfgp) => 0;
  957. // write half COUNT files
  958. prng = 42;
  959. for (lfs_size_t i = 0; i < COUNT; i++) {
  960. // skip half but keep our prng reproducible
  961. for (lfs_size_t j = 0; j < SIZE/2; j++) {
  962. TEST_PRNG(&prng);
  963. }
  964. // write the other half
  965. lfsp_file_t file;
  966. char name[16];
  967. sprintf(name, "dir%03d/file%03d", i, i);
  968. lfsp_file_open(&lfsp, &file, name, LFSP_O_WRONLY) => 0;
  969. lfsp_file_seek(&lfsp, &file, SIZE/2, LFSP_SEEK_SET) => SIZE/2;
  970. for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) {
  971. uint8_t chunk[CHUNK];
  972. for (lfs_size_t k = 0; k < CHUNK; k++) {
  973. chunk[k] = TEST_PRNG(&prng) & 0xff;
  974. }
  975. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  976. }
  977. lfsp_file_close(&lfsp, &file) => 0;
  978. }
  979. // can we list the directories?
  980. lfsp_dir_t dir;
  981. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  982. struct lfsp_info info;
  983. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  984. assert(info.type == LFSP_TYPE_DIR);
  985. assert(strcmp(info.name, ".") == 0);
  986. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  987. assert(info.type == LFSP_TYPE_DIR);
  988. assert(strcmp(info.name, "..") == 0);
  989. for (lfs_size_t i = 0; i < COUNT; i++) {
  990. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  991. assert(info.type == LFSP_TYPE_DIR);
  992. char name[8];
  993. sprintf(name, "dir%03d", i);
  994. assert(strcmp(info.name, name) == 0);
  995. }
  996. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  997. lfsp_dir_close(&lfsp, &dir) => 0;
  998. // can we list the files?
  999. for (lfs_size_t i = 0; i < COUNT; i++) {
  1000. char name[8];
  1001. sprintf(name, "dir%03d", i);
  1002. lfsp_dir_t dir;
  1003. lfsp_dir_open(&lfsp, &dir, name) => 0;
  1004. struct lfsp_info info;
  1005. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  1006. assert(info.type == LFSP_TYPE_DIR);
  1007. assert(strcmp(info.name, ".") == 0);
  1008. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  1009. assert(info.type == LFSP_TYPE_DIR);
  1010. assert(strcmp(info.name, "..") == 0);
  1011. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  1012. assert(info.type == LFSP_TYPE_REG);
  1013. sprintf(name, "file%03d", i);
  1014. assert(strcmp(info.name, name) == 0);
  1015. assert(info.size == SIZE);
  1016. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  1017. lfsp_dir_close(&lfsp, &dir) => 0;
  1018. }
  1019. // now can we read the files?
  1020. prng = 42;
  1021. for (lfs_size_t i = 0; i < COUNT; i++) {
  1022. lfsp_file_t file;
  1023. char name[16];
  1024. sprintf(name, "dir%03d/file%03d", i, i);
  1025. lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0;
  1026. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  1027. uint8_t chunk[CHUNK];
  1028. lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK;
  1029. for (lfs_size_t k = 0; k < CHUNK; k++) {
  1030. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  1031. }
  1032. }
  1033. lfsp_file_close(&lfsp, &file) => 0;
  1034. }
  1035. lfsp_unmount(&lfsp) => 0;
  1036. '''
  1037. ## incompatiblity tests ##
  1038. # test that we fail to mount after a major version bump
  1039. [cases.test_compat_major_incompat]
  1040. in = 'lfs.c'
  1041. code = '''
  1042. // create a superblock
  1043. lfs_t lfs;
  1044. lfs_format(&lfs, cfg) => 0;
  1045. // bump the major version
  1046. //
  1047. // note we're messing around with internals to do this! this
  1048. // is not a user API
  1049. lfs_mount(&lfs, cfg) => 0;
  1050. lfs_mdir_t mdir;
  1051. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  1052. lfs_superblock_t superblock = {
  1053. .version = LFS_DISK_VERSION + 0x00010000,
  1054. .block_size = lfs.cfg->block_size,
  1055. .block_count = lfs.cfg->block_count,
  1056. .name_max = lfs.name_max,
  1057. .file_max = lfs.file_max,
  1058. .attr_max = lfs.attr_max,
  1059. };
  1060. lfs_superblock_tole32(&superblock);
  1061. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  1062. {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
  1063. &superblock})) => 0;
  1064. lfs_unmount(&lfs) => 0;
  1065. // mount should now fail
  1066. lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
  1067. '''
  1068. # test that we fail to mount after a minor version bump
  1069. [cases.test_compat_minor_incompat]
  1070. in = 'lfs.c'
  1071. code = '''
  1072. // create a superblock
  1073. lfs_t lfs;
  1074. lfs_format(&lfs, cfg) => 0;
  1075. // bump the minor version
  1076. //
  1077. // note we're messing around with internals to do this! this
  1078. // is not a user API
  1079. lfs_mount(&lfs, cfg) => 0;
  1080. lfs_mdir_t mdir;
  1081. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  1082. lfs_superblock_t superblock = {
  1083. .version = LFS_DISK_VERSION + 0x00000001,
  1084. .block_size = lfs.cfg->block_size,
  1085. .block_count = lfs.cfg->block_count,
  1086. .name_max = lfs.name_max,
  1087. .file_max = lfs.file_max,
  1088. .attr_max = lfs.attr_max,
  1089. };
  1090. lfs_superblock_tole32(&superblock);
  1091. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  1092. {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
  1093. &superblock})) => 0;
  1094. lfs_unmount(&lfs) => 0;
  1095. // mount should now fail
  1096. lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
  1097. '''
  1098. # test that we correctly bump the minor version
  1099. [cases.test_compat_minor_bump]
  1100. in = 'lfs.c'
  1101. if = 'LFS_DISK_VERSION_MINOR > 0'
  1102. code = '''
  1103. // create a superblock
  1104. lfs_t lfs;
  1105. lfs_format(&lfs, cfg) => 0;
  1106. lfs_mount(&lfs, cfg) => 0;
  1107. lfs_file_t file;
  1108. lfs_file_open(&lfs, &file, "test",
  1109. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  1110. lfs_file_write(&lfs, &file, "testtest", 8) => 8;
  1111. lfs_file_close(&lfs, &file) => 0;
  1112. lfs_unmount(&lfs) => 0;
  1113. // write an old minor version
  1114. //
  1115. // note we're messing around with internals to do this! this
  1116. // is not a user API
  1117. lfs_mount(&lfs, cfg) => 0;
  1118. lfs_mdir_t mdir;
  1119. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  1120. lfs_superblock_t superblock = {
  1121. .version = LFS_DISK_VERSION - 0x00000001,
  1122. .block_size = lfs.cfg->block_size,
  1123. .block_count = lfs.cfg->block_count,
  1124. .name_max = lfs.name_max,
  1125. .file_max = lfs.file_max,
  1126. .attr_max = lfs.attr_max,
  1127. };
  1128. lfs_superblock_tole32(&superblock);
  1129. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  1130. {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
  1131. &superblock})) => 0;
  1132. lfs_unmount(&lfs) => 0;
  1133. // mount should still work
  1134. lfs_mount(&lfs, cfg) => 0;
  1135. lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
  1136. uint8_t buffer[8];
  1137. lfs_file_read(&lfs, &file, buffer, 8) => 8;
  1138. assert(memcmp(buffer, "testtest", 8) == 0);
  1139. lfs_file_close(&lfs, &file) => 0;
  1140. lfs_unmount(&lfs) => 0;
  1141. // if we write, we need to bump the minor version
  1142. lfs_mount(&lfs, cfg) => 0;
  1143. lfs_file_open(&lfs, &file, "test", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
  1144. lfs_file_write(&lfs, &file, "teeeeest", 8) => 8;
  1145. lfs_file_close(&lfs, &file) => 0;
  1146. // minor version should have changed
  1147. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  1148. lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x7ff, 0x3ff, 0),
  1149. LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
  1150. &superblock)
  1151. => LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock));
  1152. lfs_superblock_fromle32(&superblock);
  1153. assert((superblock.version >> 16) & 0xffff == LFS_DISK_VERSION_MAJOR);
  1154. assert((superblock.version >> 0) & 0xffff == LFS_DISK_VERSION_MINOR);
  1155. lfs_unmount(&lfs) => 0;
  1156. // and of course mount should still work
  1157. lfs_mount(&lfs, cfg) => 0;
  1158. lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0;
  1159. lfs_file_read(&lfs, &file, buffer, 8) => 8;
  1160. assert(memcmp(buffer, "teeeeest", 8) == 0);
  1161. lfs_file_close(&lfs, &file) => 0;
  1162. // minor version should have changed
  1163. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  1164. lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x7ff, 0x3ff, 0),
  1165. LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
  1166. &superblock)
  1167. => LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock));
  1168. lfs_superblock_fromle32(&superblock);
  1169. assert((superblock.version >> 16) & 0xffff == LFS_DISK_VERSION_MAJOR);
  1170. assert((superblock.version >> 0) & 0xffff == LFS_DISK_VERSION_MINOR);
  1171. lfs_unmount(&lfs) => 0;
  1172. '''