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) 2013, Joyent, Inc. All rights reserved.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /* Copyright (c) 1987, 1988 Microsoft Corporation */
31 /* All Rights Reserved */
32
33 /*
34 * Portions of this source code were derived from Berkeley 4.3 BSD
35 * under license from the Regents of the University of California.
36 */
37
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/stat.h>
42 #include <sys/mkdev.h>
43 #include <sys/wait.h>
44 #include <dirent.h>
45 #include <errno.h>
46 #include <stdio.h>
47 #include <signal.h>
48 #include <ctype.h>
49 #include <locale.h>
50 #include <nl_types.h>
51 #include <langinfo.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <fcntl.h>
55 #include <string.h>
56 #include <malloc.h>
57 #include <time.h>
58 #include <utime.h>
59 #include <stdlib.h>
60 #include <stdarg.h>
61 #include <widec.h>
62 #include <sys/mtio.h>
63 #include <sys/acl.h>
64 #include <strings.h>
65 #include <deflt.h>
66 #include <limits.h>
67 #include <iconv.h>
68 #include <assert.h>
69 #include <libgen.h>
70 #include <libintl.h>
71 #include <aclutils.h>
72 #include <libnvpair.h>
73 #include <archives.h>
74
75 #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
76 extern int defcntl();
77 #endif
78 #if defined(_PC_SATTR_ENABLED)
79 #include <attr.h>
80 #include <libcmdutils.h>
81 #endif
82
83 /* Trusted Extensions */
84 #include <zone.h>
85 #include <tsol/label.h>
86 #include <sys/tsol/label_macro.h>
87
88 #include "getresponse.h"
89 /*
90 * Source compatibility
91 */
92
93 /*
94 * These constants come from archives.h and sys/fcntl.h
95 * and were introduced by the extended attributes project
96 * in Solaris 9.
97 */
98 #if !defined(O_XATTR)
99 #define AT_SYMLINK_NOFOLLOW 0x1000
100 #define AT_REMOVEDIR 0x1
101 #define AT_FDCWD 0xffd19553
102 #define _XATTR_HDRTYPE 'E'
103 static int attropen();
104 static int fstatat();
105 static int renameat();
106 static int unlinkat();
107 static int openat();
108 static int fchownat();
109 static int futimesat();
110 #endif
111
112 /*
113 * Compiling with -D_XPG4_2 gets this but produces other problems, so
114 * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
115 * explicitly doing the declaration here.
116 */
117 int utimes(const char *path, const struct timeval timeval_ptr[]);
118
119 #ifndef MINSIZE
120 #define MINSIZE 250
121 #endif
122 #define DEF_FILE "/etc/default/tar"
123
124 #define min(a, b) ((a) < (b) ? (a) : (b))
125 #define max(a, b) ((a) > (b) ? (a) : (b))
126
127 /* -DDEBUG ONLY for debugging */
128 #ifdef DEBUG
129 #undef DEBUG
130 #define DEBUG(a, b, c)\
131 (void) fprintf(stderr, "DEBUG - "), (void) fprintf(stderr, a, b, c)
132 #endif
133
134 #define TBLOCK 512 /* tape block size--should be universal */
135
136 #ifdef BSIZE
137 #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
138 #else /* BSIZE */
139 #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
140 #endif /* BSIZE */
141
142 #define NBLOCK 20
143 #define NAMSIZ 100
144 #define PRESIZ 155
145 #define MAXNAM 256
146 #define MODEMASK 0777777 /* file creation mode mask */
147 #define POSIXMODES 07777 /* mask for POSIX mode bits */
148 #define MAXEXT 9 /* reasonable max # extents for a file */
149 #define EXTMIN 50 /* min blks left on floppy to split a file */
150
151 /* max value dblock.dbuf.efsize can store */
152 #define TAR_EFSIZE_MAX 0777777777
153
154 /*
155 * Symbols which specify the values at which the use of the 'E' function
156 * modifier is required to properly store a file.
157 *
158 * TAR_OFFSET_MAX - the largest file size we can archive
159 * OCTAL7CHAR - the limit for ustar gid, uid, dev
160 */
161
162 #ifdef XHDR_DEBUG
163 /* tiny values which force the creation of extended header entries */
164 #define TAR_OFFSET_MAX 9
165 #define OCTAL7CHAR 2
166 #else
167 /* normal values */
168 #define TAR_OFFSET_MAX 077777777777ULL
169 #define OCTAL7CHAR 07777777
170 #endif
171
172 #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
173 #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
174
175 #define MAXLEV (PATH_MAX / 2)
176 #define LEV0 1
177 #define SYMLINK_LEV0 0
178
179 #define TRUE 1
180 #define FALSE 0
181
182 #define XATTR_FILE 1
183 #define NORMAL_FILE 0
184
185 #define PUT_AS_LINK 1
186 #define PUT_NOTAS_LINK 0
187
188 #ifndef VIEW_READONLY
189 #define VIEW_READONLY "SUNWattr_ro"
190 #endif
191
192 #ifndef VIEW_READWRITE
193 #define VIEW_READWRITE "SUNWattr_rw"
194 #endif
195
196 #if _FILE_OFFSET_BITS == 64
197 #define FMT_off_t "lld"
198 #define FMT_off_t_o "llo"
199 #define FMT_blkcnt_t "lld"
200 #else
201 #define FMT_off_t "ld"
202 #define FMT_off_t_o "lo"
203 #define FMT_blkcnt_t "ld"
204 #endif
205
206 /* ACL support */
207
208 static
209 struct sec_attr {
210 char attr_type;
211 char attr_len[7];
212 char attr_info[1];
213 } *attr;
214
215 #if defined(O_XATTR)
216 typedef enum {
217 ATTR_OK,
218 ATTR_SKIP,
219 ATTR_CHDIR_ERR,
220 ATTR_OPEN_ERR,
221 ATTR_XATTR_ERR,
222 ATTR_SATTR_ERR
223 } attr_status_t;
224 #endif
225
226 #if defined(O_XATTR)
227 typedef enum {
228 ARC_CREATE,
229 ARC_RESTORE
230 } arc_action_t;
231 #endif
232
233 typedef struct attr_data {
234 char *attr_parent;
235 char *attr_path;
236 int attr_parentfd;
237 int attr_rw_sysattr;
238 } attr_data_t;
239
240 /*
241 *
242 * Tar has been changed to support extended attributes.
243 *
244 * As part of this change tar now uses the new *at() syscalls
245 * such as openat, fchownat(), unlinkat()...
246 *
247 * This was done so that attributes can be handled with as few code changes
248 * as possible.
249 *
250 * What this means is that tar now opens the directory that a file or directory
251 * resides in and then performs *at() functions to manipulate the entry.
252 *
253 * For example a new file is now created like this:
254 *
255 * dfd = open(<some dir path>)
256 * fd = openat(dfd, <name>,....);
257 *
258 * or in the case of an extended attribute
259 *
260 * dfd = attropen(<pathname>, ".", ....)
261 *
262 * Once we have a directory file descriptor all of the *at() functions can
263 * be applied to it.
264 *
265 * unlinkat(dfd, <component name>,...)
266 * fchownat(dfd, <component name>,..)
267 *
268 * This works for both normal namespace files and extended attribute file
269 *
270 */
271
272 /*
273 *
274 * Extended attribute Format
275 *
276 * Extended attributes are stored in two pieces.
277 * 1. An attribute header which has information about
278 * what file the attribute is for and what the attribute
279 * is named.
280 * 2. The attribute record itself. Stored as a normal file type
281 * of entry.
282 * Both the header and attribute record have special modes/typeflags
283 * associated with them.
284 *
285 * The names of the header in the archive look like:
286 * /dev/null/attr.hdr
287 *
288 * The name of the attribute looks like:
289 * /dev/null/attr
290 *
291 * This is done so that an archiver that doesn't understand these formats
292 * can just dispose of the attribute records.
293 *
294 * The format is composed of a fixed size header followed
295 * by a variable sized xattr_buf. If the attribute is a hard link
296 * to another attribute then another xattr_buf section is included
297 * for the link.
298 *
299 * The xattr_buf is used to define the necessary "pathing" steps
300 * to get to the extended attribute. This is necessary to support
301 * a fully recursive attribute model where an attribute may itself
302 * have an attribute.
303 *
304 * The basic layout looks like this.
305 *
306 * --------------------------------
307 * | |
308 * | xattr_hdr |
309 * | |
310 * --------------------------------
311 * --------------------------------
312 * | |
313 * | xattr_buf |
314 * | |
315 * --------------------------------
316 * --------------------------------
317 * | |
318 * | (optional link info) |
319 * | |
320 * --------------------------------
321 * --------------------------------
322 * | |
323 * | attribute itself |
324 * | stored as normal tar |
325 * | or cpio data with |
326 * | special mode or |
327 * | typeflag |
328 * | |
329 * --------------------------------
330 *
331 */
332
333 /*
334 * xattrhead is a pointer to the xattr_hdr
335 *
336 * xattrp is a pointer to the xattr_buf structure
337 * which contains the "pathing" steps to get to attributes
338 *
339 * xattr_linkp is a pointer to another xattr_buf structure that is
340 * only used when an attribute is actually linked to another attribute
341 *
342 */
343
344 static struct xattr_hdr *xattrhead;
345 static struct xattr_buf *xattrp;
346 static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
347 static char *xattrapath; /* attribute name */
348 static char *xattr_linkaname; /* attribute attribute is linked to */
349 static char Hiddendir; /* are we processing hidden xattr dir */
350 static char xattrbadhead;
351
352 /* Was statically allocated tbuf[NBLOCK] */
353 static
354 union hblock {
355 char dummy[TBLOCK];
356 struct header {
357 char name[NAMSIZ]; /* If non-null prefix, path is */
358 /* <prefix>/<name>; otherwise */
359 /* <name> */
360 char mode[8];
361 char uid[8];
362 char gid[8];
363 char size[12]; /* size of this extent if file split */
364 char mtime[12];
365 char chksum[8];
366 char typeflag;
367 char linkname[NAMSIZ];
368 char magic[6];
369 char version[2];
370 char uname[32];
371 char gname[32];
372 char devmajor[8];
373 char devminor[8];
374 char prefix[PRESIZ]; /* Together with "name", the path of */
375 /* the file: <prefix>/<name> */
376 char extno; /* extent #, null if not split */
377 char extotal; /* total extents */
378 char efsize[10]; /* size of entire file */
379 } dbuf;
380 } dblock, *tbuf, xhdr_buf;
381
382 static
383 struct xtar_hdr {
384 uid_t x_uid, /* Uid of file */
385 x_gid; /* Gid of file */
386 major_t x_devmajor; /* Device major node */
387 minor_t x_devminor; /* Device minor node */
388 off_t x_filesz; /* Length of file */
389 char *x_uname, /* Pointer to name of user */
390 *x_gname, /* Pointer to gid of user */
391 *x_linkpath, /* Path for a hard/symbolic link */
392 *x_path; /* Path of file */
393 timestruc_t x_mtime; /* Seconds and nanoseconds */
394 } Xtarhdr;
395
396 static
397 struct gen_hdr {
398 ulong_t g_mode; /* Mode of file */
399 uid_t g_uid, /* Uid of file */
400 g_gid; /* Gid of file */
401 off_t g_filesz; /* Length of file */
402 time_t g_mtime; /* Modification time */
403 uint_t g_cksum; /* Checksum of file */
404 ulong_t g_devmajor, /* File system of file */
405 g_devminor; /* Major/minor of special files */
406 } Gen;
407
408 static
409 struct linkbuf {
410 ino_t inum;
411 dev_t devnum;
412 int count;
413 char pathname[MAXNAM+1]; /* added 1 for last NULL */
414 char attrname[MAXNAM+1];
415 struct linkbuf *nextp;
416 } *ihead;
417
418 /* see comments before build_table() */
419 #define TABLE_SIZE 512
420 typedef struct file_list {
421 char *name; /* Name of file to {in,ex}clude */
422 struct file_list *next; /* Linked list */
423 } file_list_t;
424 static file_list_t *exclude_tbl[TABLE_SIZE],
425 *include_tbl[TABLE_SIZE];
426
427 static int append_secattr(char **, int *, int, char *, char);
428 static void write_ancillary(union hblock *, char *, int, char);
429
430 static void add_file_to_table(file_list_t *table[], char *str);
431 static void assert_string(char *s, char *msg);
432 static int istape(int fd, int type);
433 static void backtape(void);
434 static void build_table(file_list_t *table[], char *file);
435 static int check_prefix(char **namep, char **dirp, char **compp);
436 static void closevol(void);
437 static void copy(void *dst, void *src);
438 static int convtoreg(off_t);
439 static void delete_target(int fd, char *comp, char *namep);
440 static void doDirTimes(char *name, timestruc_t modTime);
441 static void done(int n);
442 static void dorep(char *argv[]);
443 static void dotable(char *argv[]);
444 static void doxtract(char *argv[]);
445 static int tar_chdir(const char *path);
446 static int is_directory(char *name);
447 static int has_dot_dot(char *name);
448 static int is_absolute(char *name);
449 static char *make_relative_name(char *name, char **stripped_prefix);
450 static void fatal(char *format, ...);
451 static void vperror(int exit_status, char *fmt, ...);
452 static void flushtape(void);
453 static void getdir(void);
454 static void *getmem(size_t);
455 static void longt(struct stat *st, char aclchar);
456 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
457 static int makeDir(char *name);
458 static void mterr(char *operation, int i, int exitcode);
459 static void newvol(void);
460 static void passtape(void);
461 static void putempty(blkcnt_t n);
462 static int putfile(char *longname, char *shortname, char *parent,
463 attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
464 static void readtape(char *buffer);
465 static void seekdisk(blkcnt_t blocks);
466 static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
467 static void setbytes_to_skip(struct stat *st, int err);
468 static void splitfile(char *longname, int ifd, char *name,
469 char *prefix, int filetype);
470 static void tomodes(struct stat *sp);
471 static void usage(void);
472 static int xblocks(int issysattr, off_t bytes, int ofile);
473 static int xsfile(int issysattr, int ofd);
474 static void resugname(int dirfd, char *name, int symflag);
475 static int bcheck(char *bstr);
476 static int checkdir(char *name);
477 static int checksum(union hblock *dblockp);
478 #ifdef EUC
479 static int checksum_signed(union hblock *dblockp);
480 #endif /* EUC */
481 static int checkupdate(char *arg);
482 static int checkw(char c, char *name);
483 static int cmp(char *b, char *s, int n);
484 static int defset(char *arch);
485 static int endtape(void);
486 static int is_in_table(file_list_t *table[], char *str);
487 static int notsame(void);
488 static int is_prefix(char *s1, char *s2);
489 static int response(void);
490 static int build_dblock(const char *, const char *, const char,
491 const int filetype, const struct stat *, const dev_t, const char *);
492 static unsigned int hash(char *str);
493
494 static blkcnt_t kcheck(char *kstr);
495 static off_t bsrch(char *s, int n, off_t l, off_t h);
496 static void onintr(int sig);
497 static void onquit(int sig);
498 static void onhup(int sig);
499 static uid_t getuidbyname(char *);
500 static gid_t getgidbyname(char *);
501 static char *getname(gid_t);
502 static char *getgroup(gid_t);
503 static int checkf(char *name, int mode, int howmuch);
504 static int writetbuf(char *buffer, int n);
505 static int wantit(char *argv[], char **namep, char **dirp, char **comp,
506 attr_data_t **attrinfo);
507 static void append_ext_attr(char *shortname, char **secinfo, int *len);
508 static int get_xdata(void);
509 static void gen_num(const char *keyword, const u_longlong_t number);
510 static void gen_date(const char *keyword, const timestruc_t time_value);
511 static void gen_string(const char *keyword, const char *value);
512 static void get_xtime(char *value, timestruc_t *xtime);
513 static int chk_path_build(char *name, char *longname, char *linkname,
514 char *prefix, char type, int filetype);
515 static int gen_utf8_names(const char *filename);
516 static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
517 const char *src, int max_val);
518 static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
519 iconv_t iconv_cd, int xhdrflg, int max_val);
520 static int c_utf8(char *target, const char *source);
521 static int getstat(int dirfd, char *longname, char *shortname,
522 char *attrparent);
523 static void xattrs_put(char *, char *, char *, char *);
524 static void prepare_xattr(char **, char *, char *,
525 char, struct linkbuf *, int *);
526 static int put_link(char *name, char *longname, char *component,
527 char *longattrname, char *prefix, int filetype, char typeflag);
528 static int put_extra_attributes(char *longname, char *shortname,
529 char *longattrname, char *prefix, int filetype, char typeflag);
530 static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
531 char *prefix, int typeflag, int filetype, struct linkbuf *lp);
532 static int read_xattr_hdr(attr_data_t **attrinfo);
533
534 /* Trusted Extensions */
535 #define AUTO_ZONE "/zone"
536
537 static void extract_attr(char **file_ptr, struct sec_attr *);
538 static int check_ext_attr(char *filename);
539 static void rebuild_comp_path(char *str, char **namep);
540 static int rebuild_lk_comp_path(char *str, char **namep);
541
542 static void get_parent(char *path, char *dir);
543 static char *get_component(char *path);
544 static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
545 char *name, int oflag, mode_t mode);
546 static char *skipslashes(char *string, char *start);
547 static void chop_endslashes(char *path);
548 static pid_t compress_file(void);
549 static void compress_back(void);
550 static void decompress_file(void);
551 static pid_t uncompress_file(void);
552 static void *compress_malloc(size_t);
553 static void check_compression(void);
554 static char *bz_suffix(void);
555 static char *gz_suffix(void);
556 static char *xz_suffix(void);
557 static char *add_suffix();
558 static void wait_pid(pid_t);
559 static void verify_compress_opt(const char *t);
560 static void detect_compress(void);
561
562 static struct stat stbuf;
563
564 static char *myname;
565 static char *xtract_chdir = NULL;
566 static int checkflag = 0;
567 static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
568 static int rflag, xflag, vflag, tflag, mt, svmt, cflag, mflag, pflag;
569 static int uflag;
570 static int errflag;
571 static int oflag;
572 static int bflag, Aflag;
573 static int Pflag; /* POSIX conformant archive */
574 static int Eflag; /* Allow files greater than 8GB */
575 static int atflag; /* traverse extended attributes */
576 static int saflag; /* traverse extended sys attributes */
577 static int Dflag; /* Data change flag */
578 static int jflag; /* flag to use 'bzip2' */
579 static int zflag; /* flag to use 'gzip' */
580 static int Zflag; /* flag to use 'compress' */
581 static int Jflag; /* flag to use 'xz' */
582 static int aflag; /* flag to use autocompression */
583
584 /* Trusted Extensions */
585 static int Tflag; /* Trusted Extensions attr flags */
586 static int dir_flag; /* for attribute extract */
587 static int mld_flag; /* for attribute extract */
588 static char *orig_namep; /* original namep - unadorned */
589 static int rpath_flag; /* MLD real path is rebuilt */
590 static char real_path[MAXPATHLEN]; /* MLD real path */
591 static int lk_rpath_flag; /* linked to real path is rebuilt */
592 static char lk_real_path[MAXPATHLEN]; /* linked real path */
593 static bslabel_t bs_label; /* for attribute extract */
594 static bslabel_t admin_low;
595 static bslabel_t admin_high;
596 static int ignored_aprivs = 0;
597 static int ignored_fprivs = 0;
598 static int ignored_fattrs = 0;
599
600 static int term, chksum, wflag,
601 first = TRUE, defaults_used = FALSE, linkerrok;
602 static blkcnt_t recno;
603 static int freemem = 1;
604 static int nblock = NBLOCK;
605 static int Errflg = 0;
606 static int exitflag = 0;
607
608 static dev_t mt_dev; /* device containing output file */
609 static ino_t mt_ino; /* inode number of output file */
610 static int mt_devtype; /* dev type of archive, from stat structure */
611
612 static int update = 1; /* for `open' call */
613
614 static off_t low;
615 static off_t high;
616
617 static FILE *tfile;
618 static FILE *vfile = stdout;
619 static char *tmpdir;
620 static char *tmp_suffix = "/tarXXXXXX";
621 static char *tname;
622 static char archive[] = "archive0=";
623 static char *Xfile;
624 static char *usefile;
625 static char tfname[1024];
626
627 static int mulvol; /* multi-volume option selected */
628 static blkcnt_t blocklim; /* number of blocks to accept per volume */
629 static blkcnt_t tapepos; /* current block number to be written */
630 static int NotTape; /* true if tape is a disk */
631 static int dumping; /* true if writing a tape or other archive */
632 static int extno; /* number of extent: starts at 1 */
633 static int extotal; /* total extents in this file */
634 static off_t extsize; /* size of current extent during extraction */
635 static ushort_t Oumask = 0; /* old umask value */
636 static int is_posix; /* true if archive we're reading is POSIX-conformant */
637 static const char *magic_type = "ustar";
638 static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */
639 static char *xrec_ptr;
640 static off_t xrec_offset = 0;
641 static int Xhdrflag;
642 static int charset_type = 0;
643
644 static u_longlong_t xhdr_flgs; /* Bits set determine which items */
645 /* need to be in extended header. */
646 #define _X_DEVMAJOR 0x1
647 #define _X_DEVMINOR 0x2
648 #define _X_GID 0x4
649 #define _X_GNAME 0x8
650 #define _X_LINKPATH 0x10
651 #define _X_PATH 0x20
652 #define _X_SIZE 0x40
653 #define _X_UID 0x80
654 #define _X_UNAME 0x100
655 #define _X_ATIME 0x200
656 #define _X_CTIME 0x400
657 #define _X_MTIME 0x800
658 #define _X_XHDR 0x1000 /* Bit flag that determines whether 'X' */
659 /* typeflag was followed by 'A' or non 'A' */
660 /* typeflag. */
661 #define _X_LAST 0x40000000
662
663 #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4)
664 #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4)
665 #define LONG_MAX_DIGITS (10 * sizeof (long) / 4)
666 #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4)
667 /*
668 * UTF_8 encoding requires more space than the current codeset equivalent.
669 * Currently a factor of 2-3 would suffice, but it is possible for a factor
670 * of 6 to be needed in the future, so for saftey, we use that here.
671 */
672 #define UTF_8_FACTOR 6
673
674 static u_longlong_t xhdr_count = 0;
675 static char xhdr_dirname[PRESIZ + 1];
676 static char pidchars[PID_MAX_DIGITS + 1];
677 static char *tchar = ""; /* null linkpath */
678
679 static char local_path[UTF_8_FACTOR * PATH_MAX + 1];
680 static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
681 static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
682 static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
683
684 /*
685 * The following mechanism is provided to allow us to debug tar in complicated
686 * situations, like when it is part of a pipe. The idea is that you compile
687 * with -DWAITAROUND defined, and then add the 'D' function modifier to the
688 * target tar invocation, eg. "tar cDf tarfile file". If stderr is available,
689 * it will tell you to which pid to attach the debugger; otherwise, use ps to
690 * find it. Attach to the process from the debugger, and, *PRESTO*, you are
691 * there!
692 *
693 * Simply assign "waitaround = 0" once you attach to the process, and then
694 * proceed from there as usual.
695 */
696
697 #ifdef WAITAROUND
698 int waitaround = 0; /* wait for rendezvous with the debugger */
699 #endif
700
701 #define BZIP "/usr/bin/bzip2"
702 #define GZIP "/usr/bin/gzip"
703 #define COMPRESS "/usr/bin/compress"
704 #define XZ "/usr/bin/xz"
705 #define BZCAT "/usr/bin/bzcat"
706 #define GZCAT "/usr/bin/gzcat"
707 #define ZCAT "/usr/bin/zcat"
708 #define XZCAT "/usr/bin/xzcat"
709 #define GSUF 8 /* number of valid 'gzip' sufixes */
710 #define BSUF 4 /* number of valid 'bzip2' sufixes */
711 #define XSUF 1 /* number of valid 'xz' suffixes */
712
713 static char *compress_opt; /* compression type */
714
715 static char *gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
716 ".tgz", ".taz"};
717 static char *bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
718 static char *xsuffix[] = {".xz"};
719 static char *suffix;
720
721
722 int
723 main(int argc, char *argv[])
724 {
725 char *cp;
726 char *tmpdirp;
727 pid_t thispid;
728 pid_t pid;
729 int wstat;
730
731 (void) setlocale(LC_ALL, "");
732 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
733 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
734 #endif
735 (void) textdomain(TEXT_DOMAIN);
736 if (argc < 2)
737 usage();
738
739 tfile = NULL;
740 if ((myname = strdup(argv[0])) == NULL) {
741 (void) fprintf(stderr, gettext(
742 "tar: cannot allocate program name\n"));
743 exit(1);
744 }
745
746 if (init_yes() < 0) {
747 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
748 strerror(errno));
749 exit(2);
750 }
751
752 /*
753 * For XPG4 compatibility, we must be able to accept the "--"
754 * argument normally recognized by getopt; it is used to delimit
755 * the end opt the options section, and so can only appear in
756 * the position of the first argument. We simply skip it.
757 */
758
759 if (strcmp(argv[1], "--") == 0) {
760 argv++;
761 argc--;
762 if (argc < 3)
763 usage();
764 }
765
766 argv[argc] = NULL;
767 argv++;
768
769 /*
770 * Set up default values.
771 * Search the operand string looking for the first digit or an 'f'.
772 * If you find a digit, use the 'archive#' entry in DEF_FILE.
773 * If 'f' is given, bypass looking in DEF_FILE altogether.
774 * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
775 */
776 if ((usefile = getenv("TAPE")) == (char *)NULL) {
777 for (cp = *argv; *cp; ++cp)
778 if (isdigit(*cp) || *cp == 'f')
779 break;
780 if (*cp != 'f') {
781 archive[7] = (*cp)? *cp: '0';
782 if (!(defaults_used = defset(archive))) {
783 usefile = NULL;
784 nblock = 1;
785 blocklim = 0;
786 NotTape = 0;
787 }
788 }
789 }
790
791 for (cp = *argv++; *cp; cp++)
792 switch (*cp) {
793 #ifdef WAITAROUND
794 case 'D':
795 /* rendezvous with the debugger */
796 waitaround = 1;
797 break;
798 #endif
799 case 'f':
800 assert_string(*argv, gettext(
801 "tar: tarfile must be specified with 'f' "
802 "function modifier\n"));
803 usefile = *argv++;
804 break;
805 case 'F':
806 Fflag++;
807 break;
808 case 'c':
809 cflag++;
810 rflag++;
811 update = 1;
812 break;
813 #if defined(O_XATTR)
814 case '@':
815 atflag++;
816 break;
817 #endif /* O_XATTR */
818 #if defined(_PC_SATTR_ENABLED)
819 case '/':
820 saflag++;
821 break;
822 #endif /* _PC_SATTR_ENABLED */
823 case 'u':
824 uflag++; /* moved code after signals caught */
825 rflag++;
826 update = 2;
827 break;
828 case 'r':
829 rflag++;
830 update = 2;
831 break;
832 case 'v':
833 vflag++;
834 break;
835 case 'w':
836 wflag++;
837 break;
838 case 'x':
839 xflag++;
840 break;
841 case 'X':
842 assert_string(*argv, gettext(
843 "tar: exclude file must be specified with 'X' "
844 "function modifier\n"));
845 Xflag = 1;
846 Xfile = *argv++;
847 build_table(exclude_tbl, Xfile);
848 break;
849 case 't':
850 tflag++;
851 break;
852 case 'm':
853 mflag++;
854 break;
855 case 'p':
856 pflag++;
857 break;
858 case 'D':
859 Dflag++;
860 break;
861 case '-':
862 /* ignore this silently */
863 break;
864 case '0': /* numeric entries used only for defaults */
865 case '1':
866 case '2':
867 case '3':
868 case '4':
869 case '5':
870 case '6':
871 case '7':
872 break;
873 case 'b':
874 assert_string(*argv, gettext(
875 "tar: blocking factor must be specified "
876 "with 'b' function modifier\n"));
877 bflag++;
878 nblock = bcheck(*argv++);
879 break;
880 case 'n': /* not a magtape (instead of 'k') */
881 NotTape++; /* assume non-magtape */
882 break;
883 case 'l':
884 linkerrok++;
885 break;
886 case 'e':
887 errflag++;
888 case 'o':
889 oflag++;
890 break;
891 case 'h':
892 hflag++;
893 break;
894 case 'i':
895 iflag++;
896 break;
897 case 'B':
898 Bflag++;
899 break;
900 case 'P':
901 Pflag++;
902 break;
903 case 'E':
904 Eflag++;
905 Pflag++; /* Only POSIX archive made */
906 break;
907 case 'T':
908 Tflag++; /* Handle Trusted Extensions attrs */
909 pflag++; /* also set flag for ACL */
910 break;
911 case 'j': /* compession "bzip2" */
912 jflag = 1;
913 break;
914 case 'z': /* compression "gzip" */
915 zflag = 1;
916 break;
917 case 'Z': /* compression "compress" */
918 Zflag = 1;
919 break;
920 case 'J': /* compression "xz" */
921 Jflag = 1;
922 break;
923 case 'a':
924 aflag = 1; /* autocompression */
925 break;
926 default:
927 (void) fprintf(stderr, gettext(
928 "tar: %c: unknown function modifier\n"), *cp);
929 usage();
930 }
931
932 if (!rflag && !xflag && !tflag)
933 usage();
934 if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
935 (void) fprintf(stderr, gettext(
936 "tar: specify only one of [ctxru].\n"));
937 usage();
938 }
939 if (cflag) {
940 if ((jflag + zflag + Zflag + Jflag + aflag) > 1) {
941 (void) fprintf(stderr, gettext(
942 "tar: specify only one of [ajJzZ] to "
943 "create a compressed file.\n"));
944 usage();
945 }
946 }
947 /* Trusted Extensions attribute handling */
948 if (Tflag && ((getzoneid() != GLOBAL_ZONEID) ||
949 !is_system_labeled())) {
950 (void) fprintf(stderr, gettext(
951 "tar: the 'T' option is only available with "
952 "Trusted Extensions\nand must be run from "
953 "the global zone.\n"));
954 usage();
955 }
956 if (cflag && *argv == NULL)
957 fatal(gettext("Missing filenames"));
958 if (usefile == NULL)
959 fatal(gettext("device argument required"));
960
961 /* alloc a buffer of the right size */
962 if ((tbuf = (union hblock *)
963 calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
964 (union hblock *)NULL) {
965 (void) fprintf(stderr, gettext(
966 "tar: cannot allocate physio buffer\n"));
967 exit(1);
968 }
969
970 if ((xrec_ptr = malloc(xrec_size)) == NULL) {
971 (void) fprintf(stderr, gettext(
972 "tar: cannot allocate extended header buffer\n"));
973 exit(1);
974 }
975
976 #ifdef WAITAROUND
977 if (waitaround) {
978 (void) fprintf(stderr, gettext("Rendezvous with tar on pid"
979 " %d\n"), getpid());
980
981 while (waitaround) {
982 (void) sleep(10);
983 }
984 }
985 #endif
986
987 thispid = getpid();
988 (void) sprintf(pidchars, "%ld", thispid);
989 thispid = strlen(pidchars);
990
991 if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL)
992 (void) strcpy(xhdr_dirname, "/tmp");
993 else {
994 /*
995 * Make sure that dir is no longer than what can
996 * fit in the prefix part of the header.
997 */
998 if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
999 (void) strcpy(xhdr_dirname, "/tmp");
1000 if ((vflag > 0) && (Eflag > 0))
1001 (void) fprintf(stderr, gettext(
1002 "Ignoring TMPDIR\n"));
1003 } else
1004 (void) strcpy(xhdr_dirname, tmpdirp);
1005 }
1006 (void) strcat(xhdr_dirname, "/PaxHeaders.");
1007 (void) strcat(xhdr_dirname, pidchars);
1008
1009 if (rflag) {
1010 if (cflag && usefile != NULL) {
1011 /* Set the compression type */
1012 if (aflag)
1013 detect_compress();
1014
1015 if (jflag) {
1016 compress_opt = compress_malloc(strlen(BZIP)
1017 + 1);
1018 (void) strcpy(compress_opt, BZIP);
1019 } else if (zflag) {
1020 compress_opt = compress_malloc(strlen(GZIP)
1021 + 1);
1022 (void) strcpy(compress_opt, GZIP);
1023 } else if (Zflag) {
1024 compress_opt =
1025 compress_malloc(strlen(COMPRESS) + 1);
1026 (void) strcpy(compress_opt, COMPRESS);
1027 } else if (Jflag) {
1028 compress_opt = compress_malloc(strlen(XZ) + 1);
1029 (void) strcpy(compress_opt, XZ);
1030 }
1031 } else {
1032 /*
1033 * Decompress if the file is compressed for
1034 * an update or replace.
1035 */
1036 if (strcmp(usefile, "-") != 0) {
1037 check_compression();
1038 if (compress_opt != NULL) {
1039 decompress_file();
1040 }
1041 }
1042 }
1043
1044 if (cflag && tfile != NULL)
1045 usage();
1046 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1047 (void) signal(SIGINT, onintr);
1048 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1049 (void) signal(SIGHUP, onhup);
1050 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1051 (void) signal(SIGQUIT, onquit);
1052 if (uflag) {
1053 int tnum;
1054 struct stat sbuf;
1055
1056 tmpdir = getenv("TMPDIR");
1057 /*
1058 * If the name is invalid or this isn't a directory,
1059 * or the directory is not writable, then reset to
1060 * a default temporary directory.
1061 */
1062 if (tmpdir == NULL || *tmpdir == '\0' ||
1063 (strlen(tmpdir) + strlen(tmp_suffix)) > PATH_MAX) {
1064 tmpdir = "/tmp";
1065 } else if (stat(tmpdir, &sbuf) < 0 ||
1066 (sbuf.st_mode & S_IFMT) != S_IFDIR ||
1067 (sbuf.st_mode & S_IWRITE) == 0) {
1068 tmpdir = "/tmp";
1069 }
1070
1071 if ((tname = calloc(1, strlen(tmpdir) +
1072 strlen(tmp_suffix) + 1)) == NULL) {
1073 vperror(1, gettext("tar: out of memory, "
1074 "cannot create temporary file\n"));
1075 }
1076 (void) strcpy(tname, tmpdir);
1077 (void) strcat(tname, tmp_suffix);
1078
1079 if ((tnum = mkstemp(tname)) == -1)
1080 vperror(1, "%s", tname);
1081 if ((tfile = fdopen(tnum, "w")) == NULL)
1082 vperror(1, "%s", tname);
1083 }
1084 if (strcmp(usefile, "-") == 0) {
1085 if (cflag == 0)
1086 fatal(gettext(
1087 "can only create standard output archives."));
1088 vfile = stderr;
1089 mt = dup(1);
1090 ++bflag;
1091 } else {
1092 if (cflag)
1093 mt = open(usefile,
1094 O_RDWR|O_CREAT|O_TRUNC, 0666);
1095 else
1096 mt = open(usefile, O_RDWR);
1097
1098 if (mt < 0) {
1099 if (cflag == 0 || (mt = creat(usefile, 0666))
1100 < 0)
1101 vperror(1, "%s", usefile);
1102 }
1103 }
1104 /* Get inode and device number of output file */
1105 (void) fstat(mt, &stbuf);
1106 mt_ino = stbuf.st_ino;
1107 mt_dev = stbuf.st_dev;
1108 mt_devtype = stbuf.st_mode & S_IFMT;
1109 NotTape = !istape(mt, mt_devtype);
1110
1111 if (rflag && !cflag && (mt_devtype == S_IFIFO))
1112 fatal(gettext("cannot append to pipe or FIFO."));
1113
1114 if (Aflag && vflag)
1115 (void) printf(
1116 gettext("Suppressing absolute pathnames\n"));
1117 if (cflag && compress_opt != NULL) {
1118 pid = compress_file();
1119 wait_pid(pid);
1120 }
1121 dorep(argv);
1122 if (rflag && !cflag && (compress_opt != NULL))
1123 compress_back();
1124 } else if (xflag || tflag) {
1125 /*
1126 * for each argument, check to see if there is a "-I file" pair.
1127 * if so, move the 3rd argument into "-I"'s place, build_table()
1128 * using "file"'s name and increment argc one (the second
1129 * increment appears in the for loop) which removes the two
1130 * args "-I" and "file" from the argument vector.
1131 */
1132 for (argc = 0; argv[argc]; argc++) {
1133 if (strcmp(argv[argc], "-I") == 0) {
1134 if (!argv[argc+1]) {
1135 (void) fprintf(stderr, gettext(
1136 "tar: missing argument for -I flag\n"));
1137 done(2);
1138 } else {
1139 Iflag = 1;
1140 argv[argc] = argv[argc+2];
1141 build_table(include_tbl, argv[++argc]);
1142 }
1143 } else if (strcmp(argv[argc], "-C") == 0) {
1144 if (!argv[argc+1]) {
1145 (void) fprintf(stderr, gettext("tar: "
1146 "missing argument for -C flag\n"));
1147 done(2);
1148 } else if (xtract_chdir != NULL) {
1149 (void) fprintf(stderr, gettext("tar: "
1150 "extract should have only one -C "
1151 "flag\n"));
1152 done(2);
1153 } else {
1154 argv[argc] = argv[argc+2];
1155 xtract_chdir = argv[++argc];
1156 }
1157 }
1158 }
1159 if (strcmp(usefile, "-") == 0) {
1160 mt = dup(0);
1161 ++bflag;
1162 /* try to recover from short reads when reading stdin */
1163 ++Bflag;
1164 } else if ((mt = open(usefile, 0)) < 0)
1165 vperror(1, "%s", usefile);
1166
1167 /* Decompress if the file is compressed */
1168
1169 if (strcmp(usefile, "-") != 0) {
1170 check_compression();
1171 if (compress_opt != NULL) {
1172 pid = uncompress_file();
1173 wait_pid(pid);
1174 }
1175 }
1176 if (xflag) {
1177 if (xtract_chdir != NULL) {
1178 if (tar_chdir(xtract_chdir) < 0) {
1179 vperror(1, gettext("can't change "
1180 "directories to %s"), xtract_chdir);
1181 }
1182 }
1183 if (Aflag && vflag)
1184 (void) printf(gettext(
1185 "Suppressing absolute pathnames.\n"));
1186
1187 doxtract(argv);
1188 } else if (tflag)
1189 dotable(argv);
1190 }
1191 else
1192 usage();
1193
1194 done(Errflg);
1195
1196 /* Not reached: keep compiler quiet */
1197 return (1);
1198 }
1199
1200 static void
1201 usage(void)
1202 {
1203 (void) fprintf(stderr, gettext(
1204 #if defined(O_XATTR)
1205 #if defined(_PC_SATTR_ENABLED)
1206 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@/[0-7]][bf][X...] "
1207 #else
1208 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@[0-7]][bf][X...] "
1209 #endif /* _PC_SATTR_ENABLED */
1210 #else
1211 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw[0-7]][bf][X...] "
1212 #endif /* O_XATTR */
1213 "[j|J|z|Z] "
1214 "[blocksize] [tarfile] [size] [exclude-file...] "
1215 "{file | -I include-file | -C directory file}...\n"));
1216 done(1);
1217 }
1218
1219 /*
1220 * dorep - do "replacements"
1221 *
1222 * Dorep is responsible for creating ('c'), appending ('r')
1223 * and updating ('u');
1224 */
1225
1226 static void
1227 dorep(char *argv[])
1228 {
1229 char *cp, *cp2, *p;
1230 char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
1231 char file[PATH_MAX*2], origdir[PATH_MAX+1];
1232 FILE *fp = (FILE *)NULL;
1233 int archtype;
1234 int ret;
1235
1236
1237 if (!cflag) {
1238 xhdr_flgs = 0;
1239 getdir(); /* read header for next file */
1240 if (Xhdrflag > 0) {
1241 if (!Eflag)
1242 fatal(gettext("Archive contains extended"
1243 " header. -E flag required.\n"));
1244 ret = get_xdata(); /* Get extended header items */
1245 /* and regular header */
1246 } else {
1247 if (Eflag)
1248 fatal(gettext("Archive contains no extended"
1249 " header. -E flag not allowed.\n"));
1250 }
1251 while (!endtape()) { /* changed from a do while */
1252 setbytes_to_skip(&stbuf, ret);
1253 passtape(); /* skip the file data */
1254 if (term)
1255 done(Errflg); /* received signal to stop */
1256 xhdr_flgs = 0;
1257 getdir();
1258 if (Xhdrflag > 0)
1259 ret = get_xdata();
1260 }
1261 if (ret == 0) {
1262 if ((dblock.dbuf.typeflag != 'A') &&
1263 (xhdr_flgs != 0)) {
1264 load_info_from_xtarhdr(xhdr_flgs,
1265 &Xtarhdr);
1266 xhdr_flgs |= _X_XHDR;
1267 }
1268 }
1269 backtape(); /* was called by endtape */
1270 if (tfile != NULL) {
1271 /*
1272 * Buffer size is calculated to be the size of the
1273 * tmpdir string, plus 6 times the size of the tname
1274 * string, plus a value that is known to be greater
1275 * than the command pipeline string.
1276 */
1277 int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
1278 char *buf;
1279
1280 if ((buf = (char *)calloc(1, buflen)) == NULL) {
1281 vperror(1, gettext("tar: out of memory, "
1282 "cannot create sort command file\n"));
1283 }
1284
1285 (void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
1286 "sort +0 -1 +1nr %s -o %s; awk '$1 "
1287 "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1288 tmpdir, tname, tname, tname, tname, tname, tname);
1289 (void) fflush(tfile);
1290 (void) system(buf);
1291 free(buf);
1292 (void) freopen(tname, "r", tfile);
1293 (void) fstat(fileno(tfile), &stbuf);
1294 high = stbuf.st_size;
1295 }
1296 }
1297
1298 dumping = 1;
1299 if (mulvol) { /* SP-1 */
1300 if (nblock && (blocklim%nblock) != 0)
1301 fatal(gettext(
1302 "Volume size not a multiple of block size."));
1303 blocklim -= 2; /* for trailer records */
1304 if (vflag)
1305 (void) fprintf(vfile, gettext("Volume ends at %"
1306 FMT_blkcnt_t "K, blocking factor = %dK\n"),
1307 K((blocklim - 1)), K(nblock));
1308 }
1309
1310 /*
1311 * Save the original directory before it gets
1312 * changed.
1313 */
1314 if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
1315 vperror(0, gettext("A parent directory cannot be read"));
1316 exit(1);
1317 }
1318
1319 (void) strcpy(wdir, origdir);
1320
1321 while ((*argv || fp) && !term) {
1322 if (fp || (strcmp(*argv, "-I") == 0)) {
1323 if (fp == NULL) {
1324 if (*++argv == NULL)
1325 fatal(gettext(
1326 "missing file name for -I flag."));
1327 else if ((fp = fopen(*argv++, "r")) == NULL)
1328 vperror(0, "%s", argv[-1]);
1329 continue;
1330 } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
1331 (void) fclose(fp);
1332 fp = NULL;
1333 continue;
1334 } else {
1335 cp = cp2 = file;
1336 if ((p = strchr(cp2, '\n')))
1337 *p = 0;
1338 }
1339 } else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
1340 if (tar_chdir(*++argv) < 0)
1341 vperror(0, gettext(
1342 "can't change directories to %s"), *argv);
1343 else
1344 (void) getcwd(wdir, (sizeof (wdir)));
1345 argv++;
1346 continue;
1347 } else
1348 cp = cp2 = strcpy(file, *argv++);
1349
1350 /*
1351 * point cp2 to the last '/' in file, but not
1352 * to a trailing '/'
1353 */
1354 for (; *cp; cp++) {
1355 if (*cp == '/') {
1356 while (*(cp+1) == '/') {
1357 ++cp;
1358 }
1359 if (*(cp+1) != '\0') {
1360 /* not trailing slash */
1361 cp2 = cp;
1362 }
1363 }
1364 }
1365 if (cp2 != file) {
1366 *cp2 = '\0';
1367 if (tar_chdir(file) < 0) {
1368 vperror(0, gettext(
1369 "can't change directories to %s"), file);
1370 continue;
1371 }
1372 *cp2 = '/';
1373 cp2++;
1374 }
1375
1376 parent = getcwd(tempdir, (sizeof (tempdir)));
1377
1378 archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
1379 LEV0, SYMLINK_LEV0);
1380
1381 #if defined(O_XATTR)
1382 if (!exitflag) {
1383 if ((atflag || saflag) &&
1384 (archtype == PUT_NOTAS_LINK)) {
1385 xattrs_put(file, cp2, parent, NULL);
1386 }
1387 }
1388 #endif
1389
1390 if (tar_chdir(origdir) < 0)
1391 vperror(0, gettext("cannot change back?: %s"), origdir);
1392
1393 if (exitflag) {
1394 /*
1395 * If e function modifier has been specified
1396 * write the files (that are listed before the
1397 * file causing the error) to tape. exitflag is
1398 * used because only some of the error conditions
1399 * in putfile() recognize the e function modifier.
1400 */
1401 break;
1402 }
1403 }
1404
1405 putempty((blkcnt_t)2);
1406 flushtape();
1407 closevol(); /* SP-1 */
1408 if (linkerrok == 1)
1409 for (; ihead != NULL; ihead = ihead->nextp) {
1410 if (ihead->count == 0)
1411 continue;
1412 (void) fprintf(stderr, gettext(
1413 "tar: missing links to %s\n"), ihead->pathname);
1414 if (errflag)
1415 done(1);
1416 else
1417 Errflg = 1;
1418 }
1419 }
1420
1421
1422 /*
1423 * endtape - check for tape at end
1424 *
1425 * endtape checks the entry in dblock.dbuf to see if its the
1426 * special EOT entry. Endtape is usually called after getdir().
1427 *
1428 * endtape used to call backtape; it no longer does, he who
1429 * wants it backed up must call backtape himself
1430 * RETURNS: 0 if not EOT, tape position unaffected
1431 * 1 if EOT, tape position unaffected
1432 */
1433
1434 static int
1435 endtape(void)
1436 {
1437 if (dblock.dbuf.name[0] == '\0') { /* null header = EOT */
1438 return (1);
1439 } else
1440 return (0);
1441 }
1442
1443 /*
1444 * getdir - get directory entry from tar tape
1445 *
1446 * getdir reads the next tarblock off the tape and cracks
1447 * it as a directory. The checksum must match properly.
1448 *
1449 * If tfile is non-null getdir writes the file name and mod date
1450 * to tfile.
1451 */
1452
1453 static void
1454 getdir(void)
1455 {
1456 struct stat *sp;
1457 #ifdef EUC
1458 static int warn_chksum_sign = 0;
1459 #endif /* EUC */
1460
1461 top:
1462 readtape((char *)&dblock);
1463 if (dblock.dbuf.name[0] == '\0')
1464 return;
1465 sp = &stbuf;
1466 (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
1467 (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
1468 (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
1469 (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
1470 (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
1471 (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
1472 (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
1473 (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
1474
1475 is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
1476
1477 sp->st_mode = Gen.g_mode;
1478 if (is_posix && (sp->st_mode & S_IFMT) == 0)
1479 switch (dblock.dbuf.typeflag) {
1480 case '0': case 0: case _XATTR_HDRTYPE:
1481 sp->st_mode |= S_IFREG;
1482 break;
1483 case '1': /* hard link */
1484 break;
1485 case '2':
1486 sp->st_mode |= S_IFLNK;
1487 break;
1488 case '3':
1489 sp->st_mode |= S_IFCHR;
1490 break;
1491 case '4':
1492 sp->st_mode |= S_IFBLK;
1493 break;
1494 case '5':
1495 sp->st_mode |= S_IFDIR;
1496 break;
1497 case '6':
1498 sp->st_mode |= S_IFIFO;
1499 break;
1500 default:
1501 if (convtoreg(Gen.g_filesz))
1502 sp->st_mode |= S_IFREG;
1503 break;
1504 }
1505
1506 if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
1507 Xhdrflag = 1; /* Currently processing extended header */
1508 } else {
1509 Xhdrflag = 0;
1510 }
1511
1512 sp->st_uid = Gen.g_uid;
1513 sp->st_gid = Gen.g_gid;
1514 sp->st_size = Gen.g_filesz;
1515 sp->st_mtime = Gen.g_mtime;
1516 chksum = Gen.g_cksum;
1517
1518 if (dblock.dbuf.extno != '\0') { /* split file? */
1519 extno = dblock.dbuf.extno;
1520 extsize = Gen.g_filesz;
1521 extotal = dblock.dbuf.extotal;
1522 } else {
1523 extno = 0; /* tell others file not split */
1524 extsize = 0;
1525 extotal = 0;
1526 }
1527
1528 #ifdef EUC
1529 if (chksum != checksum(&dblock)) {
1530 if (chksum != checksum_signed(&dblock)) {
1531 (void) fprintf(stderr, gettext(
1532 "tar: directory checksum error\n"));
1533 if (iflag) {
1534 Errflg = 2;
1535 goto top;
1536 }
1537 done(2);
1538 } else {
1539 if (! warn_chksum_sign) {
1540 warn_chksum_sign = 1;
1541 (void) fprintf(stderr, gettext(
1542 "tar: warning: tar file made with signed checksum\n"));
1543 }
1544 }
1545 }
1546 #else
1547 if (chksum != checksum(&dblock)) {
1548 (void) fprintf(stderr, gettext(
1549 "tar: directory checksum error\n"));
1550 if (iflag) {
1551 Errflg = 2;
1552 goto top;
1553 }
1554 done(2);
1555 }
1556 #endif /* EUC */
1557 if (tfile != NULL && Xhdrflag == 0) {
1558 /*
1559 * If an extended header is present, then time is available
1560 * in nanoseconds in the extended header data, so set it.
1561 * Otherwise, give an invalid value so that checkupdate will
1562 * not test beyond seconds.
1563 */
1564 if ((xhdr_flgs & _X_MTIME))
1565 sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
1566 else
1567 sp->st_mtim.tv_nsec = -1;
1568
1569 if (xhdr_flgs & _X_PATH)
1570 (void) fprintf(tfile, "%s %10ld.%9.9ld\n",
1571 Xtarhdr.x_path, sp->st_mtim.tv_sec,
1572 sp->st_mtim.tv_nsec);
1573 else
1574 (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
1575 NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
1576 sp->st_mtim.tv_nsec);
1577 }
1578
1579 #if defined(O_XATTR)
1580 Hiddendir = 0;
1581 if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
1582 if (xattrbadhead) {
1583 free(xattrhead);
1584 xattrp = NULL;
1585 xattr_linkp = NULL;
1586 xattrhead = NULL;
1587 } else {
1588 char *aname = basename(xattrapath);
1589 size_t xindex = aname - xattrapath;
1590
1591 if (xattrapath[xindex] == '.' &&
1592 xattrapath[xindex + 1] == '\0' &&
1593 xattrp->h_typeflag == '5') {
1594 Hiddendir = 1;
1595 sp->st_mode =
1596 (S_IFDIR | (sp->st_mode & POSIXMODES));
1597 }
1598 dblock.dbuf.typeflag = xattrp->h_typeflag;
1599 }
1600 }
1601 #endif
1602 }
1603
1604
1605 /*
1606 * passtape - skip over a file on the tape
1607 *
1608 * passtape skips over the next data file on the tape.
1609 * The tape directory entry must be in dblock.dbuf. This
1610 * routine just eats the number of blocks computed from the
1611 * directory size entry; the tape must be (logically) positioned
1612 * right after thee directory info.
1613 */
1614
1615 static void
1616 passtape(void)
1617 {
1618 blkcnt_t blocks;
1619 char buf[TBLOCK];
1620
1621 /*
1622 * Types link(1), sym-link(2), char special(3), blk special(4),
1623 * directory(5), and FIFO(6) do not have data blocks associated
1624 * with them so just skip reading the data block.
1625 */
1626 if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
1627 dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
1628 dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
1629 return;
1630 blocks = TBLOCKS(stbuf.st_size);
1631
1632 /* if operating on disk, seek instead of reading */
1633 if (NotTape)
1634 seekdisk(blocks);
1635 else
1636 while (blocks-- > 0)
1637 readtape(buf);
1638 }
1639
1640 #if defined(O_XATTR)
1641 static int
1642 is_sysattr(char *name)
1643 {
1644 return ((strcmp(name, VIEW_READONLY) == 0) ||
1645 (strcmp(name, VIEW_READWRITE) == 0));
1646 }
1647 #endif
1648
1649 #if defined(O_XATTR)
1650 /*
1651 * Verify the attribute, attrname, is an attribute we want to restore.
1652 * Never restore read-only system attribute files. Only restore read-write
1653 * system attributes files when -/ was specified, and only traverse into
1654 * the 2nd level attribute directory containing only system attributes if
1655 * -@ was specified. This keeps us from archiving
1656 * <attribute name>/<read-write system attribute file>
1657 * when -/ was specified without -@.
1658 *
1659 * attrname - attribute file name
1660 * attrparent - attribute's parent name within the base file's attribute
1661 * directory hierarchy
1662 */
1663 static attr_status_t
1664 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
1665 int *rw_sysattr)
1666 {
1667 #if defined(_PC_SATTR_ENABLED)
1668 int attr_supported;
1669
1670 /* Never restore read-only system attribute files */
1671 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
1672 *rw_sysattr = 0;
1673 return (ATTR_SKIP);
1674 } else {
1675 *rw_sysattr = (attr_supported == _RW_SATTR);
1676 }
1677 #else
1678 /*
1679 * Only need to check if this attribute is an extended system
1680 * attribute.
1681 */
1682 if (*rw_sysattr = is_sysattr(attrname)) {
1683 return (ATTR_SKIP);
1684 } else {
1685 return (ATTR_OK);
1686 }
1687 #endif /* _PC_SATTR_ENABLED */
1688
1689 /*
1690 * If the extended system attribute file is specified with the
1691 * arc_rwsysattr flag, as being transient (default extended
1692 * attributes), then don't archive it.
1693 */
1694 if (*rw_sysattr && !arc_rwsysattr) {
1695 return (ATTR_SKIP);
1696 }
1697
1698 /*
1699 * Only restore read-write system attribute files
1700 * when -/ was specified. Only restore extended
1701 * attributes when -@ was specified.
1702 */
1703 if (atflag) {
1704 if (!saflag) {
1705 /*
1706 * Only archive/restore the hidden directory "." if
1707 * we're processing the top level hidden attribute
1708 * directory. We don't want to process the
1709 * hidden attribute directory of the attribute
1710 * directory that contains only extended system
1711 * attributes.
1712 */
1713 if (*rw_sysattr || (Hiddendir &&
1714 (attrparent != NULL))) {
1715 return (ATTR_SKIP);
1716 }
1717 }
1718 } else if (saflag) {
1719 /*
1720 * Only archive/restore read-write extended system attribute
1721 * files of the base file.
1722 */
1723 if (!*rw_sysattr || (attrparent != NULL)) {
1724 return (ATTR_SKIP);
1725 }
1726 } else {
1727 return (ATTR_SKIP);
1728 }
1729
1730 return (ATTR_OK);
1731 }
1732 #endif
1733
1734 static void
1735 free_children(file_list_t *children)
1736 {
1737 file_list_t *child = children;
1738 file_list_t *cptr;
1739
1740 while (child != NULL) {
1741 cptr = child->next;
1742 if (child->name != NULL) {
1743 free(child->name);
1744 }
1745 child = cptr;
1746 }
1747 }
1748
1749 static int
1750 putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
1751 int filetype, int lev, int symlink_lev)
1752 {
1753 int infile = -1; /* deliberately invalid */
1754 blkcnt_t blocks;
1755 char buf[PATH_MAX + 2]; /* Add trailing slash and null */
1756 char *bigbuf;
1757 int maxread;
1758 int hint; /* amount to write to get "in sync" */
1759 char filetmp[PATH_MAX + 1];
1760 char *cp;
1761 char *name;
1762 char *attrparent = NULL;
1763 char *longattrname = NULL;
1764 file_list_t *child = NULL;
1765 file_list_t *child_end = NULL;
1766 file_list_t *cptr;
1767 struct dirent *dp;
1768 DIR *dirp;
1769 int i;
1770 int split;
1771 int dirfd = -1;
1772 int rc = PUT_NOTAS_LINK;
1773 int archtype = 0;
1774 int rw_sysattr = 0;
1775 char newparent[PATH_MAX + MAXNAMLEN + 1];
1776 char *prefix = "";
1777 char *tmpbuf;
1778 char goodbuf[PRESIZ + 2];
1779 char junkbuf[MAXNAM+1];
1780 char *lastslash;
1781 int j;
1782 struct stat sbuf;
1783 int readlink_max;
1784
1785 (void) memset(goodbuf, '\0', sizeof (goodbuf));
1786 (void) memset(junkbuf, '\0', sizeof (junkbuf));
1787
1788 xhdr_flgs = 0;
1789
1790 if (filetype == XATTR_FILE) {
1791 attrparent = attrinfo->attr_parent;
1792 longattrname = attrinfo->attr_path;
1793 dirfd = attrinfo->attr_parentfd;
1794 rw_sysattr = attrinfo->attr_rw_sysattr;
1795 } else {
1796 dirfd = open(".", O_RDONLY);
1797 }
1798
1799 if (dirfd == -1) {
1800 (void) fprintf(stderr, gettext(
1801 "tar: unable to open%sdirectory %s%s%s%s\n"),
1802 (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
1803 (attrparent == NULL) ? "" : gettext("of attribute "),
1804 (attrparent == NULL) ? "" : attrparent,
1805 (attrparent == NULL) ? "" : gettext(" of "),
1806 (filetype == XATTR_FILE) ? longname : parent);
1807 goto out;
1808 }
1809
1810 if (lev > MAXLEV) {
1811 (void) fprintf(stderr,
1812 gettext("tar: directory nesting too deep, %s not dumped\n"),
1813 longname);
1814 goto out;
1815 }
1816
1817 if (getstat(dirfd, longname, shortname, attrparent))
1818 goto out;
1819
1820 if (hflag) {
1821 /*
1822 * Catch nesting where a file is a symlink to its directory.
1823 */
1824 j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
1825 if (S_ISLNK(sbuf.st_mode)) {
1826 if (symlink_lev++ >= MAXSYMLINKS) {
1827 (void) fprintf(stderr, gettext(
1828 "tar: %s: Number of symbolic links "
1829 "encountered during path name traversal "
1830 "exceeds MAXSYMLINKS\n"), longname);
1831 Errflg = 1;
1832 goto out;
1833 }
1834 }
1835 }
1836
1837 /*
1838 * Check if the input file is the same as the tar file we
1839 * are creating
1840 */
1841 if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
1842 (void) fprintf(stderr, gettext(
1843 "tar: %s%s%s%s%s same as archive file\n"),
1844 rw_sysattr ? gettext("system ") : "",
1845 (longattrname == NULL) ? "" : gettext("attribute "),
1846 (longattrname == NULL) ? "" : longattrname,
1847 (longattrname == NULL) ? "" : gettext(" of "),
1848 longname);
1849 Errflg = 1;
1850 goto out;
1851 }
1852 /*
1853 * Check size limit - we can't archive files that
1854 * exceed TAR_OFFSET_MAX bytes because of header
1855 * limitations. Exclude file types that set
1856 * st_size to zero below because they take no
1857 * archive space to represent contents.
1858 */
1859 if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
1860 !S_ISDIR(stbuf.st_mode) &&
1861 !S_ISCHR(stbuf.st_mode) &&
1862 !S_ISBLK(stbuf.st_mode) &&
1863 (Eflag == 0)) {
1864 (void) fprintf(stderr, gettext(
1865 "tar: %s%s%s%s%s too large to archive. "
1866 "Use E function modifier.\n"),
1867 rw_sysattr ? gettext("system ") : "",
1868 (longattrname == NULL) ? "" : gettext("attribute "),
1869 (longattrname == NULL) ? "" : longattrname,
1870 (longattrname == NULL) ? "" : gettext(" of "),
1871 longname);
1872 if (errflag)
1873 exitflag = 1;
1874 Errflg = 1;
1875 goto out;
1876 }
1877
1878 if (tfile != NULL && checkupdate(longname) == 0) {
1879 goto out;
1880 }
1881 if (checkw('r', longname) == 0) {
1882 goto out;
1883 }
1884
1885 if (Fflag &&
1886 checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
1887 goto out;
1888
1889 if (Xflag) {
1890 if (is_in_table(exclude_tbl, longname)) {
1891 if (vflag) {
1892 (void) fprintf(vfile, gettext(
1893 "a %s excluded\n"), longname);
1894 }
1895 goto out;
1896 }
1897 }
1898
1899 /*
1900 * If the length of the fullname is greater than MAXNAM,
1901 * print out a message and return (unless extended headers are used,
1902 * in which case fullname is limited to PATH_MAX).
1903 */
1904
1905 if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
1906 (split > PATH_MAX)) {
1907 (void) fprintf(stderr, gettext(
1908 "tar: %s: file name too long\n"), longname);
1909 if (errflag)
1910 exitflag = 1;
1911 Errflg = 1;
1912 goto out;
1913 }
1914
1915 /*
1916 * We split the fullname into prefix and name components if any one
1917 * of three conditions holds:
1918 * -- the length of the fullname exceeds NAMSIZ,
1919 * -- the length of the fullname equals NAMSIZ, and the shortname
1920 * is less than NAMSIZ, (splitting in this case preserves
1921 * compatibility with 5.6 and 5.5.1 tar), or
1922 * -- the length of the fullname equals NAMSIZ, the file is a
1923 * directory and we are not in POSIX-conformant mode (where
1924 * trailing slashes are removed from directories).
1925 */
1926 if ((split > NAMSIZ) ||
1927 (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1928 (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
1929 /*
1930 * Since path is limited to PRESIZ characters, look for the
1931 * last slash within PRESIZ + 1 characters only.
1932 */
1933 (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
1934 tmpbuf = goodbuf;
1935 lastslash = strrchr(tmpbuf, '/');
1936 if (lastslash == NULL) {
1937 i = split; /* Length of name */
1938 j = 0; /* Length of prefix */
1939 goodbuf[0] = '\0';
1940 } else {
1941 *lastslash = '\0'; /* Terminate the prefix */
1942 j = strlen(tmpbuf);
1943 i = split - j - 1;
1944 }
1945 /*
1946 * If the filename is greater than NAMSIZ we can't
1947 * archive the file unless we are using extended headers.
1948 */
1949 if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
1950 !Pflag)) {
1951 /* Determine which (filename or path) is too long. */
1952 lastslash = strrchr(longname, '/');
1953 if (lastslash != NULL)
1954 i = strlen(lastslash + 1);
1955 if (Eflag > 0) {
1956 xhdr_flgs |= _X_PATH;
1957 Xtarhdr.x_path = longname;
1958 if (i <= NAMSIZ)
1959 (void) strcpy(junkbuf, lastslash + 1);
1960 else
1961 (void) sprintf(junkbuf, "%llu",
1962 xhdr_count + 1);
1963 if (split - i - 1 > PRESIZ)
1964 (void) strcpy(goodbuf, xhdr_dirname);
1965 } else {
1966 if ((i > NAMSIZ) || (i == NAMSIZ &&
1967 S_ISDIR(stbuf.st_mode) && !Pflag))
1968 (void) fprintf(stderr, gettext(
1969 "tar: %s: filename is greater than "
1970 "%d\n"), lastslash == NULL ?
1971 longname : lastslash + 1, NAMSIZ);
1972 else
1973 (void) fprintf(stderr, gettext(
1974 "tar: %s: prefix is greater than %d"
1975 "\n"), longname, PRESIZ);
1976 if (errflag)
1977 exitflag = 1;
1978 Errflg = 1;
1979 goto out;
1980 }
1981 } else
1982 (void) strncpy(&junkbuf[0], longname + j + 1,
1983 strlen(longname + j + 1));
1984 name = junkbuf;
1985 prefix = goodbuf;
1986 } else {
1987 name = longname;
1988 }
1989 if (Aflag) {
1990 if ((prefix != NULL) && (*prefix != '\0'))
1991 while (*prefix == '/')
1992 ++prefix;
1993 else
1994 while (*name == '/')
1995 ++name;
1996 }
1997
1998 switch (stbuf.st_mode & S_IFMT) {
1999 case S_IFDIR:
2000 stbuf.st_size = (off_t)0;
2001 blocks = TBLOCKS(stbuf.st_size);
2002
2003 if (filetype != XATTR_FILE && Hiddendir == 0) {
2004 i = 0;
2005 cp = buf;
2006 while ((*cp++ = longname[i++]))
2007 ;
2008 *--cp = '/';
2009 *++cp = 0;
2010 }
2011 if (!oflag) {
2012 tomodes(&stbuf);
2013 if (build_dblock(name, tchar, '5', filetype,
2014 &stbuf, stbuf.st_dev, prefix) != 0) {
2015 goto out;
2016 }
2017 if (!Pflag) {
2018 /*
2019 * Old archives require a slash at the end
2020 * of a directory name.
2021 *
2022 * XXX
2023 * If directory name is too long, will
2024 * slash overfill field?
2025 */
2026 if (strlen(name) > (unsigned)NAMSIZ-1) {
2027 (void) fprintf(stderr, gettext(
2028 "tar: %s: filename is greater "
2029 "than %d\n"), name, NAMSIZ);
2030 if (errflag)
2031 exitflag = 1;
2032 Errflg = 1;
2033 goto out;
2034 } else {
2035 if (strlen(name) == (NAMSIZ - 1)) {
2036 (void) memcpy(dblock.dbuf.name,
2037 name, NAMSIZ);
2038 dblock.dbuf.name[NAMSIZ-1]
2039 = '/';
2040 } else
2041 (void) sprintf(dblock.dbuf.name,
2042 "%s/", name);
2043
2044 /*
2045 * need to recalculate checksum
2046 * because the name changed.
2047 */
2048 (void) sprintf(dblock.dbuf.chksum,
2049 "%07o", checksum(&dblock));
2050 }
2051 }
2052
2053 if (put_extra_attributes(longname, shortname,
2054 longattrname, prefix, filetype, '5') != 0)
2055 goto out;
2056
2057 #if defined(O_XATTR)
2058 /*
2059 * Reset header typeflag when archiving directory, since
2060 * build_dblock changed it on us.
2061 */
2062 if (filetype == XATTR_FILE) {
2063 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2064 } else {
2065 dblock.dbuf.typeflag = '5';
2066 }
2067 #else
2068 dblock.dbuf.typeflag = '5';
2069 #endif
2070
2071 (void) sprintf(dblock.dbuf.chksum, "%07o",
2072 checksum(&dblock));
2073
2074 (void) writetbuf((char *)&dblock, 1);
2075 }
2076 if (vflag) {
2077 #ifdef DEBUG
2078 if (NotTape)
2079 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2080 0);
2081 #endif
2082 if (filetype == XATTR_FILE && Hiddendir) {
2083 (void) fprintf(vfile,
2084 gettext("a %s attribute %s "),
2085 longname, longattrname);
2086
2087 } else {
2088 (void) fprintf(vfile, "a %s/ ", longname);
2089 }
2090 if (NotTape)
2091 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2092 K(blocks));
2093 else
2094 (void) fprintf(vfile, gettext("%" FMT_blkcnt_t
2095 " tape blocks\n"), blocks);
2096 }
2097
2098 /*
2099 * If hidden dir then break now since xattrs_put() will do
2100 * the iterating of the directory.
2101 *
2102 * At the moment, there can only be system attributes on
2103 * attributes. There can be no attributes on attributes or
2104 * directories within the attributes hidden directory hierarchy.
2105 */
2106 if (filetype == XATTR_FILE)
2107 break;
2108
2109 if (*shortname != '/')
2110 (void) sprintf(newparent, "%s/%s", parent, shortname);
2111 else
2112 (void) sprintf(newparent, "%s", shortname);
2113
2114 if (tar_chdir(shortname) < 0) {
2115 vperror(0, "%s", newparent);
2116 goto out;
2117 }
2118
2119 if ((dirp = opendir(".")) == NULL) {
2120 vperror(0, gettext(
2121 "can't open directory %s"), longname);
2122 if (tar_chdir(parent) < 0)
2123 vperror(0, gettext("cannot change back?: %s"),
2124 parent);
2125 goto out;
2126 }
2127
2128 /*
2129 * Create a list of files (children) in this directory to avoid
2130 * having to perform telldir()/seekdir().
2131 */
2132 while ((dp = readdir(dirp)) != NULL && !term) {
2133 if ((strcmp(".", dp->d_name) == 0) ||
2134 (strcmp("..", dp->d_name) == 0))
2135 continue;
2136 if (((cptr = (file_list_t *)calloc(sizeof (char),
2137 sizeof (file_list_t))) == NULL) ||
2138 ((cptr->name = strdup(dp->d_name)) == NULL)) {
2139 vperror(1, gettext(
2140 "Insufficient memory for directory "
2141 "list entry %s/%s\n"),
2142 newparent, dp->d_name);
2143 }
2144
2145 /* Add the file to the list */
2146 if (child == NULL) {
2147 child = cptr;
2148 } else {
2149 child_end->next = cptr;
2150 }
2151 child_end = cptr;
2152 }
2153 (void) closedir(dirp);
2154
2155 /*
2156 * Archive each of the files in the current directory.
2157 * If a file is a directory, putfile() is called
2158 * recursively to archive the file hierarchy of the
2159 * directory before archiving the next file in the
2160 * current directory.
2161 */
2162 while ((child != NULL) && !term) {
2163 (void) strcpy(cp, child->name);
2164 archtype = putfile(buf, cp, newparent, NULL,
2165 NORMAL_FILE, lev + 1, symlink_lev);
2166
2167 if (!exitflag) {
2168 if ((atflag || saflag) &&
2169 (archtype == PUT_NOTAS_LINK)) {
2170 xattrs_put(buf, cp, newparent, NULL);
2171 }
2172 }
2173 if (exitflag)
2174 break;
2175
2176 /* Free each child as we are done processing it. */
2177 cptr = child;
2178 child = child->next;
2179 free(cptr->name);
2180 free(cptr);
2181 }
2182 if ((child != NULL) && !term) {
2183 free_children(child);
2184 }
2185
2186 if (tar_chdir(parent) < 0) {
2187 vperror(0, gettext("cannot change back?: %s"), parent);
2188 }
2189
2190 break;
2191
2192 case S_IFLNK:
2193 readlink_max = NAMSIZ;
2194 if (stbuf.st_size > NAMSIZ) {
2195 if (Eflag > 0) {
2196 xhdr_flgs |= _X_LINKPATH;
2197 readlink_max = PATH_MAX;
2198 } else {
2199 (void) fprintf(stderr, gettext(
2200 "tar: %s: symbolic link too long\n"),
2201 longname);
2202 if (errflag)
2203 exitflag = 1;
2204 Errflg = 1;
2205 goto out;
2206 }
2207 }
2208 /*
2209 * Sym-links need header size of zero since you
2210 * don't store any data for this type.
2211 */
2212 stbuf.st_size = (off_t)0;
2213 tomodes(&stbuf);
2214 i = readlink(shortname, filetmp, readlink_max);
2215 if (i < 0) {
2216 vperror(0, gettext(
2217 "can't read symbolic link %s"), longname);
2218 goto out;
2219 } else {
2220 filetmp[i] = 0;
2221 }
2222 if (vflag)
2223 (void) fprintf(vfile, gettext(
2224 "a %s symbolic link to %s\n"),
2225 longname, filetmp);
2226 if (xhdr_flgs & _X_LINKPATH) {
2227 Xtarhdr.x_linkpath = filetmp;
2228 if (build_dblock(name, tchar, '2', filetype, &stbuf,
2229 stbuf.st_dev, prefix) != 0)
2230 goto out;
2231 } else
2232 if (build_dblock(name, filetmp, '2', filetype, &stbuf,
2233 stbuf.st_dev, prefix) != 0)
2234 goto out;
2235 (void) writetbuf((char *)&dblock, 1);
2236 /*
2237 * No acls for symlinks: mode is always 777
2238 * dont call write ancillary
2239 */
2240 rc = PUT_AS_LINK;
2241 break;
2242 case S_IFREG:
2243 if ((infile = openat(dirfd, shortname, 0)) < 0) {
2244 vperror(0, gettext("unable to open %s%s%s%s"), longname,
2245 rw_sysattr ? gettext(" system") : "",
2246 (filetype == XATTR_FILE) ?
2247 gettext(" attribute ") : "",
2248 (filetype == XATTR_FILE) ? (longattrname == NULL) ?
2249 shortname : longattrname : "");
2250 goto out;
2251 }
2252
2253 blocks = TBLOCKS(stbuf.st_size);
2254
2255 if (put_link(name, longname, shortname, longattrname,
2256 prefix, filetype, '1') == 0) {
2257 (void) close(infile);
2258 rc = PUT_AS_LINK;
2259 goto out;
2260 }
2261
2262 tomodes(&stbuf);
2263
2264 /* correctly handle end of volume */
2265 while (mulvol && tapepos + blocks + 1 > blocklim) {
2266 /* split if floppy has some room and file is large */
2267 if (((blocklim - tapepos) >= EXTMIN) &&
2268 ((blocks + 1) >= blocklim/10)) {
2269 splitfile(longname, infile,
2270 name, prefix, filetype);
2271 (void) close(dirfd);
2272 (void) close(infile);
2273 goto out;
2274 }
2275 newvol(); /* not worth it--just get new volume */
2276 }
2277 #ifdef DEBUG
2278 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2279 blocks);
2280 #endif
2281 if (build_dblock(name, tchar, '0', filetype,
2282 &stbuf, stbuf.st_dev, prefix) != 0) {
2283 goto out;
2284 }
2285 if (vflag) {
2286 #ifdef DEBUG
2287 if (NotTape)
2288 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2289 0);
2290 #endif
2291 (void) fprintf(vfile, "a %s%s%s%s ", longname,
2292 rw_sysattr ? gettext(" system") : "",
2293 (filetype == XATTR_FILE) ? gettext(
2294 " attribute ") : "",
2295 (filetype == XATTR_FILE) ?
2296 longattrname : "");
2297 if (NotTape)
2298 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2299 K(blocks));
2300 else
2301 (void) fprintf(vfile,
2302 gettext("%" FMT_blkcnt_t " tape blocks\n"),
2303 blocks);
2304 }
2305
2306 if (put_extra_attributes(longname, shortname, longattrname,
2307 prefix, filetype, '0') != 0)
2308 goto out;
2309
2310 /*
2311 * No need to reset typeflag for extended attribute here, since
2312 * put_extra_attributes already set it and we haven't called
2313 * build_dblock().
2314 */
2315 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2316 hint = writetbuf((char *)&dblock, 1);
2317 maxread = max(min(stbuf.st_blksize, stbuf.st_size),
2318 (nblock * TBLOCK));
2319 if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
2320 maxread = TBLOCK;
2321 bigbuf = buf;
2322 }
2323
2324 while (((i = (int)
2325 read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
2326 blocks) {
2327 blkcnt_t nblks;
2328
2329 nblks = ((i-1)/TBLOCK)+1;
2330 if (nblks > blocks)
2331 nblks = blocks;
2332 hint = writetbuf(bigbuf, nblks);
2333 blocks -= nblks;
2334 }
2335 (void) close(infile);
2336 if (bigbuf != buf)
2337 free(bigbuf);
2338 if (i < 0)
2339 vperror(0, gettext("Read error on %s"), longname);
2340 else if (blocks != 0 || i != 0) {
2341 (void) fprintf(stderr, gettext(
2342 "tar: %s: file changed size\n"), longname);
2343 if (errflag) {
2344 exitflag = 1;
2345 Errflg = 1;
2346 } else if (!Dflag) {
2347 Errflg = 1;
2348 }
2349 }
2350 putempty(blocks);
2351 break;
2352 case S_IFIFO:
2353 blocks = TBLOCKS(stbuf.st_size);
2354 stbuf.st_size = (off_t)0;
2355
2356 if (put_link(name, longname, shortname, longattrname,
2357 prefix, filetype, '6') == 0) {
2358 rc = PUT_AS_LINK;
2359 goto out;
2360 }
2361 tomodes(&stbuf);
2362
2363 while (mulvol && tapepos + blocks + 1 > blocklim) {
2364 if (((blocklim - tapepos) >= EXTMIN) &&
2365 ((blocks + 1) >= blocklim/10)) {
2366 splitfile(longname, infile, name,
2367 prefix, filetype);
2368 (void) close(dirfd);
2369 (void) close(infile);
2370 goto out;
2371 }
2372 newvol();
2373 }
2374 #ifdef DEBUG
2375 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2376 blocks);
2377 #endif
2378 if (vflag) {
2379 #ifdef DEBUG
2380 if (NotTape)
2381 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2382 0);
2383 #endif
2384 if (NotTape)
2385 (void) fprintf(vfile, gettext("a %s %"
2386 FMT_blkcnt_t "K\n "), longname, K(blocks));
2387 else
2388 (void) fprintf(vfile, gettext(
2389 "a %s %" FMT_blkcnt_t " tape blocks\n"),
2390 longname, blocks);
2391 }
2392 if (build_dblock(name, tchar, '6', filetype,
2393 &stbuf, stbuf.st_dev, prefix) != 0)
2394 goto out;
2395
2396 if (put_extra_attributes(longname, shortname, longattrname,
2397 prefix, filetype, '6') != 0)
2398 goto out;
2399
2400 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2401 dblock.dbuf.typeflag = '6';
2402
2403 (void) writetbuf((char *)&dblock, 1);
2404 break;
2405 case S_IFCHR:
2406 stbuf.st_size = (off_t)0;
2407 blocks = TBLOCKS(stbuf.st_size);
2408 if (put_link(name, longname, shortname, longattrname,
2409 prefix, filetype, '3') == 0) {
2410 rc = PUT_AS_LINK;
2411 goto out;
2412 }
2413 tomodes(&stbuf);
2414
2415 while (mulvol && tapepos + blocks + 1 > blocklim) {
2416 if (((blocklim - tapepos) >= EXTMIN) &&
2417 ((blocks + 1) >= blocklim/10)) {
2418 splitfile(longname, infile, name,
2419 prefix, filetype);
2420 (void) close(dirfd);
2421 goto out;
2422 }
2423 newvol();
2424 }
2425 #ifdef DEBUG
2426 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2427 blocks);
2428 #endif
2429 if (vflag) {
2430 #ifdef DEBUG
2431 if (NotTape)
2432 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2433 0);
2434 #endif
2435 if (NotTape)
2436 (void) fprintf(vfile, gettext("a %s %"
2437 FMT_blkcnt_t "K\n"), longname, K(blocks));
2438 else
2439 (void) fprintf(vfile, gettext("a %s %"
2440 FMT_blkcnt_t " tape blocks\n"), longname,
2441 blocks);
2442 }
2443 if (build_dblock(name, tchar, '3',
2444 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2445 goto out;
2446
2447 if (put_extra_attributes(longname, shortname, longattrname,
2448 prefix, filetype, '3') != 0)
2449 goto out;
2450
2451 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2452 dblock.dbuf.typeflag = '3';
2453
2454 (void) writetbuf((char *)&dblock, 1);
2455 break;
2456 case S_IFBLK:
2457 stbuf.st_size = (off_t)0;
2458 blocks = TBLOCKS(stbuf.st_size);
2459 if (put_link(name, longname, shortname, longattrname,
2460 prefix, filetype, '4') == 0) {
2461 rc = PUT_AS_LINK;
2462 goto out;
2463 }
2464 tomodes(&stbuf);
2465
2466 while (mulvol && tapepos + blocks + 1 > blocklim) {
2467 if (((blocklim - tapepos) >= EXTMIN) &&
2468 ((blocks + 1) >= blocklim/10)) {
2469 splitfile(longname, infile,
2470 name, prefix, filetype);
2471 (void) close(dirfd);
2472 goto out;
2473 }
2474 newvol();
2475 }
2476 #ifdef DEBUG
2477 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2478 blocks);
2479 #endif
2480 if (vflag) {
2481 #ifdef DEBUG
2482 if (NotTape)
2483 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2484 0);
2485 #endif
2486 (void) fprintf(vfile, "a %s ", longname);
2487 if (NotTape)
2488 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2489 K(blocks));
2490 else
2491 (void) fprintf(vfile, gettext("%"
2492 FMT_blkcnt_t " tape blocks\n"), blocks);
2493 }
2494 if (build_dblock(name, tchar, '4',
2495 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2496 goto out;
2497
2498 if (put_extra_attributes(longname, shortname, longattrname,
2499 prefix, filetype, '4') != 0)
2500 goto out;
2501
2502 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2503 dblock.dbuf.typeflag = '4';
2504
2505 (void) writetbuf((char *)&dblock, 1);
2506 break;
2507 default:
2508 (void) fprintf(stderr, gettext(
2509 "tar: %s is not a file. Not dumped\n"), longname);
2510 if (errflag)
2511 exitflag = 1;
2512 Errflg = 1;
2513 goto out;
2514 }
2515
2516 out:
2517 if ((dirfd != -1) && (filetype != XATTR_FILE)) {
2518 (void) close(dirfd);
2519 }
2520 return (rc);
2521 }
2522
2523
2524 /*
2525 * splitfile dump a large file across volumes
2526 *
2527 * splitfile(longname, fd);
2528 * char *longname; full name of file
2529 * int ifd; input file descriptor
2530 *
2531 * NOTE: only called by putfile() to dump a large file.
2532 */
2533
2534 static void
2535 splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
2536 {
2537 blkcnt_t blocks;
2538 off_t bytes, s;
2539 char buf[TBLOCK];
2540 int i, extents;
2541
2542 blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */
2543
2544 /*
2545 * # extents =
2546 * size of file after using up rest of this floppy
2547 * blocks - (blocklim - tapepos) + 1 (for header)
2548 * plus roundup value before divide by blocklim-1
2549 * + (blocklim - 1) - 1
2550 * all divided by blocklim-1 (one block for each header).
2551 * this gives
2552 * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2553 * which reduces to the expression used.
2554 * one is added to account for this first extent.
2555 *
2556 * When one is dealing with extremely large archives, one may want
2557 * to allow for a large number of extents. This code should be
2558 * revisited to determine if extents should be changed to something
2559 * larger than an int.
2560 */
2561 extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
2562
2563 if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */
2564 (void) fprintf(stderr, gettext(
2565 "tar: %s needs unusual number of volumes to split\n"
2566 "tar: %s not dumped\n"), longname, longname);
2567 return;
2568 }
2569 if (build_dblock(name, tchar, '0', filetype,
2570 &stbuf, stbuf.st_dev, prefix) != 0)
2571 return;
2572
2573 dblock.dbuf.extotal = extents;
2574 bytes = stbuf.st_size;
2575
2576 /*
2577 * The value contained in dblock.dbuf.efsize was formerly used when the
2578 * v flag was specified in conjunction with the t flag. Although it is
2579 * no longer used, older versions of tar will expect the former
2580 * behaviour, so we must continue to write it to the archive.
2581 *
2582 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2583 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2584 * store 0.
2585 */
2586 if (bytes <= TAR_EFSIZE_MAX)
2587 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
2588 else
2589 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
2590
2591 (void) fprintf(stderr, gettext(
2592 "tar: large file %s needs %d extents.\n"
2593 "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
2594 longname, extents, K(tapepos));
2595
2596 s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
2597 for (i = 1; i <= extents; i++) {
2598 if (i > 1) {
2599 newvol();
2600 if (i == extents)
2601 s = bytes; /* last ext. gets true bytes */
2602 else
2603 s = (off_t)(blocklim - 1)*TBLOCK; /* all */
2604 }
2605 bytes -= s;
2606 blocks = TBLOCKS(s);
2607
2608 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
2609 dblock.dbuf.extno = i;
2610 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2611 (void) writetbuf((char *)&dblock, 1);
2612
2613 if (vflag)
2614 (void) fprintf(vfile,
2615 gettext("+++ a %s %" FMT_blkcnt_t
2616 "K [extent #%d of %d]\n"),
2617 longname, K(blocks), i, extents);
2618 while (blocks && read(ifd, buf, TBLOCK) > 0) {
2619 blocks--;
2620 (void) writetbuf(buf, 1);
2621 }
2622 if (blocks != 0) {
2623 (void) fprintf(stderr, gettext(
2624 "tar: %s: file changed size\n"), longname);
2625 (void) fprintf(stderr, gettext(
2626 "tar: aborting split file %s\n"), longname);
2627 (void) close(ifd);
2628 return;
2629 }
2630 }
2631 (void) close(ifd);
2632 if (vflag)
2633 (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
2634 "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
2635 extents);
2636 }
2637
2638 /*
2639 * convtoreg - determines whether the file should be converted to a
2640 * regular file when extracted
2641 *
2642 * Returns 1 when file size > 0 and typeflag is not recognized
2643 * Otherwise returns 0
2644 */
2645 static int
2646 convtoreg(off_t size)
2647 {
2648 if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
2649 (dblock.dbuf.typeflag != '\0') && (dblock.dbuf.typeflag != '1') &&
2650 (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
2651 (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
2652 (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
2653 (dblock.dbuf.typeflag != 'L') &&
2654 (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
2655 (dblock.dbuf.typeflag != 'X')) {
2656 return (1);
2657 }
2658 return (0);
2659 }
2660
2661 #if defined(O_XATTR)
2662 static int
2663 save_cwd(void)
2664 {
2665 return (open(".", O_RDONLY));
2666 }
2667 #endif
2668
2669 #if defined(O_XATTR)
2670 static void
2671 rest_cwd(int *cwd)
2672 {
2673 if (*cwd != -1) {
2674 if (fchdir(*cwd) < 0) {
2675 vperror(0, gettext(
2676 "Cannot fchdir to attribute directory"));
2677 exit(1);
2678 }
2679 (void) close(*cwd);
2680 *cwd = -1;
2681 }
2682 }
2683 #endif
2684
2685 /*
2686 * Verify the underlying file system supports the attribute type.
2687 * Only archive extended attribute files when '-@' was specified.
2688 * Only archive system extended attribute files if '-/' was specified.
2689 */
2690 #if defined(O_XATTR)
2691 static attr_status_t
2692 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
2693 int *ext_attrflg)
2694 {
2695 /*
2696 * Verify extended attributes are supported/exist. We only
2697 * need to check if we are processing a base file, not an
2698 * extended attribute.
2699 */
2700 if (attrflg) {
2701 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
2702 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
2703 }
2704
2705 if (atflag) {
2706 if (!*ext_attrflg) {
2707 #if defined(_PC_SATTR_ENABLED)
2708 if (saflag) {
2709 /* Verify system attributes are supported */
2710 if (sysattr_support(filename,
2711 (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
2712 _PC_SATTR_ENABLED) != 1) {
2713 return (ATTR_SATTR_ERR);
2714 }
2715 } else
2716 return (ATTR_XATTR_ERR);
2717 #else
2718 return (ATTR_XATTR_ERR);
2719 #endif /* _PC_SATTR_ENABLED */
2720 }
2721
2722 #if defined(_PC_SATTR_ENABLED)
2723 } else if (saflag) {
2724 /* Verify system attributes are supported */
2725 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
2726 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
2727 return (ATTR_SATTR_ERR);
2728 }
2729 #endif /* _PC_SATTR_ENABLED */
2730 } else {
2731 return (ATTR_SKIP);
2732 }
2733
2734 return (ATTR_OK);
2735 }
2736 #endif
2737
2738 #if defined(O_XATTR)
2739 /*
2740 * Recursively open attribute directories until the attribute directory
2741 * containing the specified attribute, attrname, is opened.
2742 *
2743 * Currently, only 2 directory levels of attributes are supported, (i.e.,
2744 * extended system attributes on extended attributes). The following are
2745 * the possible input combinations:
2746 * 1. Open the attribute directory of the base file (don't change
2747 * into it).
2748 * attrinfo->parent = NULL
2749 * attrname = '.'
2750 * 2. Open the attribute directory of the base file and change into it.
2751 * attrinfo->parent = NULL
2752 * attrname = <attr> | <sys_attr>
2753 * 3. Open the attribute directory of the base file, change into it,
2754 * then recursively call open_attr_dir() to open the attribute's
2755 * parent directory (don't change into it).
2756 * attrinfo->parent = <attr>
2757 * attrname = '.'
2758 * 4. Open the attribute directory of the base file, change into it,
2759 * then recursively call open_attr_dir() to open the attribute's
2760 * parent directory and change into it.
2761 * attrinfo->parent = <attr>
2762 * attrname = <attr> | <sys_attr>
2763 *
2764 * An attribute directory will be opened only if the underlying file system
2765 * supports the attribute type, and if the command line specifications (atflag
2766 * and saflag) enable the processing of the attribute type.
2767 *
2768 * On succesful return, attrinfo->parentfd will be the file descriptor of the
2769 * opened attribute directory. In addition, if the attribute is a read-write
2770 * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2771 * it will be set to 0.
2772 *
2773 * Possible return values:
2774 * ATTR_OK Successfully opened and, if needed, changed into the
2775 * attribute directory containing attrname.
2776 * ATTR_SKIP The command line specifications don't enable the
2777 * processing of the attribute type.
2778 * ATTR_CHDIR_ERR An error occurred while trying to change into an
2779 * attribute directory.
2780 * ATTR_OPEN_ERR An error occurred while trying to open an
2781 * attribute directory.
2782 * ATTR_XATTR_ERR The underlying file system doesn't support extended
2783 * attributes.
2784 * ATTR_SATTR_ERR The underlying file system doesn't support extended
2785 * system attributes.
2786 */
2787 static int
2788 open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
2789 {
2790 attr_status_t rc;
2791 int firsttime = (attrinfo->attr_parentfd == -1);
2792 int saveerrno;
2793 int ext_attr;
2794
2795 /*
2796 * open_attr_dir() was recursively called (input combination number 4),
2797 * close the previously opened file descriptor as we've already changed
2798 * into it.
2799 */
2800 if (!firsttime) {
2801 (void) close(attrinfo->attr_parentfd);
2802 attrinfo->attr_parentfd = -1;
2803 }
2804
2805 /*
2806 * Verify that the underlying file system supports the restoration
2807 * of the attribute.
2808 */
2809 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
2810 &ext_attr)) != ATTR_OK) {
2811 return (rc);
2812 }
2813
2814 /* Open the base file's attribute directory */
2815 if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
2816 /*
2817 * Save the errno from the attropen so it can be reported
2818 * if the retry of the attropen fails.
2819 */
2820 saveerrno = errno;
2821 if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
2822 NULL, ".", O_RDONLY, 0)) == -1) {
2823 /*
2824 * Reset typeflag back to real value so passtape
2825 * will skip ahead correctly.
2826 */
2827 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2828 (void) close(attrinfo->attr_parentfd);
2829 attrinfo->attr_parentfd = -1;
2830 errno = saveerrno;
2831 return (ATTR_OPEN_ERR);
2832 }
2833 }
2834
2835 /*
2836 * Change into the parent attribute's directory unless we are
2837 * processing the hidden attribute directory of the base file itself.
2838 */
2839 if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
2840 if (fchdir(attrinfo->attr_parentfd) != 0) {
2841 saveerrno = errno;
2842 (void) close(attrinfo->attr_parentfd);
2843 attrinfo->attr_parentfd = -1;
2844 errno = saveerrno;
2845 return (ATTR_CHDIR_ERR);
2846 }
2847 }
2848
2849 /* Determine if the attribute should be processed */
2850 if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
2851 &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
2852 saveerrno = errno;
2853 (void) close(attrinfo->attr_parentfd);
2854 attrinfo->attr_parentfd = -1;
2855 errno = saveerrno;
2856 return (rc);
2857 }
2858
2859 /*
2860 * If the attribute is an extended attribute, or extended system
2861 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2862 * recursively call open_attr_dir() to open the attribute directory
2863 * of the parent attribute.
2864 */
2865 if (firsttime && (attrinfo->attr_parent != NULL)) {
2866 return (open_attr_dir(attrname, attrinfo->attr_parent,
2867 attrinfo->attr_parentfd, attrinfo));
2868 }
2869
2870 return (ATTR_OK);
2871 }
2872 #endif
2873
2874 static void
2875 doxtract(char *argv[])
2876 {
2877 struct stat xtractbuf; /* stat on file after extracting */
2878 blkcnt_t blocks;
2879 off_t bytes;
2880 int ofile;
2881 int newfile; /* Does the file already exist */
2882 int xcnt = 0; /* count # files extracted */
2883 int fcnt = 0; /* count # files in argv list */
2884 int dir;
2885 int dirfd = -1;
2886 int cwd = -1;
2887 int rw_sysattr;
2888 int saveerrno;
2889 uid_t Uid;
2890 char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
2891 char dirname[PATH_MAX+1];
2892 char templink[PATH_MAX+1]; /* temp link with terminating NULL */
2893 int once = 1;
2894 int error;
2895 int symflag;
2896 int want;
2897 attr_data_t *attrinfo = NULL; /* attribute info */
2898 acl_t *aclp = NULL; /* acl info */
2899 char dot[] = "."; /* dirp for using realpath */
2900 timestruc_t time_zero; /* used for call to doDirTimes */
2901 int dircreate;
2902 int convflag;
2903 time_zero.tv_sec = 0;
2904 time_zero.tv_nsec = 0;
2905
2906 /* reset Trusted Extensions variables */
2907 rpath_flag = 0;
2908 lk_rpath_flag = 0;
2909 dir_flag = 0;
2910 mld_flag = 0;
2911 bslundef(&bs_label);
2912 bsllow(&admin_low);
2913 bslhigh(&admin_high);
2914 orig_namep = 0;
2915
2916 dumping = 0; /* for newvol(), et al: we are not writing */
2917
2918 Uid = getuid();
2919
2920 for (;;) {
2921 convflag = 0;
2922 symflag = 0;
2923 dir = 0;
2924 Hiddendir = 0;
2925 rw_sysattr = 0;
2926 ofile = -1;
2927
2928 if (dirfd != -1) {
2929 (void) close(dirfd);
2930 dirfd = -1;
2931 }
2932 if (ofile != -1) {
2933 if (close(ofile) != 0)
2934 vperror(2, gettext("close error"));
2935 }
2936
2937 #if defined(O_XATTR)
2938 if (cwd != -1) {
2939 rest_cwd(&cwd);
2940 }
2941 #endif
2942
2943 /* namep is set by wantit to point to the full name */
2944 if ((want = wantit(argv, &namep, &dirp, &comp,
2945 &attrinfo)) == 0) {
2946 #if defined(O_XATTR)
2947 if (xattrp != NULL) {
2948 free(xattrhead);
2949 xattrp = NULL;
2950 xattr_linkp = NULL;
2951 xattrhead = NULL;
2952 }
2953 #endif
2954 continue;
2955 }
2956 if (want == -1)
2957 break;
2958
2959 /* Trusted Extensions */
2960 /*
2961 * During tar extract (x):
2962 * If the pathname of the restored file has been
2963 * reconstructed from the ancillary file,
2964 * use it to process the normal file.
2965 */
2966 if (mld_flag) { /* Skip over .MLD. directory */
2967 mld_flag = 0;
2968 passtape();
2969 continue;
2970 }
2971 orig_namep = namep; /* save original */
2972 if (rpath_flag) {
2973 namep = real_path; /* use zone path */
2974 comp = real_path; /* use zone path */
2975 dirp = dot; /* work from the top */
2976 rpath_flag = 0; /* reset */
2977 }
2978
2979 if (dirfd != -1)
2980 (void) close(dirfd);
2981
2982 (void) strcpy(&dirname[0], namep);
2983 dircreate = checkdir(&dirname[0]);
2984
2985 #if defined(O_XATTR)
2986 if (xattrp != NULL) {
2987 int rc;
2988
2989 if (((cwd = save_cwd()) == -1) ||
2990 ((rc = open_attr_dir(comp, dirp, cwd,
2991 attrinfo)) != ATTR_OK)) {
2992 if (cwd == -1) {
2993 vperror(0, gettext(
2994 "unable to save current working "
2995 "directory while processing "
2996 "attribute %s of %s"),
2997 dirp, attrinfo->attr_path);
2998 } else if (rc != ATTR_SKIP) {
2999 (void) fprintf(vfile,
3000 gettext("tar: cannot open "
3001 "%sattribute %s of file %s: %s\n"),
3002 attrinfo->attr_rw_sysattr ? gettext(
3003 "system ") : "",
3004 comp, dirp, strerror(errno));
3005 }
3006 free(xattrhead);
3007 xattrp = NULL;
3008 xattr_linkp = NULL;
3009 xattrhead = NULL;
3010
3011 passtape();
3012 continue;
3013 } else {
3014 dirfd = attrinfo->attr_parentfd;
3015 rw_sysattr = attrinfo->attr_rw_sysattr;
3016 }
3017 } else {
3018 dirfd = open(dirp, O_RDONLY);
3019 }
3020 #else
3021 dirfd = open(dirp, O_RDONLY);
3022 #endif
3023 if (dirfd == -1) {
3024 (void) fprintf(vfile, gettext(
3025 "tar: cannot open %s: %s\n"),
3026 dirp, strerror(errno));
3027 passtape();
3028 continue;
3029 }
3030
3031 if (xhdr_flgs & _X_LINKPATH)
3032 (void) strcpy(templink, Xtarhdr.x_linkpath);
3033 else {
3034 #if defined(O_XATTR)
3035 if (xattrp && dblock.dbuf.typeflag == '1') {
3036 (void) sprintf(templink, "%.*s", NAMSIZ,
3037 xattrp->h_names);
3038 } else {
3039 (void) sprintf(templink, "%.*s", NAMSIZ,
3040 dblock.dbuf.linkname);
3041 }
3042 #else
3043 (void) sprintf(templink, "%.*s", NAMSIZ,
3044 dblock.dbuf.linkname);
3045 #endif
3046 }
3047
3048 if (Fflag) {
3049 if (checkf(namep, is_directory(namep), Fflag) == 0) {
3050 passtape();
3051 continue;
3052 }
3053 }
3054
3055 if (checkw('x', namep) == 0) {
3056 passtape();
3057 continue;
3058 }
3059 if (once) {
3060 if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
3061 if (geteuid() == (uid_t)0) {
3062 checkflag = 1;
3063 pflag = 1;
3064 } else {
3065 /* get file creation mask */
3066 Oumask = umask(0);
3067 (void) umask(Oumask);
3068 }
3069 once = 0;
3070 } else {
3071 if (geteuid() == (uid_t)0) {
3072 pflag = 1;
3073 checkflag = 2;
3074 }
3075 if (!pflag) {
3076 /* get file creation mask */
3077 Oumask = umask(0);
3078 (void) umask(Oumask);
3079 }
3080 once = 0;
3081 }
3082 }
3083
3084 #if defined(O_XATTR)
3085 /*
3086 * Handle extraction of hidden attr dir.
3087 * Dir is automatically created, we only
3088 * need to update mode and perm's.
3089 */
3090 if ((xattrp != NULL) && Hiddendir == 1) {
3091 bytes = stbuf.st_size;
3092 blocks = TBLOCKS(bytes);
3093 if (vflag) {
3094 (void) fprintf(vfile,
3095 "x %s%s%s, %" FMT_off_t " %s, ", namep,
3096 gettext(" attribute "),
3097 xattrapath, bytes,
3098 gettext("bytes"));
3099 if (NotTape)
3100 (void) fprintf(vfile,
3101 "%" FMT_blkcnt_t "K\n", K(blocks));
3102 else
3103 (void) fprintf(vfile, gettext("%"
3104 FMT_blkcnt_t " tape blocks\n"),
3105 blocks);
3106 }
3107
3108 /*
3109 * Set the permissions and mode of the attribute
3110 * unless the attribute is a system attribute (can't
3111 * successfully do this) or the hidden attribute
3112 * directory (".") of an attribute (when the attribute
3113 * is restored, the hidden attribute directory of an
3114 * attribute is transient). Note: when the permissions
3115 * and mode are set for the hidden attribute directory
3116 * of a file on a system supporting extended system
3117 * attributes, even though it returns successfully, it
3118 * will not have any affect since the attribute
3119 * directory is transient.
3120 */
3121 if (attrinfo->attr_parent == NULL) {
3122 if (fchownat(dirfd, ".", stbuf.st_uid,
3123 stbuf.st_gid, 0) != 0) {
3124 vperror(0, gettext(
3125 "%s%s%s: failed to set ownership "
3126 "of attribute directory"), namep,
3127 gettext(" attribute "), xattrapath);
3128 }
3129
3130 if (fchmod(dirfd, stbuf.st_mode) != 0) {
3131 vperror(0, gettext(
3132 "%s%s%s: failed to set permissions "
3133 "of attribute directory"), namep,
3134 gettext(" attribute "), xattrapath);
3135 }
3136 }
3137 goto filedone;
3138 }
3139 #endif
3140
3141 if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
3142 dir = 1;
3143 if (vflag) {
3144 (void) fprintf(vfile, "x %s, 0 %s, ",
3145 &dirname[0], gettext("bytes"));
3146 if (NotTape)
3147 (void) fprintf(vfile, "0K\n");
3148 else
3149 (void) fprintf(vfile, gettext("%"
3150 FMT_blkcnt_t " tape blocks\n"),
3151 (blkcnt_t)0);
3152 }
3153 goto filedone;
3154 }
3155
3156 if (dblock.dbuf.typeflag == '6') { /* FIFO */
3157 if (rmdir(namep) < 0) {
3158 if (errno == ENOTDIR)
3159 (void) unlink(namep);
3160 }
3161 linkp = templink;
3162 if (*linkp != '\0') {
3163 if (Aflag && *linkp == '/')
3164 linkp++;
3165 if (link(linkp, namep) < 0) {
3166 (void) fprintf(stderr, gettext(
3167 "tar: %s: cannot link\n"), namep);
3168 continue;
3169 }
3170 if (vflag)
3171 (void) fprintf(vfile, gettext(
3172 "x %s linked to %s\n"), namep,
3173 linkp);
3174 xcnt++; /* increment # files extracted */
3175 continue;
3176 }
3177 if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
3178 (int)Gen.g_devmajor) < 0) {
3179 vperror(0, gettext("%s: mknod failed"), namep);
3180 continue;
3181 }
3182 bytes = stbuf.st_size;
3183 blocks = TBLOCKS(bytes);
3184 if (vflag) {
3185 (void) fprintf(vfile, "x %s, %" FMT_off_t
3186 " %s, ", namep, bytes, gettext("bytes"));
3187 if (NotTape)
3188 (void) fprintf(vfile, "%" FMT_blkcnt_t
3189 "K\n", K(blocks));
3190 else
3191 (void) fprintf(vfile, gettext("%"
3192 FMT_blkcnt_t " tape blocks\n"),
3193 blocks);
3194 }
3195 goto filedone;
3196 }
3197 if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
3198 if (rmdir(namep) < 0) {
3199 if (errno == ENOTDIR)
3200 (void) unlink(namep);
3201 }
3202 linkp = templink;
3203 if (*linkp != '\0') {
3204 if (Aflag && *linkp == '/')
3205 linkp++;
3206 if (link(linkp, namep) < 0) {
3207 (void) fprintf(stderr, gettext(
3208 "tar: %s: cannot link\n"), namep);
3209 continue;
3210 }
3211 if (vflag)
3212 (void) fprintf(vfile, gettext(
3213 "x %s linked to %s\n"), namep,
3214 linkp);
3215 xcnt++; /* increment # files extracted */
3216 continue;
3217 }
3218 if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
3219 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3220 vperror(0, gettext(
3221 "%s: mknod failed"), namep);
3222 continue;
3223 }
3224 bytes = stbuf.st_size;
3225 blocks = TBLOCKS(bytes);
3226 if (vflag) {
3227 (void) fprintf(vfile, "x %s, %" FMT_off_t
3228 " %s, ", namep, bytes, gettext("bytes"));
3229 if (NotTape)
3230 (void) fprintf(vfile, "%" FMT_blkcnt_t
3231 "K\n", K(blocks));
3232 else
3233 (void) fprintf(vfile, gettext("%"
3234 FMT_blkcnt_t " tape blocks\n"),
3235 blocks);
3236 }
3237 goto filedone;
3238 } else if (dblock.dbuf.typeflag == '3' && Uid) {
3239 (void) fprintf(stderr, gettext(
3240 "Can't create special %s\n"), namep);
3241 continue;
3242 }
3243
3244 /* BLOCK SPECIAL */
3245
3246 if (dblock.dbuf.typeflag == '4' && !Uid) {
3247 if (rmdir(namep) < 0) {
3248 if (errno == ENOTDIR)
3249 (void) unlink(namep);
3250 }
3251 linkp = templink;
3252 if (*linkp != '\0') {
3253 if (Aflag && *linkp == '/')
3254 linkp++;
3255 if (link(linkp, namep) < 0) {
3256 (void) fprintf(stderr, gettext(
3257 "tar: %s: cannot link\n"), namep);
3258 continue;
3259 }
3260 if (vflag)
3261 (void) fprintf(vfile, gettext(
3262 "x %s linked to %s\n"), namep,
3263 linkp);
3264 xcnt++; /* increment # files extracted */
3265 continue;
3266 }
3267 if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
3268 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3269 vperror(0, gettext("%s: mknod failed"), namep);
3270 continue;
3271 }
3272 bytes = stbuf.st_size;
3273 blocks = TBLOCKS(bytes);
3274 if (vflag) {
3275 (void) fprintf(vfile, gettext("x %s, %"
3276 FMT_off_t " bytes, "), namep, bytes);
3277 if (NotTape)
3278 (void) fprintf(vfile, "%" FMT_blkcnt_t
3279 "K\n", K(blocks));
3280 else
3281 (void) fprintf(vfile, gettext("%"
3282 FMT_blkcnt_t " tape blocks\n"),
3283 blocks);
3284 }
3285 goto filedone;
3286 } else if (dblock.dbuf.typeflag == '4' && Uid) {
3287 (void) fprintf(stderr,
3288 gettext("Can't create special %s\n"), namep);
3289 continue;
3290 }
3291 if (dblock.dbuf.typeflag == '2') { /* symlink */
3292 if ((Tflag) && (lk_rpath_flag == 1))
3293 linkp = lk_real_path;
3294 else
3295 linkp = templink;
3296 if (Aflag && *linkp == '/')
3297 linkp++;
3298 if (rmdir(namep) < 0) {
3299 if (errno == ENOTDIR)
3300 (void) unlink(namep);
3301 }
3302 if (symlink(linkp, namep) < 0) {
3303 vperror(0, gettext("%s: symbolic link failed"),
3304 namep);
3305 continue;
3306 }
3307 if (vflag)
3308 (void) fprintf(vfile, gettext(
3309 "x %s symbolic link to %s\n"),
3310 namep, linkp);
3311
3312 symflag = AT_SYMLINK_NOFOLLOW;
3313 goto filedone;
3314 }
3315 if (dblock.dbuf.typeflag == '1') {
3316 linkp = templink;
3317 if (Aflag && *linkp == '/')
3318 linkp++;
3319 if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
3320 if (errno == ENOTDIR)
3321 (void) unlinkat(dirfd, comp, 0);
3322 }
3323 #if defined(O_XATTR)
3324 if (xattrp && xattr_linkp) {
3325 if (fchdir(dirfd) < 0) {
3326 vperror(0, gettext(
3327 "Cannot fchdir to attribute "
3328 "directory %s"),
3329 (attrinfo->attr_parent == NULL) ?
3330 dirp : attrinfo->attr_parent);
3331 exit(1);
3332 }
3333
3334 error = link(xattr_linkaname, xattrapath);
3335 } else {
3336 error = link(linkp, namep);
3337 }
3338 #else
3339 error = link(linkp, namep);
3340 #endif
3341
3342 if (error < 0) {
3343 (void) fprintf(stderr, gettext(
3344 "tar: %s%s%s: cannot link\n"),
3345 namep, (xattr_linkp != NULL) ?
3346 gettext(" attribute ") : "",
3347 (xattr_linkp != NULL) ?
3348 xattrapath : "");
3349 continue;
3350 }
3351 if (vflag)
3352 (void) fprintf(vfile, gettext(
3353 "x %s%s%s linked to %s%s%s\n"), namep,
3354 (xattr_linkp != NULL) ?
3355 gettext(" attribute ") : "",
3356 (xattr_linkp != NULL) ?
3357 xattr_linkaname : "",
3358 linkp,
3359 (xattr_linkp != NULL) ?
3360 gettext(" attribute ") : "",
3361 (xattr_linkp != NULL) ? xattrapath : "");
3362 xcnt++; /* increment # files extracted */
3363 #if defined(O_XATTR)
3364 if (xattrp != NULL) {
3365 free(xattrhead);
3366 xattrp = NULL;
3367 xattr_linkp = NULL;
3368 xattrhead = NULL;
3369 }
3370 #endif
3371 continue;
3372 }
3373
3374 /* REGULAR FILES */
3375
3376 if (convtoreg(stbuf.st_size)) {
3377 convflag = 1;
3378 if (errflag) {
3379 (void) fprintf(stderr, gettext(
3380 "tar: %s: typeflag '%c' not recognized\n"),
3381 namep, dblock.dbuf.typeflag);
3382 done(1);
3383 } else {
3384 (void) fprintf(stderr, gettext(
3385 "tar: %s: typeflag '%c' not recognized, "
3386 "converting to regular file\n"), namep,
3387 dblock.dbuf.typeflag);
3388 Errflg = 1;
3389 }
3390 }
3391 if (dblock.dbuf.typeflag == '0' ||
3392 dblock.dbuf.typeflag == '\0' || convflag) {
3393 delete_target(dirfd, comp, namep);
3394 linkp = templink;
3395 if (*linkp != '\0') {
3396 if (Aflag && *linkp == '/')
3397 linkp++;
3398 if (link(linkp, comp) < 0) {
3399 (void) fprintf(stderr, gettext(
3400 "tar: %s: cannot link\n"), namep);
3401 continue;
3402 }
3403 if (vflag)
3404 (void) fprintf(vfile, gettext(
3405 "x %s linked to %s\n"), comp,
3406 linkp);
3407 xcnt++; /* increment # files extracted */
3408 #if defined(O_XATTR)
3409 if (xattrp != NULL) {
3410 free(xattrhead);
3411 xattrp = NULL;
3412 xattr_linkp = NULL;
3413 xattrhead = NULL;
3414 }
3415 #endif
3416 continue;
3417 }
3418 newfile = ((fstatat(dirfd, comp,
3419 &xtractbuf, 0) == -1) ? TRUE : FALSE);
3420 ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
3421 stbuf.st_mode & MODEMASK);
3422 saveerrno = errno;
3423
3424 #if defined(O_XATTR)
3425 if (xattrp != NULL) {
3426 if (ofile < 0) {
3427 ofile = retry_open_attr(dirfd, cwd,
3428 dirp, attrinfo->attr_parent, comp,
3429 O_RDWR|O_CREAT|O_TRUNC,
3430 stbuf.st_mode & MODEMASK);
3431 }
3432 }
3433 #endif
3434 if (ofile < 0) {
3435 errno = saveerrno;
3436 (void) fprintf(stderr, gettext(
3437 "tar: %s%s%s%s - cannot create\n"),
3438 (xattrp == NULL) ? "" : (rw_sysattr ?
3439 gettext("system attribute ") :
3440 gettext("attribute ")),
3441 (xattrp == NULL) ? "" : xattrapath,
3442 (xattrp == NULL) ? "" : gettext(" of "),
3443 (xattrp == NULL) ? comp : namep);
3444 if (errflag)
3445 done(1);
3446 else
3447 Errflg = 1;
3448 #if defined(O_XATTR)
3449 if (xattrp != NULL) {
3450 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
3451 free(xattrhead);
3452 xattrp = NULL;
3453 xattr_linkp = NULL;
3454 xattrhead = NULL;
3455 }
3456 #endif
3457 passtape();
3458 continue;
3459 }
3460
3461 if (Tflag && (check_ext_attr(namep) == 0)) {
3462 if (errflag)
3463 done(1);
3464 else
3465 Errflg = 1;
3466 passtape();
3467 continue;
3468 }
3469
3470 if (extno != 0) { /* file is in pieces */
3471 if (extotal < 1 || extotal > MAXEXT)
3472 (void) fprintf(stderr, gettext(
3473 "tar: ignoring bad extent info for "
3474 "%s%s%s%s\n"),
3475 (xattrp == NULL) ? "" : (rw_sysattr ?
3476 gettext("system attribute ") :
3477 gettext("attribute ")),
3478 (xattrp == NULL) ? "" : xattrapath,
3479 (xattrp == NULL) ? "" : gettext(" of "),
3480 (xattrp == NULL) ? comp : namep);
3481 else {
3482 /* extract it */
3483 (void) xsfile(rw_sysattr, ofile);
3484 }
3485 }
3486 extno = 0; /* let everyone know file is not split */
3487 bytes = stbuf.st_size;
3488 blocks = TBLOCKS(bytes);
3489 if (vflag) {
3490 (void) fprintf(vfile,
3491 "x %s%s%s, %" FMT_off_t " %s, ",
3492 (xattrp == NULL) ? "" : dirp,
3493 (xattrp == NULL) ? "" : (rw_sysattr ?
3494 gettext(" system attribute ") :
3495 gettext(" attribute ")),
3496 (xattrp == NULL) ? namep : xattrapath, bytes,
3497 gettext("bytes"));
3498 if (NotTape)
3499 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
3500 K(blocks));
3501 else
3502 (void) fprintf(vfile, gettext("%"
3503 FMT_blkcnt_t " tape blocks\n"), blocks);
3504 }
3505
3506 if (xblocks(rw_sysattr, bytes, ofile) != 0) {
3507 #if defined(O_XATTR)
3508 if (xattrp != NULL) {
3509 free(xattrhead);
3510 xattrp = NULL;
3511 xattr_linkp = NULL;
3512 xattrhead = NULL;
3513 }
3514 #endif
3515 continue;
3516 }
3517 filedone:
3518 if (mflag == 0 && !symflag) {
3519 if (dir)
3520 doDirTimes(namep, stbuf.st_mtim);
3521
3522 else
3523 #if defined(O_XATTR)
3524 if (xattrp != NULL) {
3525 /*
3526 * Set the time on the attribute unless
3527 * the attribute is a system attribute
3528 * (can't successfully do this) or the
3529 * hidden attribute directory, "." (the
3530 * time on the hidden attribute
3531 * directory will be updated when
3532 * attributes are restored, otherwise
3533 * it's transient).
3534 */
3535 if (!rw_sysattr && (Hiddendir == 0)) {
3536 setPathTimes(dirfd, comp,
3537 stbuf.st_mtim);
3538 }
3539 } else
3540 setPathTimes(dirfd, comp,
3541 stbuf.st_mtim);
3542 #else
3543 setPathTimes(dirfd, comp, stbuf.st_mtim);
3544 #endif
3545 }
3546
3547 /* moved this code from above */
3548 if (pflag && !symflag && Hiddendir == 0) {
3549 if (xattrp != NULL)
3550 (void) fchmod(ofile, stbuf.st_mode & MODEMASK);
3551 else
3552 (void) chmod(namep, stbuf.st_mode & MODEMASK);
3553 }
3554
3555
3556 /*
3557 * Because ancillary file preceeds the normal file,
3558 * acl info may have been retrieved (in aclp).
3559 * All file types are directed here (go filedone).
3560 * Always restore ACLs if there are ACLs.
3561 */
3562 if (aclp != NULL) {
3563 int ret;
3564
3565 #if defined(O_XATTR)
3566 if (xattrp != NULL) {
3567 if (Hiddendir)
3568 ret = facl_set(dirfd, aclp);
3569 else
3570 ret = facl_set(ofile, aclp);
3571 } else {
3572 ret = acl_set(namep, aclp);
3573 }
3574 #else
3575 ret = acl_set(namep, aclp);
3576 #endif
3577 if (ret < 0) {
3578 if (pflag) {
3579 (void) fprintf(stderr, gettext(
3580 "%s%s%s%s: failed to set acl "
3581 "entries\n"), namep,
3582 (xattrp == NULL) ? "" :
3583 (rw_sysattr ? gettext(
3584 " system attribute ") :
3585 gettext(" attribute ")),
3586 (xattrp == NULL) ? "" :
3587 xattrapath);
3588 }
3589 /* else: silent and continue */
3590 }
3591 acl_free(aclp);
3592 aclp = NULL;
3593 }
3594
3595 if (!oflag)
3596 /* set file ownership */
3597 resugname(dirfd, comp, symflag);
3598
3599 if (pflag && newfile == TRUE && !dir &&
3600 (dblock.dbuf.typeflag == '0' ||
3601 dblock.dbuf.typeflag == '\0' ||
3602 convflag || dblock.dbuf.typeflag == '1')) {
3603 if (fstat(ofile, &xtractbuf) == -1)
3604 (void) fprintf(stderr, gettext(
3605 "tar: cannot stat extracted file "
3606 "%s%s%s%s\n"),
3607 (xattrp == NULL) ? "" : (rw_sysattr ?
3608 gettext("system attribute ") :
3609 gettext("attribute ")),
3610 (xattrp == NULL) ? "" : xattrapath,
3611 (xattrp == NULL) ? "" :
3612 gettext(" of "), namep);
3613
3614 else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
3615 != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
3616 (void) fprintf(stderr, gettext(
3617 "tar: warning - file permissions have "
3618 "changed for %s%s%s%s (are 0%o, should be "
3619 "0%o)\n"),
3620 (xattrp == NULL) ? "" : (rw_sysattr ?
3621 gettext("system attribute ") :
3622 gettext("attribute ")),
3623 (xattrp == NULL) ? "" : xattrapath,
3624 (xattrp == NULL) ? "" :
3625 gettext(" of "), namep,
3626 xtractbuf.st_mode, stbuf.st_mode);
3627
3628 }
3629 }
3630 #if defined(O_XATTR)
3631 if (xattrp != NULL) {
3632 free(xattrhead);
3633 xattrp = NULL;
3634 xattr_linkp = NULL;
3635 xattrhead = NULL;
3636 }
3637 #endif
3638
3639 if (ofile != -1) {
3640 (void) close(dirfd);
3641 dirfd = -1;
3642 if (close(ofile) != 0)
3643 vperror(2, gettext("close error"));
3644 ofile = -1;
3645 }
3646 xcnt++; /* increment # files extracted */
3647 }
3648
3649 /*
3650 * Process ancillary file.
3651 *
3652 */
3653
3654 if (dblock.dbuf.typeflag == 'A') { /* acl info */
3655 char buf[TBLOCK];
3656 char *secp;
3657 char *tp;
3658 int attrsize;
3659 int cnt;
3660
3661 /* reset Trusted Extensions flags */
3662 dir_flag = 0;
3663 mld_flag = 0;
3664 lk_rpath_flag = 0;
3665 rpath_flag = 0;
3666
3667 if (pflag) {
3668 bytes = stbuf.st_size;
3669 if ((secp = malloc((int)bytes)) == NULL) {
3670 (void) fprintf(stderr, gettext(
3671 "Insufficient memory for acl\n"));
3672 passtape();
3673 continue;
3674 }
3675 tp = secp;
3676 blocks = TBLOCKS(bytes);
3677
3678 /*
3679 * Display a line for each ancillary file.
3680 */
3681 if (vflag && Tflag)
3682 (void) fprintf(vfile, "x %s(A), %"
3683 FMT_blkcnt_t " %s, %"
3684 FMT_blkcnt_t " %s\n",
3685 namep, bytes, gettext("bytes"),
3686 blocks, gettext("tape blocks"));
3687
3688 while (blocks-- > 0) {
3689 readtape(buf);
3690 if (bytes <= TBLOCK) {
3691 (void) memcpy(tp, buf,
3692 (size_t)bytes);
3693 break;
3694 } else {
3695 (void) memcpy(tp, buf,
3696 TBLOCK);
3697 tp += TBLOCK;
3698 }
3699 bytes -= TBLOCK;
3700 }
3701 bytes = stbuf.st_size;
3702 /* got all attributes in secp */
3703 tp = secp;
3704 do {
3705 attr = (struct sec_attr *)tp;
3706 switch (attr->attr_type) {
3707 case UFSD_ACL:
3708 case ACE_ACL:
3709 (void) sscanf(attr->attr_len,
3710 "%7o",
3711 (uint_t *)
3712 &cnt);
3713 /* header is 8 */
3714 attrsize = 8 + (int)strlen(
3715 &attr->attr_info[0]) + 1;
3716 error =
3717 acl_fromtext(
3718 &attr->attr_info[0], &aclp);
3719
3720 if (error != 0) {
3721 (void) fprintf(stderr,
3722 gettext(
3723 "aclfromtext "
3724 "failed: %s\n"),
3725 acl_strerror(
3726 error));
3727 bytes -= attrsize;
3728 break;
3729 }
3730 if (acl_cnt(aclp) != cnt) {
3731 (void) fprintf(stderr,
3732 gettext(
3733 "aclcnt error\n"));
3734 bytes -= attrsize;
3735 break;
3736 }
3737 bytes -= attrsize;
3738 break;
3739
3740 /* Trusted Extensions */
3741
3742 case DIR_TYPE:
3743 case LBL_TYPE:
3744 case APRIV_TYPE:
3745 case FPRIV_TYPE:
3746 case COMP_TYPE:
3747 case LK_COMP_TYPE:
3748 case ATTR_FLAG_TYPE:
3749 attrsize =
3750 sizeof (struct sec_attr) +
3751 strlen(&attr->attr_info[0]);
3752 bytes -= attrsize;
3753 if (Tflag)
3754 extract_attr(&namep,
3755 attr);
3756 break;
3757
3758 default:
3759 (void) fprintf(stderr, gettext(
3760 "unrecognized attr"
3761 " type\n"));
3762 bytes = (off_t)0;
3763 break;
3764 }
3765
3766 /* next attributes */
3767 tp += attrsize;
3768 } while (bytes != 0);
3769 free(secp);
3770 } else {
3771 passtape();
3772 }
3773 } /* acl */
3774
3775 } /* for */
3776
3777 /*
3778 * Ensure that all the directories still on the directory stack
3779 * get their modification times set correctly by flushing the
3780 * stack.
3781 */
3782
3783 doDirTimes(NULL, time_zero);
3784
3785 #if defined(O_XATTR)
3786 if (xattrp != NULL) {
3787 free(xattrhead);
3788 xattrp = NULL;
3789 xattr_linkp = NULL;
3790 xattrhead = NULL;
3791 }
3792 #endif
3793
3794 /*
3795 * Check if the number of files extracted is different from the
3796 * number of files listed on the command line
3797 */
3798 if (fcnt > xcnt) {
3799 (void) fprintf(stderr,
3800 gettext("tar: %d file(s) not extracted\n"),
3801 fcnt-xcnt);
3802 Errflg = 1;
3803 }
3804 }
3805
3806 /*
3807 * xblocks extract file/extent from tape to output file
3808 *
3809 * xblocks(issysattr, bytes, ofile);
3810 *
3811 * issysattr flag set if the files being extracted
3812 * is an extended system attribute file.
3813 * unsigned long long bytes size of extent or file to be extracted
3814 * ofile output file
3815 *
3816 * called by doxtract() and xsfile()
3817 */
3818
3819 static int
3820 xblocks(int issysattr, off_t bytes, int ofile)
3821 {
3822 char *buf;
3823 char tempname[NAMSIZ+1];
3824 size_t maxwrite;
3825 size_t bytesread;
3826 size_t piosize; /* preferred I/O size */
3827 struct stat tsbuf;
3828
3829 /* Don't need to do anything if this is a zero size file */
3830 if (bytes <= 0) {
3831 return (0);
3832 }
3833
3834 /*
3835 * To figure out the size of the buffer used to accumulate data
3836 * from readtape() and to write to the file, we need to determine
3837 * the largest chunk of data to be written to the file at one time.
3838 * This is determined based on the smallest of the following two
3839 * things:
3840 * 1) The size of the archived file.
3841 * 2) The preferred I/O size of the file.
3842 */
3843 if (issysattr || (bytes <= TBLOCK)) {
3844 /*
3845 * Writes to system attribute files must be
3846 * performed in one operation.
3847 */
3848 maxwrite = bytes;
3849 } else {
3850 /*
3851 * fstat() the file to get the preferred I/O size.
3852 * If it fails, then resort back to just writing
3853 * one block at a time.
3854 */
3855 if (fstat(ofile, &tsbuf) == 0) {
3856 piosize = tsbuf.st_blksize;
3857 } else {
3858 piosize = TBLOCK;
3859 }
3860 maxwrite = min(bytes, piosize);
3861 }
3862
3863 /*
3864 * The buffer used to accumulate the data for the write operation
3865 * needs to be the maximum number of bytes to be written rounded up
3866 * to the nearest TBLOCK since readtape reads one block at a time.
3867 */
3868 if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
3869 fatal(gettext("cannot allocate buffer"));
3870 }
3871
3872 while (bytes > 0) {
3873
3874 /*
3875 * readtape() obtains one block (TBLOCK) of data at a time.
3876 * Accumulate as many blocks of data in buf as we can write
3877 * in one operation.
3878 */
3879 for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
3880 readtape(buf + bytesread);
3881 }
3882
3883 if (write(ofile, buf, maxwrite) < 0) {
3884 int saveerrno = errno;
3885
3886 if (xhdr_flgs & _X_PATH)
3887 (void) strlcpy(tempname, Xtarhdr.x_path,
3888 sizeof (tempname));
3889 else
3890 (void) sprintf(tempname, "%.*s", NAMSIZ,
3891 dblock.dbuf.name);
3892 /*
3893 * If the extended system attribute being extracted
3894 * contains attributes that the user needs privileges
3895 * for, then just display a warning message, skip
3896 * the extraction of this file, and return.
3897 */
3898 if ((saveerrno == EPERM) && issysattr) {
3899 (void) fprintf(stderr, gettext(
3900 "tar: unable to extract system attribute "
3901 "%s: insufficient privileges\n"), tempname);
3902 Errflg = 1;
3903 (void) free(buf);
3904 return (1);
3905 } else {
3906 (void) fprintf(stderr, gettext(
3907 "tar: %s: HELP - extract write error\n"),
3908 tempname);
3909 done(2);
3910 }
3911 }
3912 bytes -= maxwrite;
3913
3914 /*
3915 * If we've reached this point and there is still data
3916 * to be written, maxwrite had to have been determined
3917 * by the preferred I/O size. If the number of bytes
3918 * left to write is smaller than the preferred I/O size,
3919 * then we're about to do our final write to the file, so
3920 * just set maxwrite to the number of bytes left to write.
3921 */
3922 if ((bytes > 0) && (bytes < maxwrite)) {
3923 maxwrite = bytes;
3924 }
3925 }
3926 free(buf);
3927
3928 return (0);
3929 }
3930
3931 /*
3932 * xsfile extract split file
3933 *
3934 * xsfile(ofd); ofd = output file descriptor
3935 *
3936 * file extracted and put in ofd via xblocks()
3937 *
3938 * NOTE: only called by doxtract() to extract one large file
3939 */
3940
3941 static union hblock savedblock; /* to ensure same file across volumes */
3942
3943 static int
3944 xsfile(int issysattr, int ofd)
3945 {
3946 int i, c;
3947 int sysattrerr = 0;
3948 char name[PATH_MAX+1]; /* holds name for diagnostics */
3949 int extents, totalext;
3950 off_t bytes, totalbytes;
3951
3952 if (xhdr_flgs & _X_PATH)
3953 (void) strcpy(name, Xtarhdr.x_path);
3954 else
3955 (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
3956
3957 totalbytes = (off_t)0; /* in case we read in half the file */
3958 totalext = 0; /* these keep count */
3959
3960 (void) fprintf(stderr, gettext(
3961 "tar: %s split across %d volumes\n"), name, extotal);
3962
3963 /* make sure we do extractions in order */
3964 if (extno != 1) { /* starting in middle of file? */
3965 (void) printf(gettext(
3966 "tar: first extent read is not #1\n"
3967 "OK to read file beginning with extent #%d (%s/%s) ? "),
3968 extno, yesstr, nostr);
3969 if (yes() == 0) {
3970 canit:
3971 passtape();
3972 if (close(ofd) != 0)
3973 vperror(2, gettext("close error"));
3974 if (sysattrerr) {
3975 return (1);
3976 } else {
3977 return (0);
3978 }
3979 }
3980 }
3981 extents = extotal;
3982 i = extno;
3983 /*CONSTCOND*/
3984 while (1) {
3985 if (xhdr_flgs & _X_SIZE) {
3986 bytes = extsize;
3987 } else {
3988 bytes = stbuf.st_size;
3989 }
3990
3991 if (vflag)
3992 (void) fprintf(vfile, "+++ x %s [%s #%d], %"
3993 FMT_off_t " %s, %ldK\n",
3994 name, gettext("extent"), extno,
3995 bytes, gettext("bytes"),
3996 (long)K(TBLOCKS(bytes)));
3997 if (xblocks(issysattr, bytes, ofd) != 0) {
3998 sysattrerr = 1;
3999 goto canit;
4000 }
4001
4002 totalbytes += bytes;
4003 totalext++;
4004 if (++i > extents)
4005 break;
4006
4007 /* get next volume and verify it's the right one */
4008 copy(&savedblock, &dblock);
4009 tryagain:
4010 newvol();
4011 xhdr_flgs = 0;
4012 getdir();
4013 if (Xhdrflag > 0)
4014 (void) get_xdata(); /* Get x-header & regular hdr */
4015 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
4016 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
4017 xhdr_flgs |= _X_XHDR;
4018 }
4019 if (endtape()) { /* seemingly empty volume */
4020 (void) fprintf(stderr, gettext(
4021 "tar: first record is null\n"));
4022 asknicely:
4023 (void) fprintf(stderr, gettext(
4024 "tar: need volume with extent #%d of %s\n"),
4025 i, name);
4026 goto tryagain;
4027 }
4028 if (notsame()) {
4029 (void) fprintf(stderr, gettext(
4030 "tar: first file on that volume is not "
4031 "the same file\n"));
4032 goto asknicely;
4033 }
4034 if (i != extno) {
4035 (void) fprintf(stderr, gettext(
4036 "tar: extent #%d received out of order\ntar: "
4037 "should be #%d\n"), extno, i);
4038 (void) fprintf(stderr, gettext(
4039 "Ignore error, Abort this file, or "
4040 "load New volume (i/a/n) ? "));
4041 c = response();
4042 if (c == 'a')
4043 goto canit;
4044 if (c != 'i') /* default to new volume */
4045 goto asknicely;
4046 i = extno; /* okay, start from there */
4047 }
4048 }
4049 if (vflag)
4050 (void) fprintf(vfile, gettext(
4051 "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
4052 name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
4053
4054 return (0);
4055 }
4056
4057
4058 /*
4059 * notsame() check if extract file extent is invalid
4060 *
4061 * returns true if anything differs between savedblock and dblock
4062 * except extno (extent number), checksum, or size (extent size).
4063 * Determines if this header belongs to the same file as the one we're
4064 * extracting.
4065 *
4066 * NOTE: though rather bulky, it is only called once per file
4067 * extension, and it can withstand changes in the definition
4068 * of the header structure.
4069 *
4070 * WARNING: this routine is local to xsfile() above
4071 */
4072
4073 static int
4074 notsame(void)
4075 {
4076 return (
4077 (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
4078 (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
4079 (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
4080 (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
4081 (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
4082 (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
4083 (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
4084 (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
4085 (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
4086 }
4087
4088 static void
4089 dotable(char *argv[])
4090 {
4091 int tcnt = 0; /* count # files tabled */
4092 int fcnt = 0; /* count # files in argv list */
4093 char *namep, *dirp, *comp;
4094 int want;
4095 char aclchar = ' '; /* either blank or '+' */
4096 char templink[PATH_MAX+1];
4097 attr_data_t *attrinfo = NULL;
4098
4099 dumping = 0;
4100
4101 /* if not on magtape, maximize seek speed */
4102 if (NotTape && !bflag) {
4103 #if SYS_BLOCK > TBLOCK
4104 nblock = SYS_BLOCK / TBLOCK;
4105 #else
4106 nblock = 1;
4107 #endif
4108 }
4109
4110 for (;;) {
4111
4112 /* namep is set by wantit to point to the full name */
4113 if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
4114 continue;
4115 if (want == -1)
4116 break;
4117 if (dblock.dbuf.typeflag != 'A')
4118 ++tcnt;
4119
4120 if (Fflag) {
4121 if (checkf(namep, is_directory(namep), Fflag) == 0) {
4122 passtape();
4123 continue;
4124 }
4125 }
4126 /*
4127 * ACL support:
4128 * aclchar is introduced to indicate if there are
4129 * acl entries. longt() now takes one extra argument.
4130 */
4131 if (vflag) {
4132 if (dblock.dbuf.typeflag == 'A') {
4133 aclchar = '+';
4134 passtape();
4135 continue;
4136 }
4137 longt(&stbuf, aclchar);
4138 aclchar = ' ';
4139 }
4140
4141
4142 #if defined(O_XATTR)
4143 if (xattrp != NULL) {
4144 int issysattr;
4145 char *bn = basename(attrinfo->attr_path);
4146
4147 /*
4148 * We could use sysattr_type() to test whether or not
4149 * the attribute we are processing is really an
4150 * extended system attribute, which as of this writing
4151 * just does a strcmp(), however, sysattr_type() may
4152 * be changed to issue a pathconf() call instead, which
4153 * would require being changed into the parent attribute
4154 * directory. So instead, just do simple string
4155 * comparisons to see if we are processing an extended
4156 * system attribute.
4157 */
4158 issysattr = is_sysattr(bn);
4159
4160 (void) printf(gettext("%s %sattribute %s"),
4161 xattrp->h_names,
4162 issysattr ? gettext("system ") : "",
4163 attrinfo->attr_path);
4164 } else {
4165 (void) printf("%s", namep);
4166 }
4167 #else
4168 (void) printf("%s", namep);
4169 #endif
4170
4171 if (extno != 0) {
4172 if (vflag) {
4173 /* keep the '\n' for backwards compatibility */
4174 (void) fprintf(vfile, gettext(
4175 "\n [extent #%d of %d]"), extno, extotal);
4176 } else {
4177 (void) fprintf(vfile, gettext(
4178 " [extent #%d of %d]"), extno, extotal);
4179 }
4180 }
4181 if (xhdr_flgs & _X_LINKPATH) {
4182 (void) strcpy(templink, Xtarhdr.x_linkpath);
4183 } else {
4184 #if defined(O_XATTR)
4185 if (xattrp != NULL) {
4186 (void) sprintf(templink,
4187 "file %.*s", NAMSIZ, xattrp->h_names);
4188 } else {
4189 (void) sprintf(templink, "%.*s", NAMSIZ,
4190 dblock.dbuf.linkname);
4191 }
4192 #else
4193 (void) sprintf(templink, "%.*s", NAMSIZ,
4194 dblock.dbuf.linkname);
4195 #endif
4196 templink[NAMSIZ] = '\0';
4197 }
4198 if (dblock.dbuf.typeflag == '1') {
4199 /*
4200 * TRANSLATION_NOTE
4201 * Subject is omitted here.
4202 * Translate this as if
4203 * <subject> linked to %s
4204 */
4205 #if defined(O_XATTR)
4206 if (xattrp != NULL) {
4207 (void) printf(
4208 gettext(" linked to attribute %s"),
4209 xattr_linkp->h_names +
4210 strlen(xattr_linkp->h_names) + 1);
4211 } else {
4212 (void) printf(
4213 gettext(" linked to %s"), templink);
4214 }
4215 #else
4216 (void) printf(
4217 gettext(" linked to %s"), templink);
4218
4219 #endif
4220 }
4221 if (dblock.dbuf.typeflag == '2')
4222 (void) printf(gettext(
4223 /*
4224 * TRANSLATION_NOTE
4225 * Subject is omitted here.
4226 * Translate this as if
4227 * <subject> symbolic link to %s
4228 */
4229 " symbolic link to %s"), templink);
4230 (void) printf("\n");
4231 #if defined(O_XATTR)
4232 if (xattrp != NULL) {
4233 free(xattrhead);
4234 xattrp = NULL;
4235 xattrhead = NULL;
4236 }
4237 #endif
4238 passtape();
4239 }
4240 /*
4241 * Check if the number of files tabled is different from the
4242 * number of files listed on the command line
4243 */
4244 if (fcnt > tcnt) {
4245 (void) fprintf(stderr, gettext(
4246 "tar: %d file(s) not found\n"), fcnt-tcnt);
4247 Errflg = 1;
4248 }
4249 }
4250
4251 static void
4252 putempty(blkcnt_t n)
4253 {
4254 char buf[TBLOCK];
4255 char *cp;
4256
4257 for (cp = buf; cp < &buf[TBLOCK]; )
4258 *cp++ = '\0';
4259 while (n-- > 0)
4260 (void) writetbuf(buf, 1);
4261 }
4262
4263 static ushort_t Ftype = S_IFMT;
4264
4265 static void
4266 verbose(struct stat *st, char aclchar)
4267 {
4268 int i, j, temp;
4269 mode_t mode;
4270 char modestr[12];
4271
4272 for (i = 0; i < 11; i++)
4273 modestr[i] = '-';
4274 modestr[i] = '\0';
4275
4276 /* a '+' sign is printed if there is ACL */
4277 modestr[i-1] = aclchar;
4278
4279 mode = st->st_mode;
4280 for (i = 0; i < 3; i++) {
4281 temp = (mode >> (6 - (i * 3)));
4282 j = (i * 3) + 1;
4283 if (S_IROTH & temp)
4284 modestr[j] = 'r';
4285 if (S_IWOTH & temp)
4286 modestr[j + 1] = 'w';
4287 if (S_IXOTH & temp)
4288 modestr[j + 2] = 'x';
4289 }
4290 temp = st->st_mode & Ftype;
4291 switch (temp) {
4292 case (S_IFIFO):
4293 modestr[0] = 'p';
4294 break;
4295 case (S_IFCHR):
4296 modestr[0] = 'c';
4297 break;
4298 case (S_IFDIR):
4299 modestr[0] = 'd';
4300 break;
4301 case (S_IFBLK):
4302 modestr[0] = 'b';
4303 break;
4304 case (S_IFREG): /* was initialized to '-' */
4305 break;
4306 case (S_IFLNK):
4307 modestr[0] = 'l';
4308 break;
4309 default:
4310 /* This field may be zero in old archives. */
4311 if (is_posix && dblock.dbuf.typeflag != '1') {
4312 /*
4313 * For POSIX compliant archives, the mode field
4314 * consists of 12 bits, ie: the file type bits
4315 * are not stored in dblock.dbuf.mode.
4316 * For files other than hard links, getdir() sets
4317 * the file type bits in the st_mode field of the
4318 * stat structure based upon dblock.dbuf.typeflag.
4319 */
4320 (void) fprintf(stderr, gettext(
4321 "tar: impossible file type"));
4322 }
4323 }
4324
4325 if ((S_ISUID & Gen.g_mode) == S_ISUID)
4326 modestr[3] = 's';
4327 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
4328 modestr[9] = 't';
4329 if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
4330 modestr[6] = 's';
4331 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
4332 modestr[6] = 'l';
4333 (void) fprintf(vfile, "%s", modestr);
4334 }
4335
4336 static void
4337 longt(struct stat *st, char aclchar)
4338 {
4339 char fileDate[30];
4340 struct tm *tm;
4341
4342 verbose(st, aclchar);
4343 (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
4344
4345 if (dblock.dbuf.typeflag == '2') {
4346 if (xhdr_flgs & _X_LINKPATH)
4347 st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
4348 else
4349 st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
4350 '\0', NAMSIZ) ?
4351 (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
4352 }
4353 (void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
4354
4355 tm = localtime(&(st->st_mtime));
4356 (void) strftime(fileDate, sizeof (fileDate),
4357 dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
4358 (void) fprintf(vfile, " %s ", fileDate);
4359 }
4360
4361
4362 /*
4363 * checkdir - Attempt to ensure that the path represented in name
4364 * exists, and return 1 if this is true and name itself is a
4365 * directory.
4366 * Return 0 if this path cannot be created or if name is not
4367 * a directory.
4368 */
4369
4370 static int
4371 checkdir(char *name)
4372 {
4373 char lastChar; /* the last character in name */
4374 char *cp; /* scratch pointer into name */
4375 char *firstSlash = NULL; /* first slash in name */
4376 char *lastSlash = NULL; /* last slash in name */
4377 int nameLen; /* length of name */
4378 int trailingSlash; /* true if name ends in slash */
4379 int leadingSlash; /* true if name begins with slash */
4380 int markedDir; /* true if name denotes a directory */
4381 int success; /* status of makeDir call */
4382
4383
4384 /*
4385 * Scan through the name, and locate first and last slashes.
4386 */
4387
4388 for (cp = name; *cp; cp++) {
4389 if (*cp == '/') {
4390 if (! firstSlash) {
4391 firstSlash = cp;
4392 }
4393 lastSlash = cp;
4394 }
4395 }
4396
4397 /*
4398 * Determine what you can from the proceeds of the scan.
4399 */
4400
4401 lastChar = *(cp - 1);
4402 nameLen = (int)(cp - name);
4403 trailingSlash = (lastChar == '/');
4404 leadingSlash = (*name == '/');
4405 markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash);
4406
4407 if (! lastSlash && ! markedDir) {
4408 /*
4409 * The named file does not have any subdrectory
4410 * structure; just bail out.
4411 */
4412
4413 return (0);
4414 }
4415
4416 /*
4417 * Make sure that name doesn`t end with slash for the loop.
4418 * This ensures that the makeDir attempt after the loop is
4419 * meaningful.
4420 */
4421
4422 if (trailingSlash) {
4423 name[nameLen-1] = '\0';
4424 }
4425
4426 /*
4427 * Make the path one component at a time.
4428 */
4429
4430 for (cp = strchr(leadingSlash ? name+1 : name, '/');
4431 cp;
4432 cp = strchr(cp+1, '/')) {
4433 *cp = '\0';
4434 success = makeDir(name);
4435 *cp = '/';
4436
4437 if (!success) {
4438 name[nameLen-1] = lastChar;
4439 return (0);
4440 }
4441 }
4442
4443 /*
4444 * This makes the last component of the name, if it is a
4445 * directory.
4446 */
4447
4448 if (markedDir) {
4449 if (! makeDir(name)) {
4450 name[nameLen-1] = lastChar;
4451 return (0);
4452 }
4453 }
4454
4455 name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
4456 return (markedDir);
4457 }
4458
4459 /*
4460 * resugname - Restore the user name and group name. Search the NIS
4461 * before using the uid and gid.
4462 * (It is presumed that an archive entry cannot be
4463 * simultaneously a symlink and some other type.)
4464 */
4465
4466 static void
4467 resugname(int dirfd, /* dir fd file resides in */
4468 char *name, /* name of the file to be modified */
4469 int symflag) /* true if file is a symbolic link */
4470 {
4471 uid_t duid;
4472 gid_t dgid;
4473 struct stat *sp = &stbuf;
4474 char *u_g_name;
4475
4476 if (checkflag == 1) { /* Extended tar format and euid == 0 */
4477
4478 /*
4479 * Try and extract the intended uid and gid from the name
4480 * service before believing the uid and gid in the header.
4481 *
4482 * In the case where we archived a setuid or setgid file
4483 * owned by someone with a large uid, then it will
4484 * have made it into the archive with a uid of nobody. If
4485 * the corresponding username doesn't appear to exist, then we
4486 * want to make sure it *doesn't* end up as setuid nobody!
4487 *
4488 * Our caller will print an error message about the fact
4489 * that the restore didn't work out quite right ..
4490 */
4491 if (xhdr_flgs & _X_UNAME)
4492 u_g_name = Xtarhdr.x_uname;
4493 else
4494 u_g_name = dblock.dbuf.uname;
4495 if ((duid = getuidbyname(u_g_name)) == -1) {
4496 if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
4497 (sp->st_mode & S_ISUID) == S_ISUID)
4498 (void) chmod(name,
4499 MODEMASK & sp->st_mode & ~S_ISUID);
4500 duid = sp->st_uid;
4501 }
4502
4503 /* (Ditto for gids) */
4504
4505 if (xhdr_flgs & _X_GNAME)
4506 u_g_name = Xtarhdr.x_gname;
4507 else
4508 u_g_name = dblock.dbuf.gname;
4509 if ((dgid = getgidbyname(u_g_name)) == -1) {
4510 if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
4511 (sp->st_mode & S_ISGID) == S_ISGID)
4512 (void) chmod(name,
4513 MODEMASK & sp->st_mode & ~S_ISGID);
4514 dgid = sp->st_gid;
4515 }
4516 } else if (checkflag == 2) { /* tar format and euid == 0 */
4517 duid = sp->st_uid;
4518 dgid = sp->st_gid;
4519 }
4520 if ((checkflag == 1) || (checkflag == 2))
4521 (void) fchownat(dirfd, name, duid, dgid, symflag);
4522 }
4523
4524 /*ARGSUSED*/
4525 static void
4526 onintr(int sig)
4527 {
4528 (void) signal(SIGINT, SIG_IGN);
4529 term++;
4530 }
4531
4532 /*ARGSUSED*/
4533 static void
4534 onquit(int sig)
4535 {
4536 (void) signal(SIGQUIT, SIG_IGN);
4537 term++;
4538 }
4539
4540 /*ARGSUSED*/
4541 static void
4542 onhup(int sig)
4543 {
4544 (void) signal(SIGHUP, SIG_IGN);
4545 term++;
4546 }
4547
4548 static void
4549 tomodes(struct stat *sp)
4550 {
4551 uid_t uid;
4552 gid_t gid;
4553
4554 bzero(dblock.dummy, TBLOCK);
4555
4556 /*
4557 * If the uid or gid is too large, we can't put it into
4558 * the archive. We could fail to put anything in the
4559 * archive at all .. but most of the time the name service
4560 * will save the day when we do a lookup at restore time.
4561 *
4562 * Instead we choose a "safe" uid and gid, and fix up whether
4563 * or not the setuid and setgid bits are left set to extraction
4564 * time.
4565 */
4566 if (Eflag) {
4567 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
4568 xhdr_flgs |= _X_UID;
4569 Xtarhdr.x_uid = uid;
4570 }
4571 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
4572 xhdr_flgs |= _X_GID;
4573 Xtarhdr.x_gid = gid;
4574 }
4575 if (sp->st_size > TAR_OFFSET_MAX) {
4576 xhdr_flgs |= _X_SIZE;
4577 Xtarhdr.x_filesz = sp->st_size;
4578 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4579 (off_t)0);
4580 } else
4581 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4582 sp->st_size);
4583 } else {
4584 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4585 sp->st_size);
4586 }
4587 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
4588 uid = UID_NOBODY;
4589 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
4590 gid = GID_NOBODY;
4591 (void) sprintf(dblock.dbuf.gid, "%07lo", gid);
4592 (void) sprintf(dblock.dbuf.uid, "%07lo", uid);
4593 (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
4594 (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
4595 }
4596
4597 static int
4598 #ifdef EUC
4599 /*
4600 * Warning: the result of this function depends whether 'char' is a
4601 * signed or unsigned data type. This a source of potential
4602 * non-portability among heterogeneous systems. It is retained here
4603 * for backward compatibility.
4604 */
4605 checksum_signed(union hblock *dblockp)
4606 #else
4607 checksum(union hblock *dblockp)
4608 #endif /* EUC */
4609 {
4610 int i;
4611 char *cp;
4612
4613 for (cp = dblockp->dbuf.chksum;
4614 cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
4615 *cp = ' ';
4616 i = 0;
4617 for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
4618 i += *cp;
4619 return (i);
4620 }
4621
4622 #ifdef EUC
4623 /*
4624 * Generate unsigned checksum, regardless of what C compiler is
4625 * used. Survives in the face of arbitrary 8-bit clean filenames,
4626 * e.g., internationalized filenames.
4627 */
4628 static int
4629 checksum(union hblock *dblockp)
4630 {
4631 unsigned i;
4632 unsigned char *cp;
4633
4634 for (cp = (unsigned char *) dblockp->dbuf.chksum;
4635 cp < (unsigned char *)
4636 &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
4637 *cp = ' ';
4638 i = 0;
4639 for (cp = (unsigned char *) dblockp->dummy;
4640 cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
4641 i += *cp;
4642
4643 return (i);
4644 }
4645 #endif /* EUC */
4646
4647 /*
4648 * If the w flag is set, output the action to be taken and the name of the
4649 * file. Perform the action if the user response is affirmative.
4650 */
4651
4652 static int
4653 checkw(char c, char *name)
4654 {
4655 if (wflag) {
4656 (void) fprintf(vfile, "%c ", c);
4657 if (vflag)
4658 longt(&stbuf, ' '); /* do we have acl info here */
4659 (void) fprintf(vfile, "%s: ", name);
4660 if (yes() == 1) {
4661 return (1);
4662 }
4663 return (0);
4664 }
4665 return (1);
4666 }
4667
4668 /*
4669 * When the F flag is set, exclude RCS and SCCS directories (and any files
4670 * or directories under them). If F is set twice, also exclude .o files,
4671 * and files names errs, core, and a.out.
4672 *
4673 * Return 0 if file should be excluded, 1 otherwise.
4674 */
4675
4676 static int
4677 checkf(char *longname, int is_dir, int howmuch)
4678 {
4679 static char fullname[PATH_MAX + 1];
4680 char *dir, *name;
4681
4682 #if defined(O_XATTR)
4683 /*
4684 * If there is an xattr_buf structure associated with this file,
4685 * always return 1.
4686 */
4687 if (xattrp) {
4688 return (1);
4689 }
4690 #endif
4691
4692 /*
4693 * First check to see if the base name is an RCS or SCCS directory.
4694 */
4695 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4696 return (1);
4697
4698 name = basename(fullname);
4699 if (is_dir) {
4700 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4701 return (0);
4702 }
4703
4704 /*
4705 * If two -F command line options were given then exclude .o files,
4706 * and files named errs, core, and a.out.
4707 */
4708 if (howmuch > 1 && !is_dir) {
4709 size_t l = strlen(name);
4710
4711 if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
4712 return (0);
4713 if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
4714 strcmp(name, "a.out") == 0)
4715 return (0);
4716 }
4717
4718 /*
4719 * At this point, check to see if this file has a parent directory
4720 * named RCS or SCCS. If so, then this file should be excluded too.
4721 * The strcpy() operation is done again, because basename(3C) may
4722 * modify the path string passed to it.
4723 */
4724 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4725 return (1);
4726
4727 dir = dirname(fullname);
4728 while (strcmp(dir, ".") != 0) {
4729 name = basename(dir);
4730 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4731 return (0);
4732 dir = dirname(dir);
4733 }
4734
4735 return (1);
4736 }
4737
4738 static int
4739 response(void)
4740 {
4741 int c;
4742
4743 c = getchar();
4744 if (c != '\n')
4745 while (getchar() != '\n')
4746 ;
4747 else c = 'n';
4748 return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
4749 }
4750
4751 /* Has file been modified since being put into archive? If so, return > 0. */
4752
4753 static off_t lookup(char *);
4754
4755 static int
4756 checkupdate(char *arg)
4757 {
4758 char name[PATH_MAX+1];
4759 time_t mtime;
4760 long nsecs;
4761 off_t seekp;
4762
4763 rewind(tfile);
4764 if ((seekp = lookup(arg)) < 0)
4765 return (1);
4766 (void) fseek(tfile, seekp, 0);
4767 (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
4768
4769 /*
4770 * Unless nanoseconds were stored in the file, only use seconds for
4771 * comparison of time. Nanoseconds are stored when -E is specified.
4772 */
4773 if (Eflag == 0)
4774 return (stbuf.st_mtime > mtime);
4775
4776 if ((stbuf.st_mtime < mtime) ||
4777 ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
4778 return (0);
4779 return (1);
4780 }
4781
4782
4783 /*
4784 * newvol get new floppy (or tape) volume
4785 *
4786 * newvol(); resets tapepos and first to TRUE, prompts for
4787 * for new volume, and waits.
4788 * if dumping, end-of-file is written onto the tape.
4789 */
4790
4791 static void
4792 newvol(void)
4793 {
4794 int c;
4795
4796 if (dumping) {
4797 #ifdef DEBUG
4798 DEBUG("newvol called with 'dumping' set\n", 0, 0);
4799 #endif
4800 putempty((blkcnt_t)2); /* 2 EOT marks */
4801 closevol();
4802 flushtape();
4803 sync();
4804 tapepos = 0;
4805 } else
4806 first = TRUE;
4807 if (close(mt) != 0)
4808 vperror(2, gettext("close error"));
4809 mt = 0;
4810 (void) fprintf(stderr, gettext(
4811 "tar: \007please insert new volume, then press RETURN."));
4812 (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */
4813 while ((c = getchar()) != '\n' && ! term)
4814 if (c == EOF)
4815 done(Errflg);
4816 if (term)
4817 done(Errflg);
4818
4819 errno = 0;
4820
4821 if (strcmp(usefile, "-") == 0) {
4822 mt = dup(1);
4823 } else {
4824 mt = open(usefile, dumping ? update : 0);
4825 }
4826
4827 if (mt < 0) {
4828 (void) fprintf(stderr, gettext(
4829 "tar: cannot reopen %s (%s)\n"),
4830 dumping ? gettext("output") : gettext("input"), usefile);
4831
4832 #ifdef DEBUG
4833 DEBUG("update=%d, usefile=%s ", update, usefile);
4834 DEBUG("mt=%d, [%s]\n", mt, strerror(errno));
4835 #endif
4836
4837 done(2);
4838 }
4839 }
4840
4841 /*
4842 * Write a trailer portion to close out the current output volume.
4843 */
4844
4845 static void
4846 closevol(void)
4847 {
4848 if (mulvol) {
4849 /*
4850 * blocklim does not count the 2 EOT marks;
4851 * tapepos does count the 2 EOT marks;
4852 * therefore we need the +2 below.
4853 */
4854 putempty(blocklim + (blkcnt_t)2 - tapepos);
4855 }
4856 }
4857
4858 static void
4859 done(int n)
4860 {
4861 /*
4862 * If we were terminated in some way, and we would otherwise have
4863 * exited with a value of 0, adjust to 1, so that external callers
4864 * can determine this by looking at the exit status.
4865 */
4866 if (term && n == 0)
4867 n = 1;
4868
4869 if (tfile != NULL)
4870 (void) unlink(tname);
4871 if (compress_opt != NULL)
4872 (void) free(compress_opt);
4873 if (mt > 0) {
4874 if ((close(mt) != 0) || (fclose(stdout) != 0)) {
4875 perror(gettext("tar: close error"));
4876 exit(2);
4877 }
4878 }
4879 exit(n);
4880 }
4881
4882 /*
4883 * Determine if s1 is a prefix portion of s2 (or the same as s2).
4884 */
4885
4886 static int
4887 is_prefix(char *s1, char *s2)
4888 {
4889 while (*s1)
4890 if (*s1++ != *s2++)
4891 return (0);
4892 if (*s2)
4893 return (*s2 == '/');
4894 return (1);
4895 }
4896
4897 /*
4898 * lookup and bsrch look through tfile entries to find a match for a name.
4899 * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
4900 * a pair of newline chars, so the buffer it uses must be long enough for
4901 * two lines: name and modification time as well as period, newline and space.
4902 *
4903 * A kludge was added to bsrch to take care of matching on the first entry
4904 * in the file--there is no leading newline. So, if we are reading from the
4905 * start of the file, read into byte two and set the first byte to a newline.
4906 * Otherwise, the first entry cannot be matched.
4907 *
4908 */
4909
4910 #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4911 static off_t
4912 lookup(char *s)
4913 {
4914 int i;
4915 off_t a;
4916
4917 for (i = 0; s[i]; i++)
4918 if (s[i] == ' ')
4919 break;
4920 a = bsrch(s, i, low, high);
4921 return (a);
4922 }
4923
4924 static off_t
4925 bsrch(char *s, int n, off_t l, off_t h)
4926 {
4927 int i, j;
4928 char b[N];
4929 off_t m, m1;
4930
4931
4932 loop:
4933 if (l >= h)
4934 return ((off_t)-1);
4935 m = l + (h-l)/2 - N/2;
4936 if (m < l)
4937 m = l;
4938 (void) fseek(tfile, m, 0);
4939 if (m == 0) {
4940 (void) fread(b+1, 1, N-1, tfile);
4941 b[0] = '\n';
4942 m--;
4943 } else
4944 (void) fread(b, 1, N, tfile);
4945 for (i = 0; i < N; i++) {
4946 if (b[i] == '\n')
4947 break;
4948 m++;
4949 }
4950 if (m >= h)
4951 return ((off_t)-1);
4952 m1 = m;
4953 j = i;
4954 for (i++; i < N; i++) {
4955 m1++;
4956 if (b[i] == '\n')
4957 break;
4958 }
4959 i = cmp(b+j, s, n);
4960 if (i < 0) {
4961 h = m;
4962 goto loop;
4963 }
4964 if (i > 0) {
4965 l = m1;
4966 goto loop;
4967 }
4968 if (m < 0)
4969 m = 0;
4970 return (m);
4971 }
4972
4973 static int
4974 cmp(char *b, char *s, int n)
4975 {
4976 int i;
4977
4978 assert(b[0] == '\n');
4979
4980 for (i = 0; i < n; i++) {
4981 if (b[i+1] > s[i])
4982 return (-1);
4983 if (b[i+1] < s[i])
4984 return (1);
4985 }
4986 return (b[i+1] == ' '? 0 : -1);
4987 }
4988
4989
4990 /*
4991 * seekdisk seek to next file on archive
4992 *
4993 * called by passtape() only
4994 *
4995 * WARNING: expects "nblock" to be set, that is, readtape() to have
4996 * already been called. Since passtape() is only called
4997 * after a file header block has been read (why else would
4998 * we skip to next file?), this is currently safe.
4999 *
5000 * changed to guarantee SYS_BLOCK boundary
5001 */
5002
5003 static void
5004 seekdisk(blkcnt_t blocks)
5005 {
5006 off_t seekval;
5007 #if SYS_BLOCK > TBLOCK
5008 /* handle non-multiple of SYS_BLOCK */
5009 blkcnt_t nxb; /* # extra blocks */
5010 #endif
5011
5012 tapepos += blocks;
5013 #ifdef DEBUG
5014 DEBUG("seekdisk(%" FMT_blkcnt_t ") called\n", blocks, 0);
5015 #endif
5016 if (recno + blocks <= nblock) {
5017 recno += blocks;
5018 return;
5019 }
5020 if (recno > nblock)
5021 recno = nblock;
5022 seekval = (off_t)blocks - (nblock - recno);
5023 recno = nblock; /* so readtape() reads next time through */
5024 #if SYS_BLOCK > TBLOCK
5025 nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
5026 #ifdef DEBUG
5027 DEBUG("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
5028 nxb, seekval);
5029 #endif
5030 if (nxb && nxb > seekval) /* don't seek--we'll read */
5031 goto noseek;
5032 seekval -= nxb; /* don't seek quite so far */
5033 #endif
5034 if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
5035 (void) fprintf(stderr, gettext(
5036 "tar: device seek error\n"));
5037 done(3);
5038 }
5039 #if SYS_BLOCK > TBLOCK
5040 /* read those extra blocks */
5041 noseek:
5042 if (nxb) {
5043 #ifdef DEBUG
5044 DEBUG("reading extra blocks\n", 0, 0);
5045 #endif
5046 if (read(mt, tbuf, TBLOCK*nblock) < 0) {
5047 (void) fprintf(stderr, gettext(
5048 "tar: read error while skipping file\n"));
5049 done(8);
5050 }
5051 recno = nxb; /* so we don't read in next readtape() */
5052 }
5053 #endif
5054 }
5055
5056 static void
5057 readtape(char *buffer)
5058 {
5059 int i, j;
5060
5061 ++tapepos;
5062 if (recno >= nblock || first) {
5063 if (first) {
5064 /*
5065 * set the number of blocks to read initially, based on
5066 * the defined defaults for the device, or on the
5067 * explicit block factor given.
5068 */
5069 if (bflag || defaults_used || NotTape)
5070 j = nblock;
5071 else
5072 j = NBLOCK;
5073 } else
5074 j = nblock;
5075
5076 if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
5077 (void) fprintf(stderr, gettext(
5078 "tar: tape read error\n"));
5079 done(3);
5080 /*
5081 * i == 0 and !rflag means that EOF is reached and we are
5082 * trying to update or replace an empty tar file, so exit
5083 * with an error.
5084 *
5085 * If i == 0 and !first and NotTape, it means the pointer
5086 * has gone past the EOF. It could happen if two processes
5087 * try to update the same tar file simultaneously. So exit
5088 * with an error.
5089 */
5090
5091 } else if (i == 0) {
5092 if (first && !rflag) {
5093 (void) fprintf(stderr, gettext(
5094 "tar: blocksize = %d\n"), i);
5095 done(Errflg);
5096 } else if (!first && (!rflag || NotTape)) {
5097 mterr("read", 0, 2);
5098 }
5099 } else if ((!first || Bflag) && i != TBLOCK*j) {
5100 /*
5101 * Short read - try to get the remaining bytes.
5102 */
5103
5104 int remaining = (TBLOCK * j) - i;
5105 char *b = (char *)tbuf + i;
5106 int r;
5107
5108 do {
5109 if ((r = read(mt, b, remaining)) < 0) {
5110 (void) fprintf(stderr,
5111 gettext("tar: tape read error\n"));
5112 done(3);
5113 }
5114 b += r;
5115 remaining -= r;
5116 i += r;
5117 } while (remaining > 0 && r != 0);
5118 }
5119 if (first) {
5120 if ((i % TBLOCK) != 0) {
5121 (void) fprintf(stderr, gettext(
5122 "tar: tape blocksize error\n"));
5123 done(3);
5124 }
5125 i /= TBLOCK;
5126 if (vflag && i != nblock && i != 1) {
5127 if (!NotTape)
5128 (void) fprintf(stderr, gettext(
5129 "tar: blocksize = %d\n"), i);
5130 }
5131
5132 /*
5133 * If we are reading a tape, then a short read is
5134 * understood to signify that the amount read is
5135 * the tape's actual blocking factor. We adapt
5136 * nblock accordingly. There is no reason to do
5137 * this when the device is not blocked.
5138 */
5139
5140 if (!NotTape)
5141 nblock = i;
5142 }
5143 recno = 0;
5144 }
5145
5146 first = FALSE;
5147 copy(buffer, &tbuf[recno++]);
5148 }
5149
5150
5151 /*
5152 * replacement for writetape.
5153 */
5154
5155 static int
5156 writetbuf(char *buffer, int n)
5157 {
5158 int i;
5159
5160 tapepos += n; /* output block count */
5161
5162 if (recno >= nblock) {
5163 i = write(mt, (char *)tbuf, TBLOCK*nblock);
5164 if (i != TBLOCK*nblock)
5165 mterr("write", i, 2);
5166 recno = 0;
5167 }
5168
5169 /*
5170 * Special case: We have an empty tape buffer, and the
5171 * users data size is >= the tape block size: Avoid
5172 * the bcopy and dma direct to tape. BIG WIN. Add the
5173 * residual to the tape buffer.
5174 */
5175 while (recno == 0 && n >= nblock) {
5176 i = (int)write(mt, buffer, TBLOCK*nblock);
5177 if (i != TBLOCK*nblock)
5178 mterr("write", i, 2);
5179 n -= nblock;
5180 buffer += (nblock * TBLOCK);
5181 }
5182
5183 while (n-- > 0) {
5184 (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
5185 buffer += TBLOCK;
5186 if (recno >= nblock) {
5187 i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
5188 if (i != TBLOCK*nblock)
5189 mterr("write", i, 2);
5190 recno = 0;
5191 }
5192 }
5193
5194 /* Tell the user how much to write to get in sync */
5195 return (nblock - recno);
5196 }
5197
5198 /*
5199 * backtape - reposition tape after reading soft "EOF" record
5200 *
5201 * Backtape tries to reposition the tape back over the EOF
5202 * record. This is for the 'u' and 'r' function letters so that the
5203 * tape can be extended. This code is not well designed, but
5204 * I'm confident that the only callers who care about the
5205 * backspace-over-EOF feature are those involved in 'u' and 'r'.
5206 *
5207 * The proper way to backup the tape is through the use of mtio.
5208 * Earlier spins used lseek combined with reads in a confusing
5209 * maneuver that only worked on 4.x, but shouldn't have, even
5210 * there. Lseeks are explicitly not supported for tape devices.
5211 */
5212
5213 static void
5214 backtape(void)
5215 {
5216 struct mtop mtcmd;
5217 #ifdef DEBUG
5218 DEBUG("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
5219 nblock);
5220 #endif
5221 /*
5222 * Backup to the position in the archive where the record
5223 * currently sitting in the tbuf buffer is situated.
5224 */
5225
5226 if (NotTape) {
5227 /*
5228 * For non-tape devices, this means lseeking to the
5229 * correct position. The absolute location tapepos-recno
5230 * should be the beginning of the current record.
5231 */
5232
5233 if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
5234 (off_t)-1) {
5235 (void) fprintf(stderr,
5236 gettext("tar: lseek to end of archive failed\n"));
5237 done(4);
5238 }
5239 } else {
5240 /*
5241 * For tape devices, we backup over the most recently
5242 * read record.
5243 */
5244
5245 mtcmd.mt_op = MTBSR;
5246 mtcmd.mt_count = 1;
5247
5248 if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
5249 (void) fprintf(stderr,
5250 gettext("tar: backspace over record failed\n"));
5251 done(4);
5252 }
5253 }
5254
5255 /*
5256 * Decrement the tape and tbuf buffer indices to prepare for the
5257 * coming write to overwrite the soft EOF record.
5258 */
5259
5260 recno--;
5261 tapepos--;
5262 }
5263
5264
5265 /*
5266 * flushtape write buffered block(s) onto tape
5267 *
5268 * recno points to next free block in tbuf. If nonzero, a write is done.
5269 * Care is taken to write in multiples of SYS_BLOCK when device is
5270 * non-magtape in case raw i/o is used.
5271 *
5272 * NOTE: this is called by writetape() to do the actual writing
5273 */
5274
5275 static void
5276 flushtape(void)
5277 {
5278 #ifdef DEBUG
5279 DEBUG("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno, 0);
5280 #endif
5281 if (recno > 0) { /* anything buffered? */
5282 if (NotTape) {
5283 #if SYS_BLOCK > TBLOCK
5284 int i;
5285
5286 /*
5287 * an odd-block write can only happen when
5288 * we are at the end of a volume that is not a tape.
5289 * Here we round recno up to an even SYS_BLOCK
5290 * boundary.
5291 */
5292 if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
5293 #ifdef DEBUG
5294 DEBUG("flushtape() %d rounding blocks\n", i, 0);
5295 #endif
5296 recno += i; /* round up to even SYS_BLOCK */
5297 }
5298 #endif
5299 if (recno > nblock)
5300 recno = nblock;
5301 }
5302 #ifdef DEBUG
5303 DEBUG("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
5304 " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
5305 (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
5306 #endif
5307 if (write(mt, tbuf,
5308 (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
5309 (void) fprintf(stderr, gettext(
5310 "tar: tape write error\n"));
5311 done(2);
5312 }
5313 recno = 0;
5314 }
5315 }
5316
5317 static void
5318 copy(void *dst, void *src)
5319 {
5320 (void) memcpy(dst, src, TBLOCK);
5321 }
5322
5323 /*
5324 * kcheck()
5325 * - checks the validity of size values for non-tape devices
5326 * - if size is zero, mulvol tar is disabled and size is
5327 * assumed to be infinite.
5328 * - returns volume size in TBLOCKS
5329 */
5330
5331 static blkcnt_t
5332 kcheck(char *kstr)
5333 {
5334 blkcnt_t kval;
5335
5336 kval = strtoll(kstr, NULL, 0);
5337 if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */
5338 mulvol = 0; /* definitely not mulvol, but we must */
5339 return (0); /* took out setting of NotTape */
5340 }
5341 if (kval < (blkcnt_t)MINSIZE) {
5342 (void) fprintf(stderr, gettext(
5343 "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5344 ").\n"), (ulong_t)MINSIZE, kval);
5345 (void) fprintf(stderr, gettext(
5346 "bad size entry for %s in %s.\n"),
5347 archive, DEF_FILE);
5348 done(1);
5349 }
5350 mulvol++;
5351 NotTape++; /* implies non-tape */
5352 return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */
5353 }
5354
5355
5356 /*
5357 * bcheck()
5358 * - checks the validity of blocking factors
5359 * - returns blocking factor
5360 */
5361
5362 static int
5363 bcheck(char *bstr)
5364 {
5365 blkcnt_t bval;
5366
5367 bval = strtoll(bstr, NULL, 0);
5368 if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
5369 (void) fprintf(stderr, gettext(
5370 "tar: invalid blocksize \"%s\".\n"), bstr);
5371 if (!bflag)
5372 (void) fprintf(stderr, gettext(
5373 "bad blocksize entry for '%s' in %s.\n"),
5374 archive, DEF_FILE);
5375 done(1);
5376 }
5377
5378 return ((int)bval);
5379 }
5380
5381
5382 /*
5383 * defset()
5384 * - reads DEF_FILE for the set of default values specified.
5385 * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5386 * - 'usefile' points to static data, so will be overwritten
5387 * if this routine is called a second time.
5388 * - the pattern specified by 'arch' must be followed by four
5389 * blank-separated fields (1) device (2) blocking,
5390 * (3) size(K), and (4) tape
5391 * for example: archive0=/dev/fd 1 400 n
5392 */
5393
5394 static int
5395 defset(char *arch)
5396 {
5397 char *bp;
5398
5399 if (defopen(DEF_FILE) != 0)
5400 return (FALSE);
5401 if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
5402 (void) fprintf(stderr, gettext(
5403 "tar: error setting parameters for %s.\n"), DEF_FILE);
5404 return (FALSE); /* & following ones too */
5405 }
5406 if ((bp = defread(arch)) == NULL) {
5407 (void) fprintf(stderr, gettext(
5408 "tar: missing or invalid '%s' entry in %s.\n"),
5409 arch, DEF_FILE);
5410 return (FALSE);
5411 }
5412 if ((usefile = strtok(bp, " \t")) == NULL) {
5413 (void) fprintf(stderr, gettext(
5414 "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
5415 return (FALSE);
5416 }
5417 if ((bp = strtok(NULL, " \t")) == NULL) {
5418 (void) fprintf(stderr, gettext(
5419 "tar: block component missing in '%s' entry in %s.\n"),
5420 arch, DEF_FILE);
5421 return (FALSE);
5422 }
5423 nblock = bcheck(bp);
5424 if ((bp = strtok(NULL, " \t")) == NULL) {
5425 (void) fprintf(stderr, gettext(
5426 "tar: size component missing in '%s' entry in %s.\n"),
5427 arch, DEF_FILE);
5428 return (FALSE);
5429 }
5430 blocklim = kcheck(bp);
5431 if ((bp = strtok(NULL, " \t")) != NULL)
5432 NotTape = (*bp == 'n' || *bp == 'N');
5433 else
5434 NotTape = (blocklim != 0);
5435 (void) defopen(NULL);
5436 #ifdef DEBUG
5437 DEBUG("defset: archive='%s'; usefile='%s'\n", arch, usefile);
5438 DEBUG("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
5439 nblock, blocklim);
5440 DEBUG("defset: not tape = %d\n", NotTape, 0);
5441 #endif
5442 return (TRUE);
5443 }
5444
5445
5446 /*
5447 * Following code handles excluded and included files.
5448 * A hash table of file names to be {in,ex}cluded is built.
5449 * For excluded files, before writing or extracting a file
5450 * check to see if it is in the exclude_tbl.
5451 * For included files, the wantit() procedure will check to
5452 * see if the named file is in the include_tbl.
5453 */
5454
5455 static void
5456 build_table(file_list_t *table[], char *file)
5457 {
5458 FILE *fp;
5459 char buf[PATH_MAX + 1];
5460
5461 if ((fp = fopen(file, "r")) == (FILE *)NULL)
5462 vperror(1, gettext("could not open %s"), file);
5463 while (fgets(buf, sizeof (buf), fp) != NULL) {
5464 if (buf[strlen(buf) - 1] == '\n')
5465 buf[strlen(buf) - 1] = '\0';
5466 /* Only add to table if line has something in it */
5467 if (strspn(buf, " \t") != strlen(buf))
5468 add_file_to_table(table, buf);
5469 }
5470 (void) fclose(fp);
5471 }
5472
5473
5474 /*
5475 * Add a file name to the the specified table, if the file name has any
5476 * trailing '/'s then delete them before inserting into the table
5477 */
5478
5479 static void
5480 add_file_to_table(file_list_t *table[], char *str)
5481 {
5482 char name[PATH_MAX + 1];
5483 unsigned int h;
5484 file_list_t *exp;
5485
5486 (void) strcpy(name, str);
5487 while (name[strlen(name) - 1] == '/') {
5488 name[strlen(name) - 1] = '\0';
5489 }
5490
5491 h = hash(name);
5492 if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
5493 sizeof (char))) == NULL) {
5494 (void) fprintf(stderr, gettext(
5495 "tar: out of memory, exclude/include table(entry)\n"));
5496 exit(1);
5497 }
5498
5499 if ((exp->name = strdup(name)) == NULL) {
5500 (void) fprintf(stderr, gettext(
5501 "tar: out of memory, exclude/include table(file name)\n"));
5502 exit(1);
5503 }
5504
5505 exp->next = table[h];
5506 table[h] = exp;
5507 }
5508
5509
5510 /*
5511 * See if a file name or any of the file's parent directories is in the
5512 * specified table, if the file name has any trailing '/'s then delete
5513 * them before searching the table
5514 */
5515
5516 static int
5517 is_in_table(file_list_t *table[], char *str)
5518 {
5519 char name[PATH_MAX + 1];
5520 unsigned int h;
5521 file_list_t *exp;
5522 char *ptr;
5523
5524 (void) strcpy(name, str);
5525 while (name[strlen(name) - 1] == '/') {
5526 name[strlen(name) - 1] = '\0';
5527 }
5528
5529 /*
5530 * check for the file name in the passed list
5531 */
5532 h = hash(name);
5533 exp = table[h];
5534 while (exp != NULL) {
5535 if (strcmp(name, exp->name) == 0) {
5536 return (1);
5537 }
5538 exp = exp->next;
5539 }
5540
5541 /*
5542 * check for any parent directories in the file list
5543 */
5544 while ((ptr = strrchr(name, '/'))) {
5545 *ptr = '\0';
5546 h = hash(name);
5547 exp = table[h];
5548 while (exp != NULL) {
5549 if (strcmp(name, exp->name) == 0) {
5550 return (1);
5551 }
5552 exp = exp->next;
5553 }
5554 }
5555
5556 return (0);
5557 }
5558
5559
5560 /*
5561 * Compute a hash from a string.
5562 */
5563
5564 static unsigned int
5565 hash(char *str)
5566 {
5567 char *cp;
5568 unsigned int h;
5569
5570 h = 0;
5571 for (cp = str; *cp; cp++) {
5572 h += *cp;
5573 }
5574 return (h % TABLE_SIZE);
5575 }
5576
5577 static void *
5578 getmem(size_t size)
5579 {
5580 void *p = calloc((unsigned)size, sizeof (char));
5581
5582 if (p == NULL && freemem) {
5583 (void) fprintf(stderr, gettext(
5584 "tar: out of memory, link and directory modtime "
5585 "info lost\n"));
5586 freemem = 0;
5587 if (errflag)
5588 done(1);
5589 else
5590 Errflg = 1;
5591 }
5592 return (p);
5593 }
5594
5595 /*
5596 * vperror() --variable argument perror.
5597 * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
5598 * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5599 * with the value of whatever "errno" is set to. If exit_status is not
5600 * zero, then tar exits with that error status. If errflag and exit_status
5601 * are both zero, the routine returns to where it was called and sets Errflg
5602 * to errno.
5603 */
5604
5605 static void
5606 vperror(int exit_status, char *fmt, ...)
5607 {
5608 va_list ap;
5609
5610 va_start(ap, fmt);
5611 (void) fputs("tar: ", stderr);
5612 (void) vfprintf(stderr, fmt, ap);
5613 (void) fprintf(stderr, ": %s\n", strerror(errno));
5614 va_end(ap);
5615 if (exit_status)
5616 done(exit_status);
5617 else
5618 if (errflag)
5619 done(errno);
5620 else
5621 Errflg = errno;
5622 }
5623
5624
5625 static void
5626 fatal(char *format, ...)
5627 {
5628 va_list ap;
5629
5630 va_start(ap, format);
5631 (void) fprintf(stderr, "tar: ");
5632 (void) vfprintf(stderr, format, ap);
5633 (void) fprintf(stderr, "\n");
5634 va_end(ap);
5635 done(1);
5636 }
5637
5638
5639 /*
5640 * Check to make sure that argument is a char * ptr.
5641 * Actually, we just check to see that it is non-null.
5642 * If it is null, print out the message and call usage(), bailing out.
5643 */
5644
5645 static void
5646 assert_string(char *s, char *msg)
5647 {
5648 if (s == NULL) {
5649 (void) fprintf(stderr, msg);
5650 usage();
5651 }
5652 }
5653
5654
5655 static void
5656 mterr(char *operation, int i, int exitcode)
5657 {
5658 (void) fprintf(stderr, gettext(
5659 "tar: %s error: "), operation);
5660 if (i < 0)
5661 perror("");
5662 else
5663 (void) fprintf(stderr, gettext("unexpected EOF\n"));
5664 done(exitcode);
5665 }
5666
5667 static int
5668 wantit(char *argv[], char **namep, char **dirp, char **component,
5669 attr_data_t **attrinfo)
5670 {
5671 char **cp;
5672 int gotit; /* true if we've found a match */
5673 int ret;
5674
5675 top:
5676 if (xhdr_flgs & _X_XHDR) {
5677 xhdr_flgs = 0;
5678 }
5679 getdir();
5680 if (Xhdrflag > 0) {
5681 ret = get_xdata();
5682 if (ret != 0) { /* Xhdr items and regular header */
5683 setbytes_to_skip(&stbuf, ret);
5684 passtape();
5685 return (0); /* Error--don't want to extract */
5686 }
5687 }
5688
5689 /*
5690 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5691 * of ancillary file is either over or ancillary file
5692 * processing is not required, load info from Xtarhdr and set
5693 * _X_XHDR bit in xhdr_flgs.
5694 */
5695 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
5696 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
5697 xhdr_flgs |= _X_XHDR;
5698 }
5699
5700 #if defined(O_XATTR)
5701 if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
5702 /*
5703 * Always needs to read the extended header. If atflag, saflag,
5704 * or tflag isn't set, then we'll have the correct info for
5705 * passtape() later.
5706 */
5707 (void) read_xattr_hdr(attrinfo);
5708 goto top;
5709 }
5710 /*
5711 * Now that we've read the extended header, call passtape()
5712 * if we don't want to restore attributes or system attributes.
5713 * Don't restore the attribute if we are extracting
5714 * a file from an archive (as opposed to doing a table of
5715 * contents) and any of the following are true:
5716 * 1. neither -@ or -/ was specified.
5717 * 2. -@ was specified, -/ wasn't specified, and we're
5718 * processing a hidden attribute directory of an attribute
5719 * or we're processing a read-write system attribute file.
5720 * 3. -@ wasn't specified, -/ was specified, and the file
5721 * we're processing is not a read-write system attribute file,
5722 * or we're processing the hidden attribute directory of an
5723 * attribute.
5724 *
5725 * We always process the attributes if we're just generating
5726 * generating a table of contents, or if both -@ and -/ were
5727 * specified.
5728 */
5729 if (xattrp != NULL) {
5730 attr_data_t *ainfo = *attrinfo;
5731
5732 if (!tflag &&
5733 ((!atflag && !saflag) ||
5734 (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
5735 ainfo->attr_rw_sysattr)) ||
5736 (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
5737 !ainfo->attr_rw_sysattr)))) {
5738 passtape();
5739 return (0);
5740 }
5741 }
5742 #endif
5743
5744 /* sets *namep to point at the proper name */
5745 if (check_prefix(namep, dirp, component) != 0) {
5746 passtape();
5747 return (0);
5748 }
5749
5750 if (endtape()) {
5751 if (Bflag) {
5752 /*
5753 * Logically at EOT - consume any extra blocks
5754 * so that write to our stdin won't fail and
5755 * emit an error message; otherwise something
5756 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5757 * will produce a bogus error message from "dd".
5758 */
5759
5760 while (read(mt, tbuf, TBLOCK*nblock) > 0) {
5761 /* empty body */
5762 }
5763 }
5764 return (-1);
5765 }
5766
5767 gotit = 0;
5768
5769 if ((Iflag && is_in_table(include_tbl, *namep)) ||
5770 (! Iflag && *argv == NULL)) {
5771 gotit = 1;
5772 } else {
5773 for (cp = argv; *cp; cp++) {
5774 if (is_prefix(*cp, *namep)) {
5775 gotit = 1;
5776 break;
5777 }
5778 }
5779 }
5780
5781 if (! gotit) {
5782 passtape();
5783 return (0);
5784 }
5785
5786 if (Xflag && is_in_table(exclude_tbl, *namep)) {
5787 if (vflag) {
5788 (void) fprintf(stderr, gettext("%s excluded\n"),
5789 *namep);
5790 }
5791 passtape();
5792 return (0);
5793 }
5794
5795 return (1);
5796 }
5797
5798
5799 static void
5800 setbytes_to_skip(struct stat *st, int err)
5801 {
5802 /*
5803 * In a scenario where a typeflag 'X' was followed by
5804 * a typeflag 'A' and typeflag 'O', then the number of
5805 * bytes to skip should be the size of ancillary file,
5806 * plus the dblock for regular file, and the size
5807 * from Xtarhdr. However, if the typeflag was just 'X'
5808 * followed by typeflag 'O', then the number of bytes
5809 * to skip should be the size from Xtarhdr.
5810 */
5811 if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
5812 (xhdr_flgs & _X_SIZE)) {
5813 st->st_size += TBLOCK + Xtarhdr.x_filesz;
5814 xhdr_flgs |= _X_XHDR;
5815 } else if ((dblock.dbuf.typeflag != 'A') &&
5816 (xhdr_flgs & _X_SIZE)) {
5817 st->st_size += Xtarhdr.x_filesz;
5818 xhdr_flgs |= _X_XHDR;
5819 }
5820 }
5821
5822 static int
5823 fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
5824 int rw_sysattr, attr_data_t **attrinfo)
5825 {
5826 size_t pathlen;
5827 char *tpath;
5828 char *tparent;
5829
5830 /* parent info */
5831 if (attrparent != NULL) {
5832 if ((tparent = strdup(attrparent)) == NULL) {
5833 vperror(0, gettext(
5834 "unable to allocate memory for attribute parent "
5835 "name for %sattribute %s/%s of %s"),
5836 rw_sysattr ? gettext("system ") : "",
5837 attrparent, attr, longname);
5838 return (1);
5839 }
5840 } else {
5841 tparent = NULL;
5842 }
5843
5844 /* path info */
5845 pathlen = strlen(attr) + 1;
5846 if (attrparent != NULL) {
5847 pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
5848 }
5849 if ((tpath = calloc(1, pathlen)) == NULL) {
5850 vperror(0, gettext(
5851 "unable to allocate memory for full "
5852 "attribute path name for %sattribute %s%s%s of %s"),
5853 rw_sysattr ? gettext("system ") : "",
5854 (attrparent == NULL) ? "" : attrparent,
5855 (attrparent == NULL) ? "" : "/",
5856 attr, longname);
5857 if (tparent != NULL) {
5858 free(tparent);
5859 }
5860 return (1);
5861 }
5862 (void) snprintf(tpath, pathlen, "%s%s%s",
5863 (attrparent == NULL) ? "" : attrparent,
5864 (attrparent == NULL) ? "" : "/",
5865 attr);
5866
5867 /* fill in the attribute info */
5868 if (*attrinfo == NULL) {
5869 if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
5870 vperror(0, gettext(
5871 "unable to allocate memory for attribute "
5872 "information for %sattribute %s%s%s of %s"),
5873 rw_sysattr ? gettext("system ") : "",
5874 (attrparent == NULL) ? "" : attrparent,
5875 (attrparent == NULL) ? "" : gettext("/"),
5876 attr, longname);
5877 if (tparent != NULL) {
5878 free(tparent);
5879 }
5880 free(tpath);
5881 return (1);
5882 }
5883 } else {
5884 if ((*attrinfo)->attr_parent != NULL) {
5885 free((*attrinfo)->attr_parent);
5886 }
5887 if ((*attrinfo)->attr_path != NULL) {
5888 free((*attrinfo)->attr_path);
5889 }
5890 /*
5891 * The parent file descriptor is passed in, so don't
5892 * close it here as it should be closed by the function
5893 * that opened it.
5894 */
5895 }
5896 (*attrinfo)->attr_parent = tparent;
5897 (*attrinfo)->attr_path = tpath;
5898 (*attrinfo)->attr_rw_sysattr = rw_sysattr;
5899 (*attrinfo)->attr_parentfd = atparentfd;
5900
5901 return (0);
5902 }
5903
5904 /*
5905 * Test to see if name is a directory.
5906 *
5907 * Return 1 if true, 0 otherwise.
5908 */
5909
5910 static int
5911 is_directory(char *name)
5912 {
5913 #if defined(O_XATTR)
5914 /*
5915 * If there is an xattr_buf structure associated with this file,
5916 * then the directory test is based on whether the name has a
5917 * trailing slash.
5918 */
5919 if (xattrp)
5920 return (name[strlen(name) - 1] == '/');
5921 #endif
5922 if (is_posix)
5923 return (dblock.dbuf.typeflag == '5');
5924 else
5925 return (name[strlen(name) - 1] == '/');
5926 }
5927
5928 /*
5929 * Version of chdir that handles directory pathnames of greater than PATH_MAX
5930 * length, by changing the working directory to manageable portions of the
5931 * complete directory pathname. If any of these attempts fail, then it exits
5932 * non-zero.
5933 *
5934 * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
5935 * pathname is greater than PATH_MAX, then this still won't work, and this
5936 * routine will return -1 with errno set to ENAMETOOLONG.
5937 *
5938 * NOTE: this routine is semantically different to the system chdir in
5939 * that it is remotely possible for the currently working directory to be
5940 * changed to a different directory, if a chdir call fails when processing
5941 * one of the segments of a path that is greater than PATH_MAX. This isn't
5942 * a problem as this is tar's own specific version of chdir.
5943 */
5944
5945 static int
5946 tar_chdir(const char *path) {
5947 const char *sep = "/";
5948 char *path_copy = NULL;
5949 char *ptr = NULL;
5950
5951 /* The trivial case. */
5952 if (chdir(path) == 0) {
5953 return (0);
5954 }
5955 if (errno == ENAMETOOLONG) {
5956 if (path[0] == '/' && chdir(sep) != 0)
5957 return (-1);
5958
5959 /* strtok(3C) modifies the string, so make a copy. */
5960 if ((path_copy = strdup(path)) == NULL) {
5961 return (-1);
5962 }
5963
5964 /* chdir(2) for every path element. */
5965 for (ptr = strtok(path_copy, sep);
5966 ptr != NULL;
5967 ptr = strtok(NULL, sep)) {
5968 if (chdir(ptr) != 0) {
5969 free(path_copy);
5970 return (-1);
5971 }
5972 }
5973 free(path_copy);
5974 return (0);
5975 }
5976
5977 /* If chdir fails for any reason except ENAMETOOLONG. */
5978 return (-1);
5979 }
5980
5981 /*
5982 * Test if name has a '..' sequence in it.
5983 *
5984 * Return 1 if found, 0 otherwise.
5985 */
5986
5987 static int
5988 has_dot_dot(char *name)
5989 {
5990 char *s;
5991 size_t name_len = strlen(name);
5992
5993 for (s = name; s < (name + name_len - 2); s++) {
5994 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
5995 return (1);
5996
5997 while (! (*s == '/')) {
5998 if (! *s++)
5999 return (0);
6000 }
6001 }
6002
6003 return (0);
6004 }
6005
6006 /*
6007 * Test if name is an absolute path name.
6008 *
6009 * Return 1 if true, 0 otherwise.
6010 */
6011
6012 static int
6013 is_absolute(char *name)
6014 {
6015 #if defined(O_XATTR)
6016 /*
6017 * If this is an extended attribute (whose name will begin with
6018 * "/dev/null/", always return 0 as they should be extracted with
6019 * the name intact, to allow other tar archiving programs that
6020 * don't understand extended attributes, to correctly throw them away.
6021 */
6022 if (xattrp)
6023 return (0);
6024 #endif
6025
6026 return (name[0] == '/');
6027 }
6028
6029 /*
6030 * Adjust the pathname to make it a relative one. Strip off any leading
6031 * '/' characters and if the pathname contains any '..' sequences, strip
6032 * upto and including the last occurance of '../' (or '..' if found at
6033 * the very end of the pathname).
6034 *
6035 * Return the relative pathname. stripped_prefix will also return the
6036 * portion of name that was stripped off and should be freed by the
6037 * calling routine when no longer needed.
6038 */
6039
6040 static char *
6041 make_relative_name(char *name, char **stripped_prefix)
6042 {
6043 char *s;
6044 size_t prefix_len = 0;
6045 size_t name_len = strlen(name);
6046
6047 for (s = name + prefix_len; s < (name + name_len - 2); ) {
6048 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
6049 prefix_len = s + 2 - name;
6050
6051 do {
6052 char c = *s++;
6053
6054 if (c == '/')
6055 break;
6056 } while (*s);
6057 }
6058
6059 for (s = name + prefix_len; *s == '/'; s++)
6060 continue;
6061 prefix_len = s - name;
6062
6063 /* Create the portion of the name that was stripped off. */
6064 s = malloc(prefix_len + 1);
6065 memcpy(s, name, prefix_len);
6066 s[prefix_len] = 0;
6067 *stripped_prefix = s;
6068 s = &name[prefix_len];
6069
6070 return (s);
6071 }
6072
6073 /*
6074 * Return through *namep a pointer to the proper fullname (i.e "<name> |
6075 * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6076 *
6077 * Returns 0 if successful, otherwise returns 1.
6078 */
6079
6080 static int
6081 check_prefix(char **namep, char **dirp, char **compp)
6082 {
6083 static char fullname[PATH_MAX + 1];
6084 static char dir[PATH_MAX + 1];
6085 static char component[PATH_MAX + 1];
6086 static char savename[PATH_MAX + 1];
6087 char *s;
6088
6089 (void) memset(dir, 0, sizeof (dir));
6090 (void) memset(component, 0, sizeof (component));
6091
6092 if (xhdr_flgs & _X_PATH) {
6093 (void) strcpy(fullname, Xtarhdr.x_path);
6094 } else {
6095 if (dblock.dbuf.prefix[0] != '\0')
6096 (void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
6097 dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
6098 else
6099 (void) sprintf(fullname, "%.*s", NAMSIZ,
6100 dblock.dbuf.name);
6101 }
6102
6103 /*
6104 * If we are printing a table of contents or extracting an archive,
6105 * make absolute pathnames relative and prohibit the unpacking of
6106 * files contain ".." in their name (unless the user has supplied
6107 * the -P option).
6108 */
6109 if ((tflag || xflag) && !Pflag) {
6110 if (is_absolute(fullname) || has_dot_dot(fullname)) {
6111 char *stripped_prefix;
6112 size_t prefix_len = 0;
6113
6114 (void) strcpy(savename, fullname);
6115 strcpy(fullname,
6116 make_relative_name(savename, &stripped_prefix));
6117 (void) fprintf(stderr,
6118 gettext("tar: Removing leading '%s' from '%s'\n"),
6119 stripped_prefix, savename);
6120 free(stripped_prefix);
6121 }
6122 }
6123
6124 /*
6125 * Set dir and component names
6126 */
6127
6128 get_parent(fullname, dir);
6129
6130 #if defined(O_XATTR)
6131 if (xattrp == NULL) {
6132 #endif
6133 /*
6134 * Save of real name since were going to chop off the
6135 * trailing slashes.
6136 */
6137 (void) strcpy(savename, fullname);
6138 /*
6139 * first strip of trailing slashes.
6140 */
6141 chop_endslashes(savename);
6142 s = get_component(savename);
6143 (void) strcpy(component, s);
6144
6145 #if defined(O_XATTR)
6146 } else {
6147 (void) strcpy(fullname, xattrp->h_names);
6148 (void) strcpy(dir, fullname);
6149 (void) strcpy(component, basename(xattrp->h_names +
6150 strlen(xattrp->h_names) + 1));
6151 }
6152 #endif
6153 *namep = fullname;
6154 *dirp = dir;
6155 *compp = component;
6156
6157 return (0);
6158 }
6159
6160 /*
6161 * Return true if the object indicated by the file descriptor and type
6162 * is a tape device, false otherwise
6163 */
6164
6165 static int
6166 istape(int fd, int type)
6167 {
6168 int result = 0;
6169
6170 if (S_ISCHR(type)) {
6171 struct mtget mtg;
6172
6173 if (ioctl(fd, MTIOCGET, &mtg) != -1) {
6174 result = 1;
6175 }
6176 }
6177
6178 return (result);
6179 }
6180
6181 #include <utmpx.h>
6182
6183 struct utmpx utmpx;
6184
6185 #define NMAX (sizeof (utmpx.ut_name))
6186
6187 typedef struct cachenode { /* this struct must be zeroed before using */
6188 struct cachenode *next; /* next in hash chain */
6189 int val; /* the uid or gid of this entry */
6190 int namehash; /* name's hash signature */
6191 char name[NMAX+1]; /* the string that val maps to */
6192 } cachenode_t;
6193
6194 #define HASHSIZE 256
6195
6196 static cachenode_t *names[HASHSIZE];
6197 static cachenode_t *groups[HASHSIZE];
6198 static cachenode_t *uids[HASHSIZE];
6199 static cachenode_t *gids[HASHSIZE];
6200
6201 static int
6202 hash_byname(char *name)
6203 {
6204 int i, c, h = 0;
6205
6206 for (i = 0; i < NMAX; i++) {
6207 c = name[i];
6208 if (c == '\0')
6209 break;
6210 h = (h << 4) + h + c;
6211 }
6212 return (h);
6213 }
6214
6215 static cachenode_t *
6216 hash_lookup_byval(cachenode_t *table[], int val)
6217 {
6218 int h = val;
6219 cachenode_t *c;
6220
6221 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6222 if (c->val == val)
6223 return (c);
6224 }
6225 return (NULL);
6226 }
6227
6228 static cachenode_t *
6229 hash_lookup_byname(cachenode_t *table[], char *name)
6230 {
6231 int h = hash_byname(name);
6232 cachenode_t *c;
6233
6234 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6235 if (c->namehash == h && strcmp(c->name, name) == 0)
6236 return (c);
6237 }
6238 return (NULL);
6239 }
6240
6241 static cachenode_t *
6242 hash_insert(cachenode_t *table[], char *name, int value)
6243 {
6244 cachenode_t *c;
6245 int signature;
6246
6247 c = calloc(1, sizeof (cachenode_t));
6248 if (c == NULL) {
6249 perror("malloc");
6250 exit(1);
6251 }
6252 if (name != NULL) {
6253 (void) strncpy(c->name, name, NMAX);
6254 c->namehash = hash_byname(name);
6255 }
6256 c->val = value;
6257 if (table == uids || table == gids)
6258 signature = c->val;
6259 else
6260 signature = c->namehash;
6261 c->next = table[signature & (HASHSIZE - 1)];
6262 table[signature & (HASHSIZE - 1)] = c;
6263 return (c);
6264 }
6265
6266 static char *
6267 getname(uid_t uid)
6268 {
6269 cachenode_t *c;
6270
6271 if ((c = hash_lookup_byval(uids, uid)) == NULL) {
6272 struct passwd *pwent = getpwuid(uid);
6273 c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
6274 }
6275 return (c->name);
6276 }
6277
6278 static char *
6279 getgroup(gid_t gid)
6280 {
6281 cachenode_t *c;
6282
6283 if ((c = hash_lookup_byval(gids, gid)) == NULL) {
6284 struct group *grent = getgrgid(gid);
6285 c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
6286 }
6287 return (c->name);
6288 }
6289
6290 static uid_t
6291 getuidbyname(char *name)
6292 {
6293 cachenode_t *c;
6294
6295 if ((c = hash_lookup_byname(names, name)) == NULL) {
6296 struct passwd *pwent = getpwnam(name);
6297 c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
6298 }
6299 return ((uid_t)c->val);
6300 }
6301
6302 static gid_t
6303 getgidbyname(char *group)
6304 {
6305 cachenode_t *c;
6306
6307 if ((c = hash_lookup_byname(groups, group)) == NULL) {
6308 struct group *grent = getgrnam(group);
6309 c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
6310 }
6311 return ((gid_t)c->val);
6312 }
6313
6314 /*
6315 * Build the header.
6316 * Determine whether or not an extended header is also needed. If needed,
6317 * create and write the extended header and its data.
6318 * Writing of the extended header assumes that "tomodes" has been called and
6319 * the relevant information has been placed in the header block.
6320 */
6321
6322 static int
6323 build_dblock(
6324 const char *name,
6325 const char *linkname,
6326 const char typeflag,
6327 const int filetype,
6328 const struct stat *sp,
6329 const dev_t device,
6330 const char *prefix)
6331 {
6332 int nblks;
6333 major_t dev;
6334 const char *filename;
6335 const char *lastslash;
6336
6337 if (filetype == XATTR_FILE)
6338 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
6339 else
6340 dblock.dbuf.typeflag = typeflag;
6341 (void) memset(dblock.dbuf.name, '\0', NAMSIZ);
6342 (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
6343 (void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
6344
6345 if (xhdr_flgs & _X_PATH)
6346 filename = Xtarhdr.x_path;
6347 else
6348 filename = name;
6349
6350 if ((dev = major(device)) > OCTAL7CHAR) {
6351 if (Eflag) {
6352 xhdr_flgs |= _X_DEVMAJOR;
6353 Xtarhdr.x_devmajor = dev;
6354 } else {
6355 (void) fprintf(stderr, gettext(
6356 "Device major too large for %s. Use -E flag."),
6357 filename);
6358 if (errflag)
6359 done(1);
6360 else
6361 Errflg = 1;
6362 }
6363 dev = 0;
6364 }
6365 (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
6366 if ((dev = minor(device)) > OCTAL7CHAR) {
6367 if (Eflag) {
6368 xhdr_flgs |= _X_DEVMINOR;
6369 Xtarhdr.x_devminor = dev;
6370 } else {
6371 (void) fprintf(stderr, gettext(
6372 "Device minor too large for %s. Use -E flag."),
6373 filename);
6374 if (errflag)
6375 done(1);
6376 else
6377 Errflg = 1;
6378 }
6379 dev = 0;
6380 }
6381 (void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
6382
6383 (void) strncpy(dblock.dbuf.name, name, NAMSIZ);
6384 (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
6385 (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
6386 (void) sprintf(dblock.dbuf.version, "00");
6387 (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
6388 (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
6389 (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
6390 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
6391
6392 if (Eflag) {
6393 (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
6394 (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
6395 lastslash = strrchr(name, '/');
6396 if (lastslash == NULL)
6397 lastslash = name;
6398 else
6399 lastslash++;
6400 (void) strcpy(xhdr_buf.dbuf.name, lastslash);
6401 (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
6402 (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
6403 (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
6404 xhdr_count++;
6405 xrec_offset = 0;
6406 gen_date("mtime", sp->st_mtim);
6407 xhdr_buf.dbuf.typeflag = 'X';
6408 if (gen_utf8_names(filename) != 0)
6409 return (1);
6410
6411 #ifdef XHDR_DEBUG
6412 Xtarhdr.x_uname = dblock.dbuf.uname;
6413 Xtarhdr.x_gname = dblock.dbuf.gname;
6414 xhdr_flgs |= (_X_UNAME | _X_GNAME);
6415 #endif
6416 if (xhdr_flgs) {
6417 if (xhdr_flgs & _X_DEVMAJOR)
6418 gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
6419 if (xhdr_flgs & _X_DEVMINOR)
6420 gen_num("SUN.devminor", Xtarhdr.x_devminor);
6421 if (xhdr_flgs & _X_GID)
6422 gen_num("gid", Xtarhdr.x_gid);
6423 if (xhdr_flgs & _X_UID)
6424 gen_num("uid", Xtarhdr.x_uid);
6425 if (xhdr_flgs & _X_SIZE)
6426 gen_num("size", Xtarhdr.x_filesz);
6427 if (xhdr_flgs & _X_PATH)
6428 gen_string("path", Xtarhdr.x_path);
6429 if (xhdr_flgs & _X_LINKPATH)
6430 gen_string("linkpath", Xtarhdr.x_linkpath);
6431 if (xhdr_flgs & _X_GNAME)
6432 gen_string("gname", Xtarhdr.x_gname);
6433 if (xhdr_flgs & _X_UNAME)
6434 gen_string("uname", Xtarhdr.x_uname);
6435 }
6436 (void) sprintf(xhdr_buf.dbuf.size,
6437 "%011" FMT_off_t_o, xrec_offset);
6438 (void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
6439 checksum(&xhdr_buf));
6440 (void) writetbuf((char *)&xhdr_buf, 1);
6441 nblks = TBLOCKS(xrec_offset);
6442 (void) writetbuf(xrec_ptr, nblks);
6443 }
6444 return (0);
6445 }
6446
6447
6448 /*
6449 * makeDir - ensure that a directory with the pathname denoted by name
6450 * exists, and return 1 on success, and 0 on failure (e.g.,
6451 * read-only file system, exists but not-a-directory).
6452 */
6453
6454 static int
6455 makeDir(char *name)
6456 {
6457 struct stat buf;
6458
6459 if (access(name, 0) < 0) { /* name doesn't exist */
6460 if (mkdir(name, 0777) < 0) {
6461 vperror(0, "%s", name);
6462 return (0);
6463 }
6464 } else { /* name exists */
6465 if (stat(name, &buf) < 0) {
6466 vperror(0, "%s", name);
6467 return (0);
6468 }
6469
6470 return ((buf.st_mode & S_IFMT) == S_IFDIR);
6471 }
6472
6473 return (1);
6474 }
6475
6476
6477 /*
6478 * Save this directory and its mtime on the stack, popping and setting
6479 * the mtimes of any stacked dirs which aren't parents of this one.
6480 * A null name causes the entire stack to be unwound and set.
6481 *
6482 * Since all the elements of the directory "stack" share a common
6483 * prefix, we can make do with one string. We keep only the current
6484 * directory path, with an associated array of mtime's. A negative
6485 * mtime means no mtime.
6486 *
6487 * This stack algorithm is not guaranteed to work for tapes created
6488 * with the 'r' function letter, but the vast majority of tapes with
6489 * directories are not. This avoids saving every directory record on
6490 * the tape and setting all the times at the end.
6491 *
6492 * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6493 * environment)
6494 */
6495
6496 static void
6497 doDirTimes(char *name, timestruc_t modTime)
6498 {
6499 static char dirstack[PATH_MAX+2];
6500 /* Add spaces for the last slash and last NULL */
6501 static timestruc_t modtimes[PATH_MAX+1]; /* hash table */
6502 char *p = dirstack;
6503 char *q = name;
6504 char *savp;
6505
6506 if (q) {
6507 /*
6508 * Find common prefix
6509 */
6510
6511 while (*p == *q && *p) {
6512 p++; q++;
6513 }
6514 }
6515
6516 savp = p;
6517 while (*p) {
6518 /*
6519 * Not a child: unwind the stack, setting the times.
6520 * The order we do this doesn't matter, so we go "forward."
6521 */
6522
6523 if (*p == '/')
6524 if (modtimes[p - dirstack].tv_sec >= 0) {
6525 *p = '\0'; /* zap the slash */
6526 setPathTimes(AT_FDCWD, dirstack,
6527 modtimes[p - dirstack]);
6528 *p = '/';
6529 }
6530 ++p;
6531 }
6532
6533 p = savp;
6534
6535 /*
6536 * Push this one on the "stack"
6537 */
6538
6539 if (q) {
6540
6541 /*
6542 * Since the name parameter points the dir pathname
6543 * which is limited only to contain PATH_MAX chars
6544 * at maximum, we can ignore the overflow case of p.
6545 */
6546
6547 while ((*p = *q++)) { /* append the rest of the new dir */
6548 modtimes[p - dirstack].tv_sec = -1;
6549 p++;
6550 }
6551
6552 /*
6553 * If the tar file had used 'P' or 'E' function modifier,
6554 * append the last slash.
6555 */
6556 if (*(p - 1) != '/') {
6557 *p++ = '/';
6558 *p = '\0';
6559 }
6560 /* overwrite the last one */
6561 modtimes[p - dirstack - 1] = modTime;
6562 }
6563 }
6564
6565
6566 /*
6567 * setPathTimes - set the modification time for given path. Return 1 if
6568 * successful and 0 if not successful.
6569 */
6570
6571 static void
6572 setPathTimes(int dirfd, char *path, timestruc_t modTime)
6573
6574 {
6575 struct timeval timebuf[2];
6576
6577 /*
6578 * futimesat takes an array of two timeval structs.
6579 * The first entry contains access time.
6580 * The second entry contains modification time.
6581 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6582 * microseconds.
6583 */
6584 timebuf[0].tv_sec = time((time_t *)0);
6585 timebuf[0].tv_usec = 0;
6586 timebuf[1].tv_sec = modTime.tv_sec;
6587
6588 /* Extended header: use microseconds */
6589 timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
6590
6591 if (futimesat(dirfd, path, timebuf) < 0)
6592 vperror(0, gettext("can't set time on %s"), path);
6593 }
6594
6595
6596 /*
6597 * If hflag is set then delete the symbolic link's target.
6598 * If !hflag then delete the target.
6599 */
6600
6601 static void
6602 delete_target(int fd, char *comp, char *namep)
6603 {
6604 struct stat xtractbuf;
6605 char buf[PATH_MAX + 1];
6606 int n;
6607
6608
6609 if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
6610 if (errno == ENOTDIR && !hflag) {
6611 (void) unlinkat(fd, comp, 0);
6612 } else if (errno == ENOTDIR && hflag) {
6613 if (!lstat(namep, &xtractbuf)) {
6614 if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
6615 (void) unlinkat(fd, comp, 0);
6616 } else if ((n = readlink(namep, buf,
6617 PATH_MAX)) != -1) {
6618 buf[n] = '\0';
6619 (void) unlinkat(fd, buf,
6620 AT_REMOVEDIR);
6621 if (errno == ENOTDIR)
6622 (void) unlinkat(fd, buf, 0);
6623 } else {
6624 (void) unlinkat(fd, comp, 0);
6625 }
6626 } else {
6627 (void) unlinkat(fd, comp, 0);
6628 }
6629 }
6630 }
6631 }
6632
6633
6634 /*
6635 * ACL changes:
6636 * putfile():
6637 * Get acl info after stat. Write out ancillary file
6638 * before the normal file, i.e. directory, regular, FIFO,
6639 * link, special. If acl count is less than 4, no need to
6640 * create ancillary file. (i.e. standard permission is in
6641 * use.
6642 * doxtract():
6643 * Process ancillary file. Read it in and set acl info.
6644 * watch out for 'o' function modifier.
6645 * 't' function letter to display table
6646 */
6647
6648 /*
6649 * New functions for ACLs and other security attributes
6650 */
6651
6652 /*
6653 * The function appends the new security attribute info to the end of
6654 * existing secinfo.
6655 */
6656 int
6657 append_secattr(
6658 char **secinfo, /* existing security info */
6659 int *secinfo_len, /* length of existing security info */
6660 int size, /* new attribute size: unit depends on type */
6661 char *attrtext, /* new attribute text */
6662 char attr_type) /* new attribute type */
6663 {
6664 char *new_secinfo;
6665 int newattrsize;
6666 int oldsize;
6667 struct sec_attr *attr;
6668
6669 /* no need to add */
6670 if (attr_type != DIR_TYPE) {
6671 if (attrtext == NULL)
6672 return (0);
6673 }
6674
6675 switch (attr_type) {
6676 case UFSD_ACL:
6677 case ACE_ACL:
6678 if (attrtext == NULL) {
6679 (void) fprintf(stderr, gettext("acltotext failed\n"));
6680 return (-1);
6681 }
6682 /* header: type + size = 8 */
6683 newattrsize = 8 + (int)strlen(attrtext) + 1;
6684 attr = (struct sec_attr *)malloc(newattrsize);
6685 if (attr == NULL) {
6686 (void) fprintf(stderr,
6687 gettext("can't allocate memory\n"));
6688 return (-1);
6689 }
6690 attr->attr_type = attr_type;
6691 (void) sprintf(attr->attr_len,
6692 "%06o", size); /* acl entry count */
6693 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6694 free(attrtext);
6695 break;
6696
6697 /* Trusted Extensions */
6698 case DIR_TYPE:
6699 case LBL_TYPE:
6700 newattrsize = sizeof (struct sec_attr) + strlen(attrtext);
6701 attr = (struct sec_attr *)malloc(newattrsize);
6702 if (attr == NULL) {
6703 (void) fprintf(stderr,
6704 gettext("can't allocate memory\n"));
6705 return (-1);
6706 }
6707 attr->attr_type = attr_type;
6708 (void) sprintf(attr->attr_len,
6709 "%06d", size); /* len of attr data */
6710 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6711 break;
6712
6713 default:
6714 (void) fprintf(stderr,
6715 gettext("unrecognized attribute type\n"));
6716 return (-1);
6717 }
6718
6719 /* old security info + new attr header(8) + new attr */
6720 oldsize = *secinfo_len;
6721 *secinfo_len += newattrsize;
6722 new_secinfo = (char *)malloc(*secinfo_len);
6723 if (new_secinfo == NULL) {
6724 (void) fprintf(stderr, gettext("can't allocate memory\n"));
6725 *secinfo_len -= newattrsize;
6726 free(attr);
6727 return (-1);
6728 }
6729
6730 (void) memcpy(new_secinfo, *secinfo, oldsize);
6731 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6732
6733 free(*secinfo);
6734 free(attr);
6735 *secinfo = new_secinfo;
6736 return (0);
6737 }
6738
6739 /*
6740 * write_ancillary(): write out an ancillary file.
6741 * The file has the same header as normal file except the type and size
6742 * fields. The type is 'A' and size is the sum of all attributes
6743 * in bytes.
6744 * The body contains a list of attribute type, size and info. Currently,
6745 * there is only ACL info. This file is put before the normal file.
6746 */
6747 void
6748 write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
6749 {
6750 long blocks;
6751 int savflag;
6752 int savsize;
6753
6754 /* Just tranditional permissions or no security attribute info */
6755 if (len == 0 || secinfo == NULL)
6756 return;
6757
6758 /* save flag and size */
6759 savflag = (dblockp->dbuf).typeflag;
6760 (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
6761
6762 /* special flag for ancillary file */
6763 if (hdrtype == _XATTR_HDRTYPE)
6764 dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
6765 else
6766 dblockp->dbuf.typeflag = 'A';
6767
6768 /* for pre-2.5 versions of tar, need to make sure */
6769 /* the ACL file is readable */
6770 (void) sprintf(dblock.dbuf.mode, "%07lo",
6771 (stbuf.st_mode & POSIXMODES) | 0000200);
6772 (void) sprintf(dblockp->dbuf.size, "%011o", len);
6773 (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
6774
6775 /* write out the header */
6776 (void) writetbuf((char *)dblockp, 1);
6777
6778 /* write out security info */
6779 blocks = TBLOCKS(len);
6780 (void) writetbuf((char *)secinfo, (int)blocks);
6781
6782 /* restore mode, flag and size */
6783 (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
6784 dblockp->dbuf.typeflag = savflag;
6785 (void) sprintf(dblockp->dbuf.size, "%011o", savsize);
6786 }
6787
6788 /*
6789 * Read the data record for extended headers and then the regular header.
6790 * The data are read into the buffer and then null-terminated. Entries
6791 * for typeflag 'X' extended headers are of the format:
6792 * "%d %s=%s\n"
6793 *
6794 * When an extended header record is found, the extended header must
6795 * be processed and its values used to override the values in the
6796 * normal header. The way this is done is to process the extended
6797 * header data record and set the data values, then call getdir
6798 * to process the regular header, then then to reconcile the two
6799 * sets of data.
6800 */
6801
6802 static int
6803 get_xdata(void)
6804 {
6805 struct keylist_pair {
6806 int keynum;
6807 char *keylist;
6808 } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor",
6809 _X_DEVMINOR, "SUN.devminor",
6810 _X_GID, "gid",
6811 _X_GNAME, "gname",
6812 _X_LINKPATH, "linkpath",
6813 _X_PATH, "path",
6814 _X_SIZE, "size",
6815 _X_UID, "uid",
6816 _X_UNAME, "uname",
6817 _X_MTIME, "mtime",
6818 _X_LAST, "NULL" };
6819 char *lineloc;
6820 int length, i;
6821 char *keyword, *value;
6822 blkcnt_t nblocks;
6823 int bufneeded;
6824 int errors;
6825
6826 (void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
6827 xhdr_count++;
6828 errors = 0;
6829
6830 nblocks = TBLOCKS(stbuf.st_size);
6831 bufneeded = nblocks * TBLOCK;
6832 if (bufneeded >= xrec_size) {
6833 free(xrec_ptr);
6834 xrec_size = bufneeded + 1;
6835 if ((xrec_ptr = malloc(xrec_size)) == NULL)
6836 fatal(gettext("cannot allocate buffer"));
6837 }
6838
6839 lineloc = xrec_ptr;
6840
6841 while (nblocks-- > 0) {
6842 readtape(lineloc);
6843 lineloc += TBLOCK;
6844 }
6845 lineloc = xrec_ptr;
6846 xrec_ptr[stbuf.st_size] = '\0';
6847 while (lineloc < xrec_ptr + stbuf.st_size) {
6848 if (dblock.dbuf.typeflag == 'L') {
6849 length = xrec_size;
6850 keyword = "path";
6851 value = lineloc;
6852 } else {
6853 length = atoi(lineloc);
6854 *(lineloc + length - 1) = '\0';
6855 keyword = strchr(lineloc, ' ') + 1;
6856 value = strchr(keyword, '=') + 1;
6857 *(value - 1) = '\0';
6858 }
6859 i = 0;
6860 lineloc += length;
6861 while (keylist_pair[i].keynum != (int)_X_LAST) {
6862 if (strcmp(keyword, keylist_pair[i].keylist) == 0)
6863 break;
6864 i++;
6865 }
6866 errno = 0;
6867 switch (keylist_pair[i].keynum) {
6868 case _X_DEVMAJOR:
6869 Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
6870 if (errno) {
6871 (void) fprintf(stderr, gettext(
6872 "tar: Extended header major value error "
6873 "for file # %llu.\n"), xhdr_count);
6874 errors++;
6875 } else
6876 xhdr_flgs |= _X_DEVMAJOR;
6877 break;
6878 case _X_DEVMINOR:
6879 Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
6880 if (errno) {
6881 (void) fprintf(stderr, gettext(
6882 "tar: Extended header minor value error "
6883 "for file # %llu.\n"), xhdr_count);
6884 errors++;
6885 } else
6886 xhdr_flgs |= _X_DEVMINOR;
6887 break;
6888 case _X_GID:
6889 xhdr_flgs |= _X_GID;
6890 Xtarhdr.x_gid = strtol(value, NULL, 0);
6891 if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
6892 (void) fprintf(stderr, gettext(
6893 "tar: Extended header gid value error "
6894 "for file # %llu.\n"), xhdr_count);
6895 Xtarhdr.x_gid = GID_NOBODY;
6896 }
6897 break;
6898 case _X_GNAME:
6899 if (utf8_local("gname", &Xtarhdr.x_gname,
6900 local_gname, value, _POSIX_NAME_MAX) == 0)
6901 xhdr_flgs |= _X_GNAME;
6902 break;
6903 case _X_LINKPATH:
6904 if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
6905 local_linkpath, value, PATH_MAX) == 0)
6906 xhdr_flgs |= _X_LINKPATH;
6907 else
6908 errors++;
6909 break;
6910 case _X_PATH:
6911 if (utf8_local("path", &Xtarhdr.x_path,
6912 local_path, value, PATH_MAX) == 0)
6913 xhdr_flgs |= _X_PATH;
6914 else
6915 errors++;
6916 break;
6917 case _X_SIZE:
6918 Xtarhdr.x_filesz = strtoull(value, NULL, 0);
6919 if (errno) {
6920 (void) fprintf(stderr, gettext(
6921 "tar: Extended header invalid filesize "
6922 "for file # %llu.\n"), xhdr_count);
6923 errors++;
6924 } else
6925 xhdr_flgs |= _X_SIZE;
6926 break;
6927 case _X_UID:
6928 xhdr_flgs |= _X_UID;
6929 Xtarhdr.x_uid = strtol(value, NULL, 0);
6930 if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
6931 (void) fprintf(stderr, gettext(
6932 "tar: Extended header uid value error "
6933 "for file # %llu.\n"), xhdr_count);
6934 Xtarhdr.x_uid = UID_NOBODY;
6935 }
6936 break;
6937 case _X_UNAME:
6938 if (utf8_local("uname", &Xtarhdr.x_uname,
6939 local_uname, value, _POSIX_NAME_MAX) == 0)
6940 xhdr_flgs |= _X_UNAME;
6941 break;
6942 case _X_MTIME:
6943 get_xtime(value, &(Xtarhdr.x_mtime));
6944 if (errno)
6945 (void) fprintf(stderr, gettext(
6946 "tar: Extended header modification time "
6947 "value error for file # %llu.\n"),
6948 xhdr_count);
6949 else
6950 xhdr_flgs |= _X_MTIME;
6951 break;
6952 default:
6953 (void) fprintf(stderr,
6954 gettext("tar: unrecognized extended"
6955 " header keyword '%s'. Ignored.\n"), keyword);
6956 break;
6957 }
6958 }
6959
6960 getdir(); /* get regular header */
6961 if (errors && errflag)
6962 done(1);
6963 else
6964 if (errors)
6965 Errflg = 1;
6966 return (errors);
6967 }
6968
6969 /*
6970 * load_info_from_xtarhdr - sets Gen and stbuf variables from
6971 * extended header
6972 * load_info_from_xtarhdr(flag, xhdrp);
6973 * u_longlong_t flag; xhdr_flgs
6974 * struct xtar_hdr *xhdrp; pointer to extended header
6975 * NOTE: called when typeflag is not 'A' and xhdr_flgs
6976 * is set.
6977 */
6978 static void
6979 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
6980 {
6981 if (flag & _X_DEVMAJOR) {
6982 Gen.g_devmajor = xhdrp->x_devmajor;
6983 }
6984 if (flag & _X_DEVMINOR) {
6985 Gen.g_devminor = xhdrp->x_devminor;
6986 }
6987 if (flag & _X_GID) {
6988 Gen.g_gid = xhdrp->x_gid;
6989 stbuf.st_gid = xhdrp->x_gid;
6990 }
6991 if (flag & _X_UID) {
6992 Gen.g_uid = xhdrp->x_uid;
6993 stbuf.st_uid = xhdrp->x_uid;
6994 }
6995 if (flag & _X_SIZE) {
6996 Gen.g_filesz = xhdrp->x_filesz;
6997 stbuf.st_size = xhdrp->x_filesz;
6998 }
6999 if (flag & _X_MTIME) {
7000 Gen.g_mtime = xhdrp->x_mtime.tv_sec;
7001 stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
7002 stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
7003 }
7004 }
7005
7006 /*
7007 * gen_num creates a string from a keyword and an usigned long long in the
7008 * format: %d %s=%s\n
7009 * This is part of the extended header data record.
7010 */
7011
7012 void
7013 gen_num(const char *keyword, const u_longlong_t number)
7014 {
7015 char save_val[ULONGLONG_MAX_DIGITS + 1];
7016 int len;
7017 char *curr_ptr;
7018
7019 (void) sprintf(save_val, "%llu", number);
7020 /*
7021 * len = length of entire line, including itself. len will be
7022 * two digits. So, add the string lengths plus the length of len,
7023 * plus a blank, an equal sign, and a newline.
7024 */
7025 len = strlen(save_val) + strlen(keyword) + 5;
7026 if (xrec_offset + len > xrec_size) {
7027 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7028 fatal(gettext(
7029 "cannot allocate extended header buffer"));
7030 xrec_ptr = curr_ptr;
7031 xrec_size *= 2;
7032 }
7033 (void) sprintf(&xrec_ptr[xrec_offset],
7034 "%d %s=%s\n", len, keyword, save_val);
7035 xrec_offset += len;
7036 }
7037
7038 /*
7039 * gen_date creates a string from a keyword and a timestruc_t in the
7040 * format: %d %s=%s\n
7041 * This is part of the extended header data record.
7042 * Currently, granularity is only microseconds, so the low-order three digits
7043 * will be truncated.
7044 */
7045
7046 void
7047 gen_date(const char *keyword, const timestruc_t time_value)
7048 {
7049 /* Allow for <seconds>.<nanoseconds>\n */
7050 char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
7051 int len;
7052 char *curr_ptr;
7053
7054 (void) sprintf(save_val, "%ld", time_value.tv_sec);
7055 len = strlen(save_val);
7056 save_val[len] = '.';
7057 (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
7058
7059 /*
7060 * len = length of entire line, including itself. len will be
7061 * two digits. So, add the string lengths plus the length of len,
7062 * plus a blank, an equal sign, and a newline.
7063 */
7064 len = strlen(save_val) + strlen(keyword) + 5;
7065 if (xrec_offset + len > xrec_size) {
7066 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7067 fatal(gettext(
7068 "cannot allocate extended header buffer"));
7069 xrec_ptr = curr_ptr;
7070 xrec_size *= 2;
7071 }
7072 (void) sprintf(&xrec_ptr[xrec_offset],
7073 "%d %s=%s\n", len, keyword, save_val);
7074 xrec_offset += len;
7075 }
7076
7077 /*
7078 * gen_string creates a string from a keyword and a char * in the
7079 * format: %d %s=%s\n
7080 * This is part of the extended header data record.
7081 */
7082
7083 void
7084 gen_string(const char *keyword, const char *value)
7085 {
7086 int len;
7087 char *curr_ptr;
7088
7089 /*
7090 * len = length of entire line, including itself. The character length
7091 * of len must be 1-4 characters, because the maximum size of the path
7092 * or the name is PATH_MAX, which is 1024. So, assume 1 character
7093 * for len, one for the space, one for the "=", and one for the newline.
7094 * Then adjust as needed.
7095 */
7096 /* LINTED constant expression */
7097 assert(PATH_MAX <= 9996);
7098 len = strlen(value) + strlen(keyword) + 4;
7099 if (len > 997)
7100 len += 3;
7101 else if (len > 98)
7102 len += 2;
7103 else if (len > 9)
7104 len += 1;
7105 if (xrec_offset + len > xrec_size) {
7106 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7107 fatal(gettext(
7108 "cannot allocate extended header buffer"));
7109 xrec_ptr = curr_ptr;
7110 xrec_size *= 2;
7111 }
7112 #ifdef XHDR_DEBUG
7113 if (strcmp(keyword+1, "name") != 0)
7114 #endif
7115 (void) sprintf(&xrec_ptr[xrec_offset],
7116 "%d %s=%s\n", len, keyword, value);
7117 #ifdef XHDR_DEBUG
7118 else {
7119 len += 11;
7120 (void) sprintf(&xrec_ptr[xrec_offset],
7121 "%d %s=%snametoolong\n", len, keyword, value);
7122 }
7123 #endif
7124 xrec_offset += len;
7125 }
7126
7127 /*
7128 * Convert time found in the extended header data to seconds and nanoseconds.
7129 */
7130
7131 void
7132 get_xtime(char *value, timestruc_t *xtime)
7133 {
7134 char nanosec[10];
7135 char *period;
7136 int i;
7137
7138 (void) memset(nanosec, '0', 9);
7139 nanosec[9] = '\0';
7140
7141 period = strchr(value, '.');
7142 if (period != NULL)
7143 period[0] = '\0';
7144 xtime->tv_sec = strtol(value, NULL, 10);
7145 if (period == NULL)
7146 xtime->tv_nsec = 0;
7147 else {
7148 i = strlen(period +1);
7149 (void) strncpy(nanosec, period + 1, min(i, 9));
7150 xtime->tv_nsec = strtol(nanosec, NULL, 10);
7151 }
7152 }
7153
7154 /*
7155 * Check linkpath for length.
7156 * Emit an error message and return 1 if too long.
7157 */
7158
7159 int
7160 chk_path_build(
7161 char *name,
7162 char *longname,
7163 char *linkname,
7164 char *prefix,
7165 char type,
7166 int filetype)
7167 {
7168
7169 if (strlen(linkname) > (size_t)NAMSIZ) {
7170 if (Eflag > 0) {
7171 xhdr_flgs |= _X_LINKPATH;
7172 Xtarhdr.x_linkpath = linkname;
7173 } else {
7174 (void) fprintf(stderr, gettext(
7175 "tar: %s: linked to %s\n"), longname, linkname);
7176 (void) fprintf(stderr, gettext(
7177 "tar: %s: linked name too long\n"), linkname);
7178 if (errflag)
7179 done(1);
7180 else
7181 Errflg = 1;
7182 return (1);
7183 }
7184 }
7185 if (xhdr_flgs & _X_LINKPATH)
7186 return (build_dblock(name, tchar, type,
7187 filetype, &stbuf, stbuf.st_dev,
7188 prefix));
7189 else
7190 return (build_dblock(name, linkname, type,
7191 filetype, &stbuf, stbuf.st_dev, prefix));
7192 }
7193
7194 /*
7195 * Convert from UTF-8 to local character set.
7196 */
7197
7198 static int
7199 utf8_local(
7200 char *option,
7201 char **Xhdr_ptrptr,
7202 char *target,
7203 const char *source,
7204 int max_val)
7205 {
7206 static iconv_t iconv_cd;
7207 char *nl_target;
7208 const char *iconv_src;
7209 char *iconv_trg;
7210 size_t inlen;
7211 size_t outlen;
7212
7213 if (charset_type == -1) { /* iconv_open failed in earlier try */
7214 (void) fprintf(stderr, gettext(
7215 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7216 xhdr_count, source);
7217 return (1);
7218 } else if (charset_type == 0) { /* iconv_open has not yet been done */
7219 nl_target = nl_langinfo(CODESET);
7220 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7221 nl_target = "646";
7222 if (strcmp(nl_target, "646") == 0)
7223 charset_type = 1;
7224 else if (strcmp(nl_target, "UTF-8") == 0)
7225 charset_type = 3;
7226 else {
7227 if (strncmp(nl_target, "ISO", 3) == 0)
7228 nl_target += 3;
7229 charset_type = 2;
7230 errno = 0;
7231 if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
7232 (iconv_t)-1) {
7233 if (errno == EINVAL)
7234 (void) fprintf(stderr, gettext(
7235 "tar: conversion routines not "
7236 "available for current locale. "));
7237 (void) fprintf(stderr, gettext(
7238 "file # %llu: (%s) UTF-8 conversion"
7239 " failed.\n"), xhdr_count, source);
7240 charset_type = -1;
7241 return (1);
7242 }
7243 }
7244 }
7245
7246 /* locale using 7-bit codeset or UTF-8 locale */
7247 if (charset_type == 1 || charset_type == 3) {
7248 if (strlen(source) > max_val) {
7249 (void) fprintf(stderr, gettext(
7250 "tar: file # %llu: Extended header %s too long.\n"),
7251 xhdr_count, option);
7252 return (1);
7253 }
7254 if (charset_type == 3)
7255 (void) strcpy(target, source);
7256 else if (c_utf8(target, source) != 0) {
7257 (void) fprintf(stderr, gettext(
7258 "tar: file # %llu: (%s) UTF-8 conversion"
7259 " failed.\n"), xhdr_count, source);
7260 return (1);
7261 }
7262 *Xhdr_ptrptr = target;
7263 return (0);
7264 }
7265
7266 iconv_src = source;
7267 iconv_trg = target;
7268 inlen = strlen(source);
7269 outlen = max_val * UTF_8_FACTOR;
7270 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7271 (size_t)-1) { /* Error occurred: didn't convert */
7272 (void) fprintf(stderr, gettext(
7273 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7274 xhdr_count, source);
7275 /* Get remaining output; reinitialize conversion descriptor */
7276 iconv_src = (const char *)NULL;
7277 inlen = 0;
7278 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7279 return (1);
7280 }
7281 /* Get remaining output; reinitialize conversion descriptor */
7282 iconv_src = (const char *)NULL;
7283 inlen = 0;
7284 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7285 (size_t)-1) { /* Error occurred: didn't convert */
7286 (void) fprintf(stderr, gettext(
7287 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7288 xhdr_count, source);
7289 return (1);
7290 }
7291
7292 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7293 if (strlen(target) > max_val) {
7294 (void) fprintf(stderr, gettext(
7295 "tar: file # %llu: Extended header %s too long.\n"),
7296 xhdr_count, option);
7297 return (1);
7298 }
7299 *Xhdr_ptrptr = target;
7300 return (0);
7301 }
7302
7303 /*
7304 * Check gname, uname, path, and linkpath to see if they need to go in an
7305 * extended header. If they are already slated to be in an extended header,
7306 * or if they are not ascii, then they need to be in the extended header.
7307 * Then, convert all extended names to UTF-8.
7308 */
7309
7310 int
7311 gen_utf8_names(const char *filename)
7312 {
7313 static iconv_t iconv_cd;
7314 char *nl_target;
7315 char tempbuf[MAXNAM + 1];
7316 int nbytes;
7317 int errors;
7318
7319 if (charset_type == -1) { /* Previous failure to open. */
7320 (void) fprintf(stderr, gettext(
7321 "tar: file # %llu: UTF-8 conversion failed.\n"),
7322 xhdr_count);
7323 return (1);
7324 }
7325
7326 if (charset_type == 0) { /* Need to get conversion descriptor */
7327 nl_target = nl_langinfo(CODESET);
7328 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7329 nl_target = "646";
7330 if (strcmp(nl_target, "646") == 0)
7331 charset_type = 1;
7332 else if (strcmp(nl_target, "UTF-8") == 0)
7333 charset_type = 3;
7334 else {
7335 if (strncmp(nl_target, "ISO", 3) == 0)
7336 nl_target += 3;
7337 charset_type = 2;
7338 errno = 0;
7339 #ifdef ICONV_DEBUG
7340 (void) fprintf(stderr,
7341 gettext("Opening iconv_cd with target %s\n"),
7342 nl_target);
7343 #endif
7344 if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
7345 (iconv_t)-1) {
7346 if (errno == EINVAL)
7347 (void) fprintf(stderr, gettext(
7348 "tar: conversion routines not "
7349 "available for current locale. "));
7350 (void) fprintf(stderr, gettext(
7351 "file (%s): UTF-8 conversion failed.\n"),
7352 filename);
7353 charset_type = -1;
7354 return (1);
7355 }
7356 }
7357 }
7358
7359 errors = 0;
7360
7361 errors += local_utf8(&Xtarhdr.x_gname, local_gname,
7362 dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
7363 errors += local_utf8(&Xtarhdr.x_uname, local_uname,
7364 dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX);
7365 if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */
7366 (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
7367 tempbuf[NAMSIZ] = '\0';
7368 }
7369 errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
7370 tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
7371 if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */
7372 (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
7373 tempbuf[PRESIZ] = '\0';
7374 nbytes = strlen(tempbuf);
7375 if (nbytes > 0) {
7376 tempbuf[nbytes++] = '/';
7377 tempbuf[nbytes] = '\0';
7378 }
7379 (void) strncat(tempbuf + nbytes, dblock.dbuf.name,
7380 (MAXNAM - nbytes));
7381 tempbuf[MAXNAM] = '\0';
7382 }
7383 errors += local_utf8(&Xtarhdr.x_path, local_path,
7384 tempbuf, iconv_cd, _X_PATH, PATH_MAX);
7385
7386 if (errors > 0)
7387 (void) fprintf(stderr, gettext(
7388 "tar: file (%s): UTF-8 conversion failed.\n"), filename);
7389
7390 if (errors && errflag)
7391 done(1);
7392 else
7393 if (errors)
7394 Errflg = 1;
7395 return (errors);
7396 }
7397
7398 static int
7399 local_utf8(
7400 char **Xhdr_ptrptr,
7401 char *target,
7402 const char *source,
7403 iconv_t iconv_cd,
7404 int xhdrflg,
7405 int max_val)
7406 {
7407 const char *iconv_src;
7408 const char *starting_src;
7409 char *iconv_trg;
7410 size_t inlen;
7411 size_t outlen;
7412 #ifdef ICONV_DEBUG
7413 unsigned char c_to_hex;
7414 #endif
7415
7416 /*
7417 * If the item is already slated for extended format, get the string
7418 * to convert from the extended header record. Otherwise, get it from
7419 * the regular (dblock) area.
7420 */
7421 if (xhdr_flgs & xhdrflg) {
7422 if (charset_type == 3) { /* Already UTF-8, just copy */
7423 (void) strcpy(target, *Xhdr_ptrptr);
7424 *Xhdr_ptrptr = target;
7425 return (0);
7426 } else
7427 iconv_src = (const char *) *Xhdr_ptrptr;
7428 } else {
7429 if (charset_type == 3) /* Already in UTF-8 format */
7430 return (0); /* Don't create xhdr record */
7431 iconv_src = source;
7432 }
7433 starting_src = iconv_src;
7434 iconv_trg = target;
7435 if ((inlen = strlen(iconv_src)) == 0)
7436 return (0);
7437
7438 if (charset_type == 1) { /* locale using 7-bit codeset */
7439 if (c_utf8(target, starting_src) != 0) {
7440 (void) fprintf(stderr,
7441 gettext("tar: invalid character in"
7442 " UTF-8 conversion of '%s'\n"), starting_src);
7443 return (1);
7444 }
7445 return (0);
7446 }
7447
7448 outlen = max_val * UTF_8_FACTOR;
7449 errno = 0;
7450 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7451 (size_t)-1) {
7452 /* An error occurred, or not all characters were converted */
7453 if (errno == EILSEQ)
7454 (void) fprintf(stderr,
7455 gettext("tar: invalid character in"
7456 " UTF-8 conversion of '%s'\n"), starting_src);
7457 else
7458 (void) fprintf(stderr, gettext(
7459 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7460 starting_src);
7461 /* Get remaining output; reinitialize conversion descriptor */
7462 iconv_src = (const char *)NULL;
7463 inlen = 0;
7464 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7465 return (1);
7466 }
7467 /* Get remaining output; reinitialize conversion descriptor */
7468 iconv_src = (const char *)NULL;
7469 inlen = 0;
7470 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7471 (size_t)-1) { /* Error occurred: didn't convert */
7472 if (errno == EILSEQ)
7473 (void) fprintf(stderr,
7474 gettext("tar: invalid character in"
7475 " UTF-8 conversion of '%s'\n"), starting_src);
7476 else
7477 (void) fprintf(stderr, gettext(
7478 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7479 starting_src);
7480 return (1);
7481 }
7482
7483 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7484 if (strcmp(starting_src, target) != 0) {
7485 *Xhdr_ptrptr = target;
7486 xhdr_flgs |= xhdrflg;
7487 #ifdef ICONV_DEBUG
7488 (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n",
7489 strlen(starting_src), inlen, max_val, outlen);
7490 (void) fprintf(stderr, "Input string:\n ");
7491 for (inlen = 0; inlen < strlen(starting_src); inlen++) {
7492 c_to_hex = (unsigned char)starting_src[inlen];
7493 (void) fprintf(stderr, " %2.2x", c_to_hex);
7494 if (inlen % 20 == 19)
7495 (void) fprintf(stderr, "\n ");
7496 }
7497 (void) fprintf(stderr, "\nOutput string:\n ");
7498 for (inlen = 0; inlen < strlen(target); inlen++) {
7499 c_to_hex = (unsigned char)target[inlen];
7500 (void) fprintf(stderr, " %2.2x", c_to_hex);
7501 if (inlen % 20 == 19)
7502 (void) fprintf(stderr, "\n ");
7503 }
7504 (void) fprintf(stderr, "\n");
7505 #endif
7506 }
7507
7508 return (0);
7509 }
7510
7511 /*
7512 * Function to test each byte of the source string to make sure it is
7513 * in within bounds (value between 0 and 127).
7514 * If valid, copy source to target.
7515 */
7516
7517 int
7518 c_utf8(char *target, const char *source)
7519 {
7520 size_t len;
7521 const char *thischar;
7522
7523 len = strlen(source);
7524 thischar = source;
7525 while (len-- > 0) {
7526 if (!isascii((int)(*thischar++)))
7527 return (1);
7528 }
7529
7530 (void) strcpy(target, source);
7531 return (0);
7532 }
7533
7534
7535 #if defined(O_XATTR)
7536 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
7537
7538 static void
7539 prepare_xattr(
7540 char **attrbuf,
7541 char *filename,
7542 char *attrpath,
7543 char typeflag,
7544 struct linkbuf *linkinfo,
7545 int *rlen)
7546 {
7547 char *bufhead; /* ptr to full buffer */
7548 char *aptr;
7549 struct xattr_hdr *hptr; /* ptr to header in bufhead */
7550 struct xattr_buf *tptr; /* ptr to pathing pieces */
7551 int totalen; /* total buffer length */
7552 int len; /* length returned to user */
7553 int stringlen; /* length of filename + attr */
7554 /*
7555 * length of filename + attr
7556 * in link section
7557 */
7558 int linkstringlen;
7559 int complen; /* length of pathing section */
7560 int linklen; /* length of link section */
7561 int attrnames_index; /* attrnames starting index */
7562
7563 /*
7564 * Release previous buffer
7565 */
7566
7567 if (*attrbuf != (char *)NULL) {
7568 free(*attrbuf);
7569 *attrbuf = NULL;
7570 }
7571
7572 /*
7573 * First add in fixed size stuff
7574 */
7575 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7576
7577 /*
7578 * Add space for two nulls
7579 */
7580 stringlen = strlen(attrpath) + strlen(filename) + 2;
7581 complen = stringlen + sizeof (struct xattr_buf);
7582
7583 len += stringlen;
7584
7585 /*
7586 * Now add on space for link info if any
7587 */
7588
7589 if (linkinfo != NULL) {
7590 /*
7591 * Again add space for two nulls
7592 */
7593 linkstringlen = strlen(linkinfo->pathname) +
7594 strlen(linkinfo->attrname) + 2;
7595 linklen = linkstringlen + sizeof (struct xattr_buf);
7596 len += linklen;
7597 } else {
7598 linklen = 0;
7599 }
7600
7601 /*
7602 * Now add padding to end to fill out TBLOCK
7603 *
7604 * Function returns size of real data and not size + padding.
7605 */
7606
7607 totalen = ROUNDTOTBLOCK(len);
7608
7609 if ((bufhead = calloc(1, totalen)) == NULL) {
7610 fatal(gettext("Out of memory."));
7611 }
7612
7613
7614 /*
7615 * Now we can fill in the necessary pieces
7616 */
7617
7618 /*
7619 * first fill in the fixed header
7620 */
7621 hptr = (struct xattr_hdr *)bufhead;
7622 (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7623 (void) sprintf(hptr->h_component_len, "%0*d",
7624 sizeof (hptr->h_component_len) - 1, complen);
7625 (void) sprintf(hptr->h_link_component_len, "%0*d",
7626 sizeof (hptr->h_link_component_len) - 1, linklen);
7627 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7628
7629 /*
7630 * Now fill in the filename + attrnames section
7631 * The filename and attrnames section can be composed of two or more
7632 * path segments separated by a null character. The first segment
7633 * is the path to the parent file that roots the entire sequence in
7634 * the normal name space. The remaining segments describes a path
7635 * rooted at the hidden extended attribute directory of the leaf file of
7636 * the previous segment, making it possible to name attributes on
7637 * attributes. Thus, if we are just archiving an extended attribute,
7638 * the second segment will contain the attribute name. If we are
7639 * archiving a system attribute of an extended attribute, then the
7640 * second segment will contain the attribute name, and a third segment
7641 * will contain the system attribute name. The attribute pathing
7642 * information is obtained from 'attrpath'.
7643 */
7644
7645 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7646 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7647 stringlen);
7648 (void) strcpy(tptr->h_names, filename);
7649 attrnames_index = strlen(filename) + 1;
7650 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
7651 tptr->h_typeflag = typeflag;
7652
7653 /*
7654 * Split the attrnames section into two segments if 'attrpath'
7655 * contains pathing information for a system attribute of an
7656 * extended attribute. We split them by replacing the '/' with
7657 * a '\0'.
7658 */
7659 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
7660 *aptr = '\0';
7661 }
7662
7663 /*
7664 * Now fill in the optional link section if we have one
7665 */
7666
7667 if (linkinfo != (struct linkbuf *)NULL) {
7668 tptr = (struct xattr_buf *)(bufhead +
7669 sizeof (struct xattr_hdr) + complen);
7670
7671 (void) sprintf(tptr->h_namesz, "%0*d",
7672 sizeof (tptr->h_namesz) - 1, linkstringlen);
7673 (void) strcpy(tptr->h_names, linkinfo->pathname);
7674 (void) strcpy(
7675 &tptr->h_names[strlen(linkinfo->pathname) + 1],
7676 linkinfo->attrname);
7677 tptr->h_typeflag = typeflag;
7678 }
7679 *attrbuf = (char *)bufhead;
7680 *rlen = len;
7681 }
7682
7683 #else
7684 static void
7685 prepare_xattr(
7686 char **attrbuf,
7687 char *filename,
7688 char *attrname,
7689 char typeflag,
7690 struct linkbuf *linkinfo,
7691 int *rlen)
7692 {
7693 *attrbuf = NULL;
7694 *rlen = 0;
7695 }
7696 #endif
7697
7698 int
7699 getstat(int dirfd, char *longname, char *shortname, char *attrparent)
7700 {
7701
7702 int i, j;
7703 int printerr;
7704 int slnkerr;
7705 struct stat symlnbuf;
7706
7707 if (!hflag)
7708 i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
7709 else
7710 i = fstatat(dirfd, shortname, &stbuf, 0);
7711
7712 if (i < 0) {
7713 /* Initialize flag to print error mesg. */
7714 printerr = 1;
7715 /*
7716 * If stat is done, then need to do lstat
7717 * to determine whether it's a sym link
7718 */
7719 if (hflag) {
7720 /* Save returned error */
7721 slnkerr = errno;
7722
7723 j = fstatat(dirfd, shortname,
7724 &symlnbuf, AT_SYMLINK_NOFOLLOW);
7725 /*
7726 * Suppress error message when file is a symbolic link
7727 * and function modifier 'l' is off. Exception: when
7728 * a symlink points to a symlink points to a
7729 * symlink ... and we get past MAXSYMLINKS. That
7730 * error will cause a file not to be archived, and
7731 * needs to be printed.
7732 */
7733 if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
7734 (S_ISLNK(symlnbuf.st_mode)))
7735 printerr = 0;
7736
7737 /*
7738 * Restore errno in case the lstat
7739 * on symbolic link change
7740 */
7741 errno = slnkerr;
7742 }
7743
7744 if (printerr) {
7745 (void) fprintf(stderr, gettext(
7746 "tar: %s%s%s%s: %s\n"),
7747 (attrparent == NULL) ? "" : gettext("attribute "),
7748 (attrparent == NULL) ? "" : attrparent,
7749 (attrparent == NULL) ? "" : gettext(" of "),
7750 longname, strerror(errno));
7751 Errflg = 1;
7752 }
7753 return (1);
7754 }
7755 return (0);
7756 }
7757
7758 /*
7759 * Recursively archive the extended attributes and/or extended system attributes
7760 * of the base file, longname. Note: extended system attribute files will be
7761 * archived only if the extended system attributes are not transient (i.e. the
7762 * extended system attributes are other than the default values).
7763 *
7764 * If -@ was specified and the underlying file system supports it, archive the
7765 * extended attributes, and if there is a system attribute associated with the
7766 * extended attribute, then recursively call xattrs_put() to archive the
7767 * hidden attribute directory and the extended system attribute. If -/ was
7768 * specified and the underlying file system supports it, archive the extended
7769 * system attributes. Read-only extended system attributes are never archived.
7770 *
7771 * Currently, there cannot be attributes on attributes; only system
7772 * attributes on attributes. In addition, there cannot be attributes on
7773 * system attributes. A file and it's attribute directory hierarchy looks as
7774 * follows:
7775 * longname ----> . ("." is the hidden attribute directory)
7776 * |
7777 * ----------------------------
7778 * | |
7779 * <sys_attr_name> <attr_name> ----> .
7780 * |
7781 * <sys_attr_name>
7782 *
7783 */
7784 #if defined(O_XATTR)
7785 static void
7786 xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
7787 {
7788 char *filename = (attrparent == NULL) ? shortname : attrparent;
7789 int arc_rwsysattr = 0;
7790 int dirfd;
7791 int fd = -1;
7792 int rw_sysattr = 0;
7793 int ext_attr = 0;
7794 int rc;
7795 DIR *dirp;
7796 struct dirent *dp;
7797 attr_data_t *attrinfo = NULL;
7798
7799 /*
7800 * If the underlying file system supports it, then archive the extended
7801 * attributes if -@ was specified, and the extended system attributes
7802 * if -/ was specified.
7803 */
7804 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
7805 &ext_attr) != ATTR_OK) {
7806 return;
7807 }
7808
7809 /*
7810 * Only want to archive a read-write extended system attribute file
7811 * if it contains extended system attribute settings that are not the
7812 * default values.
7813 */
7814 #if defined(_PC_SATTR_ENABLED)
7815 if (saflag) {
7816 int filefd;
7817 nvlist_t *slist = NULL;
7818
7819 /* Determine if there are non-transient system attributes */
7820 errno = 0;
7821 if ((filefd = open(filename, O_RDONLY)) == -1) {
7822 if (attrparent == NULL) {
7823 vperror(0, gettext(
7824 "unable to open file %s"), longname);
7825 }
7826 return;
7827 }
7828 if (((slist = sysattr_list(basename(myname), filefd,
7829 filename)) != NULL) || (errno != 0)) {
7830 arc_rwsysattr = 1;
7831 }
7832 if (slist != NULL) {
7833 (void) nvlist_free(slist);
7834 slist = NULL;
7835 }
7836 (void) close(filefd);
7837 }
7838
7839 /*
7840 * If we aren't archiving extended system attributes, and we are
7841 * processing an attribute, or if we are archiving extended system
7842 * attributes, and there are are no extended attributes, then there's
7843 * no need to open up the attribute directory of the file unless the
7844 * extended system attributes are not transient (i.e, the system
7845 * attributes are not the default values).
7846 */
7847 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
7848 (saflag && !ext_attr))) {
7849 return;
7850 }
7851 #endif /* _PC_SATTR_ENABLED */
7852
7853 /* open the parent attribute directory */
7854 fd = attropen(filename, ".", O_RDONLY);
7855 if (fd < 0) {
7856 vperror(0, gettext(
7857 "unable to open attribute directory for %s%s%sfile %s"),
7858 (attrparent == NULL) ? "" : gettext("attribute "),
7859 (attrparent == NULL) ? "" : attrparent,
7860 (attrparent == NULL) ? "" : gettext(" of "),
7861 longname);
7862 return;
7863 }
7864
7865 /*
7866 * We need to change into the parent's attribute directory to determine
7867 * if each of the attributes should be archived.
7868 */
7869 if (fchdir(fd) < 0) {
7870 vperror(0, gettext(
7871 "cannot change to attribute directory of %s%s%sfile %s"),
7872 (attrparent == NULL) ? "" : gettext("attribute "),
7873 (attrparent == NULL) ? "" : attrparent,
7874 (attrparent == NULL) ? "" : gettext(" of "),
7875 longname);
7876 (void) close(fd);
7877 return;
7878 }
7879
7880 if (((dirfd = dup(fd)) == -1) ||
7881 ((dirp = fdopendir(dirfd)) == NULL)) {
7882 (void) fprintf(stderr, gettext(
7883 "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7884 (attrparent == NULL) ? "" : gettext("attribute "),
7885 (attrparent == NULL) ? "" : attrparent,
7886 (attrparent == NULL) ? "" : gettext(" of "),
7887 longname);
7888 if (fd > 0) {
7889 (void) close(fd);
7890 }
7891 return;
7892 }
7893
7894 while (dp = readdir(dirp)) {
7895 if (strcmp(dp->d_name, "..") == 0) {
7896 continue;
7897 } else if (strcmp(dp->d_name, ".") == 0) {
7898 Hiddendir = 1;
7899 } else {
7900 Hiddendir = 0;
7901 }
7902
7903 /* Determine if this attribute should be archived */
7904 if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
7905 &rw_sysattr) != ATTR_OK) {
7906 continue;
7907 }
7908
7909 /* gather the attribute's information to pass to putfile() */
7910 if ((fill_in_attr_info(dp->d_name, longname, attrparent,
7911 fd, rw_sysattr, &attrinfo)) == 1) {
7912 continue;
7913 }
7914
7915 /* add the attribute to the archive */
7916 rc = putfile(longname, dp->d_name, parent, attrinfo,
7917 XATTR_FILE, LEV0, SYMLINK_LEV0);
7918
7919 if (exitflag) {
7920 break;
7921 }
7922
7923 #if defined(_PC_SATTR_ENABLED)
7924 /*
7925 * If both -/ and -@ were specified, then archive the
7926 * attribute's extended system attributes and hidden directory
7927 * by making a recursive call to xattrs_put().
7928 */
7929 if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
7930 (Hiddendir == 0)) {
7931
7932 xattrs_put(longname, shortname, parent, dp->d_name);
7933
7934 /*
7935 * Change back to the parent's attribute directory
7936 * to process any further attributes.
7937 */
7938 if (fchdir(fd) < 0) {
7939 vperror(0, gettext(
7940 "cannot change back to attribute directory "
7941 "of file %s"), longname);
7942 break;
7943 }
7944 }
7945 #endif /* _PC_SATTR_ENABLED */
7946 }
7947
7948 if (attrinfo != NULL) {
7949 if (attrinfo->attr_parent != NULL) {
7950 free(attrinfo->attr_parent);
7951 }
7952 free(attrinfo->attr_path);
7953 free(attrinfo);
7954 }
7955 (void) closedir(dirp);
7956 if (fd != -1) {
7957 (void) close(fd);
7958 }
7959
7960 /* Change back to the parent directory of the base file */
7961 if (attrparent == NULL) {
7962 (void) tar_chdir(parent);
7963 }
7964 Hiddendir = 0;
7965 }
7966 #else
7967 static void
7968 xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
7969 {
7970 }
7971 #endif /* O_XATTR */
7972
7973 static int
7974 put_link(char *name, char *longname, char *component, char *longattrname,
7975 char *prefix, int filetype, char type)
7976 {
7977
7978 if (stbuf.st_nlink > 1) {
7979 struct linkbuf *lp;
7980 int found = 0;
7981
7982 for (lp = ihead; lp != NULL; lp = lp->nextp)
7983 if (lp->inum == stbuf.st_ino &&
7984 lp->devnum == stbuf.st_dev) {
7985 found++;
7986 break;
7987 }
7988 if (found) {
7989 #if defined(O_XATTR)
7990 if (filetype == XATTR_FILE)
7991 if (put_xattr_hdr(longname, component,
7992 longattrname, prefix, type, filetype, lp)) {
7993 goto out;
7994 }
7995 #endif
7996 stbuf.st_size = (off_t)0;
7997 if (filetype != XATTR_FILE) {
7998 tomodes(&stbuf);
7999 if (chk_path_build(name, longname, lp->pathname,
8000 prefix, type, filetype) > 0) {
8001 goto out;
8002 }
8003 }
8004
8005 if (mulvol && tapepos + 1 >= blocklim)
8006 newvol();
8007 (void) writetbuf((char *)&dblock, 1);
8008 /*
8009 * write_ancillary() is not needed here.
8010 * The first link is handled in the following
8011 * else statement. No need to process ACLs
8012 * for other hard links since they are the
8013 * same file.
8014 */
8015
8016 if (vflag) {
8017 #ifdef DEBUG
8018 if (NotTape)
8019 DEBUG("seek = %" FMT_blkcnt_t
8020 "K\t", K(tapepos), 0);
8021 #endif
8022 if (filetype == XATTR_FILE) {
8023 (void) fprintf(vfile, gettext(
8024 "a %s attribute %s link to "
8025 "%s attribute %s\n"),
8026 name, component, name,
8027 lp->attrname);
8028 } else {
8029 (void) fprintf(vfile, gettext(
8030 "a %s link to %s\n"),
8031 longname, lp->pathname);
8032 }
8033 }
8034 lp->count--;
8035 return (0);
8036 } else {
8037 lp = (struct linkbuf *)getmem(sizeof (*lp));
8038 if (lp != (struct linkbuf *)NULL) {
8039 lp->nextp = ihead;
8040 ihead = lp;
8041 lp->inum = stbuf.st_ino;
8042 lp->devnum = stbuf.st_dev;
8043 lp->count = stbuf.st_nlink - 1;
8044 if (filetype == XATTR_FILE) {
8045 (void) strcpy(lp->pathname, longname);
8046 (void) strcpy(lp->attrname,
8047 component);
8048 } else {
8049 (void) strcpy(lp->pathname, longname);
8050 (void) strcpy(lp->attrname, "");
8051 }
8052 }
8053 }
8054 }
8055
8056 out:
8057 return (1);
8058 }
8059
8060 static int
8061 put_extra_attributes(char *longname, char *shortname, char *longattrname,
8062 char *prefix, int filetype, char typeflag)
8063 {
8064 static acl_t *aclp = NULL;
8065 int error;
8066
8067 if (aclp != NULL) {
8068 acl_free(aclp);
8069 aclp = NULL;
8070 }
8071 #if defined(O_XATTR)
8072 if ((atflag || saflag) && (filetype == XATTR_FILE)) {
8073 if (put_xattr_hdr(longname, shortname, longattrname, prefix,
8074 typeflag, filetype, NULL)) {
8075 return (1);
8076 }
8077 }
8078 #endif
8079
8080 /* ACL support */
8081 if (pflag) {
8082 char *secinfo = NULL;
8083 int len = 0;
8084
8085 /* ACL support */
8086 if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
8087 /*
8088 * Get ACL info: dont bother allocating space if
8089 * there is only a trivial ACL.
8090 */
8091 if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
8092 &aclp)) != 0) {
8093 (void) fprintf(stderr, gettext(
8094 "%s: failed to retrieve acl : %s\n"),
8095 longname, acl_strerror(error));
8096 return (1);
8097 }
8098 }
8099
8100 /* append security attributes if any */
8101 if (aclp != NULL) {
8102 (void) append_secattr(&secinfo, &len, acl_cnt(aclp),
8103 acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8104 ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
8105 UFSD_ACL : ACE_ACL);
8106 }
8107
8108 if (Tflag) {
8109 /* append Trusted Extensions extended attributes */
8110 append_ext_attr(shortname, &secinfo, &len);
8111 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8112
8113 } else if (aclp != NULL) {
8114 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8115 }
8116 }
8117 return (0);
8118 }
8119
8120 #if defined(O_XATTR)
8121 static int
8122 put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
8123 int typeflag, int filetype, struct linkbuf *lp)
8124 {
8125 char *lname = NULL;
8126 char *sname = NULL;
8127 int error = 0;
8128 static char *attrbuf = NULL;
8129 int attrlen;
8130
8131 lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
8132 strlen(shortname) + strlen(".hdr") + 1);
8133
8134 if (lname == NULL) {
8135 fatal(gettext("Out of Memory."));
8136 }
8137 sname = malloc(sizeof (char) * strlen(shortname) +
8138 strlen(".hdr") + 1);
8139 if (sname == NULL) {
8140 fatal(gettext("Out of Memory."));
8141 }
8142
8143 (void) sprintf(sname, "%s.hdr", shortname);
8144 (void) sprintf(lname, "/dev/null/%s", sname);
8145
8146 if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
8147 sizeof (dblock.dbuf.name)) {
8148 fatal(gettext(
8149 "Buffer overflow writing extended attribute file name"));
8150 }
8151
8152 /*
8153 * dump extended attr lookup info
8154 */
8155 prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
8156 write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
8157
8158 (void) sprintf(lname, "/dev/null/%s", shortname);
8159 (void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
8160
8161 /*
8162 * Set up filename for attribute
8163 */
8164
8165 error = build_dblock(lname, tchar, '0', filetype,
8166 &stbuf, stbuf.st_dev, prefix);
8167 free(lname);
8168 free(sname);
8169
8170 return (error);
8171 }
8172 #endif
8173
8174 #if defined(O_XATTR)
8175 static int
8176 read_xattr_hdr(attr_data_t **attrinfo)
8177 {
8178 char buf[TBLOCK];
8179 char *attrparent = NULL;
8180 blkcnt_t blocks;
8181 char *tp;
8182 off_t bytes;
8183 int comp_len, link_len;
8184 int namelen;
8185 int attrparentlen;
8186 int parentfilelen;
8187
8188 if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
8189 return (1);
8190
8191 bytes = stbuf.st_size;
8192 if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
8193 (void) fprintf(stderr, gettext(
8194 "Insufficient memory for extended attribute\n"));
8195 return (1);
8196 }
8197
8198 tp = (char *)xattrhead;
8199 blocks = TBLOCKS(bytes);
8200 while (blocks-- > 0) {
8201 readtape(buf);
8202 if (bytes <= TBLOCK) {
8203 (void) memcpy(tp, buf, (size_t)bytes);
8204 break;
8205 } else {
8206 (void) memcpy(tp, buf, TBLOCK);
8207 tp += TBLOCK;
8208 }
8209 bytes -= TBLOCK;
8210 }
8211
8212 /*
8213 * Validate that we can handle header format
8214 */
8215 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8216 (void) fprintf(stderr,
8217 gettext("Unknown extended attribute format encountered\n"));
8218 (void) fprintf(stderr,
8219 gettext("Disabling extended attribute parsing\n"));
8220 xattrbadhead = 1;
8221 return (0);
8222 }
8223 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8224 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8225 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8226 sizeof (struct xattr_hdr));
8227 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8228 if (link_len > 0)
8229 xattr_linkp = (struct xattr_buf *)
8230 ((int)xattrp + (int)comp_len);
8231 else
8232 xattr_linkp = NULL;
8233
8234 /*
8235 * Gather the attribute path from the filename and attrnames section.
8236 * The filename and attrnames section can be composed of two or more
8237 * path segments separated by a null character. The first segment
8238 * is the path to the parent file that roots the entire sequence in
8239 * the normal name space. The remaining segments describes a path
8240 * rooted at the hidden extended attribute directory of the leaf file of
8241 * the previous segment, making it possible to name attributes on
8242 * attributes.
8243 */
8244 parentfilelen = strlen(xattrp->h_names);
8245 xattrapath = xattrp->h_names + parentfilelen + 1;
8246 if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
8247 /*
8248 * The attrnames section contains a system attribute on an
8249 * attribute. Save the name of the attribute for use later,
8250 * and replace the null separating the attribute name from
8251 * the system attribute name with a '/' so that xattrapath can
8252 * be used to display messages with the full attribute path name
8253 * rooted at the hidden attribute directory of the base file
8254 * in normal name space.
8255 */
8256 attrparent = strdup(xattrapath);
8257 attrparentlen = strlen(attrparent);
8258 xattrapath[attrparentlen] = '/';
8259 }
8260 if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
8261 xattrapath + attrparentlen + 1, xattrapath, attrparent,
8262 -1, 0, attrinfo)) == 1) {
8263 free(attrparent);
8264 return (1);
8265 }
8266
8267 /* Gather link info */
8268 if (xattr_linkp) {
8269 xattr_linkaname = xattr_linkp->h_names +
8270 strlen(xattr_linkp->h_names) + 1;
8271 } else {
8272 xattr_linkaname = NULL;
8273 }
8274
8275 return (0);
8276 }
8277 #else
8278 static int
8279 read_xattr_hdr(attr_data_t **attrinfo)
8280 {
8281 return (0);
8282 }
8283 #endif
8284
8285 /*
8286 * skip over extra slashes in string.
8287 *
8288 * For example:
8289 * /usr/tmp/////
8290 *
8291 * would return pointer at
8292 * /usr/tmp/////
8293 * ^
8294 */
8295 static char *
8296 skipslashes(char *string, char *start)
8297 {
8298 while ((string > start) && *(string - 1) == '/') {
8299 string--;
8300 }
8301
8302 return (string);
8303 }
8304
8305 /*
8306 * Return the parent directory of a given path.
8307 *
8308 * Examples:
8309 * /usr/tmp return /usr
8310 * /usr/tmp/file return /usr/tmp
8311 * / returns .
8312 * /usr returns /
8313 * file returns .
8314 *
8315 * dir is assumed to be at least as big as path.
8316 */
8317 static void
8318 get_parent(char *path, char *dir)
8319 {
8320 char *s;
8321 char tmpdir[PATH_MAX + 1];
8322
8323 if (strlen(path) > PATH_MAX) {
8324 fatal(gettext("pathname is too long"));
8325 }
8326 (void) strcpy(tmpdir, path);
8327 chop_endslashes(tmpdir);
8328
8329 if ((s = strrchr(tmpdir, '/')) == NULL) {
8330 (void) strcpy(dir, ".");
8331 } else {
8332 s = skipslashes(s, tmpdir);
8333 *s = '\0';
8334 if (s == tmpdir)
8335 (void) strcpy(dir, "/");
8336 else
8337 (void) strcpy(dir, tmpdir);
8338 }
8339 }
8340
8341 #if defined(O_XATTR)
8342 static char *
8343 get_component(char *path)
8344 {
8345 char *ptr;
8346
8347 ptr = strrchr(path, '/');
8348 if (ptr == NULL) {
8349 return (path);
8350 } else {
8351 /*
8352 * Handle trailing slash
8353 */
8354 if (*(ptr + 1) == '\0')
8355 return (ptr);
8356 else
8357 return (ptr + 1);
8358 }
8359 }
8360 #else
8361 static char *
8362 get_component(char *path)
8363 {
8364 return (path);
8365 }
8366 #endif
8367
8368 #if defined(O_XATTR)
8369 static int
8370 retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
8371 int oflag, mode_t mode)
8372 {
8373 int dirfd;
8374 int ofilefd = -1;
8375 struct timeval times[2];
8376 mode_t newmode;
8377 struct stat parentstat;
8378 acl_t *aclp = NULL;
8379 int error;
8380
8381 /*
8382 * We couldn't get to attrdir. See if its
8383 * just a mode problem on the parent file.
8384 * for example: a mode such as r-xr--r--
8385 * on a ufs file system without extended
8386 * system attribute support won't let us
8387 * create an attribute dir if it doesn't
8388 * already exist, and on a ufs file system
8389 * with extended system attribute support
8390 * won't let us open the attribute for
8391 * write.
8392 *
8393 * If file has a non-trivial ACL, then save it
8394 * off so that we can place it back on after doing
8395 * chmod's.
8396 */
8397 if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
8398 O_RDONLY)) == -1) {
8399 return (-1);
8400 }
8401 if (fstat(dirfd, &parentstat) == -1) {
8402 (void) fprintf(stderr, gettext(
8403 "tar: cannot stat %sfile %s: %s\n"),
8404 (pdirfd == -1) ? "" : gettext("parent of "),
8405 (pdirfd == -1) ? dirp : name, strerror(errno));
8406 return (-1);
8407 }
8408 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
8409 (void) fprintf(stderr, gettext(
8410 "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8411 (pdirfd == -1) ? "" : gettext("parent of "),
8412 (pdirfd == -1) ? dirp : name, strerror(errno));
8413 return (-1);
8414 }
8415
8416 newmode = S_IWUSR | parentstat.st_mode;
8417 if (fchmod(dirfd, newmode) == -1) {
8418 (void) fprintf(stderr,
8419 gettext(
8420 "tar: cannot fchmod %sfile %s to %o: %s\n"),
8421 (pdirfd == -1) ? "" : gettext("parent of "),
8422 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8423 if (aclp)
8424 acl_free(aclp);
8425 return (-1);
8426 }
8427
8428
8429 if (pdirfd == -1) {
8430 /*
8431 * We weren't able to create the attribute directory before.
8432 * Now try again.
8433 */
8434 ofilefd = attropen(dirp, ".", oflag);
8435 } else {
8436 /*
8437 * We weren't able to create open the attribute before.
8438 * Now try again.
8439 */
8440 ofilefd = openat(pdirfd, name, oflag, mode);
8441 }
8442
8443 /*
8444 * Put mode back to original
8445 */
8446 if (fchmod(dirfd, parentstat.st_mode) == -1) {
8447 (void) fprintf(stderr,
8448 gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8449 (pdirfd == -1) ? "" : gettext("parent of "),
8450 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8451 }
8452
8453 if (aclp) {
8454 error = facl_set(dirfd, aclp);
8455 if (error) {
8456 (void) fprintf(stderr,
8457 gettext("tar: failed to set acl entries on "
8458 "%sfile %s\n"),
8459 (pdirfd == -1) ? "" : gettext("parent of "),
8460 (pdirfd == -1) ? dirp : name);
8461 }
8462 acl_free(aclp);
8463 }
8464
8465 /*
8466 * Put back time stamps
8467 */
8468
8469 times[0].tv_sec = parentstat.st_atime;
8470 times[0].tv_usec = 0;
8471 times[1].tv_sec = parentstat.st_mtime;
8472 times[1].tv_usec = 0;
8473
8474 (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
8475
8476 (void) close(dirfd);
8477
8478 return (ofilefd);
8479 }
8480 #endif
8481
8482 #if !defined(O_XATTR)
8483 static int
8484 openat64(int fd, const char *name, int oflag, mode_t cmode)
8485 {
8486 return (open64(name, oflag, cmode));
8487 }
8488
8489 static int
8490 openat(int fd, const char *name, int oflag, mode_t cmode)
8491 {
8492 return (open(name, oflag, cmode));
8493 }
8494
8495 static int
8496 fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
8497 {
8498 if (flag == AT_SYMLINK_NOFOLLOW)
8499 return (lchown(name, owner, group));
8500 else
8501 return (chown(name, owner, group));
8502 }
8503
8504 static int
8505 renameat(int fromfd, char *old, int tofd, char *new)
8506 {
8507 return (rename(old, new));
8508 }
8509
8510 static int
8511 futimesat(int fd, char *path, struct timeval times[2])
8512 {
8513 return (utimes(path, times));
8514 }
8515
8516 static int
8517 unlinkat(int dirfd, char *path, int flag)
8518 {
8519 if (flag == AT_REMOVEDIR)
8520 return (rmdir(path));
8521 else
8522 return (unlink(path));
8523 }
8524
8525 static int
8526 fstatat(int fd, char *path, struct stat *buf, int flag)
8527 {
8528 if (flag == AT_SYMLINK_NOFOLLOW)
8529 return (lstat(path, buf));
8530 else
8531 return (stat(path, buf));
8532 }
8533
8534 static int
8535 attropen(char *file, char *attr, int omode, mode_t cmode)
8536 {
8537 errno = ENOTSUP;
8538 return (-1);
8539 }
8540 #endif
8541
8542 static void
8543 chop_endslashes(char *path)
8544 {
8545 char *end, *ptr;
8546
8547 /*
8548 * Chop of slashes, but not if all we have is slashes
8549 * for example: ////
8550 * should make no changes, otherwise it will screw up
8551 * checkdir
8552 */
8553 end = &path[strlen(path) -1];
8554 if (*end == '/' && end != path) {
8555 ptr = skipslashes(end, path);
8556 if (ptr != NULL && ptr != path) {
8557 *ptr = '\0';
8558 }
8559 }
8560 }
8561 /* Trusted Extensions */
8562
8563 /*
8564 * append_ext_attr():
8565 *
8566 * Append extended attributes and other information into the buffer
8567 * that gets written to the ancillary file.
8568 *
8569 * With option 'T', we create a tarfile which
8570 * has an ancillary file each corresponding archived file.
8571 * Each ancillary file contains 1 or more of the
8572 * following attributes:
8573 *
8574 * attribute type attribute process procedure
8575 * ---------------- ---------------- --------------------------
8576 * DIR_TYPE = 'D' directory flag append if a directory
8577 * LBL_TYPE = 'L' SL[IL] or SL append ascii label
8578 *
8579 *
8580 */
8581 static void
8582 append_ext_attr(char *shortname, char **secinfo, int *len)
8583 {
8584 bslabel_t b_slabel; /* binary sensitvity label */
8585 char *ascii = NULL; /* ascii label */
8586
8587 /*
8588 * For each attribute type, append it if it is
8589 * relevant to the file type.
8590 */
8591
8592 /*
8593 * For attribute type DIR_TYPE,
8594 * append it to the following file type:
8595 *
8596 * S_IFDIR: directories
8597 */
8598
8599 /*
8600 * For attribute type LBL_TYPE,
8601 * append it to the following file type:
8602 *
8603 * S_IFDIR: directories (including mld, sld)
8604 * S_IFLNK: symbolic link
8605 * S_IFREG: regular file but not hard link
8606 * S_IFIFO: FIFO file but not hard link
8607 * S_IFCHR: char special file but not hard link
8608 * S_IFBLK: block special file but not hard link
8609 */
8610 switch (stbuf.st_mode & S_IFMT) {
8611
8612 case S_IFDIR:
8613
8614 /*
8615 * append DIR_TYPE
8616 */
8617 (void) append_secattr(secinfo, len, 1,
8618 "\0", DIR_TYPE);
8619
8620 /*
8621 * Get and append attribute types LBL_TYPE.
8622 * For directories, LBL_TYPE contains SL.
8623 */
8624 /* get binary sensitivity label */
8625 if (getlabel(shortname, &b_slabel) != 0) {
8626 (void) fprintf(stderr,
8627 gettext("tar: can't get sensitvity label for "
8628 " %s, getlabel() error: %s\n"),
8629 shortname, strerror(errno));
8630 } else {
8631 /* get ascii SL */
8632 if (bsltos(&b_slabel, &ascii,
8633 0, 0) <= 0) {
8634 (void) fprintf(stderr,
8635 gettext("tar: can't get ascii SL for"
8636 " %s\n"), shortname);
8637 } else {
8638 /* append LBL_TYPE */
8639 (void) append_secattr(secinfo, len,
8640 strlen(ascii) + 1, ascii,
8641 LBL_TYPE);
8642
8643 /* free storage */
8644 if (ascii != NULL) {
8645 free(ascii);
8646 ascii = (char *)0;
8647 }
8648 }
8649
8650 }
8651 break;
8652
8653 case S_IFLNK:
8654 case S_IFREG:
8655 case S_IFIFO:
8656 case S_IFCHR:
8657 case S_IFBLK:
8658
8659 /* get binary sensitivity label */
8660 if (getlabel(shortname, &b_slabel) != 0) {
8661 (void) fprintf(stderr,
8662 gettext("tar: can't get sensitivty label for %s, "
8663 "getlabel() error: %s\n"),
8664 shortname, strerror(errno));
8665 } else {
8666 /* get ascii IL[SL] */
8667 if (bsltos(&b_slabel, &ascii, 0, 0) <= 0) {
8668 (void) fprintf(stderr,
8669 gettext("tar: can't translate sensitivity "
8670 " label for %s\n"), shortname);
8671 } else {
8672 char *cmw_label;
8673 size_t cmw_length;
8674
8675 cmw_length = strlen("ADMIN_LOW [] ") +
8676 strlen(ascii);
8677 if ((cmw_label = malloc(cmw_length)) == NULL) {
8678 (void) fprintf(stderr, gettext(
8679 "Insufficient memory for label\n"));
8680 exit(1);
8681 }
8682 /* append LBL_TYPE */
8683 (void) snprintf(cmw_label, cmw_length,
8684 "ADMIN_LOW [%s]", ascii);
8685 (void) append_secattr(secinfo, len,
8686 strlen(cmw_label) + 1, cmw_label,
8687 LBL_TYPE);
8688
8689 /* free storage */
8690 if (ascii != NULL) {
8691 free(cmw_label);
8692 free(ascii);
8693 ascii = (char *)0;
8694 }
8695 }
8696 }
8697 break;
8698
8699 default:
8700 break;
8701 } /* end switch for LBL_TYPE */
8702
8703
8704 /* DONE !! */
8705 return;
8706
8707 } /* end of append_ext_attr */
8708
8709
8710 /*
8711 * Name: extract_attr()
8712 *
8713 * Description:
8714 * Process attributes from the ancillary file due to
8715 * the T option.
8716 *
8717 * Call by doxtract() as part of the switch case structure.
8718 * Making this a separate routine because the nesting are too
8719 * deep in doxtract, thus, leaving very little space
8720 * on each line for instructions.
8721 *
8722 * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
8723 *
8724 * For option 'T', following are possible attributes in
8725 * a TS 8 ancillary file: (NOTE: No IL support)
8726 *
8727 * attribute type attribute process procedure
8728 * ---------------- ---------------- -------------------------
8729 * # LBL_TYPE = 'L' SL construct binary label
8730 * # APRIV_TYPE = 'P' allowed priv construct privileges
8731 * # FPRIV_TYPE = 'p' forced priv construct privileges
8732 * # COMP_TYPE = 'C' path component construct real path
8733 * # DIR_TYPE = 'D' directory flag note it is a directory
8734 * $ UFSD_ACL = '1' ACL data construct ACL entries
8735 * ATTR_FLAG_TYPE = 'F' file attr flags construct binary flags
8736 * LK_COMP_TYPE = 'K' linked path comp construct linked real path
8737 *
8738 * note: # = attribute names common between TS 8 & TS 2.5 ancillary
8739 * files.
8740 * $ = ACL attribute is processed for the option 'p', it doesn't
8741 * need option 'T'.
8742 *
8743 * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
8744 *
8745 */
8746 static void
8747 extract_attr(char **file_ptr, struct sec_attr *attr)
8748 {
8749 int reterr, err;
8750 char *dummy_buf; /* for attribute extract */
8751
8752 dummy_buf = attr->attr_info;
8753
8754 switch (attr->attr_type) {
8755
8756 case DIR_TYPE:
8757
8758 dir_flag++;
8759 break;
8760
8761 case LBL_TYPE:
8762
8763 /*
8764 * LBL_TYPE is used to indicate SL for directory, and
8765 * CMW label for other file types.
8766 */
8767
8768 if (!dir_flag) { /* not directory */
8769 /* Skip over IL portion */
8770 char *sl_ptr = strchr(dummy_buf, '[');
8771
8772 if (sl_ptr == NULL)
8773 err = 0;
8774 else
8775 err = stobsl(sl_ptr, &bs_label,
8776 NEW_LABEL, &reterr);
8777 } else { /* directory */
8778 err = stobsl(dummy_buf, &bs_label,
8779 NEW_LABEL, &reterr);
8780 }
8781 if (err == 0) {
8782 (void) fprintf(stderr, gettext("tar: "
8783 "can't convert %s to binary label\n"),
8784 dummy_buf);
8785 bslundef(&bs_label);
8786 } else if (!blequal(&bs_label, &admin_low) &&
8787 !blequal(&bs_label, &admin_high)) {
8788 bslabel_t *from_label;
8789 char *buf;
8790 char tempbuf[MAXPATHLEN];
8791
8792 if (*orig_namep != '/') {
8793 /* got relative linked to path */
8794 (void) getcwd(tempbuf, (sizeof (tempbuf)));
8795 (void) strncat(tempbuf, "/", MAXPATHLEN);
8796 } else
8797 *tempbuf = '\0';
8798
8799 buf = real_path;
8800 (void) strncat(tempbuf, orig_namep, MAXPATHLEN);
8801 from_label = getlabelbypath(tempbuf);
8802 if (from_label != NULL) {
8803 if (blequal(from_label, &admin_low)) {
8804 if ((getpathbylabel(tempbuf, buf,
8805 MAXPATHLEN, &bs_label) == NULL)) {
8806 (void) fprintf(stderr,
8807 gettext("tar: "
8808 "can't get zone root path for "
8809 "%s\n"), tempbuf);
8810 } else
8811 rpath_flag = 1;
8812 }
8813 free(from_label);
8814 }
8815 }
8816 break;
8817
8818 case COMP_TYPE:
8819
8820 rebuild_comp_path(dummy_buf, file_ptr);
8821 break;
8822
8823 case LK_COMP_TYPE:
8824
8825 if (rebuild_lk_comp_path(dummy_buf, file_ptr)
8826 == 0) {
8827 lk_rpath_flag = 1;
8828 } else {
8829 (void) fprintf(stderr, gettext("tar: warning: link's "
8830 "target pathname might be invalid.\n"));
8831 lk_rpath_flag = 0;
8832 }
8833 break;
8834 case APRIV_TYPE:
8835 ignored_aprivs++;
8836 break;
8837 case FPRIV_TYPE:
8838 ignored_fprivs++;
8839 break;
8840 case ATTR_FLAG_TYPE:
8841 ignored_fattrs++;
8842 break;
8843
8844 default:
8845
8846 break;
8847 }
8848
8849 /* done */
8850 return;
8851
8852 } /* end extract_attr */
8853
8854
8855
8856 /*
8857 * Name: rebuild_comp_path()
8858 *
8859 * Description:
8860 * Take the string of components passed down by the calling
8861 * routine and parse the values and rebuild the path.
8862 * This routine no longer needs to produce a new real_path
8863 * string because it is produced when the 'L' LABEL_TYPE is
8864 * interpreted. So the only thing done here is to distinguish
8865 * between an SLD and an MLD entry. We only want one, so we
8866 * ignore the MLD entry by setting the mld_flag.
8867 *
8868 * return value:
8869 * none
8870 */
8871 static void
8872 rebuild_comp_path(char *str, char **namep)
8873 {
8874 char *cp;
8875
8876 while (*str != '\0') {
8877
8878 switch (*str) {
8879
8880 case MLD_TYPE:
8881
8882 str++;
8883 if ((cp = strstr(str, ";;")) != NULL) {
8884 *cp = '\0';
8885 str = cp + 2;
8886 *cp = ';';
8887 }
8888 mld_flag = 1;
8889 break;
8890
8891 case SLD_TYPE:
8892
8893 str++;
8894 if ((cp = strstr(str, ";;")) != NULL) {
8895 *cp = '\0';
8896 str = cp + 2;
8897 *cp = ';';
8898 }
8899 mld_flag = 0;
8900 break;
8901
8902 case PATH_TYPE:
8903
8904 str++;
8905 if ((cp = strstr(str, ";;")) != NULL) {
8906 *cp = '\0';
8907 str = cp + 2;
8908 *cp = ';';
8909 }
8910 break;
8911 }
8912 }
8913 if (rpath_flag)
8914 *namep = real_path;
8915 return;
8916
8917 } /* end rebuild_comp_path() */
8918
8919 /*
8920 * Name: rebuild_lk_comp_path()
8921 *
8922 * Description:
8923 * Take the string of components passed down by the calling
8924 * routine and parse the values and rebuild the path.
8925 *
8926 * return value:
8927 * 0 = succeeded
8928 * -1 = failed
8929 */
8930 static int
8931 rebuild_lk_comp_path(char *str, char **namep)
8932 {
8933 char *cp;
8934 int reterr;
8935 bslabel_t bslabel;
8936 char *buf;
8937 char pbuf[MAXPATHLEN];
8938 char *ptr1, *ptr2;
8939 int plen;
8940 int use_pbuf;
8941 char tempbuf[MAXPATHLEN];
8942 int mismatch;
8943 bslabel_t *from_label;
8944 char zonename[ZONENAME_MAX];
8945 zoneid_t zoneid;
8946
8947 /* init stuff */
8948 use_pbuf = 0;
8949 mismatch = 0;
8950
8951 /*
8952 * For linked to pathname (LK_COMP_TYPE):
8953 * - If the linked to pathname is absolute (start with /), we
8954 * will use it as is.
8955 * - If it is a relative pathname then it is relative to 1 of 2
8956 * directories. For a hardlink, it is relative to the current
8957 * directory. For a symbolic link, it is relative to the
8958 * directory the symbolic link is in. For the symbolic link
8959 * case, set a flag to indicate we need to use the prefix of
8960 * the restored file's pathname with the linked to pathname.
8961 *
8962 * NOTE: At this point, we have no way to determine if we have
8963 * a hardlink or a symbolic link. We will compare the 1st
8964 * component in the prefix portion of the restore file's
8965 * pathname to the 1st component in the attribute data
8966 * (the linked pathname). If they are the same, we will assume
8967 * the link pathname to reconstruct is relative to the current
8968 * directory. Otherwise, we will set a flag indicate we need
8969 * to use a prefix with the reconstructed name. Need to compare
8970 * both the adorned and unadorned version before deciding a
8971 * mismatch.
8972 */
8973
8974 buf = lk_real_path;
8975 if (*(str + 1) != '/') { /* got relative linked to path */
8976 ptr1 = orig_namep;
8977 ptr2 = strrchr(ptr1, '/');
8978 plen = ptr2 - ptr1;
8979 if (plen > 0) {
8980 pbuf[0] = '\0';
8981 plen++; /* include '/' */
8982 (void) strncpy(pbuf, ptr1, plen);
8983 *(pbuf + plen) = '\0';
8984 ptr2 = strchr(pbuf, '/');
8985 if (strncmp(pbuf, str + 1, ptr2 - pbuf) != 0)
8986 mismatch = 1;
8987 }
8988
8989 if (mismatch == 1)
8990 use_pbuf = 1;
8991 }
8992
8993 buf[0] = '\0';
8994
8995 while (*str != '\0') {
8996
8997 switch (*str) {
8998
8999 case MLD_TYPE:
9000
9001 str++;
9002 if ((cp = strstr(str, ";;")) != NULL) {
9003 *cp = '\0';
9004
9005 /*
9006 * Ignore attempts to backup over .MLD.
9007 */
9008 if (strcmp(str, "../") != 0)
9009 (void) strncat(buf, str, MAXPATHLEN);
9010 str = cp + 2;
9011 *cp = ';';
9012 }
9013 break;
9014
9015 case SLD_TYPE:
9016
9017 str++;
9018 if ((cp = strstr(str, ";;")) != NULL) {
9019 *cp = '\0';
9020
9021 /*
9022 * Use the path name in the header if
9023 * error occurs when processing the
9024 * SLD type.
9025 */
9026
9027 if (!stobsl(str, &bslabel,
9028 NO_CORRECTION, &reterr)) {
9029 (void) fprintf(stderr, gettext(
9030 "tar: can't translate to binary"
9031 "SL for SLD, stobsl() error:"
9032 " %s\n"), strerror(errno));
9033 return (-1);
9034 }
9035
9036 str = cp + 2;
9037 *cp = ';';
9038
9039 if (use_pbuf == 1) {
9040 if (*pbuf != '/') {
9041 /* relative linked to path */
9042
9043 (void) getcwd(tempbuf,
9044 (sizeof (tempbuf)));
9045 (void) strncat(tempbuf, "/",
9046 MAXPATHLEN);
9047 (void) strncat(tempbuf, pbuf,
9048 MAXPATHLEN);
9049 }
9050 else
9051 (void) strcpy(tempbuf, pbuf);
9052
9053 } else if (*buf != '/') {
9054 /* got relative linked to path */
9055
9056 (void) getcwd(tempbuf,
9057 (sizeof (tempbuf)));
9058 (void) strncat(tempbuf, "/",
9059 MAXPATHLEN);
9060 } else
9061 *tempbuf = '\0';
9062
9063 (void) strncat(tempbuf, buf, MAXPATHLEN);
9064 *buf = '\0';
9065
9066 if (blequal(&bslabel, &admin_high)) {
9067 bslabel = admin_low;
9068 }
9069
9070
9071 /*
9072 * Check for cross-zone symbolic links
9073 */
9074 from_label = getlabelbypath(real_path);
9075 if (rpath_flag && (from_label != NULL) &&
9076 !blequal(&bslabel, from_label)) {
9077 if ((zoneid =
9078 getzoneidbylabel(&bslabel)) == -1) {
9079 (void) fprintf(stderr,
9080 gettext("tar: can't get "
9081 "zone ID for %s\n"),
9082 tempbuf);
9083 return (-1);
9084 }
9085 if (zone_getattr(zoneid, ZONE_ATTR_NAME,
9086 &zonename, ZONENAME_MAX) == -1) {
9087 /* Badly configured zone info */
9088 (void) fprintf(stderr,
9089 gettext("tar: can't get "
9090 "zonename for %s\n"),
9091 tempbuf);
9092 return (-1);
9093 }
9094 (void) strncpy(buf, AUTO_ZONE,
9095 MAXPATHLEN);
9096 (void) strncat(buf, "/",
9097 MAXPATHLEN);
9098 (void) strncat(buf, zonename,
9099 MAXPATHLEN);
9100 }
9101 if (from_label != NULL)
9102 free(from_label);
9103 (void) strncat(buf, tempbuf, MAXPATHLEN);
9104 break;
9105 }
9106 mld_flag = 0;
9107 break;
9108
9109 case PATH_TYPE:
9110
9111 str++;
9112 if ((cp = strstr(str, ";;")) != NULL) {
9113 *cp = '\0';
9114 (void) strncat(buf, str, MAXPATHLEN);
9115 str = cp + 2;
9116 *cp = ';';
9117 }
9118 break;
9119
9120 default:
9121
9122 (void) fprintf(stderr, gettext(
9123 "tar: error rebuilding path %s\n"),
9124 *namep);
9125 *buf = '\0';
9126 str++;
9127 return (-1);
9128 }
9129 }
9130
9131 /*
9132 * Done for LK_COMP_TYPE
9133 */
9134
9135 return (0); /* component path is rebuilt successfully */
9136
9137 } /* end rebuild_lk_comp_path() */
9138
9139 /*
9140 * Name: check_ext_attr()
9141 *
9142 * Description:
9143 * Check the extended attributes for a file being extracted.
9144 * The attributes being checked here are CMW labels.
9145 * ACLs are not set here because they are set by the
9146 * pflag in doxtract().
9147 *
9148 * If the label doesn't match, return 0
9149 * else return 1
9150 */
9151 static int
9152 check_ext_attr(char *filename)
9153 {
9154 bslabel_t currentlabel; /* label from zone */
9155
9156 if (bltype(&bs_label, SUN_SL_UN)) {
9157 /* No label check possible */
9158 return (0);
9159 }
9160 if (getlabel(filename, ¤tlabel) != 0) {
9161 (void) fprintf(stderr,
9162 gettext("tar: can't get label for "
9163 " %s, getlabel() error: %s\n"),
9164 filename, strerror(errno));
9165 return (0);
9166 } else if ((blequal(¤tlabel, &bs_label)) == 0) {
9167 char *src_label = NULL; /* ascii label */
9168
9169 /* get current src SL */
9170 if (bsltos(&bs_label, &src_label, 0, 0) <= 0) {
9171 (void) fprintf(stderr,
9172 gettext("tar: can't interpret requested label for"
9173 " %s\n"), filename);
9174 } else {
9175 (void) fprintf(stderr,
9176 gettext("tar: can't apply label %s to %s\n"),
9177 src_label, filename);
9178 free(src_label);
9179 }
9180 (void) fprintf(stderr,
9181 gettext("tar: %s not restored\n"), filename);
9182 return (0);
9183 }
9184 return (1);
9185
9186 } /* end check_ext_attr */
9187
9188 /* Compressing a tar file using compression method provided in 'opt' */
9189
9190 static void
9191 compress_back()
9192 {
9193 pid_t pid;
9194 int status;
9195 int wret;
9196 struct stat statb;
9197
9198 if (vflag) {
9199 (void) fprintf(vfile,
9200 gettext("Compressing '%s' with '%s'...\n"),
9201 usefile, compress_opt);
9202 }
9203 if ((pid = fork()) == 0) {
9204 verify_compress_opt(compress_opt);
9205 (void) execlp(compress_opt, compress_opt,
9206 usefile, NULL);
9207 } else if (pid == -1) {
9208 vperror(1, "%s", gettext("Could not fork"));
9209 }
9210 wait_pid(pid);
9211 if (suffix == 0) {
9212 (void) rename(tfname, usefile);
9213 }
9214 }
9215
9216 /* The magic numbers from /etc/magic */
9217
9218 #define GZIP_MAGIC "\037\213"
9219 #define BZIP_MAGIC "BZh"
9220 #define COMP_MAGIC "\037\235"
9221 #define XZ_MAGIC "\375\067\172\130\132\000"
9222
9223 void
9224 check_compression(void)
9225 {
9226 char magic[16];
9227 FILE *fp;
9228
9229 if ((fp = fopen(usefile, "r")) != NULL) {
9230 (void) fread(magic, sizeof (char), 6, fp);
9231 (void) fclose(fp);
9232 }
9233
9234 if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
9235 if (xflag || tflag) {
9236 compress_opt = compress_malloc(strlen(GZCAT) + 1);
9237 (void) strcpy(compress_opt, GZCAT);
9238 } else if (uflag || rflag) {
9239 compress_opt = compress_malloc(strlen(GZIP) + 1);
9240 (void) strcpy(compress_opt, GZIP);
9241 }
9242 } else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
9243 if (xflag || tflag) {
9244 compress_opt = compress_malloc(strlen(BZCAT) + 1);
9245 (void) strcpy(compress_opt, BZCAT);
9246 } else if (uflag || rflag) {
9247 compress_opt = compress_malloc(strlen(BZIP) + 1);
9248 (void) strcpy(compress_opt, BZIP);
9249 }
9250 } else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
9251 if (xflag || tflag) {
9252 compress_opt = compress_malloc(strlen(ZCAT) + 1);
9253 (void) strcpy(compress_opt, ZCAT);
9254 } else if (uflag || rflag) {
9255 compress_opt = compress_malloc(strlen(COMPRESS) + 1);
9256 (void) strcpy(compress_opt, COMPRESS);
9257 }
9258 } else if (memcmp(magic, XZ_MAGIC, 6) == 0) {
9259 if (xflag || tflag) {
9260 compress_opt = compress_malloc(strlen(XZCAT) + 1);
9261 (void) strcpy(compress_opt, XZCAT);
9262 } else if (uflag || rflag) {
9263 compress_opt = compress_malloc(strlen(XZ) + 1);
9264 (void) strcpy(compress_opt, XZ);
9265 }
9266 }
9267 }
9268
9269 char *
9270 add_suffix()
9271 {
9272 (void) strcpy(tfname, usefile);
9273 if (strcmp(compress_opt, GZIP) == 0) {
9274 if ((suffix = gz_suffix()) == NULL) {
9275 strlcat(tfname, gsuffix[0], sizeof (tfname));
9276 return (gsuffix[0]);
9277 }
9278 } else if (strcmp(compress_opt, COMPRESS) == 0) {
9279 if ((suffix = gz_suffix()) == NULL) {
9280 strlcat(tfname, gsuffix[6], sizeof (tfname));
9281 return (gsuffix[6]);
9282 }
9283 } else if (strcmp(compress_opt, BZIP) == 0) {
9284 if ((suffix = bz_suffix()) == NULL) {
9285 strlcat(tfname, bsuffix[0], sizeof (tfname));
9286 return (bsuffix[0]);
9287 }
9288 } else if (strcmp(compress_opt, XZ) == 0) {
9289 if ((suffix = xz_suffix()) == NULL) {
9290 strlcat(tfname, xsuffix[0], sizeof (tfname));
9291 return (xsuffix[0]);
9292 }
9293 }
9294 return (NULL);
9295 }
9296
9297 /* Decompressing a tar file using compression method from the file type */
9298 void
9299 decompress_file(void)
9300 {
9301 pid_t pid;
9302 int status;
9303 char cmdstr[PATH_MAX];
9304 char fname[PATH_MAX];
9305 char *added_suffix;
9306
9307
9308 added_suffix = add_suffix();
9309 if (added_suffix != NULL) {
9310 (void) rename(usefile, tfname);
9311 }
9312 if ((pid = fork()) == 0) {
9313 if (vflag) {
9314 (void) fprintf(vfile,
9315 gettext("Decompressing '%s' with "
9316 "'%s'...\n"), usefile, compress_opt);
9317 }
9318 verify_compress_opt(compress_opt);
9319 (void) execlp(compress_opt, compress_opt, "-df",
9320 tfname, NULL);
9321 vperror(1, gettext("Could not exec %s"), compress_opt);
9322 } else if (pid == -1) {
9323 vperror(1, gettext("Could not fork"));
9324 }
9325 wait_pid(pid);
9326 if (suffix != NULL) {
9327 /* restore the file name - original file was without suffix */
9328 *(usefile + strlen(usefile) - strlen(suffix)) = '\0';
9329 }
9330 }
9331
9332 /* Set the archive for writing and then compress the archive */
9333 pid_t
9334 compress_file(void)
9335 {
9336 int fd[2];
9337 pid_t pid;
9338
9339 if (vflag) {
9340 (void) fprintf(vfile, gettext("Compressing '%s' with "
9341 "'%s'...\n"), usefile, compress_opt);
9342 }
9343
9344 if (pipe(fd) < 0) {
9345 vperror(1, gettext("Could not create pipe"));
9346 }
9347 if (pid = fork() > 0) {
9348 mt = fd[1];
9349 (void) close(fd[0]);
9350 return (pid);
9351 }
9352 /* child */
9353 (void) dup2(fd[0], STDIN_FILENO);
9354 (void) close(fd[1]);
9355 (void) dup2(mt, STDOUT_FILENO);
9356 verify_compress_opt(compress_opt);
9357 (void) execlp(compress_opt, compress_opt, NULL);
9358 vperror(1, gettext("Could not exec %s"), compress_opt);
9359 return (0); /*NOTREACHED*/
9360 }
9361
9362 pid_t
9363 uncompress_file(void)
9364 {
9365 int fd[2];
9366 pid_t pid;
9367
9368 if (vflag) {
9369 (void) fprintf(vfile, gettext("Decompressing '%s' with "
9370 "'%s'...\n"), usefile, compress_opt);
9371 }
9372
9373 if (pipe(fd) < 0) {
9374 vperror(1, gettext("Could not create pipe"));
9375 }
9376 if (pid = fork() > 0) {
9377 mt = fd[0];
9378 (void) close(fd[1]);
9379 return (pid);
9380 }
9381 /* child */
9382 (void) dup2(fd[1], STDOUT_FILENO);
9383 (void) close(fd[0]);
9384 (void) dup2(mt, STDIN_FILENO);
9385 verify_compress_opt(compress_opt);
9386 (void) execlp(compress_opt, compress_opt, NULL);
9387 vperror(1, gettext("Could not exec %s"), compress_opt);
9388 return (0); /*NOTREACHED*/
9389 }
9390
9391 /* Checking suffix validity */
9392 char *
9393 check_suffix(char **suf, int size)
9394 {
9395 int i;
9396 int slen;
9397 int nlen = strlen(usefile);
9398
9399 for (i = 0; i < size; i++) {
9400 slen = strlen(suf[i]);
9401 if (nlen < slen)
9402 return (NULL);
9403 if (strcmp(usefile + nlen - slen, suf[i]) == 0)
9404 return (suf[i]);
9405 }
9406 return (NULL);
9407 }
9408
9409 /* Checking valid 'bzip2' suffix */
9410 char *
9411 bz_suffix(void)
9412 {
9413 return (check_suffix(bsuffix, BSUF));
9414 }
9415
9416 /* Checking valid 'gzip' suffix */
9417 char *
9418 gz_suffix(void)
9419 {
9420 return (check_suffix(gsuffix, GSUF));
9421 }
9422
9423 /* Checking valid 'xz' suffix */
9424 char *
9425 xz_suffix(void)
9426 {
9427 return (check_suffix(xsuffix, XSUF));
9428 }
9429
9430 void *
9431 compress_malloc(size_t size)
9432 {
9433 void *opt;
9434
9435 if ((opt = malloc(size)) == NULL) {
9436 vperror(1, "%s",
9437 gettext("Could not allocate compress buffer\n"));
9438 }
9439 return (opt);
9440 }
9441
9442 void
9443 wait_pid(pid_t pid)
9444 {
9445 int status;
9446
9447 while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
9448 ;
9449 }
9450
9451 static void
9452 verify_compress_opt(const char *t)
9453 {
9454 struct stat statbuf;
9455
9456 if (stat(t, &statbuf) == -1)
9457 vperror(1, "%s %s: %s\n", gettext("Could not stat"),
9458 t, strerror(errno));
9459 }
9460
9461 static void
9462 detect_compress(void)
9463 {
9464 char *zsuf[] = {".Z"};
9465 if (check_suffix(zsuf, 1) != NULL) {
9466 Zflag = 1;
9467 } else if (check_suffix(bsuffix, BSUF) != NULL) {
9468 jflag = 1;
9469 } else if (check_suffix(gsuffix, GSUF) != NULL) {
9470 zflag = 1;
9471 } else if (check_suffix(xsuffix, XSUF) != NULL) {
9472 Jflag = 1;
9473 } else {
9474 vperror(1, "%s\n", gettext("No compression method detected"));
9475 }
9476 }