[net.sources] Public Domain cpio available

roy@phri.UUCP (Roy Smith) (05/04/85)

> 	The bottom line is that I have a program which reads cpio tapes
> which I wrote myself working only from the documentation (that makes it
> public domain, yes?).  If anybody wants it, it's yours for the asking.

Well, folks... here it is:

------Taketh all that lies above this line, and cast it into the void-----

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by phri!roy on Fri May  3 22:09:00 EDT 1985
# Contents:  READ_ME cpiolist.c cpioextract.c
 
echo x - READ_ME
sed 's/^@//' > "READ_ME" <<'@//E*O*F READ_ME//'
	What we have here is a stripped-down pair of programs which can, in
the barest marginal sense, allow you to read cpio tapes.  They were written
for one particular purpose without the expectation that they would ever be
used again, so no attempt was made to support any functionality beyond the
dead minimum.

	The reason I wrote these programs was to be able to read my Sys5
distribution tapes on my 4.2 bsd system.  The idea was that I would use
cpiolist to get a listing of all the files on the /usr file system, and
then (once I knew the names of the required files) use cpioextract to pull
off the source for the 'real' cpio, compile that under 4.2, and use it to
do the rest of the job correctly.  Notice 3 important things.  First,
cpioextract only extracts a single file per invocation.  Second, it expects
all of the directories along the path to that file to be created already.
Third, these programs only know about binary header type cpio archives
(i.e. tapes made WITHOUT the -c flag).  This is the way the Sys5
distribution was done (at least the distribution I got).

	Various caveats:  These programs were written from the Sys 5
documentation describing the cpio file formats.  From what I can gather,
since I did not look at the Sys 5 cpio sources while I was writing this, it
should qualify as public domain.  The primary purpose of these programs is
to bootstrap a full-fledged cpio from a Sys 5 distribution tape onto a
system which doesn't have cpio already (i.e. 4.2 bsd).  Having these
programs will give you the technical means of doing this; it may not give
you the legal right.  I am far from qualified to pass judgement on the
issues of what a particular Unix (tm) license allow you to do.  Use these
programs at your own risk.  All I will say is that as a holder of both Sys
5 and 4.2 bsd source licenses, I am allowed to port the Sys 5 utilities to
my 4.2 system.  If you don't hold both licenses, you probably aren't.

	Eventually, I will get around to adding more functionality to these
programs.  The top of the list features are the '-c' and '-d' flags, and
then pattern matching for file names.  If I ever get around to doing those,
I'll post the updated versions.  If you find any problems with either of
these programs, please feel free to contact me.  I'll be happy to help if I
can, but please don't expect me to have the updated versions ready on any
particular schedule.

allegra!phri!roy (Roy Smith)
System Administrator, Public Health Research Institute
@//E*O*F READ_ME//
chmod u=rw,g=r,o=r READ_ME
 
echo x - cpiolist.c
sed 's/^@//' > "cpiolist.c" <<'@//E*O*F cpiolist.c//'
/*
 * Cpiolist.c -- list a cpio tape written with binary headers
 * (i.e. written without the -c option).  Usage is "cpiolist file"
 * where 'file' is the cpio archive (probably /dev/rmt12).
 *
 * Writen, produced, and directed by:
 * Roy Smith <allegra!phri!roy>
 * The Public Health Research Institute
 *   of the City of New York, Inc.
 * 455 First Avenue
 * New York, NY 10016
 */

struct hdr
{
	short		h_magic;
	short		h_dev;
	unsigned short	h_ino;
	unsigned short	h_mode;
	unsigned short	h_uid;
	unsigned short	h_gid;
	short		h_nlink;
	short		h_rdev;
	short		h_mtime[2];
	short		h_namesize;
	short		h_filesize[2];
};

struct longword
{
	short word[2];
};

main (argc, argv)
int argc;
char *argv [];
{
	struct hdr header;
	int n, i, fd, odd, size;
	struct longword *lwp;
	char c, *ctime(), name[100];
	short temp;

	/*
	 * Attempt to open the cpio archive file.
	 */
	if ((fd = open (argv[1], 0)) < 0)
	{
		printf ("can't open file\n");
		exit (1);
	}

	while (1)
	{
		/* Read in a header */
		n = read (fd, &header, sizeof (header));
	
		/*
		 * The high and low order words of the time are
		 * in the wrong order on the tape; swap them.
		 */
		temp = header.h_mtime[0];
		header.h_mtime[0] = header.h_mtime[1];
		header.h_mtime[1] = temp;

		/* likewise, swap the high and low order sizes */
		lwp = (struct longword *) &size;
		lwp->word[0] = header.h_filesize[1];
		lwp->word[1] = header.h_filesize[0];

		/* check for trouble */
		if (header.h_magic != 070707)
		{
			printf ("out of sync!\n");
			exit (1);
		}

		/* print the header info */
		printf ("%5d", header.h_ino);
		printf ("%9#o  ", header.h_mode);
		printf ("%.24s", ctime (header.h_mtime));
		printf ("%7d ", size);

		/*
		 * read in the file name -- notice that if the name is
		 * an odd number of bytes long, it is padded to be even.
		 */
		if ((n = header.h_namesize) % 2 != 0)
			odd = 1;
		else
			odd = 0;

		i = 0;
		while (n--)
		{
			read (fd, &c, 1);
			name [i++] = c;
		}
		printf ("%s\n", name);
		if (odd)
			read (fd, &c, 1);

		/* the file data is likewise padded */
		if (size % 2 != 0)
			size++;

		/*
		 * we don't actually want the file,
		 * so just skip to the next header.
		 */
		lseek (fd, size, 1);
	}
}
@//E*O*F cpiolist.c//
chmod u=rw,g=r,o=r cpiolist.c
 
