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