]> git.saurik.com Git - apple/file_cmds.git/blob - pax/pax_format.c
3ac97ed41068311520863b890096fe7d6790bf3e
[apple/file_cmds.git] / pax / pax_format.c
1 /*-
2 * Copyright (c) 1992 Keith Muller.
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Keith Muller of the University of California, San Diego.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 #if 0
36 static const char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94";
37 #else
38 static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tar.c,v 1.34 2004/10/23 19:34:14 otto Exp $";
39 #endif
40 #endif /* not lint */
41
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <sys/stat.h>
45 #include <sys/param.h>
46 #include <string.h>
47 #include <stdio.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include "pax.h"
51 #include "extern.h"
52 #include "tar.h"
53 #include <fnmatch.h>
54 #include <regex.h>
55 #include "pat_rep.h"
56 #include <errno.h>
57
58 /*
59 * This file implements the -x pax format support; it is incomplete.
60 * Known missing features include:
61 * many -o options for "copy" mode are not implemented (only path=)
62 * many format specifiers for -o listopt are not implemented
63 * -o listopt option should work for all archive formats, not just -x pax
64 * This file was originally derived from the file tar.c. You should
65 * 'diff' it to that file to see how much of the -x pax format has been implemented.
66 */
67
68 char pax_eh_datablk[4*1024];
69 int pax_read_or_list_mode = 0;
70 int want_a_m_time_headers = 0;
71 int want_linkdata = 0;
72
73 int pax_invalid_action = 0;
74 char * pax_invalid_action_write_path = NULL;
75 char * pax_invalid_action_write_cwd = NULL;
76
77 char
78 *path_g, *path_x, *path_g_current, *path_x_current,
79 *uname_g, *uname_x, *uname_g_current, *uname_x_current,
80 *gname_g, *gname_x, *gname_g_current, *gname_x_current,
81 *comment_g, *comment_x, *comment_g_current, *comment_x_current,
82 *charset_g, *charset_x, *charset_g_current, *charset_x_current,
83 *atime_g, *atime_x, *atime_g_current, *atime_x_current,
84 *gid_g, *gid_x, *gid_g_current, *gid_x_current,
85 *linkpath_g, *linkpath_x, *linkpath_g_current, *linkpath_x_current,
86 *mtime_g, *mtime_x, *mtime_g_current, *mtime_x_current,
87 *size_g, *size_x, *size_g_current, *size_x_current,
88 *uid_g, *uid_x, *uid_g_current, *uid_x_current;
89
90 char *header_name_g_requested = NULL,
91 *header_name_x_requested = NULL;
92
93 char *header_name_g = "/tmp/GlobalHead.%p.%n",
94 *header_name_x = "%d/PaxHeaders.%p/%f";
95
96 int nglobal_headers = 0;
97 char *pax_list_opt_format;
98
99 #define O_OPTION_ACTION_NOTIMPL 0
100 #define O_OPTION_ACTION_INVALID 1
101 #define O_OPTION_ACTION_DELETE 2
102 #define O_OPTION_ACTION_STORE_HEADER 3
103 #define O_OPTION_ACTION_TIMES 4
104 #define O_OPTION_ACTION_HEADER_NAME 5
105 #define O_OPTION_ACTION_LISTOPT 6
106 #define O_OPTION_ACTION_LINKDATA 7
107
108 #define O_OPTION_ACTION_IGNORE 8
109 #define O_OPTION_ACTION_ERROR 9
110 #define O_OPTION_ACTION_STORE_HEADER2 10
111
112 #define ATTRSRC_FROM_NOWHERE 0
113 #define ATTRSRC_FROM_X_O_OPTION 1
114 #define ATTRSRC_FROM_G_O_OPTION 2
115 #define ATTRSRC_FROM_X_HEADER 3
116 #define ATTRSRC_FROM_G_HEADER 4
117
118 #define KW_PATH_CASE 0
119 #define KW_SKIP_CASE -1
120 #define KW_ATIME_CASE -2
121
122 typedef struct {
123 char * name;
124 int len;
125 int active; /* 1 means active, 0 means deleted via -o delete= */
126 int cmdline_action;
127 int header_action;
128 /* next 2 entries only used by store_header actions */
129 char ** g_value; /* -o keyword= value */
130 char ** x_value; /* -o keyword:= value */
131 char ** g_value_current; /* keyword= value found in Global extended header */
132 char ** x_value_current; /* keyword= value found in extended header */
133 int header_inx; /* starting index of header field this keyword represents */
134 int header_len; /* length of header field this keyword represents */
135 /* If negative, special cases line path= */
136 } O_OPTION_TYPE;
137
138 O_OPTION_TYPE o_option_table[] = {
139 { "atime", 5, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER,
140 &atime_g, &atime_x, &atime_g_current, &atime_x_current, 0, KW_ATIME_CASE },
141 { "charset", 7, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_IGNORE,
142 &charset_g, &charset_x, &charset_g_current, &charset_x_current, 0, KW_SKIP_CASE },
143 { "comment", 7, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_IGNORE,
144 &comment_g, &comment_x, &comment_g_current, &comment_x_current, 0, KW_SKIP_CASE },
145 { "gid", 3, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2,
146 &gid_g, &gid_x, &gid_g_current, &gid_x_current , 116, 8 },
147 { "gname", 5, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2,
148 &gname_g, &gname_x, &gname_g_current, &gname_x_current, 297, 32 },
149 { "linkpath", 8, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER,
150 &linkpath_g, &linkpath_x, &linkpath_g_current, &linkpath_x_current, 0, KW_SKIP_CASE },
151 { "mtime", 5, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER,
152 &mtime_g, &mtime_x, &mtime_g_current, &mtime_x_current, 136, KW_SKIP_CASE },
153 { "path", 4, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER,
154 &path_g, &path_x, &path_g_current, &path_x_current, 0, KW_PATH_CASE },
155 { "size", 4, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER,
156 &size_g, &size_x, &size_g_current, &size_x_current, 124, KW_SKIP_CASE },
157 { "uid", 3, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2,
158 &uid_g, &uid_x, &uid_g_current, &uid_x_current, 108, 8 },
159 { "uname", 5, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2,
160 &uname_g, &uname_x, &uname_g_current, &uname_x_current, 265, 32 },
161
162 { "exthdr.name", 11, 1, O_OPTION_ACTION_HEADER_NAME, O_OPTION_ACTION_ERROR,
163 &header_name_x, &header_name_x_requested, NULL, NULL, 0, KW_SKIP_CASE },
164 { "globexthdr.name", 15, 1, O_OPTION_ACTION_HEADER_NAME, O_OPTION_ACTION_ERROR,
165 &header_name_g, &header_name_g_requested, NULL, NULL, 0, KW_SKIP_CASE },
166
167 { "delete", 6, 1, O_OPTION_ACTION_DELETE, O_OPTION_ACTION_ERROR,
168 NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE },
169 { "invalid", 7, 1, O_OPTION_ACTION_INVALID, O_OPTION_ACTION_ERROR,
170 NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE },
171 { "linkdata", 8, 1, O_OPTION_ACTION_LINKDATA, O_OPTION_ACTION_ERROR,
172 NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE }, /* Test 241 */
173 { "listopt", 7, 1, O_OPTION_ACTION_LISTOPT, O_OPTION_ACTION_ERROR,
174 &pax_list_opt_format, NULL, NULL, NULL, 0, KW_SKIP_CASE }, /* Test 242 */
175 /* Note: listopt is supposed to apply for all formats, not just -x pax only */
176 { "times", 5, 1, O_OPTION_ACTION_TIMES, O_OPTION_ACTION_ERROR,
177 NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE },
178 };
179
180 int ext_header_inx,
181 global_ext_header_inx;
182
183 /* Make these tables big enough to handle lots of -o options, not just one per table entry */
184 int ext_header_entry [4*sizeof(o_option_table)/sizeof(O_OPTION_TYPE)],
185 global_ext_header_entry[4*sizeof(o_option_table)/sizeof(O_OPTION_TYPE)];
186
187 /*
188 * Routines for reading, writing and header identify of various versions of pax
189 */
190
191 static size_t expandname(char *, size_t, char **, const char *, size_t);
192 static u_long pax_chksm(char *, int);
193 static char *name_split(char *, int);
194 static int ul_oct(u_long, char *, int, int);
195 #ifndef LONG_OFF_T
196 static int uqd_oct(u_quad_t, char *, int, int);
197 #endif
198
199 static uid_t uid_nobody;
200 static uid_t uid_warn;
201 static gid_t gid_nobody;
202 static gid_t gid_warn;
203
204 /*
205 * Routines common to all versions of pax
206 */
207
208 /*
209 * ul_oct()
210 * convert an unsigned long to an octal string. many oddball field
211 * termination characters are used by the various versions of tar in the
212 * different fields. term selects which kind to use. str is '0' padded
213 * at the front to len. we are unable to use only one format as many old
214 * tar readers are very cranky about this.
215 * Return:
216 * 0 if the number fit into the string, -1 otherwise
217 */
218
219 static int
220 ul_oct(u_long val, char *str, int len, int term)
221 {
222 char *pt;
223
224 /*
225 * term selects the appropriate character(s) for the end of the string
226 */
227 pt = str + len - 1;
228 switch (term) {
229 case 3:
230 *pt-- = '\0';
231 break;
232 case 2:
233 *pt-- = ' ';
234 *pt-- = '\0';
235 break;
236 case 1:
237 *pt-- = ' ';
238 break;
239 case 0:
240 default:
241 *pt-- = '\0';
242 *pt-- = ' ';
243 break;
244 }
245
246 /*
247 * convert and blank pad if there is space
248 */
249 while (pt >= str) {
250 *pt-- = '0' + (char)(val & 0x7);
251 if ((val = val >> 3) == (u_long)0)
252 break;
253 }
254
255 while (pt >= str)
256 *pt-- = '0';
257 if (val != (u_long)0)
258 return(-1);
259 return(0);
260 }
261
262 #ifndef LONG_OFF_T
263 /*
264 * uqd_oct()
265 * convert an u_quad_t to an octal string. one of many oddball field
266 * termination characters are used by the various versions of tar in the
267 * different fields. term selects which kind to use. str is '0' padded
268 * at the front to len. we are unable to use only one format as many old
269 * tar readers are very cranky about this.
270 * Return:
271 * 0 if the number fit into the string, -1 otherwise
272 */
273
274 static int
275 uqd_oct(u_quad_t val, char *str, int len, int term)
276 {
277 char *pt;
278
279 /*
280 * term selects the appropriate character(s) for the end of the string
281 */
282 pt = str + len - 1;
283 switch (term) {
284 case 3:
285 *pt-- = '\0';
286 break;
287 case 2:
288 *pt-- = ' ';
289 *pt-- = '\0';
290 break;
291 case 1:
292 *pt-- = ' ';
293 break;
294 case 0:
295 default:
296 *pt-- = '\0';
297 *pt-- = ' ';
298 break;
299 }
300
301 /*
302 * convert and blank pad if there is space
303 */
304 while (pt >= str) {
305 *pt-- = '0' + (char)(val & 0x7);
306 if ((val = val >> 3) == 0)
307 break;
308 }
309
310 while (pt >= str)
311 *pt-- = '0';
312 if (val != (u_quad_t)0)
313 return(-1);
314 return(0);
315 }
316 #endif
317
318 /*
319 * pax_chksm()
320 * calculate the checksum for a pax block counting the checksum field as
321 * all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks).
322 * NOTE: we use len to short circuit summing 0's on write since we ALWAYS
323 * pad headers with 0.
324 * Return:
325 * unsigned long checksum
326 */
327
328 static u_long
329 pax_chksm(char *blk, int len)
330 {
331 char *stop;
332 char *pt;
333 u_long chksm = BLNKSUM; /* initial value is checksum field sum */
334
335 /*
336 * add the part of the block before the checksum field
337 */
338 pt = blk;
339 stop = blk + CHK_OFFSET;
340 while (pt < stop)
341 chksm += (u_long)(*pt++ & 0xff);
342 /*
343 * move past the checksum field and keep going, spec counts the
344 * checksum field as the sum of 8 blanks (which is pre-computed as
345 * BLNKSUM).
346 * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding
347 * starts, no point in summing zero's)
348 */
349 pt += CHK_LEN;
350 stop = blk + len;
351 while (pt < stop)
352 chksm += (u_long)(*pt++ & 0xff);
353 return(chksm);
354 }
355
356 void
357 pax_format_list_output(ARCHD *arcn, time_t now, FILE *fp, int term)
358 {
359 /* parse specified listopt format */
360 char *nextpercent, *nextchar;
361 char buf[4*1024];
362 int pos, cpylen;
363 char *fname;
364
365 nextpercent = strchr(pax_list_opt_format,'%');
366 if (nextpercent==NULL) {
367 /* Strange case: no specifiers? */
368 safe_print(pax_list_opt_format, fp);
369 (void)putc(term, fp);
370 (void)fflush(fp);
371 return;
372 }
373 pos = nextpercent-pax_list_opt_format;
374 memcpy(buf,pax_list_opt_format, pos);
375 while (nextpercent++) {
376 switch (*nextpercent) {
377 case 'F':
378 fname = arcn->name;
379 cpylen = strlen(fname);
380 memcpy(&buf[pos],fname,cpylen);
381 pos+= cpylen;
382 break;
383 case 'D':
384 case 'T':
385 case 'M':
386 case 'L':
387 default:
388 paxwarn(1, "Unimplemented listopt format: %c",*nextpercent);
389 break;
390 }
391 nextpercent++;
392 if (*nextpercent=='\0') {
393 break;
394 }
395 nextchar = nextpercent;
396 nextpercent = strchr(nextpercent,'%');
397 if (nextpercent==NULL) {
398 cpylen = strlen(nextchar);
399 } else {
400 cpylen = nextpercent - nextchar;
401 }
402 memcpy(&buf[pos],nextchar, cpylen);
403 pos += cpylen;
404 }
405 buf[pos]='\0';
406 safe_print(&buf[0], fp);
407 (void)putc(term, fp);
408 (void)fflush(fp);
409 return;
410 }
411
412 void
413 cleanup_pax_invalid_action()
414 {
415 switch (pax_invalid_action) {
416 case PAX_INVALID_ACTION_BYPASS:
417 case PAX_INVALID_ACTION_RENAME:
418 break;
419 case PAX_INVALID_ACTION_WRITE:
420 pax_invalid_action_write_path = NULL;
421 if (pax_invalid_action_write_cwd) {
422 free(pax_invalid_action_write_cwd);
423 pax_invalid_action_write_cwd = NULL;
424 }
425 break;
426 case PAX_INVALID_ACTION_UTF8:
427 default:
428 paxwarn(1, "pax_invalid_action not implemented:%d", pax_invalid_action);
429 }
430 }
431
432 void
433 record_pax_invalid_action_results(ARCHD * arcn, char * fixed_path)
434 {
435 switch (pax_invalid_action) {
436 case PAX_INVALID_ACTION_BYPASS:
437 case PAX_INVALID_ACTION_RENAME:
438 break;
439 case PAX_INVALID_ACTION_WRITE:
440 pax_invalid_action_write_path = fixed_path;
441 pax_invalid_action_write_cwd = strdup(arcn->name);
442 pax_invalid_action_write_cwd[fixed_path-arcn->name-1] = '\0';
443 break;
444 case PAX_INVALID_ACTION_UTF8:
445 default:
446 paxwarn(1, "pax_invalid_action not implemented:%d", pax_invalid_action);
447 }
448 }
449
450 int
451 perform_pax_invalid_action(ARCHD * arcn, int err)
452 {
453 int rc = 0;
454 switch (pax_invalid_action) {
455 case PAX_INVALID_ACTION_BYPASS:
456 rc = -1;
457 break;
458 case PAX_INVALID_ACTION_RENAME:
459 rc = tty_rename(arcn);
460 break;
461 case PAX_INVALID_ACTION_WRITE:
462 pax_invalid_action_write_path = NULL;
463 pax_invalid_action_write_cwd = NULL;
464 rc = 2;
465 break;
466 case PAX_INVALID_ACTION_UTF8:
467 default:
468 paxwarn(1, "pax_invalid_action not implemented:%d", pax_invalid_action);
469 rc = -1; /* do nothing? */
470 }
471 return rc;
472 }
473
474 static void
475 delete_keywords(char * pattern)
476 {
477 int i;
478 /* loop over all keywords, marking any matched as deleted */
479 for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) {
480 if (fnmatch(pattern, o_option_table[i].name, 0) == 0) {
481 /* Found option: mark deleted */
482 o_option_table[i].active = 0;
483 }
484 }
485 }
486
487 /*
488 * pax_opt()
489 * handle pax format specific -o options
490 * Return:
491 * 0 if ok -1 otherwise
492 */
493
494 int
495 pax_opt(void)
496 {
497 OPLIST *opt;
498 int got_option = 0;
499
500 while ((opt = opt_next()) != NULL) {
501 int i;
502 got_option = -1;
503 pax_invalid_action = PAX_INVALID_ACTION_BYPASS; /* Default for pax format */
504 /* look up opt->name */
505 for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) {
506 if (strncasecmp(opt->name, o_option_table[i].name, o_option_table[i].len) == 0) {
507 /* Found option: see if already set */
508 /* Save it away */
509 got_option = 1;
510 switch (o_option_table[i].cmdline_action) {
511 case O_OPTION_ACTION_INVALID:
512 if (opt->separator != SEP_EQ) {
513 paxwarn(1,"-o %s= option requires '=' separator: option ignored",
514 opt->name);
515 break;
516 }
517 if (opt->value) {
518 if (strncasecmp(opt->value,"bypass",6) == 0) {
519 pax_invalid_action = PAX_INVALID_ACTION_BYPASS;
520 } else if (strncasecmp(opt->value,"rename",6) == 0) {
521 pax_invalid_action = PAX_INVALID_ACTION_RENAME;
522 } else if (strncasecmp(opt->value,"UTF-8",5) == 0) {
523 pax_invalid_action = PAX_INVALID_ACTION_UTF8;
524 } else if (strncasecmp(opt->value,"write",5) == 0) {
525 pax_invalid_action = PAX_INVALID_ACTION_WRITE;
526 } else {
527 paxwarn(1,"Invalid action %s not recognized: option ignored",
528 opt->value);
529 }
530 } else {
531 paxwarn(1,"Invalid action RHS not specified: option ignored");
532 }
533 break;
534 case O_OPTION_ACTION_DELETE:
535 if (opt->separator != SEP_EQ) {
536 paxwarn(1,"-o %s= option requires '=' separator: option ignored",
537 opt->name);
538 break;
539 }
540 /* Mark all matches as deleted */
541 /* can have multiple -o delete= patterns */
542 delete_keywords(opt->value);
543 break;
544 case O_OPTION_ACTION_STORE_HEADER2:
545 if(pax_read_or_list_mode) pids = 1; /* Force -p o for these options */
546 case O_OPTION_ACTION_STORE_HEADER:
547 if (o_option_table[i].g_value == NULL ||
548 o_option_table[i].x_value == NULL ) {
549 paxwarn(1,"-o option not implemented: %s=%s",
550 opt->name, opt->value);
551 } else {
552 if (opt->separator == SEP_EQ) {
553 *(o_option_table[i].g_value) = opt->value;
554 global_ext_header_entry[global_ext_header_inx++] = i;
555 } else if (opt->separator == SEP_COLONEQ ) {
556 *(o_option_table[i].x_value) = opt->value;
557 ext_header_entry [ext_header_inx++] = i;
558 } else { /* SEP_NONE */
559 paxwarn(1,"-o %s option is missing value", opt->name);
560 }
561 }
562 break;
563 case O_OPTION_ACTION_TIMES:
564 if (opt->separator != SEP_NONE) {
565 paxwarn(1,"-o %s option takes no value: option ignored", opt->name);
566 break;
567 }
568 want_a_m_time_headers = 1;
569 break;
570 case O_OPTION_ACTION_LINKDATA:
571 if (opt->separator != SEP_NONE) {
572 paxwarn(1,"-o %s option takes no value: option ignored", opt->name);
573 break;
574 }
575 want_linkdata = 1;
576 break;
577 case O_OPTION_ACTION_HEADER_NAME:
578 if (opt->separator != SEP_EQ) {
579 paxwarn(1,"-o %s= option requires '=' separator: option ignored",
580 opt->name);
581 break;
582 }
583 *(o_option_table[i].g_value) = opt->value;
584 *(o_option_table[i].x_value) = "YES";
585 break;
586 case O_OPTION_ACTION_LISTOPT:
587 if (opt->separator != SEP_EQ) {
588 paxwarn(1,"-o %s= option requires '=' separator: option ignored",
589 opt->name);
590 break;
591 }
592 *(o_option_table[i].g_value) = opt->value;
593 break;
594 case O_OPTION_ACTION_NOTIMPL:
595 default:
596 paxwarn(1,"pax format -o option not yet implemented: %s=%s",
597 opt->name, opt->value);
598 break;
599 }
600 break;
601 }
602 }
603 if (got_option == -1) {
604 paxwarn(1,"pax format -o option not recognized: %s=%s",
605 opt->name, opt->value);
606 }
607 }
608 return(0);
609 }
610
611 static int
612 expand_extended_headers(ARCHD *arcn, HD_USTAR *hd)
613 {
614 char mybuf[BLKMULT];
615 HD_USTAR *myhd;
616 char * current_value;
617 int path_replaced = 0;
618 int i, len;
619
620 myhd = hd;
621 while (myhd->typeflag == PAXGTYPE || myhd->typeflag == PAXXTYPE) {
622 char *name, *str;
623 int size, nbytes, inx;
624 size = asc_ul(myhd->size, sizeof(myhd->size), OCT);
625 if (size > sizeof(mybuf)) {
626 paxwarn(1,"extended header buffer overflow");
627 exit(1);
628 }
629 nbytes = rd_wrbuf(mybuf, size);
630 if (nbytes != size) {
631 paxwarn(1,"extended header data read failure: nbytes=%d, size=%d\n",
632 nbytes, size);
633 exit(1);
634 }
635 /*
636 printf("Read 1 extended header: type=%c, size=%d\n",
637 myhd->typeflag, size);
638 */
639 inx=0;
640 /* loop over buffer collecting attributes */
641 while (nbytes > 0) {
642 int got_option = -1;
643 int nentries = sscanf(&mybuf[inx],"%d ", &len);
644 if (nentries != 1) {
645 paxwarn(1,"Extended header failure: length");
646 exit(1);
647 }
648 if (len < 0 || (inx+len-1 >= sizeof(mybuf))) {
649 paxwarn(1, "Extended header failure: invalid length (%d)", len);
650 exit(1);
651 }
652 if (mybuf[inx+len-1] != '\n') {
653 paxwarn(1,"Extended header failure: missed newline");
654 exit(1);
655 } else
656 mybuf[inx+len-1] = '\0';
657 name = strchr(&mybuf[inx],' ');
658 if (name) name++;
659 else {
660 paxwarn(1,"Extended header failure: missing space");
661 exit(1);
662 }
663 str = strchr(name,'=');
664 if (str) {
665 *str++='\0'; /* end of name */
666 } else {
667 paxwarn(1,"Extended header failure: missing RHS string");
668 exit(1);
669 }
670 for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) {
671 if (strncasecmp(name, o_option_table[i].name, o_option_table[i].len) == 0) {
672 /* Found option: see if already set TBD */
673 /* Save it away */
674 got_option = i;
675 break;
676 }
677 }
678 if (got_option == -1) {
679 paxwarn(1,"Unrecognized header keyword: %s",name);
680 } else {
681 /* Determine precedence of -o and header attributes */
682 int found_value = ATTRSRC_FROM_NOWHERE;
683 current_value = NULL;
684 if (myhd->typeflag == PAXXTYPE) {
685 if (*o_option_table[got_option].x_value) {
686 current_value = *o_option_table[got_option].x_value;
687 found_value = ATTRSRC_FROM_X_O_OPTION;
688 } else {
689 current_value = str;
690 found_value = ATTRSRC_FROM_X_HEADER;
691 }
692 } else if (myhd->typeflag == PAXGTYPE) {
693 if (*o_option_table[got_option].g_value) {
694 current_value = *o_option_table[got_option].g_value;
695 found_value = ATTRSRC_FROM_G_O_OPTION;
696 } else {
697 current_value = str;
698 found_value = ATTRSRC_FROM_G_HEADER;
699 }
700 } else {
701 paxwarn(1,"Unsupported header type:%c",myhd->typeflag);
702 }
703 if (current_value) {
704 /* Save this attribute value for use later */
705 switch (o_option_table[got_option].header_action) {
706 case O_OPTION_ACTION_IGNORE:
707 paxwarn(1,"ignoring header keyword: %s",name);
708 break;
709 case O_OPTION_ACTION_STORE_HEADER2:
710 case O_OPTION_ACTION_STORE_HEADER:
711 switch (found_value) {
712 case ATTRSRC_FROM_NOWHERE: /* shouldn't happen */
713 paxwarn(1, "internal error: value from nowhere");
714 break;
715 case ATTRSRC_FROM_X_O_OPTION:
716 case ATTRSRC_FROM_G_O_OPTION:
717 break;
718 case ATTRSRC_FROM_X_HEADER:
719 current_value = strdup(current_value);
720 if(*o_option_table[got_option].x_value_current)
721 free(*o_option_table[got_option].x_value_current);
722 *o_option_table[got_option].x_value_current = current_value;
723 break;
724 case ATTRSRC_FROM_G_HEADER:
725 current_value = strdup(current_value);
726 if(*o_option_table[got_option].g_value_current)
727 free(*o_option_table[got_option].g_value_current);
728 *o_option_table[got_option].g_value_current = current_value;
729 break;
730 }
731 break;
732 case O_OPTION_ACTION_ERROR:
733 default:
734 paxwarn(1,"Unsupported extended header attribute: %s=%s",
735 name, str);
736 }
737 }
738 }
739 inx+=len;
740 nbytes -= len;
741 }
742
743 /* position file at next header */
744 (void)rd_skip(TAR_PAD(size));
745
746 /* read next header */
747 nbytes = rd_wrbuf(mybuf, frmt->hsz);
748 if (nbytes != frmt->hsz) {
749 paxwarn(1,"extended header read failure: nbytes=%d, size=%d\n",
750 nbytes, frmt->hsz);
751 }
752 myhd = ((HD_USTAR *)mybuf);
753 /* repeat until no more extended headers */
754 }
755
756 /* The header about to be returned must now be updated using all the extended
757 header values collected and any command line options */
758 /* Acceleration: check during command option processing. If there are no -o
759 options, and no changes from any header, do not need to run through this loop. */
760
761 for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) {
762 int header_len, free_it;
763 if (!o_option_table[i].active) {
764 continue; /* deleted keywords */
765 }
766 header_len = o_option_table[i].header_len;
767 if (header_len == KW_SKIP_CASE) {
768 continue;
769 }
770 free_it = 0;
771 /* Calculate values for all non-skip keywords */
772 current_value = NULL;
773 if (o_option_table[i].x_value) {
774 current_value = *o_option_table[i].x_value;
775 }
776 if (!current_value) { /* No -o := */
777 if (o_option_table[i].x_value_current) {
778 current_value = *o_option_table[i].x_value_current;
779 }
780 if (current_value) {
781 /* Must remove it: x header values not valid beyond this header */
782 *o_option_table[i].x_value_current = NULL;
783 free_it = 1;
784 } else { /* No x values, try globals */
785 current_value = *o_option_table[i].g_value;
786 if (!current_value) {
787 current_value = *o_option_table[i].g_value_current;
788 }
789 }
790 }
791 if (current_value) {
792 /* Update current header with this value */
793 /*
794 printf ("Found current_value:%s for %s, pids=%d\n",
795 current_value, o_option_table[i].name, pids);
796 */
797 len = strlen(current_value);
798 if (header_len == KW_ATIME_CASE) {
799 time_t asecs = strtoul(current_value, NULL, 10);
800 arcn->sb.st_atimespec.tv_sec = asecs;
801 } else if (header_len == KW_PATH_CASE) { /* Special case for path keyword */
802 path_replaced = 1;
803 arcn->nlen = len;
804 strlcpy(arcn->name,current_value,sizeof(arcn->name));
805 } else if (header_len >= 0) { // Skip negative values
806 if (len > header_len) {
807 paxwarn(1," length of string from extended header bigger than header field:"
808 " THAT won't work!\n");
809 } else {
810 char * p = (char *) myhd;
811 memcpy(&p[o_option_table[i].header_inx],
812 current_value, len);
813 if (len != header_len) {
814 /* pad with ? */
815 p[o_option_table[i].header_inx+len] = '\0';
816 }
817 }
818 }
819 if (free_it) {
820 free(current_value);
821 }
822 }
823 }
824
825 if (myhd==hd) return(path_replaced);
826
827 /* must put new header into memory of original */
828 memcpy(hd, myhd, sizeof(HD_USTAR));
829
830 return(path_replaced);
831 }
832
833 /*
834 * pax_id()
835 * determine if a block given to us is a valid pax header. We have to
836 * be on the lookout for those pesky blocks of all zero's
837 * Return:
838 * 0 if a ustar header, -1 otherwise
839 */
840
841 int
842 pax_id(char *blk, int size)
843 {
844 HD_USTAR *hd;
845
846 if (size < BLKMULT)
847 return(-1);
848 hd = (HD_USTAR *)blk;
849
850 /*
851 * check for block of zero's first, a simple and fast test then check
852 * ustar magic cookie. We should use TMAGLEN, but some USTAR archive
853 * programs are fouled up and create archives missing the \0. Last we
854 * check the checksum. If ok we have to assume it is a valid header.
855 */
856 if (hd->name[0] == '\0')
857 return(-1);
858 if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)
859 return(-1);
860 if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != pax_chksm(blk,BLKMULT))
861 return(-1);
862 if ((hd->typeflag != PAXXTYPE) && (hd->typeflag != PAXGTYPE)) {
863 /* Not explicitly pax format, but at least ustar */
864 if (act==LIST || act==EXTRACT) {
865 /* Although insufficient evidence, call it pax format */
866 return(0);
867 }
868 return(-1);
869 }
870 pax_invalid_action = PAX_INVALID_ACTION_BYPASS; /* Default for pax format */
871 return(0);
872 }
873
874 /*
875 * pax_rd()
876 * extract the values out of block already determined to be a pax header.
877 * store the values in the ARCHD parameter.
878 * Return:
879 * 0
880 */
881
882 int
883 pax_rd(ARCHD *arcn, char *buf)
884 {
885 HD_USTAR *hd;
886 int cnt = 0;
887 int check_path;
888 dev_t devmajor;
889 dev_t devminor;
890
891 /*
892 * we only get proper sized buffers
893 */
894 if (pax_id(buf, BLKMULT) < 0)
895 return(-1);
896
897 memset(arcn, 0, sizeof(*arcn));
898 arcn->org_name = arcn->name;
899 arcn->sb.st_nlink = 1;
900 hd = (HD_USTAR *)buf;
901
902 check_path = expand_extended_headers(arcn, hd);
903
904 if (check_path) {
905 /*
906 * pathname derived from extended head or -o option;
907 * full name is in one string, but length may exceed
908 * max path so be careful.
909 */
910 if (arcn->nlen > sizeof(arcn->name)) {
911 paxwarn(1,"pathname from extended header info doesn't fit! (len=%d)\n",
912 arcn->nlen);
913 }
914 } else {
915 /*
916 * see if the filename is split into two parts. if so, join the parts.
917 * we copy the prefix first and add a / between the prefix and name.
918 */
919 char *dest = arcn->name;
920 if (*(hd->prefix) != '\0') {
921 cnt = strlcpy(dest, hd->prefix, sizeof(arcn->name) - 1);
922 dest += cnt;
923 *dest++ = '/';
924 cnt++;
925 } else {
926 cnt = 0;
927 }
928
929 if (hd->typeflag != LONGLINKTYPE && hd->typeflag != LONGNAMETYPE) {
930 arcn->nlen = cnt + expandname(dest, sizeof(arcn->name) - cnt,
931 &gnu_name_string, hd->name, sizeof(hd->name));
932 arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name),
933 &gnu_link_string, hd->linkname, sizeof(hd->linkname));
934 }
935 }
936
937 /*
938 * follow the spec to the letter. we should only have mode bits, strip
939 * off all other crud we may be passed.
940 */
941 arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
942 0xfff);
943 #ifdef LONG_OFF_T
944 arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
945 #else
946 arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
947 #endif
948 arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
949 if (arcn->sb.st_atimespec.tv_sec == 0) { // Can be set from header
950 arcn->sb.st_atime = arcn->sb.st_mtime;
951 }
952 arcn->sb.st_ctime = arcn->sb.st_mtime;
953
954 /*
955 * If we can find the ascii names for gname and uname in the password
956 * and group files we will use the uid's and gid they bind. Otherwise
957 * we use the uid and gid values stored in the header. (This is what
958 * the posix spec wants).
959 */
960 hd->gname[sizeof(hd->gname) - 1] = '\0';
961 if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)
962 arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
963 hd->uname[sizeof(hd->uname) - 1] = '\0';
964 if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
965 arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
966
967 /*
968 * set the defaults, these may be changed depending on the file type
969 */
970 arcn->pad = 0;
971 arcn->skip = 0;
972 arcn->sb.st_rdev = (dev_t)0;
973
974 /*
975 * set the mode and PAX type according to the typeflag in the header
976 */
977 switch (hd->typeflag) {
978 case FIFOTYPE:
979 arcn->type = PAX_FIF;
980 arcn->sb.st_mode |= S_IFIFO;
981 break;
982 case DIRTYPE:
983 arcn->type = PAX_DIR;
984 arcn->sb.st_mode |= S_IFDIR;
985 arcn->sb.st_nlink = 2;
986
987 /*
988 * Some programs that create pax archives append a '/'
989 * to the pathname for directories. This clearly violates
990 * pax specs, but we will silently strip it off anyway.
991 */
992 if (arcn->name[arcn->nlen - 1] == '/')
993 arcn->name[--arcn->nlen] = '\0';
994 break;
995 case BLKTYPE:
996 case CHRTYPE:
997 /*
998 * this type requires the rdev field to be set.
999 */
1000 if (hd->typeflag == BLKTYPE) {
1001 arcn->type = PAX_BLK;
1002 arcn->sb.st_mode |= S_IFBLK;
1003 } else {
1004 arcn->type = PAX_CHR;
1005 arcn->sb.st_mode |= S_IFCHR;
1006 }
1007 devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
1008 devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
1009 arcn->sb.st_rdev = TODEV(devmajor, devminor);
1010 break;
1011 case SYMTYPE:
1012 case LNKTYPE:
1013 if (hd->typeflag == SYMTYPE) {
1014 arcn->type = PAX_SLK;
1015 arcn->sb.st_mode |= S_IFLNK;
1016 } else {
1017 arcn->type = PAX_HLK;
1018 /*
1019 * so printing looks better
1020 */
1021 arcn->sb.st_mode |= S_IFREG;
1022 arcn->sb.st_nlink = 2;
1023 }
1024 break;
1025 case LONGLINKTYPE:
1026 case LONGNAMETYPE:
1027 /*
1028 * GNU long link/file; we tag these here and let the
1029 * pax internals deal with it -- too ugly otherwise.
1030 */
1031 arcn->type =
1032 hd->typeflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF;
1033 arcn->pad = TAR_PAD(arcn->sb.st_size);
1034 arcn->skip = arcn->sb.st_size;
1035 break;
1036 case CONTTYPE:
1037 case AREGTYPE:
1038 case REGTYPE:
1039 default:
1040 /*
1041 * these types have file data that follows. Set the skip and
1042 * pad fields.
1043 */
1044 arcn->type = PAX_REG;
1045 arcn->pad = TAR_PAD(arcn->sb.st_size);
1046 arcn->skip = arcn->sb.st_size;
1047 arcn->sb.st_mode |= S_IFREG;
1048 break;
1049 }
1050 return(0);
1051 }
1052
1053 void
1054 adjust_copy_for_pax_options(ARCHD * arcn)
1055 {
1056 /* Because ext_header options take precedence over global_header options, apply
1057 global options first, then override with any extended header options */
1058 int i;
1059 if (global_ext_header_inx) {
1060 for (i=0; i < global_ext_header_inx; i++) {
1061 if (!o_option_table[global_ext_header_entry[i]].active) continue; /* deleted keywords */
1062 if (strcmp(o_option_table[global_ext_header_entry[i]].name, "path")==0) {
1063 strlcpy(arcn->name,*(o_option_table[global_ext_header_entry[i]].g_value),
1064 sizeof(arcn->name));
1065 arcn->nlen = strlen(*(o_option_table[global_ext_header_entry[i]].g_value));
1066 } else { /* only handle path for now: others TBD */
1067 paxwarn(1, "adjust arcn for global extended header options not implemented:%d", i);
1068 }
1069 }
1070 }
1071 if (ext_header_inx) {
1072 for (i=0; i < ext_header_inx; i++) {
1073 if (!o_option_table[ext_header_entry[i]].active) continue; /* deleted keywords */
1074 if (strcmp(o_option_table[ext_header_entry[i]].name, "path")==0) {
1075 strlcpy(arcn->name,*(o_option_table[ext_header_entry[i]].x_value),
1076 sizeof(arcn->name));
1077 arcn->nlen = strlen(*(o_option_table[ext_header_entry[i]].x_value));
1078 } else { /* only handle path for now: others TBD */
1079 paxwarn(1, "adjust arcn for extended header options not implemented:%d", i);
1080 }
1081 }
1082 }
1083 if (want_a_m_time_headers) {
1084 /* TBD */
1085 }
1086 }
1087
1088 static int
1089 emit_extended_header_record(int len, int total_len, int head_type,
1090 char * name, char * value)
1091 {
1092 if (total_len + len > sizeof(pax_eh_datablk)) {
1093 paxwarn(1,"extended header buffer overflow for header type '%c': %d",
1094 head_type, total_len+len);
1095 } else {
1096 sprintf(&pax_eh_datablk[total_len],"%d %s=%s\n", len, name, value);
1097 total_len += len;
1098 }
1099 return (total_len);
1100 }
1101
1102 __attribute__((__malloc__))
1103 static char *
1104 substitute_percent(char * header, char * filename)
1105 {
1106 char *nextpercent, *nextchar;
1107 char buf[4*1024];
1108 int pos, cpylen;
1109 char *dname, *fname;
1110
1111 nextpercent = strchr(header,'%');
1112 if (nextpercent==NULL) return strdup(header);
1113 pos = nextpercent-header;
1114 memcpy(buf,header, pos);
1115 while (nextpercent++) {
1116 switch (*nextpercent) {
1117 case '%':
1118 buf[pos++]='%'; /* just skip it */
1119 break;
1120 case 'd':
1121 dname = strrchr(filename,'/');
1122 if (dname==NULL) {
1123 cpylen = 1;
1124 dname = ".";
1125 } else {
1126 cpylen = dname-filename;
1127 dname = filename;
1128 }
1129 memcpy(&buf[pos],dname,cpylen);
1130 pos+= cpylen;
1131 break;
1132 case 'f':
1133 fname = strrchr(filename,'/');
1134 if (fname==NULL) {
1135 fname = filename;
1136 } else {
1137 fname++;
1138 }
1139 cpylen = strlen(fname);
1140 memcpy(&buf[pos],fname,cpylen);
1141 pos+= cpylen;
1142 break;
1143 case 'n':
1144 pos += sprintf (&buf[pos],"%d",nglobal_headers);
1145 break;
1146 case 'p':
1147 pos += sprintf (&buf[pos],"%d",getpid());
1148 break;
1149 default:
1150 paxwarn(1,"header format substitution failed: '%c'", *nextpercent);
1151 return strdup(header);
1152 }
1153 nextpercent++;
1154 if (*nextpercent=='\0') {
1155 break;
1156 }
1157 nextchar = nextpercent;
1158 nextpercent = strchr(nextpercent,'%');
1159 if (nextpercent==NULL) {
1160 cpylen = strlen(nextchar);
1161 } else {
1162 cpylen = nextpercent - nextchar;
1163 }
1164 memcpy(&buf[pos],nextchar, cpylen);
1165 pos += cpylen;
1166 }
1167 buf[pos]='\0';
1168 return (strdup(&buf[0]));
1169 }
1170
1171 static int
1172 generate_pax_ext_header_and_data(ARCHD *arcn, int nfields, int *table,
1173 char header_type, char * header_name, char * header_name_requested)
1174 {
1175 HD_USTAR *hd;
1176 char hdblk[sizeof(HD_USTAR)];
1177 u_long records_size;
1178 int term_char, i, len, total_len;
1179 char * str, *name;
1180
1181 if (nfields == 0 && (header_name_requested == NULL)) {
1182 if (header_type==PAXXTYPE) {
1183 if (!want_a_m_time_headers) return (0);
1184 } else
1185 return (0);
1186 }
1187
1188 /* There might be no fields but a header with a specific name or
1189 times might be wanted */
1190
1191 term_char = 1;
1192 memset(hdblk, 0, sizeof(hdblk));
1193 hd = (HD_USTAR *)hdblk;
1194 memset(pax_eh_datablk, 0, sizeof(pax_eh_datablk));
1195
1196 /* generate header */
1197 hd->typeflag = header_type;
1198
1199 /* These fields appear to be necessary to be able to treat extended headers
1200 like files in older versions of pax */
1201 ul_oct((u_long)0444, hd->mode, sizeof(hd->mode), term_char);
1202 strncpy(hd->magic, TMAGIC, TMAGLEN);
1203 strncpy(hd->version, TVERSION, TVERSLEN);
1204 ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),term_char);
1205
1206 /* compute size of data */
1207 total_len = 0;
1208 for (i=0; i < nfields; i++) {
1209 if (!o_option_table[table[i]].active) continue; /* deleted keywords */
1210 name = o_option_table[table[i]].name;
1211 if (header_type == PAXXTYPE) {
1212 str = *(o_option_table[table[i]].x_value);
1213 } else {
1214 str = *(o_option_table[table[i]].g_value);
1215 }
1216 if (str==NULL) {
1217 paxwarn(1,"Missing option value for %s", name);
1218 continue;
1219 }
1220 len = strlen(str) + o_option_table[table[i]].len + 3;
1221 if (len < 9) len++;
1222 else if (len < 98) len = len + 2;
1223 else if (len < 997) len = len + 3;
1224 else if (len < 9996) len = len + 4;
1225 else {
1226 paxwarn(1,"extended header data too long for header type '%c': %d",
1227 header_type, len);
1228 }
1229 total_len = emit_extended_header_record(len, total_len,
1230 header_type, name, str);
1231 }
1232
1233 if ((header_type == PAXXTYPE) && want_a_m_time_headers) {
1234 char time_buffer[12];
1235 memset(time_buffer,0,sizeof(time_buffer));
1236 sprintf(&time_buffer[0],"%d",(int)arcn->sb.st_atime);
1237 /* 3 chars + strlen("atime") + time + # chars in len */
1238 len = 3 + 5 + strlen(&time_buffer[0]) + 2;
1239 total_len = emit_extended_header_record(len, total_len,
1240 header_type, "atime", &time_buffer[0]);
1241 memset(time_buffer,0,sizeof(time_buffer));
1242 sprintf(&time_buffer[0],"%d",(int)arcn->sb.st_mtime);
1243 /* 3 chars + strlen("mtime") + time + # chars in len */
1244 len = 3 + 5 + strlen(&time_buffer[0]) + 2;
1245 total_len = emit_extended_header_record(len, total_len,
1246 header_type, "mtime", &time_buffer[0]);
1247 }
1248
1249 /* Check if all fields were deleted: might not need to generate anything */
1250 if ((total_len==0) && (header_name_requested == NULL)) return (0);
1251
1252 if (header_type == PAXGTYPE) nglobal_headers++;
1253 /* substitution of fields in header_name */
1254 header_name = substitute_percent(header_name, arcn->name);
1255 if (strlen(header_name) == sizeof(hd->name)) { /* must account for name just fits in buffer */
1256 strncpy(hd->name, header_name, sizeof(hd->name));
1257 } else {
1258 strlcpy(hd->name, header_name, sizeof(hd->name));
1259 }
1260
1261 free(header_name);
1262 header_name = NULL;
1263 records_size = (u_long)total_len;
1264 if (ul_oct(records_size, hd->size, sizeof(hd->size), term_char)) {
1265 paxwarn(1,"extended header data too long for header type '%c'", header_type);
1266 return(1);
1267 }
1268
1269 if (ul_oct(pax_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum, sizeof(hd->chksum), term_char)) {
1270 paxwarn(1,"extended header data checksum failed: header type '%c'", header_type);
1271 return(1);
1272 }
1273
1274 /* write out header */
1275 if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)
1276 return(-1);
1277 if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
1278 return(-1);
1279 /* write out header data */
1280 if (total_len > 0) {
1281 if (wr_rdbuf(pax_eh_datablk, total_len) < 0)
1282 return(-1);
1283 if (wr_skip((off_t)(BLKMULT - total_len)) < 0)
1284 return(-1);
1285 /*
1286 printf("data written:\n%s",&pax_eh_datablk[0]);
1287 */
1288 }
1289
1290 /*
1291 paxwarn(0,"extended header and data written: header type '%c', #items: %d, %d characters",
1292 header_type, nfields, records_size);
1293 */
1294 return (0);
1295 }
1296
1297 /*
1298 * pax_wr()
1299 * write a pax header for the file specified in the ARCHD to the archive
1300 * Have to check for file types that cannot be stored and file names that
1301 * are too long. Be careful of the term (last arg) to ul_oct, we only use
1302 * '\0' for the termination character (this is different than picky tar)
1303 * ASSUMED: space after header in header block is zero filled
1304 * Return:
1305 * 0 if file has data to be written after the header, 1 if file has NO
1306 * data to write after the header, -1 if archive write failed
1307 */
1308
1309 int
1310 pax_wr(ARCHD *arcn)
1311 {
1312 HD_USTAR *hd;
1313 char *pt;
1314 char hdblk[sizeof(HD_USTAR)];
1315 mode_t mode12only;
1316 int term_char=3; /* orignal setting */
1317 term_char=1; /* To pass conformance tests 274, 301 */
1318
1319 /*
1320 * check for those file system types pax cannot store
1321 */
1322 if (arcn->type == PAX_SCK) {
1323 paxwarn(1, "Pax cannot archive a socket %s", arcn->org_name);
1324 return(1);
1325 }
1326
1327 /*
1328 * check the length of the linkname
1329 */
1330 if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
1331 (arcn->type == PAX_HRG)) && (arcn->ln_nlen > sizeof(hd->linkname))){
1332 paxwarn(1, "Link name too long for pax %s", arcn->ln_name);
1333 /*
1334 * Conformance: test pax:285 wants error code to be non-zero, and
1335 * test tar:12 wants error code from pax to be 0
1336 */
1337 return(1);
1338 }
1339
1340 /*
1341 * split the path name into prefix and name fields (if needed). if
1342 * pt != arcn->name, the name has to be split
1343 */
1344 if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
1345 paxwarn(1, "File name too long for pax %s", arcn->name);
1346 return(1);
1347 }
1348
1349 generate_pax_ext_header_and_data(arcn, global_ext_header_inx, &global_ext_header_entry[0],
1350 PAXGTYPE, header_name_g, header_name_g_requested);
1351 generate_pax_ext_header_and_data(arcn, ext_header_inx, &ext_header_entry[0],
1352 PAXXTYPE, header_name_x, header_name_x_requested);
1353
1354 /*
1355 * zero out the header so we don't have to worry about zero fill below
1356 */
1357 memset(hdblk, 0, sizeof(hdblk));
1358 hd = (HD_USTAR *)hdblk;
1359 arcn->pad = 0L;
1360 /* To pass conformance tests 274/301, always set these fields to "zero" */
1361 ul_oct(0, hd->devmajor, sizeof(hd->devmajor), term_char);
1362 ul_oct(0, hd->devminor, sizeof(hd->devminor), term_char);
1363
1364 /*
1365 * split the name, or zero out the prefix
1366 */
1367 if (pt != arcn->name) {
1368 /*
1369 * name was split, pt points at the / where the split is to
1370 * occur, we remove the / and copy the first part to the prefix
1371 */
1372 *pt = '\0';
1373 strlcpy(hd->prefix, arcn->name, sizeof(hd->prefix));
1374 *pt++ = '/';
1375 }
1376
1377 /*
1378 * copy the name part. this may be the whole path or the part after
1379 * the prefix
1380 */
1381 if (strlen(pt) == sizeof(hd->name)) { /* must account for name just fits in buffer */
1382 strncpy(hd->name, pt, sizeof(hd->name));
1383 } else {
1384 strlcpy(hd->name, pt, sizeof(hd->name));
1385 }
1386
1387 /*
1388 * set the fields in the header that are type dependent
1389 */
1390 switch (arcn->type) {
1391 case PAX_DIR:
1392 hd->typeflag = DIRTYPE;
1393 if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
1394 goto out;
1395 break;
1396 case PAX_CHR:
1397 case PAX_BLK:
1398 if (arcn->type == PAX_CHR)
1399 hd->typeflag = CHRTYPE;
1400 else
1401 hd->typeflag = BLKTYPE;
1402 if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,
1403 sizeof(hd->devmajor), term_char) ||
1404 ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,
1405 sizeof(hd->devminor), term_char) ||
1406 ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
1407 goto out;
1408 break;
1409 case PAX_FIF:
1410 hd->typeflag = FIFOTYPE;
1411 if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
1412 goto out;
1413 break;
1414 case PAX_SLK:
1415 case PAX_HLK:
1416 case PAX_HRG:
1417 if (arcn->type == PAX_SLK)
1418 hd->typeflag = SYMTYPE;
1419 else
1420 hd->typeflag = LNKTYPE;
1421 if (strlen(arcn->ln_name) == sizeof(hd->linkname)) { /* must account for name just fits in buffer */
1422 strncpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname));
1423 } else {
1424 strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname));
1425 }
1426 if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
1427 goto out;
1428 break;
1429 case PAX_REG:
1430 case PAX_CTG:
1431 default:
1432 /*
1433 * file data with this type, set the padding
1434 */
1435 if (arcn->type == PAX_CTG)
1436 hd->typeflag = CONTTYPE;
1437 else
1438 hd->typeflag = REGTYPE;
1439 arcn->pad = TAR_PAD(arcn->sb.st_size);
1440 # ifdef LONG_OFF_T
1441 if (ul_oct((u_long)arcn->sb.st_size, hd->size,
1442 sizeof(hd->size), term_char)) {
1443 # else
1444 if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
1445 sizeof(hd->size), term_char)) {
1446 # endif
1447 paxwarn(1,"File is too long for pax %s",arcn->org_name);
1448 return(1);
1449 }
1450 break;
1451 }
1452
1453 strncpy(hd->magic, TMAGIC, TMAGLEN);
1454 strncpy(hd->version, TVERSION, TVERSLEN);
1455
1456 /*
1457 * set the remaining fields. Some versions want all 16 bits of mode
1458 * we better humor them (they really do not meet spec though)....
1459 */
1460 if (ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), term_char)) {
1461 if (uid_nobody == 0) {
1462 if (uid_name("nobody", &uid_nobody) == -1)
1463 goto out;
1464 }
1465 if (uid_warn != arcn->sb.st_uid) {
1466 uid_warn = arcn->sb.st_uid;
1467 paxwarn(1,
1468 "Pax header field is too small for uid %lu, "
1469 "using nobody", (u_long)arcn->sb.st_uid);
1470 }
1471 if (ul_oct((u_long)uid_nobody, hd->uid, sizeof(hd->uid), term_char))
1472 goto out;
1473 }
1474 if (ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), term_char)) {
1475 if (gid_nobody == 0) {
1476 if (gid_name("nobody", &gid_nobody) == -1)
1477 goto out;
1478 }
1479 if (gid_warn != arcn->sb.st_gid) {
1480 gid_warn = arcn->sb.st_gid;
1481 paxwarn(1,
1482 "Pax header field is too small for gid %lu, "
1483 "using nobody", (u_long)arcn->sb.st_gid);
1484 }
1485 if (ul_oct((u_long)gid_nobody, hd->gid, sizeof(hd->gid), term_char))
1486 goto out;
1487 }
1488 /* However, Unix conformance tests do not like MORE than 12 mode bits:
1489 remove all beyond (see definition of stat.st_mode structure) */
1490 mode12only = ((u_long)arcn->sb.st_mode) & 0x00000fff;
1491 if (ul_oct((u_long)mode12only, hd->mode, sizeof(hd->mode), term_char) ||
1492 ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),term_char))
1493 goto out;
1494 strncpy(hd->uname, name_uid(arcn->sb.st_uid, 0), sizeof(hd->uname));
1495 strncpy(hd->gname, name_gid(arcn->sb.st_gid, 0), sizeof(hd->gname));
1496
1497 /*
1498 * calculate and store the checksum write the header to the archive
1499 * return 0 tells the caller to now write the file data, 1 says no data
1500 * needs to be written
1501 */
1502 if (ul_oct(pax_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum,
1503 sizeof(hd->chksum), term_char))
1504 goto out;
1505 if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)
1506 return(-1);
1507 if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
1508 return(-1);
1509 if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
1510 return(0);
1511 return(1);
1512
1513 out:
1514 /*
1515 * header field is out of range
1516 */
1517 paxwarn(1, "Pax header field is too small for %s", arcn->org_name);
1518 return(1);
1519 }
1520
1521 /*
1522 * name_split()
1523 * see if the name has to be split for storage in a ustar header. We try
1524 * to fit the entire name in the name field without splitting if we can.
1525 * The split point is always at a /
1526 * Return
1527 * character pointer to split point (always the / that is to be removed
1528 * if the split is not needed, the points is set to the start of the file
1529 * name (it would violate the spec to split there). A NULL is returned if
1530 * the file name is too long
1531 */
1532
1533 static char *
1534 name_split(char *name, int len)
1535 {
1536 char *start;
1537
1538 /*
1539 * check to see if the file name is small enough to fit in the name
1540 * field. if so just return a pointer to the name.
1541 */
1542 if (len <= TNMSZ)
1543 return(name);
1544 if (len > (TPFSZ + TNMSZ))
1545 return(NULL);
1546
1547 /*
1548 * we start looking at the biggest sized piece that fits in the name
1549 * field. We walk forward looking for a slash to split at. The idea is
1550 * to find the biggest piece to fit in the name field (or the smallest
1551 * prefix we can find)
1552 */
1553 start = name + len - TNMSZ -1;
1554 if ((*start == '/') && (start == name))
1555 ++start; /* 101 byte paths with leading '/' are dinged otherwise */
1556 while ((*start != '\0') && (*start != '/'))
1557 ++start;
1558
1559 /*
1560 * if we hit the end of the string, this name cannot be split, so we
1561 * cannot store this file.
1562 */
1563 if (*start == '\0')
1564 return(NULL);
1565 len = start - name;
1566
1567 /*
1568 * NOTE: /str where the length of str == TNMSZ can not be stored under
1569 * the p1003.1-1990 spec for ustar. We could force a prefix of / and
1570 * the file would then expand on extract to //str. The len == 0 below
1571 * makes this special case follow the spec to the letter.
1572 */
1573 if ((len >= TPFSZ) || (len == 0))
1574 return(NULL);
1575
1576 /*
1577 * ok have a split point, return it to the caller
1578 */
1579 return(start);
1580 }
1581
1582 static size_t
1583 expandname(char *buf, size_t len, char **gnu_name, const char *name, size_t name_len)
1584 {
1585 size_t nlen;
1586
1587 if (*gnu_name) {
1588 if ((nlen = strlcpy(buf, *gnu_name, len)) >= len)
1589 nlen = len - 1;
1590 free(*gnu_name);
1591 *gnu_name = NULL;
1592 } else {
1593 if (name_len < len) {
1594 /* name may not be null terminated: it might be as big as the
1595 field, so copy is limited to the max size of the header field */
1596 if ((nlen = strlcpy(buf, name, name_len+1)) >= name_len+1)
1597 nlen = name_len;
1598 } else {
1599 if ((nlen = strlcpy(buf, name, len)) >= len)
1600 nlen = len - 1;
1601 }
1602 }
1603 return(nlen);
1604 }