static char rcsid[] = "$Header: header.c,v 10.1 86/07/21 14:56:20 bog Exp $";

/************************************************************************\
**									**
**			Copyright 1982 - 1986				**
**			VALID LOGIC SYSTEMS INCORPORATED		**
**									**
**	This listing contains confidential proprietary information	**
**	which is not to be disclosed to unauthorized persons without	**
**	written consent of an officer of Valid Logic Systems 		**
**	Incoroporated.							**
**									**
**	The copyright notice appearing above is included to provide	**
**	statutory protection in the event of unauthorized or 		**
**	unintentional public disclosure.				**
**									**
\************************************************************************/

/*
 * cpio -- copy file collections
 *
 * TO COMPILE:
 *	UNIX: cc -O cpio.c -s -i -o cpio 
 *	STANDALONE: Good God!  Look at the makefile. #define STANDALONE. Pray.
 */

/*
 * Standalone Modifications by Bill O. Galllmeister (Valid) 0786.
 *
 * Notes:
 *	fgets() undef:	added one in prf.c
 *	unlink() undef.
 *	chmod() undef.
 *	chdir() undef.
 *	chown() undef.
 *	umask() undef.
 *
 *	Port alloc()'s to standalone library?  That may be the easiest thing...
 */
#define VALID		/* They're heeeere. */
#define DOTDOTBROKEN	/* Something to do with relative paths involving .. */

#ifdef DOTDOTBROKEN
char absolutepath[1024];
#endif DOTDOTBROKEN

#define TRUE 1
#define FALSE 0

#include <sys/types.h>
#ifdef	STANDALONE
#include "../h/param.h"
#include "../h/fs.h"
#include "../h/inode.h"
#include "../salib/saio.h"
#else	STANDALONE
#include <stdio.h>
#endif	STANDALONE
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>

#ifdef RT
#define S_IFEXT 0120000	/*  allocated by extents  */
#define S_IF1EXT 0130000	/*  one extent  */
#endif RT

#ifdef VALID
/*
 * Bogus stat mode -- non-standard... we just did it this way to make it
 * work. Ford uses S_IFIFO for something or other. Literally, 0140000 means
 * a file is both a regular file and is a directory.
 */
#define S_IFIFO 0140000  
#endif

#define EQ(x,y)	(strcmp(x,y)==0)
/* for VAX, Interdata, ... */
#define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];}
#define MAGIC	070707
#define IN	1	/* 'i' option. */
#define OUT	2	/* 'o' option. */
#define PASS	3	/* 'p' option (STANDALONE-bar). */
#define HDRSIZE	((sizeof Hdr)-256)	/* Size of the header sans filename. */
#define LINKS	1000	/* Total number of links allowed. */
#define MERT 0
#define CHARS 76

#ifdef RT
#define MERT 1	/* yes = 1 ;  no = 0 */
extern long filespace;
#endif RT

struct	stat	Statb, Xstatb;

struct header {
	short	h_magic,
		h_dev;
#ifdef VALID
	unsigned short	h_ino,
#else  VALID
	ushort	h_ino,
#endif VALID
		h_mode,
		h_uid,
		h_gid;
	short	h_nlink,
		h_rdev,
		h_mtime[2],
		h_namesize,
		h_filesize[2];
	char	h_name[256];
} Hdr;

int	Bufsize = 512;
short	Buf[256], *Dbuf;
char    BBuf[512];
char    *Cbuf;
int	Wct,Wc;
short	*Wp;
char    *Cp;

#ifdef STANDALONE
/*
 * malloc() hurts too much to put together.  Just allocate some bss now.
 */
char DBuffer[5120], CBuffer[5120];
/*
 * Version string comes from vers.c -- created by vers.sh on the fly.
 */
extern char version[];
#endif STANDALONE

#ifdef RT
short Actual_size[2];	/* MERT variable */
struct{
	long long_size;
};
#endif RT

#ifdef VALID

/*
**  Data structures and functions to support the -f option added to cpio
**  by Preston Gardner at Valid, January 1983.
*/

#ifdef STANDALONE		/********* Standalone **********/

/*
 * No-Ops in the wonderful world of STANDALONE.
 */
#define signal(action,reaction);
#define getuid()		0	/* Root's ID. */
#define getgid()		0	/* The root club. */
#define access(plink,plonk)	0	/* You can go anywhere, do anything. */
#define getwd(p)		strcpy(p,"/")	/* We live @ root. cd()-bar. */

#ifdef DEBUG
#define DODEBUG(str) str
#else
#define DODEBUG(str)
#endif
#ifdef DEBUG2
#define DODEBUG2(str) str
#else
#define DODEBUG2(str)
#endif
#ifdef DEBUG3
#define DODEBUG3(str) str
#else
#define DODEBUG3(str)
#endif

#else   STANDALONE		/********* Standalone **********/
#define DODEBUG(str)
#define DODEBUG2(str)
#define DODEBUG3(str)
#endif  STANDALONE		/********* Standalone **********/

short FileList = 0;	/* 1 iff -f option is on */
#define FILETABLESIZ 10000
char *fileTable[FILETABLESIZ];  /* table of file names */
char *fileOfFiles = "/dev/null";/* name of file that has list of files in it */
int nFilesInList = 0;

int TableLoc(loc,str)
int *loc;
char *str;
{
    register char *p;
    int i, nTries, sum, found;

#ifdef	STANDALONE
    DODEBUG(printf("TableLoc(%s){\n",str);)
#else	STANDALONE
    DODEBUG(fprintf(stderr,"TableLoc(%s){\n",str);)
#endif	STANDALONE
    sum = 0; p = str;
    while (*p != '\0') {
	sum += (short)*p++;
#ifdef	STANDALONE
	DODEBUG(printf("sum=%d\n",sum);)
#else	STANDALONE
	DODEBUG(fprintf(stderr,"sum=%d\n",sum);)
#endif	STANDALONE
    }
    sum %= FILETABLESIZ;
#ifdef	STANDALONE
    DODEBUG(printf("sum=%d\n",sum);)
#else	STANDALONE
    DODEBUG(fprintf(stderr,"sum=%d\n",sum);)
#endif	STANDALONE
    i = sum;
    found = 0; nTries = 0;
    while (fileTable[i] != NULL) {
#ifdef	STANDALONE
	DODEBUG(printf("try item %d <%s>\n",i,fileTable[i]);)
#else	STANDALONE
	DODEBUG(fprintf(stderr,"try item %d <%s>\n",i,fileTable[i]);)
#endif	STANDALONE
	if (strcmp(str, fileTable[i]) == 0) {
	    found = 1;
	    break;
	}
	if (nTries > FILETABLESIZ) {
#ifndef STANDALONE
	    fprintf(stderr,"cpio--infinite loop in file table search\n");
#else   STANDALONE
	    printf("cpio--infinite loop in file table search\n");
#endif  STANDALONE
	    exit(1);
	}
	i++; nTries++;
    }
    *loc = i;
#ifdef	STANDALONE
    DODEBUG(printf("TableLoc returns %d loc %d\n",found,i);)
#else	STANDALONE
    DODEBUG(fprintf(stderr,"TableLoc returns %d loc %d\n",found,i);)
#endif	STANDALONE
    return(found);
}

