/* @(#)header.c 1.73 03/02/01 Copyright 1985, 1995 J. Schilling */
#ifndef lint
static char sccsid[] =
"@(#)header.c 1.73 03/02/01 Copyright 1985, 1995 J. Schilling";
#endif
/*
* Handling routines to read/write, parse/create
* archive headers
*
* Copyright (c) 1985, 1995 J. Schilling
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; see the file COPYING. If not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <mconfig.h>
#include <stdio.h>
#include <stdxlib.h>
#include "star.h"
#include "props.h"
#include "table.h"
#include <dirdefs.h>
#include <standard.h>
#include <strdefs.h>
#define __XDEV__ /* Needed to activate _dev_major()/_dev_minor() */
#include <device.h>
#include <schily.h>
#include "starsubs.h"
/* ustar */
LOCAL char magic[TMAGLEN] = TMAGIC;
/* star */
LOCAL char stmagic[STMAGLEN] = STMAGIC;
/* gnu tar */
LOCAL char gmagic[GMAGLEN] = GMAGIC;
LOCAL char *hdrtxt[] = {
/* 0 */ "UNDEFINED",
/* 1 */ "unknown tar",
/* 2 */ "old tar",
/* 3 */ "star",
/* 4 */ "gnu tar",
/* 5 */ "ustar",
/* 6 */ "xstar",
/* 7 */ "xustar",
/* 8 */ "exustar",
/* 9 */ "pax", /* USTAR POSIX.1-2001 */
/*10 */ "suntar",
/*11 */ "res11", /* Reserved */
/*12 */ "res12", /* Reserved */
/*13 */ "res13", /* Reserved */
/*14 */ "res14", /* Reserved */
/*15 */ "bar",
/*16 */ "cpio binary",
/*17 */ "cpio -c",
/*18 */ "cpio",
/*19 */ "cpio crc",
/*20 */ "cpio ascii",
/*21 */ "cpio ascii crc",
};
extern FILE *tty;
extern FILE *vpr;
extern long hdrtype;
extern long chdrtype;
extern int version;
extern int swapflg;
extern BOOL debug;
extern BOOL numeric;
extern int verbose;
extern BOOL xflag;
extern BOOL nflag;
extern BOOL ignoreerr;
extern BOOL signedcksum;
extern BOOL nowarn;
extern BOOL nullout;
extern BOOL modebits;
extern Ullong tsize;
extern char *bigbuf;
extern int bigsize;
LOCAL Ulong checksum __PR((TCB * ptb));
LOCAL Ulong bar_checksum __PR((TCB * ptb));
LOCAL BOOL signedtarsum __PR((TCB *ptb, Ulong ocheck));
LOCAL BOOL isstmagic __PR((char* s));
LOCAL BOOL isxmagic __PR((TCB *ptb));
LOCAL BOOL ismagic __PR((char* s));
LOCAL BOOL isgnumagic __PR((char* s));
LOCAL BOOL strxneql __PR((char* s1, char* s2, int l));
LOCAL BOOL ustmagcheck __PR((TCB * ptb));
LOCAL void print_hdrtype __PR((int type));
EXPORT int get_hdrtype __PR((TCB * ptb, BOOL isrecurse));
EXPORT int get_compression __PR((TCB * ptb));
EXPORT int get_tcb __PR((TCB * ptb));
EXPORT void put_tcb __PR((TCB * ptb, FINFO * info));
EXPORT void write_tcb __PR((TCB * ptb, FINFO * info));
EXPORT void put_volhdr __PR((char* name));
EXPORT BOOL get_volhdr __PR((FINFO * info, char* vhname));
EXPORT void info_to_tcb __PR((FINFO * info, TCB * ptb));
LOCAL void info_to_star __PR((FINFO * info, TCB * ptb));
LOCAL void info_to_ustar __PR((FINFO * info, TCB * ptb));
LOCAL void info_to_xstar __PR((FINFO * info, TCB * ptb));
LOCAL void info_to_gnutar __PR((FINFO * info, TCB * ptb));
EXPORT int tcb_to_info __PR((TCB * ptb, FINFO * info));
LOCAL void tar_to_info __PR((TCB * ptb, FINFO * info));
LOCAL void star_to_info __PR((TCB * ptb, FINFO * info));
LOCAL void ustar_to_info __PR((TCB * ptb, FINFO * info));
LOCAL void xstar_to_info __PR((TCB * ptb, FINFO * info));
LOCAL void gnutar_to_info __PR((TCB * ptb, FINFO * info));
LOCAL void cpiotcb_to_info __PR((TCB * ptb, FINFO * info));
LOCAL int ustoxt __PR((int ustype));
EXPORT BOOL ia_change __PR((TCB * ptb, FINFO * info));
LOCAL BOOL checkeof __PR((TCB * ptb));
LOCAL BOOL eofblock __PR((TCB * ptb));
LOCAL void astoo_cpio __PR((char* s, Ulong * l, int cnt));
LOCAL void stoli __PR((char* s, Ulong * l));
EXPORT void stolli __PR((char* s, Ullong * ull));
LOCAL void litos __PR((char* s, Ulong l, int fieldw));
EXPORT void llitos __PR((char* s, Ullong ull, int fieldw));
LOCAL void stob __PR((char* s, Ulong * l, int fieldw));
LOCAL void stollb __PR((char* s, Ullong * ull, int fieldw));
LOCAL void btos __PR((char* s, Ulong l, int fieldw));
LOCAL void llbtos __PR((char* s, Ullong ull, int fieldw));
EXPORT void dump_info __PR((FINFO *info));
/*
* XXX Hier sollte eine tar/bar universelle Checksummenfunktion sein!
*/
#define CHECKS sizeof(ptb->ustar_dbuf.t_chksum)
/*
* We know, that sizeof(TCP) is 512 and therefore has no
* reminder when dividing by 8
*
* CHECKS is known to be 8 too, use loop unrolling.
*/
#define DO8(a) a;a;a;a;a;a;a;a;
LOCAL Ulong
checksum(ptb)
register TCB *ptb;
{
register int i;
register Ulong sum = 0;
register Uchar *us;
if (signedcksum) {
register char *ss;
ss = (char *)ptb;
for (i=sizeof(*ptb)/8; --i >= 0;) {
DO8(sum += *ss++);
}
if (sum == 0L) /* Block containing 512 nul's */
return(sum);
ss=(char *)ptb->ustar_dbuf.t_chksum;
DO8(sum -= *ss++);
sum += CHECKS*' ';
} else {
us = (Uchar *)ptb;
for (i=sizeof(*ptb)/8; --i >= 0;) {
DO8(sum += *us++);
}
if (sum == 0L) /* Block containing 512 nul's */
return(sum);
us=(Uchar *)ptb->ustar_dbuf.t_chksum;
DO8(sum -= *us++);
sum += CHECKS*' ';
}
return sum;
}
#undef CHECKS
#define CHECKS sizeof(ptb->bar_dbuf.t_chksum)
LOCAL Ulong
bar_checksum(ptb)
register TCB *ptb;
{
register int i;
register Ulong sum = 0;
register Uchar *us;
if (signedcksum) {
register char *ss;
ss = (char *)ptb;
for (i=sizeof(*ptb); --i >= 0;)
sum += *ss++;
if (sum == 0L) /* Block containing 512 nul's */
return(sum);
for (i=CHECKS, ss=(char *)ptb->bar_dbuf.t_chksum; --i >= 0;)
sum -= *ss++;
sum += CHECKS*' ';
} else {
us = (Uchar *)ptb;
for (i=sizeof(*ptb); --i >= 0;)
sum += *us++;
if (sum == 0L) /* Block containing 512 nul's */
return(sum);
for (i=CHECKS, us=(Uchar *)ptb->bar_dbuf.t_chksum; --i >= 0;)
sum -= *us++;
sum += CHECKS*' ';
}
return sum;
}
#undef CHECKS
LOCAL BOOL
signedtarsum(ptb, ocheck)
TCB *ptb;
Ulong ocheck;
{
BOOL osigned = signedcksum;
Ulong check;
signedcksum = !signedcksum;
check = checksum(ptb);
if (ocheck == check) {
errmsgno(EX_BAD, "WARNING: archive uses %s checksums.\n",
signedcksum?"signed":"unsigned");
return (TRUE);
}
signedcksum = osigned;
return (FALSE);
}
LOCAL BOOL
isstmagic(s)
char *s;
{
return (strxneql(s, stmagic, STMAGLEN));
}
/*
* Check for XUSTAR format.
*
* This is star's upcoming new standard format. This format understands star's
* old extended POSIX format and in future will write POSIX.1-2001 extensions
* using 'x' headers.
*/
LOCAL BOOL
isxmagic(ptb)
TCB *ptb;
{
register int i;
/*
* prefix[130] is is granted to be '\0' with 'xstar'.
*/
if (ptb->xstar_dbuf.t_prefix[130] != '\0')
return (FALSE);
/*
* If atime[0]...atime[10] or ctime[0]...ctime[10]
* is not a POSIX octal number it cannot be 'xstar'.
* With the octal representation we may store any date
* for 1970 +- 136 years (1834 ... 2106). After 2106
* we will most likely always use POSIX.1-2001 'x'
* headers and thus don't need to check for base 256
* numbers.
*/
for (i = 0; i < 11; i++) {
if (ptb->xstar_dbuf.t_atime[i] < '0' ||
ptb->xstar_dbuf.t_atime[i] > '7')
return (FALSE);
if (ptb->xstar_dbuf.t_ctime[i] < '0' ||
ptb->xstar_dbuf.t_ctime[i] > '7')
return (FALSE);
}
/*
* Check for both POSIX compliant end of number characters.
*/
if ((ptb->xstar_dbuf.t_atime[11] != ' ' &&
ptb->xstar_dbuf.t_atime[11] != '\0') ||
(ptb->xstar_dbuf.t_ctime[11] != ' ' &&
ptb->xstar_dbuf.t_ctime[11] != '\0'))
return (FALSE);
return (TRUE);
}
LOCAL BOOL
ismagic(s)
char *s;
{
return (strxneql(s, magic, TMAGLEN));
}
LOCAL BOOL
isgnumagic(s)
char *s;
{
return (strxneql(s, gmagic, GMAGLEN));
}
LOCAL BOOL
strxneql(s1, s2, l)
register char *s1;
register char *s2;
register int l;
{
while (--l >= 0)
if (*s1++ != *s2++)
return (FALSE);
return (TRUE);
}
LOCAL BOOL
ustmagcheck(ptb)
TCB *ptb;
{
if (ismagic(ptb->xstar_dbuf.t_magic) &&
strxneql(ptb->xstar_dbuf.t_version, "00", 2))
return (TRUE);
return (FALSE);
}
LOCAL void
print_hdrtype(type)
int type;
{
BOOL isswapped = H_ISSWAPPED(type);
if (H_TYPE(type) > H_MAX_ARCH)
type = H_UNDEF;
type = H_TYPE(type);
error("%s%s archive.\n", isswapped?"swapped ":"", hdrtxt[type]);
}
EXPORT int
get_hdrtype(ptb, isrecurse)
TCB *ptb;
BOOL isrecurse;
{
Ulong check;
Ulong ocheck;
int ret = H_UNDEF;
stoli(ptb->dbuf.t_chksum, &ocheck);
check = checksum(ptb);
if (ocheck != check && !signedtarsum(ptb, ocheck)) {
if (debug && !isrecurse) {
errmsgno(EX_BAD,
"Bad tar checksum at: %lld: 0%lo should be 0%lo.\n",
tblocks(),
ocheck, check);
}
goto nottar;
}
if (isstmagic(ptb->dbuf.t_magic)) { /* Check for 'tar\0' at end */
if (ustmagcheck(ptb))
ret = H_XSTAR;
else
ret = H_STAR;
if (debug) print_hdrtype(ret);
return (ret);
}
if (ustmagcheck(ptb)) { /* 'ustar\000' POSIX magic */
if (isxmagic(ptb)) {
if (ptb->ustar_dbuf.t_typeflag == 'g' ||
ptb->ustar_dbuf.t_typeflag == 'x')
ret = H_EXUSTAR;
else
ret = H_XUSTAR;
} else {
if (ptb->ustar_dbuf.t_typeflag == 'g' ||
ptb->ustar_dbuf.t_typeflag == 'x')
ret = H_PAX;
else if (ptb->ustar_dbuf.t_typeflag == 'X')
ret = H_SUNTAR;
else
ret = H_USTAR;
}
if (debug) print_hdrtype(ret);
return (ret);
}
if (isgnumagic(&ptb->dbuf.t_vers)) { /* 'ustar ' GNU magic */
ret = H_GNUTAR;
if (debug) print_hdrtype(ret);
return (ret);
}
if ((ptb->dbuf.t_mode[6] == ' ' && ptb->dbuf.t_mode[7] == '\0')) {
ret = H_OTAR;
if (debug) print_hdrtype(ret);
return (ret);
}
if (ptb->ustar_dbuf.t_typeflag == LF_VOLHDR ||
ptb->ustar_dbuf.t_typeflag == LF_MULTIVOL) {
/*
* Gnu volume headers & multi volume headers
* are no real tar headers.
*/
if (debug) error("gnutar buggy archive.\n");
ret = H_GNUTAR;
if (debug) print_hdrtype(ret);
return (ret);
}
/*
* The only thing we know here is:
* we found a header with a correct tar checksum.
*/
ret = H_TAR;
if (debug) print_hdrtype(ret);
return (ret);
nottar:
if (ptb->bar_dbuf.bar_magic[0] == 'V') {
stoli(ptb->bar_dbuf.t_chksum, &ocheck);
check = bar_checksum(ptb);
if (ocheck == check) {
ret = H_BAR;
if (debug) print_hdrtype(ret);
return (ret);
} else if (debug && !isrecurse) {
errmsgno(EX_BAD,
"Bad bar checksum at: %lld: 0%lo should be 0%lo.\n",
tblocks(),
ocheck, check);
}
}
if (strxneql((char *)ptb, "070701", 6)) {
ret = H_CPIO_ASC;
if (debug) print_hdrtype(ret);
return (ret);
}
if (strxneql((char *)ptb, "070702", 6)) {
ret = H_CPIO_ACRC;
if (debug) print_hdrtype(ret);
return (ret);
}
if (strxneql((char *)ptb, "070707", 6)) {
ret = H_CPIO_CHR;
if (debug) print_hdrtype(ret);
return (ret);
}
if (strxneql((char *)ptb, "\161\301", 2)) {
ret = H_CPIO_NBIN;
if (debug) print_hdrtype(ret);
return (ret);
}
if (strxneql((char *)ptb, "\161\302", 2)) {
ret = H_CPIO_CRC;
if (debug) print_hdrtype(ret);
return (ret);
}
if (strxneql((char *)ptb, "\161\307", 2)) {
ret = H_CPIO_BIN;
if (debug) print_hdrtype(ret);
return (ret);
}
if (debug) error("no tar archive??\n");
if (!isrecurse) {
int rret;
swabbytes((char *)ptb, TBLOCK);
rret = get_hdrtype(ptb, TRUE);
swabbytes((char *)ptb, TBLOCK);
rret = H_SWAPPED(rret);
if (debug) print_hdrtype(rret);
return (rret);
}
if (debug) print_hdrtype(ret);
return (ret);
}
EXPORT int
get_compression(ptb)
TCB *ptb;
{
char *p = (char *)ptb;
if (p[0] == '\037') {
if ((p[1] == '\037') || /* Packed */
(p[1] == '\213') || /* Gzip compressed */
(p[1] == '\235') || /* LZW compressed */
(p[1] == '\236') || /* Freezed */
(p[1] == '\240')) /* SCO LZH compressed*/
return (C_GZIP);
}
if (p[0] == 'B' && p[1] == 'Z' && p[2] == 'h')
return (C_BZIP2);
return (C_NONE);
}
EXPORT int
get_tcb(ptb)
TCB *ptb;
{
Ulong check;
Ulong ocheck;
BOOL eof;
do {
/*
* bei der Option -i wird ein genulltes File
* fehlerhaft als EOF Block erkannt !
* wenn nicht t_magic gesetzt ist.
*/
if (readblock((char *)ptb) == EOF) {
errmsgno(EX_BAD, "Hard EOF on input, first EOF block is missing.\n");
return (EOF);
}
/*
* First tar control block
*/
if (swapflg < 0) {
BOOL swapped;
hdrtype = get_hdrtype(ptb, FALSE);
swapped = H_ISSWAPPED(hdrtype);
if (chdrtype != H_UNDEF &&
swapped != H_ISSWAPPED(chdrtype)) {
swapped = H_ISSWAPPED(chdrtype);
}
if (swapped) {
swapflg = 1;
swabbytes((char *)ptb, TBLOCK); /* copy of TCB*/
swabbytes(bigbuf, bigsize); /* io buffer */
} else {
swapflg = 0;
}
/*
* wake up fifo (first block ist swapped)
*/
buf_resume();
if (H_TYPE(hdrtype) == H_BAR) {
comerrno(EX_BAD, "Can't handle bar archives (yet).\n");
}
if (H_TYPE(hdrtype) >= H_CPIO_BASE) {
/* XXX JS Test */if (H_TYPE(hdrtype) == H_CPIO_CHR) {
/* XXX JS Test */FINFO info;
/* XXX JS Test */tcb_to_info(ptb, &info);
/* XXX JS Test */}
comerrno(EX_BAD, "Can't handle cpio archives (yet).\n");
}
if (H_TYPE(hdrtype) == H_UNDEF) {
switch (get_compression(ptb)) {
case C_GZIP:
comerrno(EX_BAD, "Archive is compressed, try to use the -z option.\n");
break;
case C_BZIP2:
comerrno(EX_BAD, "Archive is bzip2 compressed, try to use the -bz option.\n");
break;
}
if (!ignoreerr) {
comerrno(EX_BAD,
"Unknown archive type (neither tar, nor bar/cpio).\n");
}
}
if (chdrtype != H_UNDEF && chdrtype != hdrtype) {
errmsgno(EX_BAD, "Found: ");
print_hdrtype(hdrtype);
errmsgno(EX_BAD, "WARNING: extracting as ");
print_hdrtype(chdrtype);
hdrtype = chdrtype;
}
setprops(hdrtype);
}
eof = (ptb->dbuf.t_name[0] == '\0') && checkeof(ptb);
if (eof && !ignoreerr) {
return (EOF);
}
/*
* XXX Hier muß eine Universalchecksummenüberprüfung hin
*/
stoli(ptb->dbuf.t_chksum, &ocheck);
check = checksum(ptb);
/*
* check == 0 : genullter Block.
*/
if (check != 0 && ocheck == check) {
char *tmagic = ptb->ustar_dbuf.t_magic;
switch (H_TYPE(hdrtype)) {
case H_XUSTAR:
case H_EXUSTAR:
if (ismagic(tmagic) && isxmagic(ptb))
return (0);
/*
* Both formats are equivalent.
* Acept XSTAR too.
*/
/* FALLTHROUGH */
case H_XSTAR:
if (ismagic(tmagic) &&
isstmagic(ptb->xstar_dbuf.t_xmagic))
return (0);
break;
case H_PAX:
case H_USTAR:
case H_SUNTAR:
if (ismagic(tmagic))
return (0);
break;
case H_GNUTAR:
if (isgnumagic(tmagic))
return (0);
break;
case H_STAR:
tmagic = ptb->star_dbuf.t_magic;
if (ptb->dbuf.t_vers < STVERSION ||
isstmagic(tmagic))
return (0);
break;
default:
case H_TAR:
case H_OTAR:
return (0);
}
errmsgno(EX_BAD, "Wrong magic at: %lld: '%.8s'.\n",
tblocks(), tmagic);
/*
* Allow buggy gnu Volheaders & Multivolheaders to work
*/
if (H_TYPE(hdrtype) == H_GNUTAR)
return (0);
} else if (eof) {
errmsgno(EX_BAD, "EOF Block at: %lld ignored.\n",
tblocks());
} else {
if (signedtarsum(ptb, ocheck))
return (0);
errmsgno(EX_BAD, "Checksum error at: %lld: 0%lo should be 0%lo.\n",
tblocks(),
ocheck, check);
}
} while (ignoreerr);
exprstats(EX_BAD);
/* NOTREACHED */
return (EOF); /* Keep lint happy */
}
EXPORT void
put_tcb(ptb, info)
TCB *ptb;
register FINFO *info;
{
TCB tb;
int x1 = 0;
int x2 = 0;
if (info->f_flags & (F_LONGNAME|F_LONGLINK))
x1++;
if (info->f_xflags & (XF_PATH|XF_LINKPATH))
x1++;
/*XXX start alter code und Test */
if (( (info->f_flags & F_ADDSLASH) ? 1:0 +
info->f_namelen > props.pr_maxsname &&
(ptb->dbuf.t_prefix[0] == '\0' || H_TYPE(hdrtype) == H_GNUTAR)) ||
info->f_lnamelen > props.pr_maxslname)
x2++;
if ((x1 != x2) && info->f_xftype != XT_META) {
error("type: %ld name: '%s' x1 %d x2 %d namelen: %ld prefix: '%s' lnamelen: %ld\n",
info->f_filetype, info->f_name, x1, x2,
info->f_namelen, ptb->dbuf.t_prefix, info->f_lnamelen);
}
/*XXX ende alter code und Test */
if (x1 || x2 || (info->f_xflags != 0)) {
if ((info->f_flags & F_TCB_BUF) != 0) { /* TCB is on buffer */
movetcb(ptb, &tb);
ptb = &tb;
info->f_flags &= ~F_TCB_BUF;
}
if (info->f_xflags != 0)
info_to_xhdr(info, ptb);
else
write_longnames(info);
}
write_tcb(ptb, info);
}
EXPORT void
write_tcb(ptb, info)
TCB *ptb;
register FINFO *info;
{
if (tsize > 0) {
TCB tb;
Llong left;
off_t size = info->f_rsize;
left = tsize - tblocks();
if (is_link(info))
size = 0L;
/* file + tcb + EOF */
if (left < (tarblocks(size)+1+2)) {
if ((info->f_flags & F_TCB_BUF) != 0) {
movetcb(ptb, &tb);
ptb = &tb;
info->f_flags &= ~F_TCB_BUF;
}
nexttape();
}
}
if (!nullout) { /* 17 (> 16) Bit !!! */
if (props.pr_fillc == '0')
litos(ptb->dbuf.t_chksum, checksum(ptb) & 0x1FFFF, 7);
else
litos(ptb->dbuf.t_chksum, checksum(ptb) & 0x1FFFF, 6);
}
if ((info->f_flags & F_TCB_BUF) != 0) /* TCB is on buffer */
put_block();
else
writeblock((char *)ptb);
}
EXPORT void
put_volhdr(name)
char *name;
{
FINFO finfo;
TCB tb;
struct timeval tv;
if (name == 0)
return;
if ((props.pr_flags & PR_VOLHDR) == 0)
return;
gettimeofday(&tv, (struct timezone *)0);
fillbytes((char *)&finfo, sizeof (FINFO), '\0');
filltcb(&tb);
finfo.f_name = name;
finfo.f_namelen = strlen(name);
finfo.f_xftype = XT_VOLHDR;
finfo.f_mtime = tv.tv_sec;
finfo.f_mnsec = tv.tv_usec*1000;
finfo.f_tcb = &tb;
if (!name_to_tcb(&finfo, &tb)) /* Name too long */
return;
info_to_tcb(&finfo, &tb);
put_tcb(&tb, &finfo);
vprint(&finfo);
}
EXPORT BOOL
get_volhdr(info, vhname)
FINFO *info;
char *vhname;
{
error("Volhdr: %s\n", info->f_name);
if (vhname) {
return (streql(info->f_name, vhname));
} else {
return (TRUE);
}
}
EXPORT void
info_to_tcb(info, ptb)
register FINFO *info;
register TCB *ptb;
{
if (nullout)
return;
if (props.pr_fillc == '0') {
/*
* This is a POSIX compliant header, it is allowed to use
* 7 bytes from 8 byte headers as POSIX only requires a ' ' or
* '\0' as last char.
*/
if (modebits)
litos(ptb->dbuf.t_mode, (info->f_mode|info->f_type) & 0xFFFF, 7);
else
litos(ptb->dbuf.t_mode, info->f_mode & 0xFFFF, 7);
if (info->f_uid > MAXOCTAL7 && (props.pr_flags & PR_XHDR)) {
info->f_xflags |= XF_UID;
}
/* XXX */
litos(ptb->dbuf.t_uid, info->f_uid & MAXOCTAL7, 7);
if (info->f_gid > MAXOCTAL7 && (props.pr_flags & PR_XHDR)) {
info->f_xflags |= XF_GID;
}
/* XXX */
litos(ptb->dbuf.t_gid, info->f_gid & MAXOCTAL7, 7);
} else {
/*
* This is a pre POSIX header, it is only allowed to use
* 6 bytes from 8 byte headers as historic TAR requires a ' '
* and a '\0' as last char.
*/
if (modebits)
litos(ptb->dbuf.t_mode, (info->f_mode|info->f_type) & 0xFFFF, 6);
else
litos(ptb->dbuf.t_mode, info->f_mode & 0xFFFF, 6);
if (info->f_uid > MAXOCTAL6 && (props.pr_flags & PR_XHDR)) {
info->f_xflags |= XF_UID;
}
/* XXX */
litos(ptb->dbuf.t_uid, info->f_uid & MAXOCTAL6, 6);
if (info->f_gid > MAXOCTAL7 && (props.pr_flags & PR_XHDR)) {
info->f_xflags |= XF_GID;
}
/* XXX */
litos(ptb->dbuf.t_gid, info->f_gid & MAXOCTAL6, 6);
}
if (info->f_rsize > MAXOCTAL11 && (props.pr_flags & PR_XHDR)) {
info->f_xflags |= XF_SIZE;
}
/* XXX */
if (info->f_rsize <= MAXINT32) {
litos(ptb->dbuf.t_size, (Ulong)info->f_rsize, 11);
} else {
if (info->f_rsize > MAXOCTAL11 &&
(props.pr_flags & PR_BASE256) == 0) {
litos(ptb->dbuf.t_size, (Ulong)0, 11);
} else {
llitos(ptb->dbuf.t_size, (Ullong)info->f_rsize, 11);
}
}
litos(ptb->dbuf.t_mtime, (Ulong)info->f_mtime, 11);
ptb->dbuf.t_linkflag = XTTOUS(info->f_xftype);
if (H_TYPE(hdrtype) == H_USTAR) {
info_to_ustar(info, ptb);
} else if (H_TYPE(hdrtype) == H_PAX) {
info_to_ustar(info, ptb);
} else if (H_TYPE(hdrtype) == H_SUNTAR) {
info_to_ustar(info, ptb);
} else if (H_TYPE(hdrtype) == H_XSTAR) {
info_to_xstar(info, ptb);
} else if (H_TYPE(hdrtype) == H_XUSTAR) {
info_to_xstar(info, ptb);
} else if (H_TYPE(hdrtype) == H_EXUSTAR) {
info_to_xstar(info, ptb);
} else if (H_TYPE(hdrtype) == H_GNUTAR) {
info_to_gnutar(info, ptb);
} else if (H_TYPE(hdrtype) == H_STAR) {
info_to_star(info, ptb);
}
}
/*
* Used to create old star format header.
*/
LOCAL void
info_to_star(info, ptb)
register FINFO *info;
register TCB *ptb;
{
ptb->dbuf.t_vers = STVERSION;
litos(ptb->dbuf.t_filetype, info->f_filetype & 0xFFFF, 6); /* XXX -> 7 ??? */
litos(ptb->dbuf.t_type, info->f_type & 0xFFFF, 11);
#ifdef needed
/* XXX we need to do something if st_rdev is > 32 bits */
if ((info->f_rdevmaj > MAXOCTAL7 || info->f_rdevmin > MAXOCTAL7) &&
(props.pr_flags & PR_XHDR)) {
info->f_xflags |= XF_DEVMAJOR|XF_DEVMINOR;
}
#endif
litos(ptb->dbuf.t_rdev, info->f_rdev, 11);
#ifdef DEV_MINOR_NONCONTIG
ptb->dbuf.t_devminorbits = '@';
if (props.pr_flags & PR_XHDR) {
info->f_xflags |= XF_DEVMAJOR|XF_DEVMINOR;
}
#else
ptb->dbuf.t_devminorbits = '@' + minorbits;
#endif
litos(ptb->dbuf.t_atime, (Ulong)info->f_atime, 11);
litos(ptb->dbuf.t_ctime, (Ulong)info->f_ctime, 11);
/* strcpy(ptb->dbuf.t_magic, stmagic);*/
ptb->dbuf.t_magic[0] = 't';
ptb->dbuf.t_magic[1] = 'a';
ptb->dbuf.t_magic[2] = 'r';
if (!numeric) {
nameuid(ptb->dbuf.t_uname, STUNMLEN, info->f_uid);
/* XXX Korrektes overflowchecking */
if (ptb->dbuf.t_uname[STUNMLEN-1] != '\0' &&
props.pr_flags & PR_XHDR) {
info->f_xflags |= XF_UNAME;
}
namegid(ptb->dbuf.t_gname, STGNMLEN, info->f_gid);
/* XXX Korrektes overflowchecking */
if (ptb->dbuf.t_gname[STGNMLEN-1] != '\0' &&
props.pr_flags & PR_XHDR) {
info->f_xflags |= XF_GNAME;
}
if (*ptb->dbuf.t_uname) {
info->f_uname = ptb->dbuf.t_uname;
info->f_umaxlen = STUNMLEN;
}
if (*ptb->dbuf.t_gname) {
info->f_gname = ptb->dbuf.t_gname;
info->f_gmaxlen = STGNMLEN;
}
}
if (is_sparse(info)) {
if (info->f_size > MAXOCTAL11 && (props.pr_flags & PR_XHDR)) {
info->f_xflags |= XF_REALSIZE;
}
/* XXX Korrektes overflowchecking fuer xhdr */
if (info->f_size <= MAXINT32) {
litos(ptb->xstar_in_dbuf.t_realsize, (Ulong)info->f_size, 11);
} else {
llitos(ptb->xstar_in_dbuf.t_realsize, (Ullong)info->f_size, 11);
}
}
}
/*
* Used to create USTAR, PAX, SunTAR format header.
*/
LOCAL void
info_to_ustar(info, ptb)
register FINFO *info;
register TCB *ptb;
{
/* strcpy(ptb->ustar_dbuf.t_magic, magic);*/
ptb->ustar_dbuf.t_magic[0] = 'u';
ptb->ustar_dbuf.t_magic[1] = 's';
ptb->ustar_dbuf.t_magic[2] = 't';
ptb->ustar_dbuf.t_magic[3] = 'a';
ptb->ustar_dbuf.t_magic[4] = 'r';
/* strncpy(ptb->ustar_dbuf.t_version, TVERSION, TVERSLEN);*/
/*
* strncpy is slow: use handcrafted replacement.
*/
ptb->ustar_dbuf.t_version[0] = '0';
ptb->ustar_dbuf.t_version[1] = '0';
if (!numeric) {
/* XXX Korrektes overflowchecking fuer xhdr */
nameuid(ptb->ustar_dbuf.t_uname, TUNMLEN, info->f_uid);
/* XXX Korrektes overflowchecking fuer xhdr */
namegid(ptb->ustar_dbuf.t_gname, TGNMLEN, info->f_gid);
if (*ptb->ustar_dbuf.t_uname) {
info->f_uname = ptb->ustar_dbuf.t_uname;
info->f_umaxlen = TUNMLEN;
}
if (*ptb->ustar_dbuf.t_gname) {
info->f_gname = ptb->ustar_dbuf.t_gname;
info->f_gmaxlen = TGNMLEN;
}
}
if (info->f_rdevmaj > MAXOCTAL7 && (props.pr_flags & PR_XHDR)) {
info->f_xflags |= XF_DEVMAJOR;
}
/* XXX */
litos(ptb->ustar_dbuf.t_devmajor, info->f_rdevmaj, 7);
#if DEV_MINOR_BITS > 21 /* XXX */
/*
* XXX The DEV_MINOR_BITS autoconf macro is only tested with 32 bit
* XXX ints but this does not matter as it is sufficient to know that
* XXX it will not fit into a 7 digit octal number.
*/
if (info->f_rdevmin > MAXOCTAL7) {
extern BOOL hpdev;
if (props.pr_flags & PR_XHDR) {
info->f_xflags |= XF_DEVMINOR;
}
if ((info->f_rdevmin <= MAXOCTAL8) && hpdev) {
char c;
/*
* Implement the method from HP-UX that allows 24 bit
* for the device minor number. Note that this method
* violates the POSIX specs.
*/
c = ptb->ustar_dbuf.t_prefix[0];
litos(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 8);
ptb->ustar_dbuf.t_prefix[0] = c;
} else {
/*
* XXX If we ever need to write more than a long into
* XXX devmajor, we need to change llitos() to check
* XXX for 7 char limits too.
*/
/* XXX */
btos(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 7);
}
} else
#endif
{
litos(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 7);
}
}
/*
* Used to create XSTAR, XUSTAR, EXUSTAR format header.
*/
LOCAL void
info_to_xstar(info, ptb)
register FINFO *info;
register TCB *ptb;
{
info_to_ustar(info, ptb);
litos(ptb->xstar_dbuf.t_atime, (Ulong)info->f_atime, 11);
litos(ptb->xstar_dbuf.t_ctime, (Ulong)info->f_ctime, 11);
/*
* Help recognition in isxmagic(), make sure that prefix[130] is null.
*/
ptb->xstar_dbuf.t_prefix[130] = '\0';
if (H_TYPE(hdrtype) == H_XSTAR) {
/* strcpy(ptb->xstar_dbuf.t_xmagic, stmagic);*/
ptb->xstar_dbuf.t_xmagic[0] = 't';
ptb->xstar_dbuf.t_xmagic[1] = 'a';
ptb->xstar_dbuf.t_xmagic[2] = 'r';
}
if (is_sparse(info)) {
if (info->f_size > MAXOCTAL11 && (props.pr_flags & PR_XHDR)) {
info->f_xflags |= XF_REALSIZE;
}
/* XXX Korrektes overflowchecking fuer xhdr */
if (info->f_size <= MAXINT32) {
litos(ptb->xstar_in_dbuf.t_realsize, (Ulong)info->f_size, 11);
} else {
llitos(ptb->xstar_in_dbuf.t_realsize, (Ullong)info->f_size, 11);
}
}
}
/*
* Used to create GNU tar format header.
*/
LOCAL void
info_to_gnutar(info, ptb)
register FINFO *info;
register TCB *ptb;
{
strcpy(ptb->gnu_dbuf.t_magic, gmagic);
if (!numeric) {
nameuid(ptb->ustar_dbuf.t_uname, TUNMLEN, info->f_uid);
namegid(ptb->ustar_dbuf.t_gname, TGNMLEN, info->f_gid);
if (*ptb->ustar_dbuf.t_uname) {
info->f_uname = ptb->ustar_dbuf.t_uname;
info->f_umaxlen = TUNMLEN;
}
if (*ptb->ustar_dbuf.t_gname) {
info->f_gname = ptb->ustar_dbuf.t_gname;
info->f_gmaxlen = TGNMLEN;
}
}
if (info->f_xftype == XT_CHR || info->f_xftype == XT_BLK) {
litos(ptb->ustar_dbuf.t_devmajor, info->f_rdevmaj, 6); /* XXX -> 7 ??? */
litos(ptb->ustar_dbuf.t_devminor, info->f_rdevmin, 6); /* XXX -> 7 ??? */
}
/*
* XXX GNU tar only fill this if doing a gnudump.
*/
litos(ptb->gnu_dbuf.t_atime, (Ulong)info->f_atime, 11);
litos(ptb->gnu_dbuf.t_ctime, (Ulong)info->f_ctime, 11);
if (is_sparse(info)) {
if (info->f_size <= MAXINT32) {
litos(ptb->gnu_in_dbuf.t_realsize, (Ulong)info->f_size, 11);
} else {
llitos(ptb->gnu_in_dbuf.t_realsize, (Ullong)info->f_size, 11);
}
}
}
EXPORT int
tcb_to_info(ptb, info)
register TCB *ptb;
register FINFO *info;
{
int ret = 0;
char xname;
char xlink;
char xpfx;
Ulong ul;
Ullong ull;
int xt = XT_BAD;
int rxt = XT_BAD;
static BOOL posixwarn = FALSE;
static BOOL namewarn = FALSE;
static BOOL modewarn = FALSE;
/*
* F_HAS_NAME is only used from list.c when the -listnew option is
* present. Keep f_lname and f_name, don't read LF_LONGLINK/LF_LONGNAME
* in this case.
*/
if ((info->f_flags & F_HAS_NAME) == 0)
info->f_lname = ptb->dbuf.t_linkname;
info->f_uname = info->f_gname = NULL;
info->f_umaxlen = info->f_gmaxlen = 0L;
info->f_xftype = XT_BAD;
info->f_rxftype = XT_BAD;
info->f_xflags = 0;
info->f_contoffset = (off_t)0;
info->f_flags &= F_HAS_NAME;
info->f_fflags = 0L;
info->f_nlink = 0;
info->f_dir = NULL;
/* XXX JS Test */if (H_TYPE(hdrtype) >= H_CPIO_BASE) {
/* XXX JS Test */cpiotcb_to_info(ptb, info);
/* XXX JS Test */list_file(info);
/* XXX JS Test */return (ret);
/* XXX JS Test */}
while (pr_isxheader(ptb->dbuf.t_linkflag)) {
/*
* Handle POSIX.1-2001 extensions.
*/
if ((ptb->dbuf.t_linkflag == LF_XHDR ||
ptb->dbuf.t_linkflag == LF_VU_XHDR)) {
ret = tcb_to_xhdr(ptb, info);
if (ret != 0)
return (ret);
xt = info->f_xftype;
rxt = info->f_rxftype;
}
/*
* Handle very long names the old (star & gnutar) way.
*/
if ((info->f_flags & F_HAS_NAME) == 0 &&
props.pr_nflags & PR_LONG_NAMES) {
while (ptb->dbuf.t_linkflag == LF_LONGLINK ||
ptb->dbuf.t_linkflag == LF_LONGNAME) {
ret = tcb_to_longname(ptb, info);
}
}
}
if (!pr_validtype(ptb->dbuf.t_linkflag)) {
errmsgno(EX_BAD,
"WARNING: Archive contains unknown typeflag '%c' (0x%02X).\n",
ptb->dbuf.t_linkflag, ptb->dbuf.t_linkflag);
}
if (ptb->dbuf.t_name[NAMSIZ] == '\0') {
if (ptb->dbuf.t_name[NAMSIZ-1] == '\0') {
if (!nowarn && !modewarn) {
errmsgno(EX_BAD,
"WARNING: Archive violates POSIX 1003.1 (mode field starts with null byte).\n");
modewarn = TRUE;
}
} else if (!nowarn && !namewarn) {
errmsgno(EX_BAD,
"WARNING: Archive violates POSIX 1003.1 (100 char filename is null terminated).\n");
namewarn = TRUE;
}
ptb->dbuf.t_name[NAMSIZ] = ' ';
}
stoli(ptb->dbuf.t_mode, &info->f_mode);
if (info->f_mode & ~07777) {
if (!nowarn && !modebits && H_TYPE(hdrtype) == H_USTAR && !posixwarn) {
errmsgno(EX_BAD,
"WARNING: Archive violates POSIX 1003.1 (too many bits in mode field).\n");
posixwarn = TRUE;
}
info->f_mode &= 07777;
}
if ((info->f_xflags & XF_UID) == 0)
stoli(ptb->dbuf.t_uid, &info->f_uid);
if ((info->f_xflags & XF_UID) == 0)
stoli(ptb->dbuf.t_gid, &info->f_gid);
if ((info->f_xflags & XF_SIZE) == 0) {
stolli(ptb->dbuf.t_size, &ull);
info->f_size = ull;
}
switch (ptb->dbuf.t_linkflag) {
case LNKTYPE:
case DIRTYPE:
case CHRTYPE:
case BLKTYPE:
case FIFOTYPE:
case LF_META:
info->f_rsize = 0L;
break;
default:
if ((info->f_xflags & XF_SIZE) == 0)
info->f_rsize = info->f_size;
break;
}
if ((info->f_xflags & XF_MTIME) == 0) {
stoli(ptb->dbuf.t_mtime, &ul);
info->f_mtime = (time_t)ul;
info->f_mnsec = 0L;
}
info->f_typeflag = ptb->ustar_dbuf.t_typeflag;
switch (H_TYPE(hdrtype)) {
default:
case H_TAR:
case H_OTAR:
tar_to_info(ptb, info);
break;
case H_PAX:
case H_USTAR:
case H_SUNTAR:
ustar_to_info(ptb, info);
break;
case H_XSTAR:
case H_XUSTAR:
case H_EXUSTAR:
xstar_to_info(ptb, info);
break;
case H_GNUTAR:
gnutar_to_info(ptb, info);
break;
case H_STAR:
star_to_info(ptb, info);
break;
}
info->f_rxftype = info->f_xftype;
if (rxt != XT_BAD) {
info->f_rxftype = rxt;
info->f_filetype = XTTOST(info->f_rxftype);
info->f_type = XTTOIF(info->f_rxftype);
/*
* XT_LINK may be any 'real' file type,
* XT_META may be either a regular file or a contigouos file.
*/
if (info->f_xftype != XT_LINK && info->f_xftype != XT_META)
info->f_xftype = info->f_rxftype;
}
if (xt != XT_BAD) {
info->f_xftype = xt;
}
/*
* Hack for list module (option -newest) ...
* Save and restore t_name[NAMSIZ] & t_linkname[NAMSIZ]
*/
xname = ptb->dbuf.t_name[NAMSIZ];
ptb->dbuf.t_name[NAMSIZ] = '\0'; /* allow 100 chars in name */
xlink = ptb->dbuf.t_linkname[NAMSIZ];
ptb->dbuf.t_linkname[NAMSIZ] = '\0';/* allow 100 chars in linkname */
xpfx = ptb->dbuf.t_prefix[PFXSIZ];
ptb->dbuf.t_prefix[PFXSIZ] = '\0'; /* allow 155 chars in prefix*/
/*
* Handle long name in posix split form now.
* Also copy ptb->dbuf.t_linkname[] if namelen is == 100.
*/
tcb_to_name(ptb, info);
ptb->dbuf.t_name[NAMSIZ] = xname; /* restore remembered value */
ptb->dbuf.t_linkname[NAMSIZ] = xlink; /* restore remembered value */
ptb->dbuf.t_prefix[PFXSIZ] = xpfx; /* restore remembered value */
return (ret);
}
/*
* Used to convert from old tar format header.
*/
LOCAL void
tar_to_info(ptb, info)
register TCB *ptb;
register FINFO *info;
{
register int typeflag = ptb->ustar_dbuf.t_typeflag;
if (ptb->dbuf.t_name[strlen(ptb->dbuf.t_name) - 1] == '/') {
typeflag = DIRTYPE;
info->f_filetype = F_DIR;
info->f_rsize = (off_t)0; /* XXX hier?? siehe oben */
} else if (typeflag == SYMTYPE) {
info->f_filetype = F_SLINK;
} else if (typeflag != DIRTYPE) {
info->f_filetype = F_FILE;
}
info->f_xftype = USTOXT(typeflag);
info->f_type = XTTOIF(info->f_xftype);
info->f_rdevmaj = info->f_rdevmin = info->f_rdev = 0;
info->f_ctime = info->f_atime = info->f_mtime;
info->f_cnsec = info->f_ansec = 0L;
}
/*
* Used to convert from old star format header.
*/
LOCAL void
star_to_info(ptb, info)
register TCB *ptb;
register FINFO *info;
{
Ulong id;
Ullong ull;
int mbits;
version = ptb->dbuf.t_vers;
if (ptb->dbuf.t_vers < STVERSION) {
tar_to_info(ptb, info);
return;
}
stoli(ptb->dbuf.t_filetype, &info->f_filetype);
stoli(ptb->dbuf.t_type, &info->f_type);
/*
* star Erweiterungen sind wieder ANSI kompatibel, d.h. linkflag
* hält den echten Dateityp (LONKLINK, LONGNAME, SPARSE ...)
*/
if(ptb->dbuf.t_linkflag < '1')
info->f_xftype = IFTOXT(info->f_type);
else
info->f_xftype = USTOXT(ptb->ustar_dbuf.t_typeflag);
stoli(ptb->dbuf.t_rdev, &info->f_rdev);
if ((info->f_xflags & (XF_DEVMAJOR|XF_DEVMINOR)) !=
(XF_DEVMAJOR|XF_DEVMINOR)) {
mbits = ptb->dbuf.t_devminorbits - '@';
if (mbits == 0) {
static BOOL dwarned = FALSE;
if (!dwarned) {
errmsgno(EX_BAD,
#ifdef DEV_MINOR_NONCONTIG
"WARNING: Minor device numbers are non contiguous, devices may not be extracted correctly.\n");
#else
"WARNING: The archiving system used non contiguous minor numbers, cannot extract devices correctly.\n");
#endif
dwarned = TRUE;
}
/*
* Let us hope that both, the archiving and the
* extracting system use the same major()/minor()
* mapping.
*/
info->f_rdevmaj = major(info->f_rdev);
info->f_rdevmin = minor(info->f_rdev);
} else {
/*
* Convert from remote major()/minor() mapping to
* local major()/minor() mapping.
*/
if (mbits < 0) /* Old star format */
mbits = 8;
info->f_rdevmaj = _dev_major(mbits, info->f_rdev);
info->f_rdevmin = _dev_minor(mbits, info->f_rdev);
info->f_rdev = makedev(info->f_rdevmaj, info->f_rdevmin);
}
}
if ((info->f_xflags & XF_ATIME) == 0) {
stoli(ptb->dbuf.t_atime, &id);
info->f_atime = (time_t)id;
info->f_ansec = 0L;
}
if ((info->f_xflags & XF_CTIME) == 0) {
stoli(ptb->dbuf.t_ctime, &id);
info->f_ctime = (time_t)id;
info->f_cnsec = 0L;
}
if ((info->f_xflags & XF_UNAME) == 0) {
if (*ptb->dbuf.t_uname) {
info->f_uname = ptb->dbuf.t_uname;
info->f_umaxlen = STUNMLEN;
}
}
if (info->f_uname) {
if (!numeric && uidname(info->f_uname, info->f_umaxlen, &id))
info->f_uid = id;
}
if ((info->f_xflags & XF_GNAME) == 0) {
if (*ptb->dbuf.t_gname) {
info->f_gname = ptb->dbuf.t_gname;
info->f_gmaxlen = STGNMLEN;
}
}
if (info->f_gname) {
if (!numeric && gidname(info->f_gname, info->f_gmaxlen, &id))
info->f_gid = id;
}
if (is_sparse(info)) {
if ((info->f_xflags & XF_REALSIZE) == 0) {
stolli(ptb->xstar_in_dbuf.t_realsize, &ull);
info->f_size = ull;
}
}
if (is_multivol(info)) {
stolli(ptb->xstar_in_dbuf.t_offset, &ull);
info->f_contoffset = ull;
}
}
/*
* Used to convert from USTAR, PAX, SunTAR format header.
*/
LOCAL void
ustar_to_info(ptb, info)
register TCB *ptb;
register FINFO *info;
{
Ulong id;
char c;
info->f_xftype = USTOXT(ptb->ustar_dbuf.t_typeflag);
info->f_filetype = XTTOST(info->f_xftype);
info->f_type = XTTOIF(info->f_xftype);
if ((info->f_xflags & XF_UNAME) == 0) {
if (*ptb->ustar_dbuf.t_uname) {
info->f_uname = ptb->ustar_dbuf.t_uname;
info->f_umaxlen = TUNMLEN;
}
}
if (info->f_uname) {
if (!numeric && uidname(info->f_uname, info->f_umaxlen, &id))
info->f_uid = id;
}
if ((info->f_xflags & XF_GNAME) == 0) {
if (*ptb->ustar_dbuf.t_gname) {
info->f_gname = ptb->ustar_dbuf.t_gname;
info->f_gmaxlen = TGNMLEN;
}
}
if (info->f_gname) {
if (!numeric && gidname(info->f_gname, info->f_gmaxlen, &id))
info->f_gid = id;
}
if ((info->f_xflags & XF_DEVMAJOR) == 0)
stoli(ptb->ustar_dbuf.t_devmajor, &info->f_rdevmaj);
if ((info->f_xflags & XF_DEVMINOR) == 0) {
if (ptb->ustar_dbuf.t_devminor[0] & 0x80) {
stob(ptb->ustar_dbuf.t_devminor, &info->f_rdevmin, 7);
} else {
/*
* The 'tar' that comes with HP-UX writes illegal tar
* archives. It includes 8 characters in the minor
* field and allows to archive 24 bits for the minor
* device which are used by HP-UX. As we like to be
* able to read these archives, we need to convert
* the number carefully by temporarily writing a NULL
* to the next character and restoring the right
* content afterwards.
*/
c = ptb->ustar_dbuf.t_prefix[0];
ptb->ustar_dbuf.t_prefix[0] = '\0';
stoli(ptb->ustar_dbuf.t_devminor, &info->f_rdevmin);
ptb->ustar_dbuf.t_prefix[0] = c;
}
}
info->f_rdev = makedev(info->f_rdevmaj, info->f_rdevmin);
/*
* ANSI Tar hat keine atime & ctime im Header!
*/
if ((info->f_xflags & XF_ATIME) == 0) {
info->f_atime = info->f_mtime;
info->f_ansec = 0L;
}
if ((info->f_xflags & XF_CTIME) == 0) {
info->f_ctime = info->f_mtime;
info->f_cnsec = 0L;
}
}
/*
* Used to convert from XSTAR, XUSTAR, EXUSTAR format header.
*/
LOCAL void
xstar_to_info(ptb, info)
register TCB *ptb;
register FINFO *info;
{
Ulong ul;
Ullong ull;
ustar_to_info(ptb, info);
if ((info->f_xflags & XF_ATIME) == 0) {
stoli(ptb->xstar_dbuf.t_atime, &ul);
info->f_atime = (time_t)ul;
info->f_ansec = 0L;
}
if ((info->f_xflags & XF_CTIME) == 0) {
stoli(ptb->xstar_dbuf.t_ctime, &ul);
info->f_ctime = (time_t)ul;
info->f_cnsec = 0L;
}
if (is_sparse(info)) {
if ((info->f_xflags & XF_REALSIZE) == 0) {
stolli(ptb->xstar_in_dbuf.t_realsize, &ull);
info->f_size = ull;
}
}
if (is_multivol(info)) {
stolli(ptb->xstar_in_dbuf.t_offset, &ull);
info->f_contoffset = ull;
}
}
/*
* Used to convert from GNU tar format header.
*/
LOCAL void
gnutar_to_info(ptb, info)
register TCB *ptb;
register FINFO *info;
{
Ulong ul;
Ullong ull;
ustar_to_info(ptb, info);
if ((info->f_xflags & XF_ATIME) == 0) {
stoli(ptb->gnu_dbuf.t_atime, &ul);
info->f_atime = (time_t)ul;
info->f_ansec = 0L;
if (info->f_atime == 0 && ptb->gnu_dbuf.t_atime[0] == '\0')
info->f_atime = info->f_mtime;
}
if ((info->f_xflags & XF_CTIME) == 0) {
stoli(ptb->gnu_dbuf.t_ctime, &ul);
info->f_ctime = (time_t)ul;
info->f_cnsec = 0L;
if (info->f_ctime == 0 && ptb->gnu_dbuf.t_ctime[0] == '\0')
info->f_ctime = info->f_mtime;
}
if (is_sparse(info)) {
stolli(ptb->gnu_in_dbuf.t_realsize, &ull);
info->f_size = ull;
}
if (is_multivol(info)) {
stolli(ptb->gnu_dbuf.t_offset, &ull);
info->f_contoffset = ull;
}
}
/*
* XXX vorerst nur zum Test!
*/
LOCAL void
cpiotcb_to_info(ptb, info)
register TCB *ptb;
register FINFO *info;
{
Ulong ul;
astoo_cpio(&((char *)ptb)[6], &ul, 6);
info->f_dev = ul;
astoo_cpio(&((char *)ptb)[12], &ul, 6);
info->f_ino = ul;
error("ino: %lld\n", (Llong)info->f_ino);
astoo_cpio(&((char *)ptb)[18], &info->f_mode, 6);
error("mode: %lo\n", info->f_mode);
info->f_type = info->f_mode & S_IFMT;
info->f_mode = info->f_mode & 07777;
info->f_xftype = IFTOXT(info->f_type);
info->f_filetype = XTTOST(info->f_xftype);
astoo_cpio(&((char *)ptb)[24], &info->f_uid, 6);
astoo_cpio(&((char *)ptb)[30], &info->f_gid, 6);
astoo_cpio(&((char *)ptb)[36], &info->f_nlink, 6);
astoo_cpio(&((char *)ptb)[42], &info->f_rdev, 6);
astoo_cpio(&((char *)ptb)[48], &ul, 11);
info->f_atime = (time_t)ul;
astoo_cpio(&((char *)ptb)[59], &info->f_namelen, 6);
astoo_cpio(&((char *)ptb)[65], &ul, 11);
info->f_size = ul;
info->f_rsize = info->f_size;
info->f_name = &((char *)ptb)[76];
}
LOCAL int
ustoxt(ustype)
char ustype;
{
/*
* Map ANSI types
*/
if (ustype >= REGTYPE && ustype <= CONTTYPE)
return _USTOXT(ustype);
/*
* Map Vendor Unique (Gnu tar & Star) types ANSI: "local enhancements"
*/
if ((props.pr_flags & (PR_LOCAL_STAR|PR_LOCAL_GNU)) &&
ustype >= 'A' && ustype <= 'Z')
return _VTTOXT(ustype);
/*
* treat unknown types as regular files conforming to standard
*/
return (XT_FILE);
}
/* ARGSUSED */
EXPORT BOOL
ia_change(ptb, info)
TCB *ptb;
FINFO *info;
{
char buf[NAMSIZ+1]; /* XXX nur 100 chars ?? */
char ans;
int len;
if (verbose)
list_file(info);
else
vprint(info);
if (nflag)
return (FALSE);
fprintf(vpr, "get/put ? Y(es)/N(o)/C(hange name) :");fflush(vpr);
fgetline(tty, buf, 2);
if ((ans = toupper(buf[0])) == 'Y')
return (TRUE);
else if (ans == 'C') {
for(;;) {
fprintf(vpr, "Enter new name:");
fflush(vpr);
if ((len = fgetline(tty, buf, sizeof buf)) == 0)
continue;
if (len > sizeof(buf) - 1)
errmsgno(EX_BAD, "Name too long.\n");
else
break;
}
strcpy(info->f_name, buf); /* XXX nur 100 chars ?? */
if (xflag && newer(info))
return (FALSE);
return (TRUE);
}
return (FALSE);
}
LOCAL BOOL
checkeof(ptb)
TCB *ptb;
{
if (!eofblock(ptb))
return (FALSE);
if (debug)
errmsgno(EX_BAD, "First EOF Block OK\n");
markeof();
if (readblock((char *)ptb) == EOF) {
errmsgno(EX_BAD, "Incorrect EOF, second EOF block is missing.\n");
return (TRUE);
}
if (!eofblock(ptb)) {
if (!nowarn)
errmsgno(EX_BAD, "WARNING: Partial (single block) EOF detected.\n");
return (FALSE);
}
if (debug)
errmsgno(EX_BAD, "Second EOF Block OK\n");
return (TRUE);
}
LOCAL BOOL
eofblock(ptb)
TCB *ptb;
{
register short i;
register char *s = (char *) ptb;
if (props.pr_nflags & PR_DUMB_EOF)
return (ptb->dbuf.t_name[0] == '\0');
for (i=0; i < TBLOCK; i++)
if (*s++ != '\0')
return (FALSE);
return (TRUE);
}
/*
* Convert octal string -> long int
*/
LOCAL void /*char **/
astoo_cpio(s,l, cnt)
register char *s;
Ulong *l;
register int cnt;
{
register Ulong ret = 0L;
register char c;
register int t;
for(;cnt > 0; cnt--) {
c = *s++;
if(isoctal(c))
t = c - '0';
else
break;
ret *= 8;
ret += t;
}
*l = ret;
/*return(s);*/
}
/*
* Convert string -> long int
*/
LOCAL void /*char **/
stoli(s,l)
register char *s;
Ulong *l;
{
register Ulong ret = 0L;
register char c;
register int t;
while(*s == ' ')
s++;
for(;;) {
c = *s++;
if(isoctal(c))
t = c - '0';
else
break;
ret *= 8;
ret += t;
}
*l = ret;
/*return(s);*/
}
/*
* Convert string -> long long int
*/
EXPORT void /*char **/
stolli(s,ull)
register char *s;
Ullong *ull;
{
register Ullong ret = (Ullong)0;
register char c;
register int t;
if (*((Uchar*)s) & 0x80) {
stollb(s, ull, 11);
return;
}
while(*s == ' ')
s++;
for(;;) {
c = *s++;
if(isoctal(c))
t = c - '0';
else
break;
ret *= 8;
ret += t;
}
*ull = ret;
/*return(s);*/
}
/*
* Convert long int -> string.
*/
LOCAL void
litos(s, l, fieldw)
char *s;
register Ulong l;
register int fieldw;
{
register char *p = &s[fieldw+1];
register char fill = props.pr_fillc;
/*
* Bei 12 Byte Feldern würde hier das Nächste Feld überschrieben, wenn
* entgegen der normalen Reihenfolge geschrieben wird!
* Da der TCB sowieso vorher genullt wird ist es aber kein Problem
* das bei 8 Bytes Feldern notwendige Nullbyte wegzulassen.
*/
/*XXX *p = '\0';*/
/*
* Das Zeichen nach einer Zahl.
* XXX Soll hier besser ein NULL Byte bei POSIX Tar hin?
* XXX Wuerde das Probleme mit einer automatischen Erkennung geben?
*/
*--p = ' ';
/*??? *--p = '\0';*/
do {
*--p = (l%8) + '0'; /* Compiler optimiert */
} while (--fieldw > 0 && (l /= 8) > 0);
switch (fieldw) {
default:
break;
case 11: *--p = fill; /* FALLTHROUGH */
case 10: *--p = fill; /* FALLTHROUGH */
case 9: *--p = fill; /* FALLTHROUGH */
case 8: *--p = fill; /* FALLTHROUGH */
case 7: *--p = fill; /* FALLTHROUGH */
case 6: *--p = fill; /* FALLTHROUGH */
case 5: *--p = fill; /* FALLTHROUGH */
case 4: *--p = fill; /* FALLTHROUGH */
case 3: *--p = fill; /* FALLTHROUGH */
case 2: *--p = fill; /* FALLTHROUGH */
case 1: *--p = fill; /* FALLTHROUGH */
case 0: ;
}
}
/*
* Convert long long int -> string.
*/
EXPORT void
llitos(s, ull, fieldw)
char *s;
register Ullong ull;
register int fieldw;
{
register char *p = &s[fieldw+1];
register char fill = props.pr_fillc;
/*
* Currently only used with fieldwidth == 11.
* XXX Large 8 byte fields are handled separately.
*/
if (/*fieldw == 11 &&*/ ull > MAXOCTAL11) {
llbtos(s, ull, fieldw);
return;
}
/*
* Bei 12 Byte Feldern würde hier das Nächste Feld überschrieben, wenn
* entgegen der normalen Reihenfolge geschrieben wird!
* Da der TCB sowieso vorher genullt wird ist es aber kein Problem
* das bei 8 Bytes Feldern notwendige Nullbyte wegzulassen.
*/
/*XXX *p = '\0';*/
/*
* Das Zeichen nach einer Zahl.
* XXX Soll hier besser ein NULL Byte bei POSIX Tar hin?
* XXX Wuerde das Probleme mit einer automatischen Erkennung geben?
*/
*--p = ' ';
/*??? *--p = '\0';*/
do {
*--p = (ull%8) + '0'; /* Compiler optimiert */
} while (--fieldw > 0 && (ull /= 8) > 0);
switch (fieldw) {
default:
break;
case 11: *--p = fill; /* FALLTHROUGH */
case 10: *--p = fill; /* FALLTHROUGH */
case 9: *--p = fill; /* FALLTHROUGH */
case 8: *--p = fill; /* FALLTHROUGH */
case 7: *--p = fill; /* FALLTHROUGH */
case 6: *--p = fill; /* FALLTHROUGH */
case 5: *--p = fill; /* FALLTHROUGH */
case 4: *--p = fill; /* FALLTHROUGH */
case 3: *--p = fill; /* FALLTHROUGH */
case 2: *--p = fill; /* FALLTHROUGH */
case 1: *--p = fill; /* FALLTHROUGH */
case 0: ;
}
}
/*
* Convert binary (base 256) string -> long int.
*/
LOCAL void /*char **/
stob(s, l, fieldw)
register char *s;
Ulong *l;
register int fieldw;
{
register Ulong ret = 0L;
register Uchar c;
c = *s++ & 0x7F;
ret = c * 256;
while (--fieldw >= 0) {
c = *s++;
ret *= 256;
ret += c;
}
*l = ret;
/*return(s);*/
}
/*
* Convert binary (base 256) string -> long long int.
*/
LOCAL void /*char **/
stollb(s, ull, fieldw)
register char *s;
Ullong *ull;
register int fieldw;
{
register Ullong ret = 0L;
register Uchar c;
c = *s++ & 0x7F;
ret = c * 256;
while (--fieldw >= 0) {
c = *s++;
ret *= 256;
ret += c;
}
*ull = ret;
/*return(s);*/
}
/*
* Convert long int -> binary (base 256) string.
*/
LOCAL void
btos(s, l, fieldw)
char *s;
register Ulong l;
register int fieldw;
{
register char *p = &s[fieldw+1];
do {
*--p = l%256; /* Compiler optimiert */
} while (--fieldw > 0 && (l /= 256) > 0);
s[0] |= 0x80;
}
/*
* Convert long long int -> binary (base 256) string.
*/
LOCAL void
llbtos(s, ull, fieldw)
char *s;
register Ullong ull;
register int fieldw;
{
register char *p = &s[fieldw+1];
do {
*--p = ull%256; /* Compiler optimiert */
} while (--fieldw > 0 && (ull /= 256) > 0);
s[0] |= 0x80;
}
/*--------------------------------------------------------------------------*/
EXPORT void
dump_info(info)
FINFO *info;
{
error("f_name: '%s'\n", info->f_name);
error("f_namelen: %lu\n", info->f_namelen);
error("f_lname: '%s'\n", info->f_lname);
error("f_lnamelen: %lu\n", info->f_lnamelen);
error("f_uname: '%s'\n", info->f_uname);
error("f_umaxlen: %lu\n", info->f_umaxlen);
error("f_gname: '%s'\n", info->f_gname);
error("f_gmaxlen: %lu\n", info->f_gmaxlen);
error("f_dir: %p\n", info->f_dir);
error("f_dirlen: %d\n", info->f_dirlen);
error("f_dev: 0x%llX\n", (Ullong)info->f_dev);
error("f_ino: %llu\n", (Ullong)info->f_ino);
error("f_nlink: %lu\n", info->f_nlink);
error("f_mode: 0%lo\n", info->f_mode);
error("f_uid: %lu\n", info->f_uid);
error("f_gid: %lu\n", info->f_gid);
error("f_size: %lld\n", (Llong)info->f_size);
error("f_rsize: %lld\n", (Llong)info->f_rsize);
error("f_contoffset:%lld\n", (Llong)info->f_contoffset);
error("f_flags: 0x%lX\n", info->f_flags);
error("f_xflags: 0x%lX\n", info->f_xflags);
error("f_xftype: %lu (%s)\n", info->f_xftype, XTTONAME(info->f_xftype));
error("f_rxftype: %lu (%s)\n", info->f_rxftype, XTTONAME(info->f_rxftype));
error("f_filetype: %lu\n", info->f_filetype);
error("f_typeflag: '%c'\n", info->f_typeflag);
error("f_type: 0%lo\n", info->f_type);
error("f_rdev: %lu\n", info->f_rdev);
error("f_rdevmaj: %lu\n", info->f_rdevmaj);
error("f_rdevmin: %lu\n", info->f_rdevmin);
error("f_atime: %.24s +0.%9.9lu s\n", ctime(&info->f_atime), info->f_ansec);
error("f_mtime: %.24s +0.%9.9lu s\n", ctime(&info->f_mtime), info->f_mnsec);
error("f_ctime: %.24s +0.%9.9lu s\n", ctime(&info->f_ctime), info->f_cnsec);
error("f_fflags: 0x%lX\n", info->f_fflags);
}
syntax highlighted by Code2HTML, v. 0.9.1