Mention the popt upgrade.
[rsync/rsync.git] / generator.c
1 /* -*- c-file-style: "linux" -*-
2
3    rsync -- fast file replication program
4    
5    Copyright (C) 1996-2000 by Andrew Tridgell 
6    Copyright (C) Paul Mackerras 1996
7    Copyright (C) 2002 by Martin Pool <mbp@samba.org>
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "rsync.h"
25
26 extern int verbose;
27 extern int dry_run;
28 extern int relative_paths;
29 extern int preserve_links;
30 extern int am_root;
31 extern int preserve_devices;
32 extern int preserve_hard_links;
33 extern int update_only;
34 extern int opt_ignore_existing;
35 extern int block_size;
36 extern int csum_length;
37 extern int ignore_times;
38 extern int size_only;
39 extern int io_timeout;
40 extern int remote_version;
41 extern int always_checksum;
42 extern int modify_window;
43 extern char *compare_dest;
44
45
46 /* choose whether to skip a particular file */
47 static int skip_file(char *fname,
48                      struct file_struct *file, STRUCT_STAT *st)
49 {
50         if (st->st_size != file->length) {
51                 return 0;
52         }
53         
54         /* if always checksum is set then we use the checksum instead 
55            of the file time to determine whether to sync */
56         if (always_checksum && S_ISREG(st->st_mode)) {
57                 char sum[MD4_SUM_LENGTH];
58                 char fnamecmpdest[MAXPATHLEN];
59
60                 if (compare_dest != NULL) {
61                         if (access(fname, 0) != 0) {
62                                 snprintf(fnamecmpdest,MAXPATHLEN,"%s/%s",
63                                                     compare_dest,fname);
64                                 fname = fnamecmpdest;
65                         }
66                 }
67                 file_checksum(fname,sum,st->st_size);
68                 if (remote_version < 21) {
69                         return (memcmp(sum,file->sum,2) == 0);
70                 } else {
71                         return (memcmp(sum,file->sum,MD4_SUM_LENGTH) == 0);
72                 }
73         }
74
75         if (size_only) {
76                 return 1;
77         }
78
79         if (ignore_times) {
80                 return 0;
81         }
82
83         return (cmp_modtime(st->st_mtime,file->modtime) == 0);
84 }
85
86
87 /* use a larger block size for really big files */
88 static int adapt_block_size(struct file_struct *file, int bsize)
89 {
90         int ret;
91
92         if (bsize != BLOCK_SIZE) return bsize;
93
94         ret = file->length / (10000); /* rough heuristic */
95         ret = ret & ~15; /* multiple of 16 */
96         if (ret < bsize) ret = bsize;
97         if (ret > CHUNK_SIZE/2) ret = CHUNK_SIZE/2;
98         return ret;
99 }
100
101
102 /*
103   send a sums struct down a fd
104   */
105 static void send_sums(struct sum_struct *s, int f_out)
106 {
107         if (s) {
108                 size_t i;
109
110                 /* tell the other guy how many we are going to be
111                    doing and how many bytes there are in the last
112                    chunk */
113                 write_int(f_out, s->count);
114                 write_int(f_out, s->n);
115                 write_int(f_out, s->remainder);
116
117                 for (i = 0; i < s->count; i++) {
118                         write_int(f_out, s->sums[i].sum1);
119                         write_buf(f_out, s->sums[i].sum2, csum_length);
120                 }
121         } else {
122                 /* we don't have checksums */
123                 write_int(f_out, 0);
124                 write_int(f_out, block_size);
125                 write_int(f_out, 0);
126         }
127 }
128
129
130 /**
131  * Perhaps we want to just send an empty checksum set for this file,
132  * which will force the whole thing to be literally transferred.
133  *
134  * When do we do this?  If the user's explicitly said they
135  * want the whole thing, or if { they haven't explicitly
136  * requested a delta, and it's local but not batch mode.}
137  *
138  * Whew. */
139 static BOOL disable_deltas_p(void)
140 {
141         extern int whole_file, no_whole_file;
142         extern int local_server;
143         extern int write_batch;
144
145         assert(whole_file == 0 || whole_file == 1);
146
147         /* whole_file and no_whole_file are never both on at the same time */
148
149         if (whole_file)
150                 return True;
151         else if (no_whole_file)
152                 return False;
153         else if (write_batch)
154                 return False;
155         else
156                 return local_server;
157 }
158
159
160 /**
161  * Generate a stream of signatures/checksums that describe a buffer.
162  *
163  * Generate approximately one checksum every @p n bytes.
164  *
165  * @return Newly-allocated sum_struct
166  **/
167 static struct sum_struct *generate_sums(struct map_struct *buf, OFF_T len,
168                                         int n)
169 {
170         int i;
171         struct sum_struct *s;
172         int count;
173         int block_len = n;
174         int remainder = (len % block_len);
175         OFF_T offset = 0;
176
177         count = (len + (block_len - 1)) / block_len;
178
179         s = (struct sum_struct *) malloc(sizeof(*s));
180         if (!s)
181                 out_of_memory("generate_sums");
182
183         s->count = count;
184         s->remainder = remainder;
185         s->n = n;
186         s->flength = len;
187
188         if (count == 0) {
189                 s->sums = NULL;
190                 return s;
191         }
192
193         if (verbose > 3) {
194                 rprintf(FINFO, "count=%ld rem=%ld n=%ld flength=%.0f\n",
195                         (long) s->count, (long) s->remainder,
196                         (long) s->n, (double) s->flength);
197         }
198
199         s->sums = (struct sum_buf *) malloc(sizeof(s->sums[0]) * s->count);
200         if (!s->sums)
201                 out_of_memory("generate_sums");
202
203         for (i = 0; i < count; i++) {
204                 int n1 = MIN(len, n);
205                 char *map = map_ptr(buf, offset, n1);
206
207                 s->sums[i].sum1 = get_checksum1(map, n1);
208                 get_checksum2(map, n1, s->sums[i].sum2);
209
210                 s->sums[i].offset = offset;
211                 s->sums[i].len = n1;
212                 s->sums[i].i = i;
213
214                 if (verbose > 3)
215                         rprintf(FINFO,
216                                 "chunk[%d] offset=%.0f len=%d sum1=%08x\n",
217                                 i, (double) s->sums[i].offset,
218                                 s->sums[i].len, s->sums[i].sum1);
219
220                 len -= n1;
221                 offset += n1;
222         }
223
224         return s;
225 }
226
227
228
229 /**
230  * Acts on file number @p i from @p flist, whose name is @p fname.
231  *
232  * First fixes up permissions, then generates checksums for the file.
233  *
234  * @note This comment was added later by mbp who was trying to work it
235  * out.  It might be wrong.
236  **/ 
237 void recv_generator(char *fname, struct file_list *flist, int i, int f_out)
238 {  
239         int fd;
240         STRUCT_STAT st;
241         struct map_struct *buf;
242         struct sum_struct *s;
243         int statret;
244         struct file_struct *file = flist->files[i];
245         char *fnamecmp;
246         char fnamecmpbuf[MAXPATHLEN];
247         extern char *compare_dest;
248         extern int list_only;
249         extern int preserve_perms;
250         extern int only_existing;
251         extern int orig_umask;
252
253         if (list_only) return;
254
255         if (verbose > 2)
256                 rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
257
258         statret = link_stat(fname,&st);
259
260         if (only_existing && statret == -1 && errno == ENOENT) {
261                 /* we only want to update existing files */
262                 if (verbose > 1) rprintf(FINFO, "not creating new file \"%s\"\n",fname);
263                 return;
264         }
265
266         if (statret == 0 && 
267             !preserve_perms && 
268             (S_ISDIR(st.st_mode) == S_ISDIR(file->mode))) {
269                 /* if the file exists already and we aren't perserving
270                    presmissions then act as though the remote end sent
271                    us the file permissions we already have */
272                 file->mode = (file->mode & _S_IFMT) | (st.st_mode & ~_S_IFMT);
273         }
274
275         if (S_ISDIR(file->mode)) {
276                 /* The file to be received is a directory, so we need
277                  * to prepare appropriately.  If there is already a
278                  * file of that name and it is *not* a directory, then
279                  * we need to delete it.  If it doesn't exist, then
280                  * recursively create it. */
281           
282                 if (dry_run) return; /* XXXX -- might cause inaccuracies?? -- mbp */
283                 if (statret == 0 && !S_ISDIR(st.st_mode)) {
284                         if (robust_unlink(fname) != 0) {
285                                 rprintf(FERROR, RSYNC_NAME
286                                         ": recv_generator: unlink \"%s\" to make room for directory: %s\n",
287                                         fname,strerror(errno));
288                                 return;
289                         }
290                         statret = -1;
291                 }
292                 if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
293                         if (!(relative_paths && errno==ENOENT && 
294                               create_directory_path(fname, orig_umask)==0 && 
295                               do_mkdir(fname,file->mode)==0)) {
296                                 rprintf(FERROR, RSYNC_NAME ": recv_generator: mkdir \"%s\": %s (2)\n",
297                                         fname,strerror(errno));
298                         }
299                 }
300                 /* f_out is set to -1 when doing final directory 
301                    permission and modification time repair */
302                 if (set_perms(fname,file,NULL,0) && verbose && (f_out != -1)) 
303                         rprintf(FINFO,"%s/\n",fname);
304                 return;
305         }
306
307         if (preserve_links && S_ISLNK(file->mode)) {
308 #if SUPPORT_LINKS
309                 char lnk[MAXPATHLEN];
310                 int l;
311                 extern int safe_symlinks;
312
313                 if (safe_symlinks && unsafe_symlink(file->link, fname)) {
314                         if (verbose) {
315                                 rprintf(FINFO,"ignoring unsafe symlink \"%s\" -> \"%s\"\n",
316                                         fname,file->link);
317                         }
318                         return;
319                 }
320                 if (statret == 0) {
321                         l = readlink(fname,lnk,MAXPATHLEN-1);
322                         if (l > 0) {
323                                 lnk[l] = 0;
324                                 /* A link already pointing to the
325                                  * right place -- no further action
326                                  * required. */
327                                 if (strcmp(lnk,file->link) == 0) {
328                                         set_perms(fname,file,&st,1);
329                                         return;
330                                 }
331                         }  
332                         /* Not a symlink, so delete whatever's
333                          * already there and put a new symlink
334                          * in place. */                    
335                         delete_file(fname);
336                 }
337                 if (do_symlink(file->link,fname) != 0) {
338                         rprintf(FERROR,RSYNC_NAME": symlink \"%s\" -> \"%s\": %s\n",
339                                 fname,file->link,strerror(errno));
340                 } else {
341                         set_perms(fname,file,NULL,0);
342                         if (verbose) {
343                                 rprintf(FINFO,"%s -> %s\n", fname,file->link);
344                         }
345                 }
346 #endif
347                 return;
348         }
349
350 #ifdef HAVE_MKNOD
351         if (am_root && preserve_devices && IS_DEVICE(file->mode)) {
352                 if (statret != 0 || 
353                     st.st_mode != file->mode ||
354                     st.st_rdev != file->rdev) { 
355                         delete_file(fname);
356                         if (verbose > 2)
357                                 rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
358                                         fname,(int)file->mode,(int)file->rdev);
359                         if (do_mknod(fname,file->mode,file->rdev) != 0) {
360                                 rprintf(FERROR,"mknod %s : %s\n",fname,strerror(errno));
361                         } else {
362                                 set_perms(fname,file,NULL,0);
363                                 if (verbose)
364                                         rprintf(FINFO,"%s\n",fname);
365                         }
366                 } else {
367                         set_perms(fname,file,&st,1);
368                 }
369                 return;
370         }
371 #endif
372
373         if (preserve_hard_links && check_hard_link(file)) {
374                 if (verbose > 1)
375                         rprintf(FINFO, "recv_generator: \"%s\" is a hard link\n",f_name(file));
376                 return;
377         }
378
379         if (!S_ISREG(file->mode)) {
380                 rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
381                 return;
382         }
383
384         fnamecmp = fname;
385
386         if ((statret == -1) && (compare_dest != NULL)) {
387                 /* try the file at compare_dest instead */
388                 int saveerrno = errno;
389                 snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",compare_dest,fname);
390                 statret = link_stat(fnamecmpbuf,&st);
391                 if (!S_ISREG(st.st_mode))
392                         statret = -1;
393                 if (statret == -1)
394                         errno = saveerrno;
395                 else
396                         fnamecmp = fnamecmpbuf;
397         }
398
399         if (statret == -1) {
400                 if (errno == ENOENT) {
401                         write_int(f_out,i);
402                         if (!dry_run) send_sums(NULL,f_out);
403                 } else {
404                         if (verbose > 1)
405                                 rprintf(FERROR, RSYNC_NAME
406                                         ": recv_generator failed to open \"%s\": %s\n",
407                                         fname, strerror(errno));
408                 }
409                 return;
410         }
411
412         if (!S_ISREG(st.st_mode)) {
413                 if (delete_file(fname) != 0) {
414                         return;
415                 }
416
417                 /* now pretend the file didn't exist */
418                 write_int(f_out,i);
419                 if (!dry_run) send_sums(NULL,f_out);    
420                 return;
421         }
422
423         if (opt_ignore_existing && fnamecmp == fname) { 
424                 if (verbose > 1)
425                         rprintf(FINFO,"%s exists\n",fname);
426                 return;
427         } 
428
429         if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
430                 if (verbose > 1)
431                         rprintf(FINFO,"%s is newer\n",fname);
432                 return;
433         }
434
435         if (skip_file(fname, file, &st)) {
436                 if (fnamecmp == fname)
437                         set_perms(fname,file,&st,1);
438                 return;
439         }
440
441         if (dry_run) {
442                 write_int(f_out,i);
443                 return;
444         }
445
446         if (disable_deltas_p()) {
447                 write_int(f_out,i);
448                 send_sums(NULL,f_out);    
449                 return;
450         }
451
452         /* open the file */  
453         fd = do_open(fnamecmp, O_RDONLY, 0);
454
455         if (fd == -1) {
456                 rprintf(FERROR,RSYNC_NAME": failed to open \"%s\", continuing : %s\n",fnamecmp,strerror(errno));
457                 /* pretend the file didn't exist */
458                 write_int(f_out,i);
459                 send_sums(NULL,f_out);
460                 return;
461         }
462
463         if (st.st_size > 0) {
464                 buf = map_file(fd,st.st_size);
465         } else {
466                 buf = NULL;
467         }
468
469         if (verbose > 3)
470                 rprintf(FINFO,"gen mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
471
472         s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));
473
474         if (verbose > 2)
475                 rprintf(FINFO,"sending sums for %d\n",i);
476
477         write_int(f_out,i);
478         send_sums(s,f_out);
479
480         close(fd);
481         if (buf) unmap_file(buf);
482
483         free_sums(s);
484 }
485
486
487
488 void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
489 {
490         int i;
491         int phase=0;
492
493         if (verbose > 2)
494                 rprintf(FINFO,"generator starting pid=%d count=%d\n",
495                         (int)getpid(),flist->count);
496
497         if (verbose >= 2) {
498                 rprintf(FINFO,
499                         disable_deltas_p() 
500                         ? "delta-transmission disabled for local transfer or --whole-file\n"
501                         : "delta transmission enabled\n");
502         }
503         
504         /* we expect to just sit around now, so don't exit on a
505            timeout. If we really get a timeout then the other process should
506            exit */
507         io_timeout = 0;
508
509         for (i = 0; i < flist->count; i++) {
510                 struct file_struct *file = flist->files[i];
511                 mode_t saved_mode = file->mode;
512                 if (!file->basename) continue;
513
514                 /* we need to ensure that any directories we create have writeable
515                    permissions initially so that we can create the files within
516                    them. This is then fixed after the files are transferred */
517                 if (!am_root && S_ISDIR(file->mode)) {
518                         file->mode |= S_IWUSR; /* user write */
519                         /* XXX: Could this be causing a problem on SCO?  Perhaps their
520                          * handling of permissions is strange? */
521                 }
522
523                 recv_generator(local_name?local_name:f_name(file),
524                                flist,i,f);
525
526                 file->mode = saved_mode;
527         }
528
529         phase++;
530         csum_length = SUM_LENGTH;
531         ignore_times=1;
532
533         if (verbose > 2)
534                 rprintf(FINFO,"generate_files phase=%d\n",phase);
535
536         write_int(f,-1);
537
538         if (remote_version >= 13) {
539                 /* in newer versions of the protocol the files can cycle through
540                    the system more than once to catch initial checksum errors */
541                 for (i=read_int(f_recv); i != -1; i=read_int(f_recv)) {
542                         struct file_struct *file = flist->files[i];
543                         recv_generator(local_name?local_name:f_name(file),
544                                        flist,i,f);    
545                 }
546
547                 phase++;
548                 if (verbose > 2)
549                         rprintf(FINFO,"generate_files phase=%d\n",phase);
550
551                 write_int(f,-1);
552         }
553 }