]> git.gag.com Git - debian/tar/blob - src/buffer.c
603bdc20dc29fa7137715d6e72187b3a69c8b043
[debian/tar] / src / buffer.c
1 /* Buffer management for tar.
2    Copyright (C) 1988 Free Software Foundation
3
4 This file is part of GNU Tar.
5
6 GNU Tar is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Tar is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Tar; see the file COPYING.  If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 /*
21  * Buffer management for tar.
22  *
23  * Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
24  */
25
26 #include <stdio.h>
27 #include <errno.h>
28 #ifndef STDC_HEADERS
29 extern int errno;
30 #endif
31 #include <sys/types.h>          /* For non-Berkeley systems */
32 #include <signal.h>
33 #include <time.h>
34 time_t time();
35
36 #ifndef NO_MTIO
37 #include <sys/ioctl.h>
38 #include <sys/mtio.h>
39 #endif
40
41 #ifdef BSD42
42 #include <sys/file.h>
43 #else
44 #ifndef V7
45 #include <fcntl.h>
46 #endif
47 #endif
48
49 #ifdef  __MSDOS__
50 #include <process.h>
51 #endif
52
53 #ifdef XENIX
54 #include <sys/inode.h>
55 #endif
56
57 #include "tar.h"
58 #include "port.h"
59 #include "rmt.h"
60 #include "regex.h"
61
62 /* Either stdout or stderr:  The thing we write messages (standard msgs, not
63    errors) to.  Stdout unless we're writing a pipe, in which case stderr */
64 FILE *msg_file = stdout;
65
66 #define STDIN   0               /* Standard input  file descriptor */
67 #define STDOUT  1               /* Standard output file descriptor */
68
69 #define PREAD   0               /* Read  file descriptor from pipe() */
70 #define PWRITE  1               /* Write file descriptor from pipe() */
71
72 #define MAGIC_STAT      105     /* Magic status returned by child, if
73                                    it can't exec.  We hope compress/sh
74                                    never return this status! */
75
76 char *valloc();
77
78 void writeerror();
79 void readerror();
80
81 void ck_pipe();
82 void ck_close();
83
84 int backspace_output();
85 extern void finish_header();
86 void flush_archive();
87 int isfile();
88 int new_volume();
89 void verify_volume();
90 extern void to_oct();
91
92 #ifndef __MSDOS__
93 /* Obnoxious test to see if dimwit is trying to dump the archive */
94 dev_t ar_dev;
95 ino_t ar_ino;
96 #endif
97
98 /*
99  * The record pointed to by save_rec should not be overlaid
100  * when reading in a new tape block.  Copy it to record_save_area first, and
101  * change the pointer in *save_rec to point to record_save_area.
102  * Saved_recno records the record number at the time of the save.
103  * This is used by annofile() to print the record number of a file's
104  * header record.
105  */
106 static union record **save_rec;
107  union record record_save_area;
108 static long         saved_recno;
109
110 /*
111  * PID of child program, if f_compress or remote archive access.
112  */
113 static int      childpid = 0;
114
115 /*
116  * Record number of the start of this block of records
117  */
118 long    baserec;
119
120 /*
121  * Error recovery stuff
122  */
123 static int      r_error_count;
124
125 /*
126  * Have we hit EOF yet?
127  */
128 static int      eof;
129
130 /* JF we're reading, but we just read the last record and its time to update */
131 extern time_to_start_writing;
132 int file_to_switch_to= -1;      /* If remote update, close archive, and use
133                                    this descriptor to write to */
134
135 static int volno = 1;           /* JF which volume of a multi-volume tape
136                                    we're on */
137
138 char *save_name = 0;            /* Name of the file we are currently writing */
139 long save_totsize;              /* total size of file we are writing.  Only
140                                    valid if save_name is non_zero */
141 long save_sizeleft;             /* Where we are in the file we are writing.
142                                    Only valid if save_name is non-zero */
143
144 int write_archive_to_stdout;
145
146 /* Used by fl_read and fl_write to store the real info about saved names */
147 static char real_s_name[NAMSIZ];
148 static long real_s_totsize;
149 static long real_s_sizeleft;
150
151 /* Reset the EOF flag (if set), and re-set ar_record, etc */
152
153 void
154 reset_eof()
155 {
156         if(eof) {
157                 eof=0;
158                 ar_record=ar_block;
159                 ar_last=ar_block+blocking;
160                 ar_reading=0;
161         }
162 }
163
164 /*
165  * Return the location of the next available input or output record.
166  * Return NULL for EOF.  Once we have returned NULL, we just keep returning
167  * it, to avoid accidentally going on to the next file on the "tape".
168  */
169 union record *
170 findrec()
171 {
172         if (ar_record == ar_last) {
173                 if (eof)
174                         return (union record *)NULL;    /* EOF */
175                 flush_archive();
176                 if (ar_record == ar_last) {
177                         eof++;
178                         return (union record *)NULL;    /* EOF */
179                 }
180         }
181         return ar_record;
182 }
183
184
185 /*
186  * Indicate that we have used all records up thru the argument.
187  * (should the arg have an off-by-1? XXX FIXME)
188  */
189 void
190 userec(rec)
191         union record *rec;
192 {
193         while(rec >= ar_record)
194                 ar_record++;
195         /*
196          * Do NOT flush the archive here.  If we do, the same
197          * argument to userec() could mean the next record (if the
198          * input block is exactly one record long), which is not what
199          * is intended.
200          */
201         if (ar_record > ar_last)
202                 abort();
203 }
204
205
206 /*
207  * Return a pointer to the end of the current records buffer.
208  * All the space between findrec() and endofrecs() is available
209  * for filling with data, or taking data from.
210  */
211 union record *
212 endofrecs()
213 {
214         return ar_last;
215 }
216
217
218 /*
219  * Duplicate a file descriptor into a certain slot.
220  * Equivalent to BSD "dup2" with error reporting.
221  */
222 void
223 dupto(from, to, msg)
224         int from, to;
225         char *msg;
226 {
227         int err;
228
229         if (from != to) {
230                 err=close(to);
231                 if(err<0 && errno!=EBADF) {
232                         msg_perror("Cannot close descriptor %d",to);
233                         exit(EX_SYSTEM);
234                 }
235                 err = dup(from);
236                 if (err != to) {
237                         msg_perror("cannot dup %s",msg);
238                         exit(EX_SYSTEM);
239                 }
240                 ck_close(from);
241         }
242 }
243
244 #ifdef __MSDOS__
245 void
246 child_open()
247 {
248         fprintf(stderr,"MS-DOS %s can't use compressed or remote archives\n",tar);
249         exit(EX_ARGSBAD);
250 }
251 #else
252 void
253 child_open()
254 {
255         int pipe[2];
256         int err = 0;
257
258         int kidpipe[2];
259         int kidchildpid;
260
261 #define READ    0
262 #define WRITE   1
263
264         ck_pipe(pipe);
265
266         childpid=fork();
267         if(childpid<0) {
268                 msg_perror("cannot fork");
269                 exit(EX_SYSTEM);
270         }
271         if(childpid>0) {
272                 /* We're the parent.  Clean up and be happy */
273                 /* This, at least, is easy */
274
275                 if(ar_reading) {
276                         f_reblock++;
277                         archive=pipe[READ];
278                         ck_close(pipe[WRITE]);
279                 } else {
280                         archive = pipe[WRITE];
281                         ck_close(pipe[READ]);
282                 }
283                 return;
284         }
285
286         /* We're the kid */
287         if(ar_reading) {
288                 dupto(pipe[WRITE],STDOUT,"(child) pipe to stdout");
289                 ck_close(pipe[READ]);
290         } else {
291                 dupto(pipe[READ],STDIN,"(child) pipe to stdin");
292                 ck_close(pipe[WRITE]);
293         }
294
295         /* We need a child tar only if
296            1: we're reading/writing stdin/out (to force reblocking)
297            2: the file is to be accessed by rmt (compress doesn't know how)
298            3: the file is not a plain file */
299 #ifdef NO_REMOTE
300         if(!(ar_file[0]=='-' && ar_file[1]=='\0') && isfile(ar_file))
301 #else
302         if(!(ar_file[0]=='-' && ar_file[1]=='\0') && !_remdev(ar_file) && isfile(ar_file))
303 #endif
304         {
305                 /* We don't need a child tar.  Open the archive */
306                 if(ar_reading) {
307                         archive=open(ar_file, O_RDONLY|O_BINARY, 0666);
308                         if(archive<0) {
309                                 msg_perror("can't open archive %s",ar_file);
310                                 exit(EX_BADARCH);
311                         }
312                         dupto(archive,STDIN,"archive to stdin");
313                         /* close(archive); */
314                 } else {
315                         archive=creat(ar_file,0666);
316                         if(archive<0) {
317                                 msg_perror("can't open archive %s",ar_file);
318                                 exit(EX_BADARCH);
319                         }
320                         dupto(archive,STDOUT,"archive to stdout");
321                         /* close(archive); */
322                 }
323         } else {
324                 /* We need a child tar */
325                 ck_pipe(kidpipe);
326
327                 kidchildpid=fork();
328                 if(kidchildpid<0) {
329                         msg_perror("child can't fork");
330                         exit(EX_SYSTEM);
331                 }
332
333                 if(kidchildpid>0) {
334                         /* About to exec compress:  set up the files */
335                         if(ar_reading) {
336                                 dupto(kidpipe[READ],STDIN,"((child)) pipe to stdin");
337                                 ck_close(kidpipe[WRITE]);
338                                 /* dup2(pipe[WRITE],STDOUT); */
339                         } else {
340                                 /* dup2(pipe[READ],STDIN); */
341                                 dupto(kidpipe[WRITE],STDOUT,"((child)) pipe to stdout");
342                                 ck_close(kidpipe[READ]);
343                         }
344                         /* ck_close(pipe[READ]); */
345                         /* ck_close(pipe[WRITE]); */
346                         /* ck_close(kidpipe[READ]);
347                         ck_close(kidpipe[WRITE]); */
348                 } else {
349                 /* Grandchild.  Do the right thing, namely sit here and
350                    read/write the archive, and feed stuff back to compress */
351                         tar="tar (child)";
352                         if(ar_reading) {
353                                 dupto(kidpipe[WRITE],STDOUT,"[child] pipe to stdout");
354                                 ck_close(kidpipe[READ]);
355                         } else {
356                                 dupto(kidpipe[READ],STDIN,"[child] pipe to stdin");
357                                 ck_close(kidpipe[WRITE]);
358                         }
359
360                         if (ar_file[0] == '-' && ar_file[1] == '\0') {
361                                 if (ar_reading)
362                                         archive = STDIN;
363                                 else
364                                         archive = STDOUT;
365                         } else /* This can't happen if (ar_reading==2)
366                                 archive = rmtopen(ar_file, O_RDWR|O_CREAT|O_BINARY, 0666);
367                         else */if(ar_reading)
368                                 archive = rmtopen(ar_file, O_RDONLY|O_BINARY, 0666);
369                         else
370                                 archive = rmtcreat(ar_file, 0666);
371
372                         if (archive < 0) {
373                                 msg_perror("can't open archive %s",ar_file);
374                                 exit(EX_BADARCH);
375                         }
376
377                         if(ar_reading) {
378                                 for(;;) {
379                                         char *ptr;
380                                         int max,count;
381                 
382                                         r_error_count = 0;
383                                 error_loop:
384                                         err=rmtread(archive, ar_block->charptr,(int)(blocksize));
385                                         if(err<0) {
386                                                 readerror();
387                                                 goto error_loop;
388                                         }
389                                         if(err==0)
390                                                 break;
391                                         ptr = ar_block->charptr;
392                                         max = err;
393                                         while(max) {
394                                                 count = (max<RECORDSIZE) ? max : RECORDSIZE;
395                                                 err=write(STDOUT,ptr,count);
396                                                 if(err!=count) {
397                                                         if(err<0) {
398                                                                 msg_perror("can't write to compress");
399                                                                 exit(EX_SYSTEM);
400                                                         } else
401                                                                 msg("write to compress short %d bytes",count-err);
402                                                         count = (err<0) ? 0 : err;
403                                                 }
404                                                 ptr+=count;
405                                                 max-=count;
406                                         }
407                                 }
408                         } else {
409                                 for(;;) {
410                                         int n;
411                                         char *ptr;
412                 
413                                         n=blocksize;
414                                         ptr = ar_block->charptr;
415                                         while(n) {
416                                                 err=read(STDIN,ptr,(n<RECORDSIZE) ? n : RECORDSIZE);
417                                                 if(err<=0)
418                                                         break;
419                                                 n-=err;
420                                                 ptr+=err;
421                                         }
422                                                 /* EOF */
423                                         if(err==0) {
424                                                 if(f_compress<2)
425                                                         blocksize-=n;
426                                                 else
427                                                         bzero(ar_block->charptr+blocksize-n,n);
428                                                 err=rmtwrite(archive,ar_block->charptr,blocksize);
429                                                 if(err!=(blocksize))
430                                                         writeerror(err);
431                                                 if(f_compress<2)
432                                                         blocksize+=n;
433                                                 break;
434                                         }
435                                         if(n) {
436                                                 msg_perror("can't read from compress");
437                                                 exit(EX_SYSTEM);
438                                         }
439                                         err=rmtwrite(archive, ar_block->charptr, (int)blocksize);
440                                         if(err!=blocksize)
441                                                 writeerror(err);
442                                 }
443                         }
444                 
445                         /* close_archive(); */
446                         exit(0);
447                 }
448         }
449                 /* So we should exec compress (-d) */
450         if(ar_reading)
451                 execlp("compress", "compress", "-d", (char *)0);
452         else
453                 execlp("compress", "compress", (char *)0);
454         msg_perror("can't exec compress");
455         _exit(EX_SYSTEM);
456 }
457
458
459 /* return non-zero if p is the name of a directory */
460 int
461 isfile(p)
462 char *p;
463 {
464         struct stat stbuf;
465
466         if(stat(p,&stbuf)<0)
467                 return 1;
468         if(S_ISREG(stbuf.st_mode))
469                 return 1;
470         return 0;
471 }
472
473 #endif
474
475 /*
476  * Open an archive file.  The argument specifies whether we are
477  * reading or writing.
478  */
479 /* JF if the arg is 2, open for reading and writing. */
480 void
481 open_archive(reading)
482         int reading;
483 {
484         msg_file = f_exstdout ? stderr : stdout;
485
486         if (blocksize == 0) {
487                 msg("invalid value for blocksize");
488                 exit(EX_ARGSBAD);
489         }
490
491         if(ar_file==0) {
492                 msg("No archive name given, what should I do?");
493                 exit(EX_BADARCH);
494         }
495
496         /*NOSTRICT*/
497         if(f_multivol) {
498                 ar_block = (union record *) valloc((unsigned)(blocksize+(2*RECORDSIZE)));
499                 if(ar_block)
500                         ar_block += 2;
501         } else
502                 ar_block = (union record *) valloc((unsigned)blocksize);
503         if (!ar_block) {
504                 msg("could not allocate memory for blocking factor %d",
505                         blocking);
506                 exit(EX_ARGSBAD);
507         }
508
509         ar_record = ar_block;
510         ar_last   = ar_block + blocking;
511         ar_reading = reading;
512
513         if (f_compress) {
514                 if(reading==2 || f_verify) {
515                         msg("cannot update or verify compressed archives");
516                         exit(EX_ARGSBAD);
517                 }
518                 child_open();
519                 if(!reading && ar_file[0]=='-' && ar_file[1]=='\0')
520                         msg_file = stderr;
521                 /* child_open(rem_host, rem_file); */
522         } else if (ar_file[0] == '-' && ar_file[1] == '\0') {
523                 f_reblock++;    /* Could be a pipe, be safe */
524                 if(f_verify) {
525                         msg("can't verify stdin/stdout archive");
526                         exit(EX_ARGSBAD);
527                 }
528                 if(reading==2) {
529                         archive=STDIN;
530                         msg_file=stderr;
531                         write_archive_to_stdout++;
532                 } else if (reading)
533                         archive = STDIN;
534                 else {
535                         archive = STDOUT;
536                         msg_file = stderr;
537                 }
538         } else if (reading==2 || f_verify) {
539                 archive = rmtopen(ar_file, O_RDWR|O_CREAT|O_BINARY, 0666);
540         } else if(reading) {
541                 archive = rmtopen(ar_file, O_RDONLY|O_BINARY, 0666);
542         } else {
543                 archive = rmtcreat(ar_file, 0666);
544         }
545         if (archive < 0) {
546                 msg_perror("can't open %s",ar_file);
547                 exit(EX_BADARCH);
548         }
549
550 #ifndef __MSDOS__
551         if(!_isrmt(archive)) {
552                 struct stat tmp_stat;
553
554                 fstat(archive,&tmp_stat);
555                 if(S_ISREG(tmp_stat.st_mode)) {
556                         ar_dev=tmp_stat.st_dev;
557                         ar_ino=tmp_stat.st_ino;
558                 }
559         }
560 #endif
561
562 #ifdef  __MSDOS__
563         setmode(archive, O_BINARY);
564 #endif
565
566         if (reading) {
567                 ar_last = ar_block;             /* Set up for 1st block = # 0 */
568                 (void) findrec();               /* Read it in, check for EOF */
569
570                 if(f_volhdr) {
571                         union record *head;
572 #if 0
573                         char *ptr;
574
575                         if(f_multivol) {
576                                 ptr=malloc(strlen(f_volhdr)+20);
577                                 sprintf(ptr,"%s Volume %d",f_volhdr,1);
578                         } else
579                                 ptr=f_volhdr;
580 #endif
581                         head=findrec();
582                         if(!head) {
583                                 msg("Archive not labelled to match %s",f_volhdr);
584                                 exit(EX_BADVOL);
585                         }
586                         if (re_match (label_pattern, head->header.name,
587                                       strlen (head->header.name), 0, 0) < 0) {
588                                 msg ("Volume mismatch!  %s!=%s", f_volhdr,
589                                      head->header.name);
590                                 exit (EX_BADVOL);
591                         }
592 #if 0                   
593                         if(strcmp(ptr,head->header.name)) {
594                                 msg("Volume mismatch!  %s!=%s",ptr,head->header.name);
595                                 exit(EX_BADVOL);
596                         }
597                         if(ptr!=f_volhdr)
598                                 free(ptr);
599 #endif
600                 }
601         } else if(f_volhdr) {
602                 bzero((void *)ar_block,RECORDSIZE);
603                 if(f_multivol)
604                         sprintf(ar_block->header.name,"%s Volume 1",f_volhdr);
605                 else
606                         strcpy(ar_block->header.name,f_volhdr);
607                 ar_block->header.linkflag = LF_VOLHDR;
608                 to_oct(time(0), 1+12, ar_block->header.mtime);
609                 finish_header(ar_block);
610                 /* ar_record++; */
611         }
612 }
613
614
615 /*
616  * Remember a union record * as pointing to something that we
617  * need to keep when reading onward in the file.  Only one such
618  * thing can be remembered at once, and it only works when reading
619  * an archive.
620  *
621  * We calculate "offset" then add it because some compilers end up
622  * adding (baserec+ar_record), doing a 9-bit shift of baserec, then
623  * subtracting ar_block from that, shifting it back, losing the top 9 bits.
624  */
625 void
626 saverec(pointer)
627         union record **pointer;
628 {
629         long offset;
630
631         save_rec = pointer;
632         offset = ar_record - ar_block;
633         saved_recno = baserec + offset;
634 }
635
636 /*
637  * Perform a write to flush the buffer.
638  */
639
640 /*send_buffer_to_file();
641   if(new_volume) {
642         deal_with_new_volume_stuff();
643         send_buffer_to_file();
644   }
645  */
646
647 void
648 fl_write()
649 {
650         int err;
651         int copy_back;
652         static long bytes_written = 0;
653
654         if(tape_length && bytes_written >= tape_length * 1024) {
655                 errno = ENOSPC;
656                 err = 0;
657         } else
658                 err = rmtwrite(archive, ar_block->charptr,(int) blocksize);
659         if(err!=blocksize && !f_multivol)
660                 writeerror(err);
661         else if (f_totals)
662                 tot_written += blocksize;
663
664         if(err>0)
665                 bytes_written+=err;
666         if (err == blocksize) {
667                 if(f_multivol) {
668                         if(!save_name) {
669                                 real_s_name[0]='\0';
670                                 real_s_totsize=0;
671                                 real_s_sizeleft = 0;
672                                 return;
673                         }
674 #ifdef __MSDOS__
675                         if(save_name[1]==':')
676                                 save_name+=2;
677 #endif
678                         while(*save_name=='/')
679                                 save_name++;
680
681                         strcpy(real_s_name,save_name);
682                         real_s_totsize = save_totsize;
683                         real_s_sizeleft = save_sizeleft;
684                 }
685                 return;
686         }
687
688         /* We're multivol  Panic if we didn't get the right kind of response */
689         /* ENXIO is for the UNIX PC */
690         if(err>0 || (err<0 && errno!=ENOSPC && errno!=EIO && errno!=ENXIO))
691                 writeerror(err);
692
693         if(new_volume(0)<0)
694                 return;
695         bytes_written=0;
696         if(f_volhdr && real_s_name[0]) {
697                 copy_back=2;
698                 ar_block-=2;
699         } else if(f_volhdr || real_s_name[0]) {
700                 copy_back = 1;
701                 ar_block--;
702         } else
703                 copy_back = 0;
704         if(f_volhdr) {
705                 bzero((void *)ar_block,RECORDSIZE);
706                 sprintf(ar_block->header.name,"%s Volume %d",f_volhdr,volno);
707                 to_oct(time(0), 1+12, ar_block->header.mtime);
708                 ar_block->header.linkflag = LF_VOLHDR;
709                 finish_header(ar_block);
710         }
711         if(real_s_name[0]) {
712                 int tmp;
713
714                 if(f_volhdr)
715                         ar_block++;
716                 bzero((void *)ar_block,RECORDSIZE);
717                 strcpy(ar_block->header.name,real_s_name);
718                 ar_block->header.linkflag = LF_MULTIVOL;
719                 to_oct((long)real_s_sizeleft,1+12,
720                        ar_block->header.size);
721                 to_oct((long)real_s_totsize-real_s_sizeleft,
722                        1+12,ar_block->header.offset);
723                 tmp=f_verbose;
724                 f_verbose=0;
725                 finish_header(ar_block);
726                 f_verbose=tmp;
727                 if(f_volhdr)
728                         ar_block--;
729         }
730
731         err = rmtwrite(archive, ar_block->charptr,(int) blocksize);
732         if(err!=blocksize)
733                 writeerror(err);
734         else if (f_totals)
735                 tot_written += blocksize;
736                 
737
738         bytes_written = blocksize;
739         if(copy_back) {
740                 ar_block+=copy_back;
741                 bcopy((void *)(ar_block+blocking-copy_back),
742                       (void *)ar_record,
743                       copy_back*RECORDSIZE);
744                 ar_record+=copy_back;
745
746                 if(real_s_sizeleft>=copy_back*RECORDSIZE)
747                         real_s_sizeleft-=copy_back*RECORDSIZE;
748                 else if((real_s_sizeleft+RECORDSIZE-1)/RECORDSIZE<=copy_back)
749                         real_s_name[0] = '\0';
750                 else {
751 #ifdef __MSDOS__
752                         if(save_name[1]==':')
753                                 save_name+=2;
754 #endif
755                         while(*save_name=='/')
756                                 save_name++;
757
758                         strcpy(real_s_name,save_name);
759                         real_s_sizeleft = save_sizeleft;
760                         real_s_totsize=save_totsize;
761                 }
762                 copy_back = 0;
763         }
764 }
765
766 /* Handle write errors on the archive.  Write errors are always fatal */
767 /* Hitting the end of a volume does not cause a write error unless the write
768 *  was the first block of the volume */
769
770 void
771 writeerror(err)
772 int err;
773 {
774         if (err < 0) {
775                 msg_perror("can't write to %s",ar_file);
776                 exit(EX_BADARCH);
777         } else {
778                 msg("only wrote %u of %u bytes to %s",err,blocksize,ar_file);
779                 exit(EX_BADARCH);
780         }
781 }
782
783 /*
784  * Handle read errors on the archive.
785  *
786  * If the read should be retried, readerror() returns to the caller.
787  */
788 void
789 readerror()
790 {
791 #       define  READ_ERROR_MAX  10
792
793         read_error_flag++;              /* Tell callers */
794
795         msg_perror("read error on %s",ar_file);
796
797         if (baserec == 0) {
798                 /* First block of tape.  Probably stupidity error */
799                 exit(EX_BADARCH);
800         }
801
802         /*
803          * Read error in mid archive.  We retry up to READ_ERROR_MAX times
804          * and then give up on reading the archive.  We set read_error_flag
805          * for our callers, so they can cope if they want.
806          */
807         if (r_error_count++ > READ_ERROR_MAX) {
808                 msg("Too many errors, quitting.");
809                 exit(EX_BADARCH);
810         }
811         return;
812 }
813
814
815 /*
816  * Perform a read to flush the buffer.
817  */
818 void
819 fl_read()
820 {
821         int err;                /* Result from system call */
822         int left;               /* Bytes left */
823         char *more;             /* Pointer to next byte to read */
824
825         /*
826          * Clear the count of errors.  This only applies to a single
827          * call to fl_read.  We leave read_error_flag alone; it is
828          * only turned off by higher level software.
829          */
830         r_error_count = 0;      /* Clear error count */
831
832         /*
833          * If we are about to wipe out a record that
834          * somebody needs to keep, copy it out to a holding
835          * area and adjust somebody's pointer to it.
836          */
837         if (save_rec &&
838             *save_rec >= ar_record &&
839             *save_rec < ar_last) {
840                 record_save_area = **save_rec;
841                 *save_rec = &record_save_area;
842         }
843         if(write_archive_to_stdout && baserec!=0) {
844                 err=rmtwrite(1, ar_block->charptr, blocksize);
845                 if(err!=blocksize)
846                         writeerror(err);
847         }
848         if(f_multivol) {
849                 if(save_name) {
850                         if(save_name!=real_s_name) {
851 #ifdef __MSDOS__
852                                 if(save_name[1]==':')
853                                         save_name+=2;
854 #endif
855                                 while(*save_name=='/')
856                                         save_name++;
857
858                                 strcpy(real_s_name,save_name);
859                                 save_name=real_s_name;
860                         }
861                         real_s_totsize = save_totsize;
862                         real_s_sizeleft = save_sizeleft;
863                                 
864                 } else {
865                         real_s_name[0]='\0';
866                         real_s_totsize=0;
867                         real_s_sizeleft = 0;
868                 }
869         }
870
871 error_loop:
872         err = rmtread(archive, ar_block->charptr, (int)blocksize);
873         if (err == blocksize)
874                 return;
875
876         if((err == 0 || (err<0 && errno==ENOSPC)) && f_multivol) {
877                 union record *head;
878
879         try_volume:
880                 if(new_volume((cmd_mode==CMD_APPEND || cmd_mode==CMD_CAT || cmd_mode==CMD_UPDATE) ? 2 : 1)<0)
881                         return;
882         vol_error:
883                 err = rmtread(archive, ar_block->charptr,(int) blocksize);
884                 if(err < 0) {
885                         readerror();
886                         goto vol_error;
887                 }
888                 if(err!=blocksize)
889                         goto short_read;
890
891                 head=ar_block;
892
893                 if(head->header.linkflag==LF_VOLHDR) {
894                         if(f_volhdr) {
895 #if 0
896                                 char *ptr;
897
898                                 ptr=(char *)malloc(strlen(f_volhdr)+20);
899                                 sprintf(ptr,"%s Volume %d",f_volhdr,volno);
900 #endif
901                                 if (re_match (label_pattern, head->header.name,
902                                               strlen (head->header.name),
903                                               0, 0) < 0) {
904                                         msg("Volume mismatch! %s!=%s",f_volhdr,
905                                             head->header.name);
906                                         --volno;
907                                         goto try_volume;
908                                       }
909                                     
910 #if 0
911                                 if(strcmp(ptr,head->header.name)) {
912                                         msg("Volume mismatch! %s!=%s",ptr,head->header.name);
913                                         --volno;
914                                         free(ptr);
915                                         goto try_volume;
916                                 }
917                                 free(ptr);
918 #endif
919                         }
920                         if(f_verbose)
921                                 fprintf(msg_file,"Reading %s\n",head->header.name);
922                         head++;
923                 } else if(f_volhdr) {
924                         msg("Warning:  No volume header!");
925                 }
926
927                 if(real_s_name[0]) {
928                         long from_oct();
929
930                         if(head->header.linkflag!=LF_MULTIVOL || strcmp(head->header.name,real_s_name)) {
931                                 msg("%s is not continued on this volume!",real_s_name);
932                                 --volno;
933                                 goto try_volume;
934                         }
935                         if(real_s_totsize!=from_oct(1+12,head->header.size)+from_oct(1+12,head->header.offset)) {
936                                 msg("%s is the wrong size (%ld!=%ld+%ld)",
937                                        head->header.name,save_totsize,
938                                        from_oct(1+12,head->header.size),
939                                        from_oct(1+12,head->header.offset));
940                                 --volno;
941                                 goto try_volume;
942                         }
943                         if(real_s_totsize-real_s_sizeleft!=from_oct(1+12,head->header.offset)) {
944                                 msg("This volume is out of sequence");
945                                 --volno;
946                                 goto try_volume;
947                         }
948                         head++;
949                 }
950                 ar_record=head;
951                 return;
952         } else if (err < 0) {
953                 readerror();
954                 goto error_loop;        /* Try again */
955         }
956
957  short_read:
958         more = ar_block->charptr + err;
959         left = blocksize - err;
960
961 again:
962         if (0 == (((unsigned)left) % RECORDSIZE)) {
963                 /* FIXME, for size=0, multi vol support */
964                 /* On the first block, warn about the problem */
965                 if (!f_reblock && baserec == 0 && f_verbose && err > 0) {
966                 /*      msg("Blocksize = %d record%s",
967                                 err / RECORDSIZE, (err > RECORDSIZE)? "s": "");*/
968                         msg("Blocksize = %d records", err / RECORDSIZE);
969                 }
970                 ar_last = ar_block + ((unsigned)(blocksize - left))/RECORDSIZE;
971                 return;
972         }
973         if (f_reblock) {
974                 /*
975                  * User warned us about this.  Fix up.
976                  */
977                 if (left > 0) {
978 error2loop:
979                         err = rmtread(archive, more, (int)left);
980                         if (err < 0) {
981                                 readerror();
982                                 goto error2loop;        /* Try again */
983                         }
984                         if (err == 0) {
985                                 msg("archive %s EOF not on block boundary",ar_file);
986                                 exit(EX_BADARCH);
987                         }
988                         left -= err;
989                         more += err;
990                         goto again;
991                 }
992         } else {
993                 msg("only read %d bytes from archive %s",err,ar_file);
994                 exit(EX_BADARCH);
995         }
996 }
997
998
999 /*
1000  * Flush the current buffer to/from the archive.
1001  */
1002 void
1003 flush_archive()
1004 {
1005         int c;
1006
1007         baserec += ar_last - ar_block;  /* Keep track of block #s */
1008         ar_record = ar_block;           /* Restore pointer to start */
1009         ar_last = ar_block + blocking;  /* Restore pointer to end */
1010
1011         if (ar_reading) {
1012                 if(time_to_start_writing) {
1013                         time_to_start_writing=0;
1014                         ar_reading=0;
1015
1016                         if(file_to_switch_to>=0) {
1017                                 if((c=rmtclose(archive))<0)
1018                                         msg_perror("Warning: can't close %s(%d,%d)",ar_file,archive,c);
1019
1020                                 archive=file_to_switch_to;
1021                         } else
1022                                 (void)backspace_output();
1023                         fl_write();
1024                 } else
1025                         fl_read();
1026         } else {
1027                 fl_write();
1028         }
1029 }
1030
1031 /* Backspace the archive descriptor by one blocks worth.
1032    If its a tape, MTIOCTOP will work.  If its something else,
1033    we try to seek on it.  If we can't seek, we lose! */
1034 int
1035 backspace_output()
1036 {
1037         long cur;
1038         /* int er; */
1039         extern char *output_start;
1040
1041 #ifdef MTIOCTOP
1042         struct mtop t;
1043
1044         t.mt_op = MTBSR;
1045         t.mt_count = 1;
1046         if((rmtioctl(archive,MTIOCTOP,&t))>=0)
1047                 return 1;
1048         if(errno==EIO && (rmtioctl(archive,MTIOCTOP,&t))>=0)
1049                 return 1;
1050 #endif
1051
1052                 cur=rmtlseek(archive,0L,1);
1053         cur-=blocksize;
1054         /* Seek back to the beginning of this block and
1055            start writing there. */
1056
1057         if(rmtlseek(archive,cur,0)!=cur) {
1058                 /* Lseek failed.  Try a different method */
1059                 msg("Couldn't backspace archive file.  It may be unreadable without -i.");
1060                 /* Replace the first part of the block with nulls */
1061                 if(ar_block->charptr!=output_start)
1062                         bzero(ar_block->charptr,output_start-ar_block->charptr);
1063                 return 2;
1064         }
1065         return 3;
1066 }
1067
1068
1069 /*
1070  * Close the archive file.
1071  */
1072 void
1073 close_archive()
1074 {
1075         int child;
1076         int status;
1077         int c;
1078
1079         if (time_to_start_writing || !ar_reading)
1080                 flush_archive();
1081         if(cmd_mode==CMD_DELETE) {
1082                 off_t pos;
1083
1084                 pos = rmtlseek(archive,0L,1);
1085 #ifndef __MSDOS__
1086                 (void) ftruncate(archive,pos);
1087 #else
1088                 (void)rmtwrite(archive,"",0);
1089 #endif
1090         }
1091         if(f_verify)
1092                 verify_volume();
1093
1094         if((c=rmtclose(archive))<0)
1095                 msg_perror("Warning: can't close %s(%d,%d)",ar_file,archive,c);
1096
1097 #ifndef __MSDOS__
1098         if (childpid) {
1099                 /*
1100                  * Loop waiting for the right child to die, or for
1101                  * no more kids.
1102                  */
1103                 while (((child = wait(&status)) != childpid) && child != -1)
1104                         ;
1105
1106                 if (child != -1) {
1107                         switch (WTERMSIG(status)) {
1108                         case 0:
1109                                 /* Child voluntarily terminated  -- but why? */
1110                                 if (WEXITSTATUS(status) == MAGIC_STAT) {
1111                                         exit(EX_SYSTEM);/* Child had trouble */
1112                                 }
1113                                 if (WEXITSTATUS(status) == (SIGPIPE + 128)) {
1114                                         /*
1115                                          * /bin/sh returns this if its child
1116                                          * dies with SIGPIPE.  'Sok.
1117                                          */
1118                                         break;
1119                                 } else if (WEXITSTATUS(status))
1120                                         msg("child returned status %d",
1121                                                 WEXITSTATUS(status));
1122                         case SIGPIPE:
1123                                 break;          /* This is OK. */
1124
1125                         default:
1126                                 msg("child died with signal %d%s",
1127                                  WTERMSIG(status),
1128                                  WIFCOREDUMPED(status)? " (core dumped)": "");
1129                         }
1130                 }
1131         }
1132 #endif  /* __MSDOS__ */
1133 }
1134
1135
1136 #ifdef DONTDEF
1137 /*
1138  * Message management.
1139  *
1140  * anno writes a message prefix on stream (eg stdout, stderr).
1141  *
1142  * The specified prefix is normally output followed by a colon and a space.
1143  * However, if other command line options are set, more output can come
1144  * out, such as the record # within the archive.
1145  *
1146  * If the specified prefix is NULL, no output is produced unless the
1147  * command line option(s) are set.
1148  *
1149  * If the third argument is 1, the "saved" record # is used; if 0, the
1150  * "current" record # is used.
1151  */
1152 void
1153 anno(stream, prefix, savedp)
1154         FILE    *stream;
1155         char    *prefix;
1156         int     savedp;
1157 {
1158 #       define  MAXANNO 50
1159         char    buffer[MAXANNO];        /* Holds annorecment */
1160 #       define  ANNOWIDTH 13
1161         int     space;
1162         long    offset;
1163         int     save_e;
1164
1165         save_e=errno;
1166         /* Make sure previous output gets out in sequence */
1167         if (stream == stderr)
1168                 fflush(stdout);
1169         if (f_sayblock) {
1170                 if (prefix) {
1171                         fputs(prefix, stream);
1172                         putc(' ', stream);
1173                 }
1174                 offset = ar_record - ar_block;
1175                 (void) sprintf(buffer, "rec %d: ",
1176                         savedp? saved_recno:
1177                                 baserec + offset);
1178                 fputs(buffer, stream);
1179                 space = ANNOWIDTH - strlen(buffer);
1180                 if (space > 0) {
1181                         fprintf(stream, "%*s", space, "");
1182                 }
1183         } else if (prefix) {
1184                 fputs(prefix, stream);
1185                 fputs(": ", stream);
1186         }
1187         errno=save_e;
1188 }
1189 #endif
1190
1191 /* We've hit the end of the old volume.  Close it and open the next one */
1192 /* Values for type:  0: writing  1: reading  2: updating */
1193 int
1194 new_volume(type)
1195 int     type;
1196 {
1197         int     c;
1198         char    inbuf[80];
1199         char    *p;
1200         static FILE *read_file = 0;
1201         extern int now_verifying;
1202         extern char TTY_NAME[];
1203         char *getenv();
1204
1205         if(!read_file && !f_run_script_at_end)
1206                 read_file = (archive==0) ? fopen(TTY_NAME, "r") : stdin;
1207
1208         if(now_verifying)
1209                 return -1;
1210         if(f_verify)
1211                 verify_volume();
1212         if((c=rmtclose(archive))<0)
1213                 msg_perror("Warning: can't close %s(%d,%d)",ar_file,archive,c);
1214
1215         volno++;
1216  tryagain:
1217         if (f_run_script_at_end)
1218                 system(info_script);
1219         else for(;;) {
1220                 fprintf(msg_file,"\007Prepare volume #%d and hit return: ",volno);
1221                 fflush(msg_file);
1222                 if(fgets(inbuf,sizeof(inbuf),read_file)==0) {
1223                         fprintf(msg_file,"EOF?  What does that mean?");
1224                         if(cmd_mode!=CMD_EXTRACT && cmd_mode!=CMD_LIST && cmd_mode!=CMD_DIFF)
1225                                 msg("Warning:  Archive is INCOMPLETE!");
1226                         exit(EX_BADARCH);
1227                 }
1228                 if(inbuf[0]=='\n' || inbuf[0]=='y' || inbuf[0]=='Y')
1229                         break;
1230
1231                 switch(inbuf[0]) {
1232                 case '?':
1233                 {
1234                         fprintf(msg_file,"\
1235  n [name]   Give a new filename for the next (and subsequent) volume(s)\n\
1236  q          Abort tar\n\
1237  !          Spawn a subshell\n\
1238  ?          Print this list\n");
1239                 }
1240                         break;
1241
1242                 case 'q':       /* Quit */
1243                         fprintf(msg_file,"No new volume; exiting.\n");
1244                         if(cmd_mode!=CMD_EXTRACT && cmd_mode!=CMD_LIST && cmd_mode!=CMD_DIFF)
1245                                 msg("Warning:  Archive is INCOMPLETE!");
1246                         exit(EX_BADARCH);
1247
1248                 case 'n':       /* Get new file name */
1249                 {
1250                         char *q,*r;
1251                         static char *old_name;
1252
1253                         for(q= &inbuf[1];*q==' ' || *q=='\t';q++)
1254                                 ;
1255                         for(r=q;*r;r++)
1256                                 if(*r=='\n')
1257                                         *r='\0';
1258                         if(old_name)
1259                                 free(old_name);
1260                         old_name=p=(char *)malloc((unsigned)(strlen(q)+2));
1261                         if(p==0) {
1262                                 msg("Can't allocate memory for name");
1263                                 exit(EX_SYSTEM);
1264                         }
1265                         (void) strcpy(p,q);
1266                         ar_file=p;
1267                 }
1268                         break;
1269
1270                 case '!':
1271 #ifdef __MSDOS__
1272                         spawnl(P_WAIT,getenv("COMSPEC"),"-",0);
1273 #else
1274                                 /* JF this needs work! */
1275                         switch(fork()) {
1276                         case -1:
1277                                 msg_perror("can't fork!");
1278                                 break;
1279                         case 0:
1280                                 p=getenv("SHELL");
1281                                 if(p==0) p="/bin/sh";
1282                                 execlp(p,"-sh","-i",0);
1283                                 msg_perror("can't exec a shell %s",p);
1284                                 _exit(55);
1285                         default:
1286                                 wait(0);
1287                                 break;
1288                         }
1289 #endif
1290                         break;
1291                 }
1292         }
1293
1294         if(type==2 || f_verify)
1295                 archive=rmtopen(ar_file,O_RDWR|O_CREAT,0666);
1296         else if(type==1)
1297                 archive=rmtopen(ar_file,O_RDONLY,0666);
1298         else if(type==0)
1299                 archive=rmtcreat(ar_file,0666);
1300         else
1301                 archive= -1;
1302
1303         if(archive<0) {
1304                 msg_perror("can't open %s",ar_file);
1305                 goto tryagain;
1306         }
1307 #ifdef __MSDOS__
1308         setmode(archive,O_BINARY);
1309 #endif
1310         return 0;
1311 }
1312
1313 /* this is a useless function that takes a buffer returned by wantbytes
1314    and does nothing with it.  If the function called by wantbytes returns
1315    an error indicator (non-zero), this function is called for the rest of
1316    the file.
1317  */
1318 int
1319 no_op(size,data)
1320 int size;
1321 char *data;
1322 {
1323         return 0;
1324 }
1325
1326 /* Some other routine wants SIZE bytes in the archive.  For each chunk of
1327    the archive, call FUNC with the size of the chunk, and the address of
1328    the chunk it can work with.
1329  */
1330 int
1331 wantbytes(size,func)
1332 long size;
1333 int (*func)();
1334 {
1335         char *data;
1336         long    data_size;
1337
1338         while(size) {
1339                 data = findrec()->charptr;
1340                 if (data == NULL) {     /* Check it... */
1341                         msg("Unexpected EOF on archive file");
1342                         return -1;
1343                 }
1344                 data_size = endofrecs()->charptr - data;
1345                 if(data_size>size)
1346                         data_size=size;
1347                 if((*func)(data_size,data))
1348                         func=no_op;
1349                 userec((union record *)(data + data_size - 1));
1350                 size-=data_size;
1351         }
1352         return 0;
1353 }