This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 52dac57f7636137d272bb719a8d474bdf5cad294 Author: zhengyu16 <[email protected]> AuthorDate: Thu Nov 6 14:23:46 2025 +0800 fs/vfs: add link, symlink and readlink support for mountpt 1. add three func to mountpt_operations: link symlink readlink 2. modify fs_link、fs_symlink、fs_readlink for mountpt Signed-off-by: zhengyu16 <[email protected]> --- fs/vfs/fs_link.c | 53 ++++++++++++++++++++++++++++++------------- fs/vfs/fs_readlink.c | 62 ++++++++++++++++++++++++++++++++++++--------------- fs/vfs/fs_symlink.c | 24 +++++++++++++++----- include/nuttx/fs/fs.h | 11 +++++++++ 4 files changed, 112 insertions(+), 38 deletions(-) diff --git a/fs/vfs/fs_link.c b/fs/vfs/fs_link.c index 03c49f75cd3..21432eb6ad3 100644 --- a/fs/vfs/fs_link.c +++ b/fs/vfs/fs_link.c @@ -105,16 +105,6 @@ int link(FAR const char *path1, FAR const char *path2) target = desc_path1.node; - /* Check if target inode is a mountpoint. */ - - if (INODE_IS_MOUNTPT(target)) - { - /* Hard links within the mounted volume are not supported */ - - errcode = ENOSYS; - goto errout_with_target; - } - if (INODE_GET_NLINK(target) >= _POSIX_LINK_MAX) { /* Too many links to the target inode */ @@ -144,9 +134,35 @@ int link(FAR const char *path1, FAR const char *path2) DEBUGASSERT(newinode != NULL); if (INODE_IS_MOUNTPT(newinode)) { - /* Hard links within the mounted volume are not supported */ - - errcode = ENOSYS; + /* Check if path1 and path2 are on the same mountpoint */ + + if (newinode != target) + { + errcode = EXDEV; + goto errout_with_newinode; + } + + if (target->u.i_mops && target->u.i_mops->link) + { + /* Perform the link operation using the relative path at the + * mountpoint. + */ + + ret = target->u.i_mops->link(target, desc_path1.relpath, + desc_path2.relpath); + if (ret < 0) + { + errcode = -ret; + goto errout_with_newinode; + } + } + else + { + /* Hard links within this type of fs are not supported */ + + errcode = ENOSYS; + goto errout_with_newinode; + } } else #endif @@ -154,9 +170,8 @@ int link(FAR const char *path1, FAR const char *path2) /* A node already exists in the pseudofs at 'path2' */ errcode = EEXIST; + goto errout_with_newinode; } - - goto errout_with_newinode; } /* No inode exists that contains this path. Create a new inode in the @@ -165,6 +180,14 @@ int link(FAR const char *path1, FAR const char *path2) else { + /* Cannot link between pseudofs and other mountpoints */ + + if (INODE_IS_MOUNTPT(target)) + { + errcode = EXDEV; + goto errout_with_target; + } + /* Create an inode in the pseudo-filesystem at this path. */ inode_lock(); diff --git a/fs/vfs/fs_readlink.c b/fs/vfs/fs_readlink.c index e75ad191886..ad301ec46b3 100644 --- a/fs/vfs/fs_readlink.c +++ b/fs/vfs/fs_readlink.c @@ -94,28 +94,54 @@ ssize_t readlink(FAR const char *path, FAR char *buf, size_t bufsize) node = desc.node; DEBUGASSERT(node != NULL); - ret = inode_checkpathperm(node, 0, 0); - if (ret < 0) - { - errcode = -ret; - goto errout_with_inode; - } - - /* An inode was found that includes this path and possibly refers to a - * symbolic link. - * - * Check if the inode is a valid symbolic link. +#ifndef CONFIG_DISABLE_MOUNTPOINT + /* If the inode is a mountpoint, let the mountpoint's readlink + * method handle the request. */ - if (!INODE_IS_SOFTLINK(node)) + if (INODE_IS_MOUNTPT(node)) { - errcode = EINVAL; - goto errout_with_inode; + if (node->u.i_mops && node->u.i_mops->readlink) + { + ret = node->u.i_mops->readlink(node, desc.relpath, buf, bufsize); + if (ret < 0) + { + errcode = -ret; + goto errout_with_inode; + } + } + else + { + errcode = ENOSYS; + goto errout_with_inode; + } + } + else +#endif + { + ret = inode_checkpathperm(node, 0, 0); + if (ret < 0) + { + errcode = -ret; + goto errout_with_inode; + } + + /* An inode was found that includes this path and possibly refers to a + * symbolic link. + * + * Check if the inode is a valid symbolic link. + */ + + if (!INODE_IS_SOFTLINK(node)) + { + errcode = EINVAL; + goto errout_with_inode; + } + + /* Copy the link target path to the user-provided buffer. */ + + strlcpy(buf, node->u.i_link, bufsize); } - - /* Copy the link target pathto the user-provided buffer. */ - - strlcpy(buf, node->u.i_link, bufsize); /* Release our reference on the inode and return the length */ diff --git a/fs/vfs/fs_symlink.c b/fs/vfs/fs_symlink.c index f4a828117ec..76cac2bad73 100644 --- a/fs/vfs/fs_symlink.c +++ b/fs/vfs/fs_symlink.c @@ -109,9 +109,23 @@ int symlink(FAR const char *path1, FAR const char *path2) DEBUGASSERT(desc.node != NULL); if (INODE_IS_MOUNTPT(desc.node)) { - /* Symbolic links within the mounted volume are not supported */ - - errcode = ENOSYS; + if (desc.node->u.i_mops && desc.node->u.i_mops->symlink) + { + ret = desc.node->u.i_mops->symlink(desc.node, path1, + desc.relpath); + if (ret < 0) + { + errcode = -ret; + goto errout_with_inode; + } + } + else + { + /* Symbolic links within this type of fs are not supported */ + + errcode = ENOSYS; + goto errout_with_inode; + } } else #endif @@ -119,9 +133,8 @@ int symlink(FAR const char *path1, FAR const char *path2) /* A node already exists in the pseudofs at 'path1' */ errcode = EEXIST; + goto errout_with_inode; } - - goto errout_with_inode; } /* No inode exists that contains this path. Create a new inode in the @@ -133,6 +146,7 @@ int symlink(FAR const char *path1, FAR const char *path2) /* Copy path1 */ FAR char *newpath2 = fs_heap_strdup(path1); + if (newpath2 == NULL) { errcode = ENOMEM; diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index 33ef992a861..a12cc3e2976 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -402,6 +402,17 @@ struct mountpt_operations CODE int (*permission)(FAR struct inode *mountpt, FAR const char *relpath, int amode); + +#ifdef CONFIG_FS_LINKS + CODE int (*link)(FAR struct inode *mountpt, FAR const char *relpath1, + FAR const char *relpath2); + CODE int (*symlink)(FAR struct inode *mountpt, + FAR const char *path1, + FAR const char *relpath2); + CODE ssize_t (*readlink)(FAR struct inode *mountpt, + FAR const char *relpath, + FAR char *buf, size_t bufsize); +#endif }; #endif /* CONFIG_DISABLE_MOUNTPOINT */
