11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1992 Keith Muller.
31556Srgrimes * Copyright (c) 1992, 1993
41556Srgrimes *	The Regents of the University of California.  All rights reserved.
51556Srgrimes *
61556Srgrimes * This code is derived from software contributed to Berkeley by
71556Srgrimes * Keith Muller of the University of California, San Diego.
81556Srgrimes *
91556Srgrimes * Redistribution and use in source and binary forms, with or without
101556Srgrimes * modification, are permitted provided that the following conditions
111556Srgrimes * are met:
121556Srgrimes * 1. Redistributions of source code must retain the above copyright
131556Srgrimes *    notice, this list of conditions and the following disclaimer.
141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
151556Srgrimes *    notice, this list of conditions and the following disclaimer in the
161556Srgrimes *    documentation and/or other materials provided with the distribution.
171556Srgrimes * 4. Neither the name of the University nor the names of its contributors
181556Srgrimes *    may be used to endorse or promote products derived from this software
191556Srgrimes *    without specific prior written permission.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311556Srgrimes * SUCH DAMAGE.
321556Srgrimes */
331556Srgrimes
341556Srgrimes#ifndef lint
3536049Scharnier#if 0
3636049Scharnierstatic char sccsid[] = "@(#)tar.c	8.2 (Berkeley) 4/18/94";
3736049Scharnier#endif
381556Srgrimes#endif /* not lint */
3999110Sobrien#include <sys/cdefs.h>
4099110Sobrien__FBSDID("$FreeBSD$");
411556Srgrimes
421556Srgrimes#include <sys/types.h>
431556Srgrimes#include <sys/time.h>
441556Srgrimes#include <sys/stat.h>
451556Srgrimes#include <string.h>
461556Srgrimes#include <stdio.h>
471556Srgrimes#include "pax.h"
481556Srgrimes#include "extern.h"
491556Srgrimes#include "tar.h"
501556Srgrimes
511556Srgrimes/*
521556Srgrimes * Routines for reading, writing and header identify of various versions of tar
531556Srgrimes */
541556Srgrimes
5590113Simpstatic u_long tar_chksm(char *, int);
5690113Simpstatic char *name_split(char *, int);
5790113Simpstatic int ul_oct(u_long, char *, int, int);
581556Srgrimes#ifndef NET2_STAT
5990113Simpstatic int uqd_oct(u_quad_t, char *, int, int);
601556Srgrimes#endif
611556Srgrimes
621556Srgrimes/*
631556Srgrimes * Routines common to all versions of tar
641556Srgrimes */
651556Srgrimes
661556Srgrimesstatic int tar_nodir;			/* do not write dirs under old tar */
671556Srgrimes
681556Srgrimes/*
691556Srgrimes * tar_endwr()
701556Srgrimes *	add the tar trailer of two null blocks
711556Srgrimes * Return:
721556Srgrimes *	0 if ok, -1 otherwise (what wr_skip returns)
731556Srgrimes */
741556Srgrimes
751556Srgrimesint
761556Srgrimestar_endwr(void)
771556Srgrimes{
781556Srgrimes	return(wr_skip((off_t)(NULLCNT*BLKMULT)));
791556Srgrimes}
801556Srgrimes
811556Srgrimes/*
821556Srgrimes * tar_endrd()
831556Srgrimes *	no cleanup needed here, just return size of trailer (for append)
841556Srgrimes * Return:
851556Srgrimes *	size of trailer (2 * BLKMULT)
861556Srgrimes */
871556Srgrimes
881556Srgrimesoff_t
891556Srgrimestar_endrd(void)
901556Srgrimes{
911556Srgrimes	return((off_t)(NULLCNT*BLKMULT));
921556Srgrimes}
931556Srgrimes
941556Srgrimes/*
951556Srgrimes * tar_trail()
961556Srgrimes *	Called to determine if a header block is a valid trailer. We are passed
971556Srgrimes *	the block, the in_sync flag (which tells us we are in resync mode;
981556Srgrimes *	looking for a valid header), and cnt (which starts at zero) which is
991556Srgrimes *	used to count the number of empty blocks we have seen so far.
1001556Srgrimes * Return:
1011556Srgrimes *	0 if a valid trailer, -1 if not a valid trailer, or 1 if the block
1021556Srgrimes *	could never contain a header.
1031556Srgrimes */
1041556Srgrimes
1051556Srgrimesint
10690113Simptar_trail(char *buf, int in_resync, int *cnt)
1071556Srgrimes{
10890113Simp	int i;
1091556Srgrimes
1101556Srgrimes	/*
1111556Srgrimes	 * look for all zero, trailer is two consecutive blocks of zero
1121556Srgrimes	 */
1131556Srgrimes	for (i = 0; i < BLKMULT; ++i) {
1141556Srgrimes		if (buf[i] != '\0')
1151556Srgrimes			break;
1161556Srgrimes	}
1171556Srgrimes
1181556Srgrimes	/*
1191556Srgrimes	 * if not all zero it is not a trailer, but MIGHT be a header.
1201556Srgrimes	 */
1211556Srgrimes	if (i != BLKMULT)
1221556Srgrimes		return(-1);
1231556Srgrimes
1241556Srgrimes	/*
1251556Srgrimes	 * When given a zero block, we must be careful!
1261556Srgrimes	 * If we are not in resync mode, check for the trailer. Have to watch
1271556Srgrimes	 * out that we do not mis-identify file data as the trailer, so we do
1281556Srgrimes	 * NOT try to id a trailer during resync mode. During resync mode we
1291556Srgrimes	 * might as well throw this block out since a valid header can NEVER be
1301556Srgrimes	 * a block of all 0 (we must have a valid file name).
1311556Srgrimes	 */
1321556Srgrimes	if (!in_resync && (++*cnt >= NULLCNT))
1331556Srgrimes		return(0);
1341556Srgrimes	return(1);
1351556Srgrimes}
1361556Srgrimes
1371556Srgrimes/*
1381556Srgrimes * ul_oct()
1391556Srgrimes *	convert an unsigned long to an octal string. many oddball field
1401556Srgrimes *	termination characters are used by the various versions of tar in the
14176351Skris *	different fields. term selects which kind to use. str is '0' padded
1421556Srgrimes *	at the front to len. we are unable to use only one format as many old
1431556Srgrimes *	tar readers are very cranky about this.
1441556Srgrimes * Return:
1451556Srgrimes *	0 if the number fit into the string, -1 otherwise
1461556Srgrimes */
1471556Srgrimes
1481556Srgrimesstatic int
14990113Simpul_oct(u_long val, char *str, int len, int term)
1501556Srgrimes{
15190113Simp	char *pt;
1528855Srgrimes
1531556Srgrimes	/*
1541556Srgrimes	 * term selects the appropriate character(s) for the end of the string
1551556Srgrimes	 */
1561556Srgrimes	pt = str + len - 1;
1571556Srgrimes	switch(term) {
1581556Srgrimes	case 3:
1591556Srgrimes		*pt-- = '\0';
1601556Srgrimes		break;
1611556Srgrimes	case 2:
1621556Srgrimes		*pt-- = ' ';
1631556Srgrimes		*pt-- = '\0';
1641556Srgrimes		break;
1651556Srgrimes	case 1:
1661556Srgrimes		*pt-- = ' ';
1671556Srgrimes		break;
1681556Srgrimes	case 0:
1691556Srgrimes	default:
1701556Srgrimes		*pt-- = '\0';
1711556Srgrimes		*pt-- = ' ';
1721556Srgrimes		break;
1731556Srgrimes	}
1741556Srgrimes
1751556Srgrimes	/*
1761556Srgrimes	 * convert and blank pad if there is space
1771556Srgrimes	 */
1781556Srgrimes	while (pt >= str) {
1791556Srgrimes		*pt-- = '0' + (char)(val & 0x7);
1801556Srgrimes		if ((val = val >> 3) == (u_long)0)
1811556Srgrimes			break;
1821556Srgrimes	}
1831556Srgrimes
1841556Srgrimes	while (pt >= str)
18576351Skris		*pt-- = '0';
1861556Srgrimes	if (val != (u_long)0)
1871556Srgrimes		return(-1);
1881556Srgrimes	return(0);
1891556Srgrimes}
1901556Srgrimes
1911556Srgrimes#ifndef NET2_STAT
1921556Srgrimes/*
1931556Srgrimes * uqd_oct()
1941556Srgrimes *	convert an u_quad_t to an octal string. one of many oddball field
1951556Srgrimes *	termination characters are used by the various versions of tar in the
19676351Skris *	different fields. term selects which kind to use. str is '0' padded
1971556Srgrimes *	at the front to len. we are unable to use only one format as many old
1981556Srgrimes *	tar readers are very cranky about this.
1991556Srgrimes * Return:
2001556Srgrimes *	0 if the number fit into the string, -1 otherwise
2011556Srgrimes */
2021556Srgrimes
2031556Srgrimesstatic int
20490113Simpuqd_oct(u_quad_t val, char *str, int len, int term)
2051556Srgrimes{
20690113Simp	char *pt;
2078855Srgrimes
2081556Srgrimes	/*
2091556Srgrimes	 * term selects the appropriate character(s) for the end of the string
2101556Srgrimes	 */
2111556Srgrimes	pt = str + len - 1;
2121556Srgrimes	switch(term) {
2131556Srgrimes	case 3:
2141556Srgrimes		*pt-- = '\0';
2151556Srgrimes		break;
2161556Srgrimes	case 2:
2171556Srgrimes		*pt-- = ' ';
2181556Srgrimes		*pt-- = '\0';
2191556Srgrimes		break;
2201556Srgrimes	case 1:
2211556Srgrimes		*pt-- = ' ';
2221556Srgrimes		break;
2231556Srgrimes	case 0:
2241556Srgrimes	default:
2251556Srgrimes		*pt-- = '\0';
2261556Srgrimes		*pt-- = ' ';
2271556Srgrimes		break;
2281556Srgrimes	}
2291556Srgrimes
2301556Srgrimes	/*
2311556Srgrimes	 * convert and blank pad if there is space
2321556Srgrimes	 */
2331556Srgrimes	while (pt >= str) {
2341556Srgrimes		*pt-- = '0' + (char)(val & 0x7);
2351556Srgrimes		if ((val = val >> 3) == 0)
2361556Srgrimes			break;
2371556Srgrimes	}
2381556Srgrimes
2391556Srgrimes	while (pt >= str)
24076351Skris		*pt-- = '0';
2411556Srgrimes	if (val != (u_quad_t)0)
2421556Srgrimes		return(-1);
2431556Srgrimes	return(0);
2441556Srgrimes}
2451556Srgrimes#endif
2461556Srgrimes
2471556Srgrimes/*
2481556Srgrimes * tar_chksm()
2491556Srgrimes *	calculate the checksum for a tar block counting the checksum field as
25046684Skris *	all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks).
2511556Srgrimes *	NOTE: we use len to short circuit summing 0's on write since we ALWAYS
2521556Srgrimes *	pad headers with 0.
2531556Srgrimes * Return:
2541556Srgrimes *	unsigned long checksum
2551556Srgrimes */
2561556Srgrimes
2571556Srgrimesstatic u_long
25890113Simptar_chksm(char *blk, int len)
2591556Srgrimes{
26090113Simp	char *stop;
26190113Simp	char *pt;
26246684Skris	u_long chksm = BLNKSUM;	/* initial value is checksum field sum */
2631556Srgrimes
2641556Srgrimes	/*
2651556Srgrimes	 * add the part of the block before the checksum field
2661556Srgrimes	 */
2671556Srgrimes	pt = blk;
2681556Srgrimes	stop = blk + CHK_OFFSET;
2698855Srgrimes	while (pt < stop)
2708855Srgrimes		chksm += (u_long)(*pt++ & 0xff);
2711556Srgrimes	/*
2721556Srgrimes	 * move past the checksum field and keep going, spec counts the
2731556Srgrimes	 * checksum field as the sum of 8 blanks (which is pre-computed as
2741556Srgrimes	 * BLNKSUM).
2751556Srgrimes	 * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding
2761556Srgrimes	 * starts, no point in summing zero's)
2771556Srgrimes	 */
2781556Srgrimes	pt += CHK_LEN;
2791556Srgrimes	stop = blk + len;
2801556Srgrimes	while (pt < stop)
2818855Srgrimes		chksm += (u_long)(*pt++ & 0xff);
2821556Srgrimes	return(chksm);
2831556Srgrimes}
2841556Srgrimes
2851556Srgrimes/*
2861556Srgrimes * Routines for old BSD style tar (also made portable to sysV tar)
2871556Srgrimes */
2881556Srgrimes
2891556Srgrimes/*
2901556Srgrimes * tar_id()
2911556Srgrimes *	determine if a block given to us is a valid tar header (and not a USTAR
292222177Suqs *	header). We have to be on the lookout for those pesky blocks of all
2931556Srgrimes *	zero's.
2941556Srgrimes * Return:
2951556Srgrimes *	0 if a tar header, -1 otherwise
2961556Srgrimes */
2971556Srgrimes
2981556Srgrimesint
29990113Simptar_id(char *blk, int size)
3001556Srgrimes{
30190113Simp	HD_TAR *hd;
30290113Simp	HD_USTAR *uhd;
3031556Srgrimes
3041556Srgrimes	if (size < BLKMULT)
3051556Srgrimes		return(-1);
3061556Srgrimes	hd = (HD_TAR *)blk;
3071556Srgrimes	uhd = (HD_USTAR *)blk;
3081556Srgrimes
3091556Srgrimes	/*
3101556Srgrimes	 * check for block of zero's first, a simple and fast test, then make
3111556Srgrimes	 * sure this is not a ustar header by looking for the ustar magic
3121556Srgrimes	 * cookie. We should use TMAGLEN, but some USTAR archive programs are
3131556Srgrimes	 * wrong and create archives missing the \0. Last we check the
3141556Srgrimes	 * checksum. If this is ok we have to assume it is a valid header.
3151556Srgrimes	 */
3161556Srgrimes	if (hd->name[0] == '\0')
3171556Srgrimes		return(-1);
3181556Srgrimes	if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0)
3191556Srgrimes		return(-1);
3201556Srgrimes	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
3211556Srgrimes		return(-1);
3221556Srgrimes	return(0);
3231556Srgrimes}
3241556Srgrimes
3251556Srgrimes/*
3261556Srgrimes * tar_opt()
3271556Srgrimes *	handle tar format specific -o options
3281556Srgrimes * Return:
3291556Srgrimes *	0 if ok -1 otherwise
3301556Srgrimes */
3311556Srgrimes
3321556Srgrimesint
3331556Srgrimestar_opt(void)
3341556Srgrimes{
3351556Srgrimes	OPLIST *opt;
3361556Srgrimes
3371556Srgrimes	while ((opt = opt_next()) != NULL) {
3381556Srgrimes		if (strcmp(opt->name, TAR_OPTION) ||
3391556Srgrimes		    strcmp(opt->value, TAR_NODIR)) {
34076017Skris			paxwarn(1, "Unknown tar format -o option/value pair %s=%s",
3411556Srgrimes			    opt->name, opt->value);
34276017Skris			paxwarn(1,"%s=%s is the only supported tar format option",
3431556Srgrimes			    TAR_OPTION, TAR_NODIR);
3441556Srgrimes			return(-1);
3451556Srgrimes		}
3461556Srgrimes
3471556Srgrimes		/*
3481556Srgrimes		 * we only support one option, and only when writing
3491556Srgrimes		 */
3501556Srgrimes		if ((act != APPND) && (act != ARCHIVE)) {
35176017Skris			paxwarn(1, "%s=%s is only supported when writing.",
3521556Srgrimes			    opt->name, opt->value);
3531556Srgrimes			return(-1);
3541556Srgrimes		}
3551556Srgrimes		tar_nodir = 1;
3561556Srgrimes	}
3571556Srgrimes	return(0);
3581556Srgrimes}
3591556Srgrimes
3601556Srgrimes
3611556Srgrimes/*
3621556Srgrimes * tar_rd()
3631556Srgrimes *	extract the values out of block already determined to be a tar header.
3641556Srgrimes *	store the values in the ARCHD parameter.
3651556Srgrimes * Return:
3661556Srgrimes *	0
3671556Srgrimes */
3681556Srgrimes
3691556Srgrimesint
37090113Simptar_rd(ARCHD *arcn, char *buf)
3711556Srgrimes{
37290113Simp	HD_TAR *hd;
37390113Simp	char *pt;
3741556Srgrimes
3751556Srgrimes	/*
3761556Srgrimes	 * we only get proper sized buffers passed to us
3771556Srgrimes	 */
3781556Srgrimes	if (tar_id(buf, BLKMULT) < 0)
3791556Srgrimes		return(-1);
3801556Srgrimes	arcn->org_name = arcn->name;
3811556Srgrimes	arcn->sb.st_nlink = 1;
3821556Srgrimes	arcn->pat = NULL;
3831556Srgrimes
3841556Srgrimes	/*
3851556Srgrimes	 * copy out the name and values in the stat buffer
3861556Srgrimes	 */
3871556Srgrimes	hd = (HD_TAR *)buf;
388137645Syar	/*
389137645Syar	 * old tar format specifies the name always be null-terminated,
390137645Syar	 * but let's be robust to broken archives.
391137645Syar	 * the same applies to handling links below.
392137645Syar	 */
393137645Syar	arcn->nlen = l_strncpy(arcn->name, hd->name,
394137645Syar	    MIN(sizeof(hd->name), sizeof(arcn->name)) - 1);
3951556Srgrimes	arcn->name[arcn->nlen] = '\0';
3961556Srgrimes	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) &
3971556Srgrimes	    0xfff);
3981556Srgrimes	arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
3991556Srgrimes	arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
40076351Skris#ifdef NET2_STAT
40176351Skris	arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
40285618Sdillon	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
40376351Skris#else
40476351Skris	arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
40585618Sdillon	arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);
40676351Skris#endif
4071556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
4081556Srgrimes
4091556Srgrimes	/*
4101556Srgrimes	 * have to look at the last character, it may be a '/' and that is used
4111556Srgrimes	 * to encode this as a directory
4121556Srgrimes	 */
4131556Srgrimes	pt = &(arcn->name[arcn->nlen - 1]);
4141556Srgrimes	arcn->pad = 0;
4151556Srgrimes	arcn->skip = 0;
4161556Srgrimes	switch(hd->linkflag) {
4171556Srgrimes	case SYMTYPE:
4181556Srgrimes		/*
4191556Srgrimes		 * symbolic link, need to get the link name and set the type in
4201556Srgrimes		 * the st_mode so -v printing will look correct.
4211556Srgrimes		 */
4221556Srgrimes		arcn->type = PAX_SLK;
4231556Srgrimes		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
424137645Syar		    MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1);
4251556Srgrimes		arcn->ln_name[arcn->ln_nlen] = '\0';
4261556Srgrimes		arcn->sb.st_mode |= S_IFLNK;
4271556Srgrimes		break;
4281556Srgrimes	case LNKTYPE:
4291556Srgrimes		/*
4301556Srgrimes		 * hard link, need to get the link name, set the type in the
4311556Srgrimes		 * st_mode and st_nlink so -v printing will look better.
4321556Srgrimes		 */
4331556Srgrimes		arcn->type = PAX_HLK;
4341556Srgrimes		arcn->sb.st_nlink = 2;
4351556Srgrimes		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
436137645Syar		    MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1);
4371556Srgrimes		arcn->ln_name[arcn->ln_nlen] = '\0';
4381556Srgrimes
4391556Srgrimes		/*
4401556Srgrimes		 * no idea of what type this thing really points at, but
4411556Srgrimes		 * we set something for printing only.
4421556Srgrimes		 */
4431556Srgrimes		arcn->sb.st_mode |= S_IFREG;
4441556Srgrimes		break;
44576351Skris	case DIRTYPE:
44676351Skris		/*
44776351Skris		 * It is a directory, set the mode for -v printing
44876351Skris		 */
44976351Skris		arcn->type = PAX_DIR;
45076351Skris		arcn->sb.st_mode |= S_IFDIR;
45176351Skris		arcn->sb.st_nlink = 2;
45276351Skris		arcn->ln_name[0] = '\0';
45376351Skris		arcn->ln_nlen = 0;
45476351Skris		break;
4551556Srgrimes	case AREGTYPE:
4561556Srgrimes	case REGTYPE:
4571556Srgrimes	default:
4581556Srgrimes		/*
4591556Srgrimes		 * If we have a trailing / this is a directory and NOT a file.
4601556Srgrimes		 */
4611556Srgrimes		arcn->ln_name[0] = '\0';
4621556Srgrimes		arcn->ln_nlen = 0;
4631556Srgrimes		if (*pt == '/') {
4641556Srgrimes			/*
4651556Srgrimes			 * it is a directory, set the mode for -v printing
4661556Srgrimes			 */
4671556Srgrimes			arcn->type = PAX_DIR;
4681556Srgrimes			arcn->sb.st_mode |= S_IFDIR;
4691556Srgrimes			arcn->sb.st_nlink = 2;
4701556Srgrimes		} else {
4711556Srgrimes			/*
4721556Srgrimes			 * have a file that will be followed by data. Set the
47346684Skris			 * skip value to the size field and calculate the size
4741556Srgrimes			 * of the padding.
4751556Srgrimes			 */
4761556Srgrimes			arcn->type = PAX_REG;
4771556Srgrimes			arcn->sb.st_mode |= S_IFREG;
4781556Srgrimes			arcn->pad = TAR_PAD(arcn->sb.st_size);
4791556Srgrimes			arcn->skip = arcn->sb.st_size;
4801556Srgrimes		}
4811556Srgrimes		break;
4821556Srgrimes	}
4831556Srgrimes
4841556Srgrimes	/*
4851556Srgrimes	 * strip off any trailing slash.
4861556Srgrimes	 */
4871556Srgrimes	if (*pt == '/') {
4888855Srgrimes		*pt = '\0';
4891556Srgrimes		--arcn->nlen;
4901556Srgrimes	}
4911556Srgrimes	return(0);
4921556Srgrimes}
4931556Srgrimes
4941556Srgrimes/*
4951556Srgrimes * tar_wr()
4961556Srgrimes *	write a tar header for the file specified in the ARCHD to the archive.
4971556Srgrimes *	Have to check for file types that cannot be stored and file names that
4981556Srgrimes *	are too long. Be careful of the term (last arg) to ul_oct, each field
4991556Srgrimes *	of tar has it own spec for the termination character(s).
5001556Srgrimes *	ASSUMED: space after header in header block is zero filled
5011556Srgrimes * Return:
5021556Srgrimes *	0 if file has data to be written after the header, 1 if file has NO
5031556Srgrimes *	data to write after the header, -1 if archive write failed
5041556Srgrimes */
5051556Srgrimes
5061556Srgrimesint
50790113Simptar_wr(ARCHD *arcn)
5081556Srgrimes{
50990113Simp	HD_TAR *hd;
5101556Srgrimes	int len;
511164699Sru	HD_TAR hdblk;
5121556Srgrimes
5131556Srgrimes	/*
514102230Strhodes	 * check for those file system types which tar cannot store
5151556Srgrimes	 */
5161556Srgrimes	switch(arcn->type) {
5171556Srgrimes	case PAX_DIR:
5181556Srgrimes		/*
5191556Srgrimes		 * user asked that dirs not be written to the archive
5201556Srgrimes		 */
5211556Srgrimes		if (tar_nodir)
5221556Srgrimes			return(1);
5231556Srgrimes		break;
5241556Srgrimes	case PAX_CHR:
52576017Skris		paxwarn(1, "Tar cannot archive a character device %s",
5261556Srgrimes		    arcn->org_name);
5271556Srgrimes		return(1);
5281556Srgrimes	case PAX_BLK:
52976017Skris		paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name);
5301556Srgrimes		return(1);
5311556Srgrimes	case PAX_SCK:
53276017Skris		paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name);
5331556Srgrimes		return(1);
5341556Srgrimes	case PAX_FIF:
53576017Skris		paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name);
5361556Srgrimes		return(1);
5371556Srgrimes	case PAX_SLK:
5381556Srgrimes	case PAX_HLK:
5391556Srgrimes	case PAX_HRG:
540137645Syar		if (arcn->ln_nlen >= (int)sizeof(hd->linkname)) {
54176017Skris			paxwarn(1,"Link name too long for tar %s", arcn->ln_name);
5421556Srgrimes			return(1);
5431556Srgrimes		}
5441556Srgrimes		break;
5451556Srgrimes	case PAX_REG:
5461556Srgrimes	case PAX_CTG:
5471556Srgrimes	default:
5481556Srgrimes		break;
5491556Srgrimes	}
5501556Srgrimes
5511556Srgrimes	/*
5521556Srgrimes	 * check file name len, remember extra char for dirs (the / at the end)
5531556Srgrimes	 */
5541556Srgrimes	len = arcn->nlen;
5551556Srgrimes	if (arcn->type == PAX_DIR)
5561556Srgrimes		++len;
557114469Sobrien	if (len >= (int)sizeof(hd->name)) {
55876017Skris		paxwarn(1, "File name too long for tar %s", arcn->name);
5591556Srgrimes		return(1);
5601556Srgrimes	}
5611556Srgrimes
5621556Srgrimes	/*
5631556Srgrimes	 * copy the data out of the ARCHD into the tar header based on the type
5641556Srgrimes	 * of the file. Remember many tar readers want the unused fields to be
5651556Srgrimes	 * padded with zero. We set the linkflag field (type), the linkname
5661556Srgrimes	 * (or zero if not used),the size, and set the padding (if any) to be
5671556Srgrimes	 * added after the file data (0 for all other types, as they only have
5681556Srgrimes	 * a header)
5691556Srgrimes	 */
570164699Sru	hd = &hdblk;
57176351Skris	l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1);
57276351Skris	hd->name[sizeof(hd->name) - 1] = '\0';
5731556Srgrimes	arcn->pad = 0;
5741556Srgrimes
5751556Srgrimes	if (arcn->type == PAX_DIR) {
5761556Srgrimes		/*
5771556Srgrimes		 * directories are the same as files, except have a filename
5781556Srgrimes		 * that ends with a /, we add the slash here. No data follows,
5791556Srgrimes		 * dirs, so no pad.
5801556Srgrimes		 */
5811556Srgrimes		hd->linkflag = AREGTYPE;
58276017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
5831556Srgrimes		hd->name[len-1] = '/';
5841556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
5851556Srgrimes			goto out;
5861556Srgrimes	} else if (arcn->type == PAX_SLK) {
5871556Srgrimes		/*
5881556Srgrimes		 * no data follows this file, so no pad
5891556Srgrimes		 */
5901556Srgrimes		hd->linkflag = SYMTYPE;
59176351Skris		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
59276351Skris		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
5931556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
5941556Srgrimes			goto out;
5951556Srgrimes	} else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {
5961556Srgrimes		/*
5971556Srgrimes		 * no data follows this file, so no pad
5981556Srgrimes		 */
5991556Srgrimes		hd->linkflag = LNKTYPE;
60076351Skris		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
60176351Skris		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
6021556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
6031556Srgrimes			goto out;
6041556Srgrimes	} else {
6051556Srgrimes		/*
6061556Srgrimes		 * data follows this file, so set the pad
6071556Srgrimes		 */
6081556Srgrimes		hd->linkflag = AREGTYPE;
60976017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
6101556Srgrimes#		ifdef NET2_STAT
6111556Srgrimes		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
6121556Srgrimes		    sizeof(hd->size), 1)) {
6131556Srgrimes#		else
6141556Srgrimes		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
6151556Srgrimes		    sizeof(hd->size), 1)) {
6161556Srgrimes#		endif
61776017Skris			paxwarn(1,"File is too large for tar %s", arcn->org_name);
6181556Srgrimes			return(1);
6191556Srgrimes		}
6201556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
6211556Srgrimes	}
6221556Srgrimes
6231556Srgrimes	/*
6241556Srgrimes	 * copy those fields that are independent of the type
6251556Srgrimes	 */
6261556Srgrimes	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) ||
6271556Srgrimes	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) ||
6281556Srgrimes	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) ||
6291556Srgrimes	    ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1))
6301556Srgrimes		goto out;
6311556Srgrimes
6321556Srgrimes	/*
6331556Srgrimes	 * calculate and add the checksum, then write the header. A return of
6341556Srgrimes	 * 0 tells the caller to now write the file data, 1 says no data needs
6351556Srgrimes	 * to be written
6361556Srgrimes	 */
637164699Sru	if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_TAR)), hd->chksum,
63876351Skris	    sizeof(hd->chksum), 3))
6391556Srgrimes		goto out;
640164699Sru	if (wr_rdbuf((char *)&hdblk, sizeof(HD_TAR)) < 0)
6411556Srgrimes		return(-1);
6421556Srgrimes	if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0)
6431556Srgrimes		return(-1);
6441556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
6451556Srgrimes		return(0);
6461556Srgrimes	return(1);
6471556Srgrimes
6481556Srgrimes    out:
6491556Srgrimes	/*
6501556Srgrimes	 * header field is out of range
6511556Srgrimes	 */
65276017Skris	paxwarn(1, "Tar header field is too small for %s", arcn->org_name);
6531556Srgrimes	return(1);
6541556Srgrimes}
6551556Srgrimes
6561556Srgrimes/*
6571556Srgrimes * Routines for POSIX ustar
6581556Srgrimes */
6591556Srgrimes
6601556Srgrimes/*
6611556Srgrimes * ustar_strd()
6621556Srgrimes *	initialization for ustar read
6631556Srgrimes * Return:
6641556Srgrimes *	0 if ok, -1 otherwise
6651556Srgrimes */
6661556Srgrimes
6671556Srgrimesint
6681556Srgrimesustar_strd(void)
6691556Srgrimes{
6701556Srgrimes	if ((usrtb_start() < 0) || (grptb_start() < 0))
6711556Srgrimes		return(-1);
6721556Srgrimes	return(0);
6731556Srgrimes}
6741556Srgrimes
6751556Srgrimes/*
6761556Srgrimes * ustar_stwr()
6771556Srgrimes *	initialization for ustar write
6781556Srgrimes * Return:
6791556Srgrimes *	0 if ok, -1 otherwise
6801556Srgrimes */
6811556Srgrimes
6821556Srgrimesint
6831556Srgrimesustar_stwr(void)
6841556Srgrimes{
6851556Srgrimes	if ((uidtb_start() < 0) || (gidtb_start() < 0))
6861556Srgrimes		return(-1);
6871556Srgrimes	return(0);
6881556Srgrimes}
6891556Srgrimes
6901556Srgrimes/*
6911556Srgrimes * ustar_id()
6921556Srgrimes *	determine if a block given to us is a valid ustar header. We have to
6931556Srgrimes *	be on the lookout for those pesky blocks of all zero's
6941556Srgrimes * Return:
6951556Srgrimes *	0 if a ustar header, -1 otherwise
6961556Srgrimes */
6971556Srgrimes
6981556Srgrimesint
6991556Srgrimesustar_id(char *blk, int size)
7001556Srgrimes{
70190113Simp	HD_USTAR *hd;
7021556Srgrimes
7031556Srgrimes	if (size < BLKMULT)
7041556Srgrimes		return(-1);
7051556Srgrimes	hd = (HD_USTAR *)blk;
7061556Srgrimes
7071556Srgrimes	/*
7081556Srgrimes	 * check for block of zero's first, a simple and fast test then check
7091556Srgrimes	 * ustar magic cookie. We should use TMAGLEN, but some USTAR archive
7101556Srgrimes	 * programs are fouled up and create archives missing the \0. Last we
7111556Srgrimes	 * check the checksum. If ok we have to assume it is a valid header.
7121556Srgrimes	 */
7131556Srgrimes	if (hd->name[0] == '\0')
7141556Srgrimes		return(-1);
7151556Srgrimes	if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)
7161556Srgrimes		return(-1);
7171556Srgrimes	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
7181556Srgrimes		return(-1);
7191556Srgrimes	return(0);
7201556Srgrimes}
7211556Srgrimes
7221556Srgrimes/*
7231556Srgrimes * ustar_rd()
7241556Srgrimes *	extract the values out of block already determined to be a ustar header.
7251556Srgrimes *	store the values in the ARCHD parameter.
7261556Srgrimes * Return:
7271556Srgrimes *	0
7281556Srgrimes */
7291556Srgrimes
7301556Srgrimesint
73190113Simpustar_rd(ARCHD *arcn, char *buf)
7321556Srgrimes{
73390113Simp	HD_USTAR *hd;
73490113Simp	char *dest;
73590113Simp	int cnt = 0;
7361556Srgrimes	dev_t devmajor;
7371556Srgrimes	dev_t devminor;
7381556Srgrimes
7391556Srgrimes	/*
7401556Srgrimes	 * we only get proper sized buffers
7411556Srgrimes	 */
7421556Srgrimes	if (ustar_id(buf, BLKMULT) < 0)
7431556Srgrimes		return(-1);
7441556Srgrimes	arcn->org_name = arcn->name;
7451556Srgrimes	arcn->sb.st_nlink = 1;
7461556Srgrimes	arcn->pat = NULL;
74776351Skris	arcn->nlen = 0;
7481556Srgrimes	hd = (HD_USTAR *)buf;
7491556Srgrimes
7501556Srgrimes	/*
7511556Srgrimes	 * see if the filename is split into two parts. if, so joint the parts.
7521556Srgrimes	 * we copy the prefix first and add a / between the prefix and name.
7531556Srgrimes	 */
7541556Srgrimes	dest = arcn->name;
7551556Srgrimes	if (*(hd->prefix) != '\0') {
756137645Syar		cnt = l_strncpy(dest, hd->prefix,
757137645Syar		    MIN(sizeof(hd->prefix), sizeof(arcn->name) - 2));
75876351Skris		dest += cnt;
7591556Srgrimes		*dest++ = '/';
76076351Skris		cnt++;
7611556Srgrimes	}
762137645Syar	/*
763137645Syar	 * ustar format specifies the name may be unterminated
764137645Syar	 * if it fills the entire field.  this also applies to
765137645Syar	 * the prefix and the linkname.
766137645Syar	 */
767137645Syar	arcn->nlen = cnt + l_strncpy(dest, hd->name,
768137645Syar	    MIN(sizeof(hd->name), sizeof(arcn->name) - cnt - 1));
7691556Srgrimes	arcn->name[arcn->nlen] = '\0';
7701556Srgrimes
7711556Srgrimes	/*
7721556Srgrimes	 * follow the spec to the letter. we should only have mode bits, strip
7731556Srgrimes	 * off all other crud we may be passed.
7741556Srgrimes	 */
7751556Srgrimes	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
7761556Srgrimes	    0xfff);
77776351Skris#ifdef NET2_STAT
77876351Skris	arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
77985618Sdillon	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
78076351Skris#else
78176351Skris	arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
78285618Sdillon	arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);
78376351Skris#endif
7841556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
7851556Srgrimes
7861556Srgrimes	/*
7871556Srgrimes	 * If we can find the ascii names for gname and uname in the password
7881556Srgrimes	 * and group files we will use the uid's and gid they bind. Otherwise
7891556Srgrimes	 * we use the uid and gid values stored in the header. (This is what
79046684Skris	 * the POSIX spec wants).
7911556Srgrimes	 */
7921556Srgrimes	hd->gname[sizeof(hd->gname) - 1] = '\0';
7931556Srgrimes	if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)
7941556Srgrimes		arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
7951556Srgrimes	hd->uname[sizeof(hd->uname) - 1] = '\0';
7961556Srgrimes	if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
7971556Srgrimes		arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
7981556Srgrimes
7991556Srgrimes	/*
8001556Srgrimes	 * set the defaults, these may be changed depending on the file type
8011556Srgrimes	 */
8021556Srgrimes	arcn->ln_name[0] = '\0';
8031556Srgrimes	arcn->ln_nlen = 0;
8041556Srgrimes	arcn->pad = 0;
8051556Srgrimes	arcn->skip = 0;
8061556Srgrimes	arcn->sb.st_rdev = (dev_t)0;
8071556Srgrimes
8081556Srgrimes	/*
8091556Srgrimes	 * set the mode and PAX type according to the typeflag in the header
8101556Srgrimes	 */
8111556Srgrimes	switch(hd->typeflag) {
8121556Srgrimes	case FIFOTYPE:
8131556Srgrimes		arcn->type = PAX_FIF;
8141556Srgrimes		arcn->sb.st_mode |= S_IFIFO;
8151556Srgrimes		break;
8161556Srgrimes	case DIRTYPE:
8171556Srgrimes		arcn->type = PAX_DIR;
8181556Srgrimes		arcn->sb.st_mode |= S_IFDIR;
8191556Srgrimes		arcn->sb.st_nlink = 2;
8201556Srgrimes
8211556Srgrimes		/*
8221556Srgrimes		 * Some programs that create ustar archives append a '/'
8231556Srgrimes		 * to the pathname for directories. This clearly violates
8241556Srgrimes		 * ustar specs, but we will silently strip it off anyway.
8251556Srgrimes		 */
8261556Srgrimes		if (arcn->name[arcn->nlen - 1] == '/')
8271556Srgrimes			arcn->name[--arcn->nlen] = '\0';
8281556Srgrimes		break;
8291556Srgrimes	case BLKTYPE:
8301556Srgrimes	case CHRTYPE:
8311556Srgrimes		/*
8321556Srgrimes		 * this type requires the rdev field to be set.
8331556Srgrimes		 */
8341556Srgrimes		if (hd->typeflag == BLKTYPE) {
8351556Srgrimes			arcn->type = PAX_BLK;
8361556Srgrimes			arcn->sb.st_mode |= S_IFBLK;
8371556Srgrimes		} else {
8381556Srgrimes			arcn->type = PAX_CHR;
8391556Srgrimes			arcn->sb.st_mode |= S_IFCHR;
8401556Srgrimes		}
8411556Srgrimes		devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
8421556Srgrimes		devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
8431556Srgrimes		arcn->sb.st_rdev = TODEV(devmajor, devminor);
8441556Srgrimes		break;
8451556Srgrimes	case SYMTYPE:
8461556Srgrimes	case LNKTYPE:
8471556Srgrimes		if (hd->typeflag == SYMTYPE) {
8481556Srgrimes			arcn->type = PAX_SLK;
8491556Srgrimes			arcn->sb.st_mode |= S_IFLNK;
8501556Srgrimes		} else {
8511556Srgrimes			arcn->type = PAX_HLK;
8521556Srgrimes			/*
8531556Srgrimes			 * so printing looks better
8541556Srgrimes			 */
8551556Srgrimes			arcn->sb.st_mode |= S_IFREG;
8561556Srgrimes			arcn->sb.st_nlink = 2;
8571556Srgrimes		}
8581556Srgrimes		/*
8591556Srgrimes		 * copy the link name
8601556Srgrimes		 */
8611556Srgrimes		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
862137645Syar		    MIN(sizeof(hd->linkname), sizeof(arcn->ln_name) - 1));
8631556Srgrimes		arcn->ln_name[arcn->ln_nlen] = '\0';
8641556Srgrimes		break;
8651556Srgrimes	case CONTTYPE:
8661556Srgrimes	case AREGTYPE:
8671556Srgrimes	case REGTYPE:
8681556Srgrimes	default:
8691556Srgrimes		/*
8701556Srgrimes		 * these types have file data that follows. Set the skip and
8711556Srgrimes		 * pad fields.
8721556Srgrimes		 */
8731556Srgrimes		arcn->type = PAX_REG;
8741556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
8751556Srgrimes		arcn->skip = arcn->sb.st_size;
8761556Srgrimes		arcn->sb.st_mode |= S_IFREG;
8771556Srgrimes		break;
8781556Srgrimes	}
8791556Srgrimes	return(0);
8801556Srgrimes}
8811556Srgrimes
8821556Srgrimes/*
8831556Srgrimes * ustar_wr()
8841556Srgrimes *	write a ustar header for the file specified in the ARCHD to the archive
8851556Srgrimes *	Have to check for file types that cannot be stored and file names that
8861556Srgrimes *	are too long. Be careful of the term (last arg) to ul_oct, we only use
8871556Srgrimes *	'\0' for the termination character (this is different than picky tar)
8881556Srgrimes *	ASSUMED: space after header in header block is zero filled
8891556Srgrimes * Return:
8901556Srgrimes *	0 if file has data to be written after the header, 1 if file has NO
8911556Srgrimes *	data to write after the header, -1 if archive write failed
8921556Srgrimes */
8931556Srgrimes
8941556Srgrimesint
89590113Simpustar_wr(ARCHD *arcn)
8961556Srgrimes{
89790113Simp	HD_USTAR *hd;
89890113Simp	char *pt;
899164699Sru	HD_USTAR hdblk;
9001556Srgrimes
9011556Srgrimes	/*
902102230Strhodes	 * check for those file system types ustar cannot store
9031556Srgrimes	 */
9041556Srgrimes	if (arcn->type == PAX_SCK) {
90576017Skris		paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name);
9061556Srgrimes		return(1);
9071556Srgrimes	}
9081556Srgrimes
9091556Srgrimes	/*
9101556Srgrimes	 * check the length of the linkname
9111556Srgrimes	 */
9121556Srgrimes	if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
913114469Sobrien	    (arcn->type == PAX_HRG)) &&
914137645Syar	    (arcn->ln_nlen > (int)sizeof(hd->linkname))) {
91576017Skris		paxwarn(1, "Link name too long for ustar %s", arcn->ln_name);
9161556Srgrimes		return(1);
9171556Srgrimes	}
9181556Srgrimes
9191556Srgrimes	/*
9201556Srgrimes	 * split the path name into prefix and name fields (if needed). if
9211556Srgrimes	 * pt != arcn->name, the name has to be split
9221556Srgrimes	 */
9231556Srgrimes	if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
92476017Skris		paxwarn(1, "File name too long for ustar %s", arcn->name);
9251556Srgrimes		return(1);
9261556Srgrimes	}
927164699Sru	hd = &hdblk;
9281556Srgrimes	arcn->pad = 0L;
9291556Srgrimes
9301556Srgrimes	/*
9311556Srgrimes	 * split the name, or zero out the prefix
9321556Srgrimes	 */
9331556Srgrimes	if (pt != arcn->name) {
9341556Srgrimes		/*
9351556Srgrimes		 * name was split, pt points at the / where the split is to
9361556Srgrimes		 * occur, we remove the / and copy the first part to the prefix
9371556Srgrimes		 */
9381556Srgrimes		*pt = '\0';
939137645Syar		l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix));
9401556Srgrimes		*pt++ = '/';
9411556Srgrimes	} else
94276017Skris		memset(hd->prefix, 0, sizeof(hd->prefix));
9431556Srgrimes
9441556Srgrimes	/*
9451556Srgrimes	 * copy the name part. this may be the whole path or the part after
946137645Syar	 * the prefix.  both the name and prefix may fill the entire field.
9471556Srgrimes	 */
948137645Syar	l_strncpy(hd->name, pt, sizeof(hd->name));
9491556Srgrimes
9508855Srgrimes	/*
9511556Srgrimes	 * set the fields in the header that are type dependent
9521556Srgrimes	 */
9531556Srgrimes	switch(arcn->type) {
9541556Srgrimes	case PAX_DIR:
9551556Srgrimes		hd->typeflag = DIRTYPE;
95676017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
95776017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
95876017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
9591556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9601556Srgrimes			goto out;
9611556Srgrimes		break;
9621556Srgrimes	case PAX_CHR:
9631556Srgrimes	case PAX_BLK:
9641556Srgrimes		if (arcn->type == PAX_CHR)
9651556Srgrimes			hd->typeflag = CHRTYPE;
9661556Srgrimes		else
9671556Srgrimes			hd->typeflag = BLKTYPE;
96876017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
9691556Srgrimes		if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,
9701556Srgrimes		   sizeof(hd->devmajor), 3) ||
9711556Srgrimes		   ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,
9721556Srgrimes		   sizeof(hd->devminor), 3) ||
9731556Srgrimes		   ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9741556Srgrimes			goto out;
9751556Srgrimes		break;
9761556Srgrimes	case PAX_FIF:
9771556Srgrimes		hd->typeflag = FIFOTYPE;
97876017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
97976017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
98076017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
9811556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9821556Srgrimes			goto out;
9831556Srgrimes		break;
9841556Srgrimes	case PAX_SLK:
9851556Srgrimes	case PAX_HLK:
9861556Srgrimes	case PAX_HRG:
9871556Srgrimes		if (arcn->type == PAX_SLK)
9881556Srgrimes			hd->typeflag = SYMTYPE;
9891556Srgrimes		else
9901556Srgrimes			hd->typeflag = LNKTYPE;
991137645Syar		/* the link name may occupy the entire field in ustar */
992137645Syar		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname));
99376017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
99476017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
9951556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9961556Srgrimes			goto out;
9971556Srgrimes		break;
9981556Srgrimes	case PAX_REG:
9991556Srgrimes	case PAX_CTG:
10001556Srgrimes	default:
10011556Srgrimes		/*
10021556Srgrimes		 * file data with this type, set the padding
10031556Srgrimes		 */
10041556Srgrimes		if (arcn->type == PAX_CTG)
10051556Srgrimes			hd->typeflag = CONTTYPE;
10061556Srgrimes		else
10071556Srgrimes			hd->typeflag = REGTYPE;
100876017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
100976017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
101076017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
10111556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
10121556Srgrimes#		ifdef NET2_STAT
10131556Srgrimes		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
10141556Srgrimes		    sizeof(hd->size), 3)) {
10151556Srgrimes#		else
10161556Srgrimes		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
10171556Srgrimes		    sizeof(hd->size), 3)) {
10181556Srgrimes#		endif
101976017Skris			paxwarn(1,"File is too long for ustar %s",arcn->org_name);
10201556Srgrimes			return(1);
10211556Srgrimes		}
10221556Srgrimes		break;
10231556Srgrimes	}
10241556Srgrimes
102576351Skris	l_strncpy(hd->magic, TMAGIC, TMAGLEN);
102676351Skris	l_strncpy(hd->version, TVERSION, TVERSLEN);
10271556Srgrimes
10281556Srgrimes	/*
10291556Srgrimes	 * set the remaining fields. Some versions want all 16 bits of mode
10301556Srgrimes	 * we better humor them (they really do not meet spec though)....
10311556Srgrimes	 */
10321556Srgrimes	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) ||
10331556Srgrimes	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3)  ||
10341556Srgrimes	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) ||
10351556Srgrimes	    ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3))
10361556Srgrimes		goto out;
103776351Skris	l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname));
103876351Skris	l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname));
10391556Srgrimes
10401556Srgrimes	/*
10411556Srgrimes	 * calculate and store the checksum write the header to the archive
10421556Srgrimes	 * return 0 tells the caller to now write the file data, 1 says no data
10431556Srgrimes	 * needs to be written
10441556Srgrimes	 */
1045164699Sru	if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_USTAR)), hd->chksum,
10461556Srgrimes	   sizeof(hd->chksum), 3))
10471556Srgrimes		goto out;
1048164699Sru	if (wr_rdbuf((char *)&hdblk, sizeof(HD_USTAR)) < 0)
10491556Srgrimes		return(-1);
10501556Srgrimes	if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
10511556Srgrimes		return(-1);
10521556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
10531556Srgrimes		return(0);
10541556Srgrimes	return(1);
10551556Srgrimes
10561556Srgrimes    out:
10571556Srgrimes    	/*
10581556Srgrimes	 * header field is out of range
10591556Srgrimes	 */
106076017Skris	paxwarn(1, "Ustar header field is too small for %s", arcn->org_name);
10611556Srgrimes	return(1);
10621556Srgrimes}
10631556Srgrimes
10641556Srgrimes/*
10651556Srgrimes * name_split()
10661556Srgrimes *	see if the name has to be split for storage in a ustar header. We try
10671556Srgrimes *	to fit the entire name in the name field without splitting if we can.
10681556Srgrimes *	The split point is always at a /
10691556Srgrimes * Return
10701556Srgrimes *	character pointer to split point (always the / that is to be removed
10711556Srgrimes *	if the split is not needed, the points is set to the start of the file
10721556Srgrimes *	name (it would violate the spec to split there). A NULL is returned if
10731556Srgrimes *	the file name is too long
10741556Srgrimes */
10751556Srgrimes
10761556Srgrimesstatic char *
107790113Simpname_split(char *name, int len)
10781556Srgrimes{
107990113Simp	char *start;
10801556Srgrimes
10811556Srgrimes	/*
10821556Srgrimes	 * check to see if the file name is small enough to fit in the name
10831556Srgrimes	 * field. if so just return a pointer to the name.
10841556Srgrimes	 */
1085137645Syar	if (len <= TNMSZ)
10861556Srgrimes		return(name);
1087211963Sbrian	if (len > TPFSZ + TNMSZ)
10881556Srgrimes		return(NULL);
10891556Srgrimes
10901556Srgrimes	/*
10911556Srgrimes	 * we start looking at the biggest sized piece that fits in the name
109246684Skris	 * field. We walk forward looking for a slash to split at. The idea is
10931556Srgrimes	 * to find the biggest piece to fit in the name field (or the smallest
109440533Smsmith	 * prefix we can find)
10951556Srgrimes	 */
1096211864Sbrian	start = name + len - TNMSZ;
10971556Srgrimes	while ((*start != '\0') && (*start != '/'))
10981556Srgrimes		++start;
10991556Srgrimes
11001556Srgrimes	/*
11011556Srgrimes	 * if we hit the end of the string, this name cannot be split, so we
11021556Srgrimes	 * cannot store this file.
11031556Srgrimes	 */
11041556Srgrimes	if (*start == '\0')
11051556Srgrimes		return(NULL);
11061556Srgrimes	len = start - name;
11071556Srgrimes
11081556Srgrimes	/*
11091556Srgrimes	 * NOTE: /str where the length of str == TNMSZ can not be stored under
11101556Srgrimes	 * the p1003.1-1990 spec for ustar. We could force a prefix of / and
11111556Srgrimes	 * the file would then expand on extract to //str. The len == 0 below
11121556Srgrimes	 * makes this special case follow the spec to the letter.
11131556Srgrimes	 */
1114137645Syar	if ((len > TPFSZ) || (len == 0))
11151556Srgrimes		return(NULL);
11161556Srgrimes
11171556Srgrimes	/*
11181556Srgrimes	 * ok have a split point, return it to the caller
11191556Srgrimes	 */
11201556Srgrimes	return(start);
11211556Srgrimes}
1122