Fix some fuzz in the --help text hunks.
[rsync/rsync-patches.git] / partial-dir.diff
1 You must run "make proto" after applying this patch.
2
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
13 @@ -111,7 +112,8 @@ void _exit_cleanup(int code, const char 
14                 }
15         }
16  
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))) {
20                 char *fname = cleanup_fname;
21                 cleanup_fname = NULL;
22                 if (cleanup_fd_r != -1)
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;
33 @@ -411,7 +412,18 @@ static void recv_generator(char *fname, 
34                 return;
35         }
36  
37 -       fnamecmp = fname;
38 +       if (partial_dir) {
39 +               STRUCT_STAT st2;
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)) {
44 +                       statret = 0;
45 +                       st = st2;
46 +               } else
47 +                       fnamecmp = fname;
48 +       } else
49 +               fnamecmp = fname;
50  
51         if (statret == -1 && compare_dest != NULL) {
52                 /* try the file at compare_dest instead */
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 },
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
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,
100 @@ -777,7 +787,8 @@ int parse_arguments(int *argc, const cha
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;
110 @@ -969,7 +980,10 @@ void server_options(char **args,int *arg
111                 args[ac++] = arg;
112         }
113  
114 -       if (keep_partial)
115 +       if (partial_dir && am_sender) {
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;
132 @@ -338,7 +339,7 @@ int recv_files(int f_in, struct file_lis
133         char *fname, fbuf[MAXPATHLEN];
134         char template[MAXPATHLEN];
135         char fnametmp[MAXPATHLEN];
136 -       char *fnamecmp;
137 +       char *fnamecmp, *partialptr;
138         char fnamecmpbuf[MAXPATHLEN];
139         struct file_struct *file;
140         struct stats initial_stats;
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);
150 @@ -434,9 +433,22 @@ int recv_files(int f_in, struct file_lis
151                         continue;
152                 }
153  
154 +               if (partial_dir) {
155 +                       if ((partialptr = fname_in_partial_dir(fname)) != NULL)
156 +                               fnamecmp = partialptr;
157 +                       else
158 +                               fnamecmp = fname;
159 +               } else
160 +                       fnamecmp = partialptr = fname;
161 +
162                 /* open the file */
163                 fd1 = do_open(fnamecmp, O_RDONLY, 0);
164  
165 +               if (fd1 == -1 && fnamecmp != fname) {
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,
173 @@ -524,7 +536,8 @@ int recv_files(int f_in, struct file_lis
174                                 continue;
175                         }
176  
177 -                       cleanup_set(fnametmp, fname, file, fd1, fd2);
178 +                       if (partialptr)
179 +                               cleanup_set(fnametmp, partialptr, file, fd1, fd2);
180                 }
181  
182                 if (!am_server && verbose)
183 @@ -544,10 +557,20 @@ int recv_files(int f_in, struct file_lis
184                         exit_cleanup(RERR_FILEIO);
185                 }
186  
187 -               if (recv_ok || keep_partial || inplace)
188 +               if (recv_ok || inplace)
189                         finish_transfer(fname, fnametmp, file, recv_ok);
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;
196                         do_unlink(fnametmp);
197 +               }
198 +
199 +               if (partialptr != fname && fnamecmp == partialptr && recv_ok) {
200 +                       do_unlink(partialptr);
201 +                       handle_partial_dir(partialptr, 0);
202 +               }
203  
204                 cleanup_disable();
205  
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) {
232 --- orig/rsync.yo       2004-07-24 16:52:10
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
242 @@ -865,6 +866,25 @@ it is more desirable to keep partially t
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 +
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!
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.
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, ...)
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;
288 @@ -945,6 +946,74 @@ char *full_fname(const char *fn)
289         return result;
290  }
291  
292 +static char partial_fname[MAXPATHLEN];
293 +
294 +char *fname_in_partial_dir(const char *fname)
295 +{
296 +       char *t = partial_fname;
297 +       int sz = sizeof partial_fname;
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) {
311 +               *partial_fname = '\0';
312 +               return NULL;
313 +       }
314 +
315 +       return partial_fname;
316 +}
317 +
318 +int handle_partial_dir(const char *fname, int create)
319 +{
320 +       char *fn, *dir = partial_fname;
321 +
322 +       if (fname != partial_fname)
323 +               return 1;
324 +       if (!create && *partial_dir == '/')
325 +               return 1;
326 +       if (!(fn = strrchr(partial_fname, '/')))
327 +               return 1;
328 +
329 +       *fn = '\0';
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);
355 +       *fn = '/';
356 +
357 +       return 1;
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)