From: Paul Allen <paula@atc.boeing.com>
Subject: A tarfile splitter.
Reply-To: paula@atc.boeing.com
Organization: The Internet
Date: Wed, 15 Apr 1992 04:59:06 GMT

Here is a program that may be of some help to those trying
to figure out how to move 25Mb or so of Linux files to their
home systems via floppies.  In short, this is a simple-minded
attempt to split up a large tar file into smaller tar files
that can each fit on a floppy.  The README file contains all
the details, so I'll leave it at that.

Enjoy!

Paul Allen
----------------------------------------------------------

# /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	tarscan.c
# This archive created: Tue Apr 14 20:48:34 1992
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(3606 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^	X//' << \SHAR_EOF > 'README'
	XThis is tarscan, a program that can read a tarfile and break it
	Xup into smaller self-contained tarfiles that do not exceed a
	Xspecified size limit.  I originally wrote it many years ago to
	Xscan old news archive tapes for Subject lines.  It was posted
	Xto one of the old moderated Unix sources newsgroups, where Rich
	X$alz did some radical clean-up on my sloppy code.  I have added
	Xthe tarfile splitting logic since then.  It's been a loong time
	Xsince I've looked at this code.  Any ugly kluges you find should
	Xproperly be attributed to me, and not to Rich $alz.
	X
	XThe program is invoked like this:
	X
	Xtarscan [-v] [-f filename-prefix] [-s size]
	X
	XThe -v switch causes tarscan to output (on stdout) a verbose listing
	Xof the members of the input tarfile and any Subject: line found in
	Xthe first block of the file.
	X
	XThe -f switch causes tarscan to write a new tarfile on the specified
	Xfilename with "000" appended to it.
	X
	XThe -s switch specifies a maximum size (in 512-byte blocks) for the
	Xoutput tarfiles.  If more than one output file is created, the three-
	Xdigit file suffix is incremented for each file.
	X
	X
	XTypically, I use tarscan to package up a bunch of files into floppy-
	Xsized hunks for transfer to my home system.  My usual usage is like
	Xthis:
	X
	Xtar cf - ./* |tarscan -v -f ../myfiles. -s 2400 >../myfiles.lis
	X
	XThis command will tar up everything in the current directory into
	Xtarfiles that will all fit on 5.25" HD floppies.  The tarfiles and
	Xthe listing file will be created in the parent directory.  The
	Xtarfiles will have names myfiles.000, myfiles.001, myfiles.002, ...
	XThe listing file will contain a table of contents for each 
	Xtarfile.  
	X
	XBugs:
	X
	XTarscan doesn't try to break up members of the input tarfile between
	Xmore than one output tarfile.  A member file that is larger than a
	Xfloppy will be written by itself in a single output tarfile, and it
	Xstill won't fit on a floppy.
	X
	XA corrollary to this is that packaging up relatively large files,
	Xsuch as a bunch of several-hundred-kilobyte compressed tar's,
	Xcan potentially result in considerable variation in the sizes of
	Xthe output tarfiles and consequent wasted space on the floppies.
	XSuch is life, eh?  :-)
	X
	XThe -v listing logic doesn't handle directories correctly.  No data
	Xis lost, but the listing is sometimes confusing.  I've known about
	Xthis for years, but have never had the energy to fix it.  :-)
	X
	XTarscan sometimes spits out a complaint about a file name too long
	Xon the last member of the input tarfile.  The output tarfiles are
	Xalways correct and complete, so I've never bothered to squash this
	Xbogus message.
	X
	XIt is probably possible to confuse tarscan by giving it a set of
	Xarguments that don't make sense n combination with each other.  
	XThe program tries to protect itself, but this code is not 
	Xwell-tested since I never give it arguments that don't make sense.  
	X:-)
	X
	X
	X
	XTarscan is probably of most use for those who have an easy route
	Xto floppies from their Internet-connected machine.  A SPARCstation
	Xwith a 3.5" floppy is ideal, since one can simply dd the tarfiles
	Xdirectly to /dev/fd0.  On a PC with an ethernet card, one can ftp
	Xthe tarfiles to DOS-formatted floppies.  (And read them under
	Xlinux with tar -i.) 
	X
	XThese sources are known to work on Suns running SunOS revs ranging
	Xfrom about 3.2 up to 4.1.2, although they will probably compile fine
	Xon other systems.  I haven't tried compiling tarscan under Linux,
	Xbut a variant works under Minix.
	X
	X
	XI hope this is useful for some of you.  If you fix any of the known
	Xbugs, or find new ones, I would appreciate hearing about it.
	X
	XPaul Allen
	Xpallen@atc.boeing.com
	X4/14/92
	X
	X
	X
SHAR_EOF
if test 3606 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 3606 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'tarscan.c'" '(5295 characters)'
if test -f 'tarscan.c'
then
	echo shar: will not over-write existing file "'tarscan.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'tarscan.c'
	X/*
	X**  TARSCAN
	X**  News archive tape scanner/splitter.
	X**
	X**  Reads a tar news archive, optionally splitting it into smaller
	X**  archives or listing the contained files and their Subject lines
	X**  on stdout.  Useful for creating a multi-floppy archive when
	X**  you might want to retrieve just one file from the 27th floppy
	X**  of an archive.  Each volume is a complete stand-alone tar archive.
	X**
	X**  Arguments:
	X**
	X**	One or more of:
	X**
	X**	-v		Write file names and Subject lines on stdout.
	X**			(Mainly for news articles or mail.)  If the
	X**			-s switch is present, tarscan will announce
	X**			volume changes on stdout.
	X**
	X**	-f filename	Copy the input tarfile to the named file.
	X**
	X**	-s size		Only used with -f.  Break the tarfile into
	X**			individual tarfiles that don't exceed 'size'
	X**			tape blocks.  If 'filename' is a device,
	X**			the user will be prompted to change media
	X**			when appropriate.  If 'filename' is not a
	X**			device, then the input tarfile is copied
	X**			into a series of files with 'filename' as
	X**			a base and sequential numbers as a suffix.
	X**			(Beware of 14-character filenames!)
	X**
	X*/
	X#include <stdio.h>
	X#include <sys/file.h>
	X#include <strings.h>
	X
	X#define TBLOCK		512
	X#define NAMSIZ		100
	X#define CLUMP		1
	X
	Xextern char	*strcpy();
	X
	Xextern char	*optarg;
	Xextern int	 optind;
	X
	Xtypedef union {
	X    char	 dummy[TBLOCK];
	X    struct {
	X	char	 name[NAMSIZ];
	X	char	 mode[8];
	X	char	 uid[8];
	X	char	 gid[8];
	X	char	 size[12];
	X	char	 mtime[12];
	X	char	 chksum[8];
	X	char	 linkflag;
	X	char	 linkname[NAMSIZ];
	X    } D;
	X} HEADER;
	X
	X#define OCTAL(x) (((x) >= '0') && ((x) <= '7'))
	X
	Xvoid
	Xusage ()
	X{
	X    fprintf (stderr, "Usage: tarscan [-v] [-f filename [-s size] ] <tarfile\n");
	X    exit (1);
	X}
	X
	Xstatic HEADER *
	Xmyread(mt)
	X    int			 mt;
	X{
	X    static HEADER	 buff[CLUMP];
	X    static int		 pos = CLUMP;
	X    int			 len;
	X
	X    if (pos == CLUMP) {
	X	if ((len=read(mt, (char *)buff, sizeof buff)) == 0) {
	X	    return ((HEADER *) 0);
	X	} else if (len == -1) {
	X	    perror ("read");
	X	    exit (1);
	X	}
	X	pos = 0;
	X    }
	X    return(&buff[pos++]);
	X}
	X
	X
	Xmain(ac, av)
	X    int			 ac;
	X    char		*av[];
	X{
	X    register HEADER	*H;
	X    register char	*p;
	X    register char	*q;
	X    register char	*r;
	X    register char	*t;
	X    char		 subject[256];
	X    register int	 Nblocks;
	X    register int	 first;
	X    register int	 size;
	X    char		 Name[NAMSIZ];
	X    int			 outblocks;
	X    int			 outvol = 0;
	X    int			 outfile = -1;
	X    int			 volume_size;
	X    char		 zbuff [TBLOCK];
	X    char		 outname [100];
	X    char		 t_outname [100];
	X    int			 verbose = 0;
	X    int			 make_copy = 0;
	X    int			 limit_size = 0;
	X    int			 start;
	X    int			 c;
	X    int			 device;
	X
	X    for (p=zbuff,q=zbuff+TBLOCK; p<q; (*p++)=0) ;
	X
	X    while ((c=getopt(ac, av, "vf:s:")) != -1)
	X	switch (c) {
	X	case 'v':
	X	    verbose = 1;
	X	    fprintf (stderr, "verbose flag\n");
	X	    break;
	X	case 'f':
	X	    make_copy = 1;
	X	    strcpy (outname, optarg);
	X	    device = strncmp ("/dev/", outname, 5) == 0;
	X	    fprintf (stderr, "make copy on %s\n", outname);
	X	    break;
	X	case 's':
	X	    limit_size = 1;
	X	    volume_size = atoi(optarg);
	X	    fprintf (stderr, "limit output volumes to %d blocks\n", volume_size);
	X	    break;
	X	default:
	X	    usage ();
	X	    exit (1);
	X	}
	X
	X    if ((verbose + make_copy + limit_size) == 0) {
	X	usage ();
	X	exit (1);
	X    }
	X    if (limit_size && !make_copy) {
	X	usage ();
	X	exit (1);
	X    }
	X
	X    if (!limit_size) {
	X	if (device) {
	X	    outfile = open (outname, O_WRONLY);
	X	} else {
	X	    outfile = creat (outname, 0777);
	X	}
	X	if (outfile == -1) {
	X	    perror ("open output file");
	X	    exit (1);
	X	}
	X    } else {
	X	outblocks = volume_size;
	X    }
	X
	X    for (first = 0, Nblocks = 0; H = myread(0); ) {
	X	if (Nblocks) {
	X	    Nblocks--;
	X	    if (first && verbose) {
	X		for (p=H->D.name, q=p+TBLOCK, start=1; p<q; p++) {
	X		    if (start && (strncmp(p, "Subject", 7)==0)) {
	X			for (t=subject, r=p+8; r<q && *r != '\n'; r++) *(t++) = *r;
	X			*t = 0;
	X			printf ("	%s", subject);
	X			break;
	X		    }
	X		    start = *p == '\n';
	X		}
	X		printf ("\n");
	X	    }
	X	    first = 0;
	X	}
	X	else if (H->D.name[0]) {
	X	    if (H->D.name[NAMSIZ - 1]) {
	X		H->D.name[NAMSIZ - 1] = 0;
	X		fprintf(stderr,
	X			"Name \"%s\" is more than %d bytes long, I give up!\n",
	X			H->D.name,
	X			NAMSIZ);
	X		exit(1);
	X	    }
	X	    size = 0;
	X	    if (H->D.linkflag != '1')
	X		for (p = H->D.size,q=H->D.size+12; p<q ; p++) {
	X		    if (OCTAL(*p)) size = (size << 3) + *p - '0';
	X		}
	X	    Nblocks = size / TBLOCK + ((size % TBLOCK) > 0);
	X	    first = Nblocks > 0;
	X	    if (make_copy && ((outblocks+Nblocks+3) > volume_size)) {
	X		if (outfile > 0) {
	X		    write (outfile, zbuff, TBLOCK);
	X		    write (outfile, zbuff, TBLOCK);
	X		    close (outfile);
	X		}
	X		if (device) {
	X		    outfile = open (outname, O_RDONLY);
	X		} else {
	X		    sprintf (t_outname, "%s%03d", outname , outvol);
	X	            outfile=creat(t_outname, 0777);
	X		}
	X		if (outfile == -1) {
	X		    perror ("open output file");
	X		    exit(1);
	X	        } 
	X		if (verbose && limit_size) 
	X		    if (device) 
	X			printf ("\n\nVolume %d on %s\n\n", outvol, outname);
	X		    else
	X			printf ("\n\nTarfile: %s\n\n", t_outname);
	X		outvol++;
	X		outblocks = 0;
	X	    }
	X	    printf ("%s", H->D.name);
	X	} 
	X	if (make_copy) {
	X	    if (write(outfile, (char *) H, TBLOCK) != TBLOCK) { 
	X		perror ("write tape block");
	X		exit (1);
	X	    }
	X	    outblocks++;
	X	}
	X    }    
	X
	X    exit(0);
	X}
SHAR_EOF
if test 5295 -ne "`wc -c < 'tarscan.c'`"
then
	echo shar: error transmitting "'tarscan.c'" '(should have been 5295 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0