From c95da96a0c51c66c8cb2eff97b768a717d9e0c79 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 1 Jul 1998 03:36:03 +0000 Subject: [PATCH] added a --partial option which tells rsync to keep partially transferred files if the transfer is interrupted. added a "options summary" section to the man page --- main.c | 4 +++ options.c | 12 ++++++- rsync.c | 94 ++++++++++++++++++++++++++++++++++--------------------- rsync.yo | 56 +++++++++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 37 deletions(-) diff --git a/main.c b/main.c index 3c4d99c7..ed9dd173 100644 --- a/main.c +++ b/main.c @@ -172,6 +172,10 @@ static char *get_local_name(struct file_list *flist,char *name) STRUCT_STAT st; extern int orig_umask; + if (verbose > 2) + rprintf(FINFO,"get_local_name count=%d %s\n", + flist->count, name); + if (do_stat(name,&st) == 0) { if (S_ISDIR(st.st_mode)) { if (!push_dir(name, 0)) { diff --git a/options.c b/options.c index 757598d6..10c27733 100644 --- a/options.c +++ b/options.c @@ -56,6 +56,7 @@ int recurse = 0; int am_daemon=0; int am_client=0; int do_stats=0; +int keep_partial=0; int block_size=BLOCK_SIZE; @@ -108,6 +109,7 @@ void usage(int F) rprintf(F," --rsync-path=PATH specify path to rsync on the remote machine\n"); rprintf(F," -C, --cvs-exclude auto ignore files in the same way CVS does\n"); rprintf(F," --delete delete files that don't exist on the sending side\n"); + rprintf(F," --partial keep partially transferred files\n"); rprintf(F," --force force deletion of directories even if not empty\n"); rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n"); rprintf(F," --timeout=TIME set IO timeout in seconds\n"); @@ -137,7 +139,7 @@ void usage(int F) enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE, OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH, OPT_FORCE,OPT_TIMEOUT,OPT_DAEMON,OPT_CONFIG,OPT_PORT, - OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS}; + OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS, OPT_PARTIAL}; static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z"; @@ -183,6 +185,7 @@ static struct option long_options[] = { {"compress", 0, 0, 'z'}, {"daemon", 0, 0, OPT_DAEMON}, {"stats", 0, 0, OPT_STATS}, + {"partial", 0, 0, OPT_PARTIAL}, {"config", 1, 0, OPT_CONFIG}, {"port", 1, 0, OPT_PORT}, {0,0,0,0}}; @@ -382,6 +385,10 @@ void parse_arguments(int argc, char *argv[]) do_stats = 1; break; + case OPT_PARTIAL: + keep_partial = 1; + break; + case OPT_CONFIG: config_file = optarg; break; @@ -477,6 +484,9 @@ void server_options(char **args,int *argc) if (delete_mode) args[ac++] = "--delete"; + if (keep_partial) + args[ac++] = "--partial"; + if (force_delete) args[ac++] = "--force"; diff --git a/rsync.c b/rsync.c index 38321459..7ad7a9ad 100644 --- a/rsync.c +++ b/rsync.c @@ -731,11 +731,19 @@ static void delete_files(struct file_list *flist) } 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; + + if (cleanup_fname && keep_partial) { + finish_transfer(cleanup_new_fname, cleanup_fname, cleanup_file); + } io_flush(); - if (cleanup_fname) + if (cleanup_fname && !keep_partial) do_unlink(cleanup_fname); signal(SIGUSR1, SIG_IGN); if (code) { @@ -790,6 +798,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 +859,9 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) } while (1) { + cleanup_fname = NULL; + cleanup_new_fname = NULL; + i = read_int(f_in); if (i == -1) { if (phase==0 && remote_version >= 13) { @@ -909,6 +960,8 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen) } cleanup_fname = fnametmp; + cleanup_new_fname = fname; + cleanup_file = file; if (!am_server && verbose) printf("%s\n",fname); @@ -924,43 +977,12 @@ 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; - + cleanup_new_fname = NULL; + cleanup_file = NULL; if (!recv_ok) { if (csum_length == SUM_LENGTH) { diff --git a/rsync.yo b/rsync.yo index 4a8fe045..b13a8b8c 100644 --- a/rsync.yo +++ b/rsync.yo @@ -187,6 +187,56 @@ quote(rsync -az -e ssh --delete ~ftp/pub/samba/ nimbus:"~ftp/pub/tridge/samba") this is launched from cron every few hours. +manpagesection(OPTIONS SUMMARY) + +Here is a short summary of the options avalable in rsync. Please refer +to the detailed description below for a complete description. + +verb( + -v, --verbose increase verbosity + -c, --checksum always checksum + -a, --archive archive mode + -r, --recursive recurse into directories + -R, --relative use relative path names + -b, --backup make backups (default ~ extension) + -u, --update update only (don't overwrite newer files) + -l, --links preserve soft links + -L, --copy-links treat soft links like regular files + -H, --hard-links preserve hard links + -p, --perms preserve permissions + -o, --owner preserve owner (root only) + -g, --group preserve group + -D, --devices preserve devices (root only) + -t, --times preserve times + -S, --sparse handle sparse files efficiently + -n, --dry-run show what would have been transferred + -W, --whole-file copy whole files, no incremental checks + -x, --one-file-system don't cross filesystem boundaries + -B, --block-size=SIZE checksum blocking size + -e, --rsh=COMMAND specify rsh replacement + --rsync-path=PATH specify path to rsync on the remote machine + -C, --cvs-exclude auto ignore files in the same way CVS does + --delete delete files that don't exist on the sending side + --partial keep partially transferred files + --force force deletion of directories even if not empty + --numeric-ids don't map uid/gid values by user/group name + --timeout=TIME set IO timeout in seconds + -I, --ignore-times don't exclude files that match length and time + -T --temp-dir=DIR create temporary files in directory DIR + -z, --compress compress file data + --exclude=PATTERN exclude file FILE + --exclude-from=PATTERN exclude files listed in FILE + --include=PATTERN don't exclude file FILE + --include-from=PATTERN don't exclude files listed in FILE + --suffix=SUFFIX override backup suffix + --version print version number + --daemon run as a rsync daemon + --config=FILE specify alternate rsyncd.conf file + --port=PORT specify alternate rsyncd port number + --stats give some file transfer stats + -h, --help show this help screen +) + manpageoptions() rsync uses the GNU long options package. Many of the command line @@ -269,6 +319,12 @@ dit(bf(-W, --whole-file)) With this option the incremental rsync algorithm is not used and the whole file is sent as-is instead. This may be useful when using rsync with a local machine. +dit(bf(--partial)) By default rsync will delete any partially +transferred file if the transfer is interrupted. In some circumstances +it is more desirable to keep partially transferred files. Using the +--partial option tells rsync to keep the partial file which should +make a subsequent transfer of the rest of the file much faster. + dit(bf(-p, --perms)) This option causes rsync to update the remote permissions to be the same as the local permissions. -- 2.34.1