ReadFileTable()
{
#ifdef	STANDALONE
    int fp;		/* file holding file table */
#else	STANDALONE
    FILE *fp;		/* file holding file table */
#endif	STANDALONE
    int i, buflen;
#define STRBUFSIZ 150
    char strbuf[STRBUFSIZ];

#ifdef	STANDALONE
    DODEBUG(printf("ReadFileTable(){\n");)
    fp = open(fileOfFiles, F_READ);	/* Open the name file */
    if (fp == -1) {
#else	STANDALONE
    DODEBUG(fprintf(stderr,"ReadFileTable(){\n");)
    fp = fopen(fileOfFiles, "r");	/* Open the name file */
    if (fp == NULL) {
#endif	STANDALONE
	perror("cpio (file-of-files)");	/* Box is locked. */
	exit(1);
    }
    nFilesInList = 0;
    while (fgets(strbuf,STRBUFSIZ,fp) != NULL) {
	buflen = strlen(strbuf);
	strbuf[buflen-1] = '\0'; /* get rid of '\n' at end */
#ifdef	STANDALONE
	DODEBUG(printf("read %s\n", strbuf);)
#else	STANDALONE
	DODEBUG(fprintf(stderr,"read %s\n", strbuf);)
#endif	STANDALONE
	if (nFilesInList >= FILETABLESIZ) {
#ifdef	STANDALONE
	    printf("cpio: out of space on file table -- quit\n");
#else	STANDALONE
	    fprintf(stderr, "cpio: out of space on file table -- quit\n");
#endif	STANDALONE
	    exit(1);
	}
	if (TableLoc(&i,strbuf)) {
	    /* there already; do nothing */
	} else {
	    fileTable[i] = (char *)calloc(buflen,sizeof(char));
	    if (fileTable[i] == NULL) {
		perror("cpio (out of memory on file table)");
		exit(1);
	    }
	    strcpy(fileTable[i],strbuf);
	    nFilesInList++;
	}
    }
#ifdef	STANDALONE
    close(fp);
#else	STANDALONE
    fclose(fp);
#endif	STANDALONE
#ifdef	STANDALONE
    DODEBUG(printf("}end ReadFileTable\n");)
#else	STANDALONE
    DODEBUG(fprintf(stderr,"}end ReadFileTable\n");)
#endif	STANDALONE
}

SearchFileTable(str)
char *str;
{
    int foo;
    return(TableLoc(&foo,str));
}

/*
 * Data structures to support the -q option which makes cpio quit
 * when its found the the one file it is looking for.
 * Added by Peter Hackett at Valid, October 1984.
 */

int quitwhenfoundit = FALSE; /* iff -q option */
int foundqfile = FALSE;
char *pathofqfile;

/*
 * Data structures to support the -S option which put symbolic links
 * into the archive literally rather that following the link and putting
 * what the link points to into the archive.
 * Added by Peter Hackett at Valid, December 1984.
 */

int literalsymlink = FALSE; /* iff -S option */
int A_symbolic = FALSE;
#define SYMBUFSIZE 1025
char symbuf[SYMBUFSIZE];

/*
 * Data structure(s) to support the -M option which changes the mode
 * and ownership of directories that already exist to the mode and owner
 * of the directories in the archive.
 * Added by Peter Hackett at Valid, December 1984
 */

int chmodexistdirs = FALSE; /* iff -M option */

/* end of code to support the -f , -q , -S and -M options */
/******************************************************************************/
#endif

short	Option,
	Dir,
	Uncond,
	Link,
	Rename,
	Toc,
	Verbose,
	Select,
	Mod_time,
	Acc_time,
	Cflag,
	Swap;

int	Ifile,
	Ofile,
	Input = 0,
	Output = 1;
long	Blocks,
	Longfile,
	Longtime;

char	Fullname[256],
	Name[256];
int	Pathend;

#ifndef	STANDALONE
FILE	*Rtty,
	*Wtty;
#endif	STANDALONE

char	*Pattern[100];
char	Strhdr[500];
char	*Chdr = Strhdr;
short	Dev,
	Uid,
	Gid,
	A_directory,
	A_special,
#ifdef RT
	One_extent,
	Multi_extent,
#endif
	Filetype = S_IFMT;
#ifdef RT
short Remove_mode = 0007777;
short New_mode;
#endif

extern	errno;
#ifndef STANDALONE
char	*malloc();
char 	*cd();
#endif  STANDALONE
char	*Cd_name;
#ifdef	STANDALONE
int 	popen();
#else	STANDALONE
FILE 	*popen();
#endif	STANDALONE

union { long l; short s[2]; char c[4]; } U;

/* for VAX, Interdata, ... */
long mklong(v)
short v[];
{
	U.l = 1;
	if(U.c[0])
		U.s[0] = v[1], U.s[1] = v[0];
	else
		U.s[0] = v[0], U.s[1] = v[1];
	return U.l;
}

#ifndef STANDALONE
main(argc, argv)
char **argv;
{
#else   STANDALONE
main()
{
	char **argv;
	int argc;
#endif  STANDALONE

	register ct;
	long	filesz;
	long lng;
	register char *fullp;
	register i;
	char *p;

	signal(SIGSYS, 1);	/* No-op in standalone mode. */
#ifdef STANDALONE
	getargs(&argc,&argv);	/* Interactively retrieve arguments. */
#endif STANDALONE
	DODEBUG(printf("Back from getargs\n");)

	if(argc == 1)
		usage();
	if(*argv[1] != '-')
		usage();
	Uid = getuid();		/* Always 0 in standalone. */
	umask(0);
	Gid = getgid();		/* Always 0 in standalone. */
	Pattern[0] = "*";

	while(*++argv[1]) {
		switch(*argv[1]) {
		case 'a':
			Acc_time++;
			break;
		case 'B':
			Bufsize = 5120;
			break;
#ifdef VALID
		case 'f':
			FileList = 1;
			if (argc == 3) {
			    fileOfFiles = argv[2];
			} else {
			    usage();
			    exit(1);
			}
			break;
#endif
		case 'i':
			Option = IN;
#ifdef VALID
			for (p=argv[1];(*p!='\0')&&(*p!='f')&&(*p!='q');p++);
			if ((*p=='f')||(*p=='q')) {
				Pattern[1] = NULL;
			} else
#endif
			if(argc > 2 ) {
				for(i = 0; (i+2) < argc; ++i)
					Pattern[i] = argv[i+2];
			}
			break;
		case 'o':
			if(argc != 2)
				usage();
			Option = OUT;
			break;
#ifndef STANDALONE
		case 'p':
			if(argc != 3)
				usage();
			if(access(argv[2], 2) == -1) {
accerr:
				err("cannot write in <%s>\n", argv[2]);
				exit(2);
			}
			strcpy(Fullname, argv[2]);
			strcat(Fullname, "/");
			stat(Fullname, &Xstatb);
			if((Xstatb.st_mode&S_IFMT) != S_IFDIR)
				goto accerr;
			Option = PASS;
			Dev = Xstatb.st_dev;
			break;
#endif  STANDALONE
		case 'c':
			Cflag++;
			break;
		case 'd':
			Dir++;
			break;
		case 'l':
			Link++;
			break;
		case 'm':
			Mod_time++;
			break;
#ifdef VALID
                case 'M':
			chmodexistdirs = TRUE;
			break;
		case 'q':
			quitwhenfoundit = TRUE;
			if (argc == 3) {
			    pathofqfile = argv[2];
			} else {
			    usage();
			    exit(1);
			}
			break;
#endif
#ifndef STANDALONE
		/*
		 * A crock, in any event...
		 */
		case 'r':
			Rename++;
			Rtty = fopen("/dev/tty", "r");
			Wtty = fopen("/dev/tty", "w");
			if(Rtty==NULL || Wtty==NULL) {
				err(
				  "Cannot rename (/dev/tty missing)\n");
				exit(2);
			}
			break;
#endif STANDALONE
		case 's':
			Swap++;
			break;
#ifdef VALID
		case 'S':
			literalsymlink = TRUE;
			break;
#endif
		case 't':
			Toc++;
			break;
		case 'u':
			Uncond++;
			break;
		case 'v':
			Verbose++;
			break;
		case '6':
			Filetype = 060000;
			break;
		default:
			usage();
		}
	}
	if(!Option) {
		err("Options must include o|i|p\n");
		exit(2);
	}

	if (Cflag && Swap)  {
		err("Swap flag is ignored with Cflag\n");
		Swap = 0;
	}

	if(Option != PASS)  {
#ifndef STANDALONE
		Wp = Dbuf = (short *)malloc(Bufsize);
		Cp = Cbuf = (char *)malloc(Bufsize);
#else   STANDALONE
		Wp = Dbuf = (short *)DBuffer;
		Cp = Cbuf = (char *)CBuffer;
#endif  STANDALONE
	}
	Wct = Bufsize >> 1;
	Wc = Bufsize;

	if(Option == PASS && Rename) {
		err("Pass and Rename cannot be used together\n");
		exit(2);
	}
#ifdef VALID
	if(FileList && quitwhenfoundit) {
		err("q and f options can not be used at the same time\n");
		usage();
		exit(2);
	}
#endif
#ifdef DOTDOTBROKEN
	if(Option==PASS || Option==IN) {
            if(!getwd(absolutepath)) {
#ifdef STANDALONE
		printf("cpio: getwd() blew up.  I'm left with %s",absolutepath);
#else  STANDALONE
		fprintf(stderr,"cpio: %s",absolutepath);
#endif STANDALONE
		exit(2);
	    }
	    absolutepath[strlen(absolutepath)]='/';
	}
#endif
	switch(Option) {

#ifndef	STANDALONE
	case OUT:
		while(getname()) {
			if( mklong(Hdr.h_filesize) == 0L) {
				if ( Cflag )
				     writehdr(Chdr,CHARS+Hdr.h_namesize);
				else
				     bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
#ifdef RT
				if( (MERT) && (((Hdr.h_mode & Filetype) == S_IF1EXT)
					|| ((Hdr.h_mode & Filetype) == S_IFEXT))) {
					actsize();
					bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
				}
#endif
				continue;
			}
			if ( Cflag )
			     writehdr(Chdr,CHARS+Hdr.h_namesize);
			else
			     bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
#ifdef RT
			if( (MERT) && (((Hdr.h_mode & Filetype) == S_IF1EXT)
				|| ((Hdr.h_mode & Filetype) == S_IFEXT))) {
				actsize();
				bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
			}
#endif

#ifdef VALID
			if ( A_symbolic ) {
			    for(filesz=0; filesz<mklong(Hdr.h_filesize); filesz+= 512) {
				ct = mklong(Hdr.h_filesize)-filesz>512? 512: mklong(Hdr.h_filesize)-filesz;
				Cflag? writehdr(symbuf+filesz,ct): bwrite(symbuf+filesz,ct);
			    }
			}
			else {
#endif
			    if((Ifile = open(Hdr.h_name, 0)) < 0) {
				err("<%s> ?\n", Hdr.h_name);
				continue;
			    }
			    for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= 512){
				ct = filesz>512? 512: filesz;
			        if(read(Ifile, Cflag? BBuf: (char *)Buf, ct) < 0) {
				    err("Cannot read %s\n", Hdr.h_name);
				    continue;
			        }
			        Cflag? writehdr(BBuf,ct): bwrite(Buf,ct);
			    }
			    close(Ifile);
#ifdef VALID
			}
#endif

			if(Acc_time)
				utime(Hdr.h_name, &Statb.st_atime);
			if(Verbose)
				err("%s\n", Hdr.h_name);
		}
		strcpy(Hdr.h_name, "TRAILER!!!");
		Hdr.h_magic = MAGIC;
		MKSHORT(Hdr.h_filesize, 0L);
		Hdr.h_namesize = strlen("TRAILER!!!") + 1;
		if ( Cflag )  {
		     lng = 0;
		     bintochar(lng);
		     writehdr(Chdr,CHARS+Hdr.h_namesize);
		}
		else
		     bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
		Cflag? writehdr(Cbuf, Bufsize): bwrite(Dbuf, Bufsize);
		break;
#endif	STANDALONE

	case IN:
#ifdef VALID
		if (FileList) {
		    ReadFileTable();
		}
		pwd();
		while(!foundqfile && gethdr()) {
#else
		pwd();
		while(gethdr()) {
#endif
		    Ofile = ckname(Hdr.h_name)? openout(Hdr.h_name): 0;
		    for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= 512){
			ct = filesz>512? 512: filesz;
			Cflag? readhdr(BBuf, ct): bread(Buf, ct);
			if(Ofile) {
			    if(Swap)
				swap(Buf, ct);
			    if(write(Ofile, Cflag? BBuf: (char *)Buf, ct) < 0) {
				if(errno == ENOSPC) { 
				    err("cpio: File system full -- quit\n");
				    exit(2);
				}
				err("Cannot write %s\n", Hdr.h_name);
				continue;
			    }
			}
		    }
		    if(Ofile) {
			close(Ofile);
#ifdef	STANDALONE
			set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
#else	STANDALONE
			set_time(Cd_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
#endif	STANDALONE
		    }
		    if(!Select)
			continue;
		    if(Verbose)
			if(Toc)
			    pentry(Hdr.h_name);
			else
#ifdef	STANDALONE
			    printf("%s\n", Hdr.h_name);
#else	STANDALONE
			    puts(Hdr.h_name);
#endif	STANDALONE
		    else if(Toc)
			puts(Hdr.h_name);
		}
		break;

#ifndef	STANDALONE
	case PASS:
		fullp = Fullname + strlen(Fullname);

		while(getname()) {
			if(!ckname(Hdr.h_name))
				continue;
			strcpy(fullp, Hdr.h_name);

			if(Link
			&& !A_directory
			&& Dev == Statb.st_dev) {
/* ???			&& (Uid == Statb.st_uid || !Uid)) {*/
				if(link(Hdr.h_name, Fullname) < 0) { /* missing dir.? */
					unlink(Fullname);
					missdir(Fullname);
					if(link(Hdr.h_name, Fullname) < 0) {
						err(
						 "Cannot link <%s> & <%s>\n",
						 Hdr.h_name, Fullname);
						continue;
					}
				}
				set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
				goto ckverbose;
			}
			if(!(Ofile = openout(Fullname)))
				continue;
			if((Ifile = open(Hdr.h_name, 0)) < 0) {
				err("<%s> ?\n", Hdr.h_name);
				close(Ofile);
				continue;
			}
			filesz = Statb.st_size;
			for(; filesz > 0; filesz -= 512) {
			    ct = filesz>512? 512: filesz;
				if(read(Ifile, Buf, ct) < 0) {
				    err("Cannot read %s\n", Hdr.h_name);
				    break;
				}
			    if(Ofile)
				    if(write(Ofile, Buf, ct) < 0) {
					if(errno == ENOSPC) { 
					    err("cpio: File system full -- quit\n");
					    exit(2);
					}
				        err("Cannot write %s\n", Hdr.h_name);
				        break;
				    }
			    ++Blocks;
			}
			close(Ifile);
			if(Acc_time)
				utime(Hdr.h_name, &Statb.st_atime);
			if(Ofile) {
				close(Ofile);
				set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime));
ckverbose:
				if(Verbose)
					puts(Fullname);
			}
		}
#endif	STANDALONE
	}
	err("%ld blocks\n", Blocks * (Bufsize>>9));
	exit(0);
}
usage()
{
#ifdef VALID
#ifdef	STANDALONE
  printf("Usage: cpio -o[acvBS] <name-list >collection\n");
  printf("       cpio -i[cdmrstuvBM6] [pattern ...] <collection\n");
  printf("       cpio -if[cdmrstuvBM6] file-of-files <collection\n");
  printf("       cpio -iq[cdmrstuvBM6] path-of-one-file <collection\n");
  printf("       cpio -p[adlmruvMS] directory <name-list\n");
#else	STANDALONE
  fprintf(stderr,"Usage: cpio -o[acvBS] <name-list >collection\n");
  fprintf(stderr,"       cpio -i[cdmrstuvBM6] [pattern ...] <collection\n");
  fprintf(stderr,"       cpio -if[cdmrstuvBM6] file-of-files <collection\n");
  fprintf(stderr,"       cpio -iq[cdmrstuvBM6] path-of-one-file <collection\n");
  fprintf(stderr,"       cpio -p[adlmruvMS] directory <name-list\n");
#endif	STANDALONE
#else
	err("Usage: cpio -o[acvB] <name-list >collection\n%s\n%s\n",
	"       cpio -i[cdmrstuvB6] [pattern ...] <collection",
	"       cpio -p[adlmruv] directory <name-list");
#endif
	exit(2);
}

