tar.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[] = "@(#)tar.c	8.2 (Berkeley) 4/18/94";
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 <stdio.h>
481556Srgrimes#include <ctype.h>
491556Srgrimes#include <unistd.h>
501556Srgrimes#include <stdlib.h>
511556Srgrimes#include "pax.h"
521556Srgrimes#include "extern.h"
531556Srgrimes#include "tar.h"
541556Srgrimes
551556Srgrimes/*
561556Srgrimes * Routines for reading, writing and header identify of various versions of tar
571556Srgrimes */
581556Srgrimes
591556Srgrimesstatic u_long tar_chksm __P((register char *, register int));
601556Srgrimesstatic char *name_split __P((register char *, register int));
611556Srgrimesstatic int ul_oct __P((u_long, register char *, register int, int));
621556Srgrimes#ifndef NET2_STAT
631556Srgrimesstatic int uqd_oct __P((u_quad_t, register char *, register int, int));
641556Srgrimes#endif
651556Srgrimes
661556Srgrimes/*
671556Srgrimes * Routines common to all versions of tar
681556Srgrimes */
691556Srgrimes
701556Srgrimesstatic int tar_nodir;			/* do not write dirs under old tar */
711556Srgrimes
721556Srgrimes/*
731556Srgrimes * tar_endwr()
741556Srgrimes *	add the tar trailer of two null blocks
751556Srgrimes * Return:
761556Srgrimes *	0 if ok, -1 otherwise (what wr_skip returns)
771556Srgrimes */
781556Srgrimes
791556Srgrimes#if __STDC__
801556Srgrimesint
811556Srgrimestar_endwr(void)
821556Srgrimes#else
831556Srgrimesint
841556Srgrimestar_endwr()
851556Srgrimes#endif
861556Srgrimes{
871556Srgrimes	return(wr_skip((off_t)(NULLCNT*BLKMULT)));
881556Srgrimes}
891556Srgrimes
901556Srgrimes/*
911556Srgrimes * tar_endrd()
921556Srgrimes *	no cleanup needed here, just return size of trailer (for append)
931556Srgrimes * Return:
941556Srgrimes *	size of trailer (2 * BLKMULT)
951556Srgrimes */
961556Srgrimes
971556Srgrimes#if __STDC__
981556Srgrimesoff_t
991556Srgrimestar_endrd(void)
1001556Srgrimes#else
1011556Srgrimesoff_t
1021556Srgrimestar_endrd()
1031556Srgrimes#endif
1041556Srgrimes{
1051556Srgrimes	return((off_t)(NULLCNT*BLKMULT));
1061556Srgrimes}
1071556Srgrimes
1081556Srgrimes/*
1091556Srgrimes * tar_trail()
1101556Srgrimes *	Called to determine if a header block is a valid trailer. We are passed
1111556Srgrimes *	the block, the in_sync flag (which tells us we are in resync mode;
1121556Srgrimes *	looking for a valid header), and cnt (which starts at zero) which is
1131556Srgrimes *	used to count the number of empty blocks we have seen so far.
1141556Srgrimes * Return:
1151556Srgrimes *	0 if a valid trailer, -1 if not a valid trailer, or 1 if the block
1161556Srgrimes *	could never contain a header.
1171556Srgrimes */
1181556Srgrimes
1191556Srgrimes#if __STDC__
1201556Srgrimesint
1211556Srgrimestar_trail(register char *buf, register int in_resync, register int *cnt)
1221556Srgrimes#else
1231556Srgrimesint
1241556Srgrimestar_trail(buf, in_resync, cnt)
1251556Srgrimes	register char *buf;
1261556Srgrimes	register int in_resync;
1271556Srgrimes	register int *cnt;
1281556Srgrimes#endif
1291556Srgrimes{
1301556Srgrimes	register int i;
1311556Srgrimes
1321556Srgrimes	/*
1331556Srgrimes	 * look for all zero, trailer is two consecutive blocks of zero
1341556Srgrimes	 */
1351556Srgrimes	for (i = 0; i < BLKMULT; ++i) {
1361556Srgrimes		if (buf[i] != '\0')
1371556Srgrimes			break;
1381556Srgrimes	}
1391556Srgrimes
1401556Srgrimes	/*
1411556Srgrimes	 * if not all zero it is not a trailer, but MIGHT be a header.
1421556Srgrimes	 */
1431556Srgrimes	if (i != BLKMULT)
1441556Srgrimes		return(-1);
1451556Srgrimes
1461556Srgrimes	/*
1471556Srgrimes	 * When given a zero block, we must be careful!
1481556Srgrimes	 * If we are not in resync mode, check for the trailer. Have to watch
1491556Srgrimes	 * out that we do not mis-identify file data as the trailer, so we do
1501556Srgrimes	 * NOT try to id a trailer during resync mode. During resync mode we
1511556Srgrimes	 * might as well throw this block out since a valid header can NEVER be
1521556Srgrimes	 * a block of all 0 (we must have a valid file name).
1531556Srgrimes	 */
1541556Srgrimes	if (!in_resync && (++*cnt >= NULLCNT))
1551556Srgrimes		return(0);
1561556Srgrimes	return(1);
1571556Srgrimes}
1581556Srgrimes
1591556Srgrimes/*
1601556Srgrimes * ul_oct()
1611556Srgrimes *	convert an unsigned long to an octal string. many oddball field
1621556Srgrimes *	termination characters are used by the various versions of tar in the
1631556Srgrimes *	different fields. term selects which kind to use. str is BLANK padded
1641556Srgrimes *	at the front to len. we are unable to use only one format as many old
1651556Srgrimes *	tar readers are very cranky about this.
1661556Srgrimes * Return:
1671556Srgrimes *	0 if the number fit into the string, -1 otherwise
1681556Srgrimes */
1691556Srgrimes
1701556Srgrimes#if __STDC__
1711556Srgrimesstatic int
1721556Srgrimesul_oct(u_long val, register char *str, register int len, int term)
1731556Srgrimes#else
1741556Srgrimesstatic int
1751556Srgrimesul_oct(val, str, len, term)
1761556Srgrimes	u_long val;
1771556Srgrimes	register char *str;
1781556Srgrimes	register int len;
1791556Srgrimes	int term;
1801556Srgrimes#endif
1811556Srgrimes{
1821556Srgrimes	register char *pt;
1831556Srgrimes
1841556Srgrimes	/*
1851556Srgrimes	 * term selects the appropriate character(s) for the end of the string
1861556Srgrimes	 */
1871556Srgrimes	pt = str + len - 1;
1881556Srgrimes	switch(term) {
1891556Srgrimes	case 3:
1901556Srgrimes		*pt-- = '\0';
1911556Srgrimes		break;
1921556Srgrimes	case 2:
1931556Srgrimes		*pt-- = ' ';
1941556Srgrimes		*pt-- = '\0';
1951556Srgrimes		break;
1961556Srgrimes	case 1:
1971556Srgrimes		*pt-- = ' ';
1981556Srgrimes		break;
1991556Srgrimes	case 0:
2001556Srgrimes	default:
2011556Srgrimes		*pt-- = '\0';
2021556Srgrimes		*pt-- = ' ';
2031556Srgrimes		break;
2041556Srgrimes	}
2051556Srgrimes
2061556Srgrimes	/*
2071556Srgrimes	 * convert and blank pad if there is space
2081556Srgrimes	 */
2091556Srgrimes	while (pt >= str) {
2101556Srgrimes		*pt-- = '0' + (char)(val & 0x7);
2111556Srgrimes		if ((val = val >> 3) == (u_long)0)
2121556Srgrimes			break;
2131556Srgrimes	}
2141556Srgrimes
2151556Srgrimes	while (pt >= str)
2161556Srgrimes		*pt-- = ' ';
2171556Srgrimes	if (val != (u_long)0)
2181556Srgrimes		return(-1);
2191556Srgrimes	return(0);
2201556Srgrimes}
2211556Srgrimes
2221556Srgrimes#ifndef NET2_STAT
2231556Srgrimes/*
2241556Srgrimes * uqd_oct()
2251556Srgrimes *	convert an u_quad_t to an octal string. one of many oddball field
2261556Srgrimes *	termination characters are used by the various versions of tar in the
2271556Srgrimes *	different fields. term selects which kind to use. str is BLANK padded
2281556Srgrimes *	at the front to len. we are unable to use only one format as many old
2291556Srgrimes *	tar readers are very cranky about this.
2301556Srgrimes * Return:
2311556Srgrimes *	0 if the number fit into the string, -1 otherwise
2321556Srgrimes */
2331556Srgrimes
2341556Srgrimes#if __STDC__
2351556Srgrimesstatic int
2361556Srgrimesuqd_oct(u_quad_t val, register char *str, register int len, int term)
2371556Srgrimes#else
2381556Srgrimesstatic int
2391556Srgrimesuqd_oct(val, str, len, term)
2401556Srgrimes	u_quad_t val;
2411556Srgrimes	register char *str;
2421556Srgrimes	register int len;
2431556Srgrimes	int term;
2441556Srgrimes#endif
2451556Srgrimes{
2461556Srgrimes	register char *pt;
2471556Srgrimes
2481556Srgrimes	/*
2491556Srgrimes	 * term selects the appropriate character(s) for the end of the string
2501556Srgrimes	 */
2511556Srgrimes	pt = str + len - 1;
2521556Srgrimes	switch(term) {
2531556Srgrimes	case 3:
2541556Srgrimes		*pt-- = '\0';
2551556Srgrimes		break;
2561556Srgrimes	case 2:
2571556Srgrimes		*pt-- = ' ';
2581556Srgrimes		*pt-- = '\0';
2591556Srgrimes		break;
2601556Srgrimes	case 1:
2611556Srgrimes		*pt-- = ' ';
2621556Srgrimes		break;
2631556Srgrimes	case 0:
2641556Srgrimes	default:
2651556Srgrimes		*pt-- = '\0';
2661556Srgrimes		*pt-- = ' ';
2671556Srgrimes		break;
2681556Srgrimes	}
2691556Srgrimes
2701556Srgrimes	/*
2711556Srgrimes	 * convert and blank pad if there is space
2721556Srgrimes	 */
2731556Srgrimes	while (pt >= str) {
2741556Srgrimes		*pt-- = '0' + (char)(val & 0x7);
2751556Srgrimes		if ((val = val >> 3) == 0)
2761556Srgrimes			break;
2771556Srgrimes	}
2781556Srgrimes
2791556Srgrimes	while (pt >= str)
2801556Srgrimes		*pt-- = ' ';
2811556Srgrimes	if (val != (u_quad_t)0)
2821556Srgrimes		return(-1);
2831556Srgrimes	return(0);
2841556Srgrimes}
2851556Srgrimes#endif
2861556Srgrimes
2871556Srgrimes/*
2881556Srgrimes * tar_chksm()
2891556Srgrimes *	calculate the checksum for a tar block counting the checksum field as
2901556Srgrimes *	all blanks (BLNKSUM is that value pre-calculated, the sume of 8 blanks).
2911556Srgrimes *	NOTE: we use len to short circuit summing 0's on write since we ALWAYS
2921556Srgrimes *	pad headers with 0.
2931556Srgrimes * Return:
2941556Srgrimes *	unsigned long checksum
2951556Srgrimes */
2961556Srgrimes
2971556Srgrimes#if __STDC__
2981556Srgrimesstatic u_long
2991556Srgrimestar_chksm(register char *blk, register int len)
3001556Srgrimes#else
3011556Srgrimesstatic u_long
3021556Srgrimestar_chksm(blk, len)
3031556Srgrimes	register char *blk;
3041556Srgrimes	register int len;
3051556Srgrimes#endif
3061556Srgrimes{
3071556Srgrimes	register char *stop;
3081556Srgrimes	register char *pt;
3091556Srgrimes	u_long chksm = BLNKSUM;	/* inital value is checksum field sum */
3101556Srgrimes
3111556Srgrimes	/*
3121556Srgrimes	 * add the part of the block before the checksum field
3131556Srgrimes	 */
3141556Srgrimes	pt = blk;
3151556Srgrimes	stop = blk + CHK_OFFSET;
3161556Srgrimes	while (pt < stop)
3171556Srgrimes		chksm += (u_long)(*pt++ & 0xff);
3181556Srgrimes	/*
3191556Srgrimes	 * move past the checksum field and keep going, spec counts the
3201556Srgrimes	 * checksum field as the sum of 8 blanks (which is pre-computed as
3211556Srgrimes	 * BLNKSUM).
3221556Srgrimes	 * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding
3231556Srgrimes	 * starts, no point in summing zero's)
3241556Srgrimes	 */
3251556Srgrimes	pt += CHK_LEN;
3261556Srgrimes	stop = blk + len;
3271556Srgrimes	while (pt < stop)
3281556Srgrimes		chksm += (u_long)(*pt++ & 0xff);
3291556Srgrimes	return(chksm);
3301556Srgrimes}
3311556Srgrimes
3321556Srgrimes/*
3331556Srgrimes * Routines for old BSD style tar (also made portable to sysV tar)
3341556Srgrimes */
3351556Srgrimes
3361556Srgrimes/*
3371556Srgrimes * tar_id()
3381556Srgrimes *	determine if a block given to us is a valid tar header (and not a USTAR
3391556Srgrimes *	header). We have to be on the lookout for those pesky blocks of	all
3401556Srgrimes *	zero's.
3411556Srgrimes * Return:
3421556Srgrimes *	0 if a tar header, -1 otherwise
3431556Srgrimes */
3441556Srgrimes
3451556Srgrimes#if __STDC__
3461556Srgrimesint
3471556Srgrimestar_id(register char *blk, int size)
3481556Srgrimes#else
3491556Srgrimesint
3501556Srgrimestar_id(blk, size)
3511556Srgrimes	register char *blk;
3521556Srgrimes	int size;
3531556Srgrimes#endif
3541556Srgrimes{
3551556Srgrimes	register HD_TAR *hd;
3561556Srgrimes	register HD_USTAR *uhd;
3571556Srgrimes
3581556Srgrimes	if (size < BLKMULT)
3591556Srgrimes		return(-1);
3601556Srgrimes	hd = (HD_TAR *)blk;
3611556Srgrimes	uhd = (HD_USTAR *)blk;
3621556Srgrimes
3631556Srgrimes	/*
3641556Srgrimes	 * check for block of zero's first, a simple and fast test, then make
3651556Srgrimes	 * sure this is not a ustar header by looking for the ustar magic
3661556Srgrimes	 * cookie. We should use TMAGLEN, but some USTAR archive programs are
3671556Srgrimes	 * wrong and create archives missing the \0. Last we check the
3681556Srgrimes	 * checksum. If this is ok we have to assume it is a valid header.
3691556Srgrimes	 */
3701556Srgrimes	if (hd->name[0] == '\0')
3711556Srgrimes		return(-1);
3721556Srgrimes	if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0)
3731556Srgrimes		return(-1);
3741556Srgrimes	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
3751556Srgrimes		return(-1);
3761556Srgrimes	return(0);
3771556Srgrimes}
3781556Srgrimes
3791556Srgrimes/*
3801556Srgrimes * tar_opt()
3811556Srgrimes *	handle tar format specific -o options
3821556Srgrimes * Return:
3831556Srgrimes *	0 if ok -1 otherwise
3841556Srgrimes */
3851556Srgrimes
3861556Srgrimes#if __STDC__
3871556Srgrimesint
3881556Srgrimestar_opt(void)
3891556Srgrimes#else
3901556Srgrimesint
3911556Srgrimestar_opt()
3921556Srgrimes#endif
3931556Srgrimes{
3941556Srgrimes	OPLIST *opt;
3951556Srgrimes
3961556Srgrimes	while ((opt = opt_next()) != NULL) {
3971556Srgrimes		if (strcmp(opt->name, TAR_OPTION) ||
3981556Srgrimes		    strcmp(opt->value, TAR_NODIR)) {
3991556Srgrimes			warn(1, "Unknown tar format -o option/value pair %s=%s",
4001556Srgrimes			    opt->name, opt->value);
4011556Srgrimes			warn(1,"%s=%s is the only supported tar format option",
4021556Srgrimes			    TAR_OPTION, TAR_NODIR);
4031556Srgrimes			return(-1);
4041556Srgrimes		}
4051556Srgrimes
4061556Srgrimes		/*
4071556Srgrimes		 * we only support one option, and only when writing
4081556Srgrimes		 */
4091556Srgrimes		if ((act != APPND) && (act != ARCHIVE)) {
4101556Srgrimes			warn(1, "%s=%s is only supported when writing.",
4111556Srgrimes			    opt->name, opt->value);
4121556Srgrimes			return(-1);
4131556Srgrimes		}
4141556Srgrimes		tar_nodir = 1;
4151556Srgrimes	}
4161556Srgrimes	return(0);
4171556Srgrimes}
4181556Srgrimes
4191556Srgrimes
4201556Srgrimes/*
4211556Srgrimes * tar_rd()
4221556Srgrimes *	extract the values out of block already determined to be a tar header.
4231556Srgrimes *	store the values in the ARCHD parameter.
4241556Srgrimes * Return:
4251556Srgrimes *	0
4261556Srgrimes */
4271556Srgrimes
4281556Srgrimes#if __STDC__
4291556Srgrimesint
4301556Srgrimestar_rd(register ARCHD *arcn, register char *buf)
4311556Srgrimes#else
4321556Srgrimesint
4331556Srgrimestar_rd(arcn, buf)
4341556Srgrimes	register ARCHD *arcn;
4351556Srgrimes	register char *buf;
4361556Srgrimes#endif
4371556Srgrimes{
4381556Srgrimes	register HD_TAR *hd;
4391556Srgrimes	register char *pt;
4401556Srgrimes
4411556Srgrimes	/*
4421556Srgrimes	 * we only get proper sized buffers passed to us
4431556Srgrimes	 */
4441556Srgrimes	if (tar_id(buf, BLKMULT) < 0)
4451556Srgrimes		return(-1);
4461556Srgrimes	arcn->org_name = arcn->name;
4471556Srgrimes	arcn->sb.st_nlink = 1;
4481556Srgrimes	arcn->pat = NULL;
4491556Srgrimes
4501556Srgrimes	/*
4511556Srgrimes	 * copy out the name and values in the stat buffer
4521556Srgrimes	 */
4531556Srgrimes	hd = (HD_TAR *)buf;
4541556Srgrimes	arcn->nlen = l_strncpy(arcn->name, hd->name, sizeof(hd->name));
4551556Srgrimes	arcn->name[arcn->nlen] = '\0';
4561556Srgrimes	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) &
4571556Srgrimes	    0xfff);
4581556Srgrimes	arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
4591556Srgrimes	arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
4601556Srgrimes	arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT);
4611556Srgrimes	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
4621556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
4631556Srgrimes
4641556Srgrimes	/*
4651556Srgrimes	 * have to look at the last character, it may be a '/' and that is used
4661556Srgrimes	 * to encode this as a directory
4671556Srgrimes	 */
4681556Srgrimes	pt = &(arcn->name[arcn->nlen - 1]);
4691556Srgrimes	arcn->pad = 0;
4701556Srgrimes	arcn->skip = 0;
4711556Srgrimes	switch(hd->linkflag) {
4721556Srgrimes	case SYMTYPE:
4731556Srgrimes		/*
4741556Srgrimes		 * symbolic link, need to get the link name and set the type in
4751556Srgrimes		 * the st_mode so -v printing will look correct.
4761556Srgrimes		 */
4771556Srgrimes		arcn->type = PAX_SLK;
4781556Srgrimes		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
4791556Srgrimes			sizeof(hd->linkname));
4801556Srgrimes		arcn->ln_name[arcn->ln_nlen] = '\0';
4811556Srgrimes		arcn->sb.st_mode |= S_IFLNK;
4821556Srgrimes		break;
4831556Srgrimes	case LNKTYPE:
4841556Srgrimes		/*
4851556Srgrimes		 * hard link, need to get the link name, set the type in the
4861556Srgrimes		 * st_mode and st_nlink so -v printing will look better.
4871556Srgrimes		 */
4881556Srgrimes		arcn->type = PAX_HLK;
4891556Srgrimes		arcn->sb.st_nlink = 2;
4901556Srgrimes		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
4911556Srgrimes			sizeof(hd->linkname));
4921556Srgrimes		arcn->ln_name[arcn->ln_nlen] = '\0';
4931556Srgrimes
4941556Srgrimes		/*
4951556Srgrimes		 * no idea of what type this thing really points at, but
4961556Srgrimes		 * we set something for printing only.
4971556Srgrimes		 */
4981556Srgrimes		arcn->sb.st_mode |= S_IFREG;
4991556Srgrimes		break;
5001556Srgrimes	case AREGTYPE:
5011556Srgrimes	case REGTYPE:
5021556Srgrimes	default:
5031556Srgrimes		/*
5041556Srgrimes		 * If we have a trailing / this is a directory and NOT a file.
5051556Srgrimes		 */
5061556Srgrimes		arcn->ln_name[0] = '\0';
5071556Srgrimes		arcn->ln_nlen = 0;
5081556Srgrimes		if (*pt == '/') {
5091556Srgrimes			/*
5101556Srgrimes			 * it is a directory, set the mode for -v printing
5111556Srgrimes			 */
5121556Srgrimes			arcn->type = PAX_DIR;
5131556Srgrimes			arcn->sb.st_mode |= S_IFDIR;
5141556Srgrimes			arcn->sb.st_nlink = 2;
5151556Srgrimes		} else {
5161556Srgrimes			/*
5171556Srgrimes			 * have a file that will be followed by data. Set the
5181556Srgrimes			 * skip value to the size field and caluculate the size
5191556Srgrimes			 * of the padding.
5201556Srgrimes			 */
5211556Srgrimes			arcn->type = PAX_REG;
5221556Srgrimes			arcn->sb.st_mode |= S_IFREG;
5231556Srgrimes			arcn->pad = TAR_PAD(arcn->sb.st_size);
5241556Srgrimes			arcn->skip = arcn->sb.st_size;
5251556Srgrimes		}
5261556Srgrimes		break;
5271556Srgrimes	}
5281556Srgrimes
5291556Srgrimes	/*
5301556Srgrimes	 * strip off any trailing slash.
5311556Srgrimes	 */
5321556Srgrimes	if (*pt == '/') {
5331556Srgrimes		*pt = '\0';
5341556Srgrimes		--arcn->nlen;
5351556Srgrimes	}
5361556Srgrimes	return(0);
5371556Srgrimes}
5381556Srgrimes
5391556Srgrimes/*
5401556Srgrimes * tar_wr()
5411556Srgrimes *	write a tar header for the file specified in the ARCHD to the archive.
5421556Srgrimes *	Have to check for file types that cannot be stored and file names that
5431556Srgrimes *	are too long. Be careful of the term (last arg) to ul_oct, each field
5441556Srgrimes *	of tar has it own spec for the termination character(s).
5451556Srgrimes *	ASSUMED: space after header in header block is zero filled
5461556Srgrimes * Return:
5471556Srgrimes *	0 if file has data to be written after the header, 1 if file has NO
5481556Srgrimes *	data to write after the header, -1 if archive write failed
5491556Srgrimes */
5501556Srgrimes
5511556Srgrimes#if __STDC__
5521556Srgrimesint
5531556Srgrimestar_wr(register ARCHD *arcn)
5541556Srgrimes#else
5551556Srgrimesint
5561556Srgrimestar_wr(arcn)
5571556Srgrimes	register ARCHD *arcn;
5581556Srgrimes#endif
5591556Srgrimes{
5601556Srgrimes	register HD_TAR *hd;
5611556Srgrimes	int len;
5621556Srgrimes	char hdblk[sizeof(HD_TAR)];
5631556Srgrimes
5641556Srgrimes	/*
5651556Srgrimes	 * check for those file system types which tar cannot store
5661556Srgrimes	 */
5671556Srgrimes	switch(arcn->type) {
5681556Srgrimes	case PAX_DIR:
5691556Srgrimes		/*
5701556Srgrimes		 * user asked that dirs not be written to the archive
5711556Srgrimes		 */
5721556Srgrimes		if (tar_nodir)
5731556Srgrimes			return(1);
5741556Srgrimes		break;
5751556Srgrimes	case PAX_CHR:
5761556Srgrimes		warn(1, "Tar cannot archive a character device %s",
5771556Srgrimes		    arcn->org_name);
5781556Srgrimes		return(1);
5791556Srgrimes	case PAX_BLK:
5801556Srgrimes		warn(1, "Tar cannot archive a block device %s", arcn->org_name);
5811556Srgrimes		return(1);
5821556Srgrimes	case PAX_SCK:
5831556Srgrimes		warn(1, "Tar cannot archive a socket %s", arcn->org_name);
5841556Srgrimes		return(1);
5851556Srgrimes	case PAX_FIF:
5861556Srgrimes		warn(1, "Tar cannot archive a fifo %s", arcn->org_name);
5871556Srgrimes		return(1);
5881556Srgrimes	case PAX_SLK:
5891556Srgrimes	case PAX_HLK:
5901556Srgrimes	case PAX_HRG:
5911556Srgrimes		if (arcn->ln_nlen > sizeof(hd->linkname)) {
5921556Srgrimes			warn(1,"Link name too long for tar %s", arcn->ln_name);
5931556Srgrimes			return(1);
5941556Srgrimes		}
5951556Srgrimes		break;
5961556Srgrimes	case PAX_REG:
5971556Srgrimes	case PAX_CTG:
5981556Srgrimes	default:
5991556Srgrimes		break;
6001556Srgrimes	}
6011556Srgrimes
6021556Srgrimes	/*
6031556Srgrimes	 * check file name len, remember extra char for dirs (the / at the end)
6041556Srgrimes	 */
6051556Srgrimes	len = arcn->nlen;
6061556Srgrimes	if (arcn->type == PAX_DIR)
6071556Srgrimes		++len;
6081556Srgrimes	if (len > sizeof(hd->name)) {
6091556Srgrimes		warn(1, "File name too long for tar %s", arcn->name);
6101556Srgrimes		return(1);
6111556Srgrimes	}
6121556Srgrimes
6131556Srgrimes	/*
6141556Srgrimes	 * copy the data out of the ARCHD into the tar header based on the type
6151556Srgrimes	 * of the file. Remember many tar readers want the unused fields to be
6161556Srgrimes	 * padded with zero. We set the linkflag field (type), the linkname
6171556Srgrimes	 * (or zero if not used),the size, and set the padding (if any) to be
6181556Srgrimes	 * added after the file data (0 for all other types, as they only have
6191556Srgrimes	 * a header)
6201556Srgrimes	 */
6211556Srgrimes	hd = (HD_TAR *)hdblk;
6221556Srgrimes	zf_strncpy(hd->name, arcn->name, sizeof(hd->name));
6231556Srgrimes	arcn->pad = 0;
6241556Srgrimes
6251556Srgrimes	if (arcn->type == PAX_DIR) {
6261556Srgrimes		/*
6271556Srgrimes		 * directories are the same as files, except have a filename
6281556Srgrimes		 * that ends with a /, we add the slash here. No data follows,
6291556Srgrimes		 * dirs, so no pad.
6301556Srgrimes		 */
6311556Srgrimes		hd->linkflag = AREGTYPE;
6321556Srgrimes		bzero(hd->linkname, sizeof(hd->linkname));
6331556Srgrimes		hd->name[len-1] = '/';
6341556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
6351556Srgrimes			goto out;
6361556Srgrimes	} else if (arcn->type == PAX_SLK) {
6371556Srgrimes		/*
6381556Srgrimes		 * no data follows this file, so no pad
6391556Srgrimes		 */
6401556Srgrimes		hd->linkflag = SYMTYPE;
6411556Srgrimes		zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname));
6421556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
6431556Srgrimes			goto out;
6441556Srgrimes	} else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {
6451556Srgrimes		/*
6461556Srgrimes		 * no data follows this file, so no pad
6471556Srgrimes		 */
6481556Srgrimes		hd->linkflag = LNKTYPE;
6491556Srgrimes		zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname));
6501556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
6511556Srgrimes			goto out;
6521556Srgrimes	} else {
6531556Srgrimes		/*
6541556Srgrimes		 * data follows this file, so set the pad
6551556Srgrimes		 */
6561556Srgrimes		hd->linkflag = AREGTYPE;
6571556Srgrimes		bzero(hd->linkname, sizeof(hd->linkname));
6581556Srgrimes#		ifdef NET2_STAT
6591556Srgrimes		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
6601556Srgrimes		    sizeof(hd->size), 1)) {
6611556Srgrimes#		else
6621556Srgrimes		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
6631556Srgrimes		    sizeof(hd->size), 1)) {
6641556Srgrimes#		endif
6651556Srgrimes			warn(1,"File is too large for tar %s", arcn->org_name);
6661556Srgrimes			return(1);
6671556Srgrimes		}
6681556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
6691556Srgrimes	}
6701556Srgrimes
6711556Srgrimes	/*
6721556Srgrimes	 * copy those fields that are independent of the type
6731556Srgrimes	 */
6741556Srgrimes	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) ||
6751556Srgrimes	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) ||
6761556Srgrimes	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) ||
6771556Srgrimes	    ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1))
6781556Srgrimes		goto out;
6791556Srgrimes
6801556Srgrimes	/*
6811556Srgrimes	 * calculate and add the checksum, then write the header. A return of
6821556Srgrimes	 * 0 tells the caller to now write the file data, 1 says no data needs
6831556Srgrimes	 * to be written
6841556Srgrimes	 */
6851556Srgrimes	if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum,
6861556Srgrimes	    sizeof(hd->chksum), 2))
6871556Srgrimes		goto out;
6881556Srgrimes	if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0)
6891556Srgrimes		return(-1);
6901556Srgrimes	if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0)
6911556Srgrimes		return(-1);
6921556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
6931556Srgrimes		return(0);
6941556Srgrimes	return(1);
6951556Srgrimes
6961556Srgrimes    out:
6971556Srgrimes	/*
6981556Srgrimes	 * header field is out of range
6991556Srgrimes	 */
7001556Srgrimes	warn(1, "Tar header field is too small for %s", arcn->org_name);
7011556Srgrimes	return(1);
7021556Srgrimes}
7031556Srgrimes
7041556Srgrimes/*
7051556Srgrimes * Routines for POSIX ustar
7061556Srgrimes */
7071556Srgrimes
7081556Srgrimes/*
7091556Srgrimes * ustar_strd()
7101556Srgrimes *	initialization for ustar read
7111556Srgrimes * Return:
7121556Srgrimes *	0 if ok, -1 otherwise
7131556Srgrimes */
7141556Srgrimes
7151556Srgrimes#if __STDC__
7161556Srgrimesint
7171556Srgrimesustar_strd(void)
7181556Srgrimes#else
7191556Srgrimesint
7201556Srgrimesustar_strd()
7211556Srgrimes#endif
7221556Srgrimes{
7231556Srgrimes	if ((usrtb_start() < 0) || (grptb_start() < 0))
7241556Srgrimes		return(-1);
7251556Srgrimes	return(0);
7261556Srgrimes}
7271556Srgrimes
7281556Srgrimes/*
7291556Srgrimes * ustar_stwr()
7301556Srgrimes *	initialization for ustar write
7311556Srgrimes * Return:
7321556Srgrimes *	0 if ok, -1 otherwise
7331556Srgrimes */
7341556Srgrimes
7351556Srgrimes#if __STDC__
7361556Srgrimesint
7371556Srgrimesustar_stwr(void)
7381556Srgrimes#else
7391556Srgrimesint
7401556Srgrimesustar_stwr()
7411556Srgrimes#endif
7421556Srgrimes{
7431556Srgrimes	if ((uidtb_start() < 0) || (gidtb_start() < 0))
7441556Srgrimes		return(-1);
7451556Srgrimes	return(0);
7461556Srgrimes}
7471556Srgrimes
7481556Srgrimes/*
7491556Srgrimes * ustar_id()
7501556Srgrimes *	determine if a block given to us is a valid ustar header. We have to
7511556Srgrimes *	be on the lookout for those pesky blocks of all zero's
7521556Srgrimes * Return:
7531556Srgrimes *	0 if a ustar header, -1 otherwise
7541556Srgrimes */
7551556Srgrimes
7561556Srgrimes#if __STDC__
7571556Srgrimesint
7581556Srgrimesustar_id(char *blk, int size)
7591556Srgrimes#else
7601556Srgrimesint
7611556Srgrimesustar_id(blk, size)
7621556Srgrimes	char *blk;
7631556Srgrimes	int size;
7641556Srgrimes#endif
7651556Srgrimes{
7661556Srgrimes	register HD_USTAR *hd;
7671556Srgrimes
7681556Srgrimes	if (size < BLKMULT)
7691556Srgrimes		return(-1);
7701556Srgrimes	hd = (HD_USTAR *)blk;
7711556Srgrimes
7721556Srgrimes	/*
7731556Srgrimes	 * check for block of zero's first, a simple and fast test then check
7741556Srgrimes	 * ustar magic cookie. We should use TMAGLEN, but some USTAR archive
7751556Srgrimes	 * programs are fouled up and create archives missing the \0. Last we
7761556Srgrimes	 * check the checksum. If ok we have to assume it is a valid header.
7771556Srgrimes	 */
7781556Srgrimes	if (hd->name[0] == '\0')
7791556Srgrimes		return(-1);
7801556Srgrimes	if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)
7811556Srgrimes		return(-1);
7821556Srgrimes	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
7831556Srgrimes		return(-1);
7841556Srgrimes	return(0);
7851556Srgrimes}
7861556Srgrimes
7871556Srgrimes/*
7881556Srgrimes * ustar_rd()
7891556Srgrimes *	extract the values out of block already determined to be a ustar header.
7901556Srgrimes *	store the values in the ARCHD parameter.
7911556Srgrimes * Return:
7921556Srgrimes *	0
7931556Srgrimes */
7941556Srgrimes
7951556Srgrimes#if __STDC__
7961556Srgrimesint
7971556Srgrimesustar_rd(register ARCHD *arcn, register char *buf)
7981556Srgrimes#else
7991556Srgrimesint
8001556Srgrimesustar_rd(arcn, buf)
8011556Srgrimes	register ARCHD *arcn;
8021556Srgrimes	register char *buf;
8031556Srgrimes#endif
8041556Srgrimes{
8051556Srgrimes	register HD_USTAR *hd;
8061556Srgrimes	register char *dest;
8071556Srgrimes	register int cnt = 0;
8081556Srgrimes	dev_t devmajor;
8091556Srgrimes	dev_t devminor;
8101556Srgrimes
8111556Srgrimes	/*
8121556Srgrimes	 * we only get proper sized buffers
8131556Srgrimes	 */
8141556Srgrimes	if (ustar_id(buf, BLKMULT) < 0)
8151556Srgrimes		return(-1);
8161556Srgrimes	arcn->org_name = arcn->name;
8171556Srgrimes	arcn->sb.st_nlink = 1;
8181556Srgrimes	arcn->pat = NULL;
8191556Srgrimes	hd = (HD_USTAR *)buf;
8201556Srgrimes
8211556Srgrimes	/*
8221556Srgrimes	 * see if the filename is split into two parts. if, so joint the parts.
8231556Srgrimes	 * we copy the prefix first and add a / between the prefix and name.
8241556Srgrimes	 */
8251556Srgrimes	dest = arcn->name;
8261556Srgrimes	if (*(hd->prefix) != '\0') {
8271556Srgrimes		cnt = l_strncpy(arcn->name, hd->prefix, sizeof(hd->prefix));
8281556Srgrimes		dest = arcn->name + arcn->nlen;
8291556Srgrimes		*dest++ = '/';
8301556Srgrimes	}
8311556Srgrimes	arcn->nlen = l_strncpy(dest, hd->name, sizeof(hd->name));
8321556Srgrimes	arcn->nlen += cnt;
8331556Srgrimes	arcn->name[arcn->nlen] = '\0';
8341556Srgrimes
8351556Srgrimes	/*
8361556Srgrimes	 * follow the spec to the letter. we should only have mode bits, strip
8371556Srgrimes	 * off all other crud we may be passed.
8381556Srgrimes	 */
8391556Srgrimes	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
8401556Srgrimes	    0xfff);
8411556Srgrimes	arcn->sb.st_size = (size_t)asc_ul(hd->size, sizeof(hd->size), OCT);
8421556Srgrimes	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
8431556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
8441556Srgrimes
8451556Srgrimes	/*
8461556Srgrimes	 * If we can find the ascii names for gname and uname in the password
8471556Srgrimes	 * and group files we will use the uid's and gid they bind. Otherwise
8481556Srgrimes	 * we use the uid and gid values stored in the header. (This is what
8491556Srgrimes	 * the posix spec wants).
8501556Srgrimes	 */
8511556Srgrimes	hd->gname[sizeof(hd->gname) - 1] = '\0';
8521556Srgrimes	if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)
8531556Srgrimes		arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
8541556Srgrimes	hd->uname[sizeof(hd->uname) - 1] = '\0';
8551556Srgrimes	if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
8561556Srgrimes		arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
8571556Srgrimes
8581556Srgrimes	/*
8591556Srgrimes	 * set the defaults, these may be changed depending on the file type
8601556Srgrimes	 */
8611556Srgrimes	arcn->ln_name[0] = '\0';
8621556Srgrimes	arcn->ln_nlen = 0;
8631556Srgrimes	arcn->pad = 0;
8641556Srgrimes	arcn->skip = 0;
8651556Srgrimes	arcn->sb.st_rdev = (dev_t)0;
8661556Srgrimes
8671556Srgrimes	/*
8681556Srgrimes	 * set the mode and PAX type according to the typeflag in the header
8691556Srgrimes	 */
8701556Srgrimes	switch(hd->typeflag) {
8711556Srgrimes	case FIFOTYPE:
8721556Srgrimes		arcn->type = PAX_FIF;
8731556Srgrimes		arcn->sb.st_mode |= S_IFIFO;
8741556Srgrimes		break;
8751556Srgrimes	case DIRTYPE:
8761556Srgrimes		arcn->type = PAX_DIR;
8771556Srgrimes		arcn->sb.st_mode |= S_IFDIR;
8781556Srgrimes		arcn->sb.st_nlink = 2;
8791556Srgrimes
8801556Srgrimes		/*
8811556Srgrimes		 * Some programs that create ustar archives append a '/'
8821556Srgrimes		 * to the pathname for directories. This clearly violates
8831556Srgrimes		 * ustar specs, but we will silently strip it off anyway.
8841556Srgrimes		 */
8851556Srgrimes		if (arcn->name[arcn->nlen - 1] == '/')
8861556Srgrimes			arcn->name[--arcn->nlen] = '\0';
8871556Srgrimes		break;
8881556Srgrimes	case BLKTYPE:
8891556Srgrimes	case CHRTYPE:
8901556Srgrimes		/*
8911556Srgrimes		 * this type requires the rdev field to be set.
8921556Srgrimes		 */
8931556Srgrimes		if (hd->typeflag == BLKTYPE) {
8941556Srgrimes			arcn->type = PAX_BLK;
8951556Srgrimes			arcn->sb.st_mode |= S_IFBLK;
8961556Srgrimes		} else {
8971556Srgrimes			arcn->type = PAX_CHR;
8981556Srgrimes			arcn->sb.st_mode |= S_IFCHR;
8991556Srgrimes		}
9001556Srgrimes		devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
9011556Srgrimes		devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
9021556Srgrimes		arcn->sb.st_rdev = TODEV(devmajor, devminor);
9031556Srgrimes		break;
9041556Srgrimes	case SYMTYPE:
9051556Srgrimes	case LNKTYPE:
9061556Srgrimes		if (hd->typeflag == SYMTYPE) {
9071556Srgrimes			arcn->type = PAX_SLK;
9081556Srgrimes			arcn->sb.st_mode |= S_IFLNK;
9091556Srgrimes		} else {
9101556Srgrimes			arcn->type = PAX_HLK;
9111556Srgrimes			/*
9121556Srgrimes			 * so printing looks better
9131556Srgrimes			 */
9141556Srgrimes			arcn->sb.st_mode |= S_IFREG;
9151556Srgrimes			arcn->sb.st_nlink = 2;
9161556Srgrimes		}
9171556Srgrimes		/*
9181556Srgrimes		 * copy the link name
9191556Srgrimes		 */
9201556Srgrimes		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
9211556Srgrimes			sizeof(hd->linkname));
9221556Srgrimes		arcn->ln_name[arcn->ln_nlen] = '\0';
9231556Srgrimes		break;
9241556Srgrimes	case CONTTYPE:
9251556Srgrimes	case AREGTYPE:
9261556Srgrimes	case REGTYPE:
9271556Srgrimes	default:
9281556Srgrimes		/*
9291556Srgrimes		 * these types have file data that follows. Set the skip and
9301556Srgrimes		 * pad fields.
9311556Srgrimes		 */
9321556Srgrimes		arcn->type = PAX_REG;
9331556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
9341556Srgrimes		arcn->skip = arcn->sb.st_size;
9351556Srgrimes		arcn->sb.st_mode |= S_IFREG;
9361556Srgrimes		break;
9371556Srgrimes	}
9381556Srgrimes	return(0);
9391556Srgrimes}
9401556Srgrimes
9411556Srgrimes/*
9421556Srgrimes * ustar_wr()
9431556Srgrimes *	write a ustar header for the file specified in the ARCHD to the archive
9441556Srgrimes *	Have to check for file types that cannot be stored and file names that
9451556Srgrimes *	are too long. Be careful of the term (last arg) to ul_oct, we only use
9461556Srgrimes *	'\0' for the termination character (this is different than picky tar)
9471556Srgrimes *	ASSUMED: space after header in header block is zero filled
9481556Srgrimes * Return:
9491556Srgrimes *	0 if file has data to be written after the header, 1 if file has NO
9501556Srgrimes *	data to write after the header, -1 if archive write failed
9511556Srgrimes */
9521556Srgrimes
9531556Srgrimes#if __STDC__
9541556Srgrimesint
9551556Srgrimesustar_wr(register ARCHD *arcn)
9561556Srgrimes#else
9571556Srgrimesint
9581556Srgrimesustar_wr(arcn)
9591556Srgrimes	register ARCHD *arcn;
9601556Srgrimes#endif
9611556Srgrimes{
9621556Srgrimes	register HD_USTAR *hd;
9631556Srgrimes	register char *pt;
9641556Srgrimes	char hdblk[sizeof(HD_USTAR)];
9651556Srgrimes
9661556Srgrimes	/*
9671556Srgrimes	 * check for those file system types ustar cannot store
9681556Srgrimes	 */
9691556Srgrimes	if (arcn->type == PAX_SCK) {
9701556Srgrimes		warn(1, "Ustar cannot archive a socket %s", arcn->org_name);
9711556Srgrimes		return(1);
9721556Srgrimes	}
9731556Srgrimes
9741556Srgrimes	/*
9751556Srgrimes	 * check the length of the linkname
9761556Srgrimes	 */
9771556Srgrimes	if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
9781556Srgrimes	    (arcn->type == PAX_HRG)) && (arcn->ln_nlen > sizeof(hd->linkname))){
9791556Srgrimes		warn(1, "Link name too long for ustar %s", arcn->ln_name);
9801556Srgrimes		return(1);
9811556Srgrimes	}
9821556Srgrimes
9831556Srgrimes	/*
9841556Srgrimes	 * split the path name into prefix and name fields (if needed). if
9851556Srgrimes	 * pt != arcn->name, the name has to be split
9861556Srgrimes	 */
9871556Srgrimes	if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
9881556Srgrimes		warn(1, "File name too long for ustar %s", arcn->name);
9891556Srgrimes		return(1);
9901556Srgrimes	}
9911556Srgrimes	hd = (HD_USTAR *)hdblk;
9921556Srgrimes	arcn->pad = 0L;
9931556Srgrimes
9941556Srgrimes	/*
9951556Srgrimes	 * split the name, or zero out the prefix
9961556Srgrimes	 */
9971556Srgrimes	if (pt != arcn->name) {
9981556Srgrimes		/*
9991556Srgrimes		 * name was split, pt points at the / where the split is to
10001556Srgrimes		 * occur, we remove the / and copy the first part to the prefix
10011556Srgrimes		 */
10021556Srgrimes		*pt = '\0';
10031556Srgrimes		zf_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix));
10041556Srgrimes		*pt++ = '/';
10051556Srgrimes	} else
10061556Srgrimes		bzero(hd->prefix, sizeof(hd->prefix));
10071556Srgrimes
10081556Srgrimes	/*
10091556Srgrimes	 * copy the name part. this may be the whole path or the part after
10101556Srgrimes	 * the prefix
10111556Srgrimes	 */
10121556Srgrimes	zf_strncpy(hd->name, pt, sizeof(hd->name));
10131556Srgrimes
10141556Srgrimes	/*
10151556Srgrimes	 * set the fields in the header that are type dependent
10161556Srgrimes	 */
10171556Srgrimes	switch(arcn->type) {
10181556Srgrimes	case PAX_DIR:
10191556Srgrimes		hd->typeflag = DIRTYPE;
10201556Srgrimes		bzero(hd->linkname, sizeof(hd->linkname));
10211556Srgrimes		bzero(hd->devmajor, sizeof(hd->devmajor));
10221556Srgrimes		bzero(hd->devminor, sizeof(hd->devminor));
10231556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
10241556Srgrimes			goto out;
10251556Srgrimes		break;
10261556Srgrimes	case PAX_CHR:
10271556Srgrimes	case PAX_BLK:
10281556Srgrimes		if (arcn->type == PAX_CHR)
10291556Srgrimes			hd->typeflag = CHRTYPE;
10301556Srgrimes		else
10311556Srgrimes			hd->typeflag = BLKTYPE;
10321556Srgrimes		bzero(hd->linkname, sizeof(hd->linkname));
10331556Srgrimes		if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,
10341556Srgrimes		   sizeof(hd->devmajor), 3) ||
10351556Srgrimes		   ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,
10361556Srgrimes		   sizeof(hd->devminor), 3) ||
10371556Srgrimes		   ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
10381556Srgrimes			goto out;
10391556Srgrimes		break;
10401556Srgrimes	case PAX_FIF:
10411556Srgrimes		hd->typeflag = FIFOTYPE;
10421556Srgrimes		bzero(hd->linkname, sizeof(hd->linkname));
10431556Srgrimes		bzero(hd->devmajor, sizeof(hd->devmajor));
10441556Srgrimes		bzero(hd->devminor, sizeof(hd->devminor));
10451556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
10461556Srgrimes			goto out;
10471556Srgrimes		break;
10481556Srgrimes	case PAX_SLK:
10491556Srgrimes	case PAX_HLK:
10501556Srgrimes	case PAX_HRG:
10511556Srgrimes		if (arcn->type == PAX_SLK)
10521556Srgrimes			hd->typeflag = SYMTYPE;
10531556Srgrimes		else
10541556Srgrimes			hd->typeflag = LNKTYPE;
10551556Srgrimes		zf_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname));
10561556Srgrimes		bzero(hd->devmajor, sizeof(hd->devmajor));
10571556Srgrimes		bzero(hd->devminor, sizeof(hd->devminor));
10581556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
10591556Srgrimes			goto out;
10601556Srgrimes		break;
10611556Srgrimes	case PAX_REG:
10621556Srgrimes	case PAX_CTG:
10631556Srgrimes	default:
10641556Srgrimes		/*
10651556Srgrimes		 * file data with this type, set the padding
10661556Srgrimes		 */
10671556Srgrimes		if (arcn->type == PAX_CTG)
10681556Srgrimes			hd->typeflag = CONTTYPE;
10691556Srgrimes		else
10701556Srgrimes			hd->typeflag = REGTYPE;
10711556Srgrimes		bzero(hd->linkname, sizeof(hd->linkname));
10721556Srgrimes		bzero(hd->devmajor, sizeof(hd->devmajor));
10731556Srgrimes		bzero(hd->devminor, sizeof(hd->devminor));
10741556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
10751556Srgrimes#		ifdef NET2_STAT
10761556Srgrimes		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
10771556Srgrimes		    sizeof(hd->size), 3)) {
10781556Srgrimes#		else
10791556Srgrimes		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
10801556Srgrimes		    sizeof(hd->size), 3)) {
10811556Srgrimes#		endif
10821556Srgrimes			warn(1,"File is too long for ustar %s",arcn->org_name);
10831556Srgrimes			return(1);
10841556Srgrimes		}
10851556Srgrimes		break;
10861556Srgrimes	}
10871556Srgrimes
10881556Srgrimes	zf_strncpy(hd->magic, TMAGIC, TMAGLEN);
10891556Srgrimes	zf_strncpy(hd->version, TVERSION, TVERSLEN);
10901556Srgrimes
10911556Srgrimes	/*
10921556Srgrimes	 * set the remaining fields. Some versions want all 16 bits of mode
10931556Srgrimes	 * we better humor them (they really do not meet spec though)....
10941556Srgrimes	 */
10951556Srgrimes	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) ||
10961556Srgrimes	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3)  ||
10971556Srgrimes	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) ||
10981556Srgrimes	    ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3))
10991556Srgrimes		goto out;
11001556Srgrimes	zf_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname));
11011556Srgrimes	zf_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname));
11021556Srgrimes
11031556Srgrimes	/*
11041556Srgrimes	 * calculate and store the checksum write the header to the archive
11051556Srgrimes	 * return 0 tells the caller to now write the file data, 1 says no data
11061556Srgrimes	 * needs to be written
11071556Srgrimes	 */
11081556Srgrimes	if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum,
11091556Srgrimes	   sizeof(hd->chksum), 3))
11101556Srgrimes		goto out;
11111556Srgrimes	if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)
11121556Srgrimes		return(-1);
11131556Srgrimes	if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
11141556Srgrimes		return(-1);
11151556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
11161556Srgrimes		return(0);
11171556Srgrimes	return(1);
11181556Srgrimes
11191556Srgrimes    out:
11201556Srgrimes    	/*
11211556Srgrimes	 * header field is out of range
11221556Srgrimes	 */
11231556Srgrimes	warn(1, "Ustar header field is too small for %s", arcn->org_name);
11241556Srgrimes	return(1);
11251556Srgrimes}
11261556Srgrimes
11271556Srgrimes/*
11281556Srgrimes * name_split()
11291556Srgrimes *	see if the name has to be split for storage in a ustar header. We try
11301556Srgrimes *	to fit the entire name in the name field without splitting if we can.
11311556Srgrimes *	The split point is always at a /
11321556Srgrimes * Return
11331556Srgrimes *	character pointer to split point (always the / that is to be removed
11341556Srgrimes *	if the split is not needed, the points is set to the start of the file
11351556Srgrimes *	name (it would violate the spec to split there). A NULL is returned if
11361556Srgrimes *	the file name is too long
11371556Srgrimes */
11381556Srgrimes
11391556Srgrimes#if __STDC__
11401556Srgrimesstatic char *
11411556Srgrimesname_split(register char *name, register int len)
11421556Srgrimes#else
11431556Srgrimesstatic char *
11441556Srgrimesname_split(name, len)
11451556Srgrimes	register char *name;
11461556Srgrimes	register int len;
11471556Srgrimes#endif
11481556Srgrimes{
11491556Srgrimes	register char *start;
11501556Srgrimes
11511556Srgrimes	/*
11521556Srgrimes	 * check to see if the file name is small enough to fit in the name
11531556Srgrimes	 * field. if so just return a pointer to the name.
11541556Srgrimes	 */
11551556Srgrimes	if (len <= TNMSZ)
11561556Srgrimes		return(name);
11571556Srgrimes	if (len > (TPFSZ + TNMSZ + 1))
11581556Srgrimes		return(NULL);
11591556Srgrimes
11601556Srgrimes	/*
11611556Srgrimes	 * we start looking at the biggest sized piece that fits in the name
11621556Srgrimes	 * field. We walk foward looking for a slash to split at. The idea is
11631556Srgrimes	 * to find the biggest piece to fit in the name field (or the smallest
11641556Srgrimes	 * prefix we can find) (the -1 is correct the biggest piece would
11651556Srgrimes	 * include the slash between the two parts that gets thrown away)
11661556Srgrimes	 */
11671556Srgrimes	start = name + len - TNMSZ - 1;
11681556Srgrimes	while ((*start != '\0') && (*start != '/'))
11691556Srgrimes		++start;
11701556Srgrimes
11711556Srgrimes	/*
11721556Srgrimes	 * if we hit the end of the string, this name cannot be split, so we
11731556Srgrimes	 * cannot store this file.
11741556Srgrimes	 */
11751556Srgrimes	if (*start == '\0')
11761556Srgrimes		return(NULL);
11771556Srgrimes	len = start - name;
11781556Srgrimes
11791556Srgrimes	/*
11801556Srgrimes	 * NOTE: /str where the length of str == TNMSZ can not be stored under
11811556Srgrimes	 * the p1003.1-1990 spec for ustar. We could force a prefix of / and
11821556Srgrimes	 * the file would then expand on extract to //str. The len == 0 below
11831556Srgrimes	 * makes this special case follow the spec to the letter.
11841556Srgrimes	 */
11851556Srgrimes	if ((len > TPFSZ) || (len == 0))
11861556Srgrimes		return(NULL);
11871556Srgrimes
11881556Srgrimes	/*
11891556Srgrimes	 * ok have a split point, return it to the caller
11901556Srgrimes	 */
11911556Srgrimes	return(start);
11921556Srgrimes}
1193