This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 921cdee8b56 fs/vfs: Make fstat() of an open directory describe the 
directory.
921cdee8b56 is described below

commit 921cdee8b56bb78f8b1ea373da989060a1aa45d1
Author: Marco Casaroli <[email protected]>
AuthorDate: Fri Oct 9 13:49:15 2026 +0200

    fs/vfs: Make fstat() of an open directory describe the directory.
    
    open() of a directory gives the file a stand-in inode, g_dir_inode,
    with the directory operations.  file_fstat() did not know it and
    returned inode_stat() of that stand-in: a directory, but with st_ino 0
    and none of the real directory's attributes, on every file system.
    Programs that walk directories with openat() and fstat(), for example
    with fts, compare st_dev and st_ino with those from stat() to detect
    loops and changed directories, and failed.
    
    Stat the directory by the path that the open directory keeps.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 fs/inode/inode.h  | 11 +++++++++++
 fs/vfs/fs_dir.c   | 27 +++++++++++++++++++++++++++
 fs/vfs/fs_fstat.c | 18 +++++++++++++-----
 3 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/fs/inode/inode.h b/fs/inode/inode.h
index f80695a1898..beb3438e830 100644
--- a/fs/inode/inode.h
+++ b/fs/inode/inode.h
@@ -524,6 +524,17 @@ int foreach_inode(foreach_inode_t handler, FAR void *arg);
 
 int dir_allocate(FAR struct file *filep, FAR const char *relpath);
 
+/****************************************************************************
+ * Name: dir_fstat
+ *
+ * Description:
+ *   fstat() of a directory opened with open().  Returns -ENOTTY if filep
+ *   is not such a directory.
+ *
+ ****************************************************************************/
+
+int dir_fstat(FAR struct file *filep, FAR struct stat *buf);
+
 /****************************************************************************
  * Name: pseudofile_create
  *
diff --git a/fs/vfs/fs_dir.c b/fs/vfs/fs_dir.c
index 75f54db3632..156abe15550 100644
--- a/fs/vfs/fs_dir.c
+++ b/fs/vfs/fs_dir.c
@@ -668,3 +668,30 @@ int dir_allocate(FAR struct file *filep, FAR const char 
*relpath)
   lib_put_pathbuffer(path_prefix);
   return ret;
 }
+
+/****************************************************************************
+ * Name: dir_fstat
+ *
+ * Description:
+ *   fstat() of a file descriptor that open() returned for a directory.
+ *   Such a descriptor has a stand-in inode, so stat the directory itself
+ *   by its path.
+ *
+ * Returned Value:
+ *   Zero (OK) on success, a negated errno value on failure, or -ENOTTY if
+ *   filep is not a directory opened with open().
+ *
+ ****************************************************************************/
+
+int dir_fstat(FAR struct file *filep, FAR struct stat *buf)
+{
+  FAR struct fs_dirent_s *dir;
+
+  if (filep->f_inode != &g_dir_inode)
+    {
+      return -ENOTTY;
+    }
+
+  dir = filep->f_priv;
+  return nx_stat(dir->fd_path, buf, 1);
+}
diff --git a/fs/vfs/fs_fstat.c b/fs/vfs/fs_fstat.c
index 1e8d7c127bc..3b5948fea8b 100644
--- a/fs/vfs/fs_fstat.c
+++ b/fs/vfs/fs_fstat.c
@@ -211,14 +211,22 @@ int file_fstat(FAR struct file *filep, FAR struct stat 
*buf)
   else
 #endif
     {
-      /* Check if the inode is a proxy for a block or MTD driver */
+      /* A directory opened with open() has a stand-in inode; stat the
+       * directory itself.
+       */
 
-      ret = proxy_fstat(filep, inode, buf);
-      if (ret < 0)
+      ret = dir_fstat(filep, buf);
+      if (ret == -ENOTTY)
         {
-          /* The inode is part of the root pseudo file system. */
+          /* Check if the inode is a proxy for a block or MTD driver */
+
+          ret = proxy_fstat(filep, inode, buf);
+          if (ret < 0)
+            {
+              /* The inode is part of the root pseudo file system. */
 
-          ret = inode_stat(inode, buf, 0);
+              ret = inode_stat(inode, buf, 0);
+            }
         }
     }
 

Reply via email to