musl: glob-util: filter out . and .. even if GLOB_ALTDIRFUNC is not supported

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.
This commit is contained in:
Yu Watanabe
2025-11-17 12:19:22 +09:00
parent 3bc03c67f0
commit 07e437f569
2 changed files with 94 additions and 0 deletions
+76
View 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;