test_compat.toml 43 KB

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