X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/a71b436858ba82aa171bd4b9f7deccd69a7541b1..refs/heads/wip/copy-unsafe-links-double:/flist.c diff --git a/flist.c b/flist.c index a167c3b9..1819e39c 100644 --- a/flist.c +++ b/flist.c @@ -198,7 +198,8 @@ void show_flist_stats(void) * * The stat structure pointed to by stp will contain information about the * link or the referent as appropriate, if they exist. */ -static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf) +static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf, + unsigned int *phys_depth_p) { #ifdef SUPPORT_LINKS if (link_stat(path, stp, copy_dirlinks) < 0) @@ -208,11 +209,12 @@ static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf) if (llen < 0) return -1; linkbuf[llen] = '\0'; - if (copy_unsafe_links && unsafe_symlink(linkbuf, path)) { + if (copy_unsafe_links && unsafe_symlink(linkbuf, *phys_depth_p)) { if (INFO_GTE(SYMSAFE, 1)) { rprintf(FINFO,"copying unsafe symlink \"%s\" -> \"%s\"\n", path, linkbuf); } + *phys_depth_p = 0; return x_stat(path, stp, NULL); } if (munge_symlinks && am_sender && llen > SYMLINK_PREFIX_LEN @@ -221,6 +223,8 @@ static int readlink_stat(const char *path, STRUCT_STAT *stp, char *linkbuf) llen - SYMLINK_PREFIX_LEN + 1); } } + if (copy_unsafe_links && S_ISDIR(stp->st_mode)) + (*phys_depth_p)++; return 0; #else return x_stat(path, stp, NULL); @@ -301,7 +305,7 @@ static int is_excluded(const char *fname, int is_dir, int filter_level) } static void send_directory(int f, struct file_list *flist, - char *fbuf, int len, int flags); + char *fbuf, int len, int flags, unsigned int phys_depth); static const char *pathname, *orig_dir; static int pathname_len; @@ -1131,6 +1135,12 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x /* Create a file_struct for a named file by reading its stat() information * and performing extensive checks against global options. * + * If we're the sender and --copy-unsafe-links is on, we want to consider a + * symlink unsafe if it leaves the subtree established by another unsafe + * symlink, but that can't be determined based on "fname". So the depth of + * real directories since the last unsafe symlink is passed as "phys_depth". + * In other cases, "phys_depth" is ignored. + * * Returns a pointer to the new file struct, or NULL if there was an error * or this file should be excluded. * @@ -1139,7 +1149,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x * "io_error |= IOERR_GENERAL" to avoid deletion of the file from the * destination if --delete is on. */ struct file_struct *make_file(const char *fname, struct file_list *flist, - STRUCT_STAT *stp, int flags, int filter_level) + STRUCT_STAT *stp, int flags, int filter_level, + unsigned int phys_depth) { static char *lastdir; static int lastdir_len = -1; @@ -1167,7 +1178,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, * dir, or a request to delete a specific file. */ st = *stp; *linkname = '\0'; /* make IBM code checker happy */ - } else if (readlink_stat(thisname, &st, linkname) != 0) { + } else if (readlink_stat(thisname, &st, linkname, &phys_depth) != 0) { int save_errno = errno; /* See if file is excluded before reporting an error. */ if (filter_level != NO_FILTERS @@ -1314,6 +1325,9 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, extra_len += SUM_EXTRA_CNT * EXTRA_LEN; } + if (copy_unsafe_links && S_ISDIR(st.st_mode)) + extra_len += EXTRA_LEN; // F_DIR_PHYS_DEPTH + #if EXTRA_ROUNDING > 0 if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN)) extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN; @@ -1398,6 +1412,9 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, if (sender_keeps_checksum && S_ISREG(st.st_mode)) memcpy(F_SUM(file), tmp_sum, checksum_len); + if (copy_unsafe_links && S_ISDIR(st.st_mode)) + F_DIR_PHYS_DEPTH(file) = phys_depth; /* as adjusted by readlink_stat */ + if (unsort_ndx) F_NDX(file) = stats.num_dirs; @@ -1412,11 +1429,12 @@ void unmake_file(struct file_struct *file) static struct file_struct *send_file_name(int f, struct file_list *flist, const char *fname, STRUCT_STAT *stp, - int flags, int filter_level) + int flags, int filter_level, + unsigned int phys_depth) { struct file_struct *file; - file = make_file(fname, flist, stp, flags, filter_level); + file = make_file(fname, flist, stp, flags, filter_level, phys_depth); if (!file) return NULL; @@ -1570,7 +1588,7 @@ static void send_if_directory(int f, struct file_list *flist, return; } save_filters = push_local_filters(fbuf, len); - send_directory(f, flist, fbuf, len, flags); + send_directory(f, flist, fbuf, len, flags, F_DIR_PHYS_DEPTH(file)); pop_local_filters(save_filters); fbuf[ol] = '\0'; if (is_dot_dir) @@ -1703,7 +1721,7 @@ static void interpret_stat_error(const char *fname, int is_dir) * might call this with f set to -2, which also indicates that local filter * rules should be ignored. */ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, - int flags) + int flags, unsigned int phys_depth) { struct dirent *di; unsigned remainder; @@ -1752,7 +1770,7 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, continue; } - send_file_name(f, flist, fbuf, NULL, flags, filter_level); + send_file_name(f, flist, fbuf, NULL, flags, filter_level, phys_depth); } fbuf[len] = '\0'; @@ -1772,6 +1790,10 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, } } +/* Used in a few places where we need to pass a phys_depth but can't easily + * determine what it should be. FIXME! */ +#define FIXME_path_depth path_depth + static void send_implied_dirs(int f, struct file_list *flist, char *fname, char *start, char *limit, int flags, char name_type) { @@ -1826,14 +1848,16 @@ static void send_implied_dirs(int f, struct file_list *flist, char *fname, for (slash = start; (slash = strchr(slash+1, '/')) != NULL; ) { *slash = '\0'; - file = send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS); + file = send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS, + FIXME_path_depth(fname)); depth++; if (!inc_recurse && file && S_ISDIR(file->mode)) change_local_filter_dir(fname, strlen(fname), depth); *slash = '/'; } - file = send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS); + file = send_file_name(f, flist, fname, NULL, flags, ALL_FILTERS, + FIXME_path_depth(fname)); if (inc_recurse) { if (file && !S_ISDIR(file->mode)) file = NULL; @@ -1897,7 +1921,7 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist) } filesystem_dev = st.st_dev; } - send_directory(f, flist, fbuf, dlen, flags); + send_directory(f, flist, fbuf, dlen, flags, F_DIR_PHYS_DEPTH(file)); } if (!relative_paths) @@ -1930,9 +1954,11 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist) interpret_stat_error(fbuf, True); continue; } - send_file_name(f, flist, fbuf, &st, FLAG_TOP_DIR | flags, ALL_FILTERS); + send_file_name(f, flist, fbuf, &st, FLAG_TOP_DIR | flags, ALL_FILTERS, + FIXME_path_depth(fbuf)); } else - send_file_name(f, flist, fbuf, NULL, FLAG_TOP_DIR | flags, ALL_FILTERS); + send_file_name(f, flist, fbuf, NULL, FLAG_TOP_DIR | flags, ALL_FILTERS, + FIXME_path_depth(fbuf)); } free(relname_list); @@ -2174,7 +2200,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (*fn == '.' && fn[1] == '/' && !implied_dot_dir) { send_file_name(f, flist, ".", NULL, (flags | FLAG_IMPLIED_DIR) & ~FLAG_CONTENT_DIR, - ALL_FILTERS); + ALL_FILTERS, 0); implied_dot_dir = 1; } len = clean_fname(fn, CFN_KEEP_TRAILING_SLASH @@ -2278,7 +2304,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) struct file_struct *file; file = send_file_name(f, flist, fbuf, &st, FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags, - NO_FILTERS); + NO_FILTERS, FIXME_path_depth(fbuf)); if (!file) continue; if (inc_recurse) { @@ -2287,12 +2313,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) send_dir_depth = 0; change_local_filter_dir(fbuf, len, send_dir_depth); } - send_directory(f, flist, fbuf, len, flags); + send_directory(f, flist, fbuf, len, flags, F_DIR_PHYS_DEPTH(file)); } } else send_if_directory(f, flist, file, fbuf, len, flags); } else - send_file_name(f, flist, fbuf, &st, flags, NO_FILTERS); + send_file_name(f, flist, fbuf, &st, flags, NO_FILTERS, + FIXME_path_depth(fbuf)); } gettimeofday(&end_tv, NULL); @@ -3155,7 +3182,8 @@ struct file_list *get_dirlist(char *dirname, int dlen, int ignore_filter_rules) recurse = 0; xfer_dirs = 1; - send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen, FLAG_CONTENT_DIR); + send_directory(ignore_filter_rules ? -2 : -1, dirlist, dirname, dlen, + FLAG_CONTENT_DIR, PHYS_DEPTH_N_A); xfer_dirs = save_xfer_dirs; recurse = save_recurse; if (INFO_GTE(PROGRESS, 1))