lfs.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711
  1. /*
  2. * The little filesystem
  3. *
  4. * Copyright (c) 2017 Christopher Haster
  5. * Distributed under the MIT license
  6. */
  7. #include "lfs.h"
  8. #include "lfs_util.h"
  9. #include <string.h>
  10. #include <stdlib.h>
  11. /// Block device operations ///
  12. static int lfs_bd_flush(lfs_t *lfs) {
  13. if (lfs->pcache.off != -1) {
  14. int err = lfs->cfg->prog(lfs->cfg, lfs->pcache.block,
  15. lfs->pcache.off, lfs->cfg->prog_size,
  16. lfs->pcache.buffer);
  17. if (err) {
  18. return err;
  19. }
  20. lfs->pcache.off = -1;
  21. }
  22. return 0;
  23. }
  24. static int lfs_bd_read(lfs_t *lfs, lfs_block_t block,
  25. lfs_off_t off, lfs_size_t size, void *buffer) {
  26. uint8_t *data = buffer;
  27. // flush overlapping programs
  28. while (size > 0) {
  29. if (block == lfs->pcache.block && off >= lfs->pcache.off &&
  30. off < lfs->pcache.off + lfs->cfg->prog_size) {
  31. // is already in cache?
  32. lfs_size_t diff = lfs_min(size,
  33. lfs->cfg->prog_size - (off-lfs->pcache.off));
  34. memcpy(data, &lfs->pcache.buffer[off-lfs->pcache.off], diff);
  35. data += diff;
  36. off += diff;
  37. size -= diff;
  38. continue;
  39. } else if (block == lfs->rcache.block && off >= lfs->rcache.off &&
  40. off < lfs->rcache.off + lfs->cfg->read_size) {
  41. // is already in cache?
  42. lfs_size_t diff = lfs_min(size,
  43. lfs->cfg->read_size - (off-lfs->rcache.off));
  44. memcpy(data, &lfs->rcache.buffer[off-lfs->rcache.off], diff);
  45. data += diff;
  46. off += diff;
  47. size -= diff;
  48. continue;
  49. }
  50. // write out pending programs
  51. int err = lfs_bd_flush(lfs);
  52. if (err) {
  53. return err;
  54. }
  55. if (off % lfs->cfg->read_size == 0 &&
  56. size >= lfs->cfg->read_size) {
  57. // bypass cache?
  58. lfs_size_t diff = size - (size % lfs->cfg->read_size);
  59. int err = lfs->cfg->read(lfs->cfg, block, off, diff, data);
  60. if (err) {
  61. return err;
  62. }
  63. data += diff;
  64. off += diff;
  65. size -= diff;
  66. continue;
  67. }
  68. // load to cache, first condition can no longer fail
  69. lfs->rcache.block = block;
  70. lfs->rcache.off = off - (off % lfs->cfg->read_size);
  71. err = lfs->cfg->read(lfs->cfg, lfs->rcache.block,
  72. lfs->rcache.off, lfs->cfg->read_size,
  73. lfs->rcache.buffer);
  74. if (err) {
  75. return err;
  76. }
  77. }
  78. return 0;
  79. }
  80. static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block,
  81. lfs_off_t off, lfs_size_t size, const void *buffer) {
  82. const uint8_t *data = buffer;
  83. if (block == lfs->rcache.block) {
  84. // invalidate read cache
  85. lfs->rcache.off = -1;
  86. }
  87. while (size > 0) {
  88. if (block == lfs->pcache.block && off >= lfs->pcache.off &&
  89. off < lfs->pcache.off + lfs->cfg->prog_size) {
  90. // is already in cache?
  91. lfs_size_t diff = lfs_min(size,
  92. lfs->cfg->prog_size - (off-lfs->pcache.off));
  93. memcpy(&lfs->pcache.buffer[off-lfs->pcache.off], data, diff);
  94. data += diff;
  95. off += diff;
  96. size -= diff;
  97. continue;
  98. }
  99. // write out pending programs
  100. int err = lfs_bd_flush(lfs);
  101. if (err) {
  102. return err;
  103. }
  104. if (off % lfs->cfg->prog_size == 0 &&
  105. size >= lfs->cfg->prog_size) {
  106. // bypass cache?
  107. lfs_size_t diff = size - (size % lfs->cfg->prog_size);
  108. int err = lfs->cfg->prog(lfs->cfg, block, off, diff, data);
  109. if (err) {
  110. return err;
  111. }
  112. data += diff;
  113. off += diff;
  114. size -= diff;
  115. continue;
  116. }
  117. // prepare cache, first condition can no longer fail
  118. lfs->pcache.block = block;
  119. lfs->pcache.off = off - (off % lfs->cfg->prog_size);
  120. }
  121. return 0;
  122. }
  123. static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) {
  124. return lfs->cfg->erase(lfs->cfg, block);
  125. }
  126. static int lfs_bd_sync(lfs_t *lfs) {
  127. int err = lfs_bd_flush(lfs);
  128. if (err) {
  129. return err;
  130. }
  131. return lfs->cfg->sync(lfs->cfg);
  132. }
  133. static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block,
  134. lfs_off_t off, lfs_size_t size, const void *buffer) {
  135. const uint8_t *data = buffer;
  136. for (lfs_off_t i = 0; i < size; i++) {
  137. uint8_t c;
  138. int err = lfs_bd_read(lfs, block, off+i, 1, &c);
  139. if (err) {
  140. return err;
  141. }
  142. if (c != data[i]) {
  143. return false;
  144. }
  145. }
  146. return true;
  147. }
  148. /// Block allocator ///
  149. static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
  150. lfs_t *lfs = p;
  151. lfs_block_t off = (block - lfs->free.start) % lfs->cfg->block_count;
  152. if (off < lfs->cfg->lookahead) {
  153. lfs->free.lookahead[off / 32] |= 1U << (off % 32);
  154. }
  155. return 0;
  156. }
  157. static int lfs_alloc_scan(lfs_t *lfs, lfs_block_t *block) {
  158. lfs_block_t end = lfs->free.start + lfs->cfg->block_count;
  159. while (true) {
  160. while (lfs->free.off < lfs->cfg->lookahead) {
  161. lfs_block_t off = lfs->free.off;
  162. lfs->free.off += 1;
  163. if (!(lfs->free.lookahead[off / 32] & (1U << (off % 32)))) {
  164. // found a free block
  165. *block = (lfs->free.start + off) % lfs->cfg->block_count;
  166. return 0;
  167. }
  168. }
  169. // could not find block
  170. lfs->free.start += lfs->cfg->lookahead;
  171. lfs->free.off = 0;
  172. if (lfs_scmp(lfs->free.start, end) > 0) {
  173. return LFS_ERR_NOSPC;
  174. }
  175. // find mask of free blocks from tree
  176. memset(lfs->free.lookahead, 0, lfs->cfg->lookahead/8);
  177. int err = lfs_traverse(lfs, lfs_alloc_lookahead, lfs);
  178. if (err) {
  179. return err;
  180. }
  181. }
  182. }
  183. static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
  184. // try to scan for free block
  185. int err = lfs_alloc_scan(lfs, block);
  186. if (err != LFS_ERR_NOSPC) {
  187. return err;
  188. }
  189. // still can't allocate a block? check for orphans
  190. err = lfs_deorphan(lfs);
  191. if (err) {
  192. return err;
  193. }
  194. // scan again or die trying
  195. return lfs_alloc_scan(lfs, block);
  196. }
  197. /// Metadata pair and directory operations ///
  198. static inline void lfs_pairswap(lfs_block_t pair[2]) {
  199. lfs_block_t t = pair[0];
  200. pair[0] = pair[1];
  201. pair[1] = t;
  202. }
  203. static inline bool lfs_pairisnull(const lfs_block_t pair[2]) {
  204. return !pair[0] || !pair[1];
  205. }
  206. static inline int lfs_paircmp(
  207. const lfs_block_t paira[2],
  208. const lfs_block_t pairb[2]) {
  209. return !((paira[0] == pairb[0] && paira[1] == pairb[1]) ||
  210. (paira[0] == pairb[1] && paira[1] == pairb[0]));
  211. }
  212. static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir) {
  213. // Allocate pair of dir blocks
  214. for (int i = 0; i < 2; i++) {
  215. int err = lfs_alloc(lfs, &dir->pair[i]);
  216. if (err) {
  217. return err;
  218. }
  219. }
  220. // Rather than clobbering one of the blocks we just pretend
  221. // the revision may be valid
  222. int err = lfs_bd_read(lfs, dir->pair[0], 0, 4, &dir->d.rev);
  223. if (err) {
  224. return err;
  225. }
  226. // Set defaults
  227. dir->d.rev += 1;
  228. dir->d.size = sizeof(dir->d);
  229. dir->d.tail[0] = 0;
  230. dir->d.tail[1] = 0;
  231. dir->off = sizeof(dir->d);
  232. // Don't write out yet, let caller take care of that
  233. return 0;
  234. }
  235. static int lfs_dir_fetch(lfs_t *lfs,
  236. lfs_dir_t *dir, const lfs_block_t pair[2]) {
  237. // copy out pair, otherwise may be aliasing dir
  238. const lfs_block_t tpair[2] = {pair[0], pair[1]};
  239. bool valid = false;
  240. // check both blocks for the most recent revision
  241. for (int i = 0; i < 2; i++) {
  242. struct lfs_disk_dir test;
  243. int err = lfs_bd_read(lfs, tpair[i], 0, sizeof(test), &test);
  244. if (err) {
  245. return err;
  246. }
  247. if (valid && lfs_scmp(test.rev, dir->d.rev) < 0) {
  248. continue;
  249. }
  250. uint32_t crc = 0xffffffff;
  251. crc = lfs_crc(crc, sizeof(test), &test);
  252. for (lfs_off_t j = sizeof(test); j < lfs->cfg->block_size; j += 4) {
  253. uint32_t word;
  254. int err = lfs_bd_read(lfs, tpair[i], j, 4, &word);
  255. if (err) {
  256. return err;
  257. }
  258. crc = lfs_crc(crc, 4, &word);
  259. }
  260. if (crc != 0) {
  261. continue;
  262. }
  263. valid = true;
  264. // setup dir in case it's valid
  265. dir->pair[0] = tpair[(i+0) % 2];
  266. dir->pair[1] = tpair[(i+1) % 2];
  267. dir->off = sizeof(dir->d);
  268. dir->d = test;
  269. }
  270. if (!valid) {
  271. LFS_ERROR("Corrupted dir pair at %d %d", tpair[0], tpair[1]);
  272. return LFS_ERR_CORRUPT;
  273. }
  274. return 0;
  275. }
  276. static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
  277. const lfs_entry_t *entry, const void *data) {
  278. dir->d.rev += 1;
  279. lfs_pairswap(dir->pair);
  280. int err = lfs_bd_erase(lfs, dir->pair[0]);
  281. if (err) {
  282. return err;
  283. }
  284. uint32_t crc = 0xffffffff;
  285. crc = lfs_crc(crc, sizeof(dir->d), &dir->d);
  286. err = lfs_bd_prog(lfs, dir->pair[0], 0, sizeof(dir->d), &dir->d);
  287. if (err) {
  288. return err;
  289. }
  290. lfs_off_t off = sizeof(dir->d);
  291. lfs_size_t size = 0x7fffffff & dir->d.size;
  292. while (off < size) {
  293. if (entry && off == entry->off) {
  294. crc = lfs_crc(crc, sizeof(entry->d), &entry->d);
  295. int err = lfs_bd_prog(lfs, dir->pair[0],
  296. off, sizeof(entry->d), &entry->d);
  297. if (err) {
  298. return err;
  299. }
  300. off += sizeof(entry->d);
  301. if (data) {
  302. crc = lfs_crc(crc, entry->d.len - sizeof(entry->d), data);
  303. int err = lfs_bd_prog(lfs, dir->pair[0],
  304. off, entry->d.len - sizeof(entry->d), data);
  305. if (err) {
  306. return err;
  307. }
  308. off += entry->d.len - sizeof(entry->d);
  309. }
  310. } else {
  311. uint8_t data;
  312. int err = lfs_bd_read(lfs, dir->pair[1], off, 1, &data);
  313. if (err) {
  314. return err;
  315. }
  316. crc = lfs_crc(crc, 1, &data);
  317. err = lfs_bd_prog(lfs, dir->pair[0], off, 1, &data);
  318. if (err) {
  319. return err;
  320. }
  321. off += 1;
  322. }
  323. }
  324. while (off < lfs->cfg->block_size-4) {
  325. uint8_t data = 0xff;
  326. crc = lfs_crc(crc, 1, &data);
  327. err = lfs_bd_prog(lfs, dir->pair[0], off, 1, &data);
  328. if (err) {
  329. return err;
  330. }
  331. off += 1;
  332. }
  333. err = lfs_bd_prog(lfs, dir->pair[0], lfs->cfg->block_size-4, 4, &crc);
  334. if (err) {
  335. return err;
  336. }
  337. return lfs_bd_sync(lfs);
  338. }
  339. static int lfs_dir_shift(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
  340. dir->d.rev += 1;
  341. dir->d.size -= entry->d.len;
  342. lfs_pairswap(dir->pair);
  343. int err = lfs_bd_erase(lfs, dir->pair[0]);
  344. if (err) {
  345. return err;
  346. }
  347. uint32_t crc = 0xffffffff;
  348. crc = lfs_crc(crc, sizeof(dir->d), &dir->d);
  349. err = lfs_bd_prog(lfs, dir->pair[0], 0, sizeof(dir->d), &dir->d);
  350. if (err) {
  351. return err;
  352. }
  353. lfs_off_t woff = sizeof(dir->d);
  354. lfs_off_t roff = sizeof(dir->d);
  355. lfs_size_t size = 0x7fffffff & dir->d.size;
  356. while (woff < size) {
  357. if (roff == entry->off) {
  358. roff += entry->d.len;
  359. } else {
  360. uint8_t data;
  361. int err = lfs_bd_read(lfs, dir->pair[1], roff, 1, &data);
  362. if (err) {
  363. return err;
  364. }
  365. crc = lfs_crc(crc, 1, (void*)&data);
  366. err = lfs_bd_prog(lfs, dir->pair[0], woff, 1, &data);
  367. if (err) {
  368. return err;
  369. }
  370. woff += 1;
  371. roff += 1;
  372. }
  373. }
  374. while (woff < lfs->cfg->block_size-4) {
  375. uint8_t data = 0xff;
  376. crc = lfs_crc(crc, 1, &data);
  377. err = lfs_bd_prog(lfs, dir->pair[0], woff, 1, &data);
  378. if (err) {
  379. return err;
  380. }
  381. woff += 1;
  382. }
  383. err = lfs_bd_prog(lfs, dir->pair[0], lfs->cfg->block_size-4, 4, &crc);
  384. if (err) {
  385. return err;
  386. }
  387. return lfs_bd_sync(lfs);
  388. }
  389. static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
  390. lfs_entry_t *entry, const void *data) {
  391. // check if we fit, if top bit is set we do not and move on
  392. while (true) {
  393. if (dir->d.size + entry->d.len <= lfs->cfg->block_size - 4) {
  394. entry->off = dir->d.size;
  395. dir->d.size += entry->d.len;
  396. return lfs_dir_commit(lfs, dir, entry, data);
  397. }
  398. if (!(0x80000000 & dir->d.size)) {
  399. lfs_dir_t newdir;
  400. int err = lfs_dir_alloc(lfs, &newdir);
  401. if (err) {
  402. return err;
  403. }
  404. newdir.d.tail[0] = dir->d.tail[0];
  405. newdir.d.tail[1] = dir->d.tail[1];
  406. entry->off = newdir.d.size;
  407. newdir.d.size += entry->d.len;
  408. err = lfs_dir_commit(lfs, &newdir, entry, data);
  409. if (err) {
  410. return err;
  411. }
  412. dir->d.size |= 0x80000000;
  413. dir->d.tail[0] = newdir.pair[0];
  414. dir->d.tail[1] = newdir.pair[1];
  415. return lfs_dir_commit(lfs, dir, NULL, NULL);
  416. }
  417. int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
  418. if (err) {
  419. return err;
  420. }
  421. }
  422. }
  423. static int lfs_dir_remove(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
  424. // either shift out the one entry or remove the whole dir block
  425. if (dir->d.size == sizeof(dir->d)) {
  426. lfs_dir_t pdir;
  427. int err = lfs_dir_fetch(lfs, &pdir, lfs->root);
  428. if (err) {
  429. return err;
  430. }
  431. while (lfs_paircmp(pdir.d.tail, dir->pair) != 0) {
  432. int err = lfs_dir_fetch(lfs, &pdir, pdir.d.tail);
  433. if (err) {
  434. return err;
  435. }
  436. }
  437. if (!(pdir.d.size & 0x80000000)) {
  438. return lfs_dir_shift(lfs, dir, entry);
  439. } else {
  440. pdir.d.tail[0] = dir->d.tail[0];
  441. pdir.d.tail[1] = dir->d.tail[1];
  442. return lfs_dir_commit(lfs, &pdir, NULL, NULL);
  443. }
  444. } else {
  445. return lfs_dir_shift(lfs, dir, entry);
  446. }
  447. }
  448. static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
  449. while (true) {
  450. if (dir->off + sizeof(entry->d) > (0x7fffffff & dir->d.size)) {
  451. if (!(0x80000000 & dir->d.size)) {
  452. entry->off = dir->off;
  453. return LFS_ERR_NOENT;
  454. }
  455. int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
  456. if (err) {
  457. return err;
  458. }
  459. dir->off = sizeof(dir->d);
  460. dir->pos += sizeof(dir->d);
  461. continue;
  462. }
  463. int err = lfs_bd_read(lfs, dir->pair[0], dir->off,
  464. sizeof(entry->d), &entry->d);
  465. if (err) {
  466. return err;
  467. }
  468. dir->off += entry->d.len;
  469. dir->pos += entry->d.len;
  470. if ((0xff & entry->d.type) == LFS_TYPE_REG ||
  471. (0xff & entry->d.type) == LFS_TYPE_DIR) {
  472. entry->off = dir->off - entry->d.len;
  473. return 0;
  474. }
  475. }
  476. }
  477. static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
  478. lfs_entry_t *entry, const char **path) {
  479. const char *pathname = *path;
  480. size_t pathlen;
  481. while (true) {
  482. nextname:
  483. // skip slashes
  484. pathname += strspn(pathname, "/");
  485. pathlen = strcspn(pathname, "/");
  486. // skip '.' and root '..'
  487. if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) ||
  488. (pathlen == 2 && memcmp(pathname, "..", 2) == 0)) {
  489. pathname += pathlen;
  490. goto nextname;
  491. }
  492. // skip if matched by '..' in name
  493. const char *suffix = pathname + pathlen;
  494. size_t sufflen;
  495. int depth = 1;
  496. while (true) {
  497. suffix += strspn(suffix, "/");
  498. sufflen = strcspn(suffix, "/");
  499. if (sufflen == 0) {
  500. break;
  501. }
  502. if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) {
  503. depth -= 1;
  504. if (depth == 0) {
  505. pathname = suffix + sufflen;
  506. goto nextname;
  507. }
  508. } else {
  509. depth += 1;
  510. }
  511. suffix += sufflen;
  512. }
  513. // find path
  514. while (true) {
  515. int err = lfs_dir_next(lfs, dir, entry);
  516. if (err) {
  517. return err;
  518. }
  519. if (entry->d.len - sizeof(entry->d) != pathlen) {
  520. continue;
  521. }
  522. int ret = lfs_bd_cmp(lfs, dir->pair[0],
  523. entry->off + sizeof(entry->d), pathlen, pathname);
  524. if (ret < 0) {
  525. return ret;
  526. }
  527. // Found match
  528. if (ret == true) {
  529. break;
  530. }
  531. }
  532. pathname += pathlen;
  533. pathname += strspn(pathname, "/");
  534. if (pathname[0] == '\0') {
  535. return 0;
  536. }
  537. // continue on if we hit a directory
  538. if (entry->d.type != LFS_TYPE_DIR) {
  539. return LFS_ERR_NOTDIR;
  540. }
  541. int err = lfs_dir_fetch(lfs, dir, entry->d.u.dir);
  542. if (err) {
  543. return err;
  544. }
  545. *path = pathname;
  546. }
  547. return 0;
  548. }
  549. /// Top level directory operations ///
  550. int lfs_mkdir(lfs_t *lfs, const char *path) {
  551. // fetch parent directory
  552. lfs_dir_t cwd;
  553. int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
  554. if (err) {
  555. return err;
  556. }
  557. lfs_entry_t entry;
  558. err = lfs_dir_find(lfs, &cwd, &entry, &path);
  559. if (err != LFS_ERR_NOENT) {
  560. return err ? err : LFS_ERR_EXISTS;
  561. }
  562. // Build up new directory
  563. lfs_dir_t dir;
  564. err = lfs_dir_alloc(lfs, &dir);
  565. if (err) {
  566. return err;
  567. }
  568. dir.d.tail[0] = cwd.d.tail[0];
  569. dir.d.tail[1] = cwd.d.tail[1];
  570. err = lfs_dir_commit(lfs, &dir, NULL, NULL);
  571. if (err) {
  572. return err;
  573. }
  574. entry.d.type = LFS_TYPE_DIR;
  575. entry.d.len = sizeof(entry.d) + strlen(path);
  576. entry.d.u.dir[0] = dir.pair[0];
  577. entry.d.u.dir[1] = dir.pair[1];
  578. cwd.d.tail[0] = dir.pair[0];
  579. cwd.d.tail[1] = dir.pair[1];
  580. return lfs_dir_append(lfs, &cwd, &entry, path);
  581. }
  582. int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
  583. dir->pair[0] = lfs->root[0];
  584. dir->pair[1] = lfs->root[1];
  585. int err = lfs_dir_fetch(lfs, dir, dir->pair);
  586. if (err) {
  587. return err;
  588. }
  589. if (strspn(path, "/.") == strlen(path)) {
  590. // can only be something like '/././../.'
  591. dir->head[0] = dir->pair[0];
  592. dir->head[1] = dir->pair[1];
  593. dir->pos = sizeof(dir->d) - 2;
  594. dir->off = sizeof(dir->d);
  595. return 0;
  596. }
  597. lfs_entry_t entry;
  598. err = lfs_dir_find(lfs, dir, &entry, &path);
  599. if (err) {
  600. return err;
  601. } else if (entry.d.type != LFS_TYPE_DIR) {
  602. return LFS_ERR_NOTDIR;
  603. }
  604. err = lfs_dir_fetch(lfs, dir, entry.d.u.dir);
  605. if (err) {
  606. return err;
  607. }
  608. // setup head dir
  609. // special offset for '.' and '..'
  610. dir->head[0] = dir->pair[0];
  611. dir->head[1] = dir->pair[1];
  612. dir->pos = sizeof(dir->d) - 2;
  613. dir->off = sizeof(dir->d);
  614. return 0;
  615. }
  616. int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
  617. // Do nothing, dir is always synchronized
  618. return 0;
  619. }
  620. int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
  621. memset(info, 0, sizeof(*info));
  622. // special offset for '.' and '..'
  623. if (dir->pos == sizeof(dir->d) - 2) {
  624. info->type = LFS_TYPE_DIR;
  625. strcpy(info->name, ".");
  626. dir->pos += 1;
  627. return 1;
  628. } else if (dir->pos == sizeof(dir->d) - 1) {
  629. info->type = LFS_TYPE_DIR;
  630. strcpy(info->name, "..");
  631. dir->pos += 1;
  632. return 1;
  633. }
  634. lfs_entry_t entry;
  635. int err = lfs_dir_next(lfs, dir, &entry);
  636. if (err) {
  637. return (err == LFS_ERR_NOENT) ? 0 : err;
  638. }
  639. info->type = entry.d.type & 0xff;
  640. if (info->type == LFS_TYPE_REG) {
  641. info->size = entry.d.u.file.size;
  642. }
  643. err = lfs_bd_read(lfs, dir->pair[0], entry.off + sizeof(entry.d),
  644. entry.d.len - sizeof(entry.d), info->name);
  645. if (err) {
  646. return err;
  647. }
  648. return 1;
  649. }
  650. int lfs_dir_seek(lfs_t *lfs, lfs_dir_t *dir, lfs_off_t off) {
  651. // simply walk from head dir
  652. int err = lfs_dir_rewind(lfs, dir);
  653. if (err) {
  654. return err;
  655. }
  656. dir->pos = off;
  657. while (off > (0x7fffffff & dir->d.size)) {
  658. off -= 0x7fffffff & dir->d.size;
  659. if (!(0x80000000 & dir->d.size)) {
  660. return LFS_ERR_INVAL;
  661. }
  662. int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
  663. if (err) {
  664. return err;
  665. }
  666. }
  667. dir->off = off;
  668. return 0;
  669. }
  670. lfs_soff_t lfs_dir_tell(lfs_t *lfs, lfs_dir_t *dir) {
  671. return dir->pos;
  672. }
  673. int lfs_dir_rewind(lfs_t *lfs, lfs_dir_t *dir) {
  674. // reload the head dir
  675. int err = lfs_dir_fetch(lfs, dir, dir->head);
  676. if (err) {
  677. return err;
  678. }
  679. dir->pair[0] = dir->head[0];
  680. dir->pair[1] = dir->head[1];
  681. dir->pos = sizeof(dir->d) - 2;
  682. dir->off = sizeof(dir->d);
  683. return 0;
  684. }
  685. /// Index list operations ///
  686. static int lfs_index(lfs_t *lfs, lfs_off_t *off) {
  687. lfs_off_t i = 0;
  688. while (*off >= lfs->cfg->block_size) {
  689. i += 1;
  690. *off -= lfs->cfg->block_size;
  691. *off += 4*lfs_min(lfs_ctz(i)+1, lfs->words-1);
  692. }
  693. return i;
  694. }
  695. static int lfs_index_find(lfs_t *lfs, lfs_block_t head, lfs_size_t size,
  696. lfs_size_t pos, lfs_block_t *block, lfs_off_t *off) {
  697. if (size == 0) {
  698. *block = 0;
  699. *off = 0;
  700. return 0;
  701. }
  702. lfs_off_t current = lfs_index(lfs, &(lfs_off_t){size-1});
  703. lfs_off_t target = lfs_index(lfs, &pos);
  704. while (current > target) {
  705. lfs_size_t skip = lfs_min(
  706. lfs_npw2(current-target+1) - 1,
  707. lfs_min(lfs_ctz(current)+1, lfs->words-1) - 1);
  708. int err = lfs_bd_read(lfs, head, 4*skip, 4, &head);
  709. if (err) {
  710. return err;
  711. }
  712. current -= 1 << skip;
  713. }
  714. *block = head;
  715. *off = pos;
  716. return 0;
  717. }
  718. static int lfs_index_extend(lfs_t *lfs,
  719. lfs_block_t head, lfs_size_t size,
  720. lfs_off_t *block, lfs_block_t *off) {
  721. // go ahead and grab a block
  722. int err = lfs_alloc(lfs, block);
  723. if (err) {
  724. return err;
  725. }
  726. err = lfs_bd_erase(lfs, *block);
  727. if (err) {
  728. return err;
  729. }
  730. if (size == 0) {
  731. *off = 0;
  732. return 0;
  733. }
  734. size -= 1;
  735. lfs_off_t index = lfs_index(lfs, &size);
  736. size += 1;
  737. // just copy out the last block if it is incomplete
  738. if (size != lfs->cfg->block_size) {
  739. for (lfs_off_t i = 0; i < size; i++) {
  740. uint8_t data;
  741. int err = lfs_bd_read(lfs, head, i, 1, &data);
  742. if (err) {
  743. return err;
  744. }
  745. err = lfs_bd_prog(lfs, *block, i, 1, &data);
  746. if (err) {
  747. return err;
  748. }
  749. }
  750. *off = size;
  751. return 0;
  752. }
  753. // append block
  754. index += 1;
  755. lfs_size_t skips = lfs_min(lfs_ctz(index)+1, lfs->words-1);
  756. for (lfs_off_t i = 0; i < skips; i++) {
  757. int err = lfs_bd_prog(lfs, *block, 4*i, 4, &head);
  758. if (err) {
  759. return err;
  760. }
  761. if (i != skips-1) {
  762. err = lfs_bd_read(lfs, head, 4*i, 4, &head);
  763. if (err) {
  764. return err;
  765. }
  766. }
  767. }
  768. *off = 4*skips;
  769. return 0;
  770. }
  771. static int lfs_index_traverse(lfs_t *lfs,
  772. lfs_block_t head, lfs_size_t size,
  773. int (*cb)(void*, lfs_block_t), void *data) {
  774. if (size == 0) {
  775. return 0;
  776. }
  777. lfs_off_t index = lfs_index(lfs, &(lfs_off_t){size-1});
  778. while (true) {
  779. int err = cb(data, head);
  780. if (err) {
  781. return err;
  782. }
  783. if (index == 0) {
  784. return 0;
  785. }
  786. err = lfs_bd_read(lfs, head, 0, 4, &head);
  787. if (err) {
  788. return err;
  789. }
  790. index -= 1;
  791. }
  792. return 0;
  793. }
  794. /// Top level file operations ///
  795. int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
  796. const char *path, int flags) {
  797. // Allocate entry for file if it doesn't exist
  798. lfs_dir_t cwd;
  799. int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
  800. if (err) {
  801. return err;
  802. }
  803. lfs_entry_t entry;
  804. err = lfs_dir_find(lfs, &cwd, &entry, &path);
  805. if (err && err != LFS_ERR_NOENT) {
  806. return err;
  807. }
  808. if (err == LFS_ERR_NOENT) {
  809. if (!(flags & LFS_O_CREAT)) {
  810. return LFS_ERR_NOENT;
  811. }
  812. // create entry to remember name
  813. entry.d.type = LFS_TYPE_REG;
  814. entry.d.len = sizeof(entry.d) + strlen(path);
  815. entry.d.u.file.head = 0;
  816. entry.d.u.file.size = 0;
  817. err = lfs_dir_append(lfs, &cwd, &entry, path);
  818. if (err) {
  819. return err;
  820. }
  821. } else if (entry.d.type == LFS_TYPE_DIR) {
  822. return LFS_ERR_ISDIR;
  823. } else if (flags & LFS_O_EXCL) {
  824. return LFS_ERR_EXISTS;
  825. }
  826. // setup file struct
  827. file->pair[0] = cwd.pair[0];
  828. file->pair[1] = cwd.pair[1];
  829. file->off = entry.off;
  830. file->head = entry.d.u.file.head;
  831. file->size = entry.d.u.file.size;
  832. file->flags = flags;
  833. file->pos = 0;
  834. file->wblock = 0;
  835. file->rblock = 0;
  836. if (flags & LFS_O_TRUNC) {
  837. file->head = 0;
  838. file->size = 0;
  839. }
  840. return 0;
  841. }
  842. int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
  843. return lfs_file_sync(lfs, file);
  844. }
  845. static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
  846. if (file->rblock) {
  847. // just drop read block
  848. file->rblock = 0;
  849. }
  850. if (file->wblock) {
  851. lfs_off_t pos = file->pos;
  852. // copy over anything after current branch
  853. lfs_file_t orig = {
  854. .head = file->head,
  855. .size = file->size,
  856. .flags = LFS_O_RDONLY,
  857. .pos = file->pos,
  858. .rblock = 0,
  859. };
  860. while (file->pos < file->size) {
  861. uint8_t data;
  862. lfs_ssize_t res = lfs_file_read(lfs, &orig, &data, 1);
  863. if (res < 0) {
  864. return res;
  865. }
  866. res = lfs_file_write(lfs, file, &data, 1);
  867. if (res < 0) {
  868. return res;
  869. }
  870. }
  871. // actual file updates
  872. file->head = file->wblock;
  873. file->size = file->pos;
  874. file->wblock = 0;
  875. file->flags |= LFS_O_DIRTY;
  876. file->pos = pos;
  877. }
  878. return 0;
  879. }
  880. int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) {
  881. int err = lfs_file_flush(lfs, file);
  882. if (err) {
  883. return err;
  884. }
  885. if (file->flags & LFS_O_DIRTY) {
  886. // update dir entry
  887. lfs_dir_t cwd;
  888. int err = lfs_dir_fetch(lfs, &cwd, file->pair);
  889. if (err) {
  890. return err;
  891. }
  892. lfs_entry_t entry = {.off = file->off};
  893. err = lfs_bd_read(lfs, cwd.pair[0], entry.off,
  894. sizeof(entry.d), &entry.d);
  895. if (err) {
  896. return err;
  897. }
  898. if (entry.d.type != LFS_TYPE_REG) {
  899. // sanity check valid entry
  900. return LFS_ERR_INVAL;
  901. }
  902. entry.d.u.file.head = file->head;
  903. entry.d.u.file.size = file->size;
  904. err = lfs_dir_commit(lfs, &cwd, &entry, NULL);
  905. if (err) {
  906. return err;
  907. }
  908. file->flags &= ~LFS_O_DIRTY;
  909. }
  910. return 0;
  911. }
  912. lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
  913. void *buffer, lfs_size_t size) {
  914. uint8_t *data = buffer;
  915. lfs_size_t nsize = size;
  916. if ((file->flags & 3) == LFS_O_WRONLY) {
  917. return LFS_ERR_INVAL;
  918. }
  919. if (file->wblock) {
  920. // flush out any writes
  921. int err = lfs_file_flush(lfs, file);
  922. if (err) {
  923. return err;
  924. }
  925. }
  926. size = lfs_min(size, file->size - file->pos);
  927. nsize = size;
  928. while (nsize > 0) {
  929. // check if we need a new block
  930. if (!file->rblock || file->roff == lfs->cfg->block_size) {
  931. int err = lfs_index_find(lfs, file->head, file->size,
  932. file->pos, &file->rblock, &file->roff);
  933. if (err) {
  934. return err;
  935. }
  936. }
  937. // read as much as we can in current block
  938. lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->roff);
  939. int err = lfs_bd_read(lfs, file->rblock, file->roff, diff, data);
  940. if (err) {
  941. return err;
  942. }
  943. file->pos += diff;
  944. file->roff += diff;
  945. data += diff;
  946. nsize -= diff;
  947. }
  948. return size;
  949. }
  950. lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
  951. const void *buffer, lfs_size_t size) {
  952. const uint8_t *data = buffer;
  953. lfs_size_t nsize = size;
  954. if ((file->flags & 3) == LFS_O_RDONLY) {
  955. return LFS_ERR_INVAL;
  956. }
  957. if (file->rblock) {
  958. // drop any reads
  959. int err = lfs_file_flush(lfs, file);
  960. if (err) {
  961. return err;
  962. }
  963. }
  964. if ((file->flags & LFS_O_APPEND) && file->pos < file->size) {
  965. file->pos = file->size;
  966. }
  967. while (nsize > 0) {
  968. // check if we need a new block
  969. if (!file->wblock || file->woff == lfs->cfg->block_size) {
  970. if (!file->wblock) {
  971. // find out which block we're extending from
  972. int err = lfs_index_find(lfs, file->head, file->size,
  973. file->pos, &file->wblock, &file->woff);
  974. if (err) {
  975. return err;
  976. }
  977. }
  978. // extend file with new blocks
  979. int err = lfs_index_extend(lfs, file->wblock, file->pos,
  980. &file->wblock, &file->woff);
  981. if (err) {
  982. return err;
  983. }
  984. }
  985. // program as much as we can in current block
  986. lfs_size_t diff = lfs_min(nsize, lfs->cfg->block_size - file->woff);
  987. int err = lfs_bd_prog(lfs, file->wblock, file->woff, diff, data);
  988. if (err) {
  989. return err;
  990. }
  991. file->pos += diff;
  992. file->woff += diff;
  993. data += diff;
  994. nsize -= diff;
  995. }
  996. if (file->flags & LFS_O_SYNC) {
  997. int err = lfs_file_sync(lfs, file);
  998. if (err) {
  999. return err;
  1000. }
  1001. }
  1002. return size;
  1003. }
  1004. lfs_soff_t lfs_file_seek(lfs_t *lfs, lfs_file_t *file,
  1005. lfs_soff_t off, int whence) {
  1006. // write out everything beforehand, may be noop if rdonly
  1007. int err = lfs_file_flush(lfs, file);
  1008. if (err) {
  1009. return err;
  1010. }
  1011. // update pos
  1012. lfs_off_t pos = file->pos;
  1013. if (whence == LFS_SEEK_SET) {
  1014. file->pos = off;
  1015. } else if (whence == LFS_SEEK_CUR) {
  1016. file->pos = file->pos + off;
  1017. } else if (whence == LFS_SEEK_END) {
  1018. file->pos = file->size + off;
  1019. }
  1020. return pos;
  1021. }
  1022. lfs_soff_t lfs_file_tell(lfs_t *lfs, lfs_file_t *file) {
  1023. return file->pos;
  1024. }
  1025. int lfs_file_rewind(lfs_t *lfs, lfs_file_t *file) {
  1026. lfs_soff_t res = lfs_file_seek(lfs, file, 0, LFS_SEEK_SET);
  1027. if (res < 0) {
  1028. return res;
  1029. }
  1030. return 0;
  1031. }
  1032. lfs_soff_t lfs_file_size(lfs_t *lfs, lfs_file_t *file) {
  1033. return lfs_max(file->pos, file->size);
  1034. }
  1035. /// General fs oprations ///
  1036. int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
  1037. lfs_dir_t cwd;
  1038. int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
  1039. if (err) {
  1040. return err;
  1041. }
  1042. lfs_entry_t entry;
  1043. err = lfs_dir_find(lfs, &cwd, &entry, &path);
  1044. if (err) {
  1045. return err;
  1046. }
  1047. memset(info, 0, sizeof(*info));
  1048. info->type = entry.d.type & 0xff;
  1049. if (info->type == LFS_TYPE_REG) {
  1050. info->size = entry.d.u.file.size;
  1051. }
  1052. err = lfs_bd_read(lfs, cwd.pair[0], entry.off + sizeof(entry.d),
  1053. entry.d.len - sizeof(entry.d), info->name);
  1054. if (err) {
  1055. return err;
  1056. }
  1057. return 0;
  1058. }
  1059. int lfs_remove(lfs_t *lfs, const char *path) {
  1060. lfs_dir_t cwd;
  1061. int err = lfs_dir_fetch(lfs, &cwd, lfs->root);
  1062. if (err) {
  1063. return err;
  1064. }
  1065. lfs_entry_t entry;
  1066. err = lfs_dir_find(lfs, &cwd, &entry, &path);
  1067. if (err) {
  1068. return err;
  1069. }
  1070. lfs_dir_t dir;
  1071. if (entry.d.type == LFS_TYPE_DIR) {
  1072. // must be empty before removal, checking size
  1073. // without masking top bit checks for any case where
  1074. // dir is not empty
  1075. int err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir);
  1076. if (err) {
  1077. return err;
  1078. } else if (dir.d.size != sizeof(dir.d)) {
  1079. return LFS_ERR_INVAL;
  1080. }
  1081. }
  1082. // remove the entry
  1083. err = lfs_dir_remove(lfs, &cwd, &entry);
  1084. if (err) {
  1085. return err;
  1086. }
  1087. // if we were a directory, just run a deorphan step, this should
  1088. // collect us, although is expensive
  1089. if (entry.d.type == LFS_TYPE_DIR) {
  1090. int err = lfs_deorphan(lfs);
  1091. if (err) {
  1092. return err;
  1093. }
  1094. }
  1095. return 0;
  1096. }
  1097. int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
  1098. // find old entry
  1099. lfs_dir_t oldcwd;
  1100. int err = lfs_dir_fetch(lfs, &oldcwd, lfs->root);
  1101. if (err) {
  1102. return err;
  1103. }
  1104. lfs_entry_t oldentry;
  1105. err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath);
  1106. if (err) {
  1107. return err;
  1108. }
  1109. // allocate new entry
  1110. lfs_dir_t newcwd;
  1111. err = lfs_dir_fetch(lfs, &newcwd, lfs->root);
  1112. if (err) {
  1113. return err;
  1114. }
  1115. lfs_entry_t preventry;
  1116. err = lfs_dir_find(lfs, &newcwd, &preventry, &newpath);
  1117. if (err && err != LFS_ERR_NOENT) {
  1118. return err;
  1119. }
  1120. bool prevexists = (err != LFS_ERR_NOENT);
  1121. // must have same type
  1122. if (prevexists && preventry.d.type != oldentry.d.type) {
  1123. return LFS_ERR_INVAL;
  1124. }
  1125. lfs_dir_t dir;
  1126. if (prevexists && preventry.d.type == LFS_TYPE_DIR) {
  1127. // must be empty before removal, checking size
  1128. // without masking top bit checks for any case where
  1129. // dir is not empty
  1130. int err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir);
  1131. if (err) {
  1132. return err;
  1133. } else if (dir.d.size != sizeof(dir.d)) {
  1134. return LFS_ERR_INVAL;
  1135. }
  1136. }
  1137. // move to new location
  1138. lfs_entry_t newentry = preventry;
  1139. newentry.d = oldentry.d;
  1140. newentry.d.len = sizeof(newentry.d) + strlen(newpath);
  1141. if (prevexists) {
  1142. int err = lfs_dir_commit(lfs, &newcwd, &newentry, newpath);
  1143. if (err) {
  1144. return err;
  1145. }
  1146. } else {
  1147. int err = lfs_dir_append(lfs, &newcwd, &newentry, newpath);
  1148. if (err) {
  1149. return err;
  1150. }
  1151. }
  1152. // fetch again in case newcwd == oldcwd
  1153. err = lfs_dir_fetch(lfs, &oldcwd, oldcwd.pair);
  1154. if (err) {
  1155. return err;
  1156. }
  1157. err = lfs_dir_find(lfs, &oldcwd, &oldentry, &oldpath);
  1158. if (err) {
  1159. return err;
  1160. }
  1161. // remove from old location
  1162. err = lfs_dir_remove(lfs, &oldcwd, &oldentry);
  1163. if (err) {
  1164. return err;
  1165. }
  1166. // if we were a directory, just run a deorphan step, this should
  1167. // collect us, although is expensive
  1168. if (prevexists && preventry.d.type == LFS_TYPE_DIR) {
  1169. int err = lfs_deorphan(lfs);
  1170. if (err) {
  1171. return err;
  1172. }
  1173. }
  1174. return 0;
  1175. }
  1176. /// Filesystem operations ///
  1177. static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
  1178. lfs->cfg = cfg;
  1179. lfs->words = lfs->cfg->block_size / sizeof(uint32_t);
  1180. // setup read cache
  1181. lfs->rcache.off = -1;
  1182. if (lfs->cfg->read_buffer) {
  1183. lfs->rcache.buffer = lfs->cfg->read_buffer;
  1184. } else {
  1185. lfs->rcache.buffer = malloc(lfs->cfg->read_size);
  1186. if (!lfs->rcache.buffer) {
  1187. return LFS_ERR_NOMEM;
  1188. }
  1189. }
  1190. // setup program cache
  1191. lfs->pcache.off = -1;
  1192. if (lfs->cfg->prog_buffer) {
  1193. lfs->pcache.buffer = lfs->cfg->prog_buffer;
  1194. } else {
  1195. lfs->pcache.buffer = malloc(lfs->cfg->prog_size);
  1196. if (!lfs->pcache.buffer) {
  1197. return LFS_ERR_NOMEM;
  1198. }
  1199. }
  1200. // setup lookahead
  1201. if (lfs->cfg->lookahead_buffer) {
  1202. lfs->free.lookahead = lfs->cfg->lookahead_buffer;
  1203. } else {
  1204. lfs->free.lookahead = malloc(lfs->cfg->lookahead/8);
  1205. if (!lfs->free.lookahead) {
  1206. return LFS_ERR_NOMEM;
  1207. }
  1208. }
  1209. return 0;
  1210. }
  1211. static int lfs_deinit(lfs_t *lfs) {
  1212. // Free allocated memory
  1213. if (!lfs->cfg->read_buffer) {
  1214. free(lfs->rcache.buffer);
  1215. }
  1216. if (!lfs->cfg->prog_buffer) {
  1217. free(lfs->pcache.buffer);
  1218. }
  1219. return 0;
  1220. }
  1221. int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
  1222. int err = lfs_init(lfs, cfg);
  1223. if (err) {
  1224. return err;
  1225. }
  1226. // Create free lookahead
  1227. memset(lfs->free.lookahead, 0, lfs->cfg->lookahead/8);
  1228. lfs->free.start = 0;
  1229. lfs->free.off = 0;
  1230. // Create superblock dir
  1231. lfs_dir_t superdir;
  1232. err = lfs_dir_alloc(lfs, &superdir);
  1233. if (err) {
  1234. return err;
  1235. }
  1236. // Write root directory
  1237. lfs_dir_t root;
  1238. err = lfs_dir_alloc(lfs, &root);
  1239. if (err) {
  1240. return err;
  1241. }
  1242. err = lfs_dir_commit(lfs, &root, NULL, NULL);
  1243. if (err) {
  1244. return err;
  1245. }
  1246. lfs->root[0] = root.pair[0];
  1247. lfs->root[1] = root.pair[1];
  1248. // Write superblocks
  1249. lfs_superblock_t superblock = {
  1250. .off = sizeof(superdir.d),
  1251. .d.type = LFS_TYPE_SUPERBLOCK,
  1252. .d.len = sizeof(superblock.d),
  1253. .d.version = 0x00000001,
  1254. .d.magic = {"littlefs"},
  1255. .d.block_size = lfs->cfg->block_size,
  1256. .d.block_count = lfs->cfg->block_count,
  1257. .d.root = {lfs->root[0], lfs->root[1]},
  1258. };
  1259. superdir.d.tail[0] = root.pair[0];
  1260. superdir.d.tail[1] = root.pair[1];
  1261. superdir.d.size += sizeof(superdir.d);
  1262. for (int i = 0; i < 2; i++) {
  1263. // Write both pairs for extra safety, do some finagling to pretend
  1264. // the superblock is an entry
  1265. int err = lfs_dir_commit(lfs, &superdir,
  1266. (const lfs_entry_t*)&superblock,
  1267. (const struct lfs_disk_entry*)&superblock.d + 1);
  1268. if (err) {
  1269. LFS_ERROR("Failed to write superblock at %d", superdir.pair[0]);
  1270. return err;
  1271. }
  1272. }
  1273. // sanity check that fetch works
  1274. err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1});
  1275. if (err) {
  1276. return err;
  1277. }
  1278. return lfs_deinit(lfs);
  1279. }
  1280. int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
  1281. int err = lfs_init(lfs, cfg);
  1282. if (err) {
  1283. return err;
  1284. }
  1285. // setup free lookahead
  1286. lfs->free.start = -lfs->cfg->lookahead;
  1287. lfs->free.off = lfs->cfg->lookahead;
  1288. // load superblock
  1289. lfs_dir_t dir;
  1290. lfs_superblock_t superblock;
  1291. err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1});
  1292. if (!err) {
  1293. err = lfs_bd_read(lfs, dir.pair[0],
  1294. sizeof(dir.d), sizeof(superblock.d), &superblock.d);
  1295. lfs->root[0] = superblock.d.root[0];
  1296. lfs->root[1] = superblock.d.root[1];
  1297. }
  1298. if (err == LFS_ERR_CORRUPT ||
  1299. memcmp(superblock.d.magic, "littlefs", 8) != 0) {
  1300. LFS_ERROR("Invalid superblock at %d %d", dir.pair[0], dir.pair[1]);
  1301. return LFS_ERR_CORRUPT;
  1302. }
  1303. if (superblock.d.version > 0x0000ffff) {
  1304. LFS_ERROR("Invalid version %d.%d\n",
  1305. 0xffff & (superblock.d.version >> 16),
  1306. 0xffff & (superblock.d.version >> 0));
  1307. return LFS_ERR_INVAL;
  1308. }
  1309. return err;
  1310. }
  1311. int lfs_unmount(lfs_t *lfs) {
  1312. return lfs_deinit(lfs);
  1313. }
  1314. /// Littlefs specific operations ///
  1315. int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
  1316. // iterate over metadata pairs
  1317. lfs_dir_t dir;
  1318. lfs_entry_t entry;
  1319. lfs_block_t cwd[2] = {0, 1};
  1320. while (true) {
  1321. for (int i = 0; i < 2; i++) {
  1322. int err = cb(data, cwd[i]);
  1323. if (err) {
  1324. return err;
  1325. }
  1326. }
  1327. int err = lfs_dir_fetch(lfs, &dir, cwd);
  1328. if (err) {
  1329. return err;
  1330. }
  1331. // iterate over contents
  1332. while ((0x7fffffff & dir.d.size) >= dir.off + sizeof(entry.d)) {
  1333. int err = lfs_bd_read(lfs, dir.pair[0], dir.off,
  1334. sizeof(entry.d), &entry.d);
  1335. if (err) {
  1336. return err;
  1337. }
  1338. dir.off += entry.d.len;
  1339. if ((0xf & entry.d.type) == LFS_TYPE_REG) {
  1340. int err = lfs_index_traverse(lfs,
  1341. entry.d.u.file.head, entry.d.u.file.size,
  1342. cb, data);
  1343. if (err) {
  1344. return err;
  1345. }
  1346. }
  1347. }
  1348. cwd[0] = dir.d.tail[0];
  1349. cwd[1] = dir.d.tail[1];
  1350. if (!cwd[0]) {
  1351. return 0;
  1352. }
  1353. }
  1354. }
  1355. static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2]) {
  1356. // iterate over all directory directory entries
  1357. lfs_dir_t parent = {
  1358. .d.tail[0] = lfs->root[0],
  1359. .d.tail[1] = lfs->root[1],
  1360. };
  1361. while (parent.d.tail[0]) {
  1362. lfs_entry_t entry;
  1363. int err = lfs_dir_fetch(lfs, &parent, parent.d.tail);
  1364. if (err) {
  1365. return err;
  1366. }
  1367. while (true) {
  1368. int err = lfs_dir_next(lfs, &parent, &entry);
  1369. if (err && err != LFS_ERR_NOENT) {
  1370. return err;
  1371. }
  1372. if (err == LFS_ERR_NOENT) {
  1373. break;
  1374. }
  1375. if ((0xf & entry.d.type) == LFS_TYPE_DIR &&
  1376. lfs_paircmp(entry.d.u.dir, dir) == 0) {
  1377. return true;
  1378. }
  1379. }
  1380. }
  1381. return false;
  1382. }
  1383. int lfs_deorphan(lfs_t *lfs) {
  1384. // iterate over all directories
  1385. lfs_dir_t pdir;
  1386. lfs_dir_t cdir;
  1387. // skip root
  1388. int err = lfs_dir_fetch(lfs, &pdir, lfs->root);
  1389. if (err) {
  1390. return err;
  1391. }
  1392. while (pdir.d.tail[0]) {
  1393. int err = lfs_dir_fetch(lfs, &cdir, pdir.d.tail);
  1394. if (err) {
  1395. return err;
  1396. }
  1397. // check if we have a parent
  1398. int parent = lfs_parent(lfs, pdir.d.tail);
  1399. if (parent < 0) {
  1400. return parent;
  1401. }
  1402. if (!parent) {
  1403. // we are an orphan
  1404. LFS_DEBUG("Orphan %d %d", pdir.d.tail[0], pdir.d.tail[1]);
  1405. pdir.d.tail[0] = cdir.d.tail[0];
  1406. pdir.d.tail[1] = cdir.d.tail[1];
  1407. err = lfs_dir_commit(lfs, &pdir, NULL, NULL);
  1408. if (err) {
  1409. return err;
  1410. }
  1411. break;
  1412. }
  1413. memcpy(&pdir, &cdir, sizeof(pdir));
  1414. }
  1415. return 0;
  1416. }