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