summaryrefslogtreecommitdiff
path: root/components/lwp/syscall/syscall_file_path.c
diff options
context:
space:
mode:
Diffstat (limited to 'components/lwp/syscall/syscall_file_path.c')
-rw-r--r--components/lwp/syscall/syscall_file_path.c462
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);
+}