kernel_liteos_a/syscall/fs_syscall.c

2599 lines
56 KiB
C

/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 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.
*/
#include "syscall_pub.h"
#ifdef LOSCFG_FS_VFS
#include "errno.h"
#include "unistd.h"
#include "fs/fd_table.h"
#include "fs/file.h"
#include "fs/fs.h"
#include "fs/fs_operation.h"
#include "sys/mount.h"
#include "los_task_pri.h"
#include "sys/utsname.h"
#include "sys/uio.h"
#include "poll.h"
#include "sys/prctl.h"
#ifdef LOSCFG_KERNEL_DYNLOAD
#include "los_exec_elf.h"
#endif
#include "los_syscall.h"
#include "dirent.h"
#include "user_copy.h"
#include "los_vm_map.h"
#include "los_memory.h"
#include "los_strncpy_from_user.h"
#include "capability_type.h"
#include "capability_api.h"
#include "sys/statfs.h"
#define HIGH_SHIFT_BIT 32
#define TIMESPEC_TIMES_NUM 2
static int CheckNewAttrTime(struct IATTR *attr, struct timespec times[TIMESPEC_TIMES_NUM])
{
int ret = ENOERR;
struct timespec stp = {0};
if (times) {
if (times[0].tv_nsec == UTIME_OMIT) {
attr->attr_chg_valid &= ~CHG_ATIME;
} else if (times[0].tv_nsec == UTIME_NOW) {
ret = clock_gettime(CLOCK_REALTIME, &stp);
if (ret < 0) {
return -get_errno();
}
attr->attr_chg_atime = (unsigned int)stp.tv_sec;
attr->attr_chg_valid |= CHG_ATIME;
} else {
attr->attr_chg_atime = (unsigned int)times[0].tv_sec;
attr->attr_chg_valid |= CHG_ATIME;
}
if (times[1].tv_nsec == UTIME_OMIT) {
attr->attr_chg_valid &= ~CHG_MTIME;
} else if (times[1].tv_nsec == UTIME_NOW) {
ret = clock_gettime(CLOCK_REALTIME, &stp);
if (ret < 0) {
return -get_errno();
}
attr->attr_chg_mtime = (unsigned int)stp.tv_sec;
attr->attr_chg_valid |= CHG_MTIME;
} else {
attr->attr_chg_mtime = (unsigned int)times[1].tv_sec;
attr->attr_chg_valid |= CHG_MTIME;
}
} else {
ret = clock_gettime(CLOCK_REALTIME, &stp);
if (ret < 0) {
return -get_errno();
}
attr->attr_chg_atime = (unsigned int)stp.tv_sec;
attr->attr_chg_mtime = (unsigned int)stp.tv_sec;
attr->attr_chg_valid |= CHG_ATIME;
attr->attr_chg_valid |= CHG_MTIME;
}
return ret;
}
static int GetFullpathNull(int fd, const char *path, char **filePath)
{
int ret;
char *fullPath = NULL;
struct file *file = NULL;
if ((fd != AT_FDCWD) && (path == NULL)) {
fd = GetAssociatedSystemFd(fd);
ret = fs_getfilep(fd, &file);
if (ret < 0) {
return -get_errno();
}
fullPath = file->f_path;
} else {
ret = GetFullpath(fd, path, &fullPath);
if (ret < 0) {
return ret;
}
}
*filePath = fullPath;
return ret;
}
static int UserIovItemCheck(const struct iovec *iov, const int iovcnt)
{
int i;
for (i = 0; i < iovcnt; ++i) {
if (iov[i].iov_len == 0) {
continue;
}
if (!LOS_IsUserAddressRange((vaddr_t)(UINTPTR)iov[i].iov_base, iov[i].iov_len)) {
return i;
}
}
return iovcnt;
}
static int UserIovCopy(struct iovec **iovBuf, const struct iovec *iov, const int iovcnt, int *valid_iovcnt)
{
int ret;
int bufLen = iovcnt * sizeof(struct iovec);
if (bufLen < 0) {
return -EINVAL;
}
*iovBuf = (struct iovec*)LOS_MemAlloc(OS_SYS_MEM_ADDR, bufLen);
if (*iovBuf == NULL) {
return -ENOMEM;
}
if (LOS_ArchCopyFromUser(*iovBuf, iov, bufLen) != 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, *iovBuf);
return -EFAULT;
}
ret = UserIovItemCheck(*iovBuf, iovcnt);
if (ret == 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, *iovBuf);
return -EFAULT;
}
*valid_iovcnt = ret;
return 0;
}
static int PollfdToSystem(struct pollfd *fds, nfds_t nfds, int **pollFdsBak)
{
if ((nfds != 0 && fds == NULL) || (pollFdsBak == NULL)) {
set_errno(EINVAL);
return -1;
}
if (nfds == 0) {
return 0;
}
int *pollFds = (int *)malloc(sizeof(int) * nfds);
if (pollFds == NULL) {
set_errno(ENOMEM);
return -1;
}
for (int i = 0; i < nfds; ++i) {
struct pollfd *p_fds = &fds[i];
pollFds[i] = p_fds->fd;
if (p_fds->fd < 0) {
set_errno(EBADF);
free(pollFds);
return -1;
}
p_fds->fd = GetAssociatedSystemFd(p_fds->fd);
}
*pollFdsBak = pollFds;
return 0;
}
static void RestorePollfd(struct pollfd *fds, nfds_t nfds, const int *pollFds)
{
if ((fds == NULL) || (pollFds == NULL)) {
return;
}
for (int i = 0; i < nfds; ++i) {
struct pollfd *p_fds = &fds[i];
p_fds->fd = pollFds[i];
}
}
static int UserPoll(struct pollfd *fds, nfds_t nfds, int timeout)
{
int *pollFds = NULL;
int ret = PollfdToSystem(fds, nfds, &pollFds);
if (ret < 0) {
return -1;
}
ret = poll(fds, nfds, timeout);
RestorePollfd(fds, nfds, pollFds);
free(pollFds);
return ret;
}
int SysClose(int fd)
{
int ret;
/* Process fd convert to system global fd */
int sysfd = DisassociateProcessFd(fd);
ret = close(sysfd);
if (ret < 0) {
AssociateSystemFd(fd, sysfd);
return -get_errno();
}
FreeProcessFd(fd);
return ret;
}
ssize_t SysRead(int fd, void *buf, size_t nbytes)
{
int ret;
if (nbytes == 0) {
return 0;
}
if (!LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buf, nbytes)) {
return -EFAULT;
}
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
ret = read(fd, buf, nbytes);
if (ret < 0) {
return -get_errno();
}
return ret;
}
ssize_t SysWrite(int fd, const void *buf, size_t nbytes)
{
int ret;
if (nbytes == 0) {
return 0;
}
if (!LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buf, nbytes)) {
return -EFAULT;
}
/* Process fd convert to system global fd */
int sysfd = GetAssociatedSystemFd(fd);
ret = write(sysfd, buf, nbytes);
if (ret < 0) {
return -get_errno();
}
return ret;
}
int SysOpen(const char *path, int oflags, ...)
{
int ret;
int procFd;
mode_t mode = DEFAULT_FILE_MODE; /* 0666: File read-write properties. */
char *pathRet = NULL;
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
return ret;
}
}
procFd = AllocProcessFd();
if (procFd < 0) {
ret = -EMFILE;
goto ERROUT;
}
if (oflags & O_CLOEXEC) {
SetCloexecFlag(procFd);
}
if ((unsigned int)oflags & O_DIRECTORY) {
ret = do_opendir(pathRet, oflags);
} else {
#ifdef LOSCFG_FILE_MODE
va_list ap;
va_start(ap, oflags);
mode = va_arg(ap, int);
va_end(ap);
#endif
ret = do_open(AT_FDCWD, pathRet, oflags, mode);
}
if (ret < 0) {
ret = -get_errno();
goto ERROUT;
}
AssociateSystemFd(procFd, ret);
if (pathRet != NULL) {
LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return procFd;
ERROUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
if (procFd >= 0) {
FreeProcessFd(procFd);
}
return ret;
}
int SysCreat(const char *pathname, mode_t mode)
{
int ret = 0;
char *pathRet = NULL;
if (pathname != NULL) {
ret = UserPathCopy(pathname, &pathRet);
if (ret != 0) {
goto OUT;
}
}
int procFd = AllocProcessFd();
if (procFd < 0) {
ret = -EMFILE;
goto OUT;
}
ret = open((pathname ? pathRet : NULL), O_CREAT | O_TRUNC | O_WRONLY, mode);
if (ret < 0) {
FreeProcessFd(procFd);
ret = -get_errno();
} else {
AssociateSystemFd(procFd, ret);
ret = procFd;
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysLink(const char *oldpath, const char *newpath)
{
int ret;
char *oldpathRet = NULL;
char *newpathRet = NULL;
if (oldpath != NULL) {
ret = UserPathCopy(oldpath, &oldpathRet);
if (ret != 0) {
goto OUT;
}
}
if (newpath != NULL) {
ret = UserPathCopy(newpath, &newpathRet);
if (ret != 0) {
goto OUT;
}
}
ret = link(oldpathRet, newpathRet);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (oldpathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, oldpathRet);
}
if (newpathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, newpathRet);
}
return ret;
}
ssize_t SysReadlink(const char *pathname, char *buf, size_t bufsize)
{
ssize_t ret;
char *pathRet = NULL;
if (bufsize == 0) {
return -EINVAL;
}
if (pathname != NULL) {
ret = UserPathCopy(pathname, &pathRet);
if (ret != 0) {
goto OUT;
}
}
if (!LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buf, bufsize)) {
ret = -EFAULT;
goto OUT;
}
ret = readlink(pathRet, buf, bufsize);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysSymlink(const char *target, const char *linkpath)
{
int ret;
char *targetRet = NULL;
char *pathRet = NULL;
if (target != NULL) {
ret = UserPathCopy(target, &targetRet);
if (ret != 0) {
goto OUT;
}
}
if (linkpath != NULL) {
ret = UserPathCopy(linkpath, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = symlink(targetRet, pathRet);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
if (targetRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, targetRet);
}
return ret;
}
int SysUnlink(const char *pathname)
{
int ret;
char *pathRet = NULL;
if (pathname != NULL) {
ret = UserPathCopy(pathname, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = do_unlink(AT_FDCWD, (pathname ? pathRet : NULL));
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
#ifdef LOSCFG_KERNEL_DYNLOAD
int SysExecve(const char *fileName, char *const *argv, char *const *envp)
{
return LOS_DoExecveFile(fileName, argv, envp);
}
#endif
int SysFchdir(int fd)
{
int ret;
int sysFd;
struct file *file = NULL;
sysFd = GetAssociatedSystemFd(fd);
if (sysFd < 0) {
return -EBADF;
}
ret = fs_getfilep(sysFd, &file);
if (ret < 0) {
return -get_errno();
}
ret = chdir(file->f_path);
if (ret < 0) {
ret = -get_errno();
}
return ret;
}
int SysChdir(const char *path)
{
int ret;
char *pathRet = NULL;
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = chdir(path ? pathRet : NULL);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
off_t SysLseek(int fd, off_t offset, int whence)
{
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
return _lseek(fd, offset, whence);
}
off64_t SysLseek64(int fd, int offsetHigh, int offsetLow, off64_t *result, int whence)
{
off64_t ret;
off64_t res;
int retVal;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
ret = _lseek64(fd, offsetHigh, offsetLow, &res, whence);
if (ret != 0) {
return ret;
}
retVal = LOS_ArchCopyToUser(result, &res, sizeof(off64_t));
if (retVal != 0) {
return -EFAULT;
}
return 0;
}
#ifdef LOSCFG_FS_NFS
static int NfsMountRef(const char *serverIpAndPath, const char *mountPath,
unsigned int uid, unsigned int gid) __attribute__((weakref("nfs_mount")));
static int NfsMount(const char *serverIpAndPath, const char *mountPath,
unsigned int uid, unsigned int gid)
{
int ret;
if ((serverIpAndPath == NULL) || (mountPath == NULL)) {
return -EINVAL;
}
ret = NfsMountRef(serverIpAndPath, mountPath, uid, gid);
if (ret < 0) {
ret = -get_errno();
}
return ret;
}
#endif
int SysMount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags,
const void *data)
{
int ret;
char *sourceRet = NULL;
char *targetRet = NULL;
char *dataRet = NULL;
char fstypeRet[FILESYSTEM_TYPE_MAX + 1] = {0};
if (!IsCapPermit(CAP_FS_MOUNT)) {
return -EPERM;
}
if (target != NULL) {
ret = UserPathCopy(target, &targetRet);
if (ret != 0) {
goto OUT;
}
}
if (filesystemtype != NULL) {
ret = LOS_StrncpyFromUser(fstypeRet, filesystemtype, FILESYSTEM_TYPE_MAX + 1);
if (ret < 0) {
goto OUT;
} else if (ret > FILESYSTEM_TYPE_MAX) {
ret = -ENODEV;
goto OUT;
}
if (strcmp(fstypeRet, "ramfs") && (source != NULL)) {
ret = UserPathCopy(source, &sourceRet);
if (ret != 0) {
goto OUT;
}
}
#ifdef LOSCFG_FS_NFS
if (strcmp(fstypeRet, "nfs") == 0) {
ret = NfsMount(sourceRet, targetRet, 0, 0);
goto OUT;
}
#endif
}
if (data != NULL) {
ret = UserPathCopy(data, &dataRet);
if (ret != 0) {
goto OUT;
}
}
ret = mount(sourceRet, targetRet, (filesystemtype ? fstypeRet : NULL), mountflags, dataRet);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (sourceRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, sourceRet);
}
if (targetRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, targetRet);
}
if (dataRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, dataRet);
}
return ret;
}
int SysUmount(const char *target)
{
int ret;
char *pathRet = NULL;
if (!IsCapPermit(CAP_FS_MOUNT)) {
return -EPERM;
}
if (target != NULL) {
ret = UserPathCopy(target, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = umount(target ? pathRet : NULL);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysAccess(const char *path, int amode)
{
int ret;
char *pathRet = NULL;
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = access(pathRet, amode);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysRename(const char *oldpath, const char *newpath)
{
int ret;
char *pathOldRet = NULL;
char *pathNewRet = NULL;
if (oldpath != NULL) {
ret = UserPathCopy(oldpath, &pathOldRet);
if (ret != 0) {
goto OUT;
}
}
if (newpath != NULL) {
ret = UserPathCopy(newpath, &pathNewRet);
if (ret != 0) {
goto OUT;
}
}
ret = do_rename(AT_FDCWD, (oldpath ? pathOldRet : NULL), AT_FDCWD,
(newpath ? pathNewRet : NULL));
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathOldRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathOldRet);
}
if (pathNewRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathNewRet);
}
return ret;
}
int SysMkdir(const char *pathname, mode_t mode)
{
int ret;
char *pathRet = NULL;
if (pathname != NULL) {
ret = UserPathCopy(pathname, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = do_mkdir(AT_FDCWD, (pathname ? pathRet : NULL), mode);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysRmdir(const char *pathname)
{
int ret;
char *pathRet = NULL;
if (pathname != NULL) {
ret = UserPathCopy(pathname, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = do_rmdir(AT_FDCWD, (pathname ? pathRet : NULL));
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysDup(int fd)
{
int sysfd = GetAssociatedSystemFd(fd);
/* Check if the param is valid, note that: socket fd is not support dup2 */
if ((sysfd < 0) || (sysfd >= CONFIG_NFILE_DESCRIPTORS)) {
return -EBADF;
}
int dupfd = AllocProcessFd();
if (dupfd < 0) {
return -EMFILE;
}
files_refer(sysfd);
AssociateSystemFd(dupfd, sysfd);
return dupfd;
}
void SysSync(void)
{
sync();
}
int SysUmount2(const char *target, int flags)
{
if (flags != 0) {
return -EINVAL;
}
return SysUmount(target);
}
int SysIoctl(int fd, int req, void *arg)
{
int ret;
unsigned int size = _IOC_SIZE((unsigned int)req);
unsigned int dir = _IOC_DIR((unsigned int)req);
if ((size == 0) && (dir != _IOC_NONE)) {
return -EINVAL;
}
if ((dir != _IOC_NONE) && (((void *)(uintptr_t)arg) == NULL)) {
return -EINVAL;
}
if ((dir & _IOC_READ) || (dir & _IOC_WRITE)) {
if (!LOS_IsUserAddressRange((uintptr_t)arg, size)) {
return -EFAULT;
}
}
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
ret = ioctl(fd, req, arg);
if (ret < 0) {
return -get_errno();
}
return ret;
}
int SysFcntl(int fd, int cmd, void *arg)
{
/* Process fd convert to system global fd */
int sysfd = GetAssociatedSystemFd(fd);
int ret = VfsFcntl(fd, cmd, arg);
if (ret == CONTINE_NUTTX_FCNTL) {
ret = fcntl(sysfd, cmd, arg);
}
if (ret < 0) {
return -get_errno();
}
return ret;
}
#ifdef LOSCFG_KERNEL_PIPE
int SysPipe(int pipefd[2]) /* 2 : pipe fds for read and write */
{
int ret;
int pipeFdIntr[2] = {0}; /* 2 : pipe fds for read and write */
int procFd0 = AllocProcessFd();
if (procFd0 < 0) {
return -EMFILE;
}
int procFd1 = AllocProcessFd();
if (procFd1 < 0) {
FreeProcessFd(procFd0);
return -EMFILE;
}
ret = pipe(pipeFdIntr);
if (ret < 0) {
FreeProcessFd(procFd0);
FreeProcessFd(procFd1);
return -get_errno();
}
int sysPipeFd0 = pipeFdIntr[0];
int sysPipeFd1 = pipeFdIntr[1];
AssociateSystemFd(procFd0, sysPipeFd0);
AssociateSystemFd(procFd1, sysPipeFd1);
pipeFdIntr[0] = procFd0;
pipeFdIntr[1] = procFd1;
ret = LOS_ArchCopyToUser(pipefd, pipeFdIntr, sizeof(pipeFdIntr));
if (ret != 0) {
FreeProcessFd(procFd0);
FreeProcessFd(procFd1);
close(sysPipeFd0);
close(sysPipeFd1);
return -EFAULT;
}
return ret;
}
#endif
int SysDup2(int fd1, int fd2)
{
int ret;
int sysfd1 = GetAssociatedSystemFd(fd1);
int sysfd2 = GetAssociatedSystemFd(fd2);
/* Check if the param is valid, note that: socket fd is not support dup2 */
if ((sysfd1 < 0) || (sysfd1 >= CONFIG_NFILE_DESCRIPTORS) || (CheckProcessFd(fd2) != OK)) {
return -EBADF;
}
/* Handle special circumstances */
if (fd1 == fd2) {
return fd2;
}
ret = AllocSpecifiedProcessFd(fd2);
if (ret != OK) {
return ret;
}
/* close the sysfd2 in need */
if (sysfd2 >= 0) {
ret = close(sysfd2);
if (ret < 0) {
AssociateSystemFd(fd2, sysfd2);
return -get_errno();
}
}
files_refer(sysfd1);
AssociateSystemFd(fd2, sysfd1);
/* if fd1 is not equal to fd2, the FD_CLOEXEC flag associated with fd2 shall be cleared */
ClearCloexecFlag(fd2);
return fd2;
}
static int SelectParamCheckCopy(fd_set *readfds, fd_set *writefds, fd_set *exceptfds, fd_set **fdsBuf)
{
fd_set *readfdsRet = NULL;
fd_set *writefdsRet = NULL;
fd_set *exceptfdsRet = NULL;
*fdsBuf = (fd_set *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(fd_set) * 3); /* 3: three param need check and copy */
if (*fdsBuf == NULL) {
return -ENOMEM;
}
readfdsRet = *fdsBuf; /* LOS_MemAlloc 3 sizeof(fd_set) space,first use for readfds */
writefdsRet = *fdsBuf + 1; /* 1: LOS_MemAlloc 3 sizeof(fd_set) space,second use for writefds */
exceptfdsRet = *fdsBuf + 2; /* 2: LOS_MemAlloc 3 sizeof(fd_set) space,thired use for exceptfds */
if (readfds != NULL) {
if (LOS_ArchCopyFromUser(readfdsRet, readfds, sizeof(fd_set)) != 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, *fdsBuf);
return -EFAULT;
}
}
if (writefds != NULL) {
if (LOS_ArchCopyFromUser(writefdsRet, writefds, sizeof(fd_set)) != 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, *fdsBuf);
return -EFAULT;
}
}
if (exceptfds != NULL) {
if (LOS_ArchCopyFromUser(exceptfdsRet, exceptfds, sizeof(fd_set)) != 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, *fdsBuf);
return -EFAULT;
}
}
return 0;
}
int SysSelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
{
int ret;
fd_set *fdsRet = NULL;
fd_set *readfdsRet = NULL;
fd_set *writefdsRet = NULL;
fd_set *exceptfdsRet = NULL;
struct timeval timeoutRet = {0};
ret = SelectParamCheckCopy(readfds, writefds, exceptfds, &fdsRet);
if (ret != 0) {
return ret;
}
readfdsRet = fdsRet; /* LOS_MemAlloc 3 sizeof(fd_set) space,first use for readfds */
writefdsRet = fdsRet + 1; /* 1: LOS_MemAlloc 3 sizeof(fd_set) space,second use for writefds */
exceptfdsRet = fdsRet + 2; /* 2: LOS_MemAlloc 3 sizeof(fd_set) space,thired use for exceptfds */
if (timeout != NULL) {
if (LOS_ArchCopyFromUser(&timeoutRet, timeout, sizeof(struct timeval)) != 0) {
goto ERROUT;
}
}
ret = do_select(nfds, (readfds ? readfdsRet : NULL), (writefds ? writefdsRet : NULL),
(exceptfds ? exceptfdsRet : NULL), (timeout ? (&timeoutRet) : NULL), UserPoll);
if (ret < 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, fdsRet);
return -get_errno();
}
if (readfds != NULL) {
if (LOS_ArchCopyToUser(readfds, readfdsRet, sizeof(fd_set)) != 0) {
goto ERROUT;
}
}
if (writefds != NULL) {
if (LOS_ArchCopyToUser(writefds, writefdsRet, sizeof(fd_set)) != 0) {
goto ERROUT;
}
}
if (exceptfds != 0) {
if (LOS_ArchCopyToUser(exceptfds, exceptfdsRet, sizeof(fd_set)) != 0) {
goto ERROUT;
}
}
(void)LOS_MemFree(OS_SYS_MEM_ADDR, fdsRet);
return ret;
ERROUT:
(void)LOS_MemFree(OS_SYS_MEM_ADDR, fdsRet);
return -EFAULT;
}
int SysTruncate(const char *path, off_t length)
{
int ret;
int fd = -1;
char *pathRet = NULL;
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
goto OUT;
}
}
fd = open((path ? pathRet : NULL), O_RDWR);
if (fd < 0) {
/* The errno value has already been set */
ret = -get_errno();
goto OUT;
}
ret = ftruncate(fd, length);
close(fd);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysTruncate64(const char *path, off64_t length)
{
int ret;
int fd = -1;
char *pathRet = NULL;
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
goto OUT;
}
}
fd = open((path ? pathRet : NULL), O_RDWR);
if (fd < 0) {
/* The errno value has already been set */
ret = -get_errno();
goto OUT;
}
ret = ftruncate64(fd, length);
close(fd);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysFtruncate(int fd, off_t length)
{
int ret;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
ret = ftruncate(fd, length);
if (ret < 0) {
return -get_errno();
}
return ret;
}
int SysStatfs(const char *path, struct statfs *buf)
{
int ret;
char *pathRet = NULL;
struct statfs bufRet = {0};
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = statfs((path ? pathRet : NULL), (buf ? (&bufRet) : NULL));
if (ret < 0) {
ret = -get_errno();
goto OUT;
}
ret = LOS_ArchCopyToUser(buf, &bufRet, sizeof(struct statfs));
if (ret != 0) {
ret = -EFAULT;
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysStatfs64(const char *path, size_t sz, struct statfs *buf)
{
int ret;
char *pathRet = NULL;
struct statfs bufRet = {0};
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
goto OUT;
}
}
if (sz != sizeof(*buf)) {
ret = -EINVAL;
goto OUT;
}
ret = statfs((path ? pathRet : NULL), (buf ? (&bufRet) : NULL));
if (ret < 0) {
ret = -get_errno();
goto OUT;
}
ret = LOS_ArchCopyToUser(buf, &bufRet, sizeof(struct statfs));
if (ret != 0) {
ret = -EFAULT;
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysStat(const char *path, struct kstat *buf)
{
int ret;
char *pathRet = NULL;
struct stat bufRet = {0};
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = stat((path ? pathRet : NULL), (buf ? (&bufRet) : NULL));
if (ret < 0) {
ret = -get_errno();
goto OUT;
}
ret = LOS_ArchCopyToUser(buf, &bufRet, sizeof(struct kstat));
if (ret != 0) {
ret = -EFAULT;
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysLstat(const char *path, struct kstat *buffer)
{
int ret;
char *pathRet = NULL;
struct stat bufRet = {0};
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = stat((path ? pathRet : NULL), (buffer ? (&bufRet) : NULL));
if (ret < 0) {
ret = -get_errno();
goto OUT;
}
ret = LOS_ArchCopyToUser(buffer, &bufRet, sizeof(struct kstat));
if (ret != 0) {
ret = -EFAULT;
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysFstat(int fd, struct stat *buf)
{
int ret;
struct stat bufRet = {0};
struct file *filep = NULL;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
ret = fs_getfilep(fd, &filep);
if (ret < 0) {
return -get_errno();
}
if (filep->f_oflags & O_DIRECTORY) {
return -EBADF;
}
ret = stat(filep->f_path, (buf ? (&bufRet) : NULL));
if (ret < 0) {
return -get_errno();
}
ret = LOS_ArchCopyToUser(buf, &bufRet, sizeof(struct stat));
if (ret != 0) {
return -EFAULT;
}
return ret;
}
int SysStatx(int fd, const char *restrict path, int flag, unsigned mask, struct statx *restrict stx)
{
return -ENOSYS;
}
int SysFsync(int fd)
{
int ret;
struct file *filep = NULL;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
/* Get the file structure corresponding to the file descriptor. */
ret = fs_getfilep(fd, &filep);
if (ret < 0) {
/* The errno value has already been set */
return -get_errno();
}
if (filep->f_oflags & O_DIRECTORY) {
return -EBADF;
}
/* Perform the fsync operation */
ret = file_fsync(filep);
if (ret < 0) {
return -get_errno();
}
return ret;
}
ssize_t SysReadv(int fd, const struct iovec *iov, int iovcnt)
{
int ret;
int valid_iovcnt = -1;
struct iovec *iovRet = NULL;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
if ((iov == NULL) || (iovcnt < 0) || (iovcnt > IOV_MAX)) {
return -EINVAL;
}
if (iovcnt == 0) {
return 0;
}
ret = UserIovCopy(&iovRet, iov, iovcnt, &valid_iovcnt);
if (ret != 0) {
return ret;
}
if (valid_iovcnt <= 0) {
ret = -EFAULT;
goto OUT;
}
ret = vfs_readv(fd, iovRet, valid_iovcnt, NULL);
if (ret < 0) {
ret = -get_errno();
}
OUT:
(void)LOS_MemFree(OS_SYS_MEM_ADDR, iovRet);
return ret;
}
ssize_t SysWritev(int fd, const struct iovec *iov, int iovcnt)
{
int ret;
int valid_iovcnt = -1;
struct iovec *iovRet = NULL;
/* Process fd convert to system global fd */
int sysfd = GetAssociatedSystemFd(fd);
if ((iovcnt < 0) || (iovcnt > IOV_MAX)) {
return -EINVAL;
}
if (iovcnt == 0) {
return 0;
}
if (iov == NULL) {
return -EFAULT;
}
ret = UserIovCopy(&iovRet, iov, iovcnt, &valid_iovcnt);
if (ret != 0) {
return ret;
}
if (valid_iovcnt != iovcnt) {
ret = -EFAULT;
goto OUT_FREE;
}
ret = writev(sysfd, iovRet, valid_iovcnt);
if (ret < 0) {
ret = -get_errno();
}
OUT_FREE:
(void)LOS_MemFree(OS_SYS_MEM_ADDR, iovRet);
return ret;
}
int SysPoll(struct pollfd *fds, nfds_t nfds, int timeout)
{
int ret;
struct pollfd *kfds = NULL;
if ((nfds >= MAX_POLL_NFDS) || (nfds == 0) || (fds == NULL)) {
return -EINVAL;
}
kfds = (struct pollfd *)malloc(sizeof(struct pollfd) * nfds);
if (kfds != NULL) {
if (LOS_ArchCopyFromUser(kfds, fds, sizeof(struct pollfd) * nfds) != 0) {
ret = -EFAULT;
goto OUT_KFD;
}
}
int *pollFds = NULL;
ret = PollfdToSystem(kfds, nfds, &pollFds);
if (ret < 0) {
ret = -get_errno();
goto OUT_KFD;
}
ret = poll(kfds, nfds, timeout);
if (ret < 0) {
ret = -get_errno();
goto OUT;
}
if (kfds != NULL) {
RestorePollfd(kfds, nfds, pollFds);
if (LOS_ArchCopyToUser(fds, kfds, sizeof(struct pollfd) * nfds) != 0) {
ret = -EFAULT;
goto OUT;
}
}
OUT:
free(pollFds);
OUT_KFD:
free(kfds);
return ret;
}
int SysPrctl(int option, ...)
{
unsigned long name;
va_list ap;
errno_t err;
va_start(ap, option);
if (option != PR_SET_NAME) {
PRINT_ERR("%s: %d, no support option : 0x%x\n", __FUNCTION__, __LINE__, option);
err = EOPNOTSUPP;
goto ERROR;
}
name = va_arg(ap, unsigned long);
if (!LOS_IsUserAddress(name)) {
err = EFAULT;
goto ERROR;
}
err = OsSetTaskName(OsCurrTaskGet(), (const char *)(uintptr_t)name, TRUE);
if (err != LOS_OK) {
goto ERROR;
}
va_end(ap);
return ENOERR;
ERROR:
va_end(ap);
return -err;
}
ssize_t SysPread64(int fd, void *buf, size_t nbytes, off64_t offset)
{
int ret, retVal;
char *bufRet = NULL;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
if (nbytes == 0) {
ret = pread64(fd, buf, nbytes, offset);
if (ret < 0) {
return -get_errno();
} else {
return ret;
}
}
bufRet = (char *)LOS_MemAlloc(OS_SYS_MEM_ADDR, nbytes);
if (bufRet == NULL) {
return -ENOMEM;
}
ret = pread64(fd, (buf ? bufRet : NULL), nbytes, offset);
if (ret < 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, bufRet);
return -get_errno();
}
retVal = LOS_ArchCopyToUser(buf, bufRet, ret);
if (retVal != 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, bufRet);
return -EFAULT;
}
(void)LOS_MemFree(OS_SYS_MEM_ADDR, bufRet);
return ret;
}
ssize_t SysPwrite64(int fd, const void *buf, size_t nbytes, off64_t offset)
{
int ret;
char *bufRet = NULL;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
if (nbytes == 0) {
ret = pwrite64(fd, buf, nbytes, offset);
if (ret < 0) {
return -get_errno();
}
return ret;
}
bufRet = (char *)LOS_MemAlloc(OS_SYS_MEM_ADDR, nbytes);
if (bufRet == NULL) {
return -ENOMEM;
}
if (buf != NULL) {
ret = LOS_ArchCopyFromUser(bufRet, buf, nbytes);
if (ret != 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, bufRet);
return -EFAULT;
}
}
ret = pwrite64(fd, (buf ? bufRet : NULL), nbytes, offset);
if (ret < 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, bufRet);
return -get_errno();
}
(void)LOS_MemFree(OS_SYS_MEM_ADDR, bufRet);
return ret;
}
char *SysGetcwd(char *buf, size_t n)
{
char *ret = NULL;
char *bufRet = NULL;
size_t bufLen = n;
int retVal;
if (bufLen > PATH_MAX) {
bufLen = PATH_MAX;
}
bufRet = (char *)LOS_MemAlloc(OS_SYS_MEM_ADDR, bufLen);
if (bufRet == NULL) {
return (char *)(intptr_t)-ENOMEM;
}
(void)memset_s(bufRet, bufLen, 0, bufLen);
ret = getcwd((buf ? bufRet : NULL), bufLen);
if (ret == NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, bufRet);
return (char *)(intptr_t)-get_errno();
}
retVal = LOS_ArchCopyToUser(buf, bufRet, bufLen);
if (retVal != 0) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, bufRet);
return (char *)(intptr_t)-EFAULT;
}
ret = buf;
(void)LOS_MemFree(OS_SYS_MEM_ADDR, bufRet);
return ret;
}
ssize_t SysSendFile(int outfd, int infd, off_t *offset, size_t count)
{
int ret, retVal;
off_t offsetRet;
retVal = LOS_ArchCopyFromUser(&offsetRet, offset, sizeof(off_t));
if (retVal != 0) {
return -EFAULT;
}
/* Process fd convert to system global fd */
outfd = GetAssociatedSystemFd(outfd);
infd = GetAssociatedSystemFd(infd);
ret = sendfile(outfd, infd, (offset ? (&offsetRet) : NULL), count);
if (ret < 0) {
return -get_errno();
}
retVal = LOS_ArchCopyToUser(offset, &offsetRet, sizeof(off_t));
if (retVal != 0) {
return -EFAULT;
}
return ret;
}
int SysFtruncate64(int fd, off64_t length)
{
int ret;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
ret = ftruncate64(fd, length);
if (ret < 0) {
return -get_errno();
}
return ret;
}
int SysOpenat(int dirfd, const char *path, int oflags, ...)
{
int ret;
int procFd;
char *pathRet = NULL;
mode_t mode;
#ifdef LOSCFG_FILE_MODE
va_list ap;
va_start(ap, oflags);
mode = va_arg(ap, int);
va_end(ap);
#else
mode = 0666; /* 0666: File read-write properties. */
#endif
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
return ret;
}
}
procFd = AllocProcessFd();
if (procFd < 0) {
ret = -EMFILE;
goto ERROUT;
}
if (oflags & O_CLOEXEC) {
SetCloexecFlag(procFd);
}
if (dirfd != AT_FDCWD) {
/* Process fd convert to system global fd */
dirfd = GetAssociatedSystemFd(dirfd);
}
ret = do_open(dirfd, (path ? pathRet : NULL), oflags, mode);
if (ret < 0) {
ret = -get_errno();
goto ERROUT;
}
AssociateSystemFd(procFd, ret);
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return procFd;
ERROUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
if (procFd >= 0) {
FreeProcessFd(procFd);
}
return ret;
}
int SysMkdirat(int dirfd, const char *pathname, mode_t mode)
{
int ret;
char *pathRet = NULL;
if (pathname != NULL) {
ret = UserPathCopy(pathname, &pathRet);
if (ret != 0) {
goto OUT;
}
}
if (dirfd != AT_FDCWD) {
/* Process fd convert to system global fd */
dirfd = GetAssociatedSystemFd(dirfd);
}
ret = do_mkdir(dirfd, (pathname ? pathRet : NULL), mode);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysLinkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags)
{
int ret;
char *oldpathRet = NULL;
char *newpathRet = NULL;
if (oldpath != NULL) {
ret = UserPathCopy(oldpath, &oldpathRet);
if (ret != 0) {
goto OUT;
}
}
if (newpath != NULL) {
ret = UserPathCopy(newpath, &newpathRet);
if (ret != 0) {
goto OUT;
}
}
if (olddirfd != AT_FDCWD) {
/* Process fd convert to system global fd */
olddirfd = GetAssociatedSystemFd(olddirfd);
}
if (newdirfd != AT_FDCWD) {
/* Process fd convert to system global fd */
newdirfd = GetAssociatedSystemFd(newdirfd);
}
ret = linkat(olddirfd, oldpathRet, newdirfd, newpathRet, flags);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (oldpathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, oldpathRet);
}
if (newpathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, newpathRet);
}
return ret;
}
int SysSymlinkat(const char *target, int dirfd, const char *linkpath)
{
int ret;
char *pathRet = NULL;
char *targetRet = NULL;
if (target != NULL) {
ret = UserPathCopy(target, &targetRet);
if (ret != 0) {
goto OUT;
}
}
if (linkpath != NULL) {
ret = UserPathCopy(linkpath, &pathRet);
if (ret != 0) {
goto OUT;
}
}
if (dirfd != AT_FDCWD) {
/* Process fd convert to system global fd */
dirfd = GetAssociatedSystemFd(dirfd);
}
ret = symlinkat(targetRet, dirfd, pathRet);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
if (targetRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, targetRet);
}
return ret;
}
ssize_t SysReadlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize)
{
ssize_t ret;
char *pathRet = NULL;
if (bufsize == 0) {
return -EINVAL;
}
if (pathname != NULL) {
ret = UserPathCopy(pathname, &pathRet);
if (ret != 0) {
goto OUT;
}
}
if (dirfd != AT_FDCWD) {
/* Process fd convert to system global fd */
dirfd = GetAssociatedSystemFd(dirfd);
}
if (!LOS_IsUserAddressRange((vaddr_t)(UINTPTR)buf, bufsize)) {
ret = -EFAULT;
goto OUT;
}
ret = readlinkat(dirfd, pathRet, buf, bufsize);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysUnlinkat(int dirfd, const char *pathname, int flag)
{
int ret;
char *pathRet = NULL;
if (pathname != NULL) {
ret = UserPathCopy(pathname, &pathRet);
if (ret != 0) {
goto OUT;
}
}
if (dirfd != AT_FDCWD) {
/* Process fd convert to system global fd */
dirfd = GetAssociatedSystemFd(dirfd);
}
ret = unlinkat(dirfd, (pathname ? pathRet : NULL), flag);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysRenameat(int oldfd, const char *oldpath, int newdfd, const char *newpath)
{
int ret;
char *pathOldRet = NULL;
char *pathNewRet = NULL;
if (oldpath != NULL) {
ret = UserPathCopy(oldpath, &pathOldRet);
if (ret != 0) {
goto OUT;
}
}
if (newpath != NULL) {
ret = UserPathCopy(newpath, &pathNewRet);
if (ret != 0) {
goto OUT;
}
}
if (oldfd != AT_FDCWD) {
/* Process fd convert to system global fd */
oldfd = GetAssociatedSystemFd(oldfd);
}
if (newdfd != AT_FDCWD) {
/* Process fd convert to system global fd */
newdfd = GetAssociatedSystemFd(newdfd);
}
ret = do_rename(oldfd, (oldpath ? pathOldRet : NULL), newdfd, (newpath ? pathNewRet : NULL));
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathOldRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathOldRet);
}
if (pathNewRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathNewRet);
}
return ret;
}
int SysFallocate(int fd, int mode, off_t offset, off_t len)
{
int ret;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
ret = fallocate(fd, mode, offset, len);
if (ret < 0) {
return -get_errno();
}
return ret;
}
int SysFallocate64(int fd, int mode, off64_t offset, off64_t len)
{
int ret;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
ret = fallocate64(fd, mode, offset, len);
if (ret < 0) {
return -get_errno();
}
return ret;
}
ssize_t SysPreadv(int fd, const struct iovec *iov, int iovcnt, long loffset, long hoffset)
{
off_t offsetflag;
offsetflag = (off_t)((unsigned long long)loffset | (((unsigned long long)hoffset) << HIGH_SHIFT_BIT));
int ret;
int valid_iovcnt = -1;
struct iovec *iovRet = NULL;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
if ((iov == NULL) || (iovcnt < 0) || (iovcnt > IOV_MAX)) {
return -EINVAL;
}
if (iovcnt == 0) {
return 0;
}
ret = UserIovCopy(&iovRet, iov, iovcnt, &valid_iovcnt);
if (ret != 0) {
return ret;
}
if (valid_iovcnt <= 0) {
ret = -EFAULT;
goto OUT_FREE;
}
ret = preadv(fd, iovRet, valid_iovcnt, offsetflag);
if (ret < 0) {
ret = -get_errno();
}
OUT_FREE:
(void)(void)LOS_MemFree(OS_SYS_MEM_ADDR, iovRet);
return ret;
}
ssize_t SysPwritev(int fd, const struct iovec *iov, int iovcnt, long loffset, long hoffset)
{
off_t offsetflag;
offsetflag = (off_t)((unsigned long long)loffset | (((unsigned long long)hoffset) << HIGH_SHIFT_BIT));
int ret;
int valid_iovcnt = -1;
struct iovec *iovRet = NULL;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
if ((iov == NULL) || (iovcnt < 0) || (iovcnt > IOV_MAX)) {
return -EINVAL;
}
if (iovcnt == 0) {
return 0;
}
ret = UserIovCopy(&iovRet, iov, iovcnt, &valid_iovcnt);
if (ret != 0) {
return ret;
}
if (valid_iovcnt != iovcnt) {
ret = -EFAULT;
goto OUT_FREE;
}
ret = pwritev(fd, iovRet, valid_iovcnt, offsetflag);
if (ret < 0) {
ret = -get_errno();
}
OUT_FREE:
(void)LOS_MemFree(OS_SYS_MEM_ADDR, iovRet);
return ret;
}
#ifdef LOSCFG_FS_FAT
int SysFormat(const char *dev, int sectors, int option)
{
int ret;
char *devRet = NULL;
if (!IsCapPermit(CAP_FS_FORMAT)) {
return -EPERM;
}
if (dev != NULL) {
ret = UserPathCopy(dev, &devRet);
if (ret != 0) {
goto OUT;
}
}
ret = format((dev ? devRet : NULL), sectors, option);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (devRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, devRet);
}
return ret;
}
#endif
int SysFstat64(int fd, struct stat64 *buf)
{
int ret;
struct stat64 bufRet = {0};
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
ret = fstat64(fd, (buf ? (&bufRet) : NULL));
if (ret < 0) {
return -get_errno();
}
ret = LOS_ArchCopyToUser(buf, &bufRet, sizeof(struct stat64));
if (ret != 0) {
return -EFAULT;
}
return ret;
}
int SysFcntl64(int fd, int cmd, void *arg)
{
/* Process fd convert to system global fd */
int sysfd = GetAssociatedSystemFd(fd);
int ret = VfsFcntl(fd, cmd, arg);
if (ret == CONTINE_NUTTX_FCNTL) {
ret = fcntl64(sysfd, cmd, arg);
}
if (ret < 0) {
return -get_errno();
}
return ret;
}
int SysGetdents64(int fd, struct dirent *de_user, unsigned int count)
{
if (!LOS_IsUserAddressRange((VADDR_T)(UINTPTR)de_user, count)) {
return -EFAULT;
}
struct dirent *de_knl = NULL;
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
int ret = do_readdir(fd, &de_knl, count);
if (ret < 0) {
return ret;
}
if (de_knl != NULL) {
int cpy_ret = LOS_ArchCopyToUser(de_user, de_knl, ret);
if (cpy_ret != 0)
{
return -EFAULT;
}
}
return ret;
}
char *SysRealpath(const char *path, char *resolved_path)
{
char *pathRet = NULL;
char *resolved_pathRet = NULL;
char *result = NULL;
int ret;
if (resolved_path == NULL) {
return (char *)(intptr_t)-EINVAL;
}
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
result = (char *)(intptr_t)ret;
goto OUT;
}
}
resolved_pathRet = realpath((path ? pathRet : NULL), NULL);
if (resolved_pathRet == NULL) {
result = (char *)(intptr_t)-get_errno();
goto OUT;
}
ret = LOS_ArchCopyToUser(resolved_path, resolved_pathRet, strlen(resolved_pathRet) + 1);
if (ret != 0) {
result = (char *)(intptr_t)-EFAULT;
goto OUT;
}
result = resolved_path;
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
if (resolved_pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, resolved_pathRet);
}
return result;
}
int SysUtimensat(int fd, const char *path, struct timespec times[TIMESPEC_TIMES_NUM], int flag)
{
int ret;
int timeLen;
struct IATTR attr = {0};
char *filePath = NULL;
timeLen = TIMESPEC_TIMES_NUM * sizeof(struct timespec);
CHECK_ASPACE(times, timeLen);
DUP_FROM_USER(times, timeLen);
ret = CheckNewAttrTime(&attr, times);
FREE_DUP(times);
if (ret < 0) {
goto OUT;
}
ret = GetFullpathNull(fd, path, &filePath);
if (ret < 0) {
goto OUT;
}
ret = chattr(filePath, &attr);
if (ret < 0) {
ret = -get_errno();
}
OUT:
PointerFree(filePath);
return ret;
}
int SysChmod(const char *pathname, mode_t mode)
{
int ret;
char *pathRet = NULL;
if (pathname != NULL) {
ret = UserPathCopy(pathname, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = chmod(pathRet, mode);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysFchmodat(int fd, const char *path, mode_t mode, int flag)
{
int ret;
char *pathRet = NULL;
char *fullpath = NULL;
struct IATTR attr = {
.attr_chg_mode = mode,
.attr_chg_valid = CHG_MODE,
};
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
goto OUT;
}
}
if (fd != AT_FDCWD) {
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
}
ret = vfs_normalize_pathat(fd, pathRet, &fullpath);
if (ret < 0) {
goto OUT;
}
ret = chattr(fullpath, &attr);
if (ret < 0) {
ret = -get_errno();
}
OUT:
PointerFree(pathRet);
PointerFree(fullpath);
return ret;
}
int SysFchmod(int fd, mode_t mode)
{
int ret;
int sysFd;
struct IATTR attr = {
.attr_chg_mode = mode,
.attr_chg_valid = CHG_MODE, /* change mode */
};
struct file *file = NULL;
sysFd = GetAssociatedSystemFd(fd);
if (sysFd < 0) {
return -EBADF;
}
ret = fs_getfilep(sysFd, &file);
if (ret < 0) {
return -get_errno();
}
ret = chattr(file->f_path, &attr);
if (ret < 0) {
return -get_errno();
}
return ret;
}
int SysFchownat(int fd, const char *path, uid_t owner, gid_t group, int flag)
{
int ret;
char *fullpath = NULL;
struct IATTR attr = {
.attr_chg_valid = 0,
};
ret = GetFullpath(fd, path, &fullpath);
if (ret < 0) {
goto OUT;
}
if (owner != (uid_t)-1) {
attr.attr_chg_uid = owner;
attr.attr_chg_valid |= CHG_UID;
}
if (group != (gid_t)-1) {
attr.attr_chg_gid = group;
attr.attr_chg_valid |= CHG_GID;
}
ret = chattr(fullpath, &attr);
if (ret < 0) {
ret = -get_errno();
}
OUT:
PointerFree(fullpath);
return ret;
}
int SysFchown(int fd, uid_t owner, gid_t group)
{
int ret;
int sysFd;
struct IATTR attr = {0};
attr.attr_chg_valid = 0;
struct file *file = NULL;
sysFd = GetAssociatedSystemFd(fd);
if (sysFd < 0) {
return -EBADF;
}
ret = fs_getfilep(sysFd, &file);
if (ret < 0) {
return -get_errno();
}
if (owner != (uid_t)-1) {
attr.attr_chg_uid = owner;
attr.attr_chg_valid |= CHG_UID;
}
if (group != (gid_t)-1) {
attr.attr_chg_gid = group;
attr.attr_chg_valid |= CHG_GID;
}
ret = chattr(file->f_path, &attr);
if (ret < 0) {
ret = -get_errno();
}
return ret;
}
int SysChown(const char *pathname, uid_t owner, gid_t group)
{
int ret;
char *pathRet = NULL;
if (pathname != NULL) {
ret = UserPathCopy(pathname, &pathRet);
if (ret != 0) {
goto OUT;
}
}
ret = chown(pathRet, owner, group);
if (ret < 0) {
ret = -get_errno();
}
OUT:
if (pathRet != NULL) {
(void)LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
return ret;
}
int SysFstatat64(int dirfd, const char *restrict path, struct stat *restrict buf, int flag)
{
int ret;
struct stat bufRet = {0};
char *pathRet = NULL;
char *fullpath = NULL;
if (path != NULL) {
ret = UserPathCopy(path, &pathRet);
if (ret != 0) {
goto OUT;
}
}
if (dirfd != AT_FDCWD) {
/* Process fd convert to system global fd */
dirfd = GetAssociatedSystemFd(dirfd);
}
ret = vfs_normalize_pathat(dirfd, pathRet, &fullpath);
if (ret < 0) {
goto OUT;
}
ret = stat(fullpath, &bufRet);
if (ret < 0) {
ret = -get_errno();
goto OUT;
}
ret = LOS_ArchCopyToUser(buf, &bufRet, sizeof(struct stat));
if (ret != 0) {
ret = -EFAULT;
goto OUT;
}
OUT:
if (pathRet != NULL) {
LOS_MemFree(OS_SYS_MEM_ADDR, pathRet);
}
if (fullpath != NULL) {
free(fullpath);
}
return ret;
}
int SysFaccessat(int fd, const char *filename, int amode, int flag)
{
int ret;
struct stat buf;
struct statfs fsBuf;
char *fullDirectory = NULL;
ret = GetFullpath(fd, filename, &fullDirectory);
if (ret < 0) {
goto OUT;
}
ret = statfs(fullDirectory, &fsBuf);
if (ret != 0) {
ret = -get_errno();
goto OUT;
}
if ((fsBuf.f_flags & MS_RDONLY) && ((unsigned int)amode & W_OK)) {
ret = -EROFS;
goto OUT;
}
ret = stat(fullDirectory, &buf);
if (ret != 0) {
ret = -get_errno();
goto OUT;
}
if (VfsPermissionCheck(buf.st_uid, buf.st_gid, buf.st_mode, amode)) {
ret = -EACCES;
}
OUT:
PointerFree(fullDirectory);
return ret;
}
int SysFstatfs(int fd, struct statfs *buf)
{
int ret;
struct file *filep = NULL;
struct statfs bufRet = {0};
/* Process fd convert to system global fd */
fd = GetAssociatedSystemFd(fd);
ret = fs_getfilep(fd, &filep);
if (ret < 0) {
ret = -get_errno();
return ret;
}
ret = statfs(filep->f_path, &bufRet);
if (ret < 0) {
ret = -get_errno();
return ret;
}
ret = LOS_ArchCopyToUser(buf, &bufRet, sizeof(struct statfs));
if (ret != 0) {
ret = -EFAULT;
}
return ret;
}
int SysFstatfs64(int fd, size_t sz, struct statfs *buf)
{
int ret = 0;
if (sz != sizeof(struct statfs)) {
ret = -EINVAL;
return ret;
}
ret = SysFstatfs(fd, buf);
return ret;
}
int SysPpoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, const sigset_t *sigMask, int nsig)
{
int timeout;
int ret;
sigset_t_l origMask;
sigset_t_l setl;
if (sigMask == NULL) {
ret = -EINVAL;
return ret;
}
CHECK_ASPACE(tmo_p, sizeof(struct timespec));
CHECK_ASPACE(sigMask, sizeof(sigset_t));
CPY_FROM_USER(tmo_p);
CPY_FROM_USER(sigMask);
timeout = (tmo_p == NULL) ? -1 : (tmo_p->tv_sec * OS_SYS_US_PER_MS + tmo_p->tv_nsec / OS_SYS_NS_PER_MS);
if (timeout & 0x80000000) {
ret = -EINVAL;
return ret;
}
setl.sig[0] = *sigMask;
OsSigprocMask(SIG_SETMASK, &setl, &origMask);
ret = SysPoll(fds, nfds, timeout);
if (ret < 0) {
ret = -get_errno();
}
OsSigprocMask(SIG_SETMASK, &origMask, NULL);
PointerFree(tmo_pbak);
PointerFree(sigMaskbak);
return (ret == -1) ? -get_errno() : ret;
}
int SysPselect6(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
const struct timespec *timeout, const long data[2])
{
int ret;
int retVal;
sigset_t_l origMask;
sigset_t_l setl;
CHECK_ASPACE(readfds, sizeof(fd_set));
CHECK_ASPACE(writefds, sizeof(fd_set));
CHECK_ASPACE(exceptfds, sizeof(fd_set));
CHECK_ASPACE(timeout, sizeof(struct timeval));
CPY_FROM_USER(readfds);
CPY_FROM_USER(writefds);
CPY_FROM_USER(exceptfds);
DUP_FROM_USER(timeout, sizeof(struct timeval));
((struct timeval *)timeout)->tv_usec = timeout->tv_nsec / 1000; /* 1000, convert ns to us */
if (data != NULL) {
retVal = LOS_ArchCopyFromUser(&(setl.sig[0]), (int *)data[0], sizeof(sigset_t));
if (retVal != 0) {
ret = -EFAULT;
FREE_DUP(timeout);
return ret;
}
}
OsSigprocMask(SIG_SETMASK, &setl, &origMask);
ret = do_select(nfds, readfds, writefds, exceptfds, (struct timeval *)timeout, UserPoll);
if (ret < 0) {
/* do not copy parameter back to user mode if do_select failed */
ret = -get_errno();
FREE_DUP(timeout);
return ret;
}
OsSigprocMask(SIG_SETMASK, &origMask, NULL);
CPY_TO_USER(readfds);
CPY_TO_USER(writefds);
CPY_TO_USER(exceptfds);
FREE_DUP(timeout);
return ret;
}
#endif