• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "fatfs.h"
33 #ifdef LOSCFG_FS_FAT
34 #include "ff.h"
35 #include "disk_pri.h"
36 #include "diskio.h"
37 #include "fs/file.h"
38 #include "fs/fs.h"
39 #include "fs/dirent_fs.h"
40 #include "fs/mount.h"
41 #include "vnode.h"
42 #include "path_cache.h"
43 #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
44 #include "virpartff.h"
45 #include "errcode_fat.h"
46 #endif
47 #include "los_tables.h"
48 #include "user_copy.h"
49 #include "los_vm_filemap.h"
50 #include "los_hash.h"
51 #include "los_vm_common.h"
52 #include <time.h>
53 #include <errno.h>
54 #include <dirent.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <sys/stat.h>
58 #include <sys/types.h>
59 #include <fcntl.h>
60 
61 
62 struct VnodeOps fatfs_vops; /* forward define */
63 struct file_operations_vfs fatfs_fops;
64 
65 #define BITMASK4 0x0F
66 #define BITMASK5 0x1F
67 #define BITMASK6 0x3F
68 #define BITMASK7 0x7F
69 #define FTIME_MIN_OFFSET 6 /* minute offset in word */
70 #define FTIME_HR_OFFSET 11 /* hour offset in word */
71 #define FTIME_MTH_OFFSET 5 /* month offset in word */
72 #define FTIME_YEAR_OFFSET 9 /* year offset in word */
73 #define FTIME_DATE_OFFSET 16 /* date offset in dword */
74 #define SEC_MULTIPLIER 2
75 #define YEAR_OFFSET 80 /* Year start from 1980 in FATFS, while start from 1900 in struct tm */
76 
fatfs_2_vfs(int result)77 int fatfs_2_vfs(int result)
78 {
79     int status = ENOERR;
80 
81 #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
82     if (result < 0 || result >= VIRERR_BASE) {
83         return result;
84     }
85 #else
86     if (result < 0) {
87         return result;
88     }
89 #endif
90 
91     /* FatFs errno to Libc errno */
92     switch (result) {
93         case FR_OK:
94             break;
95 
96         case FR_NO_FILE:
97         case FR_NO_PATH:
98             status = ENOENT;
99             break;
100 
101         case FR_NO_FILESYSTEM:
102             status = ENOTSUP;
103             break;
104 
105         case FR_INVALID_NAME:
106             status = EINVAL;
107             break;
108 
109         case FR_EXIST:
110         case FR_INVALID_OBJECT:
111             status = EEXIST;
112             break;
113 
114         case FR_DISK_ERR:
115         case FR_NOT_READY:
116         case FR_INT_ERR:
117             status = EIO;
118             break;
119 
120         case FR_WRITE_PROTECTED:
121             status = EROFS;
122             break;
123         case FR_MKFS_ABORTED:
124         case FR_INVALID_PARAMETER:
125             status = EINVAL;
126             break;
127 
128         case FR_NO_SPACE_LEFT:
129             status = ENOSPC;
130             break;
131         case FR_NO_DIRENTRY:
132             status = ENFILE;
133             break;
134         case FR_NO_EMPTY_DIR:
135             status = ENOTEMPTY;
136             break;
137         case FR_IS_DIR:
138             status = EISDIR;
139             break;
140         case FR_NO_DIR:
141             status = ENOTDIR;
142             break;
143         case FR_NO_EPERM:
144         case FR_DENIED:
145             status = EPERM;
146             break;
147         case FR_LOCKED:
148         case FR_TIMEOUT:
149             status = EBUSY;
150             break;
151 #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
152         case FR_MODIFIED:
153             status = -VIRERR_MODIFIED;
154             break;
155         case FR_CHAIN_ERR:
156             status = -VIRERR_CHAIN_ERR;
157             break;
158         case FR_OCCUPIED:
159             status = -VIRERR_OCCUPIED;
160             break;
161         case FR_NOTCLEAR:
162             status = -VIRERR_NOTCLEAR;
163             break;
164         case FR_NOTFIT:
165             status = -VIRERR_NOTFIT;
166             break;
167         case FR_INVAILD_FATFS:
168             status = -VIRERR_INTER_ERR;
169             break;
170 #endif
171         default:
172             status = -FAT_ERROR;
173             break;
174     }
175 
176     return status;
177 }
178 
fatfs_is_last_cluster(FATFS * fs,DWORD cclust)179 static bool fatfs_is_last_cluster(FATFS *fs, DWORD cclust)
180 {
181     switch (fs->fs_type) {
182         case FS_FAT12:
183             return (cclust == FAT12_END_OF_CLUSTER);
184         case FS_FAT16:
185             return (cclust == FAT16_END_OF_CLUSTER);
186         case FS_FAT32:
187         default:
188             return (cclust == FAT32_END_OF_CLUSTER);
189     }
190 }
191 
fatfs_sync(unsigned long mountflags,FATFS * fs)192 static int fatfs_sync(unsigned long mountflags, FATFS *fs)
193 {
194 #ifdef LOSCFG_FS_FAT_CACHE
195     los_part *part = NULL;
196     if (!(mountflags & (MS_NOSYNC | MS_RDONLY))) {
197         part = get_part((INT)fs->pdrv);
198         if (part == NULL) {
199             return -ENODEV;
200         }
201 
202         (void)OsSdSync(part->disk_id);
203     }
204 #endif
205     return 0;
206 }
fatfs_hash_cmp(struct Vnode * vp,void * arg)207 int fatfs_hash_cmp(struct Vnode *vp, void *arg)
208 {
209     DIR_FILE *dfp_target = (DIR_FILE *)arg;
210     DIR_FILE *dfp = (DIR_FILE *)vp->data;
211 
212     return dfp_target->f_dir.sect != dfp->f_dir.sect ||
213               dfp_target->f_dir.dptr != dfp->f_dir.dptr ||
214               dfp_target->fno.sclst != dfp->fno.sclst;
215 }
216 
fatfs_hash(QWORD sect,DWORD dptr,DWORD sclst)217 static DWORD fatfs_hash(QWORD sect, DWORD dptr, DWORD sclst)
218 {
219     DWORD hash = FNV1_32A_INIT;
220     hash = LOS_HashFNV32aBuf(&sect, sizeof(QWORD), hash);
221     hash = LOS_HashFNV32aBuf(&dptr, sizeof(DWORD), hash);
222     hash = LOS_HashFNV32aBuf(&sclst, sizeof(DWORD), hash);
223 
224     return hash;
225 }
226 
fatfs_get_mode(BYTE attribute,mode_t fs_mode)227 static mode_t fatfs_get_mode(BYTE attribute, mode_t fs_mode)
228 {
229     mode_t mask = 0;
230     if (attribute & AM_RDO) {
231         mask = S_IWUSR | S_IWGRP | S_IWOTH;
232     }
233     fs_mode &= ~mask;
234     if (attribute & AM_DIR) {
235         fs_mode |= S_IFDIR;
236     } else if (attribute & AM_LNK) {
237         fs_mode |= S_IFLNK;
238     } else {
239         fs_mode |= S_IFREG;
240     }
241     return fs_mode;
242 }
243 
fatfstype_2_vnodetype(BYTE type)244 static enum VnodeType fatfstype_2_vnodetype(BYTE type)
245 {
246     switch (type) {
247         case AM_ARC:
248             return VNODE_TYPE_REG;
249         case AM_DIR:
250             return VNODE_TYPE_DIR;
251         case AM_LNK:
252             return VNODE_TYPE_LNK;
253         default:
254             return VNODE_TYPE_UNKNOWN;
255     }
256 }
257 
258 #define DIR_SIZE 32
init_cluster(DIR_FILE * pdfp,DIR * dp_new,FATFS * fs,int type,const char * target,DWORD * clust)259 static FRESULT init_cluster(DIR_FILE *pdfp, DIR *dp_new, FATFS *fs, int type, const char *target, DWORD *clust)
260 {
261     FRESULT result;
262     BYTE *dir = NULL;
263     QWORD sect;
264     DWORD pclust;
265     UINT n;
266 
267     /* Allocate a new cluster */
268     *clust = create_chain(&(dp_new->obj), 0);
269     if (*clust == 0) {
270         return FR_NO_SPACE_LEFT;
271     }
272     if (*clust == 1 || *clust == DISK_ERROR) {
273         return FR_DISK_ERR;
274     }
275 
276     result = sync_window(fs); /* Flush FAT */
277     if (result != FR_OK) {
278         remove_chain(&(dp_new->obj), *clust, 0);
279         return result;
280     }
281 
282     /* Initialize the new cluster */
283 #ifndef LOSCFG_FS_FAT_VIRTUAL_PARTITION
284     dir = fs->win;
285 #else
286     dir = PARENTFS(fs)->win;
287 #endif
288 
289     sect = clst2sect(fs, *clust);
290     mem_set(dir, 0, SS(fs));
291     if (type == AM_LNK && target) {
292         /* Write target to symlink */
293         (void)strcpy_s((char *)dir, SS(fs), target);
294     } else {
295         /* Write the dir cluster */
296         mem_set(dir, 0, SS(fs));
297         /* 11, the The max length of of the short file name,  Create "." entry */
298         mem_set(dir + DIR_Name, ' ', 11);
299         dir[DIR_Name] = '.';
300         dir[DIR_Attr] = AM_DIR;
301         st_clust(fs, dir, *clust);
302         mem_cpy(dir + DIR_SIZE, dir, DIR_SIZE); /* Create ".." entry */
303         dir[DIR_SIZE + 1] = '.'; /* Add extra "." */
304         pclust = pdfp->fno.sclst;
305         if (fs->fs_type == FS_FAT32 && pclust == fs->dirbase) {
306             pclust = 0;
307         }
308         st_clust(fs, dir + DIR_SIZE, pclust);
309     }
310 
311 #ifndef LOSCFG_FS_FAT_VIRTUAL_PARTITION
312     fs->winsect = sect++;
313     fs->wflag = 1;
314 #else
315     PARENTFS(fs)->winsect = sect++;
316     PARENTFS(fs)->wflag = 1;
317 #endif
318     result = sync_window(fs);
319     if (result != FR_OK) {
320         remove_chain(&(dp_new->obj), *clust, 0);
321         return result;
322     }
323 
324     /* Rest of directory cluster should set to be zero */
325     if (type == AM_DIR) {
326         mem_set(dir, 0, SS(fs));
327         for (n = fs->csize - 1; n > 0; n--) {
328 #ifndef LOSCFG_FS_FAT_VIRTUAL_PARTITION
329             fs->winsect = sect++;
330             fs->wflag = 1;
331 #else
332             PARENTFS(fs)->winsect = sect++;
333             PARENTFS(fs)->wflag = 1;
334 #endif
335             result = sync_window(fs);
336             if (result != FR_OK) {
337                 remove_chain(&(dp_new->obj), *clust, 0);
338                 return result;
339             }
340         }
341     }
342 
343     return FR_OK;
344 }
345 
fatfs_create_obj(struct Vnode * parent,const char * name,int mode,struct Vnode ** vpp,BYTE type,const char * target)346 static int fatfs_create_obj(struct Vnode *parent, const char *name, int mode, struct Vnode **vpp,
347                             BYTE type,  const char *target)
348 {
349     struct Vnode *vp = NULL;
350     FATFS *fs = (FATFS *)parent->originMount->data;
351     DIR_FILE *dfp = (DIR_FILE *)parent->data;
352     FILINFO *finfo = &(dfp->fno);
353     DIR_FILE *dfp_new = NULL;
354     FILINFO *finfo_new = NULL;
355     DIR *dp_new = NULL;
356     QWORD time;
357     DWORD hash;
358     DWORD clust = 0;
359     FRESULT result;
360     int ret;
361 
362     if ((type != AM_ARC) && (type != AM_DIR) && (type != AM_LNK)) {
363         result = FR_INVALID_NAME;
364         goto ERROR_EXIT;
365     }
366 
367     dfp_new = (DIR_FILE *)zalloc(sizeof(DIR_FILE));
368     if (dfp_new == NULL) {
369         result = FR_NOT_ENOUGH_CORE;
370         goto ERROR_EXIT;
371     }
372 
373     ret = lock_fs(fs);
374     if (ret == FALSE) { /* lock failed */
375         result = FR_TIMEOUT;
376         goto ERROR_FREE;
377     }
378 
379     if (finfo->fattrib & AM_ARC || finfo->fattrib & AM_LNK) {
380         result = FR_NO_DIR;
381         goto ERROR_UNLOCK;
382     }
383 
384     finfo_new = &(dfp_new->fno);
385     LOS_ListInit(&finfo_new->fp_list);
386     dp_new = &(dfp_new->f_dir);
387     dp_new->obj.fs = fs;
388     dp_new->obj.sclust = finfo->sclst;
389 
390     DEF_NAMBUF;
391     INIT_NAMBUF(fs);
392 
393     result = create_name(dp_new, &name);
394     if (result != FR_OK) {
395         goto ERROR_UNLOCK;
396     }
397 
398     result = dir_find(dp_new);
399     if (result == FR_OK) {
400         result = FR_EXIST;
401         goto ERROR_UNLOCK;
402     }
403 
404     if (type == AM_DIR || type == AM_LNK) {
405         result = init_cluster(dfp, dp_new, fs, type, target, &clust);
406         if (result != FR_OK) {
407             goto ERROR_UNLOCK;
408         }
409     }
410 
411     result = dir_register(dp_new);
412     if (result != FR_OK) {
413         goto ERROR_REMOVE_CHAIN;
414     }
415 
416     /* Set the directory entry attribute */
417     if (time_status == SYSTEM_TIME_ENABLE) {
418         time = GET_FATTIME();
419     } else {
420         time = 0;
421     }
422     st_dword(dp_new->dir + DIR_CrtTime, time);
423     st_dword(dp_new->dir + DIR_ModTime, time);
424     st_word(dp_new->dir + DIR_LstAccDate, time >> FTIME_DATE_OFFSET);
425     dp_new->dir[DIR_Attr] = type;
426     if (((DWORD)mode & S_IWUSR) == 0) {
427         dp_new->dir[DIR_Attr] |= AM_RDO;
428     }
429     st_clust(fs, dp_new->dir, clust);
430     if (type == AM_ARC) {
431         st_dword(dp_new->dir + DIR_FileSize, 0);
432     } else if (type == AM_LNK) {
433         st_dword(dp_new->dir + DIR_FileSize, strlen(target));
434     }
435 
436 #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
437     PARENTFS(fs)->wflag = 1;
438 #else
439     fs->wflag = 1;
440 #endif
441     result = sync_fs(fs);
442     if (result != FR_OK) {
443         goto ERROR_REMOVE_CHAIN;
444     }
445     result = dir_read(dp_new, 0);
446     if (result != FR_OK) {
447         goto ERROR_REMOVE_CHAIN;
448     }
449     dp_new->blk_ofs = dir_ofs(dp_new);
450     get_fileinfo(dp_new, finfo_new);
451     if (type == AM_ARC) {
452         dp_new->obj.objsize = 0;
453     } else if (type == AM_LNK) {
454         dp_new->obj.objsize = strlen(target);
455     } else {
456         finfo_new->fsize = fs->csize * SS(fs);
457     }
458 
459     ret = VnodeAlloc(&fatfs_vops, &vp);
460     if (ret != 0) {
461         result = FR_NOT_ENOUGH_CORE;
462         goto ERROR_REMOVE_CHAIN;
463     }
464 
465     vp->parent = parent;
466     vp->fop = &fatfs_fops;
467     vp->data = dfp_new;
468     vp->originMount = parent->originMount;
469     vp->uid = fs->fs_uid;
470     vp->gid = fs->fs_gid;
471     vp->mode = fatfs_get_mode(finfo_new->fattrib, fs->fs_mode);
472     vp->type = fatfstype_2_vnodetype(type);
473 
474     hash = fatfs_hash(dp_new->sect, dp_new->dptr, finfo_new->sclst);
475     ret = VfsHashInsert(vp, hash);
476     if (ret != 0) {
477         result = FR_NOT_ENOUGH_CORE;
478         goto ERROR_REMOVE_CHAIN;
479     }
480     *vpp = vp;
481 
482     unlock_fs(fs, FR_OK);
483     FREE_NAMBUF();
484     return fatfs_sync(parent->originMount->mountFlags, fs);
485 
486 ERROR_REMOVE_CHAIN:
487     remove_chain(&(dp_new->obj), clust, 0);
488 ERROR_UNLOCK:
489     unlock_fs(fs, result);
490     FREE_NAMBUF();
491 ERROR_FREE:
492     free(dfp_new);
493 ERROR_EXIT:
494     return -fatfs_2_vfs(result);
495 }
496 
fatfs_lookup(struct Vnode * parent,const char * path,int len,struct Vnode ** vpp)497 int fatfs_lookup(struct Vnode *parent, const char *path, int len, struct Vnode **vpp)
498 {
499     struct Vnode *vp = NULL;
500     FATFS *fs = (FATFS *)(parent->originMount->data);
501     DIR_FILE *dfp;
502     DIR *dp = NULL;
503     FILINFO *finfo = NULL;
504     DWORD hash;
505     FRESULT result;
506     int ret;
507 
508     dfp = (DIR_FILE *)zalloc(sizeof(DIR_FILE));
509     if (dfp == NULL) {
510         ret = ENOMEM;
511         goto ERROR_EXIT;
512     }
513 
514     ret = lock_fs(fs);
515     if (ret == FALSE) {
516         ret = EBUSY;
517         goto ERROR_FREE;
518     }
519     finfo = &(dfp->fno);
520     LOS_ListInit(&finfo->fp_list);
521     dp = &(dfp->f_dir);
522     dp->obj.fs = fs;
523     dp->obj.sclust = ((DIR_FILE *)(parent->data))->fno.sclst;
524 
525     DEF_NAMBUF;
526     INIT_NAMBUF(fs);
527     result = create_name(dp, &path);
528     if (result != FR_OK) {
529         ret = fatfs_2_vfs(result);
530         goto ERROR_UNLOCK;
531     }
532 
533     result = dir_find(dp);
534     if (result != FR_OK) {
535         ret = fatfs_2_vfs(result);
536         goto ERROR_UNLOCK;
537     }
538 
539     if (dp->fn[NSFLAG] & NS_NONAME) {
540         result = FR_INVALID_NAME;
541         ret = fatfs_2_vfs(result);
542         goto ERROR_UNLOCK;
543     }
544 
545     get_fileinfo(dp, finfo);
546     dp->obj.objsize = 0;
547 
548     hash = fatfs_hash(dp->sect, dp->dptr, finfo->sclst);
549     ret = VfsHashGet(parent->originMount, hash, &vp, fatfs_hash_cmp, dfp);
550     if (ret != 0) {
551         ret = VnodeAlloc(&fatfs_vops, &vp);
552         if (ret != 0) {
553             ret = ENOMEM;
554             result = FR_NOT_ENOUGH_CORE;
555             goto ERROR_UNLOCK;
556         }
557         vp->parent = parent;
558         vp->fop = &fatfs_fops;
559         vp->data = dfp;
560         vp->originMount = parent->originMount;
561         vp->uid = fs->fs_uid;
562         vp->gid = fs->fs_gid;
563         vp->mode = fatfs_get_mode(finfo->fattrib, fs->fs_mode);
564         if (finfo->fattrib & AM_DIR) {
565             vp->type = VNODE_TYPE_DIR;
566             finfo->fsize = fs->csize * SS(fs);
567         } else {
568             vp->type = VNODE_TYPE_REG;
569         }
570 
571         ret = VfsHashInsert(vp, hash);
572         if (ret != 0) {
573             result = FR_INVALID_PARAMETER;
574             goto ERROR_UNLOCK;
575         }
576     } else {
577         vp->parent = parent;
578         free(dfp); /* hash hit dfp is no needed */
579     }
580 
581     unlock_fs(fs, FR_OK);
582     FREE_NAMBUF();
583     *vpp = vp;
584     return 0;
585 
586 ERROR_UNLOCK:
587     unlock_fs(fs, result);
588     FREE_NAMBUF();
589 ERROR_FREE:
590     free(dfp);
591 ERROR_EXIT:
592     return -ret;
593 }
594 
fatfs_create(struct Vnode * parent,const char * name,int mode,struct Vnode ** vpp)595 int fatfs_create(struct Vnode *parent, const char *name, int mode, struct Vnode **vpp)
596 {
597     return fatfs_create_obj(parent, name, mode, vpp, AM_ARC, NULL);
598 }
599 
fatfs_open(struct file * filep)600 int fatfs_open(struct file *filep)
601 {
602     struct Vnode *vp = filep->f_vnode;
603     FATFS *fs = (FATFS *)vp->originMount->data;
604     DIR_FILE *dfp = (DIR_FILE *)vp->data;
605     DIR *dp = &(dfp->f_dir);
606     FILINFO *finfo = &(dfp->fno);
607     FIL *fp;
608     int ret;
609 
610     fp = (FIL *)zalloc(sizeof(FIL) + SS(fs));
611     if (fp == NULL) {
612         ret = ENOMEM;
613         goto ERROR_EXIT;
614     }
615     ret = lock_fs(fs);
616     if (ret == FALSE) {
617         ret = EBUSY;
618         goto ERROR_FREE;
619     }
620 
621     fp->dir_sect = dp->sect;
622     fp->dir_ptr = dp->dir;
623     fp->obj.sclust = finfo->sclst;
624     fp->obj.objsize = finfo->fsize;
625 #if FF_USE_FASTSEEK
626     fp->cltbl = 0; /* Disable fast seek mode */
627 #endif
628     fp->obj.fs = fs;
629     fp->obj.id = fs->id;
630     fp->flag = FA_READ | FA_WRITE;
631     fp->err = 0;
632     fp->sect = 0;
633     fp->fptr = 0;
634     fp->buf = (BYTE *)fp + sizeof(FIL);
635     LOS_ListAdd(&finfo->fp_list, &fp->fp_entry);
636     unlock_fs(fs, FR_OK);
637 
638     filep->f_priv = fp;
639     return 0;
640 
641 ERROR_FREE:
642     free(fp);
643 ERROR_EXIT:
644     return -ret;
645 }
646 
fatfs_close(struct file * filep)647 int fatfs_close(struct file *filep)
648 {
649     FIL *fp = (FIL *)filep->f_priv;
650     FATFS *fs = fp->obj.fs;
651     FRESULT result;
652     int ret;
653 
654     ret = lock_fs(fs);
655     if (ret == FALSE) {
656         return -EBUSY;
657     }
658 #if !FF_FS_READONLY
659     result = f_sync(fp); /* Flush cached data */
660     if (result != FR_OK) {
661         goto EXIT;
662     }
663     ret = fatfs_sync(filep->f_vnode->originMount->mountFlags, fs);
664     if (ret != 0) {
665         unlock_fs(fs, FR_OK);
666         return ret;
667     }
668 #endif
669     LOS_ListDelete(&fp->fp_entry);
670     free(fp);
671     filep->f_priv = NULL;
672 EXIT:
673     unlock_fs(fs, result);
674     return -fatfs_2_vfs(result);
675 }
676 
fatfs_read(struct file * filep,char * buff,size_t count)677 int fatfs_read(struct file *filep, char *buff, size_t count)
678 {
679     FIL *fp = (FIL *)filep->f_priv;
680     FATFS *fs = fp->obj.fs;
681     struct Vnode *vp = filep->f_vnode;
682     FILINFO *finfo = &((DIR_FILE *)(vp->data))->fno;
683     size_t rcount;
684     FRESULT result;
685     int ret;
686 
687     ret = lock_fs(fs);
688     if (ret == FALSE) {
689         return -EBUSY;
690     }
691     fp->obj.objsize = finfo->fsize;
692     fp->obj.sclust = finfo->sclst;
693     result = f_read(fp, buff, count, &rcount);
694     if (result != FR_OK) {
695         goto EXIT;
696     }
697     filep->f_pos = fp->fptr;
698 EXIT:
699     unlock_fs(fs, result);
700     return rcount;
701 }
702 
update_dir(DIR * dp,FILINFO * finfo)703 static FRESULT update_dir(DIR *dp, FILINFO *finfo)
704 {
705     FATFS *fs = dp->obj.fs;
706     DWORD tm;
707     BYTE *dbuff = NULL;
708     FRESULT result;
709 
710     result = move_window(fs, dp->sect);
711     if (result != FR_OK) {
712         return result;
713     }
714     dbuff = fs->win + dp->dptr % SS(fs);
715     dbuff[DIR_Attr] = finfo->fattrib;
716     st_clust(fs, dbuff, finfo->sclst); /* Update start cluster */
717     st_dword(dbuff + DIR_FileSize, (DWORD)finfo->fsize); /* Update file size */
718     if (time_status == SYSTEM_TIME_ENABLE) {
719         tm = GET_FATTIME();
720     } else {
721         tm = 0;
722     }
723     st_dword(dbuff + DIR_ModTime, tm); /* Update mtime */
724     st_word(dbuff + DIR_LstAccDate, tm >> FTIME_DATE_OFFSET); /* Update access date */
725 #ifndef LOSCFG_FS_FAT_VIRTUAL_PARTITION
726     fs->wflag = 1;
727 #else
728     PARENTFS(fs)->wflag = 1;
729 #endif
730     return sync_fs(fs);
731 }
732 
fatfs_lseek64(struct file * filep,off64_t offset,int whence)733 off64_t fatfs_lseek64(struct file *filep, off64_t offset, int whence)
734 {
735     FIL *fp = (FIL *)filep->f_priv;
736     FATFS *fs = fp->obj.fs;
737     struct Vnode *vp = filep->f_vnode;
738     DIR_FILE *dfp = (DIR_FILE *)vp->data;
739     FILINFO *finfo = &(dfp->fno);
740     struct Mount *mount = vp->originMount;
741     FSIZE_t fpos;
742     FRESULT result;
743     int ret;
744 
745     switch (whence) {
746         case SEEK_CUR:
747             offset = filep->f_pos + offset;
748             if (offset < 0) {
749                 return -EINVAL;
750             }
751             fpos = offset;
752             break;
753         case SEEK_SET:
754             if (offset < 0) {
755                 return -EINVAL;
756             }
757             fpos = offset;
758             break;
759         case SEEK_END:
760             offset = (off_t)((long long)finfo->fsize + offset);
761             if (offset < 0) {
762                 return -EINVAL;
763             }
764             fpos = offset;
765             break;
766         default:
767             return -EINVAL;
768     }
769 
770     if (offset >= FAT32_MAXSIZE) {
771         return -EINVAL;
772     }
773 
774     ret = lock_fs(fs);
775     if (ret == FALSE) {
776         return -EBUSY;
777     }
778 
779     if (fpos > finfo->fsize) {
780         if ((filep->f_oflags & O_ACCMODE) == O_RDONLY) {
781             result = FR_DENIED;
782             goto ERROR_EXIT;
783         }
784         if (mount->mountFlags & MS_RDONLY) {
785             result = FR_WRITE_PROTECTED;
786             goto ERROR_EXIT;
787         }
788     }
789     fp->obj.sclust = finfo->sclst;
790     fp->obj.objsize = finfo->fsize;
791 
792     result = f_lseek(fp, fpos);
793     finfo->fsize = fp->obj.objsize;
794     finfo->sclst = fp->obj.sclust;
795     if (result != FR_OK) {
796         goto ERROR_EXIT;
797     }
798 
799     result = f_sync(fp);
800     if (result != FR_OK) {
801         goto ERROR_EXIT;
802     }
803     filep->f_pos = fpos;
804 
805     unlock_fs(fs, FR_OK);
806     return fpos;
807 ERROR_EXIT:
808     unlock_fs(fs, result);
809     return -fatfs_2_vfs(result);
810 }
811 
fatfs_lseek(struct file * filep,off_t offset,int whence)812 off_t fatfs_lseek(struct file *filep, off_t offset, int whence)
813 {
814     return (off_t)fatfs_lseek64(filep, offset, whence);
815 }
816 
update_filbuff(FILINFO * finfo,FIL * wfp,const char * data)817 static int update_filbuff(FILINFO *finfo, FIL *wfp, const char  *data)
818 {
819     LOS_DL_LIST *list = &finfo->fp_list;
820     FATFS *fs = wfp->obj.fs;
821     FIL *entry = NULL;
822     int ret = 0;
823 
824     LOS_DL_LIST_FOR_EACH_ENTRY(entry, list, FIL, fp_entry) {
825         if (entry == wfp) {
826             continue;
827         }
828         if (entry->sect != 0) {
829             if (disk_read(fs->pdrv, entry->buf, entry->sect, 1) != RES_OK) {
830                 ret = -1;
831             }
832         }
833     }
834 
835     return ret;
836 }
837 
fatfs_write(struct file * filep,const char * buff,size_t count)838 int fatfs_write(struct file *filep, const char *buff, size_t count)
839 {
840     FIL *fp = (FIL *)filep->f_priv;
841     FATFS *fs = fp->obj.fs;
842     struct Vnode *vp = filep->f_vnode;
843     FILINFO *finfo = &(((DIR_FILE *)vp->data)->fno);
844     size_t wcount;
845     FRESULT result;
846     int ret;
847 
848     ret = lock_fs(fs);
849     if (ret == FALSE) {
850         return -EBUSY;
851     }
852     fp->obj.objsize = finfo->fsize;
853     fp->obj.sclust = finfo->sclst;
854     result = f_write(fp, buff, count, &wcount);
855     if (result != FR_OK) {
856         goto ERROR_EXIT;
857     }
858 
859     finfo->fsize = fp->obj.objsize;
860     finfo->sclst = fp->obj.sclust;
861     result = f_sync(fp);
862     if (result != FR_OK) {
863         goto ERROR_EXIT;
864     }
865     update_filbuff(finfo, fp, buff);
866 
867     filep->f_pos = fp->fptr;
868 
869     unlock_fs(fs, FR_OK);
870     return wcount;
871 ERROR_EXIT:
872     unlock_fs(fs, result);
873     return -fatfs_2_vfs(result);
874 }
875 
fatfs_fsync(struct file * filep)876 int fatfs_fsync(struct file *filep)
877 {
878     FIL *fp = filep->f_priv;
879     FATFS *fs = fp->obj.fs;
880     FRESULT result;
881     int ret;
882 
883     ret = lock_fs(fs);
884     if (ret == FALSE) {
885         return -EBUSY;
886     }
887 
888     result = f_sync(fp);
889     unlock_fs(fs, result);
890     return -fatfs_2_vfs(result);
891 }
892 
fatfs_fallocate64(struct file * filep,int mode,off64_t offset,off64_t len)893 int fatfs_fallocate64(struct file *filep, int mode, off64_t offset, off64_t len)
894 {
895     FIL *fp = (FIL *)filep->f_priv;
896     FATFS *fs = fp->obj.fs;
897     struct Vnode *vp = filep->f_vnode;
898     FILINFO *finfo = &((DIR_FILE *)(vp->data))->fno;
899     FRESULT result;
900     int ret;
901 
902     if (offset < 0 || len <= 0) {
903         return -EINVAL;
904     }
905 
906     if (len >= FAT32_MAXSIZE || offset >= FAT32_MAXSIZE ||
907         len + offset >= FAT32_MAXSIZE) {
908         return -EINVAL;
909     }
910 
911     if (mode != FALLOC_FL_KEEP_SIZE) {
912         return -EINVAL;
913     }
914 
915     ret = lock_fs(fs);
916     if (ret == FALSE) {
917         return -EBUSY;
918     }
919     result = f_expand(fp, (FSIZE_t)offset, (FSIZE_t)len, 1);
920     if (result == FR_OK) {
921         if (finfo->sclst == 0) {
922             finfo->sclst = fp->obj.sclust;
923         }
924         result = f_sync(fp);
925     }
926     unlock_fs(fs, result);
927 
928     return -fatfs_2_vfs(result);
929 }
930 
realloc_cluster(FILINFO * finfo,FFOBJID * obj,FSIZE_t size)931 static FRESULT realloc_cluster(FILINFO *finfo, FFOBJID *obj, FSIZE_t size)
932 {
933     FATFS *fs = obj->fs;
934     off64_t remain;
935     DWORD cclust;
936     DWORD pclust;
937     QWORD csize;
938     FRESULT result;
939 
940     if (size == 0) { /* Remove cluster chain */
941         if (finfo->sclst != 0) {
942             result = remove_chain(obj, finfo->sclst, 0);
943             if (result != FR_OK) {
944                 return result;
945             }
946             finfo->sclst = 0;
947         }
948         return FR_OK;
949     }
950 
951     remain = size;
952     csize = SS(fs) * fs->csize;
953     if (finfo->sclst == 0) { /* Allocate one cluster if file doesn't have any cluster */
954         cclust = create_chain(obj, 0);
955         if (cclust == 0) {
956             return FR_NO_SPACE_LEFT;
957         }
958         if (cclust == 1 || cclust == DISK_ERROR) {
959             return FR_DISK_ERR;
960         }
961         finfo->sclst = cclust;
962     }
963     cclust = finfo->sclst;
964     while (remain > csize) { /* Follow or strentch the cluster chain */
965         pclust = cclust;
966         cclust = create_chain(obj, pclust);
967         if (cclust == 0) {
968             return FR_NO_SPACE_LEFT;
969         }
970         if (cclust == 1 || cclust == DISK_ERROR) {
971             return FR_DISK_ERR;
972         }
973         remain -= csize;
974     }
975     pclust = cclust;
976     cclust = get_fat(obj, pclust);
977     if ((cclust == BAD_CLUSTER) || (cclust == DISK_ERROR)) {
978         return FR_DISK_ERR;
979     }
980     if (!fatfs_is_last_cluster(obj->fs, cclust)) { /* Remove extra cluster if existing */
981         result = remove_chain(obj, cclust, pclust);
982         if (result != FR_OK) {
983             return result;
984         }
985     }
986 
987     return FR_OK;
988 }
989 
fatfs_fallocate(struct file * filep,int mode,off_t offset,off_t len)990 int fatfs_fallocate(struct file *filep, int mode, off_t offset, off_t len)
991 {
992     return fatfs_fallocate64(filep, mode, offset, len);
993 }
994 
fatfs_truncate64(struct Vnode * vp,off64_t len)995 int fatfs_truncate64(struct Vnode *vp, off64_t len)
996 {
997     FATFS *fs = (FATFS *)vp->originMount->data;
998     DIR_FILE *dfp = (DIR_FILE *)vp->data;
999     DIR *dp = &(dfp->f_dir);
1000     FILINFO *finfo = &(dfp->fno);
1001     FFOBJID object;
1002     FRESULT result = FR_OK;
1003     int ret;
1004 
1005     if (len < 0 || len >= FAT32_MAXSIZE) {
1006         return -EINVAL;
1007     }
1008 
1009     ret = lock_fs(fs);
1010     if (ret == FALSE) {
1011         result = FR_TIMEOUT;
1012         goto ERROR_OUT;
1013     }
1014     if (len == finfo->fsize) {
1015         unlock_fs(fs, FR_OK);
1016         return 0;
1017     }
1018 
1019     object.fs = fs;
1020     result = realloc_cluster(finfo, &object, (FSIZE_t)len);
1021     if (result != FR_OK) {
1022         goto ERROR_UNLOCK;
1023     }
1024     finfo->fsize = (FSIZE_t)len;
1025 
1026     result = update_dir(dp, finfo);
1027     if (result != FR_OK) {
1028         goto ERROR_UNLOCK;
1029     }
1030     unlock_fs(fs, FR_OK);
1031     return fatfs_sync(vp->originMount->mountFlags, fs);
1032 ERROR_UNLOCK:
1033     unlock_fs(fs, result);
1034 ERROR_OUT:
1035     return -fatfs_2_vfs(result);
1036 }
1037 
fatfs_truncate(struct Vnode * vp,off_t len)1038 int fatfs_truncate(struct Vnode *vp, off_t len)
1039 {
1040     return fatfs_truncate64(vp, len);
1041 }
1042 
fat_bind_check(struct Vnode * blk_driver,los_part ** partition)1043 static int fat_bind_check(struct Vnode *blk_driver, los_part **partition)
1044 {
1045     los_part *part = NULL;
1046 
1047     if (blk_driver == NULL || blk_driver->data == NULL) {
1048         return ENODEV;
1049     }
1050 
1051     struct drv_data *dd = blk_driver->data;
1052     if (dd->ops == NULL) {
1053         return ENODEV;
1054     }
1055     const struct block_operations *bops = dd->ops;
1056     if (bops->open == NULL) {
1057         return EINVAL;
1058     }
1059     if (bops->open(blk_driver) < 0) {
1060         return EBUSY;
1061     }
1062 
1063     part = los_part_find(blk_driver);
1064     if (part == NULL) {
1065         return ENODEV;
1066     }
1067     if (part->part_name != NULL) {
1068         bops->close(blk_driver);
1069         return EBUSY;
1070     }
1071 
1072 #ifndef FF_MULTI_PARTITION
1073     if (part->part_no_mbr > 1) {
1074         bops->close(blk_driver);
1075         return EPERM;
1076     }
1077 #endif
1078 
1079     *partition = part;
1080     return 0;
1081 }
1082 
fatfs_mount(struct Mount * mnt,struct Vnode * blk_device,const void * data)1083 int fatfs_mount(struct Mount *mnt, struct Vnode *blk_device, const void *data)
1084 {
1085     struct Vnode *vp = NULL;
1086     FATFS *fs = NULL;
1087     DIR_FILE *dfp = NULL;
1088     los_part *part = NULL;
1089     QWORD start_sector;
1090     BYTE fmt;
1091     DWORD hash;
1092     FRESULT result;
1093     int ret;
1094 
1095     ret = fat_bind_check(blk_device, &part);
1096     if (ret != 0) {
1097         goto ERROR_EXIT;
1098     }
1099 
1100     ret = SetDiskPartName(part, "vfat");
1101     if (ret != 0) {
1102         ret = EIO;
1103         goto ERROR_EXIT;
1104     }
1105 
1106     fs = (FATFS *)zalloc(sizeof(FATFS));
1107     if (fs == NULL) {
1108         ret = ENOMEM;
1109         goto ERROR_PARTNAME;
1110     }
1111 
1112 #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
1113     fs->vir_flag = FS_PARENT;
1114     fs->parent_fs = fs;
1115     fs->vir_amount = DISK_ERROR;
1116     fs->vir_avail = FS_VIRDISABLE;
1117 #endif
1118 
1119     ret = ff_cre_syncobj(0, &fs->sobj);
1120     if (ret == 0) { /* create sync object failed */
1121         ret = EINVAL;
1122         goto ERROR_WITH_FS;
1123     }
1124 
1125     ret = lock_fs(fs);
1126     if (ret == FALSE) {
1127         ret = EBUSY;
1128         goto ERROR_WITH_MUX;
1129     }
1130 
1131     fs->fs_type = 0;
1132     fs->pdrv = part->part_id;
1133 
1134 #if FF_MAX_SS != FF_MIN_SS  /* Get sector size (multiple sector size cfg only) */
1135     if (disk_ioctl(fs->pdrv, GET_SECTOR_SIZE, &(fs->ssize)) != RES_OK) {
1136         ret = EIO;
1137         goto ERROR_WITH_LOCK;
1138     }
1139     if (fs->ssize > FF_MAX_SS || fs->ssize < FF_MIN_SS || (fs->ssize & (fs->ssize - 1))) {
1140         ret = EIO;
1141         goto ERROR_WITH_LOCK;
1142     }
1143 #endif
1144 
1145     fs->win = (BYTE *)ff_memalloc(SS(fs));
1146     if (fs->win == NULL) {
1147         ret = ENOMEM;
1148         goto ERROR_WITH_LOCK;
1149     }
1150 
1151     result = find_fat_partition(fs, part, &fmt, &start_sector);
1152     if (result != FR_OK) {
1153         ret = fatfs_2_vfs(result);
1154         goto ERROR_WITH_FSWIN;
1155     }
1156 
1157     result = init_fatobj(fs, fmt, start_sector);
1158     if (result != FR_OK) {
1159         ret = fatfs_2_vfs(result);
1160         goto ERROR_WITH_FSWIN;
1161     }
1162 
1163     fs->fs_uid = mnt->vnodeBeCovered->uid;
1164     fs->fs_gid = mnt->vnodeBeCovered->gid;
1165     fs->fs_dmask = GetUmask();
1166     fs->fs_fmask = GetUmask();
1167     fs->fs_mode = mnt->vnodeBeCovered->mode & (S_IRWXU | S_IRWXG | S_IRWXO);
1168 
1169     dfp = (DIR_FILE *)zalloc(sizeof(DIR_FILE));
1170     if (dfp == NULL) {
1171         ret = ENOMEM;
1172         goto ERROR_WITH_FSWIN;
1173     }
1174 
1175     dfp->f_dir.obj.fs = fs;
1176     dfp->f_dir.obj.sclust = 0; /* set start clust 0, root */
1177     dfp->f_dir.obj.attr = AM_DIR;
1178     dfp->f_dir.obj.objsize = 0; /* dir size is 0 */
1179     dfp->fno.fsize = 0;
1180     dfp->fno.fdate = 0;
1181     dfp->fno.ftime = 0;
1182     dfp->fno.fattrib = AM_DIR;
1183     dfp->fno.sclst = 0;
1184     dfp->fno.fsize = fs->csize * SS(fs);
1185     dfp->fno.fname[0] = '/'; /* Mark as root dir */
1186     dfp->fno.fname[1] = '\0';
1187     LOS_ListInit(&(dfp->fno.fp_list));
1188 
1189     ret = VnodeAlloc(&fatfs_vops, &vp);
1190     if (ret != 0) {
1191         ret = ENOMEM;
1192         goto ERROR_WITH_FSWIN;
1193     }
1194 
1195     mnt->data = fs;
1196     mnt->vnodeCovered = vp;
1197 
1198     vp->parent = mnt->vnodeBeCovered;
1199     vp->fop = &fatfs_fops;
1200     vp->data = dfp;
1201     vp->originMount = mnt;
1202     vp->uid = fs->fs_uid;
1203     vp->gid = fs->fs_gid;
1204     vp->mode = mnt->vnodeBeCovered->mode;
1205     vp->type = VNODE_TYPE_DIR;
1206 
1207     hash = fatfs_hash(0, 0, 0);
1208     ret = VfsHashInsert(vp, hash);
1209     if (ret != 0) {
1210         ret = -ret;
1211         goto ERROR_WITH_LOCK;
1212     }
1213     unlock_fs(fs, FR_OK);
1214 
1215     return 0;
1216 
1217 ERROR_WITH_FSWIN:
1218     ff_memfree(fs->win);
1219 ERROR_WITH_LOCK:
1220     unlock_fs(fs, FR_OK);
1221 ERROR_WITH_MUX:
1222     ff_del_syncobj(&fs->sobj);
1223 ERROR_WITH_FS:
1224     free(fs);
1225 ERROR_PARTNAME:
1226     if (part->part_name) {
1227         free(part->part_name);
1228         part->part_name = NULL;
1229     }
1230 ERROR_EXIT:
1231     return -ret;
1232 }
1233 
fatfs_umount(struct Mount * mnt,struct Vnode ** blkdriver)1234 int fatfs_umount(struct Mount *mnt, struct Vnode **blkdriver)
1235 {
1236     struct Vnode *device;
1237     FATFS *fs = (FATFS *)mnt->data;
1238     los_part *part;
1239     int ret;
1240 
1241     ret = lock_fs(fs);
1242     if (ret == FALSE) {
1243         return -EBUSY;
1244     }
1245 
1246     part = get_part(fs->pdrv);
1247     if (part == NULL) {
1248         unlock_fs(fs, FR_OK);
1249         return -ENODEV;
1250     }
1251     device = part->dev;
1252     if (device == NULL) {
1253         unlock_fs(fs, FR_OK);
1254         return -ENODEV;
1255     }
1256 #ifdef LOSCFG_FS_FAT_CACHE
1257     ret = OsSdSync(part->disk_id);
1258     if (ret != 0) {
1259         unlock_fs(fs, FR_DISK_ERR);
1260         return -EIO;
1261     }
1262 #endif
1263     if (part->part_name != NULL) {
1264         free(part->part_name);
1265         part->part_name = NULL;
1266     }
1267 
1268     struct drv_data *dd = device->data;
1269     if (dd->ops == NULL) {
1270         unlock_fs(fs, FR_OK);
1271         return ENODEV;
1272     }
1273 
1274     const struct block_operations *bops = dd->ops;
1275     if (bops != NULL && bops->close != NULL) {
1276         bops->close(*blkdriver);
1277     }
1278 
1279     if (fs->win != NULL) {
1280         ff_memfree(fs->win);
1281     }
1282 
1283     unlock_fs(fs, FR_OK);
1284 
1285     ret = ff_del_syncobj(&fs->sobj);
1286     if (ret == FALSE) {
1287         return -EINVAL;
1288     }
1289     free(fs);
1290 
1291     *blkdriver = device;
1292 
1293     return 0;
1294 }
1295 
fatfs_sync_adapt(struct Mount * mnt)1296 int fatfs_sync_adapt(struct Mount *mnt)
1297 {
1298     (void)mnt;
1299     int ret = 0;
1300 #ifdef LOSCFG_FS_FAT_CACHE
1301     struct Vnode *dev = NULL;
1302     los_part *part = NULL;
1303 
1304     if (mnt == NULL) {
1305         return -EINVAL;
1306     }
1307 
1308     dev = mnt->vnodeDev;
1309     part = los_part_find(dev);
1310     if (part == NULL) {
1311         return -EINVAL;
1312     }
1313 
1314     ret = OsSdSync(part->disk_id);
1315 #endif
1316     return ret;
1317 }
1318 
fatfs_statfs(struct Mount * mnt,struct statfs * info)1319 int fatfs_statfs(struct Mount *mnt, struct statfs *info)
1320 {
1321     FATFS *fs = (FATFS *)mnt->data;
1322     DWORD nclst = 0;
1323     FRESULT result = FR_OK;
1324     int ret;
1325 
1326     info->f_type = MSDOS_SUPER_MAGIC;
1327 #if FF_MAX_SS != FF_MIN_SS
1328     info->f_bsize = fs->ssize * fs->csize;
1329 #else
1330     info->f_bsize = FF_MIN_SS * fs->csize;
1331 #endif
1332     info->f_blocks = fs->n_fatent;
1333     ret = lock_fs(fs);
1334     if (ret == FALSE) {
1335         return -EBUSY;
1336     }
1337     /* free cluster is unavailable, update it */
1338     if (fs->free_clst == DISK_ERROR) {
1339         result = fat_count_free_entries(&nclst, fs);
1340     }
1341     info->f_bfree = fs->free_clst;
1342     info->f_bavail = fs->free_clst;
1343     unlock_fs(fs, result);
1344 
1345 #if FF_USE_LFN
1346     /* Maximum length of filenames */
1347     info->f_namelen = FF_MAX_LFN;
1348 #else
1349     /* Maximum length of filenames: 8 is the basename length, 1 is the dot, 3 is the extension length */
1350     info->f_namelen = (8 + 1 + 3);
1351 #endif
1352     info->f_fsid.__val[0] = MSDOS_SUPER_MAGIC;
1353     info->f_fsid.__val[1] = 1;
1354     info->f_frsize = SS(fs) * fs->csize;
1355     info->f_files = 0;
1356     info->f_ffree = 0;
1357     info->f_flags = mnt->mountFlags;
1358 
1359     return -fatfs_2_vfs(result);
1360 }
1361 
GET_SECONDS(WORD ftime)1362 static inline int GET_SECONDS(WORD ftime)
1363 {
1364     return (ftime & BITMASK5) * SEC_MULTIPLIER;
1365 }
GET_MINUTES(WORD ftime)1366 static inline int GET_MINUTES(WORD ftime)
1367 {
1368     return (ftime >> FTIME_MIN_OFFSET) & BITMASK6;
1369 }
GET_HOURS(WORD ftime)1370 static inline int GET_HOURS(WORD ftime)
1371 {
1372     return (ftime >> FTIME_HR_OFFSET) & BITMASK5;
1373 }
GET_DAY(WORD fdate)1374 static inline int GET_DAY(WORD fdate)
1375 {
1376     return fdate & BITMASK5;
1377 }
GET_MONTH(WORD fdate)1378 static inline int GET_MONTH(WORD fdate)
1379 {
1380     return (fdate >> FTIME_MTH_OFFSET) & BITMASK4;
1381 }
GET_YEAR(WORD fdate)1382 static inline int GET_YEAR(WORD fdate)
1383 {
1384     return (fdate >> FTIME_YEAR_OFFSET) & BITMASK7;
1385 }
1386 
fattime_transfer(WORD fdate,WORD ftime)1387 static time_t fattime_transfer(WORD fdate, WORD ftime)
1388 {
1389     struct tm time = { 0 };
1390     time.tm_sec = GET_SECONDS(ftime);
1391     time.tm_min = GET_MINUTES(ftime);
1392     time.tm_hour = GET_HOURS(ftime);
1393     time.tm_mday = GET_DAY(fdate);
1394     time.tm_mon = GET_MONTH(fdate);
1395     time.tm_year = GET_YEAR(fdate) + YEAR_OFFSET; /* Year start from 1980 in FATFS */
1396     time_t ret = mktime(&time);
1397     return ret;
1398 }
1399 
fattime_format(time_t time)1400 DWORD fattime_format(time_t time)
1401 {
1402     struct tm st;
1403     DWORD ftime;
1404 
1405     localtime_r(&time, &st);
1406 
1407     ftime = (DWORD)st.tm_mday;
1408     ftime |= ((DWORD)st.tm_mon) << FTIME_MTH_OFFSET;
1409     ftime |= ((DWORD)((st.tm_year > YEAR_OFFSET) ? (st.tm_year - YEAR_OFFSET) : 0)) << FTIME_YEAR_OFFSET;
1410     ftime <<= FTIME_DATE_OFFSET;
1411 
1412     ftime |= (DWORD)st.tm_sec / SEC_MULTIPLIER;
1413     ftime |= ((DWORD)st.tm_min) << FTIME_MIN_OFFSET;
1414     ftime |= ((DWORD)st.tm_hour) << FTIME_HR_OFFSET;
1415 
1416     return ftime;
1417 }
1418 
fatfs_stat(struct Vnode * vp,struct stat * sp)1419 int fatfs_stat(struct Vnode *vp, struct stat* sp)
1420 {
1421     FATFS *fs = (FATFS *)vp->originMount->data;
1422     DIR_FILE *dfp = (DIR_FILE *)vp->data;
1423     FILINFO *finfo = &(dfp->fno);
1424     time_t time;
1425     int ret;
1426 
1427     ret = lock_fs(fs);
1428     if (ret == FALSE) {
1429         return EBUSY;
1430     }
1431 
1432     sp->st_dev = fs->pdrv;
1433     sp->st_mode = vp->mode;
1434     sp->st_nlink = 1;
1435     sp->st_uid = fs->fs_uid;
1436     sp->st_gid = fs->fs_gid;
1437     sp->st_size = finfo->fsize;
1438     sp->st_blksize = fs->csize * SS(fs);
1439     if (finfo->fattrib & AM_ARC) {
1440         sp->st_blocks = finfo->fsize ? ((finfo->fsize - 1) / SS(fs) / fs->csize + 1) : 0;
1441     } else {
1442         sp->st_blocks = fs->csize;
1443     }
1444     time = fattime_transfer(finfo->fdate, finfo->ftime);
1445     sp->st_mtime = time;
1446 
1447     /* Adapt to kstat member "long tv_sec" */
1448     sp->__st_mtim32.tv_sec = (long)time;
1449 
1450     unlock_fs(fs, FR_OK);
1451     return 0;
1452 }
1453 
fatfs_chtime(DIR * dp,struct IATTR * attr)1454 void fatfs_chtime(DIR *dp, struct IATTR *attr)
1455 {
1456     BYTE *dir = dp->dir;
1457     DWORD ftime;
1458     if (attr->attr_chg_valid & CHG_ATIME) {
1459         ftime = fattime_format(attr->attr_chg_atime);
1460         st_word(dir + DIR_LstAccDate, (ftime >> FTIME_DATE_OFFSET));
1461     }
1462 
1463     if (attr->attr_chg_valid & CHG_CTIME) {
1464         ftime = fattime_format(attr->attr_chg_ctime);
1465         st_dword(dir + DIR_CrtTime, ftime);
1466     }
1467 
1468     if (attr->attr_chg_valid & CHG_MTIME) {
1469         ftime = fattime_format(attr->attr_chg_mtime);
1470         st_dword(dir + DIR_ModTime, ftime);
1471     }
1472 }
1473 
fatfs_chattr(struct Vnode * vp,struct IATTR * attr)1474 int fatfs_chattr(struct Vnode *vp, struct IATTR *attr)
1475 {
1476     FATFS *fs = (FATFS *)vp->originMount->data;
1477     DIR_FILE *dfp = (DIR_FILE *)vp->data;
1478     DIR *dp = &(dfp->f_dir);
1479     FILINFO *finfo = &(dfp->fno);
1480     BYTE *dir = dp->dir;
1481     DWORD ftime;
1482     FRESULT result;
1483     int ret;
1484 
1485     if (finfo->fname[0] == '/') { /* Is root dir of fatfs ? */
1486         return 0;
1487     }
1488 
1489     ret = lock_fs(fs);
1490     if (ret == FALSE) {
1491         result = FR_TIMEOUT;
1492         goto ERROR_OUT;
1493     }
1494 
1495     result = move_window(fs, dp->sect);
1496     if (result != FR_OK) {
1497         goto ERROR_UNLOCK;
1498     }
1499 
1500     if (attr->attr_chg_valid & CHG_MODE) {
1501         /* FAT only support readonly flag */
1502         if ((attr->attr_chg_mode & S_IWUSR) == 0 && (finfo->fattrib & AM_RDO) == 0) {
1503             dir[DIR_Attr] |= AM_RDO;
1504             finfo->fattrib |= AM_RDO;
1505             fs->wflag = 1;
1506         } else if ((attr->attr_chg_mode & S_IWUSR) != 0 && (finfo->fattrib & AM_RDO) != 0) {
1507             dir[DIR_Attr] &= ~AM_RDO;
1508             finfo->fattrib &= ~AM_RDO;
1509             fs->wflag = 1;
1510         }
1511         vp->mode = fatfs_get_mode(finfo->fattrib, fs->fs_mode);
1512     }
1513 
1514     if (attr->attr_chg_valid & (CHG_ATIME | CHG_CTIME | CHG_MTIME)) {
1515         fatfs_chtime(dp, attr);
1516         ftime = ld_dword(dp->dir + DIR_ModTime);
1517         finfo->fdate = (WORD)(ftime >> FTIME_DATE_OFFSET);
1518         finfo->ftime = (WORD)ftime;
1519     }
1520 
1521     result = sync_window(fs);
1522     if (result != FR_OK) {
1523         goto ERROR_UNLOCK;
1524     }
1525 
1526     unlock_fs(fs, FR_OK);
1527     return fatfs_sync(vp->originMount->mountFlags, fs);
1528 ERROR_UNLOCK:
1529     unlock_fs(fs, result);
1530 ERROR_OUT:
1531     return -fatfs_2_vfs(result);
1532 }
1533 
fatfs_opendir(struct Vnode * vp,struct fs_dirent_s * idir)1534 int fatfs_opendir(struct Vnode *vp, struct fs_dirent_s *idir)
1535 {
1536     FATFS *fs = vp->originMount->data;
1537     DIR_FILE *dfp = (DIR_FILE *)vp->data;
1538     FILINFO *finfo = &(dfp->fno);
1539     DIR *dp;
1540     DWORD clst;
1541     FRESULT result;
1542     int ret;
1543 
1544     dp = (DIR*)zalloc(sizeof(DIR));
1545     if (dp == NULL) {
1546         return -ENOMEM;
1547     }
1548 
1549     ret = lock_fs(fs);
1550     if (ret == FALSE) {
1551         return -EBUSY;
1552     }
1553     clst = finfo->sclst;
1554     dp->obj.fs = fs;
1555     dp->obj.sclust = clst;
1556 
1557     result = dir_sdi(dp, 0);
1558     if (result != FR_OK) {
1559         free(dp);
1560         unlock_fs(fs, result);
1561         return -fatfs_2_vfs(result);
1562     }
1563     unlock_fs(fs, result);
1564     idir->u.fs_dir = dp;
1565 
1566     return 0;
1567 }
1568 
fatfs_readdir(struct Vnode * vp,struct fs_dirent_s * idir)1569 int fatfs_readdir(struct Vnode *vp, struct fs_dirent_s *idir)
1570 {
1571     FATFS *fs = vp->originMount->data;
1572     FILINFO fno;
1573     DIR* dp = (DIR*)idir->u.fs_dir;
1574     struct dirent *dirp = NULL;
1575     FRESULT result;
1576     int ret, i;
1577 
1578     ret = lock_fs(fs);
1579     if (ret == FALSE) { /* Lock fs failed */
1580         return -EBUSY;
1581     }
1582     DEF_NAMBUF;
1583     INIT_NAMBUF(fs);
1584     for (i = 0; i < idir->read_cnt; i++) {
1585         /* using dir_read_massive to promote performance */
1586         result = dir_read_massive(dp, 0);
1587         if (result == FR_NO_FILE) {
1588             break;
1589         } else if (result != FR_OK) {
1590             goto ERROR_UNLOCK;
1591         }
1592         get_fileinfo(dp, &fno);
1593         /* 0x00 for end of directory and 0xFF for directory is empty */
1594         if (fno.fname[0] == 0x00 || fno.fname[0] == (TCHAR)0xFF) {
1595             break;
1596         }
1597 
1598         dirp = &(idir->fd_dir[i]);
1599         if (fno.fattrib & AM_DIR) { /* is dir */
1600             dirp->d_type = DT_DIR;
1601         } else {
1602             dirp->d_type = DT_REG;
1603         }
1604         if (strncpy_s(dirp->d_name, sizeof(dirp->d_name), fno.fname, strlen(fno.fname)) != EOK) {
1605             result = FR_NOT_ENOUGH_CORE;
1606             goto ERROR_UNLOCK;
1607         }
1608         result = dir_next(dp, 0);
1609         if (result != FR_OK && result != FR_NO_FILE) {
1610             goto ERROR_UNLOCK;
1611         }
1612         idir->fd_position++;
1613         idir->fd_dir[i].d_off = idir->fd_position;
1614         idir->fd_dir[i].d_reclen = (uint16_t)sizeof(struct dirent);
1615     }
1616     unlock_fs(fs, FR_OK);
1617     FREE_NAMBUF();
1618     return i;
1619 ERROR_UNLOCK:
1620     unlock_fs(fs, result);
1621     FREE_NAMBUF();
1622     return -fatfs_2_vfs(result);
1623 }
1624 
fatfs_rewinddir(struct Vnode * vp,struct fs_dirent_s * dir)1625 int fatfs_rewinddir(struct Vnode *vp, struct fs_dirent_s *dir)
1626 {
1627     DIR *dp = (DIR *)dir->u.fs_dir;
1628     FATFS *fs = dp->obj.fs;
1629     FRESULT result;
1630     int ret;
1631 
1632     ret = lock_fs(fs);
1633     if (ret == FALSE) {
1634         return -EBUSY;
1635     }
1636 
1637     result = dir_sdi(dp, 0);
1638     unlock_fs(fs, result);
1639     return -fatfs_2_vfs(result);
1640 }
1641 
fatfs_closedir(struct Vnode * vp,struct fs_dirent_s * dir)1642 int fatfs_closedir(struct Vnode *vp, struct fs_dirent_s *dir)
1643 {
1644     DIR *dp = (DIR *)dir->u.fs_dir;
1645     free(dp);
1646     dir->u.fs_dir = NULL;
1647     return 0;
1648 }
1649 
rename_check(DIR * dp_new,FILINFO * finfo_new,DIR * dp_old,FILINFO * finfo_old)1650 static FRESULT rename_check(DIR *dp_new, FILINFO *finfo_new, DIR *dp_old, FILINFO *finfo_old)
1651 {
1652     DIR dir_sub;
1653     FRESULT result;
1654     if (finfo_new->fattrib & AM_ARC) { /* new path is file */
1655         if (finfo_old->fattrib & AM_DIR) { /* but old path is dir */
1656             return FR_NO_DIR;
1657         }
1658     } else if (finfo_new->fattrib & AM_DIR) { /* new path is dir */
1659         if (finfo_old->fattrib & AM_ARC) { /* old path is file */
1660             return FR_IS_DIR;
1661         }
1662         dir_sub.obj.fs = dp_old->obj.fs;
1663         dir_sub.obj.sclust = finfo_new->sclst;
1664         result = dir_sdi(&dir_sub, 0);
1665         if (result != FR_OK) {
1666             return result;
1667         }
1668         result = dir_read(&dir_sub, 0);
1669         if (result == FR_OK) { /* new path isn't empty file */
1670             return FR_NO_EMPTY_DIR;
1671         }
1672     } else { /* System file or volume label */
1673         return FR_DENIED;
1674     }
1675     return FR_OK;
1676 }
1677 
fatfs_rename(struct Vnode * old_vnode,struct Vnode * new_parent,const char * oldname,const char * newname)1678 int fatfs_rename(struct Vnode *old_vnode, struct Vnode *new_parent, const char *oldname, const char *newname)
1679 {
1680     FATFS *fs = (FATFS *)(old_vnode->originMount->data);
1681     DIR_FILE *dfp_old = (DIR_FILE *)old_vnode->data;
1682     DIR *dp_old = &(dfp_old->f_dir);
1683     FILINFO *finfo_old = &(dfp_old->fno);
1684     DIR_FILE *dfp_new = NULL;
1685     DIR* dp_new = NULL;
1686     FILINFO* finfo_new = NULL;
1687     DWORD clust;
1688     FRESULT result;
1689     int ret;
1690 
1691     ret = lock_fs(fs);
1692     if (ret == FALSE) { /* Lock fs failed */
1693         return -EBUSY;
1694     }
1695 
1696     dfp_new = (DIR_FILE *)zalloc(sizeof(DIR_FILE));
1697     if (dfp_new == NULL) {
1698         result = FR_NOT_ENOUGH_CORE;
1699         goto ERROR_UNLOCK;
1700     }
1701     dp_new = &(dfp_new->f_dir);
1702     finfo_new = &(dfp_new->fno);
1703 
1704     dp_new->obj.sclust = ((DIR_FILE *)(new_parent->data))->fno.sclst;
1705     dp_new->obj.fs = fs;
1706 
1707     /* Find new path */
1708     DEF_NAMBUF;
1709     INIT_NAMBUF(fs);
1710     result = create_name(dp_new, &newname);
1711     if (result != FR_OK) {
1712         goto ERROR_FREE;
1713     }
1714     result = dir_find(dp_new);
1715     if (result == FR_OK) { /* new path name exist */
1716         get_fileinfo(dp_new, finfo_new);
1717         result = rename_check(dp_new, finfo_new, dp_old, finfo_old);
1718         if (result != FR_OK) {
1719             goto ERROR_FREE;
1720         }
1721         result = dir_remove(dp_old);
1722         if (result != FR_OK) {
1723             goto ERROR_FREE;
1724         }
1725         clust = finfo_new->sclst;
1726         if (clust != 0) { /* remove the new path cluster chain if exists */
1727             result = remove_chain(&(dp_new->obj), clust, 0);
1728             if (result != FR_OK) {
1729                 goto ERROR_FREE;
1730             }
1731         }
1732     } else { /* new path name not exist */
1733         result = dir_remove(dp_old);
1734         if (result != FR_OK) {
1735             goto ERROR_FREE;
1736         }
1737         result = dir_register(dp_new);
1738         if (result != FR_OK) {
1739             goto ERROR_FREE;
1740         }
1741     }
1742 
1743     /* update new dir entry with old info */
1744     result = update_dir(dp_new, finfo_old);
1745     if (result != FR_OK) {
1746         goto ERROR_FREE;
1747     }
1748     result = dir_read(dp_new, 0);
1749     if (result != FR_OK) {
1750         goto ERROR_FREE;
1751     }
1752     dp_new->blk_ofs = dir_ofs(dp_new);
1753     get_fileinfo(dp_new, finfo_new);
1754 
1755     dfp_new->fno.fp_list.pstNext = dfp_old->fno.fp_list.pstNext;
1756     dfp_new->fno.fp_list.pstPrev = dfp_old->fno.fp_list.pstPrev;
1757     ret = memcpy_s(dfp_old, sizeof(DIR_FILE), dfp_new, sizeof(DIR_FILE));
1758     if (ret != 0) {
1759         result = FR_NOT_ENOUGH_CORE;
1760         goto ERROR_FREE;
1761     }
1762     free(dfp_new);
1763     unlock_fs(fs, FR_OK);
1764     FREE_NAMBUF();
1765     return fatfs_sync(old_vnode->originMount->mountFlags, fs);
1766 
1767 ERROR_FREE:
1768     free(dfp_new);
1769 ERROR_UNLOCK:
1770     unlock_fs(fs, result);
1771     FREE_NAMBUF();
1772     return -fatfs_2_vfs(result);
1773 }
1774 
1775 
fatfs_erase(los_part * part,int option)1776 static int fatfs_erase(los_part *part, int option)
1777 {
1778     int opt = option;
1779     if ((UINT)opt & FMT_ERASE) {
1780         opt = (UINT)opt & (~FMT_ERASE);
1781         if (EraseDiskByID(part->disk_id, part->sector_start, part->sector_count) != LOS_OK) {
1782             PRINTK("Disk erase error.\n");
1783             return -1;
1784         }
1785     }
1786 
1787     if (opt != FM_FAT && opt != FM_FAT32) {
1788         opt = FM_ANY;
1789     }
1790 
1791     return opt;
1792 }
1793 
fatfs_set_part_info(los_part * part)1794 static int fatfs_set_part_info(los_part *part)
1795 {
1796     los_disk *disk = NULL;
1797     char *buf = NULL;
1798     int ret;
1799 
1800     /* If there is no MBR before, the partition info needs to be changed after mkfs */
1801     if (part->type != EMMC && part->part_no_mbr == 0) {
1802         disk = get_disk(part->disk_id);
1803         if (disk == NULL) {
1804             return -EIO;
1805         }
1806         buf = (char *)zalloc(disk->sector_size);
1807         if (buf == NULL) {
1808             return -ENOMEM;
1809         }
1810         (void)memset_s(buf, disk->sector_size, 0, disk->sector_size);
1811         ret = los_disk_read(part->disk_id, buf, 0, 1, TRUE); /* TRUE when not reading large data */
1812         if (ret < 0) {
1813             free(buf);
1814             return -EIO;
1815         }
1816         part->sector_start = LD_DWORD_DISK(&buf[PAR_OFFSET + PAR_START_OFFSET]);
1817         part->sector_count = LD_DWORD_DISK(&buf[PAR_OFFSET + PAR_COUNT_OFFSET]);
1818         part->part_no_mbr = 1;
1819         part->filesystem_type = buf[PAR_OFFSET + PAR_TYPE_OFFSET];
1820 
1821         free(buf);
1822     }
1823     return 0;
1824 }
1825 
fatfs_setlabel(los_part * part)1826 static FRESULT fatfs_setlabel(los_part *part)
1827 {
1828     QWORD start_sector = 0;
1829     BYTE fmt = 0;
1830     FATFS fs;
1831     FRESULT result;
1832 
1833 #ifdef LOSCFG_FS_FAT_VIRTUAL_PARTITION
1834     fs.vir_flag = FS_PARENT;
1835     fs.parent_fs = &fs;
1836     fs.vir_amount = DISK_ERROR;
1837     fs.vir_avail = FS_VIRDISABLE;
1838 #endif
1839     if (disk_ioctl(fs.pdrv, GET_SECTOR_SIZE, &(fs.ssize)) != RES_OK) {
1840         return -EIO;
1841     }
1842     fs.win = (BYTE *)ff_memalloc(fs.ssize);
1843     if (fs.win == NULL) {
1844         return -ENOMEM;
1845     }
1846 
1847     result = find_fat_partition(&fs, part, &fmt, &start_sector);
1848     if (result != FR_OK) {
1849         free(fs.win);
1850         return -fatfs_2_vfs(result);
1851     }
1852 
1853     result = init_fatobj(&fs, fmt, start_sector);
1854     if (result != FR_OK) {
1855         free(fs.win);
1856         return -fatfs_2_vfs(result);
1857     }
1858 
1859     result = set_volumn_label(&fs, FatLabel);
1860     free(fs.win);
1861 
1862     return result;
1863 }
1864 
fatfs_mkfs(struct Vnode * device,int sectors,int option)1865 int fatfs_mkfs(struct Vnode *device, int sectors, int option)
1866 {
1867     BYTE *work_buff = NULL;
1868     los_part *part = NULL;
1869     FRESULT result;
1870     MKFS_PARM opt = {0};
1871     int ret;
1872 
1873     part = los_part_find(device);
1874     if (part == NULL || device->data == NULL) {
1875         return -ENODEV;
1876     }
1877 
1878     if (sectors < 0 || sectors > FAT32_MAX_CLUSTER_SIZE || ((DWORD)sectors & ((DWORD)sectors - 1))) {
1879         return -EINVAL;
1880     }
1881 
1882     if (option != FMT_FAT && option != FMT_FAT32 && option != FMT_ANY && option != FMT_ERASE) {
1883         return -EINVAL;
1884     }
1885 
1886     if (part->part_name != NULL) { /* The part is mounted */
1887         return -EBUSY;
1888     }
1889     option = fatfs_erase(part, option);
1890     work_buff = (BYTE *)zalloc(FF_MAX_SS);
1891     if (work_buff == NULL) {
1892         return -ENOMEM;
1893     }
1894 
1895     opt.n_sect = sectors;
1896     opt.fmt = (BYTE)option;
1897     result = _mkfs(part, &opt, work_buff, FF_MAX_SS);
1898     free(work_buff);
1899     if (result != FR_OK) {
1900         return -fatfs_2_vfs(result);
1901     }
1902 
1903     result = fatfs_setlabel(part);
1904     if (result == FR_OK) {
1905 #ifdef LOSCFG_FS_FAT_CACHE
1906         ret = OsSdSync(part->disk_id);
1907         if (ret != 0) {
1908             return -EIO;
1909         }
1910 #endif
1911     }
1912 
1913     ret = fatfs_set_part_info(part);
1914     if (ret != 0) {
1915         return -EIO;
1916     }
1917 
1918     return -fatfs_2_vfs(result);
1919 }
1920 
fatfs_mkdir(struct Vnode * parent,const char * name,mode_t mode,struct Vnode ** vpp)1921 int fatfs_mkdir(struct Vnode *parent, const char *name, mode_t mode, struct Vnode **vpp)
1922 {
1923     return fatfs_create_obj(parent, name, mode, vpp, AM_DIR, NULL);
1924 }
1925 
fatfs_rmdir(struct Vnode * parent,struct Vnode * vp,const char * name)1926 int fatfs_rmdir(struct Vnode *parent, struct Vnode *vp, const char *name)
1927 {
1928     FATFS *fs = (FATFS *)vp->originMount->data;
1929     DIR_FILE *dfp = (DIR_FILE *)vp->data;
1930     FILINFO *finfo = &(dfp->fno);
1931     DIR *dp = &(dfp->f_dir);
1932     DIR dir_sub;
1933     FRESULT result = FR_OK;
1934     int ret;
1935 
1936     if (finfo->fattrib & AM_ARC) {
1937         result = FR_NO_DIR;
1938         goto ERROR_OUT;
1939     }
1940 
1941     DEF_NAMBUF;
1942     INIT_NAMBUF(fs);
1943 
1944     ret = lock_fs(fs);
1945     if (ret == FALSE) {
1946         result = FR_TIMEOUT;
1947         goto ERROR_OUT;
1948     }
1949     dir_sub.obj.fs = fs;
1950     dir_sub.obj.sclust = finfo->sclst;
1951     result = dir_sdi(&dir_sub, 0);
1952     if (result != FR_OK) {
1953         goto ERROR_UNLOCK;
1954     }
1955     result = dir_read(&dir_sub, 0);
1956     if (result == FR_OK) {
1957         result = FR_NO_EMPTY_DIR;
1958         goto ERROR_UNLOCK;
1959     }
1960     result = dir_remove(dp); /* remove directory entry */
1961     if (result != FR_OK) {
1962         goto ERROR_UNLOCK;
1963     }
1964     /* Directory entry contains at least one cluster */
1965     result = remove_chain(&(dp->obj), finfo->sclst, 0);
1966     if (result != FR_OK) {
1967         goto ERROR_UNLOCK;
1968     }
1969 
1970     unlock_fs(fs, FR_OK);
1971     FREE_NAMBUF();
1972     return fatfs_sync(vp->originMount->mountFlags, fs);
1973 
1974 ERROR_UNLOCK:
1975     unlock_fs(fs, result);
1976     FREE_NAMBUF();
1977 ERROR_OUT:
1978     return -fatfs_2_vfs(result);
1979 }
1980 
fatfs_reclaim(struct Vnode * vp)1981 int fatfs_reclaim(struct Vnode *vp)
1982 {
1983     free(vp->data);
1984     vp->data = NULL;
1985     return 0;
1986 }
1987 
fatfs_unlink(struct Vnode * parent,struct Vnode * vp,const char * name)1988 int fatfs_unlink(struct Vnode *parent, struct Vnode *vp, const char *name)
1989 {
1990     FATFS *fs = (FATFS *)vp->originMount->data;
1991     DIR_FILE *dfp = (DIR_FILE *)vp->data;
1992     FILINFO *finfo = &(dfp->fno);
1993     DIR *dp = &(dfp->f_dir);
1994     FRESULT result = FR_OK;
1995     int ret;
1996 
1997     if (finfo->fattrib & AM_DIR) {
1998         result = FR_IS_DIR;
1999         goto ERROR_OUT;
2000     }
2001     ret = lock_fs(fs);
2002     if (ret == FALSE) {
2003         result = FR_TIMEOUT;
2004         goto ERROR_OUT;
2005     }
2006     result = dir_remove(dp); /* remove directory entry */
2007     if (result != FR_OK) {
2008         goto ERROR_UNLOCK;
2009     }
2010     if (finfo->sclst != 0) { /* if cluster chain exists */
2011         result = remove_chain(&(dp->obj), finfo->sclst, 0);
2012         if (result != FR_OK) {
2013             goto ERROR_UNLOCK;
2014         }
2015     }
2016     result = sync_fs(fs);
2017     if (result != FR_OK) {
2018         goto ERROR_UNLOCK;
2019     }
2020     unlock_fs(fs, FR_OK);
2021     return fatfs_sync(vp->originMount->mountFlags, fs);
2022 
2023 ERROR_UNLOCK:
2024     unlock_fs(fs, result);
2025 ERROR_OUT:
2026     return -fatfs_2_vfs(result);
2027 }
2028 
fatfs_ioctl(struct file * filep,int req,unsigned long arg)2029 int fatfs_ioctl(struct file *filep, int req, unsigned long arg)
2030 {
2031     return -ENOSYS;
2032 }
2033 
2034 #define CHECK_FILE_NUM 3
combine_time(FILINFO * finfo)2035 static inline DWORD combine_time(FILINFO *finfo)
2036 {
2037     return (finfo->fdate << FTIME_DATE_OFFSET) | finfo->ftime;
2038 }
2039 
get_oldest_time(DIR_FILE df[],DWORD * oldest_time,UINT len)2040 static UINT get_oldest_time(DIR_FILE df[], DWORD *oldest_time, UINT len)
2041 {
2042     int i;
2043     DWORD old_time = combine_time(&(df[0].fno));
2044     DWORD time;
2045     UINT index = 0;
2046     for (i = 1; i < len; i++) {
2047         time = combine_time(&(df[i].fno));
2048         if (time < old_time) {
2049             old_time = time;
2050             index = i;
2051         }
2052     }
2053     *oldest_time = old_time;
2054     return index;
2055 }
2056 
fscheck(DIR * dp)2057 static FRESULT fscheck(DIR *dp)
2058 {
2059     DIR_FILE df[CHECK_FILE_NUM] = {0};
2060     FILINFO fno;
2061     UINT index = 0;
2062     UINT count;
2063     DWORD time;
2064     DWORD old_time = -1;
2065     FRESULT result;
2066     for (count = 0; count < CHECK_FILE_NUM; count++) {
2067         if ((result = f_readdir(dp, &fno)) != FR_OK) {
2068             return result;
2069         } else {
2070             if (fno.fname[0] == 0 || fno.fname[0] == (TCHAR)0xFF) {
2071                 break;
2072             }
2073             (void)memcpy_s(&df[count].f_dir, sizeof(DIR), dp, sizeof(DIR));
2074             (void)memcpy_s(&df[count].fno, sizeof(FILINFO), &fno, sizeof(FILINFO));
2075             time = combine_time(&(df[count].fno));
2076             if (time < old_time) {
2077                 old_time = time;
2078                 index = count;
2079             }
2080         }
2081     }
2082     while ((result = f_readdir(dp, &fno)) == FR_OK) {
2083         if (fno.fname[0] == 0 || fno.fname[0] == (TCHAR)0xFF) {
2084             break;
2085         }
2086         time = combine_time(&fno);
2087         if (time < old_time) {
2088             (void)memcpy_s(&df[index].f_dir, sizeof(DIR), dp, sizeof(DIR));
2089             (void)memcpy_s(&df[index].fno, sizeof(FILINFO), &fno, sizeof(FILINFO));
2090             index = get_oldest_time(df, &old_time, CHECK_FILE_NUM);
2091         }
2092     }
2093     index = 0;
2094     while (result == FR_OK && index < count) {
2095         result = f_fcheckfat(&df[index]);
2096         ++index;
2097     }
2098 
2099     return result;
2100 }
2101 
fatfs_fscheck(struct Vnode * vp,struct fs_dirent_s * dir)2102 int fatfs_fscheck(struct Vnode* vp, struct fs_dirent_s *dir)
2103 {
2104     FATFS *fs = (FATFS *)vp->originMount->data;
2105     DIR *dp = NULL;
2106     FILINFO *finfo = &(((DIR_FILE *)(vp->data))->fno);
2107 #ifdef LOSCFG_FS_FAT_CACHE
2108     los_part *part = NULL;
2109 #endif
2110     FRESULT result;
2111     int ret;
2112 
2113     if (fs->fs_type != FS_FAT32) {
2114         return -EINVAL;
2115     }
2116 
2117     if ((finfo->fattrib & AM_DIR) == 0) {
2118         return -ENOTDIR;
2119     }
2120 
2121     ret = fatfs_opendir(vp, dir);
2122     if (ret < 0) {
2123         return ret;
2124     }
2125 
2126     ret = lock_fs(fs);
2127     if (ret == FALSE) {
2128         result = FR_TIMEOUT;
2129         goto ERROR_WITH_DIR;
2130     }
2131 
2132     dp = (DIR *)dir->u.fs_dir;
2133     dp->obj.id = fs->id;
2134     result = fscheck(dp);
2135     if (result != FR_OK) {
2136         goto ERROR_UNLOCK;
2137     }
2138 
2139     unlock_fs(fs, FR_OK);
2140 
2141     ret = fatfs_closedir(vp, dir);
2142     if (ret < 0) {
2143         return ret;
2144     }
2145 
2146 #ifdef LOSCFG_FS_FAT_CACHE
2147     part = get_part((INT)fs->pdrv);
2148     if (part != NULL) {
2149         (void)OsSdSync(part->disk_id);
2150     }
2151 #endif
2152 
2153     return 0;
2154 
2155 ERROR_UNLOCK:
2156     unlock_fs(fs, result);
2157 ERROR_WITH_DIR:
2158     fatfs_closedir(vp, dir);
2159     return -fatfs_2_vfs(result);
2160 }
2161 
fatfs_symlink(struct Vnode * parentVnode,struct Vnode ** newVnode,const char * path,const char * target)2162 int fatfs_symlink(struct Vnode *parentVnode, struct Vnode **newVnode, const char *path, const char *target)
2163 {
2164     return fatfs_create_obj(parentVnode, path, 0, newVnode, AM_LNK, target);
2165 }
2166 
fatfs_readlink(struct Vnode * vnode,char * buffer,size_t bufLen)2167 ssize_t fatfs_readlink(struct Vnode *vnode, char *buffer, size_t bufLen)
2168 {
2169     int ret;
2170     FRESULT res;
2171     DWORD clust;
2172     QWORD sect;
2173     DIR_FILE *dfp = (DIR_FILE *)(vnode->data);
2174     DIR *dp = &(dfp->f_dir);
2175     FATFS *fs = dp->obj.fs;
2176     FILINFO *finfo = &(dfp->fno);
2177     size_t targetLen = finfo->fsize;
2178     size_t cnt;
2179 
2180     ret = lock_fs(fs);
2181     if (ret == FALSE) {
2182         return -EBUSY;
2183     }
2184 
2185     clust = finfo->sclst;
2186     sect = clst2sect(fs, clust);    /* Get current sector */
2187     if (sect == 0) {
2188         res = FR_DISK_ERR;
2189         goto ERROUT;
2190     }
2191 
2192     if (move_window(fs, sect) != FR_OK) {
2193         res = FR_DISK_ERR;
2194         goto ERROUT;
2195     }
2196 
2197     cnt = (bufLen - 1) < targetLen ? (bufLen - 1) : targetLen;
2198     ret = LOS_CopyFromKernel(buffer, bufLen, fs->win, cnt);
2199     if (ret != EOK) {
2200         res = FR_INVALID_PARAMETER;
2201         goto ERROUT;
2202     }
2203     buffer[cnt] = '\0';
2204 
2205     unlock_fs(fs, FR_OK);
2206     return cnt;
2207 
2208 ERROUT:
2209     unlock_fs(fs, res);
2210     return -fatfs_2_vfs(res);
2211 }
2212 
fatfs_readpage(struct Vnode * vnode,char * buff,off_t pos)2213 ssize_t fatfs_readpage(struct Vnode *vnode, char *buff, off_t pos)
2214 {
2215     FATFS *fs = (FATFS *)(vnode->originMount->data);
2216     DIR_FILE *dfp = (DIR_FILE *)(vnode->data);
2217     FILINFO *finfo = &(dfp->fno);
2218     FAT_ENTRY *ep = &(dfp->fat_entry);
2219     DWORD clust;
2220     DWORD sclust;
2221     QWORD sect;
2222     QWORD step;
2223     QWORD n;
2224     size_t position; /* byte offset */
2225     BYTE *buf = (BYTE *)buff;
2226     size_t buflen = PAGE_SIZE;
2227     FRESULT result;
2228     int ret;
2229 
2230     ret = lock_fs(fs);
2231     if (ret == FALSE) {
2232         result = FR_TIMEOUT;
2233         goto ERROR_OUT;
2234     }
2235 
2236     if (finfo->fsize <= pos) {
2237         result = FR_OK;
2238         goto ERROR_UNLOCK;
2239     }
2240 
2241     if (ep->clst == 0) {
2242         ep->clst = finfo->sclst;
2243     }
2244 
2245     if (pos >= ep->pos) {
2246         clust = ep->clst;
2247         position = ep->pos;
2248     } else {
2249         clust = finfo->sclst;
2250         position = 0;
2251     }
2252 
2253     /* Get to the current cluster */
2254     n = pos / SS(fs) / fs->csize - position / SS(fs) / fs->csize;
2255     while (n--) {
2256         clust = get_fat(&(dfp->f_dir.obj), clust);
2257         if ((clust == BAD_CLUSTER) || (clust == DISK_ERROR)) {
2258             result = FR_DISK_ERR;
2259             goto ERROR_UNLOCK;
2260         }
2261     }
2262 
2263     /* Get to the currnet sector */
2264     sect = clst2sect(fs, clust);
2265     sect += (pos / SS(fs)) & (fs->csize - 1);
2266 
2267     /* How many sectors do we need to read once */
2268     if (fs->csize < buflen / SS(fs)) {
2269         step = fs->csize;
2270     } else {
2271         step = buflen / SS(fs);
2272     }
2273 
2274     n = 0;
2275     sclust = clust;
2276     while (n < buflen / SS(fs)) {
2277         if (disk_read(fs->pdrv, buf, sect, step) != RES_OK) {
2278             result = FR_DISK_ERR;
2279             goto ERROR_UNLOCK;
2280         }
2281         n += step;
2282         if (n >= buflen / SS(fs)) {
2283             break;
2284         }
2285 
2286         /* As cluster size is aligned, it must jump to next cluster when cluster size is less than pagesize */
2287         clust = get_fat(&(dfp->f_dir.obj), clust);
2288         if ((clust == BAD_CLUSTER) || (clust == DISK_ERROR)) {
2289             result = FR_DISK_ERR;
2290             goto ERROR_UNLOCK;
2291         } else if (fatfs_is_last_cluster(fs, clust)) {
2292             break; /* read end */
2293         }
2294         sect = clst2sect(fs, clust);
2295         buf += step * SS(fs);
2296     }
2297 
2298     ep->clst = sclust;
2299     ep->pos = pos;
2300 
2301     unlock_fs(fs, FR_OK);
2302 
2303     return (ssize_t)min(finfo->fsize - pos, n * SS(fs));
2304 
2305 ERROR_UNLOCK:
2306     unlock_fs(fs, result);
2307 ERROR_OUT:
2308     return -fatfs_2_vfs(result);
2309 }
2310 
fatfs_writepage(struct Vnode * vnode,char * buff,off_t pos,size_t buflen)2311 ssize_t fatfs_writepage(struct Vnode *vnode, char *buff, off_t pos, size_t buflen)
2312 {
2313     FATFS *fs = (FATFS *)(vnode->originMount->data);
2314     DIR_FILE *dfp = (DIR_FILE *)(vnode->data);
2315     FILINFO *finfo = &(dfp->fno);
2316     FAT_ENTRY *ep = &(dfp->fat_entry);
2317     DWORD clust;
2318     DWORD sclst;
2319     QWORD sect;
2320     QWORD step;
2321     QWORD n;
2322     size_t position; /* byte offset */
2323     BYTE *buf = (BYTE *)buff;
2324     FRESULT result;
2325     FIL fil;
2326     int ret;
2327 
2328     ret = lock_fs(fs);
2329     if (ret == FALSE) {
2330         result = FR_TIMEOUT;
2331         goto ERROR_OUT;
2332     }
2333 
2334     if (finfo->fsize <= pos) {
2335         result = FR_OK;
2336         goto ERROR_UNLOCK;
2337     }
2338 
2339     if (ep->clst == 0) {
2340         ep->clst = finfo->sclst;
2341     }
2342 
2343     if (pos >= ep->pos) {
2344         clust = ep->clst;
2345         position = ep->pos;
2346     } else {
2347         clust = finfo->sclst;
2348         position = 0;
2349     }
2350 
2351     /* Get to the current cluster */
2352     n = pos / SS(fs) / fs->csize - position / SS(fs) / fs->csize;
2353     while (n--) {
2354         clust = get_fat(&(dfp->f_dir.obj), clust);
2355         if ((clust == BAD_CLUSTER) || (clust == DISK_ERROR)) {
2356             result = FR_DISK_ERR;
2357             goto ERROR_UNLOCK;
2358         }
2359     }
2360 
2361     /* Get to the currnet sector */
2362     sect = clst2sect(fs, clust);
2363     sect += (pos / SS(fs)) & (fs->csize - 1);
2364 
2365     /* How many sectors do we need to read once */
2366     if (fs->csize < buflen / SS(fs)) {
2367         step = fs->csize;
2368     } else {
2369         step = buflen / SS(fs);
2370     }
2371 
2372     n = 0;
2373     sclst = clust;
2374     while (n < buflen / SS(fs)) {
2375         if (disk_write(fs->pdrv, buf, sect, step) != RES_OK) {
2376             result = FR_DISK_ERR;
2377             goto ERROR_UNLOCK;
2378         }
2379         n += step;
2380         if (n >= buflen / SS(fs)) {
2381             break;
2382         }
2383 
2384         /* As cluster size is aligned, it must jump to next cluster when cluster size is less than pagesize */
2385         clust = get_fat(&(dfp->f_dir.obj), clust);
2386         if ((clust == BAD_CLUSTER) || (clust == DISK_ERROR)) {
2387             result = FR_DISK_ERR;
2388             goto ERROR_UNLOCK;
2389         } else if (fatfs_is_last_cluster(fs, clust)) {
2390             break; /* read end */
2391         }
2392         sect = clst2sect(fs, clust);
2393         buf += step * SS(fs);
2394     }
2395 
2396     ep->clst = sclst;
2397     ep->pos = pos;
2398 
2399     fil.obj.fs = fs;
2400     if (update_filbuff(finfo, &fil, NULL) < 0) {
2401         result = FR_DISK_ERR;
2402         goto ERROR_UNLOCK;
2403     }
2404 
2405     unlock_fs(fs, FR_OK);
2406 
2407     return (ssize_t)min(finfo->fsize - pos, n * SS(fs));
2408 ERROR_UNLOCK:
2409     unlock_fs(fs, result);
2410 ERROR_OUT:
2411     return -fatfs_2_vfs(result);
2412 }
2413 
2414 struct VnodeOps fatfs_vops = {
2415     /* file ops */
2416     .Getattr = fatfs_stat,
2417     .Chattr = fatfs_chattr,
2418     .Lookup = fatfs_lookup,
2419     .Rename = fatfs_rename,
2420     .Create = fatfs_create,
2421     .ReadPage = fatfs_readpage,
2422     .WritePage = fatfs_writepage,
2423     .Unlink = fatfs_unlink,
2424     .Reclaim = fatfs_reclaim,
2425     .Truncate = fatfs_truncate,
2426     .Truncate64 = fatfs_truncate64,
2427     /* dir ops */
2428     .Opendir = fatfs_opendir,
2429     .Readdir = fatfs_readdir,
2430     .Rewinddir = fatfs_rewinddir,
2431     .Closedir = fatfs_closedir,
2432     .Mkdir = fatfs_mkdir,
2433     .Rmdir = fatfs_rmdir,
2434     .Fscheck = fatfs_fscheck,
2435     .Symlink = fatfs_symlink,
2436     .Readlink = fatfs_readlink,
2437 };
2438 
2439 struct MountOps fatfs_mops = {
2440     .Mount = fatfs_mount,
2441     .Unmount = fatfs_umount,
2442     .Statfs = fatfs_statfs,
2443     .Sync = fatfs_sync_adapt,
2444 };
2445 
2446 struct file_operations_vfs fatfs_fops = {
2447     .open = fatfs_open,
2448     .read = fatfs_read,
2449     .write = fatfs_write,
2450     .seek = fatfs_lseek,
2451     .close = fatfs_close,
2452     .mmap = OsVfsFileMmap,
2453     .fallocate = fatfs_fallocate,
2454     .fallocate64 = fatfs_fallocate64,
2455     .fsync = fatfs_fsync,
2456     .ioctl = fatfs_ioctl,
2457 };
2458 
2459 FSMAP_ENTRY(fat_fsmap, "vfat", fatfs_mops, FALSE, TRUE);
2460 
2461 #endif /* LOSCFG_FS_FAT */
2462