1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7
8 #include "dirent-util.h"
9 #include "errno-util.h"
10 #include "glob-util.h"
11 #include "macro.h"
12 #include "path-util.h"
13 #include "strv.h"
14
closedir_wrapper(void * v)15 static void closedir_wrapper(void* v) {
16 (void) closedir(v);
17 }
18
safe_glob(const char * path,int flags,glob_t * pglob)19 int safe_glob(const char *path, int flags, glob_t *pglob) {
20 int k;
21
22 /* We want to set GLOB_ALTDIRFUNC ourselves, don't allow it to be set. */
23 assert(!(flags & GLOB_ALTDIRFUNC));
24
25 if (!pglob->gl_closedir)
26 pglob->gl_closedir = closedir_wrapper;
27 if (!pglob->gl_readdir)
28 pglob->gl_readdir = (struct dirent *(*)(void *)) readdir_no_dot;
29 if (!pglob->gl_opendir)
30 pglob->gl_opendir = (void *(*)(const char *)) opendir;
31 if (!pglob->gl_lstat)
32 pglob->gl_lstat = lstat;
33 if (!pglob->gl_stat)
34 pglob->gl_stat = stat;
35
36 errno = 0;
37 k = glob(path, flags | GLOB_ALTDIRFUNC, NULL, pglob);
38 if (k == GLOB_NOMATCH)
39 return -ENOENT;
40 if (k == GLOB_NOSPACE)
41 return -ENOMEM;
42 if (k != 0)
43 return errno_or_else(EIO);
44 if (strv_isempty(pglob->gl_pathv))
45 return -ENOENT;
46
47 return 0;
48 }
49
glob_exists(const char * path)50 int glob_exists(const char *path) {
51 _cleanup_globfree_ glob_t g = {};
52 int k;
53
54 assert(path);
55
56 k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE, &g);
57 if (k == -ENOENT)
58 return false;
59 if (k < 0)
60 return k;
61 return true;
62 }
63
glob_extend(char *** strv,const char * path,int flags)64 int glob_extend(char ***strv, const char *path, int flags) {
65 _cleanup_globfree_ glob_t g = {};
66 int k;
67
68 k = safe_glob(path, GLOB_NOSORT|GLOB_BRACE|flags, &g);
69 if (k < 0)
70 return k;
71
72 return strv_extend_strv(strv, g.gl_pathv, false);
73 }
74
glob_non_glob_prefix(const char * path,char ** ret)75 int glob_non_glob_prefix(const char *path, char **ret) {
76 /* Return the path of the path that has no glob characters. */
77
78 size_t n = strcspn(path, GLOB_CHARS);
79
80 if (path[n] != '\0')
81 while (n > 0 && path[n-1] != '/')
82 n--;
83
84 if (n == 0)
85 return -ENOENT;
86
87 char *ans = strndup(path, n);
88 if (!ans)
89 return -ENOMEM;
90 *ret = ans;
91 return 0;
92 }
93