+++ /dev/null
-Patch from Mark Curtis to implement the --inplace option.
-Improved by Wayne Davison.
-
-Run these commands after applying the patch:
-
- autoconf
- autoheader
- ./configure
- make
-
-Optional:
-
- make rsync.1
-
---- orig/configure.in 2004-04-30 18:04:07
-+++ configure.in 2004-07-03 20:19:54
-@@ -442,7 +442,7 @@ dnl AC_FUNC_MEMCMP
- AC_FUNC_UTIME_NULL
- AC_FUNC_ALLOCA
- AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo \
-- fchmod fstat strchr readlink link utime utimes strftime mtrace \
-+ fchmod fstat strchr readlink link utime utimes strftime mtrace ftruncate \
- memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk \
- strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid)
-
---- orig/match.c 2004-07-15 02:21:10
-+++ match.c 2004-07-16 19:39:08
-@@ -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,12 @@ static void hash_search(int f,struct sum
- if (l != s->sums[i].len)
- continue;
-
-+ /* inplace: ensure chunk's offset is either >= our
-+ * offset or that the data didn't move. */
-+ if (inplace && s->sums[i].offset < offset
-+ && !(s->sums[i].flags & SUMFLG_SAME_OFFSET))
-+ continue;
-+
- if (verbose > 3)
- rprintf(FINFO,"potential match at %.0f target=%.0f %.0f sum=%08x\n",
- (double)offset,(double)j,(double)i,sum);
-@@ -215,15 +222,41 @@ static void hash_search(int f,struct sum
- continue;
- }
-
-+ /* If inplace is enabled, the best possible match is
-+ * one with an identical offset, so we prefer that over
-+ * the following want_i optimization. */
-+ if (inplace) {
-+ do {
-+ size_t i2 = targets[j].i;
-+ if (s->sums[i2].offset != offset)
-+ continue;
-+ if (i2 != i) {
-+ if (sum != s->sums[i2].sum1)
-+ break;
-+ if (memcmp(sum2, s->sums[i2].sum2,
-+ s->s2length) != 0)
-+ break;
-+ i = i2;
-+ }
-+ /* This chunk was at the same offset on
-+ * both the sender and the receiver. */
-+ s->sums[i].flags |= SUMFLG_SAME_OFFSET;
-+ goto set_want_i;
-+ } while (++j < s->count && targets[j].t == t);
-+ }
-+
- /* we've found a match, but now check to see
- * if want_i can hint at a better match. */
- if (i != want_i && want_i < s->count
-+ && (!inplace || s->sums[want_i].offset >= offset
-+ || s->sums[want_i].flags & SUMFLG_SAME_OFFSET)
- && sum == s->sums[want_i].sum1
- && memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
- /* we've found an adjacent match - the RLL coder
- * will be happy */
- i = want_i;
- }
-+ set_want_i:
- want_i = i + 1;
-
- matched(f,s,buf,offset,i);
---- orig/options.c 2004-07-16 19:35:29
-+++ options.c 2004-07-03 20:19:54
-@@ -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;
-
-
-@@ -148,6 +149,7 @@ char *bind_address;
- static void print_rsync_version(enum logcode f)
- {
- char const *got_socketpair = "no ";
-+ char const *have_inplace = "no ";
- char const *hardlinks = "no ";
- char const *links = "no ";
- char const *ipv6 = "no ";
-@@ -157,6 +159,10 @@ static void print_rsync_version(enum log
- got_socketpair = "";
- #endif
-
-+#if HAVE_FTRUNCATE
-+ have_inplace = "";
-+#endif
-+
- #if SUPPORT_HARD_LINKS
- hardlinks = "";
- #endif
-@@ -182,8 +188,8 @@ static void print_rsync_version(enum log
- /* Note that this field may not have type ino_t. It depends
- * on the complicated interaction between largefile feature
- * macros. */
-- rprintf(f, " %sIPv6, %d-bit system inums, %d-bit internal inums\n",
-- ipv6,
-+ rprintf(f, " %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums\n",
-+ have_inplace, ipv6,
- (int) (sizeof dumstat->st_ino * 8),
- (int) (sizeof (uint64) * 8));
- #ifdef MAINTAINER_MODE
-@@ -233,6 +239,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");
-@@ -340,6 +347,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 },
-@@ -754,6 +762,18 @@ int parse_arguments(int *argc, const cha
- bwlimit_writemax = 512;
- }
-
-+ if (inplace) {
-+#if HAVE_FTRUNCATE
-+ if (keep_partial)
-+ keep_partial = 0;
-+#else
-+ snprintf(err_buf, sizeof err_buf,
-+ "inplace is not supported on this %s\n",
-+ am_server ? "server" : "client");
-+ return 0;
-+#endif
-+ }
-+
- if (files_from) {
- char *colon;
- if (*argc != 2 && !(am_server && am_sender && *argc == 1)) {
-@@ -971,6 +991,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;
---- orig/receiver.c 2004-07-14 17:12:06
-+++ receiver.c 2004-07-03 20:19:54
-@@ -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)
- {
-@@ -255,16 +256,30 @@ 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);
-
-+#ifdef HAVE_FTRUNCATE
-+ if (inplace)
-+ ftruncate(fd, offset);
-+#endif
-+
- if (do_progress)
- end_progress(total_size);
-
-@@ -414,44 +429,59 @@ int recv_files(int f_in, struct file_lis
- } 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(fnamecmp));
-+ 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;
-- }
-
-- cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2);
-+ /* 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);
-+ }
-
- if (!am_server && verbose)
- rprintf(FINFO, "%s\n", fname);
---- orig/rsync.c 2004-07-02 18:06:32
-+++ rsync.c 2004-07-03 20:19:54
-@@ -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,13 @@ void finish_transfer(char *fname, char *
- if (make_backups && !make_backup(fname))
- return;
-
-+ if (inplace) {
-+ if (verbose > 2)
-+ rprintf(FINFO, "finishing %s\n", fname);
-+ set_perms(fname, file, NULL, 0);
-+ return;
-+ }
-+
- /* move tmp file over real file */
- if (verbose > 2)
- rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
---- orig/rsync.h 2004-07-07 08:27:00
-+++ rsync.h 2004-07-16 19:36:20
-@@ -458,11 +458,13 @@ struct file_list {
- struct file_struct **files;
- };
-
-+#define SUMFLG_SAME_OFFSET (1<<0)
-+
- struct sum_buf {
- OFF_T offset; /**< offset in file of this chunk */
- unsigned int len; /**< length of chunk of file */
-- int i; /**< index of this chunk */
- uint32 sum1; /**< simple checksum */
-+ short flags; /**< flag bits */
- char sum2[SUM_LENGTH]; /**< checksum */
- };
-
---- orig/rsync.yo 2004-07-16 19:35:29
-+++ rsync.yo 2004-07-03 20:19:55
-@@ -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.
-
---- orig/sender.c 2004-07-15 02:21:11
-+++ sender.c 2004-07-16 19:40:59
-@@ -85,7 +85,7 @@ static struct sum_struct *receive_sums(i
- read_buf(f, s->sums[i].sum2, s->s2length);
-
- s->sums[i].offset = offset;
-- s->sums[i].i = i;
-+ s->sums[i].flags = 0;
-
- if (i == (int) s->count-1 && s->remainder != 0) {
- s->sums[i].len = s->remainder;