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 #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 "cmsis_os2.h"
44 #include "fs_operations.h"
45
46 /* the max name length of different parts should not bigger than 32 */
47 #define FS_DRIVE_NAME_MAX_LEN 32
48
49 #ifndef FAT_MAX_OPEN_DIRS
50 #define FAT_MAX_OPEN_DIRS 8
51 #endif /* FAT_MAX_OPEN_DIRS */
52
53 #ifndef FS_LOCK_TIMEOUT_SEC
54 #define FS_LOCK_TIMEOUT_SEC 15
55 #endif /* FS_LOCK_TIMEOUT_SEC */
56
57 #define PART_NAME 0x0
58 #define VOLUME_NAME 0x1
59 #define PATH_NAME 0x2
60 #define NAME_MASK 0x3
61
62 typedef struct {
63 UINT8 useFlag;
64 FIL fil;
65 } FatHandleStruct;
66
67 static FatHandleStruct g_handle[FAT_MAX_OPEN_FILES] = {0};
68 static DIR g_dir[FAT_MAX_OPEN_DIRS] = {0};
69 static FATFS g_fatfs[FF_VOLUMES] = {0};
70 static UINT8 g_workBuffer[FF_MAX_SS];
71 static UINT32 g_fileNum = 0;
72 static UINT32 g_dirNum = 0;
73 static struct dirent g_retValue;
74 static pthread_mutex_t g_fsMutex = PTHREAD_MUTEX_INITIALIZER;
75
76 static const char * const g_volPath[FF_VOLUMES] = {FF_VOLUME_STRS};
77 static BOOL g_volWriteEnable[FF_VOLUMES] = {FALSE};
78
FsLock(void)79 static int FsLock(void)
80 {
81 INT32 ret = 0;
82 struct timespec absTimeout = {0};
83 if (osKernelGetState() != osKernelRunning) {
84 return ret;
85 }
86 ret = clock_gettime(CLOCK_REALTIME, &absTimeout);
87 if (ret != 0) {
88 PRINTK("clock gettime err 0x%x!\r\n", errno);
89 return errno;
90 }
91 absTimeout.tv_sec += FS_LOCK_TIMEOUT_SEC;
92 ret = pthread_mutex_timedlock(&g_fsMutex, &absTimeout);
93 return ret;
94 }
95
FsUnlock(void)96 static void FsUnlock(void)
97 {
98 if (osKernelGetState() != osKernelRunning) {
99 return;
100 }
101 (void)pthread_mutex_unlock(&g_fsMutex);
102 }
103
IsValidFd(int fd)104 static bool IsValidFd(int fd)
105 {
106 if ((fd < 0) || (fd >= FAT_MAX_OPEN_FILES) || (g_handle[fd].useFlag == 0)) {
107 return false;
108 }
109 return true;
110 }
111
FsChangeDrive(const char * path)112 static int FsChangeDrive(const char *path)
113 {
114 INT32 res;
115 CHAR tmpPath[FS_DRIVE_NAME_MAX_LEN] = { "/" }; /* the max name length of different parts is 16 */
116 errno_t retErr;
117 UINT16 pathLen;
118 pathLen = strlen((char const *)path);
119 /* make sure the path begin with "/", the path like /xxx/yyy/... */
120 if (pathLen >= (FS_DRIVE_NAME_MAX_LEN - 1)) {
121 /* 2: except first flag "/" and last end flag */
122 pathLen = FS_DRIVE_NAME_MAX_LEN - 2;
123 }
124
125 retErr = strncpy_s(tmpPath + 1, (FS_DRIVE_NAME_MAX_LEN - 1), (char const *)path, pathLen);
126 if (retErr != EOK) {
127 return FS_FAILURE;
128 }
129
130 res = f_chdrive(tmpPath);
131 if (res != FR_OK) {
132 return FS_FAILURE;
133 }
134
135 return FS_SUCCESS;
136 }
137
FsPartitionMatch(const char * path,int flag)138 static int FsPartitionMatch(const char *path, int flag)
139 {
140 INT32 ret;
141 UINT32 index;
142 CHAR tmpName[FF_MAX_LFN] = {0};
143
144 if (path == NULL) {
145 return FS_FAILURE;
146 }
147
148 switch ((UINT32)flag & NAME_MASK) {
149 case VOLUME_NAME:
150 ret = sscanf_s(path, "/%[^/]", tmpName, FF_MAX_LFN);
151 if (ret <= 0) {
152 return FS_FAILURE;
153 }
154 break;
155 case PATH_NAME:
156 ret = sscanf_s(path, "%[^/]", tmpName, FF_MAX_LFN);
157 if (ret <= 0) {
158 return FS_FAILURE;
159 }
160 break;
161 case PART_NAME:
162 default:
163 ret = strcpy_s(tmpName, FF_MAX_LFN, path);
164 if (ret != EOK) {
165 return FS_FAILURE;
166 }
167 }
168
169 for (index = 0; index < FF_VOLUMES; index++) {
170 if (strcmp(tmpName, g_volPath[index]) == 0) {
171 return index;
172 }
173 }
174 return FS_FAILURE;
175 }
176
Remount(const char * path,unsigned long mountflags)177 static int Remount(const char *path, unsigned long mountflags)
178 {
179 INT32 index;
180
181 index = FsPartitionMatch(path, PART_NAME);
182 if (index == FS_FAILURE) {
183 PRINTK("Wrong volume path!\r\n");
184 errno = ENOENT;
185 return FS_FAILURE;
186 }
187
188 /* remount is not allowed when the device is not mounted. */
189 if (g_fatfs[index].fs_type == 0) {
190 errno = EINVAL;
191 return FS_FAILURE;
192 }
193 g_volWriteEnable[index] = (mountflags & MS_RDONLY) ? FALSE : TRUE;
194
195 return FS_SUCCESS;
196 }
197
FsCheckByPath(const char * path)198 static bool FsCheckByPath(const char *path)
199 {
200 INT32 index;
201
202 index = FsPartitionMatch(path, PATH_NAME);
203 if (index == FS_FAILURE) {
204 return FS_FAILURE;
205 }
206
207 return g_volWriteEnable[index];
208 }
209
FsCheckByID(int id)210 static bool FsCheckByID(int id)
211 {
212 INT32 index;
213
214 for (index = 0; index < FF_VOLUMES; index++) {
215 if (g_fatfs[index].id == id) {
216 return g_volWriteEnable[index];
217 }
218 }
219 return false;
220 }
221
FatFsGetMode(int oflags)222 static unsigned int FatFsGetMode(int oflags)
223 {
224 UINT32 fmode = FA_READ;
225
226 if ((UINT32)oflags & O_WRONLY) {
227 fmode |= FA_WRITE;
228 }
229
230 if (((UINT32)oflags & O_ACCMODE) & O_RDWR) {
231 fmode |= FA_WRITE;
232 }
233 /* Creates a new file if the file is not existing, otherwise, just open it. */
234 if ((UINT32)oflags & O_CREAT) {
235 fmode |= FA_OPEN_ALWAYS;
236 /* Creates a new file. If the file already exists, the function shall fail. */
237 if ((UINT32)oflags & O_EXCL) {
238 fmode |= FA_CREATE_NEW;
239 }
240 }
241 /* Creates a new file. If the file already exists, its length shall be truncated to 0. */
242 if ((UINT32)oflags & O_TRUNC) {
243 fmode |= FA_CREATE_ALWAYS;
244 }
245
246 return fmode;
247 }
248
FatfsErrno(int result)249 static int FatfsErrno(int result)
250 {
251 INT32 status = 0;
252
253 if (result < 0) {
254 return result;
255 }
256
257 /* FatFs errno to Libc errno */
258 switch (result) {
259 case FR_OK:
260 break;
261
262 case FR_NO_FILE:
263 case FR_NO_PATH:
264 case FR_NO_FILESYSTEM:
265 status = ENOENT;
266 break;
267
268 case FR_INVALID_NAME:
269 status = EINVAL;
270 break;
271
272 case FR_EXIST:
273 case FR_INVALID_OBJECT:
274 status = EEXIST;
275 break;
276
277 case FR_DISK_ERR:
278 case FR_NOT_READY:
279 case FR_INT_ERR:
280 status = EIO;
281 break;
282
283 case FR_WRITE_PROTECTED:
284 status = EROFS;
285 break;
286 case FR_MKFS_ABORTED:
287 case FR_INVALID_PARAMETER:
288 status = EINVAL;
289 break;
290
291 case FR_NO_SPACE_LEFT:
292 status = ENOSPC;
293 break;
294 case FR_NO_DIRENTRY:
295 status = ENFILE;
296 break;
297 case FR_NO_EMPTY_DIR:
298 status = ENOTEMPTY;
299 break;
300 case FR_IS_DIR:
301 status = EISDIR;
302 break;
303 case FR_NO_DIR:
304 status = ENOTDIR;
305 break;
306 case FR_NO_EPERM:
307 case FR_DENIED:
308 status = EPERM;
309 break;
310 case FR_LOCKED:
311 status = EBUSY;
312 break;
313 default:
314 status = result;
315 break;
316 }
317
318 return status;
319 }
320
fatfs_mount(const char * source,const char * target,const char * filesystemtype,unsigned long mountflags,const void * data)321 int fatfs_mount(const char *source, const char *target,
322 const char *filesystemtype, unsigned long mountflags,
323 const void *data)
324 {
325 INT32 index;
326 FRESULT res;
327 INT32 ret;
328
329 if ((target == NULL) || (filesystemtype == NULL)) {
330 errno = EFAULT;
331 return FS_FAILURE;
332 }
333
334 ret = FsLock();
335 if (ret != 0) {
336 errno = ret;
337 return FS_FAILURE;
338 }
339
340 if (mountflags & MS_REMOUNT) {
341 ret = Remount(target, mountflags);
342 goto OUT;
343 }
344
345 if (strcmp(filesystemtype, "fat") != 0) {
346 errno = ENODEV;
347 ret = FS_FAILURE;
348 goto OUT;
349 }
350
351 index = FsPartitionMatch(target, VOLUME_NAME);
352 if (index == FS_FAILURE) {
353 errno = ENODEV;
354 ret = FS_FAILURE;
355 goto OUT;
356 }
357
358 /* If the volume has been mounted */
359 if (g_fatfs[index].fs_type != 0) {
360 errno = EBUSY;
361 ret = FS_FAILURE;
362 goto OUT;
363 }
364
365 res = f_mount(&g_fatfs[index], target, 1);
366 if (res != FR_OK) {
367 errno = FatfsErrno(res);
368 ret = FS_FAILURE;
369 goto OUT;
370 }
371
372 g_volWriteEnable[index] = (mountflags & MS_RDONLY) ? FALSE : TRUE;
373 ret = FS_SUCCESS;
374
375 OUT:
376 FsUnlock();
377 return ret;
378 }
379
fatfs_umount(const char * target)380 int fatfs_umount(const char *target)
381 {
382 FRESULT res;
383 INT32 ret;
384 INT32 index;
385
386 if (target == NULL) {
387 errno = EFAULT;
388 return FS_FAILURE;
389 }
390
391 ret = FsLock();
392 if (ret != 0) {
393 errno = ret;
394 return FS_FAILURE;
395 }
396
397 index = FsPartitionMatch(target, VOLUME_NAME);
398 if (index == FS_FAILURE) {
399 errno = ENOENT;
400 ret = FS_FAILURE;
401 goto OUT;
402 }
403
404 /* The volume is not mounted */
405 if (g_fatfs[index].fs_type == 0) {
406 errno = EINVAL;
407 ret = FS_FAILURE;
408 goto OUT;
409 }
410
411 /* umount is not allowed when a file or diretory is opened. */
412 if (f_checkopenlock(index) != FR_OK) {
413 errno = EBUSY;
414 ret = FS_FAILURE;
415 goto OUT;
416 }
417
418 res = f_mount((FATFS *)NULL, target, 0);
419 if (res != FR_OK) {
420 errno = FatfsErrno(res);
421 ret = FS_FAILURE;
422 goto OUT;
423 }
424
425 if (g_fatfs[index].win != NULL) {
426 ff_memfree(g_fatfs[index].win);
427 }
428
429 (void)memset_s(&g_fatfs[index], sizeof(FATFS), 0x0, sizeof(FATFS));
430
431 ret = FS_SUCCESS;
432
433 OUT:
434 FsUnlock();
435 return ret;
436 }
437
CloseAll(int index)438 static int CloseAll(int index)
439 {
440 INT32 i;
441 FRESULT res;
442
443 for (i = 0; i < FAT_MAX_OPEN_FILES; i++) {
444 if (g_fileNum <= 0) {
445 break;
446 }
447 if ((g_handle[i].useFlag == 1) && (g_handle[i].fil.obj.fs == &g_fatfs[index])) {
448 res = f_close(&g_handle[i].fil);
449 if (res != FR_OK) {
450 errno = FatfsErrno(res);
451 return FS_FAILURE;
452 }
453 (void)memset_s(&g_handle[i], sizeof(FatHandleStruct), 0x0, sizeof(FatHandleStruct));
454 g_fileNum--;
455 }
456 }
457
458 for (i = 0; i < FAT_MAX_OPEN_DIRS; i++) {
459 if (g_dirNum <= 0) {
460 break;
461 }
462 if (g_dir[i].obj.fs == &g_fatfs[index]) {
463 res = f_closedir(&g_dir[i]);
464 if (res != FR_OK) {
465 errno = FatfsErrno(res);
466 return FS_FAILURE;
467 }
468 (void)memset_s(&g_dir[i], sizeof(DIR), 0x0, sizeof(DIR));
469 g_dirNum--;
470 }
471 }
472
473 return FS_SUCCESS;
474 }
475
fatfs_umount2(const char * target,int flag)476 int fatfs_umount2(const char *target, int flag)
477 {
478 INT32 index;
479 INT32 ret;
480 UINT32 flags;
481 FRESULT res;
482
483 if (target == NULL) {
484 errno = EFAULT;
485 return FS_FAILURE;
486 }
487
488 flags = MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW;
489 if ((UINT32)flag & ~flags) {
490 errno = EINVAL;
491 return FS_FAILURE;
492 }
493
494 ret = FsLock();
495 if (ret != 0) {
496 errno = ret;
497 return FS_FAILURE;
498 }
499
500 index = FsPartitionMatch(target, VOLUME_NAME);
501 if (index == FS_FAILURE) {
502 errno = ENOENT;
503 ret = FS_FAILURE;
504 goto OUT;
505 }
506
507 /* The volume is not mounted */
508 if (g_fatfs[index].fs_type == 0) {
509 errno = EINVAL;
510 ret = FS_FAILURE;
511 goto OUT;
512 }
513
514 if ((UINT32)flag & MNT_FORCE) {
515 ret = CloseAll(index);
516 if (ret != FS_SUCCESS) {
517 goto OUT;
518 }
519 }
520
521 res = f_mount((FATFS *)NULL, target, 0);
522 if (res != FR_OK) {
523 errno = FatfsErrno(res);
524 ret = FS_FAILURE;
525 goto OUT;
526 }
527
528 if (g_fatfs[index].win != NULL) {
529 ff_memfree(g_fatfs[index].win);
530 }
531
532 (void)memset_s(&g_fatfs[index], sizeof(FATFS), 0x0, sizeof(FATFS));
533 ret = FS_SUCCESS;
534
535 OUT:
536 FsUnlock();
537 return ret;
538 }
539
fatfs_open(const char * path,int oflag,...)540 int fatfs_open(const char *path, int oflag, ...)
541 {
542 FRESULT res;
543 UINT32 i;
544 UINT32 openNum = 0;
545 UINT32 fmode;
546 INT32 ret;
547 FILINFO fileInfo = {0};
548
549 if (path == NULL) {
550 errno = EFAULT;
551 return FS_FAILURE;
552 }
553
554 fmode = FatFsGetMode(oflag);
555
556 ret = FsLock();
557 if (ret != 0) {
558 errno = ret;
559 return FS_FAILURE;
560 }
561
562 if (g_fileNum >= FAT_MAX_OPEN_FILES) {
563 PRINTK("FAT g_fileNum is out of range 0x%x!\r\n", g_fileNum);
564 errno = ENFILE;
565 ret = FS_FAILURE;
566 goto OUT;
567 }
568
569 for (i = 0; i < FAT_MAX_OPEN_FILES; i++) {
570 if (g_handle[i].useFlag == 0) {
571 openNum = i;
572 break;
573 }
574 }
575
576 if (i >= FAT_MAX_OPEN_FILES) {
577 PRINTK("FAT opennum is out of range 0x%x!\r\n", openNum);
578 errno = ENFILE;
579 ret = FS_FAILURE;
580 goto OUT;
581 }
582
583 ret = FsChangeDrive(path);
584 if (ret != FS_SUCCESS) {
585 PRINTK("FAT open ChangeDrive err 0x%x!\r\n", ret);
586 errno = ENOENT;
587 ret = FS_FAILURE;
588 goto OUT;
589 }
590
591 /* cannot creat a new file in the write protected part */
592 if ((((UINT32)oflag & O_CREAT) != 0) && (!FsCheckByPath(path))) {
593 res = f_stat(path, &fileInfo);
594 if ((res == FR_NO_FILE) || (res == FR_NO_PATH)) {
595 PRINTK("FAT creat err 0x%x!\r\n", res);
596 errno = EACCES;
597 ret = FS_FAILURE;
598 goto OUT;
599 }
600 }
601
602 res = f_open(&g_handle[openNum].fil, path, fmode);
603 if (res != FR_OK) {
604 PRINTK("FAT open err 0x%x!\r\n", res);
605 errno = FatfsErrno(res);
606 ret = FS_FAILURE;
607 goto OUT;
608 }
609
610 g_handle[openNum].useFlag = 1;
611 g_fileNum++;
612
613 ret = openNum;
614
615 OUT:
616 FsUnlock();
617 return ret;
618 }
619
fatfs_close(int fd)620 int fatfs_close(int fd)
621 {
622 FRESULT res;
623 INT32 ret;
624
625 ret = FsLock();
626 if (ret != 0) {
627 errno = ret;
628 return FS_FAILURE;
629 }
630
631 if (!IsValidFd(fd)) {
632 FsUnlock();
633 errno = EBADF;
634 return FS_FAILURE;
635 }
636
637 if (g_handle[fd].fil.obj.fs == NULL) {
638 FsUnlock();
639 errno = ENOENT;
640 return FS_FAILURE;
641 }
642
643 res = f_close(&g_handle[fd].fil);
644 if (res != FR_OK) {
645 PRINTK("FAT close err 0x%x!\r\n", res);
646 FsUnlock();
647 errno = FatfsErrno(res);
648 return FS_FAILURE;
649 }
650
651 #if !FF_FS_TINY
652 if (g_handle[fd].fil.buf != NULL) {
653 (void)ff_memfree(g_handle[fd].fil.buf);
654 }
655 #endif
656
657 (void)memset_s(&g_handle[fd], sizeof(FatHandleStruct), 0x0, sizeof(FatHandleStruct));
658
659 if (g_fileNum > 0) {
660 g_fileNum--;
661 }
662
663 FsUnlock();
664
665 return FS_SUCCESS;
666 }
667
fatfs_read(int fd,void * buf,size_t nbyte)668 ssize_t fatfs_read(int fd, void *buf, size_t nbyte)
669 {
670 FRESULT res;
671 INT32 ret;
672 UINT32 lenRead;
673
674 if (buf == NULL) {
675 errno = EFAULT;
676 return FS_FAILURE;
677 }
678
679 ret = FsLock();
680 if (ret != 0) {
681 errno = ret;
682 return FS_FAILURE;
683 }
684
685 if (!IsValidFd(fd)) {
686 FsUnlock();
687 errno = EBADF;
688 return FS_FAILURE;
689 }
690
691 if (g_handle[fd].fil.obj.fs == NULL) {
692 FsUnlock();
693 errno = ENOENT;
694 return FS_FAILURE;
695 }
696
697 res = f_read(&g_handle[fd].fil, buf, nbyte, &lenRead);
698 if (res != FR_OK) {
699 FsUnlock();
700 errno = FatfsErrno(res);
701 return FS_FAILURE;
702 }
703 FsUnlock();
704
705 return (ssize_t)lenRead;
706 }
707
fatfs_write(int fd,const void * buf,size_t nbyte)708 ssize_t fatfs_write(int fd, const void *buf, size_t nbyte)
709 {
710 FRESULT res;
711 INT32 ret;
712 UINT32 lenWrite;
713 static BOOL overFlow = FALSE;
714
715 if (buf == NULL) {
716 errno = EFAULT;
717 return FS_FAILURE;
718 }
719
720 ret = FsLock();
721 if (ret != 0) {
722 errno = ret;
723 return FS_FAILURE;
724 }
725
726 if (!IsValidFd(fd)) {
727 errno = EBADF;
728 goto ERROUT;
729 }
730
731 if (g_handle[fd].fil.obj.fs == NULL) {
732 errno = ENOENT;
733 goto ERROUT;
734 }
735
736 if (!FsCheckByID(g_handle[fd].fil.obj.fs->id)) {
737 errno = EACCES;
738 goto ERROUT;
739 }
740
741 res = f_write(&g_handle[fd].fil, buf, nbyte, &lenWrite);
742 if ((res == FR_OK) && (lenWrite == 0) && (nbyte != 0) && (overFlow == FALSE)) {
743 overFlow = TRUE;
744 PRINTK("FAT write err 0x%x!\r\n", fd);
745 }
746
747 if ((res != FR_OK) || (nbyte != lenWrite)) {
748 errno = FatfsErrno(res);
749 goto ERROUT;
750 }
751
752 FsUnlock();
753 return (ssize_t)lenWrite;
754
755 ERROUT:
756 FsUnlock();
757 return FS_FAILURE;
758 }
759
fatfs_lseek(int fd,off_t offset,int whence)760 off_t fatfs_lseek(int fd, off_t offset, int whence)
761 {
762 FRESULT res;
763 INT32 ret;
764 off_t pos;
765
766 ret = FsLock();
767 if (ret != 0) {
768 errno = ret;
769 return FS_FAILURE;
770 }
771
772 if (!IsValidFd(fd)) {
773 errno = EBADF;
774 goto ERROUT;
775 }
776
777 if (g_handle[fd].fil.obj.fs == NULL) {
778 errno = ENOENT;
779 goto ERROUT;
780 }
781
782 if (whence == SEEK_SET) {
783 pos = 0;
784 } else if (whence == SEEK_CUR) {
785 pos = f_tell(&g_handle[fd].fil);
786 } else if (whence == SEEK_END) {
787 pos = f_size(&g_handle[fd].fil);
788 } else {
789 errno = EINVAL;
790 goto ERROUT;
791 }
792
793 res = f_lseek(&g_handle[fd].fil, offset + pos);
794 if (res != FR_OK) {
795 errno = FatfsErrno(res);
796 goto ERROUT;
797 }
798
799 pos = f_tell(&g_handle[fd].fil);
800 FsUnlock();
801 return pos;
802
803 ERROUT:
804 FsUnlock();
805 return FS_FAILURE;
806 }
807
808 /* Remove the specified FILE */
fatfs_unlink(const char * path)809 int fatfs_unlink(const char *path)
810 {
811 FRESULT res;
812 INT32 ret;
813
814 if (path == NULL) {
815 errno = EFAULT;
816 return FS_FAILURE;
817 }
818
819 ret = FsLock();
820 if (ret != 0) {
821 errno = ret;
822 return FS_FAILURE;
823 }
824
825 if (!FsCheckByPath(path)) {
826 errno = EACCES;
827 ret = FS_FAILURE;
828 goto OUT;
829 }
830
831 ret = FsChangeDrive(path);
832 if (ret != FS_SUCCESS) {
833 PRINTK("FAT ulink ChangeDrive err 0x%x!\r\n", ret);
834 errno = ENOENT;
835 ret = FS_FAILURE;
836 goto OUT;
837 }
838
839 res = f_unlink(path);
840 if (res != FR_OK) {
841 PRINTK("FAT ulink err 0x%x!\r\n", res);
842 errno = FatfsErrno(res);
843 ret = FS_FAILURE;
844 goto OUT;
845 }
846
847 ret = FS_SUCCESS;
848
849 OUT:
850 FsUnlock();
851 return ret;
852 }
853
854 /* Return information about a file */
fatfs_fstat(int fd,struct stat * buf)855 int fatfs_fstat(int fd, struct stat *buf)
856 {
857 INT32 ret;
858
859 if (buf == NULL) {
860 errno = EFAULT;
861 return FS_FAILURE;
862 }
863
864 ret = FsLock();
865 if (ret != 0) {
866 errno = ret;
867 return FS_FAILURE;
868 }
869
870 if (!IsValidFd(fd)) {
871 FsUnlock();
872 errno = EBADF;
873 return FS_FAILURE;
874 }
875
876 if (g_handle[fd].fil.obj.fs == NULL) {
877 FsUnlock();
878 errno = ENOENT;
879 return FS_FAILURE;
880 }
881
882 buf->st_size = f_size(&g_handle[fd].fil);
883 buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
884 S_IWUSR | S_IWGRP | S_IWOTH |
885 S_IXUSR | S_IXGRP | S_IXOTH;
886 if (g_handle[fd].fil.obj.attr & AM_RDO) {
887 buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
888 }
889
890 FsUnlock();
891 return FS_SUCCESS;
892 }
893
fatfs_stat(const char * path,struct stat * buf)894 int fatfs_stat(const char *path, struct stat *buf)
895 {
896 FRESULT res;
897 FILINFO fileInfo = {0};
898 INT32 ret;
899
900 if ((path == NULL) || (buf == NULL)) {
901 errno = EFAULT;
902 return FS_FAILURE;
903 }
904
905 ret = FsLock();
906 if (ret != 0) {
907 errno = ret;
908 return FS_FAILURE;
909 }
910
911 ret = FsChangeDrive(path);
912 if (ret != FS_SUCCESS) {
913 PRINTK("FAT stat ChangeDrive err 0x%x!\r\n", ret);
914 errno = ENOENT;
915 ret = FS_FAILURE;
916 goto OUT;
917 }
918
919 res = f_stat(path, &fileInfo);
920 if (res != FR_OK) {
921 PRINTK("FAT stat err 0x%x!\r\n", res);
922 errno = FatfsErrno(res);
923 ret = FS_FAILURE;
924 goto OUT;
925 }
926
927 buf->st_size = fileInfo.fsize;
928 buf->st_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH |
929 S_IWUSR | S_IWGRP | S_IWOTH |
930 S_IXUSR | S_IXGRP | S_IXOTH;
931
932 if (fileInfo.fattrib & AM_RDO) {
933 buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
934 }
935
936 if (fileInfo.fattrib & AM_DIR) {
937 buf->st_mode &= ~S_IFREG;
938 buf->st_mode |= S_IFDIR;
939 }
940
941 ret = FS_SUCCESS;
942
943 OUT:
944 FsUnlock();
945 return ret;
946 }
947
948 /* Synchronize all changes to Flash */
fatfs_fsync(int fd)949 int fatfs_fsync(int fd)
950 {
951 FRESULT res;
952 INT32 ret;
953
954 ret = FsLock();
955 if (ret != 0) {
956 errno = ret;
957 return FS_FAILURE;
958 }
959
960 if (!IsValidFd(fd)) {
961 errno = EBADF;
962 ret = FS_FAILURE;
963 goto OUT;
964 }
965
966 if (g_handle[fd].fil.obj.fs == NULL) {
967 errno = ENOENT;
968 ret = FS_FAILURE;
969 goto OUT;
970 }
971
972 if (!FsCheckByID(g_handle[fd].fil.obj.fs->id)) {
973 errno = EACCES;
974 ret = FS_FAILURE;
975 goto OUT;
976 }
977
978 res = f_sync(&g_handle[fd].fil);
979 if (res != FR_OK) {
980 errno = FatfsErrno(res);
981 ret = FS_FAILURE;
982 goto OUT;
983 }
984 ret = FS_SUCCESS;
985
986 OUT:
987 FsUnlock();
988 return ret;
989 }
990
fatfs_mkdir(const char * path,mode_t mode)991 int fatfs_mkdir(const char *path, mode_t mode)
992 {
993 FRESULT res;
994 INT32 ret;
995
996 if (path == NULL) {
997 errno = EFAULT;
998 return FS_FAILURE;
999 }
1000
1001 ret = FsLock();
1002 if (ret != 0) {
1003 errno = ret;
1004 return FS_FAILURE;
1005 }
1006
1007 if (!FsCheckByPath(path)) {
1008 errno = EACCES;
1009 ret = FS_FAILURE;
1010 goto OUT;
1011 }
1012
1013 ret = FsChangeDrive(path);
1014 if (ret != FS_SUCCESS) {
1015 PRINTK("FAT mkdir ChangeDrive err 0x%x!\r\n", ret);
1016 errno = ENOENT;
1017 ret = FS_FAILURE;
1018 goto OUT;
1019 }
1020
1021 res = f_mkdir(path);
1022 if (res != FR_OK) {
1023 PRINTK("FAT mkdir err 0x%x!\r\n", res);
1024 errno = FatfsErrno(res);
1025 ret = FS_FAILURE;
1026 goto OUT;
1027 }
1028 ret = FS_SUCCESS;
1029
1030 OUT:
1031 FsUnlock();
1032 return ret;
1033 }
1034
fatfs_opendir(const char * dirName)1035 DIR *fatfs_opendir(const char *dirName)
1036 {
1037 FRESULT res;
1038 UINT32 openNum = 0;
1039 UINT32 i;
1040 INT32 ret;
1041
1042 if (dirName == NULL) {
1043 errno = EFAULT;
1044 return NULL;
1045 }
1046
1047 ret = FsLock();
1048 if (ret != 0) {
1049 errno = ret;
1050 return NULL;
1051 }
1052
1053 if (g_dirNum >= FAT_MAX_OPEN_DIRS) {
1054 PRINTK("FAT opendir g_dirNum err 0x%x!\r\n", g_dirNum);
1055 errno = ENFILE;
1056 goto ERROUT;
1057 }
1058
1059 for (i = 0; i < FAT_MAX_OPEN_DIRS; i++) {
1060 if (g_dir[i].dir == NULL) {
1061 openNum = i;
1062 break;
1063 }
1064 }
1065
1066 if (i >= FAT_MAX_OPEN_DIRS) {
1067 PRINTK("FAT dir opennum is out of range 0x%x!\r\n", openNum);
1068 errno = ENFILE;
1069 goto ERROUT;
1070 }
1071
1072 ret = FsChangeDrive(dirName);
1073 if (ret != FS_SUCCESS) {
1074 PRINTK("FAT opendir ChangeDrive err 0x%x!\r\n", ret);
1075 errno = ENOENT;
1076 goto ERROUT;
1077 }
1078
1079 res = f_opendir(&g_dir[openNum], dirName);
1080 if (res != FR_OK) {
1081 g_dir[openNum].dir = NULL;
1082 PRINTK("FAT opendir err 0x%x!\r\n", res);
1083 errno = FatfsErrno(res);
1084 goto ERROUT;
1085 }
1086
1087 g_dirNum++;
1088
1089 FsUnlock();
1090 return &g_dir[openNum];
1091
1092 ERROUT:
1093 FsUnlock();
1094 return NULL;
1095 }
1096
fatfs_readdir(DIR * dir)1097 struct dirent *fatfs_readdir(DIR *dir)
1098 {
1099 FRESULT res;
1100 INT32 ret;
1101 FILINFO fileInfo = {0};
1102
1103 if (dir == NULL) {
1104 errno = EBADF;
1105 return NULL;
1106 }
1107
1108 ret = FsLock();
1109 if (ret != 0) {
1110 errno = ret;
1111 return NULL;
1112 }
1113
1114 res = f_readdir(dir, &fileInfo);
1115 /* if res not ok or fname is NULL , return NULL */
1116 if ((res != FR_OK) || (fileInfo.fname[0] == 0x0)) {
1117 PRINTK("FAT readdir err 0x%x!\r\n", res);
1118 errno = FatfsErrno(res);
1119 FsUnlock();
1120 return NULL;
1121 }
1122
1123 (void)memcpy_s(g_retValue.d_name, sizeof(g_retValue.d_name), fileInfo.fname, sizeof(g_retValue.d_name));
1124 if (fileInfo.fattrib & AM_DIR) {
1125 g_retValue.d_type = DT_DIR;
1126 } else {
1127 g_retValue.d_type = DT_REG;
1128 }
1129 FsUnlock();
1130
1131 return &g_retValue;
1132 }
1133
fatfs_closedir(DIR * dir)1134 int fatfs_closedir(DIR *dir)
1135 {
1136 FRESULT res;
1137 INT32 ret;
1138
1139 if (dir == NULL) {
1140 errno = EBADF;
1141 return FS_FAILURE;
1142 }
1143
1144 ret = FsLock();
1145 if (ret != 0) {
1146 errno = ret;
1147 return FS_FAILURE;
1148 }
1149
1150 g_dirNum--;
1151
1152 res = f_closedir(dir);
1153 if (res != FR_OK) {
1154 PRINTK("FAT closedir err 0x%x!\r\n", res);
1155 FsUnlock();
1156 errno = FatfsErrno(res);
1157 return FS_FAILURE;
1158 }
1159 dir->dir = NULL;
1160 FsUnlock();
1161
1162 return FS_SUCCESS;
1163 }
1164
fatfs_rmdir(const char * path)1165 int fatfs_rmdir(const char *path)
1166 {
1167 FRESULT res;
1168 INT32 ret;
1169
1170 if (path == NULL) {
1171 errno = EFAULT;
1172 return FS_FAILURE;
1173 }
1174
1175 ret = FsLock();
1176 if (ret != 0) {
1177 errno = ret;
1178 return FS_FAILURE;
1179 }
1180
1181 if (!FsCheckByPath(path)) {
1182 errno = EACCES;
1183 ret = FS_FAILURE;
1184 goto OUT;
1185 }
1186
1187 ret = FsChangeDrive(path);
1188 if (ret != FS_SUCCESS) {
1189 PRINTK("FAT rmdir ChangeDrive err 0x%x!\r\n", ret);
1190 errno = ENOENT;
1191 ret = FS_FAILURE;
1192 goto OUT;
1193 }
1194
1195 res = f_rmdir(path);
1196 if (res != FR_OK) {
1197 PRINTK("FAT rmdir err 0x%x!\r\n", res);
1198 errno = FatfsErrno(res);
1199 ret = FS_FAILURE;
1200 goto OUT;
1201 }
1202 ret = FS_SUCCESS;
1203
1204 OUT:
1205 FsUnlock();
1206 return ret;
1207 }
1208
fatfs_rename(const char * oldName,const char * newName)1209 int fatfs_rename(const char *oldName, const char *newName)
1210 {
1211 FRESULT res;
1212 INT32 ret;
1213
1214 if ((oldName == NULL) || (newName == NULL)) {
1215 errno = EFAULT;
1216 return FS_FAILURE;
1217 }
1218
1219 ret = FsLock();
1220 if (ret != 0) {
1221 errno = ret;
1222 return FS_FAILURE;
1223 }
1224
1225 if (!FsCheckByPath(oldName) || !FsCheckByPath(newName)) {
1226 errno = EACCES;
1227 ret = FS_FAILURE;
1228 goto OUT;
1229 }
1230
1231 ret = FsChangeDrive(oldName);
1232 if (ret != FS_SUCCESS) {
1233 PRINTK("FAT f_getfree ChangeDrive err 0x%x!\r\n", ret);
1234 errno = ENOENT;
1235 ret = FS_FAILURE;
1236 goto OUT;
1237 }
1238
1239 res = f_rename(oldName, newName);
1240 if (res != FR_OK) {
1241 PRINTK("FAT frename err 0x%x!\r\n", res);
1242 errno = FatfsErrno(res);
1243 ret = FS_FAILURE;
1244 goto OUT;
1245 }
1246 ret = FS_SUCCESS;
1247
1248 OUT:
1249 FsUnlock();
1250 return ret;
1251 }
1252
fatfs_statfs(const char * path,struct statfs * buf)1253 int fatfs_statfs(const char *path, struct statfs *buf)
1254 {
1255 FATFS *fs = NULL;
1256 UINT32 freeClust;
1257 FRESULT res;
1258 INT32 ret;
1259
1260 if ((path == NULL) || (buf == NULL)) {
1261 errno = EFAULT;
1262 return FS_FAILURE;
1263 }
1264
1265 ret = FsLock();
1266 if (ret != 0) {
1267 errno = ret;
1268 return FS_FAILURE;
1269 }
1270
1271 ret = FsChangeDrive(path);
1272 if (ret != FR_OK) {
1273 PRINTK("FAT f_getfree ChangeDrive err %d.", ret);
1274 errno = FatfsErrno(FR_INVALID_PARAMETER);
1275 ret = FS_FAILURE;
1276 goto OUT;
1277 }
1278
1279 res = f_getfree(path, &freeClust, &fs);
1280 if (res != FR_OK) {
1281 PRINTK("FAT f_getfree err 0x%x.", res);
1282 errno = FatfsErrno(res);
1283 ret = FS_FAILURE;
1284 goto OUT;
1285 }
1286 buf->f_bfree = freeClust;
1287 buf->f_bavail = freeClust;
1288 /* Cluster #0 and #1 is for VBR, reserve sectors and fat */
1289 buf->f_blocks = fs->n_fatent - 2;
1290 #if FF_MAX_SS != FF_MIN_SS
1291 buf->f_bsize = fs->ssize * fs->csize;
1292 #else
1293 buf->f_bsize = FF_MIN_SS * fs->csize;
1294 #endif
1295
1296 ret = FS_SUCCESS;
1297
1298 OUT:
1299 FsUnlock();
1300 return ret;
1301 }
1302
do_truncate(int fd,off_t length,UINT count)1303 static int do_truncate(int fd, off_t length, UINT count)
1304 {
1305 FRESULT res = FR_OK;
1306 INT32 ret = FS_SUCCESS;
1307 DWORD csz;
1308
1309 csz = (DWORD)(g_handle[fd].fil.obj.fs)->csize * SS(g_handle[fd].fil.obj.fs); /* Cluster size */
1310 if (length > csz * count) {
1311 #if FF_USE_EXPAND
1312 res = f_expand(&g_handle[fd].fil, 0, (FSIZE_t)(length), FALLOC_FL_KEEP_SIZE);
1313 #else
1314 errno = ENOSYS;
1315 ret = FS_FAILURE;
1316 return ret;
1317 #endif
1318 } else if (length < csz * count) {
1319 res = f_truncate(&g_handle[fd].fil, (FSIZE_t)length);
1320 }
1321
1322 if (res != FR_OK) {
1323 errno = FatfsErrno(res);
1324 ret = FS_FAILURE;
1325 return ret;
1326 }
1327
1328 g_handle[fd].fil.obj.objsize = length; /* Set file size to length */
1329 g_handle[fd].fil.flag |= 0x40; /* Set modified flag */
1330
1331 return ret;
1332 }
1333
fatfs_ftruncate(int fd,off_t length)1334 int fatfs_ftruncate(int fd, off_t length)
1335 {
1336 FRESULT res;
1337 INT32 ret;
1338 UINT count;
1339 DWORD fclust;
1340
1341 if ((length < 0) || (length > UINT_MAX)) {
1342 errno = EINVAL;
1343 return FS_FAILURE;
1344 }
1345
1346 ret = FsLock();
1347 if (ret != 0) {
1348 errno = ret;
1349 return FS_FAILURE;
1350 }
1351
1352 if (!IsValidFd(fd)) {
1353 errno = EBADF;
1354 ret = FS_FAILURE;
1355 goto OUT;
1356 }
1357
1358 if (g_handle[fd].fil.obj.fs == NULL) {
1359 errno = ENOENT;
1360 ret = FS_FAILURE;
1361 goto OUT;
1362 }
1363
1364 if (!FsCheckByID(g_handle[fd].fil.obj.fs->id)) {
1365 errno = EACCES;
1366 ret = FS_FAILURE;
1367 goto OUT;
1368 }
1369
1370 res = f_getclustinfo(&g_handle[fd].fil, &fclust, &count);
1371 if (res != FR_OK) {
1372 errno = FatfsErrno(res);
1373 ret = FS_FAILURE;
1374 goto OUT;
1375 }
1376
1377 ret = do_truncate(fd, length, count);
1378 if (ret != FR_OK) {
1379 goto OUT;
1380 }
1381
1382 ret = FS_SUCCESS;
1383
1384 OUT:
1385 FsUnlock();
1386 return ret;
1387 }
1388
fatfs_fdisk(int pdrv,const unsigned int * partTbl)1389 int fatfs_fdisk(int pdrv, const unsigned int *partTbl)
1390 {
1391 INT32 index;
1392 FRESULT res;
1393 INT32 ret;
1394
1395 if (partTbl == NULL) {
1396 errno = EFAULT;
1397 return FS_FAILURE;
1398 }
1399
1400 ret = FsLock();
1401 if (ret != 0) {
1402 errno = ret;
1403 ret = FS_FAILURE;
1404 goto OUT;
1405 }
1406
1407 /* fdisk is not allowed when the device has been mounted. */
1408 for (index = 0; index < FF_VOLUMES; index++) {
1409 if ((g_fatfs[index].pdrv == pdrv) && (g_fatfs[index].fs_type != 0)) {
1410 errno = EBUSY;
1411 ret = FS_FAILURE;
1412 goto OUT;
1413 }
1414 }
1415
1416 res = f_fdisk(pdrv, (DWORD const *)partTbl, g_workBuffer);
1417 if (res != FR_OK) {
1418 errno = FatfsErrno(res);
1419 ret = FS_FAILURE;
1420 goto OUT;
1421 }
1422
1423 ret = FS_SUCCESS;
1424
1425 OUT:
1426 FsUnlock();
1427 return ret;
1428 }
1429
fatfs_format(const char * dev,int sectors,int option)1430 int fatfs_format(const char *dev, int sectors, int option)
1431 {
1432 INT32 index;
1433 FRESULT res;
1434 INT32 ret;
1435 MKFS_PARM opt = {0};
1436
1437 if (dev == NULL) {
1438 errno = EFAULT;
1439 return FS_FAILURE;
1440 }
1441
1442 ret = FsLock();
1443 if (ret != 0) {
1444 errno = ret;
1445 return FS_FAILURE;
1446 }
1447
1448 index = FsPartitionMatch(dev, VOLUME_NAME);
1449 if (index == FS_FAILURE) {
1450 errno = ENOENT;
1451 ret = FS_FAILURE;
1452 goto OUT;
1453 }
1454
1455 /* format is not allowed when the device has been mounted. */
1456 if (g_fatfs[index].fs_type != 0) {
1457 errno = EBUSY;
1458 ret = FS_FAILURE;
1459 goto OUT;
1460 }
1461
1462 opt.fmt = option,
1463 opt.n_sect = sectors,
1464 res = f_mkfs(dev, &opt, g_workBuffer, FF_MAX_SS);
1465 if (res != FR_OK) {
1466 errno = FatfsErrno(res);
1467 ret = FS_FAILURE;
1468 goto OUT;
1469 }
1470
1471 ret = FS_SUCCESS;
1472
1473 OUT:
1474 FsUnlock();
1475 return ret;
1476 }
1477
fatfs_pread(int fd,void * buf,size_t nbyte,off_t offset)1478 ssize_t fatfs_pread(int fd, void *buf, size_t nbyte, off_t offset)
1479 {
1480 INT32 ret;
1481 off_t savepos, pos;
1482
1483 if (buf == NULL) {
1484 errno = EFAULT;
1485 return FS_FAILURE;
1486 }
1487
1488 ret = FsLock();
1489 if (ret != 0) {
1490 errno = ret;
1491 return FS_FAILURE;
1492 }
1493
1494 if (!IsValidFd(fd)) {
1495 FsUnlock();
1496 errno = EBADF;
1497 return FS_FAILURE;
1498 }
1499
1500 savepos = (off_t)fatfs_lseek(fd, 0, SEEK_CUR);
1501 if (savepos == (off_t)-1) {
1502 errno = FatfsErrno(savepos);
1503 return FS_FAILURE;
1504 }
1505
1506 pos = (off_t)fatfs_lseek(fd, offset, SEEK_SET);
1507 if (pos == (off_t)-1) {
1508 errno = FatfsErrno(pos);
1509 return FS_FAILURE;
1510 }
1511
1512 ret = fatfs_read(fd, buf, nbyte);
1513 if (ret < 0) {
1514 FsUnlock();
1515 errno = FatfsErrno(ret);
1516 return FS_FAILURE;
1517 }
1518
1519 pos = (off_t)fatfs_lseek(fd, savepos, SEEK_SET);
1520 if ((pos == (off_t)-1) && (ret >= 0)) {
1521 errno = FatfsErrno(pos);
1522 return FS_FAILURE;
1523 }
1524
1525 FsUnlock();
1526
1527 return (ssize_t)ret;
1528 }
1529
fatfs_pwrite(int fd,const void * buf,size_t nbyte,off_t offset)1530 ssize_t fatfs_pwrite(int fd, const void *buf, size_t nbyte, off_t offset)
1531 {
1532 INT32 ret;
1533 off_t savepos, pos;
1534
1535 if (buf == NULL) {
1536 errno = EFAULT;
1537 return FS_FAILURE;
1538 }
1539
1540 ret = FsLock();
1541 if (ret != 0) {
1542 errno = ret;
1543 return FS_FAILURE;
1544 }
1545
1546 if (!IsValidFd(fd)) {
1547 FsUnlock();
1548 errno = EBADF;
1549 return FS_FAILURE;
1550 }
1551
1552 savepos = (off_t)fatfs_lseek(fd, 0, SEEK_CUR);
1553 if (savepos == (off_t)-1) {
1554 errno = FatfsErrno(savepos);
1555 return FS_FAILURE;
1556 }
1557
1558 pos = (off_t)fatfs_lseek(fd, offset, SEEK_SET);
1559 if (pos == (off_t)-1) {
1560 errno = FatfsErrno(pos);
1561 return FS_FAILURE;
1562 }
1563
1564 ret = fatfs_write(fd, buf, nbyte);
1565 if (ret < 0) {
1566 FsUnlock();
1567 errno = FatfsErrno(ret);
1568 return FS_FAILURE;
1569 }
1570
1571 pos = (off_t)fatfs_lseek(fd, savepos, SEEK_SET);
1572 if ((pos == (off_t)-1) && (ret >= 0)) {
1573 errno = FatfsErrno(pos);
1574 return FS_FAILURE;
1575 }
1576
1577 FsUnlock();
1578
1579 return (ssize_t)ret;
1580 }
1581
1582 struct MountOps g_fatfsMnt = {
1583 .Mount = fatfs_mount,
1584 .Umount = fatfs_umount,
1585 .Umount2 = fatfs_umount2,
1586 .Statfs = fatfs_statfs,
1587 };
1588
1589 struct FileOps g_fatfsFops = {
1590 .Mkdir = fatfs_mkdir,
1591 .Unlink = fatfs_unlink,
1592 .Rmdir = fatfs_rmdir,
1593 .Opendir = fatfs_opendir,
1594 .Readdir = fatfs_readdir,
1595 .Closedir = fatfs_closedir,
1596 .Open = fatfs_open,
1597 .Close = fatfs_close,
1598 .Write = fatfs_write,
1599 .Read = fatfs_read,
1600 .Seek = fatfs_lseek,
1601 .Rename = fatfs_rename,
1602 .Getattr = fatfs_stat,
1603 .Fsync = fatfs_fsync,
1604 .Fstat = fatfs_fstat,
1605 .Pread = fatfs_pread,
1606 .Pwrite = fatfs_pwrite,
1607 };
1608