Allow the send_file_entry() and receive_file_entry() routines to be
[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 /* TODO: Someone please rewrite this!  Why in the world don't we use
64  * the send/receive code from flist.c for this? */
65 void write_batch_flist_info(int flist_count, struct file_struct **fptr)
66 {
67         int i;
68         int bytes_to_write;
69
70         /* Write flist info to batch file */
71
72         bytes_to_write =
73             sizeof(time_t) +
74             sizeof(OFF_T) +
75             sizeof(mode_t) +
76             sizeof(INO64_T) +
77             sizeof(DEV64_T) +
78             sizeof(DEV64_T) +
79             sizeof(uid_t) +
80             sizeof(gid_t);
81
82         fdb_open = 1;
83         fdb_close = 0;
84
85         for (i = 0; i < flist_count; i++) {
86                 write_batch_flist_file((char*)&fptr[i]->flags, sizeof fptr[0]->flags);
87                 write_batch_flist_file((char*)fptr[i], bytes_to_write);
88                 write_char_bufs(fptr[i]->basename);
89                 write_char_bufs(fptr[i]->dirname);
90                 write_char_bufs(fptr[i]->basedir);
91                 write_char_bufs(fptr[i]->link);
92                 if (i == flist_count - 1) {
93                         fdb_close = 1;
94                 }
95                 write_char_bufs(fptr[i]->sum);
96         }
97 }
98
99 void write_char_bufs(char *buf)
100 {
101         /* Write the size of the string which will follow  */
102
103         char b[4];
104
105         SIVAL(b, 0, buf != NULL ? strlen(buf) : 0);
106
107         write_batch_flist_file(b, sizeof(int));
108
109         /*  Write the string if there is one */
110
111         if (buf != NULL) {
112                 write_batch_flist_file(buf, strlen(buf));
113         }
114 }
115
116 void write_batch_argvs_file(int argc, char *argv[])
117 {
118         int fdb;
119         int i;
120         char buff[256]; /* XXX */
121         char buff2[MAXPATHLEN + 6];
122         char filename[MAXPATHLEN];
123
124         /* Set up file extension */
125         strlcpy(filename, batch_prefix, sizeof(filename));
126         strlcat(filename, rsync_argvs_file, sizeof(filename));
127
128         /*
129          * Open batch argvs file for writing;
130          * create it if it doesn't exist
131          */
132         fdb = do_open(filename, O_WRONLY | O_CREAT | O_TRUNC,
133                       S_IREAD | S_IWRITE | S_IEXEC);
134         if (fdb == -1) {
135                 rprintf(FERROR, "Batch file %s open error: %s\n",
136                         filename, strerror(errno));
137                 close(fdb);
138                 exit_cleanup(1);
139         }
140         buff[0] = '\0';
141
142         /* Write argvs info to batch file */
143
144         for (i = 0; i < argc; ++i) {
145                 if (i == argc - 2) /* Skip source directory on cmdline */
146                     continue;
147                 /*
148                  * FIXME:
149                  * I think directly manipulating argv[] is probably bogus
150                  */
151                 if (!strncmp(argv[i], "--write-batch",
152                         strlen("--write-batch"))) {
153                         /* Safer to change it here than script */
154                         /*
155                          * Change to --read-batch=prefix
156                          * to get ready for remote
157                          */
158                         strlcat(buff, "--read-batch=", sizeof(buff));
159                         strlcat(buff, batch_prefix, sizeof(buff));
160                 } else
161                 if (i == argc - 1) {
162                     snprintf(buff2, sizeof(buff2), "${1:-%s}", argv[i]);
163                     strlcat(buff, buff2, sizeof(buff));
164                 }
165                 else {
166                         strlcat(buff, argv[i], sizeof(buff));
167                 }
168
169                 if (i < (argc - 1)) {
170                         strlcat(buff, " ", sizeof(buff));
171                 }
172         }
173         strlcat(buff, "\n", sizeof(buff));
174         if (!write(fdb, buff, strlen(buff))) {
175                 rprintf(FERROR, "Batch file %s write error: %s\n",
176                         filename, strerror(errno));
177                 close(fdb);
178                 exit_cleanup(1);
179         }
180         close(fdb);
181 }
182
183 struct file_list *create_flist_from_batch(void)
184 {
185         unsigned short flags;
186
187         fdb_open = 1;
188         fdb_close = 0;
189
190         batch_flist = new(struct file_list);
191         if (!batch_flist) {
192                 out_of_memory("create_flist_from_batch");
193         }
194         batch_flist->count = 0;
195         batch_flist->malloced = 1000;
196         batch_flist->files = new_array(struct file_struct *,
197                                        batch_flist->malloced);
198         if (!batch_flist->files) {
199                 out_of_memory("create_flist_from_batch");
200         }
201
202         for (flags = read_batch_flags(); flags; flags = read_batch_flags()) {
203
204                 int i = batch_flist->count;
205
206                 if (i >= batch_flist->malloced) {
207                         if (batch_flist->malloced < 1000)
208                                 batch_flist->malloced += 1000;
209                         else
210                                 batch_flist->malloced *= 2;
211                         batch_flist->files
212                                 = realloc_array(batch_flist->files,
213                                                 struct file_struct *,
214                                                 batch_flist->malloced);
215                         if (!batch_flist->files)
216                                 out_of_memory("create_flist_from_batch");
217                 }
218                 read_batch_flist_info(&batch_flist->files[i]);
219                 batch_flist->files[i]->flags = flags;
220
221                 batch_flist->count++;
222         }
223
224         return batch_flist;
225 }
226
227 int read_batch_flist_file(char *buff, int len)
228 {
229         int bytes_read;
230         char filename[MAXPATHLEN];
231
232         if (fdb_open) {
233                 /* Set up file extension */
234                 strlcpy(filename, batch_prefix, sizeof(filename));
235                 strlcat(filename, rsync_flist_file, sizeof(filename));
236
237                 /* Open batch flist file for reading */
238                 fdb = do_open(filename, O_RDONLY, 0);
239                 if (fdb == -1) {
240                         rprintf(FERROR, "Batch file %s open error: %s\n",
241                                 filename, strerror(errno));
242                         close(fdb);
243                         exit_cleanup(1);
244                 }
245                 fdb_open = 0;
246         }
247
248         /* Read flist batch file */
249
250         switch (bytes_read = read(fdb, buff, len)) {
251             case -1:
252                 rprintf(FERROR, "Batch file %s read error: %s\n",
253                         filename, strerror(errno));
254                 close(fdb);
255                 exit_cleanup(1);
256                 break;
257             case 0:     /* EOF */
258                 close(fdb);
259         }
260
261         return bytes_read;
262 }
263
264 unsigned short read_batch_flags(void)
265 {
266         unsigned short flags;
267
268         if (read_batch_flist_file((char*)&flags, sizeof flags))
269                 return 1;
270         return 0;
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 }