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