This returns an expanded (absolute) filename for the merge-file name if * the name has any slashes in it OR if the parent_dirscan var is True; * otherwise it returns the original merge_file name. If the len_ptr value * is non-NULL the merge_file name is limited by the referenced length * value and will be updated with the length of the resulting name. We * always return a name that is null
| 597 | * always return a name that is null terminated, even if the merge_file |
| 598 | * name was not. */ |
| 599 | static char *parse_merge_name(const char *merge_file, unsigned int *len_ptr, |
| 600 | unsigned int prefix_skip) |
| 601 | { |
| 602 | static char buf[MAXPATHLEN]; |
| 603 | char *fn, tmpbuf[MAXPATHLEN]; |
| 604 | unsigned int fn_len; |
| 605 | |
| 606 | if (!parent_dirscan && *merge_file != '/') { |
| 607 | /* Return the name unchanged it doesn't have any slashes. */ |
| 608 | if (len_ptr) { |
| 609 | const char *p = merge_file + *len_ptr; |
| 610 | while (--p > merge_file && *p != '/') {} |
| 611 | if (p == merge_file) { |
| 612 | strlcpy(buf, merge_file, *len_ptr + 1); |
| 613 | return buf; |
| 614 | } |
| 615 | } else if (strchr(merge_file, '/') == NULL) |
| 616 | return (char *)merge_file; |
| 617 | } |
| 618 | |
| 619 | fn = *merge_file == '/' ? buf : tmpbuf; |
| 620 | if (sanitize_paths) { |
| 621 | const char *r = prefix_skip ? "/" : NULL; |
| 622 | /* null-terminate the name if it isn't already */ |
| 623 | if (len_ptr && merge_file[*len_ptr]) { |
| 624 | char *to = fn == buf ? tmpbuf : buf; |
| 625 | strlcpy(to, merge_file, *len_ptr + 1); |
| 626 | merge_file = to; |
| 627 | } |
| 628 | if (!sanitize_path(fn, merge_file, r, dirbuf_depth, SP_DEFAULT)) { |
| 629 | rprintf(FERROR, "merge-file name overflows: %s\n", |
| 630 | merge_file); |
| 631 | return NULL; |
| 632 | } |
| 633 | fn_len = strlen(fn); |
| 634 | } else { |
| 635 | strlcpy(fn, merge_file, len_ptr ? *len_ptr + 1 : MAXPATHLEN); |
| 636 | fn_len = clean_fname(fn, CFN_COLLAPSE_DOT_DOT_DIRS); |
| 637 | } |
| 638 | |
| 639 | /* If the name isn't in buf yet, it wasn't absolute. */ |
| 640 | if (fn != buf) { |
| 641 | int d_len = dirbuf_len - prefix_skip; |
| 642 | if (d_len + fn_len >= MAXPATHLEN) { |
| 643 | rprintf(FERROR, "merge-file name overflows: %s\n", fn); |
| 644 | return NULL; |
| 645 | } |
| 646 | memcpy(buf, dirbuf + prefix_skip, d_len); |
| 647 | memcpy(buf + d_len, fn, fn_len + 1); |
| 648 | fn_len = clean_fname(buf, CFN_COLLAPSE_DOT_DOT_DIRS); |
| 649 | } |
| 650 | |
| 651 | if (len_ptr) |
| 652 | *len_ptr = fn_len; |
| 653 | return buf; |
| 654 | } |
| 655 | |
| 656 | /* Sets the dirbuf and dirbuf_len values. */ |
no test coverage detected