echo x - cpioextract.c
sed 's/^@//' > "cpioextract.c" <<'@//E*O*F cpioextract.c//'
/*
 * Cpioextract.c -- extract a single file from a cpio archive
 * written with binary headers (i.e. without the -c option)
 *
 * Usage is: cpioextract cpio_archive_file archived_file_name
 *
 * Written by:
 * Roy Smith <allegra!phri!roy>
 * The Public Health Research Institute
 *   of the City of New York, Inc.
 * 455 First Avenue, New York, NY 10016
 */

struct hdr
{
	short		h_magic;
	short		h_dev;
	unsigned short	h_ino;
	unsigned short	h_mode;
	unsigned short	h_uid;
	unsigned short	h_gid;
	short		h_nlink;
	short		h_rdev;
	short		h_mtime[2];
	short		h_namesize;
	short		h_filesize[2];
};

struct longword
{
	short word[2];
};

main (argc, argv)
int argc;
char *argv [];
{
	struct hdr header;
	int n, i, fd, odd, size;
	struct longword *lwp;
	char c, *ctime(), name[100];
	short temp;

	/* attempt to open cpio archive file */
	if ((fd = open (argv[1], 0)) < 0)
	{
		printf ("can't open file\n");
		exit (1);
	}

	while (1)
	{
		/* read in a header */		
		n = read (fd, &header, sizeof (header));
	
		/* tape has high and low order times reversed, fix them */
		temp = header.h_mtime[0];
		header.h_mtime[0] = header.h_mtime[1];
		header.h_mtime[1] = temp;

		/* likewise, the file size */
		lwp = (struct longword *) &size;
		lwp->word[0] = header.h_filesize[1];
		lwp->word[1] = header.h_filesize[0];

		/* sanity check */
		if (header.h_magic != 070707)
		{
			printf ("out of sync!\n");
			exit (1);
		}

		/*
		 * if the file name is an odd number of characters, it is
		 * padded on the tape to be even; deal with this.
		 */
		if ((n = header.h_namesize) % 2 != 0)
			odd = 1;
		else
			odd = 0;

		/* read the file name from the archive */
		i = 0;
		while (n--)
		{
			read (fd, &c, 1);
			name [i++] = c;
		}
		if (odd)
			read (fd, &c, 1);

		/* is this the file we want? */
		if (strcmp (name, argv[2]) == 0)
		{
			copyout (fd, size);
			exit (0);
		}
		else
		{
			/*
			 * this wasn't the right file; skip past it (and one
			 * extra padding byte if the file size was odd).
			 */
			if (size % 2 != 0)
				size++;

			lseek (fd, size, 1);
		}
	}
}

/*
 * pull a file out of the archive.  fd is a file descriptor for the
 * cpio archive, n is the size of the file we are supposed to get.
 * the file is output to standard output.
 */ 	
copyout (fd, n)
int fd, n;
{
	int nk;
	char buf[1024];

	/*
	 * how many full kilobyte blocks are there,
	 * and how many bytes left over? */
	 */
	nk = n / 1024;
	n %= 1024;

	/* get all the whole blocks */
	while (nk--)
	{
		read (fd, buf, 1024);
		write (1, buf, 1024);
	}
	/* and get the residual fractional kilobyte */
	read (fd, buf, n);
	write (1, buf, n);
}
@//E*O*F cpioextract.c//
chmod u=rw,g=r,o=r cpioextract.c
 
echo Inspecting for damage in transit...
temp=/tmp/shar$$; dtemp=/tmp/.shar$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
      41     448    2496 READ_ME
     113     369    2210 cpiolist.c
     139     462    2626 cpioextract.c
     293    1279    7332 total
!!!
wc  READ_ME cpiolist.c cpioextract.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0
-- 
allegra!phri!roy (Roy Smith)
System Administrator, Public Health Research Institute