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