Annotation of embedaddon/rsync/sender.c, revision 1.1.1.4
1.1 misho 1: /*
2: * Routines only used by the sending process.
3: *
4: * Copyright (C) 1996 Andrew Tridgell
5: * Copyright (C) 1996 Paul Mackerras
1.1.1.4 ! misho 6: * Copyright (C) 2003-2020 Wayne Davison
1.1 misho 7: *
8: * This program is free software; you can redistribute it and/or modify
9: * it under the terms of the GNU General Public License as published by
10: * the Free Software Foundation; either version 3 of the License, or
11: * (at your option) any later version.
12: *
13: * This program is distributed in the hope that it will be useful,
14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: * GNU General Public License for more details.
17: *
18: * You should have received a copy of the GNU General Public License along
19: * with this program; if not, visit the http://fsf.org website.
20: */
21:
22: #include "rsync.h"
1.1.1.2 misho 23: #include "inums.h"
1.1.1.4 ! misho 24: #include "ifuncs.h"
1.1 misho 25:
26: extern int do_xfers;
27: extern int am_server;
28: extern int am_daemon;
29: extern int inc_recurse;
30: extern int log_before_transfer;
31: extern int stdout_format_has_i;
32: extern int logfile_format_has_i;
1.1.1.3 misho 33: extern int want_xattr_optim;
1.1 misho 34: extern int csum_length;
35: extern int append_mode;
1.1.1.4 ! misho 36: extern int copy_links;
1.1 misho 37: extern int io_error;
1.1.1.2 misho 38: extern int flist_eof;
1.1 misho 39: extern int allowed_lull;
40: extern int preserve_xattrs;
41: extern int protocol_version;
42: extern int remove_source_files;
43: extern int updating_basis_file;
44: extern int make_backups;
1.1.1.4 ! misho 45: extern int make_source_backups;
1.1 misho 46: extern int inplace;
1.1.1.4 ! misho 47: extern int inplace_partial;
1.1 misho 48: extern int batch_fd;
49: extern int write_batch;
1.1.1.2 misho 50: extern int file_old_total;
1.1.1.4 ! misho 51: extern BOOL want_progress_now;
! 52: extern char *source_filter;
1.1 misho 53: extern struct stats stats;
54: extern struct file_list *cur_flist, *first_flist, *dir_flist;
55:
1.1.1.2 misho 56: BOOL extra_flist_sending_enabled;
57:
1.1 misho 58: /**
59: * @file
60: *
61: * The sender gets checksums from the generator, calculates deltas,
62: * and transmits them to the receiver. The sender process runs on the
63: * machine holding the source files.
64: **/
65:
66: /**
67: * Receive the checksums for a buffer
68: **/
69: static struct sum_struct *receive_sums(int f)
70: {
1.1.1.4 ! misho 71: struct sum_struct *s = new(struct sum_struct);
1.1.1.2 misho 72: int lull_mod = protocol_version >= 31 ? 0 : allowed_lull * 5;
1.1 misho 73: OFF_T offset = 0;
1.1.1.4 ! misho 74: int32 i;
1.1 misho 75:
76: read_sum_head(f, s);
77:
78: s->sums = NULL;
79:
1.1.1.2 misho 80: if (DEBUG_GTE(DELTASUM, 3)) {
81: rprintf(FINFO, "count=%s n=%ld rem=%ld\n",
82: big_num(s->count), (long)s->blength, (long)s->remainder);
1.1 misho 83: }
84:
85: if (append_mode > 0) {
86: s->flength = (OFF_T)s->count * s->blength;
87: if (s->remainder)
88: s->flength -= s->blength - s->remainder;
89: return s;
90: }
91:
92: if (s->count == 0)
93: return(s);
94:
1.1.1.4 ! misho 95: s->sums = new_array(struct sum_buf, s->count);
1.1 misho 96:
97: for (i = 0; i < s->count; i++) {
98: s->sums[i].sum1 = read_int(f);
99: read_buf(f, s->sums[i].sum2, s->s2length);
100:
101: s->sums[i].offset = offset;
102: s->sums[i].flags = 0;
103:
104: if (i == s->count-1 && s->remainder != 0)
105: s->sums[i].len = s->remainder;
106: else
107: s->sums[i].len = s->blength;
108: offset += s->sums[i].len;
109:
1.1.1.2 misho 110: if (lull_mod && !(i % lull_mod))
111: maybe_send_keepalive(time(NULL), True);
1.1 misho 112:
1.1.1.2 misho 113: if (DEBUG_GTE(DELTASUM, 3)) {
1.1 misho 114: rprintf(FINFO,
1.1.1.2 misho 115: "chunk[%d] len=%d offset=%s sum1=%08x\n",
116: i, s->sums[i].len, big_num(s->sums[i].offset),
1.1 misho 117: s->sums[i].sum1);
118: }
119: }
120:
121: s->flength = offset;
122:
123: return s;
124: }
125:
126: void successful_send(int ndx)
127: {
128: char fname[MAXPATHLEN];
1.1.1.2 misho 129: char *failed_op;
1.1 misho 130: struct file_struct *file;
131: struct file_list *flist;
1.1.1.2 misho 132: STRUCT_STAT st;
1.1.1.4 ! misho 133: int result;
1.1 misho 134:
135: if (!remove_source_files)
136: return;
137:
138: flist = flist_for_ndx(ndx, "successful_send");
139: file = flist->files[ndx - flist->ndx_start];
140: if (!change_pathname(file, NULL, 0))
141: return;
142: f_name(file, fname);
143:
1.1.1.4 ! misho 144: if ((copy_links ? do_stat(fname, &st) : do_lstat(fname, &st)) < 0) {
1.1.1.2 misho 145: failed_op = "re-lstat";
146: goto failed;
147: }
148:
1.1.1.4 ! misho 149: if (st.st_size != F_LENGTH(file) || st.st_mtime != file->modtime
1.1.1.2 misho 150: #ifdef ST_MTIME_NSEC
151: || (NSEC_BUMP(file) && (uint32)st.ST_MTIME_NSEC != F_MOD_NSEC(file))
152: #endif
1.1.1.4 ! misho 153: ) {
1.1.1.3 misho 154: rprintf(FERROR_XFER, "ERROR: Skipping sender remove for changed file: %s\n", fname);
1.1.1.2 misho 155: return;
156: }
157:
1.1.1.4 ! misho 158: if (make_source_backups)
! 159: result = !make_backup(fname, True);
! 160: else
! 161: result = do_unlink(fname);
! 162: if (result < 0) {
1.1.1.2 misho 163: failed_op = "remove";
164: failed:
165: if (errno == ENOENT)
166: rprintf(FINFO, "sender file already removed: %s\n", fname);
167: else
1.1.1.3 misho 168: rsyserr(FERROR_XFER, errno, "sender failed to %s %s", failed_op, fname);
1.1.1.2 misho 169: } else {
170: if (INFO_GTE(REMOVE, 1))
1.1 misho 171: rprintf(FINFO, "sender removed %s\n", fname);
1.1.1.2 misho 172: }
1.1 misho 173: }
174:
175: static void write_ndx_and_attrs(int f_out, int ndx, int iflags,
176: const char *fname, struct file_struct *file,
177: uchar fnamecmp_type, char *buf, int len)
178: {
179: write_ndx(f_out, ndx);
180: if (protocol_version < 29)
181: return;
182: write_shortint(f_out, iflags);
183: if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
184: write_byte(f_out, fnamecmp_type);
185: if (iflags & ITEM_XNAME_FOLLOWS)
186: write_vstring(f_out, buf, len);
187: #ifdef SUPPORT_XATTRS
1.1.1.2 misho 188: if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
1.1.1.3 misho 189: && !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)))
1.1 misho 190: send_xattr_request(fname, file, f_out);
191: #endif
192: }
193:
194: void send_files(int f_in, int f_out)
195: {
196: int fd = -1;
197: struct sum_struct *s;
198: struct map_struct *mbuf = NULL;
199: STRUCT_STAT st;
200: char fname[MAXPATHLEN], xname[MAXPATHLEN];
201: const char *path, *slash;
202: uchar fnamecmp_type;
203: int iflags, xlen;
204: struct file_struct *file;
205: int phase = 0, max_phase = protocol_version >= 29 ? 2 : 1;
206: int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
207: enum logcode log_code = log_before_transfer ? FLOG : FINFO;
208: int f_xfer = write_batch < 0 ? batch_fd : f_out;
209: int save_io_error = io_error;
210: int ndx, j;
1.1.1.4 ! misho 211: char *filter_argv[MAX_FILTER_ARGS + 1];
! 212: char *tmp = 0;
! 213: int unlink_tmp = 0;
! 214:
! 215: if (source_filter) {
! 216: char *p;
! 217: char *sep = " \t";
! 218: int i;
! 219: for (p = strtok(source_filter, sep), i = 0;
! 220: p && i < MAX_FILTER_ARGS;
! 221: p = strtok(0, sep))
! 222: filter_argv[i++] = p;
! 223: filter_argv[i] = NULL;
! 224: if (p) {
! 225: rprintf(FERROR,
! 226: "Too many arguments to source-filter (> %d)\n",
! 227: MAX_FILTER_ARGS);
! 228: exit_cleanup(RERR_SYNTAX);
! 229: }
! 230: }
1.1 misho 231:
1.1.1.2 misho 232: if (DEBUG_GTE(SEND, 1))
1.1 misho 233: rprintf(FINFO, "send_files starting\n");
234:
1.1.1.4 ! misho 235: progress_init();
! 236:
1.1 misho 237: while (1) {
1.1.1.2 misho 238: if (inc_recurse) {
239: send_extra_file_list(f_out, MIN_FILECNT_LOOKAHEAD);
240: extra_flist_sending_enabled = !flist_eof;
241: }
1.1 misho 242:
243: /* This call also sets cur_flist. */
1.1.1.2 misho 244: ndx = read_ndx_and_attrs(f_in, f_out, &iflags, &fnamecmp_type,
1.1 misho 245: xname, &xlen);
1.1.1.2 misho 246: extra_flist_sending_enabled = False;
247:
1.1 misho 248: if (ndx == NDX_DONE) {
1.1.1.4 ! misho 249: if (!am_server && cur_flist) {
1.1.1.2 misho 250: set_current_file_index(NULL, 0);
1.1.1.4 ! misho 251: if (INFO_GTE(PROGRESS, 2))
! 252: end_progress(0);
1.1.1.2 misho 253: }
1.1 misho 254: if (inc_recurse && first_flist) {
1.1.1.2 misho 255: file_old_total -= first_flist->used;
1.1 misho 256: flist_free(first_flist);
257: if (first_flist) {
1.1.1.2 misho 258: if (first_flist == cur_flist)
259: file_old_total = cur_flist->used;
1.1 misho 260: write_ndx(f_out, NDX_DONE);
261: continue;
262: }
263: }
264: if (++phase > max_phase)
265: break;
1.1.1.2 misho 266: if (DEBUG_GTE(SEND, 1))
1.1 misho 267: rprintf(FINFO, "send_files phase=%d\n", phase);
268: write_ndx(f_out, NDX_DONE);
269: continue;
270: }
271:
272: if (inc_recurse)
1.1.1.2 misho 273: send_extra_file_list(f_out, MIN_FILECNT_LOOKAHEAD);
1.1 misho 274:
275: if (ndx - cur_flist->ndx_start >= 0)
276: file = cur_flist->files[ndx - cur_flist->ndx_start];
277: else
278: file = dir_flist->files[cur_flist->parent_ndx];
279: if (F_PATHNAME(file)) {
280: path = F_PATHNAME(file);
281: slash = "/";
282: } else {
283: path = slash = "";
284: }
285: if (!change_pathname(file, NULL, 0))
286: continue;
287: f_name(file, fname);
288:
1.1.1.2 misho 289: if (DEBUG_GTE(SEND, 1))
1.1 misho 290: rprintf(FINFO, "send_files(%d, %s%s%s)\n", ndx, path,slash,fname);
291:
292: #ifdef SUPPORT_XATTRS
1.1.1.2 misho 293: if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
1.1.1.3 misho 294: && !(want_xattr_optim && BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE)))
1.1 misho 295: recv_xattr_request(file, f_in);
296: #endif
297:
298: if (!(iflags & ITEM_TRANSFER)) {
299: maybe_log_item(file, iflags, itemizing, xname);
1.1.1.4 ! misho 300: write_ndx_and_attrs(f_out, ndx, iflags, fname, file, fnamecmp_type, xname, xlen);
1.1.1.2 misho 301: if (iflags & ITEM_IS_NEW) {
302: stats.created_files++;
303: if (S_ISREG(file->mode)) {
304: /* Nothing further to count. */
305: } else if (S_ISDIR(file->mode))
306: stats.created_dirs++;
307: #ifdef SUPPORT_LINKS
308: else if (S_ISLNK(file->mode))
309: stats.created_symlinks++;
310: #endif
311: else if (IS_DEVICE(file->mode))
312: stats.created_devices++;
313: else
314: stats.created_specials++;
315: }
1.1 misho 316: continue;
317: }
318: if (phase == 2) {
319: rprintf(FERROR,
320: "got transfer request in phase 2 [%s]\n",
321: who_am_i());
322: exit_cleanup(RERR_PROTOCOL);
323: }
324:
325: if (file->flags & FLAG_FILE_SENT) {
326: if (csum_length == SHORT_SUM_LENGTH) {
327: /* For inplace: redo phase turns off the backup
328: * flag so that we do a regular inplace send. */
329: make_backups = -make_backups;
330: append_mode = -append_mode;
331: csum_length = SUM_LENGTH;
332: }
333: } else {
334: if (csum_length != SHORT_SUM_LENGTH) {
335: make_backups = -make_backups;
336: append_mode = -append_mode;
337: csum_length = SHORT_SUM_LENGTH;
338: }
1.1.1.2 misho 339: if (iflags & ITEM_IS_NEW)
340: stats.created_files++;
1.1 misho 341: }
342:
1.1.1.4 ! misho 343: updating_basis_file = (inplace_partial && fnamecmp_type == FNAMECMP_PARTIAL_DIR)
! 344: || (inplace && (protocol_version >= 29 ? fnamecmp_type == FNAMECMP_FNAME : make_backups <= 0));
1.1 misho 345:
1.1.1.4 ! misho 346: if (!am_server)
1.1 misho 347: set_current_file_index(file, ndx);
1.1.1.2 misho 348: stats.xferred_files++;
1.1 misho 349: stats.total_transferred_size += F_LENGTH(file);
350:
1.1.1.3 misho 351: remember_initial_stats();
1.1.1.2 misho 352:
1.1 misho 353: if (!do_xfers) { /* log the transfer */
1.1.1.2 misho 354: log_item(FCLIENT, file, iflags, NULL);
1.1.1.4 ! misho 355: write_ndx_and_attrs(f_out, ndx, iflags, fname, file, fnamecmp_type, xname, xlen);
1.1 misho 356: continue;
357: }
358:
359: if (!(s = receive_sums(f_in))) {
360: io_error |= IOERR_GENERAL;
361: rprintf(FERROR_XFER, "receive_sums failed\n");
362: exit_cleanup(RERR_PROTOCOL);
363: }
364:
1.1.1.4 ! misho 365: unlink_tmp = 0;
1.1 misho 366: fd = do_open(fname, O_RDONLY, 0);
367: if (fd == -1) {
368: if (errno == ENOENT) {
1.1.1.4 ! misho 369: enum logcode c = am_daemon && protocol_version < 28 ? FERROR : FWARNING;
1.1 misho 370: io_error |= IOERR_VANISHED;
371: rprintf(c, "file has vanished: %s\n",
372: full_fname(fname));
373: } else {
374: io_error |= IOERR_GENERAL;
375: rsyserr(FERROR_XFER, errno,
376: "send_files failed to open %s",
377: full_fname(fname));
378: }
379: free_sums(s);
380: if (protocol_version >= 30)
381: send_msg_int(MSG_NO_SEND, ndx);
382: continue;
383: }
384:
1.1.1.4 ! misho 385: if (source_filter) {
! 386: int fd2;
! 387: char *tmpl = "/tmp/rsync-filtered_sourceXXXXXX";
! 388:
! 389: tmp = strdup(tmpl);
! 390: fd2 = mkstemp(tmp);
! 391: if (fd2 == -1) {
! 392: rprintf(FERROR, "mkstemp %s failed: %s\n",
! 393: tmp, strerror(errno));
! 394: } else {
! 395: int status;
! 396: pid_t pid = run_filter_on_file(filter_argv, fd2, fd);
! 397: close(fd);
! 398: close(fd2);
! 399: wait_process_with_flush(pid, &status);
! 400: if (status != 0) {
! 401: rprintf(FERROR,
! 402: "bypassing source filter %s; exited with code: %d\n",
! 403: source_filter, status);
! 404: fd = do_open(fname, O_RDONLY, 0);
! 405: } else {
! 406: fd = do_open(tmp, O_RDONLY, 0);
! 407: unlink_tmp = 1;
! 408: }
! 409: }
! 410: }
! 411:
1.1 misho 412: /* map the local file */
413: if (do_fstat(fd, &st) != 0) {
414: io_error |= IOERR_GENERAL;
415: rsyserr(FERROR_XFER, errno, "fstat failed");
416: free_sums(s);
417: close(fd);
1.1.1.2 misho 418: exit_cleanup(RERR_FILEIO);
1.1 misho 419: }
420:
1.1.1.4 ! misho 421: if (IS_DEVICE(st.st_mode) && st.st_size == 0)
! 422: st.st_size = get_device_size(fd, fname);
! 423:
1.1 misho 424: if (st.st_size) {
425: int32 read_size = MAX(s->blength * 3, MAX_MAP_SIZE);
426: mbuf = map_file(fd, st.st_size, read_size, s->blength);
427: } else
428: mbuf = NULL;
429:
1.1.1.2 misho 430: if (DEBUG_GTE(DELTASUM, 2)) {
431: rprintf(FINFO, "send_files mapped %s%s%s of size %s\n",
432: path,slash,fname, big_num(st.st_size));
1.1 misho 433: }
434:
1.1.1.4 ! misho 435: write_ndx_and_attrs(f_out, ndx, iflags, fname, file, fnamecmp_type, xname, xlen);
1.1 misho 436: write_sum_head(f_xfer, s);
437:
1.1.1.2 misho 438: if (DEBUG_GTE(DELTASUM, 2))
1.1 misho 439: rprintf(FINFO, "calling match_sums %s%s%s\n", path,slash,fname);
440:
441: if (log_before_transfer)
1.1.1.2 misho 442: log_item(FCLIENT, file, iflags, NULL);
443: else if (!am_server && INFO_GTE(NAME, 1) && INFO_EQ(PROGRESS, 1))
1.1 misho 444: rprintf(FCLIENT, "%s\n", fname);
445:
446: set_compression(fname);
447:
448: match_sums(f_xfer, s, mbuf, st.st_size);
1.1.1.2 misho 449: if (INFO_GTE(PROGRESS, 1))
1.1 misho 450: end_progress(st.st_size);
1.1.1.4 ! misho 451: else if (want_progress_now)
! 452: instant_progress(fname);
1.1 misho 453:
1.1.1.2 misho 454: log_item(log_code, file, iflags, NULL);
1.1 misho 455:
456: if (mbuf) {
457: j = unmap_file(mbuf);
458: if (j) {
459: io_error |= IOERR_GENERAL;
460: rsyserr(FERROR_XFER, j,
461: "read errors mapping %s",
462: full_fname(fname));
463: }
464: }
465: close(fd);
1.1.1.4 ! misho 466: if (unlink_tmp)
! 467: unlink(tmp);
1.1 misho 468:
469: free_sums(s);
470:
1.1.1.2 misho 471: if (DEBUG_GTE(SEND, 1))
1.1 misho 472: rprintf(FINFO, "sender finished %s%s%s\n", path,slash,fname);
473:
474: /* Flag that we actually sent this entry. */
475: file->flags |= FLAG_FILE_SENT;
476: }
477: if (make_backups < 0)
478: make_backups = -make_backups;
479:
480: if (io_error != save_io_error && protocol_version >= 30)
481: send_msg_int(MSG_IO_ERROR, io_error);
482:
1.1.1.2 misho 483: if (DEBUG_GTE(SEND, 1))
1.1 misho 484: rprintf(FINFO, "send files finished\n");
485:
486: match_report();
487:
488: write_ndx(f_out, NDX_DONE);
489: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>