[comp.sys.amiga] Tarsplit.c & tar

mwm@violet.berkeley.edu (Mike Meyer) (01/13/87)

Ok, here's the source to tarsplit.c. It's a straight port of the OS/9
program that does the same thing. Major gotcha: tarsplit doesn't do
name translation, so '.' and '..' don't work. For instance, you can't
do "tar cf - ." on the Unix end and then take it apart on the Amiga,
as "." isn't a recognized file name.

Recomended useage: cd to the parent of the directory you want to
download, and do:

	tar cbf 1 download.tar download_dir

This will tar download_dir into download.tar. Setting the blocksize to
1 causes minimal wasted space in the image. I haven't tried
compressing the result; gotta do that soon. After downloading it, cd
to the place you want the directory to appear in, and do "tarsplit
download.tar" (or whever you put it). For small files (*NOT* the mg
sources!), putting things in ram: works fine.

For those who don't want to compile it, or don't trust your compiler,
I put the binary in the pub/amiga directory on ucbvax. Matt should
feel free to delete it, though. I didn't uuencode it, and I didn't
touch Matt's index.

Note: This has not been tested under either Lattice 3.10, or any
version of MANX. It's also the second posting, having been posted
nearly a year ago; right after I did it.

Finally, I've heard rumors of a PD tar. If I can find a copy, I'll
probably try and post it, but not do the port.

	<mike

P.S. - since he doesn't mention it in the file, I'll do it here. The
original OS/9 version of this was written by James Jones (the hacker
from Mars :-). James can currently be found as jejones@mcrware.UUCP.

-------------------- cut here, only one file --------------------
/*
 * TarSplit -- split up tar files (creating directories as needed)
 *
 * usage: TarSplit [pathname]
 *
 * semantics: splits up tar file taken from stdin (or pathname, if
 * specified) and creates the files therein under the working data
 * directory.
 */

#include <stdio.h>

#ifdef	AMIGA
#include <exec/types.h>
typedef	int	bool ;
bool	ChkSumOK() ;
#include <libraries/dosextens.h>
#else
#include <modes.h>
#include <bool.h>
#define DIRMODE		(S_IREAD | S_IWRITE | S_IEXEC | S_IOREAD | S_IOEXEC)
#endif
#define TBLOCK	512
#define NAMSIZ	100

union hblock {
	char dummy[TBLOCK];
	struct header {
		char name[NAMSIZ];
		char mode[8];
		char uid[8];
		char gid[8];
		char size[12];
		char mtime[12];
		char chksum[8];
		char linkflag;
		char linkname[NAMSIZ];
	} dbuf;
};

#define BLKSIZE		(sizeof (union hblock))
#define HARDLINK	'1'
#define SYMBLINK	'2'
#define NORMAL		'\0'

main(argc, argv)
int	argc;
char	*argv[];
{
	FILE		*TarFP;
	union hblock	TarBlock;

#ifndef	AMIGA
	/* make the compiler happy about formatted I/O for longs... */
	pflinit();
#endif

	switch(argc) {
#ifndef	AMIGA
	case 1:
		TarFP = stdin;
		break;
#endif
	case 2:
		if ((TarFP = fopen(argv[1], "r")) == NULL) {
			fprintf(stderr, "TarSplit: can't open %s\n", argv[1]);
			exit(1);
		}
		break;
	default:
		fprintf(stderr, "usage: TarSplit [pathname]\n");
		exit(1);
	}

	for (;;) {
		if (fread(&TarBlock, BLKSIZE, 1, TarFP) == NULL) {
			fprintf(stderr, "TarSplit: premature EOF\n");
			exit(1);
		} else if (IsZero(&TarBlock)) {
			while (fread(&TarBlock, BLKSIZE, 1, TarFP) != NULL)
				;
			break;
		} else
			DoFile(&TarBlock, TarFP);
	}

}

bool
IsZero(block)
union hblock	*block;
{
	int	i;
	char	*cblock;

	cblock = block->dummy;
	for (i = 0; i < TBLOCK; i++)
		if (*cblock++ != '\0')
			return(FALSE);

	return (TRUE);

}

DoFile(block, TarFP)
union hblock	*block;
FILE		*TarFP;
{
	long	FSize;
	char	FName[NAMSIZ], *RefName;
	int	i;
	bool	IsDir, OpenOK;
	FILE	*NewFP;

	if (!ChkSumOK(block)) {
		fprintf(stderr, "TarSplit: bad checksum, name %s?\n",
			block->dbuf.name);
		exit(1);
	}

	switch(block->dbuf.linkflag) {
	case HARDLINK:
	case SYMBLINK:
		fprintf(stderr, "TarSplit: can't handle links\n");
		exit(1);
	case NORMAL:
		break;
	default:
		fprintf(stderr, "TarSplit: unknown linkflag\n");
		exit(1);
	}

#ifdef	AMIGA
	if (sscanf(block->dbuf.size, "%12lo", &FSize) != 1) {
#else
	if (sscanf(block->dbuf.size, "%12O", &FSize) != 1) {
#endif
		fprintf(stderr, "TarSplit: bad size\n");
		exit(1);
	}

	for (i = 0, RefName = block->dbuf.name; *RefName; i++, RefName++)
		FName[i] = *RefName;

	if (IsDir = (*(RefName - 1) == '/')) {
		FName[i - 1] = '\0';
		if (strcmp(FName, ".") == 0)
			OpenOK = TRUE;
		else
#ifdef	AMIGA
			{
			struct FileLock *Lock, *CreateDir() ;
			OpenOK = (Lock = CreateDir(FName)) != 0 ;
			UnLock(Lock) ;
			}
#else
			OpenOK = mknod(FName, DIRMODE) == 0;
#endif
	} else {
		FName[i] = '\0';
		OpenOK = (NewFP = fopen(FName, "w")) != NULL;
	}

	if (!OpenOK) {
		fprintf(stderr, "TarSplit: can't create %s\n", FName);
		exit(1);
	}

	for (; FSize > 0; FSize -= TBLOCK) {
		if (fread(block, BLKSIZE, 1, TarFP) == NULL) {
			fprintf(stderr, "TarSplit: premature EOF\n");
			exit(1);
		}
		if (!IsDir)
			fwrite(block->dummy, 1,
				(FSize > TBLOCK ? TBLOCK : (int) FSize), NewFP);
	}

	if (!IsDir)
		fclose(NewFP);

}

bool
ChkSumOK(block)
union hblock	*block;
{
	long	Accum, ChkSumVal;
	int	i;

#ifdef	AMIGA
	sscanf(block->dbuf.chksum, "%8lo", &ChkSumVal);
#else
	sscanf(block->dbuf.chksum, "%8O", &ChkSumVal);
#endif
	for (i = 0; i < 8; i++)
		block->dbuf.chksum[i] = ' ';

	Accum = 0;
	for (i = 0; i < TBLOCK; i++)
		Accum += 0xff & block->dummy[i];

	return(Accum == ChkSumVal);

}