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 #define _GNU_SOURCE 1
33 #include "ff.h"
34 #include "fatfs.h"
35 #include "errno.h"
36 #include "stdbool.h"
37 #include "limits.h"
38 #include "pthread.h"
39 #include "time.h"
40 #include "securec.h"
41 #include "los_compiler.h"
42 #include "los_debug.h"
43 #include "los_sched.h"
44 #include "vfs_files.h"
45 #include "vfs_operations.h"
46 #include "vfs_partition.h"
47 #include "vfs_maps.h"
48 #include "vfs_mount.h"
49 #include "los_fs.h"
50
51 /* the max name length of different parts should not bigger than 32 */
52 #define FS_DRIVE_NAME_MAX_LEN 32
53
54 #ifndef FAT_MAX_OPEN_DIRS
55 #define FAT_MAX_OPEN_DIRS 8
56 #endif /* FAT_MAX_OPEN_DIRS */
57
58 #ifndef FS_LOCK_TIMEOUT_SEC
59 #define FS_LOCK_TIMEOUT_SEC 15
60 #endif /* FS_LOCK_TIMEOUT_SEC */
61
62 static UINT8 g_workBuffer[FF_MAX_SS];
63 static char *g_volPath[FF_VOLUMES] = {FF_VOLUME_STRS};
64
65 PARTITION VolToPart[] = {
66 { 0, 0, 1, 0, 0 },
67 { 0, 0, 2, 0, 0 },
68 { 0, 0, 3, 0, 0 },
69 { 0, 0, 4, 0, 0 }
70 };
71
FsChangeDrive(const char *path)72 static int FsChangeDrive(const char *path)
73 {
74 INT32 res;
75 errno_t retErr;
76 UINT16 pathLen = strlen((char const *)path);
77 /* the max name length of different parts is 16 */
78 CHAR tmpPath[FS_DRIVE_NAME_MAX_LEN] = { "/" };
79
80 /* make sure the path begin with "/", the path like /xxx/yyy/... */
81 if (pathLen >= (FS_DRIVE_NAME_MAX_LEN - 1)) {
82 /* 2: except first flag "/" and last end flag */
83 pathLen = FS_DRIVE_NAME_MAX_LEN - 2;
84 }
85
86 retErr = strncpy_s(tmpPath + 1, (FS_DRIVE_NAME_MAX_LEN - 1), (char const *)path, pathLen);
87 if (retErr != EOK) {
88 return (int)LOS_NOK;
89 }
90
91 res = f_chdrive(tmpPath);
92 if (res != FR_OK) {
93 return (int)LOS_NOK;
94 }
95
96 return (int)LOS_OK;
97 }
98
Remount(struct MountPoint *mp, unsigned long mountflags)99 static int Remount(struct MountPoint *mp, unsigned long mountflags)
100 {
101 FATFS *fatfs = (FATFS *)mp->mData;
102
103 /* remount is not allowed when the device is not mounted. */
104 if (fatfs->fs_type == 0) {
105 errno = EINVAL;
106 return (int)LOS_NOK;
107 }
108 mp->mWriteEnable = (mountflags & MS_RDONLY) ? FALSE : TRUE;
109
110 return (int)LOS_OK;
111 }
112
FatFsGetMode(int oflags)113 static unsigned int FatFsGetMode(int oflags)
114 {
115 UINT32 fmode = FA_READ;
116
117 if ((UINT32)oflags & O_WRONLY) {
118 fmode |= FA_WRITE;
119 }
120
121 if (((UINT32)oflags & O_ACCMODE) & O_RDWR) {
122 fmode |= FA_WRITE;
123 }
124 /* Creates a new file if the file is not existing, otherwise, just open it. */
125 if ((UINT32)oflags & O_CREAT) {
126 fmode |= FA_OPEN_ALWAYS;
127 /* Creates a new file. If the file already exists, the function shall fail. */
128 if ((UINT32)oflags & O_EXCL) {
129 fmode |= FA_CREATE_NEW;
130 }
131 }
132 /* Creates a new file. If the file already exists, its length shall be truncated to 0. */
133 if ((UINT32)oflags & O_TRUNC) {
134 fmode |= FA_CREATE_ALWAYS;
135 }
136
137 return fmode;
138 }
139
FatfsErrno(int result)140 static int FatfsErrno(int result)
141 {
142 INT32 status = 0;
143
144 if (result < 0) {
145 return result;
146 }
147
148 /* FatFs errno to Libc errno */
149 switch (result) {
150 case FR_OK:
151 break;
152
153 case FR_NO_FILE:
154 case FR_NO_PATH:
155 case FR_NO_FILESYSTEM:
156 status = ENOENT;
157 break;
158
159 case FR_INVALID_NAME:
160 status = EINVAL;
161 break;
162
163 case FR_EXIST:
164 case FR_INVALID_OBJECT:
165 status = EEXIST;
166 break;
167
168 case FR_DISK_ERR:
169 case FR_NOT_READY:
170 case FR_INT_ERR:
171 status = EIO;
172 break;
173
174 case FR_WRITE_PROTECTED:
175 status = EROFS;
176 break;
177 case FR_MKFS_ABORTED:
178 case FR_INVALID_PARAMETER:
179 status = EINVAL;
180 break;
181
182 case FR_NO_SPACE_LEFT:
183 status = ENOSPC;
184 break;
185 case FR_NO_DIRENTRY:
186 status = ENFILE;
187 break;
188 case FR_NO_EMPTY_DIR:
189 status = ENOTEMPTY;
190 break;
191 case FR_IS_DIR:
192 status = EISDIR;
193 break;
194 case FR_NO_DIR:
195 status = ENOTDIR;
196 break;
197 case FR_NO_EPERM:
198 case FR_DENIED:
199 status = EPERM;
200 break;
201 case FR_LOCKED:
202 status = EBUSY;
203 break;
204 default:
205 status = result;
206 break;
207 }
208
209 return status;
210 }
211
GetLdPath(const char *source)212 char * GetLdPath(const char *source)
213 {
214 #define LDPATH_PAD 2 // 2 means: strlen("/") + len of '\0'
215 int ret;
216 int partId = GetPartIdByPartName(source);
217 if ((partId < 0) || (partId >= MAX_PARTITION_NUM)) {
218 return NULL;
219 }
220
221 char *volPath = g_volPath[partId];
222 char *ldPath = (char *)LOSCFG_FS_MALLOC_HOOK(strlen(volPath) + LDPATH_PAD);
223 if (ldPath == NULL) {
224 return NULL;
225 }
226
227 (void)memset_s(ldPath, strlen(volPath) + LDPATH_PAD, 0, strlen(volPath) + LDPATH_PAD);
228
229 /* Convert volPath to ldpath, for example, convert "inner" to "/inner" */
230 *ldPath = '/';
231 ret = strcpy_s(ldPath + 1, strlen(volPath)+1, volPath);
232 if (ret != EOK) {
233 LOSCFG_FS_FREE_HOOK(ldPath);
234 return NULL;
235 }
236
237 return ldPath;
238 }
239
PutLdPath(const char *ldPath)240 void PutLdPath(const char *ldPath)
241 {
242 if (ldPath != NULL) {
243 LOSCFG_FS_FREE_HOOK((void *)ldPath);
244 }
245 }
246
FatfsMount(struct MountPoint *mp, unsigned long mountflags, const void *data)247 int FatfsMount(struct MountPoint *mp, unsigned long mountflags,
248 const void *data)
249 {
250 FRESULT res;
251 FATFS *fs = NULL;
252
253 if (mountflags & MS_REMOUNT) {
254 return Remount(mp, mountflags);
255 }
256
257 char *ldPath = GetLdPath(mp->mDev);
258 if (ldPath == NULL) {
259 errno = EFAULT;
260 return (int)LOS_NOK;
261 }
262
263 fs = (FATFS *)LOSCFG_FS_MALLOC_HOOK(sizeof(FATFS));
264 if (fs == NULL) {
265 errno = ENOMEM;
266 PutLdPath(ldPath);
267 return (int)LOS_NOK;
268 }
269 (void)memset_s(fs, sizeof(FATFS), 0, sizeof(FATFS));
270
271 res = f_mount(fs, ldPath, 1);
272 if (res != FR_OK) {
273 LOSCFG_FS_FREE_HOOK(fs);
274 PutLdPath(ldPath);
275 errno = FatfsErrno(res);
276 return (int)LOS_NOK;
277 }
278 mp->mData = (void *)fs;
279
280 PutLdPath(ldPath);
281 return (int)LOS_OK;
282 }
283
FatfsUmount(struct MountPoint *mp)284 int FatfsUmount(struct MountPoint *mp)
285 {
286 int volId;
287 FRESULT res;
288 char *ldPath = NULL;
289 FATFS *fatfs = (FATFS *)mp->mData;
290
291 /* The volume is not mounted */
292 if (fatfs->fs_type == 0) {
293 errno = EINVAL;
294 return (int)LOS_NOK;
295 }
296
297 volId = GetPartIdByPartName(mp->mDev);
298 /* umount is not allowed when a file or directory is opened. */
299 if (f_checkopenlock(volId) != FR_OK) {
300 errno = EBUSY;
301 return (int)LOS_NOK;
302 }
303
304 ldPath = GetLdPath(mp->mDev);
305 if (ldPath == NULL) {
306 errno = EFAULT;
307 return (int)LOS_NOK;
308 }
309
310 res = f_mount((FATFS *)NULL, ldPath, 0);
311 if (res != FR_OK) {
312 errno = FatfsErrno(res);
313 PutLdPath(ldPath);
314 return (int)LOS_NOK;
315 }
316
317 if (fatfs->win != NULL) {
318 ff_memfree(fatfs->win);
319 }
320
321 LOSCFG_FS_FREE_HOOK(mp->mData);
322 mp->mData = NULL;
323
324 PutLdPath(ldPath);
325 return (int)LOS_OK;
326 }
327
FatfsUmount2(struct MountPoint *mp, int flag)328 int FatfsUmount2(struct MountPoint *mp, int flag)
329 {
330 UINT32 flags;
331 FRESULT res;
332 char *ldPath = NULL;
333 FATFS *fatfs = (FATFS *)mp->mData;
334
335 flags = MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW;
336 if ((UINT32)flag & ~flags) {
337 errno = EINVAL;
338 return (int)LOS_NOK;
339 }
340
341 /* The volume is not mounted */
342 if (fatfs->fs_type == 0) {
343 errno = EINVAL;
344 return (int)LOS_NOK;
345 }
346
347 ldPath = GetLdPath(mp->mDev);
348 if (ldPath == NULL) {
349 errno = EFAULT;
350 return (int)LOS_NOK;
351 }
352
353 res = f_mount((FATFS *)NULL, ldPath, 0);
354 if (res != FR_OK) {
355 PutLdPath(ldPath);
356 errno = FatfsErrno(res);
357 return (int)LOS_NOK;
358 }
359
360 if (fatfs->win != NULL) {
361 ff_memfree(fatfs->win);
362 }
363
364 LOSCFG_FS_FREE_HOOK(mp->mData);
365 mp->mData = NULL;
366
367 PutLdPath(ldPath);
368 return (int)LOS_OK;
369 }
370
FatfsOpen(struct File *file, const char *path, int oflag)371 int FatfsOpen(struct File *file, const char *path, int oflag)
372 {
373 FRESULT res;
374 UINT32 fmode;
375 FIL *fp = NULL;
376 int ret;
377
378 if (path == NULL) {
379 errno = EFAULT;
380 return (int)LOS_NOK;
381 }
382
383 fmode = FatFsGetMode(oflag);
384
385 fp = (FIL *)LOSCFG_FS_MALLOC_HOOK(sizeof(FIL));
386 if (fp == NULL) {
387 errno = ENOMEM;
388 return (int)LOS_NOK;
389 }
390 (void)memset_s(fp, sizeof(FIL), 0, sizeof(FIL));
391
392 ret = FsChangeDrive(path);
393 if (ret != (int)LOS_OK) {
394 PRINT_ERR("FAT open ChangeDrive err 0x%x!\r\n", ret);
395 errno = ENOENT;
396 LOSCFG_FS_FREE_HOOK(fp);
397 return (int)LOS_NOK;
398 }
399
400 res = f_open(fp, path, fmode);
401 if (res != FR_OK) {
402 PRINT_ERR("FAT open err 0x%x!\r\n", res);
403 LOSCFG_FS_FREE_HOOK(fp);
404 errno = FatfsErrno(res);
405 return (int)LOS_NOK;
406 }
407
408 file->fData = (void *)fp;
409
410 return (int)LOS_OK;
411 }
412
FatfsClose(struct File *file)413 int FatfsClose(struct File *file)
414 {
415 FRESULT res;
416 FIL *fp = (FIL *)file->fData;
417
418 if ((fp == NULL) || (fp->obj.fs == NULL)) {
419 errno = ENOENT;
420 return (int)LOS_NOK;
421 }
422
423 res = f_close(fp);
424 if (res != FR_OK) {
425 PRINT_ERR("FAT close err 0x%x!\r\n", res);
426 errno = FatfsErrno(res);
427 return (int)LOS_NOK;
428 }
429
430 #if !FF_FS_TINY
431 if (fp->buf != NULL) {
432 (void)ff_memfree(fp->buf);
433 }
434 #endif
435 LOSCFG_FS_FREE_HOOK(file->fData);
436 file->fData = NULL;
437
438 return (int)LOS_OK;
439 }
440
FatfsRead(struct File *file, char *buf, size_t nbyte)441 ssize_t FatfsRead(struct File *file, char *buf, size_t nbyte)
442 {
443 FRESULT res;
444 UINT32 lenRead;
445 FIL *fp = (FIL *)file->fData;
446
447 if (buf == NULL) {
448 errno = EFAULT;
449 return (ssize_t)LOS_NOK;
450 }
451
452 if (fp == NULL) {
453 errno = ENOENT;
454 return (ssize_t)LOS_NOK;
455 }
456
457 res = f_read(fp, buf, nbyte, &lenRead);
458 if (res != FR_OK) {
459 errno = FatfsErrno(res);
460 return (ssize_t)LOS_NOK;
461 }
462
463 return (ssize_t)lenRead;
464 }
465
FatfsWrite(struct File *file, const char *buf, size_t nbyte)466 ssize_t FatfsWrite(struct File *file, const char *buf, size_t nbyte)
467 {
468 FRESULT res;
469 UINT32 lenWrite;
470 static BOOL overFlow = FALSE;
471 FIL *fp = (FIL *)file->fData;
472
473 if (buf == NULL) {
474 errno = EFAULT;
475 return (ssize_t)LOS_NOK;
476 }
477
478 if ((fp == NULL) || (fp->obj.fs == NULL)) {
479 errno = ENOENT;
480 return (ssize_t)LOS_NOK;
481 }
482
483 res = f_write(fp, buf, nbyte, &lenWrite);
484 if ((res == FR_OK) && (lenWrite == 0) && (nbyte != 0) && (overFlow == FALSE)) {
485 overFlow = TRUE;
486 PRINT_ERR("FAT write err!\r\n");
487 }
488
489 if ((res != FR_OK) || (nbyte != lenWrite)) {
490 errno = FatfsErrno(res);
491 return (ssize_t)LOS_NOK;
492 }
493
494 return (ssize_t)lenWrite;
495 }
496
FatfsLseek(struct File *file, off_t offset, int whence)497 off_t FatfsLseek(struct File *file, off_t offset, int whence)
498 {
499 FRESULT res;
500 off_t pos;
501 FIL *fp = (FIL *)file->fData;
502
503 if ((fp == NULL) || (fp->obj.fs == NULL)) {
504 errno = ENOENT;
505 return (off_t)LOS_NOK;
506 }
507
508 if (whence == SEEK_SET) {
509 pos = 0;
510 } else if (whence == SEEK_CUR) {
511 pos = f_tell(fp);
512 } else if (whence == SEEK_END) {
513 pos = f_size(fp);
514 } else {
515 errno = EINVAL;
516 return (off_t)LOS_NOK;
517 }
518
519 res = f_lseek(fp, offset + pos);
520 if (res != FR_OK) {
521 errno = FatfsErrno(res);
522 return (off_t)LOS_NOK;
523 }
524
525 pos = f_tell(fp);
526 return pos;
527 }
528
529 /* Remove the specified FILE */
FatfsUnlink(struct MountPoint *mp, const char *path)530 int FatfsUnlink(struct MountPoint *mp, const char *path)
531 {
532 FRESULT res;
533 int ret;
534
535 if (path == NULL) {
536 errno = EFAULT;
537 return (int)LOS_NOK;
538 }
539
540 if (!mp->mWriteEnable) {
541 errno = EACCES;
542 return (int)LOS_NOK;
543 }
544
545 ret = FsChangeDrive(path);
546 if (ret != (int)LOS_OK) {
547 PRINT_ERR("FAT unlink ChangeDrive err 0x%x!\r\n", ret);
548 errno = ENOENT;
549 return (int)LOS_NOK;
550 }
551
552 res = f_unlink(path);
553 if (res != FR_OK) {
554 PRINT_ERR("FAT unlink err 0x%x!\r\n", res);
555 errno = FatfsErrno(res);
556 return (int)LOS_NOK;
557 }
558
559 return (int)LOS_OK;
560 }
561
FatfsStat(struct MountPoint *mp, const char *path, struct stat *buf)562 int FatfsStat(struct MountPoint *mp, const char *path, struct stat *buf)
563 {
564 FRESULT res;
565 FILINFO fileInfo = {0};
566 int ret;
567
568 if ((path == NULL) || (buf == NULL)) {
569 errno = EFAULT;
570 return (int)LOS_NOK;
571 }
572
573 ret = FsChangeDrive(path);
574 if (ret != (int)LOS_OK) {
575 PRINT_ERR("FAT stat ChangeDrive err 0x%x!\r\n", ret);
576 errno = ENOENT;
577 return (int)LOS_NOK;
578 }
579
580 res = f_stat(path, &fileInfo);
581 if (res != FR_OK) {
582 PRINT_ERR("FAT stat err 0x%x!\r\n", res);
583 errno = FatfsErrno(res);
584 return (int)LOS_NOK;
585 }
586
587 buf->st_size = fileInfo.fsize;
588 buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
589 S_IWUSR | S_IWGRP | S_IWOTH |
590 S_IXUSR | S_IXGRP | S_IXOTH;
591
592 if (fileInfo.fattrib & AM_RDO) {
593 buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
594 }
595
596 if (fileInfo.fattrib & AM_DIR) {
597 buf->st_mode &= ~S_IFREG;
598 buf->st_mode |= S_IFDIR;
599 }
600
601 return (int)LOS_OK;
602 }
603
604 /* Synchronize all changes to Flash */
FatfsSync(struct File *file)605 int FatfsSync(struct File *file)
606 {
607 FRESULT res;
608 FIL *fp = (FIL *)file->fData;
609
610 if ((fp == NULL) || (fp->obj.fs == NULL)) {
611 errno = ENOENT;
612 return (int)LOS_NOK;
613 }
614
615 res = f_sync(fp);
616 if (res != FR_OK) {
617 errno = FatfsErrno(res);
618 return (int)LOS_NOK;
619 }
620
621 return (int)LOS_OK;
622 }
623
FatfsMkdir(struct MountPoint *mp, const char *path)624 int FatfsMkdir(struct MountPoint *mp, const char *path)
625 {
626 FRESULT res;
627 int ret;
628
629 if (path == NULL) {
630 errno = EFAULT;
631 return (int)LOS_NOK;
632 }
633
634 if (!mp->mWriteEnable) {
635 errno = EACCES;
636 return (int)LOS_NOK;
637 }
638
639 ret = FsChangeDrive(path);
640 if (ret != (int)LOS_OK) {
641 PRINT_ERR("FAT mkdir ChangeDrive err 0x%x!\r\n", ret);
642 errno = ENOENT;
643 return (int)LOS_NOK;
644 }
645
646 res = f_mkdir(path);
647 if (res != FR_OK) {
648 PRINT_ERR("FAT mkdir err 0x%x!\r\n", res);
649 errno = FatfsErrno(res);
650 return (int)LOS_NOK;
651 }
652
653 return (int)LOS_OK;
654 }
655
FatfsOpendir(struct Dir *dir, const char *dirName)656 int FatfsOpendir(struct Dir *dir, const char *dirName)
657 {
658 FRESULT res;
659 DIR *dp = NULL;
660 int ret;
661
662 if (dirName == NULL) {
663 errno = EFAULT;
664 return (int)LOS_NOK;
665 }
666
667 ret = FsChangeDrive(dirName);
668 if (ret != (int)LOS_OK) {
669 PRINT_ERR("FAT opendir ChangeDrive err 0x%x!\r\n", ret);
670 errno = ENOENT;
671 return (int)LOS_NOK;
672 }
673
674 dp = (DIR *)LOSCFG_FS_MALLOC_HOOK(sizeof(DIR));
675 if (dp == NULL) {
676 errno = ENOENT;
677 return (int)LOS_NOK;
678 }
679 (void)memset_s(dp, sizeof(DIR), 0, sizeof(DIR));
680
681 res = f_opendir(dp, dirName);
682 if (res != FR_OK) {
683 PRINT_ERR("FAT opendir err 0x%x!\r\n", res);
684 LOSCFG_FS_FREE_HOOK(dp);
685 errno = FatfsErrno(res);
686 return (int)LOS_NOK;
687 }
688
689 dir->dData = dp;
690 dir->dOffset = 0;
691
692 return (int)LOS_OK;
693 }
694
FatfsReaddir(struct Dir *dir, struct dirent *dent)695 int FatfsReaddir(struct Dir *dir, struct dirent *dent)
696 {
697 FRESULT res;
698 FILINFO fileInfo = {0};
699 DIR *dp = NULL;
700
701 if ((dir == NULL) || (dir->dData == NULL)) {
702 errno = EBADF;
703 return (int)LOS_NOK;
704 }
705
706 dp = (DIR *)dir->dData;
707 res = f_readdir(dp, &fileInfo);
708 /* if res not ok or fname is NULL , return NULL */
709 if ((res != FR_OK) || (fileInfo.fname[0] == 0x0)) {
710 PRINT_ERR("FAT readdir err 0x%x!\r\n", res);
711 errno = FatfsErrno(res);
712 return (int)LOS_NOK;
713 }
714
715 (void)memcpy_s(dent->d_name, sizeof(dent->d_name),
716 fileInfo.fname, sizeof(dent->d_name));
717 if (fileInfo.fattrib & AM_DIR) {
718 dent->d_type = DT_DIR;
719 } else {
720 dent->d_type = DT_REG;
721 }
722
723 return (int)LOS_OK;
724 }
725
FatfsClosedir(struct Dir *dir)726 int FatfsClosedir(struct Dir *dir)
727 {
728 FRESULT res;
729 DIR *dp = NULL;
730
731 if ((dir == NULL) || (dir->dData == NULL)) {
732 errno = EBADF;
733 return (int)LOS_NOK;
734 }
735
736 dp = dir->dData;
737 res = f_closedir(dp);
738 if (res != FR_OK) {
739 PRINT_ERR("FAT closedir err 0x%x!\r\n", res);
740 errno = FatfsErrno(res);
741 return (int)LOS_NOK;
742 }
743
744 LOSCFG_FS_FREE_HOOK(dir->dData);
745 dir->dData = NULL;
746
747 return (int)LOS_OK;
748 }
749
FatfsRmdir(struct MountPoint *mp, const char *path)750 int FatfsRmdir(struct MountPoint *mp, const char *path)
751 {
752 FRESULT res;
753 int ret;
754
755 if ((path == NULL) || (mp == NULL)) {
756 errno = EFAULT;
757 return (int)LOS_NOK;
758 }
759
760 if (!mp->mWriteEnable) {
761 errno = EACCES;
762 return (int)LOS_NOK;
763 }
764
765 ret = FsChangeDrive(path);
766 if (ret != (int)LOS_OK) {
767 PRINT_ERR("FAT rmdir ChangeDrive err 0x%x!\r\n", ret);
768 errno = ENOENT;
769 return (int)LOS_NOK;
770 }
771
772 res = f_rmdir(path);
773 if (res != FR_OK) {
774 PRINT_ERR("FAT rmdir err 0x%x!\r\n", res);
775 errno = FatfsErrno(res);
776 return (int)LOS_NOK;
777 }
778
779 return (int)LOS_OK;
780 }
781
FatfsRename(struct MountPoint *mp, const char *oldName, const char *newName)782 int FatfsRename(struct MountPoint *mp, const char *oldName, const char *newName)
783 {
784 FRESULT res;
785 int ret;
786
787 if ((oldName == NULL) || (newName == NULL)) {
788 errno = EFAULT;
789 return (int)LOS_NOK;
790 }
791
792 if (!mp->mWriteEnable) {
793 errno = EACCES;
794 return (int)LOS_NOK;
795 }
796
797 ret = FsChangeDrive(oldName);
798 if (ret != (int)LOS_OK) {
799 PRINT_ERR("FAT f_getfree ChangeDrive err 0x%x!\r\n", ret);
800 errno = ENOENT;
801 return (int)LOS_NOK;
802 }
803
804 res = f_rename(oldName, newName);
805 if (res != FR_OK) {
806 PRINT_ERR("FAT frename err 0x%x!\r\n", res);
807 errno = FatfsErrno(res);
808 return (int)LOS_NOK;
809 }
810
811 return (int)LOS_OK;
812 }
813
FatfsStatfs(const char *path, struct statfs *buf)814 int FatfsStatfs(const char *path, struct statfs *buf)
815 {
816 FATFS *fs = NULL;
817 UINT32 freeClust;
818 FRESULT res;
819 int ret;
820
821 if ((path == NULL) || (buf == NULL)) {
822 errno = EFAULT;
823 return (int)LOS_NOK;
824 }
825
826 ret = FsChangeDrive(path);
827 if (ret != FR_OK) {
828 PRINT_ERR("FAT f_getfree ChangeDrive err %d.", ret);
829 errno = FatfsErrno(FR_INVALID_PARAMETER);
830 return (int)LOS_NOK;
831 }
832
833 res = f_getfree(path, &freeClust, &fs);
834 if (res != FR_OK) {
835 PRINT_ERR("FAT f_getfree err 0x%x.", res);
836 errno = FatfsErrno(res);
837 return (int)LOS_NOK;
838 }
839 buf->f_bfree = freeClust;
840 buf->f_bavail = freeClust;
841 /* Cluster #0 and #1 is for VBR, reserve sectors and fat */
842 buf->f_blocks = fs->n_fatent - 2;
843 #if FF_MAX_SS != FF_MIN_SS
844 buf->f_bsize = fs->ssize * fs->csize;
845 #else
846 buf->f_bsize = FF_MIN_SS * fs->csize;
847 #endif
848
849 return (int)LOS_OK;
850 }
851
DoTruncate(struct File *file, off_t length, UINT32 count)852 static int DoTruncate(struct File *file, off_t length, UINT32 count)
853 {
854 FRESULT res = FR_OK;
855 DWORD csz;
856 FIL *fp = (FIL *)file->fData;
857
858 csz = (DWORD)(fp->obj.fs)->csize * SS(fp->obj.fs); /* Cluster size */
859 if (length > csz * count) {
860 #if FF_USE_EXPAND
861 res = f_expand(fp, 0, (FSIZE_t)(length), FALLOC_FL_KEEP_SIZE);
862 #else
863 errno = ENOSYS;
864 return (int)LOS_NOK;
865 #endif
866 } else if (length < csz * count) {
867 res = f_truncate(fp, (FSIZE_t)length);
868 }
869
870 if (res != FR_OK) {
871 errno = FatfsErrno(res);
872 return (int)LOS_NOK;
873 }
874
875 fp->obj.objsize = length; /* Set file size to length */
876 fp->flag |= 0x40; /* Set modified flag */
877
878 return (int)LOS_OK;
879 }
880
FatfsTruncate(struct File *file, off_t length)881 int FatfsTruncate(struct File *file, off_t length)
882 {
883 FRESULT res;
884 UINT count;
885 DWORD fclust;
886 FIL *fp = (FIL *)file->fData;
887
888 if ((length < 0) || (length > UINT_MAX)) {
889 errno = EINVAL;
890 return (int)LOS_NOK;
891 }
892
893 if ((fp == NULL) || (fp->obj.fs == NULL)) {
894 errno = ENOENT;
895 return (int)LOS_NOK;
896 }
897
898 res = f_getclustinfo(fp, &fclust, &count);
899 if (res != FR_OK) {
900 errno = FatfsErrno(res);
901 return (int)LOS_NOK;
902 }
903
904 return DoTruncate(file, length, count);
905 }
906
FatfsFdisk(const char *dev, int *partTbl, int arrayNum)907 int FatfsFdisk(const char *dev, int *partTbl, int arrayNum)
908 {
909 int pdrv;
910 FRESULT res;
911
912 if ((dev == NULL) || (partTbl == NULL)) {
913 errno = EFAULT;
914 return (int)LOS_NOK;
915 }
916
917 pdrv = GetDevIdByDevName(dev);
918 if (pdrv < 0) {
919 errno = EFAULT;
920 return (int)LOS_NOK;
921 }
922
923 res = f_fdisk(pdrv, (DWORD const *)partTbl, g_workBuffer);
924 if (res != FR_OK) {
925 errno = FatfsErrno(res);
926 return (int)LOS_NOK;
927 }
928
929 return (int)LOS_OK;
930 }
931
FatfsFormat(const char *partName, void *privData)932 int FatfsFormat(const char *partName, void *privData)
933 {
934 FRESULT res;
935 MKFS_PARM opt = {0};
936 int option = *(int *)privData;
937 char *dev = NULL; /* logical driver */
938
939 if (partName == NULL) {
940 errno = EFAULT;
941 return (int)LOS_NOK;
942 }
943
944 dev = GetLdPath(partName);
945 if (dev == NULL) {
946 errno = EFAULT;
947 return (int)LOS_NOK;
948 }
949
950 opt.fmt = option;
951 opt.n_sect = 0; /* use default allocation unit size depends on the volume
952 size. */
953 res = f_mkfs(dev, &opt, g_workBuffer, FF_MAX_SS);
954 if (res != FR_OK) {
955 errno = FatfsErrno(res);
956 PutLdPath(dev);
957 return (int)LOS_NOK;
958 }
959
960 return (int)LOS_OK;
961 }
962
963 static struct MountOps g_fatfsMnt = {
964 .mount = FatfsMount,
965 .umount = FatfsUmount,
966 .umount2 = FatfsUmount2,
967 .statfs = FatfsStatfs,
968 };
969
970 static struct FileOps g_fatfsFops = {
971 .open = FatfsOpen,
972 .close = FatfsClose,
973 .read = FatfsRead,
974 .write = FatfsWrite,
975 .lseek = FatfsLseek,
976 .stat = FatfsStat,
977 .truncate = FatfsTruncate,
978 .unlink = FatfsUnlink,
979 .rename = FatfsRename,
980 .ioctl = NULL, /* not support */
981 .sync = FatfsSync,
982 .opendir = FatfsOpendir,
983 .readdir = FatfsReaddir,
984 .closedir = FatfsClosedir,
985 .mkdir = FatfsMkdir,
986 .rmdir = FatfsRmdir,
987 };
988
989 static struct FsManagement g_fatfsMgt = {
990 .fdisk = FatfsFdisk,
991 .format = FatfsFormat,
992 };
993
FatFsInit(void)994 void FatFsInit(void)
995 {
996 (void)OsFsRegister("vfat", &g_fatfsMnt, &g_fatfsFops, &g_fatfsMgt);
997 }
998