#ifndef	STANDALONE
getname()
{
	register char *namep = Name;
	long tlong;

	for(;;) {
		if(gets(namep) == NULL)
			return 0;
		if(*namep == '.' && namep[1] == '/')
			namep += 2;
		strcpy(Hdr.h_name, namep);
#ifdef VALID
#ifdef	STANDALONE
                DODEBUG3(printf(
				"In getname namep is %s literalsymlink is %o\n",
				namep,literalsymlink);)
#else	STANDALONE
                DODEBUG3(fprintf(stderr,
				"In getname namep is %s literalsymlink is %o\n",
				namep,literalsymlink);)
#endif	STANDALONE
		if ( literalsymlink ) {
#ifdef	STANDALONE
		    DODEBUG3(printf("Doing lstat\n");)
#else	STANDALONE
		    DODEBUG3(fprintf(stderr,"Doing lstat\n");)
#endif	STANDALONE
		    if(lstat(namep, &Statb) < 0) {
			    err("< %s > ?\n", Hdr.h_name);
			    continue;
		    }
		}
		else
#endif
		    if(stat(namep, &Statb) < 0) {
			    err("< %s > ?\n", Hdr.h_name);
			    continue;
		    }
#ifdef VALID
		A_symbolic = (Statb.st_mode & Filetype) == S_IFLNK;
#ifdef	STANDALONE
		DODEBUG3(printf(
			 "still in getname Statb.st_mode is %o\n",
			 Statb.st_mode);)
#else	STANDALONE
		DODEBUG3(fprintf(stderr,
			 "still in getname Statb.st_mode is %o\n",
			 Statb.st_mode);)
#endif	STANDALONE
#ifdef	STANDALONE
                DODEBUG3(printf("still in getname A_symbolic is %o\n",
				A_symbolic);)
#else	STANDALONE
                DODEBUG3(fprintf(stderr,"still in getname A_symbolic is %o\n",
				A_symbolic);)
#endif	STANDALONE
#endif
		A_directory = (Statb.st_mode & Filetype) == S_IFDIR;
		A_special = ((Statb.st_mode & Filetype) == S_IFBLK)
			|| ((Statb.st_mode & Filetype) == S_IFCHR)
			|| ((Statb.st_mode & Filetype) == S_IFIFO);
#ifdef RT
		if(MERT) {
			One_extent = (Statb.st_mode & Filetype) == S_IF1EXT;
			Multi_extent = (Statb.st_mode & Filetype) == S_IFEXT;
		}
#endif
		Hdr.h_magic = MAGIC;
		Hdr.h_namesize = strlen(Hdr.h_name) + 1;
		Hdr.h_uid = Statb.st_uid;
		Hdr.h_gid = Statb.st_gid;
		Hdr.h_dev = Statb.st_dev;
		Hdr.h_ino = Statb.st_ino;
		Hdr.h_mode = Statb.st_mode;
		MKSHORT(Hdr.h_mtime, Statb.st_mtime);
		Hdr.h_nlink = Statb.st_nlink;
#ifdef VALID
		if ( A_symbolic ) {
		    if((tlong=readlink(Hdr.h_name,symbuf,sizeof(symbuf))) < 0) {
			err("Cannot readlink %s\n",Hdr.h_name);
			continue;
		    }
#ifdef	STANDALONE
		    DODEBUG3(printf(
				  "still in getname tlong is %d symbuf is %s\n",
				  tlong,symbuf);)
#else	STANDALONE
		    DODEBUG3(fprintf(stderr,
				  "still in getname tlong is %d symbuf is %s\n",
				  tlong,symbuf);)
#endif	STANDALONE
		}
		else
#endif
		    tlong = Hdr.h_mode & S_IFREG? Statb.st_size: 0L;
		MKSHORT(Hdr.h_filesize, tlong);
		Hdr.h_rdev = Statb.st_rdev;
		if(Cflag)
			bintochar(tlong);
		return 1;
	}
}

