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