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