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