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 <unistd.h>
481556Srgrimes#include <stdlib.h>
491556Srgrimes#include "pax.h"
501556Srgrimes#include "extern.h"
511556Srgrimes#include "tar.h"
521556Srgrimes
531556Srgrimes/*
541556Srgrimes * Routines for reading, writing and header identify of various versions of tar
551556Srgrimes */
561556Srgrimes
5790113Simpstatic u_long tar_chksm(char *, int);
5890113Simpstatic char *name_split(char *, int);
5990113Simpstatic int ul_oct(u_long, char *, int, int);
601556Srgrimes#ifndef NET2_STAT
6190113Simpstatic int uqd_oct(u_quad_t, char *, int, int);
621556Srgrimes#endif
631556Srgrimes
641556Srgrimes/*
651556Srgrimes * Routines common to all versions of tar
661556Srgrimes */
671556Srgrimes
681556Srgrimesstatic int tar_nodir;			/* do not write dirs under old tar */
691556Srgrimes
701556Srgrimes/*
711556Srgrimes * tar_endwr()
721556Srgrimes *	add the tar trailer of two null blocks
731556Srgrimes * Return:
741556Srgrimes *	0 if ok, -1 otherwise (what wr_skip returns)
751556Srgrimes */
761556Srgrimes
771556Srgrimesint
781556Srgrimestar_endwr(void)
791556Srgrimes{
801556Srgrimes	return(wr_skip((off_t)(NULLCNT*BLKMULT)));
811556Srgrimes}
821556Srgrimes
831556Srgrimes/*
841556Srgrimes * tar_endrd()
851556Srgrimes *	no cleanup needed here, just return size of trailer (for append)
861556Srgrimes * Return:
871556Srgrimes *	size of trailer (2 * BLKMULT)
881556Srgrimes */
891556Srgrimes
901556Srgrimesoff_t
911556Srgrimestar_endrd(void)
921556Srgrimes{
931556Srgrimes	return((off_t)(NULLCNT*BLKMULT));
941556Srgrimes}
951556Srgrimes
961556Srgrimes/*
971556Srgrimes * tar_trail()
981556Srgrimes *	Called to determine if a header block is a valid trailer. We are passed
991556Srgrimes *	the block, the in_sync flag (which tells us we are in resync mode;
1001556Srgrimes *	looking for a valid header), and cnt (which starts at zero) which is
1011556Srgrimes *	used to count the number of empty blocks we have seen so far.
1021556Srgrimes * Return:
1031556Srgrimes *	0 if a valid trailer, -1 if not a valid trailer, or 1 if the block
1041556Srgrimes *	could never contain a header.
1051556Srgrimes */
1061556Srgrimes
1071556Srgrimesint
10890113Simptar_trail(char *buf, int in_resync, int *cnt)
1091556Srgrimes{
11090113Simp	int i;
1111556Srgrimes
1121556Srgrimes	/*
1131556Srgrimes	 * look for all zero, trailer is two consecutive blocks of zero
1141556Srgrimes	 */
1151556Srgrimes	for (i = 0; i < BLKMULT; ++i) {
1161556Srgrimes		if (buf[i] != '\0')
1171556Srgrimes			break;
1181556Srgrimes	}
1191556Srgrimes
1201556Srgrimes	/*
1211556Srgrimes	 * if not all zero it is not a trailer, but MIGHT be a header.
1221556Srgrimes	 */
1231556Srgrimes	if (i != BLKMULT)
1241556Srgrimes		return(-1);
1251556Srgrimes
1261556Srgrimes	/*
1271556Srgrimes	 * When given a zero block, we must be careful!
1281556Srgrimes	 * If we are not in resync mode, check for the trailer. Have to watch
1291556Srgrimes	 * out that we do not mis-identify file data as the trailer, so we do
1301556Srgrimes	 * NOT try to id a trailer during resync mode. During resync mode we
1311556Srgrimes	 * might as well throw this block out since a valid header can NEVER be
1321556Srgrimes	 * a block of all 0 (we must have a valid file name).
1331556Srgrimes	 */
1341556Srgrimes	if (!in_resync && (++*cnt >= NULLCNT))
1351556Srgrimes		return(0);
1361556Srgrimes	return(1);
1371556Srgrimes}
1381556Srgrimes
1391556Srgrimes/*
1401556Srgrimes * ul_oct()
1411556Srgrimes *	convert an unsigned long to an octal string. many oddball field
1421556Srgrimes *	termination characters are used by the various versions of tar in the
14376351Skris *	different fields. term selects which kind to use. str is '0' padded
1441556Srgrimes *	at the front to len. we are unable to use only one format as many old
1451556Srgrimes *	tar readers are very cranky about this.
1461556Srgrimes * Return:
1471556Srgrimes *	0 if the number fit into the string, -1 otherwise
1481556Srgrimes */
1491556Srgrimes
1501556Srgrimesstatic int
15190113Simpul_oct(u_long val, char *str, int len, int term)
1521556Srgrimes{
15390113Simp	char *pt;
1548855Srgrimes
1551556Srgrimes	/*
1561556Srgrimes	 * term selects the appropriate character(s) for the end of the string
1571556Srgrimes	 */
1581556Srgrimes	pt = str + len - 1;
1591556Srgrimes	switch(term) {
1601556Srgrimes	case 3:
1611556Srgrimes		*pt-- = '\0';
1621556Srgrimes		break;
1631556Srgrimes	case 2:
1641556Srgrimes		*pt-- = ' ';
1651556Srgrimes		*pt-- = '\0';
1661556Srgrimes		break;
1671556Srgrimes	case 1:
1681556Srgrimes		*pt-- = ' ';
1691556Srgrimes		break;
1701556Srgrimes	case 0:
1711556Srgrimes	default:
1721556Srgrimes		*pt-- = '\0';
1731556Srgrimes		*pt-- = ' ';
1741556Srgrimes		break;
1751556Srgrimes	}
1761556Srgrimes
1771556Srgrimes	/*
1781556Srgrimes	 * convert and blank pad if there is space
1791556Srgrimes	 */
1801556Srgrimes	while (pt >= str) {
1811556Srgrimes		*pt-- = '0' + (char)(val & 0x7);
1821556Srgrimes		if ((val = val >> 3) == (u_long)0)
1831556Srgrimes			break;
1841556Srgrimes	}
1851556Srgrimes
1861556Srgrimes	while (pt >= str)
18776351Skris		*pt-- = '0';
1881556Srgrimes	if (val != (u_long)0)
1891556Srgrimes		return(-1);
1901556Srgrimes	return(0);
1911556Srgrimes}
1921556Srgrimes
1931556Srgrimes#ifndef NET2_STAT
1941556Srgrimes/*
1951556Srgrimes * uqd_oct()
1961556Srgrimes *	convert an u_quad_t to an octal string. one of many oddball field
1971556Srgrimes *	termination characters are used by the various versions of tar in the
19876351Skris *	different fields. term selects which kind to use. str is '0' padded
1991556Srgrimes *	at the front to len. we are unable to use only one format as many old
2001556Srgrimes *	tar readers are very cranky about this.
2011556Srgrimes * Return:
2021556Srgrimes *	0 if the number fit into the string, -1 otherwise
2031556Srgrimes */
2041556Srgrimes
2051556Srgrimesstatic int
20690113Simpuqd_oct(u_quad_t val, char *str, int len, int term)
2071556Srgrimes{
20890113Simp	char *pt;
2098855Srgrimes
2101556Srgrimes	/*
2111556Srgrimes	 * term selects the appropriate character(s) for the end of the string
2121556Srgrimes	 */
2131556Srgrimes	pt = str + len - 1;
2141556Srgrimes	switch(term) {
2151556Srgrimes	case 3:
2161556Srgrimes		*pt-- = '\0';
2171556Srgrimes		break;
2181556Srgrimes	case 2:
2191556Srgrimes		*pt-- = ' ';
2201556Srgrimes		*pt-- = '\0';
2211556Srgrimes		break;
2221556Srgrimes	case 1:
2231556Srgrimes		*pt-- = ' ';
2241556Srgrimes		break;
2251556Srgrimes	case 0:
2261556Srgrimes	default:
2271556Srgrimes		*pt-- = '\0';
2281556Srgrimes		*pt-- = ' ';
2291556Srgrimes		break;
2301556Srgrimes	}
2311556Srgrimes
2321556Srgrimes	/*
2331556Srgrimes	 * convert and blank pad if there is space
2341556Srgrimes	 */
2351556Srgrimes	while (pt >= str) {
2361556Srgrimes		*pt-- = '0' + (char)(val & 0x7);
2371556Srgrimes		if ((val = val >> 3) == 0)
2381556Srgrimes			break;
2391556Srgrimes	}
2401556Srgrimes
2411556Srgrimes	while (pt >= str)
24276351Skris		*pt-- = '0';
2431556Srgrimes	if (val != (u_quad_t)0)
2441556Srgrimes		return(-1);
2451556Srgrimes	return(0);
2461556Srgrimes}
2471556Srgrimes#endif
2481556Srgrimes
2491556Srgrimes/*
2501556Srgrimes * tar_chksm()
2511556Srgrimes *	calculate the checksum for a tar block counting the checksum field as
25246684Skris *	all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks).
2531556Srgrimes *	NOTE: we use len to short circuit summing 0's on write since we ALWAYS
2541556Srgrimes *	pad headers with 0.
2551556Srgrimes * Return:
2561556Srgrimes *	unsigned long checksum
2571556Srgrimes */
2581556Srgrimes
2591556Srgrimesstatic u_long
26090113Simptar_chksm(char *blk, int len)
2611556Srgrimes{
26290113Simp	char *stop;
26390113Simp	char *pt;
26446684Skris	u_long chksm = BLNKSUM;	/* initial value is checksum field sum */
2651556Srgrimes
2661556Srgrimes	/*
2671556Srgrimes	 * add the part of the block before the checksum field
2681556Srgrimes	 */
2691556Srgrimes	pt = blk;
2701556Srgrimes	stop = blk + CHK_OFFSET;
2718855Srgrimes	while (pt < stop)
2728855Srgrimes		chksm += (u_long)(*pt++ & 0xff);
2731556Srgrimes	/*
2741556Srgrimes	 * move past the checksum field and keep going, spec counts the
2751556Srgrimes	 * checksum field as the sum of 8 blanks (which is pre-computed as
2761556Srgrimes	 * BLNKSUM).
2771556Srgrimes	 * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding
2781556Srgrimes	 * starts, no point in summing zero's)
2791556Srgrimes	 */
2801556Srgrimes	pt += CHK_LEN;
2811556Srgrimes	stop = blk + len;
2821556Srgrimes	while (pt < stop)
2838855Srgrimes		chksm += (u_long)(*pt++ & 0xff);
2841556Srgrimes	return(chksm);
2851556Srgrimes}
2861556Srgrimes
2871556Srgrimes/*
2881556Srgrimes * Routines for old BSD style tar (also made portable to sysV tar)
2891556Srgrimes */
2901556Srgrimes
2911556Srgrimes/*
2921556Srgrimes * tar_id()
2931556Srgrimes *	determine if a block given to us is a valid tar header (and not a USTAR
294222177Suqs *	header). We have to be on the lookout for those pesky blocks of all
2951556Srgrimes *	zero's.
2961556Srgrimes * Return:
2971556Srgrimes *	0 if a tar header, -1 otherwise
2981556Srgrimes */
2991556Srgrimes
3001556Srgrimesint
30190113Simptar_id(char *blk, int size)
3021556Srgrimes{
30390113Simp	HD_TAR *hd;
30490113Simp	HD_USTAR *uhd;
3051556Srgrimes
3061556Srgrimes	if (size < BLKMULT)
3071556Srgrimes		return(-1);
3081556Srgrimes	hd = (HD_TAR *)blk;
3091556Srgrimes	uhd = (HD_USTAR *)blk;
3101556Srgrimes
3111556Srgrimes	/*
3121556Srgrimes	 * check for block of zero's first, a simple and fast test, then make
3131556Srgrimes	 * sure this is not a ustar header by looking for the ustar magic
3141556Srgrimes	 * cookie. We should use TMAGLEN, but some USTAR archive programs are
3151556Srgrimes	 * wrong and create archives missing the \0. Last we check the
3161556Srgrimes	 * checksum. If this is ok we have to assume it is a valid header.
3171556Srgrimes	 */
3181556Srgrimes	if (hd->name[0] == '\0')
3191556Srgrimes		return(-1);
3201556Srgrimes	if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0)
3211556Srgrimes		return(-1);
3221556Srgrimes	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
3231556Srgrimes		return(-1);
3241556Srgrimes	return(0);
3251556Srgrimes}
3261556Srgrimes
3271556Srgrimes/*
3281556Srgrimes * tar_opt()
3291556Srgrimes *	handle tar format specific -o options
3301556Srgrimes * Return:
3311556Srgrimes *	0 if ok -1 otherwise
3321556Srgrimes */
3331556Srgrimes
3341556Srgrimesint
3351556Srgrimestar_opt(void)
3361556Srgrimes{
3371556Srgrimes	OPLIST *opt;
3381556Srgrimes
3391556Srgrimes	while ((opt = opt_next()) != NULL) {
3401556Srgrimes		if (strcmp(opt->name, TAR_OPTION) ||
3411556Srgrimes		    strcmp(opt->value, TAR_NODIR)) {
34276017Skris			paxwarn(1, "Unknown tar format -o option/value pair %s=%s",
3431556Srgrimes			    opt->name, opt->value);
34476017Skris			paxwarn(1,"%s=%s is the only supported tar format option",
3451556Srgrimes			    TAR_OPTION, TAR_NODIR);
3461556Srgrimes			return(-1);
3471556Srgrimes		}
3481556Srgrimes
3491556Srgrimes		/*
3501556Srgrimes		 * we only support one option, and only when writing
3511556Srgrimes		 */
3521556Srgrimes		if ((act != APPND) && (act != ARCHIVE)) {
35376017Skris			paxwarn(1, "%s=%s is only supported when writing.",
3541556Srgrimes			    opt->name, opt->value);
3551556Srgrimes			return(-1);
3561556Srgrimes		}
3571556Srgrimes		tar_nodir = 1;
3581556Srgrimes	}
3591556Srgrimes	return(0);
3601556Srgrimes}
3611556Srgrimes
3621556Srgrimes
3631556Srgrimes/*
3641556Srgrimes * tar_rd()
3651556Srgrimes *	extract the values out of block already determined to be a tar header.
3661556Srgrimes *	store the values in the ARCHD parameter.
3671556Srgrimes * Return:
3681556Srgrimes *	0
3691556Srgrimes */
3701556Srgrimes
3711556Srgrimesint
37290113Simptar_rd(ARCHD *arcn, char *buf)
3731556Srgrimes{
37490113Simp	HD_TAR *hd;
37590113Simp	char *pt;
3761556Srgrimes
3771556Srgrimes	/*
3781556Srgrimes	 * we only get proper sized buffers passed to us
3791556Srgrimes	 */
3801556Srgrimes	if (tar_id(buf, BLKMULT) < 0)
3811556Srgrimes		return(-1);
3821556Srgrimes	arcn->org_name = arcn->name;
3831556Srgrimes	arcn->sb.st_nlink = 1;
3841556Srgrimes	arcn->pat = NULL;
3851556Srgrimes
3861556Srgrimes	/*
3871556Srgrimes	 * copy out the name and values in the stat buffer
3881556Srgrimes	 */
3891556Srgrimes	hd = (HD_TAR *)buf;
390137645Syar	/*
391137645Syar	 * old tar format specifies the name always be null-terminated,
392137645Syar	 * but let's be robust to broken archives.
393137645Syar	 * the same applies to handling links below.
394137645Syar	 */
395137645Syar	arcn->nlen = l_strncpy(arcn->name, hd->name,
396137645Syar	    MIN(sizeof(hd->name), sizeof(arcn->name)) - 1);
3971556Srgrimes	arcn->name[arcn->nlen] = '\0';
3981556Srgrimes	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) &
3991556Srgrimes	    0xfff);
4001556Srgrimes	arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
4011556Srgrimes	arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
40276351Skris#ifdef NET2_STAT
40376351Skris	arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
40485618Sdillon	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
40576351Skris#else
40676351Skris	arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
40785618Sdillon	arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);
40876351Skris#endif
4091556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
4101556Srgrimes
4111556Srgrimes	/*
4121556Srgrimes	 * have to look at the last character, it may be a '/' and that is used
4131556Srgrimes	 * to encode this as a directory
4141556Srgrimes	 */
4151556Srgrimes	pt = &(arcn->name[arcn->nlen - 1]);
4161556Srgrimes	arcn->pad = 0;
4171556Srgrimes	arcn->skip = 0;
4181556Srgrimes	switch(hd->linkflag) {
4191556Srgrimes	case SYMTYPE:
4201556Srgrimes		/*
4211556Srgrimes		 * symbolic link, need to get the link name and set the type in
4221556Srgrimes		 * the st_mode so -v printing will look correct.
4231556Srgrimes		 */
4241556Srgrimes		arcn->type = PAX_SLK;
4251556Srgrimes		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
426137645Syar		    MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1);
4271556Srgrimes		arcn->ln_name[arcn->ln_nlen] = '\0';
4281556Srgrimes		arcn->sb.st_mode |= S_IFLNK;
4291556Srgrimes		break;
4301556Srgrimes	case LNKTYPE:
4311556Srgrimes		/*
4321556Srgrimes		 * hard link, need to get the link name, set the type in the
4331556Srgrimes		 * st_mode and st_nlink so -v printing will look better.
4341556Srgrimes		 */
4351556Srgrimes		arcn->type = PAX_HLK;
4361556Srgrimes		arcn->sb.st_nlink = 2;
4371556Srgrimes		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
438137645Syar		    MIN(sizeof(hd->linkname), sizeof(arcn->ln_name)) - 1);
4391556Srgrimes		arcn->ln_name[arcn->ln_nlen] = '\0';
4401556Srgrimes
4411556Srgrimes		/*
4421556Srgrimes		 * no idea of what type this thing really points at, but
4431556Srgrimes		 * we set something for printing only.
4441556Srgrimes		 */
4451556Srgrimes		arcn->sb.st_mode |= S_IFREG;
4461556Srgrimes		break;
44776351Skris	case DIRTYPE:
44876351Skris		/*
44976351Skris		 * It is a directory, set the mode for -v printing
45076351Skris		 */
45176351Skris		arcn->type = PAX_DIR;
45276351Skris		arcn->sb.st_mode |= S_IFDIR;
45376351Skris		arcn->sb.st_nlink = 2;
45476351Skris		arcn->ln_name[0] = '\0';
45576351Skris		arcn->ln_nlen = 0;
45676351Skris		break;
4571556Srgrimes	case AREGTYPE:
4581556Srgrimes	case REGTYPE:
4591556Srgrimes	default:
4601556Srgrimes		/*
4611556Srgrimes		 * If we have a trailing / this is a directory and NOT a file.
4621556Srgrimes		 */
4631556Srgrimes		arcn->ln_name[0] = '\0';
4641556Srgrimes		arcn->ln_nlen = 0;
4651556Srgrimes		if (*pt == '/') {
4661556Srgrimes			/*
4671556Srgrimes			 * it is a directory, set the mode for -v printing
4681556Srgrimes			 */
4691556Srgrimes			arcn->type = PAX_DIR;
4701556Srgrimes			arcn->sb.st_mode |= S_IFDIR;
4711556Srgrimes			arcn->sb.st_nlink = 2;
4721556Srgrimes		} else {
4731556Srgrimes			/*
4741556Srgrimes			 * have a file that will be followed by data. Set the
47546684Skris			 * skip value to the size field and calculate the size
4761556Srgrimes			 * of the padding.
4771556Srgrimes			 */
4781556Srgrimes			arcn->type = PAX_REG;
4791556Srgrimes			arcn->sb.st_mode |= S_IFREG;
4801556Srgrimes			arcn->pad = TAR_PAD(arcn->sb.st_size);
4811556Srgrimes			arcn->skip = arcn->sb.st_size;
4821556Srgrimes		}
4831556Srgrimes		break;
4841556Srgrimes	}
4851556Srgrimes
4861556Srgrimes	/*
4871556Srgrimes	 * strip off any trailing slash.
4881556Srgrimes	 */
4891556Srgrimes	if (*pt == '/') {
4908855Srgrimes		*pt = '\0';
4911556Srgrimes		--arcn->nlen;
4921556Srgrimes	}
4931556Srgrimes	return(0);
4941556Srgrimes}
4951556Srgrimes
4961556Srgrimes/*
4971556Srgrimes * tar_wr()
4981556Srgrimes *	write a tar header for the file specified in the ARCHD to the archive.
4991556Srgrimes *	Have to check for file types that cannot be stored and file names that
5001556Srgrimes *	are too long. Be careful of the term (last arg) to ul_oct, each field
5011556Srgrimes *	of tar has it own spec for the termination character(s).
5021556Srgrimes *	ASSUMED: space after header in header block is zero filled
5031556Srgrimes * Return:
5041556Srgrimes *	0 if file has data to be written after the header, 1 if file has NO
5051556Srgrimes *	data to write after the header, -1 if archive write failed
5061556Srgrimes */
5071556Srgrimes
5081556Srgrimesint
50990113Simptar_wr(ARCHD *arcn)
5101556Srgrimes{
51190113Simp	HD_TAR *hd;
5121556Srgrimes	int len;
513164699Sru	HD_TAR hdblk;
5141556Srgrimes
5151556Srgrimes	/*
516102230Strhodes	 * check for those file system types which tar cannot store
5171556Srgrimes	 */
5181556Srgrimes	switch(arcn->type) {
5191556Srgrimes	case PAX_DIR:
5201556Srgrimes		/*
5211556Srgrimes		 * user asked that dirs not be written to the archive
5221556Srgrimes		 */
5231556Srgrimes		if (tar_nodir)
5241556Srgrimes			return(1);
5251556Srgrimes		break;
5261556Srgrimes	case PAX_CHR:
52776017Skris		paxwarn(1, "Tar cannot archive a character device %s",
5281556Srgrimes		    arcn->org_name);
5291556Srgrimes		return(1);
5301556Srgrimes	case PAX_BLK:
53176017Skris		paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name);
5321556Srgrimes		return(1);
5331556Srgrimes	case PAX_SCK:
53476017Skris		paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name);
5351556Srgrimes		return(1);
5361556Srgrimes	case PAX_FIF:
53776017Skris		paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name);
5381556Srgrimes		return(1);
5391556Srgrimes	case PAX_SLK:
5401556Srgrimes	case PAX_HLK:
5411556Srgrimes	case PAX_HRG:
542137645Syar		if (arcn->ln_nlen >= (int)sizeof(hd->linkname)) {
54376017Skris			paxwarn(1,"Link name too long for tar %s", arcn->ln_name);
5441556Srgrimes			return(1);
5451556Srgrimes		}
5461556Srgrimes		break;
5471556Srgrimes	case PAX_REG:
5481556Srgrimes	case PAX_CTG:
5491556Srgrimes	default:
5501556Srgrimes		break;
5511556Srgrimes	}
5521556Srgrimes
5531556Srgrimes	/*
5541556Srgrimes	 * check file name len, remember extra char for dirs (the / at the end)
5551556Srgrimes	 */
5561556Srgrimes	len = arcn->nlen;
5571556Srgrimes	if (arcn->type == PAX_DIR)
5581556Srgrimes		++len;
559114469Sobrien	if (len >= (int)sizeof(hd->name)) {
56076017Skris		paxwarn(1, "File name too long for tar %s", arcn->name);
5611556Srgrimes		return(1);
5621556Srgrimes	}
5631556Srgrimes
5641556Srgrimes	/*
5651556Srgrimes	 * copy the data out of the ARCHD into the tar header based on the type
5661556Srgrimes	 * of the file. Remember many tar readers want the unused fields to be
5671556Srgrimes	 * padded with zero. We set the linkflag field (type), the linkname
5681556Srgrimes	 * (or zero if not used),the size, and set the padding (if any) to be
5691556Srgrimes	 * added after the file data (0 for all other types, as they only have
5701556Srgrimes	 * a header)
5711556Srgrimes	 */
572164699Sru	hd = &hdblk;
57376351Skris	l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1);
57476351Skris	hd->name[sizeof(hd->name) - 1] = '\0';
5751556Srgrimes	arcn->pad = 0;
5761556Srgrimes
5771556Srgrimes	if (arcn->type == PAX_DIR) {
5781556Srgrimes		/*
5791556Srgrimes		 * directories are the same as files, except have a filename
5801556Srgrimes		 * that ends with a /, we add the slash here. No data follows,
5811556Srgrimes		 * dirs, so no pad.
5821556Srgrimes		 */
5831556Srgrimes		hd->linkflag = AREGTYPE;
58476017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
5851556Srgrimes		hd->name[len-1] = '/';
5861556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
5871556Srgrimes			goto out;
5881556Srgrimes	} else if (arcn->type == PAX_SLK) {
5891556Srgrimes		/*
5901556Srgrimes		 * no data follows this file, so no pad
5911556Srgrimes		 */
5921556Srgrimes		hd->linkflag = SYMTYPE;
59376351Skris		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
59476351Skris		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
5951556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
5961556Srgrimes			goto out;
5971556Srgrimes	} else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {
5981556Srgrimes		/*
5991556Srgrimes		 * no data follows this file, so no pad
6001556Srgrimes		 */
6011556Srgrimes		hd->linkflag = LNKTYPE;
60276351Skris		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
60376351Skris		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
6041556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
6051556Srgrimes			goto out;
6061556Srgrimes	} else {
6071556Srgrimes		/*
6081556Srgrimes		 * data follows this file, so set the pad
6091556Srgrimes		 */
6101556Srgrimes		hd->linkflag = AREGTYPE;
61176017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
6121556Srgrimes#		ifdef NET2_STAT
6131556Srgrimes		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
6141556Srgrimes		    sizeof(hd->size), 1)) {
6151556Srgrimes#		else
6161556Srgrimes		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
6171556Srgrimes		    sizeof(hd->size), 1)) {
6181556Srgrimes#		endif
61976017Skris			paxwarn(1,"File is too large for tar %s", arcn->org_name);
6201556Srgrimes			return(1);
6211556Srgrimes		}
6221556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
6231556Srgrimes	}
6241556Srgrimes
6251556Srgrimes	/*
6261556Srgrimes	 * copy those fields that are independent of the type
6271556Srgrimes	 */
6281556Srgrimes	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) ||
6291556Srgrimes	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) ||
6301556Srgrimes	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) ||
6311556Srgrimes	    ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1))
6321556Srgrimes		goto out;
6331556Srgrimes
6341556Srgrimes	/*
6351556Srgrimes	 * calculate and add the checksum, then write the header. A return of
6361556Srgrimes	 * 0 tells the caller to now write the file data, 1 says no data needs
6371556Srgrimes	 * to be written
6381556Srgrimes	 */
639164699Sru	if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_TAR)), hd->chksum,
64076351Skris	    sizeof(hd->chksum), 3))
6411556Srgrimes		goto out;
642164699Sru	if (wr_rdbuf((char *)&hdblk, sizeof(HD_TAR)) < 0)
6431556Srgrimes		return(-1);
6441556Srgrimes	if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0)
6451556Srgrimes		return(-1);
6461556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
6471556Srgrimes		return(0);
6481556Srgrimes	return(1);
6491556Srgrimes
6501556Srgrimes    out:
6511556Srgrimes	/*
6521556Srgrimes	 * header field is out of range
6531556Srgrimes	 */
65476017Skris	paxwarn(1, "Tar header field is too small for %s", arcn->org_name);
6551556Srgrimes	return(1);
6561556Srgrimes}
6571556Srgrimes
6581556Srgrimes/*
6591556Srgrimes * Routines for POSIX ustar
6601556Srgrimes */
6611556Srgrimes
6621556Srgrimes/*
6631556Srgrimes * ustar_strd()
6641556Srgrimes *	initialization for ustar read
6651556Srgrimes * Return:
6661556Srgrimes *	0 if ok, -1 otherwise
6671556Srgrimes */
6681556Srgrimes
6691556Srgrimesint
6701556Srgrimesustar_strd(void)
6711556Srgrimes{
6721556Srgrimes	if ((usrtb_start() < 0) || (grptb_start() < 0))
6731556Srgrimes		return(-1);
6741556Srgrimes	return(0);
6751556Srgrimes}
6761556Srgrimes
6771556Srgrimes/*
6781556Srgrimes * ustar_stwr()
6791556Srgrimes *	initialization for ustar write
6801556Srgrimes * Return:
6811556Srgrimes *	0 if ok, -1 otherwise
6821556Srgrimes */
6831556Srgrimes
6841556Srgrimesint
6851556Srgrimesustar_stwr(void)
6861556Srgrimes{
6871556Srgrimes	if ((uidtb_start() < 0) || (gidtb_start() < 0))
6881556Srgrimes		return(-1);
6891556Srgrimes	return(0);
6901556Srgrimes}
6911556Srgrimes
6921556Srgrimes/*
6931556Srgrimes * ustar_id()
6941556Srgrimes *	determine if a block given to us is a valid ustar header. We have to
6951556Srgrimes *	be on the lookout for those pesky blocks of all zero's
6961556Srgrimes * Return:
6971556Srgrimes *	0 if a ustar header, -1 otherwise
6981556Srgrimes */
6991556Srgrimes
7001556Srgrimesint
7011556Srgrimesustar_id(char *blk, int size)
7021556Srgrimes{
70390113Simp	HD_USTAR *hd;
7041556Srgrimes
7051556Srgrimes	if (size < BLKMULT)
7061556Srgrimes		return(-1);
7071556Srgrimes	hd = (HD_USTAR *)blk;
7081556Srgrimes
7091556Srgrimes	/*
7101556Srgrimes	 * check for block of zero's first, a simple and fast test then check
7111556Srgrimes	 * ustar magic cookie. We should use TMAGLEN, but some USTAR archive
7121556Srgrimes	 * programs are fouled up and create archives missing the \0. Last we
7131556Srgrimes	 * check the checksum. If ok we have to assume it is a valid header.
7141556Srgrimes	 */
7151556Srgrimes	if (hd->name[0] == '\0')
7161556Srgrimes		return(-1);
7171556Srgrimes	if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)
7181556Srgrimes		return(-1);
7191556Srgrimes	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
7201556Srgrimes		return(-1);
7211556Srgrimes	return(0);
7221556Srgrimes}
7231556Srgrimes
7241556Srgrimes/*
7251556Srgrimes * ustar_rd()
7261556Srgrimes *	extract the values out of block already determined to be a ustar header.
7271556Srgrimes *	store the values in the ARCHD parameter.
7281556Srgrimes * Return:
7291556Srgrimes *	0
7301556Srgrimes */
7311556Srgrimes
7321556Srgrimesint
73390113Simpustar_rd(ARCHD *arcn, char *buf)
7341556Srgrimes{
73590113Simp	HD_USTAR *hd;
73690113Simp	char *dest;
73790113Simp	int cnt = 0;
7381556Srgrimes	dev_t devmajor;
7391556Srgrimes	dev_t devminor;
7401556Srgrimes
7411556Srgrimes	/*
7421556Srgrimes	 * we only get proper sized buffers
7431556Srgrimes	 */
7441556Srgrimes	if (ustar_id(buf, BLKMULT) < 0)
7451556Srgrimes		return(-1);
7461556Srgrimes	arcn->org_name = arcn->name;
7471556Srgrimes	arcn->sb.st_nlink = 1;
7481556Srgrimes	arcn->pat = NULL;
74976351Skris	arcn->nlen = 0;
7501556Srgrimes	hd = (HD_USTAR *)buf;
7511556Srgrimes
7521556Srgrimes	/*
7531556Srgrimes	 * see if the filename is split into two parts. if, so joint the parts.
7541556Srgrimes	 * we copy the prefix first and add a / between the prefix and name.
7551556Srgrimes	 */
7561556Srgrimes	dest = arcn->name;
7571556Srgrimes	if (*(hd->prefix) != '\0') {
758137645Syar		cnt = l_strncpy(dest, hd->prefix,
759137645Syar		    MIN(sizeof(hd->prefix), sizeof(arcn->name) - 2));
76076351Skris		dest += cnt;
7611556Srgrimes		*dest++ = '/';
76276351Skris		cnt++;
7631556Srgrimes	}
764137645Syar	/*
765137645Syar	 * ustar format specifies the name may be unterminated
766137645Syar	 * if it fills the entire field.  this also applies to
767137645Syar	 * the prefix and the linkname.
768137645Syar	 */
769137645Syar	arcn->nlen = cnt + l_strncpy(dest, hd->name,
770137645Syar	    MIN(sizeof(hd->name), sizeof(arcn->name) - cnt - 1));
7711556Srgrimes	arcn->name[arcn->nlen] = '\0';
7721556Srgrimes
7731556Srgrimes	/*
7741556Srgrimes	 * follow the spec to the letter. we should only have mode bits, strip
7751556Srgrimes	 * off all other crud we may be passed.
7761556Srgrimes	 */
7771556Srgrimes	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
7781556Srgrimes	    0xfff);
77976351Skris#ifdef NET2_STAT
78076351Skris	arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
78185618Sdillon	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
78276351Skris#else
78376351Skris	arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
78485618Sdillon	arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);
78576351Skris#endif
7861556Srgrimes	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
7871556Srgrimes
7881556Srgrimes	/*
7891556Srgrimes	 * If we can find the ascii names for gname and uname in the password
7901556Srgrimes	 * and group files we will use the uid's and gid they bind. Otherwise
7911556Srgrimes	 * we use the uid and gid values stored in the header. (This is what
79246684Skris	 * the POSIX spec wants).
7931556Srgrimes	 */
7941556Srgrimes	hd->gname[sizeof(hd->gname) - 1] = '\0';
7951556Srgrimes	if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)
7961556Srgrimes		arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
7971556Srgrimes	hd->uname[sizeof(hd->uname) - 1] = '\0';
7981556Srgrimes	if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
7991556Srgrimes		arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
8001556Srgrimes
8011556Srgrimes	/*
8021556Srgrimes	 * set the defaults, these may be changed depending on the file type
8031556Srgrimes	 */
8041556Srgrimes	arcn->ln_name[0] = '\0';
8051556Srgrimes	arcn->ln_nlen = 0;
8061556Srgrimes	arcn->pad = 0;
8071556Srgrimes	arcn->skip = 0;
8081556Srgrimes	arcn->sb.st_rdev = (dev_t)0;
8091556Srgrimes
8101556Srgrimes	/*
8111556Srgrimes	 * set the mode and PAX type according to the typeflag in the header
8121556Srgrimes	 */
8131556Srgrimes	switch(hd->typeflag) {
8141556Srgrimes	case FIFOTYPE:
8151556Srgrimes		arcn->type = PAX_FIF;
8161556Srgrimes		arcn->sb.st_mode |= S_IFIFO;
8171556Srgrimes		break;
8181556Srgrimes	case DIRTYPE:
8191556Srgrimes		arcn->type = PAX_DIR;
8201556Srgrimes		arcn->sb.st_mode |= S_IFDIR;
8211556Srgrimes		arcn->sb.st_nlink = 2;
8221556Srgrimes
8231556Srgrimes		/*
8241556Srgrimes		 * Some programs that create ustar archives append a '/'
8251556Srgrimes		 * to the pathname for directories. This clearly violates
8261556Srgrimes		 * ustar specs, but we will silently strip it off anyway.
8271556Srgrimes		 */
8281556Srgrimes		if (arcn->name[arcn->nlen - 1] == '/')
8291556Srgrimes			arcn->name[--arcn->nlen] = '\0';
8301556Srgrimes		break;
8311556Srgrimes	case BLKTYPE:
8321556Srgrimes	case CHRTYPE:
8331556Srgrimes		/*
8341556Srgrimes		 * this type requires the rdev field to be set.
8351556Srgrimes		 */
8361556Srgrimes		if (hd->typeflag == BLKTYPE) {
8371556Srgrimes			arcn->type = PAX_BLK;
8381556Srgrimes			arcn->sb.st_mode |= S_IFBLK;
8391556Srgrimes		} else {
8401556Srgrimes			arcn->type = PAX_CHR;
8411556Srgrimes			arcn->sb.st_mode |= S_IFCHR;
8421556Srgrimes		}
8431556Srgrimes		devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
8441556Srgrimes		devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
8451556Srgrimes		arcn->sb.st_rdev = TODEV(devmajor, devminor);
8461556Srgrimes		break;
8471556Srgrimes	case SYMTYPE:
8481556Srgrimes	case LNKTYPE:
8491556Srgrimes		if (hd->typeflag == SYMTYPE) {
8501556Srgrimes			arcn->type = PAX_SLK;
8511556Srgrimes			arcn->sb.st_mode |= S_IFLNK;
8521556Srgrimes		} else {
8531556Srgrimes			arcn->type = PAX_HLK;
8541556Srgrimes			/*
8551556Srgrimes			 * so printing looks better
8561556Srgrimes			 */
8571556Srgrimes			arcn->sb.st_mode |= S_IFREG;
8581556Srgrimes			arcn->sb.st_nlink = 2;
8591556Srgrimes		}
8601556Srgrimes		/*
8611556Srgrimes		 * copy the link name
8621556Srgrimes		 */
8631556Srgrimes		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
864137645Syar		    MIN(sizeof(hd->linkname), sizeof(arcn->ln_name) - 1));
8651556Srgrimes		arcn->ln_name[arcn->ln_nlen] = '\0';
8661556Srgrimes		break;
8671556Srgrimes	case CONTTYPE:
8681556Srgrimes	case AREGTYPE:
8691556Srgrimes	case REGTYPE:
8701556Srgrimes	default:
8711556Srgrimes		/*
8721556Srgrimes		 * these types have file data that follows. Set the skip and
8731556Srgrimes		 * pad fields.
8741556Srgrimes		 */
8751556Srgrimes		arcn->type = PAX_REG;
8761556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
8771556Srgrimes		arcn->skip = arcn->sb.st_size;
8781556Srgrimes		arcn->sb.st_mode |= S_IFREG;
8791556Srgrimes		break;
8801556Srgrimes	}
8811556Srgrimes	return(0);
8821556Srgrimes}
8831556Srgrimes
8841556Srgrimes/*
8851556Srgrimes * ustar_wr()
8861556Srgrimes *	write a ustar header for the file specified in the ARCHD to the archive
8871556Srgrimes *	Have to check for file types that cannot be stored and file names that
8881556Srgrimes *	are too long. Be careful of the term (last arg) to ul_oct, we only use
8891556Srgrimes *	'\0' for the termination character (this is different than picky tar)
8901556Srgrimes *	ASSUMED: space after header in header block is zero filled
8911556Srgrimes * Return:
8921556Srgrimes *	0 if file has data to be written after the header, 1 if file has NO
8931556Srgrimes *	data to write after the header, -1 if archive write failed
8941556Srgrimes */
8951556Srgrimes
8961556Srgrimesint
89790113Simpustar_wr(ARCHD *arcn)
8981556Srgrimes{
89990113Simp	HD_USTAR *hd;
90090113Simp	char *pt;
901164699Sru	HD_USTAR hdblk;
9021556Srgrimes
9031556Srgrimes	/*
904102230Strhodes	 * check for those file system types ustar cannot store
9051556Srgrimes	 */
9061556Srgrimes	if (arcn->type == PAX_SCK) {
90776017Skris		paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name);
9081556Srgrimes		return(1);
9091556Srgrimes	}
9101556Srgrimes
9111556Srgrimes	/*
9121556Srgrimes	 * check the length of the linkname
9131556Srgrimes	 */
9141556Srgrimes	if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
915114469Sobrien	    (arcn->type == PAX_HRG)) &&
916137645Syar	    (arcn->ln_nlen > (int)sizeof(hd->linkname))) {
91776017Skris		paxwarn(1, "Link name too long for ustar %s", arcn->ln_name);
9181556Srgrimes		return(1);
9191556Srgrimes	}
9201556Srgrimes
9211556Srgrimes	/*
9221556Srgrimes	 * split the path name into prefix and name fields (if needed). if
9231556Srgrimes	 * pt != arcn->name, the name has to be split
9241556Srgrimes	 */
9251556Srgrimes	if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
92676017Skris		paxwarn(1, "File name too long for ustar %s", arcn->name);
9271556Srgrimes		return(1);
9281556Srgrimes	}
929164699Sru	hd = &hdblk;
9301556Srgrimes	arcn->pad = 0L;
9311556Srgrimes
9321556Srgrimes	/*
9331556Srgrimes	 * split the name, or zero out the prefix
9341556Srgrimes	 */
9351556Srgrimes	if (pt != arcn->name) {
9361556Srgrimes		/*
9371556Srgrimes		 * name was split, pt points at the / where the split is to
9381556Srgrimes		 * occur, we remove the / and copy the first part to the prefix
9391556Srgrimes		 */
9401556Srgrimes		*pt = '\0';
941137645Syar		l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix));
9421556Srgrimes		*pt++ = '/';
9431556Srgrimes	} else
94476017Skris		memset(hd->prefix, 0, sizeof(hd->prefix));
9451556Srgrimes
9461556Srgrimes	/*
9471556Srgrimes	 * copy the name part. this may be the whole path or the part after
948137645Syar	 * the prefix.  both the name and prefix may fill the entire field.
9491556Srgrimes	 */
950137645Syar	l_strncpy(hd->name, pt, sizeof(hd->name));
9511556Srgrimes
9528855Srgrimes	/*
9531556Srgrimes	 * set the fields in the header that are type dependent
9541556Srgrimes	 */
9551556Srgrimes	switch(arcn->type) {
9561556Srgrimes	case PAX_DIR:
9571556Srgrimes		hd->typeflag = DIRTYPE;
95876017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
95976017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
96076017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
9611556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9621556Srgrimes			goto out;
9631556Srgrimes		break;
9641556Srgrimes	case PAX_CHR:
9651556Srgrimes	case PAX_BLK:
9661556Srgrimes		if (arcn->type == PAX_CHR)
9671556Srgrimes			hd->typeflag = CHRTYPE;
9681556Srgrimes		else
9691556Srgrimes			hd->typeflag = BLKTYPE;
97076017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
9711556Srgrimes		if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,
9721556Srgrimes		   sizeof(hd->devmajor), 3) ||
9731556Srgrimes		   ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,
9741556Srgrimes		   sizeof(hd->devminor), 3) ||
9751556Srgrimes		   ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9761556Srgrimes			goto out;
9771556Srgrimes		break;
9781556Srgrimes	case PAX_FIF:
9791556Srgrimes		hd->typeflag = FIFOTYPE;
98076017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
98176017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
98276017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
9831556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9841556Srgrimes			goto out;
9851556Srgrimes		break;
9861556Srgrimes	case PAX_SLK:
9871556Srgrimes	case PAX_HLK:
9881556Srgrimes	case PAX_HRG:
9891556Srgrimes		if (arcn->type == PAX_SLK)
9901556Srgrimes			hd->typeflag = SYMTYPE;
9911556Srgrimes		else
9921556Srgrimes			hd->typeflag = LNKTYPE;
993137645Syar		/* the link name may occupy the entire field in ustar */
994137645Syar		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname));
99576017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
99676017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
9971556Srgrimes		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
9981556Srgrimes			goto out;
9991556Srgrimes		break;
10001556Srgrimes	case PAX_REG:
10011556Srgrimes	case PAX_CTG:
10021556Srgrimes	default:
10031556Srgrimes		/*
10041556Srgrimes		 * file data with this type, set the padding
10051556Srgrimes		 */
10061556Srgrimes		if (arcn->type == PAX_CTG)
10071556Srgrimes			hd->typeflag = CONTTYPE;
10081556Srgrimes		else
10091556Srgrimes			hd->typeflag = REGTYPE;
101076017Skris		memset(hd->linkname, 0, sizeof(hd->linkname));
101176017Skris		memset(hd->devmajor, 0, sizeof(hd->devmajor));
101276017Skris		memset(hd->devminor, 0, sizeof(hd->devminor));
10131556Srgrimes		arcn->pad = TAR_PAD(arcn->sb.st_size);
10141556Srgrimes#		ifdef NET2_STAT
10151556Srgrimes		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
10161556Srgrimes		    sizeof(hd->size), 3)) {
10171556Srgrimes#		else
10181556Srgrimes		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
10191556Srgrimes		    sizeof(hd->size), 3)) {
10201556Srgrimes#		endif
102176017Skris			paxwarn(1,"File is too long for ustar %s",arcn->org_name);
10221556Srgrimes			return(1);
10231556Srgrimes		}
10241556Srgrimes		break;
10251556Srgrimes	}
10261556Srgrimes
102776351Skris	l_strncpy(hd->magic, TMAGIC, TMAGLEN);
102876351Skris	l_strncpy(hd->version, TVERSION, TVERSLEN);
10291556Srgrimes
10301556Srgrimes	/*
10311556Srgrimes	 * set the remaining fields. Some versions want all 16 bits of mode
10321556Srgrimes	 * we better humor them (they really do not meet spec though)....
10331556Srgrimes	 */
10341556Srgrimes	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) ||
10351556Srgrimes	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3)  ||
10361556Srgrimes	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) ||
10371556Srgrimes	    ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3))
10381556Srgrimes		goto out;
103976351Skris	l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname));
104076351Skris	l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname));
10411556Srgrimes
10421556Srgrimes	/*
10431556Srgrimes	 * calculate and store the checksum write the header to the archive
10441556Srgrimes	 * return 0 tells the caller to now write the file data, 1 says no data
10451556Srgrimes	 * needs to be written
10461556Srgrimes	 */
1047164699Sru	if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_USTAR)), hd->chksum,
10481556Srgrimes	   sizeof(hd->chksum), 3))
10491556Srgrimes		goto out;
1050164699Sru	if (wr_rdbuf((char *)&hdblk, sizeof(HD_USTAR)) < 0)
10511556Srgrimes		return(-1);
10521556Srgrimes	if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
10531556Srgrimes		return(-1);
10541556Srgrimes	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
10551556Srgrimes		return(0);
10561556Srgrimes	return(1);
10571556Srgrimes
10581556Srgrimes    out:
10591556Srgrimes    	/*
10601556Srgrimes	 * header field is out of range
10611556Srgrimes	 */
106276017Skris	paxwarn(1, "Ustar header field is too small for %s", arcn->org_name);
10631556Srgrimes	return(1);
10641556Srgrimes}
10651556Srgrimes
10661556Srgrimes/*
10671556Srgrimes * name_split()
10681556Srgrimes *	see if the name has to be split for storage in a ustar header. We try
10691556Srgrimes *	to fit the entire name in the name field without splitting if we can.
10701556Srgrimes *	The split point is always at a /
10711556Srgrimes * Return
10721556Srgrimes *	character pointer to split point (always the / that is to be removed
10731556Srgrimes *	if the split is not needed, the points is set to the start of the file
10741556Srgrimes *	name (it would violate the spec to split there). A NULL is returned if
10751556Srgrimes *	the file name is too long
10761556Srgrimes */
10771556Srgrimes
10781556Srgrimesstatic char *
107990113Simpname_split(char *name, int len)
10801556Srgrimes{
108190113Simp	char *start;
10821556Srgrimes
10831556Srgrimes	/*
10841556Srgrimes	 * check to see if the file name is small enough to fit in the name
10851556Srgrimes	 * field. if so just return a pointer to the name.
10861556Srgrimes	 */
1087137645Syar	if (len <= TNMSZ)
10881556Srgrimes		return(name);
1089211963Sbrian	if (len > TPFSZ + TNMSZ)
10901556Srgrimes		return(NULL);
10911556Srgrimes
10921556Srgrimes	/*
10931556Srgrimes	 * we start looking at the biggest sized piece that fits in the name
109446684Skris	 * field. We walk forward looking for a slash to split at. The idea is
10951556Srgrimes	 * to find the biggest piece to fit in the name field (or the smallest
109640533Smsmith	 * prefix we can find)
10971556Srgrimes	 */
1098211864Sbrian	start = name + len - TNMSZ;
10991556Srgrimes	while ((*start != '\0') && (*start != '/'))
11001556Srgrimes		++start;
11011556Srgrimes
11021556Srgrimes	/*
11031556Srgrimes	 * if we hit the end of the string, this name cannot be split, so we
11041556Srgrimes	 * cannot store this file.
11051556Srgrimes	 */
11061556Srgrimes	if (*start == '\0')
11071556Srgrimes		return(NULL);
11081556Srgrimes	len = start - name;
11091556Srgrimes
11101556Srgrimes	/*
11111556Srgrimes	 * NOTE: /str where the length of str == TNMSZ can not be stored under
11121556Srgrimes	 * the p1003.1-1990 spec for ustar. We could force a prefix of / and
11131556Srgrimes	 * the file would then expand on extract to //str. The len == 0 below
11141556Srgrimes	 * makes this special case follow the spec to the letter.
11151556Srgrimes	 */
1116137645Syar	if ((len > TPFSZ) || (len == 0))
11171556Srgrimes		return(NULL);
11181556Srgrimes
11191556Srgrimes	/*
11201556Srgrimes	 * ok have a split point, return it to the caller
11211556Srgrimes	 */
11221556Srgrimes	return(start);
11231556Srgrimes}
1124