Annotation of embedaddon/rsync/receiver.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Routines only used by the receiving process.
! 3: *
! 4: * Copyright (C) 1996-2000 Andrew Tridgell
! 5: * Copyright (C) 1996 Paul Mackerras
! 6: * Copyright (C) 2003-2009 Wayne Davison
! 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"
! 23:
! 24: extern int verbose;
! 25: extern int dry_run;
! 26: extern int do_xfers;
! 27: extern int am_root;
! 28: extern int am_server;
! 29: extern int do_progress;
! 30: extern int inc_recurse;
! 31: extern int log_before_transfer;
! 32: extern int stdout_format_has_i;
! 33: extern int logfile_format_has_i;
! 34: extern int csum_length;
! 35: extern int read_batch;
! 36: extern int write_batch;
! 37: extern int batch_gen_fd;
! 38: extern int protocol_version;
! 39: extern int relative_paths;
! 40: extern int preserve_hard_links;
! 41: extern int preserve_perms;
! 42: extern int preserve_xattrs;
! 43: extern int basis_dir_cnt;
! 44: extern int make_backups;
! 45: extern int cleanup_got_literal;
! 46: extern int remove_source_files;
! 47: extern int append_mode;
! 48: extern int sparse_files;
! 49: extern int keep_partial;
! 50: extern int checksum_seed;
! 51: extern int inplace;
! 52: extern int delay_updates;
! 53: extern mode_t orig_umask;
! 54: extern struct stats stats;
! 55: extern char *tmpdir;
! 56: extern char *partial_dir;
! 57: extern char *basis_dir[MAX_BASIS_DIRS+1];
! 58: extern struct file_list *cur_flist, *first_flist, *dir_flist;
! 59: extern struct filter_list_struct daemon_filter_list;
! 60:
! 61: static struct bitbag *delayed_bits = NULL;
! 62: static int phase = 0, redoing = 0;
! 63: static flist_ndx_list batch_redo_list;
! 64: /* We're either updating the basis file or an identical copy: */
! 65: static int updating_basis_or_equiv;
! 66:
! 67: #define TMPNAME_SUFFIX ".XXXXXX"
! 68: #define TMPNAME_SUFFIX_LEN ((int)sizeof TMPNAME_SUFFIX - 1)
! 69:
! 70: /* get_tmpname() - create a tmp filename for a given filename
! 71: *
! 72: * If a tmpdir is defined, use that as the directory to put it in. Otherwise,
! 73: * the tmp filename is in the same directory as the given name. Note that
! 74: * there may be no directory at all in the given name!
! 75: *
! 76: * The tmp filename is basically the given filename with a dot prepended, and
! 77: * .XXXXXX appended (for mkstemp() to put its unique gunk in). We take care
! 78: * to not exceed either the MAXPATHLEN or NAME_MAX, especially the last, as
! 79: * the basename basically becomes 8 characters longer. In such a case, the
! 80: * original name is shortened sufficiently to make it all fit.
! 81: *
! 82: * Of course, the only reason the file is based on the original name is to
! 83: * make it easier to figure out what purpose a temp file is serving when a
! 84: * transfer is in progress. */
! 85: int get_tmpname(char *fnametmp, const char *fname)
! 86: {
! 87: int maxname, added, length = 0;
! 88: const char *f;
! 89: char *suf;
! 90:
! 91: if (tmpdir) {
! 92: /* Note: this can't overflow, so the return value is safe */
! 93: length = strlcpy(fnametmp, tmpdir, MAXPATHLEN - 2);
! 94: fnametmp[length++] = '/';
! 95: }
! 96:
! 97: if ((f = strrchr(fname, '/')) != NULL) {
! 98: ++f;
! 99: if (!tmpdir) {
! 100: length = f - fname;
! 101: /* copy up to and including the slash */
! 102: strlcpy(fnametmp, fname, length + 1);
! 103: }
! 104: } else
! 105: f = fname;
! 106: fnametmp[length++] = '.';
! 107:
! 108: /* The maxname value is bufsize, and includes space for the '\0'.
! 109: * NAME_MAX needs an extra -1 for the name's leading dot. */
! 110: maxname = MIN(MAXPATHLEN - length - TMPNAME_SUFFIX_LEN,
! 111: NAME_MAX - 1 - TMPNAME_SUFFIX_LEN);
! 112:
! 113: if (maxname < 1) {
! 114: rprintf(FERROR_XFER, "temporary filename too long: %s\n", fname);
! 115: fnametmp[0] = '\0';
! 116: return 0;
! 117: }
! 118:
! 119: added = strlcpy(fnametmp + length, f, maxname);
! 120: if (added >= maxname)
! 121: added = maxname - 1;
! 122: suf = fnametmp + length + added;
! 123:
! 124: /* Trim any dangling high-bit chars if the first-trimmed char (if any) is
! 125: * also a high-bit char, just in case we cut into a multi-byte sequence.
! 126: * We are guaranteed to stop because of the leading '.' we added. */
! 127: if ((int)f[added] & 0x80) {
! 128: while ((int)suf[-1] & 0x80)
! 129: suf--;
! 130: }
! 131:
! 132: memcpy(suf, TMPNAME_SUFFIX, TMPNAME_SUFFIX_LEN+1);
! 133:
! 134: return 1;
! 135: }
! 136:
! 137: /* Opens a temporary file for writing.
! 138: * Success: Writes name into fnametmp, returns fd.
! 139: * Failure: Clobbers fnametmp, returns -1.
! 140: * Calling cleanup_set() is the caller's job. */
! 141: int open_tmpfile(char *fnametmp, const char *fname, struct file_struct *file)
! 142: {
! 143: int fd;
! 144: mode_t added_perms;
! 145:
! 146: if (!get_tmpname(fnametmp, fname))
! 147: return -1;
! 148:
! 149: if (am_root < 0) {
! 150: /* For --fake-super, the file must be useable by the copying
! 151: * user, just like it would be for root. */
! 152: added_perms = S_IRUSR|S_IWUSR;
! 153: } else {
! 154: /* For a normal copy, we need to be able to tweak things like xattrs. */
! 155: added_perms = S_IWUSR;
! 156: }
! 157:
! 158: /* We initially set the perms without the setuid/setgid bits or group
! 159: * access to ensure that there is no race condition. They will be
! 160: * correctly updated after the right owner and group info is set.
! 161: * (Thanks to snabb@epipe.fi for pointing this out.) */
! 162: fd = do_mkstemp(fnametmp, (file->mode|added_perms) & INITACCESSPERMS);
! 163:
! 164: #if 0
! 165: /* In most cases parent directories will already exist because their
! 166: * information should have been previously transferred, but that may
! 167: * not be the case with -R */
! 168: if (fd == -1 && relative_paths && errno == ENOENT
! 169: && create_directory_path(fnametmp) == 0) {
! 170: /* Get back to name with XXXXXX in it. */
! 171: get_tmpname(fnametmp, fname);
! 172: fd = do_mkstemp(fnametmp, (file->mode|added_perms) & INITACCESSPERMS);
! 173: }
! 174: #endif
! 175:
! 176: if (fd == -1) {
! 177: rsyserr(FERROR_XFER, errno, "mkstemp %s failed",
! 178: full_fname(fnametmp));
! 179: return -1;
! 180: }
! 181:
! 182: return fd;
! 183: }
! 184:
! 185: static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
! 186: const char *fname, int fd, OFF_T total_size)
! 187: {
! 188: static char file_sum1[MAX_DIGEST_LEN];
! 189: static char file_sum2[MAX_DIGEST_LEN];
! 190: struct map_struct *mapbuf;
! 191: struct sum_struct sum;
! 192: int32 len, sum_len;
! 193: OFF_T offset = 0;
! 194: OFF_T offset2;
! 195: char *data;
! 196: int32 i;
! 197: char *map = NULL;
! 198:
! 199: read_sum_head(f_in, &sum);
! 200:
! 201: if (fd_r >= 0 && size_r > 0) {
! 202: int32 read_size = MAX(sum.blength * 2, 16*1024);
! 203: mapbuf = map_file(fd_r, size_r, read_size, sum.blength);
! 204: if (verbose > 2) {
! 205: rprintf(FINFO, "recv mapped %s of size %.0f\n",
! 206: fname_r, (double)size_r);
! 207: }
! 208: } else
! 209: mapbuf = NULL;
! 210:
! 211: sum_init(checksum_seed);
! 212:
! 213: if (append_mode > 0) {
! 214: OFF_T j;
! 215: sum.flength = (OFF_T)sum.count * sum.blength;
! 216: if (sum.remainder)
! 217: sum.flength -= sum.blength - sum.remainder;
! 218: if (append_mode == 2) {
! 219: for (j = CHUNK_SIZE; j < sum.flength; j += CHUNK_SIZE) {
! 220: if (do_progress)
! 221: show_progress(offset, total_size);
! 222: sum_update(map_ptr(mapbuf, offset, CHUNK_SIZE),
! 223: CHUNK_SIZE);
! 224: offset = j;
! 225: }
! 226: if (offset < sum.flength) {
! 227: int32 len = (int32)(sum.flength - offset);
! 228: if (do_progress)
! 229: show_progress(offset, total_size);
! 230: sum_update(map_ptr(mapbuf, offset, len), len);
! 231: }
! 232: }
! 233: offset = sum.flength;
! 234: if (fd != -1 && (j = do_lseek(fd, offset, SEEK_SET)) != offset) {
! 235: rsyserr(FERROR_XFER, errno, "lseek of %s returned %.0f, not %.0f",
! 236: full_fname(fname), (double)j, (double)offset);
! 237: exit_cleanup(RERR_FILEIO);
! 238: }
! 239: }
! 240:
! 241: while ((i = recv_token(f_in, &data)) != 0) {
! 242: if (do_progress)
! 243: show_progress(offset, total_size);
! 244:
! 245: if (i > 0) {
! 246: if (verbose > 3) {
! 247: rprintf(FINFO,"data recv %d at %.0f\n",
! 248: i,(double)offset);
! 249: }
! 250:
! 251: stats.literal_data += i;
! 252: cleanup_got_literal = 1;
! 253:
! 254: sum_update(data, i);
! 255:
! 256: if (fd != -1 && write_file(fd,data,i) != i)
! 257: goto report_write_error;
! 258: offset += i;
! 259: continue;
! 260: }
! 261:
! 262: i = -(i+1);
! 263: offset2 = i * (OFF_T)sum.blength;
! 264: len = sum.blength;
! 265: if (i == (int)sum.count-1 && sum.remainder != 0)
! 266: len = sum.remainder;
! 267:
! 268: stats.matched_data += len;
! 269:
! 270: if (verbose > 3) {
! 271: rprintf(FINFO,
! 272: "chunk[%d] of size %ld at %.0f offset=%.0f%s\n",
! 273: i, (long)len, (double)offset2, (double)offset,
! 274: updating_basis_or_equiv && offset == offset2 ? " (seek)" : "");
! 275: }
! 276:
! 277: if (mapbuf) {
! 278: map = map_ptr(mapbuf,offset2,len);
! 279:
! 280: see_token(map, len);
! 281: sum_update(map, len);
! 282: }
! 283:
! 284: if (updating_basis_or_equiv) {
! 285: if (offset == offset2 && fd != -1) {
! 286: OFF_T pos;
! 287: if (flush_write_file(fd) < 0)
! 288: goto report_write_error;
! 289: offset += len;
! 290: if ((pos = do_lseek(fd, len, SEEK_CUR)) != offset) {
! 291: rsyserr(FERROR_XFER, errno,
! 292: "lseek of %s returned %.0f, not %.0f",
! 293: full_fname(fname),
! 294: (double)pos, (double)offset);
! 295: exit_cleanup(RERR_FILEIO);
! 296: }
! 297: continue;
! 298: }
! 299: }
! 300: if (fd != -1 && map && write_file(fd, map, len) != (int)len)
! 301: goto report_write_error;
! 302: offset += len;
! 303: }
! 304:
! 305: if (flush_write_file(fd) < 0)
! 306: goto report_write_error;
! 307:
! 308: #ifdef HAVE_FTRUNCATE
! 309: if (inplace && fd != -1 && do_ftruncate(fd, offset) < 0) {
! 310: rsyserr(FERROR_XFER, errno, "ftruncate failed on %s",
! 311: full_fname(fname));
! 312: }
! 313: #endif
! 314:
! 315: if (do_progress)
! 316: end_progress(total_size);
! 317:
! 318: if (fd != -1 && offset > 0 && sparse_end(fd, offset) != 0) {
! 319: report_write_error:
! 320: rsyserr(FERROR_XFER, errno, "write failed on %s",
! 321: full_fname(fname));
! 322: exit_cleanup(RERR_FILEIO);
! 323: }
! 324:
! 325: sum_len = sum_end(file_sum1);
! 326:
! 327: if (mapbuf)
! 328: unmap_file(mapbuf);
! 329:
! 330: read_buf(f_in, file_sum2, sum_len);
! 331: if (verbose > 2)
! 332: rprintf(FINFO,"got file_sum\n");
! 333: if (fd != -1 && memcmp(file_sum1, file_sum2, sum_len) != 0)
! 334: return 0;
! 335: return 1;
! 336: }
! 337:
! 338:
! 339: static void discard_receive_data(int f_in, OFF_T length)
! 340: {
! 341: receive_data(f_in, NULL, -1, 0, NULL, -1, length);
! 342: }
! 343:
! 344: static void handle_delayed_updates(char *local_name)
! 345: {
! 346: char *fname, *partialptr;
! 347: int ndx;
! 348:
! 349: for (ndx = -1; (ndx = bitbag_next_bit(delayed_bits, ndx)) >= 0; ) {
! 350: struct file_struct *file = cur_flist->files[ndx];
! 351: fname = local_name ? local_name : f_name(file, NULL);
! 352: if ((partialptr = partial_dir_fname(fname)) != NULL) {
! 353: if (make_backups > 0 && !make_backup(fname))
! 354: continue;
! 355: if (verbose > 2) {
! 356: rprintf(FINFO, "renaming %s to %s\n",
! 357: partialptr, fname);
! 358: }
! 359: /* We don't use robust_rename() here because the
! 360: * partial-dir must be on the same drive. */
! 361: if (do_rename(partialptr, fname) < 0) {
! 362: rsyserr(FERROR_XFER, errno,
! 363: "rename failed for %s (from %s)",
! 364: full_fname(fname), partialptr);
! 365: } else {
! 366: if (remove_source_files
! 367: || (preserve_hard_links && F_IS_HLINKED(file)))
! 368: send_msg_int(MSG_SUCCESS, ndx);
! 369: handle_partial_dir(partialptr, PDIR_DELETE);
! 370: }
! 371: }
! 372: }
! 373: }
! 374:
! 375: static void no_batched_update(int ndx, BOOL is_redo)
! 376: {
! 377: struct file_list *flist = flist_for_ndx(ndx, "no_batched_update");
! 378: struct file_struct *file = flist->files[ndx - flist->ndx_start];
! 379:
! 380: rprintf(FERROR_XFER, "(No batched update for%s \"%s\")\n",
! 381: is_redo ? " resend of" : "", f_name(file, NULL));
! 382:
! 383: if (inc_recurse && !dry_run)
! 384: send_msg_int(MSG_NO_SEND, ndx);
! 385: }
! 386:
! 387: static int we_want_redo(int desired_ndx)
! 388: {
! 389: static int redo_ndx = -1;
! 390:
! 391: while (redo_ndx < desired_ndx) {
! 392: if (redo_ndx >= 0)
! 393: no_batched_update(redo_ndx, True);
! 394: if ((redo_ndx = flist_ndx_pop(&batch_redo_list)) < 0)
! 395: return 0;
! 396: }
! 397:
! 398: if (redo_ndx == desired_ndx) {
! 399: redo_ndx = -1;
! 400: return 1;
! 401: }
! 402:
! 403: return 0;
! 404: }
! 405:
! 406: static int gen_wants_ndx(int desired_ndx)
! 407: {
! 408: static int next_ndx = -1;
! 409: static int done_cnt = 0;
! 410: static BOOL got_eof = False;
! 411: int flist_num = first_flist->flist_num;
! 412:
! 413: if (got_eof)
! 414: return 0;
! 415:
! 416: while (next_ndx < desired_ndx) {
! 417: if (inc_recurse && flist_num <= done_cnt)
! 418: return 0;
! 419: if (next_ndx >= 0)
! 420: no_batched_update(next_ndx, False);
! 421: if ((next_ndx = read_int(batch_gen_fd)) < 0) {
! 422: if (inc_recurse) {
! 423: done_cnt++;
! 424: continue;
! 425: }
! 426: got_eof = True;
! 427: return 0;
! 428: }
! 429: }
! 430:
! 431: if (next_ndx == desired_ndx) {
! 432: next_ndx = -1;
! 433: return 1;
! 434: }
! 435:
! 436: return 0;
! 437: }
! 438:
! 439: /**
! 440: * main routine for receiver process.
! 441: *
! 442: * Receiver process runs on the same host as the generator process. */
! 443: int recv_files(int f_in, char *local_name)
! 444: {
! 445: int fd1,fd2;
! 446: STRUCT_STAT st;
! 447: int iflags, xlen;
! 448: char *fname, fbuf[MAXPATHLEN];
! 449: char xname[MAXPATHLEN];
! 450: char fnametmp[MAXPATHLEN];
! 451: char *fnamecmp, *partialptr;
! 452: char fnamecmpbuf[MAXPATHLEN];
! 453: uchar fnamecmp_type;
! 454: struct file_struct *file;
! 455: struct stats initial_stats;
! 456: int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
! 457: enum logcode log_code = log_before_transfer ? FLOG : FINFO;
! 458: int max_phase = protocol_version >= 29 ? 2 : 1;
! 459: int dflt_perms = (ACCESSPERMS & ~orig_umask);
! 460: #ifdef SUPPORT_ACLS
! 461: const char *parent_dirname = "";
! 462: #endif
! 463: int ndx, recv_ok;
! 464:
! 465: if (verbose > 2)
! 466: rprintf(FINFO, "recv_files(%d) starting\n", cur_flist->used);
! 467:
! 468: if (delay_updates)
! 469: delayed_bits = bitbag_create(cur_flist->used + 1);
! 470:
! 471: while (1) {
! 472: cleanup_disable();
! 473:
! 474: /* This call also sets cur_flist. */
! 475: ndx = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,
! 476: xname, &xlen);
! 477: if (ndx == NDX_DONE) {
! 478: if (inc_recurse && first_flist) {
! 479: if (read_batch)
! 480: gen_wants_ndx(first_flist->used + first_flist->ndx_start);
! 481: flist_free(first_flist);
! 482: if (first_flist)
! 483: continue;
! 484: } else if (read_batch && first_flist)
! 485: gen_wants_ndx(first_flist->used);
! 486: if (++phase > max_phase)
! 487: break;
! 488: if (verbose > 2)
! 489: rprintf(FINFO, "recv_files phase=%d\n", phase);
! 490: if (phase == 2 && delay_updates)
! 491: handle_delayed_updates(local_name);
! 492: send_msg(MSG_DONE, "", 0, 0);
! 493: continue;
! 494: }
! 495:
! 496: if (ndx - cur_flist->ndx_start >= 0)
! 497: file = cur_flist->files[ndx - cur_flist->ndx_start];
! 498: else
! 499: file = dir_flist->files[cur_flist->parent_ndx];
! 500: fname = local_name ? local_name : f_name(file, fbuf);
! 501:
! 502: if (verbose > 2)
! 503: rprintf(FINFO, "recv_files(%s)\n", fname);
! 504:
! 505: #ifdef SUPPORT_XATTRS
! 506: if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers)
! 507: recv_xattr_request(file, f_in);
! 508: #endif
! 509:
! 510: if (!(iflags & ITEM_TRANSFER)) {
! 511: maybe_log_item(file, iflags, itemizing, xname);
! 512: #ifdef SUPPORT_XATTRS
! 513: if (preserve_xattrs && iflags & ITEM_REPORT_XATTR && do_xfers
! 514: && !BITS_SET(iflags, ITEM_XNAME_FOLLOWS|ITEM_LOCAL_CHANGE))
! 515: set_file_attrs(fname, file, NULL, fname, 0);
! 516: #endif
! 517: continue;
! 518: }
! 519: if (phase == 2) {
! 520: rprintf(FERROR,
! 521: "got transfer request in phase 2 [%s]\n",
! 522: who_am_i());
! 523: exit_cleanup(RERR_PROTOCOL);
! 524: }
! 525:
! 526: if (file->flags & FLAG_FILE_SENT) {
! 527: if (csum_length == SHORT_SUM_LENGTH) {
! 528: if (keep_partial && !partial_dir)
! 529: make_backups = -make_backups; /* prevents double backup */
! 530: if (append_mode)
! 531: sparse_files = -sparse_files;
! 532: append_mode = -append_mode;
! 533: csum_length = SUM_LENGTH;
! 534: redoing = 1;
! 535: }
! 536: } else {
! 537: if (csum_length != SHORT_SUM_LENGTH) {
! 538: if (keep_partial && !partial_dir)
! 539: make_backups = -make_backups;
! 540: if (append_mode)
! 541: sparse_files = -sparse_files;
! 542: append_mode = -append_mode;
! 543: csum_length = SHORT_SUM_LENGTH;
! 544: redoing = 0;
! 545: }
! 546: }
! 547:
! 548: if (!am_server && do_progress)
! 549: set_current_file_index(file, ndx);
! 550: stats.num_transferred_files++;
! 551: stats.total_transferred_size += F_LENGTH(file);
! 552:
! 553: cleanup_got_literal = 0;
! 554:
! 555: if (daemon_filter_list.head
! 556: && check_filter(&daemon_filter_list, FLOG, fname, 0) < 0) {
! 557: rprintf(FERROR, "attempt to hack rsync failed.\n");
! 558: exit_cleanup(RERR_PROTOCOL);
! 559: }
! 560:
! 561: if (read_batch) {
! 562: int wanted = redoing
! 563: ? we_want_redo(ndx)
! 564: : gen_wants_ndx(ndx);
! 565: if (!wanted) {
! 566: rprintf(FINFO,
! 567: "(Skipping batched update for%s \"%s\")\n",
! 568: redoing ? " resend of" : "",
! 569: fname);
! 570: discard_receive_data(f_in, F_LENGTH(file));
! 571: file->flags |= FLAG_FILE_SENT;
! 572: continue;
! 573: }
! 574: }
! 575:
! 576: if (!do_xfers) { /* log the transfer */
! 577: log_item(FCLIENT, file, &stats, iflags, NULL);
! 578: if (read_batch)
! 579: discard_receive_data(f_in, F_LENGTH(file));
! 580: continue;
! 581: }
! 582: if (write_batch < 0) {
! 583: log_item(FCLIENT, file, &stats, iflags, NULL);
! 584: if (!am_server)
! 585: discard_receive_data(f_in, F_LENGTH(file));
! 586: continue;
! 587: }
! 588:
! 589: partialptr = partial_dir ? partial_dir_fname(fname) : fname;
! 590:
! 591: if (protocol_version >= 29) {
! 592: switch (fnamecmp_type) {
! 593: case FNAMECMP_FNAME:
! 594: fnamecmp = fname;
! 595: break;
! 596: case FNAMECMP_PARTIAL_DIR:
! 597: fnamecmp = partialptr;
! 598: break;
! 599: case FNAMECMP_BACKUP:
! 600: fnamecmp = get_backup_name(fname);
! 601: break;
! 602: case FNAMECMP_FUZZY:
! 603: if (file->dirname) {
! 604: pathjoin(fnamecmpbuf, MAXPATHLEN,
! 605: file->dirname, xname);
! 606: fnamecmp = fnamecmpbuf;
! 607: } else
! 608: fnamecmp = xname;
! 609: break;
! 610: default:
! 611: if (fnamecmp_type >= basis_dir_cnt) {
! 612: rprintf(FERROR,
! 613: "invalid basis_dir index: %d.\n",
! 614: fnamecmp_type);
! 615: exit_cleanup(RERR_PROTOCOL);
! 616: }
! 617: pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
! 618: basis_dir[fnamecmp_type], fname);
! 619: fnamecmp = fnamecmpbuf;
! 620: break;
! 621: }
! 622: if (!fnamecmp || (daemon_filter_list.head
! 623: && check_filter(&daemon_filter_list, FLOG, fname, 0) < 0)) {
! 624: fnamecmp = fname;
! 625: fnamecmp_type = FNAMECMP_FNAME;
! 626: }
! 627: } else {
! 628: /* Reminder: --inplace && --partial-dir are never
! 629: * enabled at the same time. */
! 630: if (inplace && make_backups > 0) {
! 631: if (!(fnamecmp = get_backup_name(fname)))
! 632: fnamecmp = fname;
! 633: else
! 634: fnamecmp_type = FNAMECMP_BACKUP;
! 635: } else if (partial_dir && partialptr)
! 636: fnamecmp = partialptr;
! 637: else
! 638: fnamecmp = fname;
! 639: }
! 640:
! 641: initial_stats = stats;
! 642:
! 643: /* open the file */
! 644: fd1 = do_open(fnamecmp, O_RDONLY, 0);
! 645:
! 646: if (fd1 == -1 && protocol_version < 29) {
! 647: if (fnamecmp != fname) {
! 648: fnamecmp = fname;
! 649: fd1 = do_open(fnamecmp, O_RDONLY, 0);
! 650: }
! 651:
! 652: if (fd1 == -1 && basis_dir[0]) {
! 653: /* pre-29 allowed only one alternate basis */
! 654: pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
! 655: basis_dir[0], fname);
! 656: fnamecmp = fnamecmpbuf;
! 657: fd1 = do_open(fnamecmp, O_RDONLY, 0);
! 658: }
! 659: }
! 660:
! 661: updating_basis_or_equiv = inplace
! 662: && (fnamecmp == fname || fnamecmp_type == FNAMECMP_BACKUP);
! 663:
! 664: if (fd1 == -1) {
! 665: st.st_mode = 0;
! 666: st.st_size = 0;
! 667: } else if (do_fstat(fd1,&st) != 0) {
! 668: rsyserr(FERROR_XFER, errno, "fstat %s failed",
! 669: full_fname(fnamecmp));
! 670: discard_receive_data(f_in, F_LENGTH(file));
! 671: close(fd1);
! 672: if (inc_recurse)
! 673: send_msg_int(MSG_NO_SEND, ndx);
! 674: continue;
! 675: }
! 676:
! 677: if (fd1 != -1 && S_ISDIR(st.st_mode) && fnamecmp == fname) {
! 678: /* this special handling for directories
! 679: * wouldn't be necessary if robust_rename()
! 680: * and the underlying robust_unlink could cope
! 681: * with directories
! 682: */
! 683: rprintf(FERROR_XFER, "recv_files: %s is a directory\n",
! 684: full_fname(fnamecmp));
! 685: discard_receive_data(f_in, F_LENGTH(file));
! 686: close(fd1);
! 687: if (inc_recurse)
! 688: send_msg_int(MSG_NO_SEND, ndx);
! 689: continue;
! 690: }
! 691:
! 692: if (fd1 != -1 && !S_ISREG(st.st_mode)) {
! 693: close(fd1);
! 694: fd1 = -1;
! 695: }
! 696:
! 697: /* If we're not preserving permissions, change the file-list's
! 698: * mode based on the local permissions and some heuristics. */
! 699: if (!preserve_perms) {
! 700: int exists = fd1 != -1;
! 701: #ifdef SUPPORT_ACLS
! 702: const char *dn = file->dirname ? file->dirname : ".";
! 703: if (parent_dirname != dn
! 704: && strcmp(parent_dirname, dn) != 0) {
! 705: dflt_perms = default_perms_for_dir(dn);
! 706: parent_dirname = dn;
! 707: }
! 708: #endif
! 709: file->mode = dest_mode(file->mode, st.st_mode,
! 710: dflt_perms, exists);
! 711: }
! 712:
! 713: /* We now check to see if we are writing the file "inplace" */
! 714: if (inplace) {
! 715: fd2 = do_open(fname, O_WRONLY|O_CREAT, 0600);
! 716: if (fd2 == -1) {
! 717: rsyserr(FERROR_XFER, errno, "open %s failed",
! 718: full_fname(fname));
! 719: }
! 720: } else {
! 721: fd2 = open_tmpfile(fnametmp, fname, file);
! 722: if (fd2 != -1)
! 723: cleanup_set(fnametmp, partialptr, file, fd1, fd2);
! 724: }
! 725:
! 726: if (fd2 == -1) {
! 727: discard_receive_data(f_in, F_LENGTH(file));
! 728: if (fd1 != -1)
! 729: close(fd1);
! 730: if (inc_recurse)
! 731: send_msg_int(MSG_NO_SEND, ndx);
! 732: continue;
! 733: }
! 734:
! 735: /* log the transfer */
! 736: if (log_before_transfer)
! 737: log_item(FCLIENT, file, &initial_stats, iflags, NULL);
! 738: else if (!am_server && verbose && do_progress)
! 739: rprintf(FINFO, "%s\n", fname);
! 740:
! 741: /* recv file data */
! 742: recv_ok = receive_data(f_in, fnamecmp, fd1, st.st_size,
! 743: fname, fd2, F_LENGTH(file));
! 744:
! 745: log_item(log_code, file, &initial_stats, iflags, NULL);
! 746:
! 747: if (fd1 != -1)
! 748: close(fd1);
! 749: if (close(fd2) < 0) {
! 750: rsyserr(FERROR, errno, "close failed on %s",
! 751: full_fname(fnametmp));
! 752: exit_cleanup(RERR_FILEIO);
! 753: }
! 754:
! 755: if ((recv_ok && (!delay_updates || !partialptr)) || inplace) {
! 756: if (partialptr == fname)
! 757: partialptr = NULL;
! 758: if (!finish_transfer(fname, fnametmp, fnamecmp,
! 759: partialptr, file, recv_ok, 1))
! 760: recv_ok = -1;
! 761: else if (fnamecmp == partialptr) {
! 762: do_unlink(partialptr);
! 763: handle_partial_dir(partialptr, PDIR_DELETE);
! 764: }
! 765: } else if (keep_partial && partialptr) {
! 766: if (!handle_partial_dir(partialptr, PDIR_CREATE)) {
! 767: rprintf(FERROR,
! 768: "Unable to create partial-dir for %s -- discarding %s.\n",
! 769: local_name ? local_name : f_name(file, NULL),
! 770: recv_ok ? "completed file" : "partial file");
! 771: do_unlink(fnametmp);
! 772: recv_ok = -1;
! 773: } else if (!finish_transfer(partialptr, fnametmp, fnamecmp, NULL,
! 774: file, recv_ok, !partial_dir))
! 775: recv_ok = -1;
! 776: else if (delay_updates && recv_ok) {
! 777: bitbag_set_bit(delayed_bits, ndx);
! 778: recv_ok = 2;
! 779: } else
! 780: partialptr = NULL;
! 781: } else
! 782: do_unlink(fnametmp);
! 783:
! 784: cleanup_disable();
! 785:
! 786: if (read_batch)
! 787: file->flags |= FLAG_FILE_SENT;
! 788:
! 789: switch (recv_ok) {
! 790: case 2:
! 791: break;
! 792: case 1:
! 793: if (remove_source_files || inc_recurse
! 794: || (preserve_hard_links && F_IS_HLINKED(file)))
! 795: send_msg_int(MSG_SUCCESS, ndx);
! 796: break;
! 797: case 0: {
! 798: enum logcode msgtype = redoing ? FERROR_XFER : FWARNING;
! 799: if (msgtype == FERROR_XFER || verbose) {
! 800: char *errstr, *redostr, *keptstr;
! 801: if (!(keep_partial && partialptr) && !inplace)
! 802: keptstr = "discarded";
! 803: else if (partial_dir)
! 804: keptstr = "put into partial-dir";
! 805: else
! 806: keptstr = "retained";
! 807: if (msgtype == FERROR_XFER) {
! 808: errstr = "ERROR";
! 809: redostr = "";
! 810: } else {
! 811: errstr = "WARNING";
! 812: redostr = read_batch ? " (may try again)"
! 813: : " (will try again)";
! 814: }
! 815: rprintf(msgtype,
! 816: "%s: %s failed verification -- update %s%s.\n",
! 817: errstr, local_name ? f_name(file, NULL) : fname,
! 818: keptstr, redostr);
! 819: }
! 820: if (!redoing) {
! 821: if (read_batch)
! 822: flist_ndx_push(&batch_redo_list, ndx);
! 823: send_msg_int(MSG_REDO, ndx);
! 824: file->flags |= FLAG_FILE_SENT;
! 825: } else if (inc_recurse)
! 826: send_msg_int(MSG_NO_SEND, ndx);
! 827: break;
! 828: }
! 829: case -1:
! 830: if (inc_recurse)
! 831: send_msg_int(MSG_NO_SEND, ndx);
! 832: break;
! 833: }
! 834: }
! 835: if (make_backups < 0)
! 836: make_backups = -make_backups;
! 837:
! 838: if (phase == 2 && delay_updates) /* for protocol_version < 29 */
! 839: handle_delayed_updates(local_name);
! 840:
! 841: if (verbose > 2)
! 842: rprintf(FINFO,"recv_files finished\n");
! 843:
! 844: return 0;
! 845: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>