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 "pax.h"
491556Srgrimes#include "cpio.h"
501556Srgrimes#include "extern.h"
511556Srgrimes
5290113Simpstatic int rd_nm(ARCHD *, int);
5390113Simpstatic int rd_ln_nm(ARCHD *);
5490113Simpstatic int com_rd(ARCHD *);
551556Srgrimes
561556Srgrimes/*
571556Srgrimes * Routines which support the different cpio versions
581556Srgrimes */
591556Srgrimes
601556Srgrimesstatic int swp_head;		/* binary cpio header byte swap */
611556Srgrimes
621556Srgrimes/*
631556Srgrimes * Routines common to all versions of cpio
641556Srgrimes */
651556Srgrimes
661556Srgrimes/*
671556Srgrimes * cpio_strd()
681556Srgrimes *	Fire up the hard link detection code
691556Srgrimes * Return:
701556Srgrimes *      0 if ok -1 otherwise (the return values of lnk_start())
711556Srgrimes */
721556Srgrimes
731556Srgrimesint
741556Srgrimescpio_strd(void)
751556Srgrimes{
761556Srgrimes	return(lnk_start());
771556Srgrimes}
781556Srgrimes
791556Srgrimes/*
801556Srgrimes * cpio_trail()
811556Srgrimes *	Called to determine if a header block is a valid trailer. We are
821556Srgrimes *	passed the block, the in_sync flag (which tells us we are in resync
831556Srgrimes *	mode; looking for a valid header), and cnt (which starts at zero)
841556Srgrimes *	which is used to count the number of empty blocks we have seen so far.
851556Srgrimes * Return:
868855Srgrimes *	0 if a valid trailer, -1 if not a valid trailer,
871556Srgrimes */
881556Srgrimes
891556Srgrimesint
9090113Simpcpio_trail(ARCHD *arcn)
911556Srgrimes{
921556Srgrimes	/*
931556Srgrimes	 * look for trailer id in file we are about to process
941556Srgrimes	 */
951556Srgrimes	if ((strcmp(arcn->name, TRAILER) == 0) && (arcn->sb.st_size == 0))
961556Srgrimes		return(0);
971556Srgrimes	return(-1);
981556Srgrimes}
991556Srgrimes
1001556Srgrimes/*
1011556Srgrimes * com_rd()
1021556Srgrimes *	operations common to all cpio read functions.
1031556Srgrimes * Return:
1041556Srgrimes *	0
1051556Srgrimes */
1061556Srgrimes
1071556Srgrimesstatic int
10890113Simpcom_rd(ARCHD *arcn)
1091556Srgrimes{
1101556Srgrimes	arcn->skip = 0;
1111556Srgrimes	arcn->pat = NULL;
1121556Srgrimes	arcn->org_name = arcn->name;
1131556Srgrimes	switch(arcn->sb.st_mode & C_IFMT) {
1141556Srgrimes	case C_ISFIFO:
1151556Srgrimes		arcn->type = PAX_FIF;
1161556Srgrimes		break;
1171556Srgrimes	case C_ISDIR:
1181556Srgrimes		arcn->type = PAX_DIR;
1191556Srgrimes		break;
1201556Srgrimes	case C_ISBLK:
1211556Srgrimes		arcn->type = PAX_BLK;
1221556Srgrimes		break;
1231556Srgrimes	case C_ISCHR:
1241556Srgrimes		arcn->type = PAX_CHR;
1251556Srgrimes		break;
1261556Srgrimes	case C_ISLNK:
1271556Srgrimes		arcn->type = PAX_SLK;
1281556Srgrimes		break;
1291556Srgrimes	case C_ISOCK:
1301556Srgrimes		arcn->type = PAX_SCK;
1311556Srgrimes		break;
1321556Srgrimes	case C_ISCTG:
1331556Srgrimes	case C_ISREG:
1341556Srgrimes	default:
1351556Srgrimes		/*
1361556Srgrimes		 * we have file data, set up skip (pad is set in the format
1371556Srgrimes		 * specific sections)
1381556Srgrimes		 */
1391556Srgrimes		arcn->sb.st_mode = (arcn->sb.st_mode & 0xfff) | C_ISREG;
1401556Srgrimes		arcn->type = PAX_REG;
1411556Srgrimes		arcn->skip = arcn->sb.st_size;
1421556Srgrimes		break;
1431556Srgrimes	}
1441556Srgrimes	if (chk_lnk(arcn) < 0)
1451556Srgrimes		return(-1);
1461556Srgrimes	return(0);
1471556Srgrimes}
1481556Srgrimes
1491556Srgrimes/*
1501556Srgrimes * cpio_end_wr()
1511556Srgrimes *	write the special file with the name trailer in the proper format
1521556Srgrimes * Return:
1531556Srgrimes *	result of the write of the trailer from the cpio specific write func
1541556Srgrimes */
1551556Srgrimes
1561556Srgrimesint
1571556Srgrimescpio_endwr(void)
1581556Srgrimes{
1591556Srgrimes	ARCHD last;
1601556Srgrimes
1611556Srgrimes	/*
1621556Srgrimes	 * create a trailer request and call the proper format write function
1631556Srgrimes	 */
16476017Skris	memset(&last, 0, sizeof(last));
1651556Srgrimes	last.nlen = sizeof(TRAILER) - 1;
1661556Srgrimes	last.type = PAX_REG;
1671556Srgrimes	last.sb.st_nlink = 1;
1681556Srgrimes	(void)strcpy(last.name, TRAILER);
1691556Srgrimes	return((*frmt->wr)(&last));
1701556Srgrimes}
1711556Srgrimes
1721556Srgrimes/*
1731556Srgrimes * rd_nam()
1741556Srgrimes *	read in the file name which follows the cpio header
1751556Srgrimes * Return:
1761556Srgrimes *	0 if ok, -1 otherwise
1771556Srgrimes */
1781556Srgrimes
1791556Srgrimesstatic int
18090113Simprd_nm(ARCHD *arcn, int nsz)
1811556Srgrimes{
1821556Srgrimes	/*
1831556Srgrimes	 * do not even try bogus values
1841556Srgrimes	 */
185114469Sobrien	if ((nsz == 0) || (nsz > (int)sizeof(arcn->name))) {
18676017Skris		paxwarn(1, "Cpio file name length %d is out of range", nsz);
1871556Srgrimes		return(-1);
1881556Srgrimes	}
1891556Srgrimes
1901556Srgrimes	/*
1911556Srgrimes	 * read the name and make sure it is not empty and is \0 terminated
1921556Srgrimes	 */
1931556Srgrimes	if ((rd_wrbuf(arcn->name,nsz) != nsz) || (arcn->name[nsz-1] != '\0') ||
1941556Srgrimes	    (arcn->name[0] == '\0')) {
19576017Skris		paxwarn(1, "Cpio file name in header is corrupted");
1961556Srgrimes		return(-1);
1971556Srgrimes	}
1981556Srgrimes	return(0);
1991556Srgrimes}
2001556Srgrimes
2011556Srgrimes/*
2021556Srgrimes * rd_ln_nm()
2031556Srgrimes *	read in the link name for a file with links. The link name is stored
2041556Srgrimes *	like file data (and is NOT \0 terminated!)
2051556Srgrimes * Return:
2061556Srgrimes *	0 if ok, -1 otherwise
2071556Srgrimes */
2081556Srgrimes
2091556Srgrimesstatic int
21090113Simprd_ln_nm(ARCHD *arcn)
2111556Srgrimes{
2121556Srgrimes	/*
2131556Srgrimes	 * check the length specified for bogus values
2141556Srgrimes	 */
2151556Srgrimes	if ((arcn->sb.st_size == 0) ||
216114583Smarkm	    ((size_t)arcn->sb.st_size >= sizeof(arcn->ln_name))) {
2171556Srgrimes#		ifdef NET2_STAT
21876017Skris		paxwarn(1, "Cpio link name length is invalid: %lu",
2191556Srgrimes		    arcn->sb.st_size);
2201556Srgrimes#		else
221104548Stjr		paxwarn(1, "Cpio link name length is invalid: %ju",
222104548Stjr		    (uintmax_t)arcn->sb.st_size);
2231556Srgrimes#		endif
2241556Srgrimes		return(-1);
2251556Srgrimes	}
2261556Srgrimes
2271556Srgrimes	/*
2281556Srgrimes	 * read in the link name and \0 terminate it
2291556Srgrimes	 */
2301556Srgrimes	if (rd_wrbuf(arcn->ln_name, (int)arcn->sb.st_size) !=
2311556Srgrimes	    (int)arcn->sb.st_size) {
23276017Skris		paxwarn(1, "Cpio link name read error");
2331556Srgrimes		return(-1);
2341556Srgrimes	}
2351556Srgrimes	arcn->ln_nlen = arcn->sb.st_size;
2361556Srgrimes	arcn->ln_name[arcn->ln_nlen] = '\0';
2371556Srgrimes
2381556Srgrimes	/*
2391556Srgrimes	 * watch out for those empty link names
2401556Srgrimes	 */
2411556Srgrimes	if (arcn->ln_name[0] == '\0') {
24276017Skris		paxwarn(1, "Cpio link name is corrupt");
2431556Srgrimes		return(-1);
2441556Srgrimes	}
2451556Srgrimes	return(0);
2461556Srgrimes}
2471556Srgrimes
2481556Srgrimes/*
2491556Srgrimes * Routines common to the extended byte oriented cpio format
2501556Srgrimes */
2511556Srgrimes
2521556Srgrimes/*
2531556Srgrimes * cpio_id()
2541556Srgrimes *      determine if a block given to us is a valid extended byte oriented
2551556Srgrimes *	cpio header
2561556Srgrimes * Return:
2571556Srgrimes *      0 if a valid header, -1 otherwise
2581556Srgrimes */
2591556Srgrimes
2601556Srgrimesint
2611556Srgrimescpio_id(char *blk, int size)
2621556Srgrimes{
263114469Sobrien	if ((size < (int)sizeof(HD_CPIO)) ||
2641556Srgrimes	    (strncmp(blk, AMAGIC, sizeof(AMAGIC) - 1) != 0))
2651556Srgrimes		return(-1);
2661556Srgrimes	return(0);
2671556Srgrimes}
2681556Srgrimes
2691556Srgrimes/*
2701556Srgrimes * cpio_rd()
2711556Srgrimes *	determine if a buffer is a byte oriented extended cpio archive entry.
2721556Srgrimes *	convert and store the values in the ARCHD parameter.
2731556Srgrimes * Return:
2741556Srgrimes *	0 if a valid header, -1 otherwise.
2751556Srgrimes */
2761556Srgrimes
2771556Srgrimesint
27890113Simpcpio_rd(ARCHD *arcn, char *buf)
2791556Srgrimes{
28090113Simp	int nsz;
28190113Simp	HD_CPIO *hd;
2821556Srgrimes
2831556Srgrimes	/*
2841556Srgrimes	 * check that this is a valid header, if not return -1
2851556Srgrimes	 */
2861556Srgrimes	if (cpio_id(buf, sizeof(HD_CPIO)) < 0)
2871556Srgrimes		return(-1);
2881556Srgrimes	hd = (HD_CPIO *)buf;
2891556Srgrimes
2901556Srgrimes	/*
2911556Srgrimes	 * byte oriented cpio (posix) does not have padding! extract the octal
2921556Srgrimes	 * ascii fields from the header
2931556Srgrimes	 */
2941556Srgrimes	arcn->pad = 0L;
2951556Srgrimes	arcn->sb.st_dev = (dev_t)asc_ul(hd->c_dev, sizeof(hd->c_dev), OCT);
2961556Srgrimes	arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), OCT);
2971556Srgrimes	arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), OCT);
2981556Srgrimes	arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), OCT);
2991556Srgrimes	arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), OCT);
3001556Srgrimes	arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
3011556Srgrimes	    OCT);
3021556Srgrimes	arcn->sb.st_rdev = (dev_t)asc_ul(hd->c_rdev, sizeof(hd->c_rdev), OCT);
30385617Sdillon#ifdef NET2_STAT
3041556Srgrimes	arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime, sizeof(hd->c_mtime),
3051556Srgrimes	    OCT);
30685617Sdillon#else
30785617Sdillon	arcn->sb.st_mtime = (time_t)asc_uqd(hd->c_mtime, sizeof(hd->c_mtime),
30885617Sdillon	    OCT);
30985617Sdillon#endif
3101556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
31185617Sdillon#ifdef NET2_STAT
3121556Srgrimes	arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,sizeof(hd->c_filesize),
3131556Srgrimes	    OCT);
31485617Sdillon#else
3151556Srgrimes	arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,sizeof(hd->c_filesize),
3161556Srgrimes	    OCT);
31785617Sdillon#endif
3181556Srgrimes
3191556Srgrimes	/*
3201556Srgrimes	 * check name size and if valid, read in the name of this entry (name
3211556Srgrimes	 * follows header in the archive)
3221556Srgrimes	 */
3231556Srgrimes	if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),OCT)) < 2)
3241556Srgrimes		return(-1);
3251556Srgrimes	arcn->nlen = nsz - 1;
3261556Srgrimes	if (rd_nm(arcn, nsz) < 0)
3271556Srgrimes		return(-1);
3281556Srgrimes
3291556Srgrimes	if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
3301556Srgrimes		/*
3311556Srgrimes	 	 * no link name to read for this file
3321556Srgrimes	 	 */
3331556Srgrimes		arcn->ln_nlen = 0;
3341556Srgrimes		arcn->ln_name[0] = '\0';
3351556Srgrimes		return(com_rd(arcn));
3361556Srgrimes	}
3371556Srgrimes
3381556Srgrimes	/*
3391556Srgrimes	 * check link name size and read in the link name. Link names are
3401556Srgrimes	 * stored like file data.
3411556Srgrimes	 */
3421556Srgrimes	if (rd_ln_nm(arcn) < 0)
3431556Srgrimes		return(-1);
3441556Srgrimes
3451556Srgrimes	/*
3461556Srgrimes	 * we have a valid header (with a link)
3471556Srgrimes	 */
3481556Srgrimes	return(com_rd(arcn));
3491556Srgrimes}
3501556Srgrimes
3511556Srgrimes/*
3521556Srgrimes * cpio_endrd()
3531556Srgrimes *      no cleanup needed here, just return size of the trailer (for append)
3541556Srgrimes * Return:
3551556Srgrimes *      size of trailer header in this format
3561556Srgrimes */
3571556Srgrimes
3581556Srgrimesoff_t
3591556Srgrimescpio_endrd(void)
3601556Srgrimes{
3611556Srgrimes	return((off_t)(sizeof(HD_CPIO) + sizeof(TRAILER)));
3621556Srgrimes}
3631556Srgrimes
3641556Srgrimes/*
3651556Srgrimes * cpio_stwr()
3661556Srgrimes *	start up the device mapping table
3671556Srgrimes * Return:
3681556Srgrimes *	0 if ok, -1 otherwise (what dev_start() returns)
3691556Srgrimes */
3701556Srgrimes
3711556Srgrimesint
3721556Srgrimescpio_stwr(void)
3731556Srgrimes{
3741556Srgrimes	return(dev_start());
3751556Srgrimes}
3761556Srgrimes
3771556Srgrimes/*
3781556Srgrimes * cpio_wr()
3791556Srgrimes *	copy the data in the ARCHD to buffer in extended byte oriented cpio
3801556Srgrimes *	format.
3811556Srgrimes * Return
3821556Srgrimes *      0 if file has data to be written after the header, 1 if file has NO
3831556Srgrimes *	data to write after the header, -1 if archive write failed
3841556Srgrimes */
3851556Srgrimes
3861556Srgrimesint
38790113Simpcpio_wr(ARCHD *arcn)
3881556Srgrimes{
38990113Simp	HD_CPIO *hd;
39090113Simp	int nsz;
391164699Sru	HD_CPIO hdblk;
3921556Srgrimes
3931556Srgrimes	/*
3941556Srgrimes	 * check and repair truncated device and inode fields in the header
3951556Srgrimes	 */
3961556Srgrimes	if (map_dev(arcn, (u_long)CPIO_MASK, (u_long)CPIO_MASK) < 0)
3971556Srgrimes		return(-1);
3981556Srgrimes
3991556Srgrimes	arcn->pad = 0L;
4001556Srgrimes	nsz = arcn->nlen + 1;
401164699Sru	hd = &hdblk;
4021556Srgrimes	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
4031556Srgrimes		arcn->sb.st_rdev = 0;
4041556Srgrimes
4051556Srgrimes	switch(arcn->type) {
4061556Srgrimes	case PAX_CTG:
4071556Srgrimes	case PAX_REG:
4081556Srgrimes	case PAX_HRG:
4091556Srgrimes		/*
4101556Srgrimes		 * set data size for file data
4111556Srgrimes		 */
4121556Srgrimes#		ifdef NET2_STAT
4131556Srgrimes		if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
4141556Srgrimes		    sizeof(hd->c_filesize), OCT)) {
4151556Srgrimes#		else
4161556Srgrimes		if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
4171556Srgrimes		    sizeof(hd->c_filesize), OCT)) {
4181556Srgrimes#		endif
41976017Skris			paxwarn(1,"File is too large for cpio format %s",
4201556Srgrimes			    arcn->org_name);
4211556Srgrimes			return(1);
4221556Srgrimes		}
4231556Srgrimes		break;
4241556Srgrimes	case PAX_SLK:
4251556Srgrimes		/*
4261556Srgrimes		 * set data size to hold link name
4271556Srgrimes		 */
4281556Srgrimes		if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
4291556Srgrimes		    sizeof(hd->c_filesize), OCT))
4301556Srgrimes			goto out;
4311556Srgrimes		break;
4321556Srgrimes	default:
4331556Srgrimes		/*
4341556Srgrimes		 * all other file types have no file data
4351556Srgrimes		 */
4361556Srgrimes		if (ul_asc((u_long)0, hd->c_filesize, sizeof(hd->c_filesize),
4371556Srgrimes		     OCT))
4381556Srgrimes			goto out;
4391556Srgrimes		break;
4401556Srgrimes	}
4411556Srgrimes
4421556Srgrimes	/*
4431556Srgrimes	 * copy the values to the header using octal ascii
4441556Srgrimes	 */
4451556Srgrimes	if (ul_asc((u_long)MAGIC, hd->c_magic, sizeof(hd->c_magic), OCT) ||
4461556Srgrimes	    ul_asc((u_long)arcn->sb.st_dev, hd->c_dev, sizeof(hd->c_dev),
44776019Skris		OCT) ||
4481556Srgrimes	    ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
4491556Srgrimes		OCT) ||
4501556Srgrimes	    ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
4511556Srgrimes		OCT) ||
4521556Srgrimes	    ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
4531556Srgrimes		OCT) ||
4541556Srgrimes	    ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
4551556Srgrimes		OCT) ||
4561556Srgrimes	    ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
4571556Srgrimes		 OCT) ||
4581556Srgrimes	    ul_asc((u_long)arcn->sb.st_rdev, hd->c_rdev, sizeof(hd->c_rdev),
4591556Srgrimes		OCT) ||
4601556Srgrimes	    ul_asc((u_long)arcn->sb.st_mtime,hd->c_mtime,sizeof(hd->c_mtime),
4611556Srgrimes		OCT) ||
4621556Srgrimes	    ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), OCT))
4631556Srgrimes		goto out;
4641556Srgrimes
4651556Srgrimes	/*
4661556Srgrimes	 * write the file name to the archive
4671556Srgrimes	 */
468164699Sru	if ((wr_rdbuf((char *)&hdblk, (int)sizeof(HD_CPIO)) < 0) ||
4691556Srgrimes	    (wr_rdbuf(arcn->name, nsz) < 0)) {
47076017Skris		paxwarn(1, "Unable to write cpio header for %s", arcn->org_name);
4711556Srgrimes		return(-1);
4721556Srgrimes	}
4731556Srgrimes
4741556Srgrimes	/*
4751556Srgrimes	 * if this file has data, we are done. The caller will write the file
4761556Srgrimes	 * data, if we are link tell caller we are done, go to next file
4771556Srgrimes	 */
4781556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
4791556Srgrimes	    (arcn->type == PAX_HRG))
4801556Srgrimes		return(0);
4811556Srgrimes	if (arcn->type != PAX_SLK)
4821556Srgrimes		return(1);
4831556Srgrimes
4841556Srgrimes	/*
4851556Srgrimes	 * write the link name to the archive, tell the caller to go to the
4861556Srgrimes	 * next file as we are done.
4871556Srgrimes	 */
4881556Srgrimes	if (wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) {
48976017Skris		paxwarn(1,"Unable to write cpio link name for %s",arcn->org_name);
4901556Srgrimes		return(-1);
4911556Srgrimes	}
4921556Srgrimes	return(1);
4931556Srgrimes
4941556Srgrimes    out:
4951556Srgrimes	/*
4961556Srgrimes	 * header field is out of range
4971556Srgrimes	 */
49876017Skris	paxwarn(1, "Cpio header field is too small to store file %s",
4991556Srgrimes	    arcn->org_name);
5001556Srgrimes	return(1);
5011556Srgrimes}
5021556Srgrimes
5031556Srgrimes/*
5041556Srgrimes * Routines common to the system VR4 version of cpio (with/without file CRC)
5051556Srgrimes */
5061556Srgrimes
5071556Srgrimes/*
5081556Srgrimes * vcpio_id()
5091556Srgrimes *      determine if a block given to us is a valid system VR4 cpio header
5108855Srgrimes *	WITHOUT crc. WATCH it the magic cookies are in OCTAL, the header
5111556Srgrimes *	uses HEX
5121556Srgrimes * Return:
5131556Srgrimes *      0 if a valid header, -1 otherwise
5141556Srgrimes */
5151556Srgrimes
5161556Srgrimesint
5171556Srgrimesvcpio_id(char *blk, int size)
5181556Srgrimes{
519114469Sobrien	if ((size < (int)sizeof(HD_VCPIO)) ||
5201556Srgrimes	    (strncmp(blk, AVMAGIC, sizeof(AVMAGIC) - 1) != 0))
5211556Srgrimes		return(-1);
5221556Srgrimes	return(0);
5231556Srgrimes}
5241556Srgrimes
5251556Srgrimes/*
5261556Srgrimes * crc_id()
5271556Srgrimes *      determine if a block given to us is a valid system VR4 cpio header
5281556Srgrimes *	WITH crc. WATCH it the magic cookies are in OCTAL the header uses HEX
5291556Srgrimes * Return:
5301556Srgrimes *      0 if a valid header, -1 otherwise
5311556Srgrimes */
5321556Srgrimes
5331556Srgrimesint
5341556Srgrimescrc_id(char *blk, int size)
5351556Srgrimes{
536114469Sobrien	if ((size < (int)sizeof(HD_VCPIO)) ||
537114469Sobrien	    (strncmp(blk, AVCMAGIC, (int)sizeof(AVCMAGIC) - 1) != 0))
5381556Srgrimes		return(-1);
5391556Srgrimes	return(0);
5401556Srgrimes}
5411556Srgrimes
5421556Srgrimes/*
5431556Srgrimes * crc_strd()
5441556Srgrimes w	set file data CRC calculations. Fire up the hard link detection code
5451556Srgrimes * Return:
5461556Srgrimes *      0 if ok -1 otherwise (the return values of lnk_start())
5471556Srgrimes */
5481556Srgrimes
5491556Srgrimesint
5501556Srgrimescrc_strd(void)
5511556Srgrimes{
5521556Srgrimes	docrc = 1;
5531556Srgrimes	return(lnk_start());
5541556Srgrimes}
5551556Srgrimes
5561556Srgrimes/*
5571556Srgrimes * vcpio_rd()
5581556Srgrimes *	determine if a buffer is a system VR4 archive entry. (with/without CRC)
5591556Srgrimes *	convert and store the values in the ARCHD parameter.
5601556Srgrimes * Return:
5611556Srgrimes *	0 if a valid header, -1 otherwise.
5621556Srgrimes */
5631556Srgrimes
5641556Srgrimesint
56590113Simpvcpio_rd(ARCHD *arcn, char *buf)
5661556Srgrimes{
56790113Simp	HD_VCPIO *hd;
5681556Srgrimes	dev_t devminor;
5691556Srgrimes	dev_t devmajor;
57090113Simp	int nsz;
5711556Srgrimes
5721556Srgrimes	/*
5731556Srgrimes	 * during the id phase it was determined if we were using CRC, use the
5741556Srgrimes	 * proper id routine.
5751556Srgrimes	 */
5761556Srgrimes	if (docrc) {
5771556Srgrimes		if (crc_id(buf, sizeof(HD_VCPIO)) < 0)
5781556Srgrimes			return(-1);
5791556Srgrimes	} else {
5801556Srgrimes		if (vcpio_id(buf, sizeof(HD_VCPIO)) < 0)
5811556Srgrimes			return(-1);
5821556Srgrimes	}
5831556Srgrimes
5841556Srgrimes	hd = (HD_VCPIO *)buf;
5851556Srgrimes	arcn->pad = 0L;
5861556Srgrimes
5871556Srgrimes	/*
5881556Srgrimes	 * extract the hex ascii fields from the header
5891556Srgrimes	 */
5901556Srgrimes	arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), HEX);
5911556Srgrimes	arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), HEX);
5921556Srgrimes	arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), HEX);
5931556Srgrimes	arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), HEX);
59485617Sdillon#ifdef NET2_STAT
5951556Srgrimes	arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime,sizeof(hd->c_mtime),HEX);
59685617Sdillon#else
59785617Sdillon	arcn->sb.st_mtime = (time_t)asc_uqd(hd->c_mtime,sizeof(hd->c_mtime),HEX);
59885617Sdillon#endif
5991556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
60085617Sdillon#ifdef NET2_STAT
6011556Srgrimes	arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,
6021556Srgrimes	    sizeof(hd->c_filesize), HEX);
60385617Sdillon#else
6041556Srgrimes	arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,
6051556Srgrimes	    sizeof(hd->c_filesize), HEX);
60685617Sdillon#endif
6071556Srgrimes	arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
6081556Srgrimes	    HEX);
6091556Srgrimes	devmajor = (dev_t)asc_ul(hd->c_maj, sizeof(hd->c_maj), HEX);
6101556Srgrimes	devminor = (dev_t)asc_ul(hd->c_min, sizeof(hd->c_min), HEX);
6111556Srgrimes	arcn->sb.st_dev = TODEV(devmajor, devminor);
6121556Srgrimes	devmajor = (dev_t)asc_ul(hd->c_rmaj, sizeof(hd->c_maj), HEX);
6131556Srgrimes	devminor = (dev_t)asc_ul(hd->c_rmin, sizeof(hd->c_min), HEX);
6141556Srgrimes	arcn->sb.st_rdev = TODEV(devmajor, devminor);
6151556Srgrimes	arcn->crc = asc_ul(hd->c_chksum, sizeof(hd->c_chksum), HEX);
6161556Srgrimes
6171556Srgrimes	/*
6181556Srgrimes	 * check the length of the file name, if ok read it in, return -1 if
6191556Srgrimes	 * bogus
6201556Srgrimes	 */
6211556Srgrimes	if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),HEX)) < 2)
6221556Srgrimes		return(-1);
6231556Srgrimes	arcn->nlen = nsz - 1;
6241556Srgrimes	if (rd_nm(arcn, nsz) < 0)
6251556Srgrimes		return(-1);
6261556Srgrimes
6271556Srgrimes	/*
628222177Suqs	 * skip padding. header + filename is aligned to 4 byte boundaries
6291556Srgrimes	 */
6301556Srgrimes	if (rd_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)
6311556Srgrimes		return(-1);
6321556Srgrimes
6331556Srgrimes	/*
6341556Srgrimes	 * if not a link (or a file with no data), calculate pad size (for
6351556Srgrimes	 * padding which follows the file data), clear the link name and return
6361556Srgrimes	 */
6371556Srgrimes	if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
6381556Srgrimes		/*
6391556Srgrimes		 * we have a valid header (not a link)
6401556Srgrimes		 */
6411556Srgrimes		arcn->ln_nlen = 0;
6421556Srgrimes		arcn->ln_name[0] = '\0';
6431556Srgrimes		arcn->pad = VCPIO_PAD(arcn->sb.st_size);
6441556Srgrimes		return(com_rd(arcn));
6451556Srgrimes	}
6461556Srgrimes
6471556Srgrimes	/*
6481556Srgrimes	 * read in the link name and skip over the padding
6491556Srgrimes	 */
6501556Srgrimes	if ((rd_ln_nm(arcn) < 0) ||
6511556Srgrimes	    (rd_skip((off_t)(VCPIO_PAD(arcn->sb.st_size))) < 0))
6521556Srgrimes		return(-1);
6531556Srgrimes
6541556Srgrimes	/*
6551556Srgrimes	 * we have a valid header (with a link)
6561556Srgrimes	 */
6571556Srgrimes	return(com_rd(arcn));
6581556Srgrimes}
6591556Srgrimes
6601556Srgrimes/*
6611556Srgrimes * vcpio_endrd()
6621556Srgrimes *      no cleanup needed here, just return size of the trailer (for append)
6631556Srgrimes * Return:
6641556Srgrimes *      size of trailer header in this format
6651556Srgrimes */
6661556Srgrimes
6671556Srgrimesoff_t
6681556Srgrimesvcpio_endrd(void)
6691556Srgrimes{
6701556Srgrimes	return((off_t)(sizeof(HD_VCPIO) + sizeof(TRAILER) +
6711556Srgrimes		(VCPIO_PAD(sizeof(HD_VCPIO) + sizeof(TRAILER)))));
6721556Srgrimes}
6731556Srgrimes
6741556Srgrimes/*
6751556Srgrimes * crc_stwr()
6761556Srgrimes *	start up the device mapping table, enable crc file calculation
6771556Srgrimes * Return:
6781556Srgrimes *	0 if ok, -1 otherwise (what dev_start() returns)
6791556Srgrimes */
6801556Srgrimes
6811556Srgrimesint
6821556Srgrimescrc_stwr(void)
6831556Srgrimes{
6841556Srgrimes	docrc = 1;
6851556Srgrimes	return(dev_start());
6861556Srgrimes}
6871556Srgrimes
6881556Srgrimes/*
6891556Srgrimes * vcpio_wr()
6901556Srgrimes *	copy the data in the ARCHD to buffer in system VR4 cpio
6911556Srgrimes *	(with/without crc) format.
6921556Srgrimes * Return
6931556Srgrimes *	0 if file has data to be written after the header, 1 if file has
6941556Srgrimes *	NO data to write after the header, -1 if archive write failed
6951556Srgrimes */
6961556Srgrimes
6971556Srgrimesint
69890113Simpvcpio_wr(ARCHD *arcn)
6991556Srgrimes{
70090113Simp	HD_VCPIO *hd;
7011556Srgrimes	unsigned int nsz;
702164699Sru	HD_VCPIO hdblk;
7031556Srgrimes
7041556Srgrimes	/*
7051556Srgrimes	 * check and repair truncated device and inode fields in the cpio
7061556Srgrimes	 * header
7071556Srgrimes	 */
7081556Srgrimes	if (map_dev(arcn, (u_long)VCPIO_MASK, (u_long)VCPIO_MASK) < 0)
7091556Srgrimes		return(-1);
7101556Srgrimes	nsz = arcn->nlen + 1;
711164699Sru	hd = &hdblk;
7121556Srgrimes	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
7131556Srgrimes		arcn->sb.st_rdev = 0;
7141556Srgrimes
7151556Srgrimes	/*
7161556Srgrimes	 * add the proper magic value depending whether we were asked for
7171556Srgrimes	 * file data crc's, and the crc if needed.
7181556Srgrimes	 */
7191556Srgrimes	if (docrc) {
7201556Srgrimes		if (ul_asc((u_long)VCMAGIC, hd->c_magic, sizeof(hd->c_magic),
7211556Srgrimes	    		OCT) ||
7221556Srgrimes		    ul_asc((u_long)arcn->crc,hd->c_chksum,sizeof(hd->c_chksum),
7231556Srgrimes	    		HEX))
7241556Srgrimes			goto out;
7251556Srgrimes	} else {
7261556Srgrimes		if (ul_asc((u_long)VMAGIC, hd->c_magic, sizeof(hd->c_magic),
7271556Srgrimes	    		OCT) ||
7281556Srgrimes		    ul_asc((u_long)0L, hd->c_chksum, sizeof(hd->c_chksum),HEX))
7291556Srgrimes			goto out;
7301556Srgrimes	}
7311556Srgrimes
7321556Srgrimes	switch(arcn->type) {
7331556Srgrimes	case PAX_CTG:
7341556Srgrimes	case PAX_REG:
7351556Srgrimes	case PAX_HRG:
7361556Srgrimes		/*
7371556Srgrimes		 * caller will copy file data to the archive. tell him how
7381556Srgrimes		 * much to pad.
7391556Srgrimes		 */
7401556Srgrimes		arcn->pad = VCPIO_PAD(arcn->sb.st_size);
7411556Srgrimes#		ifdef NET2_STAT
7421556Srgrimes		if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
7431556Srgrimes		    sizeof(hd->c_filesize), HEX)) {
7441556Srgrimes#		else
7451556Srgrimes		if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
7461556Srgrimes		    sizeof(hd->c_filesize), HEX)) {
7471556Srgrimes#		endif
74876017Skris			paxwarn(1,"File is too large for sv4cpio format %s",
7491556Srgrimes			    arcn->org_name);
7501556Srgrimes			return(1);
7511556Srgrimes		}
7521556Srgrimes		break;
7531556Srgrimes	case PAX_SLK:
7541556Srgrimes		/*
7551556Srgrimes		 * no file data for the caller to process, the file data has
7561556Srgrimes		 * the size of the link
7571556Srgrimes		 */
7581556Srgrimes		arcn->pad = 0L;
7591556Srgrimes		if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
7601556Srgrimes		    sizeof(hd->c_filesize), HEX))
7611556Srgrimes			goto out;
7621556Srgrimes		break;
7631556Srgrimes	default:
7641556Srgrimes		/*
7651556Srgrimes		 * no file data for the caller to process
7661556Srgrimes		 */
7671556Srgrimes		arcn->pad = 0L;
7681556Srgrimes		if (ul_asc((u_long)0L, hd->c_filesize, sizeof(hd->c_filesize),
7691556Srgrimes		    HEX))
7701556Srgrimes			goto out;
7711556Srgrimes		break;
7721556Srgrimes	}
7731556Srgrimes
7741556Srgrimes	/*
7751556Srgrimes	 * set the other fields in the header
7761556Srgrimes	 */
7771556Srgrimes	if (ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
7781556Srgrimes		HEX) ||
7791556Srgrimes	    ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
7801556Srgrimes		HEX) ||
7811556Srgrimes	    ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
7821556Srgrimes		HEX) ||
7831556Srgrimes	    ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
7841556Srgrimes    		HEX) ||
7851556Srgrimes	    ul_asc((u_long)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime),
7861556Srgrimes    		HEX) ||
7871556Srgrimes	    ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
7881556Srgrimes    		HEX) ||
7891556Srgrimes	    ul_asc((u_long)MAJOR(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj),
7901556Srgrimes		HEX) ||
7911556Srgrimes	    ul_asc((u_long)MINOR(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min),
7921556Srgrimes		HEX) ||
7931556Srgrimes	    ul_asc((u_long)MAJOR(arcn->sb.st_rdev),hd->c_rmaj,sizeof(hd->c_maj),
7941556Srgrimes		HEX) ||
7951556Srgrimes	    ul_asc((u_long)MINOR(arcn->sb.st_rdev),hd->c_rmin,sizeof(hd->c_min),
7961556Srgrimes		HEX) ||
7971556Srgrimes	    ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), HEX))
7981556Srgrimes		goto out;
7991556Srgrimes
8001556Srgrimes	/*
8011556Srgrimes	 * write the header, the file name and padding as required.
8021556Srgrimes	 */
803164699Sru	if ((wr_rdbuf((char *)&hdblk, (int)sizeof(HD_VCPIO)) < 0) ||
8041556Srgrimes	    (wr_rdbuf(arcn->name, (int)nsz) < 0)  ||
8051556Srgrimes	    (wr_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)) {
80676017Skris		paxwarn(1,"Could not write sv4cpio header for %s",arcn->org_name);
8071556Srgrimes		return(-1);
8081556Srgrimes	}
8091556Srgrimes
8101556Srgrimes	/*
8111556Srgrimes	 * if we have file data, tell the caller we are done, copy the file
8121556Srgrimes	 */
8131556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
8141556Srgrimes	    (arcn->type == PAX_HRG))
8151556Srgrimes		return(0);
8161556Srgrimes
8171556Srgrimes	/*
8181556Srgrimes	 * if we are not a link, tell the caller we are done, go to next file
8191556Srgrimes	 */
8201556Srgrimes	if (arcn->type != PAX_SLK)
8211556Srgrimes		return(1);
8221556Srgrimes
8231556Srgrimes	/*
8241556Srgrimes	 * write the link name, tell the caller we are done.
8251556Srgrimes	 */
8261556Srgrimes	if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
8271556Srgrimes	    (wr_skip((off_t)(VCPIO_PAD(arcn->ln_nlen))) < 0)) {
82876017Skris		paxwarn(1,"Could not write sv4cpio link name for %s",
8291556Srgrimes		    arcn->org_name);
8301556Srgrimes		return(-1);
8311556Srgrimes	}
8321556Srgrimes	return(1);
8331556Srgrimes
8341556Srgrimes    out:
8351556Srgrimes	/*
8361556Srgrimes	 * header field is out of range
8371556Srgrimes	 */
83876017Skris	paxwarn(1,"Sv4cpio header field is too small for file %s",arcn->org_name);
8391556Srgrimes	return(1);
8401556Srgrimes}
8411556Srgrimes
8421556Srgrimes/*
8431556Srgrimes * Routines common to the old binary header cpio
8441556Srgrimes */
8451556Srgrimes
8461556Srgrimes/*
8471556Srgrimes * bcpio_id()
848108533Sschweikh *      determine if a block given to us is an old binary cpio header
8491556Srgrimes *	(with/without header byte swapping)
8501556Srgrimes * Return:
8511556Srgrimes *      0 if a valid header, -1 otherwise
8521556Srgrimes */
8531556Srgrimes
8541556Srgrimesint
8551556Srgrimesbcpio_id(char *blk, int size)
8561556Srgrimes{
857114469Sobrien	if (size < (int)sizeof(HD_BCPIO))
8581556Srgrimes		return(-1);
8591556Srgrimes
8601556Srgrimes	/*
8611556Srgrimes	 * check both normal and byte swapped magic cookies
8621556Srgrimes	 */
8631556Srgrimes	if (((u_short)SHRT_EXT(blk)) == MAGIC)
8641556Srgrimes		return(0);
8651556Srgrimes	if (((u_short)RSHRT_EXT(blk)) == MAGIC) {
8661556Srgrimes		if (!swp_head)
8671556Srgrimes			++swp_head;
8681556Srgrimes		return(0);
8691556Srgrimes	}
8701556Srgrimes	return(-1);
8711556Srgrimes}
8721556Srgrimes
8731556Srgrimes/*
8741556Srgrimes * bcpio_rd()
875108533Sschweikh *	determine if a buffer is an old binary archive entry. (It may have byte
8761556Srgrimes *	swapped header) convert and store the values in the ARCHD parameter.
8771556Srgrimes *	This is a very old header format and should not really be used.
8781556Srgrimes * Return:
8791556Srgrimes *	0 if a valid header, -1 otherwise.
8801556Srgrimes */
8811556Srgrimes
8821556Srgrimesint
88390113Simpbcpio_rd(ARCHD *arcn, char *buf)
8841556Srgrimes{
88590113Simp	HD_BCPIO *hd;
88690113Simp	int nsz;
8871556Srgrimes
8881556Srgrimes	/*
8891556Srgrimes	 * check the header
8901556Srgrimes	 */
8911556Srgrimes	if (bcpio_id(buf, sizeof(HD_BCPIO)) < 0)
8921556Srgrimes		return(-1);
8931556Srgrimes
8941556Srgrimes	arcn->pad = 0L;
8951556Srgrimes	hd = (HD_BCPIO *)buf;
8961556Srgrimes	if (swp_head) {
8971556Srgrimes		/*
89846684Skris		 * header has swapped bytes on 16 bit boundaries
8991556Srgrimes		 */
9001556Srgrimes		arcn->sb.st_dev = (dev_t)(RSHRT_EXT(hd->h_dev));
9011556Srgrimes		arcn->sb.st_ino = (ino_t)(RSHRT_EXT(hd->h_ino));
9021556Srgrimes		arcn->sb.st_mode = (mode_t)(RSHRT_EXT(hd->h_mode));
9031556Srgrimes		arcn->sb.st_uid = (uid_t)(RSHRT_EXT(hd->h_uid));
9041556Srgrimes		arcn->sb.st_gid = (gid_t)(RSHRT_EXT(hd->h_gid));
9051556Srgrimes		arcn->sb.st_nlink = (nlink_t)(RSHRT_EXT(hd->h_nlink));
9061556Srgrimes		arcn->sb.st_rdev = (dev_t)(RSHRT_EXT(hd->h_rdev));
9071556Srgrimes		arcn->sb.st_mtime = (time_t)(RSHRT_EXT(hd->h_mtime_1));
9081556Srgrimes		arcn->sb.st_mtime =  (arcn->sb.st_mtime << 16) |
9091556Srgrimes			((time_t)(RSHRT_EXT(hd->h_mtime_2)));
9101556Srgrimes		arcn->sb.st_size = (off_t)(RSHRT_EXT(hd->h_filesize_1));
9111556Srgrimes		arcn->sb.st_size = (arcn->sb.st_size << 16) |
9121556Srgrimes			((off_t)(RSHRT_EXT(hd->h_filesize_2)));
9131556Srgrimes		nsz = (int)(RSHRT_EXT(hd->h_namesize));
9141556Srgrimes	} else {
9151556Srgrimes		arcn->sb.st_dev = (dev_t)(SHRT_EXT(hd->h_dev));
9161556Srgrimes		arcn->sb.st_ino = (ino_t)(SHRT_EXT(hd->h_ino));
9171556Srgrimes		arcn->sb.st_mode = (mode_t)(SHRT_EXT(hd->h_mode));
9181556Srgrimes		arcn->sb.st_uid = (uid_t)(SHRT_EXT(hd->h_uid));
9191556Srgrimes		arcn->sb.st_gid = (gid_t)(SHRT_EXT(hd->h_gid));
9201556Srgrimes		arcn->sb.st_nlink = (nlink_t)(SHRT_EXT(hd->h_nlink));
9211556Srgrimes		arcn->sb.st_rdev = (dev_t)(SHRT_EXT(hd->h_rdev));
9221556Srgrimes		arcn->sb.st_mtime = (time_t)(SHRT_EXT(hd->h_mtime_1));
9231556Srgrimes		arcn->sb.st_mtime =  (arcn->sb.st_mtime << 16) |
9241556Srgrimes			((time_t)(SHRT_EXT(hd->h_mtime_2)));
9251556Srgrimes		arcn->sb.st_size = (off_t)(SHRT_EXT(hd->h_filesize_1));
9261556Srgrimes		arcn->sb.st_size = (arcn->sb.st_size << 16) |
9271556Srgrimes			((off_t)(SHRT_EXT(hd->h_filesize_2)));
9281556Srgrimes		nsz = (int)(SHRT_EXT(hd->h_namesize));
9291556Srgrimes	}
9301556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
9311556Srgrimes
9321556Srgrimes	/*
9331556Srgrimes	 * check the file name size, if bogus give up. otherwise read the file
9341556Srgrimes	 * name
9351556Srgrimes	 */
9361556Srgrimes	if (nsz < 2)
9371556Srgrimes		return(-1);
9381556Srgrimes	arcn->nlen = nsz - 1;
9391556Srgrimes	if (rd_nm(arcn, nsz) < 0)
9401556Srgrimes		return(-1);
9411556Srgrimes
9421556Srgrimes	/*
943222177Suqs	 * header + file name are aligned to 2 byte boundaries, skip if needed
9441556Srgrimes	 */
9451556Srgrimes	if (rd_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)
9461556Srgrimes		return(-1);
9471556Srgrimes
9481556Srgrimes	/*
9491556Srgrimes	 * if not a link (or a file with no data), calculate pad size (for
9501556Srgrimes	 * padding which follows the file data), clear the link name and return
9511556Srgrimes	 */
9521556Srgrimes	if (((arcn->sb.st_mode & C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)){
9531556Srgrimes		/*
9541556Srgrimes		 * we have a valid header (not a link)
9551556Srgrimes		 */
9561556Srgrimes		arcn->ln_nlen = 0;
9571556Srgrimes		arcn->ln_name[0] = '\0';
9581556Srgrimes		arcn->pad = BCPIO_PAD(arcn->sb.st_size);
9591556Srgrimes		return(com_rd(arcn));
9601556Srgrimes	}
9611556Srgrimes
9621556Srgrimes	if ((rd_ln_nm(arcn) < 0) ||
9631556Srgrimes	    (rd_skip((off_t)(BCPIO_PAD(arcn->sb.st_size))) < 0))
9641556Srgrimes		return(-1);
9651556Srgrimes
9661556Srgrimes	/*
9671556Srgrimes	 * we have a valid header (with a link)
9681556Srgrimes	 */
9691556Srgrimes	return(com_rd(arcn));
9701556Srgrimes}
9711556Srgrimes
9721556Srgrimes/*
9731556Srgrimes * bcpio_endrd()
9741556Srgrimes *      no cleanup needed here, just return size of the trailer (for append)
9751556Srgrimes * Return:
9761556Srgrimes *      size of trailer header in this format
9771556Srgrimes */
9781556Srgrimes
9791556Srgrimesoff_t
9801556Srgrimesbcpio_endrd(void)
9811556Srgrimes{
9821556Srgrimes	return((off_t)(sizeof(HD_BCPIO) + sizeof(TRAILER) +
9831556Srgrimes		(BCPIO_PAD(sizeof(HD_BCPIO) + sizeof(TRAILER)))));
9841556Srgrimes}
9851556Srgrimes
9861556Srgrimes/*
9871556Srgrimes * bcpio_wr()
9881556Srgrimes *	copy the data in the ARCHD to buffer in old binary cpio format
9891556Srgrimes *	There is a real chance of field overflow with this critter. So we
990222177Suqs *	always check that the conversion is ok. nobody in their right mind
991222177Suqs *	should write an archive in this format...
9921556Srgrimes * Return
9931556Srgrimes *      0 if file has data to be written after the header, 1 if file has NO
9941556Srgrimes *	data to write after the header, -1 if archive write failed
9951556Srgrimes */
9961556Srgrimes
9971556Srgrimesint
99890113Simpbcpio_wr(ARCHD *arcn)
9991556Srgrimes{
100090113Simp	HD_BCPIO *hd;
100190113Simp	int nsz;
1002164699Sru	HD_BCPIO hdblk;
10031556Srgrimes	off_t t_offt;
10041556Srgrimes	int t_int;
10051556Srgrimes	time_t t_timet;
10061556Srgrimes
10071556Srgrimes	/*
10081556Srgrimes	 * check and repair truncated device and inode fields in the cpio
10091556Srgrimes	 * header
10101556Srgrimes	 */
10111556Srgrimes	if (map_dev(arcn, (u_long)BCPIO_MASK, (u_long)BCPIO_MASK) < 0)
10121556Srgrimes		return(-1);
10131556Srgrimes
10141556Srgrimes	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
10151556Srgrimes		arcn->sb.st_rdev = 0;
1016164699Sru	hd = &hdblk;
10171556Srgrimes
10181556Srgrimes	switch(arcn->type) {
10191556Srgrimes	case PAX_CTG:
10201556Srgrimes	case PAX_REG:
10211556Srgrimes	case PAX_HRG:
10221556Srgrimes		/*
10231556Srgrimes		 * caller will copy file data to the archive. tell him how
10241556Srgrimes		 * much to pad.
10251556Srgrimes		 */
10261556Srgrimes		arcn->pad = BCPIO_PAD(arcn->sb.st_size);
10271556Srgrimes		hd->h_filesize_1[0] = CHR_WR_0(arcn->sb.st_size);
10281556Srgrimes		hd->h_filesize_1[1] = CHR_WR_1(arcn->sb.st_size);
10291556Srgrimes		hd->h_filesize_2[0] = CHR_WR_2(arcn->sb.st_size);
10301556Srgrimes		hd->h_filesize_2[1] = CHR_WR_3(arcn->sb.st_size);
10311556Srgrimes		t_offt = (off_t)(SHRT_EXT(hd->h_filesize_1));
10321556Srgrimes		t_offt = (t_offt<<16) | ((off_t)(SHRT_EXT(hd->h_filesize_2)));
10331556Srgrimes		if (arcn->sb.st_size != t_offt) {
103476017Skris			paxwarn(1,"File is too large for bcpio format %s",
10351556Srgrimes			    arcn->org_name);
10361556Srgrimes			return(1);
10371556Srgrimes		}
10381556Srgrimes		break;
10391556Srgrimes	case PAX_SLK:
10401556Srgrimes		/*
10411556Srgrimes		 * no file data for the caller to process, the file data has
10421556Srgrimes		 * the size of the link
10431556Srgrimes		 */
10441556Srgrimes		arcn->pad = 0L;
10451556Srgrimes		hd->h_filesize_1[0] = CHR_WR_0(arcn->ln_nlen);
10461556Srgrimes		hd->h_filesize_1[1] = CHR_WR_1(arcn->ln_nlen);
10471556Srgrimes		hd->h_filesize_2[0] = CHR_WR_2(arcn->ln_nlen);
10481556Srgrimes		hd->h_filesize_2[1] = CHR_WR_3(arcn->ln_nlen);
10491556Srgrimes		t_int = (int)(SHRT_EXT(hd->h_filesize_1));
10501556Srgrimes		t_int = (t_int << 16) | ((int)(SHRT_EXT(hd->h_filesize_2)));
10511556Srgrimes		if (arcn->ln_nlen != t_int)
10521556Srgrimes			goto out;
10531556Srgrimes		break;
10541556Srgrimes	default:
10551556Srgrimes		/*
10561556Srgrimes		 * no file data for the caller to process
10571556Srgrimes		 */
10581556Srgrimes		arcn->pad = 0L;
10591556Srgrimes		hd->h_filesize_1[0] = (char)0;
10601556Srgrimes		hd->h_filesize_1[1] = (char)0;
10611556Srgrimes		hd->h_filesize_2[0] = (char)0;
10621556Srgrimes		hd->h_filesize_2[1] = (char)0;
10631556Srgrimes		break;
10641556Srgrimes	}
10651556Srgrimes
10661556Srgrimes	/*
10671556Srgrimes	 * build up the rest of the fields
10681556Srgrimes	 */
10691556Srgrimes	hd->h_magic[0] = CHR_WR_2(MAGIC);
10701556Srgrimes	hd->h_magic[1] = CHR_WR_3(MAGIC);
10711556Srgrimes	hd->h_dev[0] = CHR_WR_2(arcn->sb.st_dev);
10721556Srgrimes	hd->h_dev[1] = CHR_WR_3(arcn->sb.st_dev);
10731556Srgrimes	if (arcn->sb.st_dev != (dev_t)(SHRT_EXT(hd->h_dev)))
10741556Srgrimes		goto out;
10751556Srgrimes	hd->h_ino[0] = CHR_WR_2(arcn->sb.st_ino);
10761556Srgrimes	hd->h_ino[1] = CHR_WR_3(arcn->sb.st_ino);
10771556Srgrimes	if (arcn->sb.st_ino != (ino_t)(SHRT_EXT(hd->h_ino)))
10781556Srgrimes		goto out;
10791556Srgrimes	hd->h_mode[0] = CHR_WR_2(arcn->sb.st_mode);
10801556Srgrimes	hd->h_mode[1] = CHR_WR_3(arcn->sb.st_mode);
10811556Srgrimes	if (arcn->sb.st_mode != (mode_t)(SHRT_EXT(hd->h_mode)))
10821556Srgrimes		goto out;
10831556Srgrimes	hd->h_uid[0] = CHR_WR_2(arcn->sb.st_uid);
10841556Srgrimes	hd->h_uid[1] = CHR_WR_3(arcn->sb.st_uid);
10851556Srgrimes	if (arcn->sb.st_uid != (uid_t)(SHRT_EXT(hd->h_uid)))
10861556Srgrimes		goto out;
10871556Srgrimes	hd->h_gid[0] = CHR_WR_2(arcn->sb.st_gid);
10881556Srgrimes	hd->h_gid[1] = CHR_WR_3(arcn->sb.st_gid);
10891556Srgrimes	if (arcn->sb.st_gid != (gid_t)(SHRT_EXT(hd->h_gid)))
10901556Srgrimes		goto out;
10911556Srgrimes	hd->h_nlink[0] = CHR_WR_2(arcn->sb.st_nlink);
10921556Srgrimes	hd->h_nlink[1] = CHR_WR_3(arcn->sb.st_nlink);
10931556Srgrimes	if (arcn->sb.st_nlink != (nlink_t)(SHRT_EXT(hd->h_nlink)))
10941556Srgrimes		goto out;
10951556Srgrimes	hd->h_rdev[0] = CHR_WR_2(arcn->sb.st_rdev);
10961556Srgrimes	hd->h_rdev[1] = CHR_WR_3(arcn->sb.st_rdev);
10971556Srgrimes	if (arcn->sb.st_rdev != (dev_t)(SHRT_EXT(hd->h_rdev)))
10981556Srgrimes		goto out;
10991556Srgrimes	hd->h_mtime_1[0] = CHR_WR_0(arcn->sb.st_mtime);
11001556Srgrimes	hd->h_mtime_1[1] = CHR_WR_1(arcn->sb.st_mtime);
11011556Srgrimes	hd->h_mtime_2[0] = CHR_WR_2(arcn->sb.st_mtime);
11021556Srgrimes	hd->h_mtime_2[1] = CHR_WR_3(arcn->sb.st_mtime);
11031556Srgrimes	t_timet = (time_t)(SHRT_EXT(hd->h_mtime_1));
11041556Srgrimes	t_timet =  (t_timet << 16) | ((time_t)(SHRT_EXT(hd->h_mtime_2)));
11051556Srgrimes	if (arcn->sb.st_mtime != t_timet)
11061556Srgrimes		goto out;
11071556Srgrimes	nsz = arcn->nlen + 1;
11081556Srgrimes	hd->h_namesize[0] = CHR_WR_2(nsz);
11091556Srgrimes	hd->h_namesize[1] = CHR_WR_3(nsz);
11101556Srgrimes	if (nsz != (int)(SHRT_EXT(hd->h_namesize)))
11111556Srgrimes		goto out;
11121556Srgrimes
11131556Srgrimes	/*
11141556Srgrimes	 * write the header, the file name and padding as required.
11151556Srgrimes	 */
1116164699Sru	if ((wr_rdbuf((char *)&hdblk, (int)sizeof(HD_BCPIO)) < 0) ||
11171556Srgrimes	    (wr_rdbuf(arcn->name, nsz) < 0) ||
11181556Srgrimes	    (wr_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)) {
111976017Skris		paxwarn(1, "Could not write bcpio header for %s", arcn->org_name);
11201556Srgrimes		return(-1);
11211556Srgrimes	}
11221556Srgrimes
11231556Srgrimes	/*
11241556Srgrimes	 * if we have file data, tell the caller we are done
11251556Srgrimes	 */
11261556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
11271556Srgrimes	    (arcn->type == PAX_HRG))
11281556Srgrimes		return(0);
11291556Srgrimes
11301556Srgrimes	/*
11311556Srgrimes	 * if we are not a link, tell the caller we are done, go to next file
11321556Srgrimes	 */
11331556Srgrimes	if (arcn->type != PAX_SLK)
11341556Srgrimes		return(1);
11351556Srgrimes
11361556Srgrimes	/*
11371556Srgrimes	 * write the link name, tell the caller we are done.
11381556Srgrimes	 */
11391556Srgrimes	if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
11401556Srgrimes	    (wr_skip((off_t)(BCPIO_PAD(arcn->ln_nlen))) < 0)) {
114176017Skris		paxwarn(1,"Could not write bcpio link name for %s",arcn->org_name);
11421556Srgrimes		return(-1);
11431556Srgrimes	}
11441556Srgrimes	return(1);
11451556Srgrimes
11461556Srgrimes    out:
11471556Srgrimes	/*
11481556Srgrimes	 * header field is out of range
11491556Srgrimes	 */
115076017Skris	paxwarn(1,"Bcpio header field is too small for file %s", arcn->org_name);
11511556Srgrimes	return(1);
11521556Srgrimes}
1153