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