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);
+ }
}
}