Commit | Line | Data |
---|---|---|
a2d23604 | 1 | Patch from Mark Curtis to implement the --inplace option. |
c46f8a95 | 2 | Improved by Wayne Davison. |
a2d23604 | 3 | |
c46f8a95 WD |
4 | Run these commands after applying the patch: |
5 | ||
6 | autoconf | |
7 | autoheader | |
8 | ./configure | |
ec4215e6 WD |
9 | make |
10 | ||
11 | Optional: | |
12 | ||
13 | make rsync.1 | |
c46f8a95 | 14 | |
13bed3dd WD |
15 | --- orig/configure.in 2004-04-30 18:04:07 |
16 | +++ configure.in 2004-07-03 20:19:54 | |
c46f8a95 WD |
17 | @@ -442,7 +442,7 @@ dnl AC_FUNC_MEMCMP |
18 | AC_FUNC_UTIME_NULL | |
19 | AC_FUNC_ALLOCA | |
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) | |
25 | ||
9be39c35 | 26 | --- orig/match.c 2004-07-15 02:21:10 |
217abd66 | 27 | +++ match.c 2004-07-16 19:39:08 |
7b675ff5 | 28 | @@ -23,6 +23,7 @@ extern int verbose; |
a2d23604 WD |
29 | extern int am_server; |
30 | extern int do_progress; | |
7b675ff5 | 31 | extern int checksum_seed; |
a2d23604 WD |
32 | +extern int inplace; |
33 | ||
34 | typedef unsigned short tag; | |
35 | ||
55add4e9 WD |
36 | @@ -200,6 +201,12 @@ static void hash_search(int f,struct sum |
37 | if (l != s->sums[i].len) | |
a2d23604 WD |
38 | continue; |
39 | ||
c46f8a95 WD |
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 | |
217abd66 | 43 | + && !(s->sums[i].flags & SUMFLG_SAME_OFFSET)) |
55add4e9 WD |
44 | + continue; |
45 | + | |
a2d23604 | 46 | if (verbose > 3) |
55add4e9 WD |
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 | |
c46f8a95 WD |
50 | continue; |
51 | } | |
52 | ||
13bed3dd WD |
53 | + /* If inplace is enabled, the best possible match is |
54 | + * one with an identical offset, so we prefer that over | |
d5416699 | 55 | + * the following want_i optimization. */ |
ec4215e6 | 56 | + if (inplace) { |
13bed3dd | 57 | + do { |
ec4215e6 WD |
58 | + size_t i2 = targets[j].i; |
59 | + if (s->sums[i2].offset != offset) | |
c46f8a95 | 60 | + continue; |
ec4215e6 WD |
61 | + if (i2 != i) { |
62 | + if (sum != s->sums[i2].sum1) | |
63 | + break; | |
64 | + if (memcmp(sum2, s->sums[i2].sum2, | |
65 | + s->s2length) != 0) | |
66 | + break; | |
67 | + i = i2; | |
c46f8a95 | 68 | + } |
217abd66 | 69 | + /* This chunk was at the same offset on |
ec4215e6 | 70 | + * both the sender and the receiver. */ |
217abd66 | 71 | + s->sums[i].flags |= SUMFLG_SAME_OFFSET; |
d5416699 | 72 | + goto set_want_i; |
13bed3dd | 73 | + } while (++j < s->count && targets[j].t == t); |
ec4215e6 | 74 | + } |
13bed3dd WD |
75 | + |
76 | /* we've found a match, but now check to see | |
d5416699 WD |
77 | * if want_i can hint at a better match. */ |
78 | if (i != want_i && want_i < s->count | |
217abd66 WD |
79 | + && (!inplace || s->sums[want_i].offset >= offset |
80 | + || s->sums[want_i].flags & SUMFLG_SAME_OFFSET) | |
d5416699 WD |
81 | && sum == s->sums[want_i].sum1 |
82 | && memcmp(sum2, s->sums[want_i].sum2, s->s2length) == 0) { | |
ec4215e6 WD |
83 | /* we've found an adjacent match - the RLL coder |
84 | * will be happy */ | |
d5416699 | 85 | i = want_i; |
ec4215e6 | 86 | } |
d5416699 WD |
87 | + set_want_i: |
88 | want_i = i + 1; | |
ec4215e6 WD |
89 | |
90 | matched(f,s,buf,offset,i); | |
217abd66 | 91 | --- orig/options.c 2004-07-16 19:35:29 |
13bed3dd | 92 | +++ options.c 2004-07-03 20:19:54 |
125d7fca | 93 | @@ -94,6 +94,7 @@ int ignore_errors = 0; |
a2d23604 WD |
94 | int modify_window = 0; |
95 | int blocking_io = -1; | |
96 | int checksum_seed = 0; | |
97 | +int inplace = 0; | |
98 | unsigned int block_size = 0; | |
99 | ||
100 | ||
9be39c35 | 101 | @@ -148,6 +149,7 @@ char *bind_address; |
c46f8a95 WD |
102 | static void print_rsync_version(enum logcode f) |
103 | { | |
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 "; | |
9be39c35 | 109 | @@ -157,6 +159,10 @@ static void print_rsync_version(enum log |
c46f8a95 WD |
110 | got_socketpair = ""; |
111 | #endif | |
112 | ||
113 | +#if HAVE_FTRUNCATE | |
114 | + have_inplace = ""; | |
115 | +#endif | |
116 | + | |
117 | #if SUPPORT_HARD_LINKS | |
118 | hardlinks = ""; | |
119 | #endif | |
9be39c35 | 120 | @@ -182,8 +188,8 @@ static void print_rsync_version(enum log |
c46f8a95 WD |
121 | /* Note that this field may not have type ino_t. It depends |
122 | * on the complicated interaction between largefile feature | |
123 | * macros. */ | |
124 | - rprintf(f, " %sIPv6, %d-bit system inums, %d-bit internal inums\n", | |
125 | - ipv6, | |
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 | |
9be39c35 | 131 | @@ -233,6 +239,7 @@ void usage(enum logcode F) |
a2d23604 WD |
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"); | |
c46f8a95 | 135 | + rprintf(F," --inplace update the destination file inplace (see man page)\n"); |
125d7fca | 136 | rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); |
a2d23604 WD |
137 | rprintf(F," -l, --links copy symlinks as symlinks\n"); |
138 | rprintf(F," -L, --copy-links copy the referent of all symlinks\n"); | |
9be39c35 | 139 | @@ -340,6 +347,7 @@ static struct poptOption long_options[] |
125d7fca WD |
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 }, | |
a2d23604 | 143 | + {"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 }, |
125d7fca WD |
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 }, | |
217abd66 | 147 | @@ -754,6 +762,18 @@ int parse_arguments(int *argc, const cha |
78114162 WD |
148 | bwlimit_writemax = 512; |
149 | } | |
a2d23604 | 150 | |
c46f8a95 WD |
151 | + if (inplace) { |
152 | +#if HAVE_FTRUNCATE | |
153 | + if (keep_partial) | |
154 | + keep_partial = 0; | |
155 | +#else | |
156 | + snprintf(err_buf, sizeof err_buf, | |
157 | + "inplace is not supported on this %s\n", | |
158 | + am_server ? "server" : "client"); | |
159 | + return 0; | |
160 | +#endif | |
161 | + } | |
a2d23604 WD |
162 | + |
163 | if (files_from) { | |
164 | char *colon; | |
165 | if (*argc != 2 && !(am_server && am_sender && *argc == 1)) { | |
217abd66 | 166 | @@ -971,6 +991,9 @@ void server_options(char **args,int *arg |
a2d23604 WD |
167 | if (opt_ignore_existing && am_sender) |
168 | args[ac++] = "--ignore-existing"; | |
7b675ff5 | 169 | |
a2d23604 WD |
170 | + if (inplace) |
171 | + args[ac++] = "--inplace"; | |
7b675ff5 | 172 | + |
a2d23604 WD |
173 | if (tmpdir) { |
174 | args[ac++] = "--temp-dir"; | |
7b675ff5 | 175 | args[ac++] = tmpdir; |
9be39c35 | 176 | --- orig/receiver.c 2004-07-14 17:12:06 |
13bed3dd | 177 | +++ receiver.c 2004-07-03 20:19:54 |
7628f156 | 178 | @@ -48,6 +48,7 @@ extern int ignore_errors; |
a2d23604 | 179 | extern int orig_umask; |
7f2baf27 | 180 | extern int keep_partial; |
7b675ff5 | 181 | extern int checksum_seed; |
a2d23604 WD |
182 | +extern int inplace; |
183 | ||
184 | static void delete_one(char *fn, int is_dir) | |
185 | { | |
c46f8a95 | 186 | @@ -255,16 +256,30 @@ static int receive_data(int f_in,struct |
a2d23604 WD |
187 | sum_update(map,len); |
188 | } | |
189 | ||
c46f8a95 | 190 | - if (fd != -1 && write_file(fd, map, len) != (int)len) { |
fe6407b5 WD |
191 | - rsyserr(FERROR, errno, "write failed on %s", |
192 | - full_fname(fname)); | |
a2d23604 WD |
193 | - exit_cleanup(RERR_FILEIO); |
194 | + if (!inplace || offset != offset2) { | |
c46f8a95 | 195 | + if (fd != -1 && write_file(fd, map, len) != (int)len) { |
fe6407b5 WD |
196 | + rsyserr(FERROR, errno, "write failed on %s", |
197 | + full_fname(fname)); | |
a2d23604 WD |
198 | + exit_cleanup(RERR_FILEIO); |
199 | + } | |
200 | + } else { | |
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); | |
206 | + } | |
207 | } | |
208 | offset += len; | |
209 | } | |
210 | ||
211 | flush_write_file(fd); | |
212 | ||
c46f8a95 | 213 | +#ifdef HAVE_FTRUNCATE |
a2d23604 WD |
214 | + if (inplace) |
215 | + ftruncate(fd, offset); | |
c46f8a95 | 216 | +#endif |
a2d23604 WD |
217 | + |
218 | if (do_progress) | |
219 | end_progress(total_size); | |
220 | ||
9be39c35 | 221 | @@ -414,44 +429,59 @@ int recv_files(int f_in, struct file_lis |
a2d23604 WD |
222 | } else |
223 | mapbuf = NULL; | |
224 | ||
225 | - if (!get_tmpname(fnametmp,fname)) { | |
c46f8a95 WD |
226 | - if (mapbuf) |
227 | - unmap_file(mapbuf); | |
228 | - if (fd1 != -1) | |
229 | - close(fd1); | |
a2d23604 WD |
230 | - continue; |
231 | - } | |
232 | + /* We now check to see if we are writing file "inplace" */ | |
233 | + if (inplace) { | |
234 | + fd2 = do_open(fnamecmp, O_WRONLY|O_CREAT, 0); | |
235 | + if (fd2 == -1) { | |
fe6407b5 | 236 | + rsyserr(FERROR, errno, "open %s failed", |
c46f8a95 | 237 | + full_fname(fnamecmp)); |
a2d23604 | 238 | + receive_data(f_in,mapbuf,-1,NULL,file->length); |
c46f8a95 WD |
239 | + if (mapbuf) |
240 | + unmap_file(mapbuf); | |
241 | + if (fd1 != -1) | |
242 | + close(fd1); | |
a2d23604 WD |
243 | + continue; |
244 | + } | |
245 | + } else { | |
246 | + if (!get_tmpname(fnametmp,fname)) { | |
c46f8a95 WD |
247 | + if (mapbuf) |
248 | + unmap_file(mapbuf); | |
249 | + if (fd1 != -1) | |
250 | + close(fd1); | |
a2d23604 WD |
251 | + continue; |
252 | + } | |
253 | ||
254 | - strlcpy(template, fnametmp, sizeof template); | |
255 | + strlcpy(template, fnametmp, sizeof template); | |
256 | ||
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); | |
264 | - | |
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); | |
278 | - } | |
279 | - if (fd2 == -1) { | |
fe6407b5 WD |
280 | - rsyserr(FERROR, errno, "mkstemp %s failed", |
281 | - full_fname(fnametmp)); | |
a2d23604 | 282 | - receive_data(f_in,mapbuf,-1,NULL,file->length); |
c46f8a95 WD |
283 | - if (mapbuf) |
284 | - unmap_file(mapbuf); | |
285 | - if (fd1 != -1) | |
286 | - close(fd1); | |
a2d23604 | 287 | - continue; |
c46f8a95 WD |
288 | - } |
289 | ||
290 | - cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2); | |
a2d23604 WD |
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); | |
298 | + } | |
299 | + if (fd2 == -1) { | |
fe6407b5 WD |
300 | + rsyserr(FERROR, errno, "mkstemp %s failed", |
301 | + full_fname(fnametmp)); | |
a2d23604 | 302 | + receive_data(f_in,mapbuf,-1,NULL,file->length); |
c46f8a95 WD |
303 | + if (mapbuf) |
304 | + unmap_file(mapbuf); | |
305 | + if (fd1 != -1) | |
306 | + close(fd1); | |
a2d23604 WD |
307 | + continue; |
308 | + } | |
c46f8a95 WD |
309 | + |
310 | + cleanup_set(fnametmp, fname, file, mapbuf, fd1, fd2); | |
311 | + } | |
a2d23604 | 312 | |
c46f8a95 WD |
313 | if (!am_server && verbose) |
314 | rprintf(FINFO, "%s\n", fname); | |
13bed3dd WD |
315 | --- orig/rsync.c 2004-07-02 18:06:32 |
316 | +++ rsync.c 2004-07-03 20:19:54 | |
7b675ff5 WD |
317 | @@ -34,6 +34,7 @@ extern int force_delete; |
318 | extern int recurse; | |
a2d23604 | 319 | extern int make_backups; |
7b675ff5 | 320 | extern char *backup_dir; |
a2d23604 WD |
321 | +extern int inplace; |
322 | ||
323 | ||
324 | /* | |
c46f8a95 | 325 | @@ -239,6 +240,13 @@ void finish_transfer(char *fname, char * |
a2d23604 WD |
326 | if (make_backups && !make_backup(fname)) |
327 | return; | |
7b675ff5 | 328 | |
a2d23604 | 329 | + if (inplace) { |
c46f8a95 WD |
330 | + if (verbose > 2) |
331 | + rprintf(FINFO, "finishing %s\n", fname); | |
332 | + set_perms(fname, file, NULL, 0); | |
a2d23604 WD |
333 | + return; |
334 | + } | |
7b675ff5 | 335 | + |
a2d23604 | 336 | /* move tmp file over real file */ |
c46f8a95 WD |
337 | if (verbose > 2) |
338 | rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname); | |
217abd66 WD |
339 | --- orig/rsync.h 2004-07-07 08:27:00 |
340 | +++ rsync.h 2004-07-16 19:36:20 | |
341 | @@ -458,11 +458,13 @@ struct file_list { | |
342 | struct file_struct **files; | |
343 | }; | |
344 | ||
345 | +#define SUMFLG_SAME_OFFSET (1<<0) | |
346 | + | |
347 | struct sum_buf { | |
348 | OFF_T offset; /**< offset in file of this chunk */ | |
349 | unsigned int len; /**< length of chunk of file */ | |
350 | - int i; /**< index of this chunk */ | |
351 | uint32 sum1; /**< simple checksum */ | |
352 | + short flags; /**< flag bits */ | |
353 | char sum2[SUM_LENGTH]; /**< checksum */ | |
354 | }; | |
355 | ||
356 | --- orig/rsync.yo 2004-07-16 19:35:29 | |
13bed3dd | 357 | +++ rsync.yo 2004-07-03 20:19:55 |
a2d23604 WD |
358 | @@ -289,6 +289,7 @@ verb( |
359 | --backup-dir make backups into this directory | |
360 | --suffix=SUFFIX backup suffix (default ~ w/o --backup-dir) | |
361 | -u, --update update only (don't overwrite newer files) | |
362 | + --inplace update the destination file inplace | |
125d7fca | 363 | -K, --keep-dirlinks treat symlinked dir on receiver as dir |
a2d23604 WD |
364 | -l, --links copy symlinks as symlinks |
365 | -L, --copy-links copy the referent of all symlinks | |
125d7fca WD |
366 | @@ -484,6 +485,17 @@ dit(bf(-K, --keep-dirlinks)) On the rece |
367 | pointing to a directory, it will be treated as matching a directory | |
368 | from the sender. | |
7b675ff5 | 369 | |
a2d23604 WD |
370 | +dit(bf(--inplace)) This causes rsync not to create a new copy of the file |
371 | +and then move it into place. Instead rsync will overwrite the existing | |
372 | +file, meaning that the rsync algorithm can't extract the full ammount of | |
373 | +network reduction it might otherwise. | |
374 | + | |
375 | +This option is useful for transfer of large files with block based changes | |
376 | +and also on systems that are disk bound not network bound. | |
377 | + | |
378 | +WARNING: If the transfer is interrupted, you will have an inconsistent file | |
379 | +and the transfer should be run again. | |
7b675ff5 | 380 | + |
a2d23604 WD |
381 | dit(bf(-l, --links)) When symlinks are encountered, recreate the |
382 | symlink on the destination. | |
7b675ff5 | 383 | |
217abd66 WD |
384 | --- orig/sender.c 2004-07-15 02:21:11 |
385 | +++ sender.c 2004-07-16 19:40:59 | |
386 | @@ -85,7 +85,7 @@ static struct sum_struct *receive_sums(i | |
387 | read_buf(f, s->sums[i].sum2, s->s2length); | |
388 | ||
389 | s->sums[i].offset = offset; | |
390 | - s->sums[i].i = i; | |
391 | + s->sums[i].flags = 0; | |
392 | ||
393 | if (i == (int) s->count-1 && s->remainder != 0) { | |
394 | s->sums[i].len = s->remainder; |