1427 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1427 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2022-2023 Huawei Device Co., Ltd. All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without modification,
 | |
|  * are permitted provided that the following conditions are met:
 | |
|  *
 | |
|  * 1. Redistributions of source code must retain the above copyright notice, this list of
 | |
|  *    conditions and the following disclaimer.
 | |
|  *
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 | |
|  *    of conditions and the following disclaimer in the documentation and/or other materials
 | |
|  *    provided with the distribution.
 | |
|  *
 | |
|  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 | |
|  *    to endorse or promote products derived from this software without specific prior written
 | |
|  *    permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
|  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 | |
|  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | |
|  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 | |
|  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | |
|  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | |
|  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 | |
|  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | |
|  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | |
|  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 | |
|  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #define _GNU_SOURCE 1
 | |
| #include "los_fs.h"
 | |
| #include <stdint.h>
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| #include <stdarg.h>
 | |
| #include <stdbool.h>
 | |
| #include <unistd.h>
 | |
| #include <sys/uio.h>
 | |
| #include "errno.h"
 | |
| #include "fcntl.h"
 | |
| #include "los_mux.h"
 | |
| #include "los_debug.h"
 | |
| #include "los_sched.h"
 | |
| #include "limits.h"
 | |
| #include "securec.h"
 | |
| #include "vfs_config.h"
 | |
| #include "vfs_files.h"
 | |
| #include "vfs_maps.h"
 | |
| #include "vfs_mount.h"
 | |
| #include "vfs_operations.h"
 | |
| 
 | |
| #ifdef LOSCFG_NET_LWIP_SACK
 | |
| #include "lwipopts.h"
 | |
| #include "lwip/sockets.h"
 | |
| #define CONFIG_NSOCKET_DESCRIPTORS  LWIP_CONFIG_NUM_SOCKETS
 | |
| #else
 | |
| #define CONFIG_NSOCKET_DESCRIPTORS  0
 | |
| #endif
 | |
| 
 | |
| #ifdef LOSCFG_RANDOM_DEV
 | |
| #include "hks_client.h"
 | |
| #define RANDOM_DEV_FD  CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS
 | |
| #define RANDOM_DEV_PATH  "/dev/random"
 | |
| #endif
 | |
| 
 | |
| #if (LOSCFG_POSIX_PIPE_API == 1)
 | |
| #include "pipe_impl.h"
 | |
| #ifdef LOSCFG_RANDOM_DEV
 | |
| #define PIPE_DEV_FD (RANDOM_DEV_FD + 1)
 | |
| #else
 | |
| #define PIPE_DEV_FD (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)
 | |
| #endif
 | |
| 
 | |
| int PollQueryFd(int fd, struct PollTable *table)
 | |
| {
 | |
|     if (fd >= PIPE_DEV_FD) {
 | |
|         return PipePoll(fd, table);
 | |
|     }
 | |
| 
 | |
|     return -ENODEV;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #define FREE_AND_SET_NULL(ptr) do { \
 | |
|     LOSCFG_FS_FREE_HOOK(ptr);       \
 | |
|     ptr = NULL;                     \
 | |
| } while (0)
 | |
| 
 | |
| #define LOS_FCNTL   (O_NONBLOCK | O_NDELAY | O_APPEND | O_SYNC)
 | |
| #define IOV_MAX_CNT 4
 | |
| 
 | |
| UINT32 g_fsMutex;
 | |
| static UINT32 g_dirNum = 0;
 | |
| 
 | |
| int LOS_FsLock(void)
 | |
