pax-tar.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1987-2011 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* pax { pax tar ustar } formats
*/
#include "format.h"
#define PAX 1
#define OLD 2
#define TAR 3
#define TAR_HEADER TBLOCK
#define TAR_LARGENUM 0200
typedef struct Tar_s
{
int lastindex; /* last[] index */
} Tar_t;
/*
* output extended header keyword assignment record
*/
void
{
register size_t n;
register size_t m;
register size_t o;
if (value)
else
{
}
o = 0;
for (;;)
{
if (m == o)
break;
n += m - o;
o = m;
}
if (value)
else
}
/*
* compute tar->header checksum
*/
static unsigned long
{
register unsigned char* p;
register unsigned char* e;
register unsigned char* t;
register unsigned long u;
register unsigned long s;
register long c;
register const unsigned char* map;
t = tmp;
while (p < e)
{
*t++ = *p;
*p++ = ' ';
}
u = 0;
s = 0;
e = p + TAR_HEADER;
while (p < e)
{
c = *p++;
u += c;
if (check)
{
if (c & 0x80)
c |= (-1) << 8;
s += c;
}
}
else
{
map = ((ap->mio.mode & O_ACCMODE) == O_WRONLY) ? ap->convert[SECTION_CONTROL].f2t : ap->convert[SECTION_CONTROL].t2f;
while (p < e)
{
c = map[*p++];
u += c;
if (check)
{
if (c & 0x80)
c |= (-1) << 8;
s += c;
}
}
}
t = tmp;
while (p < e)
*p++ = *t++;
u &= TAR_SUMASK;
if (check)
{
if ((sum &= TAR_SUMASK) == u)
return 1;
if (sum == (s &= TAR_SUMASK))
{
{
}
return 1;
}
{
if (s != u)
error(state.keepgoing ? 1 : 3, "%s: %s format checksum error (%ld != %ld or %ld)", ap->name, ap->format->name, sum, u, s);
else
error(state.keepgoing ? 1 : 3, "%s: %s format checksum error (%ld != %ld)", ap->name, ap->format->name, sum, u);
}
return 0;
}
return u;
}
/*
* check if tar file name may be split to fit in header
* return
* <0 extension header required with error message for non-extension formats
* 0 no split needed
* >0 f->name offset to split
*/
static int
{
register char* s;
register char* b;
register int n;
return 0;
{
case PAX:
case TAR:
{
goto toolong;
f->longname = 1;
return -1;
}
s = f->name + n;
while (--s >= b)
{
if (!n)
break;
return s - f->name;
}
{
f->skip = 1;
}
else
f->longname = 1;
return -1;
case OLD:
error(2, "%s: file name too long -- %d max", f->name, TARSIZEOF(prefix) + TARSIZEOF(name) + !!strchr(f->name, '/'));
f->skip = 1;
return -1;
}
return 0;
}
/*
* check if f->linkpath is too long
* return
* <0 extension header required with error message for non-extension formats
* 0 it fits
*/
static int
{
{
{
case TAR:
break;
/*FALLTHROUGH*/
case OLD:
f->skip = 1;
return -1;
}
f->longlink = 1;
return -1;
}
return 0;
}
/*
* generate extended header path name from fmt
*/
static char*
{
char* s;
char* t;
size_t n;
nospace();
{
s = f->name;
if (t = strrchr(s, '/'))
f->name = t + 1;
f->name = s;
}
nospace();
return s;
}
/*
* synthesize an extended tar header
*/
static void
{
char* base;
char* next;
File_t h;
}
/*
* output an extended tar header
* some keys may already be in the header buffer for type
*/
static int
{
unsigned long n;
char* s;
char* fmt;
int lev;
int alt;
int split;
File_t h;
char num[64];
if (!f)
switch (type)
{
case EXTTYPE:
lev = 7;
alt = 4;
break;
case GLBTYPE:
lev = 3;
alt = 0;
break;
default:
return 0;
}
{
{
if ((op->flags & (OPT_HEADER|OPT_READONLY)) == OPT_HEADER && op->name == pos->bucket->name && (op->level == lev || op->level == alt))
{
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));
{
case OPT_atime:
case OPT_ctime:
case OPT_mtime:
continue;
else
{
{
case OPT_atime:
break;
case OPT_mtime:
break;
case OPT_ctime:
break;
}
continue;
while (*(s - 1) == '0')
s--;
if (*(s - 1) == '.')
*s++ = '0';
*s = 0;
s = num;
}
break;
case OPT_comment:
break;
case OPT_gid:
else
{
continue;
}
break;
case OPT_gname:
f->gidname = s;
continue;
s = f->gidname;
break;
case OPT_size:
#if _typ_int64_t
continue;
continue;
break;
#else
continue;
#endif
case OPT_uid:
else
{
continue;
}
break;
case OPT_uname:
f->uidname = s;
continue;
s = f->uidname;
break;
default:
break;
}
if (s)
}
}
}
{
}
else
split = 0;
{
nospace();
}
return split;
}
static int
tar_getoctal(const char* f, const char* p, size_t n, int z, void* r)
{
register unsigned char* s = (unsigned char*)p;
register unsigned char* e = s + n;
register uintmax_t v = 0;
while (s < e && *s == ' ')
s++;
while (s < e && *s >= '0' && *s <= '7')
v = (v << 3) + (*s++ - '0');
if (s < e)
{
if (*s == 0x80 || *s == 0xff)
{
v = *s++ == 0x80 ? 0 : 0xff;
e = (unsigned char*)p + 8;
while (s < e)
v = (v << 8) + *s++;
}
else if (*s && *s != ' ')
return -1;
}
switch (z)
{
case 1:
*(unsigned char*)r = (unsigned char)v;
break;
case 2:
break;
case 4:
break;
#ifdef _ast_int8_t
case 8:
break;
#endif
}
return 0;
}
static int
{
char* s;
char* t;
off_t n;
long num;
int i;
int m;
return 0;
{
goto nope;
return 0;
}
goto nope;
goto nope;
goto nope;
goto nope;
goto nope;
{
{
for (i = 1; i < 4; i++)
{
{
goto again;
}
}
}
goto nope;
}
goto nope;
{
{
/* old gnu tar */;
goto nope;
}
{
tp = &pax_tar_format;
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);
}
}
{
sfsprintf(f->name, TARSIZEOF(prefix) + TARSIZEOF(name) + 2, "%-.*s/%-.*s", TARSIZEOF(prefix), tar->header.prefix, TARSIZEOF(name), tar->header.name);
}
else
f->linkpath = 0;
{
case LNKTYPE:
break;
case SYMTYPE:
break;
case CHRTYPE:
goto nope;
goto nope;
break;
case BLKTYPE:
goto device;
case DIRTYPE:
break;
case FIFOTYPE:
break;
#ifdef SOKTYPE
case SOKTYPE:
break;
#endif
case EXTTYPE:
case GLBTYPE:
{
}
gettrailer(ap, f);
f->extended = 0;
goto again;
case LLNKTYPE:
case LREGTYPE:
{
{
return 0;
}
}
gettrailer(ap, f);
goto again;
case VERTYPE:
goto regular;
default:
error(1, "%s: %s: unknown %s format file type `%c' -- regular file assumed", ap->name, f->name, ap->format->name, tar->header.typeflag);
/*FALLTHROUGH*/
case REGTYPE:
case AREGTYPE:
case CONTTYPE:
break;
}
f->uidname = 0;
f->gidname = 0;
{
}
return 1;
nope:
return 0;
}
static int
tar_getprologue(Pax_t* pax, Format_t* fp, register Archive_t* ap, File_t* f, unsigned char* buf, size_t size)
{
int n;
nospace();
else
{
}
return n;
}
static int
{
{
}
return 0;
}
static int
{
nospace();
return 0;
}
static int
{
register char* s;
off_t n;
int i;
if (f->extended)
i = 0;
else
{
case PAX:
break;
case TAR:
if ((i = tar_longname(ap, f)) < 0)
{
{
return 0;
}
}
if (tar_longlink(ap, f) < 0)
{
{
return 0;
}
synthesize(ap, f, headname(ap, f, "@PaxLinkText.%(sequence)s"), LLNKTYPE, f->linkpath, strlen(f->linkpath) + 1);
}
break;
case OLD:
{
return 0;
}
break;
}
if (f->longname)
else
{
if (i)
{
i++;
}
s = f->name + i;
}
i = 0;
if (f->extended)
else
switch (f->linktype)
{
case HARDLINK:
sfsprintf(tar->header.linkname, TARSIZEOF(linkname) + 1, "%s", f->longlink ? headname(ap, f, "@PaxLinkFile.%(sequence)s") : f->linkpath);
break;
case SOFTLINK:
goto linked;
default:
{
case X_IFCHR:
i = 1;
break;
case X_IFBLK:
i = 1;
break;
case X_IFDIR:
break;
case X_IFIFO:
break;
#ifdef SOKTYPE
case X_IFSOCK:
i = 1;
break;
#endif
default:
/*FALLTHROUGH*/
case X_IFREG:
break;
}
break;
}
sfsprintf(tar->header.devmajor, TARSIZEOF(devmajor), "%0*o ", TARSIZEOF(devmajor) - 1, i ? major(idevice(f->st)) : 0);
sfsprintf(tar->header.devminor, TARSIZEOF(devminor), "%0*o ", TARSIZEOF(devminor) - 1, i ? minor(idevice(f->st)) : 0);
sfsprintf(tar->header.mode, TARSIZEOF(mode), "%0*o ", TARSIZEOF(mode) - 1, f->st->st_mode & X_IPERM);
sfsprintf(tar->header.uid, TARSIZEOF(uid), "%0*lo ", TARSIZEOF(uid) - 1, f->st->st_uid & (unsigned long)07777777);
sfsprintf(tar->header.gid, TARSIZEOF(gid), "%0*lo ", TARSIZEOF(gid) - 1, f->st->st_gid & (unsigned long)07777777);
{
for (i = 11; i > 0; i--)
{
n >>= 8;
}
}
else
sfsprintf(tar->header.mtime, TARSIZEOF(mtime), "%0*lo ", TARSIZEOF(mtime) - 1, f->st->st_mtime & (unsigned long)037777777777);
{
getidnames(f);
}
sfsprintf(tar->header.chksum, TARSIZEOF(chksum), "%0*lo ", TARSIZEOF(chksum) - 1, tar_checksum(ap, 0, 0));
return 1;
}
static off_t
{
}
static int
{
switch (index)
{
case OPT_chksum:
break;
case OPT_magic:
break;
case OPT_typeflag:
break;
case OPT_version:
break;
default:
return 0;
}
return 1;
}
static int
{
register Tarheader_t* hdr;
unsigned long sum;
switch (event)
{
case PAX_EVENT_DELTA_EXTEND:
return 1;
case PAX_EVENT_SKIP_JUNK:
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))
return 1;
return 0;
}
return 0;
}
static int
{
if (!(ap->data = newof(0, Tar_t, 1, 0)) || !(ap->tmp.global = sfstropen()) || !(ap->tmp.extended = sfstropen()) || !(ap->tmp.key = sfstropen()))
nospace();
if (append)
return 0;
{
{
if ((op->flags & OPT_GLOBAL) && op->name == hp->bucket->name && (op->level == 3 || op->level == 0) && op->perm.string)
}
}
{
{
putkey(ap, ap->tmp.global, &options[OPT_delta_base_checksum], NiL, ap->delta->base->checksum & 0xffffffff);
}
}
return 1;
}
{
"oldtar",
0,
"pre-POSIX tar with symlinks",
OLD,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
{
"pax",
0,
"POSIX 1003.1-2001 extended ustar",
PAX,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};
{
"ustar",
"tar",
"POSIX 1003.1-1988 tar",
TAR,
0,
0,
0,
0,
0,
0,
0,
0,
0,
};