cpio.c revision 3044
198944Sobrien/*-
298944Sobrien * Copyright (c) 1992 Keith Muller.
3130803Smarcel * Copyright (c) 1992, 1993
498944Sobrien *	The Regents of the University of California.  All rights reserved.
598944Sobrien *
698944Sobrien * This code is derived from software contributed to Berkeley by
798944Sobrien * Keith Muller of the University of California, San Diego.
898944Sobrien *
998944Sobrien * Redistribution and use in source and binary forms, with or without
1098944Sobrien * modification, are permitted provided that the following conditions
1198944Sobrien * are met:
1298944Sobrien * 1. Redistributions of source code must retain the above copyright
1398944Sobrien *    notice, this list of conditions and the following disclaimer.
1498944Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1598944Sobrien *    notice, this list of conditions and the following disclaimer in the
1698944Sobrien *    documentation and/or other materials provided with the distribution.
1798944Sobrien * 3. All advertising materials mentioning features or use of this software
1898944Sobrien *    must display the following acknowledgement:
1998944Sobrien *	This product includes software developed by the University of
2098944Sobrien *	California, Berkeley and its contributors.
2198944Sobrien * 4. Neither the name of the University nor the names of its contributors
2298944Sobrien *    may be used to endorse or promote products derived from this software
23130803Smarcel *    without specific prior written permission.
24130803Smarcel *
2598944Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2698944Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2798944Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2898944Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29130803Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30130803Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31130803Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32130803Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33130803Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35130803Smarcel * SUCH DAMAGE.
3698944Sobrien *
37130803Smarcel *	$Id$
38130803Smarcel */
39130803Smarcel
4098944Sobrien#ifndef lint
4198944Sobrienstatic char sccsid[] = "@(#)cpio.c	8.1 (Berkeley) 5/31/93";
4298944Sobrien#endif /* not lint */
4398944Sobrien
4498944Sobrien#include <sys/types.h>
4598944Sobrien#include <sys/time.h>
4698944Sobrien#include <sys/stat.h>
4798944Sobrien#include <sys/param.h>
4898944Sobrien#include <string.h>
49130803Smarcel#include <ctype.h>
50130803Smarcel#include <stdio.h>
51130803Smarcel#include <unistd.h>
52130803Smarcel#include <stdlib.h>
5398944Sobrien#include "pax.h"
5498944Sobrien#include "cpio.h"
5598944Sobrien#include "extern.h"
5698944Sobrien
57130803Smarcelstatic int rd_nm __P((register ARCHD *, int));
5898944Sobrienstatic int rd_ln_nm __P((register ARCHD *));
5998944Sobrienstatic int com_rd __P((register ARCHD *));
6098944Sobrien
6198944Sobrien/*
6298944Sobrien * Routines which support the different cpio versions
6398944Sobrien */
6498944Sobrien
6598944Sobrienstatic int swp_head;		/* binary cpio header byte swap */
6698944Sobrien
6798944Sobrien/*
6898944Sobrien * Routines common to all versions of cpio
6998944Sobrien */
7098944Sobrien
7198944Sobrien/*
7298944Sobrien * cpio_strd()
7398944Sobrien *	Fire up the hard link detection code
7498944Sobrien * Return:
7598944Sobrien *      0 if ok -1 otherwise (the return values of lnk_start())
7698944Sobrien */
7798944Sobrien
7898944Sobrien#if __STDC__
7998944Sobrienint
8098944Sobriencpio_strd(void)
8198944Sobrien#else
8298944Sobrienint
83130803Smarcelcpio_strd()
84130803Smarcel#endif
85130803Smarcel{
86130803Smarcel	return(lnk_start());
8798944Sobrien}
88130803Smarcel
89130803Smarcel/*
90130803Smarcel * cpio_trail()
91130803Smarcel *	Called to determine if a header block is a valid trailer. We are
9298944Sobrien *	passed the block, the in_sync flag (which tells us we are in resync
93130803Smarcel *	mode; looking for a valid header), and cnt (which starts at zero)
94130803Smarcel *	which is used to count the number of empty blocks we have seen so far.
95130803Smarcel * Return:
9698944Sobrien *	0 if a valid trailer, -1 if not a valid trailer,
9798944Sobrien */
9898944Sobrien
9998944Sobrien#if __STDC__
10098944Sobrienint
10198944Sobriencpio_trail(register ARCHD *arcn)
10298944Sobrien#else
10398944Sobrienint
10498944Sobriencpio_trail(arcn)
10598944Sobrien	register ARCHD *arcn;
10698944Sobrien#endif
10798944Sobrien{
10898944Sobrien	/*
10998944Sobrien	 * look for trailer id in file we are about to process
11098944Sobrien	 */
11198944Sobrien	if ((strcmp(arcn->name, TRAILER) == 0) && (arcn->sb.st_size == 0))
11298944Sobrien		return(0);
11398944Sobrien	return(-1);
11498944Sobrien}
11598944Sobrien
11698944Sobrien/*
11798944Sobrien * com_rd()
11898944Sobrien *	operations common to all cpio read functions.
11998944Sobrien * Return:
12098944Sobrien *	0
12198944Sobrien */
12298944Sobrien
12398944Sobrien#if __STDC__
12498944Sobrienstatic int
12598944Sobriencom_rd(register ARCHD *arcn)
12698944Sobrien#else
12798944Sobrienstatic int
12898944Sobriencom_rd(arcn)
12998944Sobrien	register ARCHD *arcn;
13098944Sobrien#endif
13198944Sobrien{
13298944Sobrien	arcn->skip = 0;
13398944Sobrien	arcn->pat = NULL;
13498944Sobrien	arcn->org_name = arcn->name;
13598944Sobrien	switch(arcn->sb.st_mode & C_IFMT) {
13698944Sobrien	case C_ISFIFO:
13798944Sobrien		arcn->type = PAX_FIF;
13898944Sobrien		break;
13998944Sobrien	case C_ISDIR:
14098944Sobrien		arcn->type = PAX_DIR;
14198944Sobrien		break;
14298944Sobrien	case C_ISBLK:
14398944Sobrien		arcn->type = PAX_BLK;
14498944Sobrien		break;
14598944Sobrien	case C_ISCHR:
14698944Sobrien		arcn->type = PAX_CHR;
14798944Sobrien		break;
14898944Sobrien	case C_ISLNK:
14998944Sobrien		arcn->type = PAX_SLK;
15098944Sobrien		break;
15198944Sobrien	case C_ISOCK:
15298944Sobrien		arcn->type = PAX_SCK;
15398944Sobrien		break;
15498944Sobrien	case C_ISCTG:
15598944Sobrien	case C_ISREG:
15698944Sobrien	default:
15798944Sobrien		/*
15898944Sobrien		 * we have file data, set up skip (pad is set in the format
15998944Sobrien		 * specific sections)
16098944Sobrien		 */
16198944Sobrien		arcn->sb.st_mode = (arcn->sb.st_mode & 0xfff) | C_ISREG;
16298944Sobrien		arcn->type = PAX_REG;
16398944Sobrien		arcn->skip = arcn->sb.st_size;
16498944Sobrien		break;
16598944Sobrien	}
16698944Sobrien	if (chk_lnk(arcn) < 0)
16798944Sobrien		return(-1);
16898944Sobrien	return(0);
16998944Sobrien}
17098944Sobrien
17198944Sobrien/*
17298944Sobrien * cpio_end_wr()
17398944Sobrien *	write the special file with the name trailer in the proper format
17498944Sobrien * Return:
17598944Sobrien *	result of the write of the trailer from the cpio specific write func
17698944Sobrien */
17798944Sobrien
17898944Sobrien#if __STDC__
17998944Sobrienint
18098944Sobriencpio_endwr(void)
18198944Sobrien#else
18298944Sobrienint
18398944Sobriencpio_endwr()
18498944Sobrien#endif
18598944Sobrien{
18698944Sobrien	ARCHD last;
18798944Sobrien
18898944Sobrien	/*
18998944Sobrien	 * create a trailer request and call the proper format write function
19098944Sobrien	 */
19198944Sobrien	bzero((char *)&last, sizeof(last));
19298944Sobrien	last.nlen = sizeof(TRAILER) - 1;
19398944Sobrien	last.type = PAX_REG;
19498944Sobrien	last.sb.st_nlink = 1;
19598944Sobrien	(void)strcpy(last.name, TRAILER);
19698944Sobrien	return((*frmt->wr)(&last));
19798944Sobrien}
19898944Sobrien
19998944Sobrien/*
20098944Sobrien * rd_nam()
20198944Sobrien *	read in the file name which follows the cpio header
20298944Sobrien * Return:
20398944Sobrien *	0 if ok, -1 otherwise
20498944Sobrien */
20598944Sobrien
20698944Sobrien#if __STDC__
20798944Sobrienstatic int
20898944Sobrienrd_nm(register ARCHD *arcn, int nsz)
20998944Sobrien#else
21098944Sobrienstatic int
21198944Sobrienrd_nm(arcn, nsz)
21298944Sobrien	register ARCHD *arcn;
21398944Sobrien	int nsz;
21498944Sobrien#endif
21598944Sobrien{
21698944Sobrien	/*
21798944Sobrien	 * do not even try bogus values
21898944Sobrien	 */
21998944Sobrien	if ((nsz == 0) || (nsz > sizeof(arcn->name))) {
22098944Sobrien		warn(1, "Cpio file name length %d is out of range", nsz);
22198944Sobrien		return(-1);
22298944Sobrien	}
22398944Sobrien
22498944Sobrien	/*
22598944Sobrien	 * read the name and make sure it is not empty and is \0 terminated
22698944Sobrien	 */
22798944Sobrien	if ((rd_wrbuf(arcn->name,nsz) != nsz) || (arcn->name[nsz-1] != '\0') ||
22898944Sobrien	    (arcn->name[0] == '\0')) {
22998944Sobrien		warn(1, "Cpio file name in header is corrupted");
230130803Smarcel		return(-1);
23198944Sobrien	}
23298944Sobrien	return(0);
23398944Sobrien}
23498944Sobrien
23598944Sobrien/*
23698944Sobrien * rd_ln_nm()
23798944Sobrien *	read in the link name for a file with links. The link name is stored
238130803Smarcel *	like file data (and is NOT \0 terminated!)
239130803Smarcel * Return:
240130803Smarcel *	0 if ok, -1 otherwise
241130803Smarcel */
242130803Smarcel
243130803Smarcel#if __STDC__
244130803Smarcelstatic int
245130803Smarcelrd_ln_nm(register ARCHD *arcn)
246130803Smarcel#else
247130803Smarcelstatic int
248130803Smarcelrd_ln_nm(arcn)
24998944Sobrien	register ARCHD *arcn;
250130803Smarcel#endif
251130803Smarcel{
252130803Smarcel	/*
253130803Smarcel	 * check the length specified for bogus values
254130803Smarcel	 */
255130803Smarcel	if ((arcn->sb.st_size == 0) ||
25698944Sobrien	    (arcn->sb.st_size >= sizeof(arcn->ln_name))) {
25798944Sobrien#		ifdef NET2_STAT
25898944Sobrien		warn(1, "Cpio link name length is invalid: %lu",
25998944Sobrien		    arcn->sb.st_size);
26098944Sobrien#		else
26198944Sobrien		warn(1, "Cpio link name length is invalid: %qu",
26298944Sobrien		    arcn->sb.st_size);
26398944Sobrien#		endif
26498944Sobrien		return(-1);
26598944Sobrien	}
26698944Sobrien
26798944Sobrien	/*
26898944Sobrien	 * read in the link name and \0 terminate it
26998944Sobrien	 */
270130803Smarcel	if (rd_wrbuf(arcn->ln_name, (int)arcn->sb.st_size) !=
27198944Sobrien	    (int)arcn->sb.st_size) {
27298944Sobrien		warn(1, "Cpio link name read error");
27398944Sobrien		return(-1);
27498944Sobrien	}
27598944Sobrien	arcn->ln_nlen = arcn->sb.st_size;
27698944Sobrien	arcn->ln_name[arcn->ln_nlen] = '\0';
27798944Sobrien
27898944Sobrien	/*
27998944Sobrien	 * watch out for those empty link names
28098944Sobrien	 */
28198944Sobrien	if (arcn->ln_name[0] == '\0') {
28298944Sobrien		warn(1, "Cpio link name is corrupt");
28398944Sobrien		return(-1);
28498944Sobrien	}
28598944Sobrien	return(0);
28698944Sobrien}
28798944Sobrien
28898944Sobrien/*
28998944Sobrien * Routines common to the extended byte oriented cpio format
29098944Sobrien */
29198944Sobrien
29298944Sobrien/*
29398944Sobrien * cpio_id()
29498944Sobrien *      determine if a block given to us is a valid extended byte oriented
29598944Sobrien *	cpio header
29698944Sobrien * Return:
29798944Sobrien *      0 if a valid header, -1 otherwise
29898944Sobrien */
29998944Sobrien
30098944Sobrien#if __STDC__
30198944Sobrienint
30298944Sobriencpio_id(char *blk, int size)
30398944Sobrien#else
30498944Sobrienint
30598944Sobriencpio_id(blk, size)
30698944Sobrien	char *blk;
30798944Sobrien	int size;
30898944Sobrien#endif
30998944Sobrien{
31098944Sobrien	if ((size < sizeof(HD_CPIO)) ||
31198944Sobrien	    (strncmp(blk, AMAGIC, sizeof(AMAGIC) - 1) != 0))
31298944Sobrien		return(-1);
31398944Sobrien	return(0);
31498944Sobrien}
31598944Sobrien
31698944Sobrien/*
31798944Sobrien * cpio_rd()
31898944Sobrien *	determine if a buffer is a byte oriented extended cpio archive entry.
319130803Smarcel *	convert and store the values in the ARCHD parameter.
32098944Sobrien * Return:
32198944Sobrien *	0 if a valid header, -1 otherwise.
32298944Sobrien */
32398944Sobrien
32498944Sobrien#if __STDC__
32598944Sobrienint
32698944Sobriencpio_rd(register ARCHD *arcn, register char *buf)
32798944Sobrien#else
32898944Sobrienint
32998944Sobriencpio_rd(arcn, buf)
33098944Sobrien	register ARCHD *arcn;
33198944Sobrien	register char *buf;
33298944Sobrien#endif
33398944Sobrien{
33498944Sobrien	register int nsz;
33598944Sobrien	register HD_CPIO *hd;
33698944Sobrien
33798944Sobrien	/*
33898944Sobrien	 * check that this is a valid header, if not return -1
33998944Sobrien	 */
34098944Sobrien	if (cpio_id(buf, sizeof(HD_CPIO)) < 0)
34198944Sobrien		return(-1);
34298944Sobrien	hd = (HD_CPIO *)buf;
34398944Sobrien
34498944Sobrien	/*
34598944Sobrien	 * byte oriented cpio (posix) does not have padding! extract the octal
34698944Sobrien	 * ascii fields from the header
34798944Sobrien	 */
34898944Sobrien	arcn->pad = 0L;
34998944Sobrien	arcn->sb.st_dev = (dev_t)asc_ul(hd->c_dev, sizeof(hd->c_dev), OCT);
35098944Sobrien	arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), OCT);
35198944Sobrien	arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), OCT);
35298944Sobrien	arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), OCT);
35398944Sobrien	arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), OCT);
35498944Sobrien	arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
35598944Sobrien	    OCT);
35698944Sobrien	arcn->sb.st_rdev = (dev_t)asc_ul(hd->c_rdev, sizeof(hd->c_rdev), OCT);
35798944Sobrien	arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime, sizeof(hd->c_mtime),
35898944Sobrien	    OCT);
35998944Sobrien	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
36098944Sobrien#	ifdef NET2_STAT
36198944Sobrien	arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,sizeof(hd->c_filesize),
36298944Sobrien	    OCT);
36398944Sobrien#	else
36498944Sobrien	arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,sizeof(hd->c_filesize),
36598944Sobrien	    OCT);
36698944Sobrien#	endif
36798944Sobrien
36898944Sobrien	/*
36998944Sobrien	 * check name size and if valid, read in the name of this entry (name
37098944Sobrien	 * follows header in the archive)
37198944Sobrien	 */
37298944Sobrien	if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),OCT)) < 2)
37398944Sobrien		return(-1);
37498944Sobrien	arcn->nlen = nsz - 1;
37598944Sobrien	if (rd_nm(arcn, nsz) < 0)
37698944Sobrien		return(-1);
37798944Sobrien
37898944Sobrien	if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
37998944Sobrien		/*
38098944Sobrien	 	 * no link name to read for this file
38198944Sobrien	 	 */
38298944Sobrien		arcn->ln_nlen = 0;
38398944Sobrien		arcn->ln_name[0] = '\0';
38498944Sobrien		return(com_rd(arcn));
38598944Sobrien	}
38698944Sobrien
38798944Sobrien	/*
38898944Sobrien	 * check link name size and read in the link name. Link names are
38998944Sobrien	 * stored like file data.
39098944Sobrien	 */
39198944Sobrien	if (rd_ln_nm(arcn) < 0)
39298944Sobrien		return(-1);
39398944Sobrien
39498944Sobrien	/*
39598944Sobrien	 * we have a valid header (with a link)
39698944Sobrien	 */
39798944Sobrien	return(com_rd(arcn));
39898944Sobrien}
39998944Sobrien
40098944Sobrien/*
40198944Sobrien * cpio_endrd()
40298944Sobrien *      no cleanup needed here, just return size of the trailer (for append)
40398944Sobrien * Return:
40498944Sobrien *      size of trailer header in this format
40598944Sobrien */
40698944Sobrien
40798944Sobrien#if __STDC__
40898944Sobrienoff_t
40998944Sobriencpio_endrd(void)
41098944Sobrien#else
41198944Sobrienoff_t
41298944Sobriencpio_endrd()
41398944Sobrien#endif
41498944Sobrien{
41598944Sobrien	return((off_t)(sizeof(HD_CPIO) + sizeof(TRAILER)));
41698944Sobrien}
41798944Sobrien
41898944Sobrien/*
41998944Sobrien * cpio_stwr()
42098944Sobrien *	start up the device mapping table
42198944Sobrien * Return:
42298944Sobrien *	0 if ok, -1 otherwise (what dev_start() returns)
42398944Sobrien */
42498944Sobrien
42598944Sobrien#if __STDC__
42698944Sobrienint
42798944Sobriencpio_stwr(void)
42898944Sobrien#else
42998944Sobrienint
43098944Sobriencpio_stwr()
43198944Sobrien#endif
43298944Sobrien{
43398944Sobrien	return(dev_start());
43498944Sobrien}
43598944Sobrien
43698944Sobrien/*
43798944Sobrien * cpio_wr()
43898944Sobrien *	copy the data in the ARCHD to buffer in extended byte oriented cpio
43998944Sobrien *	format.
44098944Sobrien * Return
44198944Sobrien *      0 if file has data to be written after the header, 1 if file has NO
44298944Sobrien *	data to write after the header, -1 if archive write failed
44398944Sobrien */
44498944Sobrien
44598944Sobrien#if __STDC__
44698944Sobrienint
44798944Sobriencpio_wr(register ARCHD *arcn)
44898944Sobrien#else
44998944Sobrienint
45098944Sobriencpio_wr(arcn)
45198944Sobrien	register ARCHD *arcn;
45298944Sobrien#endif
45398944Sobrien{
45498944Sobrien	register HD_CPIO *hd;
45598944Sobrien	register int nsz;
45698944Sobrien	char hdblk[sizeof(HD_CPIO)];
45798944Sobrien
45898944Sobrien	/*
459130803Smarcel	 * check and repair truncated device and inode fields in the header
46098944Sobrien	 */
46198944Sobrien	if (map_dev(arcn, (u_long)CPIO_MASK, (u_long)CPIO_MASK) < 0)
46298944Sobrien		return(-1);
46398944Sobrien
46498944Sobrien	arcn->pad = 0L;
46598944Sobrien	nsz = arcn->nlen + 1;
46698944Sobrien	hd = (HD_CPIO *)hdblk;
46798944Sobrien	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
46898944Sobrien		arcn->sb.st_rdev = 0;
46998944Sobrien
47098944Sobrien	switch(arcn->type) {
47198944Sobrien	case PAX_CTG:
47298944Sobrien	case PAX_REG:
47398944Sobrien	case PAX_HRG:
47498944Sobrien		/*
47598944Sobrien		 * set data size for file data
47698944Sobrien		 */
47798944Sobrien#		ifdef NET2_STAT
47898944Sobrien		if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
47998944Sobrien		    sizeof(hd->c_filesize), OCT)) {
48098944Sobrien#		else
48198944Sobrien		if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
48298944Sobrien		    sizeof(hd->c_filesize), OCT)) {
48398944Sobrien#		endif
48498944Sobrien			warn(1,"File is too large for cpio format %s",
48598944Sobrien			    arcn->org_name);
48698944Sobrien			return(1);
48798944Sobrien		}
48898944Sobrien		break;
48998944Sobrien	case PAX_SLK:
49098944Sobrien		/*
49198944Sobrien		 * set data size to hold link name
49298944Sobrien		 */
49398944Sobrien		if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
49498944Sobrien		    sizeof(hd->c_filesize), OCT))
49598944Sobrien			goto out;
49698944Sobrien		break;
49798944Sobrien	default:
49898944Sobrien		/*
49998944Sobrien		 * all other file types have no file data
50098944Sobrien		 */
50198944Sobrien		if (ul_asc((u_long)0, hd->c_filesize, sizeof(hd->c_filesize),
50298944Sobrien		     OCT))
50398944Sobrien			goto out;
50498944Sobrien		break;
50598944Sobrien	}
50698944Sobrien
50798944Sobrien	/*
50898944Sobrien	 * copy the values to the header using octal ascii
50998944Sobrien	 */
51098944Sobrien	if (ul_asc((u_long)MAGIC, hd->c_magic, sizeof(hd->c_magic), OCT) ||
51198944Sobrien	    ul_asc((u_long)arcn->sb.st_dev, hd->c_dev, sizeof(hd->c_dev),
51298944Sobrien	        OCT) ||
51398944Sobrien	    ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
514130803Smarcel		OCT) ||
515130803Smarcel	    ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
516130803Smarcel		OCT) ||
51798944Sobrien	    ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
518130803Smarcel		OCT) ||
519130803Smarcel	    ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
52098944Sobrien		OCT) ||
521130803Smarcel	    ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
522130803Smarcel		 OCT) ||
523130803Smarcel	    ul_asc((u_long)arcn->sb.st_rdev, hd->c_rdev, sizeof(hd->c_rdev),
524130803Smarcel		OCT) ||
525130803Smarcel	    ul_asc((u_long)arcn->sb.st_mtime,hd->c_mtime,sizeof(hd->c_mtime),
526130803Smarcel		OCT) ||
52798944Sobrien	    ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), OCT))
528130803Smarcel		goto out;
52998944Sobrien
530130803Smarcel	/*
53198944Sobrien	 * write the file name to the archive
53298944Sobrien	 */
53398944Sobrien	if ((wr_rdbuf(hdblk, (int)sizeof(HD_CPIO)) < 0) ||
53498944Sobrien	    (wr_rdbuf(arcn->name, nsz) < 0)) {
53598944Sobrien		warn(1, "Unable to write cpio header for %s", arcn->org_name);
53698944Sobrien		return(-1);
53798944Sobrien	}
53898944Sobrien
53998944Sobrien	/*
54098944Sobrien	 * if this file has data, we are done. The caller will write the file
54198944Sobrien	 * data, if we are link tell caller we are done, go to next file
54298944Sobrien	 */
54398944Sobrien	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
54498944Sobrien	    (arcn->type == PAX_HRG))
54598944Sobrien		return(0);
54698944Sobrien	if (arcn->type != PAX_SLK)
547130803Smarcel		return(1);
548130803Smarcel
549130803Smarcel	/*
550130803Smarcel	 * write the link name to the archive, tell the caller to go to the
551130803Smarcel	 * next file as we are done.
552130803Smarcel	 */
553130803Smarcel	if (wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) {
554130803Smarcel		warn(1,"Unable to write cpio link name for %s",arcn->org_name);
555130803Smarcel		return(-1);
556130803Smarcel	}
557130803Smarcel	return(1);
558130803Smarcel
559130803Smarcel    out:
560130803Smarcel	/*
561130803Smarcel	 * header field is out of range
562130803Smarcel	 */
563130803Smarcel	warn(1, "Cpio header field is too small to store file %s",
564130803Smarcel	    arcn->org_name);
565130803Smarcel	return(1);
566130803Smarcel}
567130803Smarcel
568130803Smarcel/*
569130803Smarcel * Routines common to the system VR4 version of cpio (with/without file CRC)
570130803Smarcel */
571130803Smarcel
572130803Smarcel/*
573130803Smarcel * vcpio_id()
574130803Smarcel *      determine if a block given to us is a valid system VR4 cpio header
575130803Smarcel *	WITHOUT crc. WATCH it the magic cookies are in OCTAL, the header
576130803Smarcel *	uses HEX
577130803Smarcel * Return:
578130803Smarcel *      0 if a valid header, -1 otherwise
579130803Smarcel */
580130803Smarcel
581130803Smarcel#if __STDC__
582130803Smarcelint
583130803Smarcelvcpio_id(char *blk, int size)
584130803Smarcel#else
585130803Smarcelint
586130803Smarcelvcpio_id(blk, size)
587130803Smarcel	char *blk;
588130803Smarcel	int size;
589130803Smarcel#endif
590130803Smarcel{
591130803Smarcel	if ((size < sizeof(HD_VCPIO)) ||
592130803Smarcel	    (strncmp(blk, AVMAGIC, sizeof(AVMAGIC) - 1) != 0))
593130803Smarcel		return(-1);
594130803Smarcel	return(0);
595130803Smarcel}
596130803Smarcel
597130803Smarcel/*
598130803Smarcel * crc_id()
599130803Smarcel *      determine if a block given to us is a valid system VR4 cpio header
600130803Smarcel *	WITH crc. WATCH it the magic cookies are in OCTAL the header uses HEX
601130803Smarcel * Return:
602130803Smarcel *      0 if a valid header, -1 otherwise
603130803Smarcel */
604130803Smarcel
605130803Smarcel#if __STDC__
606130803Smarcelint
607130803Smarcelcrc_id(char *blk, int size)
608130803Smarcel#else
609130803Smarcelint
610130803Smarcelcrc_id(blk, size)
611130803Smarcel	char *blk;
612130803Smarcel	int size;
613130803Smarcel#endif
614130803Smarcel{
615130803Smarcel	if ((size < sizeof(HD_VCPIO)) ||
616130803Smarcel	    (strncmp(blk, AVCMAGIC, sizeof(AVCMAGIC) - 1) != 0))
617130803Smarcel		return(-1);
618130803Smarcel	return(0);
619130803Smarcel}
620130803Smarcel
621130803Smarcel/*
622130803Smarcel * crc_strd()
623130803Smarcel w	set file data CRC calculations. Fire up the hard link detection code
624130803Smarcel * Return:
625130803Smarcel *      0 if ok -1 otherwise (the return values of lnk_start())
626130803Smarcel */
627130803Smarcel
628130803Smarcel#if __STDC__
629130803Smarcelint
630130803Smarcelcrc_strd(void)
631130803Smarcel#else
632130803Smarcelint
633130803Smarcelcrc_strd()
634130803Smarcel#endif
635130803Smarcel{
636130803Smarcel	docrc = 1;
637130803Smarcel	return(lnk_start());
638130803Smarcel}
639130803Smarcel
640130803Smarcel/*
641130803Smarcel * vcpio_rd()
642130803Smarcel *	determine if a buffer is a system VR4 archive entry. (with/without CRC)
643130803Smarcel *	convert and store the values in the ARCHD parameter.
644130803Smarcel * Return:
645130803Smarcel *	0 if a valid header, -1 otherwise.
646130803Smarcel */
647130803Smarcel
648130803Smarcel#if __STDC__
649130803Smarcelint
650130803Smarcelvcpio_rd(register ARCHD *arcn, register char *buf)
651130803Smarcel#else
652130803Smarcelint
653130803Smarcelvcpio_rd(arcn, buf)
654130803Smarcel	register ARCHD *arcn;
655130803Smarcel	register char *buf;
656130803Smarcel#endif
657130803Smarcel{
658130803Smarcel	register HD_VCPIO *hd;
659130803Smarcel	dev_t devminor;
660130803Smarcel	dev_t devmajor;
661130803Smarcel	register int nsz;
662130803Smarcel
663130803Smarcel	/*
664130803Smarcel	 * during the id phase it was determined if we were using CRC, use the
665130803Smarcel	 * proper id routine.
666130803Smarcel	 */
667130803Smarcel	if (docrc) {
668130803Smarcel		if (crc_id(buf, sizeof(HD_VCPIO)) < 0)
669130803Smarcel			return(-1);
670130803Smarcel	} else {
671130803Smarcel		if (vcpio_id(buf, sizeof(HD_VCPIO)) < 0)
672130803Smarcel			return(-1);
673130803Smarcel	}
674130803Smarcel
675130803Smarcel	hd = (HD_VCPIO *)buf;
676130803Smarcel	arcn->pad = 0L;
677130803Smarcel
678130803Smarcel	/*
679130803Smarcel	 * extract the hex ascii fields from the header
680130803Smarcel	 */
681130803Smarcel	arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), HEX);
682130803Smarcel	arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), HEX);
683130803Smarcel	arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), HEX);
684130803Smarcel	arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), HEX);
685130803Smarcel	arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime,sizeof(hd->c_mtime),HEX);
686130803Smarcel	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
687130803Smarcel#	ifdef NET2_STAT
688130803Smarcel	arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,
689130803Smarcel	    sizeof(hd->c_filesize), HEX);
690130803Smarcel#	else
691130803Smarcel	arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,
692130803Smarcel	    sizeof(hd->c_filesize), HEX);
693130803Smarcel#	endif
694130803Smarcel	arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
695130803Smarcel	    HEX);
696130803Smarcel	devmajor = (dev_t)asc_ul(hd->c_maj, sizeof(hd->c_maj), HEX);
697130803Smarcel	devminor = (dev_t)asc_ul(hd->c_min, sizeof(hd->c_min), HEX);
698130803Smarcel	arcn->sb.st_dev = TODEV(devmajor, devminor);
699130803Smarcel	devmajor = (dev_t)asc_ul(hd->c_rmaj, sizeof(hd->c_maj), HEX);
700130803Smarcel	devminor = (dev_t)asc_ul(hd->c_rmin, sizeof(hd->c_min), HEX);
701130803Smarcel	arcn->sb.st_rdev = TODEV(devmajor, devminor);
702130803Smarcel	arcn->crc = asc_ul(hd->c_chksum, sizeof(hd->c_chksum), HEX);
703130803Smarcel
704130803Smarcel	/*
705130803Smarcel	 * check the length of the file name, if ok read it in, return -1 if
706130803Smarcel	 * bogus
707130803Smarcel	 */
708130803Smarcel	if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),HEX)) < 2)
709130803Smarcel		return(-1);
710130803Smarcel	arcn->nlen = nsz - 1;
711130803Smarcel	if (rd_nm(arcn, nsz) < 0)
712130803Smarcel		return(-1);
713130803Smarcel
714130803Smarcel	/*
715130803Smarcel	 * skip padding. header + filename is aligned to 4 byte boundries
716130803Smarcel	 */
717130803Smarcel	if (rd_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)
718130803Smarcel		return(-1);
719130803Smarcel
720130803Smarcel	/*
721130803Smarcel	 * if not a link (or a file with no data), calculate pad size (for
722130803Smarcel	 * padding which follows the file data), clear the link name and return
723130803Smarcel	 */
724130803Smarcel	if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
725130803Smarcel		/*
726130803Smarcel		 * we have a valid header (not a link)
727130803Smarcel		 */
728130803Smarcel		arcn->ln_nlen = 0;
729130803Smarcel		arcn->ln_name[0] = '\0';
730130803Smarcel		arcn->pad = VCPIO_PAD(arcn->sb.st_size);
731130803Smarcel		return(com_rd(arcn));
732130803Smarcel	}
733130803Smarcel
734130803Smarcel	/*
735130803Smarcel	 * read in the link name and skip over the padding
736130803Smarcel	 */
737130803Smarcel	if ((rd_ln_nm(arcn) < 0) ||
738130803Smarcel	    (rd_skip((off_t)(VCPIO_PAD(arcn->sb.st_size))) < 0))
739130803Smarcel		return(-1);
740130803Smarcel
741130803Smarcel	/*
742130803Smarcel	 * we have a valid header (with a link)
743130803Smarcel	 */
744130803Smarcel	return(com_rd(arcn));
745130803Smarcel}
746130803Smarcel
747130803Smarcel/*
748130803Smarcel * vcpio_endrd()
749130803Smarcel *      no cleanup needed here, just return size of the trailer (for append)
750130803Smarcel * Return:
751130803Smarcel *      size of trailer header in this format
752130803Smarcel */
753130803Smarcel
754130803Smarcel#if __STDC__
755130803Smarceloff_t
756130803Smarcelvcpio_endrd(void)
757130803Smarcel#else
758130803Smarceloff_t
759130803Smarcelvcpio_endrd()
760130803Smarcel#endif
761130803Smarcel{
762130803Smarcel	return((off_t)(sizeof(HD_VCPIO) + sizeof(TRAILER) +
763130803Smarcel		(VCPIO_PAD(sizeof(HD_VCPIO) + sizeof(TRAILER)))));
764130803Smarcel}
765130803Smarcel
766130803Smarcel/*
767130803Smarcel * crc_stwr()
768130803Smarcel *	start up the device mapping table, enable crc file calculation
769130803Smarcel * Return:
770130803Smarcel *	0 if ok, -1 otherwise (what dev_start() returns)
771130803Smarcel */
772130803Smarcel
773130803Smarcel#if __STDC__
774130803Smarcelint
775130803Smarcelcrc_stwr(void)
776130803Smarcel#else
777130803Smarcelint
778130803Smarcelcrc_stwr()
779130803Smarcel#endif
780130803Smarcel{
781130803Smarcel	docrc = 1;
782130803Smarcel	return(dev_start());
783130803Smarcel}
784130803Smarcel
785130803Smarcel/*
786130803Smarcel * vcpio_wr()
787130803Smarcel *	copy the data in the ARCHD to buffer in system VR4 cpio
788130803Smarcel *	(with/without crc) format.
789130803Smarcel * Return
790130803Smarcel *	0 if file has data to be written after the header, 1 if file has
791130803Smarcel *	NO data to write after the header, -1 if archive write failed
792130803Smarcel */
793130803Smarcel
794130803Smarcel#if __STDC__
795130803Smarcelint
796130803Smarcelvcpio_wr(register ARCHD *arcn)
797130803Smarcel#else
798130803Smarcelint
799130803Smarcelvcpio_wr(arcn)
800130803Smarcel	register ARCHD *arcn;
801130803Smarcel#endif
802130803Smarcel{
803130803Smarcel	register HD_VCPIO *hd;
804130803Smarcel	unsigned int nsz;
805130803Smarcel	char hdblk[sizeof(HD_VCPIO)];
806130803Smarcel
807130803Smarcel	/*
808130803Smarcel	 * check and repair truncated device and inode fields in the cpio
809130803Smarcel	 * header
810130803Smarcel	 */
811130803Smarcel	if (map_dev(arcn, (u_long)VCPIO_MASK, (u_long)VCPIO_MASK) < 0)
812130803Smarcel		return(-1);
813130803Smarcel	nsz = arcn->nlen + 1;
814130803Smarcel	hd = (HD_VCPIO *)hdblk;
815130803Smarcel	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
816130803Smarcel		arcn->sb.st_rdev = 0;
817130803Smarcel
818130803Smarcel	/*
819130803Smarcel	 * add the proper magic value depending whether we were asked for
820130803Smarcel	 * file data crc's, and the crc if needed.
821130803Smarcel	 */
822130803Smarcel	if (docrc) {
823130803Smarcel		if (ul_asc((u_long)VCMAGIC, hd->c_magic, sizeof(hd->c_magic),
824130803Smarcel	    		OCT) ||
825130803Smarcel		    ul_asc((u_long)arcn->crc,hd->c_chksum,sizeof(hd->c_chksum),
826130803Smarcel	    		HEX))
827130803Smarcel			goto out;
828130803Smarcel	} else {
829130803Smarcel		if (ul_asc((u_long)VMAGIC, hd->c_magic, sizeof(hd->c_magic),
830130803Smarcel	    		OCT) ||
831130803Smarcel		    ul_asc((u_long)0L, hd->c_chksum, sizeof(hd->c_chksum),HEX))
832130803Smarcel			goto out;
833130803Smarcel	}
834130803Smarcel
835130803Smarcel	switch(arcn->type) {
836130803Smarcel	case PAX_CTG:
837130803Smarcel	case PAX_REG:
838130803Smarcel	case PAX_HRG:
839130803Smarcel		/*
840130803Smarcel		 * caller will copy file data to the archive. tell him how
841130803Smarcel		 * much to pad.
842130803Smarcel		 */
843130803Smarcel		arcn->pad = VCPIO_PAD(arcn->sb.st_size);
844130803Smarcel#		ifdef NET2_STAT
845130803Smarcel		if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
846130803Smarcel		    sizeof(hd->c_filesize), HEX)) {
847130803Smarcel#		else
848130803Smarcel		if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
849130803Smarcel		    sizeof(hd->c_filesize), HEX)) {
850130803Smarcel#		endif
851130803Smarcel			warn(1,"File is too large for sv4cpio format %s",
852130803Smarcel			    arcn->org_name);
853130803Smarcel			return(1);
854130803Smarcel		}
855130803Smarcel		break;
856130803Smarcel	case PAX_SLK:
857130803Smarcel		/*
858130803Smarcel		 * no file data for the caller to process, the file data has
859130803Smarcel		 * the size of the link
860130803Smarcel		 */
861130803Smarcel		arcn->pad = 0L;
862130803Smarcel		if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
863130803Smarcel		    sizeof(hd->c_filesize), HEX))
864130803Smarcel			goto out;
865130803Smarcel		break;
866130803Smarcel	default:
867130803Smarcel		/*
868130803Smarcel		 * no file data for the caller to process
869130803Smarcel		 */
870130803Smarcel		arcn->pad = 0L;
871130803Smarcel		if (ul_asc((u_long)0L, hd->c_filesize, sizeof(hd->c_filesize),
872130803Smarcel		    HEX))
873130803Smarcel			goto out;
874130803Smarcel		break;
875130803Smarcel	}
876130803Smarcel
877130803Smarcel	/*
878130803Smarcel	 * set the other fields in the header
879130803Smarcel	 */
880130803Smarcel	if (ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
881130803Smarcel		HEX) ||
882130803Smarcel	    ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
883130803Smarcel		HEX) ||
884130803Smarcel	    ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
885130803Smarcel		HEX) ||
886130803Smarcel	    ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
887130803Smarcel    		HEX) ||
888130803Smarcel	    ul_asc((u_long)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime),
889130803Smarcel    		HEX) ||
890130803Smarcel	    ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
891130803Smarcel    		HEX) ||
892130803Smarcel	    ul_asc((u_long)MAJOR(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj),
893130803Smarcel		HEX) ||
894130803Smarcel	    ul_asc((u_long)MINOR(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min),
895130803Smarcel		HEX) ||
896130803Smarcel	    ul_asc((u_long)MAJOR(arcn->sb.st_rdev),hd->c_rmaj,sizeof(hd->c_maj),
897130803Smarcel		HEX) ||
898130803Smarcel	    ul_asc((u_long)MINOR(arcn->sb.st_rdev),hd->c_rmin,sizeof(hd->c_min),
899130803Smarcel		HEX) ||
900130803Smarcel	    ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), HEX))
901130803Smarcel		goto out;
902130803Smarcel
903130803Smarcel	/*
904130803Smarcel	 * write the header, the file name and padding as required.
905130803Smarcel	 */
906130803Smarcel	if ((wr_rdbuf(hdblk, (int)sizeof(HD_VCPIO)) < 0) ||
907130803Smarcel	    (wr_rdbuf(arcn->name, (int)nsz) < 0)  ||
908130803Smarcel	    (wr_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)) {
909130803Smarcel		warn(1,"Could not write sv4cpio header for %s",arcn->org_name);
910130803Smarcel		return(-1);
911130803Smarcel	}
912130803Smarcel
913130803Smarcel	/*
914130803Smarcel	 * if we have file data, tell the caller we are done, copy the file
915130803Smarcel	 */
916130803Smarcel	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
917130803Smarcel	    (arcn->type == PAX_HRG))
918130803Smarcel		return(0);
91998944Sobrien
92098944Sobrien	/*
92198944Sobrien	 * if we are not a link, tell the caller we are done, go to next file
92298944Sobrien	 */
92398944Sobrien	if (arcn->type != PAX_SLK)
92498944Sobrien		return(1);
92598944Sobrien
92698944Sobrien	/*
92798944Sobrien	 * write the link name, tell the caller we are done.
92898944Sobrien	 */
92998944Sobrien	if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
93098944Sobrien	    (wr_skip((off_t)(VCPIO_PAD(arcn->ln_nlen))) < 0)) {
93198944Sobrien		warn(1,"Could not write sv4cpio link name for %s",
93298944Sobrien		    arcn->org_name);
93398944Sobrien		return(-1);
93498944Sobrien	}
93598944Sobrien	return(1);
93698944Sobrien
93798944Sobrien    out:
93898944Sobrien	/*
93998944Sobrien	 * header field is out of range
94098944Sobrien	 */
94198944Sobrien	warn(1,"Sv4cpio header field is too small for file %s",arcn->org_name);
94298944Sobrien	return(1);
94398944Sobrien}
94498944Sobrien
94598944Sobrien/*
94698944Sobrien * Routines common to the old binary header cpio
94798944Sobrien */
94898944Sobrien
94998944Sobrien/*
95098944Sobrien * bcpio_id()
95198944Sobrien *      determine if a block given to us is a old binary cpio header
95298944Sobrien *	(with/without header byte swapping)
95398944Sobrien * Return:
95498944Sobrien *      0 if a valid header, -1 otherwise
95598944Sobrien */
95698944Sobrien
95798944Sobrien#if __STDC__
95898944Sobrienint
95998944Sobrienbcpio_id(char *blk, int size)
96098944Sobrien#else
96198944Sobrienint
96298944Sobrienbcpio_id(blk, size)
96398944Sobrien	char *blk;
96498944Sobrien	int size;
96598944Sobrien#endif
96698944Sobrien{
96798944Sobrien	if (size < sizeof(HD_BCPIO))
96898944Sobrien		return(-1);
96998944Sobrien
97098944Sobrien	/*
97198944Sobrien	 * check both normal and byte swapped magic cookies
97298944Sobrien	 */
97398944Sobrien	if (((u_short)SHRT_EXT(blk)) == MAGIC)
97498944Sobrien		return(0);
97598944Sobrien	if (((u_short)RSHRT_EXT(blk)) == MAGIC) {
97698944Sobrien		if (!swp_head)
97798944Sobrien			++swp_head;
97898944Sobrien		return(0);
97998944Sobrien	}
98098944Sobrien	return(-1);
98198944Sobrien}
98298944Sobrien
98398944Sobrien/*
98498944Sobrien * bcpio_rd()
98598944Sobrien *	determine if a buffer is a old binary archive entry. (it may have byte
986130803Smarcel *	swapped header) convert and store the values in the ARCHD parameter.
987130803Smarcel *	This is a very old header format and should not really be used.
988130803Smarcel * Return:
989130803Smarcel *	0 if a valid header, -1 otherwise.
990130803Smarcel */
99198944Sobrien
992130803Smarcel#if __STDC__
993130803Smarcelint
994130803Smarcelbcpio_rd(register ARCHD *arcn, register char *buf)
995130803Smarcel#else
996130803Smarcelint
997130803Smarcelbcpio_rd(arcn, buf)
998130803Smarcel	register ARCHD *arcn;
999130803Smarcel	register char *buf;
1000130803Smarcel#endif
1001130803Smarcel{
100298944Sobrien	register HD_BCPIO *hd;
100398944Sobrien	register int nsz;
100498944Sobrien
100598944Sobrien	/*
100698944Sobrien	 * check the header
100798944Sobrien	 */
100898944Sobrien	if (bcpio_id(buf, sizeof(HD_BCPIO)) < 0)
100998944Sobrien		return(-1);
101098944Sobrien
101198944Sobrien	arcn->pad = 0L;
101298944Sobrien	hd = (HD_BCPIO *)buf;
101398944Sobrien	if (swp_head) {
101498944Sobrien		/*
101598944Sobrien		 * header has swapped bytes on 16 bit boundries
101698944Sobrien		 */
1017130803Smarcel		arcn->sb.st_dev = (dev_t)(RSHRT_EXT(hd->h_dev));
1018130803Smarcel		arcn->sb.st_ino = (ino_t)(RSHRT_EXT(hd->h_ino));
101998944Sobrien		arcn->sb.st_mode = (mode_t)(RSHRT_EXT(hd->h_mode));
102098944Sobrien		arcn->sb.st_uid = (uid_t)(RSHRT_EXT(hd->h_uid));
102198944Sobrien		arcn->sb.st_gid = (gid_t)(RSHRT_EXT(hd->h_gid));
102298944Sobrien		arcn->sb.st_nlink = (nlink_t)(RSHRT_EXT(hd->h_nlink));
102398944Sobrien		arcn->sb.st_rdev = (dev_t)(RSHRT_EXT(hd->h_rdev));
102498944Sobrien		arcn->sb.st_mtime = (time_t)(RSHRT_EXT(hd->h_mtime_1));
102598944Sobrien		arcn->sb.st_mtime =  (arcn->sb.st_mtime << 16) |
102698944Sobrien			((time_t)(RSHRT_EXT(hd->h_mtime_2)));
102798944Sobrien		arcn->sb.st_size = (off_t)(RSHRT_EXT(hd->h_filesize_1));
102898944Sobrien		arcn->sb.st_size = (arcn->sb.st_size << 16) |
102998944Sobrien			((off_t)(RSHRT_EXT(hd->h_filesize_2)));
103098944Sobrien		nsz = (int)(RSHRT_EXT(hd->h_namesize));
103198944Sobrien	} else {
103298944Sobrien		arcn->sb.st_dev = (dev_t)(SHRT_EXT(hd->h_dev));
103398944Sobrien		arcn->sb.st_ino = (ino_t)(SHRT_EXT(hd->h_ino));
103498944Sobrien		arcn->sb.st_mode = (mode_t)(SHRT_EXT(hd->h_mode));
103598944Sobrien		arcn->sb.st_uid = (uid_t)(SHRT_EXT(hd->h_uid));
103698944Sobrien		arcn->sb.st_gid = (gid_t)(SHRT_EXT(hd->h_gid));
103798944Sobrien		arcn->sb.st_nlink = (nlink_t)(SHRT_EXT(hd->h_nlink));
103898944Sobrien		arcn->sb.st_rdev = (dev_t)(SHRT_EXT(hd->h_rdev));
103998944Sobrien		arcn->sb.st_mtime = (time_t)(SHRT_EXT(hd->h_mtime_1));
104098944Sobrien		arcn->sb.st_mtime =  (arcn->sb.st_mtime << 16) |
104198944Sobrien			((time_t)(SHRT_EXT(hd->h_mtime_2)));
104298944Sobrien		arcn->sb.st_size = (off_t)(SHRT_EXT(hd->h_filesize_1));
104398944Sobrien		arcn->sb.st_size = (arcn->sb.st_size << 16) |
104498944Sobrien			((off_t)(SHRT_EXT(hd->h_filesize_2)));
104598944Sobrien		nsz = (int)(SHRT_EXT(hd->h_namesize));
104698944Sobrien	}
104798944Sobrien	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
104898944Sobrien
104998944Sobrien	/*
105098944Sobrien	 * check the file name size, if bogus give up. otherwise read the file
105198944Sobrien	 * name
105298944Sobrien	 */
105398944Sobrien	if (nsz < 2)
105498944Sobrien		return(-1);
105598944Sobrien	arcn->nlen = nsz - 1;
105698944Sobrien	if (rd_nm(arcn, nsz) < 0)
105798944Sobrien		return(-1);
105898944Sobrien
105998944Sobrien	/*
106098944Sobrien	 * header + file name are aligned to 2 byte boundries, skip if needed
106198944Sobrien	 */
106298944Sobrien	if (rd_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)
106398944Sobrien		return(-1);
106498944Sobrien
106598944Sobrien	/*
106698944Sobrien	 * if not a link (or a file with no data), calculate pad size (for
106798944Sobrien	 * padding which follows the file data), clear the link name and return
106898944Sobrien	 */
106998944Sobrien	if (((arcn->sb.st_mode & C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)){
107098944Sobrien		/*
107198944Sobrien		 * we have a valid header (not a link)
107298944Sobrien		 */
107398944Sobrien		arcn->ln_nlen = 0;
107498944Sobrien		arcn->ln_name[0] = '\0';
107598944Sobrien		arcn->pad = BCPIO_PAD(arcn->sb.st_size);
107698944Sobrien		return(com_rd(arcn));
107798944Sobrien	}
107898944Sobrien
107998944Sobrien	if ((rd_ln_nm(arcn) < 0) ||
108098944Sobrien	    (rd_skip((off_t)(BCPIO_PAD(arcn->sb.st_size))) < 0))
108198944Sobrien		return(-1);
108298944Sobrien
108398944Sobrien	/*
108498944Sobrien	 * we have a valid header (with a link)
108598944Sobrien	 */
1086130803Smarcel	return(com_rd(arcn));
108798944Sobrien}
108898944Sobrien
108998944Sobrien/*
109098944Sobrien * bcpio_endrd()
109198944Sobrien *      no cleanup needed here, just return size of the trailer (for append)
109298944Sobrien * Return:
109398944Sobrien *      size of trailer header in this format
109498944Sobrien */
109598944Sobrien
109698944Sobrien#if __STDC__
109798944Sobrienoff_t
109898944Sobrienbcpio_endrd(void)
109998944Sobrien#else
110098944Sobrienoff_t
110198944Sobrienbcpio_endrd()
110298944Sobrien#endif
110398944Sobrien{
110498944Sobrien	return((off_t)(sizeof(HD_BCPIO) + sizeof(TRAILER) +
110598944Sobrien		(BCPIO_PAD(sizeof(HD_BCPIO) + sizeof(TRAILER)))));
110698944Sobrien}
110798944Sobrien
110898944Sobrien/*
110998944Sobrien * bcpio_wr()
111098944Sobrien *	copy the data in the ARCHD to buffer in old binary cpio format
1111130803Smarcel *	There is a real chance of field overflow with this critter. So we
111298944Sobrien *	always check the conversion is ok. nobody in his their right mind
111398944Sobrien *	should write an achive in this format...
111498944Sobrien * Return
1115130803Smarcel *      0 if file has data to be written after the header, 1 if file has NO
111698944Sobrien *	data to write after the header, -1 if archive write failed
111798944Sobrien */
111898944Sobrien
111998944Sobrien#if __STDC__
112098944Sobrienint
112198944Sobrienbcpio_wr(register ARCHD *arcn)
112298944Sobrien#else
112398944Sobrienint
112498944Sobrienbcpio_wr(arcn)
112598944Sobrien	register ARCHD *arcn;
112698944Sobrien#endif
112798944Sobrien{
112898944Sobrien	register HD_BCPIO *hd;
112998944Sobrien	register int nsz;
113098944Sobrien	char hdblk[sizeof(HD_BCPIO)];
113198944Sobrien	off_t t_offt;
113298944Sobrien	int t_int;
113398944Sobrien	time_t t_timet;
113498944Sobrien
113598944Sobrien	/*
113698944Sobrien	 * check and repair truncated device and inode fields in the cpio
113798944Sobrien	 * header
113898944Sobrien	 */
113998944Sobrien	if (map_dev(arcn, (u_long)BCPIO_MASK, (u_long)BCPIO_MASK) < 0)
114098944Sobrien		return(-1);
114198944Sobrien
114298944Sobrien	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
114398944Sobrien		arcn->sb.st_rdev = 0;
114498944Sobrien	hd = (HD_BCPIO *)hdblk;
114598944Sobrien
114698944Sobrien	switch(arcn->type) {
114798944Sobrien	case PAX_CTG:
114898944Sobrien	case PAX_REG:
114998944Sobrien	case PAX_HRG:
115098944Sobrien		/*
115198944Sobrien		 * caller will copy file data to the archive. tell him how
115298944Sobrien		 * much to pad.
115398944Sobrien		 */
115498944Sobrien		arcn->pad = BCPIO_PAD(arcn->sb.st_size);
115598944Sobrien		hd->h_filesize_1[0] = CHR_WR_0(arcn->sb.st_size);
115698944Sobrien		hd->h_filesize_1[1] = CHR_WR_1(arcn->sb.st_size);
115798944Sobrien		hd->h_filesize_2[0] = CHR_WR_2(arcn->sb.st_size);
115898944Sobrien		hd->h_filesize_2[1] = CHR_WR_3(arcn->sb.st_size);
115998944Sobrien		t_offt = (off_t)(SHRT_EXT(hd->h_filesize_1));
116098944Sobrien		t_offt = (t_offt<<16) | ((off_t)(SHRT_EXT(hd->h_filesize_2)));
116198944Sobrien		if (arcn->sb.st_size != t_offt) {
116298944Sobrien			warn(1,"File is too large for bcpio format %s",
116398944Sobrien			    arcn->org_name);
116498944Sobrien			return(1);
116598944Sobrien		}
116698944Sobrien		break;
116798944Sobrien	case PAX_SLK:
116898944Sobrien		/*
116998944Sobrien		 * no file data for the caller to process, the file data has
117098944Sobrien		 * the size of the link
117198944Sobrien		 */
117298944Sobrien		arcn->pad = 0L;
117398944Sobrien		hd->h_filesize_1[0] = CHR_WR_0(arcn->ln_nlen);
117498944Sobrien		hd->h_filesize_1[1] = CHR_WR_1(arcn->ln_nlen);
117598944Sobrien		hd->h_filesize_2[0] = CHR_WR_2(arcn->ln_nlen);
117698944Sobrien		hd->h_filesize_2[1] = CHR_WR_3(arcn->ln_nlen);
117798944Sobrien		t_int = (int)(SHRT_EXT(hd->h_filesize_1));
117898944Sobrien		t_int = (t_int << 16) | ((int)(SHRT_EXT(hd->h_filesize_2)));
117998944Sobrien		if (arcn->ln_nlen != t_int)
118098944Sobrien			goto out;
118198944Sobrien		break;
118298944Sobrien	default:
118398944Sobrien		/*
118498944Sobrien		 * no file data for the caller to process
118598944Sobrien		 */
118698944Sobrien		arcn->pad = 0L;
118798944Sobrien		hd->h_filesize_1[0] = (char)0;
118898944Sobrien		hd->h_filesize_1[1] = (char)0;
118998944Sobrien		hd->h_filesize_2[0] = (char)0;
119098944Sobrien		hd->h_filesize_2[1] = (char)0;
119198944Sobrien		break;
119298944Sobrien	}
119398944Sobrien
119498944Sobrien	/*
119598944Sobrien	 * build up the rest of the fields
119698944Sobrien	 */
119798944Sobrien	hd->h_magic[0] = CHR_WR_2(MAGIC);
119898944Sobrien	hd->h_magic[1] = CHR_WR_3(MAGIC);
119998944Sobrien	hd->h_dev[0] = CHR_WR_2(arcn->sb.st_dev);
120098944Sobrien	hd->h_dev[1] = CHR_WR_3(arcn->sb.st_dev);
120198944Sobrien	if (arcn->sb.st_dev != (dev_t)(SHRT_EXT(hd->h_dev)))
120298944Sobrien		goto out;
120398944Sobrien	hd->h_ino[0] = CHR_WR_2(arcn->sb.st_ino);
120498944Sobrien	hd->h_ino[1] = CHR_WR_3(arcn->sb.st_ino);
120598944Sobrien	if (arcn->sb.st_ino != (ino_t)(SHRT_EXT(hd->h_ino)))
120698944Sobrien		goto out;
120798944Sobrien	hd->h_mode[0] = CHR_WR_2(arcn->sb.st_mode);
120898944Sobrien	hd->h_mode[1] = CHR_WR_3(arcn->sb.st_mode);
120998944Sobrien	if (arcn->sb.st_mode != (mode_t)(SHRT_EXT(hd->h_mode)))
121098944Sobrien		goto out;
121198944Sobrien	hd->h_uid[0] = CHR_WR_2(arcn->sb.st_uid);
121298944Sobrien	hd->h_uid[1] = CHR_WR_3(arcn->sb.st_uid);
121398944Sobrien	if (arcn->sb.st_uid != (uid_t)(SHRT_EXT(hd->h_uid)))
121498944Sobrien		goto out;
1215130803Smarcel	hd->h_gid[0] = CHR_WR_2(arcn->sb.st_gid);
121698944Sobrien	hd->h_gid[1] = CHR_WR_3(arcn->sb.st_gid);
1217130803Smarcel	if (arcn->sb.st_gid != (gid_t)(SHRT_EXT(hd->h_gid)))
121898944Sobrien		goto out;
1219130803Smarcel	hd->h_nlink[0] = CHR_WR_2(arcn->sb.st_nlink);
1220130803Smarcel	hd->h_nlink[1] = CHR_WR_3(arcn->sb.st_nlink);
1221130803Smarcel	if (arcn->sb.st_nlink != (nlink_t)(SHRT_EXT(hd->h_nlink)))
1222130803Smarcel		goto out;
1223130803Smarcel	hd->h_rdev[0] = CHR_WR_2(arcn->sb.st_rdev);
1224130803Smarcel	hd->h_rdev[1] = CHR_WR_3(arcn->sb.st_rdev);
1225130803Smarcel	if (arcn->sb.st_rdev != (dev_t)(SHRT_EXT(hd->h_rdev)))
1226130803Smarcel		goto out;
1227130803Smarcel	hd->h_mtime_1[0] = CHR_WR_0(arcn->sb.st_mtime);
1228130803Smarcel	hd->h_mtime_1[1] = CHR_WR_1(arcn->sb.st_mtime);
1229130803Smarcel	hd->h_mtime_2[0] = CHR_WR_2(arcn->sb.st_mtime);
1230130803Smarcel	hd->h_mtime_2[1] = CHR_WR_3(arcn->sb.st_mtime);
1231130803Smarcel	t_timet = (time_t)(SHRT_EXT(hd->h_mtime_1));
1232130803Smarcel	t_timet =  (t_timet << 16) | ((time_t)(SHRT_EXT(hd->h_mtime_2)));
1233130803Smarcel	if (arcn->sb.st_mtime != t_timet)
1234130803Smarcel		goto out;
1235130803Smarcel	nsz = arcn->nlen + 1;
1236130803Smarcel	hd->h_namesize[0] = CHR_WR_2(nsz);
1237130803Smarcel	hd->h_namesize[1] = CHR_WR_3(nsz);
1238130803Smarcel	if (nsz != (int)(SHRT_EXT(hd->h_namesize)))
1239130803Smarcel		goto out;
1240130803Smarcel
1241130803Smarcel	/*
1242130803Smarcel	 * write the header, the file name and padding as required.
1243130803Smarcel	 */
1244130803Smarcel	if ((wr_rdbuf(hdblk, (int)sizeof(HD_BCPIO)) < 0) ||
1245130803Smarcel	    (wr_rdbuf(arcn->name, nsz) < 0) ||
1246130803Smarcel	    (wr_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)) {
1247130803Smarcel		warn(1, "Could not write bcpio header for %s", arcn->org_name);
1248130803Smarcel		return(-1);
1249130803Smarcel	}
1250130803Smarcel
1251130803Smarcel	/*
1252130803Smarcel	 * if we have file data, tell the caller we are done
1253130803Smarcel	 */
1254130803Smarcel	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
1255130803Smarcel	    (arcn->type == PAX_HRG))
1256130803Smarcel		return(0);
1257130803Smarcel
1258130803Smarcel	/*
1259130803Smarcel	 * if we are not a link, tell the caller we are done, go to next file
1260130803Smarcel	 */
1261130803Smarcel	if (arcn->type != PAX_SLK)
1262130803Smarcel		return(1);
1263130803Smarcel
126498944Sobrien	/*
126598944Sobrien	 * write the link name, tell the caller we are done.
126698944Sobrien	 */
126798944Sobrien	if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
126898944Sobrien	    (wr_skip((off_t)(BCPIO_PAD(arcn->ln_nlen))) < 0)) {
126998944Sobrien		warn(1,"Could not write bcpio link name for %s",arcn->org_name);
127098944Sobrien		return(-1);
127198944Sobrien	}
127298944Sobrien	return(1);
127398944Sobrien
127498944Sobrien    out:
1275130803Smarcel	/*
127698944Sobrien	 * header field is out of range
127798944Sobrien	 */
127898944Sobrien	warn(1,"Bcpio header field is too small for file %s", arcn->org_name);
127998944Sobrien	return(1);
128098944Sobrien}
1281130803Smarcel