Tor  0.4.7.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"
19 #include "lib/string/util_string.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. */
50 char *
51 get_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. */
84 char *
85 expand_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. */
144 int
145 path_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. */
163 void
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  * */
194 int
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  */
242 static 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  */
279 char *
280 make_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. */
371 static inline bool
372 is_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. */
389 typedef 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. */
395 static bool
396 add_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. */
417 static struct smartlist_t *
418 get_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 
476 end:
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. */
490 static struct smartlist_t *
491 unglob_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 */
538 static DIR *
539 prot_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 */
549 static int
550 prot_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 */
560 static int
561 prot_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 */
570 static void
571 wrap_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  */
583 static int
584 glob_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  */
596 struct smartlist_t *
597 tor_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. */
666 bool
667 has_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. */
682 static struct smartlist_t *
683 unglob_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. */
709 struct smartlist_t *
710 get_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:2434
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:52
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
struct smartlist_t * tor_glob(const char *pattern)
Definition: path.c:597
static bool is_glob_char(const char *pattern, int pos)
Definition: path.c:372
void clean_fname_for_stat(char *name)
Definition: path.c:164
bool has_glob(const char *s)
Definition: path.c:667
static struct smartlist_t * get_glob_paths(const char *pattern, unglob_fn unglob, bool final)
Definition: path.c:418
char * get_unquoted_path(const char *path)
Definition: path.c:51
char * expand_filename(const char *filename)
Definition: path.c:85
static struct smartlist_t * unglob_opened_files(const char *pattern, int prev_sep, int next_sep)
Definition: path.c:683
static char * alloc_getcwd(void)
Definition: path.c:243
int path_is_relative(const char *filename)
Definition: path.c:145
char * make_path_absolute(const char *fname)
Definition: path.c:280
struct smartlist_t * get_glob_opened_files(const char *pattern)
Definition: path.c:710
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:102
int strcmpend(const char *s1, const char *s2)
Definition: util_string.c:251
void tor_strreplacechar(char *s, char find, char replacement)
Definition: util_string.c:148
Header for util_string.c.