Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/pax/pax-slt.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1987-2011 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
/*
23
* pax slt format for ansi and ibm labeled tapes
24
*/
25
26
#include "format.h"
27
28
#include <tm.h>
29
30
#define ANSI 1
31
#define IBM 2
32
33
#define SLT_ID "slt"
34
#define LABEL_MAX 2048
35
#define HDR_SIZE 80
36
#define NAME_SIZE 17
37
#define VARHDR_SIZE 9
38
39
typedef struct Slt_s
40
{
41
unsigned char* mapin; /* input map */
42
unsigned char* mapout; /* output map */
43
char id[NAME_SIZE+1]; /* name id */
44
char volume[64]; /* volume id */
45
char format[7]; /* format id */
46
char implementation[8];/* implementation id */
47
char owner[15]; /* owner id */
48
char standards[20]; /* standards id */
49
int done; /* label read done */
50
int ibm; /* ibm format */
51
int peek; /* buf (size peek) already read */
52
int section; /* inside section */
53
int sequence; /* sequence number */
54
int vol; /* emit volume prologue */
55
char buf[LABEL_MAX]; /* header buffer */
56
char last[5]; /* last label */
57
} Slt_t;
58
59
/*
60
* get label header number
61
*/
62
63
static long
64
getlabnum(register char* p, int byte, int width, int base)
65
{
66
register char* e;
67
register int c;
68
long n;
69
70
p += byte - 1;
71
c = *(e = p + width);
72
*e = 0;
73
n = strtol(p, NiL, base);
74
*e = c;
75
return n;
76
}
77
78
/*
79
* get label header string
80
*/
81
82
static char*
83
getlabstr(register char* p, int byte, int width, register char* s)
84
{
85
86
register char* e;
87
char* v;
88
89
v = s;
90
p += byte - 1;
91
e = p + width;
92
while (p < e && (*s = *p++) != ' ')
93
s++;
94
*s = 0;
95
return v;
96
}
97
98
/*
99
* return length of next label
100
* variable length labels have label number > 3 and Vnnnn at position 5
101
* where nnnn is the decimal length of the entire label
102
* nnnn may be < HDR_SIZE but label block must be >= HDR_SIZE
103
* 0 returned at end of label group
104
*/
105
106
static int
107
getlabel(Pax_t* pax, register Archive_t* ap, register File_t* f)
108
{
109
register Slt_t* slt = (Slt_t*)ap->data;
110
register int c;
111
register int n;
112
113
if (c = slt->peek)
114
{
115
slt->peek = 0;
116
return c;
117
}
118
if (slt->done || (c = paxread(pax, ap, slt->buf, (off_t)HDR_SIZE, (off_t)LABEL_MAX, 0)) < HDR_SIZE)
119
return *slt->last = slt->done = c = 0;
120
if (slt->buf[4] == 'V' && ((n = getlabnum(slt->buf, 4, 1, 10)) < 1 || n > 3) && (n = getlabnum(slt->buf, 6, 4, 10)) != c)
121
{
122
if ((c = n - c) > 0)
123
{
124
if (ap->io->blocked || paxread(pax, ap, slt->buf + HDR_SIZE, (off_t)0, (off_t)c, 1) != c)
125
{
126
c = HDR_SIZE;
127
error(2, "%s: %-*.*s: variable length label record too short", f->name, c, c, slt->buf);
128
}
129
else
130
c = n;
131
}
132
else if (n <= VARHDR_SIZE)
133
c = VARHDR_SIZE;
134
else
135
c = n;
136
}
137
if (!ap->io->blocked && !*slt->last && slt->buf[3] == '2' && (strneq(slt->buf, "HDR", 3) || strneq(slt->buf, "EOF", 3) || strneq(slt->buf, "EOV", 3)))
138
getlabstr(slt->buf, 26, 4, slt->last);
139
if (*slt->last && strneq(slt->buf, slt->last, 4))
140
slt->done = 1;
141
message((-4, "label: %-*.*s", c, c, slt->buf));
142
return c;
143
}
144
145
/*
146
* output file HDR/EOF/EOV labels
147
*/
148
149
static void
150
putlabels(Pax_t* pax, register Archive_t* ap, register File_t* f, char* type)
151
{
152
register Slt_t* slt = (Slt_t*)ap->data;
153
struct tm* tm;
154
155
switch (*type)
156
{
157
case 'E':
158
paxwrite(pax, ap, slt->buf, 0);
159
break;
160
case 'H':
161
slt->sequence++;
162
break;
163
}
164
tm = gmtime(&f->st->st_mtime);
165
sfsprintf(slt->buf, sizeof(slt->buf), "%s1%-17.17s000001%04d%04d000100 %02d%03d 00000 %06d%-6.6sD%-7.7s ", type, f->id, slt->section, slt->sequence, tm->tm_year, tm->tm_yday, f->record.blocks, slt->format, slt->implementation);
166
paxwrite(pax, ap, slt->buf, HDR_SIZE);
167
sfsprintf(slt->buf, sizeof(slt->buf), "%s2%c%05d%05d%010d%s%c 00 ", type, state.record.format, state.blocksize, state.record.size, f->st->st_size, type, '2');
168
paxwrite(pax, ap, slt->buf, HDR_SIZE);
169
paxwrite(pax, ap, slt->buf, 0);
170
if (streq(type, "EOV"))
171
{
172
slt->section++;
173
slt->sequence = 0;
174
}
175
else
176
slt->section = 1;
177
}
178
179
static int
180
slt_getprologue(Pax_t* pax, Format_t* fp, register Archive_t* ap, File_t* f, unsigned char* buf, size_t size)
181
{
182
register Slt_t* slt;
183
char* s;
184
char* t;
185
int lab;
186
long n;
187
off_t x;
188
char hdr[HDR_SIZE + 1];
189
190
static const char key[] = "VOL1";
191
192
if (size < HDR_SIZE)
193
return 0;
194
memcpy(hdr, buf, HDR_SIZE);
195
if (fp->flags & CONV)
196
{
197
ccmapstr(state.map.e2n, hdr, HDR_SIZE);
198
if (!strneq(hdr, key, sizeof(key) - 1))
199
return 0;
200
ccmapstr(state.map.e2n, hdr, HDR_SIZE);
201
convert(ap, SECTION_CONTROL, CC_NATIVE, CC_EBCDIC);
202
if (!ap->convert[0].on)
203
convert(ap, SECTION_DATA, CC_NATIVE, CC_EBCDIC);
204
}
205
else
206
{
207
ccmapstr(state.map.a2n, hdr, HDR_SIZE);
208
if (!strneq(hdr, key, sizeof(key) - 1))
209
return 0;
210
convert(ap, SECTION_CONTROL, CC_NATIVE, CC_ASCII);
211
if (!ap->convert[0].on)
212
convert(ap, SECTION_DATA, CC_NATIVE, CC_ASCII);
213
}
214
if (!(slt = newof(0, Slt_t, 1, 0)))
215
{
216
nospace();
217
return -1;
218
}
219
ap->data = slt;
220
getlabstr(hdr, 5, 6, state.volume);
221
getlabstr(hdr, 25, 6, slt->format);
222
getlabstr(hdr, 31, 7, slt->implementation);
223
getlabstr(hdr, 38, 14, slt->owner);
224
paxget(pax, ap, 0, &x);
225
ap->io->blocked = !x;
226
if (ap->checkdelta)
227
{
228
if (!(lab = getlabel(pax, ap, f)))
229
return 0;
230
if (strneq(slt->buf, "UVL1", 4) && strneq(slt->buf + 5, ID, IDLEN))
231
{
232
ap->checkdelta = 0;
233
s = slt->buf + 10;
234
f->st->st_mtime = getlabnum(slt->buf, 14, 10, 10);
235
n = getlabnum(slt->buf, 24, 10, 10);
236
f->st->st_uid = DELTA_LO(n);
237
f->st->st_gid = DELTA_HI(n);
238
if (t = strchr(s, ' '))
239
*t = 0;
240
deltaset(ap, s);
241
}
242
else
243
slt->peek = lab;
244
}
245
return 1;
246
}
247
248
static int
249
slt_done(Pax_t* pax, register Archive_t* ap)
250
{
251
if (ap->data)
252
{
253
free(ap->data);
254
ap->data = 0;
255
}
256
return 0;
257
}
258
259
static int
260
slt_getheader(Pax_t* pax, register Archive_t* ap, register File_t* f, int wfd)
261
{
262
register Slt_t* slt = (Slt_t*)ap->data;
263
register char* s;
264
register int i;
265
register off_t n;
266
int lab;
267
int type;
268
269
again:
270
if (!(lab = getlabel(pax, ap, f)))
271
return 0;
272
f->st->st_dev = 0;
273
f->st->st_ino = 0;
274
f->st->st_mode = X_IFREG|X_IRUSR|X_IWUSR|X_IRGRP|X_IROTH;
275
f->st->st_uid = state.uid;
276
f->st->st_gid = state.gid;
277
f->st->st_nlink = 1;
278
IDEVICE(f->st, 0);
279
f->st->st_size = 0;
280
f->linktype = NOLINK;
281
f->linkpath = 0;
282
f->uidname = 0;
283
f->gidname = 0;
284
type = 0;
285
do
286
{
287
if (strneq(slt->buf, "HDR", 3))
288
{
289
if (getlabnum(slt->buf, 4, 1, 10) != ++type)
290
error(3, "%s format HDR label out of sequence", ap->format->name);
291
if (type == 1)
292
{
293
s = f->name = paxstash(pax, &ap->stash.head, NiL, NAME_SIZE + 3);
294
for (i = 4; i <= NAME_SIZE + 3; i++)
295
{
296
if (slt->buf[i] == ' ')
297
{
298
if (i >= NAME_SIZE + 3 || slt->buf[i + 1] == ' ')
299
break;
300
*s++ = '.';
301
}
302
else
303
*s++ = isupper(slt->buf[i]) ? tolower(slt->buf[i]) : slt->buf[i];
304
}
305
if ((n = getlabnum(slt->buf, 40, 2, 10)) > 0 && n < 99)
306
sfsprintf(s, 3, ".%02d", n);
307
else
308
*s = 0;
309
f->record.section = getlabnum(slt->buf, 28, 4, 10);
310
getlabstr(slt->buf, 5, NAME_SIZE, f->id = slt->id);
311
getlabstr(slt->buf, 61, 6, slt->format);
312
getlabstr(slt->buf, 67, 7, slt->implementation);
313
#if SAVESET
314
if (streq(slt->format, SAVESET_ID) && streq(slt->implementation, SAVESET_IMPL))
315
ap->format = SAVESET;
316
#endif
317
f->st->st_mtime = 0;
318
if (n = getlabnum(slt->buf, 43, 2, 10))
319
{
320
if (slt->buf[41] == '0') n += 100;
321
if ((i = getlabnum(slt->buf, 45, 3, 10)) >= 0 && i <= 365)
322
{
323
f->st->st_mtime = i;
324
while (n-- > 70) f->st->st_mtime += ((n % 4) || n == 100) ? 365 : 366;
325
f->st->st_mtime *= 24L * 60L * 60L;
326
f->st->st_mtime += 12L * 60L * 60L;
327
}
328
}
329
if (!f->st->st_mtime)
330
f->st->st_mtime = NOW;
331
}
332
else if (type == 2)
333
{
334
switch (f->record.format = slt->buf[4])
335
{
336
case 'D': /* decimal variable */
337
case 'F': /* fixed length */
338
case 'S': /* spanned */
339
case 'U': /* input block size */
340
case 'V': /* binary variable */
341
break;
342
default:
343
error(2, "%s record format %c not supported", ap->format->name, f->record.format);
344
f->skip = 1;
345
}
346
state.blocksize = getlabnum(slt->buf, 6, 5, 10);
347
state.record.size = getlabnum(slt->buf, 11, 5, 10);
348
if (!ap->io->blocked) f->st->st_size = getlabnum(slt->buf, 16, 10, 10);
349
state.record.offset = getlabnum(slt->buf, 51, 2, 10);
350
}
351
}
352
else if (!ap->io->blocked && strneq(slt->buf, "VOL1", 4))
353
{
354
paxunread(pax, ap, slt->buf, lab);
355
if (!(getprologue(ap)))
356
return 0;
357
goto again;
358
}
359
} while ((lab = getlabel(pax, ap, f)));
360
return 1;
361
}
362
363
static int
364
slt_getdata(Pax_t* pax, register Archive_t* ap, register File_t* f, int wfd)
365
{
366
register Slt_t* slt = (Slt_t*)ap->data;
367
register off_t n;
368
register off_t size;
369
int c;
370
int i;
371
int j;
372
int k;
373
int nl;
374
off_t m;
375
Sfio_t* wfp;
376
377
if (wfd < 0)
378
wfp = 0;
379
else if (!(wfp = sfnew(NiL, NiL, SF_UNBOUND, wfd, SF_WRITE)))
380
{
381
error(2, "%s: cannot write", f->name);
382
return -1;
383
}
384
ap->io->empty = 0;
385
nl = state.record.line;
386
size = 0;
387
for (;;)
388
{
389
if (ap->io->blocked)
390
n = paxread(pax, ap, state.tmp.buffer, (off_t)0, (off_t)state.buffersize, 0);
391
else if ((m = f->st->st_size - size) <= 0)
392
n = 0;
393
else if (wfp)
394
{
395
if (m > state.buffersize)
396
m = state.buffersize;
397
n = paxread(pax, ap, state.tmp.buffer, (off_t)0, m, 1);
398
}
399
else
400
n = paxread(pax, ap, NiL, (off_t)0, m, 1);
401
if (n < 0)
402
break;
403
if (n == 0)
404
{
405
k = 1;
406
ap->sum--;
407
while (getlabel(pax, ap, f))
408
{
409
if (strneq(slt->buf, "EOV1", 4))
410
k = 0;
411
else if (!strneq(slt->buf, "EOF", 3) && !strneq(slt->buf, "EOV", 3) && !strneq(slt->buf, "UTL", 3) && ++n >= 16 && !state.keepgoing)
412
error(3, "%s: %s: %d invalid %s end of file/volume labels detected", ap->name, f->name, n, ap->format->name);
413
}
414
if (n)
415
error(1, "%s: %s: %d invalid %s end of file/volume labels detected", ap->name, f->name, n, ap->format->name);
416
if (k)
417
{
418
ap->sum++;
419
break;
420
}
421
f->record.section++;
422
f->id = strcpy(state.tmp.buffer, f->id);
423
f->name = strcpy(state.tmp.buffer + NAME_SIZE + 1, f->name);
424
for (;;)
425
{
426
newio(ap, 0, 0);
427
if (getprologue(ap))
428
{
429
File_t v;
430
struct stat st;
431
432
v.st = &st;
433
if (getheader(ap, &v))
434
{
435
if (streq(f->id, v.id) && streq(f->name, v.name) && f->record.section == v.record.section)
436
{
437
f->id = v.id;
438
f->name = v.name;
439
break;
440
}
441
error(1, "volume containing %s id %s section %d required", f->name, f->id, f->record.section);
442
}
443
ap->volume--;
444
}
445
ap->part--;
446
}
447
ap->sum++;
448
continue;
449
}
450
if (f->record.format == 'V')
451
{
452
if ((k = ((unsigned char*)state.tmp.buffer)[0] << 8 | ((unsigned char*)state.tmp.buffer)[1]) != n)
453
error(3, "%s: invalid %s V format block descriptor [%d!=%d]", f->name, ap->format->name, k, n);
454
i = 4;
455
}
456
else
457
i = 0;
458
while (i < n)
459
{
460
i += state.record.offset;
461
if (state.tmp.buffer[i] == '^')
462
switch (f->record.format)
463
{
464
case 'F':
465
if (slt->ibm)
466
break;
467
for (j = i; j < n && state.tmp.buffer[j] == '^'; j++);
468
if (j < n)
469
break;
470
/*FALLTHROUGH*/
471
case 'D':
472
case 'S':
473
i = n;
474
continue;
475
}
476
477
/*
478
* get record size
479
*/
480
481
switch (f->record.format)
482
{
483
case 'D':
484
if (sfsscanf(&state.tmp.buffer[i], "%4d", &k) != 1)
485
k = -1;
486
j = i + 4;
487
break;
488
case 'F':
489
if (i + state.record.size > n)
490
k = n - i;
491
else if (state.record.line || state.record.offset)
492
k = state.record.size;
493
else
494
k = n;
495
j = i;
496
break;
497
case 'S':
498
switch (state.tmp.buffer[i])
499
{
500
case '0':
501
case '3':
502
nl = 1;
503
break;
504
default:
505
nl = 0;
506
break;
507
}
508
if (sfsscanf(&state.tmp.buffer[i + 1], "%4d", &k) != 1)
509
k = -1;
510
j = i + 5;
511
break;
512
case 'U':
513
k = n;
514
j = i;
515
break;
516
case 'V':
517
nl = !(state.tmp.buffer[i + 2] & 01);
518
k = ((unsigned char*)state.tmp.buffer)[i] << 8 | ((unsigned char*)state.tmp.buffer)[i + 1];
519
j = i + 4;
520
break;
521
}
522
if (k < 0)
523
{
524
error(2, "invalid %s %c record size", ap->format->name, f->record.format);
525
break;
526
}
527
m = i += k;
528
if (slt->mapin)
529
ccmapstr(slt->mapin, &state.tmp.buffer[j], m - j);
530
if (state.record.line)
531
switch (f->record.format)
532
{
533
case 'F':
534
case 'U':
535
while (--m >= j && state.tmp.buffer[m] == ' ');
536
m++;
537
break;
538
}
539
k = m - j + nl;
540
size += k;
541
if (wfp)
542
{
543
if (nl)
544
{
545
c = state.tmp.buffer[m];
546
state.tmp.buffer[m] = '\n';
547
}
548
if (sfwrite(wfp, &state.tmp.buffer[j], k) != k)
549
{
550
error(ERROR_SYSTEM|1, "%s: write error", f->name);
551
break;
552
}
553
if (nl)
554
state.tmp.buffer[m] = c;
555
}
556
}
557
}
558
if (f->st->st_size && f->st->st_size != size)
559
error(1, "%s: header size %I*d does not match data size %I*d", f->name, sizeof(f->st->st_size), f->st->st_size, sizeof(size), size);
560
f->st->st_size = size;
561
if (wfp)
562
{
563
sfclose(wfp);
564
setfile(ap, f);
565
}
566
if (n < 0)
567
{
568
error(ERROR_SYSTEM|3, "%s: %s: archive read error", ap->name, f->name);
569
return -1;
570
}
571
return 1;
572
}
573
574
static int
575
slt_getepilogue(Pax_t* pax, Archive_t* ap)
576
{
577
return 1;
578
}
579
580
static int
581
slt_backup(Pax_t* pax, Archive_t* ap)
582
{
583
#ifdef MTIOCTOP
584
struct mtop mt;
585
586
mt.mt_op = MTBSF;
587
mt.mt_count = 1;
588
if (ioctl(ap->io->fd, MTIOCTOP, &mt))
589
{
590
error(ERROR_SYSTEM|3, "%s: %s archive seek MTIO error", ap->name, ap->format->name);
591
return -1;
592
}
593
return 0;
594
#else
595
error(3, "%s: %s archive seek requires MTIO", ap->name, ap->format->name);
596
return -1;
597
#endif
598
}
599
600
static int
601
slt_putprologue(Pax_t* pax, Archive_t* ap, int append)
602
{
603
register Slt_t* slt = (Slt_t*)ap->data;
604
605
if (!ap->locked && slt->vol)
606
{
607
slt->vol = 0;
608
ap->locked = 1;
609
putlabels(pax, ap, state.record.file, "HDR");
610
ap->locked = 0;
611
}
612
if (ap->format->flags & CONV)
613
{
614
convert(ap, SECTION_CONTROL, CC_NATIVE, CC_EBCDIC);
615
if (!ap->convert[0].on)
616
convert(ap, SECTION_DATA, CC_NATIVE, CC_EBCDIC);
617
}
618
#if DEBUG
619
if (ap->io->blok)
620
ap->io->blocked = 1;
621
else
622
#endif
623
ap->io->blocked = !ap->io->unblocked;
624
if (!slt->owner[0])
625
{
626
strncpy(slt->owner, fmtuid(getuid()), sizeof(slt->owner) - 1);
627
slt->owner[sizeof(slt->owner) - 1] = 0;
628
}
629
strupper(slt->owner);
630
if (!state.volume[0])
631
{
632
strncpy(state.volume, slt->owner, sizeof(state.volume) - 1);
633
state.volume[sizeof(state.volume) - 1] = 0;
634
}
635
strupper(state.volume);
636
strncpy(slt->format, SLT_ID, sizeof(slt->format) - 1);
637
strncpy(slt->implementation, IMPLEMENTATION, sizeof(slt->implementation) - 1);
638
if (ap->format->flags & CONV)
639
sfsprintf(slt->standards, sizeof(slt->standards), "%-5.5s%-5.5s%-5.5s%-4.4s", "ATT", "1", "EBCDIC", "1979");
640
else
641
sfsprintf(slt->standards, sizeof(slt->standards), "%-5.5s%-5.5s%-5.5s%-4.4s", "ISO", "646", "IRV", "1990");
642
sfsprintf(slt->buf, sizeof(slt->buf), "VOL1%-6.6s %-6.6s%-7.7s%-14.14s 4", state.volume, slt->format, slt->implementation, slt->owner);
643
paxwrite(pax, ap, slt->buf, HDR_SIZE);
644
sfsprintf(slt->buf, sizeof(slt->buf), "VOL2%-19.19s ", slt->standards);
645
paxwrite(pax, ap, slt->buf, HDR_SIZE);
646
if (ap->delta && !(ap->delta->format->flags & PSEUDO))
647
{
648
sfsprintf(slt->buf, sizeof(slt->buf), "UVL1 %-6.6s%c%-6.6s%010ld%010ld ", ID, ap->delta->compress ? TYPE_COMPRESS : TYPE_DELTA, ((Compress_format_t*)ap->delta->format)->variant, state.operation == OUT ? (long)ap->size : (long)0, state.operation == OUT ? ap->checksum : 0L);
649
paxwrite(pax, ap, slt->buf, HDR_SIZE);
650
}
651
return 1;
652
}
653
654
static int
655
slt_putheader(Pax_t* pax, Archive_t* ap, File_t* f)
656
{
657
if (state.complete)
658
complete(ap, f, 4 * HDR_SIZE);
659
putlabels(pax, ap, f, "HDR");
660
return 1;
661
}
662
663
static int
664
recordout(Pax_t* pax, Archive_t* ap, File_t* f, Sfio_t* fp)
665
{
666
register Slt_t* slt = (Slt_t*)ap->data;
667
register int c;
668
register char* p;
669
register char* recdat;
670
register char* blkdat;
671
char* rec;
672
char* blk;
673
int span;
674
675
int count = 0;
676
int partial = 0;
677
int truncated = 0;
678
679
static char span_out[] = "0132";
680
681
if (!fp)
682
error(3, "record output from buffer not supported");
683
ap->record = f;
684
f->record.blocks = 0;
685
span = 0;
686
blk = state.tmp.buffer;
687
688
/*
689
* file loop
690
*/
691
692
for (;;)
693
{
694
p = blk;
695
switch (state.record.format)
696
{
697
case 'V':
698
p += 4;
699
break;
700
}
701
blkdat = p;
702
703
/*
704
* block loop
705
*/
706
707
for (;;)
708
{
709
rec = p;
710
switch (state.record.format)
711
{
712
case 'D':
713
case 'V':
714
p += 4;
715
break;
716
case 'S':
717
p += 5;
718
break;
719
}
720
recdat = p;
721
722
/*
723
* check for partial record from previous block
724
*/
725
726
if (partial)
727
{
728
memcpy(recdat, f->record.partial, partial);
729
p += partial;
730
partial = 0;
731
}
732
733
/*
734
* record loop
735
*/
736
737
span &= 01;
738
span <<= 1;
739
for (;;)
740
{
741
if (p >= &rec[state.record.size] && state.record.size)
742
{
743
if (state.record.line)
744
{
745
truncated++;
746
while ((c = sfgetc(fp)) != EOF && c != '\n');
747
}
748
break;
749
}
750
else if (p >= &blk[state.blocksize])
751
{
752
if (state.record.format == 'S' || state.record.format == 'V')
753
{
754
if (p > recdat)
755
{
756
span |= 01;
757
break;
758
}
759
}
760
else if (partial = p - recdat)
761
{
762
/*
763
* save partial record for next block
764
*/
765
766
if (!f->record.partial && !(f->record.partial = newof(0, char, state.blocksize, 0)))
767
nospace();
768
memcpy(f->record.partial, recdat, partial);
769
}
770
p = rec;
771
goto eob;
772
}
773
else if ((c = sfgetc(fp)) == EOF)
774
{
775
if (p == recdat)
776
{
777
if (rec == blkdat) goto eof;
778
p = rec;
779
goto eob;
780
}
781
break;
782
}
783
else if (c == '\n' && state.record.line)
784
break;
785
else
786
*p++ = c;
787
}
788
switch (state.record.format)
789
{
790
case 'D':
791
c = recdat[0];
792
sfsprintf(rec, 4, "%04d", p - rec);
793
recdat[0] = c;
794
break;
795
case 'F':
796
if (c != EOF || state.record.pad)
797
{
798
memset(p, ' ', state.record.size - (p - rec));
799
p = rec + state.record.size;
800
}
801
break;
802
case 'S':
803
c = recdat[0];
804
sfsprintf(rec, 4, "%c%04d", span_out[span], p - rec);
805
recdat[0] = c;
806
break;
807
case 'U':
808
if (p == recdat) *p++ = ' ';
809
break;
810
case 'V':
811
rec[0] = ((p - rec) >> 8) & 0xff;
812
rec[1] = (p - rec) & 0xff;
813
rec[2] = span;
814
rec[3] = 0;
815
break;
816
}
817
if (slt->mapout)
818
ccmapstr(slt->mapout, recdat, p - recdat);
819
count++;
820
if (p >= &blk[state.blocksize] || state.record.format == 'U')
821
break;
822
}
823
eob:
824
switch (state.record.format)
825
{
826
case 'D':
827
case 'S':
828
if (state.record.pad)
829
{
830
memset(p, '^', state.blocksize - (p - blk));
831
p = blk + state.blocksize;
832
}
833
break;
834
case 'V':
835
blk[0] = ((p - blk) >> 8) & 0xff;
836
blk[1] = (p - blk) & 0xff;
837
blk[2] = 0;
838
blk[3] = 0;
839
break;
840
}
841
paxwrite(pax, ap, blk, p - blk);
842
f->record.blocks++;
843
}
844
eof:
845
ap->record = 0;
846
if (truncated)
847
error(1, "%s: %d out of %d record%s truncated", f->name, truncated, count, count == 1 ? "" : "s");
848
return 0;
849
}
850
851
static int
852
slt_putdata(Pax_t* pax, Archive_t* ap, File_t* f, int rfd)
853
{
854
register size_t m;
855
register ssize_t n;
856
register off_t c;
857
int r;
858
Buffer_t* bp;
859
Sfio_t* rfp;
860
861
if (ap->io->blocked)
862
return 0;
863
r = 1;
864
if (f->st->st_size > 0)
865
{
866
if (state.record.format == 'F' && !state.record.line)
867
{
868
/*
869
* this is faster than recordout()
870
*/
871
872
ap->record = f;
873
c = f->st->st_size;
874
while (c > 0)
875
{
876
n = m = c > state.record.size ? state.record.size : c;
877
878
/*
879
* NOTE: we expect that all but the last
880
* read returns state.record.size
881
* if not the the intermediate short
882
* reads are filled with 0's
883
*/
884
885
if (!r)
886
{
887
if (rfd >= 0)
888
n = read(rfd, state.tmp.buffer, m);
889
else if (bp = getbuffer(rfd))
890
{
891
memcpy(ap->io->next, bp->next, m);
892
bp->next += m;
893
}
894
else if (paxread(pax, f->ap, state.tmp.buffer, (off_t)0, (off_t)m, 1) <= 0)
895
n = -1;
896
}
897
if (n <= 0)
898
{
899
if (n)
900
error(ERROR_SYSTEM|2, "%s: read error", f->path);
901
else
902
error(2, "%s: file size changed", f->path);
903
memzero(state.tmp.buffer, state.record.size);
904
r = -1;
905
}
906
else
907
{
908
c -= n;
909
if (n < state.record.size && (c > 0 || state.record.pad))
910
{
911
memzero(state.tmp.buffer + n, state.record.size - n);
912
n = state.record.size;
913
}
914
paxwrite(pax, ap, state.tmp.buffer, n);
915
}
916
}
917
ap->record = 0;
918
if (rfd >= 0)
919
close(rfd);
920
}
921
else if (rfd < 0)
922
recordout(pax, ap, f, NiL);
923
else if (!(rfp = sfnew(NiL, NiL, SF_UNBOUND, rfd, SF_READ)))
924
{
925
error(1, "%s: cannot read", f->path);
926
close(rfd);
927
}
928
else
929
{
930
recordout(pax, ap, f, rfp);
931
sfclose(rfp);
932
}
933
}
934
return r;
935
}
936
937
static int
938
slt_puttrailer(Pax_t* pax, Archive_t* ap, File_t* f)
939
{
940
putlabels(pax, ap, f, "EOF");
941
return 0;
942
}
943
944
static off_t
945
slt_putepilogue(Pax_t* pax, Archive_t* ap)
946
{
947
register Slt_t* slt = (Slt_t*)ap->data;
948
949
if (!ap->locked)
950
{
951
ap->locked = 1;
952
putlabels(pax, ap, state.record.file, "EOV");
953
ap->locked = 0;
954
slt->vol = 1;
955
}
956
paxwrite(pax, ap, slt->buf, 0);
957
paxwrite(pax, ap, slt->buf, 0);
958
return ap->io->count;
959
}
960
961
static int
962
slt_validate(Pax_t* pax, Archive_t* ap, register File_t* f)
963
{
964
register Slt_t* slt = (Slt_t*)ap->data;
965
register char* s;
966
967
if (f->type != X_IFREG)
968
{
969
error(2, "%s: only regular files copied in %s format", f->path, ap->format->name);
970
return 0;
971
}
972
if (s = strrchr(f->name, '/'))
973
{
974
s++;
975
error(1, "%s: file name stripped to %s", f->name, s);
976
}
977
else
978
s = f->name;
979
if (strlen(s) > sizeof(slt->id) - 1)
980
{
981
error(2, "%s: file name too long", f->name);
982
return 0;
983
}
984
f->id = strupper(strcpy(slt->id, s));
985
return 1;
986
}
987
988
Format_t pax_slt_format =
989
{
990
"ansi",
991
"slt",
992
"ANSI standard label tape; for tape devices only",
993
ANSI,
994
ARCHIVE|NOHARDLINKS|IN|OUT,
995
4,
996
4,
997
0,
998
pax_slt_next,
999
0,
1000
slt_done,
1001
slt_getprologue,
1002
0,
1003
slt_getdata,
1004
0,
1005
slt_getepilogue,
1006
slt_putprologue,
1007
slt_putheader,
1008
slt_putdata,
1009
slt_puttrailer,
1010
slt_putepilogue,
1011
0,
1012
slt_backup,
1013
0,
1014
slt_validate
1015
};
1016
1017
static int
1018
ibm_getprologue(Pax_t* pax, Format_t* fp, register Archive_t* ap, File_t* f, unsigned char* buf, size_t size)
1019
{
1020
register Slt_t* slt;
1021
int n;
1022
1023
if ((n = slt_getprologue(pax, fp, ap, f, buf, size)) > 0 && state.record.charset)
1024
{
1025
slt = (Slt_t*)ap->data;
1026
slt->mapin = state.map.e2n;
1027
slt->mapout = state.map.n2e;
1028
}
1029
return n;
1030
}
1031
1032
Format_t pax_ibm_format =
1033
{
1034
"ibm",
1035
"elt",
1036
"EBCDIC standard label tape; for tape devices only",
1037
IBM,
1038
ARCHIVE|CONV|NOHARDLINKS|IN|OUT,
1039
4,
1040
4,
1041
0,
1042
PAXNEXT(ibm),
1043
0,
1044
slt_done,
1045
ibm_getprologue,
1046
0,
1047
slt_getdata,
1048
0,
1049
slt_getepilogue,
1050
slt_putprologue,
1051
slt_putheader,
1052
slt_putdata,
1053
slt_puttrailer,
1054
slt_putepilogue,
1055
0,
1056
slt_backup,
1057
0,
1058
slt_validate
1059
};
1060
1061
PAXLIB(ibm)
1062
1063