int read_ndx_and_attrs(int f_in, int f_out, int *iflag_ptr, uchar *type_ptr, char *buf, int *len_ptr) { int len, iflags = 0; struct file_list *flist; uchar fnamecmp_type = FNAMECMP_FNAME; int ndx; read_loop: while (1) { ndx = read_ndx(f_in); if (ndx >= 0) break; if (ndx == NDX_DONE) return ndx; if (ndx == NDX_DEL_STATS) { read_del_stats(f_in); if (am_sender && am_server) write_del_stats(f_out); continue; } if (!inc_recurse || am_sender) { int last; if (first_flist) last = first_flist->prev->ndx_start + first_flist->prev->used - 1; else last = -1; rprintf(FERROR, "Invalid file index: %d (%d - %d) [%s]\n", ndx, NDX_DONE, last, who_am_i()); exit_cleanup(RERR_PROTOCOL); } if (ndx == NDX_FLIST_EOF) { flist_eof = 1; if (DEBUG_GTE(FLIST, 3)) rprintf(FINFO, "[%s] flist_eof=1\n", who_am_i()); write_int(f_out, NDX_FLIST_EOF); continue; } ndx = NDX_FLIST_OFFSET - ndx; if (ndx < 0 || ndx >= dir_flist->used) { ndx = NDX_FLIST_OFFSET - ndx; rprintf(FERROR, "Invalid dir index: %d (%d - %d) [%s]\n", ndx, NDX_FLIST_OFFSET, NDX_FLIST_OFFSET - dir_flist->used + 1, who_am_i()); exit_cleanup(RERR_PROTOCOL); } if (DEBUG_GTE(FLIST, 2)) { rprintf(FINFO, "[%s] receiving flist for dir %d\n", who_am_i(), ndx); } /* Send all the data we read for this flist to the generator. */ start_flist_forward(ndx); flist = recv_file_list(f_in); flist->parent_ndx = ndx; stop_flist_forward(); } iflags = protocol_version >= 29 ? read_shortint(f_in) : ITEM_TRANSFER | ITEM_MISSING_DATA; /* Support the protocol-29 keep-alive style. */ if (protocol_version < 30 && ndx == cur_flist->used && iflags == ITEM_IS_NEW) { if (am_sender) maybe_send_keepalive(time(NULL), MSK_ALLOW_FLUSH); goto read_loop; } flist = flist_for_ndx(ndx, "read_ndx_and_attrs"); if (flist != cur_flist) { cur_flist = flist; if (am_sender) { file_old_total = cur_flist->used; for (flist = first_flist; flist != cur_flist; flist = flist->next) file_old_total += flist->used; } } if (iflags & ITEM_BASIS_TYPE_FOLLOWS) fnamecmp_type = read_byte(f_in); *type_ptr = fnamecmp_type; if (iflags & ITEM_XNAME_FOLLOWS) { if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0) exit_cleanup(RERR_PROTOCOL); } else { *buf = '\0'; len = -1; } *len_ptr = len; if (iflags & ITEM_TRANSFER) { int i = ndx - cur_flist->ndx_start; if (i < 0 || !S_ISREG(cur_flist->files[i]->mode)) { rprintf(FERROR, "received request to transfer non-regular file: %d [%s]\n", ndx, who_am_i()); exit_cleanup(RERR_PROTOCOL); } } *iflag_ptr = iflags; return ndx; }
/* * 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 status = 0, status2 = 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); if (protocol_version >= 23 && !read_batch) io_start_multiplex_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. */ io_start_buffering_out(); if (!filesfrom_host) set_msg_fd_in(f_in); send_filter_list(f_out); if (filesfrom_host) filesfrom_fd = f_in; if (write_batch && !am_server) start_write_batch(f_out); flist = send_file_list(f_out, argc, argv); set_msg_fd_in(-1); if (verbose > 3) rprintf(FINFO,"file list sent\n"); the_file_list = flist; io_flush(NORMAL_FLUSH); send_files(flist,f_out,f_in); io_flush(FULL_FLUSH); handle_stats(-1); if (protocol_version >= 24) read_final_goodbye(f_in, f_out); if (pid != -1) { if (verbose > 3) rprintf(FINFO,"client_run waiting on %d\n", (int) pid); io_flush(FULL_FLUSH); wait_process(pid, &status); } output_summary(); io_flush(FULL_FLUSH); exit_cleanup(status); } if (need_messages_from_generator && !read_batch) io_start_multiplex_out(); if (argc == 0) list_only |= 1; send_filter_list(read_batch ? -1 : f_out); if (filesfrom_fd >= 0) { io_set_filesfrom_fds(filesfrom_fd, f_out); filesfrom_fd = -1; } if (write_batch && !am_server) start_write_batch(f_in); flist = recv_file_list(f_in); the_file_list = flist; if (flist && flist->count > 0) { local_name = get_local_name(flist, argv[0]); status2 = do_recv(f_in, f_out, flist, local_name); } else { handle_stats(-1); output_summary(); } if (pid != -1) { if (verbose > 3) rprintf(FINFO,"client_run2 waiting on %d\n", (int) pid); io_flush(FULL_FLUSH); wait_process(pid, &status); } return MAX(status, status2); }
int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr, char *buf, int *len_ptr) { int len, iflags = 0; struct file_list *flist; uchar fnamecmp_type = FNAMECMP_FNAME; int ndx, save_verbose = verbose; read_loop: while (1) { ndx = read_ndx(f_in); if (ndx >= 0) break; if (ndx == NDX_DONE) return ndx; if (!inc_recurse || am_sender) { int last; if (first_flist) last = first_flist->prev->ndx_start + first_flist->prev->used - 1; else last = -1; rprintf(FERROR, "Invalid file index: %d (%d - %d) [%s]\n", ndx, NDX_DONE, last, who_am_i()); exit_cleanup(RERR_PROTOCOL); } if (ndx == NDX_FLIST_EOF) { flist_eof = 1; send_msg(MSG_FLIST_EOF, "", 0, 0); continue; } ndx = NDX_FLIST_OFFSET - ndx; if (ndx < 0 || ndx >= dir_flist->used) { ndx = NDX_FLIST_OFFSET - ndx; rprintf(FERROR, "Invalid dir index: %d (%d - %d) [%s]\n", ndx, NDX_FLIST_OFFSET, NDX_FLIST_OFFSET - dir_flist->used + 1, who_am_i()); exit_cleanup(RERR_PROTOCOL); } /* Send everything read from f_in to msg_fd_out. */ if (verbose > 3) { rprintf(FINFO, "[%s] receiving flist for dir %d\n", who_am_i(), ndx); } verbose = 0; send_msg_int(MSG_FLIST, ndx); start_flist_forward(f_in); flist = recv_file_list(f_in); flist->parent_ndx = ndx; stop_flist_forward(); verbose = save_verbose; } iflags = protocol_version >= 29 ? read_shortint(f_in) : ITEM_TRANSFER | ITEM_MISSING_DATA; /* Support the protocol-29 keep-alive style. */ if (protocol_version < 30 && ndx == cur_flist->used && iflags == ITEM_IS_NEW) { if (am_sender) maybe_send_keepalive(); goto read_loop; } cur_flist = flist_for_ndx(ndx, "read_ndx_and_attrs"); if (iflags & ITEM_BASIS_TYPE_FOLLOWS) fnamecmp_type = read_byte(f_in); *type_ptr = fnamecmp_type; if (iflags & ITEM_XNAME_FOLLOWS) { if ((len = read_vstring(f_in, buf, MAXPATHLEN)) < 0) exit_cleanup(RERR_PROTOCOL); } else { *buf = '\0'; len = -1; } *len_ptr = len; if (iflags & ITEM_TRANSFER) { int i = ndx - cur_flist->ndx_start; struct file_struct *file = cur_flist->files[i]; if (i < 0 || !(S_ISREG(file->mode) || (copy_devices && IS_DEVICE(file->mode)))) { rprintf(FERROR, "received request to transfer non-regular file: %d [%s]\n", ndx, who_am_i()); exit_cleanup(RERR_PROTOCOL); } } *iflag_ptr = iflags; return ndx; }
static void do_server_recv(int f_in, int f_out, int argc,char *argv[]) { int status; struct file_list *flist; char *local_name = NULL; char *dir = 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) { dir = argv[0]; argc--; argv++; if (!am_daemon && !push_dir(dir)) { rsyserr(FERROR, errno, "push_dir#4 %s failed", full_fname(dir)); exit_cleanup(RERR_FILESELECT); } } io_start_buffering_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); verbose = save_verbose; if (!flist) { rprintf(FERROR,"server_recv: recv_file_list error\n"); exit_cleanup(RERR_FILESELECT); } the_file_list = flist; if (argc > 0) { if (strcmp(dir,".")) { argv[0] += strlen(dir); if (argv[0][0] == '/') argv[0]++; } local_name = get_local_name(flist,argv[0]); } status = do_recv(f_in,f_out,flist,local_name); exit_cleanup(status); }