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) 2012 Gary Mills
  25  */
  26 
  27 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  28 /*      All Rights Reserved                                     */
  29 
  30 /*
  31  * Portions of this source code were derived from Berkeley 4.3 BSD
  32  * under license from the Regents of the University of California.
  33  */
  34 
  35 #include <stdio.h>
  36 #include <sys/types.h>
  37 #include <errno.h>
  38 #include <unistd.h>
  39 #include <stdlib.h>
  40 #include <fcntl.h>
  41 #include <memory.h>
  42 #include <string.h>
  43 #include <stdarg.h>
  44 #include <sys/stat.h>
  45 #include <sys/statvfs.h>
  46 #include <sys/mkdev.h>
  47 #include <sys/param.h>
  48 #include <utime.h>
  49 #include <pwd.h>
  50 #include <grp.h>
  51 #include <signal.h>
  52 #include <ctype.h>
  53 #include <locale.h>
  54 #include <sys/ioctl.h>
  55 #include <sys/mtio.h>
  56 #include <sys/fdio.h>
  57 #include "cpio.h"
  58 #include <sys/acl.h>
  59 #include <sys/time.h>
  60 #include <sys/resource.h>
  61 #include <fnmatch.h>
  62 #include <libgen.h>
  63 #include <libintl.h>
  64 #include <dirent.h>
  65 #include <limits.h>
  66 #include <aclutils.h>
  67 #if defined(_PC_SATTR_ENABLED)
  68 #include <libnvpair.h>
  69 #include <attr.h>
  70 #include <libcmdutils.h>
  71 #endif  /* _PC_SATTR_ENABLED */
  72 #ifdef SOLARIS_PRIVS
  73 #include <priv.h>
  74 #endif  /* SOLARIS_PRIVS */
  75 
  76 /*
  77  * Special kludge for off_t being a signed quantity.
  78  */
  79 #if _FILE_OFFSET_BITS == 64
  80 typedef u_longlong_t    u_off_t;
  81 #else
  82 typedef ulong_t         u_off_t;
  83 #endif
  84 
  85 #define SECMODE 0xe080
  86 
  87 #define DEVNULL         "/dev/null"
  88 #define XATTRHDR        ".hdr"
  89 
  90 #define NAMELEN         32
  91 #define TYPELEN         16
  92 #define PERMLEN         4
  93 
  94 #define FILE_COPIED     1
  95 #define FILE_LINKED     2
  96 #define FILE_PASS_ERR   -1
  97 
  98 #define ARCHIVE_NORMAL  0
  99 #define ARCHIVE_ACL     1
 100 #define ARCHIVE_XATTR   2
 101 #define ARCHIVE_SPARSE  3
 102 
 103 #ifndef VIEW_READONLY
 104 #define VIEW_READONLY   "SUNWattr_ro"
 105 #endif
 106 
 107 #ifndef VIEW_READWRITE
 108 #define VIEW_READWRITE  "SUNWattr_rw"
 109 #endif
 110 
 111 
 112 #define LSTAT(dir, path, statbuf) fstatat(dir, \
 113     get_component((Gen.g_attrnam_p == NULL) ? \
 114     path : Gen.g_attrnam_p), statbuf, AT_SYMLINK_NOFOLLOW)
 115 #define STAT(dir, path, statbuf) fstatat(dir, \
 116     get_component((Gen.g_attrnam_p == NULL) ? \
 117     path : Gen.g_attrnam_p), statbuf, 0)
 118 
 119 /*
 120  *      These limits reflect the maximum size regular file that
 121  *      can be archived, depending on the archive type. For archives
 122  *      with character-format headers (odc, tar, ustar) we use
 123  *      CHAR_OFFSET_MAX.  For archives with SVR4 ASCII headers (-c, -H crc)
 124  *      we store filesize in an 8-char hexadecimal string and use
 125  *      ASC_OFFSET_MAX.  Otherwise, we are limited to the size that will
 126  *      fit in a signed long value.
 127  */
 128 #define CHAR_OFFSET_MAX 077777777777ULL /* 11 octal digits */
 129 #define ASC_OFFSET_MAX  0XFFFFFFFF      /* 8 hexadecimal digits */
 130 #define BIN_OFFSET_MAX  LONG_MAX        /* signed long max value */
 131 
 132 #define POSIXMODES      07777
 133 
 134 static char     aclchar = ' ';
 135 
 136 static struct Lnk *add_lnk(struct Lnk **);
 137 static int bfill(void);
 138 static void bflush(void);
 139 static int chgreel(int dir);
 140 static int ckname(int);
 141 static void ckopts(long mask);
 142 static long cksum(char hdr, int byt_cnt, int *err);
 143 static int creat_hdr(void);
 144 static int creat_lnk(int dirfd, char *name1_p, char *name2_p);
 145 static int creat_spec(int dirfd);
 146 static int creat_tmp(char *nam_p);
 147 static void data_in(int proc_mode);
 148 static void data_out(void);
 149 static void data_pass(void);
 150 static void file_in(void);
 151 static int file_out(void);
 152 static int file_pass(void);
 153 static void flush_lnks(void);
 154 static int gethdr(void);
 155 static int getname(void);
 156 static void getpats(int largc, char **largv);
 157 static void ioerror(int dir);
 158 static int matched(void);
 159 static int missdir(char *nam_p);
 160 static long mklong(short v[]);
 161 static void mkshort(short sval[], long v);
 162 static int openout(int dirfd);
 163 static int read_hdr(int hdr);
 164 static void reclaim(struct Lnk *l_p);
 165 static void rstbuf(void);
 166 static void setpasswd(char *nam);
 167 static void rstfiles(int over, int dirfd);
 168 static void scan4trail(void);
 169 static void setup(int largc, char **largv);
 170 static void set_tym(int dirfd, char *nam_p, time_t atime, time_t mtime);
 171 static void sigint(int sig);
 172 static void swap(char *buf_p, int cnt);
 173 static void usage(void);
 174 static void verbose(char *nam_p);
 175 static void write_hdr(int arcflag, off_t len);
 176 static void write_trail(void);
 177 static int ustar_dir(void);
 178 static int ustar_spec(void);
 179 static struct stat *convert_to_old_stat(struct stat *, char *, char *);
 180 static void read_bar_vol_hdr(void);
 181 static void read_bar_file_hdr(void);
 182 static void setup_uncompress(FILE **);
 183 static void skip_bar_volhdr(void);
 184 static void bar_file_in(void);
 185 static int g_init(int *devtype, int *fdes);
 186 static int g_read(int, int, char *, unsigned);
 187 static int g_write(int, int, char *, unsigned);
 188 static int is_floppy(int);
 189 static int is_tape(int);
 190 static void write_ancillary(char *buf, size_t len, boolean_t padding);
 191 static int remove_dir(char *);
 192 static int save_cwd(void);
 193 static void rest_cwd(int cwd);
 194 
 195 static void xattrs_out(int (*func)());
 196 static void get_parent(char *path, char *dir);
 197 static void prepare_xattr_hdr(char **attrbuf, char *filename,
 198     char *attrname, char typeflag, struct Lnk *linkinfo, int *rlen);
 199 static char tartype(int type);
 200 static int openfile(int omode);
 201 static mode_t attrmode(char type);
 202 static char *get_component(char *path);
 203 static int open_dir(char *name);
 204 static int open_dirfd();
 205 static void close_dirfd();
 206 static void write_xattr_hdr();
 207 static char *skipslashes(char *string, char *start);
 208 static int read_xattr_hdr();
 209 static void chop_endslashes(char *path);
 210 
 211 
 212 /* helpful types */
 213 
 214 static
 215 struct passwd   *Curpw_p,       /* Current password entry for -t option */
 216                 *Rpw_p,         /* Password entry for -R option */
 217                 *dpasswd;
 218 
 219 static
 220 struct group    *Curgr_p,       /* Current group entry for -t option */
 221                 *dgroup;
 222 
 223 /* Data structure for buffered I/O. */
 224 
 225 static
 226 struct buf_info {
 227         char    *b_base_p,      /* Pointer to base of buffer */
 228                 *b_out_p,       /* Position to take bytes from buffer at */
 229                 *b_in_p,        /* Position to put bytes into buffer at */
 230                 *b_end_p;       /* Pointer to end of buffer */
 231         long    b_cnt,          /* Count of unprocessed bytes */
 232                 b_size;         /* Size of buffer in bytes */
 233 } Buffr;
 234 
 235 /* Generic header format */
 236 
 237 static
 238 struct gen_hdr {
 239         ulong_t g_magic,        /* Magic number field */
 240                 g_ino,          /* Inode number of file */
 241                 g_mode,         /* Mode of file */
 242                 g_uid,          /* Uid of file */
 243                 g_gid,          /* Gid of file */
 244                 g_nlink,        /* Number of links */
 245                 g_mtime;        /* Modification time */
 246         off_t   g_filesz;       /* Length of file */
 247         ulong_t g_dev,          /* File system of file */
 248                 g_rdev,         /* Major/minor numbers of special files */
 249                 g_namesz,       /* Length of filename */
 250                 g_cksum;        /* Checksum of file */
 251         char    g_gname[32],
 252                 g_uname[32],
 253                 g_version[2],
 254                 g_tmagic[6],
 255                 g_typeflag;
 256         char    *g_tname,
 257                 *g_prefix,
 258                 *g_nam_p,       /* Filename */
 259                 *g_attrparent_p, /* attribute parent */
 260                 *g_attrpath_p, /* attribute path */
 261                 *g_attrnam_p,   /* attribute */
 262                 *g_attrfnam_p,  /* Real file name attr belongs to */
 263                 *g_linktoattrfnam_p, /* file linked attribute belongs to */
 264                 *g_linktoattrnam_p,  /* attribute g_attrnam_p is linked to */
 265                 *g_dirpath;     /* dirname currently opened */
 266         int     g_dirfd;        /* directory file descriptor */
 267         int     g_passdirfd;    /* directory fd to pass to */
 268         int     g_rw_sysattr;   /* read-write system attribute */
 269         int     g_baseparent_fd;        /* base file's parent fd */
 270         holes_info_t *g_holes;  /* sparse file information */
 271 
 272 } Gen, *G_p;
 273 
 274 /* Data structure for handling multiply-linked files */
 275 static
 276 char    prebuf[PRESIZ+1],
 277         nambuf[NAMSIZ+1],
 278         fullnam[MAXNAM+1];
 279 
 280 
 281 static
 282 struct Lnk {
 283         short   L_cnt,          /* Number of links encountered */
 284                 L_data;         /* Data has been encountered if 1 */
 285         struct gen_hdr  L_gen;  /* gen_hdr information for this file */
 286         struct Lnk      *L_nxt_p,       /* Next file in list */
 287                         *L_bck_p,       /* Previous file in list */
 288                         *L_lnk_p;       /* Next link for this file */
 289 } Lnk_hd;
 290 
 291 static
 292 struct hdr_cpio Hdr;
 293 
 294 /*
 295  * -------------------------------------------------------------------------
 296  *                 Stuff needed to pre-view the name stream
 297  *
 298  * issymlink is used to remember that the current file is a symlink between
 299  * getname() and file_pass(); the former trashes this information immediately
 300  * when -L is specified.
 301  */
 302 
 303 static
 304 int     issymlink = 0;
 305 
 306 static
 307 FILE    *In_p = stdin;          /* Where the input comes from */
 308 
 309 typedef struct sl_info
 310 {
 311         struct sl_info *llink;  /* Left subtree ptr (tree depth in *sl_head) */
 312         struct sl_info *rlink;  /* Right subtree ptr */
 313         int bal;                /* Subtree balance factor */
 314         ulong_t sl_count;       /* Number of symlinks */
 315         int     sl_ftype;       /* file type of inode */
 316         ino_t   sl_ino;         /* Inode of file */
 317         ino_t   sl_ino2;        /* alternate inode for -Hodc */
 318 } sl_info_t;
 319 
 320 typedef struct data_in
 321 {
 322         int             data_in_errno;
 323         char            data_in_swapfile;
 324         char            data_in_proc_mode;
 325         char            data_in_rd_eof;
 326         char            data_in_wr_part;
 327         char            data_in_compress_flag;
 328         long            data_in_cksumval;
 329         FILE            *data_in_pipef;
 330 } data_in_t;
 331 
 332 /*
 333  * The following structure maintains a hash entry for the
 334  * balancing trees which are allocated for each device nodes.
 335  */
 336 typedef struct sl_info_link
 337 {
 338         dev_t           dev;
 339         sl_info_t       *head;
 340         struct sl_info_link *next;
 341 } sl_info_link_t;
 342 
 343 #define SL_INFO_ALLOC_CHUNK     1024
 344 #define NDEVHENTRY              0x40
 345 #define DEV_HASHKEY(x)          ((x) & (NDEVHENTRY -1))
 346 
 347 /*
 348  * For remapping dev,inode for -Hodc archives.
 349  */
 350 
 351 typedef struct sl_remap
 352 {
 353         dev_t                   dev;            /* device */
 354         int                     inode_count;    /* # inodes seen on dev */
 355         struct sl_remap         *next;          /* next in the chain */
 356 } sl_remap_t;
 357 
 358 /* forward declarations */
 359 
 360 static sl_info_t        *sl_info_alloc(void);
 361 static sl_info_t        *sl_insert(dev_t, ino_t, int);
 362 static ulong_t          sl_numlinks(dev_t, ino_t, int);
 363 static void             sl_preview_synonyms(void);
 364 static void             sl_remember_tgt(const struct stat *, int, int);
 365 static sl_info_t        *sl_search(dev_t, ino_t, int);
 366 static sl_info_t        *sl_devhash_lookup(dev_t);
 367 static void             sl_devhash_insert(dev_t, sl_info_t *);
 368 
 369 extern int              sl_compare(ino_t, int, ino_t, int);
 370 #define sl_compare(lino, lftype, rino, rftype)  (lino < rino ? -1 : \
 371             (lino > rino ? 1 : (lftype < rftype ? -1 : \
 372             (lftype > rftype ? 1 : 0))))
 373 
 374 /* global storage */
 375 
 376 static sl_remap_t  *sl_remap_head = NULL; /* head of the inode-remap list */
 377 static sl_info_link_t   *sl_devhash[NDEVHENTRY]; /* hash table */
 378 
 379 /*
 380  * -------------------------------------------------------------------------
 381  */
 382 
 383 static
 384 struct stat     ArchSt, /* stat(2) information of the archive */
 385                 SrcSt,  /* stat(2) information of source file */
 386                 DesSt,  /* stat(2) of destination file */
 387                 *OldSt = NULL;  /* stat info converted to svr32 format */
 388 
 389 /*
 390  * bin_mag: Used to validate a binary magic number,
 391  * by combining to bytes into an unsigned short.
 392  */
 393 
 394 static
 395 union bin_mag {
 396         unsigned char b_byte[2];
 397         ushort_t b_half;
 398 } Binmag;
 399 
 400 static
 401 union tblock *Thdr_p;   /* TAR header pointer */
 402 
 403 static union b_block *bar_Vhdr;
 404 static struct gen_hdr Gen_bar_vol;
 405 
 406 /*
 407  * swpbuf: Used in swap() to swap bytes within a halfword,
 408  * halfwords within a word, or to reverse the order of the
 409  * bytes within a word.  Also used in mklong() and mkshort().
 410  */
 411 
 412 static
 413 union swpbuf {
 414         unsigned char   s_byte[4];
 415         ushort_t        s_half[2];
 416         ulong_t s_word;
 417 } *Swp_p;
 418 
 419 static
 420 char    *myname,                /* program name */
 421         Adir,                   /* Flags object as a directory */
 422         Hiddendir,              /* Processing hidden attribute directory */
 423         Aspec,                  /* Flags object as a special file */
 424         Do_rename,              /* Indicates rename() is to be used */
 425         Time[50],               /* Array to hold date and time */
 426         Ttyname[] = "/dev/tty", /* Controlling console */
 427         T_lname[MAXPATHLEN],    /* Array to hold links name for tar */
 428         *Buf_p,                 /* Buffer for file system I/O */
 429         *Full_p,                /* Pointer to full pathname */
 430         *Efil_p,                /* -E pattern file string */
 431         *Eom_p = "Change to part %d and press RETURN key. [q] ",
 432         *Fullnam_p,             /* Full pathname */
 433         *Attrfile_p,            /* attribute file */
 434         *Hdr_p,                 /* -H header type string */
 435         *IOfil_p,               /* -I/-O input/output archive string */
 436         *Lnkend_p,              /* Pointer to end of Lnknam_p */
 437         *Lnknam_p,              /* Buffer for linking files with -p option */
 438         *Nam_p,                 /* Array to hold filename */
 439         *Savenam_p,             /* copy of filename xattr belongs to */
 440         *Own_p,                 /* New owner login id string */
 441         *Renam_p,               /* Buffer for renaming files */
 442         *Renam_attr_p,          /* Buffer for renaming attr with sys attrs */
 443         *Renametmp_p,           /* Tmp Buffer for renaming files */
 444         *Symlnk_p,              /* Buffer for holding symbolic link name */
 445         *Over_p,                /* Holds temporary filename when overwriting */
 446         **Pat_pp = 0,           /* Pattern strings */
 447         bar_linkflag,           /* flag to indicate if the file is a link */
 448         bar_linkname[MAXPATHLEN]; /* store the name of the link */
 449 
 450 static
 451 int     Append = 0,     /* Flag set while searching to end of archive */
 452         Archive,        /* File descriptor of the archive */
 453         Buf_error = 0,  /* I/O error occurred during buffer fill */
 454         Compress_sparse = 0,    /* Compress sparse files */
 455         Def_mode = 0777,        /* Default file/directory protection modes */
 456         Device,         /* Device type being accessed (used with libgenIO) */
 457         Error_cnt = 0,  /* Cumulative count of I/O errors */
 458         Finished = 1,   /* Indicates that a file transfer has completed */
 459         Hdrsz = ASCSZ,  /* Fixed length portion of the header */
 460         Hdr_type,               /* Flag to indicate type of header selected */
 461         Ifile,          /* File des. of file being archived */
 462         Ofile,          /* File des. of file being extracted from archive */
 463         Use_old_stat = 0,    /* Create an old style -Hodc hdr (small dev's) */
 464         Onecopy = 0,    /* Flags old vs. new link handling */
 465         Pad_val = 0,    /* Indicates the number of bytes to pad (if any) */
 466         PageSize = 0,   /* The native page size, used for figuring block size */
 467         Volcnt = 1,     /* Number of archive volumes processed */
 468         Verbcnt = 0,    /* Count of number of dots '.' output */
 469         Eomflag = 0,
 470         Dflag = 0,
 471         Atflag = 0,     /* Archive/restore extended attributes */
 472         SysAtflag = 0,  /* Archive/restore extended system attributes */
 473         Compressed,     /* Flag to indicate if the bar archive is compressed */
 474         Bar_vol_num = 0, /* Volume number count for bar archive */
 475         privileged = 0, /* Flag set if running with higher privileges */
 476         attr_baseparent_fd = -1;        /* attribute's base file descriptor */
 477 
 478 
 479 static
 480 gid_t   Lastgid = (gid_t)-1;    /* Used with -t & -v to record current gid */
 481 
 482 static
 483 uid_t   Lastuid = (uid_t)-1;    /* Used with -t & -v to record current uid */
 484 
 485 static
 486 long    Args,           /* Mask of selected options */
 487         Max_namesz = CPATH;     /* Maximum size of pathnames/filenames */
 488 
 489 static
 490 int     Bufsize = BUFSZ;        /* Default block size */
 491 
 492 
 493 static u_longlong_t    Blocks;  /* full blocks transferred */
 494 static u_longlong_t    SBlocks; /* cumulative char count from short reads */
 495 
 496 
 497 static off_t    Max_offset = BIN_OFFSET_MAX;    /* largest file size */
 498 static off_t    Max_filesz;                     /* from getrlimit */
 499 
 500 static ulong_t  Savedev;
 501 
 502 static
 503 FILE    *Ef_p,                  /* File pointer of pattern input file */
 504         *Err_p = stderr,        /* File pointer for error reporting */
 505         *Out_p = stdout,        /* File pointer for non-archive output */
 506         *Rtty_p,                /* Input file pointer for interactive rename */
 507         *Wtty_p;                /* Output file ptr for interactive rename */
 508 
 509 static
 510 ushort_t        Ftype = S_IFMT; /* File type mask */
 511 
 512 /* ACL support */
 513 static struct sec_attr {
 514         char    attr_type;
 515         char    attr_len[7];
 516         char    attr_info[1];
 517 } *attr;
 518 
 519 static int      Pflag = 0;      /* flag indicates that acl is preserved */
 520 static int      acl_is_set = 0; /* True if an acl was set on the file */
 521 
 522 acl_t *aclp;
 523 
 524 #if defined(O_XATTR)
 525 typedef enum {
 526         ATTR_OK,
 527         ATTR_SKIP,
 528         ATTR_CHDIR_ERR,
 529         ATTR_OPEN_ERR,
 530         ATTR_XATTR_ERR,
 531         ATTR_SATTR_ERR
 532 } attr_status_t;
 533 #endif
 534 
 535 #if defined(O_XATTR)
 536 typedef enum {
 537         ARC_CREATE,
 538         ARC_RESTORE
 539 } arc_action_t;
 540 #endif
 541 
 542 
 543 /*
 544  *
 545  * cpio has been changed to support extended attributes.
 546  *
 547  * As part of this change cpio has been changed to use the new *at() syscalls
 548  * such as openat, fchownat(), unlinkat()...
 549  *
 550  * This was done so that attributes can be handled with as few code changes
 551  * as possible.
 552  *
 553  * What this means is that cpio now opens the directory that a file or directory
 554  * resides in and then performs *at() functions to manipulate the entry.
 555  *
 556  * For example a new file is now created like this:
 557  *
 558  * dfd = open(<some dir path>)
 559  * fd = openat(dfd, <name>,....);
 560  *
 561  * or in the case of an extended attribute
 562  *
 563  * dfd = attropen(<pathname>, ".", ....)
 564  *
 565  * Once we have a directory file descriptor all of the *at() functions can
 566  * be applied to it.
 567  *
 568  * unlinkat(dfd, <component name>,...)
 569  * fchownat(dfd, <component name>,..)
 570  *
 571  * This works for both normal namespace files and extended attribute file
 572  *
 573  */
 574 
 575 /*
 576  * Extended attribute layout
 577  *
 578  * Extended attributes are stored in two pieces.
 579  * 1. An attribute header which has information about
 580  *    what file the attribute is for and what the attribute
 581  *    is named.
 582  * 2. The attribute record itself.  Stored as a normal file type
 583  *    of entry.
 584  * Both the header and attribute record have special modes/typeflags
 585  * associated with them.
 586  *
 587  * The names of the header in the archive look like:
 588  * /dev/null/attr.hdr
 589  *
 590  * The name of the attribute looks like:
 591  * /dev/null/attr.
 592  *
 593  * This is done so that an archiver that doesn't understand these formats
 594  * can just dispose of the attribute records unless the user chooses to
 595  * rename them via cpio -r or pax -i
 596  *
 597  * The format is composed of a fixed size header followed
 598  * by a variable sized xattr_buf. If the attribute is a hard link
 599  * to another attribute, then another xattr_buf section is included
 600  * for the link.
 601  *
 602  * The xattr_buf is used to define the necessary "pathing" steps
 603  * to get to the extended attribute.  This is necessary to support
 604  * a fully recursive attribute model where an attribute may itself
 605  * have an attribute.
 606  *
 607  * The basic layout looks like this.
 608  *
 609  *     --------------------------------
 610  *     |                              |
 611  *     |         xattr_hdr            |
 612  *     |                              |
 613  *     --------------------------------
 614  *     --------------------------------
 615  *     |                              |
 616  *     |        xattr_buf             |
 617  *     |                              |
 618  *     --------------------------------
 619  *     --------------------------------
 620  *     |                              |
 621  *     |      (optional link info)    |
 622  *     |                              |
 623  *     --------------------------------
 624  *     --------------------------------
 625  *     |                              |
 626  *     |      attribute itself        |
 627  *     |      stored as normal tar    |
 628  *     |      or cpio data with       |
 629  *     |      special mode or         |
 630  *     |      typeflag                |
 631  *     |                              |
 632  *     --------------------------------
 633  *
 634  */
 635 
 636 /*
 637  * Extended attributes structures
 638  *
 639  * xattrhead is the complete extended attribute header, as read of off
 640  * disk/tape. It includes the variable xattr_buf portion.
 641  *
 642  * xattrp is basically an offset into xattrhead that points to the
 643  * "pathing" section which defines how to get to the attribute.
 644  *
 645  * xattr_linkp is identical to xattrp except that it is used for linked
 646  * attributes.  It provides the pathing steps to get to the linked
 647  * attribute.
 648  *
 649  * These structures are updated when an extended attribute header is read off
 650  * of disk/tape.
 651  */
 652 static struct xattr_hdr *xattrhead;
 653 static struct xattr_buf *xattrp;
 654 static struct xattr_buf *xattr_linkp;
 655 static int              xattrbadhead;   /* is extended attribute header bad? */
 656 
 657 static int      append_secattr(char **, int *, acl_t *);
 658 
 659 /*
 660  * Note regarding cpio and changes to ensure cpio doesn't try to second
 661  * guess whether it runs with sufficient privileges or not:
 662  *
 663  * cpio has been changed so that it doesn't carry a second implementation of
 664  * the kernel's policy with respect to privileges.  Instead of attempting
 665  * to restore uid and gid from an archive only if cpio is run as uid 0,
 666  * cpio now *always* tries to restore the uid and gid from the archive
 667  * except when the -R option is specified.  When the -R is specified,
 668  * the uid and gid of the restored file will be changed to those of the
 669  * login id specified.  In addition, chown(), set_tym(), and chmod() should
 670  * only be executed once during archive extraction, and to ensure
 671  * setuid/setgid bits are restored properly, chown() should always be
 672  * executed before chmod().
 673  *
 674  * Note regarding debugging mechanism for cpio:
 675  *
 676  * The following mechanism is provided to allow us to debug cpio in complicated
 677  * situations, like when it is part of a pipe.  The idea is that you compile
 678  * with -DWAITAROUND defined, and then add the "-z" command line option to the
 679  * target cpio invocation.  If stderr is available, it will tell you to which
 680  * pid to attach the debugger; otherwise, use ps to find it.  Attach to the
 681  * process from the debugger, and, *PRESTO*, you are there!
 682  *
 683  * Simply assign "waitaround = 0" once you attach to the process, and then
 684  * proceed from there as usual.
 685  */
 686 
 687 #ifdef WAITAROUND
 688 int waitaround = 0;             /* wait for rendezvous with the debugger */
 689 #endif
 690 
 691 #define EXIT_CODE       (Error_cnt > 255 ? 255 : Error_cnt)
 692 
 693 /*
 694  * main: Call setup() to process options and perform initializations,
 695  * and then select either copy in (-i), copy out (-o), or pass (-p) action.
 696  */
 697 
 698 int
 699 main(int argc, char **argv)
 700 {
 701         int i;
 702         int passret;
 703 
 704         (void) setlocale(LC_ALL, "");
 705 #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */
 706 #define TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't */
 707 #endif
 708         (void) textdomain(TEXT_DOMAIN);
 709 
 710         (void) memset(&Gen, 0, sizeof (Gen));
 711         myname = e_strdup(E_EXIT, basename(argv[0]));
 712         setup(argc, argv);
 713 
 714         if (signal(SIGINT, sigint) == SIG_IGN)
 715                 (void) signal(SIGINT, SIG_IGN);
 716         switch (Args & (OCi | OCo | OCp)) {
 717         case OCi: /* COPY IN */
 718                 Hdr_type = NONE;
 719                 if (Atflag || SysAtflag) {
 720                         /*
 721                          * Save the current working directory, so
 722                          * we can change back here after cd'ing into
 723                          * the attribute directory when processing
 724                          * attributes.
 725                          */
 726                         if ((attr_baseparent_fd = save_cwd()) < 0) {
 727                                 msg(EXT, "Unable to open current directory.");
 728                         }
 729                 }
 730                 while ((i = gethdr()) != 0) {
 731                         Gen.g_dirfd = -1;
 732                         if (i == 1) {
 733                                 file_in();
 734                                 /*
 735                                  * Any ACL info for this file would or should
 736                                  * have been used after file_in(); clear out
 737                                  * aclp so it is is not erroneously used on
 738                                  * the next file.
 739                                  */
 740                                 if (aclp != NULL) {
 741                                         acl_free(aclp);
 742                                         aclp = NULL;
 743                                 }
 744                                 acl_is_set = 0;
 745                         }
 746                         (void) memset(&Gen, 0, sizeof (Gen));
 747                 }
 748                 /* Do not count "extra" "read-ahead" buffered data */
 749                 if (Buffr.b_cnt > Bufsize)
 750                         Blocks -=  (u_longlong_t)(Buffr.b_cnt / Bufsize);
 751                 break;
 752         case OCo: /* COPY OUT */
 753                 if (Args & OCA) {
 754                         scan4trail();
 755                 }
 756 
 757                 Gen.g_dirfd = -1;
 758                 Gen.g_dirpath = NULL;
 759                 sl_preview_synonyms();
 760 
 761                 while ((i = getname()) != 0) {
 762                         if (i == 1) {
 763                                 (void) file_out();
 764                                 if (Atflag || SysAtflag) {
 765                                         if (Gen.g_dirfd != -1) {
 766                                                 (void) close(Gen.g_dirfd);
 767                                         }
 768                                         Gen.g_dirfd = -1;
 769                                         xattrs_out(file_out);
 770                                 }
 771                         }
 772                         if (aclp != NULL) {
 773                                 acl_free(aclp);
 774                                 aclp = NULL;
 775                                 acl_is_set = 0;
 776                         }
 777                 }
 778                 write_trail();
 779                 break;
 780         case OCp: /* PASS */
 781                 sl_preview_synonyms();
 782 
 783                 Gen.g_dirfd = -1;
 784                 Gen.g_passdirfd = -1;
 785                 Gen.g_dirpath = NULL;
 786                 Compress_sparse = 1;
 787                 while (getname()) {
 788                         /*
 789                          * If file is a fully qualified path then
 790                          * file_pass will strip off the leading '/'
 791                          * and we need to save off the unstripped
 792                          * name for attribute traversal.
 793                          */
 794                         if (Atflag || SysAtflag) {
 795                                 (void) strcpy(Savenam_p, Gen.g_nam_p);
 796                         }
 797                         passret = file_pass();
 798                         if (aclp != NULL) {
 799                                 acl_free(aclp);
 800                                 aclp = NULL;
 801                                 acl_is_set = 0;
 802                         }
 803                         if (Gen.g_passdirfd != -1)
 804                                 (void) close(Gen.g_passdirfd);
 805                         Gen.g_passdirfd = -1;
 806                         if (Atflag || SysAtflag) {
 807                                 if (Gen.g_dirfd != -1) {
 808                                         (void) close(Gen.g_dirfd);
 809                                 }
 810                                 Gen.g_dirfd = -1;
 811                                 if (passret != FILE_LINKED) {
 812                                         Gen.g_nam_p = Savenam_p;
 813                                         xattrs_out(file_pass);
 814                                 }
 815                         }
 816                 }
 817                 break;
 818         default:
 819                 msg(EXT, "Impossible action.");
 820         }
 821         if (Ofile > 0) {
 822                 if (close(Ofile) != 0)
 823                         msg(EXTN, "close error");
 824         }
 825         if (Archive > 0) {
 826                 if (close(Archive) != 0)
 827                         msg(EXTN, "close error");
 828         }
 829         if ((Args & OCq) == 0) {
 830                 Blocks = (u_longlong_t)(Blocks * Bufsize + SBlocks +
 831                     0x1FF) >> 9;
 832                 msg(EPOST, "%lld blocks", Blocks);
 833         }
 834         if (Error_cnt)
 835                 msg(EPOST, "%d error(s)", Error_cnt);
 836         return (EXIT_CODE);
 837 }
 838 
 839 /*
 840  * add_lnk: Add a linked file's header to the linked file data structure, by
 841  * either adding it to the end of an existing sub-list or starting
 842  * a new sub-list.  Each sub-list saves the links to a given file.
 843  *
 844  * Directly returns a pointer to the new entry; returns a pointer to the head
 845  * of the sub-list in which that entry is located through the argument.
 846  */
 847 
 848 static struct Lnk *
 849 add_lnk(struct Lnk **sublist_return)
 850 {
 851         struct Lnk *new_entry, *sublist;
 852 
 853         for (sublist = Lnk_hd.L_nxt_p;
 854             sublist != &Lnk_hd;
 855             sublist = sublist->L_nxt_p) {
 856                 if (sublist->L_gen.g_ino == G_p->g_ino &&
 857                     sublist->L_gen.g_dev == G_p->g_dev) {
 858                         /* found */
 859                         break;
 860                 }
 861         }
 862 
 863         new_entry = e_zalloc(E_EXIT, sizeof (struct Lnk));
 864 
 865         new_entry->L_lnk_p = NULL;
 866         new_entry->L_gen = *G_p; /* structure copy */
 867 
 868         new_entry->L_gen.g_nam_p = e_zalloc(E_EXIT, (size_t)G_p->g_namesz);
 869 
 870         (void) strcpy(new_entry->L_gen.g_nam_p, G_p->g_nam_p);
 871 
 872         if (sublist == &Lnk_hd) {
 873                 /* start new sub-list */
 874                 new_entry->L_nxt_p = &Lnk_hd;
 875                 new_entry->L_bck_p = Lnk_hd.L_bck_p;
 876                 Lnk_hd.L_bck_p = new_entry->L_bck_p->L_nxt_p = new_entry;
 877                 new_entry->L_lnk_p = NULL;
 878                 new_entry->L_cnt = 1;
 879                 new_entry->L_data = Onecopy ? 0 : 1;
 880                 sublist = new_entry;
 881         } else {
 882                 /* add to existing sub-list */
 883                 struct Lnk *ptr;
 884 
 885                 sublist->L_cnt++;
 886 
 887                 for (ptr = sublist;
 888                     ptr->L_lnk_p != NULL;
 889                     ptr = ptr->L_lnk_p) {
 890                         ptr->L_gen.g_filesz = G_p->g_filesz;
 891                 }
 892 
 893                 ptr->L_gen.g_filesz = G_p->g_filesz;
 894                 ptr->L_lnk_p = new_entry;
 895         }
 896 
 897         *sublist_return = sublist;
 898         return (new_entry);
 899 }
 900 
 901 /*
 902  * bfill: Read req_cnt bytes (out of filelen bytes) from the I/O buffer,
 903  * moving them to rd_buf_p.  When there are no bytes left in the I/O buffer,
 904  * Fillbuf is set and the I/O buffer is filled.  The variable dist is the
 905  * distance to lseek if an I/O error is encountered with the -k option set
 906  * (converted to a multiple of Bufsize).
 907  */
 908 
 909 static int
 910 bfill(void)
 911 {
 912         int i = 0, rv;
 913         static int eof = 0;
 914 
 915         if (!Dflag) {
 916         while ((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) {
 917                 errno = 0;
 918                 if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
 919                         if (((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) &&
 920                             (Eomflag == 0)) {
 921                                 Eomflag = 1;
 922                                 return (1);
 923                         }
 924                         if (errno == ENOSPC) {
 925                                 (void) chgreel(INPUT);
 926                                 if (Hdr_type == BAR) {
 927                                         skip_bar_volhdr();
 928                                 }
 929                                 continue;
 930                         } else if (Args & OCk) {
 931                                 if (i++ > MX_SEEKS)
 932                                         msg(EXT, "Cannot recover.");
 933                                 if (lseek(Archive, Bufsize, SEEK_REL) < 0)
 934                                         msg(EXTN, "Cannot lseek()");
 935                                 Error_cnt++;
 936                                 Buf_error++;
 937                                 rv = 0;
 938                                 continue;
 939                         } else
 940                                 ioerror(INPUT);
 941                 } /* (rv = g_read(Device, Archive ... */
 942                 if (Hdr_type != BAR || rv == Bufsize) {
 943                         Buffr.b_in_p += rv;
 944                         Buffr.b_cnt += (long)rv;
 945                 }
 946                 if (rv == Bufsize) {
 947                         eof = 0;
 948                         Blocks++;
 949                 } else if (rv == 0) {
 950                         if (!eof) {
 951                                 eof = 1;
 952                                 break;
 953                         }
 954                         (void) chgreel(INPUT);
 955                         eof = 0;        /* reset the eof after chgreel  */
 956 
 957                         /*
 958                          * if spans multiple volume, skip the volume header of
 959                          * the next volume so that the file currently being
 960                          * extracted can continue to be extracted.
 961                          */
 962                         if (Hdr_type == BAR) {
 963                                 skip_bar_volhdr();
 964                         }
 965 
 966                         continue;
 967                 } else {
 968                         eof = 0;
 969                         SBlocks += (u_longlong_t)rv;
 970                 }
 971         } /* (Buffr.b_end_p - Buffr.b_in_p) <= Bufsize */
 972 
 973         } else {                        /* Dflag */
 974                 errno = 0;
 975                 if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
 976                         return (-1);
 977                 } /* (rv = g_read(Device, Archive ... */
 978                 Buffr.b_in_p += rv;
 979                 Buffr.b_cnt += (long)rv;
 980                 if (rv == Bufsize) {
 981                         eof = 0;
 982                         Blocks++;
 983                 } else if (!rv) {
 984                         if (!eof) {
 985                                 eof = 1;
 986                                 return (rv);
 987                         }
 988                         return (-1);
 989                 } else {
 990                         eof = 0;
 991                         SBlocks += (u_longlong_t)rv;
 992                 }
 993         }
 994         return (rv);
 995 }
 996 
 997 /*
 998  * bflush: Move wr_cnt bytes from data_p into the I/O buffer.  When the
 999  * I/O buffer is full, Flushbuf is set and the buffer is written out.
1000  */
1001 
1002 static void
1003 bflush(void)
1004 {
1005         int rv;
1006 
1007         while (Buffr.b_cnt >= Bufsize) {
1008                 errno = 0;
1009                 if ((rv = g_write(Device, Archive, Buffr.b_out_p,
1010                     Bufsize)) < 0) {
1011                         if (errno == ENOSPC && !Dflag)
1012                                 rv = chgreel(OUTPUT);
1013                         else
1014                                 ioerror(OUTPUT);
1015                 }
1016                 Buffr.b_out_p += rv;
1017                 Buffr.b_cnt -= (long)rv;
1018                 if (rv == Bufsize)
1019                         Blocks++;
1020                 else if (rv > 0)
1021                         SBlocks += (u_longlong_t)rv;
1022         }
1023         rstbuf();
1024 }
1025 
1026 /*
1027  * chgreel: Determine if end-of-medium has been reached.  If it has,
1028  * close the current medium and prompt the user for the next medium.
1029  */
1030 
1031 static int
1032 chgreel(int dir)
1033 {
1034         int lastchar, tryagain, askagain, rv;
1035         int tmpdev;
1036         char str[APATH];
1037         struct stat statb;
1038 
1039         rv = 0;
1040         if (fstat(Archive, &statb) < 0)
1041                 msg(EXTN, "Error during stat() of archive");
1042         if ((statb.st_mode & S_IFMT) != S_IFCHR) {
1043                 if (dir == INPUT) {
1044                         msg(EXT, "%s%s\n",
1045                             "Can't read input:  end of file encountered ",
1046                             "prior to expected end of archive.");
1047                 }
1048         }
1049         msg(EPOST, "\007End of medium on \"%s\".", dir ? "output" : "input");
1050         if (is_floppy(Archive))
1051                 (void) ioctl(Archive, FDEJECT, NULL);
1052         if ((close(Archive) != 0) && (dir == OUTPUT))
1053                 msg(EXTN, "close error");
1054         Archive = 0;
1055         Volcnt++;
1056         for (;;) {
1057                 if (Rtty_p == NULL)
1058                         Rtty_p = fopen(Ttyname, "r");
1059                 do { /* tryagain */
1060                         if (IOfil_p) {
1061                                 do {
1062                                         msg(EPOST, Eom_p, Volcnt);
1063                                         if (!Rtty_p || fgets(str, sizeof (str),
1064                                             Rtty_p) == NULL)
1065                                                 msg(EXT, "Cannot read tty.");
1066                                         askagain = 0;
1067                                         switch (*str) {
1068                                         case '\n':
1069                                                 (void) strcpy(str, IOfil_p);
1070                                                 break;
1071                                         case 'q':
1072                                                 exit(EXIT_CODE);
1073                                         default:
1074                                                 askagain = 1;
1075                                         }
1076                                 } while (askagain);
1077                         } else {
1078 
1079                                 if (Hdr_type == BAR)
1080                                         Bar_vol_num++;
1081 
1082                                 msg(EPOST,
1083                                     "To continue, type device/file name when "
1084                                     "ready.");
1085                                 if (!Rtty_p || fgets(str, sizeof (str),
1086                                     Rtty_p) == NULL)
1087                                         msg(EXT, "Cannot read tty.");
1088                                 lastchar = strlen(str) - 1;
1089                                 if (*(str + lastchar) == '\n') /* remove '\n' */
1090                                         *(str + lastchar) = '\0';
1091                                 if (!*str)
1092                                         exit(EXIT_CODE);
1093                         }
1094                         tryagain = 0;
1095                         if ((Archive = open(str, dir)) < 0) {
1096                                 msg(ERRN, "Cannot open \"%s\"", str);
1097                                 tryagain = 1;
1098                         }
1099                 } while (tryagain);
1100                 (void) g_init(&tmpdev, &Archive);
1101                 if (tmpdev != Device)
1102                         msg(EXT, "Cannot change media types in mid-stream.");
1103                 if (dir == INPUT)
1104                         break;
1105                 else { /* dir == OUTPUT */
1106                         errno = 0;
1107                         if ((rv = g_write(Device, Archive, Buffr.b_out_p,
1108                             Bufsize)) == Bufsize)
1109                                 break;
1110                         else
1111                                 msg(ERR,
1112                                     "Unable to write this medium, try "
1113                                     "another.");
1114                 }
1115         } /* ;; */
1116         Eomflag = 0;
1117         return (rv);
1118 }
1119 
1120 /*
1121  * ckname: Check filenames against user specified patterns,
1122  * and/or ask the user for new name when -r is used.
1123  */
1124 
1125 static int
1126 ckname(int flag)
1127 {
1128         int     lastchar;
1129         size_t  rename_bufsz = Max_namesz + 1;
1130 
1131         if (Hdr_type != TAR && Hdr_type != USTAR && Hdr_type != BAR) {
1132                 /* Re-visit tar size issues later */
1133                 if (G_p->g_namesz - 1 > Max_namesz) {
1134                         msg(ERR, "Name exceeds maximum length - skipped.");
1135                         return (F_SKIP);
1136                 }
1137         }
1138 
1139         if (Pat_pp && !matched())
1140                 return (F_SKIP);
1141 
1142         /* rename interactively */
1143         if ((Args & OCr) && !Adir && !G_p->g_rw_sysattr) {
1144                 (void) fprintf(Wtty_p, gettext("Rename \"%s%s%s\"? "),
1145                     (G_p->g_attrnam_p == NULL) ? G_p->g_nam_p : Renam_p,
1146                     (G_p->g_attrnam_p == NULL) ? "" : gettext(" Attribute "),
1147                     (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
1148                 (void) fflush(Wtty_p);
1149                 if (fgets(Renametmp_p, rename_bufsz, Rtty_p) == NULL)
1150                         msg(EXT, "Cannot read tty.");
1151                 if (feof(Rtty_p))
1152                         exit(EXIT_CODE);
1153                 lastchar = strlen(Renametmp_p) - 1;
1154 
1155                 /* remove trailing '\n' */
1156                 if (*(Renametmp_p + lastchar) == '\n')
1157                         *(Renametmp_p + lastchar) = '\0';
1158                 if (*Renametmp_p == '\0') {
1159                         msg(POST, "%s%s%s Skipped.",
1160                             (G_p->g_attrnam_p == NULL) ? G_p->g_nam_p :
1161                             G_p->g_attrfnam_p,
1162                             (G_p->g_attrnam_p == NULL) ? "" :
1163                             gettext(" Attribute "),
1164                             (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
1165                         if (G_p->g_attrparent_p == NULL) {
1166                                 *G_p->g_nam_p = '\0';
1167                         }
1168                         if (Renam_attr_p) {
1169                                 *Renam_attr_p = '\0';
1170                         }
1171                         return (F_SKIP);
1172                 } else if (strcmp(Renametmp_p, ".") != 0) {
1173                         if (G_p->g_attrnam_p == NULL) {
1174                                 if (strlen(Renametmp_p) > strlen(
1175                                     G_p->g_nam_p)) {
1176                                         if ((G_p->g_nam_p != &nambuf[0]) &&
1177                                             (G_p->g_nam_p != &fullnam[0])) {
1178                                                 free(G_p->g_nam_p);
1179                                                 G_p->g_nam_p = e_zalloc(E_EXIT,
1180                                                     rename_bufsz);
1181                                         }
1182                                 }
1183                                 if (Renam_attr_p) {
1184                                         *Renam_attr_p = '\0';
1185                                 }
1186                                 if ((strlcpy(Renam_p, Renametmp_p,
1187                                     rename_bufsz) > rename_bufsz) ||
1188                                     (strlcpy(G_p->g_nam_p, Renametmp_p,
1189                                     rename_bufsz) > rename_bufsz)) {
1190                                         msg(EXTN, "buffer overflow");
1191                                 }
1192                         } else {
1193                                 if (G_p->g_attrnam_p != NULL) {
1194                                         free(G_p->g_attrnam_p);
1195                                         G_p->g_attrnam_p = e_strdup(E_EXIT,
1196                                             Renametmp_p);
1197                                         (void) strcpy(G_p->g_nam_p, Renam_p);
1198                                         if (Renam_attr_p) {
1199                                                 if (strlcpy(Renam_attr_p,
1200                                                     Renametmp_p, rename_bufsz) >
1201                                                     rename_bufsz) {
1202                                                         msg(EXTN,
1203                                                             "buffer overflow");
1204                                                 }
1205                                         }
1206                                 }
1207                         }
1208                 } else {
1209                         if (G_p->g_attrnam_p == NULL) {
1210                                 *Renam_p = '\0';
1211                         }
1212                         if (Renam_attr_p) {
1213                                 *Renam_attr_p = '\0';
1214                         }
1215                 }
1216         }
1217         if (flag != 0 || Onecopy == 0) {
1218                 VERBOSE((Args & OCt), G_p->g_nam_p);
1219         }
1220         if (Args & OCt)
1221                 return (F_SKIP);
1222         return (F_EXTR);
1223 }
1224 
1225 /*
1226  * ckopts: Check the validity of all command line options.
1227  */
1228 
1229 static void
1230 ckopts(long mask)
1231 {
1232         int oflag;
1233         char *t_p;
1234         long errmsk;
1235         uid_t   Euid = geteuid();       /* Effective uid of invoker */
1236 #ifdef SOLARIS_PRIVS
1237         priv_set_t *privset;
1238         priv_set_t *zones_privset;
1239 #endif  /* SOLARIS_PRIVS */
1240 
1241         if (mask & OCi) {
1242                 errmsk = mask & INV_MSK4i;
1243         } else if (mask & OCo) {
1244                 errmsk = mask & INV_MSK4o;
1245         } else if (mask & OCp) {
1246                 errmsk = mask & INV_MSK4p;
1247         } else {
1248                 msg(ERR, "One of -i, -o or -p must be specified.");
1249                 errmsk = 0;
1250         }
1251 
1252         if (errmsk) {
1253                 /* if non-zero, invalid options were specified */
1254                 Error_cnt++;
1255         }
1256 
1257         if ((mask & OCa) && (mask & OCm) && ((mask & OCi) ||
1258             (mask & OCo))) {
1259                 msg(ERR, "-a and -m are mutually exclusive.");
1260         }
1261 
1262         if ((mask & OCc) && (mask & OCH) &&
1263             (strcmp("odc", Hdr_p) != 0 && strcmp("odc_sparse", Hdr_p) != 0)) {
1264                 msg(ERR, "-c and -H are mutually exclusive.");
1265         }
1266 
1267         if ((mask & OCv) && (mask & OCV)) {
1268                 msg(ERR, "-v and -V are mutually exclusive.");
1269         }
1270 
1271         if ((mask & OCt) && (mask & OCV)) {
1272                 msg(ERR, "-t and -V are mutually exclusive.");
1273         }
1274 
1275         if ((mask & OCB) && (mask & OCC)) {
1276                 msg(ERR, "-B and -C are mutually exclusive.");
1277         }
1278 
1279         if ((mask & OCH) && (mask & OC6)) {
1280                 msg(ERR, "-H and -6 are mutually exclusive.");
1281         }
1282 
1283         if ((mask & OCM) && !((mask & OCI) || (mask & OCO))) {
1284                 msg(ERR, "-M not meaningful without -O or -I.");
1285         }
1286 
1287         if ((mask & OCA) && !(mask & OCO)) {
1288                 msg(ERR, "-A requires the -O option.");
1289         }
1290 
1291         if (Bufsize <= 0) {
1292                 msg(ERR, "Illegal size given for -C option.");
1293         }
1294 
1295         if (mask & OCH) {
1296                 t_p = Hdr_p;
1297 
1298                 while (*t_p != NULL) {
1299                         if (isupper(*t_p)) {
1300                                 *t_p = 'a' + (*t_p - 'A');
1301                         }
1302 
1303                         t_p++;
1304                 }
1305 
1306                 if (!(strcmp("odc", Hdr_p))) {
1307                         Hdr_type = CHR;
1308                         Max_namesz = CPATH;
1309                         Onecopy = 0;
1310                         Use_old_stat = 1;
1311                 } else if (!(strcmp("odc_sparse", Hdr_p))) {
1312                         Hdr_type = CHR;
1313                         Max_namesz = CPATH;
1314                         Onecopy = 0;
1315                         Use_old_stat = 1;
1316                         Compress_sparse = 1;
1317                 } else if (!(strcmp("ascii_sparse", Hdr_p))) {
1318                         Hdr_type = ASC;
1319                         Max_namesz = APATH;
1320                         Onecopy = 1;
1321                         Compress_sparse = 1;
1322                 } else if (!(strcmp("crc", Hdr_p))) {
1323                         Hdr_type = CRC;
1324                         Max_namesz = APATH;
1325                         Onecopy = 1;
1326                 } else if (!(strcmp("tar", Hdr_p))) {
1327                         if (Args & OCo) {
1328                                 Hdr_type = USTAR;
1329                                 Max_namesz = HNAMLEN - 1;
1330                         } else {
1331                                 Hdr_type = TAR;
1332                                 Max_namesz = TNAMLEN - 1;
1333                         }
1334                         Onecopy = 0;
1335                 } else if (!(strcmp("ustar", Hdr_p))) {
1336                         Hdr_type = USTAR;
1337                         Max_namesz = HNAMLEN - 1;
1338                         Onecopy = 0;
1339                 } else if (!(strcmp("bar", Hdr_p))) {
1340                         if ((Args & OCo) || (Args & OCp)) {
1341                                 msg(ERR,
1342                                     "Header type bar can only be used with -i");
1343                         }
1344 
1345                         if (Args & OCP) {
1346                                 msg(ERR,
1347                                     "Can't preserve using bar header");
1348                         }
1349 
1350                         Hdr_type = BAR;
1351                         Max_namesz = TNAMLEN - 1;
1352                         Onecopy = 0;
1353                 } else {
1354                         msg(ERR, "Invalid header \"%s\" specified", Hdr_p);
1355                 }
1356         }
1357 
1358         if (mask & OCr) {
1359                 Rtty_p = fopen(Ttyname, "r");
1360                 Wtty_p = fopen(Ttyname, "w");
1361 
1362                 if (Rtty_p == NULL || Wtty_p == NULL) {
1363                         msg(ERR, "Cannot rename, \"%s\" missing", Ttyname);
1364                 }
1365         }
1366 
1367         if ((mask & OCE) && (Ef_p = fopen(Efil_p, "r")) == NULL) {
1368                 msg(ERR, "Cannot open \"%s\" to read patterns", Efil_p);
1369         }
1370 
1371         if ((mask & OCI) && (Archive = open(IOfil_p, O_RDONLY)) < 0) {
1372                 msg(ERR, "Cannot open \"%s\" for input", IOfil_p);
1373         }
1374 
1375         if (mask & OCO) {
1376                 if (mask & OCA) {
1377                         if ((Archive = open(IOfil_p, O_RDWR)) < 0) {
1378                                 msg(ERR,
1379                                     "Cannot open \"%s\" for append",
1380                                     IOfil_p);
1381                         }
1382                 } else {
1383                         oflag = (O_WRONLY | O_CREAT | O_TRUNC);
1384 
1385                         if ((Archive = open(IOfil_p, oflag, 0777)) < 0) {
1386                                 msg(ERR,
1387                                     "Cannot open \"%s\" for output",
1388                                     IOfil_p);
1389                         }
1390                 }
1391         }
1392 
1393 #ifdef SOLARIS_PRIVS
1394         if ((privset = priv_allocset()) == NULL) {
1395                 msg(ERR, "Unable to allocate privilege set");
1396         } else if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1397                 msg(ERR, "Unable to obtain privilege set");
1398         } else {
1399                 zones_privset = priv_str_to_set("zone", "", NULL);
1400                 if (zones_privset != NULL) {
1401                         privileged = (priv_issubset(zones_privset,
1402                             privset) == B_TRUE);
1403                         priv_freeset(zones_privset);
1404                 } else {
1405                         msg(ERR, "Unable to map privilege to privilege set");
1406                 }
1407         }
1408         if (privset != NULL) {
1409                 priv_freeset(privset);
1410         }
1411 #else
1412         privileged = (Euid == 0);
1413 #endif  /* SOLARIS_PRIVS */
1414 
1415         if (mask & OCR) {
1416                 if ((Rpw_p = getpwnam(Own_p)) == NULL) {
1417                         msg(ERR, "\"%s\" is not a valid user id", Own_p);
1418                 } else if ((Euid != Rpw_p->pw_uid) && !privileged) {
1419                         msg(ERR, "R option only valid for super-user or "
1420                             "id matches login id of user executing cpio");
1421                 }
1422         }
1423 
1424         if ((mask & OCo) && !(mask & OCO)) {
1425                 Out_p = stderr;
1426         }
1427 
1428         if ((mask & OCp) && ((mask & (OCB|OCC)) == 0)) {
1429                 /*
1430                  * We are in pass mode with no block size specified.  Use the
1431                  * larger of the native page size and 8192.
1432                  */
1433 
1434                 Bufsize = (PageSize > 8192) ? PageSize : 8192;
1435         }
1436 }
1437 
1438 /*
1439  * cksum: Calculate the simple checksum of a file (CRC) or header
1440  * (TARTYP (TAR and USTAR)).  For -o and the CRC header, the file is opened and
1441  * the checksum is calculated.  For -i and the CRC header, the checksum
1442  * is calculated as each block is transferred from the archive I/O buffer
1443  * to the file system I/O buffer.  The TARTYP (TAR and USTAR) headers calculate
1444  * the simple checksum of the header (with the checksum field of the
1445  * header initialized to all spaces (\040).
1446  */
1447 
1448 static long
1449 cksum(char hdr, int byt_cnt, int *err)
1450 {
1451         char *crc_p, *end_p;
1452         int cnt;
1453         long checksum = 0L, have;
1454         off_t lcnt;
1455 
1456         if (err != NULL)
1457                 *err = 0;
1458         switch (hdr) {
1459         case CRC:
1460                 if (Args & OCi) { /* do running checksum */
1461                         end_p = Buffr.b_out_p + byt_cnt;
1462                         for (crc_p = Buffr.b_out_p; crc_p < end_p; crc_p++)
1463                                 checksum += (long)*crc_p;
1464                         break;
1465                 }
1466                 /* OCo - do checksum of file */
1467                 lcnt = G_p->g_filesz;
1468 
1469                 while (lcnt > 0) {
1470                         have = (lcnt < Bufsize) ? lcnt : Bufsize;
1471                         errno = 0;
1472                         if (read(Ifile, Buf_p, have) != have) {
1473                                 msg(ERR, "Error computing checksum.");
1474                                 if (err != NULL)
1475                                         *err = 1;
1476                                 break;
1477                         }
1478                         end_p = Buf_p + have;
1479                         for (crc_p = Buf_p; crc_p < end_p; crc_p++)
1480                                 checksum += (long)*crc_p;
1481                         lcnt -= have;
1482                 }
1483                 if (lseek(Ifile, (off_t)0, SEEK_ABS) < 0)
1484                         msg(ERRN, "Cannot reset file after checksum");
1485                 break;
1486         case TARTYP: /* TAR and USTAR */
1487                 crc_p = Thdr_p->tbuf.t_cksum;
1488                 for (cnt = 0; cnt < TCRCLEN; cnt++) {
1489                         *crc_p = '\040';
1490                         crc_p++;
1491                 }
1492                 crc_p = (char *)Thdr_p;
1493                 for (cnt = 0; cnt < TARSZ; cnt++) {
1494                         /*
1495                          * tar uses unsigned checksum, so we must use unsigned
1496                          * here in order to be able to read tar archives.
1497                          */
1498                         checksum += (long)((unsigned char)(*crc_p));
1499                         crc_p++;
1500                 }
1501                 break;
1502         default:
1503                 msg(EXT, "Impossible header type.");
1504         } /* hdr */
1505         return (checksum);
1506 }
1507 
1508 /*
1509  * creat_hdr: Fill in the generic header structure with the specific
1510  *            header information based on the value of Hdr_type.
1511  *
1512  *            return (1) if this process was successful, and (0) otherwise.
1513  */
1514 
1515 static int
1516 creat_hdr(void)
1517 {
1518         ushort_t ftype;
1519         int fullnamesize;
1520         dev_t dev;
1521         ino_t ino;
1522 
1523         ftype = SrcSt.st_mode & Ftype;
1524         Adir = (ftype == S_IFDIR);
1525         Aspec = (ftype == S_IFBLK || ftype == S_IFCHR || ftype == S_IFIFO ||
1526             ftype == S_IFSOCK);
1527         switch (Hdr_type) {
1528                 case BIN:
1529                         Gen.g_magic = CMN_BIN;
1530                         break;
1531                 case CHR:
1532                         Gen.g_magic = CMN_BIN;
1533                         break;
1534                 case ASC:
1535                         Gen.g_magic = CMN_ASC;
1536                         break;
1537                 case CRC:
1538                         Gen.g_magic = CMN_CRC;
1539                         break;
1540                 case USTAR:
1541                         /*
1542                          * If the length of the full name is greater than 256,
1543                          * print out a message and return.
1544                          */
1545                         if ((fullnamesize = strlen(Gen.g_nam_p)) > MAXNAM) {
1546                                 msg(ERR,
1547                                     "%s: file name too long", Gen.g_nam_p);
1548                                 return (0);
1549                         } else if (fullnamesize > NAMSIZ) {
1550                                 /*
1551                                  * The length of the full name is greater than
1552                                  * 100, so we must split the filename from the
1553                                  * path
1554                                  */
1555                                 char namebuff[NAMSIZ+1];
1556                                 char prebuff[PRESIZ+1];
1557                                 char *lastslash;
1558                                 int presize, namesize;
1559 
1560                                 (void) memset(namebuff, '\0',
1561                                     sizeof (namebuff));
1562                                 (void) memset(prebuff, '\0', sizeof (prebuff));
1563 
1564                                 lastslash = strrchr(Gen.g_nam_p, '/');
1565 
1566                                 if (lastslash != NULL) {
1567                                         namesize = strlen(++lastslash);
1568                                         presize = fullnamesize - namesize - 1;
1569                                 } else {
1570                                         namesize = fullnamesize;
1571                                         lastslash = Gen.g_nam_p;
1572                                         presize = 0;
1573                                 }
1574 
1575                                 /*
1576                                  * If the filename is greater than 100 we can't
1577                                  * archive the file
1578                                  */
1579                                 if (namesize > NAMSIZ) {
1580                                         msg(ERR,
1581                                             "%s: filename is greater than %d",
1582                                             lastslash, NAMSIZ);
1583                                         return (0);
1584                                 }
1585                                 (void) strncpy(&namebuff[0], lastslash,
1586                                     namesize);
1587                                 /*
1588                                  * If the prefix is greater than 155 we can't
1589                                  * archive the file.
1590                                  */
1591                                 if (presize > PRESIZ) {
1592                                         msg(ERR,
1593                                             "%s: prefix is greater than %d",
1594                                             Gen.g_nam_p, PRESIZ);
1595                                         return (0);
1596                                 }
1597                                 (void) strncpy(&prebuff[0], Gen.g_nam_p,
1598                                     presize);
1599 
1600                                 Gen.g_tname = e_zalloc(E_EXIT, namesize + 1);
1601                                 (void) strcpy(Gen.g_tname, namebuff);
1602 
1603                                 Gen.g_prefix = e_zalloc(E_EXIT, presize + 1);
1604                                 (void) strcpy(Gen.g_prefix, prebuff);
1605                         } else {
1606                                 Gen.g_tname = Gen.g_nam_p;
1607                         }
1608                         (void) strcpy(Gen.g_tmagic, "ustar");
1609                         (void) strcpy(Gen.g_version, "00");
1610 
1611                         dpasswd = getpwuid(SrcSt.st_uid);
1612                         if (dpasswd == NULL) {
1613                                 msg(EPOST,
1614                                     "cpio: could not get passwd information "
1615                                     "for %s%s%s",
1616                                     (Gen.g_attrnam_p == NULL) ?
1617                                     Gen.g_nam_p : Gen.g_attrfnam_p,
1618                                     (Gen.g_attrnam_p == NULL) ?
1619                                     "" : Gen.g_rw_sysattr ?
1620                                     gettext(" System Attribute ") :
1621                                     gettext(" Attribute "),
1622                                     (Gen.g_attrnam_p == NULL) ?
1623                                     "" : Gen.g_attrnam_p);
1624                                 /* make name null string */
1625                                 Gen.g_uname[0] = '\0';
1626                         } else {
1627                                 (void) strncpy(&Gen.g_uname[0],
1628                                     dpasswd->pw_name, 32);
1629                         }
1630                         dgroup = getgrgid(SrcSt.st_gid);
1631                         if (dgroup == NULL) {
1632                                 msg(EPOST,
1633                                     "cpio: could not get group information "
1634                                     "for %s%s%s",
1635                                     (Gen.g_attrnam_p == NULL) ?
1636                                     Gen.g_nam_p : Gen.g_attrfnam_p,
1637                                     (Gen.g_attrnam_p == NULL) ?
1638                                     "" : Gen.g_rw_sysattr ?
1639                                     gettext(" System Attribute ") :
1640                                     gettext(" Attribute "),
1641                                     (Gen.g_attrnam_p == NULL) ?
1642                                     "" : Gen.g_attrnam_p);
1643                                 /* make name null string */
1644                                 Gen.g_gname[0] = '\0';
1645                         } else {
1646                                 (void) strncpy(&Gen.g_gname[0],
1647                                     dgroup->gr_name, 32);
1648                         }
1649                         Gen.g_typeflag = tartype(ftype);
1650                         /* FALLTHROUGH */
1651                 case TAR:
1652                         (void) memset(T_lname, '\0', sizeof (T_lname));
1653                         break;
1654                 default:
1655                         msg(EXT, "Impossible header type.");
1656         }
1657 
1658         if (Use_old_stat && (Gen.g_attrnam_p != NULL)) {
1659                 /*
1660                  * When processing extended attributes, creat_hdr()
1661                  * can get called multiple times which means that
1662                  * SrcSt.st.st_dev would have gotten converted to
1663                  * -Hodc format.  We should always use the original
1664                  * device here as we need to be able to match on
1665                  * the original device id from the file that was
1666                  * previewed in sl_preview_synonyms().
1667                  */
1668                 dev = Savedev;
1669         } else {
1670                 dev = SrcSt.st_dev;
1671         }
1672         ino = SrcSt.st_ino;
1673 
1674         if (Use_old_stat) {
1675                 SrcSt = *OldSt;
1676         }
1677 
1678         Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
1679         Gen.g_uid = SrcSt.st_uid;
1680         Gen.g_gid = SrcSt.st_gid;
1681         Gen.g_dev = SrcSt.st_dev;
1682 
1683         if (Use_old_stat) {
1684                 /* -Hodc */
1685 
1686                 sl_info_t *p = sl_search(dev, ino, ftype);
1687                 Gen.g_ino = p ? p->sl_ino2 : -1;
1688 
1689                 if (Gen.g_ino == (ulong_t)-1) {
1690                         msg(ERR, "%s%s%s: cannot be archived - inode too big "
1691                             "for -Hodc format",
1692                             (Gen.g_attrnam_p == NULL) ?
1693                             Gen.g_nam_p : Gen.g_attrfnam_p,
1694                             (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
1695                             gettext(" System Attribute ") :
1696                             gettext(" Attribute "),
1697                             (Gen.g_attrnam_p == NULL) ? "" : Gen.g_attrnam_p);
1698                         return (0);
1699                 }
1700         } else {
1701                 Gen.g_ino = SrcSt.st_ino;
1702         }
1703 
1704         Gen.g_mode = SrcSt.st_mode;
1705         Gen.g_mtime = SrcSt.st_mtime;
1706         Gen.g_nlink = Adir ? SrcSt.st_nlink : sl_numlinks(dev, ino, ftype);
1707 
1708         if (ftype == S_IFREG || ftype == S_IFLNK)
1709                 Gen.g_filesz = (off_t)SrcSt.st_size;
1710         else
1711                 Gen.g_filesz = (off_t)0;
1712         Gen.g_rdev = SrcSt.st_rdev;
1713         return (1);
1714 }
1715 
1716 /*
1717  * creat_lnk: Create a link from the existing name1_p to name2_p.
1718  */
1719 
1720 static
1721 int
1722 creat_lnk(int dirfd, char *name1_p, char *name2_p)
1723 {
1724         int cnt = 0;
1725 
1726         do {
1727                 errno = 0;
1728                 if (!link(name1_p, name2_p)) {
1729                         if (aclp != NULL) {
1730                                 acl_free(aclp);
1731                                 aclp = NULL;
1732                                 acl_is_set = 0;
1733                         }
1734                         cnt = 0;
1735                         break;
1736                 } else if ((errno == EEXIST) && (cnt == 0)) {
1737                         struct stat lsb1;
1738                         struct stat lsb2;
1739 
1740                         /*
1741                          * Check to see if we are trying to link this
1742                          * file to itself.  If so, count the effort as
1743                          * successful.  If the two files are different,
1744                          * or if either lstat is unsuccessful, proceed
1745                          * as we would have otherwise; the appropriate
1746                          * error will be reported subsequently.
1747                          */
1748 
1749                         if (lstat(name1_p, &lsb1) != 0) {
1750                                 msg(ERR, "Cannot lstat source file %s",
1751                                     name1_p);
1752                         } else {
1753                                 if (lstat(name2_p, &lsb2) != 0) {
1754                                         msg(ERR, "Cannot lstat "
1755                                             "destination file %s", name2_p);
1756                                 } else {
1757                                         if (lsb1.st_dev == lsb2.st_dev &&
1758                                             lsb1.st_ino == lsb2.st_ino) {
1759                                                 VERBOSE((Args & (OCv | OCV)),
1760                                                     name2_p);
1761                                                 return (0);
1762                                         }
1763                                 }
1764                         }
1765 
1766                         if (!(Args & OCu) && G_p->g_mtime <= DesSt.st_mtime)
1767                                 msg(ERR, "Existing \"%s\" same age or newer",
1768                                     name2_p);
1769                         else if (unlinkat(dirfd, get_component(name2_p), 0) < 0)
1770                                 msg(ERRN, "Error cannot unlink \"%s\"",
1771                                     name2_p);
1772                 }
1773                 cnt++;
1774         } while ((cnt < 2) && missdir(name2_p) == 0);
1775         if (!cnt) {
1776                 char *newname;
1777                 char *fromname;
1778                 char *attrname;
1779 
1780                 newname = name2_p;
1781                 fromname = name1_p;
1782                 attrname = Gen.g_attrnam_p;
1783                 if (attrname) {
1784                         if (Args & OCp) {
1785                                 newname = fromname = Fullnam_p;
1786                         } else {
1787                                 newname = Gen.g_attrfnam_p;
1788                         }
1789                 }
1790                 if (Args & OCv) {
1791                         (void) fprintf(Err_p,
1792                             gettext("%s%s%s linked to %s%s%s\n"), newname,
1793                             (attrname == NULL) ? "" : gettext(" attribute "),
1794                             (attrname == NULL) ? "" : attrname,
1795                             (attrname == NULL) ? fromname : newname,
1796                             (attrname == NULL) ? "" : gettext(" attribute "),
1797                             (attrname == NULL) ? "" : name1_p);
1798                 } else {
1799                         VERBOSE((Args & (OCv | OCV)), newname);
1800                 }
1801         } else if (cnt == 1)
1802                 msg(ERRN,
1803                     "Unable to create directory for \"%s\"", name2_p);
1804         else if (cnt == 2)
1805                 msg(ERRN,
1806                     "Cannot link \"%s\" and \"%s\"", name1_p, name2_p);
1807         return (cnt);
1808 }
1809 
1810 /*
1811  * creat_spec:
1812  *   Create one of the following:
1813  *       directory
1814  *       character special file
1815  *       block special file
1816  *       fifo
1817  *       socket
1818  */
1819 
1820 static int
1821 creat_spec(int dirfd)
1822 {
1823         char *nam_p;
1824         int cnt, result, rv = 0;
1825         char *curdir;
1826         char *lastslash;
1827 
1828         Do_rename = 0;  /* creat_tmp() may reset this */
1829 
1830         if (Args & OCp) {
1831                 nam_p = Fullnam_p;
1832         } else {
1833                 nam_p = G_p->g_nam_p;
1834         }
1835 
1836         /*
1837          * Is this the extraction of the hidden attribute directory?
1838          * If we are processing the hidden attribute directory of an
1839          * attribute, then just return as modes and times cannot be set.
1840          * Otherwise, if we are processing a hidden attribute, just set
1841          * the mode/times correctly and return.
1842          */
1843 
1844         if (Hiddendir) {
1845                 if (G_p->g_attrparent_p == NULL) {
1846                         if (Args & OCR) {
1847                                 if (fchownat(dirfd, ".", Rpw_p->pw_uid,
1848                                     Rpw_p->pw_gid, 0) != 0) {
1849                                         msg(ERRN,
1850                                             "Cannot chown() \"attribute "
1851                                             "directory of file %s\"",
1852                                             G_p->g_attrfnam_p);
1853                                 }
1854                         } else if ((fchownat(dirfd, ".", G_p->g_uid,
1855                             G_p->g_gid, 0) != 0) && privileged) {
1856                                 msg(ERRN,
1857                                     "Cannot chown() \"attribute directory of "
1858                                     "file %s\"", G_p->g_attrfnam_p);
1859                         }
1860 
1861                         if (fchmod(dirfd, G_p->g_mode) != 0) {
1862                                 msg(ERRN,
1863                                     "Cannot chmod() \"attribute directory of "
1864                                     "file %s\"", G_p->g_attrfnam_p);
1865                         }
1866 
1867                         acl_is_set = 0;
1868                         if (Pflag && aclp != NULL) {
1869                                 if (facl_set(dirfd, aclp) < 0) {
1870                                         msg(ERRN,
1871                                             "failed to set acl on attribute"
1872                                             " directory of %s ",
1873                                             G_p->g_attrfnam_p);
1874                                 } else {
1875                                         acl_is_set = 1;
1876                                 }
1877                                 acl_free(aclp);
1878                                 aclp = NULL;
1879                         }
1880                 }
1881 
1882                 return (1);
1883         }
1884 
1885         result = stat(nam_p, &DesSt);
1886 
1887         if (ustar_dir() || Adir) {
1888                 /*
1889                  *  The archive file is a directory.
1890                  *  Skip "." and ".."
1891                  */
1892 
1893                 curdir = strrchr(nam_p, '.');
1894 
1895                 if (curdir != NULL && curdir[1] == NULL) {
1896                         lastslash = strrchr(nam_p, '/');
1897 
1898                         if (lastslash != NULL) {
1899                                 lastslash++;
1900                         } else {
1901                                 lastslash = nam_p;
1902                         }
1903 
1904                         if (!(strcmp(lastslash, ".")) ||
1905                             !(strcmp(lastslash, ".."))) {
1906                                 return (1);
1907                         }
1908                 }
1909 
1910                 if (result == 0) {
1911                         /* A file by the same name exists. */
1912 
1913                         /* Take care of ACLs */
1914                         acl_is_set = 0;
1915 
1916                         if (Pflag && aclp != NULL) {
1917                                 if (acl_set(nam_p, aclp) < 0) {
1918                                         msg(ERRN,
1919                                             "\"%s\": failed to set acl",
1920                                             nam_p);
1921                                 } else {
1922                                         acl_is_set = 1;
1923                                 }
1924 
1925                                 acl_free(aclp);
1926                                 aclp = NULL;
1927                         }
1928                         if (Args & OCd) {
1929                                 /*
1930                                  * We are creating directories.  Keep the
1931                                  * existing file.
1932                                  */
1933 
1934                                 rstfiles(U_KEEP, dirfd);
1935                         }
1936 
1937                         /* Report success. */
1938 
1939                         return (1);
1940                 }
1941         } else {
1942                 /* The archive file is not a directory. */
1943 
1944                 if (result == 0) {
1945                         /*
1946                          * A file by the same name exists.  Move it to a
1947                          * temporary file.
1948                          */
1949 
1950                         if (creat_tmp(nam_p) < 0) {
1951                                 /*
1952                                  * We weren't able to create the temp file.
1953                                  * Report failure.
1954                                  */
1955 
1956                                 return (0);
1957                         }
1958                 }
1959         }
1960 
1961         /*
1962          * This pile tries to create the file directly, and, if there is a
1963          * problem, creates missing directories, and then tries to create the
1964          * file again.  Two strikes and you're out.
1965          */
1966 
1967         cnt = 0;
1968 
1969         do {
1970                 if (ustar_dir() || Adir) {
1971                         /* The archive file is a directory. */
1972 
1973                         result = mkdir(nam_p, G_p->g_mode);
1974                 } else if (ustar_spec() || Aspec) {
1975                         /*
1976                          * The archive file is block special,
1977                          * char special, socket, or a fifo.
1978                          * Note that, for a socket, the third
1979                          * parameter to mknod() is ignored.
1980                          */
1981 
1982                         result = mknod(nam_p, (int)G_p->g_mode,
1983                             (int)G_p->g_rdev);
1984                 }
1985 
1986                 if (result >= 0) {
1987                         /*
1988                          * The file creation succeeded.  Take care of the ACLs.
1989                          */
1990 
1991                         acl_is_set = 0;
1992 
1993                         if (Pflag && aclp != NULL) {
1994                                 if (acl_set(nam_p, aclp) < 0) {
1995                                         msg(ERRN,
1996                                             "\"%s\": failed to set acl", nam_p);
1997                                 } else {
1998                                         acl_is_set = 1;
1999                                 }
2000 
2001                                 acl_free(aclp);
2002                                 aclp = NULL;
2003                         }
2004 
2005                         cnt = 0;
2006                         break;
2007                 }
2008 
2009                 cnt++;
2010         } while (cnt < 2 && missdir(nam_p) == 0);
2011 
2012         switch (cnt) {
2013         case 0:
2014                 rv = 1;
2015                 rstfiles(U_OVER, dirfd);
2016                 break;
2017 
2018         case 1:
2019                 msg(ERRN,
2020                     "Cannot create directory for \"%s\"", nam_p);
2021 
2022                 if (*Over_p == '\0') {
2023                         rstfiles(U_KEEP, dirfd);
2024                 }
2025 
2026                 break;
2027 
2028         case 2:
2029                 if (ustar_dir() || Adir) {
2030                         msg(ERRN, "Cannot create directory \"%s\"", nam_p);
2031                 } else if (ustar_spec() || Aspec) {
2032                         msg(ERRN, "Cannot mknod() \"%s\"", nam_p);
2033                 }
2034 
2035                 if (*Over_p == '\0') {
2036                         rstfiles(U_KEEP, dirfd);
2037                 }
2038 
2039                 break;
2040 
2041         default:
2042                 msg(EXT, "Impossible case.");
2043         }
2044 
2045         return (rv);
2046 }
2047 
2048 /*
2049  * creat_tmp:
2050  */
2051 
2052 static int
2053 creat_tmp(char *nam_p)
2054 {
2055         char *t_p;
2056         int     cwd;
2057 
2058         if ((Args & OCp) && G_p->g_ino == DesSt.st_ino &&
2059             G_p->g_dev == DesSt.st_dev) {
2060                 msg(ERR, "Attempt to pass a file to itself.");
2061                 return (-1);
2062         }
2063 
2064         if (G_p->g_mtime <= DesSt.st_mtime && !(Args & OCu)) {
2065                 msg(ERR, "Existing \"%s\" same age or newer", nam_p);
2066                 return (-1);
2067         }
2068 
2069         /* Make the temporary file name. */
2070 
2071         (void) strcpy(Over_p, nam_p);
2072         t_p = Over_p + strlen(Over_p);
2073 
2074         while (t_p != Over_p) {
2075                 if (*(t_p - 1) == '/')
2076                         break;
2077                 t_p--;
2078         }
2079 
2080         (void) strcpy(t_p, "XXXXXX");
2081 
2082         if (G_p->g_attrnam_p != NULL) {
2083                 /*
2084                  * Save our current directory, so we can go into
2085                  * the attribute directory to make the temp file
2086                  * and then return.
2087                  */
2088 
2089                 cwd = save_cwd();
2090                 (void) fchdir(G_p->g_dirfd);
2091         }
2092 
2093         (void) mktemp(Over_p);
2094 
2095         if (G_p->g_attrnam_p != NULL) {
2096                 /* Return to the current directory. */
2097 
2098                 rest_cwd(cwd);
2099         }
2100 
2101         if (*Over_p == '\0') {
2102                 /* mktemp reports a failure. */
2103 
2104                 msg(ERR, "Cannot get temporary file name.");
2105                 return (-1);
2106         }
2107 
2108         /*
2109          * If it's a regular file, write to the temporary file, and then rename
2110          * in order to accommodate potential executables.
2111          *
2112          * Note: g_typeflag is only defined (set) for USTAR archive types.  It
2113          * defaults to 0 in the cpio-format-regular file case, so this test
2114          * succeeds.
2115          */
2116 
2117         if (G_p->g_typeflag == 0 &&
2118             (DesSt.st_mode & (ulong_t)Ftype) == S_IFREG &&
2119             (G_p->g_mode & (ulong_t)Ftype) == S_IFREG) {
2120                 /*
2121                  * The archive file and the filesystem file are both regular
2122                  * files.  We write to the temporary file in this case.
2123                  */
2124 
2125                 if (Args & OCp) {
2126                         if (G_p->g_attrnam_p == NULL) {
2127                                 Fullnam_p = Over_p;
2128                         } else {
2129                                 Attrfile_p = Over_p;
2130                         }
2131                 } else {
2132                         G_p->g_nam_p = Over_p;
2133                         if (G_p->g_attrnam_p != NULL) {
2134                                 Attrfile_p = Over_p;
2135                         }
2136                 }
2137 
2138                 if (G_p->g_attrnam_p == NULL) {
2139                         Over_p = nam_p;
2140                 } else {
2141                         Over_p = G_p->g_attrnam_p;
2142                 }
2143 
2144                 Do_rename = 1;
2145         } else {
2146                 /*
2147                  * Either the archive file or the filesystem file is not a
2148                  * regular file.
2149                  */
2150 
2151                 Do_rename = 0;
2152 
2153                 if (S_ISDIR(DesSt.st_mode)) {
2154                         /*
2155                          * The filesystem file is a directory.
2156                          *
2157                          * Save the current working directory because we will
2158                          * want to restore it back just in case remove_dir()
2159                          * fails or get confused about where we should be.
2160                          */
2161 
2162                         *Over_p = '\0';
2163                         cwd = save_cwd();
2164 
2165                         if (remove_dir(nam_p) < 0) {
2166                                 msg(ERRN,
2167                                     "Cannot remove the directory \"%s\"",
2168                                     nam_p);
2169                                 /*
2170                                  * Restore working directory back to the one
2171                                  * saved earlier.
2172                                  */
2173 
2174                                 rest_cwd(cwd);
2175                                 return (-1);
2176                         }
2177 
2178                         /*
2179                          * Restore working directory back to the one
2180                          * saved earlier
2181                          */
2182 
2183                         rest_cwd(cwd);
2184                 } else {
2185                         /*
2186                          * The file is not a directory. Will use the original
2187                          * link/unlink construct, however, if the file is
2188                          * namefs, link would fail with EXDEV. Therefore, we
2189                          * use rename() first to back up the file.
2190                          */
2191                         if (rename(nam_p, Over_p) < 0) {
2192                                 /*
2193                                  * If rename failed, try old construction
2194                                  * method.
2195                                  */
2196                                 if (link(nam_p, Over_p) < 0) {
2197                                         msg(ERRN,
2198                                             "Cannot rename temporary file "
2199                                             "\"%s\" to \"%s\"", Over_p, nam_p);
2200                                         *Over_p = '\0';
2201                                         return (-1);
2202                                 }
2203 
2204                                 if (unlink(nam_p) < 0) {
2205                                         msg(ERRN,
2206                                             "Cannot unlink() current \"%s\"",
2207                                             nam_p);
2208                                         (void) unlink(Over_p);
2209                                         *Over_p = '\0';
2210                                         return (-1);
2211                                 }
2212                         }
2213                 }
2214         }
2215 
2216         return (1);
2217 }
2218 
2219 /*
2220  * Copy the datasize amount of data from the input file to buffer.
2221  *
2222  * ifd          - Input file descriptor.
2223  * buffer       - Buffer (allocated by caller) to copy data to.
2224  * datasize     - The amount of data to read from the input file
2225  *              and copy to the buffer.
2226  * error        - When reading from an Archive file, indicates unreadable
2227  *              data was encountered, otherwise indicates errno.
2228  * data_in_info - Information needed when called from data_in().
2229  */
2230 static ssize_t
2231 read_chunk(int ifd, char *buffer, size_t datasize, data_in_t *data_in_info)
2232 {
2233         if (Args & OCp) {
2234                 return (read(ifd, buffer, datasize));
2235         } else {
2236                 FILL(datasize);
2237                 if (data_in_info->data_in_proc_mode != P_SKIP) {
2238                         if (Hdr_type == CRC)
2239                                 data_in_info->data_in_cksumval += cksum(CRC,
2240                                     datasize, NULL);
2241                         if (data_in_info->data_in_swapfile)
2242                                 swap(Buffr.b_out_p, datasize);
2243 
2244 
2245                         /*
2246                          * if the bar archive is compressed, set up a pipe and
2247                          * do the de-compression while reading in the file
2248                          */
2249                         if (Hdr_type == BAR) {
2250                                 if (data_in_info->data_in_compress_flag == 0 &&
2251                                     Compressed) {
2252                                         setup_uncompress(
2253                                             &(data_in_info->data_in_pipef));
2254                                         data_in_info->data_in_compress_flag++;
2255                                 }
2256                         }
2257                 }
2258                 (void) memcpy(buffer, Buffr.b_out_p, datasize);
2259                 Buffr.b_out_p += datasize;
2260                 Buffr.b_cnt -= datasize;
2261                 return (datasize);
2262         }
2263 }
2264 
2265 /*
2266  * Read as much data as we can.
2267  *
2268  * ifd          - input file descriptor.
2269  * buf          - Buffer (allocated by caller) to copy data to.
2270  * bytes        - The amount of data to read from the input file
2271  *              and copy to the buffer.
2272  * rdblocksz    - The size of the chunk of data to read.
2273  *
2274  * Return number of bytes failed to read.
2275  * Return -1 when buffer is empty and read failed.
2276  */
2277 static int
2278 read_bytes(int ifd, char *buf, size_t bytes, size_t rdblocksz,
2279     data_in_t *data_in_info)
2280 {
2281         size_t  bytesread;
2282         ssize_t got;
2283 
2284         for (bytesread = 0; bytesread < bytes; bytesread += got) {
2285                 /*
2286                  * Read the data from either the input file descriptor
2287                  * or the archive file.  read_chunk() will only return
2288                  * <= 0 if data_copy() was called from data_pass().
2289                  */
2290                 if ((got = read_chunk(ifd, buf + bytesread,
2291                     min(bytes - bytesread, rdblocksz),
2292                     data_in_info)) <= 0) {
2293                         /*
2294                          * We come here only in the pass mode.
2295                          * If data couldn't be read from the input file
2296                          * descriptor, return number of bytes in the buf.
2297                          * If buffer is empty, return -1.
2298                          */
2299                         if (bytesread == 0) {
2300                                 if (got == 0) /* EOF */
2301                                         data_in_info->data_in_rd_eof = 1;
2302                                 return (-1);
2303                         }
2304                         return (bytes - bytesread);
2305                 }
2306         }
2307         return (0);
2308 }
2309 
2310 /*
2311  * Write as much data as we can.
2312  *
2313  * ofd          - output file descriptor.
2314  * buf          - Source buffer to output data from.
2315  * maxwrite     - The amount of data to write to the output.
2316  *
2317  * return 0 upon success.
2318  */
2319 static int
2320 write_bytes(int ofd, char *buf, size_t maxwrite, data_in_t *data_in_info)
2321 {
2322         ssize_t cnt;
2323 
2324         errno = 0;
2325         if ((cnt = write(ofd, buf, maxwrite)) < (ssize_t)maxwrite) {
2326                 data_in_info->data_in_errno = errno;
2327                 /*
2328                  * data_in() needs to know if it was an actual write(2)
2329                  * failure, or if we just couldn't write all of the data
2330                  * requested so that we know that the rest of the file's
2331                  * data can be read but not written.
2332                  */
2333                 if (cnt != -1)
2334                         data_in_info->data_in_wr_part = 1;
2335                 return (1);
2336         } else if (Args & OCp) {
2337                 Blocks += (u_longlong_t)((cnt + (Bufsize - 1)) / Bufsize);
2338         }
2339         return (0);
2340 }
2341 
2342 /*
2343  * Perform I/O for given byte size with using limited i/o block size
2344  * and supplied buffer.
2345  *
2346  * ifd/ofd      - i/o file descriptor
2347  * buf          - buffer to be used for i/o
2348  * bytes        - Amount to read/write
2349  * wrblocksz    - Output block size.
2350  * rdblocksz    - Read block size.
2351  *
2352  * Return 0 upon success. Return negative if read failed.
2353  * Return positive non-zero if write failed.
2354  */
2355 static int
2356 rdwr_bytes(int ifd, int ofd, char *buf, off_t bytes,
2357     size_t wrblocksz, size_t rdblocksz, data_in_t *data_in_info)
2358 {
2359         int rv, sz;
2360         int error = 0;
2361         int write_it = (data_in_info->data_in_proc_mode != P_SKIP);
2362 
2363         while (bytes > 0) {
2364                 /*
2365                  * If the number of bytes left to write is smaller than
2366                  * the preferred I/O size, then we're about to do our final
2367                  * write to the file, so just set wrblocksz to the number of
2368                  * bytes left to write.
2369                  */
2370                 if (bytes < wrblocksz)
2371                         wrblocksz = bytes;
2372 
2373                 /* Read input till satisfy output block size */
2374                 sz = read_bytes(ifd, buf, wrblocksz, rdblocksz, data_in_info);
2375                 if (sz < 0)
2376                         return (sz);
2377 
2378                 if (write_it) {
2379                         rv = write_bytes(ofd, buf,
2380                             wrblocksz - sz, data_in_info);
2381                         if (rv != 0) {
2382                                 /*
2383                                  * If we wrote partial, we return and quits.
2384                                  * Otherwise, read through the rest of input
2385                                  * to go to the next file.
2386                                  */
2387                                 if ((Args & OCp) ||
2388                                     data_in_info->data_in_wr_part) {
2389                                         return (rv);
2390                                 } else {
2391                                         write_it = 0;
2392                                 }
2393                                 error = 1;
2394                         }
2395                 }
2396                 bytes -= (wrblocksz - sz);
2397         }
2398         return (error);
2399 }
2400 
2401 /*
2402  * Write zeros for give size.
2403  *
2404  * ofd          - output file descriptor
2405  * buf          - buffer to fill with zeros
2406  * bytes        - Amount to write
2407  * wrblocksz    - Write block size
2408  *
2409  * return 0 upon success.
2410  */
2411 static int
2412 write_zeros(int ofd, char *buf, off_t bytes, size_t wrblocksz,
2413     data_in_t *data_in_info)
2414 {
2415         int     rv;
2416 
2417         (void) memset(buf, 0, min(bytes, wrblocksz));
2418         while (bytes > 0) {
2419                 if (bytes < wrblocksz)
2420                         wrblocksz = bytes;
2421                 rv = write_bytes(ofd, buf, wrblocksz, data_in_info);
2422                 if (rv != 0)
2423                         return (rv);
2424                 bytes -= wrblocksz;
2425         }
2426         return (0);
2427 }
2428 
2429 /*
2430  * To figure out the size of the buffer used to accumulate data from
2431  * readtape() and to write to the file, we need to determine the largest
2432  * chunk of data to be written to the file at one time. This is determined
2433  * based on the following three things:
2434  *      1) The size of the archived file.
2435  *      2) The preferred I/O size of the file.
2436  *      3) If the file is a read-write system attribute file.
2437  * If the size of the file is less than the preferred I/O size or it's a
2438  * read-write system attribute file, which must be written in one operation,
2439  * then set the maximum write size to the size of the archived file.
2440  * Otherwise, the maximum write size is preferred I/O size.
2441  */
2442 static int
2443 calc_maxwrite(int ofd, int rw_sysattr, off_t bytes, size_t blocksize)
2444 {
2445         struct stat tsbuf;
2446         size_t maxwrite;
2447         size_t piosize;         /* preferred I/O size */
2448 
2449         if (rw_sysattr || bytes < blocksize) {
2450                 maxwrite = bytes;
2451         } else {
2452                 if (fstat(ofd, &tsbuf) == 0) {
2453                         piosize = tsbuf.st_blksize;
2454                 } else {
2455                         piosize = blocksize;
2456                 }
2457                 maxwrite = min(bytes, piosize);
2458         }
2459         return (maxwrite);
2460 }
2461 /*
2462  * data_copy() and data_copy_with_holes() copy data from the input
2463  * file to output file descriptor. If ifd is -1, then the input file is
2464  * the archive file.
2465  *
2466  * Parameters
2467  *      ifd             - Input file descriptor to read from.
2468  *      ofd             - Output file descriptor of extracted file.
2469  *      rw_sysattr      - Flag indicating if a file is an extended
2470  *                      system attribute file.
2471  *      bytes           - Amount of data (file size) of copy/write.
2472  *      blocksize       - Amount of data to read at a time from either
2473  *                      the input file descriptor or from the archive.
2474  *      data_in_info    - information needed while reading data when
2475  *                      called by data_in().
2476  *      holes           - Information of holes in the input file.
2477  *
2478  * Return code
2479  *      0               Success
2480  *      < 0          An error occurred during the read of the input
2481  *                      file
2482  *      > 0          An error occurred during the write of the output
2483  *                      file descriptor.
2484  */
2485 static int
2486 data_copy(int ifd, int ofd, int rw_sysattr, off_t bytes,
2487     size_t blocksize, data_in_t *data_in_info)
2488 {
2489         char *buf;
2490         size_t maxwrite;
2491         int rv;
2492 
2493         /* No data to copy. */
2494         if (bytes == 0)
2495                 return (0);
2496 
2497         maxwrite = calc_maxwrite(ofd, rw_sysattr, bytes, blocksize);
2498         buf = e_zalloc(E_EXIT, maxwrite);
2499 
2500         rv = rdwr_bytes(ifd, ofd, buf, bytes, maxwrite,
2501             blocksize, data_in_info);
2502 
2503         free(buf);
2504         return (rv);
2505 }
2506 
2507 static int
2508 data_copy_with_holes(int ifd, int ofd, int rw_sysattr, off_t bytes,
2509     size_t blocksize, data_in_t *data_in_info, holes_info_t *holes)
2510 {
2511         holes_list_t    *hl;
2512         off_t           curpos, noff, datasize;
2513         char            *buf;
2514         size_t          maxwrite;
2515         int             rv, error;
2516 
2517         if (bytes == 0)
2518                 return (0);
2519 
2520         maxwrite = calc_maxwrite(ofd, rw_sysattr, bytes, blocksize);
2521         buf = e_zalloc(E_EXIT, maxwrite);
2522 
2523         error = 0;
2524         curpos = 0;
2525         for (hl = holes->holes_list; hl != NULL; hl = hl->hl_next) {
2526                 if (curpos != hl->hl_data) {
2527                         /* adjust output position */
2528                         noff = lseek(ofd, hl->hl_data, SEEK_SET);
2529                         if (noff != hl->hl_data) {
2530                                 /*
2531                                  * Can't seek to the target, try to adjust
2532                                  * position by filling with zeros.
2533                                  */
2534                                 datasize = hl->hl_data - curpos;
2535                                 rv = write_zeros(ofd, buf, datasize,
2536                                     maxwrite, data_in_info);
2537                                 if (rv != 0)
2538                                         goto errout;
2539                         }
2540                         /*
2541                          * Data is contiguous in the archive, but fragmented
2542                          * in the regular file, so we also adjust the input
2543                          * file position in pass mode.
2544                          */
2545                         if (Args & OCp) {
2546                                 /* adjust input position */
2547                                 (void) lseek(ifd, hl->hl_data, SEEK_SET);
2548                         }
2549                         curpos = hl->hl_data;
2550                 }
2551                 datasize = hl->hl_hole - hl->hl_data;
2552                 if (datasize == 0) {
2553                         /*
2554                          * There is a hole at the end of file. To create
2555                          * such hole, we append one byte, and truncate the
2556                          * last block. This is necessary because ftruncate(2)
2557                          * alone allocates one block on the end of file.
2558                          */
2559                         rv = write_zeros(ofd, buf, 1, maxwrite, data_in_info);
2560                         if (rv != 0)
2561                                 goto errout;
2562                         (void) ftruncate(ofd, hl->hl_data);
2563                         break;
2564                 }
2565                 rv = rdwr_bytes(ifd, ofd, buf, datasize, maxwrite,
2566                     blocksize, data_in_info);
2567                 if (rv != 0) {
2568 errout:
2569                         /*
2570                          * Return if we got a read error or in pass mode,
2571                          * or failed with partial write. Otherwise, we'll
2572                          * read through the input stream till next file.
2573                          */
2574                         if (rv < 0 || (Args & OCp) ||
2575                             data_in_info->data_in_wr_part) {
2576                                 free(buf);
2577                                 return (rv);
2578                         }
2579                         error = 1;
2580                         hl = hl->hl_next;
2581                         break;
2582                 }
2583                 curpos += datasize;
2584         }
2585 
2586         /*
2587          * We should read through the input data to go to the next
2588          * header when non-fatal error occured.
2589          */
2590         if (error && !(Args & OCp)) {
2591                 data_in_info->data_in_proc_mode = P_SKIP;
2592                 while (hl != NULL) {
2593                         datasize = hl->hl_hole - hl->hl_data;
2594                         rv = rdwr_bytes(ifd, ofd, buf, datasize, maxwrite,
2595                             blocksize, data_in_info);
2596                         if (rv != 0)
2597                                 break;
2598                         hl = hl->hl_next;
2599                 }
2600         }
2601 
2602         free(buf);
2603         return (error);
2604 }
2605 
2606 /*
2607  * Strip off the sparse file information that is prepended to
2608  * the compressed sparse file. The information is in the following
2609  * format:
2610  *      <prepended info size><SP><orig file size><SP><holes info>
2611  * where prepended info size is long right justified in 10 bytes.
2612  * Holesdata consists of the series of offset pairs:
2613  *      <data offset><SP><hole offset><SP><data offset><SP><hole offset>...
2614  * prepended info size and original file size have been read in gethdr().
2615  * We read the rest of holes information here in this function.
2616  */
2617 static int
2618 read_holesdata(holes_info_t *holes, off_t *fileszp,
2619     char *nam_p, data_in_t *data_in_info)
2620 {
2621         char            *holesdata;
2622         size_t          holesdata_sz;
2623 
2624         /* We've already read the header. */
2625         holesdata_sz = holes->holesdata_sz - MIN_HOLES_HDRSIZE;
2626 
2627         if ((holesdata = e_zalloc(E_NORMAL, holesdata_sz)) == NULL) {
2628                 msg(ERRN, "Could not allocate memory for "
2629                     "sparse file information", nam_p);
2630                 return (1);
2631         }
2632         /*
2633          * This function is called only in OCi mode. Therefore,
2634          * read_bytes() won't fail, and won't return if error occurs in
2635          * input stream. See rstbuf().
2636          */
2637         (void) read_bytes(-1, holesdata, holesdata_sz, CPIOBSZ, data_in_info);
2638         *fileszp -= holesdata_sz;
2639 
2640         /* The string should be terminated. */
2641         if (holesdata[holesdata_sz - 1] != '\0') {
2642 invalid:
2643                 free(holesdata);
2644                 msg(ERR, "invalid sparse file information", nam_p);
2645                 return (1);
2646         }
2647         if (parse_holesdata(holes, holesdata) != 0)
2648                 goto invalid;
2649 
2650         /* sanity check */
2651         if (*fileszp != holes->data_size)
2652                 goto invalid;
2653 
2654         free(holesdata);
2655         return (0);
2656 }
2657 
2658 /*
2659  * data_in:  If proc_mode == P_PROC, bread() the file's data from the archive
2660  * and write(2) it to the open fdes gotten from openout().  If proc_mode ==
2661  * P_SKIP, or becomes P_SKIP (due to errors etc), bread(2) the file's data
2662  * and ignore it.  If the user specified any of the "swap" options (b, s or S),
2663  * and the length of the file is not appropriate for that action, do not
2664  * perform the "swap", otherwise perform the action on a buffer by buffer basis.
2665  * If the CRC header was selected, calculate a running checksum as each buffer
2666  * is processed.
2667  */
2668 static void
2669 data_in(int proc_mode)
2670 {
2671         char *nam_p;
2672         int pad, rv;
2673         int error = 0;
2674         int swapfile = 0;
2675         int cstatus = 0;
2676         off_t   filesz;
2677         data_in_t *data_in_info;
2678 
2679         if (G_p->g_attrnam_p != NULL) {
2680                 nam_p = G_p->g_attrnam_p;
2681         } else {
2682                 nam_p = G_p->g_nam_p;
2683         }
2684 
2685         if (((G_p->g_mode & Ftype) == S_IFLNK && proc_mode != P_SKIP) ||
2686             (Hdr_type == BAR && bar_linkflag == '2' && proc_mode != P_SKIP)) {
2687                 proc_mode = P_SKIP;
2688                 VERBOSE((Args & (OCv | OCV)), nam_p);
2689         }
2690         if (Args & (OCb | OCs | OCS)) { /* verfify that swapping is possible */
2691                 swapfile = 1;
2692                 if (Args & (OCs | OCb) && G_p->g_filesz % 2) {
2693                         msg(ERR,
2694                             "Cannot swap bytes of \"%s\", odd number of bytes",
2695                             nam_p);
2696                         swapfile = 0;
2697                 }
2698                 if (Args & (OCS | OCb) && G_p->g_filesz % 4) {
2699                         msg(ERR,
2700                             "Cannot swap halfwords of \"%s\", odd number "
2701                             "of halfwords", nam_p);
2702                         swapfile = 0;
2703                 }
2704         }
2705 
2706         data_in_info = e_zalloc(E_EXIT, sizeof (data_in_t));
2707         data_in_info->data_in_swapfile = swapfile;
2708         data_in_info->data_in_proc_mode = proc_mode;
2709 
2710         filesz = G_p->g_filesz;
2711 
2712         if (S_ISSPARSE(G_p->g_mode) && G_p->g_holes != NULL) {
2713                 /* We've already read the header in gethdr() */
2714                 filesz -= MIN_HOLES_HDRSIZE;
2715 
2716                 /*
2717                  * Strip rest of the sparse file information. This includes
2718                  * the data/hole offset pairs which will be used to restore
2719                  * the holes in the file.
2720                  */
2721                 if (proc_mode == P_SKIP) {
2722                         /* holes info isn't necessary to skip file */
2723                         free_holes_info(G_p->g_holes);
2724                         G_p->g_holes = NULL;
2725                 } else {
2726                         rv = read_holesdata(G_p->g_holes, &filesz,
2727                             nam_p, data_in_info);
2728                         if (rv != 0) {
2729                                 /*
2730                                  * We got an error. Skip this file. holes info
2731                                  * is no longer necessary.
2732                                  */
2733                                 free_holes_info(G_p->g_holes);
2734                                 G_p->g_holes = NULL;
2735 
2736                                 data_in_info->data_in_proc_mode = P_SKIP;
2737                                 error = 1;
2738                         }
2739                 }
2740         }
2741 
2742         if (G_p->g_holes != NULL) {
2743                 rv = data_copy_with_holes(-1, Ofile,
2744                     (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
2745                     G_p->g_holes->orig_size,
2746                     CPIOBSZ, data_in_info, G_p->g_holes);
2747 
2748                 free_holes_info(G_p->g_holes);
2749                 G_p->g_holes = NULL;
2750         } else {
2751                 rv = data_copy(-1, Ofile,
2752                     (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
2753                     filesz, CPIOBSZ, data_in_info);
2754         }
2755 
2756         /* This writes out the file from the archive */
2757         if (rv != 0 || error) {
2758                 errno = data_in_info->data_in_errno;
2759 
2760                 if (!error) {
2761                         msg(data_in_info->data_in_wr_part ? EXTN : ERRN,
2762                             "Cannot write \"%s%s%s\"",
2763                             (G_p->g_attrnam_p == NULL) ? "" :
2764                             G_p->g_attrfnam_p,
2765                             (G_p->g_attrnam_p == NULL) ? "" :
2766                             G_p->g_rw_sysattr ?
2767                             gettext(" System Attribute ") :
2768                             gettext(" Attribute "), nam_p);
2769                 }
2770                 /*
2771                  * We've failed to write to the file, and input data
2772                  * has been skiped to the next file. We'll need to restore
2773                  * the original file, and skip the rest of work.
2774                  */
2775                 proc_mode = P_SKIP;
2776                 rstfiles(U_KEEP, G_p->g_dirfd);
2777                 cstatus = close(Ofile);
2778                 Ofile = 0;
2779                 if (cstatus != 0) {
2780                         msg(EXTN, "close error");
2781                 }
2782         }
2783 
2784         /* we must use g_filesz for the amount of padding */
2785         pad = (Pad_val + 1 - (G_p->g_filesz & Pad_val)) & Pad_val;
2786         if (pad != 0) {
2787                 FILL(pad);
2788                 Buffr.b_out_p += pad;
2789                 Buffr.b_cnt -= pad;
2790         }
2791         if (proc_mode != P_SKIP) {
2792                 if (Hdr_type == CRC &&
2793                     Gen.g_cksum != data_in_info->data_in_cksumval) {
2794                         msg(ERR, "\"%s\" - checksum error", nam_p);
2795                         rstfiles(U_KEEP, G_p->g_dirfd);
2796                 } else
2797                         rstfiles(U_OVER, G_p->g_dirfd);
2798                 if (Hdr_type == BAR && data_in_info->data_in_compress_flag) {
2799                         (void) pclose(data_in_info->data_in_pipef);
2800                 } else {
2801                         cstatus = close(Ofile);
2802                 }
2803                 Ofile = 0;
2804                 if (cstatus != 0) {
2805                         msg(EXTN, "close error");
2806                 }
2807         }
2808         (void) free(data_in_info);
2809 
2810         VERBOSE((proc_mode != P_SKIP && (Args & (OCv | OCV))),
2811             (G_p->g_attrparent_p == NULL) ? G_p->g_nam_p : G_p->g_attrpath_p);
2812         Finished = 1;
2813 }
2814 
2815 /*
2816  * Read regular file. Return number of bytes which weren't read.
2817  * Upon return, real_filesz will be real file size of input file.
2818  * When read_exact is specified, read size is adjusted to the given
2819  * file size.
2820  */
2821 static off_t
2822 read_file(char *nam_p, off_t file_size, off_t *real_filesz,
2823         boolean_t read_exact)
2824 {
2825         int     amount_read;
2826         off_t   amt_to_read;
2827         off_t   readsz;
2828 
2829         if (file_size == 0)
2830                 return (0);
2831 
2832         amt_to_read = file_size;
2833         do {
2834                 if (read_exact && amt_to_read < CPIOBSZ)
2835                         readsz = amt_to_read;
2836                 else
2837                         readsz = CPIOBSZ;
2838 
2839                 FLUSH(readsz);
2840                 errno = 0;
2841 
2842                 if ((amount_read = read(Ifile, Buffr.b_in_p, readsz)) < 0) {
2843                         msg(EXTN, "Cannot read \"%s%s%s\"",
2844                             (Gen.g_attrnam_p == NULL) ?
2845                             nam_p : Gen.g_attrfnam_p,
2846                             (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
2847                             gettext(" System Attribute ") :
2848                             gettext(" Attribute "),
2849                             (Gen.g_attrnam_p == NULL) ? "" : nam_p);
2850                         break;
2851                 }
2852 
2853                 if (amount_read == 0) {
2854                         /* got EOF. the file has shrunk */
2855                         *real_filesz = file_size - amt_to_read;
2856                         break;
2857                 } else if (amount_read > amt_to_read) {
2858                         /* the file has grown */
2859                         *real_filesz = file_size +
2860                             (amount_read - amt_to_read);
2861                         amount_read = amt_to_read;
2862                 } else if (amount_read == amt_to_read) {
2863                         /* the file is the same size */
2864                         *real_filesz = file_size;
2865                 }
2866 
2867                 Buffr.b_in_p += amount_read;
2868                 Buffr.b_cnt += (long)amount_read;
2869 
2870                 amt_to_read -= (off_t)amount_read;
2871                 if (!read_exact &&
2872                     amt_to_read == 0 && amount_read == CPIOBSZ) {
2873                         /*
2874                          * If the file size is multiple of CPIOBSZ, we may
2875                          * be able to read more from the file even though
2876                          * amt_to_read already gets 0.
2877                          */
2878                         FLUSH(CPIOBSZ);
2879                         amount_read = read(Ifile, Buffr.b_in_p, CPIOBSZ);
2880                         if (amount_read != 0) {
2881                                 /* the file has grown */
2882                                 *real_filesz = file_size + amount_read;
2883                         }
2884                 }
2885         } while (amt_to_read != 0);
2886 
2887         return (amt_to_read);
2888 }
2889 
2890 /*
2891  * Read through the data in files skipping holes.
2892  */
2893 static off_t
2894 read_compress_holes(char *nam_p, off_t file_size, off_t *real_filesz,
2895     holes_info_t *holes, int *hole_changed)
2896 {
2897         off_t           left;
2898         off_t           datasize, realsz;
2899         off_t           curpos, npos;
2900         holes_list_t    *hl = holes->holes_list;
2901 
2902         curpos = 0;
2903         for (hl = holes->holes_list; hl != NULL; hl = hl->hl_next) {
2904                 datasize = hl->hl_hole - hl->hl_data;
2905 
2906                 npos = lseek(Ifile, curpos, SEEK_DATA);
2907                 if (npos == -1 && errno == ENXIO) {
2908                         /*
2909                          * No more data. There are two cases.
2910                          * - we have a hole toward the end of file.
2911                          * - file has been shrunk, and we've reached EOF.
2912                          */
2913                         *real_filesz = lseek(Ifile, 0, SEEK_END);
2914                         if (hl->hl_data == file_size)
2915                                 return (0);
2916                         /*
2917                          * File has been shrunk. Check the amount of data
2918                          * left.
2919                          */
2920                         left = 0;
2921                         while (hl != NULL) {
2922                                 left += (hl->hl_hole - hl->hl_data);
2923                                 hl = hl->hl_next;
2924                         }
2925                         return (left);
2926                 }
2927 
2928                 /* found data */
2929                 curpos = npos;
2930                 if (curpos != hl->hl_data) {
2931                         /*
2932                          * File has been changed. We shouldn't read data
2933                          * from different offset since we've already put
2934                          * the holes data.
2935                          */
2936                         *hole_changed = 1;
2937                         (void) lseek(Ifile, hl->hl_data, SEEK_SET);
2938                         curpos = hl->hl_data;
2939                 }
2940                 left = read_file(nam_p, datasize, &realsz, B_TRUE);
2941                 if (left != 0) {
2942                         /* file has been shrunk */
2943                         *real_filesz = curpos + datasize - left;
2944                         left = file_size - *real_filesz;
2945                         return (left);
2946                 }
2947                 curpos += datasize;
2948         }
2949         /*
2950          * We've read exact size of holes. We need to make sure
2951          * that file hasn't grown by reading from the EOF.
2952          */
2953         realsz = 0;
2954         (void) read_file(nam_p, CPIOBSZ, &realsz, B_FALSE);
2955 
2956         *real_filesz = curpos + realsz;
2957         return (0);
2958 }
2959 
2960 /*
2961  * data_out:  open(2) the file to be archived, compute the checksum
2962  * of it's data if the CRC header was specified and write the header.
2963  * read(2) each block of data and bwrite() it to the archive.  For TARTYP (TAR
2964  * and USTAR) archives, pad the data with NULLs to the next 512 byte boundary.
2965  */
2966 static void
2967 data_out(void)
2968 {
2969         char            *nam_p;
2970         int             cnt, pad;
2971         off_t           amt_to_read;
2972         off_t           real_filesz;
2973         int             errret = 0;
2974         int             hole_changed = 0;
2975         off_t           orig_filesz;
2976         holes_info_t    *holes = NULL;
2977 
2978         nam_p = G_p->g_nam_p;
2979         if (Aspec) {
2980                 if (Pflag && aclp != NULL) {
2981                         char    *secinfo = NULL;
2982                         int     len = 0;
2983 
2984                         /* append security attributes */
2985                         if (append_secattr(&secinfo, &len, aclp) == -1) {
2986                                 msg(ERR,
2987                                     "can create security information");
2988                         }
2989                         /* call append_secattr() if more than one */
2990 
2991                         if (len > 0) {
2992                         /* write ancillary only if there is sec info */
2993                                 write_hdr(ARCHIVE_ACL, (off_t)len);
2994                                 write_ancillary(secinfo, len, B_TRUE);
2995                         }
2996                 }
2997                 write_hdr(ARCHIVE_NORMAL, (off_t)0);
2998                 rstfiles(U_KEEP, G_p->g_dirfd);
2999                 VERBOSE((Args & (OCv | OCV)), nam_p);
3000                 return;
3001         }
3002         if ((G_p->g_mode & Ftype) == S_IFLNK && (Hdr_type !=
3003             USTAR && Hdr_type != TAR)) { /* symbolic link */
3004                 int size;
3005                 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3006 
3007                 FLUSH(G_p->g_filesz);
3008                 errno = 0;
3009 
3010                 /* Note that "size" and G_p->g_filesz are the same number */
3011 
3012                 if ((size = readlink(nam_p, Buffr.b_in_p, G_p->g_filesz)) <
3013                     0) {
3014                         msg(ERRN, "Cannot read symbolic link \"%s\"", nam_p);
3015                         return;
3016                 }
3017 
3018                 /*
3019                  * Note that it is OK not to add the NUL after the name read by
3020                  * readlink, because it is not being used subsequently.
3021                  */
3022 
3023                 Buffr.b_in_p += size;
3024                 Buffr.b_cnt += size;
3025                 pad = (Pad_val + 1 - (size & Pad_val)) & Pad_val;
3026                 if (pad != 0) {
3027                         FLUSH(pad);
3028                         (void) memset(Buffr.b_in_p, 0, pad);
3029                         Buffr.b_in_p += pad;
3030                         Buffr.b_cnt += pad;
3031                 }
3032                 VERBOSE((Args & (OCv | OCV)), nam_p);
3033                 return;
3034         } else if ((G_p->g_mode & Ftype) == S_IFLNK &&
3035             (Hdr_type == USTAR || Hdr_type == TAR)) {
3036                 int size;
3037 
3038                 /*
3039                  * G_p->g_filesz is the length of the right-hand side of
3040                  * the symlink "x -> y".
3041                  * The tar link field is only NAMSIZ long.
3042                  */
3043 
3044                 if (G_p->g_filesz > NAMSIZ) {
3045                         msg(ERRN,
3046                             "Symbolic link too long \"%s\"", nam_p);
3047                         return;
3048                 }
3049                 if ((size = readlink(nam_p, T_lname, G_p->g_filesz)) < 0) {
3050                         msg(ERRN,
3051                             "Cannot read symbolic link \"%s\"", nam_p);
3052                         return;
3053                 }
3054                 T_lname[size] = '\0';
3055                 G_p->g_filesz = (off_t)0;
3056                 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3057                 VERBOSE((Args & (OCv | OCV)), nam_p);
3058                 return;
3059         }
3060         if ((Ifile = openfile(O_RDONLY)) < 0) {
3061                 msg(ERR, "\"%s%s%s\" ?",
3062                     (Gen.g_attrnam_p == NULL) ? nam_p : Gen.g_attrfnam_p,
3063                     (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3064                     gettext(" System Attribute ") : gettext(" Attribute "),
3065                     (Gen.g_attrnam_p == NULL) ? "" :
3066                     (Gen.g_attrparent_p == NULL) ? Gen.g_attrnam_p :
3067                     Gen.g_attrparent_p);
3068                 return;
3069         }
3070 
3071         /* save original file size */
3072         orig_filesz = G_p->g_filesz;
3073 
3074         /*
3075          * Calculate the new compressed file size of a sparse file
3076          * before any of the header information is written
3077          * to the archive.
3078          */
3079         if (Compress_sparse && S_ISREG(G_p->g_mode)) {
3080                 /*
3081                  * If the file being processed is a sparse file, gather the
3082                  * hole information and the compressed file size.
3083                  * G_p->g_filesz will need to be changed to be the size of
3084                  * the compressed sparse file plus the the size of the hole
3085                  * information that will be prepended to the compressed file
3086                  * in the archive.
3087                  */
3088                 holes = get_holes_info(Ifile, G_p->g_filesz, B_FALSE);
3089                 if (holes != NULL)
3090                         G_p->g_filesz = holes->holesdata_sz + holes->data_size;
3091 
3092                 if (G_p->g_filesz > Max_offset) {
3093                         msg(ERR, "%s%s%s: too large to archive "
3094                             "in current mode",
3095                             G_p->g_nam_p,
3096                             (G_p->g_attrnam_p == NULL) ? "" :
3097                             G_p->g_rw_sysattr ?
3098                             gettext(" System Attribute ") :
3099                             gettext(" Attribute "),
3100                             (G_p->g_attrnam_p == NULL) ? "" :
3101                             ((G_p->g_attrparent_p == NULL) ?
3102                             G_p->g_attrnam_p:
3103                             G_p->g_attrpath_p));
3104 
3105                         (void) close(Ifile);
3106                         if (holes != NULL)
3107                                 free_holes_info(holes);
3108                         return; /* do not archive if it's too big */
3109                 }
3110         }
3111 
3112         /*
3113          * Dump extended attribute header.
3114          */
3115 
3116         if (Gen.g_attrnam_p != NULL) {
3117                 write_xattr_hdr();
3118         }
3119 
3120         if (Hdr_type == CRC) {
3121                 long csum = cksum(CRC, 0, &errret);
3122                 if (errret != 0) {
3123                         G_p->g_cksum = (ulong_t)-1;
3124                         msg(POST, "\"%s%s%s\" skipped",
3125                             (Gen.g_attrnam_p == NULL) ?
3126                             nam_p : Gen.g_attrfnam_p,
3127                             (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3128                             gettext(" System Attribute ") :
3129                             gettext(" Attribute "),
3130                             (Gen.g_attrnam_p == NULL) ? "" : nam_p);
3131                         if (holes != NULL)
3132                                 free_holes_info(holes);
3133                         (void) close(Ifile);
3134                         return;
3135                 }
3136                 G_p->g_cksum = csum;
3137         } else {
3138                 G_p->g_cksum = 0;
3139         }
3140 
3141         /*
3142          * ACL has been retrieved in getname().
3143          */
3144         if (Pflag) {
3145                 char    *secinfo = NULL;
3146                 int     len = 0;
3147 
3148                 /* append security attributes */
3149                 if ((append_secattr(&secinfo, &len, aclp)) == -1)
3150                         msg(ERR, "can create security information");
3151 
3152                 /* call append_secattr() if more than one */
3153 
3154                 if (len > 0) {
3155                 /* write ancillary only if there is sec info */
3156                         write_hdr(ARCHIVE_ACL, (off_t)len);
3157                         write_ancillary(secinfo, len, B_TRUE);
3158                 }
3159         }
3160 
3161         if (holes != NULL) {
3162                 /*
3163                  * Write the header info with a modified c_mode field to
3164                  * indicate a compressed sparse file is being archived,
3165                  * as well as the new file size, including the size of the
3166                  * compressed file as well as all the prepended data.
3167                  */
3168                 write_hdr(ARCHIVE_SPARSE, (off_t)0);
3169                 /* Prepend sparse file info */
3170                 write_ancillary(holes->holesdata,
3171                     holes->holesdata_sz, B_FALSE);
3172         } else {
3173                 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3174         }
3175 
3176         real_filesz = 0;
3177 
3178         if (holes != NULL) {
3179                 amt_to_read = read_compress_holes(nam_p, G_p->g_filesz,
3180                     &real_filesz, holes, &hole_changed);
3181         } else {
3182                 amt_to_read = read_file(nam_p, G_p->g_filesz,
3183                     &real_filesz, B_FALSE);
3184         }
3185 
3186         while (amt_to_read > 0) {
3187                 cnt = (amt_to_read > CPIOBSZ) ? CPIOBSZ : (int)amt_to_read;
3188                 FLUSH(cnt);
3189                 (void) memset(Buffr.b_in_p, 0, cnt);
3190                 Buffr.b_in_p += cnt;
3191                 Buffr.b_cnt += cnt;
3192                 amt_to_read -= cnt;
3193         }
3194 
3195         pad = (Pad_val + 1 - (G_p->g_filesz & Pad_val)) & Pad_val;
3196         if (pad != 0) {
3197                 FLUSH(pad);
3198                 (void) memset(Buffr.b_in_p, 0, pad);
3199                 Buffr.b_in_p += pad;
3200                 Buffr.b_cnt += pad;
3201         }
3202 
3203         if (hole_changed == 1) {
3204                 msg(ERR,
3205                     "File data and hole offsets of \"%s%s%s\" have changed",
3206                     (Gen.g_attrnam_p == NULL) ?
3207                     G_p->g_nam_p : Gen.g_attrfnam_p,
3208                     (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3209                     gettext(" System Attribute ") : gettext(" Attribute "),
3210                     (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p);
3211         }
3212         if (real_filesz > orig_filesz) {
3213                 msg(ERR, "File size of \"%s%s%s\" has increased by %lld",
3214                     (Gen.g_attrnam_p == NULL) ?
3215                     G_p->g_nam_p : Gen.g_attrfnam_p,
3216                     (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3217                     gettext(" System Attribute ") : gettext(" Attribute "),
3218                     (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p,
3219                     (real_filesz - orig_filesz));
3220         }
3221         if (real_filesz < orig_filesz) {
3222                 msg(ERR, "File size of \"%s%s%s\" has decreased by %lld",
3223                     (Gen.g_attrnam_p == NULL) ?
3224                     G_p->g_nam_p : Gen.g_attrfnam_p,
3225                     (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3226                     gettext(" System Attribute ") : gettext(" Attribute "),
3227                     (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p,
3228                     (orig_filesz - real_filesz));
3229         }
3230 
3231         if (holes != NULL)
3232                 free_holes_info(holes);
3233 
3234         (void) close(Ifile);
3235         rstfiles(U_KEEP, G_p->g_dirfd);
3236         VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3237 }
3238 
3239 /*
3240  * data_pass:  If not a special file (Aspec), open(2) the file to be
3241  * transferred, read(2) each block of data and write(2) it to the output file
3242  * Ofile, which was opened in file_pass().
3243  */
3244 static void
3245 data_pass(void)
3246 {
3247         int rv;
3248         int cstatus;
3249         char *namep = Nam_p;
3250         holes_info_t *holes = NULL;
3251         data_in_t *data_in_info;
3252 
3253         if (G_p->g_attrnam_p != NULL) {
3254                 namep = G_p->g_attrnam_p;
3255         }
3256         if (Aspec) {
3257                 rstfiles(U_KEEP, G_p->g_passdirfd);
3258                 cstatus = close(Ofile);
3259                 Ofile = 0;
3260                 VERBOSE((Args & (OCv | OCV)), Nam_p);
3261                 if (cstatus != 0) {
3262                         msg(EXTN, "close error");
3263                 }
3264                 return;
3265         }
3266         if ((Ifile = openat(G_p->g_dirfd, get_component(namep), 0)) < 0) {
3267                 msg(ERRN, "Cannot open \"%s%s%s\", skipped",
3268                     (G_p->g_attrnam_p == NULL) ? Nam_p : G_p->g_attrfnam_p,
3269                     (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
3270                     gettext(" System Attribute ") : gettext(" Attribute "),
3271                     (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3272                 rstfiles(U_KEEP, G_p->g_passdirfd);
3273                 cstatus = close(Ofile);
3274                 Ofile = 0;
3275                 if (cstatus != 0) {
3276                         msg(EXTN, "close error");
3277                 }
3278                 return;
3279         }
3280 
3281         data_in_info = e_zalloc(E_EXIT, sizeof (data_in_t));
3282         data_in_info->data_in_proc_mode = P_PROC;
3283 
3284         if (S_ISREG(G_p->g_mode))
3285                 holes = get_holes_info(Ifile, G_p->g_filesz, B_TRUE);
3286 
3287         if (holes != NULL) {
3288                 rv = data_copy_with_holes(Ifile, Ofile,
3289                     (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
3290                     G_p->g_filesz, Bufsize, data_in_info, holes);
3291 
3292                 free_holes_info(holes);
3293         } else {
3294                 rv = data_copy(Ifile, Ofile,
3295                     (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
3296                     G_p->g_filesz, Bufsize, data_in_info);
3297         }
3298 
3299         if (rv < 0) {
3300                 /* read error or unexpected EOF */
3301                 if (data_in_info->data_in_rd_eof) {
3302                         /*
3303                          * read has reached EOF unexpectedly, but this isn't
3304                          * an error since it's the latest shape of the file.
3305                          */
3306                         msg(EPOST, "File size of \"%s%s%s\" has decreased",
3307                             (G_p->g_attrnam_p == NULL) ?
3308                             Nam_p : G_p->g_attrfnam_p,
3309                             (G_p->g_attrnam_p == NULL) ? "" :
3310                             G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3311                             gettext(" Attribute "),
3312                             (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3313 
3314                         /* It's not error. We'll use the new file */
3315                         rv = 0;
3316                 } else {
3317                         /* read error */
3318                         msg(ERRN, "Cannot read \"%s%s%s\"",
3319                             (G_p->g_attrnam_p == NULL) ?
3320                             Nam_p : G_p->g_attrfnam_p,
3321                             (G_p->g_attrnam_p == NULL) ? "" :
3322                             G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3323                             gettext(" Attribute "),
3324                             (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3325                 }
3326         } else if (rv > 0) {
3327                 /* write error */
3328                 if (Do_rename) {
3329                         msg(ERRN, "Cannot write \"%s%s%s\"", Over_p,
3330                             (G_p->g_attrnam_p == NULL) ? "" :
3331                             G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3332                             gettext(" Attribute "),
3333                             (G_p->g_attrnam_p == NULL) ? "" : Over_p);
3334                 } else {
3335                         msg(ERRN, "Cannot write \"%s%s%s\"",
3336                             Fullnam_p,
3337                             (G_p->g_attrnam_p == NULL) ? "" :
3338                             G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3339                             gettext(" Attribute "),
3340                             (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3341                 }
3342         }
3343 
3344         free(data_in_info);
3345 
3346         if (rv == 0) {
3347                 rstfiles(U_OVER, G_p->g_passdirfd);
3348         } else {
3349                 rstfiles(U_KEEP, G_p->g_passdirfd);
3350         }
3351 
3352         (void) close(Ifile);
3353         cstatus = close(Ofile);
3354         Ofile = 0;
3355         if (cstatus != 0) {
3356                 msg(EXTN, "close error");
3357         }
3358         VERBOSE((Args & (OCv | OCV)), Fullnam_p);
3359         Finished = 1;
3360 }
3361 
3362 /*
3363  * file_in:  Process an object from the archive.  If a TARTYP (TAR or USTAR)
3364  * archive and g_nlink == 1, link this file to the file name in t_linkname
3365  * and return.  Handle linked files in one of two ways.  If Onecopy == 0, this
3366  * is an old style (binary or -c) archive, create and extract the data for the
3367  * first link found, link all subsequent links to this file and skip their data.
3368  * If Oncecopy == 1, save links until all have been processed, and then
3369  * process the links first to last checking their names against the patterns
3370  * and/or asking the user to rename them.  The first link that is accepted
3371  * for xtraction is created and the data is read from the archive.
3372  * All subsequent links that are accepted are linked to this file.
3373  */
3374 static void
3375 file_in(void)
3376 {
3377         struct Lnk *l_p, *tl_p;
3378         int lnkem = 0, cleanup = 0;
3379         int proc_file;
3380         struct Lnk *ttl_p;
3381         int typeflag;
3382         char savacl;
3383         int cwd;
3384 
3385         G_p = &Gen;
3386 
3387         /*
3388          * Now that we've read the extended header,
3389          * determine if we should restore attributes.
3390          * Don't restore the attribute if we are extracting
3391          * a file from an archive (as opposed to doing a table of
3392          * contents) and any of the following are true:
3393          * 1. neither -@ or -/ was specified.
3394          * 2. -@ was specified, -/ wasn't specified, and we're
3395          * processing a hidden attribute directory of an attribute
3396          * or we're processing a read-write system attribute file.
3397          * 3.  -@ wasn't specified, -/ was specified, and the file
3398          * we're processing it not a read-write system attribute file,
3399          * or we're processing the hidden attribute directory of an
3400          * attribute.
3401          *
3402          * We always process the attributes if we're just generating
3403          * generating a table of contents, or if both -@ and -/ were
3404          * specified.
3405          */
3406         if (G_p->g_attrnam_p != NULL) {
3407                 if (((Args & OCt) == 0) &&
3408                     ((!Atflag && !SysAtflag) ||
3409                     (Atflag && !SysAtflag && ((G_p->g_attrparent_p != NULL) ||
3410                     G_p->g_rw_sysattr)) ||
3411                     (!Atflag && SysAtflag && ((G_p->g_attrparent_p != NULL) ||
3412                     !G_p->g_rw_sysattr)))) {
3413                         proc_file = F_SKIP;
3414                         data_in(P_SKIP);
3415                         return;
3416                 }
3417         }
3418 
3419         /*
3420          * Open target directory if this isn't a skipped file
3421          * and g_nlink == 1
3422          *
3423          * Links are handled further down in this function.
3424          */
3425 
3426         proc_file = ckname(0);
3427 
3428         if (proc_file == F_SKIP && G_p->g_nlink == 1) {
3429                 /*
3430                  * Normally ckname() prints out the file as a side
3431                  * effect except for table of contents listing
3432                  * when its parameter is zero and Onecopy isn't
3433                  * Zero.  Due to this we need to force the name
3434                  * to be printed here.
3435                  */
3436                 if (Onecopy == 1) {
3437                         VERBOSE((Args & OCt), G_p->g_nam_p);
3438                 }
3439                 data_in(P_SKIP);
3440                 return;
3441         }
3442 
3443         if (proc_file != F_SKIP && open_dirfd() != 0) {
3444                 data_in(P_SKIP);
3445                 return;
3446         }
3447 
3448         if (Hdr_type == BAR) {
3449                 bar_file_in();
3450                 close_dirfd();
3451                 return;
3452         }
3453 
3454         /*
3455          * For archives in USTAR format, the files are extracted according
3456          * to the typeflag.
3457          */
3458         if (Hdr_type == USTAR || Hdr_type == TAR) {
3459                 typeflag = Thdr_p->tbuf.t_typeflag;
3460                 if (G_p->g_nlink == 1) {             /* hard link */
3461                         if (proc_file != F_SKIP) {
3462                                 int i;
3463                                 char lname[NAMSIZ+1];
3464                                 (void) memset(lname, '\0', sizeof (lname));
3465 
3466                                 (void) strncpy(lname, Thdr_p->tbuf.t_linkname,
3467                                     NAMSIZ);
3468                                 for (i = 0; i <= NAMSIZ && lname[i] != 0; i++)
3469                                         ;
3470 
3471                                 lname[i] = 0;
3472                                 (void) creat_lnk(G_p->g_dirfd,
3473                                     &lname[0], G_p->g_nam_p);
3474                         }
3475                         close_dirfd();
3476                         return;
3477                 }
3478                 if (typeflag == '3' || typeflag == '4' || typeflag == '5' ||
3479                     typeflag == '6') {
3480                         if (proc_file != F_SKIP &&
3481                             creat_spec(G_p->g_dirfd) > 0) {
3482                                 VERBOSE((Args & (OCv | OCV)),
3483                                     (G_p->g_attrparent_p == NULL) ?
3484                                     G_p->g_nam_p : G_p->g_attrpath_p);
3485                         }
3486                         close_dirfd();
3487                         return;
3488                 } else if (Adir || Aspec) {
3489                         if ((proc_file == F_SKIP) ||
3490                             (Ofile = openout(G_p->g_dirfd)) < 0) {
3491                                 data_in(P_SKIP);
3492                         } else {
3493                                 data_in(P_PROC);
3494                         }
3495                         close_dirfd();
3496                         return;
3497                 }
3498         }
3499 
3500         if (Adir) {
3501                 if (proc_file != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
3502                         VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3503                 }
3504                 close_dirfd();
3505                 if (Onecopy == 1) {
3506                         VERBOSE((Args & OCt), G_p->g_nam_p);
3507                 }
3508                 return;
3509         }
3510         if (G_p->g_nlink == 1 || (Hdr_type == TAR ||
3511             Hdr_type == USTAR)) {
3512                 if (Aspec) {
3513                         if (proc_file != F_SKIP && creat_spec(G_p->g_dirfd) > 0)
3514                                 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3515                 } else {
3516                         if ((proc_file == F_SKIP) ||
3517                             (Ofile = openout(G_p->g_dirfd)) < 0) {
3518                                 data_in(P_SKIP);
3519                         } else {
3520                                 data_in(P_PROC);
3521                         }
3522                 }
3523                 close_dirfd();
3524                 return;
3525         }
3526         close_dirfd();
3527 
3528         tl_p = add_lnk(&ttl_p);
3529         l_p = ttl_p;
3530         if (l_p->L_cnt == l_p->L_gen.g_nlink)
3531                 cleanup = 1;
3532         if (!Onecopy || G_p->g_attrnam_p != NULL) {
3533                 lnkem = (tl_p != l_p) ? 1 : 0;
3534                 G_p = &tl_p->L_gen;
3535                 if (proc_file == F_SKIP) {
3536                         data_in(P_SKIP);
3537                 } else {
3538                         if (open_dirfd() != 0)
3539                                 return;
3540                         if (!lnkem) {
3541                                 if (Aspec) {
3542                                         if (creat_spec(G_p->g_dirfd) > 0)
3543                                                 VERBOSE((Args & (OCv | OCV)),
3544                                                     G_p->g_nam_p);
3545                                 } else if ((Ofile =
3546                                     openout(G_p->g_dirfd)) < 0) {
3547                                         data_in(P_SKIP);
3548                                         close_dirfd();
3549                                         reclaim(l_p);
3550                                 } else {
3551                                         data_in(P_PROC);
3552                                         close_dirfd();
3553                                 }
3554                         } else {
3555                                 /*
3556                                  * Are we linking an attribute?
3557                                  */
3558                                 cwd = -1;
3559                                 if (l_p->L_gen.g_attrnam_p != NULL) {
3560                                         (void) strcpy(Lnkend_p,
3561                                             l_p->L_gen.g_attrnam_p);
3562                                         (void) strcpy(Full_p,
3563                                             tl_p->L_gen.g_attrnam_p);
3564                                         cwd = save_cwd();
3565                                         (void) fchdir(G_p->g_dirfd);
3566                                 } else {
3567                                         (void) strcpy(Lnkend_p,
3568                                             l_p->L_gen.g_nam_p);
3569                                         (void) strcpy(Full_p,
3570                                             tl_p->L_gen.g_nam_p);
3571                                 }
3572                                 (void) creat_lnk(G_p->g_dirfd,
3573                                     Lnkend_p, Full_p);
3574                                 data_in(P_SKIP);
3575                                 close_dirfd();
3576                                 l_p->L_lnk_p = NULL;
3577                                 free(tl_p->L_gen.g_nam_p);
3578                                 free(tl_p);
3579                                 if (cwd != -1)
3580                                         rest_cwd(cwd);
3581                         }
3582                 }
3583         } else { /* Onecopy */
3584                 if (tl_p->L_gen.g_filesz)
3585                         cleanup = 1;
3586                 if (!cleanup) {
3587                         close_dirfd();
3588                         return; /* don't do anything yet */
3589                 }
3590                 tl_p = l_p;
3591                 /*
3592                  * ckname will clear aclchar. We need to keep aclchar for
3593                  * all links.
3594                  */
3595                 savacl = aclchar;
3596                 while (tl_p != NULL) {
3597                         G_p = &tl_p->L_gen;
3598                         aclchar = savacl;
3599                         if ((proc_file = ckname(1)) != F_SKIP) {
3600                                 if (open_dirfd() != 0) {
3601                                         return;
3602                                 }
3603                                 if (l_p->L_data) {
3604                                         (void) creat_lnk(G_p->g_dirfd,
3605                                             l_p->L_gen.g_nam_p,
3606                                             G_p->g_nam_p);
3607                                 } else if (Aspec) {
3608                                         (void) creat_spec(G_p->g_dirfd);
3609                                         l_p->L_data = 1;
3610                                         VERBOSE((Args & (OCv | OCV)),
3611                                             G_p->g_nam_p);
3612                                 } else if ((Ofile =
3613                                     openout(G_p->g_dirfd)) < 0) {
3614                                         proc_file = F_SKIP;
3615                                 } else {
3616                                         data_in(P_PROC);
3617                                         l_p->L_data = 1;
3618                                 }
3619                         } /* (proc_file = ckname(1)) != F_SKIP */
3620 
3621                         tl_p = tl_p->L_lnk_p;
3622 
3623                         close_dirfd();
3624 
3625                         if (proc_file == F_SKIP && !cleanup) {
3626                                 tl_p->L_nxt_p = l_p->L_nxt_p;
3627                                 tl_p->L_bck_p = l_p->L_bck_p;
3628                                 l_p->L_bck_p->L_nxt_p = tl_p;
3629                                 l_p->L_nxt_p->L_bck_p = tl_p;
3630                                 free(l_p->L_gen.g_nam_p);
3631                                 free(l_p);
3632                         }
3633                 } /* tl_p->L_lnk_p != NULL */
3634                 if (l_p->L_data == 0) {
3635                         data_in(P_SKIP);
3636                 }
3637         }
3638         if (cleanup) {
3639                 reclaim(l_p);
3640         }
3641 }
3642 
3643 /*
3644  * file_out:  If the current file is not a special file (!Aspec) and it
3645  * is identical to the archive, skip it (do not archive the archive if it
3646  * is a regular file).  If creating a TARTYP (TAR or USTAR) archive, the first
3647  * time a link to a file is encountered, write the header and file out normally.
3648  * Subsequent links to this file put this file name in their t_linkname field.
3649  * Otherwise, links are handled in one of two ways, for the old headers
3650  * (i.e. binary and -c), linked files are written out as they are encountered.
3651  * For the new headers (ASC and CRC), links are saved up until all the links
3652  * to each file are found.  For a file with n links, write n - 1 headers with
3653  * g_filesz set to 0, write the final (nth) header with the correct g_filesz
3654  * value and write the data for the file to the archive.
3655  */
3656 static
3657 int
3658 file_out(void)
3659 {
3660         struct Lnk *l_p, *tl_p;
3661         int cleanup = 0;
3662         struct Lnk *ttl_p;
3663 
3664         G_p = &Gen;
3665         if (!Aspec && IDENT(SrcSt, ArchSt))
3666                 return (1); /* do not archive the archive if it's a reg file */
3667         /*
3668          * If compressing sparse files, wait until the compressed file size
3669          * is known to check if file size is too big.
3670          */
3671         if (Compress_sparse == 0 && G_p->g_filesz > Max_offset) {
3672                 msg(ERR, "%s%s%s: too large to archive in current mode",
3673                     G_p->g_nam_p,
3674                     (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
3675                     gettext(" System Attribute ") : gettext(" Attribute "),
3676                     (G_p->g_attrnam_p == NULL) ? "" :
3677                     ((G_p->g_attrparent_p == NULL) ? G_p->g_attrnam_p:
3678                     G_p->g_attrpath_p));
3679                 return (1); /* do not archive if it's too big */
3680         }
3681         if (Hdr_type == TAR || Hdr_type == USTAR) { /* TAR and USTAR */
3682                 if (Adir) {
3683                         if (Gen.g_attrnam_p != NULL) {
3684                                 write_xattr_hdr();
3685                         }
3686                         write_hdr(ARCHIVE_NORMAL, 0);
3687                         return (0);
3688                 }
3689                 if (G_p->g_nlink == 1) {
3690                         data_out();
3691                         return (0);
3692                 }
3693                 tl_p = add_lnk(&ttl_p);
3694                 l_p = ttl_p;
3695                 if (tl_p == l_p) { /* first link to this file encountered */
3696                         data_out();
3697                         return (0);
3698                 }
3699                 (void) strncpy(T_lname, l_p->L_gen.g_nam_p,
3700                     l_p->L_gen.g_namesz);
3701 
3702                 /*
3703                  * check if linkname is greater than 100 characters
3704                  */
3705                 if (strlen(T_lname) > NAMSIZ) {
3706                         msg(EPOST, "cpio: %s: linkname %s is greater than %d",
3707                             G_p->g_nam_p, T_lname, NAMSIZ);
3708                         return (1);
3709                 }
3710 
3711                 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3712                 VERBOSE((Args & (OCv | OCV)), tl_p->L_gen.g_nam_p);
3713 
3714                 /* find the lnk entry in sublist, unlink it, and free it */
3715                 for (; ttl_p->L_lnk_p != NULL;
3716                     ttl_p = ttl_p->L_lnk_p) {
3717                         if (ttl_p->L_lnk_p == tl_p) {
3718                                 ttl_p->L_lnk_p = tl_p->L_lnk_p;
3719                                 free(tl_p->L_gen.g_nam_p);
3720                                 free(tl_p);
3721                                 break;
3722                         }
3723                 }
3724 
3725                 return (0);
3726         }
3727         if (Adir) {
3728                 /*
3729                  * ACL has been retrieved in getname().
3730                  */
3731                 if (Pflag) {
3732                         char    *secinfo = NULL;
3733                         int     len = 0;
3734 
3735                         /* append security attributes */
3736                         if ((append_secattr(&secinfo, &len, aclp)) == -1)
3737                                 msg(ERR, "can create security information");
3738 
3739                         /* call append_secattr() if more than one */
3740 
3741                         if (len > 0) {
3742                         /* write ancillary */
3743                                 write_hdr(ARCHIVE_ACL, (off_t)len);
3744                                 write_ancillary(secinfo, len, B_TRUE);
3745                         }
3746                 }
3747 
3748                 if (Gen.g_attrnam_p != NULL) {
3749                         write_xattr_hdr();
3750                 }
3751                 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3752                 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3753                 return (0);
3754         }
3755         if (G_p->g_nlink == 1) {
3756                 data_out();
3757                 return (0);
3758         } else {
3759                 tl_p = add_lnk(&ttl_p);
3760                 l_p = ttl_p;
3761 
3762                 if (l_p->L_cnt == l_p->L_gen.g_nlink)
3763                         cleanup = 1;
3764                 else if (Onecopy && G_p->g_attrnam_p == NULL) {
3765                         return (0); /* don't process data yet */
3766                 }
3767         }
3768         if (Onecopy && G_p->g_attrnam_p == NULL) {
3769                 tl_p = l_p;
3770                 while (tl_p->L_lnk_p != NULL) {
3771                         G_p = &tl_p->L_gen;
3772                         G_p->g_filesz = (off_t)0;
3773                         /* one link with the acl is sufficient */
3774                         write_hdr(ARCHIVE_NORMAL, (off_t)0);
3775                         VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3776                         tl_p = tl_p->L_lnk_p;
3777                 }
3778                 G_p = &tl_p->L_gen;
3779                 if (open_dirfd() != 0)
3780                         return (1);
3781         }
3782         /* old style: has acl and data for every link */
3783         data_out();
3784         if (cleanup)
3785                 reclaim(l_p);
3786         return (0);
3787 }
3788 
3789 /*
3790  * Verify the underlying file system supports the attribute type.
3791  * Only archive extended attribute files when '-@' was specified.
3792  * Only archive system extended attribute files if '-/' was specified.
3793  */
3794 #if defined(O_XATTR)
3795 static attr_status_t
3796 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
3797     int *ext_attrflg)
3798 {
3799         /*
3800          * Verify extended attributes are supported/exist.  We only
3801          * need to check if we are processing a base file, not an
3802          * extended attribute.
3803          */
3804         if (attrflg) {
3805                 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
3806                     _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
3807         }
3808         if (Atflag) {
3809 #if defined(_PC_SATTR_ENABLED)
3810                 if (!*ext_attrflg) {
3811                         if (SysAtflag) {
3812                                 /* Verify system attributes are supported */
3813                                 if (sysattr_support(filename,
3814                                     (actflag == ARC_CREATE) ?_PC_SATTR_EXISTS :
3815                                     _PC_SATTR_ENABLED) != 1) {
3816                                         return (ATTR_SATTR_ERR);
3817                                 }
3818                         } else
3819                                 return (ATTR_XATTR_ERR);
3820 #else
3821                                 return (ATTR_XATTR_ERR);
3822 #endif  /* _PC_SATTR_ENABLED */
3823                 }
3824 
3825 #if defined(_PC_SATTR_ENABLED)
3826         } else if (SysAtflag) {
3827                 /* Verify system attributes are supported */
3828                 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
3829                     _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
3830                         return (ATTR_SATTR_ERR);
3831         }
3832 #endif  /* _PC_SATTR_ENABLED */
3833         } else {
3834                 return (ATTR_SKIP);
3835         }
3836 
3837 return (ATTR_OK);
3838 }
3839 #endif
3840 
3841 #if defined(O_XATTR)
3842 /*
3843  * Verify the attribute, attrname, is an attribute we want to restore.
3844  * Never restore read-only system attribute files.  Only restore read-write
3845  * system attributes files when -/ was specified, and only traverse into
3846  * the 2nd level attribute directory containing only system attributes if
3847  * -@ was specified.  This keeps us from archiving
3848  *      <attribute name>/<read-write system attribute file>
3849  * when -/ was specified without -@.
3850  *
3851  * attrname             - attribute file name
3852  * attrparent           - attribute's parent name within the base file's
3853  *                      attribute digrectory hierarchy
3854  * arc_rwsysattr        - flag that indicates that read-write system attribute
3855  *                      file should be archived as it contains other than
3856  *                      the default system attributes.
3857  * rw_sysattr           - on return, flag will indicate if attrname is a
3858  *                      read-write system attribute file.
3859  */
3860 static attr_status_t
3861 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
3862     int *rw_sysattr)
3863 {
3864 #if defined(_PC_SATTR_ENABLED)
3865         int     attr_supported;
3866 
3867         /* Never restore read-only system attribute files */
3868         if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
3869                 *rw_sysattr = 0;
3870                 return (ATTR_SKIP);
3871         } else {
3872                 *rw_sysattr = (attr_supported == _RW_SATTR);
3873         }
3874 
3875         /*
3876          * Don't archive a read-write system attribute file if
3877          * it contains only the default system attributes.
3878          */
3879         if (*rw_sysattr && !arc_rwsysattr) {
3880                 return (ATTR_SKIP);
3881         }
3882 
3883 #else
3884         /* Never restore read-only system attribute files */
3885         if ((*rw_sysattr = is_sysattr(attrname)) == 1) {
3886                 return (ATTR_SKIP);
3887         }
3888 #endif  /* _PC_SATTR_ENABLED */
3889 
3890         /*
3891          * Only restore read-write system attribute files
3892          * when -/ was specified.  Only restore extended
3893          * attributes when -@ was specified.
3894          */
3895         if (Atflag) {
3896                 if (!SysAtflag) {
3897                         /*
3898                          * Only archive/restore the hidden directory "." if
3899                          * we're processing the top level hidden attribute
3900                          * directory.  We don't want to process the
3901                          * hidden attribute directory of the attribute
3902                          * directory that contains only extended system
3903                          * attributes.
3904                          */
3905                         if (*rw_sysattr || (Hiddendir &&
3906                             (attrparent != NULL))) {
3907                                 return (ATTR_SKIP);
3908                         }
3909                 }
3910         } else if (SysAtflag) {
3911                 /*
3912                  * Only archive/restore read-write extended system attribute
3913                  * files of the base file.
3914                  */
3915                 if (!*rw_sysattr || (attrparent != NULL)) {
3916                         return (ATTR_SKIP);
3917                 }
3918         } else {
3919                 return (ATTR_SKIP);
3920         }
3921 
3922         return (ATTR_OK);
3923 }
3924 #endif
3925 
3926 #if defined(O_XATTR)
3927 static int
3928 retry_open_attr(int pdirfd, int cwd, char *fullname, char *pattr, char *name,
3929     int oflag, mode_t mode)
3930 {
3931         int dirfd;
3932         int ofilefd = -1;
3933         struct timeval times[2];
3934         mode_t newmode;
3935         struct stat parentstat;
3936         acl_t *aclp = NULL;
3937         int error;
3938 
3939         /*
3940          * We couldn't get to attrdir. See if its
3941          * just a mode problem on the parent file.
3942          * for example: a mode such as r-xr--r--
3943          * on a ufs file system without extended
3944          * system attribute support won't let us
3945          * create an attribute dir if it doesn't
3946          * already exist, and on a ufs file system
3947          * with extended system attribute support
3948          * won't let us open the attribute for
3949          * write.
3950          *
3951          * If file has a non-trivial ACL, then save it
3952          * off so that we can place it back on after doing
3953          * chmod's.
3954          */
3955         if ((dirfd = openat(cwd, (pattr == NULL) ? fullname : pattr,
3956             O_RDONLY)) == -1) {
3957                 return (-1);
3958         }
3959         if (fstat(dirfd, &parentstat) == -1) {
3960                 msg(ERRN, "Cannot stat %sfile %s",
3961                     (pdirfd == -1) ? "" : gettext("parent of "),
3962                     (pdirfd == -1) ? fullname : name);
3963                 (void) close(dirfd);
3964                 return (-1);
3965         }
3966         if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
3967                 msg(ERRN, "Failed to retrieve ACL on %sfile %s",
3968                     (pdirfd == -1) ? "" : gettext("parent of "),
3969                     (pdirfd == -1) ? fullname : name);
3970                 (void) close(dirfd);
3971                 return (-1);
3972         }
3973 
3974         newmode = S_IWUSR | parentstat.st_mode;
3975         if (fchmod(dirfd, newmode) == -1) {
3976                 msg(ERRN, "Cannot change mode of %sfile %s to %o",
3977                     (pdirfd == -1) ? "" : gettext("parent of "),
3978                     (pdirfd == -1) ? fullname : name, newmode);
3979                 if (aclp)
3980                         acl_free(aclp);
3981                 (void) close(dirfd);
3982                 return (-1);
3983         }
3984 
3985 
3986         if (pdirfd == -1) {
3987                 /*
3988                  * We weren't able to create the attribute directory before.
3989                  * Now try again.
3990                  */
3991                 ofilefd = attropen(fullname, ".", oflag);
3992         } else {
3993                 /*
3994                  * We weren't able to create open the attribute before.
3995                  * Now try again.
3996                  */
3997                 ofilefd = openat(pdirfd, name, oflag, mode);
3998         }
3999 
4000         /*
4001          * Put mode back to original
4002          */
4003         if (fchmod(dirfd, parentstat.st_mode) == -1) {
4004                 msg(ERRN, "Cannot restore permissions of %sfile %s to %o",
4005                     (pdirfd == -1) ? "" : gettext("parent of "),
4006                     (pdirfd == -1) ? fullname : name, newmode);
4007         }
4008 
4009         if (aclp) {
4010                 error = facl_set(dirfd, aclp);
4011                 if (error) {
4012                         msg(ERRN, "failed to set acl entries on %sfile %s\n",
4013                             (pdirfd == -1) ? "" : gettext("parent of "),
4014                             (pdirfd == -1) ? fullname : name);
4015                 }
4016                 acl_free(aclp);
4017         }
4018 
4019         /*
4020          * Put back time stamps
4021          */
4022 
4023         times[0].tv_sec = parentstat.st_atime;
4024         times[0].tv_usec = 0;
4025         times[1].tv_sec = parentstat.st_mtime;
4026         times[1].tv_usec = 0;
4027 
4028         (void) futimesat(cwd, (pattr == NULL) ? fullname : pattr, times);
4029 
4030         (void) close(dirfd);
4031 
4032         return (ofilefd);
4033 }
4034 #endif
4035 
4036 #if defined(O_XATTR)
4037 /*
4038  * Recursively open attribute directories until the attribute directory
4039  * containing the specified attribute, attrname, is opened.
4040  *
4041  * Currently, only 2 directory levels of attributes are supported, (i.e.,
4042  * extended system attributes on extended attributes).  The following are
4043  * the possible input combinations:
4044  *      1.  Open the attribute directory of the base file (don't change
4045  *          into it).
4046  *              attr_parent = NULL
4047  *              attrname = '.'
4048  *      2.  Open the attribute directory of the base file and change into it.
4049  *              attr_parent = NULL
4050  *              attrname = <attr> | <sys_attr>
4051  *      3.  Open the attribute directory of the base file, change into it,
4052  *          then recursively call open_attr_dir() to open the attribute's
4053  *          parent directory (don't change into it).
4054  *              attr_parent = <attr>
4055  *              attrname = '.'
4056  *      4.  Open the attribute directory of the base file, change into it,
4057  *          then recursively call open_attr_dir() to open the attribute's
4058  *          parent directory and change into it.
4059  *              attr_parent = <attr>
4060  *              attrname = <attr> | <sys_attr>
4061  *
4062  * An attribute directory will be opened only if the underlying file system
4063  * supports the attribute type, and if the command line specifications
4064  * (f_extended_attr and f_sys_attr) enable the processing of the attribute
4065  * type.
4066  *
4067  * On succesful return, attr_parentfd will be the file descriptor of the
4068  * opened attribute directory.  In addition, if the attribute is a read-write
4069  * extended system attribute, rw_sysattr will be set to 1, otherwise
4070  * it will be set to 0.
4071  *
4072  * Possible return values:
4073  *      ATTR_OK         Successfully opened and, if needed, changed into the
4074  *                      attribute directory containing attrname.
4075  *      ATTR_SKIP       The command line specifications don't enable the
4076  *                      processing of the attribute type.
4077  *      ATTR_CHDIR_ERR  An error occurred while trying to change into an
4078  *                      attribute directory.
4079  *      ATTR_OPEN_ERR   An error occurred while trying to open an
4080  *                      attribute directory.
4081  *      ATTR_XATTR_ERR  The underlying file system doesn't support extended
4082  *                      attributes.
4083  *      ATTR_SATTR_ERR  The underlying file system doesn't support extended
4084  *                      system attributes.
4085  */
4086 static int
4087 open_attr_dir(char *attrname, char *dirp, int cwd, char *attr_parent,
4088     int *attr_parentfd, int *rw_sysattr)
4089 {
4090         attr_status_t   rc;
4091         int             firsttime = (*attr_parentfd == -1);
4092         int             saveerrno;
4093         int             ext_attr;
4094 
4095         /*
4096          * open_attr_dir() was recursively called (input combination number 4),
4097          * close the previously opened file descriptor as we've already changed
4098          * into it.
4099          */
4100         if (!firsttime) {
4101                 (void) close(*attr_parentfd);
4102                 *attr_parentfd = -1;
4103         }
4104 
4105         /*
4106          * Verify that the underlying file system supports the restoration
4107          * of the attribute.
4108          */
4109         if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
4110             &ext_attr)) != ATTR_OK) {
4111                 return (rc);
4112         }
4113 
4114         /* Open the base file's attribute directory */
4115         if ((*attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
4116                 /*
4117                  * Save the errno from the attropen so it can be reported
4118                  * if the retry of the attropen fails.
4119                  */
4120                 saveerrno = errno;
4121                 if ((*attr_parentfd = retry_open_attr(-1, cwd, dirp,
4122                     NULL, ".", O_RDONLY, 0)) == -1) {
4123                         (void) close(*attr_parentfd);
4124                         *attr_parentfd = -1;
4125                         errno = saveerrno;
4126                         return (ATTR_OPEN_ERR);
4127                 }
4128         }
4129 
4130         /*
4131          * Change into the parent attribute's directory unless we are
4132          * processing the hidden attribute directory of the base file itself.
4133          */
4134         if ((Hiddendir == 0) || (firsttime && (attr_parent != NULL))) {
4135                 if (fchdir(*attr_parentfd) != 0) {
4136                         saveerrno = errno;
4137                         (void) close(*attr_parentfd);
4138                         *attr_parentfd = -1;
4139                         errno = saveerrno;
4140                         return (ATTR_CHDIR_ERR);
4141                 }
4142         }
4143 
4144         /* Determine if the attribute should be processed */
4145         if ((rc = verify_attr(attrname, attr_parent, 1,
4146             rw_sysattr)) != ATTR_OK) {
4147                 saveerrno = errno;
4148                 (void) close(*attr_parentfd);
4149                 *attr_parentfd = -1;
4150                 errno = saveerrno;
4151                 return (rc);
4152         }
4153 
4154         /*
4155          * If the attribute is an extended system attribute of an attribute
4156          * (i.e., <attr>/<sys_attr>), then recursively call open_attr_dir() to
4157          * open the attribute directory of the parent attribute.
4158          */
4159         if (firsttime && (attr_parent != NULL)) {
4160                 return (open_attr_dir(attrname, attr_parent, *attr_parentfd,
4161                     attr_parent, attr_parentfd, rw_sysattr));
4162         }
4163 
4164         return (ATTR_OK);
4165 }
4166 #endif
4167 
4168 /*
4169  * file_pass:  If the -l option is set (link files when possible), and the
4170  * source and destination file systems are the same, link the source file
4171  * (G_p->g_nam_p) to the destination file (Fullnam) and return.  If not a
4172  * linked file, transfer the data.  Otherwise, the first link to a file
4173  * encountered is transferred normally and subsequent links are linked to it.
4174  */
4175 
4176 static int
4177 file_pass(void)
4178 {
4179         struct Lnk *l_p, *tl_p;
4180         struct Lnk *ttl_p;
4181         char *save_name;
4182         int size;
4183         int cwd;
4184         char *lfrom, *lto;
4185 
4186         G_p = &Gen;
4187 
4188         if (Adir && !(Args & OCd)) {
4189                 msg(ERR, "Use -d option to copy \"%s\"", G_p->g_nam_p);
4190                 return (FILE_PASS_ERR);
4191         }
4192 
4193         save_name = G_p->g_nam_p;
4194 
4195         while (*(G_p->g_nam_p) == '/') {
4196                 G_p->g_nam_p++;
4197         }
4198 
4199         (void) strcpy(Full_p, (G_p->g_attrfnam_p == NULL) ?
4200             G_p->g_nam_p : G_p->g_attrfnam_p);
4201 
4202         if (G_p->g_attrnam_p == NULL) {
4203                 G_p->g_passdirfd = open_dir(Fullnam_p);
4204 
4205                 if (G_p->g_passdirfd == -1) {
4206                         msg(ERRN,
4207                             "Cannot open/create \"%s\"", Fullnam_p);
4208                         return (FILE_PASS_ERR);
4209                 }
4210         } else {
4211                 int     rw_sysattr;
4212 
4213                 /*
4214                  * Open the file's attribute directory.
4215                  * Change into the base file's starting directory then call
4216                  * open_attr_dir() to open the attribute directory of either
4217                  * the base file (if G_p->g_attrparent_p is NULL) or the
4218                  * attribute (if G_p->g_attrparent_p is set) of the base file.
4219                  */
4220 
4221                 G_p->g_passdirfd = -1;
4222                 (void) fchdir(G_p->g_baseparent_fd);
4223                 (void) open_attr_dir(G_p->g_attrnam_p, Fullnam_p,
4224                     G_p->g_baseparent_fd, (G_p->g_attrparent_p == NULL) ? NULL :
4225                     G_p->g_attrparent_p, &G_p->g_passdirfd, &rw_sysattr);
4226                 if (G_p->g_passdirfd == -1) {
4227                         msg(ERRN,
4228                             "Cannot open attribute directory of "
4229                             "%s%s%sfile \"%s\"",
4230                             (G_p->g_attrparent_p == NULL) ? "" :
4231                             gettext("attribute \""),
4232                             (G_p->g_attrparent_p == NULL) ? "" :
4233                             G_p->g_attrparent_p,
4234                             (G_p->g_attrparent_p == NULL) ? "" :
4235                             gettext("\" of "), Fullnam_p);
4236                         return (FILE_PASS_ERR);
4237                 }
4238         }
4239 
4240         if (Args & OCl) {
4241                 /* We are linking back to the source directory. */
4242 
4243                 if (!Adir) {
4244                         char *existingfile = save_name;
4245 
4246                         if ((Args & OCL) && issymlink) {
4247                                 /* We are chasing symlinks. */
4248 
4249                                 if ((size = readlink(save_name, Symlnk_p,
4250                                     MAXPATHLEN)) < 0) {
4251                                         msg(ERRN,
4252                                             "Cannot read symbolic link \"%s\"",
4253                                             save_name);
4254                                         return (FILE_PASS_ERR);
4255                                 }
4256 
4257                                 Symlnk_p[size] = '\0';
4258                                 existingfile = Symlnk_p;
4259                         }
4260 
4261                         if (G_p->g_attrnam_p == NULL) {
4262                                 if (creat_lnk(G_p->g_passdirfd,
4263                                     existingfile, Fullnam_p) == 0) {
4264                                         return (FILE_LINKED);
4265                                 }
4266                         }
4267                 }
4268         }
4269 
4270         if ((G_p->g_mode & Ftype) == S_IFLNK && !(Args & OCL)) {
4271                 /* The archive file is a symlink. */
4272 
4273                 errno = 0;
4274 
4275                 if ((size = readlink(save_name, Symlnk_p, MAXPATHLEN)) < 0) {
4276                         msg(ERRN,
4277                             "Cannot read symbolic link \"%s\"", save_name);
4278                         return (FILE_PASS_ERR);
4279                 }
4280 
4281                 errno = 0;
4282                 (void) missdir(Fullnam_p);
4283                 *(Symlnk_p + size) = '\0';
4284 
4285                 if (symlink(Symlnk_p, Fullnam_p) < 0) {
4286                         if (errno == EEXIST) {
4287                                 if (openout(G_p->g_passdirfd) < 0) {
4288                                         if (errno != EEXIST) {
4289                                                 msg(ERRN,
4290                                                     "Cannot create \"%s\"",
4291                                                     Fullnam_p);
4292                                         }
4293                                         return (FILE_PASS_ERR);
4294                                 }
4295                         } else {
4296                                 msg(ERRN, "Cannot create \"%s\"", Fullnam_p);
4297                                 return (FILE_PASS_ERR);
4298                         }
4299                 } else {
4300                         if (Args & OCR) {
4301                                 if (lchown(Fullnam_p, (int)Rpw_p->pw_uid,
4302                                     (int)Rpw_p->pw_gid) < 0) {
4303                                         msg(ERRN,
4304                                             "Error during chown() of \"%s\"",
4305                                             Fullnam_p);
4306                                 }
4307                         } else if ((lchown(Fullnam_p, (int)G_p->g_uid,
4308                             (int)G_p->g_gid) < 0) && privileged) {
4309                                 msg(ERRN,
4310                                     "Error during chown() of \"%s\"",
4311                                     Fullnam_p);
4312                         }
4313                 }
4314 
4315                 VERBOSE((Args & (OCv | OCV)), Fullnam_p);
4316                 return (FILE_PASS_ERR);
4317         }
4318 
4319         if (!Adir && G_p->g_nlink > 1) {
4320                 /* The archive file has hard links. */
4321 
4322                 tl_p = add_lnk(&ttl_p);
4323                 l_p = ttl_p;
4324 
4325                 if (tl_p == l_p) {
4326                         /* The archive file was not found. */
4327 
4328                         G_p = &tl_p->L_gen;
4329                 } else {
4330                         /* The archive file was found. */
4331 
4332                         cwd = -1;
4333 
4334                         if (l_p->L_gen.g_attrnam_p != NULL) {
4335                                 /* We are linking an attribute */
4336 
4337                                 (void) strcpy(Lnkend_p, l_p->L_gen.g_attrnam_p);
4338                                 cwd = save_cwd();
4339                                 (void) fchdir(G_p->g_passdirfd);
4340                                 lfrom = get_component(Lnknam_p);
4341                                 lto = tl_p->L_gen.g_attrnam_p;
4342                         } else {
4343                                 /* We are not linking an attribute */
4344 
4345                                 (void) strcpy(Lnkend_p, l_p->L_gen.g_nam_p);
4346                                 (void) strcpy(Full_p, tl_p->L_gen.g_nam_p);
4347                                 lfrom = Lnknam_p;
4348                                 lto = Fullnam_p;
4349                         }
4350 
4351                         (void) creat_lnk(G_p->g_passdirfd, lfrom, lto);
4352 
4353                         if (cwd) {
4354                                 rest_cwd(cwd);
4355                         }
4356 
4357                         l_p->L_lnk_p = NULL;
4358                         free(tl_p->L_gen.g_nam_p);
4359                         free(tl_p);
4360 
4361                         if (l_p->L_cnt == G_p->g_nlink) {
4362                                 reclaim(l_p);
4363                         }
4364 
4365                         return (FILE_LINKED);
4366                 }
4367         }
4368 
4369         if (Adir || Aspec) {
4370                 /*
4371                  * The archive file is a directory,  block special, char
4372                  * special or a fifo.
4373                  */
4374 
4375                 if (creat_spec(G_p->g_passdirfd) > 0) {
4376                         VERBOSE((Args & (OCv | OCV)), Fullnam_p);
4377                 }
4378         } else if ((Ofile = openout(G_p->g_passdirfd)) > 0) {
4379                 data_pass();
4380         }
4381 
4382         return (FILE_COPIED);
4383 }
4384 
4385 /*
4386  * flush_lnks: With new linked file handling, linked files are not archived
4387  * until all links have been collected.  When the end of the list of filenames
4388  * to archive has been reached, all files that did not encounter all their links
4389  * are written out with actual (encountered) link counts.  A file with n links
4390  * (that are archived) will be represented by n headers (one for each link (the
4391  * first n - 1 have g_filesz set to 0)) followed by the data for the file.
4392  */
4393 
4394 static void
4395 flush_lnks(void)
4396 {
4397         struct Lnk *l_p, *tl_p;
4398         off_t tfsize;
4399 
4400         l_p = Lnk_hd.L_nxt_p;
4401         while (l_p != &Lnk_hd) {
4402                 (void) strcpy(Gen.g_nam_p, l_p->L_gen.g_nam_p);
4403                 if (stat(Gen.g_nam_p, &SrcSt) == 0) { /* check if file exists */
4404                         tl_p = l_p;
4405                         (void) creat_hdr();
4406                         Gen.g_nlink = l_p->L_cnt; /* "actual" link count */
4407                         tfsize = Gen.g_filesz;
4408                         Gen.g_filesz = (off_t)0;
4409                         G_p = &Gen;
4410                         while (tl_p != NULL) {
4411                                 Gen.g_nam_p = tl_p->L_gen.g_nam_p;
4412                                 Gen.g_namesz = tl_p->L_gen.g_namesz;
4413                                 if (tl_p->L_lnk_p == NULL) {
4414                                         Gen.g_filesz = tfsize;
4415                                         if (open_dirfd() != 0) {
4416                                                 break;
4417                                         }
4418                                         data_out();
4419                                         break;
4420                                 }
4421                                 write_hdr(ARCHIVE_NORMAL,
4422                                     (off_t)0); /* header only */
4423                                 VERBOSE((Args & (OCv | OCV)), Gen.g_nam_p);
4424                                 tl_p = tl_p->L_lnk_p;
4425                         }
4426                         Gen.g_nam_p = Nam_p;
4427                 } else /* stat(Gen.g_nam_p, &SrcSt) == 0 */
4428                         msg(ERR, "\"%s%s%s\" has disappeared",
4429                             (Gen.g_attrnam_p == NULL) ?
4430                             Gen.g_nam_p : Gen.g_attrfnam_p,
4431                             (Gen.g_attrnam_p == NULL) ?
4432                             "" : Gen.g_rw_sysattr ?
4433                             gettext(" System Attribute ") :
4434                             gettext(" Attribute "),
4435                             (Gen.g_attrnam_p == NULL) ?
4436                             "" : Gen.g_attrnam_p);
4437                 tl_p = l_p;
4438                 l_p = l_p->L_nxt_p;
4439                 reclaim(tl_p);
4440         } /* l_p != &Lnk_hd */
4441 }
4442 
4443 #if defined(O_XATTR)
4444 static int
4445 is_sysattr(char *name)
4446 {
4447         return ((strcmp(name, VIEW_READONLY) == 0) ||
4448             (strcmp(name, VIEW_READWRITE) == 0));
4449 }
4450 #endif
4451 
4452 /*
4453  * gethdr: Get a header from the archive, validate it and check for the trailer.
4454  * Any user specified Hdr_type is ignored (set to NONE in main).  Hdr_type is
4455  * set appropriately after a valid header is found.  Unless the -k option is
4456  * set a corrupted header causes an exit with an error.  I/O errors during
4457  * examination of any part of the header cause gethdr to throw away any current
4458  * data and start over.  Other errors during examination of any part of the
4459  * header cause gethdr to advance one byte and continue the examination.
4460  */
4461 
4462 static int
4463 gethdr(void)
4464 {
4465         ushort_t ftype;
4466         int hit = NONE, cnt = 0;
4467         int goodhdr, hsize, offset;
4468         int bswap = 0;
4469         char *preptr;
4470         int k = 0;
4471         int j;
4472         int error;
4473         int aclcnt;
4474 
4475         Gen.g_nam_p = Nam_p;
4476         do { /* hit == NONE && (Args & OCk) && Buffr.b_cnt > 0 */
4477                 FILL(Hdrsz);
4478                 switch (Hdr_type) {
4479                 case NONE:
4480                 case BIN:
4481                         Binmag.b_byte[0] = Buffr.b_out_p[0];
4482                         Binmag.b_byte[1] = Buffr.b_out_p[1];
4483                         if ((Binmag.b_half == CMN_BIN) ||
4484                             (Binmag.b_half == CMN_BBS)) {
4485                                 hit = read_hdr(BIN);
4486                                 if (Hdr_type == NONE)
4487                                         bswap = 1;
4488                                 hsize = HDRSZ + Gen.g_namesz;
4489                                 break;
4490                         }
4491                         if (Hdr_type != NONE)
4492                                 break;
4493                         /*FALLTHROUGH*/
4494                 case CHR:
4495                         if (!(strncmp(Buffr.b_out_p, CMS_CHR, CMS_LEN))) {
4496                                 hit = read_hdr(CHR);
4497                                 hsize = CHRSZ + Gen.g_namesz;
4498                                 break;
4499                         }
4500                         if (Hdr_type != NONE)
4501                                 break;
4502                         /*FALLTHROUGH*/
4503                 case ASC:
4504                         if (!(strncmp(Buffr.b_out_p, CMS_ASC, CMS_LEN))) {
4505                                 hit = read_hdr(ASC);
4506                                 hsize = ASCSZ + Gen.g_namesz;
4507                                 Max_namesz = APATH;
4508                                 break;
4509                         }
4510                         if (Hdr_type != NONE)
4511                                 break;
4512                         /*FALLTHROUGH*/
4513                 case CRC:
4514                         if (!(strncmp(Buffr.b_out_p, CMS_CRC, CMS_LEN))) {
4515                                 hit = read_hdr(CRC);
4516                                 hsize = ASCSZ + Gen.g_namesz;
4517                                 Max_namesz = APATH;
4518                                 break;
4519                         }
4520                         if (Hdr_type != NONE)
4521                                 break;
4522                         /*FALLTHROUGH*/
4523 
4524                 case BAR:
4525                         if (Hdr_p != NULL && strcmp(Hdr_p, "bar") == 0) {
4526                                 Hdrsz = BARSZ;
4527                                 FILL(Hdrsz);
4528                                 if ((hit = read_hdr(BAR)) == NONE) {
4529                                         Hdrsz = ASCSZ;
4530                                         break;
4531                                 }
4532                                 hit = BAR;
4533                                 hsize = BARSZ;
4534                                 break;
4535                         }
4536                         /*FALLTHROUGH*/
4537 
4538                 case USTAR:
4539                         if (Hdr_p != NULL && strcmp(Hdr_p, "ustar") == 0) {
4540                                 Hdrsz = TARSZ;
4541                                 FILL(Hdrsz);
4542                                 if ((hit = read_hdr(USTAR)) == NONE) {
4543                                         Hdrsz = ASCSZ;
4544                                         break;
4545                                 }
4546                                 hit = USTAR;
4547                                 hsize = TARSZ;
4548                                 break;
4549                         }
4550                         /*FALLTHROUGH*/
4551                 case TAR:
4552                         if (Hdr_p != NULL && strcmp(Hdr_p, "tar") == 0) {
4553                                 Hdrsz = TARSZ;
4554                                 FILL(Hdrsz);
4555                                 if ((hit = read_hdr(TAR)) == NONE) {
4556                                         Hdrsz = ASCSZ;
4557                                         break;
4558                                 }
4559                                 hit = TAR;
4560                                 hsize = TARSZ;
4561                                 break;
4562                         }
4563                         /*FALLTHROUGH*/
4564                 default:
4565                         msg(EXT, "Impossible header type.");
4566                 } /* Hdr_type */
4567 
4568                 if (hit == TAR || hit == USTAR) {
4569                         Gen.g_nam_p = &nambuf[0];
4570                 }
4571 
4572                 if (hit != NONE) {
4573                         FILL(hsize);
4574                         goodhdr = 1;
4575                         if (Gen.g_filesz < (off_t)0 || Gen.g_namesz < 1)
4576                                 goodhdr = 0;
4577                         if ((hit != USTAR) && (hit != TAR))
4578                                 if (Gen.g_namesz - 1 > Max_namesz)
4579                                         goodhdr = 0;
4580                         /* TAR and USTAR */
4581                         if ((hit == USTAR) || (hit == TAR)) {
4582                                 if (*Gen.g_nam_p == '\0') { /* tar trailer */
4583                                         goodhdr = 1;
4584                                 } else {
4585 
4586                                         G_p = &Gen;
4587                                         if (G_p->g_cksum !=
4588                                             cksum(TARTYP, 0, NULL)) {
4589                                                 goodhdr = 0;
4590                                                 msg(ERR,
4591                                                     "Bad header - checksum "
4592                                                     "error.");
4593                                         }
4594                                 }
4595                         } else if (hit != BAR) { /* binary, -c, ASC and CRC */
4596                                 if (Gen.g_nlink <= (ulong_t)0)
4597                                         goodhdr = 0;
4598                                 if (*(Buffr.b_out_p + hsize - 1) != '\0')
4599                                         goodhdr = 0;
4600                         }
4601                         if (!goodhdr) {
4602                                 hit = NONE;
4603                                 if (!(Args & OCk))
4604                                         break;
4605                                 msg(ERR,
4606                                     "Corrupt header, file(s) may be lost.");
4607                         } else {
4608                                 FILL(hsize);
4609                         }
4610                 } /* hit != NONE */
4611                 if (hit == NONE) {
4612                         Buffr.b_out_p++;
4613                         Buffr.b_cnt--;
4614                         if (!(Args & OCk))
4615                                 break;
4616                         if (!cnt++)
4617                                 msg(ERR, "Searching for magic number/header.");
4618                 }
4619         } while (hit == NONE);
4620         if (hit == NONE) {
4621                 if (Hdr_type == NONE)
4622                         msg(EXT, "Not a cpio file, bad header.");
4623                 else
4624                         msg(EXT, "Bad magic number/header.");
4625         } else if (cnt > 0) {
4626                 msg(EPOST, "Re-synchronized on magic number/header.");
4627         }
4628         if (Hdr_type == NONE) {
4629                 Hdr_type = hit;
4630                 switch (Hdr_type) {
4631                 case BIN:
4632                         if (bswap)
4633                                 Args |= BSM;
4634                         Hdrsz = HDRSZ;
4635                         Max_namesz = CPATH;
4636                         Pad_val = HALFWD;
4637                         Onecopy = 0;
4638                         break;
4639                 case CHR:
4640                         Hdrsz = CHRSZ;
4641                         Max_namesz = CPATH;
4642                         Pad_val = 0;
4643                         Onecopy = 0;
4644                         break;
4645                 case ASC:
4646                 case CRC:
4647                         Hdrsz = ASCSZ;
4648                         Max_namesz = APATH;
4649                         Pad_val = FULLWD;
4650                         Onecopy = 1;
4651                         break;
4652                 case USTAR:
4653                         Hdrsz = TARSZ;
4654                         Max_namesz = HNAMLEN - 1;
4655                         Pad_val = FULLBK;
4656                         Onecopy = 0;
4657                         break;
4658                 case BAR:
4659                 case TAR:
4660                         Hdrsz = TARSZ;
4661                         Max_namesz = TNAMLEN - 1;
4662                         Pad_val = FULLBK;
4663                         Onecopy = 0;
4664                         break;
4665                 default:
4666                         msg(EXT, "Impossible header type.");
4667                 } /* Hdr_type */
4668         } /* Hdr_type == NONE */
4669         if ((Hdr_type == USTAR) || (Hdr_type == TAR) ||
4670             (Hdr_type == BAR)) {                        /* TAR, USTAR, BAR */
4671                 Gen.g_namesz = 0;
4672                 if (Gen.g_nam_p[0] == '\0')
4673                         return (0);
4674                 else {
4675                         preptr = &prebuf[0];
4676                         if (*preptr != NULL) {
4677                                 k = strlen(&prebuf[0]);
4678                                 if (k < PRESIZ) {
4679                                         (void) strcpy(&fullnam[0], &prebuf[0]);
4680                                         j = 0;
4681                                         fullnam[k++] = '/';
4682                                         while ((j < NAMSIZ) && (&nambuf[j] !=
4683                                             '\0')) {
4684                                                 fullnam[k] = nambuf[j];
4685                                                 k++; j++;
4686                                         }
4687                                         fullnam[k] = '\0';
4688                                 } else if (k >= PRESIZ) {
4689                                         k = 0;
4690                                         while ((k < PRESIZ) && (prebuf[k] !=
4691                                             '\0')) {
4692                                                 fullnam[k] = prebuf[k];
4693                                                 k++;
4694                                         }
4695                                         fullnam[k++] = '/';
4696                                         j = 0;
4697                                         while ((j < NAMSIZ) && (nambuf[j] !=
4698                                             '\0')) {
4699                                                 fullnam[k] = nambuf[j];
4700                                                 k++; j++;
4701                                         }
4702                                         fullnam[k] = '\0';
4703                                 }
4704                                 Gen.g_nam_p = &fullnam[0];
4705                         } else
4706                                 Gen.g_nam_p = &nambuf[0];
4707 
4708                         /*
4709                          * initialize the buffer so that the prefix will not
4710                          * applied to the next entry in the archive
4711                          */
4712                         (void) memset(prebuf, 0, sizeof (prebuf));
4713                 }
4714         } else if (Hdr_type != BAR) {
4715                 (void) memcpy(Gen.g_nam_p, Buffr.b_out_p + Hdrsz, Gen.g_namesz);
4716                 if (!(strcmp(Gen.g_nam_p, "TRAILER!!!")))
4717                         return (0);
4718         }
4719         offset = ((hsize + Pad_val) & ~Pad_val);
4720         FILL(offset + Hdrsz);
4721         Thdr_p = (union tblock *)Buffr.b_out_p;
4722         Buffr.b_out_p += offset;
4723         Buffr.b_cnt -= (off_t)offset;
4724         ftype = Gen.g_mode & Ftype;
4725 
4726 #if defined(O_XATTR)
4727         /* extended attribute support */
4728         if (((Gen.g_mode & S_IFMT) == _XATTR_CPIO_MODE) ||
4729             ((Hdr_type == USTAR || Hdr_type == TAR) &&
4730             Thdr_p->tbuf.t_typeflag == _XATTR_HDRTYPE)) {
4731                 char    *aname;
4732                 char    *attrparent = NULL;
4733                 char    *attrpath = NULL;
4734                 char    *tapath;
4735                 char    *taname;
4736 
4737                 if (xattrp != NULL) {
4738                         if (xattrbadhead) {
4739                                 free(xattrhead);
4740                                 xattrp = NULL;
4741                                 xattr_linkp = NULL;
4742                                 xattrhead = NULL;
4743                                 return (1);
4744                         }
4745 
4746                         /*
4747                          * At this point, the attribute path contains
4748                          * the path to the attribute rooted at the hidden
4749                          * attribute directory of the base file.  This can
4750                          * be a simple attribute or extended attribute name,
4751                          * or it can be something like <attr>/<sys attr> if
4752                          * we are processing a system attribute of an attribute.
4753                          * Determine the attribute name and attribute parent
4754                          * (if there is one).  When we are processing a simple
4755                          * attribute or extended attribute name, the attribute
4756                          * parent will be set to NULL.  When we are processing
4757                          * something like <attr>/<sys attr>, the attribute
4758                          * parent will be contain <attr>, and the attribute
4759                          * name will contain <sys attr>.
4760                          */
4761                         tapath = xattrp->h_names +
4762                             strlen(xattrp->h_names) + 1;
4763                         attrpath = e_strdup(E_EXIT, tapath);
4764                         if ((taname = strpbrk(tapath, "/")) != NULL) {
4765                                 aname = taname + 1;
4766                                 *taname = '\0';
4767                                 attrparent = tapath;
4768                         } else {
4769                                 aname = tapath;
4770                         }
4771 
4772                         Gen.g_rw_sysattr = is_sysattr(aname);
4773                         Gen.g_baseparent_fd = attr_baseparent_fd;
4774 
4775                         if (Gen.g_attrfnam_p != NULL) {
4776                                 free(Gen.g_attrfnam_p);
4777                                 Gen.g_attrfnam_p = NULL;
4778                         }
4779                         if (Gen.g_attrnam_p != NULL) {
4780                                 free(Gen.g_attrnam_p);
4781                                 Gen.g_attrnam_p = NULL;
4782                         }
4783                         if (Gen.g_attrparent_p != NULL) {
4784                                 free(Gen.g_attrparent_p);
4785                                 Gen.g_attrparent_p = NULL;
4786                         }
4787                         if (Gen.g_attrpath_p != NULL) {
4788                                 free(Gen.g_attrpath_p);
4789                                 Gen.g_attrpath_p = NULL;
4790                         }
4791                         if (Renam_p && Renam_p[0] != '\0') {
4792                                 Gen.g_attrfnam_p = e_strdup(E_EXIT, Renam_p);
4793                         } else {
4794                                 Gen.g_attrfnam_p = e_strdup(E_EXIT,
4795                                     xattrp->h_names);
4796                         }
4797                         Gen.g_attrnam_p = e_strdup(E_EXIT, aname);
4798 
4799                         if (attrparent != NULL) {
4800                                 if (Renam_attr_p && Renam_attr_p[0] != '\0') {
4801                                         size_t  apathlen = strlen(attrparent) +
4802                                             strlen(aname) + 2;
4803                                         Gen.g_attrparent_p = e_strdup(E_EXIT,
4804                                             Renam_attr_p);
4805                                         Gen.g_attrpath_p = e_zalloc(E_EXIT,
4806                                             apathlen);
4807                                         (void) snprintf(Gen.g_attrpath_p,
4808                                             apathlen, "%s/%s", Renam_attr_p,
4809                                             aname);
4810                                         (void) free(attrparent);
4811                                         (void) free(attrpath);
4812                                 } else {
4813                                         Gen.g_attrparent_p = attrparent;
4814                                         Gen.g_attrpath_p = attrpath;
4815                                 }
4816                         } else {
4817                                 Gen.g_attrpath_p = attrpath;
4818                         }
4819 
4820                         if (xattr_linkp != NULL) {
4821                                 if (Gen.g_linktoattrfnam_p != NULL) {
4822                                         free(Gen.g_linktoattrfnam_p);
4823                                         Gen.g_linktoattrfnam_p = NULL;
4824                                 }
4825                                 if (Gen.g_linktoattrnam_p != NULL) {
4826                                         free(Gen.g_linktoattrnam_p);
4827                                         Gen.g_linktoattrnam_p = NULL;
4828                                 }
4829                                 if (Renam_attr_p && Renam_attr_p[0] != '\0') {
4830                                         Gen.g_linktoattrfnam_p = e_strdup(
4831                                             E_EXIT, Renam_attr_p);
4832                                 } else {
4833                                         Gen.g_linktoattrfnam_p = e_strdup(
4834                                             E_EXIT, xattr_linkp->h_names);
4835                                 }
4836                                 Gen.g_linktoattrnam_p = e_strdup(E_EXIT,
4837                                     aname);
4838                                 xattr_linkp = NULL;
4839                         }
4840                         if (Hdr_type != USTAR && Hdr_type != TAR) {
4841                                 Gen.g_mode = Gen.g_mode & (~_XATTR_CPIO_MODE);
4842                                 Gen.g_mode |= attrmode(xattrp->h_typeflag);
4843                         } else if (Hdr_type == USTAR || Hdr_type == TAR) {
4844                                 Thdr_p->tbuf.t_typeflag = xattrp->h_typeflag;
4845                         }
4846 
4847                         ftype = Gen.g_mode & Ftype;
4848                         Adir = ftype == S_IFDIR;
4849                         Aspec = (ftype == S_IFBLK || ftype == S_IFCHR ||
4850                             ftype == S_IFIFO || ftype == S_IFSOCK);
4851 
4852                         if (Gen.g_attrnam_p[0] == '.' &&
4853                             Gen.g_attrnam_p[1] == '\0' &&
4854                             xattrp->h_typeflag == DIRTYPE) {
4855                                 Hiddendir = 1;
4856                         } else {
4857                                 Hiddendir = 0;
4858                         }
4859 
4860                         free(xattrhead);
4861                         xattrhead = NULL;
4862                         xattrp = NULL;
4863                 } else {
4864                         if (xattrbadhead == 0) {
4865                                 (void) read_xattr_hdr();
4866                                 return (2);
4867                         }
4868                 }
4869         } else {
4870                 Hiddendir = 0;
4871         }
4872 #endif /* O_XATTR */
4873 
4874         /* acl support: grab acl info */
4875         if ((Gen.g_mode == SECMODE) || ((Hdr_type == USTAR ||
4876             Hdr_type == TAR) && Thdr_p->tbuf.t_typeflag == 'A')) {
4877                 /* this is an ancillary file */
4878                 off_t   bytes;
4879                 char    *secp;
4880                 int     pad;
4881                 int     cnt;
4882                 char    *tp;
4883                 int     attrsize;
4884 
4885                 if (Pflag) {
4886                         bytes = Gen.g_filesz;
4887                         secp = e_zalloc(E_EXIT, (uint_t)bytes);
4888                         tp = secp;
4889 
4890                         while (bytes > 0) {
4891                                 cnt = (int)(bytes > CPIOBSZ) ? CPIOBSZ : bytes;
4892                                 FILL(cnt);
4893                                 (void) memcpy(tp, Buffr.b_out_p, cnt);
4894                                 tp += cnt;
4895                                 Buffr.b_out_p += cnt;
4896                                 Buffr.b_cnt -= (off_t)cnt;
4897                                 bytes -= (off_t)cnt;
4898                         }
4899 
4900                         pad = (Pad_val + 1 - (Gen.g_filesz & Pad_val)) &
4901                             Pad_val;
4902                         if (pad != 0) {
4903                                 FILL(pad);
4904                                 Buffr.b_out_p += pad;
4905                                 Buffr.b_cnt -= (off_t)pad;
4906                         }
4907 
4908                         /* got all attributes in secp */
4909                         tp = secp;
4910                         do {
4911                                 attr = (struct sec_attr *)tp;
4912                                 switch (attr->attr_type) {
4913                                 case UFSD_ACL:
4914                                 case ACE_ACL:
4915                                         (void) sscanf(attr->attr_len, "%7lo",
4916                                             (ulong_t *)&aclcnt);
4917                                         /* header is 8 */
4918                                         attrsize = 8 +
4919                                             strlen(&attr->attr_info[0])
4920                                             + 1;
4921 
4922                                         error =
4923                                             acl_fromtext(&attr->attr_info[0],
4924                                             &aclp);
4925 
4926                                         if (error != 0) {
4927                                                 msg(ERR,
4928                                                     "aclfromtext failed: %s",
4929                                                     acl_strerror(error));
4930                                                 bytes -= attrsize;
4931                                                 break;
4932                                         }
4933 
4934                                         if (aclcnt != acl_cnt(aclp)) {
4935                                                 msg(ERR, "acl count error");
4936                                                 bytes -= attrsize;
4937                                                 break;
4938                                         }
4939                                         bytes -= attrsize;
4940                                         break;
4941 
4942                                 /* SunFed case goes here */
4943 
4944                                 default:
4945                                         msg(EXT, "unrecognized attr type");
4946                                         break;
4947                         }
4948                         /* next attributes */
4949                         tp += attrsize;
4950                         } while (bytes > 0);
4951                         free(secp);
4952                 } else {
4953                         /* skip security info */
4954                         G_p = &Gen;
4955                         data_in(P_SKIP);
4956                 }
4957                 /*
4958                  * We already got the file content, dont call file_in()
4959                  * when return. The new return code(2) is used to
4960                  *  indicate that.
4961                  */
4962                 VERBOSE((Args & OCt), Gen.g_nam_p);
4963                 return (2);
4964         } /* acl */
4965 
4966         /*
4967          * Sparse file support
4968          * Read header of holesdata to get original file size.
4969          * This is necessary because ckname() or file_in() shows file size
4970          * with OCt before data_in() extracts the holesdata. data_in()
4971          * actually doesn't extract the holesdata since proc_mode will be
4972          * P_SKIP in the OCt mode.
4973          */
4974         if ((Hdr_type == CHR || Hdr_type == ASC) &&
4975             S_ISSPARSE(Gen.g_mode) && Gen.g_filesz > MIN_HOLES_HDRSIZE) {
4976                 char    holesdata[MIN_HOLES_HDRSIZE + 1];
4977 
4978                 FILL(MIN_HOLES_HDRSIZE);
4979                 (void) memcpy(holesdata, Buffr.b_out_p, MIN_HOLES_HDRSIZE);
4980                 holesdata[MIN_HOLES_HDRSIZE] = '\0';
4981 
4982                 Gen.g_holes = read_holes_header(holesdata, Gen.g_filesz);
4983                 if (Gen.g_holes == NULL) {
4984                         msg(EXT, "invalid sparse file information");
4985                 } else {
4986                         Buffr.b_out_p += MIN_HOLES_HDRSIZE;
4987                         Buffr.b_cnt -= MIN_HOLES_HDRSIZE;
4988                 }
4989         }
4990 
4991         Adir = (ftype == S_IFDIR);
4992         Aspec = (ftype == S_IFBLK || ftype == S_IFCHR || ftype == S_IFIFO ||
4993             ftype == S_IFSOCK);
4994 
4995         /*
4996          * Skip any trailing slashes
4997          */
4998         chop_endslashes(Gen.g_nam_p);
4999         return (1);
5000 }
5001 
5002 /*
5003  * getname: Get file names for inclusion in the archive.  When end of file
5004  * on the input stream of file names is reached, flush the link buffer out.
5005  * For each filename, remove leading "./"s and multiple "/"s, and remove
5006  * any trailing newline "\n".  Finally, verify the existence of the file,
5007  * and call creat_hdr() to fill in the gen_hdr structure.
5008  */
5009 
5010 static int
5011 getname(void)
5012 {
5013         int goodfile = 0, lastchar, err;
5014         char *s;
5015         char *dir;
5016 
5017         Gen.g_nam_p = Nam_p;
5018         Hiddendir = 0;
5019 
5020         while (!goodfile) {
5021                 err = 0;
5022 
5023                 while ((s = fgets(Gen.g_nam_p, APATH+1, In_p)) != NULL) {
5024                         lastchar = strlen(s) - 1;
5025                         issymlink = 0;
5026 
5027                         if (s[lastchar] != '\n') {
5028                                 if (lastchar == APATH - 1) {
5029                                         if (!err) {
5030                                                 msg(ERR,
5031                                                     "%s name too long.",
5032                                                     Nam_p);
5033                                         }
5034                                         goodfile = 0;
5035                                         err = 1;
5036                                 } else {
5037                                         break;
5038                                 }
5039                         } else {
5040                                 s[lastchar] = '\0';
5041                                 break;
5042                         }
5043                 }
5044 
5045                 if (s == NULL) {
5046                         if (Gen.g_dirfd != -1) {
5047                                 (void) close(Gen.g_dirfd);
5048                                 Gen.g_dirfd = -1;
5049                         }
5050                         if (Onecopy && (Args & OCo)) {
5051                                 flush_lnks();
5052                         }
5053                         return (0);
5054                 }
5055 
5056                 while (*Gen.g_nam_p == '.' && Gen.g_nam_p[1] == '/') {
5057                         Gen.g_nam_p += 2;
5058                         while (*Gen.g_nam_p == '/')
5059                                 Gen.g_nam_p++;
5060                 }
5061 
5062                 /*
5063                  * Skip any trailing slashes
5064                  */
5065                 chop_endslashes(Gen.g_nam_p);
5066 
5067                 /*
5068                  * Figure out parent directory
5069                  */
5070 
5071                 if (Gen.g_attrnam_p != NULL) {
5072                         if (Gen.g_dirfd != -1) {
5073                                 (void) close(Gen.g_dirfd);
5074                         }
5075                         Gen.g_dirfd = attropen(Gen.g_attrfnam_p, ".", O_RDONLY);
5076                         if (Gen.g_dirfd == -1) {
5077                                 msg(ERRN,
5078                                     "Cannot open attribute directory"
5079                                     " of file %s", Gen.g_attrfnam_p);
5080                                 continue;
5081                         }
5082                 } else {
5083 #ifdef O_XATTR
5084                         char dirpath[PATH_MAX];
5085 
5086                         get_parent(Gen.g_nam_p, dirpath);
5087                         if (Atflag || SysAtflag) {
5088                                 dir = dirpath;
5089                                 if (Gen.g_dirfd != -1) {
5090                                         (void) close(Gen.g_dirfd);
5091                                 }
5092                                 Gen.g_dirfd = open(dir, O_RDONLY);
5093                                 if (Gen.g_dirfd == -1) {
5094                                         msg(ERRN,
5095                                             "Cannot open directory %s", dir);
5096                                         continue;
5097                                 }
5098                         } else {
5099                                 /*
5100                                  * g_dirpath is the pathname cache maintaining
5101                                  * the dirname which is currently opened.
5102                                  * We first check the g_dirpath to see if the
5103                                  * given dirname matches. If so, we don't need
5104                                  * to open the dir, but we can use the g_dirfd
5105                                  * as is if it is still available.
5106                                  */
5107                                 dir = NULL;
5108                                 if (Gen.g_dirpath == NULL ||
5109                                     Gen.g_dirfd == -1) {
5110                                         /*
5111                                          * It's the first time or it has
5112                                          * all gone.
5113                                          */
5114                                         dir = e_strdup(E_EXIT, dirpath);
5115                                 } else {
5116                                         if (strcmp(Gen.g_dirpath,
5117                                             dirpath) != 0) {
5118                                                 /* different directory */
5119                                                 dir = e_strdup(E_EXIT, dirpath);
5120                                         }
5121                                 }
5122                                 if (dir != NULL) {
5123                                         /*
5124                                          * We need to open the new directory.
5125                                          * discard the pathname and dirfd
5126                                          * for the previous directory.
5127                                          */
5128                                         if (Gen.g_dirpath != NULL) {
5129                                                 free(Gen.g_dirpath);
5130                                                 Gen.g_dirpath = NULL;
5131                                         }
5132                                         if (Gen.g_dirfd != -1) {
5133                                                 (void) close(Gen.g_dirfd);
5134                                         }
5135                                         /* open the new dir */
5136                                         Gen.g_dirfd = open(dir, O_RDONLY);
5137                                         if (Gen.g_dirfd == -1) {
5138                                                 msg(ERRN, "Cannot open "
5139                                                     "directory %s", dir);
5140                                                 continue;
5141                                         }
5142                                         Gen.g_dirpath = dir;
5143                                 }
5144                         }
5145 #else
5146                         Gen.g_dirfd = -1;
5147 #endif
5148                 }
5149 
5150                 /* creat_hdr checks for USTAR filename length */
5151 
5152                 if (Hdr_type != USTAR && strlen(Gen.g_nam_p) >
5153                     Max_namesz) {
5154                         if (!err) {
5155                                 msg(ERR, "%s%s%s name too long.",
5156                                     (Gen.g_attrnam_p == NULL) ?
5157                                     Nam_p : Gen.g_attrfnam_p,
5158                                     (Gen.g_attrnam_p == NULL) ?
5159                                     "" : Gen.g_rw_sysattr ?
5160                                     gettext(" System Attribute ") :
5161                                     gettext(" Attribute "),
5162                                     (Gen.g_attrnam_p == NULL) ?
5163                                     "" : Gen.g_attrnam_p);
5164                         }
5165                         goodfile = 0;
5166                         err = 1;
5167                 }
5168 
5169                 if (err) {
5170                         continue;
5171                 } else {
5172                         G_p = &Gen;
5173                         if (!LSTAT(Gen.g_dirfd, Gen.g_nam_p, &SrcSt)) {
5174                                 goodfile = 1;
5175 
5176                                 if ((SrcSt.st_mode & Ftype) == S_IFLNK) {
5177                                         issymlink = 1;
5178 
5179                                         if ((Args & OCL)) {
5180                                                 errno = 0;
5181                                                 if (STAT(Gen.g_dirfd,
5182                                                     G_p->g_nam_p,
5183                                                     &SrcSt) < 0) {
5184                                                         msg(ERRN,
5185                                                             "Cannot follow"
5186                                                             " \"%s%s%s\"",
5187                                                             (Gen.g_attrnam_p ==
5188                                                             NULL) ?
5189                                                             Gen.g_nam_p :
5190                                                             Gen.g_attrfnam_p,
5191                                                             (Gen.g_attrnam_p ==
5192                                                             NULL) ? "" :
5193                                                             Gen.g_rw_sysattr ?
5194                                                             gettext(
5195                                                             " System "
5196                                                             "Attribute ") :
5197                                                             gettext(
5198                                                             " Attribute "),
5199                                                             (Gen.g_attrnam_p ==
5200                                                             NULL) ? "" :
5201                                                             Gen.g_attrnam_p);
5202                                                         goodfile = 0;
5203                                                 }
5204                                         }
5205                                 }
5206 
5207                                 if (Use_old_stat) {
5208                                         OldSt = convert_to_old_stat(&SrcSt,
5209                                             Gen.g_nam_p, Gen.g_attrnam_p);
5210 
5211                                         if (OldSt == NULL) {
5212                                                 goodfile = 0;
5213                                         }
5214                                 }
5215                         } else {
5216                                 msg(ERRN,
5217                                     "Error with fstatat() of \"%s%s%s\"",
5218                                     (Gen.g_attrnam_p == NULL) ?
5219                                     Gen.g_nam_p : Gen.g_attrfnam_p,
5220                                     (Gen.g_attrnam_p == NULL) ? "" :
5221                                     Gen.g_rw_sysattr ?
5222                                     gettext(" System Attribute ") :
5223                                     gettext(" Attribute "),
5224                                     (Gen.g_attrnam_p == NULL) ?
5225                                     "" : Gen.g_attrnam_p);
5226                         }
5227                 }
5228         }
5229 
5230         /*
5231          * Get ACL info: dont bother allocating space if there are only
5232          * standard permissions, i.e. ACL count < 4
5233          */
5234         if ((SrcSt.st_mode & Ftype) != S_IFLNK && Pflag) {
5235                 if (acl_get(Gen.g_nam_p, ACL_NO_TRIVIAL, &aclp) != 0)
5236                         msg(ERRN, "Error with acl() of \"%s\"", Gen.g_nam_p);
5237         }
5238         /* else: only traditional permissions, so proceed as usual */
5239         if (creat_hdr())
5240                 return (1);
5241         else return (2);
5242 }
5243 
5244 /*
5245  * getpats: Save any filenames/patterns specified as arguments.
5246  * Read additional filenames/patterns from the file specified by the
5247  * user.  The filenames/patterns must occur one per line.
5248  */
5249 
5250 static void
5251 getpats(int largc, char **largv)
5252 {
5253         char **t_pp;
5254         size_t len;
5255         unsigned numpat = largc, maxpat = largc + 2;
5256 
5257         Pat_pp = e_zalloc(E_EXIT, maxpat * sizeof (char *));
5258         t_pp = Pat_pp;
5259         while (*largv) {
5260                 *t_pp = e_zalloc(E_EXIT, strlen(*largv) + 1);
5261                 (void) strcpy(*t_pp, *largv);
5262                 t_pp++;
5263                 largv++;
5264         }
5265         while (fgets(Nam_p, Max_namesz + 1, Ef_p) != NULL) {
5266                 if (numpat == maxpat - 1) {
5267                         maxpat += 10;
5268                         Pat_pp = e_realloc(E_EXIT, Pat_pp,
5269                             maxpat * sizeof (char *));
5270                         t_pp = Pat_pp + numpat;
5271                 }
5272                 len = strlen(Nam_p); /* includes the \n */
5273                 *(Nam_p + len - 1) = '\0'; /* remove the \n */
5274                 *t_pp = e_zalloc(E_EXIT, len);
5275                 (void) strcpy(*t_pp, Nam_p);
5276                 t_pp++;
5277                 numpat++;
5278         }
5279         *t_pp = NULL;
5280 }
5281 
5282 static void
5283 ioerror(int dir)
5284 {
5285         int t_errno;
5286 
5287         t_errno = errno;
5288         errno = 0;
5289         if (fstat(Archive, &ArchSt) < 0)
5290                 msg(EXTN, "Error during stat() of archive");
5291         errno = t_errno;
5292         if ((ArchSt.st_mode & Ftype) != S_IFCHR) {
5293                 if (dir) {
5294                         if (errno == EFBIG)
5295                                 msg(EXT, "ulimit reached for output file.");
5296                         else if (errno == ENOSPC)
5297                                 msg(EXT, "No space left for output file.");
5298                         else
5299                                 msg(EXTN, "I/O error - cannot continue");
5300                 } else
5301                         msg(EXT, "Unexpected end-of-file encountered.");
5302         } else
5303                 msg(EXTN, "\007I/O error on \"%s\"", dir ? "output" : "input");
5304 }
5305 
5306 /*
5307  * matched: Determine if a filename matches the specified pattern(s).  If the
5308  * pattern is matched (the second return), return 0 if -f was specified, else
5309  * return != 0.  If the pattern is not matched (the first and third
5310  * returns), return 0 if -f was not specified, else return != 0.
5311  */
5312 
5313 static int
5314 matched(void)
5315 {
5316         char *str_p = G_p->g_nam_p;
5317         char **pat_pp = Pat_pp;
5318         int negatep, result;
5319 
5320         /*
5321          * Check for attribute
5322          */
5323         if (G_p->g_attrfnam_p != NULL)
5324                 str_p = G_p->g_attrfnam_p;
5325 
5326         for (pat_pp = Pat_pp; *pat_pp; pat_pp++) {
5327                 negatep = (**pat_pp == '!');
5328 
5329                 result = fnmatch(negatep ? (*pat_pp+1) : *pat_pp, str_p, 0);
5330 
5331                 if (result != 0 && result != FNM_NOMATCH) {
5332                         msg(POST, "error matching file %s with pattern"
5333                             " %s\n", str_p, *pat_pp);
5334                         return (Args & OCf);
5335                 }
5336 
5337                 if ((result == 0 && ! negatep) ||
5338                     (result == FNM_NOMATCH && negatep)) {
5339                         /* match occurred */
5340                         return (!(Args & OCf));
5341                 }
5342         }
5343         return (Args & OCf); /* not matched */
5344 }
5345 
5346 /*
5347  * missdir: Create missing directories for files.
5348  * (Possible future performance enhancement, if missdir is called, we know
5349  * that at least the very last directory of the path does not exist, therefore,
5350  * scan the path from the end
5351  */
5352 
5353 static int
5354 missdir(char *nam_p)
5355 {
5356         char *c_p;
5357         int cnt = 2;
5358         char *lastp;
5359 
5360         if (*(c_p = nam_p) == '/') /* skip over 'root slash' */
5361                 c_p++;
5362 
5363         lastp = c_p + strlen(nam_p) - 1;
5364         if (*lastp == '/')
5365                 *lastp = '\0';
5366 
5367         for (; *c_p; ++c_p) {
5368                 if (*c_p == '/') {
5369                         *c_p = '\0';
5370                         if (stat(nam_p, &DesSt) < 0) {
5371                                 if (Args & OCd) {
5372                                         cnt = mkdir(nam_p, Def_mode);
5373                                         if (cnt != 0) {
5374                                                 *c_p = '/';
5375                                                 return (cnt);
5376                                         }
5377                                 } else {
5378                                         msg(ERR, "Missing -d option.");
5379                                         *c_p = '/';
5380                                         return (-1);
5381                                 }
5382                         }
5383                         *c_p = '/';
5384                 }
5385         }
5386         if (cnt == 2) /* the file already exists */
5387                 cnt = 0;
5388         return (cnt);
5389 }
5390 
5391 /*
5392  * mklong: Convert two shorts into one long.  For VAX, Interdata ...
5393  */
5394 
5395 static long
5396 mklong(short v[])
5397 {
5398 
5399         union swpbuf swp_b;
5400 
5401         swp_b.s_word = 1;
5402         if (swp_b.s_byte[0]) {
5403                 swp_b.s_half[0] = v[1];
5404                 swp_b.s_half[1] = v[0];
5405         } else {
5406                 swp_b.s_half[0] = v[0];
5407                 swp_b.s_half[1] = v[1];
5408         }
5409         return (swp_b.s_word);
5410 }
5411 
5412 /*
5413  * mkshort: Convert a long into 2 shorts, for VAX, Interdata ...
5414  */
5415 
5416 static void
5417 mkshort(short sval[], long v)
5418 {
5419         union swpbuf *swp_p, swp_b;
5420 
5421         /* LINTED alignment */
5422         swp_p = (union swpbuf *)sval;
5423         swp_b.s_word = 1;
5424         if (swp_b.s_byte[0]) {
5425                 swp_b.s_word = v;
5426                 swp_p->s_half[0] = swp_b.s_half[1];
5427                 swp_p->s_half[1] = swp_b.s_half[0];
5428         } else {
5429                 swp_b.s_word = v;
5430                 swp_p->s_half[0] = swp_b.s_half[0];
5431                 swp_p->s_half[1] = swp_b.s_half[1];
5432         }
5433 }
5434 
5435 /*
5436  * msg: Print either a message (no error) (POST), an error message with or
5437  * without the errno (ERRN or ERR), or print an error message with or without
5438  * the errno and exit (EXTN or EXT).
5439  */
5440 void
5441 msg(int severity, const char *fmt, ...)
5442 {
5443         FILE *file_p;
5444         va_list ap;
5445 
5446         if ((Args & OCV) && Verbcnt) { /* clear current line of dots */
5447                 (void) fputc('\n', Out_p);
5448                 Verbcnt = 0;
5449         }
5450         va_start(ap, fmt);
5451         if (severity == POST)
5452                 file_p = Out_p;
5453         else
5454                 if (severity == EPOST)
5455                         file_p = Err_p;
5456                 else {
5457                         file_p = Err_p;
5458                         Error_cnt++;
5459                 }
5460         (void) fflush(Out_p);
5461         (void) fflush(Err_p);
5462         if ((severity != POST) && (severity != EPOST))
5463                 (void) fprintf(file_p, "cpio: ");
5464 
5465         /* gettext replaces version of string */
5466 
5467         (void) vfprintf(file_p, gettext(fmt), ap);
5468         if (severity == ERRN || severity == EXTN) {
5469                 if (G_p && (G_p->g_attrnam_p != NULL) && G_p->g_rw_sysattr) {
5470                         if (errno == EPERM) {
5471                                 (void) fprintf(file_p, ", errno %d, %s", errno,
5472                                     gettext("insufficient privileges\n"));
5473                         } else if (errno == EINVAL) {
5474                                 (void) fprintf(file_p, ", errno %d, %s",
5475                                     errno, gettext(
5476                                     "unsupported on underlying file system\n"));
5477                         } else {
5478                                 (void) fprintf(file_p, ", errno %d, ", errno);
5479                                 perror("");
5480                         }
5481                 } else {
5482                         (void) fprintf(file_p, ", errno %d, ", errno);
5483                         perror("");
5484                 }
5485         } else
5486                 (void) fprintf(file_p, "\n");
5487         (void) fflush(file_p);
5488         va_end(ap);
5489         if (severity == EXT || severity == EXTN) {
5490                 (void) fprintf(file_p, gettext("%d errors\n"), Error_cnt);
5491                 exit(EXIT_CODE);
5492         }
5493 }
5494 
5495 /*
5496  * openout: Open files for output and set all necessary information.
5497  * If the u option is set (unconditionally overwrite existing files),
5498  * and the current file exists, get a temporary file name from mktemp(3C),
5499  * link the temporary file to the existing file, and remove the existing file.
5500  * Finally either creat(2), mkdir(2) or mknod(2) as appropriate.
5501  *
5502  */
5503 
5504 static int
5505 openout(int dirfd)
5506 {
5507         char *nam_p;
5508         int cnt, result;
5509 
5510         Do_rename = 0;  /* creat_tmp() may reset this */
5511 
5512         if (G_p->g_attrnam_p != NULL) {
5513                 nam_p = G_p->g_attrnam_p;
5514         } else {
5515                 if (Args & OCp) {
5516                         nam_p = Fullnam_p;
5517                 } else {
5518                         nam_p = G_p->g_nam_p;
5519                 }
5520         }
5521 
5522 
5523         if ((Max_filesz != RLIM_INFINITY) &&
5524             (Max_filesz < (G_p->g_filesz >> 9))) {
5525                 /* ... divided by 512 ... */
5526                 msg(ERR, "Skipping \"%s%s%s\": exceeds ulimit by %lld bytes",
5527                     (G_p->g_attrnam_p == NULL) ? nam_p : G_p->g_attrfnam_p,
5528                     (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
5529                     gettext(" System Attribute ") : gettext(" Attribute "),
5530                     (G_p->g_attrnam_p == NULL) ? "" : nam_p,
5531                     (off_t)(G_p->g_filesz - (Max_filesz << 9)));
5532                 return (-1);
5533         }
5534 
5535         if (LSTAT(dirfd, nam_p, &DesSt) == 0) {
5536                 /*
5537                  * A file by the same name exists.  Move it to a temporary
5538                  * file unless it's a system attribute file.  If we are
5539                  * restoring a system attribute file on a file system that
5540                  * supports system attributes, then the system attribute file
5541                  * will already exist (a default system attribute file will
5542                  * get created when the file it is associated with is created).
5543                  * If we create a temporary system attribute file, we can't
5544                  * overwrite the existing system attribute file using
5545                  * renameat().  In addition, only system attributes can exist
5546                  * for an attribute of a file, therefore, a temporary file
5547                  * cannot be created for a system attribute of an attribute.
5548                  * Thus, when restoring a system attribute, we won't move it
5549                  * to a temporary file, but will attempt to process it as if
5550                  * it didn't already exist.
5551                  */
5552 
5553 #if defined(_PC_SATTR_ENABLED)
5554                 if (G_p->g_rw_sysattr == 0)
5555 #endif  /* _PC_SATTR_ENABLED */
5556                         if (creat_tmp(nam_p) < 0) {
5557                                 /*
5558                                  * We weren't able to create the temp file.
5559                                  * Report failure.
5560                                  */
5561 
5562                                 return (-1);
5563                         }
5564         }
5565 
5566         if (Do_rename) {
5567                 /* nam_p was changed by creat_tmp() above. */
5568 
5569                 if (Args & OCp) {
5570                         if (G_p->g_attrnam_p != NULL) {
5571                                 nam_p = Attrfile_p;
5572                         } else {
5573                                 nam_p = Fullnam_p;
5574                         }
5575                 } else {
5576                         nam_p = G_p->g_nam_p;
5577                 }
5578         }
5579 
5580         /*
5581          * This pile tries to create the file directly, and, if there is a
5582          * problem, creates missing directories, and then tries to create the
5583          * file again.  Two strikes and you're out.
5584          *
5585          * On XATTR system, the directory has already been created by
5586          * open_dirfd(), so error shouldn't happen in the loop. However,
5587          * on non-XATTR system, symlink/open may fail with ENOENT. In such
5588          * case, we go to create missing directories.
5589          */
5590 
5591         cnt = 0;
5592 
5593         do {
5594                 errno = 0;
5595 
5596                 if (Hdr_type == TAR && Thdr_p->tbuf.t_typeflag == SYMTYPE) {
5597                         /* The archive file is a TAR symlink. */
5598                         if ((result =
5599                             symlink(Thdr_p->tbuf.t_linkname, nam_p)) >= 0) {
5600                                 cnt = 0;
5601                                 if (Over_p != NULL) {
5602                                         (void) unlinkat(dirfd,
5603                                             get_component(Over_p), 0);
5604                                         *Over_p = '\0';
5605                                 }
5606                                 break;
5607                         } else if (errno != ENOENT) {
5608                                 /* The attempt to symlink failed. */
5609                                 msg(ERRN,
5610                                     "Cannot create symbolic link \"%s\" -> "
5611                                     "\"%s\"",
5612                                     Thdr_p->tbuf.t_linkname, nam_p);
5613 
5614                                 if (*Over_p != '\0') {
5615                                         rstfiles(U_KEEP, dirfd);
5616                                 }
5617                                 return (-1);
5618                         }
5619                 } else if (Hdr_type == BAR && bar_linkflag == SYMTYPE) {
5620                         if ((result = symlink(bar_linkname, nam_p)) >= 0) {
5621                                 cnt = 0;
5622                                 if (Over_p != NULL) {
5623                                         (void) unlinkat(dirfd,
5624                                             get_component(Over_p), 0);
5625                                         *Over_p = '\0';
5626                                 }
5627                                 break;
5628                         } else if (errno != ENOENT) {
5629                                 /* The attempt to symlink failed. */
5630                                 msg(ERRN,
5631                                     "Cannot create symbolic link \"%s\" -> "
5632                                     "\"%s\"",
5633                                     bar_linkname, nam_p);
5634                                 if (*Over_p != '\0') {
5635                                         rstfiles(U_KEEP, dirfd);
5636                                 }
5637                                 return (-1);
5638                         }
5639                 } else if ((G_p->g_mode & Ftype) == S_IFLNK) {
5640                         if ((!(Args & OCp)) && !(Hdr_type == USTAR)) {
5641                                 FILL(G_p->g_filesz);
5642                                 (void) strncpy(Symlnk_p,
5643                                     Buffr.b_out_p, G_p->g_filesz);
5644                                 *(Symlnk_p + G_p->g_filesz) = '\0';
5645                         } else if ((!(Args & OCp)) && (Hdr_type == USTAR)) {
5646                                 Symlnk_p[NAMSIZ] = '\0';
5647                                 (void) strncpy(Symlnk_p,
5648                                     &Thdr_p->tbuf.t_linkname[0], NAMSIZ);
5649                         }
5650                         if ((result = symlink(Symlnk_p, nam_p)) >= 0) {
5651                                 cnt = 0;
5652                                 if (Over_p != NULL) {
5653                                         (void) unlinkat(dirfd,
5654                                             get_component(Over_p), 0);
5655                                         *Over_p = '\0';
5656                                 }
5657                                 break;
5658                         } else if (errno != ENOENT) {
5659                                 /* The attempt to symlink failed. */
5660                                 msg(ERRN,
5661                                     "Cannot create symbolic link \"%s\" -> "
5662                                     "\"%s\"",
5663                                     Symlnk_p, nam_p);
5664 
5665                                 if (*Over_p != '\0') {
5666                                         rstfiles(U_KEEP, dirfd);
5667                                 }
5668                                 return (-1);
5669                         }
5670                 } else {
5671                         int     saveerrno;
5672 
5673                         if ((result = openat(dirfd, get_component(nam_p),
5674                             O_CREAT|O_RDWR|O_TRUNC, (int)G_p->g_mode)) < 0) {
5675                                 saveerrno = errno;
5676                                 if (G_p->g_attrnam_p != NULL)  {
5677                                         result = retry_open_attr(dirfd,
5678                                             Gen.g_baseparent_fd, Fullnam_p,
5679                                             (G_p->g_attrparent_p == NULL) ?
5680                                             NULL : G_p->g_attrparent_p, nam_p,
5681                                             O_CREAT|O_RDWR|O_TRUNC,
5682                                             (int)G_p->g_mode);
5683                                 }
5684                         }
5685                         if (result < 0) {
5686                                 errno = saveerrno;
5687                                 if (errno != ENOENT) {
5688                                         /* The attempt to open failed. */
5689                                         msg(ERRN, "Cannot open file \"%s\"",
5690                                             nam_p);
5691                                         if (*Over_p != '\0') {
5692                                                 rstfiles(U_KEEP, dirfd);
5693                                         }
5694                                         return (-1);
5695                                 }
5696                         } else {
5697                                 /* acl support */
5698                                 acl_is_set = 0;
5699                                 if (Pflag && aclp != NULL) {
5700                                         if (facl_set(result, aclp) < 0) {
5701                                                 msg(ERRN,
5702                                                     "\"%s\": failed to set acl",
5703                                                     nam_p);
5704                                         } else {
5705                                                 acl_is_set = 1;
5706                                         }
5707                                         acl_free(aclp);
5708                                         aclp = NULL;
5709                                 }
5710                                 cnt = 0;
5711                                 break;
5712                         }
5713                 }
5714                 cnt++;
5715         } while (cnt < 2 && missdir(nam_p) == 0);
5716 
5717         switch (cnt) {
5718         case 0:
5719                 if ((Args & OCi) && (Hdr_type == USTAR)) {
5720                         setpasswd(nam_p);
5721                 }
5722                 if ((G_p->g_mode & Ftype) == S_IFLNK ||
5723                     (Hdr_type == BAR && bar_linkflag == SYMTYPE)) {
5724                         if (Args & OCR) {
5725                                 if (fchownat(dirfd,
5726                                     get_component(nam_p),
5727                                     (int)Rpw_p->pw_uid,
5728                                     (int)Rpw_p->pw_gid,
5729                                     AT_SYMLINK_NOFOLLOW) < 0) {
5730                                         msg(ERRN,
5731                                             "Error during chown() of "
5732                                             "\"%s%s%s\"",
5733                                             (G_p->g_attrnam_p == NULL) ?
5734                                             nam_p : G_p->g_attrfnam_p,
5735                                             (G_p->g_attrnam_p == NULL) ?
5736                                             "" : G_p->g_rw_sysattr ?
5737                                             gettext(" System Attribute ") :
5738                                             gettext(" Attribute "),
5739                                             (G_p->g_attrnam_p == NULL) ?
5740                                             "" : nam_p);
5741                                 }
5742                         } else if ((fchownat(dirfd, get_component(nam_p),
5743                             (int)G_p->g_uid, (int)G_p->g_gid,
5744                             AT_SYMLINK_NOFOLLOW) < 0) && privileged) {
5745                                 msg(ERRN,
5746                                     "Error during chown() of \"%s%s%s\"",
5747                                     (G_p->g_attrnam_p == NULL) ?
5748                                     nam_p : G_p->g_attrfnam_p,
5749                                     (G_p->g_attrnam_p == NULL) ? "" :
5750                                     G_p->g_rw_sysattr ?
5751                                     gettext(" System Attribute ") :
5752                                     gettext(" Attribute "),
5753                                     (G_p->g_attrnam_p == NULL) ? "" : nam_p);
5754                         }
5755                 }
5756                 break;
5757 
5758         case 1:
5759                 if (Do_rename) {
5760                         msg(ERRN, "Cannot create directory for \"%s%s%s\"",
5761                             (G_p->g_attrnam_p == NULL) ? Over_p :
5762                             G_p->g_attrfnam_p,
5763                             (G_p->g_attrnam_p == NULL) ? "" :
5764                             G_p->g_rw_sysattr ?
5765                             gettext(" System Attribute ") :
5766                             gettext(" Attribute "),
5767                             (G_p->g_attrnam_p == NULL) ? "" : Over_p);
5768                 } else {
5769                         msg(ERRN, "Cannot create directory for \"%s%s%s\"",
5770                             (G_p->g_attrnam_p == NULL) ? nam_p :
5771                             G_p->g_attrfnam_p,
5772                             (G_p->g_attrnam_p == NULL) ? "" :
5773                             G_p->g_rw_sysattr ?
5774                             gettext(" System Attribute ") :
5775                             gettext(" Attribute "),
5776                             (G_p->g_attrnam_p == NULL) ? "" : nam_p);
5777                 }
5778                 break;
5779 
5780         case 2:
5781                 if (Do_rename) {
5782                         msg(ERRN, "Cannot create \"%s%s%s\"",
5783                             (G_p->g_attrnam_p == NULL) ? Over_p :
5784                             G_p->g_attrfnam_p,
5785                             (G_p->g_attrnam_p == NULL) ? "" :
5786                             G_p->g_rw_sysattr ?
5787                             gettext(" System Attribute ") :
5788                             gettext(" Attribute "),
5789                             (G_p->g_attrnam_p == NULL) ? "" :
5790                             Over_p);
5791                 } else {
5792                         msg(ERRN, "Cannot create \"%s%s%s\"",
5793                             (G_p->g_attrnam_p == NULL) ? nam_p :
5794                             G_p->g_attrfnam_p,
5795                             (G_p->g_attrnam_p == NULL) ? "" :
5796                             G_p->g_rw_sysattr ?
5797                             gettext(" System Attribute ") :
5798                             gettext(" Attribute "),
5799                             (G_p->g_attrnam_p == NULL) ? "" : nam_p);
5800                 }
5801                 break;
5802 
5803         default:
5804                 msg(EXT, "Impossible case.");
5805         }
5806 
5807         Finished = 0;
5808         return (result);
5809 }
5810 
5811 /*
5812  * read_hdr: Transfer headers from the selected format
5813  * in the archive I/O buffer to the generic structure.
5814  */
5815 
5816 static
5817 int
5818 read_hdr(int hdr)
5819 {
5820         int rv = NONE;
5821         major_t maj, rmaj;
5822         minor_t min, rmin;
5823         char tmpnull;
5824         static int bar_read_cnt = 0;
5825 
5826         if (hdr != BAR) {
5827                 if (Buffr.b_end_p != (Buffr.b_out_p + Hdrsz)) {
5828                         tmpnull = *(Buffr.b_out_p + Hdrsz);
5829                         *(Buffr.b_out_p + Hdrsz) = '\0';
5830                 }
5831         }
5832 
5833         switch (hdr) {
5834         case BIN:
5835                 (void) memcpy(&Hdr, Buffr.b_out_p, HDRSZ);
5836                 if (Hdr.h_magic == (short)CMN_BBS) {
5837                         swap((char *)&Hdr, HDRSZ);
5838                 }
5839                 Gen.g_magic = Hdr.h_magic;
5840                 Gen.g_mode = Hdr.h_mode;
5841                 Gen.g_uid = Hdr.h_uid;
5842                 Gen.g_gid = Hdr.h_gid;
5843                 Gen.g_nlink = Hdr.h_nlink;
5844                 Gen.g_mtime = mklong(Hdr.h_mtime);
5845                 Gen.g_ino = Hdr.h_ino;
5846                 Gen.g_dev = Hdr.h_dev;
5847                 Gen.g_rdev = Hdr.h_rdev;
5848                 Gen.g_cksum = 0L;
5849                 Gen.g_filesz = (off_t)mklong(Hdr.h_filesize);
5850                 Gen.g_namesz = Hdr.h_namesize;
5851                 rv = BIN;
5852                 break;
5853         case CHR:
5854                 if (sscanf(Buffr.b_out_p,
5855                     "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6o%11llo",
5856                     &Gen.g_magic, &Gen.g_dev, &Gen.g_ino, &Gen.g_mode,
5857                     &Gen.g_uid, &Gen.g_gid, &Gen.g_nlink, &Gen.g_rdev,
5858                     (ulong_t *)&Gen.g_mtime, (uint_t *)&Gen.g_namesz,
5859                     (u_off_t *)&Gen.g_filesz) == CHR_CNT) {
5860                         rv = CHR;
5861 #define cpioMAJOR(x)    (int)(((unsigned)x >> 8) & 0x7F)
5862 #define cpioMINOR(x)    (int)(x & 0xFF)
5863                         maj = cpioMAJOR(Gen.g_dev);
5864                         rmaj = cpioMAJOR(Gen.g_rdev);
5865                         min = cpioMINOR(Gen.g_dev);
5866                         rmin = cpioMINOR(Gen.g_rdev);
5867                         if (Use_old_stat) {
5868                                 /* needs error checking */
5869                                 Gen.g_dev = (maj << 8) | min;
5870                                 Gen.g_rdev = (rmaj << 8) | rmin;
5871                         } else {
5872                                 Gen.g_dev = makedev(maj, min);
5873                                 Gen.g_rdev = makedev(rmaj, rmin);
5874                         }
5875                 }
5876                 break;
5877         case ASC:
5878         case CRC:
5879                 if (sscanf(Buffr.b_out_p,
5880                     "%6lx%8lx%8lx%8lx%8lx%8lx%8lx%8llx%8x%8x%8x%8x%8x%8lx",
5881                     &Gen.g_magic, &Gen.g_ino, &Gen.g_mode, &Gen.g_uid,
5882                     &Gen.g_gid, &Gen.g_nlink, &Gen.g_mtime,
5883                     (u_off_t *)&Gen.g_filesz, (uint_t *)&maj, (uint_t *)&min,
5884                     (uint_t *)&rmaj, (uint_t *)&rmin, (uint_t *)&Gen.g_namesz,
5885                     &Gen.g_cksum) == ASC_CNT) {
5886                         Gen.g_dev = makedev(maj, min);
5887                         Gen.g_rdev = makedev(rmaj, rmin);
5888                         rv = hdr;
5889                 }
5890                 break;
5891         case USTAR: /* TAR and USTAR */
5892                 if (*Buffr.b_out_p == '\0') {
5893                         *Gen.g_nam_p = '\0';
5894                         nambuf[0] = '\0';
5895                 } else {
5896                         Thdr_p = (union tblock *)Buffr.b_out_p;
5897                         Gen.g_nam_p[0] = '\0';
5898                         (void) strncpy((char *)&nambuf,
5899                             Thdr_p->tbuf.t_name, NAMSIZ);
5900                         (void) sscanf(Thdr_p->tbuf.t_mode, "%8lo",
5901                             &Gen.g_mode);
5902                         (void) sscanf(Thdr_p->tbuf.t_uid, "%8lo", &Gen.g_uid);
5903                         (void) sscanf(Thdr_p->tbuf.t_gid, "%8lo", &Gen.g_gid);
5904                         (void) sscanf(Thdr_p->tbuf.t_size, "%11llo",
5905                             (u_off_t *)&Gen.g_filesz);
5906                         (void) sscanf(Thdr_p->tbuf.t_mtime, "%12lo",
5907                             (ulong_t *)&Gen.g_mtime);
5908                         (void) sscanf(Thdr_p->tbuf.t_cksum, "%8lo",
5909                             (ulong_t *)&Gen.g_cksum);
5910                         if (Thdr_p->tbuf.t_linkname[0] != '\0')
5911                                 Gen.g_nlink = 1;
5912                         else
5913                                 Gen.g_nlink = 0;
5914 
5915                         switch (Thdr_p->tbuf.t_typeflag) {
5916                         case SYMTYPE:
5917                                 /* Symbolic Link */
5918                                 Gen.g_nlink = 2;
5919                                 break;
5920                         case CHRTYPE:
5921                                 Gen.g_mode |= (S_IFMT & S_IFCHR);
5922                                 break;
5923                         case BLKTYPE:
5924                                 Gen.g_mode |= (S_IFMT & S_IFBLK);
5925                                 break;
5926                         case DIRTYPE:
5927                                 Gen.g_mode |= (S_IFMT & S_IFDIR);
5928                                 break;
5929                         case FIFOTYPE:
5930                                 Gen.g_mode |= (S_IFMT & S_IFIFO);
5931                                 break;
5932                         }
5933 
5934                         (void) sscanf(Thdr_p->tbuf.t_magic, "%8lo",
5935                             /* LINTED alignment */
5936                             (ulong_t *)&Gen.g_tmagic);
5937                         (void) sscanf(Thdr_p->tbuf.t_version, "%8lo",
5938                             /* LINTED alignment */
5939                             (ulong_t *)&Gen.g_version);
5940                         (void) sscanf(Thdr_p->tbuf.t_uname, "%32s",
5941                             (char *)&Gen.g_uname);
5942                         (void) sscanf(Thdr_p->tbuf.t_gname, "%32s",
5943                             (char *)&Gen.g_gname);
5944                         (void) sscanf(Thdr_p->tbuf.t_devmajor, "%8lo",
5945                             &Gen.g_dev);
5946                         (void) sscanf(Thdr_p->tbuf.t_devminor, "%8lo",
5947                             &Gen.g_rdev);
5948                         (void) strncpy((char *)&prebuf,
5949                             Thdr_p->tbuf.t_prefix, PRESIZ);
5950                         Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
5951                         Gen.g_dev = makedev(maj, min);
5952                 }
5953                 rv = USTAR;
5954                 break;
5955         case TAR:
5956                 if (*Buffr.b_out_p == '\0') {
5957                         *Gen.g_nam_p = '\0';
5958                         nambuf[0] = '\0';
5959                 } else {
5960                         Thdr_p = (union tblock *)Buffr.b_out_p;
5961                         Gen.g_nam_p[0] = '\0';
5962                         (void) sscanf(Thdr_p->tbuf.t_mode, "%lo", &Gen.g_mode);
5963                         (void) sscanf(Thdr_p->tbuf.t_uid, "%lo", &Gen.g_uid);
5964                         (void) sscanf(Thdr_p->tbuf.t_gid, "%lo", &Gen.g_gid);
5965                         (void) sscanf(Thdr_p->tbuf.t_size, "%llo",
5966                             (u_off_t *)&Gen.g_filesz);
5967                         (void) sscanf(Thdr_p->tbuf.t_mtime, "%lo",
5968                             &Gen.g_mtime);
5969                         (void) sscanf(Thdr_p->tbuf.t_cksum, "%lo",
5970                             &Gen.g_cksum);
5971                         if (Thdr_p->tbuf.t_typeflag == '1')  /* hardlink */
5972                                 Gen.g_nlink = 1;
5973                         else
5974                                 Gen.g_nlink = 0;
5975                         (void) strncpy(Gen.g_nam_p,
5976                             Thdr_p->tbuf.t_name, NAMSIZ);
5977                         Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
5978                         (void) strcpy(nambuf, Gen.g_nam_p);
5979                 }
5980                 rv = TAR;
5981                 break;
5982         case BAR:
5983                 if (Bar_vol_num == 0 && bar_read_cnt == 0) {
5984                         read_bar_vol_hdr();
5985                         bar_read_cnt++;
5986                 }
5987                 else
5988                         read_bar_file_hdr();
5989                 rv = BAR;
5990                 break;
5991         default:
5992                 msg(EXT, "Impossible header type.");
5993         }
5994 
5995         if (hdr != BAR) {
5996                 if (Buffr.b_end_p != (Buffr.b_out_p + Hdrsz))
5997                         *(Buffr.b_out_p + Hdrsz) = tmpnull;
5998         }
5999 
6000         return (rv);
6001 }
6002 
6003 /*
6004  * reclaim: Reclaim linked file structure storage.
6005  */
6006 
6007 static void
6008 reclaim(struct Lnk *p)
6009 {
6010         p->L_bck_p->L_nxt_p = p->L_nxt_p;
6011         p->L_nxt_p->L_bck_p = p->L_bck_p;
6012 
6013         while (p != NULL) {
6014                 struct Lnk *new_p = p->L_lnk_p;
6015 
6016                 free(p->L_gen.g_nam_p);
6017                 free(p);
6018                 p = new_p;
6019         }
6020 }
6021 
6022 /*
6023  * rstbuf: Reset the I/O buffer, move incomplete potential headers to
6024  * the front of the buffer and force bread() to refill the buffer.  The
6025  * return value from bread() is returned (to identify I/O errors).  On the
6026  * 3B2, reads must begin on a word boundary, therefore, with the -i option,
6027  * any remaining bytes in the buffer must be moved to the base of the buffer
6028  * in such a way that the destination locations of subsequent reads are
6029  * word aligned.
6030  */
6031 
6032 static void
6033 rstbuf(void)
6034 {
6035         int pad;
6036 
6037         if ((Args & OCi) || Append) {
6038                 if (Buffr.b_out_p != Buffr.b_base_p) {
6039                         pad = ((Buffr.b_cnt + FULLWD) & ~FULLWD);
6040                         Buffr.b_in_p = Buffr.b_base_p + pad;
6041                         pad -= Buffr.b_cnt;
6042                         (void) memcpy(Buffr.b_base_p + pad, Buffr.b_out_p,
6043                             (int)Buffr.b_cnt);
6044                         Buffr.b_out_p = Buffr.b_base_p + pad;
6045                 }
6046                 if (bfill() < 0)
6047                         msg(EXT, "Unexpected end-of-archive encountered.");
6048         } else { /* OCo */
6049                 (void) memcpy(Buffr.b_base_p, Buffr.b_out_p, (int)Buffr.b_cnt);
6050                 Buffr.b_out_p = Buffr.b_base_p;
6051                 Buffr.b_in_p = Buffr.b_base_p + Buffr.b_cnt;
6052         }
6053 }
6054 
6055 static void
6056 setpasswd(char *nam)
6057 {
6058         if ((dpasswd = getpwnam(&Gen.g_uname[0])) == NULL) {
6059                 msg(EPOST, "cpio: problem reading passwd entry");
6060                 msg(EPOST, "cpio: %s: owner not changed", nam);
6061                 if (Gen.g_uid == UID_NOBODY && S_ISREG(Gen.g_mode))
6062                         Gen.g_mode &= ~S_ISUID;
6063         } else
6064                 Gen.g_uid = dpasswd->pw_uid;
6065 
6066         if ((dgroup = getgrnam(&Gen.g_gname[0])) == NULL) {
6067                 msg(EPOST, "cpio: problem reading group entry");
6068                 msg(EPOST, "cpio: %s: group not changed", nam);
6069                 if (Gen.g_gid == GID_NOBODY && S_ISREG(Gen.g_mode))
6070                         Gen.g_mode &= ~S_ISGID;
6071         } else
6072                 Gen.g_gid = dgroup->gr_gid;
6073         G_p = &Gen;
6074 }
6075 
6076 /*
6077  * rstfiles:  Perform final changes to the file.  If the -u option is set,
6078  * and overwrite == U_OVER, remove the temporary file, else if overwrite
6079  * == U_KEEP, unlink the current file, and restore the existing version
6080  * of the file.  In addition, where appropriate, set the access or modification
6081  * times, change the owner and change the modes of the file.
6082  *
6083  * Note that if Do_rename is set, then the roles of original and temporary
6084  * file are reversed. If all went well, we will rename() the temporary file
6085  * over the original in order to accommodate potentially executing files.
6086  */
6087 static void
6088 rstfiles(int over, int dirfd)
6089 {
6090         char *inam_p, *onam_p, *nam_p;
6091         int error;
6092 
6093 #if defined(_PC_SATTR_ENABLED)
6094         /* Time or permissions cannot be set on system attribute files */
6095         if ((Gen.g_attrnam_p != NULL) && (Gen.g_rw_sysattr == 1)) {
6096                 return;
6097         }
6098 #endif  /* _PC_SATTR_ENABLED */
6099 
6100         if (Args & OCp) {
6101                 if (G_p->g_attrnam_p == NULL) {
6102                         nam_p = Fullnam_p;
6103                 } else {
6104                         nam_p = G_p->g_attrnam_p;
6105                 }
6106         } else {
6107                 if (Gen.g_nlink > (ulong_t)0) {
6108                         nam_p = G_p->g_nam_p;
6109                 } else {
6110                         nam_p = Gen.g_nam_p;
6111                 }
6112         }
6113         if (Gen.g_attrnam_p != NULL) {
6114                 nam_p = Gen.g_attrnam_p;
6115         }
6116 
6117         if ((Args & OCi) && (Hdr_type == USTAR)) {
6118                 setpasswd(nam_p);
6119         }
6120         if (over == U_KEEP && *Over_p != '\0') {
6121                 if (Do_rename) {
6122                         msg(POST, "Restoring existing \"%s%s%s\"",
6123                             (G_p->g_attrnam_p == NULL) ? Over_p : Fullnam_p,
6124                             (G_p->g_attrnam_p == NULL) ? "" :
6125                             G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6126                             gettext(" Attribute "),
6127                             (G_p->g_attrnam_p == NULL) ? "" : Over_p);
6128                 } else {
6129                         msg(POST, "Restoring existing \"%s%s%s\"",
6130                             (G_p->g_attrnam_p == NULL) ? nam_p : Fullnam_p,
6131                             (G_p->g_attrnam_p == NULL) ? "" :
6132                             G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6133                             gettext(" Attribute "),
6134                             (G_p->g_attrnam_p == NULL) ? "" : nam_p);
6135                 }
6136 
6137                 /* delete what we just built */
6138                 (void) unlinkat(dirfd, get_component(nam_p), 0);
6139 
6140                 /* If the old file needs restoring, do the necessary links */
6141                 if (Do_rename) {
6142                         char *tmp_ptr;
6143 
6144                         if (Args & OCp) {
6145                                 tmp_ptr = Fullnam_p;
6146                                 Fullnam_p = Over_p;
6147                         } else {
6148                                 tmp_ptr = G_p->g_nam_p;
6149                                 G_p->g_nam_p = Over_p;
6150                         }
6151                         Over_p = tmp_ptr;
6152 
6153                         Do_rename = 0;  /* names now have original values */
6154                 } else {
6155                         if (rename(Over_p, nam_p) < 0) {
6156                                 if (link(Over_p, nam_p) < 0) {
6157                                         msg(EXTN,
6158                                             "Cannot recover original version"
6159                                             " of \"%s%s%s\"",
6160                                             (G_p->g_attrnam_p == NULL) ?
6161                                             nam_p : Fullnam_p,
6162                                             (G_p->g_attrnam_p == NULL) ? "" :
6163                                             G_p->g_rw_sysattr ?
6164                                             gettext(" System Attribute ") :
6165                                             gettext(" Attribute "),
6166                                             (G_p->g_attrnam_p == NULL) ?
6167                                             "" : nam_p);
6168                                 }
6169                                 if (unlinkat(dirfd, get_component(Over_p), 0)) {
6170                                         msg(ERRN,
6171                                             "Cannot remove temp file "
6172                                             "\"%s%s%s\"",
6173                                             (G_p->g_attrnam_p == NULL) ?
6174                                             Over_p : Fullnam_p,
6175                                             (G_p->g_attrnam_p == NULL) ? "" :
6176                                             G_p->g_rw_sysattr ?
6177                                             gettext(" System Attribute ") :
6178                                             gettext(" Attribute "),
6179                                             (G_p->g_attrnam_p == NULL) ?
6180                                             "" : Over_p);
6181                                 }
6182                         }
6183                 }
6184                 *Over_p = '\0';
6185                 return;
6186         } else if (over == U_OVER && *Over_p != '\0') {
6187                 if (Do_rename) {
6188                         char *tmp_ptr;
6189 
6190                         (void) renameat(dirfd, get_component(nam_p),
6191                             dirfd, get_component(Over_p));
6192                         if (Args & OCp) {
6193                                 if (G_p->g_attrnam_p == NULL) {
6194                                         tmp_ptr = Fullnam_p;
6195                                         Fullnam_p = Over_p;
6196                                         Over_p = tmp_ptr;
6197                                 } else {
6198                                         /*
6199                                          * Over_p is pointing at g_attrnam_p
6200                                          * which must be preserved.
6201                                          *
6202                                          * We don't want the tmp_ptr and so
6203                                          * on to throw away our only copy of
6204                                          * the name.
6205                                          */
6206                                         Over_p = Attrfile_p;
6207                                 }
6208                         } else {
6209                                 tmp_ptr = G_p->g_nam_p;
6210                                 G_p->g_nam_p = Over_p;
6211                                 Over_p = tmp_ptr;
6212                         }
6213                         Do_rename = 0;  /* names now have original values */
6214                 } else {
6215                         if (unlinkat(dirfd, get_component(Over_p), 0) < 0) {
6216                                 msg(ERRN,
6217                                     "Cannot unlink() temp file \"%s%s%s\"",
6218                                     (G_p->g_attrnam_p == NULL) ?
6219                                     Over_p : Fullnam_p,
6220                                     (G_p->g_attrnam_p == NULL) ? "" :
6221                                     G_p->g_rw_sysattr ?
6222                                     gettext(" System Attribute ") :
6223                                     gettext(" Attribute "),
6224                                     (G_p->g_attrnam_p == NULL) ? "" : Over_p);
6225                         }
6226                 }
6227                 *Over_p = '\0';
6228         }
6229         if (Args & OCp) {
6230                 if (G_p->g_attrnam_p != NULL) {
6231                         inam_p = G_p->g_attrfnam_p;
6232                         onam_p = G_p->g_attrnam_p;
6233                 } else {
6234                         inam_p = Nam_p;
6235                         onam_p = Fullnam_p;
6236                 }
6237         } else /* OCi only uses onam_p, OCo only uses inam_p */
6238                 if (G_p->g_attrnam_p != NULL) {
6239                         inam_p = onam_p = G_p->g_attrnam_p;
6240                 } else {
6241                         inam_p = onam_p = G_p->g_nam_p;
6242                 }
6243 
6244         /*
6245          * Change the owner, time, and mode to those of the file
6246          * originally created in the archive.  Note: time and
6247          * mode do not need to be restored for a symbolic link
6248          * since rstfiles() is not called when the archived file
6249          * is a symlink.
6250          */
6251         if (!(Args & OCo)) {
6252                 if (Args & OCR) {
6253                         if (fchownat(dirfd, get_component(onam_p),
6254                             Rpw_p->pw_uid, Rpw_p->pw_gid,
6255                             AT_SYMLINK_NOFOLLOW) < 0) {
6256                                 msg(ERRN, "Cannot chown() \"%s%s%s\"",
6257                                     onam_p,
6258                                     (G_p->g_attrnam_p == NULL) ? "" :
6259                                     G_p->g_rw_sysattr ?
6260                                     gettext(" System Attribute ") :
6261                                     gettext(" Attribute "),
6262                                     (G_p->g_attrnam_p == NULL) ? "" : onam_p);
6263                         }
6264                 } else {
6265                         if ((fchownat(dirfd, get_component(onam_p),
6266                             G_p->g_uid, G_p->g_gid,
6267                             AT_SYMLINK_NOFOLLOW) < 0) && privileged) {
6268                                 msg(ERRN, "Cannot chown() \"%s%s%s\"",
6269                                     onam_p,
6270                                     (G_p->g_attrnam_p == NULL) ? "" :
6271                                     G_p->g_rw_sysattr ?
6272                                     gettext(" System Attribute ") :
6273                                     gettext(" Attribute "),
6274                                     (G_p->g_attrnam_p == NULL) ? "" : onam_p);
6275                         }
6276                 }
6277 
6278                 if (Args & OCm) {
6279                         set_tym(dirfd, get_component(onam_p),
6280                             G_p->g_mtime, G_p->g_mtime);
6281                 }
6282 
6283                 /* Acl was not set, so we must chmod */
6284                 if (!acl_is_set) {
6285                         mode_t orig_mask, new_mask;
6286 
6287                         /*
6288                          * use fchmod for attributes, since
6289                          * we known they are always regular
6290                          * files, whereas when it isn't an
6291                          * attribute it could be for a fifo
6292                          * or something other that we don't
6293                          * open and don't have a valid Ofile
6294                          * for.
6295                          */
6296                         if (privileged) {
6297                                 new_mask = G_p->g_mode;
6298                         } else {
6299                                 orig_mask = umask(0);
6300                                 new_mask = G_p->g_mode & ~orig_mask;
6301                         }
6302 
6303                         if (G_p->g_attrnam_p != NULL) {
6304                                 error = fchmod(Ofile, new_mask);
6305                         } else {
6306                                 error = chmod(onam_p, new_mask);
6307                         }
6308                         if (error < 0) {
6309                                 msg(ERRN,
6310                                     "Cannot chmod() \"%s%s%s\"",
6311                                     (G_p->g_attrnam_p == NULL) ?
6312                                     onam_p : G_p->g_attrfnam_p,
6313                                     (G_p->g_attrnam_p == NULL) ? "" :
6314                                     G_p->g_rw_sysattr ?
6315                                     gettext(" System Attribute ") :
6316                                     gettext(" Attribute "),
6317                                     (G_p->g_attrnam_p == NULL) ? "" : onam_p);
6318                         }
6319                         if (!privileged) {
6320                                 (void) umask(orig_mask);
6321                         }
6322                 }
6323         }
6324 
6325         if (!(Args & OCi) && (Args & OCa)) {
6326                 /*
6327                  * Use dirfd since we are updating original file
6328                  * and not just created file
6329                  */
6330                 set_tym(G_p->g_dirfd, get_component(inam_p),
6331                     (ulong_t)SrcSt.st_atime, (ulong_t)SrcSt.st_mtime);
6332         }
6333 }
6334 
6335 /*
6336  * scan4trail: Scan the archive looking for the trailer.
6337  * When found, back the archive up over the trailer and overwrite
6338  * the trailer with the files to be added to the archive.
6339  */
6340 
6341 static void
6342 scan4trail(void)
6343 {
6344         int rv;
6345         off_t off1, off2;
6346 
6347         Append = 1;
6348         Hdr_type = NONE;
6349         G_p = NULL;
6350         while (gethdr()) {
6351                 G_p = &Gen;
6352                 data_in(P_SKIP);
6353         }
6354         off1 = Buffr.b_cnt;
6355         off2 = Bufsize - (Buffr.b_cnt % Bufsize);
6356         Buffr.b_out_p = Buffr.b_in_p = Buffr.b_base_p;
6357         Buffr.b_cnt = (off_t)0;
6358         if (lseek(Archive, -(off1 + off2), SEEK_REL) < 0)
6359                 msg(EXTN, "Unable to append to this archive");
6360         if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0)
6361                 msg(EXTN, "Cannot append to this archive");
6362         if (lseek(Archive, (off_t)-rv, SEEK_REL) < 0)
6363                 msg(EXTN, "Unable to append to this archive");
6364         Buffr.b_cnt = off2;
6365         Buffr.b_in_p = Buffr.b_base_p + Buffr.b_cnt;
6366         Append = 0;
6367 }
6368 
6369 /*
6370  * setup:  Perform setup and initialization functions.  Parse the options
6371  * using getopt(3C), call ckopts to check the options and initialize various
6372  * structures and pointers.  Specifically, for the -i option, save any
6373  * patterns, for the -o option, check (via stat(2)) the archive, and for
6374  * the -p option, validate the destination directory.
6375  */
6376 
6377 static void
6378 setup(int largc, char **largv)
6379 {
6380         extern int optind;
6381         extern char *optarg;
6382 
6383 #if defined(O_XATTR)
6384 #if defined(_PC_SATTR_ENABLED)
6385 #ifdef WAITAROUND
6386         char    *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
6387 #else
6388         char    *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
6389 #endif  /* WAITAROUND */
6390 
6391 #else   /* _PC_SATTR_ENABLED */
6392 #ifdef WAITAROUND
6393         char    *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
6394 #else
6395         char    *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
6396 #endif  /* WAITAROUND */
6397 #endif  /* _PC_SATTR_ENABLED */
6398 
6399 #else   /* O_XATTR */
6400 #ifdef WAITAROUND
6401         char    *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
6402 #else
6403         char    *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
6404 #endif  /* WAITAROUND */
6405 #endif  /* O_XATTR */
6406 
6407         char   *dupl_p = "Only one occurrence of -%c allowed";
6408         int option;
6409         int blk_cnt, blk_cnt_max;
6410         struct rlimit rlim;
6411 
6412         /* Remember the native page size. */
6413 
6414         PageSize = sysconf(_SC_PAGESIZE);
6415 
6416         if (PageSize == -1) {
6417                 /*
6418                  * This sysconf call will almost certainly never fail.  The
6419                  * symbol PAGESIZE itself resolves to the above sysconf call,
6420                  * so we should go ahead and define our own constant.
6421                  */
6422                 PageSize = 8192;
6423         }
6424 
6425         Hdr_type = BIN;
6426         Max_offset = (off_t)(BIN_OFFSET_MAX);
6427         Efil_p = Hdr_p = Own_p = IOfil_p = NULL;
6428         while ((option = getopt(largc, largv, opts_p)) != EOF) {
6429                 switch (option) {
6430 #ifdef WAITAROUND
6431                 case 'z':
6432                         /* rendezvous with the debugger */
6433                         waitaround = 1;
6434                         break;
6435 #endif
6436                 case 'a':       /* reset access time */
6437                         Args |= OCa;
6438                         break;
6439                 case 'b':       /* swap bytes and halfwords */
6440                         Args |= OCb;
6441                         break;
6442                 case 'c':       /* select character header */
6443                         Args |= OCc;
6444                         Hdr_type = ASC;
6445                         Max_namesz = APATH;
6446                         Onecopy = 1;
6447                         break;
6448                 case 'd':       /* create directories as needed */
6449                         Args |= OCd;
6450                         break;
6451                 case 'f':       /* select files not in patterns */
6452                         Args |= OCf;
6453                         break;
6454                 case 'i':       /* "copy in" */
6455                         Args |= OCi;
6456                         Archive = 0;
6457                         break;
6458                 case 'k':       /* retry after I/O errors */
6459                         Args |= OCk;
6460                         break;
6461                 case 'l':       /* link files when possible */
6462                         Args |= OCl;
6463                         break;
6464                 case 'm':       /* retain modification time */
6465                         Args |= OCm;
6466                         break;
6467                 case 'o':       /* "copy out" */
6468                         Args |= OCo;
6469                         Archive = 1;
6470                         break;
6471                 case 'p':       /* "pass" */
6472                         Max_namesz = APATH;
6473                         Args |= OCp;
6474                         break;
6475                 case 'q':       /* "quiet" */
6476                         Args |= OCq;
6477                         break;
6478                 case 'r':       /* rename files interactively */
6479                         Args |= OCr;
6480                         break;
6481                 case 's':       /* swap bytes */
6482                         Args |= OCs;
6483                         break;
6484                 case 't':       /* table of contents */
6485                         Args |= OCt;
6486                         break;
6487                 case 'u':       /* copy unconditionally */
6488                         Args |= OCu;
6489                         break;
6490                 case 'v':       /* verbose - print file names */
6491                         Args |= OCv;
6492                         break;
6493                 case 'A':       /* append to existing archive */
6494                         Args |= OCA;
6495                         break;
6496                 case 'B':       /* set block size to 5120 bytes */
6497                         Args |= OCB;
6498                         Bufsize = 5120;
6499                         break;
6500                 case 'C':       /* set arbitrary block size */
6501                         if (Args & OCC)
6502                                 msg(ERR, dupl_p, 'C');
6503                         else {
6504                                 Args |= OCC;
6505                                 Bufsize = atoi(optarg);
6506                         }
6507                         break;
6508                 case 'D':
6509                         Dflag = 1;
6510                         break;
6511                 case 'E':       /* alternate file for pattern input */
6512                         if (Args & OCE)
6513                                 msg(ERR, dupl_p, 'E');
6514                         else {
6515                                 Args |= OCE;
6516                                 Efil_p = optarg;
6517                         }
6518                         break;
6519                 case 'H':       /* select header type */
6520                         if (Args & OCH)
6521                                 msg(ERR, dupl_p, 'H');
6522                         else {
6523                                 Args |= OCH;
6524                                 Hdr_p = optarg;
6525                         }
6526                         break;
6527                 case 'I':       /* alternate file for archive input */
6528                         if (Args & OCI)
6529                                 msg(ERR, dupl_p, 'I');
6530                         else {
6531                                 Args |= OCI;
6532                                 IOfil_p = optarg;
6533                         }
6534                         break;
6535                 case 'L':       /* follow symbolic links */
6536                         Args |= OCL;
6537                         break;
6538                 case 'M':       /* specify new end-of-media message */
6539                         if (Args & OCM)
6540                                 msg(ERR, dupl_p, 'M');
6541                         else {
6542                                 Args |= OCM;
6543                                 Eom_p = optarg;
6544                         }
6545                         break;
6546                 case 'O':       /* alternate file for archive output */
6547                         if (Args & OCO)
6548                                 msg(ERR, dupl_p, 'O');
6549                         else {
6550                                 Args |= OCO;
6551                                 IOfil_p = optarg;
6552                         }
6553                         break;
6554                 case 'P':       /* preserve acls */
6555                         Args |= OCP;
6556                         Pflag++;
6557                         break;
6558                 case 'R':       /* change owner/group of files */
6559                         if (Args & OCR)
6560                                 msg(ERR, dupl_p, 'R');
6561                         else {
6562                                 Args |= OCR;
6563                                 Own_p = optarg;
6564                         }
6565                         break;
6566                 case 'S':       /* swap halfwords */
6567                         Args |= OCS;
6568                         break;
6569                 case 'V':       /* print a dot '.' for each file */
6570                         Args |= OCV;
6571                         break;
6572                 case '6':       /* for old, sixth-edition files */
6573                         Args |= OC6;
6574                         Ftype = SIXTH;
6575                         break;
6576 #if defined(O_XATTR)
6577                 case '@':
6578                         Atflag++;
6579                         break;
6580 #if defined(_PC_SATTR_ENABLED)
6581                 case '/':
6582                         SysAtflag++;
6583                         break;
6584 #endif  /* _PC_SATTR_ENABLED */
6585 #endif  /* O_XATTR */
6586                 default:
6587                         Error_cnt++;
6588                 } /* option */
6589         } /* (option = getopt(largc, largv, opts_p)) != EOF */
6590 
6591 #ifdef WAITAROUND
6592         if (waitaround) {
6593                 (void) fprintf(stderr, gettext("Rendezvous with cpio on pid"
6594                     " %d\n"), getpid());
6595 
6596                 while (waitaround) {
6597                         (void) sleep(10);
6598                 }
6599         }
6600 #endif
6601 
6602         largc -= optind;
6603         largv += optind;
6604         ckopts(Args);
6605         if (!Error_cnt) {
6606                 if (Args & OCr) {
6607                         Renam_p = e_zalloc(E_EXIT, APATH + 1);
6608                         Renametmp_p = e_zalloc(E_EXIT, APATH + 1);
6609 #if defined(_PC_SATTR_ENABLED)
6610                         Renam_attr_p = e_zalloc(E_EXIT, APATH + 1);
6611 #endif
6612                 }
6613                 Symlnk_p = e_zalloc(E_EXIT, APATH);
6614                 Over_p = e_zalloc(E_EXIT, APATH);
6615                 Nam_p = e_zalloc(E_EXIT, APATH + 1);
6616                 if (Args & OCp) {
6617                         Savenam_p = e_zalloc(E_EXIT, APATH + 1);
6618                 }
6619                 Fullnam_p = e_zalloc(E_EXIT, APATH);
6620                 Lnknam_p = e_zalloc(E_EXIT, APATH);
6621                 Gen.g_nam_p = Nam_p;
6622                 if ((Fullnam_p = getcwd(NULL, APATH)) == NULL)
6623                         msg(EXT, "Unable to determine current directory.");
6624                 if (Args & OCi) {
6625                         if (largc > 0) /* save patterns for -i option, if any */
6626                                 Pat_pp = largv;
6627                         if (Args & OCE)
6628                                 getpats(largc, largv);
6629                 } else if (Args & OCo) {
6630                         if (largc != 0) /* error if arguments left with -o */
6631                                 Error_cnt++;
6632                         else if (fstat(Archive, &ArchSt) < 0)
6633                                 msg(ERRN, "Error during stat() of archive");
6634                         switch (Hdr_type) {
6635                         case BIN:
6636                                 Hdrsz = HDRSZ;
6637                                 Pad_val = HALFWD;
6638                                 break;
6639                         case CHR:
6640                                 Hdrsz = CHRSZ;
6641                                 Pad_val = 0;
6642                                 Max_offset = (off_t)(CHAR_OFFSET_MAX);
6643                                 break;
6644                         case ASC:
6645                         case CRC:
6646                                 Hdrsz = ASCSZ;
6647                                 Pad_val = FULLWD;
6648                                 Max_offset = (off_t)(ASC_OFFSET_MAX);
6649                                 break;
6650                         case TAR:
6651                         /* FALLTHROUGH */
6652                         case USTAR: /* TAR and USTAR */
6653                                 Hdrsz = TARSZ;
6654                                 Pad_val = FULLBK;
6655                                 Max_offset = (off_t)(CHAR_OFFSET_MAX);
6656                                 break;
6657                         default:
6658                                 msg(EXT, "Impossible header type.");
6659                         }
6660                 } else { /* directory must be specified */
6661                         if (largc != 1)
6662                                 Error_cnt++;
6663                         else if (access(*largv, 2) < 0 && (errno != EACCES))
6664                                 /*
6665                                  * EACCES is ignored here as it may occur
6666                                  * when any directory component of the path
6667                                  * does not have write permission, even though
6668                                  * the destination subdirectory has write
6669                                  * access. Writing to a read only directory
6670                                  * is handled later, as in "copy in" mode.
6671                                  */
6672                                 msg(ERRN,
6673                                     "Error during access() of \"%s\"", *largv);
6674                 }
6675         }
6676         if (Error_cnt)
6677                 usage(); /* exits! */
6678         if (Args & (OCi | OCo)) {
6679                 if (!Dflag) {
6680                         if (Args & (OCB | OCC)) {
6681                                 if (g_init(&Device, &Archive) < 0)
6682                                         msg(EXTN,
6683                                             "Error during initialization");
6684                         } else {
6685                                 if ((Bufsize = g_init(&Device, &Archive)) < 0)
6686                                         msg(EXTN,
6687                                             "Error during initialization");
6688                         }
6689                 }
6690 
6691                 blk_cnt_max = _20K / Bufsize;
6692                 if (blk_cnt_max < MX_BUFS) {
6693                         blk_cnt_max = MX_BUFS;
6694                 }
6695 
6696                 Buffr.b_base_p = NULL;
6697 
6698                 for (blk_cnt = blk_cnt_max; blk_cnt > 1; blk_cnt--) {
6699                         Buffr.b_size = (size_t)(Bufsize * blk_cnt);
6700                         Buffr.b_base_p = e_valloc(E_NORMAL, Buffr.b_size);
6701                         if (Buffr.b_base_p != NULL) {
6702                                 break;
6703                         }
6704                 }
6705                 if (Buffr.b_base_p == NULL || Buffr.b_size < (2 * CPIOBSZ)) {
6706                         msg(EXT, "Out of memory");
6707                 }
6708 
6709                 Buffr.b_out_p = Buffr.b_in_p = Buffr.b_base_p;
6710                 Buffr.b_cnt = 0L;
6711                 Buffr.b_end_p = Buffr.b_base_p + Buffr.b_size;
6712         }
6713 
6714         /*
6715          * Now that Bufsize has stabilized, we can allocate our i/o buffer
6716          */
6717         Buf_p = e_valloc(E_EXIT, Bufsize);
6718 
6719         if (Args & OCp) { /* get destination directory */
6720                 (void) strcpy(Fullnam_p, *largv);
6721                 if (stat(Fullnam_p, &DesSt) < 0)
6722                         msg(EXTN, "Error during stat() of \"%s\"", Fullnam_p);
6723                 if ((DesSt.st_mode & Ftype) != S_IFDIR)
6724                         msg(EXT, "\"%s\" is not a directory", Fullnam_p);
6725         }
6726         Full_p = Fullnam_p + strlen(Fullnam_p) - 1;
6727         if (*Full_p != '/') {
6728                 Full_p++;
6729                 *Full_p = '/';
6730         }
6731         Full_p++;
6732         *Full_p = '\0';
6733         (void) strcpy(Lnknam_p, Fullnam_p);
6734         Lnkend_p = Lnknam_p + strlen(Lnknam_p);
6735         (void) getrlimit(RLIMIT_FSIZE, &rlim);
6736         Max_filesz = (off_t)rlim.rlim_cur;
6737         Lnk_hd.L_nxt_p = Lnk_hd.L_bck_p = &Lnk_hd;
6738         Lnk_hd.L_lnk_p = NULL;
6739 }
6740 
6741 /*
6742  * set_tym: Set the access and/or modification times for a file.
6743  */
6744 
6745 static void
6746 set_tym(int dirfd, char *nam_p, time_t atime, time_t mtime)
6747 {
6748         struct timeval times[2];
6749 
6750         times[0].tv_sec = atime;
6751         times[0].tv_usec = 0;
6752         times[1].tv_sec = mtime;
6753         times[1].tv_usec = 0;
6754 
6755         if (futimesat(dirfd, nam_p, times) < 0) {
6756                 if (Args & OCa) {
6757                         msg(ERRN,
6758                             "Unable to reset access time for \"%s%s%s\"",
6759                             (G_p->g_attrnam_p == NULL) ? nam_p : Fullnam_p,
6760                             (G_p->g_attrnam_p == NULL) ? "" :
6761                             G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6762                             gettext(" Attribute "),
6763                             (G_p->g_attrnam_p == NULL) ? "" : nam_p);
6764                 } else {
6765                         msg(ERRN,
6766                             "Unable to reset modification time for \"%s%s%s\"",
6767                             (G_p->g_attrnam_p == NULL) ? nam_p : Fullnam_p,
6768                             (G_p->g_attrnam_p == NULL) ? "" :
6769                             G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6770                             gettext(" Attribute "),
6771                             (G_p->g_attrnam_p == NULL) ? "" : nam_p);
6772                 }
6773         }
6774 }
6775 
6776 /*
6777  * sigint:  Catch interrupts.  If an interrupt occurs during the extraction
6778  * of a file from the archive with the -u option set, and the filename did
6779  * exist, remove the current file and restore the original file.  Then exit.
6780  */
6781 
6782 /*ARGSUSED*/
6783 static void
6784 sigint(int sig)
6785 {
6786         char *nam_p;
6787 
6788         (void) signal(SIGINT, SIG_IGN); /* block further signals */
6789         if (!Finished) {
6790                 if (Args & OCi)
6791                         nam_p = G_p->g_nam_p;
6792                 else /* OCp */
6793                         nam_p = Fullnam_p;
6794                 if (*Over_p != '\0') { /* There is a temp file */
6795                         if (unlink(nam_p) < 0) {
6796                                 msg(ERRN,
6797                                     "Cannot remove incomplete \"%s\"", nam_p);
6798                         }
6799                         if (rename(Over_p, nam_p) < 0) {
6800                                 if (link(Over_p, nam_p) < 0) {
6801                                         msg(ERRN,
6802                                             "Cannot recover original \"%s\"",
6803                                             nam_p);
6804                                 }
6805                                 if (unlink(Over_p)) {
6806                                         msg(ERRN,
6807                                             "Cannot remove temp file \"%s\"",
6808                                             Over_p);
6809                                 }
6810                         }
6811                 } else if (unlink(nam_p))
6812                         msg(ERRN,
6813                             "Cannot remove incomplete \"%s\"", nam_p);
6814                         *Over_p = '\0';
6815         }
6816         exit(EXIT_CODE);
6817 }
6818 
6819 /*
6820  * swap: Swap bytes (-s), halfwords (-S) or or both halfwords and bytes (-b).
6821  */
6822 
6823 static void
6824 swap(char *buf_p, int cnt)
6825 {
6826         unsigned char tbyte;
6827         int tcnt;
6828         int rcnt;
6829         ushort_t thalf;
6830 
6831         rcnt = cnt % 4;
6832         cnt /= 4;
6833         if (Args & (OCb | OCs | BSM)) {
6834                 tcnt = cnt;
6835                 /* LINTED alignment */
6836                 Swp_p = (union swpbuf *)buf_p;
6837                 while (tcnt-- > 0) {
6838                         tbyte = Swp_p->s_byte[0];
6839                         Swp_p->s_byte[0] = Swp_p->s_byte[1];
6840                         Swp_p->s_byte[1] = tbyte;
6841                         tbyte = Swp_p->s_byte[2];
6842                         Swp_p->s_byte[2] = Swp_p->s_byte[3];
6843                         Swp_p->s_byte[3] = tbyte;
6844                         Swp_p++;
6845                 }
6846                 if (rcnt >= 2) {
6847                 tbyte = Swp_p->s_byte[0];
6848                 Swp_p->s_byte[0] = Swp_p->s_byte[1];
6849                 Swp_p->s_byte[1] = tbyte;
6850                 tbyte = Swp_p->s_byte[2];
6851                 }
6852         }
6853         if (Args & (OCb | OCS)) {
6854                 tcnt = cnt;
6855                 /* LINTED alignment */
6856                 Swp_p = (union swpbuf *)buf_p;
6857                 while (tcnt-- > 0) {
6858                         thalf = Swp_p->s_half[0];
6859                         Swp_p->s_half[0] = Swp_p->s_half[1];
6860                         Swp_p->s_half[1] = thalf;
6861                         Swp_p++;
6862                 }
6863         }
6864 }
6865 
6866 /*
6867  * usage: Print the usage message on stderr and exit.
6868  */
6869 
6870 static void
6871 usage(void)
6872 {
6873 
6874         (void) fflush(stdout);
6875 #if defined(O_XATTR)
6876         (void) fprintf(stderr, gettext("USAGE:\n"
6877             "\tcpio -i[bcdfkmqrstuv@BSV6] [-C size] "
6878             "[-E file] [-H hdr] [-I file [-M msg]] "
6879             "[-R id] [patterns]\n"
6880             "\tcpio -o[acv@ABLV] [-C size] "
6881             "[-H hdr] [-O file [-M msg]]\n"
6882             "\tcpio -p[adlmuv@LV] [-R id] directory\n"));
6883 #else
6884         (void) fprintf(stderr, gettext("USAGE:\n"
6885             "\tcpio -i[bcdfkmqrstuvBSV6] [-C size] "
6886             "[-E file] [-H hdr] [-I file [-M msg]] "
6887             "[-R id] [patterns]\n"
6888             "\tcpio -o[acvABLV] [-C size] "
6889             "[-H hdr] [-O file [-M msg]]\n"
6890             "\tcpio -p[adlmuvLV] [-R id] directory\n"));
6891 #endif
6892         (void) fflush(stderr);
6893         exit(EXIT_CODE);
6894 }
6895 
6896 /*
6897  * verbose: For each file, print either the filename (-v) or a dot (-V).
6898  * If the -t option (table of contents) is set, print either the filename,
6899  * or if the -v option is also set, print an "ls -l"-like listing.
6900  */
6901 
6902 static void
6903 verbose(char *nam_p)
6904 {
6905         int i, j, temp;
6906         mode_t mode;
6907         char modestr[12];
6908         time_t  ttime;
6909 
6910         /*
6911          * The printf format and associated arguments to print the current
6912          * filename.  Normally, just nam_p.  If we're processing an extended
6913          * attribute, these are overridden.
6914          */
6915         char *name_fmt = "%s";
6916         const char *name = nam_p;
6917         const char *attribute = NULL;
6918 
6919         if (Gen.g_attrnam_p != NULL) {
6920                 /*
6921                  * Translation note:
6922                  * 'attribute' is a noun.
6923                  */
6924 
6925                 if (Gen.g_rw_sysattr) {
6926                         name_fmt = gettext("%s system attribute %s");
6927                 } else if ((Args & OCt) &&
6928                     (is_sysattr(basename(Gen.g_attrnam_p)))) {
6929                         name_fmt = gettext("%s system attribute %s");
6930                 } else {
6931                         name_fmt = gettext("%s attribute %s");
6932                 }
6933 
6934                 name = (Args & OCp) ? nam_p : Gen.g_attrfnam_p;
6935                 if (Gen.g_attrparent_p == NULL) {
6936                         attribute = Gen.g_attrnam_p;
6937                 } else {
6938                         attribute = Gen.g_attrpath_p;
6939                 }
6940         }
6941 
6942         if ((Gen.g_mode == SECMODE) || ((Hdr_type == USTAR ||
6943             Hdr_type == TAR) && Thdr_p->tbuf.t_typeflag == 'A')) {
6944                 /* dont print ancillary file */
6945                 aclchar = '+';
6946                 return;
6947         }
6948         for (i = 0; i < 11; i++)
6949                 modestr[i] = '-';
6950         modestr[i] = '\0';
6951         modestr[i-1] = aclchar;
6952         aclchar = ' ';
6953 
6954         if ((Args & OCt) && (Args & OCv)) {
6955                 mode = Gen.g_mode;
6956                 for (i = 0; i < 3; i++) {
6957                         temp = (mode >> (6 - (i * 3)));
6958                         j = (i * 3) + 1;
6959                         if (S_IROTH & temp)
6960                                 modestr[j] = 'r';
6961                         if (S_IWOTH & temp)
6962                                 modestr[j + 1] = 'w';
6963                         if (S_IXOTH & temp)
6964                                 modestr[j + 2] = 'x';
6965                 }
6966 
6967                 if (Hdr_type != BAR) {
6968                         temp = Gen.g_mode & Ftype;
6969                         switch (temp) {
6970                         case (S_IFIFO):
6971                                 modestr[0] = 'p';
6972                                 break;
6973                         case (S_IFSOCK):
6974                                 modestr[0] = 's';
6975                                 break;
6976                         case (S_IFCHR):
6977                                 modestr[0] = 'c';
6978                                 break;
6979                         case (S_IFDIR):
6980                                 modestr[0] = 'd';
6981                                 break;
6982                         case (S_IFBLK):
6983                                 modestr[0] = 'b';
6984                                 break;
6985                         case (S_IFREG): /* was initialized to '-' */
6986                                 break;
6987                         case (S_IFLNK):
6988                                 modestr[0] = 'l';
6989                                 break;
6990                         default:
6991                                 msg(ERR, "Impossible file type");
6992                         }
6993                 } else {                /* bar */
6994                         temp = Gen.g_mode & Ftype;
6995                         switch (temp) {
6996                         case (S_IFIFO):
6997                                 modestr[0] = 'p';
6998                                 break;
6999                         case (S_IFSOCK):
7000                                 modestr[0] = 's';
7001                                 break;
7002                         case (S_IFCHR):
7003                                 modestr[0] = 'c';
7004                                 break;
7005                         case (S_IFDIR):
7006                                 modestr[0] = 'd';
7007                                 break;
7008                         case (S_IFBLK):
7009                                 modestr[0] = 'b';
7010                                 break;
7011                         }
7012                         if (bar_linkflag == SYMTYPE)
7013                                 modestr[0] = 'l';
7014                 }
7015                 if ((S_ISUID & Gen.g_mode) == S_ISUID)
7016                         modestr[3] = 's';
7017                 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
7018                         modestr[9] = 't';
7019                 if ((S_ISGID & G_p->g_mode) == S_ISGID && modestr[6] == 'x')
7020                         modestr[6] = 's';
7021                 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
7022                         modestr[6] = 'l';
7023                 if ((Hdr_type == TAR || Hdr_type == USTAR) && Gen.g_nlink == 0)
7024                         (void) printf("%s%4d ", modestr, (int)Gen.g_nlink+1);
7025                 else
7026                         (void) printf("%s%4d ", modestr, (int)Gen.g_nlink);
7027                 if (Lastuid == (uid_t)Gen.g_uid) {
7028                         if (Lastuid == (uid_t)-1)
7029                                 (void) printf("-1       ");
7030                         else
7031                                 (void) printf("%-9s", Curpw_p->pw_name);
7032                 } else {
7033                         if (Curpw_p = getpwuid((int)Gen.g_uid)) {
7034                                 (void) printf("%-9s", Curpw_p->pw_name);
7035                                 Lastuid = (uid_t)Gen.g_uid;
7036                         } else {
7037                                 (void) printf("%-9d", (int)Gen.g_uid);
7038                                 Lastuid = (uid_t)-1;
7039                         }
7040                 }
7041                 if (Lastgid == (gid_t)Gen.g_gid) {
7042                         if (Lastgid == (gid_t)-1)
7043                                 (void) printf("-1       ");
7044                         else
7045                                 (void) printf("%-9s", Curgr_p->gr_name);
7046                 } else {
7047                         if (Curgr_p = getgrgid((int)Gen.g_gid)) {
7048                                 (void) printf("%-9s", Curgr_p->gr_name);
7049                                 Lastgid = (gid_t)Gen.g_gid;
7050                         } else {
7051                                 (void) printf("%-9d", (int)Gen.g_gid);
7052                                 Lastgid = (gid_t)-1;
7053                         }
7054                 }
7055 
7056                 /* print file size */
7057                 if (!Aspec || ((Gen.g_mode & Ftype) == S_IFIFO) ||
7058                     ((Gen.g_mode & Ftype) == S_IFSOCK) ||
7059                     (Hdr_type == BAR && bar_linkflag == SYMTYPE)) {
7060                         off_t filesz = Gen.g_filesz;
7061 
7062                         if (S_ISSPARSE(Gen.g_mode) && Gen.g_holes != NULL)
7063                                 filesz = Gen.g_holes->orig_size;
7064 
7065                         if (filesz < (1LL << 31))
7066                                 (void) printf("%7lld ", (offset_t)filesz);
7067                         else
7068                                 (void) printf("%11lld ", (offset_t)filesz);
7069                 } else
7070                         (void) printf("%3d,%3d ", (int)major(Gen.g_rdev),
7071                             (int)minor(Gen.g_rdev));
7072                 ttime = Gen.g_mtime;
7073                 (void) strftime(Time, sizeof (Time),
7074                     dcgettext(NULL, FORMAT, LC_TIME), localtime(&ttime));
7075                 (void) printf("%s, ", Time);
7076                 str_fprintf(stdout, name_fmt, name, attribute);
7077                 if ((Gen.g_mode & Ftype) == S_IFLNK) {
7078                         if (Hdr_type == USTAR || Hdr_type == TAR)
7079                                 (void) strcpy(Symlnk_p,
7080                                     Thdr_p->tbuf.t_linkname);
7081                         else {
7082                                 FILL(Gen.g_filesz);
7083                                 (void) strncpy(Symlnk_p, Buffr.b_out_p,
7084                                     Gen.g_filesz);
7085                                 *(Symlnk_p + Gen.g_filesz) = '\0';
7086                         }
7087                         (void) printf(" -> %s", Symlnk_p);
7088                 }
7089                 if (Hdr_type == BAR) {
7090                         if (bar_linkflag == SYMTYPE)
7091                                 (void) printf(gettext(" symbolic link to %s"),
7092                                     bar_linkname);
7093                         else if (bar_linkflag == '1')
7094                                 (void) printf(gettext(" linked to %s"),
7095                                     bar_linkname);
7096                 }
7097                 if ((Hdr_type == USTAR || Hdr_type == TAR) &&
7098                     Thdr_p->tbuf.t_typeflag == '1') {
7099                         (void) printf(gettext(" linked to %s%s%s"),
7100                             (Gen.g_attrnam_p == NULL) ?
7101                             Thdr_p->tbuf.t_linkname : Gen.g_attrfnam_p,
7102                             (Gen.g_attrnam_p == NULL) ? "" :
7103                             gettext(" attribute "),
7104                             (Gen.g_attrnam_p == NULL) ?
7105                             "" : Gen.g_linktoattrnam_p);
7106                 }
7107                 (void) printf("\n");
7108         } else if ((Args & OCt) || (Args & OCv)) {
7109                 str_fprintf(Out_p, name_fmt, name, attribute);
7110                 (void) fputc('\n', Out_p);
7111         } else { /* OCV */
7112                 (void) fputc('.', Out_p);
7113                 if (Verbcnt++ >= 49) { /* start a new line of dots */
7114                         Verbcnt = 0;
7115                         (void) fputc('\n', Out_p);
7116                 }
7117         }
7118         (void) fflush(Out_p);
7119 }
7120 
7121 #define MK_USHORT(a)    (a & 00000177777)
7122 
7123 /*
7124  * write_hdr: Transfer header information for the generic structure
7125  * into the format for the selected header and bwrite() the header.
7126  */
7127 
7128 static void
7129 write_hdr(int arcflag, off_t len)
7130 {
7131         int cnt, pad;
7132         mode_t mode;
7133         uid_t uid;
7134         gid_t gid;
7135         const char warnfmt[] = "%s%s%s : %s";
7136 
7137         switch (arcflag) {
7138         case ARCHIVE_ACL:
7139                 mode = SECMODE;
7140                 break;
7141 
7142         case ARCHIVE_XATTR:
7143         case ARCHIVE_NORMAL:
7144                 /*
7145                  * If attribute is being archived in cpio format then
7146                  * zap off the file type bits since those are truly a
7147                  * mask and reset them with _XATTR_CPIO_MODE
7148                  */
7149                 /*
7150                  * len is the value of g_filesz for normal files
7151                  * and the length of the special header buffer in
7152                  * the case of acl and xattr headers.
7153                  */
7154                 if (G_p->g_attrnam_p != NULL && Hdr_type != USTAR &&
7155                     Hdr_type != TAR) {
7156                         mode = (G_p->g_mode & POSIXMODES) | _XATTR_CPIO_MODE;
7157                 } else {
7158                         mode = G_p->g_mode;
7159                 }
7160                 if (arcflag != ARCHIVE_XATTR) {
7161                         len = G_p->g_filesz;
7162                 }
7163                 break;
7164 
7165         case ARCHIVE_SPARSE:
7166                 mode = G_p->g_mode | C_ISSPARSE;
7167                 len = G_p->g_filesz;
7168                 break;
7169         }
7170 
7171         uid = G_p->g_uid;
7172         gid = G_p->g_gid;
7173         /*
7174          * Handle EFT uids and gids.  If they get too big
7175          * to be represented in a particular format, force 'em to 'nobody'.
7176          */
7177         switch (Hdr_type) {
7178         case BIN:                       /* 16-bits of u_short */
7179                 if ((ulong_t)uid > (ulong_t)USHRT_MAX)
7180                         uid = UID_NOBODY;
7181                 if ((ulong_t)gid > (ulong_t)USHRT_MAX)
7182                         gid = GID_NOBODY;
7183                 break;
7184         case CHR:                       /* %.6lo => 262143 base 10 */
7185                 if ((ulong_t)uid > (ulong_t)0777777)
7186                         uid = UID_NOBODY;
7187                 if ((ulong_t)gid > (ulong_t)0777777)
7188                         gid = GID_NOBODY;
7189                 break;
7190         case ASC:                       /* %.8lx => full 32 bits */
7191         case CRC:
7192                 break;
7193         case USTAR:
7194         case TAR:                       /* %.7lo => 2097151 base 10 */
7195                 if ((ulong_t)uid > (ulong_t)07777777)
7196                         uid = UID_NOBODY;
7197                 if ((ulong_t)gid > (ulong_t)07777777)
7198                         gid = GID_NOBODY;
7199                 break;
7200         default:
7201                 msg(EXT, "Impossible header type.");
7202         }
7203 
7204         /*
7205          * Since cpio formats -don't- encode the symbolic names, print
7206          * a warning message when we map the uid or gid this way.
7207          * Also, if the ownership just changed, clear set[ug]id bits
7208          *
7209          * (Except for USTAR format of course, where we have a string
7210          * representation of the username embedded in the header)
7211          */
7212         if (uid != G_p->g_uid && Hdr_type != USTAR) {
7213                 msg(ERR, warnfmt,
7214                     (G_p->g_attrnam_p == NULL) ?
7215                     G_p->g_nam_p : G_p->g_attrfnam_p,
7216                     (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
7217                     gettext(" System Attribute ") : gettext(" Attribute "),
7218                     (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p,
7219                     gettext("uid too large for archive format"));
7220                 if (S_ISREG(mode))
7221                         mode &= ~S_ISUID;
7222         }
7223         if (gid != G_p->g_gid && Hdr_type != USTAR) {
7224                 msg(ERR, warnfmt,
7225                     (G_p->g_attrnam_p == NULL) ?
7226                     G_p->g_nam_p : G_p->g_attrfnam_p,
7227                     (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
7228                     gettext(" System Attribute ") : gettext(" Attribute "),
7229                     (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p,
7230                     gettext("gid too large for archive format"));
7231                 if (S_ISREG(mode))
7232                         mode &= ~S_ISGID;
7233         }
7234 
7235         switch (Hdr_type) {
7236         case BIN:
7237         case CHR:
7238         case ASC:
7239         case CRC:
7240                 cnt = Hdrsz + G_p->g_namesz;
7241                 break;
7242         case TAR:
7243                 /*FALLTHROUGH*/
7244         case USTAR: /* TAR and USTAR */
7245                 cnt = TARSZ;
7246                 break;
7247         default:
7248                 msg(EXT, "Impossible header type.");
7249         }
7250         FLUSH(cnt);
7251 
7252         switch (Hdr_type) {
7253         case BIN:
7254                 Hdr.h_magic = (short)G_p->g_magic;
7255                 Hdr.h_dev = G_p->g_dev;
7256                 Hdr.h_ino = G_p->g_ino;
7257                 Hdr.h_uid = uid;
7258                 Hdr.h_gid = gid;
7259                 Hdr.h_mode = mode;
7260                 Hdr.h_nlink = G_p->g_nlink;
7261                 Hdr.h_rdev = G_p->g_rdev;
7262                 mkshort(Hdr.h_mtime, (long)G_p->g_mtime);
7263                 Hdr.h_namesize = (short)G_p->g_namesz;
7264                 mkshort(Hdr.h_filesize, (long)len);
7265                 (void) strcpy(Hdr.h_name, G_p->g_nam_p);
7266                 (void) memcpy(Buffr.b_in_p, &Hdr, cnt);
7267                 break;
7268         case CHR:
7269                 /*LINTED*/
7270                 (void) sprintf(Buffr.b_in_p,
7271                     "%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.11lo%.6lo%."
7272                     "11llo%s", G_p->g_magic, G_p->g_dev, G_p->g_ino, mode,
7273                     (long)uid, (long)gid, G_p->g_nlink, MK_USHORT(G_p->g_rdev),
7274                     G_p->g_mtime, (long)G_p->g_namesz, (offset_t)len,
7275                     G_p->g_nam_p);
7276                 break;
7277         case ASC:
7278         case CRC:
7279                 /*LINTED*/
7280                 (void) sprintf(Buffr.b_in_p,
7281                     "%.6lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%."
7282                     "8lx%.8lx%.8lx%.8lx%s",
7283                     G_p->g_magic, G_p->g_ino, mode, G_p->g_uid,
7284                     G_p->g_gid, G_p->g_nlink, G_p->g_mtime, (ulong_t)len,
7285                     major(G_p->g_dev), minor(G_p->g_dev),
7286                     major(G_p->g_rdev), minor(G_p->g_rdev),
7287                     G_p->g_namesz, G_p->g_cksum, G_p->g_nam_p);
7288                 break;
7289         case USTAR:
7290                 Thdr_p = (union tblock *)Buffr.b_in_p;
7291                 (void) memset(Thdr_p, 0, TARSZ);
7292                 (void) strncpy(Thdr_p->tbuf.t_name, G_p->g_tname,
7293                     (int)strlen(G_p->g_tname));
7294                 (void) sprintf(Thdr_p->tbuf.t_mode, "%07o", (int)mode);
7295                 (void) sprintf(Thdr_p->tbuf.t_uid, "%07o", (int)uid);
7296                 (void) sprintf(Thdr_p->tbuf.t_gid, "%07o", (int)gid);
7297                 (void) sprintf(Thdr_p->tbuf.t_size, "%011llo",
7298                     (offset_t)len);
7299                 (void) sprintf(Thdr_p->tbuf.t_mtime, "%011lo", G_p->g_mtime);
7300                 if (arcflag == ARCHIVE_ACL) {
7301                         Thdr_p->tbuf.t_typeflag = 'A';       /* ACL file type */
7302                 } else if (arcflag == ARCHIVE_XATTR ||
7303                     (G_p->g_attrnam_p != NULL)) {
7304                         Thdr_p->tbuf.t_typeflag = _XATTR_HDRTYPE;
7305                 } else {
7306                         Thdr_p->tbuf.t_typeflag = G_p->g_typeflag;
7307                 }
7308                 if (T_lname[0] != '\0') {
7309                         /*
7310                          * if not a symbolic link
7311                          */
7312                         if (((G_p->g_mode & Ftype) != S_IFLNK) &&
7313                             (G_p->g_attrnam_p == NULL)) {
7314                                 Thdr_p->tbuf.t_typeflag = LNKTYPE;
7315                                 (void) sprintf(Thdr_p->tbuf.t_size,
7316                                     "%011lo", 0L);
7317                         }
7318                         (void) strncpy(Thdr_p->tbuf.t_linkname, T_lname,
7319                             strlen(T_lname));
7320                 }
7321                 (void) strcpy(Thdr_p->tbuf.t_magic, TMAGIC);
7322                 (void) strcpy(Thdr_p->tbuf.t_version, TVERSION);
7323                 (void) strcpy(Thdr_p->tbuf.t_uname, G_p->g_uname);
7324                 (void) strcpy(Thdr_p->tbuf.t_gname, G_p->g_gname);
7325                 (void) sprintf(Thdr_p->tbuf.t_devmajor, "%07o",
7326                     (int)major(G_p->g_rdev));
7327                 (void) sprintf(Thdr_p->tbuf.t_devminor, "%07o",
7328                     (int)minor(G_p->g_rdev));
7329                 if (Gen.g_prefix) {
7330                         (void) strcpy(Thdr_p->tbuf.t_prefix, Gen.g_prefix);
7331                         free(Gen.g_prefix);
7332                         Gen.g_prefix = NULL;
7333                 } else {
7334                         Thdr_p->tbuf.t_prefix[0] = '\0';
7335                 }
7336                 (void) sprintf(Thdr_p->tbuf.t_cksum, "%07o",
7337                     (int)cksum(TARTYP, 0, NULL));
7338                 break;
7339         case TAR:
7340                 Thdr_p = (union tblock *)Buffr.b_in_p;
7341                 (void) memset(Thdr_p, 0, TARSZ);
7342                 (void) strncpy(Thdr_p->tbuf.t_name, G_p->g_nam_p,
7343                     G_p->g_namesz);
7344                 (void) sprintf(Thdr_p->tbuf.t_mode, "%07o ", (int)mode);
7345                 (void) sprintf(Thdr_p->tbuf.t_uid, "%07o ", (int)uid);
7346                 (void) sprintf(Thdr_p->tbuf.t_gid, "%07o ", (int)gid);
7347                 (void) sprintf(Thdr_p->tbuf.t_size, "%011llo ",
7348                     (offset_t)len);
7349                 (void) sprintf(Thdr_p->tbuf.t_mtime, "%011o ",
7350                     (int)G_p->g_mtime);
7351                 if (T_lname[0] != '\0') {
7352                         Thdr_p->tbuf.t_typeflag = '1';
7353                 } else {
7354                         Thdr_p->tbuf.t_typeflag = '\0';
7355                 }
7356                 (void) strncpy(Thdr_p->tbuf.t_linkname, T_lname,
7357                     strlen(T_lname));
7358                 break;
7359         default:
7360                 msg(EXT, "Impossible header type.");
7361         } /* Hdr_type */
7362 
7363         Buffr.b_in_p += cnt;
7364         Buffr.b_cnt += cnt;
7365         pad = ((cnt + Pad_val) & ~Pad_val) - cnt;
7366         if (pad != 0) {
7367                 FLUSH(pad);
7368                 (void) memset(Buffr.b_in_p, 0, pad);
7369                 Buffr.b_in_p += pad;
7370                 Buffr.b_cnt += pad;
7371         }
7372 }
7373 
7374 /*
7375  * write_trail: Create the appropriate trailer for the selected header type
7376  * and bwrite the trailer.  Pad the buffer with nulls out to the next Bufsize
7377  * boundary, and force a write.  If the write completes, or if the trailer is
7378  * completely written (but not all of the padding nulls (as can happen on end
7379  * of medium)) return.  Otherwise, the trailer was not completely written out,
7380  * so re-pad the buffer with nulls and try again.
7381  */
7382 
7383 static void
7384 write_trail(void)
7385 {
7386         int cnt, need;
7387 
7388         switch (Hdr_type) {
7389         case BIN:
7390                 Gen.g_magic = CMN_BIN;
7391                 break;
7392         case CHR:
7393                 Gen.g_magic = CMN_BIN;
7394                 break;
7395         case ASC:
7396                 Gen.g_magic = CMN_ASC;
7397                 break;
7398         case CRC:
7399                 Gen.g_magic = CMN_CRC;
7400                 break;
7401         }
7402 
7403         switch (Hdr_type) {
7404         case BIN:
7405         case CHR:
7406         case ASC:
7407         case CRC:
7408                 Gen.g_mode = Gen.g_uid = Gen.g_gid = 0;
7409                 Gen.g_nlink = 1;
7410                 Gen.g_mtime = Gen.g_ino = Gen.g_dev = 0;
7411                 Gen.g_rdev = Gen.g_cksum = 0;
7412                 Gen.g_filesz = (off_t)0;
7413                 Gen.g_namesz = strlen("TRAILER!!!") + 1;
7414                 (void) strcpy(Gen.g_nam_p, "TRAILER!!!");
7415                 G_p = &Gen;
7416                 write_hdr(ARCHIVE_NORMAL, (off_t)0);
7417                 break;
7418         case TAR:
7419         /*FALLTHROUGH*/
7420         case USTAR: /* TAR and USTAR */
7421                 for (cnt = 0; cnt < 3; cnt++) {
7422                         FLUSH(TARSZ);
7423                         (void) memset(Buffr.b_in_p, 0, TARSZ);
7424                         Buffr.b_in_p += TARSZ;
7425                         Buffr.b_cnt += TARSZ;
7426                 }
7427                 break;
7428         default:
7429                 msg(EXT, "Impossible header type.");
7430         }
7431         need = Bufsize - (Buffr.b_cnt % Bufsize);
7432         if (need == Bufsize)
7433                 need = 0;
7434 
7435         while (Buffr.b_cnt > 0) {
7436                 while (need > 0) {
7437                         cnt = (need < TARSZ) ? need : TARSZ;
7438                         need -= cnt;
7439                         FLUSH(cnt);
7440                         (void) memset(Buffr.b_in_p, 0, cnt);
7441                         Buffr.b_in_p += cnt;
7442                         Buffr.b_cnt += cnt;
7443                 }
7444                 bflush();
7445         }
7446 }
7447 
7448 /*
7449  * if archives in USTAR format, check if typeflag == '5' for directories
7450  */
7451 static int
7452 ustar_dir(void)
7453 {
7454         if (Hdr_type == USTAR || Hdr_type == TAR) {
7455                 if (Thdr_p->tbuf.t_typeflag == '5')
7456                         return (1);
7457         }
7458         return (0);
7459 }
7460 
7461 /*
7462  * if archives in USTAR format, check if typeflag == '3' || '4' || '6'
7463  * for character, block, fifo special files
7464  */
7465 static int
7466 ustar_spec(void)
7467 {
7468         int typeflag;
7469 
7470         if (Hdr_type == USTAR || Hdr_type == TAR) {
7471                 typeflag = Thdr_p->tbuf.t_typeflag;
7472                 if (typeflag == '3' || typeflag == '4' || typeflag == '6')
7473                         return (1);
7474         }
7475         return (0);
7476 }
7477 
7478 /*
7479  * The return value is a pointer to a converted copy of the information in
7480  * FromStat if the file is representable in -Hodc format, and NULL otherwise.
7481  */
7482 
7483 static struct stat *
7484 convert_to_old_stat(struct stat *FromStat, char *namep, char *attrp)
7485 {
7486         static struct stat ToSt;
7487         cpioinfo_t TmpSt;
7488 
7489         (void) memset(&TmpSt, 0, sizeof (cpioinfo_t));
7490         stat_to_svr32_stat(&TmpSt, FromStat);
7491         (void) memset(&ToSt, 0, sizeof (ToSt));
7492 
7493         if (TmpSt.st_rdev == (o_dev_t)NODEV &&
7494             (((TmpSt.st_mode & Ftype) == S_IFCHR) ||
7495             ((TmpSt.st_mode & Ftype) == S_IFBLK))) {
7496                 /*
7497                  * Encountered a problem representing the rdev information.
7498                  * Don't archive it.
7499                  */
7500 
7501                 msg(ERR, "Error -Hodc format can't support expanded"
7502                     "types on %s%s%s",
7503                     namep,
7504                     (attrp == NULL) ? "" : gettext(" Attribute"),
7505                     (attrp == NULL) ? "" : attrp);
7506                 return (NULL);
7507         }
7508 
7509         if (TmpSt.st_dev == (o_dev_t)NODEV) {
7510                 /*
7511                  * Having trouble representing the device/inode pair.  We can't
7512                  * track links in this case; break them all into separate
7513                  * files.
7514                  */
7515 
7516                 TmpSt.st_ino = 0;
7517 
7518                 if (((TmpSt.st_mode & Ftype) != S_IFDIR) &&
7519                     TmpSt.st_nlink > 1)
7520                         msg(POST,
7521                             "Warning: file %s%s%s has large "
7522                             "device number - linked "
7523                             "files will be restored as "
7524                             "separate files",
7525                             namep,
7526                             (attrp == NULL) ? "" : gettext(" Attribute"),
7527                             (attrp == NULL) ? "" : attrp);
7528 
7529                 /* ensure no links */
7530 
7531                 TmpSt.st_nlink = 1;
7532         }
7533 
7534         /* Start converting values */
7535 
7536         if (TmpSt.st_dev < 0) {
7537                 ToSt.st_dev = 0;
7538         } else {
7539                 ToSt.st_dev = (dev_t)TmpSt.st_dev;
7540         }
7541 
7542         /* -actual- not truncated uid */
7543 
7544         ToSt.st_uid = TmpSt.st_uid;
7545 
7546         /* -actual- not truncated gid */
7547 
7548         ToSt.st_gid = TmpSt.st_gid;
7549         ToSt.st_ino = (ino_t)TmpSt.st_ino;
7550         ToSt.st_mode = (mode_t)TmpSt.st_mode;
7551         ToSt.st_mtime = (ulong_t)TmpSt.st_modtime;
7552         ToSt.st_nlink = (nlink_t)TmpSt.st_nlink;
7553         ToSt.st_size = (off_t)TmpSt.st_size;
7554         ToSt.st_rdev = (dev_t)TmpSt.st_rdev;
7555 
7556         return (&ToSt);
7557 }
7558 
7559 /*
7560  * In the beginning of each bar archive, there is a header which describes the
7561  * current volume being created, followed by a header which describes the
7562  * current file being created, followed by the file itself.  If there is
7563  * more than one file to be created, a separate header will be created for
7564  * each additional file.  This structure may be repeated if the bar archive
7565  * contains multiple volumes.  If a file spans across volumes, its header
7566  * will not be repeated in the next volume.
7567  *               +------------------+
7568  *               |    vol header    |
7569  *               |------------------|
7570  *               |   file header i  |     i = 0
7571  *               |------------------|
7572  *               |     <file i>     |
7573  *               |------------------|
7574  *               |  file header i+1 |
7575  *               |------------------|
7576  *               |    <file i+1>    |
7577  *               |------------------|
7578  *               |        .         |
7579  *               |        .         |
7580  *               |        .         |
7581  *               +------------------+
7582  */
7583 
7584 /*
7585  * read in the header that describes the current volume of the bar archive
7586  * to be extracted.
7587  */
7588 static void
7589 read_bar_vol_hdr(void)
7590 {
7591         union b_block *tmp_hdr;
7592 
7593         tmp_hdr = (union b_block *)Buffr.b_out_p;
7594         if (tmp_hdr->dbuf.bar_magic[0] == BAR_VOLUME_MAGIC) {
7595 
7596                 if (bar_Vhdr == NULL) {
7597                         bar_Vhdr = e_zalloc(E_EXIT, TBLOCK);
7598                 }
7599                 (void) memcpy(&(bar_Vhdr->dbuf), &(tmp_hdr->dbuf), TBLOCK);
7600         } else {
7601                 (void) fprintf(stderr, gettext(
7602                     "bar error: cannot read volume header\n"));
7603                 exit(1);
7604         }
7605 
7606         (void) sscanf(bar_Vhdr->dbuf.mode, "%8lo", &Gen_bar_vol.g_mode);
7607         (void) sscanf(bar_Vhdr->dbuf.uid, "%8d", (int *)&Gen_bar_vol.g_uid);
7608         (void) sscanf(bar_Vhdr->dbuf.gid, "%8d", (int *)&Gen_bar_vol.g_gid);
7609         (void) sscanf(bar_Vhdr->dbuf.size, "%12llo",
7610             (u_off_t *)&Gen_bar_vol.g_filesz);
7611         (void) sscanf(bar_Vhdr->dbuf.mtime, "%12lo", &Gen_bar_vol.g_mtime);
7612         (void) sscanf(bar_Vhdr->dbuf.chksum, "%8lo", &Gen_bar_vol.g_cksum);
7613 
7614         /* set the compress flag */
7615         if (bar_Vhdr->dbuf.compressed == '1')
7616                 Compressed = 1;
7617         else
7618                 Compressed = 0;
7619 
7620         Buffr.b_out_p += 512;
7621         Buffr.b_cnt -= 512;
7622 
7623         /*
7624          * not the first volume; exit
7625          */
7626         if (strcmp(bar_Vhdr->dbuf.volume_num, "1") != 0) {
7627                 (void) fprintf(stderr,
7628                     gettext("error: This is not volume 1.  "));
7629                 (void) fprintf(stderr, gettext("This is volume %s.  "),
7630                     bar_Vhdr->dbuf.volume_num);
7631                 (void) fprintf(stderr, gettext("Please insert volume 1.\n"));
7632                 exit(1);
7633         }
7634 
7635         read_bar_file_hdr();
7636 }
7637 
7638 /*
7639  * read in the header that describes the current file to be extracted
7640  */
7641 static void
7642 read_bar_file_hdr(void)
7643 {
7644         union b_block *tmp_hdr;
7645         char *start_of_name, *name_p;
7646         char *tmp;
7647 
7648         if (*Buffr.b_out_p == '\0') {
7649                 *Gen.g_nam_p = '\0';
7650                 exit(0);
7651         }
7652 
7653         tmp_hdr = (union b_block *)Buffr.b_out_p;
7654 
7655         tmp = &tmp_hdr->dbuf.mode[1];
7656         (void) sscanf(tmp, "%8lo", &Gen.g_mode);
7657         (void) sscanf(tmp_hdr->dbuf.uid, "%8lo", &Gen.g_uid);
7658         (void) sscanf(tmp_hdr->dbuf.gid, "%8lo", &Gen.g_gid);
7659         (void) sscanf(tmp_hdr->dbuf.size, "%12llo",
7660             (u_off_t *)&Gen.g_filesz);
7661         (void) sscanf(tmp_hdr->dbuf.mtime, "%12lo", &Gen.g_mtime);
7662         (void) sscanf(tmp_hdr->dbuf.chksum, "%8lo", &Gen.g_cksum);
7663         (void) sscanf(tmp_hdr->dbuf.rdev, "%8lo", &Gen.g_rdev);
7664 
7665 #define to_new_major(x) (int)((unsigned)((x) & OMAXMAJ) << NBITSMINOR)
7666 #define to_new_minor(x) (int)((x) & OMAXMIN)
7667         Gen.g_rdev = to_new_major(Gen.g_rdev) | to_new_minor(Gen.g_rdev);
7668         bar_linkflag = tmp_hdr->dbuf.linkflag;
7669         start_of_name = &tmp_hdr->dbuf.start_of_name;
7670 
7671 
7672         name_p = Gen.g_nam_p;
7673         while (*name_p++ = *start_of_name++)
7674                 ;
7675         *name_p = '\0';
7676         if (bar_linkflag == LNKTYPE || bar_linkflag == SYMTYPE)
7677                 (void) strcpy(bar_linkname, start_of_name);
7678 
7679         Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
7680         (void) strcpy(nambuf, Gen.g_nam_p);
7681 }
7682 
7683 /*
7684  * if the bar archive is compressed, set up a pipe and do the de-compression
7685  * as the compressed file is read in.
7686  */
7687 static void
7688 setup_uncompress(FILE **pipef)
7689 {
7690         char *cmd_buf;
7691         size_t cmdlen;
7692 
7693         cmd_buf = e_zalloc(E_EXIT, MAXPATHLEN * 2);
7694 
7695         if (access(Gen.g_nam_p, W_OK) != 0) {
7696                 cmdlen = snprintf(cmd_buf, MAXPATHLEN * 2,
7697                     "chmod +w '%s'; uncompress -c > '%s'; "
7698                     "chmod 0%o '%s'",
7699                     Gen.g_nam_p, Gen.g_nam_p, (int)G_p->g_mode, Gen.g_nam_p);
7700         } else {
7701                 cmdlen = snprintf(cmd_buf, MAXPATHLEN * 2,
7702                     "uncompress -c > '%s'", Gen.g_nam_p);
7703         }
7704 
7705         if (cmdlen >= MAXPATHLEN * 2 ||
7706             (*pipef = popen(cmd_buf, "w")) == NULL) {
7707                 (void) fprintf(stderr, gettext("error\n"));
7708                 exit(1);
7709         }
7710 
7711         if (close(Ofile) != 0)
7712                 msg(EXTN, "close error");
7713         Ofile = fileno(*pipef);
7714 
7715         free(cmd_buf);
7716 }
7717 
7718 /*
7719  * if the bar archive spans multiple volumes, read in the header that
7720  * describes the next volume.
7721  */
7722 static void
7723 skip_bar_volhdr(void)
7724 {
7725         char *buff;
7726         union b_block *tmp_hdr;
7727 
7728         buff = e_zalloc(E_EXIT, (uint_t)Bufsize);
7729 
7730         if (g_read(Device, Archive, buff, Bufsize) < 0) {
7731                 (void) fprintf(stderr, gettext(
7732                     "error in skip_bar_volhdr\n"));
7733         } else {
7734 
7735                 tmp_hdr = (union b_block *)buff;
7736                 if (tmp_hdr->dbuf.bar_magic[0] == BAR_VOLUME_MAGIC) {
7737 
7738                         if (bar_Vhdr == NULL) {
7739                                 bar_Vhdr = e_zalloc(E_EXIT, TBLOCK);
7740                         }
7741                         (void) memcpy(&(bar_Vhdr->dbuf),
7742                             &(tmp_hdr->dbuf), TBLOCK);
7743                 } else {
7744                         (void) fprintf(stderr,
7745                             gettext("cpio error: cannot read bar volume "
7746                             "header\n"));
7747                         exit(1);
7748                 }
7749 
7750                 (void) sscanf(bar_Vhdr->dbuf.mode, "%8lo",
7751                     &Gen_bar_vol.g_mode);
7752                 (void) sscanf(bar_Vhdr->dbuf.uid, "%8lo",
7753                     &Gen_bar_vol.g_uid);
7754                 (void) sscanf(bar_Vhdr->dbuf.gid, "%8lo",
7755                     &Gen_bar_vol.g_gid);
7756                 (void) sscanf(bar_Vhdr->dbuf.size, "%12llo",
7757                     (u_off_t *)&Gen_bar_vol.g_filesz);
7758                 (void) sscanf(bar_Vhdr->dbuf.mtime, "%12lo",
7759                     &Gen_bar_vol.g_mtime);
7760                 (void) sscanf(bar_Vhdr->dbuf.chksum, "%8lo",
7761                     &Gen_bar_vol.g_cksum);
7762                 if (bar_Vhdr->dbuf.compressed == '1')
7763                         Compressed = 1;
7764                 else
7765                         Compressed = 0;
7766         }
7767 
7768         /*
7769          * Now put the rest of the bytes read in into the data buffer.
7770          */
7771         (void) memcpy(Buffr.b_in_p, &buff[512], (Bufsize - 512));
7772         Buffr.b_in_p += (Bufsize - 512);
7773         Buffr.b_cnt += (long)(Bufsize - 512);
7774 
7775         free(buff);
7776 }
7777 
7778 /*
7779  * check the linkflag which indicates the type of the file to be extracted,
7780  * invoke the corresponding routine to extract the file.
7781  */
7782 static void
7783 bar_file_in(void)
7784 {
7785         /*
7786          * the file is a directory
7787          */
7788         if (Adir) {
7789                 if (ckname(1) != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
7790                         VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
7791                 }
7792                 return;
7793         }
7794 
7795         switch (bar_linkflag) {
7796         case REGTYPE:
7797                 /* regular file */
7798                 if ((ckname(1) == F_SKIP) ||
7799                     (Ofile = openout(G_p->g_dirfd)) < 0) {
7800                         data_in(P_SKIP);
7801                 } else {
7802                         data_in(P_PROC);
7803                 }
7804                 break;
7805         case LNKTYPE:
7806                 /* hard link */
7807                 if (ckname(1) == F_SKIP) {
7808                         break;
7809                 }
7810                 (void) creat_lnk(G_p->g_dirfd, bar_linkname, G_p->g_nam_p);
7811                 break;
7812         case SYMTYPE:
7813                 /* symbolic link */
7814                 if ((ckname(1) == F_SKIP) ||
7815                     (Ofile = openout(G_p->g_dirfd)) < 0) {
7816                         data_in(P_SKIP);
7817                 } else {
7818                         data_in(P_PROC);
7819                 }
7820                 break;
7821         case CHRTYPE:
7822                 /* character device or FIFO */
7823                 if (ckname(1) != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
7824                         VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
7825                 }
7826                 break;
7827         default:
7828                 (void) fprintf(stderr, gettext("error: unknown file type\n"));
7829                 break;
7830         }
7831 }
7832 
7833 
7834 /*
7835  * This originally came from libgenIO/g_init.c
7836  * XXX  And it is very broken.
7837  */
7838 
7839 /* #include <sys/statvfs.h> */
7840 #include <ftw.h>
7841 /* #include <libgenIO.h> */
7842 #define G_TM_TAPE       1       /* Tapemaster controller    */
7843 #define G_XY_DISK       3       /* xy disks             */
7844 #define G_SD_DISK       7       /* scsi sd disk         */
7845 #define G_XT_TAPE       8       /* xt tapes             */
7846 #define G_SF_FLOPPY     9       /* sf floppy            */
7847 #define G_XD_DISK       10      /* xd disks             */
7848 #define G_ST_TAPE       11      /* scsi tape            */
7849 #define G_NS            12      /* noswap pseudo-dev    */
7850 #define G_RAM           13      /* ram pseudo-dev       */
7851 #define G_FT            14      /* tftp                 */
7852 #define G_HD            15      /* 386 network disk     */
7853 #define G_FD            16      /* 386 AT disk          */
7854 #define G_FILE          28      /* file, not a device   */
7855 #define G_NO_DEV        29      /* device does not require special treatment */
7856 #define G_DEV_MAX       30      /* last valid device type */
7857 
7858 /*
7859  * g_init: Determine the device being accessed, set the buffer size,
7860  * and perform any device specific initialization. Since at this point
7861  * Sun has no system call to read the configuration, the major numbers
7862  * are assumed to be static and types are figured out as such. However,
7863  * as a rough estimate, the buffer size for all types is set to 512
7864  * as a default.
7865  */
7866 
7867 static int
7868 g_init(int *devtype, int *fdes)
7869 {
7870         int bufsize;
7871         struct stat st_buf;
7872         struct statvfs stfs_buf;
7873 
7874         *devtype = G_NO_DEV;
7875         bufsize = -1;
7876         if (fstat(*fdes, &st_buf) == -1)
7877                 return (-1);
7878         if (!S_ISCHR(st_buf.st_mode) && !S_ISBLK(st_buf.st_mode)) {
7879                 if (S_ISFIFO(st_buf.st_mode)) {
7880                         bufsize = 512;
7881                 } else {
7882                         /* find block size for this file system */
7883                         *devtype = G_FILE;
7884                         if (fstatvfs(*fdes, &stfs_buf) < 0) {
7885                                         bufsize = -1;
7886                                         errno = ENODEV;
7887                         } else
7888                                 bufsize = stfs_buf.f_bsize;
7889                 }
7890 
7891                 return (bufsize);
7892 
7893         /*
7894          * We'll have to add a remote attribute to stat but this
7895          * should work for now.
7896          */
7897         } else if (st_buf.st_dev & 0x8000)  /* if remote  rdev */
7898                 return (512);
7899 
7900         bufsize = 512;
7901 
7902         if (Hdr_type == BAR) {
7903                 if (is_tape(*fdes)) {
7904                         bufsize = BAR_TAPE_SIZE;
7905                         msg(EPOST, "Archiving to tape blocking factor 126");
7906                 } else if (is_floppy(*fdes)) {
7907                         bufsize = BAR_FLOPPY_SIZE;
7908                         msg(EPOST, "Archiving to floppy blocking factor 18");
7909                 }
7910         }
7911 
7912         return (bufsize);
7913 }
7914 
7915 /*
7916  * This originally came from libgenIO/g_read.c
7917  */
7918 
7919 /*
7920  * g_read: Read nbytes of data from fdes (of type devtype) and place
7921  * data in location pointed to by buf.  In case of end of medium,
7922  * translate (where necessary) device specific EOM indications into
7923  * the generic EOM indication of rv = -1, errno = ENOSPC.
7924  */
7925 
7926 static int
7927 g_read(int devtype, int fdes, char *buf, unsigned nbytes)
7928 {
7929         int rv;
7930 
7931         if (devtype < 0 || devtype >= G_DEV_MAX) {
7932                 errno = ENODEV;
7933                 return (-1);
7934         }
7935 
7936         rv = read(fdes, buf, nbytes);
7937 
7938         /* st devices return 0 when no space left */
7939         if ((rv == 0 && errno == 0 && Hdr_type != BAR) ||
7940             (rv == -1 && errno == EIO)) {
7941                 errno = 0;
7942                 rv = 0;
7943         }
7944 
7945         return (rv);
7946 }
7947 
7948 /*
7949  * This originally came from libgenIO/g_write.c
7950  */
7951 
7952 /*
7953  * g_write: Write nbytes of data to fdes (of type devtype) from
7954  * the location pointed to by buf.  In case of end of medium,
7955  * translate (where necessary) device specific EOM indications into
7956  * the generic EOM indication of rv = -1, errno = ENOSPC.
7957  */
7958 
7959 static int
7960 g_write(int devtype, int fdes, char *buf, unsigned nbytes)
7961 {
7962         int rv;
7963 
7964         if (devtype < 0 || devtype >= G_DEV_MAX) {
7965                 errno = ENODEV;
7966                 return (-1);
7967         }
7968 
7969         rv = write(fdes, buf, nbytes);
7970 
7971         /* st devices return 0 when no more space left */
7972         if ((rv == 0 && errno == 0) || (rv == -1 && errno == EIO)) {
7973                 errno = ENOSPC;
7974                 rv = -1;
7975         }
7976 
7977         return (rv);
7978 }
7979 
7980 /*
7981  * Test for tape
7982  */
7983 
7984 static int
7985 is_tape(int fd)
7986 {
7987         struct mtget stuff;
7988 
7989         /*
7990          * try to do a generic tape ioctl, just to see if
7991          * the thing is in fact a tape drive(er).
7992          */
7993         if (ioctl(fd, MTIOCGET, &stuff) != -1) {
7994                 /* the ioctl succeeded, must have been a tape */
7995                 return (1);
7996         }
7997         return (0);
7998 }
7999 
8000 /*
8001  * Test for floppy
8002  */
8003 
8004 static int
8005 is_floppy(int fd)
8006 {
8007         struct fd_char stuff;
8008 
8009         /*
8010          * try to get the floppy drive characteristics, just to see if
8011          * the thing is in fact a floppy drive(er).
8012          */
8013         if (ioctl(fd, FDIOGCHAR, &stuff) != -1) {
8014                 /* the ioctl succeeded, must have been a floppy */
8015                 return (1);
8016         }
8017 
8018         return (0);
8019 }
8020 
8021 /*
8022  * New functions for ACLs and other security attributes
8023  */
8024 
8025 /*
8026  * The function appends the new security attribute info to the end of
8027  * existing secinfo.
8028  */
8029 static int
8030 append_secattr(
8031         char            **secinfo,      /* existing security info */
8032         int             *secinfo_len,   /* length of existing security info */
8033         acl_t           *aclp)  /* new attribute data pointer */
8034 {
8035         char    *new_secinfo;
8036         char    *attrtext;
8037         size_t  newattrsize;
8038         int     oldsize;
8039 
8040         /* no need to add */
8041         if (aclp == NULL) {
8042                 return (0);
8043         }
8044 
8045         switch (acl_type(aclp)) {
8046         case ACLENT_T:
8047         case ACE_T:
8048                 attrtext = acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8049                     ACL_SID_FMT);
8050                 if (attrtext == NULL) {
8051                         msg(EPOST, "acltotext failed");
8052                         return (-1);
8053                 }
8054                 /* header: type + size = 8 */
8055                 newattrsize = 8 + strlen(attrtext) + 1;
8056                 attr = e_zalloc(E_NORMAL, newattrsize);
8057                 if (attr == NULL) {
8058                         msg(EPOST, "can't allocate memory");
8059                         return (-1);
8060                 }
8061                 attr->attr_type = (acl_type(aclp) == ACLENT_T) ?
8062                     UFSD_ACL : ACE_ACL;
8063                 /* acl entry count */
8064                 (void) sprintf(attr->attr_len, "%06o", acl_cnt(aclp));
8065                 (void) strcpy((char *)&attr->attr_info[0], attrtext);
8066                 free(attrtext);
8067                 break;
8068 
8069                 /* SunFed's case goes here */
8070 
8071         default:
8072                 msg(EPOST, "unrecognized attribute type");
8073                 return (-1);
8074         }
8075 
8076         /* old security info + new attr header(8) + new attr */
8077         oldsize = *secinfo_len;
8078         *secinfo_len += newattrsize;
8079         new_secinfo = e_zalloc(E_NORMAL, (uint_t)*secinfo_len);
8080         if (new_secinfo == NULL) {
8081                 msg(EPOST, "can't allocate memory");
8082                 *secinfo_len -= newattrsize;
8083                 return (-1);
8084         }
8085 
8086         (void) memcpy(new_secinfo, *secinfo, oldsize);
8087         (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
8088 
8089         free(*secinfo);
8090         *secinfo = new_secinfo;
8091         return (0);
8092 }
8093 
8094 /*
8095  * Append size amount of data from buf to the archive.
8096  */
8097 static void
8098 write_ancillary(char *buf, size_t len, boolean_t padding)
8099 {
8100         int     pad, cnt;
8101 
8102         if (len == 0)
8103                 return;
8104 
8105         while (len > 0) {
8106                 cnt = (unsigned)(len > CPIOBSZ) ? CPIOBSZ : len;
8107                 FLUSH(cnt);
8108                 errno = 0;
8109                 (void) memcpy(Buffr.b_in_p, buf, (unsigned)cnt);
8110                 Buffr.b_in_p += cnt;
8111                 Buffr.b_cnt += cnt;
8112                 len -= cnt;
8113                 buf += cnt;
8114         }
8115         if (padding) {
8116                 pad = (Pad_val + 1 - (cnt & Pad_val)) & Pad_val;
8117                 if (pad != 0) {
8118                         FLUSH(pad);
8119                         (void) memset(Buffr.b_in_p, 0, pad);
8120                         Buffr.b_in_p += pad;
8121                         Buffr.b_cnt += pad;
8122                 }
8123         }
8124 }
8125 
8126 static int
8127 remove_dir(char *path)
8128 {
8129         DIR             *name;
8130         struct dirent   *direct;
8131         struct stat     sbuf;
8132         char            *path_copy;
8133 
8134 #define MSG1    "remove_dir() failed to stat(\"%s\") "
8135 #define MSG2    "remove_dir() failed to remove_dir(\"%s\") "
8136 #define MSG3    "remove_dir() failed to unlink(\"%s\") "
8137 
8138         /*
8139          * Open the directory for reading.
8140          */
8141         if ((name = opendir(path)) == NULL) {
8142                 msg(ERRN, "remove_dir() failed to opendir(\"%s\") ", path);
8143                 return (-1);
8144         }
8145 
8146         if (chdir(path) == -1) {
8147                 msg(ERRN, "remove_dir() failed to chdir(\"%s\") ", path);
8148                 return (-1);
8149         }
8150 
8151         /*
8152          * Read every directory entry.
8153          */
8154         while ((direct = readdir(name)) != NULL) {
8155                 /*
8156                  * Ignore "." and ".." entries.
8157                  */
8158                 if (strcmp(direct->d_name, ".") == 0 ||
8159                     strcmp(direct->d_name, "..") == 0)
8160                         continue;
8161 
8162                         if (lstat(direct->d_name, &sbuf) == -1) {
8163                                 msg(ERRN, MSG1, direct->d_name);
8164                                 (void) closedir(name);
8165                         return (-1);
8166                 }
8167 
8168                 if (S_ISDIR(sbuf.st_mode)) {
8169                         if (remove_dir(direct->d_name) == -1) {
8170                                 msg(ERRN, MSG2, direct->d_name);
8171                                 (void) closedir(name);
8172                                 return (-1);
8173                         }
8174                 } else {
8175                         if (unlink(direct->d_name) == -1) {
8176                                 msg(ERRN, MSG3, direct->d_name);
8177                                 (void) closedir(name);
8178                                 return (-1);
8179                         }
8180                 }
8181 
8182         }
8183 
8184         /*
8185          * Close the directory we just finished reading.
8186          */
8187         (void) closedir(name);
8188 
8189         /*
8190          * Change directory to the parent directory...
8191          */
8192         if (chdir("..") == -1) {
8193                 msg(ERRN, "remove_dir() failed to chdir(\"..\") ");
8194                 return (-1);
8195         }
8196 
8197         /*
8198          * ...and finally remove the directory; note we have to
8199          * make a copy since basename is free to modify its input.
8200          */
8201         path_copy = e_strdup(E_NORMAL, path);
8202         if (path_copy == NULL) {
8203                 msg(ERRN, "cannot strdup() the directory pathname ");
8204                 return (-1);
8205         }
8206 
8207         if (rmdir(basename(path_copy)) == -1) {
8208                 free(path_copy);
8209                 msg(ERRN, "remove_dir() failed to rmdir(\"%s\") ", path);
8210                 return (-1);
8211         }
8212 
8213         free(path_copy);
8214         return (0);
8215 
8216 }
8217 
8218 static int
8219 save_cwd(void)
8220 {
8221         return (open(".", O_RDONLY));
8222 }
8223 
8224 static void
8225 rest_cwd(int cwd)
8226 {
8227         (void) fchdir(cwd);
8228         (void) close(cwd);
8229 }
8230 
8231 #if defined(O_XATTR)
8232 static void
8233 xattrs_out(int (*func)())
8234 {
8235         int dirpfd;
8236         int filefd;
8237         int arc_rwsysattr = 0;
8238         int rw_sysattr = 0;
8239         int ext_attr = 0;
8240         DIR *dirp;
8241         struct dirent *dp;
8242         int slen;
8243         int plen;
8244         char *namep, *savenamep;
8245         char *apathp;
8246         char *attrparent = Gen.g_attrparent_p;
8247         char *filename;
8248 
8249         if (attrparent == NULL) {
8250                 filename = Gen.g_nam_p;
8251         } else {
8252                 filename = Gen.g_attrnam_p;
8253         }
8254 
8255         /*
8256          * If the underlying file system supports it, then
8257          * archive the extended attributes if -@ was specified,
8258          * and the extended system attributes if -/ was
8259          * specified.
8260          */
8261         if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
8262             &ext_attr) != ATTR_OK) {
8263                 return;
8264         }
8265 
8266 #if defined(_PC_SATTR_ENABLED)
8267         if (SysAtflag) {
8268                 int             filefd;
8269                 nvlist_t        *slist = NULL;
8270 
8271                 /*
8272                  * Determine if there are non-transient system
8273                  * attributes.
8274                  */
8275                 errno = 0;
8276                 if ((filefd = open(filename, O_RDONLY)) == -1) {
8277                         if (attrparent == NULL) {
8278                                 msg(EXTN,
8279                                     "unable to open %s%s%sfile %s",
8280                                     (attrparent == NULL) ? "" :
8281                                     gettext("attribute "),
8282                                     (attrparent == NULL) ? "" : attrparent,
8283                                     (attrparent == NULL) ? "" : gettext(" of "),
8284                                     (attrparent == NULL) ? G_p->g_nam_p :
8285                                     G_p->g_attrfnam_p);
8286                         }
8287                 }
8288                 if (((slist = sysattr_list(myname, filefd,
8289                     filename)) != NULL) || (errno != 0)) {
8290                         arc_rwsysattr = 1;
8291                 }
8292                 if (slist != NULL) {
8293                         (void) nvlist_free(slist);
8294                         slist = NULL;
8295                 }
8296                 (void) close(filefd);
8297         }
8298 
8299         /*
8300          * If we aren't archiving extended system attributes, and we are
8301          * processing an attribute, or if we are archiving extended system
8302          * attributes, and there are are no extended attributes, then there's
8303          * no need to open up the attribute directory of the file unless the
8304          * extended system attributes are not transient (i.e, the system
8305          * attributes are not the default values).
8306          */
8307         if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
8308             (SysAtflag && !ext_attr))) {
8309                 return;
8310         }
8311 
8312 #endif  /* _PC_SATTR_ENABLED */
8313 
8314         /*
8315          * If aclp still exists then free it since it is was set when base
8316          * file was extracted.
8317          */
8318         if (aclp != NULL) {
8319                 acl_free(aclp);
8320                 aclp = NULL;
8321                 acl_is_set = 0;
8322         }
8323 
8324         Gen.g_dirfd = attropen(filename, ".", O_RDONLY);
8325         if (Gen.g_dirfd == -1) {
8326                 msg(ERRN, "Cannot open attribute directory of file \"%s%s%s\"",
8327                     (attrparent == NULL) ? "" : gettext("attribute "),
8328                     (attrparent == NULL) ? "" : attrparent,
8329                     (attrparent == NULL) ? "" : gettext(" of "), filename);
8330                 return;
8331 
8332         }
8333 
8334         if (attrparent == NULL) {
8335                 savenamep = G_p->g_nam_p;
8336         } else {
8337                 savenamep = G_p->g_attrfnam_p;
8338         }
8339 
8340         if ((dirpfd = dup(Gen.g_dirfd)) == -1)  {
8341                 msg(ERRN, "Cannot dup(2) attribute directory descriptor");
8342                 return;
8343         }
8344 
8345         if ((dirp = fdopendir(dirpfd)) == NULL) {
8346                 msg(ERRN, "Cannot fdopendir(2) directory file descriptor");
8347                 return;
8348         }
8349 
8350         if (attrparent == NULL) {
8351                 Gen.g_baseparent_fd = save_cwd();
8352         }
8353 
8354         while ((dp = readdir(dirp)) != NULL) {
8355                 if (strcmp(dp->d_name, "..") == 0) {
8356                         continue;
8357                 }
8358                 if (verify_attr(dp->d_name, attrparent,
8359                     arc_rwsysattr, &rw_sysattr) != ATTR_OK) {
8360                         continue;
8361                 }
8362 
8363                 if (strcmp(dp->d_name, ".") == 0) {
8364                         Hiddendir = 1;
8365                 } else {
8366                         Hiddendir = 0;
8367                 }
8368 
8369                 Gen.g_rw_sysattr = rw_sysattr;
8370                 Gen.g_attrnam_p = dp->d_name;
8371 
8372                 if (STAT(Gen.g_dirfd, Gen.g_nam_p, &SrcSt) == -1) {
8373                         msg(ERRN,
8374                             "Could not fstatat(2) attribute \"%s\" of"
8375                             " file \"%s\"", dp->d_name, (attrparent == NULL) ?
8376                             savenamep : Gen.g_attrfnam_p);
8377                         continue;
8378                 }
8379 
8380                 if (Use_old_stat) {
8381                         Savedev = SrcSt.st_dev;
8382                         OldSt = convert_to_old_stat(&SrcSt,
8383                             Gen.g_nam_p, Gen.g_attrnam_p);
8384 
8385                         if (OldSt == NULL) {
8386                                 msg(ERRN,
8387                                     "Could not convert to old stat format");
8388                                 continue;
8389                         }
8390                 }
8391 
8392                 Gen.g_attrfnam_p = savenamep;
8393 
8394                 /*
8395                  * Set up dummy header name
8396                  *
8397                  * One piece is written with .hdr, which
8398                  * contains the actual xattr hdr or pathing information
8399                  * then the name is updated to drop the .hdr off
8400                  * and the actual file itself is archived.
8401                  */
8402                 slen = strlen(Gen.g_attrnam_p) + strlen(DEVNULL) +
8403                     strlen(XATTRHDR) + 2;       /* add one for '/' */
8404                 if ((namep = e_zalloc(E_NORMAL, slen)) == NULL) {
8405                         msg(ERRN, "Could not calloc memory for attribute name");
8406                         continue;
8407                 }
8408                 (void) snprintf(namep, slen, "%s/%s%s",
8409                     DEVNULL, Gen.g_attrnam_p, XATTRHDR);
8410                 Gen.g_nam_p = namep;
8411 
8412                 plen = strlen(Gen.g_attrnam_p) + 1;
8413                 if (Gen.g_attrparent_p != NULL) {
8414                         plen += strlen(Gen.g_attrparent_p) + 1;
8415                 }
8416                 if ((apathp = e_zalloc(E_NORMAL, plen)) == NULL) {
8417                         msg(ERRN, "Could not calloc memory for attribute name");
8418                         continue;
8419                 }
8420                 (void) snprintf(apathp, plen, "%s%s%s",
8421                     (Gen.g_attrparent_p == NULL) ? "" : Gen.g_attrparent_p,
8422                     (Gen.g_attrparent_p == NULL) ? "" : "/", Gen.g_attrnam_p);
8423 
8424                 if (Gen.g_attrpath_p != NULL) {
8425                         free(Gen.g_attrpath_p);
8426                 }
8427                 Gen.g_attrpath_p = apathp;
8428 
8429                 /*
8430                  * Get attribute's ACL info: don't bother allocating space
8431                  * if there are only standard permissions, i.e. ACL count < 4
8432                  */
8433                 if (Pflag) {
8434                         filefd = openat(Gen.g_dirfd, dp->d_name, O_RDONLY);
8435                         if (filefd == -1) {
8436                                 msg(ERRN,
8437                                     "Could not open attribute \"%s\" of"
8438                                     " file \"%s\"", dp->d_name, savenamep);
8439                                 free(namep);
8440                                 continue;
8441                         }
8442                         if (facl_get(filefd, ACL_NO_TRIVIAL, &aclp) != 0) {
8443                                 msg(ERRN,
8444                                     "Error with acl() on %s",
8445                                     Gen.g_nam_p);
8446                         }
8447                         (void) close(filefd);
8448                 }
8449 
8450                 (void) creat_hdr();
8451                 (void) (*func)();
8452 
8453 #if defined(_PC_SATTR_ENABLED)
8454                 /*
8455                  * Recursively call xattrs_out() to process the attribute's
8456                  * hidden attribute directory and read-write system attributes.
8457                  */
8458                 if (SysAtflag && !Hiddendir && !rw_sysattr) {
8459                         int     savedirfd = Gen.g_dirfd;
8460 
8461                         (void) fchdir(Gen.g_dirfd);
8462                         Gen.g_attrparent_p = dp->d_name;
8463                         xattrs_out(func);
8464                         Gen.g_dirfd = savedirfd;
8465                         Gen.g_attrparent_p = NULL;
8466                 }
8467 #endif  /* _PC_SATTR_ENABLED */
8468 
8469                 if (Gen.g_passdirfd != -1) {
8470                         (void) close(Gen.g_passdirfd);
8471                         Gen.g_passdirfd = -1;
8472                 }
8473                 Gen.g_attrnam_p = NULL;
8474                 Gen.g_attrfnam_p = NULL;
8475                 Gen.g_linktoattrfnam_p = NULL;
8476                 Gen.g_linktoattrnam_p = NULL;
8477                 Gen.g_rw_sysattr = 0;
8478                 if (Gen.g_attrpath_p != NULL) {
8479                         free(Gen.g_attrpath_p);
8480                         Gen.g_attrpath_p = NULL;
8481                 }
8482 
8483                 if (aclp != NULL) {
8484                         acl_free(aclp);
8485                         aclp = NULL;
8486                         acl_is_set = 0;
8487                 }
8488                 free(namep);
8489         }
8490 
8491         (void) closedir(dirp);
8492         (void) close(Gen.g_dirfd);
8493         if (attrparent == NULL) {
8494                 rest_cwd(Gen.g_baseparent_fd);
8495                 Gen.g_dirfd = -1;
8496         }
8497         Hiddendir = 0;
8498 }
8499 #else
8500 static void
8501 xattrs_out(int (*func)())
8502 {
8503 }
8504 #endif
8505 
8506 /*
8507  * Return the parent directory of a given path.
8508  *
8509  * Examples:
8510  * /usr/tmp return /usr
8511  * /usr/tmp/file return /usr/tmp
8512  * /  returns .
8513  * /usr returns /
8514  * file returns .
8515  *
8516  * dir is assumed to be at least as big as path.
8517  */
8518 static void
8519 get_parent(char *path, char *dir)
8520 {
8521         char *s;
8522         char tmpdir[PATH_MAX + 1];
8523 
8524         if (strlen(path) > PATH_MAX) {
8525                 msg(EXT, "pathname is too long");
8526         }
8527         (void) strcpy(tmpdir, path);
8528         chop_endslashes(tmpdir);
8529 
8530         if ((s = strrchr(tmpdir, '/')) == NULL) {
8531                 (void) strcpy(dir, ".");
8532         } else {
8533                 s = skipslashes(s, tmpdir);
8534                 *s = '\0';
8535                 if (s == tmpdir)
8536                         (void) strcpy(dir, "/");
8537                 else
8538                         (void) strcpy(dir, tmpdir);
8539         }
8540 }
8541 
8542 #if defined(O_XATTR)
8543 #define ROUNDTOTBLOCK(a)                ((a + (TBLOCK -1)) & ~(TBLOCK -1))
8544 
8545 static void
8546 prepare_xattr_hdr(
8547         char            **attrbuf,
8548         char            *filename,
8549         char            *attrpath,
8550         char            typeflag,
8551         struct Lnk      *linkinfo,
8552         int             *rlen)
8553 {
8554         char                    *bufhead;       /* ptr to full buffer */
8555         char                    *aptr;
8556         struct xattr_hdr        *hptr;          /* ptr to header in bufhead */
8557         struct xattr_buf        *tptr;          /* ptr to pathing pieces */
8558         int                     totalen;        /* total buffer length */
8559         int                     len;            /* length returned to user */
8560         int                     stringlen;      /* length of filename + attr */
8561                                                 /*
8562                                                  * length of filename + attr
8563                                                  * in link section
8564                                                  */
8565         int                     linkstringlen;
8566         int                     complen;        /* length of pathing section */
8567         int                     linklen;        /* length of link section */
8568         int                     attrnames_index; /* attrnames starting index */
8569 
8570         /*
8571          * Release previous buffer if any.
8572          */
8573 
8574         if (*attrbuf != NULL) {
8575                 free(*attrbuf);
8576                 *attrbuf = NULL;
8577         }
8578 
8579         /*
8580          * First add in fixed size stuff
8581          */
8582         len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
8583 
8584         /*
8585          * Add space for two nulls
8586          */
8587         stringlen = strlen(attrpath) + strlen(filename) + 2;
8588         complen = stringlen + sizeof (struct xattr_buf);
8589 
8590         len += stringlen;
8591 
8592         /*
8593          * Now add on space for link info if any
8594          */
8595 
8596         if (linkinfo != NULL) {
8597                 /*
8598                  * Again add space for two nulls
8599                  */
8600                 linkstringlen = strlen(linkinfo->L_gen.g_attrfnam_p) +
8601                     strlen(linkinfo->L_gen.g_attrnam_p) + 2;
8602                 linklen = linkstringlen + sizeof (struct xattr_buf);
8603                 len += linklen;
8604         } else {
8605                 linklen = 0;
8606         }
8607 
8608         /*
8609          * Now add padding to end to fill out TBLOCK
8610          *
8611          * Function returns size of real data and not size + padding.
8612          */
8613 
8614         totalen = ROUNDTOTBLOCK(len);
8615         bufhead = e_zalloc(E_EXIT, totalen);
8616 
8617         /*
8618          * Now we can fill in the necessary pieces
8619          */
8620 
8621         /*
8622          * first fill in the fixed header
8623          */
8624         hptr = (struct xattr_hdr *)bufhead;
8625         (void) strcpy(hptr->h_version, XATTR_ARCH_VERS);
8626         (void) sprintf(hptr->h_component_len, "%0*d",
8627             sizeof (hptr->h_component_len) - 1, complen);
8628         (void) sprintf(hptr->h_link_component_len, "%0*d",
8629             sizeof (hptr->h_link_component_len) - 1, linklen);
8630         (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
8631 
8632         /*
8633          * Now fill in the filename + attrnames section
8634          * The filename and attrnames section can be composed of two or more
8635          * path segments separated by a null character.  The first segment
8636          * is the path to the parent file that roots the entire sequence in
8637          * the normal name space. The remaining segments describes a path
8638          * rooted at the hidden extended attribute directory of the leaf file of
8639          * the previous segment, making it possible to name attributes on
8640          * attributes.  Thus, if we are just archiving an extended attribute,
8641          * the second segment will contain the attribute name.  If we are
8642          * archiving a system attribute of an extended attribute, then the
8643          * second segment will contain the attribute name, and a third segment
8644          * will contain the system attribute name.  The attribute pathing
8645          * information is obtained from 'attrpath'.
8646          */
8647 
8648         tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
8649         (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
8650             stringlen);
8651         (void) strcpy(tptr->h_names, filename);
8652         attrnames_index = strlen(filename) + 1;
8653         (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
8654         tptr->h_typeflag = typeflag;
8655 
8656         /*
8657          * Split the attrnames section into two segments if 'attrpath'
8658          * contains pathing information for a system attribute of an
8659          * extended attribute.  We split them by replacing the '/' with
8660          * a '\0'.
8661          */
8662         if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
8663                 *aptr = '\0';
8664         }
8665 
8666         /*
8667          * Now fill in the optional link section if we have one
8668          */
8669 
8670         if (linkinfo != NULL) {
8671                 tptr = (struct xattr_buf *)(bufhead +
8672                     sizeof (struct xattr_hdr) + complen);
8673 
8674                 (void) sprintf(tptr->h_namesz, "%0*d",
8675                     sizeof (tptr->h_namesz) - 1, linkstringlen);
8676                 (void) strcpy(tptr->h_names, linkinfo->L_gen.g_attrfnam_p);
8677                 (void) strcpy(
8678                     &tptr->h_names[strlen(linkinfo->L_gen.g_attrfnam_p) + 1],
8679                     linkinfo->L_gen.g_attrnam_p);
8680                 tptr->h_typeflag = typeflag;
8681         }
8682         *attrbuf = (char *)bufhead;
8683         *rlen = len;
8684 }
8685 #endif  /* O_XATTR */
8686 
8687 static char
8688 tartype(int type)
8689 {
8690         switch (type) {
8691 
8692         case S_IFDIR:
8693                 return (DIRTYPE);
8694 
8695         case S_IFLNK:
8696                 return (SYMTYPE);
8697 
8698         case S_IFIFO:
8699                 return (FIFOTYPE);
8700 
8701         case S_IFCHR:
8702                 return (CHRTYPE);
8703 
8704         case S_IFBLK:
8705                 return (BLKTYPE);
8706 
8707         case S_IFREG:
8708                 return (REGTYPE);
8709 
8710         default:
8711                 return ('\0');
8712         }
8713 }
8714 
8715 #if defined(O_XATTR)
8716 static int
8717 openfile(int omode)
8718 {
8719         if (G_p->g_attrnam_p != NULL) {
8720                 return (openat(G_p->g_dirfd, G_p->g_attrnam_p, omode));
8721         } else {
8722                 return (openat(G_p->g_dirfd,
8723                     get_component(G_p->g_nam_p), omode));
8724         }
8725 }
8726 #else
8727 static int
8728 openfile(int omode)
8729 {
8730         return (openat(G_p->g_dirfd, get_component(G_p->g_nam_p), omode));
8731 }
8732 #endif
8733 
8734 #if defined(O_XATTR)
8735 static int
8736 read_xattr_hdr()
8737 {
8738         off_t           bytes;
8739         int             comp_len, link_len;
8740         int             namelen;
8741         int             asz;
8742         int             cnt;
8743         char            *tp;
8744         char            *xattrapath;
8745         int             pad;
8746         int             parentfilelen;
8747 
8748         /*
8749          * Include any padding in the read.  We need to be positioned
8750          * at beginning of next header.
8751          */
8752 
8753         bytes = Gen.g_filesz;
8754 
8755         if ((xattrhead = e_zalloc(E_NORMAL, (size_t)bytes)) == NULL) {
8756                 (void) fprintf(stderr, gettext(
8757                     "Insufficient memory for extended attribute\n"));
8758                 return (1);
8759         }
8760 
8761         tp = (char *)xattrhead;
8762         while (bytes > 0) {
8763                 cnt = (int)(bytes > CPIOBSZ) ? CPIOBSZ : bytes;
8764                 FILL(cnt);
8765                 (void) memcpy(tp, Buffr.b_out_p, cnt);
8766                 tp += cnt;
8767                 Buffr.b_out_p += cnt;
8768                 Buffr.b_cnt -= (off_t)cnt;
8769                 bytes -= (off_t)cnt;
8770         }
8771 
8772         pad = (Pad_val + 1 - (Gen.g_filesz & Pad_val)) &
8773             Pad_val;
8774         if (pad != 0) {
8775                 FILL(pad);
8776                 Buffr.b_out_p += pad;
8777                 Buffr.b_cnt -= (off_t)pad;
8778         }
8779 
8780         /*
8781          * Validate that we can handle header format
8782          */
8783 
8784         if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8785                 (void) fprintf(stderr,
8786                     gettext("Unknown extended attribute format encountered\n"));
8787                 (void) fprintf(stderr,
8788                     gettext("Disabling extended attribute header parsing\n"));
8789                 xattrbadhead = 1;
8790                 return (1);
8791         }
8792         (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8793         (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8794         xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8795             sizeof (struct xattr_hdr));
8796         (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8797         if (link_len > 0) {
8798                 xattr_linkp = (struct xattr_buf *)((int)xattrp + (int)comp_len);
8799         } else {
8800                 xattr_linkp = NULL;
8801         }
8802 
8803         /*
8804          * Gather the attribute path from the filename and attrnames section.
8805          * The filename and attrnames section can be composed of two or more
8806          * path segments separated by a null character.  The first segment
8807          * is the path to the parent file that roots the entire sequence in
8808          * the normal name space. The remaining segments describes a path
8809          * rooted at the hidden extended attribute directory of the leaf file of
8810          * the previous segment, making it possible to name attributes on
8811          * attributes.
8812          */
8813         parentfilelen = strlen(xattrp->h_names);
8814         xattrapath = xattrp->h_names + parentfilelen + 1;
8815         asz = strlen(xattrapath);
8816         if ((asz + parentfilelen + 2) < namelen) {
8817                 /*
8818                  * The attrnames section contains a system attribute on an
8819                  * attribute.  Save the name of the attribute for use later,
8820                  * and replace the null separating the attribute name from
8821                  * the system attribute name with a '/' so that xattrapath can
8822                  * be used to display messages with the full attribute path name
8823                  * rooted at the hidden attribute directory of the base file
8824                  * in normal name space.
8825                  */
8826                 xattrapath[asz] = '/';
8827         }
8828 
8829         return (0);
8830 }
8831 #endif
8832 
8833 static mode_t
8834 attrmode(char type)
8835 {
8836         mode_t mode;
8837 
8838         switch (type) {
8839         case '\0':
8840         case REGTYPE:
8841         case LNKTYPE:
8842                 mode = S_IFREG;
8843                 break;
8844 
8845         case SYMTYPE:
8846                 mode = S_IFLNK;
8847                 break;
8848 
8849         case CHRTYPE:
8850                 mode = S_IFCHR;
8851                 break;
8852         case BLKTYPE:
8853                 mode = S_IFBLK;
8854                 break;
8855         case DIRTYPE:
8856                 mode = S_IFDIR;
8857                 break;
8858         case FIFOTYPE:
8859                 mode = S_IFIFO;
8860                 break;
8861         case CONTTYPE:
8862         default:
8863                 mode = 0;
8864         }
8865 
8866         return (mode);
8867 }
8868 
8869 #if defined(O_XATTR)
8870 static char *
8871 get_component(char *path)
8872 {
8873         char *ptr;
8874 
8875         ptr = strrchr(path, '/');
8876         if (ptr == NULL) {
8877                 return (path);
8878         } else {
8879                 /*
8880                  * Handle trailing slash
8881                  */
8882                 if (*(ptr + 1) == '\0')
8883                         return (ptr);
8884                 else
8885                         return (ptr + 1);
8886         }
8887 }
8888 #else
8889 static char *
8890 get_component(char *path)
8891 {
8892         return (path);
8893 }
8894 #endif
8895 
8896 static int
8897 open_dir(char *name)
8898 {
8899         int fd = -1;
8900         int cnt = 0;
8901         char *dir;
8902 
8903         dir = e_zalloc(E_EXIT, strlen(name) + 1);
8904 
8905         /*
8906          * open directory; creating missing directories along the way.
8907          */
8908         get_parent(name, dir);
8909         do {
8910                 fd = open(dir, O_RDONLY);
8911                 if (fd != -1) {
8912                         free(dir);
8913                         return (fd);
8914                 }
8915                 cnt++;
8916         } while (cnt <= 1 && missdir(name) == 0);
8917 
8918         free(dir);
8919         return (-1);
8920 }
8921 
8922 static int
8923 open_dirfd()
8924 {
8925 #ifdef O_XATTR
8926         if ((Args & OCt) == 0) {
8927                 close_dirfd();
8928                 if (G_p->g_attrnam_p != NULL) {
8929                         int     rw_sysattr;
8930 
8931                         /*
8932                          * Open the file's attribute directory.
8933                          * Change into the base file's starting directory then
8934                          * call open_attr_dir() to open the attribute directory
8935                          * of either the base file (if G_p->g_attrparent_p is
8936                          * NULL) or the attribute (if G_p->g_attrparent_p is
8937                          * set) of the base file.
8938                          */
8939                         (void) fchdir(G_p->g_baseparent_fd);
8940                         (void) open_attr_dir(G_p->g_attrnam_p,
8941                             G_p->g_attrfnam_p, G_p->g_baseparent_fd,
8942                             (G_p->g_attrparent_p == NULL) ? NULL :
8943                             G_p->g_attrparent_p, &G_p->g_dirfd, &rw_sysattr);
8944                         if (Args & OCi) {
8945                                 int     saveerrno = errno;
8946 
8947                                 (void) fchdir(G_p->g_baseparent_fd);
8948                                 errno = saveerrno;
8949                         }
8950                         if ((G_p->g_dirfd == -1) && (Args & (OCi | OCp))) {
8951                                 msg(ERRN,
8952                                     "Cannot open attribute directory "
8953                                     "of %s%s%sfile \"%s\"",
8954                                     (G_p->g_attrparent_p == NULL) ? "" :
8955                                     gettext("attribute \""),
8956                                     (G_p->g_attrparent_p == NULL) ? "" :
8957                                     G_p->g_attrparent_p,
8958                                     (G_p->g_attrparent_p == NULL) ? "" :
8959                                     gettext("\" of "),
8960                                     G_p->g_attrfnam_p);
8961                                 return (FILE_PASS_ERR);
8962                         }
8963                 } else {
8964                         G_p->g_dirfd = open_dir(G_p->g_nam_p);
8965                         if (G_p->g_dirfd == -1) {
8966                                 msg(ERRN,
8967                                     "Cannot open/create %s", G_p->g_nam_p);
8968                                 return (1);
8969                         }
8970                 }
8971         } else {
8972                 G_p->g_dirfd = -1;
8973         }
8974 #else
8975         G_p->g_dirfd = -1;
8976 #endif
8977         return (0);
8978 }
8979 
8980 static void
8981 close_dirfd()
8982 {
8983         if (G_p->g_dirfd != -1) {
8984                 (void) close(G_p->g_dirfd);
8985                 G_p->g_dirfd = -1;
8986         }
8987 }
8988 
8989 static void
8990 write_xattr_hdr()
8991 {
8992         char *attrbuf = NULL;
8993         int  attrlen = 0;
8994         char *namep;
8995         struct Lnk *tl_p, *linkinfo;
8996 
8997         /*
8998          * namep was allocated in xattrs_out.  It is big enough to hold
8999          * either the name + .hdr on the end or just the attr name
9000          */
9001 
9002 #if defined(O_XATTR)
9003         namep = Gen.g_nam_p;
9004         (void) creat_hdr();
9005 
9006         if (Args & OCo) {
9007                 linkinfo = NULL;
9008                 tl_p = Lnk_hd.L_nxt_p;
9009                 while (tl_p != &Lnk_hd) {
9010                         if (tl_p->L_gen.g_ino == G_p->g_ino &&
9011                             tl_p->L_gen.g_dev == G_p->g_dev) {
9012                                         linkinfo = tl_p;
9013                                         break; /* found */
9014                         }
9015                         tl_p = tl_p->L_nxt_p;
9016                 }
9017                 prepare_xattr_hdr(&attrbuf, Gen.g_attrfnam_p,
9018                     Gen.g_attrpath_p,
9019                     (linkinfo == NULL) ?
9020                     tartype(Gen.g_mode & Ftype) : LNKTYPE,
9021                     linkinfo, &attrlen);
9022                 Gen.g_filesz = attrlen;
9023                 write_hdr(ARCHIVE_XATTR, (off_t)attrlen);
9024                 /*LINTED*/
9025                 (void) sprintf(namep, "%s/%s", DEVNULL, Gen.g_attrnam_p);
9026                 write_ancillary(attrbuf, attrlen, B_TRUE);
9027         }
9028 
9029         (void) creat_hdr();
9030 #endif
9031 }
9032 
9033 /*
9034  * skip over extra slashes in string.
9035  *
9036  * For example:
9037  * /usr/tmp/////
9038  *
9039  * would return pointer at
9040  * /usr/tmp/////
9041  *         ^
9042  */
9043 static char *
9044 skipslashes(char *string, char *start)
9045 {
9046         while ((string > start) && *(string - 1) == '/') {
9047                 string--;
9048         }
9049 
9050         return (string);
9051 }
9052 
9053 static sl_info_t *
9054 sl_info_alloc(void)
9055 {
9056         static int num_left;
9057         static sl_info_t *slipool;
9058 
9059         if (num_left > 0) {
9060                 return (&slipool[--num_left]);
9061         }
9062         num_left = SL_INFO_ALLOC_CHUNK;
9063         slipool = e_zalloc(E_EXIT, sizeof (sl_info_t) * num_left);
9064         return (&slipool[--num_left]);
9065 }
9066 
9067 /*
9068  * If a match for the key values was found in the tree, return a pointer to it.
9069  * If a match was not found, insert it and return a pointer to it.  This is
9070  * based on Knuth's Algorithm A in Vol 3, section 6.2.3.
9071  */
9072 
9073 sl_info_t *
9074 sl_insert(dev_t device, ino_t inode, int ftype)
9075 {
9076         sl_info_t *p;           /* moves down the tree */
9077         sl_info_t *q;           /* scratch */
9078         sl_info_t *r;           /* scratch */
9079         sl_info_t *s;           /* pt where rebalancing may be needed */
9080         sl_info_t *t;           /* father of s */
9081         sl_info_t *head;
9082 
9083         int a;                  /* used to hold balance factors */
9084         int done;               /* loop control */
9085         int cmpflg;             /* used to hold the result of a comparison */
9086 
9087         /* initialize */
9088 
9089         head = sl_devhash_lookup(device);
9090 
9091         if (head == NULL) {
9092                 head = sl_info_alloc();
9093                 head->llink = NULL;
9094                 head->bal = 0;
9095 
9096                 p = head->rlink = sl_info_alloc();
9097                 p->sl_ino = inode;
9098                 p->sl_ftype = ftype;
9099                 p->sl_count = 0;
9100                 p->bal = 0;
9101                 p->llink = NULL;
9102                 p->rlink = NULL;
9103                 sl_devhash_insert(device, head);
9104                 return (p);
9105         }
9106 
9107         t = head;
9108         s = p = head->rlink;
9109 
9110         /* compare */
9111 
9112         for (done = 0; ! done; ) {
9113                 switch (sl_compare(inode, ftype, p->sl_ino, p->sl_ftype)) {
9114                         case -1:
9115                                 /* move left */
9116 
9117                                 q = p->llink;
9118 
9119                                 if (q == NULL) {
9120                                         q = sl_info_alloc();
9121                                         p->llink = q;
9122                                         done = 1;
9123                                         continue;
9124                                 }
9125 
9126                                 break;
9127 
9128                         case 0:
9129                                 /* found it */
9130                                 return (p);
9131 
9132                         case 1:
9133                                 /* move right */
9134 
9135                                 q = p->rlink;
9136 
9137                                 if (q == NULL) {
9138                                         q = sl_info_alloc();
9139                                         p->rlink = q;
9140                                         done = 1;
9141                                         continue;
9142                                 }
9143 
9144                                 break;
9145                 }
9146 
9147                 if (q->bal != 0) {
9148                         t = p;
9149                         s = q;
9150                 }
9151 
9152                 p = q;
9153         }
9154 
9155         /* insert */
9156 
9157         q->sl_ino = inode;
9158         q->sl_ftype = ftype;
9159         q->sl_count = 0;
9160         q->llink = q->rlink = NULL;
9161         q->bal = 0;
9162 
9163         /* adjust balance factors */
9164 
9165         if ((cmpflg = sl_compare(inode, ftype, s->sl_ino, s->sl_ftype)) < 0) {
9166                 r = p = s->llink;
9167         } else {
9168                 r = p = s->rlink;
9169         }
9170 
9171         while (p != q) {
9172                 switch (sl_compare(inode, ftype, p->sl_ino, p->sl_ftype)) {
9173                         case -1:
9174                                 p->bal = -1;
9175                                 p = p->llink;
9176                                 break;
9177 
9178                         case 0:
9179                                 break;
9180 
9181                         case 1:
9182                                 p->bal = 1;
9183                                 p = p->rlink;
9184                                 break;
9185                 }
9186         }
9187 
9188         /* balancing act */
9189 
9190         if (cmpflg < 0) {
9191                 a = -1;
9192         } else {
9193                 a = 1;
9194         }
9195 
9196         if (s->bal == 0) {
9197                 s->bal = a;
9198                 head->llink = (sl_info_t *)((int)head->llink + 1);
9199                 return (q);
9200         } else if (s->bal == -a) {
9201                 s->bal = 0;
9202                 return (q);
9203         }
9204 
9205         /*
9206          * (s->bal == a)
9207          */
9208 
9209         if (r->bal == a) {
9210                 /* single rotation */
9211 
9212                 p = r;
9213 
9214                 if (a == -1) {
9215                         s->llink = r->rlink;
9216                         r->rlink = s;
9217                 } else if (a == 1) {
9218                         s->rlink = r->llink;
9219                         r->llink = s;
9220                 }
9221 
9222                 s->bal = r->bal = 0;
9223 
9224         } else if (r->bal == -a) {
9225                 /* double rotation */
9226 
9227                 if (a == -1) {
9228                         p = r->rlink;
9229                         r->rlink = p->llink;
9230                         p->llink = r;
9231                         s->llink = p->rlink;
9232                         p->rlink = s;
9233                 } else if (a == 1) {
9234                         p = r->llink;
9235                         r->llink = p->rlink;
9236                         p->rlink = r;
9237                         s->rlink = p->llink;
9238                         p->llink = s;
9239                 }
9240 
9241                 if (p->bal == 0) {
9242                         s->bal = 0;
9243                         r->bal = 0;
9244                 } else if (p->bal == -a) {
9245                         s->bal = 0;
9246                         r->bal = a;
9247                 } else if (p->bal == a) {
9248                         s->bal = -a;
9249                         r->bal = 0;
9250                 }
9251 
9252                 p->bal = 0;
9253         }
9254 
9255         /* finishing touch */
9256 
9257         if (s == t->rlink) {
9258                 t->rlink = p;
9259         } else {
9260                 t->llink = p;
9261         }
9262 
9263         return (q);
9264 }
9265 
9266 /*
9267  * sl_numlinks: return the number of links that we saw during our preview.
9268  */
9269 
9270 static ulong_t
9271 sl_numlinks(dev_t device, ino_t inode, int ftype)
9272 {
9273         sl_info_t *p = sl_search(device, inode, ftype);
9274 
9275         if (p) {
9276                 return (p->sl_count);
9277         } else {
9278                 return (1);
9279         }
9280 }
9281 
9282 /*
9283  * Preview extended and extended system attributes.
9284  *
9285  * Return 0 if successful, otherwise return 1.
9286  */
9287 #if defined(O_XATTR)
9288 static int
9289 preview_attrs(char *s, char *attrparent)
9290 {
9291         char            *filename = (attrparent == NULL) ? s : attrparent;
9292         int             dirfd;
9293         int             tmpfd;
9294         int             islnk;
9295         int             rc = 0;
9296         int             arc_rwsysattr = 0;
9297         int             rw_sysattr = 0;
9298         int             ext_attr = 0;
9299         DIR             *dirp;
9300         struct dirent   *dp;
9301         struct stat     sb;
9302 
9303         /*
9304          * If the underlying file system supports it, then
9305          * archive the extended attributes if -@ was specified,
9306          * and the extended system attributes if -/ was
9307          * specified.
9308          */
9309         if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
9310             &ext_attr) != ATTR_OK) {
9311                 return (1);
9312         }
9313 
9314 #if defined(_PC_SATTR_ENABLED)
9315         if (SysAtflag) {
9316                 int             filefd;
9317                 nvlist_t        *slist = NULL;
9318 
9319                 /* Determine if there are non-transient system attributes. */
9320                 errno = 0;
9321                 if ((filefd = open(filename, O_RDONLY)) < 0) {
9322                         return (1);
9323                 }
9324                 if (((slist = sysattr_list(myname, filefd,
9325                     filename)) != NULL) || (errno != 0)) {
9326                         arc_rwsysattr = 1;
9327                 }
9328                 if (slist != NULL) {
9329                         (void) nvlist_free(slist);
9330                         slist = NULL;
9331                 }
9332                 (void) close(filefd);
9333         }
9334 
9335         if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
9336             (SysAtflag && !ext_attr))) {
9337                 return (1);
9338         }
9339 #endif  /* _PC_SATTR_ENABLED */
9340         /*
9341          * We need to open the attribute directory of the
9342          * file, and preview all of the file's attributes as
9343          * attributes of the file can be hard links to other
9344          * attributes of the file.
9345          */
9346         dirfd = attropen(filename, ".", O_RDONLY);
9347         if (dirfd == -1)
9348                 return (1);
9349 
9350         tmpfd = dup(dirfd);
9351         if (tmpfd == -1) {
9352                 (void) close(dirfd);
9353                 return (1);
9354         }
9355         dirp = fdopendir(tmpfd);
9356         if (dirp == NULL) {
9357                 (void) close(dirfd);
9358                 (void) close(tmpfd);
9359                 return (1);
9360         }
9361 
9362         while (dp = readdir(dirp)) {
9363                 if (dp->d_name[0] == '.') {
9364                         if (dp->d_name[1] == '\0') {
9365                                 Hiddendir = 1;
9366                         } else if ((dp->d_name[1] == '.') &&
9367                             (dp->d_name[2] == '\0')) {
9368                                 continue;
9369                         } else {
9370                                 Hiddendir = 0;
9371                         }
9372                 } else {
9373                         Hiddendir = 0;
9374                 }
9375 
9376                 if (fstatat(dirfd, dp->d_name, &sb,
9377                     AT_SYMLINK_NOFOLLOW) < 0) {
9378                         continue;
9379                 }
9380 
9381                 if (verify_attr(dp->d_name, attrparent,
9382                     arc_rwsysattr, &rw_sysattr) != ATTR_OK) {
9383                         continue;
9384                 }
9385 
9386                 islnk = 0;
9387                 if (S_ISLNK(sb.st_mode)) {
9388                         islnk = 1;
9389                         if (Args & OCL) {
9390                                 if (fstatat(dirfd, dp->d_name,
9391                                     &sb, 0) < 0) {
9392                                         continue;
9393                                 }
9394                         }
9395                 }
9396                 sl_remember_tgt(&sb, islnk, rw_sysattr);
9397 
9398                 /*
9399                  * Recursively call preview_attrs() to preview extended
9400                  * system attributes of attributes.
9401                  */
9402                 if (SysAtflag && !Hiddendir && !rw_sysattr) {
9403                         int     my_cwd = save_cwd();
9404 
9405                         (void) fchdir(dirfd);
9406                         rc = preview_attrs(s, dp->d_name);
9407                         rest_cwd(my_cwd);
9408                 }
9409         }
9410         (void) closedir(dirp);
9411         (void) close(dirfd);
9412         return (rc);
9413 }
9414 #endif  /* O_XATTR */
9415 
9416 /*
9417  * sl_preview_synonyms:  Read the file list from the input stream, remembering
9418  * each reference to each file.
9419  */
9420 
9421 static void
9422 sl_preview_synonyms(void)
9423 {
9424         char buf [APATH+1];
9425         char *s;
9426 
9427         char *suffix = "/cpioXXXXXX";
9428         char *tmpdir = getenv("TMPDIR");
9429         int    tmpfd, islnk;
9430         FILE *tmpfile;
9431         char *tmpfname;
9432 
9433         if (tmpdir == NULL || *tmpdir == '\0' ||
9434             (strlen(tmpdir) + strlen(suffix)) > APATH) {
9435                 struct statvfs tdsb;
9436 
9437                 tmpdir = "/var/tmp";
9438 
9439                 /* /var/tmp is read-only in the mini-root environment */
9440 
9441                 if (statvfs(tmpdir, &tdsb) == -1 || tdsb.f_flag & ST_RDONLY) {
9442                         tmpdir = "/tmp";
9443                 }
9444         }
9445 
9446         tmpfname = e_zalloc(E_EXIT, strlen(tmpdir) + strlen(suffix) + 1);
9447 
9448         (void) strcpy(tmpfname, tmpdir);
9449         (void) strcat(tmpfname, suffix);
9450 
9451         if ((tmpfd = mkstemp(tmpfname)) == -1) {
9452                 msg(EXTN, "cannot open tmpfile %s%s", tmpdir, suffix);
9453         }
9454 
9455         if (unlink(tmpfname) == -1) {
9456                 msg(EXTN, "cannot unlink tmpfile %s", tmpfname);
9457         }
9458 
9459         if ((tmpfile = fdopen(tmpfd, "w+")) == NULL) {
9460                 msg(EXTN, "cannot fdopen tmpfile %s", tmpfname);
9461         }
9462 
9463         while ((s = fgets(buf, APATH+1, In_p)) != NULL) {
9464                 size_t lastchar;
9465                 struct stat sb;
9466 
9467                 if (fputs(buf, tmpfile) == EOF) {
9468                         msg(EXTN, "problem writing to tmpfile %s", tmpfname);
9469                 }
9470 
9471                 /* pre-process the name */
9472 
9473                 lastchar = strlen(s) - 1;
9474 
9475                 if (s[lastchar] != '\n' && lastchar == APATH - 1) {
9476                         continue;
9477                 } else {
9478                         s[lastchar] = '\0';
9479                 }
9480 
9481                 while (s[0] == '.' && s[1] == '/') {
9482                         s += 2;
9483                         while (s[0] == '/') {
9484                                 s++;
9485                         }
9486                 }
9487 
9488                 if (lstat(s, &sb) < 0) {
9489                         continue;
9490                 }
9491                 islnk = 0;
9492                 if (S_ISLNK(sb.st_mode)) {
9493                         islnk = 1;
9494                         if (Args & OCL) {
9495                                 if (stat(s, &sb) < 0) {
9496                                         continue;
9497                                 }
9498                         }
9499                 }
9500                 sl_remember_tgt(&sb, islnk, 0);
9501 
9502 #if defined(O_XATTR)
9503                 if (Atflag || SysAtflag) {
9504                         (void) preview_attrs(s, NULL);
9505                 }
9506 #endif  /* O_XATTR */
9507         }
9508 
9509         if (ferror(In_p)) {
9510                 msg(EXTN, "error reading stdin");
9511         }
9512 
9513         if (fseek(tmpfile, 0L, SEEK_SET) == -1) {
9514                 msg(EXTN, "cannot fseek on tmpfile %s", tmpfname);
9515         }
9516 
9517         In_p = tmpfile;
9518         free(tmpfname);
9519 }
9520 
9521 /*
9522  * sl_remember_tgt: Add the device/inode for lstat or stat info to the list of
9523  * those we've seen before.
9524  *
9525  * This tree (rooted under head) is keyed by the device/inode of the file
9526  * being pointed to.  A count is kept of the number of references encountered
9527  * so far.
9528  */
9529 
9530 static void
9531 sl_remember_tgt(const struct stat *sbp, int isSymlink, int is_sysattr)
9532 {
9533         sl_info_t *p;
9534         dev_t device;
9535         ino_t inode;
9536         int ftype;
9537 
9538         device = sbp->st_dev;
9539         inode  = sbp->st_ino;
9540         ftype  = sbp->st_mode & Ftype;
9541 
9542         /* Determine whether we've seen this one before */
9543 
9544         p = sl_insert(device, inode, ftype);
9545 
9546         if (p->sl_count > 0) {
9547                 /*
9548                  * It appears as if have seen this file before as we found a
9549                  * matching device, inode, and file type as a file already
9550                  * processed.  Since there can possibly be files with the
9551                  * same device, inode, and file type, but aren't hard links
9552                  * (e.g., read-write system attribute files will always have
9553                  * the same inode), we need to only attempt to add one to the
9554                  * link count if the file we are processing is a hard link
9555                  * (i.e., st_nlink > 1).
9556                  *
9557                  * Note that if we are not chasing symlinks, and this one is a
9558                  * symlink, it is identically the one we saw before (you cannot
9559                  * have hard links to symlinks); in this case, we leave the
9560                  * count alone, so that we don't wind up archiving a symlink to
9561                  * itself.
9562                  */
9563 
9564                 if (((Args & OCL) || (! isSymlink)) && !is_sysattr) {
9565                         p->sl_count++;
9566                 }
9567         } else {
9568                 /* We have not seen this file before */
9569 
9570                 p->sl_count = 1;
9571 
9572                 if (Use_old_stat) {
9573                         /* -Hodc: remap inode (-1 on overflow) */
9574 
9575                         sl_remap_t  *q;
9576 
9577                         for (q = sl_remap_head; q && (q->dev != device);
9578                             q = q->next) {
9579                                 /* do nothing */
9580                         }
9581 
9582                         if (q == NULL) {
9583                                 q = e_zalloc(E_EXIT, sizeof (sl_remap_t));
9584                                 q->dev = device;
9585                                 p->sl_ino2 = q->inode_count = 1;
9586 
9587                                 q->next = (sl_remap_head) ?
9588                                     sl_remap_head->next : NULL;
9589                                 sl_remap_head = q;
9590                         } else {
9591                                 if ((size_t)q->inode_count <=
9592                                     ((1 << (sizeof (o_ino_t) * 8)) - 1)) {
9593                                         /* fits in o_ino_t */
9594                                         p->sl_ino2 = ++(q->inode_count);
9595                                 } else {
9596                                         p->sl_ino2 = (ino_t)-1;
9597                                 }
9598                         }
9599                 }
9600         }
9601 }
9602 
9603 /*
9604  * A faster search, which does not insert the key values into the tree.
9605  * If the a match was found in the tree, return a pointer to it.  If it was not
9606  * found, return NULL.
9607  */
9608 
9609 sl_info_t *
9610 sl_search(dev_t device, ino_t inode, int ftype)
9611 {
9612         sl_info_t *p;           /* moves down the tree */
9613         int c;                  /* comparison value */
9614         sl_info_t *retval = NULL; /* return value */
9615         sl_info_t *head;
9616 
9617         head = sl_devhash_lookup(device);
9618         if (head != NULL) {
9619                 for (p = head->rlink; p; ) {
9620                         if ((c = sl_compare(inode, ftype, p->sl_ino,
9621                             p->sl_ftype)) == 0) {
9622                                 retval = p;
9623                                 break;
9624                         } else if (c < 0) {
9625                                 p = p->llink;
9626                         } else {
9627                                 p = p->rlink;
9628                         }
9629                 }
9630         }
9631 
9632         return (retval);
9633 }
9634 
9635 static sl_info_t *
9636 sl_devhash_lookup(dev_t device)
9637 {
9638         int key;
9639         sl_info_link_t *lp;
9640         static sl_info_link_t *devcache;
9641 
9642         if (devcache != NULL && devcache->dev == device) {
9643                 return (devcache->head);
9644         }
9645 
9646         key = DEV_HASHKEY(device);
9647         for (lp = sl_devhash[key]; lp; lp = lp->next) {
9648                 if (lp->dev == device) {
9649                         devcache = lp;
9650                         return (lp->head);
9651                 }
9652         }
9653         return (NULL);
9654 }
9655 
9656 static void
9657 sl_devhash_insert(dev_t device, sl_info_t *head)
9658 {
9659         int key = DEV_HASHKEY(device);
9660         sl_info_link_t *lp;
9661 
9662         lp = e_zalloc(E_EXIT, sizeof (sl_info_link_t));
9663         lp->dev = device;
9664         lp->head = head;
9665         lp->next = sl_devhash[key];
9666         sl_devhash[key] = lp;
9667 }
9668 
9669 static void
9670 chop_endslashes(char *path)
9671 {
9672         char *end, *ptr;
9673 
9674         end = &path[strlen(path) -1];
9675         if (*end == '/' && end != path) {
9676                 ptr = skipslashes(end, path);
9677                 if (ptr != NULL && ptr != path) {
9678                         *ptr = '\0';
9679                 }
9680         }
9681 }
9682 
9683 #if !defined(O_XATTR)
9684 int
9685 openat64(int fd, char *name, int oflag, mode_t cmode)
9686 {
9687         return (open64(name, oflag, cmode));
9688 }
9689 
9690 int
9691 openat(int fd, char *name, int oflag, mode_t cmode)
9692 {
9693         return (open(name, oflag, cmode));
9694 }
9695 
9696 int
9697 fchownat(int fd, char *name, uid_t owner, gid_t group, int flag)
9698 {
9699         if (flag == AT_SYMLINK_NOFOLLOW)
9700                 return (lchown(name, owner, group));
9701         else
9702                 return (chown(name, owner, group));
9703 }
9704 
9705 int
9706 renameat(int fromfd, char *old, int tofd, char *new)
9707 {
9708         return (rename(old, new));
9709 }
9710 
9711 int
9712 futimesat(int fd, char *path, struct timeval times[2])
9713 {
9714         return (utimes(path, times));
9715 }
9716 
9717 int
9718 unlinkat(int dirfd, char *path, int flag)
9719 {
9720         if (flag == AT_REMOVEDIR) {
9721                 return (rmdir(path));
9722         } else {
9723                 return (unlink(path));
9724         }
9725 }
9726 
9727 int
9728 fstatat(int fd, char *path, struct stat *buf, int flag)
9729 {
9730         if (flag == AT_SYMLINK_NOFOLLOW)
9731                 return (lstat(path, buf));
9732         else
9733                 return (stat(path, buf));
9734 }
9735 
9736 int
9737 attropen(char *file, char *attr, int omode, mode_t cmode)
9738 {
9739         errno = ENOTSUP;
9740         return (-1);
9741 }
9742 #endif