bintochar(t)
long t;
{
	sprintf(Chdr,"%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.11lo%.6ho%.11lo%s",
		MAGIC,Statb.st_dev,Statb.st_ino,Statb.st_mode,Statb.st_uid,
		Statb.st_gid,Statb.st_nlink,Statb.st_rdev & 00000177777,
		Statb.st_mtime,(short)strlen(Hdr.h_name)+1,t,Hdr.h_name);
}
#endif	STANDALONE

#ifndef	STANDALONE
chartobin()
{
	sscanf(Chdr,"%6ho%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6ho%11lo",
		&Hdr.h_magic,&Hdr.h_dev,&Hdr.h_ino,&Hdr.h_mode,&Hdr.h_uid,
		&Hdr.h_gid,&Hdr.h_nlink,&Hdr.h_rdev,&Longtime,&Hdr.h_namesize,
		&Longfile);
	MKSHORT(Hdr.h_filesize, Longfile);
	MKSHORT(Hdr.h_mtime, Longtime);
}
#endif	STANDALONE

gethdr()
{

#ifndef	STANDALONE
	if ( Cflag )  {
		readhdr(Chdr,CHARS);
		chartobin();
	}
	else
#endif	STANDALONE
		bread(&Hdr, HDRSIZE);

	if(Hdr.h_magic != MAGIC) {
#ifdef	STANDALONE
	printf("%6o %6o %6o %6o %6o %6o %6o %6o %11o %6o %11o %s",
		&Hdr.h_magic,&Hdr.h_dev,&Hdr.h_ino,&Hdr.h_mode,&Hdr.h_uid,
		&Hdr.h_gid,&Hdr.h_nlink,&Hdr.h_rdev,&Longtime,&Hdr.h_namesize,
		&Longfile);
#endif	STANDALONE
		err("Out of phase--get help\n");
		exit(2);
	}
	if(!Cflag)
	     bread(Hdr.h_name, Hdr.h_namesize);
	else
	     readhdr(Hdr.h_name, Hdr.h_namesize);
	if(Swap)
		swap(Hdr.h_name, Hdr.h_namesize);
	if(EQ(Hdr.h_name, "TRAILER!!!"))
		return 0;
#ifdef VALID
	A_symbolic = (Hdr.h_mode & Filetype) == S_IFLNK;
#ifdef	STANDALONE
	DODEBUG3(printf("In gethdr A_symbolic is %o\n",A_symbolic);)
#else	STANDALONE
	DODEBUG3(fprintf(stderr,"In gethdr A_symbolic is %o\n",A_symbolic);)
#endif	STANDALONE
#endif
	A_directory = (Hdr.h_mode & Filetype) == S_IFDIR;
	A_special =((Hdr.h_mode & Filetype) == S_IFBLK)
		|| ((Hdr.h_mode & Filetype) == S_IFCHR)
		|| ((Hdr.h_mode & Filetype) == S_IFIFO);
#ifdef RT
	if( (MERT) && (((Hdr.h_mode & Filetype) == S_IF1EXT)
		|| ((Hdr.h_mode & Filetype) == S_IFEXT))) {
		One_extent = (Hdr.h_mode & Filetype) == S_IF1EXT;
		Multi_extent = (Hdr.h_mode & Filetype) == S_IFEXT;
		Actual_size[0] = Hdr.h_filesize[0];
		Actual_size[1] = Hdr.h_filesize[1];
		bread(&Hdr, HDRSIZE);
		if(Hdr.h_magic != MAGIC) {
			err("Out of phase--get MERT help");
			exit(2);
		}
		bread(Hdr.h_name, Hdr.h_namesize);
	}
#endif
	return 1;
}

