|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
- * Copyright (c) 2006-2023, RT-Thread Development Team
|
|
|
|
|
|
+ * Copyright (c) 2006-2025 RT-Thread Development Team
|
|
*
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
*
|
|
@@ -39,6 +39,21 @@ static struct rt_mutex fslock;
|
|
static struct rt_mutex fdlock;
|
|
static struct rt_mutex fdlock;
|
|
static struct dfs_fdtable _fdtab = {0};
|
|
static struct dfs_fdtable _fdtab = {0};
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Expand the file descriptor table to accommodate a specified file descriptor
|
|
|
|
+ *
|
|
|
|
+ * This function ensures that the file descriptor table in the given `dfs_fdtable` structure
|
|
|
|
+ * has sufficient capacity to include the specified file descriptor `fd`. If the table
|
|
|
|
+ * needs to be expanded, it reallocates memory and initializes new slots to `NULL`.
|
|
|
|
+ *
|
|
|
|
+ * @param[in,out] fdt Pointer to the file descriptor table to be expanded
|
|
|
|
+ * @param[in] fd The file descriptor that needs to be accommodated
|
|
|
|
+ *
|
|
|
|
+ * @return int The input file descriptor if successful (fd >= 0),
|
|
|
|
+ * -1 if expansion failed or fd exceeds maximum allowed value (DFS_FD_MAX)
|
|
|
|
+ *
|
|
|
|
+ * @note Expand table size to next multiple of 4 (but not exceeding DFS_FD_MAX)
|
|
|
|
+ */
|
|
static int _fdt_slot_expand(struct dfs_fdtable *fdt, int fd)
|
|
static int _fdt_slot_expand(struct dfs_fdtable *fdt, int fd)
|
|
{
|
|
{
|
|
int nr;
|
|
int nr;
|
|
@@ -76,6 +91,17 @@ static int _fdt_slot_expand(struct dfs_fdtable *fdt, int fd)
|
|
return fd;
|
|
return fd;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Allocate an available file descriptor slot in the file descriptor table
|
|
|
|
+ *
|
|
|
|
+ * @param[in,out] fdt Pointer to the file descriptor table to allocate from
|
|
|
|
+ * @param[in] startfd The starting file descriptor index to begin searching
|
|
|
|
+ *
|
|
|
|
+ * @return int The allocated file descriptor index if successful (>= 0),
|
|
|
|
+ * -1 if allocation failed (table expansion failed)
|
|
|
|
+ *
|
|
|
|
+ * @note If no empty slot found, expand the table and return the new index.
|
|
|
|
+ */
|
|
static int _fdt_slot_alloc(struct dfs_fdtable *fdt, int startfd)
|
|
static int _fdt_slot_alloc(struct dfs_fdtable *fdt, int startfd)
|
|
{
|
|
{
|
|
int idx;
|
|
int idx;
|
|
@@ -103,6 +129,18 @@ static int _fdt_slot_alloc(struct dfs_fdtable *fdt, int startfd)
|
|
return idx;
|
|
return idx;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Allocate a file descriptor from the file descriptor table
|
|
|
|
+ *
|
|
|
|
+ * @param[in,out] fdt Pointer to the file descriptor table to allocate from
|
|
|
|
+ * @param[in] startfd The starting file descriptor index to begin searching
|
|
|
|
+ *
|
|
|
|
+ * @return int The allocated file descriptor index if successful (>= 0),
|
|
|
|
+ * -1 if allocation failed
|
|
|
|
+ *
|
|
|
|
+ * @note This is a wrapper function that calls _fdt_slot_alloc() to perform
|
|
|
|
+ * the actual allocation. It maintains the same behavior as _fdt_slot_alloc().
|
|
|
|
+ */
|
|
static int _fdt_fd_alloc(struct dfs_fdtable *fdt, int startfd)
|
|
static int _fdt_fd_alloc(struct dfs_fdtable *fdt, int startfd)
|
|
{
|
|
{
|
|
int idx;
|
|
int idx;
|
|
@@ -130,7 +168,7 @@ rt_err_t dfs_lock(void)
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * this function will lock device file system.
|
|
|
|
|
|
+ * this function will unlock device file system.
|
|
*
|
|
*
|
|
* @note please don't invoke it on ISR.
|
|
* @note please don't invoke it on ISR.
|
|
*/
|
|
*/
|
|
@@ -144,6 +182,17 @@ void dfs_unlock(void)
|
|
*
|
|
*
|
|
* @{
|
|
* @{
|
|
*/
|
|
*/
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * @brief Lock the file descriptor table mutex
|
|
|
|
+ *
|
|
|
|
+ * @return rt_err_t RT_EOK if lock acquired successfully,
|
|
|
|
+ * -RT_ENOSYS if filesystem not initialized,
|
|
|
|
+ * -RT_EBUSY if mutex is already locked (retries until acquired)
|
|
|
|
+ *
|
|
|
|
+ * @note This function will block indefinitely until the lock is acquired.
|
|
|
|
+ * Should not be called from interrupt service routines.
|
|
|
|
+ */
|
|
rt_err_t dfs_file_lock(void)
|
|
rt_err_t dfs_file_lock(void)
|
|
{
|
|
{
|
|
rt_err_t result = -RT_EBUSY;
|
|
rt_err_t result = -RT_EBUSY;
|
|
@@ -161,6 +210,13 @@ rt_err_t dfs_file_lock(void)
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Unlock the file descriptor table mutex
|
|
|
|
+ *
|
|
|
|
+ * @note This function releases the lock acquired by dfs_file_lock().
|
|
|
|
+ * Should be called in the same context as the corresponding lock.
|
|
|
|
+ * Should not be called from interrupt service routines.
|
|
|
|
+ */
|
|
void dfs_file_unlock(void)
|
|
void dfs_file_unlock(void)
|
|
{
|
|
{
|
|
rt_mutex_release(&fdlock);
|
|
rt_mutex_release(&fdlock);
|
|
@@ -181,7 +237,7 @@ int dfs_init(void)
|
|
rt_mutex_init(&fslock, "fslock", RT_IPC_FLAG_FIFO);
|
|
rt_mutex_init(&fslock, "fslock", RT_IPC_FLAG_FIFO);
|
|
rt_mutex_init(&fdlock, "fdlock", RT_IPC_FLAG_FIFO);
|
|
rt_mutex_init(&fdlock, "fdlock", RT_IPC_FLAG_FIFO);
|
|
|
|
|
|
- /* clean fd table */
|
|
|
|
|
|
+ /* Initialize dentry system */
|
|
dfs_dentry_init();
|
|
dfs_dentry_init();
|
|
|
|
|
|
_dfs_init_ok = RT_TRUE;
|
|
_dfs_init_ok = RT_TRUE;
|
|
@@ -190,6 +246,12 @@ int dfs_init(void)
|
|
}
|
|
}
|
|
INIT_PREV_EXPORT(dfs_init);
|
|
INIT_PREV_EXPORT(dfs_init);
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Create and initialize a new file descriptor structure
|
|
|
|
+ *
|
|
|
|
+ * @return struct dfs_file* Pointer to the newly created file descriptor structure,
|
|
|
|
+ * NULL if memory allocation failed
|
|
|
|
+ */
|
|
struct dfs_file* dfs_file_create(void)
|
|
struct dfs_file* dfs_file_create(void)
|
|
{
|
|
{
|
|
struct dfs_file *file;
|
|
struct dfs_file *file;
|
|
@@ -205,6 +267,11 @@ struct dfs_file* dfs_file_create(void)
|
|
return file;
|
|
return file;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Destroy and free a file descriptor structure
|
|
|
|
+ *
|
|
|
|
+ * @param[in] file Pointer to the file descriptor structure to be destroyed
|
|
|
|
+ */
|
|
void dfs_file_destroy(struct dfs_file *file)
|
|
void dfs_file_destroy(struct dfs_file *file)
|
|
{
|
|
{
|
|
rt_mutex_detach(&file->pos_lock);
|
|
rt_mutex_detach(&file->pos_lock);
|
|
@@ -219,9 +286,14 @@ void dfs_file_destroy(struct dfs_file *file)
|
|
|
|
|
|
/**
|
|
/**
|
|
* @ingroup group_fs_file_descriptor
|
|
* @ingroup group_fs_file_descriptor
|
|
- * This function will allocate a file descriptor.
|
|
|
|
*
|
|
*
|
|
- * @return -1 on failed or the allocated file descriptor.
|
|
|
|
|
|
+ * @brief Allocate a new file descriptor in the file descriptor table
|
|
|
|
+ *
|
|
|
|
+ * @param[in,out] fdt Pointer to the file descriptor table to allocate from
|
|
|
|
+ *
|
|
|
|
+ * @return int The allocated file descriptor index if successful (>= 0),
|
|
|
|
+ * -RT_ENOSYS if filesystem lock failed,
|
|
|
|
+ * -1 if allocation failed (no empty slots or memory allocation failed)
|
|
*/
|
|
*/
|
|
int fdt_fd_new(struct dfs_fdtable *fdt)
|
|
int fdt_fd_new(struct dfs_fdtable *fdt)
|
|
{
|
|
{
|
|
@@ -269,6 +341,12 @@ int fdt_fd_new(struct dfs_fdtable *fdt)
|
|
return idx;
|
|
return idx;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Release a file descriptor from the file descriptor table
|
|
|
|
+ *
|
|
|
|
+ * @param[in,out] fdt Pointer to the file descriptor table
|
|
|
|
+ * @param[in] fd The file descriptor to be released
|
|
|
|
+ */
|
|
void fdt_fd_release(struct dfs_fdtable *fdt, int fd)
|
|
void fdt_fd_release(struct dfs_fdtable *fdt, int fd)
|
|
{
|
|
{
|
|
if (fd < fdt->maxfd)
|
|
if (fd < fdt->maxfd)
|
|
@@ -320,6 +398,17 @@ struct dfs_file *fdt_get_file(struct dfs_fdtable *fdt, int fd)
|
|
return f;
|
|
return f;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Associate a file structure with a file descriptor in the file descriptor table
|
|
|
|
+ *
|
|
|
|
+ * @param[in,out] fdt Pointer to the file descriptor table
|
|
|
|
+ * @param[in] fd The file descriptor to associate with
|
|
|
|
+ * @param[in] file Pointer to the file structure to associate
|
|
|
|
+ *
|
|
|
|
+ * @return int The file descriptor if successful (>= 0),
|
|
|
|
+ * -1 if association failed (invalid parameters or fd already in use),
|
|
|
|
+ * -RT_ENOSYS if filesystem lock failed
|
|
|
|
+ */
|
|
int fdt_fd_associate_file(struct dfs_fdtable *fdt, int fd, struct dfs_file *file)
|
|
int fdt_fd_associate_file(struct dfs_fdtable *fdt, int fd, struct dfs_file *file)
|
|
{
|
|
{
|
|
int retfd = -1;
|
|
int retfd = -1;
|
|
@@ -359,6 +448,12 @@ exit:
|
|
return retfd;
|
|
return retfd;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Allocate a new file descriptor in current process's file descriptor table
|
|
|
|
+ *
|
|
|
|
+ * @return int The allocated file descriptor index if successful (>= 0),
|
|
|
|
+ * -1 if allocation failed
|
|
|
|
+ */
|
|
int fd_new(void)
|
|
int fd_new(void)
|
|
{
|
|
{
|
|
struct dfs_fdtable *fdt;
|
|
struct dfs_fdtable *fdt;
|
|
@@ -381,6 +476,14 @@ void fd_release(int fd)
|
|
fdt_fd_release(fdt, fd);
|
|
fdt_fd_release(fdt, fd);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Get file structure by file descriptor from current process's fd table
|
|
|
|
+ *
|
|
|
|
+ * @param[in] fd The file descriptor to lookup
|
|
|
|
+ *
|
|
|
|
+ * @return struct dfs_file* Pointer to the file structure if found,
|
|
|
|
+ * NULL if invalid fd or file not found
|
|
|
|
+ */
|
|
struct dfs_file *fd_get(int fd)
|
|
struct dfs_file *fd_get(int fd)
|
|
{
|
|
{
|
|
struct dfs_fdtable *fdt;
|
|
struct dfs_fdtable *fdt;
|
|
@@ -417,6 +520,14 @@ struct dfs_fdtable *dfs_fdtable_get(void)
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef RT_USING_SMART
|
|
#ifdef RT_USING_SMART
|
|
|
|
+/**
|
|
|
|
+ * @brief Get file structure by file descriptor from current process's fd table
|
|
|
|
+ *
|
|
|
|
+ * @param[in] fd The file descriptor to lookup
|
|
|
|
+ *
|
|
|
|
+ * @return struct dfs_file* Pointer to the file structure if found,
|
|
|
|
+ * NULL if invalid fd or file not found
|
|
|
|
+ */
|
|
struct dfs_fdtable *dfs_fdtable_get_from_pid(int pid)
|
|
struct dfs_fdtable *dfs_fdtable_get_from_pid(int pid)
|
|
{
|
|
{
|
|
struct rt_lwp *lwp = RT_NULL;
|
|
struct rt_lwp *lwp = RT_NULL;
|
|
@@ -434,6 +545,11 @@ struct dfs_fdtable *dfs_fdtable_get_from_pid(int pid)
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Get the global file descriptor table
|
|
|
|
+ *
|
|
|
|
+ * @return struct dfs_fdtable* Pointer to the global file descriptor table
|
|
|
|
+ */
|
|
struct dfs_fdtable *dfs_fdtable_get_global(void)
|
|
struct dfs_fdtable *dfs_fdtable_get_global(void)
|
|
{
|
|
{
|
|
return &_fdtab;
|
|
return &_fdtab;
|
|
@@ -442,11 +558,11 @@ struct dfs_fdtable *dfs_fdtable_get_global(void)
|
|
/**
|
|
/**
|
|
* @brief Dup the specified fd_src from fdt_src to fdt_dst.
|
|
* @brief Dup the specified fd_src from fdt_src to fdt_dst.
|
|
*
|
|
*
|
|
- * @param fdt_dst is the fd table for destination, if empty, use global (_fdtab).
|
|
|
|
|
|
+ * @param[out] fdt_dst is the fd table for destination, if empty, use global (_fdtab).
|
|
*
|
|
*
|
|
- * @param fdt_src is the fd table for source, if empty, use global (_fdtab).
|
|
|
|
|
|
+ * @param[in] fdt_src is the fd table for source, if empty, use global (_fdtab).
|
|
*
|
|
*
|
|
- * @param fd_src is the fd in the designate fdt_src table.
|
|
|
|
|
|
+ * @param[in] fd_src is the fd in the designate fdt_src table.
|
|
*
|
|
*
|
|
* @return -1 on failed or the allocated file descriptor.
|
|
* @return -1 on failed or the allocated file descriptor.
|
|
*/
|
|
*/
|
|
@@ -540,6 +656,16 @@ int dfs_fdtable_drop_fd(struct dfs_fdtable *fdt, int fd)
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Duplicate a file descriptor in the current process's file descriptor table
|
|
|
|
+ *
|
|
|
|
+ * @param[in] oldfd The file descriptor to duplicate
|
|
|
|
+ * @param[in] startfd The starting index to search for an available file descriptor slot
|
|
|
|
+ *
|
|
|
|
+ * @return int The new file descriptor if successful (>=0),
|
|
|
|
+ * -1 if failed (invalid fd or allocation failed),
|
|
|
|
+ * -RT_ENOSYS if filesystem lock failed
|
|
|
|
+ */
|
|
int dfs_dup(int oldfd, int startfd)
|
|
int dfs_dup(int oldfd, int startfd)
|
|
{
|
|
{
|
|
int newfd = -1;
|
|
int newfd = -1;
|
|
@@ -576,11 +702,10 @@ exit:
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * @brief The fd in the current process dup to designate fd table.
|
|
|
|
- *
|
|
|
|
- * @param oldfd is the fd in current process.
|
|
|
|
|
|
+ * @brief Duplicate a file descriptor from current process to target file descriptor table
|
|
*
|
|
*
|
|
- * @param fdtab is the fd table to dup, if empty, use global (_fdtab).
|
|
|
|
|
|
+ * @param[in] oldfd is the fd in current process.
|
|
|
|
+ * @param[in,out] fdtab is the fd table to dup, if empty, use global (_fdtab).
|
|
*
|
|
*
|
|
* @return -1 on failed or the allocated file descriptor.
|
|
* @return -1 on failed or the allocated file descriptor.
|
|
*/
|
|
*/
|
|
@@ -625,11 +750,10 @@ exit:
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * @brief The fd in the designate fd table dup to current process.
|
|
|
|
- *
|
|
|
|
- * @param oldfd is the fd in the designate fd table.
|
|
|
|
|
|
+ * @brief Duplicate a file descriptor from source table to current process
|
|
*
|
|
*
|
|
- * @param fdtab is the fd table for oldfd, if empty, use global (_fdtab).
|
|
|
|
|
|
+ * @param[in] oldfd is the fd in the designate fd table.
|
|
|
|
+ * @param[in,out] fdtab is the fd table for oldfd, if empty, use global (_fdtab).
|
|
*
|
|
*
|
|
* @return -1 on failed or the allocated file descriptor.
|
|
* @return -1 on failed or the allocated file descriptor.
|
|
*/
|
|
*/
|
|
@@ -680,6 +804,14 @@ exit:
|
|
return newfd;
|
|
return newfd;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief System call to duplicate a file descriptor
|
|
|
|
+ *
|
|
|
|
+ * @param[in] oldfd The file descriptor to duplicate
|
|
|
|
+ *
|
|
|
|
+ * @return sysret_t/int The new file descriptor if successful (>=0),
|
|
|
|
+ * negative error code if failed
|
|
|
|
+ */
|
|
#ifdef RT_USING_SMART
|
|
#ifdef RT_USING_SMART
|
|
sysret_t sys_dup(int oldfd)
|
|
sysret_t sys_dup(int oldfd)
|
|
#else
|
|
#else
|
|
@@ -700,6 +832,16 @@ int sys_dup(int oldfd)
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief System call to duplicate a file descriptor to a specific descriptor number
|
|
|
|
+ *
|
|
|
|
+ * @param[in] oldfd The file descriptor to duplicate
|
|
|
|
+ * @param[in] newfd The desired file descriptor number
|
|
|
|
+ *
|
|
|
|
+ * @return rt_err_t The new file descriptor number if successful (>=0),
|
|
|
|
+ * -RT_ENOSYS if filesystem lock failed,
|
|
|
|
+ * -1 if operation failed (invalid descriptors or allocation failed)
|
|
|
|
+ */
|
|
rt_err_t sys_dup2(int oldfd, int newfd)
|
|
rt_err_t sys_dup2(int oldfd, int newfd)
|
|
{
|
|
{
|
|
struct dfs_fdtable *fdt = NULL;
|
|
struct dfs_fdtable *fdt = NULL;
|
|
@@ -760,12 +902,13 @@ exit:
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * this function will return a sub-path name under directory.
|
|
|
|
|
|
+ * @brief Get the subdirectory path relative to a parent directory
|
|
*
|
|
*
|
|
- * @param directory the parent directory.
|
|
|
|
- * @param filename the filename.
|
|
|
|
|
|
+ * @param[in] directory The parent directory path
|
|
|
|
+ * @param[in] filename The full path including parent directory and subpath
|
|
*
|
|
*
|
|
- * @return the subdir pointer in filename
|
|
|
|
|
|
+ * @return const char* Pointer to the subdirectory portion of filename,
|
|
|
|
+ * NULL if paths are identical or invalid
|
|
*/
|
|
*/
|
|
const char *dfs_subdir(const char *directory, const char *filename)
|
|
const char *dfs_subdir(const char *directory, const char *filename)
|
|
{
|
|
{
|
|
@@ -785,13 +928,21 @@ const char *dfs_subdir(const char *directory, const char *filename)
|
|
RTM_EXPORT(dfs_subdir);
|
|
RTM_EXPORT(dfs_subdir);
|
|
|
|
|
|
/**
|
|
/**
|
|
- * this function will normalize a path according to specified parent directory
|
|
|
|
- * and file name.
|
|
|
|
|
|
+ * @brief Normalize a path by combining directory and filename into an absolute path
|
|
*
|
|
*
|
|
- * @param directory the parent path
|
|
|
|
- * @param filename the file name
|
|
|
|
|
|
+ * @param[in] directory The parent directory path (NULL means use working directory)
|
|
|
|
+ * @param[in] filename The filename or relative path to be normalized
|
|
*
|
|
*
|
|
- * @return the built full file path (absolute path)
|
|
|
|
|
|
+ * @return char* The normalized absolute path (must be freed by caller),
|
|
|
|
+ * NULL if path is invalid or memory allocation fails
|
|
|
|
+ *
|
|
|
|
+ * @note This function will:
|
|
|
|
+ * - Handle working directory when directory is NULL
|
|
|
|
+ * - Join directory and filename with proper separators
|
|
|
|
+ * - Resolve . and .. in paths
|
|
|
|
+ * - Remove redundant slashes
|
|
|
|
+ * - Ensure path starts with /
|
|
|
|
+ * - Allocate memory for the returned path string
|
|
*/
|
|
*/
|
|
char *dfs_normalize_path(const char *directory, const char *filename)
|
|
char *dfs_normalize_path(const char *directory, const char *filename)
|
|
{
|
|
{
|
|
@@ -819,7 +970,7 @@ char *dfs_normalize_path(const char *directory, const char *filename)
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- if (filename[0] != '/') /* it's a absolute path, use it directly */
|
|
|
|
|
|
+ if (filename[0] != '/')
|
|
{
|
|
{
|
|
int path_len;
|
|
int path_len;
|
|
|
|
|
|
@@ -839,7 +990,7 @@ char *dfs_normalize_path(const char *directory, const char *filename)
|
|
rt_snprintf(fullpath, strlen(directory) + strlen(filename) + 2,
|
|
rt_snprintf(fullpath, strlen(directory) + strlen(filename) + 2,
|
|
"%s/%s", directory, filename);
|
|
"%s/%s", directory, filename);
|
|
}
|
|
}
|
|
- else
|
|
|
|
|
|
+ else /* it's a absolute path, use it directly */
|
|
{
|
|
{
|
|
fullpath = rt_strdup(filename); /* copy string */
|
|
fullpath = rt_strdup(filename); /* copy string */
|
|
|
|
|
|
@@ -847,29 +998,35 @@ char *dfs_normalize_path(const char *directory, const char *filename)
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Initialize source and destination pointers to start of path */
|
|
src = fullpath;
|
|
src = fullpath;
|
|
dst = fullpath;
|
|
dst = fullpath;
|
|
|
|
|
|
|
|
+ /* Save initial position for boundary checking */
|
|
dst0 = dst;
|
|
dst0 = dst;
|
|
while (1)
|
|
while (1)
|
|
{
|
|
{
|
|
char c = *src;
|
|
char c = *src;
|
|
|
|
|
|
|
|
+ /* Handle '.' and '..' path components */
|
|
if (c == '.')
|
|
if (c == '.')
|
|
{
|
|
{
|
|
|
|
+ /* Single dot at end of path */
|
|
if (!src[1])
|
|
if (!src[1])
|
|
- src++; /* '.' and ends */
|
|
|
|
|
|
+ src++; /* '.' and ends, Skip single dot */
|
|
else if (src[1] == '/')
|
|
else if (src[1] == '/')
|
|
{
|
|
{
|
|
/* './' case */
|
|
/* './' case */
|
|
src += 2;
|
|
src += 2;
|
|
|
|
|
|
|
|
+ /* Skip consecutive slashes */
|
|
while ((*src == '/') && (*src != '\0'))
|
|
while ((*src == '/') && (*src != '\0'))
|
|
src++;
|
|
src++;
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
else if (src[1] == '.')
|
|
else if (src[1] == '.')
|
|
{
|
|
{
|
|
|
|
+ /* Parent directory reference */
|
|
if (!src[2])
|
|
if (!src[2])
|
|
{
|
|
{
|
|
/* '..' and ends case */
|
|
/* '..' and ends case */
|
|
@@ -878,9 +1035,10 @@ char *dfs_normalize_path(const char *directory, const char *filename)
|
|
}
|
|
}
|
|
else if (src[2] == '/')
|
|
else if (src[2] == '/')
|
|
{
|
|
{
|
|
- /* '../' case */
|
|
|
|
|
|
+ /* '../' case: parent directory reference */
|
|
src += 3;
|
|
src += 3;
|
|
|
|
|
|
|
|
+ /* Skip consecutive slashes */
|
|
while ((*src == '/') && (*src != '\0'))
|
|
while ((*src == '/') && (*src != '\0'))
|
|
src++;
|
|
src++;
|
|
goto up_one;
|
|
goto up_one;
|
|
@@ -894,6 +1052,7 @@ char *dfs_normalize_path(const char *directory, const char *filename)
|
|
|
|
|
|
if (c == '/')
|
|
if (c == '/')
|
|
{
|
|
{
|
|
|
|
+ /* Add single slash */
|
|
*dst++ = '/';
|
|
*dst++ = '/';
|
|
while (c == '/')
|
|
while (c == '/')
|
|
c = *src++;
|
|
c = *src++;
|
|
@@ -901,21 +1060,25 @@ char *dfs_normalize_path(const char *directory, const char *filename)
|
|
src--;
|
|
src--;
|
|
}
|
|
}
|
|
else if (!c)
|
|
else if (!c)
|
|
- break;
|
|
|
|
|
|
+ break; /* End of string */
|
|
|
|
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
+ /* Handle parent directory reference */
|
|
up_one:
|
|
up_one:
|
|
|
|
+ /* Move back one directory level */
|
|
dst--;
|
|
dst--;
|
|
- if (dst < dst0)
|
|
|
|
|
|
+ if (dst < dst0) /* Check for path traversal underflow */
|
|
{
|
|
{
|
|
rt_free(fullpath);
|
|
rt_free(fullpath);
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
+ /* Find previous directory separator */
|
|
while (dst0 < dst && dst[-1] != '/')
|
|
while (dst0 < dst && dst[-1] != '/')
|
|
dst--;
|
|
dst--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Null-terminate the path */
|
|
*dst = '\0';
|
|
*dst = '\0';
|
|
|
|
|
|
/* remove '/' in the end of path if exist */
|
|
/* remove '/' in the end of path if exist */
|
|
@@ -936,6 +1099,11 @@ RTM_EXPORT(dfs_normalize_path);
|
|
|
|
|
|
#ifdef RT_USING_FINSH
|
|
#ifdef RT_USING_FINSH
|
|
#include <finsh.h>
|
|
#include <finsh.h>
|
|
|
|
+/**
|
|
|
|
+ * @brief List all open file descriptors in the current process
|
|
|
|
+ *
|
|
|
|
+ * @return int 0 on success, -1 if failed to get file descriptor table
|
|
|
|
+ */
|
|
int list_fd(void)
|
|
int list_fd(void)
|
|
{
|
|
{
|
|
int index;
|
|
int index;
|
|
@@ -980,6 +1148,15 @@ int list_fd(void)
|
|
}
|
|
}
|
|
MSH_CMD_EXPORT(list_fd, list file descriptor);
|
|
MSH_CMD_EXPORT(list_fd, list file descriptor);
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Dump all file descriptors information in the global file descriptor table
|
|
|
|
+ *
|
|
|
|
+ * @param[in] argc Number of command line arguments (unused)
|
|
|
|
+ * @param[in] argv Array of command line arguments (unused)
|
|
|
|
+ *
|
|
|
|
+ * @return int 0 on success,
|
|
|
|
+ * -RT_ENOSYS if failed to acquire file system lock
|
|
|
|
+ */
|
|
int dfs_fd_dump(int argc, char** argv)
|
|
int dfs_fd_dump(int argc, char** argv)
|
|
{
|
|
{
|
|
int index;
|
|
int index;
|
|
@@ -1015,7 +1192,24 @@ int dfs_fd_dump(int argc, char** argv)
|
|
MSH_CMD_EXPORT_ALIAS(dfs_fd_dump, fd_dump, fd dump);
|
|
MSH_CMD_EXPORT_ALIAS(dfs_fd_dump, fd_dump, fd dump);
|
|
|
|
|
|
#ifdef PKG_USING_DLOG
|
|
#ifdef PKG_USING_DLOG
|
|
-
|
|
|
|
|
|
+/**
|
|
|
|
+ * @brief Control the DFS (Device File System) debug logging functionality
|
|
|
|
+ *
|
|
|
|
+ * @param[in] argc Number of command line arguments (must be 2)
|
|
|
|
+ * @param[in] argv Array of command line arguments:
|
|
|
|
+ * - argv[1]: "on" to enable logging, "off" to disable logging
|
|
|
|
+ *
|
|
|
|
+ * @return int Always returns 0 (success)
|
|
|
|
+ *
|
|
|
|
+ * @note When enabled, this function activates logging for multiple DFS components:
|
|
|
|
+ * - dfs: Core DFS functionality
|
|
|
|
+ * - dfs_file: File operations
|
|
|
|
+ * - dentry: Directory entries
|
|
|
|
+ * - vnode: Virtual nodes
|
|
|
|
+ * - mnt: Mount points
|
|
|
|
+ * - rom: ROM filesystem
|
|
|
|
+ * - devfs: Device filesystem
|
|
|
|
+ */
|
|
int dfs_dlog(int argc, char** argv)
|
|
int dfs_dlog(int argc, char** argv)
|
|
{
|
|
{
|
|
if (argc == 2)
|
|
if (argc == 2)
|
|
@@ -1044,4 +1238,4 @@ MSH_CMD_EXPORT(dfs_dlog, dfs dlog on|off);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#endif
|
|
#endif
|
|
-/** @} */
|
|
|
|
|
|
+/** @} */
|