1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2008-02-22     QiuYi        The first version.
9  * 2011-10-08     Bernard      fixed the block size in statfs.
10  * 2011-11-23     Bernard      fixed the rename issue.
11  * 2012-07-26     aozima       implement ff_memalloc and ff_memfree.
12  * 2012-12-19     Bernard      fixed the O_APPEND and lseek issue.
13  * 2013-03-01     aozima       fixed the stat(st_mtime) issue.
14  * 2014-01-26     Bernard      Check the sector size before mount.
15  * 2017-02-13     Hichard      Update Fatfs version to 0.12b, support exFAT.
16  * 2017-04-11     Bernard      fix the st_blksize issue.
17  * 2017-05-26     Urey         fix f_mount error when mount more fats
18  */
19 
20 #include <rtthread.h>
21 #include "ffconf.h"
22 #include "ff.h"
23 #include <string.h>
24 #include <sys/time.h>
25 
26 /* ELM FatFs provide a DIR struct */
27 #define HAVE_DIR_STRUCTURE
28 
29 #include <dfs.h>
30 #include <dfs_fs.h>
31 #include <dfs_dentry.h>
32 #include <dfs_file.h>
33 #include <dfs_mnt.h>
34 
35 #ifdef RT_USING_PAGECACHE
36 #include "dfs_pcache.h"
37 #endif
38 
39 
40 static int dfs_elm_free_vnode(struct dfs_vnode *vnode);
41 static int dfs_elm_truncate(struct dfs_file *file, off_t offset);
42 
43 #ifdef RT_USING_PAGECACHE
44 static ssize_t dfs_elm_page_read(struct dfs_file *file, struct dfs_page *page);
45 static ssize_t dfs_elm_page_write(struct dfs_page *page);
46 
47 static struct dfs_aspace_ops dfs_elm_aspace_ops =
48 {
49     .read = dfs_elm_page_read,
50     .write = dfs_elm_page_write,
51 };
52 #endif
53 
54 #undef SS
55 #if FF_MAX_SS == FF_MIN_SS
56 #define SS(fs) ((UINT)FF_MAX_SS) /* Fixed sector size */
57 #else
58 #define SS(fs) ((fs)->ssize) /* Variable sector size */
59 #endif
60 
61 static rt_device_t disk[FF_VOLUMES] = {0};
62 
63 int dfs_elm_unmount(struct dfs_mnt *mnt);
64 
elm_result_to_dfs(FRESULT result)65 static int elm_result_to_dfs(FRESULT result)
66 {
67     int status = RT_EOK;
68 
69     switch (result)
70     {
71     case FR_OK:
72         break;
73 
74     case FR_NO_FILE:
75     case FR_NO_PATH:
76     case FR_NO_FILESYSTEM:
77         status = -ENOENT;
78         break;
79 
80     case FR_INVALID_NAME:
81         status = -EINVAL;
82         break;
83 
84     case FR_EXIST:
85     case FR_INVALID_OBJECT:
86         status = -EEXIST;
87         break;
88 
89     case FR_DISK_ERR:
90     case FR_NOT_READY:
91     case FR_INT_ERR:
92         status = -EIO;
93         break;
94 
95     case FR_WRITE_PROTECTED:
96     case FR_DENIED:
97         status = -EROFS;
98         break;
99 
100     case FR_MKFS_ABORTED:
101         status = -EINVAL;
102         break;
103 
104     default:
105         status = -1;
106         break;
107     }
108 
109     return status;
110 }
111 
112 /* results:
113  *  -1, no space to install fatfs driver
114  *  >= 0, there is an space to install fatfs driver
115  */
get_disk(rt_device_t id)116 static int get_disk(rt_device_t id)
117 {
118     int index;
119 
120     for (index = 0; index < FF_VOLUMES; index ++)
121     {
122         if (disk[index] == id)
123             return index;
124     }
125 
126     return -1;
127 }
128 
dfs_elm_mount(struct dfs_mnt * mnt,unsigned long rwflag,const void * data)129 static int dfs_elm_mount(struct dfs_mnt *mnt, unsigned long rwflag, const void *data)
130 {
131     FATFS *fat;
132     FRESULT result;
133     int index;
134     struct rt_device_blk_geometry geometry;
135     char logic_nbr[3] = {'0',':', 0};
136 
137     /* open device, but do not check the status of device */
138     if (mnt->dev_id == RT_NULL
139         || rt_device_open(mnt->dev_id, RT_DEVICE_OFLAG_RDWR) != RT_EOK)
140     {
141         return -ENODEV;
142     }
143 
144     /* get an empty position */
145     index = get_disk(RT_NULL);
146     if (index == -1)
147     {
148         rt_device_close(mnt->dev_id);
149         return -ENOENT;
150     }
151     logic_nbr[0] = '0' + index;
152 
153     /* save device */
154     disk[index] = mnt->dev_id;
155     /* check sector size */
156     if (rt_device_control(mnt->dev_id, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry) == RT_EOK)
157     {
158         if (geometry.bytes_per_sector > FF_MAX_SS)
159         {
160             rt_kprintf("The sector size of device is greater than the sector size of FAT.\n");
161             rt_device_close(mnt->dev_id);
162             return -EINVAL;
163         }
164     }
165 
166     fat = (FATFS *)rt_malloc(sizeof(FATFS));
167     if (fat == RT_NULL)
168     {
169         disk[index] = RT_NULL;
170         rt_device_close(mnt->dev_id);
171         return -ENOMEM;
172     }
173 
174     /* mount fatfs, always 0 logic driver */
175     result = f_mount(fat, (const TCHAR *)logic_nbr, 1);
176     if (result == FR_OK)
177     {
178         char drive[8];
179         DIR *dir;
180 
181         rt_snprintf(drive, sizeof(drive), "%d:/", index);
182         dir = (DIR *)rt_malloc(sizeof(DIR));
183         if (dir == RT_NULL)
184         {
185             f_mount(RT_NULL, (const TCHAR *)logic_nbr, 1);
186             disk[index] = RT_NULL;
187             rt_free(fat);
188             rt_device_close(mnt->dev_id);
189             return -ENOMEM;
190         }
191 
192         /* open the root directory to test whether the fatfs is valid */
193         result = f_opendir(dir, drive);
194         if (result != FR_OK)
195             goto __err;
196 
197         /* mount succeed! */
198         mnt->data = fat;
199         rt_free(dir);
200         return RT_EOK;
201     }
202 
203 __err:
204     f_mount(RT_NULL, (const TCHAR *)logic_nbr, 1);
205     disk[index] = RT_NULL;
206     rt_free(fat);
207     rt_device_close(mnt->dev_id);
208     return elm_result_to_dfs(result);
209 }
210 
dfs_elm_unmount(struct dfs_mnt * mnt)211 int dfs_elm_unmount(struct dfs_mnt *mnt)
212 {
213     FATFS *fat;
214     FRESULT result;
215     int  index;
216     char logic_nbr[3] = {'0',':', 0};
217 
218     fat = (FATFS *)mnt->data;
219 
220     RT_ASSERT(fat != RT_NULL);
221 
222     /* find the device index and then umount it */
223     index = get_disk(mnt->dev_id);
224     if (index == -1) /* not found */
225         return -ENOENT;
226 
227     logic_nbr[0] = '0' + index;
228     result = f_mount(RT_NULL, logic_nbr, (BYTE)0);
229     if (result != FR_OK)
230         return elm_result_to_dfs(result);
231 
232     mnt->data = RT_NULL;
233     disk[index] = RT_NULL;
234     rt_free(fat);
235     rt_device_close(mnt->dev_id);
236 
237     return RT_EOK;
238 }
239 
dfs_elm_mkfs(rt_device_t dev_id,const char * fs_name)240 int dfs_elm_mkfs(rt_device_t dev_id, const char *fs_name)
241 {
242 #define FSM_STATUS_INIT            0
243 #define FSM_STATUS_USE_TEMP_DRIVER 1
244     FATFS *fat = RT_NULL;
245     BYTE *work;
246     int flag;
247     FRESULT result;
248     int index;
249     char logic_nbr[3] = {'0',':', 0};
250     MKFS_PARM opt;
251 
252     work = rt_malloc(FF_MAX_SS);
253     if(RT_NULL == work) {
254         return -ENOMEM;
255     }
256 
257     if (dev_id == RT_NULL)
258     {
259         rt_free(work); /* release memory */
260         return -EINVAL;
261     }
262 
263     /* if the device is already mounted, then just do mkfs to the drv,
264      * while if it is not mounted yet, then find an empty drive to do mkfs
265      */
266 
267     flag = FSM_STATUS_INIT;
268     index = get_disk(dev_id);
269     if (index == -1)
270     {
271         /* not found the device id */
272         index = get_disk(RT_NULL);
273         if (index == -1)
274         {
275             /* no space to store an temp driver */
276             rt_kprintf("sorry, there is no space to do mkfs! \n");
277             rt_free(work); /* release memory */
278             return -ENOSPC;
279         }
280         else
281         {
282             fat = (FATFS *)rt_malloc(sizeof(FATFS));
283             if (fat == RT_NULL)
284             {
285                 rt_free(work); /* release memory */
286                 return -ENOMEM;
287             }
288 
289             flag = FSM_STATUS_USE_TEMP_DRIVER;
290 
291             disk[index] = dev_id;
292             /* try to open device */
293             rt_device_open(dev_id, RT_DEVICE_OFLAG_RDWR);
294 
295             /* just fill the FatFs[vol] in ff.c, or mkfs will failded!
296              * consider this condition: you just umount the elm fat,
297              * then the space in FatFs[index] is released, and now do mkfs
298              * on the disk, you will get a failure. so we need f_mount here,
299              * just fill the FatFS[index] in elm fatfs to make mkfs work.
300              */
301             logic_nbr[0] = '0' + index;
302             f_mount(fat, logic_nbr, (BYTE)index);
303         }
304     }
305     else
306     {
307         logic_nbr[0] = '0' + index;
308     }
309 
310     /* [IN] Logical drive number */
311     /* [IN] Format options */
312     /* [-]  Working buffer */
313     /* [IN] Size of working buffer */
314     rt_memset(&opt, 0, sizeof(opt));
315     opt.fmt = FM_ANY|FM_SFD;
316     result = f_mkfs(logic_nbr, &opt, work, FF_MAX_SS);
317     rt_free(work); work = RT_NULL;
318 
319     /* check flag status, we need clear the temp driver stored in disk[] */
320     if (flag == FSM_STATUS_USE_TEMP_DRIVER)
321     {
322         f_mount(RT_NULL, logic_nbr, (BYTE)index);
323         rt_free(fat);
324         disk[index] = RT_NULL;
325         /* close device */
326         rt_device_close(dev_id);
327     }
328 
329     if (result != FR_OK)
330     {
331         rt_kprintf("format error, result=%d\n", result);
332         return elm_result_to_dfs(result);
333     }
334 
335     return RT_EOK;
336 }
337 
dfs_elm_statfs(struct dfs_mnt * mnt,struct statfs * buf)338 int dfs_elm_statfs(struct dfs_mnt *mnt, struct statfs *buf)
339 {
340     FATFS *f;
341     FRESULT res;
342     char driver[4];
343     DWORD fre_clust, fre_sect, tot_sect;
344 
345     RT_ASSERT(mnt != RT_NULL);
346     RT_ASSERT(buf != RT_NULL);
347 
348     f = (FATFS *)mnt->data;
349 
350     rt_snprintf(driver, sizeof(driver), "%d:", f->pdrv);
351     res = f_getfree(driver, &fre_clust, &f);
352     if (res)
353         return elm_result_to_dfs(res);
354 
355     /* Get total sectors and free sectors */
356     tot_sect = (f->n_fatent - 2) * f->csize;
357     fre_sect = fre_clust * f->csize;
358 
359     buf->f_bfree = fre_sect;
360     buf->f_blocks = tot_sect;
361 #if FF_MAX_SS != 512
362     buf->f_bsize = f->ssize;
363 #else
364     buf->f_bsize = 512;
365 #endif
366 
367     return 0;
368 }
369 
dfs_elm_open(struct dfs_file * file)370 int dfs_elm_open(struct dfs_file *file)
371 {
372     FIL *fd;
373     BYTE mode;
374     FRESULT result;
375     char *drivers_fn;
376 
377 #if (FF_VOLUMES > 1)
378     int vol;
379     struct dfs_mnt *mnt = file->vnode->mnt;
380     extern int elm_get_vol(FATFS * fat);
381 
382     RT_ASSERT(file->vnode->ref_count > 0);
383     if (file->vnode->data)
384     {
385         if (file->vnode->type == FT_DIRECTORY
386                 && !(file->flags & O_DIRECTORY))
387         {
388             return -ENOENT;
389         }
390         file->fpos = 0;
391         return 0;
392     }
393 
394     if (mnt == NULL)
395         return -ENOENT;
396 
397     /* add path for ELM FatFS driver support */
398     vol = elm_get_vol((FATFS *)mnt->data);
399     if (vol < 0)
400         return -ENOENT;
401     drivers_fn = (char *)rt_malloc(256);
402     if (drivers_fn == RT_NULL)
403         return -ENOMEM;
404 
405     rt_snprintf(drivers_fn, 256, "%d:%s", vol, file->dentry->pathname);
406 #else
407     drivers_fn = file->dentry->pathname;
408 #endif
409 
410     if (file->flags & O_DIRECTORY)
411     {
412         DIR *dir;
413 
414         if (file->flags & O_CREAT)
415         {
416             result = f_mkdir(drivers_fn);
417             if (result != FR_OK)
418             {
419 #if FF_VOLUMES > 1
420                 rt_free(drivers_fn);
421 #endif
422                 return elm_result_to_dfs(result);
423             }
424         }
425 
426         /* open directory */
427         dir = (DIR *)rt_malloc(sizeof(DIR));
428         if (dir == RT_NULL)
429         {
430 #if FF_VOLUMES > 1
431             rt_free(drivers_fn);
432 #endif
433             return -ENOMEM;
434         }
435 
436         result = f_opendir(dir, drivers_fn);
437 #if FF_VOLUMES > 1
438         rt_free(drivers_fn);
439 #endif
440         if (result != FR_OK)
441         {
442             rt_free(dir);
443             return elm_result_to_dfs(result);
444         }
445 
446         file->vnode->data = dir;
447         rt_mutex_init(&file->vnode->lock, file->dentry->pathname, RT_IPC_FLAG_PRIO);
448         return RT_EOK;
449     }
450     else
451     {
452         mode = FA_READ;
453 
454         if (file->flags & O_WRONLY)
455             mode |= FA_WRITE;
456         if ((file->flags & O_ACCMODE) & O_RDWR)
457             mode |= FA_WRITE;
458         /* Opens the file, if it is existing. If not, a new file is created. */
459         if (file->flags & O_CREAT)
460             mode |= FA_OPEN_ALWAYS;
461         /* Creates a new file. If the file is existing, it is truncated and overwritten. */
462         if (file->flags & O_TRUNC)
463             mode |= FA_CREATE_ALWAYS;
464         /* Creates a new file. The function fails if the file is already existing. */
465         if (file->flags & O_EXCL)
466             mode |= FA_CREATE_NEW;
467 
468         /* allocate a fd */
469         fd = (FIL *)rt_malloc(sizeof(FIL));
470         if (fd == RT_NULL)
471         {
472 #if FF_VOLUMES > 1
473             rt_free(drivers_fn);
474 #endif
475             return -ENOMEM;
476         }
477 
478         result = f_open(fd, drivers_fn, mode);
479 #if FF_VOLUMES > 1
480         rt_free(drivers_fn);
481 #endif
482         if (result == FR_OK)
483         {
484             file->fpos  = fd->fptr;
485             file->vnode->size = f_size(fd);
486             file->vnode->type = FT_REGULAR;
487             file->vnode->data = fd;
488             rt_mutex_init(&file->vnode->lock, file->dentry->pathname, RT_IPC_FLAG_PRIO);
489 
490             if (file->flags & O_APPEND)
491             {
492                 /* seek to the end of file */
493                 f_lseek(fd, f_size(fd));
494                 file->fpos = fd->fptr;
495             }
496         }
497         else
498         {
499             /* open failed, return */
500             rt_free(fd);
501             return elm_result_to_dfs(result);
502         }
503     }
504 
505     return RT_EOK;
506 }
507 
dfs_elm_close(struct dfs_file * file)508 int dfs_elm_close(struct dfs_file *file)
509 {
510     FRESULT result;
511 
512     RT_ASSERT(file->vnode->ref_count > 0);
513     if (file->vnode->ref_count > 1)
514     {
515         return 0;
516     }
517     result = FR_OK;
518     if (file->vnode->type == FT_DIRECTORY)
519     {
520         DIR *dir = RT_NULL;
521 
522         dir = (DIR *)(file->vnode->data);
523         RT_ASSERT(dir != RT_NULL);
524 
525         /* release memory */
526         rt_free(dir);
527     }
528     else if (file->vnode->type == FT_REGULAR)
529     {
530         FIL *fd = RT_NULL;
531 
532         fd = (FIL *)(file->vnode->data);
533         RT_ASSERT(fd != RT_NULL);
534 
535         f_close(fd);
536         /* release memory */
537         rt_free(fd);
538     }
539 
540     file->vnode->data = RT_NULL;
541     rt_mutex_detach(&file->vnode->lock);
542 
543     return elm_result_to_dfs(result);
544 }
545 
dfs_elm_ioctl(struct dfs_file * file,int cmd,void * args)546 int dfs_elm_ioctl(struct dfs_file *file, int cmd, void *args)
547 {
548     switch (cmd)
549     {
550     case RT_FIOFTRUNCATE:
551     {
552         off_t offset = (off_t)(size_t)(args);
553         return dfs_elm_truncate(file, offset);
554     }
555     case F_GETLK:
556         return 0;
557     case F_SETLK:
558         return 0;
559     }
560     return -ENOSYS;
561 }
562 
dfs_elm_read(struct dfs_file * file,void * buf,size_t len,off_t * pos)563 ssize_t dfs_elm_read(struct dfs_file *file, void *buf, size_t len, off_t *pos)
564 {
565     FIL *fd;
566     FRESULT result = FR_OK;
567     UINT byte_read;
568 
569     if (file->vnode->type == FT_DIRECTORY)
570     {
571         return -EISDIR;
572     }
573 
574     if (file->vnode->size > *pos)
575     {
576         fd = (FIL *)(file->vnode->data);
577         RT_ASSERT(fd != RT_NULL);
578         rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
579         f_lseek(fd, *pos);
580         result = f_read(fd, buf, len, &byte_read);
581         /* update position */
582         *pos = fd->fptr;
583         rt_mutex_release(&file->vnode->lock);
584         if (result == FR_OK)
585             return byte_read;
586     }
587 
588     return elm_result_to_dfs(result);
589 }
590 
dfs_elm_write(struct dfs_file * file,const void * buf,size_t len,off_t * pos)591 ssize_t dfs_elm_write(struct dfs_file *file, const void *buf, size_t len, off_t *pos)
592 {
593     FIL *fd;
594     FRESULT result;
595     UINT byte_write;
596 
597     if (file->vnode->type == FT_DIRECTORY)
598     {
599         return -EISDIR;
600     }
601 
602     fd = (FIL *)(file->vnode->data);
603     RT_ASSERT(fd != RT_NULL);
604     rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
605     f_lseek(fd, *pos);
606     result = f_write(fd, buf, len, &byte_write);
607     /* update position and file size */
608     *pos = fd->fptr;
609     file->vnode->size = f_size(fd);
610     rt_mutex_release(&file->vnode->lock);
611     if (result == FR_OK)
612         return byte_write;
613 
614     return elm_result_to_dfs(result);
615 }
616 
dfs_elm_flush(struct dfs_file * file)617 int dfs_elm_flush(struct dfs_file *file)
618 {
619     FIL *fd;
620     FRESULT result;
621 
622     fd = (FIL *)(file->vnode->data);
623     RT_ASSERT(fd != RT_NULL);
624 
625     result = f_sync(fd);
626     return elm_result_to_dfs(result);
627 }
628 
dfs_elm_lseek(struct dfs_file * file,off_t offset,int wherece)629 off_t dfs_elm_lseek(struct dfs_file *file, off_t offset, int wherece)
630 {
631     FRESULT result = FR_OK;
632 
633     switch (wherece)
634     {
635     case SEEK_SET:
636         break;
637 
638     case SEEK_CUR:
639         offset += file->fpos;
640         break;
641 
642     case SEEK_END:
643         offset += file->vnode->size;
644         break;
645 
646     default:
647         return -EINVAL;
648     }
649 
650     if (file->vnode->type == FT_REGULAR)
651     {
652         FIL *fd;
653 
654         /* regular file type */
655         fd = (FIL *)(file->vnode->data);
656         RT_ASSERT(fd != RT_NULL);
657         rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
658         result = f_lseek(fd, offset);
659         rt_mutex_release(&file->vnode->lock);
660         if (result == FR_OK)
661         {
662             /* return current position */
663             return fd->fptr;
664         }
665     }
666     else if (file->vnode->type == FT_DIRECTORY)
667     {
668         /* which is a directory */
669         DIR *dir = RT_NULL;
670 
671         dir = (DIR *)(file->vnode->data);
672         RT_ASSERT(dir != RT_NULL);
673         rt_mutex_take(&file->vnode->lock, RT_WAITING_FOREVER);
674         result = f_seekdir(dir, offset / sizeof(struct dirent));
675         rt_mutex_release(&file->vnode->lock);
676         if (result == FR_OK)
677         {
678             /* update file position */
679             return offset;
680         }
681     }
682 
683     return elm_result_to_dfs(result);
684 }
685 
dfs_elm_truncate(struct dfs_file * file,off_t offset)686 static int dfs_elm_truncate(struct dfs_file *file, off_t offset)
687 {
688     FIL *fd;
689     FSIZE_t fptr;
690     FRESULT result = FR_OK;
691     fd = (FIL *)(file->vnode->data);
692     RT_ASSERT(fd != RT_NULL);
693 
694     /* save file read/write point */
695     fptr = fd->fptr;
696     if (offset <= fd->obj.objsize)
697     {
698         fd->fptr = offset;
699         result = f_truncate(fd);
700     }
701     else
702     {
703         result = f_lseek(fd, offset);
704     }
705     /* restore file read/write point */
706     fd->fptr = fptr;
707     return elm_result_to_dfs(result);
708 }
709 
dfs_elm_getdents(struct dfs_file * file,struct dirent * dirp,uint32_t count)710 int dfs_elm_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count)
711 {
712     DIR *dir;
713     FILINFO fno;
714     FRESULT result;
715     rt_uint32_t index;
716     struct dirent *d;
717 
718     dir = (DIR *)(file->vnode->data);
719     RT_ASSERT(dir != RT_NULL);
720 
721     /* make integer count */
722     count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
723     if (count == 0)
724         return -EINVAL;
725 
726     index = 0;
727     while (1)
728     {
729         char *fn;
730 
731         d = dirp + index;
732 
733         result = f_readdir(dir, &fno);
734         if (result != FR_OK || fno.fname[0] == 0)
735             break;
736 
737 #if FF_USE_LFN
738         fn = *fno.fname ? fno.fname : fno.altname;
739 #else
740         fn = fno.fname;
741 #endif
742 
743         d->d_type = DT_UNKNOWN;
744         if (fno.fattrib & AM_DIR)
745             d->d_type = DT_DIR;
746         else
747             d->d_type = DT_REG;
748 
749         d->d_namlen = (rt_uint8_t)rt_strlen(fn);
750         d->d_reclen = (rt_uint16_t)sizeof(struct dirent);
751         rt_strncpy(d->d_name, fn, DIRENT_NAME_MAX);
752 
753         index ++;
754         if (index * sizeof(struct dirent) >= count)
755             break;
756     }
757 
758     if (index == 0)
759         return elm_result_to_dfs(result);
760 
761     file->fpos += index * sizeof(struct dirent);
762 
763     return index * sizeof(struct dirent);
764 }
765 
dfs_elm_unlink(struct dfs_dentry * dentry)766 int dfs_elm_unlink(struct dfs_dentry *dentry)
767 {
768     FRESULT result;
769 
770 #if FF_VOLUMES > 1
771     int vol;
772     char *drivers_fn;
773     extern int elm_get_vol(FATFS * fat);
774 
775     /* add path for ELM FatFS driver support */
776     vol = elm_get_vol((FATFS *)dentry->mnt->data);
777     if (vol < 0)
778         return -ENOENT;
779     drivers_fn = (char *)rt_malloc(256);
780     if (drivers_fn == RT_NULL)
781         return -ENOMEM;
782 
783     rt_snprintf(drivers_fn, 256, "%d:%s", vol, dentry->pathname);
784 #else
785     const char *drivers_fn;
786     drivers_fn = path;
787 #endif
788 
789     result = f_unlink(drivers_fn);
790 #if FF_VOLUMES > 1
791     rt_free(drivers_fn);
792 #endif
793     return elm_result_to_dfs(result);
794 }
795 
dfs_elm_rename(struct dfs_dentry * old_dentry,struct dfs_dentry * new_dentry)796 int dfs_elm_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *new_dentry)
797 {
798     FRESULT result;
799 
800 #if FF_VOLUMES > 1
801     char *drivers_oldfn;
802     const char *drivers_newfn;
803     int vol;
804     extern int elm_get_vol(FATFS * fat);
805 
806     /* add path for ELM FatFS driver support */
807     vol = elm_get_vol((FATFS *)old_dentry->mnt->data);
808     if (vol < 0)
809         return -ENOENT;
810 
811     drivers_oldfn = (char *)rt_malloc(256);
812     if (drivers_oldfn == RT_NULL)
813         return -ENOMEM;
814     drivers_newfn = new_dentry->pathname;
815 
816     rt_snprintf(drivers_oldfn, 256, "%d:%s", vol, old_dentry->pathname);
817 #else
818     const char *drivers_oldfn, *drivers_newfn;
819 
820     drivers_oldfn = old_dentry->pathname;
821     drivers_newfn = new_dentry->pathname;
822 #endif
823 
824     result = f_rename(drivers_oldfn, drivers_newfn);
825 #if FF_VOLUMES > 1
826     rt_free(drivers_oldfn);
827 #endif
828     return elm_result_to_dfs(result);
829 }
830 
dfs_elm_stat(struct dfs_dentry * dentry,struct stat * st)831 int dfs_elm_stat(struct dfs_dentry *dentry, struct stat *st)
832 {
833     FATFS  *fat;
834     FILINFO file_info;
835     FRESULT result;
836 
837     fat = (FATFS *)dentry->mnt->data;
838 
839 #if FF_VOLUMES > 1
840     int vol;
841     char *drivers_fn;
842     extern int elm_get_vol(FATFS * fat);
843 
844     /* add path for ELM FatFS driver support */
845     vol = elm_get_vol(fat);
846     if (vol < 0)
847         return -ENOENT;
848     drivers_fn = (char *)rt_malloc(256);
849     if (drivers_fn == RT_NULL)
850         return -ENOMEM;
851 
852     rt_snprintf(drivers_fn, 256, "%d:%s", vol, dentry->pathname);
853 #else
854     const char *drivers_fn;
855     drivers_fn = dentry->pathname;
856 #endif
857 
858     result = f_stat(drivers_fn, &file_info);
859 #if FF_VOLUMES > 1
860     rt_free(drivers_fn);
861 #endif
862     if (result == FR_OK)
863     {
864         /* convert to dfs stat structure */
865         st->st_dev = (dev_t)(size_t)(dentry->mnt->dev_id);
866         st->st_ino = (ino_t)dfs_dentry_full_path_crc32(dentry);
867 
868         if (file_info.fattrib & AM_DIR)
869         {
870             st->st_mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
871         }
872         else
873         {
874             st->st_mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
875         }
876 
877         if (file_info.fattrib & AM_RDO)
878             st->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
879 
880         if (S_IFDIR & st->st_mode)
881         {
882             st->st_size = file_info.fsize;
883         }
884         else
885         {
886 #ifdef RT_USING_PAGECACHE
887             st->st_size = (dentry->vnode && dentry->vnode->aspace) ? dentry->vnode->size : file_info.fsize;
888 #else
889             st->st_size = file_info.fsize;
890 #endif
891         }
892 
893         st->st_blksize = fat->csize * SS(fat);
894         if (file_info.fattrib & AM_ARC)
895         {
896             st->st_blocks = st->st_size ? ((st->st_size - 1) / SS(fat) / fat->csize + 1) : 0;
897             st->st_blocks *= (st->st_blksize / 512);  // man say st_blocks is number of 512B blocks allocated
898         }
899         else
900         {
901             st->st_blocks = fat->csize;
902         }
903         /* get st_mtime. */
904         {
905             struct tm tm_file;
906             int year, mon, day, hour, min, sec;
907             WORD tmp;
908 
909             tmp = file_info.fdate;
910             day = tmp & 0x1F;           /* bit[4:0] Day(1..31) */
911             tmp >>= 5;
912             mon = tmp & 0x0F;           /* bit[8:5] Month(1..12) */
913             tmp >>= 4;
914             year = (tmp & 0x7F) + 1980; /* bit[15:9] Year origin from 1980(0..127) */
915 
916             tmp = file_info.ftime;
917             sec = (tmp & 0x1F) * 2;     /* bit[4:0] Second/2(0..29) */
918             tmp >>= 5;
919             min = tmp & 0x3F;           /* bit[10:5] Minute(0..59) */
920             tmp >>= 6;
921             hour = tmp & 0x1F;          /* bit[15:11] Hour(0..23) */
922 
923             rt_memset(&tm_file, 0, sizeof(tm_file));
924             tm_file.tm_year = year - 1900; /* Years since 1900 */
925             tm_file.tm_mon  = mon - 1;     /* Months *since* january: 0-11 */
926             tm_file.tm_mday = day;         /* Day of the month: 1-31 */
927             tm_file.tm_hour = hour;        /* Hours since midnight: 0-23 */
928             tm_file.tm_min  = min;         /* Minutes: 0-59 */
929             tm_file.tm_sec  = sec;         /* Seconds: 0-59 */
930 
931             st->st_mtime = timegm(&tm_file);
932         } /* get st_mtime. */
933     }
934 
935     return elm_result_to_dfs(result);
936 }
937 
dfs_elm_lookup(struct dfs_dentry * dentry)938 static struct dfs_vnode *dfs_elm_lookup(struct dfs_dentry *dentry)
939 {
940     struct stat st;
941     struct dfs_vnode *vnode = RT_NULL;
942 
943     if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
944     {
945         return NULL;
946     }
947 
948     if (dfs_elm_stat(dentry, &st) != 0)
949     {
950         return vnode;
951     }
952 
953     vnode = dfs_vnode_create();
954     if (vnode)
955     {
956         vnode->mnt = dentry->mnt;
957         vnode->size = st.st_size;
958         vnode->data = NULL;
959 
960         if (S_ISDIR(st.st_mode))
961         {
962             vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
963             vnode->type = FT_DIRECTORY;
964         }
965         else
966         {
967             vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
968             vnode->type = FT_REGULAR;
969 #ifdef RT_USING_PAGECACHE
970             vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_elm_aspace_ops);
971 #endif
972         }
973     }
974 
975     return vnode;
976 }
977 
dfs_elm_create_vnode(struct dfs_dentry * dentry,int type,mode_t mode)978 static struct dfs_vnode *dfs_elm_create_vnode(struct dfs_dentry *dentry, int type, mode_t mode)
979 {
980     struct dfs_vnode *vnode = RT_NULL;
981 
982     if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
983     {
984         return NULL;
985     }
986 
987     vnode = dfs_vnode_create();
988     if (vnode)
989     {
990         if (type == FT_DIRECTORY)
991         {
992             /* fat directory force mode 0555 */
993             vnode->mode = S_IFDIR | (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
994             vnode->type = FT_DIRECTORY;
995         }
996         else
997         {
998             /* fat REGULAR file mode force mode 0777 */
999             vnode->mode = S_IFREG | (S_IRWXU | S_IRWXG | S_IRWXO);
1000             vnode->type = FT_REGULAR;
1001 #ifdef RT_USING_PAGECACHE
1002             vnode->aspace = dfs_aspace_create(dentry, vnode, &dfs_elm_aspace_ops);
1003 #endif
1004         }
1005 
1006         vnode->mnt = dentry->mnt;
1007         vnode->data = NULL;
1008         vnode->size = 0;
1009     }
1010 
1011     return vnode;
1012 }
1013 
dfs_elm_free_vnode(struct dfs_vnode * vnode)1014 static int dfs_elm_free_vnode(struct dfs_vnode *vnode)
1015 {
1016     /* nothing to be freed */
1017     if (vnode && vnode->ref_count <= 1)
1018     {
1019         vnode->data = NULL;
1020     }
1021 
1022     return 0;
1023 }
1024 
1025 #ifdef RT_USING_PAGECACHE
dfs_elm_page_read(struct dfs_file * file,struct dfs_page * page)1026 static ssize_t dfs_elm_page_read(struct dfs_file *file, struct dfs_page *page)
1027 {
1028     int ret = -EINVAL;
1029 
1030     if (page->page)
1031     {
1032         off_t fpos = page->fpos;
1033         ret = dfs_elm_read(file, page->page, page->size, &fpos);
1034     }
1035 
1036     return ret;
1037 }
1038 
dfs_elm_page_write(struct dfs_page * page)1039 ssize_t dfs_elm_page_write(struct dfs_page *page)
1040 {
1041     FIL *fd;
1042     FRESULT result;
1043     UINT byte_write;
1044 
1045     if (page->aspace->vnode->type == FT_DIRECTORY)
1046     {
1047         return -EISDIR;
1048     }
1049 
1050     fd = (FIL *)(page->aspace->vnode->data);
1051     RT_ASSERT(fd != RT_NULL);
1052     rt_mutex_take(&page->aspace->vnode->lock, RT_WAITING_FOREVER);
1053     f_lseek(fd, page->fpos);
1054     result = f_write(fd, page->page, page->len, &byte_write);
1055     rt_mutex_release(&page->aspace->vnode->lock);
1056     if (result == FR_OK)
1057     {
1058         return byte_write;
1059     }
1060 
1061     return elm_result_to_dfs(result);
1062 }
1063 #endif
1064 
1065 static const struct dfs_file_ops dfs_elm_fops =
1066 {
1067     .open = dfs_elm_open,
1068     .close = dfs_elm_close,
1069     .ioctl = dfs_elm_ioctl,
1070     .read = dfs_elm_read,
1071     .write = dfs_elm_write,
1072     .flush = dfs_elm_flush,
1073     .lseek = dfs_elm_lseek,
1074     .truncate = dfs_elm_truncate,
1075     .getdents = dfs_elm_getdents,
1076 };
1077 
1078 static const struct dfs_filesystem_ops dfs_elm =
1079 {
1080     "elm",
1081     FS_NEED_DEVICE,
1082     &dfs_elm_fops,
1083 
1084     .mount = dfs_elm_mount,
1085     .umount = dfs_elm_unmount,
1086     .mkfs = dfs_elm_mkfs,
1087     .statfs = dfs_elm_statfs,
1088 
1089     .unlink = dfs_elm_unlink,
1090     .stat = dfs_elm_stat,
1091     .rename = dfs_elm_rename,
1092 
1093     .lookup = dfs_elm_lookup,
1094     .create_vnode = dfs_elm_create_vnode,
1095     .free_vnode = dfs_elm_free_vnode
1096 };
1097 
1098 static struct dfs_filesystem_type _elmfs =
1099 {
1100     .fs_ops = &dfs_elm,
1101 };
1102 
elm_init(void)1103 int elm_init(void)
1104 {
1105     /* register fatfs file system */
1106     dfs_register(&_elmfs);
1107 
1108     return 0;
1109 }
1110 INIT_COMPONENT_EXPORT(elm_init);
1111 
1112 /*
1113  * RT-Thread Device Interface for ELM FatFs
1114  */
1115 #include "diskio.h"
1116 
1117 /* Initialize a Drive */
disk_initialize(BYTE drv)1118 DSTATUS disk_initialize(BYTE drv)
1119 {
1120     return 0;
1121 }
1122 
1123 /* Return Disk Status */
disk_status(BYTE drv)1124 DSTATUS disk_status(BYTE drv)
1125 {
1126     return 0;
1127 }
1128 
1129 /* Read Sector(s) */
disk_read(BYTE drv,BYTE * buff,DWORD sector,UINT count)1130 DRESULT disk_read(BYTE drv, BYTE *buff, DWORD sector, UINT count)
1131 {
1132     rt_size_t result;
1133     rt_device_t device = disk[drv];
1134 
1135     result = rt_device_read(device, sector, buff, count);
1136     if (result == count)
1137     {
1138         return RES_OK;
1139     }
1140 
1141     return RES_ERROR;
1142 }
1143 
1144 /* Write Sector(s) */
disk_write(BYTE drv,const BYTE * buff,DWORD sector,UINT count)1145 DRESULT disk_write(BYTE drv, const BYTE *buff, DWORD sector, UINT count)
1146 {
1147     rt_size_t result;
1148     rt_device_t device = disk[drv];
1149 
1150     result = rt_device_write(device, sector, buff, count);
1151     if (result == count)
1152     {
1153         return RES_OK;
1154     }
1155 
1156     return RES_ERROR;
1157 }
1158 
1159 /* Miscellaneous Functions */
disk_ioctl(BYTE drv,BYTE ctrl,void * buff)1160 DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void *buff)
1161 {
1162     rt_device_t device = disk[drv];
1163 
1164     if (device == RT_NULL)
1165         return RES_ERROR;
1166 
1167     if (ctrl == GET_SECTOR_COUNT)
1168     {
1169         struct rt_device_blk_geometry geometry;
1170 
1171         rt_memset(&geometry, 0, sizeof(geometry));
1172         rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
1173 
1174         *(DWORD *)buff = geometry.sector_count;
1175         if (geometry.sector_count == 0)
1176             return RES_ERROR;
1177     }
1178     else if (ctrl == GET_SECTOR_SIZE)
1179     {
1180         struct rt_device_blk_geometry geometry;
1181 
1182         rt_memset(&geometry, 0, sizeof(geometry));
1183         rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
1184 
1185         *(WORD *)buff = (WORD)(geometry.bytes_per_sector);
1186     }
1187     else if (ctrl == GET_BLOCK_SIZE) /* Get erase block size in unit of sectors (DWORD) */
1188     {
1189         struct rt_device_blk_geometry geometry;
1190 
1191         rt_memset(&geometry, 0, sizeof(geometry));
1192         rt_device_control(device, RT_DEVICE_CTRL_BLK_GETGEOME, &geometry);
1193 
1194         *(DWORD *)buff = geometry.block_size / geometry.bytes_per_sector;
1195     }
1196     else if (ctrl == CTRL_SYNC)
1197     {
1198         rt_device_control(device, RT_DEVICE_CTRL_BLK_SYNC, RT_NULL);
1199     }
1200     else if (ctrl == CTRL_TRIM)
1201     {
1202         rt_device_control(device, RT_DEVICE_CTRL_BLK_ERASE, buff);
1203     }
1204 
1205     return RES_OK;
1206 }
1207 
get_fattime(void)1208 DWORD get_fattime(void)
1209 {
1210     DWORD fat_time = 0;
1211     time_t now;
1212     struct tm tm_now;
1213 
1214     now = time(RT_NULL);
1215     gmtime_r(&now, &tm_now);
1216 
1217     fat_time = (DWORD)(tm_now.tm_year - 80) << 25 |
1218                (DWORD)(tm_now.tm_mon + 1)   << 21 |
1219                (DWORD)tm_now.tm_mday        << 16 |
1220                (DWORD)tm_now.tm_hour        << 11 |
1221                (DWORD)tm_now.tm_min         <<  5 |
1222                (DWORD)tm_now.tm_sec / 2 ;
1223 
1224     return fat_time;
1225 }
1226 
1227 #if FF_FS_REENTRANT
1228 
1229 static rt_mutex_t Mutex[FF_VOLUMES + 1];
1230 
ff_mutex_create(int vol)1231 int ff_mutex_create (int vol)
1232 {
1233     char name[8];
1234     rt_mutex_t mutex;
1235 
1236     rt_snprintf(name, sizeof(name), "fat%d", vol);
1237     mutex = rt_mutex_create(name, RT_IPC_FLAG_PRIO);
1238     if (mutex != RT_NULL)
1239     {
1240         Mutex[vol] = mutex;
1241         return RT_TRUE;
1242     }
1243 
1244     return RT_FALSE;
1245 }
ff_mutex_delete(int vol)1246 void ff_mutex_delete (int vol)
1247 {
1248     if (Mutex[vol] != RT_NULL)
1249         rt_mutex_delete(Mutex[vol]);
1250 }
ff_mutex_take(int vol)1251 int ff_mutex_take (int vol)
1252 {
1253     if (rt_mutex_take(Mutex[vol], FF_FS_TIMEOUT) == RT_EOK)
1254         return RT_TRUE;
1255 
1256     return RT_FALSE;
1257 }
ff_mutex_give(int vol)1258 void ff_mutex_give (int vol)
1259 {
1260     rt_mutex_release(Mutex[vol]);
1261 }
1262 
1263 #endif
1264 
1265 /* Memory functions */
1266 #if FF_USE_LFN == 3
1267 /* Allocate memory block */
ff_memalloc(UINT size)1268 void *ff_memalloc(UINT size)
1269 {
1270     return rt_malloc(size);
1271 }
1272 
1273 /* Free memory block */
ff_memfree(void * mem)1274 void ff_memfree(void *mem)
1275 {
1276     rt_free(mem);
1277 }
1278 #endif /* FF_USE_LFN == 3 */
1279 
1280