4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
28 /* Copyright (c) 1987, 1988 Microsoft Corporation */
29 /* All Rights Reserved */
32 * Portions of this source code were derived from Berkeley 4.3 BSD
33 * under license from the Regents of the University of California.
37 #include <sys/types.h>
38 #include <sys/param.h>
40 #include <sys/mkdev.h>
70 #include <libnvpair.h>
73 #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
76 #if defined(_PC_SATTR_ENABLED)
78 #include <libcmdutils.h>
81 /* Trusted Extensions */
83 #include <tsol/label.h>
84 #include <sys/tsol/label_macro.h>
86 #include "getresponse.h"
88 * Source compatibility
92 * These constants come from archives.h and sys/fcntl.h
93 * and were introduced by the extended attributes project
97 #define AT_SYMLINK_NOFOLLOW 0x1000
98 #define AT_REMOVEDIR 0x1
99 #define AT_FDCWD 0xffd19553
100 #define _XATTR_HDRTYPE 'E'
101 static int attropen();
102 static int fstatat();
103 static int renameat();
104 static int unlinkat();
106 static int fchownat();
107 static int futimesat();
111 * Compiling with -D_XPG4_2 gets this but produces other problems, so
112 * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
113 * explicitly doing the declaration here.
115 int utimes(const char *path
, const struct timeval timeval_ptr
[]);
120 #define DEF_FILE "/etc/default/tar"
122 #define min(a, b) ((a) < (b) ? (a) : (b))
123 #define max(a, b) ((a) > (b) ? (a) : (b))
125 /* -DDEBUG ONLY for debugging */
128 #define DEBUG(a, b, c)\
129 (void) fprintf(stderr, "DEBUG - "), (void) fprintf(stderr, a, b, c)
132 #define TBLOCK 512 /* tape block size--should be universal */
135 #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
137 #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
144 #define MODEMASK 0777777 /* file creation mode mask */
145 #define POSIXMODES 07777 /* mask for POSIX mode bits */
146 #define MAXEXT 9 /* reasonable max # extents for a file */
147 #define EXTMIN 50 /* min blks left on floppy to split a file */
149 /* max value dblock.dbuf.efsize can store */
150 #define TAR_EFSIZE_MAX 0777777777
153 * Symbols which specify the values at which the use of the 'E' function
154 * modifier is required to properly store a file.
156 * TAR_OFFSET_MAX - the largest file size we can archive
157 * OCTAL7CHAR - the limit for ustar gid, uid, dev
161 /* tiny values which force the creation of extended header entries */
162 #define TAR_OFFSET_MAX 9
166 #define TAR_OFFSET_MAX 077777777777ULL
167 #define OCTAL7CHAR 07777777
170 #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
171 #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
173 #define MAXLEV (PATH_MAX / 2)
175 #define SYMLINK_LEV0 0
181 #define NORMAL_FILE 0
183 #define PUT_AS_LINK 1
184 #define PUT_NOTAS_LINK 0
186 #ifndef VIEW_READONLY
187 #define VIEW_READONLY "SUNWattr_ro"
190 #ifndef VIEW_READWRITE
191 #define VIEW_READWRITE "SUNWattr_rw"
194 #if _FILE_OFFSET_BITS == 64
195 #define FMT_off_t "lld"
196 #define FMT_off_t_o "llo"
197 #define FMT_blkcnt_t "lld"
199 #define FMT_off_t "ld"
200 #define FMT_off_t_o "lo"
201 #define FMT_blkcnt_t "ld"
231 typedef struct attr_data
{
240 * Tar has been changed to support extended attributes.
242 * As part of this change tar now uses the new *at() syscalls
243 * such as openat, fchownat(), unlinkat()...
245 * This was done so that attributes can be handled with as few code changes
248 * What this means is that tar now opens the directory that a file or directory
249 * resides in and then performs *at() functions to manipulate the entry.
251 * For example a new file is now created like this:
253 * dfd = open(<some dir path>)
254 * fd = openat(dfd, <name>,....);
256 * or in the case of an extended attribute
258 * dfd = attropen(<pathname>, ".", ....)
260 * Once we have a directory file descriptor all of the *at() functions can
263 * unlinkat(dfd, <component name>,...)
264 * fchownat(dfd, <component name>,..)
266 * This works for both normal namespace files and extended attribute file
272 * Extended attribute Format
274 * Extended attributes are stored in two pieces.
275 * 1. An attribute header which has information about
276 * what file the attribute is for and what the attribute
278 * 2. The attribute record itself. Stored as a normal file type
280 * Both the header and attribute record have special modes/typeflags
281 * associated with them.
283 * The names of the header in the archive look like:
286 * The name of the attribute looks like:
289 * This is done so that an archiver that doesn't understand these formats
290 * can just dispose of the attribute records.
292 * The format is composed of a fixed size header followed
293 * by a variable sized xattr_buf. If the attribute is a hard link
294 * to another attribute then another xattr_buf section is included
297 * The xattr_buf is used to define the necessary "pathing" steps
298 * to get to the extended attribute. This is necessary to support
299 * a fully recursive attribute model where an attribute may itself
302 * The basic layout looks like this.
304 * --------------------------------
308 * --------------------------------
309 * --------------------------------
313 * --------------------------------
314 * --------------------------------
316 * | (optional link info) |
318 * --------------------------------
319 * --------------------------------
321 * | attribute itself |
322 * | stored as normal tar |
323 * | or cpio data with |
324 * | special mode or |
327 * --------------------------------
332 * xattrhead is a pointer to the xattr_hdr
334 * xattrp is a pointer to the xattr_buf structure
335 * which contains the "pathing" steps to get to attributes
337 * xattr_linkp is a pointer to another xattr_buf structure that is
338 * only used when an attribute is actually linked to another attribute
342 static struct xattr_hdr
*xattrhead
;
343 static struct xattr_buf
*xattrp
;
344 static struct xattr_buf
*xattr_linkp
; /* pointer to link info, if any */
345 static char *xattrapath
; /* attribute name */
346 static char *xattr_linkaname
; /* attribute attribute is linked to */
347 static char Hiddendir
; /* are we processing hidden xattr dir */
348 static char xattrbadhead
;
350 /* Was statically allocated tbuf[NBLOCK] */
355 char name
[NAMSIZ
]; /* If non-null prefix, path is */
356 /* <prefix>/<name>; otherwise */
361 char size
[12]; /* size of this extent if file split */
365 char linkname
[NAMSIZ
];
372 char prefix
[PRESIZ
]; /* Together with "name", the path of */
373 /* the file: <prefix>/<name> */
374 char extno
; /* extent #, null if not split */
375 char extotal
; /* total extents */
376 char efsize
[10]; /* size of entire file */
378 } dblock
, *tbuf
, xhdr_buf
;
382 uid_t x_uid
, /* Uid of file */
383 x_gid
; /* Gid of file */
384 major_t x_devmajor
; /* Device major node */
385 minor_t x_devminor
; /* Device minor node */
386 off_t x_filesz
; /* Length of file */
387 char *x_uname
, /* Pointer to name of user */
388 *x_gname
, /* Pointer to gid of user */
389 *x_linkpath
, /* Path for a hard/symbolic link */
390 *x_path
; /* Path of file */
391 timestruc_t x_mtime
; /* Seconds and nanoseconds */
396 ulong_t g_mode
; /* Mode of file */
397 uid_t g_uid
, /* Uid of file */
398 g_gid
; /* Gid of file */
399 off_t g_filesz
; /* Length of file */
400 time_t g_mtime
; /* Modification time */
401 uint_t g_cksum
; /* Checksum of file */
402 ulong_t g_devmajor
, /* File system of file */
403 g_devminor
; /* Major/minor of special files */
411 char pathname
[MAXNAM
+1]; /* added 1 for last NULL */
412 char attrname
[MAXNAM
+1];
413 struct linkbuf
*nextp
;
416 /* see comments before build_table() */
417 #define TABLE_SIZE 512
418 typedef struct file_list
{
419 char *name
; /* Name of file to {in,ex}clude */
420 struct file_list
*next
; /* Linked list */
422 static file_list_t
*exclude_tbl
[TABLE_SIZE
],
423 *include_tbl
[TABLE_SIZE
];
425 static int append_secattr(char **, int *, int, char *, char);
426 static void write_ancillary(union hblock
*, char *, int, char);
428 static void add_file_to_table(file_list_t
*table
[], char *str
);
429 static void assert_string(char *s
, char *msg
);
430 static int istape(int fd
, int type
);
431 static void backtape(void);
432 static void build_table(file_list_t
*table
[], char *file
);
433 static int check_prefix(char **namep
, char **dirp
, char **compp
);
434 static void closevol(void);
435 static void copy(void *dst
, void *src
);
436 static int convtoreg(off_t
);
437 static void delete_target(int fd
, char *comp
, char *namep
);
438 static void doDirTimes(char *name
, timestruc_t modTime
);
439 static void done(int n
);
440 static void dorep(char *argv
[]);
442 static void dotable(char *argv
[], int cnt
);
443 static void doxtract(char *argv
[], int cnt
);
445 static void dotable(char *argv
[]);
446 static void doxtract(char *argv
[]);
448 static void fatal(char *format
, ...);
449 static void vperror(int exit_status
, char *fmt
, ...);
450 static void flushtape(void);
451 static void getdir(void);
452 static void *getmem(size_t);
453 static void longt(struct stat
*st
, char aclchar
);
454 static void load_info_from_xtarhdr(u_longlong_t flag
, struct xtar_hdr
*xhdrp
);
455 static int makeDir(char *name
);
456 static void mterr(char *operation
, int i
, int exitcode
);
457 static void newvol(void);
458 static void passtape(void);
459 static void putempty(blkcnt_t n
);
460 static int putfile(char *longname
, char *shortname
, char *parent
,
461 attr_data_t
*attrinfo
, int filetype
, int lev
, int symlink_lev
);
462 static void readtape(char *buffer
);
463 static void seekdisk(blkcnt_t blocks
);
464 static void setPathTimes(int dirfd
, char *path
, timestruc_t modTime
);
465 static void setbytes_to_skip(struct stat
*st
, int err
);
466 static void splitfile(char *longname
, int ifd
, char *name
,
467 char *prefix
, int filetype
);
468 static void tomodes(struct stat
*sp
);
469 static void usage(void);
470 static int xblocks(int issysattr
, off_t bytes
, int ofile
);
471 static int xsfile(int issysattr
, int ofd
);
472 static void resugname(int dirfd
, char *name
, int symflag
);
473 static int bcheck(char *bstr
);
474 static int checkdir(char *name
);
475 static int checksum(union hblock
*dblockp
);
477 static int checksum_signed(union hblock
*dblockp
);
479 static int checkupdate(char *arg
);
480 static int checkw(char c
, char *name
);
481 static int cmp(char *b
, char *s
, int n
);
482 static int defset(char *arch
);
483 static int endtape(void);
484 static int is_in_table(file_list_t
*table
[], char *str
);
485 static int notsame(void);
486 static int is_prefix(char *s1
, char *s2
);
487 static int response(void);
488 static int build_dblock(const char *, const char *, const char,
489 const int filetype
, const struct stat
*, const dev_t
, const char *);
490 static unsigned int hash(char *str
);
493 static void initarg(char *argv
[], char *file
);
494 static char *nextarg();
496 static blkcnt_t
kcheck(char *kstr
);
497 static off_t
bsrch(char *s
, int n
, off_t l
, off_t h
);
498 static void onintr(int sig
);
499 static void onquit(int sig
);
500 static void onhup(int sig
);
501 static uid_t
getuidbyname(char *);
502 static gid_t
getgidbyname(char *);
503 static char *getname(gid_t
);
504 static char *getgroup(gid_t
);
505 static int checkf(char *name
, int mode
, int howmuch
);
506 static int writetbuf(char *buffer
, int n
);
507 static int wantit(char *argv
[], char **namep
, char **dirp
, char **comp
,
508 attr_data_t
**attrinfo
);
509 static void append_ext_attr(char *shortname
, char **secinfo
, int *len
);
510 static int get_xdata(void);
511 static void gen_num(const char *keyword
, const u_longlong_t number
);
512 static void gen_date(const char *keyword
, const timestruc_t time_value
);
513 static void gen_string(const char *keyword
, const char *value
);
514 static void get_xtime(char *value
, timestruc_t
*xtime
);
515 static int chk_path_build(char *name
, char *longname
, char *linkname
,
516 char *prefix
, char type
, int filetype
);
517 static int gen_utf8_names(const char *filename
);
518 static int utf8_local(char *option
, char **Xhdr_ptrptr
, char *target
,
519 const char *src
, int max_val
);
520 static int local_utf8(char **Xhdr_ptrptr
, char *target
, const char *src
,
521 iconv_t iconv_cd
, int xhdrflg
, int max_val
);
522 static int c_utf8(char *target
, const char *source
);
523 static int getstat(int dirfd
, char *longname
, char *shortname
,
525 static void xattrs_put(char *, char *, char *, char *);
526 static void prepare_xattr(char **, char *, char *,
527 char, struct linkbuf
*, int *);
528 static int put_link(char *name
, char *longname
, char *component
,
529 char *longattrname
, char *prefix
, int filetype
, char typeflag
);
530 static int put_extra_attributes(char *longname
, char *shortname
,
531 char *longattrname
, char *prefix
, int filetype
, char typeflag
);
532 static int put_xattr_hdr(char *longname
, char *shortname
, char *longattrname
,
533 char *prefix
, int typeflag
, int filetype
, struct linkbuf
*lp
);
534 static int read_xattr_hdr(attr_data_t
**attrinfo
);
536 /* Trusted Extensions */
537 #define AUTO_ZONE "/zone"
539 static void extract_attr(char **file_ptr
, struct sec_attr
*);
540 static int check_ext_attr(char *filename
);
541 static void rebuild_comp_path(char *str
, char **namep
);
542 static int rebuild_lk_comp_path(char *str
, char **namep
);
544 static void get_parent(char *path
, char *dir
);
545 static char *get_component(char *path
);
546 static int retry_open_attr(int pdirfd
, int cwd
, char *dirp
, char *pattr
,
547 char *name
, int oflag
, mode_t mode
);
548 static char *skipslashes(char *string
, char *start
);
549 static void chop_endslashes(char *path
);
550 static pid_t
compress_file(void);
551 static void compress_back(void);
552 static void decompress_file(void);
553 static pid_t
uncompress_file(void);
554 static void *compress_malloc(size_t);
555 static void check_compression();
556 static char *bz_suffix();
557 static char *gz_suffix();
558 static char *add_suffix();
559 static void wait_pid(pid_t
);
561 static struct stat stbuf
;
564 static int checkflag
= 0;
569 static int Xflag
, Fflag
, iflag
, hflag
, Bflag
, Iflag
;
570 static int rflag
, xflag
, vflag
, tflag
, mt
, svmt
, cflag
, mflag
, pflag
;
572 static int eflag
, errflag
, qflag
;
574 static int bflag
, kflag
, Aflag
;
575 static int Pflag
; /* POSIX conformant archive */
576 static int Eflag
; /* Allow files greater than 8GB */
577 static int atflag
; /* traverse extended attributes */
578 static int saflag
; /* traverse extended sys attributes */
579 static int Dflag
; /* Data change flag */
580 static int jflag
; /* flag to use 'bzip2' */
581 static int zflag
; /* flag to use 'gzip' */
582 static int Zflag
; /* flag to use 'compress' */
584 /* Trusted Extensions */
585 static int Tflag
; /* Trusted Extensions attr flags */
586 static int dir_flag
; /* for attribute extract */
587 static int mld_flag
; /* for attribute extract */
588 static char *orig_namep
; /* original namep - unadorned */
589 static int rpath_flag
; /* MLD real path is rebuilt */
590 static char real_path
[MAXPATHLEN
]; /* MLD real path */
591 static int lk_rpath_flag
; /* linked to real path is rebuilt */
592 static char lk_real_path
[MAXPATHLEN
]; /* linked real path */
593 static bslabel_t bs_label
; /* for attribute extract */
594 static bslabel_t admin_low
;
595 static bslabel_t admin_high
;
596 static int ignored_aprivs
= 0;
597 static int ignored_fprivs
= 0;
598 static int ignored_fattrs
= 0;
600 static int term
, chksum
, wflag
,
601 first
= TRUE
, defaults_used
= FALSE
, linkerrok
;
602 static blkcnt_t recno
;
603 static int freemem
= 1;
604 static int nblock
= NBLOCK
;
605 static int Errflg
= 0;
606 static int exitflag
= 0;
608 static dev_t mt_dev
; /* device containing output file */
609 static ino_t mt_ino
; /* inode number of output file */
610 static int mt_devtype
; /* dev type of archive, from stat structure */
612 static int update
= 1; /* for `open' call */
618 static FILE *vfile
= stdout
;
619 static char tname
[] = "/tmp/tarXXXXXX";
620 static char archive
[] = "archive0=";
622 static char *usefile
;
623 static char tfname
[1024];
624 static char *Filefile
;
626 static int mulvol
; /* multi-volume option selected */
627 static blkcnt_t blocklim
; /* number of blocks to accept per volume */
628 static blkcnt_t tapepos
; /* current block number to be written */
629 static int NotTape
; /* true if tape is a disk */
630 static int dumping
; /* true if writing a tape or other archive */
631 static int extno
; /* number of extent: starts at 1 */
632 static int extotal
; /* total extents in this file */
633 static off_t extsize
; /* size of current extent during extraction */
634 static ushort_t Oumask
= 0; /* old umask value */
635 static int is_posix
; /* true if archive we're reading is POSIX-conformant */
636 static const char *magic_type
= "ustar";
637 static size_t xrec_size
= 8 * PATH_MAX
; /* extended rec initial size */
638 static char *xrec_ptr
;
639 static off_t xrec_offset
= 0;
641 static int charset_type
= 0;
643 static u_longlong_t xhdr_flgs
; /* Bits set determine which items */
644 /* need to be in extended header. */
645 #define _X_DEVMAJOR 0x1
646 #define _X_DEVMINOR 0x2
649 #define _X_LINKPATH 0x10
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' */
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
692 * Simply assign "waitaround = 0" once you attach to the process, and then
693 * proceed from there as usual.
697 int waitaround
= 0; /* wait for rendezvous with the debugger */
700 #define BZIP "/usr/bin/bzip2"
701 #define GZIP "/usr/bin/gzip"
702 #define COMPRESS "/usr/bin/compress"
703 #define BZCAT "/usr/bin/bzcat"
704 #define GZCAT "/usr/bin/gzcat"
705 #define ZCAT "/usr/bin/zcat"
706 #define GS 8 /* number of valid 'gzip' sufixes */
707 #define BS 4 /* number of valid 'bzip2' sufixes */
709 static char *compress_opt
; /* compression type */
711 static char *gsuffix
[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
713 static char *bsuffix
[] = {".bz2", ".bz", ".tbz2", ".tbz"};
718 main(int argc
, char *argv
[])
728 sysv3_env
= getenv("SYSV3");
730 (void) setlocale(LC_ALL
, "");
731 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
732 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
734 (void) textdomain(TEXT_DOMAIN
);
739 if ((myname
= strdup(argv
[0])) == NULL
) {
740 (void) fprintf(stderr
, gettext(
741 "tar: cannot allocate program name\n"));
745 if (init_yes() < 0) {
746 (void) fprintf(stderr
, gettext(ERR_MSG_INIT_YES
),
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) {
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')
780 archive
[7] = (*cp
)? *cp
: '0';
781 if (!(defaults_used
= defset(archive
))) {
790 for (cp
= *argv
++; *cp
; cp
++)
794 /* rendezvous with the debugger */
799 assert_string(*argv
, gettext(
800 "tar: tarfile must be specified with 'f' "
801 "function modifier\n"));
807 assert_string(*argv
, gettext(
808 "tar: 'F' requires a file name\n"));
825 #if defined(_PC_SATTR_ENABLED)
829 #endif /* _PC_SATTR_ENABLED */
831 uflag
++; /* moved code after signals caught */
849 assert_string(*argv
, gettext(
850 "tar: exclude file must be specified with 'X' "
851 "function modifier\n"));
854 build_table(exclude_tbl
, Xfile
);
869 /* ignore this silently */
871 case '0': /* numeric entries used only for defaults */
881 assert_string(*argv
, gettext(
882 "tar: blocking factor must be specified "
883 "with 'b' function modifier\n"));
885 nblock
= bcheck(*argv
++);
891 assert_string(*argv
, gettext(
892 "tar: size value must be specified with 'k' "
893 "function modifier\n"));
895 blocklim
= kcheck(*argv
++);
897 case 'n': /* not a magtape (instead of 'k') */
898 NotTape
++; /* assume non-magtape */
905 /* If sysv3 IS set, don't be as verbose */
928 Pflag
++; /* Only POSIX archive made */
931 Tflag
++; /* Handle Trusted Extensions attrs */
932 pflag
++; /* also set flag for ACL */
934 case 'j': /* compession "bzip2" */
937 case 'z': /* compression "gzip" */
940 case 'Z': /* compression "compress" */
944 (void) fprintf(stderr
, gettext(
945 "tar: %c: unknown function modifier\n"), *cp
);
950 if (Xflag
&& Fileflag
) {
951 (void) fprintf(stderr
, gettext(
952 "tar: specify only one of X or F.\n"));
957 if (!rflag
&& !xflag
&& !tflag
)
959 if ((rflag
&& xflag
) || (xflag
&& tflag
) || (rflag
&& tflag
)) {
960 (void) fprintf(stderr
, gettext(
961 "tar: specify only one of [ctxru].\n"));
965 if ((zflag
&& jflag
) || (zflag
&& Zflag
) ||
967 (void) fprintf(stderr
, gettext(
968 "tar: specify only one of [jzZ] to "
969 "create a compressed file.\n"));
973 /* Trusted Extensions attribute handling */
974 if (Tflag
&& ((getzoneid() != GLOBAL_ZONEID
) ||
975 !is_system_labeled())) {
976 (void) fprintf(stderr
, gettext(
977 "tar: the 'T' option is only available with "
978 "Trusted Extensions\nand must be run from "
979 "the global zone.\n"));
982 if (cflag
&& *argv
== NULL
&& Filefile
== NULL
)
983 fatal(gettext("Missing filenames"));
985 fatal(gettext("device argument required"));
987 /* alloc a buffer of the right size */
988 if ((tbuf
= (union hblock
*)
989 calloc(sizeof (union hblock
) * nblock
, sizeof (char))) ==
990 (union hblock
*)NULL
) {
991 (void) fprintf(stderr
, gettext(
992 "tar: cannot allocate physio buffer\n"));
996 if ((xrec_ptr
= malloc(xrec_size
)) == NULL
) {
997 (void) fprintf(stderr
, gettext(
998 "tar: cannot allocate extended header buffer\n"));
1004 (void) fprintf(stderr
, gettext("Rendezvous with tar on pid"
1005 " %d\n"), getpid());
1007 while (waitaround
) {
1014 (void) sprintf(pidchars
, "%ld", thispid
);
1015 thispid
= strlen(pidchars
);
1017 if ((tmpdirp
= getenv("TMPDIR")) == (char *)NULL
)
1018 (void) strcpy(xhdr_dirname
, "/tmp");
1021 * Make sure that dir is no longer than what can
1022 * fit in the prefix part of the header.
1024 if (strlen(tmpdirp
) > (size_t)(PRESIZ
- thispid
- 12)) {
1025 (void) strcpy(xhdr_dirname
, "/tmp");
1026 if ((vflag
> 0) && (Eflag
> 0))
1027 (void) fprintf(stderr
, gettext(
1028 "Ignoring TMPDIR\n"));
1030 (void) strcpy(xhdr_dirname
, tmpdirp
);
1032 (void) strcat(xhdr_dirname
, "/PaxHeaders.");
1033 (void) strcat(xhdr_dirname
, pidchars
);
1036 if (cflag
&& usefile
!= NULL
) {
1037 /* Set the compression type */
1039 compress_opt
= compress_malloc(strlen(BZIP
)
1041 (void) strcpy(compress_opt
, BZIP
);
1043 compress_opt
= compress_malloc(strlen(GZIP
)
1045 (void) strcpy(compress_opt
, GZIP
);
1048 compress_malloc(strlen(COMPRESS
) + 1);
1049 (void) strcpy(compress_opt
, COMPRESS
);
1053 * Decompress if the file is compressed for
1054 * an update or replace.
1056 if (strcmp(usefile
, "-") != 0) {
1057 check_compression();
1058 if (compress_opt
!= NULL
) {
1064 if (cflag
&& tfile
!= NULL
)
1066 if (signal(SIGINT
, SIG_IGN
) != SIG_IGN
)
1067 (void) signal(SIGINT
, onintr
);
1068 if (signal(SIGHUP
, SIG_IGN
) != SIG_IGN
)
1069 (void) signal(SIGHUP
, onhup
);
1070 if (signal(SIGQUIT
, SIG_IGN
) != SIG_IGN
)
1071 (void) signal(SIGQUIT
, onquit
);
1074 if ((tnum
= mkstemp(tname
)) == -1)
1075 vperror(1, "%s", tname
);
1076 if ((tfile
= fdopen(tnum
, "w")) == NULL
)
1077 vperror(1, "%s", tname
);
1079 if (strcmp(usefile
, "-") == 0) {
1082 "can only create standard output archives."));
1089 O_RDWR
|O_CREAT
|O_TRUNC
, 0666);
1091 mt
= open(usefile
, O_RDWR
);
1094 if (cflag
== 0 || (mt
= creat(usefile
, 0666))
1096 vperror(1, "%s", usefile
);
1099 /* Get inode and device number of output file */
1100 (void) fstat(mt
, &stbuf
);
1101 mt_ino
= stbuf
.st_ino
;
1102 mt_dev
= stbuf
.st_dev
;
1103 mt_devtype
= stbuf
.st_mode
& S_IFMT
;
1104 NotTape
= !istape(mt
, mt_devtype
);
1106 if (rflag
&& !cflag
&& (mt_devtype
== S_IFIFO
))
1107 fatal(gettext("cannot append to pipe or FIFO."));
1111 gettext("Suppressing absolute pathnames\n"));
1112 if (cflag
&& compress_opt
!= NULL
) {
1113 pid
= compress_file();
1117 if (rflag
&& !cflag
&& (compress_opt
!= NULL
))
1119 } else if (xflag
|| tflag
) {
1121 * for each argument, check to see if there is a "-I file" pair.
1122 * if so, move the 3rd argument into "-I"'s place, build_table()
1123 * using "file"'s name and increment argc one (the second
1124 * increment appears in the for loop) which removes the two
1125 * args "-I" and "file" from the argument vector.
1127 for (argc
= 0; argv
[argc
]; argc
++) {
1128 if (strcmp(argv
[argc
], "-I") == 0) {
1129 if (!argv
[argc
+1]) {
1130 (void) fprintf(stderr
, gettext(
1131 "tar: missing argument for -I flag\n"));
1135 argv
[argc
] = argv
[argc
+2];
1136 build_table(include_tbl
, argv
[++argc
]);
1139 (void) fprintf(stderr
, gettext(
1140 "tar: only one of I or F.\n"));
1148 if (strcmp(usefile
, "-") == 0) {
1151 /* try to recover from short reads when reading stdin */
1153 } else if ((mt
= open(usefile
, 0)) < 0)
1154 vperror(1, "%s", usefile
);
1156 /* Decompress if the file is compressed */
1158 if (strcmp(usefile
, "-") != 0) {
1159 check_compression();
1160 if (compress_opt
!= NULL
) {
1161 pid
= uncompress_file();
1167 (void) printf(gettext(
1168 "Suppressing absolute pathnames.\n"));
1171 doxtract(argv
, tbl_cnt
);
1178 dotable(argv
, tbl_cnt
);
1188 /* Not reached: keep compiler quiet */
1198 (void) fprintf(stderr
, gettext(
1199 #if defined(O_XATTR)
1200 #if defined(_PC_SATTR_ENABLED)
1201 "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw@/[0-7]][bfFk][X...] "
1203 "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw@[0-7]][bfFk][X...] "
1204 #endif /* _PC_SATTR_ENABLED */
1206 "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw[0-7]][bfFk][X...] "
1207 #endif /* O_XATTR */
1209 "[blocksize] [tarfile] [filename] [size] [exclude-file...] "
1210 "{file | -I include-file | -C directory file}...\n"));
1214 (void) fprintf(stderr
, gettext(
1215 #if defined(O_XATTR)
1216 #if defined(_PC_SATTR_ENABLED)
1217 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw@/[0-7]][bfk][X...] "
1219 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw@[0-7]][bfk][X...] "
1220 #endif /* _PC_SATTR_ENABLED */
1222 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw[0-7]][bfk][X...] "
1223 #endif /* O_XATTR */
1225 "[blocksize] [tarfile] [size] [exclude-file...] "
1226 "{file | -I include-file | -C directory file}...\n"));
1232 * dorep - do "replacements"
1234 * Dorep is responsible for creating ('c'), appending ('r')
1235 * and updating ('u');
1242 char wdir
[PATH_MAX
+2], tempdir
[PATH_MAX
+2], *parent
;
1243 char file
[PATH_MAX
*2], origdir
[PATH_MAX
+1];
1244 FILE *fp
= (FILE *)NULL
;
1245 FILE *ff
= (FILE *)NULL
;
1252 getdir(); /* read header for next file */
1255 fatal(gettext("Archive contains extended"
1256 " header. -E flag required.\n"));
1257 ret
= get_xdata(); /* Get extended header items */
1258 /* and regular header */
1261 fatal(gettext("Archive contains no extended"
1262 " header. -E flag not allowed.\n"));
1264 while (!endtape()) { /* changed from a do while */
1265 setbytes_to_skip(&stbuf
, ret
);
1266 passtape(); /* skip the file data */
1268 done(Errflg
); /* received signal to stop */
1275 if ((dblock
.dbuf
.typeflag
!= 'A') &&
1277 load_info_from_xtarhdr(xhdr_flgs
,
1279 xhdr_flgs
|= _X_XHDR
;
1282 backtape(); /* was called by endtape */
1283 if (tfile
!= NULL
) {
1286 (void) sprintf(buf
, "sort +0 -1 +1nr %s -o %s; awk '$1 "
1287 "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1288 tname
, tname
, tname
, tname
, tname
, tname
);
1289 (void) fflush(tfile
);
1291 (void) freopen(tname
, "r", tfile
);
1292 (void) fstat(fileno(tfile
), &stbuf
);
1293 high
= stbuf
.st_size
;
1298 if (mulvol
) { /* SP-1 */
1299 if (nblock
&& (blocklim
%nblock
) != 0)
1301 "Volume size not a multiple of block size."));
1302 blocklim
-= 2; /* for trailer records */
1304 (void) fprintf(vfile
, gettext("Volume ends at %"
1305 FMT_blkcnt_t
"K, blocking factor = %dK\n"),
1306 K((blocklim
- 1)), K(nblock
));
1311 if (Filefile
!= NULL
) {
1312 if ((ff
= fopen(Filefile
, "r")) == NULL
)
1313 vperror(0, "%s", Filefile
);
1315 (void) fprintf(stderr
, gettext(
1316 "tar: F requires a file name.\n"));
1323 * Save the original directory before it gets
1326 if (getcwd(origdir
, (PATH_MAX
+1)) == NULL
) {
1327 vperror(0, gettext("A parent directory cannot be read"));
1331 (void) strcpy(wdir
, origdir
);
1333 while ((*argv
|| fp
|| ff
) && !term
) {
1334 if (fp
|| (strcmp(*argv
, "-I") == 0)) {
1337 (void) fprintf(stderr
, gettext(
1338 "tar: only one of I or F.\n"));
1343 if (*++argv
== NULL
)
1345 "missing file name for -I flag."));
1346 else if ((fp
= fopen(*argv
++, "r")) == NULL
)
1347 vperror(0, "%s", argv
[-1]);
1349 } else if ((fgets(file
, PATH_MAX
-1, fp
)) == NULL
) {
1355 if ((p
= strchr(cp2
, '\n')))
1358 } else if ((strcmp(*argv
, "-C") == 0) && argv
[1]) {
1361 (void) fprintf(stderr
, gettext(
1362 "tar: only one of F or C\n"));
1367 if (chdir(*++argv
) < 0)
1369 "can't change directories to %s"), *argv
);
1371 (void) getcwd(wdir
, (sizeof (wdir
)));
1375 } else if (Fileflag
&& (ff
!= NULL
)) {
1376 if ((fgets(file
, PATH_MAX
-1, ff
)) == NULL
) {
1382 if (p
= strchr(cp2
, '\n'))
1387 cp
= cp2
= strcpy(file
, *argv
++);
1390 * point cp2 to the last '/' in file, but not
1395 while (*(cp
+1) == '/') {
1398 if (*(cp
+1) != '\0') {
1399 /* not trailing slash */
1406 if (chdir(file
) < 0) {
1408 "can't change directories to %s"), file
);
1415 parent
= getcwd(tempdir
, (sizeof (tempdir
)));
1417 archtype
= putfile(file
, cp2
, parent
, NULL
, NORMAL_FILE
,
1418 LEV0
, SYMLINK_LEV0
);
1420 #if defined(O_XATTR)
1422 if ((atflag
|| saflag
) &&
1423 (archtype
== PUT_NOTAS_LINK
)) {
1424 xattrs_put(file
, cp2
, parent
, NULL
);
1429 if (chdir(origdir
) < 0)
1430 vperror(0, gettext("cannot change back?: %s"), origdir
);
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.
1444 putempty((blkcnt_t
)2);
1446 closevol(); /* SP-1 */
1448 for (; ihead
!= NULL
; ihead
= ihead
->nextp
) {
1449 if (ihead
->count
== 0)
1451 (void) fprintf(stderr
, gettext(
1452 "tar: missing links to %s\n"), ihead
->pathname
);
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
1476 if (dblock
.dbuf
.name
[0] == '\0') { /* null header = EOT */
1483 * getdir - get directory entry from tar tape
1485 * getdir reads the next tarblock off the tape and cracks
1486 * it as a directory. The checksum must match properly.
1488 * If tfile is non-null getdir writes the file name and mod date
1497 static int warn_chksum_sign
= 0;
1501 readtape((char *)&dblock
);
1502 if (dblock
.dbuf
.name
[0] == '\0')
1505 (void) sscanf(dblock
.dbuf
.mode
, "%8lo", &Gen
.g_mode
);
1506 (void) sscanf(dblock
.dbuf
.uid
, "%8lo", (ulong_t
*)&Gen
.g_uid
);
1507 (void) sscanf(dblock
.dbuf
.gid
, "%8lo", (ulong_t
*)&Gen
.g_gid
);
1508 (void) sscanf(dblock
.dbuf
.size
, "%12" FMT_off_t_o
, &Gen
.g_filesz
);
1509 (void) sscanf(dblock
.dbuf
.mtime
, "%12lo", (ulong_t
*)&Gen
.g_mtime
);
1510 (void) sscanf(dblock
.dbuf
.chksum
, "%8o", &Gen
.g_cksum
);
1511 (void) sscanf(dblock
.dbuf
.devmajor
, "%8lo", &Gen
.g_devmajor
);
1512 (void) sscanf(dblock
.dbuf
.devminor
, "%8lo", &Gen
.g_devminor
);
1514 is_posix
= (strcmp(dblock
.dbuf
.magic
, magic_type
) == 0);
1516 sp
->st_mode
= Gen
.g_mode
;
1517 if (is_posix
&& (sp
->st_mode
& S_IFMT
) == 0)
1518 switch (dblock
.dbuf
.typeflag
) {
1519 case '0': case 0: case _XATTR_HDRTYPE
:
1520 sp
->st_mode
|= S_IFREG
;
1522 case '1': /* hard link */
1525 sp
->st_mode
|= S_IFLNK
;
1528 sp
->st_mode
|= S_IFCHR
;
1531 sp
->st_mode
|= S_IFBLK
;
1534 sp
->st_mode
|= S_IFDIR
;
1537 sp
->st_mode
|= S_IFIFO
;
1540 if (convtoreg(Gen
.g_filesz
))
1541 sp
->st_mode
|= S_IFREG
;
1545 if ((dblock
.dbuf
.typeflag
== 'X') || (dblock
.dbuf
.typeflag
== 'L')) {
1546 Xhdrflag
= 1; /* Currently processing extended header */
1551 sp
->st_uid
= Gen
.g_uid
;
1552 sp
->st_gid
= Gen
.g_gid
;
1553 sp
->st_size
= Gen
.g_filesz
;
1554 sp
->st_mtime
= Gen
.g_mtime
;
1555 chksum
= Gen
.g_cksum
;
1557 if (dblock
.dbuf
.extno
!= '\0') { /* split file? */
1558 extno
= dblock
.dbuf
.extno
;
1559 extsize
= Gen
.g_filesz
;
1560 extotal
= dblock
.dbuf
.extotal
;
1562 extno
= 0; /* tell others file not split */
1568 if (chksum
!= checksum(&dblock
)) {
1569 if (chksum
!= checksum_signed(&dblock
)) {
1570 (void) fprintf(stderr
, gettext(
1571 "tar: directory checksum error\n"));
1576 if (! warn_chksum_sign
) {
1577 warn_chksum_sign
= 1;
1578 (void) fprintf(stderr
, gettext(
1579 "tar: warning: tar file made with signed checksum\n"));
1584 if (chksum
!= checksum(&dblock
)) {
1585 (void) fprintf(stderr
, gettext(
1586 "tar: directory checksum error\n"));
1592 if (tfile
!= NULL
&& Xhdrflag
== 0) {
1594 * If an extended header is present, then time is available
1595 * in nanoseconds in the extended header data, so set it.
1596 * Otherwise, give an invalid value so that checkupdate will
1597 * not test beyond seconds.
1599 if ((xhdr_flgs
& _X_MTIME
))
1600 sp
->st_mtim
.tv_nsec
= Xtarhdr
.x_mtime
.tv_nsec
;
1602 sp
->st_mtim
.tv_nsec
= -1;
1604 if (xhdr_flgs
& _X_PATH
)
1605 (void) fprintf(tfile
, "%s %10ld.%9.9ld\n",
1606 Xtarhdr
.x_path
, sp
->st_mtim
.tv_sec
,
1607 sp
->st_mtim
.tv_nsec
);
1609 (void) fprintf(tfile
, "%.*s %10ld.%9.9ld\n",
1610 NAMSIZ
, dblock
.dbuf
.name
, sp
->st_mtim
.tv_sec
,
1611 sp
->st_mtim
.tv_nsec
);
1614 #if defined(O_XATTR)
1616 if (xattrp
&& dblock
.dbuf
.typeflag
== _XATTR_HDRTYPE
) {
1623 char *aname
= basename(xattrapath
);
1624 size_t xindex
= aname
- xattrapath
;
1626 if (xattrapath
[xindex
] == '.' &&
1627 xattrapath
[xindex
+ 1] == '\0' &&
1628 xattrp
->h_typeflag
== '5') {
1631 (S_IFDIR
| (sp
->st_mode
& POSIXMODES
));
1633 dblock
.dbuf
.typeflag
= xattrp
->h_typeflag
;
1641 * passtape - skip over a file on the tape
1643 * passtape skips over the next data file on the tape.
1644 * The tape directory entry must be in dblock.dbuf. This
1645 * routine just eats the number of blocks computed from the
1646 * directory size entry; the tape must be (logically) positioned
1647 * right after thee directory info.
1657 * Types link(1), sym-link(2), char special(3), blk special(4),
1658 * directory(5), and FIFO(6) do not have data blocks associated
1659 * with them so just skip reading the data block.
1661 if (dblock
.dbuf
.typeflag
== '1' || dblock
.dbuf
.typeflag
== '2' ||
1662 dblock
.dbuf
.typeflag
== '3' || dblock
.dbuf
.typeflag
== '4' ||
1663 dblock
.dbuf
.typeflag
== '5' || dblock
.dbuf
.typeflag
== '6')
1665 blocks
= TBLOCKS(stbuf
.st_size
);
1667 /* if operating on disk, seek instead of reading */
1671 while (blocks
-- > 0)
1675 #if defined(O_XATTR)
1677 is_sysattr(char *name
)
1679 return ((strcmp(name
, VIEW_READONLY
) == 0) ||
1680 (strcmp(name
, VIEW_READWRITE
) == 0));
1684 #if defined(O_XATTR)
1686 * Verify the attribute, attrname, is an attribute we want to restore.
1687 * Never restore read-only system attribute files. Only restore read-write
1688 * system attributes files when -/ was specified, and only traverse into
1689 * the 2nd level attribute directory containing only system attributes if
1690 * -@ was specified. This keeps us from archiving
1691 * <attribute name>/<read-write system attribute file>
1692 * when -/ was specified without -@.
1694 * attrname - attribute file name
1695 * attrparent - attribute's parent name within the base file's attribute
1696 * directory hierarchy
1698 static attr_status_t
1699 verify_attr(char *attrname
, char *attrparent
, int arc_rwsysattr
,
1702 #if defined(_PC_SATTR_ENABLED)
1705 /* Never restore read-only system attribute files */
1706 if ((attr_supported
= sysattr_type(attrname
)) == _RO_SATTR
) {
1710 *rw_sysattr
= (attr_supported
== _RW_SATTR
);
1714 * Only need to check if this attribute is an extended system
1717 if (*rw_sysattr
= is_sysattr(attrname
)) {
1722 #endif /* _PC_SATTR_ENABLED */
1725 * If the extended system attribute file is specified with the
1726 * arc_rwsysattr flag, as being transient (default extended
1727 * attributes), then don't archive it.
1729 if (*rw_sysattr
&& !arc_rwsysattr
) {
1734 * Only restore read-write system attribute files
1735 * when -/ was specified. Only restore extended
1736 * attributes when -@ was specified.
1741 * Only archive/restore the hidden directory "." if
1742 * we're processing the top level hidden attribute
1743 * directory. We don't want to process the
1744 * hidden attribute directory of the attribute
1745 * directory that contains only extended system
1748 if (*rw_sysattr
|| (Hiddendir
&&
1749 (attrparent
!= NULL
))) {
1753 } else if (saflag
) {
1755 * Only archive/restore read-write extended system attribute
1756 * files of the base file.
1758 if (!*rw_sysattr
|| (attrparent
!= NULL
)) {
1770 free_children(file_list_t
*children
)
1772 file_list_t
*child
= children
;
1775 while (child
!= NULL
) {
1777 if (child
->name
!= NULL
) {
1785 putfile(char *longname
, char *shortname
, char *parent
, attr_data_t
*attrinfo
,
1786 int filetype
, int lev
, int symlink_lev
)
1788 int infile
= -1; /* deliberately invalid */
1790 char buf
[PATH_MAX
+ 2]; /* Add trailing slash and null */
1793 int hint
; /* amount to write to get "in sync" */
1794 char filetmp
[PATH_MAX
+ 1];
1797 char *attrparent
= NULL
;
1798 char *longattrname
= NULL
;
1799 file_list_t
*child
= NULL
;
1800 file_list_t
*child_end
= NULL
;
1807 int rc
= PUT_NOTAS_LINK
;
1810 char newparent
[PATH_MAX
+ MAXNAMLEN
+ 1];
1813 char goodbuf
[PRESIZ
+ 2];
1814 char junkbuf
[MAXNAM
+1];
1820 (void) memset(goodbuf
, '\0', sizeof (goodbuf
));
1821 (void) memset(junkbuf
, '\0', sizeof (junkbuf
));
1825 if (filetype
== XATTR_FILE
) {
1826 attrparent
= attrinfo
->attr_parent
;
1827 longattrname
= attrinfo
->attr_path
;
1828 dirfd
= attrinfo
->attr_parentfd
;
1829 rw_sysattr
= attrinfo
->attr_rw_sysattr
;
1831 dirfd
= open(".", O_RDONLY
);
1835 (void) fprintf(stderr
, gettext(
1836 "tar: unable to open%sdirectory %s%s%s%s\n"),
1837 (filetype
== XATTR_FILE
) ? gettext(" attribute ") : " ",
1838 (attrparent
== NULL
) ? "" : gettext("of attribute "),
1839 (attrparent
== NULL
) ? "" : attrparent
,
1840 (attrparent
== NULL
) ? "" : gettext(" of "),
1841 (filetype
== XATTR_FILE
) ? longname
: parent
);
1846 (void) fprintf(stderr
,
1847 gettext("tar: directory nesting too deep, %s not dumped\n"),
1852 if (getstat(dirfd
, longname
, shortname
, attrparent
))
1857 * Catch nesting where a file is a symlink to its directory.
1859 j
= fstatat(dirfd
, shortname
, &sbuf
, AT_SYMLINK_NOFOLLOW
);
1860 if (S_ISLNK(sbuf
.st_mode
)) {
1861 if (symlink_lev
++ >= MAXSYMLINKS
) {
1862 (void) fprintf(stderr
, gettext(
1863 "tar: %s: Number of symbolic links "
1864 "encountered during path name traversal "
1865 "exceeds MAXSYMLINKS\n"), longname
);
1873 * Check if the input file is the same as the tar file we
1876 if ((mt_ino
== stbuf
.st_ino
) && (mt_dev
== stbuf
.st_dev
)) {
1877 (void) fprintf(stderr
, gettext(
1878 "tar: %s%s%s%s%s same as archive file\n"),
1879 rw_sysattr
? gettext("system ") : "",
1880 (longattrname
== NULL
) ? "" : gettext("attribute "),
1881 (longattrname
== NULL
) ? "" : longattrname
,
1882 (longattrname
== NULL
) ? "" : gettext(" of "),
1888 * Check size limit - we can't archive files that
1889 * exceed TAR_OFFSET_MAX bytes because of header
1890 * limitations. Exclude file types that set
1891 * st_size to zero below because they take no
1892 * archive space to represent contents.
1894 if ((stbuf
.st_size
> (off_t
)TAR_OFFSET_MAX
) &&
1895 !S_ISDIR(stbuf
.st_mode
) &&
1896 !S_ISCHR(stbuf
.st_mode
) &&
1897 !S_ISBLK(stbuf
.st_mode
) &&
1899 (void) fprintf(stderr
, gettext(
1900 "tar: %s%s%s%s%s too large to archive. "
1901 "Use E function modifier.\n"),
1902 rw_sysattr
? gettext("system ") : "",
1903 (longattrname
== NULL
) ? "" : gettext("attribute "),
1904 (longattrname
== NULL
) ? "" : longattrname
,
1905 (longattrname
== NULL
) ? "" : gettext(" of "),
1913 if (tfile
!= NULL
&& checkupdate(longname
) == 0) {
1916 if (checkw('r', longname
) == 0) {
1920 if (Fflag
&& checkf(shortname
, stbuf
.st_mode
, Fflag
) == 0)
1924 if (is_in_table(exclude_tbl
, longname
)) {
1926 (void) fprintf(vfile
, gettext(
1927 "a %s excluded\n"), longname
);
1934 * If the length of the fullname is greater than MAXNAM,
1935 * print out a message and return (unless extended headers are used,
1936 * in which case fullname is limited to PATH_MAX).
1939 if ((((split
= (int)strlen(longname
)) > MAXNAM
) && (Eflag
== 0)) ||
1940 (split
> PATH_MAX
)) {
1941 (void) fprintf(stderr
, gettext(
1942 "tar: %s: file name too long\n"), longname
);
1950 * We split the fullname into prefix and name components if any one
1951 * of three conditions holds:
1952 * -- the length of the fullname exceeds NAMSIZ,
1953 * -- the length of the fullname equals NAMSIZ, and the shortname
1954 * is less than NAMSIZ, (splitting in this case preserves
1955 * compatibility with 5.6 and 5.5.1 tar), or
1956 * -- the length of the fullname equals NAMSIZ, the file is a
1957 * directory and we are not in POSIX-conformant mode (where
1958 * trailing slashes are removed from directories).
1960 if ((split
> NAMSIZ
) ||
1961 (split
== NAMSIZ
&& strlen(shortname
) < NAMSIZ
) ||
1962 (split
== NAMSIZ
&& S_ISDIR(stbuf
.st_mode
) && !Pflag
)) {
1964 * Since path is limited to PRESIZ characters, look for the
1965 * last slash within PRESIZ + 1 characters only.
1967 (void) strncpy(&goodbuf
[0], longname
, min(split
, PRESIZ
+ 1));
1969 lastslash
= strrchr(tmpbuf
, '/');
1970 if (lastslash
== NULL
) {
1971 i
= split
; /* Length of name */
1972 j
= 0; /* Length of prefix */
1975 *lastslash
= '\0'; /* Terminate the prefix */
1980 * If the filename is greater than NAMSIZ we can't
1981 * archive the file unless we are using extended headers.
1983 if ((i
> NAMSIZ
) || (i
== NAMSIZ
&& S_ISDIR(stbuf
.st_mode
) &&
1985 /* Determine which (filename or path) is too long. */
1986 lastslash
= strrchr(longname
, '/');
1987 if (lastslash
!= NULL
)
1988 i
= strlen(lastslash
+ 1);
1990 xhdr_flgs
|= _X_PATH
;
1991 Xtarhdr
.x_path
= longname
;
1993 (void) strcpy(junkbuf
, lastslash
+ 1);
1995 (void) sprintf(junkbuf
, "%llu",
1997 if (split
- i
- 1 > PRESIZ
)
1998 (void) strcpy(goodbuf
, xhdr_dirname
);
2000 if ((i
> NAMSIZ
) || (i
== NAMSIZ
&&
2001 S_ISDIR(stbuf
.st_mode
) && !Pflag
))
2002 (void) fprintf(stderr
, gettext(
2003 "tar: %s: filename is greater than "
2004 "%d\n"), lastslash
== NULL
?
2005 longname
: lastslash
+ 1, NAMSIZ
);
2007 (void) fprintf(stderr
, gettext(
2008 "tar: %s: prefix is greater than %d"
2009 "\n"), longname
, PRESIZ
);
2016 (void) strncpy(&junkbuf
[0], longname
+ j
+ 1,
2017 strlen(longname
+ j
+ 1));
2024 if ((prefix
!= NULL
) && (*prefix
!= '\0'))
2025 while (*prefix
== '/')
2028 while (*name
== '/')
2032 switch (stbuf
.st_mode
& S_IFMT
) {
2034 stbuf
.st_size
= (off_t
)0;
2035 blocks
= TBLOCKS(stbuf
.st_size
);
2037 if (filetype
!= XATTR_FILE
&& Hiddendir
== 0) {
2040 while ((*cp
++ = longname
[i
++]))
2047 if (build_dblock(name
, tchar
, '5', filetype
,
2048 &stbuf
, stbuf
.st_dev
, prefix
) != 0) {
2053 * Old archives require a slash at the end
2054 * of a directory name.
2057 * If directory name is too long, will
2058 * slash overfill field?
2060 if (strlen(name
) > (unsigned)NAMSIZ
-1) {
2061 (void) fprintf(stderr
, gettext(
2062 "tar: %s: filename is greater "
2063 "than %d\n"), name
, NAMSIZ
);
2069 if (strlen(name
) == (NAMSIZ
- 1)) {
2070 (void) memcpy(dblock
.dbuf
.name
,
2072 dblock
.dbuf
.name
[NAMSIZ
-1]
2075 (void) sprintf(dblock
.dbuf
.name
,
2079 * need to recalculate checksum
2080 * because the name changed.
2082 (void) sprintf(dblock
.dbuf
.chksum
,
2083 "%07o", checksum(&dblock
));
2087 if (put_extra_attributes(longname
, shortname
,
2088 longattrname
, prefix
, filetype
, '5') != 0)
2091 #if defined(O_XATTR)
2093 * Reset header typeflag when archiving directory, since
2094 * build_dblock changed it on us.
2096 if (filetype
== XATTR_FILE
) {
2097 dblock
.dbuf
.typeflag
= _XATTR_HDRTYPE
;
2099 dblock
.dbuf
.typeflag
= '5';
2102 dblock
.dbuf
.typeflag
= '5';
2105 (void) sprintf(dblock
.dbuf
.chksum
, "%07o",
2108 (void) writetbuf((char *)&dblock
, 1);
2113 DEBUG("seek = %" FMT_blkcnt_t
"K\t", K(tapepos
),
2116 if (filetype
== XATTR_FILE
&& Hiddendir
) {
2117 (void) fprintf(vfile
, "a %s attribute %s ",
2118 longname
, longattrname
);
2121 (void) fprintf(vfile
, "a %s/ ", longname
);
2124 (void) fprintf(vfile
, "%" FMT_blkcnt_t
"K\n",
2127 (void) fprintf(vfile
, gettext("%" FMT_blkcnt_t
2128 " tape blocks\n"), blocks
);
2132 * If hidden dir then break now since xattrs_put() will do
2133 * the iterating of the directory.
2135 * At the moment, there can only be system attributes on
2136 * attributes. There can be no attributes on attributes or
2137 * directories within the attributes hidden directory hierarchy.
2139 if (filetype
== XATTR_FILE
)
2142 if (*shortname
!= '/')
2143 (void) sprintf(newparent
, "%s/%s", parent
, shortname
);
2145 (void) sprintf(newparent
, "%s", shortname
);
2147 if (chdir(shortname
) < 0) {
2148 vperror(0, "%s", newparent
);
2152 if ((dirp
= opendir(".")) == NULL
) {
2154 "can't open directory %s"), longname
);
2155 if (chdir(parent
) < 0)
2156 vperror(0, gettext("cannot change back?: %s"),
2162 * Create a list of files (children) in this directory to avoid
2163 * having to perform telldir()/seekdir().
2165 while ((dp
= readdir(dirp
)) != NULL
&& !term
) {
2166 if ((strcmp(".", dp
->d_name
) == 0) ||
2167 (strcmp("..", dp
->d_name
) == 0))
2169 if (((cptr
= (file_list_t
*)calloc(sizeof (char),
2170 sizeof (file_list_t
))) == NULL
) ||
2171 ((cptr
->name
= strdup(dp
->d_name
)) == NULL
)) {
2173 "Insufficient memory for directory "
2174 "list entry %s/%s\n"),
2175 newparent
, dp
->d_name
);
2178 /* Add the file to the list */
2179 if (child
== NULL
) {
2182 child_end
->next
= cptr
;
2186 (void) closedir(dirp
);
2189 * Archive each of the files in the current directory.
2190 * If a file is a directory, putfile() is called
2191 * recursively to archive the file hierarchy of the
2192 * directory before archiving the next file in the
2193 * current directory.
2195 while ((child
!= NULL
) && !term
) {
2196 (void) strcpy(cp
, child
->name
);
2197 archtype
= putfile(buf
, cp
, newparent
, NULL
,
2198 NORMAL_FILE
, lev
+ 1, symlink_lev
);
2201 if ((atflag
|| saflag
) &&
2202 (archtype
== PUT_NOTAS_LINK
)) {
2203 xattrs_put(buf
, cp
, newparent
, NULL
);
2209 /* Free each child as we are done processing it. */
2211 child
= child
->next
;
2215 if ((child
!= NULL
) && !term
) {
2216 free_children(child
);
2219 if (chdir(parent
) < 0) {
2220 vperror(0, gettext("cannot change back?: %s"), parent
);
2226 readlink_max
= NAMSIZ
;
2227 if (stbuf
.st_size
> NAMSIZ
) {
2229 xhdr_flgs
|= _X_LINKPATH
;
2230 readlink_max
= PATH_MAX
;
2232 (void) fprintf(stderr
, gettext(
2233 "tar: %s: symbolic link too long\n"),
2242 * Sym-links need header size of zero since you
2243 * don't store any data for this type.
2245 stbuf
.st_size
= (off_t
)0;
2247 i
= readlink(shortname
, filetmp
, readlink_max
);
2250 "can't read symbolic link %s"), longname
);
2256 (void) fprintf(vfile
, gettext(
2257 "a %s symbolic link to %s\n"),
2259 if (xhdr_flgs
& _X_LINKPATH
) {
2260 Xtarhdr
.x_linkpath
= filetmp
;
2261 if (build_dblock(name
, tchar
, '2', filetype
, &stbuf
,
2262 stbuf
.st_dev
, prefix
) != 0)
2265 if (build_dblock(name
, filetmp
, '2', filetype
, &stbuf
,
2266 stbuf
.st_dev
, prefix
) != 0)
2268 (void) writetbuf((char *)&dblock
, 1);
2270 * No acls for symlinks: mode is always 777
2271 * dont call write ancillary
2276 if ((infile
= openat(dirfd
, shortname
, 0)) < 0) {
2277 vperror(0, "unable to open %s%s%s%s", longname
,
2278 rw_sysattr
? gettext(" system") : "",
2279 (filetype
== XATTR_FILE
) ?
2280 gettext(" attribute ") : "",
2281 (filetype
== XATTR_FILE
) ? (longattrname
== NULL
) ?
2282 shortname
: longattrname
: "");
2286 blocks
= TBLOCKS(stbuf
.st_size
);
2288 if (put_link(name
, longname
, shortname
, longattrname
,
2289 prefix
, filetype
, '1') == 0) {
2290 (void) close(infile
);
2297 /* correctly handle end of volume */
2298 while (mulvol
&& tapepos
+ blocks
+ 1 > blocklim
) {
2299 /* file won't fit */
2301 if (blocks
<= blocklim
) {
2305 (void) fprintf(stderr
, gettext(
2306 "tar: Single file cannot fit on volume\n"));
2309 /* split if floppy has some room and file is large */
2310 if (((blocklim
- tapepos
) >= EXTMIN
) &&
2311 ((blocks
+ 1) >= blocklim
/10)) {
2312 splitfile(longname
, infile
,
2313 name
, prefix
, filetype
);
2314 (void) close(dirfd
);
2315 (void) close(infile
);
2318 newvol(); /* not worth it--just get new volume */
2321 DEBUG("putfile: %s wants %" FMT_blkcnt_t
" blocks\n", longname
,
2324 if (build_dblock(name
, tchar
, '0', filetype
,
2325 &stbuf
, stbuf
.st_dev
, prefix
) != 0) {
2331 DEBUG("seek = %" FMT_blkcnt_t
"K\t", K(tapepos
),
2334 (void) fprintf(vfile
, "a %s%s%s%s ", longname
,
2335 rw_sysattr
? gettext(" system") : "",
2336 (filetype
== XATTR_FILE
) ? gettext(
2337 " attribute ") : "",
2338 (filetype
== XATTR_FILE
) ?
2341 (void) fprintf(vfile
, "%" FMT_blkcnt_t
"K\n",
2344 (void) fprintf(vfile
,
2345 gettext("%" FMT_blkcnt_t
" tape blocks\n"),
2349 if (put_extra_attributes(longname
, shortname
, longattrname
,
2350 prefix
, filetype
, '0') != 0)
2354 * No need to reset typeflag for extended attribute here, since
2355 * put_extra_attributes already set it and we haven't called
2358 (void) sprintf(dblock
.dbuf
.chksum
, "%07o", checksum(&dblock
));
2359 hint
= writetbuf((char *)&dblock
, 1);
2360 maxread
= max(min(stbuf
.st_blksize
, stbuf
.st_size
),
2362 if ((bigbuf
= calloc((unsigned)maxread
, sizeof (char))) == 0) {
2368 read(infile
, bigbuf
, min((hint
*TBLOCK
), maxread
))) > 0) &&
2372 nblks
= ((i
-1)/TBLOCK
)+1;
2375 hint
= writetbuf(bigbuf
, nblks
);
2378 (void) close(infile
);
2382 vperror(0, gettext("Read error on %s"), longname
);
2383 else if (blocks
!= 0 || i
!= 0) {
2384 (void) fprintf(stderr
, gettext(
2385 "tar: %s: file changed size\n"), longname
);
2389 } else if (!Dflag
) {
2396 blocks
= TBLOCKS(stbuf
.st_size
);
2397 stbuf
.st_size
= (off_t
)0;
2399 if (put_link(name
, longname
, shortname
, longattrname
,
2400 prefix
, filetype
, '6') == 0) {
2406 while (mulvol
&& tapepos
+ blocks
+ 1 > blocklim
) {
2408 if (blocks
<= blocklim
) {
2412 (void) fprintf(stderr
, gettext(
2413 "tar: Single file cannot fit on volume\n"));
2417 if (((blocklim
- tapepos
) >= EXTMIN
) &&
2418 ((blocks
+ 1) >= blocklim
/10)) {
2419 splitfile(longname
, infile
, name
,
2421 (void) close(dirfd
);
2422 (void) close(infile
);
2428 DEBUG("putfile: %s wants %" FMT_blkcnt_t
" blocks\n", longname
,
2434 DEBUG("seek = %" FMT_blkcnt_t
"K\t", K(tapepos
),
2438 (void) fprintf(vfile
, gettext("a %s %"
2439 FMT_blkcnt_t
"K\n "), longname
, K(blocks
));
2441 (void) fprintf(vfile
, gettext(
2442 "a %s %" FMT_blkcnt_t
" tape blocks\n"),
2445 if (build_dblock(name
, tchar
, '6', filetype
,
2446 &stbuf
, stbuf
.st_dev
, prefix
) != 0)
2449 if (put_extra_attributes(longname
, shortname
, longattrname
,
2450 prefix
, filetype
, '6') != 0)
2453 (void) sprintf(dblock
.dbuf
.chksum
, "%07o", checksum(&dblock
));
2454 dblock
.dbuf
.typeflag
= '6';
2456 (void) writetbuf((char *)&dblock
, 1);
2459 stbuf
.st_size
= (off_t
)0;
2460 blocks
= TBLOCKS(stbuf
.st_size
);
2461 if (put_link(name
, longname
, shortname
, longattrname
,
2462 prefix
, filetype
, '3') == 0) {
2468 while (mulvol
&& tapepos
+ blocks
+ 1 > blocklim
) {
2470 if (blocks
<= blocklim
) {
2474 (void) fprintf(stderr
, gettext(
2475 "tar: Single file cannot fit on volume\n"));
2479 if (((blocklim
- tapepos
) >= EXTMIN
) &&
2480 ((blocks
+ 1) >= blocklim
/10)) {
2481 splitfile(longname
, infile
, name
,
2483 (void) close(dirfd
);
2489 DEBUG("putfile: %s wants %" FMT_blkcnt_t
" blocks\n", longname
,
2495 DEBUG("seek = %" FMT_blkcnt_t
"K\t", K(tapepos
),
2499 (void) fprintf(vfile
, gettext("a %s %"
2500 FMT_blkcnt_t
"K\n"), longname
, K(blocks
));
2502 (void) fprintf(vfile
, gettext("a %s %"
2503 FMT_blkcnt_t
" tape blocks\n"), longname
,
2506 if (build_dblock(name
, tchar
, '3',
2507 filetype
, &stbuf
, stbuf
.st_rdev
, prefix
) != 0)
2510 if (put_extra_attributes(longname
, shortname
, longattrname
,
2511 prefix
, filetype
, '3') != 0)
2514 (void) sprintf(dblock
.dbuf
.chksum
, "%07o", checksum(&dblock
));
2515 dblock
.dbuf
.typeflag
= '3';
2517 (void) writetbuf((char *)&dblock
, 1);
2520 stbuf
.st_size
= (off_t
)0;
2521 blocks
= TBLOCKS(stbuf
.st_size
);
2522 if (put_link(name
, longname
, shortname
, longattrname
,
2523 prefix
, filetype
, '4') == 0) {
2529 while (mulvol
&& tapepos
+ blocks
+ 1 > blocklim
) {
2531 if (blocks
<= blocklim
) {
2535 (void) fprintf(stderr
, gettext(
2536 "tar: Single file cannot fit on volume\n"));
2540 if (((blocklim
- tapepos
) >= EXTMIN
) &&
2541 ((blocks
+ 1) >= blocklim
/10)) {
2542 splitfile(longname
, infile
,
2543 name
, prefix
, filetype
);
2544 (void) close(dirfd
);
2550 DEBUG("putfile: %s wants %" FMT_blkcnt_t
" blocks\n", longname
,
2556 DEBUG("seek = %" FMT_blkcnt_t
"K\t", K(tapepos
),
2559 (void) fprintf(vfile
, "a %s ", longname
);
2561 (void) fprintf(vfile
, "%" FMT_blkcnt_t
"K\n",
2564 (void) fprintf(vfile
, gettext("%"
2565 FMT_blkcnt_t
" tape blocks\n"), blocks
);
2567 if (build_dblock(name
, tchar
, '4',
2568 filetype
, &stbuf
, stbuf
.st_rdev
, prefix
) != 0)
2571 if (put_extra_attributes(longname
, shortname
, longattrname
,
2572 prefix
, filetype
, '4') != 0)
2575 (void) sprintf(dblock
.dbuf
.chksum
, "%07o", checksum(&dblock
));
2576 dblock
.dbuf
.typeflag
= '4';
2578 (void) writetbuf((char *)&dblock
, 1);
2581 (void) fprintf(stderr
, gettext(
2582 "tar: %s is not a file. Not dumped\n"), longname
);
2590 if ((dirfd
!= -1) && (filetype
!= XATTR_FILE
)) {
2591 (void) close(dirfd
);
2598 * splitfile dump a large file across volumes
2600 * splitfile(longname, fd);
2601 * char *longname; full name of file
2602 * int ifd; input file descriptor
2604 * NOTE: only called by putfile() to dump a large file.
2608 splitfile(char *longname
, int ifd
, char *name
, char *prefix
, int filetype
)
2615 blocks
= TBLOCKS(stbuf
.st_size
); /* blocks file needs */
2619 * size of file after using up rest of this floppy
2620 * blocks - (blocklim - tapepos) + 1 (for header)
2621 * plus roundup value before divide by blocklim-1
2622 * + (blocklim - 1) - 1
2623 * all divided by blocklim-1 (one block for each header).
2625 * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2626 * which reduces to the expression used.
2627 * one is added to account for this first extent.
2629 * When one is dealing with extremely large archives, one may want
2630 * to allow for a large number of extents. This code should be
2631 * revisited to determine if extents should be changed to something
2632 * larger than an int.
2634 extents
= (int)((blocks
+ tapepos
- 1ULL)/(blocklim
- 1ULL) + 1);
2636 if (extents
< 2 || extents
> MAXEXT
) { /* let's be reasonable */
2637 (void) fprintf(stderr
, gettext(
2638 "tar: %s needs unusual number of volumes to split\n"
2639 "tar: %s not dumped\n"), longname
, longname
);
2642 if (build_dblock(name
, tchar
, '0', filetype
,
2643 &stbuf
, stbuf
.st_dev
, prefix
) != 0)
2646 dblock
.dbuf
.extotal
= extents
;
2647 bytes
= stbuf
.st_size
;
2650 * The value contained in dblock.dbuf.efsize was formerly used when the
2651 * v flag was specified in conjunction with the t flag. Although it is
2652 * no longer used, older versions of tar will expect the former
2653 * behaviour, so we must continue to write it to the archive.
2655 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2656 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2659 if (bytes
<= TAR_EFSIZE_MAX
)
2660 (void) sprintf(dblock
.dbuf
.efsize
, "%9" FMT_off_t_o
, bytes
);
2662 (void) sprintf(dblock
.dbuf
.efsize
, "%9" FMT_off_t_o
, (off_t
)0);
2664 (void) fprintf(stderr
, gettext(
2665 "tar: large file %s needs %d extents.\n"
2666 "tar: current device seek position = %" FMT_blkcnt_t
"K\n"),
2667 longname
, extents
, K(tapepos
));
2669 s
= (off_t
)(blocklim
- tapepos
- 1) * TBLOCK
;
2670 for (i
= 1; i
<= extents
; i
++) {
2674 s
= bytes
; /* last ext. gets true bytes */
2676 s
= (off_t
)(blocklim
- 1)*TBLOCK
; /* all */
2679 blocks
= TBLOCKS(s
);
2681 (void) sprintf(dblock
.dbuf
.size
, "%011" FMT_off_t_o
, s
);
2682 dblock
.dbuf
.extno
= i
;
2683 (void) sprintf(dblock
.dbuf
.chksum
, "%07o", checksum(&dblock
));
2684 (void) writetbuf((char *)&dblock
, 1);
2687 (void) fprintf(vfile
,
2688 "+++ a %s %" FMT_blkcnt_t
"K [extent #%d of %d]\n",
2689 longname
, K(blocks
), i
, extents
);
2690 while (blocks
&& read(ifd
, buf
, TBLOCK
) > 0) {
2692 (void) writetbuf(buf
, 1);
2695 (void) fprintf(stderr
, gettext(
2696 "tar: %s: file changed size\n"), longname
);
2697 (void) fprintf(stderr
, gettext(
2698 "tar: aborting split file %s\n"), longname
);
2705 (void) fprintf(vfile
, gettext("a %s %" FMT_off_t
"K (in %d "
2706 "extents)\n"), longname
, K(TBLOCKS(stbuf
.st_size
)),
2711 * convtoreg - determines whether the file should be converted to a
2712 * regular file when extracted
2714 * Returns 1 when file size > 0 and typeflag is not recognized
2715 * Otherwise returns 0
2718 convtoreg(off_t size
)
2720 if ((size
> 0) && (dblock
.dbuf
.typeflag
!= '0') &&
2721 (dblock
.dbuf
.typeflag
!= NULL
) && (dblock
.dbuf
.typeflag
!= '1') &&
2722 (dblock
.dbuf
.typeflag
!= '2') && (dblock
.dbuf
.typeflag
!= '3') &&
2723 (dblock
.dbuf
.typeflag
!= '4') && (dblock
.dbuf
.typeflag
!= '5') &&
2724 (dblock
.dbuf
.typeflag
!= '6') && (dblock
.dbuf
.typeflag
!= 'A') &&
2725 (dblock
.dbuf
.typeflag
!= 'L') &&
2726 (dblock
.dbuf
.typeflag
!= _XATTR_HDRTYPE
) &&
2727 (dblock
.dbuf
.typeflag
!= 'X')) {
2733 #if defined(O_XATTR)
2737 return (open(".", O_RDONLY
));
2741 #if defined(O_XATTR)
2746 if (fchdir(*cwd
) < 0) {
2748 "Cannot fchdir to attribute directory"));
2758 * Verify the underlying file system supports the attribute type.
2759 * Only archive extended attribute files when '-@' was specified.
2760 * Only archive system extended attribute files if '-/' was specified.
2762 #if defined(O_XATTR)
2763 static attr_status_t
2764 verify_attr_support(char *filename
, int attrflg
, arc_action_t actflag
,
2768 * Verify extended attributes are supported/exist. We only
2769 * need to check if we are processing a base file, not an
2770 * extended attribute.
2773 *ext_attrflg
= (pathconf(filename
, (actflag
== ARC_CREATE
) ?
2774 _PC_XATTR_EXISTS
: _PC_XATTR_ENABLED
) == 1);
2778 if (!*ext_attrflg
) {
2779 #if defined(_PC_SATTR_ENABLED)
2781 /* Verify system attributes are supported */
2782 if (sysattr_support(filename
,
2783 (actflag
== ARC_CREATE
) ? _PC_SATTR_EXISTS
:
2784 _PC_SATTR_ENABLED
) != 1) {
2785 return (ATTR_SATTR_ERR
);
2788 return (ATTR_XATTR_ERR
);
2790 return (ATTR_XATTR_ERR
);
2791 #endif /* _PC_SATTR_ENABLED */
2794 #if defined(_PC_SATTR_ENABLED)
2795 } else if (saflag
) {
2796 /* Verify system attributes are supported */
2797 if (sysattr_support(filename
, (actflag
== ARC_CREATE
) ?
2798 _PC_SATTR_EXISTS
: _PC_SATTR_ENABLED
) != 1) {
2799 return (ATTR_SATTR_ERR
);
2801 #endif /* _PC_SATTR_ENABLED */
2810 #if defined(O_XATTR)
2812 * Recursively open attribute directories until the attribute directory
2813 * containing the specified attribute, attrname, is opened.
2815 * Currently, only 2 directory levels of attributes are supported, (i.e.,
2816 * extended system attributes on extended attributes). The following are
2817 * the possible input combinations:
2818 * 1. Open the attribute directory of the base file (don't change
2820 * attrinfo->parent = NULL
2822 * 2. Open the attribute directory of the base file and change into it.
2823 * attrinfo->parent = NULL
2824 * attrname = <attr> | <sys_attr>
2825 * 3. Open the attribute directory of the base file, change into it,
2826 * then recursively call open_attr_dir() to open the attribute's
2827 * parent directory (don't change into it).
2828 * attrinfo->parent = <attr>
2830 * 4. Open the attribute directory of the base file, change into it,
2831 * then recursively call open_attr_dir() to open the attribute's
2832 * parent directory and change into it.
2833 * attrinfo->parent = <attr>
2834 * attrname = <attr> | <sys_attr>
2836 * An attribute directory will be opened only if the underlying file system
2837 * supports the attribute type, and if the command line specifications (atflag
2838 * and saflag) enable the processing of the attribute type.
2840 * On succesful return, attrinfo->parentfd will be the file descriptor of the
2841 * opened attribute directory. In addition, if the attribute is a read-write
2842 * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2843 * it will be set to 0.
2845 * Possible return values:
2846 * ATTR_OK Successfully opened and, if needed, changed into the
2847 * attribute directory containing attrname.
2848 * ATTR_SKIP The command line specifications don't enable the
2849 * processing of the attribute type.
2850 * ATTR_CHDIR_ERR An error occurred while trying to change into an
2851 * attribute directory.
2852 * ATTR_OPEN_ERR An error occurred while trying to open an
2853 * attribute directory.
2854 * ATTR_XATTR_ERR The underlying file system doesn't support extended
2856 * ATTR_SATTR_ERR The underlying file system doesn't support extended
2857 * system attributes.
2860 open_attr_dir(char *attrname
, char *dirp
, int cwd
, attr_data_t
*attrinfo
)
2863 int firsttime
= (attrinfo
->attr_parentfd
== -1);
2868 * open_attr_dir() was recursively called (input combination number 4),
2869 * close the previously opened file descriptor as we've already changed
2873 (void) close(attrinfo
->attr_parentfd
);
2874 attrinfo
->attr_parentfd
= -1;
2878 * Verify that the underlying file system supports the restoration
2881 if ((rc
= verify_attr_support(dirp
, firsttime
, ARC_RESTORE
,
2882 &ext_attr
)) != ATTR_OK
) {
2886 /* Open the base file's attribute directory */
2887 if ((attrinfo
->attr_parentfd
= attropen(dirp
, ".", O_RDONLY
)) == -1) {
2889 * Save the errno from the attropen so it can be reported
2890 * if the retry of the attropen fails.
2893 if ((attrinfo
->attr_parentfd
= retry_open_attr(-1, cwd
, dirp
,
2894 NULL
, ".", O_RDONLY
, 0)) == -1) {
2896 * Reset typeflag back to real value so passtape
2897 * will skip ahead correctly.
2899 dblock
.dbuf
.typeflag
= _XATTR_HDRTYPE
;
2900 (void) close(attrinfo
->attr_parentfd
);
2901 attrinfo
->attr_parentfd
= -1;
2903 return (ATTR_OPEN_ERR
);
2908 * Change into the parent attribute's directory unless we are
2909 * processing the hidden attribute directory of the base file itself.
2911 if ((Hiddendir
== 0) || (firsttime
&& attrinfo
->attr_parent
!= NULL
)) {
2912 if (fchdir(attrinfo
->attr_parentfd
) != 0) {
2914 (void) close(attrinfo
->attr_parentfd
);
2915 attrinfo
->attr_parentfd
= -1;
2917 return (ATTR_CHDIR_ERR
);
2921 /* Determine if the attribute should be processed */
2922 if ((rc
= verify_attr(attrname
, attrinfo
->attr_parent
, 1,
2923 &attrinfo
->attr_rw_sysattr
)) != ATTR_OK
) {
2925 (void) close(attrinfo
->attr_parentfd
);
2926 attrinfo
->attr_parentfd
= -1;
2932 * If the attribute is an extended attribute, or extended system
2933 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2934 * recursively call open_attr_dir() to open the attribute directory
2935 * of the parent attribute.
2937 if (firsttime
&& (attrinfo
->attr_parent
!= NULL
)) {
2938 return (open_attr_dir(attrname
, attrinfo
->attr_parent
,
2939 attrinfo
->attr_parentfd
, attrinfo
));
2948 doxtract(char *argv
[], int tbl_cnt
)
2950 doxtract(char *argv
[])
2953 struct stat xtractbuf
; /* stat on file after extracting */
2957 int newfile
; /* Does the file already exist */
2958 int xcnt
= 0; /* count # files extracted */
2959 int fcnt
= 0; /* count # files in argv list */
2966 char *namep
, *dirp
, *comp
, *linkp
; /* for removing absolute paths */
2967 char dirname
[PATH_MAX
+1];
2968 char templink
[PATH_MAX
+1]; /* temp link with terminating NULL */
2973 attr_data_t
*attrinfo
= NULL
; /* attribute info */
2974 acl_t
*aclp
= NULL
; /* acl info */
2975 char dot
[] = "."; /* dirp for using realpath */
2976 timestruc_t time_zero
; /* used for call to doDirTimes */
2979 time_zero
.tv_sec
= 0;
2980 time_zero
.tv_nsec
= 0;
2982 /* reset Trusted Extensions variables */
2987 bslundef(&bs_label
);
2989 bslhigh(&admin_high
);
2992 dumping
= 0; /* for newvol(), et al: we are not writing */
2995 * Count the number of files that are to be extracted
3000 initarg(argv
, Filefile
);
3001 while (nextarg() != NULL
)
3015 (void) close(dirfd
);
3019 if (close(ofile
) != 0)
3020 vperror(2, gettext("close error"));
3023 #if defined(O_XATTR)
3029 /* namep is set by wantit to point to the full name */
3030 if ((want
= wantit(argv
, &namep
, &dirp
, &comp
,
3032 #if defined(O_XATTR)
3033 if (xattrp
!= NULL
) {
3045 /* Trusted Extensions */
3047 * During tar extract (x):
3048 * If the pathname of the restored file has been
3049 * reconstructed from the ancillary file,
3050 * use it to process the normal file.
3052 if (mld_flag
) { /* Skip over .MLD. directory */
3057 orig_namep
= namep
; /* save original */
3059 namep
= real_path
; /* use zone path */
3060 comp
= real_path
; /* use zone path */
3061 dirp
= dot
; /* work from the top */
3062 rpath_flag
= 0; /* reset */
3066 (void) close(dirfd
);
3068 (void) strcpy(&dirname
[0], namep
);
3069 dircreate
= checkdir(&dirname
[0]);
3071 #if defined(O_XATTR)
3072 if (xattrp
!= NULL
) {
3075 if (((cwd
= save_cwd()) == -1) ||
3076 ((rc
= open_attr_dir(comp
, dirp
, cwd
,
3077 attrinfo
)) != ATTR_OK
)) {
3080 "unable to save current working "
3081 "directory while processing "
3082 "attribute %s of %s"),
3083 dirp
, attrinfo
->attr_path
);
3084 } else if (rc
!= ATTR_SKIP
) {
3085 (void) fprintf(vfile
,
3086 gettext("tar: cannot open "
3087 "%sattribute %s of file %s: %s\n"),
3088 attrinfo
->attr_rw_sysattr
? gettext(
3090 comp
, dirp
, strerror(errno
));
3100 dirfd
= attrinfo
->attr_parentfd
;
3101 rw_sysattr
= attrinfo
->attr_rw_sysattr
;
3104 dirfd
= open(dirp
, O_RDONLY
);
3107 dirfd
= open(dirp
, O_RDONLY
);
3110 (void) fprintf(vfile
, gettext(
3111 "tar: cannot open %s: %s\n"),
3112 dirp
, strerror(errno
));
3117 if (xhdr_flgs
& _X_LINKPATH
)
3118 (void) strcpy(templink
, Xtarhdr
.x_linkpath
);
3120 #if defined(O_XATTR)
3121 if (xattrp
&& dblock
.dbuf
.typeflag
== '1') {
3122 (void) sprintf(templink
, "%.*s", NAMSIZ
,
3125 (void) sprintf(templink
, "%.*s", NAMSIZ
,
3126 dblock
.dbuf
.linkname
);
3129 (void) sprintf(templink
, "%.*s", NAMSIZ
,
3130 dblock
.dbuf
.linkname
);
3137 if ((s
= strrchr(namep
, '/')) == 0)
3142 if (checkf(s
, stbuf
.st_mode
, Fflag
) == 0) {
3148 if (checkw('x', namep
) == 0) {
3153 if (strcmp(dblock
.dbuf
.magic
, magic_type
) == 0) {
3154 if (geteuid() == (uid_t
)0) {
3158 /* get file creation mask */
3160 (void) umask(Oumask
);
3164 if (geteuid() == (uid_t
)0) {
3169 /* get file creation mask */
3171 (void) umask(Oumask
);
3177 #if defined(O_XATTR)
3179 * Handle extraction of hidden attr dir.
3180 * Dir is automatically created, we only
3181 * need to update mode and perm's.
3183 if ((xattrp
!= NULL
) && Hiddendir
== 1) {
3184 bytes
= stbuf
.st_size
;
3185 blocks
= TBLOCKS(bytes
);
3187 (void) fprintf(vfile
,
3188 "x %s%s%s, %" FMT_off_t
" bytes, ", namep
,
3189 gettext(" attribute "),
3192 (void) fprintf(vfile
,
3193 "%" FMT_blkcnt_t
"K\n", K(blocks
));
3195 (void) fprintf(vfile
, gettext("%"
3196 FMT_blkcnt_t
" tape blocks\n"),
3201 * Set the permissions and mode of the attribute
3202 * unless the attribute is a system attribute (can't
3203 * successfully do this) or the hidden attribute
3204 * directory (".") of an attribute (when the attribute
3205 * is restored, the hidden attribute directory of an
3206 * attribute is transient). Note: when the permissions
3207 * and mode are set for the hidden attribute directory
3208 * of a file on a system supporting extended system
3209 * attributes, even though it returns successfully, it
3210 * will not have any affect since the attribute
3211 * directory is transient.
3213 if (attrinfo
->attr_parent
== NULL
) {
3214 if (fchownat(dirfd
, ".", stbuf
.st_uid
,
3215 stbuf
.st_gid
, 0) != 0) {
3217 "%s%s%s: failed to set ownership "
3218 "of attribute directory"), namep
,
3219 gettext(" attribute "), xattrapath
);
3222 if (fchmod(dirfd
, stbuf
.st_mode
) != 0) {
3224 "%s%s%s: failed to set permissions "
3225 "of attribute directory"), namep
,
3226 gettext(" attribute "), xattrapath
);
3233 if (dircreate
&& (!is_posix
|| dblock
.dbuf
.typeflag
== '5')) {
3236 (void) fprintf(vfile
, "x %s, 0 bytes, ",
3239 (void) fprintf(vfile
, "0K\n");
3241 (void) fprintf(vfile
, gettext("%"
3242 FMT_blkcnt_t
" tape blocks\n"),
3248 if (dblock
.dbuf
.typeflag
== '6') { /* FIFO */
3249 if (rmdir(namep
) < 0) {
3250 if (errno
== ENOTDIR
)
3251 (void) unlink(namep
);
3254 if (*linkp
!= NULL
) {
3255 if (Aflag
&& *linkp
== '/')
3257 if (link(linkp
, namep
) < 0) {
3258 (void) fprintf(stderr
, gettext(
3259 "tar: %s: cannot link\n"), namep
);
3263 (void) fprintf(vfile
, gettext(
3264 "x %s linked to %s\n"), namep
,
3266 xcnt
++; /* increment # files extracted */
3269 if (mknod(namep
, (int)(Gen
.g_mode
|S_IFIFO
),
3270 (int)Gen
.g_devmajor
) < 0) {
3271 vperror(0, gettext("%s: mknod failed"), namep
);
3274 bytes
= stbuf
.st_size
;
3275 blocks
= TBLOCKS(bytes
);
3277 (void) fprintf(vfile
, "x %s, %" FMT_off_t
3278 " bytes, ", namep
, bytes
);
3280 (void) fprintf(vfile
, "%" FMT_blkcnt_t
3283 (void) fprintf(vfile
, gettext("%"
3284 FMT_blkcnt_t
" tape blocks\n"),
3289 if (dblock
.dbuf
.typeflag
== '3' && !Uid
) { /* CHAR SPECIAL */
3290 if (rmdir(namep
) < 0) {
3291 if (errno
== ENOTDIR
)
3292 (void) unlink(namep
);
3295 if (*linkp
!= NULL
) {
3296 if (Aflag
&& *linkp
== '/')
3298 if (link(linkp
, namep
) < 0) {
3299 (void) fprintf(stderr
, gettext(
3300 "tar: %s: cannot link\n"), namep
);
3304 (void) fprintf(vfile
, gettext(
3305 "x %s linked to %s\n"), namep
,
3307 xcnt
++; /* increment # files extracted */
3310 if (mknod(namep
, (int)(Gen
.g_mode
|S_IFCHR
),
3311 (int)makedev(Gen
.g_devmajor
, Gen
.g_devminor
)) < 0) {
3313 "%s: mknod failed"), namep
);
3316 bytes
= stbuf
.st_size
;
3317 blocks
= TBLOCKS(bytes
);
3319 (void) fprintf(vfile
, "x %s, %" FMT_off_t
3320 " bytes, ", namep
, bytes
);
3322 (void) fprintf(vfile
, "%" FMT_blkcnt_t
3325 (void) fprintf(vfile
, gettext("%"
3326 FMT_blkcnt_t
" tape blocks\n"),
3330 } else if (dblock
.dbuf
.typeflag
== '3' && Uid
) {
3331 (void) fprintf(stderr
, gettext(
3332 "Can't create special %s\n"), namep
);
3338 if (dblock
.dbuf
.typeflag
== '4' && !Uid
) {
3339 if (rmdir(namep
) < 0) {
3340 if (errno
== ENOTDIR
)
3341 (void) unlink(namep
);
3344 if (*linkp
!= NULL
) {
3345 if (Aflag
&& *linkp
== '/')
3347 if (link(linkp
, namep
) < 0) {
3348 (void) fprintf(stderr
, gettext(
3349 "tar: %s: cannot link\n"), namep
);
3353 (void) fprintf(vfile
, gettext(
3354 "x %s linked to %s\n"), namep
,
3356 xcnt
++; /* increment # files extracted */
3359 if (mknod(namep
, (int)(Gen
.g_mode
|S_IFBLK
),
3360 (int)makedev(Gen
.g_devmajor
, Gen
.g_devminor
)) < 0) {
3361 vperror(0, gettext("%s: mknod failed"), namep
);
3364 bytes
= stbuf
.st_size
;
3365 blocks
= TBLOCKS(bytes
);
3367 (void) fprintf(vfile
, gettext("x %s, %"
3368 FMT_off_t
" bytes, "), namep
, bytes
);
3370 (void) fprintf(vfile
, "%" FMT_blkcnt_t
3373 (void) fprintf(vfile
, gettext("%"
3374 FMT_blkcnt_t
" tape blocks\n"),
3378 } else if (dblock
.dbuf
.typeflag
== '4' && Uid
) {
3379 (void) fprintf(stderr
,
3380 gettext("Can't create special %s\n"), namep
);
3383 if (dblock
.dbuf
.typeflag
== '2') { /* symlink */
3384 if ((Tflag
) && (lk_rpath_flag
== 1))
3385 linkp
= lk_real_path
;
3388 if (Aflag
&& *linkp
== '/')
3390 if (rmdir(namep
) < 0) {
3391 if (errno
== ENOTDIR
)
3392 (void) unlink(namep
);
3394 if (symlink(linkp
, namep
) < 0) {
3395 vperror(0, gettext("%s: symbolic link failed"),
3400 (void) fprintf(vfile
, gettext(
3401 "x %s symbolic link to %s\n"),
3404 symflag
= AT_SYMLINK_NOFOLLOW
;
3407 if (dblock
.dbuf
.typeflag
== '1') {
3409 if (Aflag
&& *linkp
== '/')
3411 if (unlinkat(dirfd
, comp
, AT_REMOVEDIR
) < 0) {
3412 if (errno
== ENOTDIR
)
3413 (void) unlinkat(dirfd
, comp
, 0);
3415 #if defined(O_XATTR)
3416 if (xattrp
&& xattr_linkp
) {
3417 if (fchdir(dirfd
) < 0) {
3419 "Cannot fchdir to attribute "
3421 (attrinfo
->attr_parent
== NULL
) ?
3422 dirp
: attrinfo
->attr_parent
);
3426 error
= link(xattr_linkaname
, xattrapath
);
3428 error
= link(linkp
, namep
);
3431 error
= link(linkp
, namep
);
3435 (void) fprintf(stderr
, gettext(
3436 "tar: %s%s%s: cannot link\n"),
3437 namep
, (xattr_linkp
!= NULL
) ?
3438 gettext(" attribute ") : "",
3439 (xattr_linkp
!= NULL
) ?
3444 (void) fprintf(vfile
, gettext(
3445 "x %s%s%s linked to %s%s%s\n"), namep
,
3446 (xattr_linkp
!= NULL
) ?
3447 gettext(" attribute ") : "",
3448 (xattr_linkp
!= NULL
) ?
3449 xattr_linkaname
: "",
3451 (xattr_linkp
!= NULL
) ?
3452 gettext(" attribute ") : "",
3453 (xattr_linkp
!= NULL
) ? xattrapath
: "");
3454 xcnt
++; /* increment # files extracted */
3455 #if defined(O_XATTR)
3456 if (xattrp
!= NULL
) {
3468 if (convtoreg(stbuf
.st_size
)) {
3471 (void) fprintf(stderr
, gettext(
3472 "tar: %s: typeflag '%c' not recognized\n"),
3473 namep
, dblock
.dbuf
.typeflag
);
3476 (void) fprintf(stderr
, gettext(
3477 "tar: %s: typeflag '%c' not recognized, "
3478 "converting to regular file\n"), namep
,
3479 dblock
.dbuf
.typeflag
);
3483 if (dblock
.dbuf
.typeflag
== '0' ||
3484 dblock
.dbuf
.typeflag
== NULL
|| convflag
) {
3485 delete_target(dirfd
, comp
, namep
);
3487 if (*linkp
!= NULL
) {
3488 if (Aflag
&& *linkp
== '/')
3490 if (link(linkp
, comp
) < 0) {
3491 (void) fprintf(stderr
, gettext(
3492 "tar: %s: cannot link\n"), namep
);
3496 (void) fprintf(vfile
, gettext(
3497 "x %s linked to %s\n"), comp
,
3499 xcnt
++; /* increment # files extracted */
3500 #if defined(O_XATTR)
3501 if (xattrp
!= NULL
) {
3510 newfile
= ((fstatat(dirfd
, comp
,
3511 &xtractbuf
, 0) == -1) ? TRUE
: FALSE
);
3512 ofile
= openat(dirfd
, comp
, O_RDWR
|O_CREAT
|O_TRUNC
,
3513 stbuf
.st_mode
& MODEMASK
);
3516 #if defined(O_XATTR)
3517 if (xattrp
!= NULL
) {
3519 ofile
= retry_open_attr(dirfd
, cwd
,
3520 dirp
, attrinfo
->attr_parent
, comp
,
3521 O_RDWR
|O_CREAT
|O_TRUNC
,
3522 stbuf
.st_mode
& MODEMASK
);
3528 (void) fprintf(stderr
, gettext(
3529 "tar: %s%s%s%s - cannot create\n"),
3530 (xattrp
== NULL
) ? "" : (rw_sysattr
?
3531 gettext("system attribure ") :
3532 gettext("attribute ")),
3533 (xattrp
== NULL
) ? "" : xattrapath
,
3534 (xattrp
== NULL
) ? "" : gettext(" of "),
3535 (xattrp
== NULL
) ? comp
: namep
);
3540 #if defined(O_XATTR)
3541 if (xattrp
!= NULL
) {
3542 dblock
.dbuf
.typeflag
= _XATTR_HDRTYPE
;
3553 if (Tflag
&& (check_ext_attr(namep
) == 0)) {
3562 if (extno
!= 0) { /* file is in pieces */
3563 if (extotal
< 1 || extotal
> MAXEXT
)
3564 (void) fprintf(stderr
, gettext(
3565 "tar: ignoring bad extent info for "
3567 (xattrp
== NULL
) ? "" : (rw_sysattr
?
3568 gettext("system attribute ") :
3569 gettext("attribute ")),
3570 (xattrp
== NULL
) ? "" : xattrapath
,
3571 (xattrp
== NULL
) ? "" : gettext(" of "),
3572 (xattrp
== NULL
) ? comp
: namep
);
3575 (void) xsfile(rw_sysattr
, ofile
);
3578 extno
= 0; /* let everyone know file is not split */
3579 bytes
= stbuf
.st_size
;
3580 blocks
= TBLOCKS(bytes
);
3582 (void) fprintf(vfile
,
3583 "x %s%s%s, %" FMT_off_t
" bytes, ",
3584 (xattrp
== NULL
) ? "" : dirp
,
3585 (xattrp
== NULL
) ? "" : (rw_sysattr
?
3586 gettext(" system attribute ") :
3587 gettext(" attribute ")),
3588 (xattrp
== NULL
) ? namep
: xattrapath
, bytes
);
3590 (void) fprintf(vfile
, "%" FMT_blkcnt_t
"K\n",
3593 (void) fprintf(vfile
, gettext("%"
3594 FMT_blkcnt_t
" tape blocks\n"), blocks
);
3597 if (xblocks(rw_sysattr
, bytes
, ofile
) != 0) {
3598 #if defined(O_XATTR)
3599 if (xattrp
!= NULL
) {
3609 if (mflag
== 0 && !symflag
) {
3611 doDirTimes(namep
, stbuf
.st_mtim
);
3614 #if defined(O_XATTR)
3615 if (xattrp
!= NULL
) {
3617 * Set the time on the attribute unless
3618 * the attribute is a system attribute
3619 * (can't successfully do this) or the
3620 * hidden attribute directory, "." (the
3621 * time on the hidden attribute
3622 * directory will be updated when
3623 * attributes are restored, otherwise
3626 if (!rw_sysattr
&& (Hiddendir
== 0)) {
3627 setPathTimes(dirfd
, comp
,
3631 setPathTimes(dirfd
, comp
,
3634 setPathTimes(dirfd
, comp
, stbuf
.st_mtim
);
3638 /* moved this code from above */
3639 if (pflag
&& !symflag
&& Hiddendir
== 0) {
3641 (void) fchmod(ofile
, stbuf
.st_mode
& MODEMASK
);
3643 (void) chmod(namep
, stbuf
.st_mode
& MODEMASK
);
3648 * Because ancillary file preceeds the normal file,
3649 * acl info may have been retrieved (in aclp).
3650 * All file types are directed here (go filedone).
3651 * Always restore ACLs if there are ACLs.
3656 #if defined(O_XATTR)
3657 if (xattrp
!= NULL
) {
3659 ret
= facl_set(dirfd
, aclp
);
3661 ret
= facl_set(ofile
, aclp
);
3663 ret
= acl_set(namep
, aclp
);
3666 ret
= acl_set(namep
, aclp
);
3670 (void) fprintf(stderr
, gettext(
3671 "%s%s%s%s: failed to set acl "
3672 "entries\n"), namep
,
3673 (xattrp
== NULL
) ? "" :
3674 (rw_sysattr
? gettext(
3675 " system attribute ") :
3676 gettext(" attribute ")),
3677 (xattrp
== NULL
) ? "" :
3680 /* else: silent and continue */
3687 resugname(dirfd
, comp
, symflag
); /* set file ownership */
3689 if (pflag
&& newfile
== TRUE
&& !dir
&&
3690 (dblock
.dbuf
.typeflag
== '0' ||
3691 dblock
.dbuf
.typeflag
== NULL
||
3692 convflag
|| dblock
.dbuf
.typeflag
== '1')) {
3693 if (fstat(ofile
, &xtractbuf
) == -1)
3694 (void) fprintf(stderr
, gettext(
3695 "tar: cannot stat extracted file "
3697 (xattrp
== NULL
) ? "" : (rw_sysattr
?
3698 gettext("system attribute ") :
3699 gettext("attribute ")),
3700 (xattrp
== NULL
) ? "" : xattrapath
,
3701 (xattrp
== NULL
) ? "" :
3702 gettext(" of "), namep
);
3704 else if ((xtractbuf
.st_mode
& (MODEMASK
& ~S_IFMT
))
3705 != (stbuf
.st_mode
& (MODEMASK
& ~S_IFMT
))) {
3706 (void) fprintf(stderr
, gettext(
3707 "tar: warning - file permissions have "
3708 "changed for %s%s%s%s (are 0%o, should be "
3710 (xattrp
== NULL
) ? "" : (rw_sysattr
?
3711 gettext("system attribute ") :
3712 gettext("attribute ")),
3713 (xattrp
== NULL
) ? "" : xattrapath
,
3714 (xattrp
== NULL
) ? "" :
3715 gettext(" of "), namep
,
3716 xtractbuf
.st_mode
, stbuf
.st_mode
);
3720 #if defined(O_XATTR)
3721 if (xattrp
!= NULL
) {
3730 (void) close(dirfd
);
3732 if (close(ofile
) != 0)
3733 vperror(2, gettext("close error"));
3736 xcnt
++; /* increment # files extracted */
3740 * Process ancillary file.
3744 if (dblock
.dbuf
.typeflag
== 'A') { /* acl info */
3751 /* reset Trusted Extensions flags */
3758 bytes
= stbuf
.st_size
;
3759 if ((secp
= malloc((int)bytes
)) == NULL
) {
3760 (void) fprintf(stderr
, gettext(
3761 "Insufficient memory for acl\n"));
3766 blocks
= TBLOCKS(bytes
);
3769 * Display a line for each ancillary file.
3772 (void) fprintf(vfile
, "x %s(A), %"
3773 FMT_blkcnt_t
" bytes, %"
3774 FMT_blkcnt_t
" tape blocks\n",
3775 namep
, bytes
, blocks
);
3777 while (blocks
-- > 0) {
3779 if (bytes
<= TBLOCK
) {
3780 (void) memcpy(tp
, buf
,
3784 (void) memcpy(tp
, buf
,
3790 bytes
= stbuf
.st_size
;
3791 /* got all attributes in secp */
3794 attr
= (struct sec_attr
*)tp
;
3795 switch (attr
->attr_type
) {
3798 (void) sscanf(attr
->attr_len
,
3803 attrsize
= 8 + (int)strlen(
3804 &attr
->attr_info
[0]) + 1;
3807 &attr
->attr_info
[0], &aclp
);
3810 (void) fprintf(stderr
,
3819 if (acl_cnt(aclp
) != cnt
) {
3820 (void) fprintf(stderr
,
3829 /* Trusted Extensions */
3837 case ATTR_FLAG_TYPE
:
3839 sizeof (struct sec_attr
) +
3840 strlen(&attr
->attr_info
[0]);
3843 extract_attr(&namep
,
3848 (void) fprintf(stderr
, gettext(
3855 /* next attributes */
3857 } while (bytes
!= 0);
3867 * Ensure that all the directories still on the directory stack
3868 * get their modification times set correctly by flushing the
3872 doDirTimes(NULL
, time_zero
);
3874 #if defined(O_XATTR)
3875 if (xattrp
!= NULL
) {
3884 * Check if the number of files extracted is different from the
3885 * number of files listed on the command line
3888 (void) fprintf(stderr
,
3889 gettext("tar: %d file(s) not extracted\n"),
3896 * xblocks extract file/extent from tape to output file
3898 * xblocks(issysattr, bytes, ofile);
3900 * issysattr flag set if the files being extracted
3901 * is an extended system attribute file.
3902 * unsigned long long bytes size of extent or file to be extracted
3905 * called by doxtract() and xsfile()
3909 xblocks(int issysattr
, off_t bytes
, int ofile
)
3912 char tempname
[NAMSIZ
+1];
3915 size_t piosize
; /* preferred I/O size */
3918 /* Don't need to do anything if this is a zero size file */
3924 * To figure out the size of the buffer used to accumulate data
3925 * from readtape() and to write to the file, we need to determine
3926 * the largest chunk of data to be written to the file at one time.
3927 * This is determined based on the smallest of the following two
3929 * 1) The size of the archived file.
3930 * 2) The preferred I/O size of the file.
3932 if (issysattr
|| (bytes
<= TBLOCK
)) {
3934 * Writes to system attribute files must be
3935 * performed in one operation.
3940 * fstat() the file to get the preferred I/O size.
3941 * If it fails, then resort back to just writing
3942 * one block at a time.
3944 if (fstat(ofile
, &tsbuf
) == 0) {
3945 piosize
= tsbuf
.st_blksize
;
3949 maxwrite
= min(bytes
, piosize
);
3953 * The buffer used to accumulate the data for the write operation
3954 * needs to be the maximum number of bytes to be written rounded up
3955 * to the nearest TBLOCK since readtape reads one block at a time.
3957 if ((buf
= malloc(TBLOCKS(maxwrite
) * TBLOCK
)) == NULL
) {
3958 fatal(gettext("cannot allocate buffer"));
3964 * readtape() obtains one block (TBLOCK) of data at a time.
3965 * Accumulate as many blocks of data in buf as we can write
3968 for (bytesread
= 0; bytesread
< maxwrite
; bytesread
+= TBLOCK
) {
3969 readtape(buf
+ bytesread
);
3972 if (write(ofile
, buf
, maxwrite
) < 0) {
3973 int saveerrno
= errno
;
3975 if (xhdr_flgs
& _X_PATH
)
3976 (void) strlcpy(tempname
, Xtarhdr
.x_path
,
3979 (void) sprintf(tempname
, "%.*s", NAMSIZ
,
3982 * If the extended system attribute being extracted
3983 * contains attributes that the user needs privileges
3984 * for, then just display a warning message, skip
3985 * the extraction of this file, and return.
3987 if ((saveerrno
== EPERM
) && issysattr
) {
3988 (void) fprintf(stderr
, gettext(
3989 "tar: unable to extract system attribute "
3990 "%s: insufficient privileges\n"), tempname
);
3995 (void) fprintf(stderr
, gettext(
3996 "tar: %s: HELP - extract write error\n"),
4004 * If we've reached this point and there is still data
4005 * to be written, maxwrite had to have been determined
4006 * by the preferred I/O size. If the number of bytes
4007 * left to write is smaller than the preferred I/O size,
4008 * then we're about to do our final write to the file, so
4009 * just set maxwrite to the number of bytes left to write.
4011 if ((bytes
> 0) && (bytes
< maxwrite
)) {
4021 * xsfile extract split file
4023 * xsfile(ofd); ofd = output file descriptor
4025 * file extracted and put in ofd via xblocks()
4027 * NOTE: only called by doxtract() to extract one large file
4030 static union hblock savedblock
; /* to ensure same file across volumes */
4033 xsfile(int issysattr
, int ofd
)
4037 char name
[PATH_MAX
+1]; /* holds name for diagnostics */
4038 int extents
, totalext
;
4039 off_t bytes
, totalbytes
;
4041 if (xhdr_flgs
& _X_PATH
)
4042 (void) strcpy(name
, Xtarhdr
.x_path
);
4044 (void) sprintf(name
, "%.*s", NAMSIZ
, dblock
.dbuf
.name
);
4046 totalbytes
= (off_t
)0; /* in case we read in half the file */
4047 totalext
= 0; /* these keep count */
4049 (void) fprintf(stderr
, gettext(
4050 "tar: %s split across %d volumes\n"), name
, extotal
);
4052 /* make sure we do extractions in order */
4053 if (extno
!= 1) { /* starting in middle of file? */
4054 (void) printf(gettext(
4055 "tar: first extent read is not #1\n"
4056 "OK to read file beginning with extent #%d (%s/%s) ? "),
4057 extno
, yesstr
, nostr
);
4061 if (close(ofd
) != 0)
4062 vperror(2, gettext("close error"));
4074 if (xhdr_flgs
& _X_SIZE
) {
4077 bytes
= stbuf
.st_size
;
4081 (void) fprintf(vfile
, "+++ x %s [extent #%d], %"
4082 FMT_off_t
" bytes, %ldK\n", name
, extno
, bytes
,
4083 (long)K(TBLOCKS(bytes
)));
4084 if (xblocks(issysattr
, bytes
, ofd
) != 0) {
4089 totalbytes
+= bytes
;
4094 /* get next volume and verify it's the right one */
4095 copy(&savedblock
, &dblock
);
4101 (void) get_xdata(); /* Get x-header & regular hdr */
4102 if ((dblock
.dbuf
.typeflag
!= 'A') && (xhdr_flgs
!= 0)) {
4103 load_info_from_xtarhdr(xhdr_flgs
, &Xtarhdr
);
4104 xhdr_flgs
|= _X_XHDR
;
4106 if (endtape()) { /* seemingly empty volume */
4107 (void) fprintf(stderr
, gettext(
4108 "tar: first record is null\n"));
4110 (void) fprintf(stderr
, gettext(
4111 "tar: need volume with extent #%d of %s\n"),
4116 (void) fprintf(stderr
, gettext(
4117 "tar: first file on that volume is not "
4118 "the same file\n"));
4122 (void) fprintf(stderr
, gettext(
4123 "tar: extent #%d received out of order\ntar: "
4124 "should be #%d\n"), extno
, i
);
4125 (void) fprintf(stderr
, gettext(
4126 "Ignore error, Abort this file, or "
4127 "load New volume (i/a/n) ? "));
4131 if (c
!= 'i') /* default to new volume */
4133 i
= extno
; /* okay, start from there */
4137 (void) fprintf(vfile
, gettext(
4138 "x %s (in %d extents), %" FMT_off_t
" bytes, %ldK\n"),
4139 name
, totalext
, totalbytes
, (long)K(TBLOCKS(totalbytes
)));
4146 * notsame() check if extract file extent is invalid
4148 * returns true if anything differs between savedblock and dblock
4149 * except extno (extent number), checksum, or size (extent size).
4150 * Determines if this header belongs to the same file as the one we're
4153 * NOTE: though rather bulky, it is only called once per file
4154 * extension, and it can withstand changes in the definition
4155 * of the header structure.
4157 * WARNING: this routine is local to xsfile() above
4164 (strncmp(savedblock
.dbuf
.name
, dblock
.dbuf
.name
, NAMSIZ
)) ||
4165 (strcmp(savedblock
.dbuf
.mode
, dblock
.dbuf
.mode
)) ||
4166 (strcmp(savedblock
.dbuf
.uid
, dblock
.dbuf
.uid
)) ||
4167 (strcmp(savedblock
.dbuf
.gid
, dblock
.dbuf
.gid
)) ||
4168 (strcmp(savedblock
.dbuf
.mtime
, dblock
.dbuf
.mtime
)) ||
4169 (savedblock
.dbuf
.typeflag
!= dblock
.dbuf
.typeflag
) ||
4170 (strncmp(savedblock
.dbuf
.linkname
, dblock
.dbuf
.linkname
, NAMSIZ
)) ||
4171 (savedblock
.dbuf
.extotal
!= dblock
.dbuf
.extotal
) ||
4172 (strcmp(savedblock
.dbuf
.efsize
, dblock
.dbuf
.efsize
)));
4177 dotable(char *argv
[], int tbl_cnt
)
4179 dotable(char *argv
[])
4183 int tcnt
; /* count # files tabled */
4184 int fcnt
; /* count # files in argv list */
4185 char *namep
, *dirp
, *comp
;
4187 char aclchar
= ' '; /* either blank or '+' */
4188 char templink
[PATH_MAX
+1];
4189 attr_data_t
*attrinfo
= NULL
;
4193 /* if not on magtape, maximize seek speed */
4194 if (NotTape
&& !bflag
) {
4195 #if SYS_BLOCK > TBLOCK
4196 nblock
= SYS_BLOCK
/ TBLOCK
;
4202 * Count the number of files that are to be tabled
4207 initarg(argv
, Filefile
);
4208 while (nextarg() != NULL
)
4215 /* namep is set by wantit to point to the full name */
4216 if ((want
= wantit(argv
, &namep
, &dirp
, &comp
, &attrinfo
)) == 0)
4220 if (dblock
.dbuf
.typeflag
!= 'A')
4225 * aclchar is introduced to indicate if there are
4226 * acl entries. longt() now takes one extra argument.
4229 if (dblock
.dbuf
.typeflag
== 'A') {
4234 longt(&stbuf
, aclchar
);
4239 #if defined(O_XATTR)
4240 if (xattrp
!= NULL
) {
4242 char *bn
= basename(attrinfo
->attr_path
);
4245 * We could use sysattr_type() to test whether or not
4246 * the attribute we are processing is really an
4247 * extended system attribute, which as of this writing
4248 * just does a strcmp(), however, sysattr_type() may
4249 * be changed to issue a pathconf() call instead, which
4250 * would require being changed into the parent attribute
4251 * directory. So instead, just do simple string
4252 * comparisons to see if we are processing an extended
4255 issysattr
= is_sysattr(bn
);
4257 (void) printf(gettext("%s %sattribute %s"),
4259 issysattr
? gettext("system ") : "",
4260 attrinfo
->attr_path
);
4262 (void) printf("%s", namep
);
4265 (void) printf("%s", namep
);
4270 /* keep the '\n' for backwards compatibility */
4271 (void) fprintf(vfile
, gettext(
4272 "\n [extent #%d of %d]"), extno
, extotal
);
4274 (void) fprintf(vfile
, gettext(
4275 " [extent #%d of %d]"), extno
, extotal
);
4278 if (xhdr_flgs
& _X_LINKPATH
) {
4279 (void) strcpy(templink
, Xtarhdr
.x_linkpath
);
4281 #if defined(O_XATTR)
4282 if (xattrp
!= NULL
) {
4283 (void) sprintf(templink
,
4284 "file %.*s", NAMSIZ
, xattrp
->h_names
);
4286 (void) sprintf(templink
, "%.*s", NAMSIZ
,
4287 dblock
.dbuf
.linkname
);
4290 (void) sprintf(templink
, "%.*s", NAMSIZ
,
4291 dblock
.dbuf
.linkname
);
4293 templink
[NAMSIZ
] = '\0';
4295 if (dblock
.dbuf
.typeflag
== '1') {
4298 * Subject is omitted here.
4299 * Translate this as if
4300 * <subject> linked to %s
4302 #if defined(O_XATTR)
4303 if (xattrp
!= NULL
) {
4305 gettext(" linked to attribute %s"),
4306 xattr_linkp
->h_names
+
4307 strlen(xattr_linkp
->h_names
) + 1);
4310 gettext(" linked to %s"), templink
);
4314 gettext(" linked to %s"), templink
);
4318 if (dblock
.dbuf
.typeflag
== '2')
4319 (void) printf(gettext(
4322 * Subject is omitted here.
4323 * Translate this as if
4324 * <subject> symbolic link to %s
4326 " symbolic link to %s"), templink
);
4327 (void) printf("\n");
4328 #if defined(O_XATTR)
4329 if (xattrp
!= NULL
) {
4338 * Check if the number of files tabled is different from the
4339 * number of files listed on the command line
4342 (void) fprintf(stderr
, gettext(
4343 "tar: %d file(s) not found\n"), fcnt
-tcnt
);
4349 putempty(blkcnt_t n
)
4354 for (cp
= buf
; cp
< &buf
[TBLOCK
]; )
4357 (void) writetbuf(buf
, 1);
4360 static ushort_t Ftype
= S_IFMT
;
4363 verbose(struct stat
*st
, char aclchar
)
4369 for (i
= 0; i
< 11; i
++)
4373 /* a '+' sign is printed if there is ACL */
4374 modestr
[i
-1] = aclchar
;
4377 for (i
= 0; i
< 3; i
++) {
4378 temp
= (mode
>> (6 - (i
* 3)));
4383 modestr
[j
+ 1] = 'w';
4385 modestr
[j
+ 2] = 'x';
4387 temp
= st
->st_mode
& Ftype
;
4401 case (S_IFREG
): /* was initialized to '-' */
4407 /* This field may be zero in old archives. */
4408 if (is_posix
&& dblock
.dbuf
.typeflag
!= '1') {
4410 * For POSIX compliant archives, the mode field
4411 * consists of 12 bits, ie: the file type bits
4412 * are not stored in dblock.dbuf.mode.
4413 * For files other than hard links, getdir() sets
4414 * the file type bits in the st_mode field of the
4415 * stat structure based upon dblock.dbuf.typeflag.
4417 (void) fprintf(stderr
, gettext(
4418 "tar: impossible file type"));
4422 if ((S_ISUID
& Gen
.g_mode
) == S_ISUID
)
4424 if ((S_ISVTX
& Gen
.g_mode
) == S_ISVTX
)
4426 if ((S_ISGID
& Gen
.g_mode
) == S_ISGID
&& modestr
[6] == 'x')
4428 else if ((S_ENFMT
& Gen
.g_mode
) == S_ENFMT
&& modestr
[6] != 'x')
4430 (void) fprintf(vfile
, "%s", modestr
);
4434 longt(struct stat
*st
, char aclchar
)
4439 verbose(st
, aclchar
);
4440 (void) fprintf(vfile
, "%3ld/%-3ld", st
->st_uid
, st
->st_gid
);
4442 if (dblock
.dbuf
.typeflag
== '2') {
4443 if (xhdr_flgs
& _X_LINKPATH
)
4444 st
->st_size
= (off_t
)strlen(Xtarhdr
.x_linkpath
);
4446 st
->st_size
= (off_t
)(memchr(dblock
.dbuf
.linkname
,
4448 (strlen(dblock
.dbuf
.linkname
)) : (NAMSIZ
));
4450 (void) fprintf(vfile
, " %6" FMT_off_t
, st
->st_size
);
4452 tm
= localtime(&(st
->st_mtime
));
4453 (void) strftime(fileDate
, sizeof (fileDate
),
4454 dcgettext((const char *)0, "%b %e %R %Y", LC_TIME
), tm
);
4455 (void) fprintf(vfile
, " %s ", fileDate
);
4460 * checkdir - Attempt to ensure that the path represented in name
4461 * exists, and return 1 if this is true and name itself is a
4463 * Return 0 if this path cannot be created or if name is not
4468 checkdir(char *name
)
4470 char lastChar
; /* the last character in name */
4471 char *cp
; /* scratch pointer into name */
4472 char *firstSlash
= NULL
; /* first slash in name */
4473 char *lastSlash
= NULL
; /* last slash in name */
4474 int nameLen
; /* length of name */
4475 int trailingSlash
; /* true if name ends in slash */
4476 int leadingSlash
; /* true if name begins with slash */
4477 int markedDir
; /* true if name denotes a directory */
4478 int success
; /* status of makeDir call */
4482 * Scan through the name, and locate first and last slashes.
4485 for (cp
= name
; *cp
; cp
++) {
4495 * Determine what you can from the proceeds of the scan.
4498 lastChar
= *(cp
- 1);
4499 nameLen
= (int)(cp
- name
);
4500 trailingSlash
= (lastChar
== '/');
4501 leadingSlash
= (*name
== '/');
4502 markedDir
= (dblock
.dbuf
.typeflag
== '5' || trailingSlash
);
4504 if (! lastSlash
&& ! markedDir
) {
4506 * The named file does not have any subdrectory
4507 * structure; just bail out.
4514 * Make sure that name doesn`t end with slash for the loop.
4515 * This ensures that the makeDir attempt after the loop is
4519 if (trailingSlash
) {
4520 name
[nameLen
-1] = '\0';
4524 * Make the path one component at a time.
4527 for (cp
= strchr(leadingSlash
? name
+1 : name
, '/');
4529 cp
= strchr(cp
+1, '/')) {
4531 success
= makeDir(name
);
4535 name
[nameLen
-1] = lastChar
;
4541 * This makes the last component of the name, if it is a
4546 if (! makeDir(name
)) {
4547 name
[nameLen
-1] = lastChar
;
4552 name
[nameLen
-1] = (lastChar
== '/') ? '\0' : lastChar
;
4557 * resugname - Restore the user name and group name. Search the NIS
4558 * before using the uid and gid.
4559 * (It is presumed that an archive entry cannot be
4560 * simultaneously a symlink and some other type.)
4564 resugname(int dirfd
, /* dir fd file resides in */
4565 char *name
, /* name of the file to be modified */
4566 int symflag
) /* true if file is a symbolic link */
4570 struct stat
*sp
= &stbuf
;
4573 if (checkflag
== 1) { /* Extended tar format and euid == 0 */
4576 * Try and extract the intended uid and gid from the name
4577 * service before believing the uid and gid in the header.
4579 * In the case where we archived a setuid or setgid file
4580 * owned by someone with a large uid, then it will
4581 * have made it into the archive with a uid of nobody. If
4582 * the corresponding username doesn't appear to exist, then we
4583 * want to make sure it *doesn't* end up as setuid nobody!
4585 * Our caller will print an error message about the fact
4586 * that the restore didn't work out quite right ..
4588 if (xhdr_flgs
& _X_UNAME
)
4589 u_g_name
= Xtarhdr
.x_uname
;
4591 u_g_name
= dblock
.dbuf
.uname
;
4592 if ((duid
= getuidbyname(u_g_name
)) == -1) {
4593 if (S_ISREG(sp
->st_mode
) && sp
->st_uid
== UID_NOBODY
&&
4594 (sp
->st_mode
& S_ISUID
) == S_ISUID
)
4596 MODEMASK
& sp
->st_mode
& ~S_ISUID
);
4600 /* (Ditto for gids) */
4602 if (xhdr_flgs
& _X_GNAME
)
4603 u_g_name
= Xtarhdr
.x_gname
;
4605 u_g_name
= dblock
.dbuf
.gname
;
4606 if ((dgid
= getgidbyname(u_g_name
)) == -1) {
4607 if (S_ISREG(sp
->st_mode
) && sp
->st_gid
== GID_NOBODY
&&
4608 (sp
->st_mode
& S_ISGID
) == S_ISGID
)
4610 MODEMASK
& sp
->st_mode
& ~S_ISGID
);
4613 } else if (checkflag
== 2) { /* tar format and euid == 0 */
4617 if ((checkflag
== 1) || (checkflag
== 2))
4618 (void) fchownat(dirfd
, name
, duid
, dgid
, symflag
);
4625 (void) signal(SIGINT
, SIG_IGN
);
4633 (void) signal(SIGQUIT
, SIG_IGN
);
4641 (void) signal(SIGHUP
, SIG_IGN
);
4646 tomodes(struct stat
*sp
)
4651 bzero(dblock
.dummy
, TBLOCK
);
4654 * If the uid or gid is too large, we can't put it into
4655 * the archive. We could fail to put anything in the
4656 * archive at all .. but most of the time the name service
4657 * will save the day when we do a lookup at restore time.
4659 * Instead we choose a "safe" uid and gid, and fix up whether
4660 * or not the setuid and setgid bits are left set to extraction
4664 if ((ulong_t
)(uid
= sp
->st_uid
) > (ulong_t
)OCTAL7CHAR
) {
4665 xhdr_flgs
|= _X_UID
;
4666 Xtarhdr
.x_uid
= uid
;
4668 if ((ulong_t
)(gid
= sp
->st_gid
) > (ulong_t
)OCTAL7CHAR
) {
4669 xhdr_flgs
|= _X_GID
;
4670 Xtarhdr
.x_gid
= gid
;
4672 if (sp
->st_size
> TAR_OFFSET_MAX
) {
4673 xhdr_flgs
|= _X_SIZE
;
4674 Xtarhdr
.x_filesz
= sp
->st_size
;
4675 (void) sprintf(dblock
.dbuf
.size
, "%011" FMT_off_t_o
,
4678 (void) sprintf(dblock
.dbuf
.size
, "%011" FMT_off_t_o
,
4681 (void) sprintf(dblock
.dbuf
.size
, "%011" FMT_off_t_o
,
4684 if ((ulong_t
)(uid
= sp
->st_uid
) > (ulong_t
)OCTAL7CHAR
)
4686 if ((ulong_t
)(gid
= sp
->st_gid
) > (ulong_t
)OCTAL7CHAR
)
4688 (void) sprintf(dblock
.dbuf
.gid
, "%07lo", gid
);
4689 (void) sprintf(dblock
.dbuf
.uid
, "%07lo", uid
);
4690 (void) sprintf(dblock
.dbuf
.mode
, "%07lo", sp
->st_mode
& POSIXMODES
);
4691 (void) sprintf(dblock
.dbuf
.mtime
, "%011lo", sp
->st_mtime
);
4697 * Warning: the result of this function depends whether 'char' is a
4698 * signed or unsigned data type. This a source of potential
4699 * non-portability among heterogeneous systems. It is retained here
4700 * for backward compatibility.
4702 checksum_signed(union hblock
*dblockp
)
4704 checksum(union hblock
*dblockp
)
4710 for (cp
= dblockp
->dbuf
.chksum
;
4711 cp
< &dblockp
->dbuf
.chksum
[sizeof (dblockp
->dbuf
.chksum
)]; cp
++)
4714 for (cp
= dblockp
->dummy
; cp
< &(dblockp
->dummy
[TBLOCK
]); cp
++)
4721 * Generate unsigned checksum, regardless of what C compiler is
4722 * used. Survives in the face of arbitrary 8-bit clean filenames,
4723 * e.g., internationalized filenames.
4726 checksum(union hblock
*dblockp
)
4731 for (cp
= (unsigned char *) dblockp
->dbuf
.chksum
;
4732 cp
< (unsigned char *)
4733 &(dblockp
->dbuf
.chksum
[sizeof (dblockp
->dbuf
.chksum
)]); cp
++)
4736 for (cp
= (unsigned char *) dblockp
->dummy
;
4737 cp
< (unsigned char *) &(dblockp
->dummy
[TBLOCK
]); cp
++)
4745 * If the w flag is set, output the action to be taken and the name of the
4746 * file. Perform the action if the user response is affirmative.
4750 checkw(char c
, char *name
)
4753 (void) fprintf(vfile
, "%c ", c
);
4755 longt(&stbuf
, ' '); /* do we have acl info here */
4756 (void) fprintf(vfile
, "%s: ", name
);
4766 * When the F flag is set, exclude RCS and SCCS directories. If F is set
4767 * twice, also exclude .o files, and files names errs, core, and a.out.
4771 checkf(char *name
, int mode
, int howmuch
)
4775 if ((mode
& S_IFMT
) == S_IFDIR
) {
4776 if ((strcmp(name
, "SCCS") == 0) || (strcmp(name
, "RCS") == 0))
4780 if ((l
= (int)strlen(name
)) < 3)
4782 if (howmuch
> 1 && name
[l
-2] == '.' && name
[l
-1] == 'o')
4785 if (strcmp(name
, "core") == 0 || strcmp(name
, "errs") == 0 ||
4786 strcmp(name
, "a.out") == 0)
4790 /* SHOULD CHECK IF IT IS EXECUTABLE */
4801 while (getchar() != '\n')
4804 return ((c
>= 'A' && c
<= 'Z') ? c
+ ('a'-'A') : c
);
4807 /* Has file been modified since being put into archive? If so, return > 0. */
4809 static off_t
lookup(char *);
4812 checkupdate(char *arg
)
4814 char name
[PATH_MAX
+1];
4820 if ((seekp
= lookup(arg
)) < 0)
4822 (void) fseek(tfile
, seekp
, 0);
4823 (void) fscanf(tfile
, "%s %ld.%ld", name
, &mtime
, &nsecs
);
4826 * Unless nanoseconds were stored in the file, only use seconds for
4827 * comparison of time. Nanoseconds are stored when -E is specified.
4830 return (stbuf
.st_mtime
> mtime
);
4832 if ((stbuf
.st_mtime
< mtime
) ||
4833 ((stbuf
.st_mtime
== mtime
) && (stbuf
.st_mtim
.tv_nsec
<= nsecs
)))
4840 * newvol get new floppy (or tape) volume
4842 * newvol(); resets tapepos and first to TRUE, prompts for
4843 * for new volume, and waits.
4844 * if dumping, end-of-file is written onto the tape.
4854 DEBUG("newvol called with 'dumping' set\n", 0, 0);
4856 putempty((blkcnt_t
)2); /* 2 EOT marks */
4864 vperror(2, gettext("close error"));
4866 (void) fprintf(stderr
, gettext(
4867 "tar: \007please insert new volume, then press RETURN."));
4868 (void) fseek(stdin
, (off_t
)0, 2); /* scan over read-ahead */
4869 while ((c
= getchar()) != '\n' && ! term
)
4877 if (strcmp(usefile
, "-") == 0) {
4880 mt
= open(usefile
, dumping
? update
: 0);
4884 (void) fprintf(stderr
, gettext(
4885 "tar: cannot reopen %s (%s)\n"),
4886 dumping
? gettext("output") : gettext("input"), usefile
);
4888 (void) fprintf(stderr
, "update=%d, usefile=%s, mt=%d, [%s]\n",
4889 update
, usefile
, mt
, strerror(errno
));
4896 * Write a trailer portion to close out the current output volume.
4904 * blocklim does not count the 2 EOT marks;
4905 * tapepos does count the 2 EOT marks;
4906 * therefore we need the +2 below.
4908 putempty(blocklim
+ (blkcnt_t
)2 - tapepos
);
4915 (void) unlink(tname
);
4916 if (compress_opt
!= NULL
)
4917 (void) free(compress_opt
);
4919 if ((close(mt
) != 0) || (fclose(stdout
) != 0)) {
4920 perror(gettext("tar: close error"));
4928 * Determine if s1 is a prefix portion of s2 (or the same as s2).
4932 is_prefix(char *s1
, char *s2
)
4938 return (*s2
== '/');
4943 * lookup and bsrch look through tfile entries to find a match for a name.
4944 * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
4945 * a pair of newline chars, so the buffer it uses must be long enough for
4946 * two lines: name and modification time as well as period, newline and space.
4948 * A kludge was added to bsrch to take care of matching on the first entry
4949 * in the file--there is no leading newline. So, if we are reading from the
4950 * start of the file, read into byte two and set the first byte to a newline.
4951 * Otherwise, the first entry cannot be matched.
4955 #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4962 for (i
= 0; s
[i
]; i
++)
4965 a
= bsrch(s
, i
, low
, high
);
4970 bsrch(char *s
, int n
, off_t l
, off_t h
)
4980 m
= l
+ (h
-l
)/2 - N
/2;
4983 (void) fseek(tfile
, m
, 0);
4985 (void) fread(b
+1, 1, N
-1, tfile
);
4989 (void) fread(b
, 1, N
, tfile
);
4990 for (i
= 0; i
< N
; i
++) {
4999 for (i
++; i
< N
; i
++) {
5019 cmp(char *b
, char *s
, int n
)
5023 assert(b
[0] == '\n');
5025 for (i
= 0; i
< n
; i
++) {
5031 return (b
[i
+1] == ' '? 0 : -1);
5036 * seekdisk seek to next file on archive
5038 * called by passtape() only
5040 * WARNING: expects "nblock" to be set, that is, readtape() to have
5041 * already been called. Since passtape() is only called
5042 * after a file header block has been read (why else would
5043 * we skip to next file?), this is currently safe.
5045 * changed to guarantee SYS_BLOCK boundary
5049 seekdisk(blkcnt_t blocks
)
5052 #if SYS_BLOCK > TBLOCK
5053 /* handle non-multiple of SYS_BLOCK */
5054 blkcnt_t nxb
; /* # extra blocks */
5059 DEBUG("seekdisk(%" FMT_blkcnt_t
") called\n", blocks
, 0);
5061 if (recno
+ blocks
<= nblock
) {
5067 seekval
= (off_t
)blocks
- (nblock
- recno
);
5068 recno
= nblock
; /* so readtape() reads next time through */
5069 #if SYS_BLOCK > TBLOCK
5070 nxb
= (blkcnt_t
)(seekval
% (off_t
)(SYS_BLOCK
/ TBLOCK
));
5072 DEBUG("xtrablks=%" FMT_blkcnt_t
" seekval=%" FMT_blkcnt_t
" blks\n",
5075 if (nxb
&& nxb
> seekval
) /* don't seek--we'll read */
5077 seekval
-= nxb
; /* don't seek quite so far */
5079 if (lseek(mt
, (off_t
)(TBLOCK
* seekval
), 1) == (off_t
)-1) {
5080 (void) fprintf(stderr
, gettext(
5081 "tar: device seek error\n"));
5084 #if SYS_BLOCK > TBLOCK
5085 /* read those extra blocks */
5089 DEBUG("reading extra blocks\n", 0, 0);
5091 if (read(mt
, tbuf
, TBLOCK
*nblock
) < 0) {
5092 (void) fprintf(stderr
, gettext(
5093 "tar: read error while skipping file\n"));
5096 recno
= nxb
; /* so we don't read in next readtape() */
5102 readtape(char *buffer
)
5107 if (recno
>= nblock
|| first
) {
5110 * set the number of blocks to read initially, based on
5111 * the defined defaults for the device, or on the
5112 * explicit block factor given.
5114 if (bflag
|| defaults_used
)
5121 if ((i
= read(mt
, tbuf
, TBLOCK
*j
)) < 0) {
5122 (void) fprintf(stderr
, gettext(
5123 "tar: tape read error\n"));
5126 * i == 0 and !rflag means that EOF is reached and we are
5127 * trying to update or replace an empty tar file, so exit
5130 * If i == 0 and !first and NotTape, it means the pointer
5131 * has gone past the EOF. It could happen if two processes
5132 * try to update the same tar file simultaneously. So exit
5136 } else if (i
== 0) {
5137 if (first
&& !rflag
) {
5138 (void) fprintf(stderr
, gettext(
5139 "tar: blocksize = %d\n"), i
);
5141 } else if (!first
&& (!rflag
|| NotTape
)) {
5142 mterr("read", 0, 2);
5144 } else if ((!first
|| Bflag
) && i
!= TBLOCK
*j
) {
5146 * Short read - try to get the remaining bytes.
5149 int remaining
= (TBLOCK
* j
) - i
;
5150 char *b
= (char *)tbuf
+ i
;
5154 if ((r
= read(mt
, b
, remaining
)) < 0) {
5155 (void) fprintf(stderr
,
5156 gettext("tar: tape read error\n"));
5162 } while (remaining
> 0 && r
!= 0);
5165 if ((i
% TBLOCK
) != 0) {
5166 (void) fprintf(stderr
, gettext(
5167 "tar: tape blocksize error\n"));
5171 if (vflag
&& i
!= nblock
&& i
!= 1) {
5173 (void) fprintf(stderr
, gettext(
5174 "tar: blocksize = %d\n"), i
);
5178 * If we are reading a tape, then a short read is
5179 * understood to signify that the amount read is
5180 * the tape's actual blocking factor. We adapt
5181 * nblock accordingly. There is no reason to do
5182 * this when the device is not blocked.
5192 copy(buffer
, &tbuf
[recno
++]);
5197 * replacement for writetape.
5201 writetbuf(char *buffer
, int n
)
5205 tapepos
+= n
; /* output block count */
5207 if (recno
>= nblock
) {
5208 i
= write(mt
, (char *)tbuf
, TBLOCK
*nblock
);
5209 if (i
!= TBLOCK
*nblock
)
5210 mterr("write", i
, 2);
5215 * Special case: We have an empty tape buffer, and the
5216 * users data size is >= the tape block size: Avoid
5217 * the bcopy and dma direct to tape. BIG WIN. Add the
5218 * residual to the tape buffer.
5220 while (recno
== 0 && n
>= nblock
) {
5221 i
= (int)write(mt
, buffer
, TBLOCK
*nblock
);
5222 if (i
!= TBLOCK
*nblock
)
5223 mterr("write", i
, 2);
5225 buffer
+= (nblock
* TBLOCK
);
5229 (void) memcpy((char *)&tbuf
[recno
++], buffer
, TBLOCK
);
5231 if (recno
>= nblock
) {
5232 i
= (int)write(mt
, (char *)tbuf
, TBLOCK
*nblock
);
5233 if (i
!= TBLOCK
*nblock
)
5234 mterr("write", i
, 2);
5239 /* Tell the user how much to write to get in sync */
5240 return (nblock
- recno
);
5244 * backtape - reposition tape after reading soft "EOF" record
5246 * Backtape tries to reposition the tape back over the EOF
5247 * record. This is for the 'u' and 'r' function letters so that the
5248 * tape can be extended. This code is not well designed, but
5249 * I'm confident that the only callers who care about the
5250 * backspace-over-EOF feature are those involved in 'u' and 'r'.
5252 * The proper way to backup the tape is through the use of mtio.
5253 * Earlier spins used lseek combined with reads in a confusing
5254 * maneuver that only worked on 4.x, but shouldn't have, even
5255 * there. Lseeks are explicitly not supported for tape devices.
5263 DEBUG("backtape() called, recno=%" FMT_blkcnt_t
" nblock=%d\n", recno
,
5267 * Backup to the position in the archive where the record
5268 * currently sitting in the tbuf buffer is situated.
5273 * For non-tape devices, this means lseeking to the
5274 * correct position. The absolute location tapepos-recno
5275 * should be the beginning of the current record.
5278 if (lseek(mt
, (off_t
)(TBLOCK
*(tapepos
-recno
)), SEEK_SET
) ==
5280 (void) fprintf(stderr
,
5281 gettext("tar: lseek to end of archive failed\n"));
5286 * For tape devices, we backup over the most recently
5290 mtcmd
.mt_op
= MTBSR
;
5293 if (ioctl(mt
, MTIOCTOP
, &mtcmd
) < 0) {
5294 (void) fprintf(stderr
,
5295 gettext("tar: backspace over record failed\n"));
5301 * Decrement the tape and tbuf buffer indices to prepare for the
5302 * coming write to overwrite the soft EOF record.
5311 * flushtape write buffered block(s) onto tape
5313 * recno points to next free block in tbuf. If nonzero, a write is done.
5314 * Care is taken to write in multiples of SYS_BLOCK when device is
5315 * non-magtape in case raw i/o is used.
5317 * NOTE: this is called by writetape() to do the actual writing
5324 DEBUG("flushtape() called, recno=%" FMT_blkcnt_t
"\n", recno
, 0);
5326 if (recno
> 0) { /* anything buffered? */
5328 #if SYS_BLOCK > TBLOCK
5332 * an odd-block write can only happen when
5333 * we are at the end of a volume that is not a tape.
5334 * Here we round recno up to an even SYS_BLOCK
5337 if ((i
= recno
% (SYS_BLOCK
/ TBLOCK
)) != 0) {
5339 DEBUG("flushtape() %d rounding blocks\n", i
, 0);
5341 recno
+= i
; /* round up to even SYS_BLOCK */
5348 DEBUG("writing out %" FMT_blkcnt_t
" blocks of %" FMT_blkcnt_t
5349 " bytes\n", (blkcnt_t
)(NotTape
? recno
: nblock
),
5350 (blkcnt_t
)(NotTape
? recno
: nblock
) * TBLOCK
);
5353 (size_t)(NotTape
? recno
: nblock
) * TBLOCK
) < 0) {
5354 (void) fprintf(stderr
, gettext(
5355 "tar: tape write error\n"));
5363 copy(void *dst
, void *src
)
5365 (void) memcpy(dst
, src
, TBLOCK
);
5370 * initarg -- initialize things for nextarg.
5372 * argv filename list, a la argv.
5373 * filefile name of file containing filenames. Unless doing
5374 * a create, seeks must be allowable (e.g. no named pipes).
5376 * - if filefile is non-NULL, it will be used first, and argv will
5377 * be used when the data in filefile are exhausted.
5378 * - otherwise argv will be used.
5380 static char **Cmdargv
= NULL
;
5381 static FILE *FILEFile
= NULL
;
5382 static long seekFile
= -1;
5383 static char *ptrtoFile
, *begofFile
, *endofFile
;
5386 initarg(char *argv
[], char *filefile
)
5388 struct stat statbuf
;
5393 if (filefile
== NULL
)
5394 return; /* no -F file */
5395 if (FILEFile
!= NULL
) {
5397 * need to REinitialize
5400 (void) fseek(FILEFile
, seekFile
, 0);
5401 ptrtoFile
= begofFile
;
5405 * first time initialization
5407 if ((FILEFile
= fopen(filefile
, "r")) == NULL
)
5408 fatal(gettext("cannot open (%s)"), filefile
);
5409 (void) fstat(fileno(FILEFile
), &statbuf
);
5410 if ((statbuf
.st_mode
& S_IFMT
) != S_IFREG
) {
5411 (void) fprintf(stderr
, gettext(
5412 "tar: %s is not a regular file\n"), filefile
);
5413 (void) fclose(FILEFile
);
5416 ptrtoFile
= begofFile
= endofFile
;
5419 return; /* the file will be read only once anyway */
5420 nbytes
= statbuf
.st_size
;
5421 while ((begofFile
= calloc(nbytes
, sizeof (char))) == NULL
)
5425 begofFile
= endofFile
;
5426 return; /* no room so just do plain reads */
5428 if (fread(begofFile
, 1, nbytes
, FILEFile
) != nbytes
)
5429 fatal(gettext("could not read %s"), filefile
);
5430 ptrtoFile
= begofFile
;
5431 endofFile
= begofFile
+ nbytes
;
5432 for (p
= begofFile
; p
< endofFile
; ++p
)
5435 if (nbytes
!= statbuf
.st_size
)
5436 seekFile
= nbytes
+ 1;
5438 (void) fclose(FILEFile
);
5442 * nextarg -- get next argument of arglist.
5444 * The argument is taken from wherever is appropriate.
5446 * If the 'F file' function modifier has been specified, the argument
5447 * will be taken from the file, unless EOF has been reached.
5448 * Otherwise the argument will be taken from argv.
5451 * Return value may point to static data, whose contents are over-
5452 * written on each call.
5457 static char nameFile
[PATH_MAX
+ 1];
5462 if (ptrtoFile
< endofFile
) {
5469 if (fgets(nameFile
, PATH_MAX
+ 1, FILEFile
) != NULL
) {
5470 n
= strlen(nameFile
);
5471 if (n
> 0 && nameFile
[n
-1] == '\n')
5472 nameFile
[n
-1] = '\0';
5476 return (*Cmdargv
++);
5482 * - checks the validity of size values for non-tape devices
5483 * - if size is zero, mulvol tar is disabled and size is
5484 * assumed to be infinite.
5485 * - returns volume size in TBLOCKS
5493 kval
= strtoll(kstr
, NULL
, 0);
5494 if (kval
== (blkcnt_t
)0) { /* no multi-volume; size is infinity. */
5495 mulvol
= 0; /* definitely not mulvol, but we must */
5496 return (0); /* took out setting of NotTape */
5498 if (kval
< (blkcnt_t
)MINSIZE
) {
5499 (void) fprintf(stderr
, gettext(
5500 "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5501 ").\n"), (ulong_t
)MINSIZE
, kval
);
5503 (void) fprintf(stderr
, gettext(
5504 "bad size entry for %s in %s.\n"),
5509 NotTape
++; /* implies non-tape */
5510 return (kval
* 1024 / TBLOCK
); /* convert to TBLOCKS */
5516 * - checks the validity of blocking factors
5517 * - returns blocking factor
5525 bval
= strtoll(bstr
, NULL
, 0);
5526 if ((bval
<= 0) || (bval
> INT_MAX
/ TBLOCK
)) {
5527 (void) fprintf(stderr
, gettext(
5528 "tar: invalid blocksize \"%s\".\n"), bstr
);
5530 (void) fprintf(stderr
, gettext(
5531 "bad blocksize entry for '%s' in %s.\n"),
5542 * - reads DEF_FILE for the set of default values specified.
5543 * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5544 * - 'usefile' points to static data, so will be overwritten
5545 * if this routine is called a second time.
5546 * - the pattern specified by 'arch' must be followed by four
5547 * blank-separated fields (1) device (2) blocking,
5548 * (3) size(K), and (4) tape
5549 * for example: archive0=/dev/fd 1 400 n
5557 if (defopen(DEF_FILE
) != 0)
5559 if (defcntl(DC_SETFLAGS
, (DC_STD
& ~(DC_CASE
))) == -1) {
5560 (void) fprintf(stderr
, gettext(
5561 "tar: error setting parameters for %s.\n"), DEF_FILE
);
5562 return (FALSE
); /* & following ones too */
5564 if ((bp
= defread(arch
)) == NULL
) {
5565 (void) fprintf(stderr
, gettext(
5566 "tar: missing or invalid '%s' entry in %s.\n"),
5570 if ((usefile
= strtok(bp
, " \t")) == NULL
) {
5571 (void) fprintf(stderr
, gettext(
5572 "tar: '%s' entry in %s is empty!\n"), arch
, DEF_FILE
);
5575 if ((bp
= strtok(NULL
, " \t")) == NULL
) {
5576 (void) fprintf(stderr
, gettext(
5577 "tar: block component missing in '%s' entry in %s.\n"),
5581 nblock
= bcheck(bp
);
5582 if ((bp
= strtok(NULL
, " \t")) == NULL
) {
5583 (void) fprintf(stderr
, gettext(
5584 "tar: size component missing in '%s' entry in %s.\n"),
5588 blocklim
= kcheck(bp
);
5589 if ((bp
= strtok(NULL
, " \t")) != NULL
)
5590 NotTape
= (*bp
== 'n' || *bp
== 'N');
5592 NotTape
= (blocklim
!= 0);
5593 (void) defopen(NULL
);
5595 DEBUG("defset: archive='%s'; usefile='%s'\n", arch
, usefile
);
5596 DEBUG("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t
"'\n",
5598 DEBUG("defset: not tape = %d\n", NotTape
, 0);
5605 * Following code handles excluded and included files.
5606 * A hash table of file names to be {in,ex}cluded is built.
5607 * For excluded files, before writing or extracting a file
5608 * check to see if it is in the exclude_tbl.
5609 * For included files, the wantit() procedure will check to
5610 * see if the named file is in the include_tbl.
5614 build_table(file_list_t
*table
[], char *file
)
5617 char buf
[PATH_MAX
+ 1];
5619 if ((fp
= fopen(file
, "r")) == (FILE *)NULL
)
5620 vperror(1, gettext("could not open %s"), file
);
5621 while (fgets(buf
, sizeof (buf
), fp
) != NULL
) {
5622 if (buf
[strlen(buf
) - 1] == '\n')
5623 buf
[strlen(buf
) - 1] = '\0';
5624 /* Only add to table if line has something in it */
5625 if (strspn(buf
, " \t") != strlen(buf
))
5626 add_file_to_table(table
, buf
);
5633 * Add a file name to the the specified table, if the file name has any
5634 * trailing '/'s then delete them before inserting into the table
5638 add_file_to_table(file_list_t
*table
[], char *str
)
5640 char name
[PATH_MAX
+ 1];
5644 (void) strcpy(name
, str
);
5645 while (name
[strlen(name
) - 1] == '/') {
5646 name
[strlen(name
) - 1] = NULL
;
5650 if ((exp
= (file_list_t
*)calloc(sizeof (file_list_t
),
5651 sizeof (char))) == NULL
) {
5652 (void) fprintf(stderr
, gettext(
5653 "tar: out of memory, exclude/include table(entry)\n"));
5657 if ((exp
->name
= strdup(name
)) == NULL
) {
5658 (void) fprintf(stderr
, gettext(
5659 "tar: out of memory, exclude/include table(file name)\n"));
5663 exp
->next
= table
[h
];
5669 * See if a file name or any of the file's parent directories is in the
5670 * specified table, if the file name has any trailing '/'s then delete
5671 * them before searching the table
5675 is_in_table(file_list_t
*table
[], char *str
)
5677 char name
[PATH_MAX
+ 1];
5682 (void) strcpy(name
, str
);
5683 while (name
[strlen(name
) - 1] == '/') {
5684 name
[strlen(name
) - 1] = NULL
;
5688 * check for the file name in the passed list
5692 while (exp
!= NULL
) {
5693 if (strcmp(name
, exp
->name
) == 0) {
5700 * check for any parent directories in the file list
5702 while ((ptr
= strrchr(name
, '/'))) {
5706 while (exp
!= NULL
) {
5707 if (strcmp(name
, exp
->name
) == 0) {
5719 * Compute a hash from a string.
5729 for (cp
= str
; *cp
; cp
++) {
5732 return (h
% TABLE_SIZE
);
5738 void *p
= calloc((unsigned)size
, sizeof (char));
5740 if (p
== NULL
&& freemem
) {
5741 (void) fprintf(stderr
, gettext(
5742 "tar: out of memory, link and directory modtime "
5754 * vperror() --variable argument perror.
5755 * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
5756 * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5757 * with the value of whatever "errno" is set to. If exit_status is not
5758 * zero, then tar exits with that error status. If errflag and exit_status
5759 * are both zero, the routine returns to where it was called and sets Errflg
5764 vperror(int exit_status
, char *fmt
, ...)
5769 (void) fputs("tar: ", stderr
);
5770 (void) vfprintf(stderr
, fmt
, ap
);
5771 (void) fprintf(stderr
, ": %s\n", strerror(errno
));
5784 fatal(char *format
, ...)
5788 va_start(ap
, format
);
5789 (void) fprintf(stderr
, "tar: ");
5790 (void) vfprintf(stderr
, format
, ap
);
5791 (void) fprintf(stderr
, "\n");
5798 * Check to make sure that argument is a char * ptr.
5799 * Actually, we just check to see that it is non-null.
5800 * If it is null, print out the message and call usage(), bailing out.
5804 assert_string(char *s
, char *msg
)
5807 (void) fprintf(stderr
, msg
);
5814 mterr(char *operation
, int i
, int exitcode
)
5816 (void) fprintf(stderr
, gettext(
5817 "tar: %s error: "), operation
);
5821 (void) fprintf(stderr
, gettext("unexpected EOF\n"));
5826 wantit(char *argv
[], char **namep
, char **dirp
, char **component
,
5827 attr_data_t
**attrinfo
)
5830 int gotit
; /* true if we've found a match */
5834 if (xhdr_flgs
& _X_XHDR
) {
5840 if (ret
!= 0) { /* Xhdr items and regular header */
5841 setbytes_to_skip(&stbuf
, ret
);
5843 return (0); /* Error--don't want to extract */
5848 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5849 * of ancillary file is either over or ancillary file
5850 * processing is not required, load info from Xtarhdr and set
5851 * _X_XHDR bit in xhdr_flgs.
5853 if ((dblock
.dbuf
.typeflag
!= 'A') && (xhdr_flgs
!= 0)) {
5854 load_info_from_xtarhdr(xhdr_flgs
, &Xtarhdr
);
5855 xhdr_flgs
|= _X_XHDR
;
5858 #if defined(O_XATTR)
5859 if (dblock
.dbuf
.typeflag
== _XATTR_HDRTYPE
&& xattrbadhead
== 0) {
5861 * Always needs to read the extended header. If atflag, saflag,
5862 * or tflag isn't set, then we'll have the correct info for
5865 (void) read_xattr_hdr(attrinfo
);
5869 * Now that we've read the extended header, call passtape()
5870 * if we don't want to restore attributes or system attributes.
5871 * Don't restore the attribute if we are extracting
5872 * a file from an archive (as opposed to doing a table of
5873 * contents) and any of the following are true:
5874 * 1. neither -@ or -/ was specified.
5875 * 2. -@ was specified, -/ wasn't specified, and we're
5876 * processing a hidden attribute directory of an attribute
5877 * or we're processing a read-write system attribute file.
5878 * 3. -@ wasn't specified, -/ was specified, and the file
5879 * we're processing is not a read-write system attribute file,
5880 * or we're processing the hidden attribute directory of an
5883 * We always process the attributes if we're just generating
5884 * generating a table of contents, or if both -@ and -/ were
5887 if (xattrp
!= NULL
) {
5888 attr_data_t
*ainfo
= *attrinfo
;
5891 ((!atflag
&& !saflag
) ||
5892 (atflag
&& !saflag
&& ((ainfo
->attr_parent
!= NULL
) ||
5893 ainfo
->attr_rw_sysattr
)) ||
5894 (!atflag
&& saflag
&& ((ainfo
->attr_parent
!= NULL
) ||
5895 !ainfo
->attr_rw_sysattr
)))) {
5902 /* sets *namep to point at the proper name */
5903 if (check_prefix(namep
, dirp
, component
) != 0) {
5911 * Logically at EOT - consume any extra blocks
5912 * so that write to our stdin won't fail and
5913 * emit an error message; otherwise something
5914 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5915 * will produce a bogus error message from "dd".
5918 while (read(mt
, tbuf
, TBLOCK
*nblock
) > 0) {
5927 if ((Iflag
&& is_in_table(include_tbl
, *namep
)) ||
5928 (! Iflag
&& *argv
== NULL
)) {
5931 for (cp
= argv
; *cp
; cp
++) {
5932 if (is_prefix(*cp
, *namep
)) {
5944 if (Xflag
&& is_in_table(exclude_tbl
, *namep
)) {
5946 (void) fprintf(stderr
, gettext("%s excluded\n"),
5958 setbytes_to_skip(struct stat
*st
, int err
)
5961 * In a scenario where a typeflag 'X' was followed by
5962 * a typeflag 'A' and typeflag 'O', then the number of
5963 * bytes to skip should be the size of ancillary file,
5964 * plus the dblock for regular file, and the size
5965 * from Xtarhdr. However, if the typeflag was just 'X'
5966 * followed by typeflag 'O', then the number of bytes
5967 * to skip should be the size from Xtarhdr.
5969 if ((err
!= 0) && (dblock
.dbuf
.typeflag
== 'A') &&
5970 (xhdr_flgs
& _X_SIZE
)) {
5971 st
->st_size
+= TBLOCK
+ Xtarhdr
.x_filesz
;
5972 xhdr_flgs
|= _X_XHDR
;
5973 } else if ((dblock
.dbuf
.typeflag
!= 'A') &&
5974 (xhdr_flgs
& _X_SIZE
)) {
5975 st
->st_size
+= Xtarhdr
.x_filesz
;
5976 xhdr_flgs
|= _X_XHDR
;
5981 fill_in_attr_info(char *attr
, char *longname
, char *attrparent
, int atparentfd
,
5982 int rw_sysattr
, attr_data_t
**attrinfo
)
5989 if (attrparent
!= NULL
) {
5990 if ((tparent
= strdup(attrparent
)) == NULL
) {
5992 "unable to allocate memory for attribute parent "
5993 "name for %sattribute %s/%s of %s"),
5994 rw_sysattr
? gettext("system ") : "",
5995 attrparent
, attr
, longname
);
6003 pathlen
= strlen(attr
) + 1;
6004 if (attrparent
!= NULL
) {
6005 pathlen
+= strlen(attrparent
) + 1; /* add 1 for '/' */
6007 if ((tpath
= calloc(1, pathlen
)) == NULL
) {
6009 "unable to allocate memory for full "
6010 "attribute path name for %sattribute %s%s%s of %s"),
6011 rw_sysattr
? gettext("system ") : "",
6012 (attrparent
== NULL
) ? "" : attrparent
,
6013 (attrparent
== NULL
) ? "" : "/",
6015 if (tparent
!= NULL
) {
6020 (void) snprintf(tpath
, pathlen
, "%s%s%s",
6021 (attrparent
== NULL
) ? "" : attrparent
,
6022 (attrparent
== NULL
) ? "" : "/",
6025 /* fill in the attribute info */
6026 if (*attrinfo
== NULL
) {
6027 if ((*attrinfo
= malloc(sizeof (attr_data_t
))) == NULL
) {
6029 "unable to allocate memory for attribute "
6030 "information for %sattribute %s%s%s of %s"),
6031 rw_sysattr
? gettext("system ") : "",
6032 (attrparent
== NULL
) ? "" : attrparent
,
6033 (attrparent
== NULL
) ? "" : gettext("/"),
6035 if (tparent
!= NULL
) {
6042 if ((*attrinfo
)->attr_parent
!= NULL
) {
6043 free((*attrinfo
)->attr_parent
);
6045 if ((*attrinfo
)->attr_path
!= NULL
) {
6046 free((*attrinfo
)->attr_path
);
6049 * The parent file descriptor is passed in, so don't
6050 * close it here as it should be closed by the function
6054 (*attrinfo
)->attr_parent
= tparent
;
6055 (*attrinfo
)->attr_path
= tpath
;
6056 (*attrinfo
)->attr_rw_sysattr
= rw_sysattr
;
6057 (*attrinfo
)->attr_parentfd
= atparentfd
;
6063 * Return through *namep a pointer to the proper fullname (i.e "<name> |
6064 * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6066 * Returns 0 if successful, otherwise returns 1.
6070 check_prefix(char **namep
, char **dirp
, char **compp
)
6072 static char fullname
[PATH_MAX
+ 1];
6073 static char dir
[PATH_MAX
+ 1];
6074 static char component
[PATH_MAX
+ 1];
6075 static char savename
[PATH_MAX
+ 1];
6078 (void) memset(dir
, 0, sizeof (dir
));
6079 (void) memset(component
, 0, sizeof (component
));
6081 if (xhdr_flgs
& _X_PATH
) {
6082 (void) strcpy(fullname
, Xtarhdr
.x_path
);
6084 if (dblock
.dbuf
.prefix
[0] != '\0')
6085 (void) sprintf(fullname
, "%.*s/%.*s", PRESIZ
,
6086 dblock
.dbuf
.prefix
, NAMSIZ
, dblock
.dbuf
.name
);
6088 (void) sprintf(fullname
, "%.*s", NAMSIZ
,
6093 * Set dir and component names
6096 get_parent(fullname
, dir
);
6098 #if defined(O_XATTR)
6099 if (xattrp
== NULL
) {
6102 * Save of real name since were going to chop off the
6105 (void) strcpy(savename
, fullname
);
6107 * first strip of trailing slashes.
6109 chop_endslashes(savename
);
6110 s
= get_component(savename
);
6111 (void) strcpy(component
, s
);
6113 #if defined(O_XATTR)
6115 (void) strcpy(fullname
, xattrp
->h_names
);
6116 (void) strcpy(dir
, fullname
);
6117 (void) strcpy(component
, basename(xattrp
->h_names
+
6118 strlen(xattrp
->h_names
) + 1));
6129 * Return true if the object indicated by the file descriptor and type
6130 * is a tape device, false otherwise
6134 istape(int fd
, int type
)
6138 if (S_ISCHR(type
)) {
6141 if (ioctl(fd
, MTIOCGET
, &mtg
) != -1) {
6153 #define NMAX (sizeof (utmpx.ut_name))
6155 typedef struct cachenode
{ /* this struct must be zeroed before using */
6156 struct cachenode
*next
; /* next in hash chain */
6157 int val
; /* the uid or gid of this entry */
6158 int namehash
; /* name's hash signature */
6159 char name
[NMAX
+1]; /* the string that val maps to */
6162 #define HASHSIZE 256
6164 static cachenode_t
*names
[HASHSIZE
];
6165 static cachenode_t
*groups
[HASHSIZE
];
6166 static cachenode_t
*uids
[HASHSIZE
];
6167 static cachenode_t
*gids
[HASHSIZE
];
6170 hash_byname(char *name
)
6174 for (i
= 0; i
< NMAX
; i
++) {
6178 h
= (h
<< 4) + h
+ c
;
6183 static cachenode_t
*
6184 hash_lookup_byval(cachenode_t
*table
[], int val
)
6189 for (c
= table
[h
& (HASHSIZE
- 1)]; c
!= NULL
; c
= c
->next
) {
6196 static cachenode_t
*
6197 hash_lookup_byname(cachenode_t
*table
[], char *name
)
6199 int h
= hash_byname(name
);
6202 for (c
= table
[h
& (HASHSIZE
- 1)]; c
!= NULL
; c
= c
->next
) {
6203 if (c
->namehash
== h
&& strcmp(c
->name
, name
) == 0)
6209 static cachenode_t
*
6210 hash_insert(cachenode_t
*table
[], char *name
, int value
)
6215 c
= calloc(1, sizeof (cachenode_t
));
6221 (void) strncpy(c
->name
, name
, NMAX
);
6222 c
->namehash
= hash_byname(name
);
6225 if (table
== uids
|| table
== gids
)
6228 signature
= c
->namehash
;
6229 c
->next
= table
[signature
& (HASHSIZE
- 1)];
6230 table
[signature
& (HASHSIZE
- 1)] = c
;
6239 if ((c
= hash_lookup_byval(uids
, uid
)) == NULL
) {
6240 struct passwd
*pwent
= getpwuid(uid
);
6241 c
= hash_insert(uids
, pwent
? pwent
->pw_name
: NULL
, uid
);
6251 if ((c
= hash_lookup_byval(gids
, gid
)) == NULL
) {
6252 struct group
*grent
= getgrgid(gid
);
6253 c
= hash_insert(gids
, grent
? grent
->gr_name
: NULL
, gid
);
6259 getuidbyname(char *name
)
6263 if ((c
= hash_lookup_byname(names
, name
)) == NULL
) {
6264 struct passwd
*pwent
= getpwnam(name
);
6265 c
= hash_insert(names
, name
, pwent
? (int)pwent
->pw_uid
: -1);
6267 return ((uid_t
)c
->val
);
6271 getgidbyname(char *group
)
6275 if ((c
= hash_lookup_byname(groups
, group
)) == NULL
) {
6276 struct group
*grent
= getgrnam(group
);
6277 c
= hash_insert(groups
, group
, grent
? (int)grent
->gr_gid
: -1);
6279 return ((gid_t
)c
->val
);
6284 * Determine whether or not an extended header is also needed. If needed,
6285 * create and write the extended header and its data.
6286 * Writing of the extended header assumes that "tomodes" has been called and
6287 * the relevant information has been placed in the header block.
6293 const char *linkname
,
6294 const char typeflag
,
6296 const struct stat
*sp
,
6302 const char *filename
;
6303 const char *lastslash
;
6305 if (filetype
== XATTR_FILE
)
6306 dblock
.dbuf
.typeflag
= _XATTR_HDRTYPE
;
6308 dblock
.dbuf
.typeflag
= typeflag
;
6309 (void) memset(dblock
.dbuf
.name
, '\0', NAMSIZ
);
6310 (void) memset(dblock
.dbuf
.linkname
, '\0', NAMSIZ
);
6311 (void) memset(dblock
.dbuf
.prefix
, '\0', PRESIZ
);
6313 if (xhdr_flgs
& _X_PATH
)
6314 filename
= Xtarhdr
.x_path
;
6318 if ((dev
= major(device
)) > OCTAL7CHAR
) {
6320 xhdr_flgs
|= _X_DEVMAJOR
;
6321 Xtarhdr
.x_devmajor
= dev
;
6323 (void) fprintf(stderr
, gettext(
6324 "Device major too large for %s. Use -E flag."),
6333 (void) sprintf(dblock
.dbuf
.devmajor
, "%07lo", dev
);
6334 if ((dev
= minor(device
)) > OCTAL7CHAR
) {
6336 xhdr_flgs
|= _X_DEVMINOR
;
6337 Xtarhdr
.x_devminor
= dev
;
6339 (void) fprintf(stderr
, gettext(
6340 "Device minor too large for %s. Use -E flag."),
6349 (void) sprintf(dblock
.dbuf
.devminor
, "%07lo", dev
);
6351 (void) strncpy(dblock
.dbuf
.name
, name
, NAMSIZ
);
6352 (void) strncpy(dblock
.dbuf
.linkname
, linkname
, NAMSIZ
);
6353 (void) sprintf(dblock
.dbuf
.magic
, "%.5s", magic_type
);
6354 (void) sprintf(dblock
.dbuf
.version
, "00");
6355 (void) sprintf(dblock
.dbuf
.uname
, "%.31s", getname(sp
->st_uid
));
6356 (void) sprintf(dblock
.dbuf
.gname
, "%.31s", getgroup(sp
->st_gid
));
6357 (void) strncpy(dblock
.dbuf
.prefix
, prefix
, PRESIZ
);
6358 (void) sprintf(dblock
.dbuf
.chksum
, "%07o", checksum(&dblock
));
6361 (void) bcopy(dblock
.dummy
, xhdr_buf
.dummy
, TBLOCK
);
6362 (void) memset(xhdr_buf
.dbuf
.name
, '\0', NAMSIZ
);
6363 lastslash
= strrchr(name
, '/');
6364 if (lastslash
== NULL
)
6368 (void) strcpy(xhdr_buf
.dbuf
.name
, lastslash
);
6369 (void) memset(xhdr_buf
.dbuf
.linkname
, '\0', NAMSIZ
);
6370 (void) memset(xhdr_buf
.dbuf
.prefix
, '\0', PRESIZ
);
6371 (void) strcpy(xhdr_buf
.dbuf
.prefix
, xhdr_dirname
);
6374 gen_date("mtime", sp
->st_mtim
);
6375 xhdr_buf
.dbuf
.typeflag
= 'X';
6376 if (gen_utf8_names(filename
) != 0)
6380 Xtarhdr
.x_uname
= dblock
.dbuf
.uname
;
6381 Xtarhdr
.x_gname
= dblock
.dbuf
.gname
;
6382 xhdr_flgs
|= (_X_UNAME
| _X_GNAME
);
6385 if (xhdr_flgs
& _X_DEVMAJOR
)
6386 gen_num("SUN.devmajor", Xtarhdr
.x_devmajor
);
6387 if (xhdr_flgs
& _X_DEVMINOR
)
6388 gen_num("SUN.devminor", Xtarhdr
.x_devminor
);
6389 if (xhdr_flgs
& _X_GID
)
6390 gen_num("gid", Xtarhdr
.x_gid
);
6391 if (xhdr_flgs
& _X_UID
)
6392 gen_num("uid", Xtarhdr
.x_uid
);
6393 if (xhdr_flgs
& _X_SIZE
)
6394 gen_num("size", Xtarhdr
.x_filesz
);
6395 if (xhdr_flgs
& _X_PATH
)
6396 gen_string("path", Xtarhdr
.x_path
);
6397 if (xhdr_flgs
& _X_LINKPATH
)
6398 gen_string("linkpath", Xtarhdr
.x_linkpath
);
6399 if (xhdr_flgs
& _X_GNAME
)
6400 gen_string("gname", Xtarhdr
.x_gname
);
6401 if (xhdr_flgs
& _X_UNAME
)
6402 gen_string("uname", Xtarhdr
.x_uname
);
6404 (void) sprintf(xhdr_buf
.dbuf
.size
,
6405 "%011" FMT_off_t_o
, xrec_offset
);
6406 (void) sprintf(xhdr_buf
.dbuf
.chksum
, "%07o",
6407 checksum(&xhdr_buf
));
6408 (void) writetbuf((char *)&xhdr_buf
, 1);
6409 nblks
= TBLOCKS(xrec_offset
);
6410 (void) writetbuf(xrec_ptr
, nblks
);
6417 * makeDir - ensure that a directory with the pathname denoted by name
6418 * exists, and return 1 on success, and 0 on failure (e.g.,
6419 * read-only file system, exists but not-a-directory).
6427 if (access(name
, 0) < 0) { /* name doesn't exist */
6428 if (mkdir(name
, 0777) < 0) {
6429 vperror(0, "%s", name
);
6432 } else { /* name exists */
6433 if (stat(name
, &buf
) < 0) {
6434 vperror(0, "%s", name
);
6438 return ((buf
.st_mode
& S_IFMT
) == S_IFDIR
);
6446 * Save this directory and its mtime on the stack, popping and setting
6447 * the mtimes of any stacked dirs which aren't parents of this one.
6448 * A null name causes the entire stack to be unwound and set.
6450 * Since all the elements of the directory "stack" share a common
6451 * prefix, we can make do with one string. We keep only the current
6452 * directory path, with an associated array of mtime's. A negative
6453 * mtime means no mtime.
6455 * This stack algorithm is not guaranteed to work for tapes created
6456 * with the 'r' function letter, but the vast majority of tapes with
6457 * directories are not. This avoids saving every directory record on
6458 * the tape and setting all the times at the end.
6460 * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6465 doDirTimes(char *name
, timestruc_t modTime
)
6467 static char dirstack
[PATH_MAX
+2];
6468 /* Add spaces for the last slash and last NULL */
6469 static timestruc_t modtimes
[PATH_MAX
+1]; /* hash table */
6476 * Find common prefix
6479 while (*p
== *q
&& *p
) {
6487 * Not a child: unwind the stack, setting the times.
6488 * The order we do this doesn't matter, so we go "forward."
6492 if (modtimes
[p
- dirstack
].tv_sec
>= 0) {
6493 *p
= '\0'; /* zap the slash */
6494 setPathTimes(AT_FDCWD
, dirstack
,
6495 modtimes
[p
- dirstack
]);
6504 * Push this one on the "stack"
6510 * Since the name parameter points the dir pathname
6511 * which is limited only to contain PATH_MAX chars
6512 * at maximum, we can ignore the overflow case of p.
6515 while ((*p
= *q
++)) { /* append the rest of the new dir */
6516 modtimes
[p
- dirstack
].tv_sec
= -1;
6521 * If the tar file had used 'P' or 'E' function modifier,
6522 * append the last slash.
6524 if (*(p
- 1) != '/') {
6528 /* overwrite the last one */
6529 modtimes
[p
- dirstack
- 1] = modTime
;
6535 * setPathTimes - set the modification time for given path. Return 1 if
6536 * successful and 0 if not successful.
6540 setPathTimes(int dirfd
, char *path
, timestruc_t modTime
)
6543 struct timeval timebuf
[2];
6546 * futimesat takes an array of two timeval structs.
6547 * The first entry contains access time.
6548 * The second entry contains modification time.
6549 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6552 timebuf
[0].tv_sec
= time((time_t *)0);
6553 timebuf
[0].tv_usec
= 0;
6554 timebuf
[1].tv_sec
= modTime
.tv_sec
;
6556 /* Extended header: use microseconds */
6557 timebuf
[1].tv_usec
= (xhdr_flgs
& _X_MTIME
) ? modTime
.tv_nsec
/1000 : 0;
6559 if (futimesat(dirfd
, path
, timebuf
) < 0)
6560 vperror(0, "can't set time on %s", path
);
6565 * If hflag is set then delete the symbolic link's target.
6566 * If !hflag then delete the target.
6570 delete_target(int fd
, char *comp
, char *namep
)
6572 struct stat xtractbuf
;
6573 char buf
[PATH_MAX
+ 1];
6577 if (unlinkat(fd
, comp
, AT_REMOVEDIR
) < 0) {
6578 if (errno
== ENOTDIR
&& !hflag
) {
6579 (void) unlinkat(fd
, comp
, 0);
6580 } else if (errno
== ENOTDIR
&& hflag
) {
6581 if (!lstat(namep
, &xtractbuf
)) {
6582 if ((xtractbuf
.st_mode
& S_IFMT
) != S_IFLNK
) {
6583 (void) unlinkat(fd
, comp
, 0);
6584 } else if ((n
= readlink(namep
, buf
,
6586 buf
[n
] = (char)NULL
;
6587 (void) unlinkat(fd
, buf
,
6589 if (errno
== ENOTDIR
)
6590 (void) unlinkat(fd
, buf
, 0);
6592 (void) unlinkat(fd
, comp
, 0);
6595 (void) unlinkat(fd
, comp
, 0);
6605 * Get acl info after stat. Write out ancillary file
6606 * before the normal file, i.e. directory, regular, FIFO,
6607 * link, special. If acl count is less than 4, no need to
6608 * create ancillary file. (i.e. standard permission is in
6611 * Process ancillary file. Read it in and set acl info.
6612 * watch out for 'o' function modifier.
6613 * 't' function letter to display table
6617 * New functions for ACLs and other security attributes
6621 * The function appends the new security attribute info to the end of
6626 char **secinfo
, /* existing security info */
6627 int *secinfo_len
, /* length of existing security info */
6628 int size
, /* new attribute size: unit depends on type */
6629 char *attrtext
, /* new attribute text */
6630 char attr_type
) /* new attribute type */
6635 struct sec_attr
*attr
;
6637 /* no need to add */
6638 if (attr_type
!= DIR_TYPE
) {
6639 if (attrtext
== NULL
)
6643 switch (attr_type
) {
6646 if (attrtext
== NULL
) {
6647 (void) fprintf(stderr
, "acltotext failed\n");
6650 /* header: type + size = 8 */
6651 newattrsize
= 8 + (int)strlen(attrtext
) + 1;
6652 attr
= (struct sec_attr
*)malloc(newattrsize
);
6654 (void) fprintf(stderr
, "can't allocate memory\n");
6657 attr
->attr_type
= attr_type
;
6658 (void) sprintf(attr
->attr_len
,
6659 "%06o", size
); /* acl entry count */
6660 (void) strcpy((char *)&attr
->attr_info
[0], attrtext
);
6664 /* Trusted Extensions */
6667 newattrsize
= sizeof (struct sec_attr
) + strlen(attrtext
);
6668 attr
= (struct sec_attr
*)malloc(newattrsize
);
6670 (void) fprintf(stderr
,
6671 gettext("can't allocate memory\n"));
6674 attr
->attr_type
= attr_type
;
6675 (void) sprintf(attr
->attr_len
,
6676 "%06d", size
); /* len of attr data */
6677 (void) strcpy((char *)&attr
->attr_info
[0], attrtext
);
6681 (void) fprintf(stderr
, "unrecognized attribute type\n");
6685 /* old security info + new attr header(8) + new attr */
6686 oldsize
= *secinfo_len
;
6687 *secinfo_len
+= newattrsize
;
6688 new_secinfo
= (char *)malloc(*secinfo_len
);
6689 if (new_secinfo
== NULL
) {
6690 (void) fprintf(stderr
, "can't allocate memory\n");
6691 *secinfo_len
-= newattrsize
;
6696 (void) memcpy(new_secinfo
, *secinfo
, oldsize
);
6697 (void) memcpy(new_secinfo
+ oldsize
, attr
, newattrsize
);
6701 *secinfo
= new_secinfo
;
6706 * write_ancillary(): write out an ancillary file.
6707 * The file has the same header as normal file except the type and size
6708 * fields. The type is 'A' and size is the sum of all attributes
6710 * The body contains a list of attribute type, size and info. Currently,
6711 * there is only ACL info. This file is put before the normal file.
6714 write_ancillary(union hblock
*dblockp
, char *secinfo
, int len
, char hdrtype
)
6720 /* Just tranditional permissions or no security attribute info */
6721 if (len
== 0 || secinfo
== NULL
)
6724 /* save flag and size */
6725 savflag
= (dblockp
->dbuf
).typeflag
;
6726 (void) sscanf(dblockp
->dbuf
.size
, "%12o", (uint_t
*)&savsize
);
6728 /* special flag for ancillary file */
6729 if (hdrtype
== _XATTR_HDRTYPE
)
6730 dblockp
->dbuf
.typeflag
= _XATTR_HDRTYPE
;
6732 dblockp
->dbuf
.typeflag
= 'A';
6734 /* for pre-2.5 versions of tar, need to make sure */
6735 /* the ACL file is readable */
6736 (void) sprintf(dblock
.dbuf
.mode
, "%07lo",
6737 (stbuf
.st_mode
& POSIXMODES
) | 0000200);
6738 (void) sprintf(dblockp
->dbuf
.size
, "%011o", len
);
6739 (void) sprintf(dblockp
->dbuf
.chksum
, "%07o", checksum(dblockp
));
6741 /* write out the header */
6742 (void) writetbuf((char *)dblockp
, 1);
6744 /* write out security info */
6745 blocks
= TBLOCKS(len
);
6746 (void) writetbuf((char *)secinfo
, (int)blocks
);
6748 /* restore mode, flag and size */
6749 (void) sprintf(dblock
.dbuf
.mode
, "%07lo", stbuf
.st_mode
& POSIXMODES
);
6750 dblockp
->dbuf
.typeflag
= savflag
;
6751 (void) sprintf(dblockp
->dbuf
.size
, "%011o", savsize
);
6755 * Read the data record for extended headers and then the regular header.
6756 * The data are read into the buffer and then null-terminated. Entries
6757 * for typeflag 'X' extended headers are of the format:
6760 * When an extended header record is found, the extended header must
6761 * be processed and its values used to override the values in the
6762 * normal header. The way this is done is to process the extended
6763 * header data record and set the data values, then call getdir
6764 * to process the regular header, then then to reconcile the two
6771 struct keylist_pair
{
6774 } keylist_pair
[] = { _X_DEVMAJOR
, "SUN.devmajor",
6775 _X_DEVMINOR
, "SUN.devminor",
6778 _X_LINKPATH
, "linkpath",
6787 char *keyword
, *value
;
6792 (void) memset(&Xtarhdr
, 0, sizeof (Xtarhdr
));
6796 nblocks
= TBLOCKS(stbuf
.st_size
);
6797 bufneeded
= nblocks
* TBLOCK
;
6798 if (bufneeded
>= xrec_size
) {
6800 xrec_size
= bufneeded
+ 1;
6801 if ((xrec_ptr
= malloc(xrec_size
)) == NULL
)
6802 fatal(gettext("cannot allocate buffer"));
6807 while (nblocks
-- > 0) {
6812 xrec_ptr
[stbuf
.st_size
] = '\0';
6813 while (lineloc
< xrec_ptr
+ stbuf
.st_size
) {
6814 if (dblock
.dbuf
.typeflag
== 'L') {
6819 length
= atoi(lineloc
);
6820 *(lineloc
+ length
- 1) = '\0';
6821 keyword
= strchr(lineloc
, ' ') + 1;
6822 value
= strchr(keyword
, '=') + 1;
6823 *(value
- 1) = '\0';
6827 while (keylist_pair
[i
].keynum
!= (int)_X_LAST
) {
6828 if (strcmp(keyword
, keylist_pair
[i
].keylist
) == 0)
6833 switch (keylist_pair
[i
].keynum
) {
6835 Xtarhdr
.x_devmajor
= (major_t
)strtoul(value
, NULL
, 0);
6837 (void) fprintf(stderr
, gettext(
6838 "tar: Extended header major value error "
6839 "for file # %llu.\n"), xhdr_count
);
6842 xhdr_flgs
|= _X_DEVMAJOR
;
6845 Xtarhdr
.x_devminor
= (minor_t
)strtoul(value
, NULL
, 0);
6847 (void) fprintf(stderr
, gettext(
6848 "tar: Extended header minor value error "
6849 "for file # %llu.\n"), xhdr_count
);
6852 xhdr_flgs
|= _X_DEVMINOR
;
6855 xhdr_flgs
|= _X_GID
;
6856 Xtarhdr
.x_gid
= strtol(value
, NULL
, 0);
6857 if ((errno
) || (Xtarhdr
.x_gid
> UID_MAX
)) {
6858 (void) fprintf(stderr
, gettext(
6859 "tar: Extended header gid value error "
6860 "for file # %llu.\n"), xhdr_count
);
6861 Xtarhdr
.x_gid
= GID_NOBODY
;
6865 if (utf8_local("gname", &Xtarhdr
.x_gname
,
6866 local_gname
, value
, _POSIX_NAME_MAX
) == 0)
6867 xhdr_flgs
|= _X_GNAME
;
6870 if (utf8_local("linkpath", &Xtarhdr
.x_linkpath
,
6871 local_linkpath
, value
, PATH_MAX
) == 0)
6872 xhdr_flgs
|= _X_LINKPATH
;
6877 if (utf8_local("path", &Xtarhdr
.x_path
,
6878 local_path
, value
, PATH_MAX
) == 0)
6879 xhdr_flgs
|= _X_PATH
;
6884 Xtarhdr
.x_filesz
= strtoull(value
, NULL
, 0);
6886 (void) fprintf(stderr
, gettext(
6887 "tar: Extended header invalid filesize "
6888 "for file # %llu.\n"), xhdr_count
);
6891 xhdr_flgs
|= _X_SIZE
;
6894 xhdr_flgs
|= _X_UID
;
6895 Xtarhdr
.x_uid
= strtol(value
, NULL
, 0);
6896 if ((errno
) || (Xtarhdr
.x_uid
> UID_MAX
)) {
6897 (void) fprintf(stderr
, gettext(
6898 "tar: Extended header uid value error "
6899 "for file # %llu.\n"), xhdr_count
);
6900 Xtarhdr
.x_uid
= UID_NOBODY
;
6904 if (utf8_local("uname", &Xtarhdr
.x_uname
,
6905 local_uname
, value
, _POSIX_NAME_MAX
) == 0)
6906 xhdr_flgs
|= _X_UNAME
;
6909 get_xtime(value
, &(Xtarhdr
.x_mtime
));
6911 (void) fprintf(stderr
, gettext(
6912 "tar: Extended header modification time "
6913 "value error for file # %llu.\n"),
6916 xhdr_flgs
|= _X_MTIME
;
6919 (void) fprintf(stderr
,
6920 gettext("tar: unrecognized extended"
6921 " header keyword '%s'. Ignored.\n"), keyword
);
6926 getdir(); /* get regular header */
6927 if (errors
&& errflag
)
6936 * load_info_from_xtarhdr - sets Gen and stbuf variables from
6938 * load_info_from_xtarhdr(flag, xhdrp);
6939 * u_longlong_t flag; xhdr_flgs
6940 * struct xtar_hdr *xhdrp; pointer to extended header
6941 * NOTE: called when typeflag is not 'A' and xhdr_flgs
6945 load_info_from_xtarhdr(u_longlong_t flag
, struct xtar_hdr
*xhdrp
)
6947 if (flag
& _X_DEVMAJOR
) {
6948 Gen
.g_devmajor
= xhdrp
->x_devmajor
;
6950 if (flag
& _X_DEVMINOR
) {
6951 Gen
.g_devminor
= xhdrp
->x_devminor
;
6953 if (flag
& _X_GID
) {
6954 Gen
.g_gid
= xhdrp
->x_gid
;
6955 stbuf
.st_gid
= xhdrp
->x_gid
;
6957 if (flag
& _X_UID
) {
6958 Gen
.g_uid
= xhdrp
->x_uid
;
6959 stbuf
.st_uid
= xhdrp
->x_uid
;
6961 if (flag
& _X_SIZE
) {
6962 Gen
.g_filesz
= xhdrp
->x_filesz
;
6963 stbuf
.st_size
= xhdrp
->x_filesz
;
6965 if (flag
& _X_MTIME
) {
6966 Gen
.g_mtime
= xhdrp
->x_mtime
.tv_sec
;
6967 stbuf
.st_mtim
.tv_sec
= xhdrp
->x_mtime
.tv_sec
;
6968 stbuf
.st_mtim
.tv_nsec
= xhdrp
->x_mtime
.tv_nsec
;
6973 * gen_num creates a string from a keyword and an usigned long long in the
6974 * format: %d %s=%s\n
6975 * This is part of the extended header data record.
6979 gen_num(const char *keyword
, const u_longlong_t number
)
6981 char save_val
[ULONGLONG_MAX_DIGITS
+ 1];
6985 (void) sprintf(save_val
, "%llu", number
);
6987 * len = length of entire line, including itself. len will be
6988 * two digits. So, add the string lengths plus the length of len,
6989 * plus a blank, an equal sign, and a newline.
6991 len
= strlen(save_val
) + strlen(keyword
) + 5;
6992 if (xrec_offset
+ len
> xrec_size
) {
6993 if (((curr_ptr
= realloc(xrec_ptr
, 2 * xrec_size
)) == NULL
))
6995 "cannot allocate extended header buffer"));
6996 xrec_ptr
= curr_ptr
;
6999 (void) sprintf(&xrec_ptr
[xrec_offset
],
7000 "%d %s=%s\n", len
, keyword
, save_val
);
7005 * gen_date creates a string from a keyword and a timestruc_t in the
7006 * format: %d %s=%s\n
7007 * This is part of the extended header data record.
7008 * Currently, granularity is only microseconds, so the low-order three digits
7009 * will be truncated.
7013 gen_date(const char *keyword
, const timestruc_t time_value
)
7015 /* Allow for <seconds>.<nanoseconds>\n */
7016 char save_val
[TIME_MAX_DIGITS
+ LONG_MAX_DIGITS
+ 2];
7020 (void) sprintf(save_val
, "%ld", time_value
.tv_sec
);
7021 len
= strlen(save_val
);
7022 save_val
[len
] = '.';
7023 (void) sprintf(&save_val
[len
+ 1], "%9.9ld", time_value
.tv_nsec
);
7026 * len = length of entire line, including itself. len will be
7027 * two digits. So, add the string lengths plus the length of len,
7028 * plus a blank, an equal sign, and a newline.
7030 len
= strlen(save_val
) + strlen(keyword
) + 5;
7031 if (xrec_offset
+ len
> xrec_size
) {
7032 if (((curr_ptr
= realloc(xrec_ptr
, 2 * xrec_size
)) == NULL
))
7034 "cannot allocate extended header buffer"));
7035 xrec_ptr
= curr_ptr
;
7038 (void) sprintf(&xrec_ptr
[xrec_offset
],
7039 "%d %s=%s\n", len
, keyword
, save_val
);
7044 * gen_string creates a string from a keyword and a char * in the
7045 * format: %d %s=%s\n
7046 * This is part of the extended header data record.
7050 gen_string(const char *keyword
, const char *value
)
7056 * len = length of entire line, including itself. The character length
7057 * of len must be 1-4 characters, because the maximum size of the path
7058 * or the name is PATH_MAX, which is 1024. So, assume 1 character
7059 * for len, one for the space, one for the "=", and one for the newline.
7060 * Then adjust as needed.
7062 /* LINTED constant expression */
7063 assert(PATH_MAX
<= 9996);
7064 len
= strlen(value
) + strlen(keyword
) + 4;
7071 if (xrec_offset
+ len
> xrec_size
) {
7072 if (((curr_ptr
= realloc(xrec_ptr
, 2 * xrec_size
)) == NULL
))
7074 "cannot allocate extended header buffer"));
7075 xrec_ptr
= curr_ptr
;
7079 if (strcmp(keyword
+1, "name") != 0)
7081 (void) sprintf(&xrec_ptr
[xrec_offset
],
7082 "%d %s=%s\n", len
, keyword
, value
);
7086 (void) sprintf(&xrec_ptr
[xrec_offset
],
7087 "%d %s=%snametoolong\n", len
, keyword
, value
);
7094 * Convert time found in the extended header data to seconds and nanoseconds.
7098 get_xtime(char *value
, timestruc_t
*xtime
)
7104 (void) memset(nanosec
, '0', 9);
7107 period
= strchr(value
, '.');
7110 xtime
->tv_sec
= strtol(value
, NULL
, 10);
7114 i
= strlen(period
+1);
7115 (void) strncpy(nanosec
, period
+ 1, min(i
, 9));
7116 xtime
->tv_nsec
= strtol(nanosec
, NULL
, 10);
7121 * Check linkpath for length.
7122 * Emit an error message and return 1 if too long.
7135 if (strlen(linkname
) > (size_t)NAMSIZ
) {
7137 xhdr_flgs
|= _X_LINKPATH
;
7138 Xtarhdr
.x_linkpath
= linkname
;
7140 (void) fprintf(stderr
, gettext(
7141 "tar: %s: linked to %s\n"), longname
, linkname
);
7142 (void) fprintf(stderr
, gettext(
7143 "tar: %s: linked name too long\n"), linkname
);
7151 if (xhdr_flgs
& _X_LINKPATH
)
7152 return (build_dblock(name
, tchar
, type
,
7153 filetype
, &stbuf
, stbuf
.st_dev
,
7156 return (build_dblock(name
, linkname
, type
,
7157 filetype
, &stbuf
, stbuf
.st_dev
, prefix
));
7161 * Convert from UTF-8 to local character set.
7172 static iconv_t iconv_cd
;
7174 const char *iconv_src
;
7179 if (charset_type
== -1) { /* iconv_open failed in earlier try */
7180 (void) fprintf(stderr
, gettext(
7181 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7182 xhdr_count
, source
);
7184 } else if (charset_type
== 0) { /* iconv_open has not yet been done */
7185 nl_target
= nl_langinfo(CODESET
);
7186 if (strlen(nl_target
) == 0) /* locale using 7-bit codeset */
7188 if (strcmp(nl_target
, "646") == 0)
7190 else if (strcmp(nl_target
, "UTF-8") == 0)
7193 if (strncmp(nl_target
, "ISO", 3) == 0)
7197 if ((iconv_cd
= iconv_open(nl_target
, "UTF-8")) ==
7199 if (errno
== EINVAL
)
7200 (void) fprintf(stderr
, gettext(
7201 "tar: conversion routines not "
7202 "available for current locale. "));
7203 (void) fprintf(stderr
, gettext(
7204 "file # %llu: (%s) UTF-8 conversion"
7205 " failed.\n"), xhdr_count
, source
);
7212 /* locale using 7-bit codeset or UTF-8 locale */
7213 if (charset_type
== 1 || charset_type
== 3) {
7214 if (strlen(source
) > max_val
) {
7215 (void) fprintf(stderr
, gettext(
7216 "tar: file # %llu: Extended header %s too long.\n"),
7217 xhdr_count
, option
);
7220 if (charset_type
== 3)
7221 (void) strcpy(target
, source
);
7222 else if (c_utf8(target
, source
) != 0) {
7223 (void) fprintf(stderr
, gettext(
7224 "tar: file # %llu: (%s) UTF-8 conversion"
7225 " failed.\n"), xhdr_count
, source
);
7228 *Xhdr_ptrptr
= target
;
7234 inlen
= strlen(source
);
7235 outlen
= max_val
* UTF_8_FACTOR
;
7236 if (iconv(iconv_cd
, &iconv_src
, &inlen
, &iconv_trg
, &outlen
) ==
7237 (size_t)-1) { /* Error occurred: didn't convert */
7238 (void) fprintf(stderr
, gettext(
7239 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7240 xhdr_count
, source
);
7241 /* Get remaining output; reinitialize conversion descriptor */
7242 iconv_src
= (const char *)NULL
;
7244 (void) iconv(iconv_cd
, &iconv_src
, &inlen
, &iconv_trg
, &outlen
);
7247 /* Get remaining output; reinitialize conversion descriptor */
7248 iconv_src
= (const char *)NULL
;
7250 if (iconv(iconv_cd
, &iconv_src
, &inlen
, &iconv_trg
, &outlen
) ==
7251 (size_t)-1) { /* Error occurred: didn't convert */
7252 (void) fprintf(stderr
, gettext(
7253 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7254 xhdr_count
, source
);
7258 *iconv_trg
= '\0'; /* Null-terminate iconv output string */
7259 if (strlen(target
) > max_val
) {
7260 (void) fprintf(stderr
, gettext(
7261 "tar: file # %llu: Extended header %s too long.\n"),
7262 xhdr_count
, option
);
7265 *Xhdr_ptrptr
= target
;
7270 * Check gname, uname, path, and linkpath to see if they need to go in an
7271 * extended header. If they are already slated to be in an extended header,
7272 * or if they are not ascii, then they need to be in the extended header.
7273 * Then, convert all extended names to UTF-8.
7277 gen_utf8_names(const char *filename
)
7279 static iconv_t iconv_cd
;
7281 char tempbuf
[MAXNAM
+ 1];
7285 if (charset_type
== -1) { /* Previous failure to open. */
7286 (void) fprintf(stderr
, gettext(
7287 "tar: file # %llu: UTF-8 conversion failed.\n"),
7292 if (charset_type
== 0) { /* Need to get conversion descriptor */
7293 nl_target
= nl_langinfo(CODESET
);
7294 if (strlen(nl_target
) == 0) /* locale using 7-bit codeset */
7296 if (strcmp(nl_target
, "646") == 0)
7298 else if (strcmp(nl_target
, "UTF-8") == 0)
7301 if (strncmp(nl_target
, "ISO", 3) == 0)
7306 (void) fprintf(stderr
,
7307 "Opening iconv_cd with target %s\n",
7310 if ((iconv_cd
= iconv_open("UTF-8", nl_target
)) ==
7312 if (errno
== EINVAL
)
7313 (void) fprintf(stderr
, gettext(
7314 "tar: conversion routines not "
7315 "available for current locale. "));
7316 (void) fprintf(stderr
, gettext(
7317 "file (%s): UTF-8 conversion failed.\n"),
7327 errors
+= local_utf8(&Xtarhdr
.x_gname
, local_gname
,
7328 dblock
.dbuf
.gname
, iconv_cd
, _X_GNAME
, _POSIX_NAME_MAX
);
7329 errors
+= local_utf8(&Xtarhdr
.x_uname
, local_uname
,
7330 dblock
.dbuf
.uname
, iconv_cd
, _X_UNAME
, _POSIX_NAME_MAX
);
7331 if ((xhdr_flgs
& _X_LINKPATH
) == 0) { /* Need null-terminated str. */
7332 (void) strncpy(tempbuf
, dblock
.dbuf
.linkname
, NAMSIZ
);
7333 tempbuf
[NAMSIZ
] = '\0';
7335 errors
+= local_utf8(&Xtarhdr
.x_linkpath
, local_linkpath
,
7336 tempbuf
, iconv_cd
, _X_LINKPATH
, PATH_MAX
);
7337 if ((xhdr_flgs
& _X_PATH
) == 0) { /* Concatenate prefix & name */
7338 (void) strncpy(tempbuf
, dblock
.dbuf
.prefix
, PRESIZ
);
7339 tempbuf
[PRESIZ
] = '\0';
7340 nbytes
= strlen(tempbuf
);
7342 tempbuf
[nbytes
++] = '/';
7343 tempbuf
[nbytes
] = '\0';
7345 (void) strncat(tempbuf
+ nbytes
, dblock
.dbuf
.name
,
7347 tempbuf
[MAXNAM
] = '\0';
7349 errors
+= local_utf8(&Xtarhdr
.x_path
, local_path
,
7350 tempbuf
, iconv_cd
, _X_PATH
, PATH_MAX
);
7353 (void) fprintf(stderr
, gettext(
7354 "tar: file (%s): UTF-8 conversion failed.\n"), filename
);
7356 if (errors
&& errflag
)
7373 const char *iconv_src
;
7374 const char *starting_src
;
7379 unsigned char c_to_hex
;
7383 * If the item is already slated for extended format, get the string
7384 * to convert from the extended header record. Otherwise, get it from
7385 * the regular (dblock) area.
7387 if (xhdr_flgs
& xhdrflg
) {
7388 if (charset_type
== 3) { /* Already UTF-8, just copy */
7389 (void) strcpy(target
, *Xhdr_ptrptr
);
7390 *Xhdr_ptrptr
= target
;
7393 iconv_src
= (const char *) *Xhdr_ptrptr
;
7395 if (charset_type
== 3) /* Already in UTF-8 format */
7396 return (0); /* Don't create xhdr record */
7399 starting_src
= iconv_src
;
7401 if ((inlen
= strlen(iconv_src
)) == 0)
7404 if (charset_type
== 1) { /* locale using 7-bit codeset */
7405 if (c_utf8(target
, starting_src
) != 0) {
7406 (void) fprintf(stderr
,
7407 gettext("tar: invalid character in"
7408 " UTF-8 conversion of '%s'\n"), starting_src
);
7414 outlen
= max_val
* UTF_8_FACTOR
;
7416 if (iconv(iconv_cd
, &iconv_src
, &inlen
, &iconv_trg
, &outlen
) ==
7418 /* An error occurred, or not all characters were converted */
7419 if (errno
== EILSEQ
)
7420 (void) fprintf(stderr
,
7421 gettext("tar: invalid character in"
7422 " UTF-8 conversion of '%s'\n"), starting_src
);
7424 (void) fprintf(stderr
, gettext(
7425 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7427 /* Get remaining output; reinitialize conversion descriptor */
7428 iconv_src
= (const char *)NULL
;
7430 (void) iconv(iconv_cd
, &iconv_src
, &inlen
, &iconv_trg
, &outlen
);
7433 /* Get remaining output; reinitialize conversion descriptor */
7434 iconv_src
= (const char *)NULL
;
7436 if (iconv(iconv_cd
, &iconv_src
, &inlen
, &iconv_trg
, &outlen
) ==
7437 (size_t)-1) { /* Error occurred: didn't convert */
7438 if (errno
== EILSEQ
)
7439 (void) fprintf(stderr
,
7440 gettext("tar: invalid character in"
7441 " UTF-8 conversion of '%s'\n"), starting_src
);
7443 (void) fprintf(stderr
, gettext(
7444 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7449 *iconv_trg
= '\0'; /* Null-terminate iconv output string */
7450 if (strcmp(starting_src
, target
) != 0) {
7451 *Xhdr_ptrptr
= target
;
7452 xhdr_flgs
|= xhdrflg
;
7454 (void) fprintf(stderr
, "*** inlen: %d %d; outlen: %d %d\n",
7455 strlen(starting_src
), inlen
, max_val
, outlen
);
7456 (void) fprintf(stderr
, "Input string:\n ");
7457 for (inlen
= 0; inlen
< strlen(starting_src
); inlen
++) {
7458 c_to_hex
= (unsigned char)starting_src
[inlen
];
7459 (void) fprintf(stderr
, " %2.2x", c_to_hex
);
7460 if (inlen
% 20 == 19)
7461 (void) fprintf(stderr
, "\n ");
7463 (void) fprintf(stderr
, "\nOutput string:\n ");
7464 for (inlen
= 0; inlen
< strlen(target
); inlen
++) {
7465 c_to_hex
= (unsigned char)target
[inlen
];
7466 (void) fprintf(stderr
, " %2.2x", c_to_hex
);
7467 if (inlen
% 20 == 19)
7468 (void) fprintf(stderr
, "\n ");
7470 (void) fprintf(stderr
, "\n");
7478 * Function to test each byte of the source string to make sure it is
7479 * in within bounds (value between 0 and 127).
7480 * If valid, copy source to target.
7484 c_utf8(char *target
, const char *source
)
7487 const char *thischar
;
7489 len
= strlen(source
);
7492 if (!isascii((int)(*thischar
++)))
7496 (void) strcpy(target
, source
);
7501 #if defined(O_XATTR)
7502 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
7510 struct linkbuf
*linkinfo
,
7513 char *bufhead
; /* ptr to full buffer */
7515 struct xattr_hdr
*hptr
; /* ptr to header in bufhead */
7516 struct xattr_buf
*tptr
; /* ptr to pathing pieces */
7517 int totalen
; /* total buffer length */
7518 int len
; /* length returned to user */
7519 int stringlen
; /* length of filename + attr */
7521 * length of filename + attr
7525 int complen
; /* length of pathing section */
7526 int linklen
; /* length of link section */
7527 int attrnames_index
; /* attrnames starting index */
7530 * Release previous buffer
7533 if (*attrbuf
!= (char *)NULL
) {
7539 * First add in fixed size stuff
7541 len
= sizeof (struct xattr_hdr
) + sizeof (struct xattr_buf
);
7544 * Add space for two nulls
7546 stringlen
= strlen(attrpath
) + strlen(filename
) + 2;
7547 complen
= stringlen
+ sizeof (struct xattr_buf
);
7552 * Now add on space for link info if any
7555 if (linkinfo
!= NULL
) {
7557 * Again add space for two nulls
7559 linkstringlen
= strlen(linkinfo
->pathname
) +
7560 strlen(linkinfo
->attrname
) + 2;
7561 linklen
= linkstringlen
+ sizeof (struct xattr_buf
);
7568 * Now add padding to end to fill out TBLOCK
7570 * Function returns size of real data and not size + padding.
7573 totalen
= ROUNDTOTBLOCK(len
);
7575 if ((bufhead
= calloc(1, totalen
)) == NULL
) {
7576 fatal(gettext("Out of memory."));
7581 * Now we can fill in the necessary pieces
7585 * first fill in the fixed header
7587 hptr
= (struct xattr_hdr
*)bufhead
;
7588 (void) sprintf(hptr
->h_version
, "%s", XATTR_ARCH_VERS
);
7589 (void) sprintf(hptr
->h_component_len
, "%0*d",
7590 sizeof (hptr
->h_component_len
) - 1, complen
);
7591 (void) sprintf(hptr
->h_link_component_len
, "%0*d",
7592 sizeof (hptr
->h_link_component_len
) - 1, linklen
);
7593 (void) sprintf(hptr
->h_size
, "%0*d", sizeof (hptr
->h_size
) - 1, len
);
7596 * Now fill in the filename + attrnames section
7597 * The filename and attrnames section can be composed of two or more
7598 * path segments separated by a null character. The first segment
7599 * is the path to the parent file that roots the entire sequence in
7600 * the normal name space. The remaining segments describes a path
7601 * rooted at the hidden extended attribute directory of the leaf file of
7602 * the previous segment, making it possible to name attributes on
7603 * attributes. Thus, if we are just archiving an extended attribute,
7604 * the second segment will contain the attribute name. If we are
7605 * archiving a system attribute of an extended attribute, then the
7606 * second segment will contain the attribute name, and a third segment
7607 * will contain the system attribute name. The attribute pathing
7608 * information is obtained from 'attrpath'.
7611 tptr
= (struct xattr_buf
*)(bufhead
+ sizeof (struct xattr_hdr
));
7612 (void) sprintf(tptr
->h_namesz
, "%0*d", sizeof (tptr
->h_namesz
) - 1,
7614 (void) strcpy(tptr
->h_names
, filename
);
7615 attrnames_index
= strlen(filename
) + 1;
7616 (void) strcpy(&tptr
->h_names
[attrnames_index
], attrpath
);
7617 tptr
->h_typeflag
= typeflag
;
7620 * Split the attrnames section into two segments if 'attrpath'
7621 * contains pathing information for a system attribute of an
7622 * extended attribute. We split them by replacing the '/' with
7625 if ((aptr
= strpbrk(&tptr
->h_names
[attrnames_index
], "/")) != NULL
) {
7630 * Now fill in the optional link section if we have one
7633 if (linkinfo
!= (struct linkbuf
*)NULL
) {
7634 tptr
= (struct xattr_buf
*)(bufhead
+
7635 sizeof (struct xattr_hdr
) + complen
);
7637 (void) sprintf(tptr
->h_namesz
, "%0*d",
7638 sizeof (tptr
->h_namesz
) - 1, linkstringlen
);
7639 (void) strcpy(tptr
->h_names
, linkinfo
->pathname
);
7641 &tptr
->h_names
[strlen(linkinfo
->pathname
) + 1],
7642 linkinfo
->attrname
);
7643 tptr
->h_typeflag
= typeflag
;
7645 *attrbuf
= (char *)bufhead
;
7656 struct linkbuf
*linkinfo
,
7665 getstat(int dirfd
, char *longname
, char *shortname
, char *attrparent
)
7671 struct stat symlnbuf
;
7674 i
= fstatat(dirfd
, shortname
, &stbuf
, AT_SYMLINK_NOFOLLOW
);
7676 i
= fstatat(dirfd
, shortname
, &stbuf
, 0);
7679 /* Initialize flag to print error mesg. */
7682 * If stat is done, then need to do lstat
7683 * to determine whether it's a sym link
7686 /* Save returned error */
7689 j
= fstatat(dirfd
, shortname
,
7690 &symlnbuf
, AT_SYMLINK_NOFOLLOW
);
7692 * Suppress error message when file is a symbolic link
7693 * and function modifier 'l' is off. Exception: when
7694 * a symlink points to a symlink points to a
7695 * symlink ... and we get past MAXSYMLINKS. That
7696 * error will cause a file not to be archived, and
7697 * needs to be printed.
7699 if ((j
== 0) && (!linkerrok
) && (slnkerr
!= ELOOP
) &&
7700 (S_ISLNK(symlnbuf
.st_mode
)))
7704 * Restore errno in case the lstat
7705 * on symbolic link change
7711 (void) fprintf(stderr
, gettext(
7712 "tar: %s%s%s%s: %s\n"),
7713 (attrparent
== NULL
) ? "" : gettext("attribute "),
7714 (attrparent
== NULL
) ? "" : attrparent
,
7715 (attrparent
== NULL
) ? "" : gettext(" of "),
7716 longname
, strerror(errno
));
7725 * Recursively archive the extended attributes and/or extended system attributes
7726 * of the base file, longname. Note: extended system attribute files will be
7727 * archived only if the extended system attributes are not transient (i.e. the
7728 * extended system attributes are other than the default values).
7730 * If -@ was specified and the underlying file system supports it, archive the
7731 * extended attributes, and if there is a system attribute associated with the
7732 * extended attribute, then recursively call xattrs_put() to archive the
7733 * hidden attribute directory and the extended system attribute. If -/ was
7734 * specified and the underlying file system supports it, archive the extended
7735 * system attributes. Read-only extended system attributes are never archived.
7737 * Currently, there cannot be attributes on attributes; only system
7738 * attributes on attributes. In addition, there cannot be attributes on
7739 * system attributes. A file and it's attribute directory hierarchy looks as
7741 * longname ----> . ("." is the hidden attribute directory)
7743 * ----------------------------
7745 * <sys_attr_name> <attr_name> ----> .
7750 #if defined(O_XATTR)
7752 xattrs_put(char *longname
, char *shortname
, char *parent
, char *attrparent
)
7754 char *filename
= (attrparent
== NULL
) ? shortname
: attrparent
;
7755 int arc_rwsysattr
= 0;
7763 attr_data_t
*attrinfo
= NULL
;
7766 * If the underlying file system supports it, then archive the extended
7767 * attributes if -@ was specified, and the extended system attributes
7768 * if -/ was specified.
7770 if (verify_attr_support(filename
, (attrparent
== NULL
), ARC_CREATE
,
7771 &ext_attr
) != ATTR_OK
) {
7776 * Only want to archive a read-write extended system attribute file
7777 * if it contains extended system attribute settings that are not the
7780 #if defined(_PC_SATTR_ENABLED)
7783 nvlist_t
*slist
= NULL
;
7785 /* Determine if there are non-transient system attributes */
7787 if ((filefd
= open(filename
, O_RDONLY
)) == -1) {
7788 if (attrparent
== NULL
) {
7790 "unable to open file %s"), longname
);
7794 if (((slist
= sysattr_list(basename(myname
), filefd
,
7795 filename
)) != NULL
) || (errno
!= 0)) {
7798 if (slist
!= NULL
) {
7799 (void) nvlist_free(slist
);
7802 (void) close(filefd
);
7806 * If we aren't archiving extended system attributes, and we are
7807 * processing an attribute, or if we are archiving extended system
7808 * attributes, and there are are no extended attributes, then there's
7809 * no need to open up the attribute directory of the file unless the
7810 * extended system attributes are not transient (i.e, the system
7811 * attributes are not the default values).
7813 if ((arc_rwsysattr
== 0) && ((attrparent
!= NULL
) ||
7814 (saflag
&& !ext_attr
))) {
7817 #endif /* _PC_SATTR_ENABLED */
7819 /* open the parent attribute directory */
7820 fd
= attropen(filename
, ".", O_RDONLY
);
7823 "unable to open attribute directory for %s%s%sfile %s"),
7824 (attrparent
== NULL
) ? "" : gettext("attribute "),
7825 (attrparent
== NULL
) ? "" : attrparent
,
7826 (attrparent
== NULL
) ? "" : gettext(" of "),
7832 * We need to change into the parent's attribute directory to determine
7833 * if each of the attributes should be archived.
7835 if (fchdir(fd
) < 0) {
7837 "cannot change to attribute directory of %s%s%sfile %s"),
7838 (attrparent
== NULL
) ? "" : gettext("attribute "),
7839 (attrparent
== NULL
) ? "" : attrparent
,
7840 (attrparent
== NULL
) ? "" : gettext(" of "),
7846 if (((dirfd
= dup(fd
)) == -1) ||
7847 ((dirp
= fdopendir(dirfd
)) == NULL
)) {
7848 (void) fprintf(stderr
, gettext(
7849 "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7850 (attrparent
== NULL
) ? "" : gettext("attribute "),
7851 (attrparent
== NULL
) ? "" : attrparent
,
7852 (attrparent
== NULL
) ? "" : gettext(" of "),
7860 while (dp
= readdir(dirp
)) {
7861 if (strcmp(dp
->d_name
, "..") == 0) {
7863 } else if (strcmp(dp
->d_name
, ".") == 0) {
7869 /* Determine if this attribute should be archived */
7870 if (verify_attr(dp
->d_name
, attrparent
, arc_rwsysattr
,
7871 &rw_sysattr
) != ATTR_OK
) {
7875 /* gather the attribute's information to pass to putfile() */
7876 if ((fill_in_attr_info(dp
->d_name
, longname
, attrparent
,
7877 fd
, rw_sysattr
, &attrinfo
)) == 1) {
7881 /* add the attribute to the archive */
7882 rc
= putfile(longname
, dp
->d_name
, parent
, attrinfo
,
7883 XATTR_FILE
, LEV0
, SYMLINK_LEV0
);
7889 #if defined(_PC_SATTR_ENABLED)
7891 * If both -/ and -@ were specified, then archive the
7892 * attribute's extended system attributes and hidden directory
7893 * by making a recursive call to xattrs_put().
7895 if (!rw_sysattr
&& saflag
&& atflag
&& (rc
!= PUT_AS_LINK
) &&
7898 xattrs_put(longname
, shortname
, parent
, dp
->d_name
);
7901 * Change back to the parent's attribute directory
7902 * to process any further attributes.
7904 if (fchdir(fd
) < 0) {
7906 "cannot change back to attribute directory "
7907 "of file %s"), longname
);
7911 #endif /* _PC_SATTR_ENABLED */
7914 if (attrinfo
!= NULL
) {
7915 if (attrinfo
->attr_parent
!= NULL
) {
7916 free(attrinfo
->attr_parent
);
7918 free(attrinfo
->attr_path
);
7921 (void) closedir(dirp
);
7926 /* Change back to the parent directory of the base file */
7927 if (attrparent
== NULL
) {
7928 (void) chdir(parent
);
7934 xattrs_put(char *longname
, char *shortname
, char *parent
, char *attrppath
)
7937 #endif /* O_XATTR */
7940 put_link(char *name
, char *longname
, char *component
, char *longattrname
,
7941 char *prefix
, int filetype
, char type
)
7944 if (stbuf
.st_nlink
> 1) {
7948 for (lp
= ihead
; lp
!= NULL
; lp
= lp
->nextp
)
7949 if (lp
->inum
== stbuf
.st_ino
&&
7950 lp
->devnum
== stbuf
.st_dev
) {
7955 #if defined(O_XATTR)
7956 if (filetype
== XATTR_FILE
)
7957 if (put_xattr_hdr(longname
, component
,
7958 longattrname
, prefix
, type
, filetype
, lp
)) {
7962 stbuf
.st_size
= (off_t
)0;
7963 if (filetype
!= XATTR_FILE
) {
7965 if (chk_path_build(name
, longname
, lp
->pathname
,
7966 prefix
, type
, filetype
) > 0) {
7971 if (mulvol
&& tapepos
+ 1 >= blocklim
)
7973 (void) writetbuf((char *)&dblock
, 1);
7975 * write_ancillary() is not needed here.
7976 * The first link is handled in the following
7977 * else statement. No need to process ACLs
7978 * for other hard links since they are the
7985 DEBUG("seek = %" FMT_blkcnt_t
7986 "K\t", K(tapepos
), 0);
7988 if (filetype
== XATTR_FILE
) {
7989 (void) fprintf(vfile
, gettext(
7990 "a %s attribute %s link to "
7991 "%s attribute %s\n"),
7992 name
, component
, name
,
7995 (void) fprintf(vfile
, gettext(
7996 "a %s link to %s\n"),
7997 longname
, lp
->pathname
);
8003 lp
= (struct linkbuf
*)getmem(sizeof (*lp
));
8004 if (lp
!= (struct linkbuf
*)NULL
) {
8007 lp
->inum
= stbuf
.st_ino
;
8008 lp
->devnum
= stbuf
.st_dev
;
8009 lp
->count
= stbuf
.st_nlink
- 1;
8010 if (filetype
== XATTR_FILE
) {
8011 (void) strcpy(lp
->pathname
, longname
);
8012 (void) strcpy(lp
->attrname
,
8015 (void) strcpy(lp
->pathname
, longname
);
8016 (void) strcpy(lp
->attrname
, "");
8027 put_extra_attributes(char *longname
, char *shortname
, char *longattrname
,
8028 char *prefix
, int filetype
, char typeflag
)
8030 static acl_t
*aclp
= NULL
;
8037 #if defined(O_XATTR)
8038 if ((atflag
|| saflag
) && (filetype
== XATTR_FILE
)) {
8039 if (put_xattr_hdr(longname
, shortname
, longattrname
, prefix
,
8040 typeflag
, filetype
, NULL
)) {
8048 char *secinfo
= NULL
;
8052 if (((stbuf
.st_mode
& S_IFMT
) != S_IFLNK
)) {
8054 * Get ACL info: dont bother allocating space if
8055 * there is only a trivial ACL.
8057 if ((error
= acl_get(shortname
, ACL_NO_TRIVIAL
,
8059 (void) fprintf(stderr
, gettext(
8060 "%s: failed to retrieve acl : %s\n"),
8061 longname
, acl_strerror(error
));
8066 /* append security attributes if any */
8068 (void) append_secattr(&secinfo
, &len
, acl_cnt(aclp
),
8069 acl_totext(aclp
, ACL_APPEND_ID
| ACL_COMPACT_FMT
|
8070 ACL_SID_FMT
), (acl_type(aclp
) == ACLENT_T
) ?
8071 UFSD_ACL
: ACE_ACL
);
8075 /* append Trusted Extensions extended attributes */
8076 append_ext_attr(shortname
, &secinfo
, &len
);
8077 (void) write_ancillary(&dblock
, secinfo
, len
, ACL_HDR
);
8079 } else if (aclp
!= NULL
) {
8080 (void) write_ancillary(&dblock
, secinfo
, len
, ACL_HDR
);
8086 #if defined(O_XATTR)
8088 put_xattr_hdr(char *longname
, char *shortname
, char *longattrname
, char *prefix
,
8089 int typeflag
, int filetype
, struct linkbuf
*lp
)
8094 static char *attrbuf
= NULL
;
8097 lname
= malloc(sizeof (char) * strlen("/dev/null") + 1 +
8098 strlen(shortname
) + strlen(".hdr") + 1);
8100 if (lname
== NULL
) {
8101 fatal(gettext("Out of Memory."));
8103 sname
= malloc(sizeof (char) * strlen(shortname
) +
8104 strlen(".hdr") + 1);
8105 if (sname
== NULL
) {
8106 fatal(gettext("Out of Memory."));
8109 (void) sprintf(sname
, "%s.hdr", shortname
);
8110 (void) sprintf(lname
, "/dev/null/%s", sname
);
8112 if (strlcpy(dblock
.dbuf
.name
, lname
, sizeof (dblock
.dbuf
.name
)) >=
8113 sizeof (dblock
.dbuf
.name
)) {
8115 "Buffer overflow writing extended attribute file name"));
8119 * dump extended attr lookup info
8121 prepare_xattr(&attrbuf
, longname
, longattrname
, typeflag
, lp
, &attrlen
);
8122 write_ancillary(&dblock
, attrbuf
, attrlen
, _XATTR_HDRTYPE
);
8124 (void) sprintf(lname
, "/dev/null/%s", shortname
);
8125 (void) strncpy(dblock
.dbuf
.name
, sname
, NAMSIZ
);
8128 * Set up filename for attribute
8131 error
= build_dblock(lname
, tchar
, '0', filetype
,
8132 &stbuf
, stbuf
.st_dev
, prefix
);
8140 #if defined(O_XATTR)
8142 read_xattr_hdr(attr_data_t
**attrinfo
)
8145 char *attrparent
= NULL
;
8149 int comp_len
, link_len
;
8154 if (dblock
.dbuf
.typeflag
!= _XATTR_HDRTYPE
)
8157 bytes
= stbuf
.st_size
;
8158 if ((xattrhead
= calloc(1, (int)bytes
)) == NULL
) {
8159 (void) fprintf(stderr
, gettext(
8160 "Insufficient memory for extended attribute\n"));
8164 tp
= (char *)xattrhead
;
8165 blocks
= TBLOCKS(bytes
);
8166 while (blocks
-- > 0) {
8168 if (bytes
<= TBLOCK
) {
8169 (void) memcpy(tp
, buf
, (size_t)bytes
);
8172 (void) memcpy(tp
, buf
, TBLOCK
);
8179 * Validate that we can handle header format
8181 if (strcmp(xattrhead
->h_version
, XATTR_ARCH_VERS
) != 0) {
8182 (void) fprintf(stderr
,
8183 gettext("Unknown extended attribute format encountered\n"));
8184 (void) fprintf(stderr
,
8185 gettext("Disabling extended attribute parsing\n"));
8189 (void) sscanf(xattrhead
->h_component_len
, "%10d", &comp_len
);
8190 (void) sscanf(xattrhead
->h_link_component_len
, "%10d", &link_len
);
8191 xattrp
= (struct xattr_buf
*)(((char *)xattrhead
) +
8192 sizeof (struct xattr_hdr
));
8193 (void) sscanf(xattrp
->h_namesz
, "%7d", &namelen
);
8195 xattr_linkp
= (struct xattr_buf
*)
8196 ((int)xattrp
+ (int)comp_len
);
8201 * Gather the attribute path from the filename and attrnames section.
8202 * The filename and attrnames section can be composed of two or more
8203 * path segments separated by a null character. The first segment
8204 * is the path to the parent file that roots the entire sequence in
8205 * the normal name space. The remaining segments describes a path
8206 * rooted at the hidden extended attribute directory of the leaf file of
8207 * the previous segment, making it possible to name attributes on
8210 parentfilelen
= strlen(xattrp
->h_names
);
8211 xattrapath
= xattrp
->h_names
+ parentfilelen
+ 1;
8212 if ((strlen(xattrapath
) + parentfilelen
+ 2) < namelen
) {
8214 * The attrnames section contains a system attribute on an
8215 * attribute. Save the name of the attribute for use later,
8216 * and replace the null separating the attribute name from
8217 * the system attribute name with a '/' so that xattrapath can
8218 * be used to display messages with the full attribute path name
8219 * rooted at the hidden attribute directory of the base file
8220 * in normal name space.
8222 attrparent
= strdup(xattrapath
);
8223 attrparentlen
= strlen(attrparent
);
8224 xattrapath
[attrparentlen
] = '/';
8226 if ((fill_in_attr_info((attrparent
== NULL
) ? xattrapath
:
8227 xattrapath
+ attrparentlen
+ 1, xattrapath
, attrparent
,
8228 -1, 0, attrinfo
)) == 1) {
8233 /* Gather link info */
8235 xattr_linkaname
= xattr_linkp
->h_names
+
8236 strlen(xattr_linkp
->h_names
) + 1;
8238 xattr_linkaname
= NULL
;
8245 read_xattr_hdr(attr_data_t
**attrinfo
)
8252 * skip over extra slashes in string.
8257 * would return pointer at
8262 skipslashes(char *string
, char *start
)
8264 while ((string
> start
) && *(string
- 1) == '/') {
8272 * Return the parent directory of a given path.
8275 * /usr/tmp return /usr
8276 * /usr/tmp/file return /usr/tmp
8281 * dir is assumed to be at least as big as path.
8284 get_parent(char *path
, char *dir
)
8287 char tmpdir
[PATH_MAX
+ 1];
8289 if (strlen(path
) > PATH_MAX
) {
8290 fatal(gettext("pathname is too long"));
8292 (void) strcpy(tmpdir
, path
);
8293 chop_endslashes(tmpdir
);
8295 if ((s
= strrchr(tmpdir
, '/')) == NULL
) {
8296 (void) strcpy(dir
, ".");
8298 s
= skipslashes(s
, tmpdir
);
8301 (void) strcpy(dir
, "/");
8303 (void) strcpy(dir
, tmpdir
);
8307 #if defined(O_XATTR)
8309 get_component(char *path
)
8313 ptr
= strrchr(path
, '/');
8318 * Handle trailing slash
8320 if (*(ptr
+ 1) == '\0')
8328 get_component(char *path
)
8334 #if defined(O_XATTR)
8336 retry_open_attr(int pdirfd
, int cwd
, char *dirp
, char *pattr
, char *name
,
8337 int oflag
, mode_t mode
)
8341 struct timeval times
[2];
8343 struct stat parentstat
;
8348 * We couldn't get to attrdir. See if its
8349 * just a mode problem on the parent file.
8350 * for example: a mode such as r-xr--r--
8351 * on a ufs file system without extended
8352 * system attribute support won't let us
8353 * create an attribute dir if it doesn't
8354 * already exist, and on a ufs file system
8355 * with extended system attribute support
8356 * won't let us open the attribute for
8359 * If file has a non-trivial ACL, then save it
8360 * off so that we can place it back on after doing
8363 if ((dirfd
= openat(cwd
, (pattr
== NULL
) ? dirp
: pattr
,
8367 if (fstat(dirfd
, &parentstat
) == -1) {
8368 (void) fprintf(stderr
, gettext(
8369 "tar: cannot stat %sfile %s: %s\n"),
8370 (pdirfd
== -1) ? "" : gettext("parent of "),
8371 (pdirfd
== -1) ? dirp
: name
, strerror(errno
));
8374 if ((error
= facl_get(dirfd
, ACL_NO_TRIVIAL
, &aclp
)) != 0) {
8375 (void) fprintf(stderr
, gettext(
8376 "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8377 (pdirfd
== -1) ? "" : gettext("parent of "),
8378 (pdirfd
== -1) ? dirp
: name
, strerror(errno
));
8382 newmode
= S_IWUSR
| parentstat
.st_mode
;
8383 if (fchmod(dirfd
, newmode
) == -1) {
8384 (void) fprintf(stderr
,
8386 "tar: cannot fchmod %sfile %s to %o: %s\n"),
8387 (pdirfd
== -1) ? "" : gettext("parent of "),
8388 (pdirfd
== -1) ? dirp
: name
, newmode
, strerror(errno
));
8397 * We weren't able to create the attribute directory before.
8400 ofilefd
= attropen(dirp
, ".", oflag
);
8403 * We weren't able to create open the attribute before.
8406 ofilefd
= openat(pdirfd
, name
, oflag
, mode
);
8410 * Put mode back to original
8412 if (fchmod(dirfd
, parentstat
.st_mode
) == -1) {
8413 (void) fprintf(stderr
,
8414 gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8415 (pdirfd
== -1) ? "" : gettext("parent of "),
8416 (pdirfd
== -1) ? dirp
: name
, newmode
, strerror(errno
));
8420 error
= facl_set(dirfd
, aclp
);
8422 (void) fprintf(stderr
,
8423 gettext("tar: failed to set acl entries on "
8425 (pdirfd
== -1) ? "" : gettext("parent of "),
8426 (pdirfd
== -1) ? dirp
: name
);
8432 * Put back time stamps
8435 times
[0].tv_sec
= parentstat
.st_atime
;
8436 times
[0].tv_usec
= 0;
8437 times
[1].tv_sec
= parentstat
.st_mtime
;
8438 times
[1].tv_usec
= 0;
8440 (void) futimesat(cwd
, (pattr
== NULL
) ? dirp
: pattr
, times
);
8442 (void) close(dirfd
);
8448 #if !defined(O_XATTR)
8450 openat64(int fd
, const char *name
, int oflag
, mode_t cmode
)
8452 return (open64(name
, oflag
, cmode
));
8456 openat(int fd
, const char *name
, int oflag
, mode_t cmode
)
8458 return (open(name
, oflag
, cmode
));
8462 fchownat(int fd
, const char *name
, uid_t owner
, gid_t group
, int flag
)
8464 if (flag
== AT_SYMLINK_NOFOLLOW
)
8465 return (lchown(name
, owner
, group
));
8467 return (chown(name
, owner
, group
));
8471 renameat(int fromfd
, char *old
, int tofd
, char *new)
8473 return (rename(old
, new));
8477 futimesat(int fd
, char *path
, struct timeval times
[2])
8479 return (utimes(path
, times
));
8483 unlinkat(int dirfd
, char *path
, int flag
)
8485 if (flag
== AT_REMOVEDIR
)
8486 return (rmdir(path
));
8488 return (unlink(path
));
8492 fstatat(int fd
, char *path
, struct stat
*buf
, int flag
)
8494 if (flag
== AT_SYMLINK_NOFOLLOW
)
8495 return (lstat(path
, buf
));
8497 return (stat(path
, buf
));
8501 attropen(char *file
, char *attr
, int omode
, mode_t cmode
)
8509 chop_endslashes(char *path
)
8514 * Chop of slashes, but not if all we have is slashes
8516 * should make no changes, otherwise it will screw up
8519 end
= &path
[strlen(path
) -1];
8520 if (*end
== '/' && end
!= path
) {
8521 ptr
= skipslashes(end
, path
);
8522 if (ptr
!= NULL
&& ptr
!= path
) {
8527 /* Trusted Extensions */
8530 * append_ext_attr():
8532 * Append extended attributes and other information into the buffer
8533 * that gets written to the ancillary file.
8535 * With option 'T', we create a tarfile which
8536 * has an ancillary file each corresponding archived file.
8537 * Each ancillary file contains 1 or more of the
8538 * following attributes:
8540 * attribute type attribute process procedure
8541 * ---------------- ---------------- --------------------------
8542 * DIR_TYPE = 'D' directory flag append if a directory
8543 * LBL_TYPE = 'L' SL[IL] or SL append ascii label
8548 append_ext_attr(char *shortname
, char **secinfo
, int *len
)
8550 bslabel_t b_slabel
; /* binary sensitvity label */
8551 char *ascii
= NULL
; /* ascii label */
8554 * For each attribute type, append it if it is
8555 * relevant to the file type.
8559 * For attribute type DIR_TYPE,
8560 * append it to the following file type:
8562 * S_IFDIR: directories
8566 * For attribute type LBL_TYPE,
8567 * append it to the following file type:
8569 * S_IFDIR: directories (including mld, sld)
8570 * S_IFLNK: symbolic link
8571 * S_IFREG: regular file but not hard link
8572 * S_IFIFO: FIFO file but not hard link
8573 * S_IFCHR: char special file but not hard link
8574 * S_IFBLK: block special file but not hard link
8576 switch (stbuf
.st_mode
& S_IFMT
) {
8583 (void) append_secattr(secinfo
, len
, 1,
8587 * Get and append attribute types LBL_TYPE.
8588 * For directories, LBL_TYPE contains SL.
8590 /* get binary sensitivity label */
8591 if (getlabel(shortname
, &b_slabel
) != 0) {
8592 (void) fprintf(stderr
,
8593 gettext("tar: can't get sensitvity label for "
8594 " %s, getlabel() error: %s\n"),
8595 shortname
, strerror(errno
));
8598 if (bsltos(&b_slabel
, &ascii
,
8600 (void) fprintf(stderr
,
8601 gettext("tar: can't get ascii SL for"
8602 " %s\n"), shortname
);
8604 /* append LBL_TYPE */
8605 (void) append_secattr(secinfo
, len
,
8606 strlen(ascii
) + 1, ascii
,
8610 if (ascii
!= NULL
) {
8625 /* get binary sensitivity label */
8626 if (getlabel(shortname
, &b_slabel
) != 0) {
8627 (void) fprintf(stderr
,
8628 gettext("tar: can't get sensitivty label for %s, "
8629 "getlabel() error: %s\n"),
8630 shortname
, strerror(errno
));
8632 /* get ascii IL[SL] */
8633 if (bsltos(&b_slabel
, &ascii
, 0, 0) <= 0) {
8634 (void) fprintf(stderr
,
8635 gettext("tar: can't translate sensitivity "
8636 " label for %s\n"), shortname
);
8641 cmw_length
= strlen("ADMIN_LOW [] ") +
8643 if ((cmw_label
= malloc(cmw_length
)) == NULL
) {
8644 (void) fprintf(stderr
, gettext(
8645 "Insufficient memory for label\n"));
8648 /* append LBL_TYPE */
8649 (void) snprintf(cmw_label
, cmw_length
,
8650 "ADMIN_LOW [%s]", ascii
);
8651 (void) append_secattr(secinfo
, len
,
8652 strlen(cmw_label
) + 1, cmw_label
,
8656 if (ascii
!= NULL
) {
8667 } /* end switch for LBL_TYPE */
8673 } /* end of append_ext_attr */
8677 * Name: extract_attr()
8680 * Process attributes from the ancillary file due to
8683 * Call by doxtract() as part of the switch case structure.
8684 * Making this a separate routine because the nesting are too
8685 * deep in doxtract, thus, leaving very little space
8686 * on each line for instructions.
8688 * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
8690 * For option 'T', following are possible attributes in
8691 * a TS 8 ancillary file: (NOTE: No IL support)
8693 * attribute type attribute process procedure
8694 * ---------------- ---------------- -------------------------
8695 * # LBL_TYPE = 'L' SL construct binary label
8696 * # APRIV_TYPE = 'P' allowed priv construct privileges
8697 * # FPRIV_TYPE = 'p' forced priv construct privileges
8698 * # COMP_TYPE = 'C' path component construct real path
8699 * # DIR_TYPE = 'D' directory flag note it is a directory
8700 * $ UFSD_ACL = '1' ACL data construct ACL entries
8701 * ATTR_FLAG_TYPE = 'F' file attr flags construct binary flags
8702 * LK_COMP_TYPE = 'K' linked path comp construct linked real path
8704 * note: # = attribute names common between TS 8 & TS 2.5 ancillary
8706 * $ = ACL attribute is processed for the option 'p', it doesn't
8709 * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
8713 extract_attr(char **file_ptr
, struct sec_attr
*attr
)
8716 char *dummy_buf
; /* for attribute extract */
8718 dummy_buf
= attr
->attr_info
;
8720 switch (attr
->attr_type
) {
8730 * LBL_TYPE is used to indicate SL for directory, and
8731 * CMW label for other file types.
8734 if (!dir_flag
) { /* not directory */
8735 /* Skip over IL portion */
8736 char *sl_ptr
= strchr(dummy_buf
, '[');
8741 err
= stobsl(sl_ptr
, &bs_label
,
8742 NEW_LABEL
, &reterr
);
8743 } else { /* directory */
8744 err
= stobsl(dummy_buf
, &bs_label
,
8745 NEW_LABEL
, &reterr
);
8748 (void) fprintf(stderr
, gettext("tar: "
8749 "can't convert %s to binary label\n"),
8751 bslundef(&bs_label
);
8752 } else if (!blequal(&bs_label
, &admin_low
) &&
8753 !blequal(&bs_label
, &admin_high
)) {
8754 bslabel_t
*from_label
;
8756 char tempbuf
[MAXPATHLEN
];
8758 if (*orig_namep
!= '/') {
8759 /* got relative linked to path */
8760 (void) getcwd(tempbuf
, (sizeof (tempbuf
)));
8761 (void) strncat(tempbuf
, "/", MAXPATHLEN
);
8766 (void) strncat(tempbuf
, orig_namep
, MAXPATHLEN
);
8767 from_label
= getlabelbypath(tempbuf
);
8768 if (from_label
!= NULL
) {
8769 if (blequal(from_label
, &admin_low
)) {
8770 if ((getpathbylabel(tempbuf
, buf
,
8771 MAXPATHLEN
, &bs_label
) == NULL
)) {
8772 (void) fprintf(stderr
,
8774 "can't get zone root path for "
8786 rebuild_comp_path(dummy_buf
, file_ptr
);
8791 if (rebuild_lk_comp_path(dummy_buf
, file_ptr
)
8795 (void) fprintf(stderr
, gettext("tar: warning: link's "
8796 "target pathname might be invalid.\n"));
8806 case ATTR_FLAG_TYPE
:
8818 } /* end extract_attr */
8823 * Name: rebuild_comp_path()
8826 * Take the string of components passed down by the calling
8827 * routine and parse the values and rebuild the path.
8828 * This routine no longer needs to produce a new real_path
8829 * string because it is produced when the 'L' LABEL_TYPE is
8830 * interpreted. So the only thing done here is to distinguish
8831 * between an SLD and an MLD entry. We only want one, so we
8832 * ignore the MLD entry by setting the mld_flag.
8838 rebuild_comp_path(char *str
, char **namep
)
8842 while (*str
!= '\0') {
8849 if ((cp
= strstr(str
, ";;")) != NULL
) {
8860 if ((cp
= strstr(str
, ";;")) != NULL
) {
8871 if ((cp
= strstr(str
, ";;")) != NULL
) {
8883 } /* end rebuild_comp_path() */
8886 * Name: rebuild_lk_comp_path()
8889 * Take the string of components passed down by the calling
8890 * routine and parse the values and rebuild the path.
8897 rebuild_lk_comp_path(char *str
, char **namep
)
8903 char pbuf
[MAXPATHLEN
];
8907 char tempbuf
[MAXPATHLEN
];
8909 bslabel_t
*from_label
;
8910 char zonename
[ZONENAME_MAX
];
8918 * For linked to pathname (LK_COMP_TYPE):
8919 * - If the linked to pathname is absolute (start with /), we
8920 * will use it as is.
8921 * - If it is a relative pathname then it is relative to 1 of 2
8922 * directories. For a hardlink, it is relative to the current
8923 * directory. For a symbolic link, it is relative to the
8924 * directory the symbolic link is in. For the symbolic link
8925 * case, set a flag to indicate we need to use the prefix of
8926 * the restored file's pathname with the linked to pathname.
8928 * NOTE: At this point, we have no way to determine if we have
8929 * a hardlink or a symbolic link. We will compare the 1st
8930 * component in the prefix portion of the restore file's
8931 * pathname to the 1st component in the attribute data
8932 * (the linked pathname). If they are the same, we will assume
8933 * the link pathname to reconstruct is relative to the current
8934 * directory. Otherwise, we will set a flag indicate we need
8935 * to use a prefix with the reconstructed name. Need to compare
8936 * both the adorned and unadorned version before deciding a
8941 if (*(str
+ 1) != '/') { /* got relative linked to path */
8943 ptr2
= strrchr(ptr1
, '/');
8947 plen
++; /* include '/' */
8948 (void) strncpy(pbuf
, ptr1
, plen
);
8949 *(pbuf
+ plen
) = '\0';
8950 ptr2
= strchr(pbuf
, '/');
8951 if (strncmp(pbuf
, str
+ 1, ptr2
- pbuf
) != 0)
8961 while (*str
!= '\0') {
8968 if ((cp
= strstr(str
, ";;")) != NULL
) {
8972 * Ignore attempts to backup over .MLD.
8974 if (strcmp(str
, "../") != 0)
8975 (void) strncat(buf
, str
, MAXPATHLEN
);
8984 if ((cp
= strstr(str
, ";;")) != NULL
) {
8988 * Use the path name in the header if
8989 * error occurs when processing the
8993 if (!stobsl(str
, &bslabel
,
8994 NO_CORRECTION
, &reterr
)) {
8995 (void) fprintf(stderr
, gettext(
8996 "tar: can't translate to binary"
8997 "SL for SLD, stobsl() error:"
8998 " %s\n"), strerror(errno
));
9005 if (use_pbuf
== 1) {
9007 /* relative linked to path */
9009 (void) getcwd(tempbuf
,
9010 (sizeof (tempbuf
)));
9011 (void) strncat(tempbuf
, "/",
9013 (void) strncat(tempbuf
, pbuf
,
9017 (void) strcpy(tempbuf
, pbuf
);
9019 } else if (*buf
!= '/') {
9020 /* got relative linked to path */
9022 (void) getcwd(tempbuf
,
9023 (sizeof (tempbuf
)));
9024 (void) strncat(tempbuf
, "/",
9029 (void) strncat(tempbuf
, buf
, MAXPATHLEN
);
9032 if (blequal(&bslabel
, &admin_high
)) {
9033 bslabel
= admin_low
;
9038 * Check for cross-zone symbolic links
9040 from_label
= getlabelbypath(real_path
);
9041 if (rpath_flag
&& (from_label
!= NULL
) &&
9042 !blequal(&bslabel
, from_label
)) {
9044 getzoneidbylabel(&bslabel
)) == -1) {
9045 (void) fprintf(stderr
,
9046 gettext("tar: can't get "
9047 "zone ID for %s\n"),
9051 if (zone_getattr(zoneid
, ZONE_ATTR_NAME
,
9052 &zonename
, ZONENAME_MAX
) == -1) {
9053 /* Badly configured zone info */
9054 (void) fprintf(stderr
,
9055 gettext("tar: can't get "
9056 "zonename for %s\n"),
9060 (void) strncpy(buf
, AUTO_ZONE
,
9062 (void) strncat(buf
, "/",
9064 (void) strncat(buf
, zonename
,
9067 if (from_label
!= NULL
)
9069 (void) strncat(buf
, tempbuf
, MAXPATHLEN
);
9078 if ((cp
= strstr(str
, ";;")) != NULL
) {
9080 (void) strncat(buf
, str
, MAXPATHLEN
);
9088 (void) fprintf(stderr
, gettext(
9089 "tar: error rebuilding path %s\n"),
9098 * Done for LK_COMP_TYPE
9101 return (0); /* component path is rebuilt successfully */
9103 } /* end rebuild_lk_comp_path() */
9106 * Name: check_ext_attr()
9109 * Check the extended attributes for a file being extracted.
9110 * The attributes being checked here are CMW labels.
9111 * ACLs are not set here because they are set by the
9112 * pflag in doxtract().
9114 * If the label doesn't match, return 0
9118 check_ext_attr(char *filename
)
9120 bslabel_t currentlabel
; /* label from zone */
9122 if (bltype(&bs_label
, SUN_SL_UN
)) {
9123 /* No label check possible */
9126 if (getlabel(filename
, ¤tlabel
) != 0) {
9127 (void) fprintf(stderr
,
9128 gettext("tar: can't get label for "
9129 " %s, getlabel() error: %s\n"),
9130 filename
, strerror(errno
));
9132 } else if ((blequal(¤tlabel
, &bs_label
)) == 0) {
9133 char *src_label
= NULL
; /* ascii label */
9135 /* get current src SL */
9136 if (bsltos(&bs_label
, &src_label
, 0, 0) <= 0) {
9137 (void) fprintf(stderr
,
9138 gettext("tar: can't interpret requested label for"
9139 " %s\n"), filename
);
9141 (void) fprintf(stderr
,
9142 gettext("tar: can't apply label %s to %s\n"),
9143 src_label
, filename
);
9146 (void) fprintf(stderr
,
9147 gettext("tar: %s not restored\n"), filename
);
9152 } /* end check_ext_attr */
9154 /* Compressing a tar file using compression method provided in 'opt' */
9165 (void) fprintf(vfile
,
9166 gettext("Compressing '%s' with '%s'...\n"),
9167 usefile
, compress_opt
);
9169 if ((pid
= fork()) == 0) {
9170 (void) execlp(compress_opt
, compress_opt
,
9172 } else if (pid
== -1) {
9173 vperror(1, "%s", gettext("Could not fork"));
9177 (void) rename(tfname
, usefile
);
9181 /* The magic numbers from /etc/magic */
9183 #define GZIP_MAGIC "\037\213"
9184 #define BZIP_MAGIC "BZh"
9185 #define COMP_MAGIC "\037\235"
9194 if ((fp
= fopen(usefile
, "r")) != NULL
) {
9195 (void) fread(buf
, sizeof (char), 6, fp
);
9201 if (memcmp(magic
, GZIP_MAGIC
, 2) == 0) {
9202 if (xflag
|| tflag
) {
9203 compress_opt
= compress_malloc(strlen(GZCAT
) + 1);
9204 (void) strcpy(compress_opt
, GZCAT
);
9205 } else if (uflag
|| rflag
) {
9206 compress_opt
= compress_malloc(strlen(GZIP
) + 1);
9207 (void) strcpy(compress_opt
, GZIP
);
9209 } else if (memcmp(magic
, BZIP_MAGIC
, 2) == 0) {
9210 if (xflag
|| tflag
) {
9211 compress_opt
= compress_malloc(strlen(BZCAT
) + 1);
9212 (void) strcpy(compress_opt
, BZCAT
);
9213 } else if (uflag
|| rflag
) {
9214 compress_opt
= compress_malloc(strlen(BZIP
) + 1);
9215 (void) strcpy(compress_opt
, BZIP
);
9217 } else if (memcmp(magic
, COMP_MAGIC
, 2) == 0) {
9218 if (xflag
|| tflag
) {
9219 compress_opt
= compress_malloc(strlen(ZCAT
) + 1);
9220 (void) strcpy(compress_opt
, ZCAT
);
9221 } else if (uflag
|| rflag
) {
9222 compress_opt
= compress_malloc(strlen(COMPRESS
) + 1);
9223 (void) strcpy(compress_opt
, COMPRESS
);
9231 (void) strcpy(tfname
, usefile
);
9232 if (strcmp(compress_opt
, GZIP
) == 0) {
9233 if ((suffix
= gz_suffix()) == NULL
) {
9234 strlcat(tfname
, gsuffix
[0], sizeof (tfname
));
9235 return (gsuffix
[0]);
9237 } else if (strcmp(compress_opt
, COMPRESS
) == 0) {
9238 if ((suffix
= gz_suffix()) == NULL
) {
9239 strlcat(tfname
, gsuffix
[6], sizeof (tfname
));
9240 return (gsuffix
[6]);
9242 } else if (strcmp(compress_opt
, BZIP
) == 0) {
9243 if ((suffix
= bz_suffix()) == NULL
) {
9244 strlcat(tfname
, bsuffix
[0], sizeof (tfname
));
9245 return (bsuffix
[0]);
9251 /* Decompressing a tar file using compression method from the file type */
9253 decompress_file(void)
9257 char cmdstr
[PATH_MAX
];
9258 char fname
[PATH_MAX
];
9262 added_suffix
= add_suffix();
9263 if (added_suffix
!= NULL
) {
9264 (void) rename(usefile
, tfname
);
9266 if ((pid
= fork()) == 0) {
9268 (void) fprintf(vfile
,
9269 gettext("Decompressing '%s' with "
9270 "'%s'...\n"), usefile
, compress_opt
);
9272 (void) execlp(compress_opt
, compress_opt
, "-df",
9274 (void) fprintf(vfile
, gettext("Could not exec %s: %s\n"),
9275 compress_opt
, usefile
, strerror(errno
));
9276 } else if (pid
== -1) {
9277 vperror(1, "Could not fork");
9280 if (suffix
!= NULL
) {
9281 /* restore the file name - original file was without suffix */
9282 *(usefile
+ strlen(usefile
) - strlen(suffix
)) = '\0';
9286 /* Set the archive for writing and then compress the archive */
9294 (void) fprintf(vfile
, gettext("Compressing '%s' with "
9295 "'%s'...\n"), usefile
, compress_opt
);
9299 vperror(1, gettext("Could not create pipe"));
9301 if (pid
= fork() > 0) {
9303 (void) close(fd
[0]);
9307 (void) dup2(fd
[0], STDIN_FILENO
);
9308 (void) close(fd
[1]);
9309 (void) dup2(mt
, STDOUT_FILENO
);
9310 (void) execlp(compress_opt
, compress_opt
, NULL
);
9311 vperror(1, "%s", gettext("Could not exec %s"), compress_opt
);
9312 return (0); /*NOTREACHED*/
9316 uncompress_file(void)
9322 (void) fprintf(vfile
, gettext("Decompressing '%s' with "
9323 "'%s'...\n"), usefile
, compress_opt
);
9327 vperror(1, gettext("Could not create pipe"));
9329 if (pid
= fork() > 0) {
9331 (void) close(fd
[1]);
9335 (void) dup2(fd
[1], STDOUT_FILENO
);
9336 (void) close(fd
[0]);
9337 (void) dup2(mt
, STDIN_FILENO
);
9338 (void) execlp(compress_opt
, compress_opt
, NULL
);
9339 vperror(1, "%s", gettext("Could not exec %s"), compress_opt
);
9340 return (0); /*NOTREACHED*/
9343 /* Checking valid 'bzip2' suffix */
9349 int nlen
= strlen(usefile
);
9351 for (i
= 0; i
< BS
; i
++) {
9352 slen
= strlen(bsuffix
[i
]);
9355 if (strcmp(usefile
+ nlen
- slen
, bsuffix
[i
]) == 0)
9356 return (bsuffix
[i
]);
9361 /* Checking valid 'gzip' suffix */
9367 int nlen
= strlen(usefile
);
9369 for (i
= 0; i
< GS
; i
++) {
9370 slen
= strlen(gsuffix
[i
]);
9373 if (strcmp(usefile
+ nlen
- slen
, gsuffix
[i
]) == 0)
9374 return (gsuffix
[i
]);
9380 compress_malloc(size_t size
)
9384 if ((opt
= malloc(size
)) == NULL
) {
9386 gettext("Could not allocate compress buffer\n"));
9396 while (waitpid(pid
, &status
, 0) == -1 && errno
== EINTR
)