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