Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/pax/bio.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1987-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Bell Laboratories
24
*
25
* pax block io support
26
*/
27
28
#include "pax.h"
29
30
#define show(s,n) fmtquote(s,NiL,NiL,(n)>64?64:(n),0)
31
32
#if _sys_mtio
33
#include <ast_tty.h>
34
#include <sys/mtio.h>
35
#if _sys_ioctl
36
#include <sys/ioctl.h>
37
#endif
38
#endif
39
#ifdef MTIOCTOP
40
#if defined(MTIOBSF) && !defined(MTBSF)
41
#define MTBSF MTIOBSF
42
#endif
43
#if defined(MTIOBSR) && !defined(MTBSR)
44
#define MTBSR MTIOBSR
45
#endif
46
#if defined(MTIOEOM) && !defined(MTEOM)
47
#define MTEOM MTIOEOM
48
#endif
49
#if defined(MTIOFSF) && !defined(MTFSF)
50
#define MTFSF MTIOFSF
51
#endif
52
#if defined(MTIOWEOF) && !defined(MTWEOF)
53
#define MTWEOF MTIOWEOF
54
#endif
55
#if !defined(MTBSF) || !defined(MTBSR) || !defined(MTWEOF) || defined(__hppa)/*hppa-compiler-signal-10*/
56
#undef MTIOCTOP
57
#endif
58
#endif
59
60
#define CVT(a,b,c,m,t) \
61
do \
62
{ \
63
if (c) \
64
switch ((a)->convert[SECTION(a)].on) \
65
{ \
66
case 1: \
67
if (state.forceconvert || SECTION(a) != SECTION_DATA || TEXT(b,c,t)) \
68
(a)->convert[SECTION(a)].on = 2; \
69
else \
70
{ \
71
(a)->convert[SECTION(a)].on = 0; \
72
break; \
73
} \
74
case 2: \
75
ccmapstr(m, b, c); \
76
break; \
77
} \
78
if ((a)->swapio) \
79
swapmem((a)->swapio, b, b, c); \
80
} while (0)
81
82
#define TEXT(b,c,t) text(t,(unsigned char*)b,c)
83
84
#define CONVERT(a,b,c) CVT(a,b,c,(a)->convert[SECTION(a)].f2t,(a)->convert[SECTION(a)].f2a)
85
#define REVERT(a,b,c) CVT(a,b,c,(a)->convert[SECTION(a)].t2f,(a)->convert[SECTION(a)].t2a)
86
87
/*
88
* return 1 if b is text data in f charset
89
*/
90
91
static const unsigned char ascii_text[] =
92
{
93
0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
94
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
95
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
96
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
97
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
98
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
99
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
100
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
101
};
102
103
static int
104
text(unsigned char* map, register unsigned char* b, ssize_t n)
105
{
106
register unsigned char* e;
107
register int c;
108
109
if (n > 256)
110
n = 256;
111
e = b + n;
112
while (b < e)
113
{
114
c = *b++;
115
c = ccmapchr(map, c);
116
if (!ascii_text[c])
117
return 0;
118
}
119
return 1;
120
}
121
122
#if 0 && DEBUG
123
124
/*
125
* --blok=i input is BLOK file
126
* --blok=o output file is BLOK file
127
*/
128
129
static int
130
blokread(register Archive_t* ap, char* buf, int n)
131
{
132
register int i;
133
register int j;
134
char c;
135
136
if (!ap->io->blokflag)
137
{
138
ap->io->blokeof = 0;
139
ap->io->blokflag = 1;
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)
143
error(3, "%s: input archive is not a BLOK file", ap->name);
144
return i;
145
}
146
if (i > 4 && lseek(ap->io->fd, (off_t)4, SEEK_SET) != 4)
147
error(3, "%s: cannot seek on input archive BLOK file -- use --blok=i", ap->name);
148
ap->io->blok = 1;
149
}
150
if (ap->io->blok)
151
{
152
j = 0;
153
do
154
{
155
if ((i = read(ap->io->fd, &c, 1)) < 1)
156
{
157
if (!i)
158
return 0;
159
if (!ap->io->blokeof)
160
{
161
ap->io->blokeof = 1;
162
return 0;
163
}
164
return -1;
165
}
166
j <<= 7;
167
j |= c & 0177;
168
} while (c & 0200);
169
if (j > 0)
170
{
171
if (j > n)
172
error(2, "%s: blokread buffer overflow (%d>%d)", ap->name, j, n);
173
if ((i = read(ap->io->fd, buf, j)) != j)
174
error(2, "%s: blokread blocking error", ap->name);
175
}
176
else
177
i = 0;
178
}
179
else
180
i = read(ap->io->fd, buf, n);
181
return i;
182
}
183
184
static int
185
blokwrite(register Archive_t* ap, char* buf, int n)
186
{
187
register char* s;
188
register int i;
189
register int j;
190
char blk[9];
191
192
if (ap->io->blok)
193
{
194
s = blk;
195
if (!ap->io->blokflag)
196
{
197
ap->io->blokflag = 1;
198
*s++ = 002;
199
*s++ = 014;
200
*s++ = 017;
201
*s++ = 013;
202
}
203
i = 0;
204
if (j = (n >> 21) & 0177)
205
{
206
*s++ = j | 0200;
207
i = 1;
208
}
209
if ((j = (n >> 14) & 0177) || i)
210
{
211
*s++ = j | 0200;
212
i = 1;
213
}
214
if ((j = (n >> 7) & 0177) || i)
215
{
216
*s++ = j | 0200;
217
i = 1;
218
}
219
*s++ = n & 0177;
220
j = s - blk;
221
if ((i = write(ap->io->fd, blk, j)) != j)
222
error(ERROR_SYSTEM|3, "%s: blokwrite count write error (%d!=%d)", ap->name, i, j);
223
if (n <= 0)
224
i = n;
225
else if ((i = write(ap->io->fd, buf, n)) != n)
226
error(ERROR_SYSTEM|3, "%s: blokwrite data write error (%d!=%d", ap->name, i, n);
227
}
228
else
229
i = write(ap->io->fd, buf, n);
230
return i;
231
}
232
233
#define read(f,b,n) blokread(f,b,n)
234
#define write(f,b,n) blokwrite(f,b,n)
235
236
#endif
237
238
#if 0
239
240
static ssize_t
241
ewrite(int f, void* b, size_t n)
242
{
243
static int count = 1;
244
245
if (!count)
246
{
247
sfprintf(sfstderr, "AHA ENOSPC\n");
248
errno = ENOSPC;
249
return -1;
250
}
251
count--;
252
return write(f, b, n);
253
}
254
255
#undef write
256
#define write(f,b,n) ewrite(f,b,n)
257
258
#endif
259
260
static char*
261
bstatus(Bio_t* io)
262
{
263
char* s;
264
265
s = sfprints("<%p,%d,%d,%I*d,%d,%d>", io->buffer, io->unread, io->fill, sizeof(io->count), io->count, io->next - (io->buffer + io->unread), io->last - (io->buffer + io->unread));
266
return strcpy(fmtbuf(strlen(s) + 1), s);
267
}
268
269
/*
270
* initialize buffered io
271
*/
272
273
void
274
binit(register Archive_t* ap)
275
{
276
unsigned long n;
277
unsigned long u;
278
279
if (ap->io->buffer)
280
return;
281
if (ap->delta)
282
ap->delta->hdr = ap->delta->hdrbuf;
283
ap->io->buffersize = state.buffersize;
284
n = 2 * state.buffersize;
285
if ((ap->io->mode & O_ACCMODE) != O_WRONLY)
286
u = MAXUNREAD;
287
else if (!(ap->format->flags & OUT))
288
error(3, "%s: archive format not supported on output" , ap->format->name);
289
else
290
u = 0;
291
if (!(ap->io->buffer = newof(0, char, n, u)))
292
error(3, "%s: cannot allocate buffer", ap->name);
293
ap->io->unread = u;
294
ap->io->next = ap->io->last = ap->io->buffer + u;
295
message((-7, "binit(%s) %s", ap->name, bstatus(ap->io)));
296
}
297
298
/*
299
* skip files on tape fd
300
*/
301
302
int
303
bskip(register Archive_t* ap)
304
{
305
long c;
306
int skip = ap->io->skip;
307
#ifdef MTIOCTOP
308
struct mtop mt;
309
#ifdef MTEOM
310
int mteom = 1;
311
#endif
312
#ifdef MTFSF
313
int mtfsf = 1;
314
#endif
315
#endif
316
317
if (ap->io->mode != O_RDONLY)
318
{
319
ap->io->next = ap->io->last = ap->io->buffer + ap->io->unread;
320
ap->io->eof = 0;
321
}
322
while (skip)
323
{
324
#ifdef MTIOCTOP
325
#ifdef MTEOM
326
if (skip < 0 && mteom)
327
{
328
mt.mt_op = MTEOM;
329
mt.mt_count = 1;
330
if (ioctl(ap->io->fd, MTIOCTOP, &mt) >= 0)
331
{
332
if (ap->io->mode != O_RDONLY)
333
ap->io->eof = 1;
334
break;
335
}
336
mteom = 0;
337
}
338
#endif
339
#ifdef MTFSF
340
if (mtfsf)
341
{
342
mt.mt_op = MTFSF;
343
mt.mt_count = 1;
344
if (ioctl(ap->io->fd, MTIOCTOP, &mt) >= 0)
345
{
346
skip--;
347
continue;
348
}
349
if (errno != ENOTTY)
350
{
351
if (ap->io->mode != O_RDONLY)
352
ap->io->eof = 1;
353
break;
354
}
355
mtfsf = 0;
356
}
357
#endif
358
#endif
359
while ((c = read(ap->io->fd, state.tmp.buffer, state.tmp.buffersize)) > 0);
360
if (c < 0)
361
{
362
if (ap->io->mode != O_RDONLY)
363
ap->io->eof = 1;
364
break;
365
}
366
skip--;
367
}
368
return 0;
369
}
370
371
/*
372
* fill input buffer at ap->io->last
373
* if must!=0 then EOF causes query for next input volume file
374
*/
375
376
static int
377
bfill(register Archive_t* ap, int must)
378
{
379
register int c;
380
381
if (ap->io->eof)
382
return -1;
383
if (ap->io->skip)
384
ap->io->skip = bskip(ap);
385
while ((c = read(ap->io->fd, ap->io->last, ap->io->buffersize)) <= 0)
386
{
387
if (must)
388
newio(ap, c, 0);
389
else
390
{
391
ap->io->eof = 1;
392
return -1;
393
}
394
}
395
message((-8, "read(%s,%d): %s", ap->name, c, show(ap->io->last, c)));
396
ap->io->eof = 0;
397
ap->io->last += c;
398
ap->io->fill++;
399
message((-7, "bfill(%s) %s", ap->name, bstatus(ap->io)));
400
return 0;
401
}
402
403
/*
404
* sum and convert a bread()/bget() chunk
405
*/
406
407
static void
408
chunk(register Archive_t* ap, char* t, char* f, register size_t n, char* o)
409
{
410
if (ap->sum > 0)
411
{
412
if (ap->flags & SUM)
413
FNVSUM(ap->memsum, f, n);
414
else
415
{
416
ap->memsum = memsum(f, n, ap->memsum);
417
ap->old.memsum = omemsum(f, n, ap->old.memsum);
418
}
419
}
420
if (o)
421
{
422
if (t != f)
423
memcpy(t, f, n);
424
CONVERT(ap, t, n);
425
}
426
}
427
428
/*
429
* buffered char input
430
* at least n chars required, m chars max
431
* if b is 0 then n chars are skipped
432
* if must!=0 then EOF causes query for next input volume file
433
*/
434
435
off_t
436
bread(register Archive_t* ap, void* ob, off_t n, off_t m, int must)
437
{
438
register char* s = (char*)ob;
439
register ssize_t c;
440
char* b;
441
register off_t r;
442
register off_t z;
443
444
if (ap->io->eof)
445
return -1;
446
if (ob)
447
message((-7, "bread(%s,%I*d,%I*d) %s", ap->name, sizeof(n), n, sizeof(m), m, bstatus(ap->io)));
448
if (m <= 0)
449
m = n;
450
b = s;
451
r = m;
452
if (ap->io->blocked)
453
{
454
if (!s)
455
b = s = state.tmp.buffer;
456
while ((c = read(ap->io->fd, s, r > ap->io->buffersize ? ap->io->buffersize : r)) <= 0)
457
{
458
if (must)
459
newio(ap, c, 0);
460
else if (ap->io->empty)
461
{
462
ap->io->eof = 1;
463
return -1;
464
}
465
else
466
{
467
if (c < 0)
468
ap->io->eof = 1;
469
else
470
ap->io->empty = 1;
471
break;
472
}
473
}
474
ap->io->empty = 0;
475
chunk(ap, s, s, c, ob);
476
s += c;
477
r -= c;
478
}
479
else
480
for (;;)
481
{
482
if ((c = ap->io->last - ap->io->next) < r)
483
{
484
if (c > 0)
485
{
486
if (ob)
487
memcpy(s, ap->io->next, c);
488
chunk(ap, s, ap->io->next, c, ob);
489
s += c;
490
r -= c;
491
}
492
ap->io->next = ap->io->last = ap->io->buffer + ap->io->unread;
493
if (!ob && ap->sum <= 0 && ap->io->seekable && (z = r / BUFFERSIZE) && lseek(ap->io->fd, z *= BUFFERSIZE, SEEK_CUR) >= 0)
494
{
495
s += z;
496
r -= z;
497
}
498
if (bfill(ap, must) < 0)
499
break;
500
}
501
else
502
{
503
chunk(ap, s, ap->io->next, r, ob);
504
ap->io->next += r;
505
s += r;
506
r = 0;
507
break;
508
}
509
}
510
ap->io->count += (r = m - r);
511
if (r < n)
512
{
513
if (ob && r)
514
{
515
bunread(ap, b, r);
516
return 0;
517
}
518
return -1;
519
}
520
#if DEBUG
521
if (ob)
522
message((-7, "bread(%s,%I*d@%I*d) %s: %s", ap->name, sizeof(r), r, sizeof(ap->io->count), ap->io->count, bstatus(ap->io), show(b, r)));
523
else
524
message((-7, "bread(%s) skip(%I*d@%I*d) %s", ap->name, sizeof(r), r, sizeof(ap->io->count), ap->io->count, bstatus(ap->io)));
525
#endif
526
return r;
527
}
528
529
/*
530
* pushback for next bread()
531
*/
532
533
void
534
bunread(register Archive_t* ap, void* b, register int n)
535
{
536
ap->io->eof = 0;
537
ap->io->count -= n;
538
if (ap->io->next == (ap->io->buffer + ap->io->unread))
539
ap->io->last = ap->io->next + n;
540
else if ((ap->io->next -= n) < ap->io->buffer + ap->io->unread)
541
{
542
if (ap->io->next < ap->io->buffer)
543
error(PANIC, "bunread(%s,%d): too much pushback", ap->name, n);
544
if (b)
545
memcpy(ap->io->next, b, n);
546
REVERT(ap, ap->io->next, n);
547
}
548
message((-7, "bunread(%s,%d@%I*d) %s: %s", ap->name, n, sizeof(ap->io->count), ap->io->count, bstatus(ap->io), show(ap->io->next, n)));
549
}
550
551
/*
552
* O_RDONLY bread() n chars and return a pointer to the char buffer
553
* O_WRONLY return output buffer pointer and available size
554
*/
555
556
char*
557
bget(register Archive_t* ap, register off_t n, off_t* p)
558
{
559
register char* b;
560
char* t;
561
size_t i;
562
size_t j;
563
size_t m;
564
int must;
565
566
if ((ap->io->mode & O_ACCMODE) == O_WRONLY)
567
{
568
if (p)
569
*p = ap->io->last - ap->io->next;
570
return ap->io->next;
571
}
572
if (n < 0)
573
{
574
n = -n;
575
must = 0;
576
}
577
else if (n > 0)
578
must = 1;
579
else
580
{
581
if (!ap->io->eof && ap->io->seekable)
582
{
583
if (ap->io->last > ap->io->next)
584
n = ap->io->last - ap->io->next;
585
else if ((n = ap->io->size - (ap->io->offset + ap->io->count)) < 0)
586
n = 0;
587
else if (n > ap->io->buffersize)
588
n = ap->io->buffersize;
589
}
590
if (p)
591
*p = n;
592
return n ? ap->io->next : (char*)0;
593
}
594
if (n > ap->io->buffersize)
595
{
596
i = ap->io->next - ap->io->buffer;
597
j = ap->io->last - ap->io->buffer;
598
m = roundof(n, PAX_DEFBUFFER * PAX_BLOCK);
599
message((-8, "bget(%s,%I*d,%d): reallocate %u=>%d", ap->name, sizeof(n), n, must, ap->io->buffersize, m));
600
if (!(b = newof(ap->io->buffer, char, 2 * m, ap->io->unread)))
601
error(3, "%s: cannot reallocate buffer", ap->name);
602
ap->io->buffersize = m;
603
if (b != ap->io->buffer)
604
{
605
ap->io->buffer = b;
606
ap->io->next = b + i;
607
ap->io->last = b + j;
608
}
609
}
610
if (p)
611
*p = n;
612
b = ap->io->next;
613
ap->io->next += n;
614
while (ap->io->next > ap->io->last)
615
{
616
if (ap->io->last > ap->io->buffer + ap->io->unread + ap->io->buffersize)
617
{
618
i = ap->io->last - b;
619
j = roundof(i, IOALIGN) - i;
620
t = ap->io->next = ap->io->buffer + ap->io->unread + j;
621
ap->io->last = t + i;
622
if (m = b - t)
623
{
624
while (i > m)
625
{
626
message((-8, "bget(%s,%I*d,%d) overlapping memcpy n=%I*d i=%d m=%d next=%p last=%p", ap->name, sizeof(n), n, must, sizeof(n), n, i, m, ap->io->next + n, ap->io->last));
627
memcpy(t, b, m);
628
t += m;
629
b += m;
630
i -= m;
631
}
632
message((-8, "bget(%s,%I*d,%d): slide %u align %u", ap->name, sizeof(n), n, must, i, j));
633
memcpy(t, b, i);
634
}
635
b = ap->io->next;
636
ap->io->next += n;
637
}
638
if (bfill(ap, must) < 0)
639
return 0;
640
}
641
chunk(ap, b, b, n, b);
642
ap->io->count += n;
643
message((-7, "bget(%s,%I*d@%I*d,%d): %s", ap->name, sizeof(n), n, sizeof(ap->io->count), ap->io->count, must, show(b, n)));
644
return b;
645
}
646
647
#ifndef bsave
648
649
/*
650
* save current position for possible backup()
651
*/
652
653
void
654
bsave(register Archive_t* ap)
655
{
656
state.backup = *ap->io;
657
message((-7, "bsave(%s,@%I*d)", ap->name, sizeof(ap->io->count), ap->io->count));
658
}
659
660
#endif
661
662
/*
663
* back up input to bsave()'d position and prime output buffer
664
*/
665
666
void
667
backup(register Archive_t* ap)
668
{
669
register off_t n;
670
register off_t m;
671
#ifdef MTIOCTOP
672
struct mtop mt;
673
#endif
674
675
if (ap->format->backup)
676
(*ap->format->backup)(&state, ap);
677
else
678
{
679
message((-7, "backup(%s) old %s new %s", ap->name, bstatus(&state.backup), bstatus(ap->io)));
680
if (ap->io->fill == state.backup.fill)
681
{
682
/*
683
* same buffer window
684
*/
685
686
m = ap->io->last - (ap->io->buffer + ap->io->unread);
687
if ((n = lseek(ap->io->fd, -m, SEEK_CUR)) == -1)
688
{
689
#ifdef MTIOCTOP
690
mt.mt_op = MTBSR;
691
mt.mt_count = 1;
692
if (ioctl(ap->io->fd, MTIOCTOP, &mt))
693
goto bad;
694
#else
695
goto bad;
696
#endif
697
}
698
message((-7, "backup(%s) %I*d => %I*d", ap->name, sizeof(m), m, sizeof(n), n));
699
ap->io->count = state.backup.count;
700
ap->io->next = state.backup.next;
701
}
702
else
703
error(PANIC, "%s: backup over intervening hard read not implemented yet", ap->name);
704
ap->io->last = ap->io->buffer + ap->io->unread + state.blocksize;
705
message((-7, "backup(%s) %s", ap->name, bstatus(ap->io)));
706
}
707
return;
708
bad:
709
error(3, "%s: cannot position %s archive for append", ap->name, ap->format->name);
710
}
711
712
/*
713
* flush buffered input
714
*/
715
716
void
717
bflushin(register Archive_t* ap, int hard)
718
{
719
ap->io->count += ap->io->last - ap->io->next;
720
ap->io->next = ap->io->last = ap->io->buffer + ap->io->unread;
721
if (hard && !ap->io->eof)
722
{
723
while (read(ap->io->fd, ap->io->next, ap->io->buffersize) > 0);
724
ap->io->eof = 1;
725
}
726
}
727
728
/*
729
* buffered seek
730
*/
731
732
off_t
733
bseek(register Archive_t* ap, off_t pos, int op, int hard)
734
{
735
off_t l;
736
off_t u;
737
738
message((-8, "bseek(%s,%I*d,%d,%d)", ap->name, sizeof(pos), pos, op, hard));
739
if (hard)
740
{
741
if (op == SEEK_CUR)
742
return -1;
743
}
744
else
745
{
746
l = ap->io->next - (ap->io->buffer + ap->io->unread);
747
u = ap->io->last - ap->io->next;
748
if (op == SEEK_CUR)
749
{
750
if ((pos + ap->io->count) < 0)
751
return -1;
752
if (-pos <= l && pos <= u)
753
{
754
ap->io->next += pos;
755
return ap->io->count += pos;
756
}
757
pos += ap->io->count;
758
op = SEEK_SET;
759
}
760
else if (op != SEEK_SET || pos < 0)
761
return -1;
762
else if (-pos <= (l + ap->io->count) && pos <= (u + ap->io->count))
763
{
764
ap->io->next += (pos - ap->io->count);
765
return ap->io->count = pos;
766
}
767
}
768
ap->io->next = ap->io->last = ap->io->buffer + ap->io->unread;
769
message((-8, "lseek(%s,%I*d,%d)", ap->name, sizeof(pos), pos + ap->io->offset, op));
770
if ((u = lseek(ap->io->fd, ap->io->offset + pos, op)) < 0 && (op != SEEK_SET || (u = pos - ap->io->count) < 0 || u > 0 && bread(ap, NiL, u, u, 1) != u || !(u += ap->io->count + ap->io->offset)))
771
return -1;
772
ap->io->empty = 0;
773
ap->io->eof = 0;
774
return ap->io->count = u - ap->io->offset;
775
}
776
777
/*
778
* flush buffered output
779
*/
780
781
void
782
bflushout(register Archive_t* ap)
783
{
784
register int n;
785
register int c;
786
787
if (n = ap->io->next - (ap->io->buffer + ap->io->unread))
788
{
789
ap->io->next = ap->io->buffer + ap->io->unread;
790
while ((c = write(ap->io->fd, ap->io->next, n)) != n)
791
{
792
message((-8, "write(%s,%d): %s", ap->name, c, show(ap->io->next, c)));
793
if (c <= 0)
794
newio(ap, c, n);
795
else
796
{
797
ap->io->next += c;
798
n -= c;
799
}
800
}
801
message((-8, "write(%s,%d): %s", ap->name, c, show(ap->io->next, c)));
802
ap->io->next = ap->io->buffer + ap->io->unread;
803
}
804
message((-7, "bflushout(%s) %s", ap->name, bstatus(ap->io)));
805
}
806
807
/*
808
* buffered output
809
*/
810
811
void
812
bwrite(register Archive_t* ap, void* ab, register off_t n)
813
{
814
register char* b = (char*)ab;
815
register long c;
816
long an;
817
818
if (!ap->raw)
819
{
820
CONVERT(ap, b, n);
821
an = ap->convert[SECTION(ap)].on ? n : 0;
822
if (ap->sum > 0)
823
ap->memsum = memsum(b, n, ap->memsum);
824
if (state.checksum.sum && SECTION(ap) == SECTION_DATA)
825
sumblock(state.checksum.sum, b, n);
826
}
827
if (ap->io->skip)
828
ap->io->skip = bskip(ap);
829
if (state.maxout && ap->io->count >= state.maxout)
830
{
831
bflushout(ap);
832
newio(ap, 0, 0);
833
}
834
ap->io->count += n;
835
if (ap->io->blocked)
836
{
837
#if DEBUG
838
if (n > 0)
839
message((-7, "bwrite(%s,%I*d@%I*d): %s", ap->name, sizeof(n), n, sizeof(ap->io->count), ap->io->count + n, show(b, n)));
840
else
841
message((-7, "bwrite(%s,%I*d@%I*d):", ap->name, sizeof(n), n, sizeof(ap->io->count), ap->io->count + n));
842
#endif
843
while ((c = write(ap->io->fd, b, n)) != n)
844
{
845
if (n <= 0)
846
{
847
#ifdef MTIOCTOP
848
{
849
struct mtop mt;
850
851
mt.mt_op = MTWEOF;
852
mt.mt_count = 1;
853
if (ioctl(ap->io->fd, MTIOCTOP, &mt) >= 0)
854
break;
855
}
856
#endif
857
error(3, "%s: cannot write tape EOF marks", ap->name);
858
}
859
if (c <= 0)
860
newio(ap, c, n);
861
else if ((n -= c) > 0)
862
b += c;
863
else
864
break;
865
}
866
}
867
else
868
{
869
#if DEBUG
870
if (n > 0)
871
message((-7, "bwrite(%s,%I*d@%I*d): %s", ap->name, sizeof(n), n, sizeof(ap->io->count), ap->io->count + n, show(b, n)));
872
else
873
message((-7, "bwrite(%s,%I*d@%I*d):", ap->name, sizeof(n), n, sizeof(ap->io->count), ap->io->count + n));
874
#endif
875
for (;;)
876
{
877
if ((c = ap->io->buffer + ap->io->unread + state.blocksize - ap->io->next) <= n)
878
{
879
if (c)
880
{
881
memcpy(ap->io->next, b, c);
882
n -= c;
883
b += c;
884
}
885
ap->io->next = ap->io->buffer + ap->io->unread;
886
while ((c = write(ap->io->fd, ap->io->next, state.blocksize)) != state.blocksize)
887
{
888
if (c <= 0)
889
newio(ap, c, n);
890
else
891
{
892
memcpy(state.tmp.buffer, ap->io->buffer + ap->io->unread + c, state.blocksize - c);
893
memcpy(ap->io->buffer + ap->io->unread, state.tmp.buffer, state.blocksize - c);
894
ap->io->next = ap->io->buffer + ap->io->unread + state.blocksize - c;
895
break;
896
}
897
}
898
message((-8, "write(%s,%ld): %s", ap->name, c, show(ap->io->buffer + ap->io->unread, c)));
899
}
900
else
901
{
902
memcpy(ap->io->next, b, n);
903
ap->io->next += n;
904
break;
905
}
906
}
907
}
908
if (!ap->raw)
909
REVERT(ap, ab, an);
910
}
911
912
/*
913
* bwrite() n chars that have been placed in the
914
* buffer returned by a previous bget()
915
*/
916
917
void
918
bput(register Archive_t* ap, register off_t n)
919
{
920
ap->io->count += n;
921
message((-7, "bput(%s,%I*d@%I*d): %s", ap->name, sizeof(n), n, sizeof(ap->io->count), ap->io->count, show(ap->io->next, n)));
922
CONVERT(ap, ap->io->next, n);
923
if (ap->sum > 0)
924
ap->memsum = memsum(ap->io->next, n, ap->memsum);
925
if (state.checksum.sum && SECTION(ap) == SECTION_DATA)
926
sumblock(state.checksum.sum, ap->io->next, n);
927
if ((ap->io->next += n) > ap->io->buffer + ap->io->unread + state.blocksize)
928
{
929
n = (ap->io->next - (ap->io->buffer + ap->io->unread)) - state.blocksize;
930
ap->io->count -= n;
931
932
/*
933
* flush out the buffer and slide over the remains
934
*/
935
936
ap->raw++;
937
bwrite(ap, ap->io->next = ap->io->buffer + ap->io->unread + state.blocksize, n);
938
ap->raw--;
939
}
940
}
941
942
/*
943
* return recommended io block size for fd
944
* 0 returned for no recommendation
945
*/
946
947
long
948
bblock(int fd)
949
{
950
#ifdef MTIOCGETBLKINFO
951
struct mtblkinfo mt;
952
953
return ioctl(fd, MTIOCGETBLKINFO, &mt) < 0 ? 0 : mt.recblksz;
954
#else
955
return 0;
956
#endif
957
}
958
959
static struct
960
{
961
char* path;
962
struct stat* st;
963
} dev;
964
965
/*
966
* find path name in /dev for <dev.st->st_dev,dev.st->st_ino>
967
* called by ftwalk()
968
*/
969
970
static int
971
devpath(register Ftw_t* ftw)
972
{
973
if (ftw->info == FTW_F && ftw->statb.st_rdev == dev.st->st_rdev && S_ISCHR(ftw->statb.st_mode) == S_ISCHR(dev.st->st_mode))
974
{
975
message((-1, "device name is %s", ftw->path));
976
dev.path = strdup(ftw->path);
977
return 1;
978
}
979
return 0;
980
}
981
982
/*
983
* initilize tty file pointers for interactive prompting
984
*/
985
986
void
987
interactive(void)
988
{
989
int fd;
990
991
if (!state.rtty)
992
{
993
fd = dup(2);
994
if (!(state.rtty = sfopen(NiL, "/dev/tty", "r")) || !(state.wtty = sfopen(NiL, "/dev/tty", "w")))
995
error(ERROR_SYSTEM|3, "cannot prompt for interactive input");
996
sfsetbuf(state.rtty, NiL, 0);
997
sfsetbuf(state.wtty, NiL, 0);
998
if (fd >= 0)
999
close(fd);
1000
}
1001
}
1002
1003
/*
1004
* check for new input or output stream
1005
* c is the io count causing the newio()
1006
* n is the pending buffered io count
1007
*/
1008
1009
void
1010
newio(register Archive_t* ap, int c, int n)
1011
{
1012
register char* s;
1013
register char* rw;
1014
char* file;
1015
char* io;
1016
char* t;
1017
off_t z;
1018
int i;
1019
struct stat st;
1020
1021
Sfio_t* cp = 0;
1022
Sfio_t* pp = 0;
1023
int oerrno = errno;
1024
1025
if (!ap->part)
1026
ap->part++;
1027
if (ap->io->mode != O_RDONLY)
1028
{
1029
rw = "write";
1030
io = "output";
1031
ap->io->offset += ap->io->count - n;
1032
ap->io->count = n;
1033
z = ap->io->offset + ap->io->count;
1034
if (ap->format->putepilogue && (*ap->format->putepilogue)(&state, ap) < 0)
1035
return;
1036
}
1037
else
1038
{
1039
rw = "read";
1040
io = "input";
1041
z = ap->io->offset + ap->io->count;
1042
}
1043
if (fstat(ap->io->fd, &st) < 0)
1044
error(ERROR_SYSTEM|3, "%s: cannot stat %s", ap->name, io);
1045
errno = oerrno;
1046
switch (X_ITYPE(modex(st.st_mode)))
1047
{
1048
case X_IFBLK:
1049
case X_IFCHR:
1050
file = 0;
1051
break;
1052
default:
1053
if (ap->io->mode != O_RDONLY)
1054
switch (c < 0 ? errno : 0)
1055
{
1056
case 0:
1057
#ifdef EFBIG
1058
case EFBIG:
1059
#endif
1060
#ifdef EDQUOT
1061
case EDQUOT:
1062
#endif
1063
file = "file";
1064
break;
1065
default:
1066
error(ERROR_SYSTEM|3, "%s: %s %s error -- cannot recover", ap->name, io, rw);
1067
break;
1068
}
1069
else
1070
file = "file";
1071
break;
1072
}
1073
i = (eomprompt && *eomprompt == '!' && !*(eomprompt + 1)) ? 3 : 1;
1074
switch (c < 0 ? errno : 0)
1075
{
1076
case 0:
1077
case ENOSPC:
1078
case ENXIO:
1079
error(i, "%s: end of %s medium", ap->name, io);
1080
break;
1081
default:
1082
error(ERROR_SYSTEM|i, "%s: %s %s error", ap->name, io, rw);
1083
break;
1084
}
1085
if (ap->total == z)
1086
error(1, "%s: no %s on part %d", ap->name, io, ap->part--);
1087
else
1088
ap->total = z;
1089
if (!file && (ap->name == definput || ap->name == defoutput))
1090
{
1091
dev.path = 0;
1092
dev.st = &st;
1093
ftwalk("/dev", devpath, 0, NiL);
1094
ap->name = dev.path;
1095
}
1096
close(ap->io->fd);
1097
if (eomprompt && *eomprompt == '!')
1098
file = 0;
1099
if (file && ap->name != definput && ap->name != defoutput && strmatch(ap->name, "*.+([0-9])") && (s = strrchr(ap->name, '.')) && (int)strtol(++s, NiL, 10) == ap->part)
1100
{
1101
/*
1102
* the parts will be ap->name in sequence
1103
* the first part realloc the name with
1104
* enough sequence space
1105
*/
1106
1107
if (ap->part == 1)
1108
{
1109
c = s - ap->name;
1110
if (!(t = newof(0, char, s - ap->name, 16)))
1111
nospace();
1112
strcpy(t, ap->name);
1113
s = (ap->name = t) + c;
1114
}
1115
sfsprintf(s, 16, "%d", ap->part + 1);
1116
if ((ap->io->fd = open(ap->name, ap->io->mode|O_BINARY, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))) >= 0)
1117
goto nextpart;
1118
error(ERROR_SYSTEM|1, "%s: cannot %s", ap->name, rw);
1119
}
1120
if (state.test & 0000040)
1121
file = 0;
1122
else if (file || ap->name == definput || ap->name == defoutput)
1123
{
1124
for (;;)
1125
{
1126
interactive();
1127
sfputc(state.wtty, CC_bel);
1128
sfprintf(state.wtty, "Enter part %d %s %s name: ", ap->part + 1, io, file ? file : "device");
1129
if (!(s = sfgetr(state.rtty, '\n', 1)))
1130
{
1131
sfputc(state.wtty, '\n');
1132
finish(2);
1133
}
1134
if (*s)
1135
{
1136
if (!file)
1137
break;
1138
if ((ap->io->fd = open(s, ap->io->mode|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) >= 0)
1139
break;
1140
error(ERROR_SYSTEM|1, "%s: cannot open", s);
1141
}
1142
}
1143
ap->name = strdup(s);
1144
}
1145
if (!file)
1146
{
1147
for (;;)
1148
{
1149
if (eomprompt && *eomprompt == '!')
1150
{
1151
1152
if (!cp && !(cp = sfstropen()))
1153
nospace();
1154
sfprintf(cp, "%s %s %d", eomprompt + 1, rw, ap->part + 1);
1155
if (ap->name)
1156
sfprintf(cp, " %s", ap->name);
1157
if (!(s = sfstruse(cp)))
1158
nospace();
1159
s = (pp = sfpopen(pp, s, "r")) ? sfgetr(pp, '\n', 1) : (char*)0;
1160
}
1161
else
1162
{
1163
interactive();
1164
sfputc(state.wtty, CC_bel);
1165
if (eomprompt)
1166
sfprintf(state.wtty, eomprompt, ap->part + 1);
1167
if (!(s = sfgetr(state.rtty, '\n', 1)))
1168
sfputc(state.wtty, '\n');
1169
}
1170
if (!s)
1171
finish(2);
1172
if (*s == '!')
1173
{
1174
static char* last;
1175
1176
if (*++s)
1177
{
1178
if (last)
1179
free(last);
1180
last = strdup(s);
1181
}
1182
else
1183
s = last;
1184
if (!s)
1185
error(1, "no previous command");
1186
else if (n = system(s))
1187
error(1, "exit status %d", n);
1188
}
1189
else if (file = *s ? s : ap->name)
1190
{
1191
if ((ap->io->fd = open(file, ap->io->mode|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) >= 0)
1192
break;
1193
if (!strchr(file, '/'))
1194
{
1195
oerrno = errno;
1196
file = strtape(file, &t);
1197
if (!*t && (ap->io->fd = open(file, ap->io->mode|O_BINARY, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) >= 0)
1198
break;
1199
errno = oerrno;
1200
}
1201
error(ERROR_SYSTEM|1, "cannot %s %s", rw, *s ? s : ap->name);
1202
}
1203
else
1204
error(1, "pathname required");
1205
}
1206
if (ap->name != file)
1207
ap->name = strdup(file);
1208
if (cp)
1209
sfclose(cp);
1210
if (pp)
1211
sfclose(pp);
1212
nextpart:
1213
ap->part++;
1214
error(1, "continuing %s %d %s on %s", ap->part == ap->volume + 1 ? "volume" : "part", ap->part, io, ap->name);
1215
}
1216
else
1217
ap->part++;
1218
if (ap->format->putprologue)
1219
(*ap->format->putprologue)(&state, ap, 0);
1220
}
1221
1222