X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/10f994a52a9f087fc77aa1856580c4917b02006c..aac5cab80b9d4fc0adff2b72aeba2406176930ae:/receiver.c diff --git a/receiver.c b/receiver.c index 14353be6..7bf14c7d 100644 --- a/receiver.c +++ b/receiver.c @@ -1,50 +1,46 @@ -/* -*- c-file-style: "linux" -*- - - Copyright (C) 1996-2000 by Andrew Tridgell - Copyright (C) Paul Mackerras 1996 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ +/* + * Routines only used by the receiving process. + * + * Copyright (C) 1996-2000 Andrew Tridgell + * Copyright (C) 1996 Paul Mackerras + * Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ #include "rsync.h" extern int verbose; extern int do_xfers; -extern int am_daemon; extern int am_server; extern int do_progress; extern int log_before_transfer; -extern int log_format_has_i; -extern int daemon_log_format_has_i; +extern int stdout_format_has_i; +extern int logfile_format_has_i; extern int csum_length; extern int read_batch; extern int write_batch; extern int batch_gen_fd; extern int protocol_version; extern int relative_paths; -extern int keep_dirlinks; extern int preserve_hard_links; extern int preserve_perms; -extern int io_error; extern int basis_dir_cnt; extern int make_backups; extern int cleanup_got_literal; -extern int remove_sent_files; -extern int module_id; -extern int ignore_errors; -extern int orig_umask; +extern int remove_source_files; extern int append_mode; extern int sparse_files; extern int keep_partial; @@ -52,7 +48,7 @@ extern int checksum_seed; extern int inplace; extern int delay_updates; extern struct stats stats; -extern char *log_format; +extern char *stdout_format; extern char *tmpdir; extern char *partial_dir; extern char *basis_dir[]; @@ -61,6 +57,8 @@ extern struct filter_list_struct server_filter_list; static struct bitbag *delayed_bits = NULL; static int phase = 0; +/* We're either updating the basis file or an identical copy: */ +static int updating_basis; /* @@ -84,17 +82,15 @@ static int phase = 0; * As long as it's unique, rsync will work. */ -static int get_tmpname(char *fnametmp, char *fname) +int get_tmpname(char *fnametmp, char *fname) { + int maxname, added, length = 0; char *f; - int length = 0; - int maxname; if (tmpdir) { /* Note: this can't overflow, so the return value is safe */ length = strlcpy(fnametmp, tmpdir, MAXPATHLEN - 2); fnametmp[length++] = '/'; - fnametmp[length] = '\0'; /* always NULL terminated */ } if ((f = strrchr(fname, '/')) != NULL) { @@ -107,8 +103,9 @@ static int get_tmpname(char *fnametmp, char *fname) } else f = fname; fnametmp[length++] = '.'; - fnametmp[length] = '\0'; /* always NULL terminated */ + /* The maxname value is bufsize, and includes space for the '\0'. + * (Note that NAME_MAX get -8 for the leading '.' above.) */ maxname = MIN(MAXPATHLEN - 7 - length, NAME_MAX - 8); if (maxname < 1) { @@ -117,8 +114,10 @@ static int get_tmpname(char *fnametmp, char *fname) return 0; } - strlcpy(fnametmp + length, f, maxname); - strcat(fnametmp + length, ".XXXXXX"); + added = strlcpy(fnametmp + length, f, maxname); + if (added >= maxname) + added = maxname - 1; + memcpy(fnametmp + length + added, ".XXXXXX", 8); return 1; } @@ -165,15 +164,15 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, offset = j; } if (offset < sum.flength) { - int32 len = sum.flength - offset; + int32 len = (int32)(sum.flength - offset); if (do_progress) show_progress(offset, total_size); sum_update(map_ptr(mapbuf, offset, len), len); offset = sum.flength; } - if (fd != -1 && do_lseek(fd, offset, SEEK_SET) != offset) { - rsyserr(FERROR, errno, "lseek failed on %s", - full_fname(fname)); + if (fd != -1 && (j = do_lseek(fd, offset, SEEK_SET)) != offset) { + rsyserr(FERROR, errno, "lseek of %s returned %.0f, not %.0f", + full_fname(fname), (double)j, (double)offset); exit_cleanup(RERR_FILEIO); } } @@ -220,15 +219,17 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, sum_update(map, len); } - if (inplace) { + if (updating_basis) { if (offset == offset2 && fd != -1) { + OFF_T pos; if (flush_write_file(fd) < 0) goto report_write_error; offset += len; - if (do_lseek(fd, len, SEEK_CUR) != offset) { + if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset) { rsyserr(FERROR, errno, - "lseek failed on %s", - full_fname(fname)); + "lseek of %s returned %.0f, not %.0f", + full_fname(fname), + (double)pos, (double)offset); exit_cleanup(RERR_FILEIO); } continue; @@ -278,11 +279,11 @@ static void discard_receive_data(int f_in, OFF_T length) static void handle_delayed_updates(struct file_list *flist, char *local_name) { - char *fname, *partialptr, numbuf[4]; - int i; + char *fname, *partialptr; + int ndx; - for (i = -1; (i = bitbag_next_bit(delayed_bits, i)) >= 0; ) { - struct file_struct *file = flist->files[i]; + for (ndx = -1; (ndx = bitbag_next_bit(delayed_bits, ndx)) >= 0; ) { + struct file_struct *file = flist->files[ndx]; fname = local_name ? local_name : f_name(file, NULL); if ((partialptr = partial_dir_fname(fname)) != NULL) { if (make_backups && !make_backup(fname)) @@ -298,32 +299,29 @@ static void handle_delayed_updates(struct file_list *flist, char *local_name) "rename failed for %s (from %s)", full_fname(fname), partialptr); } else { - if (remove_sent_files - || (preserve_hard_links - && file->link_u.links)) { - SIVAL(numbuf, 0, i); - send_msg(MSG_SUCCESS,numbuf,4); - } + if (remove_source_files + || (preserve_hard_links && F_IS_HLINKED(file))) + send_msg_int(MSG_SUCCESS, ndx); handle_partial_dir(partialptr, PDIR_DELETE); } } } } -static int get_next_gen_i(int batch_gen_fd, int next_gen_i, int desired_i) +static int get_next_gen_ndx(int batch_gen_fd, int next_gen_ndx, int desired_ndx) { - while (next_gen_i < desired_i) { - if (next_gen_i >= 0) { + while (next_gen_ndx < desired_ndx) { + if (next_gen_ndx >= 0) { rprintf(FINFO, "(No batched update for%s \"%s\")\n", phase ? " resend of" : "", - f_name(the_file_list->files[next_gen_i], NULL)); + f_name(the_file_list->files[next_gen_ndx], NULL)); } - next_gen_i = read_int(batch_gen_fd); - if (next_gen_i == -1) - next_gen_i = the_file_list->count; + next_gen_ndx = read_int(batch_gen_fd); + if (next_gen_ndx == -1) + next_gen_ndx = the_file_list->count; } - return next_gen_i; + return next_gen_ndx; } @@ -333,44 +331,41 @@ static int get_next_gen_i(int batch_gen_fd, int next_gen_i, int desired_i) * Receiver process runs on the same host as the generator process. */ int recv_files(int f_in, struct file_list *flist, char *local_name) { - int next_gen_i = -1; + int next_gen_ndx = -1; int fd1,fd2; STRUCT_STAT st; int iflags, xlen; char *fname, fbuf[MAXPATHLEN]; char xname[MAXPATHLEN]; char fnametmp[MAXPATHLEN]; - char *fnamecmp, *partialptr, numbuf[4]; + char *fnamecmp, *partialptr; char fnamecmpbuf[MAXPATHLEN]; uchar fnamecmp_type; struct file_struct *file; struct stats initial_stats; int save_make_backups = make_backups; - int itemizing = am_daemon ? daemon_log_format_has_i - : !am_server && log_format_has_i; + int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i; + enum logcode log_code = log_before_transfer ? FLOG : FINFO; int max_phase = protocol_version >= 29 ? 2 : 1; - int i, recv_ok; + int ndx, recv_ok; if (verbose > 2) - rprintf(FINFO,"recv_files(%d) starting\n",flist->count); - - if (flist->hlink_pool) { - pool_destroy(flist->hlink_pool); - flist->hlink_pool = NULL; - } + rprintf(FINFO, "recv_files(%d) starting\n", flist->count); if (delay_updates) delayed_bits = bitbag_create(flist->count); + updating_basis = inplace; + while (1) { cleanup_disable(); - i = read_int(f_in); - if (i == -1) { + ndx = read_int(f_in); + if (ndx == NDX_DONE) { if (read_batch) { - get_next_gen_i(batch_gen_fd, next_gen_i, - flist->count); - next_gen_i = -1; + get_next_gen_ndx(batch_gen_fd, next_gen_ndx, + flist->count); + next_gen_ndx = -1; } if (++phase > max_phase) break; @@ -389,12 +384,12 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) continue; } - iflags = read_item_attrs(f_in, -1, i, &fnamecmp_type, + iflags = read_item_attrs(f_in, -1, ndx, &fnamecmp_type, xname, &xlen); if (iflags == ITEM_IS_NEW) /* no-op packet */ continue; - file = flist->files[i]; + file = flist->files[ndx]; fname = local_name ? local_name : f_name(file, fbuf); if (verbose > 2) @@ -411,9 +406,9 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) exit_cleanup(RERR_PROTOCOL); } - stats.current_file_index = i; + stats.current_file_index = ndx; stats.num_transferred_files++; - stats.total_transferred_size += file->length; + stats.total_transferred_size += F_LENGTH(file); cleanup_got_literal = 0; if (server_filter_list.head @@ -423,29 +418,28 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) } if (!do_xfers) { /* log the transfer */ - if (!am_server && log_format) - log_item(file, &stats, iflags, NULL); + log_item(FCLIENT, file, &stats, iflags, NULL); if (read_batch) - discard_receive_data(f_in, file->length); + discard_receive_data(f_in, F_LENGTH(file)); continue; } if (write_batch < 0) { - log_item(file, &stats, iflags, NULL); + log_item(FINFO, file, &stats, iflags, NULL); if (!am_server) - discard_receive_data(f_in, file->length); + discard_receive_data(f_in, F_LENGTH(file)); continue; } if (read_batch) { - next_gen_i = get_next_gen_i(batch_gen_fd, next_gen_i, i); - if (i < next_gen_i) { + next_gen_ndx = get_next_gen_ndx(batch_gen_fd, next_gen_ndx, ndx); + if (ndx < next_gen_ndx) { rprintf(FINFO, "(Skipping batched update for \"%s\")\n", fname); - discard_receive_data(f_in, file->length); + discard_receive_data(f_in, F_LENGTH(file)); continue; } - next_gen_i = -1; + next_gen_ndx = -1; } partialptr = partial_dir ? partial_dir_fname(fname) : fname; @@ -462,6 +456,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) fnamecmp = get_backup_name(fname); break; case FNAMECMP_FUZZY: + updating_basis = 0; if (file->dirname) { pathjoin(fnamecmpbuf, MAXPATHLEN, file->dirname, xname); @@ -470,6 +465,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) fnamecmp = xname; break; default: + updating_basis = 0; if (fnamecmp_type >= basis_dir_cnt) { rprintf(FERROR, "invalid basis_dir index: %d.\n", @@ -516,10 +512,13 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) } } - if (fd1 != -1 && do_fstat(fd1,&st) != 0) { + if (fd1 == -1) { + st.st_mode = 0; + st.st_size = 0; + } else if (do_fstat(fd1,&st) != 0) { rsyserr(FERROR, errno, "fstat %s failed", full_fname(fnamecmp)); - discard_receive_data(f_in, file->length); + discard_receive_data(f_in, F_LENGTH(file)); close(fd1); continue; } @@ -532,7 +531,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) */ rprintf(FERROR,"recv_files: %s is a directory\n", full_fname(fnamecmp)); - discard_receive_data(f_in, file->length); + discard_receive_data(f_in, F_LENGTH(file)); close(fd1); continue; } @@ -549,20 +548,20 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) file->mode = dest_mode(file->mode, st.st_mode, exists); } - /* We now check to see if we are writing file "inplace" */ + /* We now check to see if we are writing the file "inplace" */ if (inplace) { fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600); if (fd2 == -1) { rsyserr(FERROR, errno, "open %s failed", full_fname(fname)); - discard_receive_data(f_in, file->length); + discard_receive_data(f_in, F_LENGTH(file)); if (fd1 != -1) close(fd1); continue; } } else { if (!get_tmpname(fnametmp,fname)) { - discard_receive_data(f_in, file->length); + discard_receive_data(f_in, F_LENGTH(file)); if (fd1 != -1) close(fd1); continue; @@ -580,7 +579,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) * because their information should have been previously * transferred, but that may not be the case with -R */ if (fd2 == -1 && relative_paths && errno == ENOENT - && create_directory_path(fnametmp, orig_umask) == 0) { + && create_directory_path(fnametmp) == 0) { /* Get back to name with XXXXXX in it. */ get_tmpname(fnametmp, fname); fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS); @@ -588,28 +587,26 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) if (fd2 == -1) { rsyserr(FERROR, errno, "mkstemp %s failed", full_fname(fnametmp)); - discard_receive_data(f_in, file->length); + discard_receive_data(f_in, F_LENGTH(file)); if (fd1 != -1) close(fd1); continue; } - if (keep_partial) - cleanup_set(fnametmp, partialptr, file, fd1, fd2); + cleanup_set(fnametmp, partialptr, file, fd1, fd2); } /* log the transfer */ if (log_before_transfer) - log_item(file, &initial_stats, iflags, NULL); + log_item(FCLIENT, file, &initial_stats, iflags, NULL); else if (!am_server && verbose && do_progress) rprintf(FINFO, "%s\n", fname); /* recv file data */ recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size, - fname, fd2, file->length); + fname, fd2, F_LENGTH(file)); - if (!log_before_transfer) - log_item(file, &initial_stats, iflags, NULL); + log_item(log_code, file, &initial_stats, iflags, NULL); if (fd1 != -1) close(fd1); @@ -620,9 +617,14 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) } if ((recv_ok && (!delay_updates || !partialptr)) || inplace) { - if (partialptr == fname || *partial_dir == '/') - partialptr = NULL; - finish_transfer(fname, fnametmp, partialptr, + char *temp_copy_name; + if (partialptr == fname) + partialptr = temp_copy_name = NULL; + else if (*partial_dir == '/') + temp_copy_name = NULL; + else + temp_copy_name = partialptr; + finish_transfer(fname, fnametmp, temp_copy_name, file, recv_ok, 1); if (fnamecmp == partialptr) { do_unlink(partialptr); @@ -633,7 +635,7 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) finish_transfer(partialptr, fnametmp, NULL, file, recv_ok, !partial_dir); if (delay_updates && recv_ok) { - bitbag_set_bit(delayed_bits, i); + bitbag_set_bit(delayed_bits, ndx); recv_ok = -1; } } else { @@ -644,13 +646,11 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) cleanup_disable(); if (recv_ok > 0) { - if (remove_sent_files - || (preserve_hard_links && file->link_u.links)) { - SIVAL(numbuf, 0, i); - send_msg(MSG_SUCCESS, numbuf, 4); - } + if (remove_source_files + || (preserve_hard_links && F_IS_HLINKED(file))) + send_msg_int(MSG_SUCCESS, ndx); } else if (!recv_ok) { - int msgtype = phase || read_batch ? FERROR : FINFO; + enum logcode msgtype = phase || read_batch ? FERROR : FINFO; if (msgtype == FERROR || verbose) { char *errstr, *redostr, *keptstr; if (!(keep_partial && partialptr) && !inplace) @@ -670,10 +670,8 @@ int recv_files(int f_in, struct file_list *flist, char *local_name) "%s: %s failed verification -- update %s%s.\n", errstr, fname, keptstr, redostr); } - if (!phase) { - SIVAL(numbuf, 0, i); - send_msg(MSG_REDO, numbuf, 4); - } + if (!phase) + send_msg_int(MSG_REDO, ndx); } } make_backups = save_make_backups;