X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/595251de24388fdfbac120daf9f3a748745ef7c5..ac98cd98e361d7703a9e8411aa7102613a6fb025:/main.c diff --git a/main.c b/main.c index e8b5efd3..3acdfd31 100644 --- a/main.c +++ b/main.c @@ -40,8 +40,8 @@ extern int kluge_around_eof; extern int do_stats; extern int log_got_error; extern int module_id; -extern int orig_umask; extern int copy_links; +extern int copy_dirlinks; extern int keep_dirlinks; extern int preserve_hard_links; extern int protocol_version; @@ -62,6 +62,7 @@ extern char *shell_cmd; extern char *batch_name; int local_server = 0; +mode_t orig_umask = 0; struct file_list *the_file_list; /* There's probably never more than at most 2 outstanding child processes, @@ -88,14 +89,14 @@ static int64 total_read, total_written; static void show_malloc_stats(void); /* Works like waitpid(), but if we already harvested the child pid in our - * sigchld_handler(), we succeed instead of returning an error. */ + * remember_children(), we succeed instead of returning an error. */ pid_t wait_process(pid_t pid, int *status_ptr, int flags) { pid_t waited_pid = waitpid(pid, status_ptr, flags); if (waited_pid == -1 && errno == ECHILD) { /* Status of requested child no longer available: check to - * see if it was processed by sigchld_handler(). */ + * see if it was processed by remember_children(). */ int cnt; for (cnt = 0; cnt < MAXCHILDPROCS; cnt++) { if (pid == pid_stat_table[cnt].pid) { @@ -437,8 +438,8 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char *path, /* The receiving side operates in one of two modes: * - * 1. it enters a directory and receives one or more files, placing them - * according to their names in the file-list. + * 1. it receives any number of files into a destination directory, + * placing them according to their names in the file-list. * * 2. it receives a single file and saves it using the name in the * destination path instead of its file-list name. This requires a @@ -457,7 +458,7 @@ static char *get_local_name(struct file_list *flist, char *dest_path) flist->count, NS(dest_path)); } - if (!dest_path) + if (!dest_path || list_only) return NULL; /* If the destination path refers to an existing directory, enter @@ -479,6 +480,17 @@ static char *get_local_name(struct file_list *flist, char *dest_path) " copying more than 1 file\n"); exit_cleanup(RERR_FILESELECT); } + /* Caution: flist->count could be 0! */ + if (flist->count == 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) { + rsyserr(FERROR, errno, "cannot stat destination %s", + full_fname(dest_path)); + exit_cleanup(RERR_FILESELECT); } cp = strrchr(dest_path, '/'); @@ -491,13 +503,11 @@ static char *get_local_name(struct file_list *flist, char *dest_path) if (cp && !cp[1]) *cp = '\0'; - umask(orig_umask); - if (do_mkdir(dest_path, 0777) != 0) { + if (mkdir_defmode(dest_path) != 0) { rsyserr(FERROR, errno, "mkdir %s failed", full_fname(dest_path)); exit_cleanup(RERR_FILEIO); } - umask(0); if (verbose) rprintf(FINFO, "created directory %s\n", dest_path); @@ -627,7 +637,7 @@ static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name) /* 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 = 0; + copy_links = copy_dirlinks = 0; if (preserve_hard_links) init_hard_links(); @@ -960,12 +970,12 @@ static int start_client(int argc, char *argv[]) return rc; if (!read_batch) { /* for read_batch, NO source is specified */ - argc--; shell_path = check_for_hostspec(argv[0], &shell_machine, &rsync_port); if (shell_path) { /* source is remote */ char *dummy1; int dummy2; - if (argc && check_for_hostspec(argv[argc], &dummy1, &dummy2)) { + if (--argc + && check_for_hostspec(argv[argc], &dummy1, &dummy2)) { rprintf(FERROR, "The source and destination cannot both be remote.\n"); exit_cleanup(RERR_SYNTAX); @@ -990,12 +1000,14 @@ static int start_client(int argc, char *argv[]) } else { /* source is local, check dest arg */ am_sender = 1; - if (argc < 1) { /* destination required */ - usage(FERROR); - exit_cleanup(RERR_SYNTAX); + if (argc > 1) + p = argv[--argc]; + else { + p = "."; + list_only = 1; } - shell_path = check_for_hostspec(argv[argc], &shell_machine, &rsync_port); + shell_path = check_for_hostspec(p, &shell_machine, &rsync_port); if (shell_path && filesfrom_host && *filesfrom_host && strcmp(filesfrom_host, shell_machine) != 0) { rprintf(FERROR, @@ -1010,7 +1022,7 @@ static int start_client(int argc, char *argv[]) exit_cleanup(RERR_SYNTAX); } shell_machine = NULL; - shell_path = argv[argc]; + shell_path = p; } else if (rsync_port) { if (!shell_cmd) { return start_socket_client(shell_machine, @@ -1093,7 +1105,7 @@ static RETSIGTYPE sigusr2_handler(UNUSED(int val)) _exit(0); } -static RETSIGTYPE sigchld_handler(UNUSED(int val)) +RETSIGTYPE remember_children(UNUSED(int val)) { #ifdef WNOHANG int cnt, status; @@ -1115,7 +1127,7 @@ static RETSIGTYPE sigchld_handler(UNUSED(int val)) } #endif #ifndef HAVE_SIGACTION - signal(SIGCHLD, sigchld_handler); + signal(SIGCHLD, remember_children); #endif } @@ -1186,7 +1198,7 @@ int main(int argc,char *argv[]) #endif SIGACTMASK(SIGUSR1, sigusr1_handler); SIGACTMASK(SIGUSR2, sigusr2_handler); - SIGACTMASK(SIGCHLD, sigchld_handler); + SIGACTMASK(SIGCHLD, remember_children); #ifdef MAINTAINER_MODE SIGACTMASK(SIGSEGV, rsync_panic_handler); SIGACTMASK(SIGFPE, rsync_panic_handler); @@ -1206,7 +1218,7 @@ int main(int argc,char *argv[]) /* we set a 0 umask so that correct file permissions can be * carried across */ - orig_umask = (int)umask(0); + orig_umask = umask(0); #if defined CONFIG_LOCALE && defined HAVE_SETLOCALE setlocale(LC_CTYPE, ""); @@ -1229,6 +1241,9 @@ int main(int argc,char *argv[]) /* Ignore SIGPIPE; we consistently check error codes and will * see the EPIPE. */ SIGACTION(SIGPIPE, SIG_IGN); +#ifdef SIGXFSZ + SIGACTION(SIGXFSZ, SIG_IGN); +#endif /* Initialize push_dir here because on some old systems getcwd * (implemented by forking "pwd" and reading its output) doesn't