Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 

1406 rader
38 KiB

  1. /*
  2. * spiffs_hydrogen.c
  3. *
  4. * Created on: Jun 16, 2013
  5. * Author: petera
  6. */
  7. #include "spiffs.h"
  8. #include "spiffs_nucleus.h"
  9. #if SPIFFS_FILEHDL_OFFSET
  10. #define SPIFFS_FH_OFFS(fs, fh) ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0)
  11. #define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0)
  12. #else
  13. #define SPIFFS_FH_OFFS(fs, fh) (fh)
  14. #define SPIFFS_FH_UNOFFS(fs, fh) (fh)
  15. #endif
  16. #if SPIFFS_CACHE == 1
  17. static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);
  18. #endif
  19. #if SPIFFS_BUFFER_HELP
  20. u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) {
  21. return num_descs * sizeof(spiffs_fd);
  22. }
  23. #if SPIFFS_CACHE
  24. u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages) {
  25. return sizeof(spiffs_cache) + num_pages * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs));
  26. }
  27. #endif
  28. #endif
  29. u8_t SPIFFS_mounted(spiffs *fs) {
  30. return SPIFFS_CHECK_MOUNT(fs);
  31. }
  32. s32_t SPIFFS_format(spiffs *fs) {
  33. #if SPIFFS_READ_ONLY
  34. (void)fs;
  35. return SPIFFS_ERR_RO_NOT_IMPL;
  36. #else
  37. SPIFFS_API_CHECK_CFG(fs);
  38. if (SPIFFS_CHECK_MOUNT(fs)) {
  39. fs->err_code = SPIFFS_ERR_MOUNTED;
  40. return -1;
  41. }
  42. s32_t res;
  43. SPIFFS_LOCK(fs);
  44. spiffs_block_ix bix = 0;
  45. while (bix < fs->block_count) {
  46. fs->max_erase_count = 0;
  47. res = spiffs_erase_block(fs, bix);
  48. if (res != SPIFFS_OK) {
  49. res = SPIFFS_ERR_ERASE_FAIL;
  50. }
  51. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  52. bix++;
  53. }
  54. SPIFFS_UNLOCK(fs);
  55. return 0;
  56. #endif // SPIFFS_READ_ONLY
  57. }
  58. #if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
  59. s32_t SPIFFS_probe_fs(spiffs_config *config) {
  60. s32_t res = spiffs_probe(config);
  61. return res;
  62. }
  63. #endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
  64. s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
  65. u8_t *fd_space, u32_t fd_space_size,
  66. void *cache, u32_t cache_size,
  67. spiffs_check_callback check_cb_f) {
  68. void *user_data;
  69. SPIFFS_LOCK(fs);
  70. user_data = fs->user_data;
  71. memset(fs, 0, sizeof(spiffs));
  72. memcpy(&fs->cfg, config, sizeof(spiffs_config));
  73. fs->user_data = user_data;
  74. fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);
  75. fs->work = &work[0];
  76. fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)];
  77. memset(fd_space, 0, fd_space_size);
  78. // align fd_space pointer to pointer size byte boundary
  79. u8_t ptr_size = sizeof(void*);
  80. u8_t addr_lsb = ((u8_t)(intptr_t)fd_space) & (ptr_size-1);
  81. if (addr_lsb) {
  82. fd_space += (ptr_size-addr_lsb);
  83. fd_space_size -= (ptr_size-addr_lsb);
  84. }
  85. fs->fd_space = fd_space;
  86. fs->fd_count = (fd_space_size/sizeof(spiffs_fd));
  87. // align cache pointer to 4 byte boundary
  88. addr_lsb = ((u8_t)(intptr_t)cache) & (ptr_size-1);
  89. if (addr_lsb) {
  90. u8_t *cache_8 = (u8_t *)cache;
  91. cache_8 += (ptr_size-addr_lsb);
  92. cache = cache_8;
  93. cache_size -= (ptr_size-addr_lsb);
  94. }
  95. if (cache_size & (ptr_size-1)) {
  96. cache_size -= (cache_size & (ptr_size-1));
  97. }
  98. #if SPIFFS_CACHE
  99. fs->cache = cache;
  100. fs->cache_size = (cache_size > (SPIFFS_CFG_LOG_PAGE_SZ(fs)*32)) ? SPIFFS_CFG_LOG_PAGE_SZ(fs)*32 : cache_size;
  101. spiffs_cache_init(fs);
  102. #endif
  103. s32_t res;
  104. #if SPIFFS_USE_MAGIC
  105. res = SPIFFS_CHECK_MAGIC_POSSIBLE(fs) ? SPIFFS_OK : SPIFFS_ERR_MAGIC_NOT_POSSIBLE;
  106. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  107. #endif
  108. fs->config_magic = SPIFFS_CONFIG_MAGIC;
  109. res = spiffs_obj_lu_scan(fs);
  110. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  111. SPIFFS_DBG("page index byte len: "_SPIPRIi"\n", (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs));
  112. SPIFFS_DBG("object lookup pages: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_LOOKUP_PAGES(fs));
  113. SPIFFS_DBG("page pages per block: "_SPIPRIi"\n", (u32_t)SPIFFS_PAGES_PER_BLOCK(fs));
  114. SPIFFS_DBG("page header length: "_SPIPRIi"\n", (u32_t)sizeof(spiffs_page_header));
  115. SPIFFS_DBG("object header index entries: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_HDR_IX_LEN(fs));
  116. SPIFFS_DBG("object index entries: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_IX_LEN(fs));
  117. SPIFFS_DBG("available file descriptors: "_SPIPRIi"\n", (u32_t)fs->fd_count);
  118. SPIFFS_DBG("free blocks: "_SPIPRIi"\n", (u32_t)fs->free_blocks);
  119. fs->check_cb_f = check_cb_f;
  120. fs->mounted = 1;
  121. SPIFFS_UNLOCK(fs);
  122. return 0;
  123. }
  124. void SPIFFS_unmount(spiffs *fs) {
  125. if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return;
  126. SPIFFS_LOCK(fs);
  127. u32_t i;
  128. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  129. for (i = 0; i < fs->fd_count; i++) {
  130. spiffs_fd *cur_fd = &fds[i];
  131. if (cur_fd->file_nbr != 0) {
  132. #if SPIFFS_CACHE
  133. (void)spiffs_fflush_cache(fs, cur_fd->file_nbr);
  134. #endif
  135. spiffs_fd_return(fs, cur_fd->file_nbr);
  136. }
  137. }
  138. fs->mounted = 0;
  139. SPIFFS_UNLOCK(fs);
  140. }
  141. s32_t SPIFFS_errno(spiffs *fs) {
  142. return fs->err_code;
  143. }
  144. void SPIFFS_clearerr(spiffs *fs) {
  145. fs->err_code = SPIFFS_OK;
  146. }
  147. s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) {
  148. #if SPIFFS_READ_ONLY
  149. (void)fs; (void)path; (void)mode;
  150. return SPIFFS_ERR_RO_NOT_IMPL;
  151. #else
  152. (void)mode;
  153. SPIFFS_API_CHECK_CFG(fs);
  154. SPIFFS_API_CHECK_MOUNT(fs);
  155. if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
  156. SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
  157. }
  158. SPIFFS_LOCK(fs);
  159. spiffs_obj_id obj_id;
  160. s32_t res;
  161. res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, (const u8_t*)path);
  162. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  163. res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, 0);
  164. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  165. SPIFFS_UNLOCK(fs);
  166. return 0;
  167. #endif // SPIFFS_READ_ONLY
  168. }
  169. spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) {
  170. (void)mode;
  171. SPIFFS_API_CHECK_CFG(fs);
  172. SPIFFS_API_CHECK_MOUNT(fs);
  173. if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
  174. SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
  175. }
  176. SPIFFS_LOCK(fs);
  177. spiffs_fd *fd;
  178. spiffs_page_ix pix;
  179. #if SPIFFS_READ_ONLY
  180. // not valid flags in read only mode
  181. flags &= ~(SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_TRUNC);
  182. #endif // SPIFFS_READ_ONLY
  183. s32_t res = spiffs_fd_find_new(fs, &fd, path);
  184. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  185. res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);
  186. if ((flags & SPIFFS_O_CREAT) == 0) {
  187. if (res < SPIFFS_OK) {
  188. spiffs_fd_return(fs, fd->file_nbr);
  189. }
  190. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  191. }
  192. if (res == SPIFFS_OK &&
  193. (flags & (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) == (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) {
  194. // creat and excl and file exists - fail
  195. res = SPIFFS_ERR_FILE_EXISTS;
  196. spiffs_fd_return(fs, fd->file_nbr);
  197. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  198. }
  199. if ((flags & SPIFFS_O_CREAT) && res == SPIFFS_ERR_NOT_FOUND) {
  200. #if !SPIFFS_READ_ONLY
  201. spiffs_obj_id obj_id;
  202. // no need to enter conflicting name here, already looked for it above
  203. res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, 0);
  204. if (res < SPIFFS_OK) {
  205. spiffs_fd_return(fs, fd->file_nbr);
  206. }
  207. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  208. res = spiffs_object_create(fs, obj_id, (const u8_t*)path, 0, SPIFFS_TYPE_FILE, &pix);
  209. if (res < SPIFFS_OK) {
  210. spiffs_fd_return(fs, fd->file_nbr);
  211. }
  212. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  213. flags &= ~SPIFFS_O_TRUNC;
  214. #endif // !SPIFFS_READ_ONLY
  215. } else {
  216. if (res < SPIFFS_OK) {
  217. spiffs_fd_return(fs, fd->file_nbr);
  218. }
  219. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  220. }
  221. res = spiffs_object_open_by_page(fs, pix, fd, flags, mode);
  222. if (res < SPIFFS_OK) {
  223. spiffs_fd_return(fs, fd->file_nbr);
  224. }
  225. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  226. #if !SPIFFS_READ_ONLY
  227. if (flags & SPIFFS_O_TRUNC) {
  228. res = spiffs_object_truncate(fd, 0, 0);
  229. if (res < SPIFFS_OK) {
  230. spiffs_fd_return(fs, fd->file_nbr);
  231. }
  232. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  233. }
  234. #endif // !SPIFFS_READ_ONLY
  235. fd->fdoffset = 0;
  236. SPIFFS_UNLOCK(fs);
  237. return SPIFFS_FH_OFFS(fs, fd->file_nbr);
  238. }
  239. spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) {
  240. SPIFFS_API_CHECK_CFG(fs);
  241. SPIFFS_API_CHECK_MOUNT(fs);
  242. SPIFFS_LOCK(fs);
  243. spiffs_fd *fd;
  244. s32_t res = spiffs_fd_find_new(fs, &fd, 0);
  245. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  246. res = spiffs_object_open_by_page(fs, e->pix, fd, flags, mode);
  247. if (res < SPIFFS_OK) {
  248. spiffs_fd_return(fs, fd->file_nbr);
  249. }
  250. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  251. #if !SPIFFS_READ_ONLY
  252. if (flags & SPIFFS_O_TRUNC) {
  253. res = spiffs_object_truncate(fd, 0, 0);
  254. if (res < SPIFFS_OK) {
  255. spiffs_fd_return(fs, fd->file_nbr);
  256. }
  257. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  258. }
  259. #endif // !SPIFFS_READ_ONLY
  260. fd->fdoffset = 0;
  261. SPIFFS_UNLOCK(fs);
  262. return SPIFFS_FH_OFFS(fs, fd->file_nbr);
  263. }
  264. spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode) {
  265. SPIFFS_API_CHECK_CFG(fs);
  266. SPIFFS_API_CHECK_MOUNT(fs);
  267. SPIFFS_LOCK(fs);
  268. spiffs_fd *fd;
  269. s32_t res = spiffs_fd_find_new(fs, &fd, 0);
  270. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  271. if (SPIFFS_IS_LOOKUP_PAGE(fs, page_ix)) {
  272. res = SPIFFS_ERR_NOT_A_FILE;
  273. spiffs_fd_return(fs, fd->file_nbr);
  274. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  275. }
  276. res = spiffs_object_open_by_page(fs, page_ix, fd, flags, mode);
  277. if (res == SPIFFS_ERR_IS_FREE ||
  278. res == SPIFFS_ERR_DELETED ||
  279. res == SPIFFS_ERR_NOT_FINALIZED ||
  280. res == SPIFFS_ERR_NOT_INDEX ||
  281. res == SPIFFS_ERR_INDEX_SPAN_MISMATCH) {
  282. res = SPIFFS_ERR_NOT_A_FILE;
  283. }
  284. if (res < SPIFFS_OK) {
  285. spiffs_fd_return(fs, fd->file_nbr);
  286. }
  287. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  288. #if !SPIFFS_READ_ONLY
  289. if (flags & SPIFFS_O_TRUNC) {
  290. res = spiffs_object_truncate(fd, 0, 0);
  291. if (res < SPIFFS_OK) {
  292. spiffs_fd_return(fs, fd->file_nbr);
  293. }
  294. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  295. }
  296. #endif // !SPIFFS_READ_ONLY
  297. fd->fdoffset = 0;
  298. SPIFFS_UNLOCK(fs);
  299. return SPIFFS_FH_OFFS(fs, fd->file_nbr);
  300. }
  301. static s32_t spiffs_hydro_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
  302. SPIFFS_API_CHECK_CFG(fs);
  303. SPIFFS_API_CHECK_MOUNT(fs);
  304. SPIFFS_LOCK(fs);
  305. spiffs_fd *fd;
  306. s32_t res;
  307. fh = SPIFFS_FH_UNOFFS(fs, fh);
  308. res = spiffs_fd_get(fs, fh, &fd);
  309. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  310. if ((fd->flags & SPIFFS_O_RDONLY) == 0) {
  311. res = SPIFFS_ERR_NOT_READABLE;
  312. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  313. }
  314. if (fd->size == SPIFFS_UNDEFINED_LEN && len > 0) {
  315. // special case for zero sized files
  316. res = SPIFFS_ERR_END_OF_OBJECT;
  317. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  318. }
  319. #if SPIFFS_CACHE_WR
  320. spiffs_fflush_cache(fs, fh);
  321. #endif
  322. if (fd->fdoffset + len >= fd->size) {
  323. // reading beyond file size
  324. s32_t avail = fd->size - fd->fdoffset;
  325. if (avail <= 0) {
  326. SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_END_OF_OBJECT);
  327. }
  328. res = spiffs_object_read(fd, fd->fdoffset, avail, (u8_t*)buf);
  329. if (res == SPIFFS_ERR_END_OF_OBJECT) {
  330. fd->fdoffset += avail;
  331. SPIFFS_UNLOCK(fs);
  332. return avail;
  333. } else {
  334. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  335. len = avail;
  336. }
  337. } else {
  338. // reading within file size
  339. res = spiffs_object_read(fd, fd->fdoffset, len, (u8_t*)buf);
  340. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  341. }
  342. fd->fdoffset += len;
  343. SPIFFS_UNLOCK(fs);
  344. return len;
  345. }
  346. s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
  347. s32_t res = spiffs_hydro_read(fs, fh, buf, len);
  348. if (res == SPIFFS_ERR_END_OF_OBJECT) {
  349. res = 0;
  350. }
  351. return res;
  352. }
  353. #if !SPIFFS_READ_ONLY
  354. static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) {
  355. (void)fs;
  356. s32_t res = SPIFFS_OK;
  357. s32_t remaining = len;
  358. if (fd->size != SPIFFS_UNDEFINED_LEN && offset < fd->size) {
  359. s32_t m_len = MIN((s32_t)(fd->size - offset), len);
  360. res = spiffs_object_modify(fd, offset, (u8_t *)buf, m_len);
  361. SPIFFS_CHECK_RES(res);
  362. remaining -= m_len;
  363. u8_t *buf_8 = (u8_t *)buf;
  364. buf_8 += m_len;
  365. buf = buf_8;
  366. offset += m_len;
  367. }
  368. if (remaining > 0) {
  369. res = spiffs_object_append(fd, offset, (u8_t *)buf, remaining);
  370. SPIFFS_CHECK_RES(res);
  371. }
  372. return len;
  373. }
  374. #endif // !SPIFFS_READ_ONLY
  375. s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
  376. #if SPIFFS_READ_ONLY
  377. (void)fs; (void)fh; (void)buf; (void)len;
  378. return SPIFFS_ERR_RO_NOT_IMPL;
  379. #else
  380. SPIFFS_API_CHECK_CFG(fs);
  381. SPIFFS_API_CHECK_MOUNT(fs);
  382. SPIFFS_LOCK(fs);
  383. spiffs_fd *fd;
  384. s32_t res;
  385. u32_t offset;
  386. fh = SPIFFS_FH_UNOFFS(fs, fh);
  387. res = spiffs_fd_get(fs, fh, &fd);
  388. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  389. if ((fd->flags & SPIFFS_O_WRONLY) == 0) {
  390. res = SPIFFS_ERR_NOT_WRITABLE;
  391. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  392. }
  393. if ((fd->flags & SPIFFS_O_APPEND)) {
  394. fd->fdoffset = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;
  395. }
  396. offset = fd->fdoffset;
  397. #if SPIFFS_CACHE_WR
  398. if (fd->cache_page == 0) {
  399. // see if object id is associated with cache already
  400. fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
  401. }
  402. #endif
  403. if (fd->flags & SPIFFS_O_APPEND) {
  404. if (fd->size == SPIFFS_UNDEFINED_LEN) {
  405. offset = 0;
  406. } else {
  407. offset = fd->size;
  408. }
  409. #if SPIFFS_CACHE_WR
  410. if (fd->cache_page) {
  411. offset = MAX(offset, fd->cache_page->offset + fd->cache_page->size);
  412. }
  413. #endif
  414. }
  415. #if SPIFFS_CACHE_WR
  416. if ((fd->flags & SPIFFS_O_DIRECT) == 0) {
  417. if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) {
  418. // small write, try to cache it
  419. u8_t alloc_cpage = 1;
  420. if (fd->cache_page) {
  421. // have a cached page for this fd already, check cache page boundaries
  422. if (offset < fd->cache_page->offset || // writing before cache
  423. offset > fd->cache_page->offset + fd->cache_page->size || // writing after cache
  424. offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page
  425. {
  426. // boundary violation, write back cache first and allocate new
  427. SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIpg" for fd "_SPIPRIfd":"_SPIPRIid", boundary viol, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
  428. fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
  429. res = spiffs_hydro_write(fs, fd,
  430. spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
  431. fd->cache_page->offset, fd->cache_page->size);
  432. spiffs_cache_fd_release(fs, fd->cache_page);
  433. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  434. } else {
  435. // writing within cache
  436. alloc_cpage = 0;
  437. }
  438. }
  439. if (alloc_cpage) {
  440. fd->cache_page = spiffs_cache_page_allocate_by_fd(fs, fd);
  441. if (fd->cache_page) {
  442. fd->cache_page->offset = offset;
  443. fd->cache_page->size = 0;
  444. SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page "_SPIPRIpg" for fd "_SPIPRIfd":"_SPIPRIid"\n",
  445. fd->cache_page->ix, fd->file_nbr, fd->obj_id);
  446. }
  447. }
  448. if (fd->cache_page) {
  449. u32_t offset_in_cpage = offset - fd->cache_page->offset;
  450. SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page "_SPIPRIpg" for fd "_SPIPRIfd":"_SPIPRIid", offs "_SPIPRIi":"_SPIPRIi" len "_SPIPRIi"\n",
  451. fd->cache_page->ix, fd->file_nbr, fd->obj_id,
  452. offset, offset_in_cpage, len);
  453. spiffs_cache *cache = spiffs_get_cache(fs);
  454. u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix);
  455. memcpy(&cpage_data[offset_in_cpage], buf, len);
  456. fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len);
  457. fd->fdoffset += len;
  458. SPIFFS_UNLOCK(fs);
  459. return len;
  460. } else {
  461. res = spiffs_hydro_write(fs, fd, buf, offset, len);
  462. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  463. fd->fdoffset += len;
  464. SPIFFS_UNLOCK(fs);
  465. return res;
  466. }
  467. } else {
  468. // big write, no need to cache it - but first check if there is a cached write already
  469. if (fd->cache_page) {
  470. // write back cache first
  471. SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIpg" for fd "_SPIPRIfd":"_SPIPRIid", big write, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
  472. fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
  473. res = spiffs_hydro_write(fs, fd,
  474. spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
  475. fd->cache_page->offset, fd->cache_page->size);
  476. spiffs_cache_fd_release(fs, fd->cache_page);
  477. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  478. // data written below
  479. }
  480. }
  481. }
  482. #endif
  483. res = spiffs_hydro_write(fs, fd, buf, offset, len);
  484. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  485. fd->fdoffset += len;
  486. SPIFFS_UNLOCK(fs);
  487. return res;
  488. #endif // SPIFFS_READ_ONLY
  489. }
  490. s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
  491. SPIFFS_API_CHECK_CFG(fs);
  492. SPIFFS_API_CHECK_MOUNT(fs);
  493. SPIFFS_LOCK(fs);
  494. spiffs_fd *fd;
  495. s32_t res;
  496. fh = SPIFFS_FH_UNOFFS(fs, fh);
  497. res = spiffs_fd_get(fs, fh, &fd);
  498. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  499. #if SPIFFS_CACHE_WR
  500. spiffs_fflush_cache(fs, fh);
  501. #endif
  502. s32_t fileSize = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;
  503. switch (whence) {
  504. case SPIFFS_SEEK_CUR:
  505. offs = fd->fdoffset+offs;
  506. break;
  507. case SPIFFS_SEEK_END:
  508. offs = fileSize + offs;
  509. break;
  510. }
  511. if ((offs > fileSize)) {
  512. fd->fdoffset = fileSize;
  513. res = SPIFFS_ERR_END_OF_OBJECT;
  514. }
  515. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  516. spiffs_span_ix data_spix = offs / SPIFFS_DATA_PAGE_SIZE(fs);
  517. spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  518. if (fd->cursor_objix_spix != objix_spix) {
  519. spiffs_page_ix pix;
  520. res = spiffs_obj_lu_find_id_and_span(
  521. fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, &pix);
  522. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  523. fd->cursor_objix_spix = objix_spix;
  524. fd->cursor_objix_pix = pix;
  525. }
  526. fd->fdoffset = offs;
  527. SPIFFS_UNLOCK(fs);
  528. return offs;
  529. }
  530. s32_t SPIFFS_remove(spiffs *fs, const char *path) {
  531. #if SPIFFS_READ_ONLY
  532. (void)fs; (void)path;
  533. return SPIFFS_ERR_RO_NOT_IMPL;
  534. #else
  535. SPIFFS_API_CHECK_CFG(fs);
  536. SPIFFS_API_CHECK_MOUNT(fs);
  537. if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
  538. SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
  539. }
  540. SPIFFS_LOCK(fs);
  541. spiffs_fd *fd;
  542. spiffs_page_ix pix;
  543. s32_t res;
  544. res = spiffs_fd_find_new(fs, &fd, 0);
  545. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  546. res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);
  547. if (res != SPIFFS_OK) {
  548. spiffs_fd_return(fs, fd->file_nbr);
  549. }
  550. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  551. res = spiffs_object_open_by_page(fs, pix, fd, 0,0);
  552. if (res != SPIFFS_OK) {
  553. spiffs_fd_return(fs, fd->file_nbr);
  554. }
  555. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  556. res = spiffs_object_truncate(fd, 0, 1);
  557. if (res != SPIFFS_OK) {
  558. spiffs_fd_return(fs, fd->file_nbr);
  559. }
  560. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  561. SPIFFS_UNLOCK(fs);
  562. return 0;
  563. #endif // SPIFFS_READ_ONLY
  564. }
  565. s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
  566. #if SPIFFS_READ_ONLY
  567. (void)fs; (void)fh;
  568. return SPIFFS_ERR_RO_NOT_IMPL;
  569. #else
  570. SPIFFS_API_CHECK_CFG(fs);
  571. SPIFFS_API_CHECK_MOUNT(fs);
  572. SPIFFS_LOCK(fs);
  573. spiffs_fd *fd;
  574. s32_t res;
  575. fh = SPIFFS_FH_UNOFFS(fs, fh);
  576. res = spiffs_fd_get(fs, fh, &fd);
  577. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  578. if ((fd->flags & SPIFFS_O_WRONLY) == 0) {
  579. res = SPIFFS_ERR_NOT_WRITABLE;
  580. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  581. }
  582. #if SPIFFS_CACHE_WR
  583. spiffs_cache_fd_release(fs, fd->cache_page);
  584. #endif
  585. res = spiffs_object_truncate(fd, 0, 1);
  586. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  587. SPIFFS_UNLOCK(fs);
  588. return 0;
  589. #endif // SPIFFS_READ_ONLY
  590. }
  591. static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) {
  592. (void)fh;
  593. spiffs_page_object_ix_header objix_hdr;
  594. spiffs_obj_id obj_id;
  595. s32_t res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh,
  596. SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
  597. SPIFFS_API_CHECK_RES(fs, res);
  598. u32_t obj_id_addr = SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs , pix)) +
  599. SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_obj_id);
  600. res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, fh,
  601. obj_id_addr, sizeof(spiffs_obj_id), (u8_t *)&obj_id);
  602. SPIFFS_API_CHECK_RES(fs, res);
  603. s->obj_id = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  604. s->type = objix_hdr.type;
  605. s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;
  606. s->pix = pix;
  607. strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN);
  608. #if SPIFFS_OBJ_META_LEN
  609. memcpy(s->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);
  610. #endif
  611. return res;
  612. }
  613. s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) {
  614. SPIFFS_API_CHECK_CFG(fs);
  615. SPIFFS_API_CHECK_MOUNT(fs);
  616. if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
  617. SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
  618. }
  619. SPIFFS_LOCK(fs);
  620. s32_t res;
  621. spiffs_page_ix pix;
  622. res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix);
  623. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  624. res = spiffs_stat_pix(fs, pix, 0, s);
  625. SPIFFS_UNLOCK(fs);
  626. return res;
  627. }
  628. s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {
  629. SPIFFS_API_CHECK_CFG(fs);
  630. SPIFFS_API_CHECK_MOUNT(fs);
  631. SPIFFS_LOCK(fs);
  632. spiffs_fd *fd;
  633. s32_t res;
  634. fh = SPIFFS_FH_UNOFFS(fs, fh);
  635. res = spiffs_fd_get(fs, fh, &fd);
  636. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  637. #if SPIFFS_CACHE_WR
  638. spiffs_fflush_cache(fs, fh);
  639. #endif
  640. res = spiffs_stat_pix(fs, fd->objix_hdr_pix, fh, s);
  641. SPIFFS_UNLOCK(fs);
  642. return res;
  643. }
  644. // Checks if there are any cached writes for the object id associated with
  645. // given filehandle. If so, these writes are flushed.
  646. #if SPIFFS_CACHE == 1
  647. static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
  648. (void)fs;
  649. (void)fh;
  650. s32_t res = SPIFFS_OK;
  651. #if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR
  652. spiffs_fd *fd;
  653. res = spiffs_fd_get(fs, fh, &fd);
  654. SPIFFS_API_CHECK_RES(fs, res);
  655. if ((fd->flags & SPIFFS_O_DIRECT) == 0) {
  656. if (fd->cache_page == 0) {
  657. // see if object id is associated with cache already
  658. fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
  659. }
  660. if (fd->cache_page) {
  661. SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIpg" for fd "_SPIPRIfd":"_SPIPRIid", flush, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
  662. fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
  663. res = spiffs_hydro_write(fs, fd,
  664. spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
  665. fd->cache_page->offset, fd->cache_page->size);
  666. if (res < SPIFFS_OK) {
  667. fs->err_code = res;
  668. }
  669. spiffs_cache_fd_release(fs, fd->cache_page);
  670. }
  671. }
  672. #endif
  673. return res;
  674. }
  675. #endif
  676. s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
  677. (void)fh;
  678. SPIFFS_API_CHECK_CFG(fs);
  679. SPIFFS_API_CHECK_MOUNT(fs);
  680. s32_t res = SPIFFS_OK;
  681. #if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR
  682. SPIFFS_LOCK(fs);
  683. fh = SPIFFS_FH_UNOFFS(fs, fh);
  684. res = spiffs_fflush_cache(fs, fh);
  685. SPIFFS_API_CHECK_RES_UNLOCK(fs,res);
  686. SPIFFS_UNLOCK(fs);
  687. #endif
  688. return res;
  689. }
  690. s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) {
  691. SPIFFS_API_CHECK_CFG(fs);
  692. SPIFFS_API_CHECK_MOUNT(fs);
  693. s32_t res = SPIFFS_OK;
  694. SPIFFS_LOCK(fs);
  695. fh = SPIFFS_FH_UNOFFS(fs, fh);
  696. #if SPIFFS_CACHE
  697. res = spiffs_fflush_cache(fs, fh);
  698. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  699. #endif
  700. res = spiffs_fd_return(fs, fh);
  701. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  702. SPIFFS_UNLOCK(fs);
  703. return res;
  704. }
  705. s32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) {
  706. #if SPIFFS_READ_ONLY
  707. (void)fs; (void)old_path; (void)new_path;
  708. return SPIFFS_ERR_RO_NOT_IMPL;
  709. #else
  710. SPIFFS_API_CHECK_CFG(fs);
  711. SPIFFS_API_CHECK_MOUNT(fs);
  712. if (strlen(new_path) > SPIFFS_OBJ_NAME_LEN - 1 ||
  713. strlen(old_path) > SPIFFS_OBJ_NAME_LEN - 1) {
  714. SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
  715. }
  716. SPIFFS_LOCK(fs);
  717. spiffs_page_ix pix_old, pix_dummy;
  718. spiffs_fd *fd;
  719. s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)old_path, &pix_old);
  720. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  721. res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)new_path, &pix_dummy);
  722. if (res == SPIFFS_ERR_NOT_FOUND) {
  723. res = SPIFFS_OK;
  724. } else if (res == SPIFFS_OK) {
  725. res = SPIFFS_ERR_CONFLICTING_NAME;
  726. }
  727. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  728. res = spiffs_fd_find_new(fs, &fd, 0);
  729. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  730. res = spiffs_object_open_by_page(fs, pix_old, fd, 0, 0);
  731. if (res != SPIFFS_OK) {
  732. spiffs_fd_return(fs, fd->file_nbr);
  733. }
  734. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  735. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (const u8_t*)new_path,
  736. 0, 0, &pix_dummy);
  737. #if SPIFFS_TEMPORAL_FD_CACHE
  738. if (res == SPIFFS_OK) {
  739. spiffs_fd_temporal_cache_rehash(fs, old_path, new_path);
  740. }
  741. #endif
  742. spiffs_fd_return(fs, fd->file_nbr);
  743. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  744. SPIFFS_UNLOCK(fs);
  745. return res;
  746. #endif // SPIFFS_READ_ONLY
  747. }
  748. #if SPIFFS_OBJ_META_LEN
  749. s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta) {
  750. #if SPIFFS_READ_ONLY
  751. (void)fs; (void)name; (void)meta;
  752. return SPIFFS_ERR_RO_NOT_IMPL;
  753. #else
  754. SPIFFS_API_CHECK_CFG(fs);
  755. SPIFFS_API_CHECK_MOUNT(fs);
  756. SPIFFS_LOCK(fs);
  757. spiffs_page_ix pix, pix_dummy;
  758. spiffs_fd *fd;
  759. s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)name, &pix);
  760. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  761. res = spiffs_fd_find_new(fs, &fd, 0);
  762. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  763. res = spiffs_object_open_by_page(fs, pix, fd, 0, 0);
  764. if (res != SPIFFS_OK) {
  765. spiffs_fd_return(fs, fd->file_nbr);
  766. }
  767. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  768. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta,
  769. 0, &pix_dummy);
  770. spiffs_fd_return(fs, fd->file_nbr);
  771. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  772. SPIFFS_UNLOCK(fs);
  773. return res;
  774. #endif // SPIFFS_READ_ONLY
  775. }
  776. s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta) {
  777. #if SPIFFS_READ_ONLY
  778. (void)fs; (void)fh; (void)meta;
  779. return SPIFFS_ERR_RO_NOT_IMPL;
  780. #else
  781. SPIFFS_API_CHECK_CFG(fs);
  782. SPIFFS_API_CHECK_MOUNT(fs);
  783. SPIFFS_LOCK(fs);
  784. s32_t res;
  785. spiffs_fd *fd;
  786. spiffs_page_ix pix_dummy;
  787. fh = SPIFFS_FH_UNOFFS(fs, fh);
  788. res = spiffs_fd_get(fs, fh, &fd);
  789. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  790. if ((fd->flags & SPIFFS_O_WRONLY) == 0) {
  791. res = SPIFFS_ERR_NOT_WRITABLE;
  792. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  793. }
  794. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta,
  795. 0, &pix_dummy);
  796. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  797. SPIFFS_UNLOCK(fs);
  798. return res;
  799. #endif // SPIFFS_READ_ONLY
  800. }
  801. #endif // SPIFFS_OBJ_META_LEN
  802. spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) {
  803. (void)name;
  804. if (!SPIFFS_CHECK_CFG((fs))) {
  805. (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED;
  806. return 0;
  807. }
  808. if (!SPIFFS_CHECK_MOUNT(fs)) {
  809. fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
  810. return 0;
  811. }
  812. d->fs = fs;
  813. d->block = 0;
  814. d->entry = 0;
  815. return d;
  816. }
  817. static s32_t spiffs_read_dir_v(
  818. spiffs *fs,
  819. spiffs_obj_id obj_id,
  820. spiffs_block_ix bix,
  821. int ix_entry,
  822. const void *user_const_p,
  823. void *user_var_p) {
  824. (void)user_const_p;
  825. s32_t res;
  826. spiffs_page_object_ix_header objix_hdr;
  827. if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED ||
  828. (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {
  829. return SPIFFS_VIS_COUNTINUE;
  830. }
  831. spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
  832. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  833. 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
  834. if (res != SPIFFS_OK) return res;
  835. if ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) &&
  836. objix_hdr.p_hdr.span_ix == 0 &&
  837. (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
  838. (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
  839. struct spiffs_dirent *e = (struct spiffs_dirent*)user_var_p;
  840. e->obj_id = obj_id;
  841. strcpy((char *)e->name, (char *)objix_hdr.name);
  842. e->type = objix_hdr.type;
  843. e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;
  844. e->pix = pix;
  845. #if SPIFFS_OBJ_META_LEN
  846. memcpy(e->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);
  847. #endif
  848. return SPIFFS_OK;
  849. }
  850. return SPIFFS_VIS_COUNTINUE;
  851. }
  852. struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
  853. if (!SPIFFS_CHECK_MOUNT(d->fs)) {
  854. d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
  855. return 0;
  856. }
  857. SPIFFS_LOCK(d->fs);
  858. spiffs_block_ix bix;
  859. int entry;
  860. s32_t res;
  861. struct spiffs_dirent *ret = 0;
  862. res = spiffs_obj_lu_find_entry_visitor(d->fs,
  863. d->block,
  864. d->entry,
  865. SPIFFS_VIS_NO_WRAP,
  866. 0,
  867. spiffs_read_dir_v,
  868. 0,
  869. e,
  870. &bix,
  871. &entry);
  872. if (res == SPIFFS_OK) {
  873. d->block = bix;
  874. d->entry = entry + 1;
  875. e->obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
  876. ret = e;
  877. } else {
  878. d->fs->err_code = res;
  879. }
  880. SPIFFS_UNLOCK(d->fs);
  881. return ret;
  882. }
  883. s32_t SPIFFS_closedir(spiffs_DIR *d) {
  884. SPIFFS_API_CHECK_CFG(d->fs);
  885. SPIFFS_API_CHECK_MOUNT(d->fs);
  886. return 0;
  887. }
  888. s32_t SPIFFS_check(spiffs *fs) {
  889. #if SPIFFS_READ_ONLY
  890. (void)fs;
  891. return SPIFFS_ERR_RO_NOT_IMPL;
  892. #else
  893. s32_t res;
  894. SPIFFS_API_CHECK_CFG(fs);
  895. SPIFFS_API_CHECK_MOUNT(fs);
  896. SPIFFS_LOCK(fs);
  897. res = spiffs_lookup_consistency_check(fs, 0);
  898. res = spiffs_object_index_consistency_check(fs);
  899. res = spiffs_page_consistency_check(fs);
  900. res = spiffs_obj_lu_scan(fs);
  901. SPIFFS_UNLOCK(fs);
  902. return res;
  903. #endif // SPIFFS_READ_ONLY
  904. }
  905. s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
  906. s32_t res = SPIFFS_OK;
  907. SPIFFS_API_CHECK_CFG(fs);
  908. SPIFFS_API_CHECK_MOUNT(fs);
  909. SPIFFS_LOCK(fs);
  910. u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs);
  911. u32_t blocks = fs->block_count;
  912. u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs);
  913. u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs);
  914. u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page
  915. if (total) {
  916. *total = total_data_pages * data_page_size;
  917. }
  918. if (used) {
  919. *used = fs->stats_p_allocated * data_page_size;
  920. }
  921. SPIFFS_UNLOCK(fs);
  922. return res;
  923. }
  924. s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) {
  925. #if SPIFFS_READ_ONLY
  926. (void)fs; (void)max_free_pages;
  927. return SPIFFS_ERR_RO_NOT_IMPL;
  928. #else
  929. s32_t res;
  930. SPIFFS_API_CHECK_CFG(fs);
  931. SPIFFS_API_CHECK_MOUNT(fs);
  932. SPIFFS_LOCK(fs);
  933. res = spiffs_gc_quick(fs, max_free_pages);
  934. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  935. SPIFFS_UNLOCK(fs);
  936. return 0;
  937. #endif // SPIFFS_READ_ONLY
  938. }
  939. s32_t SPIFFS_gc(spiffs *fs, u32_t size) {
  940. #if SPIFFS_READ_ONLY
  941. (void)fs; (void)size;
  942. return SPIFFS_ERR_RO_NOT_IMPL;
  943. #else
  944. s32_t res;
  945. SPIFFS_API_CHECK_CFG(fs);
  946. SPIFFS_API_CHECK_MOUNT(fs);
  947. SPIFFS_LOCK(fs);
  948. res = spiffs_gc_check(fs, size);
  949. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  950. SPIFFS_UNLOCK(fs);
  951. return 0;
  952. #endif // SPIFFS_READ_ONLY
  953. }
  954. s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
  955. s32_t res;
  956. SPIFFS_API_CHECK_CFG(fs);
  957. SPIFFS_API_CHECK_MOUNT(fs);
  958. SPIFFS_LOCK(fs);
  959. fh = SPIFFS_FH_UNOFFS(fs, fh);
  960. spiffs_fd *fd;
  961. res = spiffs_fd_get(fs, fh, &fd);
  962. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  963. #if SPIFFS_CACHE_WR
  964. res = spiffs_fflush_cache(fs, fh);
  965. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  966. #endif
  967. res = (fd->fdoffset >= (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size));
  968. SPIFFS_UNLOCK(fs);
  969. return res;
  970. }
  971. s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {
  972. s32_t res;
  973. SPIFFS_API_CHECK_CFG(fs);
  974. SPIFFS_API_CHECK_MOUNT(fs);
  975. SPIFFS_LOCK(fs);
  976. fh = SPIFFS_FH_UNOFFS(fs, fh);
  977. spiffs_fd *fd;
  978. res = spiffs_fd_get(fs, fh, &fd);
  979. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  980. #if SPIFFS_CACHE_WR
  981. res = spiffs_fflush_cache(fs, fh);
  982. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  983. #endif
  984. res = fd->fdoffset;
  985. SPIFFS_UNLOCK(fs);
  986. return res;
  987. }
  988. s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) {
  989. SPIFFS_LOCK(fs);
  990. fs->file_cb_f = cb_func;
  991. SPIFFS_UNLOCK(fs);
  992. return 0;
  993. }
  994. #if SPIFFS_IX_MAP
  995. s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,
  996. u32_t offset, u32_t len, spiffs_page_ix *map_buf) {
  997. s32_t res;
  998. SPIFFS_API_CHECK_CFG(fs);
  999. SPIFFS_API_CHECK_MOUNT(fs);
  1000. SPIFFS_LOCK(fs);
  1001. fh = SPIFFS_FH_UNOFFS(fs, fh);
  1002. spiffs_fd *fd;
  1003. res = spiffs_fd_get(fs, fh, &fd);
  1004. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  1005. if (fd->ix_map) {
  1006. SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_MAPPED);
  1007. }
  1008. map->map_buf = map_buf;
  1009. map->offset = offset;
  1010. // nb: spix range includes last
  1011. map->start_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
  1012. map->end_spix = (offset + len) / SPIFFS_DATA_PAGE_SIZE(fs);
  1013. memset(map_buf, 0, sizeof(spiffs_page_ix) * (map->end_spix - map->start_spix + 1));
  1014. fd->ix_map = map;
  1015. // scan for pixes
  1016. res = spiffs_populate_ix_map(fs, fd, 0, map->end_spix - map->start_spix + 1);
  1017. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  1018. SPIFFS_UNLOCK(fs);
  1019. return res;
  1020. }
  1021. s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh) {
  1022. s32_t res;
  1023. SPIFFS_API_CHECK_CFG(fs);
  1024. SPIFFS_API_CHECK_MOUNT(fs);
  1025. SPIFFS_LOCK(fs);
  1026. fh = SPIFFS_FH_UNOFFS(fs, fh);
  1027. spiffs_fd *fd;
  1028. res = spiffs_fd_get(fs, fh, &fd);
  1029. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  1030. if (fd->ix_map == 0) {
  1031. SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED);
  1032. }
  1033. fd->ix_map = 0;
  1034. SPIFFS_UNLOCK(fs);
  1035. return res;
  1036. }
  1037. s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offset) {
  1038. s32_t res = SPIFFS_OK;
  1039. SPIFFS_API_CHECK_CFG(fs);
  1040. SPIFFS_API_CHECK_MOUNT(fs);
  1041. SPIFFS_LOCK(fs);
  1042. fh = SPIFFS_FH_UNOFFS(fs, fh);
  1043. spiffs_fd *fd;
  1044. res = spiffs_fd_get(fs, fh, &fd);
  1045. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  1046. if (fd->ix_map == 0) {
  1047. SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED);
  1048. }
  1049. spiffs_ix_map *map = fd->ix_map;
  1050. s32_t spix_diff = offset / SPIFFS_DATA_PAGE_SIZE(fs) - map->start_spix;
  1051. map->offset = offset;
  1052. // move existing pixes if within map offs
  1053. if (spix_diff != 0) {
  1054. // move vector
  1055. int i;
  1056. const s32_t vec_len = map->end_spix - map->start_spix + 1; // spix range includes last
  1057. map->start_spix += spix_diff;
  1058. map->end_spix += spix_diff;
  1059. if (spix_diff >= vec_len) {
  1060. // moving beyond range
  1061. memset(&map->map_buf, 0, vec_len * sizeof(spiffs_page_ix));
  1062. // populate_ix_map is inclusive
  1063. res = spiffs_populate_ix_map(fs, fd, 0, vec_len-1);
  1064. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  1065. } else if (spix_diff > 0) {
  1066. // diff positive
  1067. for (i = 0; i < vec_len - spix_diff; i++) {
  1068. map->map_buf[i] = map->map_buf[i + spix_diff];
  1069. }
  1070. // memset is non-inclusive
  1071. memset(&map->map_buf[vec_len - spix_diff], 0, spix_diff * sizeof(spiffs_page_ix));
  1072. // populate_ix_map is inclusive
  1073. res = spiffs_populate_ix_map(fs, fd, vec_len - spix_diff, vec_len-1);
  1074. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  1075. } else {
  1076. // diff negative
  1077. for (i = vec_len - 1; i >= -spix_diff; i--) {
  1078. map->map_buf[i] = map->map_buf[i + spix_diff];
  1079. }
  1080. // memset is non-inclusive
  1081. memset(&map->map_buf[0], 0, -spix_diff * sizeof(spiffs_page_ix));
  1082. // populate_ix_map is inclusive
  1083. res = spiffs_populate_ix_map(fs, fd, 0, -spix_diff - 1);
  1084. SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
  1085. }
  1086. }
  1087. SPIFFS_UNLOCK(fs);
  1088. return res;
  1089. }
  1090. s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes) {
  1091. SPIFFS_API_CHECK_CFG(fs);
  1092. // always add one extra page, the offset might change to the middle of a page
  1093. return (bytes + SPIFFS_DATA_PAGE_SIZE(fs) ) / SPIFFS_DATA_PAGE_SIZE(fs);
  1094. }
  1095. s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries) {
  1096. SPIFFS_API_CHECK_CFG(fs);
  1097. return map_page_ix_entries * SPIFFS_DATA_PAGE_SIZE(fs);
  1098. }
  1099. #endif // SPIFFS_IX_MAP
  1100. #if SPIFFS_TEST_VISUALISATION
  1101. s32_t SPIFFS_vis(spiffs *fs) {
  1102. s32_t res = SPIFFS_OK;
  1103. SPIFFS_API_CHECK_CFG(fs);
  1104. SPIFFS_API_CHECK_MOUNT(fs);
  1105. SPIFFS_LOCK(fs);
  1106. int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
  1107. spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
  1108. spiffs_block_ix bix = 0;
  1109. while (bix < fs->block_count) {
  1110. // check each object lookup page
  1111. int obj_lookup_page = 0;
  1112. int cur_entry = 0;
  1113. while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
  1114. int entry_offset = obj_lookup_page * entries_per_page;
  1115. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
  1116. 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
  1117. // check each entry
  1118. while (res == SPIFFS_OK &&
  1119. cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
  1120. spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
  1121. if (cur_entry == 0) {
  1122. spiffs_printf(_SPIPRIbl" ", bix);
  1123. } else if ((cur_entry & 0x3f) == 0) {
  1124. spiffs_printf(" ");
  1125. }
  1126. if (obj_id == SPIFFS_OBJ_ID_FREE) {
  1127. spiffs_printf(SPIFFS_TEST_VIS_FREE_STR);
  1128. } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
  1129. spiffs_printf(SPIFFS_TEST_VIS_DELE_STR);
  1130. } else if (obj_id & SPIFFS_OBJ_ID_IX_FLAG){
  1131. spiffs_printf(SPIFFS_TEST_VIS_INDX_STR(obj_id));
  1132. } else {
  1133. spiffs_printf(SPIFFS_TEST_VIS_DATA_STR(obj_id));
  1134. }
  1135. cur_entry++;
  1136. if ((cur_entry & 0x3f) == 0) {
  1137. spiffs_printf("\n");
  1138. }
  1139. } // per entry
  1140. obj_lookup_page++;
  1141. } // per object lookup page
  1142. spiffs_obj_id erase_count;
  1143. res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
  1144. SPIFFS_ERASE_COUNT_PADDR(fs, bix),
  1145. sizeof(spiffs_obj_id), (u8_t *)&erase_count);
  1146. SPIFFS_CHECK_RES(res);
  1147. if (erase_count != (spiffs_obj_id)-1) {
  1148. spiffs_printf("\tera_cnt: "_SPIPRIi"\n", erase_count);
  1149. } else {
  1150. spiffs_printf("\tera_cnt: N/A\n");
  1151. }
  1152. bix++;
  1153. } // per block
  1154. spiffs_printf("era_cnt_max: "_SPIPRIi"\n", fs->max_erase_count);
  1155. spiffs_printf("last_errno: "_SPIPRIi"\n", fs->err_code);
  1156. spiffs_printf("blocks: "_SPIPRIi"\n", fs->block_count);
  1157. spiffs_printf("free_blocks: "_SPIPRIi"\n", fs->free_blocks);
  1158. spiffs_printf("page_alloc: "_SPIPRIi"\n", fs->stats_p_allocated);
  1159. spiffs_printf("page_delet: "_SPIPRIi"\n", fs->stats_p_deleted);
  1160. SPIFFS_UNLOCK(fs);
  1161. u32_t total, used;
  1162. SPIFFS_info(fs, &total, &used);
  1163. spiffs_printf("used: "_SPIPRIi" of "_SPIPRIi"\n", used, total);
  1164. return res;
  1165. }
  1166. #endif