]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
musl: glob-util: filter out . and .. even if GLOB_ALTDIRFUNC is not supported
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 25 Feb 2019 06:56:21 +0000 (14:56 +0800)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 17 Nov 2025 03:19:22 +0000 (12:19 +0900)
musl neither support GLOB_ALTDIRFUNC nor GLOB_BRACE.
Let's make safe_glob() work even when GLOB_ALTDIRFUNC is not supported.
Currently, GLOB_BRACE is simply ignored when it is not supported.

src/basic/glob-util.c
src/include/musl/glob.h [new file with mode: 0644]

index 5843ef088f3f3a11e2ab276af8f4b75284e5d09a..eda7bcb6c51730da9364ba6636caa2f4f16d4ccb 100644 (file)
@@ -9,6 +9,78 @@
 #include "string-util.h"
 #include "strv.h"
 
+#ifndef __GLIBC__
+static bool safe_glob_verify(const char *p, const char *prefix) {
+        if (isempty(p))
+                return false; /* should not happen, but for safey. */
+
+        if (prefix) {
+                /* Skip the prefix, as we allow dots in prefix.
+                 * Note, glob() does not normalize paths, hence do not use path_startswith(). */
+                p = startswith(p, prefix);
+                if (!p)
+                        return false; /* should not happen, but for safety. */
+        }
+
+        for (;;) {
+                p += strspn(p, "/");
+                if (*p == '\0')
+                        return true;
+                if (*p == '.') {
+                        p++;
+                        if (IN_SET(*p, '/', '\0'))
+                                return false; /* refuse dot */
+                        if (*p == '.') {
+                                p++;
+                                if (IN_SET(*p, '/', '\0'))
+                                        return false; /* refuse dot dot */
+                        }
+                }
+
+                p += strcspn(p, "/");
+                if (*p == '\0')
+                        return true;
+        }
+}
+
+static int filter_glob_result(char * const *result, const char *path, char ***ret) {
+        int r;
+
+        assert(path);
+
+        if (strv_isempty(result))
+                return -ENOENT;
+
+        _cleanup_free_ char *prefix = NULL;
+        r = glob_non_glob_prefix(path, &prefix);
+        if (r < 0 && r != -ENOENT)
+                return r;
+
+        _cleanup_strv_free_ char **filtered = NULL;
+        size_t n_filtered = 0;
+        STRV_FOREACH(p, result) {
+                if (!safe_glob_verify(*p, prefix))
+                        continue;
+
+                if (!ret)
+                        return 0; /* Found at least one entry, let's return earlier. */
+
+                /* When musl is used, each entry is not a head of allocated memory. Hence, it is
+                 * necessary to copy the string. */
+                r = strv_extend_with_size(&filtered, &n_filtered, *p);
+                if (r < 0)
+                        return r;
+        }
+
+        if (n_filtered == 0)
+                return -ENOENT;
+
+        assert(ret);
+        *ret = TAKE_PTR(filtered);
+        return 0;
+}
+#endif
+
 DEFINE_TRIVIAL_DESTRUCTOR(closedir_wrapper, void, closedir);
 
 int safe_glob_full(const char *path, int flags, opendir_t opendir_func, char ***ret) {
@@ -32,6 +104,10 @@ int safe_glob_full(const char *path, int flags, opendir_t opendir_func, char ***
         if (r != 0)
                 return errno_or_else(EIO);
 
+#ifndef __GLIBC__
+        return filter_glob_result(g.gl_pathv, path, ret);
+#endif
+
         if (strv_isempty(g.gl_pathv))
                 return -ENOENT;
 
diff --git a/src/include/musl/glob.h b/src/include/musl/glob.h
new file mode 100644 (file)
index 0000000..12faa8e
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include_next <glob.h>
+
+#ifndef GLOB_ALTDIRFUNC
+#define GLOB_ALTDIRFUNC (1 << 9)
+#define gl_flags    __dummy1
+#define gl_closedir __dummy2[0]
+#define gl_readdir  __dummy2[1]
+#define gl_opendir  __dummy2[2]
+#define gl_lstat    __dummy2[3]
+#define gl_stat     __dummy2[4]
+#endif
+
+#ifndef GLOB_BRACE
+#define GLOB_BRACE      (1 << 10)
+#endif