- Added a new block_size arg to map_file(). Use it to set the
[rsync/rsync.git] / generator.c
CommitLineData
ef1aa910 1/* -*- c-file-style: "linux" -*-
91262d5d
MP
2
3 rsync -- fast file replication program
2cda2560
WD
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>
2cda2560 8
2f03f956
AT
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.
2cda2560 13
2f03f956
AT
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.
2cda2560 18
2f03f956
AT
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;
716e73d4 29extern int keep_dirlinks;
2f03f956
AT
30extern int preserve_links;
31extern int am_root;
32extern int preserve_devices;
33extern int preserve_hard_links;
6744b62d
WD
34extern int preserve_perms;
35extern int preserve_uid;
36extern int preserve_gid;
2f03f956 37extern int update_only;
3d6feada 38extern int opt_ignore_existing;
2f03f956
AT
39extern int csum_length;
40extern int ignore_times;
f83f0548 41extern int size_only;
2f03f956 42extern int io_timeout;
d04e9c51 43extern int protocol_version;
2f03f956 44extern int always_checksum;
60c8d7bc 45extern char *compare_dest;
59c95e42 46extern int link_dest;
5774786f
WD
47extern int whole_file;
48extern int local_server;
5774786f 49extern int list_only;
b9f592fb 50extern int read_batch;
5774786f
WD
51extern int only_existing;
52extern int orig_umask;
53extern int safe_symlinks;
ec8290c8 54extern unsigned int block_size;
efd5ee57 55extern unsigned int max_map_size;
2f03f956 56
97f9dcae
WD
57extern struct exclude_list_struct server_exclude_list;
58
2f03f956
AT
59
60/* choose whether to skip a particular file */
dfd5ba6a 61static int skip_file(char *fname, struct file_struct *file, STRUCT_STAT *st)
2f03f956 62{
cc1e997d 63 if (st->st_size != file->length)
84acca07 64 return 0;
59c95e42 65 if (link_dest) {
e7bc9b64 66 if (preserve_perms
67e78a82 67 && (st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS))
84acca07 68 return 0;
bb24028f 69
6744b62d 70 if (am_root && preserve_uid && st->st_uid != file->uid)
84acca07 71 return 0;
bb24028f 72
a60e2dca
S
73 if (preserve_gid && file->gid != GID_NONE
74 && st->st_gid != file->gid)
84acca07 75 return 0;
59c95e42
DD
76 }
77
2cda2560 78 /* if always checksum is set then we use the checksum instead
2f03f956
AT
79 of the file time to determine whether to sync */
80 if (always_checksum && S_ISREG(st->st_mode)) {
81 char sum[MD4_SUM_LENGTH];
60c8d7bc
DD
82 char fnamecmpdest[MAXPATHLEN];
83
84 if (compare_dest != NULL) {
85 if (access(fname, 0) != 0) {
248ed45f
WD
86 pathjoin(fnamecmpdest, sizeof fnamecmpdest,
87 compare_dest, fname);
60c8d7bc
DD
88 fname = fnamecmpdest;
89 }
90 }
2f03f956 91 file_checksum(fname,sum,st->st_size);
728d0922 92 return memcmp(sum, file->u.sum, protocol_version < 21 ? 2
84acca07 93 : MD4_SUM_LENGTH) == 0;
2f03f956
AT
94 }
95
cc1e997d 96 if (size_only)
84acca07 97 return 1;
2f03f956 98
cc1e997d 99 if (ignore_times)
84acca07 100 return 0;
cc1e997d 101
84acca07 102 return cmp_modtime(st->st_mtime, file->modtime) == 0;
2f03f956
AT
103}
104
105
2f03f956 106/*
0e36d9da 107 * NULL sum_struct means we have no checksums
195bd906 108 */
fc0257c9 109void write_sum_head(int f, struct sum_struct *sum)
2f03f956 110{
fc0257c9
S
111 static struct sum_struct null_sum;
112
c338460d 113 if (sum == NULL)
fc0257c9
S
114 sum = &null_sum;
115
116 write_int(f, sum->count);
117 write_int(f, sum->blength);
d04e9c51 118 if (protocol_version >= 27)
fc0257c9
S
119 write_int(f, sum->s2length);
120 write_int(f, sum->remainder);
2f03f956
AT
121}
122
ec8290c8 123/*
195bd906 124 * set (initialize) the size entries in the per-file sum_struct
ec8290c8 125 * calculating dynamic block and checksum sizes.
195bd906 126 *
ec8290c8 127 * This is only called from generate_and_send_sums() but is a separate
195bd906
S
128 * function to encapsulate the logic.
129 *
130 * The block size is a rounded square root of file length.
131 *
132 * The checksum size is determined according to:
133 * blocksum_bits = BLOCKSUM_EXP + 2*log2(file_len) - log2(block_len)
134 * provided by Donovan Baarda which gives a probability of rsync
135 * algorithm corrupting data and falling back using the whole md4
136 * checksums.
137 *
138 * This might be made one of several selectable heuristics.
139 */
bceec82f 140
423dba8e 141static void sum_sizes_sqroot(struct sum_struct *sum, uint64 len)
195bd906 142{
da9d12f5
WD
143 unsigned int blength;
144 int s2length;
195bd906
S
145 uint32 c;
146 uint64 l;
147
148 if (block_size) {
149 blength = block_size;
150 } else if (len <= BLOCK_SIZE * BLOCK_SIZE) {
151 blength = BLOCK_SIZE;
152 } else {
153 l = len;
154 c = 1;
155 while (l >>= 2) {
156 c <<= 1;
157 }
158 blength = 0;
159 do {
160 blength |= c;
fb55e28d 161 if (len < (uint64)blength * blength)
195bd906
S
162 blength &= ~c;
163 c >>= 1;
164 } while (c >= 8); /* round to multiple of 8 */
165 blength = MAX(blength, BLOCK_SIZE);
efd5ee57 166 blength = MIN(blength, MAX_MAP_SIZE);
195bd906 167 }
5126ed1e 168 max_map_size = MAX(MAX_MAP_SIZE, blength * 32);
195bd906 169
d04e9c51 170 if (protocol_version < 27) {
195bd906
S
171 s2length = csum_length;
172 } else if (csum_length == SUM_LENGTH) {
173 s2length = SUM_LENGTH;
174 } else {
da9d12f5 175 int b = BLOCKSUM_BIAS;
195bd906
S
176 l = len;
177 while (l >>= 1) {
178 b += 2;
179 }
180 c = blength;
181 while (c >>= 1 && b) {
182 b--;
183 }
184 s2length = (b + 1 - 32 + 7) / 8; /* add a bit,
185 * subtract rollsum,
186 * round up
187 * --optimize in compiler--
188 */
189 s2length = MAX(s2length, csum_length);
190 s2length = MIN(s2length, SUM_LENGTH);
191 }
192
193 sum->flength = len;
194 sum->blength = blength;
195 sum->s2length = s2length;
196 sum->count = (len + (blength - 1)) / blength;
197 sum->remainder = (len % blength);
198
199 if (sum->count && verbose > 2) {
0e36d9da
WD
200 rprintf(FINFO, "count=%.0f rem=%u blength=%u s2length=%d flength=%.0f\n",
201 (double)sum->count, sum->remainder, sum->blength,
da9d12f5 202 sum->s2length, (double)sum->flength);
195bd906
S
203 }
204}
80605142 205
bceec82f 206
80605142
WD
207/*
208 * Generate and send a stream of signatures/checksums that describe a buffer
e66dfd18 209 *
80605142
WD
210 * Generate approximately one checksum every block_len bytes.
211 */
9774cc33 212static void generate_and_send_sums(struct map_struct *buf, OFF_T len, int f_out)
2f03f956 213{
80605142
WD
214 size_t i;
215 struct sum_struct sum;
2f03f956
AT
216 OFF_T offset = 0;
217
423dba8e 218 sum_sizes_sqroot(&sum, len);
e66dfd18 219
fc0257c9 220 write_sum_head(f_out, &sum);
2f03f956 221
80605142 222 for (i = 0; i < sum.count; i++) {
0e36d9da 223 unsigned int n1 = MIN(len, sum.blength);
e66dfd18 224 char *map = map_ptr(buf, offset, n1);
80605142
WD
225 uint32 sum1 = get_checksum1(map, n1);
226 char sum2[SUM_LENGTH];
2f03f956 227
80605142 228 get_checksum2(map, n1, sum2);
2f03f956 229
80605142 230 if (verbose > 3) {
e66dfd18 231 rprintf(FINFO,
0e36d9da
WD
232 "chunk[%.0f] offset=%.0f len=%u sum1=%08lx\n",
233 (double)i, (double)offset, n1,
234 (unsigned long)sum1);
80605142
WD
235 }
236 write_int(f_out, sum1);
fc0257c9 237 write_buf(f_out, sum2, sum.s2length);
2f03f956
AT
238 len -= n1;
239 offset += n1;
240 }
2f03f956
AT
241}
242
243
ef1aa910 244
fd322eef 245/*
420ef2c4 246 * Acts on file number @p i from @p flist, whose name is @p fname.
ef1aa910
MP
247 *
248 * First fixes up permissions, then generates checksums for the file.
249 *
420ef2c4
MP
250 * @note This comment was added later by mbp who was trying to work it
251 * out. It might be wrong.
fd322eef
WD
252 */
253static void recv_generator(char *fname, struct file_struct *file, int i,
254 int f_out)
2cda2560 255{
2f03f956
AT
256 int fd;
257 STRUCT_STAT st;
968c8030 258 struct map_struct *mapbuf;
2f03f956 259 int statret;
375a4556
DD
260 char *fnamecmp;
261 char fnamecmpbuf[MAXPATHLEN];
f7632fc6 262
dfd5ba6a
WD
263 if (list_only)
264 return;
2f03f956
AT
265
266 if (verbose > 2)
267 rprintf(FINFO,"recv_generator(%s,%d)\n",fname,i);
268
97f9dcae
WD
269 if (server_exclude_list.head
270 && check_exclude(&server_exclude_list, fname,
3e35c34b
WD
271 S_ISDIR(file->mode)) < 0) {
272 if (verbose) {
273 rprintf(FINFO, "skipping server-excluded file \"%s\"\n",
274 fname);
275 }
97f9dcae 276 return;
3e35c34b 277 }
97f9dcae 278
6218c7bf 279 statret = link_stat(fname, &st, keep_dirlinks && S_ISDIR(file->mode));
63787382 280
1347d512
AT
281 if (only_existing && statret == -1 && errno == ENOENT) {
282 /* we only want to update existing files */
3e35c34b
WD
283 if (verbose > 1)
284 rprintf(FINFO, "not creating new file \"%s\"\n", fname);
1347d512
AT
285 return;
286 }
287
2cda2560
WD
288 if (statret == 0 &&
289 !preserve_perms &&
4df9f368
AT
290 (S_ISDIR(st.st_mode) == S_ISDIR(file->mode))) {
291 /* if the file exists already and we aren't perserving
2cda2560
WD
292 * permissions then act as though the remote end sent
293 * us the file permissions we already have */
67e78a82
WD
294 file->mode = (file->mode & ~CHMOD_BITS)
295 | (st.st_mode & CHMOD_BITS);
4df9f368
AT
296 }
297
2f03f956 298 if (S_ISDIR(file->mode)) {
2cda2560
WD
299 /* The file to be received is a directory, so we need
300 * to prepare appropriately. If there is already a
301 * file of that name and it is *not* a directory, then
302 * we need to delete it. If it doesn't exist, then
303 * recursively create it. */
304
ec8290c8
WD
305 if (dry_run)
306 return; /* TODO: causes inaccuracies -- fix */
2f03f956 307 if (statret == 0 && !S_ISDIR(st.st_mode)) {
c7c11a0d 308 if (robust_unlink(fname) != 0) {
d62bcc17
WD
309 rsyserr(FERROR, errno,
310 "recv_generator: unlink %s to make room for directory",
311 full_fname(fname));
2f03f956
AT
312 return;
313 }
314 statret = -1;
315 }
316 if (statret != 0 && do_mkdir(fname,file->mode) != 0 && errno != EEXIST) {
d62bcc17
WD
317 if (!(relative_paths && errno == ENOENT
318 && create_directory_path(fname, orig_umask) == 0
319 && do_mkdir(fname, file->mode) == 0)) {
320 rsyserr(FERROR, errno,
321 "recv_generator: mkdir %s failed",
322 full_fname(fname));
2f03f956
AT
323 }
324 }
716e73d4
WD
325 /* f_out is set to -1 when doing final directory-permission
326 * and modification-time repair. */
327 if (set_perms(fname, file, statret ? NULL : &st, 0)
328 && verbose && f_out != -1)
2f03f956
AT
329 rprintf(FINFO,"%s/\n",fname);
330 return;
331 }
332
333 if (preserve_links && S_ISLNK(file->mode)) {
334#if SUPPORT_LINKS
335 char lnk[MAXPATHLEN];
336 int l;
2f03f956 337
728d0922 338 if (safe_symlinks && unsafe_symlink(file->u.link, fname)) {
2f03f956 339 if (verbose) {
ea42541f 340 rprintf(FINFO, "ignoring unsafe symlink %s -> \"%s\"\n",
728d0922 341 full_fname(fname), file->u.link);
2f03f956
AT
342 }
343 return;
344 }
345 if (statret == 0) {
346 l = readlink(fname,lnk,MAXPATHLEN-1);
347 if (l > 0) {
348 lnk[l] = 0;
85d4d142
MP
349 /* A link already pointing to the
350 * right place -- no further action
351 * required. */
728d0922 352 if (strcmp(lnk,file->u.link) == 0) {
c41b52c4
WD
353 set_perms(fname, file, &st,
354 PERMS_REPORT);
2f03f956
AT
355 return;
356 }
2cda2560 357 }
85d4d142
MP
358 /* Not a symlink, so delete whatever's
359 * already there and put a new symlink
2cda2560 360 * in place. */
4b3977bf 361 delete_file(fname);
2f03f956 362 }
728d0922 363 if (do_symlink(file->u.link,fname) != 0) {
d62bcc17
WD
364 rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed",
365 full_fname(fname), file->u.link);
2f03f956
AT
366 } else {
367 set_perms(fname,file,NULL,0);
368 if (verbose) {
728d0922 369 rprintf(FINFO,"%s -> %s\n", fname,file->u.link);
2f03f956
AT
370 }
371 }
372#endif
373 return;
374 }
375
376#ifdef HAVE_MKNOD
377 if (am_root && preserve_devices && IS_DEVICE(file->mode)) {
2cda2560 378 if (statret != 0 ||
2f03f956 379 st.st_mode != file->mode ||
3915fd75 380 st.st_rdev != file->u.rdev) {
2f03f956 381 delete_file(fname);
d62bcc17 382 if (verbose > 2) {
2f03f956 383 rprintf(FINFO,"mknod(%s,0%o,0x%x)\n",
728d0922 384 fname,(int)file->mode,(int)file->u.rdev);
d62bcc17 385 }
728d0922 386 if (do_mknod(fname,file->mode,file->u.rdev) != 0) {
d62bcc17
WD
387 rsyserr(FERROR, errno, "mknod %s failed",
388 full_fname(fname));
2f03f956
AT
389 } else {
390 set_perms(fname,file,NULL,0);
391 if (verbose)
392 rprintf(FINFO,"%s\n",fname);
393 }
394 } else {
c41b52c4 395 set_perms(fname, file, &st, PERMS_REPORT);
2f03f956
AT
396 }
397 return;
398 }
399#endif
400
d7142e23
WD
401 if (read_batch)
402 return;
403
6dff5992 404 if (preserve_hard_links && hard_link_check(file, HL_CHECK_MASTER))
2f03f956 405 return;
2f03f956
AT
406
407 if (!S_ISREG(file->mode)) {
1bbd10fe 408 rprintf(FINFO, "skipping non-regular file \"%s\"\n",fname);
2f03f956
AT
409 return;
410 }
411
375a4556
DD
412 fnamecmp = fname;
413
c338460d 414 if (statret == -1 && compare_dest != NULL) {
375a4556
DD
415 /* try the file at compare_dest instead */
416 int saveerrno = errno;
248ed45f 417 pathjoin(fnamecmpbuf, sizeof fnamecmpbuf, compare_dest, fname);
6218c7bf 418 statret = link_stat(fnamecmpbuf, &st, 0);
375a4556
DD
419 if (!S_ISREG(st.st_mode))
420 statret = -1;
421 if (statret == -1)
422 errno = saveerrno;
59c95e42
DD
423#if HAVE_LINK
424 else if (link_dest && !dry_run) {
425 if (do_link(fnamecmpbuf, fname) != 0) {
e7bc9b64 426 if (verbose > 0) {
d62bcc17
WD
427 rsyserr(FINFO, errno, "link %s => %s",
428 fnamecmpbuf, fname);
e7bc9b64 429 }
59c95e42
DD
430 }
431 fnamecmp = fnamecmpbuf;
432 }
433#endif
375a4556
DD
434 else
435 fnamecmp = fnamecmpbuf;
436 }
437
2f03f956 438 if (statret == -1) {
6dff5992
WD
439 if (preserve_hard_links && hard_link_check(file, HL_SKIP))
440 return;
2f03f956
AT
441 if (errno == ENOENT) {
442 write_int(f_out,i);
ec8290c8
WD
443 if (!dry_run)
444 write_sum_head(f_out, NULL);
ea42541f 445 } else if (verbose > 1) {
d62bcc17
WD
446 rsyserr(FERROR, errno,
447 "recv_generator: failed to open %s",
448 full_fname(fname));
2f03f956
AT
449 }
450 return;
451 }
452
453 if (!S_ISREG(st.st_mode)) {
454 if (delete_file(fname) != 0) {
455 return;
456 }
457
458 /* now pretend the file didn't exist */
6dff5992
WD
459 if (preserve_hard_links && hard_link_check(file, HL_SKIP))
460 return;
2f03f956 461 write_int(f_out,i);
ec8290c8
WD
462 if (!dry_run)
463 write_sum_head(f_out, NULL);
2f03f956
AT
464 return;
465 }
466
2cda2560 467 if (opt_ignore_existing && fnamecmp == fname) {
3d6feada
MP
468 if (verbose > 1)
469 rprintf(FINFO,"%s exists\n",fname);
470 return;
2cda2560 471 }
3d6feada 472
d3a4375f
WD
473 if (update_only && fnamecmp == fname
474 && cmp_modtime(st.st_mtime, file->modtime) > 0) {
2f03f956
AT
475 if (verbose > 1)
476 rprintf(FINFO,"%s is newer\n",fname);
477 return;
478 }
479
84acca07 480 if (skip_file(fname, file, &st)) {
bd4ed7f7 481 if (fnamecmp == fname)
c41b52c4 482 set_perms(fname, file, &st, PERMS_REPORT);
2f03f956
AT
483 return;
484 }
485
486 if (dry_run) {
487 write_int(f_out,i);
488 return;
489 }
490
f38bd4a0 491 if (whole_file > 0) {
2f03f956 492 write_int(f_out,i);
fc0257c9 493 write_sum_head(f_out, NULL);
2f03f956
AT
494 return;
495 }
496
2cda2560 497 /* open the file */
8c9fd200 498 fd = do_open(fnamecmp, O_RDONLY, 0);
2f03f956
AT
499
500 if (fd == -1) {
d62bcc17
WD
501 rsyserr(FERROR, errno, "failed to open %s, continuing",
502 full_fname(fnamecmp));
60be6acf 503 /* pretend the file didn't exist */
6dff5992
WD
504 if (preserve_hard_links && hard_link_check(file, HL_SKIP))
505 return;
60be6acf 506 write_int(f_out,i);
fc0257c9 507 write_sum_head(f_out, NULL);
2f03f956
AT
508 return;
509 }
510
968c8030
WD
511 if (st.st_size > 0)
512 mapbuf = map_file(fd,st.st_size);
513 else
514 mapbuf = NULL;
2f03f956 515
dfd5ba6a
WD
516 if (verbose > 3) {
517 rprintf(FINFO,"gen mapped %s of size %.0f\n", fnamecmp,
518 (double)st.st_size);
519 }
2f03f956 520
2f03f956 521 if (verbose > 2)
80605142 522 rprintf(FINFO, "generating and sending sums for %d\n", i);
2f03f956
AT
523
524 write_int(f_out,i);
968c8030 525 generate_and_send_sums(mapbuf, st.st_size, f_out);
2f03f956
AT
526
527 close(fd);
ec8290c8
WD
528 if (mapbuf)
529 unmap_file(mapbuf);
2f03f956
AT
530}
531
532
7daccb8e 533void generate_files(int f_out, struct file_list *flist, char *local_name)
2f03f956
AT
534{
535 int i;
e1f67417 536 int phase = 0;
968c8030 537 char fbuf[MAXPATHLEN];
2f03f956 538
45e08edb
WD
539 if (verbose > 2) {
540 rprintf(FINFO, "generator starting pid=%ld count=%d\n",
541 (long)getpid(), flist->count);
542 }
2f03f956 543
3e7053ac
MP
544 if (verbose >= 2) {
545 rprintf(FINFO,
f38bd4a0 546 whole_file > 0
3e7053ac
MP
547 ? "delta-transmission disabled for local transfer or --whole-file\n"
548 : "delta transmission enabled\n");
549 }
2cda2560 550
a57873b7
AT
551 /* we expect to just sit around now, so don't exit on a
552 timeout. If we really get a timeout then the other process should
553 exit */
554 io_timeout = 0;
555
2f03f956
AT
556 for (i = 0; i < flist->count; i++) {
557 struct file_struct *file = flist->files[i];
dfd5ba6a 558 struct file_struct copy;
2f03f956 559
dfd5ba6a
WD
560 if (!file->basename)
561 continue;
2f03f956
AT
562 /* we need to ensure that any directories we create have writeable
563 permissions initially so that we can create the files within
564 them. This is then fixed after the files are transferred */
dfd5ba6a
WD
565 if (!am_root && S_ISDIR(file->mode) && !(file->mode & S_IWUSR)) {
566 copy = *file;
2cda2560
WD
567 /* XXX: Could this be causing a problem on SCO? Perhaps their
568 * handling of permissions is strange? */
dfd5ba6a
WD
569 copy.mode |= S_IWUSR; /* user write */
570 file = &copy;
2f03f956
AT
571 }
572
3fef5364 573 recv_generator(local_name ? local_name : f_name_to(file, fbuf),
7daccb8e 574 file, i, f_out);
2f03f956
AT
575 }
576
577 phase++;
578 csum_length = SUM_LENGTH;
e1f67417 579 ignore_times = 1;
2f03f956
AT
580
581 if (verbose > 2)
582 rprintf(FINFO,"generate_files phase=%d\n",phase);
583
7daccb8e 584 write_int(f_out, -1);
2f03f956 585
bc63ae3f
S
586 /* files can cycle through the system more than once
587 * to catch initial checksum errors */
b9b15fb1 588 while ((i = get_redo_num()) != -1) {
bc63ae3f 589 struct file_struct *file = flist->files[i];
3fef5364 590 recv_generator(local_name ? local_name : f_name_to(file, fbuf),
7daccb8e 591 file, i, f_out);
bc63ae3f 592 }
2f03f956 593
bc63ae3f
S
594 phase++;
595 if (verbose > 2)
596 rprintf(FINFO,"generate_files phase=%d\n",phase);
2f03f956 597
7daccb8e 598 write_int(f_out, -1);
6dff5992
WD
599
600 if (preserve_hard_links)
601 do_hard_links();
602
603 /* now we need to fix any directory permissions that were
604 * modified during the transfer */
605 for (i = 0; i < flist->count; i++) {
606 struct file_struct *file = flist->files[i];
ec8290c8
WD
607 if (!file->basename || !S_ISDIR(file->mode))
608 continue;
6dff5992
WD
609 recv_generator(local_name ? local_name : f_name(file),
610 file, i, -1);
611 }
612
613 if (verbose > 2)
614 rprintf(FINFO,"generate_files finished\n");
2f03f956 615}