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