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