ckname(namep)
register char *namep;
{
	++Select;
#ifdef VALID
	if (FileList) {
	    if (!SearchFileTable(namep)) {
		Select = 0;
		return 0;
	    }
	} else
	if (quitwhenfoundit) {
	    if (strcmp(namep,pathofqfile) == 0) 
		foundqfile = TRUE;
	    else {
		Select = 0;
		return 0;
	    } 
	} else
#endif
	if(!nmatch(namep, Pattern)) {
		Select = 0;
		return 0;
	}
	if(Rename && !A_directory) {
#ifndef	STANDALONE
		fprintf(Wtty, "Rename <%s>\n", namep);
		fflush(Wtty);
		fgets(namep, 128, Rtty);
		if(feof(Rtty))
			exit(2);
#endif	STANDALONE
		namep[strlen(namep) - 1] = '\0';
		if(EQ(namep, "")) {
			printf("Skipped\n");
			return 0;
		}
	}
	return !Toc;
}

openout(namep)
register char *namep;
{
#ifdef VALID
	register ct;
	long filesz;
#endif
	register f;
	register char *np;

	if(!strncmp(namep, "./", 2))
		namep += 2;
	np = namep;
#ifndef	STANDALONE
	/*
	 * In standalone all paths are rooted by definition.
	 */
	if(Option == IN)
		Cd_name = namep = cd(namep);
#endif	STANDALONE
#ifdef VALID
#ifdef	STANDALONE
        DODEBUG3(printf("In openout namep is %s A_symbolic is %o\n",
			 namep,A_symbolic);)
#else	STANDALONE
        DODEBUG3(fprintf(stderr,"In openout namep is %s A_symbolic is %o\n",
			 namep,A_symbolic);)
#endif	STANDALONE
	if(A_symbolic) {
	    if (Option == IN) { 
		/* In the PASS option symbuf is already filled by getname */
		for(filesz=0; filesz<mklong(Hdr.h_filesize); filesz+= 512){
		    ct = mklong(Hdr.h_filesize)-filesz>512? 512: mklong(Hdr.h_filesize)-filesz;
		    Cflag? readhdr(symbuf+filesz, ct): bread(symbuf+filesz, ct);
		}
	        symbuf[mklong(Hdr.h_filesize)]='\0';
	    }

	    if(Swap)
		swap(Buf, ct);

            /* remove file if it exists before trying to make it */
            if(lstat(namep,&Statb) == 0) {
		if( ((Statb.st_mode & Filetype) == S_IFLNK) ||
		    ((Statb.st_mode & Filetype) == S_IFREG)    ) {
		    /* remove it then make the symbolic link */
                    if(unlink(namep) < 0) {
			perror('cpio');
			err("Cannot remove %s\n",namep);
			err("    so cannot create symbolic link file %s\n",namep);
		    }
		    else {
#ifdef CHMOD_OK
#else
/* Currently (12-84 at VALID) chmod changes the mode of the file the symbolic 
 * link points to rather that the symbolic link it self. This is a kludge'y 
 * work around.
 */
			umask( 0777 - (Hdr.h_mode & 0777) );
#endif
			if (symlink(symbuf,namep) < 0) {
			    err("Cannot create symbolic link file %s\n",namep);
			}
			else {
#ifdef CHMOD_OK
			    chmod(namep, Hdr.h_mode);
#endif
			    if(Uid == 0)
				chown(namep, Hdr.h_uid, Hdr.h_gid);
			}
#ifdef CHMOD_OK
#else
			umask(0);
#endif
		    }
		}
		else { /* its a dir or a special file */
		    err("Cannot create symbolic link file %s.\n",namep);
		    if( (Statb.st_mode & Filetype) == S_IFDIR ) 
		        err("    It already exists and is a directory.\n");
		    if( ((Statb.st_mode & Filetype) == S_IFCHR) ||  
		        ((Statb.st_mode & Filetype) == S_IFBLK) )  
		        err("    It already exists and is a device.\n");
		}

	    }
	    else { /* file does not exist, no problem */
#ifdef CHMOD_OK
#else
		umask( 0777 - (Hdr.h_mode & 0777) );
#endif
		if (symlink(symbuf,namep) < 0) {
		    err("Cannot create symbolic link file %s\n",namep);
		}
		else {
#ifdef CHMOD_OK
		    chmod(namep, Hdr.h_mode);
#endif
		    if(Uid == 0)
			chown(namep, Hdr.h_uid, Hdr.h_gid);
		}
#ifdef CHMOD_OK
#else
		umask(0);
#endif
	    }
	    MKSHORT(Hdr.h_filesize,0); /* So "IN" won't try to read file body */
	    return 0;
	}
#endif
	if(A_directory) {
#ifdef VALID
		if(!Dir
		|| Rename
		|| EQ(namep, ".")
		|| EQ(namep, ".."))
			return 0;

		if(stat(namep, &Xstatb) == 0) {
		    if (chmodexistdirs) {
			/* make sure that mode in the archive is used */
			chmod(namep, Hdr.h_mode);
			if(Uid == 0)
			    chown(namep, Hdr.h_uid, Hdr.h_gid);
		    }
		    return 0;
		}
#else
		if(!Dir
		|| Rename
		|| EQ(namep, ".")
		|| EQ(namep, "..")
		|| stat(namep, &Xstatb) == 0)
			return 0;
#endif

		if(!makdir(namep)) {
			missdir(namep);
		}
ret:
		chmod(namep, Hdr.h_mode);
		if(Uid == 0)
			chown(namep, Hdr.h_uid, Hdr.h_gid);
		set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
		return 0;
	}
	if(Hdr.h_nlink > 1)
		if(!postml(namep, np))
			return 0;
	if(A_special) {
s_again:
		if((Hdr.h_mode & Filetype) == S_IFIFO)
			Hdr.h_rdev = 0;
		if(mknod(namep, Hdr.h_mode, Hdr.h_rdev) < 0) {
			if(missdir(namep))
				goto s_again;
			err("Cannot mknod <%s>\n", namep);
			return 0;
		}
		goto ret;
	}
	if(stat(namep, &Xstatb) == 0) {
		if(Uncond && !(Xstatb.st_mode & S_IWRITE))
			unlink(namep);
		if(!Uncond && (mklong(Hdr.h_mtime) < Xstatb.st_mtime)) {
			err("current <%s> newer\n", namep);
			return 0;
		}
	}
	if(Option == PASS
	&& Hdr.h_ino == Xstatb.st_ino
	&& Hdr.h_dev == Xstatb.st_dev) {
		err("Attempt to pass file to self!\n");
		exit(2);
	}
#ifdef RT
one_again:
	if(One_extent || Multi_extent) {
		if((f = falloc(namep, Hdr.h_mode, Hdr.h_filesize[0].long_size)) < 0) {
			if(missdir(namep))
				goto one_again;
			err("Cannot create <%s> (errno:%d)\n", namep, errno);
			return 0;
		}
		if(filespace < Hdr.h_filesize[0].long_size){
			err("Cannot create contiguous file <%s> proper size\n", namep);
			err("    <%s> will be created as a regular file\n", namep);
			if(unlink(Fullname) != 0)
				err("<%s> not removed\n", namep);
			New_mode = Hdr.h_mode & Remove_mode;
			New_mode = New_mode | S_IFREG;
once_again:
			if((f = creat(namep, New_mode)) < 0){
				if(missdir(namep))
					goto once_again;
				err("Cannot create <%s> (errno:%d)\n", namep, errno);
				return (0);
			}
		}
	}
#endif
#ifdef RT
	if(MERT && (One_extent || Multi_extent))
		goto skip_c;
#endif
c_again:
	if((f = creat(namep, Hdr.h_mode)) < 0) {
		if(missdir(namep))
			goto c_again;
		err("Cannot create <%s> (errno:%d)\n", namep, errno);
		return 0;
	}
#ifdef VALID
        /* make sure that mode in the archive is used */
	fchmod(f,Hdr.h_mode);
#endif

#ifdef RT
skip_c:
#endif
	if(Uid == 0)
		chown(namep, Hdr.h_uid, Hdr.h_gid);
	return f;
}

