/* * Copyright (c) 2022-2022 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 #include #include #include #include #include #include "errno.h" #include "fcntl.h" #include "los_mux.h" #include "los_debug.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 #ifndef CONFIG_NFILE_DESCRIPTORS #define CONFIG_NFILE_DESCRIPTORS 256 #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 { \ free(ptr); \ ptr = NULL; \ } while (0) #define LOS_FCNTL (O_NONBLOCK | O_NDELAY | O_APPEND | O_SYNC) #define IOV_MAX_CNT 4 UINT32 g_fsMutex; int VfsLock(void) { if (LOS_MuxPend(g_fsMutex, LOS_WAIT_FOREVER) != LOS_OK) { PRINT_ERR("VfsLock failed!"); return LOS_NOK; } return LOS_OK; } void VfsUnlock(void) { (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 *)malloc(tmpLen); if (tmpBuf == NULL) { return LOS_OK; } if (-1 == sprintf_s(tmpBuf, tmpLen, "/%s/%s/", cwd, path)) { free(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)) { free(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)) { free(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)) { free(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)) { free(tmpBuf); return totalLen; } if (EOK != memcpy_s(buf, bufSize, tmpBuf, (((totalLen + 1) > bufSize) ? bufSize : (totalLen + 1)))) { free(tmpBuf); return LOS_OK; } buf[bufSize - 1] = 0; free(tmpBuf); return totalLen; } #endif static int VfsOpen(const char *path, int flags) { struct File *file = NULL; int fd = -1; const char *pathInMp = NULL; struct MountPoint *mp = NULL; if ((path == NULL) || (path[strlen(path) - 1] == '/')) { VFS_ERRNO_SET(EINVAL); return fd; } if (VfsLock() != 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); VfsUnlock(); 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); VfsUnlock(); return fd; } file = VfsFileGet(); if (file == NULL) { VFS_ERRNO_SET(ENFILE); VfsUnlock(); return fd; } file->fullPath = strdup(path); if (file->fullPath == NULL) { VFS_ERRNO_SET(ENOMEM); VfsFilePut(file); VfsUnlock(); return LOS_NOK; } 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 { VfsFilePut(file); } VfsUnlock(); 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 < 0) || (fd >= CONFIG_NFILE_DESCRIPTORS)) { VFS_ERRNO_SET(EBADF); return NULL; } if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EFAULT); return NULL; } file = FdToFile(fd); if ((file == NULL) || (file->fMp == NULL)) { VFS_ERRNO_SET(EBADF); VfsUnlock(); return NULL; } if (file->fStatus != FILE_STATUS_READY) { VFS_ERRNO_SET(EBADF); VfsUnlock(); 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; VfsUnlock(); } static int VfsClose(int fd) { struct File *file = NULL; int ret = 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) { free((void *)file->fullPath); } VfsDetachFile(file); VfsFilePut(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 = 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 off_t VfsLseek(int fd, off_t off, int whence) { struct File *file; off_t ret = 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; } static int VfsStat(const char *path, struct stat *stat) { struct MountPoint *mp = NULL; const char *pathInMp = NULL; int ret = LOS_NOK; if ((path == NULL) || (stat == NULL)) { VFS_ERRNO_SET(EINVAL); return ret; } if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EAGAIN); return ret; } mp = VfsMpFind(path, &pathInMp); if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0')) { VFS_ERRNO_SET(ENOENT); VfsUnlock(); return ret; } if (mp->mFs->fsFops->stat != NULL) { ret = mp->mFs->fsFops->stat(mp, pathInMp, stat); } else { VFS_ERRNO_SET(ENOTSUP); } VfsUnlock(); return ret; } static int VfsStatfs(const char *path, struct statfs *buf) { struct MountPoint *mp = NULL; const char *pathInMp = NULL; int ret = LOS_NOK; if ((path == NULL) || (buf == NULL)) { VFS_ERRNO_SET(EINVAL); return ret; } if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EAGAIN); return ret; } mp = VfsMpFind(path, &pathInMp); if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0')) { VFS_ERRNO_SET(ENOENT); VfsUnlock(); return ret; } if (mp->mFs->fsFops->stat != NULL) { ret = mp->mFs->fsMops->statfs(pathInMp, buf); } else { VFS_ERRNO_SET(ENOTSUP); } VfsUnlock(); return ret; } static int VfsUnlink(const char *path) { struct MountPoint *mp = NULL; const char *pathInMp = NULL; int ret = LOS_NOK; if (path == NULL) { VFS_ERRNO_SET(EINVAL); return ret; } if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EAGAIN); return ret; } mp = VfsMpFind(path, &pathInMp); if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0') || (mp->mFs->fsFops->unlink == NULL)) { VFS_ERRNO_SET(ENOENT); VfsUnlock(); return ret; } ret = mp->mFs->fsFops->unlink(mp, pathInMp); VfsUnlock(); return ret; } static int VfsRename(const char *old, const char *new) { struct MountPoint *mpOld = NULL; struct MountPoint *mpNew = NULL; const char *pathInMpOld = NULL; const char *pathInMpNew = NULL; int ret = LOS_NOK; if ((old == NULL) || (new == NULL)) { VFS_ERRNO_SET(EINVAL); return ret; } if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EAGAIN); return ret; } mpOld = VfsMpFind(old, &pathInMpOld); if (pathInMpOld == NULL) { VFS_ERRNO_SET(EINVAL); VfsUnlock(); return ret; } if ((mpOld == NULL) || (*pathInMpOld == '\0') || (mpOld->mFs->fsFops->unlink == NULL)) { VFS_ERRNO_SET(EINVAL); VfsUnlock(); return ret; } mpNew = VfsMpFind(new, &pathInMpNew); if ((mpNew == NULL) || (pathInMpNew == NULL) || (*pathInMpNew == '\0') || (mpNew->mFs->fsFops->unlink == NULL)) { VFS_ERRNO_SET(EINVAL); VfsUnlock(); return ret; } if (mpOld != mpNew) { VFS_ERRNO_SET(EXDEV); VfsUnlock(); return ret; } if (mpOld->mFs->fsFops->rename != NULL) { ret = mpOld->mFs->fsFops->rename(mpOld, pathInMpOld, pathInMpNew); } else { VFS_ERRNO_SET(ENOTSUP); } VfsUnlock(); return ret; } static int VfsIoctl(int fd, int func, ...) { va_list ap; unsigned long arg; struct File *file = NULL; int ret = LOS_NOK; va_start(ap, func); arg = va_arg(ap, unsigned long); va_end(ap); 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 VfsSync(int fd) { struct File *file; int ret = LOS_NOK; file = VfsAttachFileReady(fd); if (file == NULL) { return ret; } if (file->fMp->mWriteEnable == FALSE) { VFS_ERRNO_SET(EACCES); VfsDetachFile(file); return ret; } if ((file->fFops != NULL) && (file->fFops->sync != NULL)) { ret = file->fFops->sync(file); } else { VFS_ERRNO_SET(ENOTSUP); } VfsDetachFile(file); return ret; } static DIR *VfsOpendir(const char *path) { struct MountPoint *mp = NULL; const char *pathInMp = NULL; struct Dir *dir = NULL; UINT32 ret; if (path == NULL) { VFS_ERRNO_SET(EINVAL); return NULL; } dir = (struct Dir *)malloc(sizeof(struct Dir)); if (dir == NULL) { VFS_ERRNO_SET(ENOMEM); return NULL; } if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EAGAIN); free(dir); return NULL; } mp = VfsMpFind(path, &pathInMp); if ((mp == NULL) || (pathInMp == NULL)) { VFS_ERRNO_SET(ENOENT); VfsUnlock(); free(dir); return NULL; } if (mp->mFs->fsFops->opendir == NULL) { VFS_ERRNO_SET(ENOTSUP); VfsUnlock(); free(dir); return NULL; } dir->dMp = mp; dir->dOffset = 0; ret = (UINT32)mp->mFs->fsFops->opendir(dir, pathInMp); if (ret == 0) { mp->mRefs++; } else { free(dir); dir = NULL; } VfsUnlock(); return (DIR *)dir; } static struct dirent *VfsReaddir(DIR *d) { struct dirent *ret = NULL; struct Dir *dir = (struct Dir *)d; if ((dir == NULL) || (dir->dMp == NULL)) { VFS_ERRNO_SET(EINVAL); return NULL; } if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EAGAIN); return NULL; } if ((dir->dMp->mFs != NULL) && (dir->dMp->mFs->fsFops != NULL) && (dir->dMp->mFs->fsFops->readdir != NULL)) { if (dir->dMp->mFs->fsFops->readdir(dir, &dir->dDent) == 0) { ret = &dir->dDent; } else { VFS_ERRNO_SET(EBADF); } } else { VFS_ERRNO_SET(ENOTSUP); } VfsUnlock(); return ret; } static int VfsClosedir(DIR *d) { struct MountPoint *mp = NULL; int ret = LOS_NOK; struct Dir *dir = (struct Dir *)d; if ((dir == NULL) || (dir->dMp == NULL)) { VFS_ERRNO_SET(EBADF); return ret; } mp = dir->dMp; if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EAGAIN); return ret; } if ((dir->dMp->mFs != NULL) && (dir->dMp->mFs->fsFops != NULL) && (dir->dMp->mFs->fsFops->closedir != NULL)) { ret = dir->dMp->mFs->fsFops->closedir(dir); } else { VFS_ERRNO_SET(ENOTSUP); } if (ret == 0) { mp->mRefs--; } else { VFS_ERRNO_SET(EBADF); } VfsUnlock(); free(dir); dir = NULL; return ret; } static int VfsMkdir(const char *path, int mode) { struct MountPoint *mp = NULL; const char *pathInMp = NULL; int ret = LOS_NOK; (void)mode; if (path == NULL) { VFS_ERRNO_SET(EINVAL); return ret; } if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EAGAIN); return ret; } mp = VfsMpFind(path, &pathInMp); if ((mp == NULL) || (pathInMp == NULL) || (*pathInMp == '\0')) { VFS_ERRNO_SET(ENOENT); VfsUnlock(); return ret; } if (mp->mFs->fsFops->mkdir != NULL) { ret = mp->mFs->fsFops->mkdir(mp, pathInMp); } else { VFS_ERRNO_SET(ENOTSUP); ret = LOS_NOK; } VfsUnlock(); 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 ssize_t VfsPread(int fd, void *buff, size_t bytes, off_t off) { off_t savepos, pos; ssize_t ret; if (buff == NULL) { VFS_ERRNO_SET(EFAULT); return LOS_NOK; } if (bytes == 0) { return 0; } if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EAGAIN); return LOS_NOK; } savepos = LOS_Lseek(fd, 0, SEEK_CUR); if (savepos == (off_t)-1) { VfsUnlock(); return LOS_NOK; } pos = LOS_Lseek(fd, off, SEEK_SET); if (pos == (off_t)-1) { VfsUnlock(); return LOS_NOK; } ret = LOS_Read(fd, buff, bytes); pos = LOS_Lseek(fd, savepos, SEEK_SET); if ((pos == (off_t)-1) && (ret >= 0)) { VfsUnlock(); return LOS_NOK; } VfsUnlock(); return ret; } static ssize_t VfsPwrite(int fd, const void *buff, size_t bytes, off_t off) { ssize_t ret; off_t savepos, pos; if (buff == NULL) { VFS_ERRNO_SET(EFAULT); return LOS_NOK; } if (bytes == 0) { return 0; } if (VfsLock() != LOS_OK) { VFS_ERRNO_SET(EAGAIN); return LOS_NOK; } savepos = LOS_Lseek(fd, 0, SEEK_CUR); if (savepos == (off_t)-1) { VfsUnlock(); return LOS_NOK; } pos = LOS_Lseek(fd, off, SEEK_SET); if (pos == (off_t)-1) { VfsUnlock(); return LOS_NOK; } ret = LOS_Write(fd, buff, bytes); pos = LOS_Lseek(fd, savepos, SEEK_SET); if ((pos == (off_t)-1) && (ret >= 0)) { VfsUnlock(); return LOS_NOK; } VfsUnlock(); return ret; } static int MapToPosixRet(int ret) { return ((ret) < 0 ? -1 : (ret)); } /* POSIX interface */ int LOS_Open(const char *path, int flags, ...) { #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) || (path == NULL)) { errno = EINVAL; return LOS_NOK; } size_t pathLen = strlen(path) + 1; char *canonicalPath = (char *)malloc(pathLen); if (!canonicalPath) { errno = ENOMEM; return LOS_NOK; } if (GetCanonicalPath(NULL, path, canonicalPath, pathLen) == 0) { FREE_AND_SET_NULL(canonicalPath); errno = ENOMEM; return LOS_NOK; } if (strcmp(canonicalPath, RANDOM_DEV_PATH) == 0) { FREE_AND_SET_NULL(canonicalPath); if ((O_ACCMODE & (unsigned)flags) != O_RDONLY) { errno = EPERM; return LOS_NOK; } if ((unsigned)flags & O_DIRECTORY) { errno = ENOTDIR; return 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 LOS_NOK; } errno = EISDIR; return 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); } int LOS_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 = LOS_NOK; if (fd >= 0 && fd < CONFIG_NFILE_DESCRIPTORS) { ret = VfsClose(fd); } return MapToPosixRet(ret); } ssize_t LOS_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 = LOS_NOK; if (fd >= 0 && fd < CONFIG_NFILE_DESCRIPTORS) { ret = VfsRead(fd, buff, bytes); } return MapToPosixRet(ret); } ssize_t LOS_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 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 = LOS_NOK; if (fd >= 0 && fd < CONFIG_NFILE_DESCRIPTORS) { ret = VfsWrite(fd, buff, bytes); } return MapToPosixRet(ret); } off_t LOS_Lseek(int fd, off_t off, int whence) { off_t ret = VfsLseek(fd, off, whence); return ret; } int LOS_Stat(const char *path, struct stat *stat) { int ret = VfsStat(path, stat); return MapToPosixRet(ret); } int LOS_Statfs(const char *path, struct statfs *buf) { int ret = VfsStatfs(path, buf); return MapToPosixRet(ret); } int LOS_Unlink(const char *path) { int ret = VfsUnlink(path); return MapToPosixRet(ret); } int LOS_Rename(const char *oldpath, const char *newpath) { int ret = VfsRename(oldpath, newpath); return MapToPosixRet(ret); } int LOS_Fsync(int fd) { int ret = VfsSync(fd); return MapToPosixRet(ret); } DIR *LOS_Opendir(const char *path) { return VfsOpendir(path); } struct dirent *LOS_Readdir(DIR *dir) { return VfsReaddir(dir); } int LOS_Closedir(DIR *dir) { int ret = VfsClosedir(dir); return MapToPosixRet(ret); } int LOS_Mkdir(const char *path, mode_t mode) { int ret = VfsMkdir(path, (int)mode); return MapToPosixRet(ret); } int LOS_Rmdir(const char *path) { int ret = VfsUnlink(path); return MapToPosixRet(ret); } int LOS_Lstat(const char *path, struct stat *buffer) { return stat(path, buffer); } int LOS_Fstat(int fd, struct stat *buf) { struct File *filep; int ret; filep = VfsAttachFileReady(fd); if ((filep == NULL) || (filep->fMp == NULL) || filep->fullPath == NULL) { return LOS_NOK; } ret = stat(filep->fullPath, buf); VfsDetachFile(filep); return ret; } int LOS_Fcntl(int fd, int cmd, ...) { struct File *filep = NULL; va_list ap; int ret; va_start(ap, cmd); if (fd < CONFIG_NFILE_DESCRIPTORS) { filep = VfsAttachFileReady(fd); ret = VfsVfcntl(filep, cmd, ap); VfsDetachFile(filep); } else { ret = -EBADF; #ifdef LOSCFG_NET_LWIP_SACK int arg = va_arg(ap, int); ret = lwip_fcntl(fd, (long)cmd, arg); va_end(ap); return ret; #endif /* LOSCFG_NET_LWIP_SACK */ } va_end(ap); if (ret < 0) { VFS_ERRNO_SET(-ret); ret = LOS_NOK; } return ret; } int LOS_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 { ret = -EBADF; #ifdef LOSCFG_NET_LWIP_SACK 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 LOS_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 LOS_NOK; } for (i = 0; i < iovcnt; ++i) { if ((SSIZE_MAX - bufLen) < iov[i].iov_len) { return LOS_NOK; } bufLen += iov[i].iov_len; } if (bufLen == 0) { return LOS_NOK; } totalLen = bufLen * sizeof(char); buf = (char *)malloc(totalLen); if (buf == NULL) { return 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) { free(buf); return LOS_NOK; } if (totalLen < (size_t)bytesToRead) { break; } curBuf += bytesToRead; totalLen -= bytesToRead; } free(buf); return totalBytesRead; } ssize_t LOS_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 LOS_NOK; } for (i = 0; i < iovcnt; ++i) { if ((SSIZE_MAX - bufLen) < iov[i].iov_len) { VFS_ERRNO_SET(EINVAL); return LOS_NOK; } bufLen += iov[i].iov_len; } if (bufLen == 0) { return LOS_NOK; } totalLen = bufLen * sizeof(char); buf = (char *)malloc(totalLen); if (buf == NULL) { return 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) { free(buf); return LOS_NOK; } curBuf += bytesToWrite; totalLen -= bytesToWrite; } totalBytesWritten = write(fd, buf, bufLen); free(buf); return totalBytesWritten; } int LOS_Isatty(int fd) { (void)fd; return 0; } int LOS_Access(const char *path, int amode) { int result; mode_t mode; struct stat buf; result = stat(path, &buf); if (result != 0) { return 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 LOS_NOK; } } if ((unsigned int)amode & W_OK) { if ((mode & (S_IWOTH | S_IWGRP | S_IWUSR)) == 0) { VFS_ERRNO_SET(EACCES); return LOS_NOK; } } if ((unsigned int)amode & X_OK) { if ((mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) { VFS_ERRNO_SET(EACCES); return LOS_NOK; } } return 0; } int LOS_Ftruncate(int fd, off_t length) { int ret = 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 LOS_Pread(int fd, void *buff, size_t bytes, off_t off) { ssize_t ret = LOS_NOK; if (fd >= 0 && fd < CONFIG_NFILE_DESCRIPTORS) { ret = VfsPread(fd, buff, bytes, off); } return MapToPosixRet(ret); } ssize_t LOS_Pwrite(int fd, const void *buff, size_t bytes, off_t off) { ssize_t ret = LOS_NOK; if (fd >= 0 && fd < CONFIG_NFILE_DESCRIPTORS) { ret = VfsPwrite(fd, buff, bytes, off); } return MapToPosixRet(ret); }