Merged in the security fixes from 2.5.7.
[rsync/rsync.git] / batch.c
1 /* -*- c-file-style: "linux" -*-
2    
3    Weiss 1/1999
4    Batch utilities for rsync.
5
6 */
7
8 #include "rsync.h"
9 #include <time.h>
10
11 extern char *batch_prefix;
12
13 struct file_list *batch_flist;
14
15 static char rsync_flist_file[] = ".rsync_flist";
16 static char rsync_csums_file[] = ".rsync_csums";
17 static char rsync_delta_file[] = ".rsync_delta";
18 static char rsync_argvs_file[] = ".rsync_argvs";
19
20 static int fdb;
21 static int fdb_delta;
22 static int fdb_open;
23 static int fdb_close;
24
25 void write_batch_flist_file(char *buff, int bytes_to_write)
26 {
27         char filename[MAXPATHLEN];
28
29         if (fdb_open) {
30                 /* Set up file extension */
31                 strlcpy(filename, batch_prefix, sizeof(filename));
32                 strlcat(filename, rsync_flist_file, sizeof(filename));
33
34                 /*
35                  * Open batch flist file for writing;
36                  * create it if it doesn't exist
37                  */
38                 fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
39                             S_IREAD | S_IWRITE);
40                 if (fdb == -1) {
41                         rprintf(FERROR, "Batch file %s open error: %s\n",
42                                 filename, strerror(errno));
43                         close(fdb);
44                         exit_cleanup(1);
45                 }
46                 fdb_open = 0;
47         }
48
49         /* Write buffer to batch flist file */
50
51         if (write(fdb, buff, bytes_to_write) == -1) {
52                 rprintf(FERROR, "Batch file %s write error: %s\n",
53                         filename, strerror(errno));
54                 close(fdb);
55                 exit_cleanup(1);
56         }
57
58         if (fdb_close) {
59                 close(fdb);
60         }
61 }
62
63 void write_batch_flist_info(int flist_count, struct file_struct **fptr)
64 {
65         int i;
66         int bytes_to_write;
67
68         /* Write flist info to batch file */
69
70         bytes_to_write =
71             sizeof(unsigned) +
72             sizeof(time_t) +
73             sizeof(OFF_T) +
74             sizeof(mode_t) +
75             sizeof(INO64_T) +
76             sizeof(DEV64_T) +
77             sizeof(DEV64_T) +
78             sizeof(uid_t) +
79             sizeof(gid_t);
80
81         fdb_open = 1;
82         fdb_close = 0;
83
84         for (i = 0; i < flist_count; i++) {
85                 write_batch_flist_file((char *) fptr[i], bytes_to_write);
86                 write_char_bufs(fptr[i]->basename);
87                 write_char_bufs(fptr[i]->dirname);
88                 write_char_bufs(fptr[i]->basedir);
89                 write_char_bufs(fptr[i]->link);
90                 if (i == flist_count - 1) {
91                         fdb_close = 1;
92                 }
93                 write_char_bufs(fptr[i]->sum);
94         }
95 }
96
97 void write_char_bufs(char *buf)
98 {
99         /* Write the size of the string which will follow  */
100
101         char b[4];
102
103         SIVAL(b, 0, buf != NULL ? strlen(buf) : 0);
104
105         write_batch_flist_file(b, sizeof(int));
106
107         /*  Write the string if there is one */
108
109         if (buf != NULL) {
110                 write_batch_flist_file(buf, strlen(buf));
111         }
112 }
113
114 void write_batch_argvs_file(int argc, char *argv[])
115 {
116         int fdb;
117         int i;
118         char buff[256]; /* XXX */
119         char buff2[MAXPATHLEN + 6];
120         char filename[MAXPATHLEN];
121
122         /* Set up file extension */
123         strlcpy(filename, batch_prefix, sizeof(filename));
124         strlcat(filename, rsync_argvs_file, sizeof(filename));
125
126         /*
127          * Open batch argvs file for writing;
128          * create it if it doesn't exist
129          */
130         fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
131                       S_IREAD | S_IWRITE | S_IEXEC);
132         if (fdb == -1) {
133                 rprintf(FERROR, "Batch file %s open error: %s\n",
134                         filename, strerror(errno));
135                 close(fdb);
136                 exit_cleanup(1);
137         }
138         buff[0] = '\0';
139
140         /* Write argvs info to batch file */
141
142         for (i = 0; i < argc; ++i) {
143                 if (i == argc - 2) /* Skip source directory on cmdline */
144                     continue;
145                 /*
146                  * FIXME:
147                  * I think directly manipulating argv[] is probably bogus
148                  */
149                 if (!strncmp(argv[i], "--write-batch",
150                         strlen("--write-batch"))) {
151                         /* Safer to change it here than script */
152                         /*
153                          * Change to --read-batch=prefix
154                          * to get ready for remote
155                          */
156                         strlcat(buff, "--read-batch=", sizeof(buff));
157                         strlcat(buff, batch_prefix, sizeof(buff));
158                 } else
159                 if (i == argc - 1) {
160                     snprintf(buff2, sizeof(buff2), "${1:-%s}", argv[i]);
161                     strlcat(buff, buff2, sizeof(buff));
162                 }
163                 else {
164                         strlcat(buff, argv[i], sizeof(buff));
165                 }
166
167                 if (i < (argc - 1)) {
168                         strlcat(buff, " ", sizeof(buff));
169                 }
170         }
171         strlcat(buff, "\n", sizeof(buff));
172         if (!write(fdb, buff, strlen(buff))) {
173                 rprintf(FERROR, "Batch file %s write error: %s\n",
174                         filename, strerror(errno));
175                 close(fdb);
176                 exit_cleanup(1);
177         }
178         close(fdb);
179 }
180
181 struct file_list *create_flist_from_batch(void)
182 {
183         unsigned char flags;
184
185         fdb_open = 1;
186         fdb_close = 0;
187
188         batch_flist = new(struct file_list);
189         if (!batch_flist) {
190                 out_of_memory("create_flist_from_batch");
191         }
192         batch_flist->count = 0;
193         batch_flist->malloced = 1000;
194         batch_flist->files = new_array(struct file_struct *,
195                                        batch_flist->malloced);
196         if (!batch_flist->files) {
197                 out_of_memory("create_flist_from_batch");
198         }
199
200         for (flags = read_batch_flags(); flags; flags = read_batch_flags()) {
201
202                 int i = batch_flist->count;
203
204                 if (i >= batch_flist->malloced) {
205                         if (batch_flist->malloced < 1000)
206                                 batch_flist->malloced += 1000;
207                         else
208                                 batch_flist->malloced *= 2;
209                         batch_flist->files
210                                 = realloc_array(batch_flist->files,
211                                                 struct file_struct *,
212                                                 batch_flist->malloced);
213                         if (!batch_flist->files)
214                                 out_of_memory("create_flist_from_batch");
215                 }
216                 read_batch_flist_info(&batch_flist->files[i]);
217                 batch_flist->files[i]->flags = flags;
218
219                 batch_flist->count++;
220         }
221
222         return batch_flist;
223 }
224
225 int read_batch_flist_file(char *buff, int len)
226 {
227         int bytes_read;
228         char filename[MAXPATHLEN];
229
230         if (fdb_open) {
231                 /* Set up file extension */
232                 strlcpy(filename, batch_prefix, sizeof(filename));
233                 strlcat(filename, rsync_flist_file, sizeof(filename));
234
235                 /* Open batch flist file for reading */
236                 fdb = do_open(filename, O_RDONLY, 0);
237                 if (fdb == -1) {
238                         rprintf(FERROR, "Batch file %s open error: %s\n",
239                                 filename, strerror(errno));
240                         close(fdb);
241                         exit_cleanup(1);
242                 }
243                 fdb_open = 0;
244         }
245
246         /* Read flist batch file */
247
248         switch (bytes_read = read(fdb, buff, len)) {
249             case -1:
250                 rprintf(FERROR, "Batch file %s read error: %s\n",
251                         filename, strerror(errno));
252                 close(fdb);
253                 exit_cleanup(1);
254                 break;
255             case 0:     /* EOF */
256                 close(fdb);
257         }
258
259         return bytes_read;
260 }
261
262 unsigned char read_batch_flags(void)
263 {
264         int flags;
265
266         if (read_batch_flist_file((char *) &flags, 4)) {
267                 return 1;
268         } else {
269                 return 0;
270         }
271 }
272
273 void read_batch_flist_info(struct file_struct **fptr)
274 {
275         int int_str_len;
276         char char_str_len[4];
277         char buff[256];
278         struct file_struct *file;
279
280         file = new(struct file_struct);
281         if (!file)
282                 out_of_memory("read_batch_flist_info");
283         memset((char *) file, 0, sizeof(*file));
284
285         *fptr = file;
286
287         /*
288          * Keep these in sync with bytes_to_write assignment
289          * in write_batch_flist_info()
290          */
291         read_batch_flist_file((char *) &file->modtime, sizeof(time_t));
292         read_batch_flist_file((char *) &file->length, sizeof(OFF_T));
293         read_batch_flist_file((char *) &file->mode, sizeof(mode_t));
294         read_batch_flist_file((char *) &file->inode, sizeof(INO64_T));
295         read_batch_flist_file((char *) &file->dev, sizeof(DEV64_T));
296         read_batch_flist_file((char *) &file->rdev, sizeof(DEV64_T));
297         read_batch_flist_file((char *) &file->uid, sizeof(uid_t));
298         read_batch_flist_file((char *) &file->gid, sizeof(gid_t));
299         read_batch_flist_file(char_str_len, sizeof(char_str_len));
300         int_str_len = IVAL(char_str_len, 0);
301         if (int_str_len > 0) {
302                 read_batch_flist_file(buff, int_str_len);
303                 buff[int_str_len] = '\0';
304                 file->basename = strdup(buff);
305         } else {
306                 file->basename = NULL;
307         }
308
309         read_batch_flist_file(char_str_len, sizeof(char_str_len));
310         int_str_len = IVAL(char_str_len, 0);
311         if (int_str_len > 0) {
312                 read_batch_flist_file(buff, int_str_len);
313                 buff[int_str_len] = '\0';
314                 file[0].dirname = strdup(buff);
315         } else {
316                 file[0].dirname = NULL;
317         }
318
319         read_batch_flist_file(char_str_len, sizeof(char_str_len));
320         int_str_len = IVAL(char_str_len, 0);
321         if (int_str_len > 0) {
322                 read_batch_flist_file(buff, int_str_len);
323                 buff[int_str_len] = '\0';
324                 file[0].basedir = strdup(buff);
325         } else {
326                 file[0].basedir = NULL;
327         }
328
329         read_batch_flist_file(char_str_len, sizeof(char_str_len));
330         int_str_len = IVAL(char_str_len, 0);
331         if (int_str_len > 0) {
332                 read_batch_flist_file(buff, int_str_len);
333                 buff[int_str_len] = '\0';
334                 file[0].link = strdup(buff);
335         } else {
336                 file[0].link = NULL;
337         }
338
339         read_batch_flist_file(char_str_len, sizeof(char_str_len));
340         int_str_len = IVAL(char_str_len, 0);
341         if (int_str_len > 0) {
342                 read_batch_flist_file(buff, int_str_len);
343                 buff[int_str_len] = '\0';
344                 file[0].sum = strdup(buff);
345         } else {
346                 file[0].sum = NULL;
347         }
348 }
349
350 void write_batch_csums_file(void *buff, int bytes_to_write)
351 {
352         static int fdb_open = 1;
353         char filename[MAXPATHLEN];
354
355         if (fdb_open) {
356                 /* Set up file extension */
357                 strlcpy(filename, batch_prefix, sizeof(filename));
358                 strlcat(filename, rsync_csums_file, sizeof(filename));
359
360                 /*
361                  * Open batch csums file for writing;
362                  * create it if it doesn't exist
363                  */
364                 fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
365                             S_IREAD | S_IWRITE);
366                 if (fdb == -1) {
367                         rprintf(FERROR, "Batch file %s open error: %s\n",
368                                 filename, strerror(errno));
369                         close(fdb);
370                         exit_cleanup(1);
371                 }
372                 fdb_open = 0;
373         }
374
375         /* Write buffer to batch csums file */
376
377         if (write(fdb, buff, bytes_to_write) == -1) {
378                 rprintf(FERROR, "Batch file %s write error: %s\n",
379                         filename, strerror(errno));
380                 close(fdb);
381                 exit_cleanup(1);
382         }
383 }
384
385 void close_batch_csums_file(void)
386 {
387         close(fdb);
388 }
389
390
391 /**
392  * Write csum info to batch file 
393  *
394  * @todo This will break if s->count is ever larger than maxint.  The
395  * batch code should probably be changed to consistently use the
396  * variable-length integer routines, which is probably a compatible
397  * change.
398  **/
399 void write_batch_csum_info(int *flist_entry, int flist_count,
400                            struct sum_struct *s)
401 {
402         size_t i;
403         int int_count;
404         extern int csum_length;
405
406         fdb_open = 1;
407
408         write_batch_csums_file(flist_entry, sizeof(int));
409         int_count = s ? (int) s->count : 0;
410         write_batch_csums_file(&int_count, sizeof int_count);
411         
412         if (s) {
413                 for (i = 0; i < s->count; i++) {
414                         write_batch_csums_file(&s->sums[i].sum1, sizeof(uint32));
415                         if ((*flist_entry == flist_count - 1)
416                             && (i == s->count - 1)) {
417                                 fdb_close = 1;
418                         }
419                         write_batch_csums_file(s->sums[i].sum2, csum_length);
420                 }
421         }
422 }
423
424 int read_batch_csums_file(char *buff, int len)
425 {
426         static int fdb_open = 1;
427         int bytes_read;
428         char filename[MAXPATHLEN];
429
430         if (fdb_open) {
431                 /* Set up file extension */
432                 strlcpy(filename, batch_prefix, sizeof(filename));
433                 strlcat(filename, rsync_csums_file, sizeof(filename));
434
435                 /* Open batch flist file for reading */
436                 fdb = do_open(filename, O_RDONLY, 0);
437                 if (fdb == -1) {
438                         rprintf(FERROR, "Batch file %s open error: %s\n",
439                                 filename, strerror(errno));
440                         close(fdb);
441                         exit_cleanup(1);
442                 }
443                 fdb_open = 0;
444         }
445
446         /* Read csums batch file */
447
448         bytes_read = read(fdb, buff, len);
449
450         if (bytes_read == -1) {
451                 rprintf(FERROR, "Batch file %s read error: %s\n",
452                         filename, strerror(errno));
453                 close(fdb);
454                 exit_cleanup(1);
455         }
456
457         return bytes_read;
458 }
459
460 void read_batch_csum_info(int flist_entry, struct sum_struct *s,
461                           int *checksums_match)
462 {
463         int i;
464         int file_flist_entry;
465         int file_chunk_ct;
466         uint32 file_sum1;
467         char file_sum2[SUM_LENGTH];
468         extern int csum_length;
469
470         read_batch_csums_file((char *) &file_flist_entry, sizeof(int));
471         if (file_flist_entry != flist_entry) {
472                 rprintf(FINFO, "file_flist_entry (%d) != flist_entry (%d)\n",
473                         file_flist_entry, flist_entry);
474                 close(fdb);
475                 exit_cleanup(1);
476
477         } else {
478                 read_batch_csums_file((char *) &file_chunk_ct,
479                                       sizeof(int));
480                 *checksums_match = 1;
481                 for (i = 0; i < file_chunk_ct; i++) {
482
483                         read_batch_csums_file((char *) &file_sum1,
484                                               sizeof(uint32));
485                         read_batch_csums_file(file_sum2, csum_length);
486
487                         if ((s->sums[i].sum1 != file_sum1) ||
488                             (memcmp(s->sums[i].sum2, file_sum2, csum_length)
489                                 != 0)) {
490                                 *checksums_match = 0;
491                         }
492                 }               /*  end for  */
493         }
494 }
495
496 void write_batch_delta_file(char *buff, int bytes_to_write)
497 {
498         static int fdb_delta_open = 1;
499         char filename[MAXPATHLEN];
500
501         if (fdb_delta_open) {
502                 /* Set up file extension */
503                 strlcpy(filename, batch_prefix, sizeof(filename));
504                 strlcat(filename, rsync_delta_file, sizeof(filename));
505
506                 /*
507                  * Open batch delta file for writing;
508                  * create it if it doesn't exist
509                  */
510                 fdb_delta = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
511                             S_IREAD | S_IWRITE);
512                 if (fdb_delta == -1) {
513                         rprintf(FERROR, "Batch file %s open error: %s\n",
514                                 filename, strerror(errno));
515                         close(fdb_delta);
516                         exit_cleanup(1);
517                 }
518                 fdb_delta_open = 0;
519         }
520
521         /* Write buffer to batch delta file */
522
523         if (write(fdb_delta, buff, bytes_to_write) == -1) {
524                 rprintf(FERROR, "Batch file %s write error: %s\n",
525                         filename, strerror(errno));
526                 close(fdb_delta);
527                 exit_cleanup(1);
528         }
529 }
530
531 void close_batch_delta_file(void)
532 {
533         close(fdb_delta);
534 }
535
536 int read_batch_delta_file(char *buff, int len)
537 {
538         static int fdb_delta_open = 1;
539         int bytes_read;
540         char filename[MAXPATHLEN];
541
542         if (fdb_delta_open) {
543                 /* Set up file extension */
544                 strlcpy(filename, batch_prefix, sizeof(filename));
545                 strlcat(filename, rsync_delta_file, sizeof(filename));
546
547                 /* Open batch flist file for reading */
548                 fdb_delta = do_open(filename, O_RDONLY, 0);
549                 if (fdb_delta == -1) {
550                         rprintf(FERROR, "Batch file %s open error: %s\n",
551                                 filename, strerror(errno));
552                         close(fdb_delta);
553                         exit_cleanup(1);
554                 }
555                 fdb_delta_open = 0;
556         }
557
558         /* Read delta batch file */
559
560         bytes_read = read(fdb_delta, buff, len);
561
562         if (bytes_read == -1) {
563                 rprintf(FERROR, "Batch file %s read error: %s\n",
564                         filename, strerror(errno));
565                 close(fdb_delta);
566                 exit_cleanup(1);
567         }
568
569         return bytes_read;
570 }
571
572 void show_flist(int index, struct file_struct **fptr)
573 {
574         /*  for debugging    show_flist(flist->count, flist->files * */
575
576         int i;
577         for (i = 0; i < index; i++) {
578                 rprintf(FINFO, "flist->flags=%#x\n", fptr[i]->flags);
579                 rprintf(FINFO, "flist->modtime=%#lx\n",
580                         (long unsigned) fptr[i]->modtime);
581                 rprintf(FINFO, "flist->length=%.0f\n",
582                         (double) fptr[i]->length);
583                 rprintf(FINFO, "flist->mode=%#o\n", (int) fptr[i]->mode);
584                 rprintf(FINFO, "flist->basename=%s\n", fptr[i]->basename);
585                 if (fptr[i]->dirname)
586                         rprintf(FINFO, "flist->dirname=%s\n",
587                                 fptr[i]->dirname);
588                 if (fptr[i]->basedir)
589                         rprintf(FINFO, "flist->basedir=%s\n",
590                                 fptr[i]->basedir);
591         }
592 }
593
594 void show_argvs(int argc, char *argv[])
595 {
596         /*  for debugging  * */
597
598         int i;
599         rprintf(FINFO, "BATCH.C:show_argvs,argc=%d\n", argc);
600         for (i = 0; i < argc; i++) {
601                 /*    if (argv[i])   */
602                 rprintf(FINFO, "i=%d,argv[i]=%s\n", i, argv[i]);
603
604         }
605 }