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