Tor 0.4.9.8
Loading...
Searching...
No Matches
path.c
Go to the documentation of this file.
1/* Copyright (c) 2003, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4/* See LICENSE for licensing information */
5
6/**
7 * \file path.c
8 *
9 * \brief Manipulate strings that contain filesystem paths.
10 **/
11
12#include "lib/fs/path.h"
13#include "lib/malloc/malloc.h"
14#include "lib/log/log.h"
15#include "lib/log/util_bug.h"
17#include "lib/sandbox/sandbox.h"
18#include "lib/string/printf.h"
22#include "lib/fs/files.h"
23#include "lib/fs/dir.h"
24#include "lib/fs/userdb.h"
25
26#ifdef HAVE_SYS_TYPES_H
27#include <sys/types.h>
28#endif
29#ifdef HAVE_SYS_STAT_H
30#include <sys/stat.h>
31#endif
32#ifdef HAVE_UNISTD_H
33#include <unistd.h>
34#endif
35
36#ifdef _WIN32
37#include <windows.h>
38#include <shlwapi.h>
39#else /* !(defined(_WIN32)) */
40#include <dirent.h>
41#include <glob.h>
42#endif /* defined(_WIN32) */
43
44#include <errno.h>
45#include <string.h>
46
47/** Removes enclosing quotes from <b>path</b> and unescapes quotes between the
48 * enclosing quotes. Backslashes are not unescaped. Return the unquoted
49 * <b>path</b> on success or 0 if <b>path</b> is not quoted correctly. */
50char *
51get_unquoted_path(const char *path)
52{
53 size_t len = strlen(path);
54
55 if (len == 0) {
56 return tor_strdup("");
57 }
58
59 int has_start_quote = (path[0] == '\"');
60 int has_end_quote = (len > 0 && path[len-1] == '\"');
61 if (has_start_quote != has_end_quote || (len == 1 && has_start_quote)) {
62 return NULL;
63 }
64
65 char *unquoted_path = tor_malloc(len - has_start_quote - has_end_quote + 1);
66 char *s = unquoted_path;
67 size_t i;
68 for (i = has_start_quote; i < len - has_end_quote; i++) {
69 if (path[i] == '\"' && (i > 0 && path[i-1] == '\\')) {
70 *(s-1) = path[i];
71 } else if (path[i] != '\"') {
72 *s++ = path[i];
73 } else { /* unescaped quote */
74 tor_free(unquoted_path);
75 return NULL;
76 }
77 }
78 *s = '\0';
79 return unquoted_path;
80}
81
82/** Expand any homedir prefix on <b>filename</b>; return a newly allocated
83 * string. */
84char *
85expand_filename(const char *filename)
86{
87 tor_assert(filename);
88#ifdef _WIN32
89 /* Might consider using GetFullPathName() as described here:
90 * http://etutorials.org/Programming/secure+programming/
91 * Chapter+3.+Input+Validation/3.7+Validating+Filenames+and+Paths/
92 */
93 return tor_strdup(filename);
94#else /* !defined(_WIN32) */
95 if (*filename == '~') {
96 char *home, *result=NULL;
97 const char *rest;
98
99 if (filename[1] == '/' || filename[1] == '\0') {
100 home = getenv("HOME");
101 if (!home) {
102 log_warn(LD_CONFIG, "Couldn't find $HOME environment variable while "
103 "expanding \"%s\"; defaulting to \"\".", filename);
104 home = tor_strdup("");
105 } else {
106 home = tor_strdup(home);
107 }
108 rest = strlen(filename)>=2?(filename+2):"";
109 } else {
110#ifdef HAVE_PWD_H
111 char *username;
112 const char *slash;
113 slash = strchr(filename, '/');
114 if (slash)
115 username = tor_strndup(filename+1,slash-filename-1);
116 else
117 username = tor_strdup(filename+1);
118 if (!(home = get_user_homedir(username))) {
119 log_warn(LD_CONFIG,"Couldn't get homedir for \"%s\"",username);
120 tor_free(username);
121 return NULL;
122 }
123 tor_free(username);
124 rest = slash ? (slash+1) : "";
125#else /* !defined(HAVE_PWD_H) */
126 log_warn(LD_CONFIG, "Couldn't expand homedir on system without pwd.h");
127 return tor_strdup(filename);
128#endif /* defined(HAVE_PWD_H) */
129 }
130 tor_assert(home);
131 /* Remove trailing slash. */
132 if (strlen(home)>1 && !strcmpend(home,PATH_SEPARATOR)) {
133 home[strlen(home)-1] = '\0';
134 }
135 tor_asprintf(&result,"%s"PATH_SEPARATOR"%s",home,rest);
136 tor_free(home);
137 return result;
138 } else {
139 return tor_strdup(filename);
140 }
141#endif /* defined(_WIN32) */
142}
143
144/** Return true iff <b>filename</b> is a relative path. */
145int
146path_is_relative(const char *filename)
147{
148 if (filename && filename[0] == '/')
149 return 0;
150#ifdef _WIN32
151 else if (filename && filename[0] == '\\')
152 return 0;
153 else if (filename && strlen(filename)>3 && TOR_ISALPHA(filename[0]) &&
154 filename[1] == ':' && filename[2] == '\\')
155 return 0;
156#endif /* defined(_WIN32) */
157 else
158 return 1;
159}
160
161/** Clean up <b>name</b> so that we can use it in a call to "stat". On Unix,
162 * we do nothing. On Windows, we remove a trailing slash, unless the path is
163 * the root of a disk. */
164void
166{
167#ifdef _WIN32
168 size_t len = strlen(name);
169 if (!len)
170 return;
171 if (name[len-1]=='\\' || name[len-1]=='/') {
172 if (len == 1 || (len==3 && name[1]==':'))
173 return;
174 name[len-1]='\0';
175 }
176#else /* !defined(_WIN32) */
177 (void)name;
178#endif /* defined(_WIN32) */
179}
180
181/** Modify <b>fname</b> to contain the name of its parent directory. Doesn't
182 * actually examine the filesystem; does a purely syntactic modification.
183 *
184 * The parent of the root director is considered to be itself.
185 *
186 * Path separators are the forward slash (/) everywhere and additionally
187 * the backslash (\‍) on Win32.
188 *
189 * Cuts off any number of trailing path separators but otherwise ignores
190 * them for purposes of finding the parent directory.
191 *
192 * Returns 0 if a parent directory was successfully found, -1 otherwise (fname
193 * did not have any path separators or only had them at the end).
194 * */
195int
197{
198 char *cp;
199 int at_end = 1;
200 tor_assert(fname);
201#ifdef _WIN32
202 /* If we start with, say, c:, then don't consider that the start of the path
203 */
204 if (fname[0] && fname[1] == ':') {
205 fname += 2;
206 }
207#endif /* defined(_WIN32) */
208 /* Now we want to remove all path-separators at the end of the string,
209 * and to remove the end of the string starting with the path separator
210 * before the last non-path-separator. In perl, this would be
211 * s#[/]*$##; s#/[^/]*$##;
212 * on a unixy platform.
213 */
214 cp = fname + strlen(fname);
215 at_end = 1;
216 while (--cp >= fname) {
217 int is_sep = (*cp == '/'
218#ifdef _WIN32
219 || *cp == '\\'
220#endif
221 );
222 if (is_sep) {
223 if (cp == fname) {
224 /* This is the first separator in the file name; don't remove it! */
225 cp[1] = '\0';
226 return 0;
227 }
228 *cp = '\0';
229 if (! at_end)
230 return 0;
231 } else {
232 at_end = 0;
233 }
234 }
235 return -1;
236}
237
238#ifndef _WIN32
239/** Return a newly allocated string containing the output of getcwd(). Return
240 * NULL on failure. (We can't just use getcwd() into a PATH_MAX buffer, since
241 * Hurd hasn't got a PATH_MAX.)
242 */
243static char *
245{
246#ifdef HAVE_GET_CURRENT_DIR_NAME
247 /* Glibc makes this nice and simple for us. */
248 char *cwd = get_current_dir_name();
249 char *result = NULL;
250 if (cwd) {
251 /* We make a copy here, in case tor_malloc() is not malloc(). */
252 result = tor_strdup(cwd);
253 raw_free(cwd); // alias for free to avoid tripping check-spaces.
254 }
255 return result;
256#else /* !defined(HAVE_GET_CURRENT_DIR_NAME) */
257 size_t size = 1024;
258 char *buf = NULL;
259 char *ptr = NULL;
260
261 while (ptr == NULL) {
262 buf = tor_realloc(buf, size);
263 ptr = getcwd(buf, size);
264
265 if (ptr == NULL && errno != ERANGE) {
266 tor_free(buf);
267 return NULL;
268 }
269
270 size *= 2;
271 }
272 return buf;
273#endif /* defined(HAVE_GET_CURRENT_DIR_NAME) */
274}
275#endif /* !defined(_WIN32) */
276
277/** Expand possibly relative path <b>fname</b> to an absolute path.
278 * Return a newly allocated string, which may be a duplicate of <b>fname</b>.
279 */
280char *
281make_path_absolute(const char *fname)
282{
283#ifdef _WIN32
284 char *absfname_malloced = _fullpath(NULL, fname, 1);
285
286 /* We don't want to assume that tor_free can free a string allocated
287 * with malloc. On failure, return fname (it's better than nothing). */
288 char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname);
289 if (absfname_malloced) raw_free(absfname_malloced);
290
291 return absfname;
292#else /* !defined(_WIN32) */
293 char *absfname = NULL, *path = NULL;
294
295 tor_assert(fname);
296
297 if (fname[0] == '/') {
298 absfname = tor_strdup(fname);
299 } else {
300 path = alloc_getcwd();
301 if (path) {
302 tor_asprintf(&absfname, "%s/%s", path, fname);
303 tor_free(path);
304 } else {
305 /* LCOV_EXCL_START Can't make getcwd fail. */
306 /* If getcwd failed, the best we can do here is keep using the
307 * relative path. (Perhaps / isn't readable by this UID/GID.) */
308 log_warn(LD_GENERAL, "Unable to find current working directory: %s",
309 strerror(errno));
310 absfname = tor_strdup(fname);
311 /* LCOV_EXCL_STOP */
312 }
313 }
314 return absfname;
315#endif /* defined(_WIN32) */
316}
317
318/* The code below implements tor_glob and get_glob_opened_files. Because it is
319 * not easy to understand it by looking at individual functions, the big
320 * picture explanation here should be read first.
321 *
322 * Purpose of the functions:
323 * - tor_glob - receives a pattern and returns all the paths that result from
324 * its glob expansion, globs can be present on all path components.
325 * - get_glob_opened_files - receives a pattern and returns all the paths that
326 * are opened during its expansion (the paths before any path fragment that
327 * contains a glob as they have to be opened to check for glob matches). This
328 * is used to get the paths that have to be added to the seccomp sandbox
329 * allowed list.
330 *
331 * Due to OS API differences explained below, the implementation of tor_glob is
332 * completely different for Windows and POSIX systems, so we ended up with
333 * three different implementations:
334 * - tor_glob for POSIX - as POSIX glob does everything we need, we simply call
335 * it and process the results. This is completely implemented in tor_glob.
336 * - tor_glob for WIN32 - because the WIN32 API only supports expanding globs
337 * in the last path fragment, we need to expand the globs in each path
338 * fragment manually and call recursively to get the same behaviour as POSIX
339 * glob. When there are no globs in pattern, we know we are on the last path
340 * fragment and collect the full path.
341 * - get_glob_opened_files - because the paths before any path fragment with a
342 * glob will be opened to check for matches, we need to collect them and we
343 * need to expand the globs in each path fragments and call recursively until
344 * we find no more globs.
345 *
346 * As seen from the description above, both tor_glob for WIN32 and
347 * get_glob_opened_files receive a pattern and return a list of paths and have
348 * to expand all path fragments that contain globs and call themselves
349 * recursively. The differences are:
350 * - get_glob_opened_files collects paths before path fragments with globs
351 * while tor_glob for WIN32 collects full paths resulting from the expansion
352 * of all globs.
353 * - get_glob_opened_files can call tor_glob to expand path fragments with
354 * globs while tor_glob for WIN32 cannot because it IS tor_glob. For tor_glob
355 * for WIN32, an auxiliary function has to be used for this purpose.
356 *
357 * To avoid code duplication, the logic of tor_glob for WIN32 and
358 * get_glob_opened_files is implemented in get_glob_paths. The differences are
359 * configured by the extra function parameters:
360 * - final - if true, returns a list of paths obtained from expanding pattern
361 * (implements tor_glob). Otherwise, returns the paths before path fragments
362 * with globs (implements get_glob_opened_files).
363 * - unglob - function used to expand a path fragment. The function signature
364 * is defined by the unglob_fn typedef. Two implementations are available:
365 * - unglob_win32 - uses tor_listdir and PathMatchSpec (for tor_glob WIN32)
366 * - unglob_opened_files - uses tor_glob (for get_glob_opened_files)
367 */
368
369/** Returns true if the character at position <b>pos</b> in <b>pattern</b> is
370 * considered a glob. Returns false otherwise. Takes escaping into account on
371 * systems where escaping globs is supported. */
372static inline bool
373is_glob_char(const char *pattern, int pos)
374{
375 bool is_glob = pattern[pos] == '*' || pattern[pos] == '?';
376#ifdef _WIN32
377 return is_glob;
378#else /* !defined(_WIN32) */
379 bool is_escaped = pos > 0 && pattern[pos-1] == '\\';
380 return is_glob && !is_escaped;
381#endif /* defined(_WIN32) */
382}
383
384/** Expands the first path fragment of <b>pattern</b> that contains globs. The
385 * path fragment is between <b>prev_sep</b> and <b>next_sep</b>. If the path
386 * fragment is the last fragment of <b>pattern</b>, <b>next_sep</b> will be the
387 * index of the last char. Returns a list of paths resulting from the glob
388 * expansion of the path fragment. Anything after <b>next_sep</b> is not
389 * included in the returned list. Returns NULL on failure. */
390typedef struct smartlist_t * unglob_fn(const char *pattern, int prev_sep,
391 int next_sep);
392
393/** Adds <b>path</b> to <b>result</b> if it exists and is a file type we can
394 * handle. Returns false if <b>path</b> is a file type we cannot handle,
395 * returns true otherwise. Used on tor_glob for WIN32. */
396static bool
397add_non_glob_path(const char *path, struct smartlist_t *result)
398{
399 file_status_t file_type = file_status(path);
400 if (file_type == FN_ERROR) {
401 return false;
402 } else if (file_type != FN_NOENT) {
403 char *to_add = tor_strdup(path);
404 clean_fname_for_stat(to_add);
405 smartlist_add(result, to_add);
406 }
407 /* If WIN32 tor_glob is called with a non-existing path, we want it to
408 * return an empty list instead of error to match the regular version */
409 return true;
410}
411
412/** Auxiliary function used by get_glob_opened_files and WIN32 tor_glob.
413 * Returns a list of paths obtained from <b>pattern</b> using <b>unglob</b> to
414 * expand each path fragment. If <b>final</b> is true, the paths are the result
415 * of the glob expansion of <b>pattern</b> (implements tor_glob). Otherwise,
416 * the paths are the paths opened by glob while expanding <b>pattern</b>
417 * (implements get_glob_opened_files). Returns NULL on failure. */
418static struct smartlist_t *
419get_glob_paths(const char *pattern, unglob_fn unglob, bool final)
420{
421 smartlist_t *result = smartlist_new();
422 int i, prev_sep = -1, next_sep = -1;
423 bool is_glob = false, error_found = false, is_sep = false, is_last = false;
424
425 // find first path fragment with globs
426 for (i = 0; pattern[i]; i++) {
427 is_glob = is_glob || is_glob_char(pattern, i);
428 is_last = !pattern[i+1];
429 is_sep = pattern[i] == *PATH_SEPARATOR || pattern[i] == '/';
430 if (is_sep || is_last) {
431 prev_sep = next_sep;
432 next_sep = i; // next_sep+1 is start of next fragment or end of string
433 if (is_glob) {
434 break;
435 }
436 }
437 }
438
439 if (!is_glob) { // pattern fully expanded or no glob in pattern
440 if (final && !add_non_glob_path(pattern, result)) {
441 error_found = true;
442 goto end;
443 }
444 return result;
445 }
446
447 if (!final) {
448 // add path before the glob to result
449 int len = prev_sep < 1 ? prev_sep + 1 : prev_sep; // handle /*
450 char *path_until_glob = tor_strndup(pattern, len);
451 smartlist_add(result, path_until_glob);
452 }
453
454 smartlist_t *unglobbed_paths = unglob(pattern, prev_sep, next_sep);
455 if (!unglobbed_paths) {
456 error_found = true;
457 } else {
458 // for each path for current fragment, add the rest of the pattern
459 // and call recursively to get all expanded paths
460 SMARTLIST_FOREACH_BEGIN(unglobbed_paths, char *, current_path) {
461 char *next_path;
462 tor_asprintf(&next_path, "%s"PATH_SEPARATOR"%s", current_path,
463 &pattern[next_sep+1]);
464 smartlist_t *opened_next = get_glob_paths(next_path, unglob, final);
465 tor_free(next_path);
466 if (!opened_next) {
467 error_found = true;
468 break;
469 }
470 smartlist_add_all(result, opened_next);
471 smartlist_free(opened_next);
472 } SMARTLIST_FOREACH_END(current_path);
473 SMARTLIST_FOREACH(unglobbed_paths, char *, p, tor_free(p));
474 smartlist_free(unglobbed_paths);
475 }
476
477end:
478 if (error_found) {
479 SMARTLIST_FOREACH(result, char *, p, tor_free(p));
480 smartlist_free(result);
481 result = NULL;
482 }
483 return result;
484}
485
486#ifdef _WIN32
487/** Expands globs in <b>pattern</b> for the path fragment between
488 * <b>prev_sep</b> and <b>next_sep</b> using the WIN32 API. Returns NULL on
489 * failure. Used by the WIN32 implementation of tor_glob. Implements unglob_fn,
490 * see its description for more details. */
491static struct smartlist_t *
492unglob_win32(const char *pattern, int prev_sep, int next_sep)
493{
494 smartlist_t *result = smartlist_new();
495 int len = prev_sep < 1 ? prev_sep + 1 : prev_sep; // handle /*
496 char *path_until_glob = tor_strndup(pattern, len);
497
498 if (!is_file(file_status(path_until_glob))) {
499 smartlist_t *filenames = tor_listdir(path_until_glob);
500 if (!filenames) {
501 smartlist_free(result);
502 result = NULL;
503 } else {
504 SMARTLIST_FOREACH_BEGIN(filenames, char *, filename) {
505 TCHAR tpattern[MAX_PATH] = {0};
506 TCHAR tfile[MAX_PATH] = {0};
507 char *full_path;
508 tor_asprintf(&full_path, "%s"PATH_SEPARATOR"%s",
509 path_until_glob, filename);
510 char *path_curr_glob = tor_strndup(pattern, next_sep + 1);
511 // *\ must return only dirs, remove \ from the pattern so it matches
512 if (is_dir(file_status(full_path))) {
513 clean_fname_for_stat(path_curr_glob);
514 }
515#ifdef UNICODE
516 mbstowcs(tpattern, path_curr_glob, MAX_PATH);
517 mbstowcs(tfile, full_path, MAX_PATH);
518#else /* !defined(UNICODE) */
519 strlcpy(tpattern, path_curr_glob, MAX_PATH);
520 strlcpy(tfile, full_path, MAX_PATH);
521#endif /* defined(UNICODE) */
522 if (PathMatchSpec(tfile, tpattern)) {
523 smartlist_add(result, full_path);
524 } else {
525 tor_free(full_path);
526 }
527 tor_free(path_curr_glob);
528 } SMARTLIST_FOREACH_END(filename);
529 SMARTLIST_FOREACH(filenames, char *, p, tor_free(p));
530 smartlist_free(filenames);
531 }
532 }
533 tor_free(path_until_glob);
534 return result;
535}
536#elif HAVE_GLOB
537#ifdef GLOB_ALTDIRFUNC // prevent warning about unused functions
538/** Same as opendir but calls sandbox_intern_string before */
539static DIR *
540prot_opendir(const char *name)
541{
542 if (sandbox_interned_string_is_missing(name)) {
543 errno = EPERM;
544 return NULL;
545 }
546 return opendir(sandbox_intern_string(name));
547}
548
549/** Same as stat but calls sandbox_intern_string before */
550static int
551prot_stat(const char *pathname, struct stat *buf)
552{
553 if (sandbox_interned_string_is_missing(pathname)) {
554 errno = EPERM;
555 return -1;
556 }
557 return stat(sandbox_intern_string(pathname), buf);
558}
559
560/** Same as lstat but calls sandbox_intern_string before */
561static int
562prot_lstat(const char *pathname, struct stat *buf)
563{
564 if (sandbox_interned_string_is_missing(pathname)) {
565 errno = EPERM;
566 return -1;
567 }
568 return lstat(sandbox_intern_string(pathname), buf);
569}
570/** As closedir, but has the right type for gl_closedir */
571static void
572wrap_closedir(void *arg)
573{
574 closedir(arg);
575}
576#endif /* defined(GLOB_ALTDIRFUNC) */
577
578/** Function passed to glob to handle processing errors. <b>epath</b> is the
579 * path that caused the error and <b>eerrno</b> is the errno set by the
580 * function that failed. We want to ignore ENOENT and ENOTDIR because, in BSD
581 * systems, these are not ignored automatically, which makes glob fail when
582 * globs expand to non-existing paths and GLOB_ERR is set.
583 */
584static int
585glob_errfunc(const char *epath, int eerrno)
586{
587 (void)epath;
588 return eerrno == ENOENT || eerrno == ENOTDIR ? 0 : -1;
589}
590#endif /* defined(HAVE_GLOB) */
591
592/** Return a new list containing the paths that match the pattern
593 * <b>pattern</b>. Return NULL on error. On POSIX systems, errno is set by the
594 * glob function or is set to EPERM if glob tried to access a file not allowed
595 * by the seccomp sandbox.
596 */
597struct smartlist_t *
598tor_glob(const char *pattern)
599{
600 smartlist_t *result = NULL;
601
602#ifdef _WIN32
603 // PathMatchSpec does not support forward slashes, change them to backslashes
604 char *pattern_normalized = tor_strdup(pattern);
605 tor_strreplacechar(pattern_normalized, '/', *PATH_SEPARATOR);
606 result = get_glob_paths(pattern_normalized, unglob_win32, true);
607 tor_free(pattern_normalized);
608#elif HAVE_GLOB /* !(defined(_WIN32)) */
609 glob_t matches;
610 int flags = GLOB_NOSORT;
611#ifdef GLOB_ALTDIRFUNC
612 /* use functions that call sandbox_intern_string */
613 flags |= GLOB_ALTDIRFUNC;
614 typedef void *(*gl_opendir)(const char * name);
615 typedef struct dirent *(*gl_readdir)(void *);
616 typedef void (*gl_closedir)(void *);
617 matches.gl_opendir = (gl_opendir) &prot_opendir;
618 matches.gl_readdir = (gl_readdir) &readdir;
619 matches.gl_closedir = (gl_closedir) &wrap_closedir;
620 matches.gl_stat = &prot_stat;
621 matches.gl_lstat = &prot_lstat;
622#endif /* defined(GLOB_ALTDIRFUNC) */
623 // use custom error handler to workaround BSD quirks and do not set GLOB_ERR
624 // because it would make glob fail on error even if the error handler ignores
625 // the error
626 int ret = glob(pattern, flags, glob_errfunc, &matches);
627 if (ret == GLOB_NOMATCH) {
628 return smartlist_new();
629 } else if (ret != 0) {
630 return NULL;
631 }
632
633 // #40141, !249: workaround for glibc bug where patterns ending in path
634 // separator match files and folders instead of folders only.
635 // this could be in #ifdef __GLIBC__ but: 1. it might affect other libcs too,
636 // and 2. it doesn't cost much to stat each match again since libc is already
637 // supposed to do it (otherwise the file may be on slow NFS or something)
638 size_t pattern_len = strlen(pattern);
639 bool dir_only = pattern_len > 0 && pattern[pattern_len-1] == *PATH_SEPARATOR;
640
641 result = smartlist_new();
642 size_t i;
643 for (i = 0; i < matches.gl_pathc; i++) {
644 char *match = tor_strdup(matches.gl_pathv[i]);
645 size_t len = strlen(match);
646 if (len > 0 && match[len-1] == *PATH_SEPARATOR) {
647 match[len-1] = '\0';
648 }
649
650 if (!dir_only || (dir_only && is_dir(file_status(match)))) {
651 smartlist_add(result, match);
652 } else {
653 tor_free(match);
654 }
655 }
656 globfree(&matches);
657#else
658 (void)pattern;
659 return result;
660#endif /* defined(_WIN32) || ... */
661
662 return result;
663}
664
665/** Returns true if <b>s</b> contains characters that can be globbed.
666 * Returns false otherwise. */
667bool
668has_glob(const char *s)
669{
670 int i;
671 for (i = 0; s[i]; i++) {
672 if (is_glob_char(s, i)) {
673 return true;
674 }
675 }
676 return false;
677}
678
679/** Expands globs in <b>pattern</b> for the path fragment between
680 * <b>prev_sep</b> and <b>next_sep</b> using tor_glob. Returns NULL on
681 * failure. Used by get_glob_opened_files. Implements unglob_fn, see its
682 * description for more details. */
683static struct smartlist_t *
684unglob_opened_files(const char *pattern, int prev_sep, int next_sep)
685{
686 (void)prev_sep;
687 smartlist_t *result = smartlist_new();
688 // if the following fragments have no globs, we're done
689 if (has_glob(&pattern[next_sep+1])) {
690 // if there is a glob after next_sep, we know next_sep is a separator and
691 // not the last char and glob_path will have the path without the separator
692 char *glob_path = tor_strndup(pattern, next_sep);
693 smartlist_t *child_paths = tor_glob(glob_path);
694 tor_free(glob_path);
695 if (!child_paths) {
696 smartlist_free(result);
697 result = NULL;
698 } else {
699 smartlist_add_all(result, child_paths);
700 smartlist_free(child_paths);
701 }
702 }
703 return result;
704}
705
706/** Returns a list of files that are opened by the tor_glob function when
707 * called with <b>pattern</b>. Returns NULL on error. The purpose of this
708 * function is to create a list of files to be added to the sandbox white list
709 * before the sandbox is enabled. */
710struct smartlist_t *
711get_glob_opened_files(const char *pattern)
712{
713 return get_glob_paths(pattern, unglob_opened_files, false);
714}
Locale-independent character-type inspection (header)
Header for compat_string.c.
const char * name
Definition config.c:2472
smartlist_t * tor_listdir(const char *dirname)
Definition dir.c:307
Header for dir.c.
Wrappers for reading and writing data to files on disk.
file_status_t
Definition files.h:59
Headers for log.c.
#define LD_GENERAL
Definition log.h:62
#define LD_CONFIG
Definition log.h:68
Headers for util_malloc.c.
#define tor_free(p)
Definition malloc.h:56
static bool add_non_glob_path(const char *path, struct smartlist_t *result)
Definition path.c:397
int get_parent_directory(char *fname)
Definition path.c:196
char * make_path_absolute(const char *fname)
Definition path.c:281
static bool is_glob_char(const char *pattern, int pos)
Definition path.c:373
static struct smartlist_t * get_glob_paths(const char *pattern, unglob_fn unglob, bool final)
Definition path.c:419
void clean_fname_for_stat(char *name)
Definition path.c:165
static char * alloc_getcwd(void)
Definition path.c:244
struct smartlist_t * tor_glob(const char *pattern)
Definition path.c:598
bool has_glob(const char *s)
Definition path.c:668
static struct smartlist_t * unglob_opened_files(const char *pattern, int prev_sep, int next_sep)
Definition path.c:684
struct smartlist_t * get_glob_opened_files(const char *pattern)
Definition path.c:711
int path_is_relative(const char *filename)
Definition path.c:146
char * get_unquoted_path(const char *path)
Definition path.c:51
char * expand_filename(const char *filename)
Definition path.c:85
Header for path.c.
int tor_asprintf(char **strp, const char *fmt,...)
Definition printf.c:75
Header for printf.c.
Header file for sandbox.c.
#define sandbox_intern_string(s)
Definition sandbox.h:113
Header for smartlist.c.
void smartlist_add_all(smartlist_t *s1, const smartlist_t *s2)
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
char * get_user_homedir(const char *username)
Definition userdb.c:127
Header for userdb.c.
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition util_bug.h:103
int strcmpend(const char *s1, const char *s2)
void tor_strreplacechar(char *s, char find, char replacement)
Header for util_string.c.