diff options
Diffstat (limited to 'components/lwp/syscall/syscall_file_path.c')
| -rw-r--r-- | components/lwp/syscall/syscall_file_path.c | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/components/lwp/syscall/syscall_file_path.c b/components/lwp/syscall/syscall_file_path.c new file mode 100644 index 0000000000..bf086098a3 --- /dev/null +++ b/components/lwp/syscall/syscall_file_path.c @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2006-2025 RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "syscall_internal.h" + +/** + * @brief Gets the current working directory. + * + * This function retrieves the absolute pathname of the current working directory + * and stores it in the provided buffer. The buffer must be large enough to hold + * the directory path, including the null-terminator. If the buffer is too small, + * the function will return an error. + * + * @param[out] buf A pointer to a buffer where the current working directory + * path will be stored. The buffer should be large enough + * to hold the path, including the null-terminator. + * @param[in] size The size of the buffer in bytes. The buffer must be large enough + * to accommodate the full path. + * + * @return long On success, returns the number of bytes written to the buffer + * (not including the null-terminator). If the buffer is not large + * enough, returns a negative error code. + * + * @note The maximum path length depends on the system's configuration. + * Ensure the buffer size is sufficient to hold the entire path. + * + * @see sys_chdir(), sys_getcwd_r(), sys_realpath() + */ +long sys_getcwd(char *buf, size_t size) +{ + char *tmp = RT_NULL; + long ret = -1; + + if (!lwp_user_accessable((void *)buf, size)) + { + return ret; + } + + tmp = (char *)rt_malloc(size); + if (!tmp) + { + return ret; + } + + if (getcwd(tmp, size) != RT_NULL) + { + if (lwp_put_to_user(buf, tmp, size) > 0) + { + if (buf != RT_NULL) + { + ret = strlen(buf); + } + else + { + ret = -EFAULT; + } + } + } + + rt_free(tmp); + + return ret; +} + +/** + * @brief Changes the current working directory. + * + * This function changes the current working directory of the calling process + * to the directory specified by the given path. The path can be absolute or + * relative. If the specified path does not exist or the process does not have + * sufficient permissions, the function will return an error. + * + * @param[in] path The path to the new working directory. This can be either + * an absolute or a relative path. + * + * @return sysret_t Returns `0` on success, indicating that the working + * directory was successfully changed. On failure, returns a + * negative error code indicating the reason for failure. + * + * @note If the specified path is a relative path, it is interpreted relative + * to the current working directory. + * + * @see sys_getcwd(), sys_chdir() for changing directories, sys_opendir(), sys_stat() + */ +sysret_t sys_chdir(const char *path) +{ +#ifdef ARCH_MM_MMU + int err = 0; + int len = 0; + int errcode; + char *kpath = RT_NULL; + + len = lwp_user_strlen(path); + if (len <= 0) + { + return -EFAULT; + } + + kpath = (char *)kmem_get(len + 1); + if (!kpath) + { + return -ENOMEM; + } + + if (lwp_get_from_user(kpath, (void *)path, len + 1) != (len + 1)) + { + kmem_put(kpath); + return -EINVAL; + } + + err = chdir(kpath); + errcode = err != 0 ? GET_ERRNO() : 0; + + kmem_put(kpath); + + return errcode; +#else + int ret = chdir(path); + return (ret < 0 ? GET_ERRNO() : ret); +#endif +} + +/** + * @brief Changes the current working directory to the one associated with the specified file descriptor. + * + * This function changes the current working directory of the calling process + * to the directory associated with the file descriptor `fd`. The file descriptor + * should refer to an open directory. If the file descriptor does not refer to a + * directory, or if the process lacks the necessary permissions, the function will + * return an error. + * + * @param[in] fd The file descriptor referring to the directory to which the current + * working directory should be changed. + * + * @return sysret_t Returns `0` on success, indicating the current working directory + * was successfully changed. On failure, returns a negative error code. + * + * @note The file descriptor must refer to a directory. If it refers to a file or other + * non-directory object, the operation will fail. + * + * @see sys_chdir(), sys_getcwd(), sys_opendir(), sys_open() + */ +sysret_t sys_fchdir(int fd) +{ + int errcode = -ENOSYS; +#ifdef ARCH_MM_MMU +#ifdef RT_USING_DFS_V2 + int err = -1; + struct dfs_file *d; + char *kpath; + + d = fd_get(fd); + if (!d || !d->vnode) + { + return -EBADF; + } + kpath = dfs_dentry_full_path(d->dentry); + if (!kpath) + { + return -EACCES; + } + + err = chdir(kpath); + errcode = err != 0 ? GET_ERRNO() : 0; + + kmem_put(kpath); +#endif +#endif + return errcode; +} + +/** + * @brief Creates a new directory with the specified path and mode. + * + * This function creates a new directory with the specified path and mode. + * The directory is created with the permissions specified by the `mode` parameter. + * If the directory already exists, the function will return an error. + * + * @param[in] path The path of the directory to be created. This can be an absolute + * or relative path. If the directory does not exist, it will be created. + * @param[in] mode The permissions to be set for the new directory. This parameter + * specifies the access permissions for the directory owner, group, and others. + * + * @return sysret_t Returns `0` on success, indicating that the directory was successfully + * created. On failure, returns a negative error code indicating the reason for failure. + * + * @note The `mode` parameter specifies the permissions for the new directory. The permissions + * are typically specified using the `S_IRWXU`, `S_IRWXG`, and `S_IRWXO` macros, which + * define the read, write, and execute permissions for the owner, group, and others. + * + * @see sys_rmdir(), sys_chdir(), sys_mkdirat() + */ +sysret_t sys_mkdir(const char *path, mode_t mode) +{ +#ifdef ARCH_MM_MMU + int err = 0; + int len = 0; + char *kpath = RT_NULL; + + len = lwp_user_strlen(path); + if (len <= 0) + { + return -EFAULT; + } + + kpath = (char *)kmem_get(len + 1); + if (!kpath) + { + return -ENOMEM; + } + + if (lwp_get_from_user(kpath, (void *)path, len + 1) != (len + 1)) + { + kmem_put(kpath); + return -EINVAL; + } + + err = _SYS_WRAP(mkdir(kpath, mode)); + + kmem_put(kpath); + + return err; +#else + int ret = mkdir(path, mode); + return (ret < 0 ? GET_ERRNO() : ret); +#endif +} + +/** + * @brief Removes the specified directory. + * + * This function removes the directory specified by the given path. The directory + * must be empty for the operation to succeed. If the directory is not empty, the + * function will return an error. If the directory does not exist or the process + * lacks the necessary permissions, the function will also return an error. + * + * @param[in] path The path of the directory to be removed. This can be an absolute + * or relative path. The directory must be empty for the operation to succeed. + * + * @return sysret_t Returns `0` on success, indicating that the directory was successfully + * removed. On failure, returns a negative error code indicating the reason for failure. + * + * @note The directory must be empty for the operation to succeed. If the directory contains + * files or subdirectories, the operation will fail. To remove a non-empty directory, + * the contents must be deleted first. + * + * @see sys_mkdir(), sys_chdir(), sys_rmdirat() + */ +sysret_t sys_rmdir(const char *path) +{ + int err = 0; + int ret = 0; +#ifdef ARCH_MM_MMU + int len = 0; + char *kpath = RT_NULL; + + len = lwp_user_strlen(path); + if (len <= 0) + { + return -EFAULT; + } + + kpath = (char *)kmem_get(len + 1); + if (!kpath) + { + return -ENOMEM; + } + + if (lwp_get_from_user(kpath, (void *)path, len + 1) != (len + 1)) + { + kmem_put(kpath); + return -EINVAL; + } + + ret = rmdir(kpath); + if (ret < 0) + { + err = GET_ERRNO(); + } + + kmem_put(kpath); + + return (err < 0 ? err : ret); +#else + ret = rmdir(path); + if (ret < 0) + { + err = GET_ERRNO(); + } + return (err < 0 ? err : ret); +#endif +} + +/** + * @brief Reads directory entries. + * + * This function reads the directory entries from the directory stream specified by the file descriptor `fd`. + * It stores the directory entries in the buffer pointed to by `dirp`, up to the specified number of bytes (`nbytes`). + * The entries are returned in a format compatible with the `struct libc_dirent` structure. + * + * @param[in] fd The file descriptor referring to an open directory. This descriptor must be obtained + * from a call to `sys_open()` with the appropriate flags for directory reading. + * @param[out] dirp A pointer to a buffer where the directory entries will be stored. + * The buffer must be large enough to hold at least `nbytes` bytes of directory entries. + * @param[in] nbytes The size of the buffer (`dirp`) in bytes. It limits the number of directory entries + * that can be read in a single call. The function will return as many entries as possible + * that fit within the buffer size. + * + * @return sysret_t Returns the number of bytes read on success, which may be less than `nbytes` if there + * are fewer entries in the directory or if the buffer is too small. + * On failure, returns a negative error code. + * + * @note If the function returns 0, it indicates the end of the directory stream. A negative return value + * indicates an error. The caller can use the returned number of bytes to process the entries in `dirp`. + * + * @see sys_open(), sys_close(), sys_readdir(), sys_stat() + */ +sysret_t sys_getdents(int fd, struct libc_dirent *dirp, size_t nbytes) +{ + int ret = -1; + struct dfs_file *file; + size_t cnt = (nbytes / sizeof(struct libc_dirent)); + size_t rtt_nbytes = 0; + struct dirent *rtt_dirp; + +#ifdef ARCH_MM_MMU + if (!lwp_user_accessable((void *)dirp, sizeof(struct libc_dirent))) + { + return -EFAULT; + } +#endif + + if (cnt == 0) + { + return -EINVAL; + } + rtt_nbytes = cnt * sizeof(struct dirent); + rtt_dirp = (struct dirent *)rt_malloc(rtt_nbytes); + if (!rtt_dirp) + { + return -ENOMEM; + } + file = fd_get(fd); + ret = dfs_file_getdents(file, rtt_dirp, rtt_nbytes); + if (ret > 0) + { + size_t i = 0; + cnt = ret / sizeof(struct dirent); + for (i = 0; i < cnt; i++) + { + dirp[i].d_ino = 0; + dirp[i].d_off = i * sizeof(struct libc_dirent); + dirp[i].d_type = rtt_dirp[i].d_type; + dirp[i].d_reclen = sizeof(struct libc_dirent); + strcpy(dirp[i].d_name, rtt_dirp[i].d_name); + } + ret = cnt * sizeof(struct libc_dirent); + } + + if (ret < 0) + { + ret = GET_ERRNO(); + } + + rt_free(rtt_dirp); + + return ret; +} + +/** + * @brief Retrieves the current value of the error code. + * + * This function returns the most recent error code set by a system call. The error code is typically set + * when a system call fails. This function allows users to retrieve the last error that occurred, helping to + * diagnose issues or handle errors in a more controlled manner. + * + * @return sysret_t The current error code. A value of `0` indicates no error, while a non-zero value + * represents the most recent error. The error codes are system-specific and can + * represent various failure conditions (e.g., `EINVAL`, `ENOMEM`, `EIO`). + * + * @note The error code returned is specific to the current thread or process and is typically updated + * each time a system call fails. The error code is persistent until it is overwritten by the next + * failed system call or explicitly reset. + * + * @see sys_set_errno(), sys_perror(), sys_strerror() + */ +sysret_t sys_access(const char *filename, int mode) +{ + int ret = 0; +#ifdef ARCH_MM_MMU + rt_size_t len = 0; + char *kfilename = RT_NULL; + + len = lwp_user_strlen(filename); + if (len <= 0) + { + return -EINVAL; + } + + kfilename = (char *)kmem_get(len + 1); + if (!kfilename) + { + return -ENOMEM; + } + + if (lwp_get_from_user(kfilename, (void *)filename, len + 1) != (len + 1)) + { + kmem_put(kfilename); + return -EFAULT; + } + + ret = access(kfilename, mode); + if (ret < 0) + { + ret = GET_ERRNO(); + } + + kmem_put(kfilename); + return ret; +#else + ret = access(filename, mode); + return (ret < 0 ? GET_ERRNO() : ret); +#endif +} + +/** + * @brief Creates a pipe, a unidirectional data channel. + * + * This function creates a pipe, which is a unidirectional data channel used for inter-process communication. + * The pipe consists of two file descriptors: one for reading from the pipe and one for writing to the pipe. + * The pipe is used for passing data between processes or threads, typically in a producer-consumer scenario. + * + * @param[out] fd An array of two integers where the file descriptors for the read and write ends of the pipe will be stored. + * - `fd[0]`: The file descriptor for reading from the pipe. + * - `fd[1]`: The file descriptor for writing to the pipe. + * + * @return sysret_t Returns `0` on success. On failure, returns a negative error code. + * + * @note The pipe created by this function is typically used for simple communication between processes or threads. + * The data written to `fd[1]` can be read from `fd[0]`. After usage, both file descriptors should be closed. + * + * @see sys_read(), sys_write(), sys_close(), sys_fork(), sys_execve() + */ +sysret_t sys_pipe(int fd[2]) +{ + int ret; + int kfd[2] = { 0, 0 }; + + if (!lwp_user_accessable((void *)fd, sizeof(int[2]))) + { + return -EFAULT; + } + + ret = pipe(kfd); + + lwp_put_to_user((void *)fd, kfd, sizeof(int[2])); + + return (ret < 0 ? GET_ERRNO() : ret); +} |
