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

📄 main.c

📁 Rsync 3.0.5 source code
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	if (!dest_path || list_only)		return NULL;	if (daemon_filter_list.head) {		char *slash = strrchr(dest_path, '/');		if (slash && (slash[1] == '\0' || (slash[1] == '.' && slash[2] == '\0')))			*slash = '\0';		else			slash = NULL;		if ((*dest_path != '.' || dest_path[1] != '\0')		 && (check_filter(&daemon_filter_list, FLOG, dest_path, 0) < 0		  || check_filter(&daemon_filter_list, FLOG, dest_path, 1) < 0)) {			rprintf(FERROR, "skipping daemon-excluded destination \"%s\"\n",				dest_path);			exit_cleanup(RERR_FILESELECT);		}		if (slash)			*slash = '/';	}	/* See what currently exists at the destination. */	if ((statret = do_stat(dest_path, &st)) == 0) {		/* If the destination is a dir, enter it and use mode 1. */		if (S_ISDIR(st.st_mode)) {			if (!change_dir(dest_path, CD_NORMAL)) {				rsyserr(FERROR, errno, "change_dir#1 %s failed",					full_fname(dest_path));				exit_cleanup(RERR_FILESELECT);			}			return NULL;		}		if (file_total > 1) {			rprintf(FERROR,				"ERROR: destination must be a directory when"				" copying more than 1 file\n");			exit_cleanup(RERR_FILESELECT);		}		if (file_total == 1 && S_ISDIR(flist->files[0]->mode)) {			rprintf(FERROR,				"ERROR: cannot overwrite non-directory"				" with a directory\n");			exit_cleanup(RERR_FILESELECT);		}	} else if (errno != ENOENT) {		/* If we don't know what's at the destination, fail. */		rsyserr(FERROR, errno, "ERROR: cannot stat destination %s",			full_fname(dest_path));		exit_cleanup(RERR_FILESELECT);	}	cp = strrchr(dest_path, '/');	/* If we need a destination directory because the transfer is not	 * of a single non-directory or the user has requested one via a	 * destination path ending in a slash, create one and use mode 1. */	if (file_total > 1 || (cp && !cp[1])) {		/* Lop off the final slash (if any). */		if (cp && !cp[1])			*cp = '\0';		if (statret == 0) {			rprintf(FERROR,			    "ERROR: destination path is not a directory\n");			exit_cleanup(RERR_SYNTAX);		}		if (mkdir_defmode(dest_path) != 0) {			rsyserr(FERROR, errno, "mkdir %s failed",				full_fname(dest_path));			exit_cleanup(RERR_FILEIO);		}		if (flist->high >= flist->low		 && strcmp(flist->files[flist->low]->basename, ".") == 0)			flist->files[0]->flags |= FLAG_DIR_CREATED;		if (verbose)			rprintf(FINFO, "created directory %s\n", dest_path);		if (dry_run) {			/* Indicate that dest dir doesn't really exist. */			dry_run++;		}		if (!change_dir(dest_path, dry_run > 1 ? CD_SKIP_CHDIR : CD_NORMAL)) {			rsyserr(FERROR, errno, "change_dir#2 %s failed",				full_fname(dest_path));			exit_cleanup(RERR_FILESELECT);		}		return NULL;	}	/* Otherwise, we are writing a single file, possibly on top of an	 * existing non-directory.  Change to the item's parent directory	 * (if it has a path component), return the basename of the	 * destination file as the local name, and use mode 2. */	if (!cp)		return dest_path;	if (cp == dest_path)		dest_path = "/";	*cp = '\0';	if (!change_dir(dest_path, CD_NORMAL)) {		rsyserr(FERROR, errno, "change_dir#3 %s failed",			full_fname(dest_path));		exit_cleanup(RERR_FILESELECT);	}	*cp = '/';	return cp + 1;}/* This function checks on our alternate-basis directories.  If we're in * dry-run mode and the destination dir does not yet exist, we'll try to * tweak any dest-relative paths to make them work for a dry-run (the * destination dir must be in curr_dir[] when this function is called). * We also warn about any arg that is non-existent or not a directory. */static void check_alt_basis_dirs(void){	STRUCT_STAT st;	char **dir_p, *slash = strrchr(curr_dir, '/');	for (dir_p = basis_dir; *dir_p; dir_p++) {		if (dry_run > 1 && **dir_p != '/') {			int len = curr_dir_len + 1 + strlen(*dir_p) + 1;			char *new = new_array(char, len);			if (!new)				out_of_memory("check_alt_basis_dirs");			if (slash && strncmp(*dir_p, "../", 3) == 0) {			    /* We want to remove only one leading "../" prefix for			     * the directory we couldn't create in dry-run mode:			     * this ensures that any other ".." references get			     * evaluated the same as they would for a live copy. */			    *slash = '\0';			    pathjoin(new, len, curr_dir, *dir_p + 3);			    *slash = '/';			} else			    pathjoin(new, len, curr_dir, *dir_p);			*dir_p = new;		}		if (do_stat(*dir_p, &st) < 0) {			rprintf(FWARNING, "%s arg does not exist: %s\n",				dest_option, *dir_p);		} else if (!S_ISDIR(st.st_mode)) {			rprintf(FWARNING, "%s arg is not a dir: %s\n",				dest_option, *dir_p);		}	}}/* This is only called by the sender. */static void read_final_goodbye(int f_in){	int i, iflags, xlen;	uchar fnamecmp_type;	char xname[MAXPATHLEN];	if (protocol_version < 29)		i = read_int(f_in);	else {		i = read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,				       xname, &xlen);	}	if (i != NDX_DONE) {		rprintf(FERROR, "Invalid packet at end of run (%d) [%s]\n",			i, who_am_i());		exit_cleanup(RERR_PROTOCOL);	}}static void do_server_sender(int f_in, int f_out, int argc, char *argv[]){	struct file_list *flist;	char *dir = argv[0];	if (verbose > 2) {		rprintf(FINFO, "server_sender starting pid=%ld\n",			(long)getpid());	}	if (am_daemon && lp_write_only(module_id)) {		rprintf(FERROR, "ERROR: module is write only\n");		exit_cleanup(RERR_SYNTAX);		return;	}	if (am_daemon && lp_read_only(module_id) && remove_source_files) {		rprintf(FERROR,		    "ERROR: --remove-%s-files cannot be used with a read-only module\n",		    remove_source_files == 1 ? "source" : "sent");		exit_cleanup(RERR_SYNTAX);		return;	}	if (!relative_paths) {		if (!change_dir(dir, CD_NORMAL)) {			rsyserr(FERROR, errno, "change_dir#3 %s failed",				full_fname(dir));			exit_cleanup(RERR_FILESELECT);		}	}	argc--;	argv++;	if (argc == 0 && (recurse || xfer_dirs || list_only)) {		argc = 1;		argv--;		argv[0] = ".";	}	flist = send_file_list(f_out,argc,argv);	if (!flist || flist->used == 0)		exit_cleanup(0);	io_start_buffering_in(f_in);	send_files(f_in, f_out);	io_flush(FULL_FLUSH);	handle_stats(f_out);	if (protocol_version >= 24)		read_final_goodbye(f_in);	io_flush(FULL_FLUSH);	exit_cleanup(0);}static int do_recv(int f_in, int f_out, char *local_name){	int pid;	int exit_code = 0;	int error_pipe[2];	/* The receiving side mustn't obey this, or an existing symlink that	 * points to an identical file won't be replaced by the referent. */	copy_links = copy_dirlinks = copy_unsafe_links = 0;#ifdef SUPPORT_HARD_LINKS	if (preserve_hard_links && !inc_recurse)		match_hard_links(first_flist);#endif	if (fd_pair(error_pipe) < 0) {		rsyserr(FERROR, errno, "pipe failed in do_recv");		exit_cleanup(RERR_IPC);	}	io_flush(NORMAL_FLUSH);	if ((pid = do_fork()) == -1) {		rsyserr(FERROR, errno, "fork failed in do_recv");		exit_cleanup(RERR_IPC);	}	if (pid == 0) {		close(error_pipe[0]);		if (f_in != f_out)			close(f_out);		/* we can't let two processes write to the socket at one time */		io_end_multiplex_out();		/* set place to send errors */		set_msg_fd_out(error_pipe[1]);		io_start_buffering_out(error_pipe[1]);		recv_files(f_in, local_name);		io_flush(FULL_FLUSH);		handle_stats(f_in);		send_msg(MSG_DONE, "", 1, 0);		write_varlong(error_pipe[1], stats.total_read, 3);		io_flush(FULL_FLUSH);		/* Handle any keep-alive packets from the post-processing work		 * that the generator does. */		if (protocol_version >= 29) {			int iflags, xlen;			uchar fnamecmp_type;			char xname[MAXPATHLEN];			kluge_around_eof = -1;			/* This should only get stopped via a USR2 signal. */			read_ndx_and_attrs(f_in, &iflags, &fnamecmp_type,					   xname, &xlen);			rprintf(FERROR, "Invalid packet at end of run [%s]\n",				who_am_i());			exit_cleanup(RERR_PROTOCOL);		}		/* Finally, we go to sleep until our parent kills us with a		 * USR2 signal.  We sleep for a short time, as on some OSes		 * a signal won't interrupt a sleep! */		while (1)			msleep(20);	}	am_generator = 1;	io_end_multiplex_in();	if (write_batch && !am_server)		stop_write_batch();	close(error_pipe[1]);	if (f_in != f_out)		close(f_in);	io_start_buffering_out(f_out);	set_msg_fd_in(error_pipe[0]);	io_start_buffering_in(error_pipe[0]);#ifdef SUPPORT_HARD_LINKS	if (preserve_hard_links && inc_recurse) {		struct file_list *flist;		for (flist = first_flist; flist; flist = flist->next)			match_hard_links(flist);	}#endif	generate_files(f_out, local_name);	handle_stats(-1);	io_flush(FULL_FLUSH);	if (protocol_version >= 24) {		/* send a final goodbye message */		write_ndx(f_out, NDX_DONE);	}	io_flush(FULL_FLUSH);	set_msg_fd_in(-1);	kill(pid, SIGUSR2);	wait_process_with_flush(pid, &exit_code);	return exit_code;}static void do_server_recv(int f_in, int f_out, int argc, char *argv[]){	int exit_code;	struct file_list *flist;	char *local_name = NULL;	int save_verbose = verbose;	if (filesfrom_fd >= 0) {		/* We can't mix messages with files-from data on the socket,		 * so temporarily turn off verbose messages. */		verbose = 0;	}	if (verbose > 2) {		rprintf(FINFO, "server_recv(%d) starting pid=%ld\n",			argc, (long)getpid());	}	if (am_daemon && lp_read_only(module_id)) {		rprintf(FERROR,"ERROR: module is read only\n");		exit_cleanup(RERR_SYNTAX);		return;	}	if (argc > 0) {		char *dir = argv[0];		argc--;		argv++;		if (!am_daemon && !change_dir(dir, CD_NORMAL)) {			rsyserr(FERROR, errno, "change_dir#4 %s failed",				full_fname(dir));			exit_cleanup(RERR_FILESELECT);		}	}	if (protocol_version >= 30)		io_start_multiplex_in();	else		io_start_buffering_in(f_in);	recv_filter_list(f_in);	if (filesfrom_fd >= 0) {		/* We need to send the files-from names to the sender at the		 * same time that we receive the file-list from them, so we		 * need the IO routines to automatically write out the names		 * onto our f_out socket as we read the file-list.  This		 * avoids both deadlock and extra delays/buffers. */		io_set_filesfrom_fds(filesfrom_fd, f_out);		filesfrom_fd = -1;	}	flist = recv_file_list(f_in);	if (!flist) {		rprintf(FERROR,"server_recv: recv_file_list error\n");		exit_cleanup(RERR_FILESELECT);	}	if (inc_recurse && file_total == 1)		recv_additional_file_list(f_in);	verbose = save_verbose;	if (argc > 0)		local_name = get_local_name(flist,argv[0]);	/* Now that we know what our destination directory turned out to be,	 * we can sanitize the --link-/copy-/compare-dest args correctly. */	if (sanitize_paths) {		char **dir_p;		for (dir_p = basis_dir; *dir_p; dir_p++)			*dir_p = sanitize_path(NULL, *dir_p, NULL, curr_dir_depth, SP_DEFAULT);		if (partial_dir)			partial_dir = sanitize_path(NULL, partial_dir, NULL, curr_dir_depth, SP_DEFAULT);	}	check_alt_basis_dirs();	if (daemon_filter_list.head) {		char **dir_p;		struct filter_list_struct *elp = &daemon_filter_list;		for (dir_p = basis_dir; *dir_p; dir_p++) {			char *dir = *dir_p;			if (*dir == '/')				dir += module_dirlen;			if (check_filter(elp, FLOG, dir, 1) < 0)				goto options_rejected;		}		if (partial_dir && *partial_dir == '/'		 && check_filter(elp, FLOG, partial_dir + module_dirlen, 1) < 0) {		    options_rejected:			rprintf(FERROR,				"Your options have been rejected by the server.\n");			exit_cleanup(RERR_SYNTAX);		}	}	exit_code = do_recv(f_in, f_out, local_name);	exit_cleanup(exit_code);}int child_main(int argc, char *argv[]){	start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv);	return 0;}void start_server(int f_in, int f_out, int argc, char *argv[]){	set_nonblocking(f_in);	set_nonblocking(f_out);	io_set_sock_fds(f_in, f_out);	setup_protocol(f_out, f_in);	if (protocol_version >= 23)		io_start_multiplex_out();	if (am_sender) {		keep_dirlinks = 0; /* Must be disabled on the sender. */		if (need_messages_from_generator)			io_start_multiplex_in();		recv_filter_list(f_in);		do_server_sender(f_in, f_out, argc, argv);	} else		do_server_recv(f_in, f_out, argc, argv);	exit_cleanup(0);}/* * This is called once the connection has been negotiated.  It is used * for rsyncd, remote-shell, and local connections. */int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]){	struct file_list *flist = NULL;	int exit_code = 0, exit_code2 = 0;	char *local_name = NULL;	cleanup_child_pid = pid;	if (!read_batch) {		set_nonblocking(f_in);		set_nonblocking(f_out);	}	io_set_sock_fds(f_in, f_out);	setup_protocol(f_out,f_in);	/* We set our stderr file handle to blocking because ssh might have	 * set it to non-blocking.  This can be particularly troublesome if	 * stderr is a clone of stdout, because ssh would have set our stdout	 * to non-blocking at the same time (which can easily cause us to lose	 * output from our print statements).  This kluge shouldn't cause ssh	 * any problems for how we use it.  Note also that we delayed setting	 * this until after the above protocol setup so that we know for sure	 * that ssh is done twiddling its file descriptors.  */	set_blocking(STDERR_FILENO);	if (am_sender) {		keep_dirlinks = 0; /* Must be disabled on the sender. */		if (protocol_version >= 30)			io_start_multiplex_out();		else

⌨️ 快捷键说明

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