lfs.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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 uint32_t lfs_crc(const uint8_t *data, lfs_size_t size, uint32_t crc) {
  11. static const uint32_t rtable[16] = {
  12. 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
  13. 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
  14. 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
  15. 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c,
  16. };
  17. for (lfs_size_t i = 0; i < size; i++) {
  18. crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 0)) & 0xf];
  19. crc = (crc >> 4) ^ rtable[(crc ^ (data[i] >> 4)) & 0xf];
  20. }
  21. return crc;
  22. }
  23. static lfs_error_t lfs_alloc(lfs_t *lfs, lfs_ino_t *ino);
  24. static lfs_error_t lfs_free(lfs_t *lfs, lfs_ino_t ino);
  25. // Next index offset
  26. static lfs_off_t lfs_inext(lfs_t *lfs, lfs_off_t ioff) {
  27. ioff += 1;
  28. lfs_size_t wcount = lfs->info.erase_size/4;
  29. while (ioff % wcount == 0) {
  30. ioff += lfs_min(lfs_ctz(ioff/wcount + 1), wcount-1) + 1;
  31. }
  32. return ioff;
  33. }
  34. // Find index in index chain given its index offset
  35. static lfs_error_t lfs_ifind(lfs_t *lfs, lfs_ino_t head,
  36. lfs_size_t icount, lfs_off_t ioff, lfs_ino_t *ino) {
  37. lfs_size_t wcount = lfs->info.erase_size/4;
  38. lfs_off_t iitarget = ioff / wcount;
  39. lfs_off_t iicurrent = (icount-1) / wcount;
  40. while (iitarget != iicurrent) {
  41. lfs_size_t skip = lfs_min(
  42. lfs_min(lfs_ctz(iicurrent+1), wcount-1),
  43. lfs_npw2((iitarget ^ iicurrent)+1)-1);
  44. lfs_error_t err = lfs->ops->read(lfs->bd, (void*)&head,
  45. head, 4*skip, 4);
  46. if (err) {
  47. return err;
  48. }
  49. iicurrent -= 1 << skip;
  50. }
  51. return lfs->ops->read(lfs->bd, (void*)ino, head, 4*(ioff % wcount), 4);
  52. }
  53. // Append index to index chain, updates head and icount
  54. static lfs_error_t lfs_iappend(lfs_t *lfs, lfs_ino_t *headp,
  55. lfs_size_t *icountp, lfs_ino_t ino) {
  56. lfs_ino_t head = *headp;
  57. lfs_size_t ioff = *icountp - 1;
  58. lfs_size_t wcount = lfs->info.erase_size/4;
  59. ioff += 1;
  60. while (ioff % wcount == 0) {
  61. lfs_ino_t nhead;
  62. lfs_error_t err = lfs_alloc(lfs, &nhead);
  63. if (err) {
  64. return err;
  65. }
  66. lfs_off_t skips = lfs_min(lfs_ctz(ioff/wcount + 1), wcount-1) + 1;
  67. for (lfs_off_t i = 0; i < skips; i++) {
  68. err = lfs->ops->write(lfs->bd, (void*)&head, nhead, 4*i, 4);
  69. if (err) {
  70. return err;
  71. }
  72. if (head && i != skips-1) {
  73. err = lfs->ops->read(lfs->bd, (void*)&head, head, 4*i, 4);
  74. if (err) {
  75. return err;
  76. }
  77. }
  78. }
  79. ioff += skips;
  80. head = nhead;
  81. }
  82. lfs_error_t err = lfs->ops->write(lfs->bd, (void*)&ino,
  83. head, 4*(ioff % wcount), 4);
  84. if (err) {
  85. return err;
  86. }
  87. *headp = head;
  88. *icountp = ioff + 1;
  89. return 0;
  90. }
  91. // Memory managment
  92. static lfs_error_t lfs_alloc(lfs_t *lfs, lfs_ino_t *ino) {
  93. lfs_error_t err = lfs_ifind(lfs, lfs->free.head,
  94. lfs->free.icount, lfs->free.ioff, ino);
  95. if (err) {
  96. return err;
  97. }
  98. lfs->free.ioff = lfs_inext(lfs, lfs->free.ioff);
  99. return lfs->ops->erase(lfs->bd, *ino, 0, lfs->info.erase_size);
  100. }
  101. static lfs_error_t lfs_free(lfs_t *lfs, lfs_ino_t ino) {
  102. return lfs_iappend(lfs, &lfs->free.head, &lfs->free.icount, ino);
  103. }
  104. // Little filesystem operations
  105. lfs_error_t lfs_create(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *ops) {
  106. lfs->bd = bd;
  107. lfs->ops = ops;
  108. lfs_error_t err = lfs->ops->info(lfs->bd, &lfs->info);
  109. if (err) {
  110. return err;
  111. }
  112. return 0;
  113. }
  114. lfs_error_t lfs_format(lfs_t *lfs) {
  115. struct lfs_bd_info info;
  116. lfs_error_t err = lfs->ops->info(lfs->bd, &info);
  117. if (err) {
  118. return err;
  119. }
  120. err = lfs->ops->erase(lfs->bd, 0, 0, 5*info.erase_size);
  121. if (err) {
  122. return err;
  123. }
  124. // TODO make sure that erase clobbered blocks
  125. { // Create free list
  126. lfs->free.head = 4;
  127. lfs->free.ioff = 1;
  128. lfs->free.icount = 1;
  129. lfs->free.rev = 1;
  130. lfs_size_t block_count = lfs->info.total_size / lfs->info.erase_size;
  131. for (lfs_ino_t i = 5; i < block_count; i++) {
  132. lfs_error_t err = lfs_free(lfs, i);
  133. if (err) {
  134. return err;
  135. }
  136. }
  137. }
  138. {
  139. // Write root directory
  140. struct __attribute__((packed)) {
  141. lfs_word_t rev;
  142. lfs_size_t len;
  143. lfs_ino_t tail[2];
  144. struct lfs_free_list free;
  145. } header = {1, 0, {0, 0}, lfs->free};
  146. err = lfs->ops->write(lfs->bd, (void*)&header, 2, 0, sizeof(header));
  147. if (err) {
  148. return err;
  149. }
  150. uint32_t crc = lfs_crc((void*)&header, sizeof(header), 0xffffffff);
  151. for (lfs_size_t i = sizeof(header); i < info.erase_size-4; i += 4) {
  152. uint32_t data;
  153. err = lfs->ops->read(lfs->bd, (void*)&data, 2, i, 4);
  154. if (err) {
  155. return err;
  156. }
  157. crc = lfs_crc((void*)&data, 4, crc);
  158. }
  159. err = lfs->ops->write(lfs->bd, (void*)&crc, 2, info.erase_size-4, 4);
  160. if (err) {
  161. return err;
  162. }
  163. }
  164. {
  165. // Write superblock
  166. struct __attribute__((packed)) {
  167. lfs_word_t rev;
  168. lfs_word_t len;
  169. lfs_word_t tail[2];
  170. struct lfs_free_list free;
  171. char magic[4];
  172. struct lfs_bd_info info;
  173. } header = {1, 0, {2, 3}, {0}, {"lfs"}, info};
  174. err = lfs->ops->write(lfs->bd, (void*)&header, 0, 0, sizeof(header));
  175. if (err) {
  176. return err;
  177. }
  178. uint32_t crc = lfs_crc((void*)&header, sizeof(header), 0xffffffff);
  179. for (lfs_size_t i = sizeof(header); i < info.erase_size-4; i += 4) {
  180. uint32_t data;
  181. err = lfs->ops->read(lfs->bd, (void*)&data, 0, i, 4);
  182. if (err) {
  183. return err;
  184. }
  185. crc = lfs_crc((void*)&data, 4, crc);
  186. }
  187. err = lfs->ops->write(lfs->bd, (void*)&crc, 0, info.erase_size-4, 4);
  188. if (err) {
  189. return err;
  190. }
  191. }
  192. // Sanity check
  193. uint32_t crc = 0xffffffff;
  194. for (lfs_size_t i = 0; i < info.erase_size; i += 4) {
  195. uint32_t data;
  196. err = lfs->ops->read(lfs->bd, (void*)&data, 0, i, 4);
  197. if (err) {
  198. return err;
  199. }
  200. crc = lfs_crc((void*)&data, 4, crc);
  201. }
  202. uint32_t data;
  203. err = lfs->ops->read(lfs->bd, (void*)&data, 0, info.erase_size-4, 4);
  204. if (err) {
  205. return err;
  206. }
  207. return crc;
  208. }