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 f5cff1cbd66f39d76310098117829062caa0f413
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Oct 19 17:38:52 2026 +0200

    fs: Let lchown(), lchmod() and lutimens() change the link on a mount point.
    
    On a mount point, chstat_recursive() calls the chstat() method of the
    file system with the same flags for chown() and for lchown().  The file
    system cannot know that it must not follow the symbolic link.  So
    lchown(), lchmod() and lutimens() (and fchownat(), fchmodat() and
    utimensat() with AT_SYMLINK_NOFOLLOW) changed the file that the link
    points to, and left the link as it was.
    
    Add the flag CH_STAT_NOFOLLOW.  chstat_recursive() sets it when the
    caller does not resolve the link.  V9FS walks to the link without
    following it when the flag is set, as its lstat() does.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 fs/v9fs/v9fs.c        | 3 ++-
 fs/vfs/fs_chstat.c    | 7 +++++++
 include/nuttx/fs/fs.h | 1 +
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/fs/v9fs/v9fs.c b/fs/v9fs/v9fs.c
index 52514c40b06..e0b881e322a 100644
--- a/fs/v9fs/v9fs.c
+++ b/fs/v9fs/v9fs.c
@@ -961,7 +961,8 @@ static int v9fs_vfs_chstat(FAR struct inode *mountpt,
 
   client = mountpt->i_private;
 
-  ret = v9fs_client_walk(client, relpath, NULL, false);
+  ret = v9fs_client_walk(client, relpath, NULL,
+                         (flags & CH_STAT_NOFOLLOW) != 0);
   if (ret < 0)
     {
       ferr("ERROR: Can't find the fid of the relpath %d\n", ret);
diff --git a/fs/vfs/fs_chstat.c b/fs/vfs/fs_chstat.c
index e06ce347288..44b85dfbcf2 100644
--- a/fs/vfs/fs_chstat.c
+++ b/fs/vfs/fs_chstat.c
@@ -94,6 +94,13 @@ static int chstat_recursive(FAR const char *path,
 
       if (inode->u.i_mops && inode->u.i_mops->chstat)
         {
+          /* lchown(), lchmod() and lutimens() change the link itself */
+
+          if (resolve == 0)
+            {
+              flags |= CH_STAT_NOFOLLOW;
+            }
+
           /* Perform the chstat() operation */
 
           ret = inode->u.i_mops->chstat(inode, desc.relpath, buf, flags);
diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h
index 7a33f4dea2a..89022cebf24 100644
--- a/include/nuttx/fs/fs.h
+++ b/include/nuttx/fs/fs.h
@@ -175,6 +175,7 @@
 #define CH_STAT_ATIME      (1 << 3)
 #define CH_STAT_MTIME      (1 << 4)
 #define CH_STAT_SIZE       (1 << 7)
+#define CH_STAT_NOFOLLOW   (1 << 8)  /* Do not follow a final symbolic link */
 
 /****************************************************************************
  * Public Type Definitions

Reply via email to