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