bread(b, c)
register c;
register short *b;
{
	static nleft = 0;
	static short *ip;
	register short *p = ip;

	c = (c+1)>>1;
	while(c--) {
		if(!nleft) {
again:
/*
			if(read(Input, Dbuf, Bufsize)!=Bufsize) {
*/
			if(fillBuffer(Input, Dbuf, Bufsize) <= 0) {
				Input = chgreel(0, Input);
				goto again;
			}
			nleft = Bufsize >> 1;
			p = Dbuf;
			++Blocks;
		}
		*b++ = *p++;
		--nleft;
	}
	ip = p;
}

readhdr(b, c)
register c;
register char *b;
{
	static nleft = 0;
	static char *ip;
	register char *p = ip;

	while(c--)  {
		if(!nleft)  {
again:
/*
			if(read(Input, Cbuf, Bufsize) != Bufsize)  {
*/
			if(fillBuffer(Input, Cbuf, Bufsize) <= 0)  {
				Input = chgreel(0, Input);
				goto again;
			}
			nleft = Bufsize;
			p = Cbuf;
			++Blocks;
		}
		*b++ = *p++;
		--nleft;
	}
	ip = p;
}

fillBuffer(file, buffer, size)
register int file;
register char * buffer;
register int size;
{
	register int bytesRead;

	errno = 0;
	while(size > 0)  {
		if((bytesRead = read(file, buffer, size)) <= 0)
			return(bytesRead);
		size -= bytesRead;
		buffer += bytesRead;
	}
	return(1);
}

bwrite(rp, c)
register short *rp;
register c;
{
	register short *wp = Wp;

	c = (c+1) >> 1;
	while(c--) {
		if(!Wct) {
again:
			if(write(Output, Dbuf, Bufsize)<0) {
				if(errno == ENOSPC) { 
				    err("cpio: File system full -- quit\n");
				    exit(2);
				}
				Output = chgreel(1, Output);
				goto again;
			}
			Wct = Bufsize >> 1;
			wp = Dbuf;
			++Blocks;
		}
		*wp++ = *rp++;
		--Wct;
	}
	Wp = wp;
}
writehdr(rp,c)
register char *rp;
register c;
{
         register char *cp = Cp;

         while(c--)  {
                 if(!Wc)  {
again:
                        if(write(Output,Cbuf,Bufsize)<0)  {
				if(errno == ENOSPC) { 
				    err("cpio: File system full -- quit\n");
				    exit(2);
				}
                                Output = chgreel(1, Output);
                                goto again;
                        }
                        Wc = Bufsize;
                        cp = Cbuf;
                        ++Blocks;
                 }
                 *cp++ = *rp++;
                 --Wc;
         }
         Cp = cp;
}


