X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/23e43fceeb918374e99005c7d1553ded436d6bab..e1b3d5c4be46ee0b17a98aa48cb7cb152c4a008b:/rsync.c diff --git a/rsync.c b/rsync.c index 6644f141..beb3d37f 100644 --- a/rsync.c +++ b/rsync.c @@ -51,6 +51,7 @@ extern int am_root; extern int relative_paths; extern int io_timeout; extern int io_error; +extern struct stats stats; /* free a sums struct @@ -74,6 +75,7 @@ static int delete_file(char *fname) extern int force_delete; STRUCT_STAT st; int ret; + extern int recurse; if (do_unlink(fname) == 0 || errno == ENOENT) return 0; @@ -93,7 +95,8 @@ static int delete_file(char *fname) } if (do_rmdir(fname) == 0 || errno == ENOENT) return 0; - if (!force_delete || (errno != ENOTEMPTY && errno != EEXIST)) { + if (!force_delete || !recurse || + (errno != ENOTEMPTY && errno != EEXIST)) { rprintf(FERROR,"rmdir(%s) : %s\n", fname, strerror(errno)); return -1; } @@ -147,7 +150,6 @@ static void send_sums(struct sum_struct *s,int f_out) write_int(f_out,s->sums[i].sum1); write_buf(f_out,s->sums[i].sum2,csum_length); } - write_flush(f_out); } @@ -267,6 +269,7 @@ static int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st, { int updated = 0; STRUCT_STAT st2; + extern int am_daemon; if (dry_run) return 0; @@ -300,8 +303,9 @@ static int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st, } #endif - if ((am_root && preserve_uid && st->st_uid != file->uid) || - (preserve_gid && st->st_gid != file->gid)) { + if ((am_root || !am_daemon) && + ((am_root && preserve_uid && st->st_uid != file->uid) || + (preserve_gid && st->st_gid != file->gid))) { if (do_lchown(fname, (am_root&&preserve_uid)?file->uid:-1, preserve_gid?file->gid:-1) != 0) { @@ -352,7 +356,11 @@ static int skip_file(char *fname, /* use a larger block size for really big files */ int adapt_block_size(struct file_struct *file, int bsize) { - int ret = file->length / (10000); /* rough heuristic */ + int ret; + + if (bsize != BLOCK_SIZE) return bsize; + + ret = file->length / (10000); /* rough heuristic */ ret = ret & ~15; /* multiple of 16 */ if (ret < bsize) ret = bsize; if (ret > CHUNK_SIZE/2) ret = CHUNK_SIZE/2; @@ -526,7 +534,6 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out) write_int(f_out,i); send_sums(s,f_out); - write_flush(f_out); close(fd); if (buf) unmap_file(buf); @@ -557,6 +564,7 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname) if (verbose > 3) rprintf(FINFO,"data recv %d at %d\n",i,(int)offset); + stats.literal_data += i; sum_update(data,i); if (fd != -1 && write_file(fd,data,i) != i) { @@ -571,6 +579,8 @@ static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname) if (i == count-1 && remainder != 0) len = remainder; + stats.matched_data += len; + if (verbose > 3) rprintf(FINFO,"chunk[%d] of size %d at %d offset=%d\n", i,len,(int)offset2,(int)offset); @@ -636,11 +646,7 @@ static void add_delete_entry(struct file_struct *file) { if (dlist_len == dlist_alloc_len) { dlist_alloc_len += 1024; - if (!delete_list) { - delete_list = (struct delete_list *)malloc(sizeof(delete_list[0])*dlist_alloc_len); - } else { - delete_list = (struct delete_list *)realloc(delete_list, sizeof(delete_list[0])*dlist_alloc_len); - } + delete_list = (struct delete_list *)Realloc(delete_list, sizeof(delete_list[0])*dlist_alloc_len); if (!delete_list) out_of_memory("add_delete_entry"); } @@ -694,7 +700,8 @@ static void delete_files(struct file_list *flist) if (!S_ISDIR(flist->files[j]->mode) || !(flist->files[j]->flags & FLAG_DELETE)) continue; - if (delete_already_done(flist, j)) continue; + if (remote_version < 19 && + delete_already_done(flist, j)) continue; name = strdup(f_name(flist->files[j])); @@ -708,7 +715,8 @@ static void delete_files(struct file_list *flist) for (i=local_file_list->count-1;i>=0;i--) { if (!local_file_list->files[i]->basename) continue; - if (S_ISDIR(local_file_list->files[i]->mode)) + if (remote_version < 19 && + S_ISDIR(local_file_list->files[i]->mode)) add_delete_entry(local_file_list->files[i]); if (-1 == flist_find(flist,local_file_list->files[i])) { delete_one(local_file_list->files[i]); @@ -739,216 +747,237 @@ void sig_int(void) } -int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) -{ - int fd1,fd2; - STRUCT_STAT st; - char *fname; - char fnametmp[MAXPATHLEN]; - struct map_struct *buf; - int i; - struct file_struct *file; - int phase=0; - int recv_ok; - if (verbose > 2) { - rprintf(FINFO,"recv_files(%d) starting\n",flist->count); - } - if (recurse && delete_mode && !local_name && flist->count>0) { - delete_files(flist); - } +static int get_tmpname(char *fnametmp, char *fname) +{ + char *f; + + /* open tmp file */ + if (tmpdir) { + f = strrchr(fname,'/'); + if (f == NULL) + f = fname; + else + f++; + if (strlen(tmpdir)+strlen(f)+10 > MAXPATHLEN) { + rprintf(FERROR,"filename too long\n"); + return 0; + } + slprintf(fnametmp,MAXPATHLEN-1, "%s/.%s.XXXXXX",tmpdir,f); + return 1; + } - while (1) - { - i = read_int(f_in); - if (i == -1) { - if (phase==0 && remote_version >= 13) { - phase++; - csum_length = SUM_LENGTH; - if (verbose > 2) - rprintf(FINFO,"recv_files phase=%d\n",phase); - write_int(f_gen,-1); - write_flush(f_gen); - continue; + f = strrchr(fname,'/'); + + if (strlen(fname)+9 > MAXPATHLEN) { + rprintf(FERROR,"filename too long\n"); + return 0; } - break; - } - file = flist->files[i]; - fname = f_name(file); + if (f) { + *f = 0; + slprintf(fnametmp,MAXPATHLEN-1,"%s/.%s.XXXXXX", + fname,f+1); + *f = '/'; + } else { + slprintf(fnametmp,MAXPATHLEN-1,".%s.XXXXXX",fname); + } - if (local_name) - fname = local_name; + return 1; +} - if (dry_run) { - if (!am_server && verbose) - printf("%s\n",fname); - continue; - } +int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) +{ + int fd1,fd2; + STRUCT_STAT st; + char *fname; + char fnametmp[MAXPATHLEN]; + struct map_struct *buf; + int i; + struct file_struct *file; + int phase=0; + int recv_ok; + + if (verbose > 2) { + rprintf(FINFO,"recv_files(%d) starting\n",flist->count); + } - if (verbose > 2) - rprintf(FINFO,"recv_files(%s)\n",fname); + if (recurse && delete_mode && !local_name && flist->count>0) { + delete_files(flist); + } - /* open the file */ - fd1 = open(fname,O_RDONLY); + while (1) { + i = read_int(f_in); + if (i == -1) { + if (phase==0 && remote_version >= 13) { + phase++; + csum_length = SUM_LENGTH; + if (verbose > 2) + rprintf(FINFO,"recv_files phase=%d\n",phase); + write_int(f_gen,-1); + continue; + } + break; + } - if (fd1 != -1 && do_fstat(fd1,&st) != 0) { - rprintf(FERROR,"fstat %s : %s\n",fname,strerror(errno)); - receive_data(f_in,NULL,-1,NULL); - close(fd1); - continue; - } + if (i < 0 || i >= flist->count) { + rprintf(FERROR,"Invalid file index %d in recv_files (count=%d)\n", + i, flist->count); + exit_cleanup(1); + } - if (fd1 != -1 && !S_ISREG(st.st_mode)) { - rprintf(FERROR,"%s : not a regular file (recv_files)\n",fname); - receive_data(f_in,NULL,-1,NULL); - close(fd1); - continue; - } + file = flist->files[i]; + fname = f_name(file); - if (fd1 != -1 && st.st_size > 0) { - buf = map_file(fd1,st.st_size); - if (verbose > 2) - rprintf(FINFO,"recv mapped %s of size %d\n",fname,(int)st.st_size); - } else { - buf = NULL; - } + stats.num_transferred_files++; + stats.total_transferred_size += file->length; - /* open tmp file */ - if (tmpdir) { - char *f; - f = strrchr(fname,'/'); - if (f == NULL) - f = fname; - else - f++; - if (strlen(tmpdir)+strlen(f)+10 > MAXPATHLEN) { - rprintf(FERROR,"filename too long\n"); - if (buf) unmap_file(buf); - close(fd1); - continue; - } - slprintf(fnametmp,sizeof(fnametmp)-1, "%s/.%s.XXXXXX",tmpdir,f); - } else { - char *f = strrchr(fname,'/'); - - if (strlen(fname)+9 > MAXPATHLEN) { - rprintf(FERROR,"filename too long\n"); - if (buf) unmap_file(buf); - close(fd1); - continue; - } - - if (f) { - *f = 0; - slprintf(fnametmp,sizeof(fnametmp)-1,"%s/.%s.XXXXXX",fname,f+1); - *f = '/'; - } else { - slprintf(fnametmp,sizeof(fnametmp)-1,".%s.XXXXXX",fname); - } - } - if (NULL == do_mktemp(fnametmp)) { - rprintf(FERROR,"mktemp %s failed\n",fnametmp); - receive_data(f_in,buf,-1,NULL); - if (buf) unmap_file(buf); - close(fd1); - continue; - } - fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode); - if (fd2 == -1 && relative_paths && errno == ENOENT && - create_directory_path(fnametmp) == 0) { - fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode); - } - if (fd2 == -1) { - rprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno)); - receive_data(f_in,buf,-1,NULL); - if (buf) unmap_file(buf); - close(fd1); - continue; - } - - cleanup_fname = fnametmp; + if (local_name) + fname = local_name; + + if (dry_run) { + if (!am_server && verbose) + printf("%s\n",fname); + continue; + } - if (!am_server && verbose) - printf("%s\n",fname); + if (verbose > 2) + rprintf(FINFO,"recv_files(%s)\n",fname); - /* recv file data */ - recv_ok = receive_data(f_in,buf,fd2,fname); + /* open the file */ + fd1 = open(fname,O_RDONLY); - if (buf) unmap_file(buf); - if (fd1 != -1) { - close(fd1); - } - close(fd2); + if (fd1 != -1 && do_fstat(fd1,&st) != 0) { + rprintf(FERROR,"fstat %s : %s\n",fname,strerror(errno)); + receive_data(f_in,NULL,-1,NULL); + close(fd1); + continue; + } - if (verbose > 2) - rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname); + if (fd1 != -1 && !S_ISREG(st.st_mode)) { + rprintf(FERROR,"%s : not a regular file (recv_files)\n",fname); + receive_data(f_in,NULL,-1,NULL); + close(fd1); + continue; + } - if (make_backups) { - char fnamebak[MAXPATHLEN]; - if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) { - rprintf(FERROR,"backup filename too long\n"); - continue; - } - slprintf(fnamebak,sizeof(fnamebak)-1,"%s%s",fname,backup_suffix); - if (do_rename(fname,fnamebak) != 0 && errno != ENOENT) { - rprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno)); - continue; - } - } + if (fd1 != -1 && st.st_size > 0) { + buf = map_file(fd1,st.st_size); + if (verbose > 2) + rprintf(FINFO,"recv mapped %s of size %d\n",fname,(int)st.st_size); + } else { + buf = NULL; + } - /* move tmp file over real file */ - if (do_rename(fnametmp,fname) != 0) { - if (errno == EXDEV) { - /* rename failed on cross-filesystem link. - Copy the file instead. */ - if (copy_file(fnametmp,fname, file->mode)) { - rprintf(FERROR,"copy %s -> %s : %s\n", - fnametmp,fname,strerror(errno)); - } else { - set_perms(fname,file,NULL,0); - } - do_unlink(fnametmp); - } else { - rprintf(FERROR,"rename %s -> %s : %s\n", - fnametmp,fname,strerror(errno)); - do_unlink(fnametmp); - } - } else { - set_perms(fname,file,NULL,0); - } + if (!get_tmpname(fnametmp,fname)) { + if (buf) unmap_file(buf); + close(fd1); + continue; + } - cleanup_fname = NULL; + if (NULL == do_mktemp(fnametmp)) { + rprintf(FERROR,"mktemp %s failed\n",fnametmp); + receive_data(f_in,buf,-1,NULL); + if (buf) unmap_file(buf); + close(fd1); + continue; + } + fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode); + if (fd2 == -1 && relative_paths && errno == ENOENT && + create_directory_path(fnametmp) == 0) { + fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode); + } + if (fd2 == -1) { + rprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno)); + receive_data(f_in,buf,-1,NULL); + if (buf) unmap_file(buf); + close(fd1); + continue; + } + + cleanup_fname = fnametmp; + + if (!am_server && verbose) + printf("%s\n",fname); + + /* recv file data */ + recv_ok = receive_data(f_in,buf,fd2,fname); + + if (buf) unmap_file(buf); + if (fd1 != -1) { + close(fd1); + } + close(fd2); + + if (verbose > 2) + rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname); + + if (make_backups) { + char fnamebak[MAXPATHLEN]; + if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) { + rprintf(FERROR,"backup filename too long\n"); + continue; + } + slprintf(fnamebak,sizeof(fnamebak)-1,"%s%s",fname,backup_suffix); + if (do_rename(fname,fnamebak) != 0 && errno != ENOENT) { + rprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno)); + continue; + } + } - if (!recv_ok) { - if (csum_length == SUM_LENGTH) { - rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n", - fname); - } else { - if (verbose > 1) - rprintf(FINFO,"redoing %s(%d)\n",fname,i); - write_int(f_gen,i); - } - } - } + /* move tmp file over real file */ + if (do_rename(fnametmp,fname) != 0) { + if (errno == EXDEV) { + /* rename failed on cross-filesystem link. + Copy the file instead. */ + if (copy_file(fnametmp,fname, file->mode)) { + rprintf(FERROR,"copy %s -> %s : %s\n", + fnametmp,fname,strerror(errno)); + } else { + set_perms(fname,file,NULL,0); + } + do_unlink(fnametmp); + } else { + rprintf(FERROR,"rename %s -> %s : %s\n", + fnametmp,fname,strerror(errno)); + do_unlink(fnametmp); + } + } else { + set_perms(fname,file,NULL,0); + } - if (preserve_hard_links) - do_hard_links(flist); + cleanup_fname = NULL; + + + if (!recv_ok) { + if (csum_length == SUM_LENGTH) { + rprintf(FERROR,"ERROR: file corruption in %s. File changed during transfer?\n", + fname); + } else { + if (verbose > 1) + rprintf(FINFO,"redoing %s(%d)\n",fname,i); + write_int(f_gen,i); + } + } + } - /* now we need to fix any directory permissions that were - modified during the transfer */ - for (i = 0; i < flist->count; i++) { - file = flist->files[i]; - if (!file->basename || !S_ISDIR(file->mode)) continue; - recv_generator(f_name(file),flist,i,-1); - } + if (preserve_hard_links) + do_hard_links(flist); - if (verbose > 2) - rprintf(FINFO,"recv_files finished\n"); - - return 0; + /* now we need to fix any directory permissions that were + modified during the transfer */ + for (i = 0; i < flist->count; i++) { + file = flist->files[i]; + if (!file->basename || !S_ISDIR(file->mode)) continue; + recv_generator(f_name(file),flist,i,-1); + } + + if (verbose > 2) + rprintf(FINFO,"recv_files finished\n"); + + return 0; } @@ -963,21 +992,21 @@ void send_files(struct file_list *flist,int f_out,int f_in) int i; struct file_struct *file; int phase = 0; - int offset=0; if (verbose > 2) rprintf(FINFO,"send_files starting\n"); - setup_nonblocking(f_in,f_out); + setup_readbuffer(f_in); while (1) { + int offset=0; + i = read_int(f_in); if (i == -1) { if (phase==0 && remote_version >= 13) { phase++; csum_length = SUM_LENGTH; write_int(f_out,-1); - write_flush(f_out); if (verbose > 2) rprintf(FINFO,"send_files phase=%d\n",phase); continue; @@ -985,8 +1014,17 @@ void send_files(struct file_list *flist,int f_out,int f_in) break; } + if (i < 0 || i >= flist->count) { + rprintf(FERROR,"Invalid file index %d (count=%d)\n", + i, flist->count); + exit_cleanup(1); + } + file = flist->files[i]; + stats.num_transferred_files++; + stats.total_transferred_size += file->length; + fname[0] = 0; if (file->basedir) { strlcpy(fname,file->basedir,MAXPATHLEN-1); @@ -1059,7 +1097,6 @@ void send_files(struct file_list *flist,int f_out,int f_in) printf("%s\n",fname+offset); match_sums(f_out,s,buf,st.st_size); - write_flush(f_out); if (buf) unmap_file(buf); close(fd); @@ -1076,7 +1113,6 @@ void send_files(struct file_list *flist,int f_out,int f_in) match_report(); write_int(f_out,-1); - write_flush(f_out); } @@ -1116,7 +1152,6 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv) rprintf(FINFO,"generate_files phase=%d\n",phase); write_int(f,-1); - write_flush(f); /* we expect to just sit around now, so don't exit on a timeout. If we really get a timeout then the other process should exit */ @@ -1136,12 +1171,7 @@ void generate_files(int f,struct file_list *flist,char *local_name,int f_recv) rprintf(FINFO,"generate_files phase=%d\n",phase); write_int(f,-1); - write_flush(f); } - - - if (verbose > 2) - rprintf(FINFO,"generator wrote %ld\n",(long)write_total()); }