cpio.c revision 1556
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 * 3. All advertising materials mentioning features or use of this software
181556Srgrimes *    must display the following acknowledgement:
191556Srgrimes *	This product includes software developed by the University of
201556Srgrimes *	California, Berkeley and its contributors.
211556Srgrimes * 4. Neither the name of the University nor the names of its contributors
221556Srgrimes *    may be used to endorse or promote products derived from this software
231556Srgrimes *    without specific prior written permission.
241556Srgrimes *
251556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
261556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
271556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
281556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
301556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
311556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
321556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
341556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
351556Srgrimes * SUCH DAMAGE.
361556Srgrimes */
371556Srgrimes
381556Srgrimes#ifndef lint
391556Srgrimesstatic char sccsid[] = "@(#)cpio.c	8.1 (Berkeley) 5/31/93";
401556Srgrimes#endif /* not lint */
411556Srgrimes
421556Srgrimes#include <sys/types.h>
431556Srgrimes#include <sys/time.h>
441556Srgrimes#include <sys/stat.h>
451556Srgrimes#include <sys/param.h>
461556Srgrimes#include <string.h>
471556Srgrimes#include <ctype.h>
481556Srgrimes#include <stdio.h>
491556Srgrimes#include <unistd.h>
501556Srgrimes#include <stdlib.h>
511556Srgrimes#include "pax.h"
521556Srgrimes#include "cpio.h"
531556Srgrimes#include "extern.h"
541556Srgrimes
551556Srgrimesstatic int rd_nm __P((register ARCHD *, int));
561556Srgrimesstatic int rd_ln_nm __P((register ARCHD *));
571556Srgrimesstatic int com_rd __P((register ARCHD *));
581556Srgrimes
591556Srgrimes/*
601556Srgrimes * Routines which support the different cpio versions
611556Srgrimes */
621556Srgrimes
631556Srgrimesstatic int swp_head;		/* binary cpio header byte swap */
641556Srgrimes
651556Srgrimes/*
661556Srgrimes * Routines common to all versions of cpio
671556Srgrimes */
681556Srgrimes
691556Srgrimes/*
701556Srgrimes * cpio_strd()
711556Srgrimes *	Fire up the hard link detection code
721556Srgrimes * Return:
731556Srgrimes *      0 if ok -1 otherwise (the return values of lnk_start())
741556Srgrimes */
751556Srgrimes
761556Srgrimes#if __STDC__
771556Srgrimesint
781556Srgrimescpio_strd(void)
791556Srgrimes#else
801556Srgrimesint
811556Srgrimescpio_strd()
821556Srgrimes#endif
831556Srgrimes{
841556Srgrimes	return(lnk_start());
851556Srgrimes}
861556Srgrimes
871556Srgrimes/*
881556Srgrimes * cpio_trail()
891556Srgrimes *	Called to determine if a header block is a valid trailer. We are
901556Srgrimes *	passed the block, the in_sync flag (which tells us we are in resync
911556Srgrimes *	mode; looking for a valid header), and cnt (which starts at zero)
921556Srgrimes *	which is used to count the number of empty blocks we have seen so far.
931556Srgrimes * Return:
941556Srgrimes *	0 if a valid trailer, -1 if not a valid trailer,
951556Srgrimes */
961556Srgrimes
971556Srgrimes#if __STDC__
981556Srgrimesint
991556Srgrimescpio_trail(register ARCHD *arcn)
1001556Srgrimes#else
1011556Srgrimesint
1021556Srgrimescpio_trail(arcn)
1031556Srgrimes	register ARCHD *arcn;
1041556Srgrimes#endif
1051556Srgrimes{
1061556Srgrimes	/*
1071556Srgrimes	 * look for trailer id in file we are about to process
1081556Srgrimes	 */
1091556Srgrimes	if ((strcmp(arcn->name, TRAILER) == 0) && (arcn->sb.st_size == 0))
1101556Srgrimes		return(0);
1111556Srgrimes	return(-1);
1121556Srgrimes}
1131556Srgrimes
1141556Srgrimes/*
1151556Srgrimes * com_rd()
1161556Srgrimes *	operations common to all cpio read functions.
1171556Srgrimes * Return:
1181556Srgrimes *	0
1191556Srgrimes */
1201556Srgrimes
1211556Srgrimes#if __STDC__
1221556Srgrimesstatic int
1231556Srgrimescom_rd(register ARCHD *arcn)
1241556Srgrimes#else
1251556Srgrimesstatic int
1261556Srgrimescom_rd(arcn)
1271556Srgrimes	register ARCHD *arcn;
1281556Srgrimes#endif
1291556Srgrimes{
1301556Srgrimes	arcn->skip = 0;
1311556Srgrimes	arcn->pat = NULL;
1321556Srgrimes	arcn->org_name = arcn->name;
1331556Srgrimes	switch(arcn->sb.st_mode & C_IFMT) {
1341556Srgrimes	case C_ISFIFO:
1351556Srgrimes		arcn->type = PAX_FIF;
1361556Srgrimes		break;
1371556Srgrimes	case C_ISDIR:
1381556Srgrimes		arcn->type = PAX_DIR;
1391556Srgrimes		break;
1401556Srgrimes	case C_ISBLK:
1411556Srgrimes		arcn->type = PAX_BLK;
1421556Srgrimes		break;
1431556Srgrimes	case C_ISCHR:
1441556Srgrimes		arcn->type = PAX_CHR;
1451556Srgrimes		break;
1461556Srgrimes	case C_ISLNK:
1471556Srgrimes		arcn->type = PAX_SLK;
1481556Srgrimes		break;
1491556Srgrimes	case C_ISOCK:
1501556Srgrimes		arcn->type = PAX_SCK;
1511556Srgrimes		break;
1521556Srgrimes	case C_ISCTG:
1531556Srgrimes	case C_ISREG:
1541556Srgrimes	default:
1551556Srgrimes		/*
1561556Srgrimes		 * we have file data, set up skip (pad is set in the format
1571556Srgrimes		 * specific sections)
1581556Srgrimes		 */
1591556Srgrimes		arcn->sb.st_mode = (arcn->sb.st_mode & 0xfff) | C_ISREG;
1601556Srgrimes		arcn->type = PAX_REG;
1611556Srgrimes		arcn->skip = arcn->sb.st_size;
1621556Srgrimes		break;
1631556Srgrimes	}
1641556Srgrimes	if (chk_lnk(arcn) < 0)
1651556Srgrimes		return(-1);
1661556Srgrimes	return(0);
1671556Srgrimes}
1681556Srgrimes
1691556Srgrimes/*
1701556Srgrimes * cpio_end_wr()
1711556Srgrimes *	write the special file with the name trailer in the proper format
1721556Srgrimes * Return:
1731556Srgrimes *	result of the write of the trailer from the cpio specific write func
1741556Srgrimes */
1751556Srgrimes
1761556Srgrimes#if __STDC__
1771556Srgrimesint
1781556Srgrimescpio_endwr(void)
1791556Srgrimes#else
1801556Srgrimesint
1811556Srgrimescpio_endwr()
1821556Srgrimes#endif
1831556Srgrimes{
1841556Srgrimes	ARCHD last;
1851556Srgrimes
1861556Srgrimes	/*
1871556Srgrimes	 * create a trailer request and call the proper format write function
1881556Srgrimes	 */
1891556Srgrimes	bzero((char *)&last, sizeof(last));
1901556Srgrimes	last.nlen = sizeof(TRAILER) - 1;
1911556Srgrimes	last.type = PAX_REG;
1921556Srgrimes	last.sb.st_nlink = 1;
1931556Srgrimes	(void)strcpy(last.name, TRAILER);
1941556Srgrimes	return((*frmt->wr)(&last));
1951556Srgrimes}
1961556Srgrimes
1971556Srgrimes/*
1981556Srgrimes * rd_nam()
1991556Srgrimes *	read in the file name which follows the cpio header
2001556Srgrimes * Return:
2011556Srgrimes *	0 if ok, -1 otherwise
2021556Srgrimes */
2031556Srgrimes
2041556Srgrimes#if __STDC__
2051556Srgrimesstatic int
2061556Srgrimesrd_nm(register ARCHD *arcn, int nsz)
2071556Srgrimes#else
2081556Srgrimesstatic int
2091556Srgrimesrd_nm(arcn, nsz)
2101556Srgrimes	register ARCHD *arcn;
2111556Srgrimes	int nsz;
2121556Srgrimes#endif
2131556Srgrimes{
2141556Srgrimes	/*
2151556Srgrimes	 * do not even try bogus values
2161556Srgrimes	 */
2171556Srgrimes	if ((nsz == 0) || (nsz > sizeof(arcn->name))) {
2181556Srgrimes		warn(1, "Cpio file name length %d is out of range", nsz);
2191556Srgrimes		return(-1);
2201556Srgrimes	}
2211556Srgrimes
2221556Srgrimes	/*
2231556Srgrimes	 * read the name and make sure it is not empty and is \0 terminated
2241556Srgrimes	 */
2251556Srgrimes	if ((rd_wrbuf(arcn->name,nsz) != nsz) || (arcn->name[nsz-1] != '\0') ||
2261556Srgrimes	    (arcn->name[0] == '\0')) {
2271556Srgrimes		warn(1, "Cpio file name in header is corrupted");
2281556Srgrimes		return(-1);
2291556Srgrimes	}
2301556Srgrimes	return(0);
2311556Srgrimes}
2321556Srgrimes
2331556Srgrimes/*
2341556Srgrimes * rd_ln_nm()
2351556Srgrimes *	read in the link name for a file with links. The link name is stored
2361556Srgrimes *	like file data (and is NOT \0 terminated!)
2371556Srgrimes * Return:
2381556Srgrimes *	0 if ok, -1 otherwise
2391556Srgrimes */
2401556Srgrimes
2411556Srgrimes#if __STDC__
2421556Srgrimesstatic int
2431556Srgrimesrd_ln_nm(register ARCHD *arcn)
2441556Srgrimes#else
2451556Srgrimesstatic int
2461556Srgrimesrd_ln_nm(arcn)
2471556Srgrimes	register ARCHD *arcn;
2481556Srgrimes#endif
2491556Srgrimes{
2501556Srgrimes	/*
2511556Srgrimes	 * check the length specified for bogus values
2521556Srgrimes	 */
2531556Srgrimes	if ((arcn->sb.st_size == 0) ||
2541556Srgrimes	    (arcn->sb.st_size >= sizeof(arcn->ln_name))) {
2551556Srgrimes#		ifdef NET2_STAT
2561556Srgrimes		warn(1, "Cpio link name length is invalid: %lu",
2571556Srgrimes		    arcn->sb.st_size);
2581556Srgrimes#		else
2591556Srgrimes		warn(1, "Cpio link name length is invalid: %qu",
2601556Srgrimes		    arcn->sb.st_size);
2611556Srgrimes#		endif
2621556Srgrimes		return(-1);
2631556Srgrimes	}
2641556Srgrimes
2651556Srgrimes	/*
2661556Srgrimes	 * read in the link name and \0 terminate it
2671556Srgrimes	 */
2681556Srgrimes	if (rd_wrbuf(arcn->ln_name, (int)arcn->sb.st_size) !=
2691556Srgrimes	    (int)arcn->sb.st_size) {
2701556Srgrimes		warn(1, "Cpio link name read error");
2711556Srgrimes		return(-1);
2721556Srgrimes	}
2731556Srgrimes	arcn->ln_nlen = arcn->sb.st_size;
2741556Srgrimes	arcn->ln_name[arcn->ln_nlen] = '\0';
2751556Srgrimes
2761556Srgrimes	/*
2771556Srgrimes	 * watch out for those empty link names
2781556Srgrimes	 */
2791556Srgrimes	if (arcn->ln_name[0] == '\0') {
2801556Srgrimes		warn(1, "Cpio link name is corrupt");
2811556Srgrimes		return(-1);
2821556Srgrimes	}
2831556Srgrimes	return(0);
2841556Srgrimes}
2851556Srgrimes
2861556Srgrimes/*
2871556Srgrimes * Routines common to the extended byte oriented cpio format
2881556Srgrimes */
2891556Srgrimes
2901556Srgrimes/*
2911556Srgrimes * cpio_id()
2921556Srgrimes *      determine if a block given to us is a valid extended byte oriented
2931556Srgrimes *	cpio header
2941556Srgrimes * Return:
2951556Srgrimes *      0 if a valid header, -1 otherwise
2961556Srgrimes */
2971556Srgrimes
2981556Srgrimes#if __STDC__
2991556Srgrimesint
3001556Srgrimescpio_id(char *blk, int size)
3011556Srgrimes#else
3021556Srgrimesint
3031556Srgrimescpio_id(blk, size)
3041556Srgrimes	char *blk;
3051556Srgrimes	int size;
3061556Srgrimes#endif
3071556Srgrimes{
3081556Srgrimes	if ((size < sizeof(HD_CPIO)) ||
3091556Srgrimes	    (strncmp(blk, AMAGIC, sizeof(AMAGIC) - 1) != 0))
3101556Srgrimes		return(-1);
3111556Srgrimes	return(0);
3121556Srgrimes}
3131556Srgrimes
3141556Srgrimes/*
3151556Srgrimes * cpio_rd()
3161556Srgrimes *	determine if a buffer is a byte oriented extended cpio archive entry.
3171556Srgrimes *	convert and store the values in the ARCHD parameter.
3181556Srgrimes * Return:
3191556Srgrimes *	0 if a valid header, -1 otherwise.
3201556Srgrimes */
3211556Srgrimes
3221556Srgrimes#if __STDC__
3231556Srgrimesint
3241556Srgrimescpio_rd(register ARCHD *arcn, register char *buf)
3251556Srgrimes#else
3261556Srgrimesint
3271556Srgrimescpio_rd(arcn, buf)
3281556Srgrimes	register ARCHD *arcn;
3291556Srgrimes	register char *buf;
3301556Srgrimes#endif
3311556Srgrimes{
3321556Srgrimes	register int nsz;
3331556Srgrimes	register HD_CPIO *hd;
3341556Srgrimes
3351556Srgrimes	/*
3361556Srgrimes	 * check that this is a valid header, if not return -1
3371556Srgrimes	 */
3381556Srgrimes	if (cpio_id(buf, sizeof(HD_CPIO)) < 0)
3391556Srgrimes		return(-1);
3401556Srgrimes	hd = (HD_CPIO *)buf;
3411556Srgrimes
3421556Srgrimes	/*
3431556Srgrimes	 * byte oriented cpio (posix) does not have padding! extract the octal
3441556Srgrimes	 * ascii fields from the header
3451556Srgrimes	 */
3461556Srgrimes	arcn->pad = 0L;
3471556Srgrimes	arcn->sb.st_dev = (dev_t)asc_ul(hd->c_dev, sizeof(hd->c_dev), OCT);
3481556Srgrimes	arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), OCT);
3491556Srgrimes	arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), OCT);
3501556Srgrimes	arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), OCT);
3511556Srgrimes	arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), OCT);
3521556Srgrimes	arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
3531556Srgrimes	    OCT);
3541556Srgrimes	arcn->sb.st_rdev = (dev_t)asc_ul(hd->c_rdev, sizeof(hd->c_rdev), OCT);
3551556Srgrimes	arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime, sizeof(hd->c_mtime),
3561556Srgrimes	    OCT);
3571556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
3581556Srgrimes#	ifdef NET2_STAT
3591556Srgrimes	arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,sizeof(hd->c_filesize),
3601556Srgrimes	    OCT);
3611556Srgrimes#	else
3621556Srgrimes	arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,sizeof(hd->c_filesize),
3631556Srgrimes	    OCT);
3641556Srgrimes#	endif
3651556Srgrimes
3661556Srgrimes	/*
3671556Srgrimes	 * check name size and if valid, read in the name of this entry (name
3681556Srgrimes	 * follows header in the archive)
3691556Srgrimes	 */
3701556Srgrimes	if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),OCT)) < 2)
3711556Srgrimes		return(-1);
3721556Srgrimes	arcn->nlen = nsz - 1;
3731556Srgrimes	if (rd_nm(arcn, nsz) < 0)
3741556Srgrimes		return(-1);
3751556Srgrimes
3761556Srgrimes	if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
3771556Srgrimes		/*
3781556Srgrimes	 	 * no link name to read for this file
3791556Srgrimes	 	 */
3801556Srgrimes		arcn->ln_nlen = 0;
3811556Srgrimes		arcn->ln_name[0] = '\0';
3821556Srgrimes		return(com_rd(arcn));
3831556Srgrimes	}
3841556Srgrimes
3851556Srgrimes	/*
3861556Srgrimes	 * check link name size and read in the link name. Link names are
3871556Srgrimes	 * stored like file data.
3881556Srgrimes	 */
3891556Srgrimes	if (rd_ln_nm(arcn) < 0)
3901556Srgrimes		return(-1);
3911556Srgrimes
3921556Srgrimes	/*
3931556Srgrimes	 * we have a valid header (with a link)
3941556Srgrimes	 */
3951556Srgrimes	return(com_rd(arcn));
3961556Srgrimes}
3971556Srgrimes
3981556Srgrimes/*
3991556Srgrimes * cpio_endrd()
4001556Srgrimes *      no cleanup needed here, just return size of the trailer (for append)
4011556Srgrimes * Return:
4021556Srgrimes *      size of trailer header in this format
4031556Srgrimes */
4041556Srgrimes
4051556Srgrimes#if __STDC__
4061556Srgrimesoff_t
4071556Srgrimescpio_endrd(void)
4081556Srgrimes#else
4091556Srgrimesoff_t
4101556Srgrimescpio_endrd()
4111556Srgrimes#endif
4121556Srgrimes{
4131556Srgrimes	return((off_t)(sizeof(HD_CPIO) + sizeof(TRAILER)));
4141556Srgrimes}
4151556Srgrimes
4161556Srgrimes/*
4171556Srgrimes * cpio_stwr()
4181556Srgrimes *	start up the device mapping table
4191556Srgrimes * Return:
4201556Srgrimes *	0 if ok, -1 otherwise (what dev_start() returns)
4211556Srgrimes */
4221556Srgrimes
4231556Srgrimes#if __STDC__
4241556Srgrimesint
4251556Srgrimescpio_stwr(void)
4261556Srgrimes#else
4271556Srgrimesint
4281556Srgrimescpio_stwr()
4291556Srgrimes#endif
4301556Srgrimes{
4311556Srgrimes	return(dev_start());
4321556Srgrimes}
4331556Srgrimes
4341556Srgrimes/*
4351556Srgrimes * cpio_wr()
4361556Srgrimes *	copy the data in the ARCHD to buffer in extended byte oriented cpio
4371556Srgrimes *	format.
4381556Srgrimes * Return
4391556Srgrimes *      0 if file has data to be written after the header, 1 if file has NO
4401556Srgrimes *	data to write after the header, -1 if archive write failed
4411556Srgrimes */
4421556Srgrimes
4431556Srgrimes#if __STDC__
4441556Srgrimesint
4451556Srgrimescpio_wr(register ARCHD *arcn)
4461556Srgrimes#else
4471556Srgrimesint
4481556Srgrimescpio_wr(arcn)
4491556Srgrimes	register ARCHD *arcn;
4501556Srgrimes#endif
4511556Srgrimes{
4521556Srgrimes	register HD_CPIO *hd;
4531556Srgrimes	register int nsz;
4541556Srgrimes	char hdblk[sizeof(HD_CPIO)];
4551556Srgrimes
4561556Srgrimes	/*
4571556Srgrimes	 * check and repair truncated device and inode fields in the header
4581556Srgrimes	 */
4591556Srgrimes	if (map_dev(arcn, (u_long)CPIO_MASK, (u_long)CPIO_MASK) < 0)
4601556Srgrimes		return(-1);
4611556Srgrimes
4621556Srgrimes	arcn->pad = 0L;
4631556Srgrimes	nsz = arcn->nlen + 1;
4641556Srgrimes	hd = (HD_CPIO *)hdblk;
4651556Srgrimes	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
4661556Srgrimes		arcn->sb.st_rdev = 0;
4671556Srgrimes
4681556Srgrimes	switch(arcn->type) {
4691556Srgrimes	case PAX_CTG:
4701556Srgrimes	case PAX_REG:
4711556Srgrimes	case PAX_HRG:
4721556Srgrimes		/*
4731556Srgrimes		 * set data size for file data
4741556Srgrimes		 */
4751556Srgrimes#		ifdef NET2_STAT
4761556Srgrimes		if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
4771556Srgrimes		    sizeof(hd->c_filesize), OCT)) {
4781556Srgrimes#		else
4791556Srgrimes		if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
4801556Srgrimes		    sizeof(hd->c_filesize), OCT)) {
4811556Srgrimes#		endif
4821556Srgrimes			warn(1,"File is too large for cpio format %s",
4831556Srgrimes			    arcn->org_name);
4841556Srgrimes			return(1);
4851556Srgrimes		}
4861556Srgrimes		break;
4871556Srgrimes	case PAX_SLK:
4881556Srgrimes		/*
4891556Srgrimes		 * set data size to hold link name
4901556Srgrimes		 */
4911556Srgrimes		if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
4921556Srgrimes		    sizeof(hd->c_filesize), OCT))
4931556Srgrimes			goto out;
4941556Srgrimes		break;
4951556Srgrimes	default:
4961556Srgrimes		/*
4971556Srgrimes		 * all other file types have no file data
4981556Srgrimes		 */
4991556Srgrimes		if (ul_asc((u_long)0, hd->c_filesize, sizeof(hd->c_filesize),
5001556Srgrimes		     OCT))
5011556Srgrimes			goto out;
5021556Srgrimes		break;
5031556Srgrimes	}
5041556Srgrimes
5051556Srgrimes	/*
5061556Srgrimes	 * copy the values to the header using octal ascii
5071556Srgrimes	 */
5081556Srgrimes	if (ul_asc((u_long)MAGIC, hd->c_magic, sizeof(hd->c_magic), OCT) ||
5091556Srgrimes	    ul_asc((u_long)arcn->sb.st_dev, hd->c_dev, sizeof(hd->c_dev),
5101556Srgrimes	        OCT) ||
5111556Srgrimes	    ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
5121556Srgrimes		OCT) ||
5131556Srgrimes	    ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
5141556Srgrimes		OCT) ||
5151556Srgrimes	    ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
5161556Srgrimes		OCT) ||
5171556Srgrimes	    ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
5181556Srgrimes		OCT) ||
5191556Srgrimes	    ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
5201556Srgrimes		 OCT) ||
5211556Srgrimes	    ul_asc((u_long)arcn->sb.st_rdev, hd->c_rdev, sizeof(hd->c_rdev),
5221556Srgrimes		OCT) ||
5231556Srgrimes	    ul_asc((u_long)arcn->sb.st_mtime,hd->c_mtime,sizeof(hd->c_mtime),
5241556Srgrimes		OCT) ||
5251556Srgrimes	    ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), OCT))
5261556Srgrimes		goto out;
5271556Srgrimes
5281556Srgrimes	/*
5291556Srgrimes	 * write the file name to the archive
5301556Srgrimes	 */
5311556Srgrimes	if ((wr_rdbuf(hdblk, (int)sizeof(HD_CPIO)) < 0) ||
5321556Srgrimes	    (wr_rdbuf(arcn->name, nsz) < 0)) {
5331556Srgrimes		warn(1, "Unable to write cpio header for %s", arcn->org_name);
5341556Srgrimes		return(-1);
5351556Srgrimes	}
5361556Srgrimes
5371556Srgrimes	/*
5381556Srgrimes	 * if this file has data, we are done. The caller will write the file
5391556Srgrimes	 * data, if we are link tell caller we are done, go to next file
5401556Srgrimes	 */
5411556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
5421556Srgrimes	    (arcn->type == PAX_HRG))
5431556Srgrimes		return(0);
5441556Srgrimes	if (arcn->type != PAX_SLK)
5451556Srgrimes		return(1);
5461556Srgrimes
5471556Srgrimes	/*
5481556Srgrimes	 * write the link name to the archive, tell the caller to go to the
5491556Srgrimes	 * next file as we are done.
5501556Srgrimes	 */
5511556Srgrimes	if (wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) {
5521556Srgrimes		warn(1,"Unable to write cpio link name for %s",arcn->org_name);
5531556Srgrimes		return(-1);
5541556Srgrimes	}
5551556Srgrimes	return(1);
5561556Srgrimes
5571556Srgrimes    out:
5581556Srgrimes	/*
5591556Srgrimes	 * header field is out of range
5601556Srgrimes	 */
5611556Srgrimes	warn(1, "Cpio header field is too small to store file %s",
5621556Srgrimes	    arcn->org_name);
5631556Srgrimes	return(1);
5641556Srgrimes}
5651556Srgrimes
5661556Srgrimes/*
5671556Srgrimes * Routines common to the system VR4 version of cpio (with/without file CRC)
5681556Srgrimes */
5691556Srgrimes
5701556Srgrimes/*
5711556Srgrimes * vcpio_id()
5721556Srgrimes *      determine if a block given to us is a valid system VR4 cpio header
5731556Srgrimes *	WITHOUT crc. WATCH it the magic cookies are in OCTAL, the header
5741556Srgrimes *	uses HEX
5751556Srgrimes * Return:
5761556Srgrimes *      0 if a valid header, -1 otherwise
5771556Srgrimes */
5781556Srgrimes
5791556Srgrimes#if __STDC__
5801556Srgrimesint
5811556Srgrimesvcpio_id(char *blk, int size)
5821556Srgrimes#else
5831556Srgrimesint
5841556Srgrimesvcpio_id(blk, size)
5851556Srgrimes	char *blk;
5861556Srgrimes	int size;
5871556Srgrimes#endif
5881556Srgrimes{
5891556Srgrimes	if ((size < sizeof(HD_VCPIO)) ||
5901556Srgrimes	    (strncmp(blk, AVMAGIC, sizeof(AVMAGIC) - 1) != 0))
5911556Srgrimes		return(-1);
5921556Srgrimes	return(0);
5931556Srgrimes}
5941556Srgrimes
5951556Srgrimes/*
5961556Srgrimes * crc_id()
5971556Srgrimes *      determine if a block given to us is a valid system VR4 cpio header
5981556Srgrimes *	WITH crc. WATCH it the magic cookies are in OCTAL the header uses HEX
5991556Srgrimes * Return:
6001556Srgrimes *      0 if a valid header, -1 otherwise
6011556Srgrimes */
6021556Srgrimes
6031556Srgrimes#if __STDC__
6041556Srgrimesint
6051556Srgrimescrc_id(char *blk, int size)
6061556Srgrimes#else
6071556Srgrimesint
6081556Srgrimescrc_id(blk, size)
6091556Srgrimes	char *blk;
6101556Srgrimes	int size;
6111556Srgrimes#endif
6121556Srgrimes{
6131556Srgrimes	if ((size < sizeof(HD_VCPIO)) ||
6141556Srgrimes	    (strncmp(blk, AVCMAGIC, sizeof(AVCMAGIC) - 1) != 0))
6151556Srgrimes		return(-1);
6161556Srgrimes	return(0);
6171556Srgrimes}
6181556Srgrimes
6191556Srgrimes/*
6201556Srgrimes * crc_strd()
6211556Srgrimes w	set file data CRC calculations. Fire up the hard link detection code
6221556Srgrimes * Return:
6231556Srgrimes *      0 if ok -1 otherwise (the return values of lnk_start())
6241556Srgrimes */
6251556Srgrimes
6261556Srgrimes#if __STDC__
6271556Srgrimesint
6281556Srgrimescrc_strd(void)
6291556Srgrimes#else
6301556Srgrimesint
6311556Srgrimescrc_strd()
6321556Srgrimes#endif
6331556Srgrimes{
6341556Srgrimes	docrc = 1;
6351556Srgrimes	return(lnk_start());
6361556Srgrimes}
6371556Srgrimes
6381556Srgrimes/*
6391556Srgrimes * vcpio_rd()
6401556Srgrimes *	determine if a buffer is a system VR4 archive entry. (with/without CRC)
6411556Srgrimes *	convert and store the values in the ARCHD parameter.
6421556Srgrimes * Return:
6431556Srgrimes *	0 if a valid header, -1 otherwise.
6441556Srgrimes */
6451556Srgrimes
6461556Srgrimes#if __STDC__
6471556Srgrimesint
6481556Srgrimesvcpio_rd(register ARCHD *arcn, register char *buf)
6491556Srgrimes#else
6501556Srgrimesint
6511556Srgrimesvcpio_rd(arcn, buf)
6521556Srgrimes	register ARCHD *arcn;
6531556Srgrimes	register char *buf;
6541556Srgrimes#endif
6551556Srgrimes{
6561556Srgrimes	register HD_VCPIO *hd;
6571556Srgrimes	dev_t devminor;
6581556Srgrimes	dev_t devmajor;
6591556Srgrimes	register int nsz;
6601556Srgrimes
6611556Srgrimes	/*
6621556Srgrimes	 * during the id phase it was determined if we were using CRC, use the
6631556Srgrimes	 * proper id routine.
6641556Srgrimes	 */
6651556Srgrimes	if (docrc) {
6661556Srgrimes		if (crc_id(buf, sizeof(HD_VCPIO)) < 0)
6671556Srgrimes			return(-1);
6681556Srgrimes	} else {
6691556Srgrimes		if (vcpio_id(buf, sizeof(HD_VCPIO)) < 0)
6701556Srgrimes			return(-1);
6711556Srgrimes	}
6721556Srgrimes
6731556Srgrimes	hd = (HD_VCPIO *)buf;
6741556Srgrimes	arcn->pad = 0L;
6751556Srgrimes
6761556Srgrimes	/*
6771556Srgrimes	 * extract the hex ascii fields from the header
6781556Srgrimes	 */
6791556Srgrimes	arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), HEX);
6801556Srgrimes	arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), HEX);
6811556Srgrimes	arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), HEX);
6821556Srgrimes	arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), HEX);
6831556Srgrimes	arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime,sizeof(hd->c_mtime),HEX);
6841556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
6851556Srgrimes#	ifdef NET2_STAT
6861556Srgrimes	arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,
6871556Srgrimes	    sizeof(hd->c_filesize), HEX);
6881556Srgrimes#	else
6891556Srgrimes	arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,
6901556Srgrimes	    sizeof(hd->c_filesize), HEX);
6911556Srgrimes#	endif
6921556Srgrimes	arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
6931556Srgrimes	    HEX);
6941556Srgrimes	devmajor = (dev_t)asc_ul(hd->c_maj, sizeof(hd->c_maj), HEX);
6951556Srgrimes	devminor = (dev_t)asc_ul(hd->c_min, sizeof(hd->c_min), HEX);
6961556Srgrimes	arcn->sb.st_dev = TODEV(devmajor, devminor);
6971556Srgrimes	devmajor = (dev_t)asc_ul(hd->c_rmaj, sizeof(hd->c_maj), HEX);
6981556Srgrimes	devminor = (dev_t)asc_ul(hd->c_rmin, sizeof(hd->c_min), HEX);
6991556Srgrimes	arcn->sb.st_rdev = TODEV(devmajor, devminor);
7001556Srgrimes	arcn->crc = asc_ul(hd->c_chksum, sizeof(hd->c_chksum), HEX);
7011556Srgrimes
7021556Srgrimes	/*
7031556Srgrimes	 * check the length of the file name, if ok read it in, return -1 if
7041556Srgrimes	 * bogus
7051556Srgrimes	 */
7061556Srgrimes	if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),HEX)) < 2)
7071556Srgrimes		return(-1);
7081556Srgrimes	arcn->nlen = nsz - 1;
7091556Srgrimes	if (rd_nm(arcn, nsz) < 0)
7101556Srgrimes		return(-1);
7111556Srgrimes
7121556Srgrimes	/*
7131556Srgrimes	 * skip padding. header + filename is aligned to 4 byte boundries
7141556Srgrimes	 */
7151556Srgrimes	if (rd_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)
7161556Srgrimes		return(-1);
7171556Srgrimes
7181556Srgrimes	/*
7191556Srgrimes	 * if not a link (or a file with no data), calculate pad size (for
7201556Srgrimes	 * padding which follows the file data), clear the link name and return
7211556Srgrimes	 */
7221556Srgrimes	if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
7231556Srgrimes		/*
7241556Srgrimes		 * we have a valid header (not a link)
7251556Srgrimes		 */
7261556Srgrimes		arcn->ln_nlen = 0;
7271556Srgrimes		arcn->ln_name[0] = '\0';
7281556Srgrimes		arcn->pad = VCPIO_PAD(arcn->sb.st_size);
7291556Srgrimes		return(com_rd(arcn));
7301556Srgrimes	}
7311556Srgrimes
7321556Srgrimes	/*
7331556Srgrimes	 * read in the link name and skip over the padding
7341556Srgrimes	 */
7351556Srgrimes	if ((rd_ln_nm(arcn) < 0) ||
7361556Srgrimes	    (rd_skip((off_t)(VCPIO_PAD(arcn->sb.st_size))) < 0))
7371556Srgrimes		return(-1);
7381556Srgrimes
7391556Srgrimes	/*
7401556Srgrimes	 * we have a valid header (with a link)
7411556Srgrimes	 */
7421556Srgrimes	return(com_rd(arcn));
7431556Srgrimes}
7441556Srgrimes
7451556Srgrimes/*
7461556Srgrimes * vcpio_endrd()
7471556Srgrimes *      no cleanup needed here, just return size of the trailer (for append)
7481556Srgrimes * Return:
7491556Srgrimes *      size of trailer header in this format
7501556Srgrimes */
7511556Srgrimes
7521556Srgrimes#if __STDC__
7531556Srgrimesoff_t
7541556Srgrimesvcpio_endrd(void)
7551556Srgrimes#else
7561556Srgrimesoff_t
7571556Srgrimesvcpio_endrd()
7581556Srgrimes#endif
7591556Srgrimes{
7601556Srgrimes	return((off_t)(sizeof(HD_VCPIO) + sizeof(TRAILER) +
7611556Srgrimes		(VCPIO_PAD(sizeof(HD_VCPIO) + sizeof(TRAILER)))));
7621556Srgrimes}
7631556Srgrimes
7641556Srgrimes/*
7651556Srgrimes * crc_stwr()
7661556Srgrimes *	start up the device mapping table, enable crc file calculation
7671556Srgrimes * Return:
7681556Srgrimes *	0 if ok, -1 otherwise (what dev_start() returns)
7691556Srgrimes */
7701556Srgrimes
7711556Srgrimes#if __STDC__
7721556Srgrimesint
7731556Srgrimescrc_stwr(void)
7741556Srgrimes#else
7751556Srgrimesint
7761556Srgrimescrc_stwr()
7771556Srgrimes#endif
7781556Srgrimes{
7791556Srgrimes	docrc = 1;
7801556Srgrimes	return(dev_start());
7811556Srgrimes}
7821556Srgrimes
7831556Srgrimes/*
7841556Srgrimes * vcpio_wr()
7851556Srgrimes *	copy the data in the ARCHD to buffer in system VR4 cpio
7861556Srgrimes *	(with/without crc) format.
7871556Srgrimes * Return
7881556Srgrimes *	0 if file has data to be written after the header, 1 if file has
7891556Srgrimes *	NO data to write after the header, -1 if archive write failed
7901556Srgrimes */
7911556Srgrimes
7921556Srgrimes#if __STDC__
7931556Srgrimesint
7941556Srgrimesvcpio_wr(register ARCHD *arcn)
7951556Srgrimes#else
7961556Srgrimesint
7971556Srgrimesvcpio_wr(arcn)
7981556Srgrimes	register ARCHD *arcn;
7991556Srgrimes#endif
8001556Srgrimes{
8011556Srgrimes	register HD_VCPIO *hd;
8021556Srgrimes	unsigned int nsz;
8031556Srgrimes	char hdblk[sizeof(HD_VCPIO)];
8041556Srgrimes
8051556Srgrimes	/*
8061556Srgrimes	 * check and repair truncated device and inode fields in the cpio
8071556Srgrimes	 * header
8081556Srgrimes	 */
8091556Srgrimes	if (map_dev(arcn, (u_long)VCPIO_MASK, (u_long)VCPIO_MASK) < 0)
8101556Srgrimes		return(-1);
8111556Srgrimes	nsz = arcn->nlen + 1;
8121556Srgrimes	hd = (HD_VCPIO *)hdblk;
8131556Srgrimes	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
8141556Srgrimes		arcn->sb.st_rdev = 0;
8151556Srgrimes
8161556Srgrimes	/*
8171556Srgrimes	 * add the proper magic value depending whether we were asked for
8181556Srgrimes	 * file data crc's, and the crc if needed.
8191556Srgrimes	 */
8201556Srgrimes	if (docrc) {
8211556Srgrimes		if (ul_asc((u_long)VCMAGIC, hd->c_magic, sizeof(hd->c_magic),
8221556Srgrimes	    		OCT) ||
8231556Srgrimes		    ul_asc((u_long)arcn->crc,hd->c_chksum,sizeof(hd->c_chksum),
8241556Srgrimes	    		HEX))
8251556Srgrimes			goto out;
8261556Srgrimes	} else {
8271556Srgrimes		if (ul_asc((u_long)VMAGIC, hd->c_magic, sizeof(hd->c_magic),
8281556Srgrimes	    		OCT) ||
8291556Srgrimes		    ul_asc((u_long)0L, hd->c_chksum, sizeof(hd->c_chksum),HEX))
8301556Srgrimes			goto out;
8311556Srgrimes	}
8321556Srgrimes
8331556Srgrimes	switch(arcn->type) {
8341556Srgrimes	case PAX_CTG:
8351556Srgrimes	case PAX_REG:
8361556Srgrimes	case PAX_HRG:
8371556Srgrimes		/*
8381556Srgrimes		 * caller will copy file data to the archive. tell him how
8391556Srgrimes		 * much to pad.
8401556Srgrimes		 */
8411556Srgrimes		arcn->pad = VCPIO_PAD(arcn->sb.st_size);
8421556Srgrimes#		ifdef NET2_STAT
8431556Srgrimes		if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
8441556Srgrimes		    sizeof(hd->c_filesize), HEX)) {
8451556Srgrimes#		else
8461556Srgrimes		if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
8471556Srgrimes		    sizeof(hd->c_filesize), HEX)) {
8481556Srgrimes#		endif
8491556Srgrimes			warn(1,"File is too large for sv4cpio format %s",
8501556Srgrimes			    arcn->org_name);
8511556Srgrimes			return(1);
8521556Srgrimes		}
8531556Srgrimes		break;
8541556Srgrimes	case PAX_SLK:
8551556Srgrimes		/*
8561556Srgrimes		 * no file data for the caller to process, the file data has
8571556Srgrimes		 * the size of the link
8581556Srgrimes		 */
8591556Srgrimes		arcn->pad = 0L;
8601556Srgrimes		if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
8611556Srgrimes		    sizeof(hd->c_filesize), HEX))
8621556Srgrimes			goto out;
8631556Srgrimes		break;
8641556Srgrimes	default:
8651556Srgrimes		/*
8661556Srgrimes		 * no file data for the caller to process
8671556Srgrimes		 */
8681556Srgrimes		arcn->pad = 0L;
8691556Srgrimes		if (ul_asc((u_long)0L, hd->c_filesize, sizeof(hd->c_filesize),
8701556Srgrimes		    HEX))
8711556Srgrimes			goto out;
8721556Srgrimes		break;
8731556Srgrimes	}
8741556Srgrimes
8751556Srgrimes	/*
8761556Srgrimes	 * set the other fields in the header
8771556Srgrimes	 */
8781556Srgrimes	if (ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
8791556Srgrimes		HEX) ||
8801556Srgrimes	    ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
8811556Srgrimes		HEX) ||
8821556Srgrimes	    ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
8831556Srgrimes		HEX) ||
8841556Srgrimes	    ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
8851556Srgrimes    		HEX) ||
8861556Srgrimes	    ul_asc((u_long)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime),
8871556Srgrimes    		HEX) ||
8881556Srgrimes	    ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
8891556Srgrimes    		HEX) ||
8901556Srgrimes	    ul_asc((u_long)MAJOR(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj),
8911556Srgrimes		HEX) ||
8921556Srgrimes	    ul_asc((u_long)MINOR(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min),
8931556Srgrimes		HEX) ||
8941556Srgrimes	    ul_asc((u_long)MAJOR(arcn->sb.st_rdev),hd->c_rmaj,sizeof(hd->c_maj),
8951556Srgrimes		HEX) ||
8961556Srgrimes	    ul_asc((u_long)MINOR(arcn->sb.st_rdev),hd->c_rmin,sizeof(hd->c_min),
8971556Srgrimes		HEX) ||
8981556Srgrimes	    ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), HEX))
8991556Srgrimes		goto out;
9001556Srgrimes
9011556Srgrimes	/*
9021556Srgrimes	 * write the header, the file name and padding as required.
9031556Srgrimes	 */
9041556Srgrimes	if ((wr_rdbuf(hdblk, (int)sizeof(HD_VCPIO)) < 0) ||
9051556Srgrimes	    (wr_rdbuf(arcn->name, (int)nsz) < 0)  ||
9061556Srgrimes	    (wr_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)) {
9071556Srgrimes		warn(1,"Could not write sv4cpio header for %s",arcn->org_name);
9081556Srgrimes		return(-1);
9091556Srgrimes	}
9101556Srgrimes
9111556Srgrimes	/*
9121556Srgrimes	 * if we have file data, tell the caller we are done, copy the file
9131556Srgrimes	 */
9141556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
9151556Srgrimes	    (arcn->type == PAX_HRG))
9161556Srgrimes		return(0);
9171556Srgrimes
9181556Srgrimes	/*
9191556Srgrimes	 * if we are not a link, tell the caller we are done, go to next file
9201556Srgrimes	 */
9211556Srgrimes	if (arcn->type != PAX_SLK)
9221556Srgrimes		return(1);
9231556Srgrimes
9241556Srgrimes	/*
9251556Srgrimes	 * write the link name, tell the caller we are done.
9261556Srgrimes	 */
9271556Srgrimes	if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
9281556Srgrimes	    (wr_skip((off_t)(VCPIO_PAD(arcn->ln_nlen))) < 0)) {
9291556Srgrimes		warn(1,"Could not write sv4cpio link name for %s",
9301556Srgrimes		    arcn->org_name);
9311556Srgrimes		return(-1);
9321556Srgrimes	}
9331556Srgrimes	return(1);
9341556Srgrimes
9351556Srgrimes    out:
9361556Srgrimes	/*
9371556Srgrimes	 * header field is out of range
9381556Srgrimes	 */
9391556Srgrimes	warn(1,"Sv4cpio header field is too small for file %s",arcn->org_name);
9401556Srgrimes	return(1);
9411556Srgrimes}
9421556Srgrimes
9431556Srgrimes/*
9441556Srgrimes * Routines common to the old binary header cpio
9451556Srgrimes */
9461556Srgrimes
9471556Srgrimes/*
9481556Srgrimes * bcpio_id()
9491556Srgrimes *      determine if a block given to us is a old binary cpio header
9501556Srgrimes *	(with/without header byte swapping)
9511556Srgrimes * Return:
9521556Srgrimes *      0 if a valid header, -1 otherwise
9531556Srgrimes */
9541556Srgrimes
9551556Srgrimes#if __STDC__
9561556Srgrimesint
9571556Srgrimesbcpio_id(char *blk, int size)
9581556Srgrimes#else
9591556Srgrimesint
9601556Srgrimesbcpio_id(blk, size)
9611556Srgrimes	char *blk;
9621556Srgrimes	int size;
9631556Srgrimes#endif
9641556Srgrimes{
9651556Srgrimes	if (size < sizeof(HD_BCPIO))
9661556Srgrimes		return(-1);
9671556Srgrimes
9681556Srgrimes	/*
9691556Srgrimes	 * check both normal and byte swapped magic cookies
9701556Srgrimes	 */
9711556Srgrimes	if (((u_short)SHRT_EXT(blk)) == MAGIC)
9721556Srgrimes		return(0);
9731556Srgrimes	if (((u_short)RSHRT_EXT(blk)) == MAGIC) {
9741556Srgrimes		if (!swp_head)
9751556Srgrimes			++swp_head;
9761556Srgrimes		return(0);
9771556Srgrimes	}
9781556Srgrimes	return(-1);
9791556Srgrimes}
9801556Srgrimes
9811556Srgrimes/*
9821556Srgrimes * bcpio_rd()
9831556Srgrimes *	determine if a buffer is a old binary archive entry. (it may have byte
9841556Srgrimes *	swapped header) convert and store the values in the ARCHD parameter.
9851556Srgrimes *	This is a very old header format and should not really be used.
9861556Srgrimes * Return:
9871556Srgrimes *	0 if a valid header, -1 otherwise.
9881556Srgrimes */
9891556Srgrimes
9901556Srgrimes#if __STDC__
9911556Srgrimesint
9921556Srgrimesbcpio_rd(register ARCHD *arcn, register char *buf)
9931556Srgrimes#else
9941556Srgrimesint
9951556Srgrimesbcpio_rd(arcn, buf)
9961556Srgrimes	register ARCHD *arcn;
9971556Srgrimes	register char *buf;
9981556Srgrimes#endif
9991556Srgrimes{
10001556Srgrimes	register HD_BCPIO *hd;
10011556Srgrimes	register int nsz;
10021556Srgrimes
10031556Srgrimes	/*
10041556Srgrimes	 * check the header
10051556Srgrimes	 */
10061556Srgrimes	if (bcpio_id(buf, sizeof(HD_BCPIO)) < 0)
10071556Srgrimes		return(-1);
10081556Srgrimes
10091556Srgrimes	arcn->pad = 0L;
10101556Srgrimes	hd = (HD_BCPIO *)buf;
10111556Srgrimes	if (swp_head) {
10121556Srgrimes		/*
10131556Srgrimes		 * header has swapped bytes on 16 bit boundries
10141556Srgrimes		 */
10151556Srgrimes		arcn->sb.st_dev = (dev_t)(RSHRT_EXT(hd->h_dev));
10161556Srgrimes		arcn->sb.st_ino = (ino_t)(RSHRT_EXT(hd->h_ino));
10171556Srgrimes		arcn->sb.st_mode = (mode_t)(RSHRT_EXT(hd->h_mode));
10181556Srgrimes		arcn->sb.st_uid = (uid_t)(RSHRT_EXT(hd->h_uid));
10191556Srgrimes		arcn->sb.st_gid = (gid_t)(RSHRT_EXT(hd->h_gid));
10201556Srgrimes		arcn->sb.st_nlink = (nlink_t)(RSHRT_EXT(hd->h_nlink));
10211556Srgrimes		arcn->sb.st_rdev = (dev_t)(RSHRT_EXT(hd->h_rdev));
10221556Srgrimes		arcn->sb.st_mtime = (time_t)(RSHRT_EXT(hd->h_mtime_1));
10231556Srgrimes		arcn->sb.st_mtime =  (arcn->sb.st_mtime << 16) |
10241556Srgrimes			((time_t)(RSHRT_EXT(hd->h_mtime_2)));
10251556Srgrimes		arcn->sb.st_size = (off_t)(RSHRT_EXT(hd->h_filesize_1));
10261556Srgrimes		arcn->sb.st_size = (arcn->sb.st_size << 16) |
10271556Srgrimes			((off_t)(RSHRT_EXT(hd->h_filesize_2)));
10281556Srgrimes		nsz = (int)(RSHRT_EXT(hd->h_namesize));
10291556Srgrimes	} else {
10301556Srgrimes		arcn->sb.st_dev = (dev_t)(SHRT_EXT(hd->h_dev));
10311556Srgrimes		arcn->sb.st_ino = (ino_t)(SHRT_EXT(hd->h_ino));
10321556Srgrimes		arcn->sb.st_mode = (mode_t)(SHRT_EXT(hd->h_mode));
10331556Srgrimes		arcn->sb.st_uid = (uid_t)(SHRT_EXT(hd->h_uid));
10341556Srgrimes		arcn->sb.st_gid = (gid_t)(SHRT_EXT(hd->h_gid));
10351556Srgrimes		arcn->sb.st_nlink = (nlink_t)(SHRT_EXT(hd->h_nlink));
10361556Srgrimes		arcn->sb.st_rdev = (dev_t)(SHRT_EXT(hd->h_rdev));
10371556Srgrimes		arcn->sb.st_mtime = (time_t)(SHRT_EXT(hd->h_mtime_1));
10381556Srgrimes		arcn->sb.st_mtime =  (arcn->sb.st_mtime << 16) |
10391556Srgrimes			((time_t)(SHRT_EXT(hd->h_mtime_2)));
10401556Srgrimes		arcn->sb.st_size = (off_t)(SHRT_EXT(hd->h_filesize_1));
10411556Srgrimes		arcn->sb.st_size = (arcn->sb.st_size << 16) |
10421556Srgrimes			((off_t)(SHRT_EXT(hd->h_filesize_2)));
10431556Srgrimes		nsz = (int)(SHRT_EXT(hd->h_namesize));
10441556Srgrimes	}
10451556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
10461556Srgrimes
10471556Srgrimes	/*
10481556Srgrimes	 * check the file name size, if bogus give up. otherwise read the file
10491556Srgrimes	 * name
10501556Srgrimes	 */
10511556Srgrimes	if (nsz < 2)
10521556Srgrimes		return(-1);
10531556Srgrimes	arcn->nlen = nsz - 1;
10541556Srgrimes	if (rd_nm(arcn, nsz) < 0)
10551556Srgrimes		return(-1);
10561556Srgrimes
10571556Srgrimes	/*
10581556Srgrimes	 * header + file name are aligned to 2 byte boundries, skip if needed
10591556Srgrimes	 */
10601556Srgrimes	if (rd_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)
10611556Srgrimes		return(-1);
10621556Srgrimes
10631556Srgrimes	/*
10641556Srgrimes	 * if not a link (or a file with no data), calculate pad size (for
10651556Srgrimes	 * padding which follows the file data), clear the link name and return
10661556Srgrimes	 */
10671556Srgrimes	if (((arcn->sb.st_mode & C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)){
10681556Srgrimes		/*
10691556Srgrimes		 * we have a valid header (not a link)
10701556Srgrimes		 */
10711556Srgrimes		arcn->ln_nlen = 0;
10721556Srgrimes		arcn->ln_name[0] = '\0';
10731556Srgrimes		arcn->pad = BCPIO_PAD(arcn->sb.st_size);
10741556Srgrimes		return(com_rd(arcn));
10751556Srgrimes	}
10761556Srgrimes
10771556Srgrimes	if ((rd_ln_nm(arcn) < 0) ||
10781556Srgrimes	    (rd_skip((off_t)(BCPIO_PAD(arcn->sb.st_size))) < 0))
10791556Srgrimes		return(-1);
10801556Srgrimes
10811556Srgrimes	/*
10821556Srgrimes	 * we have a valid header (with a link)
10831556Srgrimes	 */
10841556Srgrimes	return(com_rd(arcn));
10851556Srgrimes}
10861556Srgrimes
10871556Srgrimes/*
10881556Srgrimes * bcpio_endrd()
10891556Srgrimes *      no cleanup needed here, just return size of the trailer (for append)
10901556Srgrimes * Return:
10911556Srgrimes *      size of trailer header in this format
10921556Srgrimes */
10931556Srgrimes
10941556Srgrimes#if __STDC__
10951556Srgrimesoff_t
10961556Srgrimesbcpio_endrd(void)
10971556Srgrimes#else
10981556Srgrimesoff_t
10991556Srgrimesbcpio_endrd()
11001556Srgrimes#endif
11011556Srgrimes{
11021556Srgrimes	return((off_t)(sizeof(HD_BCPIO) + sizeof(TRAILER) +
11031556Srgrimes		(BCPIO_PAD(sizeof(HD_BCPIO) + sizeof(TRAILER)))));
11041556Srgrimes}
11051556Srgrimes
11061556Srgrimes/*
11071556Srgrimes * bcpio_wr()
11081556Srgrimes *	copy the data in the ARCHD to buffer in old binary cpio format
11091556Srgrimes *	There is a real chance of field overflow with this critter. So we
11101556Srgrimes *	always check the conversion is ok. nobody in his their right mind
11111556Srgrimes *	should write an achive in this format...
11121556Srgrimes * Return
11131556Srgrimes *      0 if file has data to be written after the header, 1 if file has NO
11141556Srgrimes *	data to write after the header, -1 if archive write failed
11151556Srgrimes */
11161556Srgrimes
11171556Srgrimes#if __STDC__
11181556Srgrimesint
11191556Srgrimesbcpio_wr(register ARCHD *arcn)
11201556Srgrimes#else
11211556Srgrimesint
11221556Srgrimesbcpio_wr(arcn)
11231556Srgrimes	register ARCHD *arcn;
11241556Srgrimes#endif
11251556Srgrimes{
11261556Srgrimes	register HD_BCPIO *hd;
11271556Srgrimes	register int nsz;
11281556Srgrimes	char hdblk[sizeof(HD_BCPIO)];
11291556Srgrimes	off_t t_offt;
11301556Srgrimes	int t_int;
11311556Srgrimes	time_t t_timet;
11321556Srgrimes
11331556Srgrimes	/*
11341556Srgrimes	 * check and repair truncated device and inode fields in the cpio
11351556Srgrimes	 * header
11361556Srgrimes	 */
11371556Srgrimes	if (map_dev(arcn, (u_long)BCPIO_MASK, (u_long)BCPIO_MASK) < 0)
11381556Srgrimes		return(-1);
11391556Srgrimes
11401556Srgrimes	if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
11411556Srgrimes		arcn->sb.st_rdev = 0;
11421556Srgrimes	hd = (HD_BCPIO *)hdblk;
11431556Srgrimes
11441556Srgrimes	switch(arcn->type) {
11451556Srgrimes	case PAX_CTG:
11461556Srgrimes	case PAX_REG:
11471556Srgrimes	case PAX_HRG:
11481556Srgrimes		/*
11491556Srgrimes		 * caller will copy file data to the archive. tell him how
11501556Srgrimes		 * much to pad.
11511556Srgrimes		 */
11521556Srgrimes		arcn->pad = BCPIO_PAD(arcn->sb.st_size);
11531556Srgrimes		hd->h_filesize_1[0] = CHR_WR_0(arcn->sb.st_size);
11541556Srgrimes		hd->h_filesize_1[1] = CHR_WR_1(arcn->sb.st_size);
11551556Srgrimes		hd->h_filesize_2[0] = CHR_WR_2(arcn->sb.st_size);
11561556Srgrimes		hd->h_filesize_2[1] = CHR_WR_3(arcn->sb.st_size);
11571556Srgrimes		t_offt = (off_t)(SHRT_EXT(hd->h_filesize_1));
11581556Srgrimes		t_offt = (t_offt<<16) | ((off_t)(SHRT_EXT(hd->h_filesize_2)));
11591556Srgrimes		if (arcn->sb.st_size != t_offt) {
11601556Srgrimes			warn(1,"File is too large for bcpio format %s",
11611556Srgrimes			    arcn->org_name);
11621556Srgrimes			return(1);
11631556Srgrimes		}
11641556Srgrimes		break;
11651556Srgrimes	case PAX_SLK:
11661556Srgrimes		/*
11671556Srgrimes		 * no file data for the caller to process, the file data has
11681556Srgrimes		 * the size of the link
11691556Srgrimes		 */
11701556Srgrimes		arcn->pad = 0L;
11711556Srgrimes		hd->h_filesize_1[0] = CHR_WR_0(arcn->ln_nlen);
11721556Srgrimes		hd->h_filesize_1[1] = CHR_WR_1(arcn->ln_nlen);
11731556Srgrimes		hd->h_filesize_2[0] = CHR_WR_2(arcn->ln_nlen);
11741556Srgrimes		hd->h_filesize_2[1] = CHR_WR_3(arcn->ln_nlen);
11751556Srgrimes		t_int = (int)(SHRT_EXT(hd->h_filesize_1));
11761556Srgrimes		t_int = (t_int << 16) | ((int)(SHRT_EXT(hd->h_filesize_2)));
11771556Srgrimes		if (arcn->ln_nlen != t_int)
11781556Srgrimes			goto out;
11791556Srgrimes		break;
11801556Srgrimes	default:
11811556Srgrimes		/*
11821556Srgrimes		 * no file data for the caller to process
11831556Srgrimes		 */
11841556Srgrimes		arcn->pad = 0L;
11851556Srgrimes		hd->h_filesize_1[0] = (char)0;
11861556Srgrimes		hd->h_filesize_1[1] = (char)0;
11871556Srgrimes		hd->h_filesize_2[0] = (char)0;
11881556Srgrimes		hd->h_filesize_2[1] = (char)0;
11891556Srgrimes		break;
11901556Srgrimes	}
11911556Srgrimes
11921556Srgrimes	/*
11931556Srgrimes	 * build up the rest of the fields
11941556Srgrimes	 */
11951556Srgrimes	hd->h_magic[0] = CHR_WR_2(MAGIC);
11961556Srgrimes	hd->h_magic[1] = CHR_WR_3(MAGIC);
11971556Srgrimes	hd->h_dev[0] = CHR_WR_2(arcn->sb.st_dev);
11981556Srgrimes	hd->h_dev[1] = CHR_WR_3(arcn->sb.st_dev);
11991556Srgrimes	if (arcn->sb.st_dev != (dev_t)(SHRT_EXT(hd->h_dev)))
12001556Srgrimes		goto out;
12011556Srgrimes	hd->h_ino[0] = CHR_WR_2(arcn->sb.st_ino);
12021556Srgrimes	hd->h_ino[1] = CHR_WR_3(arcn->sb.st_ino);
12031556Srgrimes	if (arcn->sb.st_ino != (ino_t)(SHRT_EXT(hd->h_ino)))
12041556Srgrimes		goto out;
12051556Srgrimes	hd->h_mode[0] = CHR_WR_2(arcn->sb.st_mode);
12061556Srgrimes	hd->h_mode[1] = CHR_WR_3(arcn->sb.st_mode);
12071556Srgrimes	if (arcn->sb.st_mode != (mode_t)(SHRT_EXT(hd->h_mode)))
12081556Srgrimes		goto out;
12091556Srgrimes	hd->h_uid[0] = CHR_WR_2(arcn->sb.st_uid);
12101556Srgrimes	hd->h_uid[1] = CHR_WR_3(arcn->sb.st_uid);
12111556Srgrimes	if (arcn->sb.st_uid != (uid_t)(SHRT_EXT(hd->h_uid)))
12121556Srgrimes		goto out;
12131556Srgrimes	hd->h_gid[0] = CHR_WR_2(arcn->sb.st_gid);
12141556Srgrimes	hd->h_gid[1] = CHR_WR_3(arcn->sb.st_gid);
12151556Srgrimes	if (arcn->sb.st_gid != (gid_t)(SHRT_EXT(hd->h_gid)))
12161556Srgrimes		goto out;
12171556Srgrimes	hd->h_nlink[0] = CHR_WR_2(arcn->sb.st_nlink);
12181556Srgrimes	hd->h_nlink[1] = CHR_WR_3(arcn->sb.st_nlink);
12191556Srgrimes	if (arcn->sb.st_nlink != (nlink_t)(SHRT_EXT(hd->h_nlink)))
12201556Srgrimes		goto out;
12211556Srgrimes	hd->h_rdev[0] = CHR_WR_2(arcn->sb.st_rdev);
12221556Srgrimes	hd->h_rdev[1] = CHR_WR_3(arcn->sb.st_rdev);
12231556Srgrimes	if (arcn->sb.st_rdev != (dev_t)(SHRT_EXT(hd->h_rdev)))
12241556Srgrimes		goto out;
12251556Srgrimes	hd->h_mtime_1[0] = CHR_WR_0(arcn->sb.st_mtime);
12261556Srgrimes	hd->h_mtime_1[1] = CHR_WR_1(arcn->sb.st_mtime);
12271556Srgrimes	hd->h_mtime_2[0] = CHR_WR_2(arcn->sb.st_mtime);
12281556Srgrimes	hd->h_mtime_2[1] = CHR_WR_3(arcn->sb.st_mtime);
12291556Srgrimes	t_timet = (time_t)(SHRT_EXT(hd->h_mtime_1));
12301556Srgrimes	t_timet =  (t_timet << 16) | ((time_t)(SHRT_EXT(hd->h_mtime_2)));
12311556Srgrimes	if (arcn->sb.st_mtime != t_timet)
12321556Srgrimes		goto out;
12331556Srgrimes	nsz = arcn->nlen + 1;
12341556Srgrimes	hd->h_namesize[0] = CHR_WR_2(nsz);
12351556Srgrimes	hd->h_namesize[1] = CHR_WR_3(nsz);
12361556Srgrimes	if (nsz != (int)(SHRT_EXT(hd->h_namesize)))
12371556Srgrimes		goto out;
12381556Srgrimes
12391556Srgrimes	/*
12401556Srgrimes	 * write the header, the file name and padding as required.
12411556Srgrimes	 */
12421556Srgrimes	if ((wr_rdbuf(hdblk, (int)sizeof(HD_BCPIO)) < 0) ||
12431556Srgrimes	    (wr_rdbuf(arcn->name, nsz) < 0) ||
12441556Srgrimes	    (wr_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)) {
12451556Srgrimes		warn(1, "Could not write bcpio header for %s", arcn->org_name);
12461556Srgrimes		return(-1);
12471556Srgrimes	}
12481556Srgrimes
12491556Srgrimes	/*
12501556Srgrimes	 * if we have file data, tell the caller we are done
12511556Srgrimes	 */
12521556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
12531556Srgrimes	    (arcn->type == PAX_HRG))
12541556Srgrimes		return(0);
12551556Srgrimes
12561556Srgrimes	/*
12571556Srgrimes	 * if we are not a link, tell the caller we are done, go to next file
12581556Srgrimes	 */
12591556Srgrimes	if (arcn->type != PAX_SLK)
12601556Srgrimes		return(1);
12611556Srgrimes
12621556Srgrimes	/*
12631556Srgrimes	 * write the link name, tell the caller we are done.
12641556Srgrimes	 */
12651556Srgrimes	if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
12661556Srgrimes	    (wr_skip((off_t)(BCPIO_PAD(arcn->ln_nlen))) < 0)) {
12671556Srgrimes		warn(1,"Could not write bcpio link name for %s",arcn->org_name);
12681556Srgrimes		return(-1);
12691556Srgrimes	}
12701556Srgrimes	return(1);
12711556Srgrimes
12721556Srgrimes    out:
12731556Srgrimes	/*
12741556Srgrimes	 * header field is out of range
12751556Srgrimes	 */
12761556Srgrimes	warn(1,"Bcpio header field is too small for file %s", arcn->org_name);
12771556Srgrimes	return(1);
12781556Srgrimes}
1279