8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / tar / tar.c
blob7b15c3c2b23c2d0de898a3ea83ef9986eb9659b4
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 * Copyright 2015 Joyent, Inc.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
31 /* Copyright (c) 1987, 1988 Microsoft Corporation */
32 /* All Rights Reserved */
35 * Portions of this source code were derived from Berkeley 4.3 BSD
36 * under license from the Regents of the University of California.
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/stat.h>
43 #include <sys/mkdev.h>
44 #include <sys/wait.h>
45 #include <dirent.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <signal.h>
49 #include <ctype.h>
50 #include <locale.h>
51 #include <nl_types.h>
52 #include <langinfo.h>
53 #include <pwd.h>
54 #include <grp.h>
55 #include <fcntl.h>
56 #include <string.h>
57 #include <malloc.h>
58 #include <time.h>
59 #include <utime.h>
60 #include <stdlib.h>
61 #include <stdarg.h>
62 #include <widec.h>
63 #include <sys/mtio.h>
64 #include <sys/acl.h>
65 #include <strings.h>
66 #include <deflt.h>
67 #include <limits.h>
68 #include <iconv.h>
69 #include <assert.h>
70 #include <libgen.h>
71 #include <libintl.h>
72 #include <aclutils.h>
73 #include <libnvpair.h>
74 #include <archives.h>
76 #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
77 extern int defcntl();
78 #endif
79 #if defined(_PC_SATTR_ENABLED)
80 #include <attr.h>
81 #include <libcmdutils.h>
82 #endif
84 /* Trusted Extensions */
85 #include <zone.h>
86 #include <tsol/label.h>
87 #include <sys/tsol/label_macro.h>
89 #include "getresponse.h"
91 * Source compatibility
95 * These constants come from archives.h and sys/fcntl.h
96 * and were introduced by the extended attributes project
97 * in Solaris 9.
99 #if !defined(O_XATTR)
100 #define AT_SYMLINK_NOFOLLOW 0x1000
101 #define AT_REMOVEDIR 0x1
102 #define AT_FDCWD 0xffd19553
103 #define _XATTR_HDRTYPE 'E'
104 static int attropen();
105 static int fstatat();
106 static int renameat();
107 static int unlinkat();
108 static int openat();
109 static int fchownat();
110 static int futimesat();
111 #endif
114 * Compiling with -D_XPG4_2 gets this but produces other problems, so
115 * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
116 * explicitly doing the declaration here.
118 int utimes(const char *path, const struct timeval timeval_ptr[]);
120 #ifndef MINSIZE
121 #define MINSIZE 250
122 #endif
123 #define DEF_FILE "/etc/default/tar"
125 #define min(a, b) ((a) < (b) ? (a) : (b))
126 #define max(a, b) ((a) > (b) ? (a) : (b))
128 #define TBLOCK 512 /* tape block size--should be universal */
130 #ifdef BSIZE
131 #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
132 #else /* BSIZE */
133 #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
134 #endif /* BSIZE */
136 #define NBLOCK 20
137 #define NAMSIZ 100
138 #define PRESIZ 155
139 #define MAXNAM 256
140 #define MODEMASK 0777777 /* file creation mode mask */
141 #define POSIXMODES 07777 /* mask for POSIX mode bits */
142 #define MAXEXT 9 /* reasonable max # extents for a file */
143 #define EXTMIN 50 /* min blks left on floppy to split a file */
145 /* max value dblock.dbuf.efsize can store */
146 #define TAR_EFSIZE_MAX 0777777777
149 * Symbols which specify the values at which the use of the 'E' function
150 * modifier is required to properly store a file.
152 * TAR_OFFSET_MAX - the largest file size we can archive
153 * OCTAL7CHAR - the limit for ustar gid, uid, dev
156 #ifdef XHDR_DEBUG
157 /* tiny values which force the creation of extended header entries */
158 #define TAR_OFFSET_MAX 9
159 #define OCTAL7CHAR 2
160 #else
161 /* normal values */
162 #define TAR_OFFSET_MAX 077777777777ULL
163 #define OCTAL7CHAR 07777777
164 #endif
166 #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
167 #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
169 #define MAXLEV (PATH_MAX / 2)
170 #define LEV0 1
171 #define SYMLINK_LEV0 0
173 #define TRUE 1
174 #define FALSE 0
176 #define XATTR_FILE 1
177 #define NORMAL_FILE 0
179 #define PUT_AS_LINK 1
180 #define PUT_NOTAS_LINK 0
182 #ifndef VIEW_READONLY
183 #define VIEW_READONLY "SUNWattr_ro"
184 #endif
186 #ifndef VIEW_READWRITE
187 #define VIEW_READWRITE "SUNWattr_rw"
188 #endif
190 #if _FILE_OFFSET_BITS == 64
191 #define FMT_off_t "lld"
192 #define FMT_off_t_o "llo"
193 #define FMT_blkcnt_t "lld"
194 #else
195 #define FMT_off_t "ld"
196 #define FMT_off_t_o "lo"
197 #define FMT_blkcnt_t "ld"
198 #endif
200 /* ACL support */
202 static
203 struct sec_attr {
204 char attr_type;
205 char attr_len[7];
206 char attr_info[1];
207 } *attr;
209 #if defined(O_XATTR)
210 typedef enum {
211 ATTR_OK,
212 ATTR_SKIP,
213 ATTR_CHDIR_ERR,
214 ATTR_OPEN_ERR,
215 ATTR_XATTR_ERR,
216 ATTR_SATTR_ERR
217 } attr_status_t;
218 #endif
220 #if defined(O_XATTR)
221 typedef enum {
222 ARC_CREATE,
223 ARC_RESTORE
224 } arc_action_t;
225 #endif
227 typedef struct attr_data {
228 char *attr_parent;
229 char *attr_path;
230 int attr_parentfd;
231 int attr_rw_sysattr;
232 } attr_data_t;
236 * Tar has been changed to support extended attributes.
238 * As part of this change tar now uses the new *at() syscalls
239 * such as openat, fchownat(), unlinkat()...
241 * This was done so that attributes can be handled with as few code changes
242 * as possible.
244 * What this means is that tar now opens the directory that a file or directory
245 * resides in and then performs *at() functions to manipulate the entry.
247 * For example a new file is now created like this:
249 * dfd = open(<some dir path>)
250 * fd = openat(dfd, <name>,....);
252 * or in the case of an extended attribute
254 * dfd = attropen(<pathname>, ".", ....)
256 * Once we have a directory file descriptor all of the *at() functions can
257 * be applied to it.
259 * unlinkat(dfd, <component name>,...)
260 * fchownat(dfd, <component name>,..)
262 * This works for both normal namespace files and extended attribute file
268 * Extended attribute Format
270 * Extended attributes are stored in two pieces.
271 * 1. An attribute header which has information about
272 * what file the attribute is for and what the attribute
273 * is named.
274 * 2. The attribute record itself. Stored as a normal file type
275 * of entry.
276 * Both the header and attribute record have special modes/typeflags
277 * associated with them.
279 * The names of the header in the archive look like:
280 * /dev/null/attr.hdr
282 * The name of the attribute looks like:
283 * /dev/null/attr
285 * This is done so that an archiver that doesn't understand these formats
286 * can just dispose of the attribute records.
288 * The format is composed of a fixed size header followed
289 * by a variable sized xattr_buf. If the attribute is a hard link
290 * to another attribute then another xattr_buf section is included
291 * for the link.
293 * The xattr_buf is used to define the necessary "pathing" steps
294 * to get to the extended attribute. This is necessary to support
295 * a fully recursive attribute model where an attribute may itself
296 * have an attribute.
298 * The basic layout looks like this.
300 * --------------------------------
301 * | |
302 * | xattr_hdr |
303 * | |
304 * --------------------------------
305 * --------------------------------
306 * | |
307 * | xattr_buf |
308 * | |
309 * --------------------------------
310 * --------------------------------
311 * | |
312 * | (optional link info) |
313 * | |
314 * --------------------------------
315 * --------------------------------
316 * | |
317 * | attribute itself |
318 * | stored as normal tar |
319 * | or cpio data with |
320 * | special mode or |
321 * | typeflag |
322 * | |
323 * --------------------------------
328 * xattrhead is a pointer to the xattr_hdr
330 * xattrp is a pointer to the xattr_buf structure
331 * which contains the "pathing" steps to get to attributes
333 * xattr_linkp is a pointer to another xattr_buf structure that is
334 * only used when an attribute is actually linked to another attribute
338 static struct xattr_hdr *xattrhead;
339 static struct xattr_buf *xattrp;
340 static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
341 static char *xattrapath; /* attribute name */
342 static char *xattr_linkaname; /* attribute attribute is linked to */
343 static char Hiddendir; /* are we processing hidden xattr dir */
344 static char xattrbadhead;
346 /* Was statically allocated tbuf[NBLOCK] */
347 static
348 union hblock {
349 char dummy[TBLOCK];
350 struct header {
351 char name[NAMSIZ]; /* If non-null prefix, path is */
352 /* <prefix>/<name>; otherwise */
353 /* <name> */
354 char mode[8];
355 char uid[8];
356 char gid[8];
357 char size[12]; /* size of this extent if file split */
358 char mtime[12];
359 char chksum[8];
360 char typeflag;
361 char linkname[NAMSIZ];
362 char magic[6];
363 char version[2];
364 char uname[32];
365 char gname[32];
366 char devmajor[8];
367 char devminor[8];
368 char prefix[PRESIZ]; /* Together with "name", the path of */
369 /* the file: <prefix>/<name> */
370 char extno; /* extent #, null if not split */
371 char extotal; /* total extents */
372 char efsize[10]; /* size of entire file */
373 } dbuf;
374 } dblock, *tbuf, xhdr_buf;
376 static
377 struct xtar_hdr {
378 uid_t x_uid, /* Uid of file */
379 x_gid; /* Gid of file */
380 major_t x_devmajor; /* Device major node */
381 minor_t x_devminor; /* Device minor node */
382 off_t x_filesz; /* Length of file */
383 char *x_uname, /* Pointer to name of user */
384 *x_gname, /* Pointer to gid of user */
385 *x_linkpath, /* Path for a hard/symbolic link */
386 *x_path; /* Path of file */
387 timestruc_t x_mtime; /* Seconds and nanoseconds */
388 } Xtarhdr;
390 static
391 struct gen_hdr {
392 ulong_t g_mode; /* Mode of file */
393 uid_t g_uid, /* Uid of file */
394 g_gid; /* Gid of file */
395 off_t g_filesz; /* Length of file */
396 time_t g_mtime; /* Modification time */
397 uint_t g_cksum; /* Checksum of file */
398 ulong_t g_devmajor, /* File system of file */
399 g_devminor; /* Major/minor of special files */
400 } Gen;
402 static
403 struct linkbuf {
404 ino_t inum;
405 dev_t devnum;
406 int count;
407 char pathname[MAXNAM+1]; /* added 1 for last NULL */
408 char attrname[MAXNAM+1];
409 struct linkbuf *nextp;
410 } *ihead;
412 /* see comments before build_table() */
413 #define TABLE_SIZE 512
414 typedef struct file_list {
415 char *name; /* Name of file to {in,ex}clude */
416 struct file_list *next; /* Linked list */
417 } file_list_t;
418 static file_list_t *exclude_tbl[TABLE_SIZE],
419 *include_tbl[TABLE_SIZE];
421 static int append_secattr(char **, int *, int, char *, char);
422 static void write_ancillary(union hblock *, char *, int, char);
424 static void add_file_to_table(file_list_t *table[], char *str);
425 static void assert_string(char *s, char *msg);
426 static int istape(int fd, int type);
427 static void backtape(void);
428 static void build_table(file_list_t *table[], char *file);
429 static int check_prefix(char **namep, char **dirp, char **compp);
430 static void closevol(void);
431 static void copy(void *dst, void *src);
432 static int convtoreg(off_t);
433 static void delete_target(int fd, char *comp, char *namep);
434 static void doDirTimes(char *name, timestruc_t modTime);
435 static void done(int n);
436 static void dorep(char *argv[]);
437 static void dotable(char *argv[]);
438 static void doxtract(char *argv[]);
439 static int tar_chdir(const char *path);
440 static int is_directory(char *name);
441 static int has_dot_dot(char *name);
442 static int is_absolute(char *name);
443 static char *make_relative_name(char *name, char **stripped_prefix);
444 static void fatal(char *format, ...);
445 static void vperror(int exit_status, char *fmt, ...);
446 static void flushtape(void);
447 static void getdir(void);
448 static void *getmem(size_t);
449 static void longt(struct stat *st, char aclchar);
450 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
451 static int makeDir(char *name);
452 static void mterr(char *operation, int i, int exitcode);
453 static void newvol(void);
454 static void passtape(void);
455 static void putempty(blkcnt_t n);
456 static int putfile(char *longname, char *shortname, char *parent,
457 attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
458 static void readtape(char *buffer);
459 static void seekdisk(blkcnt_t blocks);
460 static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
461 static void setbytes_to_skip(struct stat *st, int err);
462 static void splitfile(char *longname, int ifd, char *name,
463 char *prefix, int filetype);
464 static void tomodes(struct stat *sp);
465 static void usage(void);
466 static int xblocks(int issysattr, off_t bytes, int ofile);
467 static int xsfile(int issysattr, int ofd);
468 static void resugname(int dirfd, char *name, int symflag);
469 static int bcheck(char *bstr);
470 static int checkdir(char *name);
471 static int checksum(union hblock *dblockp);
472 #ifdef EUC
473 static int checksum_signed(union hblock *dblockp);
474 #endif /* EUC */
475 static int checkupdate(char *arg);
476 static int checkw(char c, char *name);
477 static int cmp(char *b, char *s, int n);
478 static int defset(char *arch);
479 static boolean_t endtape(void);
480 static int is_in_table(file_list_t *table[], char *str);
481 static int notsame(void);
482 static int is_prefix(char *s1, char *s2);
483 static int response(void);
484 static int build_dblock(const char *, const char *, const char,
485 const int filetype, const struct stat *, const dev_t, const char *);
486 static unsigned int hash(char *str);
488 static blkcnt_t kcheck(char *kstr);
489 static off_t bsrch(char *s, int n, off_t l, off_t h);
490 static void onintr(int sig);
491 static void onquit(int sig);
492 static void onhup(int sig);
493 static uid_t getuidbyname(char *);
494 static gid_t getgidbyname(char *);
495 static char *getname(gid_t);
496 static char *getgroup(gid_t);
497 static int checkf(char *name, int mode, int howmuch);
498 static int writetbuf(char *buffer, int n);
499 static int wantit(char *argv[], char **namep, char **dirp, char **comp,
500 attr_data_t **attrinfo);
501 static void append_ext_attr(char *shortname, char **secinfo, int *len);
502 static int get_xdata(void);
503 static void gen_num(const char *keyword, const u_longlong_t number);
504 static void gen_date(const char *keyword, const timestruc_t time_value);
505 static void gen_string(const char *keyword, const char *value);
506 static void get_xtime(char *value, timestruc_t *xtime);
507 static int chk_path_build(char *name, char *longname, char *linkname,
508 char *prefix, char type, int filetype);
509 static int gen_utf8_names(const char *filename);
510 static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
511 const char *src, int max_val);
512 static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
513 iconv_t iconv_cd, int xhdrflg, int max_val);
514 static int c_utf8(char *target, const char *source);
515 static int getstat(int dirfd, char *longname, char *shortname,
516 char *attrparent);
517 static void xattrs_put(char *, char *, char *, char *);
518 static void prepare_xattr(char **, char *, char *,
519 char, struct linkbuf *, int *);
520 static int put_link(char *name, char *longname, char *component,
521 char *longattrname, char *prefix, int filetype, char typeflag);
522 static int put_extra_attributes(char *longname, char *shortname,
523 char *longattrname, char *prefix, int filetype, char typeflag);
524 static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
525 char *prefix, int typeflag, int filetype, struct linkbuf *lp);
526 static int read_xattr_hdr(attr_data_t **attrinfo);
528 /* Trusted Extensions */
529 #define AUTO_ZONE "/zone"
531 static void extract_attr(char **file_ptr, struct sec_attr *);
532 static int check_ext_attr(char *filename);
533 static void rebuild_comp_path(char *str, char **namep);
534 static int rebuild_lk_comp_path(char *str, char **namep);
536 static void get_parent(char *path, char *dir);
537 static char *get_component(char *path);
538 static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
539 char *name, int oflag, mode_t mode);
540 static char *skipslashes(char *string, char *start);
541 static void chop_endslashes(char *path);
542 static pid_t compress_file(void);
543 static void compress_back(void);
544 static void decompress_file(void);
545 static pid_t uncompress_file(void);
546 static void *compress_malloc(size_t);
547 static void check_compression(void);
548 static char *bz_suffix(void);
549 static char *gz_suffix(void);
550 static char *xz_suffix(void);
551 static char *add_suffix();
552 static void wait_pid(pid_t);
553 static void verify_compress_opt(const char *t);
554 static void detect_compress(void);
555 static void dlog(const char *, ...);
556 static boolean_t should_enable_debug(void);
558 static struct stat stbuf;
560 static char *myname;
561 static char *xtract_chdir = NULL;
562 static int checkflag = 0;
563 static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
564 static int rflag, xflag, vflag, tflag, mt, cflag, mflag, pflag;
565 static int uflag;
566 static int errflag;
567 static int oflag;
568 static int bflag, Aflag;
569 static int Pflag; /* POSIX conformant archive */
570 static int Eflag; /* Allow files greater than 8GB */
571 static int atflag; /* traverse extended attributes */
572 static int saflag; /* traverse extended sys attributes */
573 static int Dflag; /* Data change flag */
574 static int jflag; /* flag to use 'bzip2' */
575 static int zflag; /* flag to use 'gzip' */
576 static int Zflag; /* flag to use 'compress' */
577 static int Jflag; /* flag to use 'xz' */
578 static int aflag; /* flag to use autocompression */
580 /* Trusted Extensions */
581 static int Tflag; /* Trusted Extensions attr flags */
582 static int dir_flag; /* for attribute extract */
583 static int mld_flag; /* for attribute extract */
584 static char *orig_namep; /* original namep - unadorned */
585 static int rpath_flag; /* MLD real path is rebuilt */
586 static char real_path[MAXPATHLEN]; /* MLD real path */
587 static int lk_rpath_flag; /* linked to real path is rebuilt */
588 static char lk_real_path[MAXPATHLEN]; /* linked real path */
589 static bslabel_t bs_label; /* for attribute extract */
590 static bslabel_t admin_low;
591 static bslabel_t admin_high;
592 static int ignored_aprivs = 0;
593 static int ignored_fprivs = 0;
594 static int ignored_fattrs = 0;
596 static int term, chksum, wflag,
597 first = TRUE, defaults_used = FALSE, linkerrok;
598 static blkcnt_t recno;
599 static int freemem = 1;
600 static int nblock = NBLOCK;
601 static int Errflg = 0;
602 static int exitflag = 0;
604 static dev_t mt_dev; /* device containing output file */
605 static ino_t mt_ino; /* inode number of output file */
606 static int mt_devtype; /* dev type of archive, from stat structure */
608 static int update = 1; /* for `open' call */
610 static off_t low;
611 static off_t high;
613 static FILE *tfile;
614 static FILE *vfile = stdout;
615 static char *tmpdir;
616 static char *tmp_suffix = "/tarXXXXXX";
617 static char *tname;
618 static char archive[] = "archive0=";
619 static char *Xfile;
620 static char *usefile;
621 static char tfname[1024];
623 static int mulvol; /* multi-volume option selected */
624 static blkcnt_t blocklim; /* number of blocks to accept per volume */
625 static blkcnt_t tapepos; /* current block number to be written */
626 static int NotTape; /* true if tape is a disk */
627 static int dumping; /* true if writing a tape or other archive */
628 static int extno; /* number of extent: starts at 1 */
629 static int extotal; /* total extents in this file */
630 static off_t extsize; /* size of current extent during extraction */
631 static ushort_t Oumask = 0; /* old umask value */
632 static boolean_t is_posix; /* true if archive is POSIX-conformant */
633 static const char *magic_type = "ustar";
634 static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */
635 static char *xrec_ptr;
636 static off_t xrec_offset = 0;
637 static int Xhdrflag;
638 static int charset_type = 0;
640 static u_longlong_t xhdr_flgs; /* Bits set determine which items */
641 /* need to be in extended header. */
642 static pid_t comp_pid = 0;
644 static boolean_t debug_output = B_FALSE;
646 #define _X_DEVMAJOR 0x1
647 #define _X_DEVMINOR 0x2
648 #define _X_GID 0x4
649 #define _X_GNAME 0x8
650 #define _X_LINKPATH 0x10
651 #define _X_PATH 0x20
652 #define _X_SIZE 0x40
653 #define _X_UID 0x80
654 #define _X_UNAME 0x100
655 #define _X_ATIME 0x200
656 #define _X_CTIME 0x400
657 #define _X_MTIME 0x800
658 #define _X_XHDR 0x1000 /* Bit flag that determines whether 'X' */
659 /* typeflag was followed by 'A' or non 'A' */
660 /* typeflag. */
661 #define _X_LAST 0x40000000
663 #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4)
664 #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4)
665 #define LONG_MAX_DIGITS (10 * sizeof (long) / 4)
666 #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4)
668 * UTF_8 encoding requires more space than the current codeset equivalent.
669 * Currently a factor of 2-3 would suffice, but it is possible for a factor
670 * of 6 to be needed in the future, so for saftey, we use that here.
672 #define UTF_8_FACTOR 6
674 static u_longlong_t xhdr_count = 0;
675 static char xhdr_dirname[PRESIZ + 1];
676 static char pidchars[PID_MAX_DIGITS + 1];
677 static char *tchar = ""; /* null linkpath */
679 static char local_path[UTF_8_FACTOR * PATH_MAX + 1];
680 static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
681 static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
682 static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
685 * The following mechanism is provided to allow us to debug tar in complicated
686 * situations, like when it is part of a pipe. The idea is that you compile
687 * with -DWAITAROUND defined, and then add the 'D' function modifier to the
688 * target tar invocation, eg. "tar cDf tarfile file". If stderr is available,
689 * it will tell you to which pid to attach the debugger; otherwise, use ps to
690 * find it. Attach to the process from the debugger, and, *PRESTO*, you are
691 * there!
693 * Simply assign "waitaround = 0" once you attach to the process, and then
694 * proceed from there as usual.
697 #ifdef WAITAROUND
698 int waitaround = 0; /* wait for rendezvous with the debugger */
699 #endif
701 #define BZIP "/usr/bin/bzip2"
702 #define GZIP "/usr/bin/gzip"
703 #define COMPRESS "/usr/bin/compress"
704 #define XZ "/usr/bin/xz"
705 #define BZCAT "/usr/bin/bzcat"
706 #define GZCAT "/usr/bin/gzcat"
707 #define ZCAT "/usr/bin/zcat"
708 #define XZCAT "/usr/bin/xzcat"
709 #define GSUF 8 /* number of valid 'gzip' sufixes */
710 #define BSUF 4 /* number of valid 'bzip2' sufixes */
711 #define XSUF 1 /* number of valid 'xz' suffixes */
713 static char *compress_opt; /* compression type */
715 static char *gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
716 ".tgz", ".taz"};
717 static char *bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
718 static char *xsuffix[] = {".xz"};
719 static char *suffix;
723 main(int argc, char *argv[])
725 char *cp;
726 char *tmpdirp;
727 pid_t thispid;
729 (void) setlocale(LC_ALL, "");
730 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
731 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
732 #endif
733 (void) textdomain(TEXT_DOMAIN);
734 if (argc < 2)
735 usage();
737 debug_output = should_enable_debug();
739 tfile = NULL;
740 if ((myname = strdup(argv[0])) == NULL) {
741 (void) fprintf(stderr, gettext(
742 "tar: cannot allocate program name\n"));
743 exit(1);
746 if (init_yes() < 0) {
747 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
748 strerror(errno));
749 exit(2);
753 * For XPG4 compatibility, we must be able to accept the "--"
754 * argument normally recognized by getopt; it is used to delimit
755 * the end opt the options section, and so can only appear in
756 * the position of the first argument. We simply skip it.
759 if (strcmp(argv[1], "--") == 0) {
760 argv++;
761 argc--;
762 if (argc < 3)
763 usage();
766 argv[argc] = NULL;
767 argv++;
770 * Set up default values.
771 * Search the operand string looking for the first digit or an 'f'.
772 * If you find a digit, use the 'archive#' entry in DEF_FILE.
773 * If 'f' is given, bypass looking in DEF_FILE altogether.
774 * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
776 if ((usefile = getenv("TAPE")) == (char *)NULL) {
777 for (cp = *argv; *cp; ++cp)
778 if (isdigit(*cp) || *cp == 'f')
779 break;
780 if (*cp != 'f') {
781 archive[7] = (*cp)? *cp: '0';
782 if (!(defaults_used = defset(archive))) {
783 usefile = NULL;
784 nblock = 1;
785 blocklim = 0;
786 NotTape = 0;
791 for (cp = *argv++; *cp; cp++)
792 switch (*cp) {
793 #ifdef WAITAROUND
794 case 'D':
795 /* rendezvous with the debugger */
796 waitaround = 1;
797 break;
798 #endif
799 case 'f':
800 assert_string(*argv, gettext(
801 "tar: tarfile must be specified with 'f' "
802 "function modifier\n"));
803 usefile = *argv++;
804 break;
805 case 'F':
806 Fflag++;
807 break;
808 case 'c':
809 cflag++;
810 rflag++;
811 update = 1;
812 break;
813 #if defined(O_XATTR)
814 case '@':
815 atflag++;
816 break;
817 #endif /* O_XATTR */
818 #if defined(_PC_SATTR_ENABLED)
819 case '/':
820 saflag++;
821 break;
822 #endif /* _PC_SATTR_ENABLED */
823 case 'u':
824 uflag++; /* moved code after signals caught */
825 rflag++;
826 update = 2;
827 break;
828 case 'r':
829 rflag++;
830 update = 2;
831 break;
832 case 'v':
833 vflag++;
834 break;
835 case 'w':
836 wflag++;
837 break;
838 case 'x':
839 xflag++;
840 break;
841 case 'X':
842 assert_string(*argv, gettext(
843 "tar: exclude file must be specified with 'X' "
844 "function modifier\n"));
845 Xflag = 1;
846 Xfile = *argv++;
847 build_table(exclude_tbl, Xfile);
848 break;
849 case 't':
850 tflag++;
851 break;
852 case 'm':
853 mflag++;
854 break;
855 case 'p':
856 pflag++;
857 break;
858 case 'D':
859 Dflag++;
860 break;
861 case '-':
862 /* ignore this silently */
863 break;
864 case '0': /* numeric entries used only for defaults */
865 case '1':
866 case '2':
867 case '3':
868 case '4':
869 case '5':
870 case '6':
871 case '7':
872 break;
873 case 'b':
874 assert_string(*argv, gettext(
875 "tar: blocking factor must be specified "
876 "with 'b' function modifier\n"));
877 bflag++;
878 nblock = bcheck(*argv++);
879 break;
880 case 'n': /* not a magtape (instead of 'k') */
881 NotTape++; /* assume non-magtape */
882 break;
883 case 'l':
884 linkerrok++;
885 break;
886 case 'e':
887 errflag++;
888 break;
889 case 'o':
890 oflag++;
891 break;
892 case 'h':
893 hflag++;
894 break;
895 case 'i':
896 iflag++;
897 break;
898 case 'B':
899 Bflag++;
900 break;
901 case 'P':
902 Pflag++;
903 break;
904 case 'E':
905 Eflag++;
906 Pflag++; /* Only POSIX archive made */
907 break;
908 case 'T':
909 Tflag++; /* Handle Trusted Extensions attrs */
910 pflag++; /* also set flag for ACL */
911 break;
912 case 'j': /* compession "bzip2" */
913 jflag = 1;
914 break;
915 case 'z': /* compression "gzip" */
916 zflag = 1;
917 break;
918 case 'Z': /* compression "compress" */
919 Zflag = 1;
920 break;
921 case 'J': /* compression "xz" */
922 Jflag = 1;
923 break;
924 case 'a':
925 aflag = 1; /* autocompression */
926 break;
927 default:
928 (void) fprintf(stderr, gettext(
929 "tar: %c: unknown function modifier\n"), *cp);
930 usage();
933 if (!rflag && !xflag && !tflag)
934 usage();
935 if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
936 (void) fprintf(stderr, gettext(
937 "tar: specify only one of [ctxru].\n"));
938 usage();
940 if (cflag) {
941 if ((jflag + zflag + Zflag + Jflag + aflag) > 1) {
942 (void) fprintf(stderr, gettext(
943 "tar: specify only one of [ajJzZ] to "
944 "create a compressed file.\n"));
945 usage();
948 /* Trusted Extensions attribute handling */
949 if (Tflag && ((getzoneid() != GLOBAL_ZONEID) ||
950 !is_system_labeled())) {
951 (void) fprintf(stderr, gettext(
952 "tar: the 'T' option is only available with "
953 "Trusted Extensions\nand must be run from "
954 "the global zone.\n"));
955 usage();
957 if (cflag && *argv == NULL)
958 fatal(gettext("Missing filenames"));
959 if (usefile == NULL)
960 fatal(gettext("device argument required"));
962 /* alloc a buffer of the right size */
963 if ((tbuf = (union hblock *)
964 calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
965 (union hblock *)NULL) {
966 (void) fprintf(stderr, gettext(
967 "tar: cannot allocate physio buffer\n"));
968 exit(1);
971 if ((xrec_ptr = malloc(xrec_size)) == NULL) {
972 (void) fprintf(stderr, gettext(
973 "tar: cannot allocate extended header buffer\n"));
974 exit(1);
977 #ifdef WAITAROUND
978 if (waitaround) {
979 (void) fprintf(stderr, gettext("Rendezvous with tar on pid"
980 " %d\n"), getpid());
982 while (waitaround) {
983 (void) sleep(10);
986 #endif
988 thispid = getpid();
989 (void) sprintf(pidchars, "%ld", thispid);
990 thispid = strlen(pidchars);
992 if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL)
993 (void) strcpy(xhdr_dirname, "/tmp");
994 else {
996 * Make sure that dir is no longer than what can
997 * fit in the prefix part of the header.
999 if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
1000 (void) strcpy(xhdr_dirname, "/tmp");
1001 if ((vflag > 0) && (Eflag > 0))
1002 (void) fprintf(stderr, gettext(
1003 "Ignoring TMPDIR\n"));
1004 } else
1005 (void) strcpy(xhdr_dirname, tmpdirp);
1007 (void) strcat(xhdr_dirname, "/PaxHeaders.");
1008 (void) strcat(xhdr_dirname, pidchars);
1010 if (rflag) {
1011 if (cflag && usefile != NULL) {
1012 /* Set the compression type */
1013 if (aflag)
1014 detect_compress();
1016 if (jflag) {
1017 compress_opt = compress_malloc(strlen(BZIP)
1018 + 1);
1019 (void) strcpy(compress_opt, BZIP);
1020 } else if (zflag) {
1021 compress_opt = compress_malloc(strlen(GZIP)
1022 + 1);
1023 (void) strcpy(compress_opt, GZIP);
1024 } else if (Zflag) {
1025 compress_opt =
1026 compress_malloc(strlen(COMPRESS) + 1);
1027 (void) strcpy(compress_opt, COMPRESS);
1028 } else if (Jflag) {
1029 compress_opt = compress_malloc(strlen(XZ) + 1);
1030 (void) strcpy(compress_opt, XZ);
1032 } else {
1034 * Decompress if the file is compressed for
1035 * an update or replace.
1037 if (strcmp(usefile, "-") != 0) {
1038 check_compression();
1039 if (compress_opt != NULL) {
1040 decompress_file();
1045 if (cflag && tfile != NULL)
1046 usage();
1047 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1048 (void) signal(SIGINT, onintr);
1049 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1050 (void) signal(SIGHUP, onhup);
1051 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1052 (void) signal(SIGQUIT, onquit);
1053 if (uflag) {
1054 int tnum;
1055 struct stat sbuf;
1057 tmpdir = getenv("TMPDIR");
1059 * If the name is invalid or this isn't a directory,
1060 * or the directory is not writable, then reset to
1061 * a default temporary directory.
1063 if (tmpdir == NULL || *tmpdir == '\0' ||
1064 (strlen(tmpdir) + strlen(tmp_suffix)) > PATH_MAX) {
1065 tmpdir = "/tmp";
1066 } else if (stat(tmpdir, &sbuf) < 0 ||
1067 (sbuf.st_mode & S_IFMT) != S_IFDIR ||
1068 (sbuf.st_mode & S_IWRITE) == 0) {
1069 tmpdir = "/tmp";
1072 if ((tname = calloc(1, strlen(tmpdir) +
1073 strlen(tmp_suffix) + 1)) == NULL) {
1074 vperror(1, gettext("tar: out of memory, "
1075 "cannot create temporary file\n"));
1077 (void) strcpy(tname, tmpdir);
1078 (void) strcat(tname, tmp_suffix);
1080 if ((tnum = mkstemp(tname)) == -1)
1081 vperror(1, "%s", tname);
1082 if ((tfile = fdopen(tnum, "w")) == NULL)
1083 vperror(1, "%s", tname);
1085 if (strcmp(usefile, "-") == 0) {
1086 if (cflag == 0)
1087 fatal(gettext(
1088 "can only create standard output archives."));
1089 vfile = stderr;
1090 mt = dup(1);
1091 ++bflag;
1092 } else {
1093 if (cflag)
1094 mt = open(usefile,
1095 O_RDWR|O_CREAT|O_TRUNC, 0666);
1096 else
1097 mt = open(usefile, O_RDWR);
1099 if (mt < 0) {
1100 if (cflag == 0 || (mt = creat(usefile, 0666))
1101 < 0)
1102 vperror(1, "%s", usefile);
1105 /* Get inode and device number of output file */
1106 (void) fstat(mt, &stbuf);
1107 mt_ino = stbuf.st_ino;
1108 mt_dev = stbuf.st_dev;
1109 mt_devtype = stbuf.st_mode & S_IFMT;
1110 NotTape = !istape(mt, mt_devtype);
1112 if (rflag && !cflag && (mt_devtype == S_IFIFO))
1113 fatal(gettext("cannot append to pipe or FIFO."));
1115 if (Aflag && vflag)
1116 (void) printf(
1117 gettext("Suppressing absolute pathnames\n"));
1118 if (cflag && compress_opt != NULL)
1119 comp_pid = compress_file();
1120 dorep(argv);
1121 if (rflag && !cflag && (compress_opt != NULL))
1122 compress_back();
1123 } else if (xflag || tflag) {
1125 * for each argument, check to see if there is a "-I file" pair.
1126 * if so, move the 3rd argument into "-I"'s place, build_table()
1127 * using "file"'s name and increment argc one (the second
1128 * increment appears in the for loop) which removes the two
1129 * args "-I" and "file" from the argument vector.
1131 for (argc = 0; argv[argc]; argc++) {
1132 if (strcmp(argv[argc], "-I") == 0) {
1133 if (!argv[argc+1]) {
1134 (void) fprintf(stderr, gettext(
1135 "tar: missing argument for -I flag\n"));
1136 done(2);
1137 } else {
1138 Iflag = 1;
1139 argv[argc] = argv[argc+2];
1140 build_table(include_tbl, argv[++argc]);
1142 } else if (strcmp(argv[argc], "-C") == 0) {
1143 if (!argv[argc+1]) {
1144 (void) fprintf(stderr, gettext("tar: "
1145 "missing argument for -C flag\n"));
1146 done(2);
1147 } else if (xtract_chdir != NULL) {
1148 (void) fprintf(stderr, gettext("tar: "
1149 "extract should have only one -C "
1150 "flag\n"));
1151 done(2);
1152 } else {
1153 argv[argc] = argv[argc+2];
1154 xtract_chdir = argv[++argc];
1158 if (strcmp(usefile, "-") == 0) {
1159 mt = dup(0);
1160 ++bflag;
1161 /* try to recover from short reads when reading stdin */
1162 ++Bflag;
1163 } else if ((mt = open(usefile, 0)) < 0)
1164 vperror(1, "%s", usefile);
1166 /* Decompress if the file is compressed */
1168 if (strcmp(usefile, "-") != 0) {
1169 check_compression();
1170 if (compress_opt != NULL)
1171 comp_pid = uncompress_file();
1173 if (xflag) {
1174 if (xtract_chdir != NULL) {
1175 if (tar_chdir(xtract_chdir) < 0) {
1176 vperror(1, gettext("can't change "
1177 "directories to %s"), xtract_chdir);
1180 if (Aflag && vflag)
1181 (void) printf(gettext(
1182 "Suppressing absolute pathnames.\n"));
1184 doxtract(argv);
1185 } else if (tflag)
1186 dotable(argv);
1188 else
1189 usage();
1191 done(Errflg);
1193 /* Not reached: keep compiler quiet */
1194 return (1);
1197 static boolean_t
1198 should_enable_debug(void)
1200 const char *val;
1201 const char *truth[] = {
1202 "true",
1203 "1",
1204 "yes",
1205 "y",
1206 "please",
1207 NULL
1209 unsigned int i;
1211 if ((val = getenv("DEBUG_TAR")) == NULL) {
1212 return (B_FALSE);
1215 for (i = 0; truth[i] != NULL; i++) {
1216 if (strcmp(val, truth[i]) == 0) {
1217 return (B_TRUE);
1221 return (B_FALSE);
1224 /*PRINTFLIKE1*/
1225 static void
1226 dlog(const char *format, ...)
1228 va_list ap;
1230 if (!debug_output) {
1231 return;
1234 va_start(ap, format);
1235 (void) fprintf(stderr, "tar: DEBUG: ");
1236 (void) vfprintf(stderr, format, ap);
1237 va_end(ap);
1240 static void
1241 usage(void)
1243 (void) fprintf(stderr, gettext(
1244 #if defined(O_XATTR)
1245 #if defined(_PC_SATTR_ENABLED)
1246 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@/[0-7]][bf][X...] "
1247 #else
1248 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@[0-7]][bf][X...] "
1249 #endif /* _PC_SATTR_ENABLED */
1250 #else
1251 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw[0-7]][bf][X...] "
1252 #endif /* O_XATTR */
1253 "[j|J|z|Z] "
1254 "[blocksize] [tarfile] [size] [exclude-file...] "
1255 "{file | -I include-file | -C directory file}...\n"));
1256 done(1);
1260 * dorep - do "replacements"
1262 * Dorep is responsible for creating ('c'), appending ('r')
1263 * and updating ('u');
1266 static void
1267 dorep(char *argv[])
1269 char *cp, *cp2, *p;
1270 char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
1271 char file[PATH_MAX*2], origdir[PATH_MAX+1];
1272 FILE *fp = (FILE *)NULL;
1273 int archtype;
1274 int ret;
1277 if (!cflag) {
1278 xhdr_flgs = 0;
1279 getdir(); /* read header for next file */
1280 if (Xhdrflag > 0) {
1281 if (!Eflag)
1282 fatal(gettext("Archive contains extended"
1283 " header. -E flag required.\n"));
1284 ret = get_xdata(); /* Get extended header items */
1285 /* and regular header */
1286 } else {
1287 if (Eflag)
1288 fatal(gettext("Archive contains no extended"
1289 " header. -E flag not allowed.\n"));
1291 while (!endtape()) { /* changed from a do while */
1292 setbytes_to_skip(&stbuf, ret);
1293 passtape(); /* skip the file data */
1294 if (term)
1295 done(Errflg); /* received signal to stop */
1296 xhdr_flgs = 0;
1297 getdir();
1298 if (Xhdrflag > 0)
1299 ret = get_xdata();
1301 if (ret == 0) {
1302 if ((dblock.dbuf.typeflag != 'A') &&
1303 (xhdr_flgs != 0)) {
1304 load_info_from_xtarhdr(xhdr_flgs,
1305 &Xtarhdr);
1306 xhdr_flgs |= _X_XHDR;
1309 backtape(); /* was called by endtape */
1310 if (tfile != NULL) {
1312 * Buffer size is calculated to be the size of the
1313 * tmpdir string, plus 6 times the size of the tname
1314 * string, plus a value that is known to be greater
1315 * than the command pipeline string.
1317 int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
1318 char *buf;
1320 if ((buf = (char *)calloc(1, buflen)) == NULL) {
1321 vperror(1, gettext("tar: out of memory, "
1322 "cannot create sort command file\n"));
1325 (void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
1326 "sort +0 -1 +1nr %s -o %s; awk '$1 "
1327 "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1328 tmpdir, tname, tname, tname, tname, tname, tname);
1329 (void) fflush(tfile);
1330 (void) system(buf);
1331 free(buf);
1332 (void) freopen(tname, "r", tfile);
1333 (void) fstat(fileno(tfile), &stbuf);
1334 high = stbuf.st_size;
1338 dumping = 1;
1339 if (mulvol) { /* SP-1 */
1340 if (nblock && (blocklim%nblock) != 0)
1341 fatal(gettext(
1342 "Volume size not a multiple of block size."));
1343 blocklim -= 2; /* for trailer records */
1344 if (vflag)
1345 (void) fprintf(vfile, gettext("Volume ends at %"
1346 FMT_blkcnt_t "K, blocking factor = %dK\n"),
1347 K((blocklim - 1)), K(nblock));
1351 * Save the original directory before it gets
1352 * changed.
1354 if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
1355 vperror(0, gettext("A parent directory cannot be read"));
1356 exit(1);
1359 (void) strcpy(wdir, origdir);
1361 while ((*argv || fp) && !term) {
1362 if (fp || (strcmp(*argv, "-I") == 0)) {
1363 if (fp == NULL) {
1364 if (*++argv == NULL)
1365 fatal(gettext(
1366 "missing file name for -I flag."));
1367 else if ((fp = fopen(*argv++, "r")) == NULL)
1368 vperror(0, "%s", argv[-1]);
1369 continue;
1370 } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
1371 (void) fclose(fp);
1372 fp = NULL;
1373 continue;
1374 } else {
1375 cp = cp2 = file;
1376 if ((p = strchr(cp2, '\n')))
1377 *p = 0;
1379 } else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
1380 if (tar_chdir(*++argv) < 0)
1381 vperror(0, gettext(
1382 "can't change directories to %s"), *argv);
1383 else
1384 (void) getcwd(wdir, (sizeof (wdir)));
1385 argv++;
1386 continue;
1387 } else
1388 cp = cp2 = strcpy(file, *argv++);
1391 * point cp2 to the last '/' in file, but not
1392 * to a trailing '/'
1394 for (; *cp; cp++) {
1395 if (*cp == '/') {
1396 while (*(cp+1) == '/') {
1397 ++cp;
1399 if (*(cp+1) != '\0') {
1400 /* not trailing slash */
1401 cp2 = cp;
1405 if (cp2 != file) {
1406 *cp2 = '\0';
1407 if (tar_chdir(file) < 0) {
1408 vperror(0, gettext(
1409 "can't change directories to %s"), file);
1410 continue;
1412 *cp2 = '/';
1413 cp2++;
1416 parent = getcwd(tempdir, (sizeof (tempdir)));
1418 archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
1419 LEV0, SYMLINK_LEV0);
1421 #if defined(O_XATTR)
1422 if (!exitflag) {
1423 if ((atflag || saflag) &&
1424 (archtype == PUT_NOTAS_LINK)) {
1425 xattrs_put(file, cp2, parent, NULL);
1428 #endif
1430 if (tar_chdir(origdir) < 0)
1431 vperror(0, gettext("cannot change back?: %s"), origdir);
1433 if (exitflag) {
1435 * If e function modifier has been specified
1436 * write the files (that are listed before the
1437 * file causing the error) to tape. exitflag is
1438 * used because only some of the error conditions
1439 * in putfile() recognize the e function modifier.
1441 break;
1445 putempty((blkcnt_t)2);
1446 flushtape();
1447 closevol(); /* SP-1 */
1448 if (linkerrok == 1)
1449 for (; ihead != NULL; ihead = ihead->nextp) {
1450 if (ihead->count == 0)
1451 continue;
1452 (void) fprintf(stderr, gettext(
1453 "tar: missing links to %s\n"), ihead->pathname);
1454 if (errflag)
1455 done(1);
1456 else
1457 Errflg = 1;
1463 * endtape - check for tape at end
1465 * endtape checks the entry in dblock.dbuf to see if its the
1466 * special EOT entry. Endtape is usually called after getdir().
1468 * endtape used to call backtape; it no longer does, it who
1469 * wants it backed up must call backtape himself
1470 * RETURNS: 0 if not EOT, tape position unaffected
1471 * 1 if EOT, tape position unaffected
1474 static boolean_t
1475 endtape(void)
1477 if (dblock.dbuf.name[0] != '\0') {
1479 * The name field is populated.
1481 return (B_FALSE);
1484 if (is_posix && dblock.dbuf.prefix[0] != '\0') {
1486 * This is a ustar/POSIX archive, and although the name
1487 * field is empty the prefix field is not.
1489 return (B_FALSE);
1492 dlog("endtape(): found null header; EOT\n");
1493 return (B_TRUE);
1497 * getdir - get directory entry from tar tape
1499 * getdir reads the next tarblock off the tape and cracks
1500 * it as a directory. The checksum must match properly.
1502 * If tfile is non-null getdir writes the file name and mod date
1503 * to tfile.
1506 static void
1507 getdir(void)
1509 struct stat *sp;
1510 #ifdef EUC
1511 static int warn_chksum_sign = 0;
1512 #endif /* EUC */
1514 top:
1515 readtape((char *)&dblock);
1516 if (dblock.dbuf.name[0] == '\0')
1517 return;
1518 sp = &stbuf;
1519 (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
1520 (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
1521 (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
1522 (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
1523 (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
1524 (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
1525 (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
1526 (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
1528 is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
1530 sp->st_mode = Gen.g_mode;
1531 if (is_posix && (sp->st_mode & S_IFMT) == 0) {
1532 switch (dblock.dbuf.typeflag) {
1533 case '0':
1534 case 0:
1535 case _XATTR_HDRTYPE:
1536 sp->st_mode |= S_IFREG;
1537 break;
1538 case '1': /* hard link */
1539 break;
1540 case '2':
1541 sp->st_mode |= S_IFLNK;
1542 break;
1543 case '3':
1544 sp->st_mode |= S_IFCHR;
1545 break;
1546 case '4':
1547 sp->st_mode |= S_IFBLK;
1548 break;
1549 case '5':
1550 sp->st_mode |= S_IFDIR;
1551 break;
1552 case '6':
1553 sp->st_mode |= S_IFIFO;
1554 break;
1555 default:
1556 if (convtoreg(Gen.g_filesz))
1557 sp->st_mode |= S_IFREG;
1558 break;
1562 if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
1563 Xhdrflag = 1; /* Currently processing extended header */
1564 } else {
1565 Xhdrflag = 0;
1568 sp->st_uid = Gen.g_uid;
1569 sp->st_gid = Gen.g_gid;
1570 sp->st_size = Gen.g_filesz;
1571 sp->st_mtime = Gen.g_mtime;
1572 chksum = Gen.g_cksum;
1574 if (dblock.dbuf.extno != '\0') { /* split file? */
1575 extno = dblock.dbuf.extno;
1576 extsize = Gen.g_filesz;
1577 extotal = dblock.dbuf.extotal;
1578 } else {
1579 extno = 0; /* tell others file not split */
1580 extsize = 0;
1581 extotal = 0;
1584 #ifdef EUC
1585 if (chksum != checksum(&dblock)) {
1586 if (chksum != checksum_signed(&dblock)) {
1587 (void) fprintf(stderr, gettext(
1588 "tar: directory checksum error\n"));
1589 if (iflag) {
1590 Errflg = 2;
1591 goto top;
1593 done(2);
1594 } else {
1595 if (! warn_chksum_sign) {
1596 warn_chksum_sign = 1;
1597 (void) fprintf(stderr, gettext(
1598 "tar: warning: tar file made with signed checksum\n"));
1602 #else
1603 if (chksum != checksum(&dblock)) {
1604 (void) fprintf(stderr, gettext(
1605 "tar: directory checksum error\n"));
1606 if (iflag) {
1607 Errflg = 2;
1608 goto top;
1610 done(2);
1612 #endif /* EUC */
1613 if (tfile != NULL && Xhdrflag == 0) {
1615 * If an extended header is present, then time is available
1616 * in nanoseconds in the extended header data, so set it.
1617 * Otherwise, give an invalid value so that checkupdate will
1618 * not test beyond seconds.
1620 if ((xhdr_flgs & _X_MTIME))
1621 sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
1622 else
1623 sp->st_mtim.tv_nsec = -1;
1625 if (xhdr_flgs & _X_PATH)
1626 (void) fprintf(tfile, "%s %10ld.%9.9ld\n",
1627 Xtarhdr.x_path, sp->st_mtim.tv_sec,
1628 sp->st_mtim.tv_nsec);
1629 else
1630 (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
1631 NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
1632 sp->st_mtim.tv_nsec);
1635 #if defined(O_XATTR)
1636 Hiddendir = 0;
1637 if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
1638 if (xattrbadhead) {
1639 free(xattrhead);
1640 xattrp = NULL;
1641 xattr_linkp = NULL;
1642 xattrhead = NULL;
1643 } else {
1644 char *aname = basename(xattrapath);
1645 size_t xindex = aname - xattrapath;
1647 if (xattrapath[xindex] == '.' &&
1648 xattrapath[xindex + 1] == '\0' &&
1649 xattrp->h_typeflag == '5') {
1650 Hiddendir = 1;
1651 sp->st_mode =
1652 (S_IFDIR | (sp->st_mode & POSIXMODES));
1654 dblock.dbuf.typeflag = xattrp->h_typeflag;
1657 #endif
1662 * passtape - skip over a file on the tape
1664 * passtape skips over the next data file on the tape.
1665 * The tape directory entry must be in dblock.dbuf. This
1666 * routine just eats the number of blocks computed from the
1667 * directory size entry; the tape must be (logically) positioned
1668 * right after the directory info.
1671 static void
1672 passtape(void)
1674 blkcnt_t blocks;
1675 char buf[TBLOCK];
1678 * Print some debugging information about the directory entry
1679 * we are skipping over:
1681 dlog("passtape: typeflag \"%c\"\n", dblock.dbuf.typeflag);
1682 if (dblock.dbuf.name[0] != '\0') {
1683 dlog("passtape: name \"%s\"\n", dblock.dbuf.name);
1685 if (is_posix && dblock.dbuf.prefix[0] != '\0') {
1686 dlog("passtape: prefix \"%s\"\n", dblock.dbuf.prefix);
1690 * Types link(1), sym-link(2), char special(3), blk special(4),
1691 * directory(5), and FIFO(6) do not have data blocks associated
1692 * with them so just skip reading the data block.
1694 if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
1695 dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
1696 dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
1697 return;
1698 blocks = TBLOCKS(stbuf.st_size);
1700 dlog("passtape: block count %" FMT_blkcnt_t "\n", blocks);
1702 /* if operating on disk, seek instead of reading */
1703 if (NotTape)
1704 seekdisk(blocks);
1705 else
1706 while (blocks-- > 0)
1707 readtape(buf);
1710 #if defined(O_XATTR)
1711 static int
1712 is_sysattr(char *name)
1714 return ((strcmp(name, VIEW_READONLY) == 0) ||
1715 (strcmp(name, VIEW_READWRITE) == 0));
1717 #endif
1719 #if defined(O_XATTR)
1721 * Verify the attribute, attrname, is an attribute we want to restore.
1722 * Never restore read-only system attribute files. Only restore read-write
1723 * system attributes files when -/ was specified, and only traverse into
1724 * the 2nd level attribute directory containing only system attributes if
1725 * -@ was specified. This keeps us from archiving
1726 * <attribute name>/<read-write system attribute file>
1727 * when -/ was specified without -@.
1729 * attrname - attribute file name
1730 * attrparent - attribute's parent name within the base file's attribute
1731 * directory hierarchy
1733 static attr_status_t
1734 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
1735 int *rw_sysattr)
1737 #if defined(_PC_SATTR_ENABLED)
1738 int attr_supported;
1740 /* Never restore read-only system attribute files */
1741 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
1742 *rw_sysattr = 0;
1743 return (ATTR_SKIP);
1744 } else {
1745 *rw_sysattr = (attr_supported == _RW_SATTR);
1747 #else
1749 * Only need to check if this attribute is an extended system
1750 * attribute.
1752 if (*rw_sysattr = is_sysattr(attrname)) {
1753 return (ATTR_SKIP);
1754 } else {
1755 return (ATTR_OK);
1757 #endif /* _PC_SATTR_ENABLED */
1760 * If the extended system attribute file is specified with the
1761 * arc_rwsysattr flag, as being transient (default extended
1762 * attributes), then don't archive it.
1764 if (*rw_sysattr && !arc_rwsysattr) {
1765 return (ATTR_SKIP);
1769 * Only restore read-write system attribute files
1770 * when -/ was specified. Only restore extended
1771 * attributes when -@ was specified.
1773 if (atflag) {
1774 if (!saflag) {
1776 * Only archive/restore the hidden directory "." if
1777 * we're processing the top level hidden attribute
1778 * directory. We don't want to process the
1779 * hidden attribute directory of the attribute
1780 * directory that contains only extended system
1781 * attributes.
1783 if (*rw_sysattr || (Hiddendir &&
1784 (attrparent != NULL))) {
1785 return (ATTR_SKIP);
1788 } else if (saflag) {
1790 * Only archive/restore read-write extended system attribute
1791 * files of the base file.
1793 if (!*rw_sysattr || (attrparent != NULL)) {
1794 return (ATTR_SKIP);
1796 } else {
1797 return (ATTR_SKIP);
1800 return (ATTR_OK);
1802 #endif
1804 static void
1805 free_children(file_list_t *children)
1807 file_list_t *child = children;
1808 file_list_t *cptr;
1810 while (child != NULL) {
1811 cptr = child->next;
1812 if (child->name != NULL) {
1813 free(child->name);
1815 child = cptr;
1819 static int
1820 putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
1821 int filetype, int lev, int symlink_lev)
1823 int infile = -1; /* deliberately invalid */
1824 blkcnt_t blocks;
1825 char buf[PATH_MAX + 2]; /* Add trailing slash and null */
1826 char *bigbuf;
1827 int maxread;
1828 int hint; /* amount to write to get "in sync" */
1829 char filetmp[PATH_MAX + 1];
1830 char *cp;
1831 char *name;
1832 char *attrparent = NULL;
1833 char *longattrname = NULL;
1834 file_list_t *child = NULL;
1835 file_list_t *child_end = NULL;
1836 file_list_t *cptr;
1837 struct dirent *dp;
1838 DIR *dirp;
1839 int i;
1840 int split;
1841 int dirfd = -1;
1842 int rc = PUT_NOTAS_LINK;
1843 int archtype = 0;
1844 int rw_sysattr = 0;
1845 char newparent[PATH_MAX + MAXNAMLEN + 1];
1846 char *prefix = "";
1847 char *tmpbuf;
1848 char goodbuf[PRESIZ + 2];
1849 char junkbuf[MAXNAM+1];
1850 char *lastslash;
1851 int j;
1852 struct stat sbuf;
1853 int readlink_max;
1855 (void) memset(goodbuf, '\0', sizeof (goodbuf));
1856 (void) memset(junkbuf, '\0', sizeof (junkbuf));
1858 xhdr_flgs = 0;
1860 if (filetype == XATTR_FILE) {
1861 attrparent = attrinfo->attr_parent;
1862 longattrname = attrinfo->attr_path;
1863 dirfd = attrinfo->attr_parentfd;
1864 rw_sysattr = attrinfo->attr_rw_sysattr;
1865 } else {
1866 dirfd = open(".", O_RDONLY);
1869 if (dirfd == -1) {
1870 (void) fprintf(stderr, gettext(
1871 "tar: unable to open%sdirectory %s%s%s%s\n"),
1872 (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
1873 (attrparent == NULL) ? "" : gettext("of attribute "),
1874 (attrparent == NULL) ? "" : attrparent,
1875 (attrparent == NULL) ? "" : gettext(" of "),
1876 (filetype == XATTR_FILE) ? longname : parent);
1877 goto out;
1880 if (lev > MAXLEV) {
1881 (void) fprintf(stderr,
1882 gettext("tar: directory nesting too deep, %s not dumped\n"),
1883 longname);
1884 goto out;
1887 if (getstat(dirfd, longname, shortname, attrparent))
1888 goto out;
1890 if (hflag) {
1892 * Catch nesting where a file is a symlink to its directory.
1894 j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
1895 if (S_ISLNK(sbuf.st_mode)) {
1896 if (symlink_lev++ >= MAXSYMLINKS) {
1897 (void) fprintf(stderr, gettext(
1898 "tar: %s: Number of symbolic links "
1899 "encountered during path name traversal "
1900 "exceeds MAXSYMLINKS\n"), longname);
1901 Errflg = 1;
1902 goto out;
1908 * Check if the input file is the same as the tar file we
1909 * are creating
1911 if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
1912 (void) fprintf(stderr, gettext(
1913 "tar: %s%s%s%s%s same as archive file\n"),
1914 rw_sysattr ? gettext("system ") : "",
1915 (longattrname == NULL) ? "" : gettext("attribute "),
1916 (longattrname == NULL) ? "" : longattrname,
1917 (longattrname == NULL) ? "" : gettext(" of "),
1918 longname);
1919 Errflg = 1;
1920 goto out;
1923 * Check size limit - we can't archive files that
1924 * exceed TAR_OFFSET_MAX bytes because of header
1925 * limitations. Exclude file types that set
1926 * st_size to zero below because they take no
1927 * archive space to represent contents.
1929 if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
1930 !S_ISDIR(stbuf.st_mode) &&
1931 !S_ISCHR(stbuf.st_mode) &&
1932 !S_ISBLK(stbuf.st_mode) &&
1933 (Eflag == 0)) {
1934 (void) fprintf(stderr, gettext(
1935 "tar: %s%s%s%s%s too large to archive. "
1936 "Use E function modifier.\n"),
1937 rw_sysattr ? gettext("system ") : "",
1938 (longattrname == NULL) ? "" : gettext("attribute "),
1939 (longattrname == NULL) ? "" : longattrname,
1940 (longattrname == NULL) ? "" : gettext(" of "),
1941 longname);
1942 if (errflag)
1943 exitflag = 1;
1944 Errflg = 1;
1945 goto out;
1948 if (tfile != NULL && checkupdate(longname) == 0) {
1949 goto out;
1951 if (checkw('r', longname) == 0) {
1952 goto out;
1955 if (Fflag &&
1956 checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
1957 goto out;
1959 if (Xflag) {
1960 if (is_in_table(exclude_tbl, longname)) {
1961 if (vflag) {
1962 (void) fprintf(vfile, gettext(
1963 "a %s excluded\n"), longname);
1965 goto out;
1970 * If the length of the fullname is greater than MAXNAM,
1971 * print out a message and return (unless extended headers are used,
1972 * in which case fullname is limited to PATH_MAX).
1975 if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
1976 (split > PATH_MAX)) {
1977 (void) fprintf(stderr, gettext(
1978 "tar: %s: file name too long\n"), longname);
1979 if (errflag)
1980 exitflag = 1;
1981 Errflg = 1;
1982 goto out;
1986 * We split the fullname into prefix and name components if any one
1987 * of three conditions holds:
1988 * -- the length of the fullname exceeds NAMSIZ,
1989 * -- the length of the fullname equals NAMSIZ, and the shortname
1990 * is less than NAMSIZ, (splitting in this case preserves
1991 * compatibility with 5.6 and 5.5.1 tar), or
1992 * -- the length of the fullname equals NAMSIZ, the file is a
1993 * directory and we are not in POSIX-conformant mode (where
1994 * trailing slashes are removed from directories).
1996 if ((split > NAMSIZ) ||
1997 (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1998 (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
2000 * Since path is limited to PRESIZ characters, look for the
2001 * last slash within PRESIZ + 1 characters only.
2003 (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
2004 tmpbuf = goodbuf;
2005 lastslash = strrchr(tmpbuf, '/');
2006 if (lastslash == NULL) {
2007 i = split; /* Length of name */
2008 j = 0; /* Length of prefix */
2009 goodbuf[0] = '\0';
2010 } else {
2011 *lastslash = '\0'; /* Terminate the prefix */
2012 j = strlen(tmpbuf);
2013 i = split - j - 1;
2016 * If the filename is greater than NAMSIZ we can't
2017 * archive the file unless we are using extended headers.
2019 if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
2020 !Pflag)) {
2021 /* Determine which (filename or path) is too long. */
2022 lastslash = strrchr(longname, '/');
2023 if (lastslash != NULL)
2024 i = strlen(lastslash + 1);
2025 if (Eflag > 0) {
2026 xhdr_flgs |= _X_PATH;
2027 Xtarhdr.x_path = longname;
2028 if (i <= NAMSIZ)
2029 (void) strcpy(junkbuf, lastslash + 1);
2030 else
2031 (void) sprintf(junkbuf, "%llu",
2032 xhdr_count + 1);
2033 if (split - i - 1 > PRESIZ)
2034 (void) strcpy(goodbuf, xhdr_dirname);
2035 } else {
2036 if ((i > NAMSIZ) || (i == NAMSIZ &&
2037 S_ISDIR(stbuf.st_mode) && !Pflag))
2038 (void) fprintf(stderr, gettext(
2039 "tar: %s: filename is greater than "
2040 "%d\n"), lastslash == NULL ?
2041 longname : lastslash + 1, NAMSIZ);
2042 else
2043 (void) fprintf(stderr, gettext(
2044 "tar: %s: prefix is greater than %d"
2045 "\n"), longname, PRESIZ);
2046 if (errflag)
2047 exitflag = 1;
2048 Errflg = 1;
2049 goto out;
2051 } else
2052 (void) strncpy(&junkbuf[0], longname + j + 1,
2053 strlen(longname + j + 1));
2054 name = junkbuf;
2055 prefix = goodbuf;
2056 } else {
2057 name = longname;
2059 if (Aflag) {
2060 if ((prefix != NULL) && (*prefix != '\0'))
2061 while (*prefix == '/')
2062 ++prefix;
2063 else
2064 while (*name == '/')
2065 ++name;
2068 switch (stbuf.st_mode & S_IFMT) {
2069 case S_IFDIR:
2070 stbuf.st_size = (off_t)0;
2071 blocks = TBLOCKS(stbuf.st_size);
2073 if (filetype != XATTR_FILE && Hiddendir == 0) {
2074 i = 0;
2075 cp = buf;
2076 while ((*cp++ = longname[i++]))
2078 *--cp = '/';
2079 *++cp = 0;
2081 if (!oflag) {
2082 tomodes(&stbuf);
2083 if (build_dblock(name, tchar, '5', filetype,
2084 &stbuf, stbuf.st_dev, prefix) != 0) {
2085 goto out;
2087 if (!Pflag) {
2089 * Old archives require a slash at the end
2090 * of a directory name.
2092 * XXX
2093 * If directory name is too long, will
2094 * slash overfill field?
2096 if (strlen(name) > (unsigned)NAMSIZ-1) {
2097 (void) fprintf(stderr, gettext(
2098 "tar: %s: filename is greater "
2099 "than %d\n"), name, NAMSIZ);
2100 if (errflag)
2101 exitflag = 1;
2102 Errflg = 1;
2103 goto out;
2104 } else {
2105 if (strlen(name) == (NAMSIZ - 1)) {
2106 (void) memcpy(dblock.dbuf.name,
2107 name, NAMSIZ);
2108 dblock.dbuf.name[NAMSIZ-1]
2109 = '/';
2110 } else
2111 (void) sprintf(dblock.dbuf.name,
2112 "%s/", name);
2115 * need to recalculate checksum
2116 * because the name changed.
2118 (void) sprintf(dblock.dbuf.chksum,
2119 "%07o", checksum(&dblock));
2123 if (put_extra_attributes(longname, shortname,
2124 longattrname, prefix, filetype, '5') != 0)
2125 goto out;
2127 #if defined(O_XATTR)
2129 * Reset header typeflag when archiving directory, since
2130 * build_dblock changed it on us.
2132 if (filetype == XATTR_FILE) {
2133 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2134 } else {
2135 dblock.dbuf.typeflag = '5';
2137 #else
2138 dblock.dbuf.typeflag = '5';
2139 #endif
2141 (void) sprintf(dblock.dbuf.chksum, "%07o",
2142 checksum(&dblock));
2144 (void) writetbuf((char *)&dblock, 1);
2146 if (vflag) {
2147 if (NotTape) {
2148 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2150 if (filetype == XATTR_FILE && Hiddendir) {
2151 (void) fprintf(vfile,
2152 gettext("a %s attribute %s "),
2153 longname, longattrname);
2155 } else {
2156 (void) fprintf(vfile, "a %s/ ", longname);
2158 if (NotTape) {
2159 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2160 K(blocks));
2161 } else {
2162 (void) fprintf(vfile, gettext("%" FMT_blkcnt_t
2163 " tape blocks\n"), blocks);
2168 * If hidden dir then break now since xattrs_put() will do
2169 * the iterating of the directory.
2171 * At the moment, there can only be system attributes on
2172 * attributes. There can be no attributes on attributes or
2173 * directories within the attributes hidden directory hierarchy.
2175 if (filetype == XATTR_FILE)
2176 break;
2178 if (*shortname != '/')
2179 (void) sprintf(newparent, "%s/%s", parent, shortname);
2180 else
2181 (void) sprintf(newparent, "%s", shortname);
2183 if (tar_chdir(shortname) < 0) {
2184 vperror(0, "%s", newparent);
2185 goto out;
2188 if ((dirp = opendir(".")) == NULL) {
2189 vperror(0, gettext(
2190 "can't open directory %s"), longname);
2191 if (tar_chdir(parent) < 0)
2192 vperror(0, gettext("cannot change back?: %s"),
2193 parent);
2194 goto out;
2198 * Create a list of files (children) in this directory to avoid
2199 * having to perform telldir()/seekdir().
2201 while ((dp = readdir(dirp)) != NULL && !term) {
2202 if ((strcmp(".", dp->d_name) == 0) ||
2203 (strcmp("..", dp->d_name) == 0))
2204 continue;
2205 if (((cptr = (file_list_t *)calloc(sizeof (char),
2206 sizeof (file_list_t))) == NULL) ||
2207 ((cptr->name = strdup(dp->d_name)) == NULL)) {
2208 vperror(1, gettext(
2209 "Insufficient memory for directory "
2210 "list entry %s/%s\n"),
2211 newparent, dp->d_name);
2214 /* Add the file to the list */
2215 if (child == NULL) {
2216 child = cptr;
2217 } else {
2218 child_end->next = cptr;
2220 child_end = cptr;
2222 (void) closedir(dirp);
2225 * Archive each of the files in the current directory.
2226 * If a file is a directory, putfile() is called
2227 * recursively to archive the file hierarchy of the
2228 * directory before archiving the next file in the
2229 * current directory.
2231 while ((child != NULL) && !term) {
2232 (void) strcpy(cp, child->name);
2233 archtype = putfile(buf, cp, newparent, NULL,
2234 NORMAL_FILE, lev + 1, symlink_lev);
2236 if (!exitflag) {
2237 if ((atflag || saflag) &&
2238 (archtype == PUT_NOTAS_LINK)) {
2239 xattrs_put(buf, cp, newparent, NULL);
2242 if (exitflag)
2243 break;
2245 /* Free each child as we are done processing it. */
2246 cptr = child;
2247 child = child->next;
2248 free(cptr->name);
2249 free(cptr);
2251 if ((child != NULL) && !term) {
2252 free_children(child);
2255 if (tar_chdir(parent) < 0) {
2256 vperror(0, gettext("cannot change back?: %s"), parent);
2259 break;
2261 case S_IFLNK:
2262 readlink_max = NAMSIZ;
2263 if (stbuf.st_size > NAMSIZ) {
2264 if (Eflag > 0) {
2265 xhdr_flgs |= _X_LINKPATH;
2266 readlink_max = PATH_MAX;
2267 } else {
2268 (void) fprintf(stderr, gettext(
2269 "tar: %s: symbolic link too long\n"),
2270 longname);
2271 if (errflag)
2272 exitflag = 1;
2273 Errflg = 1;
2274 goto out;
2278 * Sym-links need header size of zero since you
2279 * don't store any data for this type.
2281 stbuf.st_size = (off_t)0;
2282 tomodes(&stbuf);
2283 i = readlink(shortname, filetmp, readlink_max);
2284 if (i < 0) {
2285 vperror(0, gettext(
2286 "can't read symbolic link %s"), longname);
2287 goto out;
2288 } else {
2289 filetmp[i] = 0;
2291 if (vflag)
2292 (void) fprintf(vfile, gettext(
2293 "a %s symbolic link to %s\n"),
2294 longname, filetmp);
2295 if (xhdr_flgs & _X_LINKPATH) {
2296 Xtarhdr.x_linkpath = filetmp;
2297 if (build_dblock(name, tchar, '2', filetype, &stbuf,
2298 stbuf.st_dev, prefix) != 0)
2299 goto out;
2300 } else
2301 if (build_dblock(name, filetmp, '2', filetype, &stbuf,
2302 stbuf.st_dev, prefix) != 0)
2303 goto out;
2304 (void) writetbuf((char *)&dblock, 1);
2306 * No acls for symlinks: mode is always 777
2307 * dont call write ancillary
2309 rc = PUT_AS_LINK;
2310 break;
2311 case S_IFREG:
2312 if ((infile = openat(dirfd, shortname, 0)) < 0) {
2313 vperror(0, gettext("unable to open %s%s%s%s"), longname,
2314 rw_sysattr ? gettext(" system") : "",
2315 (filetype == XATTR_FILE) ?
2316 gettext(" attribute ") : "",
2317 (filetype == XATTR_FILE) ? (longattrname == NULL) ?
2318 shortname : longattrname : "");
2319 goto out;
2322 blocks = TBLOCKS(stbuf.st_size);
2324 if (put_link(name, longname, shortname, longattrname,
2325 prefix, filetype, '1') == 0) {
2326 (void) close(infile);
2327 rc = PUT_AS_LINK;
2328 goto out;
2331 tomodes(&stbuf);
2333 /* correctly handle end of volume */
2334 while (mulvol && tapepos + blocks + 1 > blocklim) {
2335 /* split if floppy has some room and file is large */
2336 if (((blocklim - tapepos) >= EXTMIN) &&
2337 ((blocks + 1) >= blocklim/10)) {
2338 splitfile(longname, infile,
2339 name, prefix, filetype);
2340 (void) close(dirfd);
2341 (void) close(infile);
2342 goto out;
2344 newvol(); /* not worth it--just get new volume */
2346 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2347 blocks);
2348 if (build_dblock(name, tchar, '0', filetype,
2349 &stbuf, stbuf.st_dev, prefix) != 0) {
2350 goto out;
2352 if (vflag) {
2353 if (NotTape) {
2354 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2356 (void) fprintf(vfile, "a %s%s%s%s ", longname,
2357 rw_sysattr ? gettext(" system") : "",
2358 (filetype == XATTR_FILE) ? gettext(
2359 " attribute ") : "",
2360 (filetype == XATTR_FILE) ?
2361 longattrname : "");
2362 if (NotTape)
2363 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2364 K(blocks));
2365 else
2366 (void) fprintf(vfile,
2367 gettext("%" FMT_blkcnt_t " tape blocks\n"),
2368 blocks);
2371 if (put_extra_attributes(longname, shortname, longattrname,
2372 prefix, filetype, '0') != 0)
2373 goto out;
2376 * No need to reset typeflag for extended attribute here, since
2377 * put_extra_attributes already set it and we haven't called
2378 * build_dblock().
2380 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2381 hint = writetbuf((char *)&dblock, 1);
2382 maxread = max(min(stbuf.st_blksize, stbuf.st_size),
2383 (nblock * TBLOCK));
2384 if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
2385 maxread = TBLOCK;
2386 bigbuf = buf;
2389 while (((i = (int)
2390 read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
2391 blocks) {
2392 blkcnt_t nblks;
2394 nblks = ((i-1)/TBLOCK)+1;
2395 if (nblks > blocks)
2396 nblks = blocks;
2397 hint = writetbuf(bigbuf, nblks);
2398 blocks -= nblks;
2400 (void) close(infile);
2401 if (bigbuf != buf)
2402 free(bigbuf);
2403 if (i < 0)
2404 vperror(0, gettext("Read error on %s"), longname);
2405 else if (blocks != 0 || i != 0) {
2406 (void) fprintf(stderr, gettext(
2407 "tar: %s: file changed size\n"), longname);
2408 if (errflag) {
2409 exitflag = 1;
2410 Errflg = 1;
2411 } else if (!Dflag) {
2412 Errflg = 1;
2415 putempty(blocks);
2416 break;
2417 case S_IFIFO:
2418 blocks = TBLOCKS(stbuf.st_size);
2419 stbuf.st_size = (off_t)0;
2421 if (put_link(name, longname, shortname, longattrname,
2422 prefix, filetype, '6') == 0) {
2423 rc = PUT_AS_LINK;
2424 goto out;
2426 tomodes(&stbuf);
2428 while (mulvol && tapepos + blocks + 1 > blocklim) {
2429 if (((blocklim - tapepos) >= EXTMIN) &&
2430 ((blocks + 1) >= blocklim/10)) {
2431 splitfile(longname, infile, name,
2432 prefix, filetype);
2433 (void) close(dirfd);
2434 (void) close(infile);
2435 goto out;
2437 newvol();
2439 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2440 blocks);
2441 if (vflag) {
2442 if (NotTape) {
2443 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2445 (void) fprintf(vfile, gettext("a %s %"
2446 FMT_blkcnt_t "K\n "), longname, K(blocks));
2447 } else {
2448 (void) fprintf(vfile, gettext(
2449 "a %s %" FMT_blkcnt_t " tape blocks\n"),
2450 longname, blocks);
2453 if (build_dblock(name, tchar, '6', filetype,
2454 &stbuf, stbuf.st_dev, prefix) != 0)
2455 goto out;
2457 if (put_extra_attributes(longname, shortname, longattrname,
2458 prefix, filetype, '6') != 0)
2459 goto out;
2461 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2462 dblock.dbuf.typeflag = '6';
2464 (void) writetbuf((char *)&dblock, 1);
2465 break;
2466 case S_IFCHR:
2467 stbuf.st_size = (off_t)0;
2468 blocks = TBLOCKS(stbuf.st_size);
2469 if (put_link(name, longname, shortname, longattrname,
2470 prefix, filetype, '3') == 0) {
2471 rc = PUT_AS_LINK;
2472 goto out;
2474 tomodes(&stbuf);
2476 while (mulvol && tapepos + blocks + 1 > blocklim) {
2477 if (((blocklim - tapepos) >= EXTMIN) &&
2478 ((blocks + 1) >= blocklim/10)) {
2479 splitfile(longname, infile, name,
2480 prefix, filetype);
2481 (void) close(dirfd);
2482 goto out;
2484 newvol();
2486 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2487 blocks);
2488 if (vflag) {
2489 if (NotTape) {
2490 dlog("seek = %" FMT_blkcnt_t "K\t", K(tapepos));
2492 (void) fprintf(vfile, gettext("a %s %"
2493 FMT_blkcnt_t "K\n"), longname, K(blocks));
2494 } else {
2495 (void) fprintf(vfile, gettext("a %s %"
2496 FMT_blkcnt_t " tape blocks\n"), longname,
2497 blocks);
2500 if (build_dblock(name, tchar, '3',
2501 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2502 goto out;
2504 if (put_extra_attributes(longname, shortname, longattrname,
2505 prefix, filetype, '3') != 0)
2506 goto out;
2508 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2509 dblock.dbuf.typeflag = '3';
2511 (void) writetbuf((char *)&dblock, 1);
2512 break;
2513 case S_IFBLK:
2514 stbuf.st_size = (off_t)0;
2515 blocks = TBLOCKS(stbuf.st_size);
2516 if (put_link(name, longname, shortname, longattrname,
2517 prefix, filetype, '4') == 0) {
2518 rc = PUT_AS_LINK;
2519 goto out;
2521 tomodes(&stbuf);
2523 while (mulvol && tapepos + blocks + 1 > blocklim) {
2524 if (((blocklim - tapepos) >= EXTMIN) &&
2525 ((blocks + 1) >= blocklim/10)) {
2526 splitfile(longname, infile,
2527 name, prefix, filetype);
2528 (void) close(dirfd);
2529 goto out;
2531 newvol();
2533 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2534 blocks);
2535 if (vflag) {
2536 if (NotTape) {
2537 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2540 (void) fprintf(vfile, "a %s ", longname);
2541 if (NotTape)
2542 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2543 K(blocks));
2544 else
2545 (void) fprintf(vfile, gettext("%"
2546 FMT_blkcnt_t " tape blocks\n"), blocks);
2548 if (build_dblock(name, tchar, '4',
2549 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2550 goto out;
2552 if (put_extra_attributes(longname, shortname, longattrname,
2553 prefix, filetype, '4') != 0)
2554 goto out;
2556 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2557 dblock.dbuf.typeflag = '4';
2559 (void) writetbuf((char *)&dblock, 1);
2560 break;
2561 default:
2562 (void) fprintf(stderr, gettext(
2563 "tar: %s is not a file. Not dumped\n"), longname);
2564 if (errflag)
2565 exitflag = 1;
2566 Errflg = 1;
2567 goto out;
2570 out:
2571 if ((dirfd != -1) && (filetype != XATTR_FILE)) {
2572 (void) close(dirfd);
2574 return (rc);
2579 * splitfile dump a large file across volumes
2581 * splitfile(longname, fd);
2582 * char *longname; full name of file
2583 * int ifd; input file descriptor
2585 * NOTE: only called by putfile() to dump a large file.
2588 static void
2589 splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
2591 blkcnt_t blocks;
2592 off_t bytes, s;
2593 char buf[TBLOCK];
2594 int i, extents;
2596 blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */
2599 * # extents =
2600 * size of file after using up rest of this floppy
2601 * blocks - (blocklim - tapepos) + 1 (for header)
2602 * plus roundup value before divide by blocklim-1
2603 * + (blocklim - 1) - 1
2604 * all divided by blocklim-1 (one block for each header).
2605 * this gives
2606 * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2607 * which reduces to the expression used.
2608 * one is added to account for this first extent.
2610 * When one is dealing with extremely large archives, one may want
2611 * to allow for a large number of extents. This code should be
2612 * revisited to determine if extents should be changed to something
2613 * larger than an int.
2615 extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
2617 if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */
2618 (void) fprintf(stderr, gettext(
2619 "tar: %s needs unusual number of volumes to split\n"
2620 "tar: %s not dumped\n"), longname, longname);
2621 return;
2623 if (build_dblock(name, tchar, '0', filetype,
2624 &stbuf, stbuf.st_dev, prefix) != 0)
2625 return;
2627 dblock.dbuf.extotal = extents;
2628 bytes = stbuf.st_size;
2631 * The value contained in dblock.dbuf.efsize was formerly used when the
2632 * v flag was specified in conjunction with the t flag. Although it is
2633 * no longer used, older versions of tar will expect the former
2634 * behaviour, so we must continue to write it to the archive.
2636 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2637 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2638 * store 0.
2640 if (bytes <= TAR_EFSIZE_MAX)
2641 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
2642 else
2643 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
2645 (void) fprintf(stderr, gettext(
2646 "tar: large file %s needs %d extents.\n"
2647 "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
2648 longname, extents, K(tapepos));
2650 s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
2651 for (i = 1; i <= extents; i++) {
2652 if (i > 1) {
2653 newvol();
2654 if (i == extents)
2655 s = bytes; /* last ext. gets true bytes */
2656 else
2657 s = (off_t)(blocklim - 1)*TBLOCK; /* all */
2659 bytes -= s;
2660 blocks = TBLOCKS(s);
2662 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
2663 dblock.dbuf.extno = i;
2664 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2665 (void) writetbuf((char *)&dblock, 1);
2667 if (vflag)
2668 (void) fprintf(vfile,
2669 gettext("+++ a %s %" FMT_blkcnt_t
2670 "K [extent #%d of %d]\n"),
2671 longname, K(blocks), i, extents);
2672 while (blocks && read(ifd, buf, TBLOCK) > 0) {
2673 blocks--;
2674 (void) writetbuf(buf, 1);
2676 if (blocks != 0) {
2677 (void) fprintf(stderr, gettext(
2678 "tar: %s: file changed size\n"), longname);
2679 (void) fprintf(stderr, gettext(
2680 "tar: aborting split file %s\n"), longname);
2681 (void) close(ifd);
2682 return;
2685 (void) close(ifd);
2686 if (vflag)
2687 (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
2688 "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
2689 extents);
2693 * convtoreg - determines whether the file should be converted to a
2694 * regular file when extracted
2696 * Returns 1 when file size > 0 and typeflag is not recognized
2697 * Otherwise returns 0
2699 static int
2700 convtoreg(off_t size)
2702 if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
2703 (dblock.dbuf.typeflag != NULL) && (dblock.dbuf.typeflag != '1') &&
2704 (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
2705 (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
2706 (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
2707 (dblock.dbuf.typeflag != 'L') &&
2708 (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
2709 (dblock.dbuf.typeflag != 'X')) {
2710 return (1);
2712 return (0);
2715 #if defined(O_XATTR)
2716 static int
2717 save_cwd(void)
2719 return (open(".", O_RDONLY));
2721 #endif
2723 #if defined(O_XATTR)
2724 static void
2725 rest_cwd(int *cwd)
2727 if (*cwd != -1) {
2728 if (fchdir(*cwd) < 0) {
2729 vperror(0, gettext(
2730 "Cannot fchdir to attribute directory"));
2731 exit(1);
2733 (void) close(*cwd);
2734 *cwd = -1;
2737 #endif
2740 * Verify the underlying file system supports the attribute type.
2741 * Only archive extended attribute files when '-@' was specified.
2742 * Only archive system extended attribute files if '-/' was specified.
2744 #if defined(O_XATTR)
2745 static attr_status_t
2746 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
2747 int *ext_attrflg)
2750 * Verify extended attributes are supported/exist. We only
2751 * need to check if we are processing a base file, not an
2752 * extended attribute.
2754 if (attrflg) {
2755 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
2756 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
2759 if (atflag) {
2760 if (!*ext_attrflg) {
2761 #if defined(_PC_SATTR_ENABLED)
2762 if (saflag) {
2763 /* Verify system attributes are supported */
2764 if (sysattr_support(filename,
2765 (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
2766 _PC_SATTR_ENABLED) != 1) {
2767 return (ATTR_SATTR_ERR);
2769 } else
2770 return (ATTR_XATTR_ERR);
2771 #else
2772 return (ATTR_XATTR_ERR);
2773 #endif /* _PC_SATTR_ENABLED */
2776 #if defined(_PC_SATTR_ENABLED)
2777 } else if (saflag) {
2778 /* Verify system attributes are supported */
2779 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
2780 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
2781 return (ATTR_SATTR_ERR);
2783 #endif /* _PC_SATTR_ENABLED */
2784 } else {
2785 return (ATTR_SKIP);
2788 return (ATTR_OK);
2790 #endif
2792 #if defined(O_XATTR)
2794 * Recursively open attribute directories until the attribute directory
2795 * containing the specified attribute, attrname, is opened.
2797 * Currently, only 2 directory levels of attributes are supported, (i.e.,
2798 * extended system attributes on extended attributes). The following are
2799 * the possible input combinations:
2800 * 1. Open the attribute directory of the base file (don't change
2801 * into it).
2802 * attrinfo->parent = NULL
2803 * attrname = '.'
2804 * 2. Open the attribute directory of the base file and change into it.
2805 * attrinfo->parent = NULL
2806 * attrname = <attr> | <sys_attr>
2807 * 3. Open the attribute directory of the base file, change into it,
2808 * then recursively call open_attr_dir() to open the attribute's
2809 * parent directory (don't change into it).
2810 * attrinfo->parent = <attr>
2811 * attrname = '.'
2812 * 4. Open the attribute directory of the base file, change into it,
2813 * then recursively call open_attr_dir() to open the attribute's
2814 * parent directory and change into it.
2815 * attrinfo->parent = <attr>
2816 * attrname = <attr> | <sys_attr>
2818 * An attribute directory will be opened only if the underlying file system
2819 * supports the attribute type, and if the command line specifications (atflag
2820 * and saflag) enable the processing of the attribute type.
2822 * On succesful return, attrinfo->parentfd will be the file descriptor of the
2823 * opened attribute directory. In addition, if the attribute is a read-write
2824 * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2825 * it will be set to 0.
2827 * Possible return values:
2828 * ATTR_OK Successfully opened and, if needed, changed into the
2829 * attribute directory containing attrname.
2830 * ATTR_SKIP The command line specifications don't enable the
2831 * processing of the attribute type.
2832 * ATTR_CHDIR_ERR An error occurred while trying to change into an
2833 * attribute directory.
2834 * ATTR_OPEN_ERR An error occurred while trying to open an
2835 * attribute directory.
2836 * ATTR_XATTR_ERR The underlying file system doesn't support extended
2837 * attributes.
2838 * ATTR_SATTR_ERR The underlying file system doesn't support extended
2839 * system attributes.
2841 static int
2842 open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
2844 attr_status_t rc;
2845 int firsttime = (attrinfo->attr_parentfd == -1);
2846 int saveerrno;
2847 int ext_attr;
2850 * open_attr_dir() was recursively called (input combination number 4),
2851 * close the previously opened file descriptor as we've already changed
2852 * into it.
2854 if (!firsttime) {
2855 (void) close(attrinfo->attr_parentfd);
2856 attrinfo->attr_parentfd = -1;
2860 * Verify that the underlying file system supports the restoration
2861 * of the attribute.
2863 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
2864 &ext_attr)) != ATTR_OK) {
2865 return (rc);
2868 /* Open the base file's attribute directory */
2869 if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
2871 * Save the errno from the attropen so it can be reported
2872 * if the retry of the attropen fails.
2874 saveerrno = errno;
2875 if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
2876 NULL, ".", O_RDONLY, 0)) == -1) {
2878 * Reset typeflag back to real value so passtape
2879 * will skip ahead correctly.
2881 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2882 (void) close(attrinfo->attr_parentfd);
2883 attrinfo->attr_parentfd = -1;
2884 errno = saveerrno;
2885 return (ATTR_OPEN_ERR);
2890 * Change into the parent attribute's directory unless we are
2891 * processing the hidden attribute directory of the base file itself.
2893 if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
2894 if (fchdir(attrinfo->attr_parentfd) != 0) {
2895 saveerrno = errno;
2896 (void) close(attrinfo->attr_parentfd);
2897 attrinfo->attr_parentfd = -1;
2898 errno = saveerrno;
2899 return (ATTR_CHDIR_ERR);
2903 /* Determine if the attribute should be processed */
2904 if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
2905 &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
2906 saveerrno = errno;
2907 (void) close(attrinfo->attr_parentfd);
2908 attrinfo->attr_parentfd = -1;
2909 errno = saveerrno;
2910 return (rc);
2914 * If the attribute is an extended attribute, or extended system
2915 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2916 * recursively call open_attr_dir() to open the attribute directory
2917 * of the parent attribute.
2919 if (firsttime && (attrinfo->attr_parent != NULL)) {
2920 return (open_attr_dir(attrname, attrinfo->attr_parent,
2921 attrinfo->attr_parentfd, attrinfo));
2924 return (ATTR_OK);
2926 #endif
2928 static void
2929 doxtract(char *argv[])
2931 struct stat xtractbuf; /* stat on file after extracting */
2932 blkcnt_t blocks;
2933 off_t bytes;
2934 int ofile;
2935 int newfile; /* Does the file already exist */
2936 int xcnt = 0; /* count # files extracted */
2937 int fcnt = 0; /* count # files in argv list */
2938 int dir;
2939 int dirfd = -1;
2940 int cwd = -1;
2941 int rw_sysattr;
2942 int saveerrno;
2943 uid_t Uid;
2944 char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
2945 char dirname[PATH_MAX+1];
2946 char templink[PATH_MAX+1]; /* temp link with terminating NULL */
2947 int once = 1;
2948 int error;
2949 int symflag;
2950 int want;
2951 attr_data_t *attrinfo = NULL; /* attribute info */
2952 acl_t *aclp = NULL; /* acl info */
2953 char dot[] = "."; /* dirp for using realpath */
2954 timestruc_t time_zero; /* used for call to doDirTimes */
2955 int dircreate;
2956 int convflag;
2957 time_zero.tv_sec = 0;
2958 time_zero.tv_nsec = 0;
2960 /* reset Trusted Extensions variables */
2961 rpath_flag = 0;
2962 lk_rpath_flag = 0;
2963 dir_flag = 0;
2964 mld_flag = 0;
2965 bslundef(&bs_label);
2966 bsllow(&admin_low);
2967 bslhigh(&admin_high);
2968 orig_namep = 0;
2970 dumping = 0; /* for newvol(), et al: we are not writing */
2972 Uid = getuid();
2974 for (;;) {
2975 convflag = 0;
2976 symflag = 0;
2977 dir = 0;
2978 Hiddendir = 0;
2979 rw_sysattr = 0;
2980 ofile = -1;
2982 if (dirfd != -1) {
2983 (void) close(dirfd);
2984 dirfd = -1;
2986 if (ofile != -1) {
2987 if (close(ofile) != 0)
2988 vperror(2, gettext("close error"));
2991 #if defined(O_XATTR)
2992 if (cwd != -1) {
2993 rest_cwd(&cwd);
2995 #endif
2997 /* namep is set by wantit to point to the full name */
2998 if ((want = wantit(argv, &namep, &dirp, &comp,
2999 &attrinfo)) == 0) {
3000 #if defined(O_XATTR)
3001 if (xattrp != NULL) {
3002 free(xattrhead);
3003 xattrp = NULL;
3004 xattr_linkp = NULL;
3005 xattrhead = NULL;
3007 #endif
3008 continue;
3010 if (want == -1)
3011 break;
3013 /* Trusted Extensions */
3015 * During tar extract (x):
3016 * If the pathname of the restored file has been
3017 * reconstructed from the ancillary file,
3018 * use it to process the normal file.
3020 if (mld_flag) { /* Skip over .MLD. directory */
3021 mld_flag = 0;
3022 passtape();
3023 continue;
3025 orig_namep = namep; /* save original */
3026 if (rpath_flag) {
3027 namep = real_path; /* use zone path */
3028 comp = real_path; /* use zone path */
3029 dirp = dot; /* work from the top */
3030 rpath_flag = 0; /* reset */
3033 if (dirfd != -1)
3034 (void) close(dirfd);
3036 (void) strcpy(&dirname[0], namep);
3037 dircreate = checkdir(&dirname[0]);
3039 #if defined(O_XATTR)
3040 if (xattrp != NULL) {
3041 int rc;
3043 if (((cwd = save_cwd()) == -1) ||
3044 ((rc = open_attr_dir(comp, dirp, cwd,
3045 attrinfo)) != ATTR_OK)) {
3046 if (cwd == -1) {
3047 vperror(0, gettext(
3048 "unable to save current working "
3049 "directory while processing "
3050 "attribute %s of %s"),
3051 dirp, attrinfo->attr_path);
3052 } else if (rc != ATTR_SKIP) {
3053 (void) fprintf(vfile,
3054 gettext("tar: cannot open "
3055 "%sattribute %s of file %s: %s\n"),
3056 attrinfo->attr_rw_sysattr ? gettext(
3057 "system ") : "",
3058 comp, dirp, strerror(errno));
3060 free(xattrhead);
3061 xattrp = NULL;
3062 xattr_linkp = NULL;
3063 xattrhead = NULL;
3065 passtape();
3066 continue;
3067 } else {
3068 dirfd = attrinfo->attr_parentfd;
3069 rw_sysattr = attrinfo->attr_rw_sysattr;
3071 } else {
3072 dirfd = open(dirp, O_RDONLY);
3074 #else
3075 dirfd = open(dirp, O_RDONLY);
3076 #endif
3077 if (dirfd == -1) {
3078 (void) fprintf(vfile, gettext(
3079 "tar: cannot open %s: %s\n"),
3080 dirp, strerror(errno));
3081 passtape();
3082 continue;
3085 if (xhdr_flgs & _X_LINKPATH)
3086 (void) strcpy(templink, Xtarhdr.x_linkpath);
3087 else {
3088 #if defined(O_XATTR)
3089 if (xattrp && dblock.dbuf.typeflag == '1') {
3090 (void) sprintf(templink, "%.*s", NAMSIZ,
3091 xattrp->h_names);
3092 } else {
3093 (void) sprintf(templink, "%.*s", NAMSIZ,
3094 dblock.dbuf.linkname);
3096 #else
3097 (void) sprintf(templink, "%.*s", NAMSIZ,
3098 dblock.dbuf.linkname);
3099 #endif
3102 if (Fflag) {
3103 if (checkf(namep, is_directory(namep), Fflag) == 0) {
3104 passtape();
3105 continue;
3109 if (checkw('x', namep) == 0) {
3110 passtape();
3111 continue;
3113 if (once) {
3114 if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
3115 if (geteuid() == (uid_t)0) {
3116 checkflag = 1;
3117 pflag = 1;
3118 } else {
3119 /* get file creation mask */
3120 Oumask = umask(0);
3121 (void) umask(Oumask);
3123 once = 0;
3124 } else {
3125 if (geteuid() == (uid_t)0) {
3126 pflag = 1;
3127 checkflag = 2;
3129 if (!pflag) {
3130 /* get file creation mask */
3131 Oumask = umask(0);
3132 (void) umask(Oumask);
3134 once = 0;
3138 #if defined(O_XATTR)
3140 * Handle extraction of hidden attr dir.
3141 * Dir is automatically created, we only
3142 * need to update mode and perm's.
3144 if ((xattrp != NULL) && Hiddendir == 1) {
3145 bytes = stbuf.st_size;
3146 blocks = TBLOCKS(bytes);
3147 if (vflag) {
3148 (void) fprintf(vfile,
3149 "x %s%s%s, %" FMT_off_t " %s, ", namep,
3150 gettext(" attribute "),
3151 xattrapath, bytes,
3152 gettext("bytes"));
3153 if (NotTape)
3154 (void) fprintf(vfile,
3155 "%" FMT_blkcnt_t "K\n", K(blocks));
3156 else
3157 (void) fprintf(vfile, gettext("%"
3158 FMT_blkcnt_t " tape blocks\n"),
3159 blocks);
3163 * Set the permissions and mode of the attribute
3164 * unless the attribute is a system attribute (can't
3165 * successfully do this) or the hidden attribute
3166 * directory (".") of an attribute (when the attribute
3167 * is restored, the hidden attribute directory of an
3168 * attribute is transient). Note: when the permissions
3169 * and mode are set for the hidden attribute directory
3170 * of a file on a system supporting extended system
3171 * attributes, even though it returns successfully, it
3172 * will not have any affect since the attribute
3173 * directory is transient.
3175 if (attrinfo->attr_parent == NULL) {
3176 if (fchownat(dirfd, ".", stbuf.st_uid,
3177 stbuf.st_gid, 0) != 0) {
3178 vperror(0, gettext(
3179 "%s%s%s: failed to set ownership "
3180 "of attribute directory"), namep,
3181 gettext(" attribute "), xattrapath);
3184 if (fchmod(dirfd, stbuf.st_mode) != 0) {
3185 vperror(0, gettext(
3186 "%s%s%s: failed to set permissions "
3187 "of attribute directory"), namep,
3188 gettext(" attribute "), xattrapath);
3191 goto filedone;
3193 #endif
3195 if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
3196 dir = 1;
3197 if (vflag) {
3198 (void) fprintf(vfile, "x %s, 0 %s, ",
3199 &dirname[0], gettext("bytes"));
3200 if (NotTape)
3201 (void) fprintf(vfile, "0K\n");
3202 else
3203 (void) fprintf(vfile, gettext("%"
3204 FMT_blkcnt_t " tape blocks\n"),
3205 (blkcnt_t)0);
3207 goto filedone;
3210 if (dblock.dbuf.typeflag == '6') { /* FIFO */
3211 if (rmdir(namep) < 0) {
3212 if (errno == ENOTDIR)
3213 (void) unlink(namep);
3215 linkp = templink;
3216 if (*linkp != NULL) {
3217 if (Aflag && *linkp == '/')
3218 linkp++;
3219 if (link(linkp, namep) < 0) {
3220 (void) fprintf(stderr, gettext(
3221 "tar: %s: cannot link\n"), namep);
3222 continue;
3224 if (vflag)
3225 (void) fprintf(vfile, gettext(
3226 "x %s linked to %s\n"), namep,
3227 linkp);
3228 xcnt++; /* increment # files extracted */
3229 continue;
3231 if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
3232 (int)Gen.g_devmajor) < 0) {
3233 vperror(0, gettext("%s: mknod failed"), namep);
3234 continue;
3236 bytes = stbuf.st_size;
3237 blocks = TBLOCKS(bytes);
3238 if (vflag) {
3239 (void) fprintf(vfile, "x %s, %" FMT_off_t
3240 " %s, ", namep, bytes, gettext("bytes"));
3241 if (NotTape)
3242 (void) fprintf(vfile, "%" FMT_blkcnt_t
3243 "K\n", K(blocks));
3244 else
3245 (void) fprintf(vfile, gettext("%"
3246 FMT_blkcnt_t " tape blocks\n"),
3247 blocks);
3249 goto filedone;
3251 if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
3252 if (rmdir(namep) < 0) {
3253 if (errno == ENOTDIR)
3254 (void) unlink(namep);
3256 linkp = templink;
3257 if (*linkp != NULL) {
3258 if (Aflag && *linkp == '/')
3259 linkp++;
3260 if (link(linkp, namep) < 0) {
3261 (void) fprintf(stderr, gettext(
3262 "tar: %s: cannot link\n"), namep);
3263 continue;
3265 if (vflag)
3266 (void) fprintf(vfile, gettext(
3267 "x %s linked to %s\n"), namep,
3268 linkp);
3269 xcnt++; /* increment # files extracted */
3270 continue;
3272 if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
3273 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3274 vperror(0, gettext(
3275 "%s: mknod failed"), namep);
3276 continue;
3278 bytes = stbuf.st_size;
3279 blocks = TBLOCKS(bytes);
3280 if (vflag) {
3281 (void) fprintf(vfile, "x %s, %" FMT_off_t
3282 " %s, ", namep, bytes, gettext("bytes"));
3283 if (NotTape)
3284 (void) fprintf(vfile, "%" FMT_blkcnt_t
3285 "K\n", K(blocks));
3286 else
3287 (void) fprintf(vfile, gettext("%"
3288 FMT_blkcnt_t " tape blocks\n"),
3289 blocks);
3291 goto filedone;
3292 } else if (dblock.dbuf.typeflag == '3' && Uid) {
3293 (void) fprintf(stderr, gettext(
3294 "Can't create special %s\n"), namep);
3295 continue;
3298 /* BLOCK SPECIAL */
3300 if (dblock.dbuf.typeflag == '4' && !Uid) {
3301 if (rmdir(namep) < 0) {
3302 if (errno == ENOTDIR)
3303 (void) unlink(namep);
3305 linkp = templink;
3306 if (*linkp != NULL) {
3307 if (Aflag && *linkp == '/')
3308 linkp++;
3309 if (link(linkp, namep) < 0) {
3310 (void) fprintf(stderr, gettext(
3311 "tar: %s: cannot link\n"), namep);
3312 continue;
3314 if (vflag)
3315 (void) fprintf(vfile, gettext(
3316 "x %s linked to %s\n"), namep,
3317 linkp);
3318 xcnt++; /* increment # files extracted */
3319 continue;
3321 if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
3322 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3323 vperror(0, gettext("%s: mknod failed"), namep);
3324 continue;
3326 bytes = stbuf.st_size;
3327 blocks = TBLOCKS(bytes);
3328 if (vflag) {
3329 (void) fprintf(vfile, gettext("x %s, %"
3330 FMT_off_t " bytes, "), namep, bytes);
3331 if (NotTape)
3332 (void) fprintf(vfile, "%" FMT_blkcnt_t
3333 "K\n", K(blocks));
3334 else
3335 (void) fprintf(vfile, gettext("%"
3336 FMT_blkcnt_t " tape blocks\n"),
3337 blocks);
3339 goto filedone;
3340 } else if (dblock.dbuf.typeflag == '4' && Uid) {
3341 (void) fprintf(stderr,
3342 gettext("Can't create special %s\n"), namep);
3343 continue;
3345 if (dblock.dbuf.typeflag == '2') { /* symlink */
3346 if ((Tflag) && (lk_rpath_flag == 1))
3347 linkp = lk_real_path;
3348 else
3349 linkp = templink;
3350 if (Aflag && *linkp == '/')
3351 linkp++;
3352 if (rmdir(namep) < 0) {
3353 if (errno == ENOTDIR)
3354 (void) unlink(namep);
3356 if (symlink(linkp, namep) < 0) {
3357 vperror(0, gettext("%s: symbolic link failed"),
3358 namep);
3359 continue;
3361 if (vflag)
3362 (void) fprintf(vfile, gettext(
3363 "x %s symbolic link to %s\n"),
3364 namep, linkp);
3366 symflag = AT_SYMLINK_NOFOLLOW;
3367 goto filedone;
3369 if (dblock.dbuf.typeflag == '1') {
3370 linkp = templink;
3371 if (Aflag && *linkp == '/')
3372 linkp++;
3373 if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
3374 if (errno == ENOTDIR)
3375 (void) unlinkat(dirfd, comp, 0);
3377 #if defined(O_XATTR)
3378 if (xattrp && xattr_linkp) {
3379 if (fchdir(dirfd) < 0) {
3380 vperror(0, gettext(
3381 "Cannot fchdir to attribute "
3382 "directory %s"),
3383 (attrinfo->attr_parent == NULL) ?
3384 dirp : attrinfo->attr_parent);
3385 exit(1);
3388 error = link(xattr_linkaname, xattrapath);
3389 } else {
3390 error = link(linkp, namep);
3392 #else
3393 error = link(linkp, namep);
3394 #endif
3396 if (error < 0) {
3397 (void) fprintf(stderr, gettext(
3398 "tar: %s%s%s: cannot link\n"),
3399 namep, (xattr_linkp != NULL) ?
3400 gettext(" attribute ") : "",
3401 (xattr_linkp != NULL) ?
3402 xattrapath : "");
3403 continue;
3405 if (vflag)
3406 (void) fprintf(vfile, gettext(
3407 "x %s%s%s linked to %s%s%s\n"), namep,
3408 (xattr_linkp != NULL) ?
3409 gettext(" attribute ") : "",
3410 (xattr_linkp != NULL) ?
3411 xattr_linkaname : "",
3412 linkp,
3413 (xattr_linkp != NULL) ?
3414 gettext(" attribute ") : "",
3415 (xattr_linkp != NULL) ? xattrapath : "");
3416 xcnt++; /* increment # files extracted */
3417 #if defined(O_XATTR)
3418 if (xattrp != NULL) {
3419 free(xattrhead);
3420 xattrp = NULL;
3421 xattr_linkp = NULL;
3422 xattrhead = NULL;
3424 #endif
3425 continue;
3428 /* REGULAR FILES */
3430 if (convtoreg(stbuf.st_size)) {
3431 convflag = 1;
3432 if (errflag) {
3433 (void) fprintf(stderr, gettext(
3434 "tar: %s: typeflag '%c' not recognized\n"),
3435 namep, dblock.dbuf.typeflag);
3436 done(1);
3437 } else {
3438 (void) fprintf(stderr, gettext(
3439 "tar: %s: typeflag '%c' not recognized, "
3440 "converting to regular file\n"), namep,
3441 dblock.dbuf.typeflag);
3442 Errflg = 1;
3445 if (dblock.dbuf.typeflag == '0' ||
3446 dblock.dbuf.typeflag == NULL || convflag) {
3447 delete_target(dirfd, comp, namep);
3448 linkp = templink;
3449 if (*linkp != NULL) {
3450 if (Aflag && *linkp == '/')
3451 linkp++;
3452 if (link(linkp, comp) < 0) {
3453 (void) fprintf(stderr, gettext(
3454 "tar: %s: cannot link\n"), namep);
3455 continue;
3457 if (vflag)
3458 (void) fprintf(vfile, gettext(
3459 "x %s linked to %s\n"), comp,
3460 linkp);
3461 xcnt++; /* increment # files extracted */
3462 #if defined(O_XATTR)
3463 if (xattrp != NULL) {
3464 free(xattrhead);
3465 xattrp = NULL;
3466 xattr_linkp = NULL;
3467 xattrhead = NULL;
3469 #endif
3470 continue;
3472 newfile = ((fstatat(dirfd, comp,
3473 &xtractbuf, 0) == -1) ? TRUE : FALSE);
3474 ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
3475 stbuf.st_mode & MODEMASK);
3476 saveerrno = errno;
3478 #if defined(O_XATTR)
3479 if (xattrp != NULL) {
3480 if (ofile < 0) {
3481 ofile = retry_open_attr(dirfd, cwd,
3482 dirp, attrinfo->attr_parent, comp,
3483 O_RDWR|O_CREAT|O_TRUNC,
3484 stbuf.st_mode & MODEMASK);
3487 #endif
3488 if (ofile < 0) {
3489 errno = saveerrno;
3490 (void) fprintf(stderr, gettext(
3491 "tar: %s%s%s%s - cannot create\n"),
3492 (xattrp == NULL) ? "" : (rw_sysattr ?
3493 gettext("system attribute ") :
3494 gettext("attribute ")),
3495 (xattrp == NULL) ? "" : xattrapath,
3496 (xattrp == NULL) ? "" : gettext(" of "),
3497 (xattrp == NULL) ? comp : namep);
3498 if (errflag)
3499 done(1);
3500 else
3501 Errflg = 1;
3502 #if defined(O_XATTR)
3503 if (xattrp != NULL) {
3504 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
3505 free(xattrhead);
3506 xattrp = NULL;
3507 xattr_linkp = NULL;
3508 xattrhead = NULL;
3510 #endif
3511 passtape();
3512 continue;
3515 if (Tflag && (check_ext_attr(namep) == 0)) {
3516 if (errflag)
3517 done(1);
3518 else
3519 Errflg = 1;
3520 passtape();
3521 continue;
3524 if (extno != 0) { /* file is in pieces */
3525 if (extotal < 1 || extotal > MAXEXT)
3526 (void) fprintf(stderr, gettext(
3527 "tar: ignoring bad extent info for "
3528 "%s%s%s%s\n"),
3529 (xattrp == NULL) ? "" : (rw_sysattr ?
3530 gettext("system attribute ") :
3531 gettext("attribute ")),
3532 (xattrp == NULL) ? "" : xattrapath,
3533 (xattrp == NULL) ? "" : gettext(" of "),
3534 (xattrp == NULL) ? comp : namep);
3535 else {
3536 /* extract it */
3537 (void) xsfile(rw_sysattr, ofile);
3540 extno = 0; /* let everyone know file is not split */
3541 bytes = stbuf.st_size;
3542 blocks = TBLOCKS(bytes);
3543 if (vflag) {
3544 (void) fprintf(vfile,
3545 "x %s%s%s, %" FMT_off_t " %s, ",
3546 (xattrp == NULL) ? "" : dirp,
3547 (xattrp == NULL) ? "" : (rw_sysattr ?
3548 gettext(" system attribute ") :
3549 gettext(" attribute ")),
3550 (xattrp == NULL) ? namep : xattrapath, bytes,
3551 gettext("bytes"));
3552 if (NotTape)
3553 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
3554 K(blocks));
3555 else
3556 (void) fprintf(vfile, gettext("%"
3557 FMT_blkcnt_t " tape blocks\n"), blocks);
3560 if (xblocks(rw_sysattr, bytes, ofile) != 0) {
3561 #if defined(O_XATTR)
3562 if (xattrp != NULL) {
3563 free(xattrhead);
3564 xattrp = NULL;
3565 xattr_linkp = NULL;
3566 xattrhead = NULL;
3568 #endif
3569 continue;
3571 filedone:
3572 if (mflag == 0 && !symflag) {
3573 if (dir)
3574 doDirTimes(namep, stbuf.st_mtim);
3576 else
3577 #if defined(O_XATTR)
3578 if (xattrp != NULL) {
3580 * Set the time on the attribute unless
3581 * the attribute is a system attribute
3582 * (can't successfully do this) or the
3583 * hidden attribute directory, "." (the
3584 * time on the hidden attribute
3585 * directory will be updated when
3586 * attributes are restored, otherwise
3587 * it's transient).
3589 if (!rw_sysattr && (Hiddendir == 0)) {
3590 setPathTimes(dirfd, comp,
3591 stbuf.st_mtim);
3593 } else
3594 setPathTimes(dirfd, comp,
3595 stbuf.st_mtim);
3596 #else
3597 setPathTimes(dirfd, comp, stbuf.st_mtim);
3598 #endif
3601 /* moved this code from above */
3602 if (pflag && !symflag && Hiddendir == 0) {
3603 if (xattrp != NULL)
3604 (void) fchmod(ofile, stbuf.st_mode & MODEMASK);
3605 else
3606 (void) chmod(namep, stbuf.st_mode & MODEMASK);
3611 * Because ancillary file preceeds the normal file,
3612 * acl info may have been retrieved (in aclp).
3613 * All file types are directed here (go filedone).
3614 * Always restore ACLs if there are ACLs.
3616 if (aclp != NULL) {
3617 int ret;
3619 #if defined(O_XATTR)
3620 if (xattrp != NULL) {
3621 if (Hiddendir)
3622 ret = facl_set(dirfd, aclp);
3623 else
3624 ret = facl_set(ofile, aclp);
3625 } else {
3626 ret = acl_set(namep, aclp);
3628 #else
3629 ret = acl_set(namep, aclp);
3630 #endif
3631 if (ret < 0) {
3632 if (pflag) {
3633 (void) fprintf(stderr, gettext(
3634 "%s%s%s%s: failed to set acl "
3635 "entries\n"), namep,
3636 (xattrp == NULL) ? "" :
3637 (rw_sysattr ? gettext(
3638 " system attribute ") :
3639 gettext(" attribute ")),
3640 (xattrp == NULL) ? "" :
3641 xattrapath);
3643 /* else: silent and continue */
3645 acl_free(aclp);
3646 aclp = NULL;
3649 if (!oflag)
3650 /* set file ownership */
3651 resugname(dirfd, comp, symflag);
3653 if (pflag && newfile == TRUE && !dir &&
3654 (dblock.dbuf.typeflag == '0' ||
3655 dblock.dbuf.typeflag == NULL ||
3656 convflag || dblock.dbuf.typeflag == '1')) {
3657 if (fstat(ofile, &xtractbuf) == -1)
3658 (void) fprintf(stderr, gettext(
3659 "tar: cannot stat extracted file "
3660 "%s%s%s%s\n"),
3661 (xattrp == NULL) ? "" : (rw_sysattr ?
3662 gettext("system attribute ") :
3663 gettext("attribute ")),
3664 (xattrp == NULL) ? "" : xattrapath,
3665 (xattrp == NULL) ? "" :
3666 gettext(" of "), namep);
3668 else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
3669 != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
3670 (void) fprintf(stderr, gettext(
3671 "tar: warning - file permissions have "
3672 "changed for %s%s%s%s (are 0%o, should be "
3673 "0%o)\n"),
3674 (xattrp == NULL) ? "" : (rw_sysattr ?
3675 gettext("system attribute ") :
3676 gettext("attribute ")),
3677 (xattrp == NULL) ? "" : xattrapath,
3678 (xattrp == NULL) ? "" :
3679 gettext(" of "), namep,
3680 xtractbuf.st_mode, stbuf.st_mode);
3684 #if defined(O_XATTR)
3685 if (xattrp != NULL) {
3686 free(xattrhead);
3687 xattrp = NULL;
3688 xattr_linkp = NULL;
3689 xattrhead = NULL;
3691 #endif
3693 if (ofile != -1) {
3694 (void) close(dirfd);
3695 dirfd = -1;
3696 if (close(ofile) != 0)
3697 vperror(2, gettext("close error"));
3698 ofile = -1;
3700 xcnt++; /* increment # files extracted */
3704 * Process ancillary file.
3708 if (dblock.dbuf.typeflag == 'A') { /* acl info */
3709 char buf[TBLOCK];
3710 char *secp;
3711 char *tp;
3712 int attrsize;
3713 int cnt;
3715 /* reset Trusted Extensions flags */
3716 dir_flag = 0;
3717 mld_flag = 0;
3718 lk_rpath_flag = 0;
3719 rpath_flag = 0;
3721 if (pflag) {
3722 bytes = stbuf.st_size;
3723 if ((secp = malloc((int)bytes)) == NULL) {
3724 (void) fprintf(stderr, gettext(
3725 "Insufficient memory for acl\n"));
3726 passtape();
3727 continue;
3729 tp = secp;
3730 blocks = TBLOCKS(bytes);
3733 * Display a line for each ancillary file.
3735 if (vflag && Tflag)
3736 (void) fprintf(vfile, "x %s(A), %"
3737 FMT_blkcnt_t " %s, %"
3738 FMT_blkcnt_t " %s\n",
3739 namep, bytes, gettext("bytes"),
3740 blocks, gettext("tape blocks"));
3742 while (blocks-- > 0) {
3743 readtape(buf);
3744 if (bytes <= TBLOCK) {
3745 (void) memcpy(tp, buf,
3746 (size_t)bytes);
3747 break;
3748 } else {
3749 (void) memcpy(tp, buf,
3750 TBLOCK);
3751 tp += TBLOCK;
3753 bytes -= TBLOCK;
3755 bytes = stbuf.st_size;
3756 /* got all attributes in secp */
3757 tp = secp;
3758 do {
3759 attr = (struct sec_attr *)tp;
3760 switch (attr->attr_type) {
3761 case UFSD_ACL:
3762 case ACE_ACL:
3763 (void) sscanf(attr->attr_len,
3764 "%7o",
3765 (uint_t *)
3766 &cnt);
3767 /* header is 8 */
3768 attrsize = 8 + (int)strlen(
3769 &attr->attr_info[0]) + 1;
3770 error =
3771 acl_fromtext(
3772 &attr->attr_info[0], &aclp);
3774 if (error != 0) {
3775 (void) fprintf(stderr,
3776 gettext(
3777 "aclfromtext "
3778 "failed: %s\n"),
3779 acl_strerror(
3780 error));
3781 bytes -= attrsize;
3782 break;
3784 if (acl_cnt(aclp) != cnt) {
3785 (void) fprintf(stderr,
3786 gettext(
3787 "aclcnt error\n"));
3788 bytes -= attrsize;
3789 break;
3791 bytes -= attrsize;
3792 break;
3794 /* Trusted Extensions */
3796 case DIR_TYPE:
3797 case LBL_TYPE:
3798 case APRIV_TYPE:
3799 case FPRIV_TYPE:
3800 case COMP_TYPE:
3801 case LK_COMP_TYPE:
3802 case ATTR_FLAG_TYPE:
3803 attrsize =
3804 sizeof (struct sec_attr) +
3805 strlen(&attr->attr_info[0]);
3806 bytes -= attrsize;
3807 if (Tflag)
3808 extract_attr(&namep,
3809 attr);
3810 break;
3812 default:
3813 (void) fprintf(stderr, gettext(
3814 "unrecognized attr"
3815 " type\n"));
3816 bytes = (off_t)0;
3817 break;
3820 /* next attributes */
3821 tp += attrsize;
3822 } while (bytes != 0);
3823 free(secp);
3824 } else {
3825 passtape();
3827 } /* acl */
3829 } /* for */
3832 * Ensure that all the directories still on the directory stack
3833 * get their modification times set correctly by flushing the
3834 * stack.
3837 doDirTimes(NULL, time_zero);
3839 #if defined(O_XATTR)
3840 if (xattrp != NULL) {
3841 free(xattrhead);
3842 xattrp = NULL;
3843 xattr_linkp = NULL;
3844 xattrhead = NULL;
3846 #endif
3849 * Check if the number of files extracted is different from the
3850 * number of files listed on the command line
3852 if (fcnt > xcnt) {
3853 (void) fprintf(stderr,
3854 gettext("tar: %d file(s) not extracted\n"),
3855 fcnt-xcnt);
3856 Errflg = 1;
3861 * xblocks extract file/extent from tape to output file
3863 * xblocks(issysattr, bytes, ofile);
3865 * issysattr flag set if the files being extracted
3866 * is an extended system attribute file.
3867 * unsigned long long bytes size of extent or file to be extracted
3868 * ofile output file
3870 * called by doxtract() and xsfile()
3873 static int
3874 xblocks(int issysattr, off_t bytes, int ofile)
3876 char *buf;
3877 char tempname[NAMSIZ+1];
3878 size_t maxwrite;
3879 size_t bytesread;
3880 size_t piosize; /* preferred I/O size */
3881 struct stat tsbuf;
3883 /* Don't need to do anything if this is a zero size file */
3884 if (bytes <= 0) {
3885 return (0);
3889 * To figure out the size of the buffer used to accumulate data
3890 * from readtape() and to write to the file, we need to determine
3891 * the largest chunk of data to be written to the file at one time.
3892 * This is determined based on the smallest of the following two
3893 * things:
3894 * 1) The size of the archived file.
3895 * 2) The preferred I/O size of the file.
3897 if (issysattr || (bytes <= TBLOCK)) {
3899 * Writes to system attribute files must be
3900 * performed in one operation.
3902 maxwrite = bytes;
3903 } else {
3905 * fstat() the file to get the preferred I/O size.
3906 * If it fails, then resort back to just writing
3907 * one block at a time.
3909 if (fstat(ofile, &tsbuf) == 0) {
3910 piosize = tsbuf.st_blksize;
3911 } else {
3912 piosize = TBLOCK;
3914 maxwrite = min(bytes, piosize);
3918 * The buffer used to accumulate the data for the write operation
3919 * needs to be the maximum number of bytes to be written rounded up
3920 * to the nearest TBLOCK since readtape reads one block at a time.
3922 if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
3923 fatal(gettext("cannot allocate buffer"));
3926 while (bytes > 0) {
3929 * readtape() obtains one block (TBLOCK) of data at a time.
3930 * Accumulate as many blocks of data in buf as we can write
3931 * in one operation.
3933 for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
3934 readtape(buf + bytesread);
3937 if (write(ofile, buf, maxwrite) < 0) {
3938 int saveerrno = errno;
3940 if (xhdr_flgs & _X_PATH)
3941 (void) strlcpy(tempname, Xtarhdr.x_path,
3942 sizeof (tempname));
3943 else
3944 (void) sprintf(tempname, "%.*s", NAMSIZ,
3945 dblock.dbuf.name);
3947 * If the extended system attribute being extracted
3948 * contains attributes that the user needs privileges
3949 * for, then just display a warning message, skip
3950 * the extraction of this file, and return.
3952 if ((saveerrno == EPERM) && issysattr) {
3953 (void) fprintf(stderr, gettext(
3954 "tar: unable to extract system attribute "
3955 "%s: insufficient privileges\n"), tempname);
3956 Errflg = 1;
3957 (void) free(buf);
3958 return (1);
3959 } else {
3960 (void) fprintf(stderr, gettext(
3961 "tar: %s: HELP - extract write error\n"),
3962 tempname);
3963 done(2);
3966 bytes -= maxwrite;
3969 * If we've reached this point and there is still data
3970 * to be written, maxwrite had to have been determined
3971 * by the preferred I/O size. If the number of bytes
3972 * left to write is smaller than the preferred I/O size,
3973 * then we're about to do our final write to the file, so
3974 * just set maxwrite to the number of bytes left to write.
3976 if ((bytes > 0) && (bytes < maxwrite)) {
3977 maxwrite = bytes;
3980 free(buf);
3982 return (0);
3986 * xsfile extract split file
3988 * xsfile(ofd); ofd = output file descriptor
3990 * file extracted and put in ofd via xblocks()
3992 * NOTE: only called by doxtract() to extract one large file
3995 static union hblock savedblock; /* to ensure same file across volumes */
3997 static int
3998 xsfile(int issysattr, int ofd)
4000 int i, c;
4001 int sysattrerr = 0;
4002 char name[PATH_MAX+1]; /* holds name for diagnostics */
4003 int extents, totalext;
4004 off_t bytes, totalbytes;
4006 if (xhdr_flgs & _X_PATH)
4007 (void) strcpy(name, Xtarhdr.x_path);
4008 else
4009 (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
4011 totalbytes = (off_t)0; /* in case we read in half the file */
4012 totalext = 0; /* these keep count */
4014 (void) fprintf(stderr, gettext(
4015 "tar: %s split across %d volumes\n"), name, extotal);
4017 /* make sure we do extractions in order */
4018 if (extno != 1) { /* starting in middle of file? */
4019 (void) printf(gettext(
4020 "tar: first extent read is not #1\n"
4021 "OK to read file beginning with extent #%d (%s/%s) ? "),
4022 extno, yesstr, nostr);
4023 if (yes() == 0) {
4024 canit:
4025 passtape();
4026 if (close(ofd) != 0)
4027 vperror(2, gettext("close error"));
4028 if (sysattrerr) {
4029 return (1);
4030 } else {
4031 return (0);
4035 extents = extotal;
4036 i = extno;
4037 /*CONSTCOND*/
4038 while (1) {
4039 if (xhdr_flgs & _X_SIZE) {
4040 bytes = extsize;
4041 } else {
4042 bytes = stbuf.st_size;
4045 if (vflag)
4046 (void) fprintf(vfile, "+++ x %s [%s #%d], %"
4047 FMT_off_t " %s, %ldK\n",
4048 name, gettext("extent"), extno,
4049 bytes, gettext("bytes"),
4050 (long)K(TBLOCKS(bytes)));
4051 if (xblocks(issysattr, bytes, ofd) != 0) {
4052 sysattrerr = 1;
4053 goto canit;
4056 totalbytes += bytes;
4057 totalext++;
4058 if (++i > extents)
4059 break;
4061 /* get next volume and verify it's the right one */
4062 copy(&savedblock, &dblock);
4063 tryagain:
4064 newvol();
4065 xhdr_flgs = 0;
4066 getdir();
4067 if (Xhdrflag > 0)
4068 (void) get_xdata(); /* Get x-header & regular hdr */
4069 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
4070 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
4071 xhdr_flgs |= _X_XHDR;
4073 if (endtape()) { /* seemingly empty volume */
4074 (void) fprintf(stderr, gettext(
4075 "tar: first record is null\n"));
4076 asknicely:
4077 (void) fprintf(stderr, gettext(
4078 "tar: need volume with extent #%d of %s\n"),
4079 i, name);
4080 goto tryagain;
4082 if (notsame()) {
4083 (void) fprintf(stderr, gettext(
4084 "tar: first file on that volume is not "
4085 "the same file\n"));
4086 goto asknicely;
4088 if (i != extno) {
4089 (void) fprintf(stderr, gettext(
4090 "tar: extent #%d received out of order\ntar: "
4091 "should be #%d\n"), extno, i);
4092 (void) fprintf(stderr, gettext(
4093 "Ignore error, Abort this file, or "
4094 "load New volume (i/a/n) ? "));
4095 c = response();
4096 if (c == 'a')
4097 goto canit;
4098 if (c != 'i') /* default to new volume */
4099 goto asknicely;
4100 i = extno; /* okay, start from there */
4103 if (vflag)
4104 (void) fprintf(vfile, gettext(
4105 "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
4106 name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
4108 return (0);
4113 * notsame() check if extract file extent is invalid
4115 * returns true if anything differs between savedblock and dblock
4116 * except extno (extent number), checksum, or size (extent size).
4117 * Determines if this header belongs to the same file as the one we're
4118 * extracting.
4120 * NOTE: though rather bulky, it is only called once per file
4121 * extension, and it can withstand changes in the definition
4122 * of the header structure.
4124 * WARNING: this routine is local to xsfile() above
4127 static int
4128 notsame(void)
4130 return (
4131 (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
4132 (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
4133 (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
4134 (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
4135 (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
4136 (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
4137 (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
4138 (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
4139 (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
4142 static void
4143 dotable(char *argv[])
4145 int tcnt = 0; /* count # files tabled */
4146 int fcnt = 0; /* count # files in argv list */
4147 char *namep, *dirp, *comp;
4148 int want;
4149 char aclchar = ' '; /* either blank or '+' */
4150 char templink[PATH_MAX+1];
4151 attr_data_t *attrinfo = NULL;
4153 dumping = 0;
4155 /* if not on magtape, maximize seek speed */
4156 if (NotTape && !bflag) {
4157 #if SYS_BLOCK > TBLOCK
4158 nblock = SYS_BLOCK / TBLOCK;
4159 #else
4160 nblock = 1;
4161 #endif
4164 for (;;) {
4166 /* namep is set by wantit to point to the full name */
4167 if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
4168 continue;
4169 if (want == -1)
4170 break;
4171 if (dblock.dbuf.typeflag != 'A')
4172 ++tcnt;
4174 if (Fflag) {
4175 if (checkf(namep, is_directory(namep), Fflag) == 0) {
4176 passtape();
4177 continue;
4181 * ACL support:
4182 * aclchar is introduced to indicate if there are
4183 * acl entries. longt() now takes one extra argument.
4185 if (vflag) {
4186 if (dblock.dbuf.typeflag == 'A') {
4187 aclchar = '+';
4188 passtape();
4189 continue;
4191 longt(&stbuf, aclchar);
4192 aclchar = ' ';
4196 #if defined(O_XATTR)
4197 if (xattrp != NULL) {
4198 int issysattr;
4199 char *bn = basename(attrinfo->attr_path);
4202 * We could use sysattr_type() to test whether or not
4203 * the attribute we are processing is really an
4204 * extended system attribute, which as of this writing
4205 * just does a strcmp(), however, sysattr_type() may
4206 * be changed to issue a pathconf() call instead, which
4207 * would require being changed into the parent attribute
4208 * directory. So instead, just do simple string
4209 * comparisons to see if we are processing an extended
4210 * system attribute.
4212 issysattr = is_sysattr(bn);
4214 (void) printf(gettext("%s %sattribute %s"),
4215 xattrp->h_names,
4216 issysattr ? gettext("system ") : "",
4217 attrinfo->attr_path);
4218 } else {
4219 (void) printf("%s", namep);
4221 #else
4222 (void) printf("%s", namep);
4223 #endif
4225 if (extno != 0) {
4226 if (vflag) {
4227 /* keep the '\n' for backwards compatibility */
4228 (void) fprintf(vfile, gettext(
4229 "\n [extent #%d of %d]"), extno, extotal);
4230 } else {
4231 (void) fprintf(vfile, gettext(
4232 " [extent #%d of %d]"), extno, extotal);
4235 if (xhdr_flgs & _X_LINKPATH) {
4236 (void) strcpy(templink, Xtarhdr.x_linkpath);
4237 } else {
4238 #if defined(O_XATTR)
4239 if (xattrp != NULL) {
4240 (void) sprintf(templink,
4241 "file %.*s", NAMSIZ, xattrp->h_names);
4242 } else {
4243 (void) sprintf(templink, "%.*s", NAMSIZ,
4244 dblock.dbuf.linkname);
4246 #else
4247 (void) sprintf(templink, "%.*s", NAMSIZ,
4248 dblock.dbuf.linkname);
4249 #endif
4250 templink[NAMSIZ] = '\0';
4252 if (dblock.dbuf.typeflag == '1') {
4254 * TRANSLATION_NOTE
4255 * Subject is omitted here.
4256 * Translate this as if
4257 * <subject> linked to %s
4259 #if defined(O_XATTR)
4260 if (xattrp != NULL) {
4261 (void) printf(
4262 gettext(" linked to attribute %s"),
4263 xattr_linkp->h_names +
4264 strlen(xattr_linkp->h_names) + 1);
4265 } else {
4266 (void) printf(
4267 gettext(" linked to %s"), templink);
4269 #else
4270 (void) printf(
4271 gettext(" linked to %s"), templink);
4273 #endif
4275 if (dblock.dbuf.typeflag == '2')
4276 (void) printf(gettext(
4278 * TRANSLATION_NOTE
4279 * Subject is omitted here.
4280 * Translate this as if
4281 * <subject> symbolic link to %s
4283 " symbolic link to %s"), templink);
4284 (void) printf("\n");
4285 #if defined(O_XATTR)
4286 if (xattrp != NULL) {
4287 free(xattrhead);
4288 xattrp = NULL;
4289 xattrhead = NULL;
4291 #endif
4292 passtape();
4295 * Check if the number of files tabled is different from the
4296 * number of files listed on the command line
4298 if (fcnt > tcnt) {
4299 (void) fprintf(stderr, gettext(
4300 "tar: %d file(s) not found\n"), fcnt-tcnt);
4301 Errflg = 1;
4305 static void
4306 putempty(blkcnt_t n)
4308 char buf[TBLOCK];
4309 char *cp;
4311 for (cp = buf; cp < &buf[TBLOCK]; )
4312 *cp++ = '\0';
4313 while (n-- > 0)
4314 (void) writetbuf(buf, 1);
4317 static ushort_t Ftype = S_IFMT;
4319 static void
4320 verbose(struct stat *st, char aclchar)
4322 int i, j, temp;
4323 mode_t mode;
4324 char modestr[12];
4326 for (i = 0; i < 11; i++)
4327 modestr[i] = '-';
4328 modestr[i] = '\0';
4330 /* a '+' sign is printed if there is ACL */
4331 modestr[i-1] = aclchar;
4333 mode = st->st_mode;
4334 for (i = 0; i < 3; i++) {
4335 temp = (mode >> (6 - (i * 3)));
4336 j = (i * 3) + 1;
4337 if (S_IROTH & temp)
4338 modestr[j] = 'r';
4339 if (S_IWOTH & temp)
4340 modestr[j + 1] = 'w';
4341 if (S_IXOTH & temp)
4342 modestr[j + 2] = 'x';
4344 temp = st->st_mode & Ftype;
4345 switch (temp) {
4346 case (S_IFIFO):
4347 modestr[0] = 'p';
4348 break;
4349 case (S_IFCHR):
4350 modestr[0] = 'c';
4351 break;
4352 case (S_IFDIR):
4353 modestr[0] = 'd';
4354 break;
4355 case (S_IFBLK):
4356 modestr[0] = 'b';
4357 break;
4358 case (S_IFREG): /* was initialized to '-' */
4359 break;
4360 case (S_IFLNK):
4361 modestr[0] = 'l';
4362 break;
4363 default:
4364 /* This field may be zero in old archives. */
4365 if (is_posix && dblock.dbuf.typeflag != '1') {
4367 * For POSIX compliant archives, the mode field
4368 * consists of 12 bits, ie: the file type bits
4369 * are not stored in dblock.dbuf.mode.
4370 * For files other than hard links, getdir() sets
4371 * the file type bits in the st_mode field of the
4372 * stat structure based upon dblock.dbuf.typeflag.
4374 (void) fprintf(stderr, gettext(
4375 "tar: impossible file type"));
4379 if ((S_ISUID & Gen.g_mode) == S_ISUID)
4380 modestr[3] = 's';
4381 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
4382 modestr[9] = 't';
4383 if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
4384 modestr[6] = 's';
4385 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
4386 modestr[6] = 'l';
4387 (void) fprintf(vfile, "%s", modestr);
4390 static void
4391 longt(struct stat *st, char aclchar)
4393 char fileDate[30];
4394 struct tm *tm;
4396 verbose(st, aclchar);
4397 (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
4399 if (dblock.dbuf.typeflag == '2') {
4400 if (xhdr_flgs & _X_LINKPATH)
4401 st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
4402 else
4403 st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
4404 '\0', NAMSIZ) ?
4405 (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
4407 (void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
4409 tm = localtime(&(st->st_mtime));
4410 (void) strftime(fileDate, sizeof (fileDate),
4411 dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
4412 (void) fprintf(vfile, " %s ", fileDate);
4417 * checkdir - Attempt to ensure that the path represented in name
4418 * exists, and return 1 if this is true and name itself is a
4419 * directory.
4420 * Return 0 if this path cannot be created or if name is not
4421 * a directory.
4424 static int
4425 checkdir(char *name)
4427 char lastChar; /* the last character in name */
4428 char *cp; /* scratch pointer into name */
4429 char *firstSlash = NULL; /* first slash in name */
4430 char *lastSlash = NULL; /* last slash in name */
4431 int nameLen; /* length of name */
4432 int trailingSlash; /* true if name ends in slash */
4433 int leadingSlash; /* true if name begins with slash */
4434 int markedDir; /* true if name denotes a directory */
4435 int success; /* status of makeDir call */
4439 * Scan through the name, and locate first and last slashes.
4442 for (cp = name; *cp; cp++) {
4443 if (*cp == '/') {
4444 if (! firstSlash) {
4445 firstSlash = cp;
4447 lastSlash = cp;
4452 * Determine what you can from the proceeds of the scan.
4455 lastChar = *(cp - 1);
4456 nameLen = (int)(cp - name);
4457 trailingSlash = (lastChar == '/');
4458 leadingSlash = (*name == '/');
4459 markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash);
4461 if (! lastSlash && ! markedDir) {
4463 * The named file does not have any subdrectory
4464 * structure; just bail out.
4467 return (0);
4471 * Make sure that name doesn`t end with slash for the loop.
4472 * This ensures that the makeDir attempt after the loop is
4473 * meaningful.
4476 if (trailingSlash) {
4477 name[nameLen-1] = '\0';
4481 * Make the path one component at a time.
4484 for (cp = strchr(leadingSlash ? name+1 : name, '/');
4486 cp = strchr(cp+1, '/')) {
4487 *cp = '\0';
4488 success = makeDir(name);
4489 *cp = '/';
4491 if (!success) {
4492 name[nameLen-1] = lastChar;
4493 return (0);
4498 * This makes the last component of the name, if it is a
4499 * directory.
4502 if (markedDir) {
4503 if (! makeDir(name)) {
4504 name[nameLen-1] = lastChar;
4505 return (0);
4509 name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
4510 return (markedDir);
4514 * resugname - Restore the user name and group name. Search the NIS
4515 * before using the uid and gid.
4516 * (It is presumed that an archive entry cannot be
4517 * simultaneously a symlink and some other type.)
4520 static void
4521 resugname(int dirfd, /* dir fd file resides in */
4522 char *name, /* name of the file to be modified */
4523 int symflag) /* true if file is a symbolic link */
4525 uid_t duid;
4526 gid_t dgid;
4527 struct stat *sp = &stbuf;
4528 char *u_g_name;
4530 if (checkflag == 1) { /* Extended tar format and euid == 0 */
4533 * Try and extract the intended uid and gid from the name
4534 * service before believing the uid and gid in the header.
4536 * In the case where we archived a setuid or setgid file
4537 * owned by someone with a large uid, then it will
4538 * have made it into the archive with a uid of nobody. If
4539 * the corresponding username doesn't appear to exist, then we
4540 * want to make sure it *doesn't* end up as setuid nobody!
4542 * Our caller will print an error message about the fact
4543 * that the restore didn't work out quite right ..
4545 if (xhdr_flgs & _X_UNAME)
4546 u_g_name = Xtarhdr.x_uname;
4547 else
4548 u_g_name = dblock.dbuf.uname;
4549 if ((duid = getuidbyname(u_g_name)) == -1) {
4550 if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
4551 (sp->st_mode & S_ISUID) == S_ISUID)
4552 (void) chmod(name,
4553 MODEMASK & sp->st_mode & ~S_ISUID);
4554 duid = sp->st_uid;
4557 /* (Ditto for gids) */
4559 if (xhdr_flgs & _X_GNAME)
4560 u_g_name = Xtarhdr.x_gname;
4561 else
4562 u_g_name = dblock.dbuf.gname;
4563 if ((dgid = getgidbyname(u_g_name)) == -1) {
4564 if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
4565 (sp->st_mode & S_ISGID) == S_ISGID)
4566 (void) chmod(name,
4567 MODEMASK & sp->st_mode & ~S_ISGID);
4568 dgid = sp->st_gid;
4570 } else if (checkflag == 2) { /* tar format and euid == 0 */
4571 duid = sp->st_uid;
4572 dgid = sp->st_gid;
4574 if ((checkflag == 1) || (checkflag == 2))
4575 (void) fchownat(dirfd, name, duid, dgid, symflag);
4578 /*ARGSUSED*/
4579 static void
4580 onintr(int sig)
4582 (void) signal(SIGINT, SIG_IGN);
4583 term++;
4586 /*ARGSUSED*/
4587 static void
4588 onquit(int sig)
4590 (void) signal(SIGQUIT, SIG_IGN);
4591 term++;
4594 /*ARGSUSED*/
4595 static void
4596 onhup(int sig)
4598 (void) signal(SIGHUP, SIG_IGN);
4599 term++;
4602 static void
4603 tomodes(struct stat *sp)
4605 uid_t uid;
4606 gid_t gid;
4608 bzero(dblock.dummy, TBLOCK);
4611 * If the uid or gid is too large, we can't put it into
4612 * the archive. We could fail to put anything in the
4613 * archive at all .. but most of the time the name service
4614 * will save the day when we do a lookup at restore time.
4616 * Instead we choose a "safe" uid and gid, and fix up whether
4617 * or not the setuid and setgid bits are left set to extraction
4618 * time.
4620 if (Eflag) {
4621 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
4622 xhdr_flgs |= _X_UID;
4623 Xtarhdr.x_uid = uid;
4625 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
4626 xhdr_flgs |= _X_GID;
4627 Xtarhdr.x_gid = gid;
4629 if (sp->st_size > TAR_OFFSET_MAX) {
4630 xhdr_flgs |= _X_SIZE;
4631 Xtarhdr.x_filesz = sp->st_size;
4632 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4633 (off_t)0);
4634 } else
4635 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4636 sp->st_size);
4637 } else {
4638 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4639 sp->st_size);
4641 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
4642 uid = UID_NOBODY;
4643 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
4644 gid = GID_NOBODY;
4645 (void) sprintf(dblock.dbuf.gid, "%07lo", gid);
4646 (void) sprintf(dblock.dbuf.uid, "%07lo", uid);
4647 (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
4648 (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
4651 static int
4652 #ifdef EUC
4654 * Warning: the result of this function depends whether 'char' is a
4655 * signed or unsigned data type. This a source of potential
4656 * non-portability among heterogeneous systems. It is retained here
4657 * for backward compatibility.
4659 checksum_signed(union hblock *dblockp)
4660 #else
4661 checksum(union hblock *dblockp)
4662 #endif /* EUC */
4664 int i;
4665 char *cp;
4667 for (cp = dblockp->dbuf.chksum;
4668 cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
4669 *cp = ' ';
4670 i = 0;
4671 for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
4672 i += *cp;
4673 return (i);
4676 #ifdef EUC
4678 * Generate unsigned checksum, regardless of what C compiler is
4679 * used. Survives in the face of arbitrary 8-bit clean filenames,
4680 * e.g., internationalized filenames.
4682 static int
4683 checksum(union hblock *dblockp)
4685 unsigned i;
4686 unsigned char *cp;
4688 for (cp = (unsigned char *) dblockp->dbuf.chksum;
4689 cp < (unsigned char *)
4690 &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
4691 *cp = ' ';
4692 i = 0;
4693 for (cp = (unsigned char *) dblockp->dummy;
4694 cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
4695 i += *cp;
4697 return (i);
4699 #endif /* EUC */
4702 * If the w flag is set, output the action to be taken and the name of the
4703 * file. Perform the action if the user response is affirmative.
4706 static int
4707 checkw(char c, char *name)
4709 if (wflag) {
4710 (void) fprintf(vfile, "%c ", c);
4711 if (vflag)
4712 longt(&stbuf, ' '); /* do we have acl info here */
4713 (void) fprintf(vfile, "%s: ", name);
4714 if (yes() == 1) {
4715 return (1);
4717 return (0);
4719 return (1);
4723 * When the F flag is set, exclude RCS and SCCS directories (and any files
4724 * or directories under them). If F is set twice, also exclude .o files,
4725 * and files names errs, core, and a.out.
4727 * Return 0 if file should be excluded, 1 otherwise.
4730 static int
4731 checkf(char *longname, int is_dir, int howmuch)
4733 static char fullname[PATH_MAX + 1];
4734 char *dir, *name;
4736 #if defined(O_XATTR)
4738 * If there is an xattr_buf structure associated with this file,
4739 * always return 1.
4741 if (xattrp) {
4742 return (1);
4744 #endif
4747 * First check to see if the base name is an RCS or SCCS directory.
4749 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4750 return (1);
4752 name = basename(fullname);
4753 if (is_dir) {
4754 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4755 return (0);
4759 * If two -F command line options were given then exclude .o files,
4760 * and files named errs, core, and a.out.
4762 if (howmuch > 1 && !is_dir) {
4763 size_t l = strlen(name);
4765 if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
4766 return (0);
4767 if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
4768 strcmp(name, "a.out") == 0)
4769 return (0);
4773 * At this point, check to see if this file has a parent directory
4774 * named RCS or SCCS. If so, then this file should be excluded too.
4775 * The strcpy() operation is done again, because basename(3C) may
4776 * modify the path string passed to it.
4778 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4779 return (1);
4781 dir = dirname(fullname);
4782 while (strcmp(dir, ".") != 0) {
4783 name = basename(dir);
4784 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4785 return (0);
4786 dir = dirname(dir);
4789 return (1);
4792 static int
4793 response(void)
4795 int c;
4797 c = getchar();
4798 if (c != '\n')
4799 while (getchar() != '\n')
4801 else c = 'n';
4802 return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
4805 /* Has file been modified since being put into archive? If so, return > 0. */
4807 static off_t lookup(char *);
4809 static int
4810 checkupdate(char *arg)
4812 char name[PATH_MAX+1];
4813 time_t mtime;
4814 long nsecs;
4815 off_t seekp;
4817 rewind(tfile);
4818 if ((seekp = lookup(arg)) < 0)
4819 return (1);
4820 (void) fseek(tfile, seekp, 0);
4821 (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
4824 * Unless nanoseconds were stored in the file, only use seconds for
4825 * comparison of time. Nanoseconds are stored when -E is specified.
4827 if (Eflag == 0)
4828 return (stbuf.st_mtime > mtime);
4830 if ((stbuf.st_mtime < mtime) ||
4831 ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
4832 return (0);
4833 return (1);
4838 * newvol get new floppy (or tape) volume
4840 * newvol(); resets tapepos and first to TRUE, prompts for
4841 * for new volume, and waits.
4842 * if dumping, end-of-file is written onto the tape.
4845 static void
4846 newvol(void)
4848 int c;
4850 if (dumping) {
4851 dlog("newvol called with 'dumping' set\n");
4852 putempty((blkcnt_t)2); /* 2 EOT marks */
4853 closevol();
4854 flushtape();
4855 sync();
4856 tapepos = 0;
4857 } else
4858 first = TRUE;
4859 if (close(mt) != 0)
4860 vperror(2, gettext("close error"));
4861 mt = 0;
4862 (void) fprintf(stderr, gettext(
4863 "tar: \007please insert new volume, then press RETURN."));
4864 (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */
4865 while ((c = getchar()) != '\n' && ! term)
4866 if (c == EOF)
4867 done(Errflg);
4868 if (term)
4869 done(Errflg);
4871 errno = 0;
4873 if (strcmp(usefile, "-") == 0) {
4874 mt = dup(1);
4875 } else {
4876 mt = open(usefile, dumping ? update : 0);
4879 if (mt < 0) {
4880 (void) fprintf(stderr, gettext(
4881 "tar: cannot reopen %s (%s)\n"),
4882 dumping ? gettext("output") : gettext("input"), usefile);
4884 dlog("update=%d, usefile=%s ", update, usefile);
4885 dlog("mt=%d, [%s]\n", mt, strerror(errno));
4887 done(2);
4892 * Write a trailer portion to close out the current output volume.
4895 static void
4896 closevol(void)
4898 if (mulvol) {
4900 * blocklim does not count the 2 EOT marks;
4901 * tapepos does count the 2 EOT marks;
4902 * therefore we need the +2 below.
4904 putempty(blocklim + (blkcnt_t)2 - tapepos);
4908 static void
4909 done(int n)
4912 * If we were terminated in some way, and we would otherwise have
4913 * exited with a value of 0, adjust to 1, so that external callers
4914 * can determine this by looking at the exit status.
4916 if (term && n == 0)
4917 n = 1;
4919 if (tfile != NULL)
4920 (void) unlink(tname);
4921 if (compress_opt != NULL)
4922 (void) free(compress_opt);
4923 if (mt > 0) {
4924 if ((close(mt) != 0) || (fclose(stdout) != 0)) {
4925 perror(gettext("tar: close error"));
4926 exit(2);
4930 * If we have a compression child, we should have a child process that
4931 * we're waiting for to finish compressing or uncompressing the tar
4932 * stream.
4934 if (comp_pid != 0)
4935 wait_pid(comp_pid);
4936 exit(n);
4940 * Determine if s1 is a prefix portion of s2 (or the same as s2).
4943 static int
4944 is_prefix(char *s1, char *s2)
4946 while (*s1)
4947 if (*s1++ != *s2++)
4948 return (0);
4949 if (*s2)
4950 return (*s2 == '/');
4951 return (1);
4955 * lookup and bsrch look through tfile entries to find a match for a name.
4956 * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
4957 * a pair of newline chars, so the buffer it uses must be long enough for
4958 * two lines: name and modification time as well as period, newline and space.
4960 * A kludge was added to bsrch to take care of matching on the first entry
4961 * in the file--there is no leading newline. So, if we are reading from the
4962 * start of the file, read into byte two and set the first byte to a newline.
4963 * Otherwise, the first entry cannot be matched.
4967 #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4968 static off_t
4969 lookup(char *s)
4971 int i;
4972 off_t a;
4974 for (i = 0; s[i]; i++)
4975 if (s[i] == ' ')
4976 break;
4977 a = bsrch(s, i, low, high);
4978 return (a);
4981 static off_t
4982 bsrch(char *s, int n, off_t l, off_t h)
4984 int i, j;
4985 char b[N];
4986 off_t m, m1;
4989 loop:
4990 if (l >= h)
4991 return ((off_t)-1);
4992 m = l + (h-l)/2 - N/2;
4993 if (m < l)
4994 m = l;
4995 (void) fseek(tfile, m, 0);
4996 if (m == 0) {
4997 (void) fread(b+1, 1, N-1, tfile);
4998 b[0] = '\n';
4999 m--;
5000 } else
5001 (void) fread(b, 1, N, tfile);
5002 for (i = 0; i < N; i++) {
5003 if (b[i] == '\n')
5004 break;
5005 m++;
5007 if (m >= h)
5008 return ((off_t)-1);
5009 m1 = m;
5010 j = i;
5011 for (i++; i < N; i++) {
5012 m1++;
5013 if (b[i] == '\n')
5014 break;
5016 i = cmp(b+j, s, n);
5017 if (i < 0) {
5018 h = m;
5019 goto loop;
5021 if (i > 0) {
5022 l = m1;
5023 goto loop;
5025 if (m < 0)
5026 m = 0;
5027 return (m);
5030 static int
5031 cmp(char *b, char *s, int n)
5033 int i;
5035 assert(b[0] == '\n');
5037 for (i = 0; i < n; i++) {
5038 if (b[i+1] > s[i])
5039 return (-1);
5040 if (b[i+1] < s[i])
5041 return (1);
5043 return (b[i+1] == ' '? 0 : -1);
5048 * seekdisk seek to next file on archive
5050 * called by passtape() only
5052 * WARNING: expects "nblock" to be set, that is, readtape() to have
5053 * already been called. Since passtape() is only called
5054 * after a file header block has been read (why else would
5055 * we skip to next file?), this is currently safe.
5057 * changed to guarantee SYS_BLOCK boundary
5060 static void
5061 seekdisk(blkcnt_t blocks)
5063 off_t seekval;
5064 #if SYS_BLOCK > TBLOCK
5065 /* handle non-multiple of SYS_BLOCK */
5066 blkcnt_t nxb; /* # extra blocks */
5067 #endif
5069 tapepos += blocks;
5070 dlog("seekdisk(%" FMT_blkcnt_t ") called\n", blocks);
5071 if (recno + blocks <= nblock) {
5072 recno += blocks;
5073 return;
5075 if (recno > nblock)
5076 recno = nblock;
5077 seekval = (off_t)blocks - (nblock - recno);
5078 recno = nblock; /* so readtape() reads next time through */
5079 #if SYS_BLOCK > TBLOCK
5080 nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
5081 dlog("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
5082 nxb, seekval);
5083 if (nxb && nxb > seekval) /* don't seek--we'll read */
5084 goto noseek;
5085 seekval -= nxb; /* don't seek quite so far */
5086 #endif
5087 if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
5088 (void) fprintf(stderr, gettext(
5089 "tar: device seek error\n"));
5090 done(3);
5092 #if SYS_BLOCK > TBLOCK
5093 /* read those extra blocks */
5094 noseek:
5095 if (nxb) {
5096 dlog("reading extra blocks\n");
5097 if (read(mt, tbuf, TBLOCK*nblock) < 0) {
5098 (void) fprintf(stderr, gettext(
5099 "tar: read error while skipping file\n"));
5100 done(8);
5102 recno = nxb; /* so we don't read in next readtape() */
5104 #endif
5107 static void
5108 readtape(char *buffer)
5110 int i, j;
5112 ++tapepos;
5113 if (recno >= nblock || first) {
5114 if (first) {
5116 * set the number of blocks to read initially, based on
5117 * the defined defaults for the device, or on the
5118 * explicit block factor given.
5120 if (bflag || defaults_used || NotTape)
5121 j = nblock;
5122 else
5123 j = NBLOCK;
5124 } else
5125 j = nblock;
5127 if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
5128 (void) fprintf(stderr, gettext(
5129 "tar: tape read error\n"));
5130 done(3);
5132 * i == 0 and !rflag means that EOF is reached and we are
5133 * trying to update or replace an empty tar file, so exit
5134 * with an error.
5136 * If i == 0 and !first and NotTape, it means the pointer
5137 * has gone past the EOF. It could happen if two processes
5138 * try to update the same tar file simultaneously. So exit
5139 * with an error.
5142 } else if (i == 0) {
5143 if (first && !rflag) {
5144 (void) fprintf(stderr, gettext(
5145 "tar: blocksize = %d\n"), i);
5146 done(Errflg);
5147 } else if (!first && (!rflag || NotTape)) {
5148 mterr("read", 0, 2);
5150 } else if ((!first || Bflag) && i != TBLOCK*j) {
5152 * Short read - try to get the remaining bytes.
5155 int remaining = (TBLOCK * j) - i;
5156 char *b = (char *)tbuf + i;
5157 int r;
5159 do {
5160 if ((r = read(mt, b, remaining)) < 0) {
5161 (void) fprintf(stderr,
5162 gettext("tar: tape read error\n"));
5163 done(3);
5165 b += r;
5166 remaining -= r;
5167 i += r;
5168 } while (remaining > 0 && r != 0);
5170 if (first) {
5171 if ((i % TBLOCK) != 0) {
5172 (void) fprintf(stderr, gettext(
5173 "tar: tape blocksize error\n"));
5174 done(3);
5176 i /= TBLOCK;
5177 if (vflag && i != nblock && i != 1) {
5178 if (!NotTape)
5179 (void) fprintf(stderr, gettext(
5180 "tar: blocksize = %d\n"), i);
5184 * If we are reading a tape, then a short read is
5185 * understood to signify that the amount read is
5186 * the tape's actual blocking factor. We adapt
5187 * nblock accordingly. There is no reason to do
5188 * this when the device is not blocked.
5191 if (!NotTape)
5192 nblock = i;
5194 recno = 0;
5197 first = FALSE;
5198 copy(buffer, &tbuf[recno++]);
5203 * replacement for writetape.
5206 static int
5207 writetbuf(char *buffer, int n)
5209 int i;
5211 tapepos += n; /* output block count */
5213 if (recno >= nblock) {
5214 i = write(mt, (char *)tbuf, TBLOCK*nblock);
5215 if (i != TBLOCK*nblock)
5216 mterr("write", i, 2);
5217 recno = 0;
5221 * Special case: We have an empty tape buffer, and the
5222 * users data size is >= the tape block size: Avoid
5223 * the bcopy and dma direct to tape. BIG WIN. Add the
5224 * residual to the tape buffer.
5226 while (recno == 0 && n >= nblock) {
5227 i = (int)write(mt, buffer, TBLOCK*nblock);
5228 if (i != TBLOCK*nblock)
5229 mterr("write", i, 2);
5230 n -= nblock;
5231 buffer += (nblock * TBLOCK);
5234 while (n-- > 0) {
5235 (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
5236 buffer += TBLOCK;
5237 if (recno >= nblock) {
5238 i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
5239 if (i != TBLOCK*nblock)
5240 mterr("write", i, 2);
5241 recno = 0;
5245 /* Tell the user how much to write to get in sync */
5246 return (nblock - recno);
5250 * backtape - reposition tape after reading soft "EOF" record
5252 * Backtape tries to reposition the tape back over the EOF
5253 * record. This is for the 'u' and 'r' function letters so that the
5254 * tape can be extended. This code is not well designed, but
5255 * I'm confident that the only callers who care about the
5256 * backspace-over-EOF feature are those involved in 'u' and 'r'.
5258 * The proper way to backup the tape is through the use of mtio.
5259 * Earlier spins used lseek combined with reads in a confusing
5260 * maneuver that only worked on 4.x, but shouldn't have, even
5261 * there. Lseeks are explicitly not supported for tape devices.
5264 static void
5265 backtape(void)
5267 struct mtop mtcmd;
5268 dlog("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
5269 nblock);
5271 * Backup to the position in the archive where the record
5272 * currently sitting in the tbuf buffer is situated.
5275 if (NotTape) {
5277 * For non-tape devices, this means lseeking to the
5278 * correct position. The absolute location tapepos-recno
5279 * should be the beginning of the current record.
5282 if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
5283 (off_t)-1) {
5284 (void) fprintf(stderr,
5285 gettext("tar: lseek to end of archive failed\n"));
5286 done(4);
5288 } else {
5290 * For tape devices, we backup over the most recently
5291 * read record.
5294 mtcmd.mt_op = MTBSR;
5295 mtcmd.mt_count = 1;
5297 if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
5298 (void) fprintf(stderr,
5299 gettext("tar: backspace over record failed\n"));
5300 done(4);
5305 * Decrement the tape and tbuf buffer indices to prepare for the
5306 * coming write to overwrite the soft EOF record.
5309 recno--;
5310 tapepos--;
5315 * flushtape write buffered block(s) onto tape
5317 * recno points to next free block in tbuf. If nonzero, a write is done.
5318 * Care is taken to write in multiples of SYS_BLOCK when device is
5319 * non-magtape in case raw i/o is used.
5321 * NOTE: this is called by writetape() to do the actual writing
5324 static void
5325 flushtape(void)
5327 dlog("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno);
5328 if (recno > 0) { /* anything buffered? */
5329 if (NotTape) {
5330 #if SYS_BLOCK > TBLOCK
5331 int i;
5334 * an odd-block write can only happen when
5335 * we are at the end of a volume that is not a tape.
5336 * Here we round recno up to an even SYS_BLOCK
5337 * boundary.
5339 if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
5340 dlog("flushtape() %d rounding blocks\n", i);
5341 recno += i; /* round up to even SYS_BLOCK */
5343 #endif
5344 if (recno > nblock)
5345 recno = nblock;
5347 dlog("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
5348 " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
5349 (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
5350 if (write(mt, tbuf,
5351 (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
5352 (void) fprintf(stderr, gettext(
5353 "tar: tape write error\n"));
5354 done(2);
5356 recno = 0;
5360 static void
5361 copy(void *dst, void *src)
5363 (void) memcpy(dst, src, TBLOCK);
5367 * kcheck()
5368 * - checks the validity of size values for non-tape devices
5369 * - if size is zero, mulvol tar is disabled and size is
5370 * assumed to be infinite.
5371 * - returns volume size in TBLOCKS
5374 static blkcnt_t
5375 kcheck(char *kstr)
5377 blkcnt_t kval;
5379 kval = strtoll(kstr, NULL, 0);
5380 if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */
5381 mulvol = 0; /* definitely not mulvol, but we must */
5382 return (0); /* took out setting of NotTape */
5384 if (kval < (blkcnt_t)MINSIZE) {
5385 (void) fprintf(stderr, gettext(
5386 "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5387 ").\n"), (ulong_t)MINSIZE, kval);
5388 (void) fprintf(stderr, gettext(
5389 "bad size entry for %s in %s.\n"),
5390 archive, DEF_FILE);
5391 done(1);
5393 mulvol++;
5394 NotTape++; /* implies non-tape */
5395 return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */
5400 * bcheck()
5401 * - checks the validity of blocking factors
5402 * - returns blocking factor
5405 static int
5406 bcheck(char *bstr)
5408 blkcnt_t bval;
5410 bval = strtoll(bstr, NULL, 0);
5411 if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
5412 (void) fprintf(stderr, gettext(
5413 "tar: invalid blocksize \"%s\".\n"), bstr);
5414 if (!bflag)
5415 (void) fprintf(stderr, gettext(
5416 "bad blocksize entry for '%s' in %s.\n"),
5417 archive, DEF_FILE);
5418 done(1);
5421 return ((int)bval);
5426 * defset()
5427 * - reads DEF_FILE for the set of default values specified.
5428 * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5429 * - 'usefile' points to static data, so will be overwritten
5430 * if this routine is called a second time.
5431 * - the pattern specified by 'arch' must be followed by four
5432 * blank-separated fields (1) device (2) blocking,
5433 * (3) size(K), and (4) tape
5434 * for example: archive0=/dev/fd 1 400 n
5437 static int
5438 defset(char *arch)
5440 char *bp;
5442 if (defopen(DEF_FILE) != 0)
5443 return (FALSE);
5444 if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
5445 (void) fprintf(stderr, gettext(
5446 "tar: error setting parameters for %s.\n"), DEF_FILE);
5447 return (FALSE); /* & following ones too */
5449 if ((bp = defread(arch)) == NULL) {
5450 (void) fprintf(stderr, gettext(
5451 "tar: missing or invalid '%s' entry in %s.\n"),
5452 arch, DEF_FILE);
5453 return (FALSE);
5455 if ((usefile = strtok(bp, " \t")) == NULL) {
5456 (void) fprintf(stderr, gettext(
5457 "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
5458 return (FALSE);
5460 if ((bp = strtok(NULL, " \t")) == NULL) {
5461 (void) fprintf(stderr, gettext(
5462 "tar: block component missing in '%s' entry in %s.\n"),
5463 arch, DEF_FILE);
5464 return (FALSE);
5466 nblock = bcheck(bp);
5467 if ((bp = strtok(NULL, " \t")) == NULL) {
5468 (void) fprintf(stderr, gettext(
5469 "tar: size component missing in '%s' entry in %s.\n"),
5470 arch, DEF_FILE);
5471 return (FALSE);
5473 blocklim = kcheck(bp);
5474 if ((bp = strtok(NULL, " \t")) != NULL)
5475 NotTape = (*bp == 'n' || *bp == 'N');
5476 else
5477 NotTape = (blocklim != 0);
5478 (void) defopen(NULL);
5479 dlog("defset: archive='%s'; usefile='%s'\n", arch, usefile);
5480 dlog("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
5481 nblock, blocklim);
5482 dlog("defset: not tape = %d\n", NotTape);
5483 return (TRUE);
5488 * Following code handles excluded and included files.
5489 * A hash table of file names to be {in,ex}cluded is built.
5490 * For excluded files, before writing or extracting a file
5491 * check to see if it is in the exclude_tbl.
5492 * For included files, the wantit() procedure will check to
5493 * see if the named file is in the include_tbl.
5496 static void
5497 build_table(file_list_t *table[], char *file)
5499 FILE *fp;
5500 char buf[PATH_MAX + 1];
5502 if ((fp = fopen(file, "r")) == (FILE *)NULL)
5503 vperror(1, gettext("could not open %s"), file);
5504 while (fgets(buf, sizeof (buf), fp) != NULL) {
5505 if (buf[strlen(buf) - 1] == '\n')
5506 buf[strlen(buf) - 1] = '\0';
5507 /* Only add to table if line has something in it */
5508 if (strspn(buf, " \t") != strlen(buf))
5509 add_file_to_table(table, buf);
5511 (void) fclose(fp);
5516 * Add a file name to the the specified table, if the file name has any
5517 * trailing '/'s then delete them before inserting into the table
5520 static void
5521 add_file_to_table(file_list_t *table[], char *str)
5523 char name[PATH_MAX + 1];
5524 unsigned int h;
5525 file_list_t *exp;
5527 (void) strcpy(name, str);
5528 while (name[strlen(name) - 1] == '/') {
5529 name[strlen(name) - 1] = NULL;
5532 h = hash(name);
5533 if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
5534 sizeof (char))) == NULL) {
5535 (void) fprintf(stderr, gettext(
5536 "tar: out of memory, exclude/include table(entry)\n"));
5537 exit(1);
5540 if ((exp->name = strdup(name)) == NULL) {
5541 (void) fprintf(stderr, gettext(
5542 "tar: out of memory, exclude/include table(file name)\n"));
5543 exit(1);
5546 exp->next = table[h];
5547 table[h] = exp;
5552 * See if a file name or any of the file's parent directories is in the
5553 * specified table, if the file name has any trailing '/'s then delete
5554 * them before searching the table
5557 static int
5558 is_in_table(file_list_t *table[], char *str)
5560 char name[PATH_MAX + 1];
5561 unsigned int h;
5562 file_list_t *exp;
5563 char *ptr;
5565 (void) strcpy(name, str);
5566 while (name[strlen(name) - 1] == '/') {
5567 name[strlen(name) - 1] = NULL;
5571 * check for the file name in the passed list
5573 h = hash(name);
5574 exp = table[h];
5575 while (exp != NULL) {
5576 if (strcmp(name, exp->name) == 0) {
5577 return (1);
5579 exp = exp->next;
5583 * check for any parent directories in the file list
5585 while ((ptr = strrchr(name, '/'))) {
5586 *ptr = NULL;
5587 h = hash(name);
5588 exp = table[h];
5589 while (exp != NULL) {
5590 if (strcmp(name, exp->name) == 0) {
5591 return (1);
5593 exp = exp->next;
5597 return (0);
5602 * Compute a hash from a string.
5605 static unsigned int
5606 hash(char *str)
5608 char *cp;
5609 unsigned int h;
5611 h = 0;
5612 for (cp = str; *cp; cp++) {
5613 h += *cp;
5615 return (h % TABLE_SIZE);
5618 static void *
5619 getmem(size_t size)
5621 void *p = calloc((unsigned)size, sizeof (char));
5623 if (p == NULL && freemem) {
5624 (void) fprintf(stderr, gettext(
5625 "tar: out of memory, link and directory modtime "
5626 "info lost\n"));
5627 freemem = 0;
5628 if (errflag)
5629 done(1);
5630 else
5631 Errflg = 1;
5633 return (p);
5637 * vperror() --variable argument perror.
5638 * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
5639 * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5640 * with the value of whatever "errno" is set to. If exit_status is not
5641 * zero, then tar exits with that error status. If errflag and exit_status
5642 * are both zero, the routine returns to where it was called and sets Errflg
5643 * to errno.
5646 static void
5647 vperror(int exit_status, char *fmt, ...)
5649 va_list ap;
5651 va_start(ap, fmt);
5652 (void) fputs("tar: ", stderr);
5653 (void) vfprintf(stderr, fmt, ap);
5654 (void) fprintf(stderr, ": %s\n", strerror(errno));
5655 va_end(ap);
5656 if (exit_status)
5657 done(exit_status);
5658 else
5659 if (errflag)
5660 done(errno);
5661 else
5662 Errflg = errno;
5666 static void
5667 fatal(char *format, ...)
5669 va_list ap;
5671 va_start(ap, format);
5672 (void) fprintf(stderr, "tar: ");
5673 (void) vfprintf(stderr, format, ap);
5674 (void) fprintf(stderr, "\n");
5675 va_end(ap);
5676 done(1);
5681 * Check to make sure that argument is a char * ptr.
5682 * Actually, we just check to see that it is non-null.
5683 * If it is null, print out the message and call usage(), bailing out.
5686 static void
5687 assert_string(char *s, char *msg)
5689 if (s == NULL) {
5690 (void) fprintf(stderr, msg);
5691 usage();
5696 static void
5697 mterr(char *operation, int i, int exitcode)
5699 (void) fprintf(stderr, gettext(
5700 "tar: %s error: "), operation);
5701 if (i < 0)
5702 perror("");
5703 else
5704 (void) fprintf(stderr, gettext("unexpected EOF\n"));
5705 done(exitcode);
5708 static int
5709 wantit(char *argv[], char **namep, char **dirp, char **component,
5710 attr_data_t **attrinfo)
5712 char **cp;
5713 int gotit; /* true if we've found a match */
5714 int ret;
5716 top:
5717 if (xhdr_flgs & _X_XHDR) {
5718 xhdr_flgs = 0;
5720 getdir();
5721 if (Xhdrflag > 0) {
5722 ret = get_xdata();
5723 if (ret != 0) { /* Xhdr items and regular header */
5724 setbytes_to_skip(&stbuf, ret);
5725 passtape();
5726 return (0); /* Error--don't want to extract */
5731 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5732 * of ancillary file is either over or ancillary file
5733 * processing is not required, load info from Xtarhdr and set
5734 * _X_XHDR bit in xhdr_flgs.
5736 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
5737 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
5738 xhdr_flgs |= _X_XHDR;
5741 #if defined(O_XATTR)
5742 if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
5744 * Always needs to read the extended header. If atflag, saflag,
5745 * or tflag isn't set, then we'll have the correct info for
5746 * passtape() later.
5748 (void) read_xattr_hdr(attrinfo);
5749 goto top;
5752 * Now that we've read the extended header, call passtape()
5753 * if we don't want to restore attributes or system attributes.
5754 * Don't restore the attribute if we are extracting
5755 * a file from an archive (as opposed to doing a table of
5756 * contents) and any of the following are true:
5757 * 1. neither -@ or -/ was specified.
5758 * 2. -@ was specified, -/ wasn't specified, and we're
5759 * processing a hidden attribute directory of an attribute
5760 * or we're processing a read-write system attribute file.
5761 * 3. -@ wasn't specified, -/ was specified, and the file
5762 * we're processing is not a read-write system attribute file,
5763 * or we're processing the hidden attribute directory of an
5764 * attribute.
5766 * We always process the attributes if we're just generating
5767 * generating a table of contents, or if both -@ and -/ were
5768 * specified.
5770 if (xattrp != NULL) {
5771 attr_data_t *ainfo = *attrinfo;
5773 if (!tflag &&
5774 ((!atflag && !saflag) ||
5775 (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
5776 ainfo->attr_rw_sysattr)) ||
5777 (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
5778 !ainfo->attr_rw_sysattr)))) {
5779 passtape();
5780 return (0);
5783 #endif
5785 /* sets *namep to point at the proper name */
5786 if (check_prefix(namep, dirp, component) != 0) {
5787 passtape();
5788 return (0);
5791 if (endtape()) {
5792 if (Bflag) {
5793 ssize_t sz;
5794 size_t extra_blocks = 0;
5797 * Logically at EOT - consume any extra blocks
5798 * so that write to our stdin won't fail and
5799 * emit an error message; otherwise something
5800 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5801 * will produce a bogus error message from "dd".
5804 while ((sz = read(mt, tbuf, TBLOCK*nblock)) > 0) {
5805 extra_blocks += sz;
5807 dlog("wantit(): %d bytes of extra blocks\n",
5808 extra_blocks);
5810 dlog("wantit(): at end of tape.\n");
5811 return (-1);
5814 gotit = 0;
5816 if ((Iflag && is_in_table(include_tbl, *namep)) ||
5817 (! Iflag && *argv == NULL)) {
5818 gotit = 1;
5819 } else {
5820 for (cp = argv; *cp; cp++) {
5821 if (is_prefix(*cp, *namep)) {
5822 gotit = 1;
5823 break;
5828 if (! gotit) {
5829 passtape();
5830 return (0);
5833 if (Xflag && is_in_table(exclude_tbl, *namep)) {
5834 if (vflag) {
5835 (void) fprintf(stderr, gettext("%s excluded\n"),
5836 *namep);
5838 passtape();
5839 return (0);
5842 return (1);
5846 static void
5847 setbytes_to_skip(struct stat *st, int err)
5850 * In a scenario where a typeflag 'X' was followed by
5851 * a typeflag 'A' and typeflag 'O', then the number of
5852 * bytes to skip should be the size of ancillary file,
5853 * plus the dblock for regular file, and the size
5854 * from Xtarhdr. However, if the typeflag was just 'X'
5855 * followed by typeflag 'O', then the number of bytes
5856 * to skip should be the size from Xtarhdr.
5858 if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
5859 (xhdr_flgs & _X_SIZE)) {
5860 st->st_size += TBLOCK + Xtarhdr.x_filesz;
5861 xhdr_flgs |= _X_XHDR;
5862 } else if ((dblock.dbuf.typeflag != 'A') &&
5863 (xhdr_flgs & _X_SIZE)) {
5864 st->st_size += Xtarhdr.x_filesz;
5865 xhdr_flgs |= _X_XHDR;
5869 static int
5870 fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
5871 int rw_sysattr, attr_data_t **attrinfo)
5873 size_t pathlen;
5874 char *tpath;
5875 char *tparent;
5877 /* parent info */
5878 if (attrparent != NULL) {
5879 if ((tparent = strdup(attrparent)) == NULL) {
5880 vperror(0, gettext(
5881 "unable to allocate memory for attribute parent "
5882 "name for %sattribute %s/%s of %s"),
5883 rw_sysattr ? gettext("system ") : "",
5884 attrparent, attr, longname);
5885 return (1);
5887 } else {
5888 tparent = NULL;
5891 /* path info */
5892 pathlen = strlen(attr) + 1;
5893 if (attrparent != NULL) {
5894 pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
5896 if ((tpath = calloc(1, pathlen)) == NULL) {
5897 vperror(0, gettext(
5898 "unable to allocate memory for full "
5899 "attribute path name for %sattribute %s%s%s of %s"),
5900 rw_sysattr ? gettext("system ") : "",
5901 (attrparent == NULL) ? "" : attrparent,
5902 (attrparent == NULL) ? "" : "/",
5903 attr, longname);
5904 if (tparent != NULL) {
5905 free(tparent);
5907 return (1);
5909 (void) snprintf(tpath, pathlen, "%s%s%s",
5910 (attrparent == NULL) ? "" : attrparent,
5911 (attrparent == NULL) ? "" : "/",
5912 attr);
5914 /* fill in the attribute info */
5915 if (*attrinfo == NULL) {
5916 if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
5917 vperror(0, gettext(
5918 "unable to allocate memory for attribute "
5919 "information for %sattribute %s%s%s of %s"),
5920 rw_sysattr ? gettext("system ") : "",
5921 (attrparent == NULL) ? "" : attrparent,
5922 (attrparent == NULL) ? "" : gettext("/"),
5923 attr, longname);
5924 if (tparent != NULL) {
5925 free(tparent);
5927 free(tpath);
5928 return (1);
5930 } else {
5931 if ((*attrinfo)->attr_parent != NULL) {
5932 free((*attrinfo)->attr_parent);
5934 if ((*attrinfo)->attr_path != NULL) {
5935 free((*attrinfo)->attr_path);
5938 * The parent file descriptor is passed in, so don't
5939 * close it here as it should be closed by the function
5940 * that opened it.
5943 (*attrinfo)->attr_parent = tparent;
5944 (*attrinfo)->attr_path = tpath;
5945 (*attrinfo)->attr_rw_sysattr = rw_sysattr;
5946 (*attrinfo)->attr_parentfd = atparentfd;
5948 return (0);
5952 * Test to see if name is a directory.
5954 * Return 1 if true, 0 otherwise.
5957 static int
5958 is_directory(char *name)
5960 #if defined(O_XATTR)
5962 * If there is an xattr_buf structure associated with this file,
5963 * then the directory test is based on whether the name has a
5964 * trailing slash.
5966 if (xattrp)
5967 return (name[strlen(name) - 1] == '/');
5968 #endif
5969 if (is_posix)
5970 return (dblock.dbuf.typeflag == '5');
5971 else
5972 return (name[strlen(name) - 1] == '/');
5976 * Version of chdir that handles directory pathnames of greater than PATH_MAX
5977 * length, by changing the working directory to manageable portions of the
5978 * complete directory pathname. If any of these attempts fail, then it exits
5979 * non-zero.
5981 * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
5982 * pathname is greater than PATH_MAX, then this still won't work, and this
5983 * routine will return -1 with errno set to ENAMETOOLONG.
5985 * NOTE: this routine is semantically different to the system chdir in
5986 * that it is remotely possible for the currently working directory to be
5987 * changed to a different directory, if a chdir call fails when processing
5988 * one of the segments of a path that is greater than PATH_MAX. This isn't
5989 * a problem as this is tar's own specific version of chdir.
5992 static int
5993 tar_chdir(const char *path)
5995 const char *sep = "/";
5996 char *path_copy = NULL;
5997 char *ptr = NULL;
5999 /* The trivial case. */
6000 if (chdir(path) == 0) {
6001 return (0);
6003 if (errno == ENAMETOOLONG) {
6004 if (path[0] == '/' && chdir(sep) != 0)
6005 return (-1);
6007 /* strtok(3C) modifies the string, so make a copy. */
6008 if ((path_copy = strdup(path)) == NULL) {
6009 return (-1);
6012 /* chdir(2) for every path element. */
6013 for (ptr = strtok(path_copy, sep);
6014 ptr != NULL;
6015 ptr = strtok(NULL, sep)) {
6016 if (chdir(ptr) != 0) {
6017 free(path_copy);
6018 return (-1);
6021 free(path_copy);
6022 return (0);
6025 /* If chdir fails for any reason except ENAMETOOLONG. */
6026 return (-1);
6030 * Test if name has a '..' sequence in it.
6032 * Return 1 if found, 0 otherwise.
6035 static int
6036 has_dot_dot(char *name)
6038 char *s;
6039 size_t name_len = strlen(name);
6041 for (s = name; s < (name + name_len - 2); s++) {
6042 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
6043 return (1);
6045 while (! (*s == '/')) {
6046 if (! *s++)
6047 return (0);
6051 return (0);
6055 * Test if name is an absolute path name.
6057 * Return 1 if true, 0 otherwise.
6060 static int
6061 is_absolute(char *name)
6063 #if defined(O_XATTR)
6065 * If this is an extended attribute (whose name will begin with
6066 * "/dev/null/", always return 0 as they should be extracted with
6067 * the name intact, to allow other tar archiving programs that
6068 * don't understand extended attributes, to correctly throw them away.
6070 if (xattrp)
6071 return (0);
6072 #endif
6074 return (name[0] == '/');
6078 * Adjust the pathname to make it a relative one. Strip off any leading
6079 * '/' characters and if the pathname contains any '..' sequences, strip
6080 * upto and including the last occurance of '../' (or '..' if found at
6081 * the very end of the pathname).
6083 * Return the relative pathname. stripped_prefix will also return the
6084 * portion of name that was stripped off and should be freed by the
6085 * calling routine when no longer needed.
6088 static char *
6089 make_relative_name(char *name, char **stripped_prefix)
6091 char *s;
6092 size_t prefix_len = 0;
6093 size_t name_len = strlen(name);
6095 for (s = name + prefix_len; s < (name + name_len - 2); ) {
6096 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
6097 prefix_len = s + 2 - name;
6099 do {
6100 char c = *s++;
6102 if (c == '/')
6103 break;
6104 } while (*s);
6107 for (s = name + prefix_len; *s == '/'; s++)
6108 continue;
6109 prefix_len = s - name;
6111 /* Create the portion of the name that was stripped off. */
6112 s = malloc(prefix_len + 1);
6113 memcpy(s, name, prefix_len);
6114 s[prefix_len] = 0;
6115 *stripped_prefix = s;
6116 s = &name[prefix_len];
6118 return (s);
6122 * Return through *namep a pointer to the proper fullname (i.e "<name> |
6123 * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6125 * Returns 0 if successful, otherwise returns 1.
6128 static int
6129 check_prefix(char **namep, char **dirp, char **compp)
6131 static char fullname[PATH_MAX + 1];
6132 static char dir[PATH_MAX + 1];
6133 static char component[PATH_MAX + 1];
6134 static char savename[PATH_MAX + 1];
6135 char *s;
6137 (void) memset(dir, 0, sizeof (dir));
6138 (void) memset(component, 0, sizeof (component));
6140 if (xhdr_flgs & _X_PATH) {
6141 (void) strcpy(fullname, Xtarhdr.x_path);
6142 } else {
6143 if (dblock.dbuf.prefix[0] != '\0')
6144 (void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
6145 dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
6146 else
6147 (void) sprintf(fullname, "%.*s", NAMSIZ,
6148 dblock.dbuf.name);
6152 * If we are printing a table of contents or extracting an archive,
6153 * make absolute pathnames relative and prohibit the unpacking of
6154 * files contain ".." in their name (unless the user has supplied
6155 * the -P option).
6157 if ((tflag || xflag) && !Pflag) {
6158 if (is_absolute(fullname) || has_dot_dot(fullname)) {
6159 char *stripped_prefix;
6161 (void) strcpy(savename, fullname);
6162 strcpy(fullname,
6163 make_relative_name(savename, &stripped_prefix));
6164 (void) fprintf(stderr,
6165 gettext("tar: Removing leading '%s' from '%s'\n"),
6166 stripped_prefix, savename);
6167 free(stripped_prefix);
6172 * Set dir and component names
6175 get_parent(fullname, dir);
6177 #if defined(O_XATTR)
6178 if (xattrp == NULL) {
6179 #endif
6181 * Save of real name since were going to chop off the
6182 * trailing slashes.
6184 (void) strcpy(savename, fullname);
6186 * first strip of trailing slashes.
6188 chop_endslashes(savename);
6189 s = get_component(savename);
6190 (void) strcpy(component, s);
6192 #if defined(O_XATTR)
6193 } else {
6194 (void) strcpy(fullname, xattrp->h_names);
6195 (void) strcpy(dir, fullname);
6196 (void) strcpy(component, basename(xattrp->h_names +
6197 strlen(xattrp->h_names) + 1));
6199 #endif
6200 *namep = fullname;
6201 *dirp = dir;
6202 *compp = component;
6204 return (0);
6208 * Return true if the object indicated by the file descriptor and type
6209 * is a tape device, false otherwise
6212 static int
6213 istape(int fd, int type)
6215 int result = 0;
6217 if (S_ISCHR(type)) {
6218 struct mtget mtg;
6220 if (ioctl(fd, MTIOCGET, &mtg) != -1) {
6221 result = 1;
6225 return (result);
6228 #include <utmpx.h>
6230 struct utmpx utmpx;
6232 #define NMAX (sizeof (utmpx.ut_name))
6234 typedef struct cachenode { /* this struct must be zeroed before using */
6235 struct cachenode *next; /* next in hash chain */
6236 int val; /* the uid or gid of this entry */
6237 int namehash; /* name's hash signature */
6238 char name[NMAX+1]; /* the string that val maps to */
6239 } cachenode_t;
6241 #define HASHSIZE 256
6243 static cachenode_t *names[HASHSIZE];
6244 static cachenode_t *groups[HASHSIZE];
6245 static cachenode_t *uids[HASHSIZE];
6246 static cachenode_t *gids[HASHSIZE];
6248 static int
6249 hash_byname(char *name)
6251 int i, c, h = 0;
6253 for (i = 0; i < NMAX; i++) {
6254 c = name[i];
6255 if (c == '\0')
6256 break;
6257 h = (h << 4) + h + c;
6259 return (h);
6262 static cachenode_t *
6263 hash_lookup_byval(cachenode_t *table[], int val)
6265 int h = val;
6266 cachenode_t *c;
6268 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6269 if (c->val == val)
6270 return (c);
6272 return (NULL);
6275 static cachenode_t *
6276 hash_lookup_byname(cachenode_t *table[], char *name)
6278 int h = hash_byname(name);
6279 cachenode_t *c;
6281 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6282 if (c->namehash == h && strcmp(c->name, name) == 0)
6283 return (c);
6285 return (NULL);
6288 static cachenode_t *
6289 hash_insert(cachenode_t *table[], char *name, int value)
6291 cachenode_t *c;
6292 int signature;
6294 c = calloc(1, sizeof (cachenode_t));
6295 if (c == NULL) {
6296 perror("malloc");
6297 exit(1);
6299 if (name != NULL) {
6300 (void) strncpy(c->name, name, NMAX);
6301 c->namehash = hash_byname(name);
6303 c->val = value;
6304 if (table == uids || table == gids)
6305 signature = c->val;
6306 else
6307 signature = c->namehash;
6308 c->next = table[signature & (HASHSIZE - 1)];
6309 table[signature & (HASHSIZE - 1)] = c;
6310 return (c);
6313 static char *
6314 getname(uid_t uid)
6316 cachenode_t *c;
6318 if ((c = hash_lookup_byval(uids, uid)) == NULL) {
6319 struct passwd *pwent = getpwuid(uid);
6320 c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
6322 return (c->name);
6325 static char *
6326 getgroup(gid_t gid)
6328 cachenode_t *c;
6330 if ((c = hash_lookup_byval(gids, gid)) == NULL) {
6331 struct group *grent = getgrgid(gid);
6332 c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
6334 return (c->name);
6337 static uid_t
6338 getuidbyname(char *name)
6340 cachenode_t *c;
6342 if ((c = hash_lookup_byname(names, name)) == NULL) {
6343 struct passwd *pwent = getpwnam(name);
6344 c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
6346 return ((uid_t)c->val);
6349 static gid_t
6350 getgidbyname(char *group)
6352 cachenode_t *c;
6354 if ((c = hash_lookup_byname(groups, group)) == NULL) {
6355 struct group *grent = getgrnam(group);
6356 c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
6358 return ((gid_t)c->val);
6362 * Build the header.
6363 * Determine whether or not an extended header is also needed. If needed,
6364 * create and write the extended header and its data.
6365 * Writing of the extended header assumes that "tomodes" has been called and
6366 * the relevant information has been placed in the header block.
6369 static int
6370 build_dblock(
6371 const char *name,
6372 const char *linkname,
6373 const char typeflag,
6374 const int filetype,
6375 const struct stat *sp,
6376 const dev_t device,
6377 const char *prefix)
6379 int nblks;
6380 major_t dev;
6381 const char *filename;
6382 const char *lastslash;
6384 if (filetype == XATTR_FILE)
6385 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
6386 else
6387 dblock.dbuf.typeflag = typeflag;
6388 (void) memset(dblock.dbuf.name, '\0', NAMSIZ);
6389 (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
6390 (void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
6392 if (xhdr_flgs & _X_PATH)
6393 filename = Xtarhdr.x_path;
6394 else
6395 filename = name;
6397 if ((dev = major(device)) > OCTAL7CHAR) {
6398 if (Eflag) {
6399 xhdr_flgs |= _X_DEVMAJOR;
6400 Xtarhdr.x_devmajor = dev;
6401 } else {
6402 (void) fprintf(stderr, gettext(
6403 "Device major too large for %s. Use -E flag."),
6404 filename);
6405 if (errflag)
6406 done(1);
6407 else
6408 Errflg = 1;
6410 dev = 0;
6412 (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
6413 if ((dev = minor(device)) > OCTAL7CHAR) {
6414 if (Eflag) {
6415 xhdr_flgs |= _X_DEVMINOR;
6416 Xtarhdr.x_devminor = dev;
6417 } else {
6418 (void) fprintf(stderr, gettext(
6419 "Device minor too large for %s. Use -E flag."),
6420 filename);
6421 if (errflag)
6422 done(1);
6423 else
6424 Errflg = 1;
6426 dev = 0;
6428 (void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
6430 (void) strncpy(dblock.dbuf.name, name, NAMSIZ);
6431 (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
6432 (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
6433 (void) sprintf(dblock.dbuf.version, "00");
6434 (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
6435 (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
6436 (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
6437 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
6439 if (Eflag) {
6440 (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
6441 (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
6442 lastslash = strrchr(name, '/');
6443 if (lastslash == NULL)
6444 lastslash = name;
6445 else
6446 lastslash++;
6447 (void) strcpy(xhdr_buf.dbuf.name, lastslash);
6448 (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
6449 (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
6450 (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
6451 xhdr_count++;
6452 xrec_offset = 0;
6453 gen_date("mtime", sp->st_mtim);
6454 xhdr_buf.dbuf.typeflag = 'X';
6455 if (gen_utf8_names(filename) != 0)
6456 return (1);
6458 #ifdef XHDR_DEBUG
6459 Xtarhdr.x_uname = dblock.dbuf.uname;
6460 Xtarhdr.x_gname = dblock.dbuf.gname;
6461 xhdr_flgs |= (_X_UNAME | _X_GNAME);
6462 #endif
6463 if (xhdr_flgs) {
6464 if (xhdr_flgs & _X_DEVMAJOR)
6465 gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
6466 if (xhdr_flgs & _X_DEVMINOR)
6467 gen_num("SUN.devminor", Xtarhdr.x_devminor);
6468 if (xhdr_flgs & _X_GID)
6469 gen_num("gid", Xtarhdr.x_gid);
6470 if (xhdr_flgs & _X_UID)
6471 gen_num("uid", Xtarhdr.x_uid);
6472 if (xhdr_flgs & _X_SIZE)
6473 gen_num("size", Xtarhdr.x_filesz);
6474 if (xhdr_flgs & _X_PATH)
6475 gen_string("path", Xtarhdr.x_path);
6476 if (xhdr_flgs & _X_LINKPATH)
6477 gen_string("linkpath", Xtarhdr.x_linkpath);
6478 if (xhdr_flgs & _X_GNAME)
6479 gen_string("gname", Xtarhdr.x_gname);
6480 if (xhdr_flgs & _X_UNAME)
6481 gen_string("uname", Xtarhdr.x_uname);
6483 (void) sprintf(xhdr_buf.dbuf.size,
6484 "%011" FMT_off_t_o, xrec_offset);
6485 (void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
6486 checksum(&xhdr_buf));
6487 (void) writetbuf((char *)&xhdr_buf, 1);
6488 nblks = TBLOCKS(xrec_offset);
6489 (void) writetbuf(xrec_ptr, nblks);
6491 return (0);
6496 * makeDir - ensure that a directory with the pathname denoted by name
6497 * exists, and return 1 on success, and 0 on failure (e.g.,
6498 * read-only file system, exists but not-a-directory).
6501 static int
6502 makeDir(char *name)
6504 struct stat buf;
6506 if (access(name, 0) < 0) { /* name doesn't exist */
6507 if (mkdir(name, 0777) < 0) {
6508 vperror(0, "%s", name);
6509 return (0);
6511 } else { /* name exists */
6512 if (stat(name, &buf) < 0) {
6513 vperror(0, "%s", name);
6514 return (0);
6517 return ((buf.st_mode & S_IFMT) == S_IFDIR);
6520 return (1);
6525 * Save this directory and its mtime on the stack, popping and setting
6526 * the mtimes of any stacked dirs which aren't parents of this one.
6527 * A null name causes the entire stack to be unwound and set.
6529 * Since all the elements of the directory "stack" share a common
6530 * prefix, we can make do with one string. We keep only the current
6531 * directory path, with an associated array of mtime's. A negative
6532 * mtime means no mtime.
6534 * This stack algorithm is not guaranteed to work for tapes created
6535 * with the 'r' function letter, but the vast majority of tapes with
6536 * directories are not. This avoids saving every directory record on
6537 * the tape and setting all the times at the end.
6539 * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6540 * environment)
6543 static void
6544 doDirTimes(char *name, timestruc_t modTime)
6546 static char dirstack[PATH_MAX+2];
6547 /* Add spaces for the last slash and last NULL */
6548 static timestruc_t modtimes[PATH_MAX+1]; /* hash table */
6549 char *p = dirstack;
6550 char *q = name;
6551 char *savp;
6553 if (q) {
6555 * Find common prefix
6558 while (*p == *q && *p) {
6559 p++; q++;
6563 savp = p;
6564 while (*p) {
6566 * Not a child: unwind the stack, setting the times.
6567 * The order we do this doesn't matter, so we go "forward."
6570 if (*p == '/')
6571 if (modtimes[p - dirstack].tv_sec >= 0) {
6572 *p = '\0'; /* zap the slash */
6573 setPathTimes(AT_FDCWD, dirstack,
6574 modtimes[p - dirstack]);
6575 *p = '/';
6577 ++p;
6580 p = savp;
6583 * Push this one on the "stack"
6586 if (q) {
6589 * Since the name parameter points the dir pathname
6590 * which is limited only to contain PATH_MAX chars
6591 * at maximum, we can ignore the overflow case of p.
6594 while ((*p = *q++)) { /* append the rest of the new dir */
6595 modtimes[p - dirstack].tv_sec = -1;
6596 p++;
6600 * If the tar file had used 'P' or 'E' function modifier,
6601 * append the last slash.
6603 if (*(p - 1) != '/') {
6604 *p++ = '/';
6605 *p = '\0';
6607 /* overwrite the last one */
6608 modtimes[p - dirstack - 1] = modTime;
6614 * setPathTimes - set the modification time for given path. Return 1 if
6615 * successful and 0 if not successful.
6618 static void
6619 setPathTimes(int dirfd, char *path, timestruc_t modTime)
6621 struct timeval timebuf[2];
6624 * futimesat takes an array of two timeval structs.
6625 * The first entry contains access time.
6626 * The second entry contains modification time.
6627 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6628 * microseconds.
6630 timebuf[0].tv_sec = time((time_t *)0);
6631 timebuf[0].tv_usec = 0;
6632 timebuf[1].tv_sec = modTime.tv_sec;
6634 /* Extended header: use microseconds */
6635 timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
6637 if (futimesat(dirfd, path, timebuf) < 0)
6638 vperror(0, gettext("can't set time on %s"), path);
6643 * If hflag is set then delete the symbolic link's target.
6644 * If !hflag then delete the target.
6647 static void
6648 delete_target(int fd, char *comp, char *namep)
6650 struct stat xtractbuf;
6651 char buf[PATH_MAX + 1];
6652 int n;
6655 if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
6656 if (errno == ENOTDIR && !hflag) {
6657 (void) unlinkat(fd, comp, 0);
6658 } else if (errno == ENOTDIR && hflag) {
6659 if (!lstat(namep, &xtractbuf)) {
6660 if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
6661 (void) unlinkat(fd, comp, 0);
6662 } else if ((n = readlink(namep, buf,
6663 PATH_MAX)) != -1) {
6664 buf[n] = (char)NULL;
6665 (void) unlinkat(fd, buf,
6666 AT_REMOVEDIR);
6667 if (errno == ENOTDIR)
6668 (void) unlinkat(fd, buf, 0);
6669 } else {
6670 (void) unlinkat(fd, comp, 0);
6672 } else {
6673 (void) unlinkat(fd, comp, 0);
6681 * ACL changes:
6682 * putfile():
6683 * Get acl info after stat. Write out ancillary file
6684 * before the normal file, i.e. directory, regular, FIFO,
6685 * link, special. If acl count is less than 4, no need to
6686 * create ancillary file. (i.e. standard permission is in
6687 * use.
6688 * doxtract():
6689 * Process ancillary file. Read it in and set acl info.
6690 * watch out for 'o' function modifier.
6691 * 't' function letter to display table
6695 * New functions for ACLs and other security attributes
6699 * The function appends the new security attribute info to the end of
6700 * existing secinfo.
6703 append_secattr(
6704 char **secinfo, /* existing security info */
6705 int *secinfo_len, /* length of existing security info */
6706 int size, /* new attribute size: unit depends on type */
6707 char *attrtext, /* new attribute text */
6708 char attr_type) /* new attribute type */
6710 char *new_secinfo;
6711 int newattrsize;
6712 int oldsize;
6713 struct sec_attr *attr;
6715 /* no need to add */
6716 if (attr_type != DIR_TYPE) {
6717 if (attrtext == NULL)
6718 return (0);
6721 switch (attr_type) {
6722 case UFSD_ACL:
6723 case ACE_ACL:
6724 if (attrtext == NULL) {
6725 (void) fprintf(stderr, gettext("acltotext failed\n"));
6726 return (-1);
6728 /* header: type + size = 8 */
6729 newattrsize = 8 + (int)strlen(attrtext) + 1;
6730 attr = (struct sec_attr *)malloc(newattrsize);
6731 if (attr == NULL) {
6732 (void) fprintf(stderr,
6733 gettext("can't allocate memory\n"));
6734 return (-1);
6736 attr->attr_type = attr_type;
6737 (void) sprintf(attr->attr_len,
6738 "%06o", size); /* acl entry count */
6739 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6740 free(attrtext);
6741 break;
6743 /* Trusted Extensions */
6744 case DIR_TYPE:
6745 case LBL_TYPE:
6746 newattrsize = sizeof (struct sec_attr) + strlen(attrtext);
6747 attr = (struct sec_attr *)malloc(newattrsize);
6748 if (attr == NULL) {
6749 (void) fprintf(stderr,
6750 gettext("can't allocate memory\n"));
6751 return (-1);
6753 attr->attr_type = attr_type;
6754 (void) sprintf(attr->attr_len,
6755 "%06d", size); /* len of attr data */
6756 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6757 break;
6759 default:
6760 (void) fprintf(stderr,
6761 gettext("unrecognized attribute type\n"));
6762 return (-1);
6765 /* old security info + new attr header(8) + new attr */
6766 oldsize = *secinfo_len;
6767 *secinfo_len += newattrsize;
6768 new_secinfo = (char *)malloc(*secinfo_len);
6769 if (new_secinfo == NULL) {
6770 (void) fprintf(stderr, gettext("can't allocate memory\n"));
6771 *secinfo_len -= newattrsize;
6772 free(attr);
6773 return (-1);
6776 (void) memcpy(new_secinfo, *secinfo, oldsize);
6777 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6779 free(*secinfo);
6780 free(attr);
6781 *secinfo = new_secinfo;
6782 return (0);
6786 * write_ancillary(): write out an ancillary file.
6787 * The file has the same header as normal file except the type and size
6788 * fields. The type is 'A' and size is the sum of all attributes
6789 * in bytes.
6790 * The body contains a list of attribute type, size and info. Currently,
6791 * there is only ACL info. This file is put before the normal file.
6793 void
6794 write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
6796 long blocks;
6797 int savflag;
6798 int savsize;
6800 /* Just tranditional permissions or no security attribute info */
6801 if (len == 0 || secinfo == NULL)
6802 return;
6804 /* save flag and size */
6805 savflag = (dblockp->dbuf).typeflag;
6806 (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
6808 /* special flag for ancillary file */
6809 if (hdrtype == _XATTR_HDRTYPE)
6810 dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
6811 else
6812 dblockp->dbuf.typeflag = 'A';
6814 /* for pre-2.5 versions of tar, need to make sure */
6815 /* the ACL file is readable */
6816 (void) sprintf(dblock.dbuf.mode, "%07lo",
6817 (stbuf.st_mode & POSIXMODES) | 0000200);
6818 (void) sprintf(dblockp->dbuf.size, "%011o", len);
6819 (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
6821 /* write out the header */
6822 (void) writetbuf((char *)dblockp, 1);
6824 /* write out security info */
6825 blocks = TBLOCKS(len);
6826 (void) writetbuf((char *)secinfo, (int)blocks);
6828 /* restore mode, flag and size */
6829 (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
6830 dblockp->dbuf.typeflag = savflag;
6831 (void) sprintf(dblockp->dbuf.size, "%011o", savsize);
6835 * Read the data record for extended headers and then the regular header.
6836 * The data are read into the buffer and then null-terminated. Entries
6837 * for typeflag 'X' extended headers are of the format:
6838 * "%d %s=%s\n"
6840 * When an extended header record is found, the extended header must
6841 * be processed and its values used to override the values in the
6842 * normal header. The way this is done is to process the extended
6843 * header data record and set the data values, then call getdir
6844 * to process the regular header, then then to reconcile the two
6845 * sets of data.
6848 static int
6849 get_xdata(void)
6851 struct keylist_pair {
6852 int keynum;
6853 char *keylist;
6854 } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor",
6855 _X_DEVMINOR, "SUN.devminor",
6856 _X_GID, "gid",
6857 _X_GNAME, "gname",
6858 _X_LINKPATH, "linkpath",
6859 _X_PATH, "path",
6860 _X_SIZE, "size",
6861 _X_UID, "uid",
6862 _X_UNAME, "uname",
6863 _X_MTIME, "mtime",
6864 _X_LAST, "NULL" };
6865 char *lineloc;
6866 int length, i;
6867 char *keyword, *value;
6868 blkcnt_t nblocks;
6869 int bufneeded;
6870 int errors;
6872 (void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
6873 xhdr_count++;
6874 errors = 0;
6876 nblocks = TBLOCKS(stbuf.st_size);
6877 bufneeded = nblocks * TBLOCK;
6878 if (bufneeded >= xrec_size) {
6879 free(xrec_ptr);
6880 xrec_size = bufneeded + 1;
6881 if ((xrec_ptr = malloc(xrec_size)) == NULL)
6882 fatal(gettext("cannot allocate buffer"));
6885 lineloc = xrec_ptr;
6887 while (nblocks-- > 0) {
6888 readtape(lineloc);
6889 lineloc += TBLOCK;
6891 lineloc = xrec_ptr;
6892 xrec_ptr[stbuf.st_size] = '\0';
6893 while (lineloc < xrec_ptr + stbuf.st_size) {
6894 if (dblock.dbuf.typeflag == 'L') {
6895 length = xrec_size;
6896 keyword = "path";
6897 value = lineloc;
6898 } else {
6899 length = atoi(lineloc);
6900 *(lineloc + length - 1) = '\0';
6901 keyword = strchr(lineloc, ' ') + 1;
6902 value = strchr(keyword, '=') + 1;
6903 *(value - 1) = '\0';
6905 i = 0;
6906 lineloc += length;
6907 while (keylist_pair[i].keynum != (int)_X_LAST) {
6908 if (strcmp(keyword, keylist_pair[i].keylist) == 0)
6909 break;
6910 i++;
6912 errno = 0;
6913 switch (keylist_pair[i].keynum) {
6914 case _X_DEVMAJOR:
6915 Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
6916 if (errno) {
6917 (void) fprintf(stderr, gettext(
6918 "tar: Extended header major value error "
6919 "for file # %llu.\n"), xhdr_count);
6920 errors++;
6921 } else
6922 xhdr_flgs |= _X_DEVMAJOR;
6923 break;
6924 case _X_DEVMINOR:
6925 Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
6926 if (errno) {
6927 (void) fprintf(stderr, gettext(
6928 "tar: Extended header minor value error "
6929 "for file # %llu.\n"), xhdr_count);
6930 errors++;
6931 } else
6932 xhdr_flgs |= _X_DEVMINOR;
6933 break;
6934 case _X_GID:
6935 xhdr_flgs |= _X_GID;
6936 Xtarhdr.x_gid = strtol(value, NULL, 0);
6937 if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
6938 (void) fprintf(stderr, gettext(
6939 "tar: Extended header gid value error "
6940 "for file # %llu.\n"), xhdr_count);
6941 Xtarhdr.x_gid = GID_NOBODY;
6943 break;
6944 case _X_GNAME:
6945 if (utf8_local("gname", &Xtarhdr.x_gname,
6946 local_gname, value, _POSIX_NAME_MAX) == 0)
6947 xhdr_flgs |= _X_GNAME;
6948 break;
6949 case _X_LINKPATH:
6950 if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
6951 local_linkpath, value, PATH_MAX) == 0)
6952 xhdr_flgs |= _X_LINKPATH;
6953 else
6954 errors++;
6955 break;
6956 case _X_PATH:
6957 if (utf8_local("path", &Xtarhdr.x_path,
6958 local_path, value, PATH_MAX) == 0)
6959 xhdr_flgs |= _X_PATH;
6960 else
6961 errors++;
6962 break;
6963 case _X_SIZE:
6964 Xtarhdr.x_filesz = strtoull(value, NULL, 0);
6965 if (errno) {
6966 (void) fprintf(stderr, gettext(
6967 "tar: Extended header invalid filesize "
6968 "for file # %llu.\n"), xhdr_count);
6969 errors++;
6970 } else
6971 xhdr_flgs |= _X_SIZE;
6972 break;
6973 case _X_UID:
6974 xhdr_flgs |= _X_UID;
6975 Xtarhdr.x_uid = strtol(value, NULL, 0);
6976 if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
6977 (void) fprintf(stderr, gettext(
6978 "tar: Extended header uid value error "
6979 "for file # %llu.\n"), xhdr_count);
6980 Xtarhdr.x_uid = UID_NOBODY;
6982 break;
6983 case _X_UNAME:
6984 if (utf8_local("uname", &Xtarhdr.x_uname,
6985 local_uname, value, _POSIX_NAME_MAX) == 0)
6986 xhdr_flgs |= _X_UNAME;
6987 break;
6988 case _X_MTIME:
6989 get_xtime(value, &(Xtarhdr.x_mtime));
6990 if (errno)
6991 (void) fprintf(stderr, gettext(
6992 "tar: Extended header modification time "
6993 "value error for file # %llu.\n"),
6994 xhdr_count);
6995 else
6996 xhdr_flgs |= _X_MTIME;
6997 break;
6998 default:
6999 (void) fprintf(stderr,
7000 gettext("tar: unrecognized extended"
7001 " header keyword '%s'. Ignored.\n"), keyword);
7002 break;
7006 getdir(); /* get regular header */
7007 if (errors && errflag)
7008 done(1);
7009 else
7010 if (errors)
7011 Errflg = 1;
7012 return (errors);
7016 * load_info_from_xtarhdr - sets Gen and stbuf variables from
7017 * extended header
7018 * load_info_from_xtarhdr(flag, xhdrp);
7019 * u_longlong_t flag; xhdr_flgs
7020 * struct xtar_hdr *xhdrp; pointer to extended header
7021 * NOTE: called when typeflag is not 'A' and xhdr_flgs
7022 * is set.
7024 static void
7025 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
7027 if (flag & _X_DEVMAJOR) {
7028 Gen.g_devmajor = xhdrp->x_devmajor;
7030 if (flag & _X_DEVMINOR) {
7031 Gen.g_devminor = xhdrp->x_devminor;
7033 if (flag & _X_GID) {
7034 Gen.g_gid = xhdrp->x_gid;
7035 stbuf.st_gid = xhdrp->x_gid;
7037 if (flag & _X_UID) {
7038 Gen.g_uid = xhdrp->x_uid;
7039 stbuf.st_uid = xhdrp->x_uid;
7041 if (flag & _X_SIZE) {
7042 Gen.g_filesz = xhdrp->x_filesz;
7043 stbuf.st_size = xhdrp->x_filesz;
7045 if (flag & _X_MTIME) {
7046 Gen.g_mtime = xhdrp->x_mtime.tv_sec;
7047 stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
7048 stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
7053 * gen_num creates a string from a keyword and an usigned long long in the
7054 * format: %d %s=%s\n
7055 * This is part of the extended header data record.
7058 void
7059 gen_num(const char *keyword, const u_longlong_t number)
7061 char save_val[ULONGLONG_MAX_DIGITS + 1];
7062 int len;
7063 char *curr_ptr;
7065 (void) sprintf(save_val, "%llu", number);
7067 * len = length of entire line, including itself. len will be
7068 * two digits. So, add the string lengths plus the length of len,
7069 * plus a blank, an equal sign, and a newline.
7071 len = strlen(save_val) + strlen(keyword) + 5;
7072 if (xrec_offset + len > xrec_size) {
7073 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7074 fatal(gettext(
7075 "cannot allocate extended header buffer"));
7076 xrec_ptr = curr_ptr;
7077 xrec_size *= 2;
7079 (void) sprintf(&xrec_ptr[xrec_offset],
7080 "%d %s=%s\n", len, keyword, save_val);
7081 xrec_offset += len;
7085 * gen_date creates a string from a keyword and a timestruc_t in the
7086 * format: %d %s=%s\n
7087 * This is part of the extended header data record.
7088 * Currently, granularity is only microseconds, so the low-order three digits
7089 * will be truncated.
7092 void
7093 gen_date(const char *keyword, const timestruc_t time_value)
7095 /* Allow for <seconds>.<nanoseconds>\n */
7096 char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
7097 int len;
7098 char *curr_ptr;
7100 (void) sprintf(save_val, "%ld", time_value.tv_sec);
7101 len = strlen(save_val);
7102 save_val[len] = '.';
7103 (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
7106 * len = length of entire line, including itself. len will be
7107 * two digits. So, add the string lengths plus the length of len,
7108 * plus a blank, an equal sign, and a newline.
7110 len = strlen(save_val) + strlen(keyword) + 5;
7111 if (xrec_offset + len > xrec_size) {
7112 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7113 fatal(gettext(
7114 "cannot allocate extended header buffer"));
7115 xrec_ptr = curr_ptr;
7116 xrec_size *= 2;
7118 (void) sprintf(&xrec_ptr[xrec_offset],
7119 "%d %s=%s\n", len, keyword, save_val);
7120 xrec_offset += len;
7124 * gen_string creates a string from a keyword and a char * in the
7125 * format: %d %s=%s\n
7126 * This is part of the extended header data record.
7129 void
7130 gen_string(const char *keyword, const char *value)
7132 int len;
7133 char *curr_ptr;
7136 * len = length of entire line, including itself. The character length
7137 * of len must be 1-4 characters, because the maximum size of the path
7138 * or the name is PATH_MAX, which is 1024. So, assume 1 character
7139 * for len, one for the space, one for the "=", and one for the newline.
7140 * Then adjust as needed.
7142 /* LINTED constant expression */
7143 assert(PATH_MAX <= 9996);
7144 len = strlen(value) + strlen(keyword) + 4;
7145 if (len > 997)
7146 len += 3;
7147 else if (len > 98)
7148 len += 2;
7149 else if (len > 9)
7150 len += 1;
7151 if (xrec_offset + len > xrec_size) {
7152 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7153 fatal(gettext(
7154 "cannot allocate extended header buffer"));
7155 xrec_ptr = curr_ptr;
7156 xrec_size *= 2;
7158 #ifdef XHDR_DEBUG
7159 if (strcmp(keyword+1, "name") != 0)
7160 #endif
7161 (void) sprintf(&xrec_ptr[xrec_offset],
7162 "%d %s=%s\n", len, keyword, value);
7163 #ifdef XHDR_DEBUG
7164 else {
7165 len += 11;
7166 (void) sprintf(&xrec_ptr[xrec_offset],
7167 "%d %s=%snametoolong\n", len, keyword, value);
7169 #endif
7170 xrec_offset += len;
7174 * Convert time found in the extended header data to seconds and nanoseconds.
7177 void
7178 get_xtime(char *value, timestruc_t *xtime)
7180 char nanosec[10];
7181 char *period;
7182 int i;
7184 (void) memset(nanosec, '0', 9);
7185 nanosec[9] = '\0';
7187 period = strchr(value, '.');
7188 if (period != NULL)
7189 period[0] = '\0';
7190 xtime->tv_sec = strtol(value, NULL, 10);
7191 if (period == NULL)
7192 xtime->tv_nsec = 0;
7193 else {
7194 i = strlen(period +1);
7195 (void) strncpy(nanosec, period + 1, min(i, 9));
7196 xtime->tv_nsec = strtol(nanosec, NULL, 10);
7201 * Check linkpath for length.
7202 * Emit an error message and return 1 if too long.
7206 chk_path_build(
7207 char *name,
7208 char *longname,
7209 char *linkname,
7210 char *prefix,
7211 char type,
7212 int filetype)
7215 if (strlen(linkname) > (size_t)NAMSIZ) {
7216 if (Eflag > 0) {
7217 xhdr_flgs |= _X_LINKPATH;
7218 Xtarhdr.x_linkpath = linkname;
7219 } else {
7220 (void) fprintf(stderr, gettext(
7221 "tar: %s: linked to %s\n"), longname, linkname);
7222 (void) fprintf(stderr, gettext(
7223 "tar: %s: linked name too long\n"), linkname);
7224 if (errflag)
7225 done(1);
7226 else
7227 Errflg = 1;
7228 return (1);
7231 if (xhdr_flgs & _X_LINKPATH)
7232 return (build_dblock(name, tchar, type,
7233 filetype, &stbuf, stbuf.st_dev,
7234 prefix));
7235 else
7236 return (build_dblock(name, linkname, type,
7237 filetype, &stbuf, stbuf.st_dev, prefix));
7241 * Convert from UTF-8 to local character set.
7244 static int
7245 utf8_local(
7246 char *option,
7247 char **Xhdr_ptrptr,
7248 char *target,
7249 const char *source,
7250 int max_val)
7252 static iconv_t iconv_cd;
7253 char *nl_target;
7254 const char *iconv_src;
7255 char *iconv_trg;
7256 size_t inlen;
7257 size_t outlen;
7259 if (charset_type == -1) { /* iconv_open failed in earlier try */
7260 (void) fprintf(stderr, gettext(
7261 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7262 xhdr_count, source);
7263 return (1);
7264 } else if (charset_type == 0) { /* iconv_open has not yet been done */
7265 nl_target = nl_langinfo(CODESET);
7266 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7267 nl_target = "646";
7268 if (strcmp(nl_target, "646") == 0)
7269 charset_type = 1;
7270 else if (strcmp(nl_target, "UTF-8") == 0)
7271 charset_type = 3;
7272 else {
7273 if (strncmp(nl_target, "ISO", 3) == 0)
7274 nl_target += 3;
7275 charset_type = 2;
7276 errno = 0;
7277 if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
7278 (iconv_t)-1) {
7279 if (errno == EINVAL)
7280 (void) fprintf(stderr, gettext(
7281 "tar: conversion routines not "
7282 "available for current locale. "));
7283 (void) fprintf(stderr, gettext(
7284 "file # %llu: (%s) UTF-8 conversion"
7285 " failed.\n"), xhdr_count, source);
7286 charset_type = -1;
7287 return (1);
7292 /* locale using 7-bit codeset or UTF-8 locale */
7293 if (charset_type == 1 || charset_type == 3) {
7294 if (strlen(source) > max_val) {
7295 (void) fprintf(stderr, gettext(
7296 "tar: file # %llu: Extended header %s too long.\n"),
7297 xhdr_count, option);
7298 return (1);
7300 if (charset_type == 3)
7301 (void) strcpy(target, source);
7302 else if (c_utf8(target, source) != 0) {
7303 (void) fprintf(stderr, gettext(
7304 "tar: file # %llu: (%s) UTF-8 conversion"
7305 " failed.\n"), xhdr_count, source);
7306 return (1);
7308 *Xhdr_ptrptr = target;
7309 return (0);
7312 iconv_src = source;
7313 iconv_trg = target;
7314 inlen = strlen(source);
7315 outlen = max_val * UTF_8_FACTOR;
7316 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7317 (size_t)-1) { /* Error occurred: didn't convert */
7318 (void) fprintf(stderr, gettext(
7319 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7320 xhdr_count, source);
7321 /* Get remaining output; reinitialize conversion descriptor */
7322 iconv_src = (const char *)NULL;
7323 inlen = 0;
7324 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7325 return (1);
7327 /* Get remaining output; reinitialize conversion descriptor */
7328 iconv_src = (const char *)NULL;
7329 inlen = 0;
7330 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7331 (size_t)-1) { /* Error occurred: didn't convert */
7332 (void) fprintf(stderr, gettext(
7333 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7334 xhdr_count, source);
7335 return (1);
7338 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7339 if (strlen(target) > max_val) {
7340 (void) fprintf(stderr, gettext(
7341 "tar: file # %llu: Extended header %s too long.\n"),
7342 xhdr_count, option);
7343 return (1);
7345 *Xhdr_ptrptr = target;
7346 return (0);
7350 * Check gname, uname, path, and linkpath to see if they need to go in an
7351 * extended header. If they are already slated to be in an extended header,
7352 * or if they are not ascii, then they need to be in the extended header.
7353 * Then, convert all extended names to UTF-8.
7357 gen_utf8_names(const char *filename)
7359 static iconv_t iconv_cd;
7360 char *nl_target;
7361 char tempbuf[MAXNAM + 1];
7362 int nbytes;
7363 int errors;
7365 if (charset_type == -1) { /* Previous failure to open. */
7366 (void) fprintf(stderr, gettext(
7367 "tar: file # %llu: UTF-8 conversion failed.\n"),
7368 xhdr_count);
7369 return (1);
7372 if (charset_type == 0) { /* Need to get conversion descriptor */
7373 nl_target = nl_langinfo(CODESET);
7374 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7375 nl_target = "646";
7376 if (strcmp(nl_target, "646") == 0)
7377 charset_type = 1;
7378 else if (strcmp(nl_target, "UTF-8") == 0)
7379 charset_type = 3;
7380 else {
7381 if (strncmp(nl_target, "ISO", 3) == 0)
7382 nl_target += 3;
7383 charset_type = 2;
7384 errno = 0;
7385 #ifdef ICONV_DEBUG
7386 (void) fprintf(stderr,
7387 gettext("Opening iconv_cd with target %s\n"),
7388 nl_target);
7389 #endif
7390 if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
7391 (iconv_t)-1) {
7392 if (errno == EINVAL)
7393 (void) fprintf(stderr, gettext(
7394 "tar: conversion routines not "
7395 "available for current locale. "));
7396 (void) fprintf(stderr, gettext(
7397 "file (%s): UTF-8 conversion failed.\n"),
7398 filename);
7399 charset_type = -1;
7400 return (1);
7405 errors = 0;
7407 errors += local_utf8(&Xtarhdr.x_gname, local_gname,
7408 dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
7409 errors += local_utf8(&Xtarhdr.x_uname, local_uname,
7410 dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX);
7411 if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */
7412 (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
7413 tempbuf[NAMSIZ] = '\0';
7415 errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
7416 tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
7417 if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */
7418 (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
7419 tempbuf[PRESIZ] = '\0';
7420 nbytes = strlen(tempbuf);
7421 if (nbytes > 0) {
7422 tempbuf[nbytes++] = '/';
7423 tempbuf[nbytes] = '\0';
7425 (void) strncat(tempbuf + nbytes, dblock.dbuf.name,
7426 (MAXNAM - nbytes));
7427 tempbuf[MAXNAM] = '\0';
7429 errors += local_utf8(&Xtarhdr.x_path, local_path,
7430 tempbuf, iconv_cd, _X_PATH, PATH_MAX);
7432 if (errors > 0)
7433 (void) fprintf(stderr, gettext(
7434 "tar: file (%s): UTF-8 conversion failed.\n"), filename);
7436 if (errors && errflag)
7437 done(1);
7438 else
7439 if (errors)
7440 Errflg = 1;
7441 return (errors);
7444 static int
7445 local_utf8(
7446 char **Xhdr_ptrptr,
7447 char *target,
7448 const char *source,
7449 iconv_t iconv_cd,
7450 int xhdrflg,
7451 int max_val)
7453 const char *iconv_src;
7454 const char *starting_src;
7455 char *iconv_trg;
7456 size_t inlen;
7457 size_t outlen;
7458 #ifdef ICONV_DEBUG
7459 unsigned char c_to_hex;
7460 #endif
7463 * If the item is already slated for extended format, get the string
7464 * to convert from the extended header record. Otherwise, get it from
7465 * the regular (dblock) area.
7467 if (xhdr_flgs & xhdrflg) {
7468 if (charset_type == 3) { /* Already UTF-8, just copy */
7469 (void) strcpy(target, *Xhdr_ptrptr);
7470 *Xhdr_ptrptr = target;
7471 return (0);
7472 } else
7473 iconv_src = (const char *) *Xhdr_ptrptr;
7474 } else {
7475 if (charset_type == 3) /* Already in UTF-8 format */
7476 return (0); /* Don't create xhdr record */
7477 iconv_src = source;
7479 starting_src = iconv_src;
7480 iconv_trg = target;
7481 if ((inlen = strlen(iconv_src)) == 0)
7482 return (0);
7484 if (charset_type == 1) { /* locale using 7-bit codeset */
7485 if (c_utf8(target, starting_src) != 0) {
7486 (void) fprintf(stderr,
7487 gettext("tar: invalid character in"
7488 " UTF-8 conversion of '%s'\n"), starting_src);
7489 return (1);
7491 return (0);
7494 outlen = max_val * UTF_8_FACTOR;
7495 errno = 0;
7496 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7497 (size_t)-1) {
7498 /* An error occurred, or not all characters were converted */
7499 if (errno == EILSEQ)
7500 (void) fprintf(stderr,
7501 gettext("tar: invalid character in"
7502 " UTF-8 conversion of '%s'\n"), starting_src);
7503 else
7504 (void) fprintf(stderr, gettext(
7505 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7506 starting_src);
7507 /* Get remaining output; reinitialize conversion descriptor */
7508 iconv_src = (const char *)NULL;
7509 inlen = 0;
7510 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7511 return (1);
7513 /* Get remaining output; reinitialize conversion descriptor */
7514 iconv_src = (const char *)NULL;
7515 inlen = 0;
7516 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7517 (size_t)-1) { /* Error occurred: didn't convert */
7518 if (errno == EILSEQ)
7519 (void) fprintf(stderr,
7520 gettext("tar: invalid character in"
7521 " UTF-8 conversion of '%s'\n"), starting_src);
7522 else
7523 (void) fprintf(stderr, gettext(
7524 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7525 starting_src);
7526 return (1);
7529 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7530 if (strcmp(starting_src, target) != 0) {
7531 *Xhdr_ptrptr = target;
7532 xhdr_flgs |= xhdrflg;
7533 #ifdef ICONV_DEBUG
7534 (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n",
7535 strlen(starting_src), inlen, max_val, outlen);
7536 (void) fprintf(stderr, "Input string:\n ");
7537 for (inlen = 0; inlen < strlen(starting_src); inlen++) {
7538 c_to_hex = (unsigned char)starting_src[inlen];
7539 (void) fprintf(stderr, " %2.2x", c_to_hex);
7540 if (inlen % 20 == 19)
7541 (void) fprintf(stderr, "\n ");
7543 (void) fprintf(stderr, "\nOutput string:\n ");
7544 for (inlen = 0; inlen < strlen(target); inlen++) {
7545 c_to_hex = (unsigned char)target[inlen];
7546 (void) fprintf(stderr, " %2.2x", c_to_hex);
7547 if (inlen % 20 == 19)
7548 (void) fprintf(stderr, "\n ");
7550 (void) fprintf(stderr, "\n");
7551 #endif
7554 return (0);
7558 * Function to test each byte of the source string to make sure it is
7559 * in within bounds (value between 0 and 127).
7560 * If valid, copy source to target.
7564 c_utf8(char *target, const char *source)
7566 size_t len;
7567 const char *thischar;
7569 len = strlen(source);
7570 thischar = source;
7571 while (len-- > 0) {
7572 if (!isascii((int)(*thischar++)))
7573 return (1);
7576 (void) strcpy(target, source);
7577 return (0);
7581 #if defined(O_XATTR)
7582 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
7584 static void
7585 prepare_xattr(
7586 char **attrbuf,
7587 char *filename,
7588 char *attrpath,
7589 char typeflag,
7590 struct linkbuf *linkinfo,
7591 int *rlen)
7593 char *bufhead; /* ptr to full buffer */
7594 char *aptr;
7595 struct xattr_hdr *hptr; /* ptr to header in bufhead */
7596 struct xattr_buf *tptr; /* ptr to pathing pieces */
7597 int totalen; /* total buffer length */
7598 int len; /* length returned to user */
7599 int stringlen; /* length of filename + attr */
7601 * length of filename + attr
7602 * in link section
7604 int linkstringlen;
7605 int complen; /* length of pathing section */
7606 int linklen; /* length of link section */
7607 int attrnames_index; /* attrnames starting index */
7610 * Release previous buffer
7613 if (*attrbuf != (char *)NULL) {
7614 free(*attrbuf);
7615 *attrbuf = NULL;
7619 * First add in fixed size stuff
7621 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7624 * Add space for two nulls
7626 stringlen = strlen(attrpath) + strlen(filename) + 2;
7627 complen = stringlen + sizeof (struct xattr_buf);
7629 len += stringlen;
7632 * Now add on space for link info if any
7635 if (linkinfo != NULL) {
7637 * Again add space for two nulls
7639 linkstringlen = strlen(linkinfo->pathname) +
7640 strlen(linkinfo->attrname) + 2;
7641 linklen = linkstringlen + sizeof (struct xattr_buf);
7642 len += linklen;
7643 } else {
7644 linklen = 0;
7648 * Now add padding to end to fill out TBLOCK
7650 * Function returns size of real data and not size + padding.
7653 totalen = ROUNDTOTBLOCK(len);
7655 if ((bufhead = calloc(1, totalen)) == NULL) {
7656 fatal(gettext("Out of memory."));
7661 * Now we can fill in the necessary pieces
7665 * first fill in the fixed header
7667 hptr = (struct xattr_hdr *)bufhead;
7668 (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7669 (void) sprintf(hptr->h_component_len, "%0*d",
7670 sizeof (hptr->h_component_len) - 1, complen);
7671 (void) sprintf(hptr->h_link_component_len, "%0*d",
7672 sizeof (hptr->h_link_component_len) - 1, linklen);
7673 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7676 * Now fill in the filename + attrnames section
7677 * The filename and attrnames section can be composed of two or more
7678 * path segments separated by a null character. The first segment
7679 * is the path to the parent file that roots the entire sequence in
7680 * the normal name space. The remaining segments describes a path
7681 * rooted at the hidden extended attribute directory of the leaf file of
7682 * the previous segment, making it possible to name attributes on
7683 * attributes. Thus, if we are just archiving an extended attribute,
7684 * the second segment will contain the attribute name. If we are
7685 * archiving a system attribute of an extended attribute, then the
7686 * second segment will contain the attribute name, and a third segment
7687 * will contain the system attribute name. The attribute pathing
7688 * information is obtained from 'attrpath'.
7691 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7692 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7693 stringlen);
7694 (void) strcpy(tptr->h_names, filename);
7695 attrnames_index = strlen(filename) + 1;
7696 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
7697 tptr->h_typeflag = typeflag;
7700 * Split the attrnames section into two segments if 'attrpath'
7701 * contains pathing information for a system attribute of an
7702 * extended attribute. We split them by replacing the '/' with
7703 * a '\0'.
7705 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
7706 *aptr = '\0';
7710 * Now fill in the optional link section if we have one
7713 if (linkinfo != (struct linkbuf *)NULL) {
7714 tptr = (struct xattr_buf *)(bufhead +
7715 sizeof (struct xattr_hdr) + complen);
7717 (void) sprintf(tptr->h_namesz, "%0*d",
7718 sizeof (tptr->h_namesz) - 1, linkstringlen);
7719 (void) strcpy(tptr->h_names, linkinfo->pathname);
7720 (void) strcpy(
7721 &tptr->h_names[strlen(linkinfo->pathname) + 1],
7722 linkinfo->attrname);
7723 tptr->h_typeflag = typeflag;
7725 *attrbuf = (char *)bufhead;
7726 *rlen = len;
7729 #else
7730 static void
7731 prepare_xattr(
7732 char **attrbuf,
7733 char *filename,
7734 char *attrname,
7735 char typeflag,
7736 struct linkbuf *linkinfo,
7737 int *rlen)
7739 *attrbuf = NULL;
7740 *rlen = 0;
7742 #endif
7745 getstat(int dirfd, char *longname, char *shortname, char *attrparent)
7748 int i, j;
7749 int printerr;
7750 int slnkerr;
7751 struct stat symlnbuf;
7753 if (!hflag)
7754 i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
7755 else
7756 i = fstatat(dirfd, shortname, &stbuf, 0);
7758 if (i < 0) {
7759 /* Initialize flag to print error mesg. */
7760 printerr = 1;
7762 * If stat is done, then need to do lstat
7763 * to determine whether it's a sym link
7765 if (hflag) {
7766 /* Save returned error */
7767 slnkerr = errno;
7769 j = fstatat(dirfd, shortname,
7770 &symlnbuf, AT_SYMLINK_NOFOLLOW);
7772 * Suppress error message when file is a symbolic link
7773 * and function modifier 'l' is off. Exception: when
7774 * a symlink points to a symlink points to a
7775 * symlink ... and we get past MAXSYMLINKS. That
7776 * error will cause a file not to be archived, and
7777 * needs to be printed.
7779 if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
7780 (S_ISLNK(symlnbuf.st_mode)))
7781 printerr = 0;
7784 * Restore errno in case the lstat
7785 * on symbolic link change
7787 errno = slnkerr;
7790 if (printerr) {
7791 (void) fprintf(stderr, gettext(
7792 "tar: %s%s%s%s: %s\n"),
7793 (attrparent == NULL) ? "" : gettext("attribute "),
7794 (attrparent == NULL) ? "" : attrparent,
7795 (attrparent == NULL) ? "" : gettext(" of "),
7796 longname, strerror(errno));
7797 Errflg = 1;
7799 return (1);
7801 return (0);
7805 * Recursively archive the extended attributes and/or extended system attributes
7806 * of the base file, longname. Note: extended system attribute files will be
7807 * archived only if the extended system attributes are not transient (i.e. the
7808 * extended system attributes are other than the default values).
7810 * If -@ was specified and the underlying file system supports it, archive the
7811 * extended attributes, and if there is a system attribute associated with the
7812 * extended attribute, then recursively call xattrs_put() to archive the
7813 * hidden attribute directory and the extended system attribute. If -/ was
7814 * specified and the underlying file system supports it, archive the extended
7815 * system attributes. Read-only extended system attributes are never archived.
7817 * Currently, there cannot be attributes on attributes; only system
7818 * attributes on attributes. In addition, there cannot be attributes on
7819 * system attributes. A file and it's attribute directory hierarchy looks as
7820 * follows:
7821 * longname ----> . ("." is the hidden attribute directory)
7823 * ----------------------------
7824 * | |
7825 * <sys_attr_name> <attr_name> ----> .
7827 * <sys_attr_name>
7830 #if defined(O_XATTR)
7831 static void
7832 xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
7834 char *filename = (attrparent == NULL) ? shortname : attrparent;
7835 int arc_rwsysattr = 0;
7836 int dirfd;
7837 int fd = -1;
7838 int rw_sysattr = 0;
7839 int ext_attr = 0;
7840 int rc;
7841 DIR *dirp;
7842 struct dirent *dp;
7843 attr_data_t *attrinfo = NULL;
7846 * If the underlying file system supports it, then archive the extended
7847 * attributes if -@ was specified, and the extended system attributes
7848 * if -/ was specified.
7850 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
7851 &ext_attr) != ATTR_OK) {
7852 return;
7856 * Only want to archive a read-write extended system attribute file
7857 * if it contains extended system attribute settings that are not the
7858 * default values.
7860 #if defined(_PC_SATTR_ENABLED)
7861 if (saflag) {
7862 int filefd;
7863 nvlist_t *slist = NULL;
7865 /* Determine if there are non-transient system attributes */
7866 errno = 0;
7867 if ((filefd = open(filename, O_RDONLY)) == -1) {
7868 if (attrparent == NULL) {
7869 vperror(0, gettext(
7870 "unable to open file %s"), longname);
7872 return;
7874 if (((slist = sysattr_list(basename(myname), filefd,
7875 filename)) != NULL) || (errno != 0)) {
7876 arc_rwsysattr = 1;
7878 if (slist != NULL) {
7879 (void) nvlist_free(slist);
7880 slist = NULL;
7882 (void) close(filefd);
7886 * If we aren't archiving extended system attributes, and we are
7887 * processing an attribute, or if we are archiving extended system
7888 * attributes, and there are are no extended attributes, then there's
7889 * no need to open up the attribute directory of the file unless the
7890 * extended system attributes are not transient (i.e, the system
7891 * attributes are not the default values).
7893 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
7894 (saflag && !ext_attr))) {
7895 return;
7897 #endif /* _PC_SATTR_ENABLED */
7899 /* open the parent attribute directory */
7900 fd = attropen(filename, ".", O_RDONLY);
7901 if (fd < 0) {
7902 vperror(0, gettext(
7903 "unable to open attribute directory for %s%s%sfile %s"),
7904 (attrparent == NULL) ? "" : gettext("attribute "),
7905 (attrparent == NULL) ? "" : attrparent,
7906 (attrparent == NULL) ? "" : gettext(" of "),
7907 longname);
7908 return;
7912 * We need to change into the parent's attribute directory to determine
7913 * if each of the attributes should be archived.
7915 if (fchdir(fd) < 0) {
7916 vperror(0, gettext(
7917 "cannot change to attribute directory of %s%s%sfile %s"),
7918 (attrparent == NULL) ? "" : gettext("attribute "),
7919 (attrparent == NULL) ? "" : attrparent,
7920 (attrparent == NULL) ? "" : gettext(" of "),
7921 longname);
7922 (void) close(fd);
7923 return;
7926 if (((dirfd = dup(fd)) == -1) ||
7927 ((dirp = fdopendir(dirfd)) == NULL)) {
7928 (void) fprintf(stderr, gettext(
7929 "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7930 (attrparent == NULL) ? "" : gettext("attribute "),
7931 (attrparent == NULL) ? "" : attrparent,
7932 (attrparent == NULL) ? "" : gettext(" of "),
7933 longname);
7934 if (fd > 0) {
7935 (void) close(fd);
7937 return;
7940 while ((dp = readdir(dirp)) != NULL) {
7941 if (strcmp(dp->d_name, "..") == 0) {
7942 continue;
7943 } else if (strcmp(dp->d_name, ".") == 0) {
7944 Hiddendir = 1;
7945 } else {
7946 Hiddendir = 0;
7949 /* Determine if this attribute should be archived */
7950 if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
7951 &rw_sysattr) != ATTR_OK) {
7952 continue;
7955 /* gather the attribute's information to pass to putfile() */
7956 if ((fill_in_attr_info(dp->d_name, longname, attrparent,
7957 fd, rw_sysattr, &attrinfo)) == 1) {
7958 continue;
7961 /* add the attribute to the archive */
7962 rc = putfile(longname, dp->d_name, parent, attrinfo,
7963 XATTR_FILE, LEV0, SYMLINK_LEV0);
7965 if (exitflag) {
7966 break;
7969 #if defined(_PC_SATTR_ENABLED)
7971 * If both -/ and -@ were specified, then archive the
7972 * attribute's extended system attributes and hidden directory
7973 * by making a recursive call to xattrs_put().
7975 if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
7976 (Hiddendir == 0)) {
7978 xattrs_put(longname, shortname, parent, dp->d_name);
7981 * Change back to the parent's attribute directory
7982 * to process any further attributes.
7984 if (fchdir(fd) < 0) {
7985 vperror(0, gettext(
7986 "cannot change back to attribute directory "
7987 "of file %s"), longname);
7988 break;
7991 #endif /* _PC_SATTR_ENABLED */
7994 if (attrinfo != NULL) {
7995 if (attrinfo->attr_parent != NULL) {
7996 free(attrinfo->attr_parent);
7998 free(attrinfo->attr_path);
7999 free(attrinfo);
8001 (void) closedir(dirp);
8002 if (fd != -1) {
8003 (void) close(fd);
8006 /* Change back to the parent directory of the base file */
8007 if (attrparent == NULL) {
8008 (void) tar_chdir(parent);
8010 Hiddendir = 0;
8012 #else
8013 static void
8014 xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
8017 #endif /* O_XATTR */
8019 static int
8020 put_link(char *name, char *longname, char *component, char *longattrname,
8021 char *prefix, int filetype, char type)
8024 if (stbuf.st_nlink > 1) {
8025 struct linkbuf *lp;
8026 int found = 0;
8028 for (lp = ihead; lp != NULL; lp = lp->nextp)
8029 if (lp->inum == stbuf.st_ino &&
8030 lp->devnum == stbuf.st_dev) {
8031 found++;
8032 break;
8034 if (found) {
8035 #if defined(O_XATTR)
8036 if (filetype == XATTR_FILE)
8037 if (put_xattr_hdr(longname, component,
8038 longattrname, prefix, type, filetype, lp)) {
8039 goto out;
8041 #endif
8042 stbuf.st_size = (off_t)0;
8043 if (filetype != XATTR_FILE) {
8044 tomodes(&stbuf);
8045 if (chk_path_build(name, longname, lp->pathname,
8046 prefix, type, filetype) > 0) {
8047 goto out;
8051 if (mulvol && tapepos + 1 >= blocklim)
8052 newvol();
8053 (void) writetbuf((char *)&dblock, 1);
8055 * write_ancillary() is not needed here.
8056 * The first link is handled in the following
8057 * else statement. No need to process ACLs
8058 * for other hard links since they are the
8059 * same file.
8062 if (vflag) {
8063 if (NotTape)
8064 dlog("seek = %" FMT_blkcnt_t
8065 "K\n", K(tapepos));
8066 if (filetype == XATTR_FILE) {
8067 (void) fprintf(vfile, gettext(
8068 "a %s attribute %s link to "
8069 "%s attribute %s\n"),
8070 name, component, name,
8071 lp->attrname);
8072 } else {
8073 (void) fprintf(vfile, gettext(
8074 "a %s link to %s\n"),
8075 longname, lp->pathname);
8078 lp->count--;
8079 return (0);
8080 } else {
8081 lp = (struct linkbuf *)getmem(sizeof (*lp));
8082 if (lp != (struct linkbuf *)NULL) {
8083 lp->nextp = ihead;
8084 ihead = lp;
8085 lp->inum = stbuf.st_ino;
8086 lp->devnum = stbuf.st_dev;
8087 lp->count = stbuf.st_nlink - 1;
8088 if (filetype == XATTR_FILE) {
8089 (void) strcpy(lp->pathname, longname);
8090 (void) strcpy(lp->attrname,
8091 component);
8092 } else {
8093 (void) strcpy(lp->pathname, longname);
8094 (void) strcpy(lp->attrname, "");
8100 out:
8101 return (1);
8104 static int
8105 put_extra_attributes(char *longname, char *shortname, char *longattrname,
8106 char *prefix, int filetype, char typeflag)
8108 static acl_t *aclp = NULL;
8109 int error;
8111 if (aclp != NULL) {
8112 acl_free(aclp);
8113 aclp = NULL;
8115 #if defined(O_XATTR)
8116 if ((atflag || saflag) && (filetype == XATTR_FILE)) {
8117 if (put_xattr_hdr(longname, shortname, longattrname, prefix,
8118 typeflag, filetype, NULL)) {
8119 return (1);
8122 #endif
8124 /* ACL support */
8125 if (pflag) {
8126 char *secinfo = NULL;
8127 int len = 0;
8129 /* ACL support */
8130 if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
8132 * Get ACL info: dont bother allocating space if
8133 * there is only a trivial ACL.
8135 if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
8136 &aclp)) != 0) {
8137 (void) fprintf(stderr, gettext(
8138 "%s: failed to retrieve acl : %s\n"),
8139 longname, acl_strerror(error));
8140 return (1);
8144 /* append security attributes if any */
8145 if (aclp != NULL) {
8146 (void) append_secattr(&secinfo, &len, acl_cnt(aclp),
8147 acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8148 ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
8149 UFSD_ACL : ACE_ACL);
8152 if (Tflag) {
8153 /* append Trusted Extensions extended attributes */
8154 append_ext_attr(shortname, &secinfo, &len);
8155 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8157 } else if (aclp != NULL) {
8158 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8161 return (0);
8164 #if defined(O_XATTR)
8165 static int
8166 put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
8167 int typeflag, int filetype, struct linkbuf *lp)
8169 char *lname = NULL;
8170 char *sname = NULL;
8171 int error = 0;
8172 static char *attrbuf = NULL;
8173 int attrlen;
8175 lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
8176 strlen(shortname) + strlen(".hdr") + 1);
8178 if (lname == NULL) {
8179 fatal(gettext("Out of Memory."));
8181 sname = malloc(sizeof (char) * strlen(shortname) +
8182 strlen(".hdr") + 1);
8183 if (sname == NULL) {
8184 fatal(gettext("Out of Memory."));
8187 (void) sprintf(sname, "%s.hdr", shortname);
8188 (void) sprintf(lname, "/dev/null/%s", sname);
8190 if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
8191 sizeof (dblock.dbuf.name)) {
8192 fatal(gettext(
8193 "Buffer overflow writing extended attribute file name"));
8197 * dump extended attr lookup info
8199 prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
8200 write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
8202 (void) sprintf(lname, "/dev/null/%s", shortname);
8203 (void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
8206 * Set up filename for attribute
8209 error = build_dblock(lname, tchar, '0', filetype,
8210 &stbuf, stbuf.st_dev, prefix);
8211 free(lname);
8212 free(sname);
8214 return (error);
8216 #endif
8218 #if defined(O_XATTR)
8219 static int
8220 read_xattr_hdr(attr_data_t **attrinfo)
8222 char buf[TBLOCK];
8223 char *attrparent = NULL;
8224 blkcnt_t blocks;
8225 char *tp;
8226 off_t bytes;
8227 int comp_len, link_len;
8228 int namelen;
8229 int attrparentlen;
8230 int parentfilelen;
8232 if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
8233 return (1);
8235 bytes = stbuf.st_size;
8236 if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
8237 (void) fprintf(stderr, gettext(
8238 "Insufficient memory for extended attribute\n"));
8239 return (1);
8242 tp = (char *)xattrhead;
8243 blocks = TBLOCKS(bytes);
8244 while (blocks-- > 0) {
8245 readtape(buf);
8246 if (bytes <= TBLOCK) {
8247 (void) memcpy(tp, buf, (size_t)bytes);
8248 break;
8249 } else {
8250 (void) memcpy(tp, buf, TBLOCK);
8251 tp += TBLOCK;
8253 bytes -= TBLOCK;
8257 * Validate that we can handle header format
8259 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8260 (void) fprintf(stderr,
8261 gettext("Unknown extended attribute format encountered\n"));
8262 (void) fprintf(stderr,
8263 gettext("Disabling extended attribute parsing\n"));
8264 xattrbadhead = 1;
8265 return (0);
8267 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8268 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8269 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8270 sizeof (struct xattr_hdr));
8271 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8272 if (link_len > 0)
8273 xattr_linkp = (struct xattr_buf *)
8274 ((int)xattrp + (int)comp_len);
8275 else
8276 xattr_linkp = NULL;
8279 * Gather the attribute path from the filename and attrnames section.
8280 * The filename and attrnames section can be composed of two or more
8281 * path segments separated by a null character. The first segment
8282 * is the path to the parent file that roots the entire sequence in
8283 * the normal name space. The remaining segments describes a path
8284 * rooted at the hidden extended attribute directory of the leaf file of
8285 * the previous segment, making it possible to name attributes on
8286 * attributes.
8288 parentfilelen = strlen(xattrp->h_names);
8289 xattrapath = xattrp->h_names + parentfilelen + 1;
8290 if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
8292 * The attrnames section contains a system attribute on an
8293 * attribute. Save the name of the attribute for use later,
8294 * and replace the null separating the attribute name from
8295 * the system attribute name with a '/' so that xattrapath can
8296 * be used to display messages with the full attribute path name
8297 * rooted at the hidden attribute directory of the base file
8298 * in normal name space.
8300 attrparent = strdup(xattrapath);
8301 attrparentlen = strlen(attrparent);
8302 xattrapath[attrparentlen] = '/';
8304 if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
8305 xattrapath + attrparentlen + 1, xattrapath, attrparent,
8306 -1, 0, attrinfo)) == 1) {
8307 free(attrparent);
8308 return (1);
8311 /* Gather link info */
8312 if (xattr_linkp) {
8313 xattr_linkaname = xattr_linkp->h_names +
8314 strlen(xattr_linkp->h_names) + 1;
8315 } else {
8316 xattr_linkaname = NULL;
8319 return (0);
8321 #else
8322 static int
8323 read_xattr_hdr(attr_data_t **attrinfo)
8325 return (0);
8327 #endif
8330 * skip over extra slashes in string.
8332 * For example:
8333 * /usr/tmp/////
8335 * would return pointer at
8336 * /usr/tmp/////
8339 static char *
8340 skipslashes(char *string, char *start)
8342 while ((string > start) && *(string - 1) == '/') {
8343 string--;
8346 return (string);
8350 * Return the parent directory of a given path.
8352 * Examples:
8353 * /usr/tmp return /usr
8354 * /usr/tmp/file return /usr/tmp
8355 * / returns .
8356 * /usr returns /
8357 * file returns .
8359 * dir is assumed to be at least as big as path.
8361 static void
8362 get_parent(char *path, char *dir)
8364 char *s;
8365 char tmpdir[PATH_MAX + 1];
8367 if (strlen(path) > PATH_MAX) {
8368 fatal(gettext("pathname is too long"));
8370 (void) strcpy(tmpdir, path);
8371 chop_endslashes(tmpdir);
8373 if ((s = strrchr(tmpdir, '/')) == NULL) {
8374 (void) strcpy(dir, ".");
8375 } else {
8376 s = skipslashes(s, tmpdir);
8377 *s = '\0';
8378 if (s == tmpdir)
8379 (void) strcpy(dir, "/");
8380 else
8381 (void) strcpy(dir, tmpdir);
8385 #if defined(O_XATTR)
8386 static char *
8387 get_component(char *path)
8389 char *ptr;
8391 ptr = strrchr(path, '/');
8392 if (ptr == NULL) {
8393 return (path);
8394 } else {
8396 * Handle trailing slash
8398 if (*(ptr + 1) == '\0')
8399 return (ptr);
8400 else
8401 return (ptr + 1);
8404 #else
8405 static char *
8406 get_component(char *path)
8408 return (path);
8410 #endif
8412 #if defined(O_XATTR)
8413 static int
8414 retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
8415 int oflag, mode_t mode)
8417 int dirfd;
8418 int ofilefd = -1;
8419 struct timeval times[2];
8420 mode_t newmode;
8421 struct stat parentstat;
8422 acl_t *aclp = NULL;
8423 int error;
8426 * We couldn't get to attrdir. See if its
8427 * just a mode problem on the parent file.
8428 * for example: a mode such as r-xr--r--
8429 * on a ufs file system without extended
8430 * system attribute support won't let us
8431 * create an attribute dir if it doesn't
8432 * already exist, and on a ufs file system
8433 * with extended system attribute support
8434 * won't let us open the attribute for
8435 * write.
8437 * If file has a non-trivial ACL, then save it
8438 * off so that we can place it back on after doing
8439 * chmod's.
8441 if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
8442 O_RDONLY)) == -1) {
8443 return (-1);
8445 if (fstat(dirfd, &parentstat) == -1) {
8446 (void) fprintf(stderr, gettext(
8447 "tar: cannot stat %sfile %s: %s\n"),
8448 (pdirfd == -1) ? "" : gettext("parent of "),
8449 (pdirfd == -1) ? dirp : name, strerror(errno));
8450 return (-1);
8452 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
8453 (void) fprintf(stderr, gettext(
8454 "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8455 (pdirfd == -1) ? "" : gettext("parent of "),
8456 (pdirfd == -1) ? dirp : name, strerror(errno));
8457 return (-1);
8460 newmode = S_IWUSR | parentstat.st_mode;
8461 if (fchmod(dirfd, newmode) == -1) {
8462 (void) fprintf(stderr,
8463 gettext(
8464 "tar: cannot fchmod %sfile %s to %o: %s\n"),
8465 (pdirfd == -1) ? "" : gettext("parent of "),
8466 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8467 if (aclp)
8468 acl_free(aclp);
8469 return (-1);
8473 if (pdirfd == -1) {
8475 * We weren't able to create the attribute directory before.
8476 * Now try again.
8478 ofilefd = attropen(dirp, ".", oflag);
8479 } else {
8481 * We weren't able to create open the attribute before.
8482 * Now try again.
8484 ofilefd = openat(pdirfd, name, oflag, mode);
8488 * Put mode back to original
8490 if (fchmod(dirfd, parentstat.st_mode) == -1) {
8491 (void) fprintf(stderr,
8492 gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8493 (pdirfd == -1) ? "" : gettext("parent of "),
8494 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8497 if (aclp) {
8498 error = facl_set(dirfd, aclp);
8499 if (error) {
8500 (void) fprintf(stderr,
8501 gettext("tar: failed to set acl entries on "
8502 "%sfile %s\n"),
8503 (pdirfd == -1) ? "" : gettext("parent of "),
8504 (pdirfd == -1) ? dirp : name);
8506 acl_free(aclp);
8510 * Put back time stamps
8513 times[0].tv_sec = parentstat.st_atime;
8514 times[0].tv_usec = 0;
8515 times[1].tv_sec = parentstat.st_mtime;
8516 times[1].tv_usec = 0;
8518 (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
8520 (void) close(dirfd);
8522 return (ofilefd);
8524 #endif
8526 #if !defined(O_XATTR)
8527 static int
8528 openat64(int fd, const char *name, int oflag, mode_t cmode)
8530 return (open64(name, oflag, cmode));
8533 static int
8534 openat(int fd, const char *name, int oflag, mode_t cmode)
8536 return (open(name, oflag, cmode));
8539 static int
8540 fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
8542 if (flag == AT_SYMLINK_NOFOLLOW)
8543 return (lchown(name, owner, group));
8544 else
8545 return (chown(name, owner, group));
8548 static int
8549 renameat(int fromfd, char *old, int tofd, char *new)
8551 return (rename(old, new));
8554 static int
8555 futimesat(int fd, char *path, struct timeval times[2])
8557 return (utimes(path, times));
8560 static int
8561 unlinkat(int dirfd, char *path, int flag)
8563 if (flag == AT_REMOVEDIR)
8564 return (rmdir(path));
8565 else
8566 return (unlink(path));
8569 static int
8570 fstatat(int fd, char *path, struct stat *buf, int flag)
8572 if (flag == AT_SYMLINK_NOFOLLOW)
8573 return (lstat(path, buf));
8574 else
8575 return (stat(path, buf));
8578 static int
8579 attropen(char *file, char *attr, int omode, mode_t cmode)
8581 errno = ENOTSUP;
8582 return (-1);
8584 #endif
8586 static void
8587 chop_endslashes(char *path)
8589 char *end, *ptr;
8592 * Chop of slashes, but not if all we have is slashes
8593 * for example: ////
8594 * should make no changes, otherwise it will screw up
8595 * checkdir
8597 end = &path[strlen(path) -1];
8598 if (*end == '/' && end != path) {
8599 ptr = skipslashes(end, path);
8600 if (ptr != NULL && ptr != path) {
8601 *ptr = '\0';
8605 /* Trusted Extensions */
8608 * append_ext_attr():
8610 * Append extended attributes and other information into the buffer
8611 * that gets written to the ancillary file.
8613 * With option 'T', we create a tarfile which
8614 * has an ancillary file each corresponding archived file.
8615 * Each ancillary file contains 1 or more of the
8616 * following attributes:
8618 * attribute type attribute process procedure
8619 * ---------------- ---------------- --------------------------
8620 * DIR_TYPE = 'D' directory flag append if a directory
8621 * LBL_TYPE = 'L' SL[IL] or SL append ascii label
8625 static void
8626 append_ext_attr(char *shortname, char **secinfo, int *len)
8628 bslabel_t b_slabel; /* binary sensitvity label */
8629 char *ascii = NULL; /* ascii label */
8632 * For each attribute type, append it if it is
8633 * relevant to the file type.
8637 * For attribute type DIR_TYPE,
8638 * append it to the following file type:
8640 * S_IFDIR: directories
8644 * For attribute type LBL_TYPE,
8645 * append it to the following file type:
8647 * S_IFDIR: directories (including mld, sld)
8648 * S_IFLNK: symbolic link
8649 * S_IFREG: regular file but not hard link
8650 * S_IFIFO: FIFO file but not hard link
8651 * S_IFCHR: char special file but not hard link
8652 * S_IFBLK: block special file but not hard link
8654 switch (stbuf.st_mode & S_IFMT) {
8656 case S_IFDIR:
8659 * append DIR_TYPE
8661 (void) append_secattr(secinfo, len, 1,
8662 "\0", DIR_TYPE);
8665 * Get and append attribute types LBL_TYPE.
8666 * For directories, LBL_TYPE contains SL.
8668 /* get binary sensitivity label */
8669 if (getlabel(shortname, &b_slabel) != 0) {
8670 (void) fprintf(stderr,
8671 gettext("tar: can't get sensitvity label for "
8672 " %s, getlabel() error: %s\n"),
8673 shortname, strerror(errno));
8674 } else {
8675 /* get ascii SL */
8676 if (bsltos(&b_slabel, &ascii,
8677 0, 0) <= 0) {
8678 (void) fprintf(stderr,
8679 gettext("tar: can't get ascii SL for"
8680 " %s\n"), shortname);
8681 } else {
8682 /* append LBL_TYPE */
8683 (void) append_secattr(secinfo, len,
8684 strlen(ascii) + 1, ascii,
8685 LBL_TYPE);
8687 /* free storage */
8688 if (ascii != NULL) {
8689 free(ascii);
8690 ascii = (char *)0;
8695 break;
8697 case S_IFLNK:
8698 case S_IFREG:
8699 case S_IFIFO:
8700 case S_IFCHR:
8701 case S_IFBLK:
8703 /* get binary sensitivity label */
8704 if (getlabel(shortname, &b_slabel) != 0) {
8705 (void) fprintf(stderr,
8706 gettext("tar: can't get sensitivty label for %s, "
8707 "getlabel() error: %s\n"),
8708 shortname, strerror(errno));
8709 } else {
8710 /* get ascii IL[SL] */
8711 if (bsltos(&b_slabel, &ascii, 0, 0) <= 0) {
8712 (void) fprintf(stderr,
8713 gettext("tar: can't translate sensitivity "
8714 " label for %s\n"), shortname);
8715 } else {
8716 char *cmw_label;
8717 size_t cmw_length;
8719 cmw_length = strlen("ADMIN_LOW [] ") +
8720 strlen(ascii);
8721 if ((cmw_label = malloc(cmw_length)) == NULL) {
8722 (void) fprintf(stderr, gettext(
8723 "Insufficient memory for label\n"));
8724 exit(1);
8726 /* append LBL_TYPE */
8727 (void) snprintf(cmw_label, cmw_length,
8728 "ADMIN_LOW [%s]", ascii);
8729 (void) append_secattr(secinfo, len,
8730 strlen(cmw_label) + 1, cmw_label,
8731 LBL_TYPE);
8733 /* free storage */
8734 if (ascii != NULL) {
8735 free(cmw_label);
8736 free(ascii);
8737 ascii = (char *)0;
8741 break;
8743 default:
8744 break;
8745 } /* end switch for LBL_TYPE */
8748 /* DONE !! */
8749 return;
8751 } /* end of append_ext_attr */
8755 * Name: extract_attr()
8757 * Description:
8758 * Process attributes from the ancillary file due to
8759 * the T option.
8761 * Call by doxtract() as part of the switch case structure.
8762 * Making this a separate routine because the nesting are too
8763 * deep in doxtract, thus, leaving very little space
8764 * on each line for instructions.
8766 * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
8768 * For option 'T', following are possible attributes in
8769 * a TS 8 ancillary file: (NOTE: No IL support)
8771 * attribute type attribute process procedure
8772 * ---------------- ---------------- -------------------------
8773 * # LBL_TYPE = 'L' SL construct binary label
8774 * # APRIV_TYPE = 'P' allowed priv construct privileges
8775 * # FPRIV_TYPE = 'p' forced priv construct privileges
8776 * # COMP_TYPE = 'C' path component construct real path
8777 * # DIR_TYPE = 'D' directory flag note it is a directory
8778 * $ UFSD_ACL = '1' ACL data construct ACL entries
8779 * ATTR_FLAG_TYPE = 'F' file attr flags construct binary flags
8780 * LK_COMP_TYPE = 'K' linked path comp construct linked real path
8782 * note: # = attribute names common between TS 8 & TS 2.5 ancillary
8783 * files.
8784 * $ = ACL attribute is processed for the option 'p', it doesn't
8785 * need option 'T'.
8787 * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
8790 static void
8791 extract_attr(char **file_ptr, struct sec_attr *attr)
8793 int reterr, err;
8794 char *dummy_buf; /* for attribute extract */
8796 dummy_buf = attr->attr_info;
8798 switch (attr->attr_type) {
8800 case DIR_TYPE:
8802 dir_flag++;
8803 break;
8805 case LBL_TYPE:
8808 * LBL_TYPE is used to indicate SL for directory, and
8809 * CMW label for other file types.
8812 if (!dir_flag) { /* not directory */
8813 /* Skip over IL portion */
8814 char *sl_ptr = strchr(dummy_buf, '[');
8816 if (sl_ptr == NULL)
8817 err = 0;
8818 else
8819 err = stobsl(sl_ptr, &bs_label,
8820 NEW_LABEL, &reterr);
8821 } else { /* directory */
8822 err = stobsl(dummy_buf, &bs_label,
8823 NEW_LABEL, &reterr);
8825 if (err == 0) {
8826 (void) fprintf(stderr, gettext("tar: "
8827 "can't convert %s to binary label\n"),
8828 dummy_buf);
8829 bslundef(&bs_label);
8830 } else if (!blequal(&bs_label, &admin_low) &&
8831 !blequal(&bs_label, &admin_high)) {
8832 bslabel_t *from_label;
8833 char *buf;
8834 char tempbuf[MAXPATHLEN];
8836 if (*orig_namep != '/') {
8837 /* got relative linked to path */
8838 (void) getcwd(tempbuf, (sizeof (tempbuf)));
8839 (void) strncat(tempbuf, "/", MAXPATHLEN);
8840 } else
8841 *tempbuf = '\0';
8843 buf = real_path;
8844 (void) strncat(tempbuf, orig_namep, MAXPATHLEN);
8845 from_label = getlabelbypath(tempbuf);
8846 if (from_label != NULL) {
8847 if (blequal(from_label, &admin_low)) {
8848 if ((getpathbylabel(tempbuf, buf,
8849 MAXPATHLEN, &bs_label) == NULL)) {
8850 (void) fprintf(stderr,
8851 gettext("tar: "
8852 "can't get zone root path for "
8853 "%s\n"), tempbuf);
8854 } else
8855 rpath_flag = 1;
8857 free(from_label);
8860 break;
8862 case COMP_TYPE:
8864 rebuild_comp_path(dummy_buf, file_ptr);
8865 break;
8867 case LK_COMP_TYPE:
8869 if (rebuild_lk_comp_path(dummy_buf, file_ptr)
8870 == 0) {
8871 lk_rpath_flag = 1;
8872 } else {
8873 (void) fprintf(stderr, gettext("tar: warning: link's "
8874 "target pathname might be invalid.\n"));
8875 lk_rpath_flag = 0;
8877 break;
8878 case APRIV_TYPE:
8879 ignored_aprivs++;
8880 break;
8881 case FPRIV_TYPE:
8882 ignored_fprivs++;
8883 break;
8884 case ATTR_FLAG_TYPE:
8885 ignored_fattrs++;
8886 break;
8888 default:
8890 break;
8893 /* done */
8894 return;
8896 } /* end extract_attr */
8901 * Name: rebuild_comp_path()
8903 * Description:
8904 * Take the string of components passed down by the calling
8905 * routine and parse the values and rebuild the path.
8906 * This routine no longer needs to produce a new real_path
8907 * string because it is produced when the 'L' LABEL_TYPE is
8908 * interpreted. So the only thing done here is to distinguish
8909 * between an SLD and an MLD entry. We only want one, so we
8910 * ignore the MLD entry by setting the mld_flag.
8912 * return value:
8913 * none
8915 static void
8916 rebuild_comp_path(char *str, char **namep)
8918 char *cp;
8920 while (*str != '\0') {
8922 switch (*str) {
8924 case MLD_TYPE:
8926 str++;
8927 if ((cp = strstr(str, ";;")) != NULL) {
8928 *cp = '\0';
8929 str = cp + 2;
8930 *cp = ';';
8932 mld_flag = 1;
8933 break;
8935 case SLD_TYPE:
8937 str++;
8938 if ((cp = strstr(str, ";;")) != NULL) {
8939 *cp = '\0';
8940 str = cp + 2;
8941 *cp = ';';
8943 mld_flag = 0;
8944 break;
8946 case PATH_TYPE:
8948 str++;
8949 if ((cp = strstr(str, ";;")) != NULL) {
8950 *cp = '\0';
8951 str = cp + 2;
8952 *cp = ';';
8954 break;
8957 if (rpath_flag)
8958 *namep = real_path;
8959 return;
8961 } /* end rebuild_comp_path() */
8964 * Name: rebuild_lk_comp_path()
8966 * Description:
8967 * Take the string of components passed down by the calling
8968 * routine and parse the values and rebuild the path.
8970 * return value:
8971 * 0 = succeeded
8972 * -1 = failed
8974 static int
8975 rebuild_lk_comp_path(char *str, char **namep)
8977 char *cp;
8978 int reterr;
8979 bslabel_t bslabel;
8980 char *buf;
8981 char pbuf[MAXPATHLEN];
8982 char *ptr1, *ptr2;
8983 int plen;
8984 int use_pbuf;
8985 char tempbuf[MAXPATHLEN];
8986 int mismatch;
8987 bslabel_t *from_label;
8988 char zonename[ZONENAME_MAX];
8989 zoneid_t zoneid;
8991 /* init stuff */
8992 use_pbuf = 0;
8993 mismatch = 0;
8996 * For linked to pathname (LK_COMP_TYPE):
8997 * - If the linked to pathname is absolute (start with /), we
8998 * will use it as is.
8999 * - If it is a relative pathname then it is relative to 1 of 2
9000 * directories. For a hardlink, it is relative to the current
9001 * directory. For a symbolic link, it is relative to the
9002 * directory the symbolic link is in. For the symbolic link
9003 * case, set a flag to indicate we need to use the prefix of
9004 * the restored file's pathname with the linked to pathname.
9006 * NOTE: At this point, we have no way to determine if we have
9007 * a hardlink or a symbolic link. We will compare the 1st
9008 * component in the prefix portion of the restore file's
9009 * pathname to the 1st component in the attribute data
9010 * (the linked pathname). If they are the same, we will assume
9011 * the link pathname to reconstruct is relative to the current
9012 * directory. Otherwise, we will set a flag indicate we need
9013 * to use a prefix with the reconstructed name. Need to compare
9014 * both the adorned and unadorned version before deciding a
9015 * mismatch.
9018 buf = lk_real_path;
9019 if (*(str + 1) != '/') { /* got relative linked to path */
9020 ptr1 = orig_namep;
9021 ptr2 = strrchr(ptr1, '/');
9022 plen = ptr2 - ptr1;
9023 if (plen > 0) {
9024 pbuf[0] = '\0';
9025 plen++; /* include '/' */
9026 (void) strncpy(pbuf, ptr1, plen);
9027 *(pbuf + plen) = '\0';
9028 ptr2 = strchr(pbuf, '/');
9029 if (strncmp(pbuf, str + 1, ptr2 - pbuf) != 0)
9030 mismatch = 1;
9033 if (mismatch == 1)
9034 use_pbuf = 1;
9037 buf[0] = '\0';
9039 while (*str != '\0') {
9041 switch (*str) {
9043 case MLD_TYPE:
9045 str++;
9046 if ((cp = strstr(str, ";;")) != NULL) {
9047 *cp = '\0';
9050 * Ignore attempts to backup over .MLD.
9052 if (strcmp(str, "../") != 0)
9053 (void) strncat(buf, str, MAXPATHLEN);
9054 str = cp + 2;
9055 *cp = ';';
9057 break;
9059 case SLD_TYPE:
9061 str++;
9062 if ((cp = strstr(str, ";;")) != NULL) {
9063 *cp = '\0';
9066 * Use the path name in the header if
9067 * error occurs when processing the
9068 * SLD type.
9071 if (!stobsl(str, &bslabel,
9072 NO_CORRECTION, &reterr)) {
9073 (void) fprintf(stderr, gettext(
9074 "tar: can't translate to binary"
9075 "SL for SLD, stobsl() error:"
9076 " %s\n"), strerror(errno));
9077 return (-1);
9080 str = cp + 2;
9081 *cp = ';';
9083 if (use_pbuf == 1) {
9084 if (*pbuf != '/') {
9085 /* relative linked to path */
9087 (void) getcwd(tempbuf,
9088 (sizeof (tempbuf)));
9089 (void) strncat(tempbuf, "/",
9090 MAXPATHLEN);
9091 (void) strncat(tempbuf, pbuf,
9092 MAXPATHLEN);
9094 else
9095 (void) strcpy(tempbuf, pbuf);
9097 } else if (*buf != '/') {
9098 /* got relative linked to path */
9100 (void) getcwd(tempbuf,
9101 (sizeof (tempbuf)));
9102 (void) strncat(tempbuf, "/",
9103 MAXPATHLEN);
9104 } else
9105 *tempbuf = '\0';
9107 (void) strncat(tempbuf, buf, MAXPATHLEN);
9108 *buf = '\0';
9110 if (blequal(&bslabel, &admin_high)) {
9111 bslabel = admin_low;
9116 * Check for cross-zone symbolic links
9118 from_label = getlabelbypath(real_path);
9119 if (rpath_flag && (from_label != NULL) &&
9120 !blequal(&bslabel, from_label)) {
9121 if ((zoneid =
9122 getzoneidbylabel(&bslabel)) == -1) {
9123 (void) fprintf(stderr,
9124 gettext("tar: can't get "
9125 "zone ID for %s\n"),
9126 tempbuf);
9127 return (-1);
9129 if (zone_getattr(zoneid, ZONE_ATTR_NAME,
9130 &zonename, ZONENAME_MAX) == -1) {
9131 /* Badly configured zone info */
9132 (void) fprintf(stderr,
9133 gettext("tar: can't get "
9134 "zonename for %s\n"),
9135 tempbuf);
9136 return (-1);
9138 (void) strncpy(buf, AUTO_ZONE,
9139 MAXPATHLEN);
9140 (void) strncat(buf, "/",
9141 MAXPATHLEN);
9142 (void) strncat(buf, zonename,
9143 MAXPATHLEN);
9145 if (from_label != NULL)
9146 free(from_label);
9147 (void) strncat(buf, tempbuf, MAXPATHLEN);
9148 break;
9150 mld_flag = 0;
9151 break;
9153 case PATH_TYPE:
9155 str++;
9156 if ((cp = strstr(str, ";;")) != NULL) {
9157 *cp = '\0';
9158 (void) strncat(buf, str, MAXPATHLEN);
9159 str = cp + 2;
9160 *cp = ';';
9162 break;
9164 default:
9166 (void) fprintf(stderr, gettext(
9167 "tar: error rebuilding path %s\n"),
9168 *namep);
9169 *buf = '\0';
9170 str++;
9171 return (-1);
9176 * Done for LK_COMP_TYPE
9179 return (0); /* component path is rebuilt successfully */
9181 } /* end rebuild_lk_comp_path() */
9184 * Name: check_ext_attr()
9186 * Description:
9187 * Check the extended attributes for a file being extracted.
9188 * The attributes being checked here are CMW labels.
9189 * ACLs are not set here because they are set by the
9190 * pflag in doxtract().
9192 * If the label doesn't match, return 0
9193 * else return 1
9195 static int
9196 check_ext_attr(char *filename)
9198 bslabel_t currentlabel; /* label from zone */
9200 if (bltype(&bs_label, SUN_SL_UN)) {
9201 /* No label check possible */
9202 return (0);
9204 if (getlabel(filename, &currentlabel) != 0) {
9205 (void) fprintf(stderr,
9206 gettext("tar: can't get label for "
9207 " %s, getlabel() error: %s\n"),
9208 filename, strerror(errno));
9209 return (0);
9210 } else if ((blequal(&currentlabel, &bs_label)) == 0) {
9211 char *src_label = NULL; /* ascii label */
9213 /* get current src SL */
9214 if (bsltos(&bs_label, &src_label, 0, 0) <= 0) {
9215 (void) fprintf(stderr,
9216 gettext("tar: can't interpret requested label for"
9217 " %s\n"), filename);
9218 } else {
9219 (void) fprintf(stderr,
9220 gettext("tar: can't apply label %s to %s\n"),
9221 src_label, filename);
9222 free(src_label);
9224 (void) fprintf(stderr,
9225 gettext("tar: %s not restored\n"), filename);
9226 return (0);
9228 return (1);
9230 } /* end check_ext_attr */
9232 /* Compressing a tar file using compression method provided in 'opt' */
9234 static void
9235 compress_back()
9237 pid_t pid;
9239 if (vflag) {
9240 (void) fprintf(vfile,
9241 gettext("Compressing '%s' with '%s'...\n"),
9242 usefile, compress_opt);
9244 if ((pid = fork()) == 0) {
9245 verify_compress_opt(compress_opt);
9246 (void) execlp(compress_opt, compress_opt,
9247 usefile, NULL);
9248 } else if (pid == -1) {
9249 vperror(1, "%s", gettext("Could not fork"));
9251 wait_pid(pid);
9252 if (suffix == 0) {
9253 (void) rename(tfname, usefile);
9257 /* The magic numbers from /etc/magic */
9259 #define GZIP_MAGIC "\037\213"
9260 #define BZIP_MAGIC "BZh"
9261 #define COMP_MAGIC "\037\235"
9262 #define XZ_MAGIC "\375\067\172\130\132\000"
9264 void
9265 check_compression(void)
9267 char magic[16];
9268 FILE *fp;
9270 if ((fp = fopen(usefile, "r")) != NULL) {
9271 (void) fread(magic, sizeof (char), 6, fp);
9272 (void) fclose(fp);
9275 if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
9276 if (xflag || tflag) {
9277 compress_opt = compress_malloc(strlen(GZCAT) + 1);
9278 (void) strcpy(compress_opt, GZCAT);
9279 } else if (uflag || rflag) {
9280 compress_opt = compress_malloc(strlen(GZIP) + 1);
9281 (void) strcpy(compress_opt, GZIP);
9283 } else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
9284 if (xflag || tflag) {
9285 compress_opt = compress_malloc(strlen(BZCAT) + 1);
9286 (void) strcpy(compress_opt, BZCAT);
9287 } else if (uflag || rflag) {
9288 compress_opt = compress_malloc(strlen(BZIP) + 1);
9289 (void) strcpy(compress_opt, BZIP);
9291 } else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
9292 if (xflag || tflag) {
9293 compress_opt = compress_malloc(strlen(ZCAT) + 1);
9294 (void) strcpy(compress_opt, ZCAT);
9295 } else if (uflag || rflag) {
9296 compress_opt = compress_malloc(strlen(COMPRESS) + 1);
9297 (void) strcpy(compress_opt, COMPRESS);
9299 } else if (memcmp(magic, XZ_MAGIC, 6) == 0) {
9300 if (xflag || tflag) {
9301 compress_opt = compress_malloc(strlen(XZCAT) + 1);
9302 (void) strcpy(compress_opt, XZCAT);
9303 } else if (uflag || rflag) {
9304 compress_opt = compress_malloc(strlen(XZ) + 1);
9305 (void) strcpy(compress_opt, XZ);
9310 char *
9311 add_suffix()
9313 (void) strcpy(tfname, usefile);
9314 if (strcmp(compress_opt, GZIP) == 0) {
9315 if ((suffix = gz_suffix()) == NULL) {
9316 strlcat(tfname, gsuffix[0], sizeof (tfname));
9317 return (gsuffix[0]);
9319 } else if (strcmp(compress_opt, COMPRESS) == 0) {
9320 if ((suffix = gz_suffix()) == NULL) {
9321 strlcat(tfname, gsuffix[6], sizeof (tfname));
9322 return (gsuffix[6]);
9324 } else if (strcmp(compress_opt, BZIP) == 0) {
9325 if ((suffix = bz_suffix()) == NULL) {
9326 strlcat(tfname, bsuffix[0], sizeof (tfname));
9327 return (bsuffix[0]);
9329 } else if (strcmp(compress_opt, XZ) == 0) {
9330 if ((suffix = xz_suffix()) == NULL) {
9331 strlcat(tfname, xsuffix[0], sizeof (tfname));
9332 return (xsuffix[0]);
9335 return (NULL);
9338 /* Decompressing a tar file using compression method from the file type */
9339 void
9340 decompress_file(void)
9342 pid_t pid;
9343 char *added_suffix;
9346 added_suffix = add_suffix();
9347 if (added_suffix != NULL) {
9348 (void) rename(usefile, tfname);
9350 if ((pid = fork()) == 0) {
9351 if (vflag) {
9352 (void) fprintf(vfile,
9353 gettext("Decompressing '%s' with "
9354 "'%s'...\n"), usefile, compress_opt);
9356 verify_compress_opt(compress_opt);
9357 (void) execlp(compress_opt, compress_opt, "-df",
9358 tfname, NULL);
9359 vperror(1, gettext("Could not exec %s"), compress_opt);
9360 } else if (pid == -1) {
9361 vperror(1, gettext("Could not fork"));
9363 wait_pid(pid);
9364 if (suffix != NULL) {
9365 /* restore the file name - original file was without suffix */
9366 *(usefile + strlen(usefile) - strlen(suffix)) = '\0';
9370 /* Set the archive for writing and then compress the archive */
9371 pid_t
9372 compress_file(void)
9374 int fd[2];
9375 pid_t pid;
9377 if (vflag) {
9378 (void) fprintf(vfile, gettext("Compressing '%s' with "
9379 "'%s'...\n"), usefile, compress_opt);
9382 if (pipe(fd) < 0) {
9383 vperror(1, gettext("Could not create pipe"));
9385 if ((pid = fork()) > 0) {
9386 mt = fd[1];
9387 (void) close(fd[0]);
9388 return (pid);
9390 /* child */
9391 (void) dup2(fd[0], STDIN_FILENO);
9392 (void) close(fd[1]);
9393 (void) dup2(mt, STDOUT_FILENO);
9394 verify_compress_opt(compress_opt);
9395 (void) execlp(compress_opt, compress_opt, NULL);
9396 vperror(1, gettext("Could not exec %s"), compress_opt);
9397 return (0); /*NOTREACHED*/
9400 pid_t
9401 uncompress_file(void)
9403 int fd[2];
9404 pid_t pid;
9406 if (vflag) {
9407 (void) fprintf(vfile, gettext("Decompressing '%s' with "
9408 "'%s'...\n"), usefile, compress_opt);
9411 if (pipe(fd) < 0) {
9412 vperror(1, gettext("Could not create pipe"));
9414 if ((pid = fork()) > 0) {
9415 mt = fd[0];
9416 (void) close(fd[1]);
9417 return (pid);
9419 /* child */
9420 (void) dup2(fd[1], STDOUT_FILENO);
9421 (void) close(fd[0]);
9422 (void) dup2(mt, STDIN_FILENO);
9423 verify_compress_opt(compress_opt);
9424 (void) execlp(compress_opt, compress_opt, NULL);
9425 vperror(1, gettext("Could not exec %s"), compress_opt);
9426 return (0); /*NOTREACHED*/
9429 /* Checking suffix validity */
9430 char *
9431 check_suffix(char **suf, int size)
9433 int i;
9434 int slen;
9435 int nlen = strlen(usefile);
9437 for (i = 0; i < size; i++) {
9438 slen = strlen(suf[i]);
9439 if (nlen < slen)
9440 return (NULL);
9441 if (strcmp(usefile + nlen - slen, suf[i]) == 0)
9442 return (suf[i]);
9444 return (NULL);
9447 /* Checking valid 'bzip2' suffix */
9448 char *
9449 bz_suffix(void)
9451 return (check_suffix(bsuffix, BSUF));
9454 /* Checking valid 'gzip' suffix */
9455 char *
9456 gz_suffix(void)
9458 return (check_suffix(gsuffix, GSUF));
9461 /* Checking valid 'xz' suffix */
9462 char *
9463 xz_suffix(void)
9465 return (check_suffix(xsuffix, XSUF));
9468 void *
9469 compress_malloc(size_t size)
9471 void *opt;
9473 if ((opt = malloc(size)) == NULL) {
9474 vperror(1, "%s",
9475 gettext("Could not allocate compress buffer\n"));
9477 return (opt);
9480 void
9481 wait_pid(pid_t pid)
9483 int status;
9485 while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
9489 static void
9490 verify_compress_opt(const char *t)
9492 struct stat statbuf;
9494 if (stat(t, &statbuf) == -1)
9495 vperror(1, "%s %s: %s\n", gettext("Could not stat"),
9496 t, strerror(errno));
9499 static void
9500 detect_compress(void)
9502 char *zsuf[] = {".Z"};
9503 if (check_suffix(zsuf, 1) != NULL) {
9504 Zflag = 1;
9505 } else if (check_suffix(bsuffix, BSUF) != NULL) {
9506 jflag = 1;
9507 } else if (check_suffix(gsuffix, GSUF) != NULL) {
9508 zflag = 1;
9509 } else if (check_suffix(xsuffix, XSUF) != NULL) {
9510 Jflag = 1;
9511 } else {
9512 vperror(1, "%s\n", gettext("No compression method detected"));