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