spiffs.c 16 KB

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