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);
|
|
}
|