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 */
 

Reply via email to