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