⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 generator.c

📁 Rsync 3.0.5 source code
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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-2008 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"extern int verbose;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 am_server;extern int am_daemon;extern int inc_recurse;extern int do_progress;extern int relative_paths;extern int implied_dirs;extern int keep_dirlinks;extern int preserve_acls;extern int preserve_xattrs;extern int preserve_links;extern int preserve_devices;extern int preserve_specials;extern int preserve_hard_links;extern int preserve_executability;extern int preserve_perms;extern int preserve_times;extern int uid_ndx;extern int gid_ndx;extern int delete_mode;extern int delete_before;extern int delete_during;extern int delete_after;extern int msgdone_cnt;extern int ignore_errors;extern int remove_source_files;extern int delay_updates;extern int update_only;extern int ignore_existing;extern int ignore_non_existing;extern int inplace;extern int append_mode;extern int make_backups;extern int csum_length;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 ignore_timeout;extern int protocol_version;extern int file_total;extern int fuzzy_basis;extern int always_checksum;extern int checksum_len;extern char *partial_dir;extern char *basis_dir[];extern int compare_dest;extern int copy_dest;extern int link_dest;extern int whole_file;extern int list_only;extern int read_batch;extern int safe_symlinks;extern long block_size; /* "long" because popt can't set an int32. */extern int unsort_ndx;extern int max_delete;extern int force_delete;extern int one_file_system;extern struct stats stats;extern dev_t filesystem_dev;extern mode_t orig_umask;extern uid_t our_uid;extern char *backup_dir;extern char *backup_suffix;extern int backup_suffix_len;extern struct file_list *cur_flist, *first_flist, *dir_flist;extern struct filter_list_struct daemon_filter_list;int ignore_perishable = 0;int non_perishable_cnt = 0;int maybe_ATTRS_REPORT = 0;static dev_t dev_zero;static int deletion_count = 0; /* used to implement --max-delete */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;/* For calling delete_item() and delete_dir_contents(). */#define DEL_NO_UID_WRITE 	(1<<0) /* file/dir has our uid w/o write perm */#define DEL_RECURSE		(1<<1) /* if dir, delete all contents */#define DEL_DIR_IS_EMPTY	(1<<2) /* internal delete_FUNCTIONS use only */#define DEL_FOR_FILE		(1<<3) /* making room for a replacement file */#define DEL_FOR_DIR		(1<<4) /* making room for a replacement dir */#define DEL_FOR_SYMLINK 	(1<<5) /* making room for a replacement symlink */#define DEL_FOR_DEVICE		(1<<6) /* making room for a replacement device */#define DEL_FOR_SPECIAL 	(1<<7) /* making room for a replacement special */#define DEL_MAKE_ROOM (DEL_FOR_FILE|DEL_FOR_DIR|DEL_FOR_SYMLINK|DEL_FOR_DEVICE|DEL_FOR_SPECIAL)enum nonregtype {    TYPE_DIR, TYPE_SPECIAL, TYPE_DEVICE, TYPE_SYMLINK};enum delret {    DR_SUCCESS = 0, DR_FAILURE, DR_AT_LIMIT, DR_NOT_EMPTY};/* Forward declarations. */static enum delret delete_dir_contents(char *fname, uint16 flags);#ifdef SUPPORT_HARD_LINKSstatic void handle_skipped_hlink(struct file_struct *file, int itemizing,				 enum logcode code, int f_out);#endifstatic int is_backup_file(char *fn){	int k = strlen(fn) - backup_suffix_len;	return k > 0 && strcmp(fn+k, backup_suffix) == 0;}/* Delete a file or directory.  If DEL_RECURSE is set in the flags, this will * delete recursively. * * Note that fbuf must point to a MAXPATHLEN buffer if the mode indicates it's * a directory! (The buffer is used for recursion, but returned unchanged.) */static enum delret delete_item(char *fbuf, uint16 mode, uint16 flags){	enum delret ret;	char *what;	int ok;	if (verbose > 2) {		rprintf(FINFO, "delete_item(%s) mode=%o flags=%d\n",			fbuf, (int)mode, (int)flags);	}	if (flags & DEL_NO_UID_WRITE)		do_chmod(fbuf, mode | S_IWUSR);	if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) {		int save_uid_ndx = uid_ndx;		/* This only happens on the first call to delete_item() since		 * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */		if (!uid_ndx)			uid_ndx = ++file_extra_cnt;		ignore_perishable = 1;		/* If DEL_RECURSE is not set, this just reports emptiness. */		ret = delete_dir_contents(fbuf, flags);		ignore_perishable = 0;		if (!save_uid_ndx) {			--file_extra_cnt;			uid_ndx = 0;		}		if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT)			goto check_ret;		/* OK: try to delete the directory. */	}	if (!(flags & DEL_MAKE_ROOM) && max_delete >= 0 && ++deletion_count > max_delete)		return DR_AT_LIMIT;	if (S_ISDIR(mode)) {		what = "rmdir";		ok = do_rmdir(fbuf) == 0;	} else if (make_backups > 0 && (backup_dir || !is_backup_file(fbuf))) {		what = "make_backup";		ok = make_backup(fbuf);	} else {		what = "unlink";		ok = robust_unlink(fbuf) == 0;	}	if (ok) {		if (!(flags & DEL_MAKE_ROOM))			log_delete(fbuf, mode);		ret = DR_SUCCESS;	} else {		if (S_ISDIR(mode) && errno == ENOTEMPTY) {			rprintf(FINFO, "cannot delete non-empty directory: %s\n",				fbuf);			ret = DR_NOT_EMPTY;		} else if (errno != ENOENT) {			rsyserr(FERROR, errno, "delete_file: %s(%s) failed",				what, fbuf);			ret = DR_FAILURE;		} else {			deletion_count--;			ret = DR_SUCCESS;		}	}  check_ret:	if (ret != DR_SUCCESS && flags & DEL_MAKE_ROOM) {		const char *desc;		switch (flags & DEL_MAKE_ROOM) {		case DEL_FOR_FILE: desc = "regular file"; break;		case DEL_FOR_DIR: desc = "directory"; break;		case DEL_FOR_SYMLINK: desc = "symlink"; break;		case DEL_FOR_DEVICE: desc = "device file"; break;		case DEL_FOR_SPECIAL: desc = "special file"; break;		default: exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE */		}		rprintf(FERROR_XFER, "could not make way for new %s: %s\n",			desc, fbuf);	}	return ret;}/* The directory is about to be deleted: if DEL_RECURSE is given, delete all * its contents, otherwise just checks for content.  Returns DR_SUCCESS or * DR_NOT_EMPTY.  Note that fname must point to a MAXPATHLEN buffer!  (The * buffer is used for recursion, but returned unchanged.) */static enum delret delete_dir_contents(char *fname, uint16 flags){	struct file_list *dirlist;	enum delret ret;	unsigned remainder;	void *save_filters;	int j, dlen;	char *p;	if (verbose > 3) {		rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n",			fname, flags);	}	dlen = strlen(fname);	save_filters = push_local_filters(fname, dlen);	non_perishable_cnt = 0;	dirlist = get_dirlist(fname, dlen, 0);	ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS;	if (!dirlist->used)		goto done;	if (!(flags & DEL_RECURSE)) {		ret = DR_NOT_EMPTY;		goto done;	}	p = fname + dlen;	if (dlen != 1 || *fname != '/')		*p++ = '/';	remainder = MAXPATHLEN - (p - fname);	/* We do our own recursion, so make delete_item() non-recursive. */	flags = (flags & ~(DEL_RECURSE|DEL_MAKE_ROOM|DEL_NO_UID_WRITE))	      | DEL_DIR_IS_EMPTY;	for (j = dirlist->used; j--; ) {		struct file_struct *fp = dirlist->files[j];		if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) {			if (verbose > 1) {				rprintf(FINFO,				    "mount point, %s, pins parent directory\n",				    f_name(fp, NULL));			}			ret = DR_NOT_EMPTY;			continue;		}		strlcpy(p, fp->basename, remainder);		if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid)			do_chmod(fname, fp->mode | S_IWUSR);		/* Save stack by recursing to ourself directly. */		if (S_ISDIR(fp->mode)) {			if (delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS)				ret = DR_NOT_EMPTY;		}		if (delete_item(fname, fp->mode, flags) != DR_SUCCESS)			ret = DR_NOT_EMPTY;	}	fname[dlen] = '\0';  done:	flist_free(dirlist);	pop_local_filters(save_filters);	if (ret == DR_NOT_EMPTY) {		rprintf(FINFO, "cannot delete non-empty directory: %s\n",			fname);	}	return ret;}static int start_delete_delay_temp(void){	char fnametmp[MAXPATHLEN];	int save_dry_run = dry_run;	dry_run = 0;	if (!get_tmpname(fnametmp, "deldelay")	 || (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;	int j, len, mode;	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) {	  invalid_data:		rprintf(FERROR, "ERROR: invalid data in delete-delay file.\n");		return -1;	}	past_space = strchr(bp, ' ') + 1;	len = j - read_pos - (past_space - bp) + 1; /* count the '\0' */	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;}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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -