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 cacded6ab90fb34ad6f294f7b47787aab415bb58
Author: yezhonghui <[email protected]>
AuthorDate: Thu Nov 12 00:35:11 2026 +0800

    fs/procfs: list registered entries once and in their directory
    
    procfs_readdir() assumes that the entries of one directory are adjacent
    in g_procfs_entries, and drops a first-level name only when it repeats
    the name reported just before it.  procfs_register() appends to the end
    of the table, so after registering "fs/foo" and "foo_bar":
    
    - "ls /proc" reports "fs" a second time, and hides "foo_bar" because
      its first two characters match the "fs" reported before it.
    - "ls /proc/fs" stops at the first entry outside fs/ and never reaches
      "foo".
    
    Scan the rest of the table for each directory instead, and skip a name
    when an earlier entry already yields it.  Since the scan now covers the
    whole table, a member of a subdirectory must also have '/' right after
    the directory name, so "foo_bar" is not taken as part of "fs".
    
    Signed-off-by: yezhonghui <[email protected]>
    Signed-off-by: jingfei <[email protected]>
---
 fs/procfs/fs_procfs.c | 93 +++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 72 insertions(+), 21 deletions(-)

diff --git a/fs/procfs/fs_procfs.c b/fs/procfs/fs_procfs.c
index aa198ff23f7..91c0e83750d 100644
--- a/fs/procfs/fs_procfs.c
+++ b/fs/procfs/fs_procfs.c
@@ -823,6 +823,45 @@ static int procfs_closedir(FAR struct inode *mountpt,
   return ret;
 }
 
+/****************************************************************************
+ * Name: procfs_listed
+ *
+ * Description:
+ *   Return true if an entry before 'index' already yields the directory
+ *   entry 'name' ('len' bytes) under the directory 'dir' ('dirlen' bytes,
+ *   0 for the procfs root).
+ *
+ ****************************************************************************/
+
+static bool procfs_listed(unsigned int index, FAR const char *dir,
+                          size_t dirlen, FAR const char *name, size_t len)
+{
+  unsigned int x;
+
+  for (x = 0; x < index; x++)
+    {
+      FAR const char *path = g_procfs_entries[x].pathpattern;
+
+      if (dirlen > 0)
+        {
+          if (strncmp(path, dir, dirlen) != 0 || path[dirlen] != '/')
+            {
+              continue;
+            }
+
+          path += dirlen + 1;
+        }
+
+      if (strncmp(path, name, len) == 0 &&
+          (path[len] == '/' || path[len] == '*' || path[len] == '\0'))
+        {
+          return true;
+        }
+    }
+
+  return false;
+}
+
 /****************************************************************************
  * Name: procfs_readdir
  *
@@ -839,6 +878,7 @@ static int procfs_readdir(FAR struct inode *mountpt,
   FAR struct procfs_level0_s *level0;
   FAR const char *name = NULL;
   unsigned int index;
+  size_t len;
   int ret = -ENOENT;
 
   DEBUGASSERT(mountpt && dir);
@@ -898,8 +938,8 @@ static int procfs_readdir(FAR struct inode *mountpt,
                    */
 
                   name = g_procfs_entries[index].pathpattern;
-                  if (!level0->lastlen ||
-                      strncmp(name, level0->lastread, level0->lastlen) != 0)
+                  if (!procfs_listed(index, NULL, 0, name,
+                                     strcspn(name, "/")))
                     {
                       /* Not a duplicate, return the first segment of this
                        * entry
@@ -943,7 +983,7 @@ static int procfs_readdir(FAR struct inode *mountpt,
 
               /* Advance to next entry for the next read */
 
-              priv->index = priv->nentries + index;
+              priv->index = priv->nentries + index + 1;
               ret = OK;
             }
         }
@@ -984,37 +1024,48 @@ static int procfs_readdir(FAR struct inode *mountpt,
 
       level1 = (FAR struct procfs_level1_s *)priv;
 
-      /* Test if this entry matches.  We assume all entries of the same
-       * subdirectory are listed in order in the procfs_entry array.
+      /* procfs_register() appends to the table, so the entries of one
+       * subdirectory need not be adjacent: scan the rest of the table and
+       * skip names already reported.
        */
 
-      if (level1->base.index < g_procfs_entrycount &&
-          level1->firstindex < g_procfs_entrycount &&
-          strncmp(g_procfs_entries[level1->base.index].pathpattern,
-                  g_procfs_entries[level1->firstindex].pathpattern,
-                  level1->subdirlen) == 0)
+      while (level1->firstindex < g_procfs_entrycount &&
+             level1->base.index < g_procfs_entrycount)
         {
-          /* This entry matches.  Report the subdir entry */
+          FAR const char *subdir =
+            g_procfs_entries[level1->firstindex].pathpattern;
 
-          name = &g_procfs_entries[level1->base.index].
-                    pathpattern[level1->subdirlen + 1];
-          level1->lastlen = strcspn(name, "/");
-          level1->lastread = name;
-          strlcpy(entry->d_name, name, level1->lastlen + 1);
+          index = level1->base.index++;
+          name  = g_procfs_entries[index].pathpattern;
+          if (strncmp(name, subdir, level1->subdirlen) != 0 ||
+              name[level1->subdirlen] != '/')
+            {
+              continue;
+            }
 
           /* Some of the search entries contain '**' wildcards.  When we
            * report the entry name, we must remove this wildcard search
            * specifier.
            */
 
-          while (entry->d_name[level1->lastlen - 1] == '*')
+          name += level1->subdirlen + 1;
+          len   = strcspn(name, "/");
+          while (len > 0 && name[len - 1] == '*')
             {
-              level1->lastlen--;
+              len--;
             }
 
-          entry->d_name[level1->lastlen] = '\0';
+          if (len == 0 ||
+              procfs_listed(index, subdir, level1->subdirlen, name, len))
+            {
+              continue;
+            }
+
+          level1->lastlen  = len;
+          level1->lastread = name;
+          strlcpy(entry->d_name, name, len + 1);
 
-          if (name[level1->lastlen] == '/')
+          if (name[len] == '/')
             {
               entry->d_type = DTYPE_DIRECTORY;
             }
@@ -1023,8 +1074,8 @@ static int procfs_readdir(FAR struct inode *mountpt,
               entry->d_type = DTYPE_FILE;
             }
 
-          level1->base.index++;
           ret = OK;
+          break;
         }
     }
   else

Reply via email to