xref: /csrg-svn/old/cpio/cpio.c (revision 37871)
133828Sbostic /*	Copyright (c) 1988 AT&T	*/
233828Sbostic /*	  All Rights Reserved  	*/
333828Sbostic 
433828Sbostic /*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
533828Sbostic /*	The copyright notice above does not evidence any   	*/
633828Sbostic /*	actual or intended publication of such source code.	*/
733828Sbostic 
833828Sbostic #ident	"@(#)cpio:cpio.c	1.30.1.11"
933828Sbostic /*	/sccs/src/cmd/s.cpio.c
1033828Sbostic 	cpio.c	1.30.1.11	1/11/86 13:46:48
1133828Sbostic 	Reworked cpio which uses getopt(3) to interpret flag arguments and
1233828Sbostic 	changes reels to the save file name.
1333828Sbostic 	Performance and size improvements.
1433828Sbostic */
1533828Sbostic 
1633828Sbostic /*	cpio	COMPILE:	cc -O cpio.c -s -i -o cpio -lgen -lerr
1733828Sbostic 	cpio -- copy file collections
1833828Sbostic 
1933828Sbostic */
2033828Sbostic #include <errno.h>
2133828Sbostic #include <fcntl.h>
2233828Sbostic #include <memory.h>
2333828Sbostic #include <stdio.h>
2433828Sbostic #include <string.h>
2533828Sbostic #include <signal.h>
2633828Sbostic #include <varargs.h>
2733829Sbostic #include <sys/param.h>
2833829Sbostic #include <sys/types.h>
2933828Sbostic #include <sys/stat.h>
30*37871Sbostic #include <paths.h>
3133828Sbostic 
3233829Sbostic struct utimbuf {
3333829Sbostic 	time_t	actime;
3433829Sbostic 	time_t	modtime;
3533829Sbostic };
3633829Sbostic #ifndef S_IFIFO
3733829Sbostic #define	S_IFIFO	010000
3833829Sbostic #endif
3933829Sbostic 
4033828Sbostic #define EQ(x,y)	(strcmp(x,y)==0)
4133828Sbostic 
4233828Sbostic 				/* MKSHORT:  for VAX, Interdata, ...	*/
4333828Sbostic 				/* Take a 4-byte long, lv, and turn it	*/
4433828Sbostic 				/* into an array of two 2-byte shorts, v*/
4533828Sbostic #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];}
4633828Sbostic 
4733828Sbostic #define MAGIC	070707		/* cpio magic number */
4833829Sbostic #define BSMAGIC	0143561		/* byte-swapped cpio magic number */
4933828Sbostic #define IN	'i'		/* copy in */
5033828Sbostic #define OUT	'o'		/* copy out */
5133828Sbostic #define PASS	'p'		/* direct copy */
5233828Sbostic #define HDRSIZE	(Hdr.h_name - (char *)&Hdr)	/* header size minus filename field */
5333828Sbostic #define LINKS	500		/* no. of links allocated per bunch */
5433828Sbostic #define CHARS	76		/* ASCII header size minus filename field */
5533828Sbostic #define BUFSIZE 512		/* In u370, can't use BUFSIZ or BSIZE */
5633828Sbostic #define CPIOBSZ 4096		/* file read/write */
5733828Sbostic #define MK_USHORT(a)	(a & 00000177777)	/* Make unsigned shorts for portable  */
5833828Sbostic 						/* header.  Hardware may only know    */
5933828Sbostic 						/* integer operations and sign extend */
6033828Sbostic 						/* the large unsigned short resulting */
6133828Sbostic 						/* in 8 rather than 6 octal char in   */
6233828Sbostic 						/* the header.			      */
6333828Sbostic 
6433828Sbostic static struct	stat	Statb, Xstatb;
6533828Sbostic 
6633828Sbostic 	/* Cpio header format */
6733828Sbostic static struct header {
6833828Sbostic 	short	h_magic;
6933828Sbostic 	short	h_dev;
7033828Sbostic 	ushort	h_ino;
7133828Sbostic 	ushort	h_mode,
7233828Sbostic 		h_uid,
7333828Sbostic 		h_gid;
7433828Sbostic 	short	h_nlink;
7533828Sbostic 	short	h_rdev;
7633828Sbostic 	short	h_mtime[2],
7733828Sbostic 		h_namesize,
7833828Sbostic 		h_filesize[2];
7933828Sbostic 	char	h_name[256];
8033828Sbostic } Hdr;
8133828Sbostic 
8233829Sbostic char	Symlbuf[MAXPATHLEN + 1];	/* target of symbolic link */
8333828Sbostic static unsigned	Bufsize = BUFSIZE;		/* default record size */
8433828Sbostic static char	Buf[CPIOBSZ], *Cbuf;
8533828Sbostic static char	*Cp;
8633828Sbostic 
8733828Sbostic 
8833828Sbostic static
8933828Sbostic short	Option,
9033828Sbostic 	Dir,
9133828Sbostic 	Uncond,
9233828Sbostic 	PassLink,
9333828Sbostic 	Rename,
9433828Sbostic 	Toc,
9533828Sbostic 	Verbose,
9633828Sbostic 	Mod_time,
9733828Sbostic 	Acc_time,
9833828Sbostic 	Cflag,
9933828Sbostic 	fflag,
10033828Sbostic 	Swap,
10133828Sbostic 	byteswap,
10233828Sbostic 	halfswap;
10333828Sbostic 
10433828Sbostic static
10533828Sbostic int	Ifile,
10633828Sbostic 	Ofile,
10733828Sbostic 	Input = 0,
10833828Sbostic 	Output = 1;
10933828Sbostic 			/* sBlocks: short Blocks.  Cumulative character   */
11033828Sbostic 			/* count for short reads in bread().  Encountered */
11133828Sbostic 			/* with communication lines and pipes as in:      */
11233828Sbostic 			/* split -100 cpio_archive; cat xa* | cpio -icd   */
11333828Sbostic static
11433828Sbostic long	sBlocks,
11533828Sbostic 	Blocks,
11633828Sbostic 	Longfile,
11733828Sbostic 	Longtime;
11833828Sbostic 
11933828Sbostic static
12033828Sbostic char	Fullname[256],
12133828Sbostic 	Name[256];
12233828Sbostic static
12333828Sbostic int	Pathend;
12433828Sbostic static
12533828Sbostic char	*swfile;
12633828Sbostic static
12733828Sbostic char	*eommsg = "Change to part %d and press RETURN key. [q] ";
12833828Sbostic 
12933828Sbostic static
13033828Sbostic FILE	*Rtty,
13133828Sbostic 	*Wtty;
13233828Sbostic static
133*37871Sbostic char	ttyname[] = _PATH_TTY;
13433828Sbostic 
13533828Sbostic static
13633828Sbostic char	**Pattern = 0;
13733828Sbostic static
13833828Sbostic char	Chdr[500];
13933828Sbostic static
14033828Sbostic short	Dev;
14133828Sbostic ushort	Uid,
14233828Sbostic 	A_directory,
14333828Sbostic 	A_special,
14433829Sbostic 	A_symlink,
14533828Sbostic 	Filetype = S_IFMT;
14633828Sbostic 
14733828Sbostic extern	errno;
14833828Sbostic extern	void exit();
14933828Sbostic char	*malloc();
15033828Sbostic FILE 	*popen();
15133828Sbostic 
15233829Sbostic static char *smemcpy();
15333829Sbostic 
15433828Sbostic static
15533828Sbostic union {
15633828Sbostic 	long l;
15733828Sbostic 	short s[2];
15833828Sbostic 	char c[4];
15933828Sbostic } U;
16033828Sbostic 
16133828Sbostic /* for VAX, Interdata, ... */
16233828Sbostic static
16333828Sbostic long mklong(v)
16433828Sbostic short v[];
16533828Sbostic {
16633828Sbostic 	U.l = 1;
16733828Sbostic 	if(U.c[0])
16833828Sbostic 		U.s[0] = v[1], U.s[1] = v[0];
16933828Sbostic 	else
17033828Sbostic 		U.s[0] = v[0], U.s[1] = v[1];
17133828Sbostic 	return U.l;
17233828Sbostic }
17333828Sbostic 
17433828Sbostic main(argc, argv)
17533828Sbostic char **argv;
17633828Sbostic {
17733828Sbostic 	register ct;
17833828Sbostic 	long	filesz;
17933829Sbostic 	int	symlsz;
18033828Sbostic 	register char *fullp;
18133828Sbostic 	register i;
18233828Sbostic 	int ans;
18333829Sbostic 	register char *symlinkp;
18433828Sbostic 	short select;			/* set when files are selected */
18533828Sbostic 	extern char	*optarg;
18633828Sbostic 	extern int	optind;
18733828Sbostic 
18833829Sbostic 	signal(SIGSYS, SIG_IGN);
18933829Sbostic 	if(argc <= 1 || *argv[1] != '-')
19033828Sbostic 		usage();
19133828Sbostic 	Uid = getuid();
19233828Sbostic 
19333829Sbostic 	while( (ans = getopt( argc, argv, "aBC:ifopcdlmrSsbtuvM:6eI:O:")) != EOF ) {
19433828Sbostic 
19533828Sbostic 		switch( ans ) {
19633828Sbostic 		case 'a':		/* reset access time */
19733828Sbostic 			Acc_time++;
19833828Sbostic 			break;
19933828Sbostic 		case 'B':		/* change record size to 5120 bytes */
20033828Sbostic 			Bufsize = 5120;
20133828Sbostic 			break;
20233828Sbostic 		case 'C':		/* reset buffer size to arbitrary valu
20333828Sbostic 					*/
20433828Sbostic 			Bufsize = atoi( optarg );
20533829Sbostic 			if( Bufsize == 0 ) {
20633829Sbostic 				fperr("Illegal argument to -%c, '%s'",
20733828Sbostic 					ans, optarg );
20833829Sbostic 				exit(2);
20933829Sbostic 			}
21033828Sbostic 			break;
21133828Sbostic 		case 'i':
21233828Sbostic 			Option = IN;
21333828Sbostic 			break;
21433828Sbostic 		case 'f':	/* copy files not matched by patterns */
21533828Sbostic 			fflag++;
21633828Sbostic 			break;
21733828Sbostic 		case 'o':
21833828Sbostic 			Option = OUT;
21933828Sbostic 			break;
22033828Sbostic 		case 'p':
22133828Sbostic 			Option = PASS;
22233828Sbostic 			break;
22333828Sbostic 		case 'c':		/* ASCII header */
22433828Sbostic 			Cflag++;
22533828Sbostic 			break;
22633828Sbostic 		case 'd':		/* create directories when needed */
22733828Sbostic 			Dir++;
22833828Sbostic 			break;
22933828Sbostic 		case 'l':		/* link files, when necessary */
23033828Sbostic 			PassLink++;
23133828Sbostic 			break;
23233828Sbostic 		case 'm':		/* retain mod time */
23333828Sbostic 			Mod_time++;
23433828Sbostic 			break;
23533828Sbostic 		case 'r':		/* rename files interactively */
23633828Sbostic 			Rename++;
23733828Sbostic 			Rtty = fopen(ttyname, "r");
23833828Sbostic 			Wtty = fopen(ttyname, "w");
23933828Sbostic 			if(Rtty==NULL || Wtty==NULL) {
24033829Sbostic 				fperrno("Cannot rename (%s missing)",
24133828Sbostic 					ttyname );
24233829Sbostic 				exit(2);
24333828Sbostic 			}
24433828Sbostic 			break;
24533828Sbostic 		case 'S':		/* swap halfwords */
24633828Sbostic 			halfswap++;
24733828Sbostic 			Swap++;
24833828Sbostic 			break;
24933828Sbostic 		case 's':		/* swap bytes */
25033828Sbostic 			byteswap++;
25133828Sbostic 			Swap++;
25233828Sbostic 			break;
25333828Sbostic 		case 'b':		/* swap both bytes and halfwords */
25433829Sbostic 			halfswap++;
25533829Sbostic 			byteswap++;
25633828Sbostic 			Swap++;
25733828Sbostic 			break;
25833828Sbostic 		case 't':		/* table of contents */
25933828Sbostic 			Toc++;
26033828Sbostic 			break;
26133828Sbostic 		case 'u':		/* copy unconditionally */
26233828Sbostic 			Uncond++;
26333828Sbostic 			break;
26433828Sbostic 		case 'v':		/* verbose - print out file names */
26533829Sbostic 			Verbose++;
26633828Sbostic 			break;
26733828Sbostic 		case 'M':		/* alternate message for end-of-media */
26833828Sbostic 			eommsg = optarg;
26933828Sbostic 			break;
27033828Sbostic 		case '6':		/* for old, sixth-edition files */
27133828Sbostic 			Filetype = 060000;
27233828Sbostic 			break;
27333828Sbostic 		case 'I':
27433828Sbostic 			chkswfile( swfile, ans, Option );
27533829Sbostic 			if( (i = open( optarg, O_RDONLY ) ) < 0) {
27633829Sbostic 				fperrno("Cannot open <%s> for input", optarg);
27733829Sbostic 				exit(2);
27833829Sbostic 			}
27933829Sbostic 			if( dup2(i, Input ) < 0 ) {
28033829Sbostic 				fperrno("Cannot dup to standard input");
28133829Sbostic 				exit(2);
28233829Sbostic 			}
28333828Sbostic 			swfile = optarg;
28433828Sbostic 			break;
28533828Sbostic 		case 'O':
28633828Sbostic 			chkswfile( swfile, ans, Option );
28733829Sbostic 			if( (i = open( optarg, O_WRONLY | O_CREAT | O_TRUNC,
28833829Sbostic 			    0666 ) ) < 0) {
28933829Sbostic 				fperrno("Cannot open <%s> for output", optarg);
29033829Sbostic 				exit(2);
29133829Sbostic 			}
29233829Sbostic 			if( dup2(i, Output ) < 0 ) {
29333829Sbostic 				fperrno("Cannot dup to standard output");
29433829Sbostic 				exit(2);
29533829Sbostic 			}
29633828Sbostic 			swfile = optarg;
29733828Sbostic 			break;
29833828Sbostic 		default:
29933828Sbostic 			usage();
30033828Sbostic 		}
30133828Sbostic 	}
30233828Sbostic 	if(!Option) {
30333829Sbostic 		(void) fprintf(stderr,
30433829Sbostic 		    "Options must include one of -o, -i, or -p\n");
30533829Sbostic 		exit(2);
30633828Sbostic 	}
30733828Sbostic 
30833828Sbostic 	if(Option == PASS) {
30933828Sbostic 		if(Rename) {
31033829Sbostic 			(void) fprintf(stderr,
31133829Sbostic 			    "Pass and Rename cannot be used together\n");
31233829Sbostic 			exit(2);
31333828Sbostic 		}
31433828Sbostic 		if( Bufsize != BUFSIZE ) {
31533828Sbostic 			fprintf( stderr, "`B' or `C' option is irrelevant with the '-p' option\n");
31633828Sbostic 			Bufsize = BUFSIZE;
31733828Sbostic 		}
31833828Sbostic 
31933828Sbostic 	}else  {
32033829Sbostic 		Cp = Cbuf = (char *)malloc(Bufsize);
32133829Sbostic 		if(Cp == NULL) {
32233829Sbostic 			perror("cpio");
32333829Sbostic 			exit(2);
32433829Sbostic 		}
32533828Sbostic 	}
32633828Sbostic 	argc -= optind;
32733828Sbostic 	argv += optind;
32833828Sbostic 
32933828Sbostic 	switch(Option) {
33033828Sbostic 	case OUT:
33133828Sbostic 		if(argc != 0)
33233828Sbostic 			usage();
33333828Sbostic 		/* get filename, copy header and file out */
33433828Sbostic 		while(getname()) {
33533828Sbostic 			if( mklong(Hdr.h_filesize) == 0L) {
33633828Sbostic 				if( Cflag )
33733828Sbostic 					bwrite(Chdr,CHARS+Hdr.h_namesize);
33833828Sbostic 				else
33933828Sbostic 					bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
34033828Sbostic 				if(Verbose)
34133829Sbostic 					(void) fprintf(stderr, "%s\n",
34233829Sbostic 					    Hdr.h_name);
34333828Sbostic 				continue;
34433829Sbostic 			} else if( A_symlink ) {
34533829Sbostic 				symlsz = (int) mklong(Hdr.h_filesize);
34633829Sbostic 				if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
34733829Sbostic 					fperrno("Cannot read symbolic link <%s>",
34833829Sbostic 					    Hdr.h_name);
34933829Sbostic 					continue;
35033829Sbostic 				}
35133829Sbostic 				Symlbuf[symlsz] = '\0';
35233829Sbostic 				bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
35333829Sbostic 				bwrite(Symlbuf, symlsz);
35433829Sbostic 				if(Verbose)
35533829Sbostic 					(void) fprintf(stderr, "%s\n",
35633829Sbostic 					    Hdr.h_name);
35733829Sbostic 				continue;
35833828Sbostic 			}
35933828Sbostic 			if((Ifile = open(Hdr.h_name, 0)) < 0) {
36033829Sbostic 				fperrno("Cannot open <%s>", Hdr.h_name);
36133828Sbostic 				continue;
36233828Sbostic 			}
36333828Sbostic 			if ( Cflag )
36433828Sbostic 				bwrite(Chdr,CHARS+Hdr.h_namesize);
36533828Sbostic 			else
36633828Sbostic 				bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
36733828Sbostic 			for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
36833828Sbostic 				ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
36933828Sbostic 				if(read(Ifile, Buf, ct) < 0) {
37033829Sbostic  					fperrno("Cannot read %s", Hdr.h_name);
37133828Sbostic 					continue;
37233828Sbostic 				}
37333828Sbostic 				bwrite(Buf,ct);
37433828Sbostic 			}
37533828Sbostic 			close(Ifile);
37633829Sbostic 			if(Acc_time) {
37733829Sbostic 				struct utimbuf utb;
37833829Sbostic 
37933829Sbostic 				utb.actime = Statb.st_atime;
38033829Sbostic 				utb.modtime = Statb.st_mtime;
38133829Sbostic 				(void)utime(Hdr.h_name, &utb);
38233829Sbostic 			}
38333828Sbostic 			if(Verbose)
38433829Sbostic 				(void) fprintf(stderr, "%s\n", Hdr.h_name);
38533828Sbostic 		}
38633828Sbostic 
38733828Sbostic 	/* copy trailer, after all files have been copied */
38833828Sbostic 		strcpy(Hdr.h_name, "TRAILER!!!");
38933828Sbostic 		Hdr.h_magic = MAGIC;
39033828Sbostic 		MKSHORT(Hdr.h_filesize, 0L);
39133828Sbostic 		Hdr.h_namesize = strlen("TRAILER!!!") + 1;
39233828Sbostic 		if ( Cflag )  {
39333828Sbostic 			bintochar(0L);
39433828Sbostic 			bwrite(Chdr, CHARS+Hdr.h_namesize);
39533828Sbostic 		}
39633828Sbostic 		else
39733828Sbostic 			bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
39833828Sbostic 		bwrite(Cbuf, Bufsize);
39933828Sbostic 		break;
40033828Sbostic 
40133828Sbostic 	case IN:
40233828Sbostic 		if(argc > 0 ) {	/* save patterns, if any */
40333828Sbostic 			Pattern = argv;
40433828Sbostic 		}
40533828Sbostic 		pwd();
40633828Sbostic 		chkhdr();
40733828Sbostic 		while(gethdr()) {
40833829Sbostic 			if (A_symlink) {
40933829Sbostic 				symlsz = (int) mklong(Hdr.h_filesize);
41033829Sbostic 				bread(Symlbuf, symlsz);
41133829Sbostic 				Symlbuf[symlsz] = '\0';
41233830Sbostic 				if( ckname(Hdr.h_name)  &&  !Toc)
41333829Sbostic 					(void)openout(Hdr.h_name, Symlbuf);
41433829Sbostic 			} else {
41533829Sbostic 				if( (select = ckname(Hdr.h_name))  &&  !Toc )
41633829Sbostic 					Ofile = openout(Hdr.h_name, (char *)0);
41733829Sbostic 				else
41833829Sbostic 					Ofile = 0;
41933829Sbostic 				for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
42033829Sbostic 					ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
42133829Sbostic 					bread(Buf, ct);
42233829Sbostic 					if(Ofile) {
42333829Sbostic 						if(Swap)
42433829Sbostic 						       swap(Buf,ct,byteswap,halfswap);
42533829Sbostic 						if(write(Ofile, Buf, ct) < 0) {
42633829Sbostic 						 fperrno("Cannot write %s", Hdr.h_name);
42733829Sbostic 						 continue;
42833829Sbostic 						}
42933828Sbostic 					}
43033828Sbostic 				}
43133829Sbostic 				if( Ofile ) {
43233829Sbostic 					(void) close(Ofile);
43333829Sbostic 					if(chmod(Hdr.h_name, Hdr.h_mode) < 0)
43433829Sbostic 						fperrno("Cannot change mode of <%s>",
43533829Sbostic 						    Hdr.h_name);
43633829Sbostic 					set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
43733829Sbostic 				}
43833828Sbostic 			}
43933828Sbostic 			if(select) {
44033828Sbostic 				if(Verbose)
44133828Sbostic 					if(Toc)
44233828Sbostic 						pentry(Hdr.h_name);
44333828Sbostic 					else
44433829Sbostic 						puts(Hdr.h_name);
44533828Sbostic 				else if(Toc)
44633828Sbostic 					puts(Hdr.h_name);
44733828Sbostic 			}
44833828Sbostic 		}
44933828Sbostic 		break;
45033828Sbostic 
45133828Sbostic 	case PASS:		/* move files around */
45233828Sbostic 		if(argc != 1)
45333828Sbostic 			usage();
45433828Sbostic 		if(access(argv[0], 2) == -1) {
45533829Sbostic 			(void) fperrno("Cannot write in <%s>", argv[0]);
45633829Sbostic 			exit(2);
45733828Sbostic 		}
45833828Sbostic 		strcpy(Fullname, argv[0]);	/* destination directory */
45933829Sbostic 		if(stat(Fullname, &Xstatb) < 0) {
46033829Sbostic 			fperrno("Cannot stat <%s>", Fullname);
46133829Sbostic 			exit(2);
46233829Sbostic 		}
46333829Sbostic 		if((Xstatb.st_mode&S_IFMT) != S_IFDIR) {
46433829Sbostic 			(void) fprintf(stderr, "<%s> is not a directory",
46533829Sbostic 			    Fullname);
46633829Sbostic 			exit(2);
46733829Sbostic 		}
46833828Sbostic 		Dev = Xstatb.st_dev;
46933828Sbostic 		if( Fullname[ strlen(Fullname) - 1 ] != '/' )
47033828Sbostic 			strcat(Fullname, "/");
47133828Sbostic 		fullp = Fullname + strlen(Fullname);
47233828Sbostic 
47333828Sbostic 		while(getname()) {
47433828Sbostic 			if (A_directory && !Dir)
47533829Sbostic 				fperr("Use `-d' option to copy <%s>",
47633828Sbostic 					Hdr.h_name);
47733828Sbostic 			if(!ckname(Hdr.h_name))
47833828Sbostic 				continue;
47933828Sbostic 			i = 0;
48033828Sbostic 			while(Hdr.h_name[i] == '/')
48133828Sbostic 				i++;
48233828Sbostic 			strcpy(fullp, &(Hdr.h_name[i]));
48333828Sbostic 
48433828Sbostic 			if( PassLink  &&  !A_directory  &&  Dev == Statb.st_dev ) {
48533828Sbostic 				if(link(Hdr.h_name, Fullname) < 0) {
48633828Sbostic 					switch(errno) {
48733828Sbostic 						case ENOENT:
48833828Sbostic 							if(missdir(Fullname) != 0) {
48933829Sbostic 								fperrno("Cannot create directory for <%s>",
49033829Sbostic 									Fullname);
49133828Sbostic 								continue;
49233828Sbostic 							}
49333828Sbostic 							break;
49433828Sbostic 						case EEXIST:
49533828Sbostic 							if(unlink(Fullname) < 0) {
49633829Sbostic 								fperrno("Cannot unlink <%s>",
49733829Sbostic 									Fullname);
49833828Sbostic 								continue;
49933828Sbostic 							}
50033828Sbostic 							break;
50133828Sbostic 						default:
50233829Sbostic 							fperrno("Cannot link <%s> to <%s>",
50333829Sbostic 								Hdr.h_name, Fullname);
50433828Sbostic 							continue;
50533828Sbostic 						}
50633828Sbostic 					if(link(Hdr.h_name, Fullname) < 0) {
50733829Sbostic 						fperrno("Cannot link <%s> to <%s>",
50833829Sbostic 							Hdr.h_name, Fullname);
50933828Sbostic 						continue;
51033828Sbostic 					}
51133828Sbostic 				}
51233828Sbostic 
51333828Sbostic 				goto ckverbose;
51433828Sbostic 			}
51533829Sbostic 			if( A_symlink ) {
51633829Sbostic 			   symlsz = (int) mklong(Hdr.h_filesize);
51733829Sbostic 			   if (readlink(Hdr.h_name, Symlbuf, symlsz) < 0) {
51833829Sbostic 				fperrno("Cannot read symbolic link <%s>",
51933829Sbostic 				    Hdr.h_name);
52033828Sbostic 				continue;
52133829Sbostic 			   }
52233829Sbostic 			   Symlbuf[symlsz] = '\0';
52333829Sbostic 			   if(!openout(Fullname, Symlbuf))
52433829Sbostic 				continue;
52533829Sbostic 			   Blocks += ((symlsz + (BUFSIZE - 1)) / BUFSIZE);
52633829Sbostic 			   if(Verbose)
52733829Sbostic 				puts(Fullname);
52833829Sbostic 			   continue;
52933829Sbostic 			}
53033829Sbostic 			if(!(Ofile = openout(Fullname, (char *)0)))
53133829Sbostic 				continue;
53233829Sbostic 			if((Ifile = open(Hdr.h_name, 0)) < 0) {
53333829Sbostic 				fperrno("Cannot open <%s>", Hdr.h_name);
53433828Sbostic 				close(Ofile);
53533828Sbostic 				continue;
53633828Sbostic 			}
53733828Sbostic 			filesz = Statb.st_size;
53833828Sbostic 			for(; filesz > 0; filesz -= CPIOBSZ) {
53933828Sbostic 				ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
54033828Sbostic 				if(read(Ifile, Buf, ct) < 0) {
54133829Sbostic 					fperrno("Cannot read %s", Hdr.h_name);
54233828Sbostic 					break;
54333828Sbostic 				}
54433829Sbostic 				if(write(Ofile, Buf, ct) < 0) {
54533829Sbostic 				 fperrno("Cannot write %s", Hdr.h_name);
54633829Sbostic 				 break;
54733829Sbostic 				}
54833829Sbostic 				/* Removed u370 ifdef which caused cpio */
54933829Sbostic 				/* to report blocks in terms of 4096 bytes. */
55033828Sbostic 
55133828Sbostic 				Blocks += ((ct + (BUFSIZE - 1)) / BUFSIZE);
55233828Sbostic 			}
55333828Sbostic 			close(Ifile);
55433829Sbostic 			if(Acc_time) {
55533829Sbostic 				struct utimbuf utb;
55633829Sbostic 
55733829Sbostic 				utb.actime = Statb.st_atime;
55833829Sbostic 				utb.modtime = Statb.st_mtime;
55933829Sbostic 				(void)utime(Hdr.h_name, &utb);
56033829Sbostic 			}
56133828Sbostic 			if(Ofile) {
56233828Sbostic 				close(Ofile);
56333829Sbostic 				if(chmod(Fullname, Hdr.h_mode) < 0)
56433829Sbostic 					fperrno("Cannot change mode of <%s>",
56533829Sbostic 					    Fullname);
56633828Sbostic 				set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime));
56733828Sbostic ckverbose:
56833828Sbostic 				if(Verbose)
56933829Sbostic 					puts(Fullname);
57033828Sbostic 			}
57133828Sbostic 		}
57233828Sbostic 	}
57333828Sbostic 	/* print number of blocks actually copied */
57433828Sbostic 	Blocks += ((sBlocks + (BUFSIZE - 1)) / BUFSIZE);
57533829Sbostic 	(void) fprintf(stderr, "%ld blocks\n", Blocks * (Bufsize>>9));
57633828Sbostic 	exit(0);
57733828Sbostic }
57833828Sbostic 
57933828Sbostic static
58033828Sbostic usage()
58133828Sbostic {
58233829Sbostic 	(void) fprintf("Usage: %s\n     %s\n     %s\n     %s\n       %s\n",
58333829Sbostic 	    "cpio -o[acvB] <name-list >collection",
58433829Sbostic 	    "cpio -o[acvB] -Ocollection <name-list",
58533829Sbostic 	    "cpio -i[cdmrstuvfB6] [ pattern ... ] <collection",
58633829Sbostic 	    "cpio -i[cdmrstuvfB6] -Icollection [ pattern ... ]",
58733829Sbostic 	    "cpio -p[adlmruv] directory <name-list");
58833828Sbostic }
58933828Sbostic 
59033828Sbostic static
59133828Sbostic chkswfile( sp, c, option )
59233828Sbostic char	*sp;
59333828Sbostic char	c;
59433828Sbostic short	option;
59533828Sbostic {
59633829Sbostic 	if( !option ) {
59733829Sbostic 		fperr( "-%c must be specified before -%c option",
59833828Sbostic 			c == 'I' ? 'i' : 'o', c );
59933829Sbostic 		exit(2);
60033829Sbostic 	}
60133829Sbostic 	if( (c == 'I'  &&  option != IN)  ||  (c == 'O'  &&  option != OUT) ) {
60233829Sbostic 		fperr( "-%c option not permitted with -%c option", c,
60333828Sbostic 			option );
60433829Sbostic 		exit(2);
60533829Sbostic 	}
60633828Sbostic 	if( !sp )
60733828Sbostic 		return;
60833829Sbostic 	fperr("No more than one -I or -O flag permitted");
60933829Sbostic 	exit(2);
61033828Sbostic }
61133828Sbostic 
61233828Sbostic static
61333828Sbostic getname()		/* get file name, get info for header */
61433828Sbostic {
61533828Sbostic 	register char *namep = Name;
61633828Sbostic 	register ushort ftype;
61733829Sbostic 	struct stat Lstatb;
61833828Sbostic 	long tlong;
61933828Sbostic 
62033828Sbostic 	for(;;) {
62133828Sbostic 		if(gets(namep) == NULL)
62233828Sbostic 			return 0;
62333828Sbostic 		while(*namep == '.' && namep[1] == '/') {
62433828Sbostic 			namep++;
62533828Sbostic 			while(*namep == '/') namep++;
62633828Sbostic 		}
62733828Sbostic 		strcpy(Hdr.h_name, namep);
62833829Sbostic 		if(lstat(namep, &Statb) < 0) {
62933829Sbostic 			fperrno("Cannot stat <%s>", Hdr.h_name);
63033828Sbostic 			continue;
63133828Sbostic 		}
63233828Sbostic 		ftype = Statb.st_mode & Filetype;
63333828Sbostic 		A_directory = (ftype == S_IFDIR);
63433828Sbostic 		A_special = (ftype == S_IFBLK)
63533828Sbostic 			|| (ftype == S_IFCHR)
63633828Sbostic 			|| (ftype == S_IFIFO);
63733829Sbostic 		A_symlink = (ftype == S_IFLNK);
63833828Sbostic 		Hdr.h_magic = MAGIC;
63933828Sbostic 		Hdr.h_namesize = strlen(Hdr.h_name) + 1;
64033828Sbostic 		Hdr.h_uid = Statb.st_uid;
64133828Sbostic 		Hdr.h_gid = Statb.st_gid;
64233828Sbostic 		Hdr.h_dev = Statb.st_dev;
64333828Sbostic 		Hdr.h_ino = Statb.st_ino;
64433828Sbostic 		Hdr.h_mode = Statb.st_mode;
64533828Sbostic 		MKSHORT(Hdr.h_mtime, Statb.st_mtime);
64633828Sbostic 		Hdr.h_nlink = Statb.st_nlink;
64733829Sbostic 		tlong = ((Hdr.h_mode&S_IFMT) == S_IFREG ||
64833829Sbostic 			(Hdr.h_mode&S_IFMT) == S_IFLNK)? Statb.st_size: 0L;
64933828Sbostic 		MKSHORT(Hdr.h_filesize, tlong);
65033828Sbostic 		Hdr.h_rdev = Statb.st_rdev;
65133828Sbostic 		if( Cflag )
65233828Sbostic 			bintochar(tlong);
65333828Sbostic 		return 1;
65433828Sbostic 	}
65533828Sbostic }
65633828Sbostic 
65733828Sbostic static
65833828Sbostic bintochar(t)		/* ASCII header write */
65933828Sbostic long t;
66033828Sbostic {
66133828Sbostic 	sprintf(Chdr,"%.6o%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.11lo%.6ho%.11lo%s",
66233828Sbostic 		MAGIC, MK_USHORT(Statb.st_dev), MK_USHORT(Statb.st_ino), Statb.st_mode, Statb.st_uid,
66333828Sbostic 		Statb.st_gid, Statb.st_nlink, MK_USHORT(Statb.st_rdev),
66433828Sbostic 		Statb.st_mtime, (short)strlen(Hdr.h_name)+1, t, Hdr.h_name);
66533828Sbostic }
66633828Sbostic 
66733828Sbostic static
66833828Sbostic chartobin()		/* ASCII header read */
66933828Sbostic {
67033828Sbostic 	sscanf(Chdr, "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6ho%11lo",
67133828Sbostic 		&Hdr.h_magic, &Hdr.h_dev, &Hdr.h_ino, &Hdr.h_mode, &Hdr.h_uid,
67233828Sbostic 		&Hdr.h_gid, &Hdr.h_nlink, &Hdr.h_rdev, &Longtime,
67333828Sbostic 		&Hdr.h_namesize, &Longfile);
67433828Sbostic 	MKSHORT(Hdr.h_filesize, Longfile);
67533828Sbostic 	MKSHORT(Hdr.h_mtime, Longtime);
67633828Sbostic }
67733828Sbostic 
67833828Sbostic 
67933828Sbostic /*	Check the header for the magic number.  Switch modes automatically to
68033828Sbostic 	match the type of header found.
68133828Sbostic */
68233828Sbostic static
68333828Sbostic chkhdr()
68433828Sbostic {
68533828Sbostic 	bread(Chdr, CHARS);
68633828Sbostic 	chartobin();
68733828Sbostic 	if( Hdr.h_magic == MAGIC )
68833828Sbostic 		Cflag = 1;
68933828Sbostic 	else {
69033828Sbostic 		breread(&Hdr.h_magic, sizeof Hdr.h_magic);
69133829Sbostic 		if( Hdr.h_magic == MAGIC || Hdr.h_magic == (short)BSMAGIC )
69233828Sbostic 			Cflag = 0;
69333829Sbostic 		else {
69433829Sbostic 			fperr("This is not a cpio file.  Bad magic number.");
69533829Sbostic 			exit(2);
69633829Sbostic 		}
69733828Sbostic 	}
69833828Sbostic 	breread(Chdr, 0);
69933828Sbostic }
70033828Sbostic 
70133828Sbostic 
70233828Sbostic static
70333828Sbostic gethdr()		/* get file headers */
70433828Sbostic {
70533828Sbostic 	register ushort ftype;
70633828Sbostic 
70733828Sbostic 	if (Cflag)  {
70833828Sbostic 		bread(Chdr, CHARS);
70933828Sbostic 		chartobin();
71033828Sbostic 	}
71133828Sbostic 	else
71233828Sbostic 		bread(&Hdr, HDRSIZE);
71333828Sbostic 
71433829Sbostic 	if(Hdr.h_magic == (short)BSMAGIC)
71533829Sbostic 		swap((char *)&Hdr, HDRSIZE, 1, 0);
71633829Sbostic 	else if( Hdr.h_magic != MAGIC ) {
71733829Sbostic 		fperr("Out of phase--get help");
71833829Sbostic 		exit(2);
71933828Sbostic 	}
72033828Sbostic 	bread(Hdr.h_name, Hdr.h_namesize);
72133828Sbostic 	if(EQ(Hdr.h_name, "TRAILER!!!"))
72233828Sbostic 		return 0;
72333828Sbostic 	ftype = Hdr.h_mode & Filetype;
72433828Sbostic 	A_directory = (ftype == S_IFDIR);
72533828Sbostic 	A_special = (ftype == S_IFBLK)
72633828Sbostic 		||  (ftype == S_IFCHR)
72733828Sbostic 		||  (ftype == S_IFIFO);
72833829Sbostic 	A_symlink = (ftype == S_IFLNK);
72933828Sbostic 	return 1;
73033828Sbostic }
73133828Sbostic 
73233828Sbostic static
73333828Sbostic ckname(namep)	/* check filenames with patterns given on cmd line */
73433828Sbostic register char *namep;
73533828Sbostic {
73633828Sbostic 	char	buf[sizeof Hdr.h_name];
73733828Sbostic 
73833828Sbostic 	if(fflag ^ !nmatch(namep, Pattern)) {
73933828Sbostic 		return 0;
74033828Sbostic 	}
74133828Sbostic 	if(Rename && !A_directory) {	/* rename interactively */
74233828Sbostic 		fprintf(Wtty, "Rename <%s>\n", namep);
74333828Sbostic 		fflush(Wtty);
74433828Sbostic 		fgets(buf, sizeof buf, Rtty);
74533828Sbostic 		if(feof(Rtty))
74633828Sbostic 			exit(2);
74733828Sbostic 		buf[strlen(buf) - 1] = '\0';
74833828Sbostic 		if(EQ(buf, "")) {
74933828Sbostic 			strcpy(namep,buf);
75033828Sbostic 			printf("Skipped\n");
75133828Sbostic 			return 0;
75233828Sbostic 		}
75333828Sbostic 		else if(EQ(buf, "."))
75433828Sbostic 			printf("Same name\n");
75533828Sbostic 		else
75633828Sbostic 			strcpy(namep,buf);
75733828Sbostic 	}
75833828Sbostic 	return  1;
75933828Sbostic }
76033828Sbostic 
76133828Sbostic static
76233829Sbostic openout(namep, symlname)	/* open files for writing, set all necessary info */
76333828Sbostic register char *namep;
76433829Sbostic char *symlname;
76533828Sbostic {
76633828Sbostic 	register f;
76733828Sbostic 	register char *np;
76833828Sbostic 	int ans;
76933828Sbostic 
77033828Sbostic 	if(!strncmp(namep, "./", 2))
77133828Sbostic 		namep += 2;
77233828Sbostic 	np = namep;
77333828Sbostic 	if(A_directory) {
77433828Sbostic 		if( !Dir  ||  Rename  ||  EQ(namep, ".")  ||  EQ(namep, "..") )
77533828Sbostic 			/* do not consider . or .. files */
77633828Sbostic 			return 0;
77733828Sbostic 		if(stat(namep, &Xstatb) == -1) {
77833828Sbostic 
77933828Sbostic /* try creating (only twice) */
78033828Sbostic 			ans = 0;
78133828Sbostic 			do {
78233829Sbostic 				if(mkdir(namep, Hdr.h_mode) != 0) {
78333828Sbostic 					ans += 1;
78433828Sbostic 				}else {
78533828Sbostic 					ans = 0;
78633828Sbostic 					break;
78733828Sbostic 				}
78833828Sbostic 			}while(ans < 2 && missdir(namep) == 0);
78933828Sbostic 			if(ans == 1) {
79033828Sbostic 				fperrno("Cannot create directory for <%s>",
79133828Sbostic 					namep);
79233828Sbostic 				return(0);
79333828Sbostic 			}else if(ans == 2) {
79433828Sbostic 				fperrno("Cannot create directory <%s>", namep);
79533828Sbostic 				return(0);
79633828Sbostic 			}
79733828Sbostic 		}
79833828Sbostic 
79933828Sbostic ret:
80033829Sbostic 		if(chmod(namep, Hdr.h_mode) < 0)
80133829Sbostic 			fperrno("Cannot change mode of <%s>", namep);
80233828Sbostic 		if(Uid == 0)
80333829Sbostic 			if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
80433829Sbostic 				fperrno("Cannot change ownership of <%s>",
80533829Sbostic 				    namep);
80633828Sbostic 		set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
80733828Sbostic 		return 0;
80833828Sbostic 	}
80933828Sbostic 	if(Hdr.h_nlink > 1)
81033828Sbostic 		if(!postml(namep, np))
81133828Sbostic 			return 0;
81233829Sbostic 	if(lstat(namep, &Xstatb) == 0) {
81333828Sbostic 		if(Uncond && !((!(Xstatb.st_mode & S_IWRITE) || A_special) && (Uid != 0))) {
81433828Sbostic 			if(unlink(namep) < 0) {
81533828Sbostic 				fperrno("cannot unlink current <%s>", namep);
81633828Sbostic 			}
81733828Sbostic 		}
81833828Sbostic 		if(!Uncond && (mklong(Hdr.h_mtime) <= Xstatb.st_mtime)) {
81933828Sbostic 		/* There's a newer or same aged version of file on destination */
82033829Sbostic 			fperr("current <%s> newer or same age", np);
82133828Sbostic 			return 0;
82233828Sbostic 		}
82333828Sbostic 	}
82433828Sbostic 	if( Option == PASS
82533828Sbostic 		&& Hdr.h_ino == Xstatb.st_ino
82633828Sbostic 		&& Hdr.h_dev == Xstatb.st_dev) {
82733829Sbostic 		fperr("Attempt to pass file to self!");
82833829Sbostic 		exit(2);
82933828Sbostic 	}
83033829Sbostic 	if(A_symlink) {
83133829Sbostic /* try symlinking (only twice) */
83233829Sbostic 		ans = 0;
83333829Sbostic 		do {
83433829Sbostic 			if(symlink(
83533829Sbostic symlname, namep) < 0) {
83633829Sbostic 				ans += 1;
83733829Sbostic 			}else {
83833829Sbostic 				ans = 0;
83933829Sbostic 				break;
84033829Sbostic 			}
84133829Sbostic 		}while(ans < 2 && missdir(np) == 0);
84233829Sbostic 		if(ans == 1) {
84333829Sbostic 			fperrno("Cannot create directory for <%s>", namep);
84433829Sbostic 			return(0);
84533829Sbostic 		}else if(ans == 2) {
84633829Sbostic 			fperrno("Cannot symlink <%s> and <%s>", namep, symlname);
84733829Sbostic 			return(0);
84833829Sbostic 		}
84933829Sbostic 
85033829Sbostic 		return 0;
85133829Sbostic 	}
85233828Sbostic 	if(A_special) {
85333828Sbostic 		if((Hdr.h_mode & Filetype) == S_IFIFO)
85433828Sbostic 			Hdr.h_rdev = 0;
85533828Sbostic 
85633828Sbostic /* try creating (only twice) */
85733828Sbostic 		ans = 0;
85833828Sbostic 		do {
85933828Sbostic 			if(mknod(namep, Hdr.h_mode, Hdr.h_rdev) < 0) {
86033828Sbostic 				ans += 1;
86133828Sbostic 			}else {
86233828Sbostic 				ans = 0;
86333828Sbostic 				break;
86433828Sbostic 			}
86533828Sbostic 		}while(ans < 2 && missdir(np) == 0);
86633828Sbostic 		if(ans == 1) {
86733828Sbostic 			fperrno("Cannot create directory for <%s>", namep);
86833828Sbostic 			return(0);
86933828Sbostic 		}else if(ans == 2) {
87033828Sbostic 			fperrno("Cannot mknod <%s>", namep);
87133828Sbostic 			return(0);
87233828Sbostic 		}
87333828Sbostic 
87433828Sbostic 		goto ret;
87533828Sbostic 	}
87633828Sbostic 
87733828Sbostic /* try creating (only twice) */
87833828Sbostic 	ans = 0;
87933828Sbostic 	do {
88033828Sbostic 		if((f = creat(namep, Hdr.h_mode)) < 0) {
88133828Sbostic 			ans += 1;
88233828Sbostic 		}else {
88333828Sbostic 			ans = 0;
88433828Sbostic 			break;
88533828Sbostic 		}
88633828Sbostic 	}while(ans < 2 && missdir(np) == 0);
88733828Sbostic 	if(ans == 1) {
88833828Sbostic 		fperrno("Cannot create directory for <%s>", namep);
88933828Sbostic 		return(0);
89033828Sbostic 	}else if(ans == 2) {
89133828Sbostic 		fperrno("Cannot create <%s>", namep);
89233828Sbostic 		return(0);
89333828Sbostic 	}
89433828Sbostic 
89533828Sbostic 	if(Uid == 0)
89633829Sbostic 		if(chown(namep, Hdr.h_uid, Hdr.h_gid) < 0)
89733829Sbostic 			fperrno("Cannot change ownership of <%s>", namep);
89833828Sbostic 	return f;
89933828Sbostic }
90033828Sbostic 
90133828Sbostic 
90233828Sbostic /*	Shared by bread() and breread()
90333828Sbostic */
90433828Sbostic static int	nleft = 0;	/* unread chars left in Cbuf */
90533828Sbostic static char	*ip;		/* pointer to next char to be read from Cbuf */
90633828Sbostic 
90733828Sbostic /*	Reread the current buffer Cbuf.
90833828Sbostic 	A character count, c, of 0 simply resets the pointer so next bread gets
90933828Sbostic 	the same data again.
91033828Sbostic */
91133828Sbostic static
91233828Sbostic breread(b, c)
91333828Sbostic char	*b;
91433828Sbostic int	c;
91533828Sbostic {
91633828Sbostic 	ip = Cbuf;
91733828Sbostic 	if( nleft )
91833828Sbostic 		nleft = Bufsize;
91933828Sbostic 	if( !c )
92033828Sbostic 		return;
92133828Sbostic 	bread(b, c);
92233828Sbostic }
92333828Sbostic 
92433828Sbostic static
92533828Sbostic bread(b, c)
92633828Sbostic register char	*b;
92733828Sbostic register int	c;
92833828Sbostic {
92933828Sbostic 	register int	rv;
93033828Sbostic 	register char	*p = ip;
93133828Sbostic 
93233828Sbostic 	if( !Cflag ) {
93333828Sbostic 		/* round c up to an even number */
93433828Sbostic 		c = (c+1)/2;
93533828Sbostic 		c *= 2;
93633828Sbostic 	}
93733828Sbostic 	while( c )  {
93833828Sbostic 		if( nleft == 0 ) {
93933828Sbostic 			while( (rv = read(Input, Cbuf, Bufsize)) == 0 ) {
94033828Sbostic 				Input = chgreel(0, Input, rv);
94133828Sbostic 			}
94233828Sbostic 			if( rv == Bufsize ) {
94333828Sbostic 				nleft = Bufsize;
94433828Sbostic 				p = Cbuf;
94533828Sbostic 				++Blocks;
94633828Sbostic 			}
94733829Sbostic 			else if( rv == -1 ) {
94833829Sbostic 				fperrno("Read error on archive");
94933829Sbostic 				exit(2);
95033829Sbostic 			}
95133828Sbostic 			else if( rv < Bufsize ) {	/* short read */
95233828Sbostic 				smemcpy( &Cbuf[ Bufsize - rv ], Cbuf, rv );
95333828Sbostic 				nleft = rv;
95433828Sbostic 				p = &Cbuf[ Bufsize - rv ];
95533828Sbostic 				sBlocks += rv;
95633828Sbostic 			}
95733828Sbostic 		}
95833828Sbostic 		if( nleft <= c ) {
95933828Sbostic 			memcpy( b, p, nleft );
96033828Sbostic 			c -= nleft;
96133828Sbostic 			b += nleft;
96233828Sbostic 			p += nleft;
96333828Sbostic 			nleft = 0;
96433828Sbostic 		}
96533828Sbostic 		else {
96633828Sbostic 			memcpy( b, p, c );
96733828Sbostic 			nleft -= c;
96833828Sbostic 			b += c;
96933828Sbostic 			p += c;
97033828Sbostic 			c = 0;
97133828Sbostic 		}
97233828Sbostic 	}
97333828Sbostic 	ip = p;
97433828Sbostic }
97533828Sbostic 
97633828Sbostic 
97733828Sbostic static
97833828Sbostic bwrite(rp, c)
97933828Sbostic register char *rp;
98033828Sbostic register c;
98133828Sbostic {
98233828Sbostic 	register char	*cp = Cp;
98333828Sbostic 	static unsigned	Ccnt = 0;
98433828Sbostic 	register unsigned Cleft;
98533828Sbostic 	register int	rv;
98633828Sbostic 
98733828Sbostic 	if( !Cflag ) {
98833828Sbostic 		/* round c up to an even number */
98933828Sbostic 		c = (c+1)/2;
99033828Sbostic 		c *= 2;
99133828Sbostic 	}
99233828Sbostic 	while( c )  {
99333828Sbostic 		if( (Cleft = Bufsize - Ccnt) <= c ) {
99433828Sbostic 			memcpy( cp, rp, Cleft );
99533828Sbostic 			rv = write(Output, Cbuf, Bufsize);
99633828Sbostic 			if( rv == 0  ||  ( rv == -1  &&  errno == ENXIO ) ) {
99733828Sbostic 				rv = eomchgreel();
99833828Sbostic 			}
99933828Sbostic 			if( rv == Bufsize ) {
100033828Sbostic 				Ccnt = 0;
100133828Sbostic 				cp = Cbuf;
100233828Sbostic 			}
100333829Sbostic 			else if( rv == -1 ) {
100433829Sbostic 				fperrno("Write error on archive");
100533829Sbostic 				exit(2);
100633829Sbostic 			}
100733828Sbostic 			else if( rv < Bufsize ) {
100833828Sbostic 				Output = chgreel(1, Output, 0);
100933828Sbostic 				smemcpy( Cbuf, &Cbuf[ Bufsize - rv ], rv );
101033828Sbostic 				Ccnt = Bufsize - rv;
101133828Sbostic 				cp = &Cbuf[ rv ];
101233828Sbostic 			}
101333828Sbostic 			++Blocks;
101433828Sbostic 			rp += Cleft;
101533828Sbostic 			c -= Cleft;
101633828Sbostic 		}
101733828Sbostic 		else {
101833828Sbostic 			memcpy( cp, rp, c );
101933828Sbostic 			Ccnt += c;
102033828Sbostic 			cp += c;
102133828Sbostic 			rp += c;
102233828Sbostic 			c = 0;
102333828Sbostic 		}
102433828Sbostic 	}
102533828Sbostic 	Cp = cp;
102633828Sbostic }
102733828Sbostic 
102833828Sbostic 
102933828Sbostic static int	reelcount = 1;	/* used below and in chgreel() */
103033828Sbostic 
103133828Sbostic /*	Change reel due to reaching end-of-media.
103233828Sbostic 	Keep trying to get a successful write before considering the
103333828Sbostic 	change-of-reel as successful.
103433828Sbostic */
103533828Sbostic static
103633828Sbostic int
103733828Sbostic eomchgreel()
103833828Sbostic {
103933828Sbostic 	int	rv;
104033828Sbostic 
104133828Sbostic 	while( 1 ) {
104233828Sbostic 		Output = chgreel(1, Output, 0);
104333828Sbostic 		rv = write(Output, Cbuf, Bufsize);
104433828Sbostic 		if( rv == Bufsize )
104533828Sbostic 			return  rv;
104633829Sbostic 		if( rv == -1 )
104733829Sbostic 			fperrno( "Unable to write this medium" );
104833829Sbostic 		else
104933829Sbostic 			fperr( "Unable to write this medium: Premature EOF" );
105033829Sbostic 		(void) fprintf(stderr, "Try again.\n");
105133828Sbostic 		reelcount--;
105233828Sbostic 	}
105333828Sbostic 	/*NOTREACHED*/
105433828Sbostic }
105533828Sbostic 
105633828Sbostic 
105733828Sbostic static
105833828Sbostic postml(namep, np)		/* linking funtion:  Postml() is called after */
105933828Sbostic register char *namep, *np;	/* namep is created.  Postml() checks to see  */
106033828Sbostic {				/* if namep should be linked to np.  If so,   */
106133828Sbostic 				/* postml() removes the independent instance  */
106233828Sbostic 	register i;		/* of namep and links namep to np.	      */
106333828Sbostic 	static struct ml {
106433828Sbostic 		short	m_dev;
106533828Sbostic 		ushort	m_ino;
106633828Sbostic 		char	m_name[2];
106733828Sbostic 	} **ml = 0;
106833828Sbostic 	register struct ml	*mlp;
106933828Sbostic 	static unsigned	mlsize = 0;
107033828Sbostic 	static unsigned	mlinks = 0;
107133828Sbostic 	char		*lnamep;
107233828Sbostic 	int		ans;
107333828Sbostic 
107433828Sbostic 	if( !ml ) {
107533828Sbostic 		mlsize = LINKS;
107633829Sbostic 		ml = (struct ml **) malloc(mlsize * sizeof(struct ml));
107733828Sbostic 	}
107833828Sbostic 	else if( mlinks == mlsize ) {
107933828Sbostic 		mlsize += LINKS;
108033829Sbostic 		ml = (struct ml **) realloc((char *) ml,
108133829Sbostic 		    mlsize * sizeof(struct ml));
108233828Sbostic 	}
108333829Sbostic 	if (ml == NULL) {
108433829Sbostic 		fperr("Out of memory for links");
108533829Sbostic 		exit(2);
108633829Sbostic 	}
108733828Sbostic 	for(i = 0; i < mlinks; ++i) {
108833828Sbostic 		mlp = ml[i];
108933828Sbostic 		if(mlp->m_ino==Hdr.h_ino  &&  mlp->m_dev==Hdr.h_dev) {
109033828Sbostic 			if(Verbose)
109133829Sbostic 			  printf("%s linked to %s\n", ml[i]->m_name,
109233829Sbostic 				np);
109333828Sbostic 			unlink(namep);
109433828Sbostic 			if(Option == IN && *(mlp->m_name) != '/') {
109533828Sbostic 				Fullname[Pathend] = '\0';
109633828Sbostic 				strcat(Fullname, mlp->m_name);
109733828Sbostic 				lnamep = Fullname;
109833828Sbostic 			}
109933828Sbostic 			lnamep = mlp->m_name;
110033828Sbostic 
110133828Sbostic /* try linking (only twice) */
110233828Sbostic 			ans = 0;
110333828Sbostic 			do {
110433828Sbostic 				if(link(lnamep, namep) < 0) {
110533828Sbostic 					ans += 1;
110633828Sbostic 				}else {
110733828Sbostic 					ans = 0;
110833828Sbostic 					break;
110933828Sbostic 				}
111033828Sbostic 			}while(ans < 2 && missdir(np) == 0);
111133828Sbostic 			if(ans == 1) {
111233828Sbostic 				fperrno("Cannot create directory for <%s>", np);
111333828Sbostic 				return(0);
111433828Sbostic 			}else if(ans == 2) {
111533828Sbostic 				fperrno("Cannot link <%s> & <%s>", lnamep, np);
111633828Sbostic 				return(0);
111733828Sbostic 			}
111833828Sbostic 
111933828Sbostic 			set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
112033828Sbostic 			return 0;
112133828Sbostic 		}
112233828Sbostic 	}
112333829Sbostic 	if( !(ml[mlinks] = (struct ml *)malloc(strlen(np) + 2 + sizeof(struct ml)))) {
112433828Sbostic 		static int first=1;
112533828Sbostic 
112633828Sbostic 		if(first)
112733829Sbostic 			fperr("Out of memory for links");
112833828Sbostic 		first = 0;
112933828Sbostic 		return 1;
113033828Sbostic 	}
113133828Sbostic 	ml[mlinks]->m_dev = Hdr.h_dev;
113233828Sbostic 	ml[mlinks]->m_ino = Hdr.h_ino;
113333828Sbostic 	strcpy(ml[mlinks]->m_name, np);
113433828Sbostic 	++mlinks;
113533828Sbostic 	return 1;
113633828Sbostic }
113733828Sbostic 
113833828Sbostic static
113933828Sbostic pentry(namep)		/* print verbose table of contents */
114033828Sbostic register char *namep;
114133828Sbostic {
114233828Sbostic 
114333828Sbostic 	static short lastid = -1;
114433828Sbostic #include <pwd.h>
114533828Sbostic 	static struct passwd *pw;
114633828Sbostic 	struct passwd *getpwuid();
114733828Sbostic 	static char tbuf[32];
114833828Sbostic 	char *ctime();
114933828Sbostic 
115033828Sbostic 	printf("%-7o", MK_USHORT(Hdr.h_mode));
115133828Sbostic 	if(lastid == Hdr.h_uid)
115233828Sbostic 		printf("%-6s", pw->pw_name);
115333828Sbostic 	else {
115433828Sbostic 		setpwent();
115533828Sbostic 		if(pw = getpwuid((int)Hdr.h_uid)) {
115633828Sbostic 			printf("%-6s", pw->pw_name);
115733828Sbostic 			lastid = Hdr.h_uid;
115833828Sbostic 		} else {
115933828Sbostic 			printf("%-6d", Hdr.h_uid);
116033828Sbostic 			lastid = -1;
116133828Sbostic 		}
116233828Sbostic 	}
116333828Sbostic 	printf("%7ld ", mklong(Hdr.h_filesize));
116433828Sbostic 	U.l = mklong(Hdr.h_mtime);
116533828Sbostic 	strcpy(tbuf, ctime((long *)&U.l));
116633828Sbostic 	tbuf[24] = '\0';
116733829Sbostic 	printf(" %s  %s", &tbuf[4], namep);
116833829Sbostic 	if (A_symlink)
116933829Sbostic 		printf(" -> %s", Symlbuf);
117033829Sbostic 	putchar('\n');
117133828Sbostic }
117233828Sbostic 
117333828Sbostic 		/* pattern matching functions */
117433828Sbostic static
117533828Sbostic nmatch(s, pat)
117633828Sbostic char *s, **pat;
117733828Sbostic {
117833828Sbostic 	if( !pat )
117933828Sbostic 		return 1;
118033828Sbostic 	while(*pat) {
118133828Sbostic 		if((**pat == '!' && !gmatch(s, *pat+1))
118233828Sbostic 		|| gmatch(s, *pat))
118333828Sbostic 			return 1;
118433828Sbostic 		++pat;
118533828Sbostic 	}
118633828Sbostic 	return 0;
118733828Sbostic }
118833828Sbostic 
118933828Sbostic 
119033828Sbostic static
119133828Sbostic gmatch(s, p)
119233828Sbostic register char *s, *p;
119333828Sbostic {
119433828Sbostic 	register int c;
119533828Sbostic 	register cc, ok, lc, scc;
119633828Sbostic 
119733828Sbostic 	scc = *s;
119833828Sbostic 	lc = 077777;
119933828Sbostic 	switch (c = *p) {
120033828Sbostic 
120133828Sbostic 	case '[':
120233828Sbostic 		ok = 0;
120333828Sbostic 		while (cc = *++p) {
120433828Sbostic 			switch (cc) {
120533828Sbostic 
120633828Sbostic 			case ']':
120733828Sbostic 				if (ok)
120833828Sbostic 					return(gmatch(++s, ++p));
120933828Sbostic 				else
121033828Sbostic 					return(0);
121133828Sbostic 
121233828Sbostic 			case '-':
121333828Sbostic 				ok |= ((lc <= scc) && (scc <= (cc=p[1])));
121433828Sbostic 			}
121533828Sbostic 			if (scc==(lc=cc)) ok++;
121633828Sbostic 		}
121733828Sbostic 		return(0);
121833828Sbostic 
121933828Sbostic 	case '?':
122033828Sbostic 	caseq:
122133828Sbostic 		if(scc) return(gmatch(++s, ++p));
122233828Sbostic 		return(0);
122333828Sbostic 	case '*':
122433828Sbostic 		return(umatch(s, ++p));
122533828Sbostic 	case 0:
122633828Sbostic 		return(!scc);
122733828Sbostic 	}
122833828Sbostic 	if (c==scc) goto caseq;
122933828Sbostic 	return(0);
123033828Sbostic }
123133828Sbostic 
123233828Sbostic 
123333828Sbostic 
123433828Sbostic static
123533828Sbostic umatch(s, p)
123633828Sbostic register char *s, *p;
123733828Sbostic {
123833828Sbostic 	if(*p==0) return(1);
123933828Sbostic 	while(*s)
124033828Sbostic 		if (gmatch(s++,p)) return(1);
124133828Sbostic 	return(0);
124233828Sbostic }
124333828Sbostic 
124433829Sbostic swap(buf, bytecount, bytes, halfwords)	/* swap halfwords, bytes or both */
124533829Sbostic char *buf;
124633829Sbostic int bytecount;
124733829Sbostic int bytes, halfwords;
124833828Sbostic {
124933829Sbostic 	register int count;
125033829Sbostic 	int n, i;
125133828Sbostic 
125233829Sbostic 	if(bytes) {
125333829Sbostic 		register union swpbytes {
125433829Sbostic 			short	shortw;
125533829Sbostic 			char	charv[2];
125633829Sbostic 		} *pbuf;
125733829Sbostic 		register char c;
125833828Sbostic 
125933829Sbostic 		count = bytecount;
126033829Sbostic 		pbuf = (union swpbytes *)buf;
126133829Sbostic 		if (count % sizeof(union swpbytes))
126233829Sbostic 			pbuf->charv[count] = 0;
126333829Sbostic 		count = (count + (sizeof(union swpbytes) - 1)) / sizeof(union swpbytes);
126433829Sbostic 		while (count--) {
126533829Sbostic 			c = pbuf->charv[0];
126633829Sbostic 			pbuf->charv[0] = pbuf->charv[1];
126733829Sbostic 			pbuf->charv[1] = c;
126833829Sbostic 			++pbuf;
126933828Sbostic 		}
127033828Sbostic 	}
127133829Sbostic 	if (halfwords) {
127233829Sbostic 		register union swphalf {
127333829Sbostic 			long	longw;
127433829Sbostic 			short	shortv[2];
127533829Sbostic 			char	charv[4];
127633829Sbostic 		} *pbuf;
127733829Sbostic 		register short cc;
127833829Sbostic 
127933829Sbostic 		count = bytecount;
128033829Sbostic 		pbuf = (union swphalf *)buf;
128133829Sbostic 		if (n = count % sizeof(union swphalf))
128233829Sbostic 			if(bytes && n % 2)
128333829Sbostic 				for(i = count + 1; i <= count + (sizeof(union swphalf) - n); i++)
128433829Sbostic 					pbuf->charv[i] = 0;
128533829Sbostic 			else
128633829Sbostic 				for (i = count; i < count + (sizeof(union swphalf) - n); i++)
128733829Sbostic 					pbuf->charv[i] = 0;
128833829Sbostic 		count = (count + (sizeof(union swphalf) - 1)) / sizeof(union swphalf);
128933829Sbostic 		while (count--) {
129033828Sbostic 			cc = pbuf->shortv[0];
129133828Sbostic 			pbuf->shortv[0] = pbuf->shortv[1];
129233828Sbostic 			pbuf->shortv[1] = cc;
129333828Sbostic 			++pbuf;
129433828Sbostic 		}
129533828Sbostic 	}
129633828Sbostic }
129733828Sbostic 
129833828Sbostic 
129933828Sbostic static
130033828Sbostic set_time(namep, atime, mtime)	/* set access and modification times */
130133828Sbostic register char *namep;
130233828Sbostic time_t atime, mtime;
130333828Sbostic {
130433829Sbostic 	static struct utimbuf timevec;
130533828Sbostic 
130633828Sbostic 	if(!Mod_time)
130733828Sbostic 		return;
130833829Sbostic 	timevec.actime = atime;
130933829Sbostic 	timevec.modtime = mtime;
131033829Sbostic 	(void)utime(namep, &timevec);
131133828Sbostic }
131233828Sbostic 
131333828Sbostic 
131433828Sbostic 
131533828Sbostic static
131633828Sbostic chgreel(x, fl, rv)
131733828Sbostic {
131833828Sbostic 	register f;
131933828Sbostic 	char str[BUFSIZ];
132033828Sbostic 	struct stat statb;
132133828Sbostic 
132233828Sbostic 	fstat(fl, &statb);
132333828Sbostic 	if((statb.st_mode&S_IFMT) != S_IFCHR) {
132433828Sbostic 		fperrno("Can't %s: ", x? "write output": "read input");
132533828Sbostic 		exit(2);
132633828Sbostic 	}
132733828Sbostic 	if( rv == 0  ||
132833828Sbostic 		( rv == -1  &&  ( errno == ENOSPC  ||  errno == ENXIO ) ) )
132933829Sbostic 		fperr( "\007Reached end of medium on %s",
133033828Sbostic 			x? "output":"input" );
133133828Sbostic 	else {
133233828Sbostic 		fperrno( "\007Encountered an error on %s",
133333828Sbostic 			x? "output":"input" );
133433828Sbostic 		exit(2);
133533828Sbostic 	}
133633829Sbostic 	if( Rtty == NULL ) {
133733829Sbostic 		Rtty = fopen(ttyname, "r");
133833829Sbostic 		if( Rtty == NULL ) {
133933829Sbostic 			fperrno("Cannot prompt (can't open %s)", ttyname);
134033829Sbostic 			exit(2);
134133829Sbostic 		}
134233829Sbostic 	}
134333828Sbostic 	close(fl);
134433828Sbostic 	reelcount++;
134533828Sbostic again:
134633828Sbostic 	if( swfile ) {
134733828Sbostic 	    askagain:
134833828Sbostic 		fperr( eommsg, reelcount );
134933828Sbostic 		fgets(str, sizeof str, Rtty);
135033828Sbostic 		switch( *str ) {
135133828Sbostic 		case '\n':
135233828Sbostic 			strcpy( str, swfile );
135333828Sbostic 			break;
135433828Sbostic 		case 'q':
135533828Sbostic 			exit(2);
135633828Sbostic 		default:
135733828Sbostic 			goto askagain;
135833828Sbostic 		}
135933828Sbostic 	}
136033828Sbostic 	else {
136133829Sbostic 		fperr("If you want to go on, type device/file name when ready.");
136233828Sbostic 		fgets(str, sizeof str, Rtty);
136333828Sbostic 		str[strlen(str) - 1] = '\0';
136433828Sbostic 		if(!*str)
136533828Sbostic 			exit(2);
136633828Sbostic 	}
136733828Sbostic 	if((f = open(str, x? 1: 0)) < 0) {
136833829Sbostic 		fperrno("Can't open <%s>", str);
136933828Sbostic 		goto again;
137033828Sbostic 	}
137133828Sbostic 	return f;
137233828Sbostic }
137333828Sbostic 
137433828Sbostic 
137533828Sbostic 
137633828Sbostic static
137733828Sbostic missdir(namep)
137833828Sbostic register char *namep;
137933828Sbostic {
138033828Sbostic 	register char *np;
138133828Sbostic 	register ct = 2;
138233828Sbostic 
138333828Sbostic 	for(np = namep; *np; ++np)
138433828Sbostic 		if(*np == '/') {
138533828Sbostic 			if(np == namep) continue;	/* skip over 'root slash' */
138633828Sbostic 			*np = '\0';
138733828Sbostic 			if(stat(namep, &Xstatb) == -1) {
138833828Sbostic 				if(Dir) {
138933829Sbostic 					if((ct = mkdir(namep, 0777)) != 0) {
139033828Sbostic 						*np = '/';
139133828Sbostic 						return(ct);
139233828Sbostic 					}
139333828Sbostic 				}else {
139433829Sbostic 					fperr("missing 'd' option");
139533828Sbostic 					return(-1);
139633828Sbostic 				}
139733828Sbostic 			}
139833828Sbostic 			*np = '/';
139933828Sbostic 		}
140033828Sbostic 	if (ct == 2) ct = 0;		/* the file already exists */
140133828Sbostic 	return ct;
140233828Sbostic }
140333828Sbostic 
140433828Sbostic 
140533828Sbostic 
140633828Sbostic static
140733828Sbostic pwd()		/* get working directory */
140833828Sbostic {
140933829Sbostic 	if (getwd(Fullname) == 0) {
141033829Sbostic 		(void)fprintf(stderr, "cpio: %s\n",
141133829Sbostic 		    Fullname);
141233828Sbostic 		exit(2);
141333829Sbostic 	}
141433828Sbostic 	Pathend = strlen(Fullname);
141533829Sbostic 	Fullname[Pathend++] = '/';
141633829Sbostic 	Fullname[Pathend] = '\0';
141733828Sbostic }
141833828Sbostic 
141933828Sbostic 
142033828Sbostic /*
142133828Sbostic 	print message on the stderr
142233828Sbostic */
142333828Sbostic static
142433828Sbostic fperr( va_alist )
142533828Sbostic va_dcl
142633828Sbostic {
142733828Sbostic 	va_list	args;
142833828Sbostic 	char	*fmt;
142933828Sbostic 
143033828Sbostic 	va_start( args );
143133829Sbostic 	fprintf( stderr, "cpio: ");
143233828Sbostic 	fmt = va_arg( args, char * );
143333828Sbostic 	vfprintf( stderr, fmt, args );
143433829Sbostic 	putc( '\n', stderr);
143533828Sbostic 	fflush( stderr );
143633828Sbostic }
143733828Sbostic 
143833828Sbostic /*
143933828Sbostic 	print message on the stderr followed by error number and meaning.
144033828Sbostic */
144133828Sbostic static
144233828Sbostic fperrno( va_alist )
144333828Sbostic va_dcl
144433828Sbostic {
144533828Sbostic 	va_list	args;
144633828Sbostic 	char	*fmt;
144733828Sbostic 
144833828Sbostic 	va_start( args );
144933829Sbostic 	fprintf( stderr, "cpio: ");
145033828Sbostic 	fmt = va_arg( args, char * );
145133828Sbostic 	vfprintf( stderr, fmt, args );
145233829Sbostic 	fprintf( stderr, ": " );
145333828Sbostic 	fflush( stderr );
145433828Sbostic 	perror("");
145533828Sbostic }
145633828Sbostic 
145733828Sbostic 
145833829Sbostic /*	Safe memory copy.
145933829Sbostic 	Fast if the to and from strings do not overlap,
146033829Sbostic 	slower but safe if they do.
146133829Sbostic */
146233829Sbostic 
146333829Sbostic static char *
146433829Sbostic smemcpy( to, from, count )
146533829Sbostic register char		*to, *from;
146633829Sbostic register unsigned	count;
146733828Sbostic {
146833829Sbostic 	char	*savedto;
146933829Sbostic 
147033829Sbostic 	if( &to[ count ] <= from  ||  &from[ count ] <= to )
147133829Sbostic 		return  memcpy( to, from, count );
147233829Sbostic 
147333829Sbostic 	if( to == from )
147433829Sbostic 		return  to;
147533829Sbostic 
147633829Sbostic 	savedto = to;
147733829Sbostic 	if( to < from )
147833829Sbostic 		while( count-- )
147933829Sbostic 			*(to++) = *(from++);
148033829Sbostic 	else {
148133829Sbostic 		to += count;
148233829Sbostic 		from += count;
148333829Sbostic 		while( count-- )
148433829Sbostic 			*(--to) = *(--from);
148533828Sbostic 	}
148633828Sbostic 
148733829Sbostic 	return  savedto;
148833828Sbostic }
148933831Sbostic 
149033831Sbostic extern int _doprnt();
149133831Sbostic 
149233831Sbostic /*VARARGS2*/
149333831Sbostic int
149433831Sbostic vfprintf(iop, format, ap)
149533831Sbostic FILE *iop;
149633831Sbostic char *format;
149733831Sbostic va_list ap;
149833831Sbostic {
149933831Sbostic 	register int count;
150033831Sbostic 
150133831Sbostic 	if (!(iop->_flag | _IOWRT)) {
150233831Sbostic 		/* if no write flag */
150333831Sbostic 		if (iop->_flag | _IORW) {
150433831Sbostic 			/* if ok, cause read-write */
150533831Sbostic 			iop->_flag |= _IOWRT;
150633831Sbostic 		} else {
150733831Sbostic 			/* else error */
150833831Sbostic 			return EOF;
150933831Sbostic 		}
151033831Sbostic 	}
151133831Sbostic 	count = _doprnt(format, ap, iop);
151233831Sbostic 	return(ferror(iop)? EOF: count);
151333831Sbostic }
1514