1 /* @(#)xheader.c	1.105 21/07/02 Copyright 2001-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)xheader.c	1.105 21/07/02 Copyright 2001-2021 J. Schilling";
6 #endif
7 /*
8  *	Handling routines to read/write, parse/create
9  *	POSIX.1-2001 extended archive headers
10  *
11  *	Copyright (c) 2001-2021 J. Schilling
12  */
13 /*
14  * The contents of this file are subject to the terms of the
15  * Common Development and Distribution License, Version 1.0 only
16  * (the "License").  You may not use this file except in compliance
17  * with the License.
18  *
19  * See the file CDDL.Schily.txt in this distribution for details.
20  * A copy of the CDDL is also available via the Internet at
21  * http://www.opensource.org/licenses/cddl1.txt
22  *
23  * When distributing Covered Code, include this CDDL HEADER in each
24  * file and include the License file CDDL.Schily.txt from this distribution.
25  */
26 
27 #include <schily/stdio.h>
28 #include <schily/stdlib.h>
29 #include <schily/unistd.h>	/* getpagesize() */
30 #include <schily/libport.h>	/* getpagesize() */
31 #include "star.h"
32 #include "props.h"
33 #include "table.h"
34 #include <schily/dirent.h>
35 #include <schily/standard.h>
36 #include <schily/string.h>
37 #define	__XDEV__	/* Needed to activate _dev_major()/_dev_minor() */
38 #include <schily/device.h>
39 #define	GT_COMERR		/* #define comerr gtcomerr */
40 #define	GT_ERROR		/* #define error gterror   */
41 #include <schily/schily.h>
42 #include <schily/idcache.h>
43 #include "starsubs.h"
44 #include "movearch.h"
45 #include "xtab.h"
46 #include "pathname.h"
47 
48 extern	BOOL	no_xheader;
49 extern	BOOL	nowarn;
50 extern	BOOL	binflag;
51 
52 extern	GINFO	*grip;				/* Global read info pointer	*/
53 
54 #define	MAX_UNAME	64	/* The maximum length of a user/group name */
55 
56 /*
57  * Flags for gen_text()
58  */
59 #define	T_ADDSLASH	1	/* Add slash to the argument	*/
60 #define	T_UTF8		2	/* Convert arg to UTF-8 coding	*/
61 
62 typedef struct _unknown unkn_t;
63 
64 struct _unknown {
65 	unkn_t	*u_next;
66 	char	u_name[1];
67 };
68 
69 LOCAL	void	_xbinit		__PR((void));
70 EXPORT	void	xbinit		__PR((void));
71 LOCAL	void	xbgrow		__PR((size_t newsize));
72 EXPORT	void	xbbackup	__PR((void));
73 EXPORT	void	xbrestore	__PR((void));
74 EXPORT	size_t	xhsize		__PR((void));
75 LOCAL	void	write_xhdr	__PR((int type));
76 EXPORT	void	info_to_xhdr	__PR((FINFO * info, TCB * ptb));
77 LOCAL	void	check_xtime	__PR((char *keyword, FINFO *info));
78 EXPORT	void	gen_xtime	__PR((char *keyword, time_t sec, Ulong nsec));
79 EXPORT	void	gen_unumber	__PR((char *keyword, Ullong arg));
80 EXPORT	void	gen_number	__PR((char *keyword, Llong arg));
81 LOCAL	void	gen_iarray	__PR((char *keyword, ino_t *arg, size_t ents, size_t len));
82 EXPORT	void	gen_text	__PR((char *keyword, char *arg, size_t alen,
83 								Uint flags));
84 LOCAL	int	len_len		__PR((size_t len));
85 LOCAL	xtab_t	*lookup		__PR((char *cmd, int clen, xtab_t *cp));
86 EXPORT	int	tcb_to_xhdr	__PR((TCB * ptb, FINFO * info));
87 EXPORT	BOOL	xhparse		__PR((FINFO *info, char	*p, char *ep));
88 LOCAL	void	print_unknown	__PR((char *keyword));
89 EXPORT	void	xh_rangeerr	__PR((char *keyword, char *arg, size_t len));
90 LOCAL	void	print_toolong	__PR((char *keyword, char *arg, size_t len));
91 LOCAL	void	get_xvolhdr	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
92 LOCAL	void	info_xcopy	__PR((FINFO *ninfo, FINFO *oinfo));
93 EXPORT	BOOL	get_xtime	__PR((char *keyword, char *arg, size_t len,
94 						time_t *secp, long *nsecp));
95 LOCAL	void	get_atime	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
96 LOCAL	void	get_ctime	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
97 LOCAL	void	get_mtime	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
98 #ifdef	__needed_
99 EXPORT	BOOL	get_number	__PR((char *keyword, char *arg, Llong *llp));
100 #endif
101 LOCAL	BOOL	get_xnumber	__PR((char *keyword, char *arg, Ullong *llp, char *type));
102 EXPORT	BOOL	get_unumber	__PR((char *keyword, char *arg, Ullong *ullp, Ullong maxval));
103 EXPORT	BOOL	get_snumber	__PR((char *keyword, char *arg, Ullong *ullp, BOOL *negp, Ullong minval, Ullong maxval));
104 LOCAL	void	get_uid		__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
105 LOCAL	void	get_gid		__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
106 LOCAL	void	get_uname	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
107 LOCAL	void	get_gname	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
108 LOCAL	void	get_path	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
109 LOCAL	void	get_lpath	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
110 LOCAL	void	get_size	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
111 LOCAL	void	get_realsize	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
112 LOCAL	void	get_offset	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
113 LOCAL	void	get_major	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
114 LOCAL	void	get_minor	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
115 LOCAL	void	get_fsmajor	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
116 LOCAL	void	get_fsminor	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
117 LOCAL	void	get_minorbits	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
118 LOCAL	void	get_dev		__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
119 LOCAL	void	get_ino		__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
120 LOCAL	void	get_nlink	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
121 LOCAL	void	get_filetype	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
122 #ifdef	USE_ACL
123 LOCAL	void	get_acl_type	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
124 LOCAL	void	get_acl_access	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
125 LOCAL	void	get_acl_default	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
126 LOCAL	void	get_acl_ace	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
127 #endif
128 #ifdef  USE_XATTR
129 LOCAL	void	get_attr	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
130 #endif
131 #ifdef	USE_FFLAGS
132 LOCAL	void	get_xfflags	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
133 #endif
134 LOCAL	void	get_dir		__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
135 LOCAL	void	get_iarray	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
136 LOCAL	void	get_release	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
137 LOCAL	void	get_archtype	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
138 LOCAL	void	get_hdrcharset	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
139 LOCAL	void	get_dummy	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
140 LOCAL	void	unsup_arg	__PR((char *keyword, char *arg));
141 LOCAL	void	bad_utf8	__PR((char *keyword, char *arg));
142 
143 /*
144  * Convert unsigned integer into a decimal string.
145  * The parameter 'val' is of the needed size (basic type), so it is as fast
146  * as possible.
147  *
148  * The string is written starting from the end backwards for best speed.
149  */
150 LOCAL	Uchar	dtab[] = "0123456789";
151 
152 #define	ui2decimal(val, np)	do {					      \
153 					*--(np) = dtab[(val) % (unsigned)10]; \
154 					(val) = (val) / (unsigned)10;	      \
155 				} while ((val) > 0)
156 
157 #define	scopy(to, from)		while ((*(to)++ = *(from)++) != '\0')
158 
159 
160 LOCAL	char	*xbuf;	/* Space used to prepare I/O from/to extended headers */
161 LOCAL	size_t	xblen;	/* the length of the buffer for the extended headers */
162 LOCAL	size_t	xbidx;	/* The index where we start to prepare next entry    */
163 
164 EXPORT	BOOL	ghdr;	/* We need wo write a 'g'lobal header		*/
165 LOCAL	FINFO	ginfo;	/* The 'g'lobal FINFO data			*/
166 LOCAL	char	*guname;
167 LOCAL	char	*ggname;
168 
169 LOCAL	unkn_t	*unkn;	/* A list of unknown keywords to print warnings once */
170 LOCAL	Ulong	badf;	/* A list of bad flags				*/
171 
172 /*
173  * Important for the correctness of gen_number(): As long as we stay <= 55
174  * chars for the keyword, a 128 bit number entry will fit into 100 chars.
175  *
176  *			x_name,		x_namelen, x_func,	x_flag
177  */
178 LOCAL xtab_t xtab[] = {
179 			{ "atime",		5, get_atime,	0	},
180 			{ "ctime",		5, get_ctime,	0	},
181 			{ "mtime",		5, get_mtime,	0	},
182 
183 			{ "uid",		3, get_uid,	0	},
184 			{ "uname",		5, get_uname,	0	},
185 			{ "gid",		3, get_gid,	0	},
186 			{ "gname",		5, get_gname,	0	},
187 
188 			{ "path",		4, get_path,	0	},
189 			{ "linkpath",		8, get_lpath,	0	},
190 
191 			{ "size",		4, get_size,	0	},
192 
193 			{ "charset",		7, get_dummy,	0	},
194 			{ "comment",		7, get_dummy,	0	},
195 			{ "hdrcharset",		10, get_hdrcharset,	0	},
196 /* "BINARY" */
197 
198 			{ "SCHILY.devmajor",	15, get_major,	0	},
199 			{ "SCHILY.devminor",	15, get_minor,	0	},
200 
201 #ifdef	USE_ACL
202 			{ "SCHILY.acl.access",	17, get_acl_access, 0	},
203 			{ "SCHILY.acl.default",	18, get_acl_default, 0	},
204 			{ "SCHILY.acl.ace",	14, get_acl_ace, 0	},
205 			{ "SCHILY.acl.type",	15, get_acl_type, 0	},
206 #else
207 /*
208  * We don't want star to complain about unknown extended headers when it
209  * has been compiled without ACL support.
210  */
211 			{ "SCHILY.acl.access",	17, get_dummy,	0	},
212 			{ "SCHILY.acl.default",	18, get_dummy,	0	},
213 			{ "SCHILY.acl.ace",	14, get_dummy,	0	},
214 			{ "SCHILY.acl.type",	15, get_dummy,	0	},
215 #endif
216 #ifdef  USE_XATTR
217 			{ "SCHILY.xattr.*",	14, get_attr,	0	},
218 #else
219 			{ "SCHILY.xattr.*",	14, get_dummy,	0	},
220 #endif
221 
222 #ifdef	USE_FFLAGS
223 			{ "SCHILY.fflags",	13, get_xfflags, 0	},
224 #else
225 /*
226  * We don't want star to complain about unknown extended headers when it
227  * has been compiled without extended file flag support.
228  */
229 			{ "SCHILY.fflags",	13, get_dummy,	0	},
230 #endif
231 			{ "SCHILY.dev",		10, get_dev,	0	},
232 			{ "SCHILY.devminorbits", 19, get_minorbits,	0	},
233 			{ "SCHILY.fsdevmajor",	17, get_fsmajor, 0	},
234 			{ "SCHILY.fsdevminor",	17, get_fsminor, 0	},
235 			{ "SCHILY.ino",		10, get_ino,	0	},
236 			{ "SCHILY.nlink",	12, get_nlink,	0	},
237 			{ "SCHILY.filetype",	15, get_filetype, 0	},
238 			{ "SCHILY.tarfiletype",	18, get_filetype, 0	},
239 			{ "SCHILY.realsize",	15, get_realsize, 0	},
240 			{ "SCHILY.offset",	13, get_offset, 0	},
241 
242 			{ "SCHILY.dir",		10, get_dir,	0	},
243 			{ "SCHILY.ddev",	11, get_dummy,	0	},
244 			{ "SCHILY.dino",	11, get_iarray,	0	},
245 
246 			{ "SCHILY.release",	14, get_release, 0	},
247 			{ "SCHILY.archtype",	15, get_archtype, 0	},
248 			{ "SCHILY.volhdr.*",	15, get_xvolhdr, 0	},
249 
250 			{ "SUN.devmajor",	12, get_major,	0	},
251 			{ "SUN.devminor",	12, get_minor,	0	},
252 
253 			{ NULL,			0, NULL,	0	}};
254 
255 /*
256  * Initialize the growable buffer used for reading the extended headers
257  */
258 LOCAL void
_xbinit()259 _xbinit()
260 {
261 	xbuf = ___malloc(1, "growable xheader");
262 	xblen = 1;
263 	xbidx = 0;
264 }
265 
266 EXPORT void
xbinit()267 xbinit()
268 {
269 	_xbinit();
270 
271 	init_pspace(PS_EXIT, &ginfo.f_pname);
272 	ginfo.f_name = ginfo.f_pname.ps_path;
273 	ginfo.f_name[0] = '\0';
274 
275 	init_pspace(PS_EXIT, &ginfo.f_plname);
276 	ginfo.f_lname = ginfo.f_plname.ps_path;
277 	ginfo.f_lname[0] = '\0';
278 
279 	ginfo.f_uname = ___malloc(MAX_UNAME+1, "global user name");
280 	ginfo.f_gname = ___malloc(MAX_UNAME+1, "global group name");
281 	ginfo.f_uname[0] = '\0';
282 	ginfo.f_gname[0] = '\0';
283 	ginfo.f_devminorbits = 0;
284 	ggname = ginfo.f_gname;
285 	ginfo.f_xflags = 0;
286 	guname = ginfo.f_uname;
287 	ggname = ginfo.f_gname;
288 }
289 
290 /*
291  * Grow the growable buffer used for reading the extended headers
292  */
293 LOCAL void
xbgrow(newsize)294 xbgrow(newsize)
295 	size_t	newsize;
296 {
297 	char	*newbuf;
298 	size_t	i;
299 	int	ps = getpagesize();
300 
301 	/*
302 	 * grow in pagesize units
303 	 */
304 	for (i = 0; i < newsize; i += ps)
305 		/* LINTED */
306 		;
307 	newsize = i + xblen;
308 	newbuf = ___realloc(xbuf, newsize, "growable xheader");
309 	xbuf = newbuf;
310 	xblen = newsize;
311 }
312 
313 /*
314  * Variables used to allow us to create an extended header while we write one
315  */
316 LOCAL	char	*oxbuf;	/* Space used to prepare I/O from/to extended headers */
317 LOCAL	size_t	oxblen;	/* the length of the buffer for the extended headers */
318 LOCAL	size_t	oxbidx;	/* The index where we start to prepare next entry    */
319 
320 EXPORT void
xbbackup()321 xbbackup()
322 {
323 	oxbuf  = xbuf;
324 	oxblen = xblen;
325 	oxbidx = xbidx;
326 
327 	_xbinit();
328 }
329 
330 EXPORT void
xbrestore()331 xbrestore()
332 {
333 	free(xbuf);
334 
335 	xbuf  = oxbuf;
336 	xblen = oxblen;
337 	xbidx = oxbidx;
338 }
339 
340 EXPORT size_t
xhsize()341 xhsize()
342 {
343 	return (xbidx);
344 }
345 
346 LOCAL void
write_xhdr(type)347 write_xhdr(type)
348 	int	type;
349 {
350 	FINFO	finfo;
351 	TCB	tb;
352 	TCB	*xptb;
353 	move_t	move;
354 
355 	fillbytes((char *)&finfo, sizeof (finfo), '\0');
356 
357 	if ((xptb = (TCB *)get_block(TBLOCK)) == NULL)
358 		xptb = &tb;
359 	else
360 		finfo.f_flags |= F_TCB_BUF;
361 	filltcb(xptb);
362 	strcpy(xptb->dbuf.t_name, "././@PaxHeader");
363 	finfo.f_name = xptb->dbuf.t_name;
364 	finfo.f_mode = TUREAD|TUWRITE;
365 	finfo.f_rsize = finfo.f_size = xbidx;
366 	finfo.f_xftype = XT_FILE;
367 	info_to_tcb(&finfo, xptb);
368 	xptb->dbuf.t_linkflag = (char)type;
369 	write_tcb(xptb, &finfo);
370 
371 	move.m_data = xbuf;
372 	move.m_size = finfo.f_size;
373 	move.m_flags = 0;
374 	cr_file(&finfo, vp_move_to_arch, &move, 0, "moving extended header");
375 
376 	xbidx = 0;	/* Reset xbuffer index to start of buffer. */
377 }
378 
379 /*
380  * Prepare and write out the extended header
381  */
382 /* ARGSUSED */
383 EXPORT void
info_to_xhdr(info,ptb)384 info_to_xhdr(info, ptb)
385 	register FINFO	*info;
386 	register TCB	*ptb;
387 {
388 		char	name[MAX_UNAME+1];
389 	register Ulong	xflags;
390 extern	long	hdrtype;
391 extern	BOOL	dodump;
392 
393 	if (no_xheader)
394 		return;
395 
396 	if (ghdr) {
397 		/*
398 		 * Delayed writing of a 'g' header is required.
399 		 */
400 		write_xhdr('g');
401 		ghdr = FALSE;
402 	}
403 
404 	xflags = info->f_xflags & (props.pr_xhmask | XF_NOTIME);
405 	/*
406 	 * Unless we really don't want extended sub-second resolution
407 	 * timestamps or a specific selection of timestams has been set up,
408 	 * include all times (atime/ctime/mtime) if we need to include extended
409 	 * headers at all.
410 	 */
411 	if ((xflags & (XF_ATIME|XF_CTIME|XF_MTIME|XF_NOTIME)) == 0)
412 		xflags |= (XF_ATIME|XF_CTIME|XF_MTIME);
413 	else if (xflags & XF_NOTIME)
414 		xflags &= ~(XF_ATIME|XF_CTIME|XF_MTIME);
415 
416 #ifdef	DEBUG_XHDR
417 	xflags = 0xffffffff;
418 #endif
419 	if ((xflags & ~XF_NOTIME) == 0)
420 		return;
421 
422 	if (xflags & XF_ATIME) {
423 		check_xtime("atime", info);
424 		gen_xtime("atime", info->f_atime, info->f_ansec);
425 	}
426 	if (xflags & XF_CTIME) {
427 		check_xtime("ctime", info);
428 		gen_xtime("ctime", info->f_ctime, info->f_cnsec);
429 	}
430 	if (xflags & XF_MTIME) {
431 		check_xtime("mtime", info);
432 		gen_xtime("mtime", info->f_mtime, info->f_mnsec);
433 	}
434 
435 	if (xflags & XF_UID) {
436 		/* LINTED */
437 		if (info->f_uid >= 0)
438 			gen_unumber("uid", (Ullong)info->f_uid);
439 		else
440 			gen_number("uid", (Llong)info->f_uid);
441 	}
442 	if (xflags & XF_GID) {
443 		/* LINTED */
444 		if (info->f_gid >= 0)
445 			gen_unumber("gid", (Ullong)info->f_gid);
446 		else
447 			gen_number("gid", (Llong)info->f_gid);
448 	}
449 
450 	if (xflags & XF_UNAME) {
451 		ic_nameuid(name, sizeof (name)-1, info->f_uid);
452 		gen_text("uname", name, (size_t)-1, T_UTF8);
453 	}
454 	if (xflags & XF_GNAME) {
455 		ic_namegid(name, sizeof (name)-1, info->f_gid);
456 		gen_text("gname", name, (size_t)-1, T_UTF8);
457 	}
458 
459 	if (xflags & XF_PATH) {
460 		gen_text("path", info->f_name, (size_t)-1,
461 			(info->f_flags & F_ADDSLASH) != 0 ?
462 				(T_ADDSLASH|T_UTF8) : T_UTF8);
463 	}
464 
465 	if (xflags & XF_LINKPATH && info->f_lnamelen)
466 		gen_text("linkpath", info->f_lname, (size_t)-1, T_UTF8);
467 
468 	if (xflags & XF_SIZE)
469 		gen_unumber("size", (Ullong)info->f_rsize);
470 
471 	/*
472 	 * If "SCHILY.realsize" is needed, it must be past any "size" keyword
473 	 * in case a "size" keyword is also present.
474 	 */
475 	if (xflags & XF_REALSIZE)
476 		gen_unumber("SCHILY.realsize", (Ullong)info->f_size);
477 	if (xflags & XF_OFFSET)
478 		gen_unumber("SCHILY.offset", (Ullong)info->f_contoffset);
479 
480 	if (H_TYPE(hdrtype) == H_SUNTAR) {
481 		if (xflags & XF_DEVMAJOR) {
482 			/* LINTED */
483 			if (info->f_rdevmaj >= 0)
484 				gen_unumber("SUN.devmajor", (Ullong)info->f_rdevmaj);
485 			else
486 				gen_number("SUN.devmajor", (Llong)info->f_rdevmaj);
487 		}
488 		if (xflags & XF_DEVMINOR) {
489 			/* LINTED */
490 			if (info->f_rdevmin >= 0)
491 				gen_unumber("SUN.devminor", (Ullong)info->f_rdevmin);
492 			else
493 				gen_number("SUN.devminor", (Llong)info->f_rdevmin);
494 		}
495 	} else {
496 		if (xflags & XF_DEVMAJOR) {
497 			/* LINTED */
498 			if (info->f_rdevmaj >= 0)
499 				gen_unumber("SCHILY.devmajor", (Ullong)info->f_rdevmaj);
500 			else
501 				gen_number("SCHILY.devmajor", (Llong)info->f_rdevmaj);
502 		}
503 		if (xflags & XF_DEVMINOR) {
504 			/* LINTED */
505 			if (info->f_rdevmin >= 0)
506 				gen_unumber("SCHILY.devminor", (Ullong)info->f_rdevmin);
507 			else
508 				gen_number("SCHILY.devminor", (Llong)info->f_rdevmin);
509 		}
510 	}
511 
512 #ifdef	USE_ACL
513 	/*
514 	 * POSIX draft Access Control Lists, currently supported e.g. by Linux.
515 	 * Solaris ACLs have been converted to POSIX draft ACLs before.
516 	 */
517 #ifdef	__later__
518 	if (xflags & (XF_ACL_ACCESS|XF_ACL_DEFAULT)) {
519 		gen_text("SCHILY.acl.type", "POSIX draft", 11, 0);
520 	}
521 	if (xflags & XF_ACL_ACE) {
522 		gen_text("SCHILY.acl.type", "NFSv4", 5, 0);
523 	}
524 #endif
525 	if (xflags & XF_ACL_ACE) {
526 		gen_text("SCHILY.acl.ace", info->f_acl_ace, (size_t)-1, T_UTF8);
527 	}
528 
529 	if (xflags & XF_ACL_ACCESS) {
530 		gen_text("SCHILY.acl.access", info->f_acl_access,
531 							(size_t)-1, T_UTF8);
532 	}
533 
534 	if (xflags & XF_ACL_DEFAULT) {
535 		gen_text("SCHILY.acl.default", info->f_acl_default,
536 							(size_t)-1, T_UTF8);
537 	}
538 #endif  /* USE_ACL */
539 
540 #ifdef USE_XATTR
541 	if ((xflags & XF_XATTR) && info->f_xattr) {
542 		star_xattr_t	*x;
543 
544 		for (x = info->f_xattr; x->name; x++) {
545 			char aname[PATH_MAX];
546 			js_snprintf(aname, PATH_MAX, "SCHILY.xattr.%s", x->name);
547 			gen_text(aname, x->value, x->value_len, 0);
548 		}
549 	}
550 #endif  /* USE_XATTR */
551 
552 #ifdef	USE_FFLAGS
553 	if (xflags & XF_FFLAGS) {
554 extern char	*textfromflags	__PR((FINFO *, char *));
555 
556 		char	fbuf[512];
557 		gen_text("SCHILY.fflags", textfromflags(info, fbuf),
558 							(size_t)-1, 0);
559 	}
560 #endif
561 
562 	if (dodump) {
563 #ifdef	__future__
564 		gen_unumber("SCHILY.fsdevmajor", (Ullong)major(info->f_dev));
565 		gen_unumber("SCHILY.fsdevminor", (Ullong)minor(info->f_dev));
566 #endif
567 		/* LINTED */
568 		if (info->f_dev >= 0)
569 			gen_unumber("SCHILY.dev", (Ullong)info->f_dev);
570 		else
571 			gen_number("SCHILY.dev", (Llong)info->f_dev);
572 		gen_unumber("SCHILY.ino", (Ullong)info->f_ino);
573 		gen_unumber("SCHILY.nlink", (Ullong)info->f_nlink);
574 		gen_text("SCHILY.filetype", XTTONAME(info->f_rxftype),
575 								(size_t)-1, 0);
576 #ifdef	__needed__
577 		if (info->f_rxftype != info->f_xftype)
578 			gen_text("SCHILY.tarfiletype", XTTONAME(info->f_xftype),
579 								(size_t)-1, 0);
580 #endif
581 		if (is_dir(info)) {
582 			size_t	oidx = xbidx;
583 
584 			if (info->f_dir)
585 				gen_text("SCHILY.dir",
586 					info->f_dir, info->f_dirlen, T_UTF8);
587 			/*
588 			 * Estimate same length for inode array and dir content
589 			 * Add 1 to (xbidx - oidx) as "SCHILY.dino" is one
590 			 * longer than "SCHILY.dir".
591 			 */
592 			if (info->f_dirinos)
593 				gen_iarray("SCHILY.dino",
594 					info->f_dirinos, info->f_dirents,
595 					xbidx - oidx + 1);
596 		}
597 	} else if (is_multivol(info)) {
598 		gen_text("SCHILY.filetype", XTTONAME(info->f_rxftype),
599 								(size_t)-1, 0);
600 	}
601 
602 	write_xhdr(props.pr_xc);
603 }
604 
605 LOCAL void
check_xtime(keyword,info)606 check_xtime(keyword, info)
607 	register char	*keyword;
608 	register FINFO	*info;
609 {
610 	long	l = 0;	/* Make GCC happy */
611 
612 	if (*keyword == 'a')
613 		l = info->f_ansec;
614 	else if (*keyword == 'c')
615 		l = info->f_cnsec;
616 	else if (*keyword == 'm')
617 		l = info->f_mnsec;
618 
619 	if (l >= 0 && l < 1000000000)
620 		return;
621 
622 	/*
623 	 * check_xtime() is used in write mode so info->f_name is valid.
624 	 */
625 	errmsgno(EX_BAD, "Bad '%s' nsec value %ld for '%s' at %lld.\n",
626 		keyword, l, info->f_name, tblocks());
627 	l = 0;
628 
629 	if (*keyword == 'a')
630 		info->f_ansec = l;
631 	else if (*keyword == 'c')
632 		info->f_cnsec = l;
633 	else if (*keyword == 'm')
634 		info->f_mnsec = l;
635 }
636 
637 /*
638  * Create a time string with sub-second granularity.
639  *
640  * <length> <time-name-spec>=<seconds>.<nano-seconds>\n
641  *
642  *	00 atime=<seconds>.123456789\n
643  *	00 ctime=<seconds>.123456789\n
644  *	00 mtime=<seconds>.123456789\n
645  *
646  *	00 mtime=.123456789\n
647  *	.123456789.123456789
648  *
649  * As we always emmit 9 digits for the sub-second part, the
650  * length of this entry is always more than 20 and less than 100.
651  * The size of an entry is 20 + the size of the "seconds" part of the entry.
652  * With 64 bit unsigned numbers, the "seconds" part will be 20 char at max.
653  * We may safely fill in the two digit <length> later, when we know the value.
654  *
655  * The code is highly optimised because in PAX (extended TAR) mode we are
656  * spending a significant amount of user CPU time in it.
657  */
658 EXPORT void
gen_xtime(keyword,sec,nsec)659 gen_xtime(keyword, sec, nsec)
660 		char	*keyword;
661 	register time_t	sec;
662 	register Ulong	nsec;
663 {
664 		char	nb[32];
665 	register char	*p;
666 	register char	*np;
667 	register size_t	len;
668 
669 	if (nsec >= 1000000000)	/* We would create an unusable string */
670 		nsec = 0;
671 
672 	if ((xbidx + 100) > xblen)
673 		xbgrow(100);
674 
675 	/*
676 	 * The following code is equivalent to:
677 	 *
678 	 * sprintf(p, "%d %s=%lld.%9.9ld\n", length, keyword, (Llong)sec, nsec)
679 	 *
680 	 * But is twice as fast.
681 	 */
682 	len = 20;		/* Base length, second field must be added  */
683 	p = &xbuf[xbidx+2];	/* point past length field		    */
684 	/*
685 	 * Fill in " ?time="
686 	 */
687 	*p++ = ' ';
688 	if (keyword[0] == 'a' || keyword[0] == 'c' || keyword[0] == 'm') {
689 		*p++ = keyword[0];
690 		*p++ = 't'; *p++ = 'i'; *p++ = 'm'; *p++ = 'e';
691 	} else {
692 		len = 15;	/* 2digitlen + ' ' + '=' + '.' + nsec + '\n' */
693 		np = keyword;
694 		while ((*p++ = *np++) != '\0')
695 			len++;
696 		--p;
697 	}
698 	*p++ = '=';
699 	if (sec < 0) {		/* Time is before 01.01.1970 ...	    */
700 		*p++ = '-';
701 		sec = -sec;
702 		len += 1;
703 	}
704 
705 	np = &nb[sizeof (nb)-1]; /* Point to end of number string buffer    */
706 	*np = '\0';		/* Null terminate			    */
707 	ui2decimal(sec, np);	/* Convert to unsigned decimal string	    */
708 	len += &nb[sizeof (nb)-1] - np;
709 
710 	scopy(p, np);		/* Copy number string buffer to xheader	    */
711 	--p,			/* Overshoot compensation		    */
712 	*p++ = '.';		/* Decimal point between secs and nsecs	    */
713 
714 	np = &p[10];		/* Point to end of <nsec> string part	    */
715 	*np = '\0';		/* Null terminate			    */
716 	*--np = '\n';		/* Newline at end of line		    */
717 	ui2decimal(nsec, np);	/* Convert to unsigned decimal string	    */
718 	while (np > p)
719 		*--np = '0';	/* Left fill with '0' to 9 digits	    */
720 
721 	np = &xbuf[xbidx+2];	/* Point to end of length string part	    */
722 	xbidx += len;		/* 'len' is trashed in ui2decimal()	    */
723 	ui2decimal(len, np);	/* Convert to unsigned decimal string	    */
724 }
725 
726 /*
727  * Create a generic unsigned number string.
728  *
729  * <length> <name-spec>=<value>\n
730  *
731  * The length of this entry is always less than 100 chars if the length of the
732  * 'name-spec' is less than 75 chars (the maximum length of a 64 bit number in
733  * decimal is 20 digits). Even in case of a 128 bit number length will be less
734  * than 100 chars if the length of 'name-spec' is less than 55 chars.
735  *
736  * The code is highly optimised because in dump mode when using extended TAR
737  * headers with additional fields, we are spending a significant amount of
738  * user CPU time in it.
739  */
740 EXPORT void
gen_unumber(keyword,arg)741 gen_unumber(keyword, arg)
742 	register char	*keyword;
743 	register Ullong	arg;
744 {
745 		char	nb[64];	/* 41 is enough for unsigned 128 bit ints    */
746 	register char	*p;
747 	register char	*np;
748 	register size_t	len;
749 	register size_t	i;
750 
751 	if ((xbidx + 100) > xblen)
752 		xbgrow(100);
753 
754 	/*
755 	 * The following code is equivalent to:
756 	 *
757 	 * sprintf(p, "%d %s=%llu\n", length, keyword, arg);
758 	 *
759 	 * But is twice as fast.
760 	 */
761 	np = &nb[sizeof (nb)-1]; /* Point to end of number string buffer    */
762 	*np = '\0';		/* Null terminate			    */
763 	ui2decimal(arg, np);	/* Convert to unsigned decimal string	    */
764 
765 	len = strlen(keyword);	/* Compute the length, start with strlen(kw) */
766 
767 	len += &nb[sizeof (nb)-1] - np;	/* Add strlen(number)		    */
768 	len += 2 + 3;		/* Add 2 for strlen(len) and 3 for " =\n"   */
769 
770 	if (len < 10) {		/* If < 10, the len field is 1 digit only   */
771 		len -= 1;	/* This happens when strlen(keyword) is < 4 */
772 		i = 1;		/* and number is one digit only.	    */
773 	} else {
774 		i = 2;
775 	}
776 	p = &xbuf[xbidx+i];	/* Point past length field		    */
777 	*p++ = ' ';		/* Fill in space after length field	    */
778 	scopy(p, keyword);	/* Copy keyword into to xheader		    */
779 	--p,			/* Overshoot compensation		    */
780 	*p++ = '=';		/* Fill in '=' after keyword field	    */
781 
782 	scopy(p, np);		/* Copy number string buffer to xheader	    */
783 	*--p = '\n';		/* Newline at end of line		    */
784 
785 	np = &xbuf[xbidx+i];	/* Point to end of length string part	    */
786 	xbidx += len;		/* 'len' is trashed in ui2decimal()	    */
787 	ui2decimal(len, np);	/* Convert to unsigned decimal string	    */
788 }
789 
790 /*
791  * Create a generic signed number string.
792  *
793  * <length> <name-spec>=<value>\n
794  *
795  * The length of this entry is always less than 100 chars if the length of the
796  * 'name-spec' is less than 75 chars (the maximum length of a 64 bit number in
797  * decimal is 20 digits). Even in case of a 128 bit number length will be less
798  * than 100 chars if the length of 'name-spec' is less than 55 chars.
799  *
800  * The code is highly optimised because in dump mode when using extended TAR
801  * headers with additional fields, we are spending a significant amount of
802  * user CPU time in it.
803  */
804 EXPORT void
gen_number(keyword,arg)805 gen_number(keyword, arg)
806 	register char	*keyword;
807 	register Llong	arg;
808 {
809 		char	nb[64];	/* 41 is enough for unsigned 128 bit ints    */
810 	register char	*p;
811 	register char	*np;
812 	register size_t	len;
813 	register size_t	i;
814 		BOOL	neg = FALSE;
815 
816 	if ((xbidx + 100) > xblen)
817 		xbgrow(100);
818 
819 	/*
820 	 * The following code is equivalent to:
821 	 *
822 	 * sprintf(p, "%d %s=%lld\n", length, keyword, arg);
823 	 *
824 	 * But is twice as fast.
825 	 */
826 	np = &nb[sizeof (nb)-1]; /* Point to end of number string buffer    */
827 	*np = '\0';		/* Null terminate			    */
828 	if (arg < 0) {
829 		arg = -arg;
830 		neg = TRUE;
831 	}
832 	ui2decimal(arg, np);	/* Convert to unsigned decimal string	    */
833 	if (neg)
834 		*--np = '-';
835 
836 	len = strlen(keyword);	/* Compute the length, start with strlen(kw) */
837 
838 	len += &nb[sizeof (nb)-1] - np;	/* Add strlen(number)		    */
839 	len += 2 + 3;		/* Add 2 for strlen(len) and 3 for " =\n"   */
840 
841 	if (len < 10) {		/* If < 10, the len field is 1 digit only   */
842 		len -= 1;	/* This happens when strlen(keyword) is < 4 */
843 		i = 1;		/* and number is one digit only.	    */
844 	} else {
845 		i = 2;
846 	}
847 	p = &xbuf[xbidx+i];	/* Point past length field		    */
848 	*p++ = ' ';		/* Fill in space after length field	    */
849 	scopy(p, keyword);	/* Copy keyword into to xheader		    */
850 	--p,			/* Overshoot compensation		    */
851 	*p++ = '=';		/* Fill in '=' after keyword field	    */
852 
853 	scopy(p, np);		/* Copy number string buffer to xheader	    */
854 	*--p = '\n';		/* Newline at end of line		    */
855 
856 	np = &xbuf[xbidx+i];	/* Point to end of length string part	    */
857 	xbidx += len;		/* 'len' is trashed in ui2decimal()	    */
858 	ui2decimal(len, np);	/* Convert to unsigned decimal string	    */
859 }
860 
861 /*
862  * Create a string from an array of unsigned inode numbers.
863  *
864  * <length> <keyword>=<values>\n
865  *
866  * <values> is a space separated list of unsigned integers in decimal ascii.
867  *
868  * The len parameter is the estimated length of the whole string. It is used
869  * to pre-allocate a buffer that hopefully has the right size already in order
870  * to avoid copying the content.
871  *
872  * The code is highly optimised because in dump mode when using extended TAR
873  * headers with additional fields, we are spending a significant amount of
874  * user CPU time in it.
875  */
876 LOCAL void
gen_iarray(keyword,arg,ents,len)877 gen_iarray(keyword, arg, ents, len)
878 	register char	*keyword;
879 		ino_t	*arg;
880 		size_t	ents;
881 	register size_t	len;	/* Estimated length */
882 {
883 		char	nb[64];	/* 41 is enough for unsigned 128 bit ints    */
884 	register Ullong	ll;
885 	register char	*p;
886 	register char	*np;
887 	register size_t	i;
888 	register size_t	llen;
889 	register size_t	olen;
890 
891 	/*
892 	 * The following code is equivalent to:
893 	 *
894 	 * sprintf(p, "%d %s=%llu %llu ...\n", length, keyword, arg[...]...);
895 	 *
896 	 * But avoids copying if possible.
897 	 */
898 	i = len;
899 	if (len <= 0)			/* No estimated length already	    */
900 		len = strlen(keyword) + 3; /* + ' ' + '=' + '\n'	    */
901 	olen = len;
902 	len += llen = len_len(len);	/* add length of length string	    */
903 
904 	if (i <= 0)
905 		i = len + ents * 2;	/* Make a minimal guess on the len  */
906 	else
907 		i = len;		/* Use guessed value from parameter */
908 
909 	if ((xbidx + i) > xblen)
910 		xbgrow(i);
911 
912 	p = &xbuf[xbidx+llen];	/* Point past length field		    */
913 	*p++ = ' ';		/* Fill in space after length field	    */
914 	scopy(p, keyword);	/* Copy keyword into to xheader		    */
915 	--p,			/* Overshoot compensation		    */
916 	*p++ = '=';		/* Fill in '=' after keyword field	    */
917 
918 	len = p - &xbuf[xbidx];	/* strlen(keyword) + ' ' + '='		    */
919 	for (i = 0; i < ents; i++) {
920 		if (((p - xbuf) + 100) > xblen) {
921 			register size_t	xb_idx;
922 			/*
923 			 * The address for xbuf may change in case that
924 			 * realloc() cannot grow the current memory chunk,
925 			 * recalculate 'p' in this case.
926 			 */
927 			xb_idx = p - xbuf;
928 			xbgrow(100);
929 			p = xbuf + xb_idx;
930 		}
931 		ll = (Llong)arg[i];
932 		np = &nb[sizeof (nb)-1]; /* Point to end of number str. buf */
933 		*np = '\0';		/* Null terminate		    */
934 		ui2decimal(ll, np);	/* Convert to unsigned decimal str. */
935 		len += &nb[sizeof (nb)-1] - np;	/* strlen(number)	    */
936 		len += 1;		/* Space (' ') or Newline ('\n')    */
937 
938 		scopy(p, np);		/* Copy number str. buf to xheader  */
939 		p[-1] = ' ';		/* Space at end of number	    */
940 	}
941 	*--p = '\n';			/* Overwrite last space by newline  */
942 	i = p - &xbuf[xbidx] + 1; /* Total string length		    */
943 	i -= llen;		/* Subtract old length length value	    */
944 
945 	if (olen != i) {	/* Length without length string changed	    */
946 		olen = llen;	/* Save old length string length	    */
947 		llen = len_len(i);	/* New length of length string	    */
948 		if (olen != llen) {	/* We need to move the whole text   */
949 			p = &xbuf[xbidx+olen];
950 			olen = llen - olen;
951 			movebytes(p, p+olen, i);
952 		}
953 		len = i + llen;
954 	}
955 
956 	np = &xbuf[xbidx+llen];	/* Point to end of length string part	    */
957 	*np = ' ';		/* May have been overwritten by movebytes() */
958 	xbidx += len;		/* 'len' is trashed in ui2decimal()	    */
959 	ui2decimal(len, np);	/* Convert to unsigned decimal string	    */
960 }
961 
962 /*
963  * Create a generic text string in UTF-8 coding.
964  *
965  * <length> <name-spec>=<value>\n
966  *
967  * This function will have to carefully check for the resultant length
968  * and thus compute the total length in advance. If the rare case that the
969  * UTF-8 conversion changes the length so much that the length of the length
970  * string will be different from the estimated value, we need to move whole
971  * text by one.
972  *
973  * The code is highly optimised because in dump mode when using extended TAR
974  * headers with additional fields, we may need to copy directory listings
975  * that are longer then 100000 bytes.
976  */
977 EXPORT void
gen_text(keyword,arg,alen,flags)978 gen_text(keyword, arg, alen, flags)
979 	register char	*keyword;
980 		char	*arg;
981 		size_t	alen;
982 		Uint	flags;
983 {
984 	register char	*p;
985 	register char	*np;
986 	register size_t	len;
987 	register size_t	i;
988 	register size_t	llen;
989 	register size_t	olen;
990 
991 	/*
992 	 * The following code is equivalent to:
993 	 *
994 	 * sprintf(p, "%d %s=%s\n", length, keyword, arg);
995 	 *
996 	 * But avoids copying if possible.
997 	 */
998 	if ((len = alen) == (size_t)-1)
999 		len = strlen(arg);
1000 	alen = len;
1001 	if (flags & T_ADDSLASH)		/* only used if 'path' is a dir	    */
1002 		len++;
1003 
1004 	len += strlen(keyword) + 3;	/* + ' ' + '=' + '\n'		    */
1005 	olen = len;
1006 	len += llen = len_len(len);	/* add length of length string	    */
1007 
1008 	i = len;
1009 	if (flags & T_UTF8)
1010 		i *= 6;			/* UTF-8 Factor may be up to 6!	    */
1011 	if ((xbidx + i) > xblen)
1012 		xbgrow(i);
1013 
1014 
1015 	p = &xbuf[xbidx+llen];	/* Point past length field		    */
1016 	*p++ = ' ';		/* Fill in space after length field	    */
1017 	scopy(p, keyword);	/* Copy keyword into to xheader		    */
1018 	--p,			/* Overshoot compensation		    */
1019 	*p++ = '=';		/* Fill in '=' after keyword field	    */
1020 
1021 	if (flags & T_UTF8 && !binflag) {
1022 		i = to_utf8((Uchar *)p, i, (Uchar *)arg, alen);
1023 		p += i + 1;
1024 	} else {
1025 		p = movebytes(arg, p, alen);
1026 		p++;
1027 	}
1028 
1029 	if (flags & T_ADDSLASH) { /* only used if 'path' is a dir	    */
1030 		i++;		/* String length increases by '/'	    */
1031 		*--p = '/';	/* Slash at end of string		    */
1032 		*++p = '\n';	/* Newline at end of line		    */
1033 	} else {
1034 		*--p = '\n';	/* Newline at end of line		    */
1035 	}
1036 	i = p - &xbuf[xbidx] + 1; /* Total string length		    */
1037 	i -= llen;		/* Subtract old length length value	    */
1038 
1039 	if (olen != i) {	/* Length without length string changed	    */
1040 		olen = llen;	/* Save old length string length	    */
1041 		llen = len_len(i);	/* New length of length string	    */
1042 		if (olen != llen) {	/* We need to move the whole text   */
1043 			p = &xbuf[xbidx+olen];
1044 			olen = llen - olen;
1045 			movebytes(p, p+olen, i);
1046 		}
1047 		len = i + llen;
1048 	}
1049 
1050 	np = &xbuf[xbidx+llen];	/* Point to end of length string part	    */
1051 	*np = ' ';		/* May have been overwritten by movebytes() */
1052 	xbidx += len;		/* 'len' is trashed in ui2decimal()	    */
1053 	ui2decimal(len, np);	/* Convert to unsigned decimal string	    */
1054 }
1055 
1056 /*
1057  * It bad to see new global variables while we are working on a star library.
1058  */
1059 LOCAL	star_xattr_t	*static_xattr;
1060 
1061 /*
1062  * The xattr list grows dynamically. Reset it before reading
1063  * the next Extended Header.
1064  */
1065 EXPORT void
tcb_to_xhdr_reset()1066 tcb_to_xhdr_reset()
1067 {
1068 	/*
1069 	 * XXX Dies soll laut A Gr�nbacher in tcb_to_info() aufgerufen werden
1070 	 */
1071 	free_xattr(&static_xattr);
1072 }
1073 
1074 LOCAL int
len_len(len)1075 len_len(len)
1076 	register size_t	len;
1077 {
1078 	if (len <= 8)
1079 		return (1);
1080 	if (len <= 97)
1081 		return (2);
1082 	if (len <= 996)
1083 		return (3);
1084 	if (len <= 9995)
1085 		return (4);
1086 	if (len <= 99994)
1087 		return (5);
1088 	if (len <= 999993)
1089 		return (6);
1090 	if (len <= 9999992)
1091 		return (7);
1092 	if (len <= 99999991)
1093 		return (8);
1094 	if (len <= 999999990)
1095 		return (9);
1096 
1097 	return (10);
1098 }
1099 
1100 /*
1101  * Lookup command in command tab
1102  */
1103 LOCAL xtab_t *
lookup(cmd,clen,cp)1104 lookup(cmd, clen, cp)
1105 	register char	*cmd;
1106 	register int	clen;
1107 	register xtab_t	*cp;
1108 {
1109 	for (; cp->x_name; cp++) {
1110 		register int	len = cp->x_namelen-1;
1111 
1112 		if (cp->x_name[len] == '*') {
1113 			if (strncmp(cmd, cp->x_name, len) == 0)
1114 				return (cp);
1115 		}
1116 		if (clen != cp->x_namelen)
1117 			continue;
1118 
1119 		if ((*cmd == *cp->x_name) &&
1120 		    strcmp(cmd, cp->x_name) == 0) {
1121 			return (cp);
1122 		}
1123 	}
1124 	return ((xtab_t *)NULL);
1125 }
1126 
1127 /*
1128  * Read extended POSIX.1-2001 header and parse the content.
1129  */
1130 EXPORT int
tcb_to_xhdr(ptb,info)1131 tcb_to_xhdr(ptb, info)
1132 	register TCB	*ptb;
1133 	register FINFO	*info;
1134 {
1135 	register char	*p;
1136 	register char 	*ep;
1137 		FINFO	*oinfo = info;
1138 		move_t	move;
1139 		Ullong	ull;
1140 
1141 #ifdef	XH_DEBUG
1142 error("Block: %lld\n", tblocks());
1143 #endif
1144 	if (ptb->dbuf.t_linkflag == LF_GHDR) {
1145 		grinit();
1146 		info = &ginfo;
1147 	}
1148 	/*
1149 	 * File size is strlen of extended header
1150 	 */
1151 	stolli(ptb->dbuf.t_size, &ull);
1152 	info->f_size = ull;
1153 	info->f_rsize = (off_t)info->f_size;
1154 	/*
1155 	 * Reset xbidx to make xbgrow() work correctly for our case.
1156 	 */
1157 	xbidx = 0;
1158 	if ((info->f_size+1) > xblen)
1159 		xbgrow(info->f_size+1);
1160 
1161 	/*
1162 	 * move_from_arch() always adds null byte to make decoding easier.
1163 	 */
1164 	move.m_data = xbuf;
1165 	move.m_flags = 0;
1166 	if (xt_file(info, vp_move_from_arch, &move, 0,
1167 						"moving extended header") < 0) {
1168 		die(EX_BAD);
1169 	}
1170 
1171 #ifdef	XH_DEBUG
1172 error("Block: %lld\n", tblocks());
1173 error("xbuf: '%s'\n", xbuf);
1174 #endif
1175 
1176 	p = xbuf;
1177 	ep = p + ull;
1178 	if (!no_xheader)
1179 		xhparse(info, p, ep);
1180 
1181 	if (ptb->dbuf.t_linkflag == LF_GHDR) {
1182 		griprint(grip);
1183 		gipsetup(grip);
1184 		info_xcopy(oinfo, info);
1185 	}
1186 	return (get_tcb(ptb));
1187 }
1188 
1189 EXPORT BOOL
xhparse(info,p,ep)1190 xhparse(info, p, ep)
1191 	register FINFO	*info;
1192 	register char	*p;
1193 	register char	*ep;
1194 {
1195 	register xtab_t	*cp;
1196 	register char	*keyword;
1197 	register char 	*arg;
1198 		long	length;
1199 
1200 	while (p < ep) {
1201 		register int klen;
1202 
1203 		if (*p < '0' || *p > '9') {
1204 			errmsgno(EX_BAD,
1205 			"Syntax error in extended header: non digit in len at %lld.\n",
1206 			tblocks());
1207 			return (FALSE);
1208 		}
1209 		keyword = astolb(p, &length, 10);
1210 		if (*keyword != ' ') {
1211 			errmsgno(EX_BAD,
1212 			"Syntax error in extended header: missing ' ' at %lld.\n",
1213 			tblocks());
1214 			return (FALSE);
1215 		}
1216 		keyword++;
1217 		arg = strchr(keyword, '=');
1218 		klen = arg - keyword;
1219 		if ((arg == NULL) || (klen > length)) {
1220 			errmsgno(EX_BAD,
1221 			"Syntax error in extended header: missing '=' at %lld.\n",
1222 			tblocks());
1223 			return (FALSE);
1224 		}
1225 		*arg++ = '\0';			/* Kill equal sign */
1226 
1227 		if (*(p + length -1) != '\n') {
1228 			arg[-1] = '=';
1229 			errmsgno(EX_BAD,
1230 			"Syntax error in extended header: missing '\\n' at %lld.\n",
1231 			tblocks());
1232 			return (FALSE);
1233 		}
1234 		*(p + length -1) = '\0';	/* Kill new-line character */
1235 
1236 		if ((cp = lookup(keyword, klen, xtab)) != NULL) {
1237 			(*cp->x_func)(info, keyword, klen,
1238 						arg, length - (arg-p) - 1);
1239 		} else {
1240 			print_unknown(keyword);
1241 		}
1242 		arg[-1] = '=';
1243 		p += length;
1244 		p[-1] = '\n';
1245 	}
1246 	return (TRUE);
1247 }
1248 
1249 LOCAL void
print_unknown(keyword)1250 print_unknown(keyword)
1251 	register char	*keyword;
1252 {
1253 	register unkn_t	*up = unkn;
1254 
1255 	while (up) {
1256 		if (streql(keyword, up->u_name))
1257 			break;
1258 		up = up->u_next;
1259 	}
1260 	if (up == NULL) {
1261 		errmsgno(EX_BAD,
1262 			"Unknown extended header keyword '%s' ignored at %lld.\n",
1263 				keyword, tblocks());
1264 
1265 		up = ___malloc(sizeof (*up) + strlen(keyword), "unknown list");
1266 		strcpy(up->u_name, keyword);
1267 		up->u_next = unkn;
1268 		unkn = up;
1269 	}
1270 }
1271 
1272 EXPORT void
xh_rangeerr(keyword,arg,len)1273 xh_rangeerr(keyword, arg, len)
1274 	char	*keyword;
1275 	char	*arg;
1276 	size_t	len;
1277 {
1278 	if (nowarn)
1279 		return;
1280 	errmsgno(EX_BAD,
1281 		"WARNING: %s '%.*s' in extended header at %lld exceeds local range.\n",
1282 		keyword, (int)len, arg, tblocks());
1283 }
1284 
1285 LOCAL void
print_toolong(keyword,arg,len)1286 print_toolong(keyword, arg, len)
1287 	char	*keyword;
1288 	char	*arg;
1289 	size_t	len;
1290 {
1291 	if (nowarn)
1292 		return;
1293 	errmsgno(EX_BAD,
1294 		"WARNING: %s '%.*s' in extended header at %lld too long, ignoring.\n",
1295 		keyword, (int)len, arg, tblocks());
1296 }
1297 
1298 LOCAL void
get_xvolhdr(info,keyword,klen,arg,len)1299 get_xvolhdr(info, keyword, klen, arg, len)
1300 	FINFO	*info;
1301 	char	*keyword;
1302 	int	klen;
1303 	char	*arg;
1304 	size_t	len;
1305 {
1306 	register xtab_t	*cp;
1307 extern		xtab_t	volhtab[];
1308 
1309 	if ((cp = lookup(keyword, klen, volhtab)) != NULL) {
1310 		(*cp->x_func)(info, keyword, klen,
1311 					arg, len);
1312 	} else {
1313 		print_unknown(keyword);
1314 	}
1315 }
1316 
1317 LOCAL void
info_xcopy(ninfo,oinfo)1318 info_xcopy(ninfo, oinfo)
1319 	register FINFO	*ninfo;
1320 	register FINFO	*oinfo;
1321 {
1322 	if (oinfo->f_xflags & XF_ATIME) {
1323 		ninfo->f_atime = oinfo->f_atime;
1324 		ninfo->f_ansec = oinfo->f_ansec;
1325 		ninfo->f_xflags |= XF_ATIME;
1326 	}
1327 	if (oinfo->f_xflags & XF_CTIME) {
1328 		ninfo->f_ctime = oinfo->f_ctime;
1329 		ninfo->f_cnsec = oinfo->f_cnsec;
1330 		ninfo->f_xflags |= XF_CTIME;
1331 	}
1332 	if (oinfo->f_xflags & XF_MTIME) {
1333 		ninfo->f_mtime = oinfo->f_mtime;
1334 		ninfo->f_mnsec = oinfo->f_mnsec;
1335 		ninfo->f_xflags |= XF_MTIME;
1336 	}
1337 	/* We ignore XF_COMMENT */
1338 	if (oinfo->f_xflags & XF_UID) {
1339 		ninfo->f_uid = oinfo->f_uid;
1340 		ninfo->f_xflags |= XF_UID;
1341 	}
1342 	if (oinfo->f_xflags & XF_UNAME) {
1343 		strcpy(guname, oinfo->f_uname);
1344 		ninfo->f_uname = oinfo->f_uname;
1345 		ninfo->f_umaxlen = ninfo->f_umaxlen;
1346 		oinfo->f_uname = guname;
1347 		ninfo->f_xflags |= XF_UNAME;
1348 	}
1349 	if (oinfo->f_xflags & XF_GID) {
1350 		ninfo->f_gid = oinfo->f_gid;
1351 		ninfo->f_xflags |= XF_GID;
1352 	}
1353 	if (oinfo->f_xflags & XF_GNAME) {
1354 		strcpy(ggname, oinfo->f_gname);
1355 		ninfo->f_gname = oinfo->f_gname;
1356 		ninfo->f_gmaxlen = ninfo->f_gmaxlen;
1357 		oinfo->f_gname = ggname;
1358 		ninfo->f_xflags |= XF_GNAME;
1359 	}
1360 	if (oinfo->f_xflags & XF_PATH) {
1361 		strcpy(ninfo->f_name, oinfo->f_name);
1362 		ninfo->f_xflags |= XF_PATH;
1363 	}
1364 	if (oinfo->f_xflags & XF_LINKPATH) {
1365 		strcpy(ninfo->f_lname, oinfo->f_lname);
1366 		ninfo->f_xflags |= XF_LINKPATH;
1367 	}
1368 
1369 	if (oinfo->f_xflags & XF_SIZE) {
1370 		ninfo->f_rsize = oinfo->f_rsize;
1371 		ninfo->f_xflags |= XF_SIZE;
1372 	}
1373 	/* XF_CHARSET currently is a dummy */
1374 
1375 	if (oinfo->f_xflags & XF_DEVMAJOR) {
1376 		ninfo->f_rdevmaj = oinfo->f_rdevmaj;
1377 		ninfo->f_xflags |= XF_DEVMAJOR;
1378 	}
1379 	if (oinfo->f_xflags & XF_DEVMINOR) {
1380 		ninfo->f_rdevmin = oinfo->f_rdevmin;
1381 		ninfo->f_xflags |= XF_DEVMINOR;
1382 	}
1383 	if (oinfo->f_xflags & (XF_ACL_ACCESS|XF_ACL_DEFAULT)) {
1384 		errmsgno(EX_BAD, "WARNING: Found global ACL data at %lld.\n",
1385 			tblocks());
1386 	}
1387 	if (oinfo->f_xflags & XF_FFLAGS) {
1388 		ninfo->f_fflags = oinfo->f_fflags;
1389 		ninfo->f_xflags |= XF_FFLAGS;
1390 	}
1391 	if (oinfo->f_xflags & XF_REALSIZE) {
1392 		ninfo->f_size = oinfo->f_size;
1393 		ninfo->f_xflags |= XF_REALSIZE;
1394 	}
1395 	if (oinfo->f_xflags & XF_OFFSET) {
1396 		ninfo->f_contoffset = oinfo->f_contoffset;
1397 		ninfo->f_xflags |= XF_OFFSET;
1398 	}
1399 	if (oinfo->f_xflags & XF_XATTR) {
1400 		errmsgno(EX_BAD, "WARNING: Found global XATTR data at %lld.\n",
1401 			tblocks());
1402 	}
1403 }
1404 
1405 /*
1406  * generic function to read args that hold times
1407  *
1408  * The time may either be in second resolution or in sub-second resolution.
1409  * In the latter case the second fraction and the sub second fraction
1410  * is separated by a dot ('.').
1411  */
1412 EXPORT BOOL
get_xtime(keyword,arg,len,secp,nsecp)1413 get_xtime(keyword, arg, len, secp, nsecp)
1414 	char	*keyword;
1415 	char	*arg;
1416 	size_t	len;
1417 	time_t	*secp;
1418 	long	*nsecp;
1419 {
1420 #ifdef	__use_default_time__
1421 extern struct	timespec	ddate;
1422 #endif
1423 	Llong	ll;
1424 	long	l;
1425 	int	flen;
1426 	char	*p;
1427 
1428 	p = astollb(arg, &ll, 10);
1429 	if (*p == '\0' || *p == '.') {
1430 		time_t	secs = ll;
1431 		if (secs != ll) {
1432 			xh_rangeerr(keyword, arg, len);
1433 #ifdef	__use_default_time__
1434 			*secp = ddate.tv_sec;
1435 #endif
1436 			goto bad;
1437 		}
1438 		*secp = ll;		/* XXX Check for NULL ptr? */
1439 	}
1440 	if (*p == '\0') {		/* time has second resolution only */
1441 		if (nsecp == NULL)
1442 			return (TRUE);
1443 		*nsecp = 0;
1444 		return (TRUE);
1445 	} else if (*p == '.') {		/* time has sub-second resolution */
1446 		flen = strlen(++p);	/* remember resolution		    */
1447 		if (flen > 9)		/* if resolution is better than	    */
1448 			p[9] = '\0';	/* nanoseconds kill rest of line as */
1449 		p = astolb(p, &l, 10);	/* we don't understand more.	    */
1450 		if (*p == '\0') {	/* number read correctly	    */
1451 			if (l >= 0) {
1452 				while (flen < 9) {	/* convert to nsecs */
1453 					l *= 10;
1454 					flen++;
1455 				}
1456 				if (nsecp == NULL)
1457 					return (TRUE);
1458 				*nsecp = l;
1459 				return (TRUE);
1460 			}
1461 		}
1462 	}
1463 bad:
1464 	errmsgno(EX_BAD, "Bad timespec '%s' for '%s' in extended header at %lld.\n",
1465 		arg, keyword, tblocks());
1466 	return (FALSE);
1467 }
1468 
1469 /*
1470  * get read access time from extended header
1471  */
1472 /* ARGSUSED */
1473 LOCAL void
get_atime(info,keyword,klen,arg,len)1474 get_atime(info, keyword, klen, arg, len)
1475 	FINFO	*info;
1476 	char	*keyword;
1477 	int	klen;
1478 	char	*arg;
1479 	size_t	len;
1480 {
1481 	if (len == 0) {
1482 		info->f_xflags &= ~XF_ATIME;
1483 		return;
1484 	}
1485 	if (get_xtime(keyword, arg, len, &info->f_atime, &info->f_ansec))
1486 		info->f_xflags |= XF_ATIME;
1487 }
1488 
1489 /*
1490  * get inode status change time from extended header
1491  */
1492 /* ARGSUSED */
1493 LOCAL void
get_ctime(info,keyword,klen,arg,len)1494 get_ctime(info, keyword, klen, arg, len)
1495 	FINFO	*info;
1496 	char	*keyword;
1497 	int	klen;
1498 	char	*arg;
1499 	size_t	len;
1500 {
1501 	if (len == 0) {
1502 		info->f_xflags &= ~XF_CTIME;
1503 		return;
1504 	}
1505 	if (get_xtime(keyword, arg, len, &info->f_ctime, &info->f_cnsec))
1506 		info->f_xflags |= XF_CTIME;
1507 }
1508 
1509 /*
1510  * get modification time from extended header
1511  */
1512 /* ARGSUSED */
1513 LOCAL void
get_mtime(info,keyword,klen,arg,len)1514 get_mtime(info, keyword, klen, arg, len)
1515 	FINFO	*info;
1516 	char	*keyword;
1517 	int	klen;
1518 	char	*arg;
1519 	size_t	len;
1520 {
1521 	if (len == 0) {
1522 		info->f_xflags &= ~XF_MTIME;
1523 		return;
1524 	}
1525 	if (get_xtime(keyword, arg, len, &info->f_mtime, &info->f_mnsec))
1526 		info->f_xflags |= XF_MTIME;
1527 }
1528 
1529 /*
1530  * generic function to read args that hold decimal numbers
1531  */
1532 #ifdef	__needed_
1533 EXPORT BOOL
get_number(keyword,arg,llp)1534 get_number(keyword, arg, llp)
1535 	char	*keyword;
1536 	char	*arg;
1537 	Llong	*llp;
1538 {
1539 	Llong	ll;
1540 	char	*p;
1541 
1542 	p = astollb(arg, &ll, 10);
1543 	if (*p == '\0') {		/* number read correctly */
1544 		*llp = ll;		/* XXX Check for NULL ptr? */
1545 		return (TRUE);
1546 	}
1547 	errmsgno(EX_BAD, "Bad number '%s' for '%s' in extended header at %lld.\n",
1548 		arg, keyword, tblocks());
1549 	return (FALSE);
1550 }
1551 #endif
1552 
1553 /*
1554  * generic function to read args that hold unsigned decimal numbers
1555  */
1556 LOCAL BOOL
get_xnumber(keyword,arg,ullp,type)1557 get_xnumber(keyword, arg, ullp, type)
1558 	char	*keyword;
1559 	char	*arg;
1560 	Ullong	*ullp;
1561 	char	*type;
1562 {
1563 	Ullong	ull;
1564 	char	*p;
1565 
1566 	seterrno(0);
1567 	p = astoullb(arg, &ull, 10);
1568 	if (*p == '\0') {		/* number read correctly */
1569 		if (geterrno() != 0) {
1570 			errmsgno(EX_BAD,
1571 			"Number overflow with '%s' for '%s' in extended header at %lld.\n",
1572 			arg, keyword, tblocks());
1573 			return (FALSE);
1574 		}
1575 		*ullp = ull;		/* XXX Check for NULL ptr? */
1576 		return (TRUE);
1577 	}
1578 	errmsgno(EX_BAD, "Bad %s number '%s' for '%s' in extended header at %lld.\n",
1579 		type,
1580 		arg, keyword, tblocks());
1581 	return (FALSE);
1582 }
1583 
1584 EXPORT BOOL
get_unumber(keyword,arg,ullp,maxval)1585 get_unumber(keyword, arg, ullp, maxval)
1586 	char	*keyword;
1587 	char	*arg;
1588 	Ullong	*ullp;
1589 	Ullong	maxval;
1590 {
1591 	if (!get_xnumber(keyword, arg, ullp, "unsigned"))
1592 		return (FALSE);
1593 
1594 	if (*ullp > maxval) {
1595 		errmsgno(EX_BAD,
1596 		"Value '%s' is out of range 0..%llu for '%s' in extended header at %lld.\n",
1597 		arg, maxval, keyword, tblocks());
1598 		return (FALSE);
1599 	}
1600 	return (TRUE);
1601 }
1602 
1603 
1604 /*
1605  * generic function to read args that hold signed decimal numbers
1606  */
1607 EXPORT BOOL
get_snumber(keyword,arg,ullp,negp,minval,maxval)1608 get_snumber(keyword, arg, ullp, negp, minval, maxval)
1609 	char	*keyword;
1610 	char	*arg;
1611 	Ullong	*ullp;
1612 	BOOL	*negp;
1613 	Ullong	minval;
1614 	Ullong	maxval;
1615 {
1616 	char	*p = arg;
1617 #define	is_space(c)	 ((c) == ' ' || (c) == '\t')
1618 
1619 	while (is_space(*p))
1620 		p++;
1621 
1622 	*negp = FALSE;
1623 	if (*p == '-') {
1624 		p++;
1625 		*negp = TRUE;
1626 	}
1627 	return (get_xnumber(keyword, p, ullp, "signed"));
1628 }
1629 
1630 /*
1631  * get user id (if > 2097151)
1632  * POSIX requires uid_t to be a signed int but the values for uid_t to be
1633  * non-negative.
1634  * We allow signed ints and carefully check the values.
1635  */
1636 /* ARGSUSED */
1637 LOCAL void
get_uid(info,keyword,klen,arg,len)1638 get_uid(info, keyword, klen, arg, len)
1639 	FINFO	*info;
1640 	char	*keyword;
1641 	int	klen;
1642 	char	*arg;
1643 	size_t	len;
1644 {
1645 	Ullong	ull;
1646 	BOOL	neg = FALSE;
1647 
1648 	if (len == 0) {
1649 		info->f_xflags &= ~XF_UID;
1650 		return;
1651 	}
1652 	if (get_snumber(keyword, arg, &ull, &neg,
1653 					-(Ullong)UID_T_MIN, UID_T_MAX)) {
1654 		info->f_xflags |= XF_UID;
1655 		if (neg)
1656 			info->f_uid = -ull;
1657 		else
1658 			info->f_uid = ull;
1659 
1660 		if ((neg && -info->f_uid != ull) ||
1661 			(!neg && info->f_uid != ull)) {
1662 
1663 			xh_rangeerr(keyword, arg, len);
1664 			info->f_flags |= F_BAD_UID;
1665 			info->f_uid = ic_uid_nobody();
1666 		}
1667 	}
1668 }
1669 
1670 /*
1671  * get group id (if > 2097151)
1672  * POSIX requires gid_t to be a signed int but the values for gid_t to be
1673  * non-negative.
1674  * We allow signed ints and carefully check the values.
1675  */
1676 /* ARGSUSED */
1677 LOCAL void
get_gid(info,keyword,klen,arg,len)1678 get_gid(info, keyword, klen, arg, len)
1679 	FINFO	*info;
1680 	char	*keyword;
1681 	int	klen;
1682 	char	*arg;
1683 	size_t	len;
1684 {
1685 	Ullong	ull;
1686 	BOOL	neg = FALSE;
1687 
1688 	if (len == 0) {
1689 		info->f_xflags &= ~XF_GID;
1690 		return;
1691 	}
1692 	if (get_snumber(keyword, arg, &ull, &neg,
1693 					-(Ullong)GID_T_MIN, GID_T_MAX)) {
1694 		info->f_xflags |= XF_UID;
1695 		if (neg)
1696 			info->f_gid = -ull;
1697 		else
1698 			info->f_gid = ull;
1699 
1700 		if ((neg && -info->f_gid != ull) ||
1701 			(!neg && info->f_gid != ull)) {
1702 
1703 			xh_rangeerr(keyword, arg, len);
1704 			info->f_flags |= F_BAD_GID;
1705 			info->f_gid = ic_gid_nobody();
1706 		}
1707 	}
1708 }
1709 
1710 /*
1711  * Space for returning user/group names.
1712  * XXX If we ever change to use allocated space, we need to change info_xcopy()
1713  */
1714 LOCAL	Uchar	_uname[MAX_UNAME+2];
1715 LOCAL	Uchar	_gname[MAX_UNAME+2];
1716 
1717 /*
1718  * get user name (if name length is > 32 chars or if contains non ASCII chars)
1719  */
1720 /* ARGSUSED */
1721 LOCAL void
get_uname(info,keyword,klen,arg,len)1722 get_uname(info, keyword, klen, arg, len)
1723 	FINFO	*info;
1724 	char	*keyword;
1725 	int	klen;
1726 	char	*arg;
1727 	size_t	len;
1728 {
1729 	if (len == 0) {
1730 		info->f_xflags &= ~XF_UNAME;
1731 		return;
1732 	}
1733 	if (len > MAX_UNAME) {
1734 		print_toolong(keyword, arg, len);
1735 		return;
1736 	}
1737 	if (ginfo.f_xflags & XF_BINARY) {
1738 		strcpy((char *)_uname, arg);
1739 		info->f_xflags |= XF_UNAME;
1740 		info->f_uname = (char *)_uname;
1741 		info->f_umaxlen = len;
1742 	} else if (from_utf8(_uname, sizeof (_uname), (Uchar *)arg, &len)) {
1743 		info->f_xflags |= XF_UNAME;
1744 		info->f_uname = (char *)_uname;
1745 		info->f_umaxlen = len;
1746 	} else {
1747 		bad_utf8(keyword, arg);
1748 	}
1749 }
1750 
1751 /*
1752  * get group name (if name length is > 32 chars or if contains non ASCII chars)
1753  */
1754 /* ARGSUSED */
1755 LOCAL void
get_gname(info,keyword,klen,arg,len)1756 get_gname(info, keyword, klen, arg, len)
1757 	FINFO	*info;
1758 	char	*keyword;
1759 	int	klen;
1760 	char	*arg;
1761 	size_t	len;
1762 {
1763 	if (len == 0) {
1764 		info->f_xflags &= ~XF_GNAME;
1765 		return;
1766 	}
1767 	if (len > MAX_UNAME) {
1768 		print_toolong(keyword, arg, len);
1769 		return;
1770 	}
1771 	if (ginfo.f_xflags & XF_BINARY) {
1772 		strcpy((char *)_gname, arg);
1773 		info->f_xflags |= XF_GNAME;
1774 		info->f_gname = (char *)_gname;
1775 		info->f_gmaxlen = len;
1776 	} else if (from_utf8(_gname, sizeof (_gname), (Uchar *)arg, &len)) {
1777 		info->f_xflags |= XF_GNAME;
1778 		info->f_gname = (char *)_gname;
1779 		info->f_gmaxlen = len;
1780 	} else {
1781 		bad_utf8(keyword, arg);
1782 	}
1783 }
1784 
1785 /*
1786  * get path (if name length is > 100-255 chars or if contains non ASCII chars)
1787  */
1788 /* ARGSUSED */
1789 LOCAL void
get_path(info,keyword,klen,arg,len)1790 get_path(info, keyword, klen, arg, len)
1791 	FINFO	*info;
1792 	char	*keyword;
1793 	int	klen;
1794 	char	*arg;
1795 	size_t	len;
1796 {
1797 	if (len == 0) {
1798 		info->f_xflags &= ~XF_PATH;
1799 		return;
1800 	}
1801 
1802 	/*
1803 	 * Check whether we are called via get_xhtype() -> xhparse()
1804 	 */
1805 	if (info->f_name == NULL)
1806 		return;
1807 
1808 	if (ginfo.f_xflags & XF_BINARY) {
1809 		if (strlcpy_pspace(PS_STDERR, &info->f_pname, arg, len) < 0) {
1810 			print_toolong(keyword, arg, len);
1811 			info->f_xflags |= F_BAD_META;
1812 			return;
1813 		}
1814 		info->f_name = info->f_pname.ps_path;
1815 		info->f_namelen = len;
1816 		info->f_xflags |= XF_PATH;
1817 	} else {
1818 		size_t	ilen = len;
1819 		BOOL	ret;
1820 
1821 		do {
1822 			len = ilen;
1823 			ret = from_utf8((Uchar *)info->f_name,
1824 					info->f_pname.ps_size,
1825 					(Uchar *)arg, &len);
1826 			if (len >= info->f_pname.ps_size) {
1827 				/*
1828 				 * An increment of 1 is OK, since it is unlikely
1829 				 * that the path grows by more than 256 per dir.
1830 				 */
1831 				if (incr_pspace(PS_STDERR,
1832 						&info->f_pname, 1) < 0) {
1833 					print_toolong(keyword, arg, len);
1834 					info->f_xflags |= F_BAD_META;
1835 					return;
1836 				}
1837 				info->f_name = info->f_pname.ps_path;
1838 			} else
1839 				break;
1840 		} while (1);
1841 
1842 		if (ret) {
1843 			info->f_namelen = len;
1844 			info->f_xflags |= XF_PATH;
1845 		} else {
1846 			bad_utf8(keyword, arg);
1847 		}
1848 	}
1849 }
1850 
1851 /*
1852  * get link path (if name length is > 100 chars or if contains non ASCII chars)
1853  */
1854 /* ARGSUSED */
1855 LOCAL void
get_lpath(info,keyword,klen,arg,len)1856 get_lpath(info, keyword, klen, arg, len)
1857 	FINFO	*info;
1858 	char	*keyword;
1859 	int	klen;
1860 	char	*arg;
1861 	size_t	len;
1862 {
1863 	if (len == 0) {
1864 		info->f_xflags &= ~XF_LINKPATH;
1865 		return;
1866 	}
1867 
1868 	/*
1869 	 * Check whether we are called via get_xhtype() -> xhparse()
1870 	 */
1871 	if (info->f_lname == NULL)
1872 		return;
1873 
1874 	if (ginfo.f_xflags & XF_BINARY) {
1875 		if (strlcpy_pspace(PS_STDERR, &info->f_plname, arg, len) < 0) {
1876 			print_toolong(keyword, arg, len);
1877 			info->f_xflags |= F_BAD_META;
1878 			return;
1879 		}
1880 		info->f_lname = info->f_plname.ps_path;
1881 		info->f_lnamelen = len;
1882 		info->f_xflags |= XF_LINKPATH;
1883 	} else {
1884 		size_t	ilen = len;
1885 		BOOL	ret;
1886 
1887 		do {
1888 			len = ilen;
1889 			ret = from_utf8((Uchar *)info->f_lname,
1890 					info->f_plname.ps_size,
1891 					(Uchar *)arg, &len);
1892 			if (len >= info->f_plname.ps_size) {
1893 				/*
1894 				 * An increment of 1 is OK, since it is unlikely
1895 				 * that the path grows by more than 256 per dir.
1896 				 */
1897 				if (incr_pspace(PS_STDERR,
1898 						&info->f_plname, 1) < 0) {
1899 					print_toolong(keyword, arg, len);
1900 					info->f_xflags |= F_BAD_META;
1901 					return;
1902 				}
1903 				info->f_lname = info->f_plname.ps_path;
1904 			} else
1905 				break;
1906 		} while (1);
1907 
1908 		if (ret) {
1909 			info->f_lnamelen = len;
1910 			info->f_xflags |= XF_LINKPATH;
1911 		} else {
1912 			bad_utf8(keyword, arg);
1913 		}
1914 	}
1915 }
1916 
1917 /*
1918  * get size, either real size or size on tape (usually when size is > 8 GB)
1919  * The file size is doubtlessly an ungined integer
1920  */
1921 /* ARGSUSED */
1922 LOCAL void
get_size(info,keyword,klen,arg,len)1923 get_size(info, keyword, klen, arg, len)
1924 	FINFO	*info;
1925 	char	*keyword;
1926 	int	klen;
1927 	char	*arg;
1928 	size_t	len;
1929 {
1930 	Ullong	ull;
1931 
1932 	if (len == 0) {
1933 		info->f_xflags &= ~XF_SIZE;
1934 		return;
1935 	}
1936 	if (get_unumber(keyword, arg, &ull, OFF_T_MAX)) {
1937 		info->f_xflags |= XF_SIZE;
1938 		info->f_llsize = ull;
1939 		info->f_rsize = (off_t)ull;
1940 		if (info->f_rsize != ull) {
1941 			xh_rangeerr(keyword, arg, len);
1942 			ull = 0;
1943 			info->f_flags |= (F_BAD_META | F_BAD_SIZE);
1944 			info->f_rsize = (off_t)ull;
1945 		}
1946 		/*
1947 		 * If real size is not yet known, copy over the tape size to
1948 		 * avoid problems. If real size is found later, it will
1949 		 * overwrite unconditional.
1950 		 */
1951 		if ((info->f_xflags & XF_REALSIZE) == 0) {
1952 			info->f_xflags |= XF_REALSIZE;
1953 			info->f_size = (off_t)ull;
1954 		}
1955 	}
1956 }
1957 
1958 /*
1959  * get real file size (usually when size is > 8 GB)
1960  * The real file size is doubtlessly an ungined integer
1961  */
1962 /* ARGSUSED */
1963 LOCAL void
get_realsize(info,keyword,klen,arg,len)1964 get_realsize(info, keyword, klen, arg, len)
1965 	FINFO	*info;
1966 	char	*keyword;
1967 	int	klen;
1968 	char	*arg;
1969 	size_t	len;
1970 {
1971 	Ullong	ull;
1972 
1973 	if (len == 0) {
1974 		info->f_xflags &= ~XF_REALSIZE;
1975 		return;
1976 	}
1977 	if (get_unumber(keyword, arg, &ull, OFF_T_MAX)) {
1978 		info->f_xflags |= XF_REALSIZE;
1979 		info->f_size = (off_t)ull;
1980 		if (info->f_size != ull) {
1981 			xh_rangeerr(keyword, arg, len);
1982 			info->f_size = (off_t)0;
1983 		}
1984 	}
1985 }
1986 
1987 /*
1988  * get multivolume file offset (usually when size is > 8 GB)
1989  * The multivolume file offset is doubtlessly an ungined integer
1990  */
1991 /* ARGSUSED */
1992 LOCAL void
get_offset(info,keyword,klen,arg,len)1993 get_offset(info, keyword, klen, arg, len)
1994 	FINFO	*info;
1995 	char	*keyword;
1996 	int	klen;
1997 	char	*arg;
1998 	size_t	len;
1999 {
2000 	Ullong	ull;
2001 
2002 	if (len == 0) {
2003 		info->f_xflags &= ~XF_OFFSET;
2004 		return;
2005 	}
2006 	if (get_unumber(keyword, arg, &ull, OFF_T_MAX)) {
2007 		info->f_xflags |= XF_OFFSET;
2008 		info->f_contoffset = (off_t)ull;
2009 		if (info->f_contoffset != ull) {
2010 			xh_rangeerr(keyword, arg, len);
2011 			info->f_contoffset = (off_t)0;
2012 		}
2013 	}
2014 }
2015 
2016 /*
2017  * get major device number (always vendor unique)
2018  * The major device number should be unsigned but POSIX does not say anything
2019  * about the content and defined dev_t to be a signed int.
2020  */
2021 /* ARGSUSED */
2022 LOCAL void
get_major(info,keyword,klen,arg,len)2023 get_major(info, keyword, klen, arg, len)
2024 	FINFO	*info;
2025 	char	*keyword;
2026 	int	klen;
2027 	char	*arg;
2028 	size_t	len;
2029 {
2030 	Ullong	ull;
2031 	BOOL	neg = FALSE;
2032 	dev_t	d;
2033 
2034 	if (len == 0) {
2035 		info->f_xflags &= ~XF_DEVMAJOR;
2036 		return;
2037 	}
2038 	if (get_snumber(keyword, arg, &ull, &neg,
2039 					-(Ullong)MAJOR_T_MIN, MAJOR_T_MAX)) {
2040 		info->f_xflags |= XF_DEVMAJOR;
2041 		if (neg)
2042 			info->f_rdevmaj = -ull;
2043 		else
2044 			info->f_rdevmaj = ull;
2045 		d = makedev(info->f_rdevmaj, 0);
2046 		d = major(d);
2047 		if ((neg && -d != ull) || (!neg && d != ull)) {
2048 			xh_rangeerr(keyword, arg, len);
2049 			info->f_flags |= F_BAD_META;
2050 		}
2051 	}
2052 }
2053 
2054 /*
2055  * get minor device number (always vendor unique)
2056  * The minor device number should be unsigned but POSIX does not say anything
2057  * about the content and defined dev_t to be a signed int.
2058  */
2059 /* ARGSUSED */
2060 LOCAL void
get_minor(info,keyword,klen,arg,len)2061 get_minor(info, keyword, klen, arg, len)
2062 	FINFO	*info;
2063 	char	*keyword;
2064 	int	klen;
2065 	char	*arg;
2066 	size_t	len;
2067 {
2068 	Ullong	ull;
2069 	BOOL	neg = FALSE;
2070 	dev_t	d;
2071 
2072 	if (len == 0) {
2073 		info->f_xflags &= ~XF_DEVMINOR;
2074 		return;
2075 	}
2076 	if (get_snumber(keyword, arg, &ull, &neg,
2077 					-(Ullong)MINOR_T_MIN, MINOR_T_MAX)) {
2078 		info->f_xflags |= XF_DEVMINOR;
2079 		if (neg)
2080 			info->f_rdevmin = -ull;
2081 		else
2082 			info->f_rdevmin = ull;
2083 		d = makedev(0, info->f_rdevmin);
2084 		d = minor(d);
2085 		if ((neg && -d != ull) || (!neg && d != ull)) {
2086 			xh_rangeerr(keyword, arg, len);
2087 			info->f_flags |= F_BAD_META;
2088 		}
2089 	}
2090 }
2091 
2092 /*
2093  * get major device number for st_dev (always vendor unique)
2094  * The major device number should be unsigned but POSIX does not say anything
2095  * about the content and defined dev_t to be a signed int.
2096  */
2097 /* ARGSUSED */
2098 LOCAL void
get_fsmajor(info,keyword,klen,arg,len)2099 get_fsmajor(info, keyword, klen, arg, len)
2100 	FINFO	*info;
2101 	char	*keyword;
2102 	int	klen;
2103 	char	*arg;
2104 	size_t	len;
2105 {
2106 	Ullong	ull;
2107 	BOOL	neg = FALSE;
2108 	dev_t	d;
2109 
2110 	if (len == 0) {
2111 		info->f_xflags &= ~XF_FSDEVMAJOR;
2112 		return;
2113 	}
2114 	if (get_snumber(keyword, arg, &ull, &neg,
2115 					-(Ullong)MAJOR_T_MIN, MAJOR_T_MAX)) {
2116 		info->f_xflags |= XF_FSDEVMAJOR;
2117 		if (neg)
2118 			info->f_devmaj = -ull;
2119 		else
2120 			info->f_devmaj = ull;
2121 		d = makedev(info->f_devmaj, 0);
2122 		d = major(d);
2123 		if ((neg && -d != ull) || (!neg && d != ull)) {
2124 			xh_rangeerr(keyword, arg, len);
2125 			info->f_flags |= F_BAD_META;
2126 		}
2127 	}
2128 	if (info->f_xflags & XF_FSDEVMINOR)
2129 		info->f_dev = makedev(info->f_devmaj, info->f_devmin);
2130 }
2131 
2132 /*
2133  * get minor device number for st_dev (always vendor unique)
2134  * The minor device number should be unsigned but POSIX does not say anything
2135  * about the content and defined dev_t to be a signed int.
2136  */
2137 /* ARGSUSED */
2138 LOCAL void
get_fsminor(info,keyword,klen,arg,len)2139 get_fsminor(info, keyword, klen, arg, len)
2140 	FINFO	*info;
2141 	char	*keyword;
2142 	int	klen;
2143 	char	*arg;
2144 	size_t	len;
2145 {
2146 	Ullong	ull;
2147 	BOOL	neg = FALSE;
2148 	dev_t	d;
2149 
2150 	if (len == 0) {
2151 		info->f_xflags &= ~XF_FSDEVMINOR;
2152 		return;
2153 	}
2154 	if (get_snumber(keyword, arg, &ull, &neg,
2155 					-(Ullong)MINOR_T_MIN, MINOR_T_MAX)) {
2156 		info->f_xflags |= XF_FSDEVMINOR;
2157 		if (neg)
2158 			info->f_devmin = -ull;
2159 		else
2160 			info->f_devmin = ull;
2161 		d = makedev(0, info->f_devmin);
2162 		d = minor(d);
2163 		if ((neg && -d != ull) || (!neg && d != ull)) {
2164 			xh_rangeerr(keyword, arg, len);
2165 			info->f_flags |= F_BAD_META;
2166 		}
2167 	}
2168 	if (info->f_xflags & XF_FSDEVMAJOR)
2169 		info->f_dev = makedev(info->f_devmaj, info->f_devmin);
2170 }
2171 
2172 /*
2173  * get number of minor bits for this file (vendor unique)
2174  * This is naturally unsigned.
2175  */
2176 /* ARGSUSED */
2177 LOCAL void
get_minorbits(info,keyword,klen,arg,len)2178 get_minorbits(info, keyword, klen, arg, len)
2179 	FINFO	*info;
2180 	char	*keyword;
2181 	int	klen;
2182 	char	*arg;
2183 	size_t	len;
2184 {
2185 	Ullong	ull;
2186 
2187 	if (len == 0) {
2188 		info->f_devminorbits = 0;
2189 		return;
2190 	}
2191 	if (get_unumber(keyword, arg, &ull, INO_T_MAX)) {
2192 		info->f_devminorbits = ull;
2193 		if (info->f_devminorbits != ull) {
2194 			xh_rangeerr(keyword, arg, len);
2195 			info->f_devminorbits = 0;
2196 		}
2197 	}
2198 }
2199 
2200 /*
2201  * get device number of device containing FS (vendor unique)
2202  * The device number should be unsigned but POSIX does not say anything
2203  * about the content and defined dev_t to be a signed int.
2204  */
2205 /* ARGSUSED */
2206 LOCAL void
get_dev(info,keyword,klen,arg,len)2207 get_dev(info, keyword, klen, arg, len)
2208 	FINFO	*info;
2209 	char	*keyword;
2210 	int	klen;
2211 	char	*arg;
2212 	size_t	len;
2213 {
2214 	Ullong	ull;
2215 	BOOL	neg = FALSE;
2216 
2217 	if (len == 0) {
2218 		info->f_dev = 0;
2219 		return;
2220 	}
2221 	/*
2222 	 * SCHILY.fsdevmajor and SCHILY.fsdevminor win
2223 	 */
2224 	if (info->f_xflags & (XF_FSDEVMAJOR|XF_FSDEVMINOR))
2225 		return;
2226 
2227 	info->f_devmaj = 0;
2228 	info->f_devmin = 0;
2229 	if (get_snumber(keyword, arg, &ull, &neg,
2230 					-(Ullong)DEV_T_MIN, DEV_T_MAX)) {
2231 		int	mbits;
2232 		Llong	ll;
2233 
2234 		if (neg)
2235 			info->f_dev = ll = -ull;
2236 		else
2237 			info->f_dev = ll = ull;
2238 
2239 		mbits = info->f_devminorbits;
2240 		if (mbits == 0)
2241 			mbits = ginfo.f_devminorbits;
2242 		if (mbits) {
2243 			int	oerr = geterrno();
2244 
2245 			seterrno(0);
2246 			info->f_devmaj	= _dev_major(mbits, ll);
2247 			info->f_devmin	= _dev_minor(mbits, ll);
2248 			info->f_dev = makedev(info->f_devmaj, info->f_devmin);
2249 			ull = dev_make(info->f_devmaj, info->f_devmin);
2250 			/*
2251 			 * Check whether the device from the archive
2252 			 * can be represented on the local system.
2253 			 * We only need info->f_dev to detect a mount point
2254 			 * so there is no problem that some platforms with
2255 			 * non-contiguous minor bits cannot be used to compute
2256 			 * info->f_devmaj and info->f_devmin.
2257 			 * So do not warn for related problems when minorbits
2258 			 * is 0.
2259 			 */
2260 			if (geterrno() ||
2261 			    info->f_devmaj != major(info->f_dev) ||
2262 			    info->f_devmin != minor(info->f_dev) ||
2263 			    (minorbits != 0 && (Ullong)info->f_dev != ull)) {
2264 				xh_rangeerr(keyword, arg, len);
2265 				info->f_dev = 0;
2266 				info->f_devmaj = 0;
2267 				info->f_devmin = 0;
2268 			}
2269 			seterrno(oerr);
2270 			return;
2271 		}
2272 		/*
2273 		 * Let us hope that both, the archiving and the
2274 		 * extracting system use the same major()/minor()
2275 		 * mapping.
2276 		 */
2277 		info->f_devmaj	= major(ll);
2278 		info->f_devmin	= minor(ll);
2279 
2280 		if ((neg && -info->f_dev != ull) ||
2281 			(!neg && info->f_dev != ull)) {
2282 			xh_rangeerr(keyword, arg, len);
2283 			info->f_dev = 0;
2284 		}
2285 	}
2286 }
2287 
2288 /*
2289  * get inode number for this file (vendor unique)
2290  * POSIX defines ino_t to be unsigned.
2291  */
2292 /* ARGSUSED */
2293 LOCAL void
get_ino(info,keyword,klen,arg,len)2294 get_ino(info, keyword, klen, arg, len)
2295 	FINFO	*info;
2296 	char	*keyword;
2297 	int	klen;
2298 	char	*arg;
2299 	size_t	len;
2300 {
2301 	Ullong	ull;
2302 
2303 	if (len == 0) {
2304 		info->f_ino = 0;
2305 		return;
2306 	}
2307 	if (get_unumber(keyword, arg, &ull, INO_T_MAX)) {
2308 		info->f_ino = ull;
2309 		if (info->f_ino != ull) {
2310 			xh_rangeerr(keyword, arg, len);
2311 			info->f_ino = 0;
2312 		}
2313 	}
2314 }
2315 
2316 /*
2317  * get link count for this file (vendor unique)
2318  * POSIX defines nlink_t to ne signed but all real link counts in archives
2319  * need to be positive numbers.
2320  */
2321 /* ARGSUSED */
2322 LOCAL void
get_nlink(info,keyword,klen,arg,len)2323 get_nlink(info, keyword, klen, arg, len)
2324 	FINFO	*info;
2325 	char	*keyword;
2326 	int	klen;
2327 	char	*arg;
2328 	size_t	len;
2329 {
2330 	Ullong	ull;
2331 
2332 	if (len == 0) {
2333 		info->f_nlink = 0;
2334 		return;
2335 	}
2336 	if (get_unumber(keyword, arg, &ull, NLINK_T_MAX)) {
2337 		info->f_nlink = ull;
2338 		if (info->f_nlink != ull) {
2339 			xh_rangeerr(keyword, arg, len);
2340 			info->f_nlink = 0;
2341 		}
2342 	}
2343 }
2344 
2345 /*
2346  * get tar file type or real file type for this file (vendor unique)
2347  */
2348 /* ARGSUSED */
2349 LOCAL void
get_filetype(info,keyword,klen,arg,len)2350 get_filetype(info, keyword, klen, arg, len)
2351 	FINFO	*info;
2352 	char	*keyword;
2353 	int	klen;
2354 	char	*arg;
2355 	size_t	len;
2356 {
2357 	int	i;
2358 
2359 	if (len == 0) {
2360 		if (keyword[7] == 'f')		/* "SCHILY.filetype" */
2361 			info->f_rxftype = XT_BAD;
2362 		else
2363 			info->f_xftype = XT_BAD;
2364 		return;
2365 	}
2366 
2367 	for (i = 0; i <= XT_BAD; i++) {
2368 		if (xtnamelen_tab[i] != len)
2369 			continue;
2370 		if (streql(xttoname_tab[i], arg))
2371 			break;
2372 	}
2373 	if (i >= XT_BAD)			/* Use type from tarhdr */
2374 		return;
2375 
2376 	if (keyword[7] == 'f') {		/* "SCHILY.filetype" */
2377 		info->f_rxftype = i;
2378 		info->f_filetype = XTTOST(info->f_rxftype);
2379 		info->f_type = XTTOIF(info->f_rxftype);
2380 	} else {				/* "SCHILY.tarfiletype" */
2381 		info->f_xftype = i;
2382 	}
2383 }
2384 
2385 #ifdef	USE_ACL
2386 
2387 /*
2388  * XXX acl_access_text/acl_default_text are a bad idea. (see acl_unix.c)
2389  */
2390 LOCAL pathstore_t	acl_access_text;
2391 LOCAL pathstore_t	acl_default_text;
2392 
2393 /* ARGSUSED */
2394 LOCAL void
get_acl_type(info,keyword,klen,arg,len)2395 get_acl_type(info, keyword, klen, arg, len)
2396 	FINFO	*info;
2397 	char	*keyword;
2398 	int	klen;
2399 	char	*arg;
2400 	size_t	len;
2401 {
2402 	if (len == 11 && streql(arg, "POSIX draft"))
2403 		return;
2404 	if (len == 5 && streql(arg, "NFSv4"))
2405 		return;
2406 
2407 	info->f_flags |= F_BAD_ACL;
2408 
2409 	if (badf & F_BAD_ACL)
2410 		return;
2411 	errmsgno(EX_BAD,
2412 		"Unknown ACL type '%s' ignored at %lld.\n",
2413 				arg, tblocks());
2414 	badf |= F_BAD_ACL;
2415 }
2416 
2417 /* ARGSUSED */
2418 LOCAL void
get_acl_access(info,keyword,klen,arg,len)2419 get_acl_access(info, keyword, klen, arg, len)
2420 	FINFO	*info;
2421 	char	*keyword;
2422 	int	klen;
2423 	char	*arg;
2424 	size_t	len;
2425 {
2426 	if (len == 0 || (info->f_flags & F_BAD_ACL)) {
2427 		info->f_xflags &= ~XF_ACL_ACCESS;
2428 		info->f_acl_access = NULL;
2429 		return;
2430 	}
2431 	if ((len + 2) > acl_access_text.ps_size)
2432 		grow_pspace(PS_EXIT, &acl_access_text, (len + 2));
2433 	if (acl_access_text.ps_path == NULL)
2434 		return;
2435 	if (ginfo.f_xflags & XF_BINARY) {
2436 		strcpy(acl_access_text.ps_path, arg);
2437 		info->f_xflags |= XF_ACL_ACCESS;
2438 		info->f_acl_access = acl_access_text.ps_path;
2439 	} else if (from_utf8((Uchar *)acl_access_text.ps_path,
2440 		    acl_access_text.ps_size,
2441 		    (Uchar *)arg, &len)) {
2442 		info->f_xflags |= XF_ACL_ACCESS;
2443 		info->f_acl_access = acl_access_text.ps_path;
2444 	} else {
2445 		bad_utf8(keyword, arg);
2446 	}
2447 }
2448 
2449 /* ARGSUSED */
2450 LOCAL void
get_acl_default(info,keyword,klen,arg,len)2451 get_acl_default(info, keyword, klen, arg, len)
2452 	FINFO	*info;
2453 	char	*keyword;
2454 	int	klen;
2455 	char	*arg;
2456 	size_t	len;
2457 {
2458 	if (len == 0 || (info->f_flags & F_BAD_ACL)) {
2459 		info->f_xflags &= ~XF_ACL_DEFAULT;
2460 		info->f_acl_default = NULL;
2461 		return;
2462 	}
2463 	if ((len + 2) > acl_default_text.ps_size)
2464 		grow_pspace(PS_EXIT, &acl_default_text, (len + 2));
2465 	if (acl_default_text.ps_path == NULL)
2466 		return;
2467 	if (ginfo.f_xflags & XF_BINARY) {
2468 		strcpy(acl_default_text.ps_path, arg);
2469 		info->f_xflags |= XF_ACL_DEFAULT;
2470 		info->f_acl_default = acl_default_text.ps_path;
2471 	} else if (from_utf8((Uchar *)acl_default_text.ps_path,
2472 		    acl_default_text.ps_size,
2473 		    (Uchar *)arg, &len)) {
2474 		info->f_xflags |= XF_ACL_DEFAULT;
2475 		info->f_acl_default = acl_default_text.ps_path;
2476 	} else {
2477 		bad_utf8(keyword, arg);
2478 	}
2479 }
2480 
2481 LOCAL pathstore_t	acl_ace_text;
2482 
2483 /* ARGSUSED */
2484 LOCAL void
get_acl_ace(info,keyword,klen,arg,len)2485 get_acl_ace(info, keyword, klen, arg, len)
2486 	FINFO	*info;
2487 	char	*keyword;
2488 	int	klen;
2489 	char	*arg;
2490 	size_t	len;
2491 {
2492 	if (len == 0 || (info->f_flags & F_BAD_ACL)) {
2493 		info->f_xflags &= ~XF_ACL_ACE;
2494 		info->f_acl_ace = NULL;
2495 		return;
2496 	}
2497 	if ((len + 2) > acl_ace_text.ps_size)
2498 		grow_pspace(PS_EXIT, &acl_ace_text, (len + 2));
2499 	if (acl_ace_text.ps_path == NULL)
2500 		return;
2501 	if (ginfo.f_xflags & XF_BINARY) {
2502 		strcpy(acl_ace_text.ps_path, arg);
2503 		info->f_xflags |= XF_ACL_ACE;
2504 		info->f_acl_ace = acl_ace_text.ps_path;
2505 	} else if (from_utf8((Uchar *)acl_ace_text.ps_path,
2506 		    acl_ace_text.ps_size,
2507 		    (Uchar *)arg, &len)) {
2508 		info->f_xflags |= XF_ACL_ACE;
2509 		info->f_acl_ace = acl_ace_text.ps_path;
2510 	} else {
2511 		bad_utf8(keyword, arg);
2512 	}
2513 }
2514 
2515 #endif  /* USE_ACL */
2516 
2517 #ifdef USE_XATTR
2518 
2519 /* ARGSUSED */
2520 LOCAL void
get_attr(info,keyword,klen,arg,len)2521 get_attr(info, keyword, klen, arg, len)
2522 	FINFO	*info;
2523 	char	*keyword;
2524 	int	klen;
2525 	char	*arg;
2526 	size_t	len;
2527 {
2528 	register star_xattr_t	*x;
2529 	register size_t		num = 0;
2530 
2531 #ifdef	__never__
2532 	/*
2533 	 * This is definitely wrong, since we may have a single empty xattr
2534 	 * and the code below disables all xattrs for the current file.
2535 	 */
2536 	if (len == 0) {
2537 		/*
2538 		 * This is not the right way as we clear all xattr info.
2539 		 */
2540 		if (static_xattr) {
2541 			free(static_xattr);
2542 			static_xattr = NULL;
2543 		}
2544 		info->f_fflags = 0;
2545 		info->f_xflags &= ~XF_FFLAGS;
2546 		return;
2547 	}
2548 #endif
2549 	if (static_xattr) {
2550 		for (x = static_xattr; x->name; x++)
2551 			num++;
2552 		x = ___realloc(static_xattr,
2553 			(num+2) * sizeof (star_xattr_t), "extended attribute");
2554 	} else {
2555 		x = ___malloc(
2556 			(num+2) * sizeof (star_xattr_t), "extended attribute");
2557 	}
2558 	static_xattr = x;
2559 	x += num;
2560 
2561 	/*
2562 	 * should always succeed ...
2563 	 */
2564 	if (strncmp(keyword, "SCHILY.xattr.", 13) == 0)
2565 		keyword += 13;
2566 
2567 	x->name = ___malloc(strlen(keyword)+1, "extended attribute");
2568 	x->value = ___malloc(len+1, "extended attribute");
2569 	strcpy(x->name, keyword);
2570 	x->value_len = len;
2571 	movebytes(arg, x->value, len);
2572 	((char *)x->value)[len] = '\0';
2573 	fillbytes(x+1, sizeof (star_xattr_t), '\0');
2574 
2575 	info->f_xattr = static_xattr;
2576 	info->f_xflags |= XF_XATTR;
2577 }
2578 
2579 #endif  /* USE_XATTR */
2580 
2581 #ifdef	USE_FFLAGS
2582 
2583 /* ARGSUSED */
2584 LOCAL void
get_xfflags(info,keyword,klen,arg,len)2585 get_xfflags(info, keyword, klen, arg, len)
2586 	FINFO	*info;
2587 	char	*keyword;
2588 	int	klen;
2589 	char	*arg;
2590 	size_t	len;
2591 {
2592 	if (len == 0) {
2593 		info->f_fflags = 0;
2594 		info->f_xflags &= ~XF_FFLAGS;
2595 		return;
2596 	}
2597 	texttoflags(info, arg);
2598 	info->f_xflags |= XF_FFLAGS;
2599 }
2600 
2601 #endif	/* USE_FFLAGS */
2602 
2603 /* ARGSUSED */
2604 LOCAL void
get_dir(info,keyword,klen,arg,len)2605 get_dir(info, keyword, klen, arg, len)
2606 	FINFO	*info;
2607 	char	*keyword;
2608 	int	klen;
2609 	char	*arg;
2610 	size_t	len;
2611 {
2612 	info->f_dir = 0;
2613 	info->f_dirlen = 0;
2614 
2615 	if (len == 0)
2616 		return;
2617 	/*
2618 	 * Old archives had only one nul at the end.
2619 	 * Note that we propagate the space from the xheader extract buffer
2620 	 * to the extraction process (e.g. diff.c or incremental restore.c)
2621 	 */
2622 	if (arg[len-2] != '\0')
2623 		arg[len++] = '\0';	/* Kill '\n' */
2624 
2625 	if (ginfo.f_xflags & XF_BINARY) {
2626 		;
2627 	} else {
2628 		/*
2629 		 * The non UTF-8 string is shorter so we convert in place.
2630 		 */
2631 		from_utf8((Uchar *)arg, len, (Uchar *)arg, &len);
2632 	}
2633 	info->f_dir = arg;
2634 	info->f_dirlen = len;
2635 }
2636 
2637 /* ARGSUSED */
2638 LOCAL void
get_iarray(info,keyword,klen,arg,len)2639 get_iarray(info, keyword, klen, arg, len)
2640 	FINFO	*info;
2641 	char	*keyword;
2642 	int	klen;
2643 	char	*arg;
2644 	size_t	len;
2645 {
2646 	register size_t	dirents = 0;
2647 	register size_t	i;
2648 	register char	*p = arg;
2649 	register ino_t	*ino;
2650 		Ullong	ull;
2651 
2652 	if (info->f_dirinos)
2653 		free(info->f_dirinos);
2654 	info->f_dirinos = NULL;
2655 	info->f_dirents = 0;
2656 
2657 	if (len == 0)
2658 		return;
2659 
2660 	while (p) {
2661 		if (*p == ' ')
2662 			p++;
2663 		p = strchr(p, ' ');
2664 		dirents++;
2665 	}
2666 	ino = ___malloc(dirents * sizeof (ino_t), "inos");
2667 
2668 	for (p = arg, i = 0; i < dirents; i++) {
2669 		if (*p == ' ')
2670 			p++;
2671 		seterrno(0);
2672 		p = astoullb(p, &ull, 10);
2673 		if (*p != ' ' && *p != '\0') {
2674 			errmsgno(EX_BAD,
2675 			"Bad number '%s' for '%s' in extended header al %lld.\n",
2676 							arg, keyword, tblocks());
2677 			/* XXX ino -> 0 and continue instead? */
2678 			free(ino);
2679 			return;
2680 		} else {
2681 			if (geterrno() != 0) {
2682 				errmsgno(EX_BAD,
2683 				"Number overflow with '%s' for '%s' in extended header at %lld.\n",
2684 					arg, keyword, tblocks());
2685 				/* XXX ino -> 0 and continue instead? */
2686 				free(ino);
2687 				return;
2688 			}
2689 		}
2690 		if (ull > INO_T_MAX) {
2691 			xh_rangeerr(keyword, arg, len);
2692 			ino[i] = 0;
2693 		} else {
2694 			ino[i] = ull;
2695 		}
2696 	}
2697 	info->f_dirinos = ino;
2698 	info->f_dirents = dirents;
2699 }
2700 
2701 /* ARGSUSED */
2702 LOCAL void
get_release(info,keyword,klen,arg,len)2703 get_release(info, keyword, klen, arg, len)
2704 	FINFO	*info;
2705 	char	*keyword;
2706 	int	klen;
2707 	char	*arg;
2708 	size_t	len;
2709 {
2710 	if (len == 0) {
2711 		if (grip->release) {
2712 			if ((grip->gflags & GF_NOALLOC) == 0)
2713 				free(grip->release);
2714 			grip->release = NULL;
2715 		}
2716 		grip->gflags &= ~GF_RELEASE;
2717 		return;
2718 	}
2719 	if (ginfo.f_xflags & XF_BINARY) {
2720 		;
2721 	} else {
2722 		/*
2723 		 * The non UTF-8 string is shorter so we convert in place.
2724 		 */
2725 		from_utf8((Uchar *)arg, len, (Uchar *)arg, &len);
2726 	}
2727 	grip->gflags |= GF_RELEASE;
2728 	grip->release = ___savestr(arg);
2729 }
2730 
2731 /* ARGSUSED */
2732 LOCAL void
get_archtype(info,keyword,klen,arg,len)2733 get_archtype(info, keyword, klen, arg, len)
2734 	FINFO	*info;
2735 	char	*keyword;
2736 	int	klen;
2737 	char	*arg;
2738 	size_t	len;
2739 {
2740 	if (len == 0) {
2741 		grip->gflags &= ~GF_ARCHTYPE;
2742 		grip->archtype = H_UNDEF;
2743 		return;
2744 	}
2745 	grip->gflags |= GF_ARCHTYPE;
2746 	grip->archtype = hdr_type(arg);
2747 }
2748 
2749 /*
2750  * Get the charset used for path, linkpath, uname and gname.
2751  */
2752 /* ARGSUSED */
2753 LOCAL void
get_hdrcharset(info,keyword,klen,arg,len)2754 get_hdrcharset(info, keyword, klen, arg, len)
2755 	FINFO	*info;
2756 	char	*keyword;
2757 	int	klen;
2758 	char	*arg;
2759 	size_t	len;
2760 {
2761 #ifdef	__needed__
2762 	BOOL	is_global = info == &ginfo;
2763 #endif
2764 
2765 	if (len == 23 && streql("ISO-IR 10646 2000 UTF-8", arg)) {
2766 		info->f_xflags &= ~XF_BINARY;
2767 	} else if (len == 6 && streql("BINARY", arg)) {
2768 		info->f_xflags |= XF_BINARY;
2769 	} else {
2770 		unsup_arg(keyword, arg);
2771 	}
2772 }
2773 
2774 /*
2775  * Dummy 'get' function used for all fields that we don't yet understand or
2776  * fields that we indent to ignore.
2777  */
2778 /* ARGSUSED */
2779 LOCAL void
get_dummy(info,keyword,klen,arg,len)2780 get_dummy(info, keyword, klen, arg, len)
2781 	FINFO	*info;
2782 	char	*keyword;
2783 	int	klen;
2784 	char	*arg;
2785 	size_t	len;
2786 {
2787 }
2788 
2789 LOCAL void
unsup_arg(keyword,arg)2790 unsup_arg(keyword, arg)
2791 	char	*keyword;
2792 	char	*arg;
2793 {
2794 	errmsgno(EX_BAD,
2795 		"Unsupported arg '%s' for '%s' in extended header at %lld.\n",
2796 		arg, keyword, tblocks());
2797 }
2798 
2799 LOCAL void
bad_utf8(keyword,arg)2800 bad_utf8(keyword, arg)
2801 	char	*keyword;
2802 	char	*arg;
2803 {
2804 	errmsgno(EX_BAD, "Bad UTF-8 arg '%s' for '%s' in extended header at %lld.\n",
2805 		arg, keyword, tblocks());
2806 }
2807