Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

v47i107: tp - Extracting tp, itp and dtp Unix archives, Part01/01

10 views
Skip to first unread message

Warren Toomey

unread,
Mar 27, 1995, 1:41:01 PM3/27/95
to
Submitted-by: w...@csadfa.cs.adfa.oz.au (Warren Toomey)
Posting-number: Volume 47, Issue 107
Archive-name: tp/part01
Environment: UNIX

The Tp, Dtp and Itp Archive Programs list the table of contents and extract
files from tp, dtp and itp Unix archives. These archive formats were used in
6th and 7th Edition Unix, and predate tar(1) format.

I wrote these to extract archives of this type off old backup tapes. I
hope some other people find the programs useful.

How do I know if my file is in tp/dtp/itp format?

Simple. Compile tp, dtp and itp, and try doing a table of contents using
each program:

% tp t file
% dtp t file
% itp t file

If one of them gives something sane-looking, you have probably found the
right one, and you can use the `x' option with the same command to extract
files. Please note: the programs do not use the checksums available in the
archives. If the archive is corrupt, the programs will merrily extract garbage.

I am _very_ interested in finding programs that can extract from 7th
Edition dump/restor archives, and also from 6th and 7th Edition filesystem
images. If you have any of these or know of them, please email me!

Warren Toomey w...@cs.adfa.oz.au March 1995
---
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# Contents: README Makefile dtp.1 dtp.c itp.1 itp.c tp.1 tp.c
# Wrapped by kent@sparky on Mon Mar 27 12:30:53 1995
PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 1 (of 1)."'
if test -f 'README' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1557 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
X Tp, Dtp and Itp Archive Programs
X --------------------------------
X
XThese programs list the table of contents and extract files from tp, dtp
Xand itp Unix archives. These archive formats were used in 6th and 7th
XEdition Unix, and predate tar(1) format.
X
X
XHow do I know if my file is in tp/dtp/itp format?
X-------------------------------------------------
X
XSimple. Compile tp, dtp and itp, and try doing a table of contents using
Xeach program:
X
X % tp t file
X % dtp t file
X % itp t file
X
XIf one of them gives something sane-looking, you have probably found the
Xright one, and you can use the `x' option with the same command to extract
Xfiles.
X
X
XCaveats
X-------
X
XThe programs do not use the checksums available in the archives. If the
Xarchive is corrupt, the programs will merrily extract garbage.
X
Xmkdir -p is used to recursively make directory hierachies if they are needed.
XThis could be recoded, but the programs were hacked up to do what I needed
Xand I haven't fixed this yet.
X
XThe programs have only had a small sample of input archives to extract. Thus,
Xthey may not extract all tp/dtp/itp archives. Bug reports and patches most
Xwelcome.
X
X
XOther Notes
X-----------
X
XI wrote these to extract archives of this type off old backup tapes. I
Xhope some other people find the programs useful.
X
XI am _very_ interested in finding programs that can extract from 7th
XEdition dump/restor archives, and also from 6th and 7th Edition filesystem
Ximages. If you have any of these or know of them, please email me!
X
X Warren Toomey w...@cs.adfa.oz.au March 1995
END_OF_FILE
if test 1557 -ne `wc -c <'README'`; then
echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(506 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X# Makefile for tp, itp and dtp
X#
X# If your machine is big endian, uncomment the next line
X#END= -DBIG_ENDIAN
X
XCC= gcc
XCFLAGS= -Wall $(END)
XBINDIR=/usr/local/bin
XMANDIR=/usr/local/man/man1
X
Xall: tp dtp itp
X
Xtp: tp.c
X $(CC) -o tp $(CFLAGS) tp.c
X
Xitp: itp.c
X $(CC) -o itp $(CFLAGS) itp.c
X
Xdtp: dtp.c
X $(CC) -o dtp $(CFLAGS) dtp.c
X
Xinstall: tp dtp itp tp.1 itp.1 dtp.1
X install -m 755 -o bin -g bin tp itp dtp $(BINDIR)
X install -c -m 644 -o bin -g bin tp.1 itp.1 dtp.1 $(MANDIR)
X
Xclean:
X rm -f tp itp dtp *.o
END_OF_FILE
if test 506 -ne `wc -c <'Makefile'`; then
echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'dtp.1' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dtp.1'\"
else
echo shar: Extracting \"'dtp.1'\" \(2272 characters\)
sed "s/^X//" >'dtp.1' <<'END_OF_FILE'
X.TH dtp 1L "Mar 1995"
X.SH NAME
Xdtp \- extract/list the contents of a Unix dtp archive
X.SH SYNOPSIS
X.B dtp
X[
X.B t|x
X]
X.I filename
X.SH DESCRIPTION
X.B dtp
Xtakes the filename of a Unix dtp archive as its second argument, and either
Xlists the contents of the archive, or extracts the contents of the archive
Xto the current directory. The first argument is either a
X.B t
Xor an
X.B x.
X.SH OPTIONS
X.TP
X.B t
XProduce a table of contents.
X.TP
X.B x
XExtract the archive's contents to the current directory.
X.SH ARCHIVE FORMAT
XA
X.I dtp
Xarchive is broken up into a number of 512-byte blocks. Block 0 contains
Xthe offset of the actual files' data, stored in a uint16_t at bytes 6 and 7.
XThis value is converted to an offset in bytes as follows:
X.PP
X.nf
Xoffset = 64 * (256 * byte[6] + byte[7]);
X.fi
X.PP
XBlock 1 begins the archive's table of contents. The table of contents is
Xmade up of a number of records with the following C structure:
X.PP
X.nf
X/* dtp tape directory entry */
Xstruct tpdir {
X char pathname[114]; /* Filename of file */
X uint16_t mode; /* Unix mode */
X uint8_t uid; /* Owner of file */
X uint8_t gid; /* Group of file */
X uint8_t unused1;
X uint8_t size[3]; /* Size in bytes */
X uint8_t modtime[4]; /* Time of last modification */
X uint16_t tapeaddr; /* Beginning block on tape */
X};
X.fi
X.PP
Xwhere
X.I uintXX_t
Xindicates an unsigned integer
X.I XX
Xbits wide.
X.PP
XThe table of contents extends from Block 1 up to the data offset
Xcalculated above. Alternatively,
Xthe last record in the table of contents may be indicated by a 0 in the
Xfirst byte of the
X.I pathname
Xstring. All blocks following this block contain the files in the archive.
XThe
X.I tapeaddr
Xfield in each file entry points to the first block after the offset
Xwhich contains the
Xdata for that file. Files are stored contiguously. Where a file is
Xnot a multiple of the block-size in size, it is padded with bytes
Xso that it is a integral number of blocks.
X.SH BUGS
X.B dtp
Xdoes not use the
X.I checksum
Xfield in the table of contents records.
X.PP
X.I mkdir -p
Xis used to recursively make directory hierachies if they are needed.
X.SH "SEE ALSO"
X.BR tp (1L),
X.BR itp (1L),
X.BR mkdir (1)
X.SH AUTHOR
XWarren Toomey w...@cs.adfa.oz.au
END_OF_FILE
if test 2272 -ne `wc -c <'dtp.1'`; then
echo shar: \"'dtp.1'\" unpacked with wrong size!
fi
# end of 'dtp.1'
fi
if test -f 'dtp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'dtp.c'\"
else
echo shar: Extracting \"'dtp.c'\" \(6146 characters\)
sed "s/^X//" >'dtp.c' <<'END_OF_FILE'
X/* Dtp: read contents of a dtp archive.
X * Author: Warren Toomey w...@cs.adfa.oz.au
X * Version 1.1 March 1995
X *
X * This works on a little-endian machine. You will probably have endian
X * trouble with the 2-, 3- and 4-octet fields in the tpdir structure.
X */
X
X#include <sys/types.h>
X#include <utime.h>
X#include <stdio.h>
X#include <string.h>
X#define BLKSIZ 512 /* Size of dtp tape blocks */
X
X#include <stdlib.h> /* malloc's definition */
X#include <time.h> /* ctime's definition */
X#include <unistd.h> /* chown's definition */
X#include <sys/stat.h> /* chmod's definition */
X
X/* Typedefs */
Xtypedef char int8_t; /* These may need redefining */
Xtypedef unsigned char uint8_t;
Xtypedef short int16_t;
Xtypedef unsigned short uint16_t;
Xtypedef long int32_t;
Xtypedef unsigned long uint32_t;
X
X/* dtp tape directory entry */
Xstruct tpdir {
X char pathname[114]; /* Filename of file */
X uint16_t mode; /* Unix mode */
X uint8_t uid; /* Owner of file */
X uint8_t gid; /* Group of file */
X uint8_t unused1;
X uint8_t size[3]; /* Size in bytes */
X uint8_t modtime[4]; /* Time of last modification */
X uint16_t tapeaddr; /* Beginning block on tape */
X};
X
X/* We build a linked list when
X * reading in the tape
X */
Xstruct tlist {
X struct tpdir tdir;
X uint32_t modtime;
X int size;
X struct tlist *next;
X};
X
Xvoid mkrecursdir(char *name);
X
Xvoid swap16(i)
X uint16_t *i;
X{
X char *a, b;
X
X a= (char *)i; b= a[0]; a[0]= a[1]; a[1]=b;
X}
X
Xvoid swap32(i)
X uint32_t *i;
X{
X char *a, b;
X
X a= (char *)i; b= a[0]; a[0]= a[3]; a[3]=b; b=a[1]; a[1]=a[2]; a[2]=b;
X}
X
Xvoid checktypes()
X{
X if (sizeof(int8_t)!=1) { printf("Wrong size for type int8_t\n"); exit(1); }
X if (sizeof(uint8_t)!=1) { printf("Wrong size for type uint8_t\n"); exit(1); }
X if (sizeof(int16_t)!=2) { printf("Wrong size for type int16_t\n"); exit(1); }
X if (sizeof(uint16_t)!=2) { printf("Wrong size for type uint16_t\n"); exit(1); }
X if (sizeof(int32_t)!=4) { printf("Wrong size for type int32_t\n"); exit(1); }
X if (sizeof(uint32_t)!=4) { printf("Wrong size for type uint32_t\n"); exit(1); }
X}
X
Xvoid usage()
X{
X printf("Usage: dtp [t|x] filename\n"); exit(1);
X}
X
Xint main(argc, argv)
X int argc;
X char *argv[];
X{
X uint8_t buf[BLKSIZ];
X FILE *zin, *zout;
X int toc = 1;
X int extract = 0;
X uint32_t size;
X struct tlist *thead = NULL, *tent, *this;
X int blockbytes;
X uint8_t *b;
X struct utimbuf utbuf;
X uint32_t offset;
X
X checktypes(); /* Check size of our typedefs */
X if (argc != 3) usage(); /* Give usage if wrong # args */
X if (argv[1][0] == 't') {
X toc = 1; extract = 0;
X } /* Either extract of give contents */
X if (argv[1][0] == 'x') {
X toc = 0; extract = 1;
X }
X zin = fopen(argv[2], "r");
X if (zin == NULL) { perror("Opening input file"); exit(1); }
X
X /* Determine the offset to data */
X if ((fread(buf, 8, 1, zin)) != 1) {
X printf("Offset read failed\n"); exit(1);
X }
X offset = 64 * (256 * buf[6] + buf[7]);
X printf("Offset to data at %d, 0x%x\n", offset, offset);
X
X fseek(zin, 128, SEEK_SET);
X
X /* Read in the tape directory entries */
X while (1) {
X /* If we've reached the data, no more dir entries */
X if (ftell(zin) == offset) break;
X
X tent = (struct tlist *) malloc(sizeof(struct tlist));
X tent->next = NULL;
X if ((fread(&(tent->tdir), sizeof(struct tpdir), 1, zin)) != 1) {
X printf("fread failed on dtp archive %s\n",argv[2]); break;
X }
X
X /* If entry has no name, we've reached end of the list */
X if (tent->tdir.pathname[0] == '\0') break;
X
X /* Get the size of the file */
X size = tent->tdir.size[0] * 65536 + tent->tdir.size[2] * 256
X + tent->tdir.size[1];
X tent->size = size;
X
X#ifdef BIG_ENDIAN
X /* Convert multibyte fields */
X swap16(&(tent->tdir.mode));
X swap16(&(tent->tdir.tapeaddr));
X#endif
X
X /* Convert the modification time into a normal Unix time value */
X b = tent->tdir.modtime;
X tent->modtime = 16777216 * b[1] + 65536 * b[0] + 256 * b[3] + b[2];
X
X /* Print the table of contents */
X if (toc) {
X printf("%s %o %d %d %d at %d %s", tent->tdir.pathname,
X tent->tdir.mode, tent->tdir.uid, tent->tdir.gid, size,
X tent->tdir.tapeaddr, ctime(&(tent->modtime)));
X }
X
X /* Add entry to the list */
X if (thead == NULL) thead = this = tent;
X else { this->next = tent; this = tent; }
X }
X
X if (extract)
X for (this = thead; this; this = this->next) {
X
X /* Print the file's name on stdout */
X printf("x %s %d, ", this->tdir.pathname, this->size);
X
X /* Convert file size into # of tape blocks */
X blockbytes = BLKSIZ * ((this->size + 511) / 512);
X printf("%d blockbytes\n", blockbytes);
X if (this->size == 0) continue;
X
X /* Seek to the beginning of the file */
X fseek(zin, offset + BLKSIZ * this->tdir.tapeaddr, SEEK_SET);
X size = this->size;
X
X /* Open the output file */
X zout = fopen(this->tdir.pathname, "w");
X if (zout == NULL) {
X /* Ok, try making the directories */
X mkrecursdir(this->tdir.pathname);
X zout = fopen(this->tdir.pathname, "w");
X if (zout == NULL) {
X printf("Can't open %s for writing\n", this->tdir.pathname);
X continue;
X }
X }
X
X /* Read and write the blocks from the archive to the file */
X while (size) {
X if ((fread(&buf, BLKSIZ, 1, zin)) != 1) {
X printf("Error reading block for %s\n", this->tdir.pathname);
X break;
X }
X if (size < BLKSIZ) { fwrite(&buf, size, 1, zout); size = 0; }
X else { fwrite(&buf, BLKSIZ, 1, zout); size -= BLKSIZ; }
X }
X
X /* Close the file */
X fclose(zout);
X
X /* Set up the file's mode, owner, group and modification time */
X chmod(this->tdir.pathname, this->tdir.mode);
X chown(this->tdir.pathname, this->tdir.uid, this->tdir.gid);
X utbuf.actime = utbuf.modtime = this->modtime;
X utime(this->tdir.pathname, &utbuf);
X }
X exit(0);
X}
X
X/* Build the directory needed to create the file.
X * We cheat by using mkdir -p.
X */
X
Xvoid
Xmkrecursdir(char *name)
X{
X char *c;
X char buf[300];
X
X c = strrchr(name, '/');
X if (c) {
X *c = '\0';
X sprintf(buf, "/bin/mkdir -p %s", name);
X system(buf);
X *c = '/';
X }
X}
END_OF_FILE
if test 6146 -ne `wc -c <'dtp.c'`; then
echo shar: \"'dtp.c'\" unpacked with wrong size!
fi
# end of 'dtp.c'
fi
if test -f 'itp.1' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'itp.1'\"
else
echo shar: Extracting \"'itp.1'\" \(1972 characters\)
sed "s/^X//" >'itp.1' <<'END_OF_FILE'
X.TH itp 1L "Mar 1995"
X.SH NAME
Xitp \- extract/list the contents of a Unix itp archive
X.SH SYNOPSIS
X.B itp
X[
X.B t|x
X]
X.I filename
X.SH DESCRIPTION
X.B itp
Xtakes the filename of a Unix itp archive as its second argument, and either
Xlists the contents of the archive, or extracts the contents of the archive
Xto the current directory. The first argument is either a
X.B t
Xor an
X.B x.
X.SH OPTIONS
X.TP
X.B t
XProduce a table of contents.
X.TP
X.B x
XExtract the archive's contents to the current directory.
X.SH ARCHIVE FORMAT
XA
X.I itp
Xarchive is broken up into a number of 512-byte blocks.
XBlock 0 begins the archive's table of contents. The table of contents is
Xmade up of a number of records with the following C structure:
X.PP
X.nf
X/* itp tape directory entry */
Xstruct tpdir {
X char pathname[48]; /* Filename of file */
X uint16_t mode; /* Unix mode */
X uint8_t uid; /* Owner of file */
X uint8_t gid; /* Group of file */
X char unused1;
X uint8_t size[3]; /* Size in bytes */
X uint32_t modtime; /* Time of last modification */
X uint16_t tapeaddr; /* Beginning block on tape */
X uint16_t checksum; /* Checksum */
X};
X.fi
X.PP
Xwhere
X.I uintXX_t
Xindicates an unsigned integer
X.I XX
Xbits wide.
X.PP
XThe last record in the table of contents has a 0 in the first byte of the
X.I pathname
Xstring. All blocks following this block contain the files in the archive.
XThe
X.I tapeaddr
Xfield in each file entry points to the first block which contains the
Xdata for that file. Files are stored contiguously. Where a file is
Xnot a multiple of the block-size in size, it is padded with bytes
Xso that it is a integral number of blocks.
X.SH BUGS
X.B itp
Xdoes not use the
X.I checksum
Xfield in the table of contents records.
X.PP
X.I mkdir -p
Xis used to recursively make directory hierachies if they are needed.
X.SH "SEE ALSO"
X.BR tp (1L),
X.BR itp (1L),
X.BR mkdir (1)
X.SH AUTHOR
XWarren Toomey w...@cs.adfa.oz.au
END_OF_FILE
if test 1972 -ne `wc -c <'itp.1'`; then
echo shar: \"'itp.1'\" unpacked with wrong size!
fi
# end of 'itp.1'
fi
if test -f 'itp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'itp.c'\"
else
echo shar: Extracting \"'itp.c'\" \(6040 characters\)
sed "s/^X//" >'itp.c' <<'END_OF_FILE'
X/* Itp: read contents of a itp archive.
X * Author: Warren Toomey w...@cs.adfa.oz.au
X * Version 1.1 March 1995
X *
X * This works on a little-endian machine. You will probably have endian
X * trouble with the 2-, 3- and 4-octet fields in the tpdir structure.
X */
X
X#include <sys/types.h>
X#include <utime.h>
X#include <stdio.h>
X#include <string.h>
X#define BLKSIZ 512 /* Size of itp tape blocks */
X
X#include <stdlib.h> /* malloc's definition */
X#include <time.h> /* ctime's definition */
X#include <unistd.h> /* chown's definition */
X#include <sys/stat.h> /* chmod's definition */
X
X/* Typedefs */
Xtypedef char int8_t; /* These may need redefining */
Xtypedef unsigned char uint8_t;
Xtypedef short int16_t;
Xtypedef unsigned short uint16_t;
Xtypedef long int32_t;
Xtypedef unsigned long uint32_t;
X
X/* itp tape directory entry */
Xstruct tpdir {
X char pathname[48]; /* Filename of file */
X uint16_t mode; /* Unix mode */
X uint8_t uid; /* Owner of file */
X uint8_t gid; /* Group of file */
X char unused1;
X uint8_t size[3]; /* Size in bytes */
X uint32_t modtime; /* Time of last modification */
X uint16_t tapeaddr; /* Beginning block on tape */
X uint16_t checksum; /* Checksum */
X};
X
X/* We build a linked list when
X * reading in the tape
X */
Xstruct tlist {
X struct tpdir tdir;
X int size;
X struct tlist *next;
X};
X
Xvoid mkrecursdir(char *name);
X
Xvoid swap16(i)
X uint16_t *i;
X{
X char *a, b;
X
X a= (char *)i; b= a[0]; a[0]= a[1]; a[1]=b;
X}
X
Xvoid swap32(i)
X uint32_t *i;
X{
X char *a, b;
X
X a= (char *)i; b= a[0]; a[0]= a[3]; a[3]=b; b=a[1]; a[1]=a[2]; a[2]=b;
X}
X
Xvoid checktypes()
X{
X if (sizeof(int8_t)!=1) { printf("Wrong size for type int8_t\n"); exit(1); }
X if (sizeof(uint8_t)!=1) { printf("Wrong size for type uint8_t\n"); exit(1); }
X if (sizeof(int16_t)!=2) { printf("Wrong size for type int16_t\n"); exit(1); }
X if (sizeof(uint16_t)!=2) { printf("Wrong size for type uint16_t\n"); exit(1); }
X if (sizeof(int32_t)!=4) { printf("Wrong size for type int32_t\n"); exit(1); }
X if (sizeof(uint32_t)!=4) { printf("Wrong size for type uint32_t\n"); exit(1); }
X}
X
Xvoid usage()
X{
X printf("Usage: itp [t|x] filename\n"); exit(1);
X}
X
Xint main(argc, argv)
X int argc;
X char *argv[];
X{
X char buf[BLKSIZ];
X FILE *zin, *zout;
X int toc = 1;
X int extract = 0;
X uint32_t size;
X struct tlist *thead = NULL, *tent, *this;
X int blockbytes;
X uint8_t a, *b;
X struct utimbuf utbuf;
X
X checktypes(); /* Check size of our typedefs */
X if (argc != 3) usage(); /* Give usage if wrong # args */
X if (argv[1][0] == 't') {
X toc = 1; extract = 0;
X } /* Either extract of give contents */
X if (argv[1][0] == 'x') {
X toc = 0; extract = 1;
X }
X zin = fopen(argv[2], "r");
X if (zin == NULL) { perror("Opening input file"); exit(1); }
X
X /* Read in the tape directory entries */
X while (1) {
X tent = (struct tlist *) malloc(sizeof(struct tlist));
X tent->next = NULL;
X if ((fread(&(tent->tdir), sizeof(struct tpdir), 1, zin)) != 1) {
X printf("fread failed on itp archive %s\n",argv[2]);
X break;
X }
X
X /* If entry has no name, we've reached end of the list */
X if (tent->tdir.pathname[0] == '\0') break;
X
X /* Get the size of the file */
X size = tent->tdir.size[0] * 65536 + tent->tdir.size[2] * 256
X + tent->tdir.size[1];
X tent->size = size;
X
X#ifdef BIG_ENDIAN
X /* Convert multibyte fields */
X swap16(&(tent->tdir.mode));
X swap16(&(tent->tdir.tapeaddr));
X /* Convert the modification time into a normal Unix time value */
X b = (uint8_t *) & (tent->tdir.modtime);
X a = b[0]; b[0] = b[1]; b[1] = a;
X a = b[2]; b[2] = b[3]; b[3] = a;
X#else
X /* Convert the modification time into a normal Unix time value */
X b = (uint8_t *) & (tent->tdir.modtime);
X a = b[0]; b[0] = b[2]; b[2] = a;
X a = b[1]; b[1] = b[3]; b[3] = a;
X#endif
X
X /* Print the table of contents */
X if (toc) { printf("%s %o %d %d %d at %d %s", tent->tdir.pathname,
X tent->tdir.mode, tent->tdir.uid, tent->tdir.gid, size,
X tent->tdir.tapeaddr, ctime(&(tent->tdir.modtime)));
X }
X
X /* Add entry to the list */
X if (thead == NULL) thead = this = tent;
X else { this->next = tent; this = tent; }
X }
X
X if (extract)
X for (this = thead; this; this = this->next) {
X
X /* Print the file's name on stdout */
X printf("x %s %d, ", this->tdir.pathname, this->size);
X
X /* Convert file size into # of tape blocks */
X blockbytes = BLKSIZ * ((this->size + 511) / 512);
X printf("%d blockbytes\n", blockbytes);
X if (this->size==0) continue;
X
X /* Seek to the beginning of the file */
X fseek(zin, BLKSIZ * this->tdir.tapeaddr, SEEK_SET);
X size = this->size;
X
X /* Open the output file */
X zout = fopen(this->tdir.pathname, "w");
X if (zout == NULL) {
X /* Ok, try making the directories */
X mkrecursdir(this->tdir.pathname);
X zout = fopen(this->tdir.pathname, "w");
X if (zout == NULL) {
X printf("Can't open %s for writing\n", this->tdir.pathname);
X continue;
X }
X }
X
X /* Read and write the blocks from the archive to the file */
X while (size) {
X if ((fread(&buf, BLKSIZ, 1, zin)) != 1) {
X printf("Error reading block for %s\n", this->tdir.pathname);
X break;
X }
X if (size < BLKSIZ) { fwrite(&buf, size, 1, zout); size = 0; }
X else { fwrite(&buf, BLKSIZ, 1, zout); size -= BLKSIZ; }
X }
X
X /* Close the file */
X fclose(zout);
X
X /* Set up the file's mode, owner, group and modification time */
X chmod(this->tdir.pathname, this->tdir.mode);
X chown(this->tdir.pathname, this->tdir.uid, this->tdir.gid);
X utbuf.actime = utbuf.modtime = this->tdir.modtime;
X utime(this->tdir.pathname, &utbuf);
X }
X exit(0);
X}
X
X/* Build the directory needed to create the file.
X * We cheat by using mkdir -p.
X */
Xvoid
Xmkrecursdir(char *name)
X{
X char *c;
X char buf[300];
X
X c = strrchr(name, '/');
X if (c) {
X *c = '\0';
X sprintf(buf, "/bin/mkdir -p %s", name); system(buf);
X *c = '/';
X }
X}
END_OF_FILE
if test 6040 -ne `wc -c <'itp.c'`; then
echo shar: \"'itp.c'\" unpacked with wrong size!
fi
# end of 'itp.c'
fi
if test -f 'tp.1' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'tp.1'\"
else
echo shar: Extracting \"'tp.1'\" \(1987 characters\)
sed "s/^X//" >'tp.1' <<'END_OF_FILE'
X.TH tp 1L "Mar 1995"
X.SH NAME
Xtp \- extract/list the contents of a Unix tp archive
X.SH SYNOPSIS
X.B tp
X[
X.B t|x
X]
X.I filename
X.SH DESCRIPTION
X.B tp
Xtakes the filename of a Unix tp archive as its second argument, and either
Xlists the contents of the archive, or extracts the contents of the archive
Xto the current directory. The first argument is either a
X.B t
Xor an
X.B x.
X.SH OPTIONS
X.TP
X.B t
XProduce a table of contents.
X.TP
X.B x
XExtract the archive's contents to the current directory.
X.SH ARCHIVE FORMAT
XA
X.I tp
Xarchive is broken up into a number of 512-byte blocks. Block 0 is unused.
XBlock 1 begins the archive's table of contents. The table of contents is
Xmade up of a number of records with the following C structure:
X.PP
X.nf
X/* tp file entry */
Xstruct tpdir {
X char pathname[32]; /* Filename of file */
X uint16_t mode; /* Unix mode */
X uint8_t uid; /* Owner of file */
X uint8_t gid; /* Group of file */
X char unused1;
X uint8_t size[3]; /* Size in bytes */
X uint32_t modtime; /* Time of last modification */
X uint16_t tapeaddr; /* Beginning block on tape */
X char unused2[16];
X uint16_t checksum; /* Checksum */
X};
X.fi
X.PP
Xwhere
X.I uintXX_t
Xindicates an unsigned integer
X.I XX
Xbits wide.
X.PP
XThe last record in the table of contents has a 0 in the first byte of the
X.I pathname
Xstring. All blocks following this block contain the files in the archive.
XThe
X.I tapeaddr
Xfield in each file entry points to the first block which contains the
Xdata for that file. Files are stored contiguously. Where a file is
Xnot a multiple of the block-size in size, it is padded with bytes
Xso that it is a integral number of blocks.
X.SH BUGS
X.B tp
Xdoes not use the
X.I checksum
Xfield in the table of contents records.
X.PP
X.I mkdir -p
Xis used to recursively make directory hierachies if they are needed.
X.SH "SEE ALSO"
X.BR dtp (1L),
X.BR itp (1L),
X.BR mkdir (1)
X.SH AUTHOR
XWarren Toomey w...@cs.adfa.oz.au
END_OF_FILE
if test 1987 -ne `wc -c <'tp.1'`; then
echo shar: \"'tp.1'\" unpacked with wrong size!
fi
# end of 'tp.1'
fi
if test -f 'tp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'tp.c'\"
else
echo shar: Extracting \"'tp.c'\" \(5983 characters\)
sed "s/^X//" >'tp.c' <<'END_OF_FILE'
X/* Tp: read contents of a tp archive.
X * Author: Warren Toomey w...@cs.adfa.oz.au
X * Version 1.1 March 1995
X *
X * This works on a little-endian machine. You will probably have endian
X * trouble with the 2-, 3- and 4-octet fields in the tpdir structure.
X */
X
X#include <sys/types.h>
X#include <utime.h>
X#include <stdio.h>
X#include <string.h>
X#define BLKSIZ 512 /* Size of tp tape blocks */
X
X#include <stdlib.h> /* malloc's definition */
X#include <time.h> /* ctime's definition */
X#include <unistd.h> /* chown's definition */
X#include <sys/stat.h> /* chmod's definition */
X
X/* Typedefs */
Xtypedef char int8_t; /* These may need redefining */
Xtypedef unsigned char uint8_t;
Xtypedef short int16_t;
Xtypedef unsigned short uint16_t;
Xtypedef long int32_t;
Xtypedef unsigned long uint32_t;
X
X/* tp tape directory entry */
Xstruct tpdir {
X char pathname[32]; /* Filename of file */
X uint16_t mode; /* Unix mode */
X uint8_t uid; /* Owner of file */
X uint8_t gid; /* Group of file */
X char unused1;
X uint8_t size[3]; /* Size in bytes */
X uint32_t modtime; /* Time of last modification */
X uint16_t tapeaddr; /* Beginning block on tape */
X char unused2[16];
X uint16_t checksum; /* Checksum */
X};
X
X/* We build a linked list when
X * reading in the tape
X */
Xstruct tlist {
X struct tpdir tdir;
X int size;
X struct tlist *next;
X};
X
Xvoid mkrecursdir(char *name);
X
Xvoid swap16(i)
X uint16_t *i;
X{
X char *a, b;
X
X a= (char *)i; b= a[0]; a[0]= a[1]; a[1]=b;
X}
X
Xvoid swap32(i)
X uint32_t *i;
X{
X char *a, b;
X
X a= (char *)i; b= a[0]; a[0]= a[3]; a[3]=b; b=a[1]; a[1]=a[2]; a[2]=b;
X}
X
Xvoid checktypes()
X{
X if (sizeof(int8_t)!=1) { printf("Wrong size for type int8_t\n"); exit(1); }
X if (sizeof(uint8_t)!=1) { printf("Wrong size for type uint8_t\n"); exit(1); }
X if (sizeof(int16_t)!=2) { printf("Wrong size for type int16_t\n"); exit(1); }
X if (sizeof(uint16_t)!=2) { printf("Wrong size for type uint16_t\n"); exit(1); }
X if (sizeof(int32_t)!=4) { printf("Wrong size for type int32_t\n"); exit(1); }
X if (sizeof(uint32_t)!=4) { printf("Wrong size for type uint32_t\n"); exit(1); }
X}
X
Xvoid usage()
X{
X printf("Usage: tp [t|x] filename\n"); exit(1);
X}
X
Xint main(argc, argv)
X int argc;
X char *argv[];
X{
X char buf[BLKSIZ];
X FILE *zin, *zout;
X int toc = 1;
X int extract = 0;
X uint32_t size;
X struct tlist *thead = NULL, *tent, *this;
X int blockbytes;
X uint8_t a, *b;
X struct utimbuf utbuf;
X
X checktypes(); /* Check size of our typedefs */
X if (argc != 3) usage(); /* Give usage if wrong # args */
X if (argv[1][0] == 't') {
X toc = 1; extract = 0;
X } /* Either extract of give contents */
X if (argv[1][0] == 'x') {
X toc = 0; extract = 1;
X }
X zin = fopen(argv[2], "r");
X if (zin == NULL) { perror("Opening input file"); exit(1); }
X fseek(zin, (long) BLKSIZ, SEEK_SET);
X
X /* Read in the tape directory entries */
X while (1) {
X tent = (struct tlist *) malloc(sizeof(struct tlist));
X tent->next = NULL;
X if ((fread(&(tent->tdir), sizeof(struct tpdir), 1, zin)) != 1) {
X printf("fread failed on tp archive %s\n",argv[2]);
X break;
X }
X
X /* If entry has no name, we've reached end of the list */
X if (tent->tdir.pathname[0] == '\0') break;
X
X /* Get the size of the file */
X size = tent->tdir.size[0] * 65536 + tent->tdir.size[2] * 256
X + tent->tdir.size[1];
X tent->size = size;
X
X#ifdef BIG_ENDIAN
X /* Convert multibyte fields */
X swap16(&(tent->tdir.mode));
X swap16(&(tent->tdir.tapeaddr));
X /* Convert the modification time into a normal Unix time value */
X b = (uint8_t *) & (tent->tdir.modtime);
X a = b[0]; b[0] = b[1]; b[1] = a;
X a = b[2]; b[2] = b[3]; b[3] = a;
X#else
X /* Convert the modification time into a normal Unix time value */
X b = (uint8_t *) & (tent->tdir.modtime);
X a = b[0]; b[0] = b[2]; b[2] = a;
X a = b[1]; b[1] = b[3]; b[3] = a;
X#endif
X
X /* Print the table of contents */
X if (toc) { printf("%s %o %d %d %d at %d %s", tent->tdir.pathname,
X tent->tdir.mode, tent->tdir.uid, tent->tdir.gid, size,
X tent->tdir.tapeaddr, ctime(&(tent->tdir.modtime)));
X }
X
X /* Add entry to the list */
X if (thead == NULL) thead = this = tent;
X else { this->next = tent; this = tent; }
X }
X
X if (extract)
X for (this = thead; this; this = this->next) {
X
X /* Print the file's name on stdout */
X printf("x %s %d, ", this->tdir.pathname, this->size);
X
X /* Convert file size into # of tape blocks */
X blockbytes = BLKSIZ * ((this->size + 511) / 512);
X printf("%d blockbytes\n", blockbytes);
X
X /* Seek to the beginning of the file */
X fseek(zin, BLKSIZ * this->tdir.tapeaddr, SEEK_SET);
X size = this->size;
X
X /* Open the output file */
X zout = fopen(this->tdir.pathname, "w");
X if (zout == NULL) {
X /* Ok, try making the directories */
X mkrecursdir(this->tdir.pathname);
X zout = fopen(this->tdir.pathname, "w");
X if (zout == NULL) {
X printf("Can't open %s for writing\n", this->tdir.pathname);
X continue;
X }
X }
X
X /* Read and write the blocks from the archive to the file */
X while (size) {
X if ((fread(&buf, BLKSIZ, 1, zin)) != 1) {
X printf("Error reading block for %s\n", this->tdir.pathname);
X break;
X }
X if (size < BLKSIZ) { fwrite(&buf, size, 1, zout); size = 0; }
X else { fwrite(&buf, BLKSIZ, 1, zout); size -= BLKSIZ; }
X }
X
X /* Close the file */
X fclose(zout);
X
X /* Set up the file's mode, owner, group and modification time */
X chmod(this->tdir.pathname, this->tdir.mode);
X chown(this->tdir.pathname, this->tdir.uid, this->tdir.gid);
X utbuf.actime = utbuf.modtime = this->tdir.modtime;
X utime(this->tdir.pathname, &utbuf);
X }
X exit(0);
X}
X
X/* Build the directory needed to create the file.
X * We cheat by using mkdir -p.
X */
Xvoid
Xmkrecursdir(char *name)
X{
X char *c;
X char buf[300];
X
X c = strrchr(name, '/');
X if (c) {
X *c = '\0';
X sprintf(buf, "/bin/mkdir -p %s", name); system(buf);
X *c = '/';
X }
X}
END_OF_FILE
if test 5983 -ne `wc -c <'tp.c'`; then
echo shar: \"'tp.c'\" unpacked with wrong size!
fi
# end of 'tp.c'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have the archive.
rm -f ark[1-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...

0 new messages