Implement a --partial-dir=DIR option.
[rsync/rsync-patches.git] / partial-dir.diff
1 --- orig/cleanup.c      2004-07-20 21:36:07
2 +++ cleanup.c   2004-07-23 19:19:47
3 @@ -24,6 +24,7 @@
4  extern int io_error;
5  extern int keep_partial;
6  extern int log_got_error;
7 +extern char *partial_dir;
8  
9  /**
10   * Close all open sockets and files, allowing a (somewhat) graceful
11 @@ -113,6 +114,8 @@ void _exit_cleanup(int code, const char 
12  
13         if (cleanup_got_literal && cleanup_fname && keep_partial) {
14                 char *fname = cleanup_fname;
15 +               if (partial_dir)
16 +                       do_mkdir(partial_dir, 0700);
17                 cleanup_fname = NULL;
18                 if (cleanup_fd_r != -1)
19                         close(cleanup_fd_r);
20 --- orig/generator.c    2004-07-23 17:16:12
21 +++ generator.c 2004-07-23 19:19:47
22 @@ -42,6 +42,7 @@ extern int size_only;
23  extern int io_timeout;
24  extern int protocol_version;
25  extern int always_checksum;
26 +extern char *partial_dir;
27  extern char *compare_dest;
28  extern int link_dest;
29  extern int whole_file;
30 @@ -413,6 +414,21 @@ static void recv_generator(char *fname, 
31  
32         fnamecmp = fname;
33  
34 +       if (partial_dir) {
35 +               STRUCT_STAT st2;
36 +               char *fn = strrchr(fname, '/');
37 +               if (fn)
38 +                       fn++;
39 +               else
40 +                       fn = fname;
41 +               pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, partial_dir, fn);
42 +               if (link_stat(fnamecmpbuf, &st2, 0) == 0 && S_ISREG(st2.st_mode)) {
43 +                       statret = 0;
44 +                       st = st2;
45 +                       fnamecmp = fnamecmpbuf;
46 +               }
47 +       }
48 +
49         if (statret == -1 && compare_dest != NULL) {
50                 /* try the file at compare_dest instead */
51                 int saveerrno = errno;
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 @@ -770,6 +773,11 @@ int parse_arguments(int *argc, const cha
79  
80         if (inplace) {
81  #if HAVE_FTRUNCATE
82 +               if (partial_dir) {
83 +                       snprintf(err_buf, sizeof err_buf,
84 +                                "--inplace cannot be used with --partial-dir\n");
85 +                       return 0;
86 +               }
87                 keep_partial = 0;
88  #else
89                 snprintf(err_buf, sizeof err_buf,
90 @@ -777,7 +785,8 @@ int parse_arguments(int *argc, const cha
91                          am_server ? "server" : "client");
92                 return 0;
93  #endif
94 -       }
95 +       } else if (partial_dir)
96 +               keep_partial = 1;
97  
98         if (files_from) {
99                 char *colon;
100 @@ -969,7 +978,10 @@ void server_options(char **args,int *arg
101                 args[ac++] = arg;
102         }
103  
104 -       if (keep_partial)
105 +       if (partial_dir) {
106 +               args[ac++] = "--partial-dir";
107 +               args[ac++] = partial_dir;
108 +       } else if (keep_partial)
109                 args[ac++] = "--partial";
110  
111         if (force_delete)
112 --- orig/receiver.c     2004-07-23 17:16:13
113 +++ receiver.c  2004-07-23 19:19:48
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;
122 @@ -339,7 +340,7 @@ int recv_files(int f_in, struct file_lis
123         char template[MAXPATHLEN];
124         char fnametmp[MAXPATHLEN];
125         char *fnamecmp;
126 -       char fnamecmpbuf[MAXPATHLEN];
127 +       char fnamecmpbuf[MAXPATHLEN], partialbuf[MAXPATHLEN];
128         struct file_struct *file;
129         struct stats initial_stats;
130         int save_make_backups = make_backups;
131 @@ -406,8 +407,6 @@ int recv_files(int f_in, struct file_lis
132                 if (verbose > 2)
133                         rprintf(FINFO,"recv_files(%s)\n",fname);
134  
135 -               fnamecmp = fname;
136 -
137                 if (read_batch) {
138                         while (i > next_gen_i) {
139                                 next_gen_i = read_int(batch_gen_fd);
140 @@ -434,9 +433,25 @@ int recv_files(int f_in, struct file_lis
141                         continue;
142                 }
143  
144 +               if (partial_dir) {
145 +                       char *fn = strrchr(fname, '/');
146 +                       if (fn)
147 +                               fn++;
148 +                       else
149 +                               fn = fname;
150 +                       pathjoin(partialbuf, sizeof partialbuf, partial_dir, fn);
151 +                       fnamecmp = partialbuf;
152 +               } else
153 +                       fnamecmp = fname;
154 +
155                 /* open the file */
156                 fd1 = do_open(fnamecmp, O_RDONLY, 0);
157  
158 +               if (fd1 == -1 && partial_dir) {
159 +                       fnamecmp = fname;
160 +                       fd1 = do_open(fnamecmp, O_RDONLY, 0);
161 +               }
162 +
163                 if (fd1 == -1 && compare_dest != NULL) {
164                         /* try the file at compare_dest instead */
165                         pathjoin(fnamecmpbuf, sizeof fnamecmpbuf,
166 @@ -524,7 +539,8 @@ int recv_files(int f_in, struct file_lis
167                                 continue;
168                         }
169  
170 -                       cleanup_set(fnametmp, fname, file, fd1, fd2);
171 +                       cleanup_set(fnametmp, partial_dir ? partialbuf : fname,
172 +                                   file, fd1, fd2);
173                 }
174  
175                 if (!am_server && verbose)
176 @@ -549,6 +565,12 @@ int recv_files(int f_in, struct file_lis
177                 else
178                         do_unlink(fnametmp);
179  
180 +               if (fnamecmp == partialbuf) {
181 +                       do_unlink(partialbuf);
182 +                       if (*partialbuf != '/')
183 +                               do_rmdir(partial_dir);
184 +               }
185 +
186                 cleanup_disable();
187  
188                 if (!recv_ok) {
189 --- orig/rsync.yo       2004-07-23 17:16:13
190 +++ rsync.yo    2004-07-23 19:36:41
191 @@ -317,6 +317,7 @@ verb(
192       --ignore-errors         delete even if there are I/O errors
193       --max-delete=NUM        don't delete more than NUM files
194       --partial               keep partially transferred files
195 +     --partial-dir=DIR       put a partially transferred file into DIR
196       --force                 force deletion of dirs even if not empty
197       --numeric-ids           don't map uid/gid values by user/group name
198       --timeout=TIME          set I/O timeout in seconds
199 @@ -865,6 +866,21 @@ it is more desirable to keep partially t
200  --partial option tells rsync to keep the partial file which should
201  make a subsequent transfer of the rest of the file much faster.
202  
203 +dit(bf(--partial-dir=DIR)) Turns on --partial mode, but tells rsync to
204 +put a partially transferred file into DIR instead of writing out the
205 +file to the destination dir.  Rsync will also use a file found in this
206 +dir as data to speed up a subsequent transfer.
207 +
208 +Rsync will create the dir if it is missing, so feel free to use a
209 +relative path (such as quote(--partial-dir=.rsync-partial)) if you
210 +want the file put into a directory relative to the current directory
211 +in the tree (rsync will also try to remove the DIR if a partial file
212 +was found and the DIR was specified as a relative path).
213 +
214 +If you want to delete files on the destination, be sure to use
215 +--delete-after instead of --delete or the partial file may be deleted
216 +before it can be used.
217 +
218  dit(bf(--progress)) This option tells rsync to print information
219  showing the progress of the transfer. This gives a bored user
220  something to watch.