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