spiffs.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. #include <stdio.h>
  2. #include "platform.h"
  3. #include "spiffs.h"
  4. /*
  5. * With the intoduction of a unified FatFS and SPIFFS support (#1397), the SPIFFS
  6. * interface is now abstracted through a uses a single SPIFFS entry point
  7. * myspiffs_realm() which returns a vfs_fs_fns object (as does myfatfs_realm()).
  8. * All other functions and data are static.
  9. *
  10. * Non-OS SDK V3.0 introduces a flash partition table (PT) and SPIFFS has now been
  11. * updated to support this:
  12. * - SPIFFS limits search to the specifed SPIFFS0 address and size.
  13. * - Any headroom / offset from other partitions is reflected in the PT allocations.
  14. * - Unforced mounts will attempt to mount any valid SPIFSS found in this range
  15. * (NodeMCU uses the SPIFFS_USE_MAGIC setting to make existing FS discoverable).
  16. * - Subject to the following, no offset or FS search is done. The FS is assumed
  17. * to be at the first valid location at the start of the partition.
  18. */
  19. #include "spiffs_nucleus.h"
  20. static spiffs fs;
  21. static void (*automounter)();
  22. #define LOG_PAGE_SIZE 256
  23. #define LOG_BLOCK_SIZE (INTERNAL_FLASH_SECTOR_SIZE * 2)
  24. #define LOG_BLOCK_SIZE_SMALL_FS (INTERNAL_FLASH_SECTOR_SIZE)
  25. #define MIN_BLOCKS_FS 4
  26. #define MASK_1MB (0x100000-1)
  27. #define ALIGN (0x2000)
  28. static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
  29. static u8_t spiffs_fds[sizeof(spiffs_fd) * SPIFFS_MAX_OPEN_FILES];
  30. #if SPIFFS_CACHE
  31. static u8_t myspiffs_cache[20 + (LOG_PAGE_SIZE+20)*4];
  32. #endif
  33. static s32_t my_spiffs_read(u32_t addr, u32_t size, u8_t *dst) {
  34. platform_flash_read(dst, addr, size);
  35. return SPIFFS_OK;
  36. }
  37. static s32_t my_spiffs_write(u32_t addr, u32_t size, u8_t *src) {
  38. platform_flash_write(src, addr, size);
  39. return SPIFFS_OK;
  40. }
  41. static int erase_cnt = -1; // If set to >=0 then erasing gives a ... feedback
  42. static s32_t my_spiffs_erase(u32_t addr, u32_t size) {
  43. u32_t sect_first = platform_flash_get_sector_of_address(addr);
  44. u32_t sect_last = sect_first;
  45. while( sect_first <= sect_last ) {
  46. if (erase_cnt >= 0 && (erase_cnt++ & 0xF) == 0) {
  47. dbg_printf(".");
  48. }
  49. if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR ) {
  50. return SPIFFS_ERR_INTERNAL;
  51. }
  52. }
  53. return SPIFFS_OK;
  54. }
  55. void myspiffs_check_callback(spiffs_check_type type, spiffs_check_report report, u32_t arg1, u32_t arg2){
  56. // if(SPIFFS_CHECK_PROGRESS == report) return;
  57. // NODE_ERR("type: %d, report: %d, arg1: %d, arg2: %d\n", type, report, arg1, arg2);
  58. }
  59. /*******************
  60. * Note that the W25Q32BV array is organized into 16,384 programmable pages of 256-bytes 
  61. * each. Up to 256 bytes can be programmed at a time. Pages can be erased in groups of 
  62. * 16 (4KB sector erase), groups of 128 (32KB block erase), groups of 256 (64KB block 
  63. * erase) or the entire chip (chip erase). The W25Q32BV has 1,024 erasable sectors and 
  64. * 64 erasable blocks respectively. The small 4KB sectors allow for greater flexibility 
  65. * in applications that require data and parameter storage. 
  66. *
  67. * Returns TRUE if FS was found.
  68. */
  69. static bool myspiffs_set_cfg(spiffs_config *cfg, bool force_create) {
  70. uint32 pt_start, pt_size, pt_end;
  71. pt_size = platform_flash_get_partition (NODEMCU_SPIFFS0_PARTITION, &pt_start);
  72. if (pt_size == 0) {
  73. return FALSE;
  74. }
  75. pt_end = pt_start + pt_size;
  76. cfg->hal_read_f = my_spiffs_read;
  77. cfg->hal_write_f = my_spiffs_write;
  78. cfg->hal_erase_f = my_spiffs_erase;
  79. cfg->phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE;
  80. cfg->log_page_size = LOG_PAGE_SIZE;
  81. cfg->phys_addr = (pt_start + ALIGN - 1) & ~(ALIGN - 1);
  82. cfg->phys_size = (pt_end & ~(ALIGN - 1)) - cfg->phys_addr;
  83. if (cfg->phys_size < MIN_BLOCKS_FS * LOG_BLOCK_SIZE_SMALL_FS) {
  84. return FALSE;
  85. } else if (cfg->phys_size < MIN_BLOCKS_FS * LOG_BLOCK_SIZE) {
  86. cfg->log_block_size = LOG_BLOCK_SIZE_SMALL_FS;
  87. } else {
  88. cfg->log_block_size = LOG_BLOCK_SIZE;
  89. }
  90. #ifdef SPIFFS_USE_MAGIC_LENGTH
  91. if (!force_create) {
  92. int size = SPIFFS_probe_fs(cfg);
  93. if (size > 0 && size < cfg->phys_size) {
  94. NODE_DBG("Overriding size:%x\n",size);
  95. cfg->phys_size = size;
  96. }
  97. if (size <= 0) {
  98. return FALSE;
  99. }
  100. }
  101. #endif
  102. NODE_DBG("myspiffs set cfg block: %x %x %x %x %x %x\n", pt_start, pt_end,
  103. cfg->phys_size, cfg->phys_addr, cfg->phys_size, cfg->log_block_size);
  104. return TRUE;
  105. }
  106. static bool myspiffs_mount(bool force_mount) {
  107. STARTUP_COUNT;
  108. spiffs_config cfg;
  109. if (!myspiffs_set_cfg(&cfg, force_mount) && !force_mount) {
  110. return FALSE;
  111. }
  112. fs.err_code = 0;
  113. int res = SPIFFS_mount(&fs,
  114. &cfg,
  115. spiffs_work_buf,
  116. spiffs_fds,
  117. sizeof(spiffs_fds),
  118. #if SPIFFS_CACHE
  119. myspiffs_cache,
  120. sizeof(myspiffs_cache),
  121. #else
  122. 0, 0,
  123. #endif
  124. // myspiffs_check_callback);
  125. 0);
  126. NODE_DBG("mount res: %d, %d\n", res, fs.err_code);
  127. STARTUP_COUNT;
  128. return res == SPIFFS_OK;
  129. }
  130. void myspiffs_unmount() {
  131. SPIFFS_unmount(&fs);
  132. }
  133. // FS formatting function
  134. // Returns 1 if OK, 0 for error
  135. int myspiffs_format( void )
  136. {
  137. SPIFFS_unmount(&fs);
  138. myspiffs_mount(TRUE);
  139. SPIFFS_unmount(&fs);
  140. NODE_DBG("Formatting: size 0x%x, addr 0x%x\n", fs.cfg.phys_size, fs.cfg.phys_addr);
  141. erase_cnt = 0;
  142. int status = SPIFFS_format(&fs);
  143. erase_cnt = -1;
  144. return status < 0 ? 0 : myspiffs_mount(FALSE);
  145. }
  146. // ***************************************************************************
  147. // vfs API
  148. // ***************************************************************************
  149. #include <stdlib.h>
  150. #include "vfs_int.h"
  151. #define MY_LDRV_ID "FLASH"
  152. // default current drive
  153. static int is_current_drive = TRUE;
  154. // forward declarations
  155. static sint32_t myspiffs_vfs_close( const struct vfs_file *fd );
  156. static sint32_t myspiffs_vfs_read( const struct vfs_file *fd, void *ptr, size_t len );
  157. static sint32_t myspiffs_vfs_write( const struct vfs_file *fd, const void *ptr, size_t len );
  158. static sint32_t myspiffs_vfs_lseek( const struct vfs_file *fd, sint32_t off, int whence );
  159. static sint32_t myspiffs_vfs_eof( const struct vfs_file *fd );
  160. static sint32_t myspiffs_vfs_tell( const struct vfs_file *fd );
  161. static sint32_t myspiffs_vfs_flush( const struct vfs_file *fd );
  162. static uint32_t myspiffs_vfs_size( const struct vfs_file *fd );
  163. static sint32_t myspiffs_vfs_ferrno( const struct vfs_file *fd );
  164. static sint32_t myspiffs_vfs_closedir( const struct vfs_dir *dd );
  165. static sint32_t myspiffs_vfs_readdir( const struct vfs_dir *dd, struct vfs_stat *buf );
  166. static vfs_vol *myspiffs_vfs_mount( const char *name, int num );
  167. static vfs_file *myspiffs_vfs_open( const char *name, const char *mode );
  168. static vfs_dir *myspiffs_vfs_opendir( const char *name );
  169. static sint32_t myspiffs_vfs_stat( const char *name, struct vfs_stat *buf );
  170. static sint32_t myspiffs_vfs_remove( const char *name );
  171. static sint32_t myspiffs_vfs_rename( const char *oldname, const char *newname );
  172. static sint32_t myspiffs_vfs_fsinfo( uint32_t *total, uint32_t *used );
  173. static sint32_t myspiffs_vfs_fscfg( uint32_t *phys_addr, uint32_t *phys_size );
  174. static sint32_t myspiffs_vfs_format( void );
  175. static sint32_t myspiffs_vfs_errno( void );
  176. static void myspiffs_vfs_clearerr( void );
  177. static sint32_t myspiffs_vfs_umount( const struct vfs_vol *vol );
  178. // ---------------------------------------------------------------------------
  179. // function tables
  180. //
  181. static vfs_fs_fns myspiffs_fs_fns = {
  182. .mount = myspiffs_vfs_mount,
  183. .open = myspiffs_vfs_open,
  184. .opendir = myspiffs_vfs_opendir,
  185. .stat = myspiffs_vfs_stat,
  186. .remove = myspiffs_vfs_remove,
  187. .rename = myspiffs_vfs_rename,
  188. .mkdir = NULL,
  189. .fsinfo = myspiffs_vfs_fsinfo,
  190. .fscfg = myspiffs_vfs_fscfg,
  191. .format = myspiffs_vfs_format,
  192. .chdrive = NULL,
  193. .chdir = NULL,
  194. .ferrno = myspiffs_vfs_errno,
  195. .clearerr = myspiffs_vfs_clearerr
  196. };
  197. static vfs_file_fns myspiffs_file_fns = {
  198. .close = myspiffs_vfs_close,
  199. .read = myspiffs_vfs_read,
  200. .write = myspiffs_vfs_write,
  201. .lseek = myspiffs_vfs_lseek,
  202. .eof = myspiffs_vfs_eof,
  203. .tell = myspiffs_vfs_tell,
  204. .flush = myspiffs_vfs_flush,
  205. .size = myspiffs_vfs_size,
  206. .ferrno = myspiffs_vfs_ferrno
  207. };
  208. static vfs_dir_fns myspiffs_dd_fns = {
  209. .close = myspiffs_vfs_closedir,
  210. .readdir = myspiffs_vfs_readdir
  211. };
  212. // ---------------------------------------------------------------------------
  213. // specific struct extensions
  214. //
  215. struct myvfs_file {
  216. struct vfs_file vfs_file;
  217. spiffs_file fh;
  218. };
  219. struct myvfs_dir {
  220. struct vfs_dir vfs_dir;
  221. spiffs_DIR d;
  222. };
  223. // ---------------------------------------------------------------------------
  224. // volume functions
  225. //
  226. static sint32_t myspiffs_vfs_umount( const struct vfs_vol *vol ) {
  227. // not implemented
  228. return VFS_RES_ERR;
  229. }
  230. // ---------------------------------------------------------------------------
  231. // dir functions
  232. //
  233. #define GET_DIR_D(descr) \
  234. const struct myvfs_dir *mydd = (const struct myvfs_dir *)descr; \
  235. spiffs_DIR *d = (spiffs_DIR *)&(mydd->d);
  236. static sint32_t myspiffs_vfs_closedir( const struct vfs_dir *dd ) {
  237. GET_DIR_D(dd);
  238. sint32_t res = SPIFFS_closedir( d );
  239. // free descriptor memory
  240. free( (void *)dd );
  241. }
  242. static sint32_t myspiffs_vfs_readdir( const struct vfs_dir *dd, struct vfs_stat *buf ) {
  243. GET_DIR_D(dd);
  244. struct spiffs_dirent dirent;
  245. if (SPIFFS_readdir( d, &dirent )) {
  246. memset( buf, 0, sizeof( struct vfs_stat ) );
  247. // copy entries to item
  248. // fill in supported stat entries
  249. strncpy( buf->name, dirent.name, FS_OBJ_NAME_LEN+1 );
  250. buf->name[FS_OBJ_NAME_LEN] = '\0';
  251. buf->size = dirent.size;
  252. return VFS_RES_OK;
  253. }
  254. return VFS_RES_ERR;
  255. }
  256. // ---------------------------------------------------------------------------
  257. // file functions
  258. //
  259. #define GET_FILE_FH(descr) \
  260. const struct myvfs_file *myfd = (const struct myvfs_file *)descr; \
  261. spiffs_file fh = myfd->fh;
  262. static sint32_t myspiffs_vfs_close( const struct vfs_file *fd ) {
  263. GET_FILE_FH(fd);
  264. sint32_t res = SPIFFS_close( &fs, fh );
  265. // free descriptor memory
  266. free( (void *)fd );
  267. return res;
  268. }
  269. static sint32_t myspiffs_vfs_read( const struct vfs_file *fd, void *ptr, size_t len ) {
  270. GET_FILE_FH(fd);
  271. sint32_t n = SPIFFS_read( &fs, fh, ptr, len );
  272. return n >= 0 ? n : VFS_RES_ERR;
  273. }
  274. static sint32_t myspiffs_vfs_write( const struct vfs_file *fd, const void *ptr, size_t len ) {
  275. GET_FILE_FH(fd);
  276. sint32_t n = SPIFFS_write( &fs, fh, (void *)ptr, len );
  277. return n >= 0 ? n : VFS_RES_ERR;
  278. }
  279. static sint32_t myspiffs_vfs_lseek( const struct vfs_file *fd, sint32_t off, int whence ) {
  280. GET_FILE_FH(fd);
  281. int spiffs_whence;
  282. switch (whence) {
  283. default:
  284. case VFS_SEEK_SET:
  285. spiffs_whence = SPIFFS_SEEK_SET;
  286. break;
  287. case VFS_SEEK_CUR:
  288. spiffs_whence = SPIFFS_SEEK_CUR;
  289. break;
  290. case VFS_SEEK_END:
  291. spiffs_whence = SPIFFS_SEEK_END;
  292. break;
  293. }
  294. sint32_t res = SPIFFS_lseek( &fs, fh, off, spiffs_whence );
  295. return res >= 0 ? res : VFS_RES_ERR;
  296. }
  297. static sint32_t myspiffs_vfs_eof( const struct vfs_file *fd ) {
  298. GET_FILE_FH(fd);
  299. return SPIFFS_eof( &fs, fh );
  300. }
  301. static sint32_t myspiffs_vfs_tell( const struct vfs_file *fd ) {
  302. GET_FILE_FH(fd);
  303. return SPIFFS_tell( &fs, fh );
  304. }
  305. static sint32_t myspiffs_vfs_flush( const struct vfs_file *fd ) {
  306. GET_FILE_FH(fd);
  307. return SPIFFS_fflush( &fs, fh ) >= 0 ? VFS_RES_OK : VFS_RES_ERR;
  308. }
  309. static uint32_t myspiffs_vfs_size( const struct vfs_file *fd ) {
  310. GET_FILE_FH(fd);
  311. int32_t curpos = SPIFFS_tell( &fs, fh );
  312. int32_t size = SPIFFS_lseek( &fs, fh, 0, SPIFFS_SEEK_END );
  313. (void) SPIFFS_lseek( &fs, fh, curpos, SPIFFS_SEEK_SET );
  314. return size;
  315. }
  316. static sint32_t myspiffs_vfs_ferrno( const struct vfs_file *fd ) {
  317. return SPIFFS_errno( &fs );
  318. }
  319. static int fs_mode2flag(const char *mode){
  320. if(strlen(mode)==1){
  321. if(strcmp(mode,"w")==0)
  322. return SPIFFS_WRONLY|SPIFFS_CREAT|SPIFFS_TRUNC;
  323. else if(strcmp(mode, "r")==0)
  324. return SPIFFS_RDONLY;
  325. else if(strcmp(mode, "a")==0)
  326. return SPIFFS_WRONLY|SPIFFS_CREAT|SPIFFS_APPEND;
  327. else
  328. return SPIFFS_RDONLY;
  329. } else if (strlen(mode)==2){
  330. if(strcmp(mode,"r+")==0)
  331. return SPIFFS_RDWR;
  332. else if(strcmp(mode, "w+")==0)
  333. return SPIFFS_RDWR|SPIFFS_CREAT|SPIFFS_TRUNC;
  334. else if(strcmp(mode, "a+")==0)
  335. return SPIFFS_RDWR|SPIFFS_CREAT|SPIFFS_APPEND;
  336. else
  337. return SPIFFS_RDONLY;
  338. } else {
  339. return SPIFFS_RDONLY;
  340. }
  341. }
  342. // ---------------------------------------------------------------------------
  343. // filesystem functions
  344. //
  345. static vfs_file *myspiffs_vfs_open( const char *name, const char *mode ) {
  346. struct myvfs_file *fd;
  347. int flags = fs_mode2flag( mode );
  348. if (fd = (struct myvfs_file *)malloc( sizeof( struct myvfs_file ) )) {
  349. if (0 < (fd->fh = SPIFFS_open( &fs, name, flags, 0 ))) {
  350. fd->vfs_file.fs_type = VFS_FS_SPIFFS;
  351. fd->vfs_file.fns = &myspiffs_file_fns;
  352. return (vfs_file *)fd;
  353. } else {
  354. free( fd );
  355. }
  356. }
  357. return NULL;
  358. }
  359. static vfs_dir *myspiffs_vfs_opendir( const char *name ){
  360. struct myvfs_dir *dd;
  361. if (dd = (struct myvfs_dir *)malloc( sizeof( struct myvfs_dir ) )) {
  362. if (SPIFFS_opendir( &fs, name, &(dd->d) )) {
  363. dd->vfs_dir.fs_type = VFS_FS_SPIFFS;
  364. dd->vfs_dir.fns = &myspiffs_dd_fns;
  365. return (vfs_dir *)dd;
  366. } else {
  367. free( dd );
  368. }
  369. }
  370. return NULL;
  371. }
  372. static sint32_t myspiffs_vfs_stat( const char *name, struct vfs_stat *buf ) {
  373. spiffs_stat stat;
  374. if (0 <= SPIFFS_stat( &fs, name, &stat )) {
  375. memset( buf, 0, sizeof( struct vfs_stat ) );
  376. // fill in supported stat entries
  377. strncpy( buf->name, stat.name, FS_OBJ_NAME_LEN+1 );
  378. buf->name[FS_OBJ_NAME_LEN] = '\0';
  379. buf->size = stat.size;
  380. return VFS_RES_OK;
  381. } else {
  382. return VFS_RES_ERR;
  383. }
  384. }
  385. static sint32_t myspiffs_vfs_remove( const char *name ) {
  386. return SPIFFS_remove( &fs, name );
  387. }
  388. static sint32_t myspiffs_vfs_rename( const char *oldname, const char *newname ) {
  389. return SPIFFS_rename( &fs, oldname, newname );
  390. }
  391. static sint32_t myspiffs_vfs_fsinfo( uint32_t *total, uint32_t *used ) {
  392. return SPIFFS_info( &fs, total, used );
  393. }
  394. static sint32_t myspiffs_vfs_fscfg( uint32_t *phys_addr, uint32_t *phys_size ) {
  395. *phys_addr = fs.cfg.phys_addr;
  396. *phys_size = fs.cfg.phys_size;
  397. return VFS_RES_OK;
  398. }
  399. static vfs_vol *myspiffs_vfs_mount( const char *name, int num ) {
  400. // volume descriptor not supported, just return TRUE / FALSE
  401. return myspiffs_mount(FALSE) ? (vfs_vol *)1 : NULL;
  402. }
  403. static sint32_t myspiffs_vfs_format( void ) {
  404. return myspiffs_format();
  405. }
  406. static sint32_t myspiffs_vfs_errno( void ) {
  407. return SPIFFS_errno( &fs );
  408. }
  409. static void myspiffs_vfs_clearerr( void ) {
  410. SPIFFS_clearerr( &fs );
  411. }
  412. // The callback will be called on the first file operation
  413. void myspiffs_set_automount(void (*mounter)()) {
  414. automounter = mounter;
  415. }
  416. // ---------------------------------------------------------------------------
  417. // VFS interface functions
  418. //
  419. vfs_fs_fns *myspiffs_realm( const char *inname, char **outname, int set_current_drive ) {
  420. if (automounter) {
  421. void (*mounter)() = automounter;
  422. automounter = NULL;
  423. mounter();
  424. }
  425. if (inname[0] == '/') {
  426. // logical drive is specified, check if it's our id
  427. if (0 == strncmp(inname + 1, MY_LDRV_ID, sizeof(MY_LDRV_ID)-1)) {
  428. *outname = (char *)(inname + sizeof(MY_LDRV_ID));
  429. if (*outname[0] == '/') {
  430. // skip leading /
  431. (*outname)++;
  432. }
  433. if (set_current_drive) is_current_drive = TRUE;
  434. return &myspiffs_fs_fns;
  435. }
  436. } else {
  437. // no logical drive in patchspec, are we current drive?
  438. if (is_current_drive) {
  439. *outname = (char *)inname;
  440. return &myspiffs_fs_fns;
  441. }
  442. }
  443. if (set_current_drive) is_current_drive = FALSE;
  444. return NULL;
  445. }