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