test_compat.toml 43 KB

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