Patch from Mark Curtis to implement the --inplace option.

--- match.c	21 May 2004 08:27:04 -0000	1.62
+++ match.c	21 May 2004 09:03:09 -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	6 May 2004 21:08:01 -0000	1.148
+++ options.c	21 May 2004 09:03:09 -0000
@@ -91,6 +91,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;
 
 
@@ -231,6 +232,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," -l, --links                 copy symlinks as symlinks\n");
   rprintf(F," -L, --copy-links            copy the referent of all symlinks\n");
   rprintf(F,"     --copy-unsafe-links     copy the referent of \"unsafe\" symlinks\n");
@@ -321,6 +323,7 @@ static struct poptOption long_options[] 
   {"delete",           0,  POPT_ARG_NONE,   &delete_mode, 0, 0, 0 },
   {"existing",         0,  POPT_ARG_NONE,   &only_existing, 0, 0, 0 },
   {"ignore-existing",  0,  POPT_ARG_NONE,   &opt_ignore_existing, 0, 0, 0 },
+  {"inplace",          0,  POPT_ARG_NONE,   &inplace, 0, 0, 0 },
   {"delete-after",     0,  POPT_ARG_NONE,   0,              OPT_DELETE_AFTER, 0, 0 },
   {"delete-excluded",  0,  POPT_ARG_NONE,   0,              OPT_DELETE_EXCLUDED, 0, 0 },
   {"force",            0,  POPT_ARG_NONE,   &force_delete, 0, 0, 0 },
@@ -723,6 +726,9 @@ int parse_arguments(int *argc, const cha
 	if (do_progress && !verbose)
 		verbose = 1;
 
+	if (inplace && keep_partial)
+		keep_partial = 0;
+
 	if (files_from) {
 		char *colon;
 		if (*argc != 2 && !(am_server && am_sender && *argc == 1)) {
@@ -939,6 +945,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	21 May 2004 08:27:04 -0000	1.79
+++ receiver.c	21 May 2004 09:03:09 -0000
@@ -47,6 +47,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)
 {
@@ -252,16 +253,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);
 
@@ -413,37 +426,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	21 May 2004 08:43:03 -0000	1.140
+++ rsync.c	21 May 2004 09:03:09 -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	7 May 2004 00:18:37 -0000	1.169
+++ rsync.yo	21 May 2004 09:03:10 -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
  -l, --links                 copy symlinks as symlinks
  -L, --copy-links            copy the referent of all symlinks
      --copy-unsafe-links     copy the referent of "unsafe" symlinks
@@ -478,6 +479,17 @@ symlink where the destination has a file
 regardless of the timestamps.  This might change in the future (feel
 free to comment on this on the mailing list if you have an opinion).
 
+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.
 
