6910 tar option "e" also forces "o"
[unleashed.git] / usr / src / cmd / tar / tar.c
blobe5cc47ac2463fc1960ed75741f58b32cce2c7a0c
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 * Copyright 2015 Joyent, Inc.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 /* Copyright (c) 1987, 1988 Microsoft Corporation */
31 /* All Rights Reserved */
34 * Portions of this source code were derived from Berkeley 4.3 BSD
35 * under license from the Regents of the University of California.
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>
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
83 /* Trusted Extensions */
84 #include <zone.h>
85 #include <tsol/label.h>
86 #include <sys/tsol/label_macro.h>
88 #include "getresponse.h"
90 * Source compatibility
94 * These constants come from archives.h and sys/fcntl.h
95 * and were introduced by the extended attributes project
96 * in Solaris 9.
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
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.
117 int utimes(const char *path, const struct timeval timeval_ptr[]);
119 #ifndef MINSIZE
120 #define MINSIZE 250
121 #endif
122 #define DEF_FILE "/etc/default/tar"
124 #define min(a, b) ((a) < (b) ? (a) : (b))
125 #define max(a, b) ((a) > (b) ? (a) : (b))
127 #define TBLOCK 512 /* tape block size--should be universal */
129 #ifdef BSIZE
130 #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
131 #else /* BSIZE */
132 #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
133 #endif /* BSIZE */
135 #define NBLOCK 20
136 #define NAMSIZ 100
137 #define PRESIZ 155
138 #define MAXNAM 256
139 #define MODEMASK 0777777 /* file creation mode mask */
140 #define POSIXMODES 07777 /* mask for POSIX mode bits */
141 #define MAXEXT 9 /* reasonable max # extents for a file */
142 #define EXTMIN 50 /* min blks left on floppy to split a file */
144 /* max value dblock.dbuf.efsize can store */
145 #define TAR_EFSIZE_MAX 0777777777
148 * Symbols which specify the values at which the use of the 'E' function
149 * modifier is required to properly store a file.
151 * TAR_OFFSET_MAX - the largest file size we can archive
152 * OCTAL7CHAR - the limit for ustar gid, uid, dev
155 #ifdef XHDR_DEBUG
156 /* tiny values which force the creation of extended header entries */
157 #define TAR_OFFSET_MAX 9
158 #define OCTAL7CHAR 2
159 #else
160 /* normal values */
161 #define TAR_OFFSET_MAX 077777777777ULL
162 #define OCTAL7CHAR 07777777
163 #endif
165 #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
166 #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
168 #define MAXLEV (PATH_MAX / 2)
169 #define LEV0 1
170 #define SYMLINK_LEV0 0
172 #define TRUE 1
173 #define FALSE 0
175 #define XATTR_FILE 1
176 #define NORMAL_FILE 0
178 #define PUT_AS_LINK 1
179 #define PUT_NOTAS_LINK 0
181 #ifndef VIEW_READONLY
182 #define VIEW_READONLY "SUNWattr_ro"
183 #endif
185 #ifndef VIEW_READWRITE
186 #define VIEW_READWRITE "SUNWattr_rw"
187 #endif
189 #if _FILE_OFFSET_BITS == 64
190 #define FMT_off_t "lld"
191 #define FMT_off_t_o "llo"
192 #define FMT_blkcnt_t "lld"
193 #else
194 #define FMT_off_t "ld"
195 #define FMT_off_t_o "lo"
196 #define FMT_blkcnt_t "ld"
197 #endif
199 /* ACL support */
201 static
202 struct sec_attr {
203 char attr_type;
204 char attr_len[7];
205 char attr_info[1];
206 } *attr;
208 #if defined(O_XATTR)
209 typedef enum {
210 ATTR_OK,
211 ATTR_SKIP,
212 ATTR_CHDIR_ERR,
213 ATTR_OPEN_ERR,
214 ATTR_XATTR_ERR,
215 ATTR_SATTR_ERR
216 } attr_status_t;
217 #endif
219 #if defined(O_XATTR)
220 typedef enum {
221 ARC_CREATE,
222 ARC_RESTORE
223 } arc_action_t;
224 #endif
226 typedef struct attr_data {
227 char *attr_parent;
228 char *attr_path;
229 int attr_parentfd;
230 int attr_rw_sysattr;
231 } attr_data_t;
235 * Tar has been changed to support extended attributes.
237 * As part of this change tar now uses the new *at() syscalls
238 * such as openat, fchownat(), unlinkat()...
240 * This was done so that attributes can be handled with as few code changes
241 * as possible.
243 * What this means is that tar now opens the directory that a file or directory
244 * resides in and then performs *at() functions to manipulate the entry.
246 * For example a new file is now created like this:
248 * dfd = open(<some dir path>)
249 * fd = openat(dfd, <name>,....);
251 * or in the case of an extended attribute
253 * dfd = attropen(<pathname>, ".", ....)
255 * Once we have a directory file descriptor all of the *at() functions can
256 * be applied to it.
258 * unlinkat(dfd, <component name>,...)
259 * fchownat(dfd, <component name>,..)
261 * This works for both normal namespace files and extended attribute file
267 * Extended attribute Format
269 * Extended attributes are stored in two pieces.
270 * 1. An attribute header which has information about
271 * what file the attribute is for and what the attribute
272 * is named.
273 * 2. The attribute record itself. Stored as a normal file type
274 * of entry.
275 * Both the header and attribute record have special modes/typeflags
276 * associated with them.
278 * The names of the header in the archive look like:
279 * /dev/null/attr.hdr
281 * The name of the attribute looks like:
282 * /dev/null/attr
284 * This is done so that an archiver that doesn't understand these formats
285 * can just dispose of the attribute records.
287 * The format is composed of a fixed size header followed
288 * by a variable sized xattr_buf. If the attribute is a hard link
289 * to another attribute then another xattr_buf section is included
290 * for the link.
292 * The xattr_buf is used to define the necessary "pathing" steps
293 * to get to the extended attribute. This is necessary to support
294 * a fully recursive attribute model where an attribute may itself
295 * have an attribute.
297 * The basic layout looks like this.
299 * --------------------------------
300 * | |
301 * | xattr_hdr |
302 * | |
303 * --------------------------------
304 * --------------------------------
305 * | |
306 * | xattr_buf |
307 * | |
308 * --------------------------------
309 * --------------------------------
310 * | |
311 * | (optional link info) |
312 * | |
313 * --------------------------------
314 * --------------------------------
315 * | |
316 * | attribute itself |
317 * | stored as normal tar |
318 * | or cpio data with |
319 * | special mode or |
320 * | typeflag |
321 * | |
322 * --------------------------------
327 * xattrhead is a pointer to the xattr_hdr
329 * xattrp is a pointer to the xattr_buf structure
330 * which contains the "pathing" steps to get to attributes
332 * xattr_linkp is a pointer to another xattr_buf structure that is
333 * only used when an attribute is actually linked to another attribute
337 static struct xattr_hdr *xattrhead;
338 static struct xattr_buf *xattrp;
339 static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
340 static char *xattrapath; /* attribute name */
341 static char *xattr_linkaname; /* attribute attribute is linked to */
342 static char Hiddendir; /* are we processing hidden xattr dir */
343 static char xattrbadhead;
345 /* Was statically allocated tbuf[NBLOCK] */
346 static
347 union hblock {
348 char dummy[TBLOCK];
349 struct header {
350 char name[NAMSIZ]; /* If non-null prefix, path is */
351 /* <prefix>/<name>; otherwise */
352 /* <name> */
353 char mode[8];
354 char uid[8];
355 char gid[8];
356 char size[12]; /* size of this extent if file split */
357 char mtime[12];
358 char chksum[8];
359 char typeflag;
360 char linkname[NAMSIZ];
361 char magic[6];
362 char version[2];
363 char uname[32];
364 char gname[32];
365 char devmajor[8];
366 char devminor[8];
367 char prefix[PRESIZ]; /* Together with "name", the path of */
368 /* the file: <prefix>/<name> */
369 char extno; /* extent #, null if not split */
370 char extotal; /* total extents */
371 char efsize[10]; /* size of entire file */
372 } dbuf;
373 } dblock, *tbuf, xhdr_buf;
375 static
376 struct xtar_hdr {
377 uid_t x_uid, /* Uid of file */
378 x_gid; /* Gid of file */
379 major_t x_devmajor; /* Device major node */
380 minor_t x_devminor; /* Device minor node */
381 off_t x_filesz; /* Length of file */
382 char *x_uname, /* Pointer to name of user */
383 *x_gname, /* Pointer to gid of user */
384 *x_linkpath, /* Path for a hard/symbolic link */
385 *x_path; /* Path of file */
386 timestruc_t x_mtime; /* Seconds and nanoseconds */
387 } Xtarhdr;
389 static
390 struct gen_hdr {
391 ulong_t g_mode; /* Mode of file */
392 uid_t g_uid, /* Uid of file */
393 g_gid; /* Gid of file */
394 off_t g_filesz; /* Length of file */
395 time_t g_mtime; /* Modification time */
396 uint_t g_cksum; /* Checksum of file */
397 ulong_t g_devmajor, /* File system of file */
398 g_devminor; /* Major/minor of special files */
399 } Gen;
401 static
402 struct linkbuf {
403 ino_t inum;
404 dev_t devnum;
405 int count;
406 char pathname[MAXNAM+1]; /* added 1 for last NULL */
407 char attrname[MAXNAM+1];
408 struct linkbuf *nextp;
409 } *ihead;
411 /* see comments before build_table() */
412 #define TABLE_SIZE 512
413 typedef struct file_list {
414 char *name; /* Name of file to {in,ex}clude */
415 struct file_list *next; /* Linked list */
416 } file_list_t;
417 static file_list_t *exclude_tbl[TABLE_SIZE],
418 *include_tbl[TABLE_SIZE];
420 static int append_secattr(char **, int *, int, char *, char);
421 static void write_ancillary(union hblock *, char *, int, char);
423 static void add_file_to_table(file_list_t *table[], char *str);
424 static void assert_string(char *s, char *msg);
425 static int istape(int fd, int type);
426 static void backtape(void);
427 static void build_table(file_list_t *table[], char *file);
428 static int check_prefix(char **namep, char **dirp, char **compp);
429 static void closevol(void);
430 static void copy(void *dst, void *src);
431 static int convtoreg(off_t);
432 static void delete_target(int fd, char *comp, char *namep);
433 static void doDirTimes(char *name, timestruc_t modTime);
434 static void done(int n);
435 static void dorep(char *argv[]);
436 static void dotable(char *argv[]);
437 static void doxtract(char *argv[]);
438 static int tar_chdir(const char *path);
439 static int is_directory(char *name);
440 static int has_dot_dot(char *name);
441 static int is_absolute(char *name);
442 static char *make_relative_name(char *name, char **stripped_prefix);
443 static void fatal(char *format, ...);
444 static void vperror(int exit_status, char *fmt, ...);
445 static void flushtape(void);
446 static void getdir(void);
447 static void *getmem(size_t);
448 static void longt(struct stat *st, char aclchar);
449 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
450 static int makeDir(char *name);
451 static void mterr(char *operation, int i, int exitcode);
452 static void newvol(void);
453 static void passtape(void);
454 static void putempty(blkcnt_t n);
455 static int putfile(char *longname, char *shortname, char *parent,
456 attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
457 static void readtape(char *buffer);
458 static void seekdisk(blkcnt_t blocks);
459 static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
460 static void setbytes_to_skip(struct stat *st, int err);
461 static void splitfile(char *longname, int ifd, char *name,
462 char *prefix, int filetype);
463 static void tomodes(struct stat *sp);
464 static void usage(void);
465 static int xblocks(int issysattr, off_t bytes, int ofile);
466 static int xsfile(int issysattr, int ofd);
467 static void resugname(int dirfd, char *name, int symflag);
468 static int bcheck(char *bstr);
469 static int checkdir(char *name);
470 static int checksum(union hblock *dblockp);
471 #ifdef EUC
472 static int checksum_signed(union hblock *dblockp);
473 #endif /* EUC */
474 static int checkupdate(char *arg);
475 static int checkw(char c, char *name);
476 static int cmp(char *b, char *s, int n);
477 static int defset(char *arch);
478 static boolean_t endtape(void);
479 static int is_in_table(file_list_t *table[], char *str);
480 static int notsame(void);
481 static int is_prefix(char *s1, char *s2);
482 static int response(void);
483 static int build_dblock(const char *, const char *, const char,
484 const int filetype, const struct stat *, const dev_t, const char *);
485 static unsigned int hash(char *str);
487 static blkcnt_t kcheck(char *kstr);
488 static off_t bsrch(char *s, int n, off_t l, off_t h);
489 static void onintr(int sig);
490 static void onquit(int sig);
491 static void onhup(int sig);
492 static uid_t getuidbyname(char *);
493 static gid_t getgidbyname(char *);
494 static char *getname(gid_t);
495 static char *getgroup(gid_t);
496 static int checkf(char *name, int mode, int howmuch);
497 static int writetbuf(char *buffer, int n);
498 static int wantit(char *argv[], char **namep, char **dirp, char **comp,
499 attr_data_t **attrinfo);
500 static void append_ext_attr(char *shortname, char **secinfo, int *len);
501 static int get_xdata(void);
502 static void gen_num(const char *keyword, const u_longlong_t number);
503 static void gen_date(const char *keyword, const timestruc_t time_value);
504 static void gen_string(const char *keyword, const char *value);
505 static void get_xtime(char *value, timestruc_t *xtime);
506 static int chk_path_build(char *name, char *longname, char *linkname,
507 char *prefix, char type, int filetype);
508 static int gen_utf8_names(const char *filename);
509 static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
510 const char *src, int max_val);
511 static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
512 iconv_t iconv_cd, int xhdrflg, int max_val);
513 static int c_utf8(char *target, const char *source);
514 static int getstat(int dirfd, char *longname, char *shortname,
515 char *attrparent);
516 static void xattrs_put(char *, char *, char *, char *);
517 static void prepare_xattr(char **, char *, char *,
518 char, struct linkbuf *, int *);
519 static int put_link(char *name, char *longname, char *component,
520 char *longattrname, char *prefix, int filetype, char typeflag);
521 static int put_extra_attributes(char *longname, char *shortname,
522 char *longattrname, char *prefix, int filetype, char typeflag);
523 static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
524 char *prefix, int typeflag, int filetype, struct linkbuf *lp);
525 static int read_xattr_hdr(attr_data_t **attrinfo);
527 /* Trusted Extensions */
528 #define AUTO_ZONE "/zone"
530 static void extract_attr(char **file_ptr, struct sec_attr *);
531 static int check_ext_attr(char *filename);
532 static void rebuild_comp_path(char *str, char **namep);
533 static int rebuild_lk_comp_path(char *str, char **namep);
535 static void get_parent(char *path, char *dir);
536 static char *get_component(char *path);
537 static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
538 char *name, int oflag, mode_t mode);
539 static char *skipslashes(char *string, char *start);
540 static void chop_endslashes(char *path);
541 static pid_t compress_file(void);
542 static void compress_back(void);
543 static void decompress_file(void);
544 static pid_t uncompress_file(void);
545 static void *compress_malloc(size_t);
546 static void check_compression(void);
547 static char *bz_suffix(void);
548 static char *gz_suffix(void);
549 static char *xz_suffix(void);
550 static char *add_suffix();
551 static void wait_pid(pid_t);
552 static void verify_compress_opt(const char *t);
553 static void detect_compress(void);
554 static void dlog(const char *, ...);
555 static boolean_t should_enable_debug(void);
557 static struct stat stbuf;
559 static char *myname;
560 static char *xtract_chdir = NULL;
561 static int checkflag = 0;
562 static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
563 static int rflag, xflag, vflag, tflag, mt, cflag, mflag, pflag;
564 static int uflag;
565 static int errflag;
566 static int oflag;
567 static int bflag, Aflag;
568 static int Pflag; /* POSIX conformant archive */
569 static int Eflag; /* Allow files greater than 8GB */
570 static int atflag; /* traverse extended attributes */
571 static int saflag; /* traverse extended sys attributes */
572 static int Dflag; /* Data change flag */
573 static int jflag; /* flag to use 'bzip2' */
574 static int zflag; /* flag to use 'gzip' */
575 static int Zflag; /* flag to use 'compress' */
576 static int Jflag; /* flag to use 'xz' */
577 static int aflag; /* flag to use autocompression */
579 /* Trusted Extensions */
580 static int Tflag; /* Trusted Extensions attr flags */
581 static int dir_flag; /* for attribute extract */
582 static int mld_flag; /* for attribute extract */
583 static char *orig_namep; /* original namep - unadorned */
584 static int rpath_flag; /* MLD real path is rebuilt */
585 static char real_path[MAXPATHLEN]; /* MLD real path */
586 static int lk_rpath_flag; /* linked to real path is rebuilt */
587 static char lk_real_path[MAXPATHLEN]; /* linked real path */
588 static bslabel_t bs_label; /* for attribute extract */
589 static bslabel_t admin_low;
590 static bslabel_t admin_high;
591 static int ignored_aprivs = 0;
592 static int ignored_fprivs = 0;
593 static int ignored_fattrs = 0;
595 static int term, chksum, wflag,
596 first = TRUE, defaults_used = FALSE, linkerrok;
597 static blkcnt_t recno;
598 static int freemem = 1;
599 static int nblock = NBLOCK;
600 static int Errflg = 0;
601 static int exitflag = 0;
603 static dev_t mt_dev; /* device containing output file */
604 static ino_t mt_ino; /* inode number of output file */
605 static int mt_devtype; /* dev type of archive, from stat structure */
607 static int update = 1; /* for `open' call */
609 static off_t low;
610 static off_t high;
612 static FILE *tfile;
613 static FILE *vfile = stdout;
614 static char *tmpdir;
615 static char *tmp_suffix = "/tarXXXXXX";
616 static char *tname;
617 static char archive[] = "archive0=";
618 static char *Xfile;
619 static char *usefile;
620 static char tfname[1024];
622 static int mulvol; /* multi-volume option selected */
623 static blkcnt_t blocklim; /* number of blocks to accept per volume */
624 static blkcnt_t tapepos; /* current block number to be written */
625 static int NotTape; /* true if tape is a disk */
626 static int dumping; /* true if writing a tape or other archive */
627 static int extno; /* number of extent: starts at 1 */
628 static int extotal; /* total extents in this file */
629 static off_t extsize; /* size of current extent during extraction */
630 static ushort_t Oumask = 0; /* old umask value */
631 static boolean_t is_posix; /* true if archive is POSIX-conformant */
632 static const char *magic_type = "ustar";
633 static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */
634 static char *xrec_ptr;
635 static off_t xrec_offset = 0;
636 static int Xhdrflag;
637 static int charset_type = 0;
639 static u_longlong_t xhdr_flgs; /* Bits set determine which items */
640 /* need to be in extended header. */
641 static pid_t comp_pid = 0;
643 static boolean_t debug_output = B_FALSE;
645 #define _X_DEVMAJOR 0x1
646 #define _X_DEVMINOR 0x2
647 #define _X_GID 0x4
648 #define _X_GNAME 0x8
649 #define _X_LINKPATH 0x10
650 #define _X_PATH 0x20
651 #define _X_SIZE 0x40
652 #define _X_UID 0x80
653 #define _X_UNAME 0x100
654 #define _X_ATIME 0x200
655 #define _X_CTIME 0x400
656 #define _X_MTIME 0x800
657 #define _X_XHDR 0x1000 /* Bit flag that determines whether 'X' */
658 /* typeflag was followed by 'A' or non 'A' */
659 /* typeflag. */
660 #define _X_LAST 0x40000000
662 #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4)
663 #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4)
664 #define LONG_MAX_DIGITS (10 * sizeof (long) / 4)
665 #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4)
667 * UTF_8 encoding requires more space than the current codeset equivalent.
668 * Currently a factor of 2-3 would suffice, but it is possible for a factor
669 * of 6 to be needed in the future, so for saftey, we use that here.
671 #define UTF_8_FACTOR 6
673 static u_longlong_t xhdr_count = 0;
674 static char xhdr_dirname[PRESIZ + 1];
675 static char pidchars[PID_MAX_DIGITS + 1];
676 static char *tchar = ""; /* null linkpath */
678 static char local_path[UTF_8_FACTOR * PATH_MAX + 1];
679 static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
680 static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
681 static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
684 * The following mechanism is provided to allow us to debug tar in complicated
685 * situations, like when it is part of a pipe. The idea is that you compile
686 * with -DWAITAROUND defined, and then add the 'D' function modifier to the
687 * target tar invocation, eg. "tar cDf tarfile file". If stderr is available,
688 * it will tell you to which pid to attach the debugger; otherwise, use ps to
689 * find it. Attach to the process from the debugger, and, *PRESTO*, you are
690 * there!
692 * Simply assign "waitaround = 0" once you attach to the process, and then
693 * proceed from there as usual.
696 #ifdef WAITAROUND
697 int waitaround = 0; /* wait for rendezvous with the debugger */
698 #endif
700 #define BZIP "/usr/bin/bzip2"
701 #define GZIP "/usr/bin/gzip"
702 #define COMPRESS "/usr/bin/compress"
703 #define XZ "/usr/bin/xz"
704 #define BZCAT "/usr/bin/bzcat"
705 #define GZCAT "/usr/bin/gzcat"
706 #define ZCAT "/usr/bin/zcat"
707 #define XZCAT "/usr/bin/xzcat"
708 #define GSUF 8 /* number of valid 'gzip' sufixes */
709 #define BSUF 4 /* number of valid 'bzip2' sufixes */
710 #define XSUF 1 /* number of valid 'xz' suffixes */
712 static char *compress_opt; /* compression type */
714 static char *gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
715 ".tgz", ".taz"};
716 static char *bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
717 static char *xsuffix[] = {".xz"};
718 static char *suffix;
722 main(int argc, char *argv[])
724 char *cp;
725 char *tmpdirp;
726 pid_t thispid;
728 (void) setlocale(LC_ALL, "");
729 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
730 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
731 #endif
732 (void) textdomain(TEXT_DOMAIN);
733 if (argc < 2)
734 usage();
736 debug_output = should_enable_debug();
738 tfile = NULL;
739 if ((myname = strdup(argv[0])) == NULL) {
740 (void) fprintf(stderr, gettext(
741 "tar: cannot allocate program name\n"));
742 exit(1);
745 if (init_yes() < 0) {
746 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
747 strerror(errno));
748 exit(2);
752 * For XPG4 compatibility, we must be able to accept the "--"
753 * argument normally recognized by getopt; it is used to delimit
754 * the end opt the options section, and so can only appear in
755 * the position of the first argument. We simply skip it.
758 if (strcmp(argv[1], "--") == 0) {
759 argv++;
760 argc--;
761 if (argc < 3)
762 usage();
765 argv[argc] = NULL;
766 argv++;
769 * Set up default values.
770 * Search the operand string looking for the first digit or an 'f'.
771 * If you find a digit, use the 'archive#' entry in DEF_FILE.
772 * If 'f' is given, bypass looking in DEF_FILE altogether.
773 * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
775 if ((usefile = getenv("TAPE")) == (char *)NULL) {
776 for (cp = *argv; *cp; ++cp)
777 if (isdigit(*cp) || *cp == 'f')
778 break;
779 if (*cp != 'f') {
780 archive[7] = (*cp)? *cp: '0';
781 if (!(defaults_used = defset(archive))) {
782 usefile = NULL;
783 nblock = 1;
784 blocklim = 0;
785 NotTape = 0;
790 for (cp = *argv++; *cp; cp++)
791 switch (*cp) {
792 #ifdef WAITAROUND
793 case 'D':
794 /* rendezvous with the debugger */
795 waitaround = 1;
796 break;
797 #endif
798 case 'f':
799 assert_string(*argv, gettext(
800 "tar: tarfile must be specified with 'f' "
801 "function modifier\n"));
802 usefile = *argv++;
803 break;
804 case 'F':
805 Fflag++;
806 break;
807 case 'c':
808 cflag++;
809 rflag++;
810 update = 1;
811 break;
812 #if defined(O_XATTR)
813 case '@':
814 atflag++;
815 break;
816 #endif /* O_XATTR */
817 #if defined(_PC_SATTR_ENABLED)
818 case '/':
819 saflag++;
820 break;
821 #endif /* _PC_SATTR_ENABLED */
822 case 'u':
823 uflag++; /* moved code after signals caught */
824 rflag++;
825 update = 2;
826 break;
827 case 'r':
828 rflag++;
829 update = 2;
830 break;
831 case 'v':
832 vflag++;
833 break;
834 case 'w':
835 wflag++;
836 break;
837 case 'x':
838 xflag++;
839 break;
840 case 'X':
841 assert_string(*argv, gettext(
842 "tar: exclude file must be specified with 'X' "
843 "function modifier\n"));
844 Xflag = 1;
845 Xfile = *argv++;
846 build_table(exclude_tbl, Xfile);
847 break;
848 case 't':
849 tflag++;
850 break;
851 case 'm':
852 mflag++;
853 break;
854 case 'p':
855 pflag++;
856 break;
857 case 'D':
858 Dflag++;
859 break;
860 case '-':
861 /* ignore this silently */
862 break;
863 case '0': /* numeric entries used only for defaults */
864 case '1':
865 case '2':
866 case '3':
867 case '4':
868 case '5':
869 case '6':
870 case '7':
871 break;
872 case 'b':
873 assert_string(*argv, gettext(
874 "tar: blocking factor must be specified "
875 "with 'b' function modifier\n"));
876 bflag++;
877 nblock = bcheck(*argv++);
878 break;
879 case 'n': /* not a magtape (instead of 'k') */
880 NotTape++; /* assume non-magtape */
881 break;
882 case 'l':
883 linkerrok++;
884 break;
885 case 'e':
886 errflag++;
887 break;
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();
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();
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();
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();
956 if (cflag && *argv == NULL)
957 fatal(gettext("Missing filenames"));
958 if (usefile == NULL)
959 fatal(gettext("device argument required"));
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);
970 if ((xrec_ptr = malloc(xrec_size)) == NULL) {
971 (void) fprintf(stderr, gettext(
972 "tar: cannot allocate extended header buffer\n"));
973 exit(1);
976 #ifdef WAITAROUND
977 if (waitaround) {
978 (void) fprintf(stderr, gettext("Rendezvous with tar on pid"
979 " %d\n"), getpid());
981 while (waitaround) {
982 (void) sleep(10);
985 #endif
987 thispid = getpid();
988 (void) sprintf(pidchars, "%ld", thispid);
989 thispid = strlen(pidchars);
991 if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL)
992 (void) strcpy(xhdr_dirname, "/tmp");
993 else {
995 * Make sure that dir is no longer than what can
996 * fit in the prefix part of the header.
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);
1006 (void) strcat(xhdr_dirname, "/PaxHeaders.");
1007 (void) strcat(xhdr_dirname, pidchars);
1009 if (rflag) {
1010 if (cflag && usefile != NULL) {
1011 /* Set the compression type */
1012 if (aflag)
1013 detect_compress();
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);
1031 } else {
1033 * Decompress if the file is compressed for
1034 * an update or replace.
1036 if (strcmp(usefile, "-") != 0) {
1037 check_compression();
1038 if (compress_opt != NULL) {
1039 decompress_file();
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;
1056 tmpdir = getenv("TMPDIR");
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.
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";
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"));
1076 (void) strcpy(tname, tmpdir);
1077 (void) strcat(tname, tmp_suffix);
1079 if ((tnum = mkstemp(tname)) == -1)
1080 vperror(1, "%s", tname);
1081 if ((tfile = fdopen(tnum, "w")) == NULL)
1082 vperror(1, "%s", tname);
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);
1098 if (mt < 0) {
1099 if (cflag == 0 || (mt = creat(usefile, 0666))
1100 < 0)
1101 vperror(1, "%s", usefile);
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);
1111 if (rflag && !cflag && (mt_devtype == S_IFIFO))
1112 fatal(gettext("cannot append to pipe or FIFO."));
1114 if (Aflag && vflag)
1115 (void) printf(
1116 gettext("Suppressing absolute pathnames\n"));
1117 if (cflag && compress_opt != NULL)
1118 comp_pid = compress_file();
1119 dorep(argv);
1120 if (rflag && !cflag && (compress_opt != NULL))
1121 compress_back();
1122 } else if (xflag || tflag) {
1124 * for each argument, check to see if there is a "-I file" pair.
1125 * if so, move the 3rd argument into "-I"'s place, build_table()
1126 * using "file"'s name and increment argc one (the second
1127 * increment appears in the for loop) which removes the two
1128 * args "-I" and "file" from the argument vector.
1130 for (argc = 0; argv[argc]; argc++) {
1131 if (strcmp(argv[argc], "-I") == 0) {
1132 if (!argv[argc+1]) {
1133 (void) fprintf(stderr, gettext(
1134 "tar: missing argument for -I flag\n"));
1135 done(2);
1136 } else {
1137 Iflag = 1;
1138 argv[argc] = argv[argc+2];
1139 build_table(include_tbl, argv[++argc]);
1141 } else if (strcmp(argv[argc], "-C") == 0) {
1142 if (!argv[argc+1]) {
1143 (void) fprintf(stderr, gettext("tar: "
1144 "missing argument for -C flag\n"));
1145 done(2);
1146 } else if (xtract_chdir != NULL) {
1147 (void) fprintf(stderr, gettext("tar: "
1148 "extract should have only one -C "
1149 "flag\n"));
1150 done(2);
1151 } else {
1152 argv[argc] = argv[argc+2];
1153 xtract_chdir = argv[++argc];
1157 if (strcmp(usefile, "-") == 0) {
1158 mt = dup(0);
1159 ++bflag;
1160 /* try to recover from short reads when reading stdin */
1161 ++Bflag;
1162 } else if ((mt = open(usefile, 0)) < 0)
1163 vperror(1, "%s", usefile);
1165 /* Decompress if the file is compressed */
1167 if (strcmp(usefile, "-") != 0) {
1168 check_compression();
1169 if (compress_opt != NULL)
1170 comp_pid = uncompress_file();
1172 if (xflag) {
1173 if (xtract_chdir != NULL) {
1174 if (tar_chdir(xtract_chdir) < 0) {
1175 vperror(1, gettext("can't change "
1176 "directories to %s"), xtract_chdir);
1179 if (Aflag && vflag)
1180 (void) printf(gettext(
1181 "Suppressing absolute pathnames.\n"));
1183 doxtract(argv);
1184 } else if (tflag)
1185 dotable(argv);
1187 else
1188 usage();
1190 done(Errflg);
1192 /* Not reached: keep compiler quiet */
1193 return (1);
1196 static boolean_t
1197 should_enable_debug(void)
1199 const char *val;
1200 const char *truth[] = {
1201 "true",
1202 "1",
1203 "yes",
1204 "y",
1205 "please",
1206 NULL
1208 unsigned int i;
1210 if ((val = getenv("DEBUG_TAR")) == NULL) {
1211 return (B_FALSE);
1214 for (i = 0; truth[i] != NULL; i++) {
1215 if (strcmp(val, truth[i]) == 0) {
1216 return (B_TRUE);
1220 return (B_FALSE);
1223 /*PRINTFLIKE1*/
1224 static void
1225 dlog(const char *format, ...)
1227 va_list ap;
1229 if (!debug_output) {
1230 return;
1233 va_start(ap, format);
1234 (void) fprintf(stderr, "tar: DEBUG: ");
1235 (void) vfprintf(stderr, format, ap);
1236 va_end(ap);
1239 static void
1240 usage(void)
1242 (void) fprintf(stderr, gettext(
1243 #if defined(O_XATTR)
1244 #if defined(_PC_SATTR_ENABLED)
1245 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@/[0-7]][bf][X...] "
1246 #else
1247 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@[0-7]][bf][X...] "
1248 #endif /* _PC_SATTR_ENABLED */
1249 #else
1250 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw[0-7]][bf][X...] "
1251 #endif /* O_XATTR */
1252 "[j|J|z|Z] "
1253 "[blocksize] [tarfile] [size] [exclude-file...] "
1254 "{file | -I include-file | -C directory file}...\n"));
1255 done(1);
1259 * dorep - do "replacements"
1261 * Dorep is responsible for creating ('c'), appending ('r')
1262 * and updating ('u');
1265 static void
1266 dorep(char *argv[])
1268 char *cp, *cp2, *p;
1269 char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
1270 char file[PATH_MAX*2], origdir[PATH_MAX+1];
1271 FILE *fp = (FILE *)NULL;
1272 int archtype;
1273 int ret;
1276 if (!cflag) {
1277 xhdr_flgs = 0;
1278 getdir(); /* read header for next file */
1279 if (Xhdrflag > 0) {
1280 if (!Eflag)
1281 fatal(gettext("Archive contains extended"
1282 " header. -E flag required.\n"));
1283 ret = get_xdata(); /* Get extended header items */
1284 /* and regular header */
1285 } else {
1286 if (Eflag)
1287 fatal(gettext("Archive contains no extended"
1288 " header. -E flag not allowed.\n"));
1290 while (!endtape()) { /* changed from a do while */
1291 setbytes_to_skip(&stbuf, ret);
1292 passtape(); /* skip the file data */
1293 if (term)
1294 done(Errflg); /* received signal to stop */
1295 xhdr_flgs = 0;
1296 getdir();
1297 if (Xhdrflag > 0)
1298 ret = get_xdata();
1300 if (ret == 0) {
1301 if ((dblock.dbuf.typeflag != 'A') &&
1302 (xhdr_flgs != 0)) {
1303 load_info_from_xtarhdr(xhdr_flgs,
1304 &Xtarhdr);
1305 xhdr_flgs |= _X_XHDR;
1308 backtape(); /* was called by endtape */
1309 if (tfile != NULL) {
1311 * Buffer size is calculated to be the size of the
1312 * tmpdir string, plus 6 times the size of the tname
1313 * string, plus a value that is known to be greater
1314 * than the command pipeline string.
1316 int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
1317 char *buf;
1319 if ((buf = (char *)calloc(1, buflen)) == NULL) {
1320 vperror(1, gettext("tar: out of memory, "
1321 "cannot create sort command file\n"));
1324 (void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
1325 "sort +0 -1 +1nr %s -o %s; awk '$1 "
1326 "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1327 tmpdir, tname, tname, tname, tname, tname, tname);
1328 (void) fflush(tfile);
1329 (void) system(buf);
1330 free(buf);
1331 (void) freopen(tname, "r", tfile);
1332 (void) fstat(fileno(tfile), &stbuf);
1333 high = stbuf.st_size;
1337 dumping = 1;
1338 if (mulvol) { /* SP-1 */
1339 if (nblock && (blocklim%nblock) != 0)
1340 fatal(gettext(
1341 "Volume size not a multiple of block size."));
1342 blocklim -= 2; /* for trailer records */
1343 if (vflag)
1344 (void) fprintf(vfile, gettext("Volume ends at %"
1345 FMT_blkcnt_t "K, blocking factor = %dK\n"),
1346 K((blocklim - 1)), K(nblock));
1350 * Save the original directory before it gets
1351 * changed.
1353 if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
1354 vperror(0, gettext("A parent directory cannot be read"));
1355 exit(1);
1358 (void) strcpy(wdir, origdir);
1360 while ((*argv || fp) && !term) {
1361 if (fp || (strcmp(*argv, "-I") == 0)) {
1362 if (fp == NULL) {
1363 if (*++argv == NULL)
1364 fatal(gettext(
1365 "missing file name for -I flag."));
1366 else if ((fp = fopen(*argv++, "r")) == NULL)
1367 vperror(0, "%s", argv[-1]);
1368 continue;
1369 } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
1370 (void) fclose(fp);
1371 fp = NULL;
1372 continue;
1373 } else {
1374 cp = cp2 = file;
1375 if ((p = strchr(cp2, '\n')))
1376 *p = 0;
1378 } else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
1379 if (tar_chdir(*++argv) < 0)
1380 vperror(0, gettext(
1381 "can't change directories to %s"), *argv);
1382 else
1383 (void) getcwd(wdir, (sizeof (wdir)));
1384 argv++;
1385 continue;
1386 } else
1387 cp = cp2 = strcpy(file, *argv++);
1390 * point cp2 to the last '/' in file, but not
1391 * to a trailing '/'
1393 for (; *cp; cp++) {
1394 if (*cp == '/') {
1395 while (*(cp+1) == '/') {
1396 ++cp;
1398 if (*(cp+1) != '\0') {
1399 /* not trailing slash */
1400 cp2 = cp;
1404 if (cp2 != file) {
1405 *cp2 = '\0';
1406 if (tar_chdir(file) < 0) {
1407 vperror(0, gettext(
1408 "can't change directories to %s"), file);
1409 continue;
1411 *cp2 = '/';
1412 cp2++;
1415 parent = getcwd(tempdir, (sizeof (tempdir)));
1417 archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
1418 LEV0, SYMLINK_LEV0);
1420 #if defined(O_XATTR)
1421 if (!exitflag) {
1422 if ((atflag || saflag) &&
1423 (archtype == PUT_NOTAS_LINK)) {
1424 xattrs_put(file, cp2, parent, NULL);
1427 #endif
1429 if (tar_chdir(origdir) < 0)
1430 vperror(0, gettext("cannot change back?: %s"), origdir);
1432 if (exitflag) {
1434 * If e function modifier has been specified
1435 * write the files (that are listed before the
1436 * file causing the error) to tape. exitflag is
1437 * used because only some of the error conditions
1438 * in putfile() recognize the e function modifier.
1440 break;
1444 putempty((blkcnt_t)2);
1445 flushtape();
1446 closevol(); /* SP-1 */
1447 if (linkerrok == 1)
1448 for (; ihead != NULL; ihead = ihead->nextp) {
1449 if (ihead->count == 0)
1450 continue;
1451 (void) fprintf(stderr, gettext(
1452 "tar: missing links to %s\n"), ihead->pathname);
1453 if (errflag)
1454 done(1);
1455 else
1456 Errflg = 1;
1462 * endtape - check for tape at end
1464 * endtape checks the entry in dblock.dbuf to see if its the
1465 * special EOT entry. Endtape is usually called after getdir().
1467 * endtape used to call backtape; it no longer does, he who
1468 * wants it backed up must call backtape himself
1469 * RETURNS: 0 if not EOT, tape position unaffected
1470 * 1 if EOT, tape position unaffected
1473 static boolean_t
1474 endtape(void)
1476 if (dblock.dbuf.name[0] != '\0') {
1478 * The name field is populated.
1480 return (B_FALSE);
1483 if (is_posix && dblock.dbuf.prefix[0] != '\0') {
1485 * This is a ustar/POSIX archive, and although the name
1486 * field is empty the prefix field is not.
1488 return (B_FALSE);
1491 dlog("endtape(): found null header; EOT\n");
1492 return (B_TRUE);
1496 * getdir - get directory entry from tar tape
1498 * getdir reads the next tarblock off the tape and cracks
1499 * it as a directory. The checksum must match properly.
1501 * If tfile is non-null getdir writes the file name and mod date
1502 * to tfile.
1505 static void
1506 getdir(void)
1508 struct stat *sp;
1509 #ifdef EUC
1510 static int warn_chksum_sign = 0;
1511 #endif /* EUC */
1513 top:
1514 readtape((char *)&dblock);
1515 if (dblock.dbuf.name[0] == '\0')
1516 return;
1517 sp = &stbuf;
1518 (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
1519 (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
1520 (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
1521 (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
1522 (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
1523 (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
1524 (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
1525 (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
1527 is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
1529 sp->st_mode = Gen.g_mode;
1530 if (is_posix && (sp->st_mode & S_IFMT) == 0) {
1531 switch (dblock.dbuf.typeflag) {
1532 case '0':
1533 case 0:
1534 case _XATTR_HDRTYPE:
1535 sp->st_mode |= S_IFREG;
1536 break;
1537 case '1': /* hard link */
1538 break;
1539 case '2':
1540 sp->st_mode |= S_IFLNK;
1541 break;
1542 case '3':
1543 sp->st_mode |= S_IFCHR;
1544 break;
1545 case '4':
1546 sp->st_mode |= S_IFBLK;
1547 break;
1548 case '5':
1549 sp->st_mode |= S_IFDIR;
1550 break;
1551 case '6':
1552 sp->st_mode |= S_IFIFO;
1553 break;
1554 default:
1555 if (convtoreg(Gen.g_filesz))
1556 sp->st_mode |= S_IFREG;
1557 break;
1561 if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
1562 Xhdrflag = 1; /* Currently processing extended header */
1563 } else {
1564 Xhdrflag = 0;
1567 sp->st_uid = Gen.g_uid;
1568 sp->st_gid = Gen.g_gid;
1569 sp->st_size = Gen.g_filesz;
1570 sp->st_mtime = Gen.g_mtime;
1571 chksum = Gen.g_cksum;
1573 if (dblock.dbuf.extno != '\0') { /* split file? */
1574 extno = dblock.dbuf.extno;
1575 extsize = Gen.g_filesz;
1576 extotal = dblock.dbuf.extotal;
1577 } else {
1578 extno = 0; /* tell others file not split */
1579 extsize = 0;
1580 extotal = 0;
1583 #ifdef EUC
1584 if (chksum != checksum(&dblock)) {
1585 if (chksum != checksum_signed(&dblock)) {
1586 (void) fprintf(stderr, gettext(
1587 "tar: directory checksum error\n"));
1588 if (iflag) {
1589 Errflg = 2;
1590 goto top;
1592 done(2);
1593 } else {
1594 if (! warn_chksum_sign) {
1595 warn_chksum_sign = 1;
1596 (void) fprintf(stderr, gettext(
1597 "tar: warning: tar file made with signed checksum\n"));
1601 #else
1602 if (chksum != checksum(&dblock)) {
1603 (void) fprintf(stderr, gettext(
1604 "tar: directory checksum error\n"));
1605 if (iflag) {
1606 Errflg = 2;
1607 goto top;
1609 done(2);
1611 #endif /* EUC */
1612 if (tfile != NULL && Xhdrflag == 0) {
1614 * If an extended header is present, then time is available
1615 * in nanoseconds in the extended header data, so set it.
1616 * Otherwise, give an invalid value so that checkupdate will
1617 * not test beyond seconds.
1619 if ((xhdr_flgs & _X_MTIME))
1620 sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
1621 else
1622 sp->st_mtim.tv_nsec = -1;
1624 if (xhdr_flgs & _X_PATH)
1625 (void) fprintf(tfile, "%s %10ld.%9.9ld\n",
1626 Xtarhdr.x_path, sp->st_mtim.tv_sec,
1627 sp->st_mtim.tv_nsec);
1628 else
1629 (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
1630 NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
1631 sp->st_mtim.tv_nsec);
1634 #if defined(O_XATTR)
1635 Hiddendir = 0;
1636 if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
1637 if (xattrbadhead) {
1638 free(xattrhead);
1639 xattrp = NULL;
1640 xattr_linkp = NULL;
1641 xattrhead = NULL;
1642 } else {
1643 char *aname = basename(xattrapath);
1644 size_t xindex = aname - xattrapath;
1646 if (xattrapath[xindex] == '.' &&
1647 xattrapath[xindex + 1] == '\0' &&
1648 xattrp->h_typeflag == '5') {
1649 Hiddendir = 1;
1650 sp->st_mode =
1651 (S_IFDIR | (sp->st_mode & POSIXMODES));
1653 dblock.dbuf.typeflag = xattrp->h_typeflag;
1656 #endif
1661 * passtape - skip over a file on the tape
1663 * passtape skips over the next data file on the tape.
1664 * The tape directory entry must be in dblock.dbuf. This
1665 * routine just eats the number of blocks computed from the
1666 * directory size entry; the tape must be (logically) positioned
1667 * right after the directory info.
1670 static void
1671 passtape(void)
1673 blkcnt_t blocks;
1674 char buf[TBLOCK];
1677 * Print some debugging information about the directory entry
1678 * we are skipping over:
1680 dlog("passtape: typeflag \"%c\"\n", dblock.dbuf.typeflag);
1681 if (dblock.dbuf.name[0] != '\0') {
1682 dlog("passtape: name \"%s\"\n", dblock.dbuf.name);
1684 if (is_posix && dblock.dbuf.prefix[0] != '\0') {
1685 dlog("passtape: prefix \"%s\"\n", dblock.dbuf.prefix);
1689 * Types link(1), sym-link(2), char special(3), blk special(4),
1690 * directory(5), and FIFO(6) do not have data blocks associated
1691 * with them so just skip reading the data block.
1693 if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
1694 dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
1695 dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
1696 return;
1697 blocks = TBLOCKS(stbuf.st_size);
1699 dlog("passtape: block count %" FMT_blkcnt_t "\n", blocks);
1701 /* if operating on disk, seek instead of reading */
1702 if (NotTape)
1703 seekdisk(blocks);
1704 else
1705 while (blocks-- > 0)
1706 readtape(buf);
1709 #if defined(O_XATTR)
1710 static int
1711 is_sysattr(char *name)
1713 return ((strcmp(name, VIEW_READONLY) == 0) ||
1714 (strcmp(name, VIEW_READWRITE) == 0));
1716 #endif
1718 #if defined(O_XATTR)
1720 * Verify the attribute, attrname, is an attribute we want to restore.
1721 * Never restore read-only system attribute files. Only restore read-write
1722 * system attributes files when -/ was specified, and only traverse into
1723 * the 2nd level attribute directory containing only system attributes if
1724 * -@ was specified. This keeps us from archiving
1725 * <attribute name>/<read-write system attribute file>
1726 * when -/ was specified without -@.
1728 * attrname - attribute file name
1729 * attrparent - attribute's parent name within the base file's attribute
1730 * directory hierarchy
1732 static attr_status_t
1733 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
1734 int *rw_sysattr)
1736 #if defined(_PC_SATTR_ENABLED)
1737 int attr_supported;
1739 /* Never restore read-only system attribute files */
1740 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
1741 *rw_sysattr = 0;
1742 return (ATTR_SKIP);
1743 } else {
1744 *rw_sysattr = (attr_supported == _RW_SATTR);
1746 #else
1748 * Only need to check if this attribute is an extended system
1749 * attribute.
1751 if (*rw_sysattr = is_sysattr(attrname)) {
1752 return (ATTR_SKIP);
1753 } else {
1754 return (ATTR_OK);
1756 #endif /* _PC_SATTR_ENABLED */
1759 * If the extended system attribute file is specified with the
1760 * arc_rwsysattr flag, as being transient (default extended
1761 * attributes), then don't archive it.
1763 if (*rw_sysattr && !arc_rwsysattr) {
1764 return (ATTR_SKIP);
1768 * Only restore read-write system attribute files
1769 * when -/ was specified. Only restore extended
1770 * attributes when -@ was specified.
1772 if (atflag) {
1773 if (!saflag) {
1775 * Only archive/restore the hidden directory "." if
1776 * we're processing the top level hidden attribute
1777 * directory. We don't want to process the
1778 * hidden attribute directory of the attribute
1779 * directory that contains only extended system
1780 * attributes.
1782 if (*rw_sysattr || (Hiddendir &&
1783 (attrparent != NULL))) {
1784 return (ATTR_SKIP);
1787 } else if (saflag) {
1789 * Only archive/restore read-write extended system attribute
1790 * files of the base file.
1792 if (!*rw_sysattr || (attrparent != NULL)) {
1793 return (ATTR_SKIP);
1795 } else {
1796 return (ATTR_SKIP);
1799 return (ATTR_OK);
1801 #endif
1803 static void
1804 free_children(file_list_t *children)
1806 file_list_t *child = children;
1807 file_list_t *cptr;
1809 while (child != NULL) {
1810 cptr = child->next;
1811 if (child->name != NULL) {
1812 free(child->name);
1814 child = cptr;
1818 static int
1819 putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
1820 int filetype, int lev, int symlink_lev)
1822 int infile = -1; /* deliberately invalid */
1823 blkcnt_t blocks;
1824 char buf[PATH_MAX + 2]; /* Add trailing slash and null */
1825 char *bigbuf;
1826 int maxread;
1827 int hint; /* amount to write to get "in sync" */
1828 char filetmp[PATH_MAX + 1];
1829 char *cp;
1830 char *name;
1831 char *attrparent = NULL;
1832 char *longattrname = NULL;
1833 file_list_t *child = NULL;
1834 file_list_t *child_end = NULL;
1835 file_list_t *cptr;
1836 struct dirent *dp;
1837 DIR *dirp;
1838 int i;
1839 int split;
1840 int dirfd = -1;
1841 int rc = PUT_NOTAS_LINK;
1842 int archtype = 0;
1843 int rw_sysattr = 0;
1844 char newparent[PATH_MAX + MAXNAMLEN + 1];
1845 char *prefix = "";
1846 char *tmpbuf;
1847 char goodbuf[PRESIZ + 2];
1848 char junkbuf[MAXNAM+1];
1849 char *lastslash;
1850 int j;
1851 struct stat sbuf;
1852 int readlink_max;
1854 (void) memset(goodbuf, '\0', sizeof (goodbuf));
1855 (void) memset(junkbuf, '\0', sizeof (junkbuf));
1857 xhdr_flgs = 0;
1859 if (filetype == XATTR_FILE) {
1860 attrparent = attrinfo->attr_parent;
1861 longattrname = attrinfo->attr_path;
1862 dirfd = attrinfo->attr_parentfd;
1863 rw_sysattr = attrinfo->attr_rw_sysattr;
1864 } else {
1865 dirfd = open(".", O_RDONLY);
1868 if (dirfd == -1) {
1869 (void) fprintf(stderr, gettext(
1870 "tar: unable to open%sdirectory %s%s%s%s\n"),
1871 (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
1872 (attrparent == NULL) ? "" : gettext("of attribute "),
1873 (attrparent == NULL) ? "" : attrparent,
1874 (attrparent == NULL) ? "" : gettext(" of "),
1875 (filetype == XATTR_FILE) ? longname : parent);
1876 goto out;
1879 if (lev > MAXLEV) {
1880 (void) fprintf(stderr,
1881 gettext("tar: directory nesting too deep, %s not dumped\n"),
1882 longname);
1883 goto out;
1886 if (getstat(dirfd, longname, shortname, attrparent))
1887 goto out;
1889 if (hflag) {
1891 * Catch nesting where a file is a symlink to its directory.
1893 j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
1894 if (S_ISLNK(sbuf.st_mode)) {
1895 if (symlink_lev++ >= MAXSYMLINKS) {
1896 (void) fprintf(stderr, gettext(
1897 "tar: %s: Number of symbolic links "
1898 "encountered during path name traversal "
1899 "exceeds MAXSYMLINKS\n"), longname);
1900 Errflg = 1;
1901 goto out;
1907 * Check if the input file is the same as the tar file we
1908 * are creating
1910 if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
1911 (void) fprintf(stderr, gettext(
1912 "tar: %s%s%s%s%s same as archive file\n"),
1913 rw_sysattr ? gettext("system ") : "",
1914 (longattrname == NULL) ? "" : gettext("attribute "),
1915 (longattrname == NULL) ? "" : longattrname,
1916 (longattrname == NULL) ? "" : gettext(" of "),
1917 longname);
1918 Errflg = 1;
1919 goto out;
1922 * Check size limit - we can't archive files that
1923 * exceed TAR_OFFSET_MAX bytes because of header
1924 * limitations. Exclude file types that set
1925 * st_size to zero below because they take no
1926 * archive space to represent contents.
1928 if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
1929 !S_ISDIR(stbuf.st_mode) &&
1930 !S_ISCHR(stbuf.st_mode) &&
1931 !S_ISBLK(stbuf.st_mode) &&
1932 (Eflag == 0)) {
1933 (void) fprintf(stderr, gettext(
1934 "tar: %s%s%s%s%s too large to archive. "
1935 "Use E function modifier.\n"),
1936 rw_sysattr ? gettext("system ") : "",
1937 (longattrname == NULL) ? "" : gettext("attribute "),
1938 (longattrname == NULL) ? "" : longattrname,
1939 (longattrname == NULL) ? "" : gettext(" of "),
1940 longname);
1941 if (errflag)
1942 exitflag = 1;
1943 Errflg = 1;
1944 goto out;
1947 if (tfile != NULL && checkupdate(longname) == 0) {
1948 goto out;
1950 if (checkw('r', longname) == 0) {
1951 goto out;
1954 if (Fflag &&
1955 checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
1956 goto out;
1958 if (Xflag) {
1959 if (is_in_table(exclude_tbl, longname)) {
1960 if (vflag) {
1961 (void) fprintf(vfile, gettext(
1962 "a %s excluded\n"), longname);
1964 goto out;
1969 * If the length of the fullname is greater than MAXNAM,
1970 * print out a message and return (unless extended headers are used,
1971 * in which case fullname is limited to PATH_MAX).
1974 if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
1975 (split > PATH_MAX)) {
1976 (void) fprintf(stderr, gettext(
1977 "tar: %s: file name too long\n"), longname);
1978 if (errflag)
1979 exitflag = 1;
1980 Errflg = 1;
1981 goto out;
1985 * We split the fullname into prefix and name components if any one
1986 * of three conditions holds:
1987 * -- the length of the fullname exceeds NAMSIZ,
1988 * -- the length of the fullname equals NAMSIZ, and the shortname
1989 * is less than NAMSIZ, (splitting in this case preserves
1990 * compatibility with 5.6 and 5.5.1 tar), or
1991 * -- the length of the fullname equals NAMSIZ, the file is a
1992 * directory and we are not in POSIX-conformant mode (where
1993 * trailing slashes are removed from directories).
1995 if ((split > NAMSIZ) ||
1996 (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1997 (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
1999 * Since path is limited to PRESIZ characters, look for the
2000 * last slash within PRESIZ + 1 characters only.
2002 (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
2003 tmpbuf = goodbuf;
2004 lastslash = strrchr(tmpbuf, '/');
2005 if (lastslash == NULL) {
2006 i = split; /* Length of name */
2007 j = 0; /* Length of prefix */
2008 goodbuf[0] = '\0';
2009 } else {
2010 *lastslash = '\0'; /* Terminate the prefix */
2011 j = strlen(tmpbuf);
2012 i = split - j - 1;
2015 * If the filename is greater than NAMSIZ we can't
2016 * archive the file unless we are using extended headers.
2018 if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
2019 !Pflag)) {
2020 /* Determine which (filename or path) is too long. */
2021 lastslash = strrchr(longname, '/');
2022 if (lastslash != NULL)
2023 i = strlen(lastslash + 1);
2024 if (Eflag > 0) {
2025 xhdr_flgs |= _X_PATH;
2026 Xtarhdr.x_path = longname;
2027 if (i <= NAMSIZ)
2028 (void) strcpy(junkbuf, lastslash + 1);
2029 else
2030 (void) sprintf(junkbuf, "%llu",
2031 xhdr_count + 1);
2032 if (split - i - 1 > PRESIZ)
2033 (void) strcpy(goodbuf, xhdr_dirname);
2034 } else {
2035 if ((i > NAMSIZ) || (i == NAMSIZ &&
2036 S_ISDIR(stbuf.st_mode) && !Pflag))
2037 (void) fprintf(stderr, gettext(
2038 "tar: %s: filename is greater than "
2039 "%d\n"), lastslash == NULL ?
2040 longname : lastslash + 1, NAMSIZ);
2041 else
2042 (void) fprintf(stderr, gettext(
2043 "tar: %s: prefix is greater than %d"
2044 "\n"), longname, PRESIZ);
2045 if (errflag)
2046 exitflag = 1;
2047 Errflg = 1;
2048 goto out;
2050 } else
2051 (void) strncpy(&junkbuf[0], longname + j + 1,
2052 strlen(longname + j + 1));
2053 name = junkbuf;
2054 prefix = goodbuf;
2055 } else {
2056 name = longname;
2058 if (Aflag) {
2059 if ((prefix != NULL) && (*prefix != '\0'))
2060 while (*prefix == '/')
2061 ++prefix;
2062 else
2063 while (*name == '/')
2064 ++name;
2067 switch (stbuf.st_mode & S_IFMT) {
2068 case S_IFDIR:
2069 stbuf.st_size = (off_t)0;
2070 blocks = TBLOCKS(stbuf.st_size);
2072 if (filetype != XATTR_FILE && Hiddendir == 0) {
2073 i = 0;
2074 cp = buf;
2075 while ((*cp++ = longname[i++]))
2077 *--cp = '/';
2078 *++cp = 0;
2080 if (!oflag) {
2081 tomodes(&stbuf);
2082 if (build_dblock(name, tchar, '5', filetype,
2083 &stbuf, stbuf.st_dev, prefix) != 0) {
2084 goto out;
2086 if (!Pflag) {
2088 * Old archives require a slash at the end
2089 * of a directory name.
2091 * XXX
2092 * If directory name is too long, will
2093 * slash overfill field?
2095 if (strlen(name) > (unsigned)NAMSIZ-1) {
2096 (void) fprintf(stderr, gettext(
2097 "tar: %s: filename is greater "
2098 "than %d\n"), name, NAMSIZ);
2099 if (errflag)
2100 exitflag = 1;
2101 Errflg = 1;
2102 goto out;
2103 } else {
2104 if (strlen(name) == (NAMSIZ - 1)) {
2105 (void) memcpy(dblock.dbuf.name,
2106 name, NAMSIZ);
2107 dblock.dbuf.name[NAMSIZ-1]
2108 = '/';
2109 } else
2110 (void) sprintf(dblock.dbuf.name,
2111 "%s/", name);
2114 * need to recalculate checksum
2115 * because the name changed.
2117 (void) sprintf(dblock.dbuf.chksum,
2118 "%07o", checksum(&dblock));
2122 if (put_extra_attributes(longname, shortname,
2123 longattrname, prefix, filetype, '5') != 0)
2124 goto out;
2126 #if defined(O_XATTR)
2128 * Reset header typeflag when archiving directory, since
2129 * build_dblock changed it on us.
2131 if (filetype == XATTR_FILE) {
2132 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2133 } else {
2134 dblock.dbuf.typeflag = '5';
2136 #else
2137 dblock.dbuf.typeflag = '5';
2138 #endif
2140 (void) sprintf(dblock.dbuf.chksum, "%07o",
2141 checksum(&dblock));
2143 (void) writetbuf((char *)&dblock, 1);
2145 if (vflag) {
2146 if (NotTape) {
2147 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2149 if (filetype == XATTR_FILE && Hiddendir) {
2150 (void) fprintf(vfile,
2151 gettext("a %s attribute %s "),
2152 longname, longattrname);
2154 } else {
2155 (void) fprintf(vfile, "a %s/ ", longname);
2157 if (NotTape) {
2158 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2159 K(blocks));
2160 } else {
2161 (void) fprintf(vfile, gettext("%" FMT_blkcnt_t
2162 " tape blocks\n"), blocks);
2167 * If hidden dir then break now since xattrs_put() will do
2168 * the iterating of the directory.
2170 * At the moment, there can only be system attributes on
2171 * attributes. There can be no attributes on attributes or
2172 * directories within the attributes hidden directory hierarchy.
2174 if (filetype == XATTR_FILE)
2175 break;
2177 if (*shortname != '/')
2178 (void) sprintf(newparent, "%s/%s", parent, shortname);
2179 else
2180 (void) sprintf(newparent, "%s", shortname);
2182 if (tar_chdir(shortname) < 0) {
2183 vperror(0, "%s", newparent);
2184 goto out;
2187 if ((dirp = opendir(".")) == NULL) {
2188 vperror(0, gettext(
2189 "can't open directory %s"), longname);
2190 if (tar_chdir(parent) < 0)
2191 vperror(0, gettext("cannot change back?: %s"),
2192 parent);
2193 goto out;
2197 * Create a list of files (children) in this directory to avoid
2198 * having to perform telldir()/seekdir().
2200 while ((dp = readdir(dirp)) != NULL && !term) {
2201 if ((strcmp(".", dp->d_name) == 0) ||
2202 (strcmp("..", dp->d_name) == 0))
2203 continue;
2204 if (((cptr = (file_list_t *)calloc(sizeof (char),
2205 sizeof (file_list_t))) == NULL) ||
2206 ((cptr->name = strdup(dp->d_name)) == NULL)) {
2207 vperror(1, gettext(
2208 "Insufficient memory for directory "
2209 "list entry %s/%s\n"),
2210 newparent, dp->d_name);
2213 /* Add the file to the list */
2214 if (child == NULL) {
2215 child = cptr;
2216 } else {
2217 child_end->next = cptr;
2219 child_end = cptr;
2221 (void) closedir(dirp);
2224 * Archive each of the files in the current directory.
2225 * If a file is a directory, putfile() is called
2226 * recursively to archive the file hierarchy of the
2227 * directory before archiving the next file in the
2228 * current directory.
2230 while ((child != NULL) && !term) {
2231 (void) strcpy(cp, child->name);
2232 archtype = putfile(buf, cp, newparent, NULL,
2233 NORMAL_FILE, lev + 1, symlink_lev);
2235 if (!exitflag) {
2236 if ((atflag || saflag) &&
2237 (archtype == PUT_NOTAS_LINK)) {
2238 xattrs_put(buf, cp, newparent, NULL);
2241 if (exitflag)
2242 break;
2244 /* Free each child as we are done processing it. */
2245 cptr = child;
2246 child = child->next;
2247 free(cptr->name);
2248 free(cptr);
2250 if ((child != NULL) && !term) {
2251 free_children(child);
2254 if (tar_chdir(parent) < 0) {
2255 vperror(0, gettext("cannot change back?: %s"), parent);
2258 break;
2260 case S_IFLNK:
2261 readlink_max = NAMSIZ;
2262 if (stbuf.st_size > NAMSIZ) {
2263 if (Eflag > 0) {
2264 xhdr_flgs |= _X_LINKPATH;
2265 readlink_max = PATH_MAX;
2266 } else {
2267 (void) fprintf(stderr, gettext(
2268 "tar: %s: symbolic link too long\n"),
2269 longname);
2270 if (errflag)
2271 exitflag = 1;
2272 Errflg = 1;
2273 goto out;
2277 * Sym-links need header size of zero since you
2278 * don't store any data for this type.
2280 stbuf.st_size = (off_t)0;
2281 tomodes(&stbuf);
2282 i = readlink(shortname, filetmp, readlink_max);
2283 if (i < 0) {
2284 vperror(0, gettext(
2285 "can't read symbolic link %s"), longname);
2286 goto out;
2287 } else {
2288 filetmp[i] = 0;
2290 if (vflag)
2291 (void) fprintf(vfile, gettext(
2292 "a %s symbolic link to %s\n"),
2293 longname, filetmp);
2294 if (xhdr_flgs & _X_LINKPATH) {
2295 Xtarhdr.x_linkpath = filetmp;
2296 if (build_dblock(name, tchar, '2', filetype, &stbuf,
2297 stbuf.st_dev, prefix) != 0)
2298 goto out;
2299 } else
2300 if (build_dblock(name, filetmp, '2', filetype, &stbuf,
2301 stbuf.st_dev, prefix) != 0)
2302 goto out;
2303 (void) writetbuf((char *)&dblock, 1);
2305 * No acls for symlinks: mode is always 777
2306 * dont call write ancillary
2308 rc = PUT_AS_LINK;
2309 break;
2310 case S_IFREG:
2311 if ((infile = openat(dirfd, shortname, 0)) < 0) {
2312 vperror(0, gettext("unable to open %s%s%s%s"), longname,
2313 rw_sysattr ? gettext(" system") : "",
2314 (filetype == XATTR_FILE) ?
2315 gettext(" attribute ") : "",
2316 (filetype == XATTR_FILE) ? (longattrname == NULL) ?
2317 shortname : longattrname : "");
2318 goto out;
2321 blocks = TBLOCKS(stbuf.st_size);
2323 if (put_link(name, longname, shortname, longattrname,
2324 prefix, filetype, '1') == 0) {
2325 (void) close(infile);
2326 rc = PUT_AS_LINK;
2327 goto out;
2330 tomodes(&stbuf);
2332 /* correctly handle end of volume */
2333 while (mulvol && tapepos + blocks + 1 > blocklim) {
2334 /* split if floppy has some room and file is large */
2335 if (((blocklim - tapepos) >= EXTMIN) &&
2336 ((blocks + 1) >= blocklim/10)) {
2337 splitfile(longname, infile,
2338 name, prefix, filetype);
2339 (void) close(dirfd);
2340 (void) close(infile);
2341 goto out;
2343 newvol(); /* not worth it--just get new volume */
2345 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2346 blocks);
2347 if (build_dblock(name, tchar, '0', filetype,
2348 &stbuf, stbuf.st_dev, prefix) != 0) {
2349 goto out;
2351 if (vflag) {
2352 if (NotTape) {
2353 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2355 (void) fprintf(vfile, "a %s%s%s%s ", longname,
2356 rw_sysattr ? gettext(" system") : "",
2357 (filetype == XATTR_FILE) ? gettext(
2358 " attribute ") : "",
2359 (filetype == XATTR_FILE) ?
2360 longattrname : "");
2361 if (NotTape)
2362 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2363 K(blocks));
2364 else
2365 (void) fprintf(vfile,
2366 gettext("%" FMT_blkcnt_t " tape blocks\n"),
2367 blocks);
2370 if (put_extra_attributes(longname, shortname, longattrname,
2371 prefix, filetype, '0') != 0)
2372 goto out;
2375 * No need to reset typeflag for extended attribute here, since
2376 * put_extra_attributes already set it and we haven't called
2377 * build_dblock().
2379 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2380 hint = writetbuf((char *)&dblock, 1);
2381 maxread = max(min(stbuf.st_blksize, stbuf.st_size),
2382 (nblock * TBLOCK));
2383 if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
2384 maxread = TBLOCK;
2385 bigbuf = buf;
2388 while (((i = (int)
2389 read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
2390 blocks) {
2391 blkcnt_t nblks;
2393 nblks = ((i-1)/TBLOCK)+1;
2394 if (nblks > blocks)
2395 nblks = blocks;
2396 hint = writetbuf(bigbuf, nblks);
2397 blocks -= nblks;
2399 (void) close(infile);
2400 if (bigbuf != buf)
2401 free(bigbuf);
2402 if (i < 0)
2403 vperror(0, gettext("Read error on %s"), longname);
2404 else if (blocks != 0 || i != 0) {
2405 (void) fprintf(stderr, gettext(
2406 "tar: %s: file changed size\n"), longname);
2407 if (errflag) {
2408 exitflag = 1;
2409 Errflg = 1;
2410 } else if (!Dflag) {
2411 Errflg = 1;
2414 putempty(blocks);
2415 break;
2416 case S_IFIFO:
2417 blocks = TBLOCKS(stbuf.st_size);
2418 stbuf.st_size = (off_t)0;
2420 if (put_link(name, longname, shortname, longattrname,
2421 prefix, filetype, '6') == 0) {
2422 rc = PUT_AS_LINK;
2423 goto out;
2425 tomodes(&stbuf);
2427 while (mulvol && tapepos + blocks + 1 > blocklim) {
2428 if (((blocklim - tapepos) >= EXTMIN) &&
2429 ((blocks + 1) >= blocklim/10)) {
2430 splitfile(longname, infile, name,
2431 prefix, filetype);
2432 (void) close(dirfd);
2433 (void) close(infile);
2434 goto out;
2436 newvol();
2438 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2439 blocks);
2440 if (vflag) {
2441 if (NotTape) {
2442 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2444 (void) fprintf(vfile, gettext("a %s %"
2445 FMT_blkcnt_t "K\n "), longname, K(blocks));
2446 } else {
2447 (void) fprintf(vfile, gettext(
2448 "a %s %" FMT_blkcnt_t " tape blocks\n"),
2449 longname, blocks);
2452 if (build_dblock(name, tchar, '6', filetype,
2453 &stbuf, stbuf.st_dev, prefix) != 0)
2454 goto out;
2456 if (put_extra_attributes(longname, shortname, longattrname,
2457 prefix, filetype, '6') != 0)
2458 goto out;
2460 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2461 dblock.dbuf.typeflag = '6';
2463 (void) writetbuf((char *)&dblock, 1);
2464 break;
2465 case S_IFCHR:
2466 stbuf.st_size = (off_t)0;
2467 blocks = TBLOCKS(stbuf.st_size);
2468 if (put_link(name, longname, shortname, longattrname,
2469 prefix, filetype, '3') == 0) {
2470 rc = PUT_AS_LINK;
2471 goto out;
2473 tomodes(&stbuf);
2475 while (mulvol && tapepos + blocks + 1 > blocklim) {
2476 if (((blocklim - tapepos) >= EXTMIN) &&
2477 ((blocks + 1) >= blocklim/10)) {
2478 splitfile(longname, infile, name,
2479 prefix, filetype);
2480 (void) close(dirfd);
2481 goto out;
2483 newvol();
2485 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2486 blocks);
2487 if (vflag) {
2488 if (NotTape) {
2489 dlog("seek = %" FMT_blkcnt_t "K\t", K(tapepos));
2491 (void) fprintf(vfile, gettext("a %s %"
2492 FMT_blkcnt_t "K\n"), longname, K(blocks));
2493 } else {
2494 (void) fprintf(vfile, gettext("a %s %"
2495 FMT_blkcnt_t " tape blocks\n"), longname,
2496 blocks);
2499 if (build_dblock(name, tchar, '3',
2500 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2501 goto out;
2503 if (put_extra_attributes(longname, shortname, longattrname,
2504 prefix, filetype, '3') != 0)
2505 goto out;
2507 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2508 dblock.dbuf.typeflag = '3';
2510 (void) writetbuf((char *)&dblock, 1);
2511 break;
2512 case S_IFBLK:
2513 stbuf.st_size = (off_t)0;
2514 blocks = TBLOCKS(stbuf.st_size);
2515 if (put_link(name, longname, shortname, longattrname,
2516 prefix, filetype, '4') == 0) {
2517 rc = PUT_AS_LINK;
2518 goto out;
2520 tomodes(&stbuf);
2522 while (mulvol && tapepos + blocks + 1 > blocklim) {
2523 if (((blocklim - tapepos) >= EXTMIN) &&
2524 ((blocks + 1) >= blocklim/10)) {
2525 splitfile(longname, infile,
2526 name, prefix, filetype);
2527 (void) close(dirfd);
2528 goto out;
2530 newvol();
2532 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2533 blocks);
2534 if (vflag) {
2535 if (NotTape) {
2536 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2539 (void) fprintf(vfile, "a %s ", longname);
2540 if (NotTape)
2541 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2542 K(blocks));
2543 else
2544 (void) fprintf(vfile, gettext("%"
2545 FMT_blkcnt_t " tape blocks\n"), blocks);
2547 if (build_dblock(name, tchar, '4',
2548 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2549 goto out;
2551 if (put_extra_attributes(longname, shortname, longattrname,
2552 prefix, filetype, '4') != 0)
2553 goto out;
2555 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2556 dblock.dbuf.typeflag = '4';
2558 (void) writetbuf((char *)&dblock, 1);
2559 break;
2560 default:
2561 (void) fprintf(stderr, gettext(
2562 "tar: %s is not a file. Not dumped\n"), longname);
2563 if (errflag)
2564 exitflag = 1;
2565 Errflg = 1;
2566 goto out;
2569 out:
2570 if ((dirfd != -1) && (filetype != XATTR_FILE)) {
2571 (void) close(dirfd);
2573 return (rc);
2578 * splitfile dump a large file across volumes
2580 * splitfile(longname, fd);
2581 * char *longname; full name of file
2582 * int ifd; input file descriptor
2584 * NOTE: only called by putfile() to dump a large file.
2587 static void
2588 splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
2590 blkcnt_t blocks;
2591 off_t bytes, s;
2592 char buf[TBLOCK];
2593 int i, extents;
2595 blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */
2598 * # extents =
2599 * size of file after using up rest of this floppy
2600 * blocks - (blocklim - tapepos) + 1 (for header)
2601 * plus roundup value before divide by blocklim-1
2602 * + (blocklim - 1) - 1
2603 * all divided by blocklim-1 (one block for each header).
2604 * this gives
2605 * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2606 * which reduces to the expression used.
2607 * one is added to account for this first extent.
2609 * When one is dealing with extremely large archives, one may want
2610 * to allow for a large number of extents. This code should be
2611 * revisited to determine if extents should be changed to something
2612 * larger than an int.
2614 extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
2616 if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */
2617 (void) fprintf(stderr, gettext(
2618 "tar: %s needs unusual number of volumes to split\n"
2619 "tar: %s not dumped\n"), longname, longname);
2620 return;
2622 if (build_dblock(name, tchar, '0', filetype,
2623 &stbuf, stbuf.st_dev, prefix) != 0)
2624 return;
2626 dblock.dbuf.extotal = extents;
2627 bytes = stbuf.st_size;
2630 * The value contained in dblock.dbuf.efsize was formerly used when the
2631 * v flag was specified in conjunction with the t flag. Although it is
2632 * no longer used, older versions of tar will expect the former
2633 * behaviour, so we must continue to write it to the archive.
2635 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2636 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2637 * store 0.
2639 if (bytes <= TAR_EFSIZE_MAX)
2640 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
2641 else
2642 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
2644 (void) fprintf(stderr, gettext(
2645 "tar: large file %s needs %d extents.\n"
2646 "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
2647 longname, extents, K(tapepos));
2649 s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
2650 for (i = 1; i <= extents; i++) {
2651 if (i > 1) {
2652 newvol();
2653 if (i == extents)
2654 s = bytes; /* last ext. gets true bytes */
2655 else
2656 s = (off_t)(blocklim - 1)*TBLOCK; /* all */
2658 bytes -= s;
2659 blocks = TBLOCKS(s);
2661 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
2662 dblock.dbuf.extno = i;
2663 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2664 (void) writetbuf((char *)&dblock, 1);
2666 if (vflag)
2667 (void) fprintf(vfile,
2668 gettext("+++ a %s %" FMT_blkcnt_t
2669 "K [extent #%d of %d]\n"),
2670 longname, K(blocks), i, extents);
2671 while (blocks && read(ifd, buf, TBLOCK) > 0) {
2672 blocks--;
2673 (void) writetbuf(buf, 1);
2675 if (blocks != 0) {
2676 (void) fprintf(stderr, gettext(
2677 "tar: %s: file changed size\n"), longname);
2678 (void) fprintf(stderr, gettext(
2679 "tar: aborting split file %s\n"), longname);
2680 (void) close(ifd);
2681 return;
2684 (void) close(ifd);
2685 if (vflag)
2686 (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
2687 "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
2688 extents);
2692 * convtoreg - determines whether the file should be converted to a
2693 * regular file when extracted
2695 * Returns 1 when file size > 0 and typeflag is not recognized
2696 * Otherwise returns 0
2698 static int
2699 convtoreg(off_t size)
2701 if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
2702 (dblock.dbuf.typeflag != NULL) && (dblock.dbuf.typeflag != '1') &&
2703 (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
2704 (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
2705 (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
2706 (dblock.dbuf.typeflag != 'L') &&
2707 (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
2708 (dblock.dbuf.typeflag != 'X')) {
2709 return (1);
2711 return (0);
2714 #if defined(O_XATTR)
2715 static int
2716 save_cwd(void)
2718 return (open(".", O_RDONLY));
2720 #endif
2722 #if defined(O_XATTR)
2723 static void
2724 rest_cwd(int *cwd)
2726 if (*cwd != -1) {
2727 if (fchdir(*cwd) < 0) {
2728 vperror(0, gettext(
2729 "Cannot fchdir to attribute directory"));
2730 exit(1);
2732 (void) close(*cwd);
2733 *cwd = -1;
2736 #endif
2739 * Verify the underlying file system supports the attribute type.
2740 * Only archive extended attribute files when '-@' was specified.
2741 * Only archive system extended attribute files if '-/' was specified.
2743 #if defined(O_XATTR)
2744 static attr_status_t
2745 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
2746 int *ext_attrflg)
2749 * Verify extended attributes are supported/exist. We only
2750 * need to check if we are processing a base file, not an
2751 * extended attribute.
2753 if (attrflg) {
2754 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
2755 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
2758 if (atflag) {
2759 if (!*ext_attrflg) {
2760 #if defined(_PC_SATTR_ENABLED)
2761 if (saflag) {
2762 /* Verify system attributes are supported */
2763 if (sysattr_support(filename,
2764 (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
2765 _PC_SATTR_ENABLED) != 1) {
2766 return (ATTR_SATTR_ERR);
2768 } else
2769 return (ATTR_XATTR_ERR);
2770 #else
2771 return (ATTR_XATTR_ERR);
2772 #endif /* _PC_SATTR_ENABLED */
2775 #if defined(_PC_SATTR_ENABLED)
2776 } else if (saflag) {
2777 /* Verify system attributes are supported */
2778 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
2779 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
2780 return (ATTR_SATTR_ERR);
2782 #endif /* _PC_SATTR_ENABLED */
2783 } else {
2784 return (ATTR_SKIP);
2787 return (ATTR_OK);
2789 #endif
2791 #if defined(O_XATTR)
2793 * Recursively open attribute directories until the attribute directory
2794 * containing the specified attribute, attrname, is opened.
2796 * Currently, only 2 directory levels of attributes are supported, (i.e.,
2797 * extended system attributes on extended attributes). The following are
2798 * the possible input combinations:
2799 * 1. Open the attribute directory of the base file (don't change
2800 * into it).
2801 * attrinfo->parent = NULL
2802 * attrname = '.'
2803 * 2. Open the attribute directory of the base file and change into it.
2804 * attrinfo->parent = NULL
2805 * attrname = <attr> | <sys_attr>
2806 * 3. Open the attribute directory of the base file, change into it,
2807 * then recursively call open_attr_dir() to open the attribute's
2808 * parent directory (don't change into it).
2809 * attrinfo->parent = <attr>
2810 * attrname = '.'
2811 * 4. Open the attribute directory of the base file, change into it,
2812 * then recursively call open_attr_dir() to open the attribute's
2813 * parent directory and change into it.
2814 * attrinfo->parent = <attr>
2815 * attrname = <attr> | <sys_attr>
2817 * An attribute directory will be opened only if the underlying file system
2818 * supports the attribute type, and if the command line specifications (atflag
2819 * and saflag) enable the processing of the attribute type.
2821 * On succesful return, attrinfo->parentfd will be the file descriptor of the
2822 * opened attribute directory. In addition, if the attribute is a read-write
2823 * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2824 * it will be set to 0.
2826 * Possible return values:
2827 * ATTR_OK Successfully opened and, if needed, changed into the
2828 * attribute directory containing attrname.
2829 * ATTR_SKIP The command line specifications don't enable the
2830 * processing of the attribute type.
2831 * ATTR_CHDIR_ERR An error occurred while trying to change into an
2832 * attribute directory.
2833 * ATTR_OPEN_ERR An error occurred while trying to open an
2834 * attribute directory.
2835 * ATTR_XATTR_ERR The underlying file system doesn't support extended
2836 * attributes.
2837 * ATTR_SATTR_ERR The underlying file system doesn't support extended
2838 * system attributes.
2840 static int
2841 open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
2843 attr_status_t rc;
2844 int firsttime = (attrinfo->attr_parentfd == -1);
2845 int saveerrno;
2846 int ext_attr;
2849 * open_attr_dir() was recursively called (input combination number 4),
2850 * close the previously opened file descriptor as we've already changed
2851 * into it.
2853 if (!firsttime) {
2854 (void) close(attrinfo->attr_parentfd);
2855 attrinfo->attr_parentfd = -1;
2859 * Verify that the underlying file system supports the restoration
2860 * of the attribute.
2862 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
2863 &ext_attr)) != ATTR_OK) {
2864 return (rc);
2867 /* Open the base file's attribute directory */
2868 if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
2870 * Save the errno from the attropen so it can be reported
2871 * if the retry of the attropen fails.
2873 saveerrno = errno;
2874 if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
2875 NULL, ".", O_RDONLY, 0)) == -1) {
2877 * Reset typeflag back to real value so passtape
2878 * will skip ahead correctly.
2880 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2881 (void) close(attrinfo->attr_parentfd);
2882 attrinfo->attr_parentfd = -1;
2883 errno = saveerrno;
2884 return (ATTR_OPEN_ERR);
2889 * Change into the parent attribute's directory unless we are
2890 * processing the hidden attribute directory of the base file itself.
2892 if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
2893 if (fchdir(attrinfo->attr_parentfd) != 0) {
2894 saveerrno = errno;
2895 (void) close(attrinfo->attr_parentfd);
2896 attrinfo->attr_parentfd = -1;
2897 errno = saveerrno;
2898 return (ATTR_CHDIR_ERR);
2902 /* Determine if the attribute should be processed */
2903 if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
2904 &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
2905 saveerrno = errno;
2906 (void) close(attrinfo->attr_parentfd);
2907 attrinfo->attr_parentfd = -1;
2908 errno = saveerrno;
2909 return (rc);
2913 * If the attribute is an extended attribute, or extended system
2914 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2915 * recursively call open_attr_dir() to open the attribute directory
2916 * of the parent attribute.
2918 if (firsttime && (attrinfo->attr_parent != NULL)) {
2919 return (open_attr_dir(attrname, attrinfo->attr_parent,
2920 attrinfo->attr_parentfd, attrinfo));
2923 return (ATTR_OK);
2925 #endif
2927 static void
2928 doxtract(char *argv[])
2930 struct stat xtractbuf; /* stat on file after extracting */
2931 blkcnt_t blocks;
2932 off_t bytes;
2933 int ofile;
2934 int newfile; /* Does the file already exist */
2935 int xcnt = 0; /* count # files extracted */
2936 int fcnt = 0; /* count # files in argv list */
2937 int dir;
2938 int dirfd = -1;
2939 int cwd = -1;
2940 int rw_sysattr;
2941 int saveerrno;
2942 uid_t Uid;
2943 char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
2944 char dirname[PATH_MAX+1];
2945 char templink[PATH_MAX+1]; /* temp link with terminating NULL */
2946 int once = 1;
2947 int error;
2948 int symflag;
2949 int want;
2950 attr_data_t *attrinfo = NULL; /* attribute info */
2951 acl_t *aclp = NULL; /* acl info */
2952 char dot[] = "."; /* dirp for using realpath */
2953 timestruc_t time_zero; /* used for call to doDirTimes */
2954 int dircreate;
2955 int convflag;
2956 time_zero.tv_sec = 0;
2957 time_zero.tv_nsec = 0;
2959 /* reset Trusted Extensions variables */
2960 rpath_flag = 0;
2961 lk_rpath_flag = 0;
2962 dir_flag = 0;
2963 mld_flag = 0;
2964 bslundef(&bs_label);
2965 bsllow(&admin_low);
2966 bslhigh(&admin_high);
2967 orig_namep = 0;
2969 dumping = 0; /* for newvol(), et al: we are not writing */
2971 Uid = getuid();
2973 for (;;) {
2974 convflag = 0;
2975 symflag = 0;
2976 dir = 0;
2977 Hiddendir = 0;
2978 rw_sysattr = 0;
2979 ofile = -1;
2981 if (dirfd != -1) {
2982 (void) close(dirfd);
2983 dirfd = -1;
2985 if (ofile != -1) {
2986 if (close(ofile) != 0)
2987 vperror(2, gettext("close error"));
2990 #if defined(O_XATTR)
2991 if (cwd != -1) {
2992 rest_cwd(&cwd);
2994 #endif
2996 /* namep is set by wantit to point to the full name */
2997 if ((want = wantit(argv, &namep, &dirp, &comp,
2998 &attrinfo)) == 0) {
2999 #if defined(O_XATTR)
3000 if (xattrp != NULL) {
3001 free(xattrhead);
3002 xattrp = NULL;
3003 xattr_linkp = NULL;
3004 xattrhead = NULL;
3006 #endif
3007 continue;
3009 if (want == -1)
3010 break;
3012 /* Trusted Extensions */
3014 * During tar extract (x):
3015 * If the pathname of the restored file has been
3016 * reconstructed from the ancillary file,
3017 * use it to process the normal file.
3019 if (mld_flag) { /* Skip over .MLD. directory */
3020 mld_flag = 0;
3021 passtape();
3022 continue;
3024 orig_namep = namep; /* save original */
3025 if (rpath_flag) {
3026 namep = real_path; /* use zone path */
3027 comp = real_path; /* use zone path */
3028 dirp = dot; /* work from the top */
3029 rpath_flag = 0; /* reset */
3032 if (dirfd != -1)
3033 (void) close(dirfd);
3035 (void) strcpy(&dirname[0], namep);
3036 dircreate = checkdir(&dirname[0]);
3038 #if defined(O_XATTR)
3039 if (xattrp != NULL) {
3040 int rc;
3042 if (((cwd = save_cwd()) == -1) ||
3043 ((rc = open_attr_dir(comp, dirp, cwd,
3044 attrinfo)) != ATTR_OK)) {
3045 if (cwd == -1) {
3046 vperror(0, gettext(
3047 "unable to save current working "
3048 "directory while processing "
3049 "attribute %s of %s"),
3050 dirp, attrinfo->attr_path);
3051 } else if (rc != ATTR_SKIP) {
3052 (void) fprintf(vfile,
3053 gettext("tar: cannot open "
3054 "%sattribute %s of file %s: %s\n"),
3055 attrinfo->attr_rw_sysattr ? gettext(
3056 "system ") : "",
3057 comp, dirp, strerror(errno));
3059 free(xattrhead);
3060 xattrp = NULL;
3061 xattr_linkp = NULL;
3062 xattrhead = NULL;
3064 passtape();
3065 continue;
3066 } else {
3067 dirfd = attrinfo->attr_parentfd;
3068 rw_sysattr = attrinfo->attr_rw_sysattr;
3070 } else {
3071 dirfd = open(dirp, O_RDONLY);
3073 #else
3074 dirfd = open(dirp, O_RDONLY);
3075 #endif
3076 if (dirfd == -1) {
3077 (void) fprintf(vfile, gettext(
3078 "tar: cannot open %s: %s\n"),
3079 dirp, strerror(errno));
3080 passtape();
3081 continue;
3084 if (xhdr_flgs & _X_LINKPATH)
3085 (void) strcpy(templink, Xtarhdr.x_linkpath);
3086 else {
3087 #if defined(O_XATTR)
3088 if (xattrp && dblock.dbuf.typeflag == '1') {
3089 (void) sprintf(templink, "%.*s", NAMSIZ,
3090 xattrp->h_names);
3091 } else {
3092 (void) sprintf(templink, "%.*s", NAMSIZ,
3093 dblock.dbuf.linkname);
3095 #else
3096 (void) sprintf(templink, "%.*s", NAMSIZ,
3097 dblock.dbuf.linkname);
3098 #endif
3101 if (Fflag) {
3102 if (checkf(namep, is_directory(namep), Fflag) == 0) {
3103 passtape();
3104 continue;
3108 if (checkw('x', namep) == 0) {
3109 passtape();
3110 continue;
3112 if (once) {
3113 if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
3114 if (geteuid() == (uid_t)0) {
3115 checkflag = 1;
3116 pflag = 1;
3117 } else {
3118 /* get file creation mask */
3119 Oumask = umask(0);
3120 (void) umask(Oumask);
3122 once = 0;
3123 } else {
3124 if (geteuid() == (uid_t)0) {
3125 pflag = 1;
3126 checkflag = 2;
3128 if (!pflag) {
3129 /* get file creation mask */
3130 Oumask = umask(0);
3131 (void) umask(Oumask);
3133 once = 0;
3137 #if defined(O_XATTR)
3139 * Handle extraction of hidden attr dir.
3140 * Dir is automatically created, we only
3141 * need to update mode and perm's.
3143 if ((xattrp != NULL) && Hiddendir == 1) {
3144 bytes = stbuf.st_size;
3145 blocks = TBLOCKS(bytes);
3146 if (vflag) {
3147 (void) fprintf(vfile,
3148 "x %s%s%s, %" FMT_off_t " %s, ", namep,
3149 gettext(" attribute "),
3150 xattrapath, bytes,
3151 gettext("bytes"));
3152 if (NotTape)
3153 (void) fprintf(vfile,
3154 "%" FMT_blkcnt_t "K\n", K(blocks));
3155 else
3156 (void) fprintf(vfile, gettext("%"
3157 FMT_blkcnt_t " tape blocks\n"),
3158 blocks);
3162 * Set the permissions and mode of the attribute
3163 * unless the attribute is a system attribute (can't
3164 * successfully do this) or the hidden attribute
3165 * directory (".") of an attribute (when the attribute
3166 * is restored, the hidden attribute directory of an
3167 * attribute is transient). Note: when the permissions
3168 * and mode are set for the hidden attribute directory
3169 * of a file on a system supporting extended system
3170 * attributes, even though it returns successfully, it
3171 * will not have any affect since the attribute
3172 * directory is transient.
3174 if (attrinfo->attr_parent == NULL) {
3175 if (fchownat(dirfd, ".", stbuf.st_uid,
3176 stbuf.st_gid, 0) != 0) {
3177 vperror(0, gettext(
3178 "%s%s%s: failed to set ownership "
3179 "of attribute directory"), namep,
3180 gettext(" attribute "), xattrapath);
3183 if (fchmod(dirfd, stbuf.st_mode) != 0) {
3184 vperror(0, gettext(
3185 "%s%s%s: failed to set permissions "
3186 "of attribute directory"), namep,
3187 gettext(" attribute "), xattrapath);
3190 goto filedone;
3192 #endif
3194 if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
3195 dir = 1;
3196 if (vflag) {
3197 (void) fprintf(vfile, "x %s, 0 %s, ",
3198 &dirname[0], gettext("bytes"));
3199 if (NotTape)
3200 (void) fprintf(vfile, "0K\n");
3201 else
3202 (void) fprintf(vfile, gettext("%"
3203 FMT_blkcnt_t " tape blocks\n"),
3204 (blkcnt_t)0);
3206 goto filedone;
3209 if (dblock.dbuf.typeflag == '6') { /* FIFO */
3210 if (rmdir(namep) < 0) {
3211 if (errno == ENOTDIR)
3212 (void) unlink(namep);
3214 linkp = templink;
3215 if (*linkp != NULL) {
3216 if (Aflag && *linkp == '/')
3217 linkp++;
3218 if (link(linkp, namep) < 0) {
3219 (void) fprintf(stderr, gettext(
3220 "tar: %s: cannot link\n"), namep);
3221 continue;
3223 if (vflag)
3224 (void) fprintf(vfile, gettext(
3225 "x %s linked to %s\n"), namep,
3226 linkp);
3227 xcnt++; /* increment # files extracted */
3228 continue;
3230 if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
3231 (int)Gen.g_devmajor) < 0) {
3232 vperror(0, gettext("%s: mknod failed"), namep);
3233 continue;
3235 bytes = stbuf.st_size;
3236 blocks = TBLOCKS(bytes);
3237 if (vflag) {
3238 (void) fprintf(vfile, "x %s, %" FMT_off_t
3239 " %s, ", namep, bytes, gettext("bytes"));
3240 if (NotTape)
3241 (void) fprintf(vfile, "%" FMT_blkcnt_t
3242 "K\n", K(blocks));
3243 else
3244 (void) fprintf(vfile, gettext("%"
3245 FMT_blkcnt_t " tape blocks\n"),
3246 blocks);
3248 goto filedone;
3250 if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
3251 if (rmdir(namep) < 0) {
3252 if (errno == ENOTDIR)
3253 (void) unlink(namep);
3255 linkp = templink;
3256 if (*linkp != NULL) {
3257 if (Aflag && *linkp == '/')
3258 linkp++;
3259 if (link(linkp, namep) < 0) {
3260 (void) fprintf(stderr, gettext(
3261 "tar: %s: cannot link\n"), namep);
3262 continue;
3264 if (vflag)
3265 (void) fprintf(vfile, gettext(
3266 "x %s linked to %s\n"), namep,
3267 linkp);
3268 xcnt++; /* increment # files extracted */
3269 continue;
3271 if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
3272 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3273 vperror(0, gettext(
3274 "%s: mknod failed"), namep);
3275 continue;
3277 bytes = stbuf.st_size;
3278 blocks = TBLOCKS(bytes);
3279 if (vflag) {
3280 (void) fprintf(vfile, "x %s, %" FMT_off_t
3281 " %s, ", namep, bytes, gettext("bytes"));
3282 if (NotTape)
3283 (void) fprintf(vfile, "%" FMT_blkcnt_t
3284 "K\n", K(blocks));
3285 else
3286 (void) fprintf(vfile, gettext("%"
3287 FMT_blkcnt_t " tape blocks\n"),
3288 blocks);
3290 goto filedone;
3291 } else if (dblock.dbuf.typeflag == '3' && Uid) {
3292 (void) fprintf(stderr, gettext(
3293 "Can't create special %s\n"), namep);
3294 continue;
3297 /* BLOCK SPECIAL */
3299 if (dblock.dbuf.typeflag == '4' && !Uid) {
3300 if (rmdir(namep) < 0) {
3301 if (errno == ENOTDIR)
3302 (void) unlink(namep);
3304 linkp = templink;
3305 if (*linkp != NULL) {
3306 if (Aflag && *linkp == '/')
3307 linkp++;
3308 if (link(linkp, namep) < 0) {
3309 (void) fprintf(stderr, gettext(
3310 "tar: %s: cannot link\n"), namep);
3311 continue;
3313 if (vflag)
3314 (void) fprintf(vfile, gettext(
3315 "x %s linked to %s\n"), namep,
3316 linkp);
3317 xcnt++; /* increment # files extracted */
3318 continue;
3320 if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
3321 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3322 vperror(0, gettext("%s: mknod failed"), namep);
3323 continue;
3325 bytes = stbuf.st_size;
3326 blocks = TBLOCKS(bytes);
3327 if (vflag) {
3328 (void) fprintf(vfile, gettext("x %s, %"
3329 FMT_off_t " bytes, "), namep, bytes);
3330 if (NotTape)
3331 (void) fprintf(vfile, "%" FMT_blkcnt_t
3332 "K\n", K(blocks));
3333 else
3334 (void) fprintf(vfile, gettext("%"
3335 FMT_blkcnt_t " tape blocks\n"),
3336 blocks);
3338 goto filedone;
3339 } else if (dblock.dbuf.typeflag == '4' && Uid) {
3340 (void) fprintf(stderr,
3341 gettext("Can't create special %s\n"), namep);
3342 continue;
3344 if (dblock.dbuf.typeflag == '2') { /* symlink */
3345 if ((Tflag) && (lk_rpath_flag == 1))
3346 linkp = lk_real_path;
3347 else
3348 linkp = templink;
3349 if (Aflag && *linkp == '/')
3350 linkp++;
3351 if (rmdir(namep) < 0) {
3352 if (errno == ENOTDIR)
3353 (void) unlink(namep);
3355 if (symlink(linkp, namep) < 0) {
3356 vperror(0, gettext("%s: symbolic link failed"),
3357 namep);
3358 continue;
3360 if (vflag)
3361 (void) fprintf(vfile, gettext(
3362 "x %s symbolic link to %s\n"),
3363 namep, linkp);
3365 symflag = AT_SYMLINK_NOFOLLOW;
3366 goto filedone;
3368 if (dblock.dbuf.typeflag == '1') {
3369 linkp = templink;
3370 if (Aflag && *linkp == '/')
3371 linkp++;
3372 if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
3373 if (errno == ENOTDIR)
3374 (void) unlinkat(dirfd, comp, 0);
3376 #if defined(O_XATTR)
3377 if (xattrp && xattr_linkp) {
3378 if (fchdir(dirfd) < 0) {
3379 vperror(0, gettext(
3380 "Cannot fchdir to attribute "
3381 "directory %s"),
3382 (attrinfo->attr_parent == NULL) ?
3383 dirp : attrinfo->attr_parent);
3384 exit(1);
3387 error = link(xattr_linkaname, xattrapath);
3388 } else {
3389 error = link(linkp, namep);
3391 #else
3392 error = link(linkp, namep);
3393 #endif
3395 if (error < 0) {
3396 (void) fprintf(stderr, gettext(
3397 "tar: %s%s%s: cannot link\n"),
3398 namep, (xattr_linkp != NULL) ?
3399 gettext(" attribute ") : "",
3400 (xattr_linkp != NULL) ?
3401 xattrapath : "");
3402 continue;
3404 if (vflag)
3405 (void) fprintf(vfile, gettext(
3406 "x %s%s%s linked to %s%s%s\n"), namep,
3407 (xattr_linkp != NULL) ?
3408 gettext(" attribute ") : "",
3409 (xattr_linkp != NULL) ?
3410 xattr_linkaname : "",
3411 linkp,
3412 (xattr_linkp != NULL) ?
3413 gettext(" attribute ") : "",
3414 (xattr_linkp != NULL) ? xattrapath : "");
3415 xcnt++; /* increment # files extracted */
3416 #if defined(O_XATTR)
3417 if (xattrp != NULL) {
3418 free(xattrhead);
3419 xattrp = NULL;
3420 xattr_linkp = NULL;
3421 xattrhead = NULL;
3423 #endif
3424 continue;
3427 /* REGULAR FILES */
3429 if (convtoreg(stbuf.st_size)) {
3430 convflag = 1;
3431 if (errflag) {
3432 (void) fprintf(stderr, gettext(
3433 "tar: %s: typeflag '%c' not recognized\n"),
3434 namep, dblock.dbuf.typeflag);
3435 done(1);
3436 } else {
3437 (void) fprintf(stderr, gettext(
3438 "tar: %s: typeflag '%c' not recognized, "
3439 "converting to regular file\n"), namep,
3440 dblock.dbuf.typeflag);
3441 Errflg = 1;
3444 if (dblock.dbuf.typeflag == '0' ||
3445 dblock.dbuf.typeflag == NULL || convflag) {
3446 delete_target(dirfd, comp, namep);
3447 linkp = templink;
3448 if (*linkp != NULL) {
3449 if (Aflag && *linkp == '/')
3450 linkp++;
3451 if (link(linkp, comp) < 0) {
3452 (void) fprintf(stderr, gettext(
3453 "tar: %s: cannot link\n"), namep);
3454 continue;
3456 if (vflag)
3457 (void) fprintf(vfile, gettext(
3458 "x %s linked to %s\n"), comp,
3459 linkp);
3460 xcnt++; /* increment # files extracted */
3461 #if defined(O_XATTR)
3462 if (xattrp != NULL) {
3463 free(xattrhead);
3464 xattrp = NULL;
3465 xattr_linkp = NULL;
3466 xattrhead = NULL;
3468 #endif
3469 continue;
3471 newfile = ((fstatat(dirfd, comp,
3472 &xtractbuf, 0) == -1) ? TRUE : FALSE);
3473 ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
3474 stbuf.st_mode & MODEMASK);
3475 saveerrno = errno;
3477 #if defined(O_XATTR)
3478 if (xattrp != NULL) {
3479 if (ofile < 0) {
3480 ofile = retry_open_attr(dirfd, cwd,
3481 dirp, attrinfo->attr_parent, comp,
3482 O_RDWR|O_CREAT|O_TRUNC,
3483 stbuf.st_mode & MODEMASK);
3486 #endif
3487 if (ofile < 0) {
3488 errno = saveerrno;
3489 (void) fprintf(stderr, gettext(
3490 "tar: %s%s%s%s - cannot create\n"),
3491 (xattrp == NULL) ? "" : (rw_sysattr ?
3492 gettext("system attribute ") :
3493 gettext("attribute ")),
3494 (xattrp == NULL) ? "" : xattrapath,
3495 (xattrp == NULL) ? "" : gettext(" of "),
3496 (xattrp == NULL) ? comp : namep);
3497 if (errflag)
3498 done(1);
3499 else
3500 Errflg = 1;
3501 #if defined(O_XATTR)
3502 if (xattrp != NULL) {
3503 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
3504 free(xattrhead);
3505 xattrp = NULL;
3506 xattr_linkp = NULL;
3507 xattrhead = NULL;
3509 #endif
3510 passtape();
3511 continue;
3514 if (Tflag && (check_ext_attr(namep) == 0)) {
3515 if (errflag)
3516 done(1);
3517 else
3518 Errflg = 1;
3519 passtape();
3520 continue;
3523 if (extno != 0) { /* file is in pieces */
3524 if (extotal < 1 || extotal > MAXEXT)
3525 (void) fprintf(stderr, gettext(
3526 "tar: ignoring bad extent info for "
3527 "%s%s%s%s\n"),
3528 (xattrp == NULL) ? "" : (rw_sysattr ?
3529 gettext("system attribute ") :
3530 gettext("attribute ")),
3531 (xattrp == NULL) ? "" : xattrapath,
3532 (xattrp == NULL) ? "" : gettext(" of "),
3533 (xattrp == NULL) ? comp : namep);
3534 else {
3535 /* extract it */
3536 (void) xsfile(rw_sysattr, ofile);
3539 extno = 0; /* let everyone know file is not split */
3540 bytes = stbuf.st_size;
3541 blocks = TBLOCKS(bytes);
3542 if (vflag) {
3543 (void) fprintf(vfile,
3544 "x %s%s%s, %" FMT_off_t " %s, ",
3545 (xattrp == NULL) ? "" : dirp,
3546 (xattrp == NULL) ? "" : (rw_sysattr ?
3547 gettext(" system attribute ") :
3548 gettext(" attribute ")),
3549 (xattrp == NULL) ? namep : xattrapath, bytes,
3550 gettext("bytes"));
3551 if (NotTape)
3552 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
3553 K(blocks));
3554 else
3555 (void) fprintf(vfile, gettext("%"
3556 FMT_blkcnt_t " tape blocks\n"), blocks);
3559 if (xblocks(rw_sysattr, bytes, ofile) != 0) {
3560 #if defined(O_XATTR)
3561 if (xattrp != NULL) {
3562 free(xattrhead);
3563 xattrp = NULL;
3564 xattr_linkp = NULL;
3565 xattrhead = NULL;
3567 #endif
3568 continue;
3570 filedone:
3571 if (mflag == 0 && !symflag) {
3572 if (dir)
3573 doDirTimes(namep, stbuf.st_mtim);
3575 else
3576 #if defined(O_XATTR)
3577 if (xattrp != NULL) {
3579 * Set the time on the attribute unless
3580 * the attribute is a system attribute
3581 * (can't successfully do this) or the
3582 * hidden attribute directory, "." (the
3583 * time on the hidden attribute
3584 * directory will be updated when
3585 * attributes are restored, otherwise
3586 * it's transient).
3588 if (!rw_sysattr && (Hiddendir == 0)) {
3589 setPathTimes(dirfd, comp,
3590 stbuf.st_mtim);
3592 } else
3593 setPathTimes(dirfd, comp,
3594 stbuf.st_mtim);
3595 #else
3596 setPathTimes(dirfd, comp, stbuf.st_mtim);
3597 #endif
3600 /* moved this code from above */
3601 if (pflag && !symflag && Hiddendir == 0) {
3602 if (xattrp != NULL)
3603 (void) fchmod(ofile, stbuf.st_mode & MODEMASK);
3604 else
3605 (void) chmod(namep, stbuf.st_mode & MODEMASK);
3610 * Because ancillary file preceeds the normal file,
3611 * acl info may have been retrieved (in aclp).
3612 * All file types are directed here (go filedone).
3613 * Always restore ACLs if there are ACLs.
3615 if (aclp != NULL) {
3616 int ret;
3618 #if defined(O_XATTR)
3619 if (xattrp != NULL) {
3620 if (Hiddendir)
3621 ret = facl_set(dirfd, aclp);
3622 else
3623 ret = facl_set(ofile, aclp);
3624 } else {
3625 ret = acl_set(namep, aclp);
3627 #else
3628 ret = acl_set(namep, aclp);
3629 #endif
3630 if (ret < 0) {
3631 if (pflag) {
3632 (void) fprintf(stderr, gettext(
3633 "%s%s%s%s: failed to set acl "
3634 "entries\n"), namep,
3635 (xattrp == NULL) ? "" :
3636 (rw_sysattr ? gettext(
3637 " system attribute ") :
3638 gettext(" attribute ")),
3639 (xattrp == NULL) ? "" :
3640 xattrapath);
3642 /* else: silent and continue */
3644 acl_free(aclp);
3645 aclp = NULL;
3648 if (!oflag)
3649 /* set file ownership */
3650 resugname(dirfd, comp, symflag);
3652 if (pflag && newfile == TRUE && !dir &&
3653 (dblock.dbuf.typeflag == '0' ||
3654 dblock.dbuf.typeflag == NULL ||
3655 convflag || dblock.dbuf.typeflag == '1')) {
3656 if (fstat(ofile, &xtractbuf) == -1)
3657 (void) fprintf(stderr, gettext(
3658 "tar: cannot stat extracted file "
3659 "%s%s%s%s\n"),
3660 (xattrp == NULL) ? "" : (rw_sysattr ?
3661 gettext("system attribute ") :
3662 gettext("attribute ")),
3663 (xattrp == NULL) ? "" : xattrapath,
3664 (xattrp == NULL) ? "" :
3665 gettext(" of "), namep);
3667 else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
3668 != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
3669 (void) fprintf(stderr, gettext(
3670 "tar: warning - file permissions have "
3671 "changed for %s%s%s%s (are 0%o, should be "
3672 "0%o)\n"),
3673 (xattrp == NULL) ? "" : (rw_sysattr ?
3674 gettext("system attribute ") :
3675 gettext("attribute ")),
3676 (xattrp == NULL) ? "" : xattrapath,
3677 (xattrp == NULL) ? "" :
3678 gettext(" of "), namep,
3679 xtractbuf.st_mode, stbuf.st_mode);
3683 #if defined(O_XATTR)
3684 if (xattrp != NULL) {
3685 free(xattrhead);
3686 xattrp = NULL;
3687 xattr_linkp = NULL;
3688 xattrhead = NULL;
3690 #endif
3692 if (ofile != -1) {
3693 (void) close(dirfd);
3694 dirfd = -1;
3695 if (close(ofile) != 0)
3696 vperror(2, gettext("close error"));
3697 ofile = -1;
3699 xcnt++; /* increment # files extracted */
3703 * Process ancillary file.
3707 if (dblock.dbuf.typeflag == 'A') { /* acl info */
3708 char buf[TBLOCK];
3709 char *secp;
3710 char *tp;
3711 int attrsize;
3712 int cnt;
3714 /* reset Trusted Extensions flags */
3715 dir_flag = 0;
3716 mld_flag = 0;
3717 lk_rpath_flag = 0;
3718 rpath_flag = 0;
3720 if (pflag) {
3721 bytes = stbuf.st_size;
3722 if ((secp = malloc((int)bytes)) == NULL) {
3723 (void) fprintf(stderr, gettext(
3724 "Insufficient memory for acl\n"));
3725 passtape();
3726 continue;
3728 tp = secp;
3729 blocks = TBLOCKS(bytes);
3732 * Display a line for each ancillary file.
3734 if (vflag && Tflag)
3735 (void) fprintf(vfile, "x %s(A), %"
3736 FMT_blkcnt_t " %s, %"
3737 FMT_blkcnt_t " %s\n",
3738 namep, bytes, gettext("bytes"),
3739 blocks, gettext("tape blocks"));
3741 while (blocks-- > 0) {
3742 readtape(buf);
3743 if (bytes <= TBLOCK) {
3744 (void) memcpy(tp, buf,
3745 (size_t)bytes);
3746 break;
3747 } else {
3748 (void) memcpy(tp, buf,
3749 TBLOCK);
3750 tp += TBLOCK;
3752 bytes -= TBLOCK;
3754 bytes = stbuf.st_size;
3755 /* got all attributes in secp */
3756 tp = secp;
3757 do {
3758 attr = (struct sec_attr *)tp;
3759 switch (attr->attr_type) {
3760 case UFSD_ACL:
3761 case ACE_ACL:
3762 (void) sscanf(attr->attr_len,
3763 "%7o",
3764 (uint_t *)
3765 &cnt);
3766 /* header is 8 */
3767 attrsize = 8 + (int)strlen(
3768 &attr->attr_info[0]) + 1;
3769 error =
3770 acl_fromtext(
3771 &attr->attr_info[0], &aclp);
3773 if (error != 0) {
3774 (void) fprintf(stderr,
3775 gettext(
3776 "aclfromtext "
3777 "failed: %s\n"),
3778 acl_strerror(
3779 error));
3780 bytes -= attrsize;
3781 break;
3783 if (acl_cnt(aclp) != cnt) {
3784 (void) fprintf(stderr,
3785 gettext(
3786 "aclcnt error\n"));
3787 bytes -= attrsize;
3788 break;
3790 bytes -= attrsize;
3791 break;
3793 /* Trusted Extensions */
3795 case DIR_TYPE:
3796 case LBL_TYPE:
3797 case APRIV_TYPE:
3798 case FPRIV_TYPE:
3799 case COMP_TYPE:
3800 case LK_COMP_TYPE:
3801 case ATTR_FLAG_TYPE:
3802 attrsize =
3803 sizeof (struct sec_attr) +
3804 strlen(&attr->attr_info[0]);
3805 bytes -= attrsize;
3806 if (Tflag)
3807 extract_attr(&namep,
3808 attr);
3809 break;
3811 default:
3812 (void) fprintf(stderr, gettext(
3813 "unrecognized attr"
3814 " type\n"));
3815 bytes = (off_t)0;
3816 break;
3819 /* next attributes */
3820 tp += attrsize;
3821 } while (bytes != 0);
3822 free(secp);
3823 } else {
3824 passtape();
3826 } /* acl */
3828 } /* for */
3831 * Ensure that all the directories still on the directory stack
3832 * get their modification times set correctly by flushing the
3833 * stack.
3836 doDirTimes(NULL, time_zero);
3838 #if defined(O_XATTR)
3839 if (xattrp != NULL) {
3840 free(xattrhead);
3841 xattrp = NULL;
3842 xattr_linkp = NULL;
3843 xattrhead = NULL;
3845 #endif
3848 * Check if the number of files extracted is different from the
3849 * number of files listed on the command line
3851 if (fcnt > xcnt) {
3852 (void) fprintf(stderr,
3853 gettext("tar: %d file(s) not extracted\n"),
3854 fcnt-xcnt);
3855 Errflg = 1;
3860 * xblocks extract file/extent from tape to output file
3862 * xblocks(issysattr, bytes, ofile);
3864 * issysattr flag set if the files being extracted
3865 * is an extended system attribute file.
3866 * unsigned long long bytes size of extent or file to be extracted
3867 * ofile output file
3869 * called by doxtract() and xsfile()
3872 static int
3873 xblocks(int issysattr, off_t bytes, int ofile)
3875 char *buf;
3876 char tempname[NAMSIZ+1];
3877 size_t maxwrite;
3878 size_t bytesread;
3879 size_t piosize; /* preferred I/O size */
3880 struct stat tsbuf;
3882 /* Don't need to do anything if this is a zero size file */
3883 if (bytes <= 0) {
3884 return (0);
3888 * To figure out the size of the buffer used to accumulate data
3889 * from readtape() and to write to the file, we need to determine
3890 * the largest chunk of data to be written to the file at one time.
3891 * This is determined based on the smallest of the following two
3892 * things:
3893 * 1) The size of the archived file.
3894 * 2) The preferred I/O size of the file.
3896 if (issysattr || (bytes <= TBLOCK)) {
3898 * Writes to system attribute files must be
3899 * performed in one operation.
3901 maxwrite = bytes;
3902 } else {
3904 * fstat() the file to get the preferred I/O size.
3905 * If it fails, then resort back to just writing
3906 * one block at a time.
3908 if (fstat(ofile, &tsbuf) == 0) {
3909 piosize = tsbuf.st_blksize;
3910 } else {
3911 piosize = TBLOCK;
3913 maxwrite = min(bytes, piosize);
3917 * The buffer used to accumulate the data for the write operation
3918 * needs to be the maximum number of bytes to be written rounded up
3919 * to the nearest TBLOCK since readtape reads one block at a time.
3921 if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
3922 fatal(gettext("cannot allocate buffer"));
3925 while (bytes > 0) {
3928 * readtape() obtains one block (TBLOCK) of data at a time.
3929 * Accumulate as many blocks of data in buf as we can write
3930 * in one operation.
3932 for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
3933 readtape(buf + bytesread);
3936 if (write(ofile, buf, maxwrite) < 0) {
3937 int saveerrno = errno;
3939 if (xhdr_flgs & _X_PATH)
3940 (void) strlcpy(tempname, Xtarhdr.x_path,
3941 sizeof (tempname));
3942 else
3943 (void) sprintf(tempname, "%.*s", NAMSIZ,
3944 dblock.dbuf.name);
3946 * If the extended system attribute being extracted
3947 * contains attributes that the user needs privileges
3948 * for, then just display a warning message, skip
3949 * the extraction of this file, and return.
3951 if ((saveerrno == EPERM) && issysattr) {
3952 (void) fprintf(stderr, gettext(
3953 "tar: unable to extract system attribute "
3954 "%s: insufficient privileges\n"), tempname);
3955 Errflg = 1;
3956 (void) free(buf);
3957 return (1);
3958 } else {
3959 (void) fprintf(stderr, gettext(
3960 "tar: %s: HELP - extract write error\n"),
3961 tempname);
3962 done(2);
3965 bytes -= maxwrite;
3968 * If we've reached this point and there is still data
3969 * to be written, maxwrite had to have been determined
3970 * by the preferred I/O size. If the number of bytes
3971 * left to write is smaller than the preferred I/O size,
3972 * then we're about to do our final write to the file, so
3973 * just set maxwrite to the number of bytes left to write.
3975 if ((bytes > 0) && (bytes < maxwrite)) {
3976 maxwrite = bytes;
3979 free(buf);
3981 return (0);
3985 * xsfile extract split file
3987 * xsfile(ofd); ofd = output file descriptor
3989 * file extracted and put in ofd via xblocks()
3991 * NOTE: only called by doxtract() to extract one large file
3994 static union hblock savedblock; /* to ensure same file across volumes */
3996 static int
3997 xsfile(int issysattr, int ofd)
3999 int i, c;
4000 int sysattrerr = 0;
4001 char name[PATH_MAX+1]; /* holds name for diagnostics */
4002 int extents, totalext;
4003 off_t bytes, totalbytes;
4005 if (xhdr_flgs & _X_PATH)
4006 (void) strcpy(name, Xtarhdr.x_path);
4007 else
4008 (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
4010 totalbytes = (off_t)0; /* in case we read in half the file */
4011 totalext = 0; /* these keep count */
4013 (void) fprintf(stderr, gettext(
4014 "tar: %s split across %d volumes\n"), name, extotal);
4016 /* make sure we do extractions in order */
4017 if (extno != 1) { /* starting in middle of file? */
4018 (void) printf(gettext(
4019 "tar: first extent read is not #1\n"
4020 "OK to read file beginning with extent #%d (%s/%s) ? "),
4021 extno, yesstr, nostr);
4022 if (yes() == 0) {
4023 canit:
4024 passtape();
4025 if (close(ofd) != 0)
4026 vperror(2, gettext("close error"));
4027 if (sysattrerr) {
4028 return (1);
4029 } else {
4030 return (0);
4034 extents = extotal;
4035 i = extno;
4036 /*CONSTCOND*/
4037 while (1) {
4038 if (xhdr_flgs & _X_SIZE) {
4039 bytes = extsize;
4040 } else {
4041 bytes = stbuf.st_size;
4044 if (vflag)
4045 (void) fprintf(vfile, "+++ x %s [%s #%d], %"
4046 FMT_off_t " %s, %ldK\n",
4047 name, gettext("extent"), extno,
4048 bytes, gettext("bytes"),
4049 (long)K(TBLOCKS(bytes)));
4050 if (xblocks(issysattr, bytes, ofd) != 0) {
4051 sysattrerr = 1;
4052 goto canit;
4055 totalbytes += bytes;
4056 totalext++;
4057 if (++i > extents)
4058 break;
4060 /* get next volume and verify it's the right one */
4061 copy(&savedblock, &dblock);
4062 tryagain:
4063 newvol();
4064 xhdr_flgs = 0;
4065 getdir();
4066 if (Xhdrflag > 0)
4067 (void) get_xdata(); /* Get x-header & regular hdr */
4068 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
4069 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
4070 xhdr_flgs |= _X_XHDR;
4072 if (endtape()) { /* seemingly empty volume */
4073 (void) fprintf(stderr, gettext(
4074 "tar: first record is null\n"));
4075 asknicely:
4076 (void) fprintf(stderr, gettext(
4077 "tar: need volume with extent #%d of %s\n"),
4078 i, name);
4079 goto tryagain;
4081 if (notsame()) {
4082 (void) fprintf(stderr, gettext(
4083 "tar: first file on that volume is not "
4084 "the same file\n"));
4085 goto asknicely;
4087 if (i != extno) {
4088 (void) fprintf(stderr, gettext(
4089 "tar: extent #%d received out of order\ntar: "
4090 "should be #%d\n"), extno, i);
4091 (void) fprintf(stderr, gettext(
4092 "Ignore error, Abort this file, or "
4093 "load New volume (i/a/n) ? "));
4094 c = response();
4095 if (c == 'a')
4096 goto canit;
4097 if (c != 'i') /* default to new volume */
4098 goto asknicely;
4099 i = extno; /* okay, start from there */
4102 if (vflag)
4103 (void) fprintf(vfile, gettext(
4104 "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
4105 name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
4107 return (0);
4112 * notsame() check if extract file extent is invalid
4114 * returns true if anything differs between savedblock and dblock
4115 * except extno (extent number), checksum, or size (extent size).
4116 * Determines if this header belongs to the same file as the one we're
4117 * extracting.
4119 * NOTE: though rather bulky, it is only called once per file
4120 * extension, and it can withstand changes in the definition
4121 * of the header structure.
4123 * WARNING: this routine is local to xsfile() above
4126 static int
4127 notsame(void)
4129 return (
4130 (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
4131 (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
4132 (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
4133 (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
4134 (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
4135 (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
4136 (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
4137 (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
4138 (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
4141 static void
4142 dotable(char *argv[])
4144 int tcnt = 0; /* count # files tabled */
4145 int fcnt = 0; /* count # files in argv list */
4146 char *namep, *dirp, *comp;
4147 int want;
4148 char aclchar = ' '; /* either blank or '+' */
4149 char templink[PATH_MAX+1];
4150 attr_data_t *attrinfo = NULL;
4152 dumping = 0;
4154 /* if not on magtape, maximize seek speed */
4155 if (NotTape && !bflag) {
4156 #if SYS_BLOCK > TBLOCK
4157 nblock = SYS_BLOCK / TBLOCK;
4158 #else
4159 nblock = 1;
4160 #endif
4163 for (;;) {
4165 /* namep is set by wantit to point to the full name */
4166 if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
4167 continue;
4168 if (want == -1)
4169 break;
4170 if (dblock.dbuf.typeflag != 'A')
4171 ++tcnt;
4173 if (Fflag) {
4174 if (checkf(namep, is_directory(namep), Fflag) == 0) {
4175 passtape();
4176 continue;
4180 * ACL support:
4181 * aclchar is introduced to indicate if there are
4182 * acl entries. longt() now takes one extra argument.
4184 if (vflag) {
4185 if (dblock.dbuf.typeflag == 'A') {
4186 aclchar = '+';
4187 passtape();
4188 continue;
4190 longt(&stbuf, aclchar);
4191 aclchar = ' ';
4195 #if defined(O_XATTR)
4196 if (xattrp != NULL) {
4197 int issysattr;
4198 char *bn = basename(attrinfo->attr_path);
4201 * We could use sysattr_type() to test whether or not
4202 * the attribute we are processing is really an
4203 * extended system attribute, which as of this writing
4204 * just does a strcmp(), however, sysattr_type() may
4205 * be changed to issue a pathconf() call instead, which
4206 * would require being changed into the parent attribute
4207 * directory. So instead, just do simple string
4208 * comparisons to see if we are processing an extended
4209 * system attribute.
4211 issysattr = is_sysattr(bn);
4213 (void) printf(gettext("%s %sattribute %s"),
4214 xattrp->h_names,
4215 issysattr ? gettext("system ") : "",
4216 attrinfo->attr_path);
4217 } else {
4218 (void) printf("%s", namep);
4220 #else
4221 (void) printf("%s", namep);
4222 #endif
4224 if (extno != 0) {
4225 if (vflag) {
4226 /* keep the '\n' for backwards compatibility */
4227 (void) fprintf(vfile, gettext(
4228 "\n [extent #%d of %d]"), extno, extotal);
4229 } else {
4230 (void) fprintf(vfile, gettext(
4231 " [extent #%d of %d]"), extno, extotal);
4234 if (xhdr_flgs & _X_LINKPATH) {
4235 (void) strcpy(templink, Xtarhdr.x_linkpath);
4236 } else {
4237 #if defined(O_XATTR)
4238 if (xattrp != NULL) {
4239 (void) sprintf(templink,
4240 "file %.*s", NAMSIZ, xattrp->h_names);
4241 } else {
4242 (void) sprintf(templink, "%.*s", NAMSIZ,
4243 dblock.dbuf.linkname);
4245 #else
4246 (void) sprintf(templink, "%.*s", NAMSIZ,
4247 dblock.dbuf.linkname);
4248 #endif
4249 templink[NAMSIZ] = '\0';
4251 if (dblock.dbuf.typeflag == '1') {
4253 * TRANSLATION_NOTE
4254 * Subject is omitted here.
4255 * Translate this as if
4256 * <subject> linked to %s
4258 #if defined(O_XATTR)
4259 if (xattrp != NULL) {
4260 (void) printf(
4261 gettext(" linked to attribute %s"),
4262 xattr_linkp->h_names +
4263 strlen(xattr_linkp->h_names) + 1);
4264 } else {
4265 (void) printf(
4266 gettext(" linked to %s"), templink);
4268 #else
4269 (void) printf(
4270 gettext(" linked to %s"), templink);
4272 #endif
4274 if (dblock.dbuf.typeflag == '2')
4275 (void) printf(gettext(
4277 * TRANSLATION_NOTE
4278 * Subject is omitted here.
4279 * Translate this as if
4280 * <subject> symbolic link to %s
4282 " symbolic link to %s"), templink);
4283 (void) printf("\n");
4284 #if defined(O_XATTR)
4285 if (xattrp != NULL) {
4286 free(xattrhead);
4287 xattrp = NULL;
4288 xattrhead = NULL;
4290 #endif
4291 passtape();
4294 * Check if the number of files tabled is different from the
4295 * number of files listed on the command line
4297 if (fcnt > tcnt) {
4298 (void) fprintf(stderr, gettext(
4299 "tar: %d file(s) not found\n"), fcnt-tcnt);
4300 Errflg = 1;
4304 static void
4305 putempty(blkcnt_t n)
4307 char buf[TBLOCK];
4308 char *cp;
4310 for (cp = buf; cp < &buf[TBLOCK]; )
4311 *cp++ = '\0';
4312 while (n-- > 0)
4313 (void) writetbuf(buf, 1);
4316 static ushort_t Ftype = S_IFMT;
4318 static void
4319 verbose(struct stat *st, char aclchar)
4321 int i, j, temp;
4322 mode_t mode;
4323 char modestr[12];
4325 for (i = 0; i < 11; i++)
4326 modestr[i] = '-';
4327 modestr[i] = '\0';
4329 /* a '+' sign is printed if there is ACL */
4330 modestr[i-1] = aclchar;
4332 mode = st->st_mode;
4333 for (i = 0; i < 3; i++) {
4334 temp = (mode >> (6 - (i * 3)));
4335 j = (i * 3) + 1;
4336 if (S_IROTH & temp)
4337 modestr[j] = 'r';
4338 if (S_IWOTH & temp)
4339 modestr[j + 1] = 'w';
4340 if (S_IXOTH & temp)
4341 modestr[j + 2] = 'x';
4343 temp = st->st_mode & Ftype;
4344 switch (temp) {
4345 case (S_IFIFO):
4346 modestr[0] = 'p';
4347 break;
4348 case (S_IFCHR):
4349 modestr[0] = 'c';
4350 break;
4351 case (S_IFDIR):
4352 modestr[0] = 'd';
4353 break;
4354 case (S_IFBLK):
4355 modestr[0] = 'b';
4356 break;
4357 case (S_IFREG): /* was initialized to '-' */
4358 break;
4359 case (S_IFLNK):
4360 modestr[0] = 'l';
4361 break;
4362 default:
4363 /* This field may be zero in old archives. */
4364 if (is_posix && dblock.dbuf.typeflag != '1') {
4366 * For POSIX compliant archives, the mode field
4367 * consists of 12 bits, ie: the file type bits
4368 * are not stored in dblock.dbuf.mode.
4369 * For files other than hard links, getdir() sets
4370 * the file type bits in the st_mode field of the
4371 * stat structure based upon dblock.dbuf.typeflag.
4373 (void) fprintf(stderr, gettext(
4374 "tar: impossible file type"));
4378 if ((S_ISUID & Gen.g_mode) == S_ISUID)
4379 modestr[3] = 's';
4380 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
4381 modestr[9] = 't';
4382 if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
4383 modestr[6] = 's';
4384 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
4385 modestr[6] = 'l';
4386 (void) fprintf(vfile, "%s", modestr);
4389 static void
4390 longt(struct stat *st, char aclchar)
4392 char fileDate[30];
4393 struct tm *tm;
4395 verbose(st, aclchar);
4396 (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
4398 if (dblock.dbuf.typeflag == '2') {
4399 if (xhdr_flgs & _X_LINKPATH)
4400 st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
4401 else
4402 st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
4403 '\0', NAMSIZ) ?
4404 (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
4406 (void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
4408 tm = localtime(&(st->st_mtime));
4409 (void) strftime(fileDate, sizeof (fileDate),
4410 dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
4411 (void) fprintf(vfile, " %s ", fileDate);
4416 * checkdir - Attempt to ensure that the path represented in name
4417 * exists, and return 1 if this is true and name itself is a
4418 * directory.
4419 * Return 0 if this path cannot be created or if name is not
4420 * a directory.
4423 static int
4424 checkdir(char *name)
4426 char lastChar; /* the last character in name */
4427 char *cp; /* scratch pointer into name */
4428 char *firstSlash = NULL; /* first slash in name */
4429 char *lastSlash = NULL; /* last slash in name */
4430 int nameLen; /* length of name */
4431 int trailingSlash; /* true if name ends in slash */
4432 int leadingSlash; /* true if name begins with slash */
4433 int markedDir; /* true if name denotes a directory */
4434 int success; /* status of makeDir call */
4438 * Scan through the name, and locate first and last slashes.
4441 for (cp = name; *cp; cp++) {
4442 if (*cp == '/') {
4443 if (! firstSlash) {
4444 firstSlash = cp;
4446 lastSlash = cp;
4451 * Determine what you can from the proceeds of the scan.
4454 lastChar = *(cp - 1);
4455 nameLen = (int)(cp - name);
4456 trailingSlash = (lastChar == '/');
4457 leadingSlash = (*name == '/');
4458 markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash);
4460 if (! lastSlash && ! markedDir) {
4462 * The named file does not have any subdrectory
4463 * structure; just bail out.
4466 return (0);
4470 * Make sure that name doesn`t end with slash for the loop.
4471 * This ensures that the makeDir attempt after the loop is
4472 * meaningful.
4475 if (trailingSlash) {
4476 name[nameLen-1] = '\0';
4480 * Make the path one component at a time.
4483 for (cp = strchr(leadingSlash ? name+1 : name, '/');
4485 cp = strchr(cp+1, '/')) {
4486 *cp = '\0';
4487 success = makeDir(name);
4488 *cp = '/';
4490 if (!success) {
4491 name[nameLen-1] = lastChar;
4492 return (0);
4497 * This makes the last component of the name, if it is a
4498 * directory.
4501 if (markedDir) {
4502 if (! makeDir(name)) {
4503 name[nameLen-1] = lastChar;
4504 return (0);
4508 name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
4509 return (markedDir);
4513 * resugname - Restore the user name and group name. Search the NIS
4514 * before using the uid and gid.
4515 * (It is presumed that an archive entry cannot be
4516 * simultaneously a symlink and some other type.)
4519 static void
4520 resugname(int dirfd, /* dir fd file resides in */
4521 char *name, /* name of the file to be modified */
4522 int symflag) /* true if file is a symbolic link */
4524 uid_t duid;
4525 gid_t dgid;
4526 struct stat *sp = &stbuf;
4527 char *u_g_name;
4529 if (checkflag == 1) { /* Extended tar format and euid == 0 */
4532 * Try and extract the intended uid and gid from the name
4533 * service before believing the uid and gid in the header.
4535 * In the case where we archived a setuid or setgid file
4536 * owned by someone with a large uid, then it will
4537 * have made it into the archive with a uid of nobody. If
4538 * the corresponding username doesn't appear to exist, then we
4539 * want to make sure it *doesn't* end up as setuid nobody!
4541 * Our caller will print an error message about the fact
4542 * that the restore didn't work out quite right ..
4544 if (xhdr_flgs & _X_UNAME)
4545 u_g_name = Xtarhdr.x_uname;
4546 else
4547 u_g_name = dblock.dbuf.uname;
4548 if ((duid = getuidbyname(u_g_name)) == -1) {
4549 if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
4550 (sp->st_mode & S_ISUID) == S_ISUID)
4551 (void) chmod(name,
4552 MODEMASK & sp->st_mode & ~S_ISUID);
4553 duid = sp->st_uid;
4556 /* (Ditto for gids) */
4558 if (xhdr_flgs & _X_GNAME)
4559 u_g_name = Xtarhdr.x_gname;
4560 else
4561 u_g_name = dblock.dbuf.gname;
4562 if ((dgid = getgidbyname(u_g_name)) == -1) {
4563 if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
4564 (sp->st_mode & S_ISGID) == S_ISGID)
4565 (void) chmod(name,
4566 MODEMASK & sp->st_mode & ~S_ISGID);
4567 dgid = sp->st_gid;
4569 } else if (checkflag == 2) { /* tar format and euid == 0 */
4570 duid = sp->st_uid;
4571 dgid = sp->st_gid;
4573 if ((checkflag == 1) || (checkflag == 2))
4574 (void) fchownat(dirfd, name, duid, dgid, symflag);
4577 /*ARGSUSED*/
4578 static void
4579 onintr(int sig)
4581 (void) signal(SIGINT, SIG_IGN);
4582 term++;
4585 /*ARGSUSED*/
4586 static void
4587 onquit(int sig)
4589 (void) signal(SIGQUIT, SIG_IGN);
4590 term++;
4593 /*ARGSUSED*/
4594 static void
4595 onhup(int sig)
4597 (void) signal(SIGHUP, SIG_IGN);
4598 term++;
4601 static void
4602 tomodes(struct stat *sp)
4604 uid_t uid;
4605 gid_t gid;
4607 bzero(dblock.dummy, TBLOCK);
4610 * If the uid or gid is too large, we can't put it into
4611 * the archive. We could fail to put anything in the
4612 * archive at all .. but most of the time the name service
4613 * will save the day when we do a lookup at restore time.
4615 * Instead we choose a "safe" uid and gid, and fix up whether
4616 * or not the setuid and setgid bits are left set to extraction
4617 * time.
4619 if (Eflag) {
4620 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
4621 xhdr_flgs |= _X_UID;
4622 Xtarhdr.x_uid = uid;
4624 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
4625 xhdr_flgs |= _X_GID;
4626 Xtarhdr.x_gid = gid;
4628 if (sp->st_size > TAR_OFFSET_MAX) {
4629 xhdr_flgs |= _X_SIZE;
4630 Xtarhdr.x_filesz = sp->st_size;
4631 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4632 (off_t)0);
4633 } else
4634 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4635 sp->st_size);
4636 } else {
4637 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4638 sp->st_size);
4640 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
4641 uid = UID_NOBODY;
4642 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
4643 gid = GID_NOBODY;
4644 (void) sprintf(dblock.dbuf.gid, "%07lo", gid);
4645 (void) sprintf(dblock.dbuf.uid, "%07lo", uid);
4646 (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
4647 (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
4650 static int
4651 #ifdef EUC
4653 * Warning: the result of this function depends whether 'char' is a
4654 * signed or unsigned data type. This a source of potential
4655 * non-portability among heterogeneous systems. It is retained here
4656 * for backward compatibility.
4658 checksum_signed(union hblock *dblockp)
4659 #else
4660 checksum(union hblock *dblockp)
4661 #endif /* EUC */
4663 int i;
4664 char *cp;
4666 for (cp = dblockp->dbuf.chksum;
4667 cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
4668 *cp = ' ';
4669 i = 0;
4670 for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
4671 i += *cp;
4672 return (i);
4675 #ifdef EUC
4677 * Generate unsigned checksum, regardless of what C compiler is
4678 * used. Survives in the face of arbitrary 8-bit clean filenames,
4679 * e.g., internationalized filenames.
4681 static int
4682 checksum(union hblock *dblockp)
4684 unsigned i;
4685 unsigned char *cp;
4687 for (cp = (unsigned char *) dblockp->dbuf.chksum;
4688 cp < (unsigned char *)
4689 &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
4690 *cp = ' ';
4691 i = 0;
4692 for (cp = (unsigned char *) dblockp->dummy;
4693 cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
4694 i += *cp;
4696 return (i);
4698 #endif /* EUC */
4701 * If the w flag is set, output the action to be taken and the name of the
4702 * file. Perform the action if the user response is affirmative.
4705 static int
4706 checkw(char c, char *name)
4708 if (wflag) {
4709 (void) fprintf(vfile, "%c ", c);
4710 if (vflag)
4711 longt(&stbuf, ' '); /* do we have acl info here */
4712 (void) fprintf(vfile, "%s: ", name);
4713 if (yes() == 1) {
4714 return (1);
4716 return (0);
4718 return (1);
4722 * When the F flag is set, exclude RCS and SCCS directories (and any files
4723 * or directories under them). If F is set twice, also exclude .o files,
4724 * and files names errs, core, and a.out.
4726 * Return 0 if file should be excluded, 1 otherwise.
4729 static int
4730 checkf(char *longname, int is_dir, int howmuch)
4732 static char fullname[PATH_MAX + 1];
4733 char *dir, *name;
4735 #if defined(O_XATTR)
4737 * If there is an xattr_buf structure associated with this file,
4738 * always return 1.
4740 if (xattrp) {
4741 return (1);
4743 #endif
4746 * First check to see if the base name is an RCS or SCCS directory.
4748 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4749 return (1);
4751 name = basename(fullname);
4752 if (is_dir) {
4753 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4754 return (0);
4758 * If two -F command line options were given then exclude .o files,
4759 * and files named errs, core, and a.out.
4761 if (howmuch > 1 && !is_dir) {
4762 size_t l = strlen(name);
4764 if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
4765 return (0);
4766 if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
4767 strcmp(name, "a.out") == 0)
4768 return (0);
4772 * At this point, check to see if this file has a parent directory
4773 * named RCS or SCCS. If so, then this file should be excluded too.
4774 * The strcpy() operation is done again, because basename(3C) may
4775 * modify the path string passed to it.
4777 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4778 return (1);
4780 dir = dirname(fullname);
4781 while (strcmp(dir, ".") != 0) {
4782 name = basename(dir);
4783 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4784 return (0);
4785 dir = dirname(dir);
4788 return (1);
4791 static int
4792 response(void)
4794 int c;
4796 c = getchar();
4797 if (c != '\n')
4798 while (getchar() != '\n')
4800 else c = 'n';
4801 return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
4804 /* Has file been modified since being put into archive? If so, return > 0. */
4806 static off_t lookup(char *);
4808 static int
4809 checkupdate(char *arg)
4811 char name[PATH_MAX+1];
4812 time_t mtime;
4813 long nsecs;
4814 off_t seekp;
4816 rewind(tfile);
4817 if ((seekp = lookup(arg)) < 0)
4818 return (1);
4819 (void) fseek(tfile, seekp, 0);
4820 (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
4823 * Unless nanoseconds were stored in the file, only use seconds for
4824 * comparison of time. Nanoseconds are stored when -E is specified.
4826 if (Eflag == 0)
4827 return (stbuf.st_mtime > mtime);
4829 if ((stbuf.st_mtime < mtime) ||
4830 ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
4831 return (0);
4832 return (1);
4837 * newvol get new floppy (or tape) volume
4839 * newvol(); resets tapepos and first to TRUE, prompts for
4840 * for new volume, and waits.
4841 * if dumping, end-of-file is written onto the tape.
4844 static void
4845 newvol(void)
4847 int c;
4849 if (dumping) {
4850 dlog("newvol called with 'dumping' set\n");
4851 putempty((blkcnt_t)2); /* 2 EOT marks */
4852 closevol();
4853 flushtape();
4854 sync();
4855 tapepos = 0;
4856 } else
4857 first = TRUE;
4858 if (close(mt) != 0)
4859 vperror(2, gettext("close error"));
4860 mt = 0;
4861 (void) fprintf(stderr, gettext(
4862 "tar: \007please insert new volume, then press RETURN."));
4863 (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */
4864 while ((c = getchar()) != '\n' && ! term)
4865 if (c == EOF)
4866 done(Errflg);
4867 if (term)
4868 done(Errflg);
4870 errno = 0;
4872 if (strcmp(usefile, "-") == 0) {
4873 mt = dup(1);
4874 } else {
4875 mt = open(usefile, dumping ? update : 0);
4878 if (mt < 0) {
4879 (void) fprintf(stderr, gettext(
4880 "tar: cannot reopen %s (%s)\n"),
4881 dumping ? gettext("output") : gettext("input"), usefile);
4883 dlog("update=%d, usefile=%s ", update, usefile);
4884 dlog("mt=%d, [%s]\n", mt, strerror(errno));
4886 done(2);
4891 * Write a trailer portion to close out the current output volume.
4894 static void
4895 closevol(void)
4897 if (mulvol) {
4899 * blocklim does not count the 2 EOT marks;
4900 * tapepos does count the 2 EOT marks;
4901 * therefore we need the +2 below.
4903 putempty(blocklim + (blkcnt_t)2 - tapepos);
4907 static void
4908 done(int n)
4911 * If we were terminated in some way, and we would otherwise have
4912 * exited with a value of 0, adjust to 1, so that external callers
4913 * can determine this by looking at the exit status.
4915 if (term && n == 0)
4916 n = 1;
4918 if (tfile != NULL)
4919 (void) unlink(tname);
4920 if (compress_opt != NULL)
4921 (void) free(compress_opt);
4922 if (mt > 0) {
4923 if ((close(mt) != 0) || (fclose(stdout) != 0)) {
4924 perror(gettext("tar: close error"));
4925 exit(2);
4929 * If we have a compression child, we should have a child process that
4930 * we're waiting for to finish compressing or uncompressing the tar
4931 * stream.
4933 if (comp_pid != 0)
4934 wait_pid(comp_pid);
4935 exit(n);
4939 * Determine if s1 is a prefix portion of s2 (or the same as s2).
4942 static int
4943 is_prefix(char *s1, char *s2)
4945 while (*s1)
4946 if (*s1++ != *s2++)
4947 return (0);
4948 if (*s2)
4949 return (*s2 == '/');
4950 return (1);
4954 * lookup and bsrch look through tfile entries to find a match for a name.
4955 * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
4956 * a pair of newline chars, so the buffer it uses must be long enough for
4957 * two lines: name and modification time as well as period, newline and space.
4959 * A kludge was added to bsrch to take care of matching on the first entry
4960 * in the file--there is no leading newline. So, if we are reading from the
4961 * start of the file, read into byte two and set the first byte to a newline.
4962 * Otherwise, the first entry cannot be matched.
4966 #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4967 static off_t
4968 lookup(char *s)
4970 int i;
4971 off_t a;
4973 for (i = 0; s[i]; i++)
4974 if (s[i] == ' ')
4975 break;
4976 a = bsrch(s, i, low, high);
4977 return (a);
4980 static off_t
4981 bsrch(char *s, int n, off_t l, off_t h)
4983 int i, j;
4984 char b[N];
4985 off_t m, m1;
4988 loop:
4989 if (l >= h)
4990 return ((off_t)-1);
4991 m = l + (h-l)/2 - N/2;
4992 if (m < l)
4993 m = l;
4994 (void) fseek(tfile, m, 0);
4995 if (m == 0) {
4996 (void) fread(b+1, 1, N-1, tfile);
4997 b[0] = '\n';
4998 m--;
4999 } else
5000 (void) fread(b, 1, N, tfile);
5001 for (i = 0; i < N; i++) {
5002 if (b[i] == '\n')
5003 break;
5004 m++;
5006 if (m >= h)
5007 return ((off_t)-1);
5008 m1 = m;
5009 j = i;
5010 for (i++; i < N; i++) {
5011 m1++;
5012 if (b[i] == '\n')
5013 break;
5015 i = cmp(b+j, s, n);
5016 if (i < 0) {
5017 h = m;
5018 goto loop;
5020 if (i > 0) {
5021 l = m1;
5022 goto loop;
5024 if (m < 0)
5025 m = 0;
5026 return (m);
5029 static int
5030 cmp(char *b, char *s, int n)
5032 int i;
5034 assert(b[0] == '\n');
5036 for (i = 0; i < n; i++) {
5037 if (b[i+1] > s[i])
5038 return (-1);
5039 if (b[i+1] < s[i])
5040 return (1);
5042 return (b[i+1] == ' '? 0 : -1);
5047 * seekdisk seek to next file on archive
5049 * called by passtape() only
5051 * WARNING: expects "nblock" to be set, that is, readtape() to have
5052 * already been called. Since passtape() is only called
5053 * after a file header block has been read (why else would
5054 * we skip to next file?), this is currently safe.
5056 * changed to guarantee SYS_BLOCK boundary
5059 static void
5060 seekdisk(blkcnt_t blocks)
5062 off_t seekval;
5063 #if SYS_BLOCK > TBLOCK
5064 /* handle non-multiple of SYS_BLOCK */
5065 blkcnt_t nxb; /* # extra blocks */
5066 #endif
5068 tapepos += blocks;
5069 dlog("seekdisk(%" FMT_blkcnt_t ") called\n", blocks);
5070 if (recno + blocks <= nblock) {
5071 recno += blocks;
5072 return;
5074 if (recno > nblock)
5075 recno = nblock;
5076 seekval = (off_t)blocks - (nblock - recno);
5077 recno = nblock; /* so readtape() reads next time through */
5078 #if SYS_BLOCK > TBLOCK
5079 nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
5080 dlog("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
5081 nxb, seekval);
5082 if (nxb && nxb > seekval) /* don't seek--we'll read */
5083 goto noseek;
5084 seekval -= nxb; /* don't seek quite so far */
5085 #endif
5086 if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
5087 (void) fprintf(stderr, gettext(
5088 "tar: device seek error\n"));
5089 done(3);
5091 #if SYS_BLOCK > TBLOCK
5092 /* read those extra blocks */
5093 noseek:
5094 if (nxb) {
5095 dlog("reading extra blocks\n");
5096 if (read(mt, tbuf, TBLOCK*nblock) < 0) {
5097 (void) fprintf(stderr, gettext(
5098 "tar: read error while skipping file\n"));
5099 done(8);
5101 recno = nxb; /* so we don't read in next readtape() */
5103 #endif
5106 static void
5107 readtape(char *buffer)
5109 int i, j;
5111 ++tapepos;
5112 if (recno >= nblock || first) {
5113 if (first) {
5115 * set the number of blocks to read initially, based on
5116 * the defined defaults for the device, or on the
5117 * explicit block factor given.
5119 if (bflag || defaults_used || NotTape)
5120 j = nblock;
5121 else
5122 j = NBLOCK;
5123 } else
5124 j = nblock;
5126 if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
5127 (void) fprintf(stderr, gettext(
5128 "tar: tape read error\n"));
5129 done(3);
5131 * i == 0 and !rflag means that EOF is reached and we are
5132 * trying to update or replace an empty tar file, so exit
5133 * with an error.
5135 * If i == 0 and !first and NotTape, it means the pointer
5136 * has gone past the EOF. It could happen if two processes
5137 * try to update the same tar file simultaneously. So exit
5138 * with an error.
5141 } else if (i == 0) {
5142 if (first && !rflag) {
5143 (void) fprintf(stderr, gettext(
5144 "tar: blocksize = %d\n"), i);
5145 done(Errflg);
5146 } else if (!first && (!rflag || NotTape)) {
5147 mterr("read", 0, 2);
5149 } else if ((!first || Bflag) && i != TBLOCK*j) {
5151 * Short read - try to get the remaining bytes.
5154 int remaining = (TBLOCK * j) - i;
5155 char *b = (char *)tbuf + i;
5156 int r;
5158 do {
5159 if ((r = read(mt, b, remaining)) < 0) {
5160 (void) fprintf(stderr,
5161 gettext("tar: tape read error\n"));
5162 done(3);
5164 b += r;
5165 remaining -= r;
5166 i += r;
5167 } while (remaining > 0 && r != 0);
5169 if (first) {
5170 if ((i % TBLOCK) != 0) {
5171 (void) fprintf(stderr, gettext(
5172 "tar: tape blocksize error\n"));
5173 done(3);
5175 i /= TBLOCK;
5176 if (vflag && i != nblock && i != 1) {
5177 if (!NotTape)
5178 (void) fprintf(stderr, gettext(
5179 "tar: blocksize = %d\n"), i);
5183 * If we are reading a tape, then a short read is
5184 * understood to signify that the amount read is
5185 * the tape's actual blocking factor. We adapt
5186 * nblock accordingly. There is no reason to do
5187 * this when the device is not blocked.
5190 if (!NotTape)
5191 nblock = i;
5193 recno = 0;
5196 first = FALSE;
5197 copy(buffer, &tbuf[recno++]);
5202 * replacement for writetape.
5205 static int
5206 writetbuf(char *buffer, int n)
5208 int i;
5210 tapepos += n; /* output block count */
5212 if (recno >= nblock) {
5213 i = write(mt, (char *)tbuf, TBLOCK*nblock);
5214 if (i != TBLOCK*nblock)
5215 mterr("write", i, 2);
5216 recno = 0;
5220 * Special case: We have an empty tape buffer, and the
5221 * users data size is >= the tape block size: Avoid
5222 * the bcopy and dma direct to tape. BIG WIN. Add the
5223 * residual to the tape buffer.
5225 while (recno == 0 && n >= nblock) {
5226 i = (int)write(mt, buffer, TBLOCK*nblock);
5227 if (i != TBLOCK*nblock)
5228 mterr("write", i, 2);
5229 n -= nblock;
5230 buffer += (nblock * TBLOCK);
5233 while (n-- > 0) {
5234 (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
5235 buffer += TBLOCK;
5236 if (recno >= nblock) {
5237 i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
5238 if (i != TBLOCK*nblock)
5239 mterr("write", i, 2);
5240 recno = 0;
5244 /* Tell the user how much to write to get in sync */
5245 return (nblock - recno);
5249 * backtape - reposition tape after reading soft "EOF" record
5251 * Backtape tries to reposition the tape back over the EOF
5252 * record. This is for the 'u' and 'r' function letters so that the
5253 * tape can be extended. This code is not well designed, but
5254 * I'm confident that the only callers who care about the
5255 * backspace-over-EOF feature are those involved in 'u' and 'r'.
5257 * The proper way to backup the tape is through the use of mtio.
5258 * Earlier spins used lseek combined with reads in a confusing
5259 * maneuver that only worked on 4.x, but shouldn't have, even
5260 * there. Lseeks are explicitly not supported for tape devices.
5263 static void
5264 backtape(void)
5266 struct mtop mtcmd;
5267 dlog("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
5268 nblock);
5270 * Backup to the position in the archive where the record
5271 * currently sitting in the tbuf buffer is situated.
5274 if (NotTape) {
5276 * For non-tape devices, this means lseeking to the
5277 * correct position. The absolute location tapepos-recno
5278 * should be the beginning of the current record.
5281 if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
5282 (off_t)-1) {
5283 (void) fprintf(stderr,
5284 gettext("tar: lseek to end of archive failed\n"));
5285 done(4);
5287 } else {
5289 * For tape devices, we backup over the most recently
5290 * read record.
5293 mtcmd.mt_op = MTBSR;
5294 mtcmd.mt_count = 1;
5296 if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
5297 (void) fprintf(stderr,
5298 gettext("tar: backspace over record failed\n"));
5299 done(4);
5304 * Decrement the tape and tbuf buffer indices to prepare for the
5305 * coming write to overwrite the soft EOF record.
5308 recno--;
5309 tapepos--;
5314 * flushtape write buffered block(s) onto tape
5316 * recno points to next free block in tbuf. If nonzero, a write is done.
5317 * Care is taken to write in multiples of SYS_BLOCK when device is
5318 * non-magtape in case raw i/o is used.
5320 * NOTE: this is called by writetape() to do the actual writing
5323 static void
5324 flushtape(void)
5326 dlog("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno);
5327 if (recno > 0) { /* anything buffered? */
5328 if (NotTape) {
5329 #if SYS_BLOCK > TBLOCK
5330 int i;
5333 * an odd-block write can only happen when
5334 * we are at the end of a volume that is not a tape.
5335 * Here we round recno up to an even SYS_BLOCK
5336 * boundary.
5338 if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
5339 dlog("flushtape() %d rounding blocks\n", i);
5340 recno += i; /* round up to even SYS_BLOCK */
5342 #endif
5343 if (recno > nblock)
5344 recno = nblock;
5346 dlog("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
5347 " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
5348 (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
5349 if (write(mt, tbuf,
5350 (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
5351 (void) fprintf(stderr, gettext(
5352 "tar: tape write error\n"));
5353 done(2);
5355 recno = 0;
5359 static void
5360 copy(void *dst, void *src)
5362 (void) memcpy(dst, src, TBLOCK);
5366 * kcheck()
5367 * - checks the validity of size values for non-tape devices
5368 * - if size is zero, mulvol tar is disabled and size is
5369 * assumed to be infinite.
5370 * - returns volume size in TBLOCKS
5373 static blkcnt_t
5374 kcheck(char *kstr)
5376 blkcnt_t kval;
5378 kval = strtoll(kstr, NULL, 0);
5379 if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */
5380 mulvol = 0; /* definitely not mulvol, but we must */
5381 return (0); /* took out setting of NotTape */
5383 if (kval < (blkcnt_t)MINSIZE) {
5384 (void) fprintf(stderr, gettext(
5385 "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5386 ").\n"), (ulong_t)MINSIZE, kval);
5387 (void) fprintf(stderr, gettext(
5388 "bad size entry for %s in %s.\n"),
5389 archive, DEF_FILE);
5390 done(1);
5392 mulvol++;
5393 NotTape++; /* implies non-tape */
5394 return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */
5399 * bcheck()
5400 * - checks the validity of blocking factors
5401 * - returns blocking factor
5404 static int
5405 bcheck(char *bstr)
5407 blkcnt_t bval;
5409 bval = strtoll(bstr, NULL, 0);
5410 if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
5411 (void) fprintf(stderr, gettext(
5412 "tar: invalid blocksize \"%s\".\n"), bstr);
5413 if (!bflag)
5414 (void) fprintf(stderr, gettext(
5415 "bad blocksize entry for '%s' in %s.\n"),
5416 archive, DEF_FILE);
5417 done(1);
5420 return ((int)bval);
5425 * defset()
5426 * - reads DEF_FILE for the set of default values specified.
5427 * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5428 * - 'usefile' points to static data, so will be overwritten
5429 * if this routine is called a second time.
5430 * - the pattern specified by 'arch' must be followed by four
5431 * blank-separated fields (1) device (2) blocking,
5432 * (3) size(K), and (4) tape
5433 * for example: archive0=/dev/fd 1 400 n
5436 static int
5437 defset(char *arch)
5439 char *bp;
5441 if (defopen(DEF_FILE) != 0)
5442 return (FALSE);
5443 if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
5444 (void) fprintf(stderr, gettext(
5445 "tar: error setting parameters for %s.\n"), DEF_FILE);
5446 return (FALSE); /* & following ones too */
5448 if ((bp = defread(arch)) == NULL) {
5449 (void) fprintf(stderr, gettext(
5450 "tar: missing or invalid '%s' entry in %s.\n"),
5451 arch, DEF_FILE);
5452 return (FALSE);
5454 if ((usefile = strtok(bp, " \t")) == NULL) {
5455 (void) fprintf(stderr, gettext(
5456 "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
5457 return (FALSE);
5459 if ((bp = strtok(NULL, " \t")) == NULL) {
5460 (void) fprintf(stderr, gettext(
5461 "tar: block component missing in '%s' entry in %s.\n"),
5462 arch, DEF_FILE);
5463 return (FALSE);
5465 nblock = bcheck(bp);
5466 if ((bp = strtok(NULL, " \t")) == NULL) {
5467 (void) fprintf(stderr, gettext(
5468 "tar: size component missing in '%s' entry in %s.\n"),
5469 arch, DEF_FILE);
5470 return (FALSE);
5472 blocklim = kcheck(bp);
5473 if ((bp = strtok(NULL, " \t")) != NULL)
5474 NotTape = (*bp == 'n' || *bp == 'N');
5475 else
5476 NotTape = (blocklim != 0);
5477 (void) defopen(NULL);
5478 dlog("defset: archive='%s'; usefile='%s'\n", arch, usefile);
5479 dlog("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
5480 nblock, blocklim);
5481 dlog("defset: not tape = %d\n", NotTape);
5482 return (TRUE);
5487 * Following code handles excluded and included files.
5488 * A hash table of file names to be {in,ex}cluded is built.
5489 * For excluded files, before writing or extracting a file
5490 * check to see if it is in the exclude_tbl.
5491 * For included files, the wantit() procedure will check to
5492 * see if the named file is in the include_tbl.
5495 static void
5496 build_table(file_list_t *table[], char *file)
5498 FILE *fp;
5499 char buf[PATH_MAX + 1];
5501 if ((fp = fopen(file, "r")) == (FILE *)NULL)
5502 vperror(1, gettext("could not open %s"), file);
5503 while (fgets(buf, sizeof (buf), fp) != NULL) {
5504 if (buf[strlen(buf) - 1] == '\n')
5505 buf[strlen(buf) - 1] = '\0';
5506 /* Only add to table if line has something in it */
5507 if (strspn(buf, " \t") != strlen(buf))
5508 add_file_to_table(table, buf);
5510 (void) fclose(fp);
5515 * Add a file name to the the specified table, if the file name has any
5516 * trailing '/'s then delete them before inserting into the table
5519 static void
5520 add_file_to_table(file_list_t *table[], char *str)
5522 char name[PATH_MAX + 1];
5523 unsigned int h;
5524 file_list_t *exp;
5526 (void) strcpy(name, str);
5527 while (name[strlen(name) - 1] == '/') {
5528 name[strlen(name) - 1] = NULL;
5531 h = hash(name);
5532 if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
5533 sizeof (char))) == NULL) {
5534 (void) fprintf(stderr, gettext(
5535 "tar: out of memory, exclude/include table(entry)\n"));
5536 exit(1);
5539 if ((exp->name = strdup(name)) == NULL) {
5540 (void) fprintf(stderr, gettext(
5541 "tar: out of memory, exclude/include table(file name)\n"));
5542 exit(1);
5545 exp->next = table[h];
5546 table[h] = exp;
5551 * See if a file name or any of the file's parent directories is in the
5552 * specified table, if the file name has any trailing '/'s then delete
5553 * them before searching the table
5556 static int
5557 is_in_table(file_list_t *table[], char *str)
5559 char name[PATH_MAX + 1];
5560 unsigned int h;
5561 file_list_t *exp;
5562 char *ptr;
5564 (void) strcpy(name, str);
5565 while (name[strlen(name) - 1] == '/') {
5566 name[strlen(name) - 1] = NULL;
5570 * check for the file name in the passed list
5572 h = hash(name);
5573 exp = table[h];
5574 while (exp != NULL) {
5575 if (strcmp(name, exp->name) == 0) {
5576 return (1);
5578 exp = exp->next;
5582 * check for any parent directories in the file list
5584 while ((ptr = strrchr(name, '/'))) {
5585 *ptr = NULL;
5586 h = hash(name);
5587 exp = table[h];
5588 while (exp != NULL) {
5589 if (strcmp(name, exp->name) == 0) {
5590 return (1);
5592 exp = exp->next;
5596 return (0);
5601 * Compute a hash from a string.
5604 static unsigned int
5605 hash(char *str)
5607 char *cp;
5608 unsigned int h;
5610 h = 0;
5611 for (cp = str; *cp; cp++) {
5612 h += *cp;
5614 return (h % TABLE_SIZE);
5617 static void *
5618 getmem(size_t size)
5620 void *p = calloc((unsigned)size, sizeof (char));
5622 if (p == NULL && freemem) {
5623 (void) fprintf(stderr, gettext(
5624 "tar: out of memory, link and directory modtime "
5625 "info lost\n"));
5626 freemem = 0;
5627 if (errflag)
5628 done(1);
5629 else
5630 Errflg = 1;
5632 return (p);
5636 * vperror() --variable argument perror.
5637 * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
5638 * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5639 * with the value of whatever "errno" is set to. If exit_status is not
5640 * zero, then tar exits with that error status. If errflag and exit_status
5641 * are both zero, the routine returns to where it was called and sets Errflg
5642 * to errno.
5645 static void
5646 vperror(int exit_status, char *fmt, ...)
5648 va_list ap;
5650 va_start(ap, fmt);
5651 (void) fputs("tar: ", stderr);
5652 (void) vfprintf(stderr, fmt, ap);
5653 (void) fprintf(stderr, ": %s\n", strerror(errno));
5654 va_end(ap);
5655 if (exit_status)
5656 done(exit_status);
5657 else
5658 if (errflag)
5659 done(errno);
5660 else
5661 Errflg = errno;
5665 static void
5666 fatal(char *format, ...)
5668 va_list ap;
5670 va_start(ap, format);
5671 (void) fprintf(stderr, "tar: ");
5672 (void) vfprintf(stderr, format, ap);
5673 (void) fprintf(stderr, "\n");
5674 va_end(ap);
5675 done(1);
5680 * Check to make sure that argument is a char * ptr.
5681 * Actually, we just check to see that it is non-null.
5682 * If it is null, print out the message and call usage(), bailing out.
5685 static void
5686 assert_string(char *s, char *msg)
5688 if (s == NULL) {
5689 (void) fprintf(stderr, msg);
5690 usage();
5695 static void
5696 mterr(char *operation, int i, int exitcode)
5698 (void) fprintf(stderr, gettext(
5699 "tar: %s error: "), operation);
5700 if (i < 0)
5701 perror("");
5702 else
5703 (void) fprintf(stderr, gettext("unexpected EOF\n"));
5704 done(exitcode);
5707 static int
5708 wantit(char *argv[], char **namep, char **dirp, char **component,
5709 attr_data_t **attrinfo)
5711 char **cp;
5712 int gotit; /* true if we've found a match */
5713 int ret;
5715 top:
5716 if (xhdr_flgs & _X_XHDR) {
5717 xhdr_flgs = 0;
5719 getdir();
5720 if (Xhdrflag > 0) {
5721 ret = get_xdata();
5722 if (ret != 0) { /* Xhdr items and regular header */
5723 setbytes_to_skip(&stbuf, ret);
5724 passtape();
5725 return (0); /* Error--don't want to extract */
5730 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5731 * of ancillary file is either over or ancillary file
5732 * processing is not required, load info from Xtarhdr and set
5733 * _X_XHDR bit in xhdr_flgs.
5735 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
5736 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
5737 xhdr_flgs |= _X_XHDR;
5740 #if defined(O_XATTR)
5741 if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
5743 * Always needs to read the extended header. If atflag, saflag,
5744 * or tflag isn't set, then we'll have the correct info for
5745 * passtape() later.
5747 (void) read_xattr_hdr(attrinfo);
5748 goto top;
5751 * Now that we've read the extended header, call passtape()
5752 * if we don't want to restore attributes or system attributes.
5753 * Don't restore the attribute if we are extracting
5754 * a file from an archive (as opposed to doing a table of
5755 * contents) and any of the following are true:
5756 * 1. neither -@ or -/ was specified.
5757 * 2. -@ was specified, -/ wasn't specified, and we're
5758 * processing a hidden attribute directory of an attribute
5759 * or we're processing a read-write system attribute file.
5760 * 3. -@ wasn't specified, -/ was specified, and the file
5761 * we're processing is not a read-write system attribute file,
5762 * or we're processing the hidden attribute directory of an
5763 * attribute.
5765 * We always process the attributes if we're just generating
5766 * generating a table of contents, or if both -@ and -/ were
5767 * specified.
5769 if (xattrp != NULL) {
5770 attr_data_t *ainfo = *attrinfo;
5772 if (!tflag &&
5773 ((!atflag && !saflag) ||
5774 (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
5775 ainfo->attr_rw_sysattr)) ||
5776 (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
5777 !ainfo->attr_rw_sysattr)))) {
5778 passtape();
5779 return (0);
5782 #endif
5784 /* sets *namep to point at the proper name */
5785 if (check_prefix(namep, dirp, component) != 0) {
5786 passtape();
5787 return (0);
5790 if (endtape()) {
5791 if (Bflag) {
5792 ssize_t sz;
5793 size_t extra_blocks = 0;
5796 * Logically at EOT - consume any extra blocks
5797 * so that write to our stdin won't fail and
5798 * emit an error message; otherwise something
5799 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5800 * will produce a bogus error message from "dd".
5803 while ((sz = read(mt, tbuf, TBLOCK*nblock)) > 0) {
5804 extra_blocks += sz;
5806 dlog("wantit(): %d bytes of extra blocks\n",
5807 extra_blocks);
5809 dlog("wantit(): at end of tape.\n");
5810 return (-1);
5813 gotit = 0;
5815 if ((Iflag && is_in_table(include_tbl, *namep)) ||
5816 (! Iflag && *argv == NULL)) {
5817 gotit = 1;
5818 } else {
5819 for (cp = argv; *cp; cp++) {
5820 if (is_prefix(*cp, *namep)) {
5821 gotit = 1;
5822 break;
5827 if (! gotit) {
5828 passtape();
5829 return (0);
5832 if (Xflag && is_in_table(exclude_tbl, *namep)) {
5833 if (vflag) {
5834 (void) fprintf(stderr, gettext("%s excluded\n"),
5835 *namep);
5837 passtape();
5838 return (0);
5841 return (1);
5845 static void
5846 setbytes_to_skip(struct stat *st, int err)
5849 * In a scenario where a typeflag 'X' was followed by
5850 * a typeflag 'A' and typeflag 'O', then the number of
5851 * bytes to skip should be the size of ancillary file,
5852 * plus the dblock for regular file, and the size
5853 * from Xtarhdr. However, if the typeflag was just 'X'
5854 * followed by typeflag 'O', then the number of bytes
5855 * to skip should be the size from Xtarhdr.
5857 if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
5858 (xhdr_flgs & _X_SIZE)) {
5859 st->st_size += TBLOCK + Xtarhdr.x_filesz;
5860 xhdr_flgs |= _X_XHDR;
5861 } else if ((dblock.dbuf.typeflag != 'A') &&
5862 (xhdr_flgs & _X_SIZE)) {
5863 st->st_size += Xtarhdr.x_filesz;
5864 xhdr_flgs |= _X_XHDR;
5868 static int
5869 fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
5870 int rw_sysattr, attr_data_t **attrinfo)
5872 size_t pathlen;
5873 char *tpath;
5874 char *tparent;
5876 /* parent info */
5877 if (attrparent != NULL) {
5878 if ((tparent = strdup(attrparent)) == NULL) {
5879 vperror(0, gettext(
5880 "unable to allocate memory for attribute parent "
5881 "name for %sattribute %s/%s of %s"),
5882 rw_sysattr ? gettext("system ") : "",
5883 attrparent, attr, longname);
5884 return (1);
5886 } else {
5887 tparent = NULL;
5890 /* path info */
5891 pathlen = strlen(attr) + 1;
5892 if (attrparent != NULL) {
5893 pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
5895 if ((tpath = calloc(1, pathlen)) == NULL) {
5896 vperror(0, gettext(
5897 "unable to allocate memory for full "
5898 "attribute path name for %sattribute %s%s%s of %s"),
5899 rw_sysattr ? gettext("system ") : "",
5900 (attrparent == NULL) ? "" : attrparent,
5901 (attrparent == NULL) ? "" : "/",
5902 attr, longname);
5903 if (tparent != NULL) {
5904 free(tparent);
5906 return (1);
5908 (void) snprintf(tpath, pathlen, "%s%s%s",
5909 (attrparent == NULL) ? "" : attrparent,
5910 (attrparent == NULL) ? "" : "/",
5911 attr);
5913 /* fill in the attribute info */
5914 if (*attrinfo == NULL) {
5915 if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
5916 vperror(0, gettext(
5917 "unable to allocate memory for attribute "
5918 "information for %sattribute %s%s%s of %s"),
5919 rw_sysattr ? gettext("system ") : "",
5920 (attrparent == NULL) ? "" : attrparent,
5921 (attrparent == NULL) ? "" : gettext("/"),
5922 attr, longname);
5923 if (tparent != NULL) {
5924 free(tparent);
5926 free(tpath);
5927 return (1);
5929 } else {
5930 if ((*attrinfo)->attr_parent != NULL) {
5931 free((*attrinfo)->attr_parent);
5933 if ((*attrinfo)->attr_path != NULL) {
5934 free((*attrinfo)->attr_path);
5937 * The parent file descriptor is passed in, so don't
5938 * close it here as it should be closed by the function
5939 * that opened it.
5942 (*attrinfo)->attr_parent = tparent;
5943 (*attrinfo)->attr_path = tpath;
5944 (*attrinfo)->attr_rw_sysattr = rw_sysattr;
5945 (*attrinfo)->attr_parentfd = atparentfd;
5947 return (0);
5951 * Test to see if name is a directory.
5953 * Return 1 if true, 0 otherwise.
5956 static int
5957 is_directory(char *name)
5959 #if defined(O_XATTR)
5961 * If there is an xattr_buf structure associated with this file,
5962 * then the directory test is based on whether the name has a
5963 * trailing slash.
5965 if (xattrp)
5966 return (name[strlen(name) - 1] == '/');
5967 #endif
5968 if (is_posix)
5969 return (dblock.dbuf.typeflag == '5');
5970 else
5971 return (name[strlen(name) - 1] == '/');
5975 * Version of chdir that handles directory pathnames of greater than PATH_MAX
5976 * length, by changing the working directory to manageable portions of the
5977 * complete directory pathname. If any of these attempts fail, then it exits
5978 * non-zero.
5980 * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
5981 * pathname is greater than PATH_MAX, then this still won't work, and this
5982 * routine will return -1 with errno set to ENAMETOOLONG.
5984 * NOTE: this routine is semantically different to the system chdir in
5985 * that it is remotely possible for the currently working directory to be
5986 * changed to a different directory, if a chdir call fails when processing
5987 * one of the segments of a path that is greater than PATH_MAX. This isn't
5988 * a problem as this is tar's own specific version of chdir.
5991 static int
5992 tar_chdir(const char *path)
5994 const char *sep = "/";
5995 char *path_copy = NULL;
5996 char *ptr = NULL;
5998 /* The trivial case. */
5999 if (chdir(path) == 0) {
6000 return (0);
6002 if (errno == ENAMETOOLONG) {
6003 if (path[0] == '/' && chdir(sep) != 0)
6004 return (-1);
6006 /* strtok(3C) modifies the string, so make a copy. */
6007 if ((path_copy = strdup(path)) == NULL) {
6008 return (-1);
6011 /* chdir(2) for every path element. */
6012 for (ptr = strtok(path_copy, sep);
6013 ptr != NULL;
6014 ptr = strtok(NULL, sep)) {
6015 if (chdir(ptr) != 0) {
6016 free(path_copy);
6017 return (-1);
6020 free(path_copy);
6021 return (0);
6024 /* If chdir fails for any reason except ENAMETOOLONG. */
6025 return (-1);
6029 * Test if name has a '..' sequence in it.
6031 * Return 1 if found, 0 otherwise.
6034 static int
6035 has_dot_dot(char *name)
6037 char *s;
6038 size_t name_len = strlen(name);
6040 for (s = name; s < (name + name_len - 2); s++) {
6041 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
6042 return (1);
6044 while (! (*s == '/')) {
6045 if (! *s++)
6046 return (0);
6050 return (0);
6054 * Test if name is an absolute path name.
6056 * Return 1 if true, 0 otherwise.
6059 static int
6060 is_absolute(char *name)
6062 #if defined(O_XATTR)
6064 * If this is an extended attribute (whose name will begin with
6065 * "/dev/null/", always return 0 as they should be extracted with
6066 * the name intact, to allow other tar archiving programs that
6067 * don't understand extended attributes, to correctly throw them away.
6069 if (xattrp)
6070 return (0);
6071 #endif
6073 return (name[0] == '/');
6077 * Adjust the pathname to make it a relative one. Strip off any leading
6078 * '/' characters and if the pathname contains any '..' sequences, strip
6079 * upto and including the last occurance of '../' (or '..' if found at
6080 * the very end of the pathname).
6082 * Return the relative pathname. stripped_prefix will also return the
6083 * portion of name that was stripped off and should be freed by the
6084 * calling routine when no longer needed.
6087 static char *
6088 make_relative_name(char *name, char **stripped_prefix)
6090 char *s;
6091 size_t prefix_len = 0;
6092 size_t name_len = strlen(name);
6094 for (s = name + prefix_len; s < (name + name_len - 2); ) {
6095 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
6096 prefix_len = s + 2 - name;
6098 do {
6099 char c = *s++;
6101 if (c == '/')
6102 break;
6103 } while (*s);
6106 for (s = name + prefix_len; *s == '/'; s++)
6107 continue;
6108 prefix_len = s - name;
6110 /* Create the portion of the name that was stripped off. */
6111 s = malloc(prefix_len + 1);
6112 memcpy(s, name, prefix_len);
6113 s[prefix_len] = 0;
6114 *stripped_prefix = s;
6115 s = &name[prefix_len];
6117 return (s);
6121 * Return through *namep a pointer to the proper fullname (i.e "<name> |
6122 * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6124 * Returns 0 if successful, otherwise returns 1.
6127 static int
6128 check_prefix(char **namep, char **dirp, char **compp)
6130 static char fullname[PATH_MAX + 1];
6131 static char dir[PATH_MAX + 1];
6132 static char component[PATH_MAX + 1];
6133 static char savename[PATH_MAX + 1];
6134 char *s;
6136 (void) memset(dir, 0, sizeof (dir));
6137 (void) memset(component, 0, sizeof (component));
6139 if (xhdr_flgs & _X_PATH) {
6140 (void) strcpy(fullname, Xtarhdr.x_path);
6141 } else {
6142 if (dblock.dbuf.prefix[0] != '\0')
6143 (void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
6144 dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
6145 else
6146 (void) sprintf(fullname, "%.*s", NAMSIZ,
6147 dblock.dbuf.name);
6151 * If we are printing a table of contents or extracting an archive,
6152 * make absolute pathnames relative and prohibit the unpacking of
6153 * files contain ".." in their name (unless the user has supplied
6154 * the -P option).
6156 if ((tflag || xflag) && !Pflag) {
6157 if (is_absolute(fullname) || has_dot_dot(fullname)) {
6158 char *stripped_prefix;
6160 (void) strcpy(savename, fullname);
6161 strcpy(fullname,
6162 make_relative_name(savename, &stripped_prefix));
6163 (void) fprintf(stderr,
6164 gettext("tar: Removing leading '%s' from '%s'\n"),
6165 stripped_prefix, savename);
6166 free(stripped_prefix);
6171 * Set dir and component names
6174 get_parent(fullname, dir);
6176 #if defined(O_XATTR)
6177 if (xattrp == NULL) {
6178 #endif
6180 * Save of real name since were going to chop off the
6181 * trailing slashes.
6183 (void) strcpy(savename, fullname);
6185 * first strip of trailing slashes.
6187 chop_endslashes(savename);
6188 s = get_component(savename);
6189 (void) strcpy(component, s);
6191 #if defined(O_XATTR)
6192 } else {
6193 (void) strcpy(fullname, xattrp->h_names);
6194 (void) strcpy(dir, fullname);
6195 (void) strcpy(component, basename(xattrp->h_names +
6196 strlen(xattrp->h_names) + 1));
6198 #endif
6199 *namep = fullname;
6200 *dirp = dir;
6201 *compp = component;
6203 return (0);
6207 * Return true if the object indicated by the file descriptor and type
6208 * is a tape device, false otherwise
6211 static int
6212 istape(int fd, int type)
6214 int result = 0;
6216 if (S_ISCHR(type)) {
6217 struct mtget mtg;
6219 if (ioctl(fd, MTIOCGET, &mtg) != -1) {
6220 result = 1;
6224 return (result);
6227 #include <utmpx.h>
6229 struct utmpx utmpx;
6231 #define NMAX (sizeof (utmpx.ut_name))
6233 typedef struct cachenode { /* this struct must be zeroed before using */
6234 struct cachenode *next; /* next in hash chain */
6235 int val; /* the uid or gid of this entry */
6236 int namehash; /* name's hash signature */
6237 char name[NMAX+1]; /* the string that val maps to */
6238 } cachenode_t;
6240 #define HASHSIZE 256
6242 static cachenode_t *names[HASHSIZE];
6243 static cachenode_t *groups[HASHSIZE];
6244 static cachenode_t *uids[HASHSIZE];
6245 static cachenode_t *gids[HASHSIZE];
6247 static int
6248 hash_byname(char *name)
6250 int i, c, h = 0;
6252 for (i = 0; i < NMAX; i++) {
6253 c = name[i];
6254 if (c == '\0')
6255 break;
6256 h = (h << 4) + h + c;
6258 return (h);
6261 static cachenode_t *
6262 hash_lookup_byval(cachenode_t *table[], int val)
6264 int h = val;
6265 cachenode_t *c;
6267 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6268 if (c->val == val)
6269 return (c);
6271 return (NULL);
6274 static cachenode_t *
6275 hash_lookup_byname(cachenode_t *table[], char *name)
6277 int h = hash_byname(name);
6278 cachenode_t *c;
6280 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6281 if (c->namehash == h && strcmp(c->name, name) == 0)
6282 return (c);
6284 return (NULL);
6287 static cachenode_t *
6288 hash_insert(cachenode_t *table[], char *name, int value)
6290 cachenode_t *c;
6291 int signature;
6293 c = calloc(1, sizeof (cachenode_t));
6294 if (c == NULL) {
6295 perror("malloc");
6296 exit(1);
6298 if (name != NULL) {
6299 (void) strncpy(c->name, name, NMAX);
6300 c->namehash = hash_byname(name);
6302 c->val = value;
6303 if (table == uids || table == gids)
6304 signature = c->val;
6305 else
6306 signature = c->namehash;
6307 c->next = table[signature & (HASHSIZE - 1)];
6308 table[signature & (HASHSIZE - 1)] = c;
6309 return (c);
6312 static char *
6313 getname(uid_t uid)
6315 cachenode_t *c;
6317 if ((c = hash_lookup_byval(uids, uid)) == NULL) {
6318 struct passwd *pwent = getpwuid(uid);
6319 c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
6321 return (c->name);
6324 static char *
6325 getgroup(gid_t gid)
6327 cachenode_t *c;
6329 if ((c = hash_lookup_byval(gids, gid)) == NULL) {
6330 struct group *grent = getgrgid(gid);
6331 c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
6333 return (c->name);
6336 static uid_t
6337 getuidbyname(char *name)
6339 cachenode_t *c;
6341 if ((c = hash_lookup_byname(names, name)) == NULL) {
6342 struct passwd *pwent = getpwnam(name);
6343 c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
6345 return ((uid_t)c->val);
6348 static gid_t
6349 getgidbyname(char *group)
6351 cachenode_t *c;
6353 if ((c = hash_lookup_byname(groups, group)) == NULL) {
6354 struct group *grent = getgrnam(group);
6355 c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
6357 return ((gid_t)c->val);
6361 * Build the header.
6362 * Determine whether or not an extended header is also needed. If needed,
6363 * create and write the extended header and its data.
6364 * Writing of the extended header assumes that "tomodes" has been called and
6365 * the relevant information has been placed in the header block.
6368 static int
6369 build_dblock(
6370 const char *name,
6371 const char *linkname,
6372 const char typeflag,
6373 const int filetype,
6374 const struct stat *sp,
6375 const dev_t device,
6376 const char *prefix)
6378 int nblks;
6379 major_t dev;
6380 const char *filename;
6381 const char *lastslash;
6383 if (filetype == XATTR_FILE)
6384 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
6385 else
6386 dblock.dbuf.typeflag = typeflag;
6387 (void) memset(dblock.dbuf.name, '\0', NAMSIZ);
6388 (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
6389 (void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
6391 if (xhdr_flgs & _X_PATH)
6392 filename = Xtarhdr.x_path;
6393 else
6394 filename = name;
6396 if ((dev = major(device)) > OCTAL7CHAR) {
6397 if (Eflag) {
6398 xhdr_flgs |= _X_DEVMAJOR;
6399 Xtarhdr.x_devmajor = dev;
6400 } else {
6401 (void) fprintf(stderr, gettext(
6402 "Device major too large for %s. Use -E flag."),
6403 filename);
6404 if (errflag)
6405 done(1);
6406 else
6407 Errflg = 1;
6409 dev = 0;
6411 (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
6412 if ((dev = minor(device)) > OCTAL7CHAR) {
6413 if (Eflag) {
6414 xhdr_flgs |= _X_DEVMINOR;
6415 Xtarhdr.x_devminor = dev;
6416 } else {
6417 (void) fprintf(stderr, gettext(
6418 "Device minor too large for %s. Use -E flag."),
6419 filename);
6420 if (errflag)
6421 done(1);
6422 else
6423 Errflg = 1;
6425 dev = 0;
6427 (void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
6429 (void) strncpy(dblock.dbuf.name, name, NAMSIZ);
6430 (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
6431 (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
6432 (void) sprintf(dblock.dbuf.version, "00");
6433 (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
6434 (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
6435 (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
6436 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
6438 if (Eflag) {
6439 (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
6440 (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
6441 lastslash = strrchr(name, '/');
6442 if (lastslash == NULL)
6443 lastslash = name;
6444 else
6445 lastslash++;
6446 (void) strcpy(xhdr_buf.dbuf.name, lastslash);
6447 (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
6448 (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
6449 (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
6450 xhdr_count++;
6451 xrec_offset = 0;
6452 gen_date("mtime", sp->st_mtim);
6453 xhdr_buf.dbuf.typeflag = 'X';
6454 if (gen_utf8_names(filename) != 0)
6455 return (1);
6457 #ifdef XHDR_DEBUG
6458 Xtarhdr.x_uname = dblock.dbuf.uname;
6459 Xtarhdr.x_gname = dblock.dbuf.gname;
6460 xhdr_flgs |= (_X_UNAME | _X_GNAME);
6461 #endif
6462 if (xhdr_flgs) {
6463 if (xhdr_flgs & _X_DEVMAJOR)
6464 gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
6465 if (xhdr_flgs & _X_DEVMINOR)
6466 gen_num("SUN.devminor", Xtarhdr.x_devminor);
6467 if (xhdr_flgs & _X_GID)
6468 gen_num("gid", Xtarhdr.x_gid);
6469 if (xhdr_flgs & _X_UID)
6470 gen_num("uid", Xtarhdr.x_uid);
6471 if (xhdr_flgs & _X_SIZE)
6472 gen_num("size", Xtarhdr.x_filesz);
6473 if (xhdr_flgs & _X_PATH)
6474 gen_string("path", Xtarhdr.x_path);
6475 if (xhdr_flgs & _X_LINKPATH)
6476 gen_string("linkpath", Xtarhdr.x_linkpath);
6477 if (xhdr_flgs & _X_GNAME)
6478 gen_string("gname", Xtarhdr.x_gname);
6479 if (xhdr_flgs & _X_UNAME)
6480 gen_string("uname", Xtarhdr.x_uname);
6482 (void) sprintf(xhdr_buf.dbuf.size,
6483 "%011" FMT_off_t_o, xrec_offset);
6484 (void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
6485 checksum(&xhdr_buf));
6486 (void) writetbuf((char *)&xhdr_buf, 1);
6487 nblks = TBLOCKS(xrec_offset);
6488 (void) writetbuf(xrec_ptr, nblks);
6490 return (0);
6495 * makeDir - ensure that a directory with the pathname denoted by name
6496 * exists, and return 1 on success, and 0 on failure (e.g.,
6497 * read-only file system, exists but not-a-directory).
6500 static int
6501 makeDir(char *name)
6503 struct stat buf;
6505 if (access(name, 0) < 0) { /* name doesn't exist */
6506 if (mkdir(name, 0777) < 0) {
6507 vperror(0, "%s", name);
6508 return (0);
6510 } else { /* name exists */
6511 if (stat(name, &buf) < 0) {
6512 vperror(0, "%s", name);
6513 return (0);
6516 return ((buf.st_mode & S_IFMT) == S_IFDIR);
6519 return (1);
6524 * Save this directory and its mtime on the stack, popping and setting
6525 * the mtimes of any stacked dirs which aren't parents of this one.
6526 * A null name causes the entire stack to be unwound and set.
6528 * Since all the elements of the directory "stack" share a common
6529 * prefix, we can make do with one string. We keep only the current
6530 * directory path, with an associated array of mtime's. A negative
6531 * mtime means no mtime.
6533 * This stack algorithm is not guaranteed to work for tapes created
6534 * with the 'r' function letter, but the vast majority of tapes with
6535 * directories are not. This avoids saving every directory record on
6536 * the tape and setting all the times at the end.
6538 * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6539 * environment)
6542 static void
6543 doDirTimes(char *name, timestruc_t modTime)
6545 static char dirstack[PATH_MAX+2];
6546 /* Add spaces for the last slash and last NULL */
6547 static timestruc_t modtimes[PATH_MAX+1]; /* hash table */
6548 char *p = dirstack;
6549 char *q = name;
6550 char *savp;
6552 if (q) {
6554 * Find common prefix
6557 while (*p == *q && *p) {
6558 p++; q++;
6562 savp = p;
6563 while (*p) {
6565 * Not a child: unwind the stack, setting the times.
6566 * The order we do this doesn't matter, so we go "forward."
6569 if (*p == '/')
6570 if (modtimes[p - dirstack].tv_sec >= 0) {
6571 *p = '\0'; /* zap the slash */
6572 setPathTimes(AT_FDCWD, dirstack,
6573 modtimes[p - dirstack]);
6574 *p = '/';
6576 ++p;
6579 p = savp;
6582 * Push this one on the "stack"
6585 if (q) {
6588 * Since the name parameter points the dir pathname
6589 * which is limited only to contain PATH_MAX chars
6590 * at maximum, we can ignore the overflow case of p.
6593 while ((*p = *q++)) { /* append the rest of the new dir */
6594 modtimes[p - dirstack].tv_sec = -1;
6595 p++;
6599 * If the tar file had used 'P' or 'E' function modifier,
6600 * append the last slash.
6602 if (*(p - 1) != '/') {
6603 *p++ = '/';
6604 *p = '\0';
6606 /* overwrite the last one */
6607 modtimes[p - dirstack - 1] = modTime;
6613 * setPathTimes - set the modification time for given path. Return 1 if
6614 * successful and 0 if not successful.
6617 static void
6618 setPathTimes(int dirfd, char *path, timestruc_t modTime)
6620 struct timeval timebuf[2];
6623 * futimesat takes an array of two timeval structs.
6624 * The first entry contains access time.
6625 * The second entry contains modification time.
6626 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6627 * microseconds.
6629 timebuf[0].tv_sec = time((time_t *)0);
6630 timebuf[0].tv_usec = 0;
6631 timebuf[1].tv_sec = modTime.tv_sec;
6633 /* Extended header: use microseconds */
6634 timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
6636 if (futimesat(dirfd, path, timebuf) < 0)
6637 vperror(0, gettext("can't set time on %s"), path);
6642 * If hflag is set then delete the symbolic link's target.
6643 * If !hflag then delete the target.
6646 static void
6647 delete_target(int fd, char *comp, char *namep)
6649 struct stat xtractbuf;
6650 char buf[PATH_MAX + 1];
6651 int n;
6654 if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
6655 if (errno == ENOTDIR && !hflag) {
6656 (void) unlinkat(fd, comp, 0);
6657 } else if (errno == ENOTDIR && hflag) {
6658 if (!lstat(namep, &xtractbuf)) {
6659 if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
6660 (void) unlinkat(fd, comp, 0);
6661 } else if ((n = readlink(namep, buf,
6662 PATH_MAX)) != -1) {
6663 buf[n] = (char)NULL;
6664 (void) unlinkat(fd, buf,
6665 AT_REMOVEDIR);
6666 if (errno == ENOTDIR)
6667 (void) unlinkat(fd, buf, 0);
6668 } else {
6669 (void) unlinkat(fd, comp, 0);
6671 } else {
6672 (void) unlinkat(fd, comp, 0);
6680 * ACL changes:
6681 * putfile():
6682 * Get acl info after stat. Write out ancillary file
6683 * before the normal file, i.e. directory, regular, FIFO,
6684 * link, special. If acl count is less than 4, no need to
6685 * create ancillary file. (i.e. standard permission is in
6686 * use.
6687 * doxtract():
6688 * Process ancillary file. Read it in and set acl info.
6689 * watch out for 'o' function modifier.
6690 * 't' function letter to display table
6694 * New functions for ACLs and other security attributes
6698 * The function appends the new security attribute info to the end of
6699 * existing secinfo.
6702 append_secattr(
6703 char **secinfo, /* existing security info */
6704 int *secinfo_len, /* length of existing security info */
6705 int size, /* new attribute size: unit depends on type */
6706 char *attrtext, /* new attribute text */
6707 char attr_type) /* new attribute type */
6709 char *new_secinfo;
6710 int newattrsize;
6711 int oldsize;
6712 struct sec_attr *attr;
6714 /* no need to add */
6715 if (attr_type != DIR_TYPE) {
6716 if (attrtext == NULL)
6717 return (0);
6720 switch (attr_type) {
6721 case UFSD_ACL:
6722 case ACE_ACL:
6723 if (attrtext == NULL) {
6724 (void) fprintf(stderr, gettext("acltotext failed\n"));
6725 return (-1);
6727 /* header: type + size = 8 */
6728 newattrsize = 8 + (int)strlen(attrtext) + 1;
6729 attr = (struct sec_attr *)malloc(newattrsize);
6730 if (attr == NULL) {
6731 (void) fprintf(stderr,
6732 gettext("can't allocate memory\n"));
6733 return (-1);
6735 attr->attr_type = attr_type;
6736 (void) sprintf(attr->attr_len,
6737 "%06o", size); /* acl entry count */
6738 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6739 free(attrtext);
6740 break;
6742 /* Trusted Extensions */
6743 case DIR_TYPE:
6744 case LBL_TYPE:
6745 newattrsize = sizeof (struct sec_attr) + strlen(attrtext);
6746 attr = (struct sec_attr *)malloc(newattrsize);
6747 if (attr == NULL) {
6748 (void) fprintf(stderr,
6749 gettext("can't allocate memory\n"));
6750 return (-1);
6752 attr->attr_type = attr_type;
6753 (void) sprintf(attr->attr_len,
6754 "%06d", size); /* len of attr data */
6755 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6756 break;
6758 default:
6759 (void) fprintf(stderr,
6760 gettext("unrecognized attribute type\n"));
6761 return (-1);
6764 /* old security info + new attr header(8) + new attr */
6765 oldsize = *secinfo_len;
6766 *secinfo_len += newattrsize;
6767 new_secinfo = (char *)malloc(*secinfo_len);
6768 if (new_secinfo == NULL) {
6769 (void) fprintf(stderr, gettext("can't allocate memory\n"));
6770 *secinfo_len -= newattrsize;
6771 free(attr);
6772 return (-1);
6775 (void) memcpy(new_secinfo, *secinfo, oldsize);
6776 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6778 free(*secinfo);
6779 free(attr);
6780 *secinfo = new_secinfo;
6781 return (0);
6785 * write_ancillary(): write out an ancillary file.
6786 * The file has the same header as normal file except the type and size
6787 * fields. The type is 'A' and size is the sum of all attributes
6788 * in bytes.
6789 * The body contains a list of attribute type, size and info. Currently,
6790 * there is only ACL info. This file is put before the normal file.
6792 void
6793 write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
6795 long blocks;
6796 int savflag;
6797 int savsize;
6799 /* Just tranditional permissions or no security attribute info */
6800 if (len == 0 || secinfo == NULL)
6801 return;
6803 /* save flag and size */
6804 savflag = (dblockp->dbuf).typeflag;
6805 (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
6807 /* special flag for ancillary file */
6808 if (hdrtype == _XATTR_HDRTYPE)
6809 dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
6810 else
6811 dblockp->dbuf.typeflag = 'A';
6813 /* for pre-2.5 versions of tar, need to make sure */
6814 /* the ACL file is readable */
6815 (void) sprintf(dblock.dbuf.mode, "%07lo",
6816 (stbuf.st_mode & POSIXMODES) | 0000200);
6817 (void) sprintf(dblockp->dbuf.size, "%011o", len);
6818 (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
6820 /* write out the header */
6821 (void) writetbuf((char *)dblockp, 1);
6823 /* write out security info */
6824 blocks = TBLOCKS(len);
6825 (void) writetbuf((char *)secinfo, (int)blocks);
6827 /* restore mode, flag and size */
6828 (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
6829 dblockp->dbuf.typeflag = savflag;
6830 (void) sprintf(dblockp->dbuf.size, "%011o", savsize);
6834 * Read the data record for extended headers and then the regular header.
6835 * The data are read into the buffer and then null-terminated. Entries
6836 * for typeflag 'X' extended headers are of the format:
6837 * "%d %s=%s\n"
6839 * When an extended header record is found, the extended header must
6840 * be processed and its values used to override the values in the
6841 * normal header. The way this is done is to process the extended
6842 * header data record and set the data values, then call getdir
6843 * to process the regular header, then then to reconcile the two
6844 * sets of data.
6847 static int
6848 get_xdata(void)
6850 struct keylist_pair {
6851 int keynum;
6852 char *keylist;
6853 } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor",
6854 _X_DEVMINOR, "SUN.devminor",
6855 _X_GID, "gid",
6856 _X_GNAME, "gname",
6857 _X_LINKPATH, "linkpath",
6858 _X_PATH, "path",
6859 _X_SIZE, "size",
6860 _X_UID, "uid",
6861 _X_UNAME, "uname",
6862 _X_MTIME, "mtime",
6863 _X_LAST, "NULL" };
6864 char *lineloc;
6865 int length, i;
6866 char *keyword, *value;
6867 blkcnt_t nblocks;
6868 int bufneeded;
6869 int errors;
6871 (void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
6872 xhdr_count++;
6873 errors = 0;
6875 nblocks = TBLOCKS(stbuf.st_size);
6876 bufneeded = nblocks * TBLOCK;
6877 if (bufneeded >= xrec_size) {
6878 free(xrec_ptr);
6879 xrec_size = bufneeded + 1;
6880 if ((xrec_ptr = malloc(xrec_size)) == NULL)
6881 fatal(gettext("cannot allocate buffer"));
6884 lineloc = xrec_ptr;
6886 while (nblocks-- > 0) {
6887 readtape(lineloc);
6888 lineloc += TBLOCK;
6890 lineloc = xrec_ptr;
6891 xrec_ptr[stbuf.st_size] = '\0';
6892 while (lineloc < xrec_ptr + stbuf.st_size) {
6893 if (dblock.dbuf.typeflag == 'L') {
6894 length = xrec_size;
6895 keyword = "path";
6896 value = lineloc;
6897 } else {
6898 length = atoi(lineloc);
6899 *(lineloc + length - 1) = '\0';
6900 keyword = strchr(lineloc, ' ') + 1;
6901 value = strchr(keyword, '=') + 1;
6902 *(value - 1) = '\0';
6904 i = 0;
6905 lineloc += length;
6906 while (keylist_pair[i].keynum != (int)_X_LAST) {
6907 if (strcmp(keyword, keylist_pair[i].keylist) == 0)
6908 break;
6909 i++;
6911 errno = 0;
6912 switch (keylist_pair[i].keynum) {
6913 case _X_DEVMAJOR:
6914 Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
6915 if (errno) {
6916 (void) fprintf(stderr, gettext(
6917 "tar: Extended header major value error "
6918 "for file # %llu.\n"), xhdr_count);
6919 errors++;
6920 } else
6921 xhdr_flgs |= _X_DEVMAJOR;
6922 break;
6923 case _X_DEVMINOR:
6924 Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
6925 if (errno) {
6926 (void) fprintf(stderr, gettext(
6927 "tar: Extended header minor value error "
6928 "for file # %llu.\n"), xhdr_count);
6929 errors++;
6930 } else
6931 xhdr_flgs |= _X_DEVMINOR;
6932 break;
6933 case _X_GID:
6934 xhdr_flgs |= _X_GID;
6935 Xtarhdr.x_gid = strtol(value, NULL, 0);
6936 if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
6937 (void) fprintf(stderr, gettext(
6938 "tar: Extended header gid value error "
6939 "for file # %llu.\n"), xhdr_count);
6940 Xtarhdr.x_gid = GID_NOBODY;
6942 break;
6943 case _X_GNAME:
6944 if (utf8_local("gname", &Xtarhdr.x_gname,
6945 local_gname, value, _POSIX_NAME_MAX) == 0)
6946 xhdr_flgs |= _X_GNAME;
6947 break;
6948 case _X_LINKPATH:
6949 if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
6950 local_linkpath, value, PATH_MAX) == 0)
6951 xhdr_flgs |= _X_LINKPATH;
6952 else
6953 errors++;
6954 break;
6955 case _X_PATH:
6956 if (utf8_local("path", &Xtarhdr.x_path,
6957 local_path, value, PATH_MAX) == 0)
6958 xhdr_flgs |= _X_PATH;
6959 else
6960 errors++;
6961 break;
6962 case _X_SIZE:
6963 Xtarhdr.x_filesz = strtoull(value, NULL, 0);
6964 if (errno) {
6965 (void) fprintf(stderr, gettext(
6966 "tar: Extended header invalid filesize "
6967 "for file # %llu.\n"), xhdr_count);
6968 errors++;
6969 } else
6970 xhdr_flgs |= _X_SIZE;
6971 break;
6972 case _X_UID:
6973 xhdr_flgs |= _X_UID;
6974 Xtarhdr.x_uid = strtol(value, NULL, 0);
6975 if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
6976 (void) fprintf(stderr, gettext(
6977 "tar: Extended header uid value error "
6978 "for file # %llu.\n"), xhdr_count);
6979 Xtarhdr.x_uid = UID_NOBODY;
6981 break;
6982 case _X_UNAME:
6983 if (utf8_local("uname", &Xtarhdr.x_uname,
6984 local_uname, value, _POSIX_NAME_MAX) == 0)
6985 xhdr_flgs |= _X_UNAME;
6986 break;
6987 case _X_MTIME:
6988 get_xtime(value, &(Xtarhdr.x_mtime));
6989 if (errno)
6990 (void) fprintf(stderr, gettext(
6991 "tar: Extended header modification time "
6992 "value error for file # %llu.\n"),
6993 xhdr_count);
6994 else
6995 xhdr_flgs |= _X_MTIME;
6996 break;
6997 default:
6998 (void) fprintf(stderr,
6999 gettext("tar: unrecognized extended"
7000 " header keyword '%s'. Ignored.\n"), keyword);
7001 break;
7005 getdir(); /* get regular header */
7006 if (errors && errflag)
7007 done(1);
7008 else
7009 if (errors)
7010 Errflg = 1;
7011 return (errors);
7015 * load_info_from_xtarhdr - sets Gen and stbuf variables from
7016 * extended header
7017 * load_info_from_xtarhdr(flag, xhdrp);
7018 * u_longlong_t flag; xhdr_flgs
7019 * struct xtar_hdr *xhdrp; pointer to extended header
7020 * NOTE: called when typeflag is not 'A' and xhdr_flgs
7021 * is set.
7023 static void
7024 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
7026 if (flag & _X_DEVMAJOR) {
7027 Gen.g_devmajor = xhdrp->x_devmajor;
7029 if (flag & _X_DEVMINOR) {
7030 Gen.g_devminor = xhdrp->x_devminor;
7032 if (flag & _X_GID) {
7033 Gen.g_gid = xhdrp->x_gid;
7034 stbuf.st_gid = xhdrp->x_gid;
7036 if (flag & _X_UID) {
7037 Gen.g_uid = xhdrp->x_uid;
7038 stbuf.st_uid = xhdrp->x_uid;
7040 if (flag & _X_SIZE) {
7041 Gen.g_filesz = xhdrp->x_filesz;
7042 stbuf.st_size = xhdrp->x_filesz;
7044 if (flag & _X_MTIME) {
7045 Gen.g_mtime = xhdrp->x_mtime.tv_sec;
7046 stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
7047 stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
7052 * gen_num creates a string from a keyword and an usigned long long in the
7053 * format: %d %s=%s\n
7054 * This is part of the extended header data record.
7057 void
7058 gen_num(const char *keyword, const u_longlong_t number)
7060 char save_val[ULONGLONG_MAX_DIGITS + 1];
7061 int len;
7062 char *curr_ptr;
7064 (void) sprintf(save_val, "%llu", number);
7066 * len = length of entire line, including itself. len will be
7067 * two digits. So, add the string lengths plus the length of len,
7068 * plus a blank, an equal sign, and a newline.
7070 len = strlen(save_val) + strlen(keyword) + 5;
7071 if (xrec_offset + len > xrec_size) {
7072 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7073 fatal(gettext(
7074 "cannot allocate extended header buffer"));
7075 xrec_ptr = curr_ptr;
7076 xrec_size *= 2;
7078 (void) sprintf(&xrec_ptr[xrec_offset],
7079 "%d %s=%s\n", len, keyword, save_val);
7080 xrec_offset += len;
7084 * gen_date creates a string from a keyword and a timestruc_t in the
7085 * format: %d %s=%s\n
7086 * This is part of the extended header data record.
7087 * Currently, granularity is only microseconds, so the low-order three digits
7088 * will be truncated.
7091 void
7092 gen_date(const char *keyword, const timestruc_t time_value)
7094 /* Allow for <seconds>.<nanoseconds>\n */
7095 char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
7096 int len;
7097 char *curr_ptr;
7099 (void) sprintf(save_val, "%ld", time_value.tv_sec);
7100 len = strlen(save_val);
7101 save_val[len] = '.';
7102 (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
7105 * len = length of entire line, including itself. len will be
7106 * two digits. So, add the string lengths plus the length of len,
7107 * plus a blank, an equal sign, and a newline.
7109 len = strlen(save_val) + strlen(keyword) + 5;
7110 if (xrec_offset + len > xrec_size) {
7111 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7112 fatal(gettext(
7113 "cannot allocate extended header buffer"));
7114 xrec_ptr = curr_ptr;
7115 xrec_size *= 2;
7117 (void) sprintf(&xrec_ptr[xrec_offset],
7118 "%d %s=%s\n", len, keyword, save_val);
7119 xrec_offset += len;
7123 * gen_string creates a string from a keyword and a char * in the
7124 * format: %d %s=%s\n
7125 * This is part of the extended header data record.
7128 void
7129 gen_string(const char *keyword, const char *value)
7131 int len;
7132 char *curr_ptr;
7135 * len = length of entire line, including itself. The character length
7136 * of len must be 1-4 characters, because the maximum size of the path
7137 * or the name is PATH_MAX, which is 1024. So, assume 1 character
7138 * for len, one for the space, one for the "=", and one for the newline.
7139 * Then adjust as needed.
7141 /* LINTED constant expression */
7142 assert(PATH_MAX <= 9996);
7143 len = strlen(value) + strlen(keyword) + 4;
7144 if (len > 997)
7145 len += 3;
7146 else if (len > 98)
7147 len += 2;
7148 else if (len > 9)
7149 len += 1;
7150 if (xrec_offset + len > xrec_size) {
7151 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7152 fatal(gettext(
7153 "cannot allocate extended header buffer"));
7154 xrec_ptr = curr_ptr;
7155 xrec_size *= 2;
7157 #ifdef XHDR_DEBUG
7158 if (strcmp(keyword+1, "name") != 0)
7159 #endif
7160 (void) sprintf(&xrec_ptr[xrec_offset],
7161 "%d %s=%s\n", len, keyword, value);
7162 #ifdef XHDR_DEBUG
7163 else {
7164 len += 11;
7165 (void) sprintf(&xrec_ptr[xrec_offset],
7166 "%d %s=%snametoolong\n", len, keyword, value);
7168 #endif
7169 xrec_offset += len;
7173 * Convert time found in the extended header data to seconds and nanoseconds.
7176 void
7177 get_xtime(char *value, timestruc_t *xtime)
7179 char nanosec[10];
7180 char *period;
7181 int i;
7183 (void) memset(nanosec, '0', 9);
7184 nanosec[9] = '\0';
7186 period = strchr(value, '.');
7187 if (period != NULL)
7188 period[0] = '\0';
7189 xtime->tv_sec = strtol(value, NULL, 10);
7190 if (period == NULL)
7191 xtime->tv_nsec = 0;
7192 else {
7193 i = strlen(period +1);
7194 (void) strncpy(nanosec, period + 1, min(i, 9));
7195 xtime->tv_nsec = strtol(nanosec, NULL, 10);
7200 * Check linkpath for length.
7201 * Emit an error message and return 1 if too long.
7205 chk_path_build(
7206 char *name,
7207 char *longname,
7208 char *linkname,
7209 char *prefix,
7210 char type,
7211 int filetype)
7214 if (strlen(linkname) > (size_t)NAMSIZ) {
7215 if (Eflag > 0) {
7216 xhdr_flgs |= _X_LINKPATH;
7217 Xtarhdr.x_linkpath = linkname;
7218 } else {
7219 (void) fprintf(stderr, gettext(
7220 "tar: %s: linked to %s\n"), longname, linkname);
7221 (void) fprintf(stderr, gettext(
7222 "tar: %s: linked name too long\n"), linkname);
7223 if (errflag)
7224 done(1);
7225 else
7226 Errflg = 1;
7227 return (1);
7230 if (xhdr_flgs & _X_LINKPATH)
7231 return (build_dblock(name, tchar, type,
7232 filetype, &stbuf, stbuf.st_dev,
7233 prefix));
7234 else
7235 return (build_dblock(name, linkname, type,
7236 filetype, &stbuf, stbuf.st_dev, prefix));
7240 * Convert from UTF-8 to local character set.
7243 static int
7244 utf8_local(
7245 char *option,
7246 char **Xhdr_ptrptr,
7247 char *target,
7248 const char *source,
7249 int max_val)
7251 static iconv_t iconv_cd;
7252 char *nl_target;
7253 const char *iconv_src;
7254 char *iconv_trg;
7255 size_t inlen;
7256 size_t outlen;
7258 if (charset_type == -1) { /* iconv_open failed in earlier try */
7259 (void) fprintf(stderr, gettext(
7260 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7261 xhdr_count, source);
7262 return (1);
7263 } else if (charset_type == 0) { /* iconv_open has not yet been done */
7264 nl_target = nl_langinfo(CODESET);
7265 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7266 nl_target = "646";
7267 if (strcmp(nl_target, "646") == 0)
7268 charset_type = 1;
7269 else if (strcmp(nl_target, "UTF-8") == 0)
7270 charset_type = 3;
7271 else {
7272 if (strncmp(nl_target, "ISO", 3) == 0)
7273 nl_target += 3;
7274 charset_type = 2;
7275 errno = 0;
7276 if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
7277 (iconv_t)-1) {
7278 if (errno == EINVAL)
7279 (void) fprintf(stderr, gettext(
7280 "tar: conversion routines not "
7281 "available for current locale. "));
7282 (void) fprintf(stderr, gettext(
7283 "file # %llu: (%s) UTF-8 conversion"
7284 " failed.\n"), xhdr_count, source);
7285 charset_type = -1;
7286 return (1);
7291 /* locale using 7-bit codeset or UTF-8 locale */
7292 if (charset_type == 1 || charset_type == 3) {
7293 if (strlen(source) > max_val) {
7294 (void) fprintf(stderr, gettext(
7295 "tar: file # %llu: Extended header %s too long.\n"),
7296 xhdr_count, option);
7297 return (1);
7299 if (charset_type == 3)
7300 (void) strcpy(target, source);
7301 else if (c_utf8(target, source) != 0) {
7302 (void) fprintf(stderr, gettext(
7303 "tar: file # %llu: (%s) UTF-8 conversion"
7304 " failed.\n"), xhdr_count, source);
7305 return (1);
7307 *Xhdr_ptrptr = target;
7308 return (0);
7311 iconv_src = source;
7312 iconv_trg = target;
7313 inlen = strlen(source);
7314 outlen = max_val * UTF_8_FACTOR;
7315 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7316 (size_t)-1) { /* Error occurred: didn't convert */
7317 (void) fprintf(stderr, gettext(
7318 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7319 xhdr_count, source);
7320 /* Get remaining output; reinitialize conversion descriptor */
7321 iconv_src = (const char *)NULL;
7322 inlen = 0;
7323 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7324 return (1);
7326 /* Get remaining output; reinitialize conversion descriptor */
7327 iconv_src = (const char *)NULL;
7328 inlen = 0;
7329 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7330 (size_t)-1) { /* Error occurred: didn't convert */
7331 (void) fprintf(stderr, gettext(
7332 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7333 xhdr_count, source);
7334 return (1);
7337 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7338 if (strlen(target) > max_val) {
7339 (void) fprintf(stderr, gettext(
7340 "tar: file # %llu: Extended header %s too long.\n"),
7341 xhdr_count, option);
7342 return (1);
7344 *Xhdr_ptrptr = target;
7345 return (0);
7349 * Check gname, uname, path, and linkpath to see if they need to go in an
7350 * extended header. If they are already slated to be in an extended header,
7351 * or if they are not ascii, then they need to be in the extended header.
7352 * Then, convert all extended names to UTF-8.
7356 gen_utf8_names(const char *filename)
7358 static iconv_t iconv_cd;
7359 char *nl_target;
7360 char tempbuf[MAXNAM + 1];
7361 int nbytes;
7362 int errors;
7364 if (charset_type == -1) { /* Previous failure to open. */
7365 (void) fprintf(stderr, gettext(
7366 "tar: file # %llu: UTF-8 conversion failed.\n"),
7367 xhdr_count);
7368 return (1);
7371 if (charset_type == 0) { /* Need to get conversion descriptor */
7372 nl_target = nl_langinfo(CODESET);
7373 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7374 nl_target = "646";
7375 if (strcmp(nl_target, "646") == 0)
7376 charset_type = 1;
7377 else if (strcmp(nl_target, "UTF-8") == 0)
7378 charset_type = 3;
7379 else {
7380 if (strncmp(nl_target, "ISO", 3) == 0)
7381 nl_target += 3;
7382 charset_type = 2;
7383 errno = 0;
7384 #ifdef ICONV_DEBUG
7385 (void) fprintf(stderr,
7386 gettext("Opening iconv_cd with target %s\n"),
7387 nl_target);
7388 #endif
7389 if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
7390 (iconv_t)-1) {
7391 if (errno == EINVAL)
7392 (void) fprintf(stderr, gettext(
7393 "tar: conversion routines not "
7394 "available for current locale. "));
7395 (void) fprintf(stderr, gettext(
7396 "file (%s): UTF-8 conversion failed.\n"),
7397 filename);
7398 charset_type = -1;
7399 return (1);
7404 errors = 0;
7406 errors += local_utf8(&Xtarhdr.x_gname, local_gname,
7407 dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
7408 errors += local_utf8(&Xtarhdr.x_uname, local_uname,
7409 dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX);
7410 if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */
7411 (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
7412 tempbuf[NAMSIZ] = '\0';
7414 errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
7415 tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
7416 if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */
7417 (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
7418 tempbuf[PRESIZ] = '\0';
7419 nbytes = strlen(tempbuf);
7420 if (nbytes > 0) {
7421 tempbuf[nbytes++] = '/';
7422 tempbuf[nbytes] = '\0';
7424 (void) strncat(tempbuf + nbytes, dblock.dbuf.name,
7425 (MAXNAM - nbytes));
7426 tempbuf[MAXNAM] = '\0';
7428 errors += local_utf8(&Xtarhdr.x_path, local_path,
7429 tempbuf, iconv_cd, _X_PATH, PATH_MAX);
7431 if (errors > 0)
7432 (void) fprintf(stderr, gettext(
7433 "tar: file (%s): UTF-8 conversion failed.\n"), filename);
7435 if (errors && errflag)
7436 done(1);
7437 else
7438 if (errors)
7439 Errflg = 1;
7440 return (errors);
7443 static int
7444 local_utf8(
7445 char **Xhdr_ptrptr,
7446 char *target,
7447 const char *source,
7448 iconv_t iconv_cd,
7449 int xhdrflg,
7450 int max_val)
7452 const char *iconv_src;
7453 const char *starting_src;
7454 char *iconv_trg;
7455 size_t inlen;
7456 size_t outlen;
7457 #ifdef ICONV_DEBUG
7458 unsigned char c_to_hex;
7459 #endif
7462 * If the item is already slated for extended format, get the string
7463 * to convert from the extended header record. Otherwise, get it from
7464 * the regular (dblock) area.
7466 if (xhdr_flgs & xhdrflg) {
7467 if (charset_type == 3) { /* Already UTF-8, just copy */
7468 (void) strcpy(target, *Xhdr_ptrptr);
7469 *Xhdr_ptrptr = target;
7470 return (0);
7471 } else
7472 iconv_src = (const char *) *Xhdr_ptrptr;
7473 } else {
7474 if (charset_type == 3) /* Already in UTF-8 format */
7475 return (0); /* Don't create xhdr record */
7476 iconv_src = source;
7478 starting_src = iconv_src;
7479 iconv_trg = target;
7480 if ((inlen = strlen(iconv_src)) == 0)
7481 return (0);
7483 if (charset_type == 1) { /* locale using 7-bit codeset */
7484 if (c_utf8(target, starting_src) != 0) {
7485 (void) fprintf(stderr,
7486 gettext("tar: invalid character in"
7487 " UTF-8 conversion of '%s'\n"), starting_src);
7488 return (1);
7490 return (0);
7493 outlen = max_val * UTF_8_FACTOR;
7494 errno = 0;
7495 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7496 (size_t)-1) {
7497 /* An error occurred, or not all characters were converted */
7498 if (errno == EILSEQ)
7499 (void) fprintf(stderr,
7500 gettext("tar: invalid character in"
7501 " UTF-8 conversion of '%s'\n"), starting_src);
7502 else
7503 (void) fprintf(stderr, gettext(
7504 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7505 starting_src);
7506 /* Get remaining output; reinitialize conversion descriptor */
7507 iconv_src = (const char *)NULL;
7508 inlen = 0;
7509 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7510 return (1);
7512 /* Get remaining output; reinitialize conversion descriptor */
7513 iconv_src = (const char *)NULL;
7514 inlen = 0;
7515 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7516 (size_t)-1) { /* Error occurred: didn't convert */
7517 if (errno == EILSEQ)
7518 (void) fprintf(stderr,
7519 gettext("tar: invalid character in"
7520 " UTF-8 conversion of '%s'\n"), starting_src);
7521 else
7522 (void) fprintf(stderr, gettext(
7523 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7524 starting_src);
7525 return (1);
7528 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7529 if (strcmp(starting_src, target) != 0) {
7530 *Xhdr_ptrptr = target;
7531 xhdr_flgs |= xhdrflg;
7532 #ifdef ICONV_DEBUG
7533 (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n",
7534 strlen(starting_src), inlen, max_val, outlen);
7535 (void) fprintf(stderr, "Input string:\n ");
7536 for (inlen = 0; inlen < strlen(starting_src); inlen++) {
7537 c_to_hex = (unsigned char)starting_src[inlen];
7538 (void) fprintf(stderr, " %2.2x", c_to_hex);
7539 if (inlen % 20 == 19)
7540 (void) fprintf(stderr, "\n ");
7542 (void) fprintf(stderr, "\nOutput string:\n ");
7543 for (inlen = 0; inlen < strlen(target); inlen++) {
7544 c_to_hex = (unsigned char)target[inlen];
7545 (void) fprintf(stderr, " %2.2x", c_to_hex);
7546 if (inlen % 20 == 19)
7547 (void) fprintf(stderr, "\n ");
7549 (void) fprintf(stderr, "\n");
7550 #endif
7553 return (0);
7557 * Function to test each byte of the source string to make sure it is
7558 * in within bounds (value between 0 and 127).
7559 * If valid, copy source to target.
7563 c_utf8(char *target, const char *source)
7565 size_t len;
7566 const char *thischar;
7568 len = strlen(source);
7569 thischar = source;
7570 while (len-- > 0) {
7571 if (!isascii((int)(*thischar++)))
7572 return (1);
7575 (void) strcpy(target, source);
7576 return (0);
7580 #if defined(O_XATTR)
7581 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
7583 static void
7584 prepare_xattr(
7585 char **attrbuf,
7586 char *filename,
7587 char *attrpath,
7588 char typeflag,
7589 struct linkbuf *linkinfo,
7590 int *rlen)
7592 char *bufhead; /* ptr to full buffer */
7593 char *aptr;
7594 struct xattr_hdr *hptr; /* ptr to header in bufhead */
7595 struct xattr_buf *tptr; /* ptr to pathing pieces */
7596 int totalen; /* total buffer length */
7597 int len; /* length returned to user */
7598 int stringlen; /* length of filename + attr */
7600 * length of filename + attr
7601 * in link section
7603 int linkstringlen;
7604 int complen; /* length of pathing section */
7605 int linklen; /* length of link section */
7606 int attrnames_index; /* attrnames starting index */
7609 * Release previous buffer
7612 if (*attrbuf != (char *)NULL) {
7613 free(*attrbuf);
7614 *attrbuf = NULL;
7618 * First add in fixed size stuff
7620 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7623 * Add space for two nulls
7625 stringlen = strlen(attrpath) + strlen(filename) + 2;
7626 complen = stringlen + sizeof (struct xattr_buf);
7628 len += stringlen;
7631 * Now add on space for link info if any
7634 if (linkinfo != NULL) {
7636 * Again add space for two nulls
7638 linkstringlen = strlen(linkinfo->pathname) +
7639 strlen(linkinfo->attrname) + 2;
7640 linklen = linkstringlen + sizeof (struct xattr_buf);
7641 len += linklen;
7642 } else {
7643 linklen = 0;
7647 * Now add padding to end to fill out TBLOCK
7649 * Function returns size of real data and not size + padding.
7652 totalen = ROUNDTOTBLOCK(len);
7654 if ((bufhead = calloc(1, totalen)) == NULL) {
7655 fatal(gettext("Out of memory."));
7660 * Now we can fill in the necessary pieces
7664 * first fill in the fixed header
7666 hptr = (struct xattr_hdr *)bufhead;
7667 (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7668 (void) sprintf(hptr->h_component_len, "%0*d",
7669 sizeof (hptr->h_component_len) - 1, complen);
7670 (void) sprintf(hptr->h_link_component_len, "%0*d",
7671 sizeof (hptr->h_link_component_len) - 1, linklen);
7672 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7675 * Now fill in the filename + attrnames section
7676 * The filename and attrnames section can be composed of two or more
7677 * path segments separated by a null character. The first segment
7678 * is the path to the parent file that roots the entire sequence in
7679 * the normal name space. The remaining segments describes a path
7680 * rooted at the hidden extended attribute directory of the leaf file of
7681 * the previous segment, making it possible to name attributes on
7682 * attributes. Thus, if we are just archiving an extended attribute,
7683 * the second segment will contain the attribute name. If we are
7684 * archiving a system attribute of an extended attribute, then the
7685 * second segment will contain the attribute name, and a third segment
7686 * will contain the system attribute name. The attribute pathing
7687 * information is obtained from 'attrpath'.
7690 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7691 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7692 stringlen);
7693 (void) strcpy(tptr->h_names, filename);
7694 attrnames_index = strlen(filename) + 1;
7695 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
7696 tptr->h_typeflag = typeflag;
7699 * Split the attrnames section into two segments if 'attrpath'
7700 * contains pathing information for a system attribute of an
7701 * extended attribute. We split them by replacing the '/' with
7702 * a '\0'.
7704 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
7705 *aptr = '\0';
7709 * Now fill in the optional link section if we have one
7712 if (linkinfo != (struct linkbuf *)NULL) {
7713 tptr = (struct xattr_buf *)(bufhead +
7714 sizeof (struct xattr_hdr) + complen);
7716 (void) sprintf(tptr->h_namesz, "%0*d",
7717 sizeof (tptr->h_namesz) - 1, linkstringlen);
7718 (void) strcpy(tptr->h_names, linkinfo->pathname);
7719 (void) strcpy(
7720 &tptr->h_names[strlen(linkinfo->pathname) + 1],
7721 linkinfo->attrname);
7722 tptr->h_typeflag = typeflag;
7724 *attrbuf = (char *)bufhead;
7725 *rlen = len;
7728 #else
7729 static void
7730 prepare_xattr(
7731 char **attrbuf,
7732 char *filename,
7733 char *attrname,
7734 char typeflag,
7735 struct linkbuf *linkinfo,
7736 int *rlen)
7738 *attrbuf = NULL;
7739 *rlen = 0;
7741 #endif
7744 getstat(int dirfd, char *longname, char *shortname, char *attrparent)
7747 int i, j;
7748 int printerr;
7749 int slnkerr;
7750 struct stat symlnbuf;
7752 if (!hflag)
7753 i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
7754 else
7755 i = fstatat(dirfd, shortname, &stbuf, 0);
7757 if (i < 0) {
7758 /* Initialize flag to print error mesg. */
7759 printerr = 1;
7761 * If stat is done, then need to do lstat
7762 * to determine whether it's a sym link
7764 if (hflag) {
7765 /* Save returned error */
7766 slnkerr = errno;
7768 j = fstatat(dirfd, shortname,
7769 &symlnbuf, AT_SYMLINK_NOFOLLOW);
7771 * Suppress error message when file is a symbolic link
7772 * and function modifier 'l' is off. Exception: when
7773 * a symlink points to a symlink points to a
7774 * symlink ... and we get past MAXSYMLINKS. That
7775 * error will cause a file not to be archived, and
7776 * needs to be printed.
7778 if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
7779 (S_ISLNK(symlnbuf.st_mode)))
7780 printerr = 0;
7783 * Restore errno in case the lstat
7784 * on symbolic link change
7786 errno = slnkerr;
7789 if (printerr) {
7790 (void) fprintf(stderr, gettext(
7791 "tar: %s%s%s%s: %s\n"),
7792 (attrparent == NULL) ? "" : gettext("attribute "),
7793 (attrparent == NULL) ? "" : attrparent,
7794 (attrparent == NULL) ? "" : gettext(" of "),
7795 longname, strerror(errno));
7796 Errflg = 1;
7798 return (1);
7800 return (0);
7804 * Recursively archive the extended attributes and/or extended system attributes
7805 * of the base file, longname. Note: extended system attribute files will be
7806 * archived only if the extended system attributes are not transient (i.e. the
7807 * extended system attributes are other than the default values).
7809 * If -@ was specified and the underlying file system supports it, archive the
7810 * extended attributes, and if there is a system attribute associated with the
7811 * extended attribute, then recursively call xattrs_put() to archive the
7812 * hidden attribute directory and the extended system attribute. If -/ was
7813 * specified and the underlying file system supports it, archive the extended
7814 * system attributes. Read-only extended system attributes are never archived.
7816 * Currently, there cannot be attributes on attributes; only system
7817 * attributes on attributes. In addition, there cannot be attributes on
7818 * system attributes. A file and it's attribute directory hierarchy looks as
7819 * follows:
7820 * longname ----> . ("." is the hidden attribute directory)
7822 * ----------------------------
7823 * | |
7824 * <sys_attr_name> <attr_name> ----> .
7826 * <sys_attr_name>
7829 #if defined(O_XATTR)
7830 static void
7831 xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
7833 char *filename = (attrparent == NULL) ? shortname : attrparent;
7834 int arc_rwsysattr = 0;
7835 int dirfd;
7836 int fd = -1;
7837 int rw_sysattr = 0;
7838 int ext_attr = 0;
7839 int rc;
7840 DIR *dirp;
7841 struct dirent *dp;
7842 attr_data_t *attrinfo = NULL;
7845 * If the underlying file system supports it, then archive the extended
7846 * attributes if -@ was specified, and the extended system attributes
7847 * if -/ was specified.
7849 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
7850 &ext_attr) != ATTR_OK) {
7851 return;
7855 * Only want to archive a read-write extended system attribute file
7856 * if it contains extended system attribute settings that are not the
7857 * default values.
7859 #if defined(_PC_SATTR_ENABLED)
7860 if (saflag) {
7861 int filefd;
7862 nvlist_t *slist = NULL;
7864 /* Determine if there are non-transient system attributes */
7865 errno = 0;
7866 if ((filefd = open(filename, O_RDONLY)) == -1) {
7867 if (attrparent == NULL) {
7868 vperror(0, gettext(
7869 "unable to open file %s"), longname);
7871 return;
7873 if (((slist = sysattr_list(basename(myname), filefd,
7874 filename)) != NULL) || (errno != 0)) {
7875 arc_rwsysattr = 1;
7877 if (slist != NULL) {
7878 (void) nvlist_free(slist);
7879 slist = NULL;
7881 (void) close(filefd);
7885 * If we aren't archiving extended system attributes, and we are
7886 * processing an attribute, or if we are archiving extended system
7887 * attributes, and there are are no extended attributes, then there's
7888 * no need to open up the attribute directory of the file unless the
7889 * extended system attributes are not transient (i.e, the system
7890 * attributes are not the default values).
7892 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
7893 (saflag && !ext_attr))) {
7894 return;
7896 #endif /* _PC_SATTR_ENABLED */
7898 /* open the parent attribute directory */
7899 fd = attropen(filename, ".", O_RDONLY);
7900 if (fd < 0) {
7901 vperror(0, gettext(
7902 "unable to open attribute directory for %s%s%sfile %s"),
7903 (attrparent == NULL) ? "" : gettext("attribute "),
7904 (attrparent == NULL) ? "" : attrparent,
7905 (attrparent == NULL) ? "" : gettext(" of "),
7906 longname);
7907 return;
7911 * We need to change into the parent's attribute directory to determine
7912 * if each of the attributes should be archived.
7914 if (fchdir(fd) < 0) {
7915 vperror(0, gettext(
7916 "cannot change to attribute directory of %s%s%sfile %s"),
7917 (attrparent == NULL) ? "" : gettext("attribute "),
7918 (attrparent == NULL) ? "" : attrparent,
7919 (attrparent == NULL) ? "" : gettext(" of "),
7920 longname);
7921 (void) close(fd);
7922 return;
7925 if (((dirfd = dup(fd)) == -1) ||
7926 ((dirp = fdopendir(dirfd)) == NULL)) {
7927 (void) fprintf(stderr, gettext(
7928 "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7929 (attrparent == NULL) ? "" : gettext("attribute "),
7930 (attrparent == NULL) ? "" : attrparent,
7931 (attrparent == NULL) ? "" : gettext(" of "),
7932 longname);
7933 if (fd > 0) {
7934 (void) close(fd);
7936 return;
7939 while ((dp = readdir(dirp)) != NULL) {
7940 if (strcmp(dp->d_name, "..") == 0) {
7941 continue;
7942 } else if (strcmp(dp->d_name, ".") == 0) {
7943 Hiddendir = 1;
7944 } else {
7945 Hiddendir = 0;
7948 /* Determine if this attribute should be archived */
7949 if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
7950 &rw_sysattr) != ATTR_OK) {
7951 continue;
7954 /* gather the attribute's information to pass to putfile() */
7955 if ((fill_in_attr_info(dp->d_name, longname, attrparent,
7956 fd, rw_sysattr, &attrinfo)) == 1) {
7957 continue;
7960 /* add the attribute to the archive */
7961 rc = putfile(longname, dp->d_name, parent, attrinfo,
7962 XATTR_FILE, LEV0, SYMLINK_LEV0);
7964 if (exitflag) {
7965 break;
7968 #if defined(_PC_SATTR_ENABLED)
7970 * If both -/ and -@ were specified, then archive the
7971 * attribute's extended system attributes and hidden directory
7972 * by making a recursive call to xattrs_put().
7974 if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
7975 (Hiddendir == 0)) {
7977 xattrs_put(longname, shortname, parent, dp->d_name);
7980 * Change back to the parent's attribute directory
7981 * to process any further attributes.
7983 if (fchdir(fd) < 0) {
7984 vperror(0, gettext(
7985 "cannot change back to attribute directory "
7986 "of file %s"), longname);
7987 break;
7990 #endif /* _PC_SATTR_ENABLED */
7993 if (attrinfo != NULL) {
7994 if (attrinfo->attr_parent != NULL) {
7995 free(attrinfo->attr_parent);
7997 free(attrinfo->attr_path);
7998 free(attrinfo);
8000 (void) closedir(dirp);
8001 if (fd != -1) {
8002 (void) close(fd);
8005 /* Change back to the parent directory of the base file */
8006 if (attrparent == NULL) {
8007 (void) tar_chdir(parent);
8009 Hiddendir = 0;
8011 #else
8012 static void
8013 xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
8016 #endif /* O_XATTR */
8018 static int
8019 put_link(char *name, char *longname, char *component, char *longattrname,
8020 char *prefix, int filetype, char type)
8023 if (stbuf.st_nlink > 1) {
8024 struct linkbuf *lp;
8025 int found = 0;
8027 for (lp = ihead; lp != NULL; lp = lp->nextp)
8028 if (lp->inum == stbuf.st_ino &&
8029 lp->devnum == stbuf.st_dev) {
8030 found++;
8031 break;
8033 if (found) {
8034 #if defined(O_XATTR)
8035 if (filetype == XATTR_FILE)
8036 if (put_xattr_hdr(longname, component,
8037 longattrname, prefix, type, filetype, lp)) {
8038 goto out;
8040 #endif
8041 stbuf.st_size = (off_t)0;
8042 if (filetype != XATTR_FILE) {
8043 tomodes(&stbuf);
8044 if (chk_path_build(name, longname, lp->pathname,
8045 prefix, type, filetype) > 0) {
8046 goto out;
8050 if (mulvol && tapepos + 1 >= blocklim)
8051 newvol();
8052 (void) writetbuf((char *)&dblock, 1);
8054 * write_ancillary() is not needed here.
8055 * The first link is handled in the following
8056 * else statement. No need to process ACLs
8057 * for other hard links since they are the
8058 * same file.
8061 if (vflag) {
8062 if (NotTape)
8063 dlog("seek = %" FMT_blkcnt_t
8064 "K\n", K(tapepos));
8065 if (filetype == XATTR_FILE) {
8066 (void) fprintf(vfile, gettext(
8067 "a %s attribute %s link to "
8068 "%s attribute %s\n"),
8069 name, component, name,
8070 lp->attrname);
8071 } else {
8072 (void) fprintf(vfile, gettext(
8073 "a %s link to %s\n"),
8074 longname, lp->pathname);
8077 lp->count--;
8078 return (0);
8079 } else {
8080 lp = (struct linkbuf *)getmem(sizeof (*lp));
8081 if (lp != (struct linkbuf *)NULL) {
8082 lp->nextp = ihead;
8083 ihead = lp;
8084 lp->inum = stbuf.st_ino;
8085 lp->devnum = stbuf.st_dev;
8086 lp->count = stbuf.st_nlink - 1;
8087 if (filetype == XATTR_FILE) {
8088 (void) strcpy(lp->pathname, longname);
8089 (void) strcpy(lp->attrname,
8090 component);
8091 } else {
8092 (void) strcpy(lp->pathname, longname);
8093 (void) strcpy(lp->attrname, "");
8099 out:
8100 return (1);
8103 static int
8104 put_extra_attributes(char *longname, char *shortname, char *longattrname,
8105 char *prefix, int filetype, char typeflag)
8107 static acl_t *aclp = NULL;
8108 int error;
8110 if (aclp != NULL) {
8111 acl_free(aclp);
8112 aclp = NULL;
8114 #if defined(O_XATTR)
8115 if ((atflag || saflag) && (filetype == XATTR_FILE)) {
8116 if (put_xattr_hdr(longname, shortname, longattrname, prefix,
8117 typeflag, filetype, NULL)) {
8118 return (1);
8121 #endif
8123 /* ACL support */
8124 if (pflag) {
8125 char *secinfo = NULL;
8126 int len = 0;
8128 /* ACL support */
8129 if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
8131 * Get ACL info: dont bother allocating space if
8132 * there is only a trivial ACL.
8134 if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
8135 &aclp)) != 0) {
8136 (void) fprintf(stderr, gettext(
8137 "%s: failed to retrieve acl : %s\n"),
8138 longname, acl_strerror(error));
8139 return (1);
8143 /* append security attributes if any */
8144 if (aclp != NULL) {
8145 (void) append_secattr(&secinfo, &len, acl_cnt(aclp),
8146 acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8147 ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
8148 UFSD_ACL : ACE_ACL);
8151 if (Tflag) {
8152 /* append Trusted Extensions extended attributes */
8153 append_ext_attr(shortname, &secinfo, &len);
8154 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8156 } else if (aclp != NULL) {
8157 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8160 return (0);
8163 #if defined(O_XATTR)
8164 static int
8165 put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
8166 int typeflag, int filetype, struct linkbuf *lp)
8168 char *lname = NULL;
8169 char *sname = NULL;
8170 int error = 0;
8171 static char *attrbuf = NULL;
8172 int attrlen;
8174 lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
8175 strlen(shortname) + strlen(".hdr") + 1);
8177 if (lname == NULL) {
8178 fatal(gettext("Out of Memory."));
8180 sname = malloc(sizeof (char) * strlen(shortname) +
8181 strlen(".hdr") + 1);
8182 if (sname == NULL) {
8183 fatal(gettext("Out of Memory."));
8186 (void) sprintf(sname, "%s.hdr", shortname);
8187 (void) sprintf(lname, "/dev/null/%s", sname);
8189 if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
8190 sizeof (dblock.dbuf.name)) {
8191 fatal(gettext(
8192 "Buffer overflow writing extended attribute file name"));
8196 * dump extended attr lookup info
8198 prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
8199 write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
8201 (void) sprintf(lname, "/dev/null/%s", shortname);
8202 (void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
8205 * Set up filename for attribute
8208 error = build_dblock(lname, tchar, '0', filetype,
8209 &stbuf, stbuf.st_dev, prefix);
8210 free(lname);
8211 free(sname);
8213 return (error);
8215 #endif
8217 #if defined(O_XATTR)
8218 static int
8219 read_xattr_hdr(attr_data_t **attrinfo)
8221 char buf[TBLOCK];
8222 char *attrparent = NULL;
8223 blkcnt_t blocks;
8224 char *tp;
8225 off_t bytes;
8226 int comp_len, link_len;
8227 int namelen;
8228 int attrparentlen;
8229 int parentfilelen;
8231 if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
8232 return (1);
8234 bytes = stbuf.st_size;
8235 if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
8236 (void) fprintf(stderr, gettext(
8237 "Insufficient memory for extended attribute\n"));
8238 return (1);
8241 tp = (char *)xattrhead;
8242 blocks = TBLOCKS(bytes);
8243 while (blocks-- > 0) {
8244 readtape(buf);
8245 if (bytes <= TBLOCK) {
8246 (void) memcpy(tp, buf, (size_t)bytes);
8247 break;
8248 } else {
8249 (void) memcpy(tp, buf, TBLOCK);
8250 tp += TBLOCK;
8252 bytes -= TBLOCK;
8256 * Validate that we can handle header format
8258 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8259 (void) fprintf(stderr,
8260 gettext("Unknown extended attribute format encountered\n"));
8261 (void) fprintf(stderr,
8262 gettext("Disabling extended attribute parsing\n"));
8263 xattrbadhead = 1;
8264 return (0);
8266 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8267 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8268 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8269 sizeof (struct xattr_hdr));
8270 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8271 if (link_len > 0)
8272 xattr_linkp = (struct xattr_buf *)
8273 ((int)xattrp + (int)comp_len);
8274 else
8275 xattr_linkp = NULL;
8278 * Gather the attribute path from the filename and attrnames section.
8279 * The filename and attrnames section can be composed of two or more
8280 * path segments separated by a null character. The first segment
8281 * is the path to the parent file that roots the entire sequence in
8282 * the normal name space. The remaining segments describes a path
8283 * rooted at the hidden extended attribute directory of the leaf file of
8284 * the previous segment, making it possible to name attributes on
8285 * attributes.
8287 parentfilelen = strlen(xattrp->h_names);
8288 xattrapath = xattrp->h_names + parentfilelen + 1;
8289 if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
8291 * The attrnames section contains a system attribute on an
8292 * attribute. Save the name of the attribute for use later,
8293 * and replace the null separating the attribute name from
8294 * the system attribute name with a '/' so that xattrapath can
8295 * be used to display messages with the full attribute path name
8296 * rooted at the hidden attribute directory of the base file
8297 * in normal name space.
8299 attrparent = strdup(xattrapath);
8300 attrparentlen = strlen(attrparent);
8301 xattrapath[attrparentlen] = '/';
8303 if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
8304 xattrapath + attrparentlen + 1, xattrapath, attrparent,
8305 -1, 0, attrinfo)) == 1) {
8306 free(attrparent);
8307 return (1);
8310 /* Gather link info */
8311 if (xattr_linkp) {
8312 xattr_linkaname = xattr_linkp->h_names +
8313 strlen(xattr_linkp->h_names) + 1;
8314 } else {
8315 xattr_linkaname = NULL;
8318 return (0);
8320 #else
8321 static int
8322 read_xattr_hdr(attr_data_t **attrinfo)
8324 return (0);
8326 #endif
8329 * skip over extra slashes in string.
8331 * For example:
8332 * /usr/tmp/////
8334 * would return pointer at
8335 * /usr/tmp/////
8338 static char *
8339 skipslashes(char *string, char *start)
8341 while ((string > start) && *(string - 1) == '/') {
8342 string--;
8345 return (string);
8349 * Return the parent directory of a given path.
8351 * Examples:
8352 * /usr/tmp return /usr
8353 * /usr/tmp/file return /usr/tmp
8354 * / returns .
8355 * /usr returns /
8356 * file returns .
8358 * dir is assumed to be at least as big as path.
8360 static void
8361 get_parent(char *path, char *dir)
8363 char *s;
8364 char tmpdir[PATH_MAX + 1];
8366 if (strlen(path) > PATH_MAX) {
8367 fatal(gettext("pathname is too long"));
8369 (void) strcpy(tmpdir, path);
8370 chop_endslashes(tmpdir);
8372 if ((s = strrchr(tmpdir, '/')) == NULL) {
8373 (void) strcpy(dir, ".");
8374 } else {
8375 s = skipslashes(s, tmpdir);
8376 *s = '\0';
8377 if (s == tmpdir)
8378 (void) strcpy(dir, "/");
8379 else
8380 (void) strcpy(dir, tmpdir);
8384 #if defined(O_XATTR)
8385 static char *
8386 get_component(char *path)
8388 char *ptr;
8390 ptr = strrchr(path, '/');
8391 if (ptr == NULL) {
8392 return (path);
8393 } else {
8395 * Handle trailing slash
8397 if (*(ptr + 1) == '\0')
8398 return (ptr);
8399 else
8400 return (ptr + 1);
8403 #else
8404 static char *
8405 get_component(char *path)
8407 return (path);
8409 #endif
8411 #if defined(O_XATTR)
8412 static int
8413 retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
8414 int oflag, mode_t mode)
8416 int dirfd;
8417 int ofilefd = -1;
8418 struct timeval times[2];
8419 mode_t newmode;
8420 struct stat parentstat;
8421 acl_t *aclp = NULL;
8422 int error;
8425 * We couldn't get to attrdir. See if its
8426 * just a mode problem on the parent file.
8427 * for example: a mode such as r-xr--r--
8428 * on a ufs file system without extended
8429 * system attribute support won't let us
8430 * create an attribute dir if it doesn't
8431 * already exist, and on a ufs file system
8432 * with extended system attribute support
8433 * won't let us open the attribute for
8434 * write.
8436 * If file has a non-trivial ACL, then save it
8437 * off so that we can place it back on after doing
8438 * chmod's.
8440 if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
8441 O_RDONLY)) == -1) {
8442 return (-1);
8444 if (fstat(dirfd, &parentstat) == -1) {
8445 (void) fprintf(stderr, gettext(
8446 "tar: cannot stat %sfile %s: %s\n"),
8447 (pdirfd == -1) ? "" : gettext("parent of "),
8448 (pdirfd == -1) ? dirp : name, strerror(errno));
8449 return (-1);
8451 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
8452 (void) fprintf(stderr, gettext(
8453 "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8454 (pdirfd == -1) ? "" : gettext("parent of "),
8455 (pdirfd == -1) ? dirp : name, strerror(errno));
8456 return (-1);
8459 newmode = S_IWUSR | parentstat.st_mode;
8460 if (fchmod(dirfd, newmode) == -1) {
8461 (void) fprintf(stderr,
8462 gettext(
8463 "tar: cannot fchmod %sfile %s to %o: %s\n"),
8464 (pdirfd == -1) ? "" : gettext("parent of "),
8465 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8466 if (aclp)
8467 acl_free(aclp);
8468 return (-1);
8472 if (pdirfd == -1) {
8474 * We weren't able to create the attribute directory before.
8475 * Now try again.
8477 ofilefd = attropen(dirp, ".", oflag);
8478 } else {
8480 * We weren't able to create open the attribute before.
8481 * Now try again.
8483 ofilefd = openat(pdirfd, name, oflag, mode);
8487 * Put mode back to original
8489 if (fchmod(dirfd, parentstat.st_mode) == -1) {
8490 (void) fprintf(stderr,
8491 gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8492 (pdirfd == -1) ? "" : gettext("parent of "),
8493 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8496 if (aclp) {
8497 error = facl_set(dirfd, aclp);
8498 if (error) {
8499 (void) fprintf(stderr,
8500 gettext("tar: failed to set acl entries on "
8501 "%sfile %s\n"),
8502 (pdirfd == -1) ? "" : gettext("parent of "),
8503 (pdirfd == -1) ? dirp : name);
8505 acl_free(aclp);
8509 * Put back time stamps
8512 times[0].tv_sec = parentstat.st_atime;
8513 times[0].tv_usec = 0;
8514 times[1].tv_sec = parentstat.st_mtime;
8515 times[1].tv_usec = 0;
8517 (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
8519 (void) close(dirfd);
8521 return (ofilefd);
8523 #endif
8525 #if !defined(O_XATTR)
8526 static int
8527 openat64(int fd, const char *name, int oflag, mode_t cmode)
8529 return (open64(name, oflag, cmode));
8532 static int
8533 openat(int fd, const char *name, int oflag, mode_t cmode)
8535 return (open(name, oflag, cmode));
8538 static int
8539 fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
8541 if (flag == AT_SYMLINK_NOFOLLOW)
8542 return (lchown(name, owner, group));
8543 else
8544 return (chown(name, owner, group));
8547 static int
8548 renameat(int fromfd, char *old, int tofd, char *new)
8550 return (rename(old, new));
8553 static int
8554 futimesat(int fd, char *path, struct timeval times[2])
8556 return (utimes(path, times));
8559 static int
8560 unlinkat(int dirfd, char *path, int flag)
8562 if (flag == AT_REMOVEDIR)
8563 return (rmdir(path));
8564 else
8565 return (unlink(path));
8568 static int
8569 fstatat(int fd, char *path, struct stat *buf, int flag)
8571 if (flag == AT_SYMLINK_NOFOLLOW)
8572 return (lstat(path, buf));
8573 else
8574 return (stat(path, buf));
8577 static int
8578 attropen(char *file, char *attr, int omode, mode_t cmode)
8580 errno = ENOTSUP;
8581 return (-1);
8583 #endif
8585 static void
8586 chop_endslashes(char *path)
8588 char *end, *ptr;
8591 * Chop of slashes, but not if all we have is slashes
8592 * for example: ////
8593 * should make no changes, otherwise it will screw up
8594 * checkdir
8596 end = &path[strlen(path) -1];
8597 if (*end == '/' && end != path) {
8598 ptr = skipslashes(end, path);
8599 if (ptr != NULL && ptr != path) {
8600 *ptr = '\0';
8604 /* Trusted Extensions */
8607 * append_ext_attr():
8609 * Append extended attributes and other information into the buffer
8610 * that gets written to the ancillary file.
8612 * With option 'T', we create a tarfile which
8613 * has an ancillary file each corresponding archived file.
8614 * Each ancillary file contains 1 or more of the
8615 * following attributes:
8617 * attribute type attribute process procedure
8618 * ---------------- ---------------- --------------------------
8619 * DIR_TYPE = 'D' directory flag append if a directory
8620 * LBL_TYPE = 'L' SL[IL] or SL append ascii label
8624 static void
8625 append_ext_attr(char *shortname, char **secinfo, int *len)
8627 bslabel_t b_slabel; /* binary sensitvity label */
8628 char *ascii = NULL; /* ascii label */
8631 * For each attribute type, append it if it is
8632 * relevant to the file type.
8636 * For attribute type DIR_TYPE,
8637 * append it to the following file type:
8639 * S_IFDIR: directories
8643 * For attribute type LBL_TYPE,
8644 * append it to the following file type:
8646 * S_IFDIR: directories (including mld, sld)
8647 * S_IFLNK: symbolic link
8648 * S_IFREG: regular file but not hard link
8649 * S_IFIFO: FIFO file but not hard link
8650 * S_IFCHR: char special file but not hard link
8651 * S_IFBLK: block special file but not hard link
8653 switch (stbuf.st_mode & S_IFMT) {
8655 case S_IFDIR:
8658 * append DIR_TYPE
8660 (void) append_secattr(secinfo, len, 1,
8661 "\0", DIR_TYPE);
8664 * Get and append attribute types LBL_TYPE.
8665 * For directories, LBL_TYPE contains SL.
8667 /* get binary sensitivity label */
8668 if (getlabel(shortname, &b_slabel) != 0) {
8669 (void) fprintf(stderr,
8670 gettext("tar: can't get sensitvity label for "
8671 " %s, getlabel() error: %s\n"),
8672 shortname, strerror(errno));
8673 } else {
8674 /* get ascii SL */
8675 if (bsltos(&b_slabel, &ascii,
8676 0, 0) <= 0) {
8677 (void) fprintf(stderr,
8678 gettext("tar: can't get ascii SL for"
8679 " %s\n"), shortname);
8680 } else {
8681 /* append LBL_TYPE */
8682 (void) append_secattr(secinfo, len,
8683 strlen(ascii) + 1, ascii,
8684 LBL_TYPE);
8686 /* free storage */
8687 if (ascii != NULL) {
8688 free(ascii);
8689 ascii = (char *)0;
8694 break;
8696 case S_IFLNK:
8697 case S_IFREG:
8698 case S_IFIFO:
8699 case S_IFCHR:
8700 case S_IFBLK:
8702 /* get binary sensitivity label */
8703 if (getlabel(shortname, &b_slabel) != 0) {
8704 (void) fprintf(stderr,
8705 gettext("tar: can't get sensitivty label for %s, "
8706 "getlabel() error: %s\n"),
8707 shortname, strerror(errno));
8708 } else {
8709 /* get ascii IL[SL] */
8710 if (bsltos(&b_slabel, &ascii, 0, 0) <= 0) {
8711 (void) fprintf(stderr,
8712 gettext("tar: can't translate sensitivity "
8713 " label for %s\n"), shortname);
8714 } else {
8715 char *cmw_label;
8716 size_t cmw_length;
8718 cmw_length = strlen("ADMIN_LOW [] ") +
8719 strlen(ascii);
8720 if ((cmw_label = malloc(cmw_length)) == NULL) {
8721 (void) fprintf(stderr, gettext(
8722 "Insufficient memory for label\n"));
8723 exit(1);
8725 /* append LBL_TYPE */
8726 (void) snprintf(cmw_label, cmw_length,
8727 "ADMIN_LOW [%s]", ascii);
8728 (void) append_secattr(secinfo, len,
8729 strlen(cmw_label) + 1, cmw_label,
8730 LBL_TYPE);
8732 /* free storage */
8733 if (ascii != NULL) {
8734 free(cmw_label);
8735 free(ascii);
8736 ascii = (char *)0;
8740 break;
8742 default:
8743 break;
8744 } /* end switch for LBL_TYPE */
8747 /* DONE !! */
8748 return;
8750 } /* end of append_ext_attr */
8754 * Name: extract_attr()
8756 * Description:
8757 * Process attributes from the ancillary file due to
8758 * the T option.
8760 * Call by doxtract() as part of the switch case structure.
8761 * Making this a separate routine because the nesting are too
8762 * deep in doxtract, thus, leaving very little space
8763 * on each line for instructions.
8765 * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
8767 * For option 'T', following are possible attributes in
8768 * a TS 8 ancillary file: (NOTE: No IL support)
8770 * attribute type attribute process procedure
8771 * ---------------- ---------------- -------------------------
8772 * # LBL_TYPE = 'L' SL construct binary label
8773 * # APRIV_TYPE = 'P' allowed priv construct privileges
8774 * # FPRIV_TYPE = 'p' forced priv construct privileges
8775 * # COMP_TYPE = 'C' path component construct real path
8776 * # DIR_TYPE = 'D' directory flag note it is a directory
8777 * $ UFSD_ACL = '1' ACL data construct ACL entries
8778 * ATTR_FLAG_TYPE = 'F' file attr flags construct binary flags
8779 * LK_COMP_TYPE = 'K' linked path comp construct linked real path
8781 * note: # = attribute names common between TS 8 & TS 2.5 ancillary
8782 * files.
8783 * $ = ACL attribute is processed for the option 'p', it doesn't
8784 * need option 'T'.
8786 * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
8789 static void
8790 extract_attr(char **file_ptr, struct sec_attr *attr)
8792 int reterr, err;
8793 char *dummy_buf; /* for attribute extract */
8795 dummy_buf = attr->attr_info;
8797 switch (attr->attr_type) {
8799 case DIR_TYPE:
8801 dir_flag++;
8802 break;
8804 case LBL_TYPE:
8807 * LBL_TYPE is used to indicate SL for directory, and
8808 * CMW label for other file types.
8811 if (!dir_flag) { /* not directory */
8812 /* Skip over IL portion */
8813 char *sl_ptr = strchr(dummy_buf, '[');
8815 if (sl_ptr == NULL)
8816 err = 0;
8817 else
8818 err = stobsl(sl_ptr, &bs_label,
8819 NEW_LABEL, &reterr);
8820 } else { /* directory */
8821 err = stobsl(dummy_buf, &bs_label,
8822 NEW_LABEL, &reterr);
8824 if (err == 0) {
8825 (void) fprintf(stderr, gettext("tar: "
8826 "can't convert %s to binary label\n"),
8827 dummy_buf);
8828 bslundef(&bs_label);
8829 } else if (!blequal(&bs_label, &admin_low) &&
8830 !blequal(&bs_label, &admin_high)) {
8831 bslabel_t *from_label;
8832 char *buf;
8833 char tempbuf[MAXPATHLEN];
8835 if (*orig_namep != '/') {
8836 /* got relative linked to path */
8837 (void) getcwd(tempbuf, (sizeof (tempbuf)));
8838 (void) strncat(tempbuf, "/", MAXPATHLEN);
8839 } else
8840 *tempbuf = '\0';
8842 buf = real_path;
8843 (void) strncat(tempbuf, orig_namep, MAXPATHLEN);
8844 from_label = getlabelbypath(tempbuf);
8845 if (from_label != NULL) {
8846 if (blequal(from_label, &admin_low)) {
8847 if ((getpathbylabel(tempbuf, buf,
8848 MAXPATHLEN, &bs_label) == NULL)) {
8849 (void) fprintf(stderr,
8850 gettext("tar: "
8851 "can't get zone root path for "
8852 "%s\n"), tempbuf);
8853 } else
8854 rpath_flag = 1;
8856 free(from_label);
8859 break;
8861 case COMP_TYPE:
8863 rebuild_comp_path(dummy_buf, file_ptr);
8864 break;
8866 case LK_COMP_TYPE:
8868 if (rebuild_lk_comp_path(dummy_buf, file_ptr)
8869 == 0) {
8870 lk_rpath_flag = 1;
8871 } else {
8872 (void) fprintf(stderr, gettext("tar: warning: link's "
8873 "target pathname might be invalid.\n"));
8874 lk_rpath_flag = 0;
8876 break;
8877 case APRIV_TYPE:
8878 ignored_aprivs++;
8879 break;
8880 case FPRIV_TYPE:
8881 ignored_fprivs++;
8882 break;
8883 case ATTR_FLAG_TYPE:
8884 ignored_fattrs++;
8885 break;
8887 default:
8889 break;
8892 /* done */
8893 return;
8895 } /* end extract_attr */
8900 * Name: rebuild_comp_path()
8902 * Description:
8903 * Take the string of components passed down by the calling
8904 * routine and parse the values and rebuild the path.
8905 * This routine no longer needs to produce a new real_path
8906 * string because it is produced when the 'L' LABEL_TYPE is
8907 * interpreted. So the only thing done here is to distinguish
8908 * between an SLD and an MLD entry. We only want one, so we
8909 * ignore the MLD entry by setting the mld_flag.
8911 * return value:
8912 * none
8914 static void
8915 rebuild_comp_path(char *str, char **namep)
8917 char *cp;
8919 while (*str != '\0') {
8921 switch (*str) {
8923 case MLD_TYPE:
8925 str++;
8926 if ((cp = strstr(str, ";;")) != NULL) {
8927 *cp = '\0';
8928 str = cp + 2;
8929 *cp = ';';
8931 mld_flag = 1;
8932 break;
8934 case SLD_TYPE:
8936 str++;
8937 if ((cp = strstr(str, ";;")) != NULL) {
8938 *cp = '\0';
8939 str = cp + 2;
8940 *cp = ';';
8942 mld_flag = 0;
8943 break;
8945 case PATH_TYPE:
8947 str++;
8948 if ((cp = strstr(str, ";;")) != NULL) {
8949 *cp = '\0';
8950 str = cp + 2;
8951 *cp = ';';
8953 break;
8956 if (rpath_flag)
8957 *namep = real_path;
8958 return;
8960 } /* end rebuild_comp_path() */
8963 * Name: rebuild_lk_comp_path()
8965 * Description:
8966 * Take the string of components passed down by the calling
8967 * routine and parse the values and rebuild the path.
8969 * return value:
8970 * 0 = succeeded
8971 * -1 = failed
8973 static int
8974 rebuild_lk_comp_path(char *str, char **namep)
8976 char *cp;
8977 int reterr;
8978 bslabel_t bslabel;
8979 char *buf;
8980 char pbuf[MAXPATHLEN];
8981 char *ptr1, *ptr2;
8982 int plen;
8983 int use_pbuf;
8984 char tempbuf[MAXPATHLEN];
8985 int mismatch;
8986 bslabel_t *from_label;
8987 char zonename[ZONENAME_MAX];
8988 zoneid_t zoneid;
8990 /* init stuff */
8991 use_pbuf = 0;
8992 mismatch = 0;
8995 * For linked to pathname (LK_COMP_TYPE):
8996 * - If the linked to pathname is absolute (start with /), we
8997 * will use it as is.
8998 * - If it is a relative pathname then it is relative to 1 of 2
8999 * directories. For a hardlink, it is relative to the current
9000 * directory. For a symbolic link, it is relative to the
9001 * directory the symbolic link is in. For the symbolic link
9002 * case, set a flag to indicate we need to use the prefix of
9003 * the restored file's pathname with the linked to pathname.
9005 * NOTE: At this point, we have no way to determine if we have
9006 * a hardlink or a symbolic link. We will compare the 1st
9007 * component in the prefix portion of the restore file's
9008 * pathname to the 1st component in the attribute data
9009 * (the linked pathname). If they are the same, we will assume
9010 * the link pathname to reconstruct is relative to the current
9011 * directory. Otherwise, we will set a flag indicate we need
9012 * to use a prefix with the reconstructed name. Need to compare
9013 * both the adorned and unadorned version before deciding a
9014 * mismatch.
9017 buf = lk_real_path;
9018 if (*(str + 1) != '/') { /* got relative linked to path */
9019 ptr1 = orig_namep;
9020 ptr2 = strrchr(ptr1, '/');
9021 plen = ptr2 - ptr1;
9022 if (plen > 0) {
9023 pbuf[0] = '\0';
9024 plen++; /* include '/' */
9025 (void) strncpy(pbuf, ptr1, plen);
9026 *(pbuf + plen) = '\0';
9027 ptr2 = strchr(pbuf, '/');
9028 if (strncmp(pbuf, str + 1, ptr2 - pbuf) != 0)
9029 mismatch = 1;
9032 if (mismatch == 1)
9033 use_pbuf = 1;
9036 buf[0] = '\0';
9038 while (*str != '\0') {
9040 switch (*str) {
9042 case MLD_TYPE:
9044 str++;
9045 if ((cp = strstr(str, ";;")) != NULL) {
9046 *cp = '\0';
9049 * Ignore attempts to backup over .MLD.
9051 if (strcmp(str, "../") != 0)
9052 (void) strncat(buf, str, MAXPATHLEN);
9053 str = cp + 2;
9054 *cp = ';';
9056 break;
9058 case SLD_TYPE:
9060 str++;
9061 if ((cp = strstr(str, ";;")) != NULL) {
9062 *cp = '\0';
9065 * Use the path name in the header if
9066 * error occurs when processing the
9067 * SLD type.
9070 if (!stobsl(str, &bslabel,
9071 NO_CORRECTION, &reterr)) {
9072 (void) fprintf(stderr, gettext(
9073 "tar: can't translate to binary"
9074 "SL for SLD, stobsl() error:"
9075 " %s\n"), strerror(errno));
9076 return (-1);
9079 str = cp + 2;
9080 *cp = ';';
9082 if (use_pbuf == 1) {
9083 if (*pbuf != '/') {
9084 /* relative linked to path */
9086 (void) getcwd(tempbuf,
9087 (sizeof (tempbuf)));
9088 (void) strncat(tempbuf, "/",
9089 MAXPATHLEN);
9090 (void) strncat(tempbuf, pbuf,
9091 MAXPATHLEN);
9093 else
9094 (void) strcpy(tempbuf, pbuf);
9096 } else if (*buf != '/') {
9097 /* got relative linked to path */
9099 (void) getcwd(tempbuf,
9100 (sizeof (tempbuf)));
9101 (void) strncat(tempbuf, "/",
9102 MAXPATHLEN);
9103 } else
9104 *tempbuf = '\0';
9106 (void) strncat(tempbuf, buf, MAXPATHLEN);
9107 *buf = '\0';
9109 if (blequal(&bslabel, &admin_high)) {
9110 bslabel = admin_low;
9115 * Check for cross-zone symbolic links
9117 from_label = getlabelbypath(real_path);
9118 if (rpath_flag && (from_label != NULL) &&
9119 !blequal(&bslabel, from_label)) {
9120 if ((zoneid =
9121 getzoneidbylabel(&bslabel)) == -1) {
9122 (void) fprintf(stderr,
9123 gettext("tar: can't get "
9124 "zone ID for %s\n"),
9125 tempbuf);
9126 return (-1);
9128 if (zone_getattr(zoneid, ZONE_ATTR_NAME,
9129 &zonename, ZONENAME_MAX) == -1) {
9130 /* Badly configured zone info */
9131 (void) fprintf(stderr,
9132 gettext("tar: can't get "
9133 "zonename for %s\n"),
9134 tempbuf);
9135 return (-1);
9137 (void) strncpy(buf, AUTO_ZONE,
9138 MAXPATHLEN);
9139 (void) strncat(buf, "/",
9140 MAXPATHLEN);
9141 (void) strncat(buf, zonename,
9142 MAXPATHLEN);
9144 if (from_label != NULL)
9145 free(from_label);
9146 (void) strncat(buf, tempbuf, MAXPATHLEN);
9147 break;
9149 mld_flag = 0;
9150 break;
9152 case PATH_TYPE:
9154 str++;
9155 if ((cp = strstr(str, ";;")) != NULL) {
9156 *cp = '\0';
9157 (void) strncat(buf, str, MAXPATHLEN);
9158 str = cp + 2;
9159 *cp = ';';
9161 break;
9163 default:
9165 (void) fprintf(stderr, gettext(
9166 "tar: error rebuilding path %s\n"),
9167 *namep);
9168 *buf = '\0';
9169 str++;
9170 return (-1);
9175 * Done for LK_COMP_TYPE
9178 return (0); /* component path is rebuilt successfully */
9180 } /* end rebuild_lk_comp_path() */
9183 * Name: check_ext_attr()
9185 * Description:
9186 * Check the extended attributes for a file being extracted.
9187 * The attributes being checked here are CMW labels.
9188 * ACLs are not set here because they are set by the
9189 * pflag in doxtract().
9191 * If the label doesn't match, return 0
9192 * else return 1
9194 static int
9195 check_ext_attr(char *filename)
9197 bslabel_t currentlabel; /* label from zone */
9199 if (bltype(&bs_label, SUN_SL_UN)) {
9200 /* No label check possible */
9201 return (0);
9203 if (getlabel(filename, &currentlabel) != 0) {
9204 (void) fprintf(stderr,
9205 gettext("tar: can't get label for "
9206 " %s, getlabel() error: %s\n"),
9207 filename, strerror(errno));
9208 return (0);
9209 } else if ((blequal(&currentlabel, &bs_label)) == 0) {
9210 char *src_label = NULL; /* ascii label */
9212 /* get current src SL */
9213 if (bsltos(&bs_label, &src_label, 0, 0) <= 0) {
9214 (void) fprintf(stderr,
9215 gettext("tar: can't interpret requested label for"
9216 " %s\n"), filename);
9217 } else {
9218 (void) fprintf(stderr,
9219 gettext("tar: can't apply label %s to %s\n"),
9220 src_label, filename);
9221 free(src_label);
9223 (void) fprintf(stderr,
9224 gettext("tar: %s not restored\n"), filename);
9225 return (0);
9227 return (1);
9229 } /* end check_ext_attr */
9231 /* Compressing a tar file using compression method provided in 'opt' */
9233 static void
9234 compress_back()
9236 pid_t pid;
9238 if (vflag) {
9239 (void) fprintf(vfile,
9240 gettext("Compressing '%s' with '%s'...\n"),
9241 usefile, compress_opt);
9243 if ((pid = fork()) == 0) {
9244 verify_compress_opt(compress_opt);
9245 (void) execlp(compress_opt, compress_opt,
9246 usefile, NULL);
9247 } else if (pid == -1) {
9248 vperror(1, "%s", gettext("Could not fork"));
9250 wait_pid(pid);
9251 if (suffix == 0) {
9252 (void) rename(tfname, usefile);
9256 /* The magic numbers from /etc/magic */
9258 #define GZIP_MAGIC "\037\213"
9259 #define BZIP_MAGIC "BZh"
9260 #define COMP_MAGIC "\037\235"
9261 #define XZ_MAGIC "\375\067\172\130\132\000"
9263 void
9264 check_compression(void)
9266 char magic[16];
9267 FILE *fp;
9269 if ((fp = fopen(usefile, "r")) != NULL) {
9270 (void) fread(magic, sizeof (char), 6, fp);
9271 (void) fclose(fp);
9274 if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
9275 if (xflag || tflag) {
9276 compress_opt = compress_malloc(strlen(GZCAT) + 1);
9277 (void) strcpy(compress_opt, GZCAT);
9278 } else if (uflag || rflag) {
9279 compress_opt = compress_malloc(strlen(GZIP) + 1);
9280 (void) strcpy(compress_opt, GZIP);
9282 } else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
9283 if (xflag || tflag) {
9284 compress_opt = compress_malloc(strlen(BZCAT) + 1);
9285 (void) strcpy(compress_opt, BZCAT);
9286 } else if (uflag || rflag) {
9287 compress_opt = compress_malloc(strlen(BZIP) + 1);
9288 (void) strcpy(compress_opt, BZIP);
9290 } else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
9291 if (xflag || tflag) {
9292 compress_opt = compress_malloc(strlen(ZCAT) + 1);
9293 (void) strcpy(compress_opt, ZCAT);
9294 } else if (uflag || rflag) {
9295 compress_opt = compress_malloc(strlen(COMPRESS) + 1);
9296 (void) strcpy(compress_opt, COMPRESS);
9298 } else if (memcmp(magic, XZ_MAGIC, 6) == 0) {
9299 if (xflag || tflag) {
9300 compress_opt = compress_malloc(strlen(XZCAT) + 1);
9301 (void) strcpy(compress_opt, XZCAT);
9302 } else if (uflag || rflag) {
9303 compress_opt = compress_malloc(strlen(XZ) + 1);
9304 (void) strcpy(compress_opt, XZ);
9309 char *
9310 add_suffix()
9312 (void) strcpy(tfname, usefile);
9313 if (strcmp(compress_opt, GZIP) == 0) {
9314 if ((suffix = gz_suffix()) == NULL) {
9315 strlcat(tfname, gsuffix[0], sizeof (tfname));
9316 return (gsuffix[0]);
9318 } else if (strcmp(compress_opt, COMPRESS) == 0) {
9319 if ((suffix = gz_suffix()) == NULL) {
9320 strlcat(tfname, gsuffix[6], sizeof (tfname));
9321 return (gsuffix[6]);
9323 } else if (strcmp(compress_opt, BZIP) == 0) {
9324 if ((suffix = bz_suffix()) == NULL) {
9325 strlcat(tfname, bsuffix[0], sizeof (tfname));
9326 return (bsuffix[0]);
9328 } else if (strcmp(compress_opt, XZ) == 0) {
9329 if ((suffix = xz_suffix()) == NULL) {
9330 strlcat(tfname, xsuffix[0], sizeof (tfname));
9331 return (xsuffix[0]);
9334 return (NULL);
9337 /* Decompressing a tar file using compression method from the file type */
9338 void
9339 decompress_file(void)
9341 pid_t pid;
9342 char *added_suffix;
9345 added_suffix = add_suffix();
9346 if (added_suffix != NULL) {
9347 (void) rename(usefile, tfname);
9349 if ((pid = fork()) == 0) {
9350 if (vflag) {
9351 (void) fprintf(vfile,
9352 gettext("Decompressing '%s' with "
9353 "'%s'...\n"), usefile, compress_opt);
9355 verify_compress_opt(compress_opt);
9356 (void) execlp(compress_opt, compress_opt, "-df",
9357 tfname, NULL);
9358 vperror(1, gettext("Could not exec %s"), compress_opt);
9359 } else if (pid == -1) {
9360 vperror(1, gettext("Could not fork"));
9362 wait_pid(pid);
9363 if (suffix != NULL) {
9364 /* restore the file name - original file was without suffix */
9365 *(usefile + strlen(usefile) - strlen(suffix)) = '\0';
9369 /* Set the archive for writing and then compress the archive */
9370 pid_t
9371 compress_file(void)
9373 int fd[2];
9374 pid_t pid;
9376 if (vflag) {
9377 (void) fprintf(vfile, gettext("Compressing '%s' with "
9378 "'%s'...\n"), usefile, compress_opt);
9381 if (pipe(fd) < 0) {
9382 vperror(1, gettext("Could not create pipe"));
9384 if ((pid = fork()) > 0) {
9385 mt = fd[1];
9386 (void) close(fd[0]);
9387 return (pid);
9389 /* child */
9390 (void) dup2(fd[0], STDIN_FILENO);
9391 (void) close(fd[1]);
9392 (void) dup2(mt, STDOUT_FILENO);
9393 verify_compress_opt(compress_opt);
9394 (void) execlp(compress_opt, compress_opt, NULL);
9395 vperror(1, gettext("Could not exec %s"), compress_opt);
9396 return (0); /*NOTREACHED*/
9399 pid_t
9400 uncompress_file(void)
9402 int fd[2];
9403 pid_t pid;
9405 if (vflag) {
9406 (void) fprintf(vfile, gettext("Decompressing '%s' with "
9407 "'%s'...\n"), usefile, compress_opt);
9410 if (pipe(fd) < 0) {
9411 vperror(1, gettext("Could not create pipe"));
9413 if ((pid = fork()) > 0) {
9414 mt = fd[0];
9415 (void) close(fd[1]);
9416 return (pid);
9418 /* child */
9419 (void) dup2(fd[1], STDOUT_FILENO);
9420 (void) close(fd[0]);
9421 (void) dup2(mt, STDIN_FILENO);
9422 verify_compress_opt(compress_opt);
9423 (void) execlp(compress_opt, compress_opt, NULL);
9424 vperror(1, gettext("Could not exec %s"), compress_opt);
9425 return (0); /*NOTREACHED*/
9428 /* Checking suffix validity */
9429 char *
9430 check_suffix(char **suf, int size)
9432 int i;
9433 int slen;
9434 int nlen = strlen(usefile);
9436 for (i = 0; i < size; i++) {
9437 slen = strlen(suf[i]);
9438 if (nlen < slen)
9439 return (NULL);
9440 if (strcmp(usefile + nlen - slen, suf[i]) == 0)
9441 return (suf[i]);
9443 return (NULL);
9446 /* Checking valid 'bzip2' suffix */
9447 char *
9448 bz_suffix(void)
9450 return (check_suffix(bsuffix, BSUF));
9453 /* Checking valid 'gzip' suffix */
9454 char *
9455 gz_suffix(void)
9457 return (check_suffix(gsuffix, GSUF));
9460 /* Checking valid 'xz' suffix */
9461 char *
9462 xz_suffix(void)
9464 return (check_suffix(xsuffix, XSUF));
9467 void *
9468 compress_malloc(size_t size)
9470 void *opt;
9472 if ((opt = malloc(size)) == NULL) {
9473 vperror(1, "%s",
9474 gettext("Could not allocate compress buffer\n"));
9476 return (opt);
9479 void
9480 wait_pid(pid_t pid)
9482 int status;
9484 while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
9488 static void
9489 verify_compress_opt(const char *t)
9491 struct stat statbuf;
9493 if (stat(t, &statbuf) == -1)
9494 vperror(1, "%s %s: %s\n", gettext("Could not stat"),
9495 t, strerror(errno));
9498 static void
9499 detect_compress(void)
9501 char *zsuf[] = {".Z"};
9502 if (check_suffix(zsuf, 1) != NULL) {
9503 Zflag = 1;
9504 } else if (check_suffix(bsuffix, BSUF) != NULL) {
9505 jflag = 1;
9506 } else if (check_suffix(gsuffix, GSUF) != NULL) {
9507 zflag = 1;
9508 } else if (check_suffix(xsuffix, XSUF) != NULL) {
9509 Jflag = 1;
9510 } else {
9511 vperror(1, "%s\n", gettext("No compression method detected"));