lfs.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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. lfs_error_t lfs_create(lfs_t *lfs, lfs_bd_t *bd, const struct lfs_bd_ops *ops) {
  24. // TODO rm me, for debugging
  25. memset(lfs, 0, sizeof(lfs_t));
  26. lfs->bd = bd;
  27. lfs->ops = ops;
  28. lfs_error_t err = lfs->ops->info(lfs->bd, &lfs->info);
  29. if (err) {
  30. return err;
  31. }
  32. return 0;
  33. }
  34. static lfs_off_t lfs_calc_irem(lfs_t *lfs, lfs_size_t isize) {
  35. lfs_size_t icount = lfs->info.erase_size/4;
  36. if (isize <= icount) {
  37. return isize;
  38. } else {
  39. return ((isize-2) % (icount-1)) + 1;
  40. }
  41. }
  42. static lfs_off_t lfs_calc_ioff(lfs_t *lfs, lfs_size_t ioff) {
  43. lfs_size_t icount = lfs->info.erase_size/4;
  44. if (ioff < icount) {
  45. return ioff;
  46. } else {
  47. return ((ioff-1) % (icount-1)) + 1;
  48. }
  49. }
  50. static lfs_error_t lfs_ifind(lfs_t *lfs, lfs_ino_t head,
  51. lfs_size_t isize, lfs_off_t ioff, lfs_ino_t *ino) {
  52. if (ioff >= isize) {
  53. return -15;
  54. } else if (isize == 1) {
  55. *ino = head;
  56. return 0;
  57. }
  58. lfs_off_t ilookback = isize - ioff;
  59. lfs_off_t irealoff = lfs_calc_ioff(lfs, ioff);
  60. while (true) {
  61. lfs_size_t irem = lfs_calc_irem(lfs, isize);
  62. if (ilookback <= irem) {
  63. return lfs->ops->read(lfs->bd, (void*)ino,
  64. head, 4*irealoff, 4);
  65. }
  66. lfs_error_t err = lfs->ops->read(lfs->bd, (void*)&head, head, 0, 4);
  67. if (err) {
  68. return err;
  69. }
  70. ilookback -= irem;
  71. isize -= irem;
  72. }
  73. }
  74. static lfs_error_t lfs_alloc(lfs_t *lfs, lfs_ino_t *ino) {
  75. lfs_error_t err = lfs_ifind(lfs, lfs->free.head,
  76. lfs->free.rev[1], lfs->free.rev[0], ino);
  77. if (err) {
  78. return err;
  79. }
  80. err = lfs->ops->erase(lfs->bd, *ino, 0, lfs->info.erase_size);
  81. if (err) {
  82. return err;
  83. }
  84. lfs->free.rev[0] += 1;
  85. return 0;
  86. }
  87. static lfs_error_t lfs_free(lfs_t *lfs, lfs_ino_t ino) {
  88. // TODO handle overflow?
  89. if (lfs->free.rev[1] == 0) {
  90. lfs->free.head = ino;
  91. lfs->free.rev[1]++;
  92. lfs->free.off = lfs->info.erase_size;
  93. return 0;
  94. }
  95. if (lfs->free.off == lfs->info.erase_size || !lfs->free.head) {
  96. lfs_ino_t nhead = 0;
  97. lfs_error_t err = lfs_alloc(lfs, &nhead);
  98. if (err) {
  99. return err;
  100. }
  101. if (lfs->free.off == lfs->info.erase_size) {
  102. err = lfs->ops->write(lfs->bd, (void*)&lfs->free.head, nhead, 0, 4);
  103. if (err) {
  104. return err;
  105. }
  106. } else {
  107. for (lfs_off_t i = 0; i < lfs->free.off; i += 4) {
  108. lfs_ino_t ino;
  109. lfs_error_t err = lfs->ops->read(lfs->bd, (void*)&ino,
  110. lfs->free.phead, i, 4);
  111. if (err) {
  112. return err;
  113. }
  114. err = lfs->ops->write(lfs->bd, (void*)&ino,
  115. nhead, i, 4);
  116. if (err) {
  117. return err;
  118. }
  119. }
  120. }
  121. lfs->free.head = nhead;
  122. lfs->free.off = 4;
  123. }
  124. lfs_error_t err = lfs->ops->write(lfs->bd, (void*)&ino,
  125. lfs->free.head, lfs->free.off, 4);
  126. if (err) {
  127. return err;
  128. }
  129. lfs->free.off += 4;
  130. lfs->free.rev[1] += 1;
  131. return 0;
  132. }
  133. lfs_error_t lfs_format(lfs_t *lfs) {
  134. struct lfs_bd_info info;
  135. lfs_error_t err = lfs->ops->info(lfs->bd, &info);
  136. if (err) {
  137. return err;
  138. }
  139. err = lfs->ops->erase(lfs->bd, 0, 0, info.erase_size);
  140. if (err) {
  141. return err;
  142. }
  143. // TODO erase what could be misinterpreted (pairs of blocks)
  144. { // Create free list
  145. lfs->free.rev[0] = 0;
  146. lfs->free.rev[1] = 0;
  147. lfs->free.phead = 0;
  148. lfs->free.head = 0;
  149. lfs->free.off = 0;
  150. lfs_size_t block_count = lfs->info.total_size / lfs->info.erase_size;
  151. for (lfs_ino_t i = 4; i < block_count; i++) {
  152. lfs_error_t err = lfs_free(lfs, i);
  153. if (err) {
  154. return err;
  155. }
  156. }
  157. }
  158. {
  159. // Write root directory
  160. struct __attribute__((packed)) {
  161. lfs_word_t rev;
  162. lfs_size_t len;
  163. lfs_ino_t tail[2];
  164. lfs_word_t free_rev[2];
  165. lfs_ino_t free_ino;
  166. } header = {1, 0, {0, 0},
  167. {lfs->free.rev[0], lfs->free.rev[1]}, lfs->free.head};
  168. err = lfs->ops->write(lfs->bd, (void*)&header, 2, 0, sizeof(header));
  169. if (err) {
  170. return err;
  171. }
  172. uint32_t crc = lfs_crc((void*)&header, sizeof(header), 0xffffffff);
  173. for (lfs_size_t i = sizeof(header); i < info.erase_size-4; i += 4) {
  174. uint32_t data;
  175. err = lfs->ops->read(lfs->bd, (void*)&data, 2, i, 4);
  176. if (err) {
  177. return err;
  178. }
  179. crc = lfs_crc((void*)&data, 4, crc);
  180. }
  181. err = lfs->ops->write(lfs->bd, (void*)&crc, 2, info.erase_size-4, 4);
  182. if (err) {
  183. return err;
  184. }
  185. }
  186. {
  187. // Write superblock
  188. struct __attribute__((packed)) {
  189. lfs_word_t rev;
  190. lfs_word_t len;
  191. lfs_word_t tail[2];
  192. lfs_word_t free_head;
  193. lfs_word_t free_end;
  194. lfs_ino_t free_ino;
  195. char magic[4];
  196. struct lfs_bd_info info;
  197. } header = {1, 0, {2, 3}, 0, 0, 0, {"lfs"}, info};
  198. err = lfs->ops->write(lfs->bd, (void*)&header, 0, 0, sizeof(header));
  199. if (err) {
  200. return err;
  201. }
  202. uint32_t crc = lfs_crc((void*)&header, sizeof(header), 0xffffffff);
  203. for (lfs_size_t i = sizeof(header); i < info.erase_size-4; i += 4) {
  204. uint32_t data;
  205. err = lfs->ops->read(lfs->bd, (void*)&data, 0, i, 4);
  206. if (err) {
  207. return err;
  208. }
  209. crc = lfs_crc((void*)&data, 4, crc);
  210. }
  211. err = lfs->ops->write(lfs->bd, (void*)&crc, 0, info.erase_size-4, 4);
  212. if (err) {
  213. return err;
  214. }
  215. }
  216. // Sanity check
  217. uint32_t crc = 0xffffffff;
  218. for (lfs_size_t i = 0; i < info.erase_size; i += 4) {
  219. uint32_t data;
  220. err = lfs->ops->read(lfs->bd, (void*)&data, 0, i, 4);
  221. if (err) {
  222. return err;
  223. }
  224. crc = lfs_crc((void*)&data, 4, crc);
  225. }
  226. uint32_t data;
  227. err = lfs->ops->read(lfs->bd, (void*)&data, 0, info.erase_size-4, 4);
  228. if (err) {
  229. return err;
  230. }
  231. return crc;
  232. }