Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / cmd / pax / bio.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: bio.c /main/3 1995/11/01 16:58:37 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
34 *           This software is licensed by AT&T Corp.            *
35 *       under the terms and conditions of the license in       *
36 *       http://www.research.att.com/orgs/ssr/book/reuse        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46
47 /* : : generated by proto : : */
48
49 #if !defined(__PROTO__)
50 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
51 #if defined(__cplusplus)
52 #define __MANGLE__      "C"
53 #else
54 #define __MANGLE__
55 #endif
56 #define __STDARG__
57 #define __PROTO__(x)    x
58 #define __OTORP__(x)
59 #define __PARAM__(n,o)  n
60 #if !defined(__STDC__) && !defined(__cplusplus)
61 #if !defined(c_plusplus)
62 #define const
63 #endif
64 #define signed
65 #define void            int
66 #define volatile
67 #define __V_            char
68 #else
69 #define __V_            void
70 #endif
71 #else
72 #define __PROTO__(x)    ()
73 #define __OTORP__(x)    x
74 #define __PARAM__(n,o)  o
75 #define __MANGLE__
76 #define __V_            char
77 #define const
78 #define signed
79 #define void            int
80 #define volatile
81 #endif
82 #if defined(__cplusplus) || defined(c_plusplus)
83 #define __VARARG__      ...
84 #else
85 #define __VARARG__
86 #endif
87 #if defined(__STDARG__)
88 #define __VA_START__(p,a)       va_start(p,a)
89 #else
90 #define __VA_START__(p,a)       va_start(p)
91 #endif
92 #endif
93 #include "pax.h"
94
95 #include "FEATURE/mtio"
96 #if _sys_mtio
97 #include <ast_tty.h>
98 #include <sys/mtio.h>
99 #endif
100 #ifdef MTIOCTOP
101 #if defined(MTIOBSF) && !defined(MTBSF)
102 #define MTBSF   MTIOBSF
103 #endif
104 #if defined(MTIOBSR) && !defined(MTBSR)
105 #define MTBSR   MTIOBSR
106 #endif
107 #if defined(MTIOEOM) && !defined(MTEOM)
108 #define MTEOM   MTIOEOM
109 #endif
110 #if defined(MTIOFSF) && !defined(MTFSF)
111 #define MTFSF   MTIOFSF
112 #endif
113 #if defined(MTIOWEOF) && !defined(MTWEOF)
114 #define MTWEOF  MTIOWEOF
115 #endif
116 #if !defined(MTBSF) || !defined(MTBSR) || !defined(MTWEOF) || defined(__hppa)/*hppa-compiler-signal-10*/
117 #undef  MTIOCTOP
118 #endif
119 #endif
120
121 #if 0 && DEBUG
122
123 /*
124  * -o blok=i    input is BLOK file
125  * -o blok=o    output file is BLOK file
126  */
127
128 static int
129 blokread __PARAM__((register Archive_t* ap, char* buf, int n), (ap, buf, n)) __OTORP__(register Archive_t* ap; char* buf; int n;){
130         register int            i;
131         register int            j;
132         char                    c;
133
134         static int              eof;
135
136         if (!ap->io.blokflag)
137         {
138                 ap->io.blokflag = 1;
139                 eof = 0;
140                 if ((i = read(ap->io.fd, buf, ap->io.blok ? 4 : n)) < 4 || !strneq(buf, "\002\014\017\013", 4))
141                 {
142                         if (ap->io.blok) error(3, "%s: input archive is not a BLOK file", ap->name);
143                         return(i);
144                 }
145                 if (i > 4 && lseek(ap->io.fd, 4L, SEEK_SET) != 4L)
146                         error(3, "%s: cannot seek on input archive BLOK file -- use -o blok=i", ap->name);
147                 ap->io.blok = 1;
148         }
149         if (ap->io.blok)
150         {
151                 j = 0;
152                 do
153                 {
154                         if ((i = read(ap->io.fd, &c, 1)) < 1)
155                                 return(i < 0 && ++eof == 1 ? 0 : -1);
156                         j <<= 7;
157                         j |= c & 0177;
158                 } while (c & 0200);
159                 if (j > 0)
160                 {
161                         if (j > n)
162                                 error(2, "%s: blokread buffer overflow (%d>%d)", ap->name, j, n);
163                         if ((i = read(ap->io.fd, buf, j)) != j)
164                                 error(2, "%s: blokread blocking error", ap->name);
165                 }
166                 else i = 0;
167         }
168         else i = read(ap->io.fd, buf, n);
169         return(i);
170 }
171
172 static int
173 blokwrite __PARAM__((register Archive_t* ap, char* buf, int n), (ap, buf, n)) __OTORP__(register Archive_t* ap; char* buf; int n;){
174         register char*  s;
175         register int    i;
176         register int    j;
177         char            blk[9];
178
179         if (ap->io.blok)
180         {
181                 s = blk;
182                 if (!ap->io.blokflag)
183                 {
184                         ap->io.blokflag = 1;
185                         *s++ = 002;
186                         *s++ = 014;
187                         *s++ = 017;
188                         *s++ = 013;
189                 }
190                 i = 0;
191                 if (j = (n >> 21) & 0177)
192                 {
193                         *s++ = j | 0200;
194                         i = 1;
195                 }
196                 if ((j = (n >> 14) & 0177) || i)
197                 {
198                         *s++ = j | 0200;
199                         i = 1;
200                 }
201                 if ((j = (n >> 7) & 0177) || i)
202                 {
203                         *s++ = j | 0200;
204                         i = 1;
205                 }
206                 *s++ = n & 0177;
207                 j = s - blk;
208                 if ((i = write(ap->io.fd, blk, j)) != j)
209                         error(ERROR_SYSTEM|3, "%s: blokwrite count write error (%d!=%d)", ap->name, i, j);
210                 if (n <= 0) i = n;
211                 else if ((i = write(ap->io.fd, buf, n)) != n)
212                         error(ERROR_SYSTEM|3, "%s: blokwrite data write error (%d!=%d", ap->name, i, n);
213         }
214         else i = write(ap->io.fd, buf, n);
215         return(i);
216 }
217
218 #define read(f,b,n)     blokread(f,b,n)
219 #define write(f,b,n)    blokwrite(f,b,n)
220
221 #endif
222
223 /*
224  * initialize buffered io
225  */
226
227 void
228 binit __PARAM__((register Archive_t* ap), (ap)) __OTORP__(register Archive_t* ap;){
229         unsigned long   n;
230
231         if (ap->delta)
232                 ap->delta->hdr = ap->delta->hdrbuf;
233         n = 2 * state.buffersize;
234         if (!(ap->io.mode & O_WRONLY))
235                 n += MAXUNREAD;
236         else if (!(format[ap->format].flags & OUT))
237                 error(3, "%s: archive format not supported on output" , format[ap->format].name);
238         if (!(ap->io.buffer = newof(0, char, n, 0)))
239                 error(3, "%s: cannot allocate buffer", ap->name);
240         ap->io.next = ap->io.last = ap->io.buffer;
241 }
242
243 /*
244  * skip files on tape fd
245  */
246
247 int
248 bskip __PARAM__((register Archive_t* ap), (ap)) __OTORP__(register Archive_t* ap;){
249         long            c;
250         int             skip = ap->io.skip;
251 #ifdef MTIOCTOP
252         struct mtop     mt;
253 #ifdef MTEOM
254         int             mteom = 1;
255 #endif
256 #ifdef MTFSF
257         int             mtfsf = 1;
258 #endif
259 #endif
260
261         if (ap->io.mode)
262         {
263                 ap->io.next = ap->io.last = ap->io.buffer + MAXUNREAD;
264                 ap->io.eof = 0;
265         }
266         while (skip)
267         {
268 #ifdef MTIOCTOP
269 #ifdef MTEOM
270                 if (skip < 0 && mteom)
271                 {
272                         mt.mt_op = MTEOM;
273                         mt.mt_count = 1;
274                         if (ioctl(ap->io.fd, MTIOCTOP, &mt) >= 0)
275                         {
276                                 if (ap->io.mode) ap->io.eof = 1;
277                                 break;
278                         }
279                         mteom = 0;
280                 }
281 #endif
282 #ifdef MTFSF
283                 if (mtfsf)
284                 {
285                         mt.mt_op = MTFSF;
286                         mt.mt_count = 1;
287                         if (ioctl(ap->io.fd, MTIOCTOP, &mt) >= 0)
288                         {
289                                 skip--;
290                                 continue;
291                         }
292                         if (errno != ENOTTY)
293                         {
294                                 if (ap->io.mode) ap->io.eof = 1;
295                                 break;
296                         }
297                         mtfsf = 0;
298                 }
299 #endif
300 #endif
301                 while ((c = read(ap->io.fd, state.tmp.buffer, state.tmp.buffersize)) > 0);
302                 if (c < 0)
303                 {
304                         if (ap->io.mode) ap->io.eof = 1;
305                         break;
306                 }
307                 skip--;
308         }
309         return(0);
310 }
311
312 /*
313  * fill input buffer at ap->io.last
314  * if must!=0 then EOF causes query for next input volume file
315  */
316
317 static int
318 bfill __PARAM__((register Archive_t* ap, int must), (ap, must)) __OTORP__(register Archive_t* ap; int must;){
319         register int    c;
320
321         if (ap->io.eof) return(-1);
322         if (ap->io.skip) ap->io.skip = bskip(ap);
323         while ((c = read(ap->io.fd, ap->io.last, state.buffersize)) <= 0)
324         {
325                 if (must) newio(ap, c, 0);
326                 else
327                 {
328                         ap->io.eof = 1;
329                         return(-1);
330                 }
331         }
332         message((-8, "read(%s,%d): %-.*s%s", ap->name, c, c > 32 ? 32 : c, ap->io.last, c > 32 ? "..." : ""));
333         ap->io.eof = 0;
334         ap->io.last += c;
335         return(0);
336 }
337
338 /*
339  * buffered char input
340  * at least n chars required, m chars max
341  * if b is 0 then n chars are skipped
342  * if must!=0 then EOF causes query for next input volume file
343  */
344
345 int
346 bread __PARAM__((register Archive_t* ap, __V_* ab, register long n, long m, int must), (ap, ab, n, m, must)) __OTORP__(register Archive_t* ap; __V_* ab; register long n; long m; int must;){
347         register char*  b = (char*)ab;
348         register int    c;
349         register char*  ob;
350
351         if (ap->io.eof) return(-1);
352         if (m <= 0) return(0);
353         ob = b;
354         if (ap->io.blocked)
355         {
356                 if (!b) b = state.tmp.buffer;
357                 while ((c = read(ap->io.fd, b, m)) <= 0)
358                 {
359                         if (must) newio(ap, c, 0);
360                         else if (ap->io.empty)
361                         {
362                                 ap->io.eof = 1;
363                                 return(-1);
364                         }
365                         else
366                         {
367                                 if (c < 0) ap->io.eof = 1;
368                                 else
369                                 {
370                                         ap->io.empty = 1;
371 #if DEBUG
372                                         if (ob) message((-7, "bread(%s,%d@%ld):", ap->name, c, ap->io.count));
373 #endif
374                                 }
375                                 return(c);
376                         }
377                 }
378                 ap->io.empty = 0;
379                 if (must && c < n) return(-1);
380                 ap->io.count += c;
381                 if (ap->sum > 0)
382                 {
383                         ap->memsum = memsum(b, c, ap->memsum);
384                         ap->old.memsum = omemsum(b, c, ap->old.memsum);
385                 }
386 #if DEBUG
387                 if (ob) message((-7, "bread(%s,%d@%ld): %-.*s%s", ap->name, c, ap->io.count, c > 32 ? 32 : c, ob, c > 32 ? "..." : ""));
388 #endif
389                 return(c);
390         }
391         else
392         {
393                 if (n <= 0) n = m;
394                 else m = n;
395                 for (;;)
396                 {
397                         if (n > (c = ap->io.last - ap->io.next))
398                         {
399                                 if (c > 0)
400                                 {
401                                         if (ap->sum > 0)
402                                         {
403                                                 ap->memsum = memsum(ap->io.next, c, ap->memsum);
404                                                 ap->old.memsum = omemsum(ap->io.next, c, ap->old.memsum);
405                                         }
406                                         if (ob) memcpy(b, ap->io.next, c);
407                                         b += c;
408                                         n -= c;
409                                         ap->io.count += c;
410                                 }
411                                 ap->io.next = ap->io.last = ap->io.buffer + MAXUNREAD;
412                                 if (!ob && ap->sum <= 0)
413                                 {
414                                         if (!ap->io.seekcheck)
415                                         {
416                                                 struct stat     st;
417
418                                                 ap->io.seekcheck = 1;
419                                                 if (lseek(ap->io.fd, 0L, SEEK_CUR) == (ap->io.count + ap->io.last - ap->io.next) && fstat(ap->io.fd, &st) != -1 && st.st_size > 0)
420                                                         ap->io.seekable = 1;
421                                         }
422                                         if (ap->io.seekable && (c = n / BUFFERSIZE) && lseek(ap->io.fd, (long)(c *= BUFFERSIZE), SEEK_CUR) != -1)
423                                         {
424                                                 b += c;
425                                                 n -= c;
426                                                 ap->io.count += c;
427                                                 message((-7, "bread(%s) skip(%d@%ld) [%ld]", ap->name, c, ap->io.count));
428                                         }
429                                 }
430                                 if (bfill(ap, must) < 0)
431                                 {
432                                         if (ob && (c = (b - ob)))
433                                         {
434                                                 bunread(ap, ob, c);
435                                                 return(0);
436                                         }
437                                         return(-1);
438                                 }
439                         }
440                         else
441                         {
442                                 if (ap->sum > 0)
443                                 {
444                                         ap->memsum = memsum(ap->io.next, n, ap->memsum);
445                                         ap->old.memsum = omemsum(ap->io.next, n, ap->old.memsum);
446                                 }
447                                 if (ob) memcpy(b, ap->io.next, n);
448                                 ap->io.next += n;
449                                 ap->io.count += n;
450 #if DEBUG
451                                 if (ob)
452                                 {
453                                         n += b - ob;
454                                         message((-7, "bread(%s,%d@%ld): %-.*s%s", ap->name, n, ap->io.count, n > 32 ? 32 : n, ob, n > 32 ? "..." : ""));
455                                 }
456 #endif
457                                 return(m);
458                         }
459                 }
460         }
461 }
462
463 /*
464  * pushback for next bread()
465  */
466
467 void
468 bunread __PARAM__((register Archive_t* ap, __V_* ab, register int n), (ap, ab, n)) __OTORP__(register Archive_t* ap; __V_* ab; register int n;){
469         register char*  b = (char*)ab;
470
471         ap->io.eof = 0;
472         ap->io.count -= n;
473         if ((ap->io.next -= n) < ap->io.buffer + MAXUNREAD)
474         {
475                 if (ap->io.next < ap->io.buffer)
476                         error(PANIC, "bunread(%s,%d): too much pushback", ap->name, n);
477                 memcpy(ap->io.next, b, n);
478         }
479         message((-7, "bunread(%s,%d@%ld): %-.*s%s", ap->name, n, ap->io.count, n > 32 ? 32 : n, b, n > 32 ? "..." : ""));
480 }
481
482 /*
483  * bread() n chars and return a pointer to the char buffer
484  */
485
486 char*
487 bget __PARAM__((register Archive_t* ap, register int n), (ap, n)) __OTORP__(register Archive_t* ap; register int n;){
488         register char*  s;
489
490         ap->io.count += n;
491         s = ap->io.next;
492         ap->io.next += n;
493         while (ap->io.next > ap->io.last)
494         {
495                 if (ap->io.last > ap->io.buffer + MAXUNREAD + state.buffersize)
496                 {
497                         register char*  b;
498                         register int    k;
499                         register int    m;
500
501                         k = ap->io.last - s;
502                         m = roundof(k, IOALIGN) - k;
503 #if DEBUG
504                         if (m) message((-8, "bget(%s) buffer alignment offset=%d", ap->name, m));
505 #endif
506                         b = ap->io.next = ap->io.buffer + MAXUNREAD + m;
507                         ap->io.last = b + k;
508                         m = s - b;
509                         while (k > m)
510                         {
511                                 message((-8, "bget(%s) overlapping memcpy n=%d k=%d m=%d", ap->name, n, k, m));
512                                 memcpy(b, s, m);
513                                 b += m;
514                                 s += m;
515                                 k -= m;
516                         }
517                         memcpy(b, s, k);
518                         s = ap->io.next;
519                         ap->io.next += n;
520                 }
521                 if (bfill(ap, 1) < 0) return(0);
522         }
523         if (ap->sum > 0)
524         {
525                 ap->memsum = memsum(s, n, ap->memsum);
526                 ap->old.memsum = omemsum(s, n, ap->old.memsum);
527         }
528         message((-7, "bget(%s,%d@%ld): %-.*s%s", ap->name, n, ap->io.count, n > 32 ? 32 : n, s, n > 32 ? "..." : ""));
529         return(s);
530 }
531
532 /*
533  * back up input to bsave()'d position and prime output buffer
534  */
535
536 void
537 backup __PARAM__((register Archive_t* ap), (ap)) __OTORP__(register Archive_t* ap;){
538         register long   n;
539         register long   m;
540 #ifdef MTIOCTOP
541         struct mtop     mt;
542 #endif
543
544         switch (ap->format)
545         {
546         case ALAR:
547         case IBMAR:
548 #ifdef MTIOCTOP
549                 mt.mt_op = MTBSF;
550                 mt.mt_count = 1;
551                 if (!(ioctl(ap->io.fd, MTIOCTOP, &mt))) return;
552 #endif
553                 break;
554         default:
555                 m = ap->io.next - (ap->io.buffer + MAXUNREAD);
556                 if ((n = ap->io.count - m) > state.backup.count)
557                 {
558                         message((-1, "backup(%s): reread %ld", ap->name, n + m));
559                         m = state.backup.last - (state.backup.buffer + MAXUNREAD);
560                         if (lseek(ap->io.fd, -(n + m), SEEK_CUR) == -1L)
561                         {
562 #ifdef MTIOCTOP
563                                 mt.mt_op = MTBSR;
564                                 mt.mt_count = 2;
565                                 if (ioctl(ap->io.fd, MTIOCTOP, &mt)) break;
566 #else
567                                 break;
568 #endif
569                         }
570                         if (read(ap->io.fd, ap->io.buffer + MAXUNREAD, m) != m) break;
571                 }
572                 else m = ap->io.last - (ap->io.buffer + MAXUNREAD);
573                 message((-1, "backup(%s): %ld", ap->name, m));
574                 if ((m = lseek(ap->io.fd, -m, SEEK_CUR)) == -1L)
575                 {
576 #ifdef MTIOCTOP
577                         mt.mt_op = MTBSR;
578                         mt.mt_count = 1;
579                         if (ioctl(ap->io.fd, MTIOCTOP, &mt)) break;
580 #else
581                         break;
582 #endif
583                 }
584                 if (state.backup.next < state.backup.last)
585                         bwrite(ap, ap->io.buffer + MAXUNREAD, state.backup.next - (state.backup.buffer + MAXUNREAD));
586                 return;
587         }
588         error(3, "%s: cannot position %s archive for append", ap->name, format[ap->format].name);
589 }
590
591 /*
592  * flush buffered input
593  */
594
595 void
596 bflushin __PARAM__((register Archive_t* ap), (ap)) __OTORP__(register Archive_t* ap;){
597         ap->io.count += ap->io.last - ap->io.next;
598         ap->io.next = ap->io.last = ap->io.buffer + MAXUNREAD;
599         if (!ap->io.eof)
600         {
601                 while (read(ap->io.fd, state.tmp.buffer, state.buffersize) > 0);
602                 ap->io.eof = 1;
603         }
604 }
605
606 /*
607  * rudimentary buffered seek -- force re-read
608  */
609
610 off_t
611 bseek __PARAM__((register Archive_t* ap, off_t pos, int op), (ap, pos, op)) __OTORP__(register Archive_t* ap; off_t pos; int op;){
612         ap->io.next = ap->io.last = ap->io.buffer + MAXUNREAD;
613         if ((pos = lseek(ap->io.fd, pos, op)) >= 0)
614         {
615                 ap->io.empty = 0;
616                 ap->io.eof = 0;
617                 ap->io.count = pos - ap->io.offset;
618         }
619         return(pos);
620 }
621
622 /*
623  * flush buffered output
624  */
625
626 void
627 bflushout __PARAM__((register Archive_t* ap), (ap)) __OTORP__(register Archive_t* ap;){
628         register int    n;
629         register int    c;
630
631         if (n = ap->io.next - ap->io.buffer)
632         {
633                 ap->io.next = ap->io.buffer;
634                 while ((c = write(ap->io.fd, ap->io.next, n)) != n)
635                 {
636                         if (c <= 0) newio(ap, c, n);
637                         else
638                         {
639                                 ap->io.next += c;
640                                 n -= c;
641                         }
642                 }
643                 ap->io.next = ap->io.buffer;
644         }
645 }
646
647 /*
648  * buffered output
649  */
650
651 void
652 bwrite __PARAM__((register Archive_t* ap, __V_* ab, register int n), (ap, ab, n)) __OTORP__(register Archive_t* ap; __V_* ab; register int n;){
653         register char*  b = (char*)ab;
654         register int    c;
655
656         if (ap->sum > 0)
657                 ap->memsum = memsum(b, n, ap->memsum);
658         if (ap->io.skip)
659                 ap->io.skip = bskip(ap);
660         if (state.maxout && ap->io.count >= state.maxout)
661         {
662                 bflushout(ap);
663                 newio(ap, 0, 0);
664         }
665         ap->io.count += n;
666         if (ap->io.blocked)
667         {
668 #if DEBUG
669                 if (n > 0) message((-7, "bwrite(%s,%d@%ld): %-.*s...", ap->name, n, ap->io.count + n, n > 32 ? 32 : n, b));
670                 else message((-7, "bwrite(%s,%d@%ld):", ap->name, n, ap->io.count + n));
671 #endif
672                 while ((c = write(ap->io.fd, b, n)) != n)
673                 {
674                         if (n <= 0)
675                         {
676 #ifdef MTIOCTOP
677                                 {
678                                         struct mtop     mt;
679
680                                         mt.mt_op = MTWEOF;
681                                         mt.mt_count = 1;
682                                         if (ioctl(ap->io.fd, MTIOCTOP, &mt) >= 0) break;
683                                 }
684 #endif
685                                 error(3, "%s: cannot write tape EOF marks", ap->name);
686                         }
687                         if (c <= 0) newio(ap, c, n);
688                         else if ((n -= c) > 0) b += c;
689                         else break;
690                 }
691         }
692         else
693         {
694 #if DEBUG
695                 if (n > 0) message((-7, "bwrite(%s,%d@%ld): %-.*s...", ap->name, n, ap->io.count + n, n > 32 ? 32 : n, b));
696                 else message((-7, "bwrite(%s,%d@%ld):", ap->name, n, ap->io.count + n));
697 #endif
698                 for (;;)
699                 {
700                         if ((c = ap->io.buffer + state.blocksize - ap->io.next) <= n)
701                         {
702                                 if (c)
703                                 {
704                                         memcpy(ap->io.next, b, c);
705                                         n -= c;
706                                         b += c;
707                                 }
708                                 ap->io.next = ap->io.buffer;
709                                 while ((c = write(ap->io.fd, ap->io.next, state.blocksize)) != state.blocksize)
710                                 {
711                                         if (c <= 0) newio(ap, c, n);
712                                         else
713                                         {
714                                                 memcpy(state.tmp.buffer, ap->io.buffer + c, state.blocksize - c);
715                                                 memcpy(ap->io.buffer, state.tmp.buffer, state.blocksize - c);
716                                                 ap->io.next = ap->io.buffer + state.blocksize - c;
717                                                 break;
718                                         }
719                                 }
720                                 message((-8, "write(%s,%d): %-.32s...", ap->name, c, ap->io.buffer));
721                         }
722                         else
723                         {
724                                 memcpy(ap->io.next, b, n);
725                                 ap->io.next += n;
726                                 break;
727                         }
728                 }
729         }
730 }
731
732 /*
733  * bwrite() n chars that have been placed in ap->io.next
734  */
735
736 void
737 bput __PARAM__((register Archive_t* ap, register int n), (ap, n)) __OTORP__(register Archive_t* ap; register int n;){
738         ap->io.count += n;
739         message((-7, "bput(%s,%d@%ld): %-.*s%s", ap->name, n, ap->io.count, n > 32 ? 32 : n, ap->io.next, n > 32 ? "..." : ""));
740         if (ap->sum > 0)
741                 ap->memsum = memsum(ap->io.next, n, ap->memsum);
742         if ((ap->io.next += n) > ap->io.buffer + state.blocksize)
743         {
744                 n = (ap->io.next - ap->io.buffer) - state.blocksize;
745                 ap->io.count -= n;
746
747                 /*
748                  * flush out the buffer and slide over the remains
749                  */
750
751                 ap->sum--;
752                 bwrite(ap, ap->io.next = ap->io.buffer + state.blocksize, n);
753                 ap->sum++;
754         }
755 }
756
757 static struct
758 {
759         char*           path;
760         struct stat*    st;
761 } dev;
762
763 /*
764  * find path name in /dev for <dev.st->st_dev,dev.st->st_ino>
765  * called by ftwalk()
766  */
767
768 static int
769 devpath __PARAM__((register Ftw_t* ftw), (ftw)) __OTORP__(register Ftw_t* ftw;){
770         if (ftw->info == FTW_F && ftw->statb.st_dev == dev.st->st_dev && ftw->statb.st_ino == dev.st->st_ino)
771         {
772                 message((-1, "device name is %s", ftw->path));
773                 dev.path = strdup(ftw->path);
774                 return(1);
775         }
776         return(0);
777 }
778
779 /*
780  * initilize tty file pointers for interactive prompting
781  */
782
783 void
784 interactive __PARAM__((void), ()){
785         int     fd;
786
787         if (!state.rtty)
788         {
789                 fd = dup(2);
790                 if (!(state.rtty = sfopen(NiL, "/dev/tty", "r")) || !(state.wtty = sfopen(NiL, "/dev/tty", "w")))
791                         error(ERROR_SYSTEM|3, "cannot prompt for interactive input");
792                 sfsetbuf(state.rtty, NiL, 0);
793                 sfsetbuf(state.wtty, NiL, 0);
794                 if (fd >= 0) close(fd);
795         }
796 }
797
798 /*
799  * check for new input or output stream
800  * c is the io count causing the newio()
801  * n is the pending buffered io count
802  */
803
804 void
805 newio __PARAM__((register Archive_t* ap, int c, int n), (ap, c, n)) __OTORP__(register Archive_t* ap; int c; int n;){
806         register char*  s;
807         register char*  rw;
808         char*           file;
809         char*           io;
810         char*           t;
811         int             vol;
812         long            z;
813         struct stat     st;
814
815         static int      locked;
816         static long     total;
817
818         vol = 0;
819         if (ap->io.mode)
820         {
821                 rw = "write";
822                 io = "output";
823                 ap->io.offset += ap->io.count - n;
824                 ap->io.count = n;
825                 z = ap->io.offset + ap->io.count;
826                 if (ap->io.blocked && state.record.file) switch (ap->format)
827                 {
828                 case ALAR:
829                 case IBMAR:
830                         if (locked) return;
831                         locked = 1;
832                         putlabels(ap, state.record.file, "EOV");
833                         locked = 0;
834                         vol = 1;
835                         break;
836                 }
837         }
838         else
839         {
840                 rw = "read";
841                 io = "input";
842                 z = ap->io.offset + ap->io.count;
843         }
844         if (fstat(ap->io.fd, &st) < 0)
845                 error(ERROR_SYSTEM|3, "%s: cannot stat %s", ap->name, io);
846         st.st_mode = modex(st.st_mode);
847         switch (X_ITYPE(st.st_mode))
848         {
849         case X_IFBLK:
850         case X_IFCHR:
851                 file = 0;
852                 break;
853         default:
854                 if (ap->io.mode) switch (c < 0 ? errno : 0)
855                 {
856                 case 0:
857 #ifdef EFBIG
858                 case EFBIG:
859 #endif
860 #ifdef EDQUOT
861                 case EDQUOT:
862 #endif
863                         file = "file";
864                         break;
865                 default:
866                         error(ERROR_SYSTEM|3, "%s: %s %s error -- cannot recover", ap->name, io, rw);
867                         break;
868                 }
869                 else file = "file";
870                 break;
871         }
872         switch (c < 0 ? errno : 0)
873         {
874         case 0:
875         case ENOSPC:
876         case ENXIO:
877                 error(1, "%s: end of %s medium", ap->name, io);
878                 break;
879         default:
880                 error(ERROR_SYSTEM|1, "%s: %s %s error", ap->name, io, rw);
881                 break;
882         }
883         if (total == z) error(1, "%s: no %s on part %d", ap->name, io, ap->part--);
884         else total = z;
885         if (!file && ap->name != definput && ap->name != defoutput)
886         {
887                 dev.path = 0;
888                 dev.st = &st;
889                 ftwalk("/dev", devpath, 0, NiL);
890                 ap->name = dev.path;
891         }
892         close(ap->io.fd);
893         if (file && ap->name != definput && ap->name != defoutput && strmatch(ap->name, "*.+([0-9])") && (s = strrchr(ap->name, '.')) && ((c = strtol(++s, NiL, 10)) == ap->part || c == (ap->part - 1)))
894         {
895                 if (ap->part == 1 && (!(ap->name = strdup(ap->name)) || !(s = strrchr(ap->name, '.'))))
896                         error(3, "out of space");
897                 s += strlen(s);
898                 while (*--s != '.')
899                 {
900                         if (*s < '9')
901                         {
902                                 (*s)++;
903                                 break;
904                         }
905                         *s = '0';
906                 }
907                 if (*s != '.')
908                 {
909                         if ((ap->io.fd = open(ap->name, ap->io.mode, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) >= 0)
910                         {
911                                 ap->part++;
912                                 error(1, "continuing %s %d %s on %s", ap->part == ap->volume + 1 ? "volume" : "part", ap->part, io, ap->name);
913                                 return;
914                         }
915                 }
916                 error(ERROR_SYSTEM|1, "%s: cannot %s", ap->name, rw);
917         }
918         if (file || ap->name == definput || ap->name == defoutput)
919         {
920                 for (;;)
921                 {
922                         interactive();
923                         sfputc(state.wtty, '\007');
924                         sfprintf(state.wtty, "Enter part %d %s %s name: ", ap->part + 1, io, file ? file : "device");
925                         if (!(s = sfgetr(state.rtty, '\n', 1)))
926                         {
927                                 sfputc(state.wtty, '\n');
928                                 finish(2);
929                         }
930                         if (*s)
931                         {
932                                 if (!file) break;
933                                 if ((ap->io.fd = open(s, ap->io.mode, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) >= 0) break;
934                                 error(ERROR_SYSTEM|1, "%s: cannot open", s);
935                         }
936                 }
937                 ap->name = strdup(s);
938         }
939         if (!file)
940         {
941                 for (;;)
942                 {
943                         interactive();
944                         sfputc(state.wtty, '\007');
945                         sfprintf(state.wtty, eomprompt, ap->part + 1);
946                         if (!(s = sfgetr(state.rtty, '\n', 1)))
947                         {
948                                 sfputc(state.wtty, '\n');
949                                 finish(2);
950                         }
951                         if (*s == '!')
952                         {
953                                 static char*    last;
954
955                                 if (*++s)
956                                 {
957                                         if (last) free(last);
958                                         last = strdup(s);
959                                 }
960                                 else s = last;
961                                 if (!s) error(1, "no previous command");
962                                 else if (n = system(s)) error(1, "exit status %d", n);
963                         }
964                         else
965                         {
966                                 file = *s ? s : ap->name;
967                                 if ((ap->io.fd = open(file, ap->io.mode)) >= 0) break;
968                                 file = strtape(file, &t);
969                                 if (!*t && (ap->io.fd = open(file, ap->io.mode)) >= 0) break;
970                                 error(ERROR_SYSTEM|1, "cannot %s %s", rw, *s ? s : ap->name);
971                         }
972                 }
973                 if (ap->name != file) ap->name = strdup(file);
974         }
975         ap->part++;
976         if (vol && !locked)
977         {
978                 locked = 1;
979                 putprologue(ap);
980                 putlabels(ap, state.record.file, "HDR");
981                 locked = 0;
982         }
983 }