test_compat.toml 42 KB

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