lfs.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  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 <string.h>
  9. #include <stdbool.h>
  10. static int lfs_diff(uint32_t a, uint32_t b) {
  11. return (int)(unsigned)(a - b);
  12. }
  13. static uint32_t lfs_crc(const uint8_t *data, lfs_size_t size, uint32_t crc) {
  14. static const uint32_t rtable[16] = {
  15. 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
  16. 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
  17. 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
  18. 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
  19. };
  20. for (lfs_size_t i = 0; i < size; i++) {
  21. crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf];
  22. crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf];
  23. }
  24. return crc;
  25. }
  26. static lfs_error_t lfs_bd_cmp(lfs_t *lfs,
  27. lfs_ino_t ino, lfs_off_t off, lfs_size_t size, const void *d) {
  28. const uint8_t *data = d;
  29. for (int i = 0; i < size; i++) {
  30. uint8_t c;
  31. int err = lfs->ops->read(lfs->bd, (void*)&c, ino, off + i, 1);
  32. if (err) {
  33. return err;
  34. }
  35. if (c != data[i]) {
  36. return false;
  37. }
  38. }
  39. return true;
  40. }
  41. static lfs_error_t lfs_alloc(lfs_t *lfs, lfs_ino_t *ino);
  42. static lfs_error_t lfs_free(lfs_t *lfs, lfs_ino_t ino);
  43. // Next index offset
  44. static lfs_off_t lfs_inext(lfs_t *lfs, lfs_off_t ioff) {
  45. ioff += 1;
  46. lfs_size_t wcount = lfs->info.erase_size/4;
  47. while (ioff % wcount == 0) {
  48. ioff += lfs_min(lfs_ctz(ioff/wcount + 1), wcount-1) + 1;
  49. }
  50. return ioff;
  51. }
  52. static lfs_off_t lfs_toindex(lfs_t *lfs, lfs_off_t off) {
  53. lfs_off_t i = 0;
  54. while (off > 512) {
  55. i = lfs_inext(lfs, i);
  56. off -= 512;
  57. }
  58. return i;
  59. }
  60. // Find index in index chain given its index offset
  61. static lfs_error_t lfs_ifind_block(lfs_t *lfs, lfs_ino_t head,
  62. lfs_size_t icount, lfs_off_t ioff, lfs_ino_t *block) {
  63. lfs_size_t wcount = lfs->info.erase_size/4;
  64. lfs_off_t iitarget = ioff / wcount;
  65. lfs_off_t iicurrent = (icount-1) / wcount;
  66. while (iitarget != iicurrent) {
  67. lfs_size_t skip = lfs_min(
  68. lfs_min(lfs_ctz(iicurrent+1), wcount-1),
  69. lfs_npw2((iitarget ^ iicurrent)+1)-1);
  70. lfs_error_t err = lfs->ops->read(lfs->bd, (void*)&head,
  71. head, 4*skip, 4);
  72. if (err) {
  73. return err;
  74. }
  75. iicurrent -= 1 << skip;
  76. }
  77. *block = head;
  78. return 0;
  79. }
  80. static lfs_error_t lfs_ifind(lfs_t *lfs, lfs_ino_t head,
  81. lfs_size_t icount, lfs_off_t ioff, lfs_ino_t *ino) {
  82. lfs_size_t wcount = lfs->info.erase_size/4;
  83. int err = lfs_ifind_block(lfs, head, icount, ioff, &head);
  84. if (err) {
  85. return err;
  86. }
  87. return lfs->ops->read(lfs->bd, (void*)ino, head, 4*(ioff % wcount), 4);
  88. }
  89. // Append index to index chain, updates head and icount
  90. static lfs_error_t lfs_iappend(lfs_t *lfs, lfs_ino_t *headp,
  91. lfs_size_t *icountp, lfs_ino_t ino) {
  92. lfs_ino_t head = *headp;
  93. lfs_size_t ioff = *icountp - 1;
  94. lfs_size_t wcount = lfs->info.erase_size/4;
  95. ioff += 1;
  96. while (ioff % wcount == 0) {
  97. lfs_ino_t nhead;
  98. lfs_error_t err = lfs_alloc(lfs, &nhead);
  99. if (err) {
  100. return err;
  101. }
  102. lfs_off_t skips = lfs_min(lfs_ctz(ioff/wcount + 1), wcount-2) + 1;
  103. for (lfs_off_t i = 0; i < skips; i++) {
  104. err = lfs->ops->write(lfs->bd, (void*)&head, nhead, 4*i, 4);
  105. if (err) {
  106. return err;
  107. }
  108. if (head && i != skips-1) {
  109. err = lfs->ops->read(lfs->bd, (void*)&head, head, 4*i, 4);
  110. if (err) {
  111. return err;
  112. }
  113. }
  114. }
  115. ioff += skips;
  116. head = nhead;
  117. }
  118. lfs_error_t err = lfs->ops->write(lfs->bd, (void*)&ino,
  119. head, 4*(ioff % wcount), 4);
  120. if (err) {
  121. return err;
  122. }
  123. *headp = head;
  124. *icountp = ioff + 1;
  125. return 0;
  126. }
  127. // Memory managment
  128. static lfs_error_t lfs_alloc(lfs_t *lfs, lfs_ino_t *ino) {
  129. // TODO save slot for freeing?
  130. lfs_error_t err = lfs_ifind(lfs, lfs->free.d.head,
  131. lfs->free.end, lfs->free.off, ino);
  132. if (err) {
  133. return err;
  134. }
  135. lfs->free.off = lfs_inext(lfs, lfs->free.off);
  136. return lfs->ops->erase(lfs->bd, *ino, 0, lfs->info.erase_size);
  137. }
  138. static lfs_error_t lfs_free(lfs_t *lfs, lfs_ino_t ino) {
  139. return lfs_iappend(lfs, &lfs->free.d.head, &lfs->free.end, ino);
  140. }
  141. static lfs_error_t lfs_free_flush(lfs_t *lfs) {
  142. lfs_size_t wcount = lfs->info.erase_size/4;
  143. for (lfs_word_t i = lfs->free.begin / wcount;
  144. i + wcount < lfs->free.off; i += wcount) {
  145. lfs_ino_t block;
  146. int err = lfs_ifind_block(lfs, lfs->free.d.head,
  147. lfs->free.end, i, &block);
  148. if (err) {
  149. return err;
  150. }
  151. lfs_free(lfs, block);
  152. }
  153. if (lfs->free.off != lfs->free.d.off || lfs->free.end != lfs->free.d.end) {
  154. // TODO handle overflow?
  155. lfs->free.d.rev += 1;
  156. }
  157. lfs->free.d.off = lfs->free.off;
  158. lfs->free.d.end = lfs->free.end;
  159. return 0;
  160. }
  161. lfs_error_t lfs_check(lfs_t *lfs, lfs_ino_t block) {
  162. uint32_t crc = 0xffffffff;
  163. for (lfs_size_t i = 0; i < lfs->info.erase_size; i += 4) {
  164. uint32_t data;
  165. int err = lfs->ops->read(lfs->bd, (void*)&data, block, i, 4);
  166. if (err) {
  167. return err;
  168. }
  169. crc = lfs_crc((void*)&data, 4, crc);
  170. }
  171. return (crc != 0) ? LFS_ERROR_CORRUPT : LFS_ERROR_OK;
  172. }
  173. struct lfs_fetch_region {
  174. lfs_off_t off;
  175. lfs_size_t size;
  176. void *data;
  177. };
  178. lfs_error_t lfs_pair_fetch(lfs_t *lfs, lfs_ino_t pair[2],
  179. int count, const struct lfs_fetch_region *regions) {
  180. int checked = 0;
  181. int rev = 0;
  182. for (int i = 0; i < 2; i++) {
  183. uint32_t nrev;
  184. int err = lfs->ops->read(lfs->bd, (void*)&nrev,
  185. pair[0], 0, 4);
  186. if (err) {
  187. return err;
  188. }
  189. // TODO diff these
  190. if (checked > 0 && lfs_diff(nrev, rev) < 0) {
  191. continue;
  192. }
  193. err = lfs_check(lfs, pair[0]);
  194. if (err == LFS_ERROR_CORRUPT) {
  195. lfs_swap(&pair[0], &pair[1]);
  196. continue;
  197. } else if (err) {
  198. return err;
  199. }
  200. checked += 1;
  201. rev = nrev;
  202. lfs_swap(&pair[0], &pair[1]);
  203. }
  204. if (checked == 0) {
  205. return LFS_ERROR_CORRUPT;
  206. }
  207. for (int i = 0; i < count; i++) {
  208. int err = lfs->ops->read(lfs->bd, regions[i].data,
  209. pair[1], regions[i].off, regions[i].size);
  210. if (err) {
  211. return err;
  212. }
  213. }
  214. return 0;
  215. }
  216. struct lfs_commit_region {
  217. lfs_off_t off;
  218. lfs_size_t size;
  219. const void *data;
  220. };
  221. lfs_error_t lfs_pair_commit(lfs_t *lfs, lfs_ino_t pair[2],
  222. int count, const struct lfs_commit_region *regions) {
  223. uint32_t crc = 0xffffffff;
  224. int err = lfs->ops->erase(lfs->bd,
  225. pair[0], 0, lfs->info.erase_size);
  226. if (err) {
  227. return err;
  228. }
  229. lfs_off_t off = 0;
  230. while (off < lfs->info.erase_size - 4) {
  231. if (count > 0 && regions[0].off == off) {
  232. crc = lfs_crc(regions[0].data, regions[0].size, crc);
  233. int err = lfs->ops->write(lfs->bd, regions[0].data,
  234. pair[0], off, regions[0].size);
  235. if (err) {
  236. return err;
  237. }
  238. off += regions[0].size;
  239. count -= 1;
  240. regions += 1;
  241. } else {
  242. // TODO faster strides?
  243. uint8_t data;
  244. int err = lfs->ops->read(lfs->bd, (void*)&data,
  245. pair[1], off, sizeof(data));
  246. if (err) {
  247. return err;
  248. }
  249. crc = lfs_crc((void*)&data, sizeof(data), crc);
  250. err = lfs->ops->write(lfs->bd, (void*)&data,
  251. pair[0], off, sizeof(data));
  252. if (err) {
  253. return err;
  254. }
  255. off += sizeof(data);
  256. }
  257. }
  258. err = lfs->ops->write(lfs->bd, (void*)&crc,
  259. pair[0], lfs->info.erase_size-4, 4);
  260. if (err) {
  261. return err;
  262. }
  263. lfs_swap(&pair[0], &pair[1]);
  264. return 0;
  265. }
  266. lfs_error_t lfs_dir_make(lfs_t *lfs, lfs_dir_t *dir, lfs_ino_t parent[2]) {
  267. // Allocate pair of dir blocks
  268. for (int i = 0; i < 2; i++) {
  269. int err = lfs_alloc(lfs, &dir->pair[i]);
  270. if (err) {
  271. return err;
  272. }
  273. }
  274. // Rather than clobbering one of the blocks we just pretend
  275. // the revision may be valid
  276. int err = lfs->ops->read(lfs->bd, (void*)&dir->d.rev, dir->pair[1], 0, 4);
  277. if (err) {
  278. return err;
  279. }
  280. dir->d.rev += 1;
  281. // Other defaults
  282. dir->i = sizeof(struct lfs_disk_dir);
  283. dir->d.size = sizeof(struct lfs_disk_dir);
  284. dir->d.tail[0] = 0;
  285. dir->d.tail[1] = 0;
  286. lfs_free_flush(lfs);
  287. dir->d.free = lfs->free.d;
  288. if (parent) {
  289. // Create '..' entry
  290. lfs_entry_t entry = {
  291. .d.type = LFS_TYPE_DIR,
  292. .d.len = sizeof(entry.d) + 2,
  293. .d.u.dir[0] = parent[0],
  294. .d.u.dir[1] = parent[1],
  295. };
  296. dir->d.size += entry.d.len;
  297. // Write out to memory
  298. return lfs_pair_commit(lfs, dir->pair,
  299. 3, (struct lfs_commit_region[3]){
  300. {0, sizeof(dir->d), &dir->d},
  301. {sizeof(dir->d), sizeof(entry.d), &entry.d},
  302. {sizeof(dir->d)+sizeof(entry.d), 2, ".."},
  303. });
  304. } else {
  305. return lfs_pair_commit(lfs, dir->pair,
  306. 1, (struct lfs_commit_region[1]){
  307. {0, sizeof(dir->d), &dir->d},
  308. });
  309. }
  310. }
  311. lfs_error_t lfs_dir_fetch(lfs_t *lfs, lfs_dir_t *dir, lfs_ino_t pair[2]) {
  312. dir->pair[0] = pair[0];
  313. dir->pair[1] = pair[1];
  314. dir->i = sizeof(dir->d);
  315. int err = lfs_pair_fetch(lfs, dir->pair,
  316. 1, (struct lfs_fetch_region[1]) {
  317. {0, sizeof(dir->d), &dir->d}
  318. });
  319. if (err == LFS_ERROR_CORRUPT) {
  320. LFS_ERROR("Corrupted dir at %d %d", pair[0], pair[1]);
  321. }
  322. return err;
  323. }
  324. lfs_error_t lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
  325. while (true) {
  326. // TODO iterate down list
  327. entry->dir[0] = dir->pair[0];
  328. entry->dir[1] = dir->pair[1];
  329. entry->off = dir->i;
  330. if (dir->d.size - dir->i < sizeof(entry->d)) {
  331. return LFS_ERROR_NO_ENTRY;
  332. }
  333. int err = lfs->ops->read(lfs->bd, (void*)&entry->d,
  334. dir->pair[1], dir->i, sizeof(entry->d));
  335. if (err) {
  336. return err;
  337. }
  338. dir->i += entry->d.len;
  339. // Skip any unknown entries
  340. if (entry->d.type == 1 || entry->d.type == 2) {
  341. return 0;
  342. }
  343. }
  344. }
  345. lfs_error_t lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
  346. const char *path, lfs_entry_t *entry) {
  347. // TODO follow directories
  348. lfs_size_t pathlen = strcspn(path, "/");
  349. while (true) {
  350. int err = lfs_dir_next(lfs, dir, entry);
  351. if (err) {
  352. return err;
  353. }
  354. if (entry->d.len - sizeof(entry->d) != pathlen) {
  355. continue;
  356. }
  357. int ret = lfs_bd_cmp(lfs, entry->dir[1],
  358. entry->off + sizeof(entry->d), pathlen, path);
  359. if (ret < 0) {
  360. return ret;
  361. }
  362. // Found match
  363. if (ret == true) {
  364. return 0;
  365. }
  366. }
  367. }
  368. lfs_error_t lfs_dir_alloc(lfs_t *lfs, lfs_dir_t *dir,
  369. const char *path, lfs_entry_t *entry, uint16_t len) {
  370. int err = lfs_dir_find(lfs, dir, path, entry);
  371. if (err != LFS_ERROR_NO_ENTRY) {
  372. return err ? err : LFS_ERROR_EXISTS;
  373. }
  374. // Check if we fit
  375. if (dir->d.size + len > lfs->info.erase_size - 4) {
  376. return -1; // TODO make fit
  377. }
  378. return 0;
  379. }
  380. lfs_error_t lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
  381. int err = lfs_dir_fetch(lfs, dir, lfs->cwd);
  382. if (err) {
  383. return err;
  384. }
  385. lfs_entry_t entry;
  386. err = lfs_dir_find(lfs, dir, path, &entry);
  387. if (err) {
  388. return err;
  389. } else if (entry.d.type != LFS_TYPE_DIR) {
  390. return LFS_ERROR_NOT_DIR;
  391. }
  392. return lfs_dir_fetch(lfs, dir, entry.d.u.dir);
  393. }
  394. lfs_error_t lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
  395. // Do nothing, dir is always synchronized
  396. return 0;
  397. }
  398. lfs_error_t lfs_mkdir(lfs_t *lfs, const char *path) {
  399. // Allocate entry for directory
  400. lfs_dir_t cwd;
  401. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  402. if (err) {
  403. return err;
  404. }
  405. lfs_entry_t entry;
  406. err = lfs_dir_alloc(lfs, &cwd, path,
  407. &entry, sizeof(entry.d)+strlen(path));
  408. if (err) {
  409. return err;
  410. }
  411. // Build up new directory
  412. lfs_dir_t dir;
  413. err = lfs_dir_make(lfs, &dir, cwd.pair); // TODO correct parent?
  414. if (err) {
  415. return err;
  416. }
  417. entry.d.type = 2;
  418. entry.d.len = sizeof(entry.d) + strlen(path);
  419. entry.d.u.dir[0] = dir.pair[0];
  420. entry.d.u.dir[1] = dir.pair[1];
  421. cwd.d.rev += 1;
  422. cwd.d.size += entry.d.len;
  423. lfs_free_flush(lfs);
  424. cwd.d.free = lfs->free.d;
  425. return lfs_pair_commit(lfs, entry.dir,
  426. 3, (struct lfs_commit_region[3]) {
  427. {0, sizeof(cwd.d), &cwd.d},
  428. {entry.off, sizeof(entry.d), &entry.d},
  429. {entry.off+sizeof(entry.d), entry.d.len - sizeof(entry.d), path}
  430. });
  431. }
  432. lfs_error_t lfs_file_open(lfs_t *lfs, lfs_file_t *file,
  433. const char *path, int flags) {
  434. // Allocate entry for file if it doesn't exist
  435. // TODO check open files
  436. lfs_dir_t cwd;
  437. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  438. if (err) {
  439. return err;
  440. }
  441. if (flags & LFS_O_CREAT) {
  442. err = lfs_dir_alloc(lfs, &cwd, path,
  443. &file->entry, sizeof(file->entry.d)+strlen(path));
  444. if (err && err != LFS_ERROR_EXISTS) {
  445. return err;
  446. }
  447. } else {
  448. err = lfs_dir_find(lfs, &cwd, path, &file->entry);
  449. if (err) {
  450. return err;
  451. }
  452. }
  453. if ((flags & LFS_O_CREAT) && err != LFS_ERROR_EXISTS) {
  454. // Store file
  455. file->head = 0;
  456. file->size = 0;
  457. file->wblock = 0;
  458. file->windex = 0;
  459. file->rblock = 0;
  460. file->rindex = 0;
  461. file->roff = 0;
  462. file->entry.d.type = 1;
  463. file->entry.d.len = sizeof(file->entry.d) + strlen(path);
  464. file->entry.d.u.file.head = file->head;
  465. file->entry.d.u.file.size = file->size;
  466. cwd.d.rev += 1;
  467. cwd.d.size += file->entry.d.len;
  468. lfs_free_flush(lfs);
  469. cwd.d.free = lfs->free.d;
  470. return lfs_pair_commit(lfs, file->entry.dir,
  471. 3, (struct lfs_commit_region[3]) {
  472. {0, sizeof(cwd.d), &cwd.d},
  473. {file->entry.off, sizeof(file->entry.d),
  474. &file->entry.d},
  475. {file->entry.off+sizeof(file->entry.d),
  476. file->entry.d.len-sizeof(file->entry.d), path}
  477. });
  478. } else {
  479. file->head = file->entry.d.u.file.head;
  480. file->size = file->entry.d.u.file.size;
  481. file->windex = lfs_toindex(lfs, file->size);
  482. file->rblock = 0;
  483. file->rindex = 0;
  484. file->roff = 0;
  485. // TODO do this lazily in write?
  486. // TODO cow the head i/d block
  487. if (file->size < lfs->info.erase_size) {
  488. file->wblock = file->head;
  489. } else {
  490. int err = lfs_ifind(lfs, file->head, file->windex,
  491. file->windex, &file->wblock);
  492. if (err) {
  493. return err;
  494. }
  495. }
  496. return 0;
  497. }
  498. }
  499. lfs_error_t lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
  500. // Store file
  501. lfs_dir_t cwd;
  502. int err = lfs_dir_fetch(lfs, &cwd, file->entry.dir);
  503. if (err) {
  504. return err;
  505. }
  506. file->entry.d.u.file.head = file->head;
  507. file->entry.d.u.file.size = file->size;
  508. cwd.d.rev += 1;
  509. lfs_free_flush(lfs);
  510. cwd.d.free = lfs->free.d;
  511. return lfs_pair_commit(lfs, file->entry.dir,
  512. 3, (struct lfs_commit_region[3]) {
  513. {0, sizeof(cwd.d), &cwd.d},
  514. {file->entry.off, sizeof(file->entry.d), &file->entry.d},
  515. });
  516. }
  517. lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
  518. const void *buffer, lfs_size_t size) {
  519. const uint8_t *data = buffer;
  520. lfs_size_t nsize = size;
  521. while (nsize > 0) {
  522. lfs_off_t woff = file->size % lfs->info.erase_size;
  523. if (file->size == 0) {
  524. int err = lfs_alloc(lfs, &file->wblock);
  525. if (err) {
  526. return err;
  527. }
  528. file->head = file->wblock;
  529. file->windex = 0;
  530. } else if (woff == 0) {
  531. // TODO check that 2 blocks are available
  532. // TODO check for available blocks for backing up scratch files?
  533. int err = lfs_alloc(lfs, &file->wblock);
  534. if (err) {
  535. return err;
  536. }
  537. err = lfs_iappend(lfs, &file->head, &file->windex, file->wblock);
  538. if (err) {
  539. return err;
  540. }
  541. }
  542. lfs_size_t diff = lfs_min(nsize, lfs->info.erase_size - woff);
  543. int err = lfs->ops->write(lfs->bd, data, file->wblock, woff, diff);
  544. if (err) {
  545. return err;
  546. }
  547. file->size += diff;
  548. data += diff;
  549. nsize -= diff;
  550. }
  551. return size;
  552. }
  553. lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
  554. void *buffer, lfs_size_t size) {
  555. uint8_t *data = buffer;
  556. lfs_size_t nsize = size;
  557. while (nsize > 0 && file->roff < file->size) {
  558. lfs_off_t roff = file->roff % lfs->info.erase_size;
  559. // TODO cache index blocks
  560. if (file->size < lfs->info.erase_size) {
  561. file->rblock = file->head;
  562. } else if (roff == 0) {
  563. int err = lfs_ifind(lfs, file->head, file->windex,
  564. file->rindex, &file->rblock);
  565. if (err) {
  566. return err;
  567. }
  568. file->rindex = lfs_inext(lfs, file->rindex);
  569. }
  570. lfs_size_t diff = lfs_min(
  571. lfs_min(nsize, file->size-file->roff),
  572. lfs->info.erase_size - roff);
  573. int err = lfs->ops->read(lfs->bd, data, file->rblock, roff, diff);
  574. if (err) {
  575. return err;
  576. }
  577. file->roff += diff;
  578. data += diff;
  579. nsize -= diff;
  580. }
  581. return size - nsize;
  582. }
  583. // Little filesystem operations
  584. lfs_error_t lfs_create(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *ops) {
  585. lfs->bd = bd;
  586. lfs->ops = ops;
  587. lfs_error_t err = lfs->ops->info(lfs->bd, &lfs->info);
  588. if (err) {
  589. return err;
  590. }
  591. return 0;
  592. }
  593. lfs_error_t lfs_format(lfs_t *lfs) {
  594. struct lfs_bd_info info;
  595. lfs_error_t err = lfs->ops->info(lfs->bd, &info);
  596. if (err) {
  597. return err;
  598. }
  599. err = lfs->ops->erase(lfs->bd, 0, 0, 3*info.erase_size);
  600. if (err) {
  601. return err;
  602. }
  603. // TODO make sure that erase clobbered blocks
  604. { // Create free list
  605. lfs->free = (lfs_free_t){
  606. .begin = 1,
  607. .off = 1,
  608. .end = 1,
  609. .d.rev = 1,
  610. .d.head = 2,
  611. .d.off = 1,
  612. .d.end = 1,
  613. };
  614. lfs_size_t block_count = lfs->info.total_size / lfs->info.erase_size;
  615. for (lfs_ino_t i = 3; i < block_count; i++) {
  616. lfs_error_t err = lfs_free(lfs, i);
  617. if (err) {
  618. return err;
  619. }
  620. }
  621. }
  622. {
  623. // Write root directory
  624. lfs_dir_t root;
  625. int err = lfs_dir_make(lfs, &root, 0);
  626. if (err) {
  627. return err;
  628. }
  629. lfs->cwd[0] = root.pair[0];
  630. lfs->cwd[1] = root.pair[1];
  631. }
  632. {
  633. // Write superblocks
  634. lfs_superblock_t superblock = {
  635. .pair = {0, 1},
  636. .d.rev = 1,
  637. .d.size = sizeof(struct lfs_disk_superblock),
  638. .d.root = {lfs->cwd[0], lfs->cwd[1]},
  639. .d.magic = {"littlefs"},
  640. .d.block_size = info.erase_size,
  641. .d.block_count = info.total_size / info.erase_size,
  642. };
  643. for (int i = 0; i < 2; i++) {
  644. lfs_ino_t block = superblock.pair[0];
  645. int err = lfs_pair_commit(lfs, superblock.pair,
  646. 1, (struct lfs_commit_region[1]){
  647. {0, sizeof(superblock.d), &superblock.d}
  648. });
  649. err = lfs_check(lfs, block);
  650. if (err) {
  651. LFS_ERROR("Failed to write superblock at %d", block);
  652. return err;
  653. }
  654. }
  655. }
  656. return 0;
  657. }
  658. lfs_error_t lfs_mount(lfs_t *lfs) {
  659. struct lfs_bd_info info;
  660. lfs_error_t err = lfs->ops->info(lfs->bd, &info);
  661. if (err) {
  662. return err;
  663. }
  664. lfs_superblock_t superblock;
  665. err = lfs_pair_fetch(lfs,
  666. (lfs_ino_t[2]){0, 1},
  667. 1, (struct lfs_fetch_region[1]){
  668. {0, sizeof(superblock.d), &superblock.d}
  669. });
  670. if ((err == LFS_ERROR_CORRUPT ||
  671. memcmp(superblock.d.magic, "littlefs", 8) != 0)) {
  672. LFS_ERROR("Invalid superblock at %d %d\n", 0, 1);
  673. return LFS_ERROR_CORRUPT;
  674. }
  675. printf("superblock %d %d\n",
  676. superblock.d.block_size,
  677. superblock.d.block_count);
  678. lfs->cwd[0] = superblock.d.root[0];
  679. lfs->cwd[1] = superblock.d.root[1];
  680. return err;
  681. }