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