Print this page
3474 tar should support -C on extract
Reviewed by: Robert Mustacchi <rm@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/tar/tar.c
+++ new/usr/src/cmd/tar/tar.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2012 Milan Jurik. All rights reserved.
24 + * Copyright (c) 2013, Joyent, Inc. All rights reserved.
24 25 */
25 26
26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 28 /* All Rights Reserved */
28 29
29 30 /* Copyright (c) 1987, 1988 Microsoft Corporation */
30 31 /* All Rights Reserved */
31 32
32 33 /*
33 34 * Portions of this source code were derived from Berkeley 4.3 BSD
34 35 * under license from the Regents of the University of California.
35 36 */
36 37
37 38 #include <unistd.h>
38 39 #include <sys/types.h>
39 40 #include <sys/param.h>
40 41 #include <sys/stat.h>
41 42 #include <sys/mkdev.h>
42 43 #include <sys/wait.h>
43 44 #include <dirent.h>
44 45 #include <errno.h>
45 46 #include <stdio.h>
46 47 #include <signal.h>
47 48 #include <ctype.h>
48 49 #include <locale.h>
49 50 #include <nl_types.h>
50 51 #include <langinfo.h>
51 52 #include <pwd.h>
52 53 #include <grp.h>
53 54 #include <fcntl.h>
54 55 #include <string.h>
55 56 #include <malloc.h>
56 57 #include <time.h>
57 58 #include <utime.h>
58 59 #include <stdlib.h>
59 60 #include <stdarg.h>
60 61 #include <widec.h>
61 62 #include <sys/mtio.h>
62 63 #include <sys/acl.h>
63 64 #include <strings.h>
64 65 #include <deflt.h>
65 66 #include <limits.h>
66 67 #include <iconv.h>
67 68 #include <assert.h>
68 69 #include <libgen.h>
69 70 #include <libintl.h>
70 71 #include <aclutils.h>
71 72 #include <libnvpair.h>
72 73 #include <archives.h>
73 74
74 75 #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
75 76 extern int defcntl();
76 77 #endif
77 78 #if defined(_PC_SATTR_ENABLED)
78 79 #include <attr.h>
79 80 #include <libcmdutils.h>
80 81 #endif
81 82
82 83 /* Trusted Extensions */
83 84 #include <zone.h>
84 85 #include <tsol/label.h>
85 86 #include <sys/tsol/label_macro.h>
86 87
87 88 #include "getresponse.h"
88 89 /*
89 90 * Source compatibility
90 91 */
91 92
92 93 /*
93 94 * These constants come from archives.h and sys/fcntl.h
94 95 * and were introduced by the extended attributes project
95 96 * in Solaris 9.
96 97 */
97 98 #if !defined(O_XATTR)
98 99 #define AT_SYMLINK_NOFOLLOW 0x1000
99 100 #define AT_REMOVEDIR 0x1
100 101 #define AT_FDCWD 0xffd19553
101 102 #define _XATTR_HDRTYPE 'E'
102 103 static int attropen();
103 104 static int fstatat();
104 105 static int renameat();
105 106 static int unlinkat();
106 107 static int openat();
107 108 static int fchownat();
108 109 static int futimesat();
109 110 #endif
110 111
111 112 /*
112 113 * Compiling with -D_XPG4_2 gets this but produces other problems, so
113 114 * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
114 115 * explicitly doing the declaration here.
115 116 */
116 117 int utimes(const char *path, const struct timeval timeval_ptr[]);
117 118
118 119 #ifndef MINSIZE
119 120 #define MINSIZE 250
120 121 #endif
121 122 #define DEF_FILE "/etc/default/tar"
122 123
123 124 #define min(a, b) ((a) < (b) ? (a) : (b))
124 125 #define max(a, b) ((a) > (b) ? (a) : (b))
125 126
126 127 /* -DDEBUG ONLY for debugging */
127 128 #ifdef DEBUG
128 129 #undef DEBUG
129 130 #define DEBUG(a, b, c)\
130 131 (void) fprintf(stderr, "DEBUG - "), (void) fprintf(stderr, a, b, c)
131 132 #endif
132 133
133 134 #define TBLOCK 512 /* tape block size--should be universal */
134 135
135 136 #ifdef BSIZE
136 137 #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
137 138 #else /* BSIZE */
138 139 #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
139 140 #endif /* BSIZE */
140 141
141 142 #define NBLOCK 20
142 143 #define NAMSIZ 100
143 144 #define PRESIZ 155
144 145 #define MAXNAM 256
145 146 #define MODEMASK 0777777 /* file creation mode mask */
146 147 #define POSIXMODES 07777 /* mask for POSIX mode bits */
147 148 #define MAXEXT 9 /* reasonable max # extents for a file */
148 149 #define EXTMIN 50 /* min blks left on floppy to split a file */
149 150
150 151 /* max value dblock.dbuf.efsize can store */
151 152 #define TAR_EFSIZE_MAX 0777777777
152 153
153 154 /*
154 155 * Symbols which specify the values at which the use of the 'E' function
155 156 * modifier is required to properly store a file.
156 157 *
157 158 * TAR_OFFSET_MAX - the largest file size we can archive
158 159 * OCTAL7CHAR - the limit for ustar gid, uid, dev
159 160 */
160 161
161 162 #ifdef XHDR_DEBUG
162 163 /* tiny values which force the creation of extended header entries */
163 164 #define TAR_OFFSET_MAX 9
164 165 #define OCTAL7CHAR 2
165 166 #else
166 167 /* normal values */
167 168 #define TAR_OFFSET_MAX 077777777777ULL
168 169 #define OCTAL7CHAR 07777777
169 170 #endif
170 171
171 172 #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
172 173 #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
173 174
174 175 #define MAXLEV (PATH_MAX / 2)
175 176 #define LEV0 1
176 177 #define SYMLINK_LEV0 0
177 178
178 179 #define TRUE 1
179 180 #define FALSE 0
180 181
181 182 #define XATTR_FILE 1
182 183 #define NORMAL_FILE 0
183 184
184 185 #define PUT_AS_LINK 1
185 186 #define PUT_NOTAS_LINK 0
186 187
187 188 #ifndef VIEW_READONLY
188 189 #define VIEW_READONLY "SUNWattr_ro"
189 190 #endif
190 191
191 192 #ifndef VIEW_READWRITE
192 193 #define VIEW_READWRITE "SUNWattr_rw"
193 194 #endif
194 195
195 196 #if _FILE_OFFSET_BITS == 64
196 197 #define FMT_off_t "lld"
197 198 #define FMT_off_t_o "llo"
198 199 #define FMT_blkcnt_t "lld"
199 200 #else
200 201 #define FMT_off_t "ld"
201 202 #define FMT_off_t_o "lo"
202 203 #define FMT_blkcnt_t "ld"
203 204 #endif
204 205
205 206 /* ACL support */
206 207
207 208 static
208 209 struct sec_attr {
209 210 char attr_type;
210 211 char attr_len[7];
211 212 char attr_info[1];
212 213 } *attr;
213 214
214 215 #if defined(O_XATTR)
215 216 typedef enum {
216 217 ATTR_OK,
217 218 ATTR_SKIP,
218 219 ATTR_CHDIR_ERR,
219 220 ATTR_OPEN_ERR,
220 221 ATTR_XATTR_ERR,
221 222 ATTR_SATTR_ERR
222 223 } attr_status_t;
223 224 #endif
224 225
225 226 #if defined(O_XATTR)
226 227 typedef enum {
227 228 ARC_CREATE,
228 229 ARC_RESTORE
229 230 } arc_action_t;
230 231 #endif
231 232
232 233 typedef struct attr_data {
233 234 char *attr_parent;
234 235 char *attr_path;
235 236 int attr_parentfd;
236 237 int attr_rw_sysattr;
237 238 } attr_data_t;
238 239
239 240 /*
240 241 *
241 242 * Tar has been changed to support extended attributes.
242 243 *
243 244 * As part of this change tar now uses the new *at() syscalls
244 245 * such as openat, fchownat(), unlinkat()...
245 246 *
246 247 * This was done so that attributes can be handled with as few code changes
247 248 * as possible.
248 249 *
249 250 * What this means is that tar now opens the directory that a file or directory
250 251 * resides in and then performs *at() functions to manipulate the entry.
251 252 *
252 253 * For example a new file is now created like this:
253 254 *
254 255 * dfd = open(<some dir path>)
255 256 * fd = openat(dfd, <name>,....);
256 257 *
257 258 * or in the case of an extended attribute
258 259 *
259 260 * dfd = attropen(<pathname>, ".", ....)
260 261 *
261 262 * Once we have a directory file descriptor all of the *at() functions can
262 263 * be applied to it.
263 264 *
264 265 * unlinkat(dfd, <component name>,...)
265 266 * fchownat(dfd, <component name>,..)
266 267 *
267 268 * This works for both normal namespace files and extended attribute file
268 269 *
269 270 */
270 271
271 272 /*
272 273 *
273 274 * Extended attribute Format
274 275 *
275 276 * Extended attributes are stored in two pieces.
276 277 * 1. An attribute header which has information about
277 278 * what file the attribute is for and what the attribute
278 279 * is named.
279 280 * 2. The attribute record itself. Stored as a normal file type
280 281 * of entry.
281 282 * Both the header and attribute record have special modes/typeflags
282 283 * associated with them.
283 284 *
284 285 * The names of the header in the archive look like:
285 286 * /dev/null/attr.hdr
286 287 *
287 288 * The name of the attribute looks like:
288 289 * /dev/null/attr
289 290 *
290 291 * This is done so that an archiver that doesn't understand these formats
291 292 * can just dispose of the attribute records.
292 293 *
293 294 * The format is composed of a fixed size header followed
294 295 * by a variable sized xattr_buf. If the attribute is a hard link
295 296 * to another attribute then another xattr_buf section is included
296 297 * for the link.
297 298 *
298 299 * The xattr_buf is used to define the necessary "pathing" steps
299 300 * to get to the extended attribute. This is necessary to support
300 301 * a fully recursive attribute model where an attribute may itself
301 302 * have an attribute.
302 303 *
303 304 * The basic layout looks like this.
304 305 *
305 306 * --------------------------------
306 307 * | |
307 308 * | xattr_hdr |
308 309 * | |
309 310 * --------------------------------
310 311 * --------------------------------
311 312 * | |
312 313 * | xattr_buf |
313 314 * | |
314 315 * --------------------------------
315 316 * --------------------------------
316 317 * | |
317 318 * | (optional link info) |
318 319 * | |
319 320 * --------------------------------
320 321 * --------------------------------
321 322 * | |
322 323 * | attribute itself |
323 324 * | stored as normal tar |
324 325 * | or cpio data with |
325 326 * | special mode or |
326 327 * | typeflag |
327 328 * | |
328 329 * --------------------------------
329 330 *
330 331 */
331 332
332 333 /*
333 334 * xattrhead is a pointer to the xattr_hdr
334 335 *
335 336 * xattrp is a pointer to the xattr_buf structure
336 337 * which contains the "pathing" steps to get to attributes
337 338 *
338 339 * xattr_linkp is a pointer to another xattr_buf structure that is
339 340 * only used when an attribute is actually linked to another attribute
340 341 *
341 342 */
342 343
343 344 static struct xattr_hdr *xattrhead;
344 345 static struct xattr_buf *xattrp;
345 346 static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
346 347 static char *xattrapath; /* attribute name */
347 348 static char *xattr_linkaname; /* attribute attribute is linked to */
348 349 static char Hiddendir; /* are we processing hidden xattr dir */
349 350 static char xattrbadhead;
350 351
351 352 /* Was statically allocated tbuf[NBLOCK] */
352 353 static
353 354 union hblock {
354 355 char dummy[TBLOCK];
355 356 struct header {
356 357 char name[NAMSIZ]; /* If non-null prefix, path is */
357 358 /* <prefix>/<name>; otherwise */
358 359 /* <name> */
359 360 char mode[8];
360 361 char uid[8];
361 362 char gid[8];
362 363 char size[12]; /* size of this extent if file split */
363 364 char mtime[12];
364 365 char chksum[8];
365 366 char typeflag;
366 367 char linkname[NAMSIZ];
367 368 char magic[6];
368 369 char version[2];
369 370 char uname[32];
370 371 char gname[32];
371 372 char devmajor[8];
372 373 char devminor[8];
373 374 char prefix[PRESIZ]; /* Together with "name", the path of */
374 375 /* the file: <prefix>/<name> */
375 376 char extno; /* extent #, null if not split */
376 377 char extotal; /* total extents */
377 378 char efsize[10]; /* size of entire file */
378 379 } dbuf;
379 380 } dblock, *tbuf, xhdr_buf;
380 381
381 382 static
382 383 struct xtar_hdr {
383 384 uid_t x_uid, /* Uid of file */
384 385 x_gid; /* Gid of file */
385 386 major_t x_devmajor; /* Device major node */
386 387 minor_t x_devminor; /* Device minor node */
387 388 off_t x_filesz; /* Length of file */
388 389 char *x_uname, /* Pointer to name of user */
389 390 *x_gname, /* Pointer to gid of user */
390 391 *x_linkpath, /* Path for a hard/symbolic link */
391 392 *x_path; /* Path of file */
392 393 timestruc_t x_mtime; /* Seconds and nanoseconds */
393 394 } Xtarhdr;
394 395
395 396 static
396 397 struct gen_hdr {
397 398 ulong_t g_mode; /* Mode of file */
398 399 uid_t g_uid, /* Uid of file */
399 400 g_gid; /* Gid of file */
400 401 off_t g_filesz; /* Length of file */
401 402 time_t g_mtime; /* Modification time */
402 403 uint_t g_cksum; /* Checksum of file */
403 404 ulong_t g_devmajor, /* File system of file */
404 405 g_devminor; /* Major/minor of special files */
405 406 } Gen;
406 407
407 408 static
408 409 struct linkbuf {
409 410 ino_t inum;
410 411 dev_t devnum;
411 412 int count;
412 413 char pathname[MAXNAM+1]; /* added 1 for last NULL */
413 414 char attrname[MAXNAM+1];
414 415 struct linkbuf *nextp;
415 416 } *ihead;
416 417
417 418 /* see comments before build_table() */
418 419 #define TABLE_SIZE 512
419 420 typedef struct file_list {
420 421 char *name; /* Name of file to {in,ex}clude */
421 422 struct file_list *next; /* Linked list */
422 423 } file_list_t;
423 424 static file_list_t *exclude_tbl[TABLE_SIZE],
424 425 *include_tbl[TABLE_SIZE];
425 426
426 427 static int append_secattr(char **, int *, int, char *, char);
427 428 static void write_ancillary(union hblock *, char *, int, char);
428 429
429 430 static void add_file_to_table(file_list_t *table[], char *str);
430 431 static void assert_string(char *s, char *msg);
431 432 static int istape(int fd, int type);
432 433 static void backtape(void);
433 434 static void build_table(file_list_t *table[], char *file);
434 435 static int check_prefix(char **namep, char **dirp, char **compp);
435 436 static void closevol(void);
436 437 static void copy(void *dst, void *src);
437 438 static int convtoreg(off_t);
438 439 static void delete_target(int fd, char *comp, char *namep);
439 440 static void doDirTimes(char *name, timestruc_t modTime);
440 441 static void done(int n);
441 442 static void dorep(char *argv[]);
442 443 static void dotable(char *argv[]);
443 444 static void doxtract(char *argv[]);
444 445 static int tar_chdir(const char *path);
445 446 static int is_directory(char *name);
446 447 static int has_dot_dot(char *name);
447 448 static int is_absolute(char *name);
448 449 static char *make_relative_name(char *name, char **stripped_prefix);
449 450 static void fatal(char *format, ...);
450 451 static void vperror(int exit_status, char *fmt, ...);
451 452 static void flushtape(void);
452 453 static void getdir(void);
453 454 static void *getmem(size_t);
454 455 static void longt(struct stat *st, char aclchar);
455 456 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
456 457 static int makeDir(char *name);
457 458 static void mterr(char *operation, int i, int exitcode);
458 459 static void newvol(void);
459 460 static void passtape(void);
460 461 static void putempty(blkcnt_t n);
461 462 static int putfile(char *longname, char *shortname, char *parent,
462 463 attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
463 464 static void readtape(char *buffer);
464 465 static void seekdisk(blkcnt_t blocks);
465 466 static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
466 467 static void setbytes_to_skip(struct stat *st, int err);
467 468 static void splitfile(char *longname, int ifd, char *name,
468 469 char *prefix, int filetype);
469 470 static void tomodes(struct stat *sp);
470 471 static void usage(void);
471 472 static int xblocks(int issysattr, off_t bytes, int ofile);
472 473 static int xsfile(int issysattr, int ofd);
473 474 static void resugname(int dirfd, char *name, int symflag);
474 475 static int bcheck(char *bstr);
475 476 static int checkdir(char *name);
476 477 static int checksum(union hblock *dblockp);
477 478 #ifdef EUC
478 479 static int checksum_signed(union hblock *dblockp);
479 480 #endif /* EUC */
480 481 static int checkupdate(char *arg);
481 482 static int checkw(char c, char *name);
482 483 static int cmp(char *b, char *s, int n);
483 484 static int defset(char *arch);
484 485 static int endtape(void);
485 486 static int is_in_table(file_list_t *table[], char *str);
486 487 static int notsame(void);
487 488 static int is_prefix(char *s1, char *s2);
488 489 static int response(void);
489 490 static int build_dblock(const char *, const char *, const char,
490 491 const int filetype, const struct stat *, const dev_t, const char *);
491 492 static unsigned int hash(char *str);
492 493
493 494 static blkcnt_t kcheck(char *kstr);
494 495 static off_t bsrch(char *s, int n, off_t l, off_t h);
495 496 static void onintr(int sig);
496 497 static void onquit(int sig);
497 498 static void onhup(int sig);
498 499 static uid_t getuidbyname(char *);
499 500 static gid_t getgidbyname(char *);
500 501 static char *getname(gid_t);
501 502 static char *getgroup(gid_t);
502 503 static int checkf(char *name, int mode, int howmuch);
503 504 static int writetbuf(char *buffer, int n);
504 505 static int wantit(char *argv[], char **namep, char **dirp, char **comp,
505 506 attr_data_t **attrinfo);
506 507 static void append_ext_attr(char *shortname, char **secinfo, int *len);
507 508 static int get_xdata(void);
508 509 static void gen_num(const char *keyword, const u_longlong_t number);
509 510 static void gen_date(const char *keyword, const timestruc_t time_value);
510 511 static void gen_string(const char *keyword, const char *value);
511 512 static void get_xtime(char *value, timestruc_t *xtime);
512 513 static int chk_path_build(char *name, char *longname, char *linkname,
513 514 char *prefix, char type, int filetype);
514 515 static int gen_utf8_names(const char *filename);
515 516 static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
516 517 const char *src, int max_val);
517 518 static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
518 519 iconv_t iconv_cd, int xhdrflg, int max_val);
519 520 static int c_utf8(char *target, const char *source);
520 521 static int getstat(int dirfd, char *longname, char *shortname,
521 522 char *attrparent);
522 523 static void xattrs_put(char *, char *, char *, char *);
523 524 static void prepare_xattr(char **, char *, char *,
524 525 char, struct linkbuf *, int *);
525 526 static int put_link(char *name, char *longname, char *component,
526 527 char *longattrname, char *prefix, int filetype, char typeflag);
527 528 static int put_extra_attributes(char *longname, char *shortname,
528 529 char *longattrname, char *prefix, int filetype, char typeflag);
529 530 static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
530 531 char *prefix, int typeflag, int filetype, struct linkbuf *lp);
531 532 static int read_xattr_hdr(attr_data_t **attrinfo);
532 533
533 534 /* Trusted Extensions */
534 535 #define AUTO_ZONE "/zone"
535 536
536 537 static void extract_attr(char **file_ptr, struct sec_attr *);
537 538 static int check_ext_attr(char *filename);
538 539 static void rebuild_comp_path(char *str, char **namep);
539 540 static int rebuild_lk_comp_path(char *str, char **namep);
540 541
541 542 static void get_parent(char *path, char *dir);
542 543 static char *get_component(char *path);
543 544 static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
544 545 char *name, int oflag, mode_t mode);
545 546 static char *skipslashes(char *string, char *start);
546 547 static void chop_endslashes(char *path);
547 548 static pid_t compress_file(void);
548 549 static void compress_back(void);
549 550 static void decompress_file(void);
550 551 static pid_t uncompress_file(void);
551 552 static void *compress_malloc(size_t);
552 553 static void check_compression(void);
553 554 static char *bz_suffix(void);
↓ open down ↓ |
520 lines elided |
↑ open up ↑ |
554 555 static char *gz_suffix(void);
555 556 static char *xz_suffix(void);
556 557 static char *add_suffix();
557 558 static void wait_pid(pid_t);
558 559 static void verify_compress_opt(const char *t);
559 560 static void detect_compress(void);
560 561
561 562 static struct stat stbuf;
562 563
563 564 static char *myname;
565 +static char *xtract_chdir = NULL;
564 566 static int checkflag = 0;
565 567 static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
566 568 static int rflag, xflag, vflag, tflag, mt, svmt, cflag, mflag, pflag;
567 569 static int uflag;
568 570 static int errflag;
569 571 static int oflag;
570 572 static int bflag, Aflag;
571 573 static int Pflag; /* POSIX conformant archive */
572 574 static int Eflag; /* Allow files greater than 8GB */
573 575 static int atflag; /* traverse extended attributes */
574 576 static int saflag; /* traverse extended sys attributes */
575 577 static int Dflag; /* Data change flag */
576 578 static int jflag; /* flag to use 'bzip2' */
577 579 static int zflag; /* flag to use 'gzip' */
578 580 static int Zflag; /* flag to use 'compress' */
579 581 static int Jflag; /* flag to use 'xz' */
580 582 static int aflag; /* flag to use autocompression */
581 583
582 584 /* Trusted Extensions */
583 585 static int Tflag; /* Trusted Extensions attr flags */
584 586 static int dir_flag; /* for attribute extract */
585 587 static int mld_flag; /* for attribute extract */
586 588 static char *orig_namep; /* original namep - unadorned */
587 589 static int rpath_flag; /* MLD real path is rebuilt */
588 590 static char real_path[MAXPATHLEN]; /* MLD real path */
589 591 static int lk_rpath_flag; /* linked to real path is rebuilt */
590 592 static char lk_real_path[MAXPATHLEN]; /* linked real path */
591 593 static bslabel_t bs_label; /* for attribute extract */
592 594 static bslabel_t admin_low;
593 595 static bslabel_t admin_high;
594 596 static int ignored_aprivs = 0;
595 597 static int ignored_fprivs = 0;
596 598 static int ignored_fattrs = 0;
597 599
598 600 static int term, chksum, wflag,
599 601 first = TRUE, defaults_used = FALSE, linkerrok;
600 602 static blkcnt_t recno;
601 603 static int freemem = 1;
602 604 static int nblock = NBLOCK;
603 605 static int Errflg = 0;
604 606 static int exitflag = 0;
605 607
606 608 static dev_t mt_dev; /* device containing output file */
607 609 static ino_t mt_ino; /* inode number of output file */
608 610 static int mt_devtype; /* dev type of archive, from stat structure */
609 611
610 612 static int update = 1; /* for `open' call */
611 613
612 614 static off_t low;
613 615 static off_t high;
614 616
615 617 static FILE *tfile;
616 618 static FILE *vfile = stdout;
617 619 static char *tmpdir;
618 620 static char *tmp_suffix = "/tarXXXXXX";
619 621 static char *tname;
620 622 static char archive[] = "archive0=";
621 623 static char *Xfile;
622 624 static char *usefile;
623 625 static char tfname[1024];
624 626
625 627 static int mulvol; /* multi-volume option selected */
626 628 static blkcnt_t blocklim; /* number of blocks to accept per volume */
627 629 static blkcnt_t tapepos; /* current block number to be written */
628 630 static int NotTape; /* true if tape is a disk */
629 631 static int dumping; /* true if writing a tape or other archive */
630 632 static int extno; /* number of extent: starts at 1 */
631 633 static int extotal; /* total extents in this file */
632 634 static off_t extsize; /* size of current extent during extraction */
633 635 static ushort_t Oumask = 0; /* old umask value */
634 636 static int is_posix; /* true if archive we're reading is POSIX-conformant */
635 637 static const char *magic_type = "ustar";
636 638 static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */
637 639 static char *xrec_ptr;
638 640 static off_t xrec_offset = 0;
639 641 static int Xhdrflag;
640 642 static int charset_type = 0;
641 643
642 644 static u_longlong_t xhdr_flgs; /* Bits set determine which items */
643 645 /* need to be in extended header. */
644 646 #define _X_DEVMAJOR 0x1
645 647 #define _X_DEVMINOR 0x2
646 648 #define _X_GID 0x4
647 649 #define _X_GNAME 0x8
648 650 #define _X_LINKPATH 0x10
649 651 #define _X_PATH 0x20
650 652 #define _X_SIZE 0x40
651 653 #define _X_UID 0x80
652 654 #define _X_UNAME 0x100
653 655 #define _X_ATIME 0x200
654 656 #define _X_CTIME 0x400
655 657 #define _X_MTIME 0x800
656 658 #define _X_XHDR 0x1000 /* Bit flag that determines whether 'X' */
657 659 /* typeflag was followed by 'A' or non 'A' */
658 660 /* typeflag. */
659 661 #define _X_LAST 0x40000000
660 662
661 663 #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4)
662 664 #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4)
663 665 #define LONG_MAX_DIGITS (10 * sizeof (long) / 4)
664 666 #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4)
665 667 /*
666 668 * UTF_8 encoding requires more space than the current codeset equivalent.
667 669 * Currently a factor of 2-3 would suffice, but it is possible for a factor
668 670 * of 6 to be needed in the future, so for saftey, we use that here.
669 671 */
670 672 #define UTF_8_FACTOR 6
671 673
672 674 static u_longlong_t xhdr_count = 0;
673 675 static char xhdr_dirname[PRESIZ + 1];
674 676 static char pidchars[PID_MAX_DIGITS + 1];
675 677 static char *tchar = ""; /* null linkpath */
676 678
677 679 static char local_path[UTF_8_FACTOR * PATH_MAX + 1];
678 680 static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
679 681 static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
680 682 static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
681 683
682 684 /*
683 685 * The following mechanism is provided to allow us to debug tar in complicated
684 686 * situations, like when it is part of a pipe. The idea is that you compile
685 687 * with -DWAITAROUND defined, and then add the 'D' function modifier to the
686 688 * target tar invocation, eg. "tar cDf tarfile file". If stderr is available,
687 689 * it will tell you to which pid to attach the debugger; otherwise, use ps to
688 690 * find it. Attach to the process from the debugger, and, *PRESTO*, you are
689 691 * there!
690 692 *
691 693 * Simply assign "waitaround = 0" once you attach to the process, and then
692 694 * proceed from there as usual.
693 695 */
694 696
695 697 #ifdef WAITAROUND
696 698 int waitaround = 0; /* wait for rendezvous with the debugger */
697 699 #endif
698 700
699 701 #define BZIP "/usr/bin/bzip2"
700 702 #define GZIP "/usr/bin/gzip"
701 703 #define COMPRESS "/usr/bin/compress"
702 704 #define XZ "/usr/bin/xz"
703 705 #define BZCAT "/usr/bin/bzcat"
704 706 #define GZCAT "/usr/bin/gzcat"
705 707 #define ZCAT "/usr/bin/zcat"
706 708 #define XZCAT "/usr/bin/xzcat"
707 709 #define GSUF 8 /* number of valid 'gzip' sufixes */
708 710 #define BSUF 4 /* number of valid 'bzip2' sufixes */
709 711 #define XSUF 1 /* number of valid 'xz' suffixes */
710 712
711 713 static char *compress_opt; /* compression type */
712 714
713 715 static char *gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
714 716 ".tgz", ".taz"};
715 717 static char *bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
716 718 static char *xsuffix[] = {".xz"};
717 719 static char *suffix;
718 720
719 721
720 722 int
721 723 main(int argc, char *argv[])
722 724 {
723 725 char *cp;
724 726 char *tmpdirp;
725 727 pid_t thispid;
726 728 pid_t pid;
727 729 int wstat;
728 730
729 731 (void) setlocale(LC_ALL, "");
730 732 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
731 733 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
732 734 #endif
733 735 (void) textdomain(TEXT_DOMAIN);
734 736 if (argc < 2)
735 737 usage();
736 738
737 739 tfile = NULL;
738 740 if ((myname = strdup(argv[0])) == NULL) {
739 741 (void) fprintf(stderr, gettext(
740 742 "tar: cannot allocate program name\n"));
741 743 exit(1);
742 744 }
743 745
744 746 if (init_yes() < 0) {
745 747 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
746 748 strerror(errno));
747 749 exit(2);
748 750 }
749 751
750 752 /*
751 753 * For XPG4 compatibility, we must be able to accept the "--"
752 754 * argument normally recognized by getopt; it is used to delimit
753 755 * the end opt the options section, and so can only appear in
754 756 * the position of the first argument. We simply skip it.
755 757 */
756 758
757 759 if (strcmp(argv[1], "--") == 0) {
758 760 argv++;
759 761 argc--;
760 762 if (argc < 3)
761 763 usage();
762 764 }
763 765
764 766 argv[argc] = NULL;
765 767 argv++;
766 768
767 769 /*
768 770 * Set up default values.
769 771 * Search the operand string looking for the first digit or an 'f'.
770 772 * If you find a digit, use the 'archive#' entry in DEF_FILE.
771 773 * If 'f' is given, bypass looking in DEF_FILE altogether.
772 774 * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
773 775 */
774 776 if ((usefile = getenv("TAPE")) == (char *)NULL) {
775 777 for (cp = *argv; *cp; ++cp)
776 778 if (isdigit(*cp) || *cp == 'f')
777 779 break;
778 780 if (*cp != 'f') {
779 781 archive[7] = (*cp)? *cp: '0';
780 782 if (!(defaults_used = defset(archive))) {
781 783 usefile = NULL;
782 784 nblock = 1;
783 785 blocklim = 0;
784 786 NotTape = 0;
785 787 }
786 788 }
787 789 }
788 790
789 791 for (cp = *argv++; *cp; cp++)
790 792 switch (*cp) {
791 793 #ifdef WAITAROUND
792 794 case 'D':
793 795 /* rendezvous with the debugger */
794 796 waitaround = 1;
795 797 break;
796 798 #endif
797 799 case 'f':
798 800 assert_string(*argv, gettext(
799 801 "tar: tarfile must be specified with 'f' "
800 802 "function modifier\n"));
801 803 usefile = *argv++;
802 804 break;
803 805 case 'F':
804 806 Fflag++;
805 807 break;
806 808 case 'c':
807 809 cflag++;
808 810 rflag++;
809 811 update = 1;
810 812 break;
811 813 #if defined(O_XATTR)
812 814 case '@':
813 815 atflag++;
814 816 break;
815 817 #endif /* O_XATTR */
816 818 #if defined(_PC_SATTR_ENABLED)
817 819 case '/':
818 820 saflag++;
819 821 break;
820 822 #endif /* _PC_SATTR_ENABLED */
821 823 case 'u':
822 824 uflag++; /* moved code after signals caught */
823 825 rflag++;
824 826 update = 2;
825 827 break;
826 828 case 'r':
827 829 rflag++;
828 830 update = 2;
829 831 break;
830 832 case 'v':
831 833 vflag++;
832 834 break;
833 835 case 'w':
834 836 wflag++;
835 837 break;
836 838 case 'x':
837 839 xflag++;
838 840 break;
839 841 case 'X':
840 842 assert_string(*argv, gettext(
841 843 "tar: exclude file must be specified with 'X' "
842 844 "function modifier\n"));
843 845 Xflag = 1;
844 846 Xfile = *argv++;
845 847 build_table(exclude_tbl, Xfile);
846 848 break;
847 849 case 't':
848 850 tflag++;
849 851 break;
850 852 case 'm':
851 853 mflag++;
852 854 break;
853 855 case 'p':
854 856 pflag++;
855 857 break;
856 858 case 'D':
857 859 Dflag++;
858 860 break;
859 861 case '-':
860 862 /* ignore this silently */
861 863 break;
862 864 case '0': /* numeric entries used only for defaults */
863 865 case '1':
864 866 case '2':
865 867 case '3':
866 868 case '4':
867 869 case '5':
868 870 case '6':
869 871 case '7':
870 872 break;
871 873 case 'b':
872 874 assert_string(*argv, gettext(
873 875 "tar: blocking factor must be specified "
874 876 "with 'b' function modifier\n"));
875 877 bflag++;
876 878 nblock = bcheck(*argv++);
877 879 break;
878 880 case 'n': /* not a magtape (instead of 'k') */
879 881 NotTape++; /* assume non-magtape */
880 882 break;
881 883 case 'l':
882 884 linkerrok++;
883 885 break;
884 886 case 'e':
885 887 errflag++;
886 888 case 'o':
887 889 oflag++;
888 890 break;
889 891 case 'h':
890 892 hflag++;
891 893 break;
892 894 case 'i':
893 895 iflag++;
894 896 break;
895 897 case 'B':
896 898 Bflag++;
897 899 break;
898 900 case 'P':
899 901 Pflag++;
900 902 break;
901 903 case 'E':
902 904 Eflag++;
903 905 Pflag++; /* Only POSIX archive made */
904 906 break;
905 907 case 'T':
906 908 Tflag++; /* Handle Trusted Extensions attrs */
907 909 pflag++; /* also set flag for ACL */
908 910 break;
909 911 case 'j': /* compession "bzip2" */
910 912 jflag = 1;
911 913 break;
912 914 case 'z': /* compression "gzip" */
913 915 zflag = 1;
914 916 break;
915 917 case 'Z': /* compression "compress" */
916 918 Zflag = 1;
917 919 break;
918 920 case 'J': /* compression "xz" */
919 921 Jflag = 1;
920 922 break;
921 923 case 'a':
922 924 aflag = 1; /* autocompression */
923 925 break;
924 926 default:
925 927 (void) fprintf(stderr, gettext(
926 928 "tar: %c: unknown function modifier\n"), *cp);
927 929 usage();
928 930 }
929 931
930 932 if (!rflag && !xflag && !tflag)
931 933 usage();
932 934 if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
933 935 (void) fprintf(stderr, gettext(
934 936 "tar: specify only one of [ctxru].\n"));
935 937 usage();
936 938 }
937 939 if (cflag) {
938 940 if ((jflag + zflag + Zflag + Jflag + aflag) > 1) {
939 941 (void) fprintf(stderr, gettext(
940 942 "tar: specify only one of [ajJzZ] to "
941 943 "create a compressed file.\n"));
942 944 usage();
943 945 }
944 946 }
945 947 /* Trusted Extensions attribute handling */
946 948 if (Tflag && ((getzoneid() != GLOBAL_ZONEID) ||
947 949 !is_system_labeled())) {
948 950 (void) fprintf(stderr, gettext(
949 951 "tar: the 'T' option is only available with "
950 952 "Trusted Extensions\nand must be run from "
951 953 "the global zone.\n"));
952 954 usage();
953 955 }
954 956 if (cflag && *argv == NULL)
955 957 fatal(gettext("Missing filenames"));
956 958 if (usefile == NULL)
957 959 fatal(gettext("device argument required"));
958 960
959 961 /* alloc a buffer of the right size */
960 962 if ((tbuf = (union hblock *)
961 963 calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
962 964 (union hblock *)NULL) {
963 965 (void) fprintf(stderr, gettext(
964 966 "tar: cannot allocate physio buffer\n"));
965 967 exit(1);
966 968 }
967 969
968 970 if ((xrec_ptr = malloc(xrec_size)) == NULL) {
969 971 (void) fprintf(stderr, gettext(
970 972 "tar: cannot allocate extended header buffer\n"));
971 973 exit(1);
972 974 }
973 975
974 976 #ifdef WAITAROUND
975 977 if (waitaround) {
976 978 (void) fprintf(stderr, gettext("Rendezvous with tar on pid"
977 979 " %d\n"), getpid());
978 980
979 981 while (waitaround) {
980 982 (void) sleep(10);
981 983 }
982 984 }
983 985 #endif
984 986
985 987 thispid = getpid();
986 988 (void) sprintf(pidchars, "%ld", thispid);
987 989 thispid = strlen(pidchars);
988 990
989 991 if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL)
990 992 (void) strcpy(xhdr_dirname, "/tmp");
991 993 else {
992 994 /*
993 995 * Make sure that dir is no longer than what can
994 996 * fit in the prefix part of the header.
995 997 */
996 998 if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
997 999 (void) strcpy(xhdr_dirname, "/tmp");
998 1000 if ((vflag > 0) && (Eflag > 0))
999 1001 (void) fprintf(stderr, gettext(
1000 1002 "Ignoring TMPDIR\n"));
1001 1003 } else
1002 1004 (void) strcpy(xhdr_dirname, tmpdirp);
1003 1005 }
1004 1006 (void) strcat(xhdr_dirname, "/PaxHeaders.");
1005 1007 (void) strcat(xhdr_dirname, pidchars);
1006 1008
1007 1009 if (rflag) {
1008 1010 if (cflag && usefile != NULL) {
1009 1011 /* Set the compression type */
1010 1012 if (aflag)
1011 1013 detect_compress();
1012 1014
1013 1015 if (jflag) {
1014 1016 compress_opt = compress_malloc(strlen(BZIP)
1015 1017 + 1);
1016 1018 (void) strcpy(compress_opt, BZIP);
1017 1019 } else if (zflag) {
1018 1020 compress_opt = compress_malloc(strlen(GZIP)
1019 1021 + 1);
1020 1022 (void) strcpy(compress_opt, GZIP);
1021 1023 } else if (Zflag) {
1022 1024 compress_opt =
1023 1025 compress_malloc(strlen(COMPRESS) + 1);
1024 1026 (void) strcpy(compress_opt, COMPRESS);
1025 1027 } else if (Jflag) {
1026 1028 compress_opt = compress_malloc(strlen(XZ) + 1);
1027 1029 (void) strcpy(compress_opt, XZ);
1028 1030 }
1029 1031 } else {
1030 1032 /*
1031 1033 * Decompress if the file is compressed for
1032 1034 * an update or replace.
1033 1035 */
1034 1036 if (strcmp(usefile, "-") != 0) {
1035 1037 check_compression();
1036 1038 if (compress_opt != NULL) {
1037 1039 decompress_file();
1038 1040 }
1039 1041 }
1040 1042 }
1041 1043
1042 1044 if (cflag && tfile != NULL)
1043 1045 usage();
1044 1046 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1045 1047 (void) signal(SIGINT, onintr);
1046 1048 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1047 1049 (void) signal(SIGHUP, onhup);
1048 1050 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1049 1051 (void) signal(SIGQUIT, onquit);
1050 1052 if (uflag) {
1051 1053 int tnum;
1052 1054 struct stat sbuf;
1053 1055
1054 1056 tmpdir = getenv("TMPDIR");
1055 1057 /*
1056 1058 * If the name is invalid or this isn't a directory,
1057 1059 * or the directory is not writable, then reset to
1058 1060 * a default temporary directory.
1059 1061 */
1060 1062 if (tmpdir == NULL || *tmpdir == '\0' ||
1061 1063 (strlen(tmpdir) + strlen(tmp_suffix)) > PATH_MAX) {
1062 1064 tmpdir = "/tmp";
1063 1065 } else if (stat(tmpdir, &sbuf) < 0 ||
1064 1066 (sbuf.st_mode & S_IFMT) != S_IFDIR ||
1065 1067 (sbuf.st_mode & S_IWRITE) == 0) {
1066 1068 tmpdir = "/tmp";
1067 1069 }
1068 1070
1069 1071 if ((tname = calloc(1, strlen(tmpdir) +
1070 1072 strlen(tmp_suffix) + 1)) == NULL) {
1071 1073 vperror(1, gettext("tar: out of memory, "
1072 1074 "cannot create temporary file\n"));
1073 1075 }
1074 1076 (void) strcpy(tname, tmpdir);
1075 1077 (void) strcat(tname, tmp_suffix);
1076 1078
1077 1079 if ((tnum = mkstemp(tname)) == -1)
1078 1080 vperror(1, "%s", tname);
1079 1081 if ((tfile = fdopen(tnum, "w")) == NULL)
1080 1082 vperror(1, "%s", tname);
1081 1083 }
1082 1084 if (strcmp(usefile, "-") == 0) {
1083 1085 if (cflag == 0)
1084 1086 fatal(gettext(
1085 1087 "can only create standard output archives."));
1086 1088 vfile = stderr;
1087 1089 mt = dup(1);
1088 1090 ++bflag;
1089 1091 } else {
1090 1092 if (cflag)
1091 1093 mt = open(usefile,
1092 1094 O_RDWR|O_CREAT|O_TRUNC, 0666);
1093 1095 else
1094 1096 mt = open(usefile, O_RDWR);
1095 1097
1096 1098 if (mt < 0) {
1097 1099 if (cflag == 0 || (mt = creat(usefile, 0666))
1098 1100 < 0)
1099 1101 vperror(1, "%s", usefile);
1100 1102 }
1101 1103 }
1102 1104 /* Get inode and device number of output file */
1103 1105 (void) fstat(mt, &stbuf);
1104 1106 mt_ino = stbuf.st_ino;
1105 1107 mt_dev = stbuf.st_dev;
1106 1108 mt_devtype = stbuf.st_mode & S_IFMT;
1107 1109 NotTape = !istape(mt, mt_devtype);
1108 1110
1109 1111 if (rflag && !cflag && (mt_devtype == S_IFIFO))
1110 1112 fatal(gettext("cannot append to pipe or FIFO."));
1111 1113
1112 1114 if (Aflag && vflag)
1113 1115 (void) printf(
1114 1116 gettext("Suppressing absolute pathnames\n"));
1115 1117 if (cflag && compress_opt != NULL) {
1116 1118 pid = compress_file();
1117 1119 wait_pid(pid);
1118 1120 }
1119 1121 dorep(argv);
1120 1122 if (rflag && !cflag && (compress_opt != NULL))
1121 1123 compress_back();
1122 1124 } else if (xflag || tflag) {
1123 1125 /*
1124 1126 * for each argument, check to see if there is a "-I file" pair.
1125 1127 * if so, move the 3rd argument into "-I"'s place, build_table()
1126 1128 * using "file"'s name and increment argc one (the second
1127 1129 * increment appears in the for loop) which removes the two
1128 1130 * args "-I" and "file" from the argument vector.
1129 1131 */
1130 1132 for (argc = 0; argv[argc]; argc++) {
↓ open down ↓ |
557 lines elided |
↑ open up ↑ |
1131 1133 if (strcmp(argv[argc], "-I") == 0) {
1132 1134 if (!argv[argc+1]) {
1133 1135 (void) fprintf(stderr, gettext(
1134 1136 "tar: missing argument for -I flag\n"));
1135 1137 done(2);
1136 1138 } else {
1137 1139 Iflag = 1;
1138 1140 argv[argc] = argv[argc+2];
1139 1141 build_table(include_tbl, argv[++argc]);
1140 1142 }
1143 + } else if (strcmp(argv[argc], "-C") == 0) {
1144 + if (!argv[argc+1]) {
1145 + (void) fprintf(stderr, gettext("tar: "
1146 + "missing argument for -C flag\n"));
1147 + done(2);
1148 + } else if (xtract_chdir != NULL) {
1149 + (void) fprintf(stderr, gettext("tar: "
1150 + "extract should have only one -C "
1151 + "flag\n"));
1152 + done(2);
1153 + } else {
1154 + argv[argc] = argv[argc+2];
1155 + xtract_chdir = argv[++argc];
1156 + }
1141 1157 }
1142 1158 }
1143 1159 if (strcmp(usefile, "-") == 0) {
1144 1160 mt = dup(0);
1145 1161 ++bflag;
1146 1162 /* try to recover from short reads when reading stdin */
1147 1163 ++Bflag;
1148 1164 } else if ((mt = open(usefile, 0)) < 0)
1149 1165 vperror(1, "%s", usefile);
1150 1166
1151 1167 /* Decompress if the file is compressed */
1152 1168
1153 1169 if (strcmp(usefile, "-") != 0) {
1154 1170 check_compression();
1155 1171 if (compress_opt != NULL) {
1156 1172 pid = uncompress_file();
1157 1173 wait_pid(pid);
1158 1174 }
1159 1175 }
1160 1176 if (xflag) {
1177 + if (xtract_chdir != NULL) {
1178 + if (tar_chdir(xtract_chdir) < 0) {
1179 + vperror(1, gettext("can't change "
1180 + "directories to %s"), xtract_chdir);
1181 + }
1182 + }
1161 1183 if (Aflag && vflag)
1162 1184 (void) printf(gettext(
1163 1185 "Suppressing absolute pathnames.\n"));
1164 1186
1165 1187 doxtract(argv);
1166 1188 } else if (tflag)
1167 1189 dotable(argv);
1168 1190 }
1169 1191 else
1170 1192 usage();
1171 1193
1172 1194 done(Errflg);
1173 1195
1174 1196 /* Not reached: keep compiler quiet */
1175 1197 return (1);
1176 1198 }
1177 1199
1178 1200 static void
1179 1201 usage(void)
1180 1202 {
1181 1203 (void) fprintf(stderr, gettext(
1182 1204 #if defined(O_XATTR)
1183 1205 #if defined(_PC_SATTR_ENABLED)
1184 1206 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@/[0-7]][bf][X...] "
1185 1207 #else
1186 1208 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@[0-7]][bf][X...] "
1187 1209 #endif /* _PC_SATTR_ENABLED */
1188 1210 #else
1189 1211 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw[0-7]][bf][X...] "
1190 1212 #endif /* O_XATTR */
1191 1213 "[j|J|z|Z] "
1192 1214 "[blocksize] [tarfile] [size] [exclude-file...] "
1193 1215 "{file | -I include-file | -C directory file}...\n"));
1194 1216 done(1);
1195 1217 }
1196 1218
1197 1219 /*
1198 1220 * dorep - do "replacements"
1199 1221 *
1200 1222 * Dorep is responsible for creating ('c'), appending ('r')
1201 1223 * and updating ('u');
1202 1224 */
1203 1225
1204 1226 static void
1205 1227 dorep(char *argv[])
1206 1228 {
1207 1229 char *cp, *cp2, *p;
1208 1230 char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
1209 1231 char file[PATH_MAX*2], origdir[PATH_MAX+1];
1210 1232 FILE *fp = (FILE *)NULL;
1211 1233 int archtype;
1212 1234 int ret;
1213 1235
1214 1236
1215 1237 if (!cflag) {
1216 1238 xhdr_flgs = 0;
1217 1239 getdir(); /* read header for next file */
1218 1240 if (Xhdrflag > 0) {
1219 1241 if (!Eflag)
1220 1242 fatal(gettext("Archive contains extended"
1221 1243 " header. -E flag required.\n"));
1222 1244 ret = get_xdata(); /* Get extended header items */
1223 1245 /* and regular header */
1224 1246 } else {
1225 1247 if (Eflag)
1226 1248 fatal(gettext("Archive contains no extended"
1227 1249 " header. -E flag not allowed.\n"));
1228 1250 }
1229 1251 while (!endtape()) { /* changed from a do while */
1230 1252 setbytes_to_skip(&stbuf, ret);
1231 1253 passtape(); /* skip the file data */
1232 1254 if (term)
1233 1255 done(Errflg); /* received signal to stop */
1234 1256 xhdr_flgs = 0;
1235 1257 getdir();
1236 1258 if (Xhdrflag > 0)
1237 1259 ret = get_xdata();
1238 1260 }
1239 1261 if (ret == 0) {
1240 1262 if ((dblock.dbuf.typeflag != 'A') &&
1241 1263 (xhdr_flgs != 0)) {
1242 1264 load_info_from_xtarhdr(xhdr_flgs,
1243 1265 &Xtarhdr);
1244 1266 xhdr_flgs |= _X_XHDR;
1245 1267 }
1246 1268 }
1247 1269 backtape(); /* was called by endtape */
1248 1270 if (tfile != NULL) {
1249 1271 /*
1250 1272 * Buffer size is calculated to be the size of the
1251 1273 * tmpdir string, plus 6 times the size of the tname
1252 1274 * string, plus a value that is known to be greater
1253 1275 * than the command pipeline string.
1254 1276 */
1255 1277 int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
1256 1278 char *buf;
1257 1279
1258 1280 if ((buf = (char *)calloc(1, buflen)) == NULL) {
1259 1281 vperror(1, gettext("tar: out of memory, "
1260 1282 "cannot create sort command file\n"));
1261 1283 }
1262 1284
1263 1285 (void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
1264 1286 "sort +0 -1 +1nr %s -o %s; awk '$1 "
1265 1287 "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1266 1288 tmpdir, tname, tname, tname, tname, tname, tname);
1267 1289 (void) fflush(tfile);
1268 1290 (void) system(buf);
1269 1291 free(buf);
1270 1292 (void) freopen(tname, "r", tfile);
1271 1293 (void) fstat(fileno(tfile), &stbuf);
1272 1294 high = stbuf.st_size;
1273 1295 }
1274 1296 }
1275 1297
1276 1298 dumping = 1;
1277 1299 if (mulvol) { /* SP-1 */
1278 1300 if (nblock && (blocklim%nblock) != 0)
1279 1301 fatal(gettext(
1280 1302 "Volume size not a multiple of block size."));
1281 1303 blocklim -= 2; /* for trailer records */
1282 1304 if (vflag)
1283 1305 (void) fprintf(vfile, gettext("Volume ends at %"
1284 1306 FMT_blkcnt_t "K, blocking factor = %dK\n"),
1285 1307 K((blocklim - 1)), K(nblock));
1286 1308 }
1287 1309
1288 1310 /*
1289 1311 * Save the original directory before it gets
1290 1312 * changed.
1291 1313 */
1292 1314 if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
1293 1315 vperror(0, gettext("A parent directory cannot be read"));
1294 1316 exit(1);
1295 1317 }
1296 1318
1297 1319 (void) strcpy(wdir, origdir);
1298 1320
1299 1321 while ((*argv || fp) && !term) {
1300 1322 if (fp || (strcmp(*argv, "-I") == 0)) {
1301 1323 if (fp == NULL) {
1302 1324 if (*++argv == NULL)
1303 1325 fatal(gettext(
1304 1326 "missing file name for -I flag."));
1305 1327 else if ((fp = fopen(*argv++, "r")) == NULL)
1306 1328 vperror(0, "%s", argv[-1]);
1307 1329 continue;
1308 1330 } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
1309 1331 (void) fclose(fp);
1310 1332 fp = NULL;
1311 1333 continue;
1312 1334 } else {
1313 1335 cp = cp2 = file;
1314 1336 if ((p = strchr(cp2, '\n')))
1315 1337 *p = 0;
1316 1338 }
1317 1339 } else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
1318 1340 if (tar_chdir(*++argv) < 0)
1319 1341 vperror(0, gettext(
1320 1342 "can't change directories to %s"), *argv);
1321 1343 else
1322 1344 (void) getcwd(wdir, (sizeof (wdir)));
1323 1345 argv++;
1324 1346 continue;
1325 1347 } else
1326 1348 cp = cp2 = strcpy(file, *argv++);
1327 1349
1328 1350 /*
1329 1351 * point cp2 to the last '/' in file, but not
1330 1352 * to a trailing '/'
1331 1353 */
1332 1354 for (; *cp; cp++) {
1333 1355 if (*cp == '/') {
1334 1356 while (*(cp+1) == '/') {
1335 1357 ++cp;
1336 1358 }
1337 1359 if (*(cp+1) != '\0') {
1338 1360 /* not trailing slash */
1339 1361 cp2 = cp;
1340 1362 }
1341 1363 }
1342 1364 }
1343 1365 if (cp2 != file) {
1344 1366 *cp2 = '\0';
1345 1367 if (tar_chdir(file) < 0) {
1346 1368 vperror(0, gettext(
1347 1369 "can't change directories to %s"), file);
1348 1370 continue;
1349 1371 }
1350 1372 *cp2 = '/';
1351 1373 cp2++;
1352 1374 }
1353 1375
1354 1376 parent = getcwd(tempdir, (sizeof (tempdir)));
1355 1377
1356 1378 archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
1357 1379 LEV0, SYMLINK_LEV0);
1358 1380
1359 1381 #if defined(O_XATTR)
1360 1382 if (!exitflag) {
1361 1383 if ((atflag || saflag) &&
1362 1384 (archtype == PUT_NOTAS_LINK)) {
1363 1385 xattrs_put(file, cp2, parent, NULL);
1364 1386 }
1365 1387 }
1366 1388 #endif
1367 1389
1368 1390 if (tar_chdir(origdir) < 0)
1369 1391 vperror(0, gettext("cannot change back?: %s"), origdir);
1370 1392
1371 1393 if (exitflag) {
1372 1394 /*
1373 1395 * If e function modifier has been specified
1374 1396 * write the files (that are listed before the
1375 1397 * file causing the error) to tape. exitflag is
1376 1398 * used because only some of the error conditions
1377 1399 * in putfile() recognize the e function modifier.
1378 1400 */
1379 1401 break;
1380 1402 }
1381 1403 }
1382 1404
1383 1405 putempty((blkcnt_t)2);
1384 1406 flushtape();
1385 1407 closevol(); /* SP-1 */
1386 1408 if (linkerrok == 1)
1387 1409 for (; ihead != NULL; ihead = ihead->nextp) {
1388 1410 if (ihead->count == 0)
1389 1411 continue;
1390 1412 (void) fprintf(stderr, gettext(
1391 1413 "tar: missing links to %s\n"), ihead->pathname);
1392 1414 if (errflag)
1393 1415 done(1);
1394 1416 else
1395 1417 Errflg = 1;
1396 1418 }
1397 1419 }
1398 1420
1399 1421
1400 1422 /*
1401 1423 * endtape - check for tape at end
1402 1424 *
1403 1425 * endtape checks the entry in dblock.dbuf to see if its the
1404 1426 * special EOT entry. Endtape is usually called after getdir().
1405 1427 *
1406 1428 * endtape used to call backtape; it no longer does, he who
1407 1429 * wants it backed up must call backtape himself
1408 1430 * RETURNS: 0 if not EOT, tape position unaffected
1409 1431 * 1 if EOT, tape position unaffected
1410 1432 */
1411 1433
1412 1434 static int
1413 1435 endtape(void)
1414 1436 {
1415 1437 if (dblock.dbuf.name[0] == '\0') { /* null header = EOT */
1416 1438 return (1);
1417 1439 } else
1418 1440 return (0);
1419 1441 }
1420 1442
1421 1443 /*
1422 1444 * getdir - get directory entry from tar tape
1423 1445 *
1424 1446 * getdir reads the next tarblock off the tape and cracks
1425 1447 * it as a directory. The checksum must match properly.
1426 1448 *
1427 1449 * If tfile is non-null getdir writes the file name and mod date
1428 1450 * to tfile.
1429 1451 */
1430 1452
1431 1453 static void
1432 1454 getdir(void)
1433 1455 {
1434 1456 struct stat *sp;
1435 1457 #ifdef EUC
1436 1458 static int warn_chksum_sign = 0;
1437 1459 #endif /* EUC */
1438 1460
1439 1461 top:
1440 1462 readtape((char *)&dblock);
1441 1463 if (dblock.dbuf.name[0] == '\0')
1442 1464 return;
1443 1465 sp = &stbuf;
1444 1466 (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
1445 1467 (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
1446 1468 (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
1447 1469 (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
1448 1470 (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
1449 1471 (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
1450 1472 (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
1451 1473 (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
1452 1474
1453 1475 is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
1454 1476
1455 1477 sp->st_mode = Gen.g_mode;
1456 1478 if (is_posix && (sp->st_mode & S_IFMT) == 0)
1457 1479 switch (dblock.dbuf.typeflag) {
1458 1480 case '0': case 0: case _XATTR_HDRTYPE:
1459 1481 sp->st_mode |= S_IFREG;
1460 1482 break;
1461 1483 case '1': /* hard link */
1462 1484 break;
1463 1485 case '2':
1464 1486 sp->st_mode |= S_IFLNK;
1465 1487 break;
1466 1488 case '3':
1467 1489 sp->st_mode |= S_IFCHR;
1468 1490 break;
1469 1491 case '4':
1470 1492 sp->st_mode |= S_IFBLK;
1471 1493 break;
1472 1494 case '5':
1473 1495 sp->st_mode |= S_IFDIR;
1474 1496 break;
1475 1497 case '6':
1476 1498 sp->st_mode |= S_IFIFO;
1477 1499 break;
1478 1500 default:
1479 1501 if (convtoreg(Gen.g_filesz))
1480 1502 sp->st_mode |= S_IFREG;
1481 1503 break;
1482 1504 }
1483 1505
1484 1506 if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
1485 1507 Xhdrflag = 1; /* Currently processing extended header */
1486 1508 } else {
1487 1509 Xhdrflag = 0;
1488 1510 }
1489 1511
1490 1512 sp->st_uid = Gen.g_uid;
1491 1513 sp->st_gid = Gen.g_gid;
1492 1514 sp->st_size = Gen.g_filesz;
1493 1515 sp->st_mtime = Gen.g_mtime;
1494 1516 chksum = Gen.g_cksum;
1495 1517
1496 1518 if (dblock.dbuf.extno != '\0') { /* split file? */
1497 1519 extno = dblock.dbuf.extno;
1498 1520 extsize = Gen.g_filesz;
1499 1521 extotal = dblock.dbuf.extotal;
1500 1522 } else {
1501 1523 extno = 0; /* tell others file not split */
1502 1524 extsize = 0;
1503 1525 extotal = 0;
1504 1526 }
1505 1527
1506 1528 #ifdef EUC
1507 1529 if (chksum != checksum(&dblock)) {
1508 1530 if (chksum != checksum_signed(&dblock)) {
1509 1531 (void) fprintf(stderr, gettext(
1510 1532 "tar: directory checksum error\n"));
1511 1533 if (iflag) {
1512 1534 Errflg = 2;
1513 1535 goto top;
1514 1536 }
1515 1537 done(2);
1516 1538 } else {
1517 1539 if (! warn_chksum_sign) {
1518 1540 warn_chksum_sign = 1;
1519 1541 (void) fprintf(stderr, gettext(
1520 1542 "tar: warning: tar file made with signed checksum\n"));
1521 1543 }
1522 1544 }
1523 1545 }
1524 1546 #else
1525 1547 if (chksum != checksum(&dblock)) {
1526 1548 (void) fprintf(stderr, gettext(
1527 1549 "tar: directory checksum error\n"));
1528 1550 if (iflag) {
1529 1551 Errflg = 2;
1530 1552 goto top;
1531 1553 }
1532 1554 done(2);
1533 1555 }
1534 1556 #endif /* EUC */
1535 1557 if (tfile != NULL && Xhdrflag == 0) {
1536 1558 /*
1537 1559 * If an extended header is present, then time is available
1538 1560 * in nanoseconds in the extended header data, so set it.
1539 1561 * Otherwise, give an invalid value so that checkupdate will
1540 1562 * not test beyond seconds.
1541 1563 */
1542 1564 if ((xhdr_flgs & _X_MTIME))
1543 1565 sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
1544 1566 else
1545 1567 sp->st_mtim.tv_nsec = -1;
1546 1568
1547 1569 if (xhdr_flgs & _X_PATH)
1548 1570 (void) fprintf(tfile, "%s %10ld.%9.9ld\n",
1549 1571 Xtarhdr.x_path, sp->st_mtim.tv_sec,
1550 1572 sp->st_mtim.tv_nsec);
1551 1573 else
1552 1574 (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
1553 1575 NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
1554 1576 sp->st_mtim.tv_nsec);
1555 1577 }
1556 1578
1557 1579 #if defined(O_XATTR)
1558 1580 Hiddendir = 0;
1559 1581 if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
1560 1582 if (xattrbadhead) {
1561 1583 free(xattrhead);
1562 1584 xattrp = NULL;
1563 1585 xattr_linkp = NULL;
1564 1586 xattrhead = NULL;
1565 1587 } else {
1566 1588 char *aname = basename(xattrapath);
1567 1589 size_t xindex = aname - xattrapath;
1568 1590
1569 1591 if (xattrapath[xindex] == '.' &&
1570 1592 xattrapath[xindex + 1] == '\0' &&
1571 1593 xattrp->h_typeflag == '5') {
1572 1594 Hiddendir = 1;
1573 1595 sp->st_mode =
1574 1596 (S_IFDIR | (sp->st_mode & POSIXMODES));
1575 1597 }
1576 1598 dblock.dbuf.typeflag = xattrp->h_typeflag;
1577 1599 }
1578 1600 }
1579 1601 #endif
1580 1602 }
1581 1603
1582 1604
1583 1605 /*
1584 1606 * passtape - skip over a file on the tape
1585 1607 *
1586 1608 * passtape skips over the next data file on the tape.
1587 1609 * The tape directory entry must be in dblock.dbuf. This
1588 1610 * routine just eats the number of blocks computed from the
1589 1611 * directory size entry; the tape must be (logically) positioned
1590 1612 * right after thee directory info.
1591 1613 */
1592 1614
1593 1615 static void
1594 1616 passtape(void)
1595 1617 {
1596 1618 blkcnt_t blocks;
1597 1619 char buf[TBLOCK];
1598 1620
1599 1621 /*
1600 1622 * Types link(1), sym-link(2), char special(3), blk special(4),
1601 1623 * directory(5), and FIFO(6) do not have data blocks associated
1602 1624 * with them so just skip reading the data block.
1603 1625 */
1604 1626 if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
1605 1627 dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
1606 1628 dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
1607 1629 return;
1608 1630 blocks = TBLOCKS(stbuf.st_size);
1609 1631
1610 1632 /* if operating on disk, seek instead of reading */
1611 1633 if (NotTape)
1612 1634 seekdisk(blocks);
1613 1635 else
1614 1636 while (blocks-- > 0)
1615 1637 readtape(buf);
1616 1638 }
1617 1639
1618 1640 #if defined(O_XATTR)
1619 1641 static int
1620 1642 is_sysattr(char *name)
1621 1643 {
1622 1644 return ((strcmp(name, VIEW_READONLY) == 0) ||
1623 1645 (strcmp(name, VIEW_READWRITE) == 0));
1624 1646 }
1625 1647 #endif
1626 1648
1627 1649 #if defined(O_XATTR)
1628 1650 /*
1629 1651 * Verify the attribute, attrname, is an attribute we want to restore.
1630 1652 * Never restore read-only system attribute files. Only restore read-write
1631 1653 * system attributes files when -/ was specified, and only traverse into
1632 1654 * the 2nd level attribute directory containing only system attributes if
1633 1655 * -@ was specified. This keeps us from archiving
1634 1656 * <attribute name>/<read-write system attribute file>
1635 1657 * when -/ was specified without -@.
1636 1658 *
1637 1659 * attrname - attribute file name
1638 1660 * attrparent - attribute's parent name within the base file's attribute
1639 1661 * directory hierarchy
1640 1662 */
1641 1663 static attr_status_t
1642 1664 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
1643 1665 int *rw_sysattr)
1644 1666 {
1645 1667 #if defined(_PC_SATTR_ENABLED)
1646 1668 int attr_supported;
1647 1669
1648 1670 /* Never restore read-only system attribute files */
1649 1671 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
1650 1672 *rw_sysattr = 0;
1651 1673 return (ATTR_SKIP);
1652 1674 } else {
1653 1675 *rw_sysattr = (attr_supported == _RW_SATTR);
1654 1676 }
1655 1677 #else
1656 1678 /*
1657 1679 * Only need to check if this attribute is an extended system
1658 1680 * attribute.
1659 1681 */
1660 1682 if (*rw_sysattr = is_sysattr(attrname)) {
1661 1683 return (ATTR_SKIP);
1662 1684 } else {
1663 1685 return (ATTR_OK);
1664 1686 }
1665 1687 #endif /* _PC_SATTR_ENABLED */
1666 1688
1667 1689 /*
1668 1690 * If the extended system attribute file is specified with the
1669 1691 * arc_rwsysattr flag, as being transient (default extended
1670 1692 * attributes), then don't archive it.
1671 1693 */
1672 1694 if (*rw_sysattr && !arc_rwsysattr) {
1673 1695 return (ATTR_SKIP);
1674 1696 }
1675 1697
1676 1698 /*
1677 1699 * Only restore read-write system attribute files
1678 1700 * when -/ was specified. Only restore extended
1679 1701 * attributes when -@ was specified.
1680 1702 */
1681 1703 if (atflag) {
1682 1704 if (!saflag) {
1683 1705 /*
1684 1706 * Only archive/restore the hidden directory "." if
1685 1707 * we're processing the top level hidden attribute
1686 1708 * directory. We don't want to process the
1687 1709 * hidden attribute directory of the attribute
1688 1710 * directory that contains only extended system
1689 1711 * attributes.
1690 1712 */
1691 1713 if (*rw_sysattr || (Hiddendir &&
1692 1714 (attrparent != NULL))) {
1693 1715 return (ATTR_SKIP);
1694 1716 }
1695 1717 }
1696 1718 } else if (saflag) {
1697 1719 /*
1698 1720 * Only archive/restore read-write extended system attribute
1699 1721 * files of the base file.
1700 1722 */
1701 1723 if (!*rw_sysattr || (attrparent != NULL)) {
1702 1724 return (ATTR_SKIP);
1703 1725 }
1704 1726 } else {
1705 1727 return (ATTR_SKIP);
1706 1728 }
1707 1729
1708 1730 return (ATTR_OK);
1709 1731 }
1710 1732 #endif
1711 1733
1712 1734 static void
1713 1735 free_children(file_list_t *children)
1714 1736 {
1715 1737 file_list_t *child = children;
1716 1738 file_list_t *cptr;
1717 1739
1718 1740 while (child != NULL) {
1719 1741 cptr = child->next;
1720 1742 if (child->name != NULL) {
1721 1743 free(child->name);
1722 1744 }
1723 1745 child = cptr;
1724 1746 }
1725 1747 }
1726 1748
1727 1749 static int
1728 1750 putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
1729 1751 int filetype, int lev, int symlink_lev)
1730 1752 {
1731 1753 int infile = -1; /* deliberately invalid */
1732 1754 blkcnt_t blocks;
1733 1755 char buf[PATH_MAX + 2]; /* Add trailing slash and null */
1734 1756 char *bigbuf;
1735 1757 int maxread;
1736 1758 int hint; /* amount to write to get "in sync" */
1737 1759 char filetmp[PATH_MAX + 1];
1738 1760 char *cp;
1739 1761 char *name;
1740 1762 char *attrparent = NULL;
1741 1763 char *longattrname = NULL;
1742 1764 file_list_t *child = NULL;
1743 1765 file_list_t *child_end = NULL;
1744 1766 file_list_t *cptr;
1745 1767 struct dirent *dp;
1746 1768 DIR *dirp;
1747 1769 int i;
1748 1770 int split;
1749 1771 int dirfd = -1;
1750 1772 int rc = PUT_NOTAS_LINK;
1751 1773 int archtype = 0;
1752 1774 int rw_sysattr = 0;
1753 1775 char newparent[PATH_MAX + MAXNAMLEN + 1];
1754 1776 char *prefix = "";
1755 1777 char *tmpbuf;
1756 1778 char goodbuf[PRESIZ + 2];
1757 1779 char junkbuf[MAXNAM+1];
1758 1780 char *lastslash;
1759 1781 int j;
1760 1782 struct stat sbuf;
1761 1783 int readlink_max;
1762 1784
1763 1785 (void) memset(goodbuf, '\0', sizeof (goodbuf));
1764 1786 (void) memset(junkbuf, '\0', sizeof (junkbuf));
1765 1787
1766 1788 xhdr_flgs = 0;
1767 1789
1768 1790 if (filetype == XATTR_FILE) {
1769 1791 attrparent = attrinfo->attr_parent;
1770 1792 longattrname = attrinfo->attr_path;
1771 1793 dirfd = attrinfo->attr_parentfd;
1772 1794 rw_sysattr = attrinfo->attr_rw_sysattr;
1773 1795 } else {
1774 1796 dirfd = open(".", O_RDONLY);
1775 1797 }
1776 1798
1777 1799 if (dirfd == -1) {
1778 1800 (void) fprintf(stderr, gettext(
1779 1801 "tar: unable to open%sdirectory %s%s%s%s\n"),
1780 1802 (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
1781 1803 (attrparent == NULL) ? "" : gettext("of attribute "),
1782 1804 (attrparent == NULL) ? "" : attrparent,
1783 1805 (attrparent == NULL) ? "" : gettext(" of "),
1784 1806 (filetype == XATTR_FILE) ? longname : parent);
1785 1807 goto out;
1786 1808 }
1787 1809
1788 1810 if (lev > MAXLEV) {
1789 1811 (void) fprintf(stderr,
1790 1812 gettext("tar: directory nesting too deep, %s not dumped\n"),
1791 1813 longname);
1792 1814 goto out;
1793 1815 }
1794 1816
1795 1817 if (getstat(dirfd, longname, shortname, attrparent))
1796 1818 goto out;
1797 1819
1798 1820 if (hflag) {
1799 1821 /*
1800 1822 * Catch nesting where a file is a symlink to its directory.
1801 1823 */
1802 1824 j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
1803 1825 if (S_ISLNK(sbuf.st_mode)) {
1804 1826 if (symlink_lev++ >= MAXSYMLINKS) {
1805 1827 (void) fprintf(stderr, gettext(
1806 1828 "tar: %s: Number of symbolic links "
1807 1829 "encountered during path name traversal "
1808 1830 "exceeds MAXSYMLINKS\n"), longname);
1809 1831 Errflg = 1;
1810 1832 goto out;
1811 1833 }
1812 1834 }
1813 1835 }
1814 1836
1815 1837 /*
1816 1838 * Check if the input file is the same as the tar file we
1817 1839 * are creating
1818 1840 */
1819 1841 if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
1820 1842 (void) fprintf(stderr, gettext(
1821 1843 "tar: %s%s%s%s%s same as archive file\n"),
1822 1844 rw_sysattr ? gettext("system ") : "",
1823 1845 (longattrname == NULL) ? "" : gettext("attribute "),
1824 1846 (longattrname == NULL) ? "" : longattrname,
1825 1847 (longattrname == NULL) ? "" : gettext(" of "),
1826 1848 longname);
1827 1849 Errflg = 1;
1828 1850 goto out;
1829 1851 }
1830 1852 /*
1831 1853 * Check size limit - we can't archive files that
1832 1854 * exceed TAR_OFFSET_MAX bytes because of header
1833 1855 * limitations. Exclude file types that set
1834 1856 * st_size to zero below because they take no
1835 1857 * archive space to represent contents.
1836 1858 */
1837 1859 if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
1838 1860 !S_ISDIR(stbuf.st_mode) &&
1839 1861 !S_ISCHR(stbuf.st_mode) &&
1840 1862 !S_ISBLK(stbuf.st_mode) &&
1841 1863 (Eflag == 0)) {
1842 1864 (void) fprintf(stderr, gettext(
1843 1865 "tar: %s%s%s%s%s too large to archive. "
1844 1866 "Use E function modifier.\n"),
1845 1867 rw_sysattr ? gettext("system ") : "",
1846 1868 (longattrname == NULL) ? "" : gettext("attribute "),
1847 1869 (longattrname == NULL) ? "" : longattrname,
1848 1870 (longattrname == NULL) ? "" : gettext(" of "),
1849 1871 longname);
1850 1872 if (errflag)
1851 1873 exitflag = 1;
1852 1874 Errflg = 1;
1853 1875 goto out;
1854 1876 }
1855 1877
1856 1878 if (tfile != NULL && checkupdate(longname) == 0) {
1857 1879 goto out;
1858 1880 }
1859 1881 if (checkw('r', longname) == 0) {
1860 1882 goto out;
1861 1883 }
1862 1884
1863 1885 if (Fflag &&
1864 1886 checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
1865 1887 goto out;
1866 1888
1867 1889 if (Xflag) {
1868 1890 if (is_in_table(exclude_tbl, longname)) {
1869 1891 if (vflag) {
1870 1892 (void) fprintf(vfile, gettext(
1871 1893 "a %s excluded\n"), longname);
1872 1894 }
1873 1895 goto out;
1874 1896 }
1875 1897 }
1876 1898
1877 1899 /*
1878 1900 * If the length of the fullname is greater than MAXNAM,
1879 1901 * print out a message and return (unless extended headers are used,
1880 1902 * in which case fullname is limited to PATH_MAX).
1881 1903 */
1882 1904
1883 1905 if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
1884 1906 (split > PATH_MAX)) {
1885 1907 (void) fprintf(stderr, gettext(
1886 1908 "tar: %s: file name too long\n"), longname);
1887 1909 if (errflag)
1888 1910 exitflag = 1;
1889 1911 Errflg = 1;
1890 1912 goto out;
1891 1913 }
1892 1914
1893 1915 /*
1894 1916 * We split the fullname into prefix and name components if any one
1895 1917 * of three conditions holds:
1896 1918 * -- the length of the fullname exceeds NAMSIZ,
1897 1919 * -- the length of the fullname equals NAMSIZ, and the shortname
1898 1920 * is less than NAMSIZ, (splitting in this case preserves
1899 1921 * compatibility with 5.6 and 5.5.1 tar), or
1900 1922 * -- the length of the fullname equals NAMSIZ, the file is a
1901 1923 * directory and we are not in POSIX-conformant mode (where
1902 1924 * trailing slashes are removed from directories).
1903 1925 */
1904 1926 if ((split > NAMSIZ) ||
1905 1927 (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1906 1928 (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
1907 1929 /*
1908 1930 * Since path is limited to PRESIZ characters, look for the
1909 1931 * last slash within PRESIZ + 1 characters only.
1910 1932 */
1911 1933 (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
1912 1934 tmpbuf = goodbuf;
1913 1935 lastslash = strrchr(tmpbuf, '/');
1914 1936 if (lastslash == NULL) {
1915 1937 i = split; /* Length of name */
1916 1938 j = 0; /* Length of prefix */
1917 1939 goodbuf[0] = '\0';
1918 1940 } else {
1919 1941 *lastslash = '\0'; /* Terminate the prefix */
1920 1942 j = strlen(tmpbuf);
1921 1943 i = split - j - 1;
1922 1944 }
1923 1945 /*
1924 1946 * If the filename is greater than NAMSIZ we can't
1925 1947 * archive the file unless we are using extended headers.
1926 1948 */
1927 1949 if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
1928 1950 !Pflag)) {
1929 1951 /* Determine which (filename or path) is too long. */
1930 1952 lastslash = strrchr(longname, '/');
1931 1953 if (lastslash != NULL)
1932 1954 i = strlen(lastslash + 1);
1933 1955 if (Eflag > 0) {
1934 1956 xhdr_flgs |= _X_PATH;
1935 1957 Xtarhdr.x_path = longname;
1936 1958 if (i <= NAMSIZ)
1937 1959 (void) strcpy(junkbuf, lastslash + 1);
1938 1960 else
1939 1961 (void) sprintf(junkbuf, "%llu",
1940 1962 xhdr_count + 1);
1941 1963 if (split - i - 1 > PRESIZ)
1942 1964 (void) strcpy(goodbuf, xhdr_dirname);
1943 1965 } else {
1944 1966 if ((i > NAMSIZ) || (i == NAMSIZ &&
1945 1967 S_ISDIR(stbuf.st_mode) && !Pflag))
1946 1968 (void) fprintf(stderr, gettext(
1947 1969 "tar: %s: filename is greater than "
1948 1970 "%d\n"), lastslash == NULL ?
1949 1971 longname : lastslash + 1, NAMSIZ);
1950 1972 else
1951 1973 (void) fprintf(stderr, gettext(
1952 1974 "tar: %s: prefix is greater than %d"
1953 1975 "\n"), longname, PRESIZ);
1954 1976 if (errflag)
1955 1977 exitflag = 1;
1956 1978 Errflg = 1;
1957 1979 goto out;
1958 1980 }
1959 1981 } else
1960 1982 (void) strncpy(&junkbuf[0], longname + j + 1,
1961 1983 strlen(longname + j + 1));
1962 1984 name = junkbuf;
1963 1985 prefix = goodbuf;
1964 1986 } else {
1965 1987 name = longname;
1966 1988 }
1967 1989 if (Aflag) {
1968 1990 if ((prefix != NULL) && (*prefix != '\0'))
1969 1991 while (*prefix == '/')
1970 1992 ++prefix;
1971 1993 else
1972 1994 while (*name == '/')
1973 1995 ++name;
1974 1996 }
1975 1997
1976 1998 switch (stbuf.st_mode & S_IFMT) {
1977 1999 case S_IFDIR:
1978 2000 stbuf.st_size = (off_t)0;
1979 2001 blocks = TBLOCKS(stbuf.st_size);
1980 2002
1981 2003 if (filetype != XATTR_FILE && Hiddendir == 0) {
1982 2004 i = 0;
1983 2005 cp = buf;
1984 2006 while ((*cp++ = longname[i++]))
1985 2007 ;
1986 2008 *--cp = '/';
1987 2009 *++cp = 0;
1988 2010 }
1989 2011 if (!oflag) {
1990 2012 tomodes(&stbuf);
1991 2013 if (build_dblock(name, tchar, '5', filetype,
1992 2014 &stbuf, stbuf.st_dev, prefix) != 0) {
1993 2015 goto out;
1994 2016 }
1995 2017 if (!Pflag) {
1996 2018 /*
1997 2019 * Old archives require a slash at the end
1998 2020 * of a directory name.
1999 2021 *
2000 2022 * XXX
2001 2023 * If directory name is too long, will
2002 2024 * slash overfill field?
2003 2025 */
2004 2026 if (strlen(name) > (unsigned)NAMSIZ-1) {
2005 2027 (void) fprintf(stderr, gettext(
2006 2028 "tar: %s: filename is greater "
2007 2029 "than %d\n"), name, NAMSIZ);
2008 2030 if (errflag)
2009 2031 exitflag = 1;
2010 2032 Errflg = 1;
2011 2033 goto out;
2012 2034 } else {
2013 2035 if (strlen(name) == (NAMSIZ - 1)) {
2014 2036 (void) memcpy(dblock.dbuf.name,
2015 2037 name, NAMSIZ);
2016 2038 dblock.dbuf.name[NAMSIZ-1]
2017 2039 = '/';
2018 2040 } else
2019 2041 (void) sprintf(dblock.dbuf.name,
2020 2042 "%s/", name);
2021 2043
2022 2044 /*
2023 2045 * need to recalculate checksum
2024 2046 * because the name changed.
2025 2047 */
2026 2048 (void) sprintf(dblock.dbuf.chksum,
2027 2049 "%07o", checksum(&dblock));
2028 2050 }
2029 2051 }
2030 2052
2031 2053 if (put_extra_attributes(longname, shortname,
2032 2054 longattrname, prefix, filetype, '5') != 0)
2033 2055 goto out;
2034 2056
2035 2057 #if defined(O_XATTR)
2036 2058 /*
2037 2059 * Reset header typeflag when archiving directory, since
2038 2060 * build_dblock changed it on us.
2039 2061 */
2040 2062 if (filetype == XATTR_FILE) {
2041 2063 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2042 2064 } else {
2043 2065 dblock.dbuf.typeflag = '5';
2044 2066 }
2045 2067 #else
2046 2068 dblock.dbuf.typeflag = '5';
2047 2069 #endif
2048 2070
2049 2071 (void) sprintf(dblock.dbuf.chksum, "%07o",
2050 2072 checksum(&dblock));
2051 2073
2052 2074 (void) writetbuf((char *)&dblock, 1);
2053 2075 }
2054 2076 if (vflag) {
2055 2077 #ifdef DEBUG
2056 2078 if (NotTape)
2057 2079 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2058 2080 0);
2059 2081 #endif
2060 2082 if (filetype == XATTR_FILE && Hiddendir) {
2061 2083 (void) fprintf(vfile,
2062 2084 gettext("a %s attribute %s "),
2063 2085 longname, longattrname);
2064 2086
2065 2087 } else {
2066 2088 (void) fprintf(vfile, "a %s/ ", longname);
2067 2089 }
2068 2090 if (NotTape)
2069 2091 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2070 2092 K(blocks));
2071 2093 else
2072 2094 (void) fprintf(vfile, gettext("%" FMT_blkcnt_t
2073 2095 " tape blocks\n"), blocks);
2074 2096 }
2075 2097
2076 2098 /*
2077 2099 * If hidden dir then break now since xattrs_put() will do
2078 2100 * the iterating of the directory.
2079 2101 *
2080 2102 * At the moment, there can only be system attributes on
2081 2103 * attributes. There can be no attributes on attributes or
2082 2104 * directories within the attributes hidden directory hierarchy.
2083 2105 */
2084 2106 if (filetype == XATTR_FILE)
2085 2107 break;
2086 2108
2087 2109 if (*shortname != '/')
2088 2110 (void) sprintf(newparent, "%s/%s", parent, shortname);
2089 2111 else
2090 2112 (void) sprintf(newparent, "%s", shortname);
2091 2113
2092 2114 if (tar_chdir(shortname) < 0) {
2093 2115 vperror(0, "%s", newparent);
2094 2116 goto out;
2095 2117 }
2096 2118
2097 2119 if ((dirp = opendir(".")) == NULL) {
2098 2120 vperror(0, gettext(
2099 2121 "can't open directory %s"), longname);
2100 2122 if (tar_chdir(parent) < 0)
2101 2123 vperror(0, gettext("cannot change back?: %s"),
2102 2124 parent);
2103 2125 goto out;
2104 2126 }
2105 2127
2106 2128 /*
2107 2129 * Create a list of files (children) in this directory to avoid
2108 2130 * having to perform telldir()/seekdir().
2109 2131 */
2110 2132 while ((dp = readdir(dirp)) != NULL && !term) {
2111 2133 if ((strcmp(".", dp->d_name) == 0) ||
2112 2134 (strcmp("..", dp->d_name) == 0))
2113 2135 continue;
2114 2136 if (((cptr = (file_list_t *)calloc(sizeof (char),
2115 2137 sizeof (file_list_t))) == NULL) ||
2116 2138 ((cptr->name = strdup(dp->d_name)) == NULL)) {
2117 2139 vperror(1, gettext(
2118 2140 "Insufficient memory for directory "
2119 2141 "list entry %s/%s\n"),
2120 2142 newparent, dp->d_name);
2121 2143 }
2122 2144
2123 2145 /* Add the file to the list */
2124 2146 if (child == NULL) {
2125 2147 child = cptr;
2126 2148 } else {
2127 2149 child_end->next = cptr;
2128 2150 }
2129 2151 child_end = cptr;
2130 2152 }
2131 2153 (void) closedir(dirp);
2132 2154
2133 2155 /*
2134 2156 * Archive each of the files in the current directory.
2135 2157 * If a file is a directory, putfile() is called
2136 2158 * recursively to archive the file hierarchy of the
2137 2159 * directory before archiving the next file in the
2138 2160 * current directory.
2139 2161 */
2140 2162 while ((child != NULL) && !term) {
2141 2163 (void) strcpy(cp, child->name);
2142 2164 archtype = putfile(buf, cp, newparent, NULL,
2143 2165 NORMAL_FILE, lev + 1, symlink_lev);
2144 2166
2145 2167 if (!exitflag) {
2146 2168 if ((atflag || saflag) &&
2147 2169 (archtype == PUT_NOTAS_LINK)) {
2148 2170 xattrs_put(buf, cp, newparent, NULL);
2149 2171 }
2150 2172 }
2151 2173 if (exitflag)
2152 2174 break;
2153 2175
2154 2176 /* Free each child as we are done processing it. */
2155 2177 cptr = child;
2156 2178 child = child->next;
2157 2179 free(cptr->name);
2158 2180 free(cptr);
2159 2181 }
2160 2182 if ((child != NULL) && !term) {
2161 2183 free_children(child);
2162 2184 }
2163 2185
2164 2186 if (tar_chdir(parent) < 0) {
2165 2187 vperror(0, gettext("cannot change back?: %s"), parent);
2166 2188 }
2167 2189
2168 2190 break;
2169 2191
2170 2192 case S_IFLNK:
2171 2193 readlink_max = NAMSIZ;
2172 2194 if (stbuf.st_size > NAMSIZ) {
2173 2195 if (Eflag > 0) {
2174 2196 xhdr_flgs |= _X_LINKPATH;
2175 2197 readlink_max = PATH_MAX;
2176 2198 } else {
2177 2199 (void) fprintf(stderr, gettext(
2178 2200 "tar: %s: symbolic link too long\n"),
2179 2201 longname);
2180 2202 if (errflag)
2181 2203 exitflag = 1;
2182 2204 Errflg = 1;
2183 2205 goto out;
2184 2206 }
2185 2207 }
2186 2208 /*
2187 2209 * Sym-links need header size of zero since you
2188 2210 * don't store any data for this type.
2189 2211 */
2190 2212 stbuf.st_size = (off_t)0;
2191 2213 tomodes(&stbuf);
2192 2214 i = readlink(shortname, filetmp, readlink_max);
2193 2215 if (i < 0) {
2194 2216 vperror(0, gettext(
2195 2217 "can't read symbolic link %s"), longname);
2196 2218 goto out;
2197 2219 } else {
2198 2220 filetmp[i] = 0;
2199 2221 }
2200 2222 if (vflag)
2201 2223 (void) fprintf(vfile, gettext(
2202 2224 "a %s symbolic link to %s\n"),
2203 2225 longname, filetmp);
2204 2226 if (xhdr_flgs & _X_LINKPATH) {
2205 2227 Xtarhdr.x_linkpath = filetmp;
2206 2228 if (build_dblock(name, tchar, '2', filetype, &stbuf,
2207 2229 stbuf.st_dev, prefix) != 0)
2208 2230 goto out;
2209 2231 } else
2210 2232 if (build_dblock(name, filetmp, '2', filetype, &stbuf,
2211 2233 stbuf.st_dev, prefix) != 0)
2212 2234 goto out;
2213 2235 (void) writetbuf((char *)&dblock, 1);
2214 2236 /*
2215 2237 * No acls for symlinks: mode is always 777
2216 2238 * dont call write ancillary
2217 2239 */
2218 2240 rc = PUT_AS_LINK;
2219 2241 break;
2220 2242 case S_IFREG:
2221 2243 if ((infile = openat(dirfd, shortname, 0)) < 0) {
2222 2244 vperror(0, gettext("unable to open %s%s%s%s"), longname,
2223 2245 rw_sysattr ? gettext(" system") : "",
2224 2246 (filetype == XATTR_FILE) ?
2225 2247 gettext(" attribute ") : "",
2226 2248 (filetype == XATTR_FILE) ? (longattrname == NULL) ?
2227 2249 shortname : longattrname : "");
2228 2250 goto out;
2229 2251 }
2230 2252
2231 2253 blocks = TBLOCKS(stbuf.st_size);
2232 2254
2233 2255 if (put_link(name, longname, shortname, longattrname,
2234 2256 prefix, filetype, '1') == 0) {
2235 2257 (void) close(infile);
2236 2258 rc = PUT_AS_LINK;
2237 2259 goto out;
2238 2260 }
2239 2261
2240 2262 tomodes(&stbuf);
2241 2263
2242 2264 /* correctly handle end of volume */
2243 2265 while (mulvol && tapepos + blocks + 1 > blocklim) {
2244 2266 /* split if floppy has some room and file is large */
2245 2267 if (((blocklim - tapepos) >= EXTMIN) &&
2246 2268 ((blocks + 1) >= blocklim/10)) {
2247 2269 splitfile(longname, infile,
2248 2270 name, prefix, filetype);
2249 2271 (void) close(dirfd);
2250 2272 (void) close(infile);
2251 2273 goto out;
2252 2274 }
2253 2275 newvol(); /* not worth it--just get new volume */
2254 2276 }
2255 2277 #ifdef DEBUG
2256 2278 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2257 2279 blocks);
2258 2280 #endif
2259 2281 if (build_dblock(name, tchar, '0', filetype,
2260 2282 &stbuf, stbuf.st_dev, prefix) != 0) {
2261 2283 goto out;
2262 2284 }
2263 2285 if (vflag) {
2264 2286 #ifdef DEBUG
2265 2287 if (NotTape)
2266 2288 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2267 2289 0);
2268 2290 #endif
2269 2291 (void) fprintf(vfile, "a %s%s%s%s ", longname,
2270 2292 rw_sysattr ? gettext(" system") : "",
2271 2293 (filetype == XATTR_FILE) ? gettext(
2272 2294 " attribute ") : "",
2273 2295 (filetype == XATTR_FILE) ?
2274 2296 longattrname : "");
2275 2297 if (NotTape)
2276 2298 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2277 2299 K(blocks));
2278 2300 else
2279 2301 (void) fprintf(vfile,
2280 2302 gettext("%" FMT_blkcnt_t " tape blocks\n"),
2281 2303 blocks);
2282 2304 }
2283 2305
2284 2306 if (put_extra_attributes(longname, shortname, longattrname,
2285 2307 prefix, filetype, '0') != 0)
2286 2308 goto out;
2287 2309
2288 2310 /*
2289 2311 * No need to reset typeflag for extended attribute here, since
2290 2312 * put_extra_attributes already set it and we haven't called
2291 2313 * build_dblock().
2292 2314 */
2293 2315 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2294 2316 hint = writetbuf((char *)&dblock, 1);
2295 2317 maxread = max(min(stbuf.st_blksize, stbuf.st_size),
2296 2318 (nblock * TBLOCK));
2297 2319 if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
2298 2320 maxread = TBLOCK;
2299 2321 bigbuf = buf;
2300 2322 }
2301 2323
2302 2324 while (((i = (int)
2303 2325 read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
2304 2326 blocks) {
2305 2327 blkcnt_t nblks;
2306 2328
2307 2329 nblks = ((i-1)/TBLOCK)+1;
2308 2330 if (nblks > blocks)
2309 2331 nblks = blocks;
2310 2332 hint = writetbuf(bigbuf, nblks);
2311 2333 blocks -= nblks;
2312 2334 }
2313 2335 (void) close(infile);
2314 2336 if (bigbuf != buf)
2315 2337 free(bigbuf);
2316 2338 if (i < 0)
2317 2339 vperror(0, gettext("Read error on %s"), longname);
2318 2340 else if (blocks != 0 || i != 0) {
2319 2341 (void) fprintf(stderr, gettext(
2320 2342 "tar: %s: file changed size\n"), longname);
2321 2343 if (errflag) {
2322 2344 exitflag = 1;
2323 2345 Errflg = 1;
2324 2346 } else if (!Dflag) {
2325 2347 Errflg = 1;
2326 2348 }
2327 2349 }
2328 2350 putempty(blocks);
2329 2351 break;
2330 2352 case S_IFIFO:
2331 2353 blocks = TBLOCKS(stbuf.st_size);
2332 2354 stbuf.st_size = (off_t)0;
2333 2355
2334 2356 if (put_link(name, longname, shortname, longattrname,
2335 2357 prefix, filetype, '6') == 0) {
2336 2358 rc = PUT_AS_LINK;
2337 2359 goto out;
2338 2360 }
2339 2361 tomodes(&stbuf);
2340 2362
2341 2363 while (mulvol && tapepos + blocks + 1 > blocklim) {
2342 2364 if (((blocklim - tapepos) >= EXTMIN) &&
2343 2365 ((blocks + 1) >= blocklim/10)) {
2344 2366 splitfile(longname, infile, name,
2345 2367 prefix, filetype);
2346 2368 (void) close(dirfd);
2347 2369 (void) close(infile);
2348 2370 goto out;
2349 2371 }
2350 2372 newvol();
2351 2373 }
2352 2374 #ifdef DEBUG
2353 2375 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2354 2376 blocks);
2355 2377 #endif
2356 2378 if (vflag) {
2357 2379 #ifdef DEBUG
2358 2380 if (NotTape)
2359 2381 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2360 2382 0);
2361 2383 #endif
2362 2384 if (NotTape)
2363 2385 (void) fprintf(vfile, gettext("a %s %"
2364 2386 FMT_blkcnt_t "K\n "), longname, K(blocks));
2365 2387 else
2366 2388 (void) fprintf(vfile, gettext(
2367 2389 "a %s %" FMT_blkcnt_t " tape blocks\n"),
2368 2390 longname, blocks);
2369 2391 }
2370 2392 if (build_dblock(name, tchar, '6', filetype,
2371 2393 &stbuf, stbuf.st_dev, prefix) != 0)
2372 2394 goto out;
2373 2395
2374 2396 if (put_extra_attributes(longname, shortname, longattrname,
2375 2397 prefix, filetype, '6') != 0)
2376 2398 goto out;
2377 2399
2378 2400 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2379 2401 dblock.dbuf.typeflag = '6';
2380 2402
2381 2403 (void) writetbuf((char *)&dblock, 1);
2382 2404 break;
2383 2405 case S_IFCHR:
2384 2406 stbuf.st_size = (off_t)0;
2385 2407 blocks = TBLOCKS(stbuf.st_size);
2386 2408 if (put_link(name, longname, shortname, longattrname,
2387 2409 prefix, filetype, '3') == 0) {
2388 2410 rc = PUT_AS_LINK;
2389 2411 goto out;
2390 2412 }
2391 2413 tomodes(&stbuf);
2392 2414
2393 2415 while (mulvol && tapepos + blocks + 1 > blocklim) {
2394 2416 if (((blocklim - tapepos) >= EXTMIN) &&
2395 2417 ((blocks + 1) >= blocklim/10)) {
2396 2418 splitfile(longname, infile, name,
2397 2419 prefix, filetype);
2398 2420 (void) close(dirfd);
2399 2421 goto out;
2400 2422 }
2401 2423 newvol();
2402 2424 }
2403 2425 #ifdef DEBUG
2404 2426 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2405 2427 blocks);
2406 2428 #endif
2407 2429 if (vflag) {
2408 2430 #ifdef DEBUG
2409 2431 if (NotTape)
2410 2432 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2411 2433 0);
2412 2434 #endif
2413 2435 if (NotTape)
2414 2436 (void) fprintf(vfile, gettext("a %s %"
2415 2437 FMT_blkcnt_t "K\n"), longname, K(blocks));
2416 2438 else
2417 2439 (void) fprintf(vfile, gettext("a %s %"
2418 2440 FMT_blkcnt_t " tape blocks\n"), longname,
2419 2441 blocks);
2420 2442 }
2421 2443 if (build_dblock(name, tchar, '3',
2422 2444 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2423 2445 goto out;
2424 2446
2425 2447 if (put_extra_attributes(longname, shortname, longattrname,
2426 2448 prefix, filetype, '3') != 0)
2427 2449 goto out;
2428 2450
2429 2451 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2430 2452 dblock.dbuf.typeflag = '3';
2431 2453
2432 2454 (void) writetbuf((char *)&dblock, 1);
2433 2455 break;
2434 2456 case S_IFBLK:
2435 2457 stbuf.st_size = (off_t)0;
2436 2458 blocks = TBLOCKS(stbuf.st_size);
2437 2459 if (put_link(name, longname, shortname, longattrname,
2438 2460 prefix, filetype, '4') == 0) {
2439 2461 rc = PUT_AS_LINK;
2440 2462 goto out;
2441 2463 }
2442 2464 tomodes(&stbuf);
2443 2465
2444 2466 while (mulvol && tapepos + blocks + 1 > blocklim) {
2445 2467 if (((blocklim - tapepos) >= EXTMIN) &&
2446 2468 ((blocks + 1) >= blocklim/10)) {
2447 2469 splitfile(longname, infile,
2448 2470 name, prefix, filetype);
2449 2471 (void) close(dirfd);
2450 2472 goto out;
2451 2473 }
2452 2474 newvol();
2453 2475 }
2454 2476 #ifdef DEBUG
2455 2477 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2456 2478 blocks);
2457 2479 #endif
2458 2480 if (vflag) {
2459 2481 #ifdef DEBUG
2460 2482 if (NotTape)
2461 2483 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2462 2484 0);
2463 2485 #endif
2464 2486 (void) fprintf(vfile, "a %s ", longname);
2465 2487 if (NotTape)
2466 2488 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2467 2489 K(blocks));
2468 2490 else
2469 2491 (void) fprintf(vfile, gettext("%"
2470 2492 FMT_blkcnt_t " tape blocks\n"), blocks);
2471 2493 }
2472 2494 if (build_dblock(name, tchar, '4',
2473 2495 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2474 2496 goto out;
2475 2497
2476 2498 if (put_extra_attributes(longname, shortname, longattrname,
2477 2499 prefix, filetype, '4') != 0)
2478 2500 goto out;
2479 2501
2480 2502 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2481 2503 dblock.dbuf.typeflag = '4';
2482 2504
2483 2505 (void) writetbuf((char *)&dblock, 1);
2484 2506 break;
2485 2507 default:
2486 2508 (void) fprintf(stderr, gettext(
2487 2509 "tar: %s is not a file. Not dumped\n"), longname);
2488 2510 if (errflag)
2489 2511 exitflag = 1;
2490 2512 Errflg = 1;
2491 2513 goto out;
2492 2514 }
2493 2515
2494 2516 out:
2495 2517 if ((dirfd != -1) && (filetype != XATTR_FILE)) {
2496 2518 (void) close(dirfd);
2497 2519 }
2498 2520 return (rc);
2499 2521 }
2500 2522
2501 2523
2502 2524 /*
2503 2525 * splitfile dump a large file across volumes
2504 2526 *
2505 2527 * splitfile(longname, fd);
2506 2528 * char *longname; full name of file
2507 2529 * int ifd; input file descriptor
2508 2530 *
2509 2531 * NOTE: only called by putfile() to dump a large file.
2510 2532 */
2511 2533
2512 2534 static void
2513 2535 splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
2514 2536 {
2515 2537 blkcnt_t blocks;
2516 2538 off_t bytes, s;
2517 2539 char buf[TBLOCK];
2518 2540 int i, extents;
2519 2541
2520 2542 blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */
2521 2543
2522 2544 /*
2523 2545 * # extents =
2524 2546 * size of file after using up rest of this floppy
2525 2547 * blocks - (blocklim - tapepos) + 1 (for header)
2526 2548 * plus roundup value before divide by blocklim-1
2527 2549 * + (blocklim - 1) - 1
2528 2550 * all divided by blocklim-1 (one block for each header).
2529 2551 * this gives
2530 2552 * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2531 2553 * which reduces to the expression used.
2532 2554 * one is added to account for this first extent.
2533 2555 *
2534 2556 * When one is dealing with extremely large archives, one may want
2535 2557 * to allow for a large number of extents. This code should be
2536 2558 * revisited to determine if extents should be changed to something
2537 2559 * larger than an int.
2538 2560 */
2539 2561 extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
2540 2562
2541 2563 if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */
2542 2564 (void) fprintf(stderr, gettext(
2543 2565 "tar: %s needs unusual number of volumes to split\n"
2544 2566 "tar: %s not dumped\n"), longname, longname);
2545 2567 return;
2546 2568 }
2547 2569 if (build_dblock(name, tchar, '0', filetype,
2548 2570 &stbuf, stbuf.st_dev, prefix) != 0)
2549 2571 return;
2550 2572
2551 2573 dblock.dbuf.extotal = extents;
2552 2574 bytes = stbuf.st_size;
2553 2575
2554 2576 /*
2555 2577 * The value contained in dblock.dbuf.efsize was formerly used when the
2556 2578 * v flag was specified in conjunction with the t flag. Although it is
2557 2579 * no longer used, older versions of tar will expect the former
2558 2580 * behaviour, so we must continue to write it to the archive.
2559 2581 *
2560 2582 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2561 2583 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2562 2584 * store 0.
2563 2585 */
2564 2586 if (bytes <= TAR_EFSIZE_MAX)
2565 2587 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
2566 2588 else
2567 2589 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
2568 2590
2569 2591 (void) fprintf(stderr, gettext(
2570 2592 "tar: large file %s needs %d extents.\n"
2571 2593 "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
2572 2594 longname, extents, K(tapepos));
2573 2595
2574 2596 s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
2575 2597 for (i = 1; i <= extents; i++) {
2576 2598 if (i > 1) {
2577 2599 newvol();
2578 2600 if (i == extents)
2579 2601 s = bytes; /* last ext. gets true bytes */
2580 2602 else
2581 2603 s = (off_t)(blocklim - 1)*TBLOCK; /* all */
2582 2604 }
2583 2605 bytes -= s;
2584 2606 blocks = TBLOCKS(s);
2585 2607
2586 2608 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
2587 2609 dblock.dbuf.extno = i;
2588 2610 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2589 2611 (void) writetbuf((char *)&dblock, 1);
2590 2612
2591 2613 if (vflag)
2592 2614 (void) fprintf(vfile,
2593 2615 gettext("+++ a %s %" FMT_blkcnt_t
2594 2616 "K [extent #%d of %d]\n"),
2595 2617 longname, K(blocks), i, extents);
2596 2618 while (blocks && read(ifd, buf, TBLOCK) > 0) {
2597 2619 blocks--;
2598 2620 (void) writetbuf(buf, 1);
2599 2621 }
2600 2622 if (blocks != 0) {
2601 2623 (void) fprintf(stderr, gettext(
2602 2624 "tar: %s: file changed size\n"), longname);
2603 2625 (void) fprintf(stderr, gettext(
2604 2626 "tar: aborting split file %s\n"), longname);
2605 2627 (void) close(ifd);
2606 2628 return;
2607 2629 }
2608 2630 }
2609 2631 (void) close(ifd);
2610 2632 if (vflag)
2611 2633 (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
2612 2634 "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
2613 2635 extents);
2614 2636 }
2615 2637
2616 2638 /*
2617 2639 * convtoreg - determines whether the file should be converted to a
2618 2640 * regular file when extracted
2619 2641 *
2620 2642 * Returns 1 when file size > 0 and typeflag is not recognized
2621 2643 * Otherwise returns 0
2622 2644 */
2623 2645 static int
2624 2646 convtoreg(off_t size)
2625 2647 {
2626 2648 if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
2627 2649 (dblock.dbuf.typeflag != NULL) && (dblock.dbuf.typeflag != '1') &&
2628 2650 (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
2629 2651 (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
2630 2652 (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
2631 2653 (dblock.dbuf.typeflag != 'L') &&
2632 2654 (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
2633 2655 (dblock.dbuf.typeflag != 'X')) {
2634 2656 return (1);
2635 2657 }
2636 2658 return (0);
2637 2659 }
2638 2660
2639 2661 #if defined(O_XATTR)
2640 2662 static int
2641 2663 save_cwd(void)
2642 2664 {
2643 2665 return (open(".", O_RDONLY));
2644 2666 }
2645 2667 #endif
2646 2668
2647 2669 #if defined(O_XATTR)
2648 2670 static void
2649 2671 rest_cwd(int *cwd)
2650 2672 {
2651 2673 if (*cwd != -1) {
2652 2674 if (fchdir(*cwd) < 0) {
2653 2675 vperror(0, gettext(
2654 2676 "Cannot fchdir to attribute directory"));
2655 2677 exit(1);
2656 2678 }
2657 2679 (void) close(*cwd);
2658 2680 *cwd = -1;
2659 2681 }
2660 2682 }
2661 2683 #endif
2662 2684
2663 2685 /*
2664 2686 * Verify the underlying file system supports the attribute type.
2665 2687 * Only archive extended attribute files when '-@' was specified.
2666 2688 * Only archive system extended attribute files if '-/' was specified.
2667 2689 */
2668 2690 #if defined(O_XATTR)
2669 2691 static attr_status_t
2670 2692 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
2671 2693 int *ext_attrflg)
2672 2694 {
2673 2695 /*
2674 2696 * Verify extended attributes are supported/exist. We only
2675 2697 * need to check if we are processing a base file, not an
2676 2698 * extended attribute.
2677 2699 */
2678 2700 if (attrflg) {
2679 2701 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
2680 2702 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
2681 2703 }
2682 2704
2683 2705 if (atflag) {
2684 2706 if (!*ext_attrflg) {
2685 2707 #if defined(_PC_SATTR_ENABLED)
2686 2708 if (saflag) {
2687 2709 /* Verify system attributes are supported */
2688 2710 if (sysattr_support(filename,
2689 2711 (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
2690 2712 _PC_SATTR_ENABLED) != 1) {
2691 2713 return (ATTR_SATTR_ERR);
2692 2714 }
2693 2715 } else
2694 2716 return (ATTR_XATTR_ERR);
2695 2717 #else
2696 2718 return (ATTR_XATTR_ERR);
2697 2719 #endif /* _PC_SATTR_ENABLED */
2698 2720 }
2699 2721
2700 2722 #if defined(_PC_SATTR_ENABLED)
2701 2723 } else if (saflag) {
2702 2724 /* Verify system attributes are supported */
2703 2725 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
2704 2726 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
2705 2727 return (ATTR_SATTR_ERR);
2706 2728 }
2707 2729 #endif /* _PC_SATTR_ENABLED */
2708 2730 } else {
2709 2731 return (ATTR_SKIP);
2710 2732 }
2711 2733
2712 2734 return (ATTR_OK);
2713 2735 }
2714 2736 #endif
2715 2737
2716 2738 #if defined(O_XATTR)
2717 2739 /*
2718 2740 * Recursively open attribute directories until the attribute directory
2719 2741 * containing the specified attribute, attrname, is opened.
2720 2742 *
2721 2743 * Currently, only 2 directory levels of attributes are supported, (i.e.,
2722 2744 * extended system attributes on extended attributes). The following are
2723 2745 * the possible input combinations:
2724 2746 * 1. Open the attribute directory of the base file (don't change
2725 2747 * into it).
2726 2748 * attrinfo->parent = NULL
2727 2749 * attrname = '.'
2728 2750 * 2. Open the attribute directory of the base file and change into it.
2729 2751 * attrinfo->parent = NULL
2730 2752 * attrname = <attr> | <sys_attr>
2731 2753 * 3. Open the attribute directory of the base file, change into it,
2732 2754 * then recursively call open_attr_dir() to open the attribute's
2733 2755 * parent directory (don't change into it).
2734 2756 * attrinfo->parent = <attr>
2735 2757 * attrname = '.'
2736 2758 * 4. Open the attribute directory of the base file, change into it,
2737 2759 * then recursively call open_attr_dir() to open the attribute's
2738 2760 * parent directory and change into it.
2739 2761 * attrinfo->parent = <attr>
2740 2762 * attrname = <attr> | <sys_attr>
2741 2763 *
2742 2764 * An attribute directory will be opened only if the underlying file system
2743 2765 * supports the attribute type, and if the command line specifications (atflag
2744 2766 * and saflag) enable the processing of the attribute type.
2745 2767 *
2746 2768 * On succesful return, attrinfo->parentfd will be the file descriptor of the
2747 2769 * opened attribute directory. In addition, if the attribute is a read-write
2748 2770 * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2749 2771 * it will be set to 0.
2750 2772 *
2751 2773 * Possible return values:
2752 2774 * ATTR_OK Successfully opened and, if needed, changed into the
2753 2775 * attribute directory containing attrname.
2754 2776 * ATTR_SKIP The command line specifications don't enable the
2755 2777 * processing of the attribute type.
2756 2778 * ATTR_CHDIR_ERR An error occurred while trying to change into an
2757 2779 * attribute directory.
2758 2780 * ATTR_OPEN_ERR An error occurred while trying to open an
2759 2781 * attribute directory.
2760 2782 * ATTR_XATTR_ERR The underlying file system doesn't support extended
2761 2783 * attributes.
2762 2784 * ATTR_SATTR_ERR The underlying file system doesn't support extended
2763 2785 * system attributes.
2764 2786 */
2765 2787 static int
2766 2788 open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
2767 2789 {
2768 2790 attr_status_t rc;
2769 2791 int firsttime = (attrinfo->attr_parentfd == -1);
2770 2792 int saveerrno;
2771 2793 int ext_attr;
2772 2794
2773 2795 /*
2774 2796 * open_attr_dir() was recursively called (input combination number 4),
2775 2797 * close the previously opened file descriptor as we've already changed
2776 2798 * into it.
2777 2799 */
2778 2800 if (!firsttime) {
2779 2801 (void) close(attrinfo->attr_parentfd);
2780 2802 attrinfo->attr_parentfd = -1;
2781 2803 }
2782 2804
2783 2805 /*
2784 2806 * Verify that the underlying file system supports the restoration
2785 2807 * of the attribute.
2786 2808 */
2787 2809 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
2788 2810 &ext_attr)) != ATTR_OK) {
2789 2811 return (rc);
2790 2812 }
2791 2813
2792 2814 /* Open the base file's attribute directory */
2793 2815 if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
2794 2816 /*
2795 2817 * Save the errno from the attropen so it can be reported
2796 2818 * if the retry of the attropen fails.
2797 2819 */
2798 2820 saveerrno = errno;
2799 2821 if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
2800 2822 NULL, ".", O_RDONLY, 0)) == -1) {
2801 2823 /*
2802 2824 * Reset typeflag back to real value so passtape
2803 2825 * will skip ahead correctly.
2804 2826 */
2805 2827 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2806 2828 (void) close(attrinfo->attr_parentfd);
2807 2829 attrinfo->attr_parentfd = -1;
2808 2830 errno = saveerrno;
2809 2831 return (ATTR_OPEN_ERR);
2810 2832 }
2811 2833 }
2812 2834
2813 2835 /*
2814 2836 * Change into the parent attribute's directory unless we are
2815 2837 * processing the hidden attribute directory of the base file itself.
2816 2838 */
2817 2839 if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
2818 2840 if (fchdir(attrinfo->attr_parentfd) != 0) {
2819 2841 saveerrno = errno;
2820 2842 (void) close(attrinfo->attr_parentfd);
2821 2843 attrinfo->attr_parentfd = -1;
2822 2844 errno = saveerrno;
2823 2845 return (ATTR_CHDIR_ERR);
2824 2846 }
2825 2847 }
2826 2848
2827 2849 /* Determine if the attribute should be processed */
2828 2850 if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
2829 2851 &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
2830 2852 saveerrno = errno;
2831 2853 (void) close(attrinfo->attr_parentfd);
2832 2854 attrinfo->attr_parentfd = -1;
2833 2855 errno = saveerrno;
2834 2856 return (rc);
2835 2857 }
2836 2858
2837 2859 /*
2838 2860 * If the attribute is an extended attribute, or extended system
2839 2861 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2840 2862 * recursively call open_attr_dir() to open the attribute directory
2841 2863 * of the parent attribute.
2842 2864 */
2843 2865 if (firsttime && (attrinfo->attr_parent != NULL)) {
2844 2866 return (open_attr_dir(attrname, attrinfo->attr_parent,
2845 2867 attrinfo->attr_parentfd, attrinfo));
2846 2868 }
2847 2869
2848 2870 return (ATTR_OK);
2849 2871 }
2850 2872 #endif
2851 2873
2852 2874 static void
2853 2875 doxtract(char *argv[])
2854 2876 {
2855 2877 struct stat xtractbuf; /* stat on file after extracting */
2856 2878 blkcnt_t blocks;
2857 2879 off_t bytes;
2858 2880 int ofile;
2859 2881 int newfile; /* Does the file already exist */
2860 2882 int xcnt = 0; /* count # files extracted */
2861 2883 int fcnt = 0; /* count # files in argv list */
2862 2884 int dir;
2863 2885 int dirfd = -1;
2864 2886 int cwd = -1;
2865 2887 int rw_sysattr;
2866 2888 int saveerrno;
2867 2889 uid_t Uid;
2868 2890 char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
2869 2891 char dirname[PATH_MAX+1];
2870 2892 char templink[PATH_MAX+1]; /* temp link with terminating NULL */
2871 2893 int once = 1;
2872 2894 int error;
2873 2895 int symflag;
2874 2896 int want;
2875 2897 attr_data_t *attrinfo = NULL; /* attribute info */
2876 2898 acl_t *aclp = NULL; /* acl info */
2877 2899 char dot[] = "."; /* dirp for using realpath */
2878 2900 timestruc_t time_zero; /* used for call to doDirTimes */
2879 2901 int dircreate;
2880 2902 int convflag;
2881 2903 time_zero.tv_sec = 0;
2882 2904 time_zero.tv_nsec = 0;
2883 2905
2884 2906 /* reset Trusted Extensions variables */
2885 2907 rpath_flag = 0;
2886 2908 lk_rpath_flag = 0;
2887 2909 dir_flag = 0;
2888 2910 mld_flag = 0;
2889 2911 bslundef(&bs_label);
2890 2912 bsllow(&admin_low);
2891 2913 bslhigh(&admin_high);
2892 2914 orig_namep = 0;
2893 2915
2894 2916 dumping = 0; /* for newvol(), et al: we are not writing */
2895 2917
2896 2918 Uid = getuid();
2897 2919
2898 2920 for (;;) {
2899 2921 convflag = 0;
2900 2922 symflag = 0;
2901 2923 dir = 0;
2902 2924 Hiddendir = 0;
2903 2925 rw_sysattr = 0;
2904 2926 ofile = -1;
2905 2927
2906 2928 if (dirfd != -1) {
2907 2929 (void) close(dirfd);
2908 2930 dirfd = -1;
2909 2931 }
2910 2932 if (ofile != -1) {
2911 2933 if (close(ofile) != 0)
2912 2934 vperror(2, gettext("close error"));
2913 2935 }
2914 2936
2915 2937 #if defined(O_XATTR)
2916 2938 if (cwd != -1) {
2917 2939 rest_cwd(&cwd);
2918 2940 }
2919 2941 #endif
2920 2942
2921 2943 /* namep is set by wantit to point to the full name */
2922 2944 if ((want = wantit(argv, &namep, &dirp, &comp,
2923 2945 &attrinfo)) == 0) {
2924 2946 #if defined(O_XATTR)
2925 2947 if (xattrp != NULL) {
2926 2948 free(xattrhead);
2927 2949 xattrp = NULL;
2928 2950 xattr_linkp = NULL;
2929 2951 xattrhead = NULL;
2930 2952 }
2931 2953 #endif
2932 2954 continue;
2933 2955 }
2934 2956 if (want == -1)
2935 2957 break;
2936 2958
2937 2959 /* Trusted Extensions */
2938 2960 /*
2939 2961 * During tar extract (x):
2940 2962 * If the pathname of the restored file has been
2941 2963 * reconstructed from the ancillary file,
2942 2964 * use it to process the normal file.
2943 2965 */
2944 2966 if (mld_flag) { /* Skip over .MLD. directory */
2945 2967 mld_flag = 0;
2946 2968 passtape();
2947 2969 continue;
2948 2970 }
2949 2971 orig_namep = namep; /* save original */
2950 2972 if (rpath_flag) {
2951 2973 namep = real_path; /* use zone path */
2952 2974 comp = real_path; /* use zone path */
2953 2975 dirp = dot; /* work from the top */
2954 2976 rpath_flag = 0; /* reset */
2955 2977 }
2956 2978
2957 2979 if (dirfd != -1)
2958 2980 (void) close(dirfd);
2959 2981
2960 2982 (void) strcpy(&dirname[0], namep);
2961 2983 dircreate = checkdir(&dirname[0]);
2962 2984
2963 2985 #if defined(O_XATTR)
2964 2986 if (xattrp != NULL) {
2965 2987 int rc;
2966 2988
2967 2989 if (((cwd = save_cwd()) == -1) ||
2968 2990 ((rc = open_attr_dir(comp, dirp, cwd,
2969 2991 attrinfo)) != ATTR_OK)) {
2970 2992 if (cwd == -1) {
2971 2993 vperror(0, gettext(
2972 2994 "unable to save current working "
2973 2995 "directory while processing "
2974 2996 "attribute %s of %s"),
2975 2997 dirp, attrinfo->attr_path);
2976 2998 } else if (rc != ATTR_SKIP) {
2977 2999 (void) fprintf(vfile,
2978 3000 gettext("tar: cannot open "
2979 3001 "%sattribute %s of file %s: %s\n"),
2980 3002 attrinfo->attr_rw_sysattr ? gettext(
2981 3003 "system ") : "",
2982 3004 comp, dirp, strerror(errno));
2983 3005 }
2984 3006 free(xattrhead);
2985 3007 xattrp = NULL;
2986 3008 xattr_linkp = NULL;
2987 3009 xattrhead = NULL;
2988 3010
2989 3011 passtape();
2990 3012 continue;
2991 3013 } else {
2992 3014 dirfd = attrinfo->attr_parentfd;
2993 3015 rw_sysattr = attrinfo->attr_rw_sysattr;
2994 3016 }
2995 3017 } else {
2996 3018 dirfd = open(dirp, O_RDONLY);
2997 3019 }
2998 3020 #else
2999 3021 dirfd = open(dirp, O_RDONLY);
3000 3022 #endif
3001 3023 if (dirfd == -1) {
3002 3024 (void) fprintf(vfile, gettext(
3003 3025 "tar: cannot open %s: %s\n"),
3004 3026 dirp, strerror(errno));
3005 3027 passtape();
3006 3028 continue;
3007 3029 }
3008 3030
3009 3031 if (xhdr_flgs & _X_LINKPATH)
3010 3032 (void) strcpy(templink, Xtarhdr.x_linkpath);
3011 3033 else {
3012 3034 #if defined(O_XATTR)
3013 3035 if (xattrp && dblock.dbuf.typeflag == '1') {
3014 3036 (void) sprintf(templink, "%.*s", NAMSIZ,
3015 3037 xattrp->h_names);
3016 3038 } else {
3017 3039 (void) sprintf(templink, "%.*s", NAMSIZ,
3018 3040 dblock.dbuf.linkname);
3019 3041 }
3020 3042 #else
3021 3043 (void) sprintf(templink, "%.*s", NAMSIZ,
3022 3044 dblock.dbuf.linkname);
3023 3045 #endif
3024 3046 }
3025 3047
3026 3048 if (Fflag) {
3027 3049 if (checkf(namep, is_directory(namep), Fflag) == 0) {
3028 3050 passtape();
3029 3051 continue;
3030 3052 }
3031 3053 }
3032 3054
3033 3055 if (checkw('x', namep) == 0) {
3034 3056 passtape();
3035 3057 continue;
3036 3058 }
3037 3059 if (once) {
3038 3060 if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
3039 3061 if (geteuid() == (uid_t)0) {
3040 3062 checkflag = 1;
3041 3063 pflag = 1;
3042 3064 } else {
3043 3065 /* get file creation mask */
3044 3066 Oumask = umask(0);
3045 3067 (void) umask(Oumask);
3046 3068 }
3047 3069 once = 0;
3048 3070 } else {
3049 3071 if (geteuid() == (uid_t)0) {
3050 3072 pflag = 1;
3051 3073 checkflag = 2;
3052 3074 }
3053 3075 if (!pflag) {
3054 3076 /* get file creation mask */
3055 3077 Oumask = umask(0);
3056 3078 (void) umask(Oumask);
3057 3079 }
3058 3080 once = 0;
3059 3081 }
3060 3082 }
3061 3083
3062 3084 #if defined(O_XATTR)
3063 3085 /*
3064 3086 * Handle extraction of hidden attr dir.
3065 3087 * Dir is automatically created, we only
3066 3088 * need to update mode and perm's.
3067 3089 */
3068 3090 if ((xattrp != NULL) && Hiddendir == 1) {
3069 3091 bytes = stbuf.st_size;
3070 3092 blocks = TBLOCKS(bytes);
3071 3093 if (vflag) {
3072 3094 (void) fprintf(vfile,
3073 3095 "x %s%s%s, %" FMT_off_t " %s, ", namep,
3074 3096 gettext(" attribute "),
3075 3097 xattrapath, bytes,
3076 3098 gettext("bytes"));
3077 3099 if (NotTape)
3078 3100 (void) fprintf(vfile,
3079 3101 "%" FMT_blkcnt_t "K\n", K(blocks));
3080 3102 else
3081 3103 (void) fprintf(vfile, gettext("%"
3082 3104 FMT_blkcnt_t " tape blocks\n"),
3083 3105 blocks);
3084 3106 }
3085 3107
3086 3108 /*
3087 3109 * Set the permissions and mode of the attribute
3088 3110 * unless the attribute is a system attribute (can't
3089 3111 * successfully do this) or the hidden attribute
3090 3112 * directory (".") of an attribute (when the attribute
3091 3113 * is restored, the hidden attribute directory of an
3092 3114 * attribute is transient). Note: when the permissions
3093 3115 * and mode are set for the hidden attribute directory
3094 3116 * of a file on a system supporting extended system
3095 3117 * attributes, even though it returns successfully, it
3096 3118 * will not have any affect since the attribute
3097 3119 * directory is transient.
3098 3120 */
3099 3121 if (attrinfo->attr_parent == NULL) {
3100 3122 if (fchownat(dirfd, ".", stbuf.st_uid,
3101 3123 stbuf.st_gid, 0) != 0) {
3102 3124 vperror(0, gettext(
3103 3125 "%s%s%s: failed to set ownership "
3104 3126 "of attribute directory"), namep,
3105 3127 gettext(" attribute "), xattrapath);
3106 3128 }
3107 3129
3108 3130 if (fchmod(dirfd, stbuf.st_mode) != 0) {
3109 3131 vperror(0, gettext(
3110 3132 "%s%s%s: failed to set permissions "
3111 3133 "of attribute directory"), namep,
3112 3134 gettext(" attribute "), xattrapath);
3113 3135 }
3114 3136 }
3115 3137 goto filedone;
3116 3138 }
3117 3139 #endif
3118 3140
3119 3141 if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
3120 3142 dir = 1;
3121 3143 if (vflag) {
3122 3144 (void) fprintf(vfile, "x %s, 0 %s, ",
3123 3145 &dirname[0], gettext("bytes"));
3124 3146 if (NotTape)
3125 3147 (void) fprintf(vfile, "0K\n");
3126 3148 else
3127 3149 (void) fprintf(vfile, gettext("%"
3128 3150 FMT_blkcnt_t " tape blocks\n"),
3129 3151 (blkcnt_t)0);
3130 3152 }
3131 3153 goto filedone;
3132 3154 }
3133 3155
3134 3156 if (dblock.dbuf.typeflag == '6') { /* FIFO */
3135 3157 if (rmdir(namep) < 0) {
3136 3158 if (errno == ENOTDIR)
3137 3159 (void) unlink(namep);
3138 3160 }
3139 3161 linkp = templink;
3140 3162 if (*linkp != NULL) {
3141 3163 if (Aflag && *linkp == '/')
3142 3164 linkp++;
3143 3165 if (link(linkp, namep) < 0) {
3144 3166 (void) fprintf(stderr, gettext(
3145 3167 "tar: %s: cannot link\n"), namep);
3146 3168 continue;
3147 3169 }
3148 3170 if (vflag)
3149 3171 (void) fprintf(vfile, gettext(
3150 3172 "x %s linked to %s\n"), namep,
3151 3173 linkp);
3152 3174 xcnt++; /* increment # files extracted */
3153 3175 continue;
3154 3176 }
3155 3177 if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
3156 3178 (int)Gen.g_devmajor) < 0) {
3157 3179 vperror(0, gettext("%s: mknod failed"), namep);
3158 3180 continue;
3159 3181 }
3160 3182 bytes = stbuf.st_size;
3161 3183 blocks = TBLOCKS(bytes);
3162 3184 if (vflag) {
3163 3185 (void) fprintf(vfile, "x %s, %" FMT_off_t
3164 3186 " %s, ", namep, bytes, gettext("bytes"));
3165 3187 if (NotTape)
3166 3188 (void) fprintf(vfile, "%" FMT_blkcnt_t
3167 3189 "K\n", K(blocks));
3168 3190 else
3169 3191 (void) fprintf(vfile, gettext("%"
3170 3192 FMT_blkcnt_t " tape blocks\n"),
3171 3193 blocks);
3172 3194 }
3173 3195 goto filedone;
3174 3196 }
3175 3197 if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
3176 3198 if (rmdir(namep) < 0) {
3177 3199 if (errno == ENOTDIR)
3178 3200 (void) unlink(namep);
3179 3201 }
3180 3202 linkp = templink;
3181 3203 if (*linkp != NULL) {
3182 3204 if (Aflag && *linkp == '/')
3183 3205 linkp++;
3184 3206 if (link(linkp, namep) < 0) {
3185 3207 (void) fprintf(stderr, gettext(
3186 3208 "tar: %s: cannot link\n"), namep);
3187 3209 continue;
3188 3210 }
3189 3211 if (vflag)
3190 3212 (void) fprintf(vfile, gettext(
3191 3213 "x %s linked to %s\n"), namep,
3192 3214 linkp);
3193 3215 xcnt++; /* increment # files extracted */
3194 3216 continue;
3195 3217 }
3196 3218 if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
3197 3219 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3198 3220 vperror(0, gettext(
3199 3221 "%s: mknod failed"), namep);
3200 3222 continue;
3201 3223 }
3202 3224 bytes = stbuf.st_size;
3203 3225 blocks = TBLOCKS(bytes);
3204 3226 if (vflag) {
3205 3227 (void) fprintf(vfile, "x %s, %" FMT_off_t
3206 3228 " %s, ", namep, bytes, gettext("bytes"));
3207 3229 if (NotTape)
3208 3230 (void) fprintf(vfile, "%" FMT_blkcnt_t
3209 3231 "K\n", K(blocks));
3210 3232 else
3211 3233 (void) fprintf(vfile, gettext("%"
3212 3234 FMT_blkcnt_t " tape blocks\n"),
3213 3235 blocks);
3214 3236 }
3215 3237 goto filedone;
3216 3238 } else if (dblock.dbuf.typeflag == '3' && Uid) {
3217 3239 (void) fprintf(stderr, gettext(
3218 3240 "Can't create special %s\n"), namep);
3219 3241 continue;
3220 3242 }
3221 3243
3222 3244 /* BLOCK SPECIAL */
3223 3245
3224 3246 if (dblock.dbuf.typeflag == '4' && !Uid) {
3225 3247 if (rmdir(namep) < 0) {
3226 3248 if (errno == ENOTDIR)
3227 3249 (void) unlink(namep);
3228 3250 }
3229 3251 linkp = templink;
3230 3252 if (*linkp != NULL) {
3231 3253 if (Aflag && *linkp == '/')
3232 3254 linkp++;
3233 3255 if (link(linkp, namep) < 0) {
3234 3256 (void) fprintf(stderr, gettext(
3235 3257 "tar: %s: cannot link\n"), namep);
3236 3258 continue;
3237 3259 }
3238 3260 if (vflag)
3239 3261 (void) fprintf(vfile, gettext(
3240 3262 "x %s linked to %s\n"), namep,
3241 3263 linkp);
3242 3264 xcnt++; /* increment # files extracted */
3243 3265 continue;
3244 3266 }
3245 3267 if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
3246 3268 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3247 3269 vperror(0, gettext("%s: mknod failed"), namep);
3248 3270 continue;
3249 3271 }
3250 3272 bytes = stbuf.st_size;
3251 3273 blocks = TBLOCKS(bytes);
3252 3274 if (vflag) {
3253 3275 (void) fprintf(vfile, gettext("x %s, %"
3254 3276 FMT_off_t " bytes, "), namep, bytes);
3255 3277 if (NotTape)
3256 3278 (void) fprintf(vfile, "%" FMT_blkcnt_t
3257 3279 "K\n", K(blocks));
3258 3280 else
3259 3281 (void) fprintf(vfile, gettext("%"
3260 3282 FMT_blkcnt_t " tape blocks\n"),
3261 3283 blocks);
3262 3284 }
3263 3285 goto filedone;
3264 3286 } else if (dblock.dbuf.typeflag == '4' && Uid) {
3265 3287 (void) fprintf(stderr,
3266 3288 gettext("Can't create special %s\n"), namep);
3267 3289 continue;
3268 3290 }
3269 3291 if (dblock.dbuf.typeflag == '2') { /* symlink */
3270 3292 if ((Tflag) && (lk_rpath_flag == 1))
3271 3293 linkp = lk_real_path;
3272 3294 else
3273 3295 linkp = templink;
3274 3296 if (Aflag && *linkp == '/')
3275 3297 linkp++;
3276 3298 if (rmdir(namep) < 0) {
3277 3299 if (errno == ENOTDIR)
3278 3300 (void) unlink(namep);
3279 3301 }
3280 3302 if (symlink(linkp, namep) < 0) {
3281 3303 vperror(0, gettext("%s: symbolic link failed"),
3282 3304 namep);
3283 3305 continue;
3284 3306 }
3285 3307 if (vflag)
3286 3308 (void) fprintf(vfile, gettext(
3287 3309 "x %s symbolic link to %s\n"),
3288 3310 namep, linkp);
3289 3311
3290 3312 symflag = AT_SYMLINK_NOFOLLOW;
3291 3313 goto filedone;
3292 3314 }
3293 3315 if (dblock.dbuf.typeflag == '1') {
3294 3316 linkp = templink;
3295 3317 if (Aflag && *linkp == '/')
3296 3318 linkp++;
3297 3319 if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
3298 3320 if (errno == ENOTDIR)
3299 3321 (void) unlinkat(dirfd, comp, 0);
3300 3322 }
3301 3323 #if defined(O_XATTR)
3302 3324 if (xattrp && xattr_linkp) {
3303 3325 if (fchdir(dirfd) < 0) {
3304 3326 vperror(0, gettext(
3305 3327 "Cannot fchdir to attribute "
3306 3328 "directory %s"),
3307 3329 (attrinfo->attr_parent == NULL) ?
3308 3330 dirp : attrinfo->attr_parent);
3309 3331 exit(1);
3310 3332 }
3311 3333
3312 3334 error = link(xattr_linkaname, xattrapath);
3313 3335 } else {
3314 3336 error = link(linkp, namep);
3315 3337 }
3316 3338 #else
3317 3339 error = link(linkp, namep);
3318 3340 #endif
3319 3341
3320 3342 if (error < 0) {
3321 3343 (void) fprintf(stderr, gettext(
3322 3344 "tar: %s%s%s: cannot link\n"),
3323 3345 namep, (xattr_linkp != NULL) ?
3324 3346 gettext(" attribute ") : "",
3325 3347 (xattr_linkp != NULL) ?
3326 3348 xattrapath : "");
3327 3349 continue;
3328 3350 }
3329 3351 if (vflag)
3330 3352 (void) fprintf(vfile, gettext(
3331 3353 "x %s%s%s linked to %s%s%s\n"), namep,
3332 3354 (xattr_linkp != NULL) ?
3333 3355 gettext(" attribute ") : "",
3334 3356 (xattr_linkp != NULL) ?
3335 3357 xattr_linkaname : "",
3336 3358 linkp,
3337 3359 (xattr_linkp != NULL) ?
3338 3360 gettext(" attribute ") : "",
3339 3361 (xattr_linkp != NULL) ? xattrapath : "");
3340 3362 xcnt++; /* increment # files extracted */
3341 3363 #if defined(O_XATTR)
3342 3364 if (xattrp != NULL) {
3343 3365 free(xattrhead);
3344 3366 xattrp = NULL;
3345 3367 xattr_linkp = NULL;
3346 3368 xattrhead = NULL;
3347 3369 }
3348 3370 #endif
3349 3371 continue;
3350 3372 }
3351 3373
3352 3374 /* REGULAR FILES */
3353 3375
3354 3376 if (convtoreg(stbuf.st_size)) {
3355 3377 convflag = 1;
3356 3378 if (errflag) {
3357 3379 (void) fprintf(stderr, gettext(
3358 3380 "tar: %s: typeflag '%c' not recognized\n"),
3359 3381 namep, dblock.dbuf.typeflag);
3360 3382 done(1);
3361 3383 } else {
3362 3384 (void) fprintf(stderr, gettext(
3363 3385 "tar: %s: typeflag '%c' not recognized, "
3364 3386 "converting to regular file\n"), namep,
3365 3387 dblock.dbuf.typeflag);
3366 3388 Errflg = 1;
3367 3389 }
3368 3390 }
3369 3391 if (dblock.dbuf.typeflag == '0' ||
3370 3392 dblock.dbuf.typeflag == NULL || convflag) {
3371 3393 delete_target(dirfd, comp, namep);
3372 3394 linkp = templink;
3373 3395 if (*linkp != NULL) {
3374 3396 if (Aflag && *linkp == '/')
3375 3397 linkp++;
3376 3398 if (link(linkp, comp) < 0) {
3377 3399 (void) fprintf(stderr, gettext(
3378 3400 "tar: %s: cannot link\n"), namep);
3379 3401 continue;
3380 3402 }
3381 3403 if (vflag)
3382 3404 (void) fprintf(vfile, gettext(
3383 3405 "x %s linked to %s\n"), comp,
3384 3406 linkp);
3385 3407 xcnt++; /* increment # files extracted */
3386 3408 #if defined(O_XATTR)
3387 3409 if (xattrp != NULL) {
3388 3410 free(xattrhead);
3389 3411 xattrp = NULL;
3390 3412 xattr_linkp = NULL;
3391 3413 xattrhead = NULL;
3392 3414 }
3393 3415 #endif
3394 3416 continue;
3395 3417 }
3396 3418 newfile = ((fstatat(dirfd, comp,
3397 3419 &xtractbuf, 0) == -1) ? TRUE : FALSE);
3398 3420 ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
3399 3421 stbuf.st_mode & MODEMASK);
3400 3422 saveerrno = errno;
3401 3423
3402 3424 #if defined(O_XATTR)
3403 3425 if (xattrp != NULL) {
3404 3426 if (ofile < 0) {
3405 3427 ofile = retry_open_attr(dirfd, cwd,
3406 3428 dirp, attrinfo->attr_parent, comp,
3407 3429 O_RDWR|O_CREAT|O_TRUNC,
3408 3430 stbuf.st_mode & MODEMASK);
3409 3431 }
3410 3432 }
3411 3433 #endif
3412 3434 if (ofile < 0) {
3413 3435 errno = saveerrno;
3414 3436 (void) fprintf(stderr, gettext(
3415 3437 "tar: %s%s%s%s - cannot create\n"),
3416 3438 (xattrp == NULL) ? "" : (rw_sysattr ?
3417 3439 gettext("system attribute ") :
3418 3440 gettext("attribute ")),
3419 3441 (xattrp == NULL) ? "" : xattrapath,
3420 3442 (xattrp == NULL) ? "" : gettext(" of "),
3421 3443 (xattrp == NULL) ? comp : namep);
3422 3444 if (errflag)
3423 3445 done(1);
3424 3446 else
3425 3447 Errflg = 1;
3426 3448 #if defined(O_XATTR)
3427 3449 if (xattrp != NULL) {
3428 3450 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
3429 3451 free(xattrhead);
3430 3452 xattrp = NULL;
3431 3453 xattr_linkp = NULL;
3432 3454 xattrhead = NULL;
3433 3455 }
3434 3456 #endif
3435 3457 passtape();
3436 3458 continue;
3437 3459 }
3438 3460
3439 3461 if (Tflag && (check_ext_attr(namep) == 0)) {
3440 3462 if (errflag)
3441 3463 done(1);
3442 3464 else
3443 3465 Errflg = 1;
3444 3466 passtape();
3445 3467 continue;
3446 3468 }
3447 3469
3448 3470 if (extno != 0) { /* file is in pieces */
3449 3471 if (extotal < 1 || extotal > MAXEXT)
3450 3472 (void) fprintf(stderr, gettext(
3451 3473 "tar: ignoring bad extent info for "
3452 3474 "%s%s%s%s\n"),
3453 3475 (xattrp == NULL) ? "" : (rw_sysattr ?
3454 3476 gettext("system attribute ") :
3455 3477 gettext("attribute ")),
3456 3478 (xattrp == NULL) ? "" : xattrapath,
3457 3479 (xattrp == NULL) ? "" : gettext(" of "),
3458 3480 (xattrp == NULL) ? comp : namep);
3459 3481 else {
3460 3482 /* extract it */
3461 3483 (void) xsfile(rw_sysattr, ofile);
3462 3484 }
3463 3485 }
3464 3486 extno = 0; /* let everyone know file is not split */
3465 3487 bytes = stbuf.st_size;
3466 3488 blocks = TBLOCKS(bytes);
3467 3489 if (vflag) {
3468 3490 (void) fprintf(vfile,
3469 3491 "x %s%s%s, %" FMT_off_t " %s, ",
3470 3492 (xattrp == NULL) ? "" : dirp,
3471 3493 (xattrp == NULL) ? "" : (rw_sysattr ?
3472 3494 gettext(" system attribute ") :
3473 3495 gettext(" attribute ")),
3474 3496 (xattrp == NULL) ? namep : xattrapath, bytes,
3475 3497 gettext("bytes"));
3476 3498 if (NotTape)
3477 3499 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
3478 3500 K(blocks));
3479 3501 else
3480 3502 (void) fprintf(vfile, gettext("%"
3481 3503 FMT_blkcnt_t " tape blocks\n"), blocks);
3482 3504 }
3483 3505
3484 3506 if (xblocks(rw_sysattr, bytes, ofile) != 0) {
3485 3507 #if defined(O_XATTR)
3486 3508 if (xattrp != NULL) {
3487 3509 free(xattrhead);
3488 3510 xattrp = NULL;
3489 3511 xattr_linkp = NULL;
3490 3512 xattrhead = NULL;
3491 3513 }
3492 3514 #endif
3493 3515 continue;
3494 3516 }
3495 3517 filedone:
3496 3518 if (mflag == 0 && !symflag) {
3497 3519 if (dir)
3498 3520 doDirTimes(namep, stbuf.st_mtim);
3499 3521
3500 3522 else
3501 3523 #if defined(O_XATTR)
3502 3524 if (xattrp != NULL) {
3503 3525 /*
3504 3526 * Set the time on the attribute unless
3505 3527 * the attribute is a system attribute
3506 3528 * (can't successfully do this) or the
3507 3529 * hidden attribute directory, "." (the
3508 3530 * time on the hidden attribute
3509 3531 * directory will be updated when
3510 3532 * attributes are restored, otherwise
3511 3533 * it's transient).
3512 3534 */
3513 3535 if (!rw_sysattr && (Hiddendir == 0)) {
3514 3536 setPathTimes(dirfd, comp,
3515 3537 stbuf.st_mtim);
3516 3538 }
3517 3539 } else
3518 3540 setPathTimes(dirfd, comp,
3519 3541 stbuf.st_mtim);
3520 3542 #else
3521 3543 setPathTimes(dirfd, comp, stbuf.st_mtim);
3522 3544 #endif
3523 3545 }
3524 3546
3525 3547 /* moved this code from above */
3526 3548 if (pflag && !symflag && Hiddendir == 0) {
3527 3549 if (xattrp != NULL)
3528 3550 (void) fchmod(ofile, stbuf.st_mode & MODEMASK);
3529 3551 else
3530 3552 (void) chmod(namep, stbuf.st_mode & MODEMASK);
3531 3553 }
3532 3554
3533 3555
3534 3556 /*
3535 3557 * Because ancillary file preceeds the normal file,
3536 3558 * acl info may have been retrieved (in aclp).
3537 3559 * All file types are directed here (go filedone).
3538 3560 * Always restore ACLs if there are ACLs.
3539 3561 */
3540 3562 if (aclp != NULL) {
3541 3563 int ret;
3542 3564
3543 3565 #if defined(O_XATTR)
3544 3566 if (xattrp != NULL) {
3545 3567 if (Hiddendir)
3546 3568 ret = facl_set(dirfd, aclp);
3547 3569 else
3548 3570 ret = facl_set(ofile, aclp);
3549 3571 } else {
3550 3572 ret = acl_set(namep, aclp);
3551 3573 }
3552 3574 #else
3553 3575 ret = acl_set(namep, aclp);
3554 3576 #endif
3555 3577 if (ret < 0) {
3556 3578 if (pflag) {
3557 3579 (void) fprintf(stderr, gettext(
3558 3580 "%s%s%s%s: failed to set acl "
3559 3581 "entries\n"), namep,
3560 3582 (xattrp == NULL) ? "" :
3561 3583 (rw_sysattr ? gettext(
3562 3584 " system attribute ") :
3563 3585 gettext(" attribute ")),
3564 3586 (xattrp == NULL) ? "" :
3565 3587 xattrapath);
3566 3588 }
3567 3589 /* else: silent and continue */
3568 3590 }
3569 3591 acl_free(aclp);
3570 3592 aclp = NULL;
3571 3593 }
3572 3594
3573 3595 if (!oflag)
3574 3596 /* set file ownership */
3575 3597 resugname(dirfd, comp, symflag);
3576 3598
3577 3599 if (pflag && newfile == TRUE && !dir &&
3578 3600 (dblock.dbuf.typeflag == '0' ||
3579 3601 dblock.dbuf.typeflag == NULL ||
3580 3602 convflag || dblock.dbuf.typeflag == '1')) {
3581 3603 if (fstat(ofile, &xtractbuf) == -1)
3582 3604 (void) fprintf(stderr, gettext(
3583 3605 "tar: cannot stat extracted file "
3584 3606 "%s%s%s%s\n"),
3585 3607 (xattrp == NULL) ? "" : (rw_sysattr ?
3586 3608 gettext("system attribute ") :
3587 3609 gettext("attribute ")),
3588 3610 (xattrp == NULL) ? "" : xattrapath,
3589 3611 (xattrp == NULL) ? "" :
3590 3612 gettext(" of "), namep);
3591 3613
3592 3614 else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
3593 3615 != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
3594 3616 (void) fprintf(stderr, gettext(
3595 3617 "tar: warning - file permissions have "
3596 3618 "changed for %s%s%s%s (are 0%o, should be "
3597 3619 "0%o)\n"),
3598 3620 (xattrp == NULL) ? "" : (rw_sysattr ?
3599 3621 gettext("system attribute ") :
3600 3622 gettext("attribute ")),
3601 3623 (xattrp == NULL) ? "" : xattrapath,
3602 3624 (xattrp == NULL) ? "" :
3603 3625 gettext(" of "), namep,
3604 3626 xtractbuf.st_mode, stbuf.st_mode);
3605 3627
3606 3628 }
3607 3629 }
3608 3630 #if defined(O_XATTR)
3609 3631 if (xattrp != NULL) {
3610 3632 free(xattrhead);
3611 3633 xattrp = NULL;
3612 3634 xattr_linkp = NULL;
3613 3635 xattrhead = NULL;
3614 3636 }
3615 3637 #endif
3616 3638
3617 3639 if (ofile != -1) {
3618 3640 (void) close(dirfd);
3619 3641 dirfd = -1;
3620 3642 if (close(ofile) != 0)
3621 3643 vperror(2, gettext("close error"));
3622 3644 ofile = -1;
3623 3645 }
3624 3646 xcnt++; /* increment # files extracted */
3625 3647 }
3626 3648
3627 3649 /*
3628 3650 * Process ancillary file.
3629 3651 *
3630 3652 */
3631 3653
3632 3654 if (dblock.dbuf.typeflag == 'A') { /* acl info */
3633 3655 char buf[TBLOCK];
3634 3656 char *secp;
3635 3657 char *tp;
3636 3658 int attrsize;
3637 3659 int cnt;
3638 3660
3639 3661 /* reset Trusted Extensions flags */
3640 3662 dir_flag = 0;
3641 3663 mld_flag = 0;
3642 3664 lk_rpath_flag = 0;
3643 3665 rpath_flag = 0;
3644 3666
3645 3667 if (pflag) {
3646 3668 bytes = stbuf.st_size;
3647 3669 if ((secp = malloc((int)bytes)) == NULL) {
3648 3670 (void) fprintf(stderr, gettext(
3649 3671 "Insufficient memory for acl\n"));
3650 3672 passtape();
3651 3673 continue;
3652 3674 }
3653 3675 tp = secp;
3654 3676 blocks = TBLOCKS(bytes);
3655 3677
3656 3678 /*
3657 3679 * Display a line for each ancillary file.
3658 3680 */
3659 3681 if (vflag && Tflag)
3660 3682 (void) fprintf(vfile, "x %s(A), %"
3661 3683 FMT_blkcnt_t " %s, %"
3662 3684 FMT_blkcnt_t " %s\n",
3663 3685 namep, bytes, gettext("bytes"),
3664 3686 blocks, gettext("tape blocks"));
3665 3687
3666 3688 while (blocks-- > 0) {
3667 3689 readtape(buf);
3668 3690 if (bytes <= TBLOCK) {
3669 3691 (void) memcpy(tp, buf,
3670 3692 (size_t)bytes);
3671 3693 break;
3672 3694 } else {
3673 3695 (void) memcpy(tp, buf,
3674 3696 TBLOCK);
3675 3697 tp += TBLOCK;
3676 3698 }
3677 3699 bytes -= TBLOCK;
3678 3700 }
3679 3701 bytes = stbuf.st_size;
3680 3702 /* got all attributes in secp */
3681 3703 tp = secp;
3682 3704 do {
3683 3705 attr = (struct sec_attr *)tp;
3684 3706 switch (attr->attr_type) {
3685 3707 case UFSD_ACL:
3686 3708 case ACE_ACL:
3687 3709 (void) sscanf(attr->attr_len,
3688 3710 "%7o",
3689 3711 (uint_t *)
3690 3712 &cnt);
3691 3713 /* header is 8 */
3692 3714 attrsize = 8 + (int)strlen(
3693 3715 &attr->attr_info[0]) + 1;
3694 3716 error =
3695 3717 acl_fromtext(
3696 3718 &attr->attr_info[0], &aclp);
3697 3719
3698 3720 if (error != 0) {
3699 3721 (void) fprintf(stderr,
3700 3722 gettext(
3701 3723 "aclfromtext "
3702 3724 "failed: %s\n"),
3703 3725 acl_strerror(
3704 3726 error));
3705 3727 bytes -= attrsize;
3706 3728 break;
3707 3729 }
3708 3730 if (acl_cnt(aclp) != cnt) {
3709 3731 (void) fprintf(stderr,
3710 3732 gettext(
3711 3733 "aclcnt error\n"));
3712 3734 bytes -= attrsize;
3713 3735 break;
3714 3736 }
3715 3737 bytes -= attrsize;
3716 3738 break;
3717 3739
3718 3740 /* Trusted Extensions */
3719 3741
3720 3742 case DIR_TYPE:
3721 3743 case LBL_TYPE:
3722 3744 case APRIV_TYPE:
3723 3745 case FPRIV_TYPE:
3724 3746 case COMP_TYPE:
3725 3747 case LK_COMP_TYPE:
3726 3748 case ATTR_FLAG_TYPE:
3727 3749 attrsize =
3728 3750 sizeof (struct sec_attr) +
3729 3751 strlen(&attr->attr_info[0]);
3730 3752 bytes -= attrsize;
3731 3753 if (Tflag)
3732 3754 extract_attr(&namep,
3733 3755 attr);
3734 3756 break;
3735 3757
3736 3758 default:
3737 3759 (void) fprintf(stderr, gettext(
3738 3760 "unrecognized attr"
3739 3761 " type\n"));
3740 3762 bytes = (off_t)0;
3741 3763 break;
3742 3764 }
3743 3765
3744 3766 /* next attributes */
3745 3767 tp += attrsize;
3746 3768 } while (bytes != 0);
3747 3769 free(secp);
3748 3770 } else {
3749 3771 passtape();
3750 3772 }
3751 3773 } /* acl */
3752 3774
3753 3775 } /* for */
3754 3776
3755 3777 /*
3756 3778 * Ensure that all the directories still on the directory stack
3757 3779 * get their modification times set correctly by flushing the
3758 3780 * stack.
3759 3781 */
3760 3782
3761 3783 doDirTimes(NULL, time_zero);
3762 3784
3763 3785 #if defined(O_XATTR)
3764 3786 if (xattrp != NULL) {
3765 3787 free(xattrhead);
3766 3788 xattrp = NULL;
3767 3789 xattr_linkp = NULL;
3768 3790 xattrhead = NULL;
3769 3791 }
3770 3792 #endif
3771 3793
3772 3794 /*
3773 3795 * Check if the number of files extracted is different from the
3774 3796 * number of files listed on the command line
3775 3797 */
3776 3798 if (fcnt > xcnt) {
3777 3799 (void) fprintf(stderr,
3778 3800 gettext("tar: %d file(s) not extracted\n"),
3779 3801 fcnt-xcnt);
3780 3802 Errflg = 1;
3781 3803 }
3782 3804 }
3783 3805
3784 3806 /*
3785 3807 * xblocks extract file/extent from tape to output file
3786 3808 *
3787 3809 * xblocks(issysattr, bytes, ofile);
3788 3810 *
3789 3811 * issysattr flag set if the files being extracted
3790 3812 * is an extended system attribute file.
3791 3813 * unsigned long long bytes size of extent or file to be extracted
3792 3814 * ofile output file
3793 3815 *
3794 3816 * called by doxtract() and xsfile()
3795 3817 */
3796 3818
3797 3819 static int
3798 3820 xblocks(int issysattr, off_t bytes, int ofile)
3799 3821 {
3800 3822 char *buf;
3801 3823 char tempname[NAMSIZ+1];
3802 3824 size_t maxwrite;
3803 3825 size_t bytesread;
3804 3826 size_t piosize; /* preferred I/O size */
3805 3827 struct stat tsbuf;
3806 3828
3807 3829 /* Don't need to do anything if this is a zero size file */
3808 3830 if (bytes <= 0) {
3809 3831 return (0);
3810 3832 }
3811 3833
3812 3834 /*
3813 3835 * To figure out the size of the buffer used to accumulate data
3814 3836 * from readtape() and to write to the file, we need to determine
3815 3837 * the largest chunk of data to be written to the file at one time.
3816 3838 * This is determined based on the smallest of the following two
3817 3839 * things:
3818 3840 * 1) The size of the archived file.
3819 3841 * 2) The preferred I/O size of the file.
3820 3842 */
3821 3843 if (issysattr || (bytes <= TBLOCK)) {
3822 3844 /*
3823 3845 * Writes to system attribute files must be
3824 3846 * performed in one operation.
3825 3847 */
3826 3848 maxwrite = bytes;
3827 3849 } else {
3828 3850 /*
3829 3851 * fstat() the file to get the preferred I/O size.
3830 3852 * If it fails, then resort back to just writing
3831 3853 * one block at a time.
3832 3854 */
3833 3855 if (fstat(ofile, &tsbuf) == 0) {
3834 3856 piosize = tsbuf.st_blksize;
3835 3857 } else {
3836 3858 piosize = TBLOCK;
3837 3859 }
3838 3860 maxwrite = min(bytes, piosize);
3839 3861 }
3840 3862
3841 3863 /*
3842 3864 * The buffer used to accumulate the data for the write operation
3843 3865 * needs to be the maximum number of bytes to be written rounded up
3844 3866 * to the nearest TBLOCK since readtape reads one block at a time.
3845 3867 */
3846 3868 if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
3847 3869 fatal(gettext("cannot allocate buffer"));
3848 3870 }
3849 3871
3850 3872 while (bytes > 0) {
3851 3873
3852 3874 /*
3853 3875 * readtape() obtains one block (TBLOCK) of data at a time.
3854 3876 * Accumulate as many blocks of data in buf as we can write
3855 3877 * in one operation.
3856 3878 */
3857 3879 for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
3858 3880 readtape(buf + bytesread);
3859 3881 }
3860 3882
3861 3883 if (write(ofile, buf, maxwrite) < 0) {
3862 3884 int saveerrno = errno;
3863 3885
3864 3886 if (xhdr_flgs & _X_PATH)
3865 3887 (void) strlcpy(tempname, Xtarhdr.x_path,
3866 3888 sizeof (tempname));
3867 3889 else
3868 3890 (void) sprintf(tempname, "%.*s", NAMSIZ,
3869 3891 dblock.dbuf.name);
3870 3892 /*
3871 3893 * If the extended system attribute being extracted
3872 3894 * contains attributes that the user needs privileges
3873 3895 * for, then just display a warning message, skip
3874 3896 * the extraction of this file, and return.
3875 3897 */
3876 3898 if ((saveerrno == EPERM) && issysattr) {
3877 3899 (void) fprintf(stderr, gettext(
3878 3900 "tar: unable to extract system attribute "
3879 3901 "%s: insufficient privileges\n"), tempname);
3880 3902 Errflg = 1;
3881 3903 (void) free(buf);
3882 3904 return (1);
3883 3905 } else {
3884 3906 (void) fprintf(stderr, gettext(
3885 3907 "tar: %s: HELP - extract write error\n"),
3886 3908 tempname);
3887 3909 done(2);
3888 3910 }
3889 3911 }
3890 3912 bytes -= maxwrite;
3891 3913
3892 3914 /*
3893 3915 * If we've reached this point and there is still data
3894 3916 * to be written, maxwrite had to have been determined
3895 3917 * by the preferred I/O size. If the number of bytes
3896 3918 * left to write is smaller than the preferred I/O size,
3897 3919 * then we're about to do our final write to the file, so
3898 3920 * just set maxwrite to the number of bytes left to write.
3899 3921 */
3900 3922 if ((bytes > 0) && (bytes < maxwrite)) {
3901 3923 maxwrite = bytes;
3902 3924 }
3903 3925 }
3904 3926 free(buf);
3905 3927
3906 3928 return (0);
3907 3929 }
3908 3930
3909 3931 /*
3910 3932 * xsfile extract split file
3911 3933 *
3912 3934 * xsfile(ofd); ofd = output file descriptor
3913 3935 *
3914 3936 * file extracted and put in ofd via xblocks()
3915 3937 *
3916 3938 * NOTE: only called by doxtract() to extract one large file
3917 3939 */
3918 3940
3919 3941 static union hblock savedblock; /* to ensure same file across volumes */
3920 3942
3921 3943 static int
3922 3944 xsfile(int issysattr, int ofd)
3923 3945 {
3924 3946 int i, c;
3925 3947 int sysattrerr = 0;
3926 3948 char name[PATH_MAX+1]; /* holds name for diagnostics */
3927 3949 int extents, totalext;
3928 3950 off_t bytes, totalbytes;
3929 3951
3930 3952 if (xhdr_flgs & _X_PATH)
3931 3953 (void) strcpy(name, Xtarhdr.x_path);
3932 3954 else
3933 3955 (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
3934 3956
3935 3957 totalbytes = (off_t)0; /* in case we read in half the file */
3936 3958 totalext = 0; /* these keep count */
3937 3959
3938 3960 (void) fprintf(stderr, gettext(
3939 3961 "tar: %s split across %d volumes\n"), name, extotal);
3940 3962
3941 3963 /* make sure we do extractions in order */
3942 3964 if (extno != 1) { /* starting in middle of file? */
3943 3965 (void) printf(gettext(
3944 3966 "tar: first extent read is not #1\n"
3945 3967 "OK to read file beginning with extent #%d (%s/%s) ? "),
3946 3968 extno, yesstr, nostr);
3947 3969 if (yes() == 0) {
3948 3970 canit:
3949 3971 passtape();
3950 3972 if (close(ofd) != 0)
3951 3973 vperror(2, gettext("close error"));
3952 3974 if (sysattrerr) {
3953 3975 return (1);
3954 3976 } else {
3955 3977 return (0);
3956 3978 }
3957 3979 }
3958 3980 }
3959 3981 extents = extotal;
3960 3982 i = extno;
3961 3983 /*CONSTCOND*/
3962 3984 while (1) {
3963 3985 if (xhdr_flgs & _X_SIZE) {
3964 3986 bytes = extsize;
3965 3987 } else {
3966 3988 bytes = stbuf.st_size;
3967 3989 }
3968 3990
3969 3991 if (vflag)
3970 3992 (void) fprintf(vfile, "+++ x %s [%s #%d], %"
3971 3993 FMT_off_t " %s, %ldK\n",
3972 3994 name, gettext("extent"), extno,
3973 3995 bytes, gettext("bytes"),
3974 3996 (long)K(TBLOCKS(bytes)));
3975 3997 if (xblocks(issysattr, bytes, ofd) != 0) {
3976 3998 sysattrerr = 1;
3977 3999 goto canit;
3978 4000 }
3979 4001
3980 4002 totalbytes += bytes;
3981 4003 totalext++;
3982 4004 if (++i > extents)
3983 4005 break;
3984 4006
3985 4007 /* get next volume and verify it's the right one */
3986 4008 copy(&savedblock, &dblock);
3987 4009 tryagain:
3988 4010 newvol();
3989 4011 xhdr_flgs = 0;
3990 4012 getdir();
3991 4013 if (Xhdrflag > 0)
3992 4014 (void) get_xdata(); /* Get x-header & regular hdr */
3993 4015 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
3994 4016 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
3995 4017 xhdr_flgs |= _X_XHDR;
3996 4018 }
3997 4019 if (endtape()) { /* seemingly empty volume */
3998 4020 (void) fprintf(stderr, gettext(
3999 4021 "tar: first record is null\n"));
4000 4022 asknicely:
4001 4023 (void) fprintf(stderr, gettext(
4002 4024 "tar: need volume with extent #%d of %s\n"),
4003 4025 i, name);
4004 4026 goto tryagain;
4005 4027 }
4006 4028 if (notsame()) {
4007 4029 (void) fprintf(stderr, gettext(
4008 4030 "tar: first file on that volume is not "
4009 4031 "the same file\n"));
4010 4032 goto asknicely;
4011 4033 }
4012 4034 if (i != extno) {
4013 4035 (void) fprintf(stderr, gettext(
4014 4036 "tar: extent #%d received out of order\ntar: "
4015 4037 "should be #%d\n"), extno, i);
4016 4038 (void) fprintf(stderr, gettext(
4017 4039 "Ignore error, Abort this file, or "
4018 4040 "load New volume (i/a/n) ? "));
4019 4041 c = response();
4020 4042 if (c == 'a')
4021 4043 goto canit;
4022 4044 if (c != 'i') /* default to new volume */
4023 4045 goto asknicely;
4024 4046 i = extno; /* okay, start from there */
4025 4047 }
4026 4048 }
4027 4049 if (vflag)
4028 4050 (void) fprintf(vfile, gettext(
4029 4051 "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
4030 4052 name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
4031 4053
4032 4054 return (0);
4033 4055 }
4034 4056
4035 4057
4036 4058 /*
4037 4059 * notsame() check if extract file extent is invalid
4038 4060 *
4039 4061 * returns true if anything differs between savedblock and dblock
4040 4062 * except extno (extent number), checksum, or size (extent size).
4041 4063 * Determines if this header belongs to the same file as the one we're
4042 4064 * extracting.
4043 4065 *
4044 4066 * NOTE: though rather bulky, it is only called once per file
4045 4067 * extension, and it can withstand changes in the definition
4046 4068 * of the header structure.
4047 4069 *
4048 4070 * WARNING: this routine is local to xsfile() above
4049 4071 */
4050 4072
4051 4073 static int
4052 4074 notsame(void)
4053 4075 {
4054 4076 return (
4055 4077 (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
4056 4078 (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
4057 4079 (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
4058 4080 (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
4059 4081 (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
4060 4082 (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
4061 4083 (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
4062 4084 (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
4063 4085 (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
4064 4086 }
4065 4087
4066 4088 static void
4067 4089 dotable(char *argv[])
4068 4090 {
4069 4091 int tcnt = 0; /* count # files tabled */
4070 4092 int fcnt = 0; /* count # files in argv list */
4071 4093 char *namep, *dirp, *comp;
4072 4094 int want;
4073 4095 char aclchar = ' '; /* either blank or '+' */
4074 4096 char templink[PATH_MAX+1];
4075 4097 attr_data_t *attrinfo = NULL;
4076 4098
4077 4099 dumping = 0;
4078 4100
4079 4101 /* if not on magtape, maximize seek speed */
4080 4102 if (NotTape && !bflag) {
4081 4103 #if SYS_BLOCK > TBLOCK
4082 4104 nblock = SYS_BLOCK / TBLOCK;
4083 4105 #else
4084 4106 nblock = 1;
4085 4107 #endif
4086 4108 }
4087 4109
4088 4110 for (;;) {
4089 4111
4090 4112 /* namep is set by wantit to point to the full name */
4091 4113 if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
4092 4114 continue;
4093 4115 if (want == -1)
4094 4116 break;
4095 4117 if (dblock.dbuf.typeflag != 'A')
4096 4118 ++tcnt;
4097 4119
4098 4120 if (Fflag) {
4099 4121 if (checkf(namep, is_directory(namep), Fflag) == 0) {
4100 4122 passtape();
4101 4123 continue;
4102 4124 }
4103 4125 }
4104 4126 /*
4105 4127 * ACL support:
4106 4128 * aclchar is introduced to indicate if there are
4107 4129 * acl entries. longt() now takes one extra argument.
4108 4130 */
4109 4131 if (vflag) {
4110 4132 if (dblock.dbuf.typeflag == 'A') {
4111 4133 aclchar = '+';
4112 4134 passtape();
4113 4135 continue;
4114 4136 }
4115 4137 longt(&stbuf, aclchar);
4116 4138 aclchar = ' ';
4117 4139 }
4118 4140
4119 4141
4120 4142 #if defined(O_XATTR)
4121 4143 if (xattrp != NULL) {
4122 4144 int issysattr;
4123 4145 char *bn = basename(attrinfo->attr_path);
4124 4146
4125 4147 /*
4126 4148 * We could use sysattr_type() to test whether or not
4127 4149 * the attribute we are processing is really an
4128 4150 * extended system attribute, which as of this writing
4129 4151 * just does a strcmp(), however, sysattr_type() may
4130 4152 * be changed to issue a pathconf() call instead, which
4131 4153 * would require being changed into the parent attribute
4132 4154 * directory. So instead, just do simple string
4133 4155 * comparisons to see if we are processing an extended
4134 4156 * system attribute.
4135 4157 */
4136 4158 issysattr = is_sysattr(bn);
4137 4159
4138 4160 (void) printf(gettext("%s %sattribute %s"),
4139 4161 xattrp->h_names,
4140 4162 issysattr ? gettext("system ") : "",
4141 4163 attrinfo->attr_path);
4142 4164 } else {
4143 4165 (void) printf("%s", namep);
4144 4166 }
4145 4167 #else
4146 4168 (void) printf("%s", namep);
4147 4169 #endif
4148 4170
4149 4171 if (extno != 0) {
4150 4172 if (vflag) {
4151 4173 /* keep the '\n' for backwards compatibility */
4152 4174 (void) fprintf(vfile, gettext(
4153 4175 "\n [extent #%d of %d]"), extno, extotal);
4154 4176 } else {
4155 4177 (void) fprintf(vfile, gettext(
4156 4178 " [extent #%d of %d]"), extno, extotal);
4157 4179 }
4158 4180 }
4159 4181 if (xhdr_flgs & _X_LINKPATH) {
4160 4182 (void) strcpy(templink, Xtarhdr.x_linkpath);
4161 4183 } else {
4162 4184 #if defined(O_XATTR)
4163 4185 if (xattrp != NULL) {
4164 4186 (void) sprintf(templink,
4165 4187 "file %.*s", NAMSIZ, xattrp->h_names);
4166 4188 } else {
4167 4189 (void) sprintf(templink, "%.*s", NAMSIZ,
4168 4190 dblock.dbuf.linkname);
4169 4191 }
4170 4192 #else
4171 4193 (void) sprintf(templink, "%.*s", NAMSIZ,
4172 4194 dblock.dbuf.linkname);
4173 4195 #endif
4174 4196 templink[NAMSIZ] = '\0';
4175 4197 }
4176 4198 if (dblock.dbuf.typeflag == '1') {
4177 4199 /*
4178 4200 * TRANSLATION_NOTE
4179 4201 * Subject is omitted here.
4180 4202 * Translate this as if
4181 4203 * <subject> linked to %s
4182 4204 */
4183 4205 #if defined(O_XATTR)
4184 4206 if (xattrp != NULL) {
4185 4207 (void) printf(
4186 4208 gettext(" linked to attribute %s"),
4187 4209 xattr_linkp->h_names +
4188 4210 strlen(xattr_linkp->h_names) + 1);
4189 4211 } else {
4190 4212 (void) printf(
4191 4213 gettext(" linked to %s"), templink);
4192 4214 }
4193 4215 #else
4194 4216 (void) printf(
4195 4217 gettext(" linked to %s"), templink);
4196 4218
4197 4219 #endif
4198 4220 }
4199 4221 if (dblock.dbuf.typeflag == '2')
4200 4222 (void) printf(gettext(
4201 4223 /*
4202 4224 * TRANSLATION_NOTE
4203 4225 * Subject is omitted here.
4204 4226 * Translate this as if
4205 4227 * <subject> symbolic link to %s
4206 4228 */
4207 4229 " symbolic link to %s"), templink);
4208 4230 (void) printf("\n");
4209 4231 #if defined(O_XATTR)
4210 4232 if (xattrp != NULL) {
4211 4233 free(xattrhead);
4212 4234 xattrp = NULL;
4213 4235 xattrhead = NULL;
4214 4236 }
4215 4237 #endif
4216 4238 passtape();
4217 4239 }
4218 4240 /*
4219 4241 * Check if the number of files tabled is different from the
4220 4242 * number of files listed on the command line
4221 4243 */
4222 4244 if (fcnt > tcnt) {
4223 4245 (void) fprintf(stderr, gettext(
4224 4246 "tar: %d file(s) not found\n"), fcnt-tcnt);
4225 4247 Errflg = 1;
4226 4248 }
4227 4249 }
4228 4250
4229 4251 static void
4230 4252 putempty(blkcnt_t n)
4231 4253 {
4232 4254 char buf[TBLOCK];
4233 4255 char *cp;
4234 4256
4235 4257 for (cp = buf; cp < &buf[TBLOCK]; )
4236 4258 *cp++ = '\0';
4237 4259 while (n-- > 0)
4238 4260 (void) writetbuf(buf, 1);
4239 4261 }
4240 4262
4241 4263 static ushort_t Ftype = S_IFMT;
4242 4264
4243 4265 static void
4244 4266 verbose(struct stat *st, char aclchar)
4245 4267 {
4246 4268 int i, j, temp;
4247 4269 mode_t mode;
4248 4270 char modestr[12];
4249 4271
4250 4272 for (i = 0; i < 11; i++)
4251 4273 modestr[i] = '-';
4252 4274 modestr[i] = '\0';
4253 4275
4254 4276 /* a '+' sign is printed if there is ACL */
4255 4277 modestr[i-1] = aclchar;
4256 4278
4257 4279 mode = st->st_mode;
4258 4280 for (i = 0; i < 3; i++) {
4259 4281 temp = (mode >> (6 - (i * 3)));
4260 4282 j = (i * 3) + 1;
4261 4283 if (S_IROTH & temp)
4262 4284 modestr[j] = 'r';
4263 4285 if (S_IWOTH & temp)
4264 4286 modestr[j + 1] = 'w';
4265 4287 if (S_IXOTH & temp)
4266 4288 modestr[j + 2] = 'x';
4267 4289 }
4268 4290 temp = st->st_mode & Ftype;
4269 4291 switch (temp) {
4270 4292 case (S_IFIFO):
4271 4293 modestr[0] = 'p';
4272 4294 break;
4273 4295 case (S_IFCHR):
4274 4296 modestr[0] = 'c';
4275 4297 break;
4276 4298 case (S_IFDIR):
4277 4299 modestr[0] = 'd';
4278 4300 break;
4279 4301 case (S_IFBLK):
4280 4302 modestr[0] = 'b';
4281 4303 break;
4282 4304 case (S_IFREG): /* was initialized to '-' */
4283 4305 break;
4284 4306 case (S_IFLNK):
4285 4307 modestr[0] = 'l';
4286 4308 break;
4287 4309 default:
4288 4310 /* This field may be zero in old archives. */
4289 4311 if (is_posix && dblock.dbuf.typeflag != '1') {
4290 4312 /*
4291 4313 * For POSIX compliant archives, the mode field
4292 4314 * consists of 12 bits, ie: the file type bits
4293 4315 * are not stored in dblock.dbuf.mode.
4294 4316 * For files other than hard links, getdir() sets
4295 4317 * the file type bits in the st_mode field of the
4296 4318 * stat structure based upon dblock.dbuf.typeflag.
4297 4319 */
4298 4320 (void) fprintf(stderr, gettext(
4299 4321 "tar: impossible file type"));
4300 4322 }
4301 4323 }
4302 4324
4303 4325 if ((S_ISUID & Gen.g_mode) == S_ISUID)
4304 4326 modestr[3] = 's';
4305 4327 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
4306 4328 modestr[9] = 't';
4307 4329 if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
4308 4330 modestr[6] = 's';
4309 4331 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
4310 4332 modestr[6] = 'l';
4311 4333 (void) fprintf(vfile, "%s", modestr);
4312 4334 }
4313 4335
4314 4336 static void
4315 4337 longt(struct stat *st, char aclchar)
4316 4338 {
4317 4339 char fileDate[30];
4318 4340 struct tm *tm;
4319 4341
4320 4342 verbose(st, aclchar);
4321 4343 (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
4322 4344
4323 4345 if (dblock.dbuf.typeflag == '2') {
4324 4346 if (xhdr_flgs & _X_LINKPATH)
4325 4347 st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
4326 4348 else
4327 4349 st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
4328 4350 '\0', NAMSIZ) ?
4329 4351 (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
4330 4352 }
4331 4353 (void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
4332 4354
4333 4355 tm = localtime(&(st->st_mtime));
4334 4356 (void) strftime(fileDate, sizeof (fileDate),
4335 4357 dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
4336 4358 (void) fprintf(vfile, " %s ", fileDate);
4337 4359 }
4338 4360
4339 4361
4340 4362 /*
4341 4363 * checkdir - Attempt to ensure that the path represented in name
4342 4364 * exists, and return 1 if this is true and name itself is a
4343 4365 * directory.
4344 4366 * Return 0 if this path cannot be created or if name is not
4345 4367 * a directory.
4346 4368 */
4347 4369
4348 4370 static int
4349 4371 checkdir(char *name)
4350 4372 {
4351 4373 char lastChar; /* the last character in name */
4352 4374 char *cp; /* scratch pointer into name */
4353 4375 char *firstSlash = NULL; /* first slash in name */
4354 4376 char *lastSlash = NULL; /* last slash in name */
4355 4377 int nameLen; /* length of name */
4356 4378 int trailingSlash; /* true if name ends in slash */
4357 4379 int leadingSlash; /* true if name begins with slash */
4358 4380 int markedDir; /* true if name denotes a directory */
4359 4381 int success; /* status of makeDir call */
4360 4382
4361 4383
4362 4384 /*
4363 4385 * Scan through the name, and locate first and last slashes.
4364 4386 */
4365 4387
4366 4388 for (cp = name; *cp; cp++) {
4367 4389 if (*cp == '/') {
4368 4390 if (! firstSlash) {
4369 4391 firstSlash = cp;
4370 4392 }
4371 4393 lastSlash = cp;
4372 4394 }
4373 4395 }
4374 4396
4375 4397 /*
4376 4398 * Determine what you can from the proceeds of the scan.
4377 4399 */
4378 4400
4379 4401 lastChar = *(cp - 1);
4380 4402 nameLen = (int)(cp - name);
4381 4403 trailingSlash = (lastChar == '/');
4382 4404 leadingSlash = (*name == '/');
4383 4405 markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash);
4384 4406
4385 4407 if (! lastSlash && ! markedDir) {
4386 4408 /*
4387 4409 * The named file does not have any subdrectory
4388 4410 * structure; just bail out.
4389 4411 */
4390 4412
4391 4413 return (0);
4392 4414 }
4393 4415
4394 4416 /*
4395 4417 * Make sure that name doesn`t end with slash for the loop.
4396 4418 * This ensures that the makeDir attempt after the loop is
4397 4419 * meaningful.
4398 4420 */
4399 4421
4400 4422 if (trailingSlash) {
4401 4423 name[nameLen-1] = '\0';
4402 4424 }
4403 4425
4404 4426 /*
4405 4427 * Make the path one component at a time.
4406 4428 */
4407 4429
4408 4430 for (cp = strchr(leadingSlash ? name+1 : name, '/');
4409 4431 cp;
4410 4432 cp = strchr(cp+1, '/')) {
4411 4433 *cp = '\0';
4412 4434 success = makeDir(name);
4413 4435 *cp = '/';
4414 4436
4415 4437 if (!success) {
4416 4438 name[nameLen-1] = lastChar;
4417 4439 return (0);
4418 4440 }
4419 4441 }
4420 4442
4421 4443 /*
4422 4444 * This makes the last component of the name, if it is a
4423 4445 * directory.
4424 4446 */
4425 4447
4426 4448 if (markedDir) {
4427 4449 if (! makeDir(name)) {
4428 4450 name[nameLen-1] = lastChar;
4429 4451 return (0);
4430 4452 }
4431 4453 }
4432 4454
4433 4455 name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
4434 4456 return (markedDir);
4435 4457 }
4436 4458
4437 4459 /*
4438 4460 * resugname - Restore the user name and group name. Search the NIS
4439 4461 * before using the uid and gid.
4440 4462 * (It is presumed that an archive entry cannot be
4441 4463 * simultaneously a symlink and some other type.)
4442 4464 */
4443 4465
4444 4466 static void
4445 4467 resugname(int dirfd, /* dir fd file resides in */
4446 4468 char *name, /* name of the file to be modified */
4447 4469 int symflag) /* true if file is a symbolic link */
4448 4470 {
4449 4471 uid_t duid;
4450 4472 gid_t dgid;
4451 4473 struct stat *sp = &stbuf;
4452 4474 char *u_g_name;
4453 4475
4454 4476 if (checkflag == 1) { /* Extended tar format and euid == 0 */
4455 4477
4456 4478 /*
4457 4479 * Try and extract the intended uid and gid from the name
4458 4480 * service before believing the uid and gid in the header.
4459 4481 *
4460 4482 * In the case where we archived a setuid or setgid file
4461 4483 * owned by someone with a large uid, then it will
4462 4484 * have made it into the archive with a uid of nobody. If
4463 4485 * the corresponding username doesn't appear to exist, then we
4464 4486 * want to make sure it *doesn't* end up as setuid nobody!
4465 4487 *
4466 4488 * Our caller will print an error message about the fact
4467 4489 * that the restore didn't work out quite right ..
4468 4490 */
4469 4491 if (xhdr_flgs & _X_UNAME)
4470 4492 u_g_name = Xtarhdr.x_uname;
4471 4493 else
4472 4494 u_g_name = dblock.dbuf.uname;
4473 4495 if ((duid = getuidbyname(u_g_name)) == -1) {
4474 4496 if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
4475 4497 (sp->st_mode & S_ISUID) == S_ISUID)
4476 4498 (void) chmod(name,
4477 4499 MODEMASK & sp->st_mode & ~S_ISUID);
4478 4500 duid = sp->st_uid;
4479 4501 }
4480 4502
4481 4503 /* (Ditto for gids) */
4482 4504
4483 4505 if (xhdr_flgs & _X_GNAME)
4484 4506 u_g_name = Xtarhdr.x_gname;
4485 4507 else
4486 4508 u_g_name = dblock.dbuf.gname;
4487 4509 if ((dgid = getgidbyname(u_g_name)) == -1) {
4488 4510 if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
4489 4511 (sp->st_mode & S_ISGID) == S_ISGID)
4490 4512 (void) chmod(name,
4491 4513 MODEMASK & sp->st_mode & ~S_ISGID);
4492 4514 dgid = sp->st_gid;
4493 4515 }
4494 4516 } else if (checkflag == 2) { /* tar format and euid == 0 */
4495 4517 duid = sp->st_uid;
4496 4518 dgid = sp->st_gid;
4497 4519 }
4498 4520 if ((checkflag == 1) || (checkflag == 2))
4499 4521 (void) fchownat(dirfd, name, duid, dgid, symflag);
4500 4522 }
4501 4523
4502 4524 /*ARGSUSED*/
4503 4525 static void
4504 4526 onintr(int sig)
4505 4527 {
4506 4528 (void) signal(SIGINT, SIG_IGN);
4507 4529 term++;
4508 4530 }
4509 4531
4510 4532 /*ARGSUSED*/
4511 4533 static void
4512 4534 onquit(int sig)
4513 4535 {
4514 4536 (void) signal(SIGQUIT, SIG_IGN);
4515 4537 term++;
4516 4538 }
4517 4539
4518 4540 /*ARGSUSED*/
4519 4541 static void
4520 4542 onhup(int sig)
4521 4543 {
4522 4544 (void) signal(SIGHUP, SIG_IGN);
4523 4545 term++;
4524 4546 }
4525 4547
4526 4548 static void
4527 4549 tomodes(struct stat *sp)
4528 4550 {
4529 4551 uid_t uid;
4530 4552 gid_t gid;
4531 4553
4532 4554 bzero(dblock.dummy, TBLOCK);
4533 4555
4534 4556 /*
4535 4557 * If the uid or gid is too large, we can't put it into
4536 4558 * the archive. We could fail to put anything in the
4537 4559 * archive at all .. but most of the time the name service
4538 4560 * will save the day when we do a lookup at restore time.
4539 4561 *
4540 4562 * Instead we choose a "safe" uid and gid, and fix up whether
4541 4563 * or not the setuid and setgid bits are left set to extraction
4542 4564 * time.
4543 4565 */
4544 4566 if (Eflag) {
4545 4567 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
4546 4568 xhdr_flgs |= _X_UID;
4547 4569 Xtarhdr.x_uid = uid;
4548 4570 }
4549 4571 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
4550 4572 xhdr_flgs |= _X_GID;
4551 4573 Xtarhdr.x_gid = gid;
4552 4574 }
4553 4575 if (sp->st_size > TAR_OFFSET_MAX) {
4554 4576 xhdr_flgs |= _X_SIZE;
4555 4577 Xtarhdr.x_filesz = sp->st_size;
4556 4578 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4557 4579 (off_t)0);
4558 4580 } else
4559 4581 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4560 4582 sp->st_size);
4561 4583 } else {
4562 4584 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4563 4585 sp->st_size);
4564 4586 }
4565 4587 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
4566 4588 uid = UID_NOBODY;
4567 4589 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
4568 4590 gid = GID_NOBODY;
4569 4591 (void) sprintf(dblock.dbuf.gid, "%07lo", gid);
4570 4592 (void) sprintf(dblock.dbuf.uid, "%07lo", uid);
4571 4593 (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
4572 4594 (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
4573 4595 }
4574 4596
4575 4597 static int
4576 4598 #ifdef EUC
4577 4599 /*
4578 4600 * Warning: the result of this function depends whether 'char' is a
4579 4601 * signed or unsigned data type. This a source of potential
4580 4602 * non-portability among heterogeneous systems. It is retained here
4581 4603 * for backward compatibility.
4582 4604 */
4583 4605 checksum_signed(union hblock *dblockp)
4584 4606 #else
4585 4607 checksum(union hblock *dblockp)
4586 4608 #endif /* EUC */
4587 4609 {
4588 4610 int i;
4589 4611 char *cp;
4590 4612
4591 4613 for (cp = dblockp->dbuf.chksum;
4592 4614 cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
4593 4615 *cp = ' ';
4594 4616 i = 0;
4595 4617 for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
4596 4618 i += *cp;
4597 4619 return (i);
4598 4620 }
4599 4621
4600 4622 #ifdef EUC
4601 4623 /*
4602 4624 * Generate unsigned checksum, regardless of what C compiler is
4603 4625 * used. Survives in the face of arbitrary 8-bit clean filenames,
4604 4626 * e.g., internationalized filenames.
4605 4627 */
4606 4628 static int
4607 4629 checksum(union hblock *dblockp)
4608 4630 {
4609 4631 unsigned i;
4610 4632 unsigned char *cp;
4611 4633
4612 4634 for (cp = (unsigned char *) dblockp->dbuf.chksum;
4613 4635 cp < (unsigned char *)
4614 4636 &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
4615 4637 *cp = ' ';
4616 4638 i = 0;
4617 4639 for (cp = (unsigned char *) dblockp->dummy;
4618 4640 cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
4619 4641 i += *cp;
4620 4642
4621 4643 return (i);
4622 4644 }
4623 4645 #endif /* EUC */
4624 4646
4625 4647 /*
4626 4648 * If the w flag is set, output the action to be taken and the name of the
4627 4649 * file. Perform the action if the user response is affirmative.
4628 4650 */
4629 4651
4630 4652 static int
4631 4653 checkw(char c, char *name)
4632 4654 {
4633 4655 if (wflag) {
4634 4656 (void) fprintf(vfile, "%c ", c);
4635 4657 if (vflag)
4636 4658 longt(&stbuf, ' '); /* do we have acl info here */
4637 4659 (void) fprintf(vfile, "%s: ", name);
4638 4660 if (yes() == 1) {
4639 4661 return (1);
4640 4662 }
4641 4663 return (0);
4642 4664 }
4643 4665 return (1);
4644 4666 }
4645 4667
4646 4668 /*
4647 4669 * When the F flag is set, exclude RCS and SCCS directories (and any files
4648 4670 * or directories under them). If F is set twice, also exclude .o files,
4649 4671 * and files names errs, core, and a.out.
4650 4672 *
4651 4673 * Return 0 if file should be excluded, 1 otherwise.
4652 4674 */
4653 4675
4654 4676 static int
4655 4677 checkf(char *longname, int is_dir, int howmuch)
4656 4678 {
4657 4679 static char fullname[PATH_MAX + 1];
4658 4680 char *dir, *name;
4659 4681
4660 4682 #if defined(O_XATTR)
4661 4683 /*
4662 4684 * If there is an xattr_buf structure associated with this file,
4663 4685 * always return 1.
4664 4686 */
4665 4687 if (xattrp) {
4666 4688 return (1);
4667 4689 }
4668 4690 #endif
4669 4691
4670 4692 /*
4671 4693 * First check to see if the base name is an RCS or SCCS directory.
4672 4694 */
4673 4695 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4674 4696 return (1);
4675 4697
4676 4698 name = basename(fullname);
4677 4699 if (is_dir) {
4678 4700 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4679 4701 return (0);
4680 4702 }
4681 4703
4682 4704 /*
4683 4705 * If two -F command line options were given then exclude .o files,
4684 4706 * and files named errs, core, and a.out.
4685 4707 */
4686 4708 if (howmuch > 1 && !is_dir) {
4687 4709 size_t l = strlen(name);
4688 4710
4689 4711 if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
4690 4712 return (0);
4691 4713 if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
4692 4714 strcmp(name, "a.out") == 0)
4693 4715 return (0);
4694 4716 }
4695 4717
4696 4718 /*
4697 4719 * At this point, check to see if this file has a parent directory
4698 4720 * named RCS or SCCS. If so, then this file should be excluded too.
4699 4721 * The strcpy() operation is done again, because basename(3C) may
4700 4722 * modify the path string passed to it.
4701 4723 */
4702 4724 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4703 4725 return (1);
4704 4726
4705 4727 dir = dirname(fullname);
4706 4728 while (strcmp(dir, ".") != 0) {
4707 4729 name = basename(dir);
4708 4730 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4709 4731 return (0);
4710 4732 dir = dirname(dir);
4711 4733 }
4712 4734
4713 4735 return (1);
4714 4736 }
4715 4737
4716 4738 static int
4717 4739 response(void)
4718 4740 {
4719 4741 int c;
4720 4742
4721 4743 c = getchar();
4722 4744 if (c != '\n')
4723 4745 while (getchar() != '\n')
4724 4746 ;
4725 4747 else c = 'n';
4726 4748 return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
4727 4749 }
4728 4750
4729 4751 /* Has file been modified since being put into archive? If so, return > 0. */
4730 4752
4731 4753 static off_t lookup(char *);
4732 4754
4733 4755 static int
4734 4756 checkupdate(char *arg)
4735 4757 {
4736 4758 char name[PATH_MAX+1];
4737 4759 time_t mtime;
4738 4760 long nsecs;
4739 4761 off_t seekp;
4740 4762
4741 4763 rewind(tfile);
4742 4764 if ((seekp = lookup(arg)) < 0)
4743 4765 return (1);
4744 4766 (void) fseek(tfile, seekp, 0);
4745 4767 (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
4746 4768
4747 4769 /*
4748 4770 * Unless nanoseconds were stored in the file, only use seconds for
4749 4771 * comparison of time. Nanoseconds are stored when -E is specified.
4750 4772 */
4751 4773 if (Eflag == 0)
4752 4774 return (stbuf.st_mtime > mtime);
4753 4775
4754 4776 if ((stbuf.st_mtime < mtime) ||
4755 4777 ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
4756 4778 return (0);
4757 4779 return (1);
4758 4780 }
4759 4781
4760 4782
4761 4783 /*
4762 4784 * newvol get new floppy (or tape) volume
4763 4785 *
4764 4786 * newvol(); resets tapepos and first to TRUE, prompts for
4765 4787 * for new volume, and waits.
4766 4788 * if dumping, end-of-file is written onto the tape.
4767 4789 */
4768 4790
4769 4791 static void
4770 4792 newvol(void)
4771 4793 {
4772 4794 int c;
4773 4795
4774 4796 if (dumping) {
4775 4797 #ifdef DEBUG
4776 4798 DEBUG("newvol called with 'dumping' set\n", 0, 0);
4777 4799 #endif
4778 4800 putempty((blkcnt_t)2); /* 2 EOT marks */
4779 4801 closevol();
4780 4802 flushtape();
4781 4803 sync();
4782 4804 tapepos = 0;
4783 4805 } else
4784 4806 first = TRUE;
4785 4807 if (close(mt) != 0)
4786 4808 vperror(2, gettext("close error"));
4787 4809 mt = 0;
4788 4810 (void) fprintf(stderr, gettext(
4789 4811 "tar: \007please insert new volume, then press RETURN."));
4790 4812 (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */
4791 4813 while ((c = getchar()) != '\n' && ! term)
4792 4814 if (c == EOF)
4793 4815 done(Errflg);
4794 4816 if (term)
4795 4817 done(Errflg);
4796 4818
4797 4819 errno = 0;
4798 4820
4799 4821 if (strcmp(usefile, "-") == 0) {
4800 4822 mt = dup(1);
4801 4823 } else {
4802 4824 mt = open(usefile, dumping ? update : 0);
4803 4825 }
4804 4826
4805 4827 if (mt < 0) {
4806 4828 (void) fprintf(stderr, gettext(
4807 4829 "tar: cannot reopen %s (%s)\n"),
4808 4830 dumping ? gettext("output") : gettext("input"), usefile);
4809 4831
4810 4832 #ifdef DEBUG
4811 4833 DEBUG("update=%d, usefile=%s ", update, usefile);
4812 4834 DEBUG("mt=%d, [%s]\n", mt, strerror(errno));
4813 4835 #endif
4814 4836
4815 4837 done(2);
4816 4838 }
4817 4839 }
4818 4840
4819 4841 /*
4820 4842 * Write a trailer portion to close out the current output volume.
4821 4843 */
4822 4844
4823 4845 static void
4824 4846 closevol(void)
4825 4847 {
4826 4848 if (mulvol) {
4827 4849 /*
4828 4850 * blocklim does not count the 2 EOT marks;
4829 4851 * tapepos does count the 2 EOT marks;
4830 4852 * therefore we need the +2 below.
4831 4853 */
4832 4854 putempty(blocklim + (blkcnt_t)2 - tapepos);
4833 4855 }
4834 4856 }
4835 4857
4836 4858 static void
4837 4859 done(int n)
4838 4860 {
4839 4861 /*
4840 4862 * If we were terminated in some way, and we would otherwise have
4841 4863 * exited with a value of 0, adjust to 1, so that external callers
4842 4864 * can determine this by looking at the exit status.
4843 4865 */
4844 4866 if (term && n == 0)
4845 4867 n = 1;
4846 4868
4847 4869 if (tfile != NULL)
4848 4870 (void) unlink(tname);
4849 4871 if (compress_opt != NULL)
4850 4872 (void) free(compress_opt);
4851 4873 if (mt > 0) {
4852 4874 if ((close(mt) != 0) || (fclose(stdout) != 0)) {
4853 4875 perror(gettext("tar: close error"));
4854 4876 exit(2);
4855 4877 }
4856 4878 }
4857 4879 exit(n);
4858 4880 }
4859 4881
4860 4882 /*
4861 4883 * Determine if s1 is a prefix portion of s2 (or the same as s2).
4862 4884 */
4863 4885
4864 4886 static int
4865 4887 is_prefix(char *s1, char *s2)
4866 4888 {
4867 4889 while (*s1)
4868 4890 if (*s1++ != *s2++)
4869 4891 return (0);
4870 4892 if (*s2)
4871 4893 return (*s2 == '/');
4872 4894 return (1);
4873 4895 }
4874 4896
4875 4897 /*
4876 4898 * lookup and bsrch look through tfile entries to find a match for a name.
4877 4899 * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
4878 4900 * a pair of newline chars, so the buffer it uses must be long enough for
4879 4901 * two lines: name and modification time as well as period, newline and space.
4880 4902 *
4881 4903 * A kludge was added to bsrch to take care of matching on the first entry
4882 4904 * in the file--there is no leading newline. So, if we are reading from the
4883 4905 * start of the file, read into byte two and set the first byte to a newline.
4884 4906 * Otherwise, the first entry cannot be matched.
4885 4907 *
4886 4908 */
4887 4909
4888 4910 #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4889 4911 static off_t
4890 4912 lookup(char *s)
4891 4913 {
4892 4914 int i;
4893 4915 off_t a;
4894 4916
4895 4917 for (i = 0; s[i]; i++)
4896 4918 if (s[i] == ' ')
4897 4919 break;
4898 4920 a = bsrch(s, i, low, high);
4899 4921 return (a);
4900 4922 }
4901 4923
4902 4924 static off_t
4903 4925 bsrch(char *s, int n, off_t l, off_t h)
4904 4926 {
4905 4927 int i, j;
4906 4928 char b[N];
4907 4929 off_t m, m1;
4908 4930
4909 4931
4910 4932 loop:
4911 4933 if (l >= h)
4912 4934 return ((off_t)-1);
4913 4935 m = l + (h-l)/2 - N/2;
4914 4936 if (m < l)
4915 4937 m = l;
4916 4938 (void) fseek(tfile, m, 0);
4917 4939 if (m == 0) {
4918 4940 (void) fread(b+1, 1, N-1, tfile);
4919 4941 b[0] = '\n';
4920 4942 m--;
4921 4943 } else
4922 4944 (void) fread(b, 1, N, tfile);
4923 4945 for (i = 0; i < N; i++) {
4924 4946 if (b[i] == '\n')
4925 4947 break;
4926 4948 m++;
4927 4949 }
4928 4950 if (m >= h)
4929 4951 return ((off_t)-1);
4930 4952 m1 = m;
4931 4953 j = i;
4932 4954 for (i++; i < N; i++) {
4933 4955 m1++;
4934 4956 if (b[i] == '\n')
4935 4957 break;
4936 4958 }
4937 4959 i = cmp(b+j, s, n);
4938 4960 if (i < 0) {
4939 4961 h = m;
4940 4962 goto loop;
4941 4963 }
4942 4964 if (i > 0) {
4943 4965 l = m1;
4944 4966 goto loop;
4945 4967 }
4946 4968 if (m < 0)
4947 4969 m = 0;
4948 4970 return (m);
4949 4971 }
4950 4972
4951 4973 static int
4952 4974 cmp(char *b, char *s, int n)
4953 4975 {
4954 4976 int i;
4955 4977
4956 4978 assert(b[0] == '\n');
4957 4979
4958 4980 for (i = 0; i < n; i++) {
4959 4981 if (b[i+1] > s[i])
4960 4982 return (-1);
4961 4983 if (b[i+1] < s[i])
4962 4984 return (1);
4963 4985 }
4964 4986 return (b[i+1] == ' '? 0 : -1);
4965 4987 }
4966 4988
4967 4989
4968 4990 /*
4969 4991 * seekdisk seek to next file on archive
4970 4992 *
4971 4993 * called by passtape() only
4972 4994 *
4973 4995 * WARNING: expects "nblock" to be set, that is, readtape() to have
4974 4996 * already been called. Since passtape() is only called
4975 4997 * after a file header block has been read (why else would
4976 4998 * we skip to next file?), this is currently safe.
4977 4999 *
4978 5000 * changed to guarantee SYS_BLOCK boundary
4979 5001 */
4980 5002
4981 5003 static void
4982 5004 seekdisk(blkcnt_t blocks)
4983 5005 {
4984 5006 off_t seekval;
4985 5007 #if SYS_BLOCK > TBLOCK
4986 5008 /* handle non-multiple of SYS_BLOCK */
4987 5009 blkcnt_t nxb; /* # extra blocks */
4988 5010 #endif
4989 5011
4990 5012 tapepos += blocks;
4991 5013 #ifdef DEBUG
4992 5014 DEBUG("seekdisk(%" FMT_blkcnt_t ") called\n", blocks, 0);
4993 5015 #endif
4994 5016 if (recno + blocks <= nblock) {
4995 5017 recno += blocks;
4996 5018 return;
4997 5019 }
4998 5020 if (recno > nblock)
4999 5021 recno = nblock;
5000 5022 seekval = (off_t)blocks - (nblock - recno);
5001 5023 recno = nblock; /* so readtape() reads next time through */
5002 5024 #if SYS_BLOCK > TBLOCK
5003 5025 nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
5004 5026 #ifdef DEBUG
5005 5027 DEBUG("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
5006 5028 nxb, seekval);
5007 5029 #endif
5008 5030 if (nxb && nxb > seekval) /* don't seek--we'll read */
5009 5031 goto noseek;
5010 5032 seekval -= nxb; /* don't seek quite so far */
5011 5033 #endif
5012 5034 if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
5013 5035 (void) fprintf(stderr, gettext(
5014 5036 "tar: device seek error\n"));
5015 5037 done(3);
5016 5038 }
5017 5039 #if SYS_BLOCK > TBLOCK
5018 5040 /* read those extra blocks */
5019 5041 noseek:
5020 5042 if (nxb) {
5021 5043 #ifdef DEBUG
5022 5044 DEBUG("reading extra blocks\n", 0, 0);
5023 5045 #endif
5024 5046 if (read(mt, tbuf, TBLOCK*nblock) < 0) {
5025 5047 (void) fprintf(stderr, gettext(
5026 5048 "tar: read error while skipping file\n"));
5027 5049 done(8);
5028 5050 }
5029 5051 recno = nxb; /* so we don't read in next readtape() */
5030 5052 }
5031 5053 #endif
5032 5054 }
5033 5055
5034 5056 static void
5035 5057 readtape(char *buffer)
5036 5058 {
5037 5059 int i, j;
5038 5060
5039 5061 ++tapepos;
5040 5062 if (recno >= nblock || first) {
5041 5063 if (first) {
5042 5064 /*
5043 5065 * set the number of blocks to read initially, based on
5044 5066 * the defined defaults for the device, or on the
5045 5067 * explicit block factor given.
5046 5068 */
5047 5069 if (bflag || defaults_used || NotTape)
5048 5070 j = nblock;
5049 5071 else
5050 5072 j = NBLOCK;
5051 5073 } else
5052 5074 j = nblock;
5053 5075
5054 5076 if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
5055 5077 (void) fprintf(stderr, gettext(
5056 5078 "tar: tape read error\n"));
5057 5079 done(3);
5058 5080 /*
5059 5081 * i == 0 and !rflag means that EOF is reached and we are
5060 5082 * trying to update or replace an empty tar file, so exit
5061 5083 * with an error.
5062 5084 *
5063 5085 * If i == 0 and !first and NotTape, it means the pointer
5064 5086 * has gone past the EOF. It could happen if two processes
5065 5087 * try to update the same tar file simultaneously. So exit
5066 5088 * with an error.
5067 5089 */
5068 5090
5069 5091 } else if (i == 0) {
5070 5092 if (first && !rflag) {
5071 5093 (void) fprintf(stderr, gettext(
5072 5094 "tar: blocksize = %d\n"), i);
5073 5095 done(Errflg);
5074 5096 } else if (!first && (!rflag || NotTape)) {
5075 5097 mterr("read", 0, 2);
5076 5098 }
5077 5099 } else if ((!first || Bflag) && i != TBLOCK*j) {
5078 5100 /*
5079 5101 * Short read - try to get the remaining bytes.
5080 5102 */
5081 5103
5082 5104 int remaining = (TBLOCK * j) - i;
5083 5105 char *b = (char *)tbuf + i;
5084 5106 int r;
5085 5107
5086 5108 do {
5087 5109 if ((r = read(mt, b, remaining)) < 0) {
5088 5110 (void) fprintf(stderr,
5089 5111 gettext("tar: tape read error\n"));
5090 5112 done(3);
5091 5113 }
5092 5114 b += r;
5093 5115 remaining -= r;
5094 5116 i += r;
5095 5117 } while (remaining > 0 && r != 0);
5096 5118 }
5097 5119 if (first) {
5098 5120 if ((i % TBLOCK) != 0) {
5099 5121 (void) fprintf(stderr, gettext(
5100 5122 "tar: tape blocksize error\n"));
5101 5123 done(3);
5102 5124 }
5103 5125 i /= TBLOCK;
5104 5126 if (vflag && i != nblock && i != 1) {
5105 5127 if (!NotTape)
5106 5128 (void) fprintf(stderr, gettext(
5107 5129 "tar: blocksize = %d\n"), i);
5108 5130 }
5109 5131
5110 5132 /*
5111 5133 * If we are reading a tape, then a short read is
5112 5134 * understood to signify that the amount read is
5113 5135 * the tape's actual blocking factor. We adapt
5114 5136 * nblock accordingly. There is no reason to do
5115 5137 * this when the device is not blocked.
5116 5138 */
5117 5139
5118 5140 if (!NotTape)
5119 5141 nblock = i;
5120 5142 }
5121 5143 recno = 0;
5122 5144 }
5123 5145
5124 5146 first = FALSE;
5125 5147 copy(buffer, &tbuf[recno++]);
5126 5148 }
5127 5149
5128 5150
5129 5151 /*
5130 5152 * replacement for writetape.
5131 5153 */
5132 5154
5133 5155 static int
5134 5156 writetbuf(char *buffer, int n)
5135 5157 {
5136 5158 int i;
5137 5159
5138 5160 tapepos += n; /* output block count */
5139 5161
5140 5162 if (recno >= nblock) {
5141 5163 i = write(mt, (char *)tbuf, TBLOCK*nblock);
5142 5164 if (i != TBLOCK*nblock)
5143 5165 mterr("write", i, 2);
5144 5166 recno = 0;
5145 5167 }
5146 5168
5147 5169 /*
5148 5170 * Special case: We have an empty tape buffer, and the
5149 5171 * users data size is >= the tape block size: Avoid
5150 5172 * the bcopy and dma direct to tape. BIG WIN. Add the
5151 5173 * residual to the tape buffer.
5152 5174 */
5153 5175 while (recno == 0 && n >= nblock) {
5154 5176 i = (int)write(mt, buffer, TBLOCK*nblock);
5155 5177 if (i != TBLOCK*nblock)
5156 5178 mterr("write", i, 2);
5157 5179 n -= nblock;
5158 5180 buffer += (nblock * TBLOCK);
5159 5181 }
5160 5182
5161 5183 while (n-- > 0) {
5162 5184 (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
5163 5185 buffer += TBLOCK;
5164 5186 if (recno >= nblock) {
5165 5187 i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
5166 5188 if (i != TBLOCK*nblock)
5167 5189 mterr("write", i, 2);
5168 5190 recno = 0;
5169 5191 }
5170 5192 }
5171 5193
5172 5194 /* Tell the user how much to write to get in sync */
5173 5195 return (nblock - recno);
5174 5196 }
5175 5197
5176 5198 /*
5177 5199 * backtape - reposition tape after reading soft "EOF" record
5178 5200 *
5179 5201 * Backtape tries to reposition the tape back over the EOF
5180 5202 * record. This is for the 'u' and 'r' function letters so that the
5181 5203 * tape can be extended. This code is not well designed, but
5182 5204 * I'm confident that the only callers who care about the
5183 5205 * backspace-over-EOF feature are those involved in 'u' and 'r'.
5184 5206 *
5185 5207 * The proper way to backup the tape is through the use of mtio.
5186 5208 * Earlier spins used lseek combined with reads in a confusing
5187 5209 * maneuver that only worked on 4.x, but shouldn't have, even
5188 5210 * there. Lseeks are explicitly not supported for tape devices.
5189 5211 */
5190 5212
5191 5213 static void
5192 5214 backtape(void)
5193 5215 {
5194 5216 struct mtop mtcmd;
5195 5217 #ifdef DEBUG
5196 5218 DEBUG("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
5197 5219 nblock);
5198 5220 #endif
5199 5221 /*
5200 5222 * Backup to the position in the archive where the record
5201 5223 * currently sitting in the tbuf buffer is situated.
5202 5224 */
5203 5225
5204 5226 if (NotTape) {
5205 5227 /*
5206 5228 * For non-tape devices, this means lseeking to the
5207 5229 * correct position. The absolute location tapepos-recno
5208 5230 * should be the beginning of the current record.
5209 5231 */
5210 5232
5211 5233 if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
5212 5234 (off_t)-1) {
5213 5235 (void) fprintf(stderr,
5214 5236 gettext("tar: lseek to end of archive failed\n"));
5215 5237 done(4);
5216 5238 }
5217 5239 } else {
5218 5240 /*
5219 5241 * For tape devices, we backup over the most recently
5220 5242 * read record.
5221 5243 */
5222 5244
5223 5245 mtcmd.mt_op = MTBSR;
5224 5246 mtcmd.mt_count = 1;
5225 5247
5226 5248 if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
5227 5249 (void) fprintf(stderr,
5228 5250 gettext("tar: backspace over record failed\n"));
5229 5251 done(4);
5230 5252 }
5231 5253 }
5232 5254
5233 5255 /*
5234 5256 * Decrement the tape and tbuf buffer indices to prepare for the
5235 5257 * coming write to overwrite the soft EOF record.
5236 5258 */
5237 5259
5238 5260 recno--;
5239 5261 tapepos--;
5240 5262 }
5241 5263
5242 5264
5243 5265 /*
5244 5266 * flushtape write buffered block(s) onto tape
5245 5267 *
5246 5268 * recno points to next free block in tbuf. If nonzero, a write is done.
5247 5269 * Care is taken to write in multiples of SYS_BLOCK when device is
5248 5270 * non-magtape in case raw i/o is used.
5249 5271 *
5250 5272 * NOTE: this is called by writetape() to do the actual writing
5251 5273 */
5252 5274
5253 5275 static void
5254 5276 flushtape(void)
5255 5277 {
5256 5278 #ifdef DEBUG
5257 5279 DEBUG("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno, 0);
5258 5280 #endif
5259 5281 if (recno > 0) { /* anything buffered? */
5260 5282 if (NotTape) {
5261 5283 #if SYS_BLOCK > TBLOCK
5262 5284 int i;
5263 5285
5264 5286 /*
5265 5287 * an odd-block write can only happen when
5266 5288 * we are at the end of a volume that is not a tape.
5267 5289 * Here we round recno up to an even SYS_BLOCK
5268 5290 * boundary.
5269 5291 */
5270 5292 if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
5271 5293 #ifdef DEBUG
5272 5294 DEBUG("flushtape() %d rounding blocks\n", i, 0);
5273 5295 #endif
5274 5296 recno += i; /* round up to even SYS_BLOCK */
5275 5297 }
5276 5298 #endif
5277 5299 if (recno > nblock)
5278 5300 recno = nblock;
5279 5301 }
5280 5302 #ifdef DEBUG
5281 5303 DEBUG("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
5282 5304 " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
5283 5305 (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
5284 5306 #endif
5285 5307 if (write(mt, tbuf,
5286 5308 (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
5287 5309 (void) fprintf(stderr, gettext(
5288 5310 "tar: tape write error\n"));
5289 5311 done(2);
5290 5312 }
5291 5313 recno = 0;
5292 5314 }
5293 5315 }
5294 5316
5295 5317 static void
5296 5318 copy(void *dst, void *src)
5297 5319 {
5298 5320 (void) memcpy(dst, src, TBLOCK);
5299 5321 }
5300 5322
5301 5323 /*
5302 5324 * kcheck()
5303 5325 * - checks the validity of size values for non-tape devices
5304 5326 * - if size is zero, mulvol tar is disabled and size is
5305 5327 * assumed to be infinite.
5306 5328 * - returns volume size in TBLOCKS
5307 5329 */
5308 5330
5309 5331 static blkcnt_t
5310 5332 kcheck(char *kstr)
5311 5333 {
5312 5334 blkcnt_t kval;
5313 5335
5314 5336 kval = strtoll(kstr, NULL, 0);
5315 5337 if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */
5316 5338 mulvol = 0; /* definitely not mulvol, but we must */
5317 5339 return (0); /* took out setting of NotTape */
5318 5340 }
5319 5341 if (kval < (blkcnt_t)MINSIZE) {
5320 5342 (void) fprintf(stderr, gettext(
5321 5343 "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5322 5344 ").\n"), (ulong_t)MINSIZE, kval);
5323 5345 (void) fprintf(stderr, gettext(
5324 5346 "bad size entry for %s in %s.\n"),
5325 5347 archive, DEF_FILE);
5326 5348 done(1);
5327 5349 }
5328 5350 mulvol++;
5329 5351 NotTape++; /* implies non-tape */
5330 5352 return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */
5331 5353 }
5332 5354
5333 5355
5334 5356 /*
5335 5357 * bcheck()
5336 5358 * - checks the validity of blocking factors
5337 5359 * - returns blocking factor
5338 5360 */
5339 5361
5340 5362 static int
5341 5363 bcheck(char *bstr)
5342 5364 {
5343 5365 blkcnt_t bval;
5344 5366
5345 5367 bval = strtoll(bstr, NULL, 0);
5346 5368 if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
5347 5369 (void) fprintf(stderr, gettext(
5348 5370 "tar: invalid blocksize \"%s\".\n"), bstr);
5349 5371 if (!bflag)
5350 5372 (void) fprintf(stderr, gettext(
5351 5373 "bad blocksize entry for '%s' in %s.\n"),
5352 5374 archive, DEF_FILE);
5353 5375 done(1);
5354 5376 }
5355 5377
5356 5378 return ((int)bval);
5357 5379 }
5358 5380
5359 5381
5360 5382 /*
5361 5383 * defset()
5362 5384 * - reads DEF_FILE for the set of default values specified.
5363 5385 * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5364 5386 * - 'usefile' points to static data, so will be overwritten
5365 5387 * if this routine is called a second time.
5366 5388 * - the pattern specified by 'arch' must be followed by four
5367 5389 * blank-separated fields (1) device (2) blocking,
5368 5390 * (3) size(K), and (4) tape
5369 5391 * for example: archive0=/dev/fd 1 400 n
5370 5392 */
5371 5393
5372 5394 static int
5373 5395 defset(char *arch)
5374 5396 {
5375 5397 char *bp;
5376 5398
5377 5399 if (defopen(DEF_FILE) != 0)
5378 5400 return (FALSE);
5379 5401 if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
5380 5402 (void) fprintf(stderr, gettext(
5381 5403 "tar: error setting parameters for %s.\n"), DEF_FILE);
5382 5404 return (FALSE); /* & following ones too */
5383 5405 }
5384 5406 if ((bp = defread(arch)) == NULL) {
5385 5407 (void) fprintf(stderr, gettext(
5386 5408 "tar: missing or invalid '%s' entry in %s.\n"),
5387 5409 arch, DEF_FILE);
5388 5410 return (FALSE);
5389 5411 }
5390 5412 if ((usefile = strtok(bp, " \t")) == NULL) {
5391 5413 (void) fprintf(stderr, gettext(
5392 5414 "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
5393 5415 return (FALSE);
5394 5416 }
5395 5417 if ((bp = strtok(NULL, " \t")) == NULL) {
5396 5418 (void) fprintf(stderr, gettext(
5397 5419 "tar: block component missing in '%s' entry in %s.\n"),
5398 5420 arch, DEF_FILE);
5399 5421 return (FALSE);
5400 5422 }
5401 5423 nblock = bcheck(bp);
5402 5424 if ((bp = strtok(NULL, " \t")) == NULL) {
5403 5425 (void) fprintf(stderr, gettext(
5404 5426 "tar: size component missing in '%s' entry in %s.\n"),
5405 5427 arch, DEF_FILE);
5406 5428 return (FALSE);
5407 5429 }
5408 5430 blocklim = kcheck(bp);
5409 5431 if ((bp = strtok(NULL, " \t")) != NULL)
5410 5432 NotTape = (*bp == 'n' || *bp == 'N');
5411 5433 else
5412 5434 NotTape = (blocklim != 0);
5413 5435 (void) defopen(NULL);
5414 5436 #ifdef DEBUG
5415 5437 DEBUG("defset: archive='%s'; usefile='%s'\n", arch, usefile);
5416 5438 DEBUG("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
5417 5439 nblock, blocklim);
5418 5440 DEBUG("defset: not tape = %d\n", NotTape, 0);
5419 5441 #endif
5420 5442 return (TRUE);
5421 5443 }
5422 5444
5423 5445
5424 5446 /*
5425 5447 * Following code handles excluded and included files.
5426 5448 * A hash table of file names to be {in,ex}cluded is built.
5427 5449 * For excluded files, before writing or extracting a file
5428 5450 * check to see if it is in the exclude_tbl.
5429 5451 * For included files, the wantit() procedure will check to
5430 5452 * see if the named file is in the include_tbl.
5431 5453 */
5432 5454
5433 5455 static void
5434 5456 build_table(file_list_t *table[], char *file)
5435 5457 {
5436 5458 FILE *fp;
5437 5459 char buf[PATH_MAX + 1];
5438 5460
5439 5461 if ((fp = fopen(file, "r")) == (FILE *)NULL)
5440 5462 vperror(1, gettext("could not open %s"), file);
5441 5463 while (fgets(buf, sizeof (buf), fp) != NULL) {
5442 5464 if (buf[strlen(buf) - 1] == '\n')
5443 5465 buf[strlen(buf) - 1] = '\0';
5444 5466 /* Only add to table if line has something in it */
5445 5467 if (strspn(buf, " \t") != strlen(buf))
5446 5468 add_file_to_table(table, buf);
5447 5469 }
5448 5470 (void) fclose(fp);
5449 5471 }
5450 5472
5451 5473
5452 5474 /*
5453 5475 * Add a file name to the the specified table, if the file name has any
5454 5476 * trailing '/'s then delete them before inserting into the table
5455 5477 */
5456 5478
5457 5479 static void
5458 5480 add_file_to_table(file_list_t *table[], char *str)
5459 5481 {
5460 5482 char name[PATH_MAX + 1];
5461 5483 unsigned int h;
5462 5484 file_list_t *exp;
5463 5485
5464 5486 (void) strcpy(name, str);
5465 5487 while (name[strlen(name) - 1] == '/') {
5466 5488 name[strlen(name) - 1] = NULL;
5467 5489 }
5468 5490
5469 5491 h = hash(name);
5470 5492 if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
5471 5493 sizeof (char))) == NULL) {
5472 5494 (void) fprintf(stderr, gettext(
5473 5495 "tar: out of memory, exclude/include table(entry)\n"));
5474 5496 exit(1);
5475 5497 }
5476 5498
5477 5499 if ((exp->name = strdup(name)) == NULL) {
5478 5500 (void) fprintf(stderr, gettext(
5479 5501 "tar: out of memory, exclude/include table(file name)\n"));
5480 5502 exit(1);
5481 5503 }
5482 5504
5483 5505 exp->next = table[h];
5484 5506 table[h] = exp;
5485 5507 }
5486 5508
5487 5509
5488 5510 /*
5489 5511 * See if a file name or any of the file's parent directories is in the
5490 5512 * specified table, if the file name has any trailing '/'s then delete
5491 5513 * them before searching the table
5492 5514 */
5493 5515
5494 5516 static int
5495 5517 is_in_table(file_list_t *table[], char *str)
5496 5518 {
5497 5519 char name[PATH_MAX + 1];
5498 5520 unsigned int h;
5499 5521 file_list_t *exp;
5500 5522 char *ptr;
5501 5523
5502 5524 (void) strcpy(name, str);
5503 5525 while (name[strlen(name) - 1] == '/') {
5504 5526 name[strlen(name) - 1] = NULL;
5505 5527 }
5506 5528
5507 5529 /*
5508 5530 * check for the file name in the passed list
5509 5531 */
5510 5532 h = hash(name);
5511 5533 exp = table[h];
5512 5534 while (exp != NULL) {
5513 5535 if (strcmp(name, exp->name) == 0) {
5514 5536 return (1);
5515 5537 }
5516 5538 exp = exp->next;
5517 5539 }
5518 5540
5519 5541 /*
5520 5542 * check for any parent directories in the file list
5521 5543 */
5522 5544 while ((ptr = strrchr(name, '/'))) {
5523 5545 *ptr = NULL;
5524 5546 h = hash(name);
5525 5547 exp = table[h];
5526 5548 while (exp != NULL) {
5527 5549 if (strcmp(name, exp->name) == 0) {
5528 5550 return (1);
5529 5551 }
5530 5552 exp = exp->next;
5531 5553 }
5532 5554 }
5533 5555
5534 5556 return (0);
5535 5557 }
5536 5558
5537 5559
5538 5560 /*
5539 5561 * Compute a hash from a string.
5540 5562 */
5541 5563
5542 5564 static unsigned int
5543 5565 hash(char *str)
5544 5566 {
5545 5567 char *cp;
5546 5568 unsigned int h;
5547 5569
5548 5570 h = 0;
5549 5571 for (cp = str; *cp; cp++) {
5550 5572 h += *cp;
5551 5573 }
5552 5574 return (h % TABLE_SIZE);
5553 5575 }
5554 5576
5555 5577 static void *
5556 5578 getmem(size_t size)
5557 5579 {
5558 5580 void *p = calloc((unsigned)size, sizeof (char));
5559 5581
5560 5582 if (p == NULL && freemem) {
5561 5583 (void) fprintf(stderr, gettext(
5562 5584 "tar: out of memory, link and directory modtime "
5563 5585 "info lost\n"));
5564 5586 freemem = 0;
5565 5587 if (errflag)
5566 5588 done(1);
5567 5589 else
5568 5590 Errflg = 1;
5569 5591 }
5570 5592 return (p);
5571 5593 }
5572 5594
5573 5595 /*
5574 5596 * vperror() --variable argument perror.
5575 5597 * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
5576 5598 * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5577 5599 * with the value of whatever "errno" is set to. If exit_status is not
5578 5600 * zero, then tar exits with that error status. If errflag and exit_status
5579 5601 * are both zero, the routine returns to where it was called and sets Errflg
5580 5602 * to errno.
5581 5603 */
5582 5604
5583 5605 static void
5584 5606 vperror(int exit_status, char *fmt, ...)
5585 5607 {
5586 5608 va_list ap;
5587 5609
5588 5610 va_start(ap, fmt);
5589 5611 (void) fputs("tar: ", stderr);
5590 5612 (void) vfprintf(stderr, fmt, ap);
5591 5613 (void) fprintf(stderr, ": %s\n", strerror(errno));
5592 5614 va_end(ap);
5593 5615 if (exit_status)
5594 5616 done(exit_status);
5595 5617 else
5596 5618 if (errflag)
5597 5619 done(errno);
5598 5620 else
5599 5621 Errflg = errno;
5600 5622 }
5601 5623
5602 5624
5603 5625 static void
5604 5626 fatal(char *format, ...)
5605 5627 {
5606 5628 va_list ap;
5607 5629
5608 5630 va_start(ap, format);
5609 5631 (void) fprintf(stderr, "tar: ");
5610 5632 (void) vfprintf(stderr, format, ap);
5611 5633 (void) fprintf(stderr, "\n");
5612 5634 va_end(ap);
5613 5635 done(1);
5614 5636 }
5615 5637
5616 5638
5617 5639 /*
5618 5640 * Check to make sure that argument is a char * ptr.
5619 5641 * Actually, we just check to see that it is non-null.
5620 5642 * If it is null, print out the message and call usage(), bailing out.
5621 5643 */
5622 5644
5623 5645 static void
5624 5646 assert_string(char *s, char *msg)
5625 5647 {
5626 5648 if (s == NULL) {
5627 5649 (void) fprintf(stderr, msg);
5628 5650 usage();
5629 5651 }
5630 5652 }
5631 5653
5632 5654
5633 5655 static void
5634 5656 mterr(char *operation, int i, int exitcode)
5635 5657 {
5636 5658 (void) fprintf(stderr, gettext(
5637 5659 "tar: %s error: "), operation);
5638 5660 if (i < 0)
5639 5661 perror("");
5640 5662 else
5641 5663 (void) fprintf(stderr, gettext("unexpected EOF\n"));
5642 5664 done(exitcode);
5643 5665 }
5644 5666
5645 5667 static int
5646 5668 wantit(char *argv[], char **namep, char **dirp, char **component,
5647 5669 attr_data_t **attrinfo)
5648 5670 {
5649 5671 char **cp;
5650 5672 int gotit; /* true if we've found a match */
5651 5673 int ret;
5652 5674
5653 5675 top:
5654 5676 if (xhdr_flgs & _X_XHDR) {
5655 5677 xhdr_flgs = 0;
5656 5678 }
5657 5679 getdir();
5658 5680 if (Xhdrflag > 0) {
5659 5681 ret = get_xdata();
5660 5682 if (ret != 0) { /* Xhdr items and regular header */
5661 5683 setbytes_to_skip(&stbuf, ret);
5662 5684 passtape();
5663 5685 return (0); /* Error--don't want to extract */
5664 5686 }
5665 5687 }
5666 5688
5667 5689 /*
5668 5690 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5669 5691 * of ancillary file is either over or ancillary file
5670 5692 * processing is not required, load info from Xtarhdr and set
5671 5693 * _X_XHDR bit in xhdr_flgs.
5672 5694 */
5673 5695 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
5674 5696 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
5675 5697 xhdr_flgs |= _X_XHDR;
5676 5698 }
5677 5699
5678 5700 #if defined(O_XATTR)
5679 5701 if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
5680 5702 /*
5681 5703 * Always needs to read the extended header. If atflag, saflag,
5682 5704 * or tflag isn't set, then we'll have the correct info for
5683 5705 * passtape() later.
5684 5706 */
5685 5707 (void) read_xattr_hdr(attrinfo);
5686 5708 goto top;
5687 5709 }
5688 5710 /*
5689 5711 * Now that we've read the extended header, call passtape()
5690 5712 * if we don't want to restore attributes or system attributes.
5691 5713 * Don't restore the attribute if we are extracting
5692 5714 * a file from an archive (as opposed to doing a table of
5693 5715 * contents) and any of the following are true:
5694 5716 * 1. neither -@ or -/ was specified.
5695 5717 * 2. -@ was specified, -/ wasn't specified, and we're
5696 5718 * processing a hidden attribute directory of an attribute
5697 5719 * or we're processing a read-write system attribute file.
5698 5720 * 3. -@ wasn't specified, -/ was specified, and the file
5699 5721 * we're processing is not a read-write system attribute file,
5700 5722 * or we're processing the hidden attribute directory of an
5701 5723 * attribute.
5702 5724 *
5703 5725 * We always process the attributes if we're just generating
5704 5726 * generating a table of contents, or if both -@ and -/ were
5705 5727 * specified.
5706 5728 */
5707 5729 if (xattrp != NULL) {
5708 5730 attr_data_t *ainfo = *attrinfo;
5709 5731
5710 5732 if (!tflag &&
5711 5733 ((!atflag && !saflag) ||
5712 5734 (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
5713 5735 ainfo->attr_rw_sysattr)) ||
5714 5736 (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
5715 5737 !ainfo->attr_rw_sysattr)))) {
5716 5738 passtape();
5717 5739 return (0);
5718 5740 }
5719 5741 }
5720 5742 #endif
5721 5743
5722 5744 /* sets *namep to point at the proper name */
5723 5745 if (check_prefix(namep, dirp, component) != 0) {
5724 5746 passtape();
5725 5747 return (0);
5726 5748 }
5727 5749
5728 5750 if (endtape()) {
5729 5751 if (Bflag) {
5730 5752 /*
5731 5753 * Logically at EOT - consume any extra blocks
5732 5754 * so that write to our stdin won't fail and
5733 5755 * emit an error message; otherwise something
5734 5756 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5735 5757 * will produce a bogus error message from "dd".
5736 5758 */
5737 5759
5738 5760 while (read(mt, tbuf, TBLOCK*nblock) > 0) {
5739 5761 /* empty body */
5740 5762 }
5741 5763 }
5742 5764 return (-1);
5743 5765 }
5744 5766
5745 5767 gotit = 0;
5746 5768
5747 5769 if ((Iflag && is_in_table(include_tbl, *namep)) ||
5748 5770 (! Iflag && *argv == NULL)) {
5749 5771 gotit = 1;
5750 5772 } else {
5751 5773 for (cp = argv; *cp; cp++) {
5752 5774 if (is_prefix(*cp, *namep)) {
5753 5775 gotit = 1;
5754 5776 break;
5755 5777 }
5756 5778 }
5757 5779 }
5758 5780
5759 5781 if (! gotit) {
5760 5782 passtape();
5761 5783 return (0);
5762 5784 }
5763 5785
5764 5786 if (Xflag && is_in_table(exclude_tbl, *namep)) {
5765 5787 if (vflag) {
5766 5788 (void) fprintf(stderr, gettext("%s excluded\n"),
5767 5789 *namep);
5768 5790 }
5769 5791 passtape();
5770 5792 return (0);
5771 5793 }
5772 5794
5773 5795 return (1);
5774 5796 }
5775 5797
5776 5798
5777 5799 static void
5778 5800 setbytes_to_skip(struct stat *st, int err)
5779 5801 {
5780 5802 /*
5781 5803 * In a scenario where a typeflag 'X' was followed by
5782 5804 * a typeflag 'A' and typeflag 'O', then the number of
5783 5805 * bytes to skip should be the size of ancillary file,
5784 5806 * plus the dblock for regular file, and the size
5785 5807 * from Xtarhdr. However, if the typeflag was just 'X'
5786 5808 * followed by typeflag 'O', then the number of bytes
5787 5809 * to skip should be the size from Xtarhdr.
5788 5810 */
5789 5811 if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
5790 5812 (xhdr_flgs & _X_SIZE)) {
5791 5813 st->st_size += TBLOCK + Xtarhdr.x_filesz;
5792 5814 xhdr_flgs |= _X_XHDR;
5793 5815 } else if ((dblock.dbuf.typeflag != 'A') &&
5794 5816 (xhdr_flgs & _X_SIZE)) {
5795 5817 st->st_size += Xtarhdr.x_filesz;
5796 5818 xhdr_flgs |= _X_XHDR;
5797 5819 }
5798 5820 }
5799 5821
5800 5822 static int
5801 5823 fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
5802 5824 int rw_sysattr, attr_data_t **attrinfo)
5803 5825 {
5804 5826 size_t pathlen;
5805 5827 char *tpath;
5806 5828 char *tparent;
5807 5829
5808 5830 /* parent info */
5809 5831 if (attrparent != NULL) {
5810 5832 if ((tparent = strdup(attrparent)) == NULL) {
5811 5833 vperror(0, gettext(
5812 5834 "unable to allocate memory for attribute parent "
5813 5835 "name for %sattribute %s/%s of %s"),
5814 5836 rw_sysattr ? gettext("system ") : "",
5815 5837 attrparent, attr, longname);
5816 5838 return (1);
5817 5839 }
5818 5840 } else {
5819 5841 tparent = NULL;
5820 5842 }
5821 5843
5822 5844 /* path info */
5823 5845 pathlen = strlen(attr) + 1;
5824 5846 if (attrparent != NULL) {
5825 5847 pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
5826 5848 }
5827 5849 if ((tpath = calloc(1, pathlen)) == NULL) {
5828 5850 vperror(0, gettext(
5829 5851 "unable to allocate memory for full "
5830 5852 "attribute path name for %sattribute %s%s%s of %s"),
5831 5853 rw_sysattr ? gettext("system ") : "",
5832 5854 (attrparent == NULL) ? "" : attrparent,
5833 5855 (attrparent == NULL) ? "" : "/",
5834 5856 attr, longname);
5835 5857 if (tparent != NULL) {
5836 5858 free(tparent);
5837 5859 }
5838 5860 return (1);
5839 5861 }
5840 5862 (void) snprintf(tpath, pathlen, "%s%s%s",
5841 5863 (attrparent == NULL) ? "" : attrparent,
5842 5864 (attrparent == NULL) ? "" : "/",
5843 5865 attr);
5844 5866
5845 5867 /* fill in the attribute info */
5846 5868 if (*attrinfo == NULL) {
5847 5869 if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
5848 5870 vperror(0, gettext(
5849 5871 "unable to allocate memory for attribute "
5850 5872 "information for %sattribute %s%s%s of %s"),
5851 5873 rw_sysattr ? gettext("system ") : "",
5852 5874 (attrparent == NULL) ? "" : attrparent,
5853 5875 (attrparent == NULL) ? "" : gettext("/"),
5854 5876 attr, longname);
5855 5877 if (tparent != NULL) {
5856 5878 free(tparent);
5857 5879 }
5858 5880 free(tpath);
5859 5881 return (1);
5860 5882 }
5861 5883 } else {
5862 5884 if ((*attrinfo)->attr_parent != NULL) {
5863 5885 free((*attrinfo)->attr_parent);
5864 5886 }
5865 5887 if ((*attrinfo)->attr_path != NULL) {
5866 5888 free((*attrinfo)->attr_path);
5867 5889 }
5868 5890 /*
5869 5891 * The parent file descriptor is passed in, so don't
5870 5892 * close it here as it should be closed by the function
5871 5893 * that opened it.
5872 5894 */
5873 5895 }
5874 5896 (*attrinfo)->attr_parent = tparent;
5875 5897 (*attrinfo)->attr_path = tpath;
5876 5898 (*attrinfo)->attr_rw_sysattr = rw_sysattr;
5877 5899 (*attrinfo)->attr_parentfd = atparentfd;
5878 5900
5879 5901 return (0);
5880 5902 }
5881 5903
5882 5904 /*
5883 5905 * Test to see if name is a directory.
5884 5906 *
5885 5907 * Return 1 if true, 0 otherwise.
5886 5908 */
5887 5909
5888 5910 static int
5889 5911 is_directory(char *name)
5890 5912 {
5891 5913 #if defined(O_XATTR)
5892 5914 /*
5893 5915 * If there is an xattr_buf structure associated with this file,
5894 5916 * then the directory test is based on whether the name has a
5895 5917 * trailing slash.
5896 5918 */
5897 5919 if (xattrp)
5898 5920 return (name[strlen(name) - 1] == '/');
5899 5921 #endif
5900 5922 if (is_posix)
5901 5923 return (dblock.dbuf.typeflag == '5');
5902 5924 else
5903 5925 return (name[strlen(name) - 1] == '/');
5904 5926 }
5905 5927
5906 5928 /*
5907 5929 * Version of chdir that handles directory pathnames of greater than PATH_MAX
5908 5930 * length, by changing the working directory to manageable portions of the
5909 5931 * complete directory pathname. If any of these attempts fail, then it exits
5910 5932 * non-zero.
5911 5933 *
5912 5934 * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
5913 5935 * pathname is greater than PATH_MAX, then this still won't work, and this
5914 5936 * routine will return -1 with errno set to ENAMETOOLONG.
5915 5937 *
5916 5938 * NOTE: this routine is semantically different to the system chdir in
5917 5939 * that it is remotely possible for the currently working directory to be
5918 5940 * changed to a different directory, if a chdir call fails when processing
5919 5941 * one of the segments of a path that is greater than PATH_MAX. This isn't
5920 5942 * a problem as this is tar's own specific version of chdir.
5921 5943 */
5922 5944
5923 5945 static int
5924 5946 tar_chdir(const char *path) {
5925 5947 const char *sep = "/";
5926 5948 char *path_copy = NULL;
5927 5949 char *ptr = NULL;
5928 5950
5929 5951 /* The trivial case. */
5930 5952 if (chdir(path) == 0) {
5931 5953 return (0);
5932 5954 }
5933 5955 if (errno == ENAMETOOLONG) {
5934 5956 if (path[0] == '/' && chdir(sep) != 0)
5935 5957 return (-1);
5936 5958
5937 5959 /* strtok(3C) modifies the string, so make a copy. */
5938 5960 if ((path_copy = strdup(path)) == NULL) {
5939 5961 return (-1);
5940 5962 }
5941 5963
5942 5964 /* chdir(2) for every path element. */
5943 5965 for (ptr = strtok(path_copy, sep);
5944 5966 ptr != NULL;
5945 5967 ptr = strtok(NULL, sep)) {
5946 5968 if (chdir(ptr) != 0) {
5947 5969 free(path_copy);
5948 5970 return (-1);
5949 5971 }
5950 5972 }
5951 5973 free(path_copy);
5952 5974 return (0);
5953 5975 }
5954 5976
5955 5977 /* If chdir fails for any reason except ENAMETOOLONG. */
5956 5978 return (-1);
5957 5979 }
5958 5980
5959 5981 /*
5960 5982 * Test if name has a '..' sequence in it.
5961 5983 *
5962 5984 * Return 1 if found, 0 otherwise.
5963 5985 */
5964 5986
5965 5987 static int
5966 5988 has_dot_dot(char *name)
5967 5989 {
5968 5990 char *s;
5969 5991 size_t name_len = strlen(name);
5970 5992
5971 5993 for (s = name; s < (name + name_len - 2); s++) {
5972 5994 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
5973 5995 return (1);
5974 5996
5975 5997 while (! (*s == '/')) {
5976 5998 if (! *s++)
5977 5999 return (0);
5978 6000 }
5979 6001 }
5980 6002
5981 6003 return (0);
5982 6004 }
5983 6005
5984 6006 /*
5985 6007 * Test if name is an absolute path name.
5986 6008 *
5987 6009 * Return 1 if true, 0 otherwise.
5988 6010 */
5989 6011
5990 6012 static int
5991 6013 is_absolute(char *name)
5992 6014 {
5993 6015 #if defined(O_XATTR)
5994 6016 /*
5995 6017 * If this is an extended attribute (whose name will begin with
5996 6018 * "/dev/null/", always return 0 as they should be extracted with
5997 6019 * the name intact, to allow other tar archiving programs that
5998 6020 * don't understand extended attributes, to correctly throw them away.
5999 6021 */
6000 6022 if (xattrp)
6001 6023 return (0);
6002 6024 #endif
6003 6025
6004 6026 return (name[0] == '/');
6005 6027 }
6006 6028
6007 6029 /*
6008 6030 * Adjust the pathname to make it a relative one. Strip off any leading
6009 6031 * '/' characters and if the pathname contains any '..' sequences, strip
6010 6032 * upto and including the last occurance of '../' (or '..' if found at
6011 6033 * the very end of the pathname).
6012 6034 *
6013 6035 * Return the relative pathname. stripped_prefix will also return the
6014 6036 * portion of name that was stripped off and should be freed by the
6015 6037 * calling routine when no longer needed.
6016 6038 */
6017 6039
6018 6040 static char *
6019 6041 make_relative_name(char *name, char **stripped_prefix)
6020 6042 {
6021 6043 char *s;
6022 6044 size_t prefix_len = 0;
6023 6045 size_t name_len = strlen(name);
6024 6046
6025 6047 for (s = name + prefix_len; s < (name + name_len - 2); ) {
6026 6048 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
6027 6049 prefix_len = s + 2 - name;
6028 6050
6029 6051 do {
6030 6052 char c = *s++;
6031 6053
6032 6054 if (c == '/')
6033 6055 break;
6034 6056 } while (*s);
6035 6057 }
6036 6058
6037 6059 for (s = name + prefix_len; *s == '/'; s++)
6038 6060 continue;
6039 6061 prefix_len = s - name;
6040 6062
6041 6063 /* Create the portion of the name that was stripped off. */
6042 6064 s = malloc(prefix_len + 1);
6043 6065 memcpy(s, name, prefix_len);
6044 6066 s[prefix_len] = 0;
6045 6067 *stripped_prefix = s;
6046 6068 s = &name[prefix_len];
6047 6069
6048 6070 return (s);
6049 6071 }
6050 6072
6051 6073 /*
6052 6074 * Return through *namep a pointer to the proper fullname (i.e "<name> |
6053 6075 * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6054 6076 *
6055 6077 * Returns 0 if successful, otherwise returns 1.
6056 6078 */
6057 6079
6058 6080 static int
6059 6081 check_prefix(char **namep, char **dirp, char **compp)
6060 6082 {
6061 6083 static char fullname[PATH_MAX + 1];
6062 6084 static char dir[PATH_MAX + 1];
6063 6085 static char component[PATH_MAX + 1];
6064 6086 static char savename[PATH_MAX + 1];
6065 6087 char *s;
6066 6088
6067 6089 (void) memset(dir, 0, sizeof (dir));
6068 6090 (void) memset(component, 0, sizeof (component));
6069 6091
6070 6092 if (xhdr_flgs & _X_PATH) {
6071 6093 (void) strcpy(fullname, Xtarhdr.x_path);
6072 6094 } else {
6073 6095 if (dblock.dbuf.prefix[0] != '\0')
6074 6096 (void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
6075 6097 dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
6076 6098 else
6077 6099 (void) sprintf(fullname, "%.*s", NAMSIZ,
6078 6100 dblock.dbuf.name);
6079 6101 }
6080 6102
6081 6103 /*
6082 6104 * If we are printing a table of contents or extracting an archive,
6083 6105 * make absolute pathnames relative and prohibit the unpacking of
6084 6106 * files contain ".." in their name (unless the user has supplied
6085 6107 * the -P option).
6086 6108 */
6087 6109 if ((tflag || xflag) && !Pflag) {
6088 6110 if (is_absolute(fullname) || has_dot_dot(fullname)) {
6089 6111 char *stripped_prefix;
6090 6112 size_t prefix_len = 0;
6091 6113
6092 6114 (void) strcpy(savename, fullname);
6093 6115 strcpy(fullname,
6094 6116 make_relative_name(savename, &stripped_prefix));
6095 6117 (void) fprintf(stderr,
6096 6118 gettext("tar: Removing leading '%s' from '%s'\n"),
6097 6119 stripped_prefix, savename);
6098 6120 free(stripped_prefix);
6099 6121 }
6100 6122 }
6101 6123
6102 6124 /*
6103 6125 * Set dir and component names
6104 6126 */
6105 6127
6106 6128 get_parent(fullname, dir);
6107 6129
6108 6130 #if defined(O_XATTR)
6109 6131 if (xattrp == NULL) {
6110 6132 #endif
6111 6133 /*
6112 6134 * Save of real name since were going to chop off the
6113 6135 * trailing slashes.
6114 6136 */
6115 6137 (void) strcpy(savename, fullname);
6116 6138 /*
6117 6139 * first strip of trailing slashes.
6118 6140 */
6119 6141 chop_endslashes(savename);
6120 6142 s = get_component(savename);
6121 6143 (void) strcpy(component, s);
6122 6144
6123 6145 #if defined(O_XATTR)
6124 6146 } else {
6125 6147 (void) strcpy(fullname, xattrp->h_names);
6126 6148 (void) strcpy(dir, fullname);
6127 6149 (void) strcpy(component, basename(xattrp->h_names +
6128 6150 strlen(xattrp->h_names) + 1));
6129 6151 }
6130 6152 #endif
6131 6153 *namep = fullname;
6132 6154 *dirp = dir;
6133 6155 *compp = component;
6134 6156
6135 6157 return (0);
6136 6158 }
6137 6159
6138 6160 /*
6139 6161 * Return true if the object indicated by the file descriptor and type
6140 6162 * is a tape device, false otherwise
6141 6163 */
6142 6164
6143 6165 static int
6144 6166 istape(int fd, int type)
6145 6167 {
6146 6168 int result = 0;
6147 6169
6148 6170 if (S_ISCHR(type)) {
6149 6171 struct mtget mtg;
6150 6172
6151 6173 if (ioctl(fd, MTIOCGET, &mtg) != -1) {
6152 6174 result = 1;
6153 6175 }
6154 6176 }
6155 6177
6156 6178 return (result);
6157 6179 }
6158 6180
6159 6181 #include <utmpx.h>
6160 6182
6161 6183 struct utmpx utmpx;
6162 6184
6163 6185 #define NMAX (sizeof (utmpx.ut_name))
6164 6186
6165 6187 typedef struct cachenode { /* this struct must be zeroed before using */
6166 6188 struct cachenode *next; /* next in hash chain */
6167 6189 int val; /* the uid or gid of this entry */
6168 6190 int namehash; /* name's hash signature */
6169 6191 char name[NMAX+1]; /* the string that val maps to */
6170 6192 } cachenode_t;
6171 6193
6172 6194 #define HASHSIZE 256
6173 6195
6174 6196 static cachenode_t *names[HASHSIZE];
6175 6197 static cachenode_t *groups[HASHSIZE];
6176 6198 static cachenode_t *uids[HASHSIZE];
6177 6199 static cachenode_t *gids[HASHSIZE];
6178 6200
6179 6201 static int
6180 6202 hash_byname(char *name)
6181 6203 {
6182 6204 int i, c, h = 0;
6183 6205
6184 6206 for (i = 0; i < NMAX; i++) {
6185 6207 c = name[i];
6186 6208 if (c == '\0')
6187 6209 break;
6188 6210 h = (h << 4) + h + c;
6189 6211 }
6190 6212 return (h);
6191 6213 }
6192 6214
6193 6215 static cachenode_t *
6194 6216 hash_lookup_byval(cachenode_t *table[], int val)
6195 6217 {
6196 6218 int h = val;
6197 6219 cachenode_t *c;
6198 6220
6199 6221 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6200 6222 if (c->val == val)
6201 6223 return (c);
6202 6224 }
6203 6225 return (NULL);
6204 6226 }
6205 6227
6206 6228 static cachenode_t *
6207 6229 hash_lookup_byname(cachenode_t *table[], char *name)
6208 6230 {
6209 6231 int h = hash_byname(name);
6210 6232 cachenode_t *c;
6211 6233
6212 6234 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6213 6235 if (c->namehash == h && strcmp(c->name, name) == 0)
6214 6236 return (c);
6215 6237 }
6216 6238 return (NULL);
6217 6239 }
6218 6240
6219 6241 static cachenode_t *
6220 6242 hash_insert(cachenode_t *table[], char *name, int value)
6221 6243 {
6222 6244 cachenode_t *c;
6223 6245 int signature;
6224 6246
6225 6247 c = calloc(1, sizeof (cachenode_t));
6226 6248 if (c == NULL) {
6227 6249 perror("malloc");
6228 6250 exit(1);
6229 6251 }
6230 6252 if (name != NULL) {
6231 6253 (void) strncpy(c->name, name, NMAX);
6232 6254 c->namehash = hash_byname(name);
6233 6255 }
6234 6256 c->val = value;
6235 6257 if (table == uids || table == gids)
6236 6258 signature = c->val;
6237 6259 else
6238 6260 signature = c->namehash;
6239 6261 c->next = table[signature & (HASHSIZE - 1)];
6240 6262 table[signature & (HASHSIZE - 1)] = c;
6241 6263 return (c);
6242 6264 }
6243 6265
6244 6266 static char *
6245 6267 getname(uid_t uid)
6246 6268 {
6247 6269 cachenode_t *c;
6248 6270
6249 6271 if ((c = hash_lookup_byval(uids, uid)) == NULL) {
6250 6272 struct passwd *pwent = getpwuid(uid);
6251 6273 c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
6252 6274 }
6253 6275 return (c->name);
6254 6276 }
6255 6277
6256 6278 static char *
6257 6279 getgroup(gid_t gid)
6258 6280 {
6259 6281 cachenode_t *c;
6260 6282
6261 6283 if ((c = hash_lookup_byval(gids, gid)) == NULL) {
6262 6284 struct group *grent = getgrgid(gid);
6263 6285 c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
6264 6286 }
6265 6287 return (c->name);
6266 6288 }
6267 6289
6268 6290 static uid_t
6269 6291 getuidbyname(char *name)
6270 6292 {
6271 6293 cachenode_t *c;
6272 6294
6273 6295 if ((c = hash_lookup_byname(names, name)) == NULL) {
6274 6296 struct passwd *pwent = getpwnam(name);
6275 6297 c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
6276 6298 }
6277 6299 return ((uid_t)c->val);
6278 6300 }
6279 6301
6280 6302 static gid_t
6281 6303 getgidbyname(char *group)
6282 6304 {
6283 6305 cachenode_t *c;
6284 6306
6285 6307 if ((c = hash_lookup_byname(groups, group)) == NULL) {
6286 6308 struct group *grent = getgrnam(group);
6287 6309 c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
6288 6310 }
6289 6311 return ((gid_t)c->val);
6290 6312 }
6291 6313
6292 6314 /*
6293 6315 * Build the header.
6294 6316 * Determine whether or not an extended header is also needed. If needed,
6295 6317 * create and write the extended header and its data.
6296 6318 * Writing of the extended header assumes that "tomodes" has been called and
6297 6319 * the relevant information has been placed in the header block.
6298 6320 */
6299 6321
6300 6322 static int
6301 6323 build_dblock(
6302 6324 const char *name,
6303 6325 const char *linkname,
6304 6326 const char typeflag,
6305 6327 const int filetype,
6306 6328 const struct stat *sp,
6307 6329 const dev_t device,
6308 6330 const char *prefix)
6309 6331 {
6310 6332 int nblks;
6311 6333 major_t dev;
6312 6334 const char *filename;
6313 6335 const char *lastslash;
6314 6336
6315 6337 if (filetype == XATTR_FILE)
6316 6338 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
6317 6339 else
6318 6340 dblock.dbuf.typeflag = typeflag;
6319 6341 (void) memset(dblock.dbuf.name, '\0', NAMSIZ);
6320 6342 (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
6321 6343 (void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
6322 6344
6323 6345 if (xhdr_flgs & _X_PATH)
6324 6346 filename = Xtarhdr.x_path;
6325 6347 else
6326 6348 filename = name;
6327 6349
6328 6350 if ((dev = major(device)) > OCTAL7CHAR) {
6329 6351 if (Eflag) {
6330 6352 xhdr_flgs |= _X_DEVMAJOR;
6331 6353 Xtarhdr.x_devmajor = dev;
6332 6354 } else {
6333 6355 (void) fprintf(stderr, gettext(
6334 6356 "Device major too large for %s. Use -E flag."),
6335 6357 filename);
6336 6358 if (errflag)
6337 6359 done(1);
6338 6360 else
6339 6361 Errflg = 1;
6340 6362 }
6341 6363 dev = 0;
6342 6364 }
6343 6365 (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
6344 6366 if ((dev = minor(device)) > OCTAL7CHAR) {
6345 6367 if (Eflag) {
6346 6368 xhdr_flgs |= _X_DEVMINOR;
6347 6369 Xtarhdr.x_devminor = dev;
6348 6370 } else {
6349 6371 (void) fprintf(stderr, gettext(
6350 6372 "Device minor too large for %s. Use -E flag."),
6351 6373 filename);
6352 6374 if (errflag)
6353 6375 done(1);
6354 6376 else
6355 6377 Errflg = 1;
6356 6378 }
6357 6379 dev = 0;
6358 6380 }
6359 6381 (void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
6360 6382
6361 6383 (void) strncpy(dblock.dbuf.name, name, NAMSIZ);
6362 6384 (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
6363 6385 (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
6364 6386 (void) sprintf(dblock.dbuf.version, "00");
6365 6387 (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
6366 6388 (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
6367 6389 (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
6368 6390 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
6369 6391
6370 6392 if (Eflag) {
6371 6393 (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
6372 6394 (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
6373 6395 lastslash = strrchr(name, '/');
6374 6396 if (lastslash == NULL)
6375 6397 lastslash = name;
6376 6398 else
6377 6399 lastslash++;
6378 6400 (void) strcpy(xhdr_buf.dbuf.name, lastslash);
6379 6401 (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
6380 6402 (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
6381 6403 (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
6382 6404 xhdr_count++;
6383 6405 xrec_offset = 0;
6384 6406 gen_date("mtime", sp->st_mtim);
6385 6407 xhdr_buf.dbuf.typeflag = 'X';
6386 6408 if (gen_utf8_names(filename) != 0)
6387 6409 return (1);
6388 6410
6389 6411 #ifdef XHDR_DEBUG
6390 6412 Xtarhdr.x_uname = dblock.dbuf.uname;
6391 6413 Xtarhdr.x_gname = dblock.dbuf.gname;
6392 6414 xhdr_flgs |= (_X_UNAME | _X_GNAME);
6393 6415 #endif
6394 6416 if (xhdr_flgs) {
6395 6417 if (xhdr_flgs & _X_DEVMAJOR)
6396 6418 gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
6397 6419 if (xhdr_flgs & _X_DEVMINOR)
6398 6420 gen_num("SUN.devminor", Xtarhdr.x_devminor);
6399 6421 if (xhdr_flgs & _X_GID)
6400 6422 gen_num("gid", Xtarhdr.x_gid);
6401 6423 if (xhdr_flgs & _X_UID)
6402 6424 gen_num("uid", Xtarhdr.x_uid);
6403 6425 if (xhdr_flgs & _X_SIZE)
6404 6426 gen_num("size", Xtarhdr.x_filesz);
6405 6427 if (xhdr_flgs & _X_PATH)
6406 6428 gen_string("path", Xtarhdr.x_path);
6407 6429 if (xhdr_flgs & _X_LINKPATH)
6408 6430 gen_string("linkpath", Xtarhdr.x_linkpath);
6409 6431 if (xhdr_flgs & _X_GNAME)
6410 6432 gen_string("gname", Xtarhdr.x_gname);
6411 6433 if (xhdr_flgs & _X_UNAME)
6412 6434 gen_string("uname", Xtarhdr.x_uname);
6413 6435 }
6414 6436 (void) sprintf(xhdr_buf.dbuf.size,
6415 6437 "%011" FMT_off_t_o, xrec_offset);
6416 6438 (void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
6417 6439 checksum(&xhdr_buf));
6418 6440 (void) writetbuf((char *)&xhdr_buf, 1);
6419 6441 nblks = TBLOCKS(xrec_offset);
6420 6442 (void) writetbuf(xrec_ptr, nblks);
6421 6443 }
6422 6444 return (0);
6423 6445 }
6424 6446
6425 6447
6426 6448 /*
6427 6449 * makeDir - ensure that a directory with the pathname denoted by name
6428 6450 * exists, and return 1 on success, and 0 on failure (e.g.,
6429 6451 * read-only file system, exists but not-a-directory).
6430 6452 */
6431 6453
6432 6454 static int
6433 6455 makeDir(char *name)
6434 6456 {
6435 6457 struct stat buf;
6436 6458
6437 6459 if (access(name, 0) < 0) { /* name doesn't exist */
6438 6460 if (mkdir(name, 0777) < 0) {
6439 6461 vperror(0, "%s", name);
6440 6462 return (0);
6441 6463 }
6442 6464 } else { /* name exists */
6443 6465 if (stat(name, &buf) < 0) {
6444 6466 vperror(0, "%s", name);
6445 6467 return (0);
6446 6468 }
6447 6469
6448 6470 return ((buf.st_mode & S_IFMT) == S_IFDIR);
6449 6471 }
6450 6472
6451 6473 return (1);
6452 6474 }
6453 6475
6454 6476
6455 6477 /*
6456 6478 * Save this directory and its mtime on the stack, popping and setting
6457 6479 * the mtimes of any stacked dirs which aren't parents of this one.
6458 6480 * A null name causes the entire stack to be unwound and set.
6459 6481 *
6460 6482 * Since all the elements of the directory "stack" share a common
6461 6483 * prefix, we can make do with one string. We keep only the current
6462 6484 * directory path, with an associated array of mtime's. A negative
6463 6485 * mtime means no mtime.
6464 6486 *
6465 6487 * This stack algorithm is not guaranteed to work for tapes created
6466 6488 * with the 'r' function letter, but the vast majority of tapes with
6467 6489 * directories are not. This avoids saving every directory record on
6468 6490 * the tape and setting all the times at the end.
6469 6491 *
6470 6492 * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6471 6493 * environment)
6472 6494 */
6473 6495
6474 6496 static void
6475 6497 doDirTimes(char *name, timestruc_t modTime)
6476 6498 {
6477 6499 static char dirstack[PATH_MAX+2];
6478 6500 /* Add spaces for the last slash and last NULL */
6479 6501 static timestruc_t modtimes[PATH_MAX+1]; /* hash table */
6480 6502 char *p = dirstack;
6481 6503 char *q = name;
6482 6504 char *savp;
6483 6505
6484 6506 if (q) {
6485 6507 /*
6486 6508 * Find common prefix
6487 6509 */
6488 6510
6489 6511 while (*p == *q && *p) {
6490 6512 p++; q++;
6491 6513 }
6492 6514 }
6493 6515
6494 6516 savp = p;
6495 6517 while (*p) {
6496 6518 /*
6497 6519 * Not a child: unwind the stack, setting the times.
6498 6520 * The order we do this doesn't matter, so we go "forward."
6499 6521 */
6500 6522
6501 6523 if (*p == '/')
6502 6524 if (modtimes[p - dirstack].tv_sec >= 0) {
6503 6525 *p = '\0'; /* zap the slash */
6504 6526 setPathTimes(AT_FDCWD, dirstack,
6505 6527 modtimes[p - dirstack]);
6506 6528 *p = '/';
6507 6529 }
6508 6530 ++p;
6509 6531 }
6510 6532
6511 6533 p = savp;
6512 6534
6513 6535 /*
6514 6536 * Push this one on the "stack"
6515 6537 */
6516 6538
6517 6539 if (q) {
6518 6540
6519 6541 /*
6520 6542 * Since the name parameter points the dir pathname
6521 6543 * which is limited only to contain PATH_MAX chars
6522 6544 * at maximum, we can ignore the overflow case of p.
6523 6545 */
6524 6546
6525 6547 while ((*p = *q++)) { /* append the rest of the new dir */
6526 6548 modtimes[p - dirstack].tv_sec = -1;
6527 6549 p++;
6528 6550 }
6529 6551
6530 6552 /*
6531 6553 * If the tar file had used 'P' or 'E' function modifier,
6532 6554 * append the last slash.
6533 6555 */
6534 6556 if (*(p - 1) != '/') {
6535 6557 *p++ = '/';
6536 6558 *p = '\0';
6537 6559 }
6538 6560 /* overwrite the last one */
6539 6561 modtimes[p - dirstack - 1] = modTime;
6540 6562 }
6541 6563 }
6542 6564
6543 6565
6544 6566 /*
6545 6567 * setPathTimes - set the modification time for given path. Return 1 if
6546 6568 * successful and 0 if not successful.
6547 6569 */
6548 6570
6549 6571 static void
6550 6572 setPathTimes(int dirfd, char *path, timestruc_t modTime)
6551 6573
6552 6574 {
6553 6575 struct timeval timebuf[2];
6554 6576
6555 6577 /*
6556 6578 * futimesat takes an array of two timeval structs.
6557 6579 * The first entry contains access time.
6558 6580 * The second entry contains modification time.
6559 6581 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6560 6582 * microseconds.
6561 6583 */
6562 6584 timebuf[0].tv_sec = time((time_t *)0);
6563 6585 timebuf[0].tv_usec = 0;
6564 6586 timebuf[1].tv_sec = modTime.tv_sec;
6565 6587
6566 6588 /* Extended header: use microseconds */
6567 6589 timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
6568 6590
6569 6591 if (futimesat(dirfd, path, timebuf) < 0)
6570 6592 vperror(0, gettext("can't set time on %s"), path);
6571 6593 }
6572 6594
6573 6595
6574 6596 /*
6575 6597 * If hflag is set then delete the symbolic link's target.
6576 6598 * If !hflag then delete the target.
6577 6599 */
6578 6600
6579 6601 static void
6580 6602 delete_target(int fd, char *comp, char *namep)
6581 6603 {
6582 6604 struct stat xtractbuf;
6583 6605 char buf[PATH_MAX + 1];
6584 6606 int n;
6585 6607
6586 6608
6587 6609 if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
6588 6610 if (errno == ENOTDIR && !hflag) {
6589 6611 (void) unlinkat(fd, comp, 0);
6590 6612 } else if (errno == ENOTDIR && hflag) {
6591 6613 if (!lstat(namep, &xtractbuf)) {
6592 6614 if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
6593 6615 (void) unlinkat(fd, comp, 0);
6594 6616 } else if ((n = readlink(namep, buf,
6595 6617 PATH_MAX)) != -1) {
6596 6618 buf[n] = (char)NULL;
6597 6619 (void) unlinkat(fd, buf,
6598 6620 AT_REMOVEDIR);
6599 6621 if (errno == ENOTDIR)
6600 6622 (void) unlinkat(fd, buf, 0);
6601 6623 } else {
6602 6624 (void) unlinkat(fd, comp, 0);
6603 6625 }
6604 6626 } else {
6605 6627 (void) unlinkat(fd, comp, 0);
6606 6628 }
6607 6629 }
6608 6630 }
6609 6631 }
6610 6632
6611 6633
6612 6634 /*
6613 6635 * ACL changes:
6614 6636 * putfile():
6615 6637 * Get acl info after stat. Write out ancillary file
6616 6638 * before the normal file, i.e. directory, regular, FIFO,
6617 6639 * link, special. If acl count is less than 4, no need to
6618 6640 * create ancillary file. (i.e. standard permission is in
6619 6641 * use.
6620 6642 * doxtract():
6621 6643 * Process ancillary file. Read it in and set acl info.
6622 6644 * watch out for 'o' function modifier.
6623 6645 * 't' function letter to display table
6624 6646 */
6625 6647
6626 6648 /*
6627 6649 * New functions for ACLs and other security attributes
6628 6650 */
6629 6651
6630 6652 /*
6631 6653 * The function appends the new security attribute info to the end of
6632 6654 * existing secinfo.
6633 6655 */
6634 6656 int
6635 6657 append_secattr(
6636 6658 char **secinfo, /* existing security info */
6637 6659 int *secinfo_len, /* length of existing security info */
6638 6660 int size, /* new attribute size: unit depends on type */
6639 6661 char *attrtext, /* new attribute text */
6640 6662 char attr_type) /* new attribute type */
6641 6663 {
6642 6664 char *new_secinfo;
6643 6665 int newattrsize;
6644 6666 int oldsize;
6645 6667 struct sec_attr *attr;
6646 6668
6647 6669 /* no need to add */
6648 6670 if (attr_type != DIR_TYPE) {
6649 6671 if (attrtext == NULL)
6650 6672 return (0);
6651 6673 }
6652 6674
6653 6675 switch (attr_type) {
6654 6676 case UFSD_ACL:
6655 6677 case ACE_ACL:
6656 6678 if (attrtext == NULL) {
6657 6679 (void) fprintf(stderr, gettext("acltotext failed\n"));
6658 6680 return (-1);
6659 6681 }
6660 6682 /* header: type + size = 8 */
6661 6683 newattrsize = 8 + (int)strlen(attrtext) + 1;
6662 6684 attr = (struct sec_attr *)malloc(newattrsize);
6663 6685 if (attr == NULL) {
6664 6686 (void) fprintf(stderr,
6665 6687 gettext("can't allocate memory\n"));
6666 6688 return (-1);
6667 6689 }
6668 6690 attr->attr_type = attr_type;
6669 6691 (void) sprintf(attr->attr_len,
6670 6692 "%06o", size); /* acl entry count */
6671 6693 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6672 6694 free(attrtext);
6673 6695 break;
6674 6696
6675 6697 /* Trusted Extensions */
6676 6698 case DIR_TYPE:
6677 6699 case LBL_TYPE:
6678 6700 newattrsize = sizeof (struct sec_attr) + strlen(attrtext);
6679 6701 attr = (struct sec_attr *)malloc(newattrsize);
6680 6702 if (attr == NULL) {
6681 6703 (void) fprintf(stderr,
6682 6704 gettext("can't allocate memory\n"));
6683 6705 return (-1);
6684 6706 }
6685 6707 attr->attr_type = attr_type;
6686 6708 (void) sprintf(attr->attr_len,
6687 6709 "%06d", size); /* len of attr data */
6688 6710 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6689 6711 break;
6690 6712
6691 6713 default:
6692 6714 (void) fprintf(stderr,
6693 6715 gettext("unrecognized attribute type\n"));
6694 6716 return (-1);
6695 6717 }
6696 6718
6697 6719 /* old security info + new attr header(8) + new attr */
6698 6720 oldsize = *secinfo_len;
6699 6721 *secinfo_len += newattrsize;
6700 6722 new_secinfo = (char *)malloc(*secinfo_len);
6701 6723 if (new_secinfo == NULL) {
6702 6724 (void) fprintf(stderr, gettext("can't allocate memory\n"));
6703 6725 *secinfo_len -= newattrsize;
6704 6726 free(attr);
6705 6727 return (-1);
6706 6728 }
6707 6729
6708 6730 (void) memcpy(new_secinfo, *secinfo, oldsize);
6709 6731 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6710 6732
6711 6733 free(*secinfo);
6712 6734 free(attr);
6713 6735 *secinfo = new_secinfo;
6714 6736 return (0);
6715 6737 }
6716 6738
6717 6739 /*
6718 6740 * write_ancillary(): write out an ancillary file.
6719 6741 * The file has the same header as normal file except the type and size
6720 6742 * fields. The type is 'A' and size is the sum of all attributes
6721 6743 * in bytes.
6722 6744 * The body contains a list of attribute type, size and info. Currently,
6723 6745 * there is only ACL info. This file is put before the normal file.
6724 6746 */
6725 6747 void
6726 6748 write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
6727 6749 {
6728 6750 long blocks;
6729 6751 int savflag;
6730 6752 int savsize;
6731 6753
6732 6754 /* Just tranditional permissions or no security attribute info */
6733 6755 if (len == 0 || secinfo == NULL)
6734 6756 return;
6735 6757
6736 6758 /* save flag and size */
6737 6759 savflag = (dblockp->dbuf).typeflag;
6738 6760 (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
6739 6761
6740 6762 /* special flag for ancillary file */
6741 6763 if (hdrtype == _XATTR_HDRTYPE)
6742 6764 dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
6743 6765 else
6744 6766 dblockp->dbuf.typeflag = 'A';
6745 6767
6746 6768 /* for pre-2.5 versions of tar, need to make sure */
6747 6769 /* the ACL file is readable */
6748 6770 (void) sprintf(dblock.dbuf.mode, "%07lo",
6749 6771 (stbuf.st_mode & POSIXMODES) | 0000200);
6750 6772 (void) sprintf(dblockp->dbuf.size, "%011o", len);
6751 6773 (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
6752 6774
6753 6775 /* write out the header */
6754 6776 (void) writetbuf((char *)dblockp, 1);
6755 6777
6756 6778 /* write out security info */
6757 6779 blocks = TBLOCKS(len);
6758 6780 (void) writetbuf((char *)secinfo, (int)blocks);
6759 6781
6760 6782 /* restore mode, flag and size */
6761 6783 (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
6762 6784 dblockp->dbuf.typeflag = savflag;
6763 6785 (void) sprintf(dblockp->dbuf.size, "%011o", savsize);
6764 6786 }
6765 6787
6766 6788 /*
6767 6789 * Read the data record for extended headers and then the regular header.
6768 6790 * The data are read into the buffer and then null-terminated. Entries
6769 6791 * for typeflag 'X' extended headers are of the format:
6770 6792 * "%d %s=%s\n"
6771 6793 *
6772 6794 * When an extended header record is found, the extended header must
6773 6795 * be processed and its values used to override the values in the
6774 6796 * normal header. The way this is done is to process the extended
6775 6797 * header data record and set the data values, then call getdir
6776 6798 * to process the regular header, then then to reconcile the two
6777 6799 * sets of data.
6778 6800 */
6779 6801
6780 6802 static int
6781 6803 get_xdata(void)
6782 6804 {
6783 6805 struct keylist_pair {
6784 6806 int keynum;
6785 6807 char *keylist;
6786 6808 } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor",
6787 6809 _X_DEVMINOR, "SUN.devminor",
6788 6810 _X_GID, "gid",
6789 6811 _X_GNAME, "gname",
6790 6812 _X_LINKPATH, "linkpath",
6791 6813 _X_PATH, "path",
6792 6814 _X_SIZE, "size",
6793 6815 _X_UID, "uid",
6794 6816 _X_UNAME, "uname",
6795 6817 _X_MTIME, "mtime",
6796 6818 _X_LAST, "NULL" };
6797 6819 char *lineloc;
6798 6820 int length, i;
6799 6821 char *keyword, *value;
6800 6822 blkcnt_t nblocks;
6801 6823 int bufneeded;
6802 6824 int errors;
6803 6825
6804 6826 (void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
6805 6827 xhdr_count++;
6806 6828 errors = 0;
6807 6829
6808 6830 nblocks = TBLOCKS(stbuf.st_size);
6809 6831 bufneeded = nblocks * TBLOCK;
6810 6832 if (bufneeded >= xrec_size) {
6811 6833 free(xrec_ptr);
6812 6834 xrec_size = bufneeded + 1;
6813 6835 if ((xrec_ptr = malloc(xrec_size)) == NULL)
6814 6836 fatal(gettext("cannot allocate buffer"));
6815 6837 }
6816 6838
6817 6839 lineloc = xrec_ptr;
6818 6840
6819 6841 while (nblocks-- > 0) {
6820 6842 readtape(lineloc);
6821 6843 lineloc += TBLOCK;
6822 6844 }
6823 6845 lineloc = xrec_ptr;
6824 6846 xrec_ptr[stbuf.st_size] = '\0';
6825 6847 while (lineloc < xrec_ptr + stbuf.st_size) {
6826 6848 if (dblock.dbuf.typeflag == 'L') {
6827 6849 length = xrec_size;
6828 6850 keyword = "path";
6829 6851 value = lineloc;
6830 6852 } else {
6831 6853 length = atoi(lineloc);
6832 6854 *(lineloc + length - 1) = '\0';
6833 6855 keyword = strchr(lineloc, ' ') + 1;
6834 6856 value = strchr(keyword, '=') + 1;
6835 6857 *(value - 1) = '\0';
6836 6858 }
6837 6859 i = 0;
6838 6860 lineloc += length;
6839 6861 while (keylist_pair[i].keynum != (int)_X_LAST) {
6840 6862 if (strcmp(keyword, keylist_pair[i].keylist) == 0)
6841 6863 break;
6842 6864 i++;
6843 6865 }
6844 6866 errno = 0;
6845 6867 switch (keylist_pair[i].keynum) {
6846 6868 case _X_DEVMAJOR:
6847 6869 Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
6848 6870 if (errno) {
6849 6871 (void) fprintf(stderr, gettext(
6850 6872 "tar: Extended header major value error "
6851 6873 "for file # %llu.\n"), xhdr_count);
6852 6874 errors++;
6853 6875 } else
6854 6876 xhdr_flgs |= _X_DEVMAJOR;
6855 6877 break;
6856 6878 case _X_DEVMINOR:
6857 6879 Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
6858 6880 if (errno) {
6859 6881 (void) fprintf(stderr, gettext(
6860 6882 "tar: Extended header minor value error "
6861 6883 "for file # %llu.\n"), xhdr_count);
6862 6884 errors++;
6863 6885 } else
6864 6886 xhdr_flgs |= _X_DEVMINOR;
6865 6887 break;
6866 6888 case _X_GID:
6867 6889 xhdr_flgs |= _X_GID;
6868 6890 Xtarhdr.x_gid = strtol(value, NULL, 0);
6869 6891 if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
6870 6892 (void) fprintf(stderr, gettext(
6871 6893 "tar: Extended header gid value error "
6872 6894 "for file # %llu.\n"), xhdr_count);
6873 6895 Xtarhdr.x_gid = GID_NOBODY;
6874 6896 }
6875 6897 break;
6876 6898 case _X_GNAME:
6877 6899 if (utf8_local("gname", &Xtarhdr.x_gname,
6878 6900 local_gname, value, _POSIX_NAME_MAX) == 0)
6879 6901 xhdr_flgs |= _X_GNAME;
6880 6902 break;
6881 6903 case _X_LINKPATH:
6882 6904 if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
6883 6905 local_linkpath, value, PATH_MAX) == 0)
6884 6906 xhdr_flgs |= _X_LINKPATH;
6885 6907 else
6886 6908 errors++;
6887 6909 break;
6888 6910 case _X_PATH:
6889 6911 if (utf8_local("path", &Xtarhdr.x_path,
6890 6912 local_path, value, PATH_MAX) == 0)
6891 6913 xhdr_flgs |= _X_PATH;
6892 6914 else
6893 6915 errors++;
6894 6916 break;
6895 6917 case _X_SIZE:
6896 6918 Xtarhdr.x_filesz = strtoull(value, NULL, 0);
6897 6919 if (errno) {
6898 6920 (void) fprintf(stderr, gettext(
6899 6921 "tar: Extended header invalid filesize "
6900 6922 "for file # %llu.\n"), xhdr_count);
6901 6923 errors++;
6902 6924 } else
6903 6925 xhdr_flgs |= _X_SIZE;
6904 6926 break;
6905 6927 case _X_UID:
6906 6928 xhdr_flgs |= _X_UID;
6907 6929 Xtarhdr.x_uid = strtol(value, NULL, 0);
6908 6930 if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
6909 6931 (void) fprintf(stderr, gettext(
6910 6932 "tar: Extended header uid value error "
6911 6933 "for file # %llu.\n"), xhdr_count);
6912 6934 Xtarhdr.x_uid = UID_NOBODY;
6913 6935 }
6914 6936 break;
6915 6937 case _X_UNAME:
6916 6938 if (utf8_local("uname", &Xtarhdr.x_uname,
6917 6939 local_uname, value, _POSIX_NAME_MAX) == 0)
6918 6940 xhdr_flgs |= _X_UNAME;
6919 6941 break;
6920 6942 case _X_MTIME:
6921 6943 get_xtime(value, &(Xtarhdr.x_mtime));
6922 6944 if (errno)
6923 6945 (void) fprintf(stderr, gettext(
6924 6946 "tar: Extended header modification time "
6925 6947 "value error for file # %llu.\n"),
6926 6948 xhdr_count);
6927 6949 else
6928 6950 xhdr_flgs |= _X_MTIME;
6929 6951 break;
6930 6952 default:
6931 6953 (void) fprintf(stderr,
6932 6954 gettext("tar: unrecognized extended"
6933 6955 " header keyword '%s'. Ignored.\n"), keyword);
6934 6956 break;
6935 6957 }
6936 6958 }
6937 6959
6938 6960 getdir(); /* get regular header */
6939 6961 if (errors && errflag)
6940 6962 done(1);
6941 6963 else
6942 6964 if (errors)
6943 6965 Errflg = 1;
6944 6966 return (errors);
6945 6967 }
6946 6968
6947 6969 /*
6948 6970 * load_info_from_xtarhdr - sets Gen and stbuf variables from
6949 6971 * extended header
6950 6972 * load_info_from_xtarhdr(flag, xhdrp);
6951 6973 * u_longlong_t flag; xhdr_flgs
6952 6974 * struct xtar_hdr *xhdrp; pointer to extended header
6953 6975 * NOTE: called when typeflag is not 'A' and xhdr_flgs
6954 6976 * is set.
6955 6977 */
6956 6978 static void
6957 6979 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
6958 6980 {
6959 6981 if (flag & _X_DEVMAJOR) {
6960 6982 Gen.g_devmajor = xhdrp->x_devmajor;
6961 6983 }
6962 6984 if (flag & _X_DEVMINOR) {
6963 6985 Gen.g_devminor = xhdrp->x_devminor;
6964 6986 }
6965 6987 if (flag & _X_GID) {
6966 6988 Gen.g_gid = xhdrp->x_gid;
6967 6989 stbuf.st_gid = xhdrp->x_gid;
6968 6990 }
6969 6991 if (flag & _X_UID) {
6970 6992 Gen.g_uid = xhdrp->x_uid;
6971 6993 stbuf.st_uid = xhdrp->x_uid;
6972 6994 }
6973 6995 if (flag & _X_SIZE) {
6974 6996 Gen.g_filesz = xhdrp->x_filesz;
6975 6997 stbuf.st_size = xhdrp->x_filesz;
6976 6998 }
6977 6999 if (flag & _X_MTIME) {
6978 7000 Gen.g_mtime = xhdrp->x_mtime.tv_sec;
6979 7001 stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
6980 7002 stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
6981 7003 }
6982 7004 }
6983 7005
6984 7006 /*
6985 7007 * gen_num creates a string from a keyword and an usigned long long in the
6986 7008 * format: %d %s=%s\n
6987 7009 * This is part of the extended header data record.
6988 7010 */
6989 7011
6990 7012 void
6991 7013 gen_num(const char *keyword, const u_longlong_t number)
6992 7014 {
6993 7015 char save_val[ULONGLONG_MAX_DIGITS + 1];
6994 7016 int len;
6995 7017 char *curr_ptr;
6996 7018
6997 7019 (void) sprintf(save_val, "%llu", number);
6998 7020 /*
6999 7021 * len = length of entire line, including itself. len will be
7000 7022 * two digits. So, add the string lengths plus the length of len,
7001 7023 * plus a blank, an equal sign, and a newline.
7002 7024 */
7003 7025 len = strlen(save_val) + strlen(keyword) + 5;
7004 7026 if (xrec_offset + len > xrec_size) {
7005 7027 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7006 7028 fatal(gettext(
7007 7029 "cannot allocate extended header buffer"));
7008 7030 xrec_ptr = curr_ptr;
7009 7031 xrec_size *= 2;
7010 7032 }
7011 7033 (void) sprintf(&xrec_ptr[xrec_offset],
7012 7034 "%d %s=%s\n", len, keyword, save_val);
7013 7035 xrec_offset += len;
7014 7036 }
7015 7037
7016 7038 /*
7017 7039 * gen_date creates a string from a keyword and a timestruc_t in the
7018 7040 * format: %d %s=%s\n
7019 7041 * This is part of the extended header data record.
7020 7042 * Currently, granularity is only microseconds, so the low-order three digits
7021 7043 * will be truncated.
7022 7044 */
7023 7045
7024 7046 void
7025 7047 gen_date(const char *keyword, const timestruc_t time_value)
7026 7048 {
7027 7049 /* Allow for <seconds>.<nanoseconds>\n */
7028 7050 char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
7029 7051 int len;
7030 7052 char *curr_ptr;
7031 7053
7032 7054 (void) sprintf(save_val, "%ld", time_value.tv_sec);
7033 7055 len = strlen(save_val);
7034 7056 save_val[len] = '.';
7035 7057 (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
7036 7058
7037 7059 /*
7038 7060 * len = length of entire line, including itself. len will be
7039 7061 * two digits. So, add the string lengths plus the length of len,
7040 7062 * plus a blank, an equal sign, and a newline.
7041 7063 */
7042 7064 len = strlen(save_val) + strlen(keyword) + 5;
7043 7065 if (xrec_offset + len > xrec_size) {
7044 7066 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7045 7067 fatal(gettext(
7046 7068 "cannot allocate extended header buffer"));
7047 7069 xrec_ptr = curr_ptr;
7048 7070 xrec_size *= 2;
7049 7071 }
7050 7072 (void) sprintf(&xrec_ptr[xrec_offset],
7051 7073 "%d %s=%s\n", len, keyword, save_val);
7052 7074 xrec_offset += len;
7053 7075 }
7054 7076
7055 7077 /*
7056 7078 * gen_string creates a string from a keyword and a char * in the
7057 7079 * format: %d %s=%s\n
7058 7080 * This is part of the extended header data record.
7059 7081 */
7060 7082
7061 7083 void
7062 7084 gen_string(const char *keyword, const char *value)
7063 7085 {
7064 7086 int len;
7065 7087 char *curr_ptr;
7066 7088
7067 7089 /*
7068 7090 * len = length of entire line, including itself. The character length
7069 7091 * of len must be 1-4 characters, because the maximum size of the path
7070 7092 * or the name is PATH_MAX, which is 1024. So, assume 1 character
7071 7093 * for len, one for the space, one for the "=", and one for the newline.
7072 7094 * Then adjust as needed.
7073 7095 */
7074 7096 /* LINTED constant expression */
7075 7097 assert(PATH_MAX <= 9996);
7076 7098 len = strlen(value) + strlen(keyword) + 4;
7077 7099 if (len > 997)
7078 7100 len += 3;
7079 7101 else if (len > 98)
7080 7102 len += 2;
7081 7103 else if (len > 9)
7082 7104 len += 1;
7083 7105 if (xrec_offset + len > xrec_size) {
7084 7106 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7085 7107 fatal(gettext(
7086 7108 "cannot allocate extended header buffer"));
7087 7109 xrec_ptr = curr_ptr;
7088 7110 xrec_size *= 2;
7089 7111 }
7090 7112 #ifdef XHDR_DEBUG
7091 7113 if (strcmp(keyword+1, "name") != 0)
7092 7114 #endif
7093 7115 (void) sprintf(&xrec_ptr[xrec_offset],
7094 7116 "%d %s=%s\n", len, keyword, value);
7095 7117 #ifdef XHDR_DEBUG
7096 7118 else {
7097 7119 len += 11;
7098 7120 (void) sprintf(&xrec_ptr[xrec_offset],
7099 7121 "%d %s=%snametoolong\n", len, keyword, value);
7100 7122 }
7101 7123 #endif
7102 7124 xrec_offset += len;
7103 7125 }
7104 7126
7105 7127 /*
7106 7128 * Convert time found in the extended header data to seconds and nanoseconds.
7107 7129 */
7108 7130
7109 7131 void
7110 7132 get_xtime(char *value, timestruc_t *xtime)
7111 7133 {
7112 7134 char nanosec[10];
7113 7135 char *period;
7114 7136 int i;
7115 7137
7116 7138 (void) memset(nanosec, '0', 9);
7117 7139 nanosec[9] = '\0';
7118 7140
7119 7141 period = strchr(value, '.');
7120 7142 if (period != NULL)
7121 7143 period[0] = '\0';
7122 7144 xtime->tv_sec = strtol(value, NULL, 10);
7123 7145 if (period == NULL)
7124 7146 xtime->tv_nsec = 0;
7125 7147 else {
7126 7148 i = strlen(period +1);
7127 7149 (void) strncpy(nanosec, period + 1, min(i, 9));
7128 7150 xtime->tv_nsec = strtol(nanosec, NULL, 10);
7129 7151 }
7130 7152 }
7131 7153
7132 7154 /*
7133 7155 * Check linkpath for length.
7134 7156 * Emit an error message and return 1 if too long.
7135 7157 */
7136 7158
7137 7159 int
7138 7160 chk_path_build(
7139 7161 char *name,
7140 7162 char *longname,
7141 7163 char *linkname,
7142 7164 char *prefix,
7143 7165 char type,
7144 7166 int filetype)
7145 7167 {
7146 7168
7147 7169 if (strlen(linkname) > (size_t)NAMSIZ) {
7148 7170 if (Eflag > 0) {
7149 7171 xhdr_flgs |= _X_LINKPATH;
7150 7172 Xtarhdr.x_linkpath = linkname;
7151 7173 } else {
7152 7174 (void) fprintf(stderr, gettext(
7153 7175 "tar: %s: linked to %s\n"), longname, linkname);
7154 7176 (void) fprintf(stderr, gettext(
7155 7177 "tar: %s: linked name too long\n"), linkname);
7156 7178 if (errflag)
7157 7179 done(1);
7158 7180 else
7159 7181 Errflg = 1;
7160 7182 return (1);
7161 7183 }
7162 7184 }
7163 7185 if (xhdr_flgs & _X_LINKPATH)
7164 7186 return (build_dblock(name, tchar, type,
7165 7187 filetype, &stbuf, stbuf.st_dev,
7166 7188 prefix));
7167 7189 else
7168 7190 return (build_dblock(name, linkname, type,
7169 7191 filetype, &stbuf, stbuf.st_dev, prefix));
7170 7192 }
7171 7193
7172 7194 /*
7173 7195 * Convert from UTF-8 to local character set.
7174 7196 */
7175 7197
7176 7198 static int
7177 7199 utf8_local(
7178 7200 char *option,
7179 7201 char **Xhdr_ptrptr,
7180 7202 char *target,
7181 7203 const char *source,
7182 7204 int max_val)
7183 7205 {
7184 7206 static iconv_t iconv_cd;
7185 7207 char *nl_target;
7186 7208 const char *iconv_src;
7187 7209 char *iconv_trg;
7188 7210 size_t inlen;
7189 7211 size_t outlen;
7190 7212
7191 7213 if (charset_type == -1) { /* iconv_open failed in earlier try */
7192 7214 (void) fprintf(stderr, gettext(
7193 7215 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7194 7216 xhdr_count, source);
7195 7217 return (1);
7196 7218 } else if (charset_type == 0) { /* iconv_open has not yet been done */
7197 7219 nl_target = nl_langinfo(CODESET);
7198 7220 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7199 7221 nl_target = "646";
7200 7222 if (strcmp(nl_target, "646") == 0)
7201 7223 charset_type = 1;
7202 7224 else if (strcmp(nl_target, "UTF-8") == 0)
7203 7225 charset_type = 3;
7204 7226 else {
7205 7227 if (strncmp(nl_target, "ISO", 3) == 0)
7206 7228 nl_target += 3;
7207 7229 charset_type = 2;
7208 7230 errno = 0;
7209 7231 if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
7210 7232 (iconv_t)-1) {
7211 7233 if (errno == EINVAL)
7212 7234 (void) fprintf(stderr, gettext(
7213 7235 "tar: conversion routines not "
7214 7236 "available for current locale. "));
7215 7237 (void) fprintf(stderr, gettext(
7216 7238 "file # %llu: (%s) UTF-8 conversion"
7217 7239 " failed.\n"), xhdr_count, source);
7218 7240 charset_type = -1;
7219 7241 return (1);
7220 7242 }
7221 7243 }
7222 7244 }
7223 7245
7224 7246 /* locale using 7-bit codeset or UTF-8 locale */
7225 7247 if (charset_type == 1 || charset_type == 3) {
7226 7248 if (strlen(source) > max_val) {
7227 7249 (void) fprintf(stderr, gettext(
7228 7250 "tar: file # %llu: Extended header %s too long.\n"),
7229 7251 xhdr_count, option);
7230 7252 return (1);
7231 7253 }
7232 7254 if (charset_type == 3)
7233 7255 (void) strcpy(target, source);
7234 7256 else if (c_utf8(target, source) != 0) {
7235 7257 (void) fprintf(stderr, gettext(
7236 7258 "tar: file # %llu: (%s) UTF-8 conversion"
7237 7259 " failed.\n"), xhdr_count, source);
7238 7260 return (1);
7239 7261 }
7240 7262 *Xhdr_ptrptr = target;
7241 7263 return (0);
7242 7264 }
7243 7265
7244 7266 iconv_src = source;
7245 7267 iconv_trg = target;
7246 7268 inlen = strlen(source);
7247 7269 outlen = max_val * UTF_8_FACTOR;
7248 7270 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7249 7271 (size_t)-1) { /* Error occurred: didn't convert */
7250 7272 (void) fprintf(stderr, gettext(
7251 7273 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7252 7274 xhdr_count, source);
7253 7275 /* Get remaining output; reinitialize conversion descriptor */
7254 7276 iconv_src = (const char *)NULL;
7255 7277 inlen = 0;
7256 7278 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7257 7279 return (1);
7258 7280 }
7259 7281 /* Get remaining output; reinitialize conversion descriptor */
7260 7282 iconv_src = (const char *)NULL;
7261 7283 inlen = 0;
7262 7284 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7263 7285 (size_t)-1) { /* Error occurred: didn't convert */
7264 7286 (void) fprintf(stderr, gettext(
7265 7287 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7266 7288 xhdr_count, source);
7267 7289 return (1);
7268 7290 }
7269 7291
7270 7292 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7271 7293 if (strlen(target) > max_val) {
7272 7294 (void) fprintf(stderr, gettext(
7273 7295 "tar: file # %llu: Extended header %s too long.\n"),
7274 7296 xhdr_count, option);
7275 7297 return (1);
7276 7298 }
7277 7299 *Xhdr_ptrptr = target;
7278 7300 return (0);
7279 7301 }
7280 7302
7281 7303 /*
7282 7304 * Check gname, uname, path, and linkpath to see if they need to go in an
7283 7305 * extended header. If they are already slated to be in an extended header,
7284 7306 * or if they are not ascii, then they need to be in the extended header.
7285 7307 * Then, convert all extended names to UTF-8.
7286 7308 */
7287 7309
7288 7310 int
7289 7311 gen_utf8_names(const char *filename)
7290 7312 {
7291 7313 static iconv_t iconv_cd;
7292 7314 char *nl_target;
7293 7315 char tempbuf[MAXNAM + 1];
7294 7316 int nbytes;
7295 7317 int errors;
7296 7318
7297 7319 if (charset_type == -1) { /* Previous failure to open. */
7298 7320 (void) fprintf(stderr, gettext(
7299 7321 "tar: file # %llu: UTF-8 conversion failed.\n"),
7300 7322 xhdr_count);
7301 7323 return (1);
7302 7324 }
7303 7325
7304 7326 if (charset_type == 0) { /* Need to get conversion descriptor */
7305 7327 nl_target = nl_langinfo(CODESET);
7306 7328 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7307 7329 nl_target = "646";
7308 7330 if (strcmp(nl_target, "646") == 0)
7309 7331 charset_type = 1;
7310 7332 else if (strcmp(nl_target, "UTF-8") == 0)
7311 7333 charset_type = 3;
7312 7334 else {
7313 7335 if (strncmp(nl_target, "ISO", 3) == 0)
7314 7336 nl_target += 3;
7315 7337 charset_type = 2;
7316 7338 errno = 0;
7317 7339 #ifdef ICONV_DEBUG
7318 7340 (void) fprintf(stderr,
7319 7341 gettext("Opening iconv_cd with target %s\n"),
7320 7342 nl_target);
7321 7343 #endif
7322 7344 if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
7323 7345 (iconv_t)-1) {
7324 7346 if (errno == EINVAL)
7325 7347 (void) fprintf(stderr, gettext(
7326 7348 "tar: conversion routines not "
7327 7349 "available for current locale. "));
7328 7350 (void) fprintf(stderr, gettext(
7329 7351 "file (%s): UTF-8 conversion failed.\n"),
7330 7352 filename);
7331 7353 charset_type = -1;
7332 7354 return (1);
7333 7355 }
7334 7356 }
7335 7357 }
7336 7358
7337 7359 errors = 0;
7338 7360
7339 7361 errors += local_utf8(&Xtarhdr.x_gname, local_gname,
7340 7362 dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
7341 7363 errors += local_utf8(&Xtarhdr.x_uname, local_uname,
7342 7364 dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX);
7343 7365 if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */
7344 7366 (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
7345 7367 tempbuf[NAMSIZ] = '\0';
7346 7368 }
7347 7369 errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
7348 7370 tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
7349 7371 if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */
7350 7372 (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
7351 7373 tempbuf[PRESIZ] = '\0';
7352 7374 nbytes = strlen(tempbuf);
7353 7375 if (nbytes > 0) {
7354 7376 tempbuf[nbytes++] = '/';
7355 7377 tempbuf[nbytes] = '\0';
7356 7378 }
7357 7379 (void) strncat(tempbuf + nbytes, dblock.dbuf.name,
7358 7380 (MAXNAM - nbytes));
7359 7381 tempbuf[MAXNAM] = '\0';
7360 7382 }
7361 7383 errors += local_utf8(&Xtarhdr.x_path, local_path,
7362 7384 tempbuf, iconv_cd, _X_PATH, PATH_MAX);
7363 7385
7364 7386 if (errors > 0)
7365 7387 (void) fprintf(stderr, gettext(
7366 7388 "tar: file (%s): UTF-8 conversion failed.\n"), filename);
7367 7389
7368 7390 if (errors && errflag)
7369 7391 done(1);
7370 7392 else
7371 7393 if (errors)
7372 7394 Errflg = 1;
7373 7395 return (errors);
7374 7396 }
7375 7397
7376 7398 static int
7377 7399 local_utf8(
7378 7400 char **Xhdr_ptrptr,
7379 7401 char *target,
7380 7402 const char *source,
7381 7403 iconv_t iconv_cd,
7382 7404 int xhdrflg,
7383 7405 int max_val)
7384 7406 {
7385 7407 const char *iconv_src;
7386 7408 const char *starting_src;
7387 7409 char *iconv_trg;
7388 7410 size_t inlen;
7389 7411 size_t outlen;
7390 7412 #ifdef ICONV_DEBUG
7391 7413 unsigned char c_to_hex;
7392 7414 #endif
7393 7415
7394 7416 /*
7395 7417 * If the item is already slated for extended format, get the string
7396 7418 * to convert from the extended header record. Otherwise, get it from
7397 7419 * the regular (dblock) area.
7398 7420 */
7399 7421 if (xhdr_flgs & xhdrflg) {
7400 7422 if (charset_type == 3) { /* Already UTF-8, just copy */
7401 7423 (void) strcpy(target, *Xhdr_ptrptr);
7402 7424 *Xhdr_ptrptr = target;
7403 7425 return (0);
7404 7426 } else
7405 7427 iconv_src = (const char *) *Xhdr_ptrptr;
7406 7428 } else {
7407 7429 if (charset_type == 3) /* Already in UTF-8 format */
7408 7430 return (0); /* Don't create xhdr record */
7409 7431 iconv_src = source;
7410 7432 }
7411 7433 starting_src = iconv_src;
7412 7434 iconv_trg = target;
7413 7435 if ((inlen = strlen(iconv_src)) == 0)
7414 7436 return (0);
7415 7437
7416 7438 if (charset_type == 1) { /* locale using 7-bit codeset */
7417 7439 if (c_utf8(target, starting_src) != 0) {
7418 7440 (void) fprintf(stderr,
7419 7441 gettext("tar: invalid character in"
7420 7442 " UTF-8 conversion of '%s'\n"), starting_src);
7421 7443 return (1);
7422 7444 }
7423 7445 return (0);
7424 7446 }
7425 7447
7426 7448 outlen = max_val * UTF_8_FACTOR;
7427 7449 errno = 0;
7428 7450 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7429 7451 (size_t)-1) {
7430 7452 /* An error occurred, or not all characters were converted */
7431 7453 if (errno == EILSEQ)
7432 7454 (void) fprintf(stderr,
7433 7455 gettext("tar: invalid character in"
7434 7456 " UTF-8 conversion of '%s'\n"), starting_src);
7435 7457 else
7436 7458 (void) fprintf(stderr, gettext(
7437 7459 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7438 7460 starting_src);
7439 7461 /* Get remaining output; reinitialize conversion descriptor */
7440 7462 iconv_src = (const char *)NULL;
7441 7463 inlen = 0;
7442 7464 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7443 7465 return (1);
7444 7466 }
7445 7467 /* Get remaining output; reinitialize conversion descriptor */
7446 7468 iconv_src = (const char *)NULL;
7447 7469 inlen = 0;
7448 7470 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7449 7471 (size_t)-1) { /* Error occurred: didn't convert */
7450 7472 if (errno == EILSEQ)
7451 7473 (void) fprintf(stderr,
7452 7474 gettext("tar: invalid character in"
7453 7475 " UTF-8 conversion of '%s'\n"), starting_src);
7454 7476 else
7455 7477 (void) fprintf(stderr, gettext(
7456 7478 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7457 7479 starting_src);
7458 7480 return (1);
7459 7481 }
7460 7482
7461 7483 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7462 7484 if (strcmp(starting_src, target) != 0) {
7463 7485 *Xhdr_ptrptr = target;
7464 7486 xhdr_flgs |= xhdrflg;
7465 7487 #ifdef ICONV_DEBUG
7466 7488 (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n",
7467 7489 strlen(starting_src), inlen, max_val, outlen);
7468 7490 (void) fprintf(stderr, "Input string:\n ");
7469 7491 for (inlen = 0; inlen < strlen(starting_src); inlen++) {
7470 7492 c_to_hex = (unsigned char)starting_src[inlen];
7471 7493 (void) fprintf(stderr, " %2.2x", c_to_hex);
7472 7494 if (inlen % 20 == 19)
7473 7495 (void) fprintf(stderr, "\n ");
7474 7496 }
7475 7497 (void) fprintf(stderr, "\nOutput string:\n ");
7476 7498 for (inlen = 0; inlen < strlen(target); inlen++) {
7477 7499 c_to_hex = (unsigned char)target[inlen];
7478 7500 (void) fprintf(stderr, " %2.2x", c_to_hex);
7479 7501 if (inlen % 20 == 19)
7480 7502 (void) fprintf(stderr, "\n ");
7481 7503 }
7482 7504 (void) fprintf(stderr, "\n");
7483 7505 #endif
7484 7506 }
7485 7507
7486 7508 return (0);
7487 7509 }
7488 7510
7489 7511 /*
7490 7512 * Function to test each byte of the source string to make sure it is
7491 7513 * in within bounds (value between 0 and 127).
7492 7514 * If valid, copy source to target.
7493 7515 */
7494 7516
7495 7517 int
7496 7518 c_utf8(char *target, const char *source)
7497 7519 {
7498 7520 size_t len;
7499 7521 const char *thischar;
7500 7522
7501 7523 len = strlen(source);
7502 7524 thischar = source;
7503 7525 while (len-- > 0) {
7504 7526 if (!isascii((int)(*thischar++)))
7505 7527 return (1);
7506 7528 }
7507 7529
7508 7530 (void) strcpy(target, source);
7509 7531 return (0);
7510 7532 }
7511 7533
7512 7534
7513 7535 #if defined(O_XATTR)
7514 7536 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
7515 7537
7516 7538 static void
7517 7539 prepare_xattr(
7518 7540 char **attrbuf,
7519 7541 char *filename,
7520 7542 char *attrpath,
7521 7543 char typeflag,
7522 7544 struct linkbuf *linkinfo,
7523 7545 int *rlen)
7524 7546 {
7525 7547 char *bufhead; /* ptr to full buffer */
7526 7548 char *aptr;
7527 7549 struct xattr_hdr *hptr; /* ptr to header in bufhead */
7528 7550 struct xattr_buf *tptr; /* ptr to pathing pieces */
7529 7551 int totalen; /* total buffer length */
7530 7552 int len; /* length returned to user */
7531 7553 int stringlen; /* length of filename + attr */
7532 7554 /*
7533 7555 * length of filename + attr
7534 7556 * in link section
7535 7557 */
7536 7558 int linkstringlen;
7537 7559 int complen; /* length of pathing section */
7538 7560 int linklen; /* length of link section */
7539 7561 int attrnames_index; /* attrnames starting index */
7540 7562
7541 7563 /*
7542 7564 * Release previous buffer
7543 7565 */
7544 7566
7545 7567 if (*attrbuf != (char *)NULL) {
7546 7568 free(*attrbuf);
7547 7569 *attrbuf = NULL;
7548 7570 }
7549 7571
7550 7572 /*
7551 7573 * First add in fixed size stuff
7552 7574 */
7553 7575 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7554 7576
7555 7577 /*
7556 7578 * Add space for two nulls
7557 7579 */
7558 7580 stringlen = strlen(attrpath) + strlen(filename) + 2;
7559 7581 complen = stringlen + sizeof (struct xattr_buf);
7560 7582
7561 7583 len += stringlen;
7562 7584
7563 7585 /*
7564 7586 * Now add on space for link info if any
7565 7587 */
7566 7588
7567 7589 if (linkinfo != NULL) {
7568 7590 /*
7569 7591 * Again add space for two nulls
7570 7592 */
7571 7593 linkstringlen = strlen(linkinfo->pathname) +
7572 7594 strlen(linkinfo->attrname) + 2;
7573 7595 linklen = linkstringlen + sizeof (struct xattr_buf);
7574 7596 len += linklen;
7575 7597 } else {
7576 7598 linklen = 0;
7577 7599 }
7578 7600
7579 7601 /*
7580 7602 * Now add padding to end to fill out TBLOCK
7581 7603 *
7582 7604 * Function returns size of real data and not size + padding.
7583 7605 */
7584 7606
7585 7607 totalen = ROUNDTOTBLOCK(len);
7586 7608
7587 7609 if ((bufhead = calloc(1, totalen)) == NULL) {
7588 7610 fatal(gettext("Out of memory."));
7589 7611 }
7590 7612
7591 7613
7592 7614 /*
7593 7615 * Now we can fill in the necessary pieces
7594 7616 */
7595 7617
7596 7618 /*
7597 7619 * first fill in the fixed header
7598 7620 */
7599 7621 hptr = (struct xattr_hdr *)bufhead;
7600 7622 (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7601 7623 (void) sprintf(hptr->h_component_len, "%0*d",
7602 7624 sizeof (hptr->h_component_len) - 1, complen);
7603 7625 (void) sprintf(hptr->h_link_component_len, "%0*d",
7604 7626 sizeof (hptr->h_link_component_len) - 1, linklen);
7605 7627 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7606 7628
7607 7629 /*
7608 7630 * Now fill in the filename + attrnames section
7609 7631 * The filename and attrnames section can be composed of two or more
7610 7632 * path segments separated by a null character. The first segment
7611 7633 * is the path to the parent file that roots the entire sequence in
7612 7634 * the normal name space. The remaining segments describes a path
7613 7635 * rooted at the hidden extended attribute directory of the leaf file of
7614 7636 * the previous segment, making it possible to name attributes on
7615 7637 * attributes. Thus, if we are just archiving an extended attribute,
7616 7638 * the second segment will contain the attribute name. If we are
7617 7639 * archiving a system attribute of an extended attribute, then the
7618 7640 * second segment will contain the attribute name, and a third segment
7619 7641 * will contain the system attribute name. The attribute pathing
7620 7642 * information is obtained from 'attrpath'.
7621 7643 */
7622 7644
7623 7645 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7624 7646 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7625 7647 stringlen);
7626 7648 (void) strcpy(tptr->h_names, filename);
7627 7649 attrnames_index = strlen(filename) + 1;
7628 7650 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
7629 7651 tptr->h_typeflag = typeflag;
7630 7652
7631 7653 /*
7632 7654 * Split the attrnames section into two segments if 'attrpath'
7633 7655 * contains pathing information for a system attribute of an
7634 7656 * extended attribute. We split them by replacing the '/' with
7635 7657 * a '\0'.
7636 7658 */
7637 7659 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
7638 7660 *aptr = '\0';
7639 7661 }
7640 7662
7641 7663 /*
7642 7664 * Now fill in the optional link section if we have one
7643 7665 */
7644 7666
7645 7667 if (linkinfo != (struct linkbuf *)NULL) {
7646 7668 tptr = (struct xattr_buf *)(bufhead +
7647 7669 sizeof (struct xattr_hdr) + complen);
7648 7670
7649 7671 (void) sprintf(tptr->h_namesz, "%0*d",
7650 7672 sizeof (tptr->h_namesz) - 1, linkstringlen);
7651 7673 (void) strcpy(tptr->h_names, linkinfo->pathname);
7652 7674 (void) strcpy(
7653 7675 &tptr->h_names[strlen(linkinfo->pathname) + 1],
7654 7676 linkinfo->attrname);
7655 7677 tptr->h_typeflag = typeflag;
7656 7678 }
7657 7679 *attrbuf = (char *)bufhead;
7658 7680 *rlen = len;
7659 7681 }
7660 7682
7661 7683 #else
7662 7684 static void
7663 7685 prepare_xattr(
7664 7686 char **attrbuf,
7665 7687 char *filename,
7666 7688 char *attrname,
7667 7689 char typeflag,
7668 7690 struct linkbuf *linkinfo,
7669 7691 int *rlen)
7670 7692 {
7671 7693 *attrbuf = NULL;
7672 7694 *rlen = 0;
7673 7695 }
7674 7696 #endif
7675 7697
7676 7698 int
7677 7699 getstat(int dirfd, char *longname, char *shortname, char *attrparent)
7678 7700 {
7679 7701
7680 7702 int i, j;
7681 7703 int printerr;
7682 7704 int slnkerr;
7683 7705 struct stat symlnbuf;
7684 7706
7685 7707 if (!hflag)
7686 7708 i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
7687 7709 else
7688 7710 i = fstatat(dirfd, shortname, &stbuf, 0);
7689 7711
7690 7712 if (i < 0) {
7691 7713 /* Initialize flag to print error mesg. */
7692 7714 printerr = 1;
7693 7715 /*
7694 7716 * If stat is done, then need to do lstat
7695 7717 * to determine whether it's a sym link
7696 7718 */
7697 7719 if (hflag) {
7698 7720 /* Save returned error */
7699 7721 slnkerr = errno;
7700 7722
7701 7723 j = fstatat(dirfd, shortname,
7702 7724 &symlnbuf, AT_SYMLINK_NOFOLLOW);
7703 7725 /*
7704 7726 * Suppress error message when file is a symbolic link
7705 7727 * and function modifier 'l' is off. Exception: when
7706 7728 * a symlink points to a symlink points to a
7707 7729 * symlink ... and we get past MAXSYMLINKS. That
7708 7730 * error will cause a file not to be archived, and
7709 7731 * needs to be printed.
7710 7732 */
7711 7733 if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
7712 7734 (S_ISLNK(symlnbuf.st_mode)))
7713 7735 printerr = 0;
7714 7736
7715 7737 /*
7716 7738 * Restore errno in case the lstat
7717 7739 * on symbolic link change
7718 7740 */
7719 7741 errno = slnkerr;
7720 7742 }
7721 7743
7722 7744 if (printerr) {
7723 7745 (void) fprintf(stderr, gettext(
7724 7746 "tar: %s%s%s%s: %s\n"),
7725 7747 (attrparent == NULL) ? "" : gettext("attribute "),
7726 7748 (attrparent == NULL) ? "" : attrparent,
7727 7749 (attrparent == NULL) ? "" : gettext(" of "),
7728 7750 longname, strerror(errno));
7729 7751 Errflg = 1;
7730 7752 }
7731 7753 return (1);
7732 7754 }
7733 7755 return (0);
7734 7756 }
7735 7757
7736 7758 /*
7737 7759 * Recursively archive the extended attributes and/or extended system attributes
7738 7760 * of the base file, longname. Note: extended system attribute files will be
7739 7761 * archived only if the extended system attributes are not transient (i.e. the
7740 7762 * extended system attributes are other than the default values).
7741 7763 *
7742 7764 * If -@ was specified and the underlying file system supports it, archive the
7743 7765 * extended attributes, and if there is a system attribute associated with the
7744 7766 * extended attribute, then recursively call xattrs_put() to archive the
7745 7767 * hidden attribute directory and the extended system attribute. If -/ was
7746 7768 * specified and the underlying file system supports it, archive the extended
7747 7769 * system attributes. Read-only extended system attributes are never archived.
7748 7770 *
7749 7771 * Currently, there cannot be attributes on attributes; only system
7750 7772 * attributes on attributes. In addition, there cannot be attributes on
7751 7773 * system attributes. A file and it's attribute directory hierarchy looks as
7752 7774 * follows:
7753 7775 * longname ----> . ("." is the hidden attribute directory)
7754 7776 * |
7755 7777 * ----------------------------
7756 7778 * | |
7757 7779 * <sys_attr_name> <attr_name> ----> .
7758 7780 * |
7759 7781 * <sys_attr_name>
7760 7782 *
7761 7783 */
7762 7784 #if defined(O_XATTR)
7763 7785 static void
7764 7786 xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
7765 7787 {
7766 7788 char *filename = (attrparent == NULL) ? shortname : attrparent;
7767 7789 int arc_rwsysattr = 0;
7768 7790 int dirfd;
7769 7791 int fd = -1;
7770 7792 int rw_sysattr = 0;
7771 7793 int ext_attr = 0;
7772 7794 int rc;
7773 7795 DIR *dirp;
7774 7796 struct dirent *dp;
7775 7797 attr_data_t *attrinfo = NULL;
7776 7798
7777 7799 /*
7778 7800 * If the underlying file system supports it, then archive the extended
7779 7801 * attributes if -@ was specified, and the extended system attributes
7780 7802 * if -/ was specified.
7781 7803 */
7782 7804 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
7783 7805 &ext_attr) != ATTR_OK) {
7784 7806 return;
7785 7807 }
7786 7808
7787 7809 /*
7788 7810 * Only want to archive a read-write extended system attribute file
7789 7811 * if it contains extended system attribute settings that are not the
7790 7812 * default values.
7791 7813 */
7792 7814 #if defined(_PC_SATTR_ENABLED)
7793 7815 if (saflag) {
7794 7816 int filefd;
7795 7817 nvlist_t *slist = NULL;
7796 7818
7797 7819 /* Determine if there are non-transient system attributes */
7798 7820 errno = 0;
7799 7821 if ((filefd = open(filename, O_RDONLY)) == -1) {
7800 7822 if (attrparent == NULL) {
7801 7823 vperror(0, gettext(
7802 7824 "unable to open file %s"), longname);
7803 7825 }
7804 7826 return;
7805 7827 }
7806 7828 if (((slist = sysattr_list(basename(myname), filefd,
7807 7829 filename)) != NULL) || (errno != 0)) {
7808 7830 arc_rwsysattr = 1;
7809 7831 }
7810 7832 if (slist != NULL) {
7811 7833 (void) nvlist_free(slist);
7812 7834 slist = NULL;
7813 7835 }
7814 7836 (void) close(filefd);
7815 7837 }
7816 7838
7817 7839 /*
7818 7840 * If we aren't archiving extended system attributes, and we are
7819 7841 * processing an attribute, or if we are archiving extended system
7820 7842 * attributes, and there are are no extended attributes, then there's
7821 7843 * no need to open up the attribute directory of the file unless the
7822 7844 * extended system attributes are not transient (i.e, the system
7823 7845 * attributes are not the default values).
7824 7846 */
7825 7847 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
7826 7848 (saflag && !ext_attr))) {
7827 7849 return;
7828 7850 }
7829 7851 #endif /* _PC_SATTR_ENABLED */
7830 7852
7831 7853 /* open the parent attribute directory */
7832 7854 fd = attropen(filename, ".", O_RDONLY);
7833 7855 if (fd < 0) {
7834 7856 vperror(0, gettext(
7835 7857 "unable to open attribute directory for %s%s%sfile %s"),
7836 7858 (attrparent == NULL) ? "" : gettext("attribute "),
7837 7859 (attrparent == NULL) ? "" : attrparent,
7838 7860 (attrparent == NULL) ? "" : gettext(" of "),
7839 7861 longname);
7840 7862 return;
7841 7863 }
7842 7864
7843 7865 /*
7844 7866 * We need to change into the parent's attribute directory to determine
7845 7867 * if each of the attributes should be archived.
7846 7868 */
7847 7869 if (fchdir(fd) < 0) {
7848 7870 vperror(0, gettext(
7849 7871 "cannot change to attribute directory of %s%s%sfile %s"),
7850 7872 (attrparent == NULL) ? "" : gettext("attribute "),
7851 7873 (attrparent == NULL) ? "" : attrparent,
7852 7874 (attrparent == NULL) ? "" : gettext(" of "),
7853 7875 longname);
7854 7876 (void) close(fd);
7855 7877 return;
7856 7878 }
7857 7879
7858 7880 if (((dirfd = dup(fd)) == -1) ||
7859 7881 ((dirp = fdopendir(dirfd)) == NULL)) {
7860 7882 (void) fprintf(stderr, gettext(
7861 7883 "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7862 7884 (attrparent == NULL) ? "" : gettext("attribute "),
7863 7885 (attrparent == NULL) ? "" : attrparent,
7864 7886 (attrparent == NULL) ? "" : gettext(" of "),
7865 7887 longname);
7866 7888 if (fd > 0) {
7867 7889 (void) close(fd);
7868 7890 }
7869 7891 return;
7870 7892 }
7871 7893
7872 7894 while (dp = readdir(dirp)) {
7873 7895 if (strcmp(dp->d_name, "..") == 0) {
7874 7896 continue;
7875 7897 } else if (strcmp(dp->d_name, ".") == 0) {
7876 7898 Hiddendir = 1;
7877 7899 } else {
7878 7900 Hiddendir = 0;
7879 7901 }
7880 7902
7881 7903 /* Determine if this attribute should be archived */
7882 7904 if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
7883 7905 &rw_sysattr) != ATTR_OK) {
7884 7906 continue;
7885 7907 }
7886 7908
7887 7909 /* gather the attribute's information to pass to putfile() */
7888 7910 if ((fill_in_attr_info(dp->d_name, longname, attrparent,
7889 7911 fd, rw_sysattr, &attrinfo)) == 1) {
7890 7912 continue;
7891 7913 }
7892 7914
7893 7915 /* add the attribute to the archive */
7894 7916 rc = putfile(longname, dp->d_name, parent, attrinfo,
7895 7917 XATTR_FILE, LEV0, SYMLINK_LEV0);
7896 7918
7897 7919 if (exitflag) {
7898 7920 break;
7899 7921 }
7900 7922
7901 7923 #if defined(_PC_SATTR_ENABLED)
7902 7924 /*
7903 7925 * If both -/ and -@ were specified, then archive the
7904 7926 * attribute's extended system attributes and hidden directory
7905 7927 * by making a recursive call to xattrs_put().
7906 7928 */
7907 7929 if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
7908 7930 (Hiddendir == 0)) {
7909 7931
7910 7932 xattrs_put(longname, shortname, parent, dp->d_name);
7911 7933
7912 7934 /*
7913 7935 * Change back to the parent's attribute directory
7914 7936 * to process any further attributes.
7915 7937 */
7916 7938 if (fchdir(fd) < 0) {
7917 7939 vperror(0, gettext(
7918 7940 "cannot change back to attribute directory "
7919 7941 "of file %s"), longname);
7920 7942 break;
7921 7943 }
7922 7944 }
7923 7945 #endif /* _PC_SATTR_ENABLED */
7924 7946 }
7925 7947
7926 7948 if (attrinfo != NULL) {
7927 7949 if (attrinfo->attr_parent != NULL) {
7928 7950 free(attrinfo->attr_parent);
7929 7951 }
7930 7952 free(attrinfo->attr_path);
7931 7953 free(attrinfo);
7932 7954 }
7933 7955 (void) closedir(dirp);
7934 7956 if (fd != -1) {
7935 7957 (void) close(fd);
7936 7958 }
7937 7959
7938 7960 /* Change back to the parent directory of the base file */
7939 7961 if (attrparent == NULL) {
7940 7962 (void) tar_chdir(parent);
7941 7963 }
7942 7964 Hiddendir = 0;
7943 7965 }
7944 7966 #else
7945 7967 static void
7946 7968 xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
7947 7969 {
7948 7970 }
7949 7971 #endif /* O_XATTR */
7950 7972
7951 7973 static int
7952 7974 put_link(char *name, char *longname, char *component, char *longattrname,
7953 7975 char *prefix, int filetype, char type)
7954 7976 {
7955 7977
7956 7978 if (stbuf.st_nlink > 1) {
7957 7979 struct linkbuf *lp;
7958 7980 int found = 0;
7959 7981
7960 7982 for (lp = ihead; lp != NULL; lp = lp->nextp)
7961 7983 if (lp->inum == stbuf.st_ino &&
7962 7984 lp->devnum == stbuf.st_dev) {
7963 7985 found++;
7964 7986 break;
7965 7987 }
7966 7988 if (found) {
7967 7989 #if defined(O_XATTR)
7968 7990 if (filetype == XATTR_FILE)
7969 7991 if (put_xattr_hdr(longname, component,
7970 7992 longattrname, prefix, type, filetype, lp)) {
7971 7993 goto out;
7972 7994 }
7973 7995 #endif
7974 7996 stbuf.st_size = (off_t)0;
7975 7997 if (filetype != XATTR_FILE) {
7976 7998 tomodes(&stbuf);
7977 7999 if (chk_path_build(name, longname, lp->pathname,
7978 8000 prefix, type, filetype) > 0) {
7979 8001 goto out;
7980 8002 }
7981 8003 }
7982 8004
7983 8005 if (mulvol && tapepos + 1 >= blocklim)
7984 8006 newvol();
7985 8007 (void) writetbuf((char *)&dblock, 1);
7986 8008 /*
7987 8009 * write_ancillary() is not needed here.
7988 8010 * The first link is handled in the following
7989 8011 * else statement. No need to process ACLs
7990 8012 * for other hard links since they are the
7991 8013 * same file.
7992 8014 */
7993 8015
7994 8016 if (vflag) {
7995 8017 #ifdef DEBUG
7996 8018 if (NotTape)
7997 8019 DEBUG("seek = %" FMT_blkcnt_t
7998 8020 "K\t", K(tapepos), 0);
7999 8021 #endif
8000 8022 if (filetype == XATTR_FILE) {
8001 8023 (void) fprintf(vfile, gettext(
8002 8024 "a %s attribute %s link to "
8003 8025 "%s attribute %s\n"),
8004 8026 name, component, name,
8005 8027 lp->attrname);
8006 8028 } else {
8007 8029 (void) fprintf(vfile, gettext(
8008 8030 "a %s link to %s\n"),
8009 8031 longname, lp->pathname);
8010 8032 }
8011 8033 }
8012 8034 lp->count--;
8013 8035 return (0);
8014 8036 } else {
8015 8037 lp = (struct linkbuf *)getmem(sizeof (*lp));
8016 8038 if (lp != (struct linkbuf *)NULL) {
8017 8039 lp->nextp = ihead;
8018 8040 ihead = lp;
8019 8041 lp->inum = stbuf.st_ino;
8020 8042 lp->devnum = stbuf.st_dev;
8021 8043 lp->count = stbuf.st_nlink - 1;
8022 8044 if (filetype == XATTR_FILE) {
8023 8045 (void) strcpy(lp->pathname, longname);
8024 8046 (void) strcpy(lp->attrname,
8025 8047 component);
8026 8048 } else {
8027 8049 (void) strcpy(lp->pathname, longname);
8028 8050 (void) strcpy(lp->attrname, "");
8029 8051 }
8030 8052 }
8031 8053 }
8032 8054 }
8033 8055
8034 8056 out:
8035 8057 return (1);
8036 8058 }
8037 8059
8038 8060 static int
8039 8061 put_extra_attributes(char *longname, char *shortname, char *longattrname,
8040 8062 char *prefix, int filetype, char typeflag)
8041 8063 {
8042 8064 static acl_t *aclp = NULL;
8043 8065 int error;
8044 8066
8045 8067 if (aclp != NULL) {
8046 8068 acl_free(aclp);
8047 8069 aclp = NULL;
8048 8070 }
8049 8071 #if defined(O_XATTR)
8050 8072 if ((atflag || saflag) && (filetype == XATTR_FILE)) {
8051 8073 if (put_xattr_hdr(longname, shortname, longattrname, prefix,
8052 8074 typeflag, filetype, NULL)) {
8053 8075 return (1);
8054 8076 }
8055 8077 }
8056 8078 #endif
8057 8079
8058 8080 /* ACL support */
8059 8081 if (pflag) {
8060 8082 char *secinfo = NULL;
8061 8083 int len = 0;
8062 8084
8063 8085 /* ACL support */
8064 8086 if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
8065 8087 /*
8066 8088 * Get ACL info: dont bother allocating space if
8067 8089 * there is only a trivial ACL.
8068 8090 */
8069 8091 if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
8070 8092 &aclp)) != 0) {
8071 8093 (void) fprintf(stderr, gettext(
8072 8094 "%s: failed to retrieve acl : %s\n"),
8073 8095 longname, acl_strerror(error));
8074 8096 return (1);
8075 8097 }
8076 8098 }
8077 8099
8078 8100 /* append security attributes if any */
8079 8101 if (aclp != NULL) {
8080 8102 (void) append_secattr(&secinfo, &len, acl_cnt(aclp),
8081 8103 acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8082 8104 ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
8083 8105 UFSD_ACL : ACE_ACL);
8084 8106 }
8085 8107
8086 8108 if (Tflag) {
8087 8109 /* append Trusted Extensions extended attributes */
8088 8110 append_ext_attr(shortname, &secinfo, &len);
8089 8111 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8090 8112
8091 8113 } else if (aclp != NULL) {
8092 8114 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8093 8115 }
8094 8116 }
8095 8117 return (0);
8096 8118 }
8097 8119
8098 8120 #if defined(O_XATTR)
8099 8121 static int
8100 8122 put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
8101 8123 int typeflag, int filetype, struct linkbuf *lp)
8102 8124 {
8103 8125 char *lname = NULL;
8104 8126 char *sname = NULL;
8105 8127 int error = 0;
8106 8128 static char *attrbuf = NULL;
8107 8129 int attrlen;
8108 8130
8109 8131 lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
8110 8132 strlen(shortname) + strlen(".hdr") + 1);
8111 8133
8112 8134 if (lname == NULL) {
8113 8135 fatal(gettext("Out of Memory."));
8114 8136 }
8115 8137 sname = malloc(sizeof (char) * strlen(shortname) +
8116 8138 strlen(".hdr") + 1);
8117 8139 if (sname == NULL) {
8118 8140 fatal(gettext("Out of Memory."));
8119 8141 }
8120 8142
8121 8143 (void) sprintf(sname, "%s.hdr", shortname);
8122 8144 (void) sprintf(lname, "/dev/null/%s", sname);
8123 8145
8124 8146 if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
8125 8147 sizeof (dblock.dbuf.name)) {
8126 8148 fatal(gettext(
8127 8149 "Buffer overflow writing extended attribute file name"));
8128 8150 }
8129 8151
8130 8152 /*
8131 8153 * dump extended attr lookup info
8132 8154 */
8133 8155 prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
8134 8156 write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
8135 8157
8136 8158 (void) sprintf(lname, "/dev/null/%s", shortname);
8137 8159 (void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
8138 8160
8139 8161 /*
8140 8162 * Set up filename for attribute
8141 8163 */
8142 8164
8143 8165 error = build_dblock(lname, tchar, '0', filetype,
8144 8166 &stbuf, stbuf.st_dev, prefix);
8145 8167 free(lname);
8146 8168 free(sname);
8147 8169
8148 8170 return (error);
8149 8171 }
8150 8172 #endif
8151 8173
8152 8174 #if defined(O_XATTR)
8153 8175 static int
8154 8176 read_xattr_hdr(attr_data_t **attrinfo)
8155 8177 {
8156 8178 char buf[TBLOCK];
8157 8179 char *attrparent = NULL;
8158 8180 blkcnt_t blocks;
8159 8181 char *tp;
8160 8182 off_t bytes;
8161 8183 int comp_len, link_len;
8162 8184 int namelen;
8163 8185 int attrparentlen;
8164 8186 int parentfilelen;
8165 8187
8166 8188 if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
8167 8189 return (1);
8168 8190
8169 8191 bytes = stbuf.st_size;
8170 8192 if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
8171 8193 (void) fprintf(stderr, gettext(
8172 8194 "Insufficient memory for extended attribute\n"));
8173 8195 return (1);
8174 8196 }
8175 8197
8176 8198 tp = (char *)xattrhead;
8177 8199 blocks = TBLOCKS(bytes);
8178 8200 while (blocks-- > 0) {
8179 8201 readtape(buf);
8180 8202 if (bytes <= TBLOCK) {
8181 8203 (void) memcpy(tp, buf, (size_t)bytes);
8182 8204 break;
8183 8205 } else {
8184 8206 (void) memcpy(tp, buf, TBLOCK);
8185 8207 tp += TBLOCK;
8186 8208 }
8187 8209 bytes -= TBLOCK;
8188 8210 }
8189 8211
8190 8212 /*
8191 8213 * Validate that we can handle header format
8192 8214 */
8193 8215 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8194 8216 (void) fprintf(stderr,
8195 8217 gettext("Unknown extended attribute format encountered\n"));
8196 8218 (void) fprintf(stderr,
8197 8219 gettext("Disabling extended attribute parsing\n"));
8198 8220 xattrbadhead = 1;
8199 8221 return (0);
8200 8222 }
8201 8223 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8202 8224 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8203 8225 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8204 8226 sizeof (struct xattr_hdr));
8205 8227 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8206 8228 if (link_len > 0)
8207 8229 xattr_linkp = (struct xattr_buf *)
8208 8230 ((int)xattrp + (int)comp_len);
8209 8231 else
8210 8232 xattr_linkp = NULL;
8211 8233
8212 8234 /*
8213 8235 * Gather the attribute path from the filename and attrnames section.
8214 8236 * The filename and attrnames section can be composed of two or more
8215 8237 * path segments separated by a null character. The first segment
8216 8238 * is the path to the parent file that roots the entire sequence in
8217 8239 * the normal name space. The remaining segments describes a path
8218 8240 * rooted at the hidden extended attribute directory of the leaf file of
8219 8241 * the previous segment, making it possible to name attributes on
8220 8242 * attributes.
8221 8243 */
8222 8244 parentfilelen = strlen(xattrp->h_names);
8223 8245 xattrapath = xattrp->h_names + parentfilelen + 1;
8224 8246 if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
8225 8247 /*
8226 8248 * The attrnames section contains a system attribute on an
8227 8249 * attribute. Save the name of the attribute for use later,
8228 8250 * and replace the null separating the attribute name from
8229 8251 * the system attribute name with a '/' so that xattrapath can
8230 8252 * be used to display messages with the full attribute path name
8231 8253 * rooted at the hidden attribute directory of the base file
8232 8254 * in normal name space.
8233 8255 */
8234 8256 attrparent = strdup(xattrapath);
8235 8257 attrparentlen = strlen(attrparent);
8236 8258 xattrapath[attrparentlen] = '/';
8237 8259 }
8238 8260 if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
8239 8261 xattrapath + attrparentlen + 1, xattrapath, attrparent,
8240 8262 -1, 0, attrinfo)) == 1) {
8241 8263 free(attrparent);
8242 8264 return (1);
8243 8265 }
8244 8266
8245 8267 /* Gather link info */
8246 8268 if (xattr_linkp) {
8247 8269 xattr_linkaname = xattr_linkp->h_names +
8248 8270 strlen(xattr_linkp->h_names) + 1;
8249 8271 } else {
8250 8272 xattr_linkaname = NULL;
8251 8273 }
8252 8274
8253 8275 return (0);
8254 8276 }
8255 8277 #else
8256 8278 static int
8257 8279 read_xattr_hdr(attr_data_t **attrinfo)
8258 8280 {
8259 8281 return (0);
8260 8282 }
8261 8283 #endif
8262 8284
8263 8285 /*
8264 8286 * skip over extra slashes in string.
8265 8287 *
8266 8288 * For example:
8267 8289 * /usr/tmp/////
8268 8290 *
8269 8291 * would return pointer at
8270 8292 * /usr/tmp/////
8271 8293 * ^
8272 8294 */
8273 8295 static char *
8274 8296 skipslashes(char *string, char *start)
8275 8297 {
8276 8298 while ((string > start) && *(string - 1) == '/') {
8277 8299 string--;
8278 8300 }
8279 8301
8280 8302 return (string);
8281 8303 }
8282 8304
8283 8305 /*
8284 8306 * Return the parent directory of a given path.
8285 8307 *
8286 8308 * Examples:
8287 8309 * /usr/tmp return /usr
8288 8310 * /usr/tmp/file return /usr/tmp
8289 8311 * / returns .
8290 8312 * /usr returns /
8291 8313 * file returns .
8292 8314 *
8293 8315 * dir is assumed to be at least as big as path.
8294 8316 */
8295 8317 static void
8296 8318 get_parent(char *path, char *dir)
8297 8319 {
8298 8320 char *s;
8299 8321 char tmpdir[PATH_MAX + 1];
8300 8322
8301 8323 if (strlen(path) > PATH_MAX) {
8302 8324 fatal(gettext("pathname is too long"));
8303 8325 }
8304 8326 (void) strcpy(tmpdir, path);
8305 8327 chop_endslashes(tmpdir);
8306 8328
8307 8329 if ((s = strrchr(tmpdir, '/')) == NULL) {
8308 8330 (void) strcpy(dir, ".");
8309 8331 } else {
8310 8332 s = skipslashes(s, tmpdir);
8311 8333 *s = '\0';
8312 8334 if (s == tmpdir)
8313 8335 (void) strcpy(dir, "/");
8314 8336 else
8315 8337 (void) strcpy(dir, tmpdir);
8316 8338 }
8317 8339 }
8318 8340
8319 8341 #if defined(O_XATTR)
8320 8342 static char *
8321 8343 get_component(char *path)
8322 8344 {
8323 8345 char *ptr;
8324 8346
8325 8347 ptr = strrchr(path, '/');
8326 8348 if (ptr == NULL) {
8327 8349 return (path);
8328 8350 } else {
8329 8351 /*
8330 8352 * Handle trailing slash
8331 8353 */
8332 8354 if (*(ptr + 1) == '\0')
8333 8355 return (ptr);
8334 8356 else
8335 8357 return (ptr + 1);
8336 8358 }
8337 8359 }
8338 8360 #else
8339 8361 static char *
8340 8362 get_component(char *path)
8341 8363 {
8342 8364 return (path);
8343 8365 }
8344 8366 #endif
8345 8367
8346 8368 #if defined(O_XATTR)
8347 8369 static int
8348 8370 retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
8349 8371 int oflag, mode_t mode)
8350 8372 {
8351 8373 int dirfd;
8352 8374 int ofilefd = -1;
8353 8375 struct timeval times[2];
8354 8376 mode_t newmode;
8355 8377 struct stat parentstat;
8356 8378 acl_t *aclp = NULL;
8357 8379 int error;
8358 8380
8359 8381 /*
8360 8382 * We couldn't get to attrdir. See if its
8361 8383 * just a mode problem on the parent file.
8362 8384 * for example: a mode such as r-xr--r--
8363 8385 * on a ufs file system without extended
8364 8386 * system attribute support won't let us
8365 8387 * create an attribute dir if it doesn't
8366 8388 * already exist, and on a ufs file system
8367 8389 * with extended system attribute support
8368 8390 * won't let us open the attribute for
8369 8391 * write.
8370 8392 *
8371 8393 * If file has a non-trivial ACL, then save it
8372 8394 * off so that we can place it back on after doing
8373 8395 * chmod's.
8374 8396 */
8375 8397 if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
8376 8398 O_RDONLY)) == -1) {
8377 8399 return (-1);
8378 8400 }
8379 8401 if (fstat(dirfd, &parentstat) == -1) {
8380 8402 (void) fprintf(stderr, gettext(
8381 8403 "tar: cannot stat %sfile %s: %s\n"),
8382 8404 (pdirfd == -1) ? "" : gettext("parent of "),
8383 8405 (pdirfd == -1) ? dirp : name, strerror(errno));
8384 8406 return (-1);
8385 8407 }
8386 8408 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
8387 8409 (void) fprintf(stderr, gettext(
8388 8410 "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8389 8411 (pdirfd == -1) ? "" : gettext("parent of "),
8390 8412 (pdirfd == -1) ? dirp : name, strerror(errno));
8391 8413 return (-1);
8392 8414 }
8393 8415
8394 8416 newmode = S_IWUSR | parentstat.st_mode;
8395 8417 if (fchmod(dirfd, newmode) == -1) {
8396 8418 (void) fprintf(stderr,
8397 8419 gettext(
8398 8420 "tar: cannot fchmod %sfile %s to %o: %s\n"),
8399 8421 (pdirfd == -1) ? "" : gettext("parent of "),
8400 8422 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8401 8423 if (aclp)
8402 8424 acl_free(aclp);
8403 8425 return (-1);
8404 8426 }
8405 8427
8406 8428
8407 8429 if (pdirfd == -1) {
8408 8430 /*
8409 8431 * We weren't able to create the attribute directory before.
8410 8432 * Now try again.
8411 8433 */
8412 8434 ofilefd = attropen(dirp, ".", oflag);
8413 8435 } else {
8414 8436 /*
8415 8437 * We weren't able to create open the attribute before.
8416 8438 * Now try again.
8417 8439 */
8418 8440 ofilefd = openat(pdirfd, name, oflag, mode);
8419 8441 }
8420 8442
8421 8443 /*
8422 8444 * Put mode back to original
8423 8445 */
8424 8446 if (fchmod(dirfd, parentstat.st_mode) == -1) {
8425 8447 (void) fprintf(stderr,
8426 8448 gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8427 8449 (pdirfd == -1) ? "" : gettext("parent of "),
8428 8450 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8429 8451 }
8430 8452
8431 8453 if (aclp) {
8432 8454 error = facl_set(dirfd, aclp);
8433 8455 if (error) {
8434 8456 (void) fprintf(stderr,
8435 8457 gettext("tar: failed to set acl entries on "
8436 8458 "%sfile %s\n"),
8437 8459 (pdirfd == -1) ? "" : gettext("parent of "),
8438 8460 (pdirfd == -1) ? dirp : name);
8439 8461 }
8440 8462 acl_free(aclp);
8441 8463 }
8442 8464
8443 8465 /*
8444 8466 * Put back time stamps
8445 8467 */
8446 8468
8447 8469 times[0].tv_sec = parentstat.st_atime;
8448 8470 times[0].tv_usec = 0;
8449 8471 times[1].tv_sec = parentstat.st_mtime;
8450 8472 times[1].tv_usec = 0;
8451 8473
8452 8474 (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
8453 8475
8454 8476 (void) close(dirfd);
8455 8477
8456 8478 return (ofilefd);
8457 8479 }
8458 8480 #endif
8459 8481
8460 8482 #if !defined(O_XATTR)
8461 8483 static int
8462 8484 openat64(int fd, const char *name, int oflag, mode_t cmode)
8463 8485 {
8464 8486 return (open64(name, oflag, cmode));
8465 8487 }
8466 8488
8467 8489 static int
8468 8490 openat(int fd, const char *name, int oflag, mode_t cmode)
8469 8491 {
8470 8492 return (open(name, oflag, cmode));
8471 8493 }
8472 8494
8473 8495 static int
8474 8496 fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
8475 8497 {
8476 8498 if (flag == AT_SYMLINK_NOFOLLOW)
8477 8499 return (lchown(name, owner, group));
8478 8500 else
8479 8501 return (chown(name, owner, group));
8480 8502 }
8481 8503
8482 8504 static int
8483 8505 renameat(int fromfd, char *old, int tofd, char *new)
8484 8506 {
8485 8507 return (rename(old, new));
8486 8508 }
8487 8509
8488 8510 static int
8489 8511 futimesat(int fd, char *path, struct timeval times[2])
8490 8512 {
8491 8513 return (utimes(path, times));
8492 8514 }
8493 8515
8494 8516 static int
8495 8517 unlinkat(int dirfd, char *path, int flag)
8496 8518 {
8497 8519 if (flag == AT_REMOVEDIR)
8498 8520 return (rmdir(path));
8499 8521 else
8500 8522 return (unlink(path));
8501 8523 }
8502 8524
8503 8525 static int
8504 8526 fstatat(int fd, char *path, struct stat *buf, int flag)
8505 8527 {
8506 8528 if (flag == AT_SYMLINK_NOFOLLOW)
8507 8529 return (lstat(path, buf));
8508 8530 else
8509 8531 return (stat(path, buf));
8510 8532 }
8511 8533
8512 8534 static int
8513 8535 attropen(char *file, char *attr, int omode, mode_t cmode)
8514 8536 {
8515 8537 errno = ENOTSUP;
8516 8538 return (-1);
8517 8539 }
8518 8540 #endif
8519 8541
8520 8542 static void
8521 8543 chop_endslashes(char *path)
8522 8544 {
8523 8545 char *end, *ptr;
8524 8546
8525 8547 /*
8526 8548 * Chop of slashes, but not if all we have is slashes
8527 8549 * for example: ////
8528 8550 * should make no changes, otherwise it will screw up
8529 8551 * checkdir
8530 8552 */
8531 8553 end = &path[strlen(path) -1];
8532 8554 if (*end == '/' && end != path) {
8533 8555 ptr = skipslashes(end, path);
8534 8556 if (ptr != NULL && ptr != path) {
8535 8557 *ptr = '\0';
8536 8558 }
8537 8559 }
8538 8560 }
8539 8561 /* Trusted Extensions */
8540 8562
8541 8563 /*
8542 8564 * append_ext_attr():
8543 8565 *
8544 8566 * Append extended attributes and other information into the buffer
8545 8567 * that gets written to the ancillary file.
8546 8568 *
8547 8569 * With option 'T', we create a tarfile which
8548 8570 * has an ancillary file each corresponding archived file.
8549 8571 * Each ancillary file contains 1 or more of the
8550 8572 * following attributes:
8551 8573 *
8552 8574 * attribute type attribute process procedure
8553 8575 * ---------------- ---------------- --------------------------
8554 8576 * DIR_TYPE = 'D' directory flag append if a directory
8555 8577 * LBL_TYPE = 'L' SL[IL] or SL append ascii label
8556 8578 *
8557 8579 *
8558 8580 */
8559 8581 static void
8560 8582 append_ext_attr(char *shortname, char **secinfo, int *len)
8561 8583 {
8562 8584 bslabel_t b_slabel; /* binary sensitvity label */
8563 8585 char *ascii = NULL; /* ascii label */
8564 8586
8565 8587 /*
8566 8588 * For each attribute type, append it if it is
8567 8589 * relevant to the file type.
8568 8590 */
8569 8591
8570 8592 /*
8571 8593 * For attribute type DIR_TYPE,
8572 8594 * append it to the following file type:
8573 8595 *
8574 8596 * S_IFDIR: directories
8575 8597 */
8576 8598
8577 8599 /*
8578 8600 * For attribute type LBL_TYPE,
8579 8601 * append it to the following file type:
8580 8602 *
8581 8603 * S_IFDIR: directories (including mld, sld)
8582 8604 * S_IFLNK: symbolic link
8583 8605 * S_IFREG: regular file but not hard link
8584 8606 * S_IFIFO: FIFO file but not hard link
8585 8607 * S_IFCHR: char special file but not hard link
8586 8608 * S_IFBLK: block special file but not hard link
8587 8609 */
8588 8610 switch (stbuf.st_mode & S_IFMT) {
8589 8611
8590 8612 case S_IFDIR:
8591 8613
8592 8614 /*
8593 8615 * append DIR_TYPE
8594 8616 */
8595 8617 (void) append_secattr(secinfo, len, 1,
8596 8618 "\0", DIR_TYPE);
8597 8619
8598 8620 /*
8599 8621 * Get and append attribute types LBL_TYPE.
8600 8622 * For directories, LBL_TYPE contains SL.
8601 8623 */
8602 8624 /* get binary sensitivity label */
8603 8625 if (getlabel(shortname, &b_slabel) != 0) {
8604 8626 (void) fprintf(stderr,
8605 8627 gettext("tar: can't get sensitvity label for "
8606 8628 " %s, getlabel() error: %s\n"),
8607 8629 shortname, strerror(errno));
8608 8630 } else {
8609 8631 /* get ascii SL */
8610 8632 if (bsltos(&b_slabel, &ascii,
8611 8633 0, 0) <= 0) {
8612 8634 (void) fprintf(stderr,
8613 8635 gettext("tar: can't get ascii SL for"
8614 8636 " %s\n"), shortname);
8615 8637 } else {
8616 8638 /* append LBL_TYPE */
8617 8639 (void) append_secattr(secinfo, len,
8618 8640 strlen(ascii) + 1, ascii,
8619 8641 LBL_TYPE);
8620 8642
8621 8643 /* free storage */
8622 8644 if (ascii != NULL) {
8623 8645 free(ascii);
8624 8646 ascii = (char *)0;
8625 8647 }
8626 8648 }
8627 8649
8628 8650 }
8629 8651 break;
8630 8652
8631 8653 case S_IFLNK:
8632 8654 case S_IFREG:
8633 8655 case S_IFIFO:
8634 8656 case S_IFCHR:
8635 8657 case S_IFBLK:
8636 8658
8637 8659 /* get binary sensitivity label */
8638 8660 if (getlabel(shortname, &b_slabel) != 0) {
8639 8661 (void) fprintf(stderr,
8640 8662 gettext("tar: can't get sensitivty label for %s, "
8641 8663 "getlabel() error: %s\n"),
8642 8664 shortname, strerror(errno));
8643 8665 } else {
8644 8666 /* get ascii IL[SL] */
8645 8667 if (bsltos(&b_slabel, &ascii, 0, 0) <= 0) {
8646 8668 (void) fprintf(stderr,
8647 8669 gettext("tar: can't translate sensitivity "
8648 8670 " label for %s\n"), shortname);
8649 8671 } else {
8650 8672 char *cmw_label;
8651 8673 size_t cmw_length;
8652 8674
8653 8675 cmw_length = strlen("ADMIN_LOW [] ") +
8654 8676 strlen(ascii);
8655 8677 if ((cmw_label = malloc(cmw_length)) == NULL) {
8656 8678 (void) fprintf(stderr, gettext(
8657 8679 "Insufficient memory for label\n"));
8658 8680 exit(1);
8659 8681 }
8660 8682 /* append LBL_TYPE */
8661 8683 (void) snprintf(cmw_label, cmw_length,
8662 8684 "ADMIN_LOW [%s]", ascii);
8663 8685 (void) append_secattr(secinfo, len,
8664 8686 strlen(cmw_label) + 1, cmw_label,
8665 8687 LBL_TYPE);
8666 8688
8667 8689 /* free storage */
8668 8690 if (ascii != NULL) {
8669 8691 free(cmw_label);
8670 8692 free(ascii);
8671 8693 ascii = (char *)0;
8672 8694 }
8673 8695 }
8674 8696 }
8675 8697 break;
8676 8698
8677 8699 default:
8678 8700 break;
8679 8701 } /* end switch for LBL_TYPE */
8680 8702
8681 8703
8682 8704 /* DONE !! */
8683 8705 return;
8684 8706
8685 8707 } /* end of append_ext_attr */
8686 8708
8687 8709
8688 8710 /*
8689 8711 * Name: extract_attr()
8690 8712 *
8691 8713 * Description:
8692 8714 * Process attributes from the ancillary file due to
8693 8715 * the T option.
8694 8716 *
8695 8717 * Call by doxtract() as part of the switch case structure.
8696 8718 * Making this a separate routine because the nesting are too
8697 8719 * deep in doxtract, thus, leaving very little space
8698 8720 * on each line for instructions.
8699 8721 *
8700 8722 * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
8701 8723 *
8702 8724 * For option 'T', following are possible attributes in
8703 8725 * a TS 8 ancillary file: (NOTE: No IL support)
8704 8726 *
8705 8727 * attribute type attribute process procedure
8706 8728 * ---------------- ---------------- -------------------------
8707 8729 * # LBL_TYPE = 'L' SL construct binary label
8708 8730 * # APRIV_TYPE = 'P' allowed priv construct privileges
8709 8731 * # FPRIV_TYPE = 'p' forced priv construct privileges
8710 8732 * # COMP_TYPE = 'C' path component construct real path
8711 8733 * # DIR_TYPE = 'D' directory flag note it is a directory
8712 8734 * $ UFSD_ACL = '1' ACL data construct ACL entries
8713 8735 * ATTR_FLAG_TYPE = 'F' file attr flags construct binary flags
8714 8736 * LK_COMP_TYPE = 'K' linked path comp construct linked real path
8715 8737 *
8716 8738 * note: # = attribute names common between TS 8 & TS 2.5 ancillary
8717 8739 * files.
8718 8740 * $ = ACL attribute is processed for the option 'p', it doesn't
8719 8741 * need option 'T'.
8720 8742 *
8721 8743 * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
8722 8744 *
8723 8745 */
8724 8746 static void
8725 8747 extract_attr(char **file_ptr, struct sec_attr *attr)
8726 8748 {
8727 8749 int reterr, err;
8728 8750 char *dummy_buf; /* for attribute extract */
8729 8751
8730 8752 dummy_buf = attr->attr_info;
8731 8753
8732 8754 switch (attr->attr_type) {
8733 8755
8734 8756 case DIR_TYPE:
8735 8757
8736 8758 dir_flag++;
8737 8759 break;
8738 8760
8739 8761 case LBL_TYPE:
8740 8762
8741 8763 /*
8742 8764 * LBL_TYPE is used to indicate SL for directory, and
8743 8765 * CMW label for other file types.
8744 8766 */
8745 8767
8746 8768 if (!dir_flag) { /* not directory */
8747 8769 /* Skip over IL portion */
8748 8770 char *sl_ptr = strchr(dummy_buf, '[');
8749 8771
8750 8772 if (sl_ptr == NULL)
8751 8773 err = 0;
8752 8774 else
8753 8775 err = stobsl(sl_ptr, &bs_label,
8754 8776 NEW_LABEL, &reterr);
8755 8777 } else { /* directory */
8756 8778 err = stobsl(dummy_buf, &bs_label,
8757 8779 NEW_LABEL, &reterr);
8758 8780 }
8759 8781 if (err == 0) {
8760 8782 (void) fprintf(stderr, gettext("tar: "
8761 8783 "can't convert %s to binary label\n"),
8762 8784 dummy_buf);
8763 8785 bslundef(&bs_label);
8764 8786 } else if (!blequal(&bs_label, &admin_low) &&
8765 8787 !blequal(&bs_label, &admin_high)) {
8766 8788 bslabel_t *from_label;
8767 8789 char *buf;
8768 8790 char tempbuf[MAXPATHLEN];
8769 8791
8770 8792 if (*orig_namep != '/') {
8771 8793 /* got relative linked to path */
8772 8794 (void) getcwd(tempbuf, (sizeof (tempbuf)));
8773 8795 (void) strncat(tempbuf, "/", MAXPATHLEN);
8774 8796 } else
8775 8797 *tempbuf = '\0';
8776 8798
8777 8799 buf = real_path;
8778 8800 (void) strncat(tempbuf, orig_namep, MAXPATHLEN);
8779 8801 from_label = getlabelbypath(tempbuf);
8780 8802 if (from_label != NULL) {
8781 8803 if (blequal(from_label, &admin_low)) {
8782 8804 if ((getpathbylabel(tempbuf, buf,
8783 8805 MAXPATHLEN, &bs_label) == NULL)) {
8784 8806 (void) fprintf(stderr,
8785 8807 gettext("tar: "
8786 8808 "can't get zone root path for "
8787 8809 "%s\n"), tempbuf);
8788 8810 } else
8789 8811 rpath_flag = 1;
8790 8812 }
8791 8813 free(from_label);
8792 8814 }
8793 8815 }
8794 8816 break;
8795 8817
8796 8818 case COMP_TYPE:
8797 8819
8798 8820 rebuild_comp_path(dummy_buf, file_ptr);
8799 8821 break;
8800 8822
8801 8823 case LK_COMP_TYPE:
8802 8824
8803 8825 if (rebuild_lk_comp_path(dummy_buf, file_ptr)
8804 8826 == 0) {
8805 8827 lk_rpath_flag = 1;
8806 8828 } else {
8807 8829 (void) fprintf(stderr, gettext("tar: warning: link's "
8808 8830 "target pathname might be invalid.\n"));
8809 8831 lk_rpath_flag = 0;
8810 8832 }
8811 8833 break;
8812 8834 case APRIV_TYPE:
8813 8835 ignored_aprivs++;
8814 8836 break;
8815 8837 case FPRIV_TYPE:
8816 8838 ignored_fprivs++;
8817 8839 break;
8818 8840 case ATTR_FLAG_TYPE:
8819 8841 ignored_fattrs++;
8820 8842 break;
8821 8843
8822 8844 default:
8823 8845
8824 8846 break;
8825 8847 }
8826 8848
8827 8849 /* done */
8828 8850 return;
8829 8851
8830 8852 } /* end extract_attr */
8831 8853
8832 8854
8833 8855
8834 8856 /*
8835 8857 * Name: rebuild_comp_path()
8836 8858 *
8837 8859 * Description:
8838 8860 * Take the string of components passed down by the calling
8839 8861 * routine and parse the values and rebuild the path.
8840 8862 * This routine no longer needs to produce a new real_path
8841 8863 * string because it is produced when the 'L' LABEL_TYPE is
8842 8864 * interpreted. So the only thing done here is to distinguish
8843 8865 * between an SLD and an MLD entry. We only want one, so we
8844 8866 * ignore the MLD entry by setting the mld_flag.
8845 8867 *
8846 8868 * return value:
8847 8869 * none
8848 8870 */
8849 8871 static void
8850 8872 rebuild_comp_path(char *str, char **namep)
8851 8873 {
8852 8874 char *cp;
8853 8875
8854 8876 while (*str != '\0') {
8855 8877
8856 8878 switch (*str) {
8857 8879
8858 8880 case MLD_TYPE:
8859 8881
8860 8882 str++;
8861 8883 if ((cp = strstr(str, ";;")) != NULL) {
8862 8884 *cp = '\0';
8863 8885 str = cp + 2;
8864 8886 *cp = ';';
8865 8887 }
8866 8888 mld_flag = 1;
8867 8889 break;
8868 8890
8869 8891 case SLD_TYPE:
8870 8892
8871 8893 str++;
8872 8894 if ((cp = strstr(str, ";;")) != NULL) {
8873 8895 *cp = '\0';
8874 8896 str = cp + 2;
8875 8897 *cp = ';';
8876 8898 }
8877 8899 mld_flag = 0;
8878 8900 break;
8879 8901
8880 8902 case PATH_TYPE:
8881 8903
8882 8904 str++;
8883 8905 if ((cp = strstr(str, ";;")) != NULL) {
8884 8906 *cp = '\0';
8885 8907 str = cp + 2;
8886 8908 *cp = ';';
8887 8909 }
8888 8910 break;
8889 8911 }
8890 8912 }
8891 8913 if (rpath_flag)
8892 8914 *namep = real_path;
8893 8915 return;
8894 8916
8895 8917 } /* end rebuild_comp_path() */
8896 8918
8897 8919 /*
8898 8920 * Name: rebuild_lk_comp_path()
8899 8921 *
8900 8922 * Description:
8901 8923 * Take the string of components passed down by the calling
8902 8924 * routine and parse the values and rebuild the path.
8903 8925 *
8904 8926 * return value:
8905 8927 * 0 = succeeded
8906 8928 * -1 = failed
8907 8929 */
8908 8930 static int
8909 8931 rebuild_lk_comp_path(char *str, char **namep)
8910 8932 {
8911 8933 char *cp;
8912 8934 int reterr;
8913 8935 bslabel_t bslabel;
8914 8936 char *buf;
8915 8937 char pbuf[MAXPATHLEN];
8916 8938 char *ptr1, *ptr2;
8917 8939 int plen;
8918 8940 int use_pbuf;
8919 8941 char tempbuf[MAXPATHLEN];
8920 8942 int mismatch;
8921 8943 bslabel_t *from_label;
8922 8944 char zonename[ZONENAME_MAX];
8923 8945 zoneid_t zoneid;
8924 8946
8925 8947 /* init stuff */
8926 8948 use_pbuf = 0;
8927 8949 mismatch = 0;
8928 8950
8929 8951 /*
8930 8952 * For linked to pathname (LK_COMP_TYPE):
8931 8953 * - If the linked to pathname is absolute (start with /), we
8932 8954 * will use it as is.
8933 8955 * - If it is a relative pathname then it is relative to 1 of 2
8934 8956 * directories. For a hardlink, it is relative to the current
8935 8957 * directory. For a symbolic link, it is relative to the
8936 8958 * directory the symbolic link is in. For the symbolic link
8937 8959 * case, set a flag to indicate we need to use the prefix of
8938 8960 * the restored file's pathname with the linked to pathname.
8939 8961 *
8940 8962 * NOTE: At this point, we have no way to determine if we have
8941 8963 * a hardlink or a symbolic link. We will compare the 1st
8942 8964 * component in the prefix portion of the restore file's
8943 8965 * pathname to the 1st component in the attribute data
8944 8966 * (the linked pathname). If they are the same, we will assume
8945 8967 * the link pathname to reconstruct is relative to the current
8946 8968 * directory. Otherwise, we will set a flag indicate we need
8947 8969 * to use a prefix with the reconstructed name. Need to compare
8948 8970 * both the adorned and unadorned version before deciding a
8949 8971 * mismatch.
8950 8972 */
8951 8973
8952 8974 buf = lk_real_path;
8953 8975 if (*(str + 1) != '/') { /* got relative linked to path */
8954 8976 ptr1 = orig_namep;
8955 8977 ptr2 = strrchr(ptr1, '/');
8956 8978 plen = ptr2 - ptr1;
8957 8979 if (plen > 0) {
8958 8980 pbuf[0] = '\0';
8959 8981 plen++; /* include '/' */
8960 8982 (void) strncpy(pbuf, ptr1, plen);
8961 8983 *(pbuf + plen) = '\0';
8962 8984 ptr2 = strchr(pbuf, '/');
8963 8985 if (strncmp(pbuf, str + 1, ptr2 - pbuf) != 0)
8964 8986 mismatch = 1;
8965 8987 }
8966 8988
8967 8989 if (mismatch == 1)
8968 8990 use_pbuf = 1;
8969 8991 }
8970 8992
8971 8993 buf[0] = '\0';
8972 8994
8973 8995 while (*str != '\0') {
8974 8996
8975 8997 switch (*str) {
8976 8998
8977 8999 case MLD_TYPE:
8978 9000
8979 9001 str++;
8980 9002 if ((cp = strstr(str, ";;")) != NULL) {
8981 9003 *cp = '\0';
8982 9004
8983 9005 /*
8984 9006 * Ignore attempts to backup over .MLD.
8985 9007 */
8986 9008 if (strcmp(str, "../") != 0)
8987 9009 (void) strncat(buf, str, MAXPATHLEN);
8988 9010 str = cp + 2;
8989 9011 *cp = ';';
8990 9012 }
8991 9013 break;
8992 9014
8993 9015 case SLD_TYPE:
8994 9016
8995 9017 str++;
8996 9018 if ((cp = strstr(str, ";;")) != NULL) {
8997 9019 *cp = '\0';
8998 9020
8999 9021 /*
9000 9022 * Use the path name in the header if
9001 9023 * error occurs when processing the
9002 9024 * SLD type.
9003 9025 */
9004 9026
9005 9027 if (!stobsl(str, &bslabel,
9006 9028 NO_CORRECTION, &reterr)) {
9007 9029 (void) fprintf(stderr, gettext(
9008 9030 "tar: can't translate to binary"
9009 9031 "SL for SLD, stobsl() error:"
9010 9032 " %s\n"), strerror(errno));
9011 9033 return (-1);
9012 9034 }
9013 9035
9014 9036 str = cp + 2;
9015 9037 *cp = ';';
9016 9038
9017 9039 if (use_pbuf == 1) {
9018 9040 if (*pbuf != '/') {
9019 9041 /* relative linked to path */
9020 9042
9021 9043 (void) getcwd(tempbuf,
9022 9044 (sizeof (tempbuf)));
9023 9045 (void) strncat(tempbuf, "/",
9024 9046 MAXPATHLEN);
9025 9047 (void) strncat(tempbuf, pbuf,
9026 9048 MAXPATHLEN);
9027 9049 }
9028 9050 else
9029 9051 (void) strcpy(tempbuf, pbuf);
9030 9052
9031 9053 } else if (*buf != '/') {
9032 9054 /* got relative linked to path */
9033 9055
9034 9056 (void) getcwd(tempbuf,
9035 9057 (sizeof (tempbuf)));
9036 9058 (void) strncat(tempbuf, "/",
9037 9059 MAXPATHLEN);
9038 9060 } else
9039 9061 *tempbuf = '\0';
9040 9062
9041 9063 (void) strncat(tempbuf, buf, MAXPATHLEN);
9042 9064 *buf = '\0';
9043 9065
9044 9066 if (blequal(&bslabel, &admin_high)) {
9045 9067 bslabel = admin_low;
9046 9068 }
9047 9069
9048 9070
9049 9071 /*
9050 9072 * Check for cross-zone symbolic links
9051 9073 */
9052 9074 from_label = getlabelbypath(real_path);
9053 9075 if (rpath_flag && (from_label != NULL) &&
9054 9076 !blequal(&bslabel, from_label)) {
9055 9077 if ((zoneid =
9056 9078 getzoneidbylabel(&bslabel)) == -1) {
9057 9079 (void) fprintf(stderr,
9058 9080 gettext("tar: can't get "
9059 9081 "zone ID for %s\n"),
9060 9082 tempbuf);
9061 9083 return (-1);
9062 9084 }
9063 9085 if (zone_getattr(zoneid, ZONE_ATTR_NAME,
9064 9086 &zonename, ZONENAME_MAX) == -1) {
9065 9087 /* Badly configured zone info */
9066 9088 (void) fprintf(stderr,
9067 9089 gettext("tar: can't get "
9068 9090 "zonename for %s\n"),
9069 9091 tempbuf);
9070 9092 return (-1);
9071 9093 }
9072 9094 (void) strncpy(buf, AUTO_ZONE,
9073 9095 MAXPATHLEN);
9074 9096 (void) strncat(buf, "/",
9075 9097 MAXPATHLEN);
9076 9098 (void) strncat(buf, zonename,
9077 9099 MAXPATHLEN);
9078 9100 }
9079 9101 if (from_label != NULL)
9080 9102 free(from_label);
9081 9103 (void) strncat(buf, tempbuf, MAXPATHLEN);
9082 9104 break;
9083 9105 }
9084 9106 mld_flag = 0;
9085 9107 break;
9086 9108
9087 9109 case PATH_TYPE:
9088 9110
9089 9111 str++;
9090 9112 if ((cp = strstr(str, ";;")) != NULL) {
9091 9113 *cp = '\0';
9092 9114 (void) strncat(buf, str, MAXPATHLEN);
9093 9115 str = cp + 2;
9094 9116 *cp = ';';
9095 9117 }
9096 9118 break;
9097 9119
9098 9120 default:
9099 9121
9100 9122 (void) fprintf(stderr, gettext(
9101 9123 "tar: error rebuilding path %s\n"),
9102 9124 *namep);
9103 9125 *buf = '\0';
9104 9126 str++;
9105 9127 return (-1);
9106 9128 }
9107 9129 }
9108 9130
9109 9131 /*
9110 9132 * Done for LK_COMP_TYPE
9111 9133 */
9112 9134
9113 9135 return (0); /* component path is rebuilt successfully */
9114 9136
9115 9137 } /* end rebuild_lk_comp_path() */
9116 9138
9117 9139 /*
9118 9140 * Name: check_ext_attr()
9119 9141 *
9120 9142 * Description:
9121 9143 * Check the extended attributes for a file being extracted.
9122 9144 * The attributes being checked here are CMW labels.
9123 9145 * ACLs are not set here because they are set by the
9124 9146 * pflag in doxtract().
9125 9147 *
9126 9148 * If the label doesn't match, return 0
9127 9149 * else return 1
9128 9150 */
9129 9151 static int
9130 9152 check_ext_attr(char *filename)
9131 9153 {
9132 9154 bslabel_t currentlabel; /* label from zone */
9133 9155
9134 9156 if (bltype(&bs_label, SUN_SL_UN)) {
9135 9157 /* No label check possible */
9136 9158 return (0);
9137 9159 }
9138 9160 if (getlabel(filename, ¤tlabel) != 0) {
9139 9161 (void) fprintf(stderr,
9140 9162 gettext("tar: can't get label for "
9141 9163 " %s, getlabel() error: %s\n"),
9142 9164 filename, strerror(errno));
9143 9165 return (0);
9144 9166 } else if ((blequal(¤tlabel, &bs_label)) == 0) {
9145 9167 char *src_label = NULL; /* ascii label */
9146 9168
9147 9169 /* get current src SL */
9148 9170 if (bsltos(&bs_label, &src_label, 0, 0) <= 0) {
9149 9171 (void) fprintf(stderr,
9150 9172 gettext("tar: can't interpret requested label for"
9151 9173 " %s\n"), filename);
9152 9174 } else {
9153 9175 (void) fprintf(stderr,
9154 9176 gettext("tar: can't apply label %s to %s\n"),
9155 9177 src_label, filename);
9156 9178 free(src_label);
9157 9179 }
9158 9180 (void) fprintf(stderr,
9159 9181 gettext("tar: %s not restored\n"), filename);
9160 9182 return (0);
9161 9183 }
9162 9184 return (1);
9163 9185
9164 9186 } /* end check_ext_attr */
9165 9187
9166 9188 /* Compressing a tar file using compression method provided in 'opt' */
9167 9189
9168 9190 static void
9169 9191 compress_back()
9170 9192 {
9171 9193 pid_t pid;
9172 9194 int status;
9173 9195 int wret;
9174 9196 struct stat statb;
9175 9197
9176 9198 if (vflag) {
9177 9199 (void) fprintf(vfile,
9178 9200 gettext("Compressing '%s' with '%s'...\n"),
9179 9201 usefile, compress_opt);
9180 9202 }
9181 9203 if ((pid = fork()) == 0) {
9182 9204 verify_compress_opt(compress_opt);
9183 9205 (void) execlp(compress_opt, compress_opt,
9184 9206 usefile, NULL);
9185 9207 } else if (pid == -1) {
9186 9208 vperror(1, "%s", gettext("Could not fork"));
9187 9209 }
9188 9210 wait_pid(pid);
9189 9211 if (suffix == 0) {
9190 9212 (void) rename(tfname, usefile);
9191 9213 }
9192 9214 }
9193 9215
9194 9216 /* The magic numbers from /etc/magic */
9195 9217
9196 9218 #define GZIP_MAGIC "\037\213"
9197 9219 #define BZIP_MAGIC "BZh"
9198 9220 #define COMP_MAGIC "\037\235"
9199 9221 #define XZ_MAGIC "\375\067\172\130\132\000"
9200 9222
9201 9223 void
9202 9224 check_compression(void)
9203 9225 {
9204 9226 char magic[16];
9205 9227 FILE *fp;
9206 9228
9207 9229 if ((fp = fopen(usefile, "r")) != NULL) {
9208 9230 (void) fread(magic, sizeof (char), 6, fp);
9209 9231 (void) fclose(fp);
9210 9232 }
9211 9233
9212 9234 if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
9213 9235 if (xflag || tflag) {
9214 9236 compress_opt = compress_malloc(strlen(GZCAT) + 1);
9215 9237 (void) strcpy(compress_opt, GZCAT);
9216 9238 } else if (uflag || rflag) {
9217 9239 compress_opt = compress_malloc(strlen(GZIP) + 1);
9218 9240 (void) strcpy(compress_opt, GZIP);
9219 9241 }
9220 9242 } else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
9221 9243 if (xflag || tflag) {
9222 9244 compress_opt = compress_malloc(strlen(BZCAT) + 1);
9223 9245 (void) strcpy(compress_opt, BZCAT);
9224 9246 } else if (uflag || rflag) {
9225 9247 compress_opt = compress_malloc(strlen(BZIP) + 1);
9226 9248 (void) strcpy(compress_opt, BZIP);
9227 9249 }
9228 9250 } else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
9229 9251 if (xflag || tflag) {
9230 9252 compress_opt = compress_malloc(strlen(ZCAT) + 1);
9231 9253 (void) strcpy(compress_opt, ZCAT);
9232 9254 } else if (uflag || rflag) {
9233 9255 compress_opt = compress_malloc(strlen(COMPRESS) + 1);
9234 9256 (void) strcpy(compress_opt, COMPRESS);
9235 9257 }
9236 9258 } else if (memcmp(magic, XZ_MAGIC, 6) == 0) {
9237 9259 if (xflag || tflag) {
9238 9260 compress_opt = compress_malloc(strlen(XZCAT) + 1);
9239 9261 (void) strcpy(compress_opt, XZCAT);
9240 9262 } else if (uflag || rflag) {
9241 9263 compress_opt = compress_malloc(strlen(XZ) + 1);
9242 9264 (void) strcpy(compress_opt, XZ);
9243 9265 }
9244 9266 }
9245 9267 }
9246 9268
9247 9269 char *
9248 9270 add_suffix()
9249 9271 {
9250 9272 (void) strcpy(tfname, usefile);
9251 9273 if (strcmp(compress_opt, GZIP) == 0) {
9252 9274 if ((suffix = gz_suffix()) == NULL) {
9253 9275 strlcat(tfname, gsuffix[0], sizeof (tfname));
9254 9276 return (gsuffix[0]);
9255 9277 }
9256 9278 } else if (strcmp(compress_opt, COMPRESS) == 0) {
9257 9279 if ((suffix = gz_suffix()) == NULL) {
9258 9280 strlcat(tfname, gsuffix[6], sizeof (tfname));
9259 9281 return (gsuffix[6]);
9260 9282 }
9261 9283 } else if (strcmp(compress_opt, BZIP) == 0) {
9262 9284 if ((suffix = bz_suffix()) == NULL) {
9263 9285 strlcat(tfname, bsuffix[0], sizeof (tfname));
9264 9286 return (bsuffix[0]);
9265 9287 }
9266 9288 } else if (strcmp(compress_opt, XZ) == 0) {
9267 9289 if ((suffix = xz_suffix()) == NULL) {
9268 9290 strlcat(tfname, xsuffix[0], sizeof (tfname));
9269 9291 return (xsuffix[0]);
9270 9292 }
9271 9293 }
9272 9294 return (NULL);
9273 9295 }
9274 9296
9275 9297 /* Decompressing a tar file using compression method from the file type */
9276 9298 void
9277 9299 decompress_file(void)
9278 9300 {
9279 9301 pid_t pid;
9280 9302 int status;
9281 9303 char cmdstr[PATH_MAX];
9282 9304 char fname[PATH_MAX];
9283 9305 char *added_suffix;
9284 9306
9285 9307
9286 9308 added_suffix = add_suffix();
9287 9309 if (added_suffix != NULL) {
9288 9310 (void) rename(usefile, tfname);
9289 9311 }
9290 9312 if ((pid = fork()) == 0) {
9291 9313 if (vflag) {
9292 9314 (void) fprintf(vfile,
9293 9315 gettext("Decompressing '%s' with "
9294 9316 "'%s'...\n"), usefile, compress_opt);
9295 9317 }
9296 9318 verify_compress_opt(compress_opt);
9297 9319 (void) execlp(compress_opt, compress_opt, "-df",
9298 9320 tfname, NULL);
9299 9321 vperror(1, gettext("Could not exec %s"), compress_opt);
9300 9322 } else if (pid == -1) {
9301 9323 vperror(1, gettext("Could not fork"));
9302 9324 }
9303 9325 wait_pid(pid);
9304 9326 if (suffix != NULL) {
9305 9327 /* restore the file name - original file was without suffix */
9306 9328 *(usefile + strlen(usefile) - strlen(suffix)) = '\0';
9307 9329 }
9308 9330 }
9309 9331
9310 9332 /* Set the archive for writing and then compress the archive */
9311 9333 pid_t
9312 9334 compress_file(void)
9313 9335 {
9314 9336 int fd[2];
9315 9337 pid_t pid;
9316 9338
9317 9339 if (vflag) {
9318 9340 (void) fprintf(vfile, gettext("Compressing '%s' with "
9319 9341 "'%s'...\n"), usefile, compress_opt);
9320 9342 }
9321 9343
9322 9344 if (pipe(fd) < 0) {
9323 9345 vperror(1, gettext("Could not create pipe"));
9324 9346 }
9325 9347 if (pid = fork() > 0) {
9326 9348 mt = fd[1];
9327 9349 (void) close(fd[0]);
9328 9350 return (pid);
9329 9351 }
9330 9352 /* child */
9331 9353 (void) dup2(fd[0], STDIN_FILENO);
9332 9354 (void) close(fd[1]);
9333 9355 (void) dup2(mt, STDOUT_FILENO);
9334 9356 verify_compress_opt(compress_opt);
9335 9357 (void) execlp(compress_opt, compress_opt, NULL);
9336 9358 vperror(1, gettext("Could not exec %s"), compress_opt);
9337 9359 return (0); /*NOTREACHED*/
9338 9360 }
9339 9361
9340 9362 pid_t
9341 9363 uncompress_file(void)
9342 9364 {
9343 9365 int fd[2];
9344 9366 pid_t pid;
9345 9367
9346 9368 if (vflag) {
9347 9369 (void) fprintf(vfile, gettext("Decompressing '%s' with "
9348 9370 "'%s'...\n"), usefile, compress_opt);
9349 9371 }
9350 9372
9351 9373 if (pipe(fd) < 0) {
9352 9374 vperror(1, gettext("Could not create pipe"));
9353 9375 }
9354 9376 if (pid = fork() > 0) {
9355 9377 mt = fd[0];
9356 9378 (void) close(fd[1]);
9357 9379 return (pid);
9358 9380 }
9359 9381 /* child */
9360 9382 (void) dup2(fd[1], STDOUT_FILENO);
9361 9383 (void) close(fd[0]);
9362 9384 (void) dup2(mt, STDIN_FILENO);
9363 9385 verify_compress_opt(compress_opt);
9364 9386 (void) execlp(compress_opt, compress_opt, NULL);
9365 9387 vperror(1, gettext("Could not exec %s"), compress_opt);
9366 9388 return (0); /*NOTREACHED*/
9367 9389 }
9368 9390
9369 9391 /* Checking suffix validity */
9370 9392 char *
9371 9393 check_suffix(char **suf, int size)
9372 9394 {
9373 9395 int i;
9374 9396 int slen;
9375 9397 int nlen = strlen(usefile);
9376 9398
9377 9399 for (i = 0; i < size; i++) {
9378 9400 slen = strlen(suf[i]);
9379 9401 if (nlen < slen)
9380 9402 return (NULL);
9381 9403 if (strcmp(usefile + nlen - slen, suf[i]) == 0)
9382 9404 return (suf[i]);
9383 9405 }
9384 9406 return (NULL);
9385 9407 }
9386 9408
9387 9409 /* Checking valid 'bzip2' suffix */
9388 9410 char *
9389 9411 bz_suffix(void)
9390 9412 {
9391 9413 return (check_suffix(bsuffix, BSUF));
9392 9414 }
9393 9415
9394 9416 /* Checking valid 'gzip' suffix */
9395 9417 char *
9396 9418 gz_suffix(void)
9397 9419 {
9398 9420 return (check_suffix(gsuffix, GSUF));
9399 9421 }
9400 9422
9401 9423 /* Checking valid 'xz' suffix */
9402 9424 char *
9403 9425 xz_suffix(void)
9404 9426 {
9405 9427 return (check_suffix(xsuffix, XSUF));
9406 9428 }
9407 9429
9408 9430 void *
9409 9431 compress_malloc(size_t size)
9410 9432 {
9411 9433 void *opt;
9412 9434
9413 9435 if ((opt = malloc(size)) == NULL) {
9414 9436 vperror(1, "%s",
9415 9437 gettext("Could not allocate compress buffer\n"));
9416 9438 }
9417 9439 return (opt);
9418 9440 }
9419 9441
9420 9442 void
9421 9443 wait_pid(pid_t pid)
9422 9444 {
9423 9445 int status;
9424 9446
9425 9447 while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
9426 9448 ;
9427 9449 }
9428 9450
9429 9451 static void
9430 9452 verify_compress_opt(const char *t)
9431 9453 {
9432 9454 struct stat statbuf;
9433 9455
9434 9456 if (stat(t, &statbuf) == -1)
9435 9457 vperror(1, "%s %s: %s\n", gettext("Could not stat"),
9436 9458 t, strerror(errno));
9437 9459 }
9438 9460
9439 9461 static void
9440 9462 detect_compress(void)
9441 9463 {
9442 9464 char *zsuf[] = {".Z"};
9443 9465 if (check_suffix(zsuf, 1) != NULL) {
9444 9466 Zflag = 1;
9445 9467 } else if (check_suffix(bsuffix, BSUF) != NULL) {
9446 9468 jflag = 1;
9447 9469 } else if (check_suffix(gsuffix, GSUF) != NULL) {
9448 9470 zflag = 1;
9449 9471 } else if (check_suffix(xsuffix, XSUF) != NULL) {
9450 9472 Jflag = 1;
9451 9473 } else {
9452 9474 vperror(1, "%s\n", gettext("No compression method detected"));
9453 9475 }
9454 9476 }
↓ open down ↓ |
8284 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX