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