postml(namep, np)
register char *namep, *np;
{
	register i;
	static struct ml {
		short	m_dev,
			m_ino;
		char	m_name[2];
	} *ml[LINKS];
	static	mlinks = 0;
	char *mlp;

	for(i = 0; i < mlinks; ++i) {
		if(mlinks == LINKS) break;
		if(ml[i]->m_ino==Hdr.h_ino &&
			ml[i]->m_dev==Hdr.h_dev) {
			if(Verbose)
			  printf("%s linked to %s\n", ml[i]->m_name,
				np);
			unlink(namep);
			if(Option == IN) {
				Fullname[Pathend] = '\0';
				strcat(Fullname, ml[i]->m_name);
				mlp = Fullname;
			} else
				mlp = ml[i]->m_name;
l_again:
			if(link(mlp, namep) < 0) {
				if(missdir(np))
					goto l_again;
				err("Cannot link <%s>&<%s>.\n",
					ml[i]->m_name, np);
			}
			set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
			return 0;
		}
	}
	if(mlinks == LINKS
	|| !(ml[mlinks] = (struct ml *)malloc(strlen(np) + 2 + sizeof(struct ml)))) {
		static int first=1;

		if(first)
			if(mlinks == LINKS)
				err("Too many links\n");
			else
				err("No memory for links\n");
		mlinks = LINKS;
		first = 0;
		return 1;
	}
	ml[mlinks]->m_dev = Hdr.h_dev;
	ml[mlinks]->m_ino = Hdr.h_ino;
	strcpy(ml[mlinks]->m_name, np);
	++mlinks;
	return 1;
}

pentry(namep)
register char *namep;
{

	register i;
	static short lastid = -1;
#include <pwd.h>
#ifndef	STANDALONE
	static struct passwd *pw;
	struct passwd *getpwuid();
#endif	STANDALONE
	static char tbuf[32];

	printf("%-7o", Hdr.h_mode & 0177777);
#ifndef	STANDALONE
	if(lastid == Hdr.h_uid)
		printf("%-6s", pw->pw_name);
	else {
		setpwent();
		if(pw = getpwuid(Hdr.h_uid)) {
			printf("%-6s", pw->pw_name);
			lastid = Hdr.h_uid;
		} else {
			printf("%-6d", Hdr.h_uid);
#else	STANDALONE
			printf(" %6d", Hdr.h_uid);
#endif	STANDALONE
			lastid = -1;
#ifndef	STANDALONE
		}
	}
#endif	STANDALONE
	printf("%7ld ", mklong(Hdr.h_filesize));
	U.l = mklong(Hdr.h_mtime);
	strcpy(tbuf, ctime(&U.l));
	tbuf[24] = '\0';
	printf(" %s  %s\n", &tbuf[4], namep);
}

nmatch(s, pat)
char *s, **pat;
{
	if(EQ(*pat, "*"))
		return 1;
	while(*pat) {
		if((**pat == '!' && !gmatch(s, *pat+1))
		|| gmatch(s, *pat))
			return 1;
		++pat;
	}
	return 0;
}
gmatch(s, p)
register char *s, *p;
{
	register int c;
	register cc, ok, lc, scc;

	scc = *s;
	lc = 077777;
	switch (c = *p) {

	case '[':
		ok = 0;
		while (cc = *++p) {
			switch (cc) {

			case ']':
				if (ok)
					return(gmatch(++s, ++p));
				else
					return(0);

			case '-':
				ok |= (lc <= scc & scc <= (cc=p[1]));
			}
			if (scc==(lc=cc)) ok++;
		}
		return(0);

	case '?':
	caseq:
		if(scc) return(gmatch(++s, ++p));
		return(0);
	case '*':
		return(umatch(s, ++p));
	case 0:
		return(!scc);
	}
	if (c==scc) goto caseq;
	return(0);
}

umatch(s, p)
register char *s, *p;
{
	if(*p==0) return(1);
	while(*s)
		if (gmatch(s++,p)) return(1);
	return(0);
}

makdir(namep)
register char *namep;
{
#ifdef VALID
        int returncode;
        umask(022);
DODEBUG3( printf( "In makdir, about to call mkdir\n" ) );
        returncode=mkdir(namep,0777);
	umask(0);
	if(returncode == 0)
	    return(1);
	else
	    return(0);
#else
	static status;
	register pid;

	if(pid = fork())
		while(wait(&status) != pid);
	else {
		close(2);
		execl("/bin/mkdir", "mkdir", namep, 0);
		exit(2);
	}
	return ((status>>8) & 0377)? 0: 1;
#endif
}

