path.c (23799B)
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" 16 #include "lib/container/smartlist.h" 17 #include "lib/sandbox/sandbox.h" 18 #include "lib/string/printf.h" 19 #include "lib/string/util_string.h" 20 #include "lib/string/compat_ctype.h" 21 #include "lib/string/compat_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; 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. */ 145 int 146 path_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. */ 164 void 165 clean_fname_for_stat(char *name) 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 * */ 195 int 196 get_parent_directory(char *fname) 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 */ 243 static char * 244 alloc_getcwd(void) 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 */ 280 char * 281 make_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. */ 372 static inline bool 373 is_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. */ 390 typedef 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. */ 396 static bool 397 add_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. */ 418 static struct smartlist_t * 419 get_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 477 end: 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. */ 491 static struct smartlist_t * 492 unglob_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 */ 539 static DIR * 540 prot_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 */ 550 static int 551 prot_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 */ 561 static int 562 prot_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 */ 571 static void 572 wrap_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 */ 584 static int 585 glob_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 */ 597 struct smartlist_t * 598 tor_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. */ 667 bool 668 has_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. */ 683 static struct smartlist_t * 684 unglob_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. */ 710 struct smartlist_t * 711 get_glob_opened_files(const char *pattern) 712 { 713 return get_glob_paths(pattern, unglob_opened_files, false); 714 }