1 Patch from Mark Curtis to implement the --inplace option.
2 Improved by Wayne Davison.
4 Run these commands after applying the patch:
15 --- orig/configure.in 2004-04-30 18:04:07
16 +++ configure.in 2004-07-03 20:19:54
17 @@ -442,7 +442,7 @@ dnl AC_FUNC_MEMCMP
20 AC_CHECK_FUNCS(waitpid wait4 getcwd strdup strerror chown chmod mknod mkfifo \
21 - fchmod fstat strchr readlink link utime utimes strftime mtrace \
22 + fchmod fstat strchr readlink link utime utimes strftime mtrace ftruncate \
23 memmove lchown vsnprintf snprintf asprintf setsid glob strpbrk \
24 strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid)
26 --- orig/match.c 2004-07-07 08:38:52
27 +++ match.c 2004-07-04 08:03:36
28 @@ -23,6 +23,7 @@ extern int verbose;
30 extern int do_progress;
31 extern int checksum_seed;
34 typedef unsigned short tag;
36 @@ -200,6 +201,12 @@ static void hash_search(int f,struct sum
37 if (l != s->sums[i].len)
40 + /* inplace: ensure chunk's offset is either >= our
41 + * offset or that the data didn't move. */
42 + if (inplace && s->sums[i].offset < offset
43 + && s->sums[i].i >= 0)
47 rprintf(FINFO,"potential match at %.0f target=%.0f %.0f sum=%08x\n",
48 (double)offset,(double)j,(double)i,sum);
49 @@ -215,15 +222,41 @@ static void hash_search(int f,struct sum
53 + /* If inplace is enabled, the best possible match is
54 + * one with an identical offset, so we prefer that over
55 + * the following want_i optimization. */
58 + size_t i2 = targets[j].i;
59 + if (s->sums[i2].offset != offset)
62 + if (sum != s->sums[i2].sum1)
64 + if (memcmp(sum2, s->sums[i2].sum2,
69 + /* Use this as a flag to indicate that
70 + * this chunk was at the same offset on
71 + * both the sender and the receiver. */
74 + } while (++j < s->count && targets[j].t == t);
77 /* we've found a match, but now check to see
78 * if want_i can hint at a better match. */
79 if (i != want_i && want_i < s->count
80 + && (!inplace || s->sums[want_i].offset >= offset || s->sums[want_i].i < 0)
81 && sum == s->sums[want_i].sum1
82 && memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) {
83 /* we've found an adjacent match - the RLL coder
90 matched(f,s,buf,offset,i);
91 --- orig/options.c 2004-06-20 19:30:00
92 +++ options.c 2004-07-03 20:19:54
93 @@ -94,6 +94,7 @@ int ignore_errors = 0;
94 int modify_window = 0;
96 int checksum_seed = 0;
98 unsigned int block_size = 0;
101 @@ -149,6 +150,7 @@ char *bind_address;
102 static void print_rsync_version(enum logcode f)
104 char const *got_socketpair = "no ";
105 + char const *have_inplace = "no ";
106 char const *hardlinks = "no ";
107 char const *links = "no ";
108 char const *ipv6 = "no ";
109 @@ -158,6 +160,10 @@ static void print_rsync_version(enum log
117 #if SUPPORT_HARD_LINKS
120 @@ -183,8 +189,8 @@ static void print_rsync_version(enum log
121 /* Note that this field may not have type ino_t. It depends
122 * on the complicated interaction between largefile feature
124 - rprintf(f, " %sIPv6, %d-bit system inums, %d-bit internal inums\n",
126 + rprintf(f, " %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums\n",
127 + have_inplace, ipv6,
128 (int) (sizeof dumstat->st_ino * 8),
129 (int) (sizeof (uint64) * 8));
130 #ifdef MAINTAINER_MODE
131 @@ -234,6 +240,7 @@ void usage(enum logcode F)
132 rprintf(F," --backup-dir make backups into this directory\n");
133 rprintf(F," --suffix=SUFFIX backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
134 rprintf(F," -u, --update update only (don't overwrite newer files)\n");
135 + rprintf(F," --inplace update the destination file inplace (see man page)\n");
136 rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n");
137 rprintf(F," -l, --links copy symlinks as symlinks\n");
138 rprintf(F," -L, --copy-links copy the referent of all symlinks\n");
139 @@ -341,6 +348,7 @@ static struct poptOption long_options[]
140 {"sparse", 'S', POPT_ARG_NONE, &sparse_files, 0, 0, 0 },
141 {"cvs-exclude", 'C', POPT_ARG_NONE, &cvs_exclude, 0, 0, 0 },
142 {"update", 'u', POPT_ARG_NONE, &update_only, 0, 0, 0 },
143 + {"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 },
144 {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 },
145 {"links", 'l', POPT_ARG_NONE, &preserve_links, 0, 0, 0 },
146 {"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 },
147 @@ -739,6 +747,18 @@ int parse_arguments(int *argc, const cha
148 bwlimit_writemax = 512;
156 + snprintf(err_buf, sizeof err_buf,
157 + "inplace is not supported on this %s\n",
158 + am_server ? "server" : "client");
165 if (*argc != 2 && !(am_server && am_sender && *argc == 1)) {
166 @@ -963,6 +983,9 @@ void server_options(char **args,int *arg
167 if (opt_ignore_existing && am_sender)
168 args[ac++] = "--ignore-existing";
171 + args[ac++] = "--inplace";
174 args[ac++] = "--temp-dir";
176 --- orig/receiver.c 2004-07-02 18:23:01
177 +++ receiver.c 2004-07-03 20:19:54
178 @@ -48,6 +48,7 @@ extern int ignore_errors;
179 extern int orig_umask;
180 extern int keep_partial;
181 extern int checksum_seed;
184 static void delete_one(char *fn, int is_dir)
186 @@ -255,16 +256,30 @@ static int receive_data(int f_in,struct
190 - if (fd != -1 && write_file(fd, map, len) != (int)len) {
191 - rsyserr(FERROR, errno, "write failed on %s",
192 - full_fname(fname));
193 - exit_cleanup(RERR_FILEIO);
194 + if (!inplace || offset != offset2) {
195 + if (fd != -1 && write_file(fd, map, len) != (int)len) {
196 + rsyserr(FERROR, errno, "write failed on %s",
197 + full_fname(fname));
198 + exit_cleanup(RERR_FILEIO);
201 + flush_write_file(fd);
202 + if (do_lseek(fd,(OFF_T)len,SEEK_CUR) != offset+len) {
203 + rprintf(FERROR, "lseek failed on %s: %s, %lli, %lli, %i\n",
204 + full_fname(fname), strerror(errno), do_lseek(fd,0,SEEK_CUR), (offset+len), i);
205 + exit_cleanup(RERR_FILEIO);
211 flush_write_file(fd);
213 +#ifdef HAVE_FTRUNCATE
215 + ftruncate(fd, offset);
219 end_progress(total_size);
221 @@ -414,44 +429,59 @@ int recv_files(int f_in,struct file_list
225 - if (!get_tmpname(fnametmp,fname)) {
227 - unmap_file(mapbuf);
232 + /* We now check to see if we are writing file "inplace" */
234 + fd2 = do_open(fnamecmp, O_WRONLY|O_CREAT, 0);
236 + rsyserr(FERROR, errno, "open %s failed",
237 + full_fname(fnamecmp));
238 + receive_data(f_in,mapbuf,-1,NULL,file->length);
240 + unmap_file(mapbuf);
246 + if (!get_tmpname(fnametmp,fname)) {
248 + unmap_file(mapbuf);
254 - strlcpy(template, fnametmp, sizeof template);
255 + strlcpy(template, fnametmp, sizeof template);
257 - /* we initially set the perms without the
258 - * setuid/setgid bits to ensure that there is no race
259 - * condition. They are then correctly updated after
260 - * the lchown. Thanks to snabb@epipe.fi for pointing
261 - * this out. We also set it initially without group
262 - * access because of a similar race condition. */
263 - fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
265 - /* in most cases parent directories will already exist
266 - * because their information should have been previously
267 - * transferred, but that may not be the case with -R */
268 - if (fd2 == -1 && relative_paths && errno == ENOENT &&
269 - create_directory_path(fnametmp, orig_umask) == 0) {
270 - strlcpy(fnametmp, template, sizeof fnametmp);
271 + /* we initially set the perms without the
272 + * setuid/setgid bits to ensure that there is no race
273 + * condition. They are then correctly updated after
274 + * the lchown. Thanks to snabb@epipe.fi for pointing
275 + * this out. We also set it initially without group
276 + * access because of a similar race condition. */
277 fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
280 - rsyserr(FERROR, errno, "mkstemp %s failed",
281 - full_fname(fnametmp));
282 - receive_data(f_in,mapbuf,-1,NULL,file->length);
284 - unmap_file(mapbuf);
290 - cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2);
291 + /* in most cases parent directories will already exist
292 + * because their information should have been previously
293 + * transferred, but that may not be the case with -R */
294 + if (fd2 == -1 && relative_paths && errno == ENOENT
295 + && create_directory_path(fnametmp, orig_umask) == 0) {
296 + strlcpy(fnametmp, template, sizeof fnametmp);
297 + fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
300 + rsyserr(FERROR, errno, "mkstemp %s failed",
301 + full_fname(fnametmp));
302 + receive_data(f_in,mapbuf,-1,NULL,file->length);
304 + unmap_file(mapbuf);
310 + cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2);
313 if (!am_server && verbose)
314 rprintf(FINFO, "%s\n", fname);
315 --- orig/rsync.c 2004-07-02 18:06:32
316 +++ rsync.c 2004-07-03 20:19:54
317 @@ -34,6 +34,7 @@ extern int force_delete;
319 extern int make_backups;
320 extern char *backup_dir;
325 @@ -239,6 +240,13 @@ void finish_transfer(char *fname, char *
326 if (make_backups && !make_backup(fname))
331 + rprintf(FINFO, "finishing %s\n", fname);
332 + set_perms(fname, file, NULL, 0);
336 /* move tmp file over real file */
338 rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
339 --- orig/rsync.yo 2004-06-17 06:32:00
340 +++ rsync.yo 2004-07-03 20:19:55
341 @@ -289,6 +289,7 @@ verb(
342 --backup-dir make backups into this directory
343 --suffix=SUFFIX backup suffix (default ~ w/o --backup-dir)
344 -u, --update update only (don't overwrite newer files)
345 + --inplace update the destination file inplace
346 -K, --keep-dirlinks treat symlinked dir on receiver as dir
347 -l, --links copy symlinks as symlinks
348 -L, --copy-links copy the referent of all symlinks
349 @@ -484,6 +485,17 @@ dit(bf(-K, --keep-dirlinks)) On the rece
350 pointing to a directory, it will be treated as matching a directory
353 +dit(bf(--inplace)) This causes rsync not to create a new copy of the file
354 +and then move it into place. Instead rsync will overwrite the existing
355 +file, meaning that the rsync algorithm can't extract the full ammount of
356 +network reduction it might otherwise.
358 +This option is useful for transfer of large files with block based changes
359 +and also on systems that are disk bound not network bound.
361 +WARNING: If the transfer is interrupted, you will have an inconsistent file
362 +and the transfer should be run again.
364 dit(bf(-l, --links)) When symlinks are encountered, recreate the
365 symlink on the destination.