lfs.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621
  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, lfs_block_t tail[2]) {
  426. // Allocate pair of dir blocks
  427. for (int i = 0; i < 2; i++) {
  428. int err = lfs_alloc(lfs, &dir->pair[i]);
  429. if (err) {
  430. return err;
  431. }
  432. }
  433. // Rather than clobbering one of the blocks we just pretend
  434. // the revision may be valid
  435. int err = lfs_bd_read(lfs, dir->pair[0], 0, 4, &dir->d.rev);
  436. if (err) {
  437. return err;
  438. }
  439. dir->d.rev += 1;
  440. // Calculate total size
  441. dir->d.size = sizeof(dir->d);
  442. dir->off = sizeof(dir->d);
  443. // Other defaults
  444. dir->d.tail[0] = tail[0];
  445. dir->d.tail[1] = tail[1];
  446. // Write out to memory
  447. return lfs_pair_commit(lfs, dir->pair,
  448. 1, (struct lfs_commit_region[]){
  449. {0, sizeof(dir->d), &dir->d}
  450. });
  451. }
  452. static int lfs_dir_fetch(lfs_t *lfs, lfs_dir_t *dir, lfs_block_t pair[2]) {
  453. dir->pair[0] = pair[0];
  454. dir->pair[1] = pair[1];
  455. dir->off = sizeof(dir->d);
  456. return lfs_pair_fetch(lfs, dir->pair,
  457. 1, (struct lfs_fetch_region[1]) {
  458. {0, sizeof(dir->d), &dir->d}
  459. });
  460. }
  461. static int lfs_dir_next(lfs_t *lfs, lfs_dir_t *dir, lfs_entry_t *entry) {
  462. while (true) {
  463. if ((0x7fffffff & dir->d.size) - dir->off < sizeof(entry->d)) {
  464. if (!(dir->d.size >> 31)) {
  465. entry->dir[0] = dir->pair[0];
  466. entry->dir[1] = dir->pair[1];
  467. entry->off = dir->off;
  468. return LFS_ERROR_NO_ENTRY;
  469. }
  470. int err = lfs_dir_fetch(lfs, dir, dir->d.tail);
  471. if (err) {
  472. return err;
  473. }
  474. dir->off = sizeof(dir->d);
  475. }
  476. int err = lfs_bd_read(lfs, dir->pair[0], dir->off,
  477. sizeof(entry->d), &entry->d);
  478. if (err) {
  479. return err;
  480. }
  481. dir->off += entry->d.len;
  482. if (entry->d.type == LFS_TYPE_REG || entry->d.type == LFS_TYPE_DIR) {
  483. entry->dir[0] = dir->pair[0];
  484. entry->dir[1] = dir->pair[1];
  485. entry->off = dir->off - entry->d.len;
  486. return 0;
  487. }
  488. }
  489. }
  490. static int lfs_dir_find(lfs_t *lfs, lfs_dir_t *dir,
  491. const char **path, lfs_entry_t *entry) {
  492. const char *pathname = *path;
  493. size_t pathlen;
  494. while (true) {
  495. nextname:
  496. // skip slashes
  497. pathname += strspn(pathname, "/");
  498. pathlen = strcspn(pathname, "/");
  499. // skip '.' and root '..'
  500. if ((pathlen == 1 && memcmp(pathname, ".", 1) == 0) ||
  501. (pathlen == 2 && memcmp(pathname, "..", 2) == 0)) {
  502. pathname += pathlen;
  503. goto nextname;
  504. }
  505. // skip if matched by '..' in name
  506. const char *suffix = pathname + pathlen;
  507. size_t sufflen;
  508. int depth = 1;
  509. while (true) {
  510. suffix += strspn(suffix, "/");
  511. sufflen = strcspn(suffix, "/");
  512. if (sufflen == 0) {
  513. break;
  514. }
  515. if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) {
  516. depth -= 1;
  517. if (depth == 0) {
  518. pathname = suffix + sufflen;
  519. goto nextname;
  520. }
  521. } else {
  522. depth += 1;
  523. }
  524. suffix += sufflen;
  525. }
  526. // find path
  527. while (true) {
  528. int err = lfs_dir_next(lfs, dir, entry);
  529. if (err) {
  530. return err;
  531. }
  532. if (entry->d.len - sizeof(entry->d) != pathlen) {
  533. continue;
  534. }
  535. int ret = lfs_bd_cmp(lfs, entry->dir[0],
  536. entry->off + sizeof(entry->d), pathlen, pathname);
  537. if (ret < 0) {
  538. return ret;
  539. }
  540. // Found match
  541. if (ret == true) {
  542. break;
  543. }
  544. }
  545. pathname += pathlen;
  546. pathname += strspn(pathname, "/");
  547. if (pathname[0] == '\0') {
  548. return 0;
  549. }
  550. // continue on if we hit a directory
  551. if (entry->d.type != LFS_TYPE_DIR) {
  552. return LFS_ERROR_NOT_DIR;
  553. }
  554. int err = lfs_dir_fetch(lfs, dir, entry->d.u.dir);
  555. if (err) {
  556. return err;
  557. }
  558. *path = pathname;
  559. }
  560. return 0;
  561. }
  562. static int lfs_dir_append(lfs_t *lfs, lfs_dir_t *dir,
  563. const char **path, lfs_entry_t *entry) {
  564. int err = lfs_dir_find(lfs, dir, path, entry);
  565. if (err != LFS_ERROR_NO_ENTRY) {
  566. return err ? err : LFS_ERROR_EXISTS;
  567. }
  568. // Check if we fit
  569. if ((0x7fffffff & dir->d.size) + sizeof(entry->d) + strlen(*path)
  570. > lfs->block_size - 4) {
  571. lfs_dir_t olddir;
  572. memcpy(&olddir, dir, sizeof(olddir));
  573. int err = lfs_dir_alloc(lfs, dir, olddir.d.tail);
  574. if (err) {
  575. return err;
  576. }
  577. entry->dir[0] = dir->pair[0];
  578. entry->dir[1] = dir->pair[1];
  579. entry->off = dir->off;
  580. olddir.d.rev += 1;
  581. olddir.d.size |= 1 << 31;
  582. olddir.d.tail[0] = dir->pair[0];
  583. olddir.d.tail[1] = dir->pair[1];
  584. return lfs_pair_commit(lfs, olddir.pair,
  585. 1, (struct lfs_commit_region[]){
  586. {0, sizeof(olddir.d), &olddir.d}
  587. });
  588. }
  589. return 0;
  590. }
  591. int lfs_mkdir(lfs_t *lfs, const char *path) {
  592. // Allocate entry for directory
  593. lfs_dir_t cwd;
  594. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  595. if (err) {
  596. return err;
  597. }
  598. lfs_entry_t entry;
  599. err = lfs_dir_append(lfs, &cwd, &path, &entry);
  600. if (err) {
  601. return err;
  602. }
  603. // Build up new directory
  604. lfs_dir_t dir;
  605. err = lfs_dir_alloc(lfs, &dir, cwd.d.tail);
  606. if (err) {
  607. return err;
  608. }
  609. entry.d.type = LFS_TYPE_DIR;
  610. entry.d.len = sizeof(entry.d) + strlen(path);
  611. entry.d.u.dir[0] = dir.pair[0];
  612. entry.d.u.dir[1] = dir.pair[1];
  613. cwd.d.rev += 1;
  614. cwd.d.size += entry.d.len;
  615. cwd.d.tail[0] = dir.pair[0];
  616. cwd.d.tail[1] = dir.pair[1];
  617. return lfs_pair_commit(lfs, entry.dir,
  618. 3, (struct lfs_commit_region[3]) {
  619. {0, sizeof(cwd.d), &cwd.d},
  620. {entry.off, sizeof(entry.d), &entry.d},
  621. {entry.off+sizeof(entry.d), entry.d.len - sizeof(entry.d), path}
  622. });
  623. }
  624. int lfs_dir_open(lfs_t *lfs, lfs_dir_t *dir, const char *path) {
  625. if (path[0] == '/') {
  626. dir->pair[0] = lfs->root[0];
  627. dir->pair[1] = lfs->root[1];
  628. } else {
  629. dir->pair[0] = lfs->cwd[0];
  630. dir->pair[1] = lfs->cwd[1];
  631. }
  632. int err = lfs_dir_fetch(lfs, dir, dir->pair);
  633. if (err) {
  634. return err;
  635. } else if (strcmp(path, "/") == 0) {
  636. // special offset for '.' and '..'
  637. dir->off = sizeof(dir->d) - 2;
  638. return 0;
  639. }
  640. lfs_entry_t entry;
  641. err = lfs_dir_find(lfs, dir, &path, &entry);
  642. if (err) {
  643. return err;
  644. } else if (entry.d.type != LFS_TYPE_DIR) {
  645. return LFS_ERROR_NOT_DIR;
  646. }
  647. err = lfs_dir_fetch(lfs, dir, entry.d.u.dir);
  648. if (err) {
  649. return err;
  650. }
  651. // special offset for '.' and '..'
  652. dir->off = sizeof(dir->d) - 2;
  653. return 0;
  654. }
  655. int lfs_dir_close(lfs_t *lfs, lfs_dir_t *dir) {
  656. // Do nothing, dir is always synchronized
  657. return 0;
  658. }
  659. int lfs_dir_read(lfs_t *lfs, lfs_dir_t *dir, struct lfs_info *info) {
  660. memset(info, 0, sizeof(*info));
  661. if (dir->off == sizeof(dir->d) - 2) {
  662. info->type = LFS_TYPE_DIR;
  663. strcpy(info->name, ".");
  664. dir->off += 1;
  665. return 1;
  666. } else if (dir->off == sizeof(dir->d) - 1) {
  667. info->type = LFS_TYPE_DIR;
  668. strcpy(info->name, "..");
  669. dir->off += 1;
  670. return 1;
  671. }
  672. lfs_entry_t entry;
  673. int err = lfs_dir_next(lfs, dir, &entry);
  674. if (err) {
  675. return (err == LFS_ERROR_NO_ENTRY) ? 0 : err;
  676. }
  677. info->type = entry.d.type & 0xff;
  678. if (info->type == LFS_TYPE_REG) {
  679. info->size = entry.d.u.file.size;
  680. }
  681. err = lfs_bd_read(lfs, entry.dir[0], entry.off + sizeof(entry.d),
  682. entry.d.len - sizeof(entry.d), info->name);
  683. if (err) {
  684. return err;
  685. }
  686. return 1;
  687. }
  688. /// File operations ///
  689. int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
  690. const char *path, int flags) {
  691. // Allocate entry for file if it doesn't exist
  692. // TODO check open files
  693. lfs_dir_t cwd;
  694. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  695. if (err) {
  696. return err;
  697. }
  698. if (flags & LFS_O_CREAT) {
  699. err = lfs_dir_append(lfs, &cwd, &path, &file->entry);
  700. if (err && err != LFS_ERROR_EXISTS) {
  701. return err;
  702. }
  703. } else {
  704. err = lfs_dir_find(lfs, &cwd, &path, &file->entry);
  705. if (err) {
  706. return err;
  707. }
  708. }
  709. if ((flags & LFS_O_CREAT) && err != LFS_ERROR_EXISTS) {
  710. // Store file
  711. file->head = 0;
  712. file->size = 0;
  713. file->wblock = 0;
  714. file->windex = 0;
  715. file->rblock = 0;
  716. file->rindex = 0;
  717. file->roff = 0;
  718. file->entry.d.type = 1;
  719. file->entry.d.len = sizeof(file->entry.d) + strlen(path);
  720. file->entry.d.u.file.head = file->head;
  721. file->entry.d.u.file.size = file->size;
  722. cwd.d.rev += 1;
  723. cwd.d.size += file->entry.d.len;
  724. return lfs_pair_commit(lfs, file->entry.dir,
  725. 3, (struct lfs_commit_region[3]) {
  726. {0, sizeof(cwd.d), &cwd.d},
  727. {file->entry.off,
  728. sizeof(file->entry.d),
  729. &file->entry.d},
  730. {file->entry.off+sizeof(file->entry.d),
  731. file->entry.d.len-sizeof(file->entry.d),
  732. path}
  733. });
  734. } else if (file->entry.d.type == LFS_TYPE_DIR) {
  735. return LFS_ERROR_IS_DIR;
  736. } else {
  737. file->head = file->entry.d.u.file.head;
  738. file->size = file->entry.d.u.file.size;
  739. file->windex = lfs_indexfrom(lfs, file->size);
  740. file->rblock = 0;
  741. file->rindex = 0;
  742. file->roff = 0;
  743. // TODO do this lazily in write?
  744. // TODO cow the head i/d block
  745. if (file->size < lfs->block_size) {
  746. file->wblock = file->head;
  747. } else {
  748. int err = lfs_index_find(lfs, file->head, file->windex,
  749. file->windex, &file->wblock);
  750. if (err) {
  751. return err;
  752. }
  753. }
  754. return 0;
  755. }
  756. }
  757. int lfs_file_close(lfs_t *lfs, lfs_file_t *file) {
  758. // Store file
  759. lfs_dir_t cwd;
  760. int err = lfs_dir_fetch(lfs, &cwd, file->entry.dir);
  761. if (err) {
  762. return err;
  763. }
  764. file->entry.d.u.file.head = file->head;
  765. file->entry.d.u.file.size = file->size;
  766. cwd.d.rev += 1;
  767. return lfs_pair_commit(lfs, file->entry.dir,
  768. 3, (struct lfs_commit_region[3]) {
  769. {0, sizeof(cwd.d), &cwd.d},
  770. {file->entry.off, sizeof(file->entry.d), &file->entry.d},
  771. });
  772. }
  773. lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
  774. const void *buffer, lfs_size_t size) {
  775. const uint8_t *data = buffer;
  776. lfs_size_t nsize = size;
  777. while (nsize > 0) {
  778. lfs_off_t woff = file->size % lfs->block_size;
  779. if (file->size == 0) {
  780. int err = lfs_alloc_erased(lfs, &file->wblock);
  781. if (err) {
  782. return err;
  783. }
  784. file->head = file->wblock;
  785. file->windex = 0;
  786. } else if (woff == 0) {
  787. int err = lfs_alloc_erased(lfs, &file->wblock);
  788. if (err) {
  789. return err;
  790. }
  791. err = lfs_index_append(lfs, &file->head,
  792. &file->windex, file->wblock);
  793. if (err) {
  794. return err;
  795. }
  796. }
  797. lfs_size_t diff = lfs_min(nsize, lfs->block_size - woff);
  798. int err = lfs_bd_prog(lfs, file->wblock, woff, diff, data);
  799. if (err) {
  800. return err;
  801. }
  802. file->size += diff;
  803. data += diff;
  804. nsize -= diff;
  805. }
  806. return size;
  807. }
  808. lfs_ssize_t lfs_file_read(lfs_t *lfs, lfs_file_t *file,
  809. void *buffer, lfs_size_t size) {
  810. uint8_t *data = buffer;
  811. lfs_size_t nsize = size;
  812. while (nsize > 0 && file->roff < file->size) {
  813. lfs_off_t roff = file->roff % lfs->block_size;
  814. // TODO cache index blocks
  815. if (file->size < lfs->block_size) {
  816. file->rblock = file->head;
  817. } else if (roff == 0) {
  818. int err = lfs_index_find(lfs, file->head, file->windex,
  819. file->rindex, &file->rblock);
  820. if (err) {
  821. return err;
  822. }
  823. file->rindex = lfs_indexnext(lfs, file->rindex);
  824. }
  825. lfs_size_t diff = lfs_min(
  826. lfs_min(nsize, file->size-file->roff),
  827. lfs->block_size - roff);
  828. int err = lfs_bd_read(lfs, file->rblock, roff, diff, data);
  829. if (err) {
  830. return err;
  831. }
  832. file->roff += diff;
  833. data += diff;
  834. nsize -= diff;
  835. }
  836. return size - nsize;
  837. }
  838. /// Generic filesystem operations ///
  839. static int lfs_configure(lfs_t *lfs, const struct lfs_config *config) {
  840. lfs->bd = config->bd;
  841. lfs->bd_ops = config->bd_ops;
  842. struct lfs_bd_info info;
  843. int err = lfs_bd_info(lfs, &info);
  844. if (err) {
  845. return err;
  846. }
  847. if (config->read_size) {
  848. if (config->read_size < info.read_size ||
  849. config->read_size % info.read_size != 0) {
  850. LFS_ERROR("Invalid read size %u, device has %u\n",
  851. config->read_size, info.read_size);
  852. return LFS_ERROR_INVALID;
  853. }
  854. lfs->read_size = config->read_size;
  855. } else {
  856. lfs->read_size = info.read_size;
  857. }
  858. if (config->prog_size) {
  859. if (config->prog_size < info.prog_size ||
  860. config->prog_size % info.prog_size != 0) {
  861. LFS_ERROR("Invalid prog size %u, device has %u\n",
  862. config->prog_size, info.prog_size);
  863. return LFS_ERROR_INVALID;
  864. }
  865. lfs->prog_size = config->prog_size;
  866. } else {
  867. lfs->prog_size = info.prog_size;
  868. }
  869. if (config->block_size) {
  870. if (config->block_size < info.erase_size ||
  871. config->block_size % info.erase_size != 0) {
  872. LFS_ERROR("Invalid block size %u, device has %u\n",
  873. config->prog_size, info.prog_size);
  874. return LFS_ERROR_INVALID;
  875. }
  876. lfs->block_size = config->block_size;
  877. } else {
  878. lfs->block_size = lfs_min(512, info.erase_size);
  879. }
  880. if (config->block_count) {
  881. if (config->block_count > info.total_size/info.erase_size) {
  882. LFS_ERROR("Invalid block size %u, device has %u\n",
  883. config->block_size,
  884. (uint32_t)(info.total_size/info.erase_size));
  885. return LFS_ERROR_INVALID;
  886. }
  887. lfs->block_count = config->block_count;
  888. } else {
  889. lfs->block_count = info.total_size / info.erase_size;
  890. }
  891. lfs->words = lfs->block_size / sizeof(uint32_t);
  892. return 0;
  893. }
  894. int lfs_format(lfs_t *lfs, const struct lfs_config *config) {
  895. int err = lfs_configure(lfs, config);
  896. if (err) {
  897. return err;
  898. }
  899. // Create free list
  900. lfs->free.begin = 2;
  901. lfs->free.end = lfs->block_count-1;
  902. // Write root directory
  903. lfs_dir_t root;
  904. err = lfs_dir_alloc(lfs, &root, (lfs_block_t[2]){0, 0});
  905. if (err) {
  906. return err;
  907. }
  908. lfs->root[0] = root.pair[0];
  909. lfs->root[1] = root.pair[1];
  910. lfs->cwd[0] = root.pair[0];
  911. lfs->cwd[1] = root.pair[1];
  912. // Write superblocks
  913. lfs_superblock_t superblock = {
  914. .pair = {0, 1},
  915. .d.rev = 1,
  916. .d.size = sizeof(superblock),
  917. .d.root = {lfs->cwd[0], lfs->cwd[1]},
  918. .d.magic = {"littlefs"},
  919. .d.block_size = lfs->block_size,
  920. .d.block_count = lfs->block_count,
  921. };
  922. for (int i = 0; i < 2; i++) {
  923. int err = lfs_pair_commit(lfs, superblock.pair,
  924. 1, (struct lfs_commit_region[]){
  925. {0, sizeof(superblock.d), &superblock.d}
  926. });
  927. if (err) {
  928. LFS_ERROR("Failed to write superblock at %d", superblock.pair[1]);
  929. return err;
  930. }
  931. uint32_t crc = 0xffffffff;
  932. err = lfs_bd_crc(lfs, superblock.pair[0], 0, lfs->block_size, &crc);
  933. if (err || crc != 0) {
  934. LFS_ERROR("Failed to write superblock at %d", superblock.pair[0]);
  935. return err ? err : LFS_ERROR_CORRUPT;
  936. }
  937. }
  938. return 0;
  939. }
  940. int lfs_mount(lfs_t *lfs, const struct lfs_config *config) {
  941. int err = lfs_configure(lfs, config);
  942. if (err) {
  943. return err;
  944. }
  945. lfs_superblock_t superblock = {
  946. .pair = {0, 1},
  947. };
  948. err = lfs_pair_fetch(lfs, superblock.pair,
  949. 1, (struct lfs_fetch_region[]){
  950. {0, sizeof(superblock.d), &superblock.d}
  951. });
  952. if ((err == LFS_ERROR_CORRUPT ||
  953. memcmp(superblock.d.magic, "littlefs", 8) != 0)) {
  954. LFS_ERROR("Invalid superblock at %d %d",
  955. superblock.pair[0], superblock.pair[1]);
  956. return LFS_ERROR_CORRUPT;
  957. }
  958. lfs->root[0] = superblock.d.root[0];
  959. lfs->root[1] = superblock.d.root[1];
  960. lfs->cwd[0] = superblock.d.root[0];
  961. lfs->cwd[1] = superblock.d.root[1];
  962. return err;
  963. }
  964. int lfs_unmount(lfs_t *lfs) {
  965. // Do nothing for now
  966. return 0;
  967. }
  968. int lfs_traverse(lfs_t *lfs, int (*cb)(void*, lfs_block_t), void *data) {
  969. // iterate over metadata pairs
  970. lfs_dir_t dir;
  971. lfs_file_t file;
  972. lfs_block_t cwd[2] = {0, 1};
  973. while (true) {
  974. for (int i = 0; i < 2; i++) {
  975. int err = cb(data, cwd[i]);
  976. if (err) {
  977. return err;
  978. }
  979. }
  980. int err = lfs_dir_fetch(lfs, &dir, cwd);
  981. if (err) {
  982. return err;
  983. }
  984. // iterate over contents
  985. while ((0x7fffffff & dir.d.size) >= dir.off + sizeof(file.entry.d)) {
  986. int err = lfs_bd_read(lfs, dir.pair[0], dir.off,
  987. sizeof(file.entry.d), &file.entry.d);
  988. if (err) {
  989. return err;
  990. }
  991. dir.off += file.entry.d.len;
  992. if ((0xf & file.entry.d.type) == LFS_TYPE_REG) {
  993. if (file.entry.d.u.file.size < lfs->block_size) {
  994. int err = cb(data, file.entry.d.u.file.head);
  995. if (err) {
  996. return err;
  997. }
  998. } else {
  999. int err = lfs_index_traverse(lfs,
  1000. file.entry.d.u.file.head,
  1001. lfs_indexfrom(lfs, file.entry.d.u.file.size),
  1002. cb, data);
  1003. if (err) {
  1004. return err;
  1005. }
  1006. }
  1007. }
  1008. }
  1009. cwd[0] = dir.d.tail[0];
  1010. cwd[1] = dir.d.tail[1];
  1011. if (!cwd[0]) {
  1012. return 0;
  1013. }
  1014. }
  1015. }
  1016. static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2]) {
  1017. // iterate over all directory directory entries
  1018. lfs_dir_t parent = {
  1019. .d.tail[0] = lfs->root[0],
  1020. .d.tail[1] = lfs->root[1],
  1021. };
  1022. while (parent.d.tail[0]) {
  1023. lfs_entry_t entry;
  1024. int err = lfs_dir_fetch(lfs, &parent, parent.d.tail);
  1025. if (err) {
  1026. return err;
  1027. }
  1028. while (true) {
  1029. int err = lfs_dir_next(lfs, &parent, &entry);
  1030. if (err && err != LFS_ERROR_NO_ENTRY) {
  1031. return err;
  1032. }
  1033. if (err == LFS_ERROR_NO_ENTRY) {
  1034. break;
  1035. }
  1036. if ((0xf & entry.d.type) == LFS_TYPE_DIR &&
  1037. lfs_paircmp(entry.d.u.dir, dir) == 0) {
  1038. return true;
  1039. }
  1040. }
  1041. }
  1042. return false;
  1043. }
  1044. int lfs_deorphan(lfs_t *lfs) {
  1045. // iterate over all directories
  1046. lfs_dir_t pdir;
  1047. lfs_dir_t cdir;
  1048. // skip root
  1049. int err = lfs_dir_fetch(lfs, &pdir, lfs->root);
  1050. if (err) {
  1051. return err;
  1052. }
  1053. while (pdir.d.tail[0]) {
  1054. int err = lfs_dir_fetch(lfs, &cdir, pdir.d.tail);
  1055. if (err) {
  1056. return err;
  1057. }
  1058. // check if we have a parent
  1059. int parent = lfs_parent(lfs, pdir.d.tail);
  1060. if (parent < 0) {
  1061. return parent;
  1062. }
  1063. if (!parent) {
  1064. // we are an orphan
  1065. LFS_INFO("Found orphan %d %d", pdir.d.tail[0], pdir.d.tail[1]);
  1066. pdir.d.tail[0] = cdir.d.tail[0];
  1067. pdir.d.tail[1] = cdir.d.tail[1];
  1068. pdir.d.rev += 1;
  1069. err = lfs_pair_commit(lfs, pdir.pair,
  1070. 1, (struct lfs_commit_region[]) {
  1071. {0, sizeof(pdir.d), &pdir.d},
  1072. });
  1073. if (err) {
  1074. return err;
  1075. }
  1076. break;
  1077. }
  1078. memcpy(&pdir, &cdir, sizeof(pdir));
  1079. }
  1080. return 0;
  1081. }
  1082. int lfs_remove(lfs_t *lfs, const char *path) {
  1083. lfs_dir_t cwd;
  1084. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  1085. if (err) {
  1086. return err;
  1087. }
  1088. lfs_entry_t entry;
  1089. err = lfs_dir_find(lfs, &cwd, &path, &entry);
  1090. if (err) {
  1091. return err;
  1092. }
  1093. lfs_dir_t dir;
  1094. if (entry.d.type == LFS_TYPE_DIR) {
  1095. // must be empty before removal, checking size
  1096. // without masking top bit checks for any case where
  1097. // dir is not empty
  1098. int err = lfs_dir_fetch(lfs, &dir, entry.d.u.dir);
  1099. if (err) {
  1100. return err;
  1101. } else if (dir.d.size != sizeof(dir.d)) {
  1102. return LFS_ERROR_INVALID;
  1103. }
  1104. }
  1105. cwd.d.rev += 1;
  1106. cwd.d.size -= entry.d.len;
  1107. // either shift out the one entry or remove the whole dir block
  1108. if (cwd.d.size == sizeof(cwd.d)) {
  1109. lfs_dir_t pdir;
  1110. int err = lfs_dir_fetch(lfs, &pdir, lfs->cwd);
  1111. if (err) {
  1112. return err;
  1113. }
  1114. while (lfs_paircmp(pdir.d.tail, cwd.pair) != 0) {
  1115. int err = lfs_dir_fetch(lfs, &pdir, pdir.d.tail);
  1116. if (err) {
  1117. return err;
  1118. }
  1119. }
  1120. // TODO easier check for head block? (common case)
  1121. if (!(pdir.d.size & 0x80000000)) {
  1122. int err = lfs_pair_shift(lfs, entry.dir,
  1123. 1, (struct lfs_commit_region[]) {
  1124. {0, sizeof(cwd.d), &cwd.d},
  1125. },
  1126. entry.off, entry.d.len);
  1127. if (err) {
  1128. return err;
  1129. }
  1130. } else {
  1131. pdir.d.tail[0] = cwd.d.tail[0];
  1132. pdir.d.tail[1] = cwd.d.tail[1];
  1133. pdir.d.rev += 1;
  1134. err = lfs_pair_commit(lfs, pdir.pair,
  1135. 1, (struct lfs_commit_region[]) {
  1136. {0, sizeof(pdir.d), &pdir.d},
  1137. });
  1138. if (err) {
  1139. return err;
  1140. }
  1141. }
  1142. } else {
  1143. int err = lfs_pair_shift(lfs, entry.dir,
  1144. 1, (struct lfs_commit_region[]) {
  1145. {0, sizeof(cwd.d), &cwd.d},
  1146. },
  1147. entry.off, entry.d.len);
  1148. if (err) {
  1149. return err;
  1150. }
  1151. }
  1152. if (entry.d.type == LFS_TYPE_DIR) {
  1153. // remove ourselves from the dir list
  1154. // this may create an orphan, which must be deorphaned
  1155. lfs_dir_t pdir;
  1156. memcpy(&pdir, &cwd, sizeof(pdir));
  1157. while (pdir.d.tail[0]) {
  1158. if (lfs_paircmp(pdir.d.tail, entry.d.u.dir) == 0) {
  1159. pdir.d.tail[0] = dir.d.tail[0];
  1160. pdir.d.tail[1] = dir.d.tail[1];
  1161. pdir.d.rev += 1;
  1162. int err = lfs_pair_commit(lfs, pdir.pair,
  1163. 1, (struct lfs_commit_region[]) {
  1164. {0, sizeof(pdir.d), &pdir.d},
  1165. });
  1166. if (err) {
  1167. return err;
  1168. }
  1169. break;
  1170. }
  1171. int err = lfs_dir_fetch(lfs, &pdir, pdir.d.tail);
  1172. if (err) {
  1173. return err;
  1174. }
  1175. }
  1176. }
  1177. return 0;
  1178. }
  1179. int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
  1180. // Find old entry
  1181. lfs_dir_t oldcwd;
  1182. int err = lfs_dir_fetch(lfs, &oldcwd, lfs->cwd);
  1183. if (err) {
  1184. return err;
  1185. }
  1186. lfs_entry_t oldentry;
  1187. err = lfs_dir_find(lfs, &oldcwd, &oldpath, &oldentry);
  1188. if (err) {
  1189. return err;
  1190. }
  1191. // Allocate new entry
  1192. lfs_dir_t newcwd;
  1193. err = lfs_dir_fetch(lfs, &newcwd, lfs->cwd);
  1194. if (err) {
  1195. return err;
  1196. }
  1197. lfs_entry_t preventry;
  1198. err = lfs_dir_append(lfs, &newcwd, &newpath, &preventry);
  1199. if (err && err != LFS_ERROR_EXISTS) {
  1200. return err;
  1201. }
  1202. bool prevexists = (err == LFS_ERROR_EXISTS);
  1203. // must have same type
  1204. if (prevexists && preventry.d.type != oldentry.d.type) {
  1205. return LFS_ERROR_INVALID;
  1206. }
  1207. lfs_dir_t dir;
  1208. if (prevexists && preventry.d.type == LFS_TYPE_DIR) {
  1209. // must be empty before removal, checking size
  1210. // without masking top bit checks for any case where
  1211. // dir is not empty
  1212. int err = lfs_dir_fetch(lfs, &dir, preventry.d.u.dir);
  1213. if (err) {
  1214. return err;
  1215. } else if (dir.d.size != sizeof(dir.d)) {
  1216. return LFS_ERROR_INVALID;
  1217. }
  1218. }
  1219. // Move to new location
  1220. lfs_entry_t newentry = preventry;
  1221. newentry.d = oldentry.d;
  1222. newentry.d.len = sizeof(newentry.d) + strlen(newpath);
  1223. newcwd.d.rev += 1;
  1224. if (!prevexists) {
  1225. newcwd.d.size += newentry.d.len;
  1226. }
  1227. err = lfs_pair_commit(lfs, newentry.dir,
  1228. 3, (struct lfs_commit_region[3]) {
  1229. {0, sizeof(newcwd.d), &newcwd.d},
  1230. {newentry.off,
  1231. sizeof(newentry.d),
  1232. &newentry.d},
  1233. {newentry.off+sizeof(newentry.d),
  1234. newentry.d.len - sizeof(newentry.d),
  1235. newpath}
  1236. });
  1237. if (err) {
  1238. return err;
  1239. }
  1240. // fetch again in case newcwd == oldcwd
  1241. // TODO handle this better?
  1242. err = lfs_dir_fetch(lfs, &oldcwd, oldcwd.pair);
  1243. if (err) {
  1244. return err;
  1245. }
  1246. err = lfs_dir_find(lfs, &oldcwd, &oldpath, &oldentry);
  1247. if (err) {
  1248. return err;
  1249. }
  1250. // Remove from old location
  1251. // TODO abstract this out for rename + remove?
  1252. oldcwd.d.rev += 1;
  1253. oldcwd.d.size -= oldentry.d.len;
  1254. // either shift out the one entry or remove the whole dir block
  1255. if (oldcwd.d.size == sizeof(oldcwd.d)) {
  1256. lfs_dir_t pdir;
  1257. int err = lfs_dir_fetch(lfs, &pdir, lfs->cwd);
  1258. if (err) {
  1259. return err;
  1260. }
  1261. while (lfs_paircmp(pdir.d.tail, oldcwd.pair) != 0) {
  1262. int err = lfs_dir_fetch(lfs, &pdir, pdir.d.tail);
  1263. if (err) {
  1264. return err;
  1265. }
  1266. }
  1267. // TODO easier check for head block? (common case)
  1268. if (!(pdir.d.size & 0x80000000)) {
  1269. int err = lfs_pair_shift(lfs, oldentry.dir,
  1270. 1, (struct lfs_commit_region[]) {
  1271. {0, sizeof(oldcwd.d), &oldcwd.d},
  1272. },
  1273. oldentry.off, oldentry.d.len);
  1274. if (err) {
  1275. return err;
  1276. }
  1277. } else {
  1278. pdir.d.tail[0] = oldcwd.d.tail[0];
  1279. pdir.d.tail[1] = oldcwd.d.tail[1];
  1280. pdir.d.rev += 1;
  1281. err = lfs_pair_commit(lfs, pdir.pair,
  1282. 1, (struct lfs_commit_region[]) {
  1283. {0, sizeof(pdir.d), &pdir.d},
  1284. });
  1285. if (err) {
  1286. return err;
  1287. }
  1288. }
  1289. } else {
  1290. int err = lfs_pair_shift(lfs, oldentry.dir,
  1291. 1, (struct lfs_commit_region[]) {
  1292. {0, sizeof(oldcwd.d), &oldcwd.d},
  1293. },
  1294. oldentry.off, oldentry.d.len);
  1295. if (err) {
  1296. return err;
  1297. }
  1298. }
  1299. // TODO abstract this out for rename + remove?
  1300. if (prevexists && preventry.d.type == LFS_TYPE_DIR) {
  1301. // remove dest from the dir list
  1302. // this may create an orphan, which must be deorphaned
  1303. lfs_dir_t pdir;
  1304. int err = lfs_dir_fetch(lfs, &pdir, lfs->root);
  1305. if (err) {
  1306. return err;
  1307. }
  1308. while (pdir.d.tail[0]) {
  1309. if (lfs_paircmp(pdir.d.tail, preventry.d.u.dir) == 0) {
  1310. pdir.d.tail[0] = dir.d.tail[0];
  1311. pdir.d.tail[1] = dir.d.tail[1];
  1312. pdir.d.rev += 1;
  1313. int err = lfs_pair_commit(lfs, pdir.pair,
  1314. 1, (struct lfs_commit_region[]) {
  1315. {0, sizeof(pdir.d), &pdir.d},
  1316. });
  1317. if (err) {
  1318. return err;
  1319. }
  1320. break;
  1321. }
  1322. int err = lfs_dir_fetch(lfs, &pdir, pdir.d.tail);
  1323. if (err) {
  1324. return err;
  1325. }
  1326. }
  1327. }
  1328. return 0;
  1329. }
  1330. int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) {
  1331. lfs_dir_t cwd;
  1332. int err = lfs_dir_fetch(lfs, &cwd, lfs->cwd);
  1333. if (err) {
  1334. return err;
  1335. }
  1336. lfs_entry_t entry;
  1337. err = lfs_dir_find(lfs, &cwd, &path, &entry);
  1338. if (err) {
  1339. return err;
  1340. }
  1341. // TODO abstract out info assignment
  1342. memset(info, 0, sizeof(*info));
  1343. info->type = entry.d.type & 0xff;
  1344. if (info->type == LFS_TYPE_REG) {
  1345. info->size = entry.d.u.file.size;
  1346. }
  1347. err = lfs_bd_read(lfs, entry.dir[0], entry.off + sizeof(entry.d),
  1348. entry.d.len - sizeof(entry.d), info->name);
  1349. if (err) {
  1350. return err;
  1351. }
  1352. return 0;
  1353. }