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