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