X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/b9f592fbf50b0dc9e3d1d33b8deb2bf9abad9ef6..4ce838e1f107239f1b18f3f8cd7c7fbab65e0bd5:/flist.c diff --git a/flist.c b/flist.c index ebb70e49..1b021ef6 100644 --- a/flist.c +++ b/flist.c @@ -34,6 +34,7 @@ extern int do_progress; extern int am_root; extern int am_server; extern int am_daemon; +extern int am_sender; extern int always_checksum; extern int module_id; extern int ignore_errors; @@ -72,6 +73,7 @@ int io_error; static char empty_sum[MD4_SUM_LENGTH]; static unsigned int file_struct_len; +static struct file_list *received_flist; static void clean_flist(struct file_list *flist, int strip_root, int no_dups); static void output_flist(struct file_list *flist); @@ -170,12 +172,12 @@ static void list_file_entry(struct file_struct *f) * @post @p buffer contains information about the link or the * referrent as appropriate, if they exist. **/ -int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf) +static int readlink_stat(const char *path, STRUCT_STAT *buffer, char *linkbuf) { #if SUPPORT_LINKS if (copy_links) return do_stat(path, buffer); - if (link_stat(path, buffer, keep_dirlinks) < 0) + if (link_stat(path, buffer, 0) < 0) return -1; if (S_ISLNK(buffer->st_mode)) { int l = readlink((char *)path, linkbuf, MAXPATHLEN - 1); @@ -531,7 +533,7 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags, static uid_t uid; static gid_t gid; static char lastname[MAXPATHLEN], *lastdir; - static int lastdir_len = -1; + static int lastdir_depth, lastdir_len = -1; char thisname[MAXPATHLEN]; unsigned int l1 = 0, l2 = 0; int alloc_len, basename_len, dirname_len, linkname_len, sum_len; @@ -570,10 +572,10 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags, strlcpy(lastname, thisname, MAXPATHLEN); - clean_fname(thisname); + clean_fname(thisname, 0); if (sanitize_paths) - sanitize_path(thisname, NULL); + sanitize_path(thisname, thisname, "", 0); if ((basename = strrchr(thisname, '/')) != NULL) { dirname_len = ++basename - thisname; /* counts future '\0' */ @@ -656,6 +658,8 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags, memcpy(bp, dirname, dirname_len - 1); bp += dirname_len; bp[-1] = '\0'; + if (sanitize_paths) + lastdir_depth = count_dir_elements(lastdir); } else if (dirname) file->dirname = dirname; @@ -671,7 +675,7 @@ void receive_file_entry(struct file_struct **fptr, unsigned short flags, file->u.link = bp; read_sbuf(f, bp, linkname_len - 1); if (sanitize_paths) - sanitize_path(bp, lastdir); + sanitize_path(bp, bp, "", lastdir_depth); bp += linkname_len; } #endif @@ -759,9 +763,9 @@ struct file_struct *make_file(char *fname, struct file_list *flist, rprintf(FINFO, "skipping overly long name: %s\n", fname); return NULL; } - clean_fname(thisname); + clean_fname(thisname, 0); if (sanitize_paths) - sanitize_path(thisname, NULL); + sanitize_path(thisname, thisname, "", 0); memset(sum, 0, SUM_LENGTH); @@ -815,8 +819,13 @@ struct file_struct *make_file(char *fname, struct file_list *flist, if (check_exclude_file(thisname, S_ISDIR(st.st_mode) != 0, exclude_level)) return NULL; - if (lp_ignore_nonreadable(module_id) && access(thisname, R_OK) != 0) - return NULL; + if (lp_ignore_nonreadable(module_id)) { +#if SUPPORT_LINKS + if (!S_ISLNK(st.st_mode)) +#endif + if (access(thisname, R_OK) != 0) + return NULL; + } skip_excludes: @@ -923,6 +932,26 @@ skip_excludes: file->basedir = flist_dir; + /* This code is only used by the receiver when it is building + * a list of files for a delete pass. */ + if (keep_dirlinks && linkname_len && flist) { + STRUCT_STAT st2; + int i = flist_find(received_flist, file); + if (i >= 0 && S_ISDIR(received_flist->files[i]->mode) + && do_stat(thisname, &st2) == 0 && S_ISDIR(st2.st_mode)) { + file->modtime = st2.st_mtime; + file->length = st2.st_size; + file->mode = st2.st_mode; + file->uid = st2.st_uid; + file->gid = st2.st_gid; + file->u.link = NULL; + if (file->link_u.idev) { + pool_free(flist->hlink_pool, 0, file->link_u.idev); + file->link_u.idev = NULL; + } + } + } + if (!S_ISDIR(st.st_mode)) stats.total_size += st.st_size; @@ -1059,7 +1088,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) "send_file_list"); if (f != -1) { - io_start_buffering_out(f); + io_start_buffering_out(); if (filesfrom_fd >= 0) { if (argv[0] && !push_dir(argv[0])) { rsyserr(FERROR, errno, "push_dir %s failed", @@ -1077,13 +1106,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (use_ff_fd) { if (read_filesfrom_line(filesfrom_fd, fname) == 0) break; - sanitize_path(fname, NULL); + sanitize_path(fname, fname, "", 0); } else { if (argc-- == 0) break; strlcpy(fname, *argv++, MAXPATHLEN); if (sanitize_paths) - sanitize_path(fname, NULL); + sanitize_path(fname, fname, "", 0); } l = strlen(fname); @@ -1249,6 +1278,7 @@ struct file_list *recv_file_list(int f) start_read = stats.total_read; flist = flist_new(WITH_HLINK, "recv_file_list"); + received_flist = flist; flist->count = 0; flist->malloced = 1000; @@ -1485,7 +1515,7 @@ static void output_flist(struct file_list *flist) for (i = 0; i < flist->count; i++) { file = flist->files[i]; - if (am_root && preserve_uid) + if ((am_root || am_sender) && preserve_uid) sprintf(uidbuf, " uid=%ld", (long)file->uid); else *uidbuf = '\0';