Fix for device nodes. (dann frazier) (Debian #129135)
[rsync/rsync.git] / generator.c
CommitLineData
ef1aa910 1/* -*- c-file-style: "linux" -*-
91262d5d
MP
2
3 rsync -- fast file replication program
ef1aa910
MP
4
5 Copyright (C) 1996-2000 by Andrew Tridgell
2f03f956 6 Copyright (C) Paul Mackerras 1996
91262d5d 7 Copyright (C) 2002 by Martin Pool <mbp@samba.org>
2f03f956
AT
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
26extern int verbose;
27extern int dry_run;
28extern int relative_paths;
29extern int preserve_links;
30extern int am_root;
31extern int preserve_devices;
32extern int preserve_hard_links;
33extern int update_only;
34extern int whole_file;
35extern int block_size;
36extern int csum_length;
37extern int ignore_times;
f83f0548 38extern int size_only;
2f03f956
AT
39extern int io_timeout;
40extern int remote_version;
41extern int always_checksum;
5b56cc19 42extern int modify_window;
60c8d7bc 43extern char *compare_dest;
2f03f956
AT
44
45
46/* choose whether to skip a particular file */
47static 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];
60c8d7bc
DD
58 char fnamecmpdest[MAXPATHLEN];
59
60 if (compare_dest != NULL) {
61 if (access(fname, 0) != 0) {
8950ac03 62 snprintf(fnamecmpdest,MAXPATHLEN,"%s/%s",
60c8d7bc
DD
63 compare_dest,fname);
64 fname = fnamecmpdest;
65 }
66 }
2f03f956 67 file_checksum(fname,sum,st->st_size);
f855a7d0
AT
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 }
2f03f956
AT
73 }
74
f83f0548
AT
75 if (size_only) {
76 return 1;
77 }
78
2f03f956
AT
79 if (ignore_times) {
80 return 0;
81 }
82
5b56cc19 83 return (cmp_modtime(st->st_mtime,file->modtime) == 0);
2f03f956
AT
84}
85
86
87/* use a larger block size for really big files */
88static 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 */
1707e0f9 105static void send_sums(struct sum_struct *s, int f_out)
2f03f956 106{
91262d5d
MP
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);
f855a7d0 126 }
2f03f956
AT
127}
128
2f03f956
AT
129/*
130 generate a stream of signatures/checksums that describe a buffer
131
132 generate approximately one checksum every n bytes
133 */
134static struct sum_struct *generate_sums(struct map_struct *buf,OFF_T len,int n)
135{
136 int i;
137 struct sum_struct *s;
138 int count;
139 int block_len = n;
140 int remainder = (len%block_len);
141 OFF_T offset = 0;
142
143 count = (len+(block_len-1))/block_len;
144
145 s = (struct sum_struct *)malloc(sizeof(*s));
146 if (!s) out_of_memory("generate_sums");
147
148 s->count = count;
149 s->remainder = remainder;
150 s->n = n;
151 s->flength = len;
152
153 if (count==0) {
154 s->sums = NULL;
155 return s;
156 }
157
158 if (verbose > 3)
5f808dfb
AT
159 rprintf(FINFO,"count=%d rem=%d n=%d flength=%.0f\n",
160 s->count,s->remainder,s->n,(double)s->flength);
2f03f956
AT
161
162 s->sums = (struct sum_buf *)malloc(sizeof(s->sums[0])*s->count);
163 if (!s->sums) out_of_memory("generate_sums");
164
165 for (i=0;i<count;i++) {
166 int n1 = MIN(len,n);
167 char *map = map_ptr(buf,offset,n1);
168
169 s->sums[i].sum1 = get_checksum1(map,n1);
170 get_checksum2(map,n1,s->sums[i].sum2);
171
172 s->sums[i].offset = offset;
173 s->sums[i].len = n1;
174 s->sums[i].i = i;
175
176 if (verbose > 3)
5f808dfb
AT
177 rprintf(FINFO,"chunk[%d] offset=%.0f len=%d sum1=%08x\n",
178 i,(double)s->sums[i].offset,s->sums[i].len,s->sums[i].sum1);
2f03f956
AT
179
180 len -= n1;
181 offset += n1;
182 }
183
184 return s;
185}
186
187
ef1aa910
MP
188
189/*
190 * Acts on file number I from FLIST, whose name is fname.
191 *
192 * First fixes up permissions, then generates checksums for the file.
193 *
194 * (This comment was added later by mbp who was trying to work it out;
195 * it might be wrong.)
196 */
2f03f956
AT
197void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
198{
199 int fd;
200 STRUCT_STAT st;
201 struct map_struct *buf;
202 struct sum_struct *s;
203 int statret;
204 struct file_struct *file = flist->files[i];
375a4556
DD
205 char *fnamecmp;
206 char fnamecmpbuf[MAXPATHLEN];
207 extern char *compare_dest;
f7632fc6 208 extern int list_only;
4df9f368 209 extern int preserve_perms;
1347d512 210 extern int only_existing;
f7632fc6
AT
211
212 if (list_only) return;
2f03f956
AT
213
214 if (verbose > 2)
215 rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
216
217 statret = link_stat(fname,&st);
63787382 218
1347d512
AT
219 if (only_existing && statret == -1 && errno == ENOENT) {
220 /* we only want to update existing files */
85d4d142
MP
221 if (verbose > 1) rprintf(FINFO, RSYNC_NAME
222 ": not creating new file \"%s\"\n",fname);
1347d512
AT
223 return;
224 }
225
4df9f368
AT
226 if (statret == 0 &&
227 !preserve_perms &&
228 (S_ISDIR(st.st_mode) == S_ISDIR(file->mode))) {
229 /* if the file exists already and we aren't perserving
230 presmissions then act as though the remote end sent
231 us the file permissions we already have */
7e0ca8e2 232 file->mode = (file->mode & _S_IFMT) | (st.st_mode & ~_S_IFMT);
4df9f368
AT
233 }
234
2f03f956 235 if (S_ISDIR(file->mode)) {
a1b1b1da
MP
236 /* The file to be received is a directory, so we need
237 * to prepare appropriately. If there is already a
238 * file of that name and it is *not* a directory, then
239 * we need to delete it. If it doesn't exist, then
240 * recursively create it. */
241
85d4d142 242 if (dry_run) return; /* XXXX -- might cause inaccuracies?? -- mbp */
2f03f956 243 if (statret == 0 && !S_ISDIR(st.st_mode)) {
c7c11a0d 244 if (robust_unlink(fname) != 0) {
85d4d142
MP
245 rprintf(FERROR, RSYNC_NAME
246 ": recv_generator: unlink \"%s\" to make room for directory: %s\n",
a1b1b1da 247 fname,strerror(errno));
2f03f956
AT
248 return;
249 }
250 statret = -1;
251 }
252 if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
253 if (!(relative_paths && errno==ENOENT &&
254 create_directory_path(fname)==0 &&
255 do_mkdir(fname,file->mode)==0)) {
85d4d142 256 rprintf(FERROR, RSYNC_NAME ": recv_generator: mkdir \"%s\": %s (2)\n",
2f03f956
AT
257 fname,strerror(errno));
258 }
259 }
de343e3c
DD
260 /* f_out is set to -1 when doing final directory
261 permission and modification time repair */
262 if (set_perms(fname,file,NULL,0) && verbose && (f_out != -1))
2f03f956
AT
263 rprintf(FINFO,"%s/\n",fname);
264 return;
265 }
266
267 if (preserve_links && S_ISLNK(file->mode)) {
268#if SUPPORT_LINKS
269 char lnk[MAXPATHLEN];
270 int l;
271 extern int safe_symlinks;
272
273 if (safe_symlinks && unsafe_symlink(file->link, fname)) {
274 if (verbose) {
85d4d142 275 rprintf(FINFO,RSYNC_NAME ": ignoring unsafe symlink \"%s\" -> \"%s\"\n",
2f03f956
AT
276 fname,file->link);
277 }
278 return;
279 }
280 if (statret == 0) {
281 l = readlink(fname,lnk,MAXPATHLEN-1);
282 if (l > 0) {
283 lnk[l] = 0;
85d4d142
MP
284 /* A link already pointing to the
285 * right place -- no further action
286 * required. */
7e0ca8e2 287 if (strcmp(lnk,file->link) == 0) {
2f03f956
AT
288 set_perms(fname,file,&st,1);
289 return;
290 }
85d4d142
MP
291 }
292 /* Not a symlink, so delete whatever's
293 * already there and put a new symlink
294 * in place. */
4b3977bf 295 delete_file(fname);
2f03f956 296 }
2f03f956 297 if (do_symlink(file->link,fname) != 0) {
85d4d142 298 rprintf(FERROR,RSYNC_NAME": symlink \"%s\" -> \"%s\": %s\n",
2f03f956
AT
299 fname,file->link,strerror(errno));
300 } else {
301 set_perms(fname,file,NULL,0);
302 if (verbose) {
85d4d142 303 rprintf(FINFO,RSYNC_NAME": %s -> %s\n",
2f03f956
AT
304 fname,file->link);
305 }
306 }
307#endif
308 return;
309 }
310
311#ifdef HAVE_MKNOD
312 if (am_root && preserve_devices && IS_DEVICE(file->mode)) {
313 if (statret != 0 ||
314 st.st_mode != file->mode ||
315 st.st_rdev != file->rdev) {
316 delete_file(fname);
317 if (verbose > 2)
318 rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
319 fname,(int)file->mode,(int)file->rdev);
320 if (do_mknod(fname,file->mode,file->rdev) != 0) {
321 rprintf(FERROR,"mknod %s : %s\n",fname,strerror(errno));
322 } else {
323 set_perms(fname,file,NULL,0);
324 if (verbose)
325 rprintf(FINFO,"%s\n",fname);
326 }
327 } else {
328 set_perms(fname,file,&st,1);
329 }
330 return;
331 }
332#endif
333
334 if (preserve_hard_links && check_hard_link(file)) {
335 if (verbose > 1)
85d4d142
MP
336 rprintf(FINFO, RSYNC_NAME
337 ": \"%s\" is a hard link\n",f_name(file));
2f03f956
AT
338 return;
339 }
340
341 if (!S_ISREG(file->mode)) {
85d4d142
MP
342 rprintf(FINFO, RSYNC_NAME
343 ": skipping non-regular file \"%s\"\n",fname);
2f03f956
AT
344 return;
345 }
346
375a4556
DD
347 fnamecmp = fname;
348
349 if ((statret == -1) && (compare_dest != NULL)) {
350 /* try the file at compare_dest instead */
351 int saveerrno = errno;
8950ac03 352 snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",compare_dest,fname);
375a4556
DD
353 statret = link_stat(fnamecmpbuf,&st);
354 if (!S_ISREG(st.st_mode))
355 statret = -1;
356 if (statret == -1)
357 errno = saveerrno;
358 else
359 fnamecmp = fnamecmpbuf;
360 }
361
2f03f956
AT
362 if (statret == -1) {
363 if (errno == ENOENT) {
364 write_int(f_out,i);
365 if (!dry_run) send_sums(NULL,f_out);
366 } else {
367 if (verbose > 1)
fb47591d
MP
368 rprintf(FERROR, RSYNC_NAME
369 ": recv_generator failed to open \"%s\": %s\n",
370 fname, strerror(errno));
2f03f956
AT
371 }
372 return;
373 }
374
375 if (!S_ISREG(st.st_mode)) {
376 if (delete_file(fname) != 0) {
377 return;
378 }
379
380 /* now pretend the file didn't exist */
381 write_int(f_out,i);
382 if (!dry_run) send_sums(NULL,f_out);
383 return;
384 }
385
5b56cc19 386 if (update_only && cmp_modtime(st.st_mtime,file->modtime)>0 && fnamecmp == fname) {
2f03f956
AT
387 if (verbose > 1)
388 rprintf(FINFO,"%s is newer\n",fname);
389 return;
390 }
391
392 if (skip_file(fname, file, &st)) {
bd4ed7f7
DD
393 if (fnamecmp == fname)
394 set_perms(fname,file,&st,1);
2f03f956
AT
395 return;
396 }
397
398 if (dry_run) {
399 write_int(f_out,i);
400 return;
401 }
402
403 if (whole_file) {
404 write_int(f_out,i);
405 send_sums(NULL,f_out);
406 return;
407 }
408
409 /* open the file */
8c9fd200 410 fd = do_open(fnamecmp, O_RDONLY, 0);
2f03f956
AT
411
412 if (fd == -1) {
85d4d142 413 rprintf(FERROR,RSYNC_NAME": failed to open \"%s\", continuing : %s\n",fnamecmp,strerror(errno));
60be6acf
DD
414 /* pretend the file didn't exist */
415 write_int(f_out,i);
416 send_sums(NULL,f_out);
2f03f956
AT
417 return;
418 }
419
420 if (st.st_size > 0) {
421 buf = map_file(fd,st.st_size);
422 } else {
423 buf = NULL;
424 }
425
426 if (verbose > 3)
5f808dfb 427 rprintf(FINFO,"gen mapped %s of size %.0f\n",fnamecmp,(double)st.st_size);
2f03f956
AT
428
429 s = generate_sums(buf,st.st_size,adapt_block_size(file, block_size));
430
431 if (verbose > 2)
432 rprintf(FINFO,"sending sums for %d\n",i);
433
434 write_int(f_out,i);
435 send_sums(s,f_out);
436
437 close(fd);
438 if (buf) unmap_file(buf);
439
440 free_sums(s);
441}
442
443
444
445void generate_files(int f,struct file_list *flist,char *local_name,int f_recv)
446{
447 int i;
448 int phase=0;
449
450 if (verbose > 2)
451 rprintf(FINFO,"generator starting pid=%d count=%d\n",
452 (int)getpid(),flist->count);
453
a57873b7
AT
454 /* we expect to just sit around now, so don't exit on a
455 timeout. If we really get a timeout then the other process should
456 exit */
457 io_timeout = 0;
458
2f03f956
AT
459 for (i = 0; i < flist->count; i++) {
460 struct file_struct *file = flist->files[i];
461 mode_t saved_mode = file->mode;
462 if (!file->basename) continue;
463
464 /* we need to ensure that any directories we create have writeable
465 permissions initially so that we can create the files within
466 them. This is then fixed after the files are transferred */
467 if (!am_root && S_ISDIR(file->mode)) {
468 file->mode |= S_IWUSR; /* user write */
a1b1b1da
MP
469 /* XXX: Could this be causing a problem on SCO? Perhaps their
470 * handling of permissions is strange? */
2f03f956
AT
471 }
472
473 recv_generator(local_name?local_name:f_name(file),
474 flist,i,f);
475
476 file->mode = saved_mode;
477 }
478
479 phase++;
480 csum_length = SUM_LENGTH;
481 ignore_times=1;
482
483 if (verbose > 2)
484 rprintf(FINFO,"generate_files phase=%d\n",phase);
485
486 write_int(f,-1);
487
2f03f956
AT
488 if (remote_version >= 13) {
489 /* in newer versions of the protocol the files can cycle through
490 the system more than once to catch initial checksum errors */
491 for (i=read_int(f_recv); i != -1; i=read_int(f_recv)) {
492 struct file_struct *file = flist->files[i];
493 recv_generator(local_name?local_name:f_name(file),
494 flist,i,f);
495 }
496
497 phase++;
498 if (verbose > 2)
499 rprintf(FINFO,"generate_files phase=%d\n",phase);
500
501 write_int(f,-1);
502 }
503}