File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / rsync.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    1: /*
    2:  * Routines common to more than one of the rsync processes.
    3:  *
    4:  * Copyright (C) 1996 Andrew Tridgell
    5:  * Copyright (C) 1996 Paul Mackerras
    6:  * Copyright (C) 2003-2020 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: #include "ifuncs.h"
   24: #if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
   25: #include <libcharset.h>
   26: #elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
   27: #include <langinfo.h>
   28: #endif
   29: 
   30: extern int dry_run;
   31: extern int preserve_acls;
   32: extern int preserve_xattrs;
   33: extern int preserve_perms;
   34: extern int preserve_fileflags;
   35: extern int preserve_executability;
   36: extern int preserve_times;
   37: extern int copy_devices;
   38: extern int am_root;
   39: extern int am_server;
   40: extern int am_daemon;
   41: extern int am_sender;
   42: extern int am_receiver;
   43: extern int am_generator;
   44: extern int am_dbadmin;
   45: extern int am_starting_up;
   46: extern int allow_8bit_chars;
   47: extern int protocol_version;
   48: extern int got_kill_signal;
   49: extern int called_from_signal_handler;
   50: extern int inc_recurse;
   51: extern int inplace;
   52: extern int flist_eof;
   53: extern int file_old_total;
   54: extern int keep_dirlinks;
   55: extern int make_backups;
   56: extern char *link_by_hash_dir;
   57: extern int sanitize_paths;
   58: extern struct file_list *cur_flist, *first_flist, *dir_flist;
   59: extern struct chmod_mode_struct *daemon_chmod_modes;
   60: #ifdef ICONV_OPTION
   61: extern char *iconv_opt;
   62: #endif
   63: 
   64: #define UPDATED_OWNER (1<<0)
   65: #define UPDATED_GROUP (1<<1)
   66: #define UPDATED_MTIME (1<<2)
   67: #define UPDATED_ATIME (1<<3)
   68: #define UPDATED_ACLS  (1<<4)
   69: #define UPDATED_MODE  (1<<5)
   70: 
   71: #define UPDATED_TIMES (UPDATED_MTIME|UPDATED_ATIME)
   72: 
   73: #ifdef ICONV_CONST
   74: iconv_t ic_chck = (iconv_t)-1;
   75: # ifdef ICONV_OPTION
   76: iconv_t ic_send = (iconv_t)-1, ic_recv = (iconv_t)-1;
   77: # endif
   78: 
   79: static const char *default_charset(void)
   80: {
   81: # if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
   82: 	return locale_charset();
   83: # elif defined HAVE_LANGINFO_H && defined HAVE_NL_LANGINFO
   84: 	return nl_langinfo(CODESET);
   85: # else
   86: 	return ""; /* Works with (at the very least) gnu iconv... */
   87: # endif
   88: }
   89: 
   90: void setup_iconv(void)
   91: {
   92: 	const char *defset = default_charset();
   93: # ifdef ICONV_OPTION
   94: 	const char *charset;
   95: 	char *cp;
   96: # endif
   97: 
   98: 	if (!am_server && !allow_8bit_chars) {
   99: 		/* It's OK if this fails... */
  100: 		ic_chck = iconv_open(defset, defset);
  101: 
  102: 		if (DEBUG_GTE(ICONV, 2)) {
  103: 			if (ic_chck == (iconv_t)-1) {
  104: 				rprintf(FINFO,
  105: 					"msg checking via isprint()"
  106: 					" (iconv_open(\"%s\", \"%s\") errno: %d)\n",
  107: 					defset, defset, errno);
  108: 			} else {
  109: 				rprintf(FINFO,
  110: 					"msg checking charset: %s\n",
  111: 					defset);
  112: 			}
  113: 		}
  114: 	} else
  115: 		ic_chck = (iconv_t)-1;
  116: 
  117: # ifdef ICONV_OPTION
  118: 	if (!iconv_opt)
  119: 		return;
  120: 
  121: 	if ((cp = strchr(iconv_opt, ',')) != NULL) {
  122: 		if (am_server) /* A local transfer needs this. */
  123: 			iconv_opt = cp + 1;
  124: 		else
  125: 			*cp = '\0';
  126: 	}
  127: 
  128: 	if (!*iconv_opt || (*iconv_opt == '.' && iconv_opt[1] == '\0'))
  129: 		charset = defset;
  130: 	else
  131: 		charset = iconv_opt;
  132: 
  133: 	if ((ic_send = iconv_open(UTF8_CHARSET, charset)) == (iconv_t)-1) {
  134: 		rprintf(FERROR, "iconv_open(\"%s\", \"%s\") failed\n",
  135: 			UTF8_CHARSET, charset);
  136: 		exit_cleanup(RERR_UNSUPPORTED);
  137: 	}
  138: 
  139: 	if ((ic_recv = iconv_open(charset, UTF8_CHARSET)) == (iconv_t)-1) {
  140: 		rprintf(FERROR, "iconv_open(\"%s\", \"%s\") failed\n",
  141: 			charset, UTF8_CHARSET);
  142: 		exit_cleanup(RERR_UNSUPPORTED);
  143: 	}
  144: 
  145: 	if (DEBUG_GTE(ICONV, 1)) {
  146: 		rprintf(FINFO, "[%s] charset: %s\n",
  147: 			who_am_i(), *charset ? charset : "[LOCALE]");
  148: 	}
  149: # endif
  150: }
  151: 
  152: /* This function converts the chars in the "in" xbuf into characters in the
  153:  * "out" xbuf.  The ".len" chars of the "in" xbuf is used starting from its
  154:  * ".pos".  The ".size" of the "out" xbuf restricts how many characters can
  155:  * be stored, starting at its ".pos+.len" position.  Note that the last byte
  156:  * of the "out" xbuf is not used, which reserves space for a trailing '\0'
  157:  * (though it is up to the caller to store a trailing '\0', as needed).
  158:  *
  159:  * We return a 0 on success or a -1 on error.  An error also sets errno to
  160:  * E2BIG, EILSEQ, or EINVAL (see below); otherwise errno will be set to 0.
  161:  * The "in" xbuf is altered to update ".pos" and ".len".  The "out" xbuf has
  162:  * data appended, and its ".len" incremented (see below for a ".size" note).
  163:  *
  164:  * If ICB_CIRCULAR_OUT is set in "flags", the chars going into the "out" xbuf
  165:  * can wrap around to the start, and the xbuf may have its ".size" reduced
  166:  * (presumably by 1 byte) if the iconv code doesn't have space to store a
  167:  * multi-byte character at the physical end of the ".buf" (though no reducing
  168:  * happens if ".pos" is <= 1, since there is no room to wrap around).
  169:  *
  170:  * If ICB_EXPAND_OUT is set in "flags", the "out" xbuf will be allocated if
  171:  * empty, and (as long as ICB_CIRCULAR_OUT is not set) expanded if too small.
  172:  * This prevents the return of E2BIG (except for a circular xbuf).
  173:  *
  174:  * If ICB_INCLUDE_BAD is set in "flags", any badly-encoded chars are included
  175:  * verbatim in the "out" xbuf, so EILSEQ will not be returned.
  176:  *
  177:  * If ICB_INCLUDE_INCOMPLETE is set in "flags", any incomplete multi-byte
  178:  * chars are included, which ensures that EINVAL is not returned.
  179:  *
  180:  * If ICB_INIT is set, the iconv() conversion state is initialized prior to
  181:  * processing the characters. */
  182: int iconvbufs(iconv_t ic, xbuf *in, xbuf *out, int flags)
  183: {
  184: 	ICONV_CONST char *ibuf;
  185: 	size_t icnt, ocnt, opos;
  186: 	char *obuf;
  187: 
  188: 	if (!out->size && flags & ICB_EXPAND_OUT) {
  189: 		size_t siz = ROUND_UP_1024(in->len * 2);
  190: 		alloc_xbuf(out, siz);
  191: 	} else if (out->len+1 >= out->size) {
  192: 		/* There is no room to even start storing data. */
  193: 		if (!(flags & ICB_EXPAND_OUT) || flags & ICB_CIRCULAR_OUT) {
  194: 			errno = E2BIG;
  195: 			return -1;
  196: 		}
  197: 		realloc_xbuf(out, out->size + ROUND_UP_1024(in->len * 2));
  198: 	}
  199: 
  200: 	if (flags & ICB_INIT)
  201: 		iconv(ic, NULL, 0, NULL, 0);
  202: 
  203: 	ibuf = in->buf + in->pos;
  204: 	icnt = in->len;
  205: 
  206: 	opos = out->pos + out->len;
  207: 	if (flags & ICB_CIRCULAR_OUT) {
  208: 		if (opos >= out->size) {
  209: 			opos -= out->size;
  210: 			/* We know that out->pos is not 0 due to the "no room" check
  211: 			 * above, so this can't go "negative". */
  212: 			ocnt = out->pos - opos - 1;
  213: 		} else {
  214: 			/* Allow the use of all bytes to the physical end of the buffer
  215: 			 * unless pos is 0, in which case we reserve our trailing '\0'. */
  216: 			ocnt = out->size - opos - (out->pos ? 0 : 1);
  217: 		}
  218: 	} else
  219: 		ocnt = out->size - opos - 1;
  220: 	obuf = out->buf + opos;
  221: 
  222: 	while (icnt) {
  223: 		while (iconv(ic, &ibuf, &icnt, &obuf, &ocnt) == (size_t)-1) {
  224: 			if (errno == EINTR)
  225: 				continue;
  226: 			if (errno == EINVAL) {
  227: 				if (!(flags & ICB_INCLUDE_INCOMPLETE))
  228: 					goto finish;
  229: 				if (!ocnt)
  230: 					goto e2big;
  231: 			} else if (errno == EILSEQ) {
  232: 				if (!(flags & ICB_INCLUDE_BAD))
  233: 					goto finish;
  234: 				if (!ocnt)
  235: 					goto e2big;
  236: 			} else if (errno == E2BIG) {
  237: 				size_t siz;
  238: 			  e2big:
  239: 				opos = obuf - out->buf;
  240: 				if (flags & ICB_CIRCULAR_OUT && out->pos > 1 && opos > out->pos) {
  241: 					/* We are in a divided circular buffer at the physical
  242: 					 * end with room to wrap to the start.  If iconv() refused
  243: 					 * to use one or more trailing bytes in the buffer, we
  244: 					 * set the size to ignore the unused bytes. */
  245: 					if (opos < out->size)
  246: 						reduce_iobuf_size(out, opos);
  247: 					obuf = out->buf;
  248: 					ocnt = out->pos - 1;
  249: 					continue;
  250: 				}
  251: 				if (!(flags & ICB_EXPAND_OUT) || flags & ICB_CIRCULAR_OUT) {
  252: 					errno = E2BIG;
  253: 					goto finish;
  254: 				}
  255: 				siz = ROUND_UP_1024(in->len * 2);
  256: 				realloc_xbuf(out, out->size + siz);
  257: 				obuf = out->buf + opos;
  258: 				ocnt += siz;
  259: 				continue;
  260: 			} else {
  261: 				rsyserr(FERROR, errno, "unexpected error from iconv()");
  262: 				exit_cleanup(RERR_UNSUPPORTED);
  263: 			}
  264: 			*obuf++ = *ibuf++;
  265: 			ocnt--, icnt--;
  266: 			if (!icnt)
  267: 				break;
  268: 		}
  269: 	}
  270: 
  271: 	errno = 0;
  272: 
  273:   finish:
  274: 	opos = obuf - out->buf;
  275: 	if (flags & ICB_CIRCULAR_OUT && opos < out->pos)
  276: 		opos += out->size;
  277: 	out->len = opos - out->pos;
  278: 
  279: 	in->len = icnt;
  280: 	in->pos = ibuf - in->buf;
  281: 
  282: 	return errno ? -1 : 0;
  283: }
  284: #endif
  285: 
  286: void send_protected_args(int fd, char *args[])
  287: {
  288: 	int i;
  289: #ifdef ICONV_OPTION
  290: 	int convert = ic_send != (iconv_t)-1;
  291: 	xbuf outbuf, inbuf;
  292: 
  293: 	if (convert)
  294: 		alloc_xbuf(&outbuf, 1024);
  295: #endif
  296: 
  297: 	for (i = 0; args[i]; i++) {} /* find first NULL */
  298: 	args[i] = "rsync"; /* set a new arg0 */
  299: 	if (DEBUG_GTE(CMD, 1))
  300: 		print_child_argv("protected args:", args + i + 1);
  301: 	do {
  302: 		if (!args[i][0])
  303: 			write_buf(fd, ".", 2);
  304: #ifdef ICONV_OPTION
  305: 		else if (convert) {
  306: 			INIT_XBUF_STRLEN(inbuf, args[i]);
  307: 			iconvbufs(ic_send, &inbuf, &outbuf,
  308: 				  ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE | ICB_INIT);
  309: 			outbuf.buf[outbuf.len] = '\0';
  310: 			write_buf(fd, outbuf.buf, outbuf.len + 1);
  311: 			outbuf.len = 0;
  312: 		}
  313: #endif
  314: 		else
  315: 			write_buf(fd, args[i], strlen(args[i]) + 1);
  316: 	} while (args[++i]);
  317: 	write_byte(fd, 0);
  318: 
  319: #ifdef ICONV_OPTION
  320: 	if (convert)
  321: 		free(outbuf.buf);
  322: #endif
  323: }
  324: 
  325: int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, char *buf, int *len_ptr)
  326: {
  327: 	int len, iflags = 0;
  328: 	struct file_list *flist;
  329: 	uchar fnamecmp_type = FNAMECMP_FNAME;
  330: 	int ndx;
  331: 
  332:   read_loop:
  333: 	while (1) {
  334: 		ndx = read_ndx(f_in);
  335: 
  336: 		if (ndx >= 0)
  337: 			break;
  338: 		if (ndx == NDX_DONE)
  339: 			return ndx;
  340: 		if (ndx == NDX_DEL_STATS) {
  341: 			read_del_stats(f_in);
  342: 			if (am_sender && am_server)
  343: 				write_del_stats(f_out);
  344: 			continue;
  345: 		}
  346: 		if (!inc_recurse || am_sender) {
  347: 			int last;
  348: 			if (first_flist)
  349: 				last = first_flist->prev->ndx_start + first_flist->prev->used - 1;
  350: 			else
  351: 				last = -1;
  352: 			rprintf(FERROR,
  353: 				"Invalid file index: %d (%d - %d) [%s]\n",
  354: 				ndx, NDX_DONE, last, who_am_i());
  355: 			exit_cleanup(RERR_PROTOCOL);
  356: 		}
  357: 		if (ndx == NDX_FLIST_EOF) {
  358: 			flist_eof = 1;
  359: 			if (DEBUG_GTE(FLIST, 3))
  360: 				rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i());
  361: 			write_int(f_out, NDX_FLIST_EOF);
  362: 			continue;
  363: 		}
  364: 		ndx = NDX_FLIST_OFFSET - ndx;
  365: 		if (ndx < 0 || ndx >= dir_flist->used) {
  366: 			ndx = NDX_FLIST_OFFSET - ndx;
  367: 			rprintf(FERROR,
  368: 				"Invalid dir index: %d (%d - %d) [%s]\n",
  369: 				ndx, NDX_FLIST_OFFSET,
  370: 				NDX_FLIST_OFFSET - dir_flist->used + 1,
  371: 				who_am_i());
  372: 			exit_cleanup(RERR_PROTOCOL);
  373: 		}
  374: 
  375: 		if (DEBUG_GTE(FLIST, 2)) {
  376: 			rprintf(FINFO, "[%s] receiving flist for dir %d\n",
  377: 				who_am_i(), ndx);
  378: 		}
  379: 		/* Send all the data we read for this flist to the generator. */
  380: 		start_flist_forward(ndx);
  381: 		flist = recv_file_list(f_in, ndx);
  382: 		flist->parent_ndx = ndx;
  383: 		stop_flist_forward();
  384: 	}
  385: 
  386: 	iflags = protocol_version >= 29 ? read_shortint(f_in)
  387: 		   : ITEM_TRANSFER | ITEM_MISSING_DATA;
  388: 
  389: 	/* Support the protocol-29 keep-alive style. */
  390: 	if (protocol_version < 30 && ndx == cur_flist->used && iflags == ITEM_IS_NEW) {
  391: 		if (am_sender)
  392: 			maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH);
  393: 		goto read_loop;
  394: 	}
  395: 
  396: 	flist = flist_for_ndx(ndx, "read_ndx_and_attrs");
  397: 	if (flist != cur_flist) {
  398: 		cur_flist = flist;
  399: 		if (am_sender) {
  400: 			file_old_total = cur_flist->used;
  401: 			for (flist = first_flist; flist != cur_flist; flist = flist->next)
  402: 				file_old_total += flist->used;
  403: 		}
  404: 	}
  405: 
  406: 	if (iflags & ITEM_BASIS_TYPE_FOLLOWS)
  407: 		fnamecmp_type = read_byte(f_in);
  408: 	*type_ptr = fnamecmp_type;
  409: 
  410: 	if (iflags & ITEM_XNAME_FOLLOWS) {
  411: 		if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0)
  412: 			exit_cleanup(RERR_PROTOCOL);
  413: 
  414: 		if (sanitize_paths) {
  415: 			sanitize_path(buf, buf, "", 0, SP_DEFAULT);
  416: 			len = strlen(buf);
  417: 		}
  418: 	} else {
  419: 		*buf = '\0';
  420: 		len = -1;
  421: 	}
  422: 	*len_ptr = len;
  423: 
  424: 	if (iflags & ITEM_TRANSFER) {
  425: 		int i = ndx - cur_flist->ndx_start;
  426: 		struct file_struct *file = cur_flist->files[i];
  427: 		if (i < 0 || !(S_ISREG(file->mode) || (copy_devices && IS_DEVICE(file->mode)))) {
  428: 			rprintf(FERROR,
  429: 				"received request to transfer non-regular file: %d [%s]\n",
  430: 				ndx, who_am_i());
  431: 			exit_cleanup(RERR_PROTOCOL);
  432: 		}
  433: 	}
  434: 
  435: 	*iflag_ptr = iflags;
  436: 	return ndx;
  437: }
  438: 
  439: /*
  440:   free a sums struct
  441:   */
  442: void free_sums(struct sum_struct *s)
  443: {
  444: 	if (s->sums) free(s->sums);
  445: 	free(s);
  446: }
  447: 
  448: /* This is only called when we aren't preserving permissions.  Figure out what
  449:  * the permissions should be and return them merged back into the mode. */
  450: mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
  451: 		 int exists)
  452: {
  453: 	int new_mode;
  454: 	/* If the file already exists, we'll return the local permissions,
  455: 	 * possibly tweaked by the --executability option. */
  456: 	if (exists) {
  457: 		new_mode = (flist_mode & ~CHMOD_BITS) | (stat_mode & CHMOD_BITS);
  458: 		if (preserve_executability && S_ISREG(flist_mode)) {
  459: 			/* If the source file is executable, grant execute
  460: 			 * rights to everyone who can read, but ONLY if the
  461: 			 * file isn't already executable. */
  462: 			if (!(flist_mode & 0111))
  463: 				new_mode &= ~0111;
  464: 			else if (!(stat_mode & 0111))
  465: 				new_mode |= (new_mode & 0444) >> 2;
  466: 		}
  467: 	} else {
  468: 		/* Apply destination default permissions and turn
  469: 		 * off special permissions. */
  470: 		new_mode = flist_mode & (~CHMOD_BITS | dflt_perms);
  471: 	}
  472: 	return new_mode;
  473: }
  474: 
  475: #if defined SUPPORT_FILEFLAGS || defined SUPPORT_FORCE_CHANGE
  476: /* Set a file's st_flags. */
  477: static int set_fileflags(const char *fname, uint32 fileflags)
  478: {
  479: 	if (do_chflags(fname, fileflags) != 0) {
  480: 		rsyserr(FERROR_XFER, errno,
  481: 			"failed to set file flags on %s",
  482: 			full_fname(fname));
  483: 		return 0;
  484: 	}
  485: 
  486: 	return 1;
  487: }
  488: 
  489: /* Remove immutable flags from an object, so it can be altered/removed. */
  490: int make_mutable(const char *fname, mode_t mode, uint32 fileflags, uint32 iflags)
  491: {
  492: 	if (S_ISLNK(mode) || !(fileflags & iflags))
  493: 		return 0;
  494: 	if (!set_fileflags(fname, fileflags & ~iflags))
  495: 		return -1;
  496: 	return 1;
  497: }
  498: 
  499: /* Undo a prior make_mutable() call that returned a 1. */
  500: int undo_make_mutable(const char *fname, uint32 fileflags)
  501: {
  502: 	if (!set_fileflags(fname, fileflags))
  503: 		return -1;
  504: 	return 1;
  505: }
  506: #endif
  507: 
  508: static int same_mtime(struct file_struct *file, STRUCT_STAT *st, int extra_accuracy)
  509: {
  510: #ifdef ST_MTIME_NSEC
  511: 	uint32 f1_nsec = F_MOD_NSEC_or_0(file);
  512: 	uint32 f2_nsec = (uint32)st->ST_MTIME_NSEC;
  513: #else
  514: 	uint32 f1_nsec = 0, f2_nsec = 0;
  515: #endif
  516: 
  517: 	if (extra_accuracy) /* ignore modify_window when setting the time after a transfer or checksum check */
  518: 		return file->modtime == st->st_mtime && f1_nsec == f2_nsec;
  519: 
  520: 	return same_time(file->modtime, f1_nsec, st->st_mtime , f2_nsec);
  521: }
  522: 
  523: int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
  524: 		   const char *fnamecmp, int flags)
  525: {
  526: 	int updated = 0;
  527: 	stat_x sx2;
  528: 	int change_uid, change_gid;
  529: 	mode_t new_mode = file->mode;
  530: 	int inherit;
  531: 
  532: 	if (!sxp) {
  533: 		if (dry_run)
  534: 			return 1;
  535: 		if (link_stat(fname, &sx2.st, 0) < 0) {
  536: 			rsyserr(FERROR_XFER, errno, "stat %s failed",
  537: 				full_fname(fname));
  538: 			return 0;
  539: 		}
  540: 		init_stat_x(&sx2);
  541: 		sxp = &sx2;
  542: 		inherit = !preserve_perms;
  543: 	} else
  544: 		inherit = !preserve_perms && file->flags & FLAG_DIR_CREATED;
  545: 
  546: 	if (inherit && S_ISDIR(new_mode) && sxp->st.st_mode & S_ISGID) {
  547: 		/* We just created this directory and its setgid
  548: 		 * bit is on, so make sure it stays on. */
  549: 		new_mode |= S_ISGID;
  550: 	}
  551: 
  552: 	if (daemon_chmod_modes && !S_ISLNK(new_mode))
  553: 		new_mode = tweak_mode(new_mode, daemon_chmod_modes);
  554: 
  555: #ifdef SUPPORT_ACLS
  556: 	if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp))
  557: 		get_acl(fname, sxp);
  558: #endif
  559: 
  560: 	change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file)
  561: 		  && !(omit_dir_changes && S_ISDIR(sxp->st.st_mode));
  562: 	change_gid = gid_ndx && !(file->flags & FLAG_SKIP_GROUP)
  563: 		  && sxp->st.st_gid != (gid_t)F_GROUP(file)
  564: 		  && !(omit_dir_changes && S_ISDIR(sxp->st.st_mode));
  565: #ifndef CAN_CHOWN_SYMLINK
  566: 	if (S_ISLNK(sxp->st.st_mode)) {
  567: 		;
  568: 	} else
  569: #endif
  570: 	if (change_uid || change_gid) {
  571: 		if (DEBUG_GTE(OWN, 1)) {
  572: 			if (change_uid) {
  573: 				rprintf(FINFO,
  574: 					"set uid of %s from %u to %u\n",
  575: 					fname, (unsigned)sxp->st.st_uid, F_OWNER(file));
  576: 			}
  577: 			if (change_gid) {
  578: 				rprintf(FINFO,
  579: 					"set gid of %s from %u to %u\n",
  580: 					fname, (unsigned)sxp->st.st_gid, F_GROUP(file));
  581: 			}
  582: 		}
  583: 		if (am_root >= 0) {
  584: 			uid_t uid = change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid;
  585: 			gid_t gid = change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid;
  586: 			if (do_lchown(fname, uid, gid, sxp->st.st_mode, ST_FLAGS(sxp->st)) != 0) {
  587: 				/* We shouldn't have attempted to change uid
  588: 				 * or gid unless have the privilege. */
  589: 				rsyserr(FERROR_XFER, errno, "%s %s failed",
  590: 					change_uid ? "chown" : "chgrp",
  591: 					full_fname(fname));
  592: 				goto cleanup;
  593: 			}
  594: 			if (uid == (uid_t)-1 && sxp->st.st_uid != (uid_t)-1)
  595: 				rprintf(FERROR_XFER, "uid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname));
  596: 			if (gid == (gid_t)-1 && sxp->st.st_gid != (gid_t)-1)
  597: 				rprintf(FERROR_XFER, "gid 4294967295 (-1) is impossible to set on %s\n", full_fname(fname));
  598: 			/* A lchown had been done, so we need to re-stat if
  599: 			 * the destination had the setuid or setgid bits set
  600: 			 * (due to the side effect of the chown call). */
  601: 			if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
  602: 				link_stat(fname, &sxp->st,
  603: 					  keep_dirlinks && S_ISDIR(sxp->st.st_mode));
  604: 			}
  605: 		}
  606: 		if (change_uid)
  607: 			updated |= UPDATED_OWNER;
  608: 		if (change_gid)
  609: 			updated |= UPDATED_GROUP;
  610: 	}
  611: 
  612: #ifdef SUPPORT_XATTRS
  613: 	if (am_root < 0)
  614: 		set_stat_xattr(fname, file, new_mode);
  615: 	if (preserve_xattrs && fnamecmp) {
  616: 		uint32 tmpflags = sxp->st.st_flags;
  617: 		sxp->st.st_flags = F_FFLAGS(file); /* set_xattr() needs to check UF_COMPRESSED */
  618: 		set_xattr(fname, file, fnamecmp, sxp);
  619: 		sxp->st.st_flags = tmpflags;
  620: 		if (S_ISDIR(sxp->st.st_mode))
  621: 			link_stat(fname, &sx2.st, 0);
  622: 	}
  623: #endif
  624: 
  625: 	if (!preserve_times
  626: 	 || (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
  627: 	 || (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
  628: 		flags |= ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME;
  629: 	else if (sxp != &sx2)
  630: 		memcpy(&sx2.st, &sxp->st, sizeof (sx2.st));
  631: 	if (!atimes_ndx || S_ISDIR(sxp->st.st_mode))
  632: 		flags |= ATTRS_SKIP_ATIME;
  633: 	/* Don't set the creation date on the root folder of an HFS+ volume. */
  634: 	if (sxp->st.st_ino == 2 && S_ISDIR(sxp->st.st_mode))
  635: 		flags |= ATTRS_SKIP_CRTIME;
  636: 	if (!(flags & ATTRS_SKIP_MTIME)
  637: #ifdef SUPPORT_HFS_COMPRESSION
  638: 	 && !(sxp->st.st_flags & UF_COMPRESSED) /* setting this alters mtime, so defer to after set_fileflags */
  639: #endif
  640: 	 && !same_mtime(file, &sxp->st, flags & ATTRS_ACCURATE_TIME)) {
  641: 		sx2.st.st_mtime = file->modtime;
  642: #ifdef ST_MTIME_NSEC
  643: 		sx2.st.ST_MTIME_NSEC = F_MOD_NSEC_or_0(file);
  644: #endif
  645: 		updated |= UPDATED_MTIME;
  646: 	}
  647: 	if (!(flags & ATTRS_SKIP_ATIME)) {
  648: 		time_t file_atime = F_ATIME(file);
  649: 		if (flags & ATTRS_ACCURATE_TIME || !same_time(sxp->st.st_atime, 0, file_atime, 0)) {
  650: 			sx2.st.st_atime = file_atime;
  651: #ifdef ST_ATIME_NSEC
  652: 			sx2.st.ST_ATIME_NSEC = 0;
  653: #endif
  654: 			updated |= UPDATED_ATIME;
  655: 		}
  656: 	}
  657: 	if (updated & UPDATED_TIMES) {
  658: 		int ret = set_times(fname, &sx2.st);
  659: 		if (ret < 0) {
  660: 			rsyserr(FERROR_XFER, errno, "failed to set times on %s",
  661: 				full_fname(fname));
  662: 			goto cleanup;
  663: 		}
  664: 		if (ret > 0) { /* ret == 1 if symlink could not be set */
  665: 			updated &= ~UPDATED_TIMES;
  666: 			file->flags |= FLAG_TIME_FAILED;
  667: 		}
  668: 	}
  669: #ifdef SUPPORT_CRTIMES
  670: 	if (crtimes_ndx && !(flags & ATTRS_SKIP_CRTIME)) {
  671: 		time_t file_crtime = F_CRTIME(file);
  672: 		if (sxp->crtime == 0)
  673: 			sxp->crtime = get_create_time(fname);
  674: 		if (!same_time(sxp->crtime, 0L, file_crtime, 0L)
  675: 		 && set_create_time(fname, file_crtime) == 0)
  676: 			updated = 1;
  677: 	}
  678: #endif
  679: 
  680: #ifdef SUPPORT_ACLS
  681: 	/* It's OK to call set_acl() now, even for a dir, as the generator
  682: 	 * will enable owner-writability using chmod, if necessary.
  683: 	 * 
  684: 	 * If set_acl() changes permission bits in the process of setting
  685: 	 * an access ACL, it changes sxp->st.st_mode so we know whether we
  686: 	 * need to chmod(). */
  687: 	if (preserve_acls && !S_ISLNK(new_mode)) {
  688: 		if (set_acl(fname, file, sxp, new_mode) > 0)
  689: 			updated |= UPDATED_ACLS;
  690: 	}
  691: #endif
  692: 
  693: #ifdef HAVE_CHMOD
  694: 	if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
  695: 		int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode, ST_FLAGS(sxp->st));
  696: 		if (ret < 0) {
  697: 			rsyserr(FERROR_XFER, errno,
  698: 				"failed to set permissions on %s",
  699: 				full_fname(fname));
  700: 			goto cleanup;
  701: 		}
  702: 		if (ret == 0) /* ret == 1 if symlink could not be set */
  703: 			updated |= UPDATED_MODE;
  704: 	}
  705: #endif
  706: 
  707: #ifdef SUPPORT_FILEFLAGS
  708: 	if (preserve_fileflags && !S_ISLNK(sxp->st.st_mode)
  709: 	 && sxp->st.st_flags != F_FFLAGS(file)) {
  710: 		uint32 fileflags = F_FFLAGS(file);
  711: 		if (flags & ATTRS_DELAY_IMMUTABLE)
  712: 			fileflags &= ~ALL_IMMUTABLE;
  713: 		if (sxp->st.st_flags != fileflags
  714: 		 && !set_fileflags(fname, fileflags))
  715: 			goto cleanup;
  716: 		updated = 1;
  717: #ifdef SUPPORT_HFS_COMPRESSION
  718: 		int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), new_mode, fileflags);
  719: 		if (ret < 0) {
  720: 			rsyserr(FERROR_XFER, errno, "failed to set times on %s",
  721: 				full_fname(fname));
  722: 			goto cleanup;
  723: 		}
  724: 		if (ret != 0)
  725: 			file->flags |= FLAG_TIME_FAILED;
  726: #endif
  727: 	}
  728: #endif
  729: 
  730: 	if (INFO_GTE(NAME, 2) && flags & ATTRS_REPORT) {
  731: 		if (updated)
  732: 			rprintf(FCLIENT, "%s\n", fname);
  733: 		else
  734: 			rprintf(FCLIENT, "%s is uptodate\n", fname);
  735: 	}
  736:   cleanup:
  737: 	if (sxp == &sx2)
  738: 		free_stat_x(&sx2);
  739: 	return updated;
  740: }
  741: 
  742: /* This is only called for SIGINT, SIGHUP, and SIGTERM. */
  743: void sig_int(int sig_num)
  744: {
  745: 	called_from_signal_handler = 1;
  746: 
  747: 	/* KLUGE: if the user hits Ctrl-C while ssh is prompting
  748: 	 * for a password, then our cleanup's sending of a SIGUSR1
  749: 	 * signal to all our children may kill ssh before it has a
  750: 	 * chance to restore the tty settings (i.e. turn echo back
  751: 	 * on).  By sleeping for a short time, ssh gets a bigger
  752: 	 * chance to do the right thing.  If child processes are
  753: 	 * not ssh waiting for a password, then this tiny delay
  754: 	 * shouldn't hurt anything. */
  755: 	msleep(400);
  756: 
  757: 	/* If we're an rsync daemon listener (not a daemon server),
  758: 	 * we'll exit with status 0 if we received SIGTERM. */
  759: 	if (am_daemon && !am_server && sig_num == SIGTERM)
  760: 		exit_cleanup(0);
  761: 
  762: 	/* If the signal arrived on the server side (or for the receiver
  763: 	 * process on the client), we want to try to do a controlled shutdown
  764: 	 * that lets the client side (generator process) know what happened.
  765: 	 * To do this, we set a flag and let the normal process handle the
  766: 	 * shutdown.  We only attempt this if multiplexed IO is in effect and
  767: 	 * we didn't already set the flag. */
  768: 	if (!got_kill_signal && (am_server || am_receiver)) {
  769: 		got_kill_signal = sig_num;
  770: 		called_from_signal_handler = 0;
  771: 		return;
  772: 	}
  773: 
  774: 	exit_cleanup(RERR_SIGNAL);
  775: }
  776: 
  777: /* Finish off a file transfer: renaming the file and setting the file's
  778:  * attributes (e.g. permissions, ownership, etc.).  If the robust_rename()
  779:  * call is forced to copy the temp file and partialptr is both non-NULL and
  780:  * not an absolute path, we stage the file into the partial-dir and then
  781:  * rename it into place.  This returns 1 on success or 0 on failure. */
  782: int finish_transfer(const char *fname, const char *fnametmp,
  783: 		    const char *fnamecmp, const char *partialptr,
  784: 		    struct file_struct *file, int ok_to_set_time,
  785: 		    int overwriting_basis)
  786: {
  787: 	int ret;
  788: 	const char *temp_copy_name = partialptr && *partialptr != '/' ? partialptr : NULL;
  789: 
  790: 	if (inplace) {
  791: 		if (DEBUG_GTE(RECV, 1))
  792: 			rprintf(FINFO, "finishing %s\n", fname);
  793: 		fnametmp = fname;
  794: 		goto do_set_file_attrs;
  795: 	}
  796: 
  797: 	if (make_backups > 1 && overwriting_basis) {
  798: 		int ok = make_backup(fname, False);
  799: 		if (!ok)
  800: 			exit_cleanup(RERR_FILEIO);
  801: 		if (ok == 1 && fnamecmp == fname)
  802: 			fnamecmp = get_backup_name(fname);
  803: 	}
  804: 
  805: 	/* Change permissions before putting the file into place. */
  806: 	set_file_attrs(fnametmp, file, NULL, fnamecmp,
  807: 		       ATTRS_DELAY_IMMUTABLE
  808: 		       | (ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME));
  809: 
  810: 	/* move tmp file over real file */
  811: 	if (DEBUG_GTE(RECV, 1))
  812: 		rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
  813: 	ret = robust_rename(fnametmp, fname, temp_copy_name, file->mode);
  814: 	if (ret < 0) {
  815: 		rsyserr(FERROR_XFER, errno, "%s %s -> \"%s\"",
  816: 			ret == -2 ? "copy" : "rename",
  817: 			full_fname(fnametmp), fname);
  818: 		if (!partialptr || (ret == -2 && temp_copy_name)
  819: 		 || robust_rename(fnametmp, partialptr, NULL, file->mode) < 0)
  820: 			do_unlink(fnametmp);
  821: 		return 0;
  822: 	}
  823: 	if (ret == 0) {
  824: 		/* The file was moved into place (not copied), so it's done. */
  825: #ifdef SUPPORT_FILEFLAGS
  826: 		if (preserve_fileflags && F_FFLAGS(file) & ALL_IMMUTABLE)
  827: 			set_fileflags(fname, F_FFLAGS(file));
  828: #endif
  829: 		return 1;
  830: 	}
  831: 	/* The file was copied, so tweak the perms of the copied file.  If it
  832: 	 * was copied to partialptr, move it into its final destination. */
  833: 	fnametmp = temp_copy_name ? temp_copy_name : fname;
  834: 
  835:   do_set_file_attrs:
  836: 	set_file_attrs(fnametmp, file, NULL, fnamecmp,
  837: 		       ok_to_set_time ? ATTRS_ACCURATE_TIME : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME | ATTRS_SKIP_CRTIME);
  838: 
  839: 	if (temp_copy_name) {
  840: 		if (do_rename(fnametmp, fname) < 0) {
  841: 			rsyserr(FERROR_XFER, errno, "rename %s -> \"%s\"",
  842: 				full_fname(fnametmp), fname);
  843: 			return 0;
  844: 		}
  845: 		handle_partial_dir(temp_copy_name, PDIR_DELETE);
  846: 	}
  847: 	return 1;
  848: }
  849: 
  850: struct file_list *flist_for_ndx(int ndx, const char *fatal_error_loc)
  851: {
  852: 	struct file_list *flist = cur_flist;
  853: 
  854: 	if (!flist && !(flist = first_flist))
  855: 		goto not_found;
  856: 
  857: 	while (ndx < flist->ndx_start-1) {
  858: 		if (flist == first_flist)
  859: 			goto not_found;
  860: 		flist = flist->prev;
  861: 	}
  862: 	while (ndx >= flist->ndx_start + flist->used) {
  863: 		if (!(flist = flist->next))
  864: 			goto not_found;
  865: 	}
  866: 	return flist;
  867: 
  868:   not_found:
  869: 	if (fatal_error_loc) {
  870: 		int first, last;
  871: 		if (first_flist) {
  872: 			first = first_flist->ndx_start - 1;
  873: 			last = first_flist->prev->ndx_start + first_flist->prev->used - 1;
  874: 		} else {
  875: 			first = 0;
  876: 			last = -1;
  877: 		}
  878: 		rprintf(FERROR,
  879: 			"File-list index %d not in %d - %d (%s) [%s]\n",
  880: 			ndx, first, last, fatal_error_loc, who_am_i());
  881: 		exit_cleanup(RERR_PROTOCOL);
  882: 	}
  883: 	return NULL;
  884: }
  885: 
  886: const char *who_am_i(void)
  887: {
  888: 	if (am_dbadmin)
  889: 		return "rsyncdb";
  890: 	if (am_starting_up)
  891: 		return am_server ? "server" : "client";
  892: 	return am_sender ? "sender"
  893: 	     : am_generator ? "generator"
  894: 	     : am_receiver ? "receiver"
  895: 	     : "Receiver"; /* pre-forked receiver */
  896: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>