11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1992 Keith Muller.
31556Srgrimes * Copyright (c) 1992, 1993
41556Srgrimes *	The Regents of the University of California.  All rights reserved.
51556Srgrimes *
61556Srgrimes * This code is derived from software contributed to Berkeley by
71556Srgrimes * Keith Muller of the University of California, San Diego.
81556Srgrimes *
91556Srgrimes * Redistribution and use in source and binary forms, with or without
101556Srgrimes * modification, are permitted provided that the following conditions
111556Srgrimes * are met:
121556Srgrimes * 1. Redistributions of source code must retain the above copyright
131556Srgrimes *    notice, this list of conditions and the following disclaimer.
141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151556Srgrimes *    notice, this list of conditions and the following disclaimer in the
161556Srgrimes *    documentation and/or other materials provided with the distribution.
171556Srgrimes * 4. Neither the name of the University nor the names of its contributors
181556Srgrimes *    may be used to endorse or promote products derived from this software
191556Srgrimes *    without specific prior written permission.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311556Srgrimes * SUCH DAMAGE.
321556Srgrimes */
331556Srgrimes
341556Srgrimes#ifndef lint
3536049Scharnier#if 0
3636049Scharnierstatic char sccsid[] = "@(#)cpio.c	8.1 (Berkeley) 5/31/93";
3736049Scharnier#endif
381556Srgrimes#endif /* not lint */
3999110Sobrien#include <sys/cdefs.h>
4099110Sobrien__FBSDID("$FreeBSD$");
411556Srgrimes
421556Srgrimes#include <sys/types.h>
431556Srgrimes#include <sys/time.h>
441556Srgrimes#include <sys/stat.h>
451556Srgrimes#include <string.h>
46104548Stjr#include <stdint.h>
471556Srgrimes#include <stdio.h>
481556Srgrimes#include <unistd.h>
491556Srgrimes#include <stdlib.h>
501556Srgrimes#include "pax.h"
511556Srgrimes#include "cpio.h"
521556Srgrimes#include "extern.h"
531556Srgrimes
5490113Simpstatic int rd_nm(ARCHD *, int);
5590113Simpstatic int rd_ln_nm(ARCHD *);
5690113Simpstatic int com_rd(ARCHD *);
571556Srgrimes
581556Srgrimes/*
591556Srgrimes * Routines which support the different cpio versions
601556Srgrimes */
611556Srgrimes
621556Srgrimesstatic int swp_head;		/* binary cpio header byte swap */
631556Srgrimes
641556Srgrimes/*
651556Srgrimes * Routines common to all versions of cpio
661556Srgrimes */
671556Srgrimes
681556Srgrimes/*
691556Srgrimes * cpio_strd()
701556Srgrimes *	Fire up the hard link detection code
711556Srgrimes * Return:
721556Srgrimes *      0 if ok -1 otherwise (the return values of lnk_start())
731556Srgrimes */
741556Srgrimes
751556Srgrimesint
761556Srgrimescpio_strd(void)
771556Srgrimes{
781556Srgrimes	return(lnk_start());
791556Srgrimes}
801556Srgrimes
811556Srgrimes/*
821556Srgrimes * cpio_trail()
831556Srgrimes *	Called to determine if a header block is a valid trailer. We are
841556Srgrimes *	passed the block, the in_sync flag (which tells us we are in resync
851556Srgrimes *	mode; looking for a valid header), and cnt (which starts at zero)
861556Srgrimes *	which is used to count the number of empty blocks we have seen so far.
871556Srgrimes * Return:
888855Srgrimes *	0 if a valid trailer, -1 if not a valid trailer,
891556Srgrimes */
901556Srgrimes
911556Srgrimesint
9290113Simpcpio_trail(ARCHD *arcn)
931556Srgrimes{
941556Srgrimes	/*
951556Srgrimes	 * look for trailer id in file we are about to process
961556Srgrimes	 */
971556Srgrimes	if ((strcmp(arcn->name, TRAILER) == 0) && (arcn->sb.st_size == 0))
981556Srgrimes		return(0);
991556Srgrimes	return(-1);
1001556Srgrimes}
1011556Srgrimes
1021556Srgrimes/*
1031556Srgrimes * com_rd()
1041556Srgrimes *	operations common to all cpio read functions.
1051556Srgrimes * Return:
1061556Srgrimes *	0
1071556Srgrimes */
1081556Srgrimes
1091556Srgrimesstatic int
11090113Simpcom_rd(ARCHD *arcn)
1111556Srgrimes{
1121556Srgrimes	arcn->skip = 0;
1131556Srgrimes	arcn->pat = NULL;
1141556Srgrimes	arcn->org_name = arcn->name;
1151556Srgrimes	switch(arcn->sb.st_mode & C_IFMT) {
1161556Srgrimes	case C_ISFIFO:
1171556Srgrimes		arcn->type = PAX_FIF;
1181556Srgrimes		break;
1191556Srgrimes	case C_ISDIR:
1201556Srgrimes		arcn->type = PAX_DIR;
1211556Srgrimes		break;
1221556Srgrimes	case C_ISBLK:
1231556Srgrimes		arcn->type = PAX_BLK;
1241556Srgrimes		break;
1251556Srgrimes	case C_ISCHR:
1261556Srgrimes		arcn->type = PAX_CHR;
1271556Srgrimes		break;
1281556Srgrimes	case C_ISLNK:
1291556Srgrimes		arcn->type = PAX_SLK;
1301556Srgrimes		break;
1311556Srgrimes	case C_ISOCK:
1321556Srgrimes		arcn->type = PAX_SCK;
1331556Srgrimes		break;
1341556Srgrimes	case C_ISCTG:
1351556Srgrimes	case C_ISREG:
1361556Srgrimes	default:
1371556Srgrimes		/*
1381556Srgrimes		 * we have file data, set up skip (pad is set in the format
1391556Srgrimes		 * specific sections)
1401556Srgrimes		 */
1411556Srgrimes		arcn->sb.st_mode = (arcn->sb.st_mode & 0xfff) | C_ISREG;
1421556Srgrimes		arcn->type = PAX_REG;
1431556Srgrimes		arcn->skip = arcn->sb.st_size;
1441556Srgrimes		break;
1451556Srgrimes	}
1461556Srgrimes	if (chk_lnk(arcn) < 0)
1471556Srgrimes		return(-1);
1481556Srgrimes	return(0);
1491556Srgrimes}
1501556Srgrimes
1511556Srgrimes/*
1521556Srgrimes * cpio_end_wr()
1531556Srgrimes *	write the special file with the name trailer in the proper format
1541556Srgrimes * Return:
1551556Srgrimes *	result of the write of the trailer from the cpio specific write func
1561556Srgrimes */
1571556Srgrimes
1581556Srgrimesint
1591556Srgrimescpio_endwr(void)
1601556Srgrimes{
1611556Srgrimes	ARCHD last;
1621556Srgrimes
1631556Srgrimes	/*
1641556Srgrimes	 * create a trailer request and call the proper format write function
1651556Srgrimes	 */
16676017Skris	memset(&last, 0, sizeof(last));
1671556Srgrimes	last.nlen = sizeof(TRAILER) - 1;
1681556Srgrimes	last.type = PAX_REG;
1691556Srgrimes	last.sb.st_nlink = 1;
1701556Srgrimes	(void)strcpy(last.name, TRAILER);
1711556Srgrimes	return((*frmt->wr)(&last));
1721556Srgrimes}
1731556Srgrimes
1741556Srgrimes/*
1751556Srgrimes * rd_nam()
1761556Srgrimes *	read in the file name which follows the cpio header
1771556Srgrimes * Return:
1781556Srgrimes *	0 if ok, -1 otherwise
1791556Srgrimes */
1801556Srgrimes
1811556Srgrimesstatic int
18290113Simprd_nm(ARCHD *arcn, int nsz)
1831556Srgrimes{
1841556Srgrimes	/*
1851556Srgrimes	 * do not even try bogus values
1861556Srgrimes	 */
187114469Sobrien	if ((nsz == 0) || (nsz > (int)sizeof(arcn->name))) {
18876017Skris		paxwarn(1, "Cpio file name length %d is out of range", nsz);
1891556Srgrimes		return(-1);
1901556Srgrimes	}
1911556Srgrimes
1921556Srgrimes	/*
1931556Srgrimes	 * read the name and make sure it is not empty and is \0 terminated
1941556Srgrimes	 */
1951556Srgrimes	if ((rd_wrbuf(arcn->name,nsz) != nsz) || (arcn->name[nsz-1] != '\0') ||
1961556Srgrimes	    (arcn->name[0] == '\0')) {
19776017Skris		paxwarn(1, "Cpio file name in header is corrupted");
1981556Srgrimes		return(-1);
1991556Srgrimes	}
2001556Srgrimes	return(0);
2011556Srgrimes}
2021556Srgrimes
2031556Srgrimes/*
2041556Srgrimes * rd_ln_nm()
2051556Srgrimes *	read in the link name for a file with links. The link name is stored
2061556Srgrimes *	like file data (and is NOT \0 terminated!)
2071556Srgrimes * Return:
2081556Srgrimes *	0 if ok, -1 otherwise
2091556Srgrimes */
2101556Srgrimes
2111556Srgrimesstatic int
21290113Simprd_ln_nm(ARCHD *arcn)
2131556Srgrimes{
2141556Srgrimes	/*
2151556Srgrimes	 * check the length specified for bogus values
2161556Srgrimes	 */
2171556Srgrimes	if ((arcn->sb.st_size == 0) ||
218114583Smarkm	    ((size_t)arcn->sb.st_size >= sizeof(arcn->ln_name))) {
2191556Srgrimes#		ifdef NET2_STAT
22076017Skris		paxwarn(1, "Cpio link name length is invalid: %lu",
2211556Srgrimes		    arcn->sb.st_size);
2221556Srgrimes#		else
223104548Stjr		paxwarn(1, "Cpio link name length is invalid: %ju",
224104548Stjr		    (uintmax_t)arcn->sb.st_size);
2251556Srgrimes#		endif
2261556Srgrimes		return(-1);
2271556Srgrimes	}
2281556Srgrimes
2291556Srgrimes	/*
2301556Srgrimes	 * read in the link name and \0 terminate it
2311556Srgrimes	 */
2321556Srgrimes	if (rd_wrbuf(arcn->ln_name, (int)arcn->sb.st_size) !=
2331556Srgrimes	    (int)arcn->sb.st_size) {
23476017Skris		paxwarn(1, "Cpio link name read error");
2351556Srgrimes		return(-1);
2361556Srgrimes	}
2371556Srgrimes	arcn->ln_nlen = arcn->sb.st_size;
2381556Srgrimes	arcn->ln_name[arcn->ln_nlen] = '\0';
2391556Srgrimes
2401556Srgrimes	/*
2411556Srgrimes	 * watch out for those empty link names
2421556Srgrimes	 */
2431556Srgrimes	if (arcn->ln_name[0] == '\0') {
24476017Skris		paxwarn(1, "Cpio link name is corrupt");
2451556Srgrimes		return(-1);
2461556Srgrimes	}
2471556Srgrimes	return(0);
2481556Srgrimes}
2491556Srgrimes
2501556Srgrimes/*
2511556Srgrimes * Routines common to the extended byte oriented cpio format
2521556Srgrimes */
2531556Srgrimes
2541556Srgrimes/*
2551556Srgrimes * cpio_id()
2561556Srgrimes *      determine if a block given to us is a valid extended byte oriented
2571556Srgrimes *	cpio header
2581556Srgrimes * Return:
2591556Srgrimes *      0 if a valid header, -1 otherwise
2601556Srgrimes */
2611556Srgrimes
2621556Srgrimesint
2631556Srgrimescpio_id(char *blk, int size)
2641556Srgrimes{
265114469Sobrien	if ((size < (int)sizeof(HD_CPIO)) ||
2661556Srgrimes	    (strncmp(blk, AMAGIC, sizeof(AMAGIC) - 1) != 0))
2671556Srgrimes		return(-1);
2681556Srgrimes	return(0);
2691556Srgrimes}
2701556Srgrimes
2711556Srgrimes/*
2721556Srgrimes * cpio_rd()
2731556Srgrimes *	determine if a buffer is a byte oriented extended cpio archive entry.
2741556Srgrimes *	convert and store the values in the ARCHD parameter.
2751556Srgrimes * Return:
2761556Srgrimes *	0 if a valid header, -1 otherwise.
2771556Srgrimes */
2781556Srgrimes
2791556Srgrimesint
28090113Simpcpio_rd(ARCHD *arcn, char *buf)
2811556Srgrimes{
28290113Simp	int nsz;
28390113Simp	HD_CPIO *hd;
2841556Srgrimes
2851556Srgrimes	/*
2861556Srgrimes	 * check that this is a valid header, if not return -1
2871556Srgrimes	 */
2881556Srgrimes	if (cpio_id(buf, sizeof(HD_CPIO)) < 0)
2891556Srgrimes		return(-1);
2901556Srgrimes	hd = (HD_CPIO *)buf;
2911556Srgrimes
2921556Srgrimes	/*
2931556Srgrimes	 * byte oriented cpio (posix) does not have padding! extract the octal
2941556Srgrimes	 * ascii fields from the header
2951556Srgrimes	 */
2961556Srgrimes	arcn->pad = 0L;
2971556Srgrimes	arcn->sb.st_dev = (dev_t)asc_ul(hd->c_dev, sizeof(hd->c_dev), OCT);
2981556Srgrimes	arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), OCT);
2991556Srgrimes	arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), OCT);
3001556Srgrimes	arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), OCT);
3011556Srgrimes	arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), OCT);
3021556Srgrimes	arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
3031556Srgrimes	    OCT);
3041556Srgrimes	arcn->sb.st_rdev = (dev_t)asc_ul(hd->c_rdev, sizeof(hd->c_rdev), OCT);
30585617Sdillon#ifdef NET2_STAT
3061556Srgrimes	arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime, sizeof(hd->c_mtime),
3071556Srgrimes	    OCT);
30885617Sdillon#else
30985617Sdillon	arcn->sb.st_mtime = (time_t)asc_uqd(hd->c_mtime, sizeof(hd->c_mtime),
31085617Sdillon	    OCT);
31185617Sdillon#endif
3121556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
31385617Sdillon#ifdef NET2_STAT
3141556Srgrimes	arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,sizeof(hd->c_filesize),
3151556Srgrimes	    OCT);
31685617Sdillon#else
3171556Srgrimes	arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,sizeof(hd->c_filesize),
3181556Srgrimes	    OCT);
31985617Sdillon#endif
3201556Srgrimes
3211556Srgrimes	/*
3221556Srgrimes	 * check name size and if valid, read in the name of this entry (name
3231556Srgrimes	 * follows header in the archive)
3241556Srgrimes	 */
3251556Srgrimes	if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),OCT)) < 2)
3261556Srgrimes		return(-1);
3271556Srgrimes	arcn->nlen = nsz - 1;
3281556Srgrimes	if (rd_nm(arcn, nsz) < 0)
3291556Srgrimes		return(-1);
3301556Srgrimes
3311556Srgrimes	if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
3321556Srgrimes		/*
3331556Srgrimes	 	 * no link name to read for this file
3341556Srgrimes	 	 */
3351556Srgrimes		arcn->ln_nlen = 0;
3361556Srgrimes		arcn->ln_name[0] = '\0';
3371556Srgrimes		return(com_rd(arcn));
3381556Srgrimes	}
3391556Srgrimes
3401556Srgrimes	/*
3411556Srgrimes	 * check link name size and read in the link name. Link names are
3421556Srgrimes	 * stored like file data.
3431556Srgrimes	 */
3441556Srgrimes	if (rd_ln_nm(arcn) < 0)
3451556Srgrimes		return(-1);
3461556Srgrimes
3471556Srgrimes	/*
3481556Srgrimes	 * we have a valid header (with a link)
3491556Srgrimes	 */
3501556Srgrimes	return(com_rd(arcn));
3511556Srgrimes}
3521556Srgrimes
3531556Srgrimes/*
3541556Srgrimes * cpio_endrd()
3551556Srgrimes *      no cleanup needed here, just return size of the trailer (for append)
3561556Srgrimes * Return:
3571556Srgrimes *      size of trailer header in this format
3581556Srgrimes */
3591556Srgrimes
3601556Srgrimesoff_t
3611556Srgrimescpio_endrd(void)
3621556Srgrimes{
3631556Srgrimes	return((off_t)(sizeof(HD_CPIO) + sizeof(TRAILER)));
3641556Srgrimes}
3651556Srgrimes
3661556Srgrimes/*
3671556Srgrimes * cpio_stwr()
3681556Srgrimes *	start up the device mapping table
3691556Srgrimes * Return:
3701556Srgrimes *	0 if ok, -1 otherwise (what dev_start() returns)
3711556Srgrimes */
3721556Srgrimes
3731556Srgrimesint
3741556Srgrimescpio_stwr(void)
3751556Srgrimes{
3761556Srgrimes	return(dev_start());
3771556Srgrimes}
3781556Srgrimes
3791556Srgrimes/*
3801556Srgrimes * cpio_wr()
3811556Srgrimes *	copy the data in the ARCHD to buffer in extended byte oriented cpio
3821556Srgrimes *	format.
3831556Srgrimes * Return
3841556Srgrimes *      0 if file has data to be written after the header, 1 if file has NO
3851556Srgrimes *	data to write after the header, -1 if archive write failed
3861556Srgrimes */
3871556Srgrimes
3881556Srgrimesint
38990113Simpcpio_wr(ARCHD *arcn)
3901556Srgrimes{
39190113Simp	HD_CPIO *hd;
39290113Simp	int nsz;
393164699Sru	HD_CPIO hdblk;
3941556Srgrimes
3951556Srgrimes	/*
3961556Srgrimes	 * check and repair truncated device and inode fields in the header
3971556Srgrimes	 */
3981556Srgrimes	if (map_dev(arcn, (u_long)CPIO_MASK, (u_long)CPIO_MASK) < 0)
3991556Srgrimes		return(-1);
4001556Srgrimes
4011556Srgrimes	arcn->pad = 0L;
4021556Srgrimes	nsz = arcn->nlen + 1;
403164699Sru	hd = &hdblk;
4041556Srgrimes	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
4051556Srgrimes		arcn->sb.st_rdev = 0;
4061556Srgrimes
4071556Srgrimes	switch(arcn->type) {
4081556Srgrimes	case PAX_CTG:
4091556Srgrimes	case PAX_REG:
4101556Srgrimes	case PAX_HRG:
4111556Srgrimes		/*
4121556Srgrimes		 * set data size for file data
4131556Srgrimes		 */
4141556Srgrimes#		ifdef NET2_STAT
4151556Srgrimes		if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
4161556Srgrimes		    sizeof(hd->c_filesize), OCT)) {
4171556Srgrimes#		else
4181556Srgrimes		if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
4191556Srgrimes		    sizeof(hd->c_filesize), OCT)) {
4201556Srgrimes#		endif
42176017Skris			paxwarn(1,"File is too large for cpio format %s",
4221556Srgrimes			    arcn->org_name);
4231556Srgrimes			return(1);
4241556Srgrimes		}
4251556Srgrimes		break;
4261556Srgrimes	case PAX_SLK:
4271556Srgrimes		/*
4281556Srgrimes		 * set data size to hold link name
4291556Srgrimes		 */
4301556Srgrimes		if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
4311556Srgrimes		    sizeof(hd->c_filesize), OCT))
4321556Srgrimes			goto out;
4331556Srgrimes		break;
4341556Srgrimes	default:
4351556Srgrimes		/*
4361556Srgrimes		 * all other file types have no file data
4371556Srgrimes		 */
4381556Srgrimes		if (ul_asc((u_long)0, hd->c_filesize, sizeof(hd->c_filesize),
4391556Srgrimes		     OCT))
4401556Srgrimes			goto out;
4411556Srgrimes		break;
4421556Srgrimes	}
4431556Srgrimes
4441556Srgrimes	/*
4451556Srgrimes	 * copy the values to the header using octal ascii
4461556Srgrimes	 */
4471556Srgrimes	if (ul_asc((u_long)MAGIC, hd->c_magic, sizeof(hd->c_magic), OCT) ||
4481556Srgrimes	    ul_asc((u_long)arcn->sb.st_dev, hd->c_dev, sizeof(hd->c_dev),
44976019Skris		OCT) ||
4501556Srgrimes	    ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
4511556Srgrimes		OCT) ||
4521556Srgrimes	    ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
4531556Srgrimes		OCT) ||
4541556Srgrimes	    ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
4551556Srgrimes		OCT) ||
4561556Srgrimes	    ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
4571556Srgrimes		OCT) ||
4581556Srgrimes	    ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
4591556Srgrimes		 OCT) ||
4601556Srgrimes	    ul_asc((u_long)arcn->sb.st_rdev, hd->c_rdev, sizeof(hd->c_rdev),
4611556Srgrimes		OCT) ||
4621556Srgrimes	    ul_asc((u_long)arcn->sb.st_mtime,hd->c_mtime,sizeof(hd->c_mtime),
4631556Srgrimes		OCT) ||
4641556Srgrimes	    ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), OCT))
4651556Srgrimes		goto out;
4661556Srgrimes
4671556Srgrimes	/*
4681556Srgrimes	 * write the file name to the archive
4691556Srgrimes	 */
470164699Sru	if ((wr_rdbuf((char *)&hdblk, (int)sizeof(HD_CPIO)) < 0) ||
4711556Srgrimes	    (wr_rdbuf(arcn->name, nsz) < 0)) {
47276017Skris		paxwarn(1, "Unable to write cpio header for %s", arcn->org_name);
4731556Srgrimes		return(-1);
4741556Srgrimes	}
4751556Srgrimes
4761556Srgrimes	/*
4771556Srgrimes	 * if this file has data, we are done. The caller will write the file
4781556Srgrimes	 * data, if we are link tell caller we are done, go to next file
4791556Srgrimes	 */
4801556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
4811556Srgrimes	    (arcn->type == PAX_HRG))
4821556Srgrimes		return(0);
4831556Srgrimes	if (arcn->type != PAX_SLK)
4841556Srgrimes		return(1);
4851556Srgrimes
4861556Srgrimes	/*
4871556Srgrimes	 * write the link name to the archive, tell the caller to go to the
4881556Srgrimes	 * next file as we are done.
4891556Srgrimes	 */
4901556Srgrimes	if (wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) {
49176017Skris		paxwarn(1,"Unable to write cpio link name for %s",arcn->org_name);
4921556Srgrimes		return(-1);
4931556Srgrimes	}
4941556Srgrimes	return(1);
4951556Srgrimes
4961556Srgrimes    out:
4971556Srgrimes	/*
4981556Srgrimes	 * header field is out of range
4991556Srgrimes	 */
50076017Skris	paxwarn(1, "Cpio header field is too small to store file %s",
5011556Srgrimes	    arcn->org_name);
5021556Srgrimes	return(1);
5031556Srgrimes}
5041556Srgrimes
5051556Srgrimes/*
5061556Srgrimes * Routines common to the system VR4 version of cpio (with/without file CRC)
5071556Srgrimes */
5081556Srgrimes
5091556Srgrimes/*
5101556Srgrimes * vcpio_id()
5111556Srgrimes *      determine if a block given to us is a valid system VR4 cpio header
5128855Srgrimes *	WITHOUT crc. WATCH it the magic cookies are in OCTAL, the header
5131556Srgrimes *	uses HEX
5141556Srgrimes * Return:
5151556Srgrimes *      0 if a valid header, -1 otherwise
5161556Srgrimes */
5171556Srgrimes
5181556Srgrimesint
5191556Srgrimesvcpio_id(char *blk, int size)
5201556Srgrimes{
521114469Sobrien	if ((size < (int)sizeof(HD_VCPIO)) ||
5221556Srgrimes	    (strncmp(blk, AVMAGIC, sizeof(AVMAGIC) - 1) != 0))
5231556Srgrimes		return(-1);
5241556Srgrimes	return(0);
5251556Srgrimes}
5261556Srgrimes
5271556Srgrimes/*
5281556Srgrimes * crc_id()
5291556Srgrimes *      determine if a block given to us is a valid system VR4 cpio header
5301556Srgrimes *	WITH crc. WATCH it the magic cookies are in OCTAL the header uses HEX
5311556Srgrimes * Return:
5321556Srgrimes *      0 if a valid header, -1 otherwise
5331556Srgrimes */
5341556Srgrimes
5351556Srgrimesint
5361556Srgrimescrc_id(char *blk, int size)
5371556Srgrimes{
538114469Sobrien	if ((size < (int)sizeof(HD_VCPIO)) ||
539114469Sobrien	    (strncmp(blk, AVCMAGIC, (int)sizeof(AVCMAGIC) - 1) != 0))
5401556Srgrimes		return(-1);
5411556Srgrimes	return(0);
5421556Srgrimes}
5431556Srgrimes
5441556Srgrimes/*
5451556Srgrimes * crc_strd()
5461556Srgrimes w	set file data CRC calculations. Fire up the hard link detection code
5471556Srgrimes * Return:
5481556Srgrimes *      0 if ok -1 otherwise (the return values of lnk_start())
5491556Srgrimes */
5501556Srgrimes
5511556Srgrimesint
5521556Srgrimescrc_strd(void)
5531556Srgrimes{
5541556Srgrimes	docrc = 1;
5551556Srgrimes	return(lnk_start());
5561556Srgrimes}
5571556Srgrimes
5581556Srgrimes/*
5591556Srgrimes * vcpio_rd()
5601556Srgrimes *	determine if a buffer is a system VR4 archive entry. (with/without CRC)
5611556Srgrimes *	convert and store the values in the ARCHD parameter.
5621556Srgrimes * Return:
5631556Srgrimes *	0 if a valid header, -1 otherwise.
5641556Srgrimes */
5651556Srgrimes
5661556Srgrimesint
56790113Simpvcpio_rd(ARCHD *arcn, char *buf)
5681556Srgrimes{
56990113Simp	HD_VCPIO *hd;
5701556Srgrimes	dev_t devminor;
5711556Srgrimes	dev_t devmajor;
57290113Simp	int nsz;
5731556Srgrimes
5741556Srgrimes	/*
5751556Srgrimes	 * during the id phase it was determined if we were using CRC, use the
5761556Srgrimes	 * proper id routine.
5771556Srgrimes	 */
5781556Srgrimes	if (docrc) {
5791556Srgrimes		if (crc_id(buf, sizeof(HD_VCPIO)) < 0)
5801556Srgrimes			return(-1);
5811556Srgrimes	} else {
5821556Srgrimes		if (vcpio_id(buf, sizeof(HD_VCPIO)) < 0)
5831556Srgrimes			return(-1);
5841556Srgrimes	}
5851556Srgrimes
5861556Srgrimes	hd = (HD_VCPIO *)buf;
5871556Srgrimes	arcn->pad = 0L;
5881556Srgrimes
5891556Srgrimes	/*
5901556Srgrimes	 * extract the hex ascii fields from the header
5911556Srgrimes	 */
5921556Srgrimes	arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), HEX);
5931556Srgrimes	arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), HEX);
5941556Srgrimes	arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), HEX);
5951556Srgrimes	arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), HEX);
59685617Sdillon#ifdef NET2_STAT
5971556Srgrimes	arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime,sizeof(hd->c_mtime),HEX);
59885617Sdillon#else
59985617Sdillon	arcn->sb.st_mtime = (time_t)asc_uqd(hd->c_mtime,sizeof(hd->c_mtime),HEX);
60085617Sdillon#endif
6011556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
60285617Sdillon#ifdef NET2_STAT
6031556Srgrimes	arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,
6041556Srgrimes	    sizeof(hd->c_filesize), HEX);
60585617Sdillon#else
6061556Srgrimes	arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,
6071556Srgrimes	    sizeof(hd->c_filesize), HEX);
60885617Sdillon#endif
6091556Srgrimes	arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
6101556Srgrimes	    HEX);
6111556Srgrimes	devmajor = (dev_t)asc_ul(hd->c_maj, sizeof(hd->c_maj), HEX);
6121556Srgrimes	devminor = (dev_t)asc_ul(hd->c_min, sizeof(hd->c_min), HEX);
6131556Srgrimes	arcn->sb.st_dev = TODEV(devmajor, devminor);
6141556Srgrimes	devmajor = (dev_t)asc_ul(hd->c_rmaj, sizeof(hd->c_maj), HEX);
6151556Srgrimes	devminor = (dev_t)asc_ul(hd->c_rmin, sizeof(hd->c_min), HEX);
6161556Srgrimes	arcn->sb.st_rdev = TODEV(devmajor, devminor);
6171556Srgrimes	arcn->crc = asc_ul(hd->c_chksum, sizeof(hd->c_chksum), HEX);
6181556Srgrimes
6191556Srgrimes	/*
6201556Srgrimes	 * check the length of the file name, if ok read it in, return -1 if
6211556Srgrimes	 * bogus
6221556Srgrimes	 */
6231556Srgrimes	if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),HEX)) < 2)
6241556Srgrimes		return(-1);
6251556Srgrimes	arcn->nlen = nsz - 1;
6261556Srgrimes	if (rd_nm(arcn, nsz) < 0)
6271556Srgrimes		return(-1);
6281556Srgrimes
6291556Srgrimes	/*
630222177Suqs	 * skip padding. header + filename is aligned to 4 byte boundaries
6311556Srgrimes	 */
6321556Srgrimes	if (rd_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)
6331556Srgrimes		return(-1);
6341556Srgrimes
6351556Srgrimes	/*
6361556Srgrimes	 * if not a link (or a file with no data), calculate pad size (for
6371556Srgrimes	 * padding which follows the file data), clear the link name and return
6381556Srgrimes	 */
6391556Srgrimes	if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
6401556Srgrimes		/*
6411556Srgrimes		 * we have a valid header (not a link)
6421556Srgrimes		 */
6431556Srgrimes		arcn->ln_nlen = 0;
6441556Srgrimes		arcn->ln_name[0] = '\0';
6451556Srgrimes		arcn->pad = VCPIO_PAD(arcn->sb.st_size);
6461556Srgrimes		return(com_rd(arcn));
6471556Srgrimes	}
6481556Srgrimes
6491556Srgrimes	/*
6501556Srgrimes	 * read in the link name and skip over the padding
6511556Srgrimes	 */
6521556Srgrimes	if ((rd_ln_nm(arcn) < 0) ||
6531556Srgrimes	    (rd_skip((off_t)(VCPIO_PAD(arcn->sb.st_size))) < 0))
6541556Srgrimes		return(-1);
6551556Srgrimes
6561556Srgrimes	/*
6571556Srgrimes	 * we have a valid header (with a link)
6581556Srgrimes	 */
6591556Srgrimes	return(com_rd(arcn));
6601556Srgrimes}
6611556Srgrimes
6621556Srgrimes/*
6631556Srgrimes * vcpio_endrd()
6641556Srgrimes *      no cleanup needed here, just return size of the trailer (for append)
6651556Srgrimes * Return:
6661556Srgrimes *      size of trailer header in this format
6671556Srgrimes */
6681556Srgrimes
6691556Srgrimesoff_t
6701556Srgrimesvcpio_endrd(void)
6711556Srgrimes{
6721556Srgrimes	return((off_t)(sizeof(HD_VCPIO) + sizeof(TRAILER) +
6731556Srgrimes		(VCPIO_PAD(sizeof(HD_VCPIO) + sizeof(TRAILER)))));
6741556Srgrimes}
6751556Srgrimes
6761556Srgrimes/*
6771556Srgrimes * crc_stwr()
6781556Srgrimes *	start up the device mapping table, enable crc file calculation
6791556Srgrimes * Return:
6801556Srgrimes *	0 if ok, -1 otherwise (what dev_start() returns)
6811556Srgrimes */
6821556Srgrimes
6831556Srgrimesint
6841556Srgrimescrc_stwr(void)
6851556Srgrimes{
6861556Srgrimes	docrc = 1;
6871556Srgrimes	return(dev_start());
6881556Srgrimes}
6891556Srgrimes
6901556Srgrimes/*
6911556Srgrimes * vcpio_wr()
6921556Srgrimes *	copy the data in the ARCHD to buffer in system VR4 cpio
6931556Srgrimes *	(with/without crc) format.
6941556Srgrimes * Return
6951556Srgrimes *	0 if file has data to be written after the header, 1 if file has
6961556Srgrimes *	NO data to write after the header, -1 if archive write failed
6971556Srgrimes */
6981556Srgrimes
6991556Srgrimesint
70090113Simpvcpio_wr(ARCHD *arcn)
7011556Srgrimes{
70290113Simp	HD_VCPIO *hd;
7031556Srgrimes	unsigned int nsz;
704164699Sru	HD_VCPIO hdblk;
7051556Srgrimes
7061556Srgrimes	/*
7071556Srgrimes	 * check and repair truncated device and inode fields in the cpio
7081556Srgrimes	 * header
7091556Srgrimes	 */
7101556Srgrimes	if (map_dev(arcn, (u_long)VCPIO_MASK, (u_long)VCPIO_MASK) < 0)
7111556Srgrimes		return(-1);
7121556Srgrimes	nsz = arcn->nlen + 1;
713164699Sru	hd = &hdblk;
7141556Srgrimes	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
7151556Srgrimes		arcn->sb.st_rdev = 0;
7161556Srgrimes
7171556Srgrimes	/*
7181556Srgrimes	 * add the proper magic value depending whether we were asked for
7191556Srgrimes	 * file data crc's, and the crc if needed.
7201556Srgrimes	 */
7211556Srgrimes	if (docrc) {
7221556Srgrimes		if (ul_asc((u_long)VCMAGIC, hd->c_magic, sizeof(hd->c_magic),
7231556Srgrimes	    		OCT) ||
7241556Srgrimes		    ul_asc((u_long)arcn->crc,hd->c_chksum,sizeof(hd->c_chksum),
7251556Srgrimes	    		HEX))
7261556Srgrimes			goto out;
7271556Srgrimes	} else {
7281556Srgrimes		if (ul_asc((u_long)VMAGIC, hd->c_magic, sizeof(hd->c_magic),
7291556Srgrimes	    		OCT) ||
7301556Srgrimes		    ul_asc((u_long)0L, hd->c_chksum, sizeof(hd->c_chksum),HEX))
7311556Srgrimes			goto out;
7321556Srgrimes	}
7331556Srgrimes
7341556Srgrimes	switch(arcn->type) {
7351556Srgrimes	case PAX_CTG:
7361556Srgrimes	case PAX_REG:
7371556Srgrimes	case PAX_HRG:
7381556Srgrimes		/*
7391556Srgrimes		 * caller will copy file data to the archive. tell him how
7401556Srgrimes		 * much to pad.
7411556Srgrimes		 */
7421556Srgrimes		arcn->pad = VCPIO_PAD(arcn->sb.st_size);
7431556Srgrimes#		ifdef NET2_STAT
7441556Srgrimes		if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
7451556Srgrimes		    sizeof(hd->c_filesize), HEX)) {
7461556Srgrimes#		else
7471556Srgrimes		if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
7481556Srgrimes		    sizeof(hd->c_filesize), HEX)) {
7491556Srgrimes#		endif
75076017Skris			paxwarn(1,"File is too large for sv4cpio format %s",
7511556Srgrimes			    arcn->org_name);
7521556Srgrimes			return(1);
7531556Srgrimes		}
7541556Srgrimes		break;
7551556Srgrimes	case PAX_SLK:
7561556Srgrimes		/*
7571556Srgrimes		 * no file data for the caller to process, the file data has
7581556Srgrimes		 * the size of the link
7591556Srgrimes		 */
7601556Srgrimes		arcn->pad = 0L;
7611556Srgrimes		if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
7621556Srgrimes		    sizeof(hd->c_filesize), HEX))
7631556Srgrimes			goto out;
7641556Srgrimes		break;
7651556Srgrimes	default:
7661556Srgrimes		/*
7671556Srgrimes		 * no file data for the caller to process
7681556Srgrimes		 */
7691556Srgrimes		arcn->pad = 0L;
7701556Srgrimes		if (ul_asc((u_long)0L, hd->c_filesize, sizeof(hd->c_filesize),
7711556Srgrimes		    HEX))
7721556Srgrimes			goto out;
7731556Srgrimes		break;
7741556Srgrimes	}
7751556Srgrimes
7761556Srgrimes	/*
7771556Srgrimes	 * set the other fields in the header
7781556Srgrimes	 */
7791556Srgrimes	if (ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
7801556Srgrimes		HEX) ||
7811556Srgrimes	    ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
7821556Srgrimes		HEX) ||
7831556Srgrimes	    ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
7841556Srgrimes		HEX) ||
7851556Srgrimes	    ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
7861556Srgrimes    		HEX) ||
7871556Srgrimes	    ul_asc((u_long)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime),
7881556Srgrimes    		HEX) ||
7891556Srgrimes	    ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
7901556Srgrimes    		HEX) ||
7911556Srgrimes	    ul_asc((u_long)MAJOR(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj),
7921556Srgrimes		HEX) ||
7931556Srgrimes	    ul_asc((u_long)MINOR(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min),
7941556Srgrimes		HEX) ||
7951556Srgrimes	    ul_asc((u_long)MAJOR(arcn->sb.st_rdev),hd->c_rmaj,sizeof(hd->c_maj),
7961556Srgrimes		HEX) ||
7971556Srgrimes	    ul_asc((u_long)MINOR(arcn->sb.st_rdev),hd->c_rmin,sizeof(hd->c_min),
7981556Srgrimes		HEX) ||
7991556Srgrimes	    ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), HEX))
8001556Srgrimes		goto out;
8011556Srgrimes
8021556Srgrimes	/*
8031556Srgrimes	 * write the header, the file name and padding as required.
8041556Srgrimes	 */
805164699Sru	if ((wr_rdbuf((char *)&hdblk, (int)sizeof(HD_VCPIO)) < 0) ||
8061556Srgrimes	    (wr_rdbuf(arcn->name, (int)nsz) < 0)  ||
8071556Srgrimes	    (wr_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)) {
80876017Skris		paxwarn(1,"Could not write sv4cpio header for %s",arcn->org_name);
8091556Srgrimes		return(-1);
8101556Srgrimes	}
8111556Srgrimes
8121556Srgrimes	/*
8131556Srgrimes	 * if we have file data, tell the caller we are done, copy the file
8141556Srgrimes	 */
8151556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
8161556Srgrimes	    (arcn->type == PAX_HRG))
8171556Srgrimes		return(0);
8181556Srgrimes
8191556Srgrimes	/*
8201556Srgrimes	 * if we are not a link, tell the caller we are done, go to next file
8211556Srgrimes	 */
8221556Srgrimes	if (arcn->type != PAX_SLK)
8231556Srgrimes		return(1);
8241556Srgrimes
8251556Srgrimes	/*
8261556Srgrimes	 * write the link name, tell the caller we are done.
8271556Srgrimes	 */
8281556Srgrimes	if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
8291556Srgrimes	    (wr_skip((off_t)(VCPIO_PAD(arcn->ln_nlen))) < 0)) {
83076017Skris		paxwarn(1,"Could not write sv4cpio link name for %s",
8311556Srgrimes		    arcn->org_name);
8321556Srgrimes		return(-1);
8331556Srgrimes	}
8341556Srgrimes	return(1);
8351556Srgrimes
8361556Srgrimes    out:
8371556Srgrimes	/*
8381556Srgrimes	 * header field is out of range
8391556Srgrimes	 */
84076017Skris	paxwarn(1,"Sv4cpio header field is too small for file %s",arcn->org_name);
8411556Srgrimes	return(1);
8421556Srgrimes}
8431556Srgrimes
8441556Srgrimes/*
8451556Srgrimes * Routines common to the old binary header cpio
8461556Srgrimes */
8471556Srgrimes
8481556Srgrimes/*
8491556Srgrimes * bcpio_id()
850108533Sschweikh *      determine if a block given to us is an old binary cpio header
8511556Srgrimes *	(with/without header byte swapping)
8521556Srgrimes * Return:
8531556Srgrimes *      0 if a valid header, -1 otherwise
8541556Srgrimes */
8551556Srgrimes
8561556Srgrimesint
8571556Srgrimesbcpio_id(char *blk, int size)
8581556Srgrimes{
859114469Sobrien	if (size < (int)sizeof(HD_BCPIO))
8601556Srgrimes		return(-1);
8611556Srgrimes
8621556Srgrimes	/*
8631556Srgrimes	 * check both normal and byte swapped magic cookies
8641556Srgrimes	 */
8651556Srgrimes	if (((u_short)SHRT_EXT(blk)) == MAGIC)
8661556Srgrimes		return(0);
8671556Srgrimes	if (((u_short)RSHRT_EXT(blk)) == MAGIC) {
8681556Srgrimes		if (!swp_head)
8691556Srgrimes			++swp_head;
8701556Srgrimes		return(0);
8711556Srgrimes	}
8721556Srgrimes	return(-1);
8731556Srgrimes}
8741556Srgrimes
8751556Srgrimes/*
8761556Srgrimes * bcpio_rd()
877108533Sschweikh *	determine if a buffer is an old binary archive entry. (It may have byte
8781556Srgrimes *	swapped header) convert and store the values in the ARCHD parameter.
8791556Srgrimes *	This is a very old header format and should not really be used.
8801556Srgrimes * Return:
8811556Srgrimes *	0 if a valid header, -1 otherwise.
8821556Srgrimes */
8831556Srgrimes
8841556Srgrimesint
88590113Simpbcpio_rd(ARCHD *arcn, char *buf)
8861556Srgrimes{
88790113Simp	HD_BCPIO *hd;
88890113Simp	int nsz;
8891556Srgrimes
8901556Srgrimes	/*
8911556Srgrimes	 * check the header
8921556Srgrimes	 */
8931556Srgrimes	if (bcpio_id(buf, sizeof(HD_BCPIO)) < 0)
8941556Srgrimes		return(-1);
8951556Srgrimes
8961556Srgrimes	arcn->pad = 0L;
8971556Srgrimes	hd = (HD_BCPIO *)buf;
8981556Srgrimes	if (swp_head) {
8991556Srgrimes		/*
90046684Skris		 * header has swapped bytes on 16 bit boundaries
9011556Srgrimes		 */
9021556Srgrimes		arcn->sb.st_dev = (dev_t)(RSHRT_EXT(hd->h_dev));
9031556Srgrimes		arcn->sb.st_ino = (ino_t)(RSHRT_EXT(hd->h_ino));
9041556Srgrimes		arcn->sb.st_mode = (mode_t)(RSHRT_EXT(hd->h_mode));
9051556Srgrimes		arcn->sb.st_uid = (uid_t)(RSHRT_EXT(hd->h_uid));
9061556Srgrimes		arcn->sb.st_gid = (gid_t)(RSHRT_EXT(hd->h_gid));
9071556Srgrimes		arcn->sb.st_nlink = (nlink_t)(RSHRT_EXT(hd->h_nlink));
9081556Srgrimes		arcn->sb.st_rdev = (dev_t)(RSHRT_EXT(hd->h_rdev));
9091556Srgrimes		arcn->sb.st_mtime = (time_t)(RSHRT_EXT(hd->h_mtime_1));
9101556Srgrimes		arcn->sb.st_mtime =  (arcn->sb.st_mtime << 16) |
9111556Srgrimes			((time_t)(RSHRT_EXT(hd->h_mtime_2)));
9121556Srgrimes		arcn->sb.st_size = (off_t)(RSHRT_EXT(hd->h_filesize_1));
9131556Srgrimes		arcn->sb.st_size = (arcn->sb.st_size << 16) |
9141556Srgrimes			((off_t)(RSHRT_EXT(hd->h_filesize_2)));
9151556Srgrimes		nsz = (int)(RSHRT_EXT(hd->h_namesize));
9161556Srgrimes	} else {
9171556Srgrimes		arcn->sb.st_dev = (dev_t)(SHRT_EXT(hd->h_dev));
9181556Srgrimes		arcn->sb.st_ino = (ino_t)(SHRT_EXT(hd->h_ino));
9191556Srgrimes		arcn->sb.st_mode = (mode_t)(SHRT_EXT(hd->h_mode));
9201556Srgrimes		arcn->sb.st_uid = (uid_t)(SHRT_EXT(hd->h_uid));
9211556Srgrimes		arcn->sb.st_gid = (gid_t)(SHRT_EXT(hd->h_gid));
9221556Srgrimes		arcn->sb.st_nlink = (nlink_t)(SHRT_EXT(hd->h_nlink));
9231556Srgrimes		arcn->sb.st_rdev = (dev_t)(SHRT_EXT(hd->h_rdev));
9241556Srgrimes		arcn->sb.st_mtime = (time_t)(SHRT_EXT(hd->h_mtime_1));
9251556Srgrimes		arcn->sb.st_mtime =  (arcn->sb.st_mtime << 16) |
9261556Srgrimes			((time_t)(SHRT_EXT(hd->h_mtime_2)));
9271556Srgrimes		arcn->sb.st_size = (off_t)(SHRT_EXT(hd->h_filesize_1));
9281556Srgrimes		arcn->sb.st_size = (arcn->sb.st_size << 16) |
9291556Srgrimes			((off_t)(SHRT_EXT(hd->h_filesize_2)));
9301556Srgrimes		nsz = (int)(SHRT_EXT(hd->h_namesize));
9311556Srgrimes	}
9321556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
9331556Srgrimes
9341556Srgrimes	/*
9351556Srgrimes	 * check the file name size, if bogus give up. otherwise read the file
9361556Srgrimes	 * name
9371556Srgrimes	 */
9381556Srgrimes	if (nsz < 2)
9391556Srgrimes		return(-1);
9401556Srgrimes	arcn->nlen = nsz - 1;
9411556Srgrimes	if (rd_nm(arcn, nsz) < 0)
9421556Srgrimes		return(-1);
9431556Srgrimes
9441556Srgrimes	/*
945222177Suqs	 * header + file name are aligned to 2 byte boundaries, skip if needed
9461556Srgrimes	 */
9471556Srgrimes	if (rd_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)
9481556Srgrimes		return(-1);
9491556Srgrimes
9501556Srgrimes	/*
9511556Srgrimes	 * if not a link (or a file with no data), calculate pad size (for
9521556Srgrimes	 * padding which follows the file data), clear the link name and return
9531556Srgrimes	 */
9541556Srgrimes	if (((arcn->sb.st_mode & C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)){
9551556Srgrimes		/*
9561556Srgrimes		 * we have a valid header (not a link)
9571556Srgrimes		 */
9581556Srgrimes		arcn->ln_nlen = 0;
9591556Srgrimes		arcn->ln_name[0] = '\0';
9601556Srgrimes		arcn->pad = BCPIO_PAD(arcn->sb.st_size);
9611556Srgrimes		return(com_rd(arcn));
9621556Srgrimes	}
9631556Srgrimes
9641556Srgrimes	if ((rd_ln_nm(arcn) < 0) ||
9651556Srgrimes	    (rd_skip((off_t)(BCPIO_PAD(arcn->sb.st_size))) < 0))
9661556Srgrimes		return(-1);
9671556Srgrimes
9681556Srgrimes	/*
9691556Srgrimes	 * we have a valid header (with a link)
9701556Srgrimes	 */
9711556Srgrimes	return(com_rd(arcn));
9721556Srgrimes}
9731556Srgrimes
9741556Srgrimes/*
9751556Srgrimes * bcpio_endrd()
9761556Srgrimes *      no cleanup needed here, just return size of the trailer (for append)
9771556Srgrimes * Return:
9781556Srgrimes *      size of trailer header in this format
9791556Srgrimes */
9801556Srgrimes
9811556Srgrimesoff_t
9821556Srgrimesbcpio_endrd(void)
9831556Srgrimes{
9841556Srgrimes	return((off_t)(sizeof(HD_BCPIO) + sizeof(TRAILER) +
9851556Srgrimes		(BCPIO_PAD(sizeof(HD_BCPIO) + sizeof(TRAILER)))));
9861556Srgrimes}
9871556Srgrimes
9881556Srgrimes/*
9891556Srgrimes * bcpio_wr()
9901556Srgrimes *	copy the data in the ARCHD to buffer in old binary cpio format
9911556Srgrimes *	There is a real chance of field overflow with this critter. So we
992222177Suqs *	always check that the conversion is ok. nobody in their right mind
993222177Suqs *	should write an archive in this format...
9941556Srgrimes * Return
9951556Srgrimes *      0 if file has data to be written after the header, 1 if file has NO
9961556Srgrimes *	data to write after the header, -1 if archive write failed
9971556Srgrimes */
9981556Srgrimes
9991556Srgrimesint
100090113Simpbcpio_wr(ARCHD *arcn)
10011556Srgrimes{
100290113Simp	HD_BCPIO *hd;
100390113Simp	int nsz;
1004164699Sru	HD_BCPIO hdblk;
10051556Srgrimes	off_t t_offt;
10061556Srgrimes	int t_int;
10071556Srgrimes	time_t t_timet;
10081556Srgrimes
10091556Srgrimes	/*
10101556Srgrimes	 * check and repair truncated device and inode fields in the cpio
10111556Srgrimes	 * header
10121556Srgrimes	 */
10131556Srgrimes	if (map_dev(arcn, (u_long)BCPIO_MASK, (u_long)BCPIO_MASK) < 0)
10141556Srgrimes		return(-1);
10151556Srgrimes
10161556Srgrimes	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
10171556Srgrimes		arcn->sb.st_rdev = 0;
1018164699Sru	hd = &hdblk;
10191556Srgrimes
10201556Srgrimes	switch(arcn->type) {
10211556Srgrimes	case PAX_CTG:
10221556Srgrimes	case PAX_REG:
10231556Srgrimes	case PAX_HRG:
10241556Srgrimes		/*
10251556Srgrimes		 * caller will copy file data to the archive. tell him how
10261556Srgrimes		 * much to pad.
10271556Srgrimes		 */
10281556Srgrimes		arcn->pad = BCPIO_PAD(arcn->sb.st_size);
10291556Srgrimes		hd->h_filesize_1[0] = CHR_WR_0(arcn->sb.st_size);
10301556Srgrimes		hd->h_filesize_1[1] = CHR_WR_1(arcn->sb.st_size);
10311556Srgrimes		hd->h_filesize_2[0] = CHR_WR_2(arcn->sb.st_size);
10321556Srgrimes		hd->h_filesize_2[1] = CHR_WR_3(arcn->sb.st_size);
10331556Srgrimes		t_offt = (off_t)(SHRT_EXT(hd->h_filesize_1));
10341556Srgrimes		t_offt = (t_offt<<16) | ((off_t)(SHRT_EXT(hd->h_filesize_2)));
10351556Srgrimes		if (arcn->sb.st_size != t_offt) {
103676017Skris			paxwarn(1,"File is too large for bcpio format %s",
10371556Srgrimes			    arcn->org_name);
10381556Srgrimes			return(1);
10391556Srgrimes		}
10401556Srgrimes		break;
10411556Srgrimes	case PAX_SLK:
10421556Srgrimes		/*
10431556Srgrimes		 * no file data for the caller to process, the file data has
10441556Srgrimes		 * the size of the link
10451556Srgrimes		 */
10461556Srgrimes		arcn->pad = 0L;
10471556Srgrimes		hd->h_filesize_1[0] = CHR_WR_0(arcn->ln_nlen);
10481556Srgrimes		hd->h_filesize_1[1] = CHR_WR_1(arcn->ln_nlen);
10491556Srgrimes		hd->h_filesize_2[0] = CHR_WR_2(arcn->ln_nlen);
10501556Srgrimes		hd->h_filesize_2[1] = CHR_WR_3(arcn->ln_nlen);
10511556Srgrimes		t_int = (int)(SHRT_EXT(hd->h_filesize_1));
10521556Srgrimes		t_int = (t_int << 16) | ((int)(SHRT_EXT(hd->h_filesize_2)));
10531556Srgrimes		if (arcn->ln_nlen != t_int)
10541556Srgrimes			goto out;
10551556Srgrimes		break;
10561556Srgrimes	default:
10571556Srgrimes		/*
10581556Srgrimes		 * no file data for the caller to process
10591556Srgrimes		 */
10601556Srgrimes		arcn->pad = 0L;
10611556Srgrimes		hd->h_filesize_1[0] = (char)0;
10621556Srgrimes		hd->h_filesize_1[1] = (char)0;
10631556Srgrimes		hd->h_filesize_2[0] = (char)0;
10641556Srgrimes		hd->h_filesize_2[1] = (char)0;
10651556Srgrimes		break;
10661556Srgrimes	}
10671556Srgrimes
10681556Srgrimes	/*
10691556Srgrimes	 * build up the rest of the fields
10701556Srgrimes	 */
10711556Srgrimes	hd->h_magic[0] = CHR_WR_2(MAGIC);
10721556Srgrimes	hd->h_magic[1] = CHR_WR_3(MAGIC);
10731556Srgrimes	hd->h_dev[0] = CHR_WR_2(arcn->sb.st_dev);
10741556Srgrimes	hd->h_dev[1] = CHR_WR_3(arcn->sb.st_dev);
10751556Srgrimes	if (arcn->sb.st_dev != (dev_t)(SHRT_EXT(hd->h_dev)))
10761556Srgrimes		goto out;
10771556Srgrimes	hd->h_ino[0] = CHR_WR_2(arcn->sb.st_ino);
10781556Srgrimes	hd->h_ino[1] = CHR_WR_3(arcn->sb.st_ino);
10791556Srgrimes	if (arcn->sb.st_ino != (ino_t)(SHRT_EXT(hd->h_ino)))
10801556Srgrimes		goto out;
10811556Srgrimes	hd->h_mode[0] = CHR_WR_2(arcn->sb.st_mode);
10821556Srgrimes	hd->h_mode[1] = CHR_WR_3(arcn->sb.st_mode);
10831556Srgrimes	if (arcn->sb.st_mode != (mode_t)(SHRT_EXT(hd->h_mode)))
10841556Srgrimes		goto out;
10851556Srgrimes	hd->h_uid[0] = CHR_WR_2(arcn->sb.st_uid);
10861556Srgrimes	hd->h_uid[1] = CHR_WR_3(arcn->sb.st_uid);
10871556Srgrimes	if (arcn->sb.st_uid != (uid_t)(SHRT_EXT(hd->h_uid)))
10881556Srgrimes		goto out;
10891556Srgrimes	hd->h_gid[0] = CHR_WR_2(arcn->sb.st_gid);
10901556Srgrimes	hd->h_gid[1] = CHR_WR_3(arcn->sb.st_gid);
10911556Srgrimes	if (arcn->sb.st_gid != (gid_t)(SHRT_EXT(hd->h_gid)))
10921556Srgrimes		goto out;
10931556Srgrimes	hd->h_nlink[0] = CHR_WR_2(arcn->sb.st_nlink);
10941556Srgrimes	hd->h_nlink[1] = CHR_WR_3(arcn->sb.st_nlink);
10951556Srgrimes	if (arcn->sb.st_nlink != (nlink_t)(SHRT_EXT(hd->h_nlink)))
10961556Srgrimes		goto out;
10971556Srgrimes	hd->h_rdev[0] = CHR_WR_2(arcn->sb.st_rdev);
10981556Srgrimes	hd->h_rdev[1] = CHR_WR_3(arcn->sb.st_rdev);
10991556Srgrimes	if (arcn->sb.st_rdev != (dev_t)(SHRT_EXT(hd->h_rdev)))
11001556Srgrimes		goto out;
11011556Srgrimes	hd->h_mtime_1[0] = CHR_WR_0(arcn->sb.st_mtime);
11021556Srgrimes	hd->h_mtime_1[1] = CHR_WR_1(arcn->sb.st_mtime);
11031556Srgrimes	hd->h_mtime_2[0] = CHR_WR_2(arcn->sb.st_mtime);
11041556Srgrimes	hd->h_mtime_2[1] = CHR_WR_3(arcn->sb.st_mtime);
11051556Srgrimes	t_timet = (time_t)(SHRT_EXT(hd->h_mtime_1));
11061556Srgrimes	t_timet =  (t_timet << 16) | ((time_t)(SHRT_EXT(hd->h_mtime_2)));
11071556Srgrimes	if (arcn->sb.st_mtime != t_timet)
11081556Srgrimes		goto out;
11091556Srgrimes	nsz = arcn->nlen + 1;
11101556Srgrimes	hd->h_namesize[0] = CHR_WR_2(nsz);
11111556Srgrimes	hd->h_namesize[1] = CHR_WR_3(nsz);
11121556Srgrimes	if (nsz != (int)(SHRT_EXT(hd->h_namesize)))
11131556Srgrimes		goto out;
11141556Srgrimes
11151556Srgrimes	/*
11161556Srgrimes	 * write the header, the file name and padding as required.
11171556Srgrimes	 */
1118164699Sru	if ((wr_rdbuf((char *)&hdblk, (int)sizeof(HD_BCPIO)) < 0) ||
11191556Srgrimes	    (wr_rdbuf(arcn->name, nsz) < 0) ||
11201556Srgrimes	    (wr_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)) {
112176017Skris		paxwarn(1, "Could not write bcpio header for %s", arcn->org_name);
11221556Srgrimes		return(-1);
11231556Srgrimes	}
11241556Srgrimes
11251556Srgrimes	/*
11261556Srgrimes	 * if we have file data, tell the caller we are done
11271556Srgrimes	 */
11281556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
11291556Srgrimes	    (arcn->type == PAX_HRG))
11301556Srgrimes		return(0);
11311556Srgrimes
11321556Srgrimes	/*
11331556Srgrimes	 * if we are not a link, tell the caller we are done, go to next file
11341556Srgrimes	 */
11351556Srgrimes	if (arcn->type != PAX_SLK)
11361556Srgrimes		return(1);
11371556Srgrimes
11381556Srgrimes	/*
11391556Srgrimes	 * write the link name, tell the caller we are done.
11401556Srgrimes	 */
11411556Srgrimes	if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
11421556Srgrimes	    (wr_skip((off_t)(BCPIO_PAD(arcn->ln_nlen))) < 0)) {
114376017Skris		paxwarn(1,"Could not write bcpio link name for %s",arcn->org_name);
11441556Srgrimes		return(-1);
11451556Srgrimes	}
11461556Srgrimes	return(1);
11471556Srgrimes
11481556Srgrimes    out:
11491556Srgrimes	/*
11501556Srgrimes	 * header field is out of range
11511556Srgrimes	 */
115276017Skris	paxwarn(1,"Bcpio header field is too small for file %s", arcn->org_name);
11531556Srgrimes	return(1);
11541556Srgrimes}
1155