Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/pax/pax-tar.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 { pax tar ustar } formats
24
*/
25
26
#include "format.h"
27
28
#undef SOKTYPE
29
30
#define PAX 1
31
#define OLD 2
32
#define TAR 3
33
34
#define TAR_HEADER TBLOCK
35
#define TAR_LARGENUM 0200
36
#define TAR_SUMASK ((1L<<(sizeof(tar->header.chksum)-1)*3)-1)
37
38
#define TARSIZEOF(m) sizeof(((Tarheader_t*)&state)->m)
39
40
typedef struct Tar_s
41
{
42
Tarheader_t header;
43
Tarheader_t last[16]; /* last n headers */
44
int lastindex; /* last[] index */
45
} Tar_t;
46
47
/*
48
* output extended header keyword assignment record
49
*/
50
51
void
52
putkey(Archive_t* ap, Sfio_t* sp, Option_t* op, const char* value, Sfulong_t number)
53
{
54
register size_t n;
55
register size_t m;
56
register size_t o;
57
58
if (value)
59
n = strlen(value);
60
else
61
{
62
n = sfprintf(ap->tmp.key, "%I*u", sizeof(number), number);
63
sfstrseek(ap->tmp.key, 0, SEEK_SET);
64
}
65
message((-5, "putkey %s=%s", op->name, value ? value : sfstrseek(ap->tmp.key, 0, SEEK_CUR)));
66
n += strlen(op->name) + 3 + ((op->flags & OPT_VENDOR) ? sizeof(VENDOR) : 0);
67
o = 0;
68
for (;;)
69
{
70
sfprintf(ap->tmp.key, "%I*u", sizeof(n), n);
71
m = sfstrtell(ap->tmp.key);
72
sfstrseek(ap->tmp.key, 0, SEEK_SET);
73
if (m == o)
74
break;
75
n += m - o;
76
o = m;
77
}
78
sfprintf(sp, "%I*u ", sizeof(n), n);
79
if (op->flags & OPT_VENDOR)
80
sfprintf(sp, "%s.", VENDOR);
81
sfprintf(sp, "%s=", op->name, value);
82
if (value)
83
sfprintf(sp, "%s", value);
84
else
85
sfprintf(sp, "%I*u", sizeof(number), number);
86
sfputc(sp, '\n');
87
}
88
89
/*
90
* compute tar->header checksum
91
*/
92
93
static unsigned long
94
tar_checksum(Archive_t* ap, int check, unsigned long sum)
95
{
96
register Tar_t* tar = (Tar_t*)ap->data;
97
register unsigned char* p;
98
register unsigned char* e;
99
register unsigned char* t;
100
register unsigned long u;
101
register unsigned long s;
102
register long c;
103
register const unsigned char* map;
104
unsigned char tmp[TARSIZEOF(chksum)];
105
106
p = (unsigned char*)tar->header.chksum;
107
e = p + TARSIZEOF(chksum);
108
t = tmp;
109
while (p < e)
110
{
111
*t++ = *p;
112
*p++ = ' ';
113
}
114
u = 0;
115
s = 0;
116
p = (unsigned char*)&tar->header;
117
e = p + TAR_HEADER;
118
if (!ap->convert[SECTION_CONTROL].on)
119
while (p < e)
120
{
121
c = *p++;
122
u += c;
123
if (check)
124
{
125
if (c & 0x80)
126
c |= (-1) << 8;
127
s += c;
128
}
129
}
130
else
131
{
132
map = ((ap->mio.mode & O_ACCMODE) == O_WRONLY) ? ap->convert[SECTION_CONTROL].f2t : ap->convert[SECTION_CONTROL].t2f;
133
while (p < e)
134
{
135
c = map[*p++];
136
u += c;
137
if (check)
138
{
139
if (c & 0x80)
140
c |= (-1) << 8;
141
s += c;
142
}
143
}
144
}
145
p = (unsigned char*)tar->header.chksum;
146
e = p + TARSIZEOF(chksum);
147
t = tmp;
148
while (p < e)
149
*p++ = *t++;
150
u &= TAR_SUMASK;
151
if (check)
152
{
153
if ((sum &= TAR_SUMASK) == u)
154
return 1;
155
if (sum == (s &= TAR_SUMASK))
156
{
157
if (!ap->old.warned)
158
{
159
ap->old.warned = 1;
160
error(1, "%s: %s format archive generated with signed checksums", ap->name, ap->format->name);
161
}
162
return 1;
163
}
164
if (ap->entry > 1)
165
{
166
if (s != u)
167
error(state.keepgoing ? 1 : 3, "%s: %s format checksum error (%ld != %ld or %ld)", ap->name, ap->format->name, sum, u, s);
168
else
169
error(state.keepgoing ? 1 : 3, "%s: %s format checksum error (%ld != %ld)", ap->name, ap->format->name, sum, u);
170
return state.keepgoing;
171
}
172
return 0;
173
}
174
return u;
175
}
176
177
/*
178
* check if tar file name may be split to fit in header
179
* return
180
* <0 extension header required with error message for non-extension formats
181
* 0 no split needed
182
* >0 f->name offset to split
183
*/
184
185
static int
186
tar_longname(Archive_t* ap, File_t* f)
187
{
188
register char* s;
189
register char* b;
190
register int n;
191
192
if (!(n = f->namesize) || --n <= TARSIZEOF(name))
193
return 0;
194
switch (ap->format->variant)
195
{
196
case PAX:
197
case TAR:
198
if (n > (TARSIZEOF(prefix) + TARSIZEOF(name) + 1))
199
{
200
if (ap->format->variant != PAX && state.strict)
201
goto toolong;
202
f->longname = 1;
203
return -1;
204
}
205
s = f->name + n;
206
b = s - TARSIZEOF(name) - 1;
207
while (--s >= b)
208
if (*s == '/' && (n = s - f->name) <= TARSIZEOF(prefix))
209
{
210
if (!n)
211
break;
212
return s - f->name;
213
}
214
if (ap->format->variant != PAX && state.strict)
215
{
216
error(2, "%s: file base name too long -- %d max", f->name, TARSIZEOF(name));
217
f->skip = 1;
218
}
219
else
220
f->longname = 1;
221
return -1;
222
case OLD:
223
toolong:
224
error(2, "%s: file name too long -- %d max", f->name, TARSIZEOF(prefix) + TARSIZEOF(name) + !!strchr(f->name, '/'));
225
f->skip = 1;
226
return -1;
227
}
228
return 0;
229
}
230
231
/*
232
* check if f->linkpath is too long
233
* return
234
* <0 extension header required with error message for non-extension formats
235
* 0 it fits
236
*/
237
238
static int
239
tar_longlink(Archive_t* ap, File_t* f)
240
{
241
if (f->linktype != NOLINK && strlen(f->linkpath) > TARSIZEOF(linkname))
242
{
243
switch (ap->format->variant)
244
{
245
case TAR:
246
if (!state.strict)
247
break;
248
/*FALLTHROUGH*/
249
case OLD:
250
error(2, "%s: link name too long -- %d max", f->linkpath, TARSIZEOF(linkname));
251
f->skip = 1;
252
return -1;
253
}
254
f->longlink = 1;
255
return -1;
256
}
257
return 0;
258
}
259
260
/*
261
* generate extended header path name from fmt
262
*/
263
264
static char*
265
headname(Archive_t* ap, File_t* f, const char* fmt)
266
{
267
char* s;
268
char* t;
269
size_t n;
270
271
if (!ap->tmp.hdr && !(ap->tmp.hdr = sfstropen()))
272
nospace();
273
listprintf(ap->tmp.hdr, ap, f, fmt);
274
if (sfstrtell(ap->tmp.hdr) > TARSIZEOF(name))
275
{
276
sfstrseek(ap->tmp.hdr, 0, SEEK_SET);
277
s = f->name;
278
if (t = strrchr(s, '/'))
279
f->name = t + 1;
280
if ((n = strlen(f->name)) > TARSIZEOF(name) / 2)
281
f->name = f->name + n - TARSIZEOF(name) / 2;
282
listprintf(ap->tmp.hdr, ap, f, fmt);
283
f->name = s;
284
}
285
if (!(s = sfstruse(ap->tmp.hdr)))
286
nospace();
287
return s;
288
}
289
290
/*
291
* synthesize an extended tar header
292
*/
293
294
static void
295
synthesize(Archive_t* ap, File_t* f, char* name, int type, char* buf, size_t n)
296
{
297
Buffer_t* bp;
298
char* base;
299
char* next;
300
File_t h;
301
struct stat st;
302
303
ap->sum -= 2;
304
initfile(ap, &h, &st, name, X_IFREG|X_IRUSR|X_IWUSR|X_IRGRP|X_IROTH);
305
h.extended = type;
306
h.st->st_gid = f->st->st_gid;
307
h.st->st_uid = f->st->st_uid;
308
h.st->st_mtime = NOW;
309
h.st->st_size = n;
310
h.fd = setbuffer(0);
311
bp = getbuffer(h.fd);
312
base = bp->base;
313
next = bp->next;
314
bp->base = bp->next = buf;
315
fileout(ap, &h);
316
bp->base = base;
317
bp->next = next;
318
ap->sum += 2;
319
}
320
321
/*
322
* output an extended tar header
323
* some keys may already be in the header buffer for type
324
*/
325
326
static int
327
extend(Archive_t* ap, File_t* f, int type)
328
{
329
unsigned long n;
330
char* s;
331
char* fmt;
332
Hash_position_t* pos;
333
Option_t* op;
334
Sfio_t* sp;
335
Value_t* vp;
336
int lev;
337
int alt;
338
int split;
339
Tv_t tv;
340
File_t h;
341
struct stat st;
342
char num[64];
343
344
if (!f)
345
initfile(ap, f = &h, &st, ".", X_IFREG|X_IRUSR|X_IWUSR|X_IRGRP|X_IROTH);
346
switch (type)
347
{
348
case EXTTYPE:
349
sp = ap->tmp.extended;
350
fmt = state.header.extended;
351
lev = 7;
352
alt = 4;
353
break;
354
case GLBTYPE:
355
sp = ap->tmp.global;
356
fmt = state.header.global;
357
lev = 3;
358
alt = 0;
359
break;
360
default:
361
return 0;
362
}
363
if (pos = hashscan(state.options, 0))
364
{
365
while (hashnext(pos))
366
{
367
op = (Option_t*)pos->bucket->value;
368
if ((op->flags & (OPT_HEADER|OPT_READONLY)) == OPT_HEADER && op->name == pos->bucket->name && (op->level == lev || op->level == alt))
369
{
370
message((-5, "extend %s level=%d:%d:%d entry=%d:%d perm=(%s,%I*d) temp=(%s,%I*d)", op->name, op->level, lev, alt, op->entry, ap->entry, op->perm.string, sizeof(op->perm.number), op->perm.number, op->temp.string, sizeof(op->temp.number), op->temp.number));
371
vp = &op->perm;
372
s = vp->string;
373
switch (op->index)
374
{
375
case OPT_atime:
376
case OPT_ctime:
377
case OPT_mtime:
378
if (op->flags & OPT_SET)
379
s = vp->string;
380
else if (type != EXTTYPE)
381
continue;
382
else
383
{
384
switch (op->index)
385
{
386
case OPT_atime:
387
tvgetatime(&tv, f->st);
388
break;
389
case OPT_mtime:
390
tvgetmtime(&tv, f->st);
391
break;
392
case OPT_ctime:
393
tvgetctime(&tv, f->st);
394
break;
395
}
396
if (!tv.tv_nsec && op->index == OPT_mtime)
397
continue;
398
s = num + sfsprintf(num, sizeof(num), "%lu.%09lu", tv.tv_sec, tv.tv_nsec);
399
while (*(s - 1) == '0')
400
s--;
401
if (*(s - 1) == '.')
402
*s++ = '0';
403
*s = 0;
404
s = num;
405
}
406
break;
407
case OPT_comment:
408
s = state.header.comment;
409
break;
410
case OPT_gid:
411
if (op->flags & OPT_SET)
412
f->st->st_gid = vp->number;
413
else
414
{
415
if (type != EXTTYPE)
416
f->st->st_gid = state.gid;
417
if ((uint32_t)f->st->st_gid <= (unsigned long)07777777)
418
continue;
419
}
420
sfsprintf(s = num, sizeof(num), "%I*u", sizeof(f->st->st_gid), f->st->st_gid);
421
break;
422
case OPT_gname:
423
if (op->flags & OPT_SET)
424
f->gidname = s;
425
else if (!f->gidname || strlen(f->gidname) < TARSIZEOF(gname) && portable(ap, f->gidname))
426
continue;
427
s = f->gidname;
428
break;
429
case OPT_size:
430
#if _typ_int64_t
431
if (type == GLBTYPE)
432
continue;
433
if (!(f->st->st_size >> 32) && !(state.test & 1))
434
continue;
435
state.test &= ~1;
436
sfsprintf(s = num, sizeof(num), "%I*u", sizeof(f->st->st_size), f->st->st_size);
437
break;
438
#else
439
continue;
440
#endif
441
case OPT_uid:
442
if (op->flags & OPT_SET)
443
f->st->st_uid = vp->number;
444
else
445
{
446
if (type != EXTTYPE)
447
f->st->st_uid = state.uid;
448
if ((unsigned long)f->st->st_uid <= (unsigned long)07777777)
449
continue;
450
}
451
sfsprintf(s = num, sizeof(num), "%I*u", sizeof(f->st->st_uid), f->st->st_uid);
452
break;
453
case OPT_uname:
454
if (op->flags & OPT_SET)
455
f->uidname = s;
456
else if (!f->uidname || strlen(f->uidname) < TARSIZEOF(uname) && portable(ap, f->uidname))
457
continue;
458
s = f->uidname;
459
break;
460
default:
461
if (!s && (op->flags & OPT_SET))
462
sfsprintf(s = num, sizeof(num), "%ld", vp->number);
463
break;
464
}
465
if (s)
466
putkey(ap, sp, op, s, 0);
467
}
468
}
469
hashdone(pos);
470
}
471
if (type == EXTTYPE)
472
{
473
if ((split = tar_longname(ap, f)) < 0 || !portable(ap, f->name))
474
putkey(ap, sp, &options[OPT_path], f->name, 0);
475
if (f->linkpath && (tar_longlink(ap, f) < 0 || !portable(ap, f->linkpath)))
476
putkey(ap, sp, &options[OPT_linkpath], f->linkpath, 0);
477
}
478
else
479
split = 0;
480
if (n = sfstrtell(sp))
481
{
482
if (!(s = sfstruse(sp)))
483
nospace();
484
synthesize(ap, f, headname(ap, f, fmt), type, s, n);
485
}
486
return split;
487
}
488
489
static int
490
tar_getoctal(const char* f, const char* p, size_t n, int z, void* r)
491
{
492
register unsigned char* s = (unsigned char*)p;
493
register unsigned char* e = s + n;
494
register uintmax_t v = 0;
495
496
while (s < e && *s == ' ')
497
s++;
498
while (s < e && *s >= '0' && *s <= '7')
499
v = (v << 3) + (*s++ - '0');
500
if (s < e)
501
{
502
if (*s == 0x80 || *s == 0xff)
503
{
504
v = *s++ == 0x80 ? 0 : 0xff;
505
e = (unsigned char*)p + 8;
506
while (s < e)
507
v = (v << 8) + *s++;
508
}
509
else if (*s && *s != ' ')
510
return -1;
511
}
512
switch (z)
513
{
514
case 1:
515
*(unsigned char*)r = (unsigned char)v;
516
break;
517
case 2:
518
*(uint16_t*)r = (uint16_t)v;
519
break;
520
case 4:
521
*(uint32_t*)r = (uint32_t)v;
522
break;
523
#ifdef _ast_int8_t
524
case 8:
525
*(uint64_t*)r = (uint64_t)v;
526
break;
527
#endif
528
}
529
return 0;
530
}
531
532
static int
533
tar_getheader(Pax_t* pax, Archive_t* ap, register File_t* f)
534
{
535
register Tar_t* tar = (Tar_t*)ap->data;
536
char* s;
537
char* t;
538
Format_t* tp;
539
Option_t* op;
540
off_t n;
541
long num;
542
int i;
543
int m;
544
545
again:
546
if (paxread(pax, ap, &tar->header, (off_t)0, (off_t)TAR_HEADER, 0) <= 0)
547
return 0;
548
if (!*tar->header.name)
549
{
550
if (ap->entry == 1)
551
goto nope;
552
return 0;
553
}
554
if (tar_getoctal("mode", tar->header.mode, 7, sizeof(f->st->st_mode), &f->st->st_mode))
555
goto nope;
556
if (tar_getoctal("uid", tar->header.uid, 7, sizeof(f->st->st_uid), &f->st->st_uid))
557
goto nope;
558
if (tar_getoctal("gid", tar->header.gid, 7, sizeof(f->st->st_gid), &f->st->st_gid))
559
goto nope;
560
if (tar_getoctal("mtime", tar->header.mtime, 11, sizeof(f->st->st_mtime), &f->st->st_mtime))
561
goto nope;
562
if (tar_getoctal("chksum", tar->header.chksum, 7, sizeof(num), &num))
563
goto nope;
564
if (!tar_checksum(ap, 1, num) && ap->entry == 1)
565
{
566
if (!ap->swapio)
567
{
568
char tmp[TARSIZEOF(chksum) + 1];
569
570
tmp[TARSIZEOF(chksum)] = 0;
571
for (i = 1; i < 4; i++)
572
{
573
memcpy(tmp, tar->header.chksum, TARSIZEOF(chksum));
574
swapmem(i, tmp, tmp, TARSIZEOF(chksum));
575
if (!tar_getoctal("chksum", tar->header.chksum, 7, sizeof(num), &num) && tar_checksum(ap, 1, num))
576
{
577
ap->swapio = i;
578
paxunread(pax, ap, &tar->header, TAR_HEADER);
579
goto again;
580
}
581
}
582
}
583
goto nope;
584
}
585
if (tar_getoctal("size", tar->header.size, 11, sizeof(f->st->st_size), &f->st->st_size))
586
goto nope;
587
if (ap->format->variant != OLD)
588
{
589
if (!streq(tar->header.magic, TMAGIC))
590
{
591
if (streq(tar->header.magic, TMAGIC " "))
592
/* old gnu tar */;
593
else if (ap->entry > 1)
594
goto nope;
595
ap->format = &pax_tar_format;
596
}
597
else if (!strneq(tar->header.version, TVERSION, TARSIZEOF(version)))
598
{
599
tp = &pax_tar_format;
600
error(1, "%s: %s format version %-.*s incompatible with implementation version %-.*s -- assuming %s", ap->name, ap->format->name, TARSIZEOF(version), tar->header.version, TARSIZEOF(version), TVERSION, tp->name);
601
ap->format = tp;
602
}
603
}
604
*((char*)tar->header.name + TARSIZEOF(name)) = 0;
605
if (ap->format->variant != OLD && *tar->header.prefix)
606
{
607
f->name = paxstash(pax, &ap->stash.head, NiL, TARSIZEOF(prefix) + TARSIZEOF(name) + 2);
608
sfsprintf(f->name, TARSIZEOF(prefix) + TARSIZEOF(name) + 2, "%-.*s/%-.*s", TARSIZEOF(prefix), tar->header.prefix, TARSIZEOF(name), tar->header.name);
609
}
610
else
611
f->name = tar->header.name;
612
*((char*)tar->header.linkname + TARSIZEOF(name)) = 0;
613
f->linktype = NOLINK;
614
f->linkpath = 0;
615
f->st->st_nlink = 1;
616
switch (tar->header.typeflag)
617
{
618
case LNKTYPE:
619
f->linktype = HARDLINK;
620
f->st->st_mode |= X_IFREG;
621
f->st->st_nlink = 2;
622
if (!ap->delta)
623
f->st->st_size = 0;
624
f->linkpath = paxstash(pax, &ap->stash.link, tar->header.linkname, 0);
625
break;
626
case SYMTYPE:
627
f->linktype = SOFTLINK;
628
f->st->st_mode |= X_IFLNK;
629
f->linkpath = paxstash(pax, &ap->stash.link, tar->header.linkname, 0);
630
break;
631
case CHRTYPE:
632
f->st->st_mode |= X_IFCHR;
633
device:
634
if (tar_getoctal("devmajor", tar->header.devmajor, 7, sizeof(i), &i))
635
goto nope;
636
if (tar_getoctal("devminor", tar->header.devminor, 7, sizeof(m), &m))
637
goto nope;
638
IDEVICE(f->st, makedev(i, m));
639
break;
640
case BLKTYPE:
641
f->st->st_mode |= X_IFBLK;
642
goto device;
643
case DIRTYPE:
644
f->st->st_mode |= X_IFDIR;
645
break;
646
case FIFOTYPE:
647
f->st->st_mode |= X_IFIFO;
648
break;
649
#ifdef SOKTYPE
650
case SOKTYPE:
651
f->st->st_mode |= X_IFSOCK;
652
break;
653
#endif
654
case EXTTYPE:
655
case GLBTYPE:
656
ap->format = &pax_pax_format;
657
if (f->st->st_size > 0)
658
{
659
ap->section = SECTION_DATA;
660
if (!(s = paxget(pax, ap, f->st->st_size, NiL)))
661
error(3, "invalid %s format '%c' extended header", ap->format->name, tar->header.typeflag);
662
s[f->st->st_size - 1] = 0;
663
setoptions(s, f->st->st_size, NiL, state.usage, ap, tar->header.typeflag);
664
}
665
ap->sum -= 2;
666
f->extended = tar->header.typeflag;
667
gettrailer(ap, f);
668
f->extended = 0;
669
ap->sum += 3;
670
deltacheck(ap, NiL);
671
goto again;
672
673
case LLNKTYPE:
674
case LREGTYPE:
675
if ((n = f->st->st_size) > 0)
676
{
677
if (!(s = paxget(pax, ap, n, NiL)))
678
{
679
error(2, "%s: invalid %s format long path header", ap->name, ap->format->name);
680
return 0;
681
}
682
op = &options[tar->header.typeflag == LLNKTYPE ? OPT_linkpath : OPT_path];
683
op->level = 6;
684
op->entry = ap->entry;
685
paxstash(pax, &op->temp, s, (size_t)n);
686
}
687
gettrailer(ap, f);
688
goto again;
689
690
case VERTYPE:
691
error(1, "version file archive members not supported -- regular file assumed");
692
goto regular;
693
694
default:
695
error(1, "%s: %s: unknown %s format file type `%c' -- regular file assumed", ap->name, f->name, ap->format->name, tar->header.typeflag);
696
/*FALLTHROUGH*/
697
case REGTYPE:
698
case AREGTYPE:
699
case CONTTYPE:
700
regular:
701
f->st->st_mode |= X_IFREG;
702
break;
703
}
704
f->uidname = 0;
705
f->gidname = 0;
706
if (ap->format->variant != OLD)
707
{
708
if (*tar->header.uname && (strtoll(tar->header.uname, &t, 0), *t))
709
f->uidname = tar->header.uname;
710
if (*tar->header.gname && (strtoll(tar->header.gname, &t, 0), *t))
711
f->gidname = tar->header.gname;
712
}
713
if (++tar->lastindex >= elementsof(tar->last))
714
tar->lastindex = 0;
715
tar->last[tar->lastindex] = tar->header;
716
return 1;
717
nope:
718
paxunread(pax, ap, &tar->header, TAR_HEADER);
719
return 0;
720
}
721
722
static int
723
tar_getprologue(Pax_t* pax, Format_t* fp, register Archive_t* ap, File_t* f, unsigned char* buf, size_t size)
724
{
725
int n;
726
727
if (!(ap->data = newof(0, Tar_t, 1, 0)))
728
nospace();
729
ap->format = fp;
730
if ((n = tar_getheader(pax, ap, f)) > 0)
731
ap->peek = 1;
732
else
733
{
734
free(ap->data);
735
ap->data = 0;
736
ap->format = 0;
737
}
738
return n;
739
}
740
741
static int
742
tar_done(Pax_t* pax, register Archive_t* ap)
743
{
744
if (ap->data)
745
{
746
free(ap->data);
747
ap->data = 0;
748
}
749
return 0;
750
}
751
752
static int
753
tar_putprologue(Pax_t* pax, register Archive_t* ap, int append)
754
{
755
if (!(ap->data = newof(0, Tar_t, 1, 0)))
756
nospace();
757
return 0;
758
}
759
760
static int
761
tar_putheader(Pax_t* pax, Archive_t* ap, register File_t* f)
762
{
763
register Tar_t* tar = (Tar_t*)ap->data;
764
register char* s;
765
off_t n;
766
int i;
767
768
if (f->extended)
769
i = 0;
770
else
771
switch (ap->format->variant)
772
{
773
case PAX:
774
i = extend(ap, f, EXTTYPE);
775
break;
776
case TAR:
777
if ((i = tar_longname(ap, f)) < 0)
778
{
779
if (state.strict)
780
{
781
ap->entry--;
782
return 0;
783
}
784
synthesize(ap, f, headname(ap, f, "@PaxPathText.%(sequence)s"), LREGTYPE, f->name, f->namesize);
785
}
786
if (tar_longlink(ap, f) < 0)
787
{
788
if (state.strict)
789
{
790
ap->entry--;
791
return 0;
792
}
793
synthesize(ap, f, headname(ap, f, "@PaxLinkText.%(sequence)s"), LLNKTYPE, f->linkpath, strlen(f->linkpath) + 1);
794
}
795
break;
796
case OLD:
797
if ((i = tar_longname(ap, f)) || tar_longlink(ap, f))
798
{
799
ap->entry--;
800
return 0;
801
}
802
break;
803
}
804
if (state.complete)
805
complete(ap, f, (ap->format->variant == PAX ? 4 : 1) * TAR_HEADER);
806
memzero(&tar->header, TAR_HEADER);
807
if (f->longname)
808
s = headname(ap, f, "@PaxPathFile.%(sequence)s");
809
else
810
{
811
if (i)
812
{
813
memcpy(tar->header.prefix, f->name, i);
814
i++;
815
}
816
s = f->name + i;
817
}
818
sfsprintf(tar->header.name, TARSIZEOF(name) + 1, "%s%s", s, f->type == X_IFDIR ? "/" : "");
819
i = 0;
820
if (f->extended)
821
tar->header.typeflag = f->extended;
822
else
823
switch (f->linktype)
824
{
825
case HARDLINK:
826
tar->header.typeflag = LNKTYPE;
827
linked:
828
sfsprintf(tar->header.linkname, TARSIZEOF(linkname) + 1, "%s", f->longlink ? headname(ap, f, "@PaxLinkFile.%(sequence)s") : f->linkpath);
829
break;
830
case SOFTLINK:
831
tar->header.typeflag = SYMTYPE;
832
goto linked;
833
default:
834
switch (ap->format->variant == OLD ? X_IFREG : f->type)
835
{
836
case X_IFCHR:
837
tar->header.typeflag = CHRTYPE;
838
i = 1;
839
break;
840
case X_IFBLK:
841
tar->header.typeflag = BLKTYPE;
842
i = 1;
843
break;
844
case X_IFDIR:
845
tar->header.typeflag = DIRTYPE;
846
break;
847
case X_IFIFO:
848
tar->header.typeflag = FIFOTYPE;
849
break;
850
#ifdef SOKTYPE
851
case X_IFSOCK:
852
tar->header.typeflag = SOKTYPE;
853
i = 1;
854
break;
855
#endif
856
default:
857
if (!f->skip && !f->delta.op)
858
error(1, "%s: %s: unknown file type %07o -- regular file assumed", ap->name, f->name, f->type);
859
/*FALLTHROUGH*/
860
case X_IFREG:
861
tar->header.typeflag = REGTYPE;
862
break;
863
}
864
break;
865
}
866
sfsprintf(tar->header.devmajor, TARSIZEOF(devmajor), "%0*o ", TARSIZEOF(devmajor) - 1, i ? major(idevice(f->st)) : 0);
867
sfsprintf(tar->header.devminor, TARSIZEOF(devminor), "%0*o ", TARSIZEOF(devminor) - 1, i ? minor(idevice(f->st)) : 0);
868
sfsprintf(tar->header.mode, TARSIZEOF(mode), "%0*o ", TARSIZEOF(mode) - 1, f->st->st_mode & X_IPERM);
869
sfsprintf(tar->header.uid, TARSIZEOF(uid), "%0*lo ", TARSIZEOF(uid) - 1, f->st->st_uid & (unsigned long)07777777);
870
sfsprintf(tar->header.gid, TARSIZEOF(gid), "%0*lo ", TARSIZEOF(gid) - 1, f->st->st_gid & (unsigned long)07777777);
871
if (ap->format->variant != PAX && (unsigned long)f->st->st_size > (unsigned long)037777777777)
872
{
873
tar->header.size[0] = TAR_LARGENUM;
874
n = f->st->st_size;
875
for (i = 11; i > 0; i--)
876
{
877
tar->header.size[i] = n & 0377;
878
n >>= 8;
879
}
880
}
881
else
882
sfsprintf(tar->header.size, TARSIZEOF(size), "%0*lo ", TARSIZEOF(size) - 1, (long)f->st->st_size);
883
sfsprintf(tar->header.mtime, TARSIZEOF(mtime), "%0*lo ", TARSIZEOF(mtime) - 1, f->st->st_mtime & (unsigned long)037777777777);
884
if (ap->format->variant != OLD)
885
{
886
strncpy(tar->header.magic, TMAGIC, TARSIZEOF(magic));
887
strncpy(tar->header.version, TVERSION, TARSIZEOF(version));
888
getidnames(f);
889
strcpy(tar->header.uname, f->uidname);
890
strcpy(tar->header.gname, f->gidname);
891
}
892
sfsprintf(tar->header.chksum, TARSIZEOF(chksum), "%0*lo ", TARSIZEOF(chksum) - 1, tar_checksum(ap, 0, 0));
893
paxwrite(pax, ap, &tar->header, TAR_HEADER);
894
return 1;
895
}
896
897
static off_t
898
tar_putepilogue(Pax_t* pax, Archive_t* ap)
899
{
900
register Tar_t* tar = (Tar_t*)ap->data;
901
902
memzero(&tar->header, TAR_HEADER);
903
paxwrite(pax, ap, &tar->header, TAR_HEADER);
904
paxwrite(pax, ap, &tar->header, TAR_HEADER);
905
return ap->io->unblocked ? BLOCKSIZE : state.blocksize;
906
}
907
908
static int
909
tar_lookup(Pax_t* pax, Archive_t* ap, File_t* f, int index, char** s, Sflong_t* n)
910
{
911
register Tar_t* tar = (Tar_t*)ap->data;
912
913
switch (index)
914
{
915
case OPT_chksum:
916
*s = tar->header.chksum;
917
break;
918
case OPT_magic:
919
*s = tar->header.magic;
920
break;
921
case OPT_typeflag:
922
*n = tar->header.typeflag;
923
break;
924
case OPT_version:
925
*s = tar->header.version;
926
break;
927
default:
928
return 0;
929
}
930
return 1;
931
}
932
933
static int
934
tar_event(Pax_t* pax, Archive_t* ap, File_t* f, void* data, unsigned long event)
935
{
936
register Tarheader_t* hdr;
937
unsigned long sum;
938
939
switch (event)
940
{
941
case PAX_EVENT_DELTA_EXTEND:
942
putkey(ap, ap->tmp.global, &options[OPT_delta_index], NiL, ap->delta->index + 1);
943
extend(ap, NiL, GLBTYPE);
944
return 1;
945
case PAX_EVENT_SKIP_JUNK:
946
hdr = (Tarheader_t*)data;
947
if (!isdigit(hdr->chksum[0]) || !isdigit(hdr->chksum[1]) || !isdigit(hdr->chksum[2]) || !isdigit(hdr->chksum[3]) || !isdigit(hdr->chksum[4]) || !isdigit(hdr->chksum[5]) || !isdigit(hdr->chksum[6]) || tar_getoctal("chksum", hdr->chksum, 7, sizeof(sum), &sum) || !tar_checksum(ap, -1, sum))
948
return 1;
949
return 0;
950
}
951
return 0;
952
}
953
954
static int
955
pax_putprologue(Pax_t* pax, register Archive_t* ap, int append)
956
{
957
Format_t* fp;
958
Hash_position_t* hp;
959
Option_t* op;
960
Delta_format_t* dp;
961
962
if (!(ap->data = newof(0, Tar_t, 1, 0)) || !(ap->tmp.global = sfstropen()) || !(ap->tmp.extended = sfstropen()) || !(ap->tmp.key = sfstropen()))
963
nospace();
964
if (append)
965
return 0;
966
if (hp = hashscan(state.options, 0))
967
{
968
while (hashnext(hp))
969
{
970
op = (Option_t*)hp->bucket->value;
971
if ((op->flags & OPT_GLOBAL) && op->name == hp->bucket->name && (op->level == 3 || op->level == 0) && op->perm.string)
972
putkey(ap, ap->tmp.global, op, op->perm.string, 0);
973
}
974
hashdone(hp);
975
}
976
if (ap->delta && !(ap->delta->format->flags & PSEUDO))
977
{
978
fp = ap->delta->format;
979
putkey(ap, ap->tmp.global, &options[OPT_delta_method], fp->name, 0);
980
if ((dp = (Delta_format_t*)fp->data) && dp->variant)
981
putkey(ap, ap->tmp.global, &options[OPT_delta_version], dp->variant, 0);
982
if (ap->delta->compress)
983
putkey(ap, ap->tmp.global, &options[OPT_delta_compress], 0, 1);
984
if (ap->delta->base)
985
{
986
putkey(ap, ap->tmp.global, &options[OPT_delta_base_size], NiL, ap->delta->base->size);
987
putkey(ap, ap->tmp.global, &options[OPT_delta_base_checksum], NiL, ap->delta->base->checksum & 0xffffffff);
988
}
989
}
990
extend(ap, NiL, GLBTYPE);
991
return 1;
992
}
993
994
Format_t pax_tar_format =
995
{
996
"oldtar",
997
0,
998
"pre-POSIX tar with symlinks",
999
OLD,
1000
ARCHIVE|LINKTYPE|SLASHDIR|IN|OUT|APPEND,
1001
DEFBUFFER,
1002
DEFBLOCKS,
1003
BLOCKSIZE,
1004
PAXNEXT(tar),
1005
0,
1006
tar_done,
1007
tar_getprologue,
1008
tar_getheader,
1009
0,
1010
0,
1011
0,
1012
tar_putprologue,
1013
tar_putheader,
1014
0,
1015
0,
1016
tar_putepilogue,
1017
0,
1018
0,
1019
0,
1020
0,
1021
tar_event,
1022
PAX_EVENT_SKIP_JUNK
1023
};
1024
1025
Format_t pax_pax_format =
1026
{
1027
"pax",
1028
0,
1029
"POSIX 1003.1-2001 extended ustar",
1030
PAX,
1031
ARCHIVE|DELTAINFO|LINKTYPE|SLASHDIR|STANDARD|SUM|IN|OUT|APPEND,
1032
DEFBUFFER,
1033
DEFBLOCKS,
1034
BLOCKSIZE,
1035
PAXNEXT(pax),
1036
0,
1037
tar_done,
1038
tar_getprologue,
1039
tar_getheader,
1040
0,
1041
0,
1042
0,
1043
pax_putprologue,
1044
tar_putheader,
1045
0,
1046
0,
1047
tar_putepilogue,
1048
0,
1049
0,
1050
0,
1051
0,
1052
tar_event,
1053
PAX_EVENT_DELTA_EXTEND
1054
};
1055
1056
Format_t pax_ustar_format =
1057
{
1058
"ustar",
1059
"tar",
1060
"POSIX 1003.1-1988 tar",
1061
TAR,
1062
ARCHIVE|LINKTYPE|SLASHDIR|IN|OUT|APPEND,
1063
DEFBUFFER,
1064
DEFBLOCKS,
1065
BLOCKSIZE,
1066
PAXNEXT(ustar),
1067
0,
1068
tar_done,
1069
tar_getprologue,
1070
tar_getheader,
1071
0,
1072
0,
1073
0,
1074
tar_putprologue,
1075
tar_putheader,
1076
0,
1077
0,
1078
tar_putepilogue,
1079
tar_lookup,
1080
0,
1081
0,
1082
0,
1083
tar_event,
1084
PAX_EVENT_SKIP_JUNK
1085
};
1086
1087
PAXLIB(ustar)
1088
1089