X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/46831d6fcf5ace953b1e354a542b9bb45cdf376a..eb86d661d79f25c91788964a768b54223717e8f6:/rsync.c diff --git a/rsync.c b/rsync.c index 38321459..5af71933 100644 --- a/rsync.c +++ b/rsync.c @@ -53,6 +53,37 @@ extern int io_timeout; extern int io_error; extern struct stats stats; + +/* handling the cleanup when a transfer is interrupted is tricky when + --partial is selected. We need to ensure that the partial file is + kept if any real data has been transferred */ +static int cleanup_got_literal; +static char *cleanup_fname; +static char *cleanup_new_fname; +static struct file_struct *cleanup_file; +static void finish_transfer(char *fname, char *fnametmp, struct file_struct *file); + +void exit_cleanup(int code) +{ + extern int keep_partial; + + signal(SIGUSR1, SIG_IGN); + + if (cleanup_got_literal && cleanup_fname && keep_partial) { + char *fname = cleanup_fname; + cleanup_fname = NULL; + finish_transfer(cleanup_new_fname, fname, cleanup_file); + } + io_flush(); + if (cleanup_fname) + do_unlink(cleanup_fname); + if (code) { + kill_all(SIGUSR1); + } + exit(code); +} + + /* free a sums struct */ @@ -546,76 +577,92 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out) -static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname) +static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname, + OFF_T total_size) { - int i,n,remainder,len,count; - OFF_T offset = 0; - OFF_T offset2; - char *data; - static char file_sum1[MD4_SUM_LENGTH]; - static char file_sum2[MD4_SUM_LENGTH]; - char *map=NULL; - - count = read_int(f_in); - n = read_int(f_in); - remainder = read_int(f_in); - - sum_init(); - - for (i=recv_token(f_in,&data); i != 0; i=recv_token(f_in,&data)) { - if (i > 0) { - if (verbose > 3) - rprintf(FINFO,"data recv %d at %d\n",i,(int)offset); - - stats.literal_data += i; - sum_update(data,i); + int i,n,remainder,len,count; + OFF_T offset = 0; + OFF_T offset2; + char *data; + static char file_sum1[MD4_SUM_LENGTH]; + static char file_sum2[MD4_SUM_LENGTH]; + char *map=NULL; + + count = read_int(f_in); + n = read_int(f_in); + remainder = read_int(f_in); + + sum_init(); + + for (i=recv_token(f_in,&data); i != 0; i=recv_token(f_in,&data)) { - if (fd != -1 && write_file(fd,data,i) != i) { - rprintf(FERROR,"write failed on %s : %s\n",fname,strerror(errno)); - exit_cleanup(1); - } - offset += i; - } else { - i = -(i+1); - offset2 = i*n; - len = n; - if (i == count-1 && remainder != 0) - len = remainder; + show_progress(offset, total_size); - stats.matched_data += len; + if (i > 0) { + if (verbose > 3) { + rprintf(FINFO,"data recv %d at %d\n", + i,(int)offset); + } - if (verbose > 3) - rprintf(FINFO,"chunk[%d] of size %d at %d offset=%d\n", - i,len,(int)offset2,(int)offset); + stats.literal_data += i; + cleanup_got_literal = 1; + + sum_update(data,i); - map = map_ptr(buf,offset2,len); + if (fd != -1 && write_file(fd,data,i) != i) { + rprintf(FERROR,"write failed on %s : %s\n",fname,strerror(errno)); + exit_cleanup(1); + } + offset += i; + continue; + } - see_token(map, len); - sum_update(map,len); + i = -(i+1); + offset2 = i*n; + len = n; + 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); + + map = map_ptr(buf,offset2,len); + + see_token(map, len); + sum_update(map,len); + + if (fd != -1 && write_file(fd,map,len) != len) { + rprintf(FERROR,"write failed on %s : %s\n", + fname,strerror(errno)); + exit_cleanup(1); + } + offset += len; + } - if (fd != -1 && write_file(fd,map,len) != len) { - rprintf(FERROR,"write failed on %s : %s\n",fname,strerror(errno)); - exit_cleanup(1); - } - offset += len; - } - } + end_progress(); - if (fd != -1 && offset > 0 && sparse_end(fd) != 0) { - rprintf(FERROR,"write failed on %s : %s\n",fname,strerror(errno)); - exit_cleanup(1); - } + if (fd != -1 && offset > 0 && sparse_end(fd) != 0) { + rprintf(FERROR,"write failed on %s : %s\n", + fname,strerror(errno)); + exit_cleanup(1); + } - sum_end(file_sum1); + sum_end(file_sum1); - if (remote_version >= 14) { - read_buf(f_in,file_sum2,MD4_SUM_LENGTH); - if (verbose > 2) - rprintf(FINFO,"got file_sum\n"); - if (fd != -1 && memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0) - return 0; - } - return 1; + if (remote_version >= 14) { + read_buf(f_in,file_sum2,MD4_SUM_LENGTH); + if (verbose > 2) { + rprintf(FINFO,"got file_sum\n"); + } + if (fd != -1 && + memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0) { + return 0; + } + } + return 1; } @@ -730,20 +777,6 @@ static void delete_files(struct file_list *flist) } } -static char *cleanup_fname; - -void exit_cleanup(int code) -{ - io_flush(); - if (cleanup_fname) - do_unlink(cleanup_fname); - signal(SIGUSR1, SIG_IGN); - if (code) { - kill_all(SIGUSR1); - } - exit(code); -} - void sig_int(void) { exit_cleanup(1); @@ -790,6 +823,46 @@ static int get_tmpname(char *fnametmp, char *fname) return 1; } +/* finish off a file transfer, renaming the file and setting the permissions + and ownership */ +static void finish_transfer(char *fname, char *fnametmp, struct file_struct *file) +{ + if (make_backups) { + char fnamebak[MAXPATHLEN]; + if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) { + rprintf(FERROR,"backup filename too long\n"); + return; + } + 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)); + return; + } + } + + /* 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); + } +} + + int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) { int fd1,fd2; @@ -811,6 +884,9 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) } while (1) { + cleanup_fname = NULL; + cleanup_got_literal = 0; + i = read_int(f_in); if (i == -1) { if (phase==0 && remote_version >= 13) { @@ -853,14 +929,14 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) if (fd1 != -1 && do_fstat(fd1,&st) != 0) { rprintf(FERROR,"fstat %s : %s\n",fname,strerror(errno)); - receive_data(f_in,NULL,-1,NULL); + receive_data(f_in,NULL,-1,NULL,file->length); close(fd1); continue; } 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); + receive_data(f_in,NULL,-1,NULL,file->length); close(fd1); continue; } @@ -881,7 +957,7 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) if (NULL == do_mktemp(fnametmp)) { rprintf(FERROR,"mktemp %s failed\n",fnametmp); - receive_data(f_in,buf,-1,NULL); + receive_data(f_in,buf,-1,NULL,file->length); if (buf) unmap_file(buf); close(fd1); continue; @@ -902,19 +978,21 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) } if (fd2 == -1) { rprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno)); - receive_data(f_in,buf,-1,NULL); + receive_data(f_in,buf,-1,NULL,file->length); if (buf) unmap_file(buf); close(fd1); continue; } cleanup_fname = fnametmp; + cleanup_new_fname = fname; + cleanup_file = file; if (!am_server && verbose) printf("%s\n",fname); /* recv file data */ - recv_ok = receive_data(f_in,buf,fd2,fname); + recv_ok = receive_data(f_in,buf,fd2,fname,file->length); if (buf) unmap_file(buf); if (fd1 != -1) { @@ -924,43 +1002,10 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) 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; - } - } - - /* 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); - } + finish_transfer(fname, fnametmp, file); + cleanup_fname = NULL; - if (!recv_ok) { if (csum_length == SUM_LENGTH) {