tar.c revision 102230
1193326Sed/*-
2193326Sed * Copyright (c) 1992 Keith Muller.
3193326Sed * Copyright (c) 1992, 1993
4193326Sed *	The Regents of the University of California.  All rights reserved.
5193326Sed *
6193326Sed * This code is derived from software contributed to Berkeley by
7193326Sed * Keith Muller of the University of California, San Diego.
8193326Sed *
9193326Sed * Redistribution and use in source and binary forms, with or without
10193326Sed * modification, are permitted provided that the following conditions
11193326Sed * are met:
12193326Sed * 1. Redistributions of source code must retain the above copyright
13193326Sed *    notice, this list of conditions and the following disclaimer.
14193326Sed * 2. Redistributions in binary form must reproduce the above copyright
15198092Srdivacky *    notice, this list of conditions and the following disclaimer in the
16193326Sed *    documentation and/or other materials provided with the distribution.
17193326Sed * 3. All advertising materials mentioning features or use of this software
18193326Sed *    must display the following acknowledgement:
19193326Sed *	This product includes software developed by the University of
20193326Sed *	California, Berkeley and its contributors.
21193326Sed * 4. Neither the name of the University nor the names of its contributors
22193326Sed *    may be used to endorse or promote products derived from this software
23218893Sdim *    without specific prior written permission.
24218893Sdim *
25223017Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26194179Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27218893Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28193326Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29198893Srdivacky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30198092Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31193326Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32193326Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33193326Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34207619Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35207619Srdivacky * SUCH DAMAGE.
36207619Srdivacky */
37207619Srdivacky
38207619Srdivacky#ifndef lint
39221345Sdim#if 0
40221345Sdimstatic char sccsid[] = "@(#)tar.c	8.2 (Berkeley) 4/18/94";
41207619Srdivacky#endif
42221345Sdim#endif /* not lint */
43207619Srdivacky#include <sys/cdefs.h>
44221345Sdim__FBSDID("$FreeBSD: head/bin/pax/tar.c 102230 2002-08-21 17:32:44Z trhodes $");
45207619Srdivacky
46221345Sdim#include <sys/types.h>
47207619Srdivacky#include <sys/time.h>
48212904Sdim#include <sys/stat.h>
49207619Srdivacky#include <string.h>
50207619Srdivacky#include <stdio.h>
51207619Srdivacky#include <unistd.h>
52207619Srdivacky#include <stdlib.h>
53207619Srdivacky#include "pax.h"
54207619Srdivacky#include "extern.h"
55210299Sed#include "tar.h"
56210299Sed
57221345Sdim/*
58207619Srdivacky * Routines for reading, writing and header identify of various versions of tar
59207619Srdivacky */
60221345Sdim
61207619Srdivackystatic u_long tar_chksm(char *, int);
62207619Srdivackystatic char *name_split(char *, int);
63212904Sdimstatic int ul_oct(u_long, char *, int, int);
64212904Sdim#ifndef NET2_STAT
65212904Sdimstatic int uqd_oct(u_quad_t, char *, int, int);
66212904Sdim#endif
67212904Sdim
68212904Sdim/*
69212904Sdim * Routines common to all versions of tar
70212904Sdim */
71207619Srdivacky
72207619Srdivackystatic int tar_nodir;			/* do not write dirs under old tar */
73212904Sdim
74212904Sdim/*
75212904Sdim * tar_endwr()
76207619Srdivacky *	add the tar trailer of two null blocks
77207619Srdivacky * Return:
78207619Srdivacky *	0 if ok, -1 otherwise (what wr_skip returns)
79207619Srdivacky */
80212904Sdim
81212904Sdimint
82207619Srdivackytar_endwr(void)
83207619Srdivacky{
84207619Srdivacky	return(wr_skip((off_t)(NULLCNT*BLKMULT)));
85207619Srdivacky}
86221345Sdim
87207619Srdivacky/*
88207619Srdivacky * tar_endrd()
89207619Srdivacky *	no cleanup needed here, just return size of trailer (for append)
90207619Srdivacky * Return:
91207619Srdivacky *	size of trailer (2 * BLKMULT)
92207619Srdivacky */
93218893Sdim
94218893Sdimoff_t
95218893Sdimtar_endrd(void)
96218893Sdim{
97218893Sdim	return((off_t)(NULLCNT*BLKMULT));
98218893Sdim}
99218893Sdim
100218893Sdim/*
101218893Sdim * tar_trail()
102218893Sdim *	Called to determine if a header block is a valid trailer. We are passed
103218893Sdim *	the block, the in_sync flag (which tells us we are in resync mode;
104218893Sdim *	looking for a valid header), and cnt (which starts at zero) which is
105218893Sdim *	used to count the number of empty blocks we have seen so far.
106218893Sdim * Return:
107218893Sdim *	0 if a valid trailer, -1 if not a valid trailer, or 1 if the block
108218893Sdim *	could never contain a header.
109218893Sdim */
110218893Sdim
111218893Sdimint
112218893Sdimtar_trail(char *buf, int in_resync, int *cnt)
113218893Sdim{
114218893Sdim	int i;
115218893Sdim
116218893Sdim	/*
117218893Sdim	 * look for all zero, trailer is two consecutive blocks of zero
118218893Sdim	 */
119218893Sdim	for (i = 0; i < BLKMULT; ++i) {
120218893Sdim		if (buf[i] != '\0')
121218893Sdim			break;
122218893Sdim	}
123218893Sdim
124218893Sdim	/*
125218893Sdim	 * if not all zero it is not a trailer, but MIGHT be a header.
126218893Sdim	 */
127218893Sdim	if (i != BLKMULT)
128218893Sdim		return(-1);
129193326Sed
130193326Sed	/*
131193326Sed	 * When given a zero block, we must be careful!
132193326Sed	 * If we are not in resync mode, check for the trailer. Have to watch
133224145Sdim	 * out that we do not mis-identify file data as the trailer, so we do
134224145Sdim	 * NOT try to id a trailer during resync mode. During resync mode we
135218893Sdim	 * might as well throw this block out since a valid header can NEVER be
136218893Sdim	 * a block of all 0 (we must have a valid file name).
137218893Sdim	 */
138224145Sdim	if (!in_resync && (++*cnt >= NULLCNT))
139224145Sdim		return(0);
140199990Srdivacky	return(1);
141199990Srdivacky}
142224145Sdim
143199990Srdivacky/*
144199990Srdivacky * ul_oct()
145199990Srdivacky *	convert an unsigned long to an octal string. many oddball field
146199990Srdivacky *	termination characters are used by the various versions of tar in the
147199990Srdivacky *	different fields. term selects which kind to use. str is '0' padded
148199990Srdivacky *	at the front to len. we are unable to use only one format as many old
149199990Srdivacky *	tar readers are very cranky about this.
150199990Srdivacky * Return:
151218893Sdim *	0 if the number fit into the string, -1 otherwise
152199990Srdivacky */
153199990Srdivacky
154218893Sdimstatic int
155199990Srdivackyul_oct(u_long val, char *str, int len, int term)
156199990Srdivacky{
157224145Sdim	char *pt;
158218893Sdim
159224145Sdim	/*
160224145Sdim	 * term selects the appropriate character(s) for the end of the string
161199990Srdivacky	 */
162218893Sdim	pt = str + len - 1;
163199990Srdivacky	switch(term) {
164218893Sdim	case 3:
165224145Sdim		*pt-- = '\0';
166224145Sdim		break;
167224145Sdim	case 2:
168224145Sdim		*pt-- = ' ';
169224145Sdim		*pt-- = '\0';
170224145Sdim		break;
171224145Sdim	case 1:
172224145Sdim		*pt-- = ' ';
173224145Sdim		break;
174224145Sdim	case 0:
175224145Sdim	default:
176199990Srdivacky		*pt-- = '\0';
177224145Sdim		*pt-- = ' ';
178218893Sdim		break;
179218893Sdim	}
180199990Srdivacky
181224145Sdim	/*
182218893Sdim	 * convert and blank pad if there is space
183199990Srdivacky	 */
184218893Sdim	while (pt >= str) {
185199990Srdivacky		*pt-- = '0' + (char)(val & 0x7);
186199990Srdivacky		if ((val = val >> 3) == (u_long)0)
187218893Sdim			break;
188210299Sed	}
189202879Srdivacky
190203955Srdivacky	while (pt >= str)
191224145Sdim		*pt-- = '0';
192202879Srdivacky	if (val != (u_long)0)
193224145Sdim		return(-1);
194224145Sdim	return(0);
195208600Srdivacky}
196218893Sdim
197208600Srdivacky#ifndef NET2_STAT
198208600Srdivacky/*
199208600Srdivacky * uqd_oct()
200208600Srdivacky *	convert an u_quad_t to an octal string. one of many oddball field
201224145Sdim *	termination characters are used by the various versions of tar in the
202208600Srdivacky *	different fields. term selects which kind to use. str is '0' padded
203224145Sdim *	at the front to len. we are unable to use only one format as many old
204224145Sdim *	tar readers are very cranky about this.
205218893Sdim * Return:
206218893Sdim *	0 if the number fit into the string, -1 otherwise
207218893Sdim */
208218893Sdim
209208600Srdivackystatic int
210208600Srdivackyuqd_oct(u_quad_t val, char *str, int len, int term)
211208600Srdivacky{
212218893Sdim	char *pt;
213208600Srdivacky
214224145Sdim	/*
215218893Sdim	 * term selects the appropriate character(s) for the end of the string
216218893Sdim	 */
217199990Srdivacky	pt = str + len - 1;
218199990Srdivacky	switch(term) {
219218893Sdim	case 3:
220218893Sdim		*pt-- = '\0';
221218893Sdim		break;
222224145Sdim	case 2:
223224145Sdim		*pt-- = ' ';
224224145Sdim		*pt-- = '\0';
225218893Sdim		break;
226218893Sdim	case 1:
227218893Sdim		*pt-- = ' ';
228218893Sdim		break;
229218893Sdim	case 0:
230218893Sdim	default:
231218893Sdim		*pt-- = '\0';
232218893Sdim		*pt-- = ' ';
233218893Sdim		break;
234218893Sdim	}
235218893Sdim
236218893Sdim	/*
237224145Sdim	 * convert and blank pad if there is space
238224145Sdim	 */
239218893Sdim	while (pt >= str) {
240218893Sdim		*pt-- = '0' + (char)(val & 0x7);
241224145Sdim		if ((val = val >> 3) == 0)
242218893Sdim			break;
243218893Sdim	}
244218893Sdim
245218893Sdim	while (pt >= str)
246224145Sdim		*pt-- = '0';
247218893Sdim	if (val != (u_quad_t)0)
248218893Sdim		return(-1);
249218893Sdim	return(0);
250218893Sdim}
251218893Sdim#endif
252218893Sdim
253221345Sdim/*
254212904Sdim * tar_chksm()
255221345Sdim *	calculate the checksum for a tar block counting the checksum field as
256212904Sdim *	all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks).
257218893Sdim *	NOTE: we use len to short circuit summing 0's on write since we ALWAYS
258224145Sdim *	pad headers with 0.
259221345Sdim * Return:
260221345Sdim *	unsigned long checksum
261221345Sdim */
262221345Sdim
263221345Sdimstatic u_long
264221345Sdimtar_chksm(char *blk, int len)
265221345Sdim{
266221345Sdim	char *stop;
267224145Sdim	char *pt;
268224145Sdim	u_long chksm = BLNKSUM;	/* initial value is checksum field sum */
269224145Sdim
270224145Sdim	/*
271224145Sdim	 * add the part of the block before the checksum field
272224145Sdim	 */
273224145Sdim	pt = blk;
274224145Sdim	stop = blk + CHK_OFFSET;
275224145Sdim	while (pt < stop)
276224145Sdim		chksm += (u_long)(*pt++ & 0xff);
277226633Sdim	/*
278226633Sdim	 * move past the checksum field and keep going, spec counts the
279212904Sdim	 * checksum field as the sum of 8 blanks (which is pre-computed as
280212904Sdim	 * BLNKSUM).
281212904Sdim	 * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding
282198893Srdivacky	 * starts, no point in summing zero's)
283221345Sdim	 */
284200583Srdivacky	pt += CHK_LEN;
285198893Srdivacky	stop = blk + len;
286199990Srdivacky	while (pt < stop)
287218893Sdim		chksm += (u_long)(*pt++ & 0xff);
288221345Sdim	return(chksm);
289199990Srdivacky}
290221345Sdim
291212904Sdim/*
292221345Sdim * Routines for old BSD style tar (also made portable to sysV tar)
293212904Sdim */
294212904Sdim
295212904Sdim/*
296221345Sdim * tar_id()
297212904Sdim *	determine if a block given to us is a valid tar header (and not a USTAR
298212904Sdim *	header). We have to be on the lookout for those pesky blocks of	all
299212904Sdim *	zero's.
300218893Sdim * Return:
301221345Sdim *	0 if a tar header, -1 otherwise
302212904Sdim */
303221345Sdim
304221345Sdimint
305221345Sdimtar_id(char *blk, int size)
306221345Sdim{
307198893Srdivacky	HD_TAR *hd;
308221345Sdim	HD_USTAR *uhd;
309221345Sdim
310221345Sdim	if (size < BLKMULT)
311221345Sdim		return(-1);
312199990Srdivacky	hd = (HD_TAR *)blk;
313226633Sdim	uhd = (HD_USTAR *)blk;
314221345Sdim
315218893Sdim	/*
316221345Sdim	 * check for block of zero's first, a simple and fast test, then make
317221345Sdim	 * sure this is not a ustar header by looking for the ustar magic
318198893Srdivacky	 * cookie. We should use TMAGLEN, but some USTAR archive programs are
319198893Srdivacky	 * wrong and create archives missing the \0. Last we check the
320221345Sdim	 * checksum. If this is ok we have to assume it is a valid header.
321218893Sdim	 */
322221345Sdim	if (hd->name[0] == '\0')
323218893Sdim		return(-1);
324210299Sed	if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0)
325210299Sed		return(-1);
326210299Sed	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
327221345Sdim		return(-1);
328221345Sdim	return(0);
329221345Sdim}
330218893Sdim
331226633Sdim/*
332221345Sdim * tar_opt()
333218893Sdim *	handle tar format specific -o options
334210299Sed * Return:
335210299Sed *	0 if ok -1 otherwise
336210299Sed */
337198893Srdivacky
338212904Sdimint
339198893Srdivackytar_opt(void)
340221345Sdim{
341212904Sdim	OPLIST *opt;
342198893Srdivacky
343198893Srdivacky	while ((opt = opt_next()) != NULL) {
344198893Srdivacky		if (strcmp(opt->name, TAR_OPTION) ||
345198893Srdivacky		    strcmp(opt->value, TAR_NODIR)) {
346198092Srdivacky			paxwarn(1, "Unknown tar format -o option/value pair %s=%s",
347198092Srdivacky			    opt->name, opt->value);
348203955Srdivacky			paxwarn(1,"%s=%s is the only supported tar format option",
349203955Srdivacky			    TAR_OPTION, TAR_NODIR);
350203955Srdivacky			return(-1);
351198092Srdivacky		}
352203955Srdivacky
353198092Srdivacky		/*
354193326Sed		 * we only support one option, and only when writing
355198092Srdivacky		 */
356198092Srdivacky		if ((act != APPND) && (act != ARCHIVE)) {
357193326Sed			paxwarn(1, "%s=%s is only supported when writing.",
358198092Srdivacky			    opt->name, opt->value);
359203955Srdivacky			return(-1);
360198092Srdivacky		}
361201361Srdivacky		tar_nodir = 1;
362201361Srdivacky	}
363198092Srdivacky	return(0);
364193326Sed}
365198092Srdivacky
366193326Sed
367198092Srdivacky/*
368193326Sed * tar_rd()
369198092Srdivacky *	extract the values out of block already determined to be a tar header.
370198092Srdivacky *	store the values in the ARCHD parameter.
371198092Srdivacky * Return:
372198092Srdivacky *	0
373198092Srdivacky */
374198092Srdivacky
375198092Srdivackyint
376198092Srdivackytar_rd(ARCHD *arcn, char *buf)
377198092Srdivacky{
378198092Srdivacky	HD_TAR *hd;
379198092Srdivacky	char *pt;
380198092Srdivacky
381198092Srdivacky	/*
382198092Srdivacky	 * we only get proper sized buffers passed to us
383198092Srdivacky	 */
384198092Srdivacky	if (tar_id(buf, BLKMULT) < 0)
385198092Srdivacky		return(-1);
386198092Srdivacky	arcn->org_name = arcn->name;
387198092Srdivacky	arcn->sb.st_nlink = 1;
388198092Srdivacky	arcn->pat = NULL;
389198092Srdivacky
390198092Srdivacky	/*
391201361Srdivacky	 * copy out the name and values in the stat buffer
392201361Srdivacky	 */
393201361Srdivacky	hd = (HD_TAR *)buf;
394201361Srdivacky	arcn->nlen = l_strncpy(arcn->name, hd->name, sizeof(arcn->name) - 1);
395201361Srdivacky	arcn->name[arcn->nlen] = '\0';
396201361Srdivacky	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) &
397201361Srdivacky	    0xfff);
398201361Srdivacky	arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
399200583Srdivacky	arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
400200583Srdivacky#ifdef NET2_STAT
401198092Srdivacky	arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
402198092Srdivacky	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
403198092Srdivacky#else
404198092Srdivacky	arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
405198092Srdivacky	arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);
406198092Srdivacky#endif
407198092Srdivacky	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
408198092Srdivacky
409198092Srdivacky	/*
410198092Srdivacky	 * have to look at the last character, it may be a '/' and that is used
411198092Srdivacky	 * to encode this as a directory
412205408Srdivacky	 */
413205408Srdivacky	pt = &(arcn->name[arcn->nlen - 1]);
414205408Srdivacky	arcn->pad = 0;
415205408Srdivacky	arcn->skip = 0;
416226633Sdim	switch(hd->linkflag) {
417205408Srdivacky	case SYMTYPE:
418198092Srdivacky		/*
419207619Srdivacky		 * symbolic link, need to get the link name and set the type in
420207619Srdivacky		 * the st_mode so -v printing will look correct.
421207619Srdivacky		 */
422198092Srdivacky		arcn->type = PAX_SLK;
423198092Srdivacky		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
424198092Srdivacky			sizeof(arcn->ln_name) - 1);
425198092Srdivacky		arcn->ln_name[arcn->ln_nlen] = '\0';
426198092Srdivacky		arcn->sb.st_mode |= S_IFLNK;
427198092Srdivacky		break;
428198092Srdivacky	case LNKTYPE:
429198092Srdivacky		/*
430198092Srdivacky		 * hard link, need to get the link name, set the type in the
431198092Srdivacky		 * st_mode and st_nlink so -v printing will look better.
432198092Srdivacky		 */
433198092Srdivacky		arcn->type = PAX_HLK;
434193326Sed		arcn->sb.st_nlink = 2;
435193326Sed		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
436212904Sdim			sizeof(arcn->ln_name) - 1);
437212904Sdim		arcn->ln_name[arcn->ln_nlen] = '\0';
438212904Sdim
439212904Sdim		/*
440212904Sdim		 * no idea of what type this thing really points at, but
441212904Sdim		 * we set something for printing only.
442212904Sdim		 */
443212904Sdim		arcn->sb.st_mode |= S_IFREG;
444212904Sdim		break;
445212904Sdim	case DIRTYPE:
446212904Sdim		/*
447212904Sdim		 * It is a directory, set the mode for -v printing
448212904Sdim		 */
449212904Sdim		arcn->type = PAX_DIR;
450212904Sdim		arcn->sb.st_mode |= S_IFDIR;
451212904Sdim		arcn->sb.st_nlink = 2;
452212904Sdim		arcn->ln_name[0] = '\0';
453212904Sdim		arcn->ln_nlen = 0;
454212904Sdim		break;
455212904Sdim	case AREGTYPE:
456212904Sdim	case REGTYPE:
457212904Sdim	default:
458212904Sdim		/*
459212904Sdim		 * If we have a trailing / this is a directory and NOT a file.
460212904Sdim		 */
461212904Sdim		arcn->ln_name[0] = '\0';
462212904Sdim		arcn->ln_nlen = 0;
463212904Sdim		if (*pt == '/') {
464212904Sdim			/*
465212904Sdim			 * it is a directory, set the mode for -v printing
466212904Sdim			 */
467212904Sdim			arcn->type = PAX_DIR;
468212904Sdim			arcn->sb.st_mode |= S_IFDIR;
469212904Sdim			arcn->sb.st_nlink = 2;
470212904Sdim		} else {
471212904Sdim			/*
472212904Sdim			 * have a file that will be followed by data. Set the
473212904Sdim			 * skip value to the size field and calculate the size
474193326Sed			 * of the padding.
475193326Sed			 */
476193326Sed			arcn->type = PAX_REG;
477193326Sed			arcn->sb.st_mode |= S_IFREG;
478193326Sed			arcn->pad = TAR_PAD(arcn->sb.st_size);
479193326Sed			arcn->skip = arcn->sb.st_size;
480193326Sed		}
481193326Sed		break;
482193326Sed	}
483193326Sed
484193326Sed	/*
485226633Sdim	 * strip off any trailing slash.
486226633Sdim	 */
487198092Srdivacky	if (*pt == '/') {
488193326Sed		*pt = '\0';
489193326Sed		--arcn->nlen;
490193326Sed	}
491193326Sed	return(0);
492193326Sed}
493218893Sdim
494193326Sed/*
495198092Srdivacky * tar_wr()
496193326Sed *	write a tar header for the file specified in the ARCHD to the archive.
497224145Sdim *	Have to check for file types that cannot be stored and file names that
498224145Sdim *	are too long. Be careful of the term (last arg) to ul_oct, each field
499193326Sed *	of tar has it own spec for the termination character(s).
500224145Sdim *	ASSUMED: space after header in header block is zero filled
501226633Sdim * Return:
502221345Sdim *	0 if file has data to be written after the header, 1 if file has NO
503193326Sed *	data to write after the header, -1 if archive write failed
504193326Sed */
505193326Sed
506193326Sedint
507193326Sedtar_wr(ARCHD *arcn)
508193326Sed{
509193326Sed	HD_TAR *hd;
510193326Sed	int len;
511193326Sed	char hdblk[sizeof(HD_TAR)];
512193326Sed
513193326Sed	/*
514218893Sdim	 * check for those file system types which tar cannot store
515193326Sed	 */
516193326Sed	switch(arcn->type) {
517193326Sed	case PAX_DIR:
518193326Sed		/*
519193326Sed		 * user asked that dirs not be written to the archive
520193326Sed		 */
521193326Sed		if (tar_nodir)
522226633Sdim			return(1);
523198092Srdivacky		break;
524198092Srdivacky	case PAX_CHR:
525193326Sed		paxwarn(1, "Tar cannot archive a character device %s",
526198092Srdivacky		    arcn->org_name);
527193326Sed		return(1);
528193326Sed	case PAX_BLK:
529218893Sdim		paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name);
530218893Sdim		return(1);
531218893Sdim	case PAX_SCK:
532218893Sdim		paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name);
533218893Sdim		return(1);
534218893Sdim	case PAX_FIF:
535218893Sdim		paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name);
536218893Sdim		return(1);
537218893Sdim	case PAX_SLK:
538218893Sdim	case PAX_HLK:
539226633Sdim	case PAX_HRG:
540226633Sdim		if (arcn->ln_nlen > sizeof(hd->linkname)) {
541218893Sdim			paxwarn(1,"Link name too long for tar %s", arcn->ln_name);
542218893Sdim			return(1);
543218893Sdim		}
544218893Sdim		break;
545218893Sdim	case PAX_REG:
546218893Sdim	case PAX_CTG:
547218893Sdim	default:
548218893Sdim		break;
549218893Sdim	}
550218893Sdim
551218893Sdim	/*
552218893Sdim	 * check file name len, remember extra char for dirs (the / at the end)
553218893Sdim	 */
554218893Sdim	len = arcn->nlen;
555218893Sdim	if (arcn->type == PAX_DIR)
556226633Sdim		++len;
557218893Sdim	if (len >= sizeof(hd->name)) {
558218893Sdim		paxwarn(1, "File name too long for tar %s", arcn->name);
559218893Sdim		return(1);
560218893Sdim	}
561218893Sdim
562218893Sdim	/*
563218893Sdim	 * copy the data out of the ARCHD into the tar header based on the type
564218893Sdim	 * of the file. Remember many tar readers want the unused fields to be
565218893Sdim	 * padded with zero. We set the linkflag field (type), the linkname
566218893Sdim	 * (or zero if not used),the size, and set the padding (if any) to be
567218893Sdim	 * added after the file data (0 for all other types, as they only have
568218893Sdim	 * a header)
569218893Sdim	 */
570218893Sdim	hd = (HD_TAR *)hdblk;
571218893Sdim	l_strncpy(hd->name, arcn->name, sizeof(hd->name) - 1);
572218893Sdim	hd->name[sizeof(hd->name) - 1] = '\0';
573218893Sdim	arcn->pad = 0;
574218893Sdim
575218893Sdim	if (arcn->type == PAX_DIR) {
576218893Sdim		/*
577218893Sdim		 * directories are the same as files, except have a filename
578218893Sdim		 * that ends with a /, we add the slash here. No data follows,
579224145Sdim		 * dirs, so no pad.
580218893Sdim		 */
581218893Sdim		hd->linkflag = AREGTYPE;
582218893Sdim		memset(hd->linkname, 0, sizeof(hd->linkname));
583218893Sdim		hd->name[len-1] = '/';
584218893Sdim		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
585218893Sdim			goto out;
586218893Sdim	} else if (arcn->type == PAX_SLK) {
587218893Sdim		/*
588218893Sdim		 * no data follows this file, so no pad
589218893Sdim		 */
590218893Sdim		hd->linkflag = SYMTYPE;
591218893Sdim		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
592218893Sdim		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
593218893Sdim		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
594218893Sdim			goto out;
595193326Sed	} else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {
596193326Sed		/*
597193326Sed		 * no data follows this file, so no pad
598193326Sed		 */
599226633Sdim		hd->linkflag = LNKTYPE;
600212904Sdim		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
601212904Sdim		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
602212904Sdim		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
603212904Sdim			goto out;
604212904Sdim	} else {
605212904Sdim		/*
606212904Sdim		 * data follows this file, so set the pad
607212904Sdim		 */
608212904Sdim		hd->linkflag = AREGTYPE;
609212904Sdim		memset(hd->linkname, 0, sizeof(hd->linkname));
610212904Sdim#		ifdef NET2_STAT
611212904Sdim		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
612212904Sdim		    sizeof(hd->size), 1)) {
613193326Sed#		else
614193326Sed		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
615193326Sed		    sizeof(hd->size), 1)) {
616212904Sdim#		endif
617193326Sed			paxwarn(1,"File is too large for tar %s", arcn->org_name);
618193326Sed			return(1);
619226633Sdim		}
620212904Sdim		arcn->pad = TAR_PAD(arcn->sb.st_size);
621212904Sdim	}
622212904Sdim
623212904Sdim	/*
624212904Sdim	 * copy those fields that are independent of the type
625212904Sdim	 */
626212904Sdim	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) ||
627212904Sdim	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) ||
628193326Sed	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) ||
629193326Sed	    ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1))
630193326Sed		goto out;
631193326Sed
632193326Sed	/*
633212904Sdim	 * calculate and add the checksum, then write the header. A return of
634212904Sdim	 * 0 tells the caller to now write the file data, 1 says no data needs
635212904Sdim	 * to be written
636212904Sdim	 */
637212904Sdim	if (ul_oct(tar_chksm(hdblk, sizeof(HD_TAR)), hd->chksum,
638212904Sdim	    sizeof(hd->chksum), 3))
639212904Sdim		goto out;
640212904Sdim	if (wr_rdbuf(hdblk, sizeof(HD_TAR)) < 0)
641193326Sed		return(-1);
642193326Sed	if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0)
643193326Sed		return(-1);
644193326Sed	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
645193326Sed		return(0);
646193326Sed	return(1);
647193326Sed
648193326Sed    out:
649193326Sed	/*
650218893Sdim	 * header field is out of range
651218893Sdim	 */
652218893Sdim	paxwarn(1, "Tar header field is too small for %s", arcn->org_name);
653218893Sdim	return(1);
654218893Sdim}
655218893Sdim
656224145Sdim/*
657218893Sdim * Routines for POSIX ustar
658193326Sed */
659198092Srdivacky
660218893Sdim/*
661193326Sed * ustar_strd()
662218893Sdim *	initialization for ustar read
663218893Sdim * Return:
664218893Sdim *	0 if ok, -1 otherwise
665218893Sdim */
666218893Sdim
667224145Sdimint
668224145Sdimustar_strd(void)
669218893Sdim{
670218893Sdim	if ((usrtb_start() < 0) || (grptb_start() < 0))
671193326Sed		return(-1);
672218893Sdim	return(0);
673218893Sdim}
674218893Sdim
675218893Sdim/*
676193326Sed * ustar_stwr()
677193326Sed *	initialization for ustar write
678193326Sed * Return:
679193326Sed *	0 if ok, -1 otherwise
680218893Sdim */
681218893Sdim
682218893Sdimint
683218893Sdimustar_stwr(void)
684224145Sdim{
685218893Sdim	if ((uidtb_start() < 0) || (gidtb_start() < 0))
686193326Sed		return(-1);
687193326Sed	return(0);
688218893Sdim}
689193326Sed
690218893Sdim/*
691218893Sdim * ustar_id()
692218893Sdim *	determine if a block given to us is a valid ustar header. We have to
693218893Sdim *	be on the lookout for those pesky blocks of all zero's
694218893Sdim * Return:
695224145Sdim *	0 if a ustar header, -1 otherwise
696224145Sdim */
697218893Sdim
698218893Sdimint
699193326Sedustar_id(char *blk, int size)
700218893Sdim{
701218893Sdim	HD_USTAR *hd;
702218893Sdim
703218893Sdim	if (size < BLKMULT)
704193326Sed		return(-1);
705193326Sed	hd = (HD_USTAR *)blk;
706193326Sed
707198092Srdivacky	/*
708198092Srdivacky	 * check for block of zero's first, a simple and fast test then check
709218893Sdim	 * ustar magic cookie. We should use TMAGLEN, but some USTAR archive
710218893Sdim	 * programs are fouled up and create archives missing the \0. Last we
711218893Sdim	 * check the checksum. If ok we have to assume it is a valid header.
712193326Sed	 */
713193326Sed	if (hd->name[0] == '\0')
714218893Sdim		return(-1);
715218893Sdim	if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)
716218893Sdim		return(-1);
717218893Sdim	if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
718218893Sdim		return(-1);
719218893Sdim	return(0);
720218893Sdim}
721218893Sdim
722201361Srdivacky/*
723226633Sdim * ustar_rd()
724226633Sdim *	extract the values out of block already determined to be a ustar header.
725226633Sdim *	store the values in the ARCHD parameter.
726226633Sdim * Return:
727226633Sdim *	0
728226633Sdim */
729226633Sdim
730218893Sdimint
731218893Sdimustar_rd(ARCHD *arcn, char *buf)
732218893Sdim{
733218893Sdim	HD_USTAR *hd;
734218893Sdim	char *dest;
735218893Sdim	int cnt = 0;
736218893Sdim	dev_t devmajor;
737218893Sdim	dev_t devminor;
738198092Srdivacky
739201361Srdivacky	/*
740201361Srdivacky	 * we only get proper sized buffers
741201361Srdivacky	 */
742198092Srdivacky	if (ustar_id(buf, BLKMULT) < 0)
743198092Srdivacky		return(-1);
744198092Srdivacky	arcn->org_name = arcn->name;
745198092Srdivacky	arcn->sb.st_nlink = 1;
746201361Srdivacky	arcn->pat = NULL;
747201361Srdivacky	arcn->nlen = 0;
748201361Srdivacky	hd = (HD_USTAR *)buf;
749201361Srdivacky
750193326Sed	/*
751193326Sed	 * see if the filename is split into two parts. if, so joint the parts.
752193326Sed	 * we copy the prefix first and add a / between the prefix and name.
753193326Sed	 */
754193326Sed	dest = arcn->name;
755193326Sed	if (*(hd->prefix) != '\0') {
756198092Srdivacky		cnt = l_strncpy(dest, hd->prefix, sizeof(arcn->name) - 2);
757193326Sed		dest += cnt;
758193326Sed		*dest++ = '/';
759193326Sed		cnt++;
760193326Sed	}
761193326Sed	arcn->nlen = cnt + l_strncpy(dest, hd->name, sizeof(arcn->name) - cnt);
762193326Sed	arcn->name[arcn->nlen] = '\0';
763193326Sed
764218893Sdim	/*
765218893Sdim	 * follow the spec to the letter. we should only have mode bits, strip
766193326Sed	 * off all other crud we may be passed.
767218893Sdim	 */
768193326Sed	arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
769193326Sed	    0xfff);
770218893Sdim#ifdef NET2_STAT
771218893Sdim	arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
772193326Sed	arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
773198092Srdivacky#else
774193326Sed	arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
775193326Sed	arcn->sb.st_mtime = (time_t)asc_uqd(hd->mtime, sizeof(hd->mtime), OCT);
776193326Sed#endif
777193326Sed	arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
778193326Sed
779193326Sed	/*
780193326Sed	 * If we can find the ascii names for gname and uname in the password
781218893Sdim	 * and group files we will use the uid's and gid they bind. Otherwise
782193326Sed	 * we use the uid and gid values stored in the header. (This is what
783198092Srdivacky	 * the POSIX spec wants).
784193326Sed	 */
785193326Sed	hd->gname[sizeof(hd->gname) - 1] = '\0';
786193326Sed	if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)
787193326Sed		arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
788198092Srdivacky	hd->uname[sizeof(hd->uname) - 1] = '\0';
789193326Sed	if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
790193326Sed		arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
791193326Sed
792198092Srdivacky	/*
793193326Sed	 * set the defaults, these may be changed depending on the file type
794193326Sed	 */
795193326Sed	arcn->ln_name[0] = '\0';
796198092Srdivacky	arcn->ln_nlen = 0;
797193326Sed	arcn->pad = 0;
798193326Sed	arcn->skip = 0;
799193326Sed	arcn->sb.st_rdev = (dev_t)0;
800198092Srdivacky
801193326Sed	/*
802193326Sed	 * set the mode and PAX type according to the typeflag in the header
803193326Sed	 */
804193326Sed	switch(hd->typeflag) {
805198092Srdivacky	case FIFOTYPE:
806193326Sed		arcn->type = PAX_FIF;
807198092Srdivacky		arcn->sb.st_mode |= S_IFIFO;
808193326Sed		break;
809221345Sdim	case DIRTYPE:
810221345Sdim		arcn->type = PAX_DIR;
811221345Sdim		arcn->sb.st_mode |= S_IFDIR;
812210299Sed		arcn->sb.st_nlink = 2;
813221345Sdim
814193326Sed		/*
815193326Sed		 * Some programs that create ustar archives append a '/'
816193326Sed		 * to the pathname for directories. This clearly violates
817219077Sdim		 * ustar specs, but we will silently strip it off anyway.
818219077Sdim		 */
819219077Sdim		if (arcn->name[arcn->nlen - 1] == '/')
820219077Sdim			arcn->name[--arcn->nlen] = '\0';
821219077Sdim		break;
822219077Sdim	case BLKTYPE:
823219077Sdim	case CHRTYPE:
824219077Sdim		/*
825219077Sdim		 * this type requires the rdev field to be set.
826219077Sdim		 */
827219077Sdim		if (hd->typeflag == BLKTYPE) {
828219077Sdim			arcn->type = PAX_BLK;
829219077Sdim			arcn->sb.st_mode |= S_IFBLK;
830207619Srdivacky		} else {
831207619Srdivacky			arcn->type = PAX_CHR;
832207619Srdivacky			arcn->sb.st_mode |= S_IFCHR;
833207619Srdivacky		}
834207619Srdivacky		devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
835207619Srdivacky		devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
836207619Srdivacky		arcn->sb.st_rdev = TODEV(devmajor, devminor);
837207619Srdivacky		break;
838207619Srdivacky	case SYMTYPE:
839207619Srdivacky	case LNKTYPE:
840207619Srdivacky		if (hd->typeflag == SYMTYPE) {
841207619Srdivacky			arcn->type = PAX_SLK;
842207619Srdivacky			arcn->sb.st_mode |= S_IFLNK;
843207619Srdivacky		} else {
844207619Srdivacky			arcn->type = PAX_HLK;
845207619Srdivacky			/*
846207619Srdivacky			 * so printing looks better
847207619Srdivacky			 */
848207619Srdivacky			arcn->sb.st_mode |= S_IFREG;
849207619Srdivacky			arcn->sb.st_nlink = 2;
850207619Srdivacky		}
851207619Srdivacky		/*
852207619Srdivacky		 * copy the link name
853207619Srdivacky		 */
854207619Srdivacky		arcn->ln_nlen = l_strncpy(arcn->ln_name, hd->linkname,
855207619Srdivacky			sizeof(arcn->ln_name) - 1);
856207619Srdivacky		arcn->ln_name[arcn->ln_nlen] = '\0';
857218893Sdim		break;
858218893Sdim	case CONTTYPE:
859218893Sdim	case AREGTYPE:
860224145Sdim	case REGTYPE:
861218893Sdim	default:
862207619Srdivacky		/*
863207619Srdivacky		 * these types have file data that follows. Set the skip and
864207619Srdivacky		 * pad fields.
865207619Srdivacky		 */
866207619Srdivacky		arcn->type = PAX_REG;
867207619Srdivacky		arcn->pad = TAR_PAD(arcn->sb.st_size);
868207619Srdivacky		arcn->skip = arcn->sb.st_size;
869207619Srdivacky		arcn->sb.st_mode |= S_IFREG;
870218893Sdim		break;
871218893Sdim	}
872218893Sdim	return(0);
873218893Sdim}
874218893Sdim
875207619Srdivacky/*
876207619Srdivacky * ustar_wr()
877207619Srdivacky *	write a ustar header for the file specified in the ARCHD to the archive
878207619Srdivacky *	Have to check for file types that cannot be stored and file names that
879207619Srdivacky *	are too long. Be careful of the term (last arg) to ul_oct, we only use
880207619Srdivacky *	'\0' for the termination character (this is different than picky tar)
881207619Srdivacky *	ASSUMED: space after header in header block is zero filled
882207619Srdivacky * Return:
883207619Srdivacky *	0 if file has data to be written after the header, 1 if file has NO
884207619Srdivacky *	data to write after the header, -1 if archive write failed
885207619Srdivacky */
886207619Srdivacky
887198092Srdivackyint
888221345Sdimustar_wr(ARCHD *arcn)
889200583Srdivacky{
890207619Srdivacky	HD_USTAR *hd;
891212904Sdim	char *pt;
892199990Srdivacky	char hdblk[sizeof(HD_USTAR)];
893218893Sdim
894218893Sdim	/*
895218893Sdim	 * check for those file system types ustar cannot store
896198092Srdivacky	 */
897198092Srdivacky	if (arcn->type == PAX_SCK) {
898221345Sdim		paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name);
899207619Srdivacky		return(1);
900207619Srdivacky	}
901206084Srdivacky
902206084Srdivacky	/*
903206084Srdivacky	 * check the length of the linkname
904199990Srdivacky	 */
905226633Sdim	if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
906198092Srdivacky	    (arcn->type == PAX_HRG)) && (arcn->ln_nlen >= sizeof(hd->linkname))){
907218893Sdim		paxwarn(1, "Link name too long for ustar %s", arcn->ln_name);
908218893Sdim		return(1);
909218893Sdim	}
910206084Srdivacky
911206084Srdivacky	/*
912221345Sdim	 * split the path name into prefix and name fields (if needed). if
913221345Sdim	 * pt != arcn->name, the name has to be split
914206084Srdivacky	 */
915206084Srdivacky	if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
916224145Sdim		paxwarn(1, "File name too long for ustar %s", arcn->name);
917224145Sdim		return(1);
918224145Sdim	}
919224145Sdim	hd = (HD_USTAR *)hdblk;
920224145Sdim	arcn->pad = 0L;
921224145Sdim
922206084Srdivacky	/*
923206084Srdivacky	 * split the name, or zero out the prefix
924206084Srdivacky	 */
925221345Sdim	if (pt != arcn->name) {
926206084Srdivacky		/*
927206084Srdivacky		 * name was split, pt points at the / where the split is to
928206084Srdivacky		 * occur, we remove the / and copy the first part to the prefix
929206084Srdivacky		 */
930224145Sdim		*pt = '\0';
931224145Sdim		l_strncpy(hd->prefix, arcn->name, sizeof(hd->prefix) - 1);
932224145Sdim		*pt++ = '/';
933206084Srdivacky	} else
934224145Sdim		memset(hd->prefix, 0, sizeof(hd->prefix));
935224145Sdim
936224145Sdim	/*
937224145Sdim	 * copy the name part. this may be the whole path or the part after
938224145Sdim	 * the prefix
939206084Srdivacky	 */
940206084Srdivacky	l_strncpy(hd->name, pt, sizeof(hd->name) - 1);
941206084Srdivacky	hd->name[sizeof(hd->name) - 1] = '\0';
942198092Srdivacky
943198092Srdivacky	/*
944221345Sdim	 * set the fields in the header that are type dependent
945221345Sdim	 */
946221345Sdim	switch(arcn->type) {
947221345Sdim	case PAX_DIR:
948221345Sdim		hd->typeflag = DIRTYPE;
949221345Sdim		memset(hd->linkname, 0, sizeof(hd->linkname));
950221345Sdim		memset(hd->devmajor, 0, sizeof(hd->devmajor));
951221345Sdim		memset(hd->devminor, 0, sizeof(hd->devminor));
952221345Sdim		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
953221345Sdim			goto out;
954221345Sdim		break;
955221345Sdim	case PAX_CHR:
956221345Sdim	case PAX_BLK:
957221345Sdim		if (arcn->type == PAX_CHR)
958221345Sdim			hd->typeflag = CHRTYPE;
959221345Sdim		else
960221345Sdim			hd->typeflag = BLKTYPE;
961221345Sdim		memset(hd->linkname, 0, sizeof(hd->linkname));
962221345Sdim		if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,
963221345Sdim		   sizeof(hd->devmajor), 3) ||
964221345Sdim		   ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,
965221345Sdim		   sizeof(hd->devminor), 3) ||
966226633Sdim		   ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
967226633Sdim			goto out;
968226633Sdim		break;
969226633Sdim	case PAX_FIF:
970226633Sdim		hd->typeflag = FIFOTYPE;
971226633Sdim		memset(hd->linkname, 0, sizeof(hd->linkname));
972226633Sdim		memset(hd->devmajor, 0, sizeof(hd->devmajor));
973226633Sdim		memset(hd->devminor, 0, sizeof(hd->devminor));
974226633Sdim		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
975226633Sdim			goto out;
976226633Sdim		break;
977226633Sdim	case PAX_SLK:
978226633Sdim	case PAX_HLK:
979226633Sdim	case PAX_HRG:
980226633Sdim		if (arcn->type == PAX_SLK)
981226633Sdim			hd->typeflag = SYMTYPE;
982226633Sdim		else
983226633Sdim			hd->typeflag = LNKTYPE;
984226633Sdim		l_strncpy(hd->linkname,arcn->ln_name, sizeof(hd->linkname) - 1);
985226633Sdim		hd->linkname[sizeof(hd->linkname) - 1] = '\0';
986226633Sdim		memset(hd->devmajor, 0, sizeof(hd->devmajor));
987226633Sdim		memset(hd->devminor, 0, sizeof(hd->devminor));
988226633Sdim		if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 3))
989226633Sdim			goto out;
990226633Sdim		break;
991226633Sdim	case PAX_REG:
992226633Sdim	case PAX_CTG:
993226633Sdim	default:
994226633Sdim		/*
995226633Sdim		 * file data with this type, set the padding
996226633Sdim		 */
997226633Sdim		if (arcn->type == PAX_CTG)
998226633Sdim			hd->typeflag = CONTTYPE;
999226633Sdim		else
1000226633Sdim			hd->typeflag = REGTYPE;
1001226633Sdim		memset(hd->linkname, 0, sizeof(hd->linkname));
1002226633Sdim		memset(hd->devmajor, 0, sizeof(hd->devmajor));
1003226633Sdim		memset(hd->devminor, 0, sizeof(hd->devminor));
1004226633Sdim		arcn->pad = TAR_PAD(arcn->sb.st_size);
1005226633Sdim#		ifdef NET2_STAT
1006226633Sdim		if (ul_oct((u_long)arcn->sb.st_size, hd->size,
1007226633Sdim		    sizeof(hd->size), 3)) {
1008226633Sdim#		else
1009226633Sdim		if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
1010226633Sdim		    sizeof(hd->size), 3)) {
1011226633Sdim#		endif
1012226633Sdim			paxwarn(1,"File is too long for ustar %s",arcn->org_name);
1013226633Sdim			return(1);
1014226633Sdim		}
1015226633Sdim		break;
1016226633Sdim	}
1017226633Sdim
1018226633Sdim	l_strncpy(hd->magic, TMAGIC, TMAGLEN);
1019226633Sdim	l_strncpy(hd->version, TVERSION, TVERSLEN);
1020226633Sdim
1021226633Sdim	/*
1022226633Sdim	 * set the remaining fields. Some versions want all 16 bits of mode
1023226633Sdim	 * we better humor them (they really do not meet spec though)....
1024226633Sdim	 */
1025226633Sdim	if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 3) ||
1026226633Sdim	    ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 3)  ||
1027226633Sdim	    ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 3) ||
1028226633Sdim	    ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),3))
1029226633Sdim		goto out;
1030226633Sdim	l_strncpy(hd->uname,name_uid(arcn->sb.st_uid, 0),sizeof(hd->uname));
1031226633Sdim	l_strncpy(hd->gname,name_gid(arcn->sb.st_gid, 0),sizeof(hd->gname));
1032226633Sdim
1033226633Sdim	/*
1034226633Sdim	 * calculate and store the checksum write the header to the archive
1035226633Sdim	 * return 0 tells the caller to now write the file data, 1 says no data
1036226633Sdim	 * needs to be written
1037226633Sdim	 */
1038226633Sdim	if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum,
1039226633Sdim	   sizeof(hd->chksum), 3))
1040226633Sdim		goto out;
1041226633Sdim	if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)
1042226633Sdim		return(-1);
1043226633Sdim	if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
1044226633Sdim		return(-1);
1045226633Sdim	if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
1046226633Sdim		return(0);
1047226633Sdim	return(1);
1048226633Sdim
1049226633Sdim    out:
1050226633Sdim    	/*
1051226633Sdim	 * header field is out of range
1052226633Sdim	 */
1053226633Sdim	paxwarn(1, "Ustar header field is too small for %s", arcn->org_name);
1054198092Srdivacky	return(1);
1055198092Srdivacky}
1056218893Sdim
1057218893Sdim/*
1058212904Sdim * name_split()
1059198092Srdivacky *	see if the name has to be split for storage in a ustar header. We try
1060212904Sdim *	to fit the entire name in the name field without splitting if we can.
1061210299Sed *	The split point is always at a /
1062218893Sdim * Return
1063218893Sdim *	character pointer to split point (always the / that is to be removed
1064218893Sdim *	if the split is not needed, the points is set to the start of the file
1065218893Sdim *	name (it would violate the spec to split there). A NULL is returned if
1066212904Sdim *	the file name is too long
1067198092Srdivacky */
1068212904Sdim
1069199482Srdivackystatic char *
1070212904Sdimname_split(char *name, int len)
1071198092Srdivacky{
1072212904Sdim	char *start;
1073206084Srdivacky
1074212904Sdim	/*
1075198092Srdivacky	 * check to see if the file name is small enough to fit in the name
1076212904Sdim	 * field. if so just return a pointer to the name.
1077198092Srdivacky	 */
1078212904Sdim	if (len < TNMSZ)
1079198092Srdivacky		return(name);
1080212904Sdim	if (len > (TPFSZ + TNMSZ))
1081198092Srdivacky		return(NULL);
1082212904Sdim
1083198092Srdivacky	/*
1084218893Sdim	 * we start looking at the biggest sized piece that fits in the name
1085218893Sdim	 * field. We walk forward looking for a slash to split at. The idea is
1086212904Sdim	 * to find the biggest piece to fit in the name field (or the smallest
1087198092Srdivacky	 * prefix we can find)
1088212904Sdim	 */
1089198893Srdivacky	start = name + len - TNMSZ;
1090212904Sdim	while ((*start != '\0') && (*start != '/'))
1091198092Srdivacky		++start;
1092212904Sdim
1093198092Srdivacky	/*
1094212904Sdim	 * if we hit the end of the string, this name cannot be split, so we
1095198092Srdivacky	 * cannot store this file.
1096212904Sdim	 */
1097198092Srdivacky	if (*start == '\0')
1098218893Sdim		return(NULL);
1099218893Sdim	len = start - name;
1100212904Sdim
1101198398Srdivacky	/*
1102212904Sdim	 * NOTE: /str where the length of str == TNMSZ can not be stored under
1103198398Srdivacky	 * the p1003.1-1990 spec for ustar. We could force a prefix of / and
1104212904Sdim	 * the file would then expand on extract to //str. The len == 0 below
1105198398Srdivacky	 * makes this special case follow the spec to the letter.
1106218893Sdim	 */
1107218893Sdim	if ((len >= TPFSZ) || (len == 0))
1108212904Sdim		return(NULL);
1109198398Srdivacky
1110212904Sdim	/*
1111198398Srdivacky	 * ok have a split point, return it to the caller
1112212904Sdim	 */
1113198398Srdivacky	return(start);
1114218893Sdim}
1115218893Sdim