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