• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #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