2929 lines · 87.1 KB · C
RawDownload
/* * Routines that are exclusive to the generator process. * * Copyright (C) 1996-2000 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2002 Martin Pool <mbp@samba.org> * Copyright (C) 2003-2023 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 3 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, visit the http://fsf.org website. */ #include "rsync.h"#include "inums.h"#include "ifuncs.h" extern int dry_run;extern int do_xfers;extern int stdout_format_has_i;extern int logfile_format_has_i;extern int am_root;extern int operator_path_resolve;extern int am_server;extern int am_daemon;extern int inc_recurse;extern int relative_paths;extern int implied_dirs;extern int keep_dirlinks;extern int write_devices;extern int preserve_acls;extern int preserve_xattrs;extern int preserve_links;extern int preserve_devices;extern int preserve_specials;extern int drop_devices;extern int preserve_hard_links;extern int preserve_executability;extern int preserve_perms;extern int preserve_mtimes;extern int omit_dir_times;extern int omit_link_times;extern int delete_mode;extern int delete_before;extern int delete_during;extern int delete_after;extern int missing_args;extern int msgdone_cnt;extern int ignore_errors;extern int remove_source_files;extern int delay_updates;extern int update_only;extern int human_readable;extern int ignore_existing;extern int ignore_non_existing;extern int want_xattr_optim;extern int modify_window;extern int inplace;extern int append_mode;extern int make_backups;extern int csum_length;extern int xfer_sum_len;extern int ignore_times;extern int size_only;extern OFF_T max_size;extern OFF_T min_size;extern int io_error;extern int flist_eof;extern int allowed_lull;extern int sock_f_out;extern int protocol_version;extern int file_total;extern int fuzzy_basis;extern int always_checksum;extern int flist_csum_len;extern char *partial_dir;extern int alt_dest_type;extern int whole_file;extern int list_only;extern int read_batch;extern int write_batch;extern int safe_symlinks;extern int32 block_size;extern int unsort_ndx;extern int max_delete;extern int force_delete;extern int one_file_system;extern int skipped_deletes;extern dev_t filesystem_dev;extern mode_t orig_umask;extern uid_t our_uid;extern char *tmpdir;extern char *basis_dir[MAX_BASIS_DIRS+1];extern struct file_list *cur_flist, *first_flist, *dir_flist;extern filter_rule_list filter_list, daemon_filter_list; int maybe_ATTRS_REPORT = 0;int maybe_ATTRS_ACCURATE_TIME = 0; static dev_t dev_zero;static int deldelay_size = 0, deldelay_cnt = 0;static char *deldelay_buf = NULL;static int deldelay_fd = -1;static int loopchk_limit;static int dir_tweaking;static int symlink_timeset_failed_flags;static int need_retouch_dir_times;static int need_retouch_dir_perms;static const char *solo_file = NULL; /* Forward declarations. */#ifdef SUPPORT_HARD_LINKSstatic void handle_skipped_hlink(struct file_struct *file, int itemizing,				 enum logcode code, int f_out);#endif #define EARLY_DELAY_DONE_MSG() (!delay_updates)#define EARLY_DELETE_DONE_MSG() (!(delete_during == 2 || delete_after)) static int start_delete_delay_temp(void){	char fnametmp[MAXPATHLEN];	int save_dry_run = dry_run; 	dry_run = 0;	if (!get_tmpname(fnametmp, "deldelay", False)	 || (deldelay_fd = do_mkstemp(fnametmp, 0600)) < 0) {		rprintf(FINFO, "NOTE: Unable to create delete-delay temp file%s.\n",			inc_recurse ? "" : " -- switching to --delete-after");		delete_during = 0;		delete_after = !inc_recurse;		dry_run = save_dry_run;		return 0;	}	unlink(fnametmp);	dry_run = save_dry_run;	return 1;} static int flush_delete_delay(void){	if (deldelay_fd < 0 && !start_delete_delay_temp())		return 0;	if (write(deldelay_fd, deldelay_buf, deldelay_cnt) != deldelay_cnt) {		rsyserr(FERROR, errno, "flush of delete-delay buffer");		delete_during = 0;		delete_after = !inc_recurse;		close(deldelay_fd);		return 0;	}	deldelay_cnt = 0;	return 1;} static int remember_delete(struct file_struct *file, const char *fname, int flags){	int len; 	if (deldelay_cnt == deldelay_size && !flush_delete_delay())		return 0; 	if (flags & DEL_NO_UID_WRITE)		deldelay_buf[deldelay_cnt++] = '!'; 	while (1) {		len = snprintf(deldelay_buf + deldelay_cnt, deldelay_size - deldelay_cnt,			       "%x %s%c", (int)file->mode, fname, '\0');		if ((deldelay_cnt += len) <= deldelay_size)			break;		deldelay_cnt -= len;		if (!flush_delete_delay())			return 0;	} 	return 1;} static int read_delay_line(char *buf, int *flags_p){	static int read_pos = 0;	unsigned int mode;	int j, len;	char *bp, *past_space; 	while (1) {		for (j = read_pos; j < deldelay_cnt && deldelay_buf[j]; j++) {}		if (j < deldelay_cnt)			break;		if (deldelay_fd < 0) {			if (j > read_pos)				goto invalid_data;			return -1;		}		deldelay_cnt -= read_pos;		if (deldelay_cnt == deldelay_size)			goto invalid_data;		if (deldelay_cnt && read_pos) {			memmove(deldelay_buf, deldelay_buf + read_pos,				deldelay_cnt);		}		len = read(deldelay_fd, deldelay_buf + deldelay_cnt,			   deldelay_size - deldelay_cnt);		if (len == 0) {			if (deldelay_cnt) {				rprintf(FERROR, "ERROR: unexpected EOF in delete-delay file.\n");			}			return -1;		}		if (len < 0) {			rsyserr(FERROR, errno,				"reading delete-delay file");			return -1;		}		deldelay_cnt += len;		read_pos = 0;	} 	bp = deldelay_buf + read_pos;	if (*bp == '!') {		bp++;		*flags_p = DEL_NO_UID_WRITE;	} else		*flags_p = 0; 	if (sscanf(bp, "%x ", &mode) != 1) {		goto invalid_data;	}	past_space = strchr(bp, ' ');	if (!past_space) {		goto invalid_data;	}	past_space++;	/* Name length + NUL.  Computed from past_space directly: the old	 * `j - read_pos - (past_space - bp)` form was off by +1 when a '!'	 * prefix had advanced bp past read_pos, over-reading deldelay_buf	 * by one byte on a buffer-filling final entry. */	len = (deldelay_buf + j) - past_space + 1;	read_pos = j + 1; 	if (len > MAXPATHLEN) {		rprintf(FERROR, "ERROR: filename too long in delete-delay file.\n");		return -1;	} 	/* The caller needs the name in a MAXPATHLEN buffer, so we copy it	 * instead of returning a pointer to our buffer. */	memcpy(buf, past_space, len); 	return mode; invalid_data:	rprintf(FERROR, "ERROR: invalid data in delete-delay file.\n");	return -1;} static void do_delayed_deletions(char *delbuf){	int mode, flags; 	if (deldelay_fd >= 0) {		if (deldelay_cnt && !flush_delete_delay())			return;		lseek(deldelay_fd, 0, 0);	}	while ((mode = read_delay_line(delbuf, &flags)) >= 0)		delete_item(delbuf, mode, flags | DEL_RECURSE);	if (deldelay_fd >= 0)		close(deldelay_fd);} /* This function is used to implement per-directory deletion, and is used by * all the --delete-WHEN options.  Note that the fbuf pointer must point to a * MAXPATHLEN buffer with the name of the directory in it (the functions we * call will append names onto the end, but the old dir value will be restored * on exit). */static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t fs_dev){	static int already_warned = 0;	static struct hashtable *dev_tbl;	struct file_list *dirlist;	char delbuf[MAXPATHLEN];	int dlen, i; 	if (!fbuf) {		change_local_filter_dir(NULL, 0, 0);		return;	} 	if (DEBUG_GTE(DEL, 2))		rprintf(FINFO, "delete_in_dir(%s)\n", fbuf); 	if (allowed_lull)		maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH); 	if (io_error & IOERR_GENERAL && !ignore_errors) {		if (already_warned)			return;		rprintf(FINFO,			"IO error encountered -- skipping file deletion\n");		already_warned = 1;		return;	} 	dlen = strlen(fbuf);	change_local_filter_dir(fbuf, dlen, F_DEPTH(file)); 	if (one_file_system) {		if (!dev_tbl)			dev_tbl = hashtable_create(16, HT_KEY64);		if (file->flags & FLAG_TOP_DIR) {			hashtable_find(dev_tbl, fs_dev+1, "");			filesystem_dev = fs_dev;		} else if (filesystem_dev != fs_dev) {			if (!hashtable_find(dev_tbl, fs_dev+1, NULL))				return;			filesystem_dev = fs_dev; /* it's a prior top-dir dev */		}	} 	dirlist = get_dirlist(fbuf, dlen, 0); 	/* If an item in dirlist is not found in flist, delete it	 * from the filesystem. */	for (i = dirlist->used; i--; ) {		struct file_struct *fp = dirlist->files[i];		if (!F_IS_ACTIVE(fp))			continue;		if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {			if (INFO_GTE(MOUNT, 1))				rprintf(FINFO, "cannot delete mount point: %s\n",					f_name(fp, NULL));			continue;		}		/* Here we want to match regardless of file type.  Replacement		 * of a file with one of another type is handled separately by		 * a delete_item call with a DEL_MAKE_ROOM flag. */		if (flist_find_ignore_dirness(cur_flist, fp) < 0) {			int flags = DEL_RECURSE;			if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US)				flags |= DEL_NO_UID_WRITE;			f_name(fp, delbuf);			if (delete_during == 2) {				if (!remember_delete(fp, delbuf, flags))					break;			} else				delete_item(delbuf, fp->mode, flags);		}	} 	flist_free(dirlist);} /* This deletes any files on the receiving side that are not present on the * sending side.  This is used by --delete-before and --delete-after. */static void do_delete_pass(void){	char fbuf[MAXPATHLEN];	STRUCT_STAT st;	int j; 	/* dry_run is incremented when the destination doesn't exist yet. */	if (dry_run > 1 || list_only)		return; 	for (j = 0; j < cur_flist->used; j++) {		struct file_struct *file = cur_flist->sorted[j]; 		if (!F_IS_ACTIVE(file))			continue; 		f_name(file, fbuf); 		if (!(file->flags & FLAG_CONTENT_DIR)) {			change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(file));			continue;		} 		if (DEBUG_GTE(DEL, 1) && file->flags & FLAG_TOP_DIR)			rprintf(FINFO, "deleting in %s\n", fbuf); 		if (link_stat(fbuf, &st, keep_dirlinks) < 0		 || !S_ISDIR(st.st_mode))			continue; 		delete_in_dir(fbuf, file, st.st_dev);	}	delete_in_dir(NULL, NULL, dev_zero); 	if (INFO_GTE(FLIST, 2) && !am_server)		rprintf(FINFO, "                    \r");} static inline int mtime_differs(STRUCT_STAT *stp, struct file_struct *file){#ifdef ST_MTIME_NSEC	return !same_time(stp->st_mtime, stp->ST_MTIME_NSEC, file->modtime, F_MOD_NSEC_or_0(file));#else	return !same_time(stp->st_mtime, 0, file->modtime, 0);#endif} static inline int any_time_differs(stat_x *sxp, struct file_struct *file, UNUSED(const char *fname)){	int differs = mtime_differs(&sxp->st, file);#ifdef SUPPORT_CRTIMES	if (!differs && crtimes_ndx) {		if (sxp->crtime == 0)			sxp->crtime = get_create_time(fname, &sxp->st);		differs = !same_time(sxp->crtime, 0, F_CRTIME(file), 0);	}#endif	return differs;} static inline int perms_differ(struct file_struct *file, stat_x *sxp){	if (preserve_perms)		return !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS); 	if (preserve_executability)		return (sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0); 	return 0;} static inline int ownership_differs(struct file_struct *file, stat_x *sxp){	if (am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file))		return 1; 	if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file))		return 1; 	return 0;} #ifdef SUPPORT_ACLSstatic inline int acls_differ(const char *fname, struct file_struct *file, stat_x *sxp){	if (preserve_acls) {		if (!ACL_READY(*sxp))			get_acl(fname, sxp);		if (set_acl(NULL, file, sxp, file->mode))			return 1;	} 	return 0;}#endif #ifdef SUPPORT_XATTRSstatic inline int xattrs_differ(const char *fname, struct file_struct *file, stat_x *sxp){	if (preserve_xattrs) {		if (!XATTR_READY(*sxp))			get_xattr(fname, -1, sxp);		if (xattr_diff(file, sxp, 0))			return 1;	} 	return 0;}#endif int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp){	if (S_ISLNK(file->mode)) {#ifdef CAN_SET_SYMLINK_TIMES		if (preserve_mtimes && !omit_link_times && any_time_differs(sxp, file, fname))			return 0;#endif#ifdef CAN_CHMOD_SYMLINK		if (perms_differ(file, sxp))			return 0;#endif#ifdef CAN_CHOWN_SYMLINK		if (ownership_differs(file, sxp))			return 0;#endif#if defined SUPPORT_ACLS && 0 /* no current symlink-ACL support */		if (acls_differ(fname, file, sxp))			return 0;#endif#if defined SUPPORT_XATTRS && !defined NO_SYMLINK_XATTRS		if (xattrs_differ(fname, file, sxp))			return 0;#endif	} else {		if (preserve_mtimes && any_time_differs(sxp, file, fname))			return 0;		if (perms_differ(file, sxp))

Lines 1–500 of 2929.