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