Patch from Mark Curtis to implement the --inplace option. --- match.c 21 May 2004 08:27:04 -0000 1.62 +++ match.c 30 Jun 2004 00:09:37 -0000 @@ -23,6 +23,7 @@ extern int verbose; extern int am_server; extern int do_progress; extern int checksum_seed; +extern int inplace; typedef unsigned short tag; @@ -200,6 +201,10 @@ static void hash_search(int f,struct sum if (l != s->sums[i].len) continue; + /* if inplace, make sure the offset is greater than where we are */ + if (inplace && offset > s->sums[i].offset) + continue; + if (verbose > 3) rprintf(FINFO,"potential match at %.0f target=%.0f %.0f sum=%08x\n", (double)offset,(double)j,(double)i,sum); --- options.c 20 Jun 2004 19:47:05 -0000 1.157 +++ options.c 30 Jun 2004 00:09:38 -0000 @@ -94,6 +94,7 @@ int ignore_errors = 0; int modify_window = 0; int blocking_io = -1; int checksum_seed = 0; +int inplace = 0; unsigned int block_size = 0; @@ -234,6 +235,7 @@ void usage(enum logcode F) rprintf(F," --backup-dir make backups into this directory\n"); rprintf(F," --suffix=SUFFIX backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX); rprintf(F," -u, --update update only (don't overwrite newer files)\n"); + rprintf(F," --inplace update the destination file inplace *SEE MAN PAGE*\n"); rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); rprintf(F," -l, --links copy symlinks as symlinks\n"); rprintf(F," -L, --copy-links copy the referent of all symlinks\n"); @@ -341,6 +343,7 @@ static struct poptOption long_options[] {"sparse", 'S', POPT_ARG_NONE, &sparse_files, 0, 0, 0 }, {"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude, 0, 0, 0 }, {"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 }, + {"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 }, {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 }, {"links", 'l', POPT_ARG_NONE, &preserve_links, 0, 0, 0 }, {"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 }, @@ -739,6 +742,9 @@ int parse_arguments(int *argc, const cha bwlimit_writemax = 512; } + if (inplace && keep_partial) + keep_partial = 0; + if (files_from) { char *colon; if (*argc != 2 && !(am_server && am_sender && *argc == 1)) { @@ -963,6 +969,9 @@ void server_options(char **args,int *arg if (opt_ignore_existing && am_sender) args[ac++] = "--ignore-existing"; + if (inplace) + args[ac++] = "--inplace"; + if (tmpdir) { args[ac++] = "--temp-dir"; args[ac++] = tmpdir; --- receiver.c 29 Jun 2004 15:12:01 -0000 1.83 +++ receiver.c 30 Jun 2004 00:09:38 -0000 @@ -48,6 +48,7 @@ extern int ignore_errors; extern int orig_umask; extern int keep_partial; extern int checksum_seed; +extern int inplace; static void delete_one(char *fn, int is_dir) { @@ -257,16 +258,28 @@ static int receive_data(int f_in,struct sum_update(map,len); } - if (fd != -1 && write_file(fd,map,len) != (int) len) { - rsyserr(FERROR, errno, "write failed on %s", - full_fname(fname)); - exit_cleanup(RERR_FILEIO); + if (!inplace || offset != offset2) { + if (fd != -1 && write_file(fd,map,len) != (int) len) { + rsyserr(FERROR, errno, "write failed on %s", + full_fname(fname)); + exit_cleanup(RERR_FILEIO); + } + } else { + flush_write_file(fd); + if (do_lseek(fd,(OFF_T)len,SEEK_CUR) != offset+len) { + rprintf(FERROR, "lseek failed on %s: %s, %lli, %lli, %i\n", + full_fname(fname), strerror(errno), do_lseek(fd,0,SEEK_CUR), (offset+len), i); + exit_cleanup(RERR_FILEIO); + } } offset += len; } flush_write_file(fd); + if (inplace) + ftruncate(fd, offset); + if (do_progress) end_progress(total_size); @@ -420,37 +433,50 @@ int recv_files(int f_in,struct file_list } else mapbuf = NULL; - if (!get_tmpname(fnametmp,fname)) { - if (mapbuf) unmap_file(mapbuf); - if (fd1 != -1) close(fd1); - continue; - } + /* We now check to see if we are writing file "inplace" */ + if (inplace) { + fd2 = do_open(fnamecmp, O_WRONLY|O_CREAT, 0); + if (fd2 == -1) { + rsyserr(FERROR, errno, "open %s failed", + full_fname(fnametmp)); + receive_data(f_in,mapbuf,-1,NULL,file->length); + if (mapbuf) unmap_file(mapbuf); + if (fd1 != -1) close(fd1); + continue; + } + } else { + if (!get_tmpname(fnametmp,fname)) { + if (mapbuf) unmap_file(mapbuf); + if (fd1 != -1) close(fd1); + continue; + } - strlcpy(template, fnametmp, sizeof template); + strlcpy(template, fnametmp, sizeof template); - /* we initially set the perms without the - * setuid/setgid bits to ensure that there is no race - * condition. They are then correctly updated after - * the lchown. Thanks to snabb@epipe.fi for pointing - * this out. We also set it initially without group - * access because of a similar race condition. */ - fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS); - - /* in most cases parent directories will already exist - * because their information should have been previously - * transferred, but that may not be the case with -R */ - if (fd2 == -1 && relative_paths && errno == ENOENT && - create_directory_path(fnametmp, orig_umask) == 0) { - strlcpy(fnametmp, template, sizeof fnametmp); + /* we initially set the perms without the + * setuid/setgid bits to ensure that there is no race + * condition. They are then correctly updated after + * the lchown. Thanks to snabb@epipe.fi for pointing + * this out. We also set it initially without group + * access because of a similar race condition. */ fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS); - } - if (fd2 == -1) { - rsyserr(FERROR, errno, "mkstemp %s failed", - full_fname(fnametmp)); - receive_data(f_in,mapbuf,-1,NULL,file->length); - if (mapbuf) unmap_file(mapbuf); - if (fd1 != -1) close(fd1); - continue; + + /* in most cases parent directories will already exist + * because their information should have been previously + * transferred, but that may not be the case with -R */ + if (fd2 == -1 && relative_paths && errno == ENOENT + && create_directory_path(fnametmp, orig_umask) == 0) { + strlcpy(fnametmp, template, sizeof fnametmp); + fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS); + } + if (fd2 == -1) { + rsyserr(FERROR, errno, "mkstemp %s failed", + full_fname(fnametmp)); + receive_data(f_in,mapbuf,-1,NULL,file->length); + if (mapbuf) unmap_file(mapbuf); + if (fd1 != -1) close(fd1); + continue; + } } cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2); --- rsync.c 11 Jun 2004 07:40:45 -0000 1.141 +++ rsync.c 30 Jun 2004 00:09:38 -0000 @@ -34,6 +34,7 @@ extern int force_delete; extern int recurse; extern int make_backups; extern char *backup_dir; +extern int inplace; /* @@ -239,6 +240,11 @@ void finish_transfer(char *fname, char * if (make_backups && !make_backup(fname)) return; + if (inplace) { + set_perms(fname,file,NULL,0); + return; + } + /* move tmp file over real file */ ret = robust_rename(fnametmp, fname, file->mode & INITACCESSPERMS); if (ret < 0) { --- rsync.yo 5 Jun 2004 16:16:30 -0000 1.171 +++ rsync.yo 30 Jun 2004 00:09:39 -0000 @@ -289,6 +289,7 @@ verb( --backup-dir make backups into this directory --suffix=SUFFIX backup suffix (default ~ w/o --backup-dir) -u, --update update only (don't overwrite newer files) + --inplace update the destination file inplace -K, --keep-dirlinks treat symlinked dir on receiver as dir -l, --links copy symlinks as symlinks -L, --copy-links copy the referent of all symlinks @@ -484,6 +485,17 @@ dit(bf(-K, --keep-dirlinks)) On the rece pointing to a directory, it will be treated as matching a directory from the sender. +dit(bf(--inplace)) This causes rsync not to create a new copy of the file +and then move it into place. Instead rsync will overwrite the existing +file, meaning that the rsync algorithm can't extract the full ammount of +network reduction it might otherwise. + +This option is useful for transfer of large files with block based changes +and also on systems that are disk bound not network bound. + +WARNING: If the transfer is interrupted, you will have an inconsistent file +and the transfer should be run again. + dit(bf(-l, --links)) When symlinks are encountered, recreate the symlink on the destination.