1 /* @(#)buffer.c 1.199 20/07/08 Copyright 1985, 1995, 2001-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)buffer.c 1.199 20/07/08 Copyright 1985, 1995, 2001-2020 J. Schilling";
6 #endif
7 /*
8 * Buffer handling routines
9 *
10 * Copyright (c) 1985, 1995, 2001-2020 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/mconfig.h>
27
28 /*
29 * XXX Until we find a better way, the next definitions must be in sync
30 * XXX with the definitions in librmt/remote.c
31 */
32 #if !defined(HAVE_FORK) || !defined(HAVE_SOCKETPAIR) || !defined(HAVE_DUP2)
33 #undef USE_RCMD_RSH
34 #endif
35 #if !defined(HAVE_GETSERVBYNAME)
36 #undef USE_REMOTE /* Cannot get rcmd() port # */
37 #endif
38 #if (!defined(HAVE_NETDB_H) || !defined(HAVE_RCMD)) && !defined(USE_RCMD_RSH)
39 #undef USE_REMOTE /* There is no rcmd() */
40 #endif
41
42 #include <schily/stdio.h>
43 #include <schily/stdlib.h>
44 #include <schily/unistd.h>
45 #include <schily/fcntl.h>
46 #include <schily/ioctl.h>
47 #include <schily/varargs.h>
48 #include "star.h"
49 #include "props.h"
50 #include <schily/errno.h>
51 #include <schily/standard.h>
52 #include "fifo.h"
53 #include <schily/string.h>
54 #include <schily/wait.h>
55 #include <schily/mtio.h>
56 #include <schily/librmt.h>
57 #define GT_COMERR /* #define comerr gtcomerr */
58 #define GT_ERROR /* #define error gterror */
59 #include <schily/schily.h>
60 #include "starsubs.h"
61
62 #include <schily/io.h> /* for setmode() prototype */
63 #include <schily/libport.h> /* getpagesize() */
64
65 #include <schily/nlsdefs.h>
66
67 /*
68 * Warning: we need the siginfo_t feature that has been introduced in 1989
69 * with SVr4 and in 1995 with SUSv1. You need a platform that is maintained
70 * since 1995.
71 *
72 * defined(HAVE_SIGPROCMASK) && defined(SA_RESTART) identifies a system that
73 * supports sigaction().
74 *
75 * defined(HAVE_SIGINFO_T) && defined(HAVE_WAITID) is needed in order to get
76 * useful values in siginfo_t. Note that Mac OS X before approx. 2018 e.g.
77 * neither fills in sip->si_pid nor sip->si_code, making siginfo_t useless.
78 */
79 #if defined(HAVE_SIGPROCMASK) && defined(SA_RESTART) && \
80 defined(SA_SIGINFO) && \
81 defined(HAVE_SIGINFO_T) && defined(HAVE_WAITID)
82 #define USE_SIGCLD
83 #endif
84
85 long bigcnt = 0;
86 long bigsize = 0; /* Tape block size (may shrink < bigbsize) */
87 long bigbsize = 0; /* Big buffer size */
88 long bufsize = 0; /* Available buffer size */
89 char *bigbase = NULL;
90 char *bigbuf = NULL;
91 char *bigptr = NULL;
92 char *eofptr = NULL;
93 Llong curblockno;
94
95 m_stats bstat;
96 m_stats *stats = &bstat;
97 int pid;
98
99 #ifdef timerclear
100 LOCAL struct timespec starttime;
101 LOCAL struct timespec stoptime;
102 #endif
103
104 LOCAL BOOL isremote = FALSE;
105 LOCAL int remfd = -1;
106 LOCAL char *remfn;
107
108 #ifdef __DJGPP__
109 LOCAL FILE *compress_tarf_save; /* Old value of tarf */
110 LOCAL FILE *compress_tmpf = NULL; /* FILE * from tmpfile() */
111 #endif
112
113 extern FILE *tarf;
114 extern FILE *tty;
115 extern FILE *vpr;
116 extern char *tarfiles[];
117 extern int ntarfiles;
118 extern int tarfindex;
119 extern BOOL force_noremote;
120 extern char *rsh;
121 extern char *rmt;
122 LOCAL int lastremote = -1;
123 extern BOOL multivol;
124 extern char *newvol_script;
125 extern BOOL use_fifo;
126 extern int swapflg;
127 extern int cmptype;
128 extern BOOL debug;
129 extern BOOL print_artype;
130 extern BOOL silent;
131 extern BOOL showtime;
132 extern BOOL no_stats;
133 extern BOOL cpio_stats;
134 extern BOOL do_fifostats;
135 extern BOOL cflag;
136 extern BOOL uflag;
137 extern BOOL rflag;
138 extern BOOL copyflag;
139 extern BOOL Zflag;
140 extern BOOL zflag;
141 extern BOOL bzflag;
142 extern BOOL lzoflag;
143 extern BOOL p7zflag;
144 extern BOOL xzflag;
145 extern BOOL lzipflag;
146 extern BOOL zstdflag;
147 extern BOOL lzmaflag;
148 extern BOOL freezeflag;
149 extern char *compress_prg;
150 extern BOOL multblk;
151 extern BOOL partial;
152 extern BOOL wready;
153 extern BOOL nullout;
154 extern Ullong tsize;
155 extern BOOL nowarn;
156
157 extern int intr;
158
159 extern GINFO *gip;
160
161
162 EXPORT void opt_remote __PR((void));
163 EXPORT BOOL openremote __PR((void));
164 EXPORT void opentape __PR((void));
165 EXPORT void closetape __PR((void));
166 EXPORT void changetape __PR((BOOL donext));
167 EXPORT void runnewvolscript __PR((int volno, int nindex));
168 EXPORT void nextitape __PR((void));
169 EXPORT void nextotape __PR((void));
170 EXPORT long startvol __PR((char *buf, long amount));
171 EXPORT void newvolhdr __PR((char *buf, long amount, BOOL do_fifo));
172 #ifdef FIFO
173 LOCAL void fbit_ffss __PR((bitstr_t *name, long startb, long stopb,
174 long *value));
175 LOCAL BOOL fifo_hpos __PR((char *buf, off_t *posp));
176 #endif
177 EXPORT void initbuf __PR((int nblocks));
178 EXPORT void markeof __PR((void));
179 EXPORT void syncbuf __PR((void));
180 EXPORT long peekblock __PR((char *buf, long amount));
181 EXPORT long readblock __PR((char *buf, long amount));
182 LOCAL long readtblock __PR((char *buf, long amount));
183 LOCAL void readbuf __PR((void));
184 EXPORT ssize_t readtape __PR((char *buf, size_t amount));
185 EXPORT void filltcb __PR((TCB *ptb));
186 EXPORT void movetcb __PR((TCB *from_ptb, TCB *to_ptb));
187 EXPORT void *get_block __PR((long amount));
188 EXPORT void put_block __PR((long amount));
189 EXPORT char *writeblock __PR((char *buf));
190 EXPORT ssize_t writetape __PR((char *buf, size_t amount));
191 LOCAL void writebuf __PR((long amount));
192 LOCAL void flushbuf __PR((void));
193 EXPORT void writeempty __PR((void));
194 EXPORT void weof __PR((void));
195 EXPORT void buf_sync __PR((long size));
196 EXPORT void buf_drain __PR((void));
197 EXPORT long buf_wait __PR((long amount));
198 EXPORT void buf_wake __PR((long amount));
199 EXPORT long buf_rwait __PR((long amount));
200 EXPORT void buf_rwake __PR((long amount));
201 EXPORT void buf_resume __PR((void));
202 EXPORT void backtape __PR((void));
203 EXPORT int mtioctl __PR((int cmd, int count));
204 EXPORT off_t mtseek __PR((off_t offset, int whence));
205 EXPORT void marktcb __PR((char *addr));
206 EXPORT Llong tblocks __PR((void));
207 EXPORT void prstats __PR((void));
208 EXPORT BOOL checkerrs __PR((void));
209 EXPORT void exprstats __PR((int ret));
210 EXPORT void excomerrno __PR((int err, char *fmt, ...)) __printflike__(2, 3);
211 EXPORT void excomerr __PR((char *fmt, ...)) __printflike__(1, 2);
212 EXPORT void die __PR((int err));
213 #ifdef USE_SIGCLD
214 LOCAL void cldhandler __PR((int sig, siginfo_t *sip, void *context));
215 LOCAL void handlecld __PR((void));
216 #endif
217 LOCAL void compressopen __PR((void));
218 LOCAL void compressclose __PR((void));
219
220 EXPORT void
opt_remote()221 opt_remote()
222 {
223 #ifdef USE_REMOTE
224 printf(" remote");
225 #endif
226 }
227
228 /*
229 * Check whether the current tarfiles[tarfindex] refers to a remote archive
230 * location and open a remote connection if needed.
231 * Called from star.c main() and from changetape().
232 */
233 EXPORT BOOL
openremote()234 openremote()
235 {
236 char host[128];
237 char lasthost[128];
238
239 if ((!nullout || (uflag || rflag)) && !force_noremote &&
240 (remfn = rmtfilename(tarfiles[tarfindex])) != NULL) {
241
242 #ifdef USE_REMOTE
243 isremote = TRUE;
244 rmtdebug(debug);
245 if (rsh)
246 rmtrsh(rsh);
247 #ifdef USE_SSH
248 else
249 rmtrsh("ssh");
250 #endif
251 if (rmt)
252 rmtrmt(rmt);
253 rmthostname(host, sizeof (host), tarfiles[tarfindex]);
254 if (debug)
255 errmsgno(EX_BAD, "Remote: %s Host: %s file: %s\n",
256 tarfiles[tarfindex], host, remfn);
257
258 if (lastremote >= 0) {
259 rmthostname(lasthost, sizeof (lasthost),
260 tarfiles[lastremote]);
261 if (!streql(host, lasthost)) {
262 close(remfd);
263 remfd = -1;
264 lastremote = -1;
265 }
266 }
267 if (remfd < 0 && (remfd = rmtgetconn(host, bigsize, 0)) < 0)
268 comerrno(EX_BAD, "Cannot get connection to '%s'.\n",
269 /* errno not valid !! */ host);
270 lastremote = tarfindex;
271 #else
272 comerrno(EX_BAD, "Remote tape support not present.\n");
273 #endif
274 } else {
275 isremote = FALSE;
276 }
277 return (isremote);
278 }
279
280 /*
281 * Open the current tarfiles[tarfindex] (a remote connection must be open)
282 * Called from star.c main() and from changetape().
283 */
284 EXPORT void
opentape()285 opentape()
286 {
287 int n = 0;
288 extern dev_t tape_dev;
289 extern ino_t tape_ino;
290 extern BOOL tape_isreg;
291 extern Llong mtskip;
292
293 if (copyflag || (nullout && !(uflag || rflag))) {
294 tarfiles[tarfindex] = "null";
295 tarf = (FILE *)NULL;
296 } else if (streql(tarfiles[tarfindex], "-")) {
297 if (cflag) {
298 tarf = stdout;
299 } else {
300 tarf = stdin;
301 multblk = TRUE;
302 }
303 setbuf(tarf, (char *)NULL);
304 setmode(fileno(tarf), O_BINARY);
305 } else if (isremote) {
306 #ifdef USE_REMOTE
307 /*
308 * isremote will always be FALSE if USE_REMOTE is not defined.
309 * NOTE any open flag bejond O_RDWR is not portable across
310 * different platforms. The remote tape library will check
311 * whether the current /etc/rmt server supports symbolic
312 * open flags. If there is no symbolic support in the
313 * remote server, our rmt client code will mask off all
314 * non portable bits. The remote rmt server defaults to
315 * O_BINARY as the client (we) may not know about O_BINARY.
316 * XXX Should we add an option that allows to specify O_TRUNC?
317 */
318 while (rmtopen(remfd, remfn, (cflag ? O_RDWR|O_CREAT:O_RDONLY)|O_BINARY) < 0) {
319 if (!wready || n++ > 12 ||
320 (geterrno() != EIO && geterrno() != EBUSY)) {
321 comerr("Cannot open remote '%s'.\n",
322 tarfiles[tarfindex]);
323 } else {
324 sleep(10);
325 }
326 }
327 #endif
328 } else {
329 FINFO finfo;
330 extern BOOL follow;
331 extern BOOL fcompat;
332 extern int ptype;
333
334 if (fcompat && (cflag && !(uflag || rflag))) {
335 /*
336 * The old syntax has a high risk of corrupting
337 * files if the user disorders the args.
338 * For this reason, we do not allow to overwrite
339 * a plain file in compat mode.
340 * XXX What if we implement 'r' & 'u' ???
341 */
342 follow++;
343 n = _getinfo(tarfiles[tarfindex], &finfo);
344 follow--;
345 if (n >= 0 && is_file(&finfo) && finfo.f_size > (off_t)0) {
346 if (ptype != P_SUNTAR) {
347 comerrno(EX_BAD,
348 "Will not overwrite non empty plain files in compat mode.\n");
349 } else {
350 errmsgno(EX_BAD,
351 "WARNING: Overwriting archive file '%s'.\n",
352 tarfiles[tarfindex]);
353 }
354 }
355 }
356
357 n = 0;
358 /*
359 * XXX Should we add an option that allows to specify O_TRUNC?
360 */
361 while ((tarf = lfilemopen(tarfiles[tarfindex],
362 cflag?"rwcub":"rub",
363 S_IRWALL)) ==
364 (FILE *)NULL) {
365 if (!wready || n++ > 12 ||
366 (geterrno() != EIO && geterrno() != EBUSY)) {
367 comerr("Cannot open '%s'.\n",
368 tarfiles[tarfindex]);
369 } else {
370 sleep(10);
371 }
372 }
373 }
374 if (tarf != (FILE *)NULL && isatty(fdown(tarf)))
375 comerrno(EX_BAD, "Archive cannot be a tty.\n");
376 if (!isremote && (!nullout || (uflag || rflag)) &&
377 tarf != (FILE *)NULL) {
378 file_raise(tarf, FALSE);
379 checkarch(tarf);
380 }
381 vpr = tarf == stdout ? stderr : stdout; /* f=stdout redirect listing */
382 if (samefile(tarf, vpr)) { /* Catch -f /dev/stdout case */
383 if (tarf != stdin) /* Don't redirect for -tv < */
384 vpr = stderr;
385 }
386
387 /*
388 * If the archive is a plain file and thus seekable
389 * do automatic compression detection.
390 */
391 if (stats->volno == 1 &&
392 tape_isreg && !cflag && (!Zflag && !zflag && !bzflag && !lzoflag &&
393 !p7zflag && !xzflag && !lzipflag && !zstdflag && !lzmaflag &&
394 !freezeflag &&
395 !compress_prg)) {
396 long htype;
397 TCB *ptb;
398
399 readtblock(bigbuf, TBLOCK);
400 ptb = (TCB *)bigbuf;
401 htype = get_hdrtype(ptb, FALSE);
402
403 if (htype == H_UNDEF) {
404 switch (cmptype = get_compression(ptb)) {
405
406 case C_NONE:
407 break;
408 case C_PACK:
409 case C_GZIP:
410 case C_LZW:
411 case C_FREEZE:
412 case C_LZH:
413 case C_PKZIP:
414 if (!silent && !print_artype) errmsgno(EX_BAD,
415 "WARNING: Archive is '%s' compressed, trying to use the -z option.\n",
416 get_cmpname(cmptype));
417 zflag = TRUE;
418 break;
419 case C_BZIP2:
420 if (!silent && !print_artype) errmsgno(EX_BAD,
421 "WARNING: Archive is 'bzip2' compressed, trying to use the -bz option.\n");
422 bzflag = TRUE;
423 break;
424 case C_LZO:
425 if (!silent && !print_artype) errmsgno(EX_BAD,
426 "WARNING: Archive is 'lzop' compressed, trying to use the -lzo option.\n");
427 lzoflag = TRUE;
428 break;
429 case C_7Z:
430 if (!silent && !print_artype) errmsgno(EX_BAD,
431 "WARNING: Archive is '7z' compressed, trying to use the -7z option.\n");
432 p7zflag = TRUE;
433 break;
434 case C_XZ:
435 if (!silent && !print_artype) errmsgno(EX_BAD,
436 "WARNING: Archive is 'xz' compressed, trying to use the -xz option.\n");
437 xzflag = TRUE;
438 break;
439 case C_LZIP:
440 if (!silent && !print_artype) errmsgno(EX_BAD,
441 "WARNING: Archive is 'lzip' compressed, trying to use the -lzip option.\n");
442 lzipflag = TRUE;
443 break;
444 case C_ZSTD:
445 if (!silent && !print_artype) errmsgno(EX_BAD,
446 "WARNING: Archive is 'zstd' compressed, trying to use the -zstd option.\n");
447 zstdflag = TRUE;
448 break;
449 case C_LZMA:
450 if (!silent && !print_artype) errmsgno(EX_BAD,
451 "WARNING: Archive is 'lzma' compressed, trying to use the -lzma option.\n");
452 lzmaflag = TRUE;
453 break;
454 case C_FREEZE2:
455 if (!silent && !print_artype) errmsgno(EX_BAD,
456 "WARNING: Archive is 'freeze2' compressed, trying to use the -freeze option.\n");
457 freezeflag = TRUE;
458 break;
459 default:
460 if (!silent) errmsgno(EX_BAD,
461 "WARNING: Unknown compression type %d.\n", cmptype);
462 break;
463 }
464 }
465 mtseek((off_t)0, SEEK_SET);
466 }
467 if (Zflag || zflag || bzflag || lzoflag ||
468 p7zflag || xzflag || lzipflag || zstdflag || lzmaflag || freezeflag ||
469 compress_prg) {
470 extern long iskip;
471
472 iskip = 0; /* We cannot skip in compressed archives. */
473 mtskip = 0; /* We cannot skip in compressed archives. */
474
475 if (isremote)
476 comerrno(EX_BAD, "Cannot compress remote archives (yet).\n");
477 /*
478 * If both values are zero, this is a device and thus may be a tape.
479 */
480 if (tape_dev || tape_ino)
481 compressopen();
482 else
483 comerrno(EX_BAD, "Can only compress files.\n");
484
485 } else if (stats->volno == 1 && mtskip) {
486 if (tape_isreg) {
487 if (mtseek((off_t)mtskip * TBLOCK, SEEK_SET) == -1)
488 excomerr("Cannot seek input for mtskip=.\n");
489 mtskip = 0;
490 } else if (mtioctl(MTNOP, 0) >= 0) {
491 extern int nblocks;
492 int count = mtskip / nblocks;
493
494 if (mtioctl(MTFSR, count) == -1)
495 excomerr("Cannot position tape for mtskip=.\n");
496 }
497 }
498
499 #ifdef timerclear
500 if (showtime && starttime.tv_sec == 0 && starttime.tv_nsec == 0 &&
501 getnstimeofday(&starttime) < 0)
502 comerr("Cannot get starttime\n");
503 #endif
504 }
505
506 /*
507 * Close the current open tarf/remfd (a remote connection must be open)
508 * Called from star.c main() and from changetape().
509 */
510 EXPORT void
closetape()511 closetape()
512 {
513 if (isremote) {
514 #ifdef USE_REMOTE
515 /*
516 * isremote will always be FALSE if USE_REMOTE is not defined.
517 */
518 if (rmtclose(remfd) < 0)
519 errmsg("Remote close failed.\n");
520 #endif
521 } else {
522 compressclose();
523 if (tarf)
524 fclose(tarf);
525 }
526 }
527
528 /*
529 * Low level medium change routine.
530 * Called from nextitape()/nextotape() and fifo_owait().
531 */
532 EXPORT void
changetape(donext)533 changetape(donext)
534 BOOL donext;
535 {
536 char ans[3];
537 int nextindex;
538
539 if (donext) {
540 pid_t opid = pid;
541
542 if (pid == 0)
543 pid = 1; /* Make sure the statistics are printed */
544 prstats();
545 pid = opid;
546 if (!cflag &&
547 (gip->tapesize > 0) &&
548 (stats->blocks*stats->nblocks + stats->parts/TBLOCK) !=
549 gip->tapesize) {
550 errmsgno(EX_BAD,
551 "WARNING: Archive size error.\n");
552 errmsgno(EX_BAD,
553 "Expected size %llu blocks, actual size %lld blocks.\n",
554 gip->tapesize,
555 stats->blocks*stats->nblocks + stats->parts/TBLOCK);
556 }
557 stats->Tblocks += stats->blocks;
558 stats->Tparts += stats->parts;
559 }
560 stats->blocks = 0L;
561 stats->parts = 0L;
562 closetape();
563 /*
564 * XXX Was passiert, wenn wir das 2. Mal bei einem Band vorbeikommen?
565 * XXX Zur Zeit wird gnadenlos ueberschrieben.
566 */
567 if (donext) {
568 stats->volno++;
569 gip->volno = stats->volno;
570 nextindex = tarfindex + 1;
571 if (nextindex >= ntarfiles)
572 nextindex = 0;
573 } else {
574 nextindex = tarfindex;
575 }
576 /*
577 * XXX We need to add something like the -l & -o option from
578 * XXX ufsdump.
579 */
580 if (newvol_script) {
581 fflush(vpr);
582 if (!donext) {
583 errmsgno(EX_BAD,
584 "Mounted volume on '%s' did not match archive",
585 tarfiles[nextindex]);
586 comerrno(EX_BAD, "Aborting.\n");
587 }
588 runnewvolscript(stats->volno, nextindex);
589 } else {
590 int len;
591
592 errmsgno(EX_BAD, "Mount volume #%d on '%s' and hit <RETURN>",
593 stats->volno, tarfiles[nextindex]);
594 ans[0] = '\n';
595 len = fgetstr(tty, ans, sizeof (ans));
596 if (len > 0 && ans[len-1] != '\n') {
597 while (getc(tty) != '\n') {
598 if (feof(tty) || ferror(tty))
599 break;
600 }
601 }
602
603 if (ttyerr(tty))
604 exit(1);
605 }
606 tarfindex = nextindex;
607 openremote();
608 opentape();
609 }
610
611 EXPORT void
runnewvolscript(volno,nindex)612 runnewvolscript(volno, nindex)
613 int volno;
614 int nindex;
615 {
616 char scrbuf[PATH_MAX];
617
618 if (!newvol_script)
619 return;
620
621 if (nindex >= ntarfiles)
622 nindex = 0;
623 /*
624 * The script is called with the next volume # and volume name
625 * as argument.
626 */
627 js_snprintf(scrbuf, sizeof (scrbuf), "%s '%d' '%s'",
628 newvol_script,
629 volno, tarfiles[nindex]);
630 system(scrbuf);
631 }
632
633 /*
634 * High level input medium change routine.
635 * Currently called from buf_rwait().
636 * Volume verification in the fifo case is done in the fifo process.
637 * For this reason, we only verify the new volume in the non fifo case.
638 */
639 EXPORT void
nextitape()640 nextitape()
641 {
642 #ifdef FIFO
643 if (use_fifo) {
644 fifo_chitape();
645 } else
646 #endif
647 {
648 int skip;
649
650 changetape(TRUE);
651 readbuf();
652 while (bigcnt > 0 && !verifyvol(bigptr, bigcnt, stats->volno, &skip)) {
653 changetape(FALSE);
654 readbuf();
655 }
656 if (skip > 0)
657 buf_rwake(skip*TBLOCK);
658 }
659 if (intr)
660 exit(2);
661 }
662
663 /*
664 * High level output medium change routine.
665 * Currently called from write_tcb() and only used if
666 * -multivol has not been specified. So this is always called
667 * from the tar process and never from the fifo background process.
668 */
669 EXPORT void
nextotape()670 nextotape()
671 {
672 weof();
673 #ifdef FIFO
674 if (use_fifo) {
675 fifo_chotape();
676 } else
677 #endif
678 changetape(TRUE);
679 if (intr)
680 exit(2);
681 }
682
683 /*
684 * Called from writetape()
685 */
686 EXPORT long
startvol(buf,amount)687 startvol(buf, amount)
688 char *buf; /* The original buffer address */
689 long amount; /* The related requested transfer count */
690 {
691 char *obuf = bigbuf;
692 char *optr = bigptr;
693 long ocnt = bigcnt;
694 long xcnt = 0;
695 BOOL ofifo = use_fifo;
696 static BOOL active = FALSE; /* If TRUE: We are already in a media change */
697 extern m_head *mp;
698
699 if (amount <= 0)
700 return (amount);
701 if (active)
702 comerrno(EX_BAD, "Panic: recursive media change requested!\n");
703 if (amount > bigsize) {
704 comerrno(EX_BAD,
705 "Panic: trying to write more than bs (%ld > %ld)!\n",
706 amount, bigsize);
707 }
708 #ifdef FIFO
709 if (use_fifo) {
710 mp->chreel = TRUE;
711
712 /*
713 * Make sure the put side of the FIFO is waiting either on
714 * mp->iblocked (because the FIFO is full) or on mp->reelwait
715 * before temporary disabling the FIFO during media change.
716 */
717 while ((mp->eflags & FIFO_EXIT) == 0 &&
718 mp->iblocked == FALSE && mp->reelwait == FALSE) {
719 usleep(100000);
720 }
721 }
722 #endif
723 active = TRUE;
724
725 /*
726 * Save the current write data in "bigbase".
727 */
728 movebytes(buf, bigbase, amount);
729
730 use_fifo = FALSE;
731 bigbuf = &bigbase[bigsize];
732 bigptr = bigbuf;
733 bigcnt = 0;
734
735 newvolhdr(buf, amount, ofifo);
736
737 if (bigcnt > 0) { /* We did create a volhdr */
738 xcnt = bigsize - bigcnt;
739 if (amount < xcnt)
740 xcnt = amount;
741 if (xcnt > 0) {
742 /*
743 * Move data from original buffer past the volhdr to
744 * fill up a complete block size.
745 */
746 movebytes(bigbase, bigptr, xcnt);
747 bigcnt += xcnt;
748 }
749 writetape(bigbuf, bigcnt);
750 }
751
752 movebytes(bigbase, buf, amount);
753 bigbuf = obuf;
754 bigptr = optr;
755 bigcnt = ocnt;
756 use_fifo = ofifo;
757 active = FALSE;
758 #ifdef FIFO
759 if (use_fifo) {
760 mp->chreel = FALSE;
761 fifo_reelwake();
762 }
763 #endif
764 return (xcnt); /* Return the amount taken from orig. buffer */
765 }
766
767 EXPORT void
newvolhdr(buf,amount,do_fifo)768 newvolhdr(buf, amount, do_fifo)
769 char *buf; /* The original buffer address */
770 long amount; /* The related requested transfer count */
771 BOOL do_fifo;
772 {
773 extern m_head *mp;
774 off_t scur_size;
775 off_t scur_off;
776 off_t sold_size;
777 off_t sold_off;
778 #ifdef FIFO
779 off_t new_size = 0;
780 BOOL nsize_valid = FALSE;
781 #endif
782
783 fifo_lock_critical();
784 scur_size = stats->cur_size;
785 scur_off = stats->cur_off;
786 sold_size = stats->old_size;
787 sold_off = stats->old_off;
788 #ifdef FIFO
789 /*
790 * If needed, find next header position in FIFO bitmap.
791 */
792 if (do_fifo && buf != NULL) /* buf == NULL -> called from put_tcb */
793 nsize_valid = fifo_hpos(buf, &new_size);
794 #endif
795 fifo_unlock_critical();
796
797 xbbackup(); /* Save current xheader data */
798
799 gip->blockoff = stats->Tblocks * stats->nblocks +
800 stats->Tparts / TBLOCK;
801
802 put_release(); /* Pax 'g' vendor unique */
803 put_archtype(); /* Pax 'g' vendor unique */
804
805 #ifdef FIFO
806 if (do_fifo && buf != NULL) { /* buf == NULL -> called from put_tcb */
807 off_t new_off = 0;
808
809 if (!nsize_valid) {
810 new_size = scur_size;
811 new_off = scur_off - FIFO_AMOUNT(mp);
812 }
813 /*
814 * Write a 'g'-header and either a 'V'-header
815 * or a 'M'-header.
816 */
817 put_volhdr(gip->label, new_size <= 0);
818 if (new_size > 0)
819 put_multhdr(new_size, new_off);
820 } else
821 #endif
822 /*
823 * Write a 'g'-header and either a 'V'-header
824 * or a 'M'-header.
825 */
826 if (!do_fifo && (sold_off < sold_size)) {
827 put_volhdr(gip->label, FALSE);
828 put_multhdr(sold_size, sold_off);
829 } else {
830 put_volhdr(gip->label, TRUE);
831 }
832
833 xbrestore(); /* Restore current xheader data */
834 stats->cur_size = scur_size;
835 stats->cur_off = scur_off;
836 stats->old_size = sold_size;
837 stats->old_off = sold_off;
838 }
839
840 #ifdef FIFO
841 /*
842 * Make the macro a function...
843 */
844 LOCAL void
fbit_ffss(name,startb,stopb,value)845 fbit_ffss(name, startb, stopb, value)
846 register bitstr_t *name;
847 register long startb;
848 register long stopb;
849 register long *value;
850 {
851 bit_lffss(name, startb, stopb, value);
852 }
853
854 /*
855 * Find next header position in FIFO bitmap.
856 */
857 LOCAL BOOL
fifo_hpos(buf,posp)858 fifo_hpos(buf, posp)
859 char *buf;
860 off_t *posp;
861 {
862 long startb;
863 long stopb;
864 long endb;
865 long bitpos = -1;
866 extern m_head *mp;
867
868 startb = (buf - mp->base) / TBLOCK;
869 stopb = -1 + (mp->putptr - mp->base) / TBLOCK;
870 endb = -1 + (mp->size) / TBLOCK;
871
872 if (buf < mp->base) {
873 stopb = mp->bmlast;
874 startb = stopb + 1 - (mp->base - buf) / TBLOCK;
875
876 fbit_ffss(mp->bmap, startb, stopb, &bitpos);
877 if (bitpos >= 0) {
878 *posp = (bitpos - startb) * TBLOCK;
879 return (TRUE);
880 }
881 startb = 0;
882 stopb = -1 + (mp->putptr - mp->base) / TBLOCK;
883 }
884 if (stopb < startb)
885 fbit_ffss(mp->bmap, startb, endb, &bitpos);
886 else
887 fbit_ffss(mp->bmap, startb, stopb, &bitpos);
888 if (bitpos >= 0) {
889 *posp = (bitpos - startb) * TBLOCK;
890 return (TRUE);
891 }
892 if (stopb < startb) {
893 fbit_ffss(mp->bmap, 0, stopb, &bitpos);
894 if (bitpos >= 0) {
895 /*
896 * endb+1 - startb == # of bits in rear part
897 */
898 *posp = (bitpos + endb+1 - startb) * TBLOCK;
899 return (TRUE);
900 }
901 }
902 return (FALSE);
903 }
904 #endif
905
906 /*
907 * Init buffer or fifo.
908 * called from star.c main().
909 */
910 EXPORT void
initbuf(nblocks)911 initbuf(nblocks)
912 int nblocks;
913 {
914 BOOL cvolhdr = cflag && (multivol || tsize > 0);
915
916 pid = getpid();
917 bufsize = bigsize = nblocks * TBLOCK;
918 #ifdef FIFO
919 if (use_fifo) {
920 initfifo();
921 }
922 #endif
923 /*
924 * As bigbuf is allocated here only in case that we have no FIFO or we
925 * are in create mode, there are no aliasing problems with bigbuf and
926 * the shared memory in the FIFO while trying to detect the archive
927 * format and byte swapping in read/extract modes.
928 * Note that -r and -u currently disable the FIFO.
929 * In case that we enable the FIFO for -r and -u, we need to add
930 * another exception here in order to have space to remember the last
931 * block of significant data that needs to be modified to append.
932 */
933 if (!use_fifo || cvolhdr || rflag || uflag) {
934 int pagesize = getpagesize();
935
936 /*
937 * llitos() overshoots by one space (' ') in cpio mode,
938 * add 10 bytes.
939 * If we create multi volume archives that need volume
940 * headers, we need additional space to prepare the
941 * first write to a new medium after a medium change.
942 * "bufsize" may be modified by initfifo() in the FIFO case,
943 * so we use "bigsize" for the extra multivol buffer to
944 * avoid allocating an unneeded huge amount of data here.
945 * In "replace" or "update" mode, we also may need to
946 * save/restore * the buffer for the tape record when doing
947 * EOF detection. As this space is needed at a different
948 * time, it may be shared with the extra multivol buffer.
949 */
950 if (cvolhdr || rflag || uflag)
951 bigsize *= 2;
952
953 /*
954 * roundup(x, y), x needs to be unsigned or x+y non-genative.
955 */
956 #undef roundup
957 #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
958
959 bigptr = bigbuf = ___malloc((size_t)bigsize+10+pagesize,
960 "buffer");
961 bigptr = bigbuf = (char *)roundup((UIntptr_t)bigptr, pagesize);
962 fillbytes(bigbuf, bigsize, '\0');
963 fillbytes(&bigbuf[bigsize], 10, 'U');
964
965 if (cvolhdr || rflag || uflag) {
966 bigsize /= 2;
967 bigbase = bigbuf;
968 bigbuf = bigptr = &bigbase[bigsize];
969 }
970 }
971 stats->nblocks = nblocks;
972 stats->blocksize = bigbsize = bigsize;
973 stats->volno = 1;
974 stats->swapflg = -1;
975 }
976
977 /*
978 * Mark the EOF position (the position of the first logical TAR EOF block)
979 * We need this position for later repositioning when appending to an archive.
980 */
981 EXPORT void
markeof()982 markeof()
983 {
984 #ifdef FIFO
985 if (use_fifo) {
986 /*
987 * Remember current FIFO status.
988 */
989 /* EMPTY */
990 }
991 #endif
992 eofptr = bigptr - TBLOCK;
993
994 if (debug) {
995 error("Blocks: %lld\n", tblocks());
996 error(
997 "bigptr - bigbuff: %lld bigbuf: %p bigptr: %p eofptr: %p lastsize: %ld\n",
998 (Llong)(bigptr - bigbuf),
999 (void *)bigbuf, (void *)bigptr, (void *)eofptr,
1000 stats->lastsize);
1001 }
1002 }
1003
1004 EXPORT void
marktcb(addr)1005 marktcb(addr)
1006 char *addr;
1007 {
1008 #ifdef FIFO
1009 extern m_head *mp;
1010 register long bit;
1011 #endif
1012 if (!multivol || !use_fifo)
1013 return;
1014 /*
1015 * As long as we don't start supporting -multivol with CPIO archives,
1016 * we will never come here when writing unblocked archives.
1017 */
1018 #ifdef FIFO
1019 bit = addr - mp->base;
1020 if (bit % TBLOCK) /* Remove this paranoia test in future. */
1021 errmsgno(EX_BAD, "TCB offset not mudulo 512.\n");
1022 bit /= TBLOCK;
1023 if (bit_test(mp->bmap, bit)) /* Remove this paranoia test in future. */
1024 errmsgno(EX_BAD, "Bit %ld is already set.\n", bit);
1025 bit_set(mp->bmap, bit);
1026 #endif
1027 }
1028
1029 /*
1030 * Prepare the buffer/fifo for reversing the direction from reading to writing.
1031 * Called from star.c main() after skipall() is ready.
1032 */
1033 EXPORT void
syncbuf()1034 syncbuf()
1035 {
1036 #ifdef FIFO
1037 if (use_fifo) {
1038 /*
1039 * Switch FIFO direction.
1040 */
1041 excomerr("Cannot update tape with FIFO.\n");
1042 }
1043 #endif
1044 if (eofptr) {
1045 /*
1046 * Only back up to "eofptr" if markeof() has been called,
1047 * this is not the case when we did ancounter a hard EOF
1048 * at the beginning of the archive (empty file),
1049 */
1050 bigptr = eofptr;
1051 bigcnt = eofptr - bigbuf;
1052 }
1053 }
1054
1055 /*
1056 * Peek into buffer for amount bytes.
1057 * Return at most TBLOCK (512) bytes.
1058 *
1059 * Called from get_tcb() for checking the archive format of the first
1060 * tape block.
1061 */
1062 EXPORT long
peekblock(buf,amount)1063 peekblock(buf, amount)
1064 register char *buf;
1065 register long amount;
1066 {
1067 register long n;
1068
1069 if ((n = buf_rwait(amount)) == 0)
1070 return (EOF);
1071 if (n > amount)
1072 n = amount;
1073 if (n >= TBLOCK) {
1074 n = TBLOCK;
1075 movetcb((TCB *)bigptr, (TCB *)buf);
1076 } else {
1077 movebytes(bigptr, buf, n);
1078 }
1079 return (n);
1080 }
1081
1082 /*
1083 * Read amount bytes.
1084 * Return at most TBLOCK (512) bytes.
1085 * Do CPIO buffer wrap handling here.
1086 *
1087 * Called from get_tcb() and from the sparse handling functions in hole.c
1088 */
1089 EXPORT long
readblock(buf,amount)1090 readblock(buf, amount)
1091 register char *buf;
1092 register long amount;
1093 {
1094 register long n;
1095
1096 if ((n = peekblock(buf, amount)) != EOF) {
1097 buf_rwake(n);
1098 if (n < amount) {
1099 if ((amount = readblock(&buf[n], amount-n)) == EOF)
1100 return (n);
1101 return (n + amount);
1102 }
1103 }
1104 return (n);
1105 }
1106
1107 /*
1108 * Low level routine to read a TAPE Block (usually 10k)
1109 * Called from opentape() to check the compression and from readtape().
1110 */
1111 LOCAL long
readtblock(buf,amount)1112 readtblock(buf, amount)
1113 char *buf;
1114 long amount;
1115 {
1116 long cnt;
1117
1118 stats->reading = TRUE;
1119 if (isremote) {
1120 #ifdef USE_REMOTE
1121 /*
1122 * isremote will always be FALSE if USE_REMOTE is not defined.
1123 */
1124 if ((cnt = rmtread(remfd, buf, amount)) < 0)
1125 excomerr("Error reading '%s'.\n", tarfiles[tarfindex]);
1126 #endif
1127 } else {
1128 if ((cnt = _niread(fileno(tarf), buf, amount)) < 0)
1129 excomerr("Error reading '%s'.\n", tarfiles[tarfindex]);
1130 }
1131 return (cnt);
1132 }
1133
1134 /*
1135 * Refill the buffer if no fifo.
1136 * Called from buf_rwait()
1137 */
1138 LOCAL void
readbuf()1139 readbuf()
1140 {
1141 bigcnt = readtape(bigbuf, bigsize);
1142 bigptr = bigbuf;
1143 }
1144
1145 /*
1146 * Mid level function to read a tape block (usually 10k)
1147 * Called from the fifo fill code and from readbuf().
1148 */
1149 EXPORT ssize_t
readtape(buf,amount)1150 readtape(buf, amount)
1151 char *buf;
1152 size_t amount;
1153 {
1154 size_t amt;
1155 ssize_t cnt;
1156 char *bp;
1157 size_t size;
1158 static BOOL teof = FALSE;
1159
1160 if (teof)
1161 return (0);
1162
1163 amt = 0;
1164 bp = buf;
1165 size = amount;
1166
1167 do {
1168 cnt = readtblock(bp, size);
1169
1170 amt += cnt;
1171 bp += cnt;
1172 size -= cnt;
1173 } while (amt < amount && cnt > 0 && multblk);
1174
1175 if (amt == 0)
1176 return (amt);
1177 if (amt < TBLOCK) {
1178 errmsgno(EX_BAD, "Error reading '%s' size (%zd) too small.\n",
1179 tarfiles[tarfindex], amt);
1180 /*
1181 * Do not continue after we did read less than 512 bytes.
1182 */
1183 teof = TRUE;
1184 }
1185 /*
1186 * First block
1187 */
1188 if (stats->swapflg < 0) {
1189 if ((amt % TBLOCK) != 0)
1190 comerrno(EX_BAD, "Invalid blocksize %zd bytes.\n", amt);
1191 if (amt < amount) {
1192 stats->blocksize = bigsize = amt;
1193 stats->nblocks = bigsize/TBLOCK;
1194 #ifdef FIFO
1195 if (use_fifo)
1196 fifo_ibs_shrink(amt);
1197 #endif
1198 errmsgno(EX_BAD, "Blocksize = %ld records.\n",
1199 stats->blocksize/TBLOCK);
1200 }
1201 }
1202 if (stats->swapflg > 0)
1203 swabbytes(buf, amt);
1204
1205 if (amt == stats->blocksize)
1206 stats->blocks++;
1207 else
1208 stats->parts += amt;
1209 stats->lastsize = amt;
1210 #ifdef DEBUG
1211 error("readbuf: cnt: %d.\n", amt);
1212 #endif
1213 return (amt);
1214 }
1215
1216 #define DO8(a) a; a; a; a; a; a; a; a;
1217
1218 #ifdef MY_SWABBYTES
1219
1220 void
swabbytes(bp,cnt)1221 swabbytes(bp, cnt)
1222 register char *bp;
1223 register long cnt;
1224 {
1225 register char c;
1226
1227 cnt /= 2; /* even count only */
1228 while ((cnt -= 8) >= 0) {
1229 DO8(c = *bp++; bp[-1] = *bp; *bp++ = c);
1230 }
1231 cnt += 8;
1232
1233 while (--cnt >= 0) {
1234 c = *bp++; bp[-1] = *bp; *bp++ = c;
1235 }
1236 }
1237 #endif
1238
1239 #define DO16(a) DO8(a) DO8(a)
1240
1241 EXPORT void
filltcb(ptb)1242 filltcb(ptb)
1243 register TCB *ptb;
1244 {
1245 register int i;
1246 register long *lp = ptb->ldummy;
1247
1248 for (i = 512/sizeof (long)/16; --i >= 0; ) {
1249 DO16(*lp++ = 0L)
1250 }
1251 }
1252
1253 EXPORT void
movetcb(from_ptb,to_ptb)1254 movetcb(from_ptb, to_ptb)
1255 register TCB *from_ptb;
1256 register TCB *to_ptb;
1257 {
1258 register int i;
1259 register long *from = from_ptb->ldummy;
1260 register long *to = to_ptb->ldummy;
1261
1262 for (i = 512/sizeof (long)/16; --i >= 0; ) {
1263 DO16(*to++ = *from++)
1264 }
1265 }
1266
1267 /*
1268 * Try to allocate 'amount' bytes from the buffer or from the fifo.
1269 * If it is not possible to get 'amount' bytes in a single chunk, return NULL.
1270 */
1271 EXPORT void *
get_block(amount)1272 get_block(amount)
1273 long amount;
1274 {
1275 if (buf_wait(amount) < amount)
1276 return ((void *)NULL);
1277 return ((void *)bigptr);
1278 }
1279
1280 /*
1281 * Tell the buffer or the fifo that 'amount' bytes in the buffer/fifo space
1282 * are ready to be written.
1283 */
1284 EXPORT void
put_block(amount)1285 put_block(amount)
1286 long amount;
1287 {
1288 buf_wake(amount);
1289 }
1290
1291 /*
1292 * Write TBLOCK bytes into the buffer/fifo space and tell the buffer/fifo
1293 * that TBLOCK bytes are ready to be written.
1294 */
1295 EXPORT char *
writeblock(buf)1296 writeblock(buf)
1297 char *buf;
1298 {
1299 char *obp;
1300
1301 buf_wait(TBLOCK);
1302 obp = bigptr;
1303 movetcb((TCB *)buf, (TCB *)bigptr);
1304 buf_wake(TBLOCK);
1305
1306 return (obp);
1307 }
1308
1309 /*
1310 * Mid level function to write a tape block (usually 10k)
1311 * Called from the fifo fill output code and from writebuf().
1312 */
1313 EXPORT ssize_t
writetape(buf,amount)1314 writetape(buf, amount)
1315 char *buf;
1316 size_t amount;
1317 {
1318 ssize_t cnt;
1319 int err = 0;
1320 /* hartes oder weiches EOF ??? */
1321 /* d.h. < 0 oder <= 0 */
1322 stats->reading = FALSE;
1323 if (multivol && tsize) {
1324 Ullong cursize;
1325
1326 cursize = stats->blocks * stats->nblocks + stats->parts / TBLOCK;
1327
1328 if (cursize >= tsize) { /* tsize= induced change */
1329 changetape(TRUE);
1330 cnt = startvol(buf, amount);
1331 if (cnt > 0)
1332 return (cnt);
1333 }
1334 }
1335 seterrno(0);
1336 if (nullout) {
1337 cnt = amount;
1338 #ifdef USE_REMOTE
1339 } else if (isremote) {
1340 cnt = rmtwrite(remfd, buf, amount); /* Handles EINTR */
1341 #endif
1342 } else {
1343 cnt = _niwrite(fileno(tarf), buf, amount); /* Handles EINTR */
1344 }
1345 if (cnt == 0) {
1346 err = EFBIG;
1347 } else if (cnt < 0) {
1348 err = geterrno();
1349 }
1350
1351 if (multivol && (err == EFBIG || err == ENOSPC)) {
1352 /*
1353 * QIC tapes (unblocked) may do partial writes at EOT.
1354 * We do the tape change not at the point when we write less
1355 * than a tape block (this may happen on pipes too) but after
1356 * we got a true EOF condition.
1357 */
1358 return (-2);
1359 }
1360 if (multivol && (err == ENXIO)) {
1361 /*
1362 * EOF condition on disk devices
1363 */
1364 return (-2);
1365 }
1366
1367 if (cnt == stats->blocksize)
1368 stats->blocks++;
1369 else if (cnt >= 0)
1370 stats->parts += cnt;
1371
1372 if (cnt <= 0)
1373 excomerrno(err, "Error writing '%s'.\n", tarfiles[tarfindex]);
1374 return (cnt);
1375 }
1376
1377 /*
1378 * Write output the buffer if no fifo.
1379 * Called from buf_wait()
1380 */
1381 LOCAL void
writebuf(amount)1382 writebuf(amount)
1383 long amount;
1384 {
1385 long cnt;
1386
1387
1388 nextwrite:
1389 cnt = writetape(bigbuf, amount);
1390
1391 if (cnt < amount) {
1392 if (cnt == -2) { /* EOT induced change */
1393 changetape(TRUE);
1394 if ((cnt = startvol(bigbuf, amount)) <= 0)
1395 goto nextwrite;
1396 }
1397 /*
1398 * QIC tapes (unblocked) may do partial writes at EOT
1399 *
1400 * Even if we hit a "planned" tape change, the fact
1401 * that we need to write a vol header looks from higher
1402 * levels as if there was a partial write.
1403 */
1404 bigptr = &bigbuf[cnt];
1405 bigcnt -= cnt;
1406 movebytes(bigptr, bigbuf, bigcnt);
1407 bigptr = &bigbuf[bigcnt];
1408 } else {
1409 bigptr = bigbuf;
1410 bigcnt = 0;
1411 }
1412 stats->old_size = stats->cur_size;
1413 stats->old_off = stats->cur_off;
1414 }
1415
1416 /*
1417 * Called only from weof()
1418 */
1419 LOCAL void
flushbuf()1420 flushbuf()
1421 {
1422 #ifdef FIFO
1423 if (!use_fifo)
1424 #endif
1425 {
1426 /*
1427 * Loop because a tape change and writing a vol header
1428 * may look like an incomplete write and need a second
1429 * write to really flush the buffer.
1430 */
1431 while (bigcnt > 0)
1432 writebuf(bigcnt);
1433 }
1434 }
1435
1436 /*
1437 * Write an empty TBLOCK
1438 * Called from weof() and cr_file()
1439 */
1440 EXPORT void
writeempty()1441 writeempty()
1442 {
1443 TCB tb;
1444
1445 filltcb(&tb);
1446 writeblock((char *)&tb);
1447 }
1448
1449 /*
1450 * Write a logical TAR EOF (2 empty TBLOCK sized blocks)
1451 * or a CPIO EOF marker.
1452 */
1453 EXPORT void
weof()1454 weof()
1455 {
1456 if ((props.pr_flags & PR_CPIO) != 0) {
1457 cpio_weof();
1458 buf_sync(TBLOCK);
1459 } else {
1460 writeempty();
1461 writeempty();
1462 }
1463 if (!partial)
1464 buf_sync(0);
1465 flushbuf();
1466 }
1467
1468 /*
1469 * If size == 0, fill the buffer up to a TAPE record (usually 10k),
1470 * if size != 0, fill the buffer up to size.
1471 */
1472 EXPORT void
buf_sync(size)1473 buf_sync(size)
1474 long size;
1475 {
1476 #ifdef FIFO
1477 if (use_fifo) {
1478 fifo_sync(size);
1479 } else
1480 #endif
1481 if (size) {
1482 long amt = 0;
1483
1484 if ((bigcnt % size) != 0)
1485 amt = size - bigcnt%size;
1486
1487 fillbytes(bigptr, amt, '\0');
1488 bigcnt += amt;
1489 bigptr += amt;
1490 } else {
1491 fillbytes(bigptr, bigsize - bigcnt, '\0');
1492 bigcnt = bigsize;
1493 }
1494 }
1495
1496 /*
1497 * Drain the fifo if in fifo mode.
1498 */
1499 EXPORT void
buf_drain()1500 buf_drain()
1501 {
1502 #ifdef FIFO
1503 if (use_fifo) {
1504 fifo_oflush(); /* Set FIFO_MEOF flag and wake other side */
1505 fifo_oclose(); /* Close sync pipe to finally wake other side */
1506 wait(0);
1507 }
1508 #endif
1509 }
1510
1511 /*
1512 * Wait until we may put amount bytes into the buffer/fifo.
1513 * The returned count may be lower. Callers need to be prepared about this.
1514 */
1515 EXPORT long
buf_wait(amount)1516 buf_wait(amount)
1517 long amount;
1518 {
1519 #ifdef FIFO
1520 if (use_fifo) {
1521 return (fifo_iwait(amount));
1522 } else
1523 #endif
1524 {
1525 if (bigcnt >= bigsize)
1526 writebuf(bigsize);
1527 return (bigsize - bigcnt);
1528 }
1529 }
1530
1531 /*
1532 * Tell the buffer/fifo management that amount bytes are ready to be written.
1533 * The space may now be written to the media and the space may be made
1534 * avbailable for being filled up again.
1535 */
1536 EXPORT void
buf_wake(amount)1537 buf_wake(amount)
1538 long amount;
1539 {
1540 #ifdef FIFO
1541 if (use_fifo) {
1542 fifo_owake(amount);
1543 } else
1544 #endif
1545 {
1546 bigptr += amount;
1547 bigcnt += amount;
1548 }
1549 if (copyflag) {
1550 /*
1551 * In copy mode, there is no blocked read/write from the fifo
1552 * Tape process. For this reason, we increment the byte count
1553 * at this place.
1554 */
1555 stats->parts += amount;
1556 }
1557 }
1558
1559 /*
1560 * Wait until we may read amount bytes from the buffer/fifo.
1561 * The returned count may be lower. Callers need to be prepared about this.
1562 */
1563 EXPORT long
buf_rwait(amount)1564 buf_rwait(amount)
1565 long amount;
1566 {
1567 long cnt;
1568
1569 again:
1570 #ifdef FIFO
1571 if (use_fifo) {
1572 cnt = fifo_owait(amount);
1573 } else
1574 #endif
1575 {
1576 if (bigcnt <= 0)
1577 readbuf();
1578 cnt = bigcnt;
1579 }
1580 if (cnt == 0 && multivol) {
1581 nextitape();
1582 goto again;
1583 }
1584 return (cnt);
1585 }
1586
1587 /*
1588 * Tell the buffer/fifo management that amount bytes are no longer needed for
1589 * read access. The space may now be filled up with new data from the medium.
1590 */
1591 EXPORT void
buf_rwake(amount)1592 buf_rwake(amount)
1593 long amount;
1594 {
1595 #ifdef FIFO
1596 if (use_fifo) {
1597 fifo_iwake(amount);
1598 } else
1599 #endif
1600 {
1601 bigptr += amount;
1602 bigcnt -= amount;
1603 }
1604 }
1605
1606 /*
1607 * Resume the fifo if the fifo has been blocked after the first read
1608 * TAPE block (usually 10 k).
1609 * If the fifo is active, fifo_resume() triggers a shadow call to
1610 * setprops() in the fifo background process.
1611 */
1612 EXPORT void
buf_resume()1613 buf_resume()
1614 {
1615 extern long hdrtype;
1616 stats->swapflg = swapflg; /* copy over for fifo process */
1617 stats->hdrtype = hdrtype; /* copy over for fifo process */
1618 bigsize = stats->blocksize; /* copy over for tar process */
1619 #ifdef FIFO
1620 if (use_fifo)
1621 fifo_resume();
1622 #endif
1623 }
1624
1625 /*
1626 * Backspace tape or medium to prepare it for appending to an archive.
1627 * Note that this currently only handles TAR archives and that even then it
1628 * will not work if the TAPE record size is < 2*TBLOCK (1024 bytes).
1629 */
1630 EXPORT void
backtape()1631 backtape()
1632 {
1633 Llong ret;
1634 BOOL istape = FALSE;
1635
1636 if (debug) {
1637 error("Blocks: %lld\n", tblocks());
1638 error("filepos: %lld seeking to: %lld bigsize: %ld\n",
1639 (Llong)mtseek((off_t)0, SEEK_CUR),
1640 (Llong)mtseek((off_t)0, SEEK_CUR) - (Llong)stats->lastsize, bigsize);
1641 }
1642
1643 if (mtioctl(MTNOP, 0) >= 0) {
1644 istape = TRUE;
1645 if (debug)
1646 error("Is a tape: BSR 1...\n");
1647 ret = mtioctl(MTBSR, 1);
1648 } else {
1649 if (debug)
1650 error("Is a file: lseek()\n");
1651 ret = mtseek(-stats->lastsize, SEEK_CUR);
1652 }
1653 if (ret == (Llong)-1)
1654 excomerr("Cannot backspace %s.\n", istape ? "tape":"medium");
1655
1656 if (stats->lastsize == stats->blocksize)
1657 stats->blocks--;
1658 else
1659 stats->parts -= stats->lastsize;
1660 }
1661
1662 /*
1663 * Send an MTIOCTOP call to the file descriptor that is use for the medium.
1664 */
1665 EXPORT int
mtioctl(cmd,count)1666 mtioctl(cmd, count)
1667 int cmd;
1668 int count;
1669 {
1670 int ret;
1671
1672 if (nullout && !(uflag || rflag)) {
1673 return (0);
1674 #ifdef USE_REMOTE
1675 } else if (isremote) {
1676 ret = rmtioctl(remfd, cmd, count);
1677 #endif
1678 } else {
1679 #if defined(MTIOCTOP) && defined(HAVE_IOCTL)
1680 struct mtop mtop;
1681
1682 mtop.mt_op = cmd;
1683 mtop.mt_count = count;
1684
1685 ret = ioctl(fdown(tarf), MTIOCTOP, &mtop);
1686 #else
1687 #ifdef ENOSYS
1688 seterrno(ENOSYS);
1689 #else
1690 seterrno(EINVAL);
1691 #endif
1692 return (-1);
1693 #endif
1694 }
1695 if (ret < 0 && debug) {
1696 errmsg("Error sending mtioctl(%d, %d) to '%s'.\n",
1697 cmd, count, tarfiles[tarfindex]);
1698 }
1699 return (ret);
1700 }
1701
1702 /*
1703 * Make an lseek() call to the file descriptor that is use for the medium.
1704 */
1705 EXPORT off_t
mtseek(offset,whence)1706 mtseek(offset, whence)
1707 off_t offset;
1708 int whence;
1709 {
1710 if (nullout && !(uflag || rflag)) {
1711 return (0L);
1712 #ifdef USE_REMOTE
1713 } else if (isremote) {
1714 return (rmtseek(remfd, offset, whence));
1715 #endif
1716 } else {
1717 return (lseek(fileno(tarf), offset, whence));
1718 }
1719 }
1720
1721 /*
1722 * Return the current archive block number based on 512 byte (TBLOCK) units.
1723 */
1724 EXPORT Llong
tblocks()1725 tblocks()
1726 {
1727 long fifo_cnt = 0;
1728 Llong ret;
1729
1730 #ifdef FIFO
1731 if (use_fifo)
1732 fifo_cnt = fifo_amount()/TBLOCK;
1733 #endif
1734 if (stats->reading)
1735 ret = (-fifo_cnt + stats->blocks * stats->nblocks +
1736 (stats->parts - (bigcnt+TBLOCK))/TBLOCK);
1737 else
1738 ret = (fifo_cnt + stats->blocks * stats->nblocks +
1739 (stats->parts + bigcnt)/TBLOCK);
1740 if (debug) {
1741 error("tblocks: %lld blocks: %lld blocksize: %ld parts: %lld bigcnt: %ld fifo_cnt: %ld\n",
1742 ret, stats->blocks, stats->blocksize, stats->parts, bigcnt, fifo_cnt);
1743 }
1744 curblockno = ret;
1745 return (ret);
1746 }
1747
1748 EXPORT void
prstats()1749 prstats()
1750 {
1751 Llong bytes;
1752 Llong kbytes;
1753 int per;
1754 #ifdef timerclear
1755 int sec;
1756 int nsec;
1757 int tmsec;
1758 #endif
1759 char *p;
1760
1761 #ifdef FIFO
1762 if (use_fifo) {
1763 extern m_head *mp;
1764 p = mp->end;
1765 } else
1766 #endif
1767 p = &bigbuf[bigbsize];
1768
1769 if ((*p != 'U' && *p != ' ') || p[1] != 'U')
1770 errmsgno(EX_BAD, "The buffer has been overwritten, please contact the author.\n");
1771
1772 if (no_stats)
1773 return;
1774 if (pid == 0) /* child */
1775 return;
1776
1777 #ifdef timerclear
1778 if (showtime && getnstimeofday(&stoptime) < 0)
1779 comerr("Cannot get stoptime\n");
1780 #endif
1781 #ifdef FIFO
1782 if (use_fifo && do_fifostats)
1783 fifo_stats();
1784 #endif
1785
1786 bytes = stats->blocks * (Llong)stats->blocksize + stats->parts;
1787 kbytes = bytes >> 10;
1788 per = ((bytes&1023)<<10)/10485;
1789
1790 if (cpio_stats) {
1791 bytes = stats->Tblocks * (Llong)stats->blocksize + stats->Tparts;
1792
1793 error("%lld blocks\n", stats->eofblock + 1 + bytes/512);
1794 return;
1795 }
1796
1797 errmsgno(EX_BAD,
1798 "%lld blocks + %lld bytes (total of %lld bytes = %lld.%02dk).\n",
1799 stats->blocks, stats->parts, bytes, kbytes, per);
1800
1801 if (stats->Tblocks + stats->Tparts) {
1802 bytes = (stats->blocks + stats->Tblocks) *
1803 (Llong)stats->blocksize +
1804 (stats->parts + stats->Tparts);
1805 kbytes = bytes >> 10;
1806 per = ((bytes&1023)<<10)/10485;
1807
1808 errmsgno(EX_BAD,
1809 "Total %lld blocks + %lld bytes (total of %lld bytes = %lld.%02dk).\n",
1810 stats->blocks + stats->Tblocks,
1811 stats->parts + stats->Tparts,
1812 bytes, kbytes, per);
1813 }
1814 #ifdef timerclear
1815 if (showtime) {
1816 Llong kbs;
1817
1818 sec = stoptime.tv_sec - starttime.tv_sec;
1819 nsec = stoptime.tv_nsec - starttime.tv_nsec;
1820 tmsec = sec*1000 + nsec/1000000;
1821 if (nsec < 0) {
1822 sec--;
1823 nsec += 1000000000;
1824 }
1825 if (tmsec == 0)
1826 tmsec++;
1827
1828 kbs = kbytes*(Llong)1000/tmsec;
1829
1830 errmsgno(EX_BAD, "Total time %d.%03dsec (%lld kBytes/sec)\n",
1831 sec, nsec/1000000, kbs);
1832 }
1833 #endif
1834 #ifdef DBG_MALLOC
1835 aprintlist(stdout, 1);
1836 #endif
1837 }
1838
1839 EXPORT BOOL
checkerrs()1840 checkerrs()
1841 {
1842 if (xstats.s_staterrs ||
1843 #ifdef USE_ACL
1844 xstats.s_getaclerrs ||
1845 #endif
1846 xstats.s_openerrs ||
1847 xstats.s_rwerrs ||
1848 xstats.s_misslinks ||
1849 xstats.s_toolong ||
1850 xstats.s_toobig ||
1851 xstats.s_isspecial ||
1852 xstats.s_sizeerrs ||
1853 xstats.s_chdir ||
1854 xstats.s_iconv ||
1855 xstats.s_id ||
1856 xstats.s_time ||
1857
1858 xstats.s_settime ||
1859 xstats.s_security ||
1860 xstats.s_lsecurity ||
1861 xstats.s_samefile ||
1862 #ifdef USE_ACL
1863 xstats.s_badacl ||
1864 xstats.s_setacl ||
1865 #endif
1866 #ifdef USE_XATTR
1867 xstats.s_getxattr ||
1868 xstats.s_setxattr ||
1869 #endif
1870 xstats.s_setmodes ||
1871 xstats.s_restore ||
1872 xstats.s_compress ||
1873 xstats.s_hardeof ||
1874 xstats.s_substerrs ||
1875 xstats.s_selinuxerrs) {
1876 if (nowarn || no_stats || (pid == 0) /* child */)
1877 return (TRUE);
1878
1879 errmsgno(EX_BAD, "The following problems occurred during archive processing:\n");
1880 errmsgno(EX_BAD, "Cannot: stat %d, open %d, read/write %d, chdir %d, iconv %d.\n",
1881 xstats.s_staterrs,
1882 xstats.s_openerrs,
1883 xstats.s_rwerrs,
1884 xstats.s_chdir,
1885 xstats.s_iconv);
1886 if (xstats.s_id || xstats.s_time)
1887 errmsgno(EX_BAD, "Range errors: uid/gid %d, time: %d.\n",
1888 xstats.s_id, xstats.s_time);
1889 errmsgno(EX_BAD, "Size changed %d.\n",
1890 xstats.s_sizeerrs);
1891 errmsgno(EX_BAD, "Missing links %d, Name too long %d, File too big %d, Not dumped %d.\n",
1892 xstats.s_misslinks,
1893 xstats.s_toolong,
1894 xstats.s_toobig,
1895 xstats.s_isspecial);
1896 if (xstats.s_settime || xstats.s_setmodes)
1897 errmsgno(EX_BAD, "Cannot set: time %d, modes %d.\n",
1898 xstats.s_settime,
1899 xstats.s_setmodes);
1900 if (xstats.s_security || xstats.s_lsecurity)
1901 errmsgno(EX_BAD, "Skipped for security reason: path name %d, link name %d.\n",
1902 xstats.s_security, xstats.s_lsecurity);
1903 if (xstats.s_samefile)
1904 errmsgno(EX_BAD, "Skipped same file %d.\n",
1905 xstats.s_samefile);
1906 #ifdef USE_ACL
1907 if (xstats.s_getaclerrs || xstats.s_badacl || xstats.s_setacl)
1908 errmsgno(EX_BAD, "Cannot get ACL: %d set ACL: %d. Bad ACL %d.\n",
1909 xstats.s_getaclerrs,
1910 xstats.s_setacl,
1911 xstats.s_badacl);
1912 #endif
1913 #ifdef USE_XATTR
1914 if (xstats.s_getxattr || xstats.s_setxattr)
1915 errmsgno(EX_BAD, "Cannot get xattr: %d set xattr: %d.\n",
1916 xstats.s_getxattr,
1917 xstats.s_setxattr);
1918 #endif
1919 #ifdef USE_SELINUX
1920 if (xstats.s_selinuxerrs)
1921 errmsgno(EX_BAD, "Cannot set SELinux security context: %d.\n",
1922 xstats.s_selinuxerrs);
1923 #endif
1924 if (xstats.s_restore)
1925 errmsgno(EX_BAD, "Problems with restore database.\n");
1926 if (xstats.s_compress)
1927 errmsgno(EX_BAD, "Problems with compress program.\n");
1928 if (xstats.s_substerrs)
1929 errmsgno(EX_BAD,
1930 "%d Problem(s) with path substitution.\n",
1931 xstats.s_substerrs);
1932 if (xstats.s_hardeof)
1933 errmsgno(EX_BAD, "Hard EOF on input.\n");
1934
1935 if (xstats.s_security)
1936 errmsgno(EX_BAD, "See option -.. on why some files have been skipped.\n");
1937 if (xstats.s_lsecurity)
1938 errmsgno(EX_BAD, "See option -secure-links on why some links have been skipped.\n");
1939 return (TRUE);
1940 }
1941 return (FALSE);
1942 }
1943
1944 EXPORT void
exprstats(ret)1945 exprstats(ret)
1946 int ret;
1947 {
1948 prstats();
1949 checkerrs();
1950 if (use_fifo)
1951 fifo_exit(ret);
1952 exit(ret);
1953 }
1954
1955 /* VARARGS2 */
1956 #ifdef PROTOTYPES
1957 EXPORT void
excomerrno(int err,char * fmt,...)1958 excomerrno(int err, char *fmt, ...)
1959 #else
1960 EXPORT void
1961 excomerrno(err, fmt, va_alist)
1962 int err;
1963 char *fmt;
1964 va_dcl
1965 #endif
1966 {
1967 va_list args;
1968
1969 #ifdef PROTOTYPES
1970 va_start(args, fmt);
1971 #else
1972 va_start(args);
1973 #endif
1974 errmsgno(err, "%r", _(fmt), args);
1975 va_end(args);
1976 #ifdef FIFO
1977 fifo_exit(err);
1978 #endif
1979 exprstats(err);
1980 /* NOTREACHED */
1981 }
1982
1983 /* VARARGS1 */
1984 #ifdef PROTOTYPES
1985 EXPORT void
excomerr(char * fmt,...)1986 excomerr(char *fmt, ...)
1987 #else
1988 EXPORT void
1989 excomerr(fmt, va_alist)
1990 char *fmt;
1991 va_dcl
1992 #endif
1993 {
1994 va_list args;
1995 int err = geterrno();
1996
1997 #ifdef PROTOTYPES
1998 va_start(args, fmt);
1999 #else
2000 va_start(args);
2001 #endif
2002 errmsgno(err, "%r", _(fmt), args);
2003 va_end(args);
2004 #ifdef FIFO
2005 fifo_exit(err);
2006 #endif
2007 exprstats(err);
2008 /* NOTREACHED */
2009 }
2010
2011 EXPORT void
die(err)2012 die(err)
2013 int err;
2014 {
2015 excomerrno(err, "Cannot recover from error - exiting.\n");
2016 }
2017
2018 /*
2019 * Quick hack to implement a -z flag. May be changed soon.
2020 */
2021 #include <schily/signal.h>
2022 #if defined(SIGDEFER) || defined(SVR4)
2023 #define signal sigset
2024 #endif
2025
2026 LOCAL pid_t compresspid;
2027
2028 #ifdef USE_SIGCLD
2029 LOCAL void
cldhandler(sig,sip,context)2030 cldhandler(sig, sip, context)
2031 int sig;
2032 siginfo_t *sip;
2033 void *context;
2034 {
2035 if (sip->si_pid != compresspid)
2036 return;
2037
2038 if (sip->si_status != 0 || sip->si_code != CLD_EXITED)
2039 xstats.s_compress++;
2040
2041 if (sip->si_status != 0 && sip->si_code == CLD_EXITED)
2042 errmsgno(EX_BAD,
2043 "Compress program exited with status %d.\n",
2044 sip->si_status);
2045 else if (sip->si_status != 0)
2046 errmsgno(EX_BAD,
2047 "Compress program died with signal %d.\n",
2048 sip->si_status);
2049 }
2050
2051 LOCAL void
handlecld()2052 handlecld()
2053 {
2054 struct sigaction sa;
2055
2056 sa.sa_sigaction = cldhandler;
2057 sigemptyset(&sa.sa_mask);
2058 sa.sa_flags = SA_RESTART|SA_SIGINFO;
2059
2060 sigaction(SIGCHLD, &sa, NULL);
2061 }
2062 #endif /* USE_SIGCLD */
2063
2064 LOCAL void
compressopen()2065 compressopen()
2066 {
2067 #ifdef HAVE_FORK
2068 FILE *pp[2];
2069 int mypid;
2070 char *zip_prog = "gzip";
2071
2072 if (compress_prg)
2073 zip_prog = compress_prg;
2074 else if (bzflag)
2075 zip_prog = "bzip2";
2076 else if (Zflag)
2077 zip_prog = "compress";
2078 else if (lzoflag)
2079 zip_prog = "lzop";
2080 else if (p7zflag)
2081 zip_prog = "p7zip";
2082 else if (xzflag)
2083 zip_prog = "xz";
2084 else if (lzipflag)
2085 zip_prog = "lzip";
2086 else if (zstdflag)
2087 zip_prog = "zstd";
2088 else if (lzmaflag)
2089 zip_prog = "lzma";
2090 else if (freezeflag)
2091 zip_prog = "freeze";
2092
2093 multblk = TRUE;
2094
2095 if (cflag && (uflag || rflag))
2096 comerrno(EX_BAD, "Cannot update compressed archives.\n");
2097
2098 #ifdef __DJGPP__
2099 if (cflag) {
2100 /*
2101 * We try to emulate a command line like:
2102 *
2103 * "star -c dir | %s > dir.tar.%s\n",
2104 * zip_prog,
2105 * Zflag?"Z":bzflag?"bz2":compress_prg?compress_prg:"gz");
2106 *
2107 * If we would use popen() instead, DJGPP will run the program
2108 * from popen() first, so there would
2109 * be no data from the "tarf" File pointer.
2110 * We use the temporary file instead.
2111 */
2112 if ((compress_tmpf = tmpfile()) == NULL)
2113 comerr("Compress pipe failed\n");
2114 compress_tarf_save = tarf;
2115 tarf = compress_tmpf;
2116
2117 } else {
2118 int stdin_save;
2119 char zip_cmd[256];
2120
2121 /*
2122 * We try to emulate a command line like:
2123 *
2124 * "%s -d < archive.tar.%s | star -x\n",
2125 * zip_prog,
2126 * Zflag?"Z":bzflag?"bz2":compress_prg?compress_prg:"gz");
2127 */
2128 js_snprintf(zip_cmd, sizeof (zip_cmd), "%s.exe -d", zip_prog);
2129
2130 stdin_save = dup(STDIN_FILENO);
2131 dup2(fileno(tarf), STDIN_FILENO);
2132 compress_tarf_save = tarf;
2133 if ((tarf = popen(zip_cmd, "rb")) == NULL)
2134 comerr("Compress pipe failed\n");
2135 dup2(stdin_save, STDIN_FILENO);
2136 fclose(compress_tarf_save);
2137 }
2138 #else
2139 if (fpipe(pp) == 0)
2140 comerr("Compress pipe failed\n");
2141 #ifdef USE_SIGCLD
2142 handlecld();
2143 #endif
2144 mypid = fork();
2145 if (mypid < 0)
2146 comerr("Compress fork failed\n");
2147 if (mypid == 0) {
2148 FILE *null;
2149 char *flg = getenv("STAR_COMPRESS_FLAG"); /* Temporary ? */
2150
2151 signal(SIGQUIT, SIG_IGN);
2152 if (cflag)
2153 fclose(pp[1]);
2154 else
2155 fclose(pp[0]);
2156
2157 #ifdef NEED_O_BINARY
2158 if (cflag)
2159 setmode(fileno(pp[0]), O_BINARY);
2160 else
2161 setmode(fileno(pp[1]), O_BINARY);
2162 #endif
2163
2164 /* We don't want to see errors */
2165 null = lfilemopen("/dev/null", "rw", S_IRWALL);
2166 if (null == NULL) {
2167 errmsg("Cannot open '%s'.\n", "/dev/null");
2168 goto err;
2169 }
2170
2171 if (cflag)
2172 fexecl(zip_prog, pp[0], tarf, null, zip_prog, flg, (char *)NULL);
2173 else
2174 fexecl(zip_prog, tarf, pp[1], null, zip_prog, "-d", (char *)NULL);
2175 err:
2176 errmsg("Compress: exec of '%s' failed\n", zip_prog);
2177 _exit(-1);
2178 } else {
2179 compresspid = mypid;
2180 }
2181 fclose(tarf);
2182 if (cflag) {
2183 tarf = pp[1];
2184 fclose(pp[0]);
2185 } else {
2186 tarf = pp[0];
2187 fclose(pp[1]);
2188 }
2189 setmode(fileno(tarf), O_BINARY);
2190 #endif /* !__DJGPP__ */
2191 #else /* !HAVE_FORK */
2192 comerrno(EX_BAD, "Inline compression not available.\n");
2193 #endif
2194 }
2195
2196 LOCAL void
compressclose()2197 compressclose()
2198 {
2199 #ifdef HAVE_FORK
2200 #ifdef __DJGPP__
2201 if (cflag) {
2202 if (compress_tmpf) {
2203 char zip_cmd[256];
2204 FILE *zipf;
2205 int cnt = -1;
2206 char buf[8192];
2207 char *zip_prog = "gzip";
2208
2209 if (compress_prg)
2210 zip_prog = compress_prg;
2211 else if (bzflag)
2212 zip_prog = "bzip2";
2213 else if (Zflag)
2214 zip_prog = "compress";
2215 else if (lzoflag)
2216 zip_prog = "lzop";
2217 else if (p7zflag)
2218 zip_prog = "p7zip";
2219 else if (xzflag)
2220 zip_prog = "xz";
2221 else if (lzipflag)
2222 zip_prog = "lzip";
2223 else if (zstdflag)
2224 zip_prog = "zstd";
2225 else if (lzmaflag)
2226 zip_prog = "lzma";
2227 else if (freezeflag)
2228 zip_prog = "freeze";
2229
2230 js_snprintf(zip_cmd, sizeof (zip_cmd), "%s.exe", zip_prog);
2231
2232 dup2(fileno(compress_tarf_save), STDOUT_FILENO);
2233
2234 if ((zipf = popen(zip_cmd, "wb")) == NULL)
2235 comerr("Compress pipe failed\n");
2236
2237 fseek(compress_tmpf, 0l, SEEK_SET);
2238
2239 while ((cnt = ffileread(compress_tmpf, buf, sizeof (buf))) > 0)
2240 ffilewrite(zipf, buf, cnt);
2241
2242 pclose(zipf);
2243 fclose(compress_tmpf);
2244 compress_tmpf = (FILE *)NULL;
2245 }
2246
2247 } else {
2248 pclose(tarf);
2249 }
2250 #endif
2251 #endif
2252 }
2253