xref: /kernel/liteos_m/components/fs/vfs/vfs_fs.c (revision 3d8536b4)
1/*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 *    conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 *    of conditions and the following disclaimer in the documentation and/or other materials
12 *    provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 *    to endorse or promote products derived from this software without specific prior written
16 *    permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#define _GNU_SOURCE 1
32#include "los_fs.h"
33#include <stdint.h>
34#include <string.h>
35#include <stdlib.h>
36#include <stdarg.h>
37#include <stdbool.h>
38#include <unistd.h>
39#include <sys/uio.h>
40#include "errno.h"
41#include "fcntl.h"
42#include "los_mux.h"
43#include "los_debug.h"
44#include "los_sched.h"
45#include "limits.h"
46#include "securec.h"
47#include "vfs_config.h"
48#include "vfs_files.h"
49#include "vfs_maps.h"
50#include "vfs_mount.h"
51#include "vfs_operations.h"
52
53#ifdef LOSCFG_NET_LWIP_SACK
54#include "lwipopts.h"
55#include "lwip/sockets.h"
56#define CONFIG_NSOCKET_DESCRIPTORS  LWIP_CONFIG_NUM_SOCKETS
57#else
58#define CONFIG_NSOCKET_DESCRIPTORS  0
59#endif
60
61#ifdef LOSCFG_RANDOM_DEV
62#include "hks_client.h"
63#define RANDOM_DEV_FD  CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS
64#define RANDOM_DEV_PATH  "/dev/random"
65#endif
66
67#if (LOSCFG_POSIX_PIPE_API == 1)
68#include "pipe_impl.h"
69#ifdef LOSCFG_RANDOM_DEV
70#define PIPE_DEV_FD (RANDOM_DEV_FD + 1)
71#else
72#define PIPE_DEV_FD (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)
73#endif
74
75int PollQueryFd(int fd, struct PollTable *table)
76{
77    if (fd >= PIPE_DEV_FD) {
78        return PipePoll(fd, table);
79    }
80
81    return -ENODEV;
82}
83#endif
84
85#define FREE_AND_SET_NULL(ptr) do { \
86    LOSCFG_FS_FREE_HOOK(ptr);       \
87    ptr = NULL;                     \
88} while (0)
89
90#define LOS_FCNTL   (O_NONBLOCK | O_NDELAY | O_APPEND | O_SYNC)
91#define IOV_MAX_CNT 4
92
93UINT32 g_fsMutex;
94static UINT32 g_dirNum = 0;
95
96int LOS_FsLock(void)
97{
98    if (!OsCheckKernelRunning()) {
99        return LOS_OK;
100    }
101    if (LOS_MuxPend(g_fsMutex, (UINT32)LOSCFG_FS_LOCK_TIMEOUT) != LOS_OK) {
102        PRINT_ERR("LOS_FsLock failed!");
103        return (int)LOS_NOK;
104    }
105
106    return LOS_OK;
107}
108
109void LOS_FsUnlock(void)
110{
111    if (!OsCheckKernelRunning()) {
112        return;
113    }
114    (void)LOS_MuxPost(g_fsMutex);
115}
116
117#ifdef LOSCFG_RANDOM_DEV
118/**
119 * @brief Get canonical form of a given path based on cwd(Current working directory).
120 *
121 * @param cwd Indicates the current working directory.
122 * @param path Indicates the path to be canonicalization.
123 * @param buf Indicates the pointer to the buffer where the result will be return.
124 * @param bufSize Indicates the size of the buffer.
125 * @return Returns the length of the canonical path.
126 *
127 * @attention if path is an absolute path, cwd is ignored. if cwd if not specified, it is assumed to be root('/').
128 *            if the buffer is not big enough the result will be truncated, but the return value will always be the
129 *            length of the canonical path.
130 */
131static size_t GetCanonicalPath(const char *cwd, const char *path, char *buf, size_t bufSize)
132{
133    size_t offset;
134    if (!path) {
135        path = "";
136    }
137
138    if ((!cwd) || (path[0] == '/')) {
139        cwd = "";
140    }
141
142    offset = strlen("///") + 1; // three '/' and one '\0'
143    size_t tmpLen = strlen(cwd) + strlen(path) + offset;
144    char *tmpBuf = (char *)LOSCFG_FS_MALLOC_HOOK(tmpLen);
145    if (tmpBuf == NULL) {
146        return LOS_OK;
147    }
148
149    if (-1 == sprintf_s(tmpBuf, tmpLen, "/%s/%s/", cwd, path)) {
150        LOSCFG_FS_FREE_HOOK(tmpBuf);
151        return LOS_OK;
152    }
153
154    char *p;
155    /* replace /./ to / */
156    offset = strlen("/./") - 1;
157    while ((p = strstr(tmpBuf, "/./")) != NULL) {
158        if (EOK != memmove_s(p, tmpLen - (p - tmpBuf), p + offset, tmpLen - (p - tmpBuf) - offset)) {
159            LOSCFG_FS_FREE_HOOK(tmpBuf);
160            return LOS_OK;
161        }
162    }
163
164    /* replace // to / */
165    while ((p = strstr(tmpBuf, "//")) != NULL) {
166        if (EOK != memmove_s(p, tmpLen - (p - tmpBuf), p + 1, tmpLen - (p - tmpBuf) - 1)) {
167            LOSCFG_FS_FREE_HOOK(tmpBuf);
168            return LOS_OK;
169        }
170    }
171
172    /* handle /../ (e.g., replace /aa/bb/../ to /aa/) */
173    offset = strlen("/../") - 1;
174    while ((p = strstr(tmpBuf, "/../")) != NULL) {
175        char *start = p;
176        while (start > tmpBuf && *(start - 1) != '/') {
177            --start;
178        }
179        if (EOK != memmove_s(start, tmpLen - (start - tmpBuf), p + offset, tmpLen - (p - tmpBuf) - offset)) {
180            LOSCFG_FS_FREE_HOOK(tmpBuf);
181            return LOS_OK;
182        }
183    }
184
185    size_t totalLen = strlen(tmpBuf);
186    /* strip the last / */
187    if (totalLen > 1 && tmpBuf[totalLen - 1] == '/') {
188        tmpBuf[--totalLen] = 0;
189    }
190
191    if ((!buf) || (bufSize == 0)) {
192        LOSCFG_FS_FREE_HOOK(tmpBuf);
193        return totalLen;
194    }
195
196    if (EOK != memcpy_s(buf, bufSize, tmpBuf, (((totalLen + 1) > bufSize) ? bufSize : (totalLen + 1)))) {
197        LOSCFG_FS_FREE_HOOK(tmpBuf);
198        return LOS_OK;
199    }
200
201    buf[bufSize - 1] = 0;
202    LOSCFG_FS_FREE_HOOK(tmpBuf);
203    return totalLen;
204}
205#endif
206
207static int VfsPathCheck(const char *path, bool isFile)
208{
209    size_t len;
210    if ((path == NULL) || (path[0] == '\0')) {
211        VFS_ERRNO_SET(EINVAL);
212        return (int)LOS_NOK;
213    }
214
215    len = strlen(path);
216    if (len >= PATH_MAX) {
217        VFS_ERRNO_SET(ENAMETOOLONG);
218        return (int)LOS_NOK;
219    }
220
221    if (isFile && path[len - 1] == '/') {
222        VFS_ERRNO_SET(EINVAL);
223        return (int)LOS_NOK;
224    }
225
226    return LOS_OK;
227}
228
229static int VfsOpen(const char *path, int flags)
230{
231    size_t len;
232    struct File *file = NULL;
233    int fd = -1;
234    const char *pathInMp = NULL;
235    struct MountPoint *mp = NULL;
236
237    if (VfsPathCheck(path, TRUE) != LOS_OK) {
238        return fd;
239    }
240
241    if (LOS_FsLock() != LOS_OK) {
242        VFS_ERRNO_SET(EAGAIN);
243        return fd;
244    }
245
246    mp = VfsMpFind(path, &pathInMp);
247    if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0') ||
248        (mp->mFs->fsFops == NULL) || (mp->mFs->fsFops->open == NULL)) {
249        /* path is not in any mountpoint */
250        VFS_ERRNO_SET(ENOENT);
251        LOS_FsUnlock();
252        return fd;
253    }
254
255    if ((mp->mWriteEnable == FALSE) &&
256        (flags & (O_CREAT | O_WRONLY | O_RDWR))) {
257        /* can't create file in read only mp */
258        VFS_ERRNO_SET(EACCES);
259        LOS_FsUnlock();
260        return fd;
261    }
262
263    file = VfsFileGet();
264    if (file == NULL) {
265        VFS_ERRNO_SET(ENFILE);
266        LOS_FsUnlock();
267        return fd;
268    }
269
270    len = strlen(path) + 1;
271    file->fullPath = LOSCFG_FS_MALLOC_HOOK(len);
272    if (file->fullPath == NULL) {
273        VFS_ERRNO_SET(ENOMEM);
274        VfsFilePut(file);
275        LOS_FsUnlock();
276        return (int)LOS_NOK;
277    }
278    (void)strcpy_s((char *)file->fullPath, len, path);
279
280    file->fFlags = (UINT32)flags;
281    file->fOffset = 0;
282    file->fData = NULL;
283    file->fFops = mp->mFs->fsFops;
284    file->fMp = mp;
285    file->fOwner = LOS_CurTaskIDGet();
286
287    if (file->fFops->open(file, pathInMp, flags) == 0) {
288        mp->mRefs++;
289        fd = FileToFd(file);
290        file->fStatus = FILE_STATUS_READY; /* file now ready to use */
291    } else {
292        LOSCFG_FS_FREE_HOOK((void *)file->fullPath);
293        VfsFilePut(file);
294    }
295
296    LOS_FsUnlock();
297    return fd;
298}
299
300/* attach to a file and then set new status */
301
302static struct File *VfsAttachFile(int fd, UINT32 status)
303{
304    struct File *file = NULL;
305
306    if ((fd < MIN_START_FD) || (fd >= CONFIG_NFILE_DESCRIPTORS)) {
307        VFS_ERRNO_SET(EBADF);
308        return NULL;
309    }
310
311    if (LOS_FsLock() != LOS_OK) {
312        VFS_ERRNO_SET(EFAULT);
313        return NULL;
314    }
315
316    file = FdToFile(fd);
317    if ((file == NULL) || (file->fMp == NULL)) {
318        VFS_ERRNO_SET(EBADF);
319        LOS_FsUnlock();
320        return NULL;
321    }
322
323    if (file->fStatus != FILE_STATUS_READY) {
324        VFS_ERRNO_SET(EBADF);
325        LOS_FsUnlock();
326        return NULL;
327    }
328
329    file->fStatus = status;
330    return file;
331}
332
333static struct File *VfsAttachFileReady(int fd)
334{
335    return VfsAttachFile(fd, FILE_STATUS_READY);
336}
337
338static struct File *VfsAttachFileWithStatus(int fd, int status)
339{
340    return VfsAttachFile(fd, (UINT32)status);
341}
342
343static void VfsDetachFile(const struct File *file)
344{
345    (void)file;
346    LOS_FsUnlock();
347}
348
349static int VfsClose(int fd)
350{
351    struct File *file = NULL;
352    int ret = (int)LOS_NOK;
353
354    file = VfsAttachFileWithStatus(fd, FILE_STATUS_CLOSING);
355    if (file == NULL) {
356        return ret;
357    }
358
359    if ((file->fFops != NULL) && (file->fFops->close != NULL)) {
360        ret = file->fFops->close(file);
361    } else {
362        VFS_ERRNO_SET(ENOTSUP);
363    }
364
365    if ((ret == 0) && (file->fMp != NULL)) {
366        file->fMp->mRefs--;
367    }
368
369    if (file->fullPath != NULL) {
370        LOSCFG_FS_FREE_HOOK((void *)file->fullPath);
371    }
372
373    VfsFilePut(file);
374
375    VfsDetachFile(file);
376
377    return ret;
378}
379
380static ssize_t VfsRead(int fd, char *buff, size_t bytes)
381{
382    struct File *file = NULL;
383    ssize_t ret = (ssize_t)-1;
384
385    if (buff == NULL) {
386        VFS_ERRNO_SET(EFAULT);
387        return ret;
388    }
389
390    if (bytes == 0) {
391        return 0;
392    }
393
394    file = VfsAttachFileReady(fd);
395    if (file == NULL) {
396        return ret;
397    }
398
399    if ((file->fFlags & O_ACCMODE) == O_WRONLY) {
400        VFS_ERRNO_SET(EACCES);
401    } else if ((file->fFops != NULL) && (file->fFops->read != NULL)) {
402        ret = file->fFops->read(file, buff, bytes);
403    } else {
404        VFS_ERRNO_SET(ENOTSUP);
405    }
406
407    /* else ret will be -1 */
408    VfsDetachFile(file);
409
410    return ret;
411}
412
413static ssize_t VfsWrite(int fd, const void *buff, size_t bytes)
414{
415    struct File *file = NULL;
416    ssize_t ret = (ssize_t)LOS_NOK;
417
418    if ((buff == NULL) || (bytes == 0)) {
419        VFS_ERRNO_SET(EINVAL);
420        return ret;
421    }
422
423    file = VfsAttachFileReady(fd);
424    if (file == NULL) {
425        return ret;
426    }
427
428    if ((file->fFlags & O_ACCMODE) == O_RDONLY) {
429        VFS_ERRNO_SET(EACCES);
430    } else if ((file->fFops != NULL) && (file->fFops->write != NULL)) {
431        ret = file->fFops->write(file, buff, bytes);
432    } else {
433        VFS_ERRNO_SET(ENOTSUP);
434    }
435
436    /* else ret will be -1 */
437    VfsDetachFile(file);
438
439    return ret;
440}
441
442static int VfsIoctl(int fd, int func, va_list ap)
443{
444    unsigned long arg;
445    struct File *file = NULL;
446    int ret = (int)LOS_NOK;
447
448    arg = va_arg(ap, unsigned long);
449    file = VfsAttachFileReady(fd);
450    if (file == NULL) {
451        return ret;
452    }
453
454    if ((file->fFops != NULL) && (file->fFops->ioctl != NULL)) {
455        ret = file->fFops->ioctl(file, func, arg);
456    } else {
457        VFS_ERRNO_SET(ENOTSUP);
458    }
459
460    VfsDetachFile(file);
461
462    return ret;
463}
464
465static int VfsVfcntl(struct File *filep, int cmd, va_list ap)
466{
467    int ret;
468    UINT32 flags;
469
470    if ((filep == NULL) || (filep->fFops == NULL)) {
471        return -EBADF;
472    }
473
474    if (cmd == F_GETFL) {
475        ret = (int)(filep->fFlags);
476    } else if (cmd == F_SETFL) {
477        flags = (UINT32)va_arg(ap, int);
478        flags &= LOS_FCNTL;
479        filep->fFlags &= ~LOS_FCNTL;
480        filep->fFlags |= flags;
481        ret = LOS_OK;
482    } else {
483        ret = -ENOSYS;
484    }
485    return ret;
486}
487
488static int MapToPosixRet(int ret)
489{
490    return ((ret) < 0 ? -1 : (ret));
491}
492
493/* POSIX interface */
494int open(const char *path, int flags, ...)
495{
496    if (path == NULL) {
497        errno = EINVAL;
498        return (int)LOS_NOK;
499    }
500#ifdef LOSCFG_RANDOM_DEV
501    unsigned flagMask = O_RDONLY | O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_LARGEFILE \
502                        | O_TRUNC | O_EXCL | O_DIRECTORY;
503    if ((unsigned)flags & ~flagMask) {
504        errno = EINVAL;
505        return (int)LOS_NOK;
506    }
507
508    size_t pathLen = strlen(path) + 1;
509    if ((unsigned)pathLen > PATH_MAX) {
510        errno = EINVAL;
511        return (int)LOS_NOK;
512    }
513
514    char *canonicalPath = (char *)LOSCFG_FS_MALLOC_HOOK(pathLen);
515    if (!canonicalPath) {
516        errno = ENOMEM;
517        return (int)LOS_NOK;
518    }
519    if (GetCanonicalPath(NULL, path, canonicalPath, pathLen) == 0) {
520        FREE_AND_SET_NULL(canonicalPath);
521        errno = ENOMEM;
522        return (int)LOS_NOK;
523    }
524
525    if (strcmp(canonicalPath, RANDOM_DEV_PATH) == 0) {
526        FREE_AND_SET_NULL(canonicalPath);
527        if ((O_ACCMODE & (unsigned)flags) != O_RDONLY) {
528            errno = EPERM;
529            return (int)LOS_NOK;
530        }
531        if ((unsigned)flags & O_DIRECTORY) {
532            errno = ENOTDIR;
533            return (int)LOS_NOK;
534        }
535        return RANDOM_DEV_FD;
536    }
537    if ((strcmp(canonicalPath, "/") == 0) ||
538        (strcmp(canonicalPath, "/dev") == 0)) {
539        FREE_AND_SET_NULL(canonicalPath);
540        if ((unsigned)flags & O_DIRECTORY) {
541            errno = EPERM;
542            return (int)LOS_NOK;
543        }
544        errno = EISDIR;
545        return (int)LOS_NOK;
546    }
547    FREE_AND_SET_NULL(canonicalPath);
548#endif
549#if (LOSCFG_POSIX_PIPE_API == 1)
550    if (!strncmp(path, PIPE_DEV_PATH, strlen(PIPE_DEV_PATH))) {
551        return PipeOpen(path, flags, PIPE_DEV_FD);
552    }
553#endif
554
555    int ret = VfsOpen(path, flags);
556    return MapToPosixRet(ret);
557}
558#if (LOSCFG_LIBC_NEWLIB == 1)
559FUNC_ALIAS(open, _open, (const char *path, int flags, ...), int);
560#endif
561
562int close(int fd)
563{
564#ifdef LOSCFG_RANDOM_DEV
565    if (fd == RANDOM_DEV_FD) {
566        return LOS_OK;
567    }
568#endif
569#ifdef LOSCFG_NET_LWIP_SACK
570    if (fd >= CONFIG_NFILE_DESCRIPTORS && fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) {
571        return closesocket(fd);
572    }
573#endif /* LOSCFG_NET_LWIP_SACK */
574#if (LOSCFG_POSIX_PIPE_API == 1)
575    if (fd >= PIPE_DEV_FD) {
576        return PipeClose(fd);
577    }
578#endif
579
580    int ret = (int)LOS_NOK;
581    if (fd >= MIN_START_FD && fd < CONFIG_NFILE_DESCRIPTORS) {
582        ret = VfsClose(fd);
583    }
584    return MapToPosixRet(ret);
585}
586#if (LOSCFG_LIBC_NEWLIB == 1)
587FUNC_ALIAS(close, _close, (int fd), int);
588#endif
589
590ssize_t read(int fd, void *buff, size_t bytes)
591{
592#ifdef LOSCFG_RANDOM_DEV
593    if (fd == RANDOM_DEV_FD) {
594        if (nbyte == 0) {
595            return FS_SUCCESS;
596        }
597        if (buf == NULL) {
598            errno = EINVAL;
599            return FS_FAILURE;
600        }
601        if (nbyte > 1024) { /* 1024, max random_size */
602            nbyte = 1024; /* hks_generate_random: random_size must <= 1024 */
603        }
604        struct hks_blob key = {HKS_BLOB_TYPE_RAW, (uint8_t *)buf, nbyte};
605        if (hks_generate_random(&key) != 0) {
606            errno = EIO;
607            return FS_FAILURE;
608        }
609        return (ssize_t)nbyte;
610    }
611#endif
612#ifdef LOSCFG_NET_LWIP_SACK
613    if (fd >= CONFIG_NFILE_DESCRIPTORS && fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) {
614        return recv(fd, buff, bytes, 0);
615    }
616#endif /* LOSCFG_NET_LWIP_SACK */
617
618#if (LOSCFG_POSIX_PIPE_API == 1)
619    if (fd >= PIPE_DEV_FD) {
620        return PipeRead(fd, buff, bytes);
621    }
622#endif
623
624    ssize_t ret = (ssize_t)LOS_NOK;
625    if (fd >= MIN_START_FD && fd < CONFIG_NFILE_DESCRIPTORS) {
626        ret = VfsRead(fd, buff, bytes);
627    }
628
629    return MapToPosixRet(ret);
630}
631#if (LOSCFG_LIBC_NEWLIB == 1)
632FUNC_ALIAS(read, _read, (int fd, void *buff, size_t bytes), ssize_t);
633#endif
634
635ssize_t write(int fd, const void *buff, size_t bytes)
636{
637#ifdef LOSCFG_RANDOM_DEV
638    if (fd == RANDOM_DEV_FD) {
639        errno = EBADF; /* "/dev/random" is readonly */
640        return (ssize_t)LOS_NOK;
641    }
642#endif
643#ifdef LOSCFG_NET_LWIP_SACK
644    if (fd >= CONFIG_NFILE_DESCRIPTORS &&
645        fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) {
646        return send(fd, buff, bytes, 0);
647    }
648#endif /* LOSCFG_NET_LWIP_SACK */
649
650#if (LOSCFG_POSIX_PIPE_API == 1)
651    if (fd >= PIPE_DEV_FD) {
652        return PipeWrite(fd, buff, bytes);
653    }
654#endif
655
656    ssize_t ret = (ssize_t)LOS_NOK;
657    if (fd >= MIN_START_FD && fd < CONFIG_NFILE_DESCRIPTORS) {
658        ret = VfsWrite(fd, buff, bytes);
659    }
660
661    return MapToPosixRet(ret);
662}
663#if (LOSCFG_LIBC_NEWLIB == 1)
664FUNC_ALIAS(write, _write, (int fd, const void *buff, size_t bytes), ssize_t);
665#endif
666
667off_t lseek(int fd, off_t off, int whence)
668{
669    struct File *file;
670    off_t ret = (off_t)LOS_NOK;
671
672    file = VfsAttachFileReady(fd);
673    if (file == NULL) {
674        return ret;
675    }
676
677    if ((file->fFops == NULL) || (file->fFops->lseek == NULL)) {
678        ret = file->fOffset;
679    } else {
680        ret = file->fFops->lseek(file, off, whence);
681    }
682
683    VfsDetachFile(file);
684    return ret;
685}
686#if (LOSCFG_LIBC_NEWLIB == 1)
687FUNC_ALIAS(lseek, _lseek, (int fd, off_t off, int whence), off_t);
688#endif
689
690int stat(const char *path, struct stat *stat)
691{
692    struct MountPoint *mp = NULL;
693    const char *pathInMp = NULL;
694    int ret = (int)LOS_NOK;
695
696    if (VfsPathCheck(path, FALSE) != LOS_OK) {
697        return MapToPosixRet(ret);
698    }
699
700    if (stat == NULL) {
701        VFS_ERRNO_SET(EINVAL);
702        return MapToPosixRet(ret);
703    }
704
705    if (LOS_FsLock() != LOS_OK) {
706        VFS_ERRNO_SET(EAGAIN);
707        return MapToPosixRet(ret);
708    }
709
710    mp = VfsMpFind(path, &pathInMp);
711    if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0')) {
712        VFS_ERRNO_SET(ENOENT);
713        LOS_FsUnlock();
714        return MapToPosixRet(ret);
715    }
716
717    if (mp->mFs->fsFops->stat != NULL) {
718        ret = mp->mFs->fsFops->stat(mp, pathInMp, stat);
719    } else {
720        VFS_ERRNO_SET(ENOTSUP);
721    }
722
723    LOS_FsUnlock();
724    return MapToPosixRet(ret);
725}
726#if (LOSCFG_LIBC_NEWLIB == 1)
727FUNC_ALIAS(stat, _stat, (const char *path, struct stat *stat), int);
728#endif
729
730int statfs(const char *path, struct statfs *buf)
731{
732    struct MountPoint *mp = NULL;
733    const char *pathInMp = NULL;
734    int ret = (int)LOS_NOK;
735
736    if (VfsPathCheck(path, FALSE) != LOS_OK) {
737        return MapToPosixRet(ret);
738    }
739
740    if (buf == NULL) {
741        VFS_ERRNO_SET(EINVAL);
742        return MapToPosixRet(ret);
743    }
744
745    if (LOS_FsLock() != LOS_OK) {
746        VFS_ERRNO_SET(EAGAIN);
747        return MapToPosixRet(ret);
748    }
749
750    mp = VfsMpFind(path, &pathInMp);
751    if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0')) {
752        VFS_ERRNO_SET(ENOENT);
753        LOS_FsUnlock();
754        return MapToPosixRet(ret);
755    }
756
757    if (mp->mFs->fsMops->statfs != NULL) {
758        ret = mp->mFs->fsMops->statfs(pathInMp, buf);
759    } else {
760        VFS_ERRNO_SET(ENOTSUP);
761    }
762
763    LOS_FsUnlock();
764    return MapToPosixRet(ret);
765}
766
767int unlink(const char *path)
768{
769    struct MountPoint *mp = NULL;
770    const char *pathInMp = NULL;
771    int ret = (int)LOS_NOK;
772
773    if (VfsPathCheck(path, FALSE) != LOS_OK) {
774        return MapToPosixRet(ret);
775    }
776
777    if (LOS_FsLock() != LOS_OK) {
778        VFS_ERRNO_SET(EAGAIN);
779        return MapToPosixRet(ret);
780    }
781
782    mp = VfsMpFind(path, &pathInMp);
783    if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0') ||
784        (mp->mFs->fsFops->unlink == NULL)) {
785        VFS_ERRNO_SET(ENOENT);
786        LOS_FsUnlock();
787        return MapToPosixRet(ret);
788    }
789
790    ret = mp->mFs->fsFops->unlink(mp, pathInMp);
791
792    LOS_FsUnlock();
793    return MapToPosixRet(ret);
794}
795#if (LOSCFG_LIBC_NEWLIB == 1)
796FUNC_ALIAS(unlink, _unlink, (const char *path), int);
797#endif
798
799int rename(const char *oldpath, const char *newpath)
800{
801    struct MountPoint *mpOld = NULL;
802    struct MountPoint *mpNew = NULL;
803    const char *pathInMpOld = NULL;
804    const char *pathInMpNew = NULL;
805    int ret = (int)LOS_NOK;
806
807    if (VfsPathCheck(oldpath, FALSE) != LOS_OK) {
808        return MapToPosixRet(ret);
809    }
810    if (VfsPathCheck(newpath, FALSE) != LOS_OK) {
811        return MapToPosixRet(ret);
812    }
813
814    if (LOS_FsLock() != LOS_OK) {
815        VFS_ERRNO_SET(EAGAIN);
816        return MapToPosixRet(ret);
817    }
818
819    mpOld = VfsMpFind(oldpath, &pathInMpOld);
820
821    if (pathInMpOld == NULL) {
822        VFS_ERRNO_SET(EINVAL);
823        LOS_FsUnlock();
824        return MapToPosixRet(ret);
825    }
826
827    if ((mpOld == NULL) || (*pathInMpOld == '\0') ||
828        (mpOld->mFs->fsFops->unlink == NULL)) {
829        VFS_ERRNO_SET(EINVAL);
830        LOS_FsUnlock();
831        return MapToPosixRet(ret);
832    }
833
834    mpNew = VfsMpFind(newpath, &pathInMpNew);
835    if ((mpNew == NULL) || (pathInMpNew == NULL) || (*pathInMpNew == '\0') || (mpNew->mFs->fsFops->unlink == NULL)) {
836        VFS_ERRNO_SET(EINVAL);
837        LOS_FsUnlock();
838        return MapToPosixRet(ret);
839    }
840
841    if (mpOld != mpNew) {
842        VFS_ERRNO_SET(EXDEV);
843        LOS_FsUnlock();
844        return MapToPosixRet(ret);
845    }
846
847    if (mpOld->mFs->fsFops->rename != NULL) {
848        ret = mpOld->mFs->fsFops->rename(mpOld, pathInMpOld, pathInMpNew);
849    } else {
850        VFS_ERRNO_SET(ENOTSUP);
851    }
852
853    LOS_FsUnlock();
854    return MapToPosixRet(ret);
855}
856
857int fsync(int fd)
858{
859    struct File *file;
860    int ret = (int)LOS_NOK;
861
862    file = VfsAttachFileReady(fd);
863    if (file == NULL) {
864        return MapToPosixRet(ret);
865    }
866
867    if (file->fMp->mWriteEnable == FALSE) {
868        VFS_ERRNO_SET(EACCES);
869        VfsDetachFile(file);
870        return MapToPosixRet(ret);
871    }
872
873    if ((file->fFops != NULL) && (file->fFops->sync != NULL)) {
874        ret = file->fFops->sync(file);
875    } else {
876        VFS_ERRNO_SET(ENOTSUP);
877    }
878
879    VfsDetachFile(file);
880    return MapToPosixRet(ret);
881}
882
883DIR *opendir(const char *path)
884{
885    struct MountPoint *mp = NULL;
886    const char *pathInMp = NULL;
887    struct Dir *dir = NULL;
888    UINT32 ret;
889
890    if (VfsPathCheck(path, FALSE) != LOS_OK) {
891        return NULL;
892    }
893
894    dir = (struct Dir *)LOSCFG_FS_MALLOC_HOOK(sizeof(struct Dir));
895    if (dir == NULL) {
896        VFS_ERRNO_SET(ENOMEM);
897        return NULL;
898    }
899
900    if (LOS_FsLock() != LOS_OK) {
901        VFS_ERRNO_SET(EAGAIN);
902        LOSCFG_FS_FREE_HOOK(dir);
903        return NULL;
904    }
905
906    if (g_dirNum >= LOSCFG_MAX_OPEN_DIRS) {
907        VFS_ERRNO_SET(ENFILE);
908        LOS_FsUnlock();
909        LOSCFG_FS_FREE_HOOK(dir);
910        return NULL;
911    }
912
913    mp = VfsMpFind(path, &pathInMp);
914    if ((mp == NULL) || (pathInMp == NULL)) {
915        VFS_ERRNO_SET(ENOENT);
916        LOS_FsUnlock();
917        LOSCFG_FS_FREE_HOOK(dir);
918        return NULL;
919    }
920
921    if (mp->mFs->fsFops->opendir == NULL) {
922        VFS_ERRNO_SET(ENOTSUP);
923        LOS_FsUnlock();
924        LOSCFG_FS_FREE_HOOK(dir);
925        return NULL;
926    }
927
928    dir->dMp = mp;
929    dir->dOffset = 0;
930
931    ret = (UINT32)mp->mFs->fsFops->opendir(dir, pathInMp);
932    if (ret == 0) {
933        mp->mRefs++;
934        g_dirNum++;
935    } else {
936        LOSCFG_FS_FREE_HOOK(dir);
937        dir = NULL;
938    }
939
940    LOS_FsUnlock();
941    return (DIR *)dir;
942}
943
944struct dirent *readdir(DIR *dir)
945{
946    struct dirent *ret = NULL;
947    struct Dir *d = (struct Dir *)dir;
948
949    if ((dir == NULL) || (d->dMp == NULL)) {
950        VFS_ERRNO_SET(EINVAL);
951        return NULL;
952    }
953
954    if (LOS_FsLock() != LOS_OK) {
955        VFS_ERRNO_SET(EAGAIN);
956        return NULL;
957    }
958
959    if ((d->dMp->mFs != NULL) && (d->dMp->mFs->fsFops != NULL) &&
960        (d->dMp->mFs->fsFops->readdir != NULL)) {
961        if (d->dMp->mFs->fsFops->readdir(d, &d->dDent) == 0) {
962            ret = &d->dDent;
963        }
964    } else {
965        VFS_ERRNO_SET(ENOTSUP);
966    }
967
968    LOS_FsUnlock();
969
970    return ret;
971}
972
973int closedir(DIR *dir)
974{
975    struct MountPoint *mp = NULL;
976    int ret = (int)LOS_NOK;
977    struct Dir *d = (struct Dir *)dir;
978
979    if ((d == NULL) || (d->dMp == NULL)) {
980        VFS_ERRNO_SET(EBADF);
981        return MapToPosixRet(ret);
982    }
983
984    mp = d->dMp;
985
986    if (LOS_FsLock() != LOS_OK) {
987        VFS_ERRNO_SET(EAGAIN);
988        return MapToPosixRet(ret);
989    }
990
991    if ((d->dMp->mFs != NULL) && (d->dMp->mFs->fsFops != NULL) &&
992        (d->dMp->mFs->fsFops->closedir != NULL)) {
993        ret = d->dMp->mFs->fsFops->closedir(d);
994    } else {
995        VFS_ERRNO_SET(ENOTSUP);
996    }
997
998    if (ret == 0) {
999        mp->mRefs--;
1000        g_dirNum--;
1001    } else {
1002        VFS_ERRNO_SET(EBADF);
1003    }
1004
1005    LOS_FsUnlock();
1006    LOSCFG_FS_FREE_HOOK(d);
1007    d = NULL;
1008    return MapToPosixRet(ret);
1009}
1010
1011int mkdir(const char *path, mode_t mode)
1012{
1013    struct MountPoint *mp = NULL;
1014    const char *pathInMp = NULL;
1015    int ret = (int)LOS_NOK;
1016    (void)mode;
1017
1018    if (VfsPathCheck(path, FALSE) != LOS_OK) {
1019        return MapToPosixRet(ret);
1020    }
1021
1022    if (LOS_FsLock() != LOS_OK) {
1023        VFS_ERRNO_SET(EAGAIN);
1024        return MapToPosixRet(ret);
1025    }
1026
1027    mp = VfsMpFind(path, &pathInMp);
1028    if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0')) {
1029        VFS_ERRNO_SET(ENOENT);
1030        LOS_FsUnlock();
1031        return MapToPosixRet(ret);
1032    }
1033
1034    if (mp->mFs->fsFops->mkdir != NULL) {
1035        ret = mp->mFs->fsFops->mkdir(mp, pathInMp);
1036    } else {
1037        VFS_ERRNO_SET(ENOTSUP);
1038    }
1039
1040    LOS_FsUnlock();
1041    return MapToPosixRet(ret);
1042}
1043
1044int rmdir(const char *path)
1045{
1046    struct MountPoint *mp = NULL;
1047    const char *pathInMp = NULL;
1048    int ret = (int)LOS_NOK;
1049
1050    if (path == NULL) {
1051        VFS_ERRNO_SET(EINVAL);
1052        return MapToPosixRet(ret);
1053    }
1054
1055    if (LOS_FsLock() != LOS_OK) {
1056        VFS_ERRNO_SET(EAGAIN);
1057        return MapToPosixRet(ret);
1058    }
1059
1060    mp = VfsMpFind(path, &pathInMp);
1061    if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0') ||
1062        (mp->mFs->fsFops->rmdir == NULL)) {
1063        VFS_ERRNO_SET(ENOENT);
1064        LOS_FsUnlock();
1065        return MapToPosixRet(ret);
1066    }
1067
1068    ret = mp->mFs->fsFops->rmdir(mp, pathInMp);
1069
1070    LOS_FsUnlock();
1071    return MapToPosixRet(ret);
1072}
1073
1074int lstat(const char *path, struct stat *buffer)
1075{
1076    return stat(path, buffer);
1077}
1078
1079int fstat(int fd, struct stat *buf)
1080{
1081    struct File *filep;
1082    int ret;
1083    filep = VfsAttachFileReady(fd);
1084    if ((filep == NULL) || (filep->fMp == NULL) || filep->fullPath == NULL) {
1085        return (int)LOS_NOK;
1086    }
1087    ret = stat(filep->fullPath, buf);
1088    VfsDetachFile(filep);
1089    return ret;
1090}
1091#if (LOSCFG_LIBC_NEWLIB == 1)
1092FUNC_ALIAS(fstat, _fstat, (int fd, struct stat *buf), int);
1093#endif
1094
1095int fcntl(int fd, int cmd, ...)
1096{
1097    struct File *filep = NULL;
1098    int ret;
1099    va_list ap;
1100
1101    va_start(ap, cmd);
1102    if (fd < CONFIG_NFILE_DESCRIPTORS) {
1103        filep = VfsAttachFileReady(fd);
1104        ret = VfsVfcntl(filep, cmd, ap);
1105        VfsDetachFile(filep);
1106    } else {
1107#ifndef LOSCFG_NET_LWIP_SACK
1108        ret = -EBADF;
1109#else
1110        int arg = va_arg(ap, int);
1111        ret = lwip_fcntl(fd, (long)cmd, arg);
1112        va_end(ap);
1113        return ret;
1114#endif /* LOSCFG_NET_LWIP_SACK */
1115    }
1116
1117    if (ret < 0) {
1118        VFS_ERRNO_SET(-ret);
1119        ret = (int)LOS_NOK;
1120    }
1121    va_end(ap);
1122    return ret;
1123}
1124
1125int ioctl(int fd, int req, ...)
1126{
1127    int ret;
1128    va_list ap;
1129
1130    va_start(ap, req);
1131    if (fd < CONFIG_NFILE_DESCRIPTORS) {
1132        ret = VfsIoctl(fd, req, ap);
1133    } else {
1134#ifndef LOSCFG_NET_LWIP_SACK
1135        ret = -EBADF;
1136#else
1137        UINTPTR arg = va_arg(ap, UINTPTR);
1138        ret = lwip_ioctl(fd, (long)req, (void *)arg);
1139#endif /* LOSCFG_NET_LWIP_SACK */
1140    }
1141
1142    va_end(ap);
1143    return ret;
1144}
1145
1146ssize_t readv(int fd, const struct iovec *iovBuf, int iovcnt)
1147{
1148    int i;
1149    errno_t ret;
1150    char *buf = NULL;
1151    char *curBuf = NULL;
1152    char *readBuf = NULL;
1153    size_t bufLen = 0;
1154    size_t bytesToRead;
1155    ssize_t totalBytesRead;
1156    size_t totalLen;
1157    const struct iovec *iov = (const struct iovec *)iovBuf;
1158
1159    if ((iov == NULL) || (iovcnt <= 0) || (iovcnt > IOV_MAX_CNT)) {
1160        return (ssize_t)LOS_NOK;
1161    }
1162
1163    for (i = 0; i < iovcnt; ++i) {
1164        if ((SSIZE_MAX - bufLen) < iov[i].iov_len) {
1165            return (ssize_t)LOS_NOK;
1166        }
1167        bufLen += iov[i].iov_len;
1168    }
1169    if (bufLen == 0) {
1170        return (ssize_t)LOS_NOK;
1171    }
1172    totalLen = bufLen * sizeof(char);
1173    buf = (char *)LOSCFG_FS_MALLOC_HOOK(totalLen);
1174    if (buf == NULL) {
1175        return (ssize_t)LOS_NOK;
1176    }
1177
1178    totalBytesRead = read(fd, buf, bufLen);
1179    if ((size_t)totalBytesRead < totalLen) {
1180        totalLen = (size_t)totalBytesRead;
1181    }
1182    curBuf = buf;
1183    for (i = 0; i < iovcnt; ++i) {
1184        readBuf = (char *)iov[i].iov_base;
1185        bytesToRead = iov[i].iov_len;
1186
1187        size_t lenToRead = totalLen < bytesToRead ? totalLen : bytesToRead;
1188        ret = memcpy_s(readBuf, bytesToRead, curBuf, lenToRead);
1189        if (ret != EOK) {
1190            LOSCFG_FS_FREE_HOOK(buf);
1191            return (ssize_t)LOS_NOK;
1192        }
1193        if (totalLen < (size_t)bytesToRead) {
1194            break;
1195        }
1196        curBuf += bytesToRead;
1197        totalLen -= bytesToRead;
1198    }
1199    LOSCFG_FS_FREE_HOOK(buf);
1200    return totalBytesRead;
1201}
1202
1203ssize_t writev(int fd, const struct iovec *iovBuf, int iovcnt)
1204{
1205    int i;
1206    errno_t ret;
1207    char *buf = NULL;
1208    char *curBuf = NULL;
1209    char *writeBuf = NULL;
1210    size_t bufLen = 0;
1211    size_t bytesToWrite;
1212    ssize_t totalBytesWritten;
1213    size_t totalLen;
1214    const struct iovec *iov = iovBuf;
1215
1216    if ((iov == NULL) || (iovcnt <= 0) || (iovcnt > IOV_MAX_CNT)) {
1217        return (ssize_t)LOS_NOK;
1218    }
1219
1220    for (i = 0; i < iovcnt; ++i) {
1221        if ((SSIZE_MAX - bufLen) < iov[i].iov_len) {
1222            VFS_ERRNO_SET(EINVAL);
1223            return (ssize_t)LOS_NOK;
1224        }
1225        bufLen += iov[i].iov_len;
1226    }
1227    if (bufLen == 0) {
1228        return (ssize_t)LOS_NOK;
1229    }
1230    totalLen = bufLen * sizeof(char);
1231    buf = (char *)LOSCFG_FS_MALLOC_HOOK(totalLen);
1232    if (buf == NULL) {
1233        return (ssize_t)LOS_NOK;
1234    }
1235    curBuf = buf;
1236    for (i = 0; i < iovcnt; ++i) {
1237        writeBuf = (char *)iov[i].iov_base;
1238        bytesToWrite = iov[i].iov_len;
1239        if (((ssize_t)totalLen <= 0) || ((ssize_t)bytesToWrite <= 0)) {
1240            continue;
1241        }
1242        ret = memcpy_s(curBuf, totalLen, writeBuf, bytesToWrite);
1243        if (ret != EOK) {
1244            LOSCFG_FS_FREE_HOOK(buf);
1245            return (ssize_t)LOS_NOK;
1246        }
1247        curBuf += bytesToWrite;
1248        totalLen -= bytesToWrite;
1249    }
1250
1251    totalBytesWritten = write(fd, buf, bufLen);
1252    LOSCFG_FS_FREE_HOOK(buf);
1253
1254    return totalBytesWritten;
1255}
1256
1257int remove(const char *filename)
1258{
1259    int ret = unlink(filename);
1260    if (ret == -EISDIR) {
1261        ret = rmdir(filename);
1262    }
1263
1264    return ret;
1265}
1266
1267int access(const char *path, int amode)
1268{
1269    int result;
1270    mode_t mode;
1271    struct stat buf;
1272
1273    result = stat(path, &buf);
1274    if (result != 0) {
1275        return (int)LOS_NOK;
1276    }
1277
1278    mode = buf.st_mode;
1279    if ((unsigned int)amode & R_OK) {
1280        if ((mode & (S_IROTH | S_IRGRP | S_IRUSR)) == 0) {
1281            VFS_ERRNO_SET(EACCES);
1282            return (int)LOS_NOK;
1283        }
1284    }
1285    if ((unsigned int)amode & W_OK) {
1286        if ((mode & (S_IWOTH | S_IWGRP | S_IWUSR)) == 0) {
1287            VFS_ERRNO_SET(EACCES);
1288            return (int)LOS_NOK;
1289        }
1290    }
1291    if ((unsigned int)amode & X_OK) {
1292        if ((mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) {
1293            VFS_ERRNO_SET(EACCES);
1294            return (int)LOS_NOK;
1295        }
1296    }
1297    return 0;
1298}
1299
1300int ftruncate(int fd, off_t length)
1301{
1302    int ret = (int)LOS_NOK;
1303    struct File *file = NULL;
1304
1305    if (length <= 0) {
1306        VFS_ERRNO_SET(EINVAL);
1307        return ret;
1308    }
1309
1310    file = VfsAttachFileReady(fd);
1311    if (file == NULL) {
1312        return ret;
1313    }
1314
1315    if (file->fMp->mWriteEnable == FALSE) {
1316        VFS_ERRNO_SET(EACCES);
1317        VfsDetachFile(file);
1318        return ret;
1319    }
1320
1321    if ((file->fFlags & O_ACCMODE) == O_RDONLY) {
1322        VFS_ERRNO_SET(EACCES);
1323    } else if ((file->fFops != NULL) && (file->fFops->truncate != NULL)) {
1324        ret = file->fFops->truncate(file, length);
1325    } else {
1326        VFS_ERRNO_SET(ENOTSUP);
1327    }
1328
1329    /* else ret will be -1 */
1330    VfsDetachFile(file);
1331    return ret;
1332}
1333
1334ssize_t pread(int fd, void *buff, size_t bytes, off_t off)
1335{
1336    ssize_t ret = (ssize_t)LOS_NOK;
1337    off_t savepos, pos;
1338
1339    if (fd < 0 || fd >= CONFIG_NFILE_DESCRIPTORS) {
1340        return MapToPosixRet((int)ret);
1341    }
1342
1343    if (buff == NULL) {
1344        VFS_ERRNO_SET(EFAULT);
1345        return MapToPosixRet((int)ret);
1346    }
1347
1348    if (bytes == 0) {
1349        return 0;
1350    }
1351
1352    if (LOS_FsLock() != LOS_OK) {
1353        VFS_ERRNO_SET(EAGAIN);
1354        return MapToPosixRet((int)ret);
1355    }
1356
1357    savepos = lseek(fd, 0, SEEK_CUR);
1358    if (savepos == (off_t)-1) {
1359        LOS_FsUnlock();
1360        return MapToPosixRet((int)ret);
1361    }
1362
1363    pos = lseek(fd, off, SEEK_SET);
1364    if (pos == (off_t)-1) {
1365        LOS_FsUnlock();
1366        return MapToPosixRet((int)ret);
1367    }
1368
1369    ret = read(fd, buff, bytes);
1370    pos = lseek(fd, savepos, SEEK_SET);
1371    if ((pos == (off_t)-1) && (ret >= 0)) {
1372        LOS_FsUnlock();
1373        return MapToPosixRet((int)LOS_NOK);
1374    }
1375
1376    LOS_FsUnlock();
1377
1378    return MapToPosixRet((int)ret);
1379}
1380
1381ssize_t pwrite(int fd, const void *buff, size_t bytes, off_t off)
1382{
1383    ssize_t ret = (ssize_t)LOS_NOK;
1384    off_t savepos, pos;
1385
1386    if ((fd < 0) || (fd >= CONFIG_NFILE_DESCRIPTORS)) {
1387        return MapToPosixRet((int)ret);
1388    }
1389
1390    if (buff == NULL) {
1391        VFS_ERRNO_SET(EFAULT);
1392        return MapToPosixRet((int)ret);
1393    }
1394
1395    if (bytes == 0) {
1396        return 0;
1397    }
1398
1399    if (LOS_FsLock() != LOS_OK) {
1400        VFS_ERRNO_SET(EAGAIN);
1401        return MapToPosixRet((int)ret);
1402    }
1403
1404    savepos = lseek(fd, 0, SEEK_CUR);
1405    if (savepos == (off_t)-1) {
1406        LOS_FsUnlock();
1407        return MapToPosixRet((int)ret);
1408    }
1409
1410    pos = lseek(fd, off, SEEK_SET);
1411    if (pos == (off_t)-1) {
1412        LOS_FsUnlock();
1413        return MapToPosixRet((int)ret);
1414    }
1415
1416    ret = write(fd, buff, bytes);
1417    pos = lseek(fd, savepos, SEEK_SET);
1418    if ((pos == (off_t)-1) && (ret >= 0)) {
1419        LOS_FsUnlock();
1420        return MapToPosixRet((int)LOS_NOK);
1421    }
1422
1423    LOS_FsUnlock();
1424
1425    return MapToPosixRet((int)ret);
1426}
1427