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(§, 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