Merge commit '00f1a4f432b3d8aad1aa270e91c44c57f03ef407'
[unleashed.git] / usr / src / cmd / cpio / cpio.c
blob6e7de845be291575055f4d89622d018a4d8ebf87
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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.
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <fcntl.h>
41 #include <memory.h>
42 #include <string.h>
43 #include <stdarg.h>
44 #include <sys/stat.h>
45 #include <sys/statvfs.h>
46 #include <sys/mkdev.h>
47 #include <sys/param.h>
48 #include <utime.h>
49 #include <pwd.h>
50 #include <grp.h>
51 #include <signal.h>
52 #include <ctype.h>
53 #include <locale.h>
54 #include <sys/ioctl.h>
55 #include <sys/mtio.h>
56 #include <sys/fdio.h>
57 #include "cpio.h"
58 #include <sys/acl.h>
59 #include <sys/time.h>
60 #include <sys/resource.h>
61 #include <fnmatch.h>
62 #include <libgen.h>
63 #include <libintl.h>
64 #include <dirent.h>
65 #include <limits.h>
66 #include <aclutils.h>
67 #if defined(_PC_SATTR_ENABLED)
68 #include <libnvpair.h>
69 #include <attr.h>
70 #include <libcmdutils.h>
71 #endif /* _PC_SATTR_ENABLED */
72 #ifdef SOLARIS_PRIVS
73 #include <priv.h>
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;
81 #else
82 typedef ulong_t u_off_t;
83 #endif
85 #define SECMODE 0xe080
87 #define DEVNULL "/dev/null"
88 #define XATTRHDR ".hdr"
90 #define NAMELEN 32
91 #define TYPELEN 16
92 #define PERMLEN 4
94 #define FILE_COPIED 1
95 #define FILE_LINKED 2
96 #define FILE_PASS_ERR -1
98 #define ARCHIVE_NORMAL 0
99 #define ARCHIVE_ACL 1
100 #define ARCHIVE_XATTR 2
101 #define ARCHIVE_SPARSE 3
103 #ifndef VIEW_READONLY
104 #define VIEW_READONLY "SUNWattr_ro"
105 #endif
107 #ifndef VIEW_READWRITE
108 #define VIEW_READWRITE "SUNWattr_rw"
109 #endif
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);
212 /* helpful types */
214 static
215 struct passwd *Curpw_p, /* Current password entry for -t option */
216 *Rpw_p, /* Password entry for -R option */
217 *dpasswd;
219 static
220 struct group *Curgr_p, /* Current group entry for -t option */
221 *dgroup;
223 /* Data structure for buffered I/O. */
225 static
226 struct buf_info {
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 */
233 } Buffr;
235 /* Generic header format */
237 static
238 struct gen_hdr {
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 */
251 char g_gname[32],
252 g_uname[32],
253 g_version[2],
254 g_tmagic[6],
255 g_typeflag;
256 char *g_tname,
257 *g_prefix,
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 */
272 } Gen, *G_p;
274 /* Data structure for handling multiply-linked files */
275 static
276 char prebuf[PRESIZ+1],
277 nambuf[NAMSIZ+1],
278 fullnam[MAXNAM+1];
281 static
282 struct Lnk {
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 */
289 } Lnk_hd;
291 static
292 struct hdr_cpio Hdr;
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.
303 static
304 int issymlink = 0;
306 static
307 FILE *In_p; /* Where the input comes from */
309 typedef struct sl_info
311 struct sl_info *llink; /* Left subtree ptr (tree depth in *sl_head) */
312 struct sl_info *rlink; /* Right subtree ptr */
313 int bal; /* Subtree balance factor */
314 ulong_t sl_count; /* Number of symlinks */
315 int sl_ftype; /* file type of inode */
316 ino_t sl_ino; /* Inode of file */
317 ino_t sl_ino2; /* alternate inode for -Hodc */
318 } sl_info_t;
320 typedef struct data_in
322 int data_in_errno;
323 char data_in_swapfile;
324 char data_in_proc_mode;
325 char data_in_rd_eof;
326 char data_in_wr_part;
327 char data_in_compress_flag;
328 long data_in_cksumval;
329 FILE *data_in_pipef;
330 } data_in_t;
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
338 dev_t dev;
339 sl_info_t *head;
340 struct sl_info_link *next;
341 } sl_info_link_t;
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 */
356 } sl_remap_t;
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))))
374 /* global storage */
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 * -------------------------------------------------------------------------
383 static
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.
394 static
395 union bin_mag {
396 unsigned char b_byte[2];
397 ushort_t b_half;
398 } Binmag;
400 static
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().
412 static
413 union swpbuf {
414 unsigned char s_byte[4];
415 ushort_t s_half[2];
416 ulong_t s_word;
417 } *Swp_p;
419 static
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 */
450 static
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 */
469 Eomflag = 0,
470 Dflag = 0,
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 */
479 static
480 gid_t Lastgid = (gid_t)-1; /* Used with -t & -v to record current gid */
482 static
483 uid_t Lastuid = (uid_t)-1; /* Used with -t & -v to record current uid */
485 static
486 long Args, /* Mask of selected options */
487 Max_namesz = CPATH; /* Maximum size of pathnames/filenames */
489 static
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;
502 static
503 FILE *Ef_p, /* File pointer of pattern input file */
504 *Err_p, /* File pointer for error reporting */
505 *Out_p, /* File pointer for non-archive output */
506 *Rtty_p, /* Input file pointer for interactive rename */
507 *Wtty_p; /* Output file ptr for interactive rename */
509 static
510 ushort_t Ftype = S_IFMT; /* File type mask */
512 /* ACL support */
513 static struct sec_attr {
514 char attr_type;
515 char attr_len[7];
516 char attr_info[1];
517 } *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 */
522 acl_t *aclp;
524 #if defined(O_XATTR)
525 typedef enum {
526 ATTR_OK,
527 ATTR_SKIP,
528 ATTR_CHDIR_ERR,
529 ATTR_OPEN_ERR,
530 ATTR_XATTR_ERR,
531 ATTR_SATTR_ERR
532 } attr_status_t;
533 #endif
535 #if defined(O_XATTR)
536 typedef enum {
537 ARC_CREATE,
538 ARC_RESTORE
539 } arc_action_t;
540 #endif
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
551 * as possible.
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
566 * be applied to it.
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
581 * is named.
582 * 2. The attribute record itself. Stored as a normal file type
583 * of entry.
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:
588 * /dev/null/attr.hdr
590 * The name of the attribute looks like:
591 * /dev/null/attr.
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
600 * for the link.
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
605 * have an attribute.
607 * The basic layout looks like this.
609 * --------------------------------
610 * | |
611 * | xattr_hdr |
612 * | |
613 * --------------------------------
614 * --------------------------------
615 * | |
616 * | xattr_buf |
617 * | |
618 * --------------------------------
619 * --------------------------------
620 * | |
621 * | (optional link info) |
622 * | |
623 * --------------------------------
624 * --------------------------------
625 * | |
626 * | attribute itself |
627 * | stored as normal tar |
628 * | or cpio data with |
629 * | special mode or |
630 * | typeflag |
631 * | |
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
647 * attribute.
649 * These structures are updated when an extended attribute header is read off
650 * of disk/tape.
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.
687 #ifdef WAITAROUND
688 int waitaround = 0; /* wait for rendezvous with the debugger */
689 #endif
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)
701 int i;
702 int passret;
704 In_p = stdin;
705 Out_p = stdout;
706 Err_p = stderr;
708 (void) setlocale(LC_ALL, "");
709 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
710 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
711 #endif
712 (void) textdomain(TEXT_DOMAIN);
714 (void) memset(&Gen, 0, sizeof (Gen));
715 myname = e_strdup(E_EXIT, basename(argv[0]));
716 setup(argc, argv);
718 if (signal(SIGINT, sigint) == SIG_IGN)
719 (void) signal(SIGINT, SIG_IGN);
720 switch (Args & (OCi | OCo | OCp)) {
721 case OCi: /* COPY IN */
722 Hdr_type = NONE;
723 if (Atflag || SysAtflag) {
725 * Save the current working directory, so
726 * we can change back here after cd'ing into
727 * the attribute directory when processing
728 * attributes.
730 if ((attr_baseparent_fd = save_cwd()) < 0) {
731 msg(EXT, "Unable to open current directory.");
734 while ((i = gethdr()) != 0) {
735 Gen.g_dirfd = -1;
736 if (i == 1) {
737 file_in();
739 * Any ACL info for this file would or should
740 * have been used after file_in(); clear out
741 * aclp so it is is not erroneously used on
742 * the next file.
744 if (aclp != NULL) {
745 acl_free(aclp);
746 aclp = NULL;
748 acl_is_set = 0;
750 (void) memset(&Gen, 0, sizeof (Gen));
752 /* Do not count "extra" "read-ahead" buffered data */
753 if (Buffr.b_cnt > Bufsize)
754 Blocks -= (u_longlong_t)(Buffr.b_cnt / Bufsize);
755 break;
756 case OCo: /* COPY OUT */
757 if (Args & OCA) {
758 scan4trail();
761 Gen.g_dirfd = -1;
762 Gen.g_dirpath = NULL;
763 sl_preview_synonyms();
765 while ((i = getname()) != 0) {
766 if (i == 1) {
767 (void) file_out();
768 if (Atflag || SysAtflag) {
769 if (Gen.g_dirfd != -1) {
770 (void) close(Gen.g_dirfd);
772 Gen.g_dirfd = -1;
773 xattrs_out(file_out);
776 if (aclp != NULL) {
777 acl_free(aclp);
778 aclp = NULL;
779 acl_is_set = 0;
782 write_trail();
783 break;
784 case OCp: /* PASS */
785 sl_preview_synonyms();
787 Gen.g_dirfd = -1;
788 Gen.g_passdirfd = -1;
789 Gen.g_dirpath = NULL;
790 Compress_sparse = 1;
791 while (getname()) {
793 * If file is a fully qualified path then
794 * file_pass will strip off the leading '/'
795 * and we need to save off the unstripped
796 * name for attribute traversal.
798 if (Atflag || SysAtflag) {
799 (void) strcpy(Savenam_p, Gen.g_nam_p);
801 passret = file_pass();
802 if (aclp != NULL) {
803 acl_free(aclp);
804 aclp = NULL;
805 acl_is_set = 0;
807 if (Gen.g_passdirfd != -1)
808 (void) close(Gen.g_passdirfd);
809 Gen.g_passdirfd = -1;
810 if (Atflag || SysAtflag) {
811 if (Gen.g_dirfd != -1) {
812 (void) close(Gen.g_dirfd);
814 Gen.g_dirfd = -1;
815 if (passret != FILE_LINKED) {
816 Gen.g_nam_p = Savenam_p;
817 xattrs_out(file_pass);
821 break;
822 default:
823 msg(EXT, "Impossible action.");
825 if (Ofile > 0) {
826 if (close(Ofile) != 0)
827 msg(EXTN, "close error");
829 if (Archive > 0) {
830 if (close(Archive) != 0)
831 msg(EXTN, "close error");
833 if ((Args & OCq) == 0) {
834 Blocks = (u_longlong_t)(Blocks * Bufsize + SBlocks +
835 0x1FF) >> 9;
836 msg(EPOST, "%lld blocks", Blocks);
838 if (Error_cnt)
839 msg(EPOST, "%d error(s)", Error_cnt);
840 return (EXIT_CODE);
844 * add_lnk: Add a linked file's header to the linked file data structure, by
845 * either adding it to the end of an existing sub-list or starting
846 * a new sub-list. Each sub-list saves the links to a given file.
848 * Directly returns a pointer to the new entry; returns a pointer to the head
849 * of the sub-list in which that entry is located through the argument.
852 static struct Lnk *
853 add_lnk(struct Lnk **sublist_return)
855 struct Lnk *new_entry, *sublist;
857 for (sublist = Lnk_hd.L_nxt_p;
858 sublist != &Lnk_hd;
859 sublist = sublist->L_nxt_p) {
860 if (sublist->L_gen.g_ino == G_p->g_ino &&
861 sublist->L_gen.g_dev == G_p->g_dev) {
862 /* found */
863 break;
867 new_entry = e_zalloc(E_EXIT, sizeof (struct Lnk));
869 new_entry->L_lnk_p = NULL;
870 new_entry->L_gen = *G_p; /* structure copy */
872 new_entry->L_gen.g_nam_p = e_zalloc(E_EXIT, (size_t)G_p->g_namesz);
874 (void) strcpy(new_entry->L_gen.g_nam_p, G_p->g_nam_p);
876 if (sublist == &Lnk_hd) {
877 /* start new sub-list */
878 new_entry->L_nxt_p = &Lnk_hd;
879 new_entry->L_bck_p = Lnk_hd.L_bck_p;
880 Lnk_hd.L_bck_p = new_entry->L_bck_p->L_nxt_p = new_entry;
881 new_entry->L_lnk_p = NULL;
882 new_entry->L_cnt = 1;
883 new_entry->L_data = Onecopy ? 0 : 1;
884 sublist = new_entry;
885 } else {
886 /* add to existing sub-list */
887 struct Lnk *ptr;
889 sublist->L_cnt++;
891 for (ptr = sublist;
892 ptr->L_lnk_p != NULL;
893 ptr = ptr->L_lnk_p) {
894 ptr->L_gen.g_filesz = G_p->g_filesz;
897 ptr->L_gen.g_filesz = G_p->g_filesz;
898 ptr->L_lnk_p = new_entry;
901 *sublist_return = sublist;
902 return (new_entry);
906 * bfill: Read req_cnt bytes (out of filelen bytes) from the I/O buffer,
907 * moving them to rd_buf_p. When there are no bytes left in the I/O buffer,
908 * Fillbuf is set and the I/O buffer is filled. The variable dist is the
909 * distance to lseek if an I/O error is encountered with the -k option set
910 * (converted to a multiple of Bufsize).
913 static int
914 bfill(void)
916 int i = 0, rv;
917 static int eof = 0;
919 if (!Dflag) {
920 while ((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) {
921 errno = 0;
922 if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
923 if (((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) &&
924 (Eomflag == 0)) {
925 Eomflag = 1;
926 return (1);
928 if (errno == ENOSPC) {
929 (void) chgreel(INPUT);
930 if (Hdr_type == BAR) {
931 skip_bar_volhdr();
933 continue;
934 } else if (Args & OCk) {
935 if (i++ > MX_SEEKS)
936 msg(EXT, "Cannot recover.");
937 if (lseek(Archive, Bufsize, SEEK_REL) < 0)
938 msg(EXTN, "Cannot lseek()");
939 Error_cnt++;
940 Buf_error++;
941 rv = 0;
942 continue;
943 } else
944 ioerror(INPUT);
945 } /* (rv = g_read(Device, Archive ... */
946 if (Hdr_type != BAR || rv == Bufsize) {
947 Buffr.b_in_p += rv;
948 Buffr.b_cnt += (long)rv;
950 if (rv == Bufsize) {
951 eof = 0;
952 Blocks++;
953 } else if (rv == 0) {
954 if (!eof) {
955 eof = 1;
956 break;
958 (void) chgreel(INPUT);
959 eof = 0; /* reset the eof after chgreel */
962 * if spans multiple volume, skip the volume header of
963 * the next volume so that the file currently being
964 * extracted can continue to be extracted.
966 if (Hdr_type == BAR) {
967 skip_bar_volhdr();
970 continue;
971 } else {
972 eof = 0;
973 SBlocks += (u_longlong_t)rv;
975 } /* (Buffr.b_end_p - Buffr.b_in_p) <= Bufsize */
977 } else { /* Dflag */
978 errno = 0;
979 if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
980 return (-1);
981 } /* (rv = g_read(Device, Archive ... */
982 Buffr.b_in_p += rv;
983 Buffr.b_cnt += (long)rv;
984 if (rv == Bufsize) {
985 eof = 0;
986 Blocks++;
987 } else if (!rv) {
988 if (!eof) {
989 eof = 1;
990 return (rv);
992 return (-1);
993 } else {
994 eof = 0;
995 SBlocks += (u_longlong_t)rv;
998 return (rv);
1002 * bflush: Move wr_cnt bytes from data_p into the I/O buffer. When the
1003 * I/O buffer is full, Flushbuf is set and the buffer is written out.
1006 static void
1007 bflush(void)
1009 int rv;
1011 while (Buffr.b_cnt >= Bufsize) {
1012 errno = 0;
1013 if ((rv = g_write(Device, Archive, Buffr.b_out_p,
1014 Bufsize)) < 0) {
1015 if (errno == ENOSPC && !Dflag)
1016 rv = chgreel(OUTPUT);
1017 else
1018 ioerror(OUTPUT);
1020 Buffr.b_out_p += rv;
1021 Buffr.b_cnt -= (long)rv;
1022 if (rv == Bufsize)
1023 Blocks++;
1024 else if (rv > 0)
1025 SBlocks += (u_longlong_t)rv;
1027 rstbuf();
1031 * chgreel: Determine if end-of-medium has been reached. If it has,
1032 * close the current medium and prompt the user for the next medium.
1035 static int
1036 chgreel(int dir)
1038 int lastchar, tryagain, askagain, rv;
1039 int tmpdev;
1040 char str[APATH];
1041 struct stat statb;
1043 rv = 0;
1044 if (fstat(Archive, &statb) < 0)
1045 msg(EXTN, "Error during stat() of archive");
1046 if ((statb.st_mode & S_IFMT) != S_IFCHR) {
1047 if (dir == INPUT) {
1048 msg(EXT, "%s%s\n",
1049 "Can't read input: end of file encountered ",
1050 "prior to expected end of archive.");
1053 msg(EPOST, "\007End of medium on \"%s\".", dir ? "output" : "input");
1054 if (is_floppy(Archive))
1055 (void) ioctl(Archive, FDEJECT, NULL);
1056 if ((close(Archive) != 0) && (dir == OUTPUT))
1057 msg(EXTN, "close error");
1058 Archive = 0;
1059 Volcnt++;
1060 for (;;) {
1061 if (Rtty_p == NULL)
1062 Rtty_p = fopen(Ttyname, "r");
1063 do { /* tryagain */
1064 if (IOfil_p) {
1065 do {
1066 msg(EPOST, Eom_p, Volcnt);
1067 if (!Rtty_p || fgets(str, sizeof (str),
1068 Rtty_p) == NULL)
1069 msg(EXT, "Cannot read tty.");
1070 askagain = 0;
1071 switch (*str) {
1072 case '\n':
1073 (void) strcpy(str, IOfil_p);
1074 break;
1075 case 'q':
1076 exit(EXIT_CODE);
1077 default:
1078 askagain = 1;
1080 } while (askagain);
1081 } else {
1083 if (Hdr_type == BAR)
1084 Bar_vol_num++;
1086 msg(EPOST,
1087 "To continue, type device/file name when "
1088 "ready.");
1089 if (!Rtty_p || fgets(str, sizeof (str),
1090 Rtty_p) == NULL)
1091 msg(EXT, "Cannot read tty.");
1092 lastchar = strlen(str) - 1;
1093 if (*(str + lastchar) == '\n') /* remove '\n' */
1094 *(str + lastchar) = '\0';
1095 if (!*str)
1096 exit(EXIT_CODE);
1098 tryagain = 0;
1099 if ((Archive = open(str, dir)) < 0) {
1100 msg(ERRN, "Cannot open \"%s\"", str);
1101 tryagain = 1;
1103 } while (tryagain);
1104 (void) g_init(&tmpdev, &Archive);
1105 if (tmpdev != Device)
1106 msg(EXT, "Cannot change media types in mid-stream.");
1107 if (dir == INPUT)
1108 break;
1109 else { /* dir == OUTPUT */
1110 errno = 0;
1111 if ((rv = g_write(Device, Archive, Buffr.b_out_p,
1112 Bufsize)) == Bufsize)
1113 break;
1114 else
1115 msg(ERR,
1116 "Unable to write this medium, try "
1117 "another.");
1119 } /* ;; */
1120 Eomflag = 0;
1121 return (rv);
1125 * ckname: Check filenames against user specified patterns,
1126 * and/or ask the user for new name when -r is used.
1129 static int
1130 ckname(int flag)
1132 int lastchar;
1133 size_t rename_bufsz = Max_namesz + 1;
1135 if (Hdr_type != TAR && Hdr_type != USTAR && Hdr_type != BAR) {
1136 /* Re-visit tar size issues later */
1137 if (G_p->g_namesz - 1 > Max_namesz) {
1138 msg(ERR, "Name exceeds maximum length - skipped.");
1139 return (F_SKIP);
1143 if (Pat_pp && !matched())
1144 return (F_SKIP);
1146 /* rename interactively */
1147 if ((Args & OCr) && !Adir && !G_p->g_rw_sysattr) {
1148 (void) fprintf(Wtty_p, gettext("Rename \"%s%s%s\"? "),
1149 (G_p->g_attrnam_p == NULL) ? G_p->g_nam_p : Renam_p,
1150 (G_p->g_attrnam_p == NULL) ? "" : gettext(" Attribute "),
1151 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
1152 (void) fflush(Wtty_p);
1153 if (fgets(Renametmp_p, rename_bufsz, Rtty_p) == NULL)
1154 msg(EXT, "Cannot read tty.");
1155 if (feof(Rtty_p))
1156 exit(EXIT_CODE);
1157 lastchar = strlen(Renametmp_p) - 1;
1159 /* remove trailing '\n' */
1160 if (*(Renametmp_p + lastchar) == '\n')
1161 *(Renametmp_p + lastchar) = '\0';
1162 if (*Renametmp_p == '\0') {
1163 msg(POST, "%s%s%s Skipped.",
1164 (G_p->g_attrnam_p == NULL) ? G_p->g_nam_p :
1165 G_p->g_attrfnam_p,
1166 (G_p->g_attrnam_p == NULL) ? "" :
1167 gettext(" Attribute "),
1168 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
1169 if (G_p->g_attrparent_p == NULL) {
1170 *G_p->g_nam_p = '\0';
1172 if (Renam_attr_p) {
1173 *Renam_attr_p = '\0';
1175 return (F_SKIP);
1176 } else if (strcmp(Renametmp_p, ".") != 0) {
1177 if (G_p->g_attrnam_p == NULL) {
1178 if (strlen(Renametmp_p) > strlen(
1179 G_p->g_nam_p)) {
1180 if ((G_p->g_nam_p != &nambuf[0]) &&
1181 (G_p->g_nam_p != &fullnam[0])) {
1182 free(G_p->g_nam_p);
1183 G_p->g_nam_p = e_zalloc(E_EXIT,
1184 rename_bufsz);
1187 if (Renam_attr_p) {
1188 *Renam_attr_p = '\0';
1190 if ((strlcpy(Renam_p, Renametmp_p,
1191 rename_bufsz) > rename_bufsz) ||
1192 (strlcpy(G_p->g_nam_p, Renametmp_p,
1193 rename_bufsz) > rename_bufsz)) {
1194 msg(EXTN, "buffer overflow");
1196 } else {
1197 if (G_p->g_attrnam_p != NULL) {
1198 free(G_p->g_attrnam_p);
1199 G_p->g_attrnam_p = e_strdup(E_EXIT,
1200 Renametmp_p);
1201 (void) strcpy(G_p->g_nam_p, Renam_p);
1202 if (Renam_attr_p) {
1203 if (strlcpy(Renam_attr_p,
1204 Renametmp_p, rename_bufsz) >
1205 rename_bufsz) {
1206 msg(EXTN,
1207 "buffer overflow");
1212 } else {
1213 if (G_p->g_attrnam_p == NULL) {
1214 *Renam_p = '\0';
1216 if (Renam_attr_p) {
1217 *Renam_attr_p = '\0';
1221 if (flag != 0 || Onecopy == 0) {
1222 VERBOSE((Args & OCt), G_p->g_nam_p);
1224 if (Args & OCt)
1225 return (F_SKIP);
1226 return (F_EXTR);
1230 * ckopts: Check the validity of all command line options.
1233 static void
1234 ckopts(long mask)
1236 int oflag;
1237 char *t_p;
1238 long errmsk;
1239 uid_t Euid = geteuid(); /* Effective uid of invoker */
1240 #ifdef SOLARIS_PRIVS
1241 priv_set_t *privset;
1242 priv_set_t *zones_privset;
1243 #endif /* SOLARIS_PRIVS */
1245 if (mask & OCi) {
1246 errmsk = mask & INV_MSK4i;
1247 } else if (mask & OCo) {
1248 errmsk = mask & INV_MSK4o;
1249 } else if (mask & OCp) {
1250 errmsk = mask & INV_MSK4p;
1251 } else {
1252 msg(ERR, "One of -i, -o or -p must be specified.");
1253 errmsk = 0;
1256 if (errmsk) {
1257 /* if non-zero, invalid options were specified */
1258 Error_cnt++;
1261 if ((mask & OCa) && (mask & OCm) && ((mask & OCi) ||
1262 (mask & OCo))) {
1263 msg(ERR, "-a and -m are mutually exclusive.");
1266 if ((mask & OCc) && (mask & OCH) &&
1267 (strcmp("odc", Hdr_p) != 0 && strcmp("odc_sparse", Hdr_p) != 0)) {
1268 msg(ERR, "-c and -H are mutually exclusive.");
1271 if ((mask & OCv) && (mask & OCV)) {
1272 msg(ERR, "-v and -V are mutually exclusive.");
1275 if ((mask & OCt) && (mask & OCV)) {
1276 msg(ERR, "-t and -V are mutually exclusive.");
1279 if ((mask & OCB) && (mask & OCC)) {
1280 msg(ERR, "-B and -C are mutually exclusive.");
1283 if ((mask & OCH) && (mask & OC6)) {
1284 msg(ERR, "-H and -6 are mutually exclusive.");
1287 if ((mask & OCM) && !((mask & OCI) || (mask & OCO))) {
1288 msg(ERR, "-M not meaningful without -O or -I.");
1291 if ((mask & OCA) && !(mask & OCO)) {
1292 msg(ERR, "-A requires the -O option.");
1295 if (Bufsize <= 0) {
1296 msg(ERR, "Illegal size given for -C option.");
1299 if (mask & OCH) {
1300 t_p = Hdr_p;
1302 while (*t_p != '\0') {
1303 if (isupper(*t_p)) {
1304 *t_p = 'a' + (*t_p - 'A');
1307 t_p++;
1310 if (!(strcmp("odc", Hdr_p))) {
1311 Hdr_type = CHR;
1312 Max_namesz = CPATH;
1313 Onecopy = 0;
1314 Use_old_stat = 1;
1315 } else if (!(strcmp("odc_sparse", Hdr_p))) {
1316 Hdr_type = CHR;
1317 Max_namesz = CPATH;
1318 Onecopy = 0;
1319 Use_old_stat = 1;
1320 Compress_sparse = 1;
1321 } else if (!(strcmp("ascii_sparse", Hdr_p))) {
1322 Hdr_type = ASC;
1323 Max_namesz = APATH;
1324 Onecopy = 1;
1325 Compress_sparse = 1;
1326 } else if (!(strcmp("crc", Hdr_p))) {
1327 Hdr_type = CRC;
1328 Max_namesz = APATH;
1329 Onecopy = 1;
1330 } else if (!(strcmp("tar", Hdr_p))) {
1331 if (Args & OCo) {
1332 Hdr_type = USTAR;
1333 Max_namesz = HNAMLEN - 1;
1334 } else {
1335 Hdr_type = TAR;
1336 Max_namesz = TNAMLEN - 1;
1338 Onecopy = 0;
1339 } else if (!(strcmp("ustar", Hdr_p))) {
1340 Hdr_type = USTAR;
1341 Max_namesz = HNAMLEN - 1;
1342 Onecopy = 0;
1343 } else if (!(strcmp("bar", Hdr_p))) {
1344 if ((Args & OCo) || (Args & OCp)) {
1345 msg(ERR,
1346 "Header type bar can only be used with -i");
1349 if (Args & OCP) {
1350 msg(ERR,
1351 "Can't preserve using bar header");
1354 Hdr_type = BAR;
1355 Max_namesz = TNAMLEN - 1;
1356 Onecopy = 0;
1357 } else {
1358 msg(ERR, "Invalid header \"%s\" specified", Hdr_p);
1362 if (mask & OCr) {
1363 Rtty_p = fopen(Ttyname, "r");
1364 Wtty_p = fopen(Ttyname, "w");
1366 if (Rtty_p == NULL || Wtty_p == NULL) {
1367 msg(ERR, "Cannot rename, \"%s\" missing", Ttyname);
1371 if ((mask & OCE) && (Ef_p = fopen(Efil_p, "r")) == NULL) {
1372 msg(ERR, "Cannot open \"%s\" to read patterns", Efil_p);
1375 if ((mask & OCI) && (Archive = open(IOfil_p, O_RDONLY)) < 0) {
1376 msg(ERR, "Cannot open \"%s\" for input", IOfil_p);
1379 if (mask & OCO) {
1380 if (mask & OCA) {
1381 if ((Archive = open(IOfil_p, O_RDWR)) < 0) {
1382 msg(ERR,
1383 "Cannot open \"%s\" for append",
1384 IOfil_p);
1386 } else {
1387 oflag = (O_WRONLY | O_CREAT | O_TRUNC);
1389 if ((Archive = open(IOfil_p, oflag, 0777)) < 0) {
1390 msg(ERR,
1391 "Cannot open \"%s\" for output",
1392 IOfil_p);
1397 #ifdef SOLARIS_PRIVS
1398 if ((privset = priv_allocset()) == NULL) {
1399 msg(ERR, "Unable to allocate privilege set");
1400 } else if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1401 msg(ERR, "Unable to obtain privilege set");
1402 } else {
1403 zones_privset = priv_str_to_set("zone", "", NULL);
1404 if (zones_privset != NULL) {
1405 privileged = (priv_issubset(zones_privset,
1406 privset) == B_TRUE);
1407 priv_freeset(zones_privset);
1408 } else {
1409 msg(ERR, "Unable to map privilege to privilege set");
1412 if (privset != NULL) {
1413 priv_freeset(privset);
1415 #else
1416 privileged = (Euid == 0);
1417 #endif /* SOLARIS_PRIVS */
1419 if (mask & OCR) {
1420 if ((Rpw_p = getpwnam(Own_p)) == NULL) {
1421 msg(ERR, "\"%s\" is not a valid user id", Own_p);
1422 } else if ((Euid != Rpw_p->pw_uid) && !privileged) {
1423 msg(ERR, "R option only valid for super-user or "
1424 "id matches login id of user executing cpio");
1428 if ((mask & OCo) && !(mask & OCO)) {
1429 Out_p = stderr;
1432 if ((mask & OCp) && ((mask & (OCB|OCC)) == 0)) {
1434 * We are in pass mode with no block size specified. Use the
1435 * larger of the native page size and 8192.
1438 Bufsize = (PageSize > 8192) ? PageSize : 8192;
1443 * cksum: Calculate the simple checksum of a file (CRC) or header
1444 * (TARTYP (TAR and USTAR)). For -o and the CRC header, the file is opened and
1445 * the checksum is calculated. For -i and the CRC header, the checksum
1446 * is calculated as each block is transferred from the archive I/O buffer
1447 * to the file system I/O buffer. The TARTYP (TAR and USTAR) headers calculate
1448 * the simple checksum of the header (with the checksum field of the
1449 * header initialized to all spaces (\040).
1452 static long
1453 cksum(char hdr, int byt_cnt, int *err)
1455 char *crc_p, *end_p;
1456 int cnt;
1457 long checksum = 0L, have;
1458 off_t lcnt;
1460 if (err != NULL)
1461 *err = 0;
1462 switch (hdr) {
1463 case CRC:
1464 if (Args & OCi) { /* do running checksum */
1465 end_p = Buffr.b_out_p + byt_cnt;
1466 for (crc_p = Buffr.b_out_p; crc_p < end_p; crc_p++)
1467 checksum += (long)*crc_p;
1468 break;
1470 /* OCo - do checksum of file */
1471 lcnt = G_p->g_filesz;
1473 while (lcnt > 0) {
1474 have = (lcnt < Bufsize) ? lcnt : Bufsize;
1475 errno = 0;
1476 if (read(Ifile, Buf_p, have) != have) {
1477 msg(ERR, "Error computing checksum.");
1478 if (err != NULL)
1479 *err = 1;
1480 break;
1482 end_p = Buf_p + have;
1483 for (crc_p = Buf_p; crc_p < end_p; crc_p++)
1484 checksum += (long)*crc_p;
1485 lcnt -= have;
1487 if (lseek(Ifile, (off_t)0, SEEK_ABS) < 0)
1488 msg(ERRN, "Cannot reset file after checksum");
1489 break;
1490 case TARTYP: /* TAR and USTAR */
1491 crc_p = Thdr_p->tbuf.t_cksum;
1492 for (cnt = 0; cnt < TCRCLEN; cnt++) {
1493 *crc_p = '\040';
1494 crc_p++;
1496 crc_p = (char *)Thdr_p;
1497 for (cnt = 0; cnt < TARSZ; cnt++) {
1499 * tar uses unsigned checksum, so we must use unsigned
1500 * here in order to be able to read tar archives.
1502 checksum += (long)((unsigned char)(*crc_p));
1503 crc_p++;
1505 break;
1506 default:
1507 msg(EXT, "Impossible header type.");
1508 } /* hdr */
1509 return (checksum);
1513 * creat_hdr: Fill in the generic header structure with the specific
1514 * header information based on the value of Hdr_type.
1516 * return (1) if this process was successful, and (0) otherwise.
1519 static int
1520 creat_hdr(void)
1522 ushort_t ftype;
1523 int fullnamesize;
1524 dev_t dev;
1525 ino_t ino;
1527 ftype = SrcSt.st_mode & Ftype;
1528 Adir = (ftype == S_IFDIR);
1529 Aspec = (ftype == S_IFBLK || ftype == S_IFCHR || ftype == S_IFIFO ||
1530 ftype == S_IFSOCK);
1531 switch (Hdr_type) {
1532 case BIN:
1533 Gen.g_magic = CMN_BIN;
1534 break;
1535 case CHR:
1536 Gen.g_magic = CMN_BIN;
1537 break;
1538 case ASC:
1539 Gen.g_magic = CMN_ASC;
1540 break;
1541 case CRC:
1542 Gen.g_magic = CMN_CRC;
1543 break;
1544 case USTAR:
1546 * If the length of the full name is greater than 256,
1547 * print out a message and return.
1549 if ((fullnamesize = strlen(Gen.g_nam_p)) > MAXNAM) {
1550 msg(ERR,
1551 "%s: file name too long", Gen.g_nam_p);
1552 return (0);
1553 } else if (fullnamesize > NAMSIZ) {
1555 * The length of the full name is greater than
1556 * 100, so we must split the filename from the
1557 * path
1559 char namebuff[NAMSIZ+1];
1560 char prebuff[PRESIZ+1];
1561 char *lastslash;
1562 int presize, namesize;
1564 (void) memset(namebuff, '\0',
1565 sizeof (namebuff));
1566 (void) memset(prebuff, '\0', sizeof (prebuff));
1568 lastslash = strrchr(Gen.g_nam_p, '/');
1570 if (lastslash != NULL) {
1571 namesize = strlen(++lastslash);
1572 presize = fullnamesize - namesize - 1;
1573 } else {
1574 namesize = fullnamesize;
1575 lastslash = Gen.g_nam_p;
1576 presize = 0;
1580 * If the filename is greater than 100 we can't
1581 * archive the file
1583 if (namesize > NAMSIZ) {
1584 msg(ERR,
1585 "%s: filename is greater than %d",
1586 lastslash, NAMSIZ);
1587 return (0);
1589 (void) strncpy(&namebuff[0], lastslash,
1590 namesize);
1592 * If the prefix is greater than 155 we can't
1593 * archive the file.
1595 if (presize > PRESIZ) {
1596 msg(ERR,
1597 "%s: prefix is greater than %d",
1598 Gen.g_nam_p, PRESIZ);
1599 return (0);
1601 (void) strncpy(&prebuff[0], Gen.g_nam_p,
1602 presize);
1604 Gen.g_tname = e_zalloc(E_EXIT, namesize + 1);
1605 (void) strcpy(Gen.g_tname, namebuff);
1607 Gen.g_prefix = e_zalloc(E_EXIT, presize + 1);
1608 (void) strcpy(Gen.g_prefix, prebuff);
1609 } else {
1610 Gen.g_tname = Gen.g_nam_p;
1612 (void) strcpy(Gen.g_tmagic, "ustar");
1613 (void) strcpy(Gen.g_version, "00");
1615 dpasswd = getpwuid(SrcSt.st_uid);
1616 if (dpasswd == NULL) {
1617 msg(EPOST,
1618 "cpio: could not get passwd information "
1619 "for %s%s%s",
1620 (Gen.g_attrnam_p == NULL) ?
1621 Gen.g_nam_p : Gen.g_attrfnam_p,
1622 (Gen.g_attrnam_p == NULL) ?
1623 "" : Gen.g_rw_sysattr ?
1624 gettext(" System Attribute ") :
1625 gettext(" Attribute "),
1626 (Gen.g_attrnam_p == NULL) ?
1627 "" : Gen.g_attrnam_p);
1628 /* make name null string */
1629 Gen.g_uname[0] = '\0';
1630 } else {
1631 (void) strncpy(&Gen.g_uname[0],
1632 dpasswd->pw_name, 32);
1634 dgroup = getgrgid(SrcSt.st_gid);
1635 if (dgroup == NULL) {
1636 msg(EPOST,
1637 "cpio: could not get group information "
1638 "for %s%s%s",
1639 (Gen.g_attrnam_p == NULL) ?
1640 Gen.g_nam_p : Gen.g_attrfnam_p,
1641 (Gen.g_attrnam_p == NULL) ?
1642 "" : Gen.g_rw_sysattr ?
1643 gettext(" System Attribute ") :
1644 gettext(" Attribute "),
1645 (Gen.g_attrnam_p == NULL) ?
1646 "" : Gen.g_attrnam_p);
1647 /* make name null string */
1648 Gen.g_gname[0] = '\0';
1649 } else {
1650 (void) strncpy(&Gen.g_gname[0],
1651 dgroup->gr_name, 32);
1653 Gen.g_typeflag = tartype(ftype);
1654 /* FALLTHROUGH */
1655 case TAR:
1656 (void) memset(T_lname, '\0', sizeof (T_lname));
1657 break;
1658 default:
1659 msg(EXT, "Impossible header type.");
1662 if (Use_old_stat && (Gen.g_attrnam_p != NULL)) {
1664 * When processing extended attributes, creat_hdr()
1665 * can get called multiple times which means that
1666 * SrcSt.st.st_dev would have gotten converted to
1667 * -Hodc format. We should always use the original
1668 * device here as we need to be able to match on
1669 * the original device id from the file that was
1670 * previewed in sl_preview_synonyms().
1672 dev = Savedev;
1673 } else {
1674 dev = SrcSt.st_dev;
1676 ino = SrcSt.st_ino;
1678 if (Use_old_stat) {
1679 SrcSt = *OldSt;
1682 Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
1683 Gen.g_uid = SrcSt.st_uid;
1684 Gen.g_gid = SrcSt.st_gid;
1685 Gen.g_dev = SrcSt.st_dev;
1687 if (Use_old_stat) {
1688 /* -Hodc */
1690 sl_info_t *p = sl_search(dev, ino, ftype);
1691 Gen.g_ino = p ? p->sl_ino2 : -1;
1693 if (Gen.g_ino == (ulong_t)-1) {
1694 msg(ERR, "%s%s%s: cannot be archived - inode too big "
1695 "for -Hodc format",
1696 (Gen.g_attrnam_p == NULL) ?
1697 Gen.g_nam_p : Gen.g_attrfnam_p,
1698 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
1699 gettext(" System Attribute ") :
1700 gettext(" Attribute "),
1701 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_attrnam_p);
1702 return (0);
1704 } else {
1705 Gen.g_ino = SrcSt.st_ino;
1708 Gen.g_mode = SrcSt.st_mode;
1709 Gen.g_mtime = SrcSt.st_mtime;
1710 Gen.g_nlink = Adir ? SrcSt.st_nlink : sl_numlinks(dev, ino, ftype);
1712 if (ftype == S_IFREG || ftype == S_IFLNK)
1713 Gen.g_filesz = (off_t)SrcSt.st_size;
1714 else
1715 Gen.g_filesz = (off_t)0;
1716 Gen.g_rdev = SrcSt.st_rdev;
1717 return (1);
1721 * creat_lnk: Create a link from the existing name1_p to name2_p.
1724 static
1726 creat_lnk(int dirfd, char *name1_p, char *name2_p)
1728 int cnt = 0;
1730 do {
1731 errno = 0;
1732 if (!link(name1_p, name2_p)) {
1733 if (aclp != NULL) {
1734 acl_free(aclp);
1735 aclp = NULL;
1736 acl_is_set = 0;
1738 cnt = 0;
1739 break;
1740 } else if ((errno == EEXIST) && (cnt == 0)) {
1741 struct stat lsb1;
1742 struct stat lsb2;
1745 * Check to see if we are trying to link this
1746 * file to itself. If so, count the effort as
1747 * successful. If the two files are different,
1748 * or if either lstat is unsuccessful, proceed
1749 * as we would have otherwise; the appropriate
1750 * error will be reported subsequently.
1753 if (lstat(name1_p, &lsb1) != 0) {
1754 msg(ERR, "Cannot lstat source file %s",
1755 name1_p);
1756 } else {
1757 if (lstat(name2_p, &lsb2) != 0) {
1758 msg(ERR, "Cannot lstat "
1759 "destination file %s", name2_p);
1760 } else {
1761 if (lsb1.st_dev == lsb2.st_dev &&
1762 lsb1.st_ino == lsb2.st_ino) {
1763 VERBOSE((Args & (OCv | OCV)),
1764 name2_p);
1765 return (0);
1770 if (!(Args & OCu) && G_p->g_mtime <= DesSt.st_mtime)
1771 msg(ERR, "Existing \"%s\" same age or newer",
1772 name2_p);
1773 else if (unlinkat(dirfd, get_component(name2_p), 0) < 0)
1774 msg(ERRN, "Error cannot unlink \"%s\"",
1775 name2_p);
1777 cnt++;
1778 } while ((cnt < 2) && missdir(name2_p) == 0);
1779 if (!cnt) {
1780 char *newname;
1781 char *fromname;
1782 char *attrname;
1784 newname = name2_p;
1785 fromname = name1_p;
1786 attrname = Gen.g_attrnam_p;
1787 if (attrname) {
1788 if (Args & OCp) {
1789 newname = fromname = Fullnam_p;
1790 } else {
1791 newname = Gen.g_attrfnam_p;
1794 if (Args & OCv) {
1795 (void) fprintf(Err_p,
1796 gettext("%s%s%s linked to %s%s%s\n"), newname,
1797 (attrname == NULL) ? "" : gettext(" attribute "),
1798 (attrname == NULL) ? "" : attrname,
1799 (attrname == NULL) ? fromname : newname,
1800 (attrname == NULL) ? "" : gettext(" attribute "),
1801 (attrname == NULL) ? "" : name1_p);
1802 } else {
1803 VERBOSE((Args & (OCv | OCV)), newname);
1805 } else if (cnt == 1)
1806 msg(ERRN,
1807 "Unable to create directory for \"%s\"", name2_p);
1808 else if (cnt == 2)
1809 msg(ERRN,
1810 "Cannot link \"%s\" and \"%s\"", name1_p, name2_p);
1811 return (cnt);
1815 * creat_spec:
1816 * Create one of the following:
1817 * directory
1818 * character special file
1819 * block special file
1820 * fifo
1821 * socket
1824 static int
1825 creat_spec(int dirfd)
1827 char *nam_p;
1828 int cnt, result, rv = 0;
1829 char *curdir;
1830 char *lastslash;
1832 Do_rename = 0; /* creat_tmp() may reset this */
1834 if (Args & OCp) {
1835 nam_p = Fullnam_p;
1836 } else {
1837 nam_p = G_p->g_nam_p;
1841 * Is this the extraction of the hidden attribute directory?
1842 * If we are processing the hidden attribute directory of an
1843 * attribute, then just return as modes and times cannot be set.
1844 * Otherwise, if we are processing a hidden attribute, just set
1845 * the mode/times correctly and return.
1848 if (Hiddendir) {
1849 if (G_p->g_attrparent_p == NULL) {
1850 if (Args & OCR) {
1851 if (fchownat(dirfd, ".", Rpw_p->pw_uid,
1852 Rpw_p->pw_gid, 0) != 0) {
1853 msg(ERRN,
1854 "Cannot chown() \"attribute "
1855 "directory of file %s\"",
1856 G_p->g_attrfnam_p);
1858 } else if ((fchownat(dirfd, ".", G_p->g_uid,
1859 G_p->g_gid, 0) != 0) && privileged) {
1860 msg(ERRN,
1861 "Cannot chown() \"attribute directory of "
1862 "file %s\"", G_p->g_attrfnam_p);
1865 if (fchmod(dirfd, G_p->g_mode) != 0) {
1866 msg(ERRN,
1867 "Cannot chmod() \"attribute directory of "
1868 "file %s\"", G_p->g_attrfnam_p);
1871 acl_is_set = 0;
1872 if (Pflag && aclp != NULL) {
1873 if (facl_set(dirfd, aclp) < 0) {
1874 msg(ERRN,
1875 "failed to set acl on attribute"
1876 " directory of %s ",
1877 G_p->g_attrfnam_p);
1878 } else {
1879 acl_is_set = 1;
1881 acl_free(aclp);
1882 aclp = NULL;
1886 return (1);
1889 result = stat(nam_p, &DesSt);
1891 if (ustar_dir() || Adir) {
1893 * The archive file is a directory.
1894 * Skip "." and ".."
1897 curdir = strrchr(nam_p, '.');
1899 if (curdir != NULL && curdir[1] == '\0') {
1900 lastslash = strrchr(nam_p, '/');
1902 if (lastslash != NULL) {
1903 lastslash++;
1904 } else {
1905 lastslash = nam_p;
1908 if (!(strcmp(lastslash, ".")) ||
1909 !(strcmp(lastslash, ".."))) {
1910 return (1);
1914 if (result == 0) {
1915 /* A file by the same name exists. */
1917 /* Take care of ACLs */
1918 acl_is_set = 0;
1920 if (Pflag && aclp != NULL) {
1921 if (acl_set(nam_p, aclp) < 0) {
1922 msg(ERRN,
1923 "\"%s\": failed to set acl",
1924 nam_p);
1925 } else {
1926 acl_is_set = 1;
1929 acl_free(aclp);
1930 aclp = NULL;
1932 if (Args & OCd) {
1934 * We are creating directories. Keep the
1935 * existing file.
1938 rstfiles(U_KEEP, dirfd);
1941 /* Report success. */
1943 return (1);
1945 } else {
1946 /* The archive file is not a directory. */
1948 if (result == 0) {
1950 * A file by the same name exists. Move it to a
1951 * temporary file.
1954 if (creat_tmp(nam_p) < 0) {
1956 * We weren't able to create the temp file.
1957 * Report failure.
1960 return (0);
1966 * This pile tries to create the file directly, and, if there is a
1967 * problem, creates missing directories, and then tries to create the
1968 * file again. Two strikes and you're out.
1971 cnt = 0;
1973 do {
1974 if (ustar_dir() || Adir) {
1975 /* The archive file is a directory. */
1977 result = mkdir(nam_p, G_p->g_mode);
1978 } else if (ustar_spec() || Aspec) {
1980 * The archive file is block special,
1981 * char special, socket, or a fifo.
1982 * Note that, for a socket, the third
1983 * parameter to mknod() is ignored.
1986 result = mknod(nam_p, (int)G_p->g_mode,
1987 (int)G_p->g_rdev);
1990 if (result >= 0) {
1992 * The file creation succeeded. Take care of the ACLs.
1995 acl_is_set = 0;
1997 if (Pflag && aclp != NULL) {
1998 if (acl_set(nam_p, aclp) < 0) {
1999 msg(ERRN,
2000 "\"%s\": failed to set acl", nam_p);
2001 } else {
2002 acl_is_set = 1;
2005 acl_free(aclp);
2006 aclp = NULL;
2009 cnt = 0;
2010 break;
2013 cnt++;
2014 } while (cnt < 2 && missdir(nam_p) == 0);
2016 switch (cnt) {
2017 case 0:
2018 rv = 1;
2019 rstfiles(U_OVER, dirfd);
2020 break;
2022 case 1:
2023 msg(ERRN,
2024 "Cannot create directory for \"%s\"", nam_p);
2026 if (*Over_p == '\0') {
2027 rstfiles(U_KEEP, dirfd);
2030 break;
2032 case 2:
2033 if (ustar_dir() || Adir) {
2034 msg(ERRN, "Cannot create directory \"%s\"", nam_p);
2035 } else if (ustar_spec() || Aspec) {
2036 msg(ERRN, "Cannot mknod() \"%s\"", nam_p);
2039 if (*Over_p == '\0') {
2040 rstfiles(U_KEEP, dirfd);
2043 break;
2045 default:
2046 msg(EXT, "Impossible case.");
2049 return (rv);
2053 * creat_tmp:
2056 static int
2057 creat_tmp(char *nam_p)
2059 char *t_p;
2060 int cwd;
2062 if ((Args & OCp) && G_p->g_ino == DesSt.st_ino &&
2063 G_p->g_dev == DesSt.st_dev) {
2064 msg(ERR, "Attempt to pass a file to itself.");
2065 return (-1);
2068 if (G_p->g_mtime <= DesSt.st_mtime && !(Args & OCu)) {
2069 msg(ERR, "Existing \"%s\" same age or newer", nam_p);
2070 return (-1);
2073 /* Make the temporary file name. */
2075 (void) strcpy(Over_p, nam_p);
2076 t_p = Over_p + strlen(Over_p);
2078 while (t_p != Over_p) {
2079 if (*(t_p - 1) == '/')
2080 break;
2081 t_p--;
2084 (void) strcpy(t_p, "XXXXXX");
2086 if (G_p->g_attrnam_p != NULL) {
2088 * Save our current directory, so we can go into
2089 * the attribute directory to make the temp file
2090 * and then return.
2093 cwd = save_cwd();
2094 (void) fchdir(G_p->g_dirfd);
2097 (void) mktemp(Over_p);
2099 if (G_p->g_attrnam_p != NULL) {
2100 /* Return to the current directory. */
2102 rest_cwd(cwd);
2105 if (*Over_p == '\0') {
2106 /* mktemp reports a failure. */
2108 msg(ERR, "Cannot get temporary file name.");
2109 return (-1);
2113 * If it's a regular file, write to the temporary file, and then rename
2114 * in order to accommodate potential executables.
2116 * Note: g_typeflag is only defined (set) for USTAR archive types. It
2117 * defaults to 0 in the cpio-format-regular file case, so this test
2118 * succeeds.
2121 if (G_p->g_typeflag == 0 &&
2122 (DesSt.st_mode & (ulong_t)Ftype) == S_IFREG &&
2123 (G_p->g_mode & (ulong_t)Ftype) == S_IFREG) {
2125 * The archive file and the filesystem file are both regular
2126 * files. We write to the temporary file in this case.
2129 if (Args & OCp) {
2130 if (G_p->g_attrnam_p == NULL) {
2131 Fullnam_p = Over_p;
2132 } else {
2133 Attrfile_p = Over_p;
2135 } else {
2136 G_p->g_nam_p = Over_p;
2137 if (G_p->g_attrnam_p != NULL) {
2138 Attrfile_p = Over_p;
2142 if (G_p->g_attrnam_p == NULL) {
2143 Over_p = nam_p;
2144 } else {
2145 Over_p = G_p->g_attrnam_p;
2148 Do_rename = 1;
2149 } else {
2151 * Either the archive file or the filesystem file is not a
2152 * regular file.
2155 Do_rename = 0;
2157 if (S_ISDIR(DesSt.st_mode)) {
2159 * The filesystem file is a directory.
2161 * Save the current working directory because we will
2162 * want to restore it back just in case remove_dir()
2163 * fails or get confused about where we should be.
2166 *Over_p = '\0';
2167 cwd = save_cwd();
2169 if (remove_dir(nam_p) < 0) {
2170 msg(ERRN,
2171 "Cannot remove the directory \"%s\"",
2172 nam_p);
2174 * Restore working directory back to the one
2175 * saved earlier.
2178 rest_cwd(cwd);
2179 return (-1);
2183 * Restore working directory back to the one
2184 * saved earlier
2187 rest_cwd(cwd);
2188 } else {
2190 * The file is not a directory. Will use the original
2191 * link/unlink construct, however, if the file is
2192 * namefs, link would fail with EXDEV. Therefore, we
2193 * use rename() first to back up the file.
2195 if (rename(nam_p, Over_p) < 0) {
2197 * If rename failed, try old construction
2198 * method.
2200 if (link(nam_p, Over_p) < 0) {
2201 msg(ERRN,
2202 "Cannot rename temporary file "
2203 "\"%s\" to \"%s\"", Over_p, nam_p);
2204 *Over_p = '\0';
2205 return (-1);
2208 if (unlink(nam_p) < 0) {
2209 msg(ERRN,
2210 "Cannot unlink() current \"%s\"",
2211 nam_p);
2212 (void) unlink(Over_p);
2213 *Over_p = '\0';
2214 return (-1);
2220 return (1);
2224 * Copy the datasize amount of data from the input file to buffer.
2226 * ifd - Input file descriptor.
2227 * buffer - Buffer (allocated by caller) to copy data to.
2228 * datasize - The amount of data to read from the input file
2229 * and copy to the buffer.
2230 * error - When reading from an Archive file, indicates unreadable
2231 * data was encountered, otherwise indicates errno.
2232 * data_in_info - Information needed when called from data_in().
2234 static ssize_t
2235 read_chunk(int ifd, char *buffer, size_t datasize, data_in_t *data_in_info)
2237 if (Args & OCp) {
2238 return (read(ifd, buffer, datasize));
2239 } else {
2240 FILL(datasize);
2241 if (data_in_info->data_in_proc_mode != P_SKIP) {
2242 if (Hdr_type == CRC)
2243 data_in_info->data_in_cksumval += cksum(CRC,
2244 datasize, NULL);
2245 if (data_in_info->data_in_swapfile)
2246 swap(Buffr.b_out_p, datasize);
2250 * if the bar archive is compressed, set up a pipe and
2251 * do the de-compression while reading in the file
2253 if (Hdr_type == BAR) {
2254 if (data_in_info->data_in_compress_flag == 0 &&
2255 Compressed) {
2256 setup_uncompress(
2257 &(data_in_info->data_in_pipef));
2258 data_in_info->data_in_compress_flag++;
2262 (void) memcpy(buffer, Buffr.b_out_p, datasize);
2263 Buffr.b_out_p += datasize;
2264 Buffr.b_cnt -= datasize;
2265 return (datasize);
2270 * Read as much data as we can.
2272 * ifd - input file descriptor.
2273 * buf - Buffer (allocated by caller) to copy data to.
2274 * bytes - The amount of data to read from the input file
2275 * and copy to the buffer.
2276 * rdblocksz - The size of the chunk of data to read.
2278 * Return number of bytes failed to read.
2279 * Return -1 when buffer is empty and read failed.
2281 static int
2282 read_bytes(int ifd, char *buf, size_t bytes, size_t rdblocksz,
2283 data_in_t *data_in_info)
2285 size_t bytesread;
2286 ssize_t got;
2288 for (bytesread = 0; bytesread < bytes; bytesread += got) {
2290 * Read the data from either the input file descriptor
2291 * or the archive file. read_chunk() will only return
2292 * <= 0 if data_copy() was called from data_pass().
2294 if ((got = read_chunk(ifd, buf + bytesread,
2295 min(bytes - bytesread, rdblocksz),
2296 data_in_info)) <= 0) {
2298 * We come here only in the pass mode.
2299 * If data couldn't be read from the input file
2300 * descriptor, return number of bytes in the buf.
2301 * If buffer is empty, return -1.
2303 if (bytesread == 0) {
2304 if (got == 0) /* EOF */
2305 data_in_info->data_in_rd_eof = 1;
2306 return (-1);
2308 return (bytes - bytesread);
2311 return (0);
2315 * Write as much data as we can.
2317 * ofd - output file descriptor.
2318 * buf - Source buffer to output data from.
2319 * maxwrite - The amount of data to write to the output.
2321 * return 0 upon success.
2323 static int
2324 write_bytes(int ofd, char *buf, size_t maxwrite, data_in_t *data_in_info)
2326 ssize_t cnt;
2328 errno = 0;
2329 if ((cnt = write(ofd, buf, maxwrite)) < (ssize_t)maxwrite) {
2330 data_in_info->data_in_errno = errno;
2332 * data_in() needs to know if it was an actual write(2)
2333 * failure, or if we just couldn't write all of the data
2334 * requested so that we know that the rest of the file's
2335 * data can be read but not written.
2337 if (cnt != -1)
2338 data_in_info->data_in_wr_part = 1;
2339 return (1);
2340 } else if (Args & OCp) {
2341 Blocks += (u_longlong_t)((cnt + (Bufsize - 1)) / Bufsize);
2343 return (0);
2347 * Perform I/O for given byte size with using limited i/o block size
2348 * and supplied buffer.
2350 * ifd/ofd - i/o file descriptor
2351 * buf - buffer to be used for i/o
2352 * bytes - Amount to read/write
2353 * wrblocksz - Output block size.
2354 * rdblocksz - Read block size.
2356 * Return 0 upon success. Return negative if read failed.
2357 * Return positive non-zero if write failed.
2359 static int
2360 rdwr_bytes(int ifd, int ofd, char *buf, off_t bytes,
2361 size_t wrblocksz, size_t rdblocksz, data_in_t *data_in_info)
2363 int rv, sz;
2364 int error = 0;
2365 int write_it = (data_in_info->data_in_proc_mode != P_SKIP);
2367 while (bytes > 0) {
2369 * If the number of bytes left to write is smaller than
2370 * the preferred I/O size, then we're about to do our final
2371 * write to the file, so just set wrblocksz to the number of
2372 * bytes left to write.
2374 if (bytes < wrblocksz)
2375 wrblocksz = bytes;
2377 /* Read input till satisfy output block size */
2378 sz = read_bytes(ifd, buf, wrblocksz, rdblocksz, data_in_info);
2379 if (sz < 0)
2380 return (sz);
2382 if (write_it) {
2383 rv = write_bytes(ofd, buf,
2384 wrblocksz - sz, data_in_info);
2385 if (rv != 0) {
2387 * If we wrote partial, we return and quits.
2388 * Otherwise, read through the rest of input
2389 * to go to the next file.
2391 if ((Args & OCp) ||
2392 data_in_info->data_in_wr_part) {
2393 return (rv);
2394 } else {
2395 write_it = 0;
2397 error = 1;
2400 bytes -= (wrblocksz - sz);
2402 return (error);
2406 * Write zeros for give size.
2408 * ofd - output file descriptor
2409 * buf - buffer to fill with zeros
2410 * bytes - Amount to write
2411 * wrblocksz - Write block size
2413 * return 0 upon success.
2415 static int
2416 write_zeros(int ofd, char *buf, off_t bytes, size_t wrblocksz,
2417 data_in_t *data_in_info)
2419 int rv;
2421 (void) memset(buf, 0, min(bytes, wrblocksz));
2422 while (bytes > 0) {
2423 if (bytes < wrblocksz)
2424 wrblocksz = bytes;
2425 rv = write_bytes(ofd, buf, wrblocksz, data_in_info);
2426 if (rv != 0)
2427 return (rv);
2428 bytes -= wrblocksz;
2430 return (0);
2434 * To figure out the size of the buffer used to accumulate data from
2435 * readtape() and to write to the file, we need to determine the largest
2436 * chunk of data to be written to the file at one time. This is determined
2437 * based on the following three things:
2438 * 1) The size of the archived file.
2439 * 2) The preferred I/O size of the file.
2440 * 3) If the file is a read-write system attribute file.
2441 * If the size of the file is less than the preferred I/O size or it's a
2442 * read-write system attribute file, which must be written in one operation,
2443 * then set the maximum write size to the size of the archived file.
2444 * Otherwise, the maximum write size is preferred I/O size.
2446 static int
2447 calc_maxwrite(int ofd, int rw_sysattr, off_t bytes, size_t blocksize)
2449 struct stat tsbuf;
2450 size_t maxwrite;
2451 size_t piosize; /* preferred I/O size */
2453 if (rw_sysattr || bytes < blocksize) {
2454 maxwrite = bytes;
2455 } else {
2456 if (fstat(ofd, &tsbuf) == 0) {
2457 piosize = tsbuf.st_blksize;
2458 } else {
2459 piosize = blocksize;
2461 maxwrite = min(bytes, piosize);
2463 return (maxwrite);
2466 * data_copy() and data_copy_with_holes() copy data from the input
2467 * file to output file descriptor. If ifd is -1, then the input file is
2468 * the archive file.
2470 * Parameters
2471 * ifd - Input file descriptor to read from.
2472 * ofd - Output file descriptor of extracted file.
2473 * rw_sysattr - Flag indicating if a file is an extended
2474 * system attribute file.
2475 * bytes - Amount of data (file size) of copy/write.
2476 * blocksize - Amount of data to read at a time from either
2477 * the input file descriptor or from the archive.
2478 * data_in_info - information needed while reading data when
2479 * called by data_in().
2480 * holes - Information of holes in the input file.
2482 * Return code
2483 * 0 Success
2484 * < 0 An error occurred during the read of the input
2485 * file
2486 * > 0 An error occurred during the write of the output
2487 * file descriptor.
2489 static int
2490 data_copy(int ifd, int ofd, int rw_sysattr, off_t bytes,
2491 size_t blocksize, data_in_t *data_in_info)
2493 char *buf;
2494 size_t maxwrite;
2495 int rv;
2497 /* No data to copy. */
2498 if (bytes == 0)
2499 return (0);
2501 maxwrite = calc_maxwrite(ofd, rw_sysattr, bytes, blocksize);
2502 buf = e_zalloc(E_EXIT, maxwrite);
2504 rv = rdwr_bytes(ifd, ofd, buf, bytes, maxwrite,
2505 blocksize, data_in_info);
2507 free(buf);
2508 return (rv);
2511 static int
2512 data_copy_with_holes(int ifd, int ofd, int rw_sysattr, off_t bytes,
2513 size_t blocksize, data_in_t *data_in_info, holes_info_t *holes)
2515 holes_list_t *hl;
2516 off_t curpos, noff, datasize;
2517 char *buf;
2518 size_t maxwrite;
2519 int rv, error;
2521 if (bytes == 0)
2522 return (0);
2524 maxwrite = calc_maxwrite(ofd, rw_sysattr, bytes, blocksize);
2525 buf = e_zalloc(E_EXIT, maxwrite);
2527 error = 0;
2528 curpos = 0;
2529 for (hl = holes->holes_list; hl != NULL; hl = hl->hl_next) {
2530 if (curpos != hl->hl_data) {
2531 /* adjust output position */
2532 noff = lseek(ofd, hl->hl_data, SEEK_SET);
2533 if (noff != hl->hl_data) {
2535 * Can't seek to the target, try to adjust
2536 * position by filling with zeros.
2538 datasize = hl->hl_data - curpos;
2539 rv = write_zeros(ofd, buf, datasize,
2540 maxwrite, data_in_info);
2541 if (rv != 0)
2542 goto errout;
2545 * Data is contiguous in the archive, but fragmented
2546 * in the regular file, so we also adjust the input
2547 * file position in pass mode.
2549 if (Args & OCp) {
2550 /* adjust input position */
2551 (void) lseek(ifd, hl->hl_data, SEEK_SET);
2553 curpos = hl->hl_data;
2555 datasize = hl->hl_hole - hl->hl_data;
2556 if (datasize == 0) {
2558 * There is a hole at the end of file. To create
2559 * such hole, we append one byte, and truncate the
2560 * last block. This is necessary because ftruncate(2)
2561 * alone allocates one block on the end of file.
2563 rv = write_zeros(ofd, buf, 1, maxwrite, data_in_info);
2564 if (rv != 0)
2565 goto errout;
2566 (void) ftruncate(ofd, hl->hl_data);
2567 break;
2569 rv = rdwr_bytes(ifd, ofd, buf, datasize, maxwrite,
2570 blocksize, data_in_info);
2571 if (rv != 0) {
2572 errout:
2574 * Return if we got a read error or in pass mode,
2575 * or failed with partial write. Otherwise, we'll
2576 * read through the input stream till next file.
2578 if (rv < 0 || (Args & OCp) ||
2579 data_in_info->data_in_wr_part) {
2580 free(buf);
2581 return (rv);
2583 error = 1;
2584 hl = hl->hl_next;
2585 break;
2587 curpos += datasize;
2591 * We should read through the input data to go to the next
2592 * header when non-fatal error occured.
2594 if (error && !(Args & OCp)) {
2595 data_in_info->data_in_proc_mode = P_SKIP;
2596 while (hl != NULL) {
2597 datasize = hl->hl_hole - hl->hl_data;
2598 rv = rdwr_bytes(ifd, ofd, buf, datasize, maxwrite,
2599 blocksize, data_in_info);
2600 if (rv != 0)
2601 break;
2602 hl = hl->hl_next;
2606 free(buf);
2607 return (error);
2611 * Strip off the sparse file information that is prepended to
2612 * the compressed sparse file. The information is in the following
2613 * format:
2614 * <prepended info size><SP><orig file size><SP><holes info>
2615 * where prepended info size is long right justified in 10 bytes.
2616 * Holesdata consists of the series of offset pairs:
2617 * <data offset><SP><hole offset><SP><data offset><SP><hole offset>...
2618 * prepended info size and original file size have been read in gethdr().
2619 * We read the rest of holes information here in this function.
2621 static int
2622 read_holesdata(holes_info_t *holes, off_t *fileszp,
2623 char *nam_p, data_in_t *data_in_info)
2625 char *holesdata;
2626 size_t holesdata_sz;
2628 /* We've already read the header. */
2629 holesdata_sz = holes->holesdata_sz - MIN_HOLES_HDRSIZE;
2631 if ((holesdata = e_zalloc(E_NORMAL, holesdata_sz)) == NULL) {
2632 msg(ERRN, "Could not allocate memory for "
2633 "sparse file information", nam_p);
2634 return (1);
2637 * This function is called only in OCi mode. Therefore,
2638 * read_bytes() won't fail, and won't return if error occurs in
2639 * input stream. See rstbuf().
2641 (void) read_bytes(-1, holesdata, holesdata_sz, CPIOBSZ, data_in_info);
2642 *fileszp -= holesdata_sz;
2644 /* The string should be terminated. */
2645 if (holesdata[holesdata_sz - 1] != '\0') {
2646 invalid:
2647 free(holesdata);
2648 msg(ERR, "invalid sparse file information", nam_p);
2649 return (1);
2651 if (parse_holesdata(holes, holesdata) != 0)
2652 goto invalid;
2654 /* sanity check */
2655 if (*fileszp != holes->data_size)
2656 goto invalid;
2658 free(holesdata);
2659 return (0);
2663 * data_in: If proc_mode == P_PROC, bread() the file's data from the archive
2664 * and write(2) it to the open fdes gotten from openout(). If proc_mode ==
2665 * P_SKIP, or becomes P_SKIP (due to errors etc), bread(2) the file's data
2666 * and ignore it. If the user specified any of the "swap" options (b, s or S),
2667 * and the length of the file is not appropriate for that action, do not
2668 * perform the "swap", otherwise perform the action on a buffer by buffer basis.
2669 * If the CRC header was selected, calculate a running checksum as each buffer
2670 * is processed.
2672 static void
2673 data_in(int proc_mode)
2675 char *nam_p;
2676 int pad, rv;
2677 int error = 0;
2678 int swapfile = 0;
2679 int cstatus = 0;
2680 off_t filesz;
2681 data_in_t *data_in_info;
2683 if (G_p->g_attrnam_p != NULL) {
2684 nam_p = G_p->g_attrnam_p;
2685 } else {
2686 nam_p = G_p->g_nam_p;
2689 if (((G_p->g_mode & Ftype) == S_IFLNK && proc_mode != P_SKIP) ||
2690 (Hdr_type == BAR && bar_linkflag == '2' && proc_mode != P_SKIP)) {
2691 proc_mode = P_SKIP;
2692 VERBOSE((Args & (OCv | OCV)), nam_p);
2694 if (Args & (OCb | OCs | OCS)) { /* verfify that swapping is possible */
2695 swapfile = 1;
2696 if (Args & (OCs | OCb) && G_p->g_filesz % 2) {
2697 msg(ERR,
2698 "Cannot swap bytes of \"%s\", odd number of bytes",
2699 nam_p);
2700 swapfile = 0;
2702 if (Args & (OCS | OCb) && G_p->g_filesz % 4) {
2703 msg(ERR,
2704 "Cannot swap halfwords of \"%s\", odd number "
2705 "of halfwords", nam_p);
2706 swapfile = 0;
2710 data_in_info = e_zalloc(E_EXIT, sizeof (data_in_t));
2711 data_in_info->data_in_swapfile = swapfile;
2712 data_in_info->data_in_proc_mode = proc_mode;
2714 filesz = G_p->g_filesz;
2716 if (S_ISSPARSE(G_p->g_mode) && G_p->g_holes != NULL) {
2717 /* We've already read the header in gethdr() */
2718 filesz -= MIN_HOLES_HDRSIZE;
2721 * Strip rest of the sparse file information. This includes
2722 * the data/hole offset pairs which will be used to restore
2723 * the holes in the file.
2725 if (proc_mode == P_SKIP) {
2726 /* holes info isn't necessary to skip file */
2727 free_holes_info(G_p->g_holes);
2728 G_p->g_holes = NULL;
2729 } else {
2730 rv = read_holesdata(G_p->g_holes, &filesz,
2731 nam_p, data_in_info);
2732 if (rv != 0) {
2734 * We got an error. Skip this file. holes info
2735 * is no longer necessary.
2737 free_holes_info(G_p->g_holes);
2738 G_p->g_holes = NULL;
2740 data_in_info->data_in_proc_mode = P_SKIP;
2741 error = 1;
2746 if (G_p->g_holes != NULL) {
2747 rv = data_copy_with_holes(-1, Ofile,
2748 (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
2749 G_p->g_holes->orig_size,
2750 CPIOBSZ, data_in_info, G_p->g_holes);
2752 free_holes_info(G_p->g_holes);
2753 G_p->g_holes = NULL;
2754 } else {
2755 rv = data_copy(-1, Ofile,
2756 (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
2757 filesz, CPIOBSZ, data_in_info);
2760 /* This writes out the file from the archive */
2761 if (rv != 0 || error) {
2762 errno = data_in_info->data_in_errno;
2764 if (!error) {
2765 msg(data_in_info->data_in_wr_part ? EXTN : ERRN,
2766 "Cannot write \"%s%s%s\"",
2767 (G_p->g_attrnam_p == NULL) ? "" :
2768 G_p->g_attrfnam_p,
2769 (G_p->g_attrnam_p == NULL) ? "" :
2770 G_p->g_rw_sysattr ?
2771 gettext(" System Attribute ") :
2772 gettext(" Attribute "), nam_p);
2775 * We've failed to write to the file, and input data
2776 * has been skiped to the next file. We'll need to restore
2777 * the original file, and skip the rest of work.
2779 proc_mode = P_SKIP;
2780 rstfiles(U_KEEP, G_p->g_dirfd);
2781 cstatus = close(Ofile);
2782 Ofile = 0;
2783 if (cstatus != 0) {
2784 msg(EXTN, "close error");
2788 /* we must use g_filesz for the amount of padding */
2789 pad = (Pad_val + 1 - (G_p->g_filesz & Pad_val)) & Pad_val;
2790 if (pad != 0) {
2791 FILL(pad);
2792 Buffr.b_out_p += pad;
2793 Buffr.b_cnt -= pad;
2795 if (proc_mode != P_SKIP) {
2796 if (Hdr_type == CRC &&
2797 Gen.g_cksum != data_in_info->data_in_cksumval) {
2798 msg(ERR, "\"%s\" - checksum error", nam_p);
2799 rstfiles(U_KEEP, G_p->g_dirfd);
2800 } else
2801 rstfiles(U_OVER, G_p->g_dirfd);
2802 if (Hdr_type == BAR && data_in_info->data_in_compress_flag) {
2803 (void) pclose(data_in_info->data_in_pipef);
2804 } else {
2805 cstatus = close(Ofile);
2807 Ofile = 0;
2808 if (cstatus != 0) {
2809 msg(EXTN, "close error");
2812 (void) free(data_in_info);
2814 VERBOSE((proc_mode != P_SKIP && (Args & (OCv | OCV))),
2815 (G_p->g_attrparent_p == NULL) ? G_p->g_nam_p : G_p->g_attrpath_p);
2816 Finished = 1;
2820 * Read regular file. Return number of bytes which weren't read.
2821 * Upon return, real_filesz will be real file size of input file.
2822 * When read_exact is specified, read size is adjusted to the given
2823 * file size.
2825 static off_t
2826 read_file(char *nam_p, off_t file_size, off_t *real_filesz,
2827 boolean_t read_exact)
2829 int amount_read;
2830 off_t amt_to_read;
2831 off_t readsz;
2833 if (file_size == 0)
2834 return (0);
2836 amt_to_read = file_size;
2837 do {
2838 if (read_exact && amt_to_read < CPIOBSZ)
2839 readsz = amt_to_read;
2840 else
2841 readsz = CPIOBSZ;
2843 FLUSH(readsz);
2844 errno = 0;
2846 if ((amount_read = read(Ifile, Buffr.b_in_p, readsz)) < 0) {
2847 msg(EXTN, "Cannot read \"%s%s%s\"",
2848 (Gen.g_attrnam_p == NULL) ?
2849 nam_p : Gen.g_attrfnam_p,
2850 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
2851 gettext(" System Attribute ") :
2852 gettext(" Attribute "),
2853 (Gen.g_attrnam_p == NULL) ? "" : nam_p);
2854 break;
2857 if (amount_read == 0) {
2858 /* got EOF. the file has shrunk */
2859 *real_filesz = file_size - amt_to_read;
2860 break;
2861 } else if (amount_read > amt_to_read) {
2862 /* the file has grown */
2863 *real_filesz = file_size +
2864 (amount_read - amt_to_read);
2865 amount_read = amt_to_read;
2866 } else if (amount_read == amt_to_read) {
2867 /* the file is the same size */
2868 *real_filesz = file_size;
2871 Buffr.b_in_p += amount_read;
2872 Buffr.b_cnt += (long)amount_read;
2874 amt_to_read -= (off_t)amount_read;
2875 if (!read_exact &&
2876 amt_to_read == 0 && amount_read == CPIOBSZ) {
2878 * If the file size is multiple of CPIOBSZ, we may
2879 * be able to read more from the file even though
2880 * amt_to_read already gets 0.
2882 FLUSH(CPIOBSZ);
2883 amount_read = read(Ifile, Buffr.b_in_p, CPIOBSZ);
2884 if (amount_read != 0) {
2885 /* the file has grown */
2886 *real_filesz = file_size + amount_read;
2889 } while (amt_to_read != 0);
2891 return (amt_to_read);
2895 * Read through the data in files skipping holes.
2897 static off_t
2898 read_compress_holes(char *nam_p, off_t file_size, off_t *real_filesz,
2899 holes_info_t *holes, int *hole_changed)
2901 off_t left;
2902 off_t datasize, realsz;
2903 off_t curpos, npos;
2904 holes_list_t *hl = holes->holes_list;
2906 curpos = 0;
2907 for (hl = holes->holes_list; hl != NULL; hl = hl->hl_next) {
2908 datasize = hl->hl_hole - hl->hl_data;
2910 npos = lseek(Ifile, curpos, SEEK_DATA);
2911 if (npos == -1 && errno == ENXIO) {
2913 * No more data. There are two cases.
2914 * - we have a hole toward the end of file.
2915 * - file has been shrunk, and we've reached EOF.
2917 *real_filesz = lseek(Ifile, 0, SEEK_END);
2918 if (hl->hl_data == file_size)
2919 return (0);
2921 * File has been shrunk. Check the amount of data
2922 * left.
2924 left = 0;
2925 while (hl != NULL) {
2926 left += (hl->hl_hole - hl->hl_data);
2927 hl = hl->hl_next;
2929 return (left);
2932 /* found data */
2933 curpos = npos;
2934 if (curpos != hl->hl_data) {
2936 * File has been changed. We shouldn't read data
2937 * from different offset since we've already put
2938 * the holes data.
2940 *hole_changed = 1;
2941 (void) lseek(Ifile, hl->hl_data, SEEK_SET);
2942 curpos = hl->hl_data;
2944 left = read_file(nam_p, datasize, &realsz, B_TRUE);
2945 if (left != 0) {
2946 /* file has been shrunk */
2947 *real_filesz = curpos + datasize - left;
2948 left = file_size - *real_filesz;
2949 return (left);
2951 curpos += datasize;
2954 * We've read exact size of holes. We need to make sure
2955 * that file hasn't grown by reading from the EOF.
2957 realsz = 0;
2958 (void) read_file(nam_p, CPIOBSZ, &realsz, B_FALSE);
2960 *real_filesz = curpos + realsz;
2961 return (0);
2965 * data_out: open(2) the file to be archived, compute the checksum
2966 * of it's data if the CRC header was specified and write the header.
2967 * read(2) each block of data and bwrite() it to the archive. For TARTYP (TAR
2968 * and USTAR) archives, pad the data with NULLs to the next 512 byte boundary.
2970 static void
2971 data_out(void)
2973 char *nam_p;
2974 int cnt, pad;
2975 off_t amt_to_read;
2976 off_t real_filesz;
2977 int errret = 0;
2978 int hole_changed = 0;
2979 off_t orig_filesz;
2980 holes_info_t *holes = NULL;
2982 nam_p = G_p->g_nam_p;
2983 if (Aspec) {
2984 if (Pflag && aclp != NULL) {
2985 char *secinfo = NULL;
2986 int len = 0;
2988 /* append security attributes */
2989 if (append_secattr(&secinfo, &len, aclp) == -1) {
2990 msg(ERR,
2991 "can create security information");
2993 /* call append_secattr() if more than one */
2995 if (len > 0) {
2996 /* write ancillary only if there is sec info */
2997 write_hdr(ARCHIVE_ACL, (off_t)len);
2998 write_ancillary(secinfo, len, B_TRUE);
3001 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3002 rstfiles(U_KEEP, G_p->g_dirfd);
3003 VERBOSE((Args & (OCv | OCV)), nam_p);
3004 return;
3006 if ((G_p->g_mode & Ftype) == S_IFLNK && (Hdr_type !=
3007 USTAR && Hdr_type != TAR)) { /* symbolic link */
3008 int size;
3009 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3011 FLUSH(G_p->g_filesz);
3012 errno = 0;
3014 /* Note that "size" and G_p->g_filesz are the same number */
3016 if ((size = readlink(nam_p, Buffr.b_in_p, G_p->g_filesz)) <
3017 0) {
3018 msg(ERRN, "Cannot read symbolic link \"%s\"", nam_p);
3019 return;
3023 * Note that it is OK not to add the NUL after the name read by
3024 * readlink, because it is not being used subsequently.
3027 Buffr.b_in_p += size;
3028 Buffr.b_cnt += size;
3029 pad = (Pad_val + 1 - (size & Pad_val)) & Pad_val;
3030 if (pad != 0) {
3031 FLUSH(pad);
3032 (void) memset(Buffr.b_in_p, 0, pad);
3033 Buffr.b_in_p += pad;
3034 Buffr.b_cnt += pad;
3036 VERBOSE((Args & (OCv | OCV)), nam_p);
3037 return;
3038 } else if ((G_p->g_mode & Ftype) == S_IFLNK &&
3039 (Hdr_type == USTAR || Hdr_type == TAR)) {
3040 int size;
3043 * G_p->g_filesz is the length of the right-hand side of
3044 * the symlink "x -> y".
3045 * The tar link field is only NAMSIZ long.
3048 if (G_p->g_filesz > NAMSIZ) {
3049 msg(ERRN,
3050 "Symbolic link too long \"%s\"", nam_p);
3051 return;
3053 if ((size = readlink(nam_p, T_lname, G_p->g_filesz)) < 0) {
3054 msg(ERRN,
3055 "Cannot read symbolic link \"%s\"", nam_p);
3056 return;
3058 T_lname[size] = '\0';
3059 G_p->g_filesz = (off_t)0;
3060 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3061 VERBOSE((Args & (OCv | OCV)), nam_p);
3062 return;
3064 if ((Ifile = openfile(O_RDONLY)) < 0) {
3065 msg(ERR, "\"%s%s%s\" ?",
3066 (Gen.g_attrnam_p == NULL) ? nam_p : Gen.g_attrfnam_p,
3067 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3068 gettext(" System Attribute ") : gettext(" Attribute "),
3069 (Gen.g_attrnam_p == NULL) ? "" :
3070 (Gen.g_attrparent_p == NULL) ? Gen.g_attrnam_p :
3071 Gen.g_attrparent_p);
3072 return;
3075 /* save original file size */
3076 orig_filesz = G_p->g_filesz;
3079 * Calculate the new compressed file size of a sparse file
3080 * before any of the header information is written
3081 * to the archive.
3083 if (Compress_sparse && S_ISREG(G_p->g_mode)) {
3085 * If the file being processed is a sparse file, gather the
3086 * hole information and the compressed file size.
3087 * G_p->g_filesz will need to be changed to be the size of
3088 * the compressed sparse file plus the the size of the hole
3089 * information that will be prepended to the compressed file
3090 * in the archive.
3092 holes = get_holes_info(Ifile, G_p->g_filesz, B_FALSE);
3093 if (holes != NULL)
3094 G_p->g_filesz = holes->holesdata_sz + holes->data_size;
3096 if (G_p->g_filesz > Max_offset) {
3097 msg(ERR, "%s%s%s: too large to archive "
3098 "in current mode",
3099 G_p->g_nam_p,
3100 (G_p->g_attrnam_p == NULL) ? "" :
3101 G_p->g_rw_sysattr ?
3102 gettext(" System Attribute ") :
3103 gettext(" Attribute "),
3104 (G_p->g_attrnam_p == NULL) ? "" :
3105 ((G_p->g_attrparent_p == NULL) ?
3106 G_p->g_attrnam_p:
3107 G_p->g_attrpath_p));
3109 (void) close(Ifile);
3110 if (holes != NULL)
3111 free_holes_info(holes);
3112 return; /* do not archive if it's too big */
3117 * Dump extended attribute header.
3120 if (Gen.g_attrnam_p != NULL) {
3121 write_xattr_hdr();
3124 if (Hdr_type == CRC) {
3125 long csum = cksum(CRC, 0, &errret);
3126 if (errret != 0) {
3127 G_p->g_cksum = (ulong_t)-1;
3128 msg(POST, "\"%s%s%s\" skipped",
3129 (Gen.g_attrnam_p == NULL) ?
3130 nam_p : Gen.g_attrfnam_p,
3131 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3132 gettext(" System Attribute ") :
3133 gettext(" Attribute "),
3134 (Gen.g_attrnam_p == NULL) ? "" : nam_p);
3135 if (holes != NULL)
3136 free_holes_info(holes);
3137 (void) close(Ifile);
3138 return;
3140 G_p->g_cksum = csum;
3141 } else {
3142 G_p->g_cksum = 0;
3146 * ACL has been retrieved in getname().
3148 if (Pflag) {
3149 char *secinfo = NULL;
3150 int len = 0;
3152 /* append security attributes */
3153 if ((append_secattr(&secinfo, &len, aclp)) == -1)
3154 msg(ERR, "can create security information");
3156 /* call append_secattr() if more than one */
3158 if (len > 0) {
3159 /* write ancillary only if there is sec info */
3160 write_hdr(ARCHIVE_ACL, (off_t)len);
3161 write_ancillary(secinfo, len, B_TRUE);
3165 if (holes != NULL) {
3167 * Write the header info with a modified c_mode field to
3168 * indicate a compressed sparse file is being archived,
3169 * as well as the new file size, including the size of the
3170 * compressed file as well as all the prepended data.
3172 write_hdr(ARCHIVE_SPARSE, (off_t)0);
3173 /* Prepend sparse file info */
3174 write_ancillary(holes->holesdata,
3175 holes->holesdata_sz, B_FALSE);
3176 } else {
3177 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3180 real_filesz = 0;
3182 if (holes != NULL) {
3183 amt_to_read = read_compress_holes(nam_p, G_p->g_filesz,
3184 &real_filesz, holes, &hole_changed);
3185 } else {
3186 amt_to_read = read_file(nam_p, G_p->g_filesz,
3187 &real_filesz, B_FALSE);
3190 while (amt_to_read > 0) {
3191 cnt = (amt_to_read > CPIOBSZ) ? CPIOBSZ : (int)amt_to_read;
3192 FLUSH(cnt);
3193 (void) memset(Buffr.b_in_p, 0, cnt);
3194 Buffr.b_in_p += cnt;
3195 Buffr.b_cnt += cnt;
3196 amt_to_read -= cnt;
3199 pad = (Pad_val + 1 - (G_p->g_filesz & Pad_val)) & Pad_val;
3200 if (pad != 0) {
3201 FLUSH(pad);
3202 (void) memset(Buffr.b_in_p, 0, pad);
3203 Buffr.b_in_p += pad;
3204 Buffr.b_cnt += pad;
3207 if (hole_changed == 1) {
3208 msg(ERR,
3209 "File data and hole offsets of \"%s%s%s\" have changed",
3210 (Gen.g_attrnam_p == NULL) ?
3211 G_p->g_nam_p : Gen.g_attrfnam_p,
3212 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3213 gettext(" System Attribute ") : gettext(" Attribute "),
3214 (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p);
3216 if (real_filesz > orig_filesz) {
3217 msg(ERR, "File size of \"%s%s%s\" has increased by %lld",
3218 (Gen.g_attrnam_p == NULL) ?
3219 G_p->g_nam_p : Gen.g_attrfnam_p,
3220 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3221 gettext(" System Attribute ") : gettext(" Attribute "),
3222 (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p,
3223 (real_filesz - orig_filesz));
3225 if (real_filesz < orig_filesz) {
3226 msg(ERR, "File size of \"%s%s%s\" has decreased by %lld",
3227 (Gen.g_attrnam_p == NULL) ?
3228 G_p->g_nam_p : Gen.g_attrfnam_p,
3229 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3230 gettext(" System Attribute ") : gettext(" Attribute "),
3231 (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p,
3232 (orig_filesz - real_filesz));
3235 if (holes != NULL)
3236 free_holes_info(holes);
3238 (void) close(Ifile);
3239 rstfiles(U_KEEP, G_p->g_dirfd);
3240 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3244 * data_pass: If not a special file (Aspec), open(2) the file to be
3245 * transferred, read(2) each block of data and write(2) it to the output file
3246 * Ofile, which was opened in file_pass().
3248 static void
3249 data_pass(void)
3251 int rv;
3252 int cstatus;
3253 char *namep = Nam_p;
3254 holes_info_t *holes = NULL;
3255 data_in_t *data_in_info;
3257 if (G_p->g_attrnam_p != NULL) {
3258 namep = G_p->g_attrnam_p;
3260 if (Aspec) {
3261 rstfiles(U_KEEP, G_p->g_passdirfd);
3262 cstatus = close(Ofile);
3263 Ofile = 0;
3264 VERBOSE((Args & (OCv | OCV)), Nam_p);
3265 if (cstatus != 0) {
3266 msg(EXTN, "close error");
3268 return;
3270 if ((Ifile = openat(G_p->g_dirfd, get_component(namep), 0)) < 0) {
3271 msg(ERRN, "Cannot open \"%s%s%s\", skipped",
3272 (G_p->g_attrnam_p == NULL) ? Nam_p : G_p->g_attrfnam_p,
3273 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
3274 gettext(" System Attribute ") : gettext(" Attribute "),
3275 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3276 rstfiles(U_KEEP, G_p->g_passdirfd);
3277 cstatus = close(Ofile);
3278 Ofile = 0;
3279 if (cstatus != 0) {
3280 msg(EXTN, "close error");
3282 return;
3285 data_in_info = e_zalloc(E_EXIT, sizeof (data_in_t));
3286 data_in_info->data_in_proc_mode = P_PROC;
3288 if (S_ISREG(G_p->g_mode))
3289 holes = get_holes_info(Ifile, G_p->g_filesz, B_TRUE);
3291 if (holes != NULL) {
3292 rv = data_copy_with_holes(Ifile, Ofile,
3293 (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
3294 G_p->g_filesz, Bufsize, data_in_info, holes);
3296 free_holes_info(holes);
3297 } else {
3298 rv = data_copy(Ifile, Ofile,
3299 (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
3300 G_p->g_filesz, Bufsize, data_in_info);
3303 if (rv < 0) {
3304 /* read error or unexpected EOF */
3305 if (data_in_info->data_in_rd_eof) {
3307 * read has reached EOF unexpectedly, but this isn't
3308 * an error since it's the latest shape of the file.
3310 msg(EPOST, "File size of \"%s%s%s\" has decreased",
3311 (G_p->g_attrnam_p == NULL) ?
3312 Nam_p : G_p->g_attrfnam_p,
3313 (G_p->g_attrnam_p == NULL) ? "" :
3314 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3315 gettext(" Attribute "),
3316 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3318 /* It's not error. We'll use the new file */
3319 rv = 0;
3320 } else {
3321 /* read error */
3322 msg(ERRN, "Cannot read \"%s%s%s\"",
3323 (G_p->g_attrnam_p == NULL) ?
3324 Nam_p : G_p->g_attrfnam_p,
3325 (G_p->g_attrnam_p == NULL) ? "" :
3326 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3327 gettext(" Attribute "),
3328 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3330 } else if (rv > 0) {
3331 /* write error */
3332 if (Do_rename) {
3333 msg(ERRN, "Cannot write \"%s%s%s\"", Over_p,
3334 (G_p->g_attrnam_p == NULL) ? "" :
3335 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3336 gettext(" Attribute "),
3337 (G_p->g_attrnam_p == NULL) ? "" : Over_p);
3338 } else {
3339 msg(ERRN, "Cannot write \"%s%s%s\"",
3340 Fullnam_p,
3341 (G_p->g_attrnam_p == NULL) ? "" :
3342 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3343 gettext(" Attribute "),
3344 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3348 free(data_in_info);
3350 if (rv == 0) {
3351 rstfiles(U_OVER, G_p->g_passdirfd);
3352 } else {
3353 rstfiles(U_KEEP, G_p->g_passdirfd);
3356 (void) close(Ifile);
3357 cstatus = close(Ofile);
3358 Ofile = 0;
3359 if (cstatus != 0) {
3360 msg(EXTN, "close error");
3362 VERBOSE((Args & (OCv | OCV)), Fullnam_p);
3363 Finished = 1;
3367 * file_in: Process an object from the archive. If a TARTYP (TAR or USTAR)
3368 * archive and g_nlink == 1, link this file to the file name in t_linkname
3369 * and return. Handle linked files in one of two ways. If Onecopy == 0, this
3370 * is an old style (binary or -c) archive, create and extract the data for the
3371 * first link found, link all subsequent links to this file and skip their data.
3372 * If Oncecopy == 1, save links until all have been processed, and then
3373 * process the links first to last checking their names against the patterns
3374 * and/or asking the user to rename them. The first link that is accepted
3375 * for xtraction is created and the data is read from the archive.
3376 * All subsequent links that are accepted are linked to this file.
3378 static void
3379 file_in(void)
3381 struct Lnk *l_p, *tl_p;
3382 int lnkem = 0, cleanup = 0;
3383 int proc_file;
3384 struct Lnk *ttl_p;
3385 int typeflag;
3386 char savacl;
3387 int cwd;
3389 G_p = &Gen;
3392 * Now that we've read the extended header,
3393 * determine if we should restore attributes.
3394 * Don't restore the attribute if we are extracting
3395 * a file from an archive (as opposed to doing a table of
3396 * contents) and any of the following are true:
3397 * 1. neither -@ or -/ was specified.
3398 * 2. -@ was specified, -/ wasn't specified, and we're
3399 * processing a hidden attribute directory of an attribute
3400 * or we're processing a read-write system attribute file.
3401 * 3. -@ wasn't specified, -/ was specified, and the file
3402 * we're processing it not a read-write system attribute file,
3403 * or we're processing the hidden attribute directory of an
3404 * attribute.
3406 * We always process the attributes if we're just generating
3407 * generating a table of contents, or if both -@ and -/ were
3408 * specified.
3410 if (G_p->g_attrnam_p != NULL) {
3411 if (((Args & OCt) == 0) &&
3412 ((!Atflag && !SysAtflag) ||
3413 (Atflag && !SysAtflag && ((G_p->g_attrparent_p != NULL) ||
3414 G_p->g_rw_sysattr)) ||
3415 (!Atflag && SysAtflag && ((G_p->g_attrparent_p != NULL) ||
3416 !G_p->g_rw_sysattr)))) {
3417 proc_file = F_SKIP;
3418 data_in(P_SKIP);
3419 return;
3424 * Open target directory if this isn't a skipped file
3425 * and g_nlink == 1
3427 * Links are handled further down in this function.
3430 proc_file = ckname(0);
3432 if (proc_file == F_SKIP && G_p->g_nlink == 1) {
3434 * Normally ckname() prints out the file as a side
3435 * effect except for table of contents listing
3436 * when its parameter is zero and Onecopy isn't
3437 * Zero. Due to this we need to force the name
3438 * to be printed here.
3440 if (Onecopy == 1) {
3441 VERBOSE((Args & OCt), G_p->g_nam_p);
3443 data_in(P_SKIP);
3444 return;
3447 if (proc_file != F_SKIP && open_dirfd() != 0) {
3448 data_in(P_SKIP);
3449 return;
3452 if (Hdr_type == BAR) {
3453 bar_file_in();
3454 close_dirfd();
3455 return;
3459 * For archives in USTAR format, the files are extracted according
3460 * to the typeflag.
3462 if (Hdr_type == USTAR || Hdr_type == TAR) {
3463 typeflag = Thdr_p->tbuf.t_typeflag;
3464 if (G_p->g_nlink == 1) { /* hard link */
3465 if (proc_file != F_SKIP) {
3466 int i;
3467 char lname[NAMSIZ+1];
3468 (void) memset(lname, '\0', sizeof (lname));
3470 (void) strncpy(lname, Thdr_p->tbuf.t_linkname,
3471 NAMSIZ);
3472 for (i = 0; i <= NAMSIZ && lname[i] != 0; i++)
3475 lname[i] = 0;
3476 (void) creat_lnk(G_p->g_dirfd,
3477 &lname[0], G_p->g_nam_p);
3479 close_dirfd();
3480 return;
3482 if (typeflag == '3' || typeflag == '4' || typeflag == '5' ||
3483 typeflag == '6') {
3484 if (proc_file != F_SKIP &&
3485 creat_spec(G_p->g_dirfd) > 0) {
3486 VERBOSE((Args & (OCv | OCV)),
3487 (G_p->g_attrparent_p == NULL) ?
3488 G_p->g_nam_p : G_p->g_attrpath_p);
3490 close_dirfd();
3491 return;
3492 } else if (Adir || Aspec) {
3493 if ((proc_file == F_SKIP) ||
3494 (Ofile = openout(G_p->g_dirfd)) < 0) {
3495 data_in(P_SKIP);
3496 } else {
3497 data_in(P_PROC);
3499 close_dirfd();
3500 return;
3504 if (Adir) {
3505 if (proc_file != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
3506 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3508 close_dirfd();
3509 if (Onecopy == 1) {
3510 VERBOSE((Args & OCt), G_p->g_nam_p);
3512 return;
3514 if (G_p->g_nlink == 1 || (Hdr_type == TAR ||
3515 Hdr_type == USTAR)) {
3516 if (Aspec) {
3517 if (proc_file != F_SKIP && creat_spec(G_p->g_dirfd) > 0)
3518 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3519 } else {
3520 if ((proc_file == F_SKIP) ||
3521 (Ofile = openout(G_p->g_dirfd)) < 0) {
3522 data_in(P_SKIP);
3523 } else {
3524 data_in(P_PROC);
3527 close_dirfd();
3528 return;
3530 close_dirfd();
3532 tl_p = add_lnk(&ttl_p);
3533 l_p = ttl_p;
3534 if (l_p->L_cnt == l_p->L_gen.g_nlink)
3535 cleanup = 1;
3536 if (!Onecopy || G_p->g_attrnam_p != NULL) {
3537 lnkem = (tl_p != l_p) ? 1 : 0;
3538 G_p = &tl_p->L_gen;
3539 if (proc_file == F_SKIP) {
3540 data_in(P_SKIP);
3541 } else {
3542 if (open_dirfd() != 0)
3543 return;
3544 if (!lnkem) {
3545 if (Aspec) {
3546 if (creat_spec(G_p->g_dirfd) > 0)
3547 VERBOSE((Args & (OCv | OCV)),
3548 G_p->g_nam_p);
3549 } else if ((Ofile =
3550 openout(G_p->g_dirfd)) < 0) {
3551 data_in(P_SKIP);
3552 close_dirfd();
3553 reclaim(l_p);
3554 } else {
3555 data_in(P_PROC);
3556 close_dirfd();
3558 } else {
3560 * Are we linking an attribute?
3562 cwd = -1;
3563 if (l_p->L_gen.g_attrnam_p != NULL) {
3564 (void) strcpy(Lnkend_p,
3565 l_p->L_gen.g_attrnam_p);
3566 (void) strcpy(Full_p,
3567 tl_p->L_gen.g_attrnam_p);
3568 cwd = save_cwd();
3569 (void) fchdir(G_p->g_dirfd);
3570 } else {
3571 (void) strcpy(Lnkend_p,
3572 l_p->L_gen.g_nam_p);
3573 (void) strcpy(Full_p,
3574 tl_p->L_gen.g_nam_p);
3576 (void) creat_lnk(G_p->g_dirfd,
3577 Lnkend_p, Full_p);
3578 data_in(P_SKIP);
3579 close_dirfd();
3580 l_p->L_lnk_p = NULL;
3581 free(tl_p->L_gen.g_nam_p);
3582 free(tl_p);
3583 if (cwd != -1)
3584 rest_cwd(cwd);
3587 } else { /* Onecopy */
3588 if (tl_p->L_gen.g_filesz)
3589 cleanup = 1;
3590 if (!cleanup) {
3591 close_dirfd();
3592 return; /* don't do anything yet */
3594 tl_p = l_p;
3596 * ckname will clear aclchar. We need to keep aclchar for
3597 * all links.
3599 savacl = aclchar;
3600 while (tl_p != NULL) {
3601 G_p = &tl_p->L_gen;
3602 aclchar = savacl;
3603 if ((proc_file = ckname(1)) != F_SKIP) {
3604 if (open_dirfd() != 0) {
3605 return;
3607 if (l_p->L_data) {
3608 (void) creat_lnk(G_p->g_dirfd,
3609 l_p->L_gen.g_nam_p,
3610 G_p->g_nam_p);
3611 } else if (Aspec) {
3612 (void) creat_spec(G_p->g_dirfd);
3613 l_p->L_data = 1;
3614 VERBOSE((Args & (OCv | OCV)),
3615 G_p->g_nam_p);
3616 } else if ((Ofile =
3617 openout(G_p->g_dirfd)) < 0) {
3618 proc_file = F_SKIP;
3619 } else {
3620 data_in(P_PROC);
3621 l_p->L_data = 1;
3623 } /* (proc_file = ckname(1)) != F_SKIP */
3625 tl_p = tl_p->L_lnk_p;
3627 close_dirfd();
3629 if (proc_file == F_SKIP && !cleanup) {
3630 tl_p->L_nxt_p = l_p->L_nxt_p;
3631 tl_p->L_bck_p = l_p->L_bck_p;
3632 l_p->L_bck_p->L_nxt_p = tl_p;
3633 l_p->L_nxt_p->L_bck_p = tl_p;
3634 free(l_p->L_gen.g_nam_p);
3635 free(l_p);
3637 } /* tl_p->L_lnk_p != NULL */
3638 if (l_p->L_data == 0) {
3639 data_in(P_SKIP);
3642 if (cleanup) {
3643 reclaim(l_p);
3648 * file_out: If the current file is not a special file (!Aspec) and it
3649 * is identical to the archive, skip it (do not archive the archive if it
3650 * is a regular file). If creating a TARTYP (TAR or USTAR) archive, the first
3651 * time a link to a file is encountered, write the header and file out normally.
3652 * Subsequent links to this file put this file name in their t_linkname field.
3653 * Otherwise, links are handled in one of two ways, for the old headers
3654 * (i.e. binary and -c), linked files are written out as they are encountered.
3655 * For the new headers (ASC and CRC), links are saved up until all the links
3656 * to each file are found. For a file with n links, write n - 1 headers with
3657 * g_filesz set to 0, write the final (nth) header with the correct g_filesz
3658 * value and write the data for the file to the archive.
3660 static
3662 file_out(void)
3664 struct Lnk *l_p, *tl_p;
3665 int cleanup = 0;
3666 struct Lnk *ttl_p;
3668 G_p = &Gen;
3669 if (!Aspec && IDENT(SrcSt, ArchSt))
3670 return (1); /* do not archive the archive if it's a reg file */
3672 * If compressing sparse files, wait until the compressed file size
3673 * is known to check if file size is too big.
3675 if (Compress_sparse == 0 && G_p->g_filesz > Max_offset) {
3676 msg(ERR, "%s%s%s: too large to archive in current mode",
3677 G_p->g_nam_p,
3678 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
3679 gettext(" System Attribute ") : gettext(" Attribute "),
3680 (G_p->g_attrnam_p == NULL) ? "" :
3681 ((G_p->g_attrparent_p == NULL) ? G_p->g_attrnam_p:
3682 G_p->g_attrpath_p));
3683 return (1); /* do not archive if it's too big */
3685 if (Hdr_type == TAR || Hdr_type == USTAR) { /* TAR and USTAR */
3686 if (Adir) {
3687 if (Gen.g_attrnam_p != NULL) {
3688 write_xattr_hdr();
3690 write_hdr(ARCHIVE_NORMAL, 0);
3691 return (0);
3693 if (G_p->g_nlink == 1) {
3694 data_out();
3695 return (0);
3697 tl_p = add_lnk(&ttl_p);
3698 l_p = ttl_p;
3699 if (tl_p == l_p) { /* first link to this file encountered */
3700 data_out();
3701 return (0);
3703 (void) strncpy(T_lname, l_p->L_gen.g_nam_p,
3704 l_p->L_gen.g_namesz);
3707 * check if linkname is greater than 100 characters
3709 if (strlen(T_lname) > NAMSIZ) {
3710 msg(EPOST, "cpio: %s: linkname %s is greater than %d",
3711 G_p->g_nam_p, T_lname, NAMSIZ);
3712 return (1);
3715 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3716 VERBOSE((Args & (OCv | OCV)), tl_p->L_gen.g_nam_p);
3718 /* find the lnk entry in sublist, unlink it, and free it */
3719 for (; ttl_p->L_lnk_p != NULL;
3720 ttl_p = ttl_p->L_lnk_p) {
3721 if (ttl_p->L_lnk_p == tl_p) {
3722 ttl_p->L_lnk_p = tl_p->L_lnk_p;
3723 free(tl_p->L_gen.g_nam_p);
3724 free(tl_p);
3725 break;
3729 return (0);
3731 if (Adir) {
3733 * ACL has been retrieved in getname().
3735 if (Pflag) {
3736 char *secinfo = NULL;
3737 int len = 0;
3739 /* append security attributes */
3740 if ((append_secattr(&secinfo, &len, aclp)) == -1)
3741 msg(ERR, "can create security information");
3743 /* call append_secattr() if more than one */
3745 if (len > 0) {
3746 /* write ancillary */
3747 write_hdr(ARCHIVE_ACL, (off_t)len);
3748 write_ancillary(secinfo, len, B_TRUE);
3752 if (Gen.g_attrnam_p != NULL) {
3753 write_xattr_hdr();
3755 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3756 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3757 return (0);
3759 if (G_p->g_nlink == 1) {
3760 data_out();
3761 return (0);
3762 } else {
3763 tl_p = add_lnk(&ttl_p);
3764 l_p = ttl_p;
3766 if (l_p->L_cnt == l_p->L_gen.g_nlink)
3767 cleanup = 1;
3768 else if (Onecopy && G_p->g_attrnam_p == NULL) {
3769 return (0); /* don't process data yet */
3772 if (Onecopy && G_p->g_attrnam_p == NULL) {
3773 tl_p = l_p;
3774 while (tl_p->L_lnk_p != NULL) {
3775 G_p = &tl_p->L_gen;
3776 G_p->g_filesz = (off_t)0;
3777 /* one link with the acl is sufficient */
3778 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3779 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3780 tl_p = tl_p->L_lnk_p;
3782 G_p = &tl_p->L_gen;
3783 if (open_dirfd() != 0)
3784 return (1);
3786 /* old style: has acl and data for every link */
3787 data_out();
3788 if (cleanup)
3789 reclaim(l_p);
3790 return (0);
3794 * Verify the underlying file system supports the attribute type.
3795 * Only archive extended attribute files when '-@' was specified.
3796 * Only archive system extended attribute files if '-/' was specified.
3798 #if defined(O_XATTR)
3799 static attr_status_t
3800 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
3801 int *ext_attrflg)
3804 * Verify extended attributes are supported/exist. We only
3805 * need to check if we are processing a base file, not an
3806 * extended attribute.
3808 if (attrflg) {
3809 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
3810 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
3812 if (Atflag) {
3813 #if defined(_PC_SATTR_ENABLED)
3814 if (!*ext_attrflg) {
3815 if (SysAtflag) {
3816 /* Verify system attributes are supported */
3817 if (sysattr_support(filename,
3818 (actflag == ARC_CREATE) ?_PC_SATTR_EXISTS :
3819 _PC_SATTR_ENABLED) != 1) {
3820 return (ATTR_SATTR_ERR);
3822 } else
3823 return (ATTR_XATTR_ERR);
3824 #else
3825 return (ATTR_XATTR_ERR);
3826 #endif /* _PC_SATTR_ENABLED */
3829 #if defined(_PC_SATTR_ENABLED)
3830 } else if (SysAtflag) {
3831 /* Verify system attributes are supported */
3832 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
3833 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
3834 return (ATTR_SATTR_ERR);
3836 #endif /* _PC_SATTR_ENABLED */
3837 } else {
3838 return (ATTR_SKIP);
3841 return (ATTR_OK);
3843 #endif
3845 #if defined(O_XATTR)
3847 * Verify the attribute, attrname, is an attribute we want to restore.
3848 * Never restore read-only system attribute files. Only restore read-write
3849 * system attributes files when -/ was specified, and only traverse into
3850 * the 2nd level attribute directory containing only system attributes if
3851 * -@ was specified. This keeps us from archiving
3852 * <attribute name>/<read-write system attribute file>
3853 * when -/ was specified without -@.
3855 * attrname - attribute file name
3856 * attrparent - attribute's parent name within the base file's
3857 * attribute digrectory hierarchy
3858 * arc_rwsysattr - flag that indicates that read-write system attribute
3859 * file should be archived as it contains other than
3860 * the default system attributes.
3861 * rw_sysattr - on return, flag will indicate if attrname is a
3862 * read-write system attribute file.
3864 static attr_status_t
3865 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
3866 int *rw_sysattr)
3868 #if defined(_PC_SATTR_ENABLED)
3869 int attr_supported;
3871 /* Never restore read-only system attribute files */
3872 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
3873 *rw_sysattr = 0;
3874 return (ATTR_SKIP);
3875 } else {
3876 *rw_sysattr = (attr_supported == _RW_SATTR);
3880 * Don't archive a read-write system attribute file if
3881 * it contains only the default system attributes.
3883 if (*rw_sysattr && !arc_rwsysattr) {
3884 return (ATTR_SKIP);
3887 #else
3888 /* Never restore read-only system attribute files */
3889 if ((*rw_sysattr = is_sysattr(attrname)) == 1) {
3890 return (ATTR_SKIP);
3892 #endif /* _PC_SATTR_ENABLED */
3895 * Only restore read-write system attribute files
3896 * when -/ was specified. Only restore extended
3897 * attributes when -@ was specified.
3899 if (Atflag) {
3900 if (!SysAtflag) {
3902 * Only archive/restore the hidden directory "." if
3903 * we're processing the top level hidden attribute
3904 * directory. We don't want to process the
3905 * hidden attribute directory of the attribute
3906 * directory that contains only extended system
3907 * attributes.
3909 if (*rw_sysattr || (Hiddendir &&
3910 (attrparent != NULL))) {
3911 return (ATTR_SKIP);
3914 } else if (SysAtflag) {
3916 * Only archive/restore read-write extended system attribute
3917 * files of the base file.
3919 if (!*rw_sysattr || (attrparent != NULL)) {
3920 return (ATTR_SKIP);
3922 } else {
3923 return (ATTR_SKIP);
3926 return (ATTR_OK);
3928 #endif
3930 #if defined(O_XATTR)
3931 static int
3932 retry_open_attr(int pdirfd, int cwd, char *fullname, char *pattr, char *name,
3933 int oflag, mode_t mode)
3935 int dirfd;
3936 int ofilefd = -1;
3937 struct timeval times[2];
3938 mode_t newmode;
3939 struct stat parentstat;
3940 acl_t *aclp = NULL;
3941 int error;
3944 * We couldn't get to attrdir. See if its
3945 * just a mode problem on the parent file.
3946 * for example: a mode such as r-xr--r--
3947 * on a ufs file system without extended
3948 * system attribute support won't let us
3949 * create an attribute dir if it doesn't
3950 * already exist, and on a ufs file system
3951 * with extended system attribute support
3952 * won't let us open the attribute for
3953 * write.
3955 * If file has a non-trivial ACL, then save it
3956 * off so that we can place it back on after doing
3957 * chmod's.
3959 if ((dirfd = openat(cwd, (pattr == NULL) ? fullname : pattr,
3960 O_RDONLY)) == -1) {
3961 return (-1);
3963 if (fstat(dirfd, &parentstat) == -1) {
3964 msg(ERRN, "Cannot stat %sfile %s",
3965 (pdirfd == -1) ? "" : gettext("parent of "),
3966 (pdirfd == -1) ? fullname : name);
3967 (void) close(dirfd);
3968 return (-1);
3970 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
3971 msg(ERRN, "Failed to retrieve ACL on %sfile %s",
3972 (pdirfd == -1) ? "" : gettext("parent of "),
3973 (pdirfd == -1) ? fullname : name);
3974 (void) close(dirfd);
3975 return (-1);
3978 newmode = S_IWUSR | parentstat.st_mode;
3979 if (fchmod(dirfd, newmode) == -1) {
3980 msg(ERRN, "Cannot change mode of %sfile %s to %o",
3981 (pdirfd == -1) ? "" : gettext("parent of "),
3982 (pdirfd == -1) ? fullname : name, newmode);
3983 if (aclp)
3984 acl_free(aclp);
3985 (void) close(dirfd);
3986 return (-1);
3990 if (pdirfd == -1) {
3992 * We weren't able to create the attribute directory before.
3993 * Now try again.
3995 ofilefd = attropen(fullname, ".", oflag);
3996 } else {
3998 * We weren't able to create open the attribute before.
3999 * Now try again.
4001 ofilefd = openat(pdirfd, name, oflag, mode);
4005 * Put mode back to original
4007 if (fchmod(dirfd, parentstat.st_mode) == -1) {
4008 msg(ERRN, "Cannot restore permissions of %sfile %s to %o",
4009 (pdirfd == -1) ? "" : gettext("parent of "),
4010 (pdirfd == -1) ? fullname : name, newmode);
4013 if (aclp) {
4014 error = facl_set(dirfd, aclp);
4015 if (error) {
4016 msg(ERRN, "failed to set acl entries on %sfile %s\n",
4017 (pdirfd == -1) ? "" : gettext("parent of "),
4018 (pdirfd == -1) ? fullname : name);
4020 acl_free(aclp);
4024 * Put back time stamps
4027 times[0].tv_sec = parentstat.st_atime;
4028 times[0].tv_usec = 0;
4029 times[1].tv_sec = parentstat.st_mtime;
4030 times[1].tv_usec = 0;
4032 (void) futimesat(cwd, (pattr == NULL) ? fullname : pattr, times);
4034 (void) close(dirfd);
4036 return (ofilefd);
4038 #endif
4040 #if defined(O_XATTR)
4042 * Recursively open attribute directories until the attribute directory
4043 * containing the specified attribute, attrname, is opened.
4045 * Currently, only 2 directory levels of attributes are supported, (i.e.,
4046 * extended system attributes on extended attributes). The following are
4047 * the possible input combinations:
4048 * 1. Open the attribute directory of the base file (don't change
4049 * into it).
4050 * attr_parent = NULL
4051 * attrname = '.'
4052 * 2. Open the attribute directory of the base file and change into it.
4053 * attr_parent = NULL
4054 * attrname = <attr> | <sys_attr>
4055 * 3. Open the attribute directory of the base file, change into it,
4056 * then recursively call open_attr_dir() to open the attribute's
4057 * parent directory (don't change into it).
4058 * attr_parent = <attr>
4059 * attrname = '.'
4060 * 4. Open the attribute directory of the base file, change into it,
4061 * then recursively call open_attr_dir() to open the attribute's
4062 * parent directory and change into it.
4063 * attr_parent = <attr>
4064 * attrname = <attr> | <sys_attr>
4066 * An attribute directory will be opened only if the underlying file system
4067 * supports the attribute type, and if the command line specifications
4068 * (f_extended_attr and f_sys_attr) enable the processing of the attribute
4069 * type.
4071 * On succesful return, attr_parentfd will be the file descriptor of the
4072 * opened attribute directory. In addition, if the attribute is a read-write
4073 * extended system attribute, rw_sysattr will be set to 1, otherwise
4074 * it will be set to 0.
4076 * Possible return values:
4077 * ATTR_OK Successfully opened and, if needed, changed into the
4078 * attribute directory containing attrname.
4079 * ATTR_SKIP The command line specifications don't enable the
4080 * processing of the attribute type.
4081 * ATTR_CHDIR_ERR An error occurred while trying to change into an
4082 * attribute directory.
4083 * ATTR_OPEN_ERR An error occurred while trying to open an
4084 * attribute directory.
4085 * ATTR_XATTR_ERR The underlying file system doesn't support extended
4086 * attributes.
4087 * ATTR_SATTR_ERR The underlying file system doesn't support extended
4088 * system attributes.
4090 static int
4091 open_attr_dir(char *attrname, char *dirp, int cwd, char *attr_parent,
4092 int *attr_parentfd, int *rw_sysattr)
4094 attr_status_t rc;
4095 int firsttime = (*attr_parentfd == -1);
4096 int saveerrno;
4097 int ext_attr;
4100 * open_attr_dir() was recursively called (input combination number 4),
4101 * close the previously opened file descriptor as we've already changed
4102 * into it.
4104 if (!firsttime) {
4105 (void) close(*attr_parentfd);
4106 *attr_parentfd = -1;
4110 * Verify that the underlying file system supports the restoration
4111 * of the attribute.
4113 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
4114 &ext_attr)) != ATTR_OK) {
4115 return (rc);
4118 /* Open the base file's attribute directory */
4119 if ((*attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
4121 * Save the errno from the attropen so it can be reported
4122 * if the retry of the attropen fails.
4124 saveerrno = errno;
4125 if ((*attr_parentfd = retry_open_attr(-1, cwd, dirp,
4126 NULL, ".", O_RDONLY, 0)) == -1) {
4127 (void) close(*attr_parentfd);
4128 *attr_parentfd = -1;
4129 errno = saveerrno;
4130 return (ATTR_OPEN_ERR);
4135 * Change into the parent attribute's directory unless we are
4136 * processing the hidden attribute directory of the base file itself.
4138 if ((Hiddendir == 0) || (firsttime && (attr_parent != NULL))) {
4139 if (fchdir(*attr_parentfd) != 0) {
4140 saveerrno = errno;
4141 (void) close(*attr_parentfd);
4142 *attr_parentfd = -1;
4143 errno = saveerrno;
4144 return (ATTR_CHDIR_ERR);
4148 /* Determine if the attribute should be processed */
4149 if ((rc = verify_attr(attrname, attr_parent, 1,
4150 rw_sysattr)) != ATTR_OK) {
4151 saveerrno = errno;
4152 (void) close(*attr_parentfd);
4153 *attr_parentfd = -1;
4154 errno = saveerrno;
4155 return (rc);
4159 * If the attribute is an extended system attribute of an attribute
4160 * (i.e., <attr>/<sys_attr>), then recursively call open_attr_dir() to
4161 * open the attribute directory of the parent attribute.
4163 if (firsttime && (attr_parent != NULL)) {
4164 return (open_attr_dir(attrname, attr_parent, *attr_parentfd,
4165 attr_parent, attr_parentfd, rw_sysattr));
4168 return (ATTR_OK);
4170 #endif
4173 * file_pass: If the -l option is set (link files when possible), and the
4174 * source and destination file systems are the same, link the source file
4175 * (G_p->g_nam_p) to the destination file (Fullnam) and return. If not a
4176 * linked file, transfer the data. Otherwise, the first link to a file
4177 * encountered is transferred normally and subsequent links are linked to it.
4180 static int
4181 file_pass(void)
4183 struct Lnk *l_p, *tl_p;
4184 struct Lnk *ttl_p;
4185 char *save_name;
4186 int size;
4187 int cwd;
4188 char *lfrom, *lto;
4190 G_p = &Gen;
4192 if (Adir && !(Args & OCd)) {
4193 msg(ERR, "Use -d option to copy \"%s\"", G_p->g_nam_p);
4194 return (FILE_PASS_ERR);
4197 save_name = G_p->g_nam_p;
4199 while (*(G_p->g_nam_p) == '/') {
4200 G_p->g_nam_p++;
4203 (void) strcpy(Full_p, (G_p->g_attrfnam_p == NULL) ?
4204 G_p->g_nam_p : G_p->g_attrfnam_p);
4206 if (G_p->g_attrnam_p == NULL) {
4207 G_p->g_passdirfd = open_dir(Fullnam_p);
4209 if (G_p->g_passdirfd == -1) {
4210 msg(ERRN,
4211 "Cannot open/create \"%s\"", Fullnam_p);
4212 return (FILE_PASS_ERR);
4214 } else {
4215 int rw_sysattr;
4218 * Open the file's attribute directory.
4219 * Change into the base file's starting directory then call
4220 * open_attr_dir() to open the attribute directory of either
4221 * the base file (if G_p->g_attrparent_p is NULL) or the
4222 * attribute (if G_p->g_attrparent_p is set) of the base file.
4225 G_p->g_passdirfd = -1;
4226 (void) fchdir(G_p->g_baseparent_fd);
4227 (void) open_attr_dir(G_p->g_attrnam_p, Fullnam_p,
4228 G_p->g_baseparent_fd, (G_p->g_attrparent_p == NULL) ? NULL :
4229 G_p->g_attrparent_p, &G_p->g_passdirfd, &rw_sysattr);
4230 if (G_p->g_passdirfd == -1) {
4231 msg(ERRN,
4232 "Cannot open attribute directory of "
4233 "%s%s%sfile \"%s\"",
4234 (G_p->g_attrparent_p == NULL) ? "" :
4235 gettext("attribute \""),
4236 (G_p->g_attrparent_p == NULL) ? "" :
4237 G_p->g_attrparent_p,
4238 (G_p->g_attrparent_p == NULL) ? "" :
4239 gettext("\" of "), Fullnam_p);
4240 return (FILE_PASS_ERR);
4244 if (Args & OCl) {
4245 /* We are linking back to the source directory. */
4247 if (!Adir) {
4248 char *existingfile = save_name;
4250 if ((Args & OCL) && issymlink) {
4251 /* We are chasing symlinks. */
4253 if ((size = readlink(save_name, Symlnk_p,
4254 MAXPATHLEN)) < 0) {
4255 msg(ERRN,
4256 "Cannot read symbolic link \"%s\"",
4257 save_name);
4258 return (FILE_PASS_ERR);
4261 Symlnk_p[size] = '\0';
4262 existingfile = Symlnk_p;
4265 if (G_p->g_attrnam_p == NULL) {
4266 if (creat_lnk(G_p->g_passdirfd,
4267 existingfile, Fullnam_p) == 0) {
4268 return (FILE_LINKED);
4274 if ((G_p->g_mode & Ftype) == S_IFLNK && !(Args & OCL)) {
4275 /* The archive file is a symlink. */
4277 errno = 0;
4279 if ((size = readlink(save_name, Symlnk_p, MAXPATHLEN)) < 0) {
4280 msg(ERRN,
4281 "Cannot read symbolic link \"%s\"", save_name);
4282 return (FILE_PASS_ERR);
4285 errno = 0;
4286 (void) missdir(Fullnam_p);
4287 *(Symlnk_p + size) = '\0';
4289 if (symlink(Symlnk_p, Fullnam_p) < 0) {
4290 if (errno == EEXIST) {
4291 if (openout(G_p->g_passdirfd) < 0) {
4292 if (errno != EEXIST) {
4293 msg(ERRN,
4294 "Cannot create \"%s\"",
4295 Fullnam_p);
4297 return (FILE_PASS_ERR);
4299 } else {
4300 msg(ERRN, "Cannot create \"%s\"", Fullnam_p);
4301 return (FILE_PASS_ERR);
4303 } else {
4304 if (Args & OCR) {
4305 if (lchown(Fullnam_p, (int)Rpw_p->pw_uid,
4306 (int)Rpw_p->pw_gid) < 0) {
4307 msg(ERRN,
4308 "Error during chown() of \"%s\"",
4309 Fullnam_p);
4311 } else if ((lchown(Fullnam_p, (int)G_p->g_uid,
4312 (int)G_p->g_gid) < 0) && privileged) {
4313 msg(ERRN,
4314 "Error during chown() of \"%s\"",
4315 Fullnam_p);
4319 VERBOSE((Args & (OCv | OCV)), Fullnam_p);
4320 return (FILE_PASS_ERR);
4323 if (!Adir && G_p->g_nlink > 1) {
4324 /* The archive file has hard links. */
4326 tl_p = add_lnk(&ttl_p);
4327 l_p = ttl_p;
4329 if (tl_p == l_p) {
4330 /* The archive file was not found. */
4332 G_p = &tl_p->L_gen;
4333 } else {
4334 /* The archive file was found. */
4336 cwd = -1;
4338 if (l_p->L_gen.g_attrnam_p != NULL) {
4339 /* We are linking an attribute */
4341 (void) strcpy(Lnkend_p, l_p->L_gen.g_attrnam_p);
4342 cwd = save_cwd();
4343 (void) fchdir(G_p->g_passdirfd);
4344 lfrom = get_component(Lnknam_p);
4345 lto = tl_p->L_gen.g_attrnam_p;
4346 } else {
4347 /* We are not linking an attribute */
4349 (void) strcpy(Lnkend_p, l_p->L_gen.g_nam_p);
4350 (void) strcpy(Full_p, tl_p->L_gen.g_nam_p);
4351 lfrom = Lnknam_p;
4352 lto = Fullnam_p;
4355 (void) creat_lnk(G_p->g_passdirfd, lfrom, lto);
4357 if (cwd) {
4358 rest_cwd(cwd);
4361 l_p->L_lnk_p = NULL;
4362 free(tl_p->L_gen.g_nam_p);
4363 free(tl_p);
4365 if (l_p->L_cnt == G_p->g_nlink) {
4366 reclaim(l_p);
4369 return (FILE_LINKED);
4373 if (Adir || Aspec) {
4375 * The archive file is a directory, block special, char
4376 * special or a fifo.
4379 if (creat_spec(G_p->g_passdirfd) > 0) {
4380 VERBOSE((Args & (OCv | OCV)), Fullnam_p);
4382 } else if ((Ofile = openout(G_p->g_passdirfd)) > 0) {
4383 data_pass();
4386 return (FILE_COPIED);
4390 * flush_lnks: With new linked file handling, linked files are not archived
4391 * until all links have been collected. When the end of the list of filenames
4392 * to archive has been reached, all files that did not encounter all their links
4393 * are written out with actual (encountered) link counts. A file with n links
4394 * (that are archived) will be represented by n headers (one for each link (the
4395 * first n - 1 have g_filesz set to 0)) followed by the data for the file.
4398 static void
4399 flush_lnks(void)
4401 struct Lnk *l_p, *tl_p;
4402 off_t tfsize;
4404 l_p = Lnk_hd.L_nxt_p;
4405 while (l_p != &Lnk_hd) {
4406 (void) strcpy(Gen.g_nam_p, l_p->L_gen.g_nam_p);
4407 if (stat(Gen.g_nam_p, &SrcSt) == 0) { /* check if file exists */
4408 tl_p = l_p;
4409 (void) creat_hdr();
4410 Gen.g_nlink = l_p->L_cnt; /* "actual" link count */
4411 tfsize = Gen.g_filesz;
4412 Gen.g_filesz = (off_t)0;
4413 G_p = &Gen;
4414 while (tl_p != NULL) {
4415 Gen.g_nam_p = tl_p->L_gen.g_nam_p;
4416 Gen.g_namesz = tl_p->L_gen.g_namesz;
4417 if (tl_p->L_lnk_p == NULL) {
4418 Gen.g_filesz = tfsize;
4419 if (open_dirfd() != 0) {
4420 break;
4422 data_out();
4423 break;
4425 write_hdr(ARCHIVE_NORMAL,
4426 (off_t)0); /* header only */
4427 VERBOSE((Args & (OCv | OCV)), Gen.g_nam_p);
4428 tl_p = tl_p->L_lnk_p;
4430 Gen.g_nam_p = Nam_p;
4431 } else /* stat(Gen.g_nam_p, &SrcSt) == 0 */
4432 msg(ERR, "\"%s%s%s\" has disappeared",
4433 (Gen.g_attrnam_p == NULL) ?
4434 Gen.g_nam_p : Gen.g_attrfnam_p,
4435 (Gen.g_attrnam_p == NULL) ?
4436 "" : Gen.g_rw_sysattr ?
4437 gettext(" System Attribute ") :
4438 gettext(" Attribute "),
4439 (Gen.g_attrnam_p == NULL) ?
4440 "" : Gen.g_attrnam_p);
4441 tl_p = l_p;
4442 l_p = l_p->L_nxt_p;
4443 reclaim(tl_p);
4444 } /* l_p != &Lnk_hd */
4447 #if defined(O_XATTR)
4448 static int
4449 is_sysattr(char *name)
4451 return ((strcmp(name, VIEW_READONLY) == 0) ||
4452 (strcmp(name, VIEW_READWRITE) == 0));
4454 #endif
4457 * gethdr: Get a header from the archive, validate it and check for the trailer.
4458 * Any user specified Hdr_type is ignored (set to NONE in main). Hdr_type is
4459 * set appropriately after a valid header is found. Unless the -k option is
4460 * set a corrupted header causes an exit with an error. I/O errors during
4461 * examination of any part of the header cause gethdr to throw away any current
4462 * data and start over. Other errors during examination of any part of the
4463 * header cause gethdr to advance one byte and continue the examination.
4466 static int
4467 gethdr(void)
4469 ushort_t ftype;
4470 int hit = NONE, cnt = 0;
4471 int goodhdr, hsize, offset;
4472 int bswap = 0;
4473 char *preptr;
4474 int k = 0;
4475 int j;
4476 int error;
4477 int aclcnt;
4479 Gen.g_nam_p = Nam_p;
4480 do { /* hit == NONE && (Args & OCk) && Buffr.b_cnt > 0 */
4481 FILL(Hdrsz);
4482 switch (Hdr_type) {
4483 case NONE:
4484 case BIN:
4485 Binmag.b_byte[0] = Buffr.b_out_p[0];
4486 Binmag.b_byte[1] = Buffr.b_out_p[1];
4487 if ((Binmag.b_half == CMN_BIN) ||
4488 (Binmag.b_half == CMN_BBS)) {
4489 hit = read_hdr(BIN);
4490 if (Hdr_type == NONE)
4491 bswap = 1;
4492 hsize = HDRSZ + Gen.g_namesz;
4493 break;
4495 if (Hdr_type != NONE)
4496 break;
4497 /*FALLTHROUGH*/
4498 case CHR:
4499 if (!(strncmp(Buffr.b_out_p, CMS_CHR, CMS_LEN))) {
4500 hit = read_hdr(CHR);
4501 hsize = CHRSZ + Gen.g_namesz;
4502 break;
4504 if (Hdr_type != NONE)
4505 break;
4506 /*FALLTHROUGH*/
4507 case ASC:
4508 if (!(strncmp(Buffr.b_out_p, CMS_ASC, CMS_LEN))) {
4509 hit = read_hdr(ASC);
4510 hsize = ASCSZ + Gen.g_namesz;
4511 Max_namesz = APATH;
4512 break;
4514 if (Hdr_type != NONE)
4515 break;
4516 /*FALLTHROUGH*/
4517 case CRC:
4518 if (!(strncmp(Buffr.b_out_p, CMS_CRC, CMS_LEN))) {
4519 hit = read_hdr(CRC);
4520 hsize = ASCSZ + Gen.g_namesz;
4521 Max_namesz = APATH;
4522 break;
4524 if (Hdr_type != NONE)
4525 break;
4526 /*FALLTHROUGH*/
4528 case BAR:
4529 if (Hdr_p != NULL && strcmp(Hdr_p, "bar") == 0) {
4530 Hdrsz = BARSZ;
4531 FILL(Hdrsz);
4532 if ((hit = read_hdr(BAR)) == NONE) {
4533 Hdrsz = ASCSZ;
4534 break;
4536 hit = BAR;
4537 hsize = BARSZ;
4538 break;
4540 /*FALLTHROUGH*/
4542 case USTAR:
4543 if (Hdr_p != NULL && strcmp(Hdr_p, "ustar") == 0) {
4544 Hdrsz = TARSZ;
4545 FILL(Hdrsz);
4546 if ((hit = read_hdr(USTAR)) == NONE) {
4547 Hdrsz = ASCSZ;
4548 break;
4550 hit = USTAR;
4551 hsize = TARSZ;
4552 break;
4554 /*FALLTHROUGH*/
4555 case TAR:
4556 if (Hdr_p != NULL && strcmp(Hdr_p, "tar") == 0) {
4557 Hdrsz = TARSZ;
4558 FILL(Hdrsz);
4559 if ((hit = read_hdr(TAR)) == NONE) {
4560 Hdrsz = ASCSZ;
4561 break;
4563 hit = TAR;
4564 hsize = TARSZ;
4565 break;
4567 /*FALLTHROUGH*/
4568 default:
4569 msg(EXT, "Impossible header type.");
4570 } /* Hdr_type */
4572 if (hit == TAR || hit == USTAR) {
4573 Gen.g_nam_p = &nambuf[0];
4576 if (hit != NONE) {
4577 FILL(hsize);
4578 goodhdr = 1;
4579 if (Gen.g_filesz < (off_t)0 || Gen.g_namesz < 1)
4580 goodhdr = 0;
4581 if ((hit != USTAR) && (hit != TAR))
4582 if (Gen.g_namesz - 1 > Max_namesz)
4583 goodhdr = 0;
4584 /* TAR and USTAR */
4585 if ((hit == USTAR) || (hit == TAR)) {
4586 if (*Gen.g_nam_p == '\0') { /* tar trailer */
4587 goodhdr = 1;
4588 } else {
4590 G_p = &Gen;
4591 if (G_p->g_cksum !=
4592 cksum(TARTYP, 0, NULL)) {
4593 goodhdr = 0;
4594 msg(ERR,
4595 "Bad header - checksum "
4596 "error.");
4599 } else if (hit != BAR) { /* binary, -c, ASC and CRC */
4600 if (Gen.g_nlink <= (ulong_t)0)
4601 goodhdr = 0;
4602 if (*(Buffr.b_out_p + hsize - 1) != '\0')
4603 goodhdr = 0;
4605 if (!goodhdr) {
4606 hit = NONE;
4607 if (!(Args & OCk))
4608 break;
4609 msg(ERR,
4610 "Corrupt header, file(s) may be lost.");
4611 } else {
4612 FILL(hsize);
4614 } /* hit != NONE */
4615 if (hit == NONE) {
4616 Buffr.b_out_p++;
4617 Buffr.b_cnt--;
4618 if (!(Args & OCk))
4619 break;
4620 if (!cnt++)
4621 msg(ERR, "Searching for magic number/header.");
4623 } while (hit == NONE);
4624 if (hit == NONE) {
4625 if (Hdr_type == NONE)
4626 msg(EXT, "Not a cpio file, bad header.");
4627 else
4628 msg(EXT, "Bad magic number/header.");
4629 } else if (cnt > 0) {
4630 msg(EPOST, "Re-synchronized on magic number/header.");
4632 if (Hdr_type == NONE) {
4633 Hdr_type = hit;
4634 switch (Hdr_type) {
4635 case BIN:
4636 if (bswap)
4637 Args |= BSM;
4638 Hdrsz = HDRSZ;
4639 Max_namesz = CPATH;
4640 Pad_val = HALFWD;
4641 Onecopy = 0;
4642 break;
4643 case CHR:
4644 Hdrsz = CHRSZ;
4645 Max_namesz = CPATH;
4646 Pad_val = 0;
4647 Onecopy = 0;
4648 break;
4649 case ASC:
4650 case CRC:
4651 Hdrsz = ASCSZ;
4652 Max_namesz = APATH;
4653 Pad_val = FULLWD;
4654 Onecopy = 1;
4655 break;
4656 case USTAR:
4657 Hdrsz = TARSZ;
4658 Max_namesz = HNAMLEN - 1;
4659 Pad_val = FULLBK;
4660 Onecopy = 0;
4661 break;
4662 case BAR:
4663 case TAR:
4664 Hdrsz = TARSZ;
4665 Max_namesz = TNAMLEN - 1;
4666 Pad_val = FULLBK;
4667 Onecopy = 0;
4668 break;
4669 default:
4670 msg(EXT, "Impossible header type.");
4671 } /* Hdr_type */
4672 } /* Hdr_type == NONE */
4673 if ((Hdr_type == USTAR) || (Hdr_type == TAR) ||
4674 (Hdr_type == BAR)) { /* TAR, USTAR, BAR */
4675 Gen.g_namesz = 0;
4676 if (Gen.g_nam_p[0] == '\0')
4677 return (0);
4678 else {
4679 preptr = &prebuf[0];
4680 if (*preptr != '\0') {
4681 k = strlen(&prebuf[0]);
4682 if (k < PRESIZ) {
4683 (void) strcpy(&fullnam[0], &prebuf[0]);
4684 j = 0;
4685 fullnam[k++] = '/';
4686 while ((j < NAMSIZ) && (nambuf[j] !=
4687 '\0')) {
4688 fullnam[k] = nambuf[j];
4689 k++; j++;
4691 fullnam[k] = '\0';
4692 } else if (k >= PRESIZ) {
4693 k = 0;
4694 while ((k < PRESIZ) && (prebuf[k] !=
4695 '\0')) {
4696 fullnam[k] = prebuf[k];
4697 k++;
4699 fullnam[k++] = '/';
4700 j = 0;
4701 while ((j < NAMSIZ) && (nambuf[j] !=
4702 '\0')) {
4703 fullnam[k] = nambuf[j];
4704 k++; j++;
4706 fullnam[k] = '\0';
4708 Gen.g_nam_p = &fullnam[0];
4709 } else
4710 Gen.g_nam_p = &nambuf[0];
4713 * initialize the buffer so that the prefix will not
4714 * applied to the next entry in the archive
4716 (void) memset(prebuf, 0, sizeof (prebuf));
4718 } else if (Hdr_type != BAR) {
4719 (void) memcpy(Gen.g_nam_p, Buffr.b_out_p + Hdrsz, Gen.g_namesz);
4720 if (!(strcmp(Gen.g_nam_p, "TRAILER!!!")))
4721 return (0);
4723 offset = ((hsize + Pad_val) & ~Pad_val);
4724 FILL(offset + Hdrsz);
4725 Thdr_p = (union tblock *)Buffr.b_out_p;
4726 Buffr.b_out_p += offset;
4727 Buffr.b_cnt -= (off_t)offset;
4728 ftype = Gen.g_mode & Ftype;
4730 #if defined(O_XATTR)
4731 /* extended attribute support */
4732 if (((Gen.g_mode & S_IFMT) == _XATTR_CPIO_MODE) ||
4733 ((Hdr_type == USTAR || Hdr_type == TAR) &&
4734 Thdr_p->tbuf.t_typeflag == _XATTR_HDRTYPE)) {
4735 char *aname;
4736 char *attrparent = NULL;
4737 char *attrpath = NULL;
4738 char *tapath;
4739 char *taname;
4741 if (xattrp != NULL) {
4742 if (xattrbadhead) {
4743 free(xattrhead);
4744 xattrp = NULL;
4745 xattr_linkp = NULL;
4746 xattrhead = NULL;
4747 return (1);
4751 * At this point, the attribute path contains
4752 * the path to the attribute rooted at the hidden
4753 * attribute directory of the base file. This can
4754 * be a simple attribute or extended attribute name,
4755 * or it can be something like <attr>/<sys attr> if
4756 * we are processing a system attribute of an attribute.
4757 * Determine the attribute name and attribute parent
4758 * (if there is one). When we are processing a simple
4759 * attribute or extended attribute name, the attribute
4760 * parent will be set to NULL. When we are processing
4761 * something like <attr>/<sys attr>, the attribute
4762 * parent will be contain <attr>, and the attribute
4763 * name will contain <sys attr>.
4765 tapath = xattrp->h_names +
4766 strlen(xattrp->h_names) + 1;
4767 attrpath = e_strdup(E_EXIT, tapath);
4768 if ((taname = strpbrk(tapath, "/")) != NULL) {
4769 aname = taname + 1;
4770 *taname = '\0';
4771 attrparent = tapath;
4772 } else {
4773 aname = tapath;
4776 Gen.g_rw_sysattr = is_sysattr(aname);
4777 Gen.g_baseparent_fd = attr_baseparent_fd;
4779 if (Gen.g_attrfnam_p != NULL) {
4780 free(Gen.g_attrfnam_p);
4781 Gen.g_attrfnam_p = NULL;
4783 if (Gen.g_attrnam_p != NULL) {
4784 free(Gen.g_attrnam_p);
4785 Gen.g_attrnam_p = NULL;
4787 if (Gen.g_attrparent_p != NULL) {
4788 free(Gen.g_attrparent_p);
4789 Gen.g_attrparent_p = NULL;
4791 if (Gen.g_attrpath_p != NULL) {
4792 free(Gen.g_attrpath_p);
4793 Gen.g_attrpath_p = NULL;
4795 if (Renam_p && Renam_p[0] != '\0') {
4796 Gen.g_attrfnam_p = e_strdup(E_EXIT, Renam_p);
4797 } else {
4798 Gen.g_attrfnam_p = e_strdup(E_EXIT,
4799 xattrp->h_names);
4801 Gen.g_attrnam_p = e_strdup(E_EXIT, aname);
4803 if (attrparent != NULL) {
4804 if (Renam_attr_p && Renam_attr_p[0] != '\0') {
4805 size_t apathlen = strlen(attrparent) +
4806 strlen(aname) + 2;
4807 Gen.g_attrparent_p = e_strdup(E_EXIT,
4808 Renam_attr_p);
4809 Gen.g_attrpath_p = e_zalloc(E_EXIT,
4810 apathlen);
4811 (void) snprintf(Gen.g_attrpath_p,
4812 apathlen, "%s/%s", Renam_attr_p,
4813 aname);
4814 (void) free(attrparent);
4815 (void) free(attrpath);
4816 } else {
4817 Gen.g_attrparent_p = attrparent;
4818 Gen.g_attrpath_p = attrpath;
4820 } else {
4821 Gen.g_attrpath_p = attrpath;
4824 if (xattr_linkp != NULL) {
4825 if (Gen.g_linktoattrfnam_p != NULL) {
4826 free(Gen.g_linktoattrfnam_p);
4827 Gen.g_linktoattrfnam_p = NULL;
4829 if (Gen.g_linktoattrnam_p != NULL) {
4830 free(Gen.g_linktoattrnam_p);
4831 Gen.g_linktoattrnam_p = NULL;
4833 if (Renam_attr_p && Renam_attr_p[0] != '\0') {
4834 Gen.g_linktoattrfnam_p = e_strdup(
4835 E_EXIT, Renam_attr_p);
4836 } else {
4837 Gen.g_linktoattrfnam_p = e_strdup(
4838 E_EXIT, xattr_linkp->h_names);
4840 Gen.g_linktoattrnam_p = e_strdup(E_EXIT,
4841 aname);
4842 xattr_linkp = NULL;
4844 if (Hdr_type != USTAR && Hdr_type != TAR) {
4845 Gen.g_mode = Gen.g_mode & (~_XATTR_CPIO_MODE);
4846 Gen.g_mode |= attrmode(xattrp->h_typeflag);
4847 } else if (Hdr_type == USTAR || Hdr_type == TAR) {
4848 Thdr_p->tbuf.t_typeflag = xattrp->h_typeflag;
4851 ftype = Gen.g_mode & Ftype;
4852 Adir = ftype == S_IFDIR;
4853 Aspec = (ftype == S_IFBLK || ftype == S_IFCHR ||
4854 ftype == S_IFIFO || ftype == S_IFSOCK);
4856 if (Gen.g_attrnam_p[0] == '.' &&
4857 Gen.g_attrnam_p[1] == '\0' &&
4858 xattrp->h_typeflag == DIRTYPE) {
4859 Hiddendir = 1;
4860 } else {
4861 Hiddendir = 0;
4864 free(xattrhead);
4865 xattrhead = NULL;
4866 xattrp = NULL;
4867 } else {
4868 if (xattrbadhead == 0) {
4869 (void) read_xattr_hdr();
4870 return (2);
4873 } else {
4874 Hiddendir = 0;
4876 #endif /* O_XATTR */
4878 /* acl support: grab acl info */
4879 if ((Gen.g_mode == SECMODE) || ((Hdr_type == USTAR ||
4880 Hdr_type == TAR) && Thdr_p->tbuf.t_typeflag == 'A')) {
4881 /* this is an ancillary file */
4882 off_t bytes;
4883 char *secp;
4884 int pad;
4885 int cnt;
4886 char *tp;
4887 int attrsize;
4889 if (Pflag) {
4890 bytes = Gen.g_filesz;
4891 secp = e_zalloc(E_EXIT, (uint_t)bytes);
4892 tp = secp;
4894 while (bytes > 0) {
4895 cnt = (int)(bytes > CPIOBSZ) ? CPIOBSZ : bytes;
4896 FILL(cnt);
4897 (void) memcpy(tp, Buffr.b_out_p, cnt);
4898 tp += cnt;
4899 Buffr.b_out_p += cnt;
4900 Buffr.b_cnt -= (off_t)cnt;
4901 bytes -= (off_t)cnt;
4904 pad = (Pad_val + 1 - (Gen.g_filesz & Pad_val)) &
4905 Pad_val;
4906 if (pad != 0) {
4907 FILL(pad);
4908 Buffr.b_out_p += pad;
4909 Buffr.b_cnt -= (off_t)pad;
4912 /* got all attributes in secp */
4913 tp = secp;
4914 do {
4915 attr = (struct sec_attr *)tp;
4916 switch (attr->attr_type) {
4917 case UFSD_ACL:
4918 case ACE_ACL:
4919 (void) sscanf(attr->attr_len, "%7lo",
4920 (ulong_t *)&aclcnt);
4921 /* header is 8 */
4922 attrsize = 8 +
4923 strlen(&attr->attr_info[0])
4924 + 1;
4926 error =
4927 acl_fromtext(&attr->attr_info[0],
4928 &aclp);
4930 if (error != 0) {
4931 msg(ERR,
4932 "aclfromtext failed: %s",
4933 acl_strerror(error));
4934 bytes -= attrsize;
4935 break;
4938 if (aclcnt != acl_cnt(aclp)) {
4939 msg(ERR, "acl count error");
4940 bytes -= attrsize;
4941 break;
4943 bytes -= attrsize;
4944 break;
4946 /* SunFed case goes here */
4948 default:
4949 msg(EXT, "unrecognized attr type");
4950 break;
4952 /* next attributes */
4953 tp += attrsize;
4954 } while (bytes > 0);
4955 free(secp);
4956 } else {
4957 /* skip security info */
4958 G_p = &Gen;
4959 data_in(P_SKIP);
4962 * We already got the file content, dont call file_in()
4963 * when return. The new return code(2) is used to
4964 * indicate that.
4966 VERBOSE((Args & OCt), Gen.g_nam_p);
4967 return (2);
4968 } /* acl */
4971 * Sparse file support
4972 * Read header of holesdata to get original file size.
4973 * This is necessary because ckname() or file_in() shows file size
4974 * with OCt before data_in() extracts the holesdata. data_in()
4975 * actually doesn't extract the holesdata since proc_mode will be
4976 * P_SKIP in the OCt mode.
4978 if ((Hdr_type == CHR || Hdr_type == ASC) &&
4979 S_ISSPARSE(Gen.g_mode) && Gen.g_filesz > MIN_HOLES_HDRSIZE) {
4980 char holesdata[MIN_HOLES_HDRSIZE + 1];
4982 FILL(MIN_HOLES_HDRSIZE);
4983 (void) memcpy(holesdata, Buffr.b_out_p, MIN_HOLES_HDRSIZE);
4984 holesdata[MIN_HOLES_HDRSIZE] = '\0';
4986 Gen.g_holes = read_holes_header(holesdata, Gen.g_filesz);
4987 if (Gen.g_holes == NULL) {
4988 msg(EXT, "invalid sparse file information");
4989 } else {
4990 Buffr.b_out_p += MIN_HOLES_HDRSIZE;
4991 Buffr.b_cnt -= MIN_HOLES_HDRSIZE;
4995 Adir = (ftype == S_IFDIR);
4996 Aspec = (ftype == S_IFBLK || ftype == S_IFCHR || ftype == S_IFIFO ||
4997 ftype == S_IFSOCK);
5000 * Skip any trailing slashes
5002 chop_endslashes(Gen.g_nam_p);
5003 return (1);
5007 * getname: Get file names for inclusion in the archive. When end of file
5008 * on the input stream of file names is reached, flush the link buffer out.
5009 * For each filename, remove leading "./"s and multiple "/"s, and remove
5010 * any trailing newline "\n". Finally, verify the existence of the file,
5011 * and call creat_hdr() to fill in the gen_hdr structure.
5014 static int
5015 getname(void)
5017 int goodfile = 0, lastchar, err;
5018 char *s;
5019 char *dir;
5021 Gen.g_nam_p = Nam_p;
5022 Hiddendir = 0;
5024 while (!goodfile) {
5025 err = 0;
5027 while ((s = fgets(Gen.g_nam_p, APATH+1, In_p)) != NULL) {
5028 lastchar = strlen(s) - 1;
5029 issymlink = 0;
5031 if (s[lastchar] != '\n') {
5032 if (lastchar == APATH - 1) {
5033 if (!err) {
5034 msg(ERR,
5035 "%s name too long.",
5036 Nam_p);
5038 goodfile = 0;
5039 err = 1;
5040 } else {
5041 break;
5043 } else {
5044 s[lastchar] = '\0';
5045 break;
5049 if (s == NULL) {
5050 if (Gen.g_dirfd != -1) {
5051 (void) close(Gen.g_dirfd);
5052 Gen.g_dirfd = -1;
5054 if (Onecopy && (Args & OCo)) {
5055 flush_lnks();
5057 return (0);
5060 while (*Gen.g_nam_p == '.' && Gen.g_nam_p[1] == '/') {
5061 Gen.g_nam_p += 2;
5062 while (*Gen.g_nam_p == '/')
5063 Gen.g_nam_p++;
5067 * Skip any trailing slashes
5069 chop_endslashes(Gen.g_nam_p);
5072 * Figure out parent directory
5075 if (Gen.g_attrnam_p != NULL) {
5076 if (Gen.g_dirfd != -1) {
5077 (void) close(Gen.g_dirfd);
5079 Gen.g_dirfd = attropen(Gen.g_attrfnam_p, ".", O_RDONLY);
5080 if (Gen.g_dirfd == -1) {
5081 msg(ERRN,
5082 "Cannot open attribute directory"
5083 " of file %s", Gen.g_attrfnam_p);
5084 continue;
5086 } else {
5087 #ifdef O_XATTR
5088 char dirpath[PATH_MAX];
5090 get_parent(Gen.g_nam_p, dirpath);
5091 if (Atflag || SysAtflag) {
5092 dir = dirpath;
5093 if (Gen.g_dirfd != -1) {
5094 (void) close(Gen.g_dirfd);
5096 Gen.g_dirfd = open(dir, O_RDONLY);
5097 if (Gen.g_dirfd == -1) {
5098 msg(ERRN,
5099 "Cannot open directory %s", dir);
5100 continue;
5102 } else {
5104 * g_dirpath is the pathname cache maintaining
5105 * the dirname which is currently opened.
5106 * We first check the g_dirpath to see if the
5107 * given dirname matches. If so, we don't need
5108 * to open the dir, but we can use the g_dirfd
5109 * as is if it is still available.
5111 dir = NULL;
5112 if (Gen.g_dirpath == NULL ||
5113 Gen.g_dirfd == -1) {
5115 * It's the first time or it has
5116 * all gone.
5118 dir = e_strdup(E_EXIT, dirpath);
5119 } else {
5120 if (strcmp(Gen.g_dirpath,
5121 dirpath) != 0) {
5122 /* different directory */
5123 dir = e_strdup(E_EXIT, dirpath);
5126 if (dir != NULL) {
5128 * We need to open the new directory.
5129 * discard the pathname and dirfd
5130 * for the previous directory.
5132 if (Gen.g_dirpath != NULL) {
5133 free(Gen.g_dirpath);
5134 Gen.g_dirpath = NULL;
5136 if (Gen.g_dirfd != -1) {
5137 (void) close(Gen.g_dirfd);
5139 /* open the new dir */
5140 Gen.g_dirfd = open(dir, O_RDONLY);
5141 if (Gen.g_dirfd == -1) {
5142 msg(ERRN, "Cannot open "
5143 "directory %s", dir);
5144 continue;
5146 Gen.g_dirpath = dir;
5149 #else
5150 Gen.g_dirfd = -1;
5151 #endif
5154 /* creat_hdr checks for USTAR filename length */
5156 if (Hdr_type != USTAR && strlen(Gen.g_nam_p) >
5157 Max_namesz) {
5158 if (!err) {
5159 msg(ERR, "%s%s%s name too long.",
5160 (Gen.g_attrnam_p == NULL) ?
5161 Nam_p : Gen.g_attrfnam_p,
5162 (Gen.g_attrnam_p == NULL) ?
5163 "" : Gen.g_rw_sysattr ?
5164 gettext(" System Attribute ") :
5165 gettext(" Attribute "),
5166 (Gen.g_attrnam_p == NULL) ?
5167 "" : Gen.g_attrnam_p);
5169 goodfile = 0;
5170 err = 1;
5173 if (err) {
5174 continue;
5175 } else {
5176 G_p = &Gen;
5177 if (!LSTAT(Gen.g_dirfd, Gen.g_nam_p, &SrcSt)) {
5178 goodfile = 1;
5180 if ((SrcSt.st_mode & Ftype) == S_IFLNK) {
5181 issymlink = 1;
5183 if ((Args & OCL)) {
5184 errno = 0;
5185 if (STAT(Gen.g_dirfd,
5186 G_p->g_nam_p,
5187 &SrcSt) < 0) {
5188 msg(ERRN,
5189 "Cannot follow"
5190 " \"%s%s%s\"",
5191 (Gen.g_attrnam_p ==
5192 NULL) ?
5193 Gen.g_nam_p :
5194 Gen.g_attrfnam_p,
5195 (Gen.g_attrnam_p ==
5196 NULL) ? "" :
5197 Gen.g_rw_sysattr ?
5198 gettext(
5199 " System "
5200 "Attribute ") :
5201 gettext(
5202 " Attribute "),
5203 (Gen.g_attrnam_p ==
5204 NULL) ? "" :
5205 Gen.g_attrnam_p);
5206 goodfile = 0;
5211 if (Use_old_stat) {
5212 OldSt = convert_to_old_stat(&SrcSt,
5213 Gen.g_nam_p, Gen.g_attrnam_p);
5215 if (OldSt == NULL) {
5216 goodfile = 0;
5219 } else {
5220 msg(ERRN,
5221 "Error with fstatat() of \"%s%s%s\"",
5222 (Gen.g_attrnam_p == NULL) ?
5223 Gen.g_nam_p : Gen.g_attrfnam_p,
5224 (Gen.g_attrnam_p == NULL) ? "" :
5225 Gen.g_rw_sysattr ?
5226 gettext(" System Attribute ") :
5227 gettext(" Attribute "),
5228 (Gen.g_attrnam_p == NULL) ?
5229 "" : Gen.g_attrnam_p);
5235 * Get ACL info: dont bother allocating space if there are only
5236 * standard permissions, i.e. ACL count < 4
5238 if ((SrcSt.st_mode & Ftype) != S_IFLNK && Pflag) {
5239 if (acl_get(Gen.g_nam_p, ACL_NO_TRIVIAL, &aclp) != 0)
5240 msg(ERRN, "Error with acl() of \"%s\"", Gen.g_nam_p);
5242 /* else: only traditional permissions, so proceed as usual */
5243 if (creat_hdr())
5244 return (1);
5245 else return (2);
5249 * getpats: Save any filenames/patterns specified as arguments.
5250 * Read additional filenames/patterns from the file specified by the
5251 * user. The filenames/patterns must occur one per line.
5254 static void
5255 getpats(int largc, char **largv)
5257 char **t_pp;
5258 size_t len;
5259 unsigned numpat = largc, maxpat = largc + 2;
5261 Pat_pp = e_zalloc(E_EXIT, maxpat * sizeof (char *));
5262 t_pp = Pat_pp;
5263 while (*largv) {
5264 *t_pp = e_zalloc(E_EXIT, strlen(*largv) + 1);
5265 (void) strcpy(*t_pp, *largv);
5266 t_pp++;
5267 largv++;
5269 while (fgets(Nam_p, Max_namesz + 1, Ef_p) != NULL) {
5270 if (numpat == maxpat - 1) {
5271 maxpat += 10;
5272 Pat_pp = e_realloc(E_EXIT, Pat_pp,
5273 maxpat * sizeof (char *));
5274 t_pp = Pat_pp + numpat;
5276 len = strlen(Nam_p); /* includes the \n */
5277 *(Nam_p + len - 1) = '\0'; /* remove the \n */
5278 *t_pp = e_zalloc(E_EXIT, len);
5279 (void) strcpy(*t_pp, Nam_p);
5280 t_pp++;
5281 numpat++;
5283 *t_pp = NULL;
5286 static void
5287 ioerror(int dir)
5289 int t_errno;
5291 t_errno = errno;
5292 errno = 0;
5293 if (fstat(Archive, &ArchSt) < 0)
5294 msg(EXTN, "Error during stat() of archive");
5295 errno = t_errno;
5296 if ((ArchSt.st_mode & Ftype) != S_IFCHR) {
5297 if (dir) {
5298 if (errno == EFBIG)
5299 msg(EXT, "ulimit reached for output file.");
5300 else if (errno == ENOSPC)
5301 msg(EXT, "No space left for output file.");
5302 else
5303 msg(EXTN, "I/O error - cannot continue");
5304 } else
5305 msg(EXT, "Unexpected end-of-file encountered.");
5306 } else
5307 msg(EXTN, "\007I/O error on \"%s\"", dir ? "output" : "input");
5311 * matched: Determine if a filename matches the specified pattern(s). If the
5312 * pattern is matched (the second return), return 0 if -f was specified, else
5313 * return != 0. If the pattern is not matched (the first and third
5314 * returns), return 0 if -f was not specified, else return != 0.
5317 static int
5318 matched(void)
5320 char *str_p = G_p->g_nam_p;
5321 char **pat_pp = Pat_pp;
5322 int negatep, result;
5325 * Check for attribute
5327 if (G_p->g_attrfnam_p != NULL)
5328 str_p = G_p->g_attrfnam_p;
5330 for (pat_pp = Pat_pp; *pat_pp; pat_pp++) {
5331 negatep = (**pat_pp == '!');
5333 result = fnmatch(negatep ? (*pat_pp+1) : *pat_pp, str_p, 0);
5335 if (result != 0 && result != FNM_NOMATCH) {
5336 msg(POST, "error matching file %s with pattern"
5337 " %s\n", str_p, *pat_pp);
5338 return (Args & OCf);
5341 if ((result == 0 && ! negatep) ||
5342 (result == FNM_NOMATCH && negatep)) {
5343 /* match occurred */
5344 return (!(Args & OCf));
5347 return (Args & OCf); /* not matched */
5351 * missdir: Create missing directories for files.
5352 * (Possible future performance enhancement, if missdir is called, we know
5353 * that at least the very last directory of the path does not exist, therefore,
5354 * scan the path from the end
5357 static int
5358 missdir(char *nam_p)
5360 char *c_p;
5361 int cnt = 2;
5362 char *lastp;
5364 if (*(c_p = nam_p) == '/') /* skip over 'root slash' */
5365 c_p++;
5367 lastp = c_p + strlen(nam_p) - 1;
5368 if (*lastp == '/')
5369 *lastp = '\0';
5371 for (; *c_p; ++c_p) {
5372 if (*c_p == '/') {
5373 *c_p = '\0';
5374 if (stat(nam_p, &DesSt) < 0) {
5375 if (Args & OCd) {
5376 cnt = mkdir(nam_p, Def_mode);
5377 if (cnt != 0) {
5378 *c_p = '/';
5379 return (cnt);
5381 } else {
5382 msg(ERR, "Missing -d option.");
5383 *c_p = '/';
5384 return (-1);
5387 *c_p = '/';
5390 if (cnt == 2) /* the file already exists */
5391 cnt = 0;
5392 return (cnt);
5396 * mklong: Convert two shorts into one long. For VAX, Interdata ...
5399 static long
5400 mklong(short v[])
5403 union swpbuf swp_b;
5405 swp_b.s_word = 1;
5406 if (swp_b.s_byte[0]) {
5407 swp_b.s_half[0] = v[1];
5408 swp_b.s_half[1] = v[0];
5409 } else {
5410 swp_b.s_half[0] = v[0];
5411 swp_b.s_half[1] = v[1];
5413 return (swp_b.s_word);
5417 * mkshort: Convert a long into 2 shorts, for VAX, Interdata ...
5420 static void
5421 mkshort(short sval[], long v)
5423 union swpbuf *swp_p, swp_b;
5425 /* LINTED alignment */
5426 swp_p = (union swpbuf *)sval;
5427 swp_b.s_word = 1;
5428 if (swp_b.s_byte[0]) {
5429 swp_b.s_word = v;
5430 swp_p->s_half[0] = swp_b.s_half[1];
5431 swp_p->s_half[1] = swp_b.s_half[0];
5432 } else {
5433 swp_b.s_word = v;
5434 swp_p->s_half[0] = swp_b.s_half[0];
5435 swp_p->s_half[1] = swp_b.s_half[1];
5440 * msg: Print either a message (no error) (POST), an error message with or
5441 * without the errno (ERRN or ERR), or print an error message with or without
5442 * the errno and exit (EXTN or EXT).
5444 void
5445 msg(int severity, const char *fmt, ...)
5447 FILE *file_p;
5448 va_list ap;
5450 if ((Args & OCV) && Verbcnt) { /* clear current line of dots */
5451 (void) fputc('\n', Out_p);
5452 Verbcnt = 0;
5454 va_start(ap, fmt);
5455 if (severity == POST)
5456 file_p = Out_p;
5457 else
5458 if (severity == EPOST)
5459 file_p = Err_p;
5460 else {
5461 file_p = Err_p;
5462 Error_cnt++;
5464 (void) fflush(Out_p);
5465 (void) fflush(Err_p);
5466 if ((severity != POST) && (severity != EPOST))
5467 (void) fprintf(file_p, "cpio: ");
5469 /* gettext replaces version of string */
5471 (void) vfprintf(file_p, gettext(fmt), ap);
5472 if (severity == ERRN || severity == EXTN) {
5473 if (G_p && (G_p->g_attrnam_p != NULL) && G_p->g_rw_sysattr) {
5474 if (errno == EPERM) {
5475 (void) fprintf(file_p, ", errno %d, %s", errno,
5476 gettext("insufficient privileges\n"));
5477 } else if (errno == EINVAL) {
5478 (void) fprintf(file_p, ", errno %d, %s",
5479 errno, gettext(
5480 "unsupported on underlying file system\n"));
5481 } else {
5482 (void) fprintf(file_p, ", errno %d, ", errno);
5483 perror("");
5485 } else {
5486 (void) fprintf(file_p, ", errno %d, ", errno);
5487 perror("");
5489 } else
5490 (void) fprintf(file_p, "\n");
5491 (void) fflush(file_p);
5492 va_end(ap);
5493 if (severity == EXT || severity == EXTN) {
5494 (void) fprintf(file_p, gettext("%d errors\n"), Error_cnt);
5495 exit(EXIT_CODE);
5500 * openout: Open files for output and set all necessary information.
5501 * If the u option is set (unconditionally overwrite existing files),
5502 * and the current file exists, get a temporary file name from mktemp(3C),
5503 * link the temporary file to the existing file, and remove the existing file.
5504 * Finally either creat(2), mkdir(2) or mknod(2) as appropriate.
5508 static int
5509 openout(int dirfd)
5511 char *nam_p;
5512 int cnt, result;
5514 Do_rename = 0; /* creat_tmp() may reset this */
5516 if (G_p->g_attrnam_p != NULL) {
5517 nam_p = G_p->g_attrnam_p;
5518 } else {
5519 if (Args & OCp) {
5520 nam_p = Fullnam_p;
5521 } else {
5522 nam_p = G_p->g_nam_p;
5527 if ((Max_filesz != RLIM_INFINITY) &&
5528 (Max_filesz < (G_p->g_filesz >> 9))) {
5529 /* ... divided by 512 ... */
5530 msg(ERR, "Skipping \"%s%s%s\": exceeds ulimit by %lld bytes",
5531 (G_p->g_attrnam_p == NULL) ? nam_p : G_p->g_attrfnam_p,
5532 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
5533 gettext(" System Attribute ") : gettext(" Attribute "),
5534 (G_p->g_attrnam_p == NULL) ? "" : nam_p,
5535 (off_t)(G_p->g_filesz - (Max_filesz << 9)));
5536 return (-1);
5539 if (LSTAT(dirfd, nam_p, &DesSt) == 0) {
5541 * A file by the same name exists. Move it to a temporary
5542 * file unless it's a system attribute file. If we are
5543 * restoring a system attribute file on a file system that
5544 * supports system attributes, then the system attribute file
5545 * will already exist (a default system attribute file will
5546 * get created when the file it is associated with is created).
5547 * If we create a temporary system attribute file, we can't
5548 * overwrite the existing system attribute file using
5549 * renameat(). In addition, only system attributes can exist
5550 * for an attribute of a file, therefore, a temporary file
5551 * cannot be created for a system attribute of an attribute.
5552 * Thus, when restoring a system attribute, we won't move it
5553 * to a temporary file, but will attempt to process it as if
5554 * it didn't already exist.
5557 #if defined(_PC_SATTR_ENABLED)
5558 if (G_p->g_rw_sysattr == 0)
5559 #endif /* _PC_SATTR_ENABLED */
5560 if (creat_tmp(nam_p) < 0) {
5562 * We weren't able to create the temp file.
5563 * Report failure.
5566 return (-1);
5570 if (Do_rename) {
5571 /* nam_p was changed by creat_tmp() above. */
5573 if (Args & OCp) {
5574 if (G_p->g_attrnam_p != NULL) {
5575 nam_p = Attrfile_p;
5576 } else {
5577 nam_p = Fullnam_p;
5579 } else {
5580 nam_p = G_p->g_nam_p;
5585 * This pile tries to create the file directly, and, if there is a
5586 * problem, creates missing directories, and then tries to create the
5587 * file again. Two strikes and you're out.
5589 * On XATTR system, the directory has already been created by
5590 * open_dirfd(), so error shouldn't happen in the loop. However,
5591 * on non-XATTR system, symlink/open may fail with ENOENT. In such
5592 * case, we go to create missing directories.
5595 cnt = 0;
5597 do {
5598 errno = 0;
5600 if (Hdr_type == TAR && Thdr_p->tbuf.t_typeflag == SYMTYPE) {
5601 /* The archive file is a TAR symlink. */
5602 if ((result =
5603 symlink(Thdr_p->tbuf.t_linkname, nam_p)) >= 0) {
5604 cnt = 0;
5605 if (Over_p != NULL) {
5606 (void) unlinkat(dirfd,
5607 get_component(Over_p), 0);
5608 *Over_p = '\0';
5610 break;
5611 } else if (errno != ENOENT) {
5612 /* The attempt to symlink failed. */
5613 msg(ERRN,
5614 "Cannot create symbolic link \"%s\" -> "
5615 "\"%s\"",
5616 Thdr_p->tbuf.t_linkname, nam_p);
5618 if (*Over_p != '\0') {
5619 rstfiles(U_KEEP, dirfd);
5621 return (-1);
5623 } else if (Hdr_type == BAR && bar_linkflag == SYMTYPE) {
5624 if ((result = symlink(bar_linkname, nam_p)) >= 0) {
5625 cnt = 0;
5626 if (Over_p != NULL) {
5627 (void) unlinkat(dirfd,
5628 get_component(Over_p), 0);
5629 *Over_p = '\0';
5631 break;
5632 } else if (errno != ENOENT) {
5633 /* The attempt to symlink failed. */
5634 msg(ERRN,
5635 "Cannot create symbolic link \"%s\" -> "
5636 "\"%s\"",
5637 bar_linkname, nam_p);
5638 if (*Over_p != '\0') {
5639 rstfiles(U_KEEP, dirfd);
5641 return (-1);
5643 } else if ((G_p->g_mode & Ftype) == S_IFLNK) {
5644 if ((!(Args & OCp)) && !(Hdr_type == USTAR)) {
5645 FILL(G_p->g_filesz);
5646 (void) strncpy(Symlnk_p,
5647 Buffr.b_out_p, G_p->g_filesz);
5648 *(Symlnk_p + G_p->g_filesz) = '\0';
5649 } else if ((!(Args & OCp)) && (Hdr_type == USTAR)) {
5650 Symlnk_p[NAMSIZ] = '\0';
5651 (void) strncpy(Symlnk_p,
5652 &Thdr_p->tbuf.t_linkname[0], NAMSIZ);
5654 if ((result = symlink(Symlnk_p, nam_p)) >= 0) {
5655 cnt = 0;
5656 if (Over_p != NULL) {
5657 (void) unlinkat(dirfd,
5658 get_component(Over_p), 0);
5659 *Over_p = '\0';
5661 break;
5662 } else if (errno != ENOENT) {
5663 /* The attempt to symlink failed. */
5664 msg(ERRN,
5665 "Cannot create symbolic link \"%s\" -> "
5666 "\"%s\"",
5667 Symlnk_p, nam_p);
5669 if (*Over_p != '\0') {
5670 rstfiles(U_KEEP, dirfd);
5672 return (-1);
5674 } else {
5675 int saveerrno;
5677 if ((result = openat(dirfd, get_component(nam_p),
5678 O_CREAT|O_RDWR|O_TRUNC, (int)G_p->g_mode)) < 0) {
5679 saveerrno = errno;
5680 if (G_p->g_attrnam_p != NULL) {
5681 result = retry_open_attr(dirfd,
5682 Gen.g_baseparent_fd, Fullnam_p,
5683 (G_p->g_attrparent_p == NULL) ?
5684 NULL : G_p->g_attrparent_p, nam_p,
5685 O_CREAT|O_RDWR|O_TRUNC,
5686 (int)G_p->g_mode);
5689 if (result < 0) {
5690 errno = saveerrno;
5691 if (errno != ENOENT) {
5692 /* The attempt to open failed. */
5693 msg(ERRN, "Cannot open file \"%s\"",
5694 nam_p);
5695 if (*Over_p != '\0') {
5696 rstfiles(U_KEEP, dirfd);
5698 return (-1);
5700 } else {
5701 /* acl support */
5702 acl_is_set = 0;
5703 if (Pflag && aclp != NULL) {
5704 if (facl_set(result, aclp) < 0) {
5705 msg(ERRN,
5706 "\"%s\": failed to set acl",
5707 nam_p);
5708 } else {
5709 acl_is_set = 1;
5711 acl_free(aclp);
5712 aclp = NULL;
5714 cnt = 0;
5715 break;
5718 cnt++;
5719 } while (cnt < 2 && missdir(nam_p) == 0);
5721 switch (cnt) {
5722 case 0:
5723 if ((Args & OCi) && (Hdr_type == USTAR)) {
5724 setpasswd(nam_p);
5726 if ((G_p->g_mode & Ftype) == S_IFLNK ||
5727 (Hdr_type == BAR && bar_linkflag == SYMTYPE)) {
5728 if (Args & OCR) {
5729 if (fchownat(dirfd,
5730 get_component(nam_p),
5731 (int)Rpw_p->pw_uid,
5732 (int)Rpw_p->pw_gid,
5733 AT_SYMLINK_NOFOLLOW) < 0) {
5734 msg(ERRN,
5735 "Error during chown() of "
5736 "\"%s%s%s\"",
5737 (G_p->g_attrnam_p == NULL) ?
5738 nam_p : G_p->g_attrfnam_p,
5739 (G_p->g_attrnam_p == NULL) ?
5740 "" : G_p->g_rw_sysattr ?
5741 gettext(" System Attribute ") :
5742 gettext(" Attribute "),
5743 (G_p->g_attrnam_p == NULL) ?
5744 "" : nam_p);
5746 } else if ((fchownat(dirfd, get_component(nam_p),
5747 (int)G_p->g_uid, (int)G_p->g_gid,
5748 AT_SYMLINK_NOFOLLOW) < 0) && privileged) {
5749 msg(ERRN,
5750 "Error during chown() of \"%s%s%s\"",
5751 (G_p->g_attrnam_p == NULL) ?
5752 nam_p : G_p->g_attrfnam_p,
5753 (G_p->g_attrnam_p == NULL) ? "" :
5754 G_p->g_rw_sysattr ?
5755 gettext(" System Attribute ") :
5756 gettext(" Attribute "),
5757 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
5760 break;
5762 case 1:
5763 if (Do_rename) {
5764 msg(ERRN, "Cannot create directory for \"%s%s%s\"",
5765 (G_p->g_attrnam_p == NULL) ? Over_p :
5766 G_p->g_attrfnam_p,
5767 (G_p->g_attrnam_p == NULL) ? "" :
5768 G_p->g_rw_sysattr ?
5769 gettext(" System Attribute ") :
5770 gettext(" Attribute "),
5771 (G_p->g_attrnam_p == NULL) ? "" : Over_p);
5772 } else {
5773 msg(ERRN, "Cannot create directory for \"%s%s%s\"",
5774 (G_p->g_attrnam_p == NULL) ? nam_p :
5775 G_p->g_attrfnam_p,
5776 (G_p->g_attrnam_p == NULL) ? "" :
5777 G_p->g_rw_sysattr ?
5778 gettext(" System Attribute ") :
5779 gettext(" Attribute "),
5780 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
5782 break;
5784 case 2:
5785 if (Do_rename) {
5786 msg(ERRN, "Cannot create \"%s%s%s\"",
5787 (G_p->g_attrnam_p == NULL) ? Over_p :
5788 G_p->g_attrfnam_p,
5789 (G_p->g_attrnam_p == NULL) ? "" :
5790 G_p->g_rw_sysattr ?
5791 gettext(" System Attribute ") :
5792 gettext(" Attribute "),
5793 (G_p->g_attrnam_p == NULL) ? "" :
5794 Over_p);
5795 } else {
5796 msg(ERRN, "Cannot create \"%s%s%s\"",
5797 (G_p->g_attrnam_p == NULL) ? nam_p :
5798 G_p->g_attrfnam_p,
5799 (G_p->g_attrnam_p == NULL) ? "" :
5800 G_p->g_rw_sysattr ?
5801 gettext(" System Attribute ") :
5802 gettext(" Attribute "),
5803 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
5805 break;
5807 default:
5808 msg(EXT, "Impossible case.");
5811 Finished = 0;
5812 return (result);
5816 * read_hdr: Transfer headers from the selected format
5817 * in the archive I/O buffer to the generic structure.
5820 static
5822 read_hdr(int hdr)
5824 int rv = NONE;
5825 major_t maj, rmaj;
5826 minor_t min, rmin;
5827 char tmpnull;
5828 static int bar_read_cnt = 0;
5830 if (hdr != BAR) {
5831 if (Buffr.b_end_p != (Buffr.b_out_p + Hdrsz)) {
5832 tmpnull = *(Buffr.b_out_p + Hdrsz);
5833 *(Buffr.b_out_p + Hdrsz) = '\0';
5837 switch (hdr) {
5838 case BIN:
5839 (void) memcpy(&Hdr, Buffr.b_out_p, HDRSZ);
5840 if (Hdr.h_magic == (short)CMN_BBS) {
5841 swap((char *)&Hdr, HDRSZ);
5843 Gen.g_magic = Hdr.h_magic;
5844 Gen.g_mode = Hdr.h_mode;
5845 Gen.g_uid = Hdr.h_uid;
5846 Gen.g_gid = Hdr.h_gid;
5847 Gen.g_nlink = Hdr.h_nlink;
5848 Gen.g_mtime = mklong(Hdr.h_mtime);
5849 Gen.g_ino = Hdr.h_ino;
5850 Gen.g_dev = Hdr.h_dev;
5851 Gen.g_rdev = Hdr.h_rdev;
5852 Gen.g_cksum = 0L;
5853 Gen.g_filesz = (off_t)mklong(Hdr.h_filesize);
5854 Gen.g_namesz = Hdr.h_namesize;
5855 rv = BIN;
5856 break;
5857 case CHR:
5858 if (sscanf(Buffr.b_out_p,
5859 "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6o%11llo",
5860 &Gen.g_magic, &Gen.g_dev, &Gen.g_ino, &Gen.g_mode,
5861 &Gen.g_uid, &Gen.g_gid, &Gen.g_nlink, &Gen.g_rdev,
5862 (ulong_t *)&Gen.g_mtime, (uint_t *)&Gen.g_namesz,
5863 (u_off_t *)&Gen.g_filesz) == CHR_CNT) {
5864 rv = CHR;
5865 #define cpioMAJOR(x) (int)(((unsigned)x >> 8) & 0x7F)
5866 #define cpioMINOR(x) (int)(x & 0xFF)
5867 maj = cpioMAJOR(Gen.g_dev);
5868 rmaj = cpioMAJOR(Gen.g_rdev);
5869 min = cpioMINOR(Gen.g_dev);
5870 rmin = cpioMINOR(Gen.g_rdev);
5871 if (Use_old_stat) {
5872 /* needs error checking */
5873 Gen.g_dev = (maj << 8) | min;
5874 Gen.g_rdev = (rmaj << 8) | rmin;
5875 } else {
5876 Gen.g_dev = makedev(maj, min);
5877 Gen.g_rdev = makedev(rmaj, rmin);
5880 break;
5881 case ASC:
5882 case CRC:
5883 if (sscanf(Buffr.b_out_p,
5884 "%6lx%8lx%8lx%8lx%8lx%8lx%8lx%8llx%8x%8x%8x%8x%8x%8lx",
5885 &Gen.g_magic, &Gen.g_ino, &Gen.g_mode, &Gen.g_uid,
5886 &Gen.g_gid, &Gen.g_nlink, &Gen.g_mtime,
5887 (u_off_t *)&Gen.g_filesz, (uint_t *)&maj, (uint_t *)&min,
5888 (uint_t *)&rmaj, (uint_t *)&rmin, (uint_t *)&Gen.g_namesz,
5889 &Gen.g_cksum) == ASC_CNT) {
5890 Gen.g_dev = makedev(maj, min);
5891 Gen.g_rdev = makedev(rmaj, rmin);
5892 rv = hdr;
5894 break;
5895 case USTAR: /* TAR and USTAR */
5896 if (*Buffr.b_out_p == '\0') {
5897 *Gen.g_nam_p = '\0';
5898 nambuf[0] = '\0';
5899 } else {
5900 Thdr_p = (union tblock *)Buffr.b_out_p;
5901 Gen.g_nam_p[0] = '\0';
5902 (void) strncpy((char *)&nambuf,
5903 Thdr_p->tbuf.t_name, NAMSIZ);
5904 (void) sscanf(Thdr_p->tbuf.t_mode, "%8lo",
5905 &Gen.g_mode);
5906 (void) sscanf(Thdr_p->tbuf.t_uid, "%8lo", &Gen.g_uid);
5907 (void) sscanf(Thdr_p->tbuf.t_gid, "%8lo", &Gen.g_gid);
5908 (void) sscanf(Thdr_p->tbuf.t_size, "%11llo",
5909 (u_off_t *)&Gen.g_filesz);
5910 (void) sscanf(Thdr_p->tbuf.t_mtime, "%12lo",
5911 (ulong_t *)&Gen.g_mtime);
5912 (void) sscanf(Thdr_p->tbuf.t_cksum, "%8lo",
5913 (ulong_t *)&Gen.g_cksum);
5914 if (Thdr_p->tbuf.t_linkname[0] != '\0')
5915 Gen.g_nlink = 1;
5916 else
5917 Gen.g_nlink = 0;
5919 switch (Thdr_p->tbuf.t_typeflag) {
5920 case SYMTYPE:
5921 /* Symbolic Link */
5922 Gen.g_nlink = 2;
5923 break;
5924 case CHRTYPE:
5925 Gen.g_mode |= (S_IFMT & S_IFCHR);
5926 break;
5927 case BLKTYPE:
5928 Gen.g_mode |= (S_IFMT & S_IFBLK);
5929 break;
5930 case DIRTYPE:
5931 Gen.g_mode |= (S_IFMT & S_IFDIR);
5932 break;
5933 case FIFOTYPE:
5934 Gen.g_mode |= (S_IFMT & S_IFIFO);
5935 break;
5938 (void) sscanf(Thdr_p->tbuf.t_magic, "%8lo",
5939 /* LINTED alignment */
5940 (ulong_t *)&Gen.g_tmagic);
5941 (void) sscanf(Thdr_p->tbuf.t_version, "%8lo",
5942 /* LINTED alignment */
5943 (ulong_t *)&Gen.g_version);
5944 (void) sscanf(Thdr_p->tbuf.t_uname, "%32s",
5945 (char *)&Gen.g_uname);
5946 (void) sscanf(Thdr_p->tbuf.t_gname, "%32s",
5947 (char *)&Gen.g_gname);
5948 (void) sscanf(Thdr_p->tbuf.t_devmajor, "%8lo",
5949 &Gen.g_dev);
5950 (void) sscanf(Thdr_p->tbuf.t_devminor, "%8lo",
5951 &Gen.g_rdev);
5952 (void) strncpy((char *)&prebuf,
5953 Thdr_p->tbuf.t_prefix, PRESIZ);
5954 Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
5955 Gen.g_dev = makedev(maj, min);
5957 rv = USTAR;
5958 break;
5959 case TAR:
5960 if (*Buffr.b_out_p == '\0') {
5961 *Gen.g_nam_p = '\0';
5962 nambuf[0] = '\0';
5963 } else {
5964 Thdr_p = (union tblock *)Buffr.b_out_p;
5965 Gen.g_nam_p[0] = '\0';
5966 (void) sscanf(Thdr_p->tbuf.t_mode, "%lo", &Gen.g_mode);
5967 (void) sscanf(Thdr_p->tbuf.t_uid, "%lo", &Gen.g_uid);
5968 (void) sscanf(Thdr_p->tbuf.t_gid, "%lo", &Gen.g_gid);
5969 (void) sscanf(Thdr_p->tbuf.t_size, "%llo",
5970 (u_off_t *)&Gen.g_filesz);
5971 (void) sscanf(Thdr_p->tbuf.t_mtime, "%lo",
5972 &Gen.g_mtime);
5973 (void) sscanf(Thdr_p->tbuf.t_cksum, "%lo",
5974 &Gen.g_cksum);
5975 if (Thdr_p->tbuf.t_typeflag == '1') /* hardlink */
5976 Gen.g_nlink = 1;
5977 else
5978 Gen.g_nlink = 0;
5979 (void) strncpy(Gen.g_nam_p,
5980 Thdr_p->tbuf.t_name, NAMSIZ);
5981 Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
5982 (void) strcpy(nambuf, Gen.g_nam_p);
5984 rv = TAR;
5985 break;
5986 case BAR:
5987 if (Bar_vol_num == 0 && bar_read_cnt == 0) {
5988 read_bar_vol_hdr();
5989 bar_read_cnt++;
5991 else
5992 read_bar_file_hdr();
5993 rv = BAR;
5994 break;
5995 default:
5996 msg(EXT, "Impossible header type.");
5999 if (hdr != BAR) {
6000 if (Buffr.b_end_p != (Buffr.b_out_p + Hdrsz))
6001 *(Buffr.b_out_p + Hdrsz) = tmpnull;
6004 return (rv);
6008 * reclaim: Reclaim linked file structure storage.
6011 static void
6012 reclaim(struct Lnk *p)
6014 p->L_bck_p->L_nxt_p = p->L_nxt_p;
6015 p->L_nxt_p->L_bck_p = p->L_bck_p;
6017 while (p != NULL) {
6018 struct Lnk *new_p = p->L_lnk_p;
6020 free(p->L_gen.g_nam_p);
6021 free(p);
6022 p = new_p;
6027 * rstbuf: Reset the I/O buffer, move incomplete potential headers to
6028 * the front of the buffer and force bread() to refill the buffer. The
6029 * return value from bread() is returned (to identify I/O errors). On the
6030 * 3B2, reads must begin on a word boundary, therefore, with the -i option,
6031 * any remaining bytes in the buffer must be moved to the base of the buffer
6032 * in such a way that the destination locations of subsequent reads are
6033 * word aligned.
6036 static void
6037 rstbuf(void)
6039 int pad;
6041 if ((Args & OCi) || Append) {
6042 if (Buffr.b_out_p != Buffr.b_base_p) {
6043 pad = ((Buffr.b_cnt + FULLWD) & ~FULLWD);
6044 Buffr.b_in_p = Buffr.b_base_p + pad;
6045 pad -= Buffr.b_cnt;
6046 (void) memcpy(Buffr.b_base_p + pad, Buffr.b_out_p,
6047 (int)Buffr.b_cnt);
6048 Buffr.b_out_p = Buffr.b_base_p + pad;
6050 if (bfill() < 0)
6051 msg(EXT, "Unexpected end-of-archive encountered.");
6052 } else { /* OCo */
6053 (void) memcpy(Buffr.b_base_p, Buffr.b_out_p, (int)Buffr.b_cnt);
6054 Buffr.b_out_p = Buffr.b_base_p;
6055 Buffr.b_in_p = Buffr.b_base_p + Buffr.b_cnt;
6059 static void
6060 setpasswd(char *nam)
6062 if ((dpasswd = getpwnam(&Gen.g_uname[0])) == NULL) {
6063 msg(EPOST, "cpio: problem reading passwd entry");
6064 msg(EPOST, "cpio: %s: owner not changed", nam);
6065 if (Gen.g_uid == UID_NOBODY && S_ISREG(Gen.g_mode))
6066 Gen.g_mode &= ~S_ISUID;
6067 } else
6068 Gen.g_uid = dpasswd->pw_uid;
6070 if ((dgroup = getgrnam(&Gen.g_gname[0])) == NULL) {
6071 msg(EPOST, "cpio: problem reading group entry");
6072 msg(EPOST, "cpio: %s: group not changed", nam);
6073 if (Gen.g_gid == GID_NOBODY && S_ISREG(Gen.g_mode))
6074 Gen.g_mode &= ~S_ISGID;
6075 } else
6076 Gen.g_gid = dgroup->gr_gid;
6077 G_p = &Gen;
6081 * rstfiles: Perform final changes to the file. If the -u option is set,
6082 * and overwrite == U_OVER, remove the temporary file, else if overwrite
6083 * == U_KEEP, unlink the current file, and restore the existing version
6084 * of the file. In addition, where appropriate, set the access or modification
6085 * times, change the owner and change the modes of the file.
6087 * Note that if Do_rename is set, then the roles of original and temporary
6088 * file are reversed. If all went well, we will rename() the temporary file
6089 * over the original in order to accommodate potentially executing files.
6091 static void
6092 rstfiles(int over, int dirfd)
6094 char *inam_p, *onam_p, *nam_p;
6095 int error;
6097 #if defined(_PC_SATTR_ENABLED)
6098 /* Time or permissions cannot be set on system attribute files */
6099 if ((Gen.g_attrnam_p != NULL) && (Gen.g_rw_sysattr == 1)) {
6100 return;
6102 #endif /* _PC_SATTR_ENABLED */
6104 if (Args & OCp) {
6105 if (G_p->g_attrnam_p == NULL) {
6106 nam_p = Fullnam_p;
6107 } else {
6108 nam_p = G_p->g_attrnam_p;
6110 } else {
6111 if (Gen.g_nlink > (ulong_t)0) {
6112 nam_p = G_p->g_nam_p;
6113 } else {
6114 nam_p = Gen.g_nam_p;
6117 if (Gen.g_attrnam_p != NULL) {
6118 nam_p = Gen.g_attrnam_p;
6121 if ((Args & OCi) && (Hdr_type == USTAR)) {
6122 setpasswd(nam_p);
6124 if (over == U_KEEP && *Over_p != '\0') {
6125 if (Do_rename) {
6126 msg(POST, "Restoring existing \"%s%s%s\"",
6127 (G_p->g_attrnam_p == NULL) ? Over_p : Fullnam_p,
6128 (G_p->g_attrnam_p == NULL) ? "" :
6129 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6130 gettext(" Attribute "),
6131 (G_p->g_attrnam_p == NULL) ? "" : Over_p);
6132 } else {
6133 msg(POST, "Restoring existing \"%s%s%s\"",
6134 (G_p->g_attrnam_p == NULL) ? nam_p : Fullnam_p,
6135 (G_p->g_attrnam_p == NULL) ? "" :
6136 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6137 gettext(" Attribute "),
6138 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
6141 /* delete what we just built */
6142 (void) unlinkat(dirfd, get_component(nam_p), 0);
6144 /* If the old file needs restoring, do the necessary links */
6145 if (Do_rename) {
6146 char *tmp_ptr;
6148 if (Args & OCp) {
6149 tmp_ptr = Fullnam_p;
6150 Fullnam_p = Over_p;
6151 } else {
6152 tmp_ptr = G_p->g_nam_p;
6153 G_p->g_nam_p = Over_p;
6155 Over_p = tmp_ptr;
6157 Do_rename = 0; /* names now have original values */
6158 } else {
6159 if (rename(Over_p, nam_p) < 0) {
6160 if (link(Over_p, nam_p) < 0) {
6161 msg(EXTN,
6162 "Cannot recover original version"
6163 " of \"%s%s%s\"",
6164 (G_p->g_attrnam_p == NULL) ?
6165 nam_p : Fullnam_p,
6166 (G_p->g_attrnam_p == NULL) ? "" :
6167 G_p->g_rw_sysattr ?
6168 gettext(" System Attribute ") :
6169 gettext(" Attribute "),
6170 (G_p->g_attrnam_p == NULL) ?
6171 "" : nam_p);
6173 if (unlinkat(dirfd, get_component(Over_p), 0)) {
6174 msg(ERRN,
6175 "Cannot remove temp file "
6176 "\"%s%s%s\"",
6177 (G_p->g_attrnam_p == NULL) ?
6178 Over_p : Fullnam_p,
6179 (G_p->g_attrnam_p == NULL) ? "" :
6180 G_p->g_rw_sysattr ?
6181 gettext(" System Attribute ") :
6182 gettext(" Attribute "),
6183 (G_p->g_attrnam_p == NULL) ?
6184 "" : Over_p);
6188 *Over_p = '\0';
6189 return;
6190 } else if (over == U_OVER && *Over_p != '\0') {
6191 if (Do_rename) {
6192 char *tmp_ptr;
6194 (void) renameat(dirfd, get_component(nam_p),
6195 dirfd, get_component(Over_p));
6196 if (Args & OCp) {
6197 if (G_p->g_attrnam_p == NULL) {
6198 tmp_ptr = Fullnam_p;
6199 Fullnam_p = Over_p;
6200 Over_p = tmp_ptr;
6201 } else {
6203 * Over_p is pointing at g_attrnam_p
6204 * which must be preserved.
6206 * We don't want the tmp_ptr and so
6207 * on to throw away our only copy of
6208 * the name.
6210 Over_p = Attrfile_p;
6212 } else {
6213 tmp_ptr = G_p->g_nam_p;
6214 G_p->g_nam_p = Over_p;
6215 Over_p = tmp_ptr;
6217 Do_rename = 0; /* names now have original values */
6218 } else {
6219 if (unlinkat(dirfd, get_component(Over_p), 0) < 0) {
6220 msg(ERRN,
6221 "Cannot unlink() temp file \"%s%s%s\"",
6222 (G_p->g_attrnam_p == NULL) ?
6223 Over_p : Fullnam_p,
6224 (G_p->g_attrnam_p == NULL) ? "" :
6225 G_p->g_rw_sysattr ?
6226 gettext(" System Attribute ") :
6227 gettext(" Attribute "),
6228 (G_p->g_attrnam_p == NULL) ? "" : Over_p);
6231 *Over_p = '\0';
6233 if (Args & OCp) {
6234 if (G_p->g_attrnam_p != NULL) {
6235 inam_p = G_p->g_attrfnam_p;
6236 onam_p = G_p->g_attrnam_p;
6237 } else {
6238 inam_p = Nam_p;
6239 onam_p = Fullnam_p;
6241 } else /* OCi only uses onam_p, OCo only uses inam_p */
6242 if (G_p->g_attrnam_p != NULL) {
6243 inam_p = onam_p = G_p->g_attrnam_p;
6244 } else {
6245 inam_p = onam_p = G_p->g_nam_p;
6249 * Change the owner, time, and mode to those of the file
6250 * originally created in the archive. Note: time and
6251 * mode do not need to be restored for a symbolic link
6252 * since rstfiles() is not called when the archived file
6253 * is a symlink.
6255 if (!(Args & OCo)) {
6256 if (Args & OCR) {
6257 if (fchownat(dirfd, get_component(onam_p),
6258 Rpw_p->pw_uid, Rpw_p->pw_gid,
6259 AT_SYMLINK_NOFOLLOW) < 0) {
6260 msg(ERRN, "Cannot chown() \"%s%s%s\"",
6261 onam_p,
6262 (G_p->g_attrnam_p == NULL) ? "" :
6263 G_p->g_rw_sysattr ?
6264 gettext(" System Attribute ") :
6265 gettext(" Attribute "),
6266 (G_p->g_attrnam_p == NULL) ? "" : onam_p);
6268 } else {
6269 if ((fchownat(dirfd, get_component(onam_p),
6270 G_p->g_uid, G_p->g_gid,
6271 AT_SYMLINK_NOFOLLOW) < 0) && privileged) {
6272 msg(ERRN, "Cannot chown() \"%s%s%s\"",
6273 onam_p,
6274 (G_p->g_attrnam_p == NULL) ? "" :
6275 G_p->g_rw_sysattr ?
6276 gettext(" System Attribute ") :
6277 gettext(" Attribute "),
6278 (G_p->g_attrnam_p == NULL) ? "" : onam_p);
6282 if (Args & OCm) {
6283 set_tym(dirfd, get_component(onam_p),
6284 G_p->g_mtime, G_p->g_mtime);
6287 /* Acl was not set, so we must chmod */
6288 if (!acl_is_set) {
6289 mode_t orig_mask, new_mask;
6292 * use fchmod for attributes, since
6293 * we known they are always regular
6294 * files, whereas when it isn't an
6295 * attribute it could be for a fifo
6296 * or something other that we don't
6297 * open and don't have a valid Ofile
6298 * for.
6300 if (privileged) {
6301 new_mask = G_p->g_mode;
6302 } else {
6303 orig_mask = umask(0);
6304 new_mask = G_p->g_mode & ~orig_mask;
6307 if (G_p->g_attrnam_p != NULL) {
6308 error = fchmod(Ofile, new_mask);
6309 } else {
6310 error = chmod(onam_p, new_mask);
6312 if (error < 0) {
6313 msg(ERRN,
6314 "Cannot chmod() \"%s%s%s\"",
6315 (G_p->g_attrnam_p == NULL) ?
6316 onam_p : G_p->g_attrfnam_p,
6317 (G_p->g_attrnam_p == NULL) ? "" :
6318 G_p->g_rw_sysattr ?
6319 gettext(" System Attribute ") :
6320 gettext(" Attribute "),
6321 (G_p->g_attrnam_p == NULL) ? "" : onam_p);
6323 if (!privileged) {
6324 (void) umask(orig_mask);
6329 if (!(Args & OCi) && (Args & OCa)) {
6331 * Use dirfd since we are updating original file
6332 * and not just created file
6334 set_tym(G_p->g_dirfd, get_component(inam_p),
6335 (ulong_t)SrcSt.st_atime, (ulong_t)SrcSt.st_mtime);
6340 * scan4trail: Scan the archive looking for the trailer.
6341 * When found, back the archive up over the trailer and overwrite
6342 * the trailer with the files to be added to the archive.
6345 static void
6346 scan4trail(void)
6348 int rv;
6349 off_t off1, off2;
6351 Append = 1;
6352 Hdr_type = NONE;
6353 G_p = NULL;
6354 while (gethdr()) {
6355 G_p = &Gen;
6356 data_in(P_SKIP);
6358 off1 = Buffr.b_cnt;
6359 off2 = Bufsize - (Buffr.b_cnt % Bufsize);
6360 Buffr.b_out_p = Buffr.b_in_p = Buffr.b_base_p;
6361 Buffr.b_cnt = (off_t)0;
6362 if (lseek(Archive, -(off1 + off2), SEEK_REL) < 0)
6363 msg(EXTN, "Unable to append to this archive");
6364 if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0)
6365 msg(EXTN, "Cannot append to this archive");
6366 if (lseek(Archive, (off_t)-rv, SEEK_REL) < 0)
6367 msg(EXTN, "Unable to append to this archive");
6368 Buffr.b_cnt = off2;
6369 Buffr.b_in_p = Buffr.b_base_p + Buffr.b_cnt;
6370 Append = 0;
6374 * setup: Perform setup and initialization functions. Parse the options
6375 * using getopt(3C), call ckopts to check the options and initialize various
6376 * structures and pointers. Specifically, for the -i option, save any
6377 * patterns, for the -o option, check (via stat(2)) the archive, and for
6378 * the -p option, validate the destination directory.
6381 static void
6382 setup(int largc, char **largv)
6384 extern int optind;
6385 extern char *optarg;
6387 #if defined(O_XATTR)
6388 #if defined(_PC_SATTR_ENABLED)
6389 #ifdef WAITAROUND
6390 char *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
6391 #else
6392 char *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
6393 #endif /* WAITAROUND */
6395 #else /* _PC_SATTR_ENABLED */
6396 #ifdef WAITAROUND
6397 char *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
6398 #else
6399 char *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
6400 #endif /* WAITAROUND */
6401 #endif /* _PC_SATTR_ENABLED */
6403 #else /* O_XATTR */
6404 #ifdef WAITAROUND
6405 char *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
6406 #else
6407 char *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
6408 #endif /* WAITAROUND */
6409 #endif /* O_XATTR */
6411 char *dupl_p = "Only one occurrence of -%c allowed";
6412 int option;
6413 int blk_cnt, blk_cnt_max;
6414 struct rlimit rlim;
6416 /* Remember the native page size. */
6418 PageSize = sysconf(_SC_PAGESIZE);
6420 if (PageSize == -1) {
6422 * This sysconf call will almost certainly never fail. The
6423 * symbol PAGESIZE itself resolves to the above sysconf call,
6424 * so we should go ahead and define our own constant.
6426 PageSize = 8192;
6429 Hdr_type = BIN;
6430 Max_offset = (off_t)(BIN_OFFSET_MAX);
6431 Efil_p = Hdr_p = Own_p = IOfil_p = NULL;
6432 while ((option = getopt(largc, largv, opts_p)) != EOF) {
6433 switch (option) {
6434 #ifdef WAITAROUND
6435 case 'z':
6436 /* rendezvous with the debugger */
6437 waitaround = 1;
6438 break;
6439 #endif
6440 case 'a': /* reset access time */
6441 Args |= OCa;
6442 break;
6443 case 'b': /* swap bytes and halfwords */
6444 Args |= OCb;
6445 break;
6446 case 'c': /* select character header */
6447 Args |= OCc;
6448 Hdr_type = ASC;
6449 Max_namesz = APATH;
6450 Onecopy = 1;
6451 break;
6452 case 'd': /* create directories as needed */
6453 Args |= OCd;
6454 break;
6455 case 'f': /* select files not in patterns */
6456 Args |= OCf;
6457 break;
6458 case 'i': /* "copy in" */
6459 Args |= OCi;
6460 Archive = 0;
6461 break;
6462 case 'k': /* retry after I/O errors */
6463 Args |= OCk;
6464 break;
6465 case 'l': /* link files when possible */
6466 Args |= OCl;
6467 break;
6468 case 'm': /* retain modification time */
6469 Args |= OCm;
6470 break;
6471 case 'o': /* "copy out" */
6472 Args |= OCo;
6473 Archive = 1;
6474 break;
6475 case 'p': /* "pass" */
6476 Max_namesz = APATH;
6477 Args |= OCp;
6478 break;
6479 case 'q': /* "quiet" */
6480 Args |= OCq;
6481 break;
6482 case 'r': /* rename files interactively */
6483 Args |= OCr;
6484 break;
6485 case 's': /* swap bytes */
6486 Args |= OCs;
6487 break;
6488 case 't': /* table of contents */
6489 Args |= OCt;
6490 break;
6491 case 'u': /* copy unconditionally */
6492 Args |= OCu;
6493 break;
6494 case 'v': /* verbose - print file names */
6495 Args |= OCv;
6496 break;
6497 case 'A': /* append to existing archive */
6498 Args |= OCA;
6499 break;
6500 case 'B': /* set block size to 5120 bytes */
6501 Args |= OCB;
6502 Bufsize = 5120;
6503 break;
6504 case 'C': /* set arbitrary block size */
6505 if (Args & OCC)
6506 msg(ERR, dupl_p, 'C');
6507 else {
6508 Args |= OCC;
6509 Bufsize = atoi(optarg);
6511 break;
6512 case 'D':
6513 Dflag = 1;
6514 break;
6515 case 'E': /* alternate file for pattern input */
6516 if (Args & OCE)
6517 msg(ERR, dupl_p, 'E');
6518 else {
6519 Args |= OCE;
6520 Efil_p = optarg;
6522 break;
6523 case 'H': /* select header type */
6524 if (Args & OCH)
6525 msg(ERR, dupl_p, 'H');
6526 else {
6527 Args |= OCH;
6528 Hdr_p = optarg;
6530 break;
6531 case 'I': /* alternate file for archive input */
6532 if (Args & OCI)
6533 msg(ERR, dupl_p, 'I');
6534 else {
6535 Args |= OCI;
6536 IOfil_p = optarg;
6538 break;
6539 case 'L': /* follow symbolic links */
6540 Args |= OCL;
6541 break;
6542 case 'M': /* specify new end-of-media message */
6543 if (Args & OCM)
6544 msg(ERR, dupl_p, 'M');
6545 else {
6546 Args |= OCM;
6547 Eom_p = optarg;
6549 break;
6550 case 'O': /* alternate file for archive output */
6551 if (Args & OCO)
6552 msg(ERR, dupl_p, 'O');
6553 else {
6554 Args |= OCO;
6555 IOfil_p = optarg;
6557 break;
6558 case 'P': /* preserve acls */
6559 Args |= OCP;
6560 Pflag++;
6561 break;
6562 case 'R': /* change owner/group of files */
6563 if (Args & OCR)
6564 msg(ERR, dupl_p, 'R');
6565 else {
6566 Args |= OCR;
6567 Own_p = optarg;
6569 break;
6570 case 'S': /* swap halfwords */
6571 Args |= OCS;
6572 break;
6573 case 'V': /* print a dot '.' for each file */
6574 Args |= OCV;
6575 break;
6576 case '6': /* for old, sixth-edition files */
6577 Args |= OC6;
6578 Ftype = SIXTH;
6579 break;
6580 #if defined(O_XATTR)
6581 case '@':
6582 Atflag++;
6583 break;
6584 #if defined(_PC_SATTR_ENABLED)
6585 case '/':
6586 SysAtflag++;
6587 break;
6588 #endif /* _PC_SATTR_ENABLED */
6589 #endif /* O_XATTR */
6590 default:
6591 Error_cnt++;
6592 } /* option */
6593 } /* (option = getopt(largc, largv, opts_p)) != EOF */
6595 #ifdef WAITAROUND
6596 if (waitaround) {
6597 (void) fprintf(stderr, gettext("Rendezvous with cpio on pid"
6598 " %d\n"), getpid());
6600 while (waitaround) {
6601 (void) sleep(10);
6604 #endif
6606 largc -= optind;
6607 largv += optind;
6608 ckopts(Args);
6609 if (!Error_cnt) {
6610 if (Args & OCr) {
6611 Renam_p = e_zalloc(E_EXIT, APATH + 1);
6612 Renametmp_p = e_zalloc(E_EXIT, APATH + 1);
6613 #if defined(_PC_SATTR_ENABLED)
6614 Renam_attr_p = e_zalloc(E_EXIT, APATH + 1);
6615 #endif
6617 Symlnk_p = e_zalloc(E_EXIT, APATH);
6618 Over_p = e_zalloc(E_EXIT, APATH);
6619 Nam_p = e_zalloc(E_EXIT, APATH + 1);
6620 if (Args & OCp) {
6621 Savenam_p = e_zalloc(E_EXIT, APATH + 1);
6623 Fullnam_p = e_zalloc(E_EXIT, APATH);
6624 Lnknam_p = e_zalloc(E_EXIT, APATH);
6625 Gen.g_nam_p = Nam_p;
6626 if ((Fullnam_p = getcwd(NULL, APATH)) == NULL)
6627 msg(EXT, "Unable to determine current directory.");
6628 if (Args & OCi) {
6629 if (largc > 0) /* save patterns for -i option, if any */
6630 Pat_pp = largv;
6631 if (Args & OCE)
6632 getpats(largc, largv);
6633 } else if (Args & OCo) {
6634 if (largc != 0) /* error if arguments left with -o */
6635 Error_cnt++;
6636 else if (fstat(Archive, &ArchSt) < 0)
6637 msg(ERRN, "Error during stat() of archive");
6638 switch (Hdr_type) {
6639 case BIN:
6640 Hdrsz = HDRSZ;
6641 Pad_val = HALFWD;
6642 break;
6643 case CHR:
6644 Hdrsz = CHRSZ;
6645 Pad_val = 0;
6646 Max_offset = (off_t)(CHAR_OFFSET_MAX);
6647 break;
6648 case ASC:
6649 case CRC:
6650 Hdrsz = ASCSZ;
6651 Pad_val = FULLWD;
6652 Max_offset = (off_t)(ASC_OFFSET_MAX);
6653 break;
6654 case TAR:
6655 /* FALLTHROUGH */
6656 case USTAR: /* TAR and USTAR */
6657 Hdrsz = TARSZ;
6658 Pad_val = FULLBK;
6659 Max_offset = (off_t)(CHAR_OFFSET_MAX);
6660 break;
6661 default:
6662 msg(EXT, "Impossible header type.");
6664 } else { /* directory must be specified */
6665 if (largc != 1)
6666 Error_cnt++;
6667 else if (access(*largv, 2) < 0 && (errno != EACCES))
6669 * EACCES is ignored here as it may occur
6670 * when any directory component of the path
6671 * does not have write permission, even though
6672 * the destination subdirectory has write
6673 * access. Writing to a read only directory
6674 * is handled later, as in "copy in" mode.
6676 msg(ERRN,
6677 "Error during access() of \"%s\"", *largv);
6680 if (Error_cnt)
6681 usage(); /* exits! */
6682 if (Args & (OCi | OCo)) {
6683 if (!Dflag) {
6684 if (Args & (OCB | OCC)) {
6685 if (g_init(&Device, &Archive) < 0)
6686 msg(EXTN,
6687 "Error during initialization");
6688 } else {
6689 if ((Bufsize = g_init(&Device, &Archive)) < 0)
6690 msg(EXTN,
6691 "Error during initialization");
6695 blk_cnt_max = _20K / Bufsize;
6696 if (blk_cnt_max < MX_BUFS) {
6697 blk_cnt_max = MX_BUFS;
6700 Buffr.b_base_p = NULL;
6702 for (blk_cnt = blk_cnt_max; blk_cnt > 1; blk_cnt--) {
6703 Buffr.b_size = (size_t)(Bufsize * blk_cnt);
6704 Buffr.b_base_p = e_valloc(E_NORMAL, Buffr.b_size);
6705 if (Buffr.b_base_p != NULL) {
6706 break;
6709 if (Buffr.b_base_p == NULL || Buffr.b_size < (2 * CPIOBSZ)) {
6710 msg(EXT, "Out of memory");
6713 Buffr.b_out_p = Buffr.b_in_p = Buffr.b_base_p;
6714 Buffr.b_cnt = 0L;
6715 Buffr.b_end_p = Buffr.b_base_p + Buffr.b_size;
6719 * Now that Bufsize has stabilized, we can allocate our i/o buffer
6721 Buf_p = e_valloc(E_EXIT, Bufsize);
6723 if (Args & OCp) { /* get destination directory */
6724 (void) strcpy(Fullnam_p, *largv);
6725 if (stat(Fullnam_p, &DesSt) < 0)
6726 msg(EXTN, "Error during stat() of \"%s\"", Fullnam_p);
6727 if ((DesSt.st_mode & Ftype) != S_IFDIR)
6728 msg(EXT, "\"%s\" is not a directory", Fullnam_p);
6730 Full_p = Fullnam_p + strlen(Fullnam_p) - 1;
6731 if (*Full_p != '/') {
6732 Full_p++;
6733 *Full_p = '/';
6735 Full_p++;
6736 *Full_p = '\0';
6737 (void) strcpy(Lnknam_p, Fullnam_p);
6738 Lnkend_p = Lnknam_p + strlen(Lnknam_p);
6739 (void) getrlimit(RLIMIT_FSIZE, &rlim);
6740 Max_filesz = (off_t)rlim.rlim_cur;
6741 Lnk_hd.L_nxt_p = Lnk_hd.L_bck_p = &Lnk_hd;
6742 Lnk_hd.L_lnk_p = NULL;
6746 * set_tym: Set the access and/or modification times for a file.
6749 static void
6750 set_tym(int dirfd, char *nam_p, time_t atime, time_t mtime)
6752 struct timeval times[2];
6754 times[0].tv_sec = atime;
6755 times[0].tv_usec = 0;
6756 times[1].tv_sec = mtime;
6757 times[1].tv_usec = 0;
6759 if (futimesat(dirfd, nam_p, times) < 0) {
6760 if (Args & OCa) {
6761 msg(ERRN,
6762 "Unable to reset access time for \"%s%s%s\"",
6763 (G_p->g_attrnam_p == NULL) ? nam_p : Fullnam_p,
6764 (G_p->g_attrnam_p == NULL) ? "" :
6765 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6766 gettext(" Attribute "),
6767 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
6768 } else {
6769 msg(ERRN,
6770 "Unable to reset modification time for \"%s%s%s\"",
6771 (G_p->g_attrnam_p == NULL) ? nam_p : Fullnam_p,
6772 (G_p->g_attrnam_p == NULL) ? "" :
6773 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6774 gettext(" Attribute "),
6775 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
6781 * sigint: Catch interrupts. If an interrupt occurs during the extraction
6782 * of a file from the archive with the -u option set, and the filename did
6783 * exist, remove the current file and restore the original file. Then exit.
6786 /*ARGSUSED*/
6787 static void
6788 sigint(int sig)
6790 char *nam_p;
6792 (void) signal(SIGINT, SIG_IGN); /* block further signals */
6793 if (!Finished) {
6794 if (Args & OCi)
6795 nam_p = G_p->g_nam_p;
6796 else /* OCp */
6797 nam_p = Fullnam_p;
6798 if (*Over_p != '\0') { /* There is a temp file */
6799 if (unlink(nam_p) < 0) {
6800 msg(ERRN,
6801 "Cannot remove incomplete \"%s\"", nam_p);
6803 if (rename(Over_p, nam_p) < 0) {
6804 if (link(Over_p, nam_p) < 0) {
6805 msg(ERRN,
6806 "Cannot recover original \"%s\"",
6807 nam_p);
6809 if (unlink(Over_p)) {
6810 msg(ERRN,
6811 "Cannot remove temp file \"%s\"",
6812 Over_p);
6815 } else if (unlink(nam_p))
6816 msg(ERRN, "Cannot remove incomplete \"%s\"", nam_p);
6817 *Over_p = '\0';
6819 exit(EXIT_CODE);
6823 * swap: Swap bytes (-s), halfwords (-S) or or both halfwords and bytes (-b).
6826 static void
6827 swap(char *buf_p, int cnt)
6829 unsigned char tbyte;
6830 int tcnt;
6831 int rcnt;
6832 ushort_t thalf;
6834 rcnt = cnt % 4;
6835 cnt /= 4;
6836 if (Args & (OCb | OCs | BSM)) {
6837 tcnt = cnt;
6838 /* LINTED alignment */
6839 Swp_p = (union swpbuf *)buf_p;
6840 while (tcnt-- > 0) {
6841 tbyte = Swp_p->s_byte[0];
6842 Swp_p->s_byte[0] = Swp_p->s_byte[1];
6843 Swp_p->s_byte[1] = tbyte;
6844 tbyte = Swp_p->s_byte[2];
6845 Swp_p->s_byte[2] = Swp_p->s_byte[3];
6846 Swp_p->s_byte[3] = tbyte;
6847 Swp_p++;
6849 if (rcnt >= 2) {
6850 tbyte = Swp_p->s_byte[0];
6851 Swp_p->s_byte[0] = Swp_p->s_byte[1];
6852 Swp_p->s_byte[1] = tbyte;
6853 tbyte = Swp_p->s_byte[2];
6856 if (Args & (OCb | OCS)) {
6857 tcnt = cnt;
6858 /* LINTED alignment */
6859 Swp_p = (union swpbuf *)buf_p;
6860 while (tcnt-- > 0) {
6861 thalf = Swp_p->s_half[0];
6862 Swp_p->s_half[0] = Swp_p->s_half[1];
6863 Swp_p->s_half[1] = thalf;
6864 Swp_p++;
6870 * usage: Print the usage message on stderr and exit.
6873 static void
6874 usage(void)
6877 (void) fflush(stdout);
6878 #if defined(O_XATTR)
6879 (void) fprintf(stderr, gettext("USAGE:\n"
6880 "\tcpio -i[bcdfkmqrstuv@BSV6] [-C size] "
6881 "[-E file] [-H hdr] [-I file [-M msg]] "
6882 "[-R id] [patterns]\n"
6883 "\tcpio -o[acv@ABLV] [-C size] "
6884 "[-H hdr] [-O file [-M msg]]\n"
6885 "\tcpio -p[adlmuv@LV] [-R id] directory\n"));
6886 #else
6887 (void) fprintf(stderr, gettext("USAGE:\n"
6888 "\tcpio -i[bcdfkmqrstuvBSV6] [-C size] "
6889 "[-E file] [-H hdr] [-I file [-M msg]] "
6890 "[-R id] [patterns]\n"
6891 "\tcpio -o[acvABLV] [-C size] "
6892 "[-H hdr] [-O file [-M msg]]\n"
6893 "\tcpio -p[adlmuvLV] [-R id] directory\n"));
6894 #endif
6895 (void) fflush(stderr);
6896 exit(EXIT_CODE);
6900 * verbose: For each file, print either the filename (-v) or a dot (-V).
6901 * If the -t option (table of contents) is set, print either the filename,
6902 * or if the -v option is also set, print an "ls -l"-like listing.
6905 static void
6906 verbose(char *nam_p)
6908 int i, j, temp;
6909 mode_t mode;
6910 char modestr[12];
6911 time_t ttime;
6914 * The printf format and associated arguments to print the current
6915 * filename. Normally, just nam_p. If we're processing an extended
6916 * attribute, these are overridden.
6918 char *name_fmt = "%s";
6919 const char *name = nam_p;
6920 const char *attribute = NULL;
6922 if (Gen.g_attrnam_p != NULL) {
6924 * Translation note:
6925 * 'attribute' is a noun.
6928 if (Gen.g_rw_sysattr) {
6929 name_fmt = gettext("%s system attribute %s");
6930 } else if ((Args & OCt) &&
6931 (is_sysattr(basename(Gen.g_attrnam_p)))) {
6932 name_fmt = gettext("%s system attribute %s");
6933 } else {
6934 name_fmt = gettext("%s attribute %s");
6937 name = (Args & OCp) ? nam_p : Gen.g_attrfnam_p;
6938 if (Gen.g_attrparent_p == NULL) {
6939 attribute = Gen.g_attrnam_p;
6940 } else {
6941 attribute = Gen.g_attrpath_p;
6945 if ((Gen.g_mode == SECMODE) || ((Hdr_type == USTAR ||
6946 Hdr_type == TAR) && Thdr_p->tbuf.t_typeflag == 'A')) {
6947 /* dont print ancillary file */
6948 aclchar = '+';
6949 return;
6951 for (i = 0; i < 11; i++)
6952 modestr[i] = '-';
6953 modestr[i] = '\0';
6954 modestr[i-1] = aclchar;
6955 aclchar = ' ';
6957 if ((Args & OCt) && (Args & OCv)) {
6958 mode = Gen.g_mode;
6959 for (i = 0; i < 3; i++) {
6960 temp = (mode >> (6 - (i * 3)));
6961 j = (i * 3) + 1;
6962 if (S_IROTH & temp)
6963 modestr[j] = 'r';
6964 if (S_IWOTH & temp)
6965 modestr[j + 1] = 'w';
6966 if (S_IXOTH & temp)
6967 modestr[j + 2] = 'x';
6970 if (Hdr_type != BAR) {
6971 temp = Gen.g_mode & Ftype;
6972 switch (temp) {
6973 case (S_IFIFO):
6974 modestr[0] = 'p';
6975 break;
6976 case (S_IFSOCK):
6977 modestr[0] = 's';
6978 break;
6979 case (S_IFCHR):
6980 modestr[0] = 'c';
6981 break;
6982 case (S_IFDIR):
6983 modestr[0] = 'd';
6984 break;
6985 case (S_IFBLK):
6986 modestr[0] = 'b';
6987 break;
6988 case (S_IFREG): /* was initialized to '-' */
6989 break;
6990 case (S_IFLNK):
6991 modestr[0] = 'l';
6992 break;
6993 default:
6994 msg(ERR, "Impossible file type");
6996 } else { /* bar */
6997 temp = Gen.g_mode & Ftype;
6998 switch (temp) {
6999 case (S_IFIFO):
7000 modestr[0] = 'p';
7001 break;
7002 case (S_IFSOCK):
7003 modestr[0] = 's';
7004 break;
7005 case (S_IFCHR):
7006 modestr[0] = 'c';
7007 break;
7008 case (S_IFDIR):
7009 modestr[0] = 'd';
7010 break;
7011 case (S_IFBLK):
7012 modestr[0] = 'b';
7013 break;
7015 if (bar_linkflag == SYMTYPE)
7016 modestr[0] = 'l';
7018 if ((S_ISUID & Gen.g_mode) == S_ISUID)
7019 modestr[3] = 's';
7020 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
7021 modestr[9] = 't';
7022 if ((S_ISGID & G_p->g_mode) == S_ISGID && modestr[6] == 'x')
7023 modestr[6] = 's';
7024 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
7025 modestr[6] = 'l';
7026 if ((Hdr_type == TAR || Hdr_type == USTAR) && Gen.g_nlink == 0)
7027 (void) printf("%s%4d ", modestr, (int)Gen.g_nlink+1);
7028 else
7029 (void) printf("%s%4d ", modestr, (int)Gen.g_nlink);
7030 if (Lastuid == (uid_t)Gen.g_uid) {
7031 if (Lastuid == (uid_t)-1)
7032 (void) printf("-1 ");
7033 else
7034 (void) printf("%-9s", Curpw_p->pw_name);
7035 } else {
7036 if (Curpw_p = getpwuid((int)Gen.g_uid)) {
7037 (void) printf("%-9s", Curpw_p->pw_name);
7038 Lastuid = (uid_t)Gen.g_uid;
7039 } else {
7040 (void) printf("%-9d", (int)Gen.g_uid);
7041 Lastuid = (uid_t)-1;
7044 if (Lastgid == (gid_t)Gen.g_gid) {
7045 if (Lastgid == (gid_t)-1)
7046 (void) printf("-1 ");
7047 else
7048 (void) printf("%-9s", Curgr_p->gr_name);
7049 } else {
7050 if (Curgr_p = getgrgid((int)Gen.g_gid)) {
7051 (void) printf("%-9s", Curgr_p->gr_name);
7052 Lastgid = (gid_t)Gen.g_gid;
7053 } else {
7054 (void) printf("%-9d", (int)Gen.g_gid);
7055 Lastgid = (gid_t)-1;
7059 /* print file size */
7060 if (!Aspec || ((Gen.g_mode & Ftype) == S_IFIFO) ||
7061 ((Gen.g_mode & Ftype) == S_IFSOCK) ||
7062 (Hdr_type == BAR && bar_linkflag == SYMTYPE)) {
7063 off_t filesz = Gen.g_filesz;
7065 if (S_ISSPARSE(Gen.g_mode) && Gen.g_holes != NULL)
7066 filesz = Gen.g_holes->orig_size;
7068 if (filesz < (1LL << 31))
7069 (void) printf("%7lld ", (offset_t)filesz);
7070 else
7071 (void) printf("%11lld ", (offset_t)filesz);
7072 } else
7073 (void) printf("%3d,%3d ", (int)major(Gen.g_rdev),
7074 (int)minor(Gen.g_rdev));
7075 ttime = Gen.g_mtime;
7076 (void) strftime(Time, sizeof (Time),
7077 dcgettext(NULL, FORMAT, LC_TIME), localtime(&ttime));
7078 (void) printf("%s, ", Time);
7079 str_fprintf(stdout, name_fmt, name, attribute);
7080 if ((Gen.g_mode & Ftype) == S_IFLNK) {
7081 if (Hdr_type == USTAR || Hdr_type == TAR)
7082 (void) strcpy(Symlnk_p,
7083 Thdr_p->tbuf.t_linkname);
7084 else {
7085 FILL(Gen.g_filesz);
7086 (void) strncpy(Symlnk_p, Buffr.b_out_p,
7087 Gen.g_filesz);
7088 *(Symlnk_p + Gen.g_filesz) = '\0';
7090 (void) printf(" -> %s", Symlnk_p);
7092 if (Hdr_type == BAR) {
7093 if (bar_linkflag == SYMTYPE)
7094 (void) printf(gettext(" symbolic link to %s"),
7095 bar_linkname);
7096 else if (bar_linkflag == '1')
7097 (void) printf(gettext(" linked to %s"),
7098 bar_linkname);
7100 if ((Hdr_type == USTAR || Hdr_type == TAR) &&
7101 Thdr_p->tbuf.t_typeflag == '1') {
7102 (void) printf(gettext(" linked to %s%s%s"),
7103 (Gen.g_attrnam_p == NULL) ?
7104 Thdr_p->tbuf.t_linkname : Gen.g_attrfnam_p,
7105 (Gen.g_attrnam_p == NULL) ? "" :
7106 gettext(" attribute "),
7107 (Gen.g_attrnam_p == NULL) ?
7108 "" : Gen.g_linktoattrnam_p);
7110 (void) printf("\n");
7111 } else if ((Args & OCt) || (Args & OCv)) {
7112 str_fprintf(Out_p, name_fmt, name, attribute);
7113 (void) fputc('\n', Out_p);
7114 } else { /* OCV */
7115 (void) fputc('.', Out_p);
7116 if (Verbcnt++ >= 49) { /* start a new line of dots */
7117 Verbcnt = 0;
7118 (void) fputc('\n', Out_p);
7121 (void) fflush(Out_p);
7124 #define MK_USHORT(a) (a & 00000177777)
7127 * write_hdr: Transfer header information for the generic structure
7128 * into the format for the selected header and bwrite() the header.
7131 static void
7132 write_hdr(int arcflag, off_t len)
7134 int cnt, pad;
7135 mode_t mode;
7136 uid_t uid;
7137 gid_t gid;
7138 const char warnfmt[] = "%s%s%s : %s";
7140 switch (arcflag) {
7141 case ARCHIVE_ACL:
7142 mode = SECMODE;
7143 break;
7145 case ARCHIVE_XATTR:
7146 case ARCHIVE_NORMAL:
7148 * If attribute is being archived in cpio format then
7149 * zap off the file type bits since those are truly a
7150 * mask and reset them with _XATTR_CPIO_MODE
7153 * len is the value of g_filesz for normal files
7154 * and the length of the special header buffer in
7155 * the case of acl and xattr headers.
7157 if (G_p->g_attrnam_p != NULL && Hdr_type != USTAR &&
7158 Hdr_type != TAR) {
7159 mode = (G_p->g_mode & POSIXMODES) | _XATTR_CPIO_MODE;
7160 } else {
7161 mode = G_p->g_mode;
7163 if (arcflag != ARCHIVE_XATTR) {
7164 len = G_p->g_filesz;
7166 break;
7168 case ARCHIVE_SPARSE:
7169 mode = G_p->g_mode | C_ISSPARSE;
7170 len = G_p->g_filesz;
7171 break;
7174 uid = G_p->g_uid;
7175 gid = G_p->g_gid;
7177 * Handle EFT uids and gids. If they get too big
7178 * to be represented in a particular format, force 'em to 'nobody'.
7180 switch (Hdr_type) {
7181 case BIN: /* 16-bits of u_short */
7182 if ((ulong_t)uid > (ulong_t)USHRT_MAX)
7183 uid = UID_NOBODY;
7184 if ((ulong_t)gid > (ulong_t)USHRT_MAX)
7185 gid = GID_NOBODY;
7186 break;
7187 case CHR: /* %.6lo => 262143 base 10 */
7188 if ((ulong_t)uid > (ulong_t)0777777)
7189 uid = UID_NOBODY;
7190 if ((ulong_t)gid > (ulong_t)0777777)
7191 gid = GID_NOBODY;
7192 break;
7193 case ASC: /* %.8lx => full 32 bits */
7194 case CRC:
7195 break;
7196 case USTAR:
7197 case TAR: /* %.7lo => 2097151 base 10 */
7198 if ((ulong_t)uid > (ulong_t)07777777)
7199 uid = UID_NOBODY;
7200 if ((ulong_t)gid > (ulong_t)07777777)
7201 gid = GID_NOBODY;
7202 break;
7203 default:
7204 msg(EXT, "Impossible header type.");
7208 * Since cpio formats -don't- encode the symbolic names, print
7209 * a warning message when we map the uid or gid this way.
7210 * Also, if the ownership just changed, clear set[ug]id bits
7212 * (Except for USTAR format of course, where we have a string
7213 * representation of the username embedded in the header)
7215 if (uid != G_p->g_uid && Hdr_type != USTAR) {
7216 msg(ERR, warnfmt,
7217 (G_p->g_attrnam_p == NULL) ?
7218 G_p->g_nam_p : G_p->g_attrfnam_p,
7219 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
7220 gettext(" System Attribute ") : gettext(" Attribute "),
7221 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p,
7222 gettext("uid too large for archive format"));
7223 if (S_ISREG(mode))
7224 mode &= ~S_ISUID;
7226 if (gid != G_p->g_gid && Hdr_type != USTAR) {
7227 msg(ERR, warnfmt,
7228 (G_p->g_attrnam_p == NULL) ?
7229 G_p->g_nam_p : G_p->g_attrfnam_p,
7230 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
7231 gettext(" System Attribute ") : gettext(" Attribute "),
7232 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p,
7233 gettext("gid too large for archive format"));
7234 if (S_ISREG(mode))
7235 mode &= ~S_ISGID;
7238 switch (Hdr_type) {
7239 case BIN:
7240 case CHR:
7241 case ASC:
7242 case CRC:
7243 cnt = Hdrsz + G_p->g_namesz;
7244 break;
7245 case TAR:
7246 /*FALLTHROUGH*/
7247 case USTAR: /* TAR and USTAR */
7248 cnt = TARSZ;
7249 break;
7250 default:
7251 msg(EXT, "Impossible header type.");
7253 FLUSH(cnt);
7255 switch (Hdr_type) {
7256 case BIN:
7257 Hdr.h_magic = (short)G_p->g_magic;
7258 Hdr.h_dev = G_p->g_dev;
7259 Hdr.h_ino = G_p->g_ino;
7260 Hdr.h_uid = uid;
7261 Hdr.h_gid = gid;
7262 Hdr.h_mode = mode;
7263 Hdr.h_nlink = G_p->g_nlink;
7264 Hdr.h_rdev = G_p->g_rdev;
7265 mkshort(Hdr.h_mtime, (long)G_p->g_mtime);
7266 Hdr.h_namesize = (short)G_p->g_namesz;
7267 mkshort(Hdr.h_filesize, (long)len);
7268 (void) strcpy(Hdr.h_name, G_p->g_nam_p);
7269 (void) memcpy(Buffr.b_in_p, &Hdr, cnt);
7270 break;
7271 case CHR:
7272 /*LINTED*/
7273 (void) sprintf(Buffr.b_in_p,
7274 "%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.11lo%.6lo%."
7275 "11llo%s", G_p->g_magic, G_p->g_dev, G_p->g_ino, mode,
7276 (long)uid, (long)gid, G_p->g_nlink, MK_USHORT(G_p->g_rdev),
7277 G_p->g_mtime, (long)G_p->g_namesz, (offset_t)len,
7278 G_p->g_nam_p);
7279 break;
7280 case ASC:
7281 case CRC:
7282 /*LINTED*/
7283 (void) sprintf(Buffr.b_in_p,
7284 "%.6lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%."
7285 "8lx%.8lx%.8lx%.8lx%s",
7286 G_p->g_magic, G_p->g_ino, mode, G_p->g_uid,
7287 G_p->g_gid, G_p->g_nlink, G_p->g_mtime, (ulong_t)len,
7288 major(G_p->g_dev), minor(G_p->g_dev),
7289 major(G_p->g_rdev), minor(G_p->g_rdev),
7290 G_p->g_namesz, G_p->g_cksum, G_p->g_nam_p);
7291 break;
7292 case USTAR:
7293 Thdr_p = (union tblock *)Buffr.b_in_p;
7294 (void) memset(Thdr_p, 0, TARSZ);
7295 (void) strncpy(Thdr_p->tbuf.t_name, G_p->g_tname,
7296 (int)strlen(G_p->g_tname));
7297 (void) sprintf(Thdr_p->tbuf.t_mode, "%07o", (int)mode);
7298 (void) sprintf(Thdr_p->tbuf.t_uid, "%07o", (int)uid);
7299 (void) sprintf(Thdr_p->tbuf.t_gid, "%07o", (int)gid);
7300 (void) sprintf(Thdr_p->tbuf.t_size, "%011llo",
7301 (offset_t)len);
7302 (void) sprintf(Thdr_p->tbuf.t_mtime, "%011lo", G_p->g_mtime);
7303 if (arcflag == ARCHIVE_ACL) {
7304 Thdr_p->tbuf.t_typeflag = 'A'; /* ACL file type */
7305 } else if (arcflag == ARCHIVE_XATTR ||
7306 (G_p->g_attrnam_p != NULL)) {
7307 Thdr_p->tbuf.t_typeflag = _XATTR_HDRTYPE;
7308 } else {
7309 Thdr_p->tbuf.t_typeflag = G_p->g_typeflag;
7311 if (T_lname[0] != '\0') {
7313 * if not a symbolic link
7315 if (((G_p->g_mode & Ftype) != S_IFLNK) &&
7316 (G_p->g_attrnam_p == NULL)) {
7317 Thdr_p->tbuf.t_typeflag = LNKTYPE;
7318 (void) sprintf(Thdr_p->tbuf.t_size,
7319 "%011lo", 0L);
7321 (void) strncpy(Thdr_p->tbuf.t_linkname, T_lname,
7322 strlen(T_lname));
7324 (void) strcpy(Thdr_p->tbuf.t_magic, TMAGIC);
7325 (void) strcpy(Thdr_p->tbuf.t_version, TVERSION);
7326 (void) strcpy(Thdr_p->tbuf.t_uname, G_p->g_uname);
7327 (void) strcpy(Thdr_p->tbuf.t_gname, G_p->g_gname);
7328 (void) sprintf(Thdr_p->tbuf.t_devmajor, "%07o",
7329 (int)major(G_p->g_rdev));
7330 (void) sprintf(Thdr_p->tbuf.t_devminor, "%07o",
7331 (int)minor(G_p->g_rdev));
7332 if (Gen.g_prefix) {
7333 (void) strcpy(Thdr_p->tbuf.t_prefix, Gen.g_prefix);
7334 free(Gen.g_prefix);
7335 Gen.g_prefix = NULL;
7336 } else {
7337 Thdr_p->tbuf.t_prefix[0] = '\0';
7339 (void) sprintf(Thdr_p->tbuf.t_cksum, "%07o",
7340 (int)cksum(TARTYP, 0, NULL));
7341 break;
7342 case TAR:
7343 Thdr_p = (union tblock *)Buffr.b_in_p;
7344 (void) memset(Thdr_p, 0, TARSZ);
7345 (void) strncpy(Thdr_p->tbuf.t_name, G_p->g_nam_p,
7346 G_p->g_namesz);
7347 (void) sprintf(Thdr_p->tbuf.t_mode, "%07o ", (int)mode);
7348 (void) sprintf(Thdr_p->tbuf.t_uid, "%07o ", (int)uid);
7349 (void) sprintf(Thdr_p->tbuf.t_gid, "%07o ", (int)gid);
7350 (void) sprintf(Thdr_p->tbuf.t_size, "%011llo ",
7351 (offset_t)len);
7352 (void) sprintf(Thdr_p->tbuf.t_mtime, "%011o ",
7353 (int)G_p->g_mtime);
7354 if (T_lname[0] != '\0') {
7355 Thdr_p->tbuf.t_typeflag = '1';
7356 } else {
7357 Thdr_p->tbuf.t_typeflag = '\0';
7359 (void) strncpy(Thdr_p->tbuf.t_linkname, T_lname,
7360 strlen(T_lname));
7361 break;
7362 default:
7363 msg(EXT, "Impossible header type.");
7364 } /* Hdr_type */
7366 Buffr.b_in_p += cnt;
7367 Buffr.b_cnt += cnt;
7368 pad = ((cnt + Pad_val) & ~Pad_val) - cnt;
7369 if (pad != 0) {
7370 FLUSH(pad);
7371 (void) memset(Buffr.b_in_p, 0, pad);
7372 Buffr.b_in_p += pad;
7373 Buffr.b_cnt += pad;
7378 * write_trail: Create the appropriate trailer for the selected header type
7379 * and bwrite the trailer. Pad the buffer with nulls out to the next Bufsize
7380 * boundary, and force a write. If the write completes, or if the trailer is
7381 * completely written (but not all of the padding nulls (as can happen on end
7382 * of medium)) return. Otherwise, the trailer was not completely written out,
7383 * so re-pad the buffer with nulls and try again.
7386 static void
7387 write_trail(void)
7389 int cnt, need;
7391 switch (Hdr_type) {
7392 case BIN:
7393 Gen.g_magic = CMN_BIN;
7394 break;
7395 case CHR:
7396 Gen.g_magic = CMN_BIN;
7397 break;
7398 case ASC:
7399 Gen.g_magic = CMN_ASC;
7400 break;
7401 case CRC:
7402 Gen.g_magic = CMN_CRC;
7403 break;
7406 switch (Hdr_type) {
7407 case BIN:
7408 case CHR:
7409 case ASC:
7410 case CRC:
7411 Gen.g_mode = Gen.g_uid = Gen.g_gid = 0;
7412 Gen.g_nlink = 1;
7413 Gen.g_mtime = Gen.g_ino = Gen.g_dev = 0;
7414 Gen.g_rdev = Gen.g_cksum = 0;
7415 Gen.g_filesz = (off_t)0;
7416 Gen.g_namesz = strlen("TRAILER!!!") + 1;
7417 (void) strcpy(Gen.g_nam_p, "TRAILER!!!");
7418 G_p = &Gen;
7419 write_hdr(ARCHIVE_NORMAL, (off_t)0);
7420 break;
7421 case TAR:
7422 /*FALLTHROUGH*/
7423 case USTAR: /* TAR and USTAR */
7424 for (cnt = 0; cnt < 3; cnt++) {
7425 FLUSH(TARSZ);
7426 (void) memset(Buffr.b_in_p, 0, TARSZ);
7427 Buffr.b_in_p += TARSZ;
7428 Buffr.b_cnt += TARSZ;
7430 break;
7431 default:
7432 msg(EXT, "Impossible header type.");
7434 need = Bufsize - (Buffr.b_cnt % Bufsize);
7435 if (need == Bufsize)
7436 need = 0;
7438 while (Buffr.b_cnt > 0) {
7439 while (need > 0) {
7440 cnt = (need < TARSZ) ? need : TARSZ;
7441 need -= cnt;
7442 FLUSH(cnt);
7443 (void) memset(Buffr.b_in_p, 0, cnt);
7444 Buffr.b_in_p += cnt;
7445 Buffr.b_cnt += cnt;
7447 bflush();
7452 * if archives in USTAR format, check if typeflag == '5' for directories
7454 static int
7455 ustar_dir(void)
7457 if (Hdr_type == USTAR || Hdr_type == TAR) {
7458 if (Thdr_p->tbuf.t_typeflag == '5')
7459 return (1);
7461 return (0);
7465 * if archives in USTAR format, check if typeflag == '3' || '4' || '6'
7466 * for character, block, fifo special files
7468 static int
7469 ustar_spec(void)
7471 int typeflag;
7473 if (Hdr_type == USTAR || Hdr_type == TAR) {
7474 typeflag = Thdr_p->tbuf.t_typeflag;
7475 if (typeflag == '3' || typeflag == '4' || typeflag == '6')
7476 return (1);
7478 return (0);
7482 * The return value is a pointer to a converted copy of the information in
7483 * FromStat if the file is representable in -Hodc format, and NULL otherwise.
7486 static struct stat *
7487 convert_to_old_stat(struct stat *FromStat, char *namep, char *attrp)
7489 static struct stat ToSt;
7490 cpioinfo_t TmpSt;
7492 (void) memset(&TmpSt, 0, sizeof (cpioinfo_t));
7493 stat_to_svr32_stat(&TmpSt, FromStat);
7494 (void) memset(&ToSt, 0, sizeof (ToSt));
7496 if (TmpSt.st_rdev == (o_dev_t)NODEV &&
7497 (((TmpSt.st_mode & Ftype) == S_IFCHR) ||
7498 ((TmpSt.st_mode & Ftype) == S_IFBLK))) {
7500 * Encountered a problem representing the rdev information.
7501 * Don't archive it.
7504 msg(ERR, "Error -Hodc format can't support expanded"
7505 "types on %s%s%s",
7506 namep,
7507 (attrp == NULL) ? "" : gettext(" Attribute"),
7508 (attrp == NULL) ? "" : attrp);
7509 return (NULL);
7512 if (TmpSt.st_dev == (o_dev_t)NODEV) {
7514 * Having trouble representing the device/inode pair. We can't
7515 * track links in this case; break them all into separate
7516 * files.
7519 TmpSt.st_ino = 0;
7521 if (((TmpSt.st_mode & Ftype) != S_IFDIR) &&
7522 TmpSt.st_nlink > 1)
7523 msg(POST,
7524 "Warning: file %s%s%s has large "
7525 "device number - linked "
7526 "files will be restored as "
7527 "separate files",
7528 namep,
7529 (attrp == NULL) ? "" : gettext(" Attribute"),
7530 (attrp == NULL) ? "" : attrp);
7532 /* ensure no links */
7534 TmpSt.st_nlink = 1;
7537 /* Start converting values */
7539 if (TmpSt.st_dev < 0) {
7540 ToSt.st_dev = 0;
7541 } else {
7542 ToSt.st_dev = (dev_t)TmpSt.st_dev;
7545 /* -actual- not truncated uid */
7547 ToSt.st_uid = TmpSt.st_uid;
7549 /* -actual- not truncated gid */
7551 ToSt.st_gid = TmpSt.st_gid;
7552 ToSt.st_ino = (ino_t)TmpSt.st_ino;
7553 ToSt.st_mode = (mode_t)TmpSt.st_mode;
7554 ToSt.st_mtime = (ulong_t)TmpSt.st_modtime;
7555 ToSt.st_nlink = (nlink_t)TmpSt.st_nlink;
7556 ToSt.st_size = (off_t)TmpSt.st_size;
7557 ToSt.st_rdev = (dev_t)TmpSt.st_rdev;
7559 return (&ToSt);
7563 * In the beginning of each bar archive, there is a header which describes the
7564 * current volume being created, followed by a header which describes the
7565 * current file being created, followed by the file itself. If there is
7566 * more than one file to be created, a separate header will be created for
7567 * each additional file. This structure may be repeated if the bar archive
7568 * contains multiple volumes. If a file spans across volumes, its header
7569 * will not be repeated in the next volume.
7570 * +------------------+
7571 * | vol header |
7572 * |------------------|
7573 * | file header i | i = 0
7574 * |------------------|
7575 * | <file i> |
7576 * |------------------|
7577 * | file header i+1 |
7578 * |------------------|
7579 * | <file i+1> |
7580 * |------------------|
7581 * | . |
7582 * | . |
7583 * | . |
7584 * +------------------+
7588 * read in the header that describes the current volume of the bar archive
7589 * to be extracted.
7591 static void
7592 read_bar_vol_hdr(void)
7594 union b_block *tmp_hdr;
7596 tmp_hdr = (union b_block *)Buffr.b_out_p;
7597 if (tmp_hdr->dbuf.bar_magic[0] == BAR_VOLUME_MAGIC) {
7599 if (bar_Vhdr == NULL) {
7600 bar_Vhdr = e_zalloc(E_EXIT, TBLOCK);
7602 (void) memcpy(&(bar_Vhdr->dbuf), &(tmp_hdr->dbuf), TBLOCK);
7603 } else {
7604 (void) fprintf(stderr, gettext(
7605 "bar error: cannot read volume header\n"));
7606 exit(1);
7609 (void) sscanf(bar_Vhdr->dbuf.mode, "%8lo", &Gen_bar_vol.g_mode);
7610 (void) sscanf(bar_Vhdr->dbuf.uid, "%8d", (int *)&Gen_bar_vol.g_uid);
7611 (void) sscanf(bar_Vhdr->dbuf.gid, "%8d", (int *)&Gen_bar_vol.g_gid);
7612 (void) sscanf(bar_Vhdr->dbuf.size, "%12llo",
7613 (u_off_t *)&Gen_bar_vol.g_filesz);
7614 (void) sscanf(bar_Vhdr->dbuf.mtime, "%12lo", &Gen_bar_vol.g_mtime);
7615 (void) sscanf(bar_Vhdr->dbuf.chksum, "%8lo", &Gen_bar_vol.g_cksum);
7617 /* set the compress flag */
7618 if (bar_Vhdr->dbuf.compressed == '1')
7619 Compressed = 1;
7620 else
7621 Compressed = 0;
7623 Buffr.b_out_p += 512;
7624 Buffr.b_cnt -= 512;
7627 * not the first volume; exit
7629 if (strcmp(bar_Vhdr->dbuf.volume_num, "1") != 0) {
7630 (void) fprintf(stderr,
7631 gettext("error: This is not volume 1. "));
7632 (void) fprintf(stderr, gettext("This is volume %s. "),
7633 bar_Vhdr->dbuf.volume_num);
7634 (void) fprintf(stderr, gettext("Please insert volume 1.\n"));
7635 exit(1);
7638 read_bar_file_hdr();
7642 * read in the header that describes the current file to be extracted
7644 static void
7645 read_bar_file_hdr(void)
7647 union b_block *tmp_hdr;
7648 char *start_of_name, *name_p;
7649 char *tmp;
7651 if (*Buffr.b_out_p == '\0') {
7652 *Gen.g_nam_p = '\0';
7653 exit(0);
7656 tmp_hdr = (union b_block *)Buffr.b_out_p;
7658 tmp = &tmp_hdr->dbuf.mode[1];
7659 (void) sscanf(tmp, "%8lo", &Gen.g_mode);
7660 (void) sscanf(tmp_hdr->dbuf.uid, "%8lo", &Gen.g_uid);
7661 (void) sscanf(tmp_hdr->dbuf.gid, "%8lo", &Gen.g_gid);
7662 (void) sscanf(tmp_hdr->dbuf.size, "%12llo",
7663 (u_off_t *)&Gen.g_filesz);
7664 (void) sscanf(tmp_hdr->dbuf.mtime, "%12lo", &Gen.g_mtime);
7665 (void) sscanf(tmp_hdr->dbuf.chksum, "%8lo", &Gen.g_cksum);
7666 (void) sscanf(tmp_hdr->dbuf.rdev, "%8lo", &Gen.g_rdev);
7668 #define to_new_major(x) (int)((unsigned)((x) & OMAXMAJ) << NBITSMINOR)
7669 #define to_new_minor(x) (int)((x) & OMAXMIN)
7670 Gen.g_rdev = to_new_major(Gen.g_rdev) | to_new_minor(Gen.g_rdev);
7671 bar_linkflag = tmp_hdr->dbuf.linkflag;
7672 start_of_name = &tmp_hdr->dbuf.start_of_name;
7675 name_p = Gen.g_nam_p;
7676 while (*name_p++ = *start_of_name++)
7678 *name_p = '\0';
7679 if (bar_linkflag == LNKTYPE || bar_linkflag == SYMTYPE)
7680 (void) strcpy(bar_linkname, start_of_name);
7682 Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
7683 (void) strcpy(nambuf, Gen.g_nam_p);
7687 * if the bar archive is compressed, set up a pipe and do the de-compression
7688 * as the compressed file is read in.
7690 static void
7691 setup_uncompress(FILE **pipef)
7693 char *cmd_buf;
7694 size_t cmdlen;
7696 cmd_buf = e_zalloc(E_EXIT, MAXPATHLEN * 2);
7698 if (access(Gen.g_nam_p, W_OK) != 0) {
7699 cmdlen = snprintf(cmd_buf, MAXPATHLEN * 2,
7700 "chmod +w '%s'; uncompress -c > '%s'; "
7701 "chmod 0%o '%s'",
7702 Gen.g_nam_p, Gen.g_nam_p, (int)G_p->g_mode, Gen.g_nam_p);
7703 } else {
7704 cmdlen = snprintf(cmd_buf, MAXPATHLEN * 2,
7705 "uncompress -c > '%s'", Gen.g_nam_p);
7708 if (cmdlen >= MAXPATHLEN * 2 ||
7709 (*pipef = popen(cmd_buf, "w")) == NULL) {
7710 (void) fprintf(stderr, gettext("error\n"));
7711 exit(1);
7714 if (close(Ofile) != 0)
7715 msg(EXTN, "close error");
7716 Ofile = fileno(*pipef);
7718 free(cmd_buf);
7722 * if the bar archive spans multiple volumes, read in the header that
7723 * describes the next volume.
7725 static void
7726 skip_bar_volhdr(void)
7728 char *buff;
7729 union b_block *tmp_hdr;
7731 buff = e_zalloc(E_EXIT, (uint_t)Bufsize);
7733 if (g_read(Device, Archive, buff, Bufsize) < 0) {
7734 (void) fprintf(stderr, gettext(
7735 "error in skip_bar_volhdr\n"));
7736 } else {
7738 tmp_hdr = (union b_block *)buff;
7739 if (tmp_hdr->dbuf.bar_magic[0] == BAR_VOLUME_MAGIC) {
7741 if (bar_Vhdr == NULL) {
7742 bar_Vhdr = e_zalloc(E_EXIT, TBLOCK);
7744 (void) memcpy(&(bar_Vhdr->dbuf),
7745 &(tmp_hdr->dbuf), TBLOCK);
7746 } else {
7747 (void) fprintf(stderr,
7748 gettext("cpio error: cannot read bar volume "
7749 "header\n"));
7750 exit(1);
7753 (void) sscanf(bar_Vhdr->dbuf.mode, "%8lo",
7754 &Gen_bar_vol.g_mode);
7755 (void) sscanf(bar_Vhdr->dbuf.uid, "%8lo",
7756 &Gen_bar_vol.g_uid);
7757 (void) sscanf(bar_Vhdr->dbuf.gid, "%8lo",
7758 &Gen_bar_vol.g_gid);
7759 (void) sscanf(bar_Vhdr->dbuf.size, "%12llo",
7760 (u_off_t *)&Gen_bar_vol.g_filesz);
7761 (void) sscanf(bar_Vhdr->dbuf.mtime, "%12lo",
7762 &Gen_bar_vol.g_mtime);
7763 (void) sscanf(bar_Vhdr->dbuf.chksum, "%8lo",
7764 &Gen_bar_vol.g_cksum);
7765 if (bar_Vhdr->dbuf.compressed == '1')
7766 Compressed = 1;
7767 else
7768 Compressed = 0;
7772 * Now put the rest of the bytes read in into the data buffer.
7774 (void) memcpy(Buffr.b_in_p, &buff[512], (Bufsize - 512));
7775 Buffr.b_in_p += (Bufsize - 512);
7776 Buffr.b_cnt += (long)(Bufsize - 512);
7778 free(buff);
7782 * check the linkflag which indicates the type of the file to be extracted,
7783 * invoke the corresponding routine to extract the file.
7785 static void
7786 bar_file_in(void)
7789 * the file is a directory
7791 if (Adir) {
7792 if (ckname(1) != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
7793 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
7795 return;
7798 switch (bar_linkflag) {
7799 case REGTYPE:
7800 /* regular file */
7801 if ((ckname(1) == F_SKIP) ||
7802 (Ofile = openout(G_p->g_dirfd)) < 0) {
7803 data_in(P_SKIP);
7804 } else {
7805 data_in(P_PROC);
7807 break;
7808 case LNKTYPE:
7809 /* hard link */
7810 if (ckname(1) == F_SKIP) {
7811 break;
7813 (void) creat_lnk(G_p->g_dirfd, bar_linkname, G_p->g_nam_p);
7814 break;
7815 case SYMTYPE:
7816 /* symbolic link */
7817 if ((ckname(1) == F_SKIP) ||
7818 (Ofile = openout(G_p->g_dirfd)) < 0) {
7819 data_in(P_SKIP);
7820 } else {
7821 data_in(P_PROC);
7823 break;
7824 case CHRTYPE:
7825 /* character device or FIFO */
7826 if (ckname(1) != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
7827 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
7829 break;
7830 default:
7831 (void) fprintf(stderr, gettext("error: unknown file type\n"));
7832 break;
7838 * This originally came from libgenIO/g_init.c
7839 * XXX And it is very broken.
7842 /* #include <sys/statvfs.h> */
7843 #include <ftw.h>
7844 /* #include <libgenIO.h> */
7845 #define G_TM_TAPE 1 /* Tapemaster controller */
7846 #define G_XY_DISK 3 /* xy disks */
7847 #define G_SD_DISK 7 /* scsi sd disk */
7848 #define G_XT_TAPE 8 /* xt tapes */
7849 #define G_SF_FLOPPY 9 /* sf floppy */
7850 #define G_XD_DISK 10 /* xd disks */
7851 #define G_ST_TAPE 11 /* scsi tape */
7852 #define G_NS 12 /* noswap pseudo-dev */
7853 #define G_RAM 13 /* ram pseudo-dev */
7854 #define G_FT 14 /* tftp */
7855 #define G_HD 15 /* 386 network disk */
7856 #define G_FD 16 /* 386 AT disk */
7857 #define G_FILE 28 /* file, not a device */
7858 #define G_NO_DEV 29 /* device does not require special treatment */
7859 #define G_DEV_MAX 30 /* last valid device type */
7862 * g_init: Determine the device being accessed, set the buffer size,
7863 * and perform any device specific initialization. Since at this point
7864 * Sun has no system call to read the configuration, the major numbers
7865 * are assumed to be static and types are figured out as such. However,
7866 * as a rough estimate, the buffer size for all types is set to 512
7867 * as a default.
7870 static int
7871 g_init(int *devtype, int *fdes)
7873 int bufsize;
7874 struct stat st_buf;
7875 struct statvfs stfs_buf;
7877 *devtype = G_NO_DEV;
7878 bufsize = -1;
7879 if (fstat(*fdes, &st_buf) == -1)
7880 return (-1);
7881 if (!S_ISCHR(st_buf.st_mode) && !S_ISBLK(st_buf.st_mode)) {
7882 if (S_ISFIFO(st_buf.st_mode)) {
7883 bufsize = 512;
7884 } else {
7885 /* find block size for this file system */
7886 *devtype = G_FILE;
7887 if (fstatvfs(*fdes, &stfs_buf) < 0) {
7888 bufsize = -1;
7889 errno = ENODEV;
7890 } else
7891 bufsize = stfs_buf.f_bsize;
7894 return (bufsize);
7897 * We'll have to add a remote attribute to stat but this
7898 * should work for now.
7900 } else if (st_buf.st_dev & 0x8000) /* if remote rdev */
7901 return (512);
7903 bufsize = 512;
7905 if (Hdr_type == BAR) {
7906 if (is_tape(*fdes)) {
7907 bufsize = BAR_TAPE_SIZE;
7908 msg(EPOST, "Archiving to tape blocking factor 126");
7909 } else if (is_floppy(*fdes)) {
7910 bufsize = BAR_FLOPPY_SIZE;
7911 msg(EPOST, "Archiving to floppy blocking factor 18");
7915 return (bufsize);
7919 * This originally came from libgenIO/g_read.c
7923 * g_read: Read nbytes of data from fdes (of type devtype) and place
7924 * data in location pointed to by buf. In case of end of medium,
7925 * translate (where necessary) device specific EOM indications into
7926 * the generic EOM indication of rv = -1, errno = ENOSPC.
7929 static int
7930 g_read(int devtype, int fdes, char *buf, unsigned nbytes)
7932 int rv;
7934 if (devtype < 0 || devtype >= G_DEV_MAX) {
7935 errno = ENODEV;
7936 return (-1);
7939 rv = read(fdes, buf, nbytes);
7941 /* st devices return 0 when no space left */
7942 if ((rv == 0 && errno == 0 && Hdr_type != BAR) ||
7943 (rv == -1 && errno == EIO)) {
7944 errno = 0;
7945 rv = 0;
7948 return (rv);
7952 * This originally came from libgenIO/g_write.c
7956 * g_write: Write nbytes of data to fdes (of type devtype) from
7957 * the location pointed to by buf. In case of end of medium,
7958 * translate (where necessary) device specific EOM indications into
7959 * the generic EOM indication of rv = -1, errno = ENOSPC.
7962 static int
7963 g_write(int devtype, int fdes, char *buf, unsigned nbytes)
7965 int rv;
7967 if (devtype < 0 || devtype >= G_DEV_MAX) {
7968 errno = ENODEV;
7969 return (-1);
7972 rv = write(fdes, buf, nbytes);
7974 /* st devices return 0 when no more space left */
7975 if ((rv == 0 && errno == 0) || (rv == -1 && errno == EIO)) {
7976 errno = ENOSPC;
7977 rv = -1;
7980 return (rv);
7984 * Test for tape
7987 static int
7988 is_tape(int fd)
7990 struct mtget stuff;
7993 * try to do a generic tape ioctl, just to see if
7994 * the thing is in fact a tape drive(er).
7996 if (ioctl(fd, MTIOCGET, &stuff) != -1) {
7997 /* the ioctl succeeded, must have been a tape */
7998 return (1);
8000 return (0);
8004 * Test for floppy
8007 static int
8008 is_floppy(int fd)
8010 struct fd_char stuff;
8013 * try to get the floppy drive characteristics, just to see if
8014 * the thing is in fact a floppy drive(er).
8016 if (ioctl(fd, FDIOGCHAR, &stuff) != -1) {
8017 /* the ioctl succeeded, must have been a floppy */
8018 return (1);
8021 return (0);
8025 * New functions for ACLs and other security attributes
8029 * The function appends the new security attribute info to the end of
8030 * existing secinfo.
8032 static int
8033 append_secattr(
8034 char **secinfo, /* existing security info */
8035 int *secinfo_len, /* length of existing security info */
8036 acl_t *aclp) /* new attribute data pointer */
8038 char *new_secinfo;
8039 char *attrtext;
8040 size_t newattrsize;
8041 int oldsize;
8043 /* no need to add */
8044 if (aclp == NULL) {
8045 return (0);
8048 switch (acl_type(aclp)) {
8049 case ACLENT_T:
8050 case ACE_T:
8051 attrtext = acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8052 ACL_SID_FMT);
8053 if (attrtext == NULL) {
8054 msg(EPOST, "acltotext failed");
8055 return (-1);
8057 /* header: type + size = 8 */
8058 newattrsize = 8 + strlen(attrtext) + 1;
8059 attr = e_zalloc(E_NORMAL, newattrsize);
8060 if (attr == NULL) {
8061 msg(EPOST, "can't allocate memory");
8062 return (-1);
8064 attr->attr_type = (acl_type(aclp) == ACLENT_T) ?
8065 UFSD_ACL : ACE_ACL;
8066 /* acl entry count */
8067 (void) sprintf(attr->attr_len, "%06o", acl_cnt(aclp));
8068 (void) strcpy((char *)&attr->attr_info[0], attrtext);
8069 free(attrtext);
8070 break;
8072 /* SunFed's case goes here */
8074 default:
8075 msg(EPOST, "unrecognized attribute type");
8076 return (-1);
8079 /* old security info + new attr header(8) + new attr */
8080 oldsize = *secinfo_len;
8081 *secinfo_len += newattrsize;
8082 new_secinfo = e_zalloc(E_NORMAL, (uint_t)*secinfo_len);
8083 if (new_secinfo == NULL) {
8084 msg(EPOST, "can't allocate memory");
8085 *secinfo_len -= newattrsize;
8086 return (-1);
8089 (void) memcpy(new_secinfo, *secinfo, oldsize);
8090 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
8092 free(*secinfo);
8093 *secinfo = new_secinfo;
8094 return (0);
8098 * Append size amount of data from buf to the archive.
8100 static void
8101 write_ancillary(char *buf, size_t len, boolean_t padding)
8103 int pad, cnt;
8105 if (len == 0)
8106 return;
8108 while (len > 0) {
8109 cnt = (unsigned)(len > CPIOBSZ) ? CPIOBSZ : len;
8110 FLUSH(cnt);
8111 errno = 0;
8112 (void) memcpy(Buffr.b_in_p, buf, (unsigned)cnt);
8113 Buffr.b_in_p += cnt;
8114 Buffr.b_cnt += cnt;
8115 len -= cnt;
8116 buf += cnt;
8118 if (padding) {
8119 pad = (Pad_val + 1 - (cnt & Pad_val)) & Pad_val;
8120 if (pad != 0) {
8121 FLUSH(pad);
8122 (void) memset(Buffr.b_in_p, 0, pad);
8123 Buffr.b_in_p += pad;
8124 Buffr.b_cnt += pad;
8129 static int
8130 remove_dir(char *path)
8132 DIR *name;
8133 struct dirent *direct;
8134 struct stat sbuf;
8135 char *path_copy;
8137 #define MSG1 "remove_dir() failed to stat(\"%s\") "
8138 #define MSG2 "remove_dir() failed to remove_dir(\"%s\") "
8139 #define MSG3 "remove_dir() failed to unlink(\"%s\") "
8142 * Open the directory for reading.
8144 if ((name = opendir(path)) == NULL) {
8145 msg(ERRN, "remove_dir() failed to opendir(\"%s\") ", path);
8146 return (-1);
8149 if (chdir(path) == -1) {
8150 msg(ERRN, "remove_dir() failed to chdir(\"%s\") ", path);
8151 return (-1);
8155 * Read every directory entry.
8157 while ((direct = readdir(name)) != NULL) {
8159 * Ignore "." and ".." entries.
8161 if (strcmp(direct->d_name, ".") == 0 ||
8162 strcmp(direct->d_name, "..") == 0)
8163 continue;
8165 if (lstat(direct->d_name, &sbuf) == -1) {
8166 msg(ERRN, MSG1, direct->d_name);
8167 (void) closedir(name);
8168 return (-1);
8171 if (S_ISDIR(sbuf.st_mode)) {
8172 if (remove_dir(direct->d_name) == -1) {
8173 msg(ERRN, MSG2, direct->d_name);
8174 (void) closedir(name);
8175 return (-1);
8177 } else {
8178 if (unlink(direct->d_name) == -1) {
8179 msg(ERRN, MSG3, direct->d_name);
8180 (void) closedir(name);
8181 return (-1);
8188 * Close the directory we just finished reading.
8190 (void) closedir(name);
8193 * Change directory to the parent directory...
8195 if (chdir("..") == -1) {
8196 msg(ERRN, "remove_dir() failed to chdir(\"..\") ");
8197 return (-1);
8201 * ...and finally remove the directory; note we have to
8202 * make a copy since basename is free to modify its input.
8204 path_copy = e_strdup(E_NORMAL, path);
8205 if (path_copy == NULL) {
8206 msg(ERRN, "cannot strdup() the directory pathname ");
8207 return (-1);
8210 if (rmdir(basename(path_copy)) == -1) {
8211 free(path_copy);
8212 msg(ERRN, "remove_dir() failed to rmdir(\"%s\") ", path);
8213 return (-1);
8216 free(path_copy);
8217 return (0);
8221 static int
8222 save_cwd(void)
8224 return (open(".", O_RDONLY));
8227 static void
8228 rest_cwd(int cwd)
8230 (void) fchdir(cwd);
8231 (void) close(cwd);
8234 #if defined(O_XATTR)
8235 static void
8236 xattrs_out(int (*func)())
8238 int dirpfd;
8239 int filefd;
8240 int arc_rwsysattr = 0;
8241 int rw_sysattr = 0;
8242 int ext_attr = 0;
8243 DIR *dirp;
8244 struct dirent *dp;
8245 int slen;
8246 int plen;
8247 char *namep, *savenamep;
8248 char *apathp;
8249 char *attrparent = Gen.g_attrparent_p;
8250 char *filename;
8252 if (attrparent == NULL) {
8253 filename = Gen.g_nam_p;
8254 } else {
8255 filename = Gen.g_attrnam_p;
8259 * If the underlying file system supports it, then
8260 * archive the extended attributes if -@ was specified,
8261 * and the extended system attributes if -/ was
8262 * specified.
8264 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
8265 &ext_attr) != ATTR_OK) {
8266 return;
8269 #if defined(_PC_SATTR_ENABLED)
8270 if (SysAtflag) {
8271 int filefd;
8272 nvlist_t *slist = NULL;
8275 * Determine if there are non-transient system
8276 * attributes.
8278 errno = 0;
8279 if ((filefd = open(filename, O_RDONLY)) == -1) {
8280 if (attrparent == NULL) {
8281 msg(EXTN,
8282 "unable to open %s%s%sfile %s",
8283 (attrparent == NULL) ? "" :
8284 gettext("attribute "),
8285 (attrparent == NULL) ? "" : attrparent,
8286 (attrparent == NULL) ? "" : gettext(" of "),
8287 (attrparent == NULL) ? G_p->g_nam_p :
8288 G_p->g_attrfnam_p);
8291 if (((slist = sysattr_list(myname, filefd,
8292 filename)) != NULL) || (errno != 0)) {
8293 arc_rwsysattr = 1;
8295 if (slist != NULL) {
8296 (void) nvlist_free(slist);
8297 slist = NULL;
8299 (void) close(filefd);
8303 * If we aren't archiving extended system attributes, and we are
8304 * processing an attribute, or if we are archiving extended system
8305 * attributes, and there are are no extended attributes, then there's
8306 * no need to open up the attribute directory of the file unless the
8307 * extended system attributes are not transient (i.e, the system
8308 * attributes are not the default values).
8310 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
8311 (SysAtflag && !ext_attr))) {
8312 return;
8315 #endif /* _PC_SATTR_ENABLED */
8318 * If aclp still exists then free it since it is was set when base
8319 * file was extracted.
8321 if (aclp != NULL) {
8322 acl_free(aclp);
8323 aclp = NULL;
8324 acl_is_set = 0;
8327 Gen.g_dirfd = attropen(filename, ".", O_RDONLY);
8328 if (Gen.g_dirfd == -1) {
8329 msg(ERRN, "Cannot open attribute directory of file \"%s%s%s\"",
8330 (attrparent == NULL) ? "" : gettext("attribute "),
8331 (attrparent == NULL) ? "" : attrparent,
8332 (attrparent == NULL) ? "" : gettext(" of "), filename);
8333 return;
8337 if (attrparent == NULL) {
8338 savenamep = G_p->g_nam_p;
8339 } else {
8340 savenamep = G_p->g_attrfnam_p;
8343 if ((dirpfd = dup(Gen.g_dirfd)) == -1) {
8344 msg(ERRN, "Cannot dup(2) attribute directory descriptor");
8345 return;
8348 if ((dirp = fdopendir(dirpfd)) == NULL) {
8349 msg(ERRN, "Cannot fdopendir(2) directory file descriptor");
8350 return;
8353 if (attrparent == NULL) {
8354 Gen.g_baseparent_fd = save_cwd();
8357 while ((dp = readdir(dirp)) != NULL) {
8358 if (strcmp(dp->d_name, "..") == 0) {
8359 continue;
8361 if (verify_attr(dp->d_name, attrparent,
8362 arc_rwsysattr, &rw_sysattr) != ATTR_OK) {
8363 continue;
8366 if (strcmp(dp->d_name, ".") == 0) {
8367 Hiddendir = 1;
8368 } else {
8369 Hiddendir = 0;
8372 Gen.g_rw_sysattr = rw_sysattr;
8373 Gen.g_attrnam_p = dp->d_name;
8375 if (STAT(Gen.g_dirfd, Gen.g_nam_p, &SrcSt) == -1) {
8376 msg(ERRN,
8377 "Could not fstatat(2) attribute \"%s\" of"
8378 " file \"%s\"", dp->d_name, (attrparent == NULL) ?
8379 savenamep : Gen.g_attrfnam_p);
8380 continue;
8383 if (Use_old_stat) {
8384 Savedev = SrcSt.st_dev;
8385 OldSt = convert_to_old_stat(&SrcSt,
8386 Gen.g_nam_p, Gen.g_attrnam_p);
8388 if (OldSt == NULL) {
8389 msg(ERRN,
8390 "Could not convert to old stat format");
8391 continue;
8395 Gen.g_attrfnam_p = savenamep;
8398 * Set up dummy header name
8400 * One piece is written with .hdr, which
8401 * contains the actual xattr hdr or pathing information
8402 * then the name is updated to drop the .hdr off
8403 * and the actual file itself is archived.
8405 slen = strlen(Gen.g_attrnam_p) + strlen(DEVNULL) +
8406 strlen(XATTRHDR) + 2; /* add one for '/' */
8407 if ((namep = e_zalloc(E_NORMAL, slen)) == NULL) {
8408 msg(ERRN, "Could not calloc memory for attribute name");
8409 continue;
8411 (void) snprintf(namep, slen, "%s/%s%s",
8412 DEVNULL, Gen.g_attrnam_p, XATTRHDR);
8413 Gen.g_nam_p = namep;
8415 plen = strlen(Gen.g_attrnam_p) + 1;
8416 if (Gen.g_attrparent_p != NULL) {
8417 plen += strlen(Gen.g_attrparent_p) + 1;
8419 if ((apathp = e_zalloc(E_NORMAL, plen)) == NULL) {
8420 msg(ERRN, "Could not calloc memory for attribute name");
8421 continue;
8423 (void) snprintf(apathp, plen, "%s%s%s",
8424 (Gen.g_attrparent_p == NULL) ? "" : Gen.g_attrparent_p,
8425 (Gen.g_attrparent_p == NULL) ? "" : "/", Gen.g_attrnam_p);
8427 if (Gen.g_attrpath_p != NULL) {
8428 free(Gen.g_attrpath_p);
8430 Gen.g_attrpath_p = apathp;
8433 * Get attribute's ACL info: don't bother allocating space
8434 * if there are only standard permissions, i.e. ACL count < 4
8436 if (Pflag) {
8437 filefd = openat(Gen.g_dirfd, dp->d_name, O_RDONLY);
8438 if (filefd == -1) {
8439 msg(ERRN,
8440 "Could not open attribute \"%s\" of"
8441 " file \"%s\"", dp->d_name, savenamep);
8442 free(namep);
8443 continue;
8445 if (facl_get(filefd, ACL_NO_TRIVIAL, &aclp) != 0) {
8446 msg(ERRN,
8447 "Error with acl() on %s",
8448 Gen.g_nam_p);
8450 (void) close(filefd);
8453 (void) creat_hdr();
8454 (void) (*func)();
8456 #if defined(_PC_SATTR_ENABLED)
8458 * Recursively call xattrs_out() to process the attribute's
8459 * hidden attribute directory and read-write system attributes.
8461 if (SysAtflag && !Hiddendir && !rw_sysattr) {
8462 int savedirfd = Gen.g_dirfd;
8464 (void) fchdir(Gen.g_dirfd);
8465 Gen.g_attrparent_p = dp->d_name;
8466 xattrs_out(func);
8467 Gen.g_dirfd = savedirfd;
8468 Gen.g_attrparent_p = NULL;
8470 #endif /* _PC_SATTR_ENABLED */
8472 if (Gen.g_passdirfd != -1) {
8473 (void) close(Gen.g_passdirfd);
8474 Gen.g_passdirfd = -1;
8476 Gen.g_attrnam_p = NULL;
8477 Gen.g_attrfnam_p = NULL;
8478 Gen.g_linktoattrfnam_p = NULL;
8479 Gen.g_linktoattrnam_p = NULL;
8480 Gen.g_rw_sysattr = 0;
8481 if (Gen.g_attrpath_p != NULL) {
8482 free(Gen.g_attrpath_p);
8483 Gen.g_attrpath_p = NULL;
8486 if (aclp != NULL) {
8487 acl_free(aclp);
8488 aclp = NULL;
8489 acl_is_set = 0;
8491 free(namep);
8494 (void) closedir(dirp);
8495 (void) close(Gen.g_dirfd);
8496 if (attrparent == NULL) {
8497 rest_cwd(Gen.g_baseparent_fd);
8498 Gen.g_dirfd = -1;
8500 Hiddendir = 0;
8502 #else
8503 static void
8504 xattrs_out(int (*func)())
8507 #endif
8510 * Return the parent directory of a given path.
8512 * Examples:
8513 * /usr/tmp return /usr
8514 * /usr/tmp/file return /usr/tmp
8515 * / returns .
8516 * /usr returns /
8517 * file returns .
8519 * dir is assumed to be at least as big as path.
8521 static void
8522 get_parent(char *path, char *dir)
8524 char *s;
8525 char tmpdir[PATH_MAX + 1];
8527 if (strlen(path) > PATH_MAX) {
8528 msg(EXT, "pathname is too long");
8530 (void) strcpy(tmpdir, path);
8531 chop_endslashes(tmpdir);
8533 if ((s = strrchr(tmpdir, '/')) == NULL) {
8534 (void) strcpy(dir, ".");
8535 } else {
8536 s = skipslashes(s, tmpdir);
8537 *s = '\0';
8538 if (s == tmpdir)
8539 (void) strcpy(dir, "/");
8540 else
8541 (void) strcpy(dir, tmpdir);
8545 #if defined(O_XATTR)
8546 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
8548 static void
8549 prepare_xattr_hdr(
8550 char **attrbuf,
8551 char *filename,
8552 char *attrpath,
8553 char typeflag,
8554 struct Lnk *linkinfo,
8555 int *rlen)
8557 char *bufhead; /* ptr to full buffer */
8558 char *aptr;
8559 struct xattr_hdr *hptr; /* ptr to header in bufhead */
8560 struct xattr_buf *tptr; /* ptr to pathing pieces */
8561 int totalen; /* total buffer length */
8562 int len; /* length returned to user */
8563 int stringlen; /* length of filename + attr */
8565 * length of filename + attr
8566 * in link section
8568 int linkstringlen;
8569 int complen; /* length of pathing section */
8570 int linklen; /* length of link section */
8571 int attrnames_index; /* attrnames starting index */
8574 * Release previous buffer if any.
8577 if (*attrbuf != NULL) {
8578 free(*attrbuf);
8579 *attrbuf = NULL;
8583 * First add in fixed size stuff
8585 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
8588 * Add space for two nulls
8590 stringlen = strlen(attrpath) + strlen(filename) + 2;
8591 complen = stringlen + sizeof (struct xattr_buf);
8593 len += stringlen;
8596 * Now add on space for link info if any
8599 if (linkinfo != NULL) {
8601 * Again add space for two nulls
8603 linkstringlen = strlen(linkinfo->L_gen.g_attrfnam_p) +
8604 strlen(linkinfo->L_gen.g_attrnam_p) + 2;
8605 linklen = linkstringlen + sizeof (struct xattr_buf);
8606 len += linklen;
8607 } else {
8608 linklen = 0;
8612 * Now add padding to end to fill out TBLOCK
8614 * Function returns size of real data and not size + padding.
8617 totalen = ROUNDTOTBLOCK(len);
8618 bufhead = e_zalloc(E_EXIT, totalen);
8621 * Now we can fill in the necessary pieces
8625 * first fill in the fixed header
8627 hptr = (struct xattr_hdr *)bufhead;
8628 (void) strcpy(hptr->h_version, XATTR_ARCH_VERS);
8629 (void) sprintf(hptr->h_component_len, "%0*d",
8630 sizeof (hptr->h_component_len) - 1, complen);
8631 (void) sprintf(hptr->h_link_component_len, "%0*d",
8632 sizeof (hptr->h_link_component_len) - 1, linklen);
8633 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
8636 * Now fill in the filename + attrnames section
8637 * The filename and attrnames section can be composed of two or more
8638 * path segments separated by a null character. The first segment
8639 * is the path to the parent file that roots the entire sequence in
8640 * the normal name space. The remaining segments describes a path
8641 * rooted at the hidden extended attribute directory of the leaf file of
8642 * the previous segment, making it possible to name attributes on
8643 * attributes. Thus, if we are just archiving an extended attribute,
8644 * the second segment will contain the attribute name. If we are
8645 * archiving a system attribute of an extended attribute, then the
8646 * second segment will contain the attribute name, and a third segment
8647 * will contain the system attribute name. The attribute pathing
8648 * information is obtained from 'attrpath'.
8651 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
8652 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
8653 stringlen);
8654 (void) strcpy(tptr->h_names, filename);
8655 attrnames_index = strlen(filename) + 1;
8656 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
8657 tptr->h_typeflag = typeflag;
8660 * Split the attrnames section into two segments if 'attrpath'
8661 * contains pathing information for a system attribute of an
8662 * extended attribute. We split them by replacing the '/' with
8663 * a '\0'.
8665 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
8666 *aptr = '\0';
8670 * Now fill in the optional link section if we have one
8673 if (linkinfo != NULL) {
8674 tptr = (struct xattr_buf *)(bufhead +
8675 sizeof (struct xattr_hdr) + complen);
8677 (void) sprintf(tptr->h_namesz, "%0*d",
8678 sizeof (tptr->h_namesz) - 1, linkstringlen);
8679 (void) strcpy(tptr->h_names, linkinfo->L_gen.g_attrfnam_p);
8680 (void) strcpy(
8681 &tptr->h_names[strlen(linkinfo->L_gen.g_attrfnam_p) + 1],
8682 linkinfo->L_gen.g_attrnam_p);
8683 tptr->h_typeflag = typeflag;
8685 *attrbuf = (char *)bufhead;
8686 *rlen = len;
8688 #endif /* O_XATTR */
8690 static char
8691 tartype(int type)
8693 switch (type) {
8695 case S_IFDIR:
8696 return (DIRTYPE);
8698 case S_IFLNK:
8699 return (SYMTYPE);
8701 case S_IFIFO:
8702 return (FIFOTYPE);
8704 case S_IFCHR:
8705 return (CHRTYPE);
8707 case S_IFBLK:
8708 return (BLKTYPE);
8710 case S_IFREG:
8711 return (REGTYPE);
8713 default:
8714 return ('\0');
8718 #if defined(O_XATTR)
8719 static int
8720 openfile(int omode)
8722 if (G_p->g_attrnam_p != NULL) {
8723 return (openat(G_p->g_dirfd, G_p->g_attrnam_p, omode));
8724 } else {
8725 return (openat(G_p->g_dirfd,
8726 get_component(G_p->g_nam_p), omode));
8729 #else
8730 static int
8731 openfile(int omode)
8733 return (openat(G_p->g_dirfd, get_component(G_p->g_nam_p), omode));
8735 #endif
8737 #if defined(O_XATTR)
8738 static int
8739 read_xattr_hdr()
8741 off_t bytes;
8742 int comp_len, link_len;
8743 int namelen;
8744 int asz;
8745 int cnt;
8746 char *tp;
8747 char *xattrapath;
8748 int pad;
8749 int parentfilelen;
8752 * Include any padding in the read. We need to be positioned
8753 * at beginning of next header.
8756 bytes = Gen.g_filesz;
8758 if ((xattrhead = e_zalloc(E_NORMAL, (size_t)bytes)) == NULL) {
8759 (void) fprintf(stderr, gettext(
8760 "Insufficient memory for extended attribute\n"));
8761 return (1);
8764 tp = (char *)xattrhead;
8765 while (bytes > 0) {
8766 cnt = (int)(bytes > CPIOBSZ) ? CPIOBSZ : bytes;
8767 FILL(cnt);
8768 (void) memcpy(tp, Buffr.b_out_p, cnt);
8769 tp += cnt;
8770 Buffr.b_out_p += cnt;
8771 Buffr.b_cnt -= (off_t)cnt;
8772 bytes -= (off_t)cnt;
8775 pad = (Pad_val + 1 - (Gen.g_filesz & Pad_val)) &
8776 Pad_val;
8777 if (pad != 0) {
8778 FILL(pad);
8779 Buffr.b_out_p += pad;
8780 Buffr.b_cnt -= (off_t)pad;
8784 * Validate that we can handle header format
8787 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8788 (void) fprintf(stderr,
8789 gettext("Unknown extended attribute format encountered\n"));
8790 (void) fprintf(stderr,
8791 gettext("Disabling extended attribute header parsing\n"));
8792 xattrbadhead = 1;
8793 return (1);
8795 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8796 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8797 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8798 sizeof (struct xattr_hdr));
8799 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8800 if (link_len > 0) {
8801 xattr_linkp = (struct xattr_buf *)((int)xattrp + (int)comp_len);
8802 } else {
8803 xattr_linkp = NULL;
8807 * Gather the attribute path from the filename and attrnames section.
8808 * The filename and attrnames section can be composed of two or more
8809 * path segments separated by a null character. The first segment
8810 * is the path to the parent file that roots the entire sequence in
8811 * the normal name space. The remaining segments describes a path
8812 * rooted at the hidden extended attribute directory of the leaf file of
8813 * the previous segment, making it possible to name attributes on
8814 * attributes.
8816 parentfilelen = strlen(xattrp->h_names);
8817 xattrapath = xattrp->h_names + parentfilelen + 1;
8818 asz = strlen(xattrapath);
8819 if ((asz + parentfilelen + 2) < namelen) {
8821 * The attrnames section contains a system attribute on an
8822 * attribute. Save the name of the attribute for use later,
8823 * and replace the null separating the attribute name from
8824 * the system attribute name with a '/' so that xattrapath can
8825 * be used to display messages with the full attribute path name
8826 * rooted at the hidden attribute directory of the base file
8827 * in normal name space.
8829 xattrapath[asz] = '/';
8832 return (0);
8834 #endif
8836 static mode_t
8837 attrmode(char type)
8839 mode_t mode;
8841 switch (type) {
8842 case '\0':
8843 case REGTYPE:
8844 case LNKTYPE:
8845 mode = S_IFREG;
8846 break;
8848 case SYMTYPE:
8849 mode = S_IFLNK;
8850 break;
8852 case CHRTYPE:
8853 mode = S_IFCHR;
8854 break;
8855 case BLKTYPE:
8856 mode = S_IFBLK;
8857 break;
8858 case DIRTYPE:
8859 mode = S_IFDIR;
8860 break;
8861 case FIFOTYPE:
8862 mode = S_IFIFO;
8863 break;
8864 case CONTTYPE:
8865 default:
8866 mode = 0;
8869 return (mode);
8872 #if defined(O_XATTR)
8873 static char *
8874 get_component(char *path)
8876 char *ptr;
8878 ptr = strrchr(path, '/');
8879 if (ptr == NULL) {
8880 return (path);
8881 } else {
8883 * Handle trailing slash
8885 if (*(ptr + 1) == '\0')
8886 return (ptr);
8887 else
8888 return (ptr + 1);
8891 #else
8892 static char *
8893 get_component(char *path)
8895 return (path);
8897 #endif
8899 static int
8900 open_dir(char *name)
8902 int fd = -1;
8903 int cnt = 0;
8904 char *dir;
8906 dir = e_zalloc(E_EXIT, strlen(name) + 1);
8909 * open directory; creating missing directories along the way.
8911 get_parent(name, dir);
8912 do {
8913 fd = open(dir, O_RDONLY);
8914 if (fd != -1) {
8915 free(dir);
8916 return (fd);
8918 cnt++;
8919 } while (cnt <= 1 && missdir(name) == 0);
8921 free(dir);
8922 return (-1);
8925 static int
8926 open_dirfd()
8928 #ifdef O_XATTR
8929 if ((Args & OCt) == 0) {
8930 close_dirfd();
8931 if (G_p->g_attrnam_p != NULL) {
8932 int rw_sysattr;
8935 * Open the file's attribute directory.
8936 * Change into the base file's starting directory then
8937 * call open_attr_dir() to open the attribute directory
8938 * of either the base file (if G_p->g_attrparent_p is
8939 * NULL) or the attribute (if G_p->g_attrparent_p is
8940 * set) of the base file.
8942 (void) fchdir(G_p->g_baseparent_fd);
8943 (void) open_attr_dir(G_p->g_attrnam_p,
8944 G_p->g_attrfnam_p, G_p->g_baseparent_fd,
8945 (G_p->g_attrparent_p == NULL) ? NULL :
8946 G_p->g_attrparent_p, &G_p->g_dirfd, &rw_sysattr);
8947 if (Args & OCi) {
8948 int saveerrno = errno;
8950 (void) fchdir(G_p->g_baseparent_fd);
8951 errno = saveerrno;
8953 if ((G_p->g_dirfd == -1) && (Args & (OCi | OCp))) {
8954 msg(ERRN,
8955 "Cannot open attribute directory "
8956 "of %s%s%sfile \"%s\"",
8957 (G_p->g_attrparent_p == NULL) ? "" :
8958 gettext("attribute \""),
8959 (G_p->g_attrparent_p == NULL) ? "" :
8960 G_p->g_attrparent_p,
8961 (G_p->g_attrparent_p == NULL) ? "" :
8962 gettext("\" of "),
8963 G_p->g_attrfnam_p);
8964 return (FILE_PASS_ERR);
8966 } else {
8967 G_p->g_dirfd = open_dir(G_p->g_nam_p);
8968 if (G_p->g_dirfd == -1) {
8969 msg(ERRN,
8970 "Cannot open/create %s", G_p->g_nam_p);
8971 return (1);
8974 } else {
8975 G_p->g_dirfd = -1;
8977 #else
8978 G_p->g_dirfd = -1;
8979 #endif
8980 return (0);
8983 static void
8984 close_dirfd()
8986 if (G_p->g_dirfd != -1) {
8987 (void) close(G_p->g_dirfd);
8988 G_p->g_dirfd = -1;
8992 static void
8993 write_xattr_hdr()
8995 char *attrbuf = NULL;
8996 int attrlen = 0;
8997 char *namep;
8998 struct Lnk *tl_p, *linkinfo;
9001 * namep was allocated in xattrs_out. It is big enough to hold
9002 * either the name + .hdr on the end or just the attr name
9005 #if defined(O_XATTR)
9006 namep = Gen.g_nam_p;
9007 (void) creat_hdr();
9009 if (Args & OCo) {
9010 linkinfo = NULL;
9011 tl_p = Lnk_hd.L_nxt_p;
9012 while (tl_p != &Lnk_hd) {
9013 if (tl_p->L_gen.g_ino == G_p->g_ino &&
9014 tl_p->L_gen.g_dev == G_p->g_dev) {
9015 linkinfo = tl_p;
9016 break; /* found */
9018 tl_p = tl_p->L_nxt_p;
9020 prepare_xattr_hdr(&attrbuf, Gen.g_attrfnam_p,
9021 Gen.g_attrpath_p,
9022 (linkinfo == NULL) ?
9023 tartype(Gen.g_mode & Ftype) : LNKTYPE,
9024 linkinfo, &attrlen);
9025 Gen.g_filesz = attrlen;
9026 write_hdr(ARCHIVE_XATTR, (off_t)attrlen);
9027 /*LINTED*/
9028 (void) sprintf(namep, "%s/%s", DEVNULL, Gen.g_attrnam_p);
9029 write_ancillary(attrbuf, attrlen, B_TRUE);
9032 (void) creat_hdr();
9033 #endif
9037 * skip over extra slashes in string.
9039 * For example:
9040 * /usr/tmp/////
9042 * would return pointer at
9043 * /usr/tmp/////
9046 static char *
9047 skipslashes(char *string, char *start)
9049 while ((string > start) && *(string - 1) == '/') {
9050 string--;
9053 return (string);
9056 static sl_info_t *
9057 sl_info_alloc(void)
9059 static int num_left;
9060 static sl_info_t *slipool;
9062 if (num_left > 0) {
9063 return (&slipool[--num_left]);
9065 num_left = SL_INFO_ALLOC_CHUNK;
9066 slipool = e_zalloc(E_EXIT, sizeof (sl_info_t) * num_left);
9067 return (&slipool[--num_left]);
9071 * If a match for the key values was found in the tree, return a pointer to it.
9072 * If a match was not found, insert it and return a pointer to it. This is
9073 * based on Knuth's Algorithm A in Vol 3, section 6.2.3.
9076 sl_info_t *
9077 sl_insert(dev_t device, ino_t inode, int ftype)
9079 sl_info_t *p; /* moves down the tree */
9080 sl_info_t *q; /* scratch */
9081 sl_info_t *r; /* scratch */
9082 sl_info_t *s; /* pt where rebalancing may be needed */
9083 sl_info_t *t; /* father of s */
9084 sl_info_t *head;
9086 int a; /* used to hold balance factors */
9087 int done; /* loop control */
9088 int cmpflg; /* used to hold the result of a comparison */
9090 /* initialize */
9092 head = sl_devhash_lookup(device);
9094 if (head == NULL) {
9095 head = sl_info_alloc();
9096 head->llink = NULL;
9097 head->bal = 0;
9099 p = head->rlink = sl_info_alloc();
9100 p->sl_ino = inode;
9101 p->sl_ftype = ftype;
9102 p->sl_count = 0;
9103 p->bal = 0;
9104 p->llink = NULL;
9105 p->rlink = NULL;
9106 sl_devhash_insert(device, head);
9107 return (p);
9110 t = head;
9111 s = p = head->rlink;
9113 /* compare */
9115 for (done = 0; ! done; ) {
9116 switch (sl_compare(inode, ftype, p->sl_ino, p->sl_ftype)) {
9117 case -1:
9118 /* move left */
9120 q = p->llink;
9122 if (q == NULL) {
9123 q = sl_info_alloc();
9124 p->llink = q;
9125 done = 1;
9126 continue;
9129 break;
9131 case 0:
9132 /* found it */
9133 return (p);
9135 case 1:
9136 /* move right */
9138 q = p->rlink;
9140 if (q == NULL) {
9141 q = sl_info_alloc();
9142 p->rlink = q;
9143 done = 1;
9144 continue;
9147 break;
9150 if (q->bal != 0) {
9151 t = p;
9152 s = q;
9155 p = q;
9158 /* insert */
9160 q->sl_ino = inode;
9161 q->sl_ftype = ftype;
9162 q->sl_count = 0;
9163 q->llink = q->rlink = NULL;
9164 q->bal = 0;
9166 /* adjust balance factors */
9168 if ((cmpflg = sl_compare(inode, ftype, s->sl_ino, s->sl_ftype)) < 0) {
9169 r = p = s->llink;
9170 } else {
9171 r = p = s->rlink;
9174 while (p != q) {
9175 switch (sl_compare(inode, ftype, p->sl_ino, p->sl_ftype)) {
9176 case -1:
9177 p->bal = -1;
9178 p = p->llink;
9179 break;
9181 case 0:
9182 break;
9184 case 1:
9185 p->bal = 1;
9186 p = p->rlink;
9187 break;
9191 /* balancing act */
9193 if (cmpflg < 0) {
9194 a = -1;
9195 } else {
9196 a = 1;
9199 if (s->bal == 0) {
9200 s->bal = a;
9201 head->llink = (sl_info_t *)((int)head->llink + 1);
9202 return (q);
9203 } else if (s->bal == -a) {
9204 s->bal = 0;
9205 return (q);
9209 * (s->bal == a)
9212 if (r->bal == a) {
9213 /* single rotation */
9215 p = r;
9217 if (a == -1) {
9218 s->llink = r->rlink;
9219 r->rlink = s;
9220 } else if (a == 1) {
9221 s->rlink = r->llink;
9222 r->llink = s;
9225 s->bal = r->bal = 0;
9227 } else if (r->bal == -a) {
9228 /* double rotation */
9230 if (a == -1) {
9231 p = r->rlink;
9232 r->rlink = p->llink;
9233 p->llink = r;
9234 s->llink = p->rlink;
9235 p->rlink = s;
9236 } else if (a == 1) {
9237 p = r->llink;
9238 r->llink = p->rlink;
9239 p->rlink = r;
9240 s->rlink = p->llink;
9241 p->llink = s;
9244 if (p->bal == 0) {
9245 s->bal = 0;
9246 r->bal = 0;
9247 } else if (p->bal == -a) {
9248 s->bal = 0;
9249 r->bal = a;
9250 } else if (p->bal == a) {
9251 s->bal = -a;
9252 r->bal = 0;
9255 p->bal = 0;
9258 /* finishing touch */
9260 if (s == t->rlink) {
9261 t->rlink = p;
9262 } else {
9263 t->llink = p;
9266 return (q);
9270 * sl_numlinks: return the number of links that we saw during our preview.
9273 static ulong_t
9274 sl_numlinks(dev_t device, ino_t inode, int ftype)
9276 sl_info_t *p = sl_search(device, inode, ftype);
9278 if (p) {
9279 return (p->sl_count);
9280 } else {
9281 return (1);
9286 * Preview extended and extended system attributes.
9288 * Return 0 if successful, otherwise return 1.
9290 #if defined(O_XATTR)
9291 static int
9292 preview_attrs(char *s, char *attrparent)
9294 char *filename = (attrparent == NULL) ? s : attrparent;
9295 int dirfd;
9296 int tmpfd;
9297 int islnk;
9298 int rc = 0;
9299 int arc_rwsysattr = 0;
9300 int rw_sysattr = 0;
9301 int ext_attr = 0;
9302 DIR *dirp;
9303 struct dirent *dp;
9304 struct stat sb;
9307 * If the underlying file system supports it, then
9308 * archive the extended attributes if -@ was specified,
9309 * and the extended system attributes if -/ was
9310 * specified.
9312 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
9313 &ext_attr) != ATTR_OK) {
9314 return (1);
9317 #if defined(_PC_SATTR_ENABLED)
9318 if (SysAtflag) {
9319 int filefd;
9320 nvlist_t *slist = NULL;
9322 /* Determine if there are non-transient system attributes. */
9323 errno = 0;
9324 if ((filefd = open(filename, O_RDONLY)) < 0) {
9325 return (1);
9327 if (((slist = sysattr_list(myname, filefd,
9328 filename)) != NULL) || (errno != 0)) {
9329 arc_rwsysattr = 1;
9331 if (slist != NULL) {
9332 (void) nvlist_free(slist);
9333 slist = NULL;
9335 (void) close(filefd);
9338 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
9339 (SysAtflag && !ext_attr))) {
9340 return (1);
9342 #endif /* _PC_SATTR_ENABLED */
9344 * We need to open the attribute directory of the
9345 * file, and preview all of the file's attributes as
9346 * attributes of the file can be hard links to other
9347 * attributes of the file.
9349 dirfd = attropen(filename, ".", O_RDONLY);
9350 if (dirfd == -1)
9351 return (1);
9353 tmpfd = dup(dirfd);
9354 if (tmpfd == -1) {
9355 (void) close(dirfd);
9356 return (1);
9358 dirp = fdopendir(tmpfd);
9359 if (dirp == NULL) {
9360 (void) close(dirfd);
9361 (void) close(tmpfd);
9362 return (1);
9365 while (dp = readdir(dirp)) {
9366 if (dp->d_name[0] == '.') {
9367 if (dp->d_name[1] == '\0') {
9368 Hiddendir = 1;
9369 } else if ((dp->d_name[1] == '.') &&
9370 (dp->d_name[2] == '\0')) {
9371 continue;
9372 } else {
9373 Hiddendir = 0;
9375 } else {
9376 Hiddendir = 0;
9379 if (fstatat(dirfd, dp->d_name, &sb,
9380 AT_SYMLINK_NOFOLLOW) < 0) {
9381 continue;
9384 if (verify_attr(dp->d_name, attrparent,
9385 arc_rwsysattr, &rw_sysattr) != ATTR_OK) {
9386 continue;
9389 islnk = 0;
9390 if (S_ISLNK(sb.st_mode)) {
9391 islnk = 1;
9392 if (Args & OCL) {
9393 if (fstatat(dirfd, dp->d_name,
9394 &sb, 0) < 0) {
9395 continue;
9399 sl_remember_tgt(&sb, islnk, rw_sysattr);
9402 * Recursively call preview_attrs() to preview extended
9403 * system attributes of attributes.
9405 if (SysAtflag && !Hiddendir && !rw_sysattr) {
9406 int my_cwd = save_cwd();
9408 (void) fchdir(dirfd);
9409 rc = preview_attrs(s, dp->d_name);
9410 rest_cwd(my_cwd);
9413 (void) closedir(dirp);
9414 (void) close(dirfd);
9415 return (rc);
9417 #endif /* O_XATTR */
9420 * sl_preview_synonyms: Read the file list from the input stream, remembering
9421 * each reference to each file.
9424 static void
9425 sl_preview_synonyms(void)
9427 char buf [APATH+1];
9428 char *s;
9430 char *suffix = "/cpioXXXXXX";
9431 char *tmpdir = getenv("TMPDIR");
9432 int tmpfd, islnk;
9433 FILE *tmpfile;
9434 char *tmpfname;
9436 if (tmpdir == NULL || *tmpdir == '\0' ||
9437 (strlen(tmpdir) + strlen(suffix)) > APATH) {
9438 struct statvfs tdsb;
9440 tmpdir = "/var/tmp";
9442 /* /var/tmp is read-only in the mini-root environment */
9444 if (statvfs(tmpdir, &tdsb) == -1 || tdsb.f_flag & ST_RDONLY) {
9445 tmpdir = "/tmp";
9449 tmpfname = e_zalloc(E_EXIT, strlen(tmpdir) + strlen(suffix) + 1);
9451 (void) strcpy(tmpfname, tmpdir);
9452 (void) strcat(tmpfname, suffix);
9454 if ((tmpfd = mkstemp(tmpfname)) == -1) {
9455 msg(EXTN, "cannot open tmpfile %s%s", tmpdir, suffix);
9458 if (unlink(tmpfname) == -1) {
9459 msg(EXTN, "cannot unlink tmpfile %s", tmpfname);
9462 if ((tmpfile = fdopen(tmpfd, "w+")) == NULL) {
9463 msg(EXTN, "cannot fdopen tmpfile %s", tmpfname);
9466 while ((s = fgets(buf, APATH+1, In_p)) != NULL) {
9467 size_t lastchar;
9468 struct stat sb;
9470 if (fputs(buf, tmpfile) == EOF) {
9471 msg(EXTN, "problem writing to tmpfile %s", tmpfname);
9474 /* pre-process the name */
9476 lastchar = strlen(s) - 1;
9478 if (s[lastchar] != '\n' && lastchar == APATH - 1) {
9479 continue;
9480 } else {
9481 s[lastchar] = '\0';
9484 while (s[0] == '.' && s[1] == '/') {
9485 s += 2;
9486 while (s[0] == '/') {
9487 s++;
9491 if (lstat(s, &sb) < 0) {
9492 continue;
9494 islnk = 0;
9495 if (S_ISLNK(sb.st_mode)) {
9496 islnk = 1;
9497 if (Args & OCL) {
9498 if (stat(s, &sb) < 0) {
9499 continue;
9503 sl_remember_tgt(&sb, islnk, 0);
9505 #if defined(O_XATTR)
9506 if (Atflag || SysAtflag) {
9507 (void) preview_attrs(s, NULL);
9509 #endif /* O_XATTR */
9512 if (ferror(In_p)) {
9513 msg(EXTN, "error reading stdin");
9516 if (fseek(tmpfile, 0L, SEEK_SET) == -1) {
9517 msg(EXTN, "cannot fseek on tmpfile %s", tmpfname);
9520 In_p = tmpfile;
9521 free(tmpfname);
9525 * sl_remember_tgt: Add the device/inode for lstat or stat info to the list of
9526 * those we've seen before.
9528 * This tree (rooted under head) is keyed by the device/inode of the file
9529 * being pointed to. A count is kept of the number of references encountered
9530 * so far.
9533 static void
9534 sl_remember_tgt(const struct stat *sbp, int isSymlink, int is_sysattr)
9536 sl_info_t *p;
9537 dev_t device;
9538 ino_t inode;
9539 int ftype;
9541 device = sbp->st_dev;
9542 inode = sbp->st_ino;
9543 ftype = sbp->st_mode & Ftype;
9545 /* Determine whether we've seen this one before */
9547 p = sl_insert(device, inode, ftype);
9549 if (p->sl_count > 0) {
9551 * It appears as if have seen this file before as we found a
9552 * matching device, inode, and file type as a file already
9553 * processed. Since there can possibly be files with the
9554 * same device, inode, and file type, but aren't hard links
9555 * (e.g., read-write system attribute files will always have
9556 * the same inode), we need to only attempt to add one to the
9557 * link count if the file we are processing is a hard link
9558 * (i.e., st_nlink > 1).
9560 * Note that if we are not chasing symlinks, and this one is a
9561 * symlink, it is identically the one we saw before (you cannot
9562 * have hard links to symlinks); in this case, we leave the
9563 * count alone, so that we don't wind up archiving a symlink to
9564 * itself.
9567 if (((Args & OCL) || (! isSymlink)) && !is_sysattr) {
9568 p->sl_count++;
9570 } else {
9571 /* We have not seen this file before */
9573 p->sl_count = 1;
9575 if (Use_old_stat) {
9576 /* -Hodc: remap inode (-1 on overflow) */
9578 sl_remap_t *q;
9580 for (q = sl_remap_head; q && (q->dev != device);
9581 q = q->next) {
9582 /* do nothing */
9585 if (q == NULL) {
9586 q = e_zalloc(E_EXIT, sizeof (sl_remap_t));
9587 q->dev = device;
9588 p->sl_ino2 = q->inode_count = 1;
9590 q->next = (sl_remap_head) ?
9591 sl_remap_head->next : NULL;
9592 sl_remap_head = q;
9593 } else {
9594 if ((size_t)q->inode_count <=
9595 ((1 << (sizeof (o_ino_t) * 8)) - 1)) {
9596 /* fits in o_ino_t */
9597 p->sl_ino2 = ++(q->inode_count);
9598 } else {
9599 p->sl_ino2 = (ino_t)-1;
9607 * A faster search, which does not insert the key values into the tree.
9608 * If the a match was found in the tree, return a pointer to it. If it was not
9609 * found, return NULL.
9612 sl_info_t *
9613 sl_search(dev_t device, ino_t inode, int ftype)
9615 sl_info_t *p; /* moves down the tree */
9616 int c; /* comparison value */
9617 sl_info_t *retval = NULL; /* return value */
9618 sl_info_t *head;
9620 head = sl_devhash_lookup(device);
9621 if (head != NULL) {
9622 for (p = head->rlink; p; ) {
9623 if ((c = sl_compare(inode, ftype, p->sl_ino,
9624 p->sl_ftype)) == 0) {
9625 retval = p;
9626 break;
9627 } else if (c < 0) {
9628 p = p->llink;
9629 } else {
9630 p = p->rlink;
9635 return (retval);
9638 static sl_info_t *
9639 sl_devhash_lookup(dev_t device)
9641 int key;
9642 sl_info_link_t *lp;
9643 static sl_info_link_t *devcache;
9645 if (devcache != NULL && devcache->dev == device) {
9646 return (devcache->head);
9649 key = DEV_HASHKEY(device);
9650 for (lp = sl_devhash[key]; lp; lp = lp->next) {
9651 if (lp->dev == device) {
9652 devcache = lp;
9653 return (lp->head);
9656 return (NULL);
9659 static void
9660 sl_devhash_insert(dev_t device, sl_info_t *head)
9662 int key = DEV_HASHKEY(device);
9663 sl_info_link_t *lp;
9665 lp = e_zalloc(E_EXIT, sizeof (sl_info_link_t));
9666 lp->dev = device;
9667 lp->head = head;
9668 lp->next = sl_devhash[key];
9669 sl_devhash[key] = lp;
9672 static void
9673 chop_endslashes(char *path)
9675 char *end, *ptr;
9677 end = &path[strlen(path) -1];
9678 if (*end == '/' && end != path) {
9679 ptr = skipslashes(end, path);
9680 if (ptr != NULL && ptr != path) {
9681 *ptr = '\0';
9686 #if !defined(O_XATTR)
9688 openat64(int fd, char *name, int oflag, mode_t cmode)
9690 return (open64(name, oflag, cmode));
9694 openat(int fd, char *name, int oflag, mode_t cmode)
9696 return (open(name, oflag, cmode));
9700 fchownat(int fd, char *name, uid_t owner, gid_t group, int flag)
9702 if (flag == AT_SYMLINK_NOFOLLOW)
9703 return (lchown(name, owner, group));
9704 else
9705 return (chown(name, owner, group));
9709 renameat(int fromfd, char *old, int tofd, char *new)
9711 return (rename(old, new));
9715 futimesat(int fd, char *path, struct timeval times[2])
9717 return (utimes(path, times));
9721 unlinkat(int dirfd, char *path, int flag)
9723 if (flag == AT_REMOVEDIR) {
9724 return (rmdir(path));
9725 } else {
9726 return (unlink(path));
9731 fstatat(int fd, char *path, struct stat *buf, int flag)
9733 if (flag == AT_SYMLINK_NOFOLLOW)
9734 return (lstat(path, buf));
9735 else
9736 return (stat(path, buf));
9740 attropen(char *file, char *attr, int omode, mode_t cmode)
9742 errno = ENOTSUP;
9743 return (-1);
9745 #endif