tar.c revision 90113
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[] =
4350471Speter  "$FreeBSD: head/bin/pax/tar.c 90113 2002-02-02 07:07:59Z imp $";
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
6190113Simpstatic u_long tar_chksm(char *, int);
6290113Simpstatic char *name_split(char *, int);
6390113Simpstatic int ul_oct(u_long, char *, int, int);
641556Srgrimes#ifndef NET2_STAT
6590113Simpstatic int uqd_oct(u_quad_t, char *, 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
811556Srgrimesint
821556Srgrimestar_endwr(void)
831556Srgrimes{
841556Srgrimes	return(wr_skip((off_t)(NULLCNT*BLKMULT)));
851556Srgrimes}
861556Srgrimes
871556Srgrimes/*
881556Srgrimes * tar_endrd()
891556Srgrimes *	no cleanup needed here, just return size of trailer (for append)
901556Srgrimes * Return:
911556Srgrimes *	size of trailer (2 * BLKMULT)
921556Srgrimes */
931556Srgrimes
941556Srgrimesoff_t
951556Srgrimestar_endrd(void)
961556Srgrimes{
971556Srgrimes	return((off_t)(NULLCNT*BLKMULT));
981556Srgrimes}
991556Srgrimes
1001556Srgrimes/*
1011556Srgrimes * tar_trail()
1021556Srgrimes *	Called to determine if a header block is a valid trailer. We are passed
1031556Srgrimes *	the block, the in_sync flag (which tells us we are in resync mode;
1041556Srgrimes *	looking for a valid header), and cnt (which starts at zero) which is
1051556Srgrimes *	used to count the number of empty blocks we have seen so far.
1061556Srgrimes * Return:
1071556Srgrimes *	0 if a valid trailer, -1 if not a valid trailer, or 1 if the block
1081556Srgrimes *	could never contain a header.
1091556Srgrimes */
1101556Srgrimes
1111556Srgrimesint
11290113Simptar_trail(char *buf, int in_resync, int *cnt)
1131556Srgrimes{
11490113Simp	int i;
1151556Srgrimes
1161556Srgrimes	/*
1171556Srgrimes	 * look for all zero, trailer is two consecutive blocks of zero
1181556Srgrimes	 */
1191556Srgrimes	for (i = 0; i < BLKMULT; ++i) {
1201556Srgrimes		if (buf[i] != '\0')
1211556Srgrimes			break;
1221556Srgrimes	}
1231556Srgrimes
1241556Srgrimes	/*
1251556Srgrimes	 * if not all zero it is not a trailer, but MIGHT be a header.
1261556Srgrimes	 */
1271556Srgrimes	if (i != BLKMULT)
1281556Srgrimes		return(-1);
1291556Srgrimes
1301556Srgrimes	/*
1311556Srgrimes	 * When given a zero block, we must be careful!
1321556Srgrimes	 * If we are not in resync mode, check for the trailer. Have to watch
1331556Srgrimes	 * out that we do not mis-identify file data as the trailer, so we do
1341556Srgrimes	 * NOT try to id a trailer during resync mode. During resync mode we
1351556Srgrimes	 * might as well throw this block out since a valid header can NEVER be
1361556Srgrimes	 * a block of all 0 (we must have a valid file name).
1371556Srgrimes	 */
1381556Srgrimes	if (!in_resync && (++*cnt >= NULLCNT))
1391556Srgrimes		return(0);
1401556Srgrimes	return(1);
1411556Srgrimes}
1421556Srgrimes
1431556Srgrimes/*
1441556Srgrimes * ul_oct()
1451556Srgrimes *	convert an unsigned long to an octal string. many oddball field
1461556Srgrimes *	termination characters are used by the various versions of tar in the
14776351Skris *	different fields. term selects which kind to use. str is '0' padded
1481556Srgrimes *	at the front to len. we are unable to use only one format as many old
1491556Srgrimes *	tar readers are very cranky about this.
1501556Srgrimes * Return:
1511556Srgrimes *	0 if the number fit into the string, -1 otherwise
1521556Srgrimes */
1531556Srgrimes
1541556Srgrimesstatic int
15590113Simpul_oct(u_long val, char *str, int len, int term)
1561556Srgrimes{
15790113Simp	char *pt;
1588855Srgrimes
1591556Srgrimes	/*
1601556Srgrimes	 * term selects the appropriate character(s) for the end of the string
1611556Srgrimes	 */
1621556Srgrimes	pt = str + len - 1;
1631556Srgrimes	switch(term) {
1641556Srgrimes	case 3:
1651556Srgrimes		*pt-- = '\0';
1661556Srgrimes		break;
1671556Srgrimes	case 2:
1681556Srgrimes		*pt-- = ' ';
1691556Srgrimes		*pt-- = '\0';
1701556Srgrimes		break;
1711556Srgrimes	case 1:
1721556Srgrimes		*pt-- = ' ';
1731556Srgrimes		break;
1741556Srgrimes	case 0:
1751556Srgrimes	default:
1761556Srgrimes		*pt-- = '\0';
1771556Srgrimes		*pt-- = ' ';
1781556Srgrimes		break;
1791556Srgrimes	}
1801556Srgrimes
1811556Srgrimes	/*
1821556Srgrimes	 * convert and blank pad if there is space
1831556Srgrimes	 */
1841556Srgrimes	while (pt >= str) {
1851556Srgrimes		*pt-- = '0' + (char)(val & 0x7);
1861556Srgrimes		if ((val = val >> 3) == (u_long)0)
1871556Srgrimes			break;
1881556Srgrimes	}
1891556Srgrimes
1901556Srgrimes	while (pt >= str)
19176351Skris		*pt-- = '0';
1921556Srgrimes	if (val != (u_long)0)
1931556Srgrimes		return(-1);
1941556Srgrimes	return(0);
1951556Srgrimes}
1961556Srgrimes
1971556Srgrimes#ifndef NET2_STAT
1981556Srgrimes/*
1991556Srgrimes * uqd_oct()
2001556Srgrimes *	convert an u_quad_t to an octal string. one of many oddball field
2011556Srgrimes *	termination characters are used by the various versions of tar in the
20276351Skris *	different fields. term selects which kind to use. str is '0' padded
2031556Srgrimes *	at the front to len. we are unable to use only one format as many old
2041556Srgrimes *	tar readers are very cranky about this.
2051556Srgrimes * Return:
2061556Srgrimes *	0 if the number fit into the string, -1 otherwise
2071556Srgrimes */
2081556Srgrimes
2091556Srgrimesstatic int
21090113Simpuqd_oct(u_quad_t val, char *str, int len, int term)
2111556Srgrimes{
21290113Simp	char *pt;
2138855Srgrimes
2141556Srgrimes	/*
2151556Srgrimes	 * term selects the appropriate character(s) for the end of the string
2161556Srgrimes	 */
2171556Srgrimes	pt = str + len - 1;
2181556Srgrimes	switch(term) {
2191556Srgrimes	case 3:
2201556Srgrimes		*pt-- = '\0';
2211556Srgrimes		break;
2221556Srgrimes	case 2:
2231556Srgrimes		*pt-- = ' ';
2241556Srgrimes		*pt-- = '\0';
2251556Srgrimes		break;
2261556Srgrimes	case 1:
2271556Srgrimes		*pt-- = ' ';
2281556Srgrimes		break;
2291556Srgrimes	case 0:
2301556Srgrimes	default:
2311556Srgrimes		*pt-- = '\0';
2321556Srgrimes		*pt-- = ' ';
2331556Srgrimes		break;
2341556Srgrimes	}
2351556Srgrimes
2361556Srgrimes	/*
2371556Srgrimes	 * convert and blank pad if there is space
2381556Srgrimes	 */
2391556Srgrimes	while (pt >= str) {
2401556Srgrimes		*pt-- = '0' + (char)(val & 0x7);
2411556Srgrimes		if ((val = val >> 3) == 0)
2421556Srgrimes			break;
2431556Srgrimes	}
2441556Srgrimes
2451556Srgrimes	while (pt >= str)
24676351Skris		*pt-- = '0';
2471556Srgrimes	if (val != (u_quad_t)0)
2481556Srgrimes		return(-1);
2491556Srgrimes	return(0);
2501556Srgrimes}
2511556Srgrimes#endif
2521556Srgrimes
2531556Srgrimes/*
2541556Srgrimes * tar_chksm()
2551556Srgrimes *	calculate the checksum for a tar block counting the checksum field as
25646684Skris *	all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks).
2571556Srgrimes *	NOTE: we use len to short circuit summing 0's on write since we ALWAYS
2581556Srgrimes *	pad headers with 0.
2591556Srgrimes * Return:
2601556Srgrimes *	unsigned long checksum
2611556Srgrimes */
2621556Srgrimes
2631556Srgrimesstatic u_long
26490113Simptar_chksm(char *blk, int len)
2651556Srgrimes{
26690113Simp	char *stop;
26790113Simp	char *pt;
26846684Skris	u_long chksm = BLNKSUM;	/* initial value is checksum field sum */
2691556Srgrimes
2701556Srgrimes	/*
2711556Srgrimes	 * add the part of the block before the checksum field
2721556Srgrimes	 */
2731556Srgrimes	pt = blk;
2741556Srgrimes	stop = blk + CHK_OFFSET;
2758855Srgrimes	while (pt < stop)
2768855Srgrimes		chksm += (u_long)(*pt++ & 0xff);
2771556Srgrimes	/*
2781556Srgrimes	 * move past the checksum field and keep going, spec counts the
2791556Srgrimes	 * checksum field as the sum of 8 blanks (which is pre-computed as
2801556Srgrimes	 * BLNKSUM).
2811556Srgrimes	 * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding
2821556Srgrimes	 * starts, no point in summing zero's)
2831556Srgrimes	 */
2841556Srgrimes	pt += CHK_LEN;
2851556Srgrimes	stop = blk + len;
2861556Srgrimes	while (pt < stop)
2878855Srgrimes		chksm += (u_long)(*pt++ & 0xff);
2881556Srgrimes	return(chksm);
2891556Srgrimes}
2901556Srgrimes
2911556Srgrimes/*
2921556Srgrimes * Routines for old BSD style tar (also made portable to sysV tar)
2931556Srgrimes */
2941556Srgrimes
2951556Srgrimes/*
2961556Srgrimes * tar_id()
2971556Srgrimes *	determine if a block given to us is a valid tar header (and not a USTAR
2981556Srgrimes *	header). We have to be on the lookout for those pesky blocks of	all
2991556Srgrimes *	zero's.
3001556Srgrimes * Return:
3011556Srgrimes *	0 if a tar header, -1 otherwise
3021556Srgrimes */
3031556Srgrimes
3041556Srgrimesint
30590113Simptar_id(char *blk, int size)
3061556Srgrimes{
30790113Simp	HD_TAR *hd;
30890113Simp	HD_USTAR *uhd;
3091556Srgrimes
3101556Srgrimes	if (size < BLKMULT)
3111556Srgrimes		return(-1);
3121556Srgrimes	hd = (HD_TAR *)blk;
3131556Srgrimes	uhd = (HD_USTAR *)blk;
3141556Srgrimes
3151556Srgrimes	/*
3161556Srgrimes	 * check for block of zero's first, a simple and fast test, then make
3171556Srgrimes	 * sure this is not a ustar header by looking for the ustar magic
3181556Srgrimes	 * cookie. We should use TMAGLEN, but some USTAR archive programs are
3191556Srgrimes	 * wrong and create archives missing the \0. Last we check the
3201556Srgrimes	 * checksum. If this is ok we have to assume it is a valid header.
3211556Srgrimes	 */
3221556Srgrimes	if (hd->name[0] == '\0')
3231556Srgrimes		return(-1);
3241556Srgrimes	if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0)
3251556Srgrimes		return(-1);
3261556Srgrimes	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
3271556Srgrimes		return(-1);
3281556Srgrimes	return(0);
3291556Srgrimes}
3301556Srgrimes
3311556Srgrimes/*
3321556Srgrimes * tar_opt()
3331556Srgrimes *	handle tar format specific -o options
3341556Srgrimes * Return:
3351556Srgrimes *	0 if ok -1 otherwise
3361556Srgrimes */
3371556Srgrimes
3381556Srgrimesint
3391556Srgrimestar_opt(void)
3401556Srgrimes{
3411556Srgrimes	OPLIST *opt;
3421556Srgrimes
3431556Srgrimes	while ((opt = opt_next()) != NULL) {
3441556Srgrimes		if (strcmp(opt->name, TAR_OPTION) ||
3451556Srgrimes		    strcmp(opt->value, TAR_NODIR)) {
34676017Skris			paxwarn(1, "Unknown tar format -o option/value pair %s=%s",
3471556Srgrimes			    opt->name, opt->value);
34876017Skris			paxwarn(1,"%s=%s is the only supported tar format option",
3491556Srgrimes			    TAR_OPTION, TAR_NODIR);
3501556Srgrimes			return(-1);
3511556Srgrimes		}
3521556Srgrimes
3531556Srgrimes		/*
3541556Srgrimes		 * we only support one option, and only when writing
3551556Srgrimes		 */
3561556Srgrimes		if ((act != APPND) && (act != ARCHIVE)) {
35776017Skris			paxwarn(1, "%s=%s is only supported when writing.",
3581556Srgrimes			    opt->name, opt->value);
3591556Srgrimes			return(-1);
3601556Srgrimes		}
3611556Srgrimes		tar_nodir = 1;
3621556Srgrimes	}
3631556Srgrimes	return(0);
3641556Srgrimes}
3651556Srgrimes
3661556Srgrimes
3671556Srgrimes/*
3681556Srgrimes * tar_rd()
3691556Srgrimes *	extract the values out of block already determined to be a tar header.
3701556Srgrimes *	store the values in the ARCHD parameter.
3711556Srgrimes * Return:
3721556Srgrimes *	0
3731556Srgrimes */
3741556Srgrimes
3751556Srgrimesint
37690113Simptar_rd(ARCHD *arcn, char *buf)
3771556Srgrimes{
37890113Simp	HD_TAR *hd;
37990113Simp	char *pt;
3801556Srgrimes
3811556Srgrimes	/*
3821556Srgrimes	 * we only get proper sized buffers passed to us
3831556Srgrimes	 */
3841556Srgrimes	if (tar_id(buf, BLKMULT) < 0)
3851556Srgrimes		return(-1);
3861556Srgrimes	arcn->org_name = arcn->name;
3871556Srgrimes	arcn->sb.st_nlink = 1;
3881556Srgrimes	arcn->pat = NULL;
3891556Srgrimes
3901556Srgrimes	/*
3911556Srgrimes	 * copy out the name and values in the stat buffer
3921556Srgrimes	 */
3931556Srgrimes	hd = (HD_TAR *)buf;
39476351Skris	arcn->nlen = l_strncpy(arcn->name, 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,
42476351Skris			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,
43676351Skris			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;
5111556Srgrimes	char hdblk[sizeof(HD_TAR)];
5121556Srgrimes
5131556Srgrimes	/*
5141556Srgrimes	 * 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:
5401556Srgrimes		if (arcn->ln_nlen > 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;
55776351Skris	if (len >= 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	 */
5701556Srgrimes	hd = (HD_TAR *)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	 */
6371556Srgrimes	if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum,
63876351Skris	    sizeof(hd->chksum), 3))
6391556Srgrimes		goto out;
6401556Srgrimes	if (wr_rdbuf(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') {
75676351Skris		cnt = l_strncpy(dest, hd->prefix, sizeof(arcn->name) - 2);
75776351Skris		dest += cnt;
7581556Srgrimes		*dest++ = '/';
75976351Skris		cnt++;
7601556Srgrimes	}
76176351Skris	arcn->nlen = cnt + l_strncpy(dest, hd->name, sizeof(arcn->name) - cnt);
7621556Srgrimes	arcn->name[arcn->nlen] = '\0';
7631556Srgrimes
7641556Srgrimes	/*
7651556Srgrimes	 * follow the spec to the letter. we should only have mode bits, strip
7661556Srgrimes	 * off all other crud we may be passed.
7671556Srgrimes	 */
7681556Srgrimes	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
7691556Srgrimes	    0xfff);
77076351Skris#ifdef NET2_STAT
77176351Skris	arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
77285618Sdillon	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
77376351Skris#else
77476351Skris	arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
77585618Sdillon	arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);
77676351Skris#endif
7771556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
7781556Srgrimes
7791556Srgrimes	/*
7801556Srgrimes	 * If we can find the ascii names for gname and uname in the password
7811556Srgrimes	 * and group files we will use the uid's and gid they bind. Otherwise
7821556Srgrimes	 * we use the uid and gid values stored in the header. (This is what
78346684Skris	 * the POSIX spec wants).
7841556Srgrimes	 */
7851556Srgrimes	hd->gname[sizeof(hd->gname) - 1] = '\0';
7861556Srgrimes	if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)
7871556Srgrimes		arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
7881556Srgrimes	hd->uname[sizeof(hd->uname) - 1] = '\0';
7891556Srgrimes	if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
7901556Srgrimes		arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
7911556Srgrimes
7921556Srgrimes	/*
7931556Srgrimes	 * set the defaults, these may be changed depending on the file type
7941556Srgrimes	 */
7951556Srgrimes	arcn->ln_name[0] = '\0';
7961556Srgrimes	arcn->ln_nlen = 0;
7971556Srgrimes	arcn->pad = 0;
7981556Srgrimes	arcn->skip = 0;
7991556Srgrimes	arcn->sb.st_rdev = (dev_t)0;
8001556Srgrimes
8011556Srgrimes	/*
8021556Srgrimes	 * set the mode and PAX type according to the typeflag in the header
8031556Srgrimes	 */
8041556Srgrimes	switch(hd->typeflag) {
8051556Srgrimes	case FIFOTYPE:
8061556Srgrimes		arcn->type = PAX_FIF;
8071556Srgrimes		arcn->sb.st_mode |= S_IFIFO;
8081556Srgrimes		break;
8091556Srgrimes	case DIRTYPE:
8101556Srgrimes		arcn->type = PAX_DIR;
8111556Srgrimes		arcn->sb.st_mode |= S_IFDIR;
8121556Srgrimes		arcn->sb.st_nlink = 2;
8131556Srgrimes
8141556Srgrimes		/*
8151556Srgrimes		 * Some programs that create ustar archives append a '/'
8161556Srgrimes		 * to the pathname for directories. This clearly violates
8171556Srgrimes		 * ustar specs, but we will silently strip it off anyway.
8181556Srgrimes		 */
8191556Srgrimes		if (arcn->name[arcn->nlen - 1] == '/')
8201556Srgrimes			arcn->name[--arcn->nlen] = '\0';
8211556Srgrimes		break;
8221556Srgrimes	case BLKTYPE:
8231556Srgrimes	case CHRTYPE:
8241556Srgrimes		/*
8251556Srgrimes		 * this type requires the rdev field to be set.
8261556Srgrimes		 */
8271556Srgrimes		if (hd->typeflag == BLKTYPE) {
8281556Srgrimes			arcn->type = PAX_BLK;
8291556Srgrimes			arcn->sb.st_mode |= S_IFBLK;
8301556Srgrimes		} else {
8311556Srgrimes			arcn->type = PAX_CHR;
8321556Srgrimes			arcn->sb.st_mode |= S_IFCHR;
8331556Srgrimes		}
8341556Srgrimes		devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
8351556Srgrimes		devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
8361556Srgrimes		arcn->sb.st_rdev = TODEV(devmajor, devminor);
8371556Srgrimes		break;
8381556Srgrimes	case SYMTYPE:
8391556Srgrimes	case LNKTYPE:
8401556Srgrimes		if (hd->typeflag == SYMTYPE) {
8411556Srgrimes			arcn->type = PAX_SLK;
8421556Srgrimes			arcn->sb.st_mode |= S_IFLNK;
8431556Srgrimes		} else {
8441556Srgrimes			arcn->type = PAX_HLK;
8451556Srgrimes			/*
8461556Srgrimes			 * so printing looks better
8471556Srgrimes			 */
8481556Srgrimes			arcn->sb.st_mode |= S_IFREG;
8491556Srgrimes			arcn->sb.st_nlink = 2;
8501556Srgrimes		}
8511556Srgrimes		/*
8521556Srgrimes		 * copy the link name
8531556Srgrimes		 */
8541556Srgrimes		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
85576351Skris			sizeof(arcn->ln_name) - 1);
8561556Srgrimes		arcn->ln_name[arcn->ln_nlen] = '\0';
8571556Srgrimes		break;
8581556Srgrimes	case CONTTYPE:
8591556Srgrimes	case AREGTYPE:
8601556Srgrimes	case REGTYPE:
8611556Srgrimes	default:
8621556Srgrimes		/*
8631556Srgrimes		 * these types have file data that follows. Set the skip and
8641556Srgrimes		 * pad fields.
8651556Srgrimes		 */
8661556Srgrimes		arcn->type = PAX_REG;
8671556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
8681556Srgrimes		arcn->skip = arcn->sb.st_size;
8691556Srgrimes		arcn->sb.st_mode |= S_IFREG;
8701556Srgrimes		break;
8711556Srgrimes	}
8721556Srgrimes	return(0);
8731556Srgrimes}
8741556Srgrimes
8751556Srgrimes/*
8761556Srgrimes * ustar_wr()
8771556Srgrimes *	write a ustar header for the file specified in the ARCHD to the archive
8781556Srgrimes *	Have to check for file types that cannot be stored and file names that
8791556Srgrimes *	are too long. Be careful of the term (last arg) to ul_oct, we only use
8801556Srgrimes *	'\0' for the termination character (this is different than picky tar)
8811556Srgrimes *	ASSUMED: space after header in header block is zero filled
8821556Srgrimes * Return:
8831556Srgrimes *	0 if file has data to be written after the header, 1 if file has NO
8841556Srgrimes *	data to write after the header, -1 if archive write failed
8851556Srgrimes */
8861556Srgrimes
8871556Srgrimesint
88890113Simpustar_wr(ARCHD *arcn)
8891556Srgrimes{
89090113Simp	HD_USTAR *hd;
89190113Simp	char *pt;
8921556Srgrimes	char hdblk[sizeof(HD_USTAR)];
8931556Srgrimes
8941556Srgrimes	/*
8951556Srgrimes	 * check for those file system types ustar cannot store
8961556Srgrimes	 */
8971556Srgrimes	if (arcn->type == PAX_SCK) {
89876017Skris		paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name);
8991556Srgrimes		return(1);
9001556Srgrimes	}
9011556Srgrimes
9021556Srgrimes	/*
9031556Srgrimes	 * check the length of the linkname
9041556Srgrimes	 */
9051556Srgrimes	if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
90640533Smsmith	    (arcn->type == PAX_HRG)) && (arcn->ln_nlen >= sizeof(hd->linkname))){
90776017Skris		paxwarn(1, "Link name too long for ustar %s", arcn->ln_name);
9081556Srgrimes		return(1);
9091556Srgrimes	}
9101556Srgrimes
9111556Srgrimes	/*
9121556Srgrimes	 * split the path name into prefix and name fields (if needed). if
9131556Srgrimes	 * pt != arcn->name, the name has to be split
9141556Srgrimes	 */
9151556Srgrimes	if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
91676017Skris		paxwarn(1, "File name too long for ustar %s", arcn->name);
9171556Srgrimes		return(1);
9181556Srgrimes	}
9191556Srgrimes	hd = (HD_USTAR *)hdblk;
9201556Srgrimes	arcn->pad = 0L;
9211556Srgrimes
9221556Srgrimes	/*
9231556Srgrimes	 * split the name, or zero out the prefix
9241556Srgrimes	 */
9251556Srgrimes	if (pt != arcn->name) {
9261556Srgrimes		/*
9271556Srgrimes		 * name was split, pt points at the / where the split is to
9281556Srgrimes		 * occur, we remove the / and copy the first part to the prefix
9291556Srgrimes		 */
9301556Srgrimes		*pt = '\0';
93176351Skris		l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix) - 1);
9321556Srgrimes		*pt++ = '/';
9331556Srgrimes	} else
93476017Skris		memset(hd->prefix, 0, sizeof(hd->prefix));
9351556Srgrimes
9361556Srgrimes	/*
9371556Srgrimes	 * copy the name part. this may be the whole path or the part after
9381556Srgrimes	 * the prefix
9391556Srgrimes	 */
94076351Skris	l_strncpy(hd->name, pt, sizeof(hd->name) - 1);
94176351Skris	hd->name[sizeof(hd->name) - 1] = '\0';
9421556Srgrimes
9438855Srgrimes	/*
9441556Srgrimes	 * set the fields in the header that are type dependent
9451556Srgrimes	 */
9461556Srgrimes	switch(arcn->type) {
9471556Srgrimes	case PAX_DIR:
9481556Srgrimes		hd->typeflag = DIRTYPE;
94976017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
95076017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
95176017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
9521556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9531556Srgrimes			goto out;
9541556Srgrimes		break;
9551556Srgrimes	case PAX_CHR:
9561556Srgrimes	case PAX_BLK:
9571556Srgrimes		if (arcn->type == PAX_CHR)
9581556Srgrimes			hd->typeflag = CHRTYPE;
9591556Srgrimes		else
9601556Srgrimes			hd->typeflag = BLKTYPE;
96176017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
9621556Srgrimes		if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,
9631556Srgrimes		   sizeof(hd->devmajor), 3) ||
9641556Srgrimes		   ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,
9651556Srgrimes		   sizeof(hd->devminor), 3) ||
9661556Srgrimes		   ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9671556Srgrimes			goto out;
9681556Srgrimes		break;
9691556Srgrimes	case PAX_FIF:
9701556Srgrimes		hd->typeflag = FIFOTYPE;
97176017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
97276017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
97376017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
9741556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9751556Srgrimes			goto out;
9761556Srgrimes		break;
9771556Srgrimes	case PAX_SLK:
9781556Srgrimes	case PAX_HLK:
9791556Srgrimes	case PAX_HRG:
9801556Srgrimes		if (arcn->type == PAX_SLK)
9811556Srgrimes			hd->typeflag = SYMTYPE;
9821556Srgrimes		else
9831556Srgrimes			hd->typeflag = LNKTYPE;
98476351Skris		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
98576351Skris		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
98676017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
98776017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
9881556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9891556Srgrimes			goto out;
9901556Srgrimes		break;
9911556Srgrimes	case PAX_REG:
9921556Srgrimes	case PAX_CTG:
9931556Srgrimes	default:
9941556Srgrimes		/*
9951556Srgrimes		 * file data with this type, set the padding
9961556Srgrimes		 */
9971556Srgrimes		if (arcn->type == PAX_CTG)
9981556Srgrimes			hd->typeflag = CONTTYPE;
9991556Srgrimes		else
10001556Srgrimes			hd->typeflag = REGTYPE;
100176017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
100276017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
100376017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
10041556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
10051556Srgrimes#		ifdef NET2_STAT
10061556Srgrimes		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
10071556Srgrimes		    sizeof(hd->size), 3)) {
10081556Srgrimes#		else
10091556Srgrimes		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
10101556Srgrimes		    sizeof(hd->size), 3)) {
10111556Srgrimes#		endif
101276017Skris			paxwarn(1,"File is too long for ustar %s",arcn->org_name);
10131556Srgrimes			return(1);
10141556Srgrimes		}
10151556Srgrimes		break;
10161556Srgrimes	}
10171556Srgrimes
101876351Skris	l_strncpy(hd->magic, TMAGIC, TMAGLEN);
101976351Skris	l_strncpy(hd->version, TVERSION, TVERSLEN);
10201556Srgrimes
10211556Srgrimes	/*
10221556Srgrimes	 * set the remaining fields. Some versions want all 16 bits of mode
10231556Srgrimes	 * we better humor them (they really do not meet spec though)....
10241556Srgrimes	 */
10251556Srgrimes	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) ||
10261556Srgrimes	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3)  ||
10271556Srgrimes	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) ||
10281556Srgrimes	    ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3))
10291556Srgrimes		goto out;
103076351Skris	l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname));
103176351Skris	l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname));
10321556Srgrimes
10331556Srgrimes	/*
10341556Srgrimes	 * calculate and store the checksum write the header to the archive
10351556Srgrimes	 * return 0 tells the caller to now write the file data, 1 says no data
10361556Srgrimes	 * needs to be written
10371556Srgrimes	 */
10381556Srgrimes	if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum,
10391556Srgrimes	   sizeof(hd->chksum), 3))
10401556Srgrimes		goto out;
10411556Srgrimes	if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)
10421556Srgrimes		return(-1);
10431556Srgrimes	if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
10441556Srgrimes		return(-1);
10451556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
10461556Srgrimes		return(0);
10471556Srgrimes	return(1);
10481556Srgrimes
10491556Srgrimes    out:
10501556Srgrimes    	/*
10511556Srgrimes	 * header field is out of range
10521556Srgrimes	 */
105376017Skris	paxwarn(1, "Ustar header field is too small for %s", arcn->org_name);
10541556Srgrimes	return(1);
10551556Srgrimes}
10561556Srgrimes
10571556Srgrimes/*
10581556Srgrimes * name_split()
10591556Srgrimes *	see if the name has to be split for storage in a ustar header. We try
10601556Srgrimes *	to fit the entire name in the name field without splitting if we can.
10611556Srgrimes *	The split point is always at a /
10621556Srgrimes * Return
10631556Srgrimes *	character pointer to split point (always the / that is to be removed
10641556Srgrimes *	if the split is not needed, the points is set to the start of the file
10651556Srgrimes *	name (it would violate the spec to split there). A NULL is returned if
10661556Srgrimes *	the file name is too long
10671556Srgrimes */
10681556Srgrimes
10691556Srgrimesstatic char *
107090113Simpname_split(char *name, int len)
10711556Srgrimes{
107290113Simp	char *start;
10731556Srgrimes
10741556Srgrimes	/*
10751556Srgrimes	 * check to see if the file name is small enough to fit in the name
10761556Srgrimes	 * field. if so just return a pointer to the name.
10771556Srgrimes	 */
107876351Skris	if (len < TNMSZ)
10791556Srgrimes		return(name);
108040533Smsmith	if (len > (TPFSZ + TNMSZ))
10811556Srgrimes		return(NULL);
10821556Srgrimes
10831556Srgrimes	/*
10841556Srgrimes	 * we start looking at the biggest sized piece that fits in the name
108546684Skris	 * field. We walk forward looking for a slash to split at. The idea is
10861556Srgrimes	 * to find the biggest piece to fit in the name field (or the smallest
108740533Smsmith	 * prefix we can find)
10881556Srgrimes	 */
108940533Smsmith	start = name + len - TNMSZ;
10901556Srgrimes	while ((*start != '\0') && (*start != '/'))
10911556Srgrimes		++start;
10921556Srgrimes
10931556Srgrimes	/*
10941556Srgrimes	 * if we hit the end of the string, this name cannot be split, so we
10951556Srgrimes	 * cannot store this file.
10961556Srgrimes	 */
10971556Srgrimes	if (*start == '\0')
10981556Srgrimes		return(NULL);
10991556Srgrimes	len = start - name;
11001556Srgrimes
11011556Srgrimes	/*
11021556Srgrimes	 * NOTE: /str where the length of str == TNMSZ can not be stored under
11031556Srgrimes	 * the p1003.1-1990 spec for ustar. We could force a prefix of / and
11041556Srgrimes	 * the file would then expand on extract to //str. The len == 0 below
11051556Srgrimes	 * makes this special case follow the spec to the letter.
11061556Srgrimes	 */
110740533Smsmith	if ((len >= TPFSZ) || (len == 0))
11081556Srgrimes		return(NULL);
11091556Srgrimes
11101556Srgrimes	/*
11111556Srgrimes	 * ok have a split point, return it to the caller
11121556Srgrimes	 */
11131556Srgrimes	return(start);
11141556Srgrimes}
1115