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