Commit | Line | Data |
---|---|---|
482eaa96 WD |
1 | You must run "make proto" after applying this patch. |
2 | ||
df8c196d | 3 | --- orig/cleanup.c 2004-07-20 21:36:07 |
f8c97b53 WD |
4 | +++ cleanup.c 2004-07-27 23:32:17 |
5 | @@ -111,7 +111,8 @@ void _exit_cleanup(int code, const char | |
1be76832 WD |
6 | } |
7 | } | |
df8c196d | 8 | |
1be76832 WD |
9 | - if (cleanup_got_literal && cleanup_fname && keep_partial) { |
10 | + if (cleanup_got_literal && cleanup_fname && keep_partial | |
f8c97b53 | 11 | + && handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) { |
df8c196d | 12 | char *fname = cleanup_fname; |
df8c196d WD |
13 | cleanup_fname = NULL; |
14 | if (cleanup_fd_r != -1) | |
3008e4d6 WD |
15 | --- orig/generator.c 2004-07-28 10:05:29 |
16 | +++ generator.c 2004-07-28 09:58:28 | |
df8c196d WD |
17 | @@ -42,6 +42,7 @@ extern int size_only; |
18 | extern int io_timeout; | |
19 | extern int protocol_version; | |
20 | extern int always_checksum; | |
21 | +extern char *partial_dir; | |
22 | extern char *compare_dest; | |
23 | extern int link_dest; | |
24 | extern int whole_file; | |
3008e4d6 | 25 | @@ -496,6 +497,16 @@ static void recv_generator(char *fname, |
482eaa96 WD |
26 | return; |
27 | } | |
df8c196d WD |
28 | |
29 | + if (partial_dir) { | |
30 | + STRUCT_STAT st2; | |
3008e4d6 WD |
31 | + char *partialptr = partial_dir_fname(fname); |
32 | + if (partialptr && link_stat(partialptr, &st2, 0) == 0 | |
482eaa96 | 33 | + && S_ISREG(st2.st_mode)) { |
df8c196d | 34 | + st = st2; |
3008e4d6 WD |
35 | + fnamecmp = partialptr; |
36 | + } | |
37 | + } | |
38 | + | |
39 | /* open the file */ | |
40 | fd = do_open(fnamecmp, O_RDONLY, 0); | |
482eaa96 | 41 | |
df8c196d | 42 | --- orig/options.c 2004-07-23 17:16:13 |
f8c97b53 | 43 | +++ options.c 2004-07-26 16:43:48 |
df8c196d WD |
44 | @@ -118,6 +118,7 @@ unsigned int backup_dir_remainder; |
45 | ||
46 | char *backup_suffix = NULL; | |
47 | char *tmpdir = NULL; | |
48 | +char *partial_dir = NULL; | |
49 | char *compare_dest = NULL; | |
50 | char *config_file = NULL; | |
51 | char *shell_cmd = NULL; | |
52 | @@ -268,6 +269,7 @@ void usage(enum logcode F) | |
53 | rprintf(F," --ignore-errors delete even if there are I/O errors\n"); | |
54 | rprintf(F," --max-delete=NUM don't delete more than NUM files\n"); | |
55 | rprintf(F," --partial keep partially transferred files\n"); | |
56 | + rprintf(F," --partial-dir=DIR put a partially transferred file into DIR\n"); | |
57 | rprintf(F," --force force deletion of directories even if not empty\n"); | |
58 | rprintf(F," --numeric-ids don't map uid/gid values by user/group name\n"); | |
59 | rprintf(F," --timeout=TIME set I/O timeout in seconds\n"); | |
60 | @@ -383,6 +385,7 @@ static struct poptOption long_options[] | |
61 | {"stats", 0, POPT_ARG_NONE, &do_stats, 0, 0, 0 }, | |
62 | {"progress", 0, POPT_ARG_NONE, &do_progress, 0, 0, 0 }, | |
63 | {"partial", 0, POPT_ARG_NONE, &keep_partial, 0, 0, 0 }, | |
64 | + {"partial-dir", 0, POPT_ARG_STRING, &partial_dir, 0, 0, 0 }, | |
65 | {"ignore-errors", 0, POPT_ARG_NONE, &ignore_errors, 0, 0, 0 }, | |
66 | {"blocking-io", 0, POPT_ARG_VAL, &blocking_io, 1, 0, 0 }, | |
67 | {"no-blocking-io", 0, POPT_ARG_VAL, &blocking_io, 0, 0, 0 }, | |
482eaa96 WD |
68 | @@ -718,6 +721,8 @@ int parse_arguments(int *argc, const cha |
69 | (*argv)[i] = alloc_sanitize_path((*argv)[i], NULL); | |
70 | if (tmpdir) | |
71 | tmpdir = alloc_sanitize_path(tmpdir, curr_dir); | |
72 | + if (partial_dir) | |
73 | + partial_dir = alloc_sanitize_path(partial_dir, curr_dir); | |
74 | if (compare_dest) | |
75 | compare_dest = alloc_sanitize_path(compare_dest, curr_dir); | |
76 | if (backup_dir) | |
77 | @@ -770,6 +775,11 @@ int parse_arguments(int *argc, const cha | |
df8c196d WD |
78 | |
79 | if (inplace) { | |
80 | #if HAVE_FTRUNCATE | |
81 | + if (partial_dir) { | |
82 | + snprintf(err_buf, sizeof err_buf, | |
83 | + "--inplace cannot be used with --partial-dir\n"); | |
84 | + return 0; | |
85 | + } | |
86 | keep_partial = 0; | |
87 | #else | |
88 | snprintf(err_buf, sizeof err_buf, | |
7684ebda | 89 | @@ -777,6 +787,10 @@ int parse_arguments(int *argc, const cha |
df8c196d WD |
90 | am_server ? "server" : "client"); |
91 | return 0; | |
92 | #endif | |
7684ebda WD |
93 | + } else if (partial_dir) { |
94 | + if (strcmp(partial_dir, ".") == 0) | |
95 | + partial_dir = NULL; | |
df8c196d | 96 | + keep_partial = 1; |
7684ebda | 97 | } |
df8c196d WD |
98 | |
99 | if (files_from) { | |
7684ebda | 100 | @@ -969,7 +983,10 @@ void server_options(char **args,int *arg |
df8c196d WD |
101 | args[ac++] = arg; |
102 | } | |
103 | ||
104 | - if (keep_partial) | |
0fe8e93e | 105 | + if (partial_dir && am_sender) { |
df8c196d WD |
106 | + args[ac++] = "--partial-dir"; |
107 | + args[ac++] = partial_dir; | |
108 | + } else if (keep_partial) | |
109 | args[ac++] = "--partial"; | |
110 | ||
111 | if (force_delete) | |
f8c97b53 WD |
112 | --- orig/receiver.c 2004-07-26 16:20:00 |
113 | +++ receiver.c 2004-07-27 23:26:20 | |
df8c196d WD |
114 | @@ -38,6 +38,7 @@ extern int preserve_perms; |
115 | extern int cvs_exclude; | |
116 | extern int io_error; | |
117 | extern char *tmpdir; | |
118 | +extern char *partial_dir; | |
119 | extern char *compare_dest; | |
120 | extern int make_backups; | |
121 | extern int do_progress; | |
7684ebda | 122 | @@ -340,7 +341,7 @@ int recv_files(int f_in, struct file_lis |
482eaa96 | 123 | char *fname, fbuf[MAXPATHLEN]; |
df8c196d WD |
124 | char template[MAXPATHLEN]; |
125 | char fnametmp[MAXPATHLEN]; | |
482eaa96 WD |
126 | - char *fnamecmp; |
127 | + char *fnamecmp, *partialptr; | |
128 | char fnamecmpbuf[MAXPATHLEN]; | |
df8c196d WD |
129 | struct file_struct *file; |
130 | struct stats initial_stats; | |
7684ebda | 131 | @@ -408,8 +409,6 @@ int recv_files(int f_in, struct file_lis |
df8c196d | 132 | if (verbose > 2) |
f8c97b53 | 133 | rprintf(FINFO, "recv_files(%s)\n", safe_fname(fname)); |
df8c196d WD |
134 | |
135 | - fnamecmp = fname; | |
136 | - | |
137 | if (read_batch) { | |
138 | while (i > next_gen_i) { | |
139 | next_gen_i = read_int(batch_gen_fd); | |
7684ebda | 140 | @@ -436,9 +435,22 @@ int recv_files(int f_in, struct file_lis |
df8c196d WD |
141 | continue; |
142 | } | |
143 | ||
144 | + if (partial_dir) { | |
f8c97b53 | 145 | + if ((partialptr = partial_dir_fname(fname)) != NULL) |
482eaa96 | 146 | + fnamecmp = partialptr; |
df8c196d | 147 | + else |
482eaa96 | 148 | + fnamecmp = fname; |
df8c196d | 149 | + } else |
482eaa96 | 150 | + fnamecmp = partialptr = fname; |
df8c196d WD |
151 | + |
152 | /* open the file */ | |
153 | fd1 = do_open(fnamecmp, O_RDONLY, 0); | |
154 | ||
482eaa96 | 155 | + if (fd1 == -1 && fnamecmp != fname) { |
df8c196d WD |
156 | + fnamecmp = fname; |
157 | + fd1 = do_open(fnamecmp, O_RDONLY, 0); | |
158 | + } | |
159 | + | |
160 | if (fd1 == -1 && compare_dest != NULL) { | |
161 | /* try the file at compare_dest instead */ | |
162 | pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, | |
7684ebda | 163 | @@ -526,7 +538,8 @@ int recv_files(int f_in, struct file_lis |
df8c196d WD |
164 | continue; |
165 | } | |
166 | ||
167 | - cleanup_set(fnametmp, fname, file, fd1, fd2); | |
482eaa96 WD |
168 | + if (partialptr) |
169 | + cleanup_set(fnametmp, partialptr, file, fd1, fd2); | |
df8c196d WD |
170 | } |
171 | ||
f8c97b53 | 172 | if (!am_server && verbose) /* log the transfer */ |
7684ebda | 173 | @@ -546,10 +559,20 @@ int recv_files(int f_in, struct file_lis |
482eaa96 WD |
174 | exit_cleanup(RERR_FILEIO); |
175 | } | |
176 | ||
177 | - if (recv_ok || keep_partial || inplace) | |
0fe8e93e | 178 | + if (recv_ok || inplace) |
482eaa96 | 179 | finish_transfer(fname, fnametmp, file, recv_ok); |
0fe8e93e WD |
180 | - else |
181 | + else if (keep_partial && partialptr | |
f8c97b53 | 182 | + && handle_partial_dir(partialptr, PDIR_CREATE)) |
0fe8e93e WD |
183 | + finish_transfer(partialptr, fnametmp, file, 0); |
184 | + else { | |
185 | + partialptr = NULL; | |
df8c196d | 186 | do_unlink(fnametmp); |
0fe8e93e WD |
187 | + } |
188 | + | |
189 | + if (partialptr != fname && fnamecmp == partialptr && recv_ok) { | |
482eaa96 | 190 | + do_unlink(partialptr); |
f8c97b53 | 191 | + handle_partial_dir(partialptr, PDIR_DELETE); |
df8c196d | 192 | + } |
0fe8e93e | 193 | |
df8c196d WD |
194 | cleanup_disable(); |
195 | ||
7684ebda | 196 | @@ -557,9 +580,13 @@ int recv_files(int f_in, struct file_lis |
0fe8e93e WD |
197 | int msgtype = csum_length == SUM_LENGTH || read_batch ? |
198 | FERROR : FINFO; | |
199 | if (msgtype == FERROR || verbose) { | |
200 | - char *errstr, *redostr; | |
201 | - char *keptstr = keep_partial || inplace ? | |
202 | - "retain" : "discard"; | |
203 | + char *errstr, *redostr, *keptstr; | |
204 | + if (!(keep_partial && partialptr) && !inplace) | |
205 | + keptstr = "discarded"; | |
206 | + else if (partial_dir) | |
207 | + keptstr = "put into partial-dir"; | |
208 | + else | |
209 | + keptstr = "retained"; | |
210 | if (msgtype == FERROR) { | |
211 | errstr = "ERROR"; | |
212 | redostr = ""; | |
7684ebda | 213 | @@ -568,7 +595,7 @@ int recv_files(int f_in, struct file_lis |
0fe8e93e WD |
214 | redostr = " (will try again)"; |
215 | } | |
216 | rprintf(msgtype, | |
217 | - "%s: %s failed verification -- update %sed%s.\n", | |
218 | + "%s: %s failed verification -- update %s%s.\n", | |
f8c97b53 WD |
219 | errstr, safe_fname(fname), |
220 | keptstr, redostr); | |
0fe8e93e | 221 | } |
f8c97b53 WD |
222 | --- orig/rsync.h 2004-07-23 17:16:13 |
223 | +++ rsync.h 2004-07-27 23:23:54 | |
224 | @@ -115,6 +115,9 @@ | |
225 | #define FULL_FLUSH 1 | |
226 | #define NORMAL_FLUSH 0 | |
227 | ||
228 | +#define PDIR_CREATE 1 | |
229 | +#define PDIR_DELETE 0 | |
230 | + | |
231 | ||
232 | /* Log-message categories. FLOG is only used on the daemon side to | |
233 | * output messages to the log file. */ | |
1be76832 | 234 | --- orig/rsync.yo 2004-07-24 16:52:10 |
3008e4d6 | 235 | +++ rsync.yo 2004-07-28 02:26:19 |
df8c196d WD |
236 | @@ -317,6 +317,7 @@ verb( |
237 | --ignore-errors delete even if there are I/O errors | |
238 | --max-delete=NUM don't delete more than NUM files | |
239 | --partial keep partially transferred files | |
240 | + --partial-dir=DIR put a partially transferred file into DIR | |
241 | --force force deletion of dirs even if not empty | |
242 | --numeric-ids don't map uid/gid values by user/group name | |
243 | --timeout=TIME set I/O timeout in seconds | |
3008e4d6 | 244 | @@ -865,6 +866,29 @@ it is more desirable to keep partially t |
df8c196d WD |
245 | --partial option tells rsync to keep the partial file which should |
246 | make a subsequent transfer of the rest of the file much faster. | |
247 | ||
248 | +dit(bf(--partial-dir=DIR)) Turns on --partial mode, but tells rsync to | |
249 | +put a partially transferred file into DIR instead of writing out the | |
250 | +file to the destination dir. Rsync will also use a file found in this | |
f8c97b53 | 251 | +dir as data to speed up the transfer (i.e. when you redo the send after |
3008e4d6 WD |
252 | +rsync creates a partial file) and delete such a file after it has served |
253 | +its purpose. | |
df8c196d | 254 | + |
3008e4d6 WD |
255 | +Rsync will create the dir if it is missing (just the last dir -- not the |
256 | +whole path). This makes it easy to use a relative path (such as | |
257 | +"--partial-dir=.rsync-partial") to have rsync create the partial-directory | |
258 | +in the destination file's directory (rsync will also try to remove the DIR | |
259 | +if a partial file was found to exist at the start of the transfer and the | |
260 | +DIR was specified as a relative path). | |
df8c196d | 261 | + |
f8c97b53 | 262 | +If you are deleting files on the destination and your partial-dir is |
3008e4d6 WD |
263 | +inside the destination hierarchy, make sure you specify an exclude to |
264 | +prevent the partial file from being deleted (it could get deleted at the | |
265 | +end of the transfer when using --delete-after, or at the beginning of the | |
266 | +transfer when using --delete). E.g. "--exclude=.rsync-partial/". | |
0fe8e93e | 267 | + |
3008e4d6 WD |
268 | +IMPORTANT: the --partial-dir should not be writable by other users to |
269 | +avoid a security risk. E.g. AVOID "/tmp". | |
df8c196d WD |
270 | + |
271 | dit(bf(--progress)) This option tells rsync to print information | |
272 | showing the progress of the transfer. This gives a bored user | |
273 | something to watch. | |
1be76832 WD |
274 | --- orig/t_stub.c 2004-05-15 20:10:13 |
275 | +++ t_stub.c 2004-07-24 17:00:35 | |
276 | @@ -28,6 +28,7 @@ | |
277 | ||
278 | int modify_window = 0; | |
279 | int module_id = -1; | |
280 | +char *partial_dir; | |
281 | struct exclude_list_struct server_exclude_list; | |
282 | ||
283 | void rprintf(UNUSED(enum logcode code), const char *format, ...) | |
f8c97b53 WD |
284 | --- orig/util.c 2004-07-26 16:33:24 |
285 | +++ util.c 2004-07-27 23:25:20 | |
482eaa96 WD |
286 | @@ -31,6 +31,7 @@ extern int verbose; |
287 | extern int dry_run; | |
288 | extern int module_id; | |
289 | extern int modify_window; | |
290 | +extern char *partial_dir; | |
291 | extern struct exclude_list_struct server_exclude_list; | |
292 | ||
293 | int sanitize_paths = 0; | |
f8c97b53 | 294 | @@ -970,6 +971,66 @@ char *full_fname(const char *fn) |
482eaa96 WD |
295 | return result; |
296 | } | |
297 | ||
1be76832 | 298 | +static char partial_fname[MAXPATHLEN]; |
482eaa96 | 299 | + |
f8c97b53 | 300 | +char *partial_dir_fname(const char *fname) |
482eaa96 | 301 | +{ |
1be76832 WD |
302 | + char *t = partial_fname; |
303 | + int sz = sizeof partial_fname; | |
482eaa96 WD |
304 | + const char *fn; |
305 | + | |
306 | + if ((fn = strrchr(fname, '/')) != NULL) { | |
307 | + fn++; | |
308 | + if (*partial_dir != '/') { | |
309 | + int len = fn - fname; | |
310 | + strncpy(t, fname, len); /* safe */ | |
311 | + t += len; | |
312 | + sz -= len; | |
313 | + } | |
314 | + } else | |
315 | + fn = fname; | |
f8c97b53 | 316 | + if ((int)pathjoin(t, sz, partial_dir, fn) >= sz) |
482eaa96 | 317 | + return NULL; |
482eaa96 | 318 | + |
1be76832 | 319 | + return partial_fname; |
482eaa96 WD |
320 | +} |
321 | + | |
f8c97b53 WD |
322 | +/* If no --partial-dir option was specified, we don't need to do anything |
323 | + * (the partial-dir is essentially '.'), so just return success. */ | |
1be76832 | 324 | +int handle_partial_dir(const char *fname, int create) |
482eaa96 | 325 | +{ |
f8c97b53 | 326 | + char *fn, *dir; |
482eaa96 | 327 | + |
1be76832 WD |
328 | + if (fname != partial_fname) |
329 | + return 1; | |
482eaa96 | 330 | + if (!create && *partial_dir == '/') |
1be76832 WD |
331 | + return 1; |
332 | + if (!(fn = strrchr(partial_fname, '/'))) | |
333 | + return 1; | |
482eaa96 WD |
334 | + |
335 | + *fn = '\0'; | |
f8c97b53 | 336 | + dir = partial_fname; |
1be76832 WD |
337 | + if (create) { |
338 | + STRUCT_STAT st; | |
339 | +#if SUPPORT_LINKS | |
340 | + int statret = do_lstat(dir, &st); | |
341 | +#else | |
342 | + int statret = do_stat(dir, &st); | |
343 | +#endif | |
344 | + if (statret == 0 && !S_ISDIR(st.st_mode)) { | |
345 | + if (do_unlink(dir) < 0) | |
346 | + return 0; | |
347 | + statret = -1; | |
348 | + } | |
f8c97b53 WD |
349 | + if (statret < 0 && do_mkdir(dir, 0700) < 0) |
350 | + return 0; | |
1be76832 WD |
351 | + } else |
352 | + do_rmdir(dir); | |
482eaa96 | 353 | + *fn = '/'; |
1be76832 WD |
354 | + |
355 | + return 1; | |
482eaa96 WD |
356 | +} |
357 | + | |
358 | /** We need to supply our own strcmp function for file list comparisons | |
359 | to ensure that signed/unsigned usage is consistent between machines. */ | |
360 | int u_strcmp(const char *cs1, const char *cs2) |