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.
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.
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]
22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 * Copyright (c) 2012 Gary Mills
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
36 #include <sys/types.h>
45 #include <sys/statvfs.h>
46 #include <sys/mkdev.h>
47 #include <sys/param.h>
54 #include <sys/ioctl.h>
60 #include <sys/resource.h>
67 #if defined(_PC_SATTR_ENABLED)
68 #include <libnvpair.h>
70 #include <libcmdutils.h>
71 #endif /* _PC_SATTR_ENABLED */
74 #endif /* SOLARIS_PRIVS */
77 * Special kludge for off_t being a signed quantity.
79 #if _FILE_OFFSET_BITS == 64
80 typedef u_longlong_t u_off_t
;
82 typedef ulong_t u_off_t
;
85 #define SECMODE 0xe080
87 #define DEVNULL "/dev/null"
88 #define XATTRHDR ".hdr"
96 #define FILE_PASS_ERR -1
98 #define ARCHIVE_NORMAL 0
100 #define ARCHIVE_XATTR 2
101 #define ARCHIVE_SPARSE 3
103 #ifndef VIEW_READONLY
104 #define VIEW_READONLY "SUNWattr_ro"
107 #ifndef VIEW_READWRITE
108 #define VIEW_READWRITE "SUNWattr_rw"
112 #define LSTAT(dir, path, statbuf) fstatat(dir, \
113 get_component((Gen.g_attrnam_p == NULL) ? \
114 path : Gen.g_attrnam_p), statbuf, AT_SYMLINK_NOFOLLOW)
115 #define STAT(dir, path, statbuf) fstatat(dir, \
116 get_component((Gen.g_attrnam_p == NULL) ? \
117 path : Gen.g_attrnam_p), statbuf, 0)
120 * These limits reflect the maximum size regular file that
121 * can be archived, depending on the archive type. For archives
122 * with character-format headers (odc, tar, ustar) we use
123 * CHAR_OFFSET_MAX. For archives with SVR4 ASCII headers (-c, -H crc)
124 * we store filesize in an 8-char hexadecimal string and use
125 * ASC_OFFSET_MAX. Otherwise, we are limited to the size that will
126 * fit in a signed long value.
128 #define CHAR_OFFSET_MAX 077777777777ULL /* 11 octal digits */
129 #define ASC_OFFSET_MAX 0XFFFFFFFF /* 8 hexadecimal digits */
130 #define BIN_OFFSET_MAX LONG_MAX /* signed long max value */
132 #define POSIXMODES 07777
134 static char aclchar
= ' ';
136 static struct Lnk
*add_lnk(struct Lnk
**);
137 static int bfill(void);
138 static void bflush(void);
139 static int chgreel(int dir
);
140 static int ckname(int);
141 static void ckopts(long mask
);
142 static long cksum(char hdr
, int byt_cnt
, int *err
);
143 static int creat_hdr(void);
144 static int creat_lnk(int dirfd
, char *name1_p
, char *name2_p
);
145 static int creat_spec(int dirfd
);
146 static int creat_tmp(char *nam_p
);
147 static void data_in(int proc_mode
);
148 static void data_out(void);
149 static void data_pass(void);
150 static void file_in(void);
151 static int file_out(void);
152 static int file_pass(void);
153 static void flush_lnks(void);
154 static int gethdr(void);
155 static int getname(void);
156 static void getpats(int largc
, char **largv
);
157 static void ioerror(int dir
);
158 static int matched(void);
159 static int missdir(char *nam_p
);
160 static long mklong(short v
[]);
161 static void mkshort(short sval
[], long v
);
162 static int openout(int dirfd
);
163 static int read_hdr(int hdr
);
164 static void reclaim(struct Lnk
*l_p
);
165 static void rstbuf(void);
166 static void setpasswd(char *nam
);
167 static void rstfiles(int over
, int dirfd
);
168 static void scan4trail(void);
169 static void setup(int largc
, char **largv
);
170 static void set_tym(int dirfd
, char *nam_p
, time_t atime
, time_t mtime
);
171 static void sigint(int sig
);
172 static void swap(char *buf_p
, int cnt
);
173 static void usage(void);
174 static void verbose(char *nam_p
);
175 static void write_hdr(int arcflag
, off_t len
);
176 static void write_trail(void);
177 static int ustar_dir(void);
178 static int ustar_spec(void);
179 static struct stat
*convert_to_old_stat(struct stat
*, char *, char *);
180 static void read_bar_vol_hdr(void);
181 static void read_bar_file_hdr(void);
182 static void setup_uncompress(FILE **);
183 static void skip_bar_volhdr(void);
184 static void bar_file_in(void);
185 static int g_init(int *devtype
, int *fdes
);
186 static int g_read(int, int, char *, unsigned);
187 static int g_write(int, int, char *, unsigned);
188 static int is_floppy(int);
189 static int is_tape(int);
190 static void write_ancillary(char *buf
, size_t len
, boolean_t padding
);
191 static int remove_dir(char *);
192 static int save_cwd(void);
193 static void rest_cwd(int cwd
);
195 static void xattrs_out(int (*func
)());
196 static void get_parent(char *path
, char *dir
);
197 static void prepare_xattr_hdr(char **attrbuf
, char *filename
,
198 char *attrname
, char typeflag
, struct Lnk
*linkinfo
, int *rlen
);
199 static char tartype(int type
);
200 static int openfile(int omode
);
201 static mode_t
attrmode(char type
);
202 static char *get_component(char *path
);
203 static int open_dir(char *name
);
204 static int open_dirfd();
205 static void close_dirfd();
206 static void write_xattr_hdr();
207 static char *skipslashes(char *string
, char *start
);
208 static int read_xattr_hdr();
209 static void chop_endslashes(char *path
);
215 struct passwd
*Curpw_p
, /* Current password entry for -t option */
216 *Rpw_p
, /* Password entry for -R option */
220 struct group
*Curgr_p
, /* Current group entry for -t option */
223 /* Data structure for buffered I/O. */
227 char *b_base_p
, /* Pointer to base of buffer */
228 *b_out_p
, /* Position to take bytes from buffer at */
229 *b_in_p
, /* Position to put bytes into buffer at */
230 *b_end_p
; /* Pointer to end of buffer */
231 long b_cnt
, /* Count of unprocessed bytes */
232 b_size
; /* Size of buffer in bytes */
235 /* Generic header format */
239 ulong_t g_magic
, /* Magic number field */
240 g_ino
, /* Inode number of file */
241 g_mode
, /* Mode of file */
242 g_uid
, /* Uid of file */
243 g_gid
, /* Gid of file */
244 g_nlink
, /* Number of links */
245 g_mtime
; /* Modification time */
246 off_t g_filesz
; /* Length of file */
247 ulong_t g_dev
, /* File system of file */
248 g_rdev
, /* Major/minor numbers of special files */
249 g_namesz
, /* Length of filename */
250 g_cksum
; /* Checksum of file */
258 *g_nam_p
, /* Filename */
259 *g_attrparent_p
, /* attribute parent */
260 *g_attrpath_p
, /* attribute path */
261 *g_attrnam_p
, /* attribute */
262 *g_attrfnam_p
, /* Real file name attr belongs to */
263 *g_linktoattrfnam_p
, /* file linked attribute belongs to */
264 *g_linktoattrnam_p
, /* attribute g_attrnam_p is linked to */
265 *g_dirpath
; /* dirname currently opened */
266 int g_dirfd
; /* directory file descriptor */
267 int g_passdirfd
; /* directory fd to pass to */
268 int g_rw_sysattr
; /* read-write system attribute */
269 int g_baseparent_fd
; /* base file's parent fd */
270 holes_info_t
*g_holes
; /* sparse file information */
274 /* Data structure for handling multiply-linked files */
276 char prebuf
[PRESIZ
+1],
283 short L_cnt
, /* Number of links encountered */
284 L_data
; /* Data has been encountered if 1 */
285 struct gen_hdr L_gen
; /* gen_hdr information for this file */
286 struct Lnk
*L_nxt_p
, /* Next file in list */
287 *L_bck_p
, /* Previous file in list */
288 *L_lnk_p
; /* Next link for this file */
295 * -------------------------------------------------------------------------
296 * Stuff needed to pre-view the name stream
298 * issymlink is used to remember that the current file is a symlink between
299 * getname() and file_pass(); the former trashes this information immediately
300 * when -L is specified.
307 FILE *In_p
; /* Where the input comes from */
309 typedef struct sl_info
311 struct sl_info
*llink
; /* Left subtree ptr (tree depth in *sl_head) */
312 struct sl_info
*rlink
; /* Right subtree ptr */
313 int bal
; /* Subtree balance factor */
314 ulong_t sl_count
; /* Number of symlinks */
315 int sl_ftype
; /* file type of inode */
316 ino_t sl_ino
; /* Inode of file */
317 ino_t sl_ino2
; /* alternate inode for -Hodc */
320 typedef struct data_in
323 char data_in_swapfile
;
324 char data_in_proc_mode
;
326 char data_in_wr_part
;
327 char data_in_compress_flag
;
328 long data_in_cksumval
;
333 * The following structure maintains a hash entry for the
334 * balancing trees which are allocated for each device nodes.
336 typedef struct sl_info_link
340 struct sl_info_link
*next
;
343 #define SL_INFO_ALLOC_CHUNK 1024
344 #define NDEVHENTRY 0x40
345 #define DEV_HASHKEY(x) ((x) & (NDEVHENTRY -1))
348 * For remapping dev,inode for -Hodc archives.
351 typedef struct sl_remap
353 dev_t dev
; /* device */
354 int inode_count
; /* # inodes seen on dev */
355 struct sl_remap
*next
; /* next in the chain */
358 /* forward declarations */
360 static sl_info_t
*sl_info_alloc(void);
361 static sl_info_t
*sl_insert(dev_t
, ino_t
, int);
362 static ulong_t
sl_numlinks(dev_t
, ino_t
, int);
363 static void sl_preview_synonyms(void);
364 static void sl_remember_tgt(const struct stat
*, int, int);
365 static sl_info_t
*sl_search(dev_t
, ino_t
, int);
366 static sl_info_t
*sl_devhash_lookup(dev_t
);
367 static void sl_devhash_insert(dev_t
, sl_info_t
*);
369 extern int sl_compare(ino_t
, int, ino_t
, int);
370 #define sl_compare(lino, lftype, rino, rftype) (lino < rino ? -1 : \
371 (lino > rino ? 1 : (lftype < rftype ? -1 : \
372 (lftype > rftype ? 1 : 0))))
376 static sl_remap_t
*sl_remap_head
= NULL
; /* head of the inode-remap list */
377 static sl_info_link_t
*sl_devhash
[NDEVHENTRY
]; /* hash table */
380 * -------------------------------------------------------------------------
384 struct stat ArchSt
, /* stat(2) information of the archive */
385 SrcSt
, /* stat(2) information of source file */
386 DesSt
, /* stat(2) of destination file */
387 *OldSt
= NULL
; /* stat info converted to svr32 format */
390 * bin_mag: Used to validate a binary magic number,
391 * by combining to bytes into an unsigned short.
396 unsigned char b_byte
[2];
401 union tblock
*Thdr_p
; /* TAR header pointer */
403 static union b_block
*bar_Vhdr
;
404 static struct gen_hdr Gen_bar_vol
;
407 * swpbuf: Used in swap() to swap bytes within a halfword,
408 * halfwords within a word, or to reverse the order of the
409 * bytes within a word. Also used in mklong() and mkshort().
414 unsigned char s_byte
[4];
420 char *myname
, /* program name */
421 Adir
, /* Flags object as a directory */
422 Hiddendir
, /* Processing hidden attribute directory */
423 Aspec
, /* Flags object as a special file */
424 Do_rename
, /* Indicates rename() is to be used */
425 Time
[50], /* Array to hold date and time */
426 Ttyname
[] = "/dev/tty", /* Controlling console */
427 T_lname
[MAXPATHLEN
], /* Array to hold links name for tar */
428 *Buf_p
, /* Buffer for file system I/O */
429 *Full_p
, /* Pointer to full pathname */
430 *Efil_p
, /* -E pattern file string */
431 *Eom_p
= "Change to part %d and press RETURN key. [q] ",
432 *Fullnam_p
, /* Full pathname */
433 *Attrfile_p
, /* attribute file */
434 *Hdr_p
, /* -H header type string */
435 *IOfil_p
, /* -I/-O input/output archive string */
436 *Lnkend_p
, /* Pointer to end of Lnknam_p */
437 *Lnknam_p
, /* Buffer for linking files with -p option */
438 *Nam_p
, /* Array to hold filename */
439 *Savenam_p
, /* copy of filename xattr belongs to */
440 *Own_p
, /* New owner login id string */
441 *Renam_p
, /* Buffer for renaming files */
442 *Renam_attr_p
, /* Buffer for renaming attr with sys attrs */
443 *Renametmp_p
, /* Tmp Buffer for renaming files */
444 *Symlnk_p
, /* Buffer for holding symbolic link name */
445 *Over_p
, /* Holds temporary filename when overwriting */
446 **Pat_pp
= 0, /* Pattern strings */
447 bar_linkflag
, /* flag to indicate if the file is a link */
448 bar_linkname
[MAXPATHLEN
]; /* store the name of the link */
451 int Append
= 0, /* Flag set while searching to end of archive */
452 Archive
, /* File descriptor of the archive */
453 Buf_error
= 0, /* I/O error occurred during buffer fill */
454 Compress_sparse
= 0, /* Compress sparse files */
455 Def_mode
= 0777, /* Default file/directory protection modes */
456 Device
, /* Device type being accessed (used with libgenIO) */
457 Error_cnt
= 0, /* Cumulative count of I/O errors */
458 Finished
= 1, /* Indicates that a file transfer has completed */
459 Hdrsz
= ASCSZ
, /* Fixed length portion of the header */
460 Hdr_type
, /* Flag to indicate type of header selected */
461 Ifile
, /* File des. of file being archived */
462 Ofile
, /* File des. of file being extracted from archive */
463 Use_old_stat
= 0, /* Create an old style -Hodc hdr (small dev's) */
464 Onecopy
= 0, /* Flags old vs. new link handling */
465 Pad_val
= 0, /* Indicates the number of bytes to pad (if any) */
466 PageSize
= 0, /* The native page size, used for figuring block size */
467 Volcnt
= 1, /* Number of archive volumes processed */
468 Verbcnt
= 0, /* Count of number of dots '.' output */
471 Atflag
= 0, /* Archive/restore extended attributes */
472 SysAtflag
= 0, /* Archive/restore extended system attributes */
473 Compressed
, /* Flag to indicate if the bar archive is compressed */
474 Bar_vol_num
= 0, /* Volume number count for bar archive */
475 privileged
= 0, /* Flag set if running with higher privileges */
476 attr_baseparent_fd
= -1; /* attribute's base file descriptor */
480 gid_t Lastgid
= (gid_t
)-1; /* Used with -t & -v to record current gid */
483 uid_t Lastuid
= (uid_t
)-1; /* Used with -t & -v to record current uid */
486 long Args
, /* Mask of selected options */
487 Max_namesz
= CPATH
; /* Maximum size of pathnames/filenames */
490 int Bufsize
= BUFSZ
; /* Default block size */
493 static u_longlong_t Blocks
; /* full blocks transferred */
494 static u_longlong_t SBlocks
; /* cumulative char count from short reads */
497 static off_t Max_offset
= BIN_OFFSET_MAX
; /* largest file size */
498 static off_t Max_filesz
; /* from getrlimit */
500 static ulong_t Savedev
;
503 FILE *Ef_p
, /* File pointer of pattern input file */
504 *Err_p
, /* File pointer for error reporting */
505 *Out_p
, /* File pointer for non-archive output */
506 *Rtty_p
, /* Input file pointer for interactive rename */
507 *Wtty_p
; /* Output file ptr for interactive rename */
510 ushort_t Ftype
= S_IFMT
; /* File type mask */
513 static struct sec_attr
{
519 static int Pflag
= 0; /* flag indicates that acl is preserved */
520 static int acl_is_set
= 0; /* True if an acl was set on the file */
545 * cpio has been changed to support extended attributes.
547 * As part of this change cpio has been changed to use the new *at() syscalls
548 * such as openat, fchownat(), unlinkat()...
550 * This was done so that attributes can be handled with as few code changes
553 * What this means is that cpio now opens the directory that a file or directory
554 * resides in and then performs *at() functions to manipulate the entry.
556 * For example a new file is now created like this:
558 * dfd = open(<some dir path>)
559 * fd = openat(dfd, <name>,....);
561 * or in the case of an extended attribute
563 * dfd = attropen(<pathname>, ".", ....)
565 * Once we have a directory file descriptor all of the *at() functions can
568 * unlinkat(dfd, <component name>,...)
569 * fchownat(dfd, <component name>,..)
571 * This works for both normal namespace files and extended attribute file
576 * Extended attribute layout
578 * Extended attributes are stored in two pieces.
579 * 1. An attribute header which has information about
580 * what file the attribute is for and what the attribute
582 * 2. The attribute record itself. Stored as a normal file type
584 * Both the header and attribute record have special modes/typeflags
585 * associated with them.
587 * The names of the header in the archive look like:
590 * The name of the attribute looks like:
593 * This is done so that an archiver that doesn't understand these formats
594 * can just dispose of the attribute records unless the user chooses to
595 * rename them via cpio -r or pax -i
597 * The format is composed of a fixed size header followed
598 * by a variable sized xattr_buf. If the attribute is a hard link
599 * to another attribute, then another xattr_buf section is included
602 * The xattr_buf is used to define the necessary "pathing" steps
603 * to get to the extended attribute. This is necessary to support
604 * a fully recursive attribute model where an attribute may itself
607 * The basic layout looks like this.
609 * --------------------------------
613 * --------------------------------
614 * --------------------------------
618 * --------------------------------
619 * --------------------------------
621 * | (optional link info) |
623 * --------------------------------
624 * --------------------------------
626 * | attribute itself |
627 * | stored as normal tar |
628 * | or cpio data with |
629 * | special mode or |
632 * --------------------------------
637 * Extended attributes structures
639 * xattrhead is the complete extended attribute header, as read of off
640 * disk/tape. It includes the variable xattr_buf portion.
642 * xattrp is basically an offset into xattrhead that points to the
643 * "pathing" section which defines how to get to the attribute.
645 * xattr_linkp is identical to xattrp except that it is used for linked
646 * attributes. It provides the pathing steps to get to the linked
649 * These structures are updated when an extended attribute header is read off
652 static struct xattr_hdr
*xattrhead
;
653 static struct xattr_buf
*xattrp
;
654 static struct xattr_buf
*xattr_linkp
;
655 static int xattrbadhead
; /* is extended attribute header bad? */
657 static int append_secattr(char **, int *, acl_t
*);
660 * Note regarding cpio and changes to ensure cpio doesn't try to second
661 * guess whether it runs with sufficient privileges or not:
663 * cpio has been changed so that it doesn't carry a second implementation of
664 * the kernel's policy with respect to privileges. Instead of attempting
665 * to restore uid and gid from an archive only if cpio is run as uid 0,
666 * cpio now *always* tries to restore the uid and gid from the archive
667 * except when the -R option is specified. When the -R is specified,
668 * the uid and gid of the restored file will be changed to those of the
669 * login id specified. In addition, chown(), set_tym(), and chmod() should
670 * only be executed once during archive extraction, and to ensure
671 * setuid/setgid bits are restored properly, chown() should always be
672 * executed before chmod().
674 * Note regarding debugging mechanism for cpio:
676 * The following mechanism is provided to allow us to debug cpio in complicated
677 * situations, like when it is part of a pipe. The idea is that you compile
678 * with -DWAITAROUND defined, and then add the "-z" command line option to the
679 * target cpio invocation. If stderr is available, it will tell you to which
680 * pid to attach the debugger; otherwise, use ps to find it. Attach to the
681 * process from the debugger, and, *PRESTO*, you are there!
683 * Simply assign "waitaround = 0" once you attach to the process, and then
684 * proceed from there as usual.
688 int waitaround
= 0; /* wait for rendezvous with the debugger */
691 #define EXIT_CODE (Error_cnt > 255 ? 255 : Error_cnt)
694 * main: Call setup() to process options and perform initializations,
695 * and then select either copy in (-i), copy out (-o), or pass (-p) action.
699 main(int argc
, char **argv
)
708 (void) setlocale(LC_ALL
, "");
709 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
710 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
712 (void) textdomain(TEXT_DOMAIN
);
714 (void) memset(&Gen
, 0, sizeof (Gen
));
715 myname
= e_strdup(E_EXIT
, basename(argv
[0]));
718 if (signal(SIGINT
, sigint
) == SIG_IGN
)
719 (void) signal(SIGINT
, SIG_IGN
);
720 switch (Args
& (OCi
| OCo
| OCp
)) {
721 case OCi
: /* COPY IN */
723 if (Atflag
|| SysAtflag
) {
725 * Save the current working directory, so
726 * we can change back here after cd'ing into
727 * the attribute directory when processing
730 if ((attr_baseparent_fd
= save_cwd()) < 0) {
731 msg(EXT
, "Unable to open current directory.");
734 while ((i
= gethdr()) != 0) {
739 * Any ACL info for this file would or should
740 * have been used after file_in(); clear out
741 * aclp so it is is not erroneously used on
750 (void) memset(&Gen
, 0, sizeof (Gen
));
752 /* Do not count "extra" "read-ahead" buffered data */
753 if (Buffr
.b_cnt
> Bufsize
)
754 Blocks
-= (u_longlong_t
)(Buffr
.b_cnt
/ Bufsize
);
756 case OCo
: /* COPY OUT */
762 Gen
.g_dirpath
= NULL
;
763 sl_preview_synonyms();
765 while ((i
= getname()) != 0) {
768 if (Atflag
|| SysAtflag
) {
769 if (Gen
.g_dirfd
!= -1) {
770 (void) close(Gen
.g_dirfd
);
773 xattrs_out(file_out
);
785 sl_preview_synonyms();
788 Gen
.g_passdirfd
= -1;
789 Gen
.g_dirpath
= NULL
;
793 * If file is a fully qualified path then
794 * file_pass will strip off the leading '/'
795 * and we need to save off the unstripped
796 * name for attribute traversal.
798 if (Atflag
|| SysAtflag
) {
799 (void) strcpy(Savenam_p
, Gen
.g_nam_p
);
801 passret
= file_pass();
807 if (Gen
.g_passdirfd
!= -1)
808 (void) close(Gen
.g_passdirfd
);
809 Gen
.g_passdirfd
= -1;
810 if (Atflag
|| SysAtflag
) {
811 if (Gen
.g_dirfd
!= -1) {
812 (void) close(Gen
.g_dirfd
);
815 if (passret
!= FILE_LINKED
) {
816 Gen
.g_nam_p
= Savenam_p
;
817 xattrs_out(file_pass
);
823 msg(EXT
, "Impossible action.");
826 if (close(Ofile
) != 0)
827 msg(EXTN
, "close error");
830 if (close(Archive
) != 0)
831 msg(EXTN
, "close error");
833 if ((Args
& OCq
) == 0) {
834 Blocks
= (u_longlong_t
)(Blocks
* Bufsize
+ SBlocks
+
836 msg(EPOST
, "%lld blocks", Blocks
);
839 msg(EPOST
, "%d error(s)", Error_cnt
);
844 * add_lnk: Add a linked file's header to the linked file data structure, by
845 * either adding it to the end of an existing sub-list or starting
846 * a new sub-list. Each sub-list saves the links to a given file.
848 * Directly returns a pointer to the new entry; returns a pointer to the head
849 * of the sub-list in which that entry is located through the argument.
853 add_lnk(struct Lnk
**sublist_return
)
855 struct Lnk
*new_entry
, *sublist
;
857 for (sublist
= Lnk_hd
.L_nxt_p
;
859 sublist
= sublist
->L_nxt_p
) {
860 if (sublist
->L_gen
.g_ino
== G_p
->g_ino
&&
861 sublist
->L_gen
.g_dev
== G_p
->g_dev
) {
867 new_entry
= e_zalloc(E_EXIT
, sizeof (struct Lnk
));
869 new_entry
->L_lnk_p
= NULL
;
870 new_entry
->L_gen
= *G_p
; /* structure copy */
872 new_entry
->L_gen
.g_nam_p
= e_zalloc(E_EXIT
, (size_t)G_p
->g_namesz
);
874 (void) strcpy(new_entry
->L_gen
.g_nam_p
, G_p
->g_nam_p
);
876 if (sublist
== &Lnk_hd
) {
877 /* start new sub-list */
878 new_entry
->L_nxt_p
= &Lnk_hd
;
879 new_entry
->L_bck_p
= Lnk_hd
.L_bck_p
;
880 Lnk_hd
.L_bck_p
= new_entry
->L_bck_p
->L_nxt_p
= new_entry
;
881 new_entry
->L_lnk_p
= NULL
;
882 new_entry
->L_cnt
= 1;
883 new_entry
->L_data
= Onecopy
? 0 : 1;
886 /* add to existing sub-list */
892 ptr
->L_lnk_p
!= NULL
;
893 ptr
= ptr
->L_lnk_p
) {
894 ptr
->L_gen
.g_filesz
= G_p
->g_filesz
;
897 ptr
->L_gen
.g_filesz
= G_p
->g_filesz
;
898 ptr
->L_lnk_p
= new_entry
;
901 *sublist_return
= sublist
;
906 * bfill: Read req_cnt bytes (out of filelen bytes) from the I/O buffer,
907 * moving them to rd_buf_p. When there are no bytes left in the I/O buffer,
908 * Fillbuf is set and the I/O buffer is filled. The variable dist is the
909 * distance to lseek if an I/O error is encountered with the -k option set
910 * (converted to a multiple of Bufsize).
920 while ((Buffr
.b_end_p
- Buffr
.b_in_p
) >= Bufsize
) {
922 if ((rv
= g_read(Device
, Archive
, Buffr
.b_in_p
, Bufsize
)) < 0) {
923 if (((Buffr
.b_end_p
- Buffr
.b_in_p
) >= Bufsize
) &&
928 if (errno
== ENOSPC
) {
929 (void) chgreel(INPUT
);
930 if (Hdr_type
== BAR
) {
934 } else if (Args
& OCk
) {
936 msg(EXT
, "Cannot recover.");
937 if (lseek(Archive
, Bufsize
, SEEK_REL
) < 0)
938 msg(EXTN
, "Cannot lseek()");
945 } /* (rv = g_read(Device, Archive ... */
946 if (Hdr_type
!= BAR
|| rv
== Bufsize
) {
948 Buffr
.b_cnt
+= (long)rv
;
953 } else if (rv
== 0) {
958 (void) chgreel(INPUT
);
959 eof
= 0; /* reset the eof after chgreel */
962 * if spans multiple volume, skip the volume header of
963 * the next volume so that the file currently being
964 * extracted can continue to be extracted.
966 if (Hdr_type
== BAR
) {
973 SBlocks
+= (u_longlong_t
)rv
;
975 } /* (Buffr.b_end_p - Buffr.b_in_p) <= Bufsize */
979 if ((rv
= g_read(Device
, Archive
, Buffr
.b_in_p
, Bufsize
)) < 0) {
981 } /* (rv = g_read(Device, Archive ... */
983 Buffr
.b_cnt
+= (long)rv
;
995 SBlocks
+= (u_longlong_t
)rv
;
1002 * bflush: Move wr_cnt bytes from data_p into the I/O buffer. When the
1003 * I/O buffer is full, Flushbuf is set and the buffer is written out.
1011 while (Buffr
.b_cnt
>= Bufsize
) {
1013 if ((rv
= g_write(Device
, Archive
, Buffr
.b_out_p
,
1015 if (errno
== ENOSPC
&& !Dflag
)
1016 rv
= chgreel(OUTPUT
);
1020 Buffr
.b_out_p
+= rv
;
1021 Buffr
.b_cnt
-= (long)rv
;
1025 SBlocks
+= (u_longlong_t
)rv
;
1031 * chgreel: Determine if end-of-medium has been reached. If it has,
1032 * close the current medium and prompt the user for the next medium.
1038 int lastchar
, tryagain
, askagain
, rv
;
1044 if (fstat(Archive
, &statb
) < 0)
1045 msg(EXTN
, "Error during stat() of archive");
1046 if ((statb
.st_mode
& S_IFMT
) != S_IFCHR
) {
1049 "Can't read input: end of file encountered ",
1050 "prior to expected end of archive.");
1053 msg(EPOST
, "\007End of medium on \"%s\".", dir
? "output" : "input");
1054 if (is_floppy(Archive
))
1055 (void) ioctl(Archive
, FDEJECT
, NULL
);
1056 if ((close(Archive
) != 0) && (dir
== OUTPUT
))
1057 msg(EXTN
, "close error");
1062 Rtty_p
= fopen(Ttyname
, "r");
1066 msg(EPOST
, Eom_p
, Volcnt
);
1067 if (!Rtty_p
|| fgets(str
, sizeof (str
),
1069 msg(EXT
, "Cannot read tty.");
1073 (void) strcpy(str
, IOfil_p
);
1083 if (Hdr_type
== BAR
)
1087 "To continue, type device/file name when "
1089 if (!Rtty_p
|| fgets(str
, sizeof (str
),
1091 msg(EXT
, "Cannot read tty.");
1092 lastchar
= strlen(str
) - 1;
1093 if (*(str
+ lastchar
) == '\n') /* remove '\n' */
1094 *(str
+ lastchar
) = '\0';
1099 if ((Archive
= open(str
, dir
)) < 0) {
1100 msg(ERRN
, "Cannot open \"%s\"", str
);
1104 (void) g_init(&tmpdev
, &Archive
);
1105 if (tmpdev
!= Device
)
1106 msg(EXT
, "Cannot change media types in mid-stream.");
1109 else { /* dir == OUTPUT */
1111 if ((rv
= g_write(Device
, Archive
, Buffr
.b_out_p
,
1112 Bufsize
)) == Bufsize
)
1116 "Unable to write this medium, try "
1125 * ckname: Check filenames against user specified patterns,
1126 * and/or ask the user for new name when -r is used.
1133 size_t rename_bufsz
= Max_namesz
+ 1;
1135 if (Hdr_type
!= TAR
&& Hdr_type
!= USTAR
&& Hdr_type
!= BAR
) {
1136 /* Re-visit tar size issues later */
1137 if (G_p
->g_namesz
- 1 > Max_namesz
) {
1138 msg(ERR
, "Name exceeds maximum length - skipped.");
1143 if (Pat_pp
&& !matched())
1146 /* rename interactively */
1147 if ((Args
& OCr
) && !Adir
&& !G_p
->g_rw_sysattr
) {
1148 (void) fprintf(Wtty_p
, gettext("Rename \"%s%s%s\"? "),
1149 (G_p
->g_attrnam_p
== NULL
) ? G_p
->g_nam_p
: Renam_p
,
1150 (G_p
->g_attrnam_p
== NULL
) ? "" : gettext(" Attribute "),
1151 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
1152 (void) fflush(Wtty_p
);
1153 if (fgets(Renametmp_p
, rename_bufsz
, Rtty_p
) == NULL
)
1154 msg(EXT
, "Cannot read tty.");
1157 lastchar
= strlen(Renametmp_p
) - 1;
1159 /* remove trailing '\n' */
1160 if (*(Renametmp_p
+ lastchar
) == '\n')
1161 *(Renametmp_p
+ lastchar
) = '\0';
1162 if (*Renametmp_p
== '\0') {
1163 msg(POST
, "%s%s%s Skipped.",
1164 (G_p
->g_attrnam_p
== NULL
) ? G_p
->g_nam_p
:
1166 (G_p
->g_attrnam_p
== NULL
) ? "" :
1167 gettext(" Attribute "),
1168 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
1169 if (G_p
->g_attrparent_p
== NULL
) {
1170 *G_p
->g_nam_p
= '\0';
1173 *Renam_attr_p
= '\0';
1176 } else if (strcmp(Renametmp_p
, ".") != 0) {
1177 if (G_p
->g_attrnam_p
== NULL
) {
1178 if (strlen(Renametmp_p
) > strlen(
1180 if ((G_p
->g_nam_p
!= &nambuf
[0]) &&
1181 (G_p
->g_nam_p
!= &fullnam
[0])) {
1183 G_p
->g_nam_p
= e_zalloc(E_EXIT
,
1188 *Renam_attr_p
= '\0';
1190 if ((strlcpy(Renam_p
, Renametmp_p
,
1191 rename_bufsz
) > rename_bufsz
) ||
1192 (strlcpy(G_p
->g_nam_p
, Renametmp_p
,
1193 rename_bufsz
) > rename_bufsz
)) {
1194 msg(EXTN
, "buffer overflow");
1197 if (G_p
->g_attrnam_p
!= NULL
) {
1198 free(G_p
->g_attrnam_p
);
1199 G_p
->g_attrnam_p
= e_strdup(E_EXIT
,
1201 (void) strcpy(G_p
->g_nam_p
, Renam_p
);
1203 if (strlcpy(Renam_attr_p
,
1204 Renametmp_p
, rename_bufsz
) >
1213 if (G_p
->g_attrnam_p
== NULL
) {
1217 *Renam_attr_p
= '\0';
1221 if (flag
!= 0 || Onecopy
== 0) {
1222 VERBOSE((Args
& OCt
), G_p
->g_nam_p
);
1230 * ckopts: Check the validity of all command line options.
1239 uid_t Euid
= geteuid(); /* Effective uid of invoker */
1240 #ifdef SOLARIS_PRIVS
1241 priv_set_t
*privset
;
1242 priv_set_t
*zones_privset
;
1243 #endif /* SOLARIS_PRIVS */
1246 errmsk
= mask
& INV_MSK4i
;
1247 } else if (mask
& OCo
) {
1248 errmsk
= mask
& INV_MSK4o
;
1249 } else if (mask
& OCp
) {
1250 errmsk
= mask
& INV_MSK4p
;
1252 msg(ERR
, "One of -i, -o or -p must be specified.");
1257 /* if non-zero, invalid options were specified */
1261 if ((mask
& OCa
) && (mask
& OCm
) && ((mask
& OCi
) ||
1263 msg(ERR
, "-a and -m are mutually exclusive.");
1266 if ((mask
& OCc
) && (mask
& OCH
) &&
1267 (strcmp("odc", Hdr_p
) != 0 && strcmp("odc_sparse", Hdr_p
) != 0)) {
1268 msg(ERR
, "-c and -H are mutually exclusive.");
1271 if ((mask
& OCv
) && (mask
& OCV
)) {
1272 msg(ERR
, "-v and -V are mutually exclusive.");
1275 if ((mask
& OCt
) && (mask
& OCV
)) {
1276 msg(ERR
, "-t and -V are mutually exclusive.");
1279 if ((mask
& OCB
) && (mask
& OCC
)) {
1280 msg(ERR
, "-B and -C are mutually exclusive.");
1283 if ((mask
& OCH
) && (mask
& OC6
)) {
1284 msg(ERR
, "-H and -6 are mutually exclusive.");
1287 if ((mask
& OCM
) && !((mask
& OCI
) || (mask
& OCO
))) {
1288 msg(ERR
, "-M not meaningful without -O or -I.");
1291 if ((mask
& OCA
) && !(mask
& OCO
)) {
1292 msg(ERR
, "-A requires the -O option.");
1296 msg(ERR
, "Illegal size given for -C option.");
1302 while (*t_p
!= '\0') {
1303 if (isupper(*t_p
)) {
1304 *t_p
= 'a' + (*t_p
- 'A');
1310 if (!(strcmp("odc", Hdr_p
))) {
1315 } else if (!(strcmp("odc_sparse", Hdr_p
))) {
1320 Compress_sparse
= 1;
1321 } else if (!(strcmp("ascii_sparse", Hdr_p
))) {
1325 Compress_sparse
= 1;
1326 } else if (!(strcmp("crc", Hdr_p
))) {
1330 } else if (!(strcmp("tar", Hdr_p
))) {
1333 Max_namesz
= HNAMLEN
- 1;
1336 Max_namesz
= TNAMLEN
- 1;
1339 } else if (!(strcmp("ustar", Hdr_p
))) {
1341 Max_namesz
= HNAMLEN
- 1;
1343 } else if (!(strcmp("bar", Hdr_p
))) {
1344 if ((Args
& OCo
) || (Args
& OCp
)) {
1346 "Header type bar can only be used with -i");
1351 "Can't preserve using bar header");
1355 Max_namesz
= TNAMLEN
- 1;
1358 msg(ERR
, "Invalid header \"%s\" specified", Hdr_p
);
1363 Rtty_p
= fopen(Ttyname
, "r");
1364 Wtty_p
= fopen(Ttyname
, "w");
1366 if (Rtty_p
== NULL
|| Wtty_p
== NULL
) {
1367 msg(ERR
, "Cannot rename, \"%s\" missing", Ttyname
);
1371 if ((mask
& OCE
) && (Ef_p
= fopen(Efil_p
, "r")) == NULL
) {
1372 msg(ERR
, "Cannot open \"%s\" to read patterns", Efil_p
);
1375 if ((mask
& OCI
) && (Archive
= open(IOfil_p
, O_RDONLY
)) < 0) {
1376 msg(ERR
, "Cannot open \"%s\" for input", IOfil_p
);
1381 if ((Archive
= open(IOfil_p
, O_RDWR
)) < 0) {
1383 "Cannot open \"%s\" for append",
1387 oflag
= (O_WRONLY
| O_CREAT
| O_TRUNC
);
1389 if ((Archive
= open(IOfil_p
, oflag
, 0777)) < 0) {
1391 "Cannot open \"%s\" for output",
1397 #ifdef SOLARIS_PRIVS
1398 if ((privset
= priv_allocset()) == NULL
) {
1399 msg(ERR
, "Unable to allocate privilege set");
1400 } else if (getppriv(PRIV_EFFECTIVE
, privset
) != 0) {
1401 msg(ERR
, "Unable to obtain privilege set");
1403 zones_privset
= priv_str_to_set("zone", "", NULL
);
1404 if (zones_privset
!= NULL
) {
1405 privileged
= (priv_issubset(zones_privset
,
1406 privset
) == B_TRUE
);
1407 priv_freeset(zones_privset
);
1409 msg(ERR
, "Unable to map privilege to privilege set");
1412 if (privset
!= NULL
) {
1413 priv_freeset(privset
);
1416 privileged
= (Euid
== 0);
1417 #endif /* SOLARIS_PRIVS */
1420 if ((Rpw_p
= getpwnam(Own_p
)) == NULL
) {
1421 msg(ERR
, "\"%s\" is not a valid user id", Own_p
);
1422 } else if ((Euid
!= Rpw_p
->pw_uid
) && !privileged
) {
1423 msg(ERR
, "R option only valid for super-user or "
1424 "id matches login id of user executing cpio");
1428 if ((mask
& OCo
) && !(mask
& OCO
)) {
1432 if ((mask
& OCp
) && ((mask
& (OCB
|OCC
)) == 0)) {
1434 * We are in pass mode with no block size specified. Use the
1435 * larger of the native page size and 8192.
1438 Bufsize
= (PageSize
> 8192) ? PageSize
: 8192;
1443 * cksum: Calculate the simple checksum of a file (CRC) or header
1444 * (TARTYP (TAR and USTAR)). For -o and the CRC header, the file is opened and
1445 * the checksum is calculated. For -i and the CRC header, the checksum
1446 * is calculated as each block is transferred from the archive I/O buffer
1447 * to the file system I/O buffer. The TARTYP (TAR and USTAR) headers calculate
1448 * the simple checksum of the header (with the checksum field of the
1449 * header initialized to all spaces (\040).
1453 cksum(char hdr
, int byt_cnt
, int *err
)
1455 char *crc_p
, *end_p
;
1457 long checksum
= 0L, have
;
1464 if (Args
& OCi
) { /* do running checksum */
1465 end_p
= Buffr
.b_out_p
+ byt_cnt
;
1466 for (crc_p
= Buffr
.b_out_p
; crc_p
< end_p
; crc_p
++)
1467 checksum
+= (long)*crc_p
;
1470 /* OCo - do checksum of file */
1471 lcnt
= G_p
->g_filesz
;
1474 have
= (lcnt
< Bufsize
) ? lcnt
: Bufsize
;
1476 if (read(Ifile
, Buf_p
, have
) != have
) {
1477 msg(ERR
, "Error computing checksum.");
1482 end_p
= Buf_p
+ have
;
1483 for (crc_p
= Buf_p
; crc_p
< end_p
; crc_p
++)
1484 checksum
+= (long)*crc_p
;
1487 if (lseek(Ifile
, (off_t
)0, SEEK_ABS
) < 0)
1488 msg(ERRN
, "Cannot reset file after checksum");
1490 case TARTYP
: /* TAR and USTAR */
1491 crc_p
= Thdr_p
->tbuf
.t_cksum
;
1492 for (cnt
= 0; cnt
< TCRCLEN
; cnt
++) {
1496 crc_p
= (char *)Thdr_p
;
1497 for (cnt
= 0; cnt
< TARSZ
; cnt
++) {
1499 * tar uses unsigned checksum, so we must use unsigned
1500 * here in order to be able to read tar archives.
1502 checksum
+= (long)((unsigned char)(*crc_p
));
1507 msg(EXT
, "Impossible header type.");
1513 * creat_hdr: Fill in the generic header structure with the specific
1514 * header information based on the value of Hdr_type.
1516 * return (1) if this process was successful, and (0) otherwise.
1527 ftype
= SrcSt
.st_mode
& Ftype
;
1528 Adir
= (ftype
== S_IFDIR
);
1529 Aspec
= (ftype
== S_IFBLK
|| ftype
== S_IFCHR
|| ftype
== S_IFIFO
||
1533 Gen
.g_magic
= CMN_BIN
;
1536 Gen
.g_magic
= CMN_BIN
;
1539 Gen
.g_magic
= CMN_ASC
;
1542 Gen
.g_magic
= CMN_CRC
;
1546 * If the length of the full name is greater than 256,
1547 * print out a message and return.
1549 if ((fullnamesize
= strlen(Gen
.g_nam_p
)) > MAXNAM
) {
1551 "%s: file name too long", Gen
.g_nam_p
);
1553 } else if (fullnamesize
> NAMSIZ
) {
1555 * The length of the full name is greater than
1556 * 100, so we must split the filename from the
1559 char namebuff
[NAMSIZ
+1];
1560 char prebuff
[PRESIZ
+1];
1562 int presize
, namesize
;
1564 (void) memset(namebuff
, '\0',
1566 (void) memset(prebuff
, '\0', sizeof (prebuff
));
1568 lastslash
= strrchr(Gen
.g_nam_p
, '/');
1570 if (lastslash
!= NULL
) {
1571 namesize
= strlen(++lastslash
);
1572 presize
= fullnamesize
- namesize
- 1;
1574 namesize
= fullnamesize
;
1575 lastslash
= Gen
.g_nam_p
;
1580 * If the filename is greater than 100 we can't
1583 if (namesize
> NAMSIZ
) {
1585 "%s: filename is greater than %d",
1589 (void) strncpy(&namebuff
[0], lastslash
,
1592 * If the prefix is greater than 155 we can't
1595 if (presize
> PRESIZ
) {
1597 "%s: prefix is greater than %d",
1598 Gen
.g_nam_p
, PRESIZ
);
1601 (void) strncpy(&prebuff
[0], Gen
.g_nam_p
,
1604 Gen
.g_tname
= e_zalloc(E_EXIT
, namesize
+ 1);
1605 (void) strcpy(Gen
.g_tname
, namebuff
);
1607 Gen
.g_prefix
= e_zalloc(E_EXIT
, presize
+ 1);
1608 (void) strcpy(Gen
.g_prefix
, prebuff
);
1610 Gen
.g_tname
= Gen
.g_nam_p
;
1612 (void) strcpy(Gen
.g_tmagic
, "ustar");
1613 (void) strcpy(Gen
.g_version
, "00");
1615 dpasswd
= getpwuid(SrcSt
.st_uid
);
1616 if (dpasswd
== NULL
) {
1618 "cpio: could not get passwd information "
1620 (Gen
.g_attrnam_p
== NULL
) ?
1621 Gen
.g_nam_p
: Gen
.g_attrfnam_p
,
1622 (Gen
.g_attrnam_p
== NULL
) ?
1623 "" : Gen
.g_rw_sysattr
?
1624 gettext(" System Attribute ") :
1625 gettext(" Attribute "),
1626 (Gen
.g_attrnam_p
== NULL
) ?
1627 "" : Gen
.g_attrnam_p
);
1628 /* make name null string */
1629 Gen
.g_uname
[0] = '\0';
1631 (void) strncpy(&Gen
.g_uname
[0],
1632 dpasswd
->pw_name
, 32);
1634 dgroup
= getgrgid(SrcSt
.st_gid
);
1635 if (dgroup
== NULL
) {
1637 "cpio: could not get group information "
1639 (Gen
.g_attrnam_p
== NULL
) ?
1640 Gen
.g_nam_p
: Gen
.g_attrfnam_p
,
1641 (Gen
.g_attrnam_p
== NULL
) ?
1642 "" : Gen
.g_rw_sysattr
?
1643 gettext(" System Attribute ") :
1644 gettext(" Attribute "),
1645 (Gen
.g_attrnam_p
== NULL
) ?
1646 "" : Gen
.g_attrnam_p
);
1647 /* make name null string */
1648 Gen
.g_gname
[0] = '\0';
1650 (void) strncpy(&Gen
.g_gname
[0],
1651 dgroup
->gr_name
, 32);
1653 Gen
.g_typeflag
= tartype(ftype
);
1656 (void) memset(T_lname
, '\0', sizeof (T_lname
));
1659 msg(EXT
, "Impossible header type.");
1662 if (Use_old_stat
&& (Gen
.g_attrnam_p
!= NULL
)) {
1664 * When processing extended attributes, creat_hdr()
1665 * can get called multiple times which means that
1666 * SrcSt.st.st_dev would have gotten converted to
1667 * -Hodc format. We should always use the original
1668 * device here as we need to be able to match on
1669 * the original device id from the file that was
1670 * previewed in sl_preview_synonyms().
1682 Gen
.g_namesz
= strlen(Gen
.g_nam_p
) + 1;
1683 Gen
.g_uid
= SrcSt
.st_uid
;
1684 Gen
.g_gid
= SrcSt
.st_gid
;
1685 Gen
.g_dev
= SrcSt
.st_dev
;
1690 sl_info_t
*p
= sl_search(dev
, ino
, ftype
);
1691 Gen
.g_ino
= p
? p
->sl_ino2
: -1;
1693 if (Gen
.g_ino
== (ulong_t
)-1) {
1694 msg(ERR
, "%s%s%s: cannot be archived - inode too big "
1696 (Gen
.g_attrnam_p
== NULL
) ?
1697 Gen
.g_nam_p
: Gen
.g_attrfnam_p
,
1698 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
1699 gettext(" System Attribute ") :
1700 gettext(" Attribute "),
1701 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_attrnam_p
);
1705 Gen
.g_ino
= SrcSt
.st_ino
;
1708 Gen
.g_mode
= SrcSt
.st_mode
;
1709 Gen
.g_mtime
= SrcSt
.st_mtime
;
1710 Gen
.g_nlink
= Adir
? SrcSt
.st_nlink
: sl_numlinks(dev
, ino
, ftype
);
1712 if (ftype
== S_IFREG
|| ftype
== S_IFLNK
)
1713 Gen
.g_filesz
= (off_t
)SrcSt
.st_size
;
1715 Gen
.g_filesz
= (off_t
)0;
1716 Gen
.g_rdev
= SrcSt
.st_rdev
;
1721 * creat_lnk: Create a link from the existing name1_p to name2_p.
1726 creat_lnk(int dirfd
, char *name1_p
, char *name2_p
)
1732 if (!link(name1_p
, name2_p
)) {
1740 } else if ((errno
== EEXIST
) && (cnt
== 0)) {
1745 * Check to see if we are trying to link this
1746 * file to itself. If so, count the effort as
1747 * successful. If the two files are different,
1748 * or if either lstat is unsuccessful, proceed
1749 * as we would have otherwise; the appropriate
1750 * error will be reported subsequently.
1753 if (lstat(name1_p
, &lsb1
) != 0) {
1754 msg(ERR
, "Cannot lstat source file %s",
1757 if (lstat(name2_p
, &lsb2
) != 0) {
1758 msg(ERR
, "Cannot lstat "
1759 "destination file %s", name2_p
);
1761 if (lsb1
.st_dev
== lsb2
.st_dev
&&
1762 lsb1
.st_ino
== lsb2
.st_ino
) {
1763 VERBOSE((Args
& (OCv
| OCV
)),
1770 if (!(Args
& OCu
) && G_p
->g_mtime
<= DesSt
.st_mtime
)
1771 msg(ERR
, "Existing \"%s\" same age or newer",
1773 else if (unlinkat(dirfd
, get_component(name2_p
), 0) < 0)
1774 msg(ERRN
, "Error cannot unlink \"%s\"",
1778 } while ((cnt
< 2) && missdir(name2_p
) == 0);
1786 attrname
= Gen
.g_attrnam_p
;
1789 newname
= fromname
= Fullnam_p
;
1791 newname
= Gen
.g_attrfnam_p
;
1795 (void) fprintf(Err_p
,
1796 gettext("%s%s%s linked to %s%s%s\n"), newname
,
1797 (attrname
== NULL
) ? "" : gettext(" attribute "),
1798 (attrname
== NULL
) ? "" : attrname
,
1799 (attrname
== NULL
) ? fromname
: newname
,
1800 (attrname
== NULL
) ? "" : gettext(" attribute "),
1801 (attrname
== NULL
) ? "" : name1_p
);
1803 VERBOSE((Args
& (OCv
| OCV
)), newname
);
1805 } else if (cnt
== 1)
1807 "Unable to create directory for \"%s\"", name2_p
);
1810 "Cannot link \"%s\" and \"%s\"", name1_p
, name2_p
);
1816 * Create one of the following:
1818 * character special file
1819 * block special file
1825 creat_spec(int dirfd
)
1828 int cnt
, result
, rv
= 0;
1832 Do_rename
= 0; /* creat_tmp() may reset this */
1837 nam_p
= G_p
->g_nam_p
;
1841 * Is this the extraction of the hidden attribute directory?
1842 * If we are processing the hidden attribute directory of an
1843 * attribute, then just return as modes and times cannot be set.
1844 * Otherwise, if we are processing a hidden attribute, just set
1845 * the mode/times correctly and return.
1849 if (G_p
->g_attrparent_p
== NULL
) {
1851 if (fchownat(dirfd
, ".", Rpw_p
->pw_uid
,
1852 Rpw_p
->pw_gid
, 0) != 0) {
1854 "Cannot chown() \"attribute "
1855 "directory of file %s\"",
1858 } else if ((fchownat(dirfd
, ".", G_p
->g_uid
,
1859 G_p
->g_gid
, 0) != 0) && privileged
) {
1861 "Cannot chown() \"attribute directory of "
1862 "file %s\"", G_p
->g_attrfnam_p
);
1865 if (fchmod(dirfd
, G_p
->g_mode
) != 0) {
1867 "Cannot chmod() \"attribute directory of "
1868 "file %s\"", G_p
->g_attrfnam_p
);
1872 if (Pflag
&& aclp
!= NULL
) {
1873 if (facl_set(dirfd
, aclp
) < 0) {
1875 "failed to set acl on attribute"
1876 " directory of %s ",
1889 result
= stat(nam_p
, &DesSt
);
1891 if (ustar_dir() || Adir
) {
1893 * The archive file is a directory.
1897 curdir
= strrchr(nam_p
, '.');
1899 if (curdir
!= NULL
&& curdir
[1] == '\0') {
1900 lastslash
= strrchr(nam_p
, '/');
1902 if (lastslash
!= NULL
) {
1908 if (!(strcmp(lastslash
, ".")) ||
1909 !(strcmp(lastslash
, ".."))) {
1915 /* A file by the same name exists. */
1917 /* Take care of ACLs */
1920 if (Pflag
&& aclp
!= NULL
) {
1921 if (acl_set(nam_p
, aclp
) < 0) {
1923 "\"%s\": failed to set acl",
1934 * We are creating directories. Keep the
1938 rstfiles(U_KEEP
, dirfd
);
1941 /* Report success. */
1946 /* The archive file is not a directory. */
1950 * A file by the same name exists. Move it to a
1954 if (creat_tmp(nam_p
) < 0) {
1956 * We weren't able to create the temp file.
1966 * This pile tries to create the file directly, and, if there is a
1967 * problem, creates missing directories, and then tries to create the
1968 * file again. Two strikes and you're out.
1974 if (ustar_dir() || Adir
) {
1975 /* The archive file is a directory. */
1977 result
= mkdir(nam_p
, G_p
->g_mode
);
1978 } else if (ustar_spec() || Aspec
) {
1980 * The archive file is block special,
1981 * char special, socket, or a fifo.
1982 * Note that, for a socket, the third
1983 * parameter to mknod() is ignored.
1986 result
= mknod(nam_p
, (int)G_p
->g_mode
,
1992 * The file creation succeeded. Take care of the ACLs.
1997 if (Pflag
&& aclp
!= NULL
) {
1998 if (acl_set(nam_p
, aclp
) < 0) {
2000 "\"%s\": failed to set acl", nam_p
);
2014 } while (cnt
< 2 && missdir(nam_p
) == 0);
2019 rstfiles(U_OVER
, dirfd
);
2024 "Cannot create directory for \"%s\"", nam_p
);
2026 if (*Over_p
== '\0') {
2027 rstfiles(U_KEEP
, dirfd
);
2033 if (ustar_dir() || Adir
) {
2034 msg(ERRN
, "Cannot create directory \"%s\"", nam_p
);
2035 } else if (ustar_spec() || Aspec
) {
2036 msg(ERRN
, "Cannot mknod() \"%s\"", nam_p
);
2039 if (*Over_p
== '\0') {
2040 rstfiles(U_KEEP
, dirfd
);
2046 msg(EXT
, "Impossible case.");
2057 creat_tmp(char *nam_p
)
2062 if ((Args
& OCp
) && G_p
->g_ino
== DesSt
.st_ino
&&
2063 G_p
->g_dev
== DesSt
.st_dev
) {
2064 msg(ERR
, "Attempt to pass a file to itself.");
2068 if (G_p
->g_mtime
<= DesSt
.st_mtime
&& !(Args
& OCu
)) {
2069 msg(ERR
, "Existing \"%s\" same age or newer", nam_p
);
2073 /* Make the temporary file name. */
2075 (void) strcpy(Over_p
, nam_p
);
2076 t_p
= Over_p
+ strlen(Over_p
);
2078 while (t_p
!= Over_p
) {
2079 if (*(t_p
- 1) == '/')
2084 (void) strcpy(t_p
, "XXXXXX");
2086 if (G_p
->g_attrnam_p
!= NULL
) {
2088 * Save our current directory, so we can go into
2089 * the attribute directory to make the temp file
2094 (void) fchdir(G_p
->g_dirfd
);
2097 (void) mktemp(Over_p
);
2099 if (G_p
->g_attrnam_p
!= NULL
) {
2100 /* Return to the current directory. */
2105 if (*Over_p
== '\0') {
2106 /* mktemp reports a failure. */
2108 msg(ERR
, "Cannot get temporary file name.");
2113 * If it's a regular file, write to the temporary file, and then rename
2114 * in order to accommodate potential executables.
2116 * Note: g_typeflag is only defined (set) for USTAR archive types. It
2117 * defaults to 0 in the cpio-format-regular file case, so this test
2121 if (G_p
->g_typeflag
== 0 &&
2122 (DesSt
.st_mode
& (ulong_t
)Ftype
) == S_IFREG
&&
2123 (G_p
->g_mode
& (ulong_t
)Ftype
) == S_IFREG
) {
2125 * The archive file and the filesystem file are both regular
2126 * files. We write to the temporary file in this case.
2130 if (G_p
->g_attrnam_p
== NULL
) {
2133 Attrfile_p
= Over_p
;
2136 G_p
->g_nam_p
= Over_p
;
2137 if (G_p
->g_attrnam_p
!= NULL
) {
2138 Attrfile_p
= Over_p
;
2142 if (G_p
->g_attrnam_p
== NULL
) {
2145 Over_p
= G_p
->g_attrnam_p
;
2151 * Either the archive file or the filesystem file is not a
2157 if (S_ISDIR(DesSt
.st_mode
)) {
2159 * The filesystem file is a directory.
2161 * Save the current working directory because we will
2162 * want to restore it back just in case remove_dir()
2163 * fails or get confused about where we should be.
2169 if (remove_dir(nam_p
) < 0) {
2171 "Cannot remove the directory \"%s\"",
2174 * Restore working directory back to the one
2183 * Restore working directory back to the one
2190 * The file is not a directory. Will use the original
2191 * link/unlink construct, however, if the file is
2192 * namefs, link would fail with EXDEV. Therefore, we
2193 * use rename() first to back up the file.
2195 if (rename(nam_p
, Over_p
) < 0) {
2197 * If rename failed, try old construction
2200 if (link(nam_p
, Over_p
) < 0) {
2202 "Cannot rename temporary file "
2203 "\"%s\" to \"%s\"", Over_p
, nam_p
);
2208 if (unlink(nam_p
) < 0) {
2210 "Cannot unlink() current \"%s\"",
2212 (void) unlink(Over_p
);
2224 * Copy the datasize amount of data from the input file to buffer.
2226 * ifd - Input file descriptor.
2227 * buffer - Buffer (allocated by caller) to copy data to.
2228 * datasize - The amount of data to read from the input file
2229 * and copy to the buffer.
2230 * error - When reading from an Archive file, indicates unreadable
2231 * data was encountered, otherwise indicates errno.
2232 * data_in_info - Information needed when called from data_in().
2235 read_chunk(int ifd
, char *buffer
, size_t datasize
, data_in_t
*data_in_info
)
2238 return (read(ifd
, buffer
, datasize
));
2241 if (data_in_info
->data_in_proc_mode
!= P_SKIP
) {
2242 if (Hdr_type
== CRC
)
2243 data_in_info
->data_in_cksumval
+= cksum(CRC
,
2245 if (data_in_info
->data_in_swapfile
)
2246 swap(Buffr
.b_out_p
, datasize
);
2250 * if the bar archive is compressed, set up a pipe and
2251 * do the de-compression while reading in the file
2253 if (Hdr_type
== BAR
) {
2254 if (data_in_info
->data_in_compress_flag
== 0 &&
2257 &(data_in_info
->data_in_pipef
));
2258 data_in_info
->data_in_compress_flag
++;
2262 (void) memcpy(buffer
, Buffr
.b_out_p
, datasize
);
2263 Buffr
.b_out_p
+= datasize
;
2264 Buffr
.b_cnt
-= datasize
;
2270 * Read as much data as we can.
2272 * ifd - input file descriptor.
2273 * buf - Buffer (allocated by caller) to copy data to.
2274 * bytes - The amount of data to read from the input file
2275 * and copy to the buffer.
2276 * rdblocksz - The size of the chunk of data to read.
2278 * Return number of bytes failed to read.
2279 * Return -1 when buffer is empty and read failed.
2282 read_bytes(int ifd
, char *buf
, size_t bytes
, size_t rdblocksz
,
2283 data_in_t
*data_in_info
)
2288 for (bytesread
= 0; bytesread
< bytes
; bytesread
+= got
) {
2290 * Read the data from either the input file descriptor
2291 * or the archive file. read_chunk() will only return
2292 * <= 0 if data_copy() was called from data_pass().
2294 if ((got
= read_chunk(ifd
, buf
+ bytesread
,
2295 min(bytes
- bytesread
, rdblocksz
),
2296 data_in_info
)) <= 0) {
2298 * We come here only in the pass mode.
2299 * If data couldn't be read from the input file
2300 * descriptor, return number of bytes in the buf.
2301 * If buffer is empty, return -1.
2303 if (bytesread
== 0) {
2304 if (got
== 0) /* EOF */
2305 data_in_info
->data_in_rd_eof
= 1;
2308 return (bytes
- bytesread
);
2315 * Write as much data as we can.
2317 * ofd - output file descriptor.
2318 * buf - Source buffer to output data from.
2319 * maxwrite - The amount of data to write to the output.
2321 * return 0 upon success.
2324 write_bytes(int ofd
, char *buf
, size_t maxwrite
, data_in_t
*data_in_info
)
2329 if ((cnt
= write(ofd
, buf
, maxwrite
)) < (ssize_t
)maxwrite
) {
2330 data_in_info
->data_in_errno
= errno
;
2332 * data_in() needs to know if it was an actual write(2)
2333 * failure, or if we just couldn't write all of the data
2334 * requested so that we know that the rest of the file's
2335 * data can be read but not written.
2338 data_in_info
->data_in_wr_part
= 1;
2340 } else if (Args
& OCp
) {
2341 Blocks
+= (u_longlong_t
)((cnt
+ (Bufsize
- 1)) / Bufsize
);
2347 * Perform I/O for given byte size with using limited i/o block size
2348 * and supplied buffer.
2350 * ifd/ofd - i/o file descriptor
2351 * buf - buffer to be used for i/o
2352 * bytes - Amount to read/write
2353 * wrblocksz - Output block size.
2354 * rdblocksz - Read block size.
2356 * Return 0 upon success. Return negative if read failed.
2357 * Return positive non-zero if write failed.
2360 rdwr_bytes(int ifd
, int ofd
, char *buf
, off_t bytes
,
2361 size_t wrblocksz
, size_t rdblocksz
, data_in_t
*data_in_info
)
2365 int write_it
= (data_in_info
->data_in_proc_mode
!= P_SKIP
);
2369 * If the number of bytes left to write is smaller than
2370 * the preferred I/O size, then we're about to do our final
2371 * write to the file, so just set wrblocksz to the number of
2372 * bytes left to write.
2374 if (bytes
< wrblocksz
)
2377 /* Read input till satisfy output block size */
2378 sz
= read_bytes(ifd
, buf
, wrblocksz
, rdblocksz
, data_in_info
);
2383 rv
= write_bytes(ofd
, buf
,
2384 wrblocksz
- sz
, data_in_info
);
2387 * If we wrote partial, we return and quits.
2388 * Otherwise, read through the rest of input
2389 * to go to the next file.
2392 data_in_info
->data_in_wr_part
) {
2400 bytes
-= (wrblocksz
- sz
);
2406 * Write zeros for give size.
2408 * ofd - output file descriptor
2409 * buf - buffer to fill with zeros
2410 * bytes - Amount to write
2411 * wrblocksz - Write block size
2413 * return 0 upon success.
2416 write_zeros(int ofd
, char *buf
, off_t bytes
, size_t wrblocksz
,
2417 data_in_t
*data_in_info
)
2421 (void) memset(buf
, 0, min(bytes
, wrblocksz
));
2423 if (bytes
< wrblocksz
)
2425 rv
= write_bytes(ofd
, buf
, wrblocksz
, data_in_info
);
2434 * To figure out the size of the buffer used to accumulate data from
2435 * readtape() and to write to the file, we need to determine the largest
2436 * chunk of data to be written to the file at one time. This is determined
2437 * based on the following three things:
2438 * 1) The size of the archived file.
2439 * 2) The preferred I/O size of the file.
2440 * 3) If the file is a read-write system attribute file.
2441 * If the size of the file is less than the preferred I/O size or it's a
2442 * read-write system attribute file, which must be written in one operation,
2443 * then set the maximum write size to the size of the archived file.
2444 * Otherwise, the maximum write size is preferred I/O size.
2447 calc_maxwrite(int ofd
, int rw_sysattr
, off_t bytes
, size_t blocksize
)
2451 size_t piosize
; /* preferred I/O size */
2453 if (rw_sysattr
|| bytes
< blocksize
) {
2456 if (fstat(ofd
, &tsbuf
) == 0) {
2457 piosize
= tsbuf
.st_blksize
;
2459 piosize
= blocksize
;
2461 maxwrite
= min(bytes
, piosize
);
2466 * data_copy() and data_copy_with_holes() copy data from the input
2467 * file to output file descriptor. If ifd is -1, then the input file is
2471 * ifd - Input file descriptor to read from.
2472 * ofd - Output file descriptor of extracted file.
2473 * rw_sysattr - Flag indicating if a file is an extended
2474 * system attribute file.
2475 * bytes - Amount of data (file size) of copy/write.
2476 * blocksize - Amount of data to read at a time from either
2477 * the input file descriptor or from the archive.
2478 * data_in_info - information needed while reading data when
2479 * called by data_in().
2480 * holes - Information of holes in the input file.
2484 * < 0 An error occurred during the read of the input
2486 * > 0 An error occurred during the write of the output
2490 data_copy(int ifd
, int ofd
, int rw_sysattr
, off_t bytes
,
2491 size_t blocksize
, data_in_t
*data_in_info
)
2497 /* No data to copy. */
2501 maxwrite
= calc_maxwrite(ofd
, rw_sysattr
, bytes
, blocksize
);
2502 buf
= e_zalloc(E_EXIT
, maxwrite
);
2504 rv
= rdwr_bytes(ifd
, ofd
, buf
, bytes
, maxwrite
,
2505 blocksize
, data_in_info
);
2512 data_copy_with_holes(int ifd
, int ofd
, int rw_sysattr
, off_t bytes
,
2513 size_t blocksize
, data_in_t
*data_in_info
, holes_info_t
*holes
)
2516 off_t curpos
, noff
, datasize
;
2524 maxwrite
= calc_maxwrite(ofd
, rw_sysattr
, bytes
, blocksize
);
2525 buf
= e_zalloc(E_EXIT
, maxwrite
);
2529 for (hl
= holes
->holes_list
; hl
!= NULL
; hl
= hl
->hl_next
) {
2530 if (curpos
!= hl
->hl_data
) {
2531 /* adjust output position */
2532 noff
= lseek(ofd
, hl
->hl_data
, SEEK_SET
);
2533 if (noff
!= hl
->hl_data
) {
2535 * Can't seek to the target, try to adjust
2536 * position by filling with zeros.
2538 datasize
= hl
->hl_data
- curpos
;
2539 rv
= write_zeros(ofd
, buf
, datasize
,
2540 maxwrite
, data_in_info
);
2545 * Data is contiguous in the archive, but fragmented
2546 * in the regular file, so we also adjust the input
2547 * file position in pass mode.
2550 /* adjust input position */
2551 (void) lseek(ifd
, hl
->hl_data
, SEEK_SET
);
2553 curpos
= hl
->hl_data
;
2555 datasize
= hl
->hl_hole
- hl
->hl_data
;
2556 if (datasize
== 0) {
2558 * There is a hole at the end of file. To create
2559 * such hole, we append one byte, and truncate the
2560 * last block. This is necessary because ftruncate(2)
2561 * alone allocates one block on the end of file.
2563 rv
= write_zeros(ofd
, buf
, 1, maxwrite
, data_in_info
);
2566 (void) ftruncate(ofd
, hl
->hl_data
);
2569 rv
= rdwr_bytes(ifd
, ofd
, buf
, datasize
, maxwrite
,
2570 blocksize
, data_in_info
);
2574 * Return if we got a read error or in pass mode,
2575 * or failed with partial write. Otherwise, we'll
2576 * read through the input stream till next file.
2578 if (rv
< 0 || (Args
& OCp
) ||
2579 data_in_info
->data_in_wr_part
) {
2591 * We should read through the input data to go to the next
2592 * header when non-fatal error occured.
2594 if (error
&& !(Args
& OCp
)) {
2595 data_in_info
->data_in_proc_mode
= P_SKIP
;
2596 while (hl
!= NULL
) {
2597 datasize
= hl
->hl_hole
- hl
->hl_data
;
2598 rv
= rdwr_bytes(ifd
, ofd
, buf
, datasize
, maxwrite
,
2599 blocksize
, data_in_info
);
2611 * Strip off the sparse file information that is prepended to
2612 * the compressed sparse file. The information is in the following
2614 * <prepended info size><SP><orig file size><SP><holes info>
2615 * where prepended info size is long right justified in 10 bytes.
2616 * Holesdata consists of the series of offset pairs:
2617 * <data offset><SP><hole offset><SP><data offset><SP><hole offset>...
2618 * prepended info size and original file size have been read in gethdr().
2619 * We read the rest of holes information here in this function.
2622 read_holesdata(holes_info_t
*holes
, off_t
*fileszp
,
2623 char *nam_p
, data_in_t
*data_in_info
)
2626 size_t holesdata_sz
;
2628 /* We've already read the header. */
2629 holesdata_sz
= holes
->holesdata_sz
- MIN_HOLES_HDRSIZE
;
2631 if ((holesdata
= e_zalloc(E_NORMAL
, holesdata_sz
)) == NULL
) {
2632 msg(ERRN
, "Could not allocate memory for "
2633 "sparse file information", nam_p
);
2637 * This function is called only in OCi mode. Therefore,
2638 * read_bytes() won't fail, and won't return if error occurs in
2639 * input stream. See rstbuf().
2641 (void) read_bytes(-1, holesdata
, holesdata_sz
, CPIOBSZ
, data_in_info
);
2642 *fileszp
-= holesdata_sz
;
2644 /* The string should be terminated. */
2645 if (holesdata
[holesdata_sz
- 1] != '\0') {
2648 msg(ERR
, "invalid sparse file information", nam_p
);
2651 if (parse_holesdata(holes
, holesdata
) != 0)
2655 if (*fileszp
!= holes
->data_size
)
2663 * data_in: If proc_mode == P_PROC, bread() the file's data from the archive
2664 * and write(2) it to the open fdes gotten from openout(). If proc_mode ==
2665 * P_SKIP, or becomes P_SKIP (due to errors etc), bread(2) the file's data
2666 * and ignore it. If the user specified any of the "swap" options (b, s or S),
2667 * and the length of the file is not appropriate for that action, do not
2668 * perform the "swap", otherwise perform the action on a buffer by buffer basis.
2669 * If the CRC header was selected, calculate a running checksum as each buffer
2673 data_in(int proc_mode
)
2681 data_in_t
*data_in_info
;
2683 if (G_p
->g_attrnam_p
!= NULL
) {
2684 nam_p
= G_p
->g_attrnam_p
;
2686 nam_p
= G_p
->g_nam_p
;
2689 if (((G_p
->g_mode
& Ftype
) == S_IFLNK
&& proc_mode
!= P_SKIP
) ||
2690 (Hdr_type
== BAR
&& bar_linkflag
== '2' && proc_mode
!= P_SKIP
)) {
2692 VERBOSE((Args
& (OCv
| OCV
)), nam_p
);
2694 if (Args
& (OCb
| OCs
| OCS
)) { /* verfify that swapping is possible */
2696 if (Args
& (OCs
| OCb
) && G_p
->g_filesz
% 2) {
2698 "Cannot swap bytes of \"%s\", odd number of bytes",
2702 if (Args
& (OCS
| OCb
) && G_p
->g_filesz
% 4) {
2704 "Cannot swap halfwords of \"%s\", odd number "
2705 "of halfwords", nam_p
);
2710 data_in_info
= e_zalloc(E_EXIT
, sizeof (data_in_t
));
2711 data_in_info
->data_in_swapfile
= swapfile
;
2712 data_in_info
->data_in_proc_mode
= proc_mode
;
2714 filesz
= G_p
->g_filesz
;
2716 if (S_ISSPARSE(G_p
->g_mode
) && G_p
->g_holes
!= NULL
) {
2717 /* We've already read the header in gethdr() */
2718 filesz
-= MIN_HOLES_HDRSIZE
;
2721 * Strip rest of the sparse file information. This includes
2722 * the data/hole offset pairs which will be used to restore
2723 * the holes in the file.
2725 if (proc_mode
== P_SKIP
) {
2726 /* holes info isn't necessary to skip file */
2727 free_holes_info(G_p
->g_holes
);
2728 G_p
->g_holes
= NULL
;
2730 rv
= read_holesdata(G_p
->g_holes
, &filesz
,
2731 nam_p
, data_in_info
);
2734 * We got an error. Skip this file. holes info
2735 * is no longer necessary.
2737 free_holes_info(G_p
->g_holes
);
2738 G_p
->g_holes
= NULL
;
2740 data_in_info
->data_in_proc_mode
= P_SKIP
;
2746 if (G_p
->g_holes
!= NULL
) {
2747 rv
= data_copy_with_holes(-1, Ofile
,
2748 (G_p
->g_attrnam_p
== NULL
) ? 0 : G_p
->g_rw_sysattr
,
2749 G_p
->g_holes
->orig_size
,
2750 CPIOBSZ
, data_in_info
, G_p
->g_holes
);
2752 free_holes_info(G_p
->g_holes
);
2753 G_p
->g_holes
= NULL
;
2755 rv
= data_copy(-1, Ofile
,
2756 (G_p
->g_attrnam_p
== NULL
) ? 0 : G_p
->g_rw_sysattr
,
2757 filesz
, CPIOBSZ
, data_in_info
);
2760 /* This writes out the file from the archive */
2761 if (rv
!= 0 || error
) {
2762 errno
= data_in_info
->data_in_errno
;
2765 msg(data_in_info
->data_in_wr_part
? EXTN
: ERRN
,
2766 "Cannot write \"%s%s%s\"",
2767 (G_p
->g_attrnam_p
== NULL
) ? "" :
2769 (G_p
->g_attrnam_p
== NULL
) ? "" :
2771 gettext(" System Attribute ") :
2772 gettext(" Attribute "), nam_p
);
2775 * We've failed to write to the file, and input data
2776 * has been skiped to the next file. We'll need to restore
2777 * the original file, and skip the rest of work.
2780 rstfiles(U_KEEP
, G_p
->g_dirfd
);
2781 cstatus
= close(Ofile
);
2784 msg(EXTN
, "close error");
2788 /* we must use g_filesz for the amount of padding */
2789 pad
= (Pad_val
+ 1 - (G_p
->g_filesz
& Pad_val
)) & Pad_val
;
2792 Buffr
.b_out_p
+= pad
;
2795 if (proc_mode
!= P_SKIP
) {
2796 if (Hdr_type
== CRC
&&
2797 Gen
.g_cksum
!= data_in_info
->data_in_cksumval
) {
2798 msg(ERR
, "\"%s\" - checksum error", nam_p
);
2799 rstfiles(U_KEEP
, G_p
->g_dirfd
);
2801 rstfiles(U_OVER
, G_p
->g_dirfd
);
2802 if (Hdr_type
== BAR
&& data_in_info
->data_in_compress_flag
) {
2803 (void) pclose(data_in_info
->data_in_pipef
);
2805 cstatus
= close(Ofile
);
2809 msg(EXTN
, "close error");
2812 (void) free(data_in_info
);
2814 VERBOSE((proc_mode
!= P_SKIP
&& (Args
& (OCv
| OCV
))),
2815 (G_p
->g_attrparent_p
== NULL
) ? G_p
->g_nam_p
: G_p
->g_attrpath_p
);
2820 * Read regular file. Return number of bytes which weren't read.
2821 * Upon return, real_filesz will be real file size of input file.
2822 * When read_exact is specified, read size is adjusted to the given
2826 read_file(char *nam_p
, off_t file_size
, off_t
*real_filesz
,
2827 boolean_t read_exact
)
2836 amt_to_read
= file_size
;
2838 if (read_exact
&& amt_to_read
< CPIOBSZ
)
2839 readsz
= amt_to_read
;
2846 if ((amount_read
= read(Ifile
, Buffr
.b_in_p
, readsz
)) < 0) {
2847 msg(EXTN
, "Cannot read \"%s%s%s\"",
2848 (Gen
.g_attrnam_p
== NULL
) ?
2849 nam_p
: Gen
.g_attrfnam_p
,
2850 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
2851 gettext(" System Attribute ") :
2852 gettext(" Attribute "),
2853 (Gen
.g_attrnam_p
== NULL
) ? "" : nam_p
);
2857 if (amount_read
== 0) {
2858 /* got EOF. the file has shrunk */
2859 *real_filesz
= file_size
- amt_to_read
;
2861 } else if (amount_read
> amt_to_read
) {
2862 /* the file has grown */
2863 *real_filesz
= file_size
+
2864 (amount_read
- amt_to_read
);
2865 amount_read
= amt_to_read
;
2866 } else if (amount_read
== amt_to_read
) {
2867 /* the file is the same size */
2868 *real_filesz
= file_size
;
2871 Buffr
.b_in_p
+= amount_read
;
2872 Buffr
.b_cnt
+= (long)amount_read
;
2874 amt_to_read
-= (off_t
)amount_read
;
2876 amt_to_read
== 0 && amount_read
== CPIOBSZ
) {
2878 * If the file size is multiple of CPIOBSZ, we may
2879 * be able to read more from the file even though
2880 * amt_to_read already gets 0.
2883 amount_read
= read(Ifile
, Buffr
.b_in_p
, CPIOBSZ
);
2884 if (amount_read
!= 0) {
2885 /* the file has grown */
2886 *real_filesz
= file_size
+ amount_read
;
2889 } while (amt_to_read
!= 0);
2891 return (amt_to_read
);
2895 * Read through the data in files skipping holes.
2898 read_compress_holes(char *nam_p
, off_t file_size
, off_t
*real_filesz
,
2899 holes_info_t
*holes
, int *hole_changed
)
2902 off_t datasize
, realsz
;
2904 holes_list_t
*hl
= holes
->holes_list
;
2907 for (hl
= holes
->holes_list
; hl
!= NULL
; hl
= hl
->hl_next
) {
2908 datasize
= hl
->hl_hole
- hl
->hl_data
;
2910 npos
= lseek(Ifile
, curpos
, SEEK_DATA
);
2911 if (npos
== -1 && errno
== ENXIO
) {
2913 * No more data. There are two cases.
2914 * - we have a hole toward the end of file.
2915 * - file has been shrunk, and we've reached EOF.
2917 *real_filesz
= lseek(Ifile
, 0, SEEK_END
);
2918 if (hl
->hl_data
== file_size
)
2921 * File has been shrunk. Check the amount of data
2925 while (hl
!= NULL
) {
2926 left
+= (hl
->hl_hole
- hl
->hl_data
);
2934 if (curpos
!= hl
->hl_data
) {
2936 * File has been changed. We shouldn't read data
2937 * from different offset since we've already put
2941 (void) lseek(Ifile
, hl
->hl_data
, SEEK_SET
);
2942 curpos
= hl
->hl_data
;
2944 left
= read_file(nam_p
, datasize
, &realsz
, B_TRUE
);
2946 /* file has been shrunk */
2947 *real_filesz
= curpos
+ datasize
- left
;
2948 left
= file_size
- *real_filesz
;
2954 * We've read exact size of holes. We need to make sure
2955 * that file hasn't grown by reading from the EOF.
2958 (void) read_file(nam_p
, CPIOBSZ
, &realsz
, B_FALSE
);
2960 *real_filesz
= curpos
+ realsz
;
2965 * data_out: open(2) the file to be archived, compute the checksum
2966 * of it's data if the CRC header was specified and write the header.
2967 * read(2) each block of data and bwrite() it to the archive. For TARTYP (TAR
2968 * and USTAR) archives, pad the data with NULLs to the next 512 byte boundary.
2978 int hole_changed
= 0;
2980 holes_info_t
*holes
= NULL
;
2982 nam_p
= G_p
->g_nam_p
;
2984 if (Pflag
&& aclp
!= NULL
) {
2985 char *secinfo
= NULL
;
2988 /* append security attributes */
2989 if (append_secattr(&secinfo
, &len
, aclp
) == -1) {
2991 "can create security information");
2993 /* call append_secattr() if more than one */
2996 /* write ancillary only if there is sec info */
2997 write_hdr(ARCHIVE_ACL
, (off_t
)len
);
2998 write_ancillary(secinfo
, len
, B_TRUE
);
3001 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3002 rstfiles(U_KEEP
, G_p
->g_dirfd
);
3003 VERBOSE((Args
& (OCv
| OCV
)), nam_p
);
3006 if ((G_p
->g_mode
& Ftype
) == S_IFLNK
&& (Hdr_type
!=
3007 USTAR
&& Hdr_type
!= TAR
)) { /* symbolic link */
3009 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3011 FLUSH(G_p
->g_filesz
);
3014 /* Note that "size" and G_p->g_filesz are the same number */
3016 if ((size
= readlink(nam_p
, Buffr
.b_in_p
, G_p
->g_filesz
)) <
3018 msg(ERRN
, "Cannot read symbolic link \"%s\"", nam_p
);
3023 * Note that it is OK not to add the NUL after the name read by
3024 * readlink, because it is not being used subsequently.
3027 Buffr
.b_in_p
+= size
;
3028 Buffr
.b_cnt
+= size
;
3029 pad
= (Pad_val
+ 1 - (size
& Pad_val
)) & Pad_val
;
3032 (void) memset(Buffr
.b_in_p
, 0, pad
);
3033 Buffr
.b_in_p
+= pad
;
3036 VERBOSE((Args
& (OCv
| OCV
)), nam_p
);
3038 } else if ((G_p
->g_mode
& Ftype
) == S_IFLNK
&&
3039 (Hdr_type
== USTAR
|| Hdr_type
== TAR
)) {
3043 * G_p->g_filesz is the length of the right-hand side of
3044 * the symlink "x -> y".
3045 * The tar link field is only NAMSIZ long.
3048 if (G_p
->g_filesz
> NAMSIZ
) {
3050 "Symbolic link too long \"%s\"", nam_p
);
3053 if ((size
= readlink(nam_p
, T_lname
, G_p
->g_filesz
)) < 0) {
3055 "Cannot read symbolic link \"%s\"", nam_p
);
3058 T_lname
[size
] = '\0';
3059 G_p
->g_filesz
= (off_t
)0;
3060 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3061 VERBOSE((Args
& (OCv
| OCV
)), nam_p
);
3064 if ((Ifile
= openfile(O_RDONLY
)) < 0) {
3065 msg(ERR
, "\"%s%s%s\" ?",
3066 (Gen
.g_attrnam_p
== NULL
) ? nam_p
: Gen
.g_attrfnam_p
,
3067 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
3068 gettext(" System Attribute ") : gettext(" Attribute "),
3069 (Gen
.g_attrnam_p
== NULL
) ? "" :
3070 (Gen
.g_attrparent_p
== NULL
) ? Gen
.g_attrnam_p
:
3071 Gen
.g_attrparent_p
);
3075 /* save original file size */
3076 orig_filesz
= G_p
->g_filesz
;
3079 * Calculate the new compressed file size of a sparse file
3080 * before any of the header information is written
3083 if (Compress_sparse
&& S_ISREG(G_p
->g_mode
)) {
3085 * If the file being processed is a sparse file, gather the
3086 * hole information and the compressed file size.
3087 * G_p->g_filesz will need to be changed to be the size of
3088 * the compressed sparse file plus the the size of the hole
3089 * information that will be prepended to the compressed file
3092 holes
= get_holes_info(Ifile
, G_p
->g_filesz
, B_FALSE
);
3094 G_p
->g_filesz
= holes
->holesdata_sz
+ holes
->data_size
;
3096 if (G_p
->g_filesz
> Max_offset
) {
3097 msg(ERR
, "%s%s%s: too large to archive "
3100 (G_p
->g_attrnam_p
== NULL
) ? "" :
3102 gettext(" System Attribute ") :
3103 gettext(" Attribute "),
3104 (G_p
->g_attrnam_p
== NULL
) ? "" :
3105 ((G_p
->g_attrparent_p
== NULL
) ?
3107 G_p
->g_attrpath_p
));
3109 (void) close(Ifile
);
3111 free_holes_info(holes
);
3112 return; /* do not archive if it's too big */
3117 * Dump extended attribute header.
3120 if (Gen
.g_attrnam_p
!= NULL
) {
3124 if (Hdr_type
== CRC
) {
3125 long csum
= cksum(CRC
, 0, &errret
);
3127 G_p
->g_cksum
= (ulong_t
)-1;
3128 msg(POST
, "\"%s%s%s\" skipped",
3129 (Gen
.g_attrnam_p
== NULL
) ?
3130 nam_p
: Gen
.g_attrfnam_p
,
3131 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
3132 gettext(" System Attribute ") :
3133 gettext(" Attribute "),
3134 (Gen
.g_attrnam_p
== NULL
) ? "" : nam_p
);
3136 free_holes_info(holes
);
3137 (void) close(Ifile
);
3140 G_p
->g_cksum
= csum
;
3146 * ACL has been retrieved in getname().
3149 char *secinfo
= NULL
;
3152 /* append security attributes */
3153 if ((append_secattr(&secinfo
, &len
, aclp
)) == -1)
3154 msg(ERR
, "can create security information");
3156 /* call append_secattr() if more than one */
3159 /* write ancillary only if there is sec info */
3160 write_hdr(ARCHIVE_ACL
, (off_t
)len
);
3161 write_ancillary(secinfo
, len
, B_TRUE
);
3165 if (holes
!= NULL
) {
3167 * Write the header info with a modified c_mode field to
3168 * indicate a compressed sparse file is being archived,
3169 * as well as the new file size, including the size of the
3170 * compressed file as well as all the prepended data.
3172 write_hdr(ARCHIVE_SPARSE
, (off_t
)0);
3173 /* Prepend sparse file info */
3174 write_ancillary(holes
->holesdata
,
3175 holes
->holesdata_sz
, B_FALSE
);
3177 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3182 if (holes
!= NULL
) {
3183 amt_to_read
= read_compress_holes(nam_p
, G_p
->g_filesz
,
3184 &real_filesz
, holes
, &hole_changed
);
3186 amt_to_read
= read_file(nam_p
, G_p
->g_filesz
,
3187 &real_filesz
, B_FALSE
);
3190 while (amt_to_read
> 0) {
3191 cnt
= (amt_to_read
> CPIOBSZ
) ? CPIOBSZ
: (int)amt_to_read
;
3193 (void) memset(Buffr
.b_in_p
, 0, cnt
);
3194 Buffr
.b_in_p
+= cnt
;
3199 pad
= (Pad_val
+ 1 - (G_p
->g_filesz
& Pad_val
)) & Pad_val
;
3202 (void) memset(Buffr
.b_in_p
, 0, pad
);
3203 Buffr
.b_in_p
+= pad
;
3207 if (hole_changed
== 1) {
3209 "File data and hole offsets of \"%s%s%s\" have changed",
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
);
3216 if (real_filesz
> orig_filesz
) {
3217 msg(ERR
, "File size of \"%s%s%s\" has increased by %lld",
3218 (Gen
.g_attrnam_p
== NULL
) ?
3219 G_p
->g_nam_p
: Gen
.g_attrfnam_p
,
3220 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
3221 gettext(" System Attribute ") : gettext(" Attribute "),
3222 (Gen
.g_attrnam_p
== NULL
) ? "" : G_p
->g_nam_p
,
3223 (real_filesz
- orig_filesz
));
3225 if (real_filesz
< orig_filesz
) {
3226 msg(ERR
, "File size of \"%s%s%s\" has decreased by %lld",
3227 (Gen
.g_attrnam_p
== NULL
) ?
3228 G_p
->g_nam_p
: Gen
.g_attrfnam_p
,
3229 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
3230 gettext(" System Attribute ") : gettext(" Attribute "),
3231 (Gen
.g_attrnam_p
== NULL
) ? "" : G_p
->g_nam_p
,
3232 (orig_filesz
- real_filesz
));
3236 free_holes_info(holes
);
3238 (void) close(Ifile
);
3239 rstfiles(U_KEEP
, G_p
->g_dirfd
);
3240 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
3244 * data_pass: If not a special file (Aspec), open(2) the file to be
3245 * transferred, read(2) each block of data and write(2) it to the output file
3246 * Ofile, which was opened in file_pass().
3253 char *namep
= Nam_p
;
3254 holes_info_t
*holes
= NULL
;
3255 data_in_t
*data_in_info
;
3257 if (G_p
->g_attrnam_p
!= NULL
) {
3258 namep
= G_p
->g_attrnam_p
;
3261 rstfiles(U_KEEP
, G_p
->g_passdirfd
);
3262 cstatus
= close(Ofile
);
3264 VERBOSE((Args
& (OCv
| OCV
)), Nam_p
);
3266 msg(EXTN
, "close error");
3270 if ((Ifile
= openat(G_p
->g_dirfd
, get_component(namep
), 0)) < 0) {
3271 msg(ERRN
, "Cannot open \"%s%s%s\", skipped",
3272 (G_p
->g_attrnam_p
== NULL
) ? Nam_p
: G_p
->g_attrfnam_p
,
3273 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_rw_sysattr
?
3274 gettext(" System Attribute ") : gettext(" Attribute "),
3275 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
3276 rstfiles(U_KEEP
, G_p
->g_passdirfd
);
3277 cstatus
= close(Ofile
);
3280 msg(EXTN
, "close error");
3285 data_in_info
= e_zalloc(E_EXIT
, sizeof (data_in_t
));
3286 data_in_info
->data_in_proc_mode
= P_PROC
;
3288 if (S_ISREG(G_p
->g_mode
))
3289 holes
= get_holes_info(Ifile
, G_p
->g_filesz
, B_TRUE
);
3291 if (holes
!= NULL
) {
3292 rv
= data_copy_with_holes(Ifile
, Ofile
,
3293 (G_p
->g_attrnam_p
== NULL
) ? 0 : G_p
->g_rw_sysattr
,
3294 G_p
->g_filesz
, Bufsize
, data_in_info
, holes
);
3296 free_holes_info(holes
);
3298 rv
= data_copy(Ifile
, Ofile
,
3299 (G_p
->g_attrnam_p
== NULL
) ? 0 : G_p
->g_rw_sysattr
,
3300 G_p
->g_filesz
, Bufsize
, data_in_info
);
3304 /* read error or unexpected EOF */
3305 if (data_in_info
->data_in_rd_eof
) {
3307 * read has reached EOF unexpectedly, but this isn't
3308 * an error since it's the latest shape of the file.
3310 msg(EPOST
, "File size of \"%s%s%s\" has decreased",
3311 (G_p
->g_attrnam_p
== NULL
) ?
3312 Nam_p
: G_p
->g_attrfnam_p
,
3313 (G_p
->g_attrnam_p
== NULL
) ? "" :
3314 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
3315 gettext(" Attribute "),
3316 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
3318 /* It's not error. We'll use the new file */
3322 msg(ERRN
, "Cannot read \"%s%s%s\"",
3323 (G_p
->g_attrnam_p
== NULL
) ?
3324 Nam_p
: G_p
->g_attrfnam_p
,
3325 (G_p
->g_attrnam_p
== NULL
) ? "" :
3326 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
3327 gettext(" Attribute "),
3328 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
3330 } else if (rv
> 0) {
3333 msg(ERRN
, "Cannot write \"%s%s%s\"", Over_p
,
3334 (G_p
->g_attrnam_p
== NULL
) ? "" :
3335 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
3336 gettext(" Attribute "),
3337 (G_p
->g_attrnam_p
== NULL
) ? "" : Over_p
);
3339 msg(ERRN
, "Cannot write \"%s%s%s\"",
3341 (G_p
->g_attrnam_p
== NULL
) ? "" :
3342 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
3343 gettext(" Attribute "),
3344 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
3351 rstfiles(U_OVER
, G_p
->g_passdirfd
);
3353 rstfiles(U_KEEP
, G_p
->g_passdirfd
);
3356 (void) close(Ifile
);
3357 cstatus
= close(Ofile
);
3360 msg(EXTN
, "close error");
3362 VERBOSE((Args
& (OCv
| OCV
)), Fullnam_p
);
3367 * file_in: Process an object from the archive. If a TARTYP (TAR or USTAR)
3368 * archive and g_nlink == 1, link this file to the file name in t_linkname
3369 * and return. Handle linked files in one of two ways. If Onecopy == 0, this
3370 * is an old style (binary or -c) archive, create and extract the data for the
3371 * first link found, link all subsequent links to this file and skip their data.
3372 * If Oncecopy == 1, save links until all have been processed, and then
3373 * process the links first to last checking their names against the patterns
3374 * and/or asking the user to rename them. The first link that is accepted
3375 * for xtraction is created and the data is read from the archive.
3376 * All subsequent links that are accepted are linked to this file.
3381 struct Lnk
*l_p
, *tl_p
;
3382 int lnkem
= 0, cleanup
= 0;
3392 * Now that we've read the extended header,
3393 * determine if we should restore attributes.
3394 * Don't restore the attribute if we are extracting
3395 * a file from an archive (as opposed to doing a table of
3396 * contents) and any of the following are true:
3397 * 1. neither -@ or -/ was specified.
3398 * 2. -@ was specified, -/ wasn't specified, and we're
3399 * processing a hidden attribute directory of an attribute
3400 * or we're processing a read-write system attribute file.
3401 * 3. -@ wasn't specified, -/ was specified, and the file
3402 * we're processing it not a read-write system attribute file,
3403 * or we're processing the hidden attribute directory of an
3406 * We always process the attributes if we're just generating
3407 * generating a table of contents, or if both -@ and -/ were
3410 if (G_p
->g_attrnam_p
!= NULL
) {
3411 if (((Args
& OCt
) == 0) &&
3412 ((!Atflag
&& !SysAtflag
) ||
3413 (Atflag
&& !SysAtflag
&& ((G_p
->g_attrparent_p
!= NULL
) ||
3414 G_p
->g_rw_sysattr
)) ||
3415 (!Atflag
&& SysAtflag
&& ((G_p
->g_attrparent_p
!= NULL
) ||
3416 !G_p
->g_rw_sysattr
)))) {
3424 * Open target directory if this isn't a skipped file
3427 * Links are handled further down in this function.
3430 proc_file
= ckname(0);
3432 if (proc_file
== F_SKIP
&& G_p
->g_nlink
== 1) {
3434 * Normally ckname() prints out the file as a side
3435 * effect except for table of contents listing
3436 * when its parameter is zero and Onecopy isn't
3437 * Zero. Due to this we need to force the name
3438 * to be printed here.
3441 VERBOSE((Args
& OCt
), G_p
->g_nam_p
);
3447 if (proc_file
!= F_SKIP
&& open_dirfd() != 0) {
3452 if (Hdr_type
== BAR
) {
3459 * For archives in USTAR format, the files are extracted according
3462 if (Hdr_type
== USTAR
|| Hdr_type
== TAR
) {
3463 typeflag
= Thdr_p
->tbuf
.t_typeflag
;
3464 if (G_p
->g_nlink
== 1) { /* hard link */
3465 if (proc_file
!= F_SKIP
) {
3467 char lname
[NAMSIZ
+1];
3468 (void) memset(lname
, '\0', sizeof (lname
));
3470 (void) strncpy(lname
, Thdr_p
->tbuf
.t_linkname
,
3472 for (i
= 0; i
<= NAMSIZ
&& lname
[i
] != 0; i
++)
3476 (void) creat_lnk(G_p
->g_dirfd
,
3477 &lname
[0], G_p
->g_nam_p
);
3482 if (typeflag
== '3' || typeflag
== '4' || typeflag
== '5' ||
3484 if (proc_file
!= F_SKIP
&&
3485 creat_spec(G_p
->g_dirfd
) > 0) {
3486 VERBOSE((Args
& (OCv
| OCV
)),
3487 (G_p
->g_attrparent_p
== NULL
) ?
3488 G_p
->g_nam_p
: G_p
->g_attrpath_p
);
3492 } else if (Adir
|| Aspec
) {
3493 if ((proc_file
== F_SKIP
) ||
3494 (Ofile
= openout(G_p
->g_dirfd
)) < 0) {
3505 if (proc_file
!= F_SKIP
&& creat_spec(G_p
->g_dirfd
) > 0) {
3506 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
3510 VERBOSE((Args
& OCt
), G_p
->g_nam_p
);
3514 if (G_p
->g_nlink
== 1 || (Hdr_type
== TAR
||
3515 Hdr_type
== USTAR
)) {
3517 if (proc_file
!= F_SKIP
&& creat_spec(G_p
->g_dirfd
) > 0)
3518 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
3520 if ((proc_file
== F_SKIP
) ||
3521 (Ofile
= openout(G_p
->g_dirfd
)) < 0) {
3532 tl_p
= add_lnk(&ttl_p
);
3534 if (l_p
->L_cnt
== l_p
->L_gen
.g_nlink
)
3536 if (!Onecopy
|| G_p
->g_attrnam_p
!= NULL
) {
3537 lnkem
= (tl_p
!= l_p
) ? 1 : 0;
3539 if (proc_file
== F_SKIP
) {
3542 if (open_dirfd() != 0)
3546 if (creat_spec(G_p
->g_dirfd
) > 0)
3547 VERBOSE((Args
& (OCv
| OCV
)),
3550 openout(G_p
->g_dirfd
)) < 0) {
3560 * Are we linking an attribute?
3563 if (l_p
->L_gen
.g_attrnam_p
!= NULL
) {
3564 (void) strcpy(Lnkend_p
,
3565 l_p
->L_gen
.g_attrnam_p
);
3566 (void) strcpy(Full_p
,
3567 tl_p
->L_gen
.g_attrnam_p
);
3569 (void) fchdir(G_p
->g_dirfd
);
3571 (void) strcpy(Lnkend_p
,
3572 l_p
->L_gen
.g_nam_p
);
3573 (void) strcpy(Full_p
,
3574 tl_p
->L_gen
.g_nam_p
);
3576 (void) creat_lnk(G_p
->g_dirfd
,
3580 l_p
->L_lnk_p
= NULL
;
3581 free(tl_p
->L_gen
.g_nam_p
);
3587 } else { /* Onecopy */
3588 if (tl_p
->L_gen
.g_filesz
)
3592 return; /* don't do anything yet */
3596 * ckname will clear aclchar. We need to keep aclchar for
3600 while (tl_p
!= NULL
) {
3603 if ((proc_file
= ckname(1)) != F_SKIP
) {
3604 if (open_dirfd() != 0) {
3608 (void) creat_lnk(G_p
->g_dirfd
,
3612 (void) creat_spec(G_p
->g_dirfd
);
3614 VERBOSE((Args
& (OCv
| OCV
)),
3617 openout(G_p
->g_dirfd
)) < 0) {
3623 } /* (proc_file = ckname(1)) != F_SKIP */
3625 tl_p
= tl_p
->L_lnk_p
;
3629 if (proc_file
== F_SKIP
&& !cleanup
) {
3630 tl_p
->L_nxt_p
= l_p
->L_nxt_p
;
3631 tl_p
->L_bck_p
= l_p
->L_bck_p
;
3632 l_p
->L_bck_p
->L_nxt_p
= tl_p
;
3633 l_p
->L_nxt_p
->L_bck_p
= tl_p
;
3634 free(l_p
->L_gen
.g_nam_p
);
3637 } /* tl_p->L_lnk_p != NULL */
3638 if (l_p
->L_data
== 0) {
3648 * file_out: If the current file is not a special file (!Aspec) and it
3649 * is identical to the archive, skip it (do not archive the archive if it
3650 * is a regular file). If creating a TARTYP (TAR or USTAR) archive, the first
3651 * time a link to a file is encountered, write the header and file out normally.
3652 * Subsequent links to this file put this file name in their t_linkname field.
3653 * Otherwise, links are handled in one of two ways, for the old headers
3654 * (i.e. binary and -c), linked files are written out as they are encountered.
3655 * For the new headers (ASC and CRC), links are saved up until all the links
3656 * to each file are found. For a file with n links, write n - 1 headers with
3657 * g_filesz set to 0, write the final (nth) header with the correct g_filesz
3658 * value and write the data for the file to the archive.
3664 struct Lnk
*l_p
, *tl_p
;
3669 if (!Aspec
&& IDENT(SrcSt
, ArchSt
))
3670 return (1); /* do not archive the archive if it's a reg file */
3672 * If compressing sparse files, wait until the compressed file size
3673 * is known to check if file size is too big.
3675 if (Compress_sparse
== 0 && G_p
->g_filesz
> Max_offset
) {
3676 msg(ERR
, "%s%s%s: too large to archive in current mode",
3678 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_rw_sysattr
?
3679 gettext(" System Attribute ") : gettext(" Attribute "),
3680 (G_p
->g_attrnam_p
== NULL
) ? "" :
3681 ((G_p
->g_attrparent_p
== NULL
) ? G_p
->g_attrnam_p
:
3682 G_p
->g_attrpath_p
));
3683 return (1); /* do not archive if it's too big */
3685 if (Hdr_type
== TAR
|| Hdr_type
== USTAR
) { /* TAR and USTAR */
3687 if (Gen
.g_attrnam_p
!= NULL
) {
3690 write_hdr(ARCHIVE_NORMAL
, 0);
3693 if (G_p
->g_nlink
== 1) {
3697 tl_p
= add_lnk(&ttl_p
);
3699 if (tl_p
== l_p
) { /* first link to this file encountered */
3703 (void) strncpy(T_lname
, l_p
->L_gen
.g_nam_p
,
3704 l_p
->L_gen
.g_namesz
);
3707 * check if linkname is greater than 100 characters
3709 if (strlen(T_lname
) > NAMSIZ
) {
3710 msg(EPOST
, "cpio: %s: linkname %s is greater than %d",
3711 G_p
->g_nam_p
, T_lname
, NAMSIZ
);
3715 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3716 VERBOSE((Args
& (OCv
| OCV
)), tl_p
->L_gen
.g_nam_p
);
3718 /* find the lnk entry in sublist, unlink it, and free it */
3719 for (; ttl_p
->L_lnk_p
!= NULL
;
3720 ttl_p
= ttl_p
->L_lnk_p
) {
3721 if (ttl_p
->L_lnk_p
== tl_p
) {
3722 ttl_p
->L_lnk_p
= tl_p
->L_lnk_p
;
3723 free(tl_p
->L_gen
.g_nam_p
);
3733 * ACL has been retrieved in getname().
3736 char *secinfo
= NULL
;
3739 /* append security attributes */
3740 if ((append_secattr(&secinfo
, &len
, aclp
)) == -1)
3741 msg(ERR
, "can create security information");
3743 /* call append_secattr() if more than one */
3746 /* write ancillary */
3747 write_hdr(ARCHIVE_ACL
, (off_t
)len
);
3748 write_ancillary(secinfo
, len
, B_TRUE
);
3752 if (Gen
.g_attrnam_p
!= NULL
) {
3755 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3756 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
3759 if (G_p
->g_nlink
== 1) {
3763 tl_p
= add_lnk(&ttl_p
);
3766 if (l_p
->L_cnt
== l_p
->L_gen
.g_nlink
)
3768 else if (Onecopy
&& G_p
->g_attrnam_p
== NULL
) {
3769 return (0); /* don't process data yet */
3772 if (Onecopy
&& G_p
->g_attrnam_p
== NULL
) {
3774 while (tl_p
->L_lnk_p
!= NULL
) {
3776 G_p
->g_filesz
= (off_t
)0;
3777 /* one link with the acl is sufficient */
3778 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3779 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
3780 tl_p
= tl_p
->L_lnk_p
;
3783 if (open_dirfd() != 0)
3786 /* old style: has acl and data for every link */
3794 * Verify the underlying file system supports the attribute type.
3795 * Only archive extended attribute files when '-@' was specified.
3796 * Only archive system extended attribute files if '-/' was specified.
3798 #if defined(O_XATTR)
3799 static attr_status_t
3800 verify_attr_support(char *filename
, int attrflg
, arc_action_t actflag
,
3804 * Verify extended attributes are supported/exist. We only
3805 * need to check if we are processing a base file, not an
3806 * extended attribute.
3809 *ext_attrflg
= (pathconf(filename
, (actflag
== ARC_CREATE
) ?
3810 _PC_XATTR_EXISTS
: _PC_XATTR_ENABLED
) == 1);
3813 #if defined(_PC_SATTR_ENABLED)
3814 if (!*ext_attrflg
) {
3816 /* Verify system attributes are supported */
3817 if (sysattr_support(filename
,
3818 (actflag
== ARC_CREATE
) ?_PC_SATTR_EXISTS
:
3819 _PC_SATTR_ENABLED
) != 1) {
3820 return (ATTR_SATTR_ERR
);
3823 return (ATTR_XATTR_ERR
);
3825 return (ATTR_XATTR_ERR
);
3826 #endif /* _PC_SATTR_ENABLED */
3829 #if defined(_PC_SATTR_ENABLED)
3830 } else if (SysAtflag
) {
3831 /* Verify system attributes are supported */
3832 if (sysattr_support(filename
, (actflag
== ARC_CREATE
) ?
3833 _PC_SATTR_EXISTS
: _PC_SATTR_ENABLED
) != 1) {
3834 return (ATTR_SATTR_ERR
);
3836 #endif /* _PC_SATTR_ENABLED */
3845 #if defined(O_XATTR)
3847 * Verify the attribute, attrname, is an attribute we want to restore.
3848 * Never restore read-only system attribute files. Only restore read-write
3849 * system attributes files when -/ was specified, and only traverse into
3850 * the 2nd level attribute directory containing only system attributes if
3851 * -@ was specified. This keeps us from archiving
3852 * <attribute name>/<read-write system attribute file>
3853 * when -/ was specified without -@.
3855 * attrname - attribute file name
3856 * attrparent - attribute's parent name within the base file's
3857 * attribute digrectory hierarchy
3858 * arc_rwsysattr - flag that indicates that read-write system attribute
3859 * file should be archived as it contains other than
3860 * the default system attributes.
3861 * rw_sysattr - on return, flag will indicate if attrname is a
3862 * read-write system attribute file.
3864 static attr_status_t
3865 verify_attr(char *attrname
, char *attrparent
, int arc_rwsysattr
,
3868 #if defined(_PC_SATTR_ENABLED)
3871 /* Never restore read-only system attribute files */
3872 if ((attr_supported
= sysattr_type(attrname
)) == _RO_SATTR
) {
3876 *rw_sysattr
= (attr_supported
== _RW_SATTR
);
3880 * Don't archive a read-write system attribute file if
3881 * it contains only the default system attributes.
3883 if (*rw_sysattr
&& !arc_rwsysattr
) {
3888 /* Never restore read-only system attribute files */
3889 if ((*rw_sysattr
= is_sysattr(attrname
)) == 1) {
3892 #endif /* _PC_SATTR_ENABLED */
3895 * Only restore read-write system attribute files
3896 * when -/ was specified. Only restore extended
3897 * attributes when -@ was specified.
3902 * Only archive/restore the hidden directory "." if
3903 * we're processing the top level hidden attribute
3904 * directory. We don't want to process the
3905 * hidden attribute directory of the attribute
3906 * directory that contains only extended system
3909 if (*rw_sysattr
|| (Hiddendir
&&
3910 (attrparent
!= NULL
))) {
3914 } else if (SysAtflag
) {
3916 * Only archive/restore read-write extended system attribute
3917 * files of the base file.
3919 if (!*rw_sysattr
|| (attrparent
!= NULL
)) {
3930 #if defined(O_XATTR)
3932 retry_open_attr(int pdirfd
, int cwd
, char *fullname
, char *pattr
, char *name
,
3933 int oflag
, mode_t mode
)
3937 struct timeval times
[2];
3939 struct stat parentstat
;
3944 * We couldn't get to attrdir. See if its
3945 * just a mode problem on the parent file.
3946 * for example: a mode such as r-xr--r--
3947 * on a ufs file system without extended
3948 * system attribute support won't let us
3949 * create an attribute dir if it doesn't
3950 * already exist, and on a ufs file system
3951 * with extended system attribute support
3952 * won't let us open the attribute for
3955 * If file has a non-trivial ACL, then save it
3956 * off so that we can place it back on after doing
3959 if ((dirfd
= openat(cwd
, (pattr
== NULL
) ? fullname
: pattr
,
3963 if (fstat(dirfd
, &parentstat
) == -1) {
3964 msg(ERRN
, "Cannot stat %sfile %s",
3965 (pdirfd
== -1) ? "" : gettext("parent of "),
3966 (pdirfd
== -1) ? fullname
: name
);
3967 (void) close(dirfd
);
3970 if ((error
= facl_get(dirfd
, ACL_NO_TRIVIAL
, &aclp
)) != 0) {
3971 msg(ERRN
, "Failed to retrieve ACL on %sfile %s",
3972 (pdirfd
== -1) ? "" : gettext("parent of "),
3973 (pdirfd
== -1) ? fullname
: name
);
3974 (void) close(dirfd
);
3978 newmode
= S_IWUSR
| parentstat
.st_mode
;
3979 if (fchmod(dirfd
, newmode
) == -1) {
3980 msg(ERRN
, "Cannot change mode of %sfile %s to %o",
3981 (pdirfd
== -1) ? "" : gettext("parent of "),
3982 (pdirfd
== -1) ? fullname
: name
, newmode
);
3985 (void) close(dirfd
);
3992 * We weren't able to create the attribute directory before.
3995 ofilefd
= attropen(fullname
, ".", oflag
);
3998 * We weren't able to create open the attribute before.
4001 ofilefd
= openat(pdirfd
, name
, oflag
, mode
);
4005 * Put mode back to original
4007 if (fchmod(dirfd
, parentstat
.st_mode
) == -1) {
4008 msg(ERRN
, "Cannot restore permissions of %sfile %s to %o",
4009 (pdirfd
== -1) ? "" : gettext("parent of "),
4010 (pdirfd
== -1) ? fullname
: name
, newmode
);
4014 error
= facl_set(dirfd
, aclp
);
4016 msg(ERRN
, "failed to set acl entries on %sfile %s\n",
4017 (pdirfd
== -1) ? "" : gettext("parent of "),
4018 (pdirfd
== -1) ? fullname
: name
);
4024 * Put back time stamps
4027 times
[0].tv_sec
= parentstat
.st_atime
;
4028 times
[0].tv_usec
= 0;
4029 times
[1].tv_sec
= parentstat
.st_mtime
;
4030 times
[1].tv_usec
= 0;
4032 (void) futimesat(cwd
, (pattr
== NULL
) ? fullname
: pattr
, times
);
4034 (void) close(dirfd
);
4040 #if defined(O_XATTR)
4042 * Recursively open attribute directories until the attribute directory
4043 * containing the specified attribute, attrname, is opened.
4045 * Currently, only 2 directory levels of attributes are supported, (i.e.,
4046 * extended system attributes on extended attributes). The following are
4047 * the possible input combinations:
4048 * 1. Open the attribute directory of the base file (don't change
4050 * attr_parent = NULL
4052 * 2. Open the attribute directory of the base file and change into it.
4053 * attr_parent = NULL
4054 * attrname = <attr> | <sys_attr>
4055 * 3. Open the attribute directory of the base file, change into it,
4056 * then recursively call open_attr_dir() to open the attribute's
4057 * parent directory (don't change into it).
4058 * attr_parent = <attr>
4060 * 4. Open the attribute directory of the base file, change into it,
4061 * then recursively call open_attr_dir() to open the attribute's
4062 * parent directory and change into it.
4063 * attr_parent = <attr>
4064 * attrname = <attr> | <sys_attr>
4066 * An attribute directory will be opened only if the underlying file system
4067 * supports the attribute type, and if the command line specifications
4068 * (f_extended_attr and f_sys_attr) enable the processing of the attribute
4071 * On succesful return, attr_parentfd will be the file descriptor of the
4072 * opened attribute directory. In addition, if the attribute is a read-write
4073 * extended system attribute, rw_sysattr will be set to 1, otherwise
4074 * it will be set to 0.
4076 * Possible return values:
4077 * ATTR_OK Successfully opened and, if needed, changed into the
4078 * attribute directory containing attrname.
4079 * ATTR_SKIP The command line specifications don't enable the
4080 * processing of the attribute type.
4081 * ATTR_CHDIR_ERR An error occurred while trying to change into an
4082 * attribute directory.
4083 * ATTR_OPEN_ERR An error occurred while trying to open an
4084 * attribute directory.
4085 * ATTR_XATTR_ERR The underlying file system doesn't support extended
4087 * ATTR_SATTR_ERR The underlying file system doesn't support extended
4088 * system attributes.
4091 open_attr_dir(char *attrname
, char *dirp
, int cwd
, char *attr_parent
,
4092 int *attr_parentfd
, int *rw_sysattr
)
4095 int firsttime
= (*attr_parentfd
== -1);
4100 * open_attr_dir() was recursively called (input combination number 4),
4101 * close the previously opened file descriptor as we've already changed
4105 (void) close(*attr_parentfd
);
4106 *attr_parentfd
= -1;
4110 * Verify that the underlying file system supports the restoration
4113 if ((rc
= verify_attr_support(dirp
, firsttime
, ARC_RESTORE
,
4114 &ext_attr
)) != ATTR_OK
) {
4118 /* Open the base file's attribute directory */
4119 if ((*attr_parentfd
= attropen(dirp
, ".", O_RDONLY
)) == -1) {
4121 * Save the errno from the attropen so it can be reported
4122 * if the retry of the attropen fails.
4125 if ((*attr_parentfd
= retry_open_attr(-1, cwd
, dirp
,
4126 NULL
, ".", O_RDONLY
, 0)) == -1) {
4127 (void) close(*attr_parentfd
);
4128 *attr_parentfd
= -1;
4130 return (ATTR_OPEN_ERR
);
4135 * Change into the parent attribute's directory unless we are
4136 * processing the hidden attribute directory of the base file itself.
4138 if ((Hiddendir
== 0) || (firsttime
&& (attr_parent
!= NULL
))) {
4139 if (fchdir(*attr_parentfd
) != 0) {
4141 (void) close(*attr_parentfd
);
4142 *attr_parentfd
= -1;
4144 return (ATTR_CHDIR_ERR
);
4148 /* Determine if the attribute should be processed */
4149 if ((rc
= verify_attr(attrname
, attr_parent
, 1,
4150 rw_sysattr
)) != ATTR_OK
) {
4152 (void) close(*attr_parentfd
);
4153 *attr_parentfd
= -1;
4159 * If the attribute is an extended system attribute of an attribute
4160 * (i.e., <attr>/<sys_attr>), then recursively call open_attr_dir() to
4161 * open the attribute directory of the parent attribute.
4163 if (firsttime
&& (attr_parent
!= NULL
)) {
4164 return (open_attr_dir(attrname
, attr_parent
, *attr_parentfd
,
4165 attr_parent
, attr_parentfd
, rw_sysattr
));
4173 * file_pass: If the -l option is set (link files when possible), and the
4174 * source and destination file systems are the same, link the source file
4175 * (G_p->g_nam_p) to the destination file (Fullnam) and return. If not a
4176 * linked file, transfer the data. Otherwise, the first link to a file
4177 * encountered is transferred normally and subsequent links are linked to it.
4183 struct Lnk
*l_p
, *tl_p
;
4192 if (Adir
&& !(Args
& OCd
)) {
4193 msg(ERR
, "Use -d option to copy \"%s\"", G_p
->g_nam_p
);
4194 return (FILE_PASS_ERR
);
4197 save_name
= G_p
->g_nam_p
;
4199 while (*(G_p
->g_nam_p
) == '/') {
4203 (void) strcpy(Full_p
, (G_p
->g_attrfnam_p
== NULL
) ?
4204 G_p
->g_nam_p
: G_p
->g_attrfnam_p
);
4206 if (G_p
->g_attrnam_p
== NULL
) {
4207 G_p
->g_passdirfd
= open_dir(Fullnam_p
);
4209 if (G_p
->g_passdirfd
== -1) {
4211 "Cannot open/create \"%s\"", Fullnam_p
);
4212 return (FILE_PASS_ERR
);
4218 * Open the file's attribute directory.
4219 * Change into the base file's starting directory then call
4220 * open_attr_dir() to open the attribute directory of either
4221 * the base file (if G_p->g_attrparent_p is NULL) or the
4222 * attribute (if G_p->g_attrparent_p is set) of the base file.
4225 G_p
->g_passdirfd
= -1;
4226 (void) fchdir(G_p
->g_baseparent_fd
);
4227 (void) open_attr_dir(G_p
->g_attrnam_p
, Fullnam_p
,
4228 G_p
->g_baseparent_fd
, (G_p
->g_attrparent_p
== NULL
) ? NULL
:
4229 G_p
->g_attrparent_p
, &G_p
->g_passdirfd
, &rw_sysattr
);
4230 if (G_p
->g_passdirfd
== -1) {
4232 "Cannot open attribute directory of "
4233 "%s%s%sfile \"%s\"",
4234 (G_p
->g_attrparent_p
== NULL
) ? "" :
4235 gettext("attribute \""),
4236 (G_p
->g_attrparent_p
== NULL
) ? "" :
4237 G_p
->g_attrparent_p
,
4238 (G_p
->g_attrparent_p
== NULL
) ? "" :
4239 gettext("\" of "), Fullnam_p
);
4240 return (FILE_PASS_ERR
);
4245 /* We are linking back to the source directory. */
4248 char *existingfile
= save_name
;
4250 if ((Args
& OCL
) && issymlink
) {
4251 /* We are chasing symlinks. */
4253 if ((size
= readlink(save_name
, Symlnk_p
,
4256 "Cannot read symbolic link \"%s\"",
4258 return (FILE_PASS_ERR
);
4261 Symlnk_p
[size
] = '\0';
4262 existingfile
= Symlnk_p
;
4265 if (G_p
->g_attrnam_p
== NULL
) {
4266 if (creat_lnk(G_p
->g_passdirfd
,
4267 existingfile
, Fullnam_p
) == 0) {
4268 return (FILE_LINKED
);
4274 if ((G_p
->g_mode
& Ftype
) == S_IFLNK
&& !(Args
& OCL
)) {
4275 /* The archive file is a symlink. */
4279 if ((size
= readlink(save_name
, Symlnk_p
, MAXPATHLEN
)) < 0) {
4281 "Cannot read symbolic link \"%s\"", save_name
);
4282 return (FILE_PASS_ERR
);
4286 (void) missdir(Fullnam_p
);
4287 *(Symlnk_p
+ size
) = '\0';
4289 if (symlink(Symlnk_p
, Fullnam_p
) < 0) {
4290 if (errno
== EEXIST
) {
4291 if (openout(G_p
->g_passdirfd
) < 0) {
4292 if (errno
!= EEXIST
) {
4294 "Cannot create \"%s\"",
4297 return (FILE_PASS_ERR
);
4300 msg(ERRN
, "Cannot create \"%s\"", Fullnam_p
);
4301 return (FILE_PASS_ERR
);
4305 if (lchown(Fullnam_p
, (int)Rpw_p
->pw_uid
,
4306 (int)Rpw_p
->pw_gid
) < 0) {
4308 "Error during chown() of \"%s\"",
4311 } else if ((lchown(Fullnam_p
, (int)G_p
->g_uid
,
4312 (int)G_p
->g_gid
) < 0) && privileged
) {
4314 "Error during chown() of \"%s\"",
4319 VERBOSE((Args
& (OCv
| OCV
)), Fullnam_p
);
4320 return (FILE_PASS_ERR
);
4323 if (!Adir
&& G_p
->g_nlink
> 1) {
4324 /* The archive file has hard links. */
4326 tl_p
= add_lnk(&ttl_p
);
4330 /* The archive file was not found. */
4334 /* The archive file was found. */
4338 if (l_p
->L_gen
.g_attrnam_p
!= NULL
) {
4339 /* We are linking an attribute */
4341 (void) strcpy(Lnkend_p
, l_p
->L_gen
.g_attrnam_p
);
4343 (void) fchdir(G_p
->g_passdirfd
);
4344 lfrom
= get_component(Lnknam_p
);
4345 lto
= tl_p
->L_gen
.g_attrnam_p
;
4347 /* We are not linking an attribute */
4349 (void) strcpy(Lnkend_p
, l_p
->L_gen
.g_nam_p
);
4350 (void) strcpy(Full_p
, tl_p
->L_gen
.g_nam_p
);
4355 (void) creat_lnk(G_p
->g_passdirfd
, lfrom
, lto
);
4361 l_p
->L_lnk_p
= NULL
;
4362 free(tl_p
->L_gen
.g_nam_p
);
4365 if (l_p
->L_cnt
== G_p
->g_nlink
) {
4369 return (FILE_LINKED
);
4373 if (Adir
|| Aspec
) {
4375 * The archive file is a directory, block special, char
4376 * special or a fifo.
4379 if (creat_spec(G_p
->g_passdirfd
) > 0) {
4380 VERBOSE((Args
& (OCv
| OCV
)), Fullnam_p
);
4382 } else if ((Ofile
= openout(G_p
->g_passdirfd
)) > 0) {
4386 return (FILE_COPIED
);
4390 * flush_lnks: With new linked file handling, linked files are not archived
4391 * until all links have been collected. When the end of the list of filenames
4392 * to archive has been reached, all files that did not encounter all their links
4393 * are written out with actual (encountered) link counts. A file with n links
4394 * (that are archived) will be represented by n headers (one for each link (the
4395 * first n - 1 have g_filesz set to 0)) followed by the data for the file.
4401 struct Lnk
*l_p
, *tl_p
;
4404 l_p
= Lnk_hd
.L_nxt_p
;
4405 while (l_p
!= &Lnk_hd
) {
4406 (void) strcpy(Gen
.g_nam_p
, l_p
->L_gen
.g_nam_p
);
4407 if (stat(Gen
.g_nam_p
, &SrcSt
) == 0) { /* check if file exists */
4410 Gen
.g_nlink
= l_p
->L_cnt
; /* "actual" link count */
4411 tfsize
= Gen
.g_filesz
;
4412 Gen
.g_filesz
= (off_t
)0;
4414 while (tl_p
!= NULL
) {
4415 Gen
.g_nam_p
= tl_p
->L_gen
.g_nam_p
;
4416 Gen
.g_namesz
= tl_p
->L_gen
.g_namesz
;
4417 if (tl_p
->L_lnk_p
== NULL
) {
4418 Gen
.g_filesz
= tfsize
;
4419 if (open_dirfd() != 0) {
4425 write_hdr(ARCHIVE_NORMAL
,
4426 (off_t
)0); /* header only */
4427 VERBOSE((Args
& (OCv
| OCV
)), Gen
.g_nam_p
);
4428 tl_p
= tl_p
->L_lnk_p
;
4430 Gen
.g_nam_p
= Nam_p
;
4431 } else /* stat(Gen.g_nam_p, &SrcSt) == 0 */
4432 msg(ERR
, "\"%s%s%s\" has disappeared",
4433 (Gen
.g_attrnam_p
== NULL
) ?
4434 Gen
.g_nam_p
: Gen
.g_attrfnam_p
,
4435 (Gen
.g_attrnam_p
== NULL
) ?
4436 "" : Gen
.g_rw_sysattr
?
4437 gettext(" System Attribute ") :
4438 gettext(" Attribute "),
4439 (Gen
.g_attrnam_p
== NULL
) ?
4440 "" : Gen
.g_attrnam_p
);
4444 } /* l_p != &Lnk_hd */
4447 #if defined(O_XATTR)
4449 is_sysattr(char *name
)
4451 return ((strcmp(name
, VIEW_READONLY
) == 0) ||
4452 (strcmp(name
, VIEW_READWRITE
) == 0));
4457 * gethdr: Get a header from the archive, validate it and check for the trailer.
4458 * Any user specified Hdr_type is ignored (set to NONE in main). Hdr_type is
4459 * set appropriately after a valid header is found. Unless the -k option is
4460 * set a corrupted header causes an exit with an error. I/O errors during
4461 * examination of any part of the header cause gethdr to throw away any current
4462 * data and start over. Other errors during examination of any part of the
4463 * header cause gethdr to advance one byte and continue the examination.
4470 int hit
= NONE
, cnt
= 0;
4471 int goodhdr
, hsize
, offset
;
4479 Gen
.g_nam_p
= Nam_p
;
4480 do { /* hit == NONE && (Args & OCk) && Buffr.b_cnt > 0 */
4485 Binmag
.b_byte
[0] = Buffr
.b_out_p
[0];
4486 Binmag
.b_byte
[1] = Buffr
.b_out_p
[1];
4487 if ((Binmag
.b_half
== CMN_BIN
) ||
4488 (Binmag
.b_half
== CMN_BBS
)) {
4489 hit
= read_hdr(BIN
);
4490 if (Hdr_type
== NONE
)
4492 hsize
= HDRSZ
+ Gen
.g_namesz
;
4495 if (Hdr_type
!= NONE
)
4499 if (!(strncmp(Buffr
.b_out_p
, CMS_CHR
, CMS_LEN
))) {
4500 hit
= read_hdr(CHR
);
4501 hsize
= CHRSZ
+ Gen
.g_namesz
;
4504 if (Hdr_type
!= NONE
)
4508 if (!(strncmp(Buffr
.b_out_p
, CMS_ASC
, CMS_LEN
))) {
4509 hit
= read_hdr(ASC
);
4510 hsize
= ASCSZ
+ Gen
.g_namesz
;
4514 if (Hdr_type
!= NONE
)
4518 if (!(strncmp(Buffr
.b_out_p
, CMS_CRC
, CMS_LEN
))) {
4519 hit
= read_hdr(CRC
);
4520 hsize
= ASCSZ
+ Gen
.g_namesz
;
4524 if (Hdr_type
!= NONE
)
4529 if (Hdr_p
!= NULL
&& strcmp(Hdr_p
, "bar") == 0) {
4532 if ((hit
= read_hdr(BAR
)) == NONE
) {
4543 if (Hdr_p
!= NULL
&& strcmp(Hdr_p
, "ustar") == 0) {
4546 if ((hit
= read_hdr(USTAR
)) == NONE
) {
4556 if (Hdr_p
!= NULL
&& strcmp(Hdr_p
, "tar") == 0) {
4559 if ((hit
= read_hdr(TAR
)) == NONE
) {
4569 msg(EXT
, "Impossible header type.");
4572 if (hit
== TAR
|| hit
== USTAR
) {
4573 Gen
.g_nam_p
= &nambuf
[0];
4579 if (Gen
.g_filesz
< (off_t
)0 || Gen
.g_namesz
< 1)
4581 if ((hit
!= USTAR
) && (hit
!= TAR
))
4582 if (Gen
.g_namesz
- 1 > Max_namesz
)
4585 if ((hit
== USTAR
) || (hit
== TAR
)) {
4586 if (*Gen
.g_nam_p
== '\0') { /* tar trailer */
4592 cksum(TARTYP
, 0, NULL
)) {
4595 "Bad header - checksum "
4599 } else if (hit
!= BAR
) { /* binary, -c, ASC and CRC */
4600 if (Gen
.g_nlink
<= (ulong_t
)0)
4602 if (*(Buffr
.b_out_p
+ hsize
- 1) != '\0')
4610 "Corrupt header, file(s) may be lost.");
4621 msg(ERR
, "Searching for magic number/header.");
4623 } while (hit
== NONE
);
4625 if (Hdr_type
== NONE
)
4626 msg(EXT
, "Not a cpio file, bad header.");
4628 msg(EXT
, "Bad magic number/header.");
4629 } else if (cnt
> 0) {
4630 msg(EPOST
, "Re-synchronized on magic number/header.");
4632 if (Hdr_type
== NONE
) {
4658 Max_namesz
= HNAMLEN
- 1;
4665 Max_namesz
= TNAMLEN
- 1;
4670 msg(EXT
, "Impossible header type.");
4672 } /* Hdr_type == NONE */
4673 if ((Hdr_type
== USTAR
) || (Hdr_type
== TAR
) ||
4674 (Hdr_type
== BAR
)) { /* TAR, USTAR, BAR */
4676 if (Gen
.g_nam_p
[0] == '\0')
4679 preptr
= &prebuf
[0];
4680 if (*preptr
!= '\0') {
4681 k
= strlen(&prebuf
[0]);
4683 (void) strcpy(&fullnam
[0], &prebuf
[0]);
4686 while ((j
< NAMSIZ
) && (nambuf
[j
] !=
4688 fullnam
[k
] = nambuf
[j
];
4692 } else if (k
>= PRESIZ
) {
4694 while ((k
< PRESIZ
) && (prebuf
[k
] !=
4696 fullnam
[k
] = prebuf
[k
];
4701 while ((j
< NAMSIZ
) && (nambuf
[j
] !=
4703 fullnam
[k
] = nambuf
[j
];
4708 Gen
.g_nam_p
= &fullnam
[0];
4710 Gen
.g_nam_p
= &nambuf
[0];
4713 * initialize the buffer so that the prefix will not
4714 * applied to the next entry in the archive
4716 (void) memset(prebuf
, 0, sizeof (prebuf
));
4718 } else if (Hdr_type
!= BAR
) {
4719 (void) memcpy(Gen
.g_nam_p
, Buffr
.b_out_p
+ Hdrsz
, Gen
.g_namesz
);
4720 if (!(strcmp(Gen
.g_nam_p
, "TRAILER!!!")))
4723 offset
= ((hsize
+ Pad_val
) & ~Pad_val
);
4724 FILL(offset
+ Hdrsz
);
4725 Thdr_p
= (union tblock
*)Buffr
.b_out_p
;
4726 Buffr
.b_out_p
+= offset
;
4727 Buffr
.b_cnt
-= (off_t
)offset
;
4728 ftype
= Gen
.g_mode
& Ftype
;
4730 #if defined(O_XATTR)
4731 /* extended attribute support */
4732 if (((Gen
.g_mode
& S_IFMT
) == _XATTR_CPIO_MODE
) ||
4733 ((Hdr_type
== USTAR
|| Hdr_type
== TAR
) &&
4734 Thdr_p
->tbuf
.t_typeflag
== _XATTR_HDRTYPE
)) {
4736 char *attrparent
= NULL
;
4737 char *attrpath
= NULL
;
4741 if (xattrp
!= NULL
) {
4751 * At this point, the attribute path contains
4752 * the path to the attribute rooted at the hidden
4753 * attribute directory of the base file. This can
4754 * be a simple attribute or extended attribute name,
4755 * or it can be something like <attr>/<sys attr> if
4756 * we are processing a system attribute of an attribute.
4757 * Determine the attribute name and attribute parent
4758 * (if there is one). When we are processing a simple
4759 * attribute or extended attribute name, the attribute
4760 * parent will be set to NULL. When we are processing
4761 * something like <attr>/<sys attr>, the attribute
4762 * parent will be contain <attr>, and the attribute
4763 * name will contain <sys attr>.
4765 tapath
= xattrp
->h_names
+
4766 strlen(xattrp
->h_names
) + 1;
4767 attrpath
= e_strdup(E_EXIT
, tapath
);
4768 if ((taname
= strpbrk(tapath
, "/")) != NULL
) {
4771 attrparent
= tapath
;
4776 Gen
.g_rw_sysattr
= is_sysattr(aname
);
4777 Gen
.g_baseparent_fd
= attr_baseparent_fd
;
4779 if (Gen
.g_attrfnam_p
!= NULL
) {
4780 free(Gen
.g_attrfnam_p
);
4781 Gen
.g_attrfnam_p
= NULL
;
4783 if (Gen
.g_attrnam_p
!= NULL
) {
4784 free(Gen
.g_attrnam_p
);
4785 Gen
.g_attrnam_p
= NULL
;
4787 if (Gen
.g_attrparent_p
!= NULL
) {
4788 free(Gen
.g_attrparent_p
);
4789 Gen
.g_attrparent_p
= NULL
;
4791 if (Gen
.g_attrpath_p
!= NULL
) {
4792 free(Gen
.g_attrpath_p
);
4793 Gen
.g_attrpath_p
= NULL
;
4795 if (Renam_p
&& Renam_p
[0] != '\0') {
4796 Gen
.g_attrfnam_p
= e_strdup(E_EXIT
, Renam_p
);
4798 Gen
.g_attrfnam_p
= e_strdup(E_EXIT
,
4801 Gen
.g_attrnam_p
= e_strdup(E_EXIT
, aname
);
4803 if (attrparent
!= NULL
) {
4804 if (Renam_attr_p
&& Renam_attr_p
[0] != '\0') {
4805 size_t apathlen
= strlen(attrparent
) +
4807 Gen
.g_attrparent_p
= e_strdup(E_EXIT
,
4809 Gen
.g_attrpath_p
= e_zalloc(E_EXIT
,
4811 (void) snprintf(Gen
.g_attrpath_p
,
4812 apathlen
, "%s/%s", Renam_attr_p
,
4814 (void) free(attrparent
);
4815 (void) free(attrpath
);
4817 Gen
.g_attrparent_p
= attrparent
;
4818 Gen
.g_attrpath_p
= attrpath
;
4821 Gen
.g_attrpath_p
= attrpath
;
4824 if (xattr_linkp
!= NULL
) {
4825 if (Gen
.g_linktoattrfnam_p
!= NULL
) {
4826 free(Gen
.g_linktoattrfnam_p
);
4827 Gen
.g_linktoattrfnam_p
= NULL
;
4829 if (Gen
.g_linktoattrnam_p
!= NULL
) {
4830 free(Gen
.g_linktoattrnam_p
);
4831 Gen
.g_linktoattrnam_p
= NULL
;
4833 if (Renam_attr_p
&& Renam_attr_p
[0] != '\0') {
4834 Gen
.g_linktoattrfnam_p
= e_strdup(
4835 E_EXIT
, Renam_attr_p
);
4837 Gen
.g_linktoattrfnam_p
= e_strdup(
4838 E_EXIT
, xattr_linkp
->h_names
);
4840 Gen
.g_linktoattrnam_p
= e_strdup(E_EXIT
,
4844 if (Hdr_type
!= USTAR
&& Hdr_type
!= TAR
) {
4845 Gen
.g_mode
= Gen
.g_mode
& (~_XATTR_CPIO_MODE
);
4846 Gen
.g_mode
|= attrmode(xattrp
->h_typeflag
);
4847 } else if (Hdr_type
== USTAR
|| Hdr_type
== TAR
) {
4848 Thdr_p
->tbuf
.t_typeflag
= xattrp
->h_typeflag
;
4851 ftype
= Gen
.g_mode
& Ftype
;
4852 Adir
= ftype
== S_IFDIR
;
4853 Aspec
= (ftype
== S_IFBLK
|| ftype
== S_IFCHR
||
4854 ftype
== S_IFIFO
|| ftype
== S_IFSOCK
);
4856 if (Gen
.g_attrnam_p
[0] == '.' &&
4857 Gen
.g_attrnam_p
[1] == '\0' &&
4858 xattrp
->h_typeflag
== DIRTYPE
) {
4868 if (xattrbadhead
== 0) {
4869 (void) read_xattr_hdr();
4876 #endif /* O_XATTR */
4878 /* acl support: grab acl info */
4879 if ((Gen
.g_mode
== SECMODE
) || ((Hdr_type
== USTAR
||
4880 Hdr_type
== TAR
) && Thdr_p
->tbuf
.t_typeflag
== 'A')) {
4881 /* this is an ancillary file */
4890 bytes
= Gen
.g_filesz
;
4891 secp
= e_zalloc(E_EXIT
, (uint_t
)bytes
);
4895 cnt
= (int)(bytes
> CPIOBSZ
) ? CPIOBSZ
: bytes
;
4897 (void) memcpy(tp
, Buffr
.b_out_p
, cnt
);
4899 Buffr
.b_out_p
+= cnt
;
4900 Buffr
.b_cnt
-= (off_t
)cnt
;
4901 bytes
-= (off_t
)cnt
;
4904 pad
= (Pad_val
+ 1 - (Gen
.g_filesz
& Pad_val
)) &
4908 Buffr
.b_out_p
+= pad
;
4909 Buffr
.b_cnt
-= (off_t
)pad
;
4912 /* got all attributes in secp */
4915 attr
= (struct sec_attr
*)tp
;
4916 switch (attr
->attr_type
) {
4919 (void) sscanf(attr
->attr_len
, "%7lo",
4920 (ulong_t
*)&aclcnt
);
4923 strlen(&attr
->attr_info
[0])
4927 acl_fromtext(&attr
->attr_info
[0],
4932 "aclfromtext failed: %s",
4933 acl_strerror(error
));
4938 if (aclcnt
!= acl_cnt(aclp
)) {
4939 msg(ERR
, "acl count error");
4946 /* SunFed case goes here */
4949 msg(EXT
, "unrecognized attr type");
4952 /* next attributes */
4954 } while (bytes
> 0);
4957 /* skip security info */
4962 * We already got the file content, dont call file_in()
4963 * when return. The new return code(2) is used to
4966 VERBOSE((Args
& OCt
), Gen
.g_nam_p
);
4971 * Sparse file support
4972 * Read header of holesdata to get original file size.
4973 * This is necessary because ckname() or file_in() shows file size
4974 * with OCt before data_in() extracts the holesdata. data_in()
4975 * actually doesn't extract the holesdata since proc_mode will be
4976 * P_SKIP in the OCt mode.
4978 if ((Hdr_type
== CHR
|| Hdr_type
== ASC
) &&
4979 S_ISSPARSE(Gen
.g_mode
) && Gen
.g_filesz
> MIN_HOLES_HDRSIZE
) {
4980 char holesdata
[MIN_HOLES_HDRSIZE
+ 1];
4982 FILL(MIN_HOLES_HDRSIZE
);
4983 (void) memcpy(holesdata
, Buffr
.b_out_p
, MIN_HOLES_HDRSIZE
);
4984 holesdata
[MIN_HOLES_HDRSIZE
] = '\0';
4986 Gen
.g_holes
= read_holes_header(holesdata
, Gen
.g_filesz
);
4987 if (Gen
.g_holes
== NULL
) {
4988 msg(EXT
, "invalid sparse file information");
4990 Buffr
.b_out_p
+= MIN_HOLES_HDRSIZE
;
4991 Buffr
.b_cnt
-= MIN_HOLES_HDRSIZE
;
4995 Adir
= (ftype
== S_IFDIR
);
4996 Aspec
= (ftype
== S_IFBLK
|| ftype
== S_IFCHR
|| ftype
== S_IFIFO
||
5000 * Skip any trailing slashes
5002 chop_endslashes(Gen
.g_nam_p
);
5007 * getname: Get file names for inclusion in the archive. When end of file
5008 * on the input stream of file names is reached, flush the link buffer out.
5009 * For each filename, remove leading "./"s and multiple "/"s, and remove
5010 * any trailing newline "\n". Finally, verify the existence of the file,
5011 * and call creat_hdr() to fill in the gen_hdr structure.
5017 int goodfile
= 0, lastchar
, err
;
5021 Gen
.g_nam_p
= Nam_p
;
5027 while ((s
= fgets(Gen
.g_nam_p
, APATH
+1, In_p
)) != NULL
) {
5028 lastchar
= strlen(s
) - 1;
5031 if (s
[lastchar
] != '\n') {
5032 if (lastchar
== APATH
- 1) {
5035 "%s name too long.",
5050 if (Gen
.g_dirfd
!= -1) {
5051 (void) close(Gen
.g_dirfd
);
5054 if (Onecopy
&& (Args
& OCo
)) {
5060 while (*Gen
.g_nam_p
== '.' && Gen
.g_nam_p
[1] == '/') {
5062 while (*Gen
.g_nam_p
== '/')
5067 * Skip any trailing slashes
5069 chop_endslashes(Gen
.g_nam_p
);
5072 * Figure out parent directory
5075 if (Gen
.g_attrnam_p
!= NULL
) {
5076 if (Gen
.g_dirfd
!= -1) {
5077 (void) close(Gen
.g_dirfd
);
5079 Gen
.g_dirfd
= attropen(Gen
.g_attrfnam_p
, ".", O_RDONLY
);
5080 if (Gen
.g_dirfd
== -1) {
5082 "Cannot open attribute directory"
5083 " of file %s", Gen
.g_attrfnam_p
);
5088 char dirpath
[PATH_MAX
];
5090 get_parent(Gen
.g_nam_p
, dirpath
);
5091 if (Atflag
|| SysAtflag
) {
5093 if (Gen
.g_dirfd
!= -1) {
5094 (void) close(Gen
.g_dirfd
);
5096 Gen
.g_dirfd
= open(dir
, O_RDONLY
);
5097 if (Gen
.g_dirfd
== -1) {
5099 "Cannot open directory %s", dir
);
5104 * g_dirpath is the pathname cache maintaining
5105 * the dirname which is currently opened.
5106 * We first check the g_dirpath to see if the
5107 * given dirname matches. If so, we don't need
5108 * to open the dir, but we can use the g_dirfd
5109 * as is if it is still available.
5112 if (Gen
.g_dirpath
== NULL
||
5113 Gen
.g_dirfd
== -1) {
5115 * It's the first time or it has
5118 dir
= e_strdup(E_EXIT
, dirpath
);
5120 if (strcmp(Gen
.g_dirpath
,
5122 /* different directory */
5123 dir
= e_strdup(E_EXIT
, dirpath
);
5128 * We need to open the new directory.
5129 * discard the pathname and dirfd
5130 * for the previous directory.
5132 if (Gen
.g_dirpath
!= NULL
) {
5133 free(Gen
.g_dirpath
);
5134 Gen
.g_dirpath
= NULL
;
5136 if (Gen
.g_dirfd
!= -1) {
5137 (void) close(Gen
.g_dirfd
);
5139 /* open the new dir */
5140 Gen
.g_dirfd
= open(dir
, O_RDONLY
);
5141 if (Gen
.g_dirfd
== -1) {
5142 msg(ERRN
, "Cannot open "
5143 "directory %s", dir
);
5146 Gen
.g_dirpath
= dir
;
5154 /* creat_hdr checks for USTAR filename length */
5156 if (Hdr_type
!= USTAR
&& strlen(Gen
.g_nam_p
) >
5159 msg(ERR
, "%s%s%s name too long.",
5160 (Gen
.g_attrnam_p
== NULL
) ?
5161 Nam_p
: Gen
.g_attrfnam_p
,
5162 (Gen
.g_attrnam_p
== NULL
) ?
5163 "" : Gen
.g_rw_sysattr
?
5164 gettext(" System Attribute ") :
5165 gettext(" Attribute "),
5166 (Gen
.g_attrnam_p
== NULL
) ?
5167 "" : Gen
.g_attrnam_p
);
5177 if (!LSTAT(Gen
.g_dirfd
, Gen
.g_nam_p
, &SrcSt
)) {
5180 if ((SrcSt
.st_mode
& Ftype
) == S_IFLNK
) {
5185 if (STAT(Gen
.g_dirfd
,
5212 OldSt
= convert_to_old_stat(&SrcSt
,
5213 Gen
.g_nam_p
, Gen
.g_attrnam_p
);
5215 if (OldSt
== NULL
) {
5221 "Error with fstatat() of \"%s%s%s\"",
5222 (Gen
.g_attrnam_p
== NULL
) ?
5223 Gen
.g_nam_p
: Gen
.g_attrfnam_p
,
5224 (Gen
.g_attrnam_p
== NULL
) ? "" :
5226 gettext(" System Attribute ") :
5227 gettext(" Attribute "),
5228 (Gen
.g_attrnam_p
== NULL
) ?
5229 "" : Gen
.g_attrnam_p
);
5235 * Get ACL info: dont bother allocating space if there are only
5236 * standard permissions, i.e. ACL count < 4
5238 if ((SrcSt
.st_mode
& Ftype
) != S_IFLNK
&& Pflag
) {
5239 if (acl_get(Gen
.g_nam_p
, ACL_NO_TRIVIAL
, &aclp
) != 0)
5240 msg(ERRN
, "Error with acl() of \"%s\"", Gen
.g_nam_p
);
5242 /* else: only traditional permissions, so proceed as usual */
5249 * getpats: Save any filenames/patterns specified as arguments.
5250 * Read additional filenames/patterns from the file specified by the
5251 * user. The filenames/patterns must occur one per line.
5255 getpats(int largc
, char **largv
)
5259 unsigned numpat
= largc
, maxpat
= largc
+ 2;
5261 Pat_pp
= e_zalloc(E_EXIT
, maxpat
* sizeof (char *));
5264 *t_pp
= e_zalloc(E_EXIT
, strlen(*largv
) + 1);
5265 (void) strcpy(*t_pp
, *largv
);
5269 while (fgets(Nam_p
, Max_namesz
+ 1, Ef_p
) != NULL
) {
5270 if (numpat
== maxpat
- 1) {
5272 Pat_pp
= e_realloc(E_EXIT
, Pat_pp
,
5273 maxpat
* sizeof (char *));
5274 t_pp
= Pat_pp
+ numpat
;
5276 len
= strlen(Nam_p
); /* includes the \n */
5277 *(Nam_p
+ len
- 1) = '\0'; /* remove the \n */
5278 *t_pp
= e_zalloc(E_EXIT
, len
);
5279 (void) strcpy(*t_pp
, Nam_p
);
5293 if (fstat(Archive
, &ArchSt
) < 0)
5294 msg(EXTN
, "Error during stat() of archive");
5296 if ((ArchSt
.st_mode
& Ftype
) != S_IFCHR
) {
5299 msg(EXT
, "ulimit reached for output file.");
5300 else if (errno
== ENOSPC
)
5301 msg(EXT
, "No space left for output file.");
5303 msg(EXTN
, "I/O error - cannot continue");
5305 msg(EXT
, "Unexpected end-of-file encountered.");
5307 msg(EXTN
, "\007I/O error on \"%s\"", dir
? "output" : "input");
5311 * matched: Determine if a filename matches the specified pattern(s). If the
5312 * pattern is matched (the second return), return 0 if -f was specified, else
5313 * return != 0. If the pattern is not matched (the first and third
5314 * returns), return 0 if -f was not specified, else return != 0.
5320 char *str_p
= G_p
->g_nam_p
;
5321 char **pat_pp
= Pat_pp
;
5322 int negatep
, result
;
5325 * Check for attribute
5327 if (G_p
->g_attrfnam_p
!= NULL
)
5328 str_p
= G_p
->g_attrfnam_p
;
5330 for (pat_pp
= Pat_pp
; *pat_pp
; pat_pp
++) {
5331 negatep
= (**pat_pp
== '!');
5333 result
= fnmatch(negatep
? (*pat_pp
+1) : *pat_pp
, str_p
, 0);
5335 if (result
!= 0 && result
!= FNM_NOMATCH
) {
5336 msg(POST
, "error matching file %s with pattern"
5337 " %s\n", str_p
, *pat_pp
);
5338 return (Args
& OCf
);
5341 if ((result
== 0 && ! negatep
) ||
5342 (result
== FNM_NOMATCH
&& negatep
)) {
5343 /* match occurred */
5344 return (!(Args
& OCf
));
5347 return (Args
& OCf
); /* not matched */
5351 * missdir: Create missing directories for files.
5352 * (Possible future performance enhancement, if missdir is called, we know
5353 * that at least the very last directory of the path does not exist, therefore,
5354 * scan the path from the end
5358 missdir(char *nam_p
)
5364 if (*(c_p
= nam_p
) == '/') /* skip over 'root slash' */
5367 lastp
= c_p
+ strlen(nam_p
) - 1;
5371 for (; *c_p
; ++c_p
) {
5374 if (stat(nam_p
, &DesSt
) < 0) {
5376 cnt
= mkdir(nam_p
, Def_mode
);
5382 msg(ERR
, "Missing -d option.");
5390 if (cnt
== 2) /* the file already exists */
5396 * mklong: Convert two shorts into one long. For VAX, Interdata ...
5406 if (swp_b
.s_byte
[0]) {
5407 swp_b
.s_half
[0] = v
[1];
5408 swp_b
.s_half
[1] = v
[0];
5410 swp_b
.s_half
[0] = v
[0];
5411 swp_b
.s_half
[1] = v
[1];
5413 return (swp_b
.s_word
);
5417 * mkshort: Convert a long into 2 shorts, for VAX, Interdata ...
5421 mkshort(short sval
[], long v
)
5423 union swpbuf
*swp_p
, swp_b
;
5425 /* LINTED alignment */
5426 swp_p
= (union swpbuf
*)sval
;
5428 if (swp_b
.s_byte
[0]) {
5430 swp_p
->s_half
[0] = swp_b
.s_half
[1];
5431 swp_p
->s_half
[1] = swp_b
.s_half
[0];
5434 swp_p
->s_half
[0] = swp_b
.s_half
[0];
5435 swp_p
->s_half
[1] = swp_b
.s_half
[1];
5440 * msg: Print either a message (no error) (POST), an error message with or
5441 * without the errno (ERRN or ERR), or print an error message with or without
5442 * the errno and exit (EXTN or EXT).
5445 msg(int severity
, const char *fmt
, ...)
5450 if ((Args
& OCV
) && Verbcnt
) { /* clear current line of dots */
5451 (void) fputc('\n', Out_p
);
5455 if (severity
== POST
)
5458 if (severity
== EPOST
)
5464 (void) fflush(Out_p
);
5465 (void) fflush(Err_p
);
5466 if ((severity
!= POST
) && (severity
!= EPOST
))
5467 (void) fprintf(file_p
, "cpio: ");
5469 /* gettext replaces version of string */
5471 (void) vfprintf(file_p
, gettext(fmt
), ap
);
5472 if (severity
== ERRN
|| severity
== EXTN
) {
5473 if (G_p
&& (G_p
->g_attrnam_p
!= NULL
) && G_p
->g_rw_sysattr
) {
5474 if (errno
== EPERM
) {
5475 (void) fprintf(file_p
, ", errno %d, %s", errno
,
5476 gettext("insufficient privileges\n"));
5477 } else if (errno
== EINVAL
) {
5478 (void) fprintf(file_p
, ", errno %d, %s",
5480 "unsupported on underlying file system\n"));
5482 (void) fprintf(file_p
, ", errno %d, ", errno
);
5486 (void) fprintf(file_p
, ", errno %d, ", errno
);
5490 (void) fprintf(file_p
, "\n");
5491 (void) fflush(file_p
);
5493 if (severity
== EXT
|| severity
== EXTN
) {
5494 (void) fprintf(file_p
, gettext("%d errors\n"), Error_cnt
);
5500 * openout: Open files for output and set all necessary information.
5501 * If the u option is set (unconditionally overwrite existing files),
5502 * and the current file exists, get a temporary file name from mktemp(3C),
5503 * link the temporary file to the existing file, and remove the existing file.
5504 * Finally either creat(2), mkdir(2) or mknod(2) as appropriate.
5514 Do_rename
= 0; /* creat_tmp() may reset this */
5516 if (G_p
->g_attrnam_p
!= NULL
) {
5517 nam_p
= G_p
->g_attrnam_p
;
5522 nam_p
= G_p
->g_nam_p
;
5527 if ((Max_filesz
!= RLIM_INFINITY
) &&
5528 (Max_filesz
< (G_p
->g_filesz
>> 9))) {
5529 /* ... divided by 512 ... */
5530 msg(ERR
, "Skipping \"%s%s%s\": exceeds ulimit by %lld bytes",
5531 (G_p
->g_attrnam_p
== NULL
) ? nam_p
: G_p
->g_attrfnam_p
,
5532 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_rw_sysattr
?
5533 gettext(" System Attribute ") : gettext(" Attribute "),
5534 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
,
5535 (off_t
)(G_p
->g_filesz
- (Max_filesz
<< 9)));
5539 if (LSTAT(dirfd
, nam_p
, &DesSt
) == 0) {
5541 * A file by the same name exists. Move it to a temporary
5542 * file unless it's a system attribute file. If we are
5543 * restoring a system attribute file on a file system that
5544 * supports system attributes, then the system attribute file
5545 * will already exist (a default system attribute file will
5546 * get created when the file it is associated with is created).
5547 * If we create a temporary system attribute file, we can't
5548 * overwrite the existing system attribute file using
5549 * renameat(). In addition, only system attributes can exist
5550 * for an attribute of a file, therefore, a temporary file
5551 * cannot be created for a system attribute of an attribute.
5552 * Thus, when restoring a system attribute, we won't move it
5553 * to a temporary file, but will attempt to process it as if
5554 * it didn't already exist.
5557 #if defined(_PC_SATTR_ENABLED)
5558 if (G_p
->g_rw_sysattr
== 0)
5559 #endif /* _PC_SATTR_ENABLED */
5560 if (creat_tmp(nam_p
) < 0) {
5562 * We weren't able to create the temp file.
5571 /* nam_p was changed by creat_tmp() above. */
5574 if (G_p
->g_attrnam_p
!= NULL
) {
5580 nam_p
= G_p
->g_nam_p
;
5585 * This pile tries to create the file directly, and, if there is a
5586 * problem, creates missing directories, and then tries to create the
5587 * file again. Two strikes and you're out.
5589 * On XATTR system, the directory has already been created by
5590 * open_dirfd(), so error shouldn't happen in the loop. However,
5591 * on non-XATTR system, symlink/open may fail with ENOENT. In such
5592 * case, we go to create missing directories.
5600 if (Hdr_type
== TAR
&& Thdr_p
->tbuf
.t_typeflag
== SYMTYPE
) {
5601 /* The archive file is a TAR symlink. */
5603 symlink(Thdr_p
->tbuf
.t_linkname
, nam_p
)) >= 0) {
5605 if (Over_p
!= NULL
) {
5606 (void) unlinkat(dirfd
,
5607 get_component(Over_p
), 0);
5611 } else if (errno
!= ENOENT
) {
5612 /* The attempt to symlink failed. */
5614 "Cannot create symbolic link \"%s\" -> "
5616 Thdr_p
->tbuf
.t_linkname
, nam_p
);
5618 if (*Over_p
!= '\0') {
5619 rstfiles(U_KEEP
, dirfd
);
5623 } else if (Hdr_type
== BAR
&& bar_linkflag
== SYMTYPE
) {
5624 if ((result
= symlink(bar_linkname
, nam_p
)) >= 0) {
5626 if (Over_p
!= NULL
) {
5627 (void) unlinkat(dirfd
,
5628 get_component(Over_p
), 0);
5632 } else if (errno
!= ENOENT
) {
5633 /* The attempt to symlink failed. */
5635 "Cannot create symbolic link \"%s\" -> "
5637 bar_linkname
, nam_p
);
5638 if (*Over_p
!= '\0') {
5639 rstfiles(U_KEEP
, dirfd
);
5643 } else if ((G_p
->g_mode
& Ftype
) == S_IFLNK
) {
5644 if ((!(Args
& OCp
)) && !(Hdr_type
== USTAR
)) {
5645 FILL(G_p
->g_filesz
);
5646 (void) strncpy(Symlnk_p
,
5647 Buffr
.b_out_p
, G_p
->g_filesz
);
5648 *(Symlnk_p
+ G_p
->g_filesz
) = '\0';
5649 } else if ((!(Args
& OCp
)) && (Hdr_type
== USTAR
)) {
5650 Symlnk_p
[NAMSIZ
] = '\0';
5651 (void) strncpy(Symlnk_p
,
5652 &Thdr_p
->tbuf
.t_linkname
[0], NAMSIZ
);
5654 if ((result
= symlink(Symlnk_p
, nam_p
)) >= 0) {
5656 if (Over_p
!= NULL
) {
5657 (void) unlinkat(dirfd
,
5658 get_component(Over_p
), 0);
5662 } else if (errno
!= ENOENT
) {
5663 /* The attempt to symlink failed. */
5665 "Cannot create symbolic link \"%s\" -> "
5669 if (*Over_p
!= '\0') {
5670 rstfiles(U_KEEP
, dirfd
);
5677 if ((result
= openat(dirfd
, get_component(nam_p
),
5678 O_CREAT
|O_RDWR
|O_TRUNC
, (int)G_p
->g_mode
)) < 0) {
5680 if (G_p
->g_attrnam_p
!= NULL
) {
5681 result
= retry_open_attr(dirfd
,
5682 Gen
.g_baseparent_fd
, Fullnam_p
,
5683 (G_p
->g_attrparent_p
== NULL
) ?
5684 NULL
: G_p
->g_attrparent_p
, nam_p
,
5685 O_CREAT
|O_RDWR
|O_TRUNC
,
5691 if (errno
!= ENOENT
) {
5692 /* The attempt to open failed. */
5693 msg(ERRN
, "Cannot open file \"%s\"",
5695 if (*Over_p
!= '\0') {
5696 rstfiles(U_KEEP
, dirfd
);
5703 if (Pflag
&& aclp
!= NULL
) {
5704 if (facl_set(result
, aclp
) < 0) {
5706 "\"%s\": failed to set acl",
5719 } while (cnt
< 2 && missdir(nam_p
) == 0);
5723 if ((Args
& OCi
) && (Hdr_type
== USTAR
)) {
5726 if ((G_p
->g_mode
& Ftype
) == S_IFLNK
||
5727 (Hdr_type
== BAR
&& bar_linkflag
== SYMTYPE
)) {
5730 get_component(nam_p
),
5733 AT_SYMLINK_NOFOLLOW
) < 0) {
5735 "Error during chown() of "
5737 (G_p
->g_attrnam_p
== NULL
) ?
5738 nam_p
: G_p
->g_attrfnam_p
,
5739 (G_p
->g_attrnam_p
== NULL
) ?
5740 "" : G_p
->g_rw_sysattr
?
5741 gettext(" System Attribute ") :
5742 gettext(" Attribute "),
5743 (G_p
->g_attrnam_p
== NULL
) ?
5746 } else if ((fchownat(dirfd
, get_component(nam_p
),
5747 (int)G_p
->g_uid
, (int)G_p
->g_gid
,
5748 AT_SYMLINK_NOFOLLOW
) < 0) && privileged
) {
5750 "Error during chown() of \"%s%s%s\"",
5751 (G_p
->g_attrnam_p
== NULL
) ?
5752 nam_p
: G_p
->g_attrfnam_p
,
5753 (G_p
->g_attrnam_p
== NULL
) ? "" :
5755 gettext(" System Attribute ") :
5756 gettext(" Attribute "),
5757 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
5764 msg(ERRN
, "Cannot create directory for \"%s%s%s\"",
5765 (G_p
->g_attrnam_p
== NULL
) ? Over_p
:
5767 (G_p
->g_attrnam_p
== NULL
) ? "" :
5769 gettext(" System Attribute ") :
5770 gettext(" Attribute "),
5771 (G_p
->g_attrnam_p
== NULL
) ? "" : Over_p
);
5773 msg(ERRN
, "Cannot create directory for \"%s%s%s\"",
5774 (G_p
->g_attrnam_p
== NULL
) ? nam_p
:
5776 (G_p
->g_attrnam_p
== NULL
) ? "" :
5778 gettext(" System Attribute ") :
5779 gettext(" Attribute "),
5780 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
5786 msg(ERRN
, "Cannot create \"%s%s%s\"",
5787 (G_p
->g_attrnam_p
== NULL
) ? Over_p
:
5789 (G_p
->g_attrnam_p
== NULL
) ? "" :
5791 gettext(" System Attribute ") :
5792 gettext(" Attribute "),
5793 (G_p
->g_attrnam_p
== NULL
) ? "" :
5796 msg(ERRN
, "Cannot create \"%s%s%s\"",
5797 (G_p
->g_attrnam_p
== NULL
) ? nam_p
:
5799 (G_p
->g_attrnam_p
== NULL
) ? "" :
5801 gettext(" System Attribute ") :
5802 gettext(" Attribute "),
5803 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
5808 msg(EXT
, "Impossible case.");
5816 * read_hdr: Transfer headers from the selected format
5817 * in the archive I/O buffer to the generic structure.
5828 static int bar_read_cnt
= 0;
5831 if (Buffr
.b_end_p
!= (Buffr
.b_out_p
+ Hdrsz
)) {
5832 tmpnull
= *(Buffr
.b_out_p
+ Hdrsz
);
5833 *(Buffr
.b_out_p
+ Hdrsz
) = '\0';
5839 (void) memcpy(&Hdr
, Buffr
.b_out_p
, HDRSZ
);
5840 if (Hdr
.h_magic
== (short)CMN_BBS
) {
5841 swap((char *)&Hdr
, HDRSZ
);
5843 Gen
.g_magic
= Hdr
.h_magic
;
5844 Gen
.g_mode
= Hdr
.h_mode
;
5845 Gen
.g_uid
= Hdr
.h_uid
;
5846 Gen
.g_gid
= Hdr
.h_gid
;
5847 Gen
.g_nlink
= Hdr
.h_nlink
;
5848 Gen
.g_mtime
= mklong(Hdr
.h_mtime
);
5849 Gen
.g_ino
= Hdr
.h_ino
;
5850 Gen
.g_dev
= Hdr
.h_dev
;
5851 Gen
.g_rdev
= Hdr
.h_rdev
;
5853 Gen
.g_filesz
= (off_t
)mklong(Hdr
.h_filesize
);
5854 Gen
.g_namesz
= Hdr
.h_namesize
;
5858 if (sscanf(Buffr
.b_out_p
,
5859 "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6o%11llo",
5860 &Gen
.g_magic
, &Gen
.g_dev
, &Gen
.g_ino
, &Gen
.g_mode
,
5861 &Gen
.g_uid
, &Gen
.g_gid
, &Gen
.g_nlink
, &Gen
.g_rdev
,
5862 (ulong_t
*)&Gen
.g_mtime
, (uint_t
*)&Gen
.g_namesz
,
5863 (u_off_t
*)&Gen
.g_filesz
) == CHR_CNT
) {
5865 #define cpioMAJOR(x) (int)(((unsigned)x >> 8) & 0x7F)
5866 #define cpioMINOR(x) (int)(x & 0xFF)
5867 maj
= cpioMAJOR(Gen
.g_dev
);
5868 rmaj
= cpioMAJOR(Gen
.g_rdev
);
5869 min
= cpioMINOR(Gen
.g_dev
);
5870 rmin
= cpioMINOR(Gen
.g_rdev
);
5872 /* needs error checking */
5873 Gen
.g_dev
= (maj
<< 8) | min
;
5874 Gen
.g_rdev
= (rmaj
<< 8) | rmin
;
5876 Gen
.g_dev
= makedev(maj
, min
);
5877 Gen
.g_rdev
= makedev(rmaj
, rmin
);
5883 if (sscanf(Buffr
.b_out_p
,
5884 "%6lx%8lx%8lx%8lx%8lx%8lx%8lx%8llx%8x%8x%8x%8x%8x%8lx",
5885 &Gen
.g_magic
, &Gen
.g_ino
, &Gen
.g_mode
, &Gen
.g_uid
,
5886 &Gen
.g_gid
, &Gen
.g_nlink
, &Gen
.g_mtime
,
5887 (u_off_t
*)&Gen
.g_filesz
, (uint_t
*)&maj
, (uint_t
*)&min
,
5888 (uint_t
*)&rmaj
, (uint_t
*)&rmin
, (uint_t
*)&Gen
.g_namesz
,
5889 &Gen
.g_cksum
) == ASC_CNT
) {
5890 Gen
.g_dev
= makedev(maj
, min
);
5891 Gen
.g_rdev
= makedev(rmaj
, rmin
);
5895 case USTAR
: /* TAR and USTAR */
5896 if (*Buffr
.b_out_p
== '\0') {
5897 *Gen
.g_nam_p
= '\0';
5900 Thdr_p
= (union tblock
*)Buffr
.b_out_p
;
5901 Gen
.g_nam_p
[0] = '\0';
5902 (void) strncpy((char *)&nambuf
,
5903 Thdr_p
->tbuf
.t_name
, NAMSIZ
);
5904 (void) sscanf(Thdr_p
->tbuf
.t_mode
, "%8lo",
5906 (void) sscanf(Thdr_p
->tbuf
.t_uid
, "%8lo", &Gen
.g_uid
);
5907 (void) sscanf(Thdr_p
->tbuf
.t_gid
, "%8lo", &Gen
.g_gid
);
5908 (void) sscanf(Thdr_p
->tbuf
.t_size
, "%11llo",
5909 (u_off_t
*)&Gen
.g_filesz
);
5910 (void) sscanf(Thdr_p
->tbuf
.t_mtime
, "%12lo",
5911 (ulong_t
*)&Gen
.g_mtime
);
5912 (void) sscanf(Thdr_p
->tbuf
.t_cksum
, "%8lo",
5913 (ulong_t
*)&Gen
.g_cksum
);
5914 if (Thdr_p
->tbuf
.t_linkname
[0] != '\0')
5919 switch (Thdr_p
->tbuf
.t_typeflag
) {
5925 Gen
.g_mode
|= (S_IFMT
& S_IFCHR
);
5928 Gen
.g_mode
|= (S_IFMT
& S_IFBLK
);
5931 Gen
.g_mode
|= (S_IFMT
& S_IFDIR
);
5934 Gen
.g_mode
|= (S_IFMT
& S_IFIFO
);
5938 (void) sscanf(Thdr_p
->tbuf
.t_magic
, "%8lo",
5939 /* LINTED alignment */
5940 (ulong_t
*)&Gen
.g_tmagic
);
5941 (void) sscanf(Thdr_p
->tbuf
.t_version
, "%8lo",
5942 /* LINTED alignment */
5943 (ulong_t
*)&Gen
.g_version
);
5944 (void) sscanf(Thdr_p
->tbuf
.t_uname
, "%32s",
5945 (char *)&Gen
.g_uname
);
5946 (void) sscanf(Thdr_p
->tbuf
.t_gname
, "%32s",
5947 (char *)&Gen
.g_gname
);
5948 (void) sscanf(Thdr_p
->tbuf
.t_devmajor
, "%8lo",
5950 (void) sscanf(Thdr_p
->tbuf
.t_devminor
, "%8lo",
5952 (void) strncpy((char *)&prebuf
,
5953 Thdr_p
->tbuf
.t_prefix
, PRESIZ
);
5954 Gen
.g_namesz
= strlen(Gen
.g_nam_p
) + 1;
5955 Gen
.g_dev
= makedev(maj
, min
);
5960 if (*Buffr
.b_out_p
== '\0') {
5961 *Gen
.g_nam_p
= '\0';
5964 Thdr_p
= (union tblock
*)Buffr
.b_out_p
;
5965 Gen
.g_nam_p
[0] = '\0';
5966 (void) sscanf(Thdr_p
->tbuf
.t_mode
, "%lo", &Gen
.g_mode
);
5967 (void) sscanf(Thdr_p
->tbuf
.t_uid
, "%lo", &Gen
.g_uid
);
5968 (void) sscanf(Thdr_p
->tbuf
.t_gid
, "%lo", &Gen
.g_gid
);
5969 (void) sscanf(Thdr_p
->tbuf
.t_size
, "%llo",
5970 (u_off_t
*)&Gen
.g_filesz
);
5971 (void) sscanf(Thdr_p
->tbuf
.t_mtime
, "%lo",
5973 (void) sscanf(Thdr_p
->tbuf
.t_cksum
, "%lo",
5975 if (Thdr_p
->tbuf
.t_typeflag
== '1') /* hardlink */
5979 (void) strncpy(Gen
.g_nam_p
,
5980 Thdr_p
->tbuf
.t_name
, NAMSIZ
);
5981 Gen
.g_namesz
= strlen(Gen
.g_nam_p
) + 1;
5982 (void) strcpy(nambuf
, Gen
.g_nam_p
);
5987 if (Bar_vol_num
== 0 && bar_read_cnt
== 0) {
5992 read_bar_file_hdr();
5996 msg(EXT
, "Impossible header type.");
6000 if (Buffr
.b_end_p
!= (Buffr
.b_out_p
+ Hdrsz
))
6001 *(Buffr
.b_out_p
+ Hdrsz
) = tmpnull
;
6008 * reclaim: Reclaim linked file structure storage.
6012 reclaim(struct Lnk
*p
)
6014 p
->L_bck_p
->L_nxt_p
= p
->L_nxt_p
;
6015 p
->L_nxt_p
->L_bck_p
= p
->L_bck_p
;
6018 struct Lnk
*new_p
= p
->L_lnk_p
;
6020 free(p
->L_gen
.g_nam_p
);
6027 * rstbuf: Reset the I/O buffer, move incomplete potential headers to
6028 * the front of the buffer and force bread() to refill the buffer. The
6029 * return value from bread() is returned (to identify I/O errors). On the
6030 * 3B2, reads must begin on a word boundary, therefore, with the -i option,
6031 * any remaining bytes in the buffer must be moved to the base of the buffer
6032 * in such a way that the destination locations of subsequent reads are
6041 if ((Args
& OCi
) || Append
) {
6042 if (Buffr
.b_out_p
!= Buffr
.b_base_p
) {
6043 pad
= ((Buffr
.b_cnt
+ FULLWD
) & ~FULLWD
);
6044 Buffr
.b_in_p
= Buffr
.b_base_p
+ pad
;
6046 (void) memcpy(Buffr
.b_base_p
+ pad
, Buffr
.b_out_p
,
6048 Buffr
.b_out_p
= Buffr
.b_base_p
+ pad
;
6051 msg(EXT
, "Unexpected end-of-archive encountered.");
6053 (void) memcpy(Buffr
.b_base_p
, Buffr
.b_out_p
, (int)Buffr
.b_cnt
);
6054 Buffr
.b_out_p
= Buffr
.b_base_p
;
6055 Buffr
.b_in_p
= Buffr
.b_base_p
+ Buffr
.b_cnt
;
6060 setpasswd(char *nam
)
6062 if ((dpasswd
= getpwnam(&Gen
.g_uname
[0])) == NULL
) {
6063 msg(EPOST
, "cpio: problem reading passwd entry");
6064 msg(EPOST
, "cpio: %s: owner not changed", nam
);
6065 if (Gen
.g_uid
== UID_NOBODY
&& S_ISREG(Gen
.g_mode
))
6066 Gen
.g_mode
&= ~S_ISUID
;
6068 Gen
.g_uid
= dpasswd
->pw_uid
;
6070 if ((dgroup
= getgrnam(&Gen
.g_gname
[0])) == NULL
) {
6071 msg(EPOST
, "cpio: problem reading group entry");
6072 msg(EPOST
, "cpio: %s: group not changed", nam
);
6073 if (Gen
.g_gid
== GID_NOBODY
&& S_ISREG(Gen
.g_mode
))
6074 Gen
.g_mode
&= ~S_ISGID
;
6076 Gen
.g_gid
= dgroup
->gr_gid
;
6081 * rstfiles: Perform final changes to the file. If the -u option is set,
6082 * and overwrite == U_OVER, remove the temporary file, else if overwrite
6083 * == U_KEEP, unlink the current file, and restore the existing version
6084 * of the file. In addition, where appropriate, set the access or modification
6085 * times, change the owner and change the modes of the file.
6087 * Note that if Do_rename is set, then the roles of original and temporary
6088 * file are reversed. If all went well, we will rename() the temporary file
6089 * over the original in order to accommodate potentially executing files.
6092 rstfiles(int over
, int dirfd
)
6094 char *inam_p
, *onam_p
, *nam_p
;
6097 #if defined(_PC_SATTR_ENABLED)
6098 /* Time or permissions cannot be set on system attribute files */
6099 if ((Gen
.g_attrnam_p
!= NULL
) && (Gen
.g_rw_sysattr
== 1)) {
6102 #endif /* _PC_SATTR_ENABLED */
6105 if (G_p
->g_attrnam_p
== NULL
) {
6108 nam_p
= G_p
->g_attrnam_p
;
6111 if (Gen
.g_nlink
> (ulong_t
)0) {
6112 nam_p
= G_p
->g_nam_p
;
6114 nam_p
= Gen
.g_nam_p
;
6117 if (Gen
.g_attrnam_p
!= NULL
) {
6118 nam_p
= Gen
.g_attrnam_p
;
6121 if ((Args
& OCi
) && (Hdr_type
== USTAR
)) {
6124 if (over
== U_KEEP
&& *Over_p
!= '\0') {
6126 msg(POST
, "Restoring existing \"%s%s%s\"",
6127 (G_p
->g_attrnam_p
== NULL
) ? Over_p
: Fullnam_p
,
6128 (G_p
->g_attrnam_p
== NULL
) ? "" :
6129 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
6130 gettext(" Attribute "),
6131 (G_p
->g_attrnam_p
== NULL
) ? "" : Over_p
);
6133 msg(POST
, "Restoring existing \"%s%s%s\"",
6134 (G_p
->g_attrnam_p
== NULL
) ? nam_p
: Fullnam_p
,
6135 (G_p
->g_attrnam_p
== NULL
) ? "" :
6136 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
6137 gettext(" Attribute "),
6138 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
6141 /* delete what we just built */
6142 (void) unlinkat(dirfd
, get_component(nam_p
), 0);
6144 /* If the old file needs restoring, do the necessary links */
6149 tmp_ptr
= Fullnam_p
;
6152 tmp_ptr
= G_p
->g_nam_p
;
6153 G_p
->g_nam_p
= Over_p
;
6157 Do_rename
= 0; /* names now have original values */
6159 if (rename(Over_p
, nam_p
) < 0) {
6160 if (link(Over_p
, nam_p
) < 0) {
6162 "Cannot recover original version"
6164 (G_p
->g_attrnam_p
== NULL
) ?
6166 (G_p
->g_attrnam_p
== NULL
) ? "" :
6168 gettext(" System Attribute ") :
6169 gettext(" Attribute "),
6170 (G_p
->g_attrnam_p
== NULL
) ?
6173 if (unlinkat(dirfd
, get_component(Over_p
), 0)) {
6175 "Cannot remove temp file "
6177 (G_p
->g_attrnam_p
== NULL
) ?
6179 (G_p
->g_attrnam_p
== NULL
) ? "" :
6181 gettext(" System Attribute ") :
6182 gettext(" Attribute "),
6183 (G_p
->g_attrnam_p
== NULL
) ?
6190 } else if (over
== U_OVER
&& *Over_p
!= '\0') {
6194 (void) renameat(dirfd
, get_component(nam_p
),
6195 dirfd
, get_component(Over_p
));
6197 if (G_p
->g_attrnam_p
== NULL
) {
6198 tmp_ptr
= Fullnam_p
;
6203 * Over_p is pointing at g_attrnam_p
6204 * which must be preserved.
6206 * We don't want the tmp_ptr and so
6207 * on to throw away our only copy of
6210 Over_p
= Attrfile_p
;
6213 tmp_ptr
= G_p
->g_nam_p
;
6214 G_p
->g_nam_p
= Over_p
;
6217 Do_rename
= 0; /* names now have original values */
6219 if (unlinkat(dirfd
, get_component(Over_p
), 0) < 0) {
6221 "Cannot unlink() temp file \"%s%s%s\"",
6222 (G_p
->g_attrnam_p
== NULL
) ?
6224 (G_p
->g_attrnam_p
== NULL
) ? "" :
6226 gettext(" System Attribute ") :
6227 gettext(" Attribute "),
6228 (G_p
->g_attrnam_p
== NULL
) ? "" : Over_p
);
6234 if (G_p
->g_attrnam_p
!= NULL
) {
6235 inam_p
= G_p
->g_attrfnam_p
;
6236 onam_p
= G_p
->g_attrnam_p
;
6241 } else /* OCi only uses onam_p, OCo only uses inam_p */
6242 if (G_p
->g_attrnam_p
!= NULL
) {
6243 inam_p
= onam_p
= G_p
->g_attrnam_p
;
6245 inam_p
= onam_p
= G_p
->g_nam_p
;
6249 * Change the owner, time, and mode to those of the file
6250 * originally created in the archive. Note: time and
6251 * mode do not need to be restored for a symbolic link
6252 * since rstfiles() is not called when the archived file
6255 if (!(Args
& OCo
)) {
6257 if (fchownat(dirfd
, get_component(onam_p
),
6258 Rpw_p
->pw_uid
, Rpw_p
->pw_gid
,
6259 AT_SYMLINK_NOFOLLOW
) < 0) {
6260 msg(ERRN
, "Cannot chown() \"%s%s%s\"",
6262 (G_p
->g_attrnam_p
== NULL
) ? "" :
6264 gettext(" System Attribute ") :
6265 gettext(" Attribute "),
6266 (G_p
->g_attrnam_p
== NULL
) ? "" : onam_p
);
6269 if ((fchownat(dirfd
, get_component(onam_p
),
6270 G_p
->g_uid
, G_p
->g_gid
,
6271 AT_SYMLINK_NOFOLLOW
) < 0) && privileged
) {
6272 msg(ERRN
, "Cannot chown() \"%s%s%s\"",
6274 (G_p
->g_attrnam_p
== NULL
) ? "" :
6276 gettext(" System Attribute ") :
6277 gettext(" Attribute "),
6278 (G_p
->g_attrnam_p
== NULL
) ? "" : onam_p
);
6283 set_tym(dirfd
, get_component(onam_p
),
6284 G_p
->g_mtime
, G_p
->g_mtime
);
6287 /* Acl was not set, so we must chmod */
6289 mode_t orig_mask
, new_mask
;
6292 * use fchmod for attributes, since
6293 * we known they are always regular
6294 * files, whereas when it isn't an
6295 * attribute it could be for a fifo
6296 * or something other that we don't
6297 * open and don't have a valid Ofile
6301 new_mask
= G_p
->g_mode
;
6303 orig_mask
= umask(0);
6304 new_mask
= G_p
->g_mode
& ~orig_mask
;
6307 if (G_p
->g_attrnam_p
!= NULL
) {
6308 error
= fchmod(Ofile
, new_mask
);
6310 error
= chmod(onam_p
, new_mask
);
6314 "Cannot chmod() \"%s%s%s\"",
6315 (G_p
->g_attrnam_p
== NULL
) ?
6316 onam_p
: G_p
->g_attrfnam_p
,
6317 (G_p
->g_attrnam_p
== NULL
) ? "" :
6319 gettext(" System Attribute ") :
6320 gettext(" Attribute "),
6321 (G_p
->g_attrnam_p
== NULL
) ? "" : onam_p
);
6324 (void) umask(orig_mask
);
6329 if (!(Args
& OCi
) && (Args
& OCa
)) {
6331 * Use dirfd since we are updating original file
6332 * and not just created file
6334 set_tym(G_p
->g_dirfd
, get_component(inam_p
),
6335 (ulong_t
)SrcSt
.st_atime
, (ulong_t
)SrcSt
.st_mtime
);
6340 * scan4trail: Scan the archive looking for the trailer.
6341 * When found, back the archive up over the trailer and overwrite
6342 * the trailer with the files to be added to the archive.
6359 off2
= Bufsize
- (Buffr
.b_cnt
% Bufsize
);
6360 Buffr
.b_out_p
= Buffr
.b_in_p
= Buffr
.b_base_p
;
6361 Buffr
.b_cnt
= (off_t
)0;
6362 if (lseek(Archive
, -(off1
+ off2
), SEEK_REL
) < 0)
6363 msg(EXTN
, "Unable to append to this archive");
6364 if ((rv
= g_read(Device
, Archive
, Buffr
.b_in_p
, Bufsize
)) < 0)
6365 msg(EXTN
, "Cannot append to this archive");
6366 if (lseek(Archive
, (off_t
)-rv
, SEEK_REL
) < 0)
6367 msg(EXTN
, "Unable to append to this archive");
6369 Buffr
.b_in_p
= Buffr
.b_base_p
+ Buffr
.b_cnt
;
6374 * setup: Perform setup and initialization functions. Parse the options
6375 * using getopt(3C), call ckopts to check the options and initialize various
6376 * structures and pointers. Specifically, for the -i option, save any
6377 * patterns, for the -o option, check (via stat(2)) the archive, and for
6378 * the -p option, validate the destination directory.
6382 setup(int largc
, char **largv
)
6385 extern char *optarg
;
6387 #if defined(O_XATTR)
6388 #if defined(_PC_SATTR_ENABLED)
6390 char *opts_p
= "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
6392 char *opts_p
= "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
6393 #endif /* WAITAROUND */
6395 #else /* _PC_SATTR_ENABLED */
6397 char *opts_p
= "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
6399 char *opts_p
= "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
6400 #endif /* WAITAROUND */
6401 #endif /* _PC_SATTR_ENABLED */
6405 char *opts_p
= "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
6407 char *opts_p
= "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
6408 #endif /* WAITAROUND */
6409 #endif /* O_XATTR */
6411 char *dupl_p
= "Only one occurrence of -%c allowed";
6413 int blk_cnt
, blk_cnt_max
;
6416 /* Remember the native page size. */
6418 PageSize
= sysconf(_SC_PAGESIZE
);
6420 if (PageSize
== -1) {
6422 * This sysconf call will almost certainly never fail. The
6423 * symbol PAGESIZE itself resolves to the above sysconf call,
6424 * so we should go ahead and define our own constant.
6430 Max_offset
= (off_t
)(BIN_OFFSET_MAX
);
6431 Efil_p
= Hdr_p
= Own_p
= IOfil_p
= NULL
;
6432 while ((option
= getopt(largc
, largv
, opts_p
)) != EOF
) {
6436 /* rendezvous with the debugger */
6440 case 'a': /* reset access time */
6443 case 'b': /* swap bytes and halfwords */
6446 case 'c': /* select character header */
6452 case 'd': /* create directories as needed */
6455 case 'f': /* select files not in patterns */
6458 case 'i': /* "copy in" */
6462 case 'k': /* retry after I/O errors */
6465 case 'l': /* link files when possible */
6468 case 'm': /* retain modification time */
6471 case 'o': /* "copy out" */
6475 case 'p': /* "pass" */
6479 case 'q': /* "quiet" */
6482 case 'r': /* rename files interactively */
6485 case 's': /* swap bytes */
6488 case 't': /* table of contents */
6491 case 'u': /* copy unconditionally */
6494 case 'v': /* verbose - print file names */
6497 case 'A': /* append to existing archive */
6500 case 'B': /* set block size to 5120 bytes */
6504 case 'C': /* set arbitrary block size */
6506 msg(ERR
, dupl_p
, 'C');
6509 Bufsize
= atoi(optarg
);
6515 case 'E': /* alternate file for pattern input */
6517 msg(ERR
, dupl_p
, 'E');
6523 case 'H': /* select header type */
6525 msg(ERR
, dupl_p
, 'H');
6531 case 'I': /* alternate file for archive input */
6533 msg(ERR
, dupl_p
, 'I');
6539 case 'L': /* follow symbolic links */
6542 case 'M': /* specify new end-of-media message */
6544 msg(ERR
, dupl_p
, 'M');
6550 case 'O': /* alternate file for archive output */
6552 msg(ERR
, dupl_p
, 'O');
6558 case 'P': /* preserve acls */
6562 case 'R': /* change owner/group of files */
6564 msg(ERR
, dupl_p
, 'R');
6570 case 'S': /* swap halfwords */
6573 case 'V': /* print a dot '.' for each file */
6576 case '6': /* for old, sixth-edition files */
6580 #if defined(O_XATTR)
6584 #if defined(_PC_SATTR_ENABLED)
6588 #endif /* _PC_SATTR_ENABLED */
6589 #endif /* O_XATTR */
6593 } /* (option = getopt(largc, largv, opts_p)) != EOF */
6597 (void) fprintf(stderr
, gettext("Rendezvous with cpio on pid"
6598 " %d\n"), getpid());
6600 while (waitaround
) {
6611 Renam_p
= e_zalloc(E_EXIT
, APATH
+ 1);
6612 Renametmp_p
= e_zalloc(E_EXIT
, APATH
+ 1);
6613 #if defined(_PC_SATTR_ENABLED)
6614 Renam_attr_p
= e_zalloc(E_EXIT
, APATH
+ 1);
6617 Symlnk_p
= e_zalloc(E_EXIT
, APATH
);
6618 Over_p
= e_zalloc(E_EXIT
, APATH
);
6619 Nam_p
= e_zalloc(E_EXIT
, APATH
+ 1);
6621 Savenam_p
= e_zalloc(E_EXIT
, APATH
+ 1);
6623 Fullnam_p
= e_zalloc(E_EXIT
, APATH
);
6624 Lnknam_p
= e_zalloc(E_EXIT
, APATH
);
6625 Gen
.g_nam_p
= Nam_p
;
6626 if ((Fullnam_p
= getcwd(NULL
, APATH
)) == NULL
)
6627 msg(EXT
, "Unable to determine current directory.");
6629 if (largc
> 0) /* save patterns for -i option, if any */
6632 getpats(largc
, largv
);
6633 } else if (Args
& OCo
) {
6634 if (largc
!= 0) /* error if arguments left with -o */
6636 else if (fstat(Archive
, &ArchSt
) < 0)
6637 msg(ERRN
, "Error during stat() of archive");
6646 Max_offset
= (off_t
)(CHAR_OFFSET_MAX
);
6652 Max_offset
= (off_t
)(ASC_OFFSET_MAX
);
6656 case USTAR
: /* TAR and USTAR */
6659 Max_offset
= (off_t
)(CHAR_OFFSET_MAX
);
6662 msg(EXT
, "Impossible header type.");
6664 } else { /* directory must be specified */
6667 else if (access(*largv
, 2) < 0 && (errno
!= EACCES
))
6669 * EACCES is ignored here as it may occur
6670 * when any directory component of the path
6671 * does not have write permission, even though
6672 * the destination subdirectory has write
6673 * access. Writing to a read only directory
6674 * is handled later, as in "copy in" mode.
6677 "Error during access() of \"%s\"", *largv
);
6681 usage(); /* exits! */
6682 if (Args
& (OCi
| OCo
)) {
6684 if (Args
& (OCB
| OCC
)) {
6685 if (g_init(&Device
, &Archive
) < 0)
6687 "Error during initialization");
6689 if ((Bufsize
= g_init(&Device
, &Archive
)) < 0)
6691 "Error during initialization");
6695 blk_cnt_max
= _20K
/ Bufsize
;
6696 if (blk_cnt_max
< MX_BUFS
) {
6697 blk_cnt_max
= MX_BUFS
;
6700 Buffr
.b_base_p
= NULL
;
6702 for (blk_cnt
= blk_cnt_max
; blk_cnt
> 1; blk_cnt
--) {
6703 Buffr
.b_size
= (size_t)(Bufsize
* blk_cnt
);
6704 Buffr
.b_base_p
= e_valloc(E_NORMAL
, Buffr
.b_size
);
6705 if (Buffr
.b_base_p
!= NULL
) {
6709 if (Buffr
.b_base_p
== NULL
|| Buffr
.b_size
< (2 * CPIOBSZ
)) {
6710 msg(EXT
, "Out of memory");
6713 Buffr
.b_out_p
= Buffr
.b_in_p
= Buffr
.b_base_p
;
6715 Buffr
.b_end_p
= Buffr
.b_base_p
+ Buffr
.b_size
;
6719 * Now that Bufsize has stabilized, we can allocate our i/o buffer
6721 Buf_p
= e_valloc(E_EXIT
, Bufsize
);
6723 if (Args
& OCp
) { /* get destination directory */
6724 (void) strcpy(Fullnam_p
, *largv
);
6725 if (stat(Fullnam_p
, &DesSt
) < 0)
6726 msg(EXTN
, "Error during stat() of \"%s\"", Fullnam_p
);
6727 if ((DesSt
.st_mode
& Ftype
) != S_IFDIR
)
6728 msg(EXT
, "\"%s\" is not a directory", Fullnam_p
);
6730 Full_p
= Fullnam_p
+ strlen(Fullnam_p
) - 1;
6731 if (*Full_p
!= '/') {
6737 (void) strcpy(Lnknam_p
, Fullnam_p
);
6738 Lnkend_p
= Lnknam_p
+ strlen(Lnknam_p
);
6739 (void) getrlimit(RLIMIT_FSIZE
, &rlim
);
6740 Max_filesz
= (off_t
)rlim
.rlim_cur
;
6741 Lnk_hd
.L_nxt_p
= Lnk_hd
.L_bck_p
= &Lnk_hd
;
6742 Lnk_hd
.L_lnk_p
= NULL
;
6746 * set_tym: Set the access and/or modification times for a file.
6750 set_tym(int dirfd
, char *nam_p
, time_t atime
, time_t mtime
)
6752 struct timeval times
[2];
6754 times
[0].tv_sec
= atime
;
6755 times
[0].tv_usec
= 0;
6756 times
[1].tv_sec
= mtime
;
6757 times
[1].tv_usec
= 0;
6759 if (futimesat(dirfd
, nam_p
, times
) < 0) {
6762 "Unable to reset access time for \"%s%s%s\"",
6763 (G_p
->g_attrnam_p
== NULL
) ? nam_p
: Fullnam_p
,
6764 (G_p
->g_attrnam_p
== NULL
) ? "" :
6765 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
6766 gettext(" Attribute "),
6767 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
6770 "Unable to reset modification time for \"%s%s%s\"",
6771 (G_p
->g_attrnam_p
== NULL
) ? nam_p
: Fullnam_p
,
6772 (G_p
->g_attrnam_p
== NULL
) ? "" :
6773 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
6774 gettext(" Attribute "),
6775 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
6781 * sigint: Catch interrupts. If an interrupt occurs during the extraction
6782 * of a file from the archive with the -u option set, and the filename did
6783 * exist, remove the current file and restore the original file. Then exit.
6792 (void) signal(SIGINT
, SIG_IGN
); /* block further signals */
6795 nam_p
= G_p
->g_nam_p
;
6798 if (*Over_p
!= '\0') { /* There is a temp file */
6799 if (unlink(nam_p
) < 0) {
6801 "Cannot remove incomplete \"%s\"", nam_p
);
6803 if (rename(Over_p
, nam_p
) < 0) {
6804 if (link(Over_p
, nam_p
) < 0) {
6806 "Cannot recover original \"%s\"",
6809 if (unlink(Over_p
)) {
6811 "Cannot remove temp file \"%s\"",
6815 } else if (unlink(nam_p
))
6816 msg(ERRN
, "Cannot remove incomplete \"%s\"", nam_p
);
6823 * swap: Swap bytes (-s), halfwords (-S) or or both halfwords and bytes (-b).
6827 swap(char *buf_p
, int cnt
)
6829 unsigned char tbyte
;
6836 if (Args
& (OCb
| OCs
| BSM
)) {
6838 /* LINTED alignment */
6839 Swp_p
= (union swpbuf
*)buf_p
;
6840 while (tcnt
-- > 0) {
6841 tbyte
= Swp_p
->s_byte
[0];
6842 Swp_p
->s_byte
[0] = Swp_p
->s_byte
[1];
6843 Swp_p
->s_byte
[1] = tbyte
;
6844 tbyte
= Swp_p
->s_byte
[2];
6845 Swp_p
->s_byte
[2] = Swp_p
->s_byte
[3];
6846 Swp_p
->s_byte
[3] = tbyte
;
6850 tbyte
= Swp_p
->s_byte
[0];
6851 Swp_p
->s_byte
[0] = Swp_p
->s_byte
[1];
6852 Swp_p
->s_byte
[1] = tbyte
;
6853 tbyte
= Swp_p
->s_byte
[2];
6856 if (Args
& (OCb
| OCS
)) {
6858 /* LINTED alignment */
6859 Swp_p
= (union swpbuf
*)buf_p
;
6860 while (tcnt
-- > 0) {
6861 thalf
= Swp_p
->s_half
[0];
6862 Swp_p
->s_half
[0] = Swp_p
->s_half
[1];
6863 Swp_p
->s_half
[1] = thalf
;
6870 * usage: Print the usage message on stderr and exit.
6877 (void) fflush(stdout
);
6878 #if defined(O_XATTR)
6879 (void) fprintf(stderr
, gettext("USAGE:\n"
6880 "\tcpio -i[bcdfkmqrstuv@BSV6] [-C size] "
6881 "[-E file] [-H hdr] [-I file [-M msg]] "
6882 "[-R id] [patterns]\n"
6883 "\tcpio -o[acv@ABLV] [-C size] "
6884 "[-H hdr] [-O file [-M msg]]\n"
6885 "\tcpio -p[adlmuv@LV] [-R id] directory\n"));
6887 (void) fprintf(stderr
, gettext("USAGE:\n"
6888 "\tcpio -i[bcdfkmqrstuvBSV6] [-C size] "
6889 "[-E file] [-H hdr] [-I file [-M msg]] "
6890 "[-R id] [patterns]\n"
6891 "\tcpio -o[acvABLV] [-C size] "
6892 "[-H hdr] [-O file [-M msg]]\n"
6893 "\tcpio -p[adlmuvLV] [-R id] directory\n"));
6895 (void) fflush(stderr
);
6900 * verbose: For each file, print either the filename (-v) or a dot (-V).
6901 * If the -t option (table of contents) is set, print either the filename,
6902 * or if the -v option is also set, print an "ls -l"-like listing.
6906 verbose(char *nam_p
)
6914 * The printf format and associated arguments to print the current
6915 * filename. Normally, just nam_p. If we're processing an extended
6916 * attribute, these are overridden.
6918 char *name_fmt
= "%s";
6919 const char *name
= nam_p
;
6920 const char *attribute
= NULL
;
6922 if (Gen
.g_attrnam_p
!= NULL
) {
6925 * 'attribute' is a noun.
6928 if (Gen
.g_rw_sysattr
) {
6929 name_fmt
= gettext("%s system attribute %s");
6930 } else if ((Args
& OCt
) &&
6931 (is_sysattr(basename(Gen
.g_attrnam_p
)))) {
6932 name_fmt
= gettext("%s system attribute %s");
6934 name_fmt
= gettext("%s attribute %s");
6937 name
= (Args
& OCp
) ? nam_p
: Gen
.g_attrfnam_p
;
6938 if (Gen
.g_attrparent_p
== NULL
) {
6939 attribute
= Gen
.g_attrnam_p
;
6941 attribute
= Gen
.g_attrpath_p
;
6945 if ((Gen
.g_mode
== SECMODE
) || ((Hdr_type
== USTAR
||
6946 Hdr_type
== TAR
) && Thdr_p
->tbuf
.t_typeflag
== 'A')) {
6947 /* dont print ancillary file */
6951 for (i
= 0; i
< 11; i
++)
6954 modestr
[i
-1] = aclchar
;
6957 if ((Args
& OCt
) && (Args
& OCv
)) {
6959 for (i
= 0; i
< 3; i
++) {
6960 temp
= (mode
>> (6 - (i
* 3)));
6965 modestr
[j
+ 1] = 'w';
6967 modestr
[j
+ 2] = 'x';
6970 if (Hdr_type
!= BAR
) {
6971 temp
= Gen
.g_mode
& Ftype
;
6988 case (S_IFREG
): /* was initialized to '-' */
6994 msg(ERR
, "Impossible file type");
6997 temp
= Gen
.g_mode
& Ftype
;
7015 if (bar_linkflag
== SYMTYPE
)
7018 if ((S_ISUID
& Gen
.g_mode
) == S_ISUID
)
7020 if ((S_ISVTX
& Gen
.g_mode
) == S_ISVTX
)
7022 if ((S_ISGID
& G_p
->g_mode
) == S_ISGID
&& modestr
[6] == 'x')
7024 else if ((S_ENFMT
& Gen
.g_mode
) == S_ENFMT
&& modestr
[6] != 'x')
7026 if ((Hdr_type
== TAR
|| Hdr_type
== USTAR
) && Gen
.g_nlink
== 0)
7027 (void) printf("%s%4d ", modestr
, (int)Gen
.g_nlink
+1);
7029 (void) printf("%s%4d ", modestr
, (int)Gen
.g_nlink
);
7030 if (Lastuid
== (uid_t
)Gen
.g_uid
) {
7031 if (Lastuid
== (uid_t
)-1)
7032 (void) printf("-1 ");
7034 (void) printf("%-9s", Curpw_p
->pw_name
);
7036 if (Curpw_p
= getpwuid((int)Gen
.g_uid
)) {
7037 (void) printf("%-9s", Curpw_p
->pw_name
);
7038 Lastuid
= (uid_t
)Gen
.g_uid
;
7040 (void) printf("%-9d", (int)Gen
.g_uid
);
7041 Lastuid
= (uid_t
)-1;
7044 if (Lastgid
== (gid_t
)Gen
.g_gid
) {
7045 if (Lastgid
== (gid_t
)-1)
7046 (void) printf("-1 ");
7048 (void) printf("%-9s", Curgr_p
->gr_name
);
7050 if (Curgr_p
= getgrgid((int)Gen
.g_gid
)) {
7051 (void) printf("%-9s", Curgr_p
->gr_name
);
7052 Lastgid
= (gid_t
)Gen
.g_gid
;
7054 (void) printf("%-9d", (int)Gen
.g_gid
);
7055 Lastgid
= (gid_t
)-1;
7059 /* print file size */
7060 if (!Aspec
|| ((Gen
.g_mode
& Ftype
) == S_IFIFO
) ||
7061 ((Gen
.g_mode
& Ftype
) == S_IFSOCK
) ||
7062 (Hdr_type
== BAR
&& bar_linkflag
== SYMTYPE
)) {
7063 off_t filesz
= Gen
.g_filesz
;
7065 if (S_ISSPARSE(Gen
.g_mode
) && Gen
.g_holes
!= NULL
)
7066 filesz
= Gen
.g_holes
->orig_size
;
7068 if (filesz
< (1LL << 31))
7069 (void) printf("%7lld ", (offset_t
)filesz
);
7071 (void) printf("%11lld ", (offset_t
)filesz
);
7073 (void) printf("%3d,%3d ", (int)major(Gen
.g_rdev
),
7074 (int)minor(Gen
.g_rdev
));
7075 ttime
= Gen
.g_mtime
;
7076 (void) strftime(Time
, sizeof (Time
),
7077 dcgettext(NULL
, FORMAT
, LC_TIME
), localtime(&ttime
));
7078 (void) printf("%s, ", Time
);
7079 str_fprintf(stdout
, name_fmt
, name
, attribute
);
7080 if ((Gen
.g_mode
& Ftype
) == S_IFLNK
) {
7081 if (Hdr_type
== USTAR
|| Hdr_type
== TAR
)
7082 (void) strcpy(Symlnk_p
,
7083 Thdr_p
->tbuf
.t_linkname
);
7086 (void) strncpy(Symlnk_p
, Buffr
.b_out_p
,
7088 *(Symlnk_p
+ Gen
.g_filesz
) = '\0';
7090 (void) printf(" -> %s", Symlnk_p
);
7092 if (Hdr_type
== BAR
) {
7093 if (bar_linkflag
== SYMTYPE
)
7094 (void) printf(gettext(" symbolic link to %s"),
7096 else if (bar_linkflag
== '1')
7097 (void) printf(gettext(" linked to %s"),
7100 if ((Hdr_type
== USTAR
|| Hdr_type
== TAR
) &&
7101 Thdr_p
->tbuf
.t_typeflag
== '1') {
7102 (void) printf(gettext(" linked to %s%s%s"),
7103 (Gen
.g_attrnam_p
== NULL
) ?
7104 Thdr_p
->tbuf
.t_linkname
: Gen
.g_attrfnam_p
,
7105 (Gen
.g_attrnam_p
== NULL
) ? "" :
7106 gettext(" attribute "),
7107 (Gen
.g_attrnam_p
== NULL
) ?
7108 "" : Gen
.g_linktoattrnam_p
);
7110 (void) printf("\n");
7111 } else if ((Args
& OCt
) || (Args
& OCv
)) {
7112 str_fprintf(Out_p
, name_fmt
, name
, attribute
);
7113 (void) fputc('\n', Out_p
);
7115 (void) fputc('.', Out_p
);
7116 if (Verbcnt
++ >= 49) { /* start a new line of dots */
7118 (void) fputc('\n', Out_p
);
7121 (void) fflush(Out_p
);
7124 #define MK_USHORT(a) (a & 00000177777)
7127 * write_hdr: Transfer header information for the generic structure
7128 * into the format for the selected header and bwrite() the header.
7132 write_hdr(int arcflag
, off_t len
)
7138 const char warnfmt
[] = "%s%s%s : %s";
7146 case ARCHIVE_NORMAL
:
7148 * If attribute is being archived in cpio format then
7149 * zap off the file type bits since those are truly a
7150 * mask and reset them with _XATTR_CPIO_MODE
7153 * len is the value of g_filesz for normal files
7154 * and the length of the special header buffer in
7155 * the case of acl and xattr headers.
7157 if (G_p
->g_attrnam_p
!= NULL
&& Hdr_type
!= USTAR
&&
7159 mode
= (G_p
->g_mode
& POSIXMODES
) | _XATTR_CPIO_MODE
;
7163 if (arcflag
!= ARCHIVE_XATTR
) {
7164 len
= G_p
->g_filesz
;
7168 case ARCHIVE_SPARSE
:
7169 mode
= G_p
->g_mode
| C_ISSPARSE
;
7170 len
= G_p
->g_filesz
;
7177 * Handle EFT uids and gids. If they get too big
7178 * to be represented in a particular format, force 'em to 'nobody'.
7181 case BIN
: /* 16-bits of u_short */
7182 if ((ulong_t
)uid
> (ulong_t
)USHRT_MAX
)
7184 if ((ulong_t
)gid
> (ulong_t
)USHRT_MAX
)
7187 case CHR
: /* %.6lo => 262143 base 10 */
7188 if ((ulong_t
)uid
> (ulong_t
)0777777)
7190 if ((ulong_t
)gid
> (ulong_t
)0777777)
7193 case ASC
: /* %.8lx => full 32 bits */
7197 case TAR
: /* %.7lo => 2097151 base 10 */
7198 if ((ulong_t
)uid
> (ulong_t
)07777777)
7200 if ((ulong_t
)gid
> (ulong_t
)07777777)
7204 msg(EXT
, "Impossible header type.");
7208 * Since cpio formats -don't- encode the symbolic names, print
7209 * a warning message when we map the uid or gid this way.
7210 * Also, if the ownership just changed, clear set[ug]id bits
7212 * (Except for USTAR format of course, where we have a string
7213 * representation of the username embedded in the header)
7215 if (uid
!= G_p
->g_uid
&& Hdr_type
!= USTAR
) {
7217 (G_p
->g_attrnam_p
== NULL
) ?
7218 G_p
->g_nam_p
: G_p
->g_attrfnam_p
,
7219 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_rw_sysattr
?
7220 gettext(" System Attribute ") : gettext(" Attribute "),
7221 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
,
7222 gettext("uid too large for archive format"));
7226 if (gid
!= G_p
->g_gid
&& Hdr_type
!= USTAR
) {
7228 (G_p
->g_attrnam_p
== NULL
) ?
7229 G_p
->g_nam_p
: G_p
->g_attrfnam_p
,
7230 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_rw_sysattr
?
7231 gettext(" System Attribute ") : gettext(" Attribute "),
7232 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
,
7233 gettext("gid too large for archive format"));
7243 cnt
= Hdrsz
+ G_p
->g_namesz
;
7247 case USTAR
: /* TAR and USTAR */
7251 msg(EXT
, "Impossible header type.");
7257 Hdr
.h_magic
= (short)G_p
->g_magic
;
7258 Hdr
.h_dev
= G_p
->g_dev
;
7259 Hdr
.h_ino
= G_p
->g_ino
;
7263 Hdr
.h_nlink
= G_p
->g_nlink
;
7264 Hdr
.h_rdev
= G_p
->g_rdev
;
7265 mkshort(Hdr
.h_mtime
, (long)G_p
->g_mtime
);
7266 Hdr
.h_namesize
= (short)G_p
->g_namesz
;
7267 mkshort(Hdr
.h_filesize
, (long)len
);
7268 (void) strcpy(Hdr
.h_name
, G_p
->g_nam_p
);
7269 (void) memcpy(Buffr
.b_in_p
, &Hdr
, cnt
);
7273 (void) sprintf(Buffr
.b_in_p
,
7274 "%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.11lo%.6lo%."
7275 "11llo%s", G_p
->g_magic
, G_p
->g_dev
, G_p
->g_ino
, mode
,
7276 (long)uid
, (long)gid
, G_p
->g_nlink
, MK_USHORT(G_p
->g_rdev
),
7277 G_p
->g_mtime
, (long)G_p
->g_namesz
, (offset_t
)len
,
7283 (void) sprintf(Buffr
.b_in_p
,
7284 "%.6lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%."
7285 "8lx%.8lx%.8lx%.8lx%s",
7286 G_p
->g_magic
, G_p
->g_ino
, mode
, G_p
->g_uid
,
7287 G_p
->g_gid
, G_p
->g_nlink
, G_p
->g_mtime
, (ulong_t
)len
,
7288 major(G_p
->g_dev
), minor(G_p
->g_dev
),
7289 major(G_p
->g_rdev
), minor(G_p
->g_rdev
),
7290 G_p
->g_namesz
, G_p
->g_cksum
, G_p
->g_nam_p
);
7293 Thdr_p
= (union tblock
*)Buffr
.b_in_p
;
7294 (void) memset(Thdr_p
, 0, TARSZ
);
7295 (void) strncpy(Thdr_p
->tbuf
.t_name
, G_p
->g_tname
,
7296 (int)strlen(G_p
->g_tname
));
7297 (void) sprintf(Thdr_p
->tbuf
.t_mode
, "%07o", (int)mode
);
7298 (void) sprintf(Thdr_p
->tbuf
.t_uid
, "%07o", (int)uid
);
7299 (void) sprintf(Thdr_p
->tbuf
.t_gid
, "%07o", (int)gid
);
7300 (void) sprintf(Thdr_p
->tbuf
.t_size
, "%011llo",
7302 (void) sprintf(Thdr_p
->tbuf
.t_mtime
, "%011lo", G_p
->g_mtime
);
7303 if (arcflag
== ARCHIVE_ACL
) {
7304 Thdr_p
->tbuf
.t_typeflag
= 'A'; /* ACL file type */
7305 } else if (arcflag
== ARCHIVE_XATTR
||
7306 (G_p
->g_attrnam_p
!= NULL
)) {
7307 Thdr_p
->tbuf
.t_typeflag
= _XATTR_HDRTYPE
;
7309 Thdr_p
->tbuf
.t_typeflag
= G_p
->g_typeflag
;
7311 if (T_lname
[0] != '\0') {
7313 * if not a symbolic link
7315 if (((G_p
->g_mode
& Ftype
) != S_IFLNK
) &&
7316 (G_p
->g_attrnam_p
== NULL
)) {
7317 Thdr_p
->tbuf
.t_typeflag
= LNKTYPE
;
7318 (void) sprintf(Thdr_p
->tbuf
.t_size
,
7321 (void) strncpy(Thdr_p
->tbuf
.t_linkname
, T_lname
,
7324 (void) strcpy(Thdr_p
->tbuf
.t_magic
, TMAGIC
);
7325 (void) strcpy(Thdr_p
->tbuf
.t_version
, TVERSION
);
7326 (void) strcpy(Thdr_p
->tbuf
.t_uname
, G_p
->g_uname
);
7327 (void) strcpy(Thdr_p
->tbuf
.t_gname
, G_p
->g_gname
);
7328 (void) sprintf(Thdr_p
->tbuf
.t_devmajor
, "%07o",
7329 (int)major(G_p
->g_rdev
));
7330 (void) sprintf(Thdr_p
->tbuf
.t_devminor
, "%07o",
7331 (int)minor(G_p
->g_rdev
));
7333 (void) strcpy(Thdr_p
->tbuf
.t_prefix
, Gen
.g_prefix
);
7335 Gen
.g_prefix
= NULL
;
7337 Thdr_p
->tbuf
.t_prefix
[0] = '\0';
7339 (void) sprintf(Thdr_p
->tbuf
.t_cksum
, "%07o",
7340 (int)cksum(TARTYP
, 0, NULL
));
7343 Thdr_p
= (union tblock
*)Buffr
.b_in_p
;
7344 (void) memset(Thdr_p
, 0, TARSZ
);
7345 (void) strncpy(Thdr_p
->tbuf
.t_name
, G_p
->g_nam_p
,
7347 (void) sprintf(Thdr_p
->tbuf
.t_mode
, "%07o ", (int)mode
);
7348 (void) sprintf(Thdr_p
->tbuf
.t_uid
, "%07o ", (int)uid
);
7349 (void) sprintf(Thdr_p
->tbuf
.t_gid
, "%07o ", (int)gid
);
7350 (void) sprintf(Thdr_p
->tbuf
.t_size
, "%011llo ",
7352 (void) sprintf(Thdr_p
->tbuf
.t_mtime
, "%011o ",
7354 if (T_lname
[0] != '\0') {
7355 Thdr_p
->tbuf
.t_typeflag
= '1';
7357 Thdr_p
->tbuf
.t_typeflag
= '\0';
7359 (void) strncpy(Thdr_p
->tbuf
.t_linkname
, T_lname
,
7363 msg(EXT
, "Impossible header type.");
7366 Buffr
.b_in_p
+= cnt
;
7368 pad
= ((cnt
+ Pad_val
) & ~Pad_val
) - cnt
;
7371 (void) memset(Buffr
.b_in_p
, 0, pad
);
7372 Buffr
.b_in_p
+= pad
;
7378 * write_trail: Create the appropriate trailer for the selected header type
7379 * and bwrite the trailer. Pad the buffer with nulls out to the next Bufsize
7380 * boundary, and force a write. If the write completes, or if the trailer is
7381 * completely written (but not all of the padding nulls (as can happen on end
7382 * of medium)) return. Otherwise, the trailer was not completely written out,
7383 * so re-pad the buffer with nulls and try again.
7393 Gen
.g_magic
= CMN_BIN
;
7396 Gen
.g_magic
= CMN_BIN
;
7399 Gen
.g_magic
= CMN_ASC
;
7402 Gen
.g_magic
= CMN_CRC
;
7411 Gen
.g_mode
= Gen
.g_uid
= Gen
.g_gid
= 0;
7413 Gen
.g_mtime
= Gen
.g_ino
= Gen
.g_dev
= 0;
7414 Gen
.g_rdev
= Gen
.g_cksum
= 0;
7415 Gen
.g_filesz
= (off_t
)0;
7416 Gen
.g_namesz
= strlen("TRAILER!!!") + 1;
7417 (void) strcpy(Gen
.g_nam_p
, "TRAILER!!!");
7419 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
7423 case USTAR
: /* TAR and USTAR */
7424 for (cnt
= 0; cnt
< 3; cnt
++) {
7426 (void) memset(Buffr
.b_in_p
, 0, TARSZ
);
7427 Buffr
.b_in_p
+= TARSZ
;
7428 Buffr
.b_cnt
+= TARSZ
;
7432 msg(EXT
, "Impossible header type.");
7434 need
= Bufsize
- (Buffr
.b_cnt
% Bufsize
);
7435 if (need
== Bufsize
)
7438 while (Buffr
.b_cnt
> 0) {
7440 cnt
= (need
< TARSZ
) ? need
: TARSZ
;
7443 (void) memset(Buffr
.b_in_p
, 0, cnt
);
7444 Buffr
.b_in_p
+= cnt
;
7452 * if archives in USTAR format, check if typeflag == '5' for directories
7457 if (Hdr_type
== USTAR
|| Hdr_type
== TAR
) {
7458 if (Thdr_p
->tbuf
.t_typeflag
== '5')
7465 * if archives in USTAR format, check if typeflag == '3' || '4' || '6'
7466 * for character, block, fifo special files
7473 if (Hdr_type
== USTAR
|| Hdr_type
== TAR
) {
7474 typeflag
= Thdr_p
->tbuf
.t_typeflag
;
7475 if (typeflag
== '3' || typeflag
== '4' || typeflag
== '6')
7482 * The return value is a pointer to a converted copy of the information in
7483 * FromStat if the file is representable in -Hodc format, and NULL otherwise.
7486 static struct stat
*
7487 convert_to_old_stat(struct stat
*FromStat
, char *namep
, char *attrp
)
7489 static struct stat ToSt
;
7492 (void) memset(&TmpSt
, 0, sizeof (cpioinfo_t
));
7493 stat_to_svr32_stat(&TmpSt
, FromStat
);
7494 (void) memset(&ToSt
, 0, sizeof (ToSt
));
7496 if (TmpSt
.st_rdev
== (o_dev_t
)NODEV
&&
7497 (((TmpSt
.st_mode
& Ftype
) == S_IFCHR
) ||
7498 ((TmpSt
.st_mode
& Ftype
) == S_IFBLK
))) {
7500 * Encountered a problem representing the rdev information.
7504 msg(ERR
, "Error -Hodc format can't support expanded"
7507 (attrp
== NULL
) ? "" : gettext(" Attribute"),
7508 (attrp
== NULL
) ? "" : attrp
);
7512 if (TmpSt
.st_dev
== (o_dev_t
)NODEV
) {
7514 * Having trouble representing the device/inode pair. We can't
7515 * track links in this case; break them all into separate
7521 if (((TmpSt
.st_mode
& Ftype
) != S_IFDIR
) &&
7524 "Warning: file %s%s%s has large "
7525 "device number - linked "
7526 "files will be restored as "
7529 (attrp
== NULL
) ? "" : gettext(" Attribute"),
7530 (attrp
== NULL
) ? "" : attrp
);
7532 /* ensure no links */
7537 /* Start converting values */
7539 if (TmpSt
.st_dev
< 0) {
7542 ToSt
.st_dev
= (dev_t
)TmpSt
.st_dev
;
7545 /* -actual- not truncated uid */
7547 ToSt
.st_uid
= TmpSt
.st_uid
;
7549 /* -actual- not truncated gid */
7551 ToSt
.st_gid
= TmpSt
.st_gid
;
7552 ToSt
.st_ino
= (ino_t
)TmpSt
.st_ino
;
7553 ToSt
.st_mode
= (mode_t
)TmpSt
.st_mode
;
7554 ToSt
.st_mtime
= (ulong_t
)TmpSt
.st_modtime
;
7555 ToSt
.st_nlink
= (nlink_t
)TmpSt
.st_nlink
;
7556 ToSt
.st_size
= (off_t
)TmpSt
.st_size
;
7557 ToSt
.st_rdev
= (dev_t
)TmpSt
.st_rdev
;
7563 * In the beginning of each bar archive, there is a header which describes the
7564 * current volume being created, followed by a header which describes the
7565 * current file being created, followed by the file itself. If there is
7566 * more than one file to be created, a separate header will be created for
7567 * each additional file. This structure may be repeated if the bar archive
7568 * contains multiple volumes. If a file spans across volumes, its header
7569 * will not be repeated in the next volume.
7570 * +------------------+
7572 * |------------------|
7573 * | file header i | i = 0
7574 * |------------------|
7576 * |------------------|
7577 * | file header i+1 |
7578 * |------------------|
7580 * |------------------|
7584 * +------------------+
7588 * read in the header that describes the current volume of the bar archive
7592 read_bar_vol_hdr(void)
7594 union b_block
*tmp_hdr
;
7596 tmp_hdr
= (union b_block
*)Buffr
.b_out_p
;
7597 if (tmp_hdr
->dbuf
.bar_magic
[0] == BAR_VOLUME_MAGIC
) {
7599 if (bar_Vhdr
== NULL
) {
7600 bar_Vhdr
= e_zalloc(E_EXIT
, TBLOCK
);
7602 (void) memcpy(&(bar_Vhdr
->dbuf
), &(tmp_hdr
->dbuf
), TBLOCK
);
7604 (void) fprintf(stderr
, gettext(
7605 "bar error: cannot read volume header\n"));
7609 (void) sscanf(bar_Vhdr
->dbuf
.mode
, "%8lo", &Gen_bar_vol
.g_mode
);
7610 (void) sscanf(bar_Vhdr
->dbuf
.uid
, "%8d", (int *)&Gen_bar_vol
.g_uid
);
7611 (void) sscanf(bar_Vhdr
->dbuf
.gid
, "%8d", (int *)&Gen_bar_vol
.g_gid
);
7612 (void) sscanf(bar_Vhdr
->dbuf
.size
, "%12llo",
7613 (u_off_t
*)&Gen_bar_vol
.g_filesz
);
7614 (void) sscanf(bar_Vhdr
->dbuf
.mtime
, "%12lo", &Gen_bar_vol
.g_mtime
);
7615 (void) sscanf(bar_Vhdr
->dbuf
.chksum
, "%8lo", &Gen_bar_vol
.g_cksum
);
7617 /* set the compress flag */
7618 if (bar_Vhdr
->dbuf
.compressed
== '1')
7623 Buffr
.b_out_p
+= 512;
7627 * not the first volume; exit
7629 if (strcmp(bar_Vhdr
->dbuf
.volume_num
, "1") != 0) {
7630 (void) fprintf(stderr
,
7631 gettext("error: This is not volume 1. "));
7632 (void) fprintf(stderr
, gettext("This is volume %s. "),
7633 bar_Vhdr
->dbuf
.volume_num
);
7634 (void) fprintf(stderr
, gettext("Please insert volume 1.\n"));
7638 read_bar_file_hdr();
7642 * read in the header that describes the current file to be extracted
7645 read_bar_file_hdr(void)
7647 union b_block
*tmp_hdr
;
7648 char *start_of_name
, *name_p
;
7651 if (*Buffr
.b_out_p
== '\0') {
7652 *Gen
.g_nam_p
= '\0';
7656 tmp_hdr
= (union b_block
*)Buffr
.b_out_p
;
7658 tmp
= &tmp_hdr
->dbuf
.mode
[1];
7659 (void) sscanf(tmp
, "%8lo", &Gen
.g_mode
);
7660 (void) sscanf(tmp_hdr
->dbuf
.uid
, "%8lo", &Gen
.g_uid
);
7661 (void) sscanf(tmp_hdr
->dbuf
.gid
, "%8lo", &Gen
.g_gid
);
7662 (void) sscanf(tmp_hdr
->dbuf
.size
, "%12llo",
7663 (u_off_t
*)&Gen
.g_filesz
);
7664 (void) sscanf(tmp_hdr
->dbuf
.mtime
, "%12lo", &Gen
.g_mtime
);
7665 (void) sscanf(tmp_hdr
->dbuf
.chksum
, "%8lo", &Gen
.g_cksum
);
7666 (void) sscanf(tmp_hdr
->dbuf
.rdev
, "%8lo", &Gen
.g_rdev
);
7668 #define to_new_major(x) (int)((unsigned)((x) & OMAXMAJ) << NBITSMINOR)
7669 #define to_new_minor(x) (int)((x) & OMAXMIN)
7670 Gen
.g_rdev
= to_new_major(Gen
.g_rdev
) | to_new_minor(Gen
.g_rdev
);
7671 bar_linkflag
= tmp_hdr
->dbuf
.linkflag
;
7672 start_of_name
= &tmp_hdr
->dbuf
.start_of_name
;
7675 name_p
= Gen
.g_nam_p
;
7676 while (*name_p
++ = *start_of_name
++)
7679 if (bar_linkflag
== LNKTYPE
|| bar_linkflag
== SYMTYPE
)
7680 (void) strcpy(bar_linkname
, start_of_name
);
7682 Gen
.g_namesz
= strlen(Gen
.g_nam_p
) + 1;
7683 (void) strcpy(nambuf
, Gen
.g_nam_p
);
7687 * if the bar archive is compressed, set up a pipe and do the de-compression
7688 * as the compressed file is read in.
7691 setup_uncompress(FILE **pipef
)
7696 cmd_buf
= e_zalloc(E_EXIT
, MAXPATHLEN
* 2);
7698 if (access(Gen
.g_nam_p
, W_OK
) != 0) {
7699 cmdlen
= snprintf(cmd_buf
, MAXPATHLEN
* 2,
7700 "chmod +w '%s'; uncompress -c > '%s'; "
7702 Gen
.g_nam_p
, Gen
.g_nam_p
, (int)G_p
->g_mode
, Gen
.g_nam_p
);
7704 cmdlen
= snprintf(cmd_buf
, MAXPATHLEN
* 2,
7705 "uncompress -c > '%s'", Gen
.g_nam_p
);
7708 if (cmdlen
>= MAXPATHLEN
* 2 ||
7709 (*pipef
= popen(cmd_buf
, "w")) == NULL
) {
7710 (void) fprintf(stderr
, gettext("error\n"));
7714 if (close(Ofile
) != 0)
7715 msg(EXTN
, "close error");
7716 Ofile
= fileno(*pipef
);
7722 * if the bar archive spans multiple volumes, read in the header that
7723 * describes the next volume.
7726 skip_bar_volhdr(void)
7729 union b_block
*tmp_hdr
;
7731 buff
= e_zalloc(E_EXIT
, (uint_t
)Bufsize
);
7733 if (g_read(Device
, Archive
, buff
, Bufsize
) < 0) {
7734 (void) fprintf(stderr
, gettext(
7735 "error in skip_bar_volhdr\n"));
7738 tmp_hdr
= (union b_block
*)buff
;
7739 if (tmp_hdr
->dbuf
.bar_magic
[0] == BAR_VOLUME_MAGIC
) {
7741 if (bar_Vhdr
== NULL
) {
7742 bar_Vhdr
= e_zalloc(E_EXIT
, TBLOCK
);
7744 (void) memcpy(&(bar_Vhdr
->dbuf
),
7745 &(tmp_hdr
->dbuf
), TBLOCK
);
7747 (void) fprintf(stderr
,
7748 gettext("cpio error: cannot read bar volume "
7753 (void) sscanf(bar_Vhdr
->dbuf
.mode
, "%8lo",
7754 &Gen_bar_vol
.g_mode
);
7755 (void) sscanf(bar_Vhdr
->dbuf
.uid
, "%8lo",
7756 &Gen_bar_vol
.g_uid
);
7757 (void) sscanf(bar_Vhdr
->dbuf
.gid
, "%8lo",
7758 &Gen_bar_vol
.g_gid
);
7759 (void) sscanf(bar_Vhdr
->dbuf
.size
, "%12llo",
7760 (u_off_t
*)&Gen_bar_vol
.g_filesz
);
7761 (void) sscanf(bar_Vhdr
->dbuf
.mtime
, "%12lo",
7762 &Gen_bar_vol
.g_mtime
);
7763 (void) sscanf(bar_Vhdr
->dbuf
.chksum
, "%8lo",
7764 &Gen_bar_vol
.g_cksum
);
7765 if (bar_Vhdr
->dbuf
.compressed
== '1')
7772 * Now put the rest of the bytes read in into the data buffer.
7774 (void) memcpy(Buffr
.b_in_p
, &buff
[512], (Bufsize
- 512));
7775 Buffr
.b_in_p
+= (Bufsize
- 512);
7776 Buffr
.b_cnt
+= (long)(Bufsize
- 512);
7782 * check the linkflag which indicates the type of the file to be extracted,
7783 * invoke the corresponding routine to extract the file.
7789 * the file is a directory
7792 if (ckname(1) != F_SKIP
&& creat_spec(G_p
->g_dirfd
) > 0) {
7793 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
7798 switch (bar_linkflag
) {
7801 if ((ckname(1) == F_SKIP
) ||
7802 (Ofile
= openout(G_p
->g_dirfd
)) < 0) {
7810 if (ckname(1) == F_SKIP
) {
7813 (void) creat_lnk(G_p
->g_dirfd
, bar_linkname
, G_p
->g_nam_p
);
7817 if ((ckname(1) == F_SKIP
) ||
7818 (Ofile
= openout(G_p
->g_dirfd
)) < 0) {
7825 /* character device or FIFO */
7826 if (ckname(1) != F_SKIP
&& creat_spec(G_p
->g_dirfd
) > 0) {
7827 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
7831 (void) fprintf(stderr
, gettext("error: unknown file type\n"));
7838 * This originally came from libgenIO/g_init.c
7839 * XXX And it is very broken.
7842 /* #include <sys/statvfs.h> */
7844 /* #include <libgenIO.h> */
7845 #define G_TM_TAPE 1 /* Tapemaster controller */
7846 #define G_XY_DISK 3 /* xy disks */
7847 #define G_SD_DISK 7 /* scsi sd disk */
7848 #define G_XT_TAPE 8 /* xt tapes */
7849 #define G_SF_FLOPPY 9 /* sf floppy */
7850 #define G_XD_DISK 10 /* xd disks */
7851 #define G_ST_TAPE 11 /* scsi tape */
7852 #define G_NS 12 /* noswap pseudo-dev */
7853 #define G_RAM 13 /* ram pseudo-dev */
7854 #define G_FT 14 /* tftp */
7855 #define G_HD 15 /* 386 network disk */
7856 #define G_FD 16 /* 386 AT disk */
7857 #define G_FILE 28 /* file, not a device */
7858 #define G_NO_DEV 29 /* device does not require special treatment */
7859 #define G_DEV_MAX 30 /* last valid device type */
7862 * g_init: Determine the device being accessed, set the buffer size,
7863 * and perform any device specific initialization. Since at this point
7864 * Sun has no system call to read the configuration, the major numbers
7865 * are assumed to be static and types are figured out as such. However,
7866 * as a rough estimate, the buffer size for all types is set to 512
7871 g_init(int *devtype
, int *fdes
)
7875 struct statvfs stfs_buf
;
7877 *devtype
= G_NO_DEV
;
7879 if (fstat(*fdes
, &st_buf
) == -1)
7881 if (!S_ISCHR(st_buf
.st_mode
) && !S_ISBLK(st_buf
.st_mode
)) {
7882 if (S_ISFIFO(st_buf
.st_mode
)) {
7885 /* find block size for this file system */
7887 if (fstatvfs(*fdes
, &stfs_buf
) < 0) {
7891 bufsize
= stfs_buf
.f_bsize
;
7897 * We'll have to add a remote attribute to stat but this
7898 * should work for now.
7900 } else if (st_buf
.st_dev
& 0x8000) /* if remote rdev */
7905 if (Hdr_type
== BAR
) {
7906 if (is_tape(*fdes
)) {
7907 bufsize
= BAR_TAPE_SIZE
;
7908 msg(EPOST
, "Archiving to tape blocking factor 126");
7909 } else if (is_floppy(*fdes
)) {
7910 bufsize
= BAR_FLOPPY_SIZE
;
7911 msg(EPOST
, "Archiving to floppy blocking factor 18");
7919 * This originally came from libgenIO/g_read.c
7923 * g_read: Read nbytes of data from fdes (of type devtype) and place
7924 * data in location pointed to by buf. In case of end of medium,
7925 * translate (where necessary) device specific EOM indications into
7926 * the generic EOM indication of rv = -1, errno = ENOSPC.
7930 g_read(int devtype
, int fdes
, char *buf
, unsigned nbytes
)
7934 if (devtype
< 0 || devtype
>= G_DEV_MAX
) {
7939 rv
= read(fdes
, buf
, nbytes
);
7941 /* st devices return 0 when no space left */
7942 if ((rv
== 0 && errno
== 0 && Hdr_type
!= BAR
) ||
7943 (rv
== -1 && errno
== EIO
)) {
7952 * This originally came from libgenIO/g_write.c
7956 * g_write: Write nbytes of data to fdes (of type devtype) from
7957 * the location pointed to by buf. In case of end of medium,
7958 * translate (where necessary) device specific EOM indications into
7959 * the generic EOM indication of rv = -1, errno = ENOSPC.
7963 g_write(int devtype
, int fdes
, char *buf
, unsigned nbytes
)
7967 if (devtype
< 0 || devtype
>= G_DEV_MAX
) {
7972 rv
= write(fdes
, buf
, nbytes
);
7974 /* st devices return 0 when no more space left */
7975 if ((rv
== 0 && errno
== 0) || (rv
== -1 && errno
== EIO
)) {
7993 * try to do a generic tape ioctl, just to see if
7994 * the thing is in fact a tape drive(er).
7996 if (ioctl(fd
, MTIOCGET
, &stuff
) != -1) {
7997 /* the ioctl succeeded, must have been a tape */
8010 struct fd_char stuff
;
8013 * try to get the floppy drive characteristics, just to see if
8014 * the thing is in fact a floppy drive(er).
8016 if (ioctl(fd
, FDIOGCHAR
, &stuff
) != -1) {
8017 /* the ioctl succeeded, must have been a floppy */
8025 * New functions for ACLs and other security attributes
8029 * The function appends the new security attribute info to the end of
8034 char **secinfo
, /* existing security info */
8035 int *secinfo_len
, /* length of existing security info */
8036 acl_t
*aclp
) /* new attribute data pointer */
8043 /* no need to add */
8048 switch (acl_type(aclp
)) {
8051 attrtext
= acl_totext(aclp
, ACL_APPEND_ID
| ACL_COMPACT_FMT
|
8053 if (attrtext
== NULL
) {
8054 msg(EPOST
, "acltotext failed");
8057 /* header: type + size = 8 */
8058 newattrsize
= 8 + strlen(attrtext
) + 1;
8059 attr
= e_zalloc(E_NORMAL
, newattrsize
);
8061 msg(EPOST
, "can't allocate memory");
8064 attr
->attr_type
= (acl_type(aclp
) == ACLENT_T
) ?
8066 /* acl entry count */
8067 (void) sprintf(attr
->attr_len
, "%06o", acl_cnt(aclp
));
8068 (void) strcpy((char *)&attr
->attr_info
[0], attrtext
);
8072 /* SunFed's case goes here */
8075 msg(EPOST
, "unrecognized attribute type");
8079 /* old security info + new attr header(8) + new attr */
8080 oldsize
= *secinfo_len
;
8081 *secinfo_len
+= newattrsize
;
8082 new_secinfo
= e_zalloc(E_NORMAL
, (uint_t
)*secinfo_len
);
8083 if (new_secinfo
== NULL
) {
8084 msg(EPOST
, "can't allocate memory");
8085 *secinfo_len
-= newattrsize
;
8089 (void) memcpy(new_secinfo
, *secinfo
, oldsize
);
8090 (void) memcpy(new_secinfo
+ oldsize
, attr
, newattrsize
);
8093 *secinfo
= new_secinfo
;
8098 * Append size amount of data from buf to the archive.
8101 write_ancillary(char *buf
, size_t len
, boolean_t padding
)
8109 cnt
= (unsigned)(len
> CPIOBSZ
) ? CPIOBSZ
: len
;
8112 (void) memcpy(Buffr
.b_in_p
, buf
, (unsigned)cnt
);
8113 Buffr
.b_in_p
+= cnt
;
8119 pad
= (Pad_val
+ 1 - (cnt
& Pad_val
)) & Pad_val
;
8122 (void) memset(Buffr
.b_in_p
, 0, pad
);
8123 Buffr
.b_in_p
+= pad
;
8130 remove_dir(char *path
)
8133 struct dirent
*direct
;
8137 #define MSG1 "remove_dir() failed to stat(\"%s\") "
8138 #define MSG2 "remove_dir() failed to remove_dir(\"%s\") "
8139 #define MSG3 "remove_dir() failed to unlink(\"%s\") "
8142 * Open the directory for reading.
8144 if ((name
= opendir(path
)) == NULL
) {
8145 msg(ERRN
, "remove_dir() failed to opendir(\"%s\") ", path
);
8149 if (chdir(path
) == -1) {
8150 msg(ERRN
, "remove_dir() failed to chdir(\"%s\") ", path
);
8155 * Read every directory entry.
8157 while ((direct
= readdir(name
)) != NULL
) {
8159 * Ignore "." and ".." entries.
8161 if (strcmp(direct
->d_name
, ".") == 0 ||
8162 strcmp(direct
->d_name
, "..") == 0)
8165 if (lstat(direct
->d_name
, &sbuf
) == -1) {
8166 msg(ERRN
, MSG1
, direct
->d_name
);
8167 (void) closedir(name
);
8171 if (S_ISDIR(sbuf
.st_mode
)) {
8172 if (remove_dir(direct
->d_name
) == -1) {
8173 msg(ERRN
, MSG2
, direct
->d_name
);
8174 (void) closedir(name
);
8178 if (unlink(direct
->d_name
) == -1) {
8179 msg(ERRN
, MSG3
, direct
->d_name
);
8180 (void) closedir(name
);
8188 * Close the directory we just finished reading.
8190 (void) closedir(name
);
8193 * Change directory to the parent directory...
8195 if (chdir("..") == -1) {
8196 msg(ERRN
, "remove_dir() failed to chdir(\"..\") ");
8201 * ...and finally remove the directory; note we have to
8202 * make a copy since basename is free to modify its input.
8204 path_copy
= e_strdup(E_NORMAL
, path
);
8205 if (path_copy
== NULL
) {
8206 msg(ERRN
, "cannot strdup() the directory pathname ");
8210 if (rmdir(basename(path_copy
)) == -1) {
8212 msg(ERRN
, "remove_dir() failed to rmdir(\"%s\") ", path
);
8224 return (open(".", O_RDONLY
));
8234 #if defined(O_XATTR)
8236 xattrs_out(int (*func
)())
8240 int arc_rwsysattr
= 0;
8247 char *namep
, *savenamep
;
8249 char *attrparent
= Gen
.g_attrparent_p
;
8252 if (attrparent
== NULL
) {
8253 filename
= Gen
.g_nam_p
;
8255 filename
= Gen
.g_attrnam_p
;
8259 * If the underlying file system supports it, then
8260 * archive the extended attributes if -@ was specified,
8261 * and the extended system attributes if -/ was
8264 if (verify_attr_support(filename
, (attrparent
== NULL
), ARC_CREATE
,
8265 &ext_attr
) != ATTR_OK
) {
8269 #if defined(_PC_SATTR_ENABLED)
8272 nvlist_t
*slist
= NULL
;
8275 * Determine if there are non-transient system
8279 if ((filefd
= open(filename
, O_RDONLY
)) == -1) {
8280 if (attrparent
== NULL
) {
8282 "unable to open %s%s%sfile %s",
8283 (attrparent
== NULL
) ? "" :
8284 gettext("attribute "),
8285 (attrparent
== NULL
) ? "" : attrparent
,
8286 (attrparent
== NULL
) ? "" : gettext(" of "),
8287 (attrparent
== NULL
) ? G_p
->g_nam_p
:
8291 if (((slist
= sysattr_list(myname
, filefd
,
8292 filename
)) != NULL
) || (errno
!= 0)) {
8295 if (slist
!= NULL
) {
8296 (void) nvlist_free(slist
);
8299 (void) close(filefd
);
8303 * If we aren't archiving extended system attributes, and we are
8304 * processing an attribute, or if we are archiving extended system
8305 * attributes, and there are are no extended attributes, then there's
8306 * no need to open up the attribute directory of the file unless the
8307 * extended system attributes are not transient (i.e, the system
8308 * attributes are not the default values).
8310 if ((arc_rwsysattr
== 0) && ((attrparent
!= NULL
) ||
8311 (SysAtflag
&& !ext_attr
))) {
8315 #endif /* _PC_SATTR_ENABLED */
8318 * If aclp still exists then free it since it is was set when base
8319 * file was extracted.
8327 Gen
.g_dirfd
= attropen(filename
, ".", O_RDONLY
);
8328 if (Gen
.g_dirfd
== -1) {
8329 msg(ERRN
, "Cannot open attribute directory of file \"%s%s%s\"",
8330 (attrparent
== NULL
) ? "" : gettext("attribute "),
8331 (attrparent
== NULL
) ? "" : attrparent
,
8332 (attrparent
== NULL
) ? "" : gettext(" of "), filename
);
8337 if (attrparent
== NULL
) {
8338 savenamep
= G_p
->g_nam_p
;
8340 savenamep
= G_p
->g_attrfnam_p
;
8343 if ((dirpfd
= dup(Gen
.g_dirfd
)) == -1) {
8344 msg(ERRN
, "Cannot dup(2) attribute directory descriptor");
8348 if ((dirp
= fdopendir(dirpfd
)) == NULL
) {
8349 msg(ERRN
, "Cannot fdopendir(2) directory file descriptor");
8353 if (attrparent
== NULL
) {
8354 Gen
.g_baseparent_fd
= save_cwd();
8357 while ((dp
= readdir(dirp
)) != NULL
) {
8358 if (strcmp(dp
->d_name
, "..") == 0) {
8361 if (verify_attr(dp
->d_name
, attrparent
,
8362 arc_rwsysattr
, &rw_sysattr
) != ATTR_OK
) {
8366 if (strcmp(dp
->d_name
, ".") == 0) {
8372 Gen
.g_rw_sysattr
= rw_sysattr
;
8373 Gen
.g_attrnam_p
= dp
->d_name
;
8375 if (STAT(Gen
.g_dirfd
, Gen
.g_nam_p
, &SrcSt
) == -1) {
8377 "Could not fstatat(2) attribute \"%s\" of"
8378 " file \"%s\"", dp
->d_name
, (attrparent
== NULL
) ?
8379 savenamep
: Gen
.g_attrfnam_p
);
8384 Savedev
= SrcSt
.st_dev
;
8385 OldSt
= convert_to_old_stat(&SrcSt
,
8386 Gen
.g_nam_p
, Gen
.g_attrnam_p
);
8388 if (OldSt
== NULL
) {
8390 "Could not convert to old stat format");
8395 Gen
.g_attrfnam_p
= savenamep
;
8398 * Set up dummy header name
8400 * One piece is written with .hdr, which
8401 * contains the actual xattr hdr or pathing information
8402 * then the name is updated to drop the .hdr off
8403 * and the actual file itself is archived.
8405 slen
= strlen(Gen
.g_attrnam_p
) + strlen(DEVNULL
) +
8406 strlen(XATTRHDR
) + 2; /* add one for '/' */
8407 if ((namep
= e_zalloc(E_NORMAL
, slen
)) == NULL
) {
8408 msg(ERRN
, "Could not calloc memory for attribute name");
8411 (void) snprintf(namep
, slen
, "%s/%s%s",
8412 DEVNULL
, Gen
.g_attrnam_p
, XATTRHDR
);
8413 Gen
.g_nam_p
= namep
;
8415 plen
= strlen(Gen
.g_attrnam_p
) + 1;
8416 if (Gen
.g_attrparent_p
!= NULL
) {
8417 plen
+= strlen(Gen
.g_attrparent_p
) + 1;
8419 if ((apathp
= e_zalloc(E_NORMAL
, plen
)) == NULL
) {
8420 msg(ERRN
, "Could not calloc memory for attribute name");
8423 (void) snprintf(apathp
, plen
, "%s%s%s",
8424 (Gen
.g_attrparent_p
== NULL
) ? "" : Gen
.g_attrparent_p
,
8425 (Gen
.g_attrparent_p
== NULL
) ? "" : "/", Gen
.g_attrnam_p
);
8427 if (Gen
.g_attrpath_p
!= NULL
) {
8428 free(Gen
.g_attrpath_p
);
8430 Gen
.g_attrpath_p
= apathp
;
8433 * Get attribute's ACL info: don't bother allocating space
8434 * if there are only standard permissions, i.e. ACL count < 4
8437 filefd
= openat(Gen
.g_dirfd
, dp
->d_name
, O_RDONLY
);
8440 "Could not open attribute \"%s\" of"
8441 " file \"%s\"", dp
->d_name
, savenamep
);
8445 if (facl_get(filefd
, ACL_NO_TRIVIAL
, &aclp
) != 0) {
8447 "Error with acl() on %s",
8450 (void) close(filefd
);
8456 #if defined(_PC_SATTR_ENABLED)
8458 * Recursively call xattrs_out() to process the attribute's
8459 * hidden attribute directory and read-write system attributes.
8461 if (SysAtflag
&& !Hiddendir
&& !rw_sysattr
) {
8462 int savedirfd
= Gen
.g_dirfd
;
8464 (void) fchdir(Gen
.g_dirfd
);
8465 Gen
.g_attrparent_p
= dp
->d_name
;
8467 Gen
.g_dirfd
= savedirfd
;
8468 Gen
.g_attrparent_p
= NULL
;
8470 #endif /* _PC_SATTR_ENABLED */
8472 if (Gen
.g_passdirfd
!= -1) {
8473 (void) close(Gen
.g_passdirfd
);
8474 Gen
.g_passdirfd
= -1;
8476 Gen
.g_attrnam_p
= NULL
;
8477 Gen
.g_attrfnam_p
= NULL
;
8478 Gen
.g_linktoattrfnam_p
= NULL
;
8479 Gen
.g_linktoattrnam_p
= NULL
;
8480 Gen
.g_rw_sysattr
= 0;
8481 if (Gen
.g_attrpath_p
!= NULL
) {
8482 free(Gen
.g_attrpath_p
);
8483 Gen
.g_attrpath_p
= NULL
;
8494 (void) closedir(dirp
);
8495 (void) close(Gen
.g_dirfd
);
8496 if (attrparent
== NULL
) {
8497 rest_cwd(Gen
.g_baseparent_fd
);
8504 xattrs_out(int (*func
)())
8510 * Return the parent directory of a given path.
8513 * /usr/tmp return /usr
8514 * /usr/tmp/file return /usr/tmp
8519 * dir is assumed to be at least as big as path.
8522 get_parent(char *path
, char *dir
)
8525 char tmpdir
[PATH_MAX
+ 1];
8527 if (strlen(path
) > PATH_MAX
) {
8528 msg(EXT
, "pathname is too long");
8530 (void) strcpy(tmpdir
, path
);
8531 chop_endslashes(tmpdir
);
8533 if ((s
= strrchr(tmpdir
, '/')) == NULL
) {
8534 (void) strcpy(dir
, ".");
8536 s
= skipslashes(s
, tmpdir
);
8539 (void) strcpy(dir
, "/");
8541 (void) strcpy(dir
, tmpdir
);
8545 #if defined(O_XATTR)
8546 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
8554 struct Lnk
*linkinfo
,
8557 char *bufhead
; /* ptr to full buffer */
8559 struct xattr_hdr
*hptr
; /* ptr to header in bufhead */
8560 struct xattr_buf
*tptr
; /* ptr to pathing pieces */
8561 int totalen
; /* total buffer length */
8562 int len
; /* length returned to user */
8563 int stringlen
; /* length of filename + attr */
8565 * length of filename + attr
8569 int complen
; /* length of pathing section */
8570 int linklen
; /* length of link section */
8571 int attrnames_index
; /* attrnames starting index */
8574 * Release previous buffer if any.
8577 if (*attrbuf
!= NULL
) {
8583 * First add in fixed size stuff
8585 len
= sizeof (struct xattr_hdr
) + sizeof (struct xattr_buf
);
8588 * Add space for two nulls
8590 stringlen
= strlen(attrpath
) + strlen(filename
) + 2;
8591 complen
= stringlen
+ sizeof (struct xattr_buf
);
8596 * Now add on space for link info if any
8599 if (linkinfo
!= NULL
) {
8601 * Again add space for two nulls
8603 linkstringlen
= strlen(linkinfo
->L_gen
.g_attrfnam_p
) +
8604 strlen(linkinfo
->L_gen
.g_attrnam_p
) + 2;
8605 linklen
= linkstringlen
+ sizeof (struct xattr_buf
);
8612 * Now add padding to end to fill out TBLOCK
8614 * Function returns size of real data and not size + padding.
8617 totalen
= ROUNDTOTBLOCK(len
);
8618 bufhead
= e_zalloc(E_EXIT
, totalen
);
8621 * Now we can fill in the necessary pieces
8625 * first fill in the fixed header
8627 hptr
= (struct xattr_hdr
*)bufhead
;
8628 (void) strcpy(hptr
->h_version
, XATTR_ARCH_VERS
);
8629 (void) sprintf(hptr
->h_component_len
, "%0*d",
8630 sizeof (hptr
->h_component_len
) - 1, complen
);
8631 (void) sprintf(hptr
->h_link_component_len
, "%0*d",
8632 sizeof (hptr
->h_link_component_len
) - 1, linklen
);
8633 (void) sprintf(hptr
->h_size
, "%0*d", sizeof (hptr
->h_size
) - 1, len
);
8636 * Now fill in the filename + attrnames section
8637 * The filename and attrnames section can be composed of two or more
8638 * path segments separated by a null character. The first segment
8639 * is the path to the parent file that roots the entire sequence in
8640 * the normal name space. The remaining segments describes a path
8641 * rooted at the hidden extended attribute directory of the leaf file of
8642 * the previous segment, making it possible to name attributes on
8643 * attributes. Thus, if we are just archiving an extended attribute,
8644 * the second segment will contain the attribute name. If we are
8645 * archiving a system attribute of an extended attribute, then the
8646 * second segment will contain the attribute name, and a third segment
8647 * will contain the system attribute name. The attribute pathing
8648 * information is obtained from 'attrpath'.
8651 tptr
= (struct xattr_buf
*)(bufhead
+ sizeof (struct xattr_hdr
));
8652 (void) sprintf(tptr
->h_namesz
, "%0*d", sizeof (tptr
->h_namesz
) - 1,
8654 (void) strcpy(tptr
->h_names
, filename
);
8655 attrnames_index
= strlen(filename
) + 1;
8656 (void) strcpy(&tptr
->h_names
[attrnames_index
], attrpath
);
8657 tptr
->h_typeflag
= typeflag
;
8660 * Split the attrnames section into two segments if 'attrpath'
8661 * contains pathing information for a system attribute of an
8662 * extended attribute. We split them by replacing the '/' with
8665 if ((aptr
= strpbrk(&tptr
->h_names
[attrnames_index
], "/")) != NULL
) {
8670 * Now fill in the optional link section if we have one
8673 if (linkinfo
!= NULL
) {
8674 tptr
= (struct xattr_buf
*)(bufhead
+
8675 sizeof (struct xattr_hdr
) + complen
);
8677 (void) sprintf(tptr
->h_namesz
, "%0*d",
8678 sizeof (tptr
->h_namesz
) - 1, linkstringlen
);
8679 (void) strcpy(tptr
->h_names
, linkinfo
->L_gen
.g_attrfnam_p
);
8681 &tptr
->h_names
[strlen(linkinfo
->L_gen
.g_attrfnam_p
) + 1],
8682 linkinfo
->L_gen
.g_attrnam_p
);
8683 tptr
->h_typeflag
= typeflag
;
8685 *attrbuf
= (char *)bufhead
;
8688 #endif /* O_XATTR */
8718 #if defined(O_XATTR)
8722 if (G_p
->g_attrnam_p
!= NULL
) {
8723 return (openat(G_p
->g_dirfd
, G_p
->g_attrnam_p
, omode
));
8725 return (openat(G_p
->g_dirfd
,
8726 get_component(G_p
->g_nam_p
), omode
));
8733 return (openat(G_p
->g_dirfd
, get_component(G_p
->g_nam_p
), omode
));
8737 #if defined(O_XATTR)
8742 int comp_len
, link_len
;
8752 * Include any padding in the read. We need to be positioned
8753 * at beginning of next header.
8756 bytes
= Gen
.g_filesz
;
8758 if ((xattrhead
= e_zalloc(E_NORMAL
, (size_t)bytes
)) == NULL
) {
8759 (void) fprintf(stderr
, gettext(
8760 "Insufficient memory for extended attribute\n"));
8764 tp
= (char *)xattrhead
;
8766 cnt
= (int)(bytes
> CPIOBSZ
) ? CPIOBSZ
: bytes
;
8768 (void) memcpy(tp
, Buffr
.b_out_p
, cnt
);
8770 Buffr
.b_out_p
+= cnt
;
8771 Buffr
.b_cnt
-= (off_t
)cnt
;
8772 bytes
-= (off_t
)cnt
;
8775 pad
= (Pad_val
+ 1 - (Gen
.g_filesz
& Pad_val
)) &
8779 Buffr
.b_out_p
+= pad
;
8780 Buffr
.b_cnt
-= (off_t
)pad
;
8784 * Validate that we can handle header format
8787 if (strcmp(xattrhead
->h_version
, XATTR_ARCH_VERS
) != 0) {
8788 (void) fprintf(stderr
,
8789 gettext("Unknown extended attribute format encountered\n"));
8790 (void) fprintf(stderr
,
8791 gettext("Disabling extended attribute header parsing\n"));
8795 (void) sscanf(xattrhead
->h_component_len
, "%10d", &comp_len
);
8796 (void) sscanf(xattrhead
->h_link_component_len
, "%10d", &link_len
);
8797 xattrp
= (struct xattr_buf
*)(((char *)xattrhead
) +
8798 sizeof (struct xattr_hdr
));
8799 (void) sscanf(xattrp
->h_namesz
, "%7d", &namelen
);
8801 xattr_linkp
= (struct xattr_buf
*)((int)xattrp
+ (int)comp_len
);
8807 * Gather the attribute path from the filename and attrnames section.
8808 * The filename and attrnames section can be composed of two or more
8809 * path segments separated by a null character. The first segment
8810 * is the path to the parent file that roots the entire sequence in
8811 * the normal name space. The remaining segments describes a path
8812 * rooted at the hidden extended attribute directory of the leaf file of
8813 * the previous segment, making it possible to name attributes on
8816 parentfilelen
= strlen(xattrp
->h_names
);
8817 xattrapath
= xattrp
->h_names
+ parentfilelen
+ 1;
8818 asz
= strlen(xattrapath
);
8819 if ((asz
+ parentfilelen
+ 2) < namelen
) {
8821 * The attrnames section contains a system attribute on an
8822 * attribute. Save the name of the attribute for use later,
8823 * and replace the null separating the attribute name from
8824 * the system attribute name with a '/' so that xattrapath can
8825 * be used to display messages with the full attribute path name
8826 * rooted at the hidden attribute directory of the base file
8827 * in normal name space.
8829 xattrapath
[asz
] = '/';
8872 #if defined(O_XATTR)
8874 get_component(char *path
)
8878 ptr
= strrchr(path
, '/');
8883 * Handle trailing slash
8885 if (*(ptr
+ 1) == '\0')
8893 get_component(char *path
)
8900 open_dir(char *name
)
8906 dir
= e_zalloc(E_EXIT
, strlen(name
) + 1);
8909 * open directory; creating missing directories along the way.
8911 get_parent(name
, dir
);
8913 fd
= open(dir
, O_RDONLY
);
8919 } while (cnt
<= 1 && missdir(name
) == 0);
8929 if ((Args
& OCt
) == 0) {
8931 if (G_p
->g_attrnam_p
!= NULL
) {
8935 * Open the file's attribute directory.
8936 * Change into the base file's starting directory then
8937 * call open_attr_dir() to open the attribute directory
8938 * of either the base file (if G_p->g_attrparent_p is
8939 * NULL) or the attribute (if G_p->g_attrparent_p is
8940 * set) of the base file.
8942 (void) fchdir(G_p
->g_baseparent_fd
);
8943 (void) open_attr_dir(G_p
->g_attrnam_p
,
8944 G_p
->g_attrfnam_p
, G_p
->g_baseparent_fd
,
8945 (G_p
->g_attrparent_p
== NULL
) ? NULL
:
8946 G_p
->g_attrparent_p
, &G_p
->g_dirfd
, &rw_sysattr
);
8948 int saveerrno
= errno
;
8950 (void) fchdir(G_p
->g_baseparent_fd
);
8953 if ((G_p
->g_dirfd
== -1) && (Args
& (OCi
| OCp
))) {
8955 "Cannot open attribute directory "
8956 "of %s%s%sfile \"%s\"",
8957 (G_p
->g_attrparent_p
== NULL
) ? "" :
8958 gettext("attribute \""),
8959 (G_p
->g_attrparent_p
== NULL
) ? "" :
8960 G_p
->g_attrparent_p
,
8961 (G_p
->g_attrparent_p
== NULL
) ? "" :
8964 return (FILE_PASS_ERR
);
8967 G_p
->g_dirfd
= open_dir(G_p
->g_nam_p
);
8968 if (G_p
->g_dirfd
== -1) {
8970 "Cannot open/create %s", G_p
->g_nam_p
);
8986 if (G_p
->g_dirfd
!= -1) {
8987 (void) close(G_p
->g_dirfd
);
8995 char *attrbuf
= NULL
;
8998 struct Lnk
*tl_p
, *linkinfo
;
9001 * namep was allocated in xattrs_out. It is big enough to hold
9002 * either the name + .hdr on the end or just the attr name
9005 #if defined(O_XATTR)
9006 namep
= Gen
.g_nam_p
;
9011 tl_p
= Lnk_hd
.L_nxt_p
;
9012 while (tl_p
!= &Lnk_hd
) {
9013 if (tl_p
->L_gen
.g_ino
== G_p
->g_ino
&&
9014 tl_p
->L_gen
.g_dev
== G_p
->g_dev
) {
9018 tl_p
= tl_p
->L_nxt_p
;
9020 prepare_xattr_hdr(&attrbuf
, Gen
.g_attrfnam_p
,
9022 (linkinfo
== NULL
) ?
9023 tartype(Gen
.g_mode
& Ftype
) : LNKTYPE
,
9024 linkinfo
, &attrlen
);
9025 Gen
.g_filesz
= attrlen
;
9026 write_hdr(ARCHIVE_XATTR
, (off_t
)attrlen
);
9028 (void) sprintf(namep
, "%s/%s", DEVNULL
, Gen
.g_attrnam_p
);
9029 write_ancillary(attrbuf
, attrlen
, B_TRUE
);
9037 * skip over extra slashes in string.
9042 * would return pointer at
9047 skipslashes(char *string
, char *start
)
9049 while ((string
> start
) && *(string
- 1) == '/') {
9059 static int num_left
;
9060 static sl_info_t
*slipool
;
9063 return (&slipool
[--num_left
]);
9065 num_left
= SL_INFO_ALLOC_CHUNK
;
9066 slipool
= e_zalloc(E_EXIT
, sizeof (sl_info_t
) * num_left
);
9067 return (&slipool
[--num_left
]);
9071 * If a match for the key values was found in the tree, return a pointer to it.
9072 * If a match was not found, insert it and return a pointer to it. This is
9073 * based on Knuth's Algorithm A in Vol 3, section 6.2.3.
9077 sl_insert(dev_t device
, ino_t inode
, int ftype
)
9079 sl_info_t
*p
; /* moves down the tree */
9080 sl_info_t
*q
; /* scratch */
9081 sl_info_t
*r
; /* scratch */
9082 sl_info_t
*s
; /* pt where rebalancing may be needed */
9083 sl_info_t
*t
; /* father of s */
9086 int a
; /* used to hold balance factors */
9087 int done
; /* loop control */
9088 int cmpflg
; /* used to hold the result of a comparison */
9092 head
= sl_devhash_lookup(device
);
9095 head
= sl_info_alloc();
9099 p
= head
->rlink
= sl_info_alloc();
9101 p
->sl_ftype
= ftype
;
9106 sl_devhash_insert(device
, head
);
9111 s
= p
= head
->rlink
;
9115 for (done
= 0; ! done
; ) {
9116 switch (sl_compare(inode
, ftype
, p
->sl_ino
, p
->sl_ftype
)) {
9123 q
= sl_info_alloc();
9141 q
= sl_info_alloc();
9161 q
->sl_ftype
= ftype
;
9163 q
->llink
= q
->rlink
= NULL
;
9166 /* adjust balance factors */
9168 if ((cmpflg
= sl_compare(inode
, ftype
, s
->sl_ino
, s
->sl_ftype
)) < 0) {
9175 switch (sl_compare(inode
, ftype
, p
->sl_ino
, p
->sl_ftype
)) {
9201 head
->llink
= (sl_info_t
*)((int)head
->llink
+ 1);
9203 } else if (s
->bal
== -a
) {
9213 /* single rotation */
9218 s
->llink
= r
->rlink
;
9220 } else if (a
== 1) {
9221 s
->rlink
= r
->llink
;
9225 s
->bal
= r
->bal
= 0;
9227 } else if (r
->bal
== -a
) {
9228 /* double rotation */
9232 r
->rlink
= p
->llink
;
9234 s
->llink
= p
->rlink
;
9236 } else if (a
== 1) {
9238 r
->llink
= p
->rlink
;
9240 s
->rlink
= p
->llink
;
9247 } else if (p
->bal
== -a
) {
9250 } else if (p
->bal
== a
) {
9258 /* finishing touch */
9260 if (s
== t
->rlink
) {
9270 * sl_numlinks: return the number of links that we saw during our preview.
9274 sl_numlinks(dev_t device
, ino_t inode
, int ftype
)
9276 sl_info_t
*p
= sl_search(device
, inode
, ftype
);
9279 return (p
->sl_count
);
9286 * Preview extended and extended system attributes.
9288 * Return 0 if successful, otherwise return 1.
9290 #if defined(O_XATTR)
9292 preview_attrs(char *s
, char *attrparent
)
9294 char *filename
= (attrparent
== NULL
) ? s
: attrparent
;
9299 int arc_rwsysattr
= 0;
9307 * If the underlying file system supports it, then
9308 * archive the extended attributes if -@ was specified,
9309 * and the extended system attributes if -/ was
9312 if (verify_attr_support(filename
, (attrparent
== NULL
), ARC_CREATE
,
9313 &ext_attr
) != ATTR_OK
) {
9317 #if defined(_PC_SATTR_ENABLED)
9320 nvlist_t
*slist
= NULL
;
9322 /* Determine if there are non-transient system attributes. */
9324 if ((filefd
= open(filename
, O_RDONLY
)) < 0) {
9327 if (((slist
= sysattr_list(myname
, filefd
,
9328 filename
)) != NULL
) || (errno
!= 0)) {
9331 if (slist
!= NULL
) {
9332 (void) nvlist_free(slist
);
9335 (void) close(filefd
);
9338 if ((arc_rwsysattr
== 0) && ((attrparent
!= NULL
) ||
9339 (SysAtflag
&& !ext_attr
))) {
9342 #endif /* _PC_SATTR_ENABLED */
9344 * We need to open the attribute directory of the
9345 * file, and preview all of the file's attributes as
9346 * attributes of the file can be hard links to other
9347 * attributes of the file.
9349 dirfd
= attropen(filename
, ".", O_RDONLY
);
9355 (void) close(dirfd
);
9358 dirp
= fdopendir(tmpfd
);
9360 (void) close(dirfd
);
9361 (void) close(tmpfd
);
9365 while (dp
= readdir(dirp
)) {
9366 if (dp
->d_name
[0] == '.') {
9367 if (dp
->d_name
[1] == '\0') {
9369 } else if ((dp
->d_name
[1] == '.') &&
9370 (dp
->d_name
[2] == '\0')) {
9379 if (fstatat(dirfd
, dp
->d_name
, &sb
,
9380 AT_SYMLINK_NOFOLLOW
) < 0) {
9384 if (verify_attr(dp
->d_name
, attrparent
,
9385 arc_rwsysattr
, &rw_sysattr
) != ATTR_OK
) {
9390 if (S_ISLNK(sb
.st_mode
)) {
9393 if (fstatat(dirfd
, dp
->d_name
,
9399 sl_remember_tgt(&sb
, islnk
, rw_sysattr
);
9402 * Recursively call preview_attrs() to preview extended
9403 * system attributes of attributes.
9405 if (SysAtflag
&& !Hiddendir
&& !rw_sysattr
) {
9406 int my_cwd
= save_cwd();
9408 (void) fchdir(dirfd
);
9409 rc
= preview_attrs(s
, dp
->d_name
);
9413 (void) closedir(dirp
);
9414 (void) close(dirfd
);
9417 #endif /* O_XATTR */
9420 * sl_preview_synonyms: Read the file list from the input stream, remembering
9421 * each reference to each file.
9425 sl_preview_synonyms(void)
9430 char *suffix
= "/cpioXXXXXX";
9431 char *tmpdir
= getenv("TMPDIR");
9436 if (tmpdir
== NULL
|| *tmpdir
== '\0' ||
9437 (strlen(tmpdir
) + strlen(suffix
)) > APATH
) {
9438 struct statvfs tdsb
;
9440 tmpdir
= "/var/tmp";
9442 /* /var/tmp is read-only in the mini-root environment */
9444 if (statvfs(tmpdir
, &tdsb
) == -1 || tdsb
.f_flag
& ST_RDONLY
) {
9449 tmpfname
= e_zalloc(E_EXIT
, strlen(tmpdir
) + strlen(suffix
) + 1);
9451 (void) strcpy(tmpfname
, tmpdir
);
9452 (void) strcat(tmpfname
, suffix
);
9454 if ((tmpfd
= mkstemp(tmpfname
)) == -1) {
9455 msg(EXTN
, "cannot open tmpfile %s%s", tmpdir
, suffix
);
9458 if (unlink(tmpfname
) == -1) {
9459 msg(EXTN
, "cannot unlink tmpfile %s", tmpfname
);
9462 if ((tmpfile
= fdopen(tmpfd
, "w+")) == NULL
) {
9463 msg(EXTN
, "cannot fdopen tmpfile %s", tmpfname
);
9466 while ((s
= fgets(buf
, APATH
+1, In_p
)) != NULL
) {
9470 if (fputs(buf
, tmpfile
) == EOF
) {
9471 msg(EXTN
, "problem writing to tmpfile %s", tmpfname
);
9474 /* pre-process the name */
9476 lastchar
= strlen(s
) - 1;
9478 if (s
[lastchar
] != '\n' && lastchar
== APATH
- 1) {
9484 while (s
[0] == '.' && s
[1] == '/') {
9486 while (s
[0] == '/') {
9491 if (lstat(s
, &sb
) < 0) {
9495 if (S_ISLNK(sb
.st_mode
)) {
9498 if (stat(s
, &sb
) < 0) {
9503 sl_remember_tgt(&sb
, islnk
, 0);
9505 #if defined(O_XATTR)
9506 if (Atflag
|| SysAtflag
) {
9507 (void) preview_attrs(s
, NULL
);
9509 #endif /* O_XATTR */
9513 msg(EXTN
, "error reading stdin");
9516 if (fseek(tmpfile
, 0L, SEEK_SET
) == -1) {
9517 msg(EXTN
, "cannot fseek on tmpfile %s", tmpfname
);
9525 * sl_remember_tgt: Add the device/inode for lstat or stat info to the list of
9526 * those we've seen before.
9528 * This tree (rooted under head) is keyed by the device/inode of the file
9529 * being pointed to. A count is kept of the number of references encountered
9534 sl_remember_tgt(const struct stat
*sbp
, int isSymlink
, int is_sysattr
)
9541 device
= sbp
->st_dev
;
9542 inode
= sbp
->st_ino
;
9543 ftype
= sbp
->st_mode
& Ftype
;
9545 /* Determine whether we've seen this one before */
9547 p
= sl_insert(device
, inode
, ftype
);
9549 if (p
->sl_count
> 0) {
9551 * It appears as if have seen this file before as we found a
9552 * matching device, inode, and file type as a file already
9553 * processed. Since there can possibly be files with the
9554 * same device, inode, and file type, but aren't hard links
9555 * (e.g., read-write system attribute files will always have
9556 * the same inode), we need to only attempt to add one to the
9557 * link count if the file we are processing is a hard link
9558 * (i.e., st_nlink > 1).
9560 * Note that if we are not chasing symlinks, and this one is a
9561 * symlink, it is identically the one we saw before (you cannot
9562 * have hard links to symlinks); in this case, we leave the
9563 * count alone, so that we don't wind up archiving a symlink to
9567 if (((Args
& OCL
) || (! isSymlink
)) && !is_sysattr
) {
9571 /* We have not seen this file before */
9576 /* -Hodc: remap inode (-1 on overflow) */
9580 for (q
= sl_remap_head
; q
&& (q
->dev
!= device
);
9586 q
= e_zalloc(E_EXIT
, sizeof (sl_remap_t
));
9588 p
->sl_ino2
= q
->inode_count
= 1;
9590 q
->next
= (sl_remap_head
) ?
9591 sl_remap_head
->next
: NULL
;
9594 if ((size_t)q
->inode_count
<=
9595 ((1 << (sizeof (o_ino_t
) * 8)) - 1)) {
9596 /* fits in o_ino_t */
9597 p
->sl_ino2
= ++(q
->inode_count
);
9599 p
->sl_ino2
= (ino_t
)-1;
9607 * A faster search, which does not insert the key values into the tree.
9608 * If the a match was found in the tree, return a pointer to it. If it was not
9609 * found, return NULL.
9613 sl_search(dev_t device
, ino_t inode
, int ftype
)
9615 sl_info_t
*p
; /* moves down the tree */
9616 int c
; /* comparison value */
9617 sl_info_t
*retval
= NULL
; /* return value */
9620 head
= sl_devhash_lookup(device
);
9622 for (p
= head
->rlink
; p
; ) {
9623 if ((c
= sl_compare(inode
, ftype
, p
->sl_ino
,
9624 p
->sl_ftype
)) == 0) {
9639 sl_devhash_lookup(dev_t device
)
9643 static sl_info_link_t
*devcache
;
9645 if (devcache
!= NULL
&& devcache
->dev
== device
) {
9646 return (devcache
->head
);
9649 key
= DEV_HASHKEY(device
);
9650 for (lp
= sl_devhash
[key
]; lp
; lp
= lp
->next
) {
9651 if (lp
->dev
== device
) {
9660 sl_devhash_insert(dev_t device
, sl_info_t
*head
)
9662 int key
= DEV_HASHKEY(device
);
9665 lp
= e_zalloc(E_EXIT
, sizeof (sl_info_link_t
));
9668 lp
->next
= sl_devhash
[key
];
9669 sl_devhash
[key
] = lp
;
9673 chop_endslashes(char *path
)
9677 end
= &path
[strlen(path
) -1];
9678 if (*end
== '/' && end
!= path
) {
9679 ptr
= skipslashes(end
, path
);
9680 if (ptr
!= NULL
&& ptr
!= path
) {
9686 #if !defined(O_XATTR)
9688 openat64(int fd
, char *name
, int oflag
, mode_t cmode
)
9690 return (open64(name
, oflag
, cmode
));
9694 openat(int fd
, char *name
, int oflag
, mode_t cmode
)
9696 return (open(name
, oflag
, cmode
));
9700 fchownat(int fd
, char *name
, uid_t owner
, gid_t group
, int flag
)
9702 if (flag
== AT_SYMLINK_NOFOLLOW
)
9703 return (lchown(name
, owner
, group
));
9705 return (chown(name
, owner
, group
));
9709 renameat(int fromfd
, char *old
, int tofd
, char *new)
9711 return (rename(old
, new));
9715 futimesat(int fd
, char *path
, struct timeval times
[2])
9717 return (utimes(path
, times
));
9721 unlinkat(int dirfd
, char *path
, int flag
)
9723 if (flag
== AT_REMOVEDIR
) {
9724 return (rmdir(path
));
9726 return (unlink(path
));
9731 fstatat(int fd
, char *path
, struct stat
*buf
, int flag
)
9733 if (flag
== AT_SYMLINK_NOFOLLOW
)
9734 return (lstat(path
, buf
));
9736 return (stat(path
, buf
));
9740 attropen(char *file
, char *attr
, int omode
, mode_t cmode
)