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
= stdin
; /* 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
= stderr
, /* File pointer for error reporting */
505 *Out_p
= stdout
, /* 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
)
704 (void) setlocale(LC_ALL
, "");
705 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
706 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
708 (void) textdomain(TEXT_DOMAIN
);
710 (void) memset(&Gen
, 0, sizeof (Gen
));
711 myname
= e_strdup(E_EXIT
, basename(argv
[0]));
714 if (signal(SIGINT
, sigint
) == SIG_IGN
)
715 (void) signal(SIGINT
, SIG_IGN
);
716 switch (Args
& (OCi
| OCo
| OCp
)) {
717 case OCi
: /* COPY IN */
719 if (Atflag
|| SysAtflag
) {
721 * Save the current working directory, so
722 * we can change back here after cd'ing into
723 * the attribute directory when processing
726 if ((attr_baseparent_fd
= save_cwd()) < 0) {
727 msg(EXT
, "Unable to open current directory.");
730 while ((i
= gethdr()) != 0) {
735 * Any ACL info for this file would or should
736 * have been used after file_in(); clear out
737 * aclp so it is is not erroneously used on
746 (void) memset(&Gen
, 0, sizeof (Gen
));
748 /* Do not count "extra" "read-ahead" buffered data */
749 if (Buffr
.b_cnt
> Bufsize
)
750 Blocks
-= (u_longlong_t
)(Buffr
.b_cnt
/ Bufsize
);
752 case OCo
: /* COPY OUT */
758 Gen
.g_dirpath
= NULL
;
759 sl_preview_synonyms();
761 while ((i
= getname()) != 0) {
764 if (Atflag
|| SysAtflag
) {
765 if (Gen
.g_dirfd
!= -1) {
766 (void) close(Gen
.g_dirfd
);
769 xattrs_out(file_out
);
781 sl_preview_synonyms();
784 Gen
.g_passdirfd
= -1;
785 Gen
.g_dirpath
= NULL
;
789 * If file is a fully qualified path then
790 * file_pass will strip off the leading '/'
791 * and we need to save off the unstripped
792 * name for attribute traversal.
794 if (Atflag
|| SysAtflag
) {
795 (void) strcpy(Savenam_p
, Gen
.g_nam_p
);
797 passret
= file_pass();
803 if (Gen
.g_passdirfd
!= -1)
804 (void) close(Gen
.g_passdirfd
);
805 Gen
.g_passdirfd
= -1;
806 if (Atflag
|| SysAtflag
) {
807 if (Gen
.g_dirfd
!= -1) {
808 (void) close(Gen
.g_dirfd
);
811 if (passret
!= FILE_LINKED
) {
812 Gen
.g_nam_p
= Savenam_p
;
813 xattrs_out(file_pass
);
819 msg(EXT
, "Impossible action.");
822 if (close(Ofile
) != 0)
823 msg(EXTN
, "close error");
826 if (close(Archive
) != 0)
827 msg(EXTN
, "close error");
829 if ((Args
& OCq
) == 0) {
830 Blocks
= (u_longlong_t
)(Blocks
* Bufsize
+ SBlocks
+
832 msg(EPOST
, "%lld blocks", Blocks
);
835 msg(EPOST
, "%d error(s)", Error_cnt
);
840 * add_lnk: Add a linked file's header to the linked file data structure, by
841 * either adding it to the end of an existing sub-list or starting
842 * a new sub-list. Each sub-list saves the links to a given file.
844 * Directly returns a pointer to the new entry; returns a pointer to the head
845 * of the sub-list in which that entry is located through the argument.
849 add_lnk(struct Lnk
**sublist_return
)
851 struct Lnk
*new_entry
, *sublist
;
853 for (sublist
= Lnk_hd
.L_nxt_p
;
855 sublist
= sublist
->L_nxt_p
) {
856 if (sublist
->L_gen
.g_ino
== G_p
->g_ino
&&
857 sublist
->L_gen
.g_dev
== G_p
->g_dev
) {
863 new_entry
= e_zalloc(E_EXIT
, sizeof (struct Lnk
));
865 new_entry
->L_lnk_p
= NULL
;
866 new_entry
->L_gen
= *G_p
; /* structure copy */
868 new_entry
->L_gen
.g_nam_p
= e_zalloc(E_EXIT
, (size_t)G_p
->g_namesz
);
870 (void) strcpy(new_entry
->L_gen
.g_nam_p
, G_p
->g_nam_p
);
872 if (sublist
== &Lnk_hd
) {
873 /* start new sub-list */
874 new_entry
->L_nxt_p
= &Lnk_hd
;
875 new_entry
->L_bck_p
= Lnk_hd
.L_bck_p
;
876 Lnk_hd
.L_bck_p
= new_entry
->L_bck_p
->L_nxt_p
= new_entry
;
877 new_entry
->L_lnk_p
= NULL
;
878 new_entry
->L_cnt
= 1;
879 new_entry
->L_data
= Onecopy
? 0 : 1;
882 /* add to existing sub-list */
888 ptr
->L_lnk_p
!= NULL
;
889 ptr
= ptr
->L_lnk_p
) {
890 ptr
->L_gen
.g_filesz
= G_p
->g_filesz
;
893 ptr
->L_gen
.g_filesz
= G_p
->g_filesz
;
894 ptr
->L_lnk_p
= new_entry
;
897 *sublist_return
= sublist
;
902 * bfill: Read req_cnt bytes (out of filelen bytes) from the I/O buffer,
903 * moving them to rd_buf_p. When there are no bytes left in the I/O buffer,
904 * Fillbuf is set and the I/O buffer is filled. The variable dist is the
905 * distance to lseek if an I/O error is encountered with the -k option set
906 * (converted to a multiple of Bufsize).
916 while ((Buffr
.b_end_p
- Buffr
.b_in_p
) >= Bufsize
) {
918 if ((rv
= g_read(Device
, Archive
, Buffr
.b_in_p
, Bufsize
)) < 0) {
919 if (((Buffr
.b_end_p
- Buffr
.b_in_p
) >= Bufsize
) &&
924 if (errno
== ENOSPC
) {
925 (void) chgreel(INPUT
);
926 if (Hdr_type
== BAR
) {
930 } else if (Args
& OCk
) {
932 msg(EXT
, "Cannot recover.");
933 if (lseek(Archive
, Bufsize
, SEEK_REL
) < 0)
934 msg(EXTN
, "Cannot lseek()");
941 } /* (rv = g_read(Device, Archive ... */
942 if (Hdr_type
!= BAR
|| rv
== Bufsize
) {
944 Buffr
.b_cnt
+= (long)rv
;
949 } else if (rv
== 0) {
954 (void) chgreel(INPUT
);
955 eof
= 0; /* reset the eof after chgreel */
958 * if spans multiple volume, skip the volume header of
959 * the next volume so that the file currently being
960 * extracted can continue to be extracted.
962 if (Hdr_type
== BAR
) {
969 SBlocks
+= (u_longlong_t
)rv
;
971 } /* (Buffr.b_end_p - Buffr.b_in_p) <= Bufsize */
975 if ((rv
= g_read(Device
, Archive
, Buffr
.b_in_p
, Bufsize
)) < 0) {
977 } /* (rv = g_read(Device, Archive ... */
979 Buffr
.b_cnt
+= (long)rv
;
991 SBlocks
+= (u_longlong_t
)rv
;
998 * bflush: Move wr_cnt bytes from data_p into the I/O buffer. When the
999 * I/O buffer is full, Flushbuf is set and the buffer is written out.
1007 while (Buffr
.b_cnt
>= Bufsize
) {
1009 if ((rv
= g_write(Device
, Archive
, Buffr
.b_out_p
,
1011 if (errno
== ENOSPC
&& !Dflag
)
1012 rv
= chgreel(OUTPUT
);
1016 Buffr
.b_out_p
+= rv
;
1017 Buffr
.b_cnt
-= (long)rv
;
1021 SBlocks
+= (u_longlong_t
)rv
;
1027 * chgreel: Determine if end-of-medium has been reached. If it has,
1028 * close the current medium and prompt the user for the next medium.
1034 int lastchar
, tryagain
, askagain
, rv
;
1040 if (fstat(Archive
, &statb
) < 0)
1041 msg(EXTN
, "Error during stat() of archive");
1042 if ((statb
.st_mode
& S_IFMT
) != S_IFCHR
) {
1045 "Can't read input: end of file encountered ",
1046 "prior to expected end of archive.");
1049 msg(EPOST
, "\007End of medium on \"%s\".", dir
? "output" : "input");
1050 if (is_floppy(Archive
))
1051 (void) ioctl(Archive
, FDEJECT
, NULL
);
1052 if ((close(Archive
) != 0) && (dir
== OUTPUT
))
1053 msg(EXTN
, "close error");
1058 Rtty_p
= fopen(Ttyname
, "r");
1062 msg(EPOST
, Eom_p
, Volcnt
);
1063 if (!Rtty_p
|| fgets(str
, sizeof (str
),
1065 msg(EXT
, "Cannot read tty.");
1069 (void) strcpy(str
, IOfil_p
);
1079 if (Hdr_type
== BAR
)
1083 "To continue, type device/file name when "
1085 if (!Rtty_p
|| fgets(str
, sizeof (str
),
1087 msg(EXT
, "Cannot read tty.");
1088 lastchar
= strlen(str
) - 1;
1089 if (*(str
+ lastchar
) == '\n') /* remove '\n' */
1090 *(str
+ lastchar
) = '\0';
1095 if ((Archive
= open(str
, dir
)) < 0) {
1096 msg(ERRN
, "Cannot open \"%s\"", str
);
1100 (void) g_init(&tmpdev
, &Archive
);
1101 if (tmpdev
!= Device
)
1102 msg(EXT
, "Cannot change media types in mid-stream.");
1105 else { /* dir == OUTPUT */
1107 if ((rv
= g_write(Device
, Archive
, Buffr
.b_out_p
,
1108 Bufsize
)) == Bufsize
)
1112 "Unable to write this medium, try "
1121 * ckname: Check filenames against user specified patterns,
1122 * and/or ask the user for new name when -r is used.
1129 size_t rename_bufsz
= Max_namesz
+ 1;
1131 if (Hdr_type
!= TAR
&& Hdr_type
!= USTAR
&& Hdr_type
!= BAR
) {
1132 /* Re-visit tar size issues later */
1133 if (G_p
->g_namesz
- 1 > Max_namesz
) {
1134 msg(ERR
, "Name exceeds maximum length - skipped.");
1139 if (Pat_pp
&& !matched())
1142 /* rename interactively */
1143 if ((Args
& OCr
) && !Adir
&& !G_p
->g_rw_sysattr
) {
1144 (void) fprintf(Wtty_p
, gettext("Rename \"%s%s%s\"? "),
1145 (G_p
->g_attrnam_p
== NULL
) ? G_p
->g_nam_p
: Renam_p
,
1146 (G_p
->g_attrnam_p
== NULL
) ? "" : gettext(" Attribute "),
1147 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
1148 (void) fflush(Wtty_p
);
1149 if (fgets(Renametmp_p
, rename_bufsz
, Rtty_p
) == NULL
)
1150 msg(EXT
, "Cannot read tty.");
1153 lastchar
= strlen(Renametmp_p
) - 1;
1155 /* remove trailing '\n' */
1156 if (*(Renametmp_p
+ lastchar
) == '\n')
1157 *(Renametmp_p
+ lastchar
) = '\0';
1158 if (*Renametmp_p
== '\0') {
1159 msg(POST
, "%s%s%s Skipped.",
1160 (G_p
->g_attrnam_p
== NULL
) ? G_p
->g_nam_p
:
1162 (G_p
->g_attrnam_p
== NULL
) ? "" :
1163 gettext(" Attribute "),
1164 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
1165 if (G_p
->g_attrparent_p
== NULL
) {
1166 *G_p
->g_nam_p
= '\0';
1169 *Renam_attr_p
= '\0';
1172 } else if (strcmp(Renametmp_p
, ".") != 0) {
1173 if (G_p
->g_attrnam_p
== NULL
) {
1174 if (strlen(Renametmp_p
) > strlen(
1176 if ((G_p
->g_nam_p
!= &nambuf
[0]) &&
1177 (G_p
->g_nam_p
!= &fullnam
[0])) {
1179 G_p
->g_nam_p
= e_zalloc(E_EXIT
,
1184 *Renam_attr_p
= '\0';
1186 if ((strlcpy(Renam_p
, Renametmp_p
,
1187 rename_bufsz
) > rename_bufsz
) ||
1188 (strlcpy(G_p
->g_nam_p
, Renametmp_p
,
1189 rename_bufsz
) > rename_bufsz
)) {
1190 msg(EXTN
, "buffer overflow");
1193 if (G_p
->g_attrnam_p
!= NULL
) {
1194 free(G_p
->g_attrnam_p
);
1195 G_p
->g_attrnam_p
= e_strdup(E_EXIT
,
1197 (void) strcpy(G_p
->g_nam_p
, Renam_p
);
1199 if (strlcpy(Renam_attr_p
,
1200 Renametmp_p
, rename_bufsz
) >
1209 if (G_p
->g_attrnam_p
== NULL
) {
1213 *Renam_attr_p
= '\0';
1217 if (flag
!= 0 || Onecopy
== 0) {
1218 VERBOSE((Args
& OCt
), G_p
->g_nam_p
);
1226 * ckopts: Check the validity of all command line options.
1235 uid_t Euid
= geteuid(); /* Effective uid of invoker */
1236 #ifdef SOLARIS_PRIVS
1237 priv_set_t
*privset
;
1238 priv_set_t
*zones_privset
;
1239 #endif /* SOLARIS_PRIVS */
1242 errmsk
= mask
& INV_MSK4i
;
1243 } else if (mask
& OCo
) {
1244 errmsk
= mask
& INV_MSK4o
;
1245 } else if (mask
& OCp
) {
1246 errmsk
= mask
& INV_MSK4p
;
1248 msg(ERR
, "One of -i, -o or -p must be specified.");
1253 /* if non-zero, invalid options were specified */
1257 if ((mask
& OCa
) && (mask
& OCm
) && ((mask
& OCi
) ||
1259 msg(ERR
, "-a and -m are mutually exclusive.");
1262 if ((mask
& OCc
) && (mask
& OCH
) &&
1263 (strcmp("odc", Hdr_p
) != 0 && strcmp("odc_sparse", Hdr_p
) != 0)) {
1264 msg(ERR
, "-c and -H are mutually exclusive.");
1267 if ((mask
& OCv
) && (mask
& OCV
)) {
1268 msg(ERR
, "-v and -V are mutually exclusive.");
1271 if ((mask
& OCt
) && (mask
& OCV
)) {
1272 msg(ERR
, "-t and -V are mutually exclusive.");
1275 if ((mask
& OCB
) && (mask
& OCC
)) {
1276 msg(ERR
, "-B and -C are mutually exclusive.");
1279 if ((mask
& OCH
) && (mask
& OC6
)) {
1280 msg(ERR
, "-H and -6 are mutually exclusive.");
1283 if ((mask
& OCM
) && !((mask
& OCI
) || (mask
& OCO
))) {
1284 msg(ERR
, "-M not meaningful without -O or -I.");
1287 if ((mask
& OCA
) && !(mask
& OCO
)) {
1288 msg(ERR
, "-A requires the -O option.");
1292 msg(ERR
, "Illegal size given for -C option.");
1298 while (*t_p
!= NULL
) {
1299 if (isupper(*t_p
)) {
1300 *t_p
= 'a' + (*t_p
- 'A');
1306 if (!(strcmp("odc", Hdr_p
))) {
1311 } else if (!(strcmp("odc_sparse", Hdr_p
))) {
1316 Compress_sparse
= 1;
1317 } else if (!(strcmp("ascii_sparse", Hdr_p
))) {
1321 Compress_sparse
= 1;
1322 } else if (!(strcmp("crc", Hdr_p
))) {
1326 } else if (!(strcmp("tar", Hdr_p
))) {
1329 Max_namesz
= HNAMLEN
- 1;
1332 Max_namesz
= TNAMLEN
- 1;
1335 } else if (!(strcmp("ustar", Hdr_p
))) {
1337 Max_namesz
= HNAMLEN
- 1;
1339 } else if (!(strcmp("bar", Hdr_p
))) {
1340 if ((Args
& OCo
) || (Args
& OCp
)) {
1342 "Header type bar can only be used with -i");
1347 "Can't preserve using bar header");
1351 Max_namesz
= TNAMLEN
- 1;
1354 msg(ERR
, "Invalid header \"%s\" specified", Hdr_p
);
1359 Rtty_p
= fopen(Ttyname
, "r");
1360 Wtty_p
= fopen(Ttyname
, "w");
1362 if (Rtty_p
== NULL
|| Wtty_p
== NULL
) {
1363 msg(ERR
, "Cannot rename, \"%s\" missing", Ttyname
);
1367 if ((mask
& OCE
) && (Ef_p
= fopen(Efil_p
, "r")) == NULL
) {
1368 msg(ERR
, "Cannot open \"%s\" to read patterns", Efil_p
);
1371 if ((mask
& OCI
) && (Archive
= open(IOfil_p
, O_RDONLY
)) < 0) {
1372 msg(ERR
, "Cannot open \"%s\" for input", IOfil_p
);
1377 if ((Archive
= open(IOfil_p
, O_RDWR
)) < 0) {
1379 "Cannot open \"%s\" for append",
1383 oflag
= (O_WRONLY
| O_CREAT
| O_TRUNC
);
1385 if ((Archive
= open(IOfil_p
, oflag
, 0777)) < 0) {
1387 "Cannot open \"%s\" for output",
1393 #ifdef SOLARIS_PRIVS
1394 if ((privset
= priv_allocset()) == NULL
) {
1395 msg(ERR
, "Unable to allocate privilege set");
1396 } else if (getppriv(PRIV_EFFECTIVE
, privset
) != 0) {
1397 msg(ERR
, "Unable to obtain privilege set");
1399 zones_privset
= priv_str_to_set("zone", "", NULL
);
1400 if (zones_privset
!= NULL
) {
1401 privileged
= (priv_issubset(zones_privset
,
1402 privset
) == B_TRUE
);
1403 priv_freeset(zones_privset
);
1405 msg(ERR
, "Unable to map privilege to privilege set");
1408 if (privset
!= NULL
) {
1409 priv_freeset(privset
);
1412 privileged
= (Euid
== 0);
1413 #endif /* SOLARIS_PRIVS */
1416 if ((Rpw_p
= getpwnam(Own_p
)) == NULL
) {
1417 msg(ERR
, "\"%s\" is not a valid user id", Own_p
);
1418 } else if ((Euid
!= Rpw_p
->pw_uid
) && !privileged
) {
1419 msg(ERR
, "R option only valid for super-user or "
1420 "id matches login id of user executing cpio");
1424 if ((mask
& OCo
) && !(mask
& OCO
)) {
1428 if ((mask
& OCp
) && ((mask
& (OCB
|OCC
)) == 0)) {
1430 * We are in pass mode with no block size specified. Use the
1431 * larger of the native page size and 8192.
1434 Bufsize
= (PageSize
> 8192) ? PageSize
: 8192;
1439 * cksum: Calculate the simple checksum of a file (CRC) or header
1440 * (TARTYP (TAR and USTAR)). For -o and the CRC header, the file is opened and
1441 * the checksum is calculated. For -i and the CRC header, the checksum
1442 * is calculated as each block is transferred from the archive I/O buffer
1443 * to the file system I/O buffer. The TARTYP (TAR and USTAR) headers calculate
1444 * the simple checksum of the header (with the checksum field of the
1445 * header initialized to all spaces (\040).
1449 cksum(char hdr
, int byt_cnt
, int *err
)
1451 char *crc_p
, *end_p
;
1453 long checksum
= 0L, have
;
1460 if (Args
& OCi
) { /* do running checksum */
1461 end_p
= Buffr
.b_out_p
+ byt_cnt
;
1462 for (crc_p
= Buffr
.b_out_p
; crc_p
< end_p
; crc_p
++)
1463 checksum
+= (long)*crc_p
;
1466 /* OCo - do checksum of file */
1467 lcnt
= G_p
->g_filesz
;
1470 have
= (lcnt
< Bufsize
) ? lcnt
: Bufsize
;
1472 if (read(Ifile
, Buf_p
, have
) != have
) {
1473 msg(ERR
, "Error computing checksum.");
1478 end_p
= Buf_p
+ have
;
1479 for (crc_p
= Buf_p
; crc_p
< end_p
; crc_p
++)
1480 checksum
+= (long)*crc_p
;
1483 if (lseek(Ifile
, (off_t
)0, SEEK_ABS
) < 0)
1484 msg(ERRN
, "Cannot reset file after checksum");
1486 case TARTYP
: /* TAR and USTAR */
1487 crc_p
= Thdr_p
->tbuf
.t_cksum
;
1488 for (cnt
= 0; cnt
< TCRCLEN
; cnt
++) {
1492 crc_p
= (char *)Thdr_p
;
1493 for (cnt
= 0; cnt
< TARSZ
; cnt
++) {
1495 * tar uses unsigned checksum, so we must use unsigned
1496 * here in order to be able to read tar archives.
1498 checksum
+= (long)((unsigned char)(*crc_p
));
1503 msg(EXT
, "Impossible header type.");
1509 * creat_hdr: Fill in the generic header structure with the specific
1510 * header information based on the value of Hdr_type.
1512 * return (1) if this process was successful, and (0) otherwise.
1523 ftype
= SrcSt
.st_mode
& Ftype
;
1524 Adir
= (ftype
== S_IFDIR
);
1525 Aspec
= (ftype
== S_IFBLK
|| ftype
== S_IFCHR
|| ftype
== S_IFIFO
||
1529 Gen
.g_magic
= CMN_BIN
;
1532 Gen
.g_magic
= CMN_BIN
;
1535 Gen
.g_magic
= CMN_ASC
;
1538 Gen
.g_magic
= CMN_CRC
;
1542 * If the length of the full name is greater than 256,
1543 * print out a message and return.
1545 if ((fullnamesize
= strlen(Gen
.g_nam_p
)) > MAXNAM
) {
1547 "%s: file name too long", Gen
.g_nam_p
);
1549 } else if (fullnamesize
> NAMSIZ
) {
1551 * The length of the full name is greater than
1552 * 100, so we must split the filename from the
1555 char namebuff
[NAMSIZ
+1];
1556 char prebuff
[PRESIZ
+1];
1558 int presize
, namesize
;
1560 (void) memset(namebuff
, '\0',
1562 (void) memset(prebuff
, '\0', sizeof (prebuff
));
1564 lastslash
= strrchr(Gen
.g_nam_p
, '/');
1566 if (lastslash
!= NULL
) {
1567 namesize
= strlen(++lastslash
);
1568 presize
= fullnamesize
- namesize
- 1;
1570 namesize
= fullnamesize
;
1571 lastslash
= Gen
.g_nam_p
;
1576 * If the filename is greater than 100 we can't
1579 if (namesize
> NAMSIZ
) {
1581 "%s: filename is greater than %d",
1585 (void) strncpy(&namebuff
[0], lastslash
,
1588 * If the prefix is greater than 155 we can't
1591 if (presize
> PRESIZ
) {
1593 "%s: prefix is greater than %d",
1594 Gen
.g_nam_p
, PRESIZ
);
1597 (void) strncpy(&prebuff
[0], Gen
.g_nam_p
,
1600 Gen
.g_tname
= e_zalloc(E_EXIT
, namesize
+ 1);
1601 (void) strcpy(Gen
.g_tname
, namebuff
);
1603 Gen
.g_prefix
= e_zalloc(E_EXIT
, presize
+ 1);
1604 (void) strcpy(Gen
.g_prefix
, prebuff
);
1606 Gen
.g_tname
= Gen
.g_nam_p
;
1608 (void) strcpy(Gen
.g_tmagic
, "ustar");
1609 (void) strcpy(Gen
.g_version
, "00");
1611 dpasswd
= getpwuid(SrcSt
.st_uid
);
1612 if (dpasswd
== NULL
) {
1614 "cpio: could not get passwd information "
1616 (Gen
.g_attrnam_p
== NULL
) ?
1617 Gen
.g_nam_p
: Gen
.g_attrfnam_p
,
1618 (Gen
.g_attrnam_p
== NULL
) ?
1619 "" : Gen
.g_rw_sysattr
?
1620 gettext(" System Attribute ") :
1621 gettext(" Attribute "),
1622 (Gen
.g_attrnam_p
== NULL
) ?
1623 "" : Gen
.g_attrnam_p
);
1624 /* make name null string */
1625 Gen
.g_uname
[0] = '\0';
1627 (void) strncpy(&Gen
.g_uname
[0],
1628 dpasswd
->pw_name
, 32);
1630 dgroup
= getgrgid(SrcSt
.st_gid
);
1631 if (dgroup
== NULL
) {
1633 "cpio: could not get group information "
1635 (Gen
.g_attrnam_p
== NULL
) ?
1636 Gen
.g_nam_p
: Gen
.g_attrfnam_p
,
1637 (Gen
.g_attrnam_p
== NULL
) ?
1638 "" : Gen
.g_rw_sysattr
?
1639 gettext(" System Attribute ") :
1640 gettext(" Attribute "),
1641 (Gen
.g_attrnam_p
== NULL
) ?
1642 "" : Gen
.g_attrnam_p
);
1643 /* make name null string */
1644 Gen
.g_gname
[0] = '\0';
1646 (void) strncpy(&Gen
.g_gname
[0],
1647 dgroup
->gr_name
, 32);
1649 Gen
.g_typeflag
= tartype(ftype
);
1652 (void) memset(T_lname
, '\0', sizeof (T_lname
));
1655 msg(EXT
, "Impossible header type.");
1658 if (Use_old_stat
&& (Gen
.g_attrnam_p
!= NULL
)) {
1660 * When processing extended attributes, creat_hdr()
1661 * can get called multiple times which means that
1662 * SrcSt.st.st_dev would have gotten converted to
1663 * -Hodc format. We should always use the original
1664 * device here as we need to be able to match on
1665 * the original device id from the file that was
1666 * previewed in sl_preview_synonyms().
1678 Gen
.g_namesz
= strlen(Gen
.g_nam_p
) + 1;
1679 Gen
.g_uid
= SrcSt
.st_uid
;
1680 Gen
.g_gid
= SrcSt
.st_gid
;
1681 Gen
.g_dev
= SrcSt
.st_dev
;
1686 sl_info_t
*p
= sl_search(dev
, ino
, ftype
);
1687 Gen
.g_ino
= p
? p
->sl_ino2
: -1;
1689 if (Gen
.g_ino
== (ulong_t
)-1) {
1690 msg(ERR
, "%s%s%s: cannot be archived - inode too big "
1692 (Gen
.g_attrnam_p
== NULL
) ?
1693 Gen
.g_nam_p
: Gen
.g_attrfnam_p
,
1694 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
1695 gettext(" System Attribute ") :
1696 gettext(" Attribute "),
1697 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_attrnam_p
);
1701 Gen
.g_ino
= SrcSt
.st_ino
;
1704 Gen
.g_mode
= SrcSt
.st_mode
;
1705 Gen
.g_mtime
= SrcSt
.st_mtime
;
1706 Gen
.g_nlink
= Adir
? SrcSt
.st_nlink
: sl_numlinks(dev
, ino
, ftype
);
1708 if (ftype
== S_IFREG
|| ftype
== S_IFLNK
)
1709 Gen
.g_filesz
= (off_t
)SrcSt
.st_size
;
1711 Gen
.g_filesz
= (off_t
)0;
1712 Gen
.g_rdev
= SrcSt
.st_rdev
;
1717 * creat_lnk: Create a link from the existing name1_p to name2_p.
1722 creat_lnk(int dirfd
, char *name1_p
, char *name2_p
)
1728 if (!link(name1_p
, name2_p
)) {
1736 } else if ((errno
== EEXIST
) && (cnt
== 0)) {
1741 * Check to see if we are trying to link this
1742 * file to itself. If so, count the effort as
1743 * successful. If the two files are different,
1744 * or if either lstat is unsuccessful, proceed
1745 * as we would have otherwise; the appropriate
1746 * error will be reported subsequently.
1749 if (lstat(name1_p
, &lsb1
) != 0) {
1750 msg(ERR
, "Cannot lstat source file %s",
1753 if (lstat(name2_p
, &lsb2
) != 0) {
1754 msg(ERR
, "Cannot lstat "
1755 "destination file %s", name2_p
);
1757 if (lsb1
.st_dev
== lsb2
.st_dev
&&
1758 lsb1
.st_ino
== lsb2
.st_ino
) {
1759 VERBOSE((Args
& (OCv
| OCV
)),
1766 if (!(Args
& OCu
) && G_p
->g_mtime
<= DesSt
.st_mtime
)
1767 msg(ERR
, "Existing \"%s\" same age or newer",
1769 else if (unlinkat(dirfd
, get_component(name2_p
), 0) < 0)
1770 msg(ERRN
, "Error cannot unlink \"%s\"",
1774 } while ((cnt
< 2) && missdir(name2_p
) == 0);
1782 attrname
= Gen
.g_attrnam_p
;
1785 newname
= fromname
= Fullnam_p
;
1787 newname
= Gen
.g_attrfnam_p
;
1791 (void) fprintf(Err_p
,
1792 gettext("%s%s%s linked to %s%s%s\n"), newname
,
1793 (attrname
== NULL
) ? "" : gettext(" attribute "),
1794 (attrname
== NULL
) ? "" : attrname
,
1795 (attrname
== NULL
) ? fromname
: newname
,
1796 (attrname
== NULL
) ? "" : gettext(" attribute "),
1797 (attrname
== NULL
) ? "" : name1_p
);
1799 VERBOSE((Args
& (OCv
| OCV
)), newname
);
1801 } else if (cnt
== 1)
1803 "Unable to create directory for \"%s\"", name2_p
);
1806 "Cannot link \"%s\" and \"%s\"", name1_p
, name2_p
);
1812 * Create one of the following:
1814 * character special file
1815 * block special file
1821 creat_spec(int dirfd
)
1824 int cnt
, result
, rv
= 0;
1828 Do_rename
= 0; /* creat_tmp() may reset this */
1833 nam_p
= G_p
->g_nam_p
;
1837 * Is this the extraction of the hidden attribute directory?
1838 * If we are processing the hidden attribute directory of an
1839 * attribute, then just return as modes and times cannot be set.
1840 * Otherwise, if we are processing a hidden attribute, just set
1841 * the mode/times correctly and return.
1845 if (G_p
->g_attrparent_p
== NULL
) {
1847 if (fchownat(dirfd
, ".", Rpw_p
->pw_uid
,
1848 Rpw_p
->pw_gid
, 0) != 0) {
1850 "Cannot chown() \"attribute "
1851 "directory of file %s\"",
1854 } else if ((fchownat(dirfd
, ".", G_p
->g_uid
,
1855 G_p
->g_gid
, 0) != 0) && privileged
) {
1857 "Cannot chown() \"attribute directory of "
1858 "file %s\"", G_p
->g_attrfnam_p
);
1861 if (fchmod(dirfd
, G_p
->g_mode
) != 0) {
1863 "Cannot chmod() \"attribute directory of "
1864 "file %s\"", G_p
->g_attrfnam_p
);
1868 if (Pflag
&& aclp
!= NULL
) {
1869 if (facl_set(dirfd
, aclp
) < 0) {
1871 "failed to set acl on attribute"
1872 " directory of %s ",
1885 result
= stat(nam_p
, &DesSt
);
1887 if (ustar_dir() || Adir
) {
1889 * The archive file is a directory.
1893 curdir
= strrchr(nam_p
, '.');
1895 if (curdir
!= NULL
&& curdir
[1] == NULL
) {
1896 lastslash
= strrchr(nam_p
, '/');
1898 if (lastslash
!= NULL
) {
1904 if (!(strcmp(lastslash
, ".")) ||
1905 !(strcmp(lastslash
, ".."))) {
1911 /* A file by the same name exists. */
1913 /* Take care of ACLs */
1916 if (Pflag
&& aclp
!= NULL
) {
1917 if (acl_set(nam_p
, aclp
) < 0) {
1919 "\"%s\": failed to set acl",
1930 * We are creating directories. Keep the
1934 rstfiles(U_KEEP
, dirfd
);
1937 /* Report success. */
1942 /* The archive file is not a directory. */
1946 * A file by the same name exists. Move it to a
1950 if (creat_tmp(nam_p
) < 0) {
1952 * We weren't able to create the temp file.
1962 * This pile tries to create the file directly, and, if there is a
1963 * problem, creates missing directories, and then tries to create the
1964 * file again. Two strikes and you're out.
1970 if (ustar_dir() || Adir
) {
1971 /* The archive file is a directory. */
1973 result
= mkdir(nam_p
, G_p
->g_mode
);
1974 } else if (ustar_spec() || Aspec
) {
1976 * The archive file is block special,
1977 * char special, socket, or a fifo.
1978 * Note that, for a socket, the third
1979 * parameter to mknod() is ignored.
1982 result
= mknod(nam_p
, (int)G_p
->g_mode
,
1988 * The file creation succeeded. Take care of the ACLs.
1993 if (Pflag
&& aclp
!= NULL
) {
1994 if (acl_set(nam_p
, aclp
) < 0) {
1996 "\"%s\": failed to set acl", nam_p
);
2010 } while (cnt
< 2 && missdir(nam_p
) == 0);
2015 rstfiles(U_OVER
, dirfd
);
2020 "Cannot create directory for \"%s\"", nam_p
);
2022 if (*Over_p
== '\0') {
2023 rstfiles(U_KEEP
, dirfd
);
2029 if (ustar_dir() || Adir
) {
2030 msg(ERRN
, "Cannot create directory \"%s\"", nam_p
);
2031 } else if (ustar_spec() || Aspec
) {
2032 msg(ERRN
, "Cannot mknod() \"%s\"", nam_p
);
2035 if (*Over_p
== '\0') {
2036 rstfiles(U_KEEP
, dirfd
);
2042 msg(EXT
, "Impossible case.");
2053 creat_tmp(char *nam_p
)
2058 if ((Args
& OCp
) && G_p
->g_ino
== DesSt
.st_ino
&&
2059 G_p
->g_dev
== DesSt
.st_dev
) {
2060 msg(ERR
, "Attempt to pass a file to itself.");
2064 if (G_p
->g_mtime
<= DesSt
.st_mtime
&& !(Args
& OCu
)) {
2065 msg(ERR
, "Existing \"%s\" same age or newer", nam_p
);
2069 /* Make the temporary file name. */
2071 (void) strcpy(Over_p
, nam_p
);
2072 t_p
= Over_p
+ strlen(Over_p
);
2074 while (t_p
!= Over_p
) {
2075 if (*(t_p
- 1) == '/')
2080 (void) strcpy(t_p
, "XXXXXX");
2082 if (G_p
->g_attrnam_p
!= NULL
) {
2084 * Save our current directory, so we can go into
2085 * the attribute directory to make the temp file
2090 (void) fchdir(G_p
->g_dirfd
);
2093 (void) mktemp(Over_p
);
2095 if (G_p
->g_attrnam_p
!= NULL
) {
2096 /* Return to the current directory. */
2101 if (*Over_p
== '\0') {
2102 /* mktemp reports a failure. */
2104 msg(ERR
, "Cannot get temporary file name.");
2109 * If it's a regular file, write to the temporary file, and then rename
2110 * in order to accommodate potential executables.
2112 * Note: g_typeflag is only defined (set) for USTAR archive types. It
2113 * defaults to 0 in the cpio-format-regular file case, so this test
2117 if (G_p
->g_typeflag
== 0 &&
2118 (DesSt
.st_mode
& (ulong_t
)Ftype
) == S_IFREG
&&
2119 (G_p
->g_mode
& (ulong_t
)Ftype
) == S_IFREG
) {
2121 * The archive file and the filesystem file are both regular
2122 * files. We write to the temporary file in this case.
2126 if (G_p
->g_attrnam_p
== NULL
) {
2129 Attrfile_p
= Over_p
;
2132 G_p
->g_nam_p
= Over_p
;
2133 if (G_p
->g_attrnam_p
!= NULL
) {
2134 Attrfile_p
= Over_p
;
2138 if (G_p
->g_attrnam_p
== NULL
) {
2141 Over_p
= G_p
->g_attrnam_p
;
2147 * Either the archive file or the filesystem file is not a
2153 if (S_ISDIR(DesSt
.st_mode
)) {
2155 * The filesystem file is a directory.
2157 * Save the current working directory because we will
2158 * want to restore it back just in case remove_dir()
2159 * fails or get confused about where we should be.
2165 if (remove_dir(nam_p
) < 0) {
2167 "Cannot remove the directory \"%s\"",
2170 * Restore working directory back to the one
2179 * Restore working directory back to the one
2186 * The file is not a directory. Will use the original
2187 * link/unlink construct, however, if the file is
2188 * namefs, link would fail with EXDEV. Therefore, we
2189 * use rename() first to back up the file.
2191 if (rename(nam_p
, Over_p
) < 0) {
2193 * If rename failed, try old construction
2196 if (link(nam_p
, Over_p
) < 0) {
2198 "Cannot rename temporary file "
2199 "\"%s\" to \"%s\"", Over_p
, nam_p
);
2204 if (unlink(nam_p
) < 0) {
2206 "Cannot unlink() current \"%s\"",
2208 (void) unlink(Over_p
);
2220 * Copy the datasize amount of data from the input file to buffer.
2222 * ifd - Input file descriptor.
2223 * buffer - Buffer (allocated by caller) to copy data to.
2224 * datasize - The amount of data to read from the input file
2225 * and copy to the buffer.
2226 * error - When reading from an Archive file, indicates unreadable
2227 * data was encountered, otherwise indicates errno.
2228 * data_in_info - Information needed when called from data_in().
2231 read_chunk(int ifd
, char *buffer
, size_t datasize
, data_in_t
*data_in_info
)
2234 return (read(ifd
, buffer
, datasize
));
2237 if (data_in_info
->data_in_proc_mode
!= P_SKIP
) {
2238 if (Hdr_type
== CRC
)
2239 data_in_info
->data_in_cksumval
+= cksum(CRC
,
2241 if (data_in_info
->data_in_swapfile
)
2242 swap(Buffr
.b_out_p
, datasize
);
2246 * if the bar archive is compressed, set up a pipe and
2247 * do the de-compression while reading in the file
2249 if (Hdr_type
== BAR
) {
2250 if (data_in_info
->data_in_compress_flag
== 0 &&
2253 &(data_in_info
->data_in_pipef
));
2254 data_in_info
->data_in_compress_flag
++;
2258 (void) memcpy(buffer
, Buffr
.b_out_p
, datasize
);
2259 Buffr
.b_out_p
+= datasize
;
2260 Buffr
.b_cnt
-= datasize
;
2266 * Read as much data as we can.
2268 * ifd - input file descriptor.
2269 * buf - Buffer (allocated by caller) to copy data to.
2270 * bytes - The amount of data to read from the input file
2271 * and copy to the buffer.
2272 * rdblocksz - The size of the chunk of data to read.
2274 * Return number of bytes failed to read.
2275 * Return -1 when buffer is empty and read failed.
2278 read_bytes(int ifd
, char *buf
, size_t bytes
, size_t rdblocksz
,
2279 data_in_t
*data_in_info
)
2284 for (bytesread
= 0; bytesread
< bytes
; bytesread
+= got
) {
2286 * Read the data from either the input file descriptor
2287 * or the archive file. read_chunk() will only return
2288 * <= 0 if data_copy() was called from data_pass().
2290 if ((got
= read_chunk(ifd
, buf
+ bytesread
,
2291 min(bytes
- bytesread
, rdblocksz
),
2292 data_in_info
)) <= 0) {
2294 * We come here only in the pass mode.
2295 * If data couldn't be read from the input file
2296 * descriptor, return number of bytes in the buf.
2297 * If buffer is empty, return -1.
2299 if (bytesread
== 0) {
2300 if (got
== 0) /* EOF */
2301 data_in_info
->data_in_rd_eof
= 1;
2304 return (bytes
- bytesread
);
2311 * Write as much data as we can.
2313 * ofd - output file descriptor.
2314 * buf - Source buffer to output data from.
2315 * maxwrite - The amount of data to write to the output.
2317 * return 0 upon success.
2320 write_bytes(int ofd
, char *buf
, size_t maxwrite
, data_in_t
*data_in_info
)
2325 if ((cnt
= write(ofd
, buf
, maxwrite
)) < (ssize_t
)maxwrite
) {
2326 data_in_info
->data_in_errno
= errno
;
2328 * data_in() needs to know if it was an actual write(2)
2329 * failure, or if we just couldn't write all of the data
2330 * requested so that we know that the rest of the file's
2331 * data can be read but not written.
2334 data_in_info
->data_in_wr_part
= 1;
2336 } else if (Args
& OCp
) {
2337 Blocks
+= (u_longlong_t
)((cnt
+ (Bufsize
- 1)) / Bufsize
);
2343 * Perform I/O for given byte size with using limited i/o block size
2344 * and supplied buffer.
2346 * ifd/ofd - i/o file descriptor
2347 * buf - buffer to be used for i/o
2348 * bytes - Amount to read/write
2349 * wrblocksz - Output block size.
2350 * rdblocksz - Read block size.
2352 * Return 0 upon success. Return negative if read failed.
2353 * Return positive non-zero if write failed.
2356 rdwr_bytes(int ifd
, int ofd
, char *buf
, off_t bytes
,
2357 size_t wrblocksz
, size_t rdblocksz
, data_in_t
*data_in_info
)
2361 int write_it
= (data_in_info
->data_in_proc_mode
!= P_SKIP
);
2365 * If the number of bytes left to write is smaller than
2366 * the preferred I/O size, then we're about to do our final
2367 * write to the file, so just set wrblocksz to the number of
2368 * bytes left to write.
2370 if (bytes
< wrblocksz
)
2373 /* Read input till satisfy output block size */
2374 sz
= read_bytes(ifd
, buf
, wrblocksz
, rdblocksz
, data_in_info
);
2379 rv
= write_bytes(ofd
, buf
,
2380 wrblocksz
- sz
, data_in_info
);
2383 * If we wrote partial, we return and quits.
2384 * Otherwise, read through the rest of input
2385 * to go to the next file.
2388 data_in_info
->data_in_wr_part
) {
2396 bytes
-= (wrblocksz
- sz
);
2402 * Write zeros for give size.
2404 * ofd - output file descriptor
2405 * buf - buffer to fill with zeros
2406 * bytes - Amount to write
2407 * wrblocksz - Write block size
2409 * return 0 upon success.
2412 write_zeros(int ofd
, char *buf
, off_t bytes
, size_t wrblocksz
,
2413 data_in_t
*data_in_info
)
2417 (void) memset(buf
, 0, min(bytes
, wrblocksz
));
2419 if (bytes
< wrblocksz
)
2421 rv
= write_bytes(ofd
, buf
, wrblocksz
, data_in_info
);
2430 * To figure out the size of the buffer used to accumulate data from
2431 * readtape() and to write to the file, we need to determine the largest
2432 * chunk of data to be written to the file at one time. This is determined
2433 * based on the following three things:
2434 * 1) The size of the archived file.
2435 * 2) The preferred I/O size of the file.
2436 * 3) If the file is a read-write system attribute file.
2437 * If the size of the file is less than the preferred I/O size or it's a
2438 * read-write system attribute file, which must be written in one operation,
2439 * then set the maximum write size to the size of the archived file.
2440 * Otherwise, the maximum write size is preferred I/O size.
2443 calc_maxwrite(int ofd
, int rw_sysattr
, off_t bytes
, size_t blocksize
)
2447 size_t piosize
; /* preferred I/O size */
2449 if (rw_sysattr
|| bytes
< blocksize
) {
2452 if (fstat(ofd
, &tsbuf
) == 0) {
2453 piosize
= tsbuf
.st_blksize
;
2455 piosize
= blocksize
;
2457 maxwrite
= min(bytes
, piosize
);
2462 * data_copy() and data_copy_with_holes() copy data from the input
2463 * file to output file descriptor. If ifd is -1, then the input file is
2467 * ifd - Input file descriptor to read from.
2468 * ofd - Output file descriptor of extracted file.
2469 * rw_sysattr - Flag indicating if a file is an extended
2470 * system attribute file.
2471 * bytes - Amount of data (file size) of copy/write.
2472 * blocksize - Amount of data to read at a time from either
2473 * the input file descriptor or from the archive.
2474 * data_in_info - information needed while reading data when
2475 * called by data_in().
2476 * holes - Information of holes in the input file.
2480 * < 0 An error occurred during the read of the input
2482 * > 0 An error occurred during the write of the output
2486 data_copy(int ifd
, int ofd
, int rw_sysattr
, off_t bytes
,
2487 size_t blocksize
, data_in_t
*data_in_info
)
2493 /* No data to copy. */
2497 maxwrite
= calc_maxwrite(ofd
, rw_sysattr
, bytes
, blocksize
);
2498 buf
= e_zalloc(E_EXIT
, maxwrite
);
2500 rv
= rdwr_bytes(ifd
, ofd
, buf
, bytes
, maxwrite
,
2501 blocksize
, data_in_info
);
2508 data_copy_with_holes(int ifd
, int ofd
, int rw_sysattr
, off_t bytes
,
2509 size_t blocksize
, data_in_t
*data_in_info
, holes_info_t
*holes
)
2512 off_t curpos
, noff
, datasize
;
2520 maxwrite
= calc_maxwrite(ofd
, rw_sysattr
, bytes
, blocksize
);
2521 buf
= e_zalloc(E_EXIT
, maxwrite
);
2525 for (hl
= holes
->holes_list
; hl
!= NULL
; hl
= hl
->hl_next
) {
2526 if (curpos
!= hl
->hl_data
) {
2527 /* adjust output position */
2528 noff
= lseek(ofd
, hl
->hl_data
, SEEK_SET
);
2529 if (noff
!= hl
->hl_data
) {
2531 * Can't seek to the target, try to adjust
2532 * position by filling with zeros.
2534 datasize
= hl
->hl_data
- curpos
;
2535 rv
= write_zeros(ofd
, buf
, datasize
,
2536 maxwrite
, data_in_info
);
2541 * Data is contiguous in the archive, but fragmented
2542 * in the regular file, so we also adjust the input
2543 * file position in pass mode.
2546 /* adjust input position */
2547 (void) lseek(ifd
, hl
->hl_data
, SEEK_SET
);
2549 curpos
= hl
->hl_data
;
2551 datasize
= hl
->hl_hole
- hl
->hl_data
;
2552 if (datasize
== 0) {
2554 * There is a hole at the end of file. To create
2555 * such hole, we append one byte, and truncate the
2556 * last block. This is necessary because ftruncate(2)
2557 * alone allocates one block on the end of file.
2559 rv
= write_zeros(ofd
, buf
, 1, maxwrite
, data_in_info
);
2562 (void) ftruncate(ofd
, hl
->hl_data
);
2565 rv
= rdwr_bytes(ifd
, ofd
, buf
, datasize
, maxwrite
,
2566 blocksize
, data_in_info
);
2570 * Return if we got a read error or in pass mode,
2571 * or failed with partial write. Otherwise, we'll
2572 * read through the input stream till next file.
2574 if (rv
< 0 || (Args
& OCp
) ||
2575 data_in_info
->data_in_wr_part
) {
2587 * We should read through the input data to go to the next
2588 * header when non-fatal error occured.
2590 if (error
&& !(Args
& OCp
)) {
2591 data_in_info
->data_in_proc_mode
= P_SKIP
;
2592 while (hl
!= NULL
) {
2593 datasize
= hl
->hl_hole
- hl
->hl_data
;
2594 rv
= rdwr_bytes(ifd
, ofd
, buf
, datasize
, maxwrite
,
2595 blocksize
, data_in_info
);
2607 * Strip off the sparse file information that is prepended to
2608 * the compressed sparse file. The information is in the following
2610 * <prepended info size><SP><orig file size><SP><holes info>
2611 * where prepended info size is long right justified in 10 bytes.
2612 * Holesdata consists of the series of offset pairs:
2613 * <data offset><SP><hole offset><SP><data offset><SP><hole offset>...
2614 * prepended info size and original file size have been read in gethdr().
2615 * We read the rest of holes information here in this function.
2618 read_holesdata(holes_info_t
*holes
, off_t
*fileszp
,
2619 char *nam_p
, data_in_t
*data_in_info
)
2622 size_t holesdata_sz
;
2624 /* We've already read the header. */
2625 holesdata_sz
= holes
->holesdata_sz
- MIN_HOLES_HDRSIZE
;
2627 if ((holesdata
= e_zalloc(E_NORMAL
, holesdata_sz
)) == NULL
) {
2628 msg(ERRN
, "Could not allocate memory for "
2629 "sparse file information", nam_p
);
2633 * This function is called only in OCi mode. Therefore,
2634 * read_bytes() won't fail, and won't return if error occurs in
2635 * input stream. See rstbuf().
2637 (void) read_bytes(-1, holesdata
, holesdata_sz
, CPIOBSZ
, data_in_info
);
2638 *fileszp
-= holesdata_sz
;
2640 /* The string should be terminated. */
2641 if (holesdata
[holesdata_sz
- 1] != '\0') {
2644 msg(ERR
, "invalid sparse file information", nam_p
);
2647 if (parse_holesdata(holes
, holesdata
) != 0)
2651 if (*fileszp
!= holes
->data_size
)
2659 * data_in: If proc_mode == P_PROC, bread() the file's data from the archive
2660 * and write(2) it to the open fdes gotten from openout(). If proc_mode ==
2661 * P_SKIP, or becomes P_SKIP (due to errors etc), bread(2) the file's data
2662 * and ignore it. If the user specified any of the "swap" options (b, s or S),
2663 * and the length of the file is not appropriate for that action, do not
2664 * perform the "swap", otherwise perform the action on a buffer by buffer basis.
2665 * If the CRC header was selected, calculate a running checksum as each buffer
2669 data_in(int proc_mode
)
2677 data_in_t
*data_in_info
;
2679 if (G_p
->g_attrnam_p
!= NULL
) {
2680 nam_p
= G_p
->g_attrnam_p
;
2682 nam_p
= G_p
->g_nam_p
;
2685 if (((G_p
->g_mode
& Ftype
) == S_IFLNK
&& proc_mode
!= P_SKIP
) ||
2686 (Hdr_type
== BAR
&& bar_linkflag
== '2' && proc_mode
!= P_SKIP
)) {
2688 VERBOSE((Args
& (OCv
| OCV
)), nam_p
);
2690 if (Args
& (OCb
| OCs
| OCS
)) { /* verfify that swapping is possible */
2692 if (Args
& (OCs
| OCb
) && G_p
->g_filesz
% 2) {
2694 "Cannot swap bytes of \"%s\", odd number of bytes",
2698 if (Args
& (OCS
| OCb
) && G_p
->g_filesz
% 4) {
2700 "Cannot swap halfwords of \"%s\", odd number "
2701 "of halfwords", nam_p
);
2706 data_in_info
= e_zalloc(E_EXIT
, sizeof (data_in_t
));
2707 data_in_info
->data_in_swapfile
= swapfile
;
2708 data_in_info
->data_in_proc_mode
= proc_mode
;
2710 filesz
= G_p
->g_filesz
;
2712 if (S_ISSPARSE(G_p
->g_mode
) && G_p
->g_holes
!= NULL
) {
2713 /* We've already read the header in gethdr() */
2714 filesz
-= MIN_HOLES_HDRSIZE
;
2717 * Strip rest of the sparse file information. This includes
2718 * the data/hole offset pairs which will be used to restore
2719 * the holes in the file.
2721 if (proc_mode
== P_SKIP
) {
2722 /* holes info isn't necessary to skip file */
2723 free_holes_info(G_p
->g_holes
);
2724 G_p
->g_holes
= NULL
;
2726 rv
= read_holesdata(G_p
->g_holes
, &filesz
,
2727 nam_p
, data_in_info
);
2730 * We got an error. Skip this file. holes info
2731 * is no longer necessary.
2733 free_holes_info(G_p
->g_holes
);
2734 G_p
->g_holes
= NULL
;
2736 data_in_info
->data_in_proc_mode
= P_SKIP
;
2742 if (G_p
->g_holes
!= NULL
) {
2743 rv
= data_copy_with_holes(-1, Ofile
,
2744 (G_p
->g_attrnam_p
== NULL
) ? 0 : G_p
->g_rw_sysattr
,
2745 G_p
->g_holes
->orig_size
,
2746 CPIOBSZ
, data_in_info
, G_p
->g_holes
);
2748 free_holes_info(G_p
->g_holes
);
2749 G_p
->g_holes
= NULL
;
2751 rv
= data_copy(-1, Ofile
,
2752 (G_p
->g_attrnam_p
== NULL
) ? 0 : G_p
->g_rw_sysattr
,
2753 filesz
, CPIOBSZ
, data_in_info
);
2756 /* This writes out the file from the archive */
2757 if (rv
!= 0 || error
) {
2758 errno
= data_in_info
->data_in_errno
;
2761 msg(data_in_info
->data_in_wr_part
? EXTN
: ERRN
,
2762 "Cannot write \"%s%s%s\"",
2763 (G_p
->g_attrnam_p
== NULL
) ? "" :
2765 (G_p
->g_attrnam_p
== NULL
) ? "" :
2767 gettext(" System Attribute ") :
2768 gettext(" Attribute "), nam_p
);
2771 * We've failed to write to the file, and input data
2772 * has been skiped to the next file. We'll need to restore
2773 * the original file, and skip the rest of work.
2776 rstfiles(U_KEEP
, G_p
->g_dirfd
);
2777 cstatus
= close(Ofile
);
2780 msg(EXTN
, "close error");
2784 /* we must use g_filesz for the amount of padding */
2785 pad
= (Pad_val
+ 1 - (G_p
->g_filesz
& Pad_val
)) & Pad_val
;
2788 Buffr
.b_out_p
+= pad
;
2791 if (proc_mode
!= P_SKIP
) {
2792 if (Hdr_type
== CRC
&&
2793 Gen
.g_cksum
!= data_in_info
->data_in_cksumval
) {
2794 msg(ERR
, "\"%s\" - checksum error", nam_p
);
2795 rstfiles(U_KEEP
, G_p
->g_dirfd
);
2797 rstfiles(U_OVER
, G_p
->g_dirfd
);
2798 if (Hdr_type
== BAR
&& data_in_info
->data_in_compress_flag
) {
2799 (void) pclose(data_in_info
->data_in_pipef
);
2801 cstatus
= close(Ofile
);
2805 msg(EXTN
, "close error");
2808 (void) free(data_in_info
);
2810 VERBOSE((proc_mode
!= P_SKIP
&& (Args
& (OCv
| OCV
))),
2811 (G_p
->g_attrparent_p
== NULL
) ? G_p
->g_nam_p
: G_p
->g_attrpath_p
);
2816 * Read regular file. Return number of bytes which weren't read.
2817 * Upon return, real_filesz will be real file size of input file.
2818 * When read_exact is specified, read size is adjusted to the given
2822 read_file(char *nam_p
, off_t file_size
, off_t
*real_filesz
,
2823 boolean_t read_exact
)
2832 amt_to_read
= file_size
;
2834 if (read_exact
&& amt_to_read
< CPIOBSZ
)
2835 readsz
= amt_to_read
;
2842 if ((amount_read
= read(Ifile
, Buffr
.b_in_p
, readsz
)) < 0) {
2843 msg(EXTN
, "Cannot read \"%s%s%s\"",
2844 (Gen
.g_attrnam_p
== NULL
) ?
2845 nam_p
: Gen
.g_attrfnam_p
,
2846 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
2847 gettext(" System Attribute ") :
2848 gettext(" Attribute "),
2849 (Gen
.g_attrnam_p
== NULL
) ? "" : nam_p
);
2853 if (amount_read
== 0) {
2854 /* got EOF. the file has shrunk */
2855 *real_filesz
= file_size
- amt_to_read
;
2857 } else if (amount_read
> amt_to_read
) {
2858 /* the file has grown */
2859 *real_filesz
= file_size
+
2860 (amount_read
- amt_to_read
);
2861 amount_read
= amt_to_read
;
2862 } else if (amount_read
== amt_to_read
) {
2863 /* the file is the same size */
2864 *real_filesz
= file_size
;
2867 Buffr
.b_in_p
+= amount_read
;
2868 Buffr
.b_cnt
+= (long)amount_read
;
2870 amt_to_read
-= (off_t
)amount_read
;
2872 amt_to_read
== 0 && amount_read
== CPIOBSZ
) {
2874 * If the file size is multiple of CPIOBSZ, we may
2875 * be able to read more from the file even though
2876 * amt_to_read already gets 0.
2879 amount_read
= read(Ifile
, Buffr
.b_in_p
, CPIOBSZ
);
2880 if (amount_read
!= 0) {
2881 /* the file has grown */
2882 *real_filesz
= file_size
+ amount_read
;
2885 } while (amt_to_read
!= 0);
2887 return (amt_to_read
);
2891 * Read through the data in files skipping holes.
2894 read_compress_holes(char *nam_p
, off_t file_size
, off_t
*real_filesz
,
2895 holes_info_t
*holes
, int *hole_changed
)
2898 off_t datasize
, realsz
;
2900 holes_list_t
*hl
= holes
->holes_list
;
2903 for (hl
= holes
->holes_list
; hl
!= NULL
; hl
= hl
->hl_next
) {
2904 datasize
= hl
->hl_hole
- hl
->hl_data
;
2906 npos
= lseek(Ifile
, curpos
, SEEK_DATA
);
2907 if (npos
== -1 && errno
== ENXIO
) {
2909 * No more data. There are two cases.
2910 * - we have a hole toward the end of file.
2911 * - file has been shrunk, and we've reached EOF.
2913 *real_filesz
= lseek(Ifile
, 0, SEEK_END
);
2914 if (hl
->hl_data
== file_size
)
2917 * File has been shrunk. Check the amount of data
2921 while (hl
!= NULL
) {
2922 left
+= (hl
->hl_hole
- hl
->hl_data
);
2930 if (curpos
!= hl
->hl_data
) {
2932 * File has been changed. We shouldn't read data
2933 * from different offset since we've already put
2937 (void) lseek(Ifile
, hl
->hl_data
, SEEK_SET
);
2938 curpos
= hl
->hl_data
;
2940 left
= read_file(nam_p
, datasize
, &realsz
, B_TRUE
);
2942 /* file has been shrunk */
2943 *real_filesz
= curpos
+ datasize
- left
;
2944 left
= file_size
- *real_filesz
;
2950 * We've read exact size of holes. We need to make sure
2951 * that file hasn't grown by reading from the EOF.
2954 (void) read_file(nam_p
, CPIOBSZ
, &realsz
, B_FALSE
);
2956 *real_filesz
= curpos
+ realsz
;
2961 * data_out: open(2) the file to be archived, compute the checksum
2962 * of it's data if the CRC header was specified and write the header.
2963 * read(2) each block of data and bwrite() it to the archive. For TARTYP (TAR
2964 * and USTAR) archives, pad the data with NULLs to the next 512 byte boundary.
2974 int hole_changed
= 0;
2976 holes_info_t
*holes
= NULL
;
2978 nam_p
= G_p
->g_nam_p
;
2980 if (Pflag
&& aclp
!= NULL
) {
2981 char *secinfo
= NULL
;
2984 /* append security attributes */
2985 if (append_secattr(&secinfo
, &len
, aclp
) == -1) {
2987 "can create security information");
2989 /* call append_secattr() if more than one */
2992 /* write ancillary only if there is sec info */
2993 write_hdr(ARCHIVE_ACL
, (off_t
)len
);
2994 write_ancillary(secinfo
, len
, B_TRUE
);
2997 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
2998 rstfiles(U_KEEP
, G_p
->g_dirfd
);
2999 VERBOSE((Args
& (OCv
| OCV
)), nam_p
);
3002 if ((G_p
->g_mode
& Ftype
) == S_IFLNK
&& (Hdr_type
!=
3003 USTAR
&& Hdr_type
!= TAR
)) { /* symbolic link */
3005 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3007 FLUSH(G_p
->g_filesz
);
3010 /* Note that "size" and G_p->g_filesz are the same number */
3012 if ((size
= readlink(nam_p
, Buffr
.b_in_p
, G_p
->g_filesz
)) <
3014 msg(ERRN
, "Cannot read symbolic link \"%s\"", nam_p
);
3019 * Note that it is OK not to add the NUL after the name read by
3020 * readlink, because it is not being used subsequently.
3023 Buffr
.b_in_p
+= size
;
3024 Buffr
.b_cnt
+= size
;
3025 pad
= (Pad_val
+ 1 - (size
& Pad_val
)) & Pad_val
;
3028 (void) memset(Buffr
.b_in_p
, 0, pad
);
3029 Buffr
.b_in_p
+= pad
;
3032 VERBOSE((Args
& (OCv
| OCV
)), nam_p
);
3034 } else if ((G_p
->g_mode
& Ftype
) == S_IFLNK
&&
3035 (Hdr_type
== USTAR
|| Hdr_type
== TAR
)) {
3039 * G_p->g_filesz is the length of the right-hand side of
3040 * the symlink "x -> y".
3041 * The tar link field is only NAMSIZ long.
3044 if (G_p
->g_filesz
> NAMSIZ
) {
3046 "Symbolic link too long \"%s\"", nam_p
);
3049 if ((size
= readlink(nam_p
, T_lname
, G_p
->g_filesz
)) < 0) {
3051 "Cannot read symbolic link \"%s\"", nam_p
);
3054 T_lname
[size
] = '\0';
3055 G_p
->g_filesz
= (off_t
)0;
3056 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3057 VERBOSE((Args
& (OCv
| OCV
)), nam_p
);
3060 if ((Ifile
= openfile(O_RDONLY
)) < 0) {
3061 msg(ERR
, "\"%s%s%s\" ?",
3062 (Gen
.g_attrnam_p
== NULL
) ? nam_p
: Gen
.g_attrfnam_p
,
3063 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
3064 gettext(" System Attribute ") : gettext(" Attribute "),
3065 (Gen
.g_attrnam_p
== NULL
) ? "" :
3066 (Gen
.g_attrparent_p
== NULL
) ? Gen
.g_attrnam_p
:
3067 Gen
.g_attrparent_p
);
3071 /* save original file size */
3072 orig_filesz
= G_p
->g_filesz
;
3075 * Calculate the new compressed file size of a sparse file
3076 * before any of the header information is written
3079 if (Compress_sparse
&& S_ISREG(G_p
->g_mode
)) {
3081 * If the file being processed is a sparse file, gather the
3082 * hole information and the compressed file size.
3083 * G_p->g_filesz will need to be changed to be the size of
3084 * the compressed sparse file plus the the size of the hole
3085 * information that will be prepended to the compressed file
3088 holes
= get_holes_info(Ifile
, G_p
->g_filesz
, B_FALSE
);
3090 G_p
->g_filesz
= holes
->holesdata_sz
+ holes
->data_size
;
3092 if (G_p
->g_filesz
> Max_offset
) {
3093 msg(ERR
, "%s%s%s: too large to archive "
3096 (G_p
->g_attrnam_p
== NULL
) ? "" :
3098 gettext(" System Attribute ") :
3099 gettext(" Attribute "),
3100 (G_p
->g_attrnam_p
== NULL
) ? "" :
3101 ((G_p
->g_attrparent_p
== NULL
) ?
3103 G_p
->g_attrpath_p
));
3105 (void) close(Ifile
);
3107 free_holes_info(holes
);
3108 return; /* do not archive if it's too big */
3113 * Dump extended attribute header.
3116 if (Gen
.g_attrnam_p
!= NULL
) {
3120 if (Hdr_type
== CRC
) {
3121 long csum
= cksum(CRC
, 0, &errret
);
3123 G_p
->g_cksum
= (ulong_t
)-1;
3124 msg(POST
, "\"%s%s%s\" skipped",
3125 (Gen
.g_attrnam_p
== NULL
) ?
3126 nam_p
: Gen
.g_attrfnam_p
,
3127 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
3128 gettext(" System Attribute ") :
3129 gettext(" Attribute "),
3130 (Gen
.g_attrnam_p
== NULL
) ? "" : nam_p
);
3132 free_holes_info(holes
);
3133 (void) close(Ifile
);
3136 G_p
->g_cksum
= csum
;
3142 * ACL has been retrieved in getname().
3145 char *secinfo
= NULL
;
3148 /* append security attributes */
3149 if ((append_secattr(&secinfo
, &len
, aclp
)) == -1)
3150 msg(ERR
, "can create security information");
3152 /* call append_secattr() if more than one */
3155 /* write ancillary only if there is sec info */
3156 write_hdr(ARCHIVE_ACL
, (off_t
)len
);
3157 write_ancillary(secinfo
, len
, B_TRUE
);
3161 if (holes
!= NULL
) {
3163 * Write the header info with a modified c_mode field to
3164 * indicate a compressed sparse file is being archived,
3165 * as well as the new file size, including the size of the
3166 * compressed file as well as all the prepended data.
3168 write_hdr(ARCHIVE_SPARSE
, (off_t
)0);
3169 /* Prepend sparse file info */
3170 write_ancillary(holes
->holesdata
,
3171 holes
->holesdata_sz
, B_FALSE
);
3173 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3178 if (holes
!= NULL
) {
3179 amt_to_read
= read_compress_holes(nam_p
, G_p
->g_filesz
,
3180 &real_filesz
, holes
, &hole_changed
);
3182 amt_to_read
= read_file(nam_p
, G_p
->g_filesz
,
3183 &real_filesz
, B_FALSE
);
3186 while (amt_to_read
> 0) {
3187 cnt
= (amt_to_read
> CPIOBSZ
) ? CPIOBSZ
: (int)amt_to_read
;
3189 (void) memset(Buffr
.b_in_p
, 0, cnt
);
3190 Buffr
.b_in_p
+= cnt
;
3195 pad
= (Pad_val
+ 1 - (G_p
->g_filesz
& Pad_val
)) & Pad_val
;
3198 (void) memset(Buffr
.b_in_p
, 0, pad
);
3199 Buffr
.b_in_p
+= pad
;
3203 if (hole_changed
== 1) {
3205 "File data and hole offsets of \"%s%s%s\" have changed",
3206 (Gen
.g_attrnam_p
== NULL
) ?
3207 G_p
->g_nam_p
: Gen
.g_attrfnam_p
,
3208 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
3209 gettext(" System Attribute ") : gettext(" Attribute "),
3210 (Gen
.g_attrnam_p
== NULL
) ? "" : G_p
->g_nam_p
);
3212 if (real_filesz
> orig_filesz
) {
3213 msg(ERR
, "File size of \"%s%s%s\" has increased by %lld",
3214 (Gen
.g_attrnam_p
== NULL
) ?
3215 G_p
->g_nam_p
: Gen
.g_attrfnam_p
,
3216 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
3217 gettext(" System Attribute ") : gettext(" Attribute "),
3218 (Gen
.g_attrnam_p
== NULL
) ? "" : G_p
->g_nam_p
,
3219 (real_filesz
- orig_filesz
));
3221 if (real_filesz
< orig_filesz
) {
3222 msg(ERR
, "File size of \"%s%s%s\" has decreased by %lld",
3223 (Gen
.g_attrnam_p
== NULL
) ?
3224 G_p
->g_nam_p
: Gen
.g_attrfnam_p
,
3225 (Gen
.g_attrnam_p
== NULL
) ? "" : Gen
.g_rw_sysattr
?
3226 gettext(" System Attribute ") : gettext(" Attribute "),
3227 (Gen
.g_attrnam_p
== NULL
) ? "" : G_p
->g_nam_p
,
3228 (orig_filesz
- real_filesz
));
3232 free_holes_info(holes
);
3234 (void) close(Ifile
);
3235 rstfiles(U_KEEP
, G_p
->g_dirfd
);
3236 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
3240 * data_pass: If not a special file (Aspec), open(2) the file to be
3241 * transferred, read(2) each block of data and write(2) it to the output file
3242 * Ofile, which was opened in file_pass().
3249 char *namep
= Nam_p
;
3250 holes_info_t
*holes
= NULL
;
3251 data_in_t
*data_in_info
;
3253 if (G_p
->g_attrnam_p
!= NULL
) {
3254 namep
= G_p
->g_attrnam_p
;
3257 rstfiles(U_KEEP
, G_p
->g_passdirfd
);
3258 cstatus
= close(Ofile
);
3260 VERBOSE((Args
& (OCv
| OCV
)), Nam_p
);
3262 msg(EXTN
, "close error");
3266 if ((Ifile
= openat(G_p
->g_dirfd
, get_component(namep
), 0)) < 0) {
3267 msg(ERRN
, "Cannot open \"%s%s%s\", skipped",
3268 (G_p
->g_attrnam_p
== NULL
) ? Nam_p
: G_p
->g_attrfnam_p
,
3269 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_rw_sysattr
?
3270 gettext(" System Attribute ") : gettext(" Attribute "),
3271 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
3272 rstfiles(U_KEEP
, G_p
->g_passdirfd
);
3273 cstatus
= close(Ofile
);
3276 msg(EXTN
, "close error");
3281 data_in_info
= e_zalloc(E_EXIT
, sizeof (data_in_t
));
3282 data_in_info
->data_in_proc_mode
= P_PROC
;
3284 if (S_ISREG(G_p
->g_mode
))
3285 holes
= get_holes_info(Ifile
, G_p
->g_filesz
, B_TRUE
);
3287 if (holes
!= NULL
) {
3288 rv
= data_copy_with_holes(Ifile
, Ofile
,
3289 (G_p
->g_attrnam_p
== NULL
) ? 0 : G_p
->g_rw_sysattr
,
3290 G_p
->g_filesz
, Bufsize
, data_in_info
, holes
);
3292 free_holes_info(holes
);
3294 rv
= data_copy(Ifile
, Ofile
,
3295 (G_p
->g_attrnam_p
== NULL
) ? 0 : G_p
->g_rw_sysattr
,
3296 G_p
->g_filesz
, Bufsize
, data_in_info
);
3300 /* read error or unexpected EOF */
3301 if (data_in_info
->data_in_rd_eof
) {
3303 * read has reached EOF unexpectedly, but this isn't
3304 * an error since it's the latest shape of the file.
3306 msg(EPOST
, "File size of \"%s%s%s\" has decreased",
3307 (G_p
->g_attrnam_p
== NULL
) ?
3308 Nam_p
: G_p
->g_attrfnam_p
,
3309 (G_p
->g_attrnam_p
== NULL
) ? "" :
3310 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
3311 gettext(" Attribute "),
3312 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
3314 /* It's not error. We'll use the new file */
3318 msg(ERRN
, "Cannot read \"%s%s%s\"",
3319 (G_p
->g_attrnam_p
== NULL
) ?
3320 Nam_p
: G_p
->g_attrfnam_p
,
3321 (G_p
->g_attrnam_p
== NULL
) ? "" :
3322 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
3323 gettext(" Attribute "),
3324 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
3326 } else if (rv
> 0) {
3329 msg(ERRN
, "Cannot write \"%s%s%s\"", Over_p
,
3330 (G_p
->g_attrnam_p
== NULL
) ? "" :
3331 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
3332 gettext(" Attribute "),
3333 (G_p
->g_attrnam_p
== NULL
) ? "" : Over_p
);
3335 msg(ERRN
, "Cannot write \"%s%s%s\"",
3337 (G_p
->g_attrnam_p
== NULL
) ? "" :
3338 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
3339 gettext(" Attribute "),
3340 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
);
3347 rstfiles(U_OVER
, G_p
->g_passdirfd
);
3349 rstfiles(U_KEEP
, G_p
->g_passdirfd
);
3352 (void) close(Ifile
);
3353 cstatus
= close(Ofile
);
3356 msg(EXTN
, "close error");
3358 VERBOSE((Args
& (OCv
| OCV
)), Fullnam_p
);
3363 * file_in: Process an object from the archive. If a TARTYP (TAR or USTAR)
3364 * archive and g_nlink == 1, link this file to the file name in t_linkname
3365 * and return. Handle linked files in one of two ways. If Onecopy == 0, this
3366 * is an old style (binary or -c) archive, create and extract the data for the
3367 * first link found, link all subsequent links to this file and skip their data.
3368 * If Oncecopy == 1, save links until all have been processed, and then
3369 * process the links first to last checking their names against the patterns
3370 * and/or asking the user to rename them. The first link that is accepted
3371 * for xtraction is created and the data is read from the archive.
3372 * All subsequent links that are accepted are linked to this file.
3377 struct Lnk
*l_p
, *tl_p
;
3378 int lnkem
= 0, cleanup
= 0;
3388 * Now that we've read the extended header,
3389 * determine if we should restore attributes.
3390 * Don't restore the attribute if we are extracting
3391 * a file from an archive (as opposed to doing a table of
3392 * contents) and any of the following are true:
3393 * 1. neither -@ or -/ was specified.
3394 * 2. -@ was specified, -/ wasn't specified, and we're
3395 * processing a hidden attribute directory of an attribute
3396 * or we're processing a read-write system attribute file.
3397 * 3. -@ wasn't specified, -/ was specified, and the file
3398 * we're processing it not a read-write system attribute file,
3399 * or we're processing the hidden attribute directory of an
3402 * We always process the attributes if we're just generating
3403 * generating a table of contents, or if both -@ and -/ were
3406 if (G_p
->g_attrnam_p
!= NULL
) {
3407 if (((Args
& OCt
) == 0) &&
3408 ((!Atflag
&& !SysAtflag
) ||
3409 (Atflag
&& !SysAtflag
&& ((G_p
->g_attrparent_p
!= NULL
) ||
3410 G_p
->g_rw_sysattr
)) ||
3411 (!Atflag
&& SysAtflag
&& ((G_p
->g_attrparent_p
!= NULL
) ||
3412 !G_p
->g_rw_sysattr
)))) {
3420 * Open target directory if this isn't a skipped file
3423 * Links are handled further down in this function.
3426 proc_file
= ckname(0);
3428 if (proc_file
== F_SKIP
&& G_p
->g_nlink
== 1) {
3430 * Normally ckname() prints out the file as a side
3431 * effect except for table of contents listing
3432 * when its parameter is zero and Onecopy isn't
3433 * Zero. Due to this we need to force the name
3434 * to be printed here.
3437 VERBOSE((Args
& OCt
), G_p
->g_nam_p
);
3443 if (proc_file
!= F_SKIP
&& open_dirfd() != 0) {
3448 if (Hdr_type
== BAR
) {
3455 * For archives in USTAR format, the files are extracted according
3458 if (Hdr_type
== USTAR
|| Hdr_type
== TAR
) {
3459 typeflag
= Thdr_p
->tbuf
.t_typeflag
;
3460 if (G_p
->g_nlink
== 1) { /* hard link */
3461 if (proc_file
!= F_SKIP
) {
3463 char lname
[NAMSIZ
+1];
3464 (void) memset(lname
, '\0', sizeof (lname
));
3466 (void) strncpy(lname
, Thdr_p
->tbuf
.t_linkname
,
3468 for (i
= 0; i
<= NAMSIZ
&& lname
[i
] != 0; i
++)
3472 (void) creat_lnk(G_p
->g_dirfd
,
3473 &lname
[0], G_p
->g_nam_p
);
3478 if (typeflag
== '3' || typeflag
== '4' || typeflag
== '5' ||
3480 if (proc_file
!= F_SKIP
&&
3481 creat_spec(G_p
->g_dirfd
) > 0) {
3482 VERBOSE((Args
& (OCv
| OCV
)),
3483 (G_p
->g_attrparent_p
== NULL
) ?
3484 G_p
->g_nam_p
: G_p
->g_attrpath_p
);
3488 } else if (Adir
|| Aspec
) {
3489 if ((proc_file
== F_SKIP
) ||
3490 (Ofile
= openout(G_p
->g_dirfd
)) < 0) {
3501 if (proc_file
!= F_SKIP
&& creat_spec(G_p
->g_dirfd
) > 0) {
3502 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
3506 VERBOSE((Args
& OCt
), G_p
->g_nam_p
);
3510 if (G_p
->g_nlink
== 1 || (Hdr_type
== TAR
||
3511 Hdr_type
== USTAR
)) {
3513 if (proc_file
!= F_SKIP
&& creat_spec(G_p
->g_dirfd
) > 0)
3514 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
3516 if ((proc_file
== F_SKIP
) ||
3517 (Ofile
= openout(G_p
->g_dirfd
)) < 0) {
3528 tl_p
= add_lnk(&ttl_p
);
3530 if (l_p
->L_cnt
== l_p
->L_gen
.g_nlink
)
3532 if (!Onecopy
|| G_p
->g_attrnam_p
!= NULL
) {
3533 lnkem
= (tl_p
!= l_p
) ? 1 : 0;
3535 if (proc_file
== F_SKIP
) {
3538 if (open_dirfd() != 0)
3542 if (creat_spec(G_p
->g_dirfd
) > 0)
3543 VERBOSE((Args
& (OCv
| OCV
)),
3546 openout(G_p
->g_dirfd
)) < 0) {
3556 * Are we linking an attribute?
3559 if (l_p
->L_gen
.g_attrnam_p
!= NULL
) {
3560 (void) strcpy(Lnkend_p
,
3561 l_p
->L_gen
.g_attrnam_p
);
3562 (void) strcpy(Full_p
,
3563 tl_p
->L_gen
.g_attrnam_p
);
3565 (void) fchdir(G_p
->g_dirfd
);
3567 (void) strcpy(Lnkend_p
,
3568 l_p
->L_gen
.g_nam_p
);
3569 (void) strcpy(Full_p
,
3570 tl_p
->L_gen
.g_nam_p
);
3572 (void) creat_lnk(G_p
->g_dirfd
,
3576 l_p
->L_lnk_p
= NULL
;
3577 free(tl_p
->L_gen
.g_nam_p
);
3583 } else { /* Onecopy */
3584 if (tl_p
->L_gen
.g_filesz
)
3588 return; /* don't do anything yet */
3592 * ckname will clear aclchar. We need to keep aclchar for
3596 while (tl_p
!= NULL
) {
3599 if ((proc_file
= ckname(1)) != F_SKIP
) {
3600 if (open_dirfd() != 0) {
3604 (void) creat_lnk(G_p
->g_dirfd
,
3608 (void) creat_spec(G_p
->g_dirfd
);
3610 VERBOSE((Args
& (OCv
| OCV
)),
3613 openout(G_p
->g_dirfd
)) < 0) {
3619 } /* (proc_file = ckname(1)) != F_SKIP */
3621 tl_p
= tl_p
->L_lnk_p
;
3625 if (proc_file
== F_SKIP
&& !cleanup
) {
3626 tl_p
->L_nxt_p
= l_p
->L_nxt_p
;
3627 tl_p
->L_bck_p
= l_p
->L_bck_p
;
3628 l_p
->L_bck_p
->L_nxt_p
= tl_p
;
3629 l_p
->L_nxt_p
->L_bck_p
= tl_p
;
3630 free(l_p
->L_gen
.g_nam_p
);
3633 } /* tl_p->L_lnk_p != NULL */
3634 if (l_p
->L_data
== 0) {
3644 * file_out: If the current file is not a special file (!Aspec) and it
3645 * is identical to the archive, skip it (do not archive the archive if it
3646 * is a regular file). If creating a TARTYP (TAR or USTAR) archive, the first
3647 * time a link to a file is encountered, write the header and file out normally.
3648 * Subsequent links to this file put this file name in their t_linkname field.
3649 * Otherwise, links are handled in one of two ways, for the old headers
3650 * (i.e. binary and -c), linked files are written out as they are encountered.
3651 * For the new headers (ASC and CRC), links are saved up until all the links
3652 * to each file are found. For a file with n links, write n - 1 headers with
3653 * g_filesz set to 0, write the final (nth) header with the correct g_filesz
3654 * value and write the data for the file to the archive.
3660 struct Lnk
*l_p
, *tl_p
;
3665 if (!Aspec
&& IDENT(SrcSt
, ArchSt
))
3666 return (1); /* do not archive the archive if it's a reg file */
3668 * If compressing sparse files, wait until the compressed file size
3669 * is known to check if file size is too big.
3671 if (Compress_sparse
== 0 && G_p
->g_filesz
> Max_offset
) {
3672 msg(ERR
, "%s%s%s: too large to archive in current mode",
3674 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_rw_sysattr
?
3675 gettext(" System Attribute ") : gettext(" Attribute "),
3676 (G_p
->g_attrnam_p
== NULL
) ? "" :
3677 ((G_p
->g_attrparent_p
== NULL
) ? G_p
->g_attrnam_p
:
3678 G_p
->g_attrpath_p
));
3679 return (1); /* do not archive if it's too big */
3681 if (Hdr_type
== TAR
|| Hdr_type
== USTAR
) { /* TAR and USTAR */
3683 if (Gen
.g_attrnam_p
!= NULL
) {
3686 write_hdr(ARCHIVE_NORMAL
, 0);
3689 if (G_p
->g_nlink
== 1) {
3693 tl_p
= add_lnk(&ttl_p
);
3695 if (tl_p
== l_p
) { /* first link to this file encountered */
3699 (void) strncpy(T_lname
, l_p
->L_gen
.g_nam_p
,
3700 l_p
->L_gen
.g_namesz
);
3703 * check if linkname is greater than 100 characters
3705 if (strlen(T_lname
) > NAMSIZ
) {
3706 msg(EPOST
, "cpio: %s: linkname %s is greater than %d",
3707 G_p
->g_nam_p
, T_lname
, NAMSIZ
);
3711 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3712 VERBOSE((Args
& (OCv
| OCV
)), tl_p
->L_gen
.g_nam_p
);
3714 /* find the lnk entry in sublist, unlink it, and free it */
3715 for (; ttl_p
->L_lnk_p
!= NULL
;
3716 ttl_p
= ttl_p
->L_lnk_p
) {
3717 if (ttl_p
->L_lnk_p
== tl_p
) {
3718 ttl_p
->L_lnk_p
= tl_p
->L_lnk_p
;
3719 free(tl_p
->L_gen
.g_nam_p
);
3729 * ACL has been retrieved in getname().
3732 char *secinfo
= NULL
;
3735 /* append security attributes */
3736 if ((append_secattr(&secinfo
, &len
, aclp
)) == -1)
3737 msg(ERR
, "can create security information");
3739 /* call append_secattr() if more than one */
3742 /* write ancillary */
3743 write_hdr(ARCHIVE_ACL
, (off_t
)len
);
3744 write_ancillary(secinfo
, len
, B_TRUE
);
3748 if (Gen
.g_attrnam_p
!= NULL
) {
3751 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3752 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
3755 if (G_p
->g_nlink
== 1) {
3759 tl_p
= add_lnk(&ttl_p
);
3762 if (l_p
->L_cnt
== l_p
->L_gen
.g_nlink
)
3764 else if (Onecopy
&& G_p
->g_attrnam_p
== NULL
) {
3765 return (0); /* don't process data yet */
3768 if (Onecopy
&& G_p
->g_attrnam_p
== NULL
) {
3770 while (tl_p
->L_lnk_p
!= NULL
) {
3772 G_p
->g_filesz
= (off_t
)0;
3773 /* one link with the acl is sufficient */
3774 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
3775 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
3776 tl_p
= tl_p
->L_lnk_p
;
3779 if (open_dirfd() != 0)
3782 /* old style: has acl and data for every link */
3790 * Verify the underlying file system supports the attribute type.
3791 * Only archive extended attribute files when '-@' was specified.
3792 * Only archive system extended attribute files if '-/' was specified.
3794 #if defined(O_XATTR)
3795 static attr_status_t
3796 verify_attr_support(char *filename
, int attrflg
, arc_action_t actflag
,
3800 * Verify extended attributes are supported/exist. We only
3801 * need to check if we are processing a base file, not an
3802 * extended attribute.
3805 *ext_attrflg
= (pathconf(filename
, (actflag
== ARC_CREATE
) ?
3806 _PC_XATTR_EXISTS
: _PC_XATTR_ENABLED
) == 1);
3809 #if defined(_PC_SATTR_ENABLED)
3810 if (!*ext_attrflg
) {
3812 /* Verify system attributes are supported */
3813 if (sysattr_support(filename
,
3814 (actflag
== ARC_CREATE
) ?_PC_SATTR_EXISTS
:
3815 _PC_SATTR_ENABLED
) != 1) {
3816 return (ATTR_SATTR_ERR
);
3819 return (ATTR_XATTR_ERR
);
3821 return (ATTR_XATTR_ERR
);
3822 #endif /* _PC_SATTR_ENABLED */
3825 #if defined(_PC_SATTR_ENABLED)
3826 } else if (SysAtflag
) {
3827 /* Verify system attributes are supported */
3828 if (sysattr_support(filename
, (actflag
== ARC_CREATE
) ?
3829 _PC_SATTR_EXISTS
: _PC_SATTR_ENABLED
) != 1) {
3830 return (ATTR_SATTR_ERR
);
3832 #endif /* _PC_SATTR_ENABLED */
3841 #if defined(O_XATTR)
3843 * Verify the attribute, attrname, is an attribute we want to restore.
3844 * Never restore read-only system attribute files. Only restore read-write
3845 * system attributes files when -/ was specified, and only traverse into
3846 * the 2nd level attribute directory containing only system attributes if
3847 * -@ was specified. This keeps us from archiving
3848 * <attribute name>/<read-write system attribute file>
3849 * when -/ was specified without -@.
3851 * attrname - attribute file name
3852 * attrparent - attribute's parent name within the base file's
3853 * attribute digrectory hierarchy
3854 * arc_rwsysattr - flag that indicates that read-write system attribute
3855 * file should be archived as it contains other than
3856 * the default system attributes.
3857 * rw_sysattr - on return, flag will indicate if attrname is a
3858 * read-write system attribute file.
3860 static attr_status_t
3861 verify_attr(char *attrname
, char *attrparent
, int arc_rwsysattr
,
3864 #if defined(_PC_SATTR_ENABLED)
3867 /* Never restore read-only system attribute files */
3868 if ((attr_supported
= sysattr_type(attrname
)) == _RO_SATTR
) {
3872 *rw_sysattr
= (attr_supported
== _RW_SATTR
);
3876 * Don't archive a read-write system attribute file if
3877 * it contains only the default system attributes.
3879 if (*rw_sysattr
&& !arc_rwsysattr
) {
3884 /* Never restore read-only system attribute files */
3885 if ((*rw_sysattr
= is_sysattr(attrname
)) == 1) {
3888 #endif /* _PC_SATTR_ENABLED */
3891 * Only restore read-write system attribute files
3892 * when -/ was specified. Only restore extended
3893 * attributes when -@ was specified.
3898 * Only archive/restore the hidden directory "." if
3899 * we're processing the top level hidden attribute
3900 * directory. We don't want to process the
3901 * hidden attribute directory of the attribute
3902 * directory that contains only extended system
3905 if (*rw_sysattr
|| (Hiddendir
&&
3906 (attrparent
!= NULL
))) {
3910 } else if (SysAtflag
) {
3912 * Only archive/restore read-write extended system attribute
3913 * files of the base file.
3915 if (!*rw_sysattr
|| (attrparent
!= NULL
)) {
3926 #if defined(O_XATTR)
3928 retry_open_attr(int pdirfd
, int cwd
, char *fullname
, char *pattr
, char *name
,
3929 int oflag
, mode_t mode
)
3933 struct timeval times
[2];
3935 struct stat parentstat
;
3940 * We couldn't get to attrdir. See if its
3941 * just a mode problem on the parent file.
3942 * for example: a mode such as r-xr--r--
3943 * on a ufs file system without extended
3944 * system attribute support won't let us
3945 * create an attribute dir if it doesn't
3946 * already exist, and on a ufs file system
3947 * with extended system attribute support
3948 * won't let us open the attribute for
3951 * If file has a non-trivial ACL, then save it
3952 * off so that we can place it back on after doing
3955 if ((dirfd
= openat(cwd
, (pattr
== NULL
) ? fullname
: pattr
,
3959 if (fstat(dirfd
, &parentstat
) == -1) {
3960 msg(ERRN
, "Cannot stat %sfile %s",
3961 (pdirfd
== -1) ? "" : gettext("parent of "),
3962 (pdirfd
== -1) ? fullname
: name
);
3963 (void) close(dirfd
);
3966 if ((error
= facl_get(dirfd
, ACL_NO_TRIVIAL
, &aclp
)) != 0) {
3967 msg(ERRN
, "Failed to retrieve ACL on %sfile %s",
3968 (pdirfd
== -1) ? "" : gettext("parent of "),
3969 (pdirfd
== -1) ? fullname
: name
);
3970 (void) close(dirfd
);
3974 newmode
= S_IWUSR
| parentstat
.st_mode
;
3975 if (fchmod(dirfd
, newmode
) == -1) {
3976 msg(ERRN
, "Cannot change mode of %sfile %s to %o",
3977 (pdirfd
== -1) ? "" : gettext("parent of "),
3978 (pdirfd
== -1) ? fullname
: name
, newmode
);
3981 (void) close(dirfd
);
3988 * We weren't able to create the attribute directory before.
3991 ofilefd
= attropen(fullname
, ".", oflag
);
3994 * We weren't able to create open the attribute before.
3997 ofilefd
= openat(pdirfd
, name
, oflag
, mode
);
4001 * Put mode back to original
4003 if (fchmod(dirfd
, parentstat
.st_mode
) == -1) {
4004 msg(ERRN
, "Cannot restore permissions of %sfile %s to %o",
4005 (pdirfd
== -1) ? "" : gettext("parent of "),
4006 (pdirfd
== -1) ? fullname
: name
, newmode
);
4010 error
= facl_set(dirfd
, aclp
);
4012 msg(ERRN
, "failed to set acl entries on %sfile %s\n",
4013 (pdirfd
== -1) ? "" : gettext("parent of "),
4014 (pdirfd
== -1) ? fullname
: name
);
4020 * Put back time stamps
4023 times
[0].tv_sec
= parentstat
.st_atime
;
4024 times
[0].tv_usec
= 0;
4025 times
[1].tv_sec
= parentstat
.st_mtime
;
4026 times
[1].tv_usec
= 0;
4028 (void) futimesat(cwd
, (pattr
== NULL
) ? fullname
: pattr
, times
);
4030 (void) close(dirfd
);
4036 #if defined(O_XATTR)
4038 * Recursively open attribute directories until the attribute directory
4039 * containing the specified attribute, attrname, is opened.
4041 * Currently, only 2 directory levels of attributes are supported, (i.e.,
4042 * extended system attributes on extended attributes). The following are
4043 * the possible input combinations:
4044 * 1. Open the attribute directory of the base file (don't change
4046 * attr_parent = NULL
4048 * 2. Open the attribute directory of the base file and change into it.
4049 * attr_parent = NULL
4050 * attrname = <attr> | <sys_attr>
4051 * 3. Open the attribute directory of the base file, change into it,
4052 * then recursively call open_attr_dir() to open the attribute's
4053 * parent directory (don't change into it).
4054 * attr_parent = <attr>
4056 * 4. Open the attribute directory of the base file, change into it,
4057 * then recursively call open_attr_dir() to open the attribute's
4058 * parent directory and change into it.
4059 * attr_parent = <attr>
4060 * attrname = <attr> | <sys_attr>
4062 * An attribute directory will be opened only if the underlying file system
4063 * supports the attribute type, and if the command line specifications
4064 * (f_extended_attr and f_sys_attr) enable the processing of the attribute
4067 * On succesful return, attr_parentfd will be the file descriptor of the
4068 * opened attribute directory. In addition, if the attribute is a read-write
4069 * extended system attribute, rw_sysattr will be set to 1, otherwise
4070 * it will be set to 0.
4072 * Possible return values:
4073 * ATTR_OK Successfully opened and, if needed, changed into the
4074 * attribute directory containing attrname.
4075 * ATTR_SKIP The command line specifications don't enable the
4076 * processing of the attribute type.
4077 * ATTR_CHDIR_ERR An error occurred while trying to change into an
4078 * attribute directory.
4079 * ATTR_OPEN_ERR An error occurred while trying to open an
4080 * attribute directory.
4081 * ATTR_XATTR_ERR The underlying file system doesn't support extended
4083 * ATTR_SATTR_ERR The underlying file system doesn't support extended
4084 * system attributes.
4087 open_attr_dir(char *attrname
, char *dirp
, int cwd
, char *attr_parent
,
4088 int *attr_parentfd
, int *rw_sysattr
)
4091 int firsttime
= (*attr_parentfd
== -1);
4096 * open_attr_dir() was recursively called (input combination number 4),
4097 * close the previously opened file descriptor as we've already changed
4101 (void) close(*attr_parentfd
);
4102 *attr_parentfd
= -1;
4106 * Verify that the underlying file system supports the restoration
4109 if ((rc
= verify_attr_support(dirp
, firsttime
, ARC_RESTORE
,
4110 &ext_attr
)) != ATTR_OK
) {
4114 /* Open the base file's attribute directory */
4115 if ((*attr_parentfd
= attropen(dirp
, ".", O_RDONLY
)) == -1) {
4117 * Save the errno from the attropen so it can be reported
4118 * if the retry of the attropen fails.
4121 if ((*attr_parentfd
= retry_open_attr(-1, cwd
, dirp
,
4122 NULL
, ".", O_RDONLY
, 0)) == -1) {
4123 (void) close(*attr_parentfd
);
4124 *attr_parentfd
= -1;
4126 return (ATTR_OPEN_ERR
);
4131 * Change into the parent attribute's directory unless we are
4132 * processing the hidden attribute directory of the base file itself.
4134 if ((Hiddendir
== 0) || (firsttime
&& (attr_parent
!= NULL
))) {
4135 if (fchdir(*attr_parentfd
) != 0) {
4137 (void) close(*attr_parentfd
);
4138 *attr_parentfd
= -1;
4140 return (ATTR_CHDIR_ERR
);
4144 /* Determine if the attribute should be processed */
4145 if ((rc
= verify_attr(attrname
, attr_parent
, 1,
4146 rw_sysattr
)) != ATTR_OK
) {
4148 (void) close(*attr_parentfd
);
4149 *attr_parentfd
= -1;
4155 * If the attribute is an extended system attribute of an attribute
4156 * (i.e., <attr>/<sys_attr>), then recursively call open_attr_dir() to
4157 * open the attribute directory of the parent attribute.
4159 if (firsttime
&& (attr_parent
!= NULL
)) {
4160 return (open_attr_dir(attrname
, attr_parent
, *attr_parentfd
,
4161 attr_parent
, attr_parentfd
, rw_sysattr
));
4169 * file_pass: If the -l option is set (link files when possible), and the
4170 * source and destination file systems are the same, link the source file
4171 * (G_p->g_nam_p) to the destination file (Fullnam) and return. If not a
4172 * linked file, transfer the data. Otherwise, the first link to a file
4173 * encountered is transferred normally and subsequent links are linked to it.
4179 struct Lnk
*l_p
, *tl_p
;
4188 if (Adir
&& !(Args
& OCd
)) {
4189 msg(ERR
, "Use -d option to copy \"%s\"", G_p
->g_nam_p
);
4190 return (FILE_PASS_ERR
);
4193 save_name
= G_p
->g_nam_p
;
4195 while (*(G_p
->g_nam_p
) == '/') {
4199 (void) strcpy(Full_p
, (G_p
->g_attrfnam_p
== NULL
) ?
4200 G_p
->g_nam_p
: G_p
->g_attrfnam_p
);
4202 if (G_p
->g_attrnam_p
== NULL
) {
4203 G_p
->g_passdirfd
= open_dir(Fullnam_p
);
4205 if (G_p
->g_passdirfd
== -1) {
4207 "Cannot open/create \"%s\"", Fullnam_p
);
4208 return (FILE_PASS_ERR
);
4214 * Open the file's attribute directory.
4215 * Change into the base file's starting directory then call
4216 * open_attr_dir() to open the attribute directory of either
4217 * the base file (if G_p->g_attrparent_p is NULL) or the
4218 * attribute (if G_p->g_attrparent_p is set) of the base file.
4221 G_p
->g_passdirfd
= -1;
4222 (void) fchdir(G_p
->g_baseparent_fd
);
4223 (void) open_attr_dir(G_p
->g_attrnam_p
, Fullnam_p
,
4224 G_p
->g_baseparent_fd
, (G_p
->g_attrparent_p
== NULL
) ? NULL
:
4225 G_p
->g_attrparent_p
, &G_p
->g_passdirfd
, &rw_sysattr
);
4226 if (G_p
->g_passdirfd
== -1) {
4228 "Cannot open attribute directory of "
4229 "%s%s%sfile \"%s\"",
4230 (G_p
->g_attrparent_p
== NULL
) ? "" :
4231 gettext("attribute \""),
4232 (G_p
->g_attrparent_p
== NULL
) ? "" :
4233 G_p
->g_attrparent_p
,
4234 (G_p
->g_attrparent_p
== NULL
) ? "" :
4235 gettext("\" of "), Fullnam_p
);
4236 return (FILE_PASS_ERR
);
4241 /* We are linking back to the source directory. */
4244 char *existingfile
= save_name
;
4246 if ((Args
& OCL
) && issymlink
) {
4247 /* We are chasing symlinks. */
4249 if ((size
= readlink(save_name
, Symlnk_p
,
4252 "Cannot read symbolic link \"%s\"",
4254 return (FILE_PASS_ERR
);
4257 Symlnk_p
[size
] = '\0';
4258 existingfile
= Symlnk_p
;
4261 if (G_p
->g_attrnam_p
== NULL
) {
4262 if (creat_lnk(G_p
->g_passdirfd
,
4263 existingfile
, Fullnam_p
) == 0) {
4264 return (FILE_LINKED
);
4270 if ((G_p
->g_mode
& Ftype
) == S_IFLNK
&& !(Args
& OCL
)) {
4271 /* The archive file is a symlink. */
4275 if ((size
= readlink(save_name
, Symlnk_p
, MAXPATHLEN
)) < 0) {
4277 "Cannot read symbolic link \"%s\"", save_name
);
4278 return (FILE_PASS_ERR
);
4282 (void) missdir(Fullnam_p
);
4283 *(Symlnk_p
+ size
) = '\0';
4285 if (symlink(Symlnk_p
, Fullnam_p
) < 0) {
4286 if (errno
== EEXIST
) {
4287 if (openout(G_p
->g_passdirfd
) < 0) {
4288 if (errno
!= EEXIST
) {
4290 "Cannot create \"%s\"",
4293 return (FILE_PASS_ERR
);
4296 msg(ERRN
, "Cannot create \"%s\"", Fullnam_p
);
4297 return (FILE_PASS_ERR
);
4301 if (lchown(Fullnam_p
, (int)Rpw_p
->pw_uid
,
4302 (int)Rpw_p
->pw_gid
) < 0) {
4304 "Error during chown() of \"%s\"",
4307 } else if ((lchown(Fullnam_p
, (int)G_p
->g_uid
,
4308 (int)G_p
->g_gid
) < 0) && privileged
) {
4310 "Error during chown() of \"%s\"",
4315 VERBOSE((Args
& (OCv
| OCV
)), Fullnam_p
);
4316 return (FILE_PASS_ERR
);
4319 if (!Adir
&& G_p
->g_nlink
> 1) {
4320 /* The archive file has hard links. */
4322 tl_p
= add_lnk(&ttl_p
);
4326 /* The archive file was not found. */
4330 /* The archive file was found. */
4334 if (l_p
->L_gen
.g_attrnam_p
!= NULL
) {
4335 /* We are linking an attribute */
4337 (void) strcpy(Lnkend_p
, l_p
->L_gen
.g_attrnam_p
);
4339 (void) fchdir(G_p
->g_passdirfd
);
4340 lfrom
= get_component(Lnknam_p
);
4341 lto
= tl_p
->L_gen
.g_attrnam_p
;
4343 /* We are not linking an attribute */
4345 (void) strcpy(Lnkend_p
, l_p
->L_gen
.g_nam_p
);
4346 (void) strcpy(Full_p
, tl_p
->L_gen
.g_nam_p
);
4351 (void) creat_lnk(G_p
->g_passdirfd
, lfrom
, lto
);
4357 l_p
->L_lnk_p
= NULL
;
4358 free(tl_p
->L_gen
.g_nam_p
);
4361 if (l_p
->L_cnt
== G_p
->g_nlink
) {
4365 return (FILE_LINKED
);
4369 if (Adir
|| Aspec
) {
4371 * The archive file is a directory, block special, char
4372 * special or a fifo.
4375 if (creat_spec(G_p
->g_passdirfd
) > 0) {
4376 VERBOSE((Args
& (OCv
| OCV
)), Fullnam_p
);
4378 } else if ((Ofile
= openout(G_p
->g_passdirfd
)) > 0) {
4382 return (FILE_COPIED
);
4386 * flush_lnks: With new linked file handling, linked files are not archived
4387 * until all links have been collected. When the end of the list of filenames
4388 * to archive has been reached, all files that did not encounter all their links
4389 * are written out with actual (encountered) link counts. A file with n links
4390 * (that are archived) will be represented by n headers (one for each link (the
4391 * first n - 1 have g_filesz set to 0)) followed by the data for the file.
4397 struct Lnk
*l_p
, *tl_p
;
4400 l_p
= Lnk_hd
.L_nxt_p
;
4401 while (l_p
!= &Lnk_hd
) {
4402 (void) strcpy(Gen
.g_nam_p
, l_p
->L_gen
.g_nam_p
);
4403 if (stat(Gen
.g_nam_p
, &SrcSt
) == 0) { /* check if file exists */
4406 Gen
.g_nlink
= l_p
->L_cnt
; /* "actual" link count */
4407 tfsize
= Gen
.g_filesz
;
4408 Gen
.g_filesz
= (off_t
)0;
4410 while (tl_p
!= NULL
) {
4411 Gen
.g_nam_p
= tl_p
->L_gen
.g_nam_p
;
4412 Gen
.g_namesz
= tl_p
->L_gen
.g_namesz
;
4413 if (tl_p
->L_lnk_p
== NULL
) {
4414 Gen
.g_filesz
= tfsize
;
4415 if (open_dirfd() != 0) {
4421 write_hdr(ARCHIVE_NORMAL
,
4422 (off_t
)0); /* header only */
4423 VERBOSE((Args
& (OCv
| OCV
)), Gen
.g_nam_p
);
4424 tl_p
= tl_p
->L_lnk_p
;
4426 Gen
.g_nam_p
= Nam_p
;
4427 } else /* stat(Gen.g_nam_p, &SrcSt) == 0 */
4428 msg(ERR
, "\"%s%s%s\" has disappeared",
4429 (Gen
.g_attrnam_p
== NULL
) ?
4430 Gen
.g_nam_p
: Gen
.g_attrfnam_p
,
4431 (Gen
.g_attrnam_p
== NULL
) ?
4432 "" : Gen
.g_rw_sysattr
?
4433 gettext(" System Attribute ") :
4434 gettext(" Attribute "),
4435 (Gen
.g_attrnam_p
== NULL
) ?
4436 "" : Gen
.g_attrnam_p
);
4440 } /* l_p != &Lnk_hd */
4443 #if defined(O_XATTR)
4445 is_sysattr(char *name
)
4447 return ((strcmp(name
, VIEW_READONLY
) == 0) ||
4448 (strcmp(name
, VIEW_READWRITE
) == 0));
4453 * gethdr: Get a header from the archive, validate it and check for the trailer.
4454 * Any user specified Hdr_type is ignored (set to NONE in main). Hdr_type is
4455 * set appropriately after a valid header is found. Unless the -k option is
4456 * set a corrupted header causes an exit with an error. I/O errors during
4457 * examination of any part of the header cause gethdr to throw away any current
4458 * data and start over. Other errors during examination of any part of the
4459 * header cause gethdr to advance one byte and continue the examination.
4466 int hit
= NONE
, cnt
= 0;
4467 int goodhdr
, hsize
, offset
;
4475 Gen
.g_nam_p
= Nam_p
;
4476 do { /* hit == NONE && (Args & OCk) && Buffr.b_cnt > 0 */
4481 Binmag
.b_byte
[0] = Buffr
.b_out_p
[0];
4482 Binmag
.b_byte
[1] = Buffr
.b_out_p
[1];
4483 if ((Binmag
.b_half
== CMN_BIN
) ||
4484 (Binmag
.b_half
== CMN_BBS
)) {
4485 hit
= read_hdr(BIN
);
4486 if (Hdr_type
== NONE
)
4488 hsize
= HDRSZ
+ Gen
.g_namesz
;
4491 if (Hdr_type
!= NONE
)
4495 if (!(strncmp(Buffr
.b_out_p
, CMS_CHR
, CMS_LEN
))) {
4496 hit
= read_hdr(CHR
);
4497 hsize
= CHRSZ
+ Gen
.g_namesz
;
4500 if (Hdr_type
!= NONE
)
4504 if (!(strncmp(Buffr
.b_out_p
, CMS_ASC
, CMS_LEN
))) {
4505 hit
= read_hdr(ASC
);
4506 hsize
= ASCSZ
+ Gen
.g_namesz
;
4510 if (Hdr_type
!= NONE
)
4514 if (!(strncmp(Buffr
.b_out_p
, CMS_CRC
, CMS_LEN
))) {
4515 hit
= read_hdr(CRC
);
4516 hsize
= ASCSZ
+ Gen
.g_namesz
;
4520 if (Hdr_type
!= NONE
)
4525 if (Hdr_p
!= NULL
&& strcmp(Hdr_p
, "bar") == 0) {
4528 if ((hit
= read_hdr(BAR
)) == NONE
) {
4539 if (Hdr_p
!= NULL
&& strcmp(Hdr_p
, "ustar") == 0) {
4542 if ((hit
= read_hdr(USTAR
)) == NONE
) {
4552 if (Hdr_p
!= NULL
&& strcmp(Hdr_p
, "tar") == 0) {
4555 if ((hit
= read_hdr(TAR
)) == NONE
) {
4565 msg(EXT
, "Impossible header type.");
4568 if (hit
== TAR
|| hit
== USTAR
) {
4569 Gen
.g_nam_p
= &nambuf
[0];
4575 if (Gen
.g_filesz
< (off_t
)0 || Gen
.g_namesz
< 1)
4577 if ((hit
!= USTAR
) && (hit
!= TAR
))
4578 if (Gen
.g_namesz
- 1 > Max_namesz
)
4581 if ((hit
== USTAR
) || (hit
== TAR
)) {
4582 if (*Gen
.g_nam_p
== '\0') { /* tar trailer */
4588 cksum(TARTYP
, 0, NULL
)) {
4591 "Bad header - checksum "
4595 } else if (hit
!= BAR
) { /* binary, -c, ASC and CRC */
4596 if (Gen
.g_nlink
<= (ulong_t
)0)
4598 if (*(Buffr
.b_out_p
+ hsize
- 1) != '\0')
4606 "Corrupt header, file(s) may be lost.");
4617 msg(ERR
, "Searching for magic number/header.");
4619 } while (hit
== NONE
);
4621 if (Hdr_type
== NONE
)
4622 msg(EXT
, "Not a cpio file, bad header.");
4624 msg(EXT
, "Bad magic number/header.");
4625 } else if (cnt
> 0) {
4626 msg(EPOST
, "Re-synchronized on magic number/header.");
4628 if (Hdr_type
== NONE
) {
4654 Max_namesz
= HNAMLEN
- 1;
4661 Max_namesz
= TNAMLEN
- 1;
4666 msg(EXT
, "Impossible header type.");
4668 } /* Hdr_type == NONE */
4669 if ((Hdr_type
== USTAR
) || (Hdr_type
== TAR
) ||
4670 (Hdr_type
== BAR
)) { /* TAR, USTAR, BAR */
4672 if (Gen
.g_nam_p
[0] == '\0')
4675 preptr
= &prebuf
[0];
4676 if (*preptr
!= NULL
) {
4677 k
= strlen(&prebuf
[0]);
4679 (void) strcpy(&fullnam
[0], &prebuf
[0]);
4682 while ((j
< NAMSIZ
) && (&nambuf
[j
] !=
4684 fullnam
[k
] = nambuf
[j
];
4688 } else if (k
>= PRESIZ
) {
4690 while ((k
< PRESIZ
) && (prebuf
[k
] !=
4692 fullnam
[k
] = prebuf
[k
];
4697 while ((j
< NAMSIZ
) && (nambuf
[j
] !=
4699 fullnam
[k
] = nambuf
[j
];
4704 Gen
.g_nam_p
= &fullnam
[0];
4706 Gen
.g_nam_p
= &nambuf
[0];
4709 * initialize the buffer so that the prefix will not
4710 * applied to the next entry in the archive
4712 (void) memset(prebuf
, 0, sizeof (prebuf
));
4714 } else if (Hdr_type
!= BAR
) {
4715 (void) memcpy(Gen
.g_nam_p
, Buffr
.b_out_p
+ Hdrsz
, Gen
.g_namesz
);
4716 if (!(strcmp(Gen
.g_nam_p
, "TRAILER!!!")))
4719 offset
= ((hsize
+ Pad_val
) & ~Pad_val
);
4720 FILL(offset
+ Hdrsz
);
4721 Thdr_p
= (union tblock
*)Buffr
.b_out_p
;
4722 Buffr
.b_out_p
+= offset
;
4723 Buffr
.b_cnt
-= (off_t
)offset
;
4724 ftype
= Gen
.g_mode
& Ftype
;
4726 #if defined(O_XATTR)
4727 /* extended attribute support */
4728 if (((Gen
.g_mode
& S_IFMT
) == _XATTR_CPIO_MODE
) ||
4729 ((Hdr_type
== USTAR
|| Hdr_type
== TAR
) &&
4730 Thdr_p
->tbuf
.t_typeflag
== _XATTR_HDRTYPE
)) {
4732 char *attrparent
= NULL
;
4733 char *attrpath
= NULL
;
4737 if (xattrp
!= NULL
) {
4747 * At this point, the attribute path contains
4748 * the path to the attribute rooted at the hidden
4749 * attribute directory of the base file. This can
4750 * be a simple attribute or extended attribute name,
4751 * or it can be something like <attr>/<sys attr> if
4752 * we are processing a system attribute of an attribute.
4753 * Determine the attribute name and attribute parent
4754 * (if there is one). When we are processing a simple
4755 * attribute or extended attribute name, the attribute
4756 * parent will be set to NULL. When we are processing
4757 * something like <attr>/<sys attr>, the attribute
4758 * parent will be contain <attr>, and the attribute
4759 * name will contain <sys attr>.
4761 tapath
= xattrp
->h_names
+
4762 strlen(xattrp
->h_names
) + 1;
4763 attrpath
= e_strdup(E_EXIT
, tapath
);
4764 if ((taname
= strpbrk(tapath
, "/")) != NULL
) {
4767 attrparent
= tapath
;
4772 Gen
.g_rw_sysattr
= is_sysattr(aname
);
4773 Gen
.g_baseparent_fd
= attr_baseparent_fd
;
4775 if (Gen
.g_attrfnam_p
!= NULL
) {
4776 free(Gen
.g_attrfnam_p
);
4777 Gen
.g_attrfnam_p
= NULL
;
4779 if (Gen
.g_attrnam_p
!= NULL
) {
4780 free(Gen
.g_attrnam_p
);
4781 Gen
.g_attrnam_p
= NULL
;
4783 if (Gen
.g_attrparent_p
!= NULL
) {
4784 free(Gen
.g_attrparent_p
);
4785 Gen
.g_attrparent_p
= NULL
;
4787 if (Gen
.g_attrpath_p
!= NULL
) {
4788 free(Gen
.g_attrpath_p
);
4789 Gen
.g_attrpath_p
= NULL
;
4791 if (Renam_p
&& Renam_p
[0] != '\0') {
4792 Gen
.g_attrfnam_p
= e_strdup(E_EXIT
, Renam_p
);
4794 Gen
.g_attrfnam_p
= e_strdup(E_EXIT
,
4797 Gen
.g_attrnam_p
= e_strdup(E_EXIT
, aname
);
4799 if (attrparent
!= NULL
) {
4800 if (Renam_attr_p
&& Renam_attr_p
[0] != '\0') {
4801 size_t apathlen
= strlen(attrparent
) +
4803 Gen
.g_attrparent_p
= e_strdup(E_EXIT
,
4805 Gen
.g_attrpath_p
= e_zalloc(E_EXIT
,
4807 (void) snprintf(Gen
.g_attrpath_p
,
4808 apathlen
, "%s/%s", Renam_attr_p
,
4810 (void) free(attrparent
);
4811 (void) free(attrpath
);
4813 Gen
.g_attrparent_p
= attrparent
;
4814 Gen
.g_attrpath_p
= attrpath
;
4817 Gen
.g_attrpath_p
= attrpath
;
4820 if (xattr_linkp
!= NULL
) {
4821 if (Gen
.g_linktoattrfnam_p
!= NULL
) {
4822 free(Gen
.g_linktoattrfnam_p
);
4823 Gen
.g_linktoattrfnam_p
= NULL
;
4825 if (Gen
.g_linktoattrnam_p
!= NULL
) {
4826 free(Gen
.g_linktoattrnam_p
);
4827 Gen
.g_linktoattrnam_p
= NULL
;
4829 if (Renam_attr_p
&& Renam_attr_p
[0] != '\0') {
4830 Gen
.g_linktoattrfnam_p
= e_strdup(
4831 E_EXIT
, Renam_attr_p
);
4833 Gen
.g_linktoattrfnam_p
= e_strdup(
4834 E_EXIT
, xattr_linkp
->h_names
);
4836 Gen
.g_linktoattrnam_p
= e_strdup(E_EXIT
,
4840 if (Hdr_type
!= USTAR
&& Hdr_type
!= TAR
) {
4841 Gen
.g_mode
= Gen
.g_mode
& (~_XATTR_CPIO_MODE
);
4842 Gen
.g_mode
|= attrmode(xattrp
->h_typeflag
);
4843 } else if (Hdr_type
== USTAR
|| Hdr_type
== TAR
) {
4844 Thdr_p
->tbuf
.t_typeflag
= xattrp
->h_typeflag
;
4847 ftype
= Gen
.g_mode
& Ftype
;
4848 Adir
= ftype
== S_IFDIR
;
4849 Aspec
= (ftype
== S_IFBLK
|| ftype
== S_IFCHR
||
4850 ftype
== S_IFIFO
|| ftype
== S_IFSOCK
);
4852 if (Gen
.g_attrnam_p
[0] == '.' &&
4853 Gen
.g_attrnam_p
[1] == '\0' &&
4854 xattrp
->h_typeflag
== DIRTYPE
) {
4864 if (xattrbadhead
== 0) {
4865 (void) read_xattr_hdr();
4872 #endif /* O_XATTR */
4874 /* acl support: grab acl info */
4875 if ((Gen
.g_mode
== SECMODE
) || ((Hdr_type
== USTAR
||
4876 Hdr_type
== TAR
) && Thdr_p
->tbuf
.t_typeflag
== 'A')) {
4877 /* this is an ancillary file */
4886 bytes
= Gen
.g_filesz
;
4887 secp
= e_zalloc(E_EXIT
, (uint_t
)bytes
);
4891 cnt
= (int)(bytes
> CPIOBSZ
) ? CPIOBSZ
: bytes
;
4893 (void) memcpy(tp
, Buffr
.b_out_p
, cnt
);
4895 Buffr
.b_out_p
+= cnt
;
4896 Buffr
.b_cnt
-= (off_t
)cnt
;
4897 bytes
-= (off_t
)cnt
;
4900 pad
= (Pad_val
+ 1 - (Gen
.g_filesz
& Pad_val
)) &
4904 Buffr
.b_out_p
+= pad
;
4905 Buffr
.b_cnt
-= (off_t
)pad
;
4908 /* got all attributes in secp */
4911 attr
= (struct sec_attr
*)tp
;
4912 switch (attr
->attr_type
) {
4915 (void) sscanf(attr
->attr_len
, "%7lo",
4916 (ulong_t
*)&aclcnt
);
4919 strlen(&attr
->attr_info
[0])
4923 acl_fromtext(&attr
->attr_info
[0],
4928 "aclfromtext failed: %s",
4929 acl_strerror(error
));
4934 if (aclcnt
!= acl_cnt(aclp
)) {
4935 msg(ERR
, "acl count error");
4942 /* SunFed case goes here */
4945 msg(EXT
, "unrecognized attr type");
4948 /* next attributes */
4950 } while (bytes
> 0);
4953 /* skip security info */
4958 * We already got the file content, dont call file_in()
4959 * when return. The new return code(2) is used to
4962 VERBOSE((Args
& OCt
), Gen
.g_nam_p
);
4967 * Sparse file support
4968 * Read header of holesdata to get original file size.
4969 * This is necessary because ckname() or file_in() shows file size
4970 * with OCt before data_in() extracts the holesdata. data_in()
4971 * actually doesn't extract the holesdata since proc_mode will be
4972 * P_SKIP in the OCt mode.
4974 if ((Hdr_type
== CHR
|| Hdr_type
== ASC
) &&
4975 S_ISSPARSE(Gen
.g_mode
) && Gen
.g_filesz
> MIN_HOLES_HDRSIZE
) {
4976 char holesdata
[MIN_HOLES_HDRSIZE
+ 1];
4978 FILL(MIN_HOLES_HDRSIZE
);
4979 (void) memcpy(holesdata
, Buffr
.b_out_p
, MIN_HOLES_HDRSIZE
);
4980 holesdata
[MIN_HOLES_HDRSIZE
] = '\0';
4982 Gen
.g_holes
= read_holes_header(holesdata
, Gen
.g_filesz
);
4983 if (Gen
.g_holes
== NULL
) {
4984 msg(EXT
, "invalid sparse file information");
4986 Buffr
.b_out_p
+= MIN_HOLES_HDRSIZE
;
4987 Buffr
.b_cnt
-= MIN_HOLES_HDRSIZE
;
4991 Adir
= (ftype
== S_IFDIR
);
4992 Aspec
= (ftype
== S_IFBLK
|| ftype
== S_IFCHR
|| ftype
== S_IFIFO
||
4996 * Skip any trailing slashes
4998 chop_endslashes(Gen
.g_nam_p
);
5003 * getname: Get file names for inclusion in the archive. When end of file
5004 * on the input stream of file names is reached, flush the link buffer out.
5005 * For each filename, remove leading "./"s and multiple "/"s, and remove
5006 * any trailing newline "\n". Finally, verify the existence of the file,
5007 * and call creat_hdr() to fill in the gen_hdr structure.
5013 int goodfile
= 0, lastchar
, err
;
5017 Gen
.g_nam_p
= Nam_p
;
5023 while ((s
= fgets(Gen
.g_nam_p
, APATH
+1, In_p
)) != NULL
) {
5024 lastchar
= strlen(s
) - 1;
5027 if (s
[lastchar
] != '\n') {
5028 if (lastchar
== APATH
- 1) {
5031 "%s name too long.",
5046 if (Gen
.g_dirfd
!= -1) {
5047 (void) close(Gen
.g_dirfd
);
5050 if (Onecopy
&& (Args
& OCo
)) {
5056 while (*Gen
.g_nam_p
== '.' && Gen
.g_nam_p
[1] == '/') {
5058 while (*Gen
.g_nam_p
== '/')
5063 * Skip any trailing slashes
5065 chop_endslashes(Gen
.g_nam_p
);
5068 * Figure out parent directory
5071 if (Gen
.g_attrnam_p
!= NULL
) {
5072 if (Gen
.g_dirfd
!= -1) {
5073 (void) close(Gen
.g_dirfd
);
5075 Gen
.g_dirfd
= attropen(Gen
.g_attrfnam_p
, ".", O_RDONLY
);
5076 if (Gen
.g_dirfd
== -1) {
5078 "Cannot open attribute directory"
5079 " of file %s", Gen
.g_attrfnam_p
);
5084 char dirpath
[PATH_MAX
];
5086 get_parent(Gen
.g_nam_p
, dirpath
);
5087 if (Atflag
|| SysAtflag
) {
5089 if (Gen
.g_dirfd
!= -1) {
5090 (void) close(Gen
.g_dirfd
);
5092 Gen
.g_dirfd
= open(dir
, O_RDONLY
);
5093 if (Gen
.g_dirfd
== -1) {
5095 "Cannot open directory %s", dir
);
5100 * g_dirpath is the pathname cache maintaining
5101 * the dirname which is currently opened.
5102 * We first check the g_dirpath to see if the
5103 * given dirname matches. If so, we don't need
5104 * to open the dir, but we can use the g_dirfd
5105 * as is if it is still available.
5108 if (Gen
.g_dirpath
== NULL
||
5109 Gen
.g_dirfd
== -1) {
5111 * It's the first time or it has
5114 dir
= e_strdup(E_EXIT
, dirpath
);
5116 if (strcmp(Gen
.g_dirpath
,
5118 /* different directory */
5119 dir
= e_strdup(E_EXIT
, dirpath
);
5124 * We need to open the new directory.
5125 * discard the pathname and dirfd
5126 * for the previous directory.
5128 if (Gen
.g_dirpath
!= NULL
) {
5129 free(Gen
.g_dirpath
);
5130 Gen
.g_dirpath
= NULL
;
5132 if (Gen
.g_dirfd
!= -1) {
5133 (void) close(Gen
.g_dirfd
);
5135 /* open the new dir */
5136 Gen
.g_dirfd
= open(dir
, O_RDONLY
);
5137 if (Gen
.g_dirfd
== -1) {
5138 msg(ERRN
, "Cannot open "
5139 "directory %s", dir
);
5142 Gen
.g_dirpath
= dir
;
5150 /* creat_hdr checks for USTAR filename length */
5152 if (Hdr_type
!= USTAR
&& strlen(Gen
.g_nam_p
) >
5155 msg(ERR
, "%s%s%s name too long.",
5156 (Gen
.g_attrnam_p
== NULL
) ?
5157 Nam_p
: Gen
.g_attrfnam_p
,
5158 (Gen
.g_attrnam_p
== NULL
) ?
5159 "" : Gen
.g_rw_sysattr
?
5160 gettext(" System Attribute ") :
5161 gettext(" Attribute "),
5162 (Gen
.g_attrnam_p
== NULL
) ?
5163 "" : Gen
.g_attrnam_p
);
5173 if (!LSTAT(Gen
.g_dirfd
, Gen
.g_nam_p
, &SrcSt
)) {
5176 if ((SrcSt
.st_mode
& Ftype
) == S_IFLNK
) {
5181 if (STAT(Gen
.g_dirfd
,
5208 OldSt
= convert_to_old_stat(&SrcSt
,
5209 Gen
.g_nam_p
, Gen
.g_attrnam_p
);
5211 if (OldSt
== NULL
) {
5217 "Error with fstatat() of \"%s%s%s\"",
5218 (Gen
.g_attrnam_p
== NULL
) ?
5219 Gen
.g_nam_p
: Gen
.g_attrfnam_p
,
5220 (Gen
.g_attrnam_p
== NULL
) ? "" :
5222 gettext(" System Attribute ") :
5223 gettext(" Attribute "),
5224 (Gen
.g_attrnam_p
== NULL
) ?
5225 "" : Gen
.g_attrnam_p
);
5231 * Get ACL info: dont bother allocating space if there are only
5232 * standard permissions, i.e. ACL count < 4
5234 if ((SrcSt
.st_mode
& Ftype
) != S_IFLNK
&& Pflag
) {
5235 if (acl_get(Gen
.g_nam_p
, ACL_NO_TRIVIAL
, &aclp
) != 0)
5236 msg(ERRN
, "Error with acl() of \"%s\"", Gen
.g_nam_p
);
5238 /* else: only traditional permissions, so proceed as usual */
5245 * getpats: Save any filenames/patterns specified as arguments.
5246 * Read additional filenames/patterns from the file specified by the
5247 * user. The filenames/patterns must occur one per line.
5251 getpats(int largc
, char **largv
)
5255 unsigned numpat
= largc
, maxpat
= largc
+ 2;
5257 Pat_pp
= e_zalloc(E_EXIT
, maxpat
* sizeof (char *));
5260 *t_pp
= e_zalloc(E_EXIT
, strlen(*largv
) + 1);
5261 (void) strcpy(*t_pp
, *largv
);
5265 while (fgets(Nam_p
, Max_namesz
+ 1, Ef_p
) != NULL
) {
5266 if (numpat
== maxpat
- 1) {
5268 Pat_pp
= e_realloc(E_EXIT
, Pat_pp
,
5269 maxpat
* sizeof (char *));
5270 t_pp
= Pat_pp
+ numpat
;
5272 len
= strlen(Nam_p
); /* includes the \n */
5273 *(Nam_p
+ len
- 1) = '\0'; /* remove the \n */
5274 *t_pp
= e_zalloc(E_EXIT
, len
);
5275 (void) strcpy(*t_pp
, Nam_p
);
5289 if (fstat(Archive
, &ArchSt
) < 0)
5290 msg(EXTN
, "Error during stat() of archive");
5292 if ((ArchSt
.st_mode
& Ftype
) != S_IFCHR
) {
5295 msg(EXT
, "ulimit reached for output file.");
5296 else if (errno
== ENOSPC
)
5297 msg(EXT
, "No space left for output file.");
5299 msg(EXTN
, "I/O error - cannot continue");
5301 msg(EXT
, "Unexpected end-of-file encountered.");
5303 msg(EXTN
, "\007I/O error on \"%s\"", dir
? "output" : "input");
5307 * matched: Determine if a filename matches the specified pattern(s). If the
5308 * pattern is matched (the second return), return 0 if -f was specified, else
5309 * return != 0. If the pattern is not matched (the first and third
5310 * returns), return 0 if -f was not specified, else return != 0.
5316 char *str_p
= G_p
->g_nam_p
;
5317 char **pat_pp
= Pat_pp
;
5318 int negatep
, result
;
5321 * Check for attribute
5323 if (G_p
->g_attrfnam_p
!= NULL
)
5324 str_p
= G_p
->g_attrfnam_p
;
5326 for (pat_pp
= Pat_pp
; *pat_pp
; pat_pp
++) {
5327 negatep
= (**pat_pp
== '!');
5329 result
= fnmatch(negatep
? (*pat_pp
+1) : *pat_pp
, str_p
, 0);
5331 if (result
!= 0 && result
!= FNM_NOMATCH
) {
5332 msg(POST
, "error matching file %s with pattern"
5333 " %s\n", str_p
, *pat_pp
);
5334 return (Args
& OCf
);
5337 if ((result
== 0 && ! negatep
) ||
5338 (result
== FNM_NOMATCH
&& negatep
)) {
5339 /* match occurred */
5340 return (!(Args
& OCf
));
5343 return (Args
& OCf
); /* not matched */
5347 * missdir: Create missing directories for files.
5348 * (Possible future performance enhancement, if missdir is called, we know
5349 * that at least the very last directory of the path does not exist, therefore,
5350 * scan the path from the end
5354 missdir(char *nam_p
)
5360 if (*(c_p
= nam_p
) == '/') /* skip over 'root slash' */
5363 lastp
= c_p
+ strlen(nam_p
) - 1;
5367 for (; *c_p
; ++c_p
) {
5370 if (stat(nam_p
, &DesSt
) < 0) {
5372 cnt
= mkdir(nam_p
, Def_mode
);
5378 msg(ERR
, "Missing -d option.");
5386 if (cnt
== 2) /* the file already exists */
5392 * mklong: Convert two shorts into one long. For VAX, Interdata ...
5402 if (swp_b
.s_byte
[0]) {
5403 swp_b
.s_half
[0] = v
[1];
5404 swp_b
.s_half
[1] = v
[0];
5406 swp_b
.s_half
[0] = v
[0];
5407 swp_b
.s_half
[1] = v
[1];
5409 return (swp_b
.s_word
);
5413 * mkshort: Convert a long into 2 shorts, for VAX, Interdata ...
5417 mkshort(short sval
[], long v
)
5419 union swpbuf
*swp_p
, swp_b
;
5421 /* LINTED alignment */
5422 swp_p
= (union swpbuf
*)sval
;
5424 if (swp_b
.s_byte
[0]) {
5426 swp_p
->s_half
[0] = swp_b
.s_half
[1];
5427 swp_p
->s_half
[1] = swp_b
.s_half
[0];
5430 swp_p
->s_half
[0] = swp_b
.s_half
[0];
5431 swp_p
->s_half
[1] = swp_b
.s_half
[1];
5436 * msg: Print either a message (no error) (POST), an error message with or
5437 * without the errno (ERRN or ERR), or print an error message with or without
5438 * the errno and exit (EXTN or EXT).
5441 msg(int severity
, const char *fmt
, ...)
5446 if ((Args
& OCV
) && Verbcnt
) { /* clear current line of dots */
5447 (void) fputc('\n', Out_p
);
5451 if (severity
== POST
)
5454 if (severity
== EPOST
)
5460 (void) fflush(Out_p
);
5461 (void) fflush(Err_p
);
5462 if ((severity
!= POST
) && (severity
!= EPOST
))
5463 (void) fprintf(file_p
, "cpio: ");
5465 /* gettext replaces version of string */
5467 (void) vfprintf(file_p
, gettext(fmt
), ap
);
5468 if (severity
== ERRN
|| severity
== EXTN
) {
5469 if (G_p
&& (G_p
->g_attrnam_p
!= NULL
) && G_p
->g_rw_sysattr
) {
5470 if (errno
== EPERM
) {
5471 (void) fprintf(file_p
, ", errno %d, %s", errno
,
5472 gettext("insufficient privileges\n"));
5473 } else if (errno
== EINVAL
) {
5474 (void) fprintf(file_p
, ", errno %d, %s",
5476 "unsupported on underlying file system\n"));
5478 (void) fprintf(file_p
, ", errno %d, ", errno
);
5482 (void) fprintf(file_p
, ", errno %d, ", errno
);
5486 (void) fprintf(file_p
, "\n");
5487 (void) fflush(file_p
);
5489 if (severity
== EXT
|| severity
== EXTN
) {
5490 (void) fprintf(file_p
, gettext("%d errors\n"), Error_cnt
);
5496 * openout: Open files for output and set all necessary information.
5497 * If the u option is set (unconditionally overwrite existing files),
5498 * and the current file exists, get a temporary file name from mktemp(3C),
5499 * link the temporary file to the existing file, and remove the existing file.
5500 * Finally either creat(2), mkdir(2) or mknod(2) as appropriate.
5510 Do_rename
= 0; /* creat_tmp() may reset this */
5512 if (G_p
->g_attrnam_p
!= NULL
) {
5513 nam_p
= G_p
->g_attrnam_p
;
5518 nam_p
= G_p
->g_nam_p
;
5523 if ((Max_filesz
!= RLIM_INFINITY
) &&
5524 (Max_filesz
< (G_p
->g_filesz
>> 9))) {
5525 /* ... divided by 512 ... */
5526 msg(ERR
, "Skipping \"%s%s%s\": exceeds ulimit by %lld bytes",
5527 (G_p
->g_attrnam_p
== NULL
) ? nam_p
: G_p
->g_attrfnam_p
,
5528 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_rw_sysattr
?
5529 gettext(" System Attribute ") : gettext(" Attribute "),
5530 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
,
5531 (off_t
)(G_p
->g_filesz
- (Max_filesz
<< 9)));
5535 if (LSTAT(dirfd
, nam_p
, &DesSt
) == 0) {
5537 * A file by the same name exists. Move it to a temporary
5538 * file unless it's a system attribute file. If we are
5539 * restoring a system attribute file on a file system that
5540 * supports system attributes, then the system attribute file
5541 * will already exist (a default system attribute file will
5542 * get created when the file it is associated with is created).
5543 * If we create a temporary system attribute file, we can't
5544 * overwrite the existing system attribute file using
5545 * renameat(). In addition, only system attributes can exist
5546 * for an attribute of a file, therefore, a temporary file
5547 * cannot be created for a system attribute of an attribute.
5548 * Thus, when restoring a system attribute, we won't move it
5549 * to a temporary file, but will attempt to process it as if
5550 * it didn't already exist.
5553 #if defined(_PC_SATTR_ENABLED)
5554 if (G_p
->g_rw_sysattr
== 0)
5555 #endif /* _PC_SATTR_ENABLED */
5556 if (creat_tmp(nam_p
) < 0) {
5558 * We weren't able to create the temp file.
5567 /* nam_p was changed by creat_tmp() above. */
5570 if (G_p
->g_attrnam_p
!= NULL
) {
5576 nam_p
= G_p
->g_nam_p
;
5581 * This pile tries to create the file directly, and, if there is a
5582 * problem, creates missing directories, and then tries to create the
5583 * file again. Two strikes and you're out.
5585 * On XATTR system, the directory has already been created by
5586 * open_dirfd(), so error shouldn't happen in the loop. However,
5587 * on non-XATTR system, symlink/open may fail with ENOENT. In such
5588 * case, we go to create missing directories.
5596 if (Hdr_type
== TAR
&& Thdr_p
->tbuf
.t_typeflag
== SYMTYPE
) {
5597 /* The archive file is a TAR symlink. */
5599 symlink(Thdr_p
->tbuf
.t_linkname
, nam_p
)) >= 0) {
5601 if (Over_p
!= NULL
) {
5602 (void) unlinkat(dirfd
,
5603 get_component(Over_p
), 0);
5607 } else if (errno
!= ENOENT
) {
5608 /* The attempt to symlink failed. */
5610 "Cannot create symbolic link \"%s\" -> "
5612 Thdr_p
->tbuf
.t_linkname
, nam_p
);
5614 if (*Over_p
!= '\0') {
5615 rstfiles(U_KEEP
, dirfd
);
5619 } else if (Hdr_type
== BAR
&& bar_linkflag
== SYMTYPE
) {
5620 if ((result
= symlink(bar_linkname
, nam_p
)) >= 0) {
5622 if (Over_p
!= NULL
) {
5623 (void) unlinkat(dirfd
,
5624 get_component(Over_p
), 0);
5628 } else if (errno
!= ENOENT
) {
5629 /* The attempt to symlink failed. */
5631 "Cannot create symbolic link \"%s\" -> "
5633 bar_linkname
, nam_p
);
5634 if (*Over_p
!= '\0') {
5635 rstfiles(U_KEEP
, dirfd
);
5639 } else if ((G_p
->g_mode
& Ftype
) == S_IFLNK
) {
5640 if ((!(Args
& OCp
)) && !(Hdr_type
== USTAR
)) {
5641 FILL(G_p
->g_filesz
);
5642 (void) strncpy(Symlnk_p
,
5643 Buffr
.b_out_p
, G_p
->g_filesz
);
5644 *(Symlnk_p
+ G_p
->g_filesz
) = '\0';
5645 } else if ((!(Args
& OCp
)) && (Hdr_type
== USTAR
)) {
5646 Symlnk_p
[NAMSIZ
] = '\0';
5647 (void) strncpy(Symlnk_p
,
5648 &Thdr_p
->tbuf
.t_linkname
[0], NAMSIZ
);
5650 if ((result
= symlink(Symlnk_p
, nam_p
)) >= 0) {
5652 if (Over_p
!= NULL
) {
5653 (void) unlinkat(dirfd
,
5654 get_component(Over_p
), 0);
5658 } else if (errno
!= ENOENT
) {
5659 /* The attempt to symlink failed. */
5661 "Cannot create symbolic link \"%s\" -> "
5665 if (*Over_p
!= '\0') {
5666 rstfiles(U_KEEP
, dirfd
);
5673 if ((result
= openat(dirfd
, get_component(nam_p
),
5674 O_CREAT
|O_RDWR
|O_TRUNC
, (int)G_p
->g_mode
)) < 0) {
5676 if (G_p
->g_attrnam_p
!= NULL
) {
5677 result
= retry_open_attr(dirfd
,
5678 Gen
.g_baseparent_fd
, Fullnam_p
,
5679 (G_p
->g_attrparent_p
== NULL
) ?
5680 NULL
: G_p
->g_attrparent_p
, nam_p
,
5681 O_CREAT
|O_RDWR
|O_TRUNC
,
5687 if (errno
!= ENOENT
) {
5688 /* The attempt to open failed. */
5689 msg(ERRN
, "Cannot open file \"%s\"",
5691 if (*Over_p
!= '\0') {
5692 rstfiles(U_KEEP
, dirfd
);
5699 if (Pflag
&& aclp
!= NULL
) {
5700 if (facl_set(result
, aclp
) < 0) {
5702 "\"%s\": failed to set acl",
5715 } while (cnt
< 2 && missdir(nam_p
) == 0);
5719 if ((Args
& OCi
) && (Hdr_type
== USTAR
)) {
5722 if ((G_p
->g_mode
& Ftype
) == S_IFLNK
||
5723 (Hdr_type
== BAR
&& bar_linkflag
== SYMTYPE
)) {
5726 get_component(nam_p
),
5729 AT_SYMLINK_NOFOLLOW
) < 0) {
5731 "Error during chown() of "
5733 (G_p
->g_attrnam_p
== NULL
) ?
5734 nam_p
: G_p
->g_attrfnam_p
,
5735 (G_p
->g_attrnam_p
== NULL
) ?
5736 "" : G_p
->g_rw_sysattr
?
5737 gettext(" System Attribute ") :
5738 gettext(" Attribute "),
5739 (G_p
->g_attrnam_p
== NULL
) ?
5742 } else if ((fchownat(dirfd
, get_component(nam_p
),
5743 (int)G_p
->g_uid
, (int)G_p
->g_gid
,
5744 AT_SYMLINK_NOFOLLOW
) < 0) && privileged
) {
5746 "Error during chown() of \"%s%s%s\"",
5747 (G_p
->g_attrnam_p
== NULL
) ?
5748 nam_p
: G_p
->g_attrfnam_p
,
5749 (G_p
->g_attrnam_p
== NULL
) ? "" :
5751 gettext(" System Attribute ") :
5752 gettext(" Attribute "),
5753 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
5760 msg(ERRN
, "Cannot create directory for \"%s%s%s\"",
5761 (G_p
->g_attrnam_p
== NULL
) ? Over_p
:
5763 (G_p
->g_attrnam_p
== NULL
) ? "" :
5765 gettext(" System Attribute ") :
5766 gettext(" Attribute "),
5767 (G_p
->g_attrnam_p
== NULL
) ? "" : Over_p
);
5769 msg(ERRN
, "Cannot create directory for \"%s%s%s\"",
5770 (G_p
->g_attrnam_p
== NULL
) ? nam_p
:
5772 (G_p
->g_attrnam_p
== NULL
) ? "" :
5774 gettext(" System Attribute ") :
5775 gettext(" Attribute "),
5776 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
5782 msg(ERRN
, "Cannot create \"%s%s%s\"",
5783 (G_p
->g_attrnam_p
== NULL
) ? Over_p
:
5785 (G_p
->g_attrnam_p
== NULL
) ? "" :
5787 gettext(" System Attribute ") :
5788 gettext(" Attribute "),
5789 (G_p
->g_attrnam_p
== NULL
) ? "" :
5792 msg(ERRN
, "Cannot create \"%s%s%s\"",
5793 (G_p
->g_attrnam_p
== NULL
) ? nam_p
:
5795 (G_p
->g_attrnam_p
== NULL
) ? "" :
5797 gettext(" System Attribute ") :
5798 gettext(" Attribute "),
5799 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
5804 msg(EXT
, "Impossible case.");
5812 * read_hdr: Transfer headers from the selected format
5813 * in the archive I/O buffer to the generic structure.
5824 static int bar_read_cnt
= 0;
5827 if (Buffr
.b_end_p
!= (Buffr
.b_out_p
+ Hdrsz
)) {
5828 tmpnull
= *(Buffr
.b_out_p
+ Hdrsz
);
5829 *(Buffr
.b_out_p
+ Hdrsz
) = '\0';
5835 (void) memcpy(&Hdr
, Buffr
.b_out_p
, HDRSZ
);
5836 if (Hdr
.h_magic
== (short)CMN_BBS
) {
5837 swap((char *)&Hdr
, HDRSZ
);
5839 Gen
.g_magic
= Hdr
.h_magic
;
5840 Gen
.g_mode
= Hdr
.h_mode
;
5841 Gen
.g_uid
= Hdr
.h_uid
;
5842 Gen
.g_gid
= Hdr
.h_gid
;
5843 Gen
.g_nlink
= Hdr
.h_nlink
;
5844 Gen
.g_mtime
= mklong(Hdr
.h_mtime
);
5845 Gen
.g_ino
= Hdr
.h_ino
;
5846 Gen
.g_dev
= Hdr
.h_dev
;
5847 Gen
.g_rdev
= Hdr
.h_rdev
;
5849 Gen
.g_filesz
= (off_t
)mklong(Hdr
.h_filesize
);
5850 Gen
.g_namesz
= Hdr
.h_namesize
;
5854 if (sscanf(Buffr
.b_out_p
,
5855 "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6o%11llo",
5856 &Gen
.g_magic
, &Gen
.g_dev
, &Gen
.g_ino
, &Gen
.g_mode
,
5857 &Gen
.g_uid
, &Gen
.g_gid
, &Gen
.g_nlink
, &Gen
.g_rdev
,
5858 (ulong_t
*)&Gen
.g_mtime
, (uint_t
*)&Gen
.g_namesz
,
5859 (u_off_t
*)&Gen
.g_filesz
) == CHR_CNT
) {
5861 #define cpioMAJOR(x) (int)(((unsigned)x >> 8) & 0x7F)
5862 #define cpioMINOR(x) (int)(x & 0xFF)
5863 maj
= cpioMAJOR(Gen
.g_dev
);
5864 rmaj
= cpioMAJOR(Gen
.g_rdev
);
5865 min
= cpioMINOR(Gen
.g_dev
);
5866 rmin
= cpioMINOR(Gen
.g_rdev
);
5868 /* needs error checking */
5869 Gen
.g_dev
= (maj
<< 8) | min
;
5870 Gen
.g_rdev
= (rmaj
<< 8) | rmin
;
5872 Gen
.g_dev
= makedev(maj
, min
);
5873 Gen
.g_rdev
= makedev(rmaj
, rmin
);
5879 if (sscanf(Buffr
.b_out_p
,
5880 "%6lx%8lx%8lx%8lx%8lx%8lx%8lx%8llx%8x%8x%8x%8x%8x%8lx",
5881 &Gen
.g_magic
, &Gen
.g_ino
, &Gen
.g_mode
, &Gen
.g_uid
,
5882 &Gen
.g_gid
, &Gen
.g_nlink
, &Gen
.g_mtime
,
5883 (u_off_t
*)&Gen
.g_filesz
, (uint_t
*)&maj
, (uint_t
*)&min
,
5884 (uint_t
*)&rmaj
, (uint_t
*)&rmin
, (uint_t
*)&Gen
.g_namesz
,
5885 &Gen
.g_cksum
) == ASC_CNT
) {
5886 Gen
.g_dev
= makedev(maj
, min
);
5887 Gen
.g_rdev
= makedev(rmaj
, rmin
);
5891 case USTAR
: /* TAR and USTAR */
5892 if (*Buffr
.b_out_p
== '\0') {
5893 *Gen
.g_nam_p
= '\0';
5896 Thdr_p
= (union tblock
*)Buffr
.b_out_p
;
5897 Gen
.g_nam_p
[0] = '\0';
5898 (void) strncpy((char *)&nambuf
,
5899 Thdr_p
->tbuf
.t_name
, NAMSIZ
);
5900 (void) sscanf(Thdr_p
->tbuf
.t_mode
, "%8lo",
5902 (void) sscanf(Thdr_p
->tbuf
.t_uid
, "%8lo", &Gen
.g_uid
);
5903 (void) sscanf(Thdr_p
->tbuf
.t_gid
, "%8lo", &Gen
.g_gid
);
5904 (void) sscanf(Thdr_p
->tbuf
.t_size
, "%11llo",
5905 (u_off_t
*)&Gen
.g_filesz
);
5906 (void) sscanf(Thdr_p
->tbuf
.t_mtime
, "%12lo",
5907 (ulong_t
*)&Gen
.g_mtime
);
5908 (void) sscanf(Thdr_p
->tbuf
.t_cksum
, "%8lo",
5909 (ulong_t
*)&Gen
.g_cksum
);
5910 if (Thdr_p
->tbuf
.t_linkname
[0] != '\0')
5915 switch (Thdr_p
->tbuf
.t_typeflag
) {
5921 Gen
.g_mode
|= (S_IFMT
& S_IFCHR
);
5924 Gen
.g_mode
|= (S_IFMT
& S_IFBLK
);
5927 Gen
.g_mode
|= (S_IFMT
& S_IFDIR
);
5930 Gen
.g_mode
|= (S_IFMT
& S_IFIFO
);
5934 (void) sscanf(Thdr_p
->tbuf
.t_magic
, "%8lo",
5935 /* LINTED alignment */
5936 (ulong_t
*)&Gen
.g_tmagic
);
5937 (void) sscanf(Thdr_p
->tbuf
.t_version
, "%8lo",
5938 /* LINTED alignment */
5939 (ulong_t
*)&Gen
.g_version
);
5940 (void) sscanf(Thdr_p
->tbuf
.t_uname
, "%32s",
5941 (char *)&Gen
.g_uname
);
5942 (void) sscanf(Thdr_p
->tbuf
.t_gname
, "%32s",
5943 (char *)&Gen
.g_gname
);
5944 (void) sscanf(Thdr_p
->tbuf
.t_devmajor
, "%8lo",
5946 (void) sscanf(Thdr_p
->tbuf
.t_devminor
, "%8lo",
5948 (void) strncpy((char *)&prebuf
,
5949 Thdr_p
->tbuf
.t_prefix
, PRESIZ
);
5950 Gen
.g_namesz
= strlen(Gen
.g_nam_p
) + 1;
5951 Gen
.g_dev
= makedev(maj
, min
);
5956 if (*Buffr
.b_out_p
== '\0') {
5957 *Gen
.g_nam_p
= '\0';
5960 Thdr_p
= (union tblock
*)Buffr
.b_out_p
;
5961 Gen
.g_nam_p
[0] = '\0';
5962 (void) sscanf(Thdr_p
->tbuf
.t_mode
, "%lo", &Gen
.g_mode
);
5963 (void) sscanf(Thdr_p
->tbuf
.t_uid
, "%lo", &Gen
.g_uid
);
5964 (void) sscanf(Thdr_p
->tbuf
.t_gid
, "%lo", &Gen
.g_gid
);
5965 (void) sscanf(Thdr_p
->tbuf
.t_size
, "%llo",
5966 (u_off_t
*)&Gen
.g_filesz
);
5967 (void) sscanf(Thdr_p
->tbuf
.t_mtime
, "%lo",
5969 (void) sscanf(Thdr_p
->tbuf
.t_cksum
, "%lo",
5971 if (Thdr_p
->tbuf
.t_typeflag
== '1') /* hardlink */
5975 (void) strncpy(Gen
.g_nam_p
,
5976 Thdr_p
->tbuf
.t_name
, NAMSIZ
);
5977 Gen
.g_namesz
= strlen(Gen
.g_nam_p
) + 1;
5978 (void) strcpy(nambuf
, Gen
.g_nam_p
);
5983 if (Bar_vol_num
== 0 && bar_read_cnt
== 0) {
5988 read_bar_file_hdr();
5992 msg(EXT
, "Impossible header type.");
5996 if (Buffr
.b_end_p
!= (Buffr
.b_out_p
+ Hdrsz
))
5997 *(Buffr
.b_out_p
+ Hdrsz
) = tmpnull
;
6004 * reclaim: Reclaim linked file structure storage.
6008 reclaim(struct Lnk
*p
)
6010 p
->L_bck_p
->L_nxt_p
= p
->L_nxt_p
;
6011 p
->L_nxt_p
->L_bck_p
= p
->L_bck_p
;
6014 struct Lnk
*new_p
= p
->L_lnk_p
;
6016 free(p
->L_gen
.g_nam_p
);
6023 * rstbuf: Reset the I/O buffer, move incomplete potential headers to
6024 * the front of the buffer and force bread() to refill the buffer. The
6025 * return value from bread() is returned (to identify I/O errors). On the
6026 * 3B2, reads must begin on a word boundary, therefore, with the -i option,
6027 * any remaining bytes in the buffer must be moved to the base of the buffer
6028 * in such a way that the destination locations of subsequent reads are
6037 if ((Args
& OCi
) || Append
) {
6038 if (Buffr
.b_out_p
!= Buffr
.b_base_p
) {
6039 pad
= ((Buffr
.b_cnt
+ FULLWD
) & ~FULLWD
);
6040 Buffr
.b_in_p
= Buffr
.b_base_p
+ pad
;
6042 (void) memcpy(Buffr
.b_base_p
+ pad
, Buffr
.b_out_p
,
6044 Buffr
.b_out_p
= Buffr
.b_base_p
+ pad
;
6047 msg(EXT
, "Unexpected end-of-archive encountered.");
6049 (void) memcpy(Buffr
.b_base_p
, Buffr
.b_out_p
, (int)Buffr
.b_cnt
);
6050 Buffr
.b_out_p
= Buffr
.b_base_p
;
6051 Buffr
.b_in_p
= Buffr
.b_base_p
+ Buffr
.b_cnt
;
6056 setpasswd(char *nam
)
6058 if ((dpasswd
= getpwnam(&Gen
.g_uname
[0])) == NULL
) {
6059 msg(EPOST
, "cpio: problem reading passwd entry");
6060 msg(EPOST
, "cpio: %s: owner not changed", nam
);
6061 if (Gen
.g_uid
== UID_NOBODY
&& S_ISREG(Gen
.g_mode
))
6062 Gen
.g_mode
&= ~S_ISUID
;
6064 Gen
.g_uid
= dpasswd
->pw_uid
;
6066 if ((dgroup
= getgrnam(&Gen
.g_gname
[0])) == NULL
) {
6067 msg(EPOST
, "cpio: problem reading group entry");
6068 msg(EPOST
, "cpio: %s: group not changed", nam
);
6069 if (Gen
.g_gid
== GID_NOBODY
&& S_ISREG(Gen
.g_mode
))
6070 Gen
.g_mode
&= ~S_ISGID
;
6072 Gen
.g_gid
= dgroup
->gr_gid
;
6077 * rstfiles: Perform final changes to the file. If the -u option is set,
6078 * and overwrite == U_OVER, remove the temporary file, else if overwrite
6079 * == U_KEEP, unlink the current file, and restore the existing version
6080 * of the file. In addition, where appropriate, set the access or modification
6081 * times, change the owner and change the modes of the file.
6083 * Note that if Do_rename is set, then the roles of original and temporary
6084 * file are reversed. If all went well, we will rename() the temporary file
6085 * over the original in order to accommodate potentially executing files.
6088 rstfiles(int over
, int dirfd
)
6090 char *inam_p
, *onam_p
, *nam_p
;
6093 #if defined(_PC_SATTR_ENABLED)
6094 /* Time or permissions cannot be set on system attribute files */
6095 if ((Gen
.g_attrnam_p
!= NULL
) && (Gen
.g_rw_sysattr
== 1)) {
6098 #endif /* _PC_SATTR_ENABLED */
6101 if (G_p
->g_attrnam_p
== NULL
) {
6104 nam_p
= G_p
->g_attrnam_p
;
6107 if (Gen
.g_nlink
> (ulong_t
)0) {
6108 nam_p
= G_p
->g_nam_p
;
6110 nam_p
= Gen
.g_nam_p
;
6113 if (Gen
.g_attrnam_p
!= NULL
) {
6114 nam_p
= Gen
.g_attrnam_p
;
6117 if ((Args
& OCi
) && (Hdr_type
== USTAR
)) {
6120 if (over
== U_KEEP
&& *Over_p
!= '\0') {
6122 msg(POST
, "Restoring existing \"%s%s%s\"",
6123 (G_p
->g_attrnam_p
== NULL
) ? Over_p
: Fullnam_p
,
6124 (G_p
->g_attrnam_p
== NULL
) ? "" :
6125 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
6126 gettext(" Attribute "),
6127 (G_p
->g_attrnam_p
== NULL
) ? "" : Over_p
);
6129 msg(POST
, "Restoring existing \"%s%s%s\"",
6130 (G_p
->g_attrnam_p
== NULL
) ? nam_p
: Fullnam_p
,
6131 (G_p
->g_attrnam_p
== NULL
) ? "" :
6132 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
6133 gettext(" Attribute "),
6134 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
6137 /* delete what we just built */
6138 (void) unlinkat(dirfd
, get_component(nam_p
), 0);
6140 /* If the old file needs restoring, do the necessary links */
6145 tmp_ptr
= Fullnam_p
;
6148 tmp_ptr
= G_p
->g_nam_p
;
6149 G_p
->g_nam_p
= Over_p
;
6153 Do_rename
= 0; /* names now have original values */
6155 if (rename(Over_p
, nam_p
) < 0) {
6156 if (link(Over_p
, nam_p
) < 0) {
6158 "Cannot recover original version"
6160 (G_p
->g_attrnam_p
== NULL
) ?
6162 (G_p
->g_attrnam_p
== NULL
) ? "" :
6164 gettext(" System Attribute ") :
6165 gettext(" Attribute "),
6166 (G_p
->g_attrnam_p
== NULL
) ?
6169 if (unlinkat(dirfd
, get_component(Over_p
), 0)) {
6171 "Cannot remove temp file "
6173 (G_p
->g_attrnam_p
== NULL
) ?
6175 (G_p
->g_attrnam_p
== NULL
) ? "" :
6177 gettext(" System Attribute ") :
6178 gettext(" Attribute "),
6179 (G_p
->g_attrnam_p
== NULL
) ?
6186 } else if (over
== U_OVER
&& *Over_p
!= '\0') {
6190 (void) renameat(dirfd
, get_component(nam_p
),
6191 dirfd
, get_component(Over_p
));
6193 if (G_p
->g_attrnam_p
== NULL
) {
6194 tmp_ptr
= Fullnam_p
;
6199 * Over_p is pointing at g_attrnam_p
6200 * which must be preserved.
6202 * We don't want the tmp_ptr and so
6203 * on to throw away our only copy of
6206 Over_p
= Attrfile_p
;
6209 tmp_ptr
= G_p
->g_nam_p
;
6210 G_p
->g_nam_p
= Over_p
;
6213 Do_rename
= 0; /* names now have original values */
6215 if (unlinkat(dirfd
, get_component(Over_p
), 0) < 0) {
6217 "Cannot unlink() temp file \"%s%s%s\"",
6218 (G_p
->g_attrnam_p
== NULL
) ?
6220 (G_p
->g_attrnam_p
== NULL
) ? "" :
6222 gettext(" System Attribute ") :
6223 gettext(" Attribute "),
6224 (G_p
->g_attrnam_p
== NULL
) ? "" : Over_p
);
6230 if (G_p
->g_attrnam_p
!= NULL
) {
6231 inam_p
= G_p
->g_attrfnam_p
;
6232 onam_p
= G_p
->g_attrnam_p
;
6237 } else /* OCi only uses onam_p, OCo only uses inam_p */
6238 if (G_p
->g_attrnam_p
!= NULL
) {
6239 inam_p
= onam_p
= G_p
->g_attrnam_p
;
6241 inam_p
= onam_p
= G_p
->g_nam_p
;
6245 * Change the owner, time, and mode to those of the file
6246 * originally created in the archive. Note: time and
6247 * mode do not need to be restored for a symbolic link
6248 * since rstfiles() is not called when the archived file
6251 if (!(Args
& OCo
)) {
6253 if (fchownat(dirfd
, get_component(onam_p
),
6254 Rpw_p
->pw_uid
, Rpw_p
->pw_gid
,
6255 AT_SYMLINK_NOFOLLOW
) < 0) {
6256 msg(ERRN
, "Cannot chown() \"%s%s%s\"",
6258 (G_p
->g_attrnam_p
== NULL
) ? "" :
6260 gettext(" System Attribute ") :
6261 gettext(" Attribute "),
6262 (G_p
->g_attrnam_p
== NULL
) ? "" : onam_p
);
6265 if ((fchownat(dirfd
, get_component(onam_p
),
6266 G_p
->g_uid
, G_p
->g_gid
,
6267 AT_SYMLINK_NOFOLLOW
) < 0) && privileged
) {
6268 msg(ERRN
, "Cannot chown() \"%s%s%s\"",
6270 (G_p
->g_attrnam_p
== NULL
) ? "" :
6272 gettext(" System Attribute ") :
6273 gettext(" Attribute "),
6274 (G_p
->g_attrnam_p
== NULL
) ? "" : onam_p
);
6279 set_tym(dirfd
, get_component(onam_p
),
6280 G_p
->g_mtime
, G_p
->g_mtime
);
6283 /* Acl was not set, so we must chmod */
6285 mode_t orig_mask
, new_mask
;
6288 * use fchmod for attributes, since
6289 * we known they are always regular
6290 * files, whereas when it isn't an
6291 * attribute it could be for a fifo
6292 * or something other that we don't
6293 * open and don't have a valid Ofile
6297 new_mask
= G_p
->g_mode
;
6299 orig_mask
= umask(0);
6300 new_mask
= G_p
->g_mode
& ~orig_mask
;
6303 if (G_p
->g_attrnam_p
!= NULL
) {
6304 error
= fchmod(Ofile
, new_mask
);
6306 error
= chmod(onam_p
, new_mask
);
6310 "Cannot chmod() \"%s%s%s\"",
6311 (G_p
->g_attrnam_p
== NULL
) ?
6312 onam_p
: G_p
->g_attrfnam_p
,
6313 (G_p
->g_attrnam_p
== NULL
) ? "" :
6315 gettext(" System Attribute ") :
6316 gettext(" Attribute "),
6317 (G_p
->g_attrnam_p
== NULL
) ? "" : onam_p
);
6320 (void) umask(orig_mask
);
6325 if (!(Args
& OCi
) && (Args
& OCa
)) {
6327 * Use dirfd since we are updating original file
6328 * and not just created file
6330 set_tym(G_p
->g_dirfd
, get_component(inam_p
),
6331 (ulong_t
)SrcSt
.st_atime
, (ulong_t
)SrcSt
.st_mtime
);
6336 * scan4trail: Scan the archive looking for the trailer.
6337 * When found, back the archive up over the trailer and overwrite
6338 * the trailer with the files to be added to the archive.
6355 off2
= Bufsize
- (Buffr
.b_cnt
% Bufsize
);
6356 Buffr
.b_out_p
= Buffr
.b_in_p
= Buffr
.b_base_p
;
6357 Buffr
.b_cnt
= (off_t
)0;
6358 if (lseek(Archive
, -(off1
+ off2
), SEEK_REL
) < 0)
6359 msg(EXTN
, "Unable to append to this archive");
6360 if ((rv
= g_read(Device
, Archive
, Buffr
.b_in_p
, Bufsize
)) < 0)
6361 msg(EXTN
, "Cannot append to this archive");
6362 if (lseek(Archive
, (off_t
)-rv
, SEEK_REL
) < 0)
6363 msg(EXTN
, "Unable to append to this archive");
6365 Buffr
.b_in_p
= Buffr
.b_base_p
+ Buffr
.b_cnt
;
6370 * setup: Perform setup and initialization functions. Parse the options
6371 * using getopt(3C), call ckopts to check the options and initialize various
6372 * structures and pointers. Specifically, for the -i option, save any
6373 * patterns, for the -o option, check (via stat(2)) the archive, and for
6374 * the -p option, validate the destination directory.
6378 setup(int largc
, char **largv
)
6381 extern char *optarg
;
6383 #if defined(O_XATTR)
6384 #if defined(_PC_SATTR_ENABLED)
6386 char *opts_p
= "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
6388 char *opts_p
= "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
6389 #endif /* WAITAROUND */
6391 #else /* _PC_SATTR_ENABLED */
6393 char *opts_p
= "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
6395 char *opts_p
= "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
6396 #endif /* WAITAROUND */
6397 #endif /* _PC_SATTR_ENABLED */
6401 char *opts_p
= "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
6403 char *opts_p
= "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
6404 #endif /* WAITAROUND */
6405 #endif /* O_XATTR */
6407 char *dupl_p
= "Only one occurrence of -%c allowed";
6409 int blk_cnt
, blk_cnt_max
;
6412 /* Remember the native page size. */
6414 PageSize
= sysconf(_SC_PAGESIZE
);
6416 if (PageSize
== -1) {
6418 * This sysconf call will almost certainly never fail. The
6419 * symbol PAGESIZE itself resolves to the above sysconf call,
6420 * so we should go ahead and define our own constant.
6426 Max_offset
= (off_t
)(BIN_OFFSET_MAX
);
6427 Efil_p
= Hdr_p
= Own_p
= IOfil_p
= NULL
;
6428 while ((option
= getopt(largc
, largv
, opts_p
)) != EOF
) {
6432 /* rendezvous with the debugger */
6436 case 'a': /* reset access time */
6439 case 'b': /* swap bytes and halfwords */
6442 case 'c': /* select character header */
6448 case 'd': /* create directories as needed */
6451 case 'f': /* select files not in patterns */
6454 case 'i': /* "copy in" */
6458 case 'k': /* retry after I/O errors */
6461 case 'l': /* link files when possible */
6464 case 'm': /* retain modification time */
6467 case 'o': /* "copy out" */
6471 case 'p': /* "pass" */
6475 case 'q': /* "quiet" */
6478 case 'r': /* rename files interactively */
6481 case 's': /* swap bytes */
6484 case 't': /* table of contents */
6487 case 'u': /* copy unconditionally */
6490 case 'v': /* verbose - print file names */
6493 case 'A': /* append to existing archive */
6496 case 'B': /* set block size to 5120 bytes */
6500 case 'C': /* set arbitrary block size */
6502 msg(ERR
, dupl_p
, 'C');
6505 Bufsize
= atoi(optarg
);
6511 case 'E': /* alternate file for pattern input */
6513 msg(ERR
, dupl_p
, 'E');
6519 case 'H': /* select header type */
6521 msg(ERR
, dupl_p
, 'H');
6527 case 'I': /* alternate file for archive input */
6529 msg(ERR
, dupl_p
, 'I');
6535 case 'L': /* follow symbolic links */
6538 case 'M': /* specify new end-of-media message */
6540 msg(ERR
, dupl_p
, 'M');
6546 case 'O': /* alternate file for archive output */
6548 msg(ERR
, dupl_p
, 'O');
6554 case 'P': /* preserve acls */
6558 case 'R': /* change owner/group of files */
6560 msg(ERR
, dupl_p
, 'R');
6566 case 'S': /* swap halfwords */
6569 case 'V': /* print a dot '.' for each file */
6572 case '6': /* for old, sixth-edition files */
6576 #if defined(O_XATTR)
6580 #if defined(_PC_SATTR_ENABLED)
6584 #endif /* _PC_SATTR_ENABLED */
6585 #endif /* O_XATTR */
6589 } /* (option = getopt(largc, largv, opts_p)) != EOF */
6593 (void) fprintf(stderr
, gettext("Rendezvous with cpio on pid"
6594 " %d\n"), getpid());
6596 while (waitaround
) {
6607 Renam_p
= e_zalloc(E_EXIT
, APATH
+ 1);
6608 Renametmp_p
= e_zalloc(E_EXIT
, APATH
+ 1);
6609 #if defined(_PC_SATTR_ENABLED)
6610 Renam_attr_p
= e_zalloc(E_EXIT
, APATH
+ 1);
6613 Symlnk_p
= e_zalloc(E_EXIT
, APATH
);
6614 Over_p
= e_zalloc(E_EXIT
, APATH
);
6615 Nam_p
= e_zalloc(E_EXIT
, APATH
+ 1);
6617 Savenam_p
= e_zalloc(E_EXIT
, APATH
+ 1);
6619 Fullnam_p
= e_zalloc(E_EXIT
, APATH
);
6620 Lnknam_p
= e_zalloc(E_EXIT
, APATH
);
6621 Gen
.g_nam_p
= Nam_p
;
6622 if ((Fullnam_p
= getcwd(NULL
, APATH
)) == NULL
)
6623 msg(EXT
, "Unable to determine current directory.");
6625 if (largc
> 0) /* save patterns for -i option, if any */
6628 getpats(largc
, largv
);
6629 } else if (Args
& OCo
) {
6630 if (largc
!= 0) /* error if arguments left with -o */
6632 else if (fstat(Archive
, &ArchSt
) < 0)
6633 msg(ERRN
, "Error during stat() of archive");
6642 Max_offset
= (off_t
)(CHAR_OFFSET_MAX
);
6648 Max_offset
= (off_t
)(ASC_OFFSET_MAX
);
6652 case USTAR
: /* TAR and USTAR */
6655 Max_offset
= (off_t
)(CHAR_OFFSET_MAX
);
6658 msg(EXT
, "Impossible header type.");
6660 } else { /* directory must be specified */
6663 else if (access(*largv
, 2) < 0 && (errno
!= EACCES
))
6665 * EACCES is ignored here as it may occur
6666 * when any directory component of the path
6667 * does not have write permission, even though
6668 * the destination subdirectory has write
6669 * access. Writing to a read only directory
6670 * is handled later, as in "copy in" mode.
6673 "Error during access() of \"%s\"", *largv
);
6677 usage(); /* exits! */
6678 if (Args
& (OCi
| OCo
)) {
6680 if (Args
& (OCB
| OCC
)) {
6681 if (g_init(&Device
, &Archive
) < 0)
6683 "Error during initialization");
6685 if ((Bufsize
= g_init(&Device
, &Archive
)) < 0)
6687 "Error during initialization");
6691 blk_cnt_max
= _20K
/ Bufsize
;
6692 if (blk_cnt_max
< MX_BUFS
) {
6693 blk_cnt_max
= MX_BUFS
;
6696 Buffr
.b_base_p
= NULL
;
6698 for (blk_cnt
= blk_cnt_max
; blk_cnt
> 1; blk_cnt
--) {
6699 Buffr
.b_size
= (size_t)(Bufsize
* blk_cnt
);
6700 Buffr
.b_base_p
= e_valloc(E_NORMAL
, Buffr
.b_size
);
6701 if (Buffr
.b_base_p
!= NULL
) {
6705 if (Buffr
.b_base_p
== NULL
|| Buffr
.b_size
< (2 * CPIOBSZ
)) {
6706 msg(EXT
, "Out of memory");
6709 Buffr
.b_out_p
= Buffr
.b_in_p
= Buffr
.b_base_p
;
6711 Buffr
.b_end_p
= Buffr
.b_base_p
+ Buffr
.b_size
;
6715 * Now that Bufsize has stabilized, we can allocate our i/o buffer
6717 Buf_p
= e_valloc(E_EXIT
, Bufsize
);
6719 if (Args
& OCp
) { /* get destination directory */
6720 (void) strcpy(Fullnam_p
, *largv
);
6721 if (stat(Fullnam_p
, &DesSt
) < 0)
6722 msg(EXTN
, "Error during stat() of \"%s\"", Fullnam_p
);
6723 if ((DesSt
.st_mode
& Ftype
) != S_IFDIR
)
6724 msg(EXT
, "\"%s\" is not a directory", Fullnam_p
);
6726 Full_p
= Fullnam_p
+ strlen(Fullnam_p
) - 1;
6727 if (*Full_p
!= '/') {
6733 (void) strcpy(Lnknam_p
, Fullnam_p
);
6734 Lnkend_p
= Lnknam_p
+ strlen(Lnknam_p
);
6735 (void) getrlimit(RLIMIT_FSIZE
, &rlim
);
6736 Max_filesz
= (off_t
)rlim
.rlim_cur
;
6737 Lnk_hd
.L_nxt_p
= Lnk_hd
.L_bck_p
= &Lnk_hd
;
6738 Lnk_hd
.L_lnk_p
= NULL
;
6742 * set_tym: Set the access and/or modification times for a file.
6746 set_tym(int dirfd
, char *nam_p
, time_t atime
, time_t mtime
)
6748 struct timeval times
[2];
6750 times
[0].tv_sec
= atime
;
6751 times
[0].tv_usec
= 0;
6752 times
[1].tv_sec
= mtime
;
6753 times
[1].tv_usec
= 0;
6755 if (futimesat(dirfd
, nam_p
, times
) < 0) {
6758 "Unable to reset access time for \"%s%s%s\"",
6759 (G_p
->g_attrnam_p
== NULL
) ? nam_p
: Fullnam_p
,
6760 (G_p
->g_attrnam_p
== NULL
) ? "" :
6761 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
6762 gettext(" Attribute "),
6763 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
6766 "Unable to reset modification time for \"%s%s%s\"",
6767 (G_p
->g_attrnam_p
== NULL
) ? nam_p
: Fullnam_p
,
6768 (G_p
->g_attrnam_p
== NULL
) ? "" :
6769 G_p
->g_rw_sysattr
? gettext(" System Attribute ") :
6770 gettext(" Attribute "),
6771 (G_p
->g_attrnam_p
== NULL
) ? "" : nam_p
);
6777 * sigint: Catch interrupts. If an interrupt occurs during the extraction
6778 * of a file from the archive with the -u option set, and the filename did
6779 * exist, remove the current file and restore the original file. Then exit.
6788 (void) signal(SIGINT
, SIG_IGN
); /* block further signals */
6791 nam_p
= G_p
->g_nam_p
;
6794 if (*Over_p
!= '\0') { /* There is a temp file */
6795 if (unlink(nam_p
) < 0) {
6797 "Cannot remove incomplete \"%s\"", nam_p
);
6799 if (rename(Over_p
, nam_p
) < 0) {
6800 if (link(Over_p
, nam_p
) < 0) {
6802 "Cannot recover original \"%s\"",
6805 if (unlink(Over_p
)) {
6807 "Cannot remove temp file \"%s\"",
6811 } else if (unlink(nam_p
))
6812 msg(ERRN
, "Cannot remove incomplete \"%s\"", nam_p
);
6819 * swap: Swap bytes (-s), halfwords (-S) or or both halfwords and bytes (-b).
6823 swap(char *buf_p
, int cnt
)
6825 unsigned char tbyte
;
6832 if (Args
& (OCb
| OCs
| BSM
)) {
6834 /* LINTED alignment */
6835 Swp_p
= (union swpbuf
*)buf_p
;
6836 while (tcnt
-- > 0) {
6837 tbyte
= Swp_p
->s_byte
[0];
6838 Swp_p
->s_byte
[0] = Swp_p
->s_byte
[1];
6839 Swp_p
->s_byte
[1] = tbyte
;
6840 tbyte
= Swp_p
->s_byte
[2];
6841 Swp_p
->s_byte
[2] = Swp_p
->s_byte
[3];
6842 Swp_p
->s_byte
[3] = tbyte
;
6846 tbyte
= Swp_p
->s_byte
[0];
6847 Swp_p
->s_byte
[0] = Swp_p
->s_byte
[1];
6848 Swp_p
->s_byte
[1] = tbyte
;
6849 tbyte
= Swp_p
->s_byte
[2];
6852 if (Args
& (OCb
| OCS
)) {
6854 /* LINTED alignment */
6855 Swp_p
= (union swpbuf
*)buf_p
;
6856 while (tcnt
-- > 0) {
6857 thalf
= Swp_p
->s_half
[0];
6858 Swp_p
->s_half
[0] = Swp_p
->s_half
[1];
6859 Swp_p
->s_half
[1] = thalf
;
6866 * usage: Print the usage message on stderr and exit.
6873 (void) fflush(stdout
);
6874 #if defined(O_XATTR)
6875 (void) fprintf(stderr
, gettext("USAGE:\n"
6876 "\tcpio -i[bcdfkmqrstuv@BSV6] [-C size] "
6877 "[-E file] [-H hdr] [-I file [-M msg]] "
6878 "[-R id] [patterns]\n"
6879 "\tcpio -o[acv@ABLV] [-C size] "
6880 "[-H hdr] [-O file [-M msg]]\n"
6881 "\tcpio -p[adlmuv@LV] [-R id] directory\n"));
6883 (void) fprintf(stderr
, gettext("USAGE:\n"
6884 "\tcpio -i[bcdfkmqrstuvBSV6] [-C size] "
6885 "[-E file] [-H hdr] [-I file [-M msg]] "
6886 "[-R id] [patterns]\n"
6887 "\tcpio -o[acvABLV] [-C size] "
6888 "[-H hdr] [-O file [-M msg]]\n"
6889 "\tcpio -p[adlmuvLV] [-R id] directory\n"));
6891 (void) fflush(stderr
);
6896 * verbose: For each file, print either the filename (-v) or a dot (-V).
6897 * If the -t option (table of contents) is set, print either the filename,
6898 * or if the -v option is also set, print an "ls -l"-like listing.
6902 verbose(char *nam_p
)
6910 * The printf format and associated arguments to print the current
6911 * filename. Normally, just nam_p. If we're processing an extended
6912 * attribute, these are overridden.
6914 char *name_fmt
= "%s";
6915 const char *name
= nam_p
;
6916 const char *attribute
= NULL
;
6918 if (Gen
.g_attrnam_p
!= NULL
) {
6921 * 'attribute' is a noun.
6924 if (Gen
.g_rw_sysattr
) {
6925 name_fmt
= gettext("%s system attribute %s");
6926 } else if ((Args
& OCt
) &&
6927 (is_sysattr(basename(Gen
.g_attrnam_p
)))) {
6928 name_fmt
= gettext("%s system attribute %s");
6930 name_fmt
= gettext("%s attribute %s");
6933 name
= (Args
& OCp
) ? nam_p
: Gen
.g_attrfnam_p
;
6934 if (Gen
.g_attrparent_p
== NULL
) {
6935 attribute
= Gen
.g_attrnam_p
;
6937 attribute
= Gen
.g_attrpath_p
;
6941 if ((Gen
.g_mode
== SECMODE
) || ((Hdr_type
== USTAR
||
6942 Hdr_type
== TAR
) && Thdr_p
->tbuf
.t_typeflag
== 'A')) {
6943 /* dont print ancillary file */
6947 for (i
= 0; i
< 11; i
++)
6950 modestr
[i
-1] = aclchar
;
6953 if ((Args
& OCt
) && (Args
& OCv
)) {
6955 for (i
= 0; i
< 3; i
++) {
6956 temp
= (mode
>> (6 - (i
* 3)));
6961 modestr
[j
+ 1] = 'w';
6963 modestr
[j
+ 2] = 'x';
6966 if (Hdr_type
!= BAR
) {
6967 temp
= Gen
.g_mode
& Ftype
;
6984 case (S_IFREG
): /* was initialized to '-' */
6990 msg(ERR
, "Impossible file type");
6993 temp
= Gen
.g_mode
& Ftype
;
7011 if (bar_linkflag
== SYMTYPE
)
7014 if ((S_ISUID
& Gen
.g_mode
) == S_ISUID
)
7016 if ((S_ISVTX
& Gen
.g_mode
) == S_ISVTX
)
7018 if ((S_ISGID
& G_p
->g_mode
) == S_ISGID
&& modestr
[6] == 'x')
7020 else if ((S_ENFMT
& Gen
.g_mode
) == S_ENFMT
&& modestr
[6] != 'x')
7022 if ((Hdr_type
== TAR
|| Hdr_type
== USTAR
) && Gen
.g_nlink
== 0)
7023 (void) printf("%s%4d ", modestr
, (int)Gen
.g_nlink
+1);
7025 (void) printf("%s%4d ", modestr
, (int)Gen
.g_nlink
);
7026 if (Lastuid
== (uid_t
)Gen
.g_uid
) {
7027 if (Lastuid
== (uid_t
)-1)
7028 (void) printf("-1 ");
7030 (void) printf("%-9s", Curpw_p
->pw_name
);
7032 if (Curpw_p
= getpwuid((int)Gen
.g_uid
)) {
7033 (void) printf("%-9s", Curpw_p
->pw_name
);
7034 Lastuid
= (uid_t
)Gen
.g_uid
;
7036 (void) printf("%-9d", (int)Gen
.g_uid
);
7037 Lastuid
= (uid_t
)-1;
7040 if (Lastgid
== (gid_t
)Gen
.g_gid
) {
7041 if (Lastgid
== (gid_t
)-1)
7042 (void) printf("-1 ");
7044 (void) printf("%-9s", Curgr_p
->gr_name
);
7046 if (Curgr_p
= getgrgid((int)Gen
.g_gid
)) {
7047 (void) printf("%-9s", Curgr_p
->gr_name
);
7048 Lastgid
= (gid_t
)Gen
.g_gid
;
7050 (void) printf("%-9d", (int)Gen
.g_gid
);
7051 Lastgid
= (gid_t
)-1;
7055 /* print file size */
7056 if (!Aspec
|| ((Gen
.g_mode
& Ftype
) == S_IFIFO
) ||
7057 ((Gen
.g_mode
& Ftype
) == S_IFSOCK
) ||
7058 (Hdr_type
== BAR
&& bar_linkflag
== SYMTYPE
)) {
7059 off_t filesz
= Gen
.g_filesz
;
7061 if (S_ISSPARSE(Gen
.g_mode
) && Gen
.g_holes
!= NULL
)
7062 filesz
= Gen
.g_holes
->orig_size
;
7064 if (filesz
< (1LL << 31))
7065 (void) printf("%7lld ", (offset_t
)filesz
);
7067 (void) printf("%11lld ", (offset_t
)filesz
);
7069 (void) printf("%3d,%3d ", (int)major(Gen
.g_rdev
),
7070 (int)minor(Gen
.g_rdev
));
7071 ttime
= Gen
.g_mtime
;
7072 (void) strftime(Time
, sizeof (Time
),
7073 dcgettext(NULL
, FORMAT
, LC_TIME
), localtime(&ttime
));
7074 (void) printf("%s, ", Time
);
7075 str_fprintf(stdout
, name_fmt
, name
, attribute
);
7076 if ((Gen
.g_mode
& Ftype
) == S_IFLNK
) {
7077 if (Hdr_type
== USTAR
|| Hdr_type
== TAR
)
7078 (void) strcpy(Symlnk_p
,
7079 Thdr_p
->tbuf
.t_linkname
);
7082 (void) strncpy(Symlnk_p
, Buffr
.b_out_p
,
7084 *(Symlnk_p
+ Gen
.g_filesz
) = '\0';
7086 (void) printf(" -> %s", Symlnk_p
);
7088 if (Hdr_type
== BAR
) {
7089 if (bar_linkflag
== SYMTYPE
)
7090 (void) printf(gettext(" symbolic link to %s"),
7092 else if (bar_linkflag
== '1')
7093 (void) printf(gettext(" linked to %s"),
7096 if ((Hdr_type
== USTAR
|| Hdr_type
== TAR
) &&
7097 Thdr_p
->tbuf
.t_typeflag
== '1') {
7098 (void) printf(gettext(" linked to %s%s%s"),
7099 (Gen
.g_attrnam_p
== NULL
) ?
7100 Thdr_p
->tbuf
.t_linkname
: Gen
.g_attrfnam_p
,
7101 (Gen
.g_attrnam_p
== NULL
) ? "" :
7102 gettext(" attribute "),
7103 (Gen
.g_attrnam_p
== NULL
) ?
7104 "" : Gen
.g_linktoattrnam_p
);
7106 (void) printf("\n");
7107 } else if ((Args
& OCt
) || (Args
& OCv
)) {
7108 str_fprintf(Out_p
, name_fmt
, name
, attribute
);
7109 (void) fputc('\n', Out_p
);
7111 (void) fputc('.', Out_p
);
7112 if (Verbcnt
++ >= 49) { /* start a new line of dots */
7114 (void) fputc('\n', Out_p
);
7117 (void) fflush(Out_p
);
7120 #define MK_USHORT(a) (a & 00000177777)
7123 * write_hdr: Transfer header information for the generic structure
7124 * into the format for the selected header and bwrite() the header.
7128 write_hdr(int arcflag
, off_t len
)
7134 const char warnfmt
[] = "%s%s%s : %s";
7142 case ARCHIVE_NORMAL
:
7144 * If attribute is being archived in cpio format then
7145 * zap off the file type bits since those are truly a
7146 * mask and reset them with _XATTR_CPIO_MODE
7149 * len is the value of g_filesz for normal files
7150 * and the length of the special header buffer in
7151 * the case of acl and xattr headers.
7153 if (G_p
->g_attrnam_p
!= NULL
&& Hdr_type
!= USTAR
&&
7155 mode
= (G_p
->g_mode
& POSIXMODES
) | _XATTR_CPIO_MODE
;
7159 if (arcflag
!= ARCHIVE_XATTR
) {
7160 len
= G_p
->g_filesz
;
7164 case ARCHIVE_SPARSE
:
7165 mode
= G_p
->g_mode
| C_ISSPARSE
;
7166 len
= G_p
->g_filesz
;
7173 * Handle EFT uids and gids. If they get too big
7174 * to be represented in a particular format, force 'em to 'nobody'.
7177 case BIN
: /* 16-bits of u_short */
7178 if ((ulong_t
)uid
> (ulong_t
)USHRT_MAX
)
7180 if ((ulong_t
)gid
> (ulong_t
)USHRT_MAX
)
7183 case CHR
: /* %.6lo => 262143 base 10 */
7184 if ((ulong_t
)uid
> (ulong_t
)0777777)
7186 if ((ulong_t
)gid
> (ulong_t
)0777777)
7189 case ASC
: /* %.8lx => full 32 bits */
7193 case TAR
: /* %.7lo => 2097151 base 10 */
7194 if ((ulong_t
)uid
> (ulong_t
)07777777)
7196 if ((ulong_t
)gid
> (ulong_t
)07777777)
7200 msg(EXT
, "Impossible header type.");
7204 * Since cpio formats -don't- encode the symbolic names, print
7205 * a warning message when we map the uid or gid this way.
7206 * Also, if the ownership just changed, clear set[ug]id bits
7208 * (Except for USTAR format of course, where we have a string
7209 * representation of the username embedded in the header)
7211 if (uid
!= G_p
->g_uid
&& Hdr_type
!= USTAR
) {
7213 (G_p
->g_attrnam_p
== NULL
) ?
7214 G_p
->g_nam_p
: G_p
->g_attrfnam_p
,
7215 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_rw_sysattr
?
7216 gettext(" System Attribute ") : gettext(" Attribute "),
7217 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
,
7218 gettext("uid too large for archive format"));
7222 if (gid
!= G_p
->g_gid
&& Hdr_type
!= USTAR
) {
7224 (G_p
->g_attrnam_p
== NULL
) ?
7225 G_p
->g_nam_p
: G_p
->g_attrfnam_p
,
7226 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_rw_sysattr
?
7227 gettext(" System Attribute ") : gettext(" Attribute "),
7228 (G_p
->g_attrnam_p
== NULL
) ? "" : G_p
->g_attrnam_p
,
7229 gettext("gid too large for archive format"));
7239 cnt
= Hdrsz
+ G_p
->g_namesz
;
7243 case USTAR
: /* TAR and USTAR */
7247 msg(EXT
, "Impossible header type.");
7253 Hdr
.h_magic
= (short)G_p
->g_magic
;
7254 Hdr
.h_dev
= G_p
->g_dev
;
7255 Hdr
.h_ino
= G_p
->g_ino
;
7259 Hdr
.h_nlink
= G_p
->g_nlink
;
7260 Hdr
.h_rdev
= G_p
->g_rdev
;
7261 mkshort(Hdr
.h_mtime
, (long)G_p
->g_mtime
);
7262 Hdr
.h_namesize
= (short)G_p
->g_namesz
;
7263 mkshort(Hdr
.h_filesize
, (long)len
);
7264 (void) strcpy(Hdr
.h_name
, G_p
->g_nam_p
);
7265 (void) memcpy(Buffr
.b_in_p
, &Hdr
, cnt
);
7269 (void) sprintf(Buffr
.b_in_p
,
7270 "%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.11lo%.6lo%."
7271 "11llo%s", G_p
->g_magic
, G_p
->g_dev
, G_p
->g_ino
, mode
,
7272 (long)uid
, (long)gid
, G_p
->g_nlink
, MK_USHORT(G_p
->g_rdev
),
7273 G_p
->g_mtime
, (long)G_p
->g_namesz
, (offset_t
)len
,
7279 (void) sprintf(Buffr
.b_in_p
,
7280 "%.6lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%."
7281 "8lx%.8lx%.8lx%.8lx%s",
7282 G_p
->g_magic
, G_p
->g_ino
, mode
, G_p
->g_uid
,
7283 G_p
->g_gid
, G_p
->g_nlink
, G_p
->g_mtime
, (ulong_t
)len
,
7284 major(G_p
->g_dev
), minor(G_p
->g_dev
),
7285 major(G_p
->g_rdev
), minor(G_p
->g_rdev
),
7286 G_p
->g_namesz
, G_p
->g_cksum
, G_p
->g_nam_p
);
7289 Thdr_p
= (union tblock
*)Buffr
.b_in_p
;
7290 (void) memset(Thdr_p
, 0, TARSZ
);
7291 (void) strncpy(Thdr_p
->tbuf
.t_name
, G_p
->g_tname
,
7292 (int)strlen(G_p
->g_tname
));
7293 (void) sprintf(Thdr_p
->tbuf
.t_mode
, "%07o", (int)mode
);
7294 (void) sprintf(Thdr_p
->tbuf
.t_uid
, "%07o", (int)uid
);
7295 (void) sprintf(Thdr_p
->tbuf
.t_gid
, "%07o", (int)gid
);
7296 (void) sprintf(Thdr_p
->tbuf
.t_size
, "%011llo",
7298 (void) sprintf(Thdr_p
->tbuf
.t_mtime
, "%011lo", G_p
->g_mtime
);
7299 if (arcflag
== ARCHIVE_ACL
) {
7300 Thdr_p
->tbuf
.t_typeflag
= 'A'; /* ACL file type */
7301 } else if (arcflag
== ARCHIVE_XATTR
||
7302 (G_p
->g_attrnam_p
!= NULL
)) {
7303 Thdr_p
->tbuf
.t_typeflag
= _XATTR_HDRTYPE
;
7305 Thdr_p
->tbuf
.t_typeflag
= G_p
->g_typeflag
;
7307 if (T_lname
[0] != '\0') {
7309 * if not a symbolic link
7311 if (((G_p
->g_mode
& Ftype
) != S_IFLNK
) &&
7312 (G_p
->g_attrnam_p
== NULL
)) {
7313 Thdr_p
->tbuf
.t_typeflag
= LNKTYPE
;
7314 (void) sprintf(Thdr_p
->tbuf
.t_size
,
7317 (void) strncpy(Thdr_p
->tbuf
.t_linkname
, T_lname
,
7320 (void) strcpy(Thdr_p
->tbuf
.t_magic
, TMAGIC
);
7321 (void) strcpy(Thdr_p
->tbuf
.t_version
, TVERSION
);
7322 (void) strcpy(Thdr_p
->tbuf
.t_uname
, G_p
->g_uname
);
7323 (void) strcpy(Thdr_p
->tbuf
.t_gname
, G_p
->g_gname
);
7324 (void) sprintf(Thdr_p
->tbuf
.t_devmajor
, "%07o",
7325 (int)major(G_p
->g_rdev
));
7326 (void) sprintf(Thdr_p
->tbuf
.t_devminor
, "%07o",
7327 (int)minor(G_p
->g_rdev
));
7329 (void) strcpy(Thdr_p
->tbuf
.t_prefix
, Gen
.g_prefix
);
7331 Gen
.g_prefix
= NULL
;
7333 Thdr_p
->tbuf
.t_prefix
[0] = '\0';
7335 (void) sprintf(Thdr_p
->tbuf
.t_cksum
, "%07o",
7336 (int)cksum(TARTYP
, 0, NULL
));
7339 Thdr_p
= (union tblock
*)Buffr
.b_in_p
;
7340 (void) memset(Thdr_p
, 0, TARSZ
);
7341 (void) strncpy(Thdr_p
->tbuf
.t_name
, G_p
->g_nam_p
,
7343 (void) sprintf(Thdr_p
->tbuf
.t_mode
, "%07o ", (int)mode
);
7344 (void) sprintf(Thdr_p
->tbuf
.t_uid
, "%07o ", (int)uid
);
7345 (void) sprintf(Thdr_p
->tbuf
.t_gid
, "%07o ", (int)gid
);
7346 (void) sprintf(Thdr_p
->tbuf
.t_size
, "%011llo ",
7348 (void) sprintf(Thdr_p
->tbuf
.t_mtime
, "%011o ",
7350 if (T_lname
[0] != '\0') {
7351 Thdr_p
->tbuf
.t_typeflag
= '1';
7353 Thdr_p
->tbuf
.t_typeflag
= '\0';
7355 (void) strncpy(Thdr_p
->tbuf
.t_linkname
, T_lname
,
7359 msg(EXT
, "Impossible header type.");
7362 Buffr
.b_in_p
+= cnt
;
7364 pad
= ((cnt
+ Pad_val
) & ~Pad_val
) - cnt
;
7367 (void) memset(Buffr
.b_in_p
, 0, pad
);
7368 Buffr
.b_in_p
+= pad
;
7374 * write_trail: Create the appropriate trailer for the selected header type
7375 * and bwrite the trailer. Pad the buffer with nulls out to the next Bufsize
7376 * boundary, and force a write. If the write completes, or if the trailer is
7377 * completely written (but not all of the padding nulls (as can happen on end
7378 * of medium)) return. Otherwise, the trailer was not completely written out,
7379 * so re-pad the buffer with nulls and try again.
7389 Gen
.g_magic
= CMN_BIN
;
7392 Gen
.g_magic
= CMN_BIN
;
7395 Gen
.g_magic
= CMN_ASC
;
7398 Gen
.g_magic
= CMN_CRC
;
7407 Gen
.g_mode
= Gen
.g_uid
= Gen
.g_gid
= 0;
7409 Gen
.g_mtime
= Gen
.g_ino
= Gen
.g_dev
= 0;
7410 Gen
.g_rdev
= Gen
.g_cksum
= 0;
7411 Gen
.g_filesz
= (off_t
)0;
7412 Gen
.g_namesz
= strlen("TRAILER!!!") + 1;
7413 (void) strcpy(Gen
.g_nam_p
, "TRAILER!!!");
7415 write_hdr(ARCHIVE_NORMAL
, (off_t
)0);
7419 case USTAR
: /* TAR and USTAR */
7420 for (cnt
= 0; cnt
< 3; cnt
++) {
7422 (void) memset(Buffr
.b_in_p
, 0, TARSZ
);
7423 Buffr
.b_in_p
+= TARSZ
;
7424 Buffr
.b_cnt
+= TARSZ
;
7428 msg(EXT
, "Impossible header type.");
7430 need
= Bufsize
- (Buffr
.b_cnt
% Bufsize
);
7431 if (need
== Bufsize
)
7434 while (Buffr
.b_cnt
> 0) {
7436 cnt
= (need
< TARSZ
) ? need
: TARSZ
;
7439 (void) memset(Buffr
.b_in_p
, 0, cnt
);
7440 Buffr
.b_in_p
+= cnt
;
7448 * if archives in USTAR format, check if typeflag == '5' for directories
7453 if (Hdr_type
== USTAR
|| Hdr_type
== TAR
) {
7454 if (Thdr_p
->tbuf
.t_typeflag
== '5')
7461 * if archives in USTAR format, check if typeflag == '3' || '4' || '6'
7462 * for character, block, fifo special files
7469 if (Hdr_type
== USTAR
|| Hdr_type
== TAR
) {
7470 typeflag
= Thdr_p
->tbuf
.t_typeflag
;
7471 if (typeflag
== '3' || typeflag
== '4' || typeflag
== '6')
7478 * The return value is a pointer to a converted copy of the information in
7479 * FromStat if the file is representable in -Hodc format, and NULL otherwise.
7482 static struct stat
*
7483 convert_to_old_stat(struct stat
*FromStat
, char *namep
, char *attrp
)
7485 static struct stat ToSt
;
7488 (void) memset(&TmpSt
, 0, sizeof (cpioinfo_t
));
7489 stat_to_svr32_stat(&TmpSt
, FromStat
);
7490 (void) memset(&ToSt
, 0, sizeof (ToSt
));
7492 if (TmpSt
.st_rdev
== (o_dev_t
)NODEV
&&
7493 (((TmpSt
.st_mode
& Ftype
) == S_IFCHR
) ||
7494 ((TmpSt
.st_mode
& Ftype
) == S_IFBLK
))) {
7496 * Encountered a problem representing the rdev information.
7500 msg(ERR
, "Error -Hodc format can't support expanded"
7503 (attrp
== NULL
) ? "" : gettext(" Attribute"),
7504 (attrp
== NULL
) ? "" : attrp
);
7508 if (TmpSt
.st_dev
== (o_dev_t
)NODEV
) {
7510 * Having trouble representing the device/inode pair. We can't
7511 * track links in this case; break them all into separate
7517 if (((TmpSt
.st_mode
& Ftype
) != S_IFDIR
) &&
7520 "Warning: file %s%s%s has large "
7521 "device number - linked "
7522 "files will be restored as "
7525 (attrp
== NULL
) ? "" : gettext(" Attribute"),
7526 (attrp
== NULL
) ? "" : attrp
);
7528 /* ensure no links */
7533 /* Start converting values */
7535 if (TmpSt
.st_dev
< 0) {
7538 ToSt
.st_dev
= (dev_t
)TmpSt
.st_dev
;
7541 /* -actual- not truncated uid */
7543 ToSt
.st_uid
= TmpSt
.st_uid
;
7545 /* -actual- not truncated gid */
7547 ToSt
.st_gid
= TmpSt
.st_gid
;
7548 ToSt
.st_ino
= (ino_t
)TmpSt
.st_ino
;
7549 ToSt
.st_mode
= (mode_t
)TmpSt
.st_mode
;
7550 ToSt
.st_mtime
= (ulong_t
)TmpSt
.st_modtime
;
7551 ToSt
.st_nlink
= (nlink_t
)TmpSt
.st_nlink
;
7552 ToSt
.st_size
= (off_t
)TmpSt
.st_size
;
7553 ToSt
.st_rdev
= (dev_t
)TmpSt
.st_rdev
;
7559 * In the beginning of each bar archive, there is a header which describes the
7560 * current volume being created, followed by a header which describes the
7561 * current file being created, followed by the file itself. If there is
7562 * more than one file to be created, a separate header will be created for
7563 * each additional file. This structure may be repeated if the bar archive
7564 * contains multiple volumes. If a file spans across volumes, its header
7565 * will not be repeated in the next volume.
7566 * +------------------+
7568 * |------------------|
7569 * | file header i | i = 0
7570 * |------------------|
7572 * |------------------|
7573 * | file header i+1 |
7574 * |------------------|
7576 * |------------------|
7580 * +------------------+
7584 * read in the header that describes the current volume of the bar archive
7588 read_bar_vol_hdr(void)
7590 union b_block
*tmp_hdr
;
7592 tmp_hdr
= (union b_block
*)Buffr
.b_out_p
;
7593 if (tmp_hdr
->dbuf
.bar_magic
[0] == BAR_VOLUME_MAGIC
) {
7595 if (bar_Vhdr
== NULL
) {
7596 bar_Vhdr
= e_zalloc(E_EXIT
, TBLOCK
);
7598 (void) memcpy(&(bar_Vhdr
->dbuf
), &(tmp_hdr
->dbuf
), TBLOCK
);
7600 (void) fprintf(stderr
, gettext(
7601 "bar error: cannot read volume header\n"));
7605 (void) sscanf(bar_Vhdr
->dbuf
.mode
, "%8lo", &Gen_bar_vol
.g_mode
);
7606 (void) sscanf(bar_Vhdr
->dbuf
.uid
, "%8d", (int *)&Gen_bar_vol
.g_uid
);
7607 (void) sscanf(bar_Vhdr
->dbuf
.gid
, "%8d", (int *)&Gen_bar_vol
.g_gid
);
7608 (void) sscanf(bar_Vhdr
->dbuf
.size
, "%12llo",
7609 (u_off_t
*)&Gen_bar_vol
.g_filesz
);
7610 (void) sscanf(bar_Vhdr
->dbuf
.mtime
, "%12lo", &Gen_bar_vol
.g_mtime
);
7611 (void) sscanf(bar_Vhdr
->dbuf
.chksum
, "%8lo", &Gen_bar_vol
.g_cksum
);
7613 /* set the compress flag */
7614 if (bar_Vhdr
->dbuf
.compressed
== '1')
7619 Buffr
.b_out_p
+= 512;
7623 * not the first volume; exit
7625 if (strcmp(bar_Vhdr
->dbuf
.volume_num
, "1") != 0) {
7626 (void) fprintf(stderr
,
7627 gettext("error: This is not volume 1. "));
7628 (void) fprintf(stderr
, gettext("This is volume %s. "),
7629 bar_Vhdr
->dbuf
.volume_num
);
7630 (void) fprintf(stderr
, gettext("Please insert volume 1.\n"));
7634 read_bar_file_hdr();
7638 * read in the header that describes the current file to be extracted
7641 read_bar_file_hdr(void)
7643 union b_block
*tmp_hdr
;
7644 char *start_of_name
, *name_p
;
7647 if (*Buffr
.b_out_p
== '\0') {
7648 *Gen
.g_nam_p
= '\0';
7652 tmp_hdr
= (union b_block
*)Buffr
.b_out_p
;
7654 tmp
= &tmp_hdr
->dbuf
.mode
[1];
7655 (void) sscanf(tmp
, "%8lo", &Gen
.g_mode
);
7656 (void) sscanf(tmp_hdr
->dbuf
.uid
, "%8lo", &Gen
.g_uid
);
7657 (void) sscanf(tmp_hdr
->dbuf
.gid
, "%8lo", &Gen
.g_gid
);
7658 (void) sscanf(tmp_hdr
->dbuf
.size
, "%12llo",
7659 (u_off_t
*)&Gen
.g_filesz
);
7660 (void) sscanf(tmp_hdr
->dbuf
.mtime
, "%12lo", &Gen
.g_mtime
);
7661 (void) sscanf(tmp_hdr
->dbuf
.chksum
, "%8lo", &Gen
.g_cksum
);
7662 (void) sscanf(tmp_hdr
->dbuf
.rdev
, "%8lo", &Gen
.g_rdev
);
7664 #define to_new_major(x) (int)((unsigned)((x) & OMAXMAJ) << NBITSMINOR)
7665 #define to_new_minor(x) (int)((x) & OMAXMIN)
7666 Gen
.g_rdev
= to_new_major(Gen
.g_rdev
) | to_new_minor(Gen
.g_rdev
);
7667 bar_linkflag
= tmp_hdr
->dbuf
.linkflag
;
7668 start_of_name
= &tmp_hdr
->dbuf
.start_of_name
;
7671 name_p
= Gen
.g_nam_p
;
7672 while (*name_p
++ = *start_of_name
++)
7675 if (bar_linkflag
== LNKTYPE
|| bar_linkflag
== SYMTYPE
)
7676 (void) strcpy(bar_linkname
, start_of_name
);
7678 Gen
.g_namesz
= strlen(Gen
.g_nam_p
) + 1;
7679 (void) strcpy(nambuf
, Gen
.g_nam_p
);
7683 * if the bar archive is compressed, set up a pipe and do the de-compression
7684 * as the compressed file is read in.
7687 setup_uncompress(FILE **pipef
)
7692 cmd_buf
= e_zalloc(E_EXIT
, MAXPATHLEN
* 2);
7694 if (access(Gen
.g_nam_p
, W_OK
) != 0) {
7695 cmdlen
= snprintf(cmd_buf
, MAXPATHLEN
* 2,
7696 "chmod +w '%s'; uncompress -c > '%s'; "
7698 Gen
.g_nam_p
, Gen
.g_nam_p
, (int)G_p
->g_mode
, Gen
.g_nam_p
);
7700 cmdlen
= snprintf(cmd_buf
, MAXPATHLEN
* 2,
7701 "uncompress -c > '%s'", Gen
.g_nam_p
);
7704 if (cmdlen
>= MAXPATHLEN
* 2 ||
7705 (*pipef
= popen(cmd_buf
, "w")) == NULL
) {
7706 (void) fprintf(stderr
, gettext("error\n"));
7710 if (close(Ofile
) != 0)
7711 msg(EXTN
, "close error");
7712 Ofile
= fileno(*pipef
);
7718 * if the bar archive spans multiple volumes, read in the header that
7719 * describes the next volume.
7722 skip_bar_volhdr(void)
7725 union b_block
*tmp_hdr
;
7727 buff
= e_zalloc(E_EXIT
, (uint_t
)Bufsize
);
7729 if (g_read(Device
, Archive
, buff
, Bufsize
) < 0) {
7730 (void) fprintf(stderr
, gettext(
7731 "error in skip_bar_volhdr\n"));
7734 tmp_hdr
= (union b_block
*)buff
;
7735 if (tmp_hdr
->dbuf
.bar_magic
[0] == BAR_VOLUME_MAGIC
) {
7737 if (bar_Vhdr
== NULL
) {
7738 bar_Vhdr
= e_zalloc(E_EXIT
, TBLOCK
);
7740 (void) memcpy(&(bar_Vhdr
->dbuf
),
7741 &(tmp_hdr
->dbuf
), TBLOCK
);
7743 (void) fprintf(stderr
,
7744 gettext("cpio error: cannot read bar volume "
7749 (void) sscanf(bar_Vhdr
->dbuf
.mode
, "%8lo",
7750 &Gen_bar_vol
.g_mode
);
7751 (void) sscanf(bar_Vhdr
->dbuf
.uid
, "%8lo",
7752 &Gen_bar_vol
.g_uid
);
7753 (void) sscanf(bar_Vhdr
->dbuf
.gid
, "%8lo",
7754 &Gen_bar_vol
.g_gid
);
7755 (void) sscanf(bar_Vhdr
->dbuf
.size
, "%12llo",
7756 (u_off_t
*)&Gen_bar_vol
.g_filesz
);
7757 (void) sscanf(bar_Vhdr
->dbuf
.mtime
, "%12lo",
7758 &Gen_bar_vol
.g_mtime
);
7759 (void) sscanf(bar_Vhdr
->dbuf
.chksum
, "%8lo",
7760 &Gen_bar_vol
.g_cksum
);
7761 if (bar_Vhdr
->dbuf
.compressed
== '1')
7768 * Now put the rest of the bytes read in into the data buffer.
7770 (void) memcpy(Buffr
.b_in_p
, &buff
[512], (Bufsize
- 512));
7771 Buffr
.b_in_p
+= (Bufsize
- 512);
7772 Buffr
.b_cnt
+= (long)(Bufsize
- 512);
7778 * check the linkflag which indicates the type of the file to be extracted,
7779 * invoke the corresponding routine to extract the file.
7785 * the file is a directory
7788 if (ckname(1) != F_SKIP
&& creat_spec(G_p
->g_dirfd
) > 0) {
7789 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
7794 switch (bar_linkflag
) {
7797 if ((ckname(1) == F_SKIP
) ||
7798 (Ofile
= openout(G_p
->g_dirfd
)) < 0) {
7806 if (ckname(1) == F_SKIP
) {
7809 (void) creat_lnk(G_p
->g_dirfd
, bar_linkname
, G_p
->g_nam_p
);
7813 if ((ckname(1) == F_SKIP
) ||
7814 (Ofile
= openout(G_p
->g_dirfd
)) < 0) {
7821 /* character device or FIFO */
7822 if (ckname(1) != F_SKIP
&& creat_spec(G_p
->g_dirfd
) > 0) {
7823 VERBOSE((Args
& (OCv
| OCV
)), G_p
->g_nam_p
);
7827 (void) fprintf(stderr
, gettext("error: unknown file type\n"));
7834 * This originally came from libgenIO/g_init.c
7835 * XXX And it is very broken.
7838 /* #include <sys/statvfs.h> */
7840 /* #include <libgenIO.h> */
7841 #define G_TM_TAPE 1 /* Tapemaster controller */
7842 #define G_XY_DISK 3 /* xy disks */
7843 #define G_SD_DISK 7 /* scsi sd disk */
7844 #define G_XT_TAPE 8 /* xt tapes */
7845 #define G_SF_FLOPPY 9 /* sf floppy */
7846 #define G_XD_DISK 10 /* xd disks */
7847 #define G_ST_TAPE 11 /* scsi tape */
7848 #define G_NS 12 /* noswap pseudo-dev */
7849 #define G_RAM 13 /* ram pseudo-dev */
7850 #define G_FT 14 /* tftp */
7851 #define G_HD 15 /* 386 network disk */
7852 #define G_FD 16 /* 386 AT disk */
7853 #define G_FILE 28 /* file, not a device */
7854 #define G_NO_DEV 29 /* device does not require special treatment */
7855 #define G_DEV_MAX 30 /* last valid device type */
7858 * g_init: Determine the device being accessed, set the buffer size,
7859 * and perform any device specific initialization. Since at this point
7860 * Sun has no system call to read the configuration, the major numbers
7861 * are assumed to be static and types are figured out as such. However,
7862 * as a rough estimate, the buffer size for all types is set to 512
7867 g_init(int *devtype
, int *fdes
)
7871 struct statvfs stfs_buf
;
7873 *devtype
= G_NO_DEV
;
7875 if (fstat(*fdes
, &st_buf
) == -1)
7877 if (!S_ISCHR(st_buf
.st_mode
) && !S_ISBLK(st_buf
.st_mode
)) {
7878 if (S_ISFIFO(st_buf
.st_mode
)) {
7881 /* find block size for this file system */
7883 if (fstatvfs(*fdes
, &stfs_buf
) < 0) {
7887 bufsize
= stfs_buf
.f_bsize
;
7893 * We'll have to add a remote attribute to stat but this
7894 * should work for now.
7896 } else if (st_buf
.st_dev
& 0x8000) /* if remote rdev */
7901 if (Hdr_type
== BAR
) {
7902 if (is_tape(*fdes
)) {
7903 bufsize
= BAR_TAPE_SIZE
;
7904 msg(EPOST
, "Archiving to tape blocking factor 126");
7905 } else if (is_floppy(*fdes
)) {
7906 bufsize
= BAR_FLOPPY_SIZE
;
7907 msg(EPOST
, "Archiving to floppy blocking factor 18");
7915 * This originally came from libgenIO/g_read.c
7919 * g_read: Read nbytes of data from fdes (of type devtype) and place
7920 * data in location pointed to by buf. In case of end of medium,
7921 * translate (where necessary) device specific EOM indications into
7922 * the generic EOM indication of rv = -1, errno = ENOSPC.
7926 g_read(int devtype
, int fdes
, char *buf
, unsigned nbytes
)
7930 if (devtype
< 0 || devtype
>= G_DEV_MAX
) {
7935 rv
= read(fdes
, buf
, nbytes
);
7937 /* st devices return 0 when no space left */
7938 if ((rv
== 0 && errno
== 0 && Hdr_type
!= BAR
) ||
7939 (rv
== -1 && errno
== EIO
)) {
7948 * This originally came from libgenIO/g_write.c
7952 * g_write: Write nbytes of data to fdes (of type devtype) from
7953 * the location pointed to by buf. In case of end of medium,
7954 * translate (where necessary) device specific EOM indications into
7955 * the generic EOM indication of rv = -1, errno = ENOSPC.
7959 g_write(int devtype
, int fdes
, char *buf
, unsigned nbytes
)
7963 if (devtype
< 0 || devtype
>= G_DEV_MAX
) {
7968 rv
= write(fdes
, buf
, nbytes
);
7970 /* st devices return 0 when no more space left */
7971 if ((rv
== 0 && errno
== 0) || (rv
== -1 && errno
== EIO
)) {
7989 * try to do a generic tape ioctl, just to see if
7990 * the thing is in fact a tape drive(er).
7992 if (ioctl(fd
, MTIOCGET
, &stuff
) != -1) {
7993 /* the ioctl succeeded, must have been a tape */
8006 struct fd_char stuff
;
8009 * try to get the floppy drive characteristics, just to see if
8010 * the thing is in fact a floppy drive(er).
8012 if (ioctl(fd
, FDIOGCHAR
, &stuff
) != -1) {
8013 /* the ioctl succeeded, must have been a floppy */
8021 * New functions for ACLs and other security attributes
8025 * The function appends the new security attribute info to the end of
8030 char **secinfo
, /* existing security info */
8031 int *secinfo_len
, /* length of existing security info */
8032 acl_t
*aclp
) /* new attribute data pointer */
8039 /* no need to add */
8044 switch (acl_type(aclp
)) {
8047 attrtext
= acl_totext(aclp
, ACL_APPEND_ID
| ACL_COMPACT_FMT
|
8049 if (attrtext
== NULL
) {
8050 msg(EPOST
, "acltotext failed");
8053 /* header: type + size = 8 */
8054 newattrsize
= 8 + strlen(attrtext
) + 1;
8055 attr
= e_zalloc(E_NORMAL
, newattrsize
);
8057 msg(EPOST
, "can't allocate memory");
8060 attr
->attr_type
= (acl_type(aclp
) == ACLENT_T
) ?
8062 /* acl entry count */
8063 (void) sprintf(attr
->attr_len
, "%06o", acl_cnt(aclp
));
8064 (void) strcpy((char *)&attr
->attr_info
[0], attrtext
);
8068 /* SunFed's case goes here */
8071 msg(EPOST
, "unrecognized attribute type");
8075 /* old security info + new attr header(8) + new attr */
8076 oldsize
= *secinfo_len
;
8077 *secinfo_len
+= newattrsize
;
8078 new_secinfo
= e_zalloc(E_NORMAL
, (uint_t
)*secinfo_len
);
8079 if (new_secinfo
== NULL
) {
8080 msg(EPOST
, "can't allocate memory");
8081 *secinfo_len
-= newattrsize
;
8085 (void) memcpy(new_secinfo
, *secinfo
, oldsize
);
8086 (void) memcpy(new_secinfo
+ oldsize
, attr
, newattrsize
);
8089 *secinfo
= new_secinfo
;
8094 * Append size amount of data from buf to the archive.
8097 write_ancillary(char *buf
, size_t len
, boolean_t padding
)
8105 cnt
= (unsigned)(len
> CPIOBSZ
) ? CPIOBSZ
: len
;
8108 (void) memcpy(Buffr
.b_in_p
, buf
, (unsigned)cnt
);
8109 Buffr
.b_in_p
+= cnt
;
8115 pad
= (Pad_val
+ 1 - (cnt
& Pad_val
)) & Pad_val
;
8118 (void) memset(Buffr
.b_in_p
, 0, pad
);
8119 Buffr
.b_in_p
+= pad
;
8126 remove_dir(char *path
)
8129 struct dirent
*direct
;
8133 #define MSG1 "remove_dir() failed to stat(\"%s\") "
8134 #define MSG2 "remove_dir() failed to remove_dir(\"%s\") "
8135 #define MSG3 "remove_dir() failed to unlink(\"%s\") "
8138 * Open the directory for reading.
8140 if ((name
= opendir(path
)) == NULL
) {
8141 msg(ERRN
, "remove_dir() failed to opendir(\"%s\") ", path
);
8145 if (chdir(path
) == -1) {
8146 msg(ERRN
, "remove_dir() failed to chdir(\"%s\") ", path
);
8151 * Read every directory entry.
8153 while ((direct
= readdir(name
)) != NULL
) {
8155 * Ignore "." and ".." entries.
8157 if (strcmp(direct
->d_name
, ".") == 0 ||
8158 strcmp(direct
->d_name
, "..") == 0)
8161 if (lstat(direct
->d_name
, &sbuf
) == -1) {
8162 msg(ERRN
, MSG1
, direct
->d_name
);
8163 (void) closedir(name
);
8167 if (S_ISDIR(sbuf
.st_mode
)) {
8168 if (remove_dir(direct
->d_name
) == -1) {
8169 msg(ERRN
, MSG2
, direct
->d_name
);
8170 (void) closedir(name
);
8174 if (unlink(direct
->d_name
) == -1) {
8175 msg(ERRN
, MSG3
, direct
->d_name
);
8176 (void) closedir(name
);
8184 * Close the directory we just finished reading.
8186 (void) closedir(name
);
8189 * Change directory to the parent directory...
8191 if (chdir("..") == -1) {
8192 msg(ERRN
, "remove_dir() failed to chdir(\"..\") ");
8197 * ...and finally remove the directory; note we have to
8198 * make a copy since basename is free to modify its input.
8200 path_copy
= e_strdup(E_NORMAL
, path
);
8201 if (path_copy
== NULL
) {
8202 msg(ERRN
, "cannot strdup() the directory pathname ");
8206 if (rmdir(basename(path_copy
)) == -1) {
8208 msg(ERRN
, "remove_dir() failed to rmdir(\"%s\") ", path
);
8220 return (open(".", O_RDONLY
));
8230 #if defined(O_XATTR)
8232 xattrs_out(int (*func
)())
8236 int arc_rwsysattr
= 0;
8243 char *namep
, *savenamep
;
8245 char *attrparent
= Gen
.g_attrparent_p
;
8248 if (attrparent
== NULL
) {
8249 filename
= Gen
.g_nam_p
;
8251 filename
= Gen
.g_attrnam_p
;
8255 * If the underlying file system supports it, then
8256 * archive the extended attributes if -@ was specified,
8257 * and the extended system attributes if -/ was
8260 if (verify_attr_support(filename
, (attrparent
== NULL
), ARC_CREATE
,
8261 &ext_attr
) != ATTR_OK
) {
8265 #if defined(_PC_SATTR_ENABLED)
8268 nvlist_t
*slist
= NULL
;
8271 * Determine if there are non-transient system
8275 if ((filefd
= open(filename
, O_RDONLY
)) == -1) {
8276 if (attrparent
== NULL
) {
8278 "unable to open %s%s%sfile %s",
8279 (attrparent
== NULL
) ? "" :
8280 gettext("attribute "),
8281 (attrparent
== NULL
) ? "" : attrparent
,
8282 (attrparent
== NULL
) ? "" : gettext(" of "),
8283 (attrparent
== NULL
) ? G_p
->g_nam_p
:
8287 if (((slist
= sysattr_list(myname
, filefd
,
8288 filename
)) != NULL
) || (errno
!= 0)) {
8291 if (slist
!= NULL
) {
8292 (void) nvlist_free(slist
);
8295 (void) close(filefd
);
8299 * If we aren't archiving extended system attributes, and we are
8300 * processing an attribute, or if we are archiving extended system
8301 * attributes, and there are are no extended attributes, then there's
8302 * no need to open up the attribute directory of the file unless the
8303 * extended system attributes are not transient (i.e, the system
8304 * attributes are not the default values).
8306 if ((arc_rwsysattr
== 0) && ((attrparent
!= NULL
) ||
8307 (SysAtflag
&& !ext_attr
))) {
8311 #endif /* _PC_SATTR_ENABLED */
8314 * If aclp still exists then free it since it is was set when base
8315 * file was extracted.
8323 Gen
.g_dirfd
= attropen(filename
, ".", O_RDONLY
);
8324 if (Gen
.g_dirfd
== -1) {
8325 msg(ERRN
, "Cannot open attribute directory of file \"%s%s%s\"",
8326 (attrparent
== NULL
) ? "" : gettext("attribute "),
8327 (attrparent
== NULL
) ? "" : attrparent
,
8328 (attrparent
== NULL
) ? "" : gettext(" of "), filename
);
8333 if (attrparent
== NULL
) {
8334 savenamep
= G_p
->g_nam_p
;
8336 savenamep
= G_p
->g_attrfnam_p
;
8339 if ((dirpfd
= dup(Gen
.g_dirfd
)) == -1) {
8340 msg(ERRN
, "Cannot dup(2) attribute directory descriptor");
8344 if ((dirp
= fdopendir(dirpfd
)) == NULL
) {
8345 msg(ERRN
, "Cannot fdopendir(2) directory file descriptor");
8349 if (attrparent
== NULL
) {
8350 Gen
.g_baseparent_fd
= save_cwd();
8353 while ((dp
= readdir(dirp
)) != NULL
) {
8354 if (strcmp(dp
->d_name
, "..") == 0) {
8357 if (verify_attr(dp
->d_name
, attrparent
,
8358 arc_rwsysattr
, &rw_sysattr
) != ATTR_OK
) {
8362 if (strcmp(dp
->d_name
, ".") == 0) {
8368 Gen
.g_rw_sysattr
= rw_sysattr
;
8369 Gen
.g_attrnam_p
= dp
->d_name
;
8371 if (STAT(Gen
.g_dirfd
, Gen
.g_nam_p
, &SrcSt
) == -1) {
8373 "Could not fstatat(2) attribute \"%s\" of"
8374 " file \"%s\"", dp
->d_name
, (attrparent
== NULL
) ?
8375 savenamep
: Gen
.g_attrfnam_p
);
8380 Savedev
= SrcSt
.st_dev
;
8381 OldSt
= convert_to_old_stat(&SrcSt
,
8382 Gen
.g_nam_p
, Gen
.g_attrnam_p
);
8384 if (OldSt
== NULL
) {
8386 "Could not convert to old stat format");
8391 Gen
.g_attrfnam_p
= savenamep
;
8394 * Set up dummy header name
8396 * One piece is written with .hdr, which
8397 * contains the actual xattr hdr or pathing information
8398 * then the name is updated to drop the .hdr off
8399 * and the actual file itself is archived.
8401 slen
= strlen(Gen
.g_attrnam_p
) + strlen(DEVNULL
) +
8402 strlen(XATTRHDR
) + 2; /* add one for '/' */
8403 if ((namep
= e_zalloc(E_NORMAL
, slen
)) == NULL
) {
8404 msg(ERRN
, "Could not calloc memory for attribute name");
8407 (void) snprintf(namep
, slen
, "%s/%s%s",
8408 DEVNULL
, Gen
.g_attrnam_p
, XATTRHDR
);
8409 Gen
.g_nam_p
= namep
;
8411 plen
= strlen(Gen
.g_attrnam_p
) + 1;
8412 if (Gen
.g_attrparent_p
!= NULL
) {
8413 plen
+= strlen(Gen
.g_attrparent_p
) + 1;
8415 if ((apathp
= e_zalloc(E_NORMAL
, plen
)) == NULL
) {
8416 msg(ERRN
, "Could not calloc memory for attribute name");
8419 (void) snprintf(apathp
, plen
, "%s%s%s",
8420 (Gen
.g_attrparent_p
== NULL
) ? "" : Gen
.g_attrparent_p
,
8421 (Gen
.g_attrparent_p
== NULL
) ? "" : "/", Gen
.g_attrnam_p
);
8423 if (Gen
.g_attrpath_p
!= NULL
) {
8424 free(Gen
.g_attrpath_p
);
8426 Gen
.g_attrpath_p
= apathp
;
8429 * Get attribute's ACL info: don't bother allocating space
8430 * if there are only standard permissions, i.e. ACL count < 4
8433 filefd
= openat(Gen
.g_dirfd
, dp
->d_name
, O_RDONLY
);
8436 "Could not open attribute \"%s\" of"
8437 " file \"%s\"", dp
->d_name
, savenamep
);
8441 if (facl_get(filefd
, ACL_NO_TRIVIAL
, &aclp
) != 0) {
8443 "Error with acl() on %s",
8446 (void) close(filefd
);
8452 #if defined(_PC_SATTR_ENABLED)
8454 * Recursively call xattrs_out() to process the attribute's
8455 * hidden attribute directory and read-write system attributes.
8457 if (SysAtflag
&& !Hiddendir
&& !rw_sysattr
) {
8458 int savedirfd
= Gen
.g_dirfd
;
8460 (void) fchdir(Gen
.g_dirfd
);
8461 Gen
.g_attrparent_p
= dp
->d_name
;
8463 Gen
.g_dirfd
= savedirfd
;
8464 Gen
.g_attrparent_p
= NULL
;
8466 #endif /* _PC_SATTR_ENABLED */
8468 if (Gen
.g_passdirfd
!= -1) {
8469 (void) close(Gen
.g_passdirfd
);
8470 Gen
.g_passdirfd
= -1;
8472 Gen
.g_attrnam_p
= NULL
;
8473 Gen
.g_attrfnam_p
= NULL
;
8474 Gen
.g_linktoattrfnam_p
= NULL
;
8475 Gen
.g_linktoattrnam_p
= NULL
;
8476 Gen
.g_rw_sysattr
= 0;
8477 if (Gen
.g_attrpath_p
!= NULL
) {
8478 free(Gen
.g_attrpath_p
);
8479 Gen
.g_attrpath_p
= NULL
;
8490 (void) closedir(dirp
);
8491 (void) close(Gen
.g_dirfd
);
8492 if (attrparent
== NULL
) {
8493 rest_cwd(Gen
.g_baseparent_fd
);
8500 xattrs_out(int (*func
)())
8506 * Return the parent directory of a given path.
8509 * /usr/tmp return /usr
8510 * /usr/tmp/file return /usr/tmp
8515 * dir is assumed to be at least as big as path.
8518 get_parent(char *path
, char *dir
)
8521 char tmpdir
[PATH_MAX
+ 1];
8523 if (strlen(path
) > PATH_MAX
) {
8524 msg(EXT
, "pathname is too long");
8526 (void) strcpy(tmpdir
, path
);
8527 chop_endslashes(tmpdir
);
8529 if ((s
= strrchr(tmpdir
, '/')) == NULL
) {
8530 (void) strcpy(dir
, ".");
8532 s
= skipslashes(s
, tmpdir
);
8535 (void) strcpy(dir
, "/");
8537 (void) strcpy(dir
, tmpdir
);
8541 #if defined(O_XATTR)
8542 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
8550 struct Lnk
*linkinfo
,
8553 char *bufhead
; /* ptr to full buffer */
8555 struct xattr_hdr
*hptr
; /* ptr to header in bufhead */
8556 struct xattr_buf
*tptr
; /* ptr to pathing pieces */
8557 int totalen
; /* total buffer length */
8558 int len
; /* length returned to user */
8559 int stringlen
; /* length of filename + attr */
8561 * length of filename + attr
8565 int complen
; /* length of pathing section */
8566 int linklen
; /* length of link section */
8567 int attrnames_index
; /* attrnames starting index */
8570 * Release previous buffer if any.
8573 if (*attrbuf
!= NULL
) {
8579 * First add in fixed size stuff
8581 len
= sizeof (struct xattr_hdr
) + sizeof (struct xattr_buf
);
8584 * Add space for two nulls
8586 stringlen
= strlen(attrpath
) + strlen(filename
) + 2;
8587 complen
= stringlen
+ sizeof (struct xattr_buf
);
8592 * Now add on space for link info if any
8595 if (linkinfo
!= NULL
) {
8597 * Again add space for two nulls
8599 linkstringlen
= strlen(linkinfo
->L_gen
.g_attrfnam_p
) +
8600 strlen(linkinfo
->L_gen
.g_attrnam_p
) + 2;
8601 linklen
= linkstringlen
+ sizeof (struct xattr_buf
);
8608 * Now add padding to end to fill out TBLOCK
8610 * Function returns size of real data and not size + padding.
8613 totalen
= ROUNDTOTBLOCK(len
);
8614 bufhead
= e_zalloc(E_EXIT
, totalen
);
8617 * Now we can fill in the necessary pieces
8621 * first fill in the fixed header
8623 hptr
= (struct xattr_hdr
*)bufhead
;
8624 (void) strcpy(hptr
->h_version
, XATTR_ARCH_VERS
);
8625 (void) sprintf(hptr
->h_component_len
, "%0*d",
8626 sizeof (hptr
->h_component_len
) - 1, complen
);
8627 (void) sprintf(hptr
->h_link_component_len
, "%0*d",
8628 sizeof (hptr
->h_link_component_len
) - 1, linklen
);
8629 (void) sprintf(hptr
->h_size
, "%0*d", sizeof (hptr
->h_size
) - 1, len
);
8632 * Now fill in the filename + attrnames section
8633 * The filename and attrnames section can be composed of two or more
8634 * path segments separated by a null character. The first segment
8635 * is the path to the parent file that roots the entire sequence in
8636 * the normal name space. The remaining segments describes a path
8637 * rooted at the hidden extended attribute directory of the leaf file of
8638 * the previous segment, making it possible to name attributes on
8639 * attributes. Thus, if we are just archiving an extended attribute,
8640 * the second segment will contain the attribute name. If we are
8641 * archiving a system attribute of an extended attribute, then the
8642 * second segment will contain the attribute name, and a third segment
8643 * will contain the system attribute name. The attribute pathing
8644 * information is obtained from 'attrpath'.
8647 tptr
= (struct xattr_buf
*)(bufhead
+ sizeof (struct xattr_hdr
));
8648 (void) sprintf(tptr
->h_namesz
, "%0*d", sizeof (tptr
->h_namesz
) - 1,
8650 (void) strcpy(tptr
->h_names
, filename
);
8651 attrnames_index
= strlen(filename
) + 1;
8652 (void) strcpy(&tptr
->h_names
[attrnames_index
], attrpath
);
8653 tptr
->h_typeflag
= typeflag
;
8656 * Split the attrnames section into two segments if 'attrpath'
8657 * contains pathing information for a system attribute of an
8658 * extended attribute. We split them by replacing the '/' with
8661 if ((aptr
= strpbrk(&tptr
->h_names
[attrnames_index
], "/")) != NULL
) {
8666 * Now fill in the optional link section if we have one
8669 if (linkinfo
!= NULL
) {
8670 tptr
= (struct xattr_buf
*)(bufhead
+
8671 sizeof (struct xattr_hdr
) + complen
);
8673 (void) sprintf(tptr
->h_namesz
, "%0*d",
8674 sizeof (tptr
->h_namesz
) - 1, linkstringlen
);
8675 (void) strcpy(tptr
->h_names
, linkinfo
->L_gen
.g_attrfnam_p
);
8677 &tptr
->h_names
[strlen(linkinfo
->L_gen
.g_attrfnam_p
) + 1],
8678 linkinfo
->L_gen
.g_attrnam_p
);
8679 tptr
->h_typeflag
= typeflag
;
8681 *attrbuf
= (char *)bufhead
;
8684 #endif /* O_XATTR */
8714 #if defined(O_XATTR)
8718 if (G_p
->g_attrnam_p
!= NULL
) {
8719 return (openat(G_p
->g_dirfd
, G_p
->g_attrnam_p
, omode
));
8721 return (openat(G_p
->g_dirfd
,
8722 get_component(G_p
->g_nam_p
), omode
));
8729 return (openat(G_p
->g_dirfd
, get_component(G_p
->g_nam_p
), omode
));
8733 #if defined(O_XATTR)
8738 int comp_len
, link_len
;
8748 * Include any padding in the read. We need to be positioned
8749 * at beginning of next header.
8752 bytes
= Gen
.g_filesz
;
8754 if ((xattrhead
= e_zalloc(E_NORMAL
, (size_t)bytes
)) == NULL
) {
8755 (void) fprintf(stderr
, gettext(
8756 "Insufficient memory for extended attribute\n"));
8760 tp
= (char *)xattrhead
;
8762 cnt
= (int)(bytes
> CPIOBSZ
) ? CPIOBSZ
: bytes
;
8764 (void) memcpy(tp
, Buffr
.b_out_p
, cnt
);
8766 Buffr
.b_out_p
+= cnt
;
8767 Buffr
.b_cnt
-= (off_t
)cnt
;
8768 bytes
-= (off_t
)cnt
;
8771 pad
= (Pad_val
+ 1 - (Gen
.g_filesz
& Pad_val
)) &
8775 Buffr
.b_out_p
+= pad
;
8776 Buffr
.b_cnt
-= (off_t
)pad
;
8780 * Validate that we can handle header format
8783 if (strcmp(xattrhead
->h_version
, XATTR_ARCH_VERS
) != 0) {
8784 (void) fprintf(stderr
,
8785 gettext("Unknown extended attribute format encountered\n"));
8786 (void) fprintf(stderr
,
8787 gettext("Disabling extended attribute header parsing\n"));
8791 (void) sscanf(xattrhead
->h_component_len
, "%10d", &comp_len
);
8792 (void) sscanf(xattrhead
->h_link_component_len
, "%10d", &link_len
);
8793 xattrp
= (struct xattr_buf
*)(((char *)xattrhead
) +
8794 sizeof (struct xattr_hdr
));
8795 (void) sscanf(xattrp
->h_namesz
, "%7d", &namelen
);
8797 xattr_linkp
= (struct xattr_buf
*)((int)xattrp
+ (int)comp_len
);
8803 * Gather the attribute path from the filename and attrnames section.
8804 * The filename and attrnames section can be composed of two or more
8805 * path segments separated by a null character. The first segment
8806 * is the path to the parent file that roots the entire sequence in
8807 * the normal name space. The remaining segments describes a path
8808 * rooted at the hidden extended attribute directory of the leaf file of
8809 * the previous segment, making it possible to name attributes on
8812 parentfilelen
= strlen(xattrp
->h_names
);
8813 xattrapath
= xattrp
->h_names
+ parentfilelen
+ 1;
8814 asz
= strlen(xattrapath
);
8815 if ((asz
+ parentfilelen
+ 2) < namelen
) {
8817 * The attrnames section contains a system attribute on an
8818 * attribute. Save the name of the attribute for use later,
8819 * and replace the null separating the attribute name from
8820 * the system attribute name with a '/' so that xattrapath can
8821 * be used to display messages with the full attribute path name
8822 * rooted at the hidden attribute directory of the base file
8823 * in normal name space.
8825 xattrapath
[asz
] = '/';
8868 #if defined(O_XATTR)
8870 get_component(char *path
)
8874 ptr
= strrchr(path
, '/');
8879 * Handle trailing slash
8881 if (*(ptr
+ 1) == '\0')
8889 get_component(char *path
)
8896 open_dir(char *name
)
8902 dir
= e_zalloc(E_EXIT
, strlen(name
) + 1);
8905 * open directory; creating missing directories along the way.
8907 get_parent(name
, dir
);
8909 fd
= open(dir
, O_RDONLY
);
8915 } while (cnt
<= 1 && missdir(name
) == 0);
8925 if ((Args
& OCt
) == 0) {
8927 if (G_p
->g_attrnam_p
!= NULL
) {
8931 * Open the file's attribute directory.
8932 * Change into the base file's starting directory then
8933 * call open_attr_dir() to open the attribute directory
8934 * of either the base file (if G_p->g_attrparent_p is
8935 * NULL) or the attribute (if G_p->g_attrparent_p is
8936 * set) of the base file.
8938 (void) fchdir(G_p
->g_baseparent_fd
);
8939 (void) open_attr_dir(G_p
->g_attrnam_p
,
8940 G_p
->g_attrfnam_p
, G_p
->g_baseparent_fd
,
8941 (G_p
->g_attrparent_p
== NULL
) ? NULL
:
8942 G_p
->g_attrparent_p
, &G_p
->g_dirfd
, &rw_sysattr
);
8944 int saveerrno
= errno
;
8946 (void) fchdir(G_p
->g_baseparent_fd
);
8949 if ((G_p
->g_dirfd
== -1) && (Args
& (OCi
| OCp
))) {
8951 "Cannot open attribute directory "
8952 "of %s%s%sfile \"%s\"",
8953 (G_p
->g_attrparent_p
== NULL
) ? "" :
8954 gettext("attribute \""),
8955 (G_p
->g_attrparent_p
== NULL
) ? "" :
8956 G_p
->g_attrparent_p
,
8957 (G_p
->g_attrparent_p
== NULL
) ? "" :
8960 return (FILE_PASS_ERR
);
8963 G_p
->g_dirfd
= open_dir(G_p
->g_nam_p
);
8964 if (G_p
->g_dirfd
== -1) {
8966 "Cannot open/create %s", G_p
->g_nam_p
);
8982 if (G_p
->g_dirfd
!= -1) {
8983 (void) close(G_p
->g_dirfd
);
8991 char *attrbuf
= NULL
;
8994 struct Lnk
*tl_p
, *linkinfo
;
8997 * namep was allocated in xattrs_out. It is big enough to hold
8998 * either the name + .hdr on the end or just the attr name
9001 #if defined(O_XATTR)
9002 namep
= Gen
.g_nam_p
;
9007 tl_p
= Lnk_hd
.L_nxt_p
;
9008 while (tl_p
!= &Lnk_hd
) {
9009 if (tl_p
->L_gen
.g_ino
== G_p
->g_ino
&&
9010 tl_p
->L_gen
.g_dev
== G_p
->g_dev
) {
9014 tl_p
= tl_p
->L_nxt_p
;
9016 prepare_xattr_hdr(&attrbuf
, Gen
.g_attrfnam_p
,
9018 (linkinfo
== NULL
) ?
9019 tartype(Gen
.g_mode
& Ftype
) : LNKTYPE
,
9020 linkinfo
, &attrlen
);
9021 Gen
.g_filesz
= attrlen
;
9022 write_hdr(ARCHIVE_XATTR
, (off_t
)attrlen
);
9024 (void) sprintf(namep
, "%s/%s", DEVNULL
, Gen
.g_attrnam_p
);
9025 write_ancillary(attrbuf
, attrlen
, B_TRUE
);
9033 * skip over extra slashes in string.
9038 * would return pointer at
9043 skipslashes(char *string
, char *start
)
9045 while ((string
> start
) && *(string
- 1) == '/') {
9055 static int num_left
;
9056 static sl_info_t
*slipool
;
9059 return (&slipool
[--num_left
]);
9061 num_left
= SL_INFO_ALLOC_CHUNK
;
9062 slipool
= e_zalloc(E_EXIT
, sizeof (sl_info_t
) * num_left
);
9063 return (&slipool
[--num_left
]);
9067 * If a match for the key values was found in the tree, return a pointer to it.
9068 * If a match was not found, insert it and return a pointer to it. This is
9069 * based on Knuth's Algorithm A in Vol 3, section 6.2.3.
9073 sl_insert(dev_t device
, ino_t inode
, int ftype
)
9075 sl_info_t
*p
; /* moves down the tree */
9076 sl_info_t
*q
; /* scratch */
9077 sl_info_t
*r
; /* scratch */
9078 sl_info_t
*s
; /* pt where rebalancing may be needed */
9079 sl_info_t
*t
; /* father of s */
9082 int a
; /* used to hold balance factors */
9083 int done
; /* loop control */
9084 int cmpflg
; /* used to hold the result of a comparison */
9088 head
= sl_devhash_lookup(device
);
9091 head
= sl_info_alloc();
9095 p
= head
->rlink
= sl_info_alloc();
9097 p
->sl_ftype
= ftype
;
9102 sl_devhash_insert(device
, head
);
9107 s
= p
= head
->rlink
;
9111 for (done
= 0; ! done
; ) {
9112 switch (sl_compare(inode
, ftype
, p
->sl_ino
, p
->sl_ftype
)) {
9119 q
= sl_info_alloc();
9137 q
= sl_info_alloc();
9157 q
->sl_ftype
= ftype
;
9159 q
->llink
= q
->rlink
= NULL
;
9162 /* adjust balance factors */
9164 if ((cmpflg
= sl_compare(inode
, ftype
, s
->sl_ino
, s
->sl_ftype
)) < 0) {
9171 switch (sl_compare(inode
, ftype
, p
->sl_ino
, p
->sl_ftype
)) {
9197 head
->llink
= (sl_info_t
*)((int)head
->llink
+ 1);
9199 } else if (s
->bal
== -a
) {
9209 /* single rotation */
9214 s
->llink
= r
->rlink
;
9216 } else if (a
== 1) {
9217 s
->rlink
= r
->llink
;
9221 s
->bal
= r
->bal
= 0;
9223 } else if (r
->bal
== -a
) {
9224 /* double rotation */
9228 r
->rlink
= p
->llink
;
9230 s
->llink
= p
->rlink
;
9232 } else if (a
== 1) {
9234 r
->llink
= p
->rlink
;
9236 s
->rlink
= p
->llink
;
9243 } else if (p
->bal
== -a
) {
9246 } else if (p
->bal
== a
) {
9254 /* finishing touch */
9256 if (s
== t
->rlink
) {
9266 * sl_numlinks: return the number of links that we saw during our preview.
9270 sl_numlinks(dev_t device
, ino_t inode
, int ftype
)
9272 sl_info_t
*p
= sl_search(device
, inode
, ftype
);
9275 return (p
->sl_count
);
9282 * Preview extended and extended system attributes.
9284 * Return 0 if successful, otherwise return 1.
9286 #if defined(O_XATTR)
9288 preview_attrs(char *s
, char *attrparent
)
9290 char *filename
= (attrparent
== NULL
) ? s
: attrparent
;
9295 int arc_rwsysattr
= 0;
9303 * If the underlying file system supports it, then
9304 * archive the extended attributes if -@ was specified,
9305 * and the extended system attributes if -/ was
9308 if (verify_attr_support(filename
, (attrparent
== NULL
), ARC_CREATE
,
9309 &ext_attr
) != ATTR_OK
) {
9313 #if defined(_PC_SATTR_ENABLED)
9316 nvlist_t
*slist
= NULL
;
9318 /* Determine if there are non-transient system attributes. */
9320 if ((filefd
= open(filename
, O_RDONLY
)) < 0) {
9323 if (((slist
= sysattr_list(myname
, filefd
,
9324 filename
)) != NULL
) || (errno
!= 0)) {
9327 if (slist
!= NULL
) {
9328 (void) nvlist_free(slist
);
9331 (void) close(filefd
);
9334 if ((arc_rwsysattr
== 0) && ((attrparent
!= NULL
) ||
9335 (SysAtflag
&& !ext_attr
))) {
9338 #endif /* _PC_SATTR_ENABLED */
9340 * We need to open the attribute directory of the
9341 * file, and preview all of the file's attributes as
9342 * attributes of the file can be hard links to other
9343 * attributes of the file.
9345 dirfd
= attropen(filename
, ".", O_RDONLY
);
9351 (void) close(dirfd
);
9354 dirp
= fdopendir(tmpfd
);
9356 (void) close(dirfd
);
9357 (void) close(tmpfd
);
9361 while (dp
= readdir(dirp
)) {
9362 if (dp
->d_name
[0] == '.') {
9363 if (dp
->d_name
[1] == '\0') {
9365 } else if ((dp
->d_name
[1] == '.') &&
9366 (dp
->d_name
[2] == '\0')) {
9375 if (fstatat(dirfd
, dp
->d_name
, &sb
,
9376 AT_SYMLINK_NOFOLLOW
) < 0) {
9380 if (verify_attr(dp
->d_name
, attrparent
,
9381 arc_rwsysattr
, &rw_sysattr
) != ATTR_OK
) {
9386 if (S_ISLNK(sb
.st_mode
)) {
9389 if (fstatat(dirfd
, dp
->d_name
,
9395 sl_remember_tgt(&sb
, islnk
, rw_sysattr
);
9398 * Recursively call preview_attrs() to preview extended
9399 * system attributes of attributes.
9401 if (SysAtflag
&& !Hiddendir
&& !rw_sysattr
) {
9402 int my_cwd
= save_cwd();
9404 (void) fchdir(dirfd
);
9405 rc
= preview_attrs(s
, dp
->d_name
);
9409 (void) closedir(dirp
);
9410 (void) close(dirfd
);
9413 #endif /* O_XATTR */
9416 * sl_preview_synonyms: Read the file list from the input stream, remembering
9417 * each reference to each file.
9421 sl_preview_synonyms(void)
9426 char *suffix
= "/cpioXXXXXX";
9427 char *tmpdir
= getenv("TMPDIR");
9432 if (tmpdir
== NULL
|| *tmpdir
== '\0' ||
9433 (strlen(tmpdir
) + strlen(suffix
)) > APATH
) {
9434 struct statvfs tdsb
;
9436 tmpdir
= "/var/tmp";
9438 /* /var/tmp is read-only in the mini-root environment */
9440 if (statvfs(tmpdir
, &tdsb
) == -1 || tdsb
.f_flag
& ST_RDONLY
) {
9445 tmpfname
= e_zalloc(E_EXIT
, strlen(tmpdir
) + strlen(suffix
) + 1);
9447 (void) strcpy(tmpfname
, tmpdir
);
9448 (void) strcat(tmpfname
, suffix
);
9450 if ((tmpfd
= mkstemp(tmpfname
)) == -1) {
9451 msg(EXTN
, "cannot open tmpfile %s%s", tmpdir
, suffix
);
9454 if (unlink(tmpfname
) == -1) {
9455 msg(EXTN
, "cannot unlink tmpfile %s", tmpfname
);
9458 if ((tmpfile
= fdopen(tmpfd
, "w+")) == NULL
) {
9459 msg(EXTN
, "cannot fdopen tmpfile %s", tmpfname
);
9462 while ((s
= fgets(buf
, APATH
+1, In_p
)) != NULL
) {
9466 if (fputs(buf
, tmpfile
) == EOF
) {
9467 msg(EXTN
, "problem writing to tmpfile %s", tmpfname
);
9470 /* pre-process the name */
9472 lastchar
= strlen(s
) - 1;
9474 if (s
[lastchar
] != '\n' && lastchar
== APATH
- 1) {
9480 while (s
[0] == '.' && s
[1] == '/') {
9482 while (s
[0] == '/') {
9487 if (lstat(s
, &sb
) < 0) {
9491 if (S_ISLNK(sb
.st_mode
)) {
9494 if (stat(s
, &sb
) < 0) {
9499 sl_remember_tgt(&sb
, islnk
, 0);
9501 #if defined(O_XATTR)
9502 if (Atflag
|| SysAtflag
) {
9503 (void) preview_attrs(s
, NULL
);
9505 #endif /* O_XATTR */
9509 msg(EXTN
, "error reading stdin");
9512 if (fseek(tmpfile
, 0L, SEEK_SET
) == -1) {
9513 msg(EXTN
, "cannot fseek on tmpfile %s", tmpfname
);
9521 * sl_remember_tgt: Add the device/inode for lstat or stat info to the list of
9522 * those we've seen before.
9524 * This tree (rooted under head) is keyed by the device/inode of the file
9525 * being pointed to. A count is kept of the number of references encountered
9530 sl_remember_tgt(const struct stat
*sbp
, int isSymlink
, int is_sysattr
)
9537 device
= sbp
->st_dev
;
9538 inode
= sbp
->st_ino
;
9539 ftype
= sbp
->st_mode
& Ftype
;
9541 /* Determine whether we've seen this one before */
9543 p
= sl_insert(device
, inode
, ftype
);
9545 if (p
->sl_count
> 0) {
9547 * It appears as if have seen this file before as we found a
9548 * matching device, inode, and file type as a file already
9549 * processed. Since there can possibly be files with the
9550 * same device, inode, and file type, but aren't hard links
9551 * (e.g., read-write system attribute files will always have
9552 * the same inode), we need to only attempt to add one to the
9553 * link count if the file we are processing is a hard link
9554 * (i.e., st_nlink > 1).
9556 * Note that if we are not chasing symlinks, and this one is a
9557 * symlink, it is identically the one we saw before (you cannot
9558 * have hard links to symlinks); in this case, we leave the
9559 * count alone, so that we don't wind up archiving a symlink to
9563 if (((Args
& OCL
) || (! isSymlink
)) && !is_sysattr
) {
9567 /* We have not seen this file before */
9572 /* -Hodc: remap inode (-1 on overflow) */
9576 for (q
= sl_remap_head
; q
&& (q
->dev
!= device
);
9582 q
= e_zalloc(E_EXIT
, sizeof (sl_remap_t
));
9584 p
->sl_ino2
= q
->inode_count
= 1;
9586 q
->next
= (sl_remap_head
) ?
9587 sl_remap_head
->next
: NULL
;
9590 if ((size_t)q
->inode_count
<=
9591 ((1 << (sizeof (o_ino_t
) * 8)) - 1)) {
9592 /* fits in o_ino_t */
9593 p
->sl_ino2
= ++(q
->inode_count
);
9595 p
->sl_ino2
= (ino_t
)-1;
9603 * A faster search, which does not insert the key values into the tree.
9604 * If the a match was found in the tree, return a pointer to it. If it was not
9605 * found, return NULL.
9609 sl_search(dev_t device
, ino_t inode
, int ftype
)
9611 sl_info_t
*p
; /* moves down the tree */
9612 int c
; /* comparison value */
9613 sl_info_t
*retval
= NULL
; /* return value */
9616 head
= sl_devhash_lookup(device
);
9618 for (p
= head
->rlink
; p
; ) {
9619 if ((c
= sl_compare(inode
, ftype
, p
->sl_ino
,
9620 p
->sl_ftype
)) == 0) {
9635 sl_devhash_lookup(dev_t device
)
9639 static sl_info_link_t
*devcache
;
9641 if (devcache
!= NULL
&& devcache
->dev
== device
) {
9642 return (devcache
->head
);
9645 key
= DEV_HASHKEY(device
);
9646 for (lp
= sl_devhash
[key
]; lp
; lp
= lp
->next
) {
9647 if (lp
->dev
== device
) {
9656 sl_devhash_insert(dev_t device
, sl_info_t
*head
)
9658 int key
= DEV_HASHKEY(device
);
9661 lp
= e_zalloc(E_EXIT
, sizeof (sl_info_link_t
));
9664 lp
->next
= sl_devhash
[key
];
9665 sl_devhash
[key
] = lp
;
9669 chop_endslashes(char *path
)
9673 end
= &path
[strlen(path
) -1];
9674 if (*end
== '/' && end
!= path
) {
9675 ptr
= skipslashes(end
, path
);
9676 if (ptr
!= NULL
&& ptr
!= path
) {
9682 #if !defined(O_XATTR)
9684 openat64(int fd
, char *name
, int oflag
, mode_t cmode
)
9686 return (open64(name
, oflag
, cmode
));
9690 openat(int fd
, char *name
, int oflag
, mode_t cmode
)
9692 return (open(name
, oflag
, cmode
));
9696 fchownat(int fd
, char *name
, uid_t owner
, gid_t group
, int flag
)
9698 if (flag
== AT_SYMLINK_NOFOLLOW
)
9699 return (lchown(name
, owner
, group
));
9701 return (chown(name
, owner
, group
));
9705 renameat(int fromfd
, char *old
, int tofd
, char *new)
9707 return (rename(old
, new));
9711 futimesat(int fd
, char *path
, struct timeval times
[2])
9713 return (utimes(path
, times
));
9717 unlinkat(int dirfd
, char *path
, int flag
)
9719 if (flag
== AT_REMOVEDIR
) {
9720 return (rmdir(path
));
9722 return (unlink(path
));
9727 fstatat(int fd
, char *path
, struct stat
*buf
, int flag
)
9729 if (flag
== AT_SYMLINK_NOFOLLOW
)
9730 return (lstat(path
, buf
));
9732 return (stat(path
, buf
));
9736 attropen(char *file
, char *attr
, int omode
, mode_t cmode
)