swap(buf, ct)
register ct;
register union swp { short	shortw; char	charv[2]; } *buf;
{
	register char c;

	ct = (ct + 1) >> 1;

	while(ct--) {
		c = buf->charv[0];
		buf->charv[0] = buf->charv[1];
		buf->charv[1] = c;
		++buf;
	}
}
set_time(namep, atime, mtime)
register *namep;
long atime, mtime;
{
	static long timevec[2];

	if(!Mod_time)
		return;
	timevec[0] = atime;
	timevec[1] = mtime;
	utime(namep, timevec);
}
chgreel(x, fl)
{
	register f;
	char str[22];
#ifndef	STANDALONE
	FILE *devtty;
#endif	STANDALONE
	struct stat statb;

	err("errno: %d, ", errno);
	err("Can't %s\n", x? "write output": "read input");
	fstat(fl, &statb);
#ifdef RT
	if(!MERT){
		if((statb.st_mode&S_IFMT) != S_IFCHR)
			exit(2);
	}
	else if((statb.st_mode & (S_IFBLK|S_IFREC))==0)
		exit(2);
#endif
#ifndef RT
	if((statb.st_mode&S_IFMT) != S_IFCHR)
		exit(2);
#endif
#ifdef	STANDALONE
	/*
	 * No support for multi-reel archives in standalone - yet
	 */

	exit (2);
#else	STANDALONE
again:
	err("If you want to go on, type device/file name when ready\n");
	devtty = fopen("/dev/tty", "r");
	fgets(str, 20, devtty);
	str[strlen(str) - 1] = '\0';
	if(!*str)
		exit(2);
	close(fl);
	if((f = open(str, x? 1: 0)) < 0) {
		err("That didn't work");
		fclose(devtty);
		goto again;
	}
	return f;
#endif	STANDALONE
}
missdir(namep)
register char *namep;
{
	register char *np;
	register ct = 0;

	if(!Dir)
		return 0;
	for(np = namep; *np; ++np)
		if(*np == '/') {
			*np = '\0';
			if(stat(namep, &Xstatb) == -1) {
			  if (makdir(namep))
			      ++ct;
			  else {
#ifdef	STANDALONE
			      printf("Can't mkdir %s\n",namep);
#else	STANDALONE
			      fprintf(stderr,"Can't mkdir %s\n",namep);
#endif	STANDALONE
			      exit(1);
			  }
                        }
			else {
			  if((Xstatb.st_mode & S_IFMT) != S_IFDIR) {
			     if(*namep != '/') { /* not rooted */
				 pwd(); /* set Fullname to current dir */
#ifdef	STANDALONE
				 printf(
#else	STANDALONE
				 fprintf(stderr,
#endif	STANDALONE
				 "\"%s%s\" already exists and is not ",
				 Fullname,namep);
#ifdef	STANDALONE
				 printf("a directory\n");
#else	STANDALONE
				 fprintf(stderr,"a directory\n");
#endif	STANDALONE
				 exit(1);
			     }
			     else {
#ifdef	STANDALONE
				 printf(
#else	STANDALONE
				 fprintf(stderr,
#endif	STANDALONE
				 "\"%s\" already exists and is not ",
				 namep);
#ifdef	STANDALONE
				 printf("a directory\n");
#else	STANDALONE
				 fprintf(stderr,"a directory\n");
#endif	STANDALONE
				 exit(1);
			     }
			  }
			}
			*np = '/';
		}
	return ct;
}
err(a, b, c)
{
#ifdef	STANDALONE
	printf(a, b, c);
#else	STANDALONE
	fprintf(stderr, a, b, c);
#endif	STANDALONE
}
pwd()
{
#ifdef	STANDALONE
	int dir;
#else	STANDALONE
	FILE *dir;
#endif	STANDALONE

#ifdef	STANDALONE
	strcpy(Fullname, "/");
#else	STANDALONE
	dir = popen("pwd", "r");
	fgets(Fullname, 256, dir);
	if(pclose(dir)) {
	    fprintf(stderr, "pwd fails -- check /bin/pwd and /bin/sh\n");
	    exit(2);
	}
#endif	STANDALONE
	Pathend = strlen(Fullname);
	Fullname[Pathend - 1] = '/';
}

#ifndef	STANDALONE
char * cd(n)
register char *n;
{
	char *p_save = Name, *n_save = n, *p_end = 0;
	register char *p = Name;
	static char dotdot[]="../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../";
	int slashes;
#ifdef DOTDOTBROKEN
	/* If there is a symbolic link directory which is cd'ed into 
	 * then cd'ing to ".." will not put you where you want to be 
	 * (your cd parent) This is fixed by cd'ing to an absolute 
	 * path. There is talk of fixing this ".." problem by having the
	 * kernel keep track of you current directory but this is
	 * not currently implemented. For now the speed of ".." is
	 * given up for the correct behavior of absolute paths.
	 */
	int startlen;
	register char *a;
	char *a_end = 0;
	char *savefulln = n;
#endif

	if(*n == '/') /* don't try to chdir on full pathnames */
		return n;
	for(; *p && *n == *p; ++p, ++n) { /* whatever part of strings == */
		if(*p == '/')
			p_save = p+1, n_save = n+1;
	}

	p = p_save;
	*p++ = '\0';
	for(slashes = 0; *p; ++p) { /* if prev is longer, chdir("..") */
		if(*p == '/')
			++slashes;
	}
	if(slashes) {
#ifdef DOTDOTBROKEN
                startlen=strlen(absolutepath);
		/* copy the dir part of n we were called with onto the end of 
		 * absolutepath. Also, change the saved path (Name) to the
		 * current path before returning */
		for(a=absolutepath+startlen, n=savefulln, p=Name ;
		    *n ; 
		    ++a, ++n, ++p) 
		{
		    *a = *n;
		    *p = *n;
		    if(*n == '/')
			a_end=a+1, n_save = n+1, p_end = p+1;
		}
		*p='\0';
		if(a_end != 0)
		    *(a_end)='\0';
		else
		    absolutepath[startlen]='\0';

		if(p_end != 0)
		    *(p_end)='\0';
		else
		    *Name='\0';
    
		if(chdir(absolutepath) == -1) {
		    if(!missdir(absolutepath)) {
cd_abs_err:
			    err("Cannot chdir (no `d' option)\n");
			    exit(2);
		    } else if(chdir(absolutepath) == -1)
			    goto cd_abs_err;
		}
                /* set absolutepath back to the working dir of cpio when 
		 * started */
		absolutepath[startlen]='\0';
		return n_save;
#else
		slashes = slashes * 3 - 1;
		dotdot[slashes] = '\0';
		chdir(dotdot);
		dotdot[slashes] = '/';
#endif
	}

	n = n_save;
	p = p_save;
	for(; *n; ++n, ++p) {
		*p = *n;
		if(*n == '/')
			p_end = p+1, n_save = n+1;
	}
	*p = '\0';

	if(p_end) {
		*p_end = '\0';
		if(chdir(p_save) == -1) {
			if(!missdir(p_save)) {
cd_err:
				err("Cannot chdir (no `d' option)\n");
				exit(2);
			} else if(chdir(p_save) == -1)
				goto cd_err;
		}
	} else
		*p_save = '\0';
	return n_save;
}
#endif	STANDALONE

#ifdef RT
actsize()
{
}
#endif

#ifdef STANDALONE

/* Random numbers with non-random names -- ain't we all? */
#define NFLAGS		16
#define FNAMEMAX	63

getargs(aargc, aargv)
	int *aargc;
	char ***aargv;
{
	static char flagbuf[NFLAGS],
		    fnamebuf[FNAMEMAX+1];
	register int i;
	static char *arguments[] = 
		{ "standalone cpio", flagbuf, 0 };

	*aargv = arguments;
	*aargc = 2;
	printf(version);

	while(1)
	{
		printf("Specify flag arguments to cpio: ");
		gets(flagbuf);

		if (index(flagbuf,'i'))
		{
			/* Reading in a cpio file. */
getin:
			printf("Input file? ");
			gets(fnamebuf);
			if ((Input = open (fnamebuf, 0)) < 0) {
				printf ("Bad input file name\n");
				goto getin;
			}
getroot:
			if (index(flagbuf,'t') == 0) {
				printf ("Root directory? ");
				gets(fnamebuf);
				if ((i = open (fnamebuf, 0)) < 0) {
					printf ("Bad root directory\n");;
					goto getroot;
				}
				close (i);
			}
			break;
		}
		else if (index(flagbuf,'o'))
		{
			/* Writing out a cpio file. */
			printf("File containing names of files to be cpio'd? ");
			gets(fnamebuf);
			printf("Output routed to it(0,2).\n");
			break;
		}
		else
			printf("Must specify 'i' or 'o' ('p' worthless).\n");
	}
	DODEBUG(printf("Got args: \"%s\" \"%s\", argc=%d\n",
		(*aargv)[0], (*aargv)[1], *aargc);)
	return (0);
}
#endif STANDALONE