| {
 | |
|     if (!OsCheckKernelRunning()) {
 | |
|         return LOS_OK;
 | |
|     }
 | |
|     if (LOS_MuxPend(g_fsMutex, (UINT32)LOSCFG_FS_LOCK_TIMEOUT) != LOS_OK) {
 | |
|         PRINT_ERR("LOS_FsLock failed!");
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     return LOS_OK;
 | |
| }
 | |
| 
 | |
| void LOS_FsUnlock(void)
 | |
| {
 | |
|     if (!OsCheckKernelRunning()) {
 | |
|         return;
 | |
|     }
 | |
|     (void)LOS_MuxPost(g_fsMutex);
 | |
| }
 | |
| 
 | |
| #ifdef LOSCFG_RANDOM_DEV
 | |
| /**
 | |
|  * @brief Get canonical form of a given path based on cwd(Current working directory).
 | |
|  *
 | |
|  * @param cwd Indicates the current working directory.
 | |
|  * @param path Indicates the path to be canonicalization.
 | |
|  * @param buf Indicates the pointer to the buffer where the result will be return.
 | |
|  * @param bufSize Indicates the size of the buffer.
 | |
|  * @return Returns the length of the canonical path.
 | |
|  *
 | |
|  * @attention if path is an absolute path, cwd is ignored. if cwd if not specified, it is assumed to be root('/').
 | |
|  *            if the buffer is not big enough the result will be truncated, but the return value will always be the
 | |
|  *            length of the canonical path.
 | |
|  */
 | |
| static size_t GetCanonicalPath(const char *cwd, const char *path, char *buf, size_t bufSize)
 | |
| {
 | |
|     size_t offset;
 | |
|     if (!path) {
 | |
|         path = "";
 | |
|     }
 | |
| 
 | |
|     if ((!cwd) || (path[0] == '/')) {
 | |
|         cwd = "";
 | |
|     }
 | |
| 
 | |
|     offset = strlen("///") + 1; // three '/' and one '\0'
 | |
|     size_t tmpLen = strlen(cwd) + strlen(path) + offset;
 | |
|     char *tmpBuf = (char *)LOSCFG_FS_MALLOC_HOOK(tmpLen);
 | |
|     if (tmpBuf == NULL) {
 | |
|         return LOS_OK;
 | |
|     }
 | |
| 
 | |
|     if (-1 == sprintf_s(tmpBuf, tmpLen, "/%s/%s/", cwd, path)) {
 | |
|         LOSCFG_FS_FREE_HOOK(tmpBuf);
 | |
|         return LOS_OK;
 | |
|     }
 | |
| 
 | |
|     char *p;
 | |
|     /* replace /./ to / */
 | |
|     offset = strlen("/./") - 1;
 | |
|     while ((p = strstr(tmpBuf, "/./")) != NULL) {
 | |
|         if (EOK != memmove_s(p, tmpLen - (p - tmpBuf), p + offset, tmpLen - (p - tmpBuf) - offset)) {
 | |
|             LOSCFG_FS_FREE_HOOK(tmpBuf);
 | |
|             return LOS_OK;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* replace // to / */
 | |
|     while ((p = strstr(tmpBuf, "//")) != NULL) {
 | |
|         if (EOK != memmove_s(p, tmpLen - (p - tmpBuf), p + 1, tmpLen - (p - tmpBuf) - 1)) {
 | |
|             LOSCFG_FS_FREE_HOOK(tmpBuf);
 | |
|             return LOS_OK;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* handle /../ (e.g., replace /aa/bb/../ to /aa/) */
 | |
|     offset = strlen("/../") - 1;
 | |
|     while ((p = strstr(tmpBuf, "/../")) != NULL) {
 | |
|         char *start = p;
 | |
|         while (start > tmpBuf && *(start - 1) != '/') {
 | |
|             --start;
 | |
|         }
 | |
|         if (EOK != memmove_s(start, tmpLen - (start - tmpBuf), p + offset, tmpLen - (p - tmpBuf) - offset)) {
 | |
|             LOSCFG_FS_FREE_HOOK(tmpBuf);
 | |
|             return LOS_OK;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     size_t totalLen = strlen(tmpBuf);
 | |
|     /* strip the last / */
 | |
|     if (totalLen > 1 && tmpBuf[totalLen - 1] == '/') {
 | |
|         tmpBuf[--totalLen] = 0;
 | |
|     }
 | |
| 
 | |
|     if ((!buf) || (bufSize == 0)) {
 | |
|         LOSCFG_FS_FREE_HOOK(tmpBuf);
 | |
|         return totalLen;
 | |
|     }
 | |
| 
 | |
|     if (EOK != memcpy_s(buf, bufSize, tmpBuf, (((totalLen + 1) > bufSize) ? bufSize : (totalLen + 1)))) {
 | |
|         LOSCFG_FS_FREE_HOOK(tmpBuf);
 | |
|         return LOS_OK;
 | |
|     }
 | |
| 
 | |
|     buf[bufSize - 1] = 0;
 | |
|     LOSCFG_FS_FREE_HOOK(tmpBuf);
 | |
|     return totalLen;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static int VfsPathCheck(const char *path, bool isFile)
 | |
| {
 | |
|     size_t len;
 | |
|     if ((path == NULL) || (path[0] == '\0')) {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     len = strlen(path);
 | |
|     if (len >= PATH_MAX) {
 | |
|         VFS_ERRNO_SET(ENAMETOOLONG);
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     if (isFile && path[len - 1] == '/') {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     return LOS_OK;
 | |
| }
 | |
| 
 | |
| static int VfsOpen(const char *path, int flags)
 | |
| {
 | |
|     size_t len;
 | |
|     struct File *file = NULL;
 | |
|     int fd = -1;
 | |
|     const char *pathInMp = NULL;
 | |
|     struct MountPoint *mp = NULL;
 | |
| 
 | |
|     if (VfsPathCheck(path, TRUE) != LOS_OK) {
 | |
|         return fd;
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return fd;
 | |
|     }
 | |
| 
 | |
|     mp = VfsMpFind(path, &pathInMp);
 | |
|     if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0') ||
 | |
|         (mp->mFs->fsFops == NULL) || (mp->mFs->fsFops->open == NULL)) {
 | |
|         /* path is not in any mountpoint */
 | |
|         VFS_ERRNO_SET(ENOENT);
 | |
|         LOS_FsUnlock();
 | |
|         return fd;
 | |
|     }
 | |
| 
 | |
|     if ((mp->mWriteEnable == FALSE) &&
 | |
|         (flags & (O_CREAT | O_WRONLY | O_RDWR))) {
 | |
|         /* can't create file in read only mp */
 | |
|         VFS_ERRNO_SET(EACCES);
 | |
|         LOS_FsUnlock();
 | |
|         return fd;
 | |
|     }
 | |
| 
 | |
|     file = VfsFileGet();
 | |
|     if (file == NULL) {
 | |
|         VFS_ERRNO_SET(ENFILE);
 | |
|         LOS_FsUnlock();
 | |
|         return fd;
 | |
|     }
 | |
| 
 | |
|     len = strlen(path) + 1;
 | |
|     file->fullPath = LOSCFG_FS_MALLOC_HOOK(len);
 | |
|     if (file->fullPath == NULL) {
 | |
|         VFS_ERRNO_SET(ENOMEM);
 | |
|         VfsFilePut(file);
 | |
|         LOS_FsUnlock();
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
|     (void)strcpy_s((char *)file->fullPath, len, path);
 | |
| 
 | |
|     file->fFlags = (UINT32)flags;
 | |
|     file->fOffset = 0;
 | |
|     file->fData = NULL;
 | |
|     file->fFops = mp->mFs->fsFops;
 | |
|     file->fMp = mp;
 | |
|     file->fOwner = LOS_CurTaskIDGet();
 | |
| 
 | |
|     if (file->fFops->open(file, pathInMp, flags) == 0) {
 | |
|         mp->mRefs++;
 | |
|         fd = FileToFd(file);
 | |
|         file->fStatus = FILE_STATUS_READY; /* file now ready to use */
 | |
|     } else {
 | |
|         LOSCFG_FS_FREE_HOOK((void *)file->fullPath);
 | |
|         VfsFilePut(file);
 | |
|     }
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
|     return fd;
 | |
| }
 | |
| 
 | |
| /* attach to a file and then set new status */
 | |
| 
 | |
| static struct File *VfsAttachFile(int fd, UINT32 status)
 | |
| {
 | |
|     struct File *file = NULL;
 | |
| 
 | |
|     if ((fd < MIN_START_FD) || (fd >= CONFIG_NFILE_DESCRIPTORS)) {
 | |
|         VFS_ERRNO_SET(EBADF);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EFAULT);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     file = FdToFile(fd);
 | |
|     if ((file == NULL) || (file->fMp == NULL)) {
 | |
|         VFS_ERRNO_SET(EBADF);
 | |
|         LOS_FsUnlock();
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (file->fStatus != FILE_STATUS_READY) {
 | |
|         VFS_ERRNO_SET(EBADF);
 | |
|         LOS_FsUnlock();
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     file->fStatus = status;
 | |
|     return file;
 | |
| }
 | |
| 
 | |
| static struct File *VfsAttachFileReady(int fd)
 | |
| {
 | |
|     return VfsAttachFile(fd, FILE_STATUS_READY);
 | |
| }
 | |
| 
 | |
| static struct File *VfsAttachFileWithStatus(int fd, int status)
 | |
| {
 | |
|     return VfsAttachFile(fd, (UINT32)status);
 | |
| }
 | |
| 
 | |
| static void VfsDetachFile(const struct File *file)
 | |
| {
 | |
|     (void)file;
 | |
|     LOS_FsUnlock();
 | |
| }
 | |
| 
 | |
| static int VfsClose(int fd)
 | |
| {
 | |
|     struct File *file = NULL;
 | |
|     int ret = (int)LOS_NOK;
 | |
| 
 | |
|     file = VfsAttachFileWithStatus(fd, FILE_STATUS_CLOSING);
 | |
|     if (file == NULL) {
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     if ((file->fFops != NULL) && (file->fFops->close != NULL)) {
 | |
|         ret = file->fFops->close(file);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     if ((ret == 0) && (file->fMp != NULL)) {
 | |
|         file->fMp->mRefs--;
 | |
|     }
 | |
| 
 | |
|     if (file->fullPath != NULL) {
 | |
|         LOSCFG_FS_FREE_HOOK((void *)file->fullPath);
 | |
|     }
 | |
| 
 | |
|     VfsFilePut(file);
 | |
| 
 | |
|     VfsDetachFile(file);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static ssize_t VfsRead(int fd, char *buff, size_t bytes)
 | |
| {
 | |
|     struct File *file = NULL;
 | |
|     ssize_t ret = (ssize_t)-1;
 | |
| 
 | |
|     if (buff == NULL) {
 | |
|         VFS_ERRNO_SET(EFAULT);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     if (bytes == 0) {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     file = VfsAttachFileReady(fd);
 | |
|     if (file == NULL) {
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     if ((file->fFlags & O_ACCMODE) == O_WRONLY) {
 | |
|         VFS_ERRNO_SET(EACCES);
 | |
|     } else if ((file->fFops != NULL) && (file->fFops->read != NULL)) {
 | |
|         ret = file->fFops->read(file, buff, bytes);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     /* else ret will be -1 */
 | |
|     VfsDetachFile(file);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static ssize_t VfsWrite(int fd, const void *buff, size_t bytes)
 | |
| {
 | |
|     struct File *file = NULL;
 | |
|     ssize_t ret = (ssize_t)LOS_NOK;
 | |
| 
 | |
|     if ((buff == NULL) || (bytes == 0)) {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     file = VfsAttachFileReady(fd);
 | |
|     if (file == NULL) {
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     if ((file->fFlags & O_ACCMODE) == O_RDONLY) {
 | |
|         VFS_ERRNO_SET(EACCES);
 | |
|     } else if ((file->fFops != NULL) && (file->fFops->write != NULL)) {
 | |
|         ret = file->fFops->write(file, buff, bytes);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     /* else ret will be -1 */
 | |
|     VfsDetachFile(file);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static int VfsIoctl(int fd, int func, va_list ap)
 | |
| {
 | |
|     unsigned long arg;
 | |
|     struct File *file = NULL;
 | |
|     int ret = (int)LOS_NOK;
 | |
| 
 | |
|     arg = va_arg(ap, unsigned long);
 | |
|     file = VfsAttachFileReady(fd);
 | |
|     if (file == NULL) {
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     if ((file->fFops != NULL) && (file->fFops->ioctl != NULL)) {
 | |
|         ret = file->fFops->ioctl(file, func, arg);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     VfsDetachFile(file);
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static int VfsVfcntl(struct File *filep, int cmd, va_list ap)
 | |
| {
 | |
|     int ret;
 | |
|     UINT32 flags;
 | |
| 
 | |
|     if ((filep == NULL) || (filep->fFops == NULL)) {
 | |
|         return -EBADF;
 | |
|     }
 | |
| 
 | |
|     if (cmd == F_GETFL) {
 | |
|         ret = (int)(filep->fFlags);
 | |
|     } else if (cmd == F_SETFL) {
 | |
|         flags = (UINT32)va_arg(ap, int);
 | |
|         flags &= LOS_FCNTL;
 | |
|         filep->fFlags &= ~LOS_FCNTL;
 | |
|         filep->fFlags |= flags;
 | |
|         ret = LOS_OK;
 | |
|     } else {
 | |
|         ret = -ENOSYS;
 | |
|     }
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| static int MapToPosixRet(int ret)
 | |
| {
 | |
|     return ((ret) < 0 ? -1 : (ret));
 | |
| }
 | |
| 
 | |
| /* POSIX interface */
 | |
| int open(const char *path, int flags, ...)
 | |
| {
 | |
|     if (path == NULL) {
 | |
|         errno = EINVAL;
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
| #ifdef LOSCFG_RANDOM_DEV
 | |
|     unsigned flagMask = O_RDONLY | O_WRONLY | O_RDWR | O_APPEND | O_CREAT | O_LARGEFILE \
 | |
|                         | O_TRUNC | O_EXCL | O_DIRECTORY;
 | |
|     if ((unsigned)flags & ~flagMask) {
 | |
|         errno = EINVAL;
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     size_t pathLen = strlen(path) + 1;
 | |
|     if ((unsigned)pathLen > PATH_MAX) {
 | |
|         errno = EINVAL;
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     char *canonicalPath = (char *)LOSCFG_FS_MALLOC_HOOK(pathLen);
 | |
|     if (!canonicalPath) {
 | |
|         errno = ENOMEM;
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
|     if (GetCanonicalPath(NULL, path, canonicalPath, pathLen) == 0) {
 | |
|         FREE_AND_SET_NULL(canonicalPath);
 | |
|         errno = ENOMEM;
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     if (strcmp(canonicalPath, RANDOM_DEV_PATH) == 0) {
 | |
|         FREE_AND_SET_NULL(canonicalPath);
 | |
|         if ((O_ACCMODE & (unsigned)flags) != O_RDONLY) {
 | |
|             errno = EPERM;
 | |
|             return (int)LOS_NOK;
 | |
|         }
 | |
|         if ((unsigned)flags & O_DIRECTORY) {
 | |
|             errno = ENOTDIR;
 | |
|             return (int)LOS_NOK;
 | |
|         }
 | |
|         return RANDOM_DEV_FD;
 | |
|     }
 | |
|     if ((strcmp(canonicalPath, "/") == 0) ||
 | |
|         (strcmp(canonicalPath, "/dev") == 0)) {
 | |
|         FREE_AND_SET_NULL(canonicalPath);
 | |
|         if ((unsigned)flags & O_DIRECTORY) {
 | |
|             errno = EPERM;
 | |
|             return (int)LOS_NOK;
 | |
|         }
 | |
|         errno = EISDIR;
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
|     FREE_AND_SET_NULL(canonicalPath);
 | |
| #endif
 | |
| #if (LOSCFG_POSIX_PIPE_API == 1)
 | |
|     if (!strncmp(path, PIPE_DEV_PATH, strlen(PIPE_DEV_PATH))) {
 | |
|         return PipeOpen(path, flags, PIPE_DEV_FD);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     int ret = VfsOpen(path, flags);
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| #if (LOSCFG_LIBC_NEWLIB == 1)
 | |
| FUNC_ALIAS(open, _open, (const char *path, int flags, ...), int);
 | |
| #endif
 | |
| 
 | |
| int close(int fd)
 | |
| {
 | |
| #ifdef LOSCFG_RANDOM_DEV
 | |
|     if (fd == RANDOM_DEV_FD) {
 | |
|         return LOS_OK;
 | |
|     }
 | |
| #endif
 | |
| #ifdef LOSCFG_NET_LWIP_SACK
 | |
|     if (fd >= CONFIG_NFILE_DESCRIPTORS && fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) {
 | |
|         return closesocket(fd);
 | |
|     }
 | |
| #endif /* LOSCFG_NET_LWIP_SACK */
 | |
| #if (LOSCFG_POSIX_PIPE_API == 1)
 | |
|     if (fd >= PIPE_DEV_FD) {
 | |
|         return PipeClose(fd);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     int ret = (int)LOS_NOK;
 | |
|     if (fd >= MIN_START_FD && fd < CONFIG_NFILE_DESCRIPTORS) {
 | |
|         ret = VfsClose(fd);
 | |
|     }
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| #if (LOSCFG_LIBC_NEWLIB == 1)
 | |
| FUNC_ALIAS(close, _close, (int fd), int);
 | |
| #endif
 | |
| 
 | |
| ssize_t read(int fd, void *buff, size_t bytes)
 | |
| {
 | |
| #ifdef LOSCFG_RANDOM_DEV
 | |
|     if (fd == RANDOM_DEV_FD) {
 | |
|         if (nbyte == 0) {
 | |
|             return FS_SUCCESS;
 | |
|         }
 | |
|         if (buf == NULL) {
 | |
|             errno = EINVAL;
 | |
|             return FS_FAILURE;
 | |
|         }
 | |
|         if (nbyte > 1024) { /* 1024, max random_size */
 | |
|             nbyte = 1024; /* hks_generate_random: random_size must <= 1024 */
 | |
|         }
 | |
|         struct hks_blob key = {HKS_BLOB_TYPE_RAW, (uint8_t *)buf, nbyte};
 | |
|         if (hks_generate_random(&key) != 0) {
 | |
|             errno = EIO;
 | |
|             return FS_FAILURE;
 | |
|         }
 | |
|         return (ssize_t)nbyte;
 | |
|     }
 | |
| #endif
 | |
| #ifdef LOSCFG_NET_LWIP_SACK
 | |
|     if (fd >= CONFIG_NFILE_DESCRIPTORS && fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) {
 | |
|         return recv(fd, buff, bytes, 0);
 | |
|     }
 | |
| #endif /* LOSCFG_NET_LWIP_SACK */
 | |
| 
 | |
| #if (LOSCFG_POSIX_PIPE_API == 1)
 | |
|     if (fd >= PIPE_DEV_FD) {
 | |
|         return PipeRead(fd, buff, bytes);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     ssize_t ret = (ssize_t)LOS_NOK;
 | |
|     if (fd >= MIN_START_FD && fd < CONFIG_NFILE_DESCRIPTORS) {
 | |
|         ret = VfsRead(fd, buff, bytes);
 | |
|     }
 | |
| 
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| #if (LOSCFG_LIBC_NEWLIB == 1)
 | |
| FUNC_ALIAS(read, _read, (int fd, void *buff, size_t bytes), ssize_t);
 | |
| #endif
 | |
| 
 | |
| ssize_t write(int fd, const void *buff, size_t bytes)
 | |
| {
 | |
| #ifdef LOSCFG_RANDOM_DEV
 | |
|     if (fd == RANDOM_DEV_FD) {
 | |
|         errno = EBADF; /* "/dev/random" is readonly */
 | |
|         return (ssize_t)LOS_NOK;
 | |
|     }
 | |
| #endif
 | |
| #ifdef LOSCFG_NET_LWIP_SACK
 | |
|     if (fd >= CONFIG_NFILE_DESCRIPTORS &&
 | |
|         fd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS)) {
 | |
|         return send(fd, buff, bytes, 0);
 | |
|     }
 | |
| #endif /* LOSCFG_NET_LWIP_SACK */
 | |
| 
 | |
| #if (LOSCFG_POSIX_PIPE_API == 1)
 | |
|     if (fd >= PIPE_DEV_FD) {
 | |
|         return PipeWrite(fd, buff, bytes);
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     ssize_t ret = (ssize_t)LOS_NOK;
 | |
|     if (fd >= MIN_START_FD && fd < CONFIG_NFILE_DESCRIPTORS) {
 | |
|         ret = VfsWrite(fd, buff, bytes);
 | |
|     }
 | |
| 
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| #if (LOSCFG_LIBC_NEWLIB == 1)
 | |
| FUNC_ALIAS(write, _write, (int fd, const void *buff, size_t bytes), ssize_t);
 | |
| #endif
 | |
| 
 | |
| off_t lseek(int fd, off_t off, int whence)
 | |
| {
 | |
|     struct File *file;
 | |
|     off_t ret = (off_t)LOS_NOK;
 | |
| 
 | |
|     file = VfsAttachFileReady(fd);
 | |
|     if (file == NULL) {
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     if ((file->fFops == NULL) || (file->fFops->lseek == NULL)) {
 | |
|         ret = file->fOffset;
 | |
|     } else {
 | |
|         ret = file->fFops->lseek(file, off, whence);
 | |
|     }
 | |
| 
 | |
|     VfsDetachFile(file);
 | |
|     return ret;
 | |
| }
 | |
| #if (LOSCFG_LIBC_NEWLIB == 1)
 | |
| FUNC_ALIAS(lseek, _lseek, (int fd, off_t off, int whence), off_t);
 | |
| #endif
 | |
| 
 | |
| int stat(const char *path, struct stat *stat)
 | |
| {
 | |
|     struct MountPoint *mp = NULL;
 | |
|     const char *pathInMp = NULL;
 | |
|     int ret = (int)LOS_NOK;
 | |
| 
 | |
|     if (VfsPathCheck(path, FALSE) != LOS_OK) {
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (stat == NULL) {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     mp = VfsMpFind(path, &pathInMp);
 | |
|     if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0')) {
 | |
|         VFS_ERRNO_SET(ENOENT);
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (mp->mFs->fsFops->stat != NULL) {
 | |
|         ret = mp->mFs->fsFops->stat(mp, pathInMp, stat);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| #if (LOSCFG_LIBC_NEWLIB == 1)
 | |
| FUNC_ALIAS(stat, _stat, (const char *path, struct stat *stat), int);
 | |
| #endif
 | |
| 
 | |
| int statfs(const char *path, struct statfs *buf)
 | |
| {
 | |
|     struct MountPoint *mp = NULL;
 | |
|     const char *pathInMp = NULL;
 | |
|     int ret = (int)LOS_NOK;
 | |
| 
 | |
|     if (VfsPathCheck(path, FALSE) != LOS_OK) {
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (buf == NULL) {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     mp = VfsMpFind(path, &pathInMp);
 | |
|     if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0')) {
 | |
|         VFS_ERRNO_SET(ENOENT);
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (mp->mFs->fsMops->statfs != NULL) {
 | |
|         ret = mp->mFs->fsMops->statfs(pathInMp, buf);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| 
 | |
| int unlink(const char *path)
 | |
| {
 | |
|     struct MountPoint *mp = NULL;
 | |
|     const char *pathInMp = NULL;
 | |
|     int ret = (int)LOS_NOK;
 | |
| 
 | |
|     if (VfsPathCheck(path, FALSE) != LOS_OK) {
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     mp = VfsMpFind(path, &pathInMp);
 | |
|     if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0') ||
 | |
|         (mp->mFs->fsFops->unlink == NULL)) {
 | |
|         VFS_ERRNO_SET(ENOENT);
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     ret = mp->mFs->fsFops->unlink(mp, pathInMp);
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| #if (LOSCFG_LIBC_NEWLIB == 1)
 | |
| FUNC_ALIAS(unlink, _unlink, (const char *path), int);
 | |
| #endif
 | |
| 
 | |
| int rename(const char *oldpath, const char *newpath)
 | |
| {
 | |
|     struct MountPoint *mpOld = NULL;
 | |
|     struct MountPoint *mpNew = NULL;
 | |
|     const char *pathInMpOld = NULL;
 | |
|     const char *pathInMpNew = NULL;
 | |
|     int ret = (int)LOS_NOK;
 | |
| 
 | |
|     if (VfsPathCheck(oldpath, FALSE) != LOS_OK) {
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
|     if (VfsPathCheck(newpath, FALSE) != LOS_OK) {
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     mpOld = VfsMpFind(oldpath, &pathInMpOld);
 | |
| 
 | |
|     if (pathInMpOld == NULL) {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if ((mpOld == NULL) || (*pathInMpOld == '\0') ||
 | |
|         (mpOld->mFs->fsFops->unlink == NULL)) {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     mpNew = VfsMpFind(newpath, &pathInMpNew);
 | |
|     if ((mpNew == NULL) || (pathInMpNew == NULL) || (*pathInMpNew == '\0') || (mpNew->mFs->fsFops->unlink == NULL)) {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (mpOld != mpNew) {
 | |
|         VFS_ERRNO_SET(EXDEV);
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (mpOld->mFs->fsFops->rename != NULL) {
 | |
|         ret = mpOld->mFs->fsFops->rename(mpOld, pathInMpOld, pathInMpNew);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| 
 | |
| int fsync(int fd)
 | |
| {
 | |
|     struct File *file;
 | |
|     int ret = (int)LOS_NOK;
 | |
| 
 | |
|     file = VfsAttachFileReady(fd);
 | |
|     if (file == NULL) {
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (file->fMp->mWriteEnable == FALSE) {
 | |
|         VFS_ERRNO_SET(EACCES);
 | |
|         VfsDetachFile(file);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if ((file->fFops != NULL) && (file->fFops->sync != NULL)) {
 | |
|         ret = file->fFops->sync(file);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     VfsDetachFile(file);
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| 
 | |
| DIR *opendir(const char *path)
 | |
| {
 | |
|     struct MountPoint *mp = NULL;
 | |
|     const char *pathInMp = NULL;
 | |
|     struct Dir *dir = NULL;
 | |
|     UINT32 ret;
 | |
| 
 | |
|     if (VfsPathCheck(path, FALSE) != LOS_OK) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     dir = (struct Dir *)LOSCFG_FS_MALLOC_HOOK(sizeof(struct Dir));
 | |
|     if (dir == NULL) {
 | |
|         VFS_ERRNO_SET(ENOMEM);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         LOSCFG_FS_FREE_HOOK(dir);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (g_dirNum >= LOSCFG_MAX_OPEN_DIRS) {
 | |
|         VFS_ERRNO_SET(ENFILE);
 | |
|         LOS_FsUnlock();
 | |
|         LOSCFG_FS_FREE_HOOK(dir);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     mp = VfsMpFind(path, &pathInMp);
 | |
|     if ((mp == NULL) || (pathInMp == NULL)) {
 | |
|         VFS_ERRNO_SET(ENOENT);
 | |
|         LOS_FsUnlock();
 | |
|         LOSCFG_FS_FREE_HOOK(dir);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (mp->mFs->fsFops->opendir == NULL) {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|         LOS_FsUnlock();
 | |
|         LOSCFG_FS_FREE_HOOK(dir);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     dir->dMp = mp;
 | |
|     dir->dOffset = 0;
 | |
| 
 | |
|     ret = (UINT32)mp->mFs->fsFops->opendir(dir, pathInMp);
 | |
|     if (ret == 0) {
 | |
|         mp->mRefs++;
 | |
|         g_dirNum++;
 | |
|     } else {
 | |
|         LOSCFG_FS_FREE_HOOK(dir);
 | |
|         dir = NULL;
 | |
|     }
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
|     return (DIR *)dir;
 | |
| }
 | |
| 
 | |
| struct dirent *readdir(DIR *dir)
 | |
| {
 | |
|     struct dirent *ret = NULL;
 | |
|     struct Dir *d = (struct Dir *)dir;
 | |
| 
 | |
|     if ((dir == NULL) || (d->dMp == NULL)) {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     if ((d->dMp->mFs != NULL) && (d->dMp->mFs->fsFops != NULL) &&
 | |
|         (d->dMp->mFs->fsFops->readdir != NULL)) {
 | |
|         if (d->dMp->mFs->fsFops->readdir(d, &d->dDent) == 0) {
 | |
|             ret = &d->dDent;
 | |
|         }
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int closedir(DIR *dir)
 | |
| {
 | |
|     struct MountPoint *mp = NULL;
 | |
|     int ret = (int)LOS_NOK;
 | |
|     struct Dir *d = (struct Dir *)dir;
 | |
| 
 | |
|     if ((d == NULL) || (d->dMp == NULL)) {
 | |
|         VFS_ERRNO_SET(EBADF);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     mp = d->dMp;
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if ((d->dMp->mFs != NULL) && (d->dMp->mFs->fsFops != NULL) &&
 | |
|         (d->dMp->mFs->fsFops->closedir != NULL)) {
 | |
|         ret = d->dMp->mFs->fsFops->closedir(d);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     if (ret == 0) {
 | |
|         mp->mRefs--;
 | |
|         g_dirNum--;
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(EBADF);
 | |
|     }
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
|     LOSCFG_FS_FREE_HOOK(d);
 | |
|     d = NULL;
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| 
 | |
| int mkdir(const char *path, mode_t mode)
 | |
| {
 | |
|     struct MountPoint *mp = NULL;
 | |
|     const char *pathInMp = NULL;
 | |
|     int ret = (int)LOS_NOK;
 | |
|     (void)mode;
 | |
| 
 | |
|     if (VfsPathCheck(path, FALSE) != LOS_OK) {
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     mp = VfsMpFind(path, &pathInMp);
 | |
|     if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0')) {
 | |
|         VFS_ERRNO_SET(ENOENT);
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (mp->mFs->fsFops->mkdir != NULL) {
 | |
|         ret = mp->mFs->fsFops->mkdir(mp, pathInMp);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| 
 | |
| int rmdir(const char *path)
 | |
| {
 | |
|     struct MountPoint *mp = NULL;
 | |
|     const char *pathInMp = NULL;
 | |
|     int ret = (int)LOS_NOK;
 | |
| 
 | |
|     if (path == NULL) {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     mp = VfsMpFind(path, &pathInMp);
 | |
|     if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0') ||
 | |
|         (mp->mFs->fsFops->rmdir == NULL)) {
 | |
|         VFS_ERRNO_SET(ENOENT);
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet(ret);
 | |
|     }
 | |
| 
 | |
|     ret = mp->mFs->fsFops->rmdir(mp, pathInMp);
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
|     return MapToPosixRet(ret);
 | |
| }
 | |
| 
 | |
| int lstat(const char *path, struct stat *buffer)
 | |
| {
 | |
|     return stat(path, buffer);
 | |
| }
 | |
| 
 | |
| int fstat(int fd, struct stat *buf)
 | |
| {
 | |
|     struct File *filep;
 | |
|     int ret;
 | |
|     filep = VfsAttachFileReady(fd);
 | |
|     if ((filep == NULL) || (filep->fMp == NULL) || filep->fullPath == NULL) {
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
|     ret = stat(filep->fullPath, buf);
 | |
|     VfsDetachFile(filep);
 | |
|     return ret;
 | |
| }
 | |
| #if (LOSCFG_LIBC_NEWLIB == 1)
 | |
| FUNC_ALIAS(fstat, _fstat, (int fd, struct stat *buf), int);
 | |
| #endif
 | |
| 
 | |
| int fcntl(int fd, int cmd, ...)
 | |
| {
 | |
|     struct File *filep = NULL;
 | |
|     int ret;
 | |
|     va_list ap;
 | |
| 
 | |
|     va_start(ap, cmd);
 | |
|     if (fd < CONFIG_NFILE_DESCRIPTORS) {
 | |
|         filep = VfsAttachFileReady(fd);
 | |
|         ret = VfsVfcntl(filep, cmd, ap);
 | |
|         VfsDetachFile(filep);
 | |
|     } else {
 | |
| #ifndef LOSCFG_NET_LWIP_SACK
 | |
|         ret = -EBADF;
 | |
| #else
 | |
|         int arg = va_arg(ap, int);
 | |
|         ret = lwip_fcntl(fd, (long)cmd, arg);
 | |
|         va_end(ap);
 | |
|         return ret;
 | |
| #endif /* LOSCFG_NET_LWIP_SACK */
 | |
|     }
 | |
| 
 | |
|     if (ret < 0) {
 | |
|         VFS_ERRNO_SET(-ret);
 | |
|         ret = (int)LOS_NOK;
 | |
|     }
 | |
|     va_end(ap);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int ioctl(int fd, int req, ...)
 | |
| {
 | |
|     int ret;
 | |
|     va_list ap;
 | |
| 
 | |
|     va_start(ap, req);
 | |
|     if (fd < CONFIG_NFILE_DESCRIPTORS) {
 | |
|         ret = VfsIoctl(fd, req, ap);
 | |
|     } else {
 | |
| #ifndef LOSCFG_NET_LWIP_SACK
 | |
|         ret = -EBADF;
 | |
| #else
 | |
|         UINTPTR arg = va_arg(ap, UINTPTR);
 | |
|         ret = lwip_ioctl(fd, (long)req, (void *)arg);
 | |
| #endif /* LOSCFG_NET_LWIP_SACK */
 | |
|     }
 | |
| 
 | |
|     va_end(ap);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| ssize_t readv(int fd, const struct iovec *iovBuf, int iovcnt)
 | |
| {
 | |
|     int i;
 | |
|     errno_t ret;
 | |
|     char *buf = NULL;
 | |
|     char *curBuf = NULL;
 | |
|     char *readBuf = NULL;
 | |
|     size_t bufLen = 0;
 | |
|     size_t bytesToRead;
 | |
|     ssize_t totalBytesRead;
 | |
|     size_t totalLen;
 | |
|     const struct iovec *iov = (const struct iovec *)iovBuf;
 | |
| 
 | |
|     if ((iov == NULL) || (iovcnt <= 0) || (iovcnt > IOV_MAX_CNT)) {
 | |
|         return (ssize_t)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < iovcnt; ++i) {
 | |
|         if ((SSIZE_MAX - bufLen) < iov[i].iov_len) {
 | |
|             return (ssize_t)LOS_NOK;
 | |
|         }
 | |
|         bufLen += iov[i].iov_len;
 | |
|     }
 | |
|     if (bufLen == 0) {
 | |
|         return (ssize_t)LOS_NOK;
 | |
|     }
 | |
|     totalLen = bufLen * sizeof(char);
 | |
|     buf = (char *)LOSCFG_FS_MALLOC_HOOK(totalLen);
 | |
|     if (buf == NULL) {
 | |
|         return (ssize_t)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     totalBytesRead = read(fd, buf, bufLen);
 | |
|     if ((size_t)totalBytesRead < totalLen) {
 | |
|         totalLen = (size_t)totalBytesRead;
 | |
|     }
 | |
|     curBuf = buf;
 | |
|     for (i = 0; i < iovcnt; ++i) {
 | |
|         readBuf = (char *)iov[i].iov_base;
 | |
|         bytesToRead = iov[i].iov_len;
 | |
| 
 | |
|         size_t lenToRead = totalLen < bytesToRead ? totalLen : bytesToRead;
 | |
|         ret = memcpy_s(readBuf, bytesToRead, curBuf, lenToRead);
 | |
|         if (ret != EOK) {
 | |
|             LOSCFG_FS_FREE_HOOK(buf);
 | |
|             return (ssize_t)LOS_NOK;
 | |
|         }
 | |
|         if (totalLen < (size_t)bytesToRead) {
 | |
|             break;
 | |
|         }
 | |
|         curBuf += bytesToRead;
 | |
|         totalLen -= bytesToRead;
 | |
|     }
 | |
|     LOSCFG_FS_FREE_HOOK(buf);
 | |
|     return totalBytesRead;
 | |
| }
 | |
| 
 | |
| ssize_t writev(int fd, const struct iovec *iovBuf, int iovcnt)
 | |
| {
 | |
|     int i;
 | |
|     errno_t ret;
 | |
|     char *buf = NULL;
 | |
|     char *curBuf = NULL;
 | |
|     char *writeBuf = NULL;
 | |
|     size_t bufLen = 0;
 | |
|     size_t bytesToWrite;
 | |
|     ssize_t totalBytesWritten;
 | |
|     size_t totalLen;
 | |
|     const struct iovec *iov = iovBuf;
 | |
| 
 | |
|     if ((iov == NULL) || (iovcnt <= 0) || (iovcnt > IOV_MAX_CNT)) {
 | |
|         return (ssize_t)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < iovcnt; ++i) {
 | |
|         if ((SSIZE_MAX - bufLen) < iov[i].iov_len) {
 | |
|             VFS_ERRNO_SET(EINVAL);
 | |
|             return (ssize_t)LOS_NOK;
 | |
|         }
 | |
|         bufLen += iov[i].iov_len;
 | |
|     }
 | |
|     if (bufLen == 0) {
 | |
|         return (ssize_t)LOS_NOK;
 | |
|     }
 | |
|     totalLen = bufLen * sizeof(char);
 | |
|     buf = (char *)LOSCFG_FS_MALLOC_HOOK(totalLen);
 | |
|     if (buf == NULL) {
 | |
|         return (ssize_t)LOS_NOK;
 | |
|     }
 | |
|     curBuf = buf;
 | |
|     for (i = 0; i < iovcnt; ++i) {
 | |
|         writeBuf = (char *)iov[i].iov_base;
 | |
|         bytesToWrite = iov[i].iov_len;
 | |
|         if (((ssize_t)totalLen <= 0) || ((ssize_t)bytesToWrite <= 0)) {
 | |
|             continue;
 | |
|         }
 | |
|         ret = memcpy_s(curBuf, totalLen, writeBuf, bytesToWrite);
 | |
|         if (ret != EOK) {
 | |
|             LOSCFG_FS_FREE_HOOK(buf);
 | |
|             return (ssize_t)LOS_NOK;
 | |
|         }
 | |
|         curBuf += bytesToWrite;
 | |
|         totalLen -= bytesToWrite;
 | |
|     }
 | |
| 
 | |
|     totalBytesWritten = write(fd, buf, bufLen);
 | |
|     LOSCFG_FS_FREE_HOOK(buf);
 | |
| 
 | |
|     return totalBytesWritten;
 | |
| }
 | |
| 
 | |
| int remove(const char *filename)
 | |
| {
 | |
|     int ret = unlink(filename);
 | |
|     if (ret == -EISDIR) {
 | |
|         ret = rmdir(filename);
 | |
|     }
 | |
| 
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| int access(const char *path, int amode)
 | |
| {
 | |
|     int result;
 | |
|     mode_t mode;
 | |
|     struct stat buf;
 | |
| 
 | |
|     result = stat(path, &buf);
 | |
|     if (result != 0) {
 | |
|         return (int)LOS_NOK;
 | |
|     }
 | |
| 
 | |
|     mode = buf.st_mode;
 | |
|     if ((unsigned int)amode & R_OK) {
 | |
|         if ((mode & (S_IROTH | S_IRGRP | S_IRUSR)) == 0) {
 | |
|             VFS_ERRNO_SET(EACCES);
 | |
|             return (int)LOS_NOK;
 | |
|         }
 | |
|     }
 | |
|     if ((unsigned int)amode & W_OK) {
 | |
|         if ((mode & (S_IWOTH | S_IWGRP | S_IWUSR)) == 0) {
 | |
|             VFS_ERRNO_SET(EACCES);
 | |
|             return (int)LOS_NOK;
 | |
|         }
 | |
|     }
 | |
|     if ((unsigned int)amode & X_OK) {
 | |
|         if ((mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) {
 | |
|             VFS_ERRNO_SET(EACCES);
 | |
|             return (int)LOS_NOK;
 | |
|         }
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int ftruncate(int fd, off_t length)
 | |
| {
 | |
|     int ret = (int)LOS_NOK;
 | |
|     struct File *file = NULL;
 | |
| 
 | |
|     if (length <= 0) {
 | |
|         VFS_ERRNO_SET(EINVAL);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     file = VfsAttachFileReady(fd);
 | |
|     if (file == NULL) {
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     if (file->fMp->mWriteEnable == FALSE) {
 | |
|         VFS_ERRNO_SET(EACCES);
 | |
|         VfsDetachFile(file);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     if ((file->fFlags & O_ACCMODE) == O_RDONLY) {
 | |
|         VFS_ERRNO_SET(EACCES);
 | |
|     } else if ((file->fFops != NULL) && (file->fFops->truncate != NULL)) {
 | |
|         ret = file->fFops->truncate(file, length);
 | |
|     } else {
 | |
|         VFS_ERRNO_SET(ENOTSUP);
 | |
|     }
 | |
| 
 | |
|     /* else ret will be -1 */
 | |
|     VfsDetachFile(file);
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| ssize_t pread(int fd, void *buff, size_t bytes, off_t off)
 | |
| {
 | |
|     ssize_t ret = (ssize_t)LOS_NOK;
 | |
|     off_t savepos, pos;
 | |
| 
 | |
|     if (fd < 0 || fd >= CONFIG_NFILE_DESCRIPTORS) {
 | |
|         return MapToPosixRet((int)ret);
 | |
|     }
 | |
| 
 | |
|     if (buff == NULL) {
 | |
|         VFS_ERRNO_SET(EFAULT);
 | |
|         return MapToPosixRet((int)ret);
 | |
|     }
 | |
| 
 | |
|     if (bytes == 0) {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return MapToPosixRet((int)ret);
 | |
|     }
 | |
| 
 | |
|     savepos = lseek(fd, 0, SEEK_CUR);
 | |
|     if (savepos == (off_t)-1) {
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet((int)ret);
 | |
|     }
 | |
| 
 | |
|     pos = lseek(fd, off, SEEK_SET);
 | |
|     if (pos == (off_t)-1) {
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet((int)ret);
 | |
|     }
 | |
| 
 | |
|     ret = read(fd, buff, bytes);
 | |
|     pos = lseek(fd, savepos, SEEK_SET);
 | |
|     if ((pos == (off_t)-1) && (ret >= 0)) {
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet((int)LOS_NOK);
 | |
|     }
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
| 
 | |
|     return MapToPosixRet((int)ret);
 | |
| }
 | |
| 
 | |
| ssize_t pwrite(int fd, const void *buff, size_t bytes, off_t off)
 | |
| {
 | |
|     ssize_t ret = (ssize_t)LOS_NOK;
 | |
|     off_t savepos, pos;
 | |
| 
 | |
|     if ((fd < 0) || (fd >= CONFIG_NFILE_DESCRIPTORS)) {
 | |
|         return MapToPosixRet((int)ret);
 | |
|     }
 | |
| 
 | |
|     if (buff == NULL) {
 | |
|         VFS_ERRNO_SET(EFAULT);
 | |
|         return MapToPosixRet((int)ret);
 | |
|     }
 | |
| 
 | |
|     if (bytes == 0) {
 | |
|         return 0;
 | |
|     }
 | |
| 
 | |
|     if (LOS_FsLock() != LOS_OK) {
 | |
|         VFS_ERRNO_SET(EAGAIN);
 | |
|         return MapToPosixRet((int)ret);
 | |
|     }
 | |
| 
 | |
|     savepos = lseek(fd, 0, SEEK_CUR);
 | |
|     if (savepos == (off_t)-1) {
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet((int)ret);
 | |
|     }
 | |
| 
 | |
|     pos = lseek(fd, off, SEEK_SET);
 | |
|     if (pos == (off_t)-1) {
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet((int)ret);
 | |
|     }
 | |
| 
 | |
|     ret = write(fd, buff, bytes);
 | |
|     pos = lseek(fd, savepos, SEEK_SET);
 | |
|     if ((pos == (off_t)-1) && (ret >= 0)) {
 | |
|         LOS_FsUnlock();
 | |
|         return MapToPosixRet((int)LOS_NOK);
 | |
|     }
 | |
| 
 | |
|     LOS_FsUnlock();
 | |
| 
 | |
|     return MapToPosixRet((int)ret);
 | |
| }
 |