lfs.c 20 KB

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