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