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 c6b8afe7992eaedd1be9ee41cb0dca4c2aa0b28e
Author: Marco Casaroli <[email protected]>
AuthorDate: Fri Oct 23 16:37:14 2026 +0200

    libs/libc/misc: Add GLOB_TILDE and GLOB_TILDE_CHECK to glob().
    
    Programs from other systems use glob() with GLOB_TILDE to find files
    in a home directory, for example "~/.config/name", and did not compile.
    A "~" at the start of the pattern is the value of HOME, or else the home
    directory of the user in the password database.  "~name" is the home
    directory of the user name.  When the home directory is not known,
    GLOB_TILDE uses the pattern as it is, and GLOB_TILDE_CHECK returns
    GLOB_NOMATCH, as in other C libraries.  The flags have the values of
    glibc and musl.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 include/glob.h            |   8 +++
 libs/libc/misc/lib_glob.c | 121 +++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 128 insertions(+), 1 deletion(-)

diff --git a/include/glob.h b/include/glob.h
index cb4de40fa2e..731bd27dc96 100644
--- a/include/glob.h
+++ b/include/glob.h
@@ -50,6 +50,14 @@
 #define GLOB_NOESCAPE 0x20 /* Disable backslash escaping. */
 #define GLOB_NOSORT   0x40 /* Do not sort the pathnames returned. */
 
+/* Extensions, with the values of other C libraries: */
+
+#define GLOB_TILDE       0x1000 /* Expand a "~" or "~name" at the start
+                                 * of the pattern to a home directory. */
+#define GLOB_TILDE_CHECK 0x4000 /* As GLOB_TILDE, but fail with
+                                 * GLOB_NOMATCH if the home directory is
+                                 * not known. */
+
 /* The following constants shall be defined as error return values:
  */
 
diff --git a/libs/libc/misc/lib_glob.c b/libs/libc/misc/lib_glob.c
index 9514f0da9c3..cd0c2de0118 100644
--- a/libs/libc/misc/lib_glob.c
+++ b/libs/libc/misc/lib_glob.c
@@ -58,6 +58,7 @@ static int do_glob(FAR char *buf, size_t pos, int type, FAR 
char *pat,
                    int flags,
                    CODE int (*errfunc)(FAR const char *path, int err),
                    FAR struct match_s **tail);
+static int glob_home(FAR const char *user, FAR char *home);
 static int ignore_err(FAR const char *path, int err);
 static void freelist(FAR struct match_s *head);
 static int sort(FAR const void *a, FAR const void *b);
@@ -403,6 +404,73 @@ static int sort(FAR const void *a, FAR const void *b)
   return strcmp(*(FAR const char**)a, *(FAR const char**)b);
 }
 
+/****************************************************************************
+ * Name: glob_home
+ *
+ * Description:
+ *   Copy the home directory of a user to home (PATH_MAX bytes).  An empty
+ *   user name is the calling user: then HOME is used when it is set, else
+ *   the password database.
+ *
+ * Returned Value:
+ *   Zero on success, GLOB_NOMATCH when the home directory is not known,
+ *   GLOB_NOSPACE when there is no memory.
+ *
+ ****************************************************************************/
+
+static int glob_home(FAR const char *user, FAR char *home)
+{
+  FAR const char *dir = NULL;
+  FAR struct passwd *entry = NULL;
+  FAR char *pwbuf = NULL;
+  struct passwd pwd;
+  int ret = 0;
+
+  if (user[0] == '\0')
+    {
+      dir = getenv("HOME");
+    }
+
+  if (dir == NULL)
+    {
+      pwbuf = lib_get_tempbuffer(NSS_BUFLEN_PASSWD);
+      if (pwbuf == NULL)
+        {
+          return GLOB_NOSPACE;
+        }
+
+      if (user[0] == '\0')
+        {
+          ret = getpwuid_r(getuid(), &pwd, pwbuf, NSS_BUFLEN_PASSWD, &entry);
+        }
+      else
+        {
+          ret = getpwnam_r(user, &pwd, pwbuf, NSS_BUFLEN_PASSWD, &entry);
+        }
+
+      if (ret == 0 && entry != NULL)
+        {
+          dir = entry->pw_dir;
+        }
+    }
+
+  if (dir == NULL)
+    {
+      ret = ret == ENOMEM ? GLOB_NOSPACE : GLOB_NOMATCH;
+    }
+  else if (strlcpy(home, dir, PATH_MAX) >= PATH_MAX - 1)
+    {
+      ret = GLOB_NOMATCH;
+    }
+
+  if (pwbuf != NULL)
+    {
+      lib_put_tempbuffer(pwbuf);
+    }
+
+  return ret;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -459,7 +527,58 @@ int glob(FAR const char *pat, int flags,
       buf[0] = 0;
       s = p;
 
-      error = do_glob(buf, pos, 0, s, flags, errfunc, &tail);
+      /* "~" or "~user" at the start of the pattern: the home directory
+       * goes to buf, and the rest of the pattern after the "/" is matched
+       * in it.
+       */
+
+      if ((flags & (GLOB_TILDE | GLOB_TILDE_CHECK)) != 0 && s[0] == '~')
+        {
+          FAR char *slash = strchr(s, '/');
+
+          if (slash != NULL)
+            {
+              *slash = '\0';
+            }
+
+          error = glob_home(s + 1, buf);
+          if (error == 0)
+            {
+              pos = strlen(buf);
+              if (slash != NULL)
+                {
+                  buf[pos++] = '/';
+                  buf[pos] = '\0';
+                  s = slash + 1;
+                }
+              else
+                {
+                  s += strlen(s);
+                }
+            }
+          else
+            {
+              /* Without GLOB_TILDE_CHECK an unknown home directory is not
+               * an error: the pattern is used as it is.
+               */
+
+              if (slash != NULL)
+                {
+                  *slash = '/';
+                }
+
+              buf[0] = '\0';
+              if (error == GLOB_NOMATCH && (flags & GLOB_TILDE_CHECK) == 0)
+                {
+                  error = 0;
+                }
+            }
+        }
+
+      if (error == 0)
+        {
+          error = do_glob(buf, pos, 0, s, flags, errfunc, &tail);
+        }
 
       lib_free(p);
     }

Reply via email to