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