lfs.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413
  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 <stdbool.h>
  11. /// Block device operations ///
  12. static int lfs_bd_info(lfs_t *lfs, struct lfs_bd_info *info) {
  13. return lfs->bd_ops->info(lfs->bd, info);
  14. }
  15. static int lfs_bd_read(lfs_t *lfs, lfs_block_t block,
  16. lfs_off_t off, lfs_size_t size, void *buffer) {
  17. return lfs->bd_ops->read(lfs->bd, block, off, size, buffer);
  18. }
  19. static int lfs_bd_prog(lfs_t *lfs, lfs_block_t block,
  20. lfs_off_t off, lfs_size_t size, const void *buffer) {
  21. return lfs->bd_ops->prog(lfs->bd, block, off, size, buffer);
  22. }
  23. static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block,
  24. lfs_off_t off, lfs_size_t size) {
  25. return lfs->bd_ops->erase(lfs->bd, block, off, size);
  26. }
  27. static int lfs_bd_sync(lfs_t *lfs) {
  28. return lfs->bd_ops->sync(lfs->bd);
  29. }
  30. static int lfs_bd_cmp(lfs_t *lfs, lfs_block_t block,
  31. lfs_off_t off, lfs_size_t size, const void *buffer) {
  32. const uint8_t *data = buffer;
  33. for (lfs_off_t i = 0; i < size; i++) {
  34. uint8_t c;
  35. int err = lfs_bd_read(lfs, block, off+i, 1, &c);
  36. if (err) {
  37. return err;
  38. }
  39. if (c != *data) {
  40. return false;
  41. }
  42. data += 1;
  43. }
  44. return true;
  45. }
  46. static int lfs_bd_crc(lfs_t *lfs, lfs_block_t block,
  47. lfs_off_t off, lfs_size_t size, uint32_t *crc) {
  48. while (off < size) {
  49. uint8_t c;
  50. int err = lfs_bd_read(lfs, block, off, 1, &c);
  51. if (err) {
  52. return err;
  53. }
  54. *crc = lfs_crc(&c, 1, *crc);
  55. off += 1;
  56. }
  57. return 0;
  58. }
  59. /// Block allocator ///
  60. static int lfs_alloc_lookahead(void *p, lfs_block_t block) {
  61. lfs_t *lfs = p;
  62. lfs_block_t off = block - lfs->free.begin;
  63. if (off < LFS_CFG_LOOKAHEAD) {
  64. lfs->lookahead[off / 32] |= 1U << (off % 32);
  65. }
  66. return 0;
  67. }
  68. static int lfs_alloc_stride(void *p, lfs_block_t block) {
  69. lfs_t *lfs = p;
  70. lfs_block_t noff = block - lfs->free.begin;
  71. lfs_block_t off = lfs->free.end - lfs->free.begin;
  72. if (noff < off) {
  73. lfs->free.end = noff + lfs->free.begin;
  74. }
  75. return 0;
  76. }
  77. static int lfs_alloc_scan(lfs_t *lfs) {
  78. lfs_block_t start = lfs->free.begin;
  79. while (true) {
  80. // mask out blocks in lookahead region
  81. memset(lfs->lookahead, 0, sizeof(lfs->lookahead));
  82. int err = lfs_traverse(lfs, lfs_alloc_lookahead, lfs);
  83. if (err) {
  84. return err;
  85. }
  86. // check if we've found a free block
  87. for (uint32_t off = 0; off < LFS_CFG_LOOKAHEAD; off++) {
  88. if (lfs->lookahead[off / 32] & (1U << (off % 32))) {
  89. continue;
  90. }
  91. // found free block, now find stride of free blocks
  92. // since this is relatively cheap (stress on relatively)
  93. lfs->free.begin += off;
  94. lfs->free.end = lfs->block_count; // before superblock
  95. // find maximum stride in tree
  96. return lfs_traverse(lfs, lfs_alloc_stride, lfs);
  97. }
  98. // continue to next lookahead unless we've searched the whole device
  99. if (start-1 - lfs->free.begin < LFS_CFG_LOOKAHEAD) {
  100. return 0;
  101. }
  102. // continue to next lookahead region
  103. lfs->free.begin += LFS_CFG_LOOKAHEAD;
  104. }
  105. }
  106. static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
  107. // If we don't remember any free blocks we will need to start searching
  108. if (lfs->free.begin == lfs->free.end) {
  109. int err = lfs_alloc_scan(lfs);
  110. if (err) {
  111. return err;
  112. }
  113. if (lfs->free.begin == lfs->free.end) {
  114. // Still can't allocate a block? check for orphans
  115. int err = lfs_deorphan(lfs);
  116. if (err) {
  117. return err;
  118. }
  119. err = lfs_alloc_scan(lfs);
  120. if (err) {
  121. return err;
  122. }
  123. if (lfs->free.begin == lfs->free.end) {
  124. // Ok, it's true, we're out of space
  125. return LFS_ERROR_NO_SPACE;
  126. }
  127. }
  128. }
  129. // Take first available block
  130. *block = lfs->free.begin;
  131. lfs->free.begin += 1;
  132. return 0;
  133. }
  134. static int lfs_alloc_erased(lfs_t *lfs, lfs_block_t *block) {
  135. int err = lfs_alloc(lfs, block);
  136. if (err) {
  137. return err;
  138. }
  139. return lfs_bd_erase(lfs, *block, 0, lfs->block_size);
  140. }
  141. /// Index list operations ///
  142. // Next index offset
  143. static lfs_off_t lfs_indexnext(lfs_t *lfs, lfs_off_t ioff) {
  144. ioff += 1;
  145. while (ioff % lfs->words == 0) {
  146. ioff += lfs_min(lfs_ctz(ioff/lfs->words + 1), lfs->words-1) + 1;
  147. }
  148. return ioff;
  149. }
  150. static lfs_off_t lfs_indexfrom(lfs_t *lfs, lfs_off_t off) {
  151. lfs_off_t i = 0;
  152. while (off > lfs->block_size) {
  153. i = lfs_indexnext(lfs, i);
  154. off -= lfs->block_size;
  155. }
  156. return i;
  157. }
  158. // Find index in index chain given its index offset
  159. static int lfs_index_find(lfs_t *lfs, lfs_block_t head,
  160. lfs_size_t icount, lfs_off_t ioff, lfs_block_t *block) {
  161. lfs_off_t iitarget = ioff / lfs->words;
  162. lfs_off_t iicurrent = (icount-1) / lfs->words;
  163. while (iitarget != iicurrent) {
  164. lfs_size_t skip = lfs_min(
  165. lfs_min(lfs_ctz(iicurrent+1), lfs->words-1),
  166. lfs_npw2((iitarget ^ iicurrent)+1)-1);
  167. int err = lfs_bd_read(lfs, head, 4*skip, 4, &head);
  168. if (err) {
  169. return err;
  170. }
  171. iicurrent -= 1 << skip;
  172. }
  173. return lfs_bd_read(lfs, head, 4*(ioff % lfs->words), 4, block);
  174. }
  175. // Append index to index chain, updates head and icount
  176. static int lfs_index_append(lfs_t *lfs, lfs_block_t *headp,
  177. lfs_size_t *icountp, lfs_block_t block) {
  178. lfs_block_t head = *headp;
  179. lfs_size_t ioff = *icountp - 1;
  180. ioff += 1;
  181. while (ioff % lfs->words == 0) {
  182. lfs_block_t nhead;
  183. int err = lfs_alloc_erased(lfs, &nhead);
  184. if (err) {
  185. return err;
  186. }
  187. lfs_off_t skips = lfs_min(
  188. lfs_ctz(ioff/lfs->words + 1), lfs->words-2) + 1;
  189. for (lfs_off_t i = 0; i < skips; i++) {
  190. err = lfs_bd_prog(lfs, nhead, 4*i, 4, &head);
  191. if (err) {
  192. return err;
  193. }
  194. if (head && i != skips-1) {
  195. err = lfs_bd_read(lfs, head, 4*i, 4, &head);
  196. if (err) {
  197. return err;
  198. }
  199. }
  200. }
  201. ioff += skips;
  202. head = nhead;
  203. }
  204. int err = lfs_bd_prog(lfs, head, 4*(ioff % lfs->words), 4, &block);
  205. if (err) {
  206. return err;
  207. }
  208. *headp = head;
  209. *icountp = ioff + 1;
  210. return 0;
  211. }
  212. static int lfs_index_traverse(lfs_t *lfs, lfs_block_t head,
  213. lfs_size_t icount, int (*cb)(void*, lfs_block_t), void *data) {
  214. lfs_off_t iicurrent = (icount-1) / lfs->words;
  215. while (iicurrent > 0) {
  216. int err = cb(data, head);
  217. if (err) {
  218. return err;
  219. }
  220. lfs_size_t skip = lfs_min(lfs_ctz(iicurrent+1), lfs->words-1);
  221. for (lfs_off_t i = skip; i < lfs->words; i++) {
  222. lfs_block_t block;
  223. int err = lfs_bd_read(lfs, head, 4*i, 4, &block);
  224. if (err) {
  225. return err;
  226. }
  227. err = cb(data, block);
  228. if (err) {
  229. return err;
  230. }
  231. }
  232. err = lfs_bd_read(lfs, head, 0, 4, &head);
  233. if (err) {
  234. return err;
  235. }
  236. iicurrent -= 1;
  237. }
  238. int err = cb(data, head);
  239. if (err) {
  240. return err;
  241. }
  242. for (lfs_off_t i = 0; i < lfs->words; i++) {
  243. lfs_block_t block;
  244. int err = lfs_bd_read(lfs, head, 4*i, 4, &block);
  245. if (err) {
  246. return err;
  247. }
  248. err = cb(data, block);
  249. if (err) {
  250. return err;
  251. }
  252. }
  253. return 0;
  254. }
  255. /// Metadata pair operations ///
  256. static inline void lfs_pairswap(lfs_block_t pair[2]) {
  257. lfs_block_t t = pair[0];
  258. pair[0] = pair[1];
  259. pair[1] = t;
  260. }
  261. static inline int lfs_paircmp(
  262. const lfs_block_t paira[2],
  263. const lfs_block_t pairb[2]) {
  264. return !((paira[0] == pairb[0] && paira[1] == pairb[1]) ||
  265. (paira[0] == pairb[1] && paira[1] == pairb[0]));
  266. }
  267. struct lfs_fetch_region {
  268. lfs_off_t off;
  269. lfs_size_t size;
  270. void *data;
  271. };
  272. static int lfs_pair_fetch(lfs_t *lfs, lfs_block_t pair[2],
  273. int count, const struct lfs_fetch_region *regions) {
  274. int checked = 0;
  275. int rev = 0;
  276. for (int i = 0; i < 2; i++) {
  277. uint32_t nrev;
  278. int err = lfs_bd_read(lfs, pair[1], 0, 4, &nrev);
  279. if (err) {
  280. return err;
  281. }
  282. if (checked > 0 && lfs_scmp(nrev, rev) < 0) {
  283. continue;
  284. }
  285. uint32_t crc = 0xffffffff;
  286. err = lfs_bd_crc(lfs, pair[1], 0, lfs->block_size, &crc);
  287. if (err) {
  288. return err;
  289. }
  290. if (crc != 0) {
  291. lfs_pairswap(pair);
  292. }
  293. checked += 1;
  294. rev = nrev;
  295. lfs_pairswap(pair);
  296. }
  297. if (checked == 0) {
  298. LFS_ERROR("Corrupted metadata pair at %d %d", pair[0], pair[1]);
  299. return LFS_ERROR_CORRUPT;
  300. }
  301. for (int i = 0; i < count; i++) {
  302. int err = lfs_bd_read(lfs, pair[0],
  303. regions[i].off, regions[i].size, regions[i].data);
  304. if (err) {
  305. return err;
  306. }
  307. }
  308. return 0;
  309. }
  310. struct lfs_commit_region {
  311. lfs_off_t off;
  312. lfs_size_t size;
  313. const void *data;
  314. };
  315. static int lfs_pair_commit(lfs_t *lfs, lfs_block_t pair[2],
  316. int count, const struct lfs_commit_region *regions) {
  317. uint32_t crc = 0xffffffff;
  318. int err = lfs_bd_erase(lfs, pair[1], 0, lfs->block_size);
  319. if (err) {
  320. return err;
  321. }
  322. lfs_off_t off = 0;
  323. while (off < lfs->block_size - 4) {
  324. if (count > 0 && regions[0].off == off) {
  325. crc = lfs_crc(regions[0].data, regions[0].size, crc);
  326. int err = lfs_bd_prog(lfs, pair[1],
  327. off, regions[0].size, regions[0].data);
  328. if (err) {
  329. return err;
  330. }
  331. off += regions[0].size;
  332. count -= 1;
  333. regions += 1;
  334. } else {
  335. // TODO faster strides?
  336. // TODO should we start crcing what's already
  337. // programmed after dir size?
  338. uint8_t data;
  339. int err = lfs_bd_read(lfs, pair[0], off, 1, &data);
  340. if (err) {
  341. return err;
  342. }
  343. crc = lfs_crc((void*)&data, 1, crc);
  344. err = lfs_bd_prog(lfs, pair[1], off, 1, &data);
  345. if (err) {
  346. return err;
  347. }
  348. off += 1;
  349. }
  350. }
  351. err = lfs_bd_prog(lfs, pair[1], lfs->block_size-4, 4, &crc);
  352. if (err) {
  353. return err;
  354. }
  355. err = lfs_bd_sync(lfs);
  356. if (err) {
  357. return err;
  358. }
  359. lfs_pairswap(pair);
  360. return 0;
  361. }
  362. // TODO maybe there is a better abstraction for this?
  363. static int lfs_pair_shift(lfs_t *lfs, lfs_block_t pair[2],
  364. int count, const struct lfs_commit_region *regions,
  365. lfs_off_t blank_start, lfs_size_t blank_size) {
  366. uint32_t crc = 0xffffffff;
  367. int err = lfs_bd_erase(lfs, pair[1], 0, lfs->block_size);
  368. if (err) {
  369. return err;
  370. }
  371. lfs_off_t woff = 0;
  372. lfs_off_t roff = 0;
  373. while (woff < lfs->block_size - 4) {
  374. if (count > 0 && regions[0].off == woff) {
  375. crc = lfs_crc(regions[0].data, regions[0].size, crc);
  376. int err = lfs_bd_prog(lfs, pair[1],
  377. woff, regions[0].size, regions[0].data);
  378. if (err) {
  379. return err;
  380. }
  381. woff += regions[0].size;
  382. roff += regions[0].size;
  383. count -= 1;
  384. regions += 1;
  385. } else if (roff == blank_start) {
  386. roff += blank_size;
  387. } else if (roff < lfs->block_size - 4) {
  388. // TODO faster strides?
  389. // TODO should we start crcing what's already
  390. // programmed after dir size?
  391. uint8_t data;
  392. int err = lfs_bd_read(lfs, pair[0], roff, 1, &data);
  393. if (err) {
  394. return err;
  395. }
  396. crc = lfs_crc((void*)&data, 1, crc);
  397. err = lfs_bd_prog(lfs, pair[1], woff, 1, &data);
  398. if (err) {
  399. return err;
  400. }
  401. woff += 1;
  402. roff += 1;
  403. } else {
  404. uint8_t data = 0;
  405. crc = lfs_crc((void*)&data, 1, crc);
  406. err = lfs_bd_prog(lfs, pair[1], woff, 1, &data);
  407. if (err) {
  408. return err;
  409. }
  410. woff += 1;
  411. }
  412. }
  413. err = lfs_bd_prog(lfs, pair[1], lfs->block_size-4, 4, &crc);
  414. if (err) {
  415. return err;
  416. }
  417. err = lfs_bd_sync(lfs);
  418. if (err) {
  419. return err;
  420. }
  421. lfs_pairswap(pair);
  422. return 0;
  423. }
  424. /// Directory operations ///
  425. static int lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir,
  426. lfs_block_t parent[2], lfs_block_t tail[2]) {
  427. // Allocate pair of dir blocks
  428. for (int i = 0; i < 2; i++) {
  429. int err = lfs_alloc(lfs, &dir->pair[i]);
  430. if (err) {
  431. return err;
  432. }
  433. }
  434. // Rather than clobbering one of the blocks we just pretend
  435. // the revision may be valid
  436. int err = lfs_bd_read(lfs, dir->pair[0], 0, 4, &dir->d.rev);
  437. if (err) {
  438. return err;
  439. }
  440. dir->d.rev += 1;
  441. // Calculate total size
  442. dir->d.size = sizeof(dir->d);
  443. dir->off = sizeof(dir->d);
  444. // Other defaults
  445. dir->d.tail[0] = tail[0];
  446. dir->d.tail[1] = tail[1];
  447. // Write out to memory
  448. if (!parent) {
  449. return lfs_pair_commit(lfs, dir->pair,
  450. 1, (struct lfs_commit_region[]){
  451. {0, sizeof(dir->d), &dir->d}
  452. });
  453. } else {
  454. dir->d.size += 2*sizeof(struct lfs_disk_entry) + 3;
  455. return lfs_pair_commit(lfs, dir->pair,
  456. 5, (struct lfs_commit_region[]){
  457. {0, sizeof(dir->d), &dir->d},
  458. {sizeof(dir->d), sizeof(struct lfs_disk_entry),
  459. &(struct lfs_disk_entry){
  460. .type = LFS_TYPE_DIR,
  461. .len = sizeof(struct lfs_disk_entry)+1,
  462. .u.dir[0] = dir->pair[0],
  463. .u.dir[1] = dir->pair[1],
  464. }},
  465. {sizeof(dir->d)+sizeof(struct lfs_disk_entry), 1, "."},
  466. {sizeof(dir->d)+sizeof(struct lfs_disk_entry)+1,
  467. sizeof(struct lfs_disk_entry),
  468. &(struct lfs_disk_entry){
  469. .type = LFS_TYPE_DIR,
  470. .len = sizeof(struct lfs_disk_entry)+2,
  471. .u.dir[0] = parent[0] ? parent[0] : dir->pair[0],
  472. .u.dir[1] = parent[1] ? parent[1] : dir->pair[1],
  473. }},
  474. {sizeof(dir->d)+2*sizeof(struct lfs_disk_entry)+1, 2, ".."},
  475. });
  476. }
  477. }
  478. static int lfs_dir_fetch(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t pair[2]) {
  479. dir->pair[0] = pair[0];
  480. dir->pair[1] = pair[1];
  481. dir->off = sizeof(dir->d);
  482. return lfs_pair_fetch(lfs, dir->pair,
  483. 1, (struct lfs_fetch_region[1]) {
  484. {0, sizeof(dir->d), &dir->d}
  485. });
  486. }
  487. static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
  488. while (true) {
  489. if ((0x7fffffff & dir->d.size) - dir->off < sizeof(entry->d)) {
  490. if (!(dir->d.size >> 31)) {
  491. entry->dir[0] = dir->pair[0];
  492. entry->dir[1] = dir->pair[1];
  493. entry->off = dir->off;
  494. return LFS_ERROR_NO_ENTRY;
  495. }
  496. int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
  497. if (err) {
  498. return err;
  499. }
  500. dir->off = sizeof(dir->d);
  501. }
  502. int err = lfs_bd_read(lfs, dir->pair[0], dir->off,
  503. sizeof(entry->d), &entry->d);
  504. if (err) {
  505. return err;
  506. }
  507. dir->off += entry->d.len;
  508. if (entry->d.type == LFS_TYPE_REG || entry->d.type == LFS_TYPE_DIR) {
  509. entry->dir[0] = dir->pair[0];
  510. entry->dir[1] = dir->pair[1];
  511. entry->off = dir->off - entry->d.len;
  512. return 0;
  513. }
  514. }
  515. }
  516. static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
  517. const char **path, lfs_entry_t *entry) {
  518. while (true) {
  519. const char *pathname = *path;
  520. lfs_size_t pathlen = strcspn(pathname, "/");
  521. while (true) {
  522. int err = lfs_dir_next(lfs, dir, entry);
  523. if (err) {
  524. return err;
  525. }
  526. if (entry->d.len - sizeof(entry->d) != pathlen) {
  527. continue;
  528. }
  529. int ret = lfs_bd_cmp(lfs, entry->dir[0],
  530. entry->off + sizeof(entry->d), pathlen, pathname);
  531. if (ret < 0) {
  532. return ret;
  533. }
  534. // Found match
  535. if (ret == true) {
  536. break;
  537. }
  538. }
  539. pathname += pathlen;
  540. pathname += strspn(pathname, "/");
  541. if (pathname[0] == '\0') {
  542. return 0;
  543. }
  544. if (entry->d.type != LFS_TYPE_DIR) {
  545. return LFS_ERROR_NOT_DIR;
  546. }
  547. int err = lfs_dir_fetch(lfs, dir, entry->d.u.dir);
  548. if (err) {
  549. return err;
  550. }
  551. *path = pathname;
  552. }
  553. return 0;
  554. }
  555. static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
  556. const char **path, lfs_entry_t *entry) {
  557. int err = lfs_dir_find(lfs, dir, path, entry);
  558. if (err != LFS_ERROR_NO_ENTRY) {
  559. return err ? err : LFS_ERROR_EXISTS;
  560. }
  561. // Check if we fit
  562. if ((0x7fffffff & dir->d.size) + sizeof(entry->d) + strlen(*path)
  563. > lfs->block_size - 4) {
  564. lfs_dir_t olddir;
  565. memcpy(&olddir, dir, sizeof(olddir));
  566. int err = lfs_dir_alloc(lfs, dir, 0, olddir.d.tail);
  567. if (err) {
  568. return err;
  569. }
  570. entry->dir[0] = dir->pair[0];
  571. entry->dir[1] = dir->pair[1];
  572. entry->off = dir->off;
  573. olddir.d.rev += 1;
  574. olddir.d.size |= 1 << 31;
  575. olddir.d.tail[0] = dir->pair[0];
  576. olddir.d.tail[1] = dir->pair[1];
  577. return lfs_pair_commit(lfs, olddir.pair,
  578. 1, (struct lfs_commit_region[]){
  579. {0, sizeof(olddir.d), &olddir.d}
  580. });
  581. }
  582. return 0;
  583. }
  584. int lfs_mkdir(lfs_t *lfs, const char *path) {
  585. // Allocate entry for directory
  586. lfs_dir_t cwd;
  587. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  588. if (err) {
  589. return err;
  590. }
  591. lfs_entry_t entry;
  592. err = lfs_dir_append(lfs, &cwd, &path, &entry);
  593. if (err) {
  594. return err;
  595. }
  596. // Build up new directory
  597. lfs_dir_t dir;
  598. err = lfs_dir_alloc(lfs, &dir, cwd.pair, cwd.d.tail);
  599. if (err) {
  600. return err;
  601. }
  602. entry.d.type = LFS_TYPE_DIR;
  603. entry.d.len = sizeof(entry.d) + strlen(path);
  604. entry.d.u.dir[0] = dir.pair[0];
  605. entry.d.u.dir[1] = dir.pair[1];
  606. cwd.d.rev += 1;
  607. cwd.d.size += entry.d.len;
  608. cwd.d.tail[0] = dir.pair[0];
  609. cwd.d.tail[1] = dir.pair[1];
  610. return lfs_pair_commit(lfs, entry.dir,
  611. 3, (struct lfs_commit_region[3]) {
  612. {0, sizeof(cwd.d), &cwd.d},
  613. {entry.off, sizeof(entry.d), &entry.d},
  614. {entry.off+sizeof(entry.d), entry.d.len - sizeof(entry.d), path}
  615. });
  616. }
  617. int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
  618. if (path[0] == '/') {
  619. dir->pair[0] = lfs->root[0];
  620. dir->pair[1] = lfs->root[1];
  621. } else {
  622. dir->pair[0] = lfs->cwd[0];
  623. dir->pair[1] = lfs->cwd[1];
  624. }
  625. int err = lfs_dir_fetch(lfs, dir, dir->pair);
  626. if (err) {
  627. return err;
  628. } else if (strcmp(path, "/") == 0) {
  629. return 0;
  630. }
  631. lfs_entry_t entry;
  632. err = lfs_dir_find(lfs, dir, &path, &entry);
  633. if (err) {
  634. return err;
  635. } else if (entry.d.type != LFS_TYPE_DIR) {
  636. return LFS_ERROR_NOT_DIR;
  637. }
  638. return lfs_dir_fetch(lfs, dir, entry.d.u.dir);
  639. }
  640. int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
  641. // Do nothing, dir is always synchronized
  642. return 0;
  643. }
  644. int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
  645. memset(info, 0, sizeof(*info));
  646. lfs_entry_t entry;
  647. int err = lfs_dir_next(lfs, dir, &entry);
  648. if (err) {
  649. return (err == LFS_ERROR_NO_ENTRY) ? 0 : err;
  650. }
  651. info->type = entry.d.type & 0xff;
  652. if (info->type == LFS_TYPE_REG) {
  653. info->size = entry.d.u.file.size;
  654. }
  655. err = lfs_bd_read(lfs, entry.dir[0], entry.off + sizeof(entry.d),
  656. entry.d.len - sizeof(entry.d), info->name);
  657. if (err) {
  658. return err;
  659. }
  660. return 1;
  661. }
  662. /// File operations ///
  663. int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
  664. const char *path, int flags) {
  665. // Allocate entry for file if it doesn't exist
  666. // TODO check open files
  667. lfs_dir_t cwd;
  668. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  669. if (err) {
  670. return err;
  671. }
  672. if (flags & LFS_O_CREAT) {
  673. err = lfs_dir_append(lfs, &cwd, &path, &file->entry);
  674. if (err && err != LFS_ERROR_EXISTS) {
  675. return err;
  676. }
  677. } else {
  678. err = lfs_dir_find(lfs, &cwd, &path, &file->entry);
  679. if (err) {
  680. return err;
  681. }
  682. }
  683. if ((flags & LFS_O_CREAT) && err != LFS_ERROR_EXISTS) {
  684. // Store file
  685. file->head = 0;
  686. file->size = 0;
  687. file->wblock = 0;
  688. file->windex = 0;
  689. file->rblock = 0;
  690. file->rindex = 0;
  691. file->roff = 0;
  692. file->entry.d.type = 1;
  693. file->entry.d.len = sizeof(file->entry.d) + strlen(path);
  694. file->entry.d.u.file.head = file->head;
  695. file->entry.d.u.file.size = file->size;
  696. cwd.d.rev += 1;
  697. cwd.d.size += file->entry.d.len;
  698. return lfs_pair_commit(lfs, file->entry.dir,
  699. 3, (struct lfs_commit_region[3]) {
  700. {0, sizeof(cwd.d), &cwd.d},
  701. {file->entry.off,
  702. sizeof(file->entry.d),
  703. &file->entry.d},
  704. {file->entry.off+sizeof(file->entry.d),
  705. file->entry.d.len-sizeof(file->entry.d),
  706. path}
  707. });
  708. } else if (file->entry.d.type == LFS_TYPE_DIR) {
  709. return LFS_ERROR_IS_DIR;
  710. } else {
  711. file->head = file->entry.d.u.file.head;
  712. file->size = file->entry.d.u.file.size;
  713. file->windex = lfs_indexfrom(lfs, file->size);
  714. file->rblock = 0;
  715. file->rindex = 0;
  716. file->roff = 0;
  717. // TODO do this lazily in write?
  718. // TODO cow the head i/d block
  719. if (file->size < lfs->block_size) {
  720. file->wblock = file->head;
  721. } else {
  722. int err = lfs_index_find(lfs, file->head, file->windex,
  723. file->windex, &file->wblock);
  724. if (err) {
  725. return err;
  726. }
  727. }
  728. return 0;
  729. }
  730. }
  731. int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
  732. // Store file
  733. lfs_dir_t cwd;
  734. int err = lfs_dir_fetch(lfs, &cwd, file->entry.dir);
  735. if (err) {
  736. return err;
  737. }
  738. file->entry.d.u.file.head = file->head;
  739. file->entry.d.u.file.size = file->size;
  740. cwd.d.rev += 1;
  741. return lfs_pair_commit(lfs, file->entry.dir,
  742. 3, (struct lfs_commit_region[3]) {
  743. {0, sizeof(cwd.d), &cwd.d},
  744. {file->entry.off, sizeof(file->entry.d), &file->entry.d},
  745. });
  746. }
  747. lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
  748. const void *buffer, lfs_size_t size) {
  749. const uint8_t *data = buffer;
  750. lfs_size_t nsize = size;
  751. while (nsize > 0) {
  752. lfs_off_t woff = file->size % lfs->block_size;
  753. if (file->size == 0) {
  754. int err = lfs_alloc_erased(lfs, &file->wblock);
  755. if (err) {
  756. return err;
  757. }
  758. file->head = file->wblock;
  759. file->windex = 0;
  760. } else if (woff == 0) {
  761. int err = lfs_alloc_erased(lfs, &file->wblock);
  762. if (err) {
  763. return err;
  764. }
  765. err = lfs_index_append(lfs, &file->head,
  766. &file->windex, file->wblock);
  767. if (err) {
  768. return err;
  769. }
  770. }
  771. lfs_size_t diff = lfs_min(nsize, lfs->block_size - woff);
  772. int err = lfs_bd_prog(lfs, file->wblock, woff, diff, data);
  773. if (err) {
  774. return err;
  775. }
  776. file->size += diff;
  777. data += diff;
  778. nsize -= diff;
  779. }
  780. return size;
  781. }
  782. lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
  783. void *buffer, lfs_size_t size) {
  784. uint8_t *data = buffer;
  785. lfs_size_t nsize = size;
  786. while (nsize > 0 && file->roff < file->size) {
  787. lfs_off_t roff = file->roff % lfs->block_size;
  788. // TODO cache index blocks
  789. if (file->size < lfs->block_size) {
  790. file->rblock = file->head;
  791. } else if (roff == 0) {
  792. int err = lfs_index_find(lfs, file->head, file->windex,
  793. file->rindex, &file->rblock);
  794. if (err) {
  795. return err;
  796. }
  797. file->rindex = lfs_indexnext(lfs, file->rindex);
  798. }
  799. lfs_size_t diff = lfs_min(
  800. lfs_min(nsize, file->size-file->roff),
  801. lfs->block_size - roff);
  802. int err = lfs_bd_read(lfs, file->rblock, roff, diff, data);
  803. if (err) {
  804. return err;
  805. }
  806. file->roff += diff;
  807. data += diff;
  808. nsize -= diff;
  809. }
  810. return size - nsize;
  811. }
  812. /// Generic filesystem operations ///
  813. static int lfs_configure(lfs_t *lfs, const struct lfs_config *config) {
  814. lfs->bd = config->bd;
  815. lfs->bd_ops = config->bd_ops;
  816. struct lfs_bd_info info;
  817. int err = lfs_bd_info(lfs, &info);
  818. if (err) {
  819. return err;
  820. }
  821. if (config->read_size) {
  822. if (config->read_size < info.read_size ||
  823. config->read_size % info.read_size != 0) {
  824. LFS_ERROR("Invalid read size %u, device has %u\n",
  825. config->read_size, info.read_size);
  826. return LFS_ERROR_INVALID;
  827. }
  828. lfs->read_size = config->read_size;
  829. } else {
  830. lfs->read_size = info.read_size;
  831. }
  832. if (config->prog_size) {
  833. if (config->prog_size < info.prog_size ||
  834. config->prog_size % info.prog_size != 0) {
  835. LFS_ERROR("Invalid prog size %u, device has %u\n",
  836. config->prog_size, info.prog_size);
  837. return LFS_ERROR_INVALID;
  838. }
  839. lfs->prog_size = config->prog_size;
  840. } else {
  841. lfs->prog_size = info.prog_size;
  842. }
  843. if (config->block_size) {
  844. if (config->block_size < info.erase_size ||
  845. config->block_size % info.erase_size != 0) {
  846. LFS_ERROR("Invalid block size %u, device has %u\n",
  847. config->prog_size, info.prog_size);
  848. return LFS_ERROR_INVALID;
  849. }
  850. lfs->block_size = config->block_size;
  851. } else {
  852. lfs->block_size = lfs_min(512, info.erase_size);
  853. }
  854. if (config->block_count) {
  855. if (config->block_count > info.total_size/info.erase_size) {
  856. LFS_ERROR("Invalid block size %u, device has %u\n",
  857. config->block_size,
  858. (uint32_t)(info.total_size/info.erase_size));
  859. return LFS_ERROR_INVALID;
  860. }
  861. lfs->block_count = config->block_count;
  862. } else {
  863. lfs->block_count = info.total_size / info.erase_size;
  864. }
  865. lfs->words = lfs->block_size / sizeof(uint32_t);
  866. return 0;
  867. }
  868. int lfs_format(lfs_t *lfs, const struct lfs_config *config) {
  869. int err = lfs_configure(lfs, config);
  870. if (err) {
  871. return err;
  872. }
  873. // Create free list
  874. lfs->free.begin = 2;
  875. lfs->free.end = lfs->block_count-1;
  876. // Write root directory
  877. lfs_dir_t root;
  878. err = lfs_dir_alloc(lfs, &root,
  879. (lfs_block_t[2]){0, 0}, (lfs_block_t[2]){0, 0});
  880. if (err) {
  881. return err;
  882. }
  883. lfs->root[0] = root.pair[0];
  884. lfs->root[1] = root.pair[1];
  885. lfs->cwd[0] = root.pair[0];
  886. lfs->cwd[1] = root.pair[1];
  887. // Write superblocks
  888. lfs_superblock_t superblock = {
  889. .pair = {0, 1},
  890. .d.rev = 1,
  891. .d.size = sizeof(superblock),
  892. .d.root = {lfs->cwd[0], lfs->cwd[1]},
  893. .d.magic = {"littlefs"},
  894. .d.block_size = lfs->block_size,
  895. .d.block_count = lfs->block_count,
  896. };
  897. for (int i = 0; i < 2; i++) {
  898. int err = lfs_pair_commit(lfs, superblock.pair,
  899. 1, (struct lfs_commit_region[]){
  900. {0, sizeof(superblock.d), &superblock.d}
  901. });
  902. if (err) {
  903. LFS_ERROR("Failed to write superblock at %d", superblock.pair[1]);
  904. return err;
  905. }
  906. uint32_t crc = 0xffffffff;
  907. err = lfs_bd_crc(lfs, superblock.pair[0], 0, lfs->block_size, &crc);
  908. if (err || crc != 0) {
  909. LFS_ERROR("Failed to write superblock at %d", superblock.pair[0]);
  910. return err ? err : LFS_ERROR_CORRUPT;
  911. }
  912. }
  913. return 0;
  914. }
  915. int lfs_mount(lfs_t *lfs, const struct lfs_config *config) {
  916. int err = lfs_configure(lfs, config);
  917. if (err) {
  918. return err;
  919. }
  920. lfs_superblock_t superblock = {
  921. .pair = {0, 1},
  922. };
  923. err = lfs_pair_fetch(lfs, superblock.pair,
  924. 1, (struct lfs_fetch_region[]){
  925. {0, sizeof(superblock.d), &superblock.d}
  926. });
  927. if ((err == LFS_ERROR_CORRUPT ||
  928. memcmp(superblock.d.magic, "littlefs", 8) != 0)) {
  929. LFS_ERROR("Invalid superblock at %d %d",
  930. superblock.pair[0], superblock.pair[1]);
  931. return LFS_ERROR_CORRUPT;
  932. }
  933. lfs->root[0] = superblock.d.root[0];
  934. lfs->root[1] = superblock.d.root[1];
  935. lfs->cwd[0] = superblock.d.root[0];
  936. lfs->cwd[1] = superblock.d.root[1];
  937. return err;
  938. }
  939. int lfs_unmount(lfs_t *lfs) {
  940. // Do nothing for now
  941. return 0;
  942. }
  943. int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
  944. // iterate over metadata pairs
  945. lfs_dir_t dir;
  946. lfs_file_t file;
  947. lfs_block_t cwd[2] = {0, 1};
  948. while (true) {
  949. for (int i = 0; i < 2; i++) {
  950. int err = cb(data, cwd[i]);
  951. if (err) {
  952. return err;
  953. }
  954. }
  955. int err = lfs_dir_fetch(lfs, &dir, cwd);
  956. if (err) {
  957. return err;
  958. }
  959. // skip '.' and '..'
  960. dir.off += 2*sizeof(struct lfs_disk_entry) + 3;
  961. // iterate over contents
  962. while ((0x7fffffff & dir.d.size) >= dir.off + sizeof(file.entry.d)) {
  963. int err = lfs_bd_read(lfs, dir.pair[0], dir.off,
  964. sizeof(file.entry.d), &file.entry.d);
  965. if (err) {
  966. return err;
  967. }
  968. dir.off += file.entry.d.len;
  969. if ((0xf & file.entry.d.type) == LFS_TYPE_REG) {
  970. if (file.entry.d.u.file.size < lfs->block_size) {
  971. int err = cb(data, file.entry.d.u.file.head);
  972. if (err) {
  973. return err;
  974. }
  975. } else {
  976. int err = lfs_index_traverse(lfs,
  977. file.entry.d.u.file.head,
  978. lfs_indexfrom(lfs, file.entry.d.u.file.size),
  979. cb, data);
  980. if (err) {
  981. return err;
  982. }
  983. }
  984. }
  985. }
  986. cwd[0] = dir.d.tail[0];
  987. cwd[1] = dir.d.tail[1];
  988. if (!cwd[0]) {
  989. return 0;
  990. }
  991. }
  992. }
  993. static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2]) {
  994. // iterate over all directory directory entries
  995. lfs_dir_t parent = {
  996. .d.tail[0] = lfs->root[0],
  997. .d.tail[1] = lfs->root[1],
  998. };
  999. while (parent.d.tail[0]) {
  1000. lfs_entry_t entry;
  1001. int err = lfs_dir_fetch(lfs, &parent, parent.d.tail);
  1002. if (err) {
  1003. return err;
  1004. }
  1005. // skip .. and . entries
  1006. for (int i = 0; i < 2; i++) {
  1007. int err = lfs_dir_next(lfs, &parent, &entry);
  1008. if (err) {
  1009. return err;
  1010. }
  1011. }
  1012. while (true) {
  1013. int err = lfs_dir_next(lfs, &parent, &entry);
  1014. if (err && err != LFS_ERROR_NO_ENTRY) {
  1015. return err;
  1016. }
  1017. if (err == LFS_ERROR_NO_ENTRY) {
  1018. break;
  1019. }
  1020. if ((0xf & entry.d.type) == LFS_TYPE_DIR &&
  1021. lfs_paircmp(entry.d.u.dir, dir) == 0) {
  1022. return true;
  1023. }
  1024. }
  1025. }
  1026. return false;
  1027. }
  1028. int lfs_deorphan(lfs_t *lfs) {
  1029. // iterate over all directories
  1030. lfs_dir_t pdir;
  1031. lfs_dir_t cdir;
  1032. // skip root
  1033. int err = lfs_dir_fetch(lfs, &pdir, lfs->root);
  1034. if (err) {
  1035. return err;
  1036. }
  1037. while (pdir.d.tail[0]) {
  1038. int err = lfs_dir_fetch(lfs, &cdir, pdir.d.tail);
  1039. if (err) {
  1040. return err;
  1041. }
  1042. // check if we have a parent
  1043. int parent = lfs_parent(lfs, pdir.d.tail);
  1044. if (parent < 0) {
  1045. return parent;
  1046. }
  1047. if (!parent) {
  1048. // we are an orphan
  1049. LFS_INFO("Found orphan %d %d", pdir.d.tail[0], pdir.d.tail[1]);
  1050. pdir.d.tail[0] = cdir.d.tail[0];
  1051. pdir.d.tail[1] = cdir.d.tail[1];
  1052. pdir.d.rev += 1;
  1053. err = lfs_pair_commit(lfs, pdir.pair,
  1054. 1, (struct lfs_commit_region[]) {
  1055. {0, sizeof(pdir.d), &pdir.d},
  1056. });
  1057. if (err) {
  1058. return err;
  1059. }
  1060. break;
  1061. }
  1062. memcpy(&pdir, &cdir, sizeof(pdir));
  1063. }
  1064. return 0;
  1065. }
  1066. int lfs_remove(lfs_t *lfs, const char *path) {
  1067. lfs_dir_t cwd;
  1068. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  1069. if (err) {
  1070. return err;
  1071. }
  1072. lfs_entry_t entry;
  1073. err = lfs_dir_find(lfs, &cwd, &path, &entry);
  1074. if (err) {
  1075. return err;
  1076. }
  1077. lfs_dir_t dir;
  1078. if (entry.d.type == LFS_TYPE_DIR) {
  1079. // must be empty before removal
  1080. int err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir);
  1081. if (err) {
  1082. return err;
  1083. } else if (dir.d.size != sizeof(dir.d) +
  1084. 2*sizeof(struct lfs_disk_entry) + 3) {
  1085. return LFS_ERROR_INVALID;
  1086. }
  1087. }
  1088. cwd.d.rev += 1;
  1089. cwd.d.size -= entry.d.len;
  1090. // either shift out the one entry or remove the whole dir block
  1091. if (cwd.d.size == sizeof(dir.d)) {
  1092. lfs_dir_t pdir;
  1093. int err = lfs_dir_fetch(lfs, &pdir, lfs->cwd);
  1094. if (err) {
  1095. return err;
  1096. }
  1097. while (lfs_paircmp(pdir.d.tail, cwd.pair) != 0) {
  1098. int err = lfs_dir_fetch(lfs, &pdir, pdir.d.tail);
  1099. if (err) {
  1100. return err;
  1101. }
  1102. }
  1103. pdir.d.tail[0] = cwd.d.tail[0];
  1104. pdir.d.tail[1] = cwd.d.tail[1];
  1105. pdir.d.rev += 1;
  1106. err = lfs_pair_commit(lfs, pdir.pair,
  1107. 1, (struct lfs_commit_region[]) {
  1108. {0, sizeof(pdir.d), &pdir.d},
  1109. });
  1110. if (err) {
  1111. return err;
  1112. }
  1113. } else {
  1114. int err = lfs_pair_shift(lfs, entry.dir,
  1115. 1, (struct lfs_commit_region[]) {
  1116. {0, sizeof(cwd.d), &cwd.d},
  1117. },
  1118. entry.off, entry.d.len);
  1119. if (err) {
  1120. return err;
  1121. }
  1122. }
  1123. if (entry.d.type == LFS_TYPE_DIR) {
  1124. // remove ourselves from the dir list
  1125. // this may create an orphan, which must be deorphaned
  1126. lfs_dir_t pdir;
  1127. memcpy(&pdir, &cwd, sizeof(pdir));
  1128. while (pdir.d.tail[0]) {
  1129. if (lfs_paircmp(pdir.d.tail, entry.d.u.dir) == 0) {
  1130. pdir.d.tail[0] = dir.d.tail[0];
  1131. pdir.d.tail[1] = dir.d.tail[1];
  1132. pdir.d.rev += 1;
  1133. int err = lfs_pair_commit(lfs, pdir.pair,
  1134. 1, (struct lfs_commit_region[]) {
  1135. {0, sizeof(pdir.d), &pdir.d},
  1136. });
  1137. if (err) {
  1138. return err;
  1139. }
  1140. break;
  1141. }
  1142. int err = lfs_dir_fetch(lfs, &pdir, pdir.d.tail);
  1143. if (err) {
  1144. return err;
  1145. }
  1146. }
  1147. }
  1148. return 0;
  1149. }
  1150. int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
  1151. lfs_dir_t cwd;
  1152. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  1153. if (err) {
  1154. return err;
  1155. }
  1156. lfs_entry_t entry;
  1157. err = lfs_dir_find(lfs, &cwd, &path, &entry);
  1158. if (err) {
  1159. return err;
  1160. }
  1161. // TODO abstract out info assignment
  1162. memset(info, 0, sizeof(*info));
  1163. info->type = entry.d.type & 0xff;
  1164. if (info->type == LFS_TYPE_REG) {
  1165. info->size = entry.d.u.file.size;
  1166. }
  1167. err = lfs_bd_read(lfs, entry.dir[0], entry.off + sizeof(entry.d),
  1168. entry.d.len - sizeof(entry.d), info->name);
  1169. if (err) {
  1170. return err;
  1171. }
  1172. return 0;
  1173. }