Unleashed v1.4
[unleashed.git] / usr / src / cmd / tar / tar.c
blobce47fc317e02873e13253d9fb0d3f257197ae318
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>
75 #include <err.h>
77 #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
78 extern int defcntl();
79 #endif
80 #if defined(_PC_SATTR_ENABLED)
81 #include <attr.h>
82 #include <libcmdutils.h>
83 #endif
85 #include "getresponse.h"
87 * Source compatibility
91 * These constants come from archives.h and sys/fcntl.h
92 * and were introduced by the extended attributes project
93 * in Solaris 9.
95 #if !defined(O_XATTR)
96 #define AT_SYMLINK_NOFOLLOW 0x1000
97 #define AT_REMOVEDIR 0x1
98 #define AT_FDCWD 0xffd19553
99 #define _XATTR_HDRTYPE 'E'
100 static int attropen();
101 static int fstatat();
102 static int renameat();
103 static int unlinkat();
104 static int openat();
105 static int fchownat();
106 static int futimesat();
107 #endif
110 * Compiling with -D_XPG4_2 gets this but produces other problems, so
111 * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
112 * explicitly doing the declaration here.
114 int utimes(const char *path, const struct timeval timeval_ptr[]);
116 #ifndef MINSIZE
117 #define MINSIZE 250
118 #endif
119 #define DEF_FILE "/etc/default/tar"
121 #define min(a, b) ((a) < (b) ? (a) : (b))
122 #define max(a, b) ((a) > (b) ? (a) : (b))
124 #define TBLOCK 512 /* tape block size--should be universal */
126 #ifdef BSIZE
127 #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
128 #else /* BSIZE */
129 #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
130 #endif /* BSIZE */
132 #define NBLOCK 20
133 #define NAMSIZ 100
134 #define PRESIZ 155
135 #define MAXNAM 256
136 #define MODEMASK 0777777 /* file creation mode mask */
137 #define POSIXMODES 07777 /* mask for POSIX mode bits */
138 #define MAXEXT 9 /* reasonable max # extents for a file */
139 #define EXTMIN 50 /* min blks left on floppy to split a file */
141 /* max value dblock.dbuf.efsize can store */
142 #define TAR_EFSIZE_MAX 0777777777
145 * Symbols which specify the values at which the use of the 'E' function
146 * modifier is required to properly store a file.
148 * TAR_OFFSET_MAX - the largest file size we can archive
149 * OCTAL7CHAR - the limit for ustar gid, uid, dev
152 #ifdef XHDR_DEBUG
153 /* tiny values which force the creation of extended header entries */
154 #define TAR_OFFSET_MAX 9
155 #define OCTAL7CHAR 2
156 #else
157 /* normal values */
158 #define TAR_OFFSET_MAX 077777777777ULL
159 #define OCTAL7CHAR 07777777
160 #endif
162 #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
163 #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
165 #define MAXLEV (PATH_MAX / 2)
166 #define LEV0 1
167 #define SYMLINK_LEV0 0
169 #define TRUE 1
170 #define FALSE 0
172 #define XATTR_FILE 1
173 #define NORMAL_FILE 0
175 #define PUT_AS_LINK 1
176 #define PUT_NOTAS_LINK 0
178 #ifndef VIEW_READONLY
179 #define VIEW_READONLY "SUNWattr_ro"
180 #endif
182 #ifndef VIEW_READWRITE
183 #define VIEW_READWRITE "SUNWattr_rw"
184 #endif
186 #define FMT_off_t "lld"
187 #define FMT_off_t_o "llo"
188 #define FMT_blkcnt_t "lld"
190 /* ACL support */
192 static
193 struct sec_attr {
194 char attr_type;
195 char attr_len[7];
196 char attr_info[1];
197 } *attr;
199 #if defined(O_XATTR)
200 typedef enum {
201 ATTR_OK,
202 ATTR_SKIP,
203 ATTR_CHDIR_ERR,
204 ATTR_OPEN_ERR,
205 ATTR_XATTR_ERR,
206 ATTR_SATTR_ERR
207 } attr_status_t;
208 #endif
210 #if defined(O_XATTR)
211 typedef enum {
212 ARC_CREATE,
213 ARC_RESTORE
214 } arc_action_t;
215 #endif
217 typedef struct attr_data {
218 char *attr_parent;
219 char *attr_path;
220 int attr_parentfd;
221 int attr_rw_sysattr;
222 } attr_data_t;
226 * Tar has been changed to support extended attributes.
228 * As part of this change tar now uses the new *at() syscalls
229 * such as openat, fchownat(), unlinkat()...
231 * This was done so that attributes can be handled with as few code changes
232 * as possible.
234 * What this means is that tar now opens the directory that a file or directory
235 * resides in and then performs *at() functions to manipulate the entry.
237 * For example a new file is now created like this:
239 * dfd = open(<some dir path>)
240 * fd = openat(dfd, <name>,....);
242 * or in the case of an extended attribute
244 * dfd = attropen(<pathname>, ".", ....)
246 * Once we have a directory file descriptor all of the *at() functions can
247 * be applied to it.
249 * unlinkat(dfd, <component name>,...)
250 * fchownat(dfd, <component name>,..)
252 * This works for both normal namespace files and extended attribute file
258 * Extended attribute Format
260 * Extended attributes are stored in two pieces.
261 * 1. An attribute header which has information about
262 * what file the attribute is for and what the attribute
263 * is named.
264 * 2. The attribute record itself. Stored as a normal file type
265 * of entry.
266 * Both the header and attribute record have special modes/typeflags
267 * associated with them.
269 * The names of the header in the archive look like:
270 * /dev/null/attr.hdr
272 * The name of the attribute looks like:
273 * /dev/null/attr
275 * This is done so that an archiver that doesn't understand these formats
276 * can just dispose of the attribute records.
278 * The format is composed of a fixed size header followed
279 * by a variable sized xattr_buf. If the attribute is a hard link
280 * to another attribute then another xattr_buf section is included
281 * for the link.
283 * The xattr_buf is used to define the necessary "pathing" steps
284 * to get to the extended attribute. This is necessary to support
285 * a fully recursive attribute model where an attribute may itself
286 * have an attribute.
288 * The basic layout looks like this.
290 * --------------------------------
291 * | |
292 * | xattr_hdr |
293 * | |
294 * --------------------------------
295 * --------------------------------
296 * | |
297 * | xattr_buf |
298 * | |
299 * --------------------------------
300 * --------------------------------
301 * | |
302 * | (optional link info) |
303 * | |
304 * --------------------------------
305 * --------------------------------
306 * | |
307 * | attribute itself |
308 * | stored as normal tar |
309 * | or cpio data with |
310 * | special mode or |
311 * | typeflag |
312 * | |
313 * --------------------------------
318 * xattrhead is a pointer to the xattr_hdr
320 * xattrp is a pointer to the xattr_buf structure
321 * which contains the "pathing" steps to get to attributes
323 * xattr_linkp is a pointer to another xattr_buf structure that is
324 * only used when an attribute is actually linked to another attribute
328 static struct xattr_hdr *xattrhead;
329 static struct xattr_buf *xattrp;
330 static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
331 static char *xattrapath; /* attribute name */
332 static char *xattr_linkaname; /* attribute attribute is linked to */
333 static char Hiddendir; /* are we processing hidden xattr dir */
334 static char xattrbadhead;
336 /* Was statically allocated tbuf[NBLOCK] */
337 static
338 union hblock {
339 char dummy[TBLOCK];
340 struct header {
341 char name[NAMSIZ]; /* If non-null prefix, path is */
342 /* <prefix>/<name>; otherwise */
343 /* <name> */
344 char mode[8];
345 char uid[8];
346 char gid[8];
347 char size[12]; /* size of this extent if file split */
348 char mtime[12];
349 char chksum[8];
350 char typeflag;
351 char linkname[NAMSIZ];
352 char magic[6];
353 char version[2];
354 char uname[32];
355 char gname[32];
356 char devmajor[8];
357 char devminor[8];
358 char prefix[PRESIZ]; /* Together with "name", the path of */
359 /* the file: <prefix>/<name> */
360 char extno; /* extent #, null if not split */
361 char extotal; /* total extents */
362 char efsize[10]; /* size of entire file */
363 } dbuf;
364 } dblock, *tbuf, xhdr_buf;
366 static
367 struct xtar_hdr {
368 uid_t x_uid, /* Uid of file */
369 x_gid; /* Gid of file */
370 major_t x_devmajor; /* Device major node */
371 minor_t x_devminor; /* Device minor node */
372 off_t x_filesz; /* Length of file */
373 char *x_uname, /* Pointer to name of user */
374 *x_gname, /* Pointer to gid of user */
375 *x_linkpath, /* Path for a hard/symbolic link */
376 *x_path; /* Path of file */
377 timestruc_t x_mtime; /* Seconds and nanoseconds */
378 } Xtarhdr;
380 static
381 struct gen_hdr {
382 ulong_t g_mode; /* Mode of file */
383 uid_t g_uid, /* Uid of file */
384 g_gid; /* Gid of file */
385 off_t g_filesz; /* Length of file */
386 time_t g_mtime; /* Modification time */
387 uint_t g_cksum; /* Checksum of file */
388 ulong_t g_devmajor, /* File system of file */
389 g_devminor; /* Major/minor of special files */
390 } Gen;
392 static
393 struct linkbuf {
394 ino_t inum;
395 dev_t devnum;
396 int count;
397 char pathname[MAXNAM+1]; /* added 1 for last NULL */
398 char attrname[MAXNAM+1];
399 struct linkbuf *nextp;
400 } *ihead;
402 /* see comments before build_table() */
403 #define TABLE_SIZE 512
404 typedef struct file_list {
405 char *name; /* Name of file to {in,ex}clude */
406 struct file_list *next; /* Linked list */
407 } file_list_t;
408 static file_list_t *exclude_tbl[TABLE_SIZE],
409 *include_tbl[TABLE_SIZE];
411 static int append_secattr(char **, int *, int, char *, char);
412 static void write_ancillary(union hblock *, char *, int, char);
414 static void add_file_to_table(file_list_t *table[], char *str);
415 static void assert_string(char *s, char *msg);
416 static int istape(int fd, int type);
417 static void backtape(void);
418 static void build_table(file_list_t *table[], char *file);
419 static int check_prefix(char **namep, char **dirp, char **compp);
420 static void closevol(void);
421 static void copy(void *dst, void *src);
422 static int convtoreg(off_t);
423 static void delete_target(int fd, char *comp, char *namep);
424 static void doDirTimes(char *name, timestruc_t modTime);
425 static void done(int n);
426 static void dorep(char *argv[]);
427 static void dotable(char *argv[]);
428 static void doxtract(char *argv[]);
429 static int tar_chdir(const char *path);
430 static int is_directory(char *name);
431 static int has_dot_dot(char *name);
432 static int is_absolute(char *name);
433 static char *make_relative_name(char *name, char **stripped_prefix);
434 static void fatal(char *format, ...);
435 static void vperror(int exit_status, char *fmt, ...);
436 static void flushtape(void);
437 static void getdir(void);
438 static void *getmem(size_t);
439 static void longt(struct stat *st, char aclchar);
440 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
441 static int makeDir(char *name);
442 static void mterr(char *operation, int i, int exitcode);
443 static void newvol(void);
444 static void passtape(void);
445 static void putempty(blkcnt_t n);
446 static int putfile(char *longname, char *shortname, char *parent,
447 attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
448 static void readtape(char *buffer);
449 static void seekdisk(blkcnt_t blocks);
450 static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
451 static void setbytes_to_skip(struct stat *st, int err);
452 static void splitfile(char *longname, int ifd, char *name,
453 char *prefix, int filetype);
454 static void tomodes(struct stat *sp);
455 static void usage(void);
456 static int xblocks(int issysattr, off_t bytes, int ofile);
457 static int xsfile(int issysattr, int ofd);
458 static void resugname(int dirfd, char *name, int symflag);
459 static int bcheck(char *bstr);
460 static int checkdir(char *name);
461 static int checksum(union hblock *dblockp);
462 #ifdef EUC
463 static int checksum_signed(union hblock *dblockp);
464 #endif /* EUC */
465 static int checkupdate(char *arg);
466 static int checkw(char c, char *name);
467 static int cmp(char *b, char *s, int n);
468 static int defset(char *arch);
469 static boolean_t endtape(void);
470 static int is_in_table(file_list_t *table[], char *str);
471 static int notsame(void);
472 static int is_prefix(char *s1, char *s2);
473 static int response(void);
474 static int build_dblock(const char *, const char *, const char,
475 const int filetype, const struct stat *, const dev_t, const char *);
476 static unsigned int hash(char *str);
478 static blkcnt_t kcheck(char *kstr);
479 static off_t bsrch(char *s, int n, off_t l, off_t h);
480 static void onintr(int sig);
481 static void onquit(int sig);
482 static void onhup(int sig);
483 static uid_t getuidbyname(char *);
484 static gid_t getgidbyname(char *);
485 static char *getname(gid_t);
486 static char *getgroup(gid_t);
487 static int checkf(char *name, int mode, int howmuch);
488 static int writetbuf(char *buffer, int n);
489 static int wantit(char *argv[], char **namep, char **dirp, char **comp,
490 attr_data_t **attrinfo);
491 static int get_xdata(void);
492 static void gen_num(const char *keyword, const u_longlong_t number);
493 static void gen_date(const char *keyword, const timestruc_t time_value);
494 static void gen_string(const char *keyword, const char *value);
495 static void get_xtime(char *value, timestruc_t *xtime);
496 static int chk_path_build(char *name, char *longname, char *linkname,
497 char *prefix, char type, int filetype);
498 static int gen_utf8_names(const char *filename);
499 static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
500 const char *src, int max_val);
501 static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
502 iconv_t iconv_cd, int xhdrflg, int max_val);
503 static int c_utf8(char *target, const char *source);
504 static int getstat(int dirfd, char *longname, char *shortname,
505 char *attrparent);
506 static void xattrs_put(char *, char *, char *, char *);
507 static void prepare_xattr(char **, char *, char *,
508 char, struct linkbuf *, int *);
509 static int put_link(char *name, char *longname, char *component,
510 char *longattrname, char *prefix, int filetype, char typeflag);
511 static int put_extra_attributes(char *longname, char *shortname,
512 char *longattrname, char *prefix, int filetype, char typeflag);
513 static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
514 char *prefix, int typeflag, int filetype, struct linkbuf *lp);
515 static int read_xattr_hdr(attr_data_t **attrinfo);
517 static void get_parent(char *path, char *dir);
518 static char *get_component(char *path);
519 static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
520 char *name, int oflag, mode_t mode);
521 static char *skipslashes(char *string, char *start);
522 static void chop_endslashes(char *path);
523 static pid_t compress_file(void);
524 static void compress_back(void);
525 static void decompress_file(void);
526 static pid_t uncompress_file(void);
527 static void *compress_malloc(size_t);
528 static void check_compression(void);
529 static char *bz_suffix(void);
530 static char *gz_suffix(void);
531 static char *xz_suffix(void);
532 static char *add_suffix();
533 static void wait_pid(pid_t);
534 static void verify_compress_opt(const char *t);
535 static void detect_compress(void);
536 static void dlog(const char *, ...);
537 static boolean_t should_enable_debug(void);
539 static struct stat stbuf;
541 static char *myname;
542 static char *xtract_chdir = NULL;
543 static int checkflag = 0;
544 static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
545 static int rflag, xflag, vflag, tflag, mt, cflag, mflag, pflag;
546 static int uflag;
547 static int errflag;
548 static int oflag;
549 static int bflag, Aflag;
550 static int Pflag; /* POSIX conformant archive */
551 static int Eflag; /* Allow files greater than 8GB */
552 static int atflag; /* traverse extended attributes */
553 static int saflag; /* traverse extended sys attributes */
554 static int Dflag; /* Data change flag */
555 static int jflag; /* flag to use 'bzip2' */
556 static int zflag; /* flag to use 'gzip' */
557 static int Zflag; /* flag to use 'compress' */
558 static int Jflag; /* flag to use 'xz' */
559 static int aflag; /* flag to use autocompression */
561 static int term, chksum, wflag,
562 first = TRUE, defaults_used = FALSE, linkerrok;
563 static blkcnt_t recno;
564 static int freemem = 1;
565 static int nblock = NBLOCK;
566 static int Errflg = 0;
567 static int exitflag = 0;
569 static dev_t mt_dev; /* device containing output file */
570 static ino_t mt_ino; /* inode number of output file */
571 static int mt_devtype; /* dev type of archive, from stat structure */
573 static int update = 1; /* for `open' call */
575 static off_t low;
576 static off_t high;
578 static FILE *tfile;
579 static FILE *vfile;
580 static char *tmpdir;
581 static char *tmp_suffix = "/tarXXXXXX";
582 static char *tname;
583 static char archive[] = "archive0=";
584 static char *Xfile;
585 static char *usefile;
586 static char tfname[1024];
588 static int mulvol; /* multi-volume option selected */
589 static blkcnt_t blocklim; /* number of blocks to accept per volume */
590 static blkcnt_t tapepos; /* current block number to be written */
591 static int NotTape; /* true if tape is a disk */
592 static int dumping; /* true if writing a tape or other archive */
593 static int extno; /* number of extent: starts at 1 */
594 static int extotal; /* total extents in this file */
595 static off_t extsize; /* size of current extent during extraction */
596 static ushort_t Oumask = 0; /* old umask value */
597 static boolean_t is_posix; /* true if archive is POSIX-conformant */
598 static const char *magic_type = "ustar";
599 static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */
600 static char *xrec_ptr;
601 static off_t xrec_offset = 0;
602 static int Xhdrflag;
603 static int charset_type = 0;
605 static u_longlong_t xhdr_flgs; /* Bits set determine which items */
606 /* need to be in extended header. */
607 static pid_t comp_pid = 0;
609 static boolean_t debug_output = B_FALSE;
611 #define _X_DEVMAJOR 0x1
612 #define _X_DEVMINOR 0x2
613 #define _X_GID 0x4
614 #define _X_GNAME 0x8
615 #define _X_LINKPATH 0x10
616 #define _X_PATH 0x20
617 #define _X_SIZE 0x40
618 #define _X_UID 0x80
619 #define _X_UNAME 0x100
620 #define _X_ATIME 0x200
621 #define _X_CTIME 0x400
622 #define _X_MTIME 0x800
623 #define _X_XHDR 0x1000 /* Bit flag that determines whether 'X' */
624 /* typeflag was followed by 'A' or non 'A' */
625 /* typeflag. */
626 #define _X_LAST 0x40000000
628 #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4)
629 #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4)
630 #define LONG_MAX_DIGITS (10 * sizeof (long) / 4)
631 #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4)
633 * UTF_8 encoding requires more space than the current codeset equivalent.
634 * Currently a factor of 2-3 would suffice, but it is possible for a factor
635 * of 6 to be needed in the future, so for saftey, we use that here.
637 #define UTF_8_FACTOR 6
639 static u_longlong_t xhdr_count = 0;
640 static char xhdr_dirname[PRESIZ + 1];
641 static char pidchars[PID_MAX_DIGITS + 1];
642 static char *tchar = ""; /* null linkpath */
644 static char local_path[UTF_8_FACTOR * PATH_MAX + 1];
645 static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
646 static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
647 static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
650 * The following mechanism is provided to allow us to debug tar in complicated
651 * situations, like when it is part of a pipe. The idea is that you compile
652 * with -DWAITAROUND defined, and then add the 'D' function modifier to the
653 * target tar invocation, eg. "tar cDf tarfile file". If stderr is available,
654 * it will tell you to which pid to attach the debugger; otherwise, use ps to
655 * find it. Attach to the process from the debugger, and, *PRESTO*, you are
656 * there!
658 * Simply assign "waitaround = 0" once you attach to the process, and then
659 * proceed from there as usual.
662 #ifdef WAITAROUND
663 int waitaround = 0; /* wait for rendezvous with the debugger */
664 #endif
666 #define BZIP "/usr/bin/bzip2"
667 #define GZIP "/usr/bin/gzip"
668 #define COMPRESS "/usr/bin/compress"
669 #define XZ "/usr/bin/xz"
670 #define BZCAT "/usr/bin/bzcat"
671 #define GZCAT "/usr/bin/gzcat"
672 #define ZCAT "/usr/bin/zcat"
673 #define XZCAT "/usr/bin/xzcat"
674 #define GSUF 8 /* number of valid 'gzip' sufixes */
675 #define BSUF 4 /* number of valid 'bzip2' sufixes */
676 #define XSUF 1 /* number of valid 'xz' suffixes */
678 static char *compress_opt; /* compression type */
680 static char *gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
681 ".tgz", ".taz"};
682 static char *bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
683 static char *xsuffix[] = {".xz"};
684 static char *suffix;
688 main(int argc, char *argv[])
690 char *cp;
691 char *tmpdirp;
692 pid_t thispid;
694 vfile = stdout;
696 (void) setlocale(LC_ALL, "");
697 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
698 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
699 #endif
700 (void) textdomain(TEXT_DOMAIN);
701 if (argc < 2)
702 usage();
704 debug_output = should_enable_debug();
706 tfile = NULL;
707 if ((myname = strdup(argv[0])) == NULL) {
708 (void) fprintf(stderr, gettext(
709 "tar: cannot allocate program name\n"));
710 exit(1);
713 if (init_yes() < 0) {
714 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
715 strerror(errno));
716 exit(2);
720 * For XPG4 compatibility, we must be able to accept the "--"
721 * argument normally recognized by getopt; it is used to delimit
722 * the end opt the options section, and so can only appear in
723 * the position of the first argument. We simply skip it.
726 if (strcmp(argv[1], "--") == 0) {
727 argv++;
728 argc--;
729 if (argc < 3)
730 usage();
733 argv[argc] = NULL;
734 argv++;
737 * Set up default values.
738 * Search the operand string looking for the first digit or an 'f'.
739 * If you find a digit, use the 'archive#' entry in DEF_FILE.
740 * If 'f' is given, bypass looking in DEF_FILE altogether.
741 * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
743 if ((usefile = getenv("TAPE")) == NULL) {
744 for (cp = *argv; *cp; ++cp)
745 if (isdigit(*cp) || *cp == 'f')
746 break;
747 if (*cp != 'f') {
748 archive[7] = (*cp)? *cp: '0';
749 if (!(defaults_used = defset(archive))) {
750 usefile = NULL;
751 nblock = 1;
752 blocklim = 0;
753 NotTape = 0;
758 for (cp = *argv++; *cp; cp++)
759 switch (*cp) {
760 #ifdef WAITAROUND
761 case 'D':
762 /* rendezvous with the debugger */
763 waitaround = 1;
764 break;
765 #endif
766 case 'f':
767 assert_string(*argv, gettext(
768 "tar: tarfile must be specified with 'f' "
769 "function modifier\n"));
770 usefile = *argv++;
771 break;
772 case 'F':
773 Fflag++;
774 break;
775 case 'c':
776 cflag++;
777 rflag++;
778 update = 1;
779 break;
780 #if defined(O_XATTR)
781 case '@':
782 atflag++;
783 break;
784 #endif /* O_XATTR */
785 #if defined(_PC_SATTR_ENABLED)
786 case '/':
787 saflag++;
788 break;
789 #endif /* _PC_SATTR_ENABLED */
790 case 'u':
791 uflag++; /* moved code after signals caught */
792 rflag++;
793 update = 2;
794 break;
795 case 'r':
796 rflag++;
797 update = 2;
798 break;
799 case 'v':
800 vflag++;
801 break;
802 case 'w':
803 wflag++;
804 break;
805 case 'x':
806 xflag++;
807 break;
808 case 'X':
809 assert_string(*argv, gettext(
810 "tar: exclude file must be specified with 'X' "
811 "function modifier\n"));
812 Xflag = 1;
813 Xfile = *argv++;
814 build_table(exclude_tbl, Xfile);
815 break;
816 case 't':
817 tflag++;
818 break;
819 case 'm':
820 mflag++;
821 break;
822 case 'p':
823 pflag++;
824 break;
825 case 'D':
826 Dflag++;
827 break;
828 case '-':
829 /* ignore this silently */
830 break;
831 case '0': /* numeric entries used only for defaults */
832 case '1':
833 case '2':
834 case '3':
835 case '4':
836 case '5':
837 case '6':
838 case '7':
839 break;
840 case 'b':
841 assert_string(*argv, gettext(
842 "tar: blocking factor must be specified "
843 "with 'b' function modifier\n"));
844 bflag++;
845 nblock = bcheck(*argv++);
846 break;
847 case 'n': /* not a magtape (instead of 'k') */
848 NotTape++; /* assume non-magtape */
849 break;
850 case 'l':
851 linkerrok++;
852 break;
853 case 'e':
854 errflag++;
855 break;
856 case 'o':
857 oflag++;
858 break;
859 case 'h':
860 hflag++;
861 break;
862 case 'i':
863 iflag++;
864 break;
865 case 'B':
866 Bflag++;
867 break;
868 case 'P':
869 Pflag++;
870 break;
871 case 'E':
872 Eflag++;
873 Pflag++; /* Only POSIX archive made */
874 break;
875 case 'j': /* compession "bzip2" */
876 jflag = 1;
877 break;
878 case 'z': /* compression "gzip" */
879 zflag = 1;
880 break;
881 case 'Z': /* compression "compress" */
882 Zflag = 1;
883 break;
884 case 'J': /* compression "xz" */
885 Jflag = 1;
886 break;
887 case 'a':
888 aflag = 1; /* autocompression */
889 break;
890 default:
891 (void) fprintf(stderr, gettext(
892 "tar: %c: unknown function modifier\n"), *cp);
893 usage();
896 if (!rflag && !xflag && !tflag)
897 usage();
898 if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
899 (void) fprintf(stderr, gettext(
900 "tar: specify only one of [ctxru].\n"));
901 usage();
903 if (cflag) {
904 if ((jflag + zflag + Zflag + Jflag + aflag) > 1) {
905 (void) fprintf(stderr, gettext(
906 "tar: specify only one of [ajJzZ] to "
907 "create a compressed file.\n"));
908 usage();
911 if (cflag && *argv == NULL)
912 fatal(gettext("Missing filenames"));
913 if (usefile == NULL)
914 fatal(gettext("device argument required"));
916 /* alloc a buffer of the right size */
917 if ((tbuf = (union hblock *)
918 calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
919 (union hblock *)NULL) {
920 (void) fprintf(stderr, gettext(
921 "tar: cannot allocate physio buffer\n"));
922 exit(1);
925 if ((xrec_ptr = malloc(xrec_size)) == NULL) {
926 (void) fprintf(stderr, gettext(
927 "tar: cannot allocate extended header buffer\n"));
928 exit(1);
931 #ifdef WAITAROUND
932 if (waitaround) {
933 (void) fprintf(stderr, gettext("Rendezvous with tar on pid"
934 " %d\n"), getpid());
936 while (waitaround) {
937 (void) sleep(10);
940 #endif
942 thispid = getpid();
943 (void) sprintf(pidchars, "%ld", thispid);
944 thispid = strlen(pidchars);
946 if ((tmpdirp = getenv("TMPDIR")) == NULL)
947 (void) strcpy(xhdr_dirname, "/tmp");
948 else {
950 * Make sure that dir is no longer than what can
951 * fit in the prefix part of the header.
953 if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
954 (void) strcpy(xhdr_dirname, "/tmp");
955 if ((vflag > 0) && (Eflag > 0))
956 (void) fprintf(stderr, gettext(
957 "Ignoring TMPDIR\n"));
958 } else
959 (void) strcpy(xhdr_dirname, tmpdirp);
961 (void) strcat(xhdr_dirname, "/PaxHeaders.");
962 (void) strcat(xhdr_dirname, pidchars);
964 if (rflag) {
965 if (cflag && usefile != NULL) {
966 /* Set the compression type */
967 if (aflag)
968 detect_compress();
970 if (jflag) {
971 compress_opt = compress_malloc(strlen(BZIP)
972 + 1);
973 (void) strcpy(compress_opt, BZIP);
974 } else if (zflag) {
975 compress_opt = compress_malloc(strlen(GZIP)
976 + 1);
977 (void) strcpy(compress_opt, GZIP);
978 } else if (Zflag) {
979 compress_opt =
980 compress_malloc(strlen(COMPRESS) + 1);
981 (void) strcpy(compress_opt, COMPRESS);
982 } else if (Jflag) {
983 compress_opt = compress_malloc(strlen(XZ) + 1);
984 (void) strcpy(compress_opt, XZ);
986 } else {
988 * Decompress if the file is compressed for
989 * an update or replace.
991 if (strcmp(usefile, "-") != 0) {
992 check_compression();
993 if (compress_opt != NULL) {
994 decompress_file();
999 if (cflag && tfile != NULL)
1000 usage();
1001 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1002 (void) signal(SIGINT, onintr);
1003 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1004 (void) signal(SIGHUP, onhup);
1005 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1006 (void) signal(SIGQUIT, onquit);
1007 if (uflag) {
1008 int tnum;
1009 struct stat sbuf;
1011 tmpdir = getenv("TMPDIR");
1013 * If the name is invalid or this isn't a directory,
1014 * or the directory is not writable, then reset to
1015 * a default temporary directory.
1017 if (tmpdir == NULL || *tmpdir == '\0' ||
1018 (strlen(tmpdir) + strlen(tmp_suffix)) > PATH_MAX) {
1019 tmpdir = "/tmp";
1020 } else if (stat(tmpdir, &sbuf) < 0 ||
1021 (sbuf.st_mode & S_IFMT) != S_IFDIR ||
1022 (sbuf.st_mode & S_IWRITE) == 0) {
1023 tmpdir = "/tmp";
1026 if ((tname = calloc(1, strlen(tmpdir) +
1027 strlen(tmp_suffix) + 1)) == NULL) {
1028 vperror(1, gettext("tar: out of memory, "
1029 "cannot create temporary file\n"));
1031 (void) strcpy(tname, tmpdir);
1032 (void) strcat(tname, tmp_suffix);
1034 if ((tnum = mkstemp(tname)) == -1)
1035 vperror(1, "%s", tname);
1036 if ((tfile = fdopen(tnum, "w")) == NULL)
1037 vperror(1, "%s", tname);
1039 if (strcmp(usefile, "-") == 0) {
1040 if (cflag == 0)
1041 fatal(gettext(
1042 "can only create standard output archives."));
1043 vfile = stderr;
1044 mt = dup(1);
1045 ++bflag;
1046 } else {
1047 if (cflag)
1048 mt = open(usefile,
1049 O_RDWR|O_CREAT|O_TRUNC, 0666);
1050 else
1051 mt = open(usefile, O_RDWR);
1053 if (mt < 0) {
1054 if (cflag == 0 || (mt = creat(usefile, 0666))
1055 < 0)
1056 vperror(1, "%s", usefile);
1059 /* Get inode and device number of output file */
1060 (void) fstat(mt, &stbuf);
1061 mt_ino = stbuf.st_ino;
1062 mt_dev = stbuf.st_dev;
1063 mt_devtype = stbuf.st_mode & S_IFMT;
1064 NotTape = !istape(mt, mt_devtype);
1066 if (rflag && !cflag && (mt_devtype == S_IFIFO))
1067 fatal(gettext("cannot append to pipe or FIFO."));
1069 if (Aflag && vflag)
1070 (void) printf(
1071 gettext("Suppressing absolute pathnames\n"));
1072 if (cflag && compress_opt != NULL)
1073 comp_pid = compress_file();
1074 dorep(argv);
1075 if (rflag && !cflag && (compress_opt != NULL))
1076 compress_back();
1077 } else if (xflag || tflag) {
1079 * for each argument, check to see if there is a "-I file" pair.
1080 * if so, move the 3rd argument into "-I"'s place, build_table()
1081 * using "file"'s name and increment argc one (the second
1082 * increment appears in the for loop) which removes the two
1083 * args "-I" and "file" from the argument vector.
1085 for (argc = 0; argv[argc]; argc++) {
1086 if (strcmp(argv[argc], "-I") == 0) {
1087 if (!argv[argc+1]) {
1088 (void) fprintf(stderr, gettext(
1089 "tar: missing argument for -I flag\n"));
1090 done(2);
1091 } else {
1092 Iflag = 1;
1093 argv[argc] = argv[argc+2];
1094 build_table(include_tbl, argv[++argc]);
1096 } else if (strcmp(argv[argc], "-C") == 0) {
1097 if (!argv[argc+1]) {
1098 (void) fprintf(stderr, gettext("tar: "
1099 "missing argument for -C flag\n"));
1100 done(2);
1101 } else if (xtract_chdir != NULL) {
1102 (void) fprintf(stderr, gettext("tar: "
1103 "extract should have only one -C "
1104 "flag\n"));
1105 done(2);
1106 } else {
1107 argv[argc] = argv[argc+2];
1108 xtract_chdir = argv[++argc];
1112 if (strcmp(usefile, "-") == 0) {
1113 mt = dup(0);
1114 ++bflag;
1115 /* try to recover from short reads when reading stdin */
1116 ++Bflag;
1117 } else if ((mt = open(usefile, O_RDONLY)) < 0)
1118 vperror(1, "%s", usefile);
1120 /* Decompress if the file is compressed */
1122 if (strcmp(usefile, "-") != 0) {
1123 check_compression();
1124 if (compress_opt != NULL)
1125 comp_pid = uncompress_file();
1127 if (xflag) {
1128 if (xtract_chdir != NULL) {
1129 if (tar_chdir(xtract_chdir) < 0) {
1130 vperror(1, gettext("can't change "
1131 "directories to %s"), xtract_chdir);
1134 if (Aflag && vflag)
1135 (void) printf(gettext(
1136 "Suppressing absolute pathnames.\n"));
1138 doxtract(argv);
1139 } else if (tflag)
1140 dotable(argv);
1142 else
1143 usage();
1145 done(Errflg);
1147 /* Not reached: keep compiler quiet */
1148 return (1);
1151 static boolean_t
1152 should_enable_debug(void)
1154 const char *val;
1155 const char *truth[] = {
1156 "true",
1157 "1",
1158 "yes",
1159 "y",
1160 "please",
1161 NULL
1163 unsigned int i;
1165 if ((val = getenv("DEBUG_TAR")) == NULL) {
1166 return (B_FALSE);
1169 for (i = 0; truth[i] != NULL; i++) {
1170 if (strcmp(val, truth[i]) == 0) {
1171 return (B_TRUE);
1175 return (B_FALSE);
1178 /*PRINTFLIKE1*/
1179 static void
1180 dlog(const char *format, ...)
1182 va_list ap;
1184 if (!debug_output) {
1185 return;
1188 va_start(ap, format);
1189 (void) fprintf(stderr, "tar: DEBUG: ");
1190 (void) vfprintf(stderr, format, ap);
1191 va_end(ap);
1194 static void
1195 usage(void)
1197 (void) fprintf(stderr, gettext(
1198 #if defined(O_XATTR)
1199 #if defined(_PC_SATTR_ENABLED)
1200 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPvw@/[0-7]][bf][X...] "
1201 #else
1202 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPvw@[0-7]][bf][X...] "
1203 #endif /* _PC_SATTR_ENABLED */
1204 #else
1205 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPvw[0-7]][bf][X...] "
1206 #endif /* O_XATTR */
1207 "[j|J|z|Z] "
1208 "[blocksize] [tarfile] [size] [exclude-file...] "
1209 "{file | -I include-file | -C directory file}...\n"));
1210 done(1);
1214 * dorep - do "replacements"
1216 * Dorep is responsible for creating ('c'), appending ('r')
1217 * and updating ('u');
1220 static void
1221 dorep(char *argv[])
1223 char *cp, *cp2, *p;
1224 char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
1225 char file[PATH_MAX*2], origdir[PATH_MAX+1];
1226 FILE *fp = NULL;
1227 int archtype;
1228 int ret;
1231 if (!cflag) {
1232 xhdr_flgs = 0;
1233 getdir(); /* read header for next file */
1234 if (Xhdrflag > 0) {
1235 if (!Eflag)
1236 fatal(gettext("Archive contains extended"
1237 " header. -E flag required.\n"));
1238 ret = get_xdata(); /* Get extended header items */
1239 /* and regular header */
1240 } else {
1241 if (Eflag)
1242 fatal(gettext("Archive contains no extended"
1243 " header. -E flag not allowed.\n"));
1245 while (!endtape()) { /* changed from a do while */
1246 setbytes_to_skip(&stbuf, ret);
1247 passtape(); /* skip the file data */
1248 if (term)
1249 done(Errflg); /* received signal to stop */
1250 xhdr_flgs = 0;
1251 getdir();
1252 if (Xhdrflag > 0)
1253 ret = get_xdata();
1255 if (ret == 0) {
1256 if ((dblock.dbuf.typeflag != 'A') &&
1257 (xhdr_flgs != 0)) {
1258 load_info_from_xtarhdr(xhdr_flgs,
1259 &Xtarhdr);
1260 xhdr_flgs |= _X_XHDR;
1263 backtape(); /* was called by endtape */
1264 if (tfile != NULL) {
1266 * Buffer size is calculated to be the size of the
1267 * tmpdir string, plus 6 times the size of the tname
1268 * string, plus a value that is known to be greater
1269 * than the command pipeline string.
1271 int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
1272 char *buf;
1274 if ((buf = (char *)calloc(1, buflen)) == NULL) {
1275 vperror(1, gettext("tar: out of memory, "
1276 "cannot create sort command file\n"));
1279 (void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
1280 "sort +0 -1 +1nr %s -o %s; awk '$1 "
1281 "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1282 tmpdir, tname, tname, tname, tname, tname, tname);
1283 (void) fflush(tfile);
1284 (void) system(buf);
1285 free(buf);
1286 (void) freopen(tname, "r", tfile);
1287 (void) fstat(fileno(tfile), &stbuf);
1288 high = stbuf.st_size;
1292 dumping = 1;
1293 if (mulvol) { /* SP-1 */
1294 if (nblock && (blocklim%nblock) != 0)
1295 fatal(gettext(
1296 "Volume size not a multiple of block size."));
1297 blocklim -= 2; /* for trailer records */
1298 if (vflag)
1299 (void) fprintf(vfile, gettext("Volume ends at %"
1300 FMT_blkcnt_t "K, blocking factor = %dK\n"),
1301 K((blocklim - 1)), K(nblock));
1305 * Save the original directory before it gets
1306 * changed.
1308 if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
1309 vperror(0, gettext("A parent directory cannot be read"));
1310 exit(1);
1313 (void) strcpy(wdir, origdir);
1315 while ((*argv || fp) && !term) {
1316 if (fp || (strcmp(*argv, "-I") == 0)) {
1317 if (fp == NULL) {
1318 if (*++argv == NULL)
1319 fatal(gettext(
1320 "missing file name for -I flag."));
1321 else if ((fp = fopen(*argv++, "r")) == NULL)
1322 vperror(0, "%s", argv[-1]);
1323 continue;
1324 } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
1325 (void) fclose(fp);
1326 fp = NULL;
1327 continue;
1328 } else {
1329 cp = cp2 = file;
1330 if ((p = strchr(cp2, '\n')))
1331 *p = 0;
1333 } else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
1334 if (tar_chdir(*++argv) < 0)
1335 vperror(0, gettext(
1336 "can't change directories to %s"), *argv);
1337 else
1338 (void) getcwd(wdir, (sizeof (wdir)));
1339 argv++;
1340 continue;
1341 } else
1342 cp = cp2 = strcpy(file, *argv++);
1345 * point cp2 to the last '/' in file, but not
1346 * to a trailing '/'
1348 for (; *cp; cp++) {
1349 if (*cp == '/') {
1350 while (*(cp+1) == '/') {
1351 ++cp;
1353 if (*(cp+1) != '\0') {
1354 /* not trailing slash */
1355 cp2 = cp;
1359 if (cp2 != file) {
1360 *cp2 = '\0';
1361 if (tar_chdir(file) < 0) {
1362 vperror(0, gettext(
1363 "can't change directories to %s"), file);
1364 continue;
1366 *cp2 = '/';
1367 cp2++;
1370 parent = getcwd(tempdir, (sizeof (tempdir)));
1372 archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
1373 LEV0, SYMLINK_LEV0);
1375 #if defined(O_XATTR)
1376 if (!exitflag) {
1377 if ((atflag || saflag) &&
1378 (archtype == PUT_NOTAS_LINK)) {
1379 xattrs_put(file, cp2, parent, NULL);
1382 #endif
1384 if (tar_chdir(origdir) < 0)
1385 vperror(0, gettext("cannot change back?: %s"), origdir);
1387 if (exitflag) {
1389 * If e function modifier has been specified
1390 * write the files (that are listed before the
1391 * file causing the error) to tape. exitflag is
1392 * used because only some of the error conditions
1393 * in putfile() recognize the e function modifier.
1395 break;
1399 putempty((blkcnt_t)2);
1400 flushtape();
1401 closevol(); /* SP-1 */
1402 if (linkerrok == 1)
1403 for (; ihead != NULL; ihead = ihead->nextp) {
1404 if (ihead->count == 0)
1405 continue;
1406 (void) fprintf(stderr, gettext(
1407 "tar: missing links to %s\n"), ihead->pathname);
1408 if (errflag)
1409 done(1);
1410 else
1411 Errflg = 1;
1417 * endtape - check for tape at end
1419 * endtape checks the entry in dblock.dbuf to see if its the
1420 * special EOT entry. Endtape is usually called after getdir().
1422 * endtape used to call backtape; it no longer does. If the caller
1423 * wants the tape backed up, it must call backtape itself
1424 * RETURNS: 0 if not EOT, tape position unaffected
1425 * 1 if EOT, tape position unaffected
1428 static boolean_t
1429 endtape(void)
1431 if (dblock.dbuf.name[0] != '\0') {
1433 * The name field is populated.
1435 return (B_FALSE);
1438 if (is_posix && dblock.dbuf.prefix[0] != '\0') {
1440 * This is a ustar/POSIX archive, and although the name
1441 * field is empty the prefix field is not.
1443 return (B_FALSE);
1446 dlog("endtape(): found null header; EOT\n");
1447 return (B_TRUE);
1451 * getdir - get directory entry from tar tape
1453 * getdir reads the next tarblock off the tape and cracks
1454 * it as a directory. The checksum must match properly.
1456 * If tfile is non-null getdir writes the file name and mod date
1457 * to tfile.
1460 static void
1461 getdir(void)
1463 struct stat *sp;
1464 #ifdef EUC
1465 static int warn_chksum_sign = 0;
1466 #endif /* EUC */
1468 top:
1469 readtape((char *)&dblock);
1470 if (dblock.dbuf.name[0] == '\0')
1471 return;
1472 sp = &stbuf;
1473 (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
1474 (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
1475 (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
1476 (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
1477 (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
1478 (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
1479 (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
1480 (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
1482 is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
1484 sp->st_mode = Gen.g_mode;
1485 if (is_posix && (sp->st_mode & S_IFMT) == 0) {
1486 switch (dblock.dbuf.typeflag) {
1487 case '0':
1488 case 0:
1489 case _XATTR_HDRTYPE:
1490 sp->st_mode |= S_IFREG;
1491 break;
1492 case '1': /* hard link */
1493 break;
1494 case '2':
1495 sp->st_mode |= S_IFLNK;
1496 break;
1497 case '3':
1498 sp->st_mode |= S_IFCHR;
1499 break;
1500 case '4':
1501 sp->st_mode |= S_IFBLK;
1502 break;
1503 case '5':
1504 sp->st_mode |= S_IFDIR;
1505 break;
1506 case '6':
1507 sp->st_mode |= S_IFIFO;
1508 break;
1509 default:
1510 if (convtoreg(Gen.g_filesz))
1511 sp->st_mode |= S_IFREG;
1512 break;
1516 if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
1517 Xhdrflag = 1; /* Currently processing extended header */
1518 } else {
1519 Xhdrflag = 0;
1522 sp->st_uid = Gen.g_uid;
1523 sp->st_gid = Gen.g_gid;
1524 sp->st_size = Gen.g_filesz;
1525 sp->st_mtime = Gen.g_mtime;
1526 chksum = Gen.g_cksum;
1528 if (dblock.dbuf.extno != '\0') { /* split file? */
1529 extno = dblock.dbuf.extno;
1530 extsize = Gen.g_filesz;
1531 extotal = dblock.dbuf.extotal;
1532 } else {
1533 extno = 0; /* tell others file not split */
1534 extsize = 0;
1535 extotal = 0;
1538 #ifdef EUC
1539 if (chksum != checksum(&dblock)) {
1540 if (chksum != checksum_signed(&dblock)) {
1541 (void) fprintf(stderr, gettext(
1542 "tar: directory checksum error\n"));
1543 if (iflag) {
1544 Errflg = 2;
1545 goto top;
1547 done(2);
1548 } else {
1549 if (! warn_chksum_sign) {
1550 warn_chksum_sign = 1;
1551 (void) fprintf(stderr, gettext(
1552 "tar: warning: tar file made with signed checksum\n"));
1556 #else
1557 if (chksum != checksum(&dblock)) {
1558 (void) fprintf(stderr, gettext(
1559 "tar: directory checksum error\n"));
1560 if (iflag) {
1561 Errflg = 2;
1562 goto top;
1564 done(2);
1566 #endif /* EUC */
1567 if (tfile != NULL && Xhdrflag == 0) {
1569 * If an extended header is present, then time is available
1570 * in nanoseconds in the extended header data, so set it.
1571 * Otherwise, give an invalid value so that checkupdate will
1572 * not test beyond seconds.
1574 if ((xhdr_flgs & _X_MTIME))
1575 sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
1576 else
1577 sp->st_mtim.tv_nsec = -1;
1579 if (xhdr_flgs & _X_PATH)
1580 (void) fprintf(tfile, "%s %10ld.%9.9ld\n",
1581 Xtarhdr.x_path, sp->st_mtim.tv_sec,
1582 sp->st_mtim.tv_nsec);
1583 else
1584 (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
1585 NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
1586 sp->st_mtim.tv_nsec);
1589 #if defined(O_XATTR)
1590 Hiddendir = 0;
1591 if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
1592 if (xattrbadhead) {
1593 free(xattrhead);
1594 xattrp = NULL;
1595 xattr_linkp = NULL;
1596 xattrhead = NULL;
1597 } else {
1598 char *aname = basename(xattrapath);
1599 size_t xindex = aname - xattrapath;
1601 if (xattrapath[xindex] == '.' &&
1602 xattrapath[xindex + 1] == '\0' &&
1603 xattrp->h_typeflag == '5') {
1604 Hiddendir = 1;
1605 sp->st_mode =
1606 (S_IFDIR | (sp->st_mode & POSIXMODES));
1608 dblock.dbuf.typeflag = xattrp->h_typeflag;
1611 #endif
1616 * passtape - skip over a file on the tape
1618 * passtape skips over the next data file on the tape.
1619 * The tape directory entry must be in dblock.dbuf. This
1620 * routine just eats the number of blocks computed from the
1621 * directory size entry; the tape must be (logically) positioned
1622 * right after the directory info.
1625 static void
1626 passtape(void)
1628 blkcnt_t blocks;
1629 char buf[TBLOCK];
1632 * Print some debugging information about the directory entry
1633 * we are skipping over:
1635 dlog("passtape: typeflag \"%c\"\n", dblock.dbuf.typeflag);
1636 if (dblock.dbuf.name[0] != '\0') {
1637 dlog("passtape: name \"%s\"\n", dblock.dbuf.name);
1639 if (is_posix && dblock.dbuf.prefix[0] != '\0') {
1640 dlog("passtape: prefix \"%s\"\n", dblock.dbuf.prefix);
1644 * Types link(1), sym-link(2), char special(3), blk special(4),
1645 * directory(5), and FIFO(6) do not have data blocks associated
1646 * with them so just skip reading the data block.
1648 if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
1649 dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
1650 dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
1651 return;
1652 blocks = TBLOCKS(stbuf.st_size);
1654 dlog("passtape: block count %" FMT_blkcnt_t "\n", blocks);
1656 /* if operating on disk, seek instead of reading */
1657 if (NotTape)
1658 seekdisk(blocks);
1659 else
1660 while (blocks-- > 0)
1661 readtape(buf);
1664 #if defined(O_XATTR)
1665 static int
1666 is_sysattr(char *name)
1668 return ((strcmp(name, VIEW_READONLY) == 0) ||
1669 (strcmp(name, VIEW_READWRITE) == 0));
1671 #endif
1673 #if defined(O_XATTR)
1675 * Verify the attribute, attrname, is an attribute we want to restore.
1676 * Never restore read-only system attribute files. Only restore read-write
1677 * system attributes files when -/ was specified, and only traverse into
1678 * the 2nd level attribute directory containing only system attributes if
1679 * -@ was specified. This keeps us from archiving
1680 * <attribute name>/<read-write system attribute file>
1681 * when -/ was specified without -@.
1683 * attrname - attribute file name
1684 * attrparent - attribute's parent name within the base file's attribute
1685 * directory hierarchy
1687 static attr_status_t
1688 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
1689 int *rw_sysattr)
1691 #if defined(_PC_SATTR_ENABLED)
1692 int attr_supported;
1694 /* Never restore read-only system attribute files */
1695 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
1696 *rw_sysattr = 0;
1697 return (ATTR_SKIP);
1698 } else {
1699 *rw_sysattr = (attr_supported == _RW_SATTR);
1701 #else
1703 * Only need to check if this attribute is an extended system
1704 * attribute.
1706 if (*rw_sysattr = is_sysattr(attrname)) {
1707 return (ATTR_SKIP);
1708 } else {
1709 return (ATTR_OK);
1711 #endif /* _PC_SATTR_ENABLED */
1714 * If the extended system attribute file is specified with the
1715 * arc_rwsysattr flag, as being transient (default extended
1716 * attributes), then don't archive it.
1718 if (*rw_sysattr && !arc_rwsysattr) {
1719 return (ATTR_SKIP);
1723 * Only restore read-write system attribute files
1724 * when -/ was specified. Only restore extended
1725 * attributes when -@ was specified.
1727 if (atflag) {
1728 if (!saflag) {
1730 * Only archive/restore the hidden directory "." if
1731 * we're processing the top level hidden attribute
1732 * directory. We don't want to process the
1733 * hidden attribute directory of the attribute
1734 * directory that contains only extended system
1735 * attributes.
1737 if (*rw_sysattr || (Hiddendir &&
1738 (attrparent != NULL))) {
1739 return (ATTR_SKIP);
1742 } else if (saflag) {
1744 * Only archive/restore read-write extended system attribute
1745 * files of the base file.
1747 if (!*rw_sysattr || (attrparent != NULL)) {
1748 return (ATTR_SKIP);
1750 } else {
1751 return (ATTR_SKIP);
1754 return (ATTR_OK);
1756 #endif
1758 static void
1759 free_children(file_list_t *children)
1761 file_list_t *child = children;
1762 file_list_t *cptr;
1764 while (child != NULL) {
1765 cptr = child->next;
1766 if (child->name != NULL) {
1767 free(child->name);
1769 child = cptr;
1773 static int
1774 putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
1775 int filetype, int lev, int symlink_lev)
1777 int infile = -1; /* deliberately invalid */
1778 blkcnt_t blocks;
1779 char buf[PATH_MAX + 2]; /* Add trailing slash and null */
1780 char *bigbuf;
1781 int maxread;
1782 int hint; /* amount to write to get "in sync" */
1783 char filetmp[PATH_MAX + 1];
1784 char *cp;
1785 char *name;
1786 char *attrparent = NULL;
1787 char *longattrname = NULL;
1788 file_list_t *child = NULL;
1789 file_list_t *child_end = NULL;
1790 file_list_t *cptr;
1791 struct dirent *dp;
1792 DIR *dirp;
1793 int i;
1794 int split;
1795 int dirfd = -1;
1796 int rc = PUT_NOTAS_LINK;
1797 int archtype = 0;
1798 int rw_sysattr = 0;
1799 char newparent[PATH_MAX + MAXNAMLEN + 1];
1800 char *prefix = "";
1801 char *tmpbuf;
1802 char goodbuf[PRESIZ + 2];
1803 char junkbuf[MAXNAM+1];
1804 char *lastslash;
1805 int j;
1806 struct stat sbuf;
1807 int readlink_max;
1809 (void) memset(goodbuf, '\0', sizeof (goodbuf));
1810 (void) memset(junkbuf, '\0', sizeof (junkbuf));
1812 xhdr_flgs = 0;
1814 if (filetype == XATTR_FILE) {
1815 attrparent = attrinfo->attr_parent;
1816 longattrname = attrinfo->attr_path;
1817 dirfd = attrinfo->attr_parentfd;
1818 rw_sysattr = attrinfo->attr_rw_sysattr;
1819 } else {
1820 dirfd = open(".", O_RDONLY);
1823 if (dirfd == -1) {
1824 (void) fprintf(stderr, gettext(
1825 "tar: unable to open%sdirectory %s%s%s%s\n"),
1826 (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
1827 (attrparent == NULL) ? "" : gettext("of attribute "),
1828 (attrparent == NULL) ? "" : attrparent,
1829 (attrparent == NULL) ? "" : gettext(" of "),
1830 (filetype == XATTR_FILE) ? longname : parent);
1831 goto out;
1834 if (lev > MAXLEV) {
1835 (void) fprintf(stderr,
1836 gettext("tar: directory nesting too deep, %s not dumped\n"),
1837 longname);
1838 goto out;
1841 if (getstat(dirfd, longname, shortname, attrparent))
1842 goto out;
1844 if (hflag) {
1846 * Catch nesting where a file is a symlink to its directory.
1848 j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
1849 if (S_ISLNK(sbuf.st_mode)) {
1850 if (symlink_lev++ >= MAXSYMLINKS) {
1851 (void) fprintf(stderr, gettext(
1852 "tar: %s: Number of symbolic links "
1853 "encountered during path name traversal "
1854 "exceeds MAXSYMLINKS\n"), longname);
1855 Errflg = 1;
1856 goto out;
1862 * Check if the input file is the same as the tar file we
1863 * are creating
1865 if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
1866 (void) fprintf(stderr, gettext(
1867 "tar: %s%s%s%s%s same as archive file\n"),
1868 rw_sysattr ? gettext("system ") : "",
1869 (longattrname == NULL) ? "" : gettext("attribute "),
1870 (longattrname == NULL) ? "" : longattrname,
1871 (longattrname == NULL) ? "" : gettext(" of "),
1872 longname);
1873 Errflg = 1;
1874 goto out;
1877 * Check size limit - we can't archive files that
1878 * exceed TAR_OFFSET_MAX bytes because of header
1879 * limitations. Exclude file types that set
1880 * st_size to zero below because they take no
1881 * archive space to represent contents.
1883 if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
1884 !S_ISDIR(stbuf.st_mode) &&
1885 !S_ISCHR(stbuf.st_mode) &&
1886 !S_ISBLK(stbuf.st_mode) &&
1887 (Eflag == 0)) {
1888 (void) fprintf(stderr, gettext(
1889 "tar: %s%s%s%s%s too large to archive. "
1890 "Use E function modifier.\n"),
1891 rw_sysattr ? gettext("system ") : "",
1892 (longattrname == NULL) ? "" : gettext("attribute "),
1893 (longattrname == NULL) ? "" : longattrname,
1894 (longattrname == NULL) ? "" : gettext(" of "),
1895 longname);
1896 if (errflag)
1897 exitflag = 1;
1898 Errflg = 1;
1899 goto out;
1902 if (tfile != NULL && checkupdate(longname) == 0) {
1903 goto out;
1905 if (checkw('r', longname) == 0) {
1906 goto out;
1909 if (Fflag &&
1910 checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
1911 goto out;
1913 if (Xflag) {
1914 if (is_in_table(exclude_tbl, longname)) {
1915 if (vflag) {
1916 (void) fprintf(vfile, gettext(
1917 "a %s excluded\n"), longname);
1919 goto out;
1924 * If the length of the fullname is greater than MAXNAM,
1925 * print out a message and return (unless extended headers are used,
1926 * in which case fullname is limited to PATH_MAX).
1929 if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
1930 (split > PATH_MAX)) {
1931 (void) fprintf(stderr, gettext(
1932 "tar: %s: file name too long\n"), longname);
1933 if (errflag)
1934 exitflag = 1;
1935 Errflg = 1;
1936 goto out;
1940 * We split the fullname into prefix and name components if any one
1941 * of three conditions holds:
1942 * -- the length of the fullname exceeds NAMSIZ,
1943 * -- the length of the fullname equals NAMSIZ, and the shortname
1944 * is less than NAMSIZ, (splitting in this case preserves
1945 * compatibility with 5.6 and 5.5.1 tar), or
1946 * -- the length of the fullname equals NAMSIZ, the file is a
1947 * directory and we are not in POSIX-conformant mode (where
1948 * trailing slashes are removed from directories).
1950 if ((split > NAMSIZ) ||
1951 (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1952 (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
1954 * Since path is limited to PRESIZ characters, look for the
1955 * last slash within PRESIZ + 1 characters only.
1957 (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
1958 tmpbuf = goodbuf;
1959 lastslash = strrchr(tmpbuf, '/');
1960 if (lastslash == NULL) {
1961 i = split; /* Length of name */
1962 j = 0; /* Length of prefix */
1963 goodbuf[0] = '\0';
1964 } else {
1965 *lastslash = '\0'; /* Terminate the prefix */
1966 j = strlen(tmpbuf);
1967 i = split - j - 1;
1970 * If the filename is greater than NAMSIZ we can't
1971 * archive the file unless we are using extended headers.
1973 if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
1974 !Pflag)) {
1975 /* Determine which (filename or path) is too long. */
1976 lastslash = strrchr(longname, '/');
1977 if (lastslash != NULL)
1978 i = strlen(lastslash + 1);
1979 if (Eflag > 0) {
1980 xhdr_flgs |= _X_PATH;
1981 Xtarhdr.x_path = longname;
1982 if (i <= NAMSIZ)
1983 (void) strcpy(junkbuf, lastslash + 1);
1984 else
1985 (void) sprintf(junkbuf, "%llu",
1986 xhdr_count + 1);
1987 if (split - i - 1 > PRESIZ)
1988 (void) strcpy(goodbuf, xhdr_dirname);
1989 } else {
1990 if ((i > NAMSIZ) || (i == NAMSIZ &&
1991 S_ISDIR(stbuf.st_mode) && !Pflag))
1992 (void) fprintf(stderr, gettext(
1993 "tar: %s: filename is greater than "
1994 "%d\n"), lastslash == NULL ?
1995 longname : lastslash + 1, NAMSIZ);
1996 else
1997 (void) fprintf(stderr, gettext(
1998 "tar: %s: prefix is greater than %d"
1999 "\n"), longname, PRESIZ);
2000 if (errflag)
2001 exitflag = 1;
2002 Errflg = 1;
2003 goto out;
2005 } else
2006 (void) strncpy(&junkbuf[0], longname + j + 1,
2007 strlen(longname + j + 1));
2008 name = junkbuf;
2009 prefix = goodbuf;
2010 } else {
2011 name = longname;
2013 if (Aflag) {
2014 if ((prefix != NULL) && (*prefix != '\0'))
2015 while (*prefix == '/')
2016 ++prefix;
2017 else
2018 while (*name == '/')
2019 ++name;
2022 switch (stbuf.st_mode & S_IFMT) {
2023 case S_IFDIR:
2024 stbuf.st_size = (off_t)0;
2025 blocks = TBLOCKS(stbuf.st_size);
2027 if (filetype != XATTR_FILE && Hiddendir == 0) {
2028 i = 0;
2029 cp = buf;
2030 while ((*cp++ = longname[i++]))
2032 *--cp = '/';
2033 *++cp = 0;
2035 if (!oflag) {
2036 tomodes(&stbuf);
2037 if (build_dblock(name, tchar, '5', filetype,
2038 &stbuf, stbuf.st_dev, prefix) != 0) {
2039 goto out;
2041 if (!Pflag) {
2043 * Old archives require a slash at the end
2044 * of a directory name.
2046 * XXX
2047 * If directory name is too long, will
2048 * slash overfill field?
2050 if (strlen(name) > (unsigned)NAMSIZ-1) {
2051 (void) fprintf(stderr, gettext(
2052 "tar: %s: filename is greater "
2053 "than %d\n"), name, NAMSIZ);
2054 if (errflag)
2055 exitflag = 1;
2056 Errflg = 1;
2057 goto out;
2058 } else {
2059 if (strlen(name) == (NAMSIZ - 1)) {
2060 (void) memcpy(dblock.dbuf.name,
2061 name, NAMSIZ);
2062 dblock.dbuf.name[NAMSIZ-1]
2063 = '/';
2064 } else
2065 (void) sprintf(dblock.dbuf.name,
2066 "%s/", name);
2069 * need to recalculate checksum
2070 * because the name changed.
2072 (void) sprintf(dblock.dbuf.chksum,
2073 "%07o", checksum(&dblock));
2077 if (put_extra_attributes(longname, shortname,
2078 longattrname, prefix, filetype, '5') != 0)
2079 goto out;
2081 #if defined(O_XATTR)
2083 * Reset header typeflag when archiving directory, since
2084 * build_dblock changed it on us.
2086 if (filetype == XATTR_FILE) {
2087 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2088 } else {
2089 dblock.dbuf.typeflag = '5';
2091 #else
2092 dblock.dbuf.typeflag = '5';
2093 #endif
2095 (void) sprintf(dblock.dbuf.chksum, "%07o",
2096 checksum(&dblock));
2098 (void) writetbuf((char *)&dblock, 1);
2100 if (vflag) {
2101 if (NotTape) {
2102 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2104 if (filetype == XATTR_FILE && Hiddendir) {
2105 (void) fprintf(vfile,
2106 gettext("a %s attribute %s "),
2107 longname, longattrname);
2109 } else {
2110 (void) fprintf(vfile, "a %s/ ", longname);
2112 if (NotTape) {
2113 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2114 K(blocks));
2115 } else {
2116 (void) fprintf(vfile, gettext("%" FMT_blkcnt_t
2117 " tape blocks\n"), blocks);
2122 * If hidden dir then break now since xattrs_put() will do
2123 * the iterating of the directory.
2125 * At the moment, there can only be system attributes on
2126 * attributes. There can be no attributes on attributes or
2127 * directories within the attributes hidden directory hierarchy.
2129 if (filetype == XATTR_FILE)
2130 break;
2132 if (*shortname != '/')
2133 (void) sprintf(newparent, "%s/%s", parent, shortname);
2134 else
2135 (void) sprintf(newparent, "%s", shortname);
2137 if (tar_chdir(shortname) < 0) {
2138 vperror(0, "%s", newparent);
2139 goto out;
2142 if ((dirp = opendir(".")) == NULL) {
2143 vperror(0, gettext(
2144 "can't open directory %s"), longname);
2145 if (tar_chdir(parent) < 0)
2146 vperror(0, gettext("cannot change back?: %s"),
2147 parent);
2148 goto out;
2152 * Create a list of files (children) in this directory to avoid
2153 * having to perform telldir()/seekdir().
2155 while ((dp = readdir(dirp)) != NULL && !term) {
2156 if ((strcmp(".", dp->d_name) == 0) ||
2157 (strcmp("..", dp->d_name) == 0))
2158 continue;
2159 if (((cptr = (file_list_t *)calloc(sizeof (char),
2160 sizeof (file_list_t))) == NULL) ||
2161 ((cptr->name = strdup(dp->d_name)) == NULL)) {
2162 vperror(1, gettext(
2163 "Insufficient memory for directory "
2164 "list entry %s/%s\n"),
2165 newparent, dp->d_name);
2168 /* Add the file to the list */
2169 if (child == NULL) {
2170 child = cptr;
2171 } else {
2172 child_end->next = cptr;
2174 child_end = cptr;
2176 (void) closedir(dirp);
2179 * Archive each of the files in the current directory.
2180 * If a file is a directory, putfile() is called
2181 * recursively to archive the file hierarchy of the
2182 * directory before archiving the next file in the
2183 * current directory.
2185 while ((child != NULL) && !term) {
2186 (void) strcpy(cp, child->name);
2187 archtype = putfile(buf, cp, newparent, NULL,
2188 NORMAL_FILE, lev + 1, symlink_lev);
2190 if (!exitflag) {
2191 if ((atflag || saflag) &&
2192 (archtype == PUT_NOTAS_LINK)) {
2193 xattrs_put(buf, cp, newparent, NULL);
2196 if (exitflag)
2197 break;
2199 /* Free each child as we are done processing it. */
2200 cptr = child;
2201 child = child->next;
2202 free(cptr->name);
2203 free(cptr);
2205 if ((child != NULL) && !term) {
2206 free_children(child);
2209 if (tar_chdir(parent) < 0) {
2210 vperror(0, gettext("cannot change back?: %s"), parent);
2213 break;
2215 case S_IFLNK:
2216 readlink_max = NAMSIZ;
2217 if (stbuf.st_size > NAMSIZ) {
2218 if (Eflag > 0) {
2219 xhdr_flgs |= _X_LINKPATH;
2220 readlink_max = PATH_MAX;
2221 } else {
2222 (void) fprintf(stderr, gettext(
2223 "tar: %s: symbolic link too long\n"),
2224 longname);
2225 if (errflag)
2226 exitflag = 1;
2227 Errflg = 1;
2228 goto out;
2232 * Sym-links need header size of zero since you
2233 * don't store any data for this type.
2235 stbuf.st_size = (off_t)0;
2236 tomodes(&stbuf);
2237 i = readlink(shortname, filetmp, readlink_max);
2238 if (i < 0) {
2239 vperror(0, gettext(
2240 "can't read symbolic link %s"), longname);
2241 goto out;
2242 } else {
2243 filetmp[i] = 0;
2245 if (vflag)
2246 (void) fprintf(vfile, gettext(
2247 "a %s symbolic link to %s\n"),
2248 longname, filetmp);
2249 if (xhdr_flgs & _X_LINKPATH) {
2250 Xtarhdr.x_linkpath = filetmp;
2251 if (build_dblock(name, tchar, '2', filetype, &stbuf,
2252 stbuf.st_dev, prefix) != 0)
2253 goto out;
2254 } else
2255 if (build_dblock(name, filetmp, '2', filetype, &stbuf,
2256 stbuf.st_dev, prefix) != 0)
2257 goto out;
2258 (void) writetbuf((char *)&dblock, 1);
2260 * No acls for symlinks: mode is always 777
2261 * dont call write ancillary
2263 rc = PUT_AS_LINK;
2264 break;
2265 case S_IFREG:
2266 if ((infile = openat(dirfd, shortname, 0)) < 0) {
2267 vperror(0, gettext("unable to open %s%s%s%s"), longname,
2268 rw_sysattr ? gettext(" system") : "",
2269 (filetype == XATTR_FILE) ?
2270 gettext(" attribute ") : "",
2271 (filetype == XATTR_FILE) ? (longattrname == NULL) ?
2272 shortname : longattrname : "");
2273 goto out;
2276 blocks = TBLOCKS(stbuf.st_size);
2278 if (put_link(name, longname, shortname, longattrname,
2279 prefix, filetype, '1') == 0) {
2280 (void) close(infile);
2281 rc = PUT_AS_LINK;
2282 goto out;
2285 tomodes(&stbuf);
2287 /* correctly handle end of volume */
2288 while (mulvol && tapepos + blocks + 1 > blocklim) {
2289 /* split if floppy has some room and file is large */
2290 if (((blocklim - tapepos) >= EXTMIN) &&
2291 ((blocks + 1) >= blocklim/10)) {
2292 splitfile(longname, infile,
2293 name, prefix, filetype);
2294 (void) close(dirfd);
2295 (void) close(infile);
2296 goto out;
2298 newvol(); /* not worth it--just get new volume */
2300 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2301 blocks);
2302 if (build_dblock(name, tchar, '0', filetype,
2303 &stbuf, stbuf.st_dev, prefix) != 0) {
2304 goto out;
2306 if (vflag) {
2307 if (NotTape) {
2308 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2310 (void) fprintf(vfile, "a %s%s%s%s ", longname,
2311 rw_sysattr ? gettext(" system") : "",
2312 (filetype == XATTR_FILE) ? gettext(
2313 " attribute ") : "",
2314 (filetype == XATTR_FILE) ?
2315 longattrname : "");
2316 if (NotTape)
2317 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2318 K(blocks));
2319 else
2320 (void) fprintf(vfile,
2321 gettext("%" FMT_blkcnt_t " tape blocks\n"),
2322 blocks);
2325 if (put_extra_attributes(longname, shortname, longattrname,
2326 prefix, filetype, '0') != 0)
2327 goto out;
2330 * No need to reset typeflag for extended attribute here, since
2331 * put_extra_attributes already set it and we haven't called
2332 * build_dblock().
2334 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2335 hint = writetbuf((char *)&dblock, 1);
2336 maxread = max(min(stbuf.st_blksize, stbuf.st_size),
2337 (nblock * TBLOCK));
2338 if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
2339 maxread = TBLOCK;
2340 bigbuf = buf;
2343 while (((i = (int)
2344 read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
2345 blocks) {
2346 blkcnt_t nblks;
2348 nblks = ((i-1)/TBLOCK)+1;
2349 if (nblks > blocks)
2350 nblks = blocks;
2351 hint = writetbuf(bigbuf, nblks);
2352 blocks -= nblks;
2354 (void) close(infile);
2355 if (bigbuf != buf)
2356 free(bigbuf);
2357 if (i < 0)
2358 vperror(0, gettext("Read error on %s"), longname);
2359 else if (blocks != 0 || i != 0) {
2360 (void) fprintf(stderr, gettext(
2361 "tar: %s: file changed size\n"), longname);
2362 if (errflag) {
2363 exitflag = 1;
2364 Errflg = 1;
2365 } else if (!Dflag) {
2366 Errflg = 1;
2369 putempty(blocks);
2370 break;
2371 case S_IFIFO:
2372 blocks = TBLOCKS(stbuf.st_size);
2373 stbuf.st_size = (off_t)0;
2375 if (put_link(name, longname, shortname, longattrname,
2376 prefix, filetype, '6') == 0) {
2377 rc = PUT_AS_LINK;
2378 goto out;
2380 tomodes(&stbuf);
2382 while (mulvol && tapepos + blocks + 1 > blocklim) {
2383 if (((blocklim - tapepos) >= EXTMIN) &&
2384 ((blocks + 1) >= blocklim/10)) {
2385 splitfile(longname, infile, name,
2386 prefix, filetype);
2387 (void) close(dirfd);
2388 (void) close(infile);
2389 goto out;
2391 newvol();
2393 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2394 blocks);
2395 if (vflag) {
2396 if (NotTape) {
2397 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2399 (void) fprintf(vfile, gettext("a %s %"
2400 FMT_blkcnt_t "K\n "), longname, K(blocks));
2401 } else {
2402 (void) fprintf(vfile, gettext(
2403 "a %s %" FMT_blkcnt_t " tape blocks\n"),
2404 longname, blocks);
2407 if (build_dblock(name, tchar, '6', filetype,
2408 &stbuf, stbuf.st_dev, prefix) != 0)
2409 goto out;
2411 if (put_extra_attributes(longname, shortname, longattrname,
2412 prefix, filetype, '6') != 0)
2413 goto out;
2415 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2416 dblock.dbuf.typeflag = '6';
2418 (void) writetbuf((char *)&dblock, 1);
2419 break;
2420 case S_IFCHR:
2421 stbuf.st_size = (off_t)0;
2422 blocks = TBLOCKS(stbuf.st_size);
2423 if (put_link(name, longname, shortname, longattrname,
2424 prefix, filetype, '3') == 0) {
2425 rc = PUT_AS_LINK;
2426 goto out;
2428 tomodes(&stbuf);
2430 while (mulvol && tapepos + blocks + 1 > blocklim) {
2431 if (((blocklim - tapepos) >= EXTMIN) &&
2432 ((blocks + 1) >= blocklim/10)) {
2433 splitfile(longname, infile, name,
2434 prefix, filetype);
2435 (void) close(dirfd);
2436 goto out;
2438 newvol();
2440 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2441 blocks);
2442 if (vflag) {
2443 if (NotTape) {
2444 dlog("seek = %" FMT_blkcnt_t "K\t", K(tapepos));
2446 (void) fprintf(vfile, gettext("a %s %"
2447 FMT_blkcnt_t "K\n"), longname, K(blocks));
2448 } else {
2449 (void) fprintf(vfile, gettext("a %s %"
2450 FMT_blkcnt_t " tape blocks\n"), longname,
2451 blocks);
2454 if (build_dblock(name, tchar, '3',
2455 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2456 goto out;
2458 if (put_extra_attributes(longname, shortname, longattrname,
2459 prefix, filetype, '3') != 0)
2460 goto out;
2462 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2463 dblock.dbuf.typeflag = '3';
2465 (void) writetbuf((char *)&dblock, 1);
2466 break;
2467 case S_IFBLK:
2468 stbuf.st_size = (off_t)0;
2469 blocks = TBLOCKS(stbuf.st_size);
2470 if (put_link(name, longname, shortname, longattrname,
2471 prefix, filetype, '4') == 0) {
2472 rc = PUT_AS_LINK;
2473 goto out;
2475 tomodes(&stbuf);
2477 while (mulvol && tapepos + blocks + 1 > blocklim) {
2478 if (((blocklim - tapepos) >= EXTMIN) &&
2479 ((blocks + 1) >= blocklim/10)) {
2480 splitfile(longname, infile,
2481 name, prefix, filetype);
2482 (void) close(dirfd);
2483 goto out;
2485 newvol();
2487 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2488 blocks);
2489 if (vflag) {
2490 if (NotTape) {
2491 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2494 (void) fprintf(vfile, "a %s ", longname);
2495 if (NotTape)
2496 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2497 K(blocks));
2498 else
2499 (void) fprintf(vfile, gettext("%"
2500 FMT_blkcnt_t " tape blocks\n"), blocks);
2502 if (build_dblock(name, tchar, '4',
2503 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2504 goto out;
2506 if (put_extra_attributes(longname, shortname, longattrname,
2507 prefix, filetype, '4') != 0)
2508 goto out;
2510 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2511 dblock.dbuf.typeflag = '4';
2513 (void) writetbuf((char *)&dblock, 1);
2514 break;
2515 default:
2516 (void) fprintf(stderr, gettext(
2517 "tar: %s is not a file. Not dumped\n"), longname);
2518 if (errflag)
2519 exitflag = 1;
2520 Errflg = 1;
2521 goto out;
2524 out:
2525 if ((dirfd != -1) && (filetype != XATTR_FILE)) {
2526 (void) close(dirfd);
2528 return (rc);
2533 * splitfile dump a large file across volumes
2535 * splitfile(longname, fd);
2536 * char *longname; full name of file
2537 * int ifd; input file descriptor
2539 * NOTE: only called by putfile() to dump a large file.
2542 static void
2543 splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
2545 blkcnt_t blocks;
2546 off_t bytes, s;
2547 char buf[TBLOCK];
2548 int i, extents;
2550 blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */
2553 * # extents =
2554 * size of file after using up rest of this floppy
2555 * blocks - (blocklim - tapepos) + 1 (for header)
2556 * plus roundup value before divide by blocklim-1
2557 * + (blocklim - 1) - 1
2558 * all divided by blocklim-1 (one block for each header).
2559 * this gives
2560 * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2561 * which reduces to the expression used.
2562 * one is added to account for this first extent.
2564 * When one is dealing with extremely large archives, one may want
2565 * to allow for a large number of extents. This code should be
2566 * revisited to determine if extents should be changed to something
2567 * larger than an int.
2569 extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
2571 if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */
2572 (void) fprintf(stderr, gettext(
2573 "tar: %s needs unusual number of volumes to split\n"
2574 "tar: %s not dumped\n"), longname, longname);
2575 return;
2577 if (build_dblock(name, tchar, '0', filetype,
2578 &stbuf, stbuf.st_dev, prefix) != 0)
2579 return;
2581 dblock.dbuf.extotal = extents;
2582 bytes = stbuf.st_size;
2585 * The value contained in dblock.dbuf.efsize was formerly used when the
2586 * v flag was specified in conjunction with the t flag. Although it is
2587 * no longer used, older versions of tar will expect the former
2588 * behaviour, so we must continue to write it to the archive.
2590 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2591 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2592 * store 0.
2594 if (bytes <= TAR_EFSIZE_MAX)
2595 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
2596 else
2597 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
2599 (void) fprintf(stderr, gettext(
2600 "tar: large file %s needs %d extents.\n"
2601 "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
2602 longname, extents, K(tapepos));
2604 s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
2605 for (i = 1; i <= extents; i++) {
2606 if (i > 1) {
2607 newvol();
2608 if (i == extents)
2609 s = bytes; /* last ext. gets true bytes */
2610 else
2611 s = (off_t)(blocklim - 1)*TBLOCK; /* all */
2613 bytes -= s;
2614 blocks = TBLOCKS(s);
2616 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
2617 dblock.dbuf.extno = i;
2618 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2619 (void) writetbuf((char *)&dblock, 1);
2621 if (vflag)
2622 (void) fprintf(vfile,
2623 gettext("+++ a %s %" FMT_blkcnt_t
2624 "K [extent #%d of %d]\n"),
2625 longname, K(blocks), i, extents);
2626 while (blocks && read(ifd, buf, TBLOCK) > 0) {
2627 blocks--;
2628 (void) writetbuf(buf, 1);
2630 if (blocks != 0) {
2631 (void) fprintf(stderr, gettext(
2632 "tar: %s: file changed size\n"), longname);
2633 (void) fprintf(stderr, gettext(
2634 "tar: aborting split file %s\n"), longname);
2635 (void) close(ifd);
2636 return;
2639 (void) close(ifd);
2640 if (vflag)
2641 (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
2642 "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
2643 extents);
2647 * convtoreg - determines whether the file should be converted to a
2648 * regular file when extracted
2650 * Returns 1 when file size > 0 and typeflag is not recognized
2651 * Otherwise returns 0
2653 static int
2654 convtoreg(off_t size)
2656 if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
2657 (dblock.dbuf.typeflag != '\0') && (dblock.dbuf.typeflag != '1') &&
2658 (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
2659 (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
2660 (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
2661 (dblock.dbuf.typeflag != 'L') &&
2662 (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
2663 (dblock.dbuf.typeflag != 'X')) {
2664 return (1);
2666 return (0);
2669 #if defined(O_XATTR)
2670 static int
2671 save_cwd(void)
2673 return (open(".", O_RDONLY));
2675 #endif
2677 #if defined(O_XATTR)
2678 static void
2679 rest_cwd(int *cwd)
2681 if (*cwd != -1) {
2682 if (fchdir(*cwd) < 0) {
2683 vperror(0, gettext(
2684 "Cannot fchdir to attribute directory"));
2685 exit(1);
2687 (void) close(*cwd);
2688 *cwd = -1;
2691 #endif
2694 * Verify the underlying file system supports the attribute type.
2695 * Only archive extended attribute files when '-@' was specified.
2696 * Only archive system extended attribute files if '-/' was specified.
2698 #if defined(O_XATTR)
2699 static attr_status_t
2700 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
2701 int *ext_attrflg)
2704 * Verify extended attributes are supported/exist. We only
2705 * need to check if we are processing a base file, not an
2706 * extended attribute.
2708 if (attrflg) {
2709 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
2710 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
2713 if (atflag) {
2714 if (!*ext_attrflg) {
2715 #if defined(_PC_SATTR_ENABLED)
2716 if (saflag) {
2717 /* Verify system attributes are supported */
2718 if (sysattr_support(filename,
2719 (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
2720 _PC_SATTR_ENABLED) != 1) {
2721 return (ATTR_SATTR_ERR);
2723 } else
2724 return (ATTR_XATTR_ERR);
2725 #else
2726 return (ATTR_XATTR_ERR);
2727 #endif /* _PC_SATTR_ENABLED */
2730 #if defined(_PC_SATTR_ENABLED)
2731 } else if (saflag) {
2732 /* Verify system attributes are supported */
2733 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
2734 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
2735 return (ATTR_SATTR_ERR);
2737 #endif /* _PC_SATTR_ENABLED */
2738 } else {
2739 return (ATTR_SKIP);
2742 return (ATTR_OK);
2744 #endif
2746 #if defined(O_XATTR)
2748 * Recursively open attribute directories until the attribute directory
2749 * containing the specified attribute, attrname, is opened.
2751 * Currently, only 2 directory levels of attributes are supported, (i.e.,
2752 * extended system attributes on extended attributes). The following are
2753 * the possible input combinations:
2754 * 1. Open the attribute directory of the base file (don't change
2755 * into it).
2756 * attrinfo->parent = NULL
2757 * attrname = '.'
2758 * 2. Open the attribute directory of the base file and change into it.
2759 * attrinfo->parent = NULL
2760 * attrname = <attr> | <sys_attr>
2761 * 3. Open the attribute directory of the base file, change into it,
2762 * then recursively call open_attr_dir() to open the attribute's
2763 * parent directory (don't change into it).
2764 * attrinfo->parent = <attr>
2765 * attrname = '.'
2766 * 4. Open the attribute directory of the base file, change into it,
2767 * then recursively call open_attr_dir() to open the attribute's
2768 * parent directory and change into it.
2769 * attrinfo->parent = <attr>
2770 * attrname = <attr> | <sys_attr>
2772 * An attribute directory will be opened only if the underlying file system
2773 * supports the attribute type, and if the command line specifications (atflag
2774 * and saflag) enable the processing of the attribute type.
2776 * On succesful return, attrinfo->parentfd will be the file descriptor of the
2777 * opened attribute directory. In addition, if the attribute is a read-write
2778 * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2779 * it will be set to 0.
2781 * Possible return values:
2782 * ATTR_OK Successfully opened and, if needed, changed into the
2783 * attribute directory containing attrname.
2784 * ATTR_SKIP The command line specifications don't enable the
2785 * processing of the attribute type.
2786 * ATTR_CHDIR_ERR An error occurred while trying to change into an
2787 * attribute directory.
2788 * ATTR_OPEN_ERR An error occurred while trying to open an
2789 * attribute directory.
2790 * ATTR_XATTR_ERR The underlying file system doesn't support extended
2791 * attributes.
2792 * ATTR_SATTR_ERR The underlying file system doesn't support extended
2793 * system attributes.
2795 static int
2796 open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
2798 attr_status_t rc;
2799 int firsttime = (attrinfo->attr_parentfd == -1);
2800 int saveerrno;
2801 int ext_attr;
2804 * open_attr_dir() was recursively called (input combination number 4),
2805 * close the previously opened file descriptor as we've already changed
2806 * into it.
2808 if (!firsttime) {
2809 (void) close(attrinfo->attr_parentfd);
2810 attrinfo->attr_parentfd = -1;
2814 * Verify that the underlying file system supports the restoration
2815 * of the attribute.
2817 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
2818 &ext_attr)) != ATTR_OK) {
2819 return (rc);
2822 /* Open the base file's attribute directory */
2823 if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
2825 * Save the errno from the attropen so it can be reported
2826 * if the retry of the attropen fails.
2828 saveerrno = errno;
2829 if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
2830 NULL, ".", O_RDONLY, 0)) == -1) {
2832 * Reset typeflag back to real value so passtape
2833 * will skip ahead correctly.
2835 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2836 (void) close(attrinfo->attr_parentfd);
2837 attrinfo->attr_parentfd = -1;
2838 errno = saveerrno;
2839 return (ATTR_OPEN_ERR);
2844 * Change into the parent attribute's directory unless we are
2845 * processing the hidden attribute directory of the base file itself.
2847 if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
2848 if (fchdir(attrinfo->attr_parentfd) != 0) {
2849 saveerrno = errno;
2850 (void) close(attrinfo->attr_parentfd);
2851 attrinfo->attr_parentfd = -1;
2852 errno = saveerrno;
2853 return (ATTR_CHDIR_ERR);
2857 /* Determine if the attribute should be processed */
2858 if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
2859 &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
2860 saveerrno = errno;
2861 (void) close(attrinfo->attr_parentfd);
2862 attrinfo->attr_parentfd = -1;
2863 errno = saveerrno;
2864 return (rc);
2868 * If the attribute is an extended attribute, or extended system
2869 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2870 * recursively call open_attr_dir() to open the attribute directory
2871 * of the parent attribute.
2873 if (firsttime && (attrinfo->attr_parent != NULL)) {
2874 return (open_attr_dir(attrname, attrinfo->attr_parent,
2875 attrinfo->attr_parentfd, attrinfo));
2878 return (ATTR_OK);
2880 #endif
2882 static void
2883 doxtract(char *argv[])
2885 struct stat xtractbuf; /* stat on file after extracting */
2886 blkcnt_t blocks;
2887 off_t bytes;
2888 int ofile;
2889 int newfile; /* Does the file already exist */
2890 int xcnt = 0; /* count # files extracted */
2891 int fcnt = 0; /* count # files in argv list */
2892 int dir;
2893 int dirfd = -1;
2894 int cwd = -1;
2895 int rw_sysattr;
2896 int saveerrno;
2897 uid_t Uid;
2898 char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
2899 char dirname[PATH_MAX+1];
2900 char templink[PATH_MAX+1]; /* temp link with terminating NULL */
2901 int once = 1;
2902 int error;
2903 int symflag;
2904 int want;
2905 attr_data_t *attrinfo = NULL; /* attribute info */
2906 acl_t *aclp = NULL; /* acl info */
2907 timestruc_t time_zero; /* used for call to doDirTimes */
2908 int dircreate;
2909 int convflag;
2910 time_zero.tv_sec = 0;
2911 time_zero.tv_nsec = 0;
2913 dumping = 0; /* for newvol(), et al: we are not writing */
2915 Uid = getuid();
2917 for (;;) {
2918 convflag = 0;
2919 symflag = 0;
2920 dir = 0;
2921 Hiddendir = 0;
2922 rw_sysattr = 0;
2923 ofile = -1;
2925 if (dirfd != -1) {
2926 (void) close(dirfd);
2927 dirfd = -1;
2929 if (ofile != -1) {
2930 if (close(ofile) != 0)
2931 vperror(2, gettext("close error"));
2934 #if defined(O_XATTR)
2935 if (cwd != -1) {
2936 rest_cwd(&cwd);
2938 #endif
2940 /* namep is set by wantit to point to the full name */
2941 if ((want = wantit(argv, &namep, &dirp, &comp,
2942 &attrinfo)) == 0) {
2943 #if defined(O_XATTR)
2944 if (xattrp != NULL) {
2945 free(xattrhead);
2946 xattrp = NULL;
2947 xattr_linkp = NULL;
2948 xattrhead = NULL;
2950 #endif
2951 continue;
2953 if (want == -1)
2954 break;
2956 if (dirfd != -1)
2957 (void) close(dirfd);
2959 (void) strcpy(&dirname[0], namep);
2960 dircreate = checkdir(&dirname[0]);
2962 #if defined(O_XATTR)
2963 if (xattrp != NULL) {
2964 int rc;
2966 if (((cwd = save_cwd()) == -1) ||
2967 ((rc = open_attr_dir(comp, dirp, cwd,
2968 attrinfo)) != ATTR_OK)) {
2969 if (cwd == -1) {
2970 vperror(0, gettext(
2971 "unable to save current working "
2972 "directory while processing "
2973 "attribute %s of %s"),
2974 dirp, attrinfo->attr_path);
2975 } else if (rc != ATTR_SKIP) {
2976 (void) fprintf(vfile,
2977 gettext("tar: cannot open "
2978 "%sattribute %s of file %s: %s\n"),
2979 attrinfo->attr_rw_sysattr ? gettext(
2980 "system ") : "",
2981 comp, dirp, strerror(errno));
2983 free(xattrhead);
2984 xattrp = NULL;
2985 xattr_linkp = NULL;
2986 xattrhead = NULL;
2988 passtape();
2989 continue;
2990 } else {
2991 dirfd = attrinfo->attr_parentfd;
2992 rw_sysattr = attrinfo->attr_rw_sysattr;
2994 } else {
2995 dirfd = open(dirp, O_RDONLY);
2997 #else
2998 dirfd = open(dirp, O_RDONLY);
2999 #endif
3000 if (dirfd == -1) {
3001 (void) fprintf(vfile, gettext(
3002 "tar: cannot open %s: %s\n"),
3003 dirp, strerror(errno));
3004 passtape();
3005 continue;
3008 if (xhdr_flgs & _X_LINKPATH)
3009 (void) strcpy(templink, Xtarhdr.x_linkpath);
3010 else {
3011 #if defined(O_XATTR)
3012 if (xattrp && dblock.dbuf.typeflag == '1') {
3013 (void) sprintf(templink, "%.*s", NAMSIZ,
3014 xattrp->h_names);
3015 } else {
3016 (void) sprintf(templink, "%.*s", NAMSIZ,
3017 dblock.dbuf.linkname);
3019 #else
3020 (void) sprintf(templink, "%.*s", NAMSIZ,
3021 dblock.dbuf.linkname);
3022 #endif
3025 if (Fflag) {
3026 if (checkf(namep, is_directory(namep), Fflag) == 0) {
3027 passtape();
3028 continue;
3032 if (checkw('x', namep) == 0) {
3033 passtape();
3034 continue;
3036 if (once) {
3037 if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
3038 if (geteuid() == (uid_t)0) {
3039 checkflag = 1;
3040 pflag = 1;
3041 } else {
3042 /* get file creation mask */
3043 Oumask = umask(0);
3044 (void) umask(Oumask);
3046 once = 0;
3047 } else {
3048 if (geteuid() == (uid_t)0) {
3049 pflag = 1;
3050 checkflag = 2;
3052 if (!pflag) {
3053 /* get file creation mask */
3054 Oumask = umask(0);
3055 (void) umask(Oumask);
3057 once = 0;
3061 #if defined(O_XATTR)
3063 * Handle extraction of hidden attr dir.
3064 * Dir is automatically created, we only
3065 * need to update mode and perm's.
3067 if ((xattrp != NULL) && Hiddendir == 1) {
3068 bytes = stbuf.st_size;
3069 blocks = TBLOCKS(bytes);
3070 if (vflag) {
3071 (void) fprintf(vfile,
3072 "x %s%s%s, %" FMT_off_t " %s, ", namep,
3073 gettext(" attribute "),
3074 xattrapath, bytes,
3075 gettext("bytes"));
3076 if (NotTape)
3077 (void) fprintf(vfile,
3078 "%" FMT_blkcnt_t "K\n", K(blocks));
3079 else
3080 (void) fprintf(vfile, gettext("%"
3081 FMT_blkcnt_t " tape blocks\n"),
3082 blocks);
3086 * Set the permissions and mode of the attribute
3087 * unless the attribute is a system attribute (can't
3088 * successfully do this) or the hidden attribute
3089 * directory (".") of an attribute (when the attribute
3090 * is restored, the hidden attribute directory of an
3091 * attribute is transient). Note: when the permissions
3092 * and mode are set for the hidden attribute directory
3093 * of a file on a system supporting extended system
3094 * attributes, even though it returns successfully, it
3095 * will not have any affect since the attribute
3096 * directory is transient.
3098 if (attrinfo->attr_parent == NULL) {
3099 if (fchownat(dirfd, ".", stbuf.st_uid,
3100 stbuf.st_gid, 0) != 0) {
3101 vperror(0, gettext(
3102 "%s%s%s: failed to set ownership "
3103 "of attribute directory"), namep,
3104 gettext(" attribute "), xattrapath);
3107 if (fchmod(dirfd, stbuf.st_mode) != 0) {
3108 vperror(0, gettext(
3109 "%s%s%s: failed to set permissions "
3110 "of attribute directory"), namep,
3111 gettext(" attribute "), xattrapath);
3114 goto filedone;
3116 #endif
3118 if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
3119 dir = 1;
3120 if (vflag) {
3121 (void) fprintf(vfile, "x %s, 0 %s, ",
3122 &dirname[0], gettext("bytes"));
3123 if (NotTape)
3124 (void) fprintf(vfile, "0K\n");
3125 else
3126 (void) fprintf(vfile, gettext("%"
3127 FMT_blkcnt_t " tape blocks\n"),
3128 (blkcnt_t)0);
3130 goto filedone;
3133 if (dblock.dbuf.typeflag == '6') { /* FIFO */
3134 if (rmdir(namep) < 0) {
3135 if (errno == ENOTDIR)
3136 (void) unlink(namep);
3138 linkp = templink;
3139 if (*linkp != '\0') {
3140 if (Aflag && *linkp == '/')
3141 linkp++;
3142 if (link(linkp, namep) < 0) {
3143 (void) fprintf(stderr, gettext(
3144 "tar: %s: cannot link\n"), namep);
3145 continue;
3147 if (vflag)
3148 (void) fprintf(vfile, gettext(
3149 "x %s linked to %s\n"), namep,
3150 linkp);
3151 xcnt++; /* increment # files extracted */
3152 continue;
3154 if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
3155 (int)Gen.g_devmajor) < 0) {
3156 vperror(0, gettext("%s: mknod failed"), namep);
3157 continue;
3159 bytes = stbuf.st_size;
3160 blocks = TBLOCKS(bytes);
3161 if (vflag) {
3162 (void) fprintf(vfile, "x %s, %" FMT_off_t
3163 " %s, ", namep, bytes, gettext("bytes"));
3164 if (NotTape)
3165 (void) fprintf(vfile, "%" FMT_blkcnt_t
3166 "K\n", K(blocks));
3167 else
3168 (void) fprintf(vfile, gettext("%"
3169 FMT_blkcnt_t " tape blocks\n"),
3170 blocks);
3172 goto filedone;
3174 if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
3175 if (rmdir(namep) < 0) {
3176 if (errno == ENOTDIR)
3177 (void) unlink(namep);
3179 linkp = templink;
3180 if (*linkp != '\0') {
3181 if (Aflag && *linkp == '/')
3182 linkp++;
3183 if (link(linkp, namep) < 0) {
3184 (void) fprintf(stderr, gettext(
3185 "tar: %s: cannot link\n"), namep);
3186 continue;
3188 if (vflag)
3189 (void) fprintf(vfile, gettext(
3190 "x %s linked to %s\n"), namep,
3191 linkp);
3192 xcnt++; /* increment # files extracted */
3193 continue;
3195 if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
3196 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3197 vperror(0, gettext(
3198 "%s: mknod failed"), namep);
3199 continue;
3201 bytes = stbuf.st_size;
3202 blocks = TBLOCKS(bytes);
3203 if (vflag) {
3204 (void) fprintf(vfile, "x %s, %" FMT_off_t
3205 " %s, ", namep, bytes, gettext("bytes"));
3206 if (NotTape)
3207 (void) fprintf(vfile, "%" FMT_blkcnt_t
3208 "K\n", K(blocks));
3209 else
3210 (void) fprintf(vfile, gettext("%"
3211 FMT_blkcnt_t " tape blocks\n"),
3212 blocks);
3214 goto filedone;
3215 } else if (dblock.dbuf.typeflag == '3' && Uid) {
3216 (void) fprintf(stderr, gettext(
3217 "Can't create special %s\n"), namep);
3218 continue;
3221 /* BLOCK SPECIAL */
3223 if (dblock.dbuf.typeflag == '4' && !Uid) {
3224 if (rmdir(namep) < 0) {
3225 if (errno == ENOTDIR)
3226 (void) unlink(namep);
3228 linkp = templink;
3229 if (*linkp != '\0') {
3230 if (Aflag && *linkp == '/')
3231 linkp++;
3232 if (link(linkp, namep) < 0) {
3233 (void) fprintf(stderr, gettext(
3234 "tar: %s: cannot link\n"), namep);
3235 continue;
3237 if (vflag)
3238 (void) fprintf(vfile, gettext(
3239 "x %s linked to %s\n"), namep,
3240 linkp);
3241 xcnt++; /* increment # files extracted */
3242 continue;
3244 if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
3245 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3246 vperror(0, gettext("%s: mknod failed"), namep);
3247 continue;
3249 bytes = stbuf.st_size;
3250 blocks = TBLOCKS(bytes);
3251 if (vflag) {
3252 (void) fprintf(vfile, gettext("x %s, %"
3253 FMT_off_t " bytes, "), namep, bytes);
3254 if (NotTape)
3255 (void) fprintf(vfile, "%" FMT_blkcnt_t
3256 "K\n", K(blocks));
3257 else
3258 (void) fprintf(vfile, gettext("%"
3259 FMT_blkcnt_t " tape blocks\n"),
3260 blocks);
3262 goto filedone;
3263 } else if (dblock.dbuf.typeflag == '4' && Uid) {
3264 (void) fprintf(stderr,
3265 gettext("Can't create special %s\n"), namep);
3266 continue;
3268 if (dblock.dbuf.typeflag == '2') { /* symlink */
3269 linkp = templink;
3270 if (Aflag && *linkp == '/')
3271 linkp++;
3272 if (rmdir(namep) < 0) {
3273 if (errno == ENOTDIR)
3274 (void) unlink(namep);
3276 if (symlink(linkp, namep) < 0) {
3277 vperror(0, gettext("%s: symbolic link failed"),
3278 namep);
3279 continue;
3281 if (vflag)
3282 (void) fprintf(vfile, gettext(
3283 "x %s symbolic link to %s\n"),
3284 namep, linkp);
3286 symflag = AT_SYMLINK_NOFOLLOW;
3287 goto filedone;
3289 if (dblock.dbuf.typeflag == '1') {
3290 linkp = templink;
3291 if (Aflag && *linkp == '/')
3292 linkp++;
3293 if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
3294 if (errno == ENOTDIR)
3295 (void) unlinkat(dirfd, comp, 0);
3297 #if defined(O_XATTR)
3298 if (xattrp && xattr_linkp) {
3299 if (fchdir(dirfd) < 0) {
3300 vperror(0, gettext(
3301 "Cannot fchdir to attribute "
3302 "directory %s"),
3303 (attrinfo->attr_parent == NULL) ?
3304 dirp : attrinfo->attr_parent);
3305 exit(1);
3308 error = link(xattr_linkaname, xattrapath);
3309 } else {
3310 error = link(linkp, namep);
3312 #else
3313 error = link(linkp, namep);
3314 #endif
3316 if (error < 0) {
3317 (void) fprintf(stderr, gettext(
3318 "tar: %s%s%s: cannot link\n"),
3319 namep, (xattr_linkp != NULL) ?
3320 gettext(" attribute ") : "",
3321 (xattr_linkp != NULL) ?
3322 xattrapath : "");
3323 continue;
3325 if (vflag)
3326 (void) fprintf(vfile, gettext(
3327 "x %s%s%s linked to %s%s%s\n"), namep,
3328 (xattr_linkp != NULL) ?
3329 gettext(" attribute ") : "",
3330 (xattr_linkp != NULL) ?
3331 xattr_linkaname : "",
3332 linkp,
3333 (xattr_linkp != NULL) ?
3334 gettext(" attribute ") : "",
3335 (xattr_linkp != NULL) ? xattrapath : "");
3336 xcnt++; /* increment # files extracted */
3337 #if defined(O_XATTR)
3338 if (xattrp != NULL) {
3339 free(xattrhead);
3340 xattrp = NULL;
3341 xattr_linkp = NULL;
3342 xattrhead = NULL;
3344 #endif
3345 continue;
3348 /* REGULAR FILES */
3350 if (convtoreg(stbuf.st_size)) {
3351 convflag = 1;
3352 if (errflag) {
3353 (void) fprintf(stderr, gettext(
3354 "tar: %s: typeflag '%c' not recognized\n"),
3355 namep, dblock.dbuf.typeflag);
3356 done(1);
3357 } else {
3358 (void) fprintf(stderr, gettext(
3359 "tar: %s: typeflag '%c' not recognized, "
3360 "converting to regular file\n"), namep,
3361 dblock.dbuf.typeflag);
3362 Errflg = 1;
3365 if (dblock.dbuf.typeflag == '0' ||
3366 dblock.dbuf.typeflag == '\0' || convflag) {
3367 delete_target(dirfd, comp, namep);
3368 linkp = templink;
3369 if (*linkp != '\0') {
3370 if (Aflag && *linkp == '/')
3371 linkp++;
3372 if (link(linkp, comp) < 0) {
3373 (void) fprintf(stderr, gettext(
3374 "tar: %s: cannot link\n"), namep);
3375 continue;
3377 if (vflag)
3378 (void) fprintf(vfile, gettext(
3379 "x %s linked to %s\n"), comp,
3380 linkp);
3381 xcnt++; /* increment # files extracted */
3382 #if defined(O_XATTR)
3383 if (xattrp != NULL) {
3384 free(xattrhead);
3385 xattrp = NULL;
3386 xattr_linkp = NULL;
3387 xattrhead = NULL;
3389 #endif
3390 continue;
3392 newfile = ((fstatat(dirfd, comp,
3393 &xtractbuf, 0) == -1) ? TRUE : FALSE);
3394 ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
3395 stbuf.st_mode & MODEMASK);
3396 saveerrno = errno;
3398 #if defined(O_XATTR)
3399 if (xattrp != NULL) {
3400 if (ofile < 0) {
3401 ofile = retry_open_attr(dirfd, cwd,
3402 dirp, attrinfo->attr_parent, comp,
3403 O_RDWR|O_CREAT|O_TRUNC,
3404 stbuf.st_mode & MODEMASK);
3407 #endif
3408 if (ofile < 0) {
3409 errno = saveerrno;
3410 (void) fprintf(stderr, gettext(
3411 "tar: %s%s%s%s - cannot create\n"),
3412 (xattrp == NULL) ? "" : (rw_sysattr ?
3413 gettext("system attribute ") :
3414 gettext("attribute ")),
3415 (xattrp == NULL) ? "" : xattrapath,
3416 (xattrp == NULL) ? "" : gettext(" of "),
3417 (xattrp == NULL) ? comp : namep);
3418 if (errflag)
3419 done(1);
3420 else
3421 Errflg = 1;
3422 #if defined(O_XATTR)
3423 if (xattrp != NULL) {
3424 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
3425 free(xattrhead);
3426 xattrp = NULL;
3427 xattr_linkp = NULL;
3428 xattrhead = NULL;
3430 #endif
3431 passtape();
3432 continue;
3435 if (extno != 0) { /* file is in pieces */
3436 if (extotal < 1 || extotal > MAXEXT)
3437 (void) fprintf(stderr, gettext(
3438 "tar: ignoring bad extent info for "
3439 "%s%s%s%s\n"),
3440 (xattrp == NULL) ? "" : (rw_sysattr ?
3441 gettext("system attribute ") :
3442 gettext("attribute ")),
3443 (xattrp == NULL) ? "" : xattrapath,
3444 (xattrp == NULL) ? "" : gettext(" of "),
3445 (xattrp == NULL) ? comp : namep);
3446 else {
3447 /* extract it */
3448 (void) xsfile(rw_sysattr, ofile);
3451 extno = 0; /* let everyone know file is not split */
3452 bytes = stbuf.st_size;
3453 blocks = TBLOCKS(bytes);
3454 if (vflag) {
3455 (void) fprintf(vfile,
3456 "x %s%s%s, %" FMT_off_t " %s, ",
3457 (xattrp == NULL) ? "" : dirp,
3458 (xattrp == NULL) ? "" : (rw_sysattr ?
3459 gettext(" system attribute ") :
3460 gettext(" attribute ")),
3461 (xattrp == NULL) ? namep : xattrapath, bytes,
3462 gettext("bytes"));
3463 if (NotTape)
3464 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
3465 K(blocks));
3466 else
3467 (void) fprintf(vfile, gettext("%"
3468 FMT_blkcnt_t " tape blocks\n"), blocks);
3471 if (xblocks(rw_sysattr, bytes, ofile) != 0) {
3472 #if defined(O_XATTR)
3473 if (xattrp != NULL) {
3474 free(xattrhead);
3475 xattrp = NULL;
3476 xattr_linkp = NULL;
3477 xattrhead = NULL;
3479 #endif
3480 continue;
3482 filedone:
3483 if (mflag == 0 && !symflag) {
3484 if (dir)
3485 doDirTimes(namep, stbuf.st_mtim);
3487 else
3488 #if defined(O_XATTR)
3489 if (xattrp != NULL) {
3491 * Set the time on the attribute unless
3492 * the attribute is a system attribute
3493 * (can't successfully do this) or the
3494 * hidden attribute directory, "." (the
3495 * time on the hidden attribute
3496 * directory will be updated when
3497 * attributes are restored, otherwise
3498 * it's transient).
3500 if (!rw_sysattr && (Hiddendir == 0)) {
3501 setPathTimes(dirfd, comp,
3502 stbuf.st_mtim);
3504 } else
3505 setPathTimes(dirfd, comp,
3506 stbuf.st_mtim);
3507 #else
3508 setPathTimes(dirfd, comp, stbuf.st_mtim);
3509 #endif
3512 /* moved this code from above */
3513 if (pflag && !symflag && Hiddendir == 0) {
3514 if (xattrp != NULL)
3515 (void) fchmod(ofile, stbuf.st_mode & MODEMASK);
3516 else
3517 (void) chmod(namep, stbuf.st_mode & MODEMASK);
3522 * Because ancillary file preceeds the normal file,
3523 * acl info may have been retrieved (in aclp).
3524 * All file types are directed here (go filedone).
3525 * Always restore ACLs if there are ACLs.
3527 if (aclp != NULL) {
3528 int ret;
3530 #if defined(O_XATTR)
3531 if (xattrp != NULL) {
3532 if (Hiddendir)
3533 ret = facl_set(dirfd, aclp);
3534 else
3535 ret = facl_set(ofile, aclp);
3536 } else {
3537 ret = acl_set(namep, aclp);
3539 #else
3540 ret = acl_set(namep, aclp);
3541 #endif
3542 if (ret < 0) {
3543 if (pflag) {
3544 (void) fprintf(stderr, gettext(
3545 "%s%s%s%s: failed to set acl "
3546 "entries\n"), namep,
3547 (xattrp == NULL) ? "" :
3548 (rw_sysattr ? gettext(
3549 " system attribute ") :
3550 gettext(" attribute ")),
3551 (xattrp == NULL) ? "" :
3552 xattrapath);
3554 /* else: silent and continue */
3556 acl_free(aclp);
3557 aclp = NULL;
3560 if (!oflag)
3561 /* set file ownership */
3562 resugname(dirfd, comp, symflag);
3564 if (pflag && newfile == TRUE && !dir &&
3565 (dblock.dbuf.typeflag == '0' ||
3566 dblock.dbuf.typeflag == '\0' ||
3567 convflag || dblock.dbuf.typeflag == '1')) {
3568 if (fstat(ofile, &xtractbuf) == -1)
3569 (void) fprintf(stderr, gettext(
3570 "tar: cannot stat extracted file "
3571 "%s%s%s%s\n"),
3572 (xattrp == NULL) ? "" : (rw_sysattr ?
3573 gettext("system attribute ") :
3574 gettext("attribute ")),
3575 (xattrp == NULL) ? "" : xattrapath,
3576 (xattrp == NULL) ? "" :
3577 gettext(" of "), namep);
3579 else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
3580 != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
3581 (void) fprintf(stderr, gettext(
3582 "tar: warning - file permissions have "
3583 "changed for %s%s%s%s (are 0%o, should be "
3584 "0%o)\n"),
3585 (xattrp == NULL) ? "" : (rw_sysattr ?
3586 gettext("system attribute ") :
3587 gettext("attribute ")),
3588 (xattrp == NULL) ? "" : xattrapath,
3589 (xattrp == NULL) ? "" :
3590 gettext(" of "), namep,
3591 xtractbuf.st_mode, stbuf.st_mode);
3595 #if defined(O_XATTR)
3596 if (xattrp != NULL) {
3597 free(xattrhead);
3598 xattrp = NULL;
3599 xattr_linkp = NULL;
3600 xattrhead = NULL;
3602 #endif
3604 if (ofile != -1) {
3605 (void) close(dirfd);
3606 dirfd = -1;
3607 if (close(ofile) != 0)
3608 vperror(2, gettext("close error"));
3609 ofile = -1;
3611 xcnt++; /* increment # files extracted */
3615 * Process ancillary file.
3619 if (dblock.dbuf.typeflag == 'A') { /* acl info */
3620 char buf[TBLOCK];
3621 char *secp;
3622 char *tp;
3623 int attrsize;
3624 int cnt;
3626 if (pflag) {
3627 bytes = stbuf.st_size;
3628 if ((secp = malloc((int)bytes)) == NULL) {
3629 (void) fprintf(stderr, gettext(
3630 "Insufficient memory for acl\n"));
3631 passtape();
3632 continue;
3634 tp = secp;
3635 blocks = TBLOCKS(bytes);
3637 while (blocks-- > 0) {
3638 readtape(buf);
3639 if (bytes <= TBLOCK) {
3640 (void) memcpy(tp, buf,
3641 (size_t)bytes);
3642 break;
3643 } else {
3644 (void) memcpy(tp, buf,
3645 TBLOCK);
3646 tp += TBLOCK;
3648 bytes -= TBLOCK;
3650 bytes = stbuf.st_size;
3651 /* got all attributes in secp */
3652 tp = secp;
3653 do {
3654 attr = (struct sec_attr *)tp;
3655 switch (attr->attr_type) {
3656 case UFSD_ACL:
3657 case ACE_ACL:
3658 (void) sscanf(attr->attr_len,
3659 "%7o",
3660 (uint_t *)
3661 &cnt);
3662 /* header is 8 */
3663 attrsize = 8 + (int)strlen(
3664 &attr->attr_info[0]) + 1;
3665 error =
3666 acl_fromtext(
3667 &attr->attr_info[0], &aclp);
3669 if (error != 0) {
3670 (void) fprintf(stderr,
3671 gettext(
3672 "aclfromtext "
3673 "failed: %s\n"),
3674 acl_strerror(
3675 error));
3676 bytes -= attrsize;
3677 break;
3679 if (acl_cnt(aclp) != cnt) {
3680 (void) fprintf(stderr,
3681 gettext(
3682 "aclcnt error\n"));
3683 bytes -= attrsize;
3684 break;
3686 bytes -= attrsize;
3687 break;
3689 default:
3690 (void) fprintf(stderr, gettext(
3691 "unrecognized attr"
3692 " type\n"));
3693 bytes = (off_t)0;
3694 break;
3697 /* next attributes */
3698 tp += attrsize;
3699 } while (bytes != 0);
3700 free(secp);
3701 } else {
3702 passtape();
3704 } /* acl */
3706 } /* for */
3709 * Ensure that all the directories still on the directory stack
3710 * get their modification times set correctly by flushing the
3711 * stack.
3714 doDirTimes(NULL, time_zero);
3716 #if defined(O_XATTR)
3717 if (xattrp != NULL) {
3718 free(xattrhead);
3719 xattrp = NULL;
3720 xattr_linkp = NULL;
3721 xattrhead = NULL;
3723 #endif
3726 * Check if the number of files extracted is different from the
3727 * number of files listed on the command line
3729 if (fcnt > xcnt) {
3730 (void) fprintf(stderr,
3731 gettext("tar: %d file(s) not extracted\n"),
3732 fcnt-xcnt);
3733 Errflg = 1;
3738 * xblocks extract file/extent from tape to output file
3740 * xblocks(issysattr, bytes, ofile);
3742 * issysattr flag set if the files being extracted
3743 * is an extended system attribute file.
3744 * unsigned long long bytes size of extent or file to be extracted
3745 * ofile output file
3747 * called by doxtract() and xsfile()
3750 static int
3751 xblocks(int issysattr, off_t bytes, int ofile)
3753 char *buf;
3754 char tempname[NAMSIZ+1];
3755 size_t maxwrite;
3756 size_t bytesread;
3757 size_t piosize; /* preferred I/O size */
3758 struct stat tsbuf;
3760 /* Don't need to do anything if this is a zero size file */
3761 if (bytes <= 0) {
3762 return (0);
3766 * To figure out the size of the buffer used to accumulate data
3767 * from readtape() and to write to the file, we need to determine
3768 * the largest chunk of data to be written to the file at one time.
3769 * This is determined based on the smallest of the following two
3770 * things:
3771 * 1) The size of the archived file.
3772 * 2) The preferred I/O size of the file.
3774 if (issysattr || (bytes <= TBLOCK)) {
3776 * Writes to system attribute files must be
3777 * performed in one operation.
3779 maxwrite = bytes;
3780 } else {
3782 * fstat() the file to get the preferred I/O size.
3783 * If it fails, then resort back to just writing
3784 * one block at a time.
3786 if (fstat(ofile, &tsbuf) == 0) {
3787 piosize = tsbuf.st_blksize;
3788 } else {
3789 piosize = TBLOCK;
3791 maxwrite = min(bytes, piosize);
3795 * The buffer used to accumulate the data for the write operation
3796 * needs to be the maximum number of bytes to be written rounded up
3797 * to the nearest TBLOCK since readtape reads one block at a time.
3799 if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
3800 fatal(gettext("cannot allocate buffer"));
3803 while (bytes > 0) {
3806 * readtape() obtains one block (TBLOCK) of data at a time.
3807 * Accumulate as many blocks of data in buf as we can write
3808 * in one operation.
3810 for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
3811 readtape(buf + bytesread);
3814 if (write(ofile, buf, maxwrite) < 0) {
3815 int saveerrno = errno;
3817 if (xhdr_flgs & _X_PATH)
3818 (void) strlcpy(tempname, Xtarhdr.x_path,
3819 sizeof (tempname));
3820 else
3821 (void) sprintf(tempname, "%.*s", NAMSIZ,
3822 dblock.dbuf.name);
3824 * If the extended system attribute being extracted
3825 * contains attributes that the user needs privileges
3826 * for, then just display a warning message, skip
3827 * the extraction of this file, and return.
3829 if ((saveerrno == EPERM) && issysattr) {
3830 (void) fprintf(stderr, gettext(
3831 "tar: unable to extract system attribute "
3832 "%s: insufficient privileges\n"), tempname);
3833 Errflg = 1;
3834 (void) free(buf);
3835 return (1);
3836 } else {
3837 warnc(saveerrno, "extracting %s", tempname);
3838 done(2);
3841 bytes -= maxwrite;
3844 * If we've reached this point and there is still data
3845 * to be written, maxwrite had to have been determined
3846 * by the preferred I/O size. If the number of bytes
3847 * left to write is smaller than the preferred I/O size,
3848 * then we're about to do our final write to the file, so
3849 * just set maxwrite to the number of bytes left to write.
3851 if ((bytes > 0) && (bytes < maxwrite)) {
3852 maxwrite = bytes;
3855 free(buf);
3857 return (0);
3861 * xsfile extract split file
3863 * xsfile(ofd); ofd = output file descriptor
3865 * file extracted and put in ofd via xblocks()
3867 * NOTE: only called by doxtract() to extract one large file
3870 static union hblock savedblock; /* to ensure same file across volumes */
3872 static int
3873 xsfile(int issysattr, int ofd)
3875 int i, c;
3876 int sysattrerr = 0;
3877 char name[PATH_MAX+1]; /* holds name for diagnostics */
3878 int extents, totalext;
3879 off_t bytes, totalbytes;
3881 if (xhdr_flgs & _X_PATH)
3882 (void) strcpy(name, Xtarhdr.x_path);
3883 else
3884 (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
3886 totalbytes = (off_t)0; /* in case we read in half the file */
3887 totalext = 0; /* these keep count */
3889 (void) fprintf(stderr, gettext(
3890 "tar: %s split across %d volumes\n"), name, extotal);
3892 /* make sure we do extractions in order */
3893 if (extno != 1) { /* starting in middle of file? */
3894 (void) printf(gettext(
3895 "tar: first extent read is not #1\n"
3896 "OK to read file beginning with extent #%d? "),
3897 extno);
3898 if (yes() == 0) {
3899 canit:
3900 passtape();
3901 if (close(ofd) != 0)
3902 vperror(2, gettext("close error"));
3903 if (sysattrerr) {
3904 return (1);
3905 } else {
3906 return (0);
3910 extents = extotal;
3911 i = extno;
3912 /*CONSTCOND*/
3913 while (1) {
3914 if (xhdr_flgs & _X_SIZE) {
3915 bytes = extsize;
3916 } else {
3917 bytes = stbuf.st_size;
3920 if (vflag)
3921 (void) fprintf(vfile, "+++ x %s [%s #%d], %"
3922 FMT_off_t " %s, %ldK\n",
3923 name, gettext("extent"), extno,
3924 bytes, gettext("bytes"),
3925 (long)K(TBLOCKS(bytes)));
3926 if (xblocks(issysattr, bytes, ofd) != 0) {
3927 sysattrerr = 1;
3928 goto canit;
3931 totalbytes += bytes;
3932 totalext++;
3933 if (++i > extents)
3934 break;
3936 /* get next volume and verify it's the right one */
3937 copy(&savedblock, &dblock);
3938 tryagain:
3939 newvol();
3940 xhdr_flgs = 0;
3941 getdir();
3942 if (Xhdrflag > 0)
3943 (void) get_xdata(); /* Get x-header & regular hdr */
3944 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
3945 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
3946 xhdr_flgs |= _X_XHDR;
3948 if (endtape()) { /* seemingly empty volume */
3949 (void) fprintf(stderr, gettext(
3950 "tar: first record is null\n"));
3951 asknicely:
3952 (void) fprintf(stderr, gettext(
3953 "tar: need volume with extent #%d of %s\n"),
3954 i, name);
3955 goto tryagain;
3957 if (notsame()) {
3958 (void) fprintf(stderr, gettext(
3959 "tar: first file on that volume is not "
3960 "the same file\n"));
3961 goto asknicely;
3963 if (i != extno) {
3964 (void) fprintf(stderr, gettext(
3965 "tar: extent #%d received out of order\ntar: "
3966 "should be #%d\n"), extno, i);
3967 (void) fprintf(stderr, gettext(
3968 "Ignore error, Abort this file, or "
3969 "load New volume (i/a/n) ? "));
3970 c = response();
3971 if (c == 'a')
3972 goto canit;
3973 if (c != 'i') /* default to new volume */
3974 goto asknicely;
3975 i = extno; /* okay, start from there */
3978 if (vflag)
3979 (void) fprintf(vfile, gettext(
3980 "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
3981 name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
3983 return (0);
3988 * notsame() check if extract file extent is invalid
3990 * returns true if anything differs between savedblock and dblock
3991 * except extno (extent number), checksum, or size (extent size).
3992 * Determines if this header belongs to the same file as the one we're
3993 * extracting.
3995 * NOTE: though rather bulky, it is only called once per file
3996 * extension, and it can withstand changes in the definition
3997 * of the header structure.
3999 * WARNING: this routine is local to xsfile() above
4002 static int
4003 notsame(void)
4005 return (
4006 (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
4007 (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
4008 (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
4009 (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
4010 (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
4011 (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
4012 (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
4013 (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
4014 (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
4017 static void
4018 dotable(char *argv[])
4020 int tcnt = 0; /* count # files tabled */
4021 int fcnt = 0; /* count # files in argv list */
4022 char *namep, *dirp, *comp;
4023 int want;
4024 char aclchar = ' '; /* either blank or '+' */
4025 char templink[PATH_MAX+1];
4026 attr_data_t *attrinfo = NULL;
4028 dumping = 0;
4030 /* if not on magtape, maximize seek speed */
4031 if (NotTape && !bflag) {
4032 #if SYS_BLOCK > TBLOCK
4033 nblock = SYS_BLOCK / TBLOCK;
4034 #else
4035 nblock = 1;
4036 #endif
4039 for (;;) {
4041 /* namep is set by wantit to point to the full name */
4042 if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
4043 continue;
4044 if (want == -1)
4045 break;
4046 if (dblock.dbuf.typeflag != 'A')
4047 ++tcnt;
4049 if (Fflag) {
4050 if (checkf(namep, is_directory(namep), Fflag) == 0) {
4051 passtape();
4052 continue;
4056 * ACL support:
4057 * aclchar is introduced to indicate if there are
4058 * acl entries. longt() now takes one extra argument.
4060 if (vflag) {
4061 if (dblock.dbuf.typeflag == 'A') {
4062 aclchar = '+';
4063 passtape();
4064 continue;
4066 longt(&stbuf, aclchar);
4067 aclchar = ' ';
4071 #if defined(O_XATTR)
4072 if (xattrp != NULL) {
4073 int issysattr;
4074 char *bn = basename(attrinfo->attr_path);
4077 * We could use sysattr_type() to test whether or not
4078 * the attribute we are processing is really an
4079 * extended system attribute, which as of this writing
4080 * just does a strcmp(), however, sysattr_type() may
4081 * be changed to issue a pathconf() call instead, which
4082 * would require being changed into the parent attribute
4083 * directory. So instead, just do simple string
4084 * comparisons to see if we are processing an extended
4085 * system attribute.
4087 issysattr = is_sysattr(bn);
4089 (void) printf(gettext("%s %sattribute %s"),
4090 xattrp->h_names,
4091 issysattr ? gettext("system ") : "",
4092 attrinfo->attr_path);
4093 } else {
4094 (void) printf("%s", namep);
4096 #else
4097 (void) printf("%s", namep);
4098 #endif
4100 if (extno != 0) {
4101 if (vflag) {
4102 /* keep the '\n' for backwards compatibility */
4103 (void) fprintf(vfile, gettext(
4104 "\n [extent #%d of %d]"), extno, extotal);
4105 } else {
4106 (void) fprintf(vfile, gettext(
4107 " [extent #%d of %d]"), extno, extotal);
4110 if (xhdr_flgs & _X_LINKPATH) {
4111 (void) strcpy(templink, Xtarhdr.x_linkpath);
4112 } else {
4113 #if defined(O_XATTR)
4114 if (xattrp != NULL) {
4115 (void) sprintf(templink,
4116 "file %.*s", NAMSIZ, xattrp->h_names);
4117 } else {
4118 (void) sprintf(templink, "%.*s", NAMSIZ,
4119 dblock.dbuf.linkname);
4121 #else
4122 (void) sprintf(templink, "%.*s", NAMSIZ,
4123 dblock.dbuf.linkname);
4124 #endif
4125 templink[NAMSIZ] = '\0';
4127 if (dblock.dbuf.typeflag == '1') {
4129 * TRANSLATION_NOTE
4130 * Subject is omitted here.
4131 * Translate this as if
4132 * <subject> linked to %s
4134 #if defined(O_XATTR)
4135 if (xattrp != NULL) {
4136 (void) printf(
4137 gettext(" linked to attribute %s"),
4138 xattr_linkp->h_names +
4139 strlen(xattr_linkp->h_names) + 1);
4140 } else {
4141 (void) printf(
4142 gettext(" linked to %s"), templink);
4144 #else
4145 (void) printf(
4146 gettext(" linked to %s"), templink);
4148 #endif
4150 if (dblock.dbuf.typeflag == '2')
4151 (void) printf(gettext(
4153 * TRANSLATION_NOTE
4154 * Subject is omitted here.
4155 * Translate this as if
4156 * <subject> symbolic link to %s
4158 " symbolic link to %s"), templink);
4159 (void) printf("\n");
4160 #if defined(O_XATTR)
4161 if (xattrp != NULL) {
4162 free(xattrhead);
4163 xattrp = NULL;
4164 xattrhead = NULL;
4166 #endif
4167 passtape();
4170 * Check if the number of files tabled is different from the
4171 * number of files listed on the command line
4173 if (fcnt > tcnt) {
4174 (void) fprintf(stderr, gettext(
4175 "tar: %d file(s) not found\n"), fcnt-tcnt);
4176 Errflg = 1;
4180 static void
4181 putempty(blkcnt_t n)
4183 char buf[TBLOCK];
4184 char *cp;
4186 for (cp = buf; cp < &buf[TBLOCK]; )
4187 *cp++ = '\0';
4188 while (n-- > 0)
4189 (void) writetbuf(buf, 1);
4192 static ushort_t Ftype = S_IFMT;
4194 static void
4195 verbose(struct stat *st, char aclchar)
4197 int i, j, temp;
4198 mode_t mode;
4199 char modestr[12];
4201 for (i = 0; i < 11; i++)
4202 modestr[i] = '-';
4203 modestr[i] = '\0';
4205 /* a '+' sign is printed if there is ACL */
4206 modestr[i-1] = aclchar;
4208 mode = st->st_mode;
4209 for (i = 0; i < 3; i++) {
4210 temp = (mode >> (6 - (i * 3)));
4211 j = (i * 3) + 1;
4212 if (S_IROTH & temp)
4213 modestr[j] = 'r';
4214 if (S_IWOTH & temp)
4215 modestr[j + 1] = 'w';
4216 if (S_IXOTH & temp)
4217 modestr[j + 2] = 'x';
4219 temp = st->st_mode & Ftype;
4220 switch (temp) {
4221 case (S_IFIFO):
4222 modestr[0] = 'p';
4223 break;
4224 case (S_IFCHR):
4225 modestr[0] = 'c';
4226 break;
4227 case (S_IFDIR):
4228 modestr[0] = 'd';
4229 break;
4230 case (S_IFBLK):
4231 modestr[0] = 'b';
4232 break;
4233 case (S_IFREG): /* was initialized to '-' */
4234 break;
4235 case (S_IFLNK):
4236 modestr[0] = 'l';
4237 break;
4238 default:
4239 /* This field may be zero in old archives. */
4240 if (is_posix && dblock.dbuf.typeflag != '1') {
4242 * For POSIX compliant archives, the mode field
4243 * consists of 12 bits, ie: the file type bits
4244 * are not stored in dblock.dbuf.mode.
4245 * For files other than hard links, getdir() sets
4246 * the file type bits in the st_mode field of the
4247 * stat structure based upon dblock.dbuf.typeflag.
4249 (void) fprintf(stderr, gettext(
4250 "tar: impossible file type"));
4254 if ((S_ISUID & Gen.g_mode) == S_ISUID)
4255 modestr[3] = 's';
4256 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
4257 modestr[9] = 't';
4258 if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
4259 modestr[6] = 's';
4260 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
4261 modestr[6] = 'l';
4262 (void) fprintf(vfile, "%s", modestr);
4265 static void
4266 longt(struct stat *st, char aclchar)
4268 char fileDate[30];
4269 struct tm *tm;
4271 verbose(st, aclchar);
4272 (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
4274 if (dblock.dbuf.typeflag == '2') {
4275 if (xhdr_flgs & _X_LINKPATH)
4276 st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
4277 else
4278 st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
4279 '\0', NAMSIZ) ?
4280 (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
4282 (void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
4284 tm = localtime(&(st->st_mtime));
4285 (void) strftime(fileDate, sizeof (fileDate),
4286 dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
4287 (void) fprintf(vfile, " %s ", fileDate);
4292 * checkdir - Attempt to ensure that the path represented in name
4293 * exists, and return 1 if this is true and name itself is a
4294 * directory.
4295 * Return 0 if this path cannot be created or if name is not
4296 * a directory.
4299 static int
4300 checkdir(char *name)
4302 char lastChar; /* the last character in name */
4303 char *cp; /* scratch pointer into name */
4304 char *firstSlash = NULL; /* first slash in name */
4305 char *lastSlash = NULL; /* last slash in name */
4306 int nameLen; /* length of name */
4307 int trailingSlash; /* true if name ends in slash */
4308 int leadingSlash; /* true if name begins with slash */
4309 int markedDir; /* true if name denotes a directory */
4310 int success; /* status of makeDir call */
4314 * Scan through the name, and locate first and last slashes.
4317 for (cp = name; *cp; cp++) {
4318 if (*cp == '/') {
4319 if (! firstSlash) {
4320 firstSlash = cp;
4322 lastSlash = cp;
4327 * Determine what you can from the proceeds of the scan.
4330 lastChar = *(cp - 1);
4331 nameLen = (int)(cp - name);
4332 trailingSlash = (lastChar == '/');
4333 leadingSlash = (*name == '/');
4334 markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash);
4336 if (! lastSlash && ! markedDir) {
4338 * The named file does not have any subdrectory
4339 * structure; just bail out.
4342 return (0);
4346 * Make sure that name doesn`t end with slash for the loop.
4347 * This ensures that the makeDir attempt after the loop is
4348 * meaningful.
4351 if (trailingSlash) {
4352 name[nameLen-1] = '\0';
4356 * Make the path one component at a time.
4359 for (cp = strchr(leadingSlash ? name+1 : name, '/');
4361 cp = strchr(cp+1, '/')) {
4362 *cp = '\0';
4363 success = makeDir(name);
4364 *cp = '/';
4366 if (!success) {
4367 name[nameLen-1] = lastChar;
4368 return (0);
4373 * This makes the last component of the name, if it is a
4374 * directory.
4377 if (markedDir) {
4378 if (! makeDir(name)) {
4379 name[nameLen-1] = lastChar;
4380 return (0);
4384 name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
4385 return (markedDir);
4389 * resugname - Restore the user name and group name. Search the NIS
4390 * before using the uid and gid.
4391 * (It is presumed that an archive entry cannot be
4392 * simultaneously a symlink and some other type.)
4395 static void
4396 resugname(int dirfd, /* dir fd file resides in */
4397 char *name, /* name of the file to be modified */
4398 int symflag) /* true if file is a symbolic link */
4400 uid_t duid;
4401 gid_t dgid;
4402 struct stat *sp = &stbuf;
4403 char *u_g_name;
4405 if (checkflag == 1) { /* Extended tar format and euid == 0 */
4408 * Try and extract the intended uid and gid from the name
4409 * service before believing the uid and gid in the header.
4411 * In the case where we archived a setuid or setgid file
4412 * owned by someone with a large uid, then it will
4413 * have made it into the archive with a uid of nobody. If
4414 * the corresponding username doesn't appear to exist, then we
4415 * want to make sure it *doesn't* end up as setuid nobody!
4417 * Our caller will print an error message about the fact
4418 * that the restore didn't work out quite right ..
4420 if (xhdr_flgs & _X_UNAME)
4421 u_g_name = Xtarhdr.x_uname;
4422 else
4423 u_g_name = dblock.dbuf.uname;
4424 if ((duid = getuidbyname(u_g_name)) == -1) {
4425 if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
4426 (sp->st_mode & S_ISUID) == S_ISUID)
4427 (void) chmod(name,
4428 MODEMASK & sp->st_mode & ~S_ISUID);
4429 duid = sp->st_uid;
4432 /* (Ditto for gids) */
4434 if (xhdr_flgs & _X_GNAME)
4435 u_g_name = Xtarhdr.x_gname;
4436 else
4437 u_g_name = dblock.dbuf.gname;
4438 if ((dgid = getgidbyname(u_g_name)) == -1) {
4439 if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
4440 (sp->st_mode & S_ISGID) == S_ISGID)
4441 (void) chmod(name,
4442 MODEMASK & sp->st_mode & ~S_ISGID);
4443 dgid = sp->st_gid;
4445 } else if (checkflag == 2) { /* tar format and euid == 0 */
4446 duid = sp->st_uid;
4447 dgid = sp->st_gid;
4449 if ((checkflag == 1) || (checkflag == 2))
4450 (void) fchownat(dirfd, name, duid, dgid, symflag);
4453 /*ARGSUSED*/
4454 static void
4455 onintr(int sig)
4457 (void) signal(SIGINT, SIG_IGN);
4458 term++;
4461 /*ARGSUSED*/
4462 static void
4463 onquit(int sig)
4465 (void) signal(SIGQUIT, SIG_IGN);
4466 term++;
4469 /*ARGSUSED*/
4470 static void
4471 onhup(int sig)
4473 (void) signal(SIGHUP, SIG_IGN);
4474 term++;
4477 static void
4478 tomodes(struct stat *sp)
4480 uid_t uid;
4481 gid_t gid;
4483 bzero(dblock.dummy, TBLOCK);
4486 * If the uid or gid is too large, we can't put it into
4487 * the archive. We could fail to put anything in the
4488 * archive at all .. but most of the time the name service
4489 * will save the day when we do a lookup at restore time.
4491 * Instead we choose a "safe" uid and gid, and fix up whether
4492 * or not the setuid and setgid bits are left set to extraction
4493 * time.
4495 if (Eflag) {
4496 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
4497 xhdr_flgs |= _X_UID;
4498 Xtarhdr.x_uid = uid;
4500 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
4501 xhdr_flgs |= _X_GID;
4502 Xtarhdr.x_gid = gid;
4504 if (sp->st_size > TAR_OFFSET_MAX) {
4505 xhdr_flgs |= _X_SIZE;
4506 Xtarhdr.x_filesz = sp->st_size;
4507 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4508 (off_t)0);
4509 } else
4510 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4511 sp->st_size);
4512 } else {
4513 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4514 sp->st_size);
4516 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
4517 uid = UID_NOBODY;
4518 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
4519 gid = GID_NOBODY;
4520 (void) sprintf(dblock.dbuf.gid, "%07lo", gid);
4521 (void) sprintf(dblock.dbuf.uid, "%07lo", uid);
4522 (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
4523 (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
4526 static int
4527 #ifdef EUC
4529 * Warning: the result of this function depends whether 'char' is a
4530 * signed or unsigned data type. This a source of potential
4531 * non-portability among heterogeneous systems. It is retained here
4532 * for backward compatibility.
4534 checksum_signed(union hblock *dblockp)
4535 #else
4536 checksum(union hblock *dblockp)
4537 #endif /* EUC */
4539 int i;
4540 char *cp;
4542 for (cp = dblockp->dbuf.chksum;
4543 cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
4544 *cp = ' ';
4545 i = 0;
4546 for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
4547 i += *cp;
4548 return (i);
4551 #ifdef EUC
4553 * Generate unsigned checksum, regardless of what C compiler is
4554 * used. Survives in the face of arbitrary 8-bit clean filenames,
4555 * e.g., internationalized filenames.
4557 static int
4558 checksum(union hblock *dblockp)
4560 unsigned i;
4561 unsigned char *cp;
4563 for (cp = (unsigned char *) dblockp->dbuf.chksum;
4564 cp < (unsigned char *)
4565 &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
4566 *cp = ' ';
4567 i = 0;
4568 for (cp = (unsigned char *) dblockp->dummy;
4569 cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
4570 i += *cp;
4572 return (i);
4574 #endif /* EUC */
4577 * If the w flag is set, output the action to be taken and the name of the
4578 * file. Perform the action if the user response is affirmative.
4581 static int
4582 checkw(char c, char *name)
4584 if (wflag) {
4585 (void) fprintf(vfile, "%c ", c);
4586 if (vflag)
4587 longt(&stbuf, ' '); /* do we have acl info here */
4588 (void) fprintf(vfile, "%s: ", name);
4589 if (yes() == 1) {
4590 return (1);
4592 return (0);
4594 return (1);
4598 * When the F flag is set, exclude RCS and SCCS directories (and any files
4599 * or directories under them). If F is set twice, also exclude .o files,
4600 * and files names errs, core, and a.out.
4602 * Return 0 if file should be excluded, 1 otherwise.
4605 static int
4606 checkf(char *longname, int is_dir, int howmuch)
4608 static char fullname[PATH_MAX + 1];
4609 char *dir, *name;
4611 #if defined(O_XATTR)
4613 * If there is an xattr_buf structure associated with this file,
4614 * always return 1.
4616 if (xattrp) {
4617 return (1);
4619 #endif
4622 * First check to see if the base name is an RCS or SCCS directory.
4624 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4625 return (1);
4627 name = basename(fullname);
4628 if (is_dir) {
4629 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4630 return (0);
4634 * If two -F command line options were given then exclude .o files,
4635 * and files named errs, core, and a.out.
4637 if (howmuch > 1 && !is_dir) {
4638 size_t l = strlen(name);
4640 if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
4641 return (0);
4642 if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
4643 strcmp(name, "a.out") == 0)
4644 return (0);
4648 * At this point, check to see if this file has a parent directory
4649 * named RCS or SCCS. If so, then this file should be excluded too.
4650 * The strcpy() operation is done again, because basename(3C) may
4651 * modify the path string passed to it.
4653 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4654 return (1);
4656 dir = dirname(fullname);
4657 while (strcmp(dir, ".") != 0) {
4658 name = basename(dir);
4659 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4660 return (0);
4661 dir = dirname(dir);
4664 return (1);
4667 static int
4668 response(void)
4670 int c;
4672 c = getchar();
4673 if (c != '\n')
4674 while (getchar() != '\n')
4676 else c = 'n';
4677 return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
4680 /* Has file been modified since being put into archive? If so, return > 0. */
4682 static off_t lookup(char *);
4684 static int
4685 checkupdate(char *arg)
4687 char name[PATH_MAX+1];
4688 time_t mtime;
4689 long nsecs;
4690 off_t seekp;
4692 rewind(tfile);
4693 if ((seekp = lookup(arg)) < 0)
4694 return (1);
4695 (void) fseek(tfile, seekp, 0);
4696 (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
4699 * Unless nanoseconds were stored in the file, only use seconds for
4700 * comparison of time. Nanoseconds are stored when -E is specified.
4702 if (Eflag == 0)
4703 return (stbuf.st_mtime > mtime);
4705 if ((stbuf.st_mtime < mtime) ||
4706 ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
4707 return (0);
4708 return (1);
4713 * newvol get new floppy (or tape) volume
4715 * newvol(); resets tapepos and first to TRUE, prompts for
4716 * for new volume, and waits.
4717 * if dumping, end-of-file is written onto the tape.
4720 static void
4721 newvol(void)
4723 int c;
4725 if (dumping) {
4726 dlog("newvol called with 'dumping' set\n");
4727 putempty((blkcnt_t)2); /* 2 EOT marks */
4728 closevol();
4729 flushtape();
4730 sync();
4731 tapepos = 0;
4732 } else
4733 first = TRUE;
4734 if (close(mt) != 0)
4735 vperror(2, gettext("close error"));
4736 mt = 0;
4737 (void) fprintf(stderr, gettext(
4738 "tar: \007please insert new volume, then press RETURN."));
4739 (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */
4740 while ((c = getchar()) != '\n' && ! term)
4741 if (c == EOF)
4742 done(Errflg);
4743 if (term)
4744 done(Errflg);
4746 errno = 0;
4748 if (strcmp(usefile, "-") == 0) {
4749 mt = dup(1);
4750 } else {
4751 mt = open(usefile, dumping ? update : 0);
4754 if (mt < 0) {
4755 (void) fprintf(stderr, gettext(
4756 "tar: cannot reopen %s (%s)\n"),
4757 dumping ? gettext("output") : gettext("input"), usefile);
4759 dlog("update=%d, usefile=%s ", update, usefile);
4760 dlog("mt=%d, [%s]\n", mt, strerror(errno));
4762 done(2);
4767 * Write a trailer portion to close out the current output volume.
4770 static void
4771 closevol(void)
4773 if (mulvol) {
4775 * blocklim does not count the 2 EOT marks;
4776 * tapepos does count the 2 EOT marks;
4777 * therefore we need the +2 below.
4779 putempty(blocklim + (blkcnt_t)2 - tapepos);
4783 static void
4784 done(int n)
4787 * If we were terminated in some way, and we would otherwise have
4788 * exited with a value of 0, adjust to 1, so that external callers
4789 * can determine this by looking at the exit status.
4791 if (term && n == 0)
4792 n = 1;
4794 if (tfile != NULL)
4795 (void) unlink(tname);
4796 if (compress_opt != NULL)
4797 (void) free(compress_opt);
4798 if (mt > 0) {
4799 if ((close(mt) != 0) || (fclose(stdout) != 0)) {
4800 perror(gettext("tar: close error"));
4801 exit(2);
4805 * If we have a compression child, we should have a child process that
4806 * we're waiting for to finish compressing or uncompressing the tar
4807 * stream.
4809 if (comp_pid != 0)
4810 wait_pid(comp_pid);
4811 exit(n);
4815 * Determine if s1 is a prefix portion of s2 (or the same as s2).
4818 static int
4819 is_prefix(char *s1, char *s2)
4821 while (*s1)
4822 if (*s1++ != *s2++)
4823 return (0);
4824 if (*s2)
4825 return (*s2 == '/');
4826 return (1);
4830 * lookup and bsrch look through tfile entries to find a match for a name.
4831 * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
4832 * a pair of newline chars, so the buffer it uses must be long enough for
4833 * two lines: name and modification time as well as period, newline and space.
4835 * A kludge was added to bsrch to take care of matching on the first entry
4836 * in the file--there is no leading newline. So, if we are reading from the
4837 * start of the file, read into byte two and set the first byte to a newline.
4838 * Otherwise, the first entry cannot be matched.
4842 #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4843 static off_t
4844 lookup(char *s)
4846 int i;
4847 off_t a;
4849 for (i = 0; s[i]; i++)
4850 if (s[i] == ' ')
4851 break;
4852 a = bsrch(s, i, low, high);
4853 return (a);
4856 static off_t
4857 bsrch(char *s, int n, off_t l, off_t h)
4859 int i, j;
4860 char b[N];
4861 off_t m, m1;
4864 loop:
4865 if (l >= h)
4866 return ((off_t)-1);
4867 m = l + (h-l)/2 - N/2;
4868 if (m < l)
4869 m = l;
4870 (void) fseek(tfile, m, 0);
4871 if (m == 0) {
4872 (void) fread(b+1, 1, N-1, tfile);
4873 b[0] = '\n';
4874 m--;
4875 } else
4876 (void) fread(b, 1, N, tfile);
4877 for (i = 0; i < N; i++) {
4878 if (b[i] == '\n')
4879 break;
4880 m++;
4882 if (m >= h)
4883 return ((off_t)-1);
4884 m1 = m;
4885 j = i;
4886 for (i++; i < N; i++) {
4887 m1++;
4888 if (b[i] == '\n')
4889 break;
4891 i = cmp(b+j, s, n);
4892 if (i < 0) {
4893 h = m;
4894 goto loop;
4896 if (i > 0) {
4897 l = m1;
4898 goto loop;
4900 if (m < 0)
4901 m = 0;
4902 return (m);
4905 static int
4906 cmp(char *b, char *s, int n)
4908 int i;
4910 assert(b[0] == '\n');
4912 for (i = 0; i < n; i++) {
4913 if (b[i+1] > s[i])
4914 return (-1);
4915 if (b[i+1] < s[i])
4916 return (1);
4918 return (b[i+1] == ' '? 0 : -1);
4923 * seekdisk seek to next file on archive
4925 * called by passtape() only
4927 * WARNING: expects "nblock" to be set, that is, readtape() to have
4928 * already been called. Since passtape() is only called
4929 * after a file header block has been read (why else would
4930 * we skip to next file?), this is currently safe.
4932 * changed to guarantee SYS_BLOCK boundary
4935 static void
4936 seekdisk(blkcnt_t blocks)
4938 off_t seekval;
4939 #if SYS_BLOCK > TBLOCK
4940 /* handle non-multiple of SYS_BLOCK */
4941 blkcnt_t nxb; /* # extra blocks */
4942 #endif
4944 tapepos += blocks;
4945 dlog("seekdisk(%" FMT_blkcnt_t ") called\n", blocks);
4946 if (recno + blocks <= nblock) {
4947 recno += blocks;
4948 return;
4950 if (recno > nblock)
4951 recno = nblock;
4952 seekval = (off_t)blocks - (nblock - recno);
4953 recno = nblock; /* so readtape() reads next time through */
4954 #if SYS_BLOCK > TBLOCK
4955 nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
4956 dlog("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
4957 nxb, seekval);
4958 if (nxb && nxb > seekval) /* don't seek--we'll read */
4959 goto noseek;
4960 seekval -= nxb; /* don't seek quite so far */
4961 #endif
4962 if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
4963 (void) fprintf(stderr, gettext(
4964 "tar: device seek error\n"));
4965 done(3);
4967 #if SYS_BLOCK > TBLOCK
4968 /* read those extra blocks */
4969 noseek:
4970 if (nxb) {
4971 dlog("reading extra blocks\n");
4972 if (read(mt, tbuf, TBLOCK*nblock) < 0) {
4973 (void) fprintf(stderr, gettext(
4974 "tar: read error while skipping file\n"));
4975 done(8);
4977 recno = nxb; /* so we don't read in next readtape() */
4979 #endif
4982 static void
4983 readtape(char *buffer)
4985 int i, j;
4987 ++tapepos;
4988 if (recno >= nblock || first) {
4989 if (first) {
4991 * set the number of blocks to read initially, based on
4992 * the defined defaults for the device, or on the
4993 * explicit block factor given.
4995 if (bflag || defaults_used || NotTape)
4996 j = nblock;
4997 else
4998 j = NBLOCK;
4999 } else
5000 j = nblock;
5002 if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
5003 (void) fprintf(stderr, gettext(
5004 "tar: tape read error\n"));
5005 done(3);
5007 * i == 0 and !rflag means that EOF is reached and we are
5008 * trying to update or replace an empty tar file, so exit
5009 * with an error.
5011 * If i == 0 and !first and NotTape, it means the pointer
5012 * has gone past the EOF. It could happen if two processes
5013 * try to update the same tar file simultaneously. So exit
5014 * with an error.
5017 } else if (i == 0) {
5018 if (first && !rflag) {
5019 (void) fprintf(stderr, gettext(
5020 "tar: blocksize = %d\n"), i);
5021 done(Errflg);
5022 } else if (!first && (!rflag || NotTape)) {
5023 mterr("read", 0, 2);
5025 } else if ((!first || Bflag) && i != TBLOCK*j) {
5027 * Short read - try to get the remaining bytes.
5030 int remaining = (TBLOCK * j) - i;
5031 char *b = (char *)tbuf + i;
5032 int r;
5034 do {
5035 if ((r = read(mt, b, remaining)) < 0) {
5036 (void) fprintf(stderr,
5037 gettext("tar: tape read error\n"));
5038 done(3);
5040 b += r;
5041 remaining -= r;
5042 i += r;
5043 } while (remaining > 0 && r != 0);
5045 if (first) {
5046 if ((i % TBLOCK) != 0) {
5047 (void) fprintf(stderr, gettext(
5048 "tar: tape blocksize error\n"));
5049 done(3);
5051 i /= TBLOCK;
5052 if (vflag && i != nblock && i != 1) {
5053 if (!NotTape)
5054 (void) fprintf(stderr, gettext(
5055 "tar: blocksize = %d\n"), i);
5059 * If we are reading a tape, then a short read is
5060 * understood to signify that the amount read is
5061 * the tape's actual blocking factor. We adapt
5062 * nblock accordingly. There is no reason to do
5063 * this when the device is not blocked.
5066 if (!NotTape)
5067 nblock = i;
5069 recno = 0;
5072 first = FALSE;
5073 copy(buffer, &tbuf[recno++]);
5078 * replacement for writetape.
5081 static int
5082 writetbuf(char *buffer, int n)
5084 int i;
5086 tapepos += n; /* output block count */
5088 if (recno >= nblock) {
5089 i = write(mt, (char *)tbuf, TBLOCK*nblock);
5090 if (i != TBLOCK*nblock)
5091 mterr("write", i, 2);
5092 recno = 0;
5096 * Special case: We have an empty tape buffer, and the
5097 * users data size is >= the tape block size: Avoid
5098 * the bcopy and dma direct to tape. BIG WIN. Add the
5099 * residual to the tape buffer.
5101 while (recno == 0 && n >= nblock) {
5102 i = (int)write(mt, buffer, TBLOCK*nblock);
5103 if (i != TBLOCK*nblock)
5104 mterr("write", i, 2);
5105 n -= nblock;
5106 buffer += (nblock * TBLOCK);
5109 while (n-- > 0) {
5110 (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
5111 buffer += TBLOCK;
5112 if (recno >= nblock) {
5113 i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
5114 if (i != TBLOCK*nblock)
5115 mterr("write", i, 2);
5116 recno = 0;
5120 /* Tell the user how much to write to get in sync */
5121 return (nblock - recno);
5125 * backtape - reposition tape after reading soft "EOF" record
5127 * Backtape tries to reposition the tape back over the EOF
5128 * record. This is for the 'u' and 'r' function letters so that the
5129 * tape can be extended. This code is not well designed, but
5130 * I'm confident that the only callers who care about the
5131 * backspace-over-EOF feature are those involved in 'u' and 'r'.
5133 * The proper way to backup the tape is through the use of mtio.
5134 * Earlier spins used lseek combined with reads in a confusing
5135 * maneuver that only worked on 4.x, but shouldn't have, even
5136 * there. Lseeks are explicitly not supported for tape devices.
5139 static void
5140 backtape(void)
5142 struct mtop mtcmd;
5143 dlog("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
5144 nblock);
5146 * Backup to the position in the archive where the record
5147 * currently sitting in the tbuf buffer is situated.
5150 if (NotTape) {
5152 * For non-tape devices, this means lseeking to the
5153 * correct position. The absolute location tapepos-recno
5154 * should be the beginning of the current record.
5157 if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
5158 (off_t)-1) {
5159 (void) fprintf(stderr,
5160 gettext("tar: lseek to end of archive failed\n"));
5161 done(4);
5163 } else {
5165 * For tape devices, we backup over the most recently
5166 * read record.
5169 mtcmd.mt_op = MTBSR;
5170 mtcmd.mt_count = 1;
5172 if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
5173 (void) fprintf(stderr,
5174 gettext("tar: backspace over record failed\n"));
5175 done(4);
5180 * Decrement the tape and tbuf buffer indices to prepare for the
5181 * coming write to overwrite the soft EOF record.
5184 recno--;
5185 tapepos--;
5190 * flushtape write buffered block(s) onto tape
5192 * recno points to next free block in tbuf. If nonzero, a write is done.
5193 * Care is taken to write in multiples of SYS_BLOCK when device is
5194 * non-magtape in case raw i/o is used.
5196 * NOTE: this is called by writetape() to do the actual writing
5199 static void
5200 flushtape(void)
5202 dlog("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno);
5203 if (recno > 0) { /* anything buffered? */
5204 if (NotTape) {
5205 #if SYS_BLOCK > TBLOCK
5206 int i;
5209 * an odd-block write can only happen when
5210 * we are at the end of a volume that is not a tape.
5211 * Here we round recno up to an even SYS_BLOCK
5212 * boundary.
5214 if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
5215 dlog("flushtape() %d rounding blocks\n", i);
5216 recno += i; /* round up to even SYS_BLOCK */
5218 #endif
5219 if (recno > nblock)
5220 recno = nblock;
5222 dlog("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
5223 " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
5224 (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
5225 if (write(mt, tbuf,
5226 (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
5227 (void) fprintf(stderr, gettext(
5228 "tar: tape write error\n"));
5229 done(2);
5231 recno = 0;
5235 static void
5236 copy(void *dst, void *src)
5238 (void) memcpy(dst, src, TBLOCK);
5242 * kcheck()
5243 * - checks the validity of size values for non-tape devices
5244 * - if size is zero, mulvol tar is disabled and size is
5245 * assumed to be infinite.
5246 * - returns volume size in TBLOCKS
5249 static blkcnt_t
5250 kcheck(char *kstr)
5252 blkcnt_t kval;
5254 kval = strtoll(kstr, NULL, 0);
5255 if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */
5256 mulvol = 0; /* definitely not mulvol, but we must */
5257 return (0); /* took out setting of NotTape */
5259 if (kval < (blkcnt_t)MINSIZE) {
5260 (void) fprintf(stderr, gettext(
5261 "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5262 ").\n"), (ulong_t)MINSIZE, kval);
5263 (void) fprintf(stderr, gettext(
5264 "bad size entry for %s in %s.\n"),
5265 archive, DEF_FILE);
5266 done(1);
5268 mulvol++;
5269 NotTape++; /* implies non-tape */
5270 return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */
5275 * bcheck()
5276 * - checks the validity of blocking factors
5277 * - returns blocking factor
5280 static int
5281 bcheck(char *bstr)
5283 blkcnt_t bval;
5285 bval = strtoll(bstr, NULL, 0);
5286 if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
5287 (void) fprintf(stderr, gettext(
5288 "tar: invalid blocksize \"%s\".\n"), bstr);
5289 if (!bflag)
5290 (void) fprintf(stderr, gettext(
5291 "bad blocksize entry for '%s' in %s.\n"),
5292 archive, DEF_FILE);
5293 done(1);
5296 return ((int)bval);
5301 * defset()
5302 * - reads DEF_FILE for the set of default values specified.
5303 * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5304 * - 'usefile' points to static data, so will be overwritten
5305 * if this routine is called a second time.
5306 * - the pattern specified by 'arch' must be followed by four
5307 * blank-separated fields (1) device (2) blocking,
5308 * (3) size(K), and (4) tape
5309 * for example: archive0=/dev/fd 1 400 n
5312 static int
5313 defset(char *arch)
5315 char *bp;
5317 if (defopen(DEF_FILE) != 0)
5318 return (FALSE);
5319 if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
5320 (void) fprintf(stderr, gettext(
5321 "tar: error setting parameters for %s.\n"), DEF_FILE);
5322 return (FALSE); /* & following ones too */
5324 if ((bp = defread(arch)) == NULL) {
5325 (void) fprintf(stderr, gettext(
5326 "tar: missing or invalid '%s' entry in %s.\n"),
5327 arch, DEF_FILE);
5328 return (FALSE);
5330 if ((usefile = strtok(bp, " \t")) == NULL) {
5331 (void) fprintf(stderr, gettext(
5332 "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
5333 return (FALSE);
5335 if ((bp = strtok(NULL, " \t")) == NULL) {
5336 (void) fprintf(stderr, gettext(
5337 "tar: block component missing in '%s' entry in %s.\n"),
5338 arch, DEF_FILE);
5339 return (FALSE);
5341 nblock = bcheck(bp);
5342 if ((bp = strtok(NULL, " \t")) == NULL) {
5343 (void) fprintf(stderr, gettext(
5344 "tar: size component missing in '%s' entry in %s.\n"),
5345 arch, DEF_FILE);
5346 return (FALSE);
5348 blocklim = kcheck(bp);
5349 if ((bp = strtok(NULL, " \t")) != NULL)
5350 NotTape = (*bp == 'n' || *bp == 'N');
5351 else
5352 NotTape = (blocklim != 0);
5353 (void) defopen(NULL);
5354 dlog("defset: archive='%s'; usefile='%s'\n", arch, usefile);
5355 dlog("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
5356 nblock, blocklim);
5357 dlog("defset: not tape = %d\n", NotTape);
5358 return (TRUE);
5363 * Following code handles excluded and included files.
5364 * A hash table of file names to be {in,ex}cluded is built.
5365 * For excluded files, before writing or extracting a file
5366 * check to see if it is in the exclude_tbl.
5367 * For included files, the wantit() procedure will check to
5368 * see if the named file is in the include_tbl.
5371 static void
5372 build_table(file_list_t *table[], char *file)
5374 FILE *fp;
5375 char buf[PATH_MAX + 1];
5377 if ((fp = fopen(file, "r")) == NULL)
5378 vperror(1, gettext("could not open %s"), file);
5379 while (fgets(buf, sizeof (buf), fp) != NULL) {
5380 if (buf[strlen(buf) - 1] == '\n')
5381 buf[strlen(buf) - 1] = '\0';
5382 /* Only add to table if line has something in it */
5383 if (strspn(buf, " \t") != strlen(buf))
5384 add_file_to_table(table, buf);
5386 (void) fclose(fp);
5391 * Add a file name to the the specified table, if the file name has any
5392 * trailing '/'s then delete them before inserting into the table
5395 static void
5396 add_file_to_table(file_list_t *table[], char *str)
5398 char name[PATH_MAX + 1];
5399 unsigned int h;
5400 file_list_t *exp;
5402 (void) strcpy(name, str);
5403 while (name[strlen(name) - 1] == '/') {
5404 name[strlen(name) - 1] = '\0';
5407 h = hash(name);
5408 if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
5409 sizeof (char))) == NULL) {
5410 (void) fprintf(stderr, gettext(
5411 "tar: out of memory, exclude/include table(entry)\n"));
5412 exit(1);
5415 if ((exp->name = strdup(name)) == NULL) {
5416 (void) fprintf(stderr, gettext(
5417 "tar: out of memory, exclude/include table(file name)\n"));
5418 exit(1);
5421 exp->next = table[h];
5422 table[h] = exp;
5427 * See if a file name or any of the file's parent directories is in the
5428 * specified table, if the file name has any trailing '/'s then delete
5429 * them before searching the table
5432 static int
5433 is_in_table(file_list_t *table[], char *str)
5435 char name[PATH_MAX + 1];
5436 unsigned int h;
5437 file_list_t *exp;
5438 char *ptr;
5440 (void) strcpy(name, str);
5441 while (name[strlen(name) - 1] == '/') {
5442 name[strlen(name) - 1] = '\0';
5446 * check for the file name in the passed list
5448 h = hash(name);
5449 exp = table[h];
5450 while (exp != NULL) {
5451 if (strcmp(name, exp->name) == 0) {
5452 return (1);
5454 exp = exp->next;
5458 * check for any parent directories in the file list
5460 while ((ptr = strrchr(name, '/'))) {
5461 *ptr = '\0';
5462 h = hash(name);
5463 exp = table[h];
5464 while (exp != NULL) {
5465 if (strcmp(name, exp->name) == 0) {
5466 return (1);
5468 exp = exp->next;
5472 return (0);
5477 * Compute a hash from a string.
5480 static unsigned int
5481 hash(char *str)
5483 char *cp;
5484 unsigned int h;
5486 h = 0;
5487 for (cp = str; *cp; cp++) {
5488 h += *cp;
5490 return (h % TABLE_SIZE);
5493 static void *
5494 getmem(size_t size)
5496 void *p = calloc((unsigned)size, sizeof (char));
5498 if (p == NULL && freemem) {
5499 (void) fprintf(stderr, gettext(
5500 "tar: out of memory, link and directory modtime "
5501 "info lost\n"));
5502 freemem = 0;
5503 if (errflag)
5504 done(1);
5505 else
5506 Errflg = 1;
5508 return (p);
5512 * vperror() --variable argument perror.
5513 * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
5514 * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5515 * with the value of whatever "errno" is set to. If exit_status is not
5516 * zero, then tar exits with that error status. If errflag and exit_status
5517 * are both zero, the routine returns to where it was called and sets Errflg
5518 * to errno.
5521 static void
5522 vperror(int exit_status, char *fmt, ...)
5524 va_list ap;
5526 va_start(ap, fmt);
5527 (void) fputs("tar: ", stderr);
5528 (void) vfprintf(stderr, fmt, ap);
5529 (void) fprintf(stderr, ": %s\n", strerror(errno));
5530 va_end(ap);
5531 if (exit_status)
5532 done(exit_status);
5533 else
5534 if (errflag)
5535 done(errno);
5536 else
5537 Errflg = errno;
5541 static void
5542 fatal(char *format, ...)
5544 va_list ap;
5546 va_start(ap, format);
5547 (void) fprintf(stderr, "tar: ");
5548 (void) vfprintf(stderr, format, ap);
5549 (void) fprintf(stderr, "\n");
5550 va_end(ap);
5551 done(1);
5556 * Check to make sure that argument is a char * ptr.
5557 * Actually, we just check to see that it is non-null.
5558 * If it is null, print out the message and call usage(), bailing out.
5561 static void
5562 assert_string(char *s, char *msg)
5564 if (s == NULL) {
5565 (void) fprintf(stderr, msg);
5566 usage();
5571 static void
5572 mterr(char *operation, int i, int exitcode)
5574 (void) fprintf(stderr, gettext(
5575 "tar: %s error: "), operation);
5576 if (i < 0)
5577 perror("");
5578 else
5579 (void) fprintf(stderr, gettext("unexpected EOF\n"));
5580 done(exitcode);
5583 static int
5584 wantit(char *argv[], char **namep, char **dirp, char **component,
5585 attr_data_t **attrinfo)
5587 char **cp;
5588 int gotit; /* true if we've found a match */
5589 int ret;
5591 top:
5592 if (xhdr_flgs & _X_XHDR) {
5593 xhdr_flgs = 0;
5595 getdir();
5596 if (Xhdrflag > 0) {
5597 ret = get_xdata();
5598 if (ret != 0) { /* Xhdr items and regular header */
5599 setbytes_to_skip(&stbuf, ret);
5600 passtape();
5601 return (0); /* Error--don't want to extract */
5606 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5607 * of ancillary file is either over or ancillary file
5608 * processing is not required, load info from Xtarhdr and set
5609 * _X_XHDR bit in xhdr_flgs.
5611 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
5612 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
5613 xhdr_flgs |= _X_XHDR;
5616 #if defined(O_XATTR)
5617 if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
5619 * Always needs to read the extended header. If atflag, saflag,
5620 * or tflag isn't set, then we'll have the correct info for
5621 * passtape() later.
5623 (void) read_xattr_hdr(attrinfo);
5624 goto top;
5627 * Now that we've read the extended header, call passtape()
5628 * if we don't want to restore attributes or system attributes.
5629 * Don't restore the attribute if we are extracting
5630 * a file from an archive (as opposed to doing a table of
5631 * contents) and any of the following are true:
5632 * 1. neither -@ or -/ was specified.
5633 * 2. -@ was specified, -/ wasn't specified, and we're
5634 * processing a hidden attribute directory of an attribute
5635 * or we're processing a read-write system attribute file.
5636 * 3. -@ wasn't specified, -/ was specified, and the file
5637 * we're processing is not a read-write system attribute file,
5638 * or we're processing the hidden attribute directory of an
5639 * attribute.
5641 * We always process the attributes if we're just generating
5642 * generating a table of contents, or if both -@ and -/ were
5643 * specified.
5645 if (xattrp != NULL) {
5646 attr_data_t *ainfo = *attrinfo;
5648 if (!tflag &&
5649 ((!atflag && !saflag) ||
5650 (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
5651 ainfo->attr_rw_sysattr)) ||
5652 (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
5653 !ainfo->attr_rw_sysattr)))) {
5654 passtape();
5655 return (0);
5658 #endif
5660 /* sets *namep to point at the proper name */
5661 if (check_prefix(namep, dirp, component) != 0) {
5662 passtape();
5663 return (0);
5666 if (endtape()) {
5667 if (Bflag) {
5668 ssize_t sz;
5669 size_t extra_blocks = 0;
5672 * Logically at EOT - consume any extra blocks
5673 * so that write to our stdin won't fail and
5674 * emit an error message; otherwise something
5675 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5676 * will produce a bogus error message from "dd".
5679 while ((sz = read(mt, tbuf, TBLOCK*nblock)) > 0) {
5680 extra_blocks += sz;
5682 dlog("wantit(): %d bytes of extra blocks\n",
5683 extra_blocks);
5685 dlog("wantit(): at end of tape.\n");
5686 return (-1);
5689 gotit = 0;
5691 if ((Iflag && is_in_table(include_tbl, *namep)) ||
5692 (! Iflag && *argv == NULL)) {
5693 gotit = 1;
5694 } else {
5695 for (cp = argv; *cp; cp++) {
5696 if (is_prefix(*cp, *namep)) {
5697 gotit = 1;
5698 break;
5703 if (! gotit) {
5704 passtape();
5705 return (0);
5708 if (Xflag && is_in_table(exclude_tbl, *namep)) {
5709 if (vflag) {
5710 (void) fprintf(stderr, gettext("%s excluded\n"),
5711 *namep);
5713 passtape();
5714 return (0);
5717 return (1);
5721 static void
5722 setbytes_to_skip(struct stat *st, int err)
5725 * In a scenario where a typeflag 'X' was followed by
5726 * a typeflag 'A' and typeflag 'O', then the number of
5727 * bytes to skip should be the size of ancillary file,
5728 * plus the dblock for regular file, and the size
5729 * from Xtarhdr. However, if the typeflag was just 'X'
5730 * followed by typeflag 'O', then the number of bytes
5731 * to skip should be the size from Xtarhdr.
5733 if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
5734 (xhdr_flgs & _X_SIZE)) {
5735 st->st_size += TBLOCK + Xtarhdr.x_filesz;
5736 xhdr_flgs |= _X_XHDR;
5737 } else if ((dblock.dbuf.typeflag != 'A') &&
5738 (xhdr_flgs & _X_SIZE)) {
5739 st->st_size += Xtarhdr.x_filesz;
5740 xhdr_flgs |= _X_XHDR;
5744 static int
5745 fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
5746 int rw_sysattr, attr_data_t **attrinfo)
5748 size_t pathlen;
5749 char *tpath;
5750 char *tparent;
5752 /* parent info */
5753 if (attrparent != NULL) {
5754 if ((tparent = strdup(attrparent)) == NULL) {
5755 vperror(0, gettext(
5756 "unable to allocate memory for attribute parent "
5757 "name for %sattribute %s/%s of %s"),
5758 rw_sysattr ? gettext("system ") : "",
5759 attrparent, attr, longname);
5760 return (1);
5762 } else {
5763 tparent = NULL;
5766 /* path info */
5767 pathlen = strlen(attr) + 1;
5768 if (attrparent != NULL) {
5769 pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
5771 if ((tpath = calloc(1, pathlen)) == NULL) {
5772 vperror(0, gettext(
5773 "unable to allocate memory for full "
5774 "attribute path name for %sattribute %s%s%s of %s"),
5775 rw_sysattr ? gettext("system ") : "",
5776 (attrparent == NULL) ? "" : attrparent,
5777 (attrparent == NULL) ? "" : "/",
5778 attr, longname);
5779 if (tparent != NULL) {
5780 free(tparent);
5782 return (1);
5784 (void) snprintf(tpath, pathlen, "%s%s%s",
5785 (attrparent == NULL) ? "" : attrparent,
5786 (attrparent == NULL) ? "" : "/",
5787 attr);
5789 /* fill in the attribute info */
5790 if (*attrinfo == NULL) {
5791 if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
5792 vperror(0, gettext(
5793 "unable to allocate memory for attribute "
5794 "information for %sattribute %s%s%s of %s"),
5795 rw_sysattr ? gettext("system ") : "",
5796 (attrparent == NULL) ? "" : attrparent,
5797 (attrparent == NULL) ? "" : gettext("/"),
5798 attr, longname);
5799 if (tparent != NULL) {
5800 free(tparent);
5802 free(tpath);
5803 return (1);
5805 } else {
5806 if ((*attrinfo)->attr_parent != NULL) {
5807 free((*attrinfo)->attr_parent);
5809 if ((*attrinfo)->attr_path != NULL) {
5810 free((*attrinfo)->attr_path);
5813 * The parent file descriptor is passed in, so don't
5814 * close it here as it should be closed by the function
5815 * that opened it.
5818 (*attrinfo)->attr_parent = tparent;
5819 (*attrinfo)->attr_path = tpath;
5820 (*attrinfo)->attr_rw_sysattr = rw_sysattr;
5821 (*attrinfo)->attr_parentfd = atparentfd;
5823 return (0);
5827 * Test to see if name is a directory.
5829 * Return 1 if true, 0 otherwise.
5832 static int
5833 is_directory(char *name)
5835 #if defined(O_XATTR)
5837 * If there is an xattr_buf structure associated with this file,
5838 * then the directory test is based on whether the name has a
5839 * trailing slash.
5841 if (xattrp)
5842 return (name[strlen(name) - 1] == '/');
5843 #endif
5844 if (is_posix)
5845 return (dblock.dbuf.typeflag == '5');
5846 else
5847 return (name[strlen(name) - 1] == '/');
5851 * Version of chdir that handles directory pathnames of greater than PATH_MAX
5852 * length, by changing the working directory to manageable portions of the
5853 * complete directory pathname. If any of these attempts fail, then it exits
5854 * non-zero.
5856 * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
5857 * pathname is greater than PATH_MAX, then this still won't work, and this
5858 * routine will return -1 with errno set to ENAMETOOLONG.
5860 * NOTE: this routine is semantically different to the system chdir in
5861 * that it is remotely possible for the currently working directory to be
5862 * changed to a different directory, if a chdir call fails when processing
5863 * one of the segments of a path that is greater than PATH_MAX. This isn't
5864 * a problem as this is tar's own specific version of chdir.
5867 static int
5868 tar_chdir(const char *path)
5870 const char *sep = "/";
5871 char *path_copy = NULL;
5872 char *ptr = NULL;
5874 /* The trivial case. */
5875 if (chdir(path) == 0) {
5876 return (0);
5878 if (errno == ENAMETOOLONG) {
5879 if (path[0] == '/' && chdir(sep) != 0)
5880 return (-1);
5882 /* strtok(3C) modifies the string, so make a copy. */
5883 if ((path_copy = strdup(path)) == NULL) {
5884 return (-1);
5887 /* chdir(2) for every path element. */
5888 for (ptr = strtok(path_copy, sep);
5889 ptr != NULL;
5890 ptr = strtok(NULL, sep)) {
5891 if (chdir(ptr) != 0) {
5892 free(path_copy);
5893 return (-1);
5896 free(path_copy);
5897 return (0);
5900 /* If chdir fails for any reason except ENAMETOOLONG. */
5901 return (-1);
5905 * Test if name has a '..' sequence in it.
5907 * Return 1 if found, 0 otherwise.
5910 static int
5911 has_dot_dot(char *name)
5913 char *s;
5914 size_t name_len = strlen(name);
5916 for (s = name; s < (name + name_len - 2); s++) {
5917 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
5918 return (1);
5920 while (! (*s == '/')) {
5921 if (! *s++)
5922 return (0);
5926 return (0);
5930 * Test if name is an absolute path name.
5932 * Return 1 if true, 0 otherwise.
5935 static int
5936 is_absolute(char *name)
5938 #if defined(O_XATTR)
5940 * If this is an extended attribute (whose name will begin with
5941 * "/dev/null/", always return 0 as they should be extracted with
5942 * the name intact, to allow other tar archiving programs that
5943 * don't understand extended attributes, to correctly throw them away.
5945 if (xattrp)
5946 return (0);
5947 #endif
5949 return (name[0] == '/');
5953 * Adjust the pathname to make it a relative one. Strip off any leading
5954 * '/' characters and if the pathname contains any '..' sequences, strip
5955 * upto and including the last occurance of '../' (or '..' if found at
5956 * the very end of the pathname).
5958 * Return the relative pathname. stripped_prefix will also return the
5959 * portion of name that was stripped off and should be freed by the
5960 * calling routine when no longer needed.
5963 static char *
5964 make_relative_name(char *name, char **stripped_prefix)
5966 char *s;
5967 size_t prefix_len = 0;
5968 size_t name_len = strlen(name);
5970 for (s = name + prefix_len; s < (name + name_len - 2); ) {
5971 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
5972 prefix_len = s + 2 - name;
5974 do {
5975 char c = *s++;
5977 if (c == '/')
5978 break;
5979 } while (*s);
5982 for (s = name + prefix_len; *s == '/'; s++)
5983 continue;
5984 prefix_len = s - name;
5986 /* Create the portion of the name that was stripped off. */
5987 s = malloc(prefix_len + 1);
5988 memcpy(s, name, prefix_len);
5989 s[prefix_len] = 0;
5990 *stripped_prefix = s;
5991 s = &name[prefix_len];
5993 return (s);
5997 * Return through *namep a pointer to the proper fullname (i.e "<name> |
5998 * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6000 * Returns 0 if successful, otherwise returns 1.
6003 static int
6004 check_prefix(char **namep, char **dirp, char **compp)
6006 static char fullname[PATH_MAX + 1];
6007 static char dir[PATH_MAX + 1];
6008 static char component[PATH_MAX + 1];
6009 static char savename[PATH_MAX + 1];
6010 char *s;
6012 (void) memset(dir, 0, sizeof (dir));
6013 (void) memset(component, 0, sizeof (component));
6015 if (xhdr_flgs & _X_PATH) {
6016 (void) strcpy(fullname, Xtarhdr.x_path);
6017 } else {
6018 if (dblock.dbuf.prefix[0] != '\0')
6019 (void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
6020 dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
6021 else
6022 (void) sprintf(fullname, "%.*s", NAMSIZ,
6023 dblock.dbuf.name);
6027 * If we are printing a table of contents or extracting an archive,
6028 * make absolute pathnames relative and prohibit the unpacking of
6029 * files contain ".." in their name (unless the user has supplied
6030 * the -P option).
6032 if ((tflag || xflag) && !Pflag) {
6033 if (is_absolute(fullname) || has_dot_dot(fullname)) {
6034 char *stripped_prefix;
6036 (void) strcpy(savename, fullname);
6037 strcpy(fullname,
6038 make_relative_name(savename, &stripped_prefix));
6039 (void) fprintf(stderr,
6040 gettext("tar: Removing leading '%s' from '%s'\n"),
6041 stripped_prefix, savename);
6042 free(stripped_prefix);
6047 * Set dir and component names
6050 get_parent(fullname, dir);
6052 #if defined(O_XATTR)
6053 if (xattrp == NULL) {
6054 #endif
6056 * Save of real name since were going to chop off the
6057 * trailing slashes.
6059 (void) strcpy(savename, fullname);
6061 * first strip of trailing slashes.
6063 chop_endslashes(savename);
6064 s = get_component(savename);
6065 (void) strcpy(component, s);
6067 #if defined(O_XATTR)
6068 } else {
6069 (void) strcpy(fullname, xattrp->h_names);
6070 (void) strcpy(dir, fullname);
6071 (void) strcpy(component, basename(xattrp->h_names +
6072 strlen(xattrp->h_names) + 1));
6074 #endif
6075 *namep = fullname;
6076 *dirp = dir;
6077 *compp = component;
6079 return (0);
6083 * Return true if the object indicated by the file descriptor and type
6084 * is a tape device, false otherwise
6087 static int
6088 istape(int fd, int type)
6090 int result = 0;
6092 if (S_ISCHR(type)) {
6093 struct mtget mtg;
6095 if (ioctl(fd, MTIOCGET, &mtg) != -1) {
6096 result = 1;
6100 return (result);
6103 #include <utmpx.h>
6105 struct utmpx utmpx;
6107 #define NMAX (sizeof (utmpx.ut_name))
6109 typedef struct cachenode { /* this struct must be zeroed before using */
6110 struct cachenode *next; /* next in hash chain */
6111 int val; /* the uid or gid of this entry */
6112 int namehash; /* name's hash signature */
6113 char name[NMAX+1]; /* the string that val maps to */
6114 } cachenode_t;
6116 #define HASHSIZE 256
6118 static cachenode_t *names[HASHSIZE];
6119 static cachenode_t *groups[HASHSIZE];
6120 static cachenode_t *uids[HASHSIZE];
6121 static cachenode_t *gids[HASHSIZE];
6123 static int
6124 hash_byname(char *name)
6126 int i, c, h = 0;
6128 for (i = 0; i < NMAX; i++) {
6129 c = name[i];
6130 if (c == '\0')
6131 break;
6132 h = (h << 4) + h + c;
6134 return (h);
6137 static cachenode_t *
6138 hash_lookup_byval(cachenode_t *table[], int val)
6140 int h = val;
6141 cachenode_t *c;
6143 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6144 if (c->val == val)
6145 return (c);
6147 return (NULL);
6150 static cachenode_t *
6151 hash_lookup_byname(cachenode_t *table[], char *name)
6153 int h = hash_byname(name);
6154 cachenode_t *c;
6156 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6157 if (c->namehash == h && strcmp(c->name, name) == 0)
6158 return (c);
6160 return (NULL);
6163 static cachenode_t *
6164 hash_insert(cachenode_t *table[], char *name, int value)
6166 cachenode_t *c;
6167 int signature;
6169 c = calloc(1, sizeof (cachenode_t));
6170 if (c == NULL) {
6171 perror("malloc");
6172 exit(1);
6174 if (name != NULL) {
6175 (void) strncpy(c->name, name, NMAX);
6176 c->namehash = hash_byname(name);
6178 c->val = value;
6179 if (table == uids || table == gids)
6180 signature = c->val;
6181 else
6182 signature = c->namehash;
6183 c->next = table[signature & (HASHSIZE - 1)];
6184 table[signature & (HASHSIZE - 1)] = c;
6185 return (c);
6188 static char *
6189 getname(uid_t uid)
6191 cachenode_t *c;
6193 if ((c = hash_lookup_byval(uids, uid)) == NULL) {
6194 struct passwd *pwent = getpwuid(uid);
6195 c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
6197 return (c->name);
6200 static char *
6201 getgroup(gid_t gid)
6203 cachenode_t *c;
6205 if ((c = hash_lookup_byval(gids, gid)) == NULL) {
6206 struct group *grent = getgrgid(gid);
6207 c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
6209 return (c->name);
6212 static uid_t
6213 getuidbyname(char *name)
6215 cachenode_t *c;
6217 if ((c = hash_lookup_byname(names, name)) == NULL) {
6218 struct passwd *pwent = getpwnam(name);
6219 c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
6221 return ((uid_t)c->val);
6224 static gid_t
6225 getgidbyname(char *group)
6227 cachenode_t *c;
6229 if ((c = hash_lookup_byname(groups, group)) == NULL) {
6230 struct group *grent = getgrnam(group);
6231 c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
6233 return ((gid_t)c->val);
6237 * Build the header.
6238 * Determine whether or not an extended header is also needed. If needed,
6239 * create and write the extended header and its data.
6240 * Writing of the extended header assumes that "tomodes" has been called and
6241 * the relevant information has been placed in the header block.
6244 static int
6245 build_dblock(
6246 const char *name,
6247 const char *linkname,
6248 const char typeflag,
6249 const int filetype,
6250 const struct stat *sp,
6251 const dev_t device,
6252 const char *prefix)
6254 int nblks;
6255 major_t dev;
6256 const char *filename;
6257 const char *lastslash;
6259 if (filetype == XATTR_FILE)
6260 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
6261 else
6262 dblock.dbuf.typeflag = typeflag;
6263 (void) memset(dblock.dbuf.name, '\0', NAMSIZ);
6264 (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
6265 (void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
6267 if (xhdr_flgs & _X_PATH)
6268 filename = Xtarhdr.x_path;
6269 else
6270 filename = name;
6272 if ((dev = major(device)) > OCTAL7CHAR) {
6273 if (Eflag) {
6274 xhdr_flgs |= _X_DEVMAJOR;
6275 Xtarhdr.x_devmajor = dev;
6276 } else {
6277 (void) fprintf(stderr, gettext(
6278 "Device major too large for %s. Use -E flag."),
6279 filename);
6280 if (errflag)
6281 done(1);
6282 else
6283 Errflg = 1;
6285 dev = 0;
6287 (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
6288 if ((dev = minor(device)) > OCTAL7CHAR) {
6289 if (Eflag) {
6290 xhdr_flgs |= _X_DEVMINOR;
6291 Xtarhdr.x_devminor = dev;
6292 } else {
6293 (void) fprintf(stderr, gettext(
6294 "Device minor too large for %s. Use -E flag."),
6295 filename);
6296 if (errflag)
6297 done(1);
6298 else
6299 Errflg = 1;
6301 dev = 0;
6303 (void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
6305 (void) strncpy(dblock.dbuf.name, name, NAMSIZ);
6306 (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
6307 (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
6308 (void) sprintf(dblock.dbuf.version, "00");
6309 (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
6310 (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
6311 (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
6312 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
6314 if (Eflag) {
6315 (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
6316 (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
6317 lastslash = strrchr(name, '/');
6318 if (lastslash == NULL)
6319 lastslash = name;
6320 else
6321 lastslash++;
6322 (void) strcpy(xhdr_buf.dbuf.name, lastslash);
6323 (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
6324 (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
6325 (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
6326 xhdr_count++;
6327 xrec_offset = 0;
6328 gen_date("mtime", sp->st_mtim);
6329 xhdr_buf.dbuf.typeflag = 'X';
6330 if (gen_utf8_names(filename) != 0)
6331 return (1);
6333 #ifdef XHDR_DEBUG
6334 Xtarhdr.x_uname = dblock.dbuf.uname;
6335 Xtarhdr.x_gname = dblock.dbuf.gname;
6336 xhdr_flgs |= (_X_UNAME | _X_GNAME);
6337 #endif
6338 if (xhdr_flgs) {
6339 if (xhdr_flgs & _X_DEVMAJOR)
6340 gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
6341 if (xhdr_flgs & _X_DEVMINOR)
6342 gen_num("SUN.devminor", Xtarhdr.x_devminor);
6343 if (xhdr_flgs & _X_GID)
6344 gen_num("gid", Xtarhdr.x_gid);
6345 if (xhdr_flgs & _X_UID)
6346 gen_num("uid", Xtarhdr.x_uid);
6347 if (xhdr_flgs & _X_SIZE)
6348 gen_num("size", Xtarhdr.x_filesz);
6349 if (xhdr_flgs & _X_PATH)
6350 gen_string("path", Xtarhdr.x_path);
6351 if (xhdr_flgs & _X_LINKPATH)
6352 gen_string("linkpath", Xtarhdr.x_linkpath);
6353 if (xhdr_flgs & _X_GNAME)
6354 gen_string("gname", Xtarhdr.x_gname);
6355 if (xhdr_flgs & _X_UNAME)
6356 gen_string("uname", Xtarhdr.x_uname);
6358 (void) sprintf(xhdr_buf.dbuf.size,
6359 "%011" FMT_off_t_o, xrec_offset);
6360 (void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
6361 checksum(&xhdr_buf));
6362 (void) writetbuf((char *)&xhdr_buf, 1);
6363 nblks = TBLOCKS(xrec_offset);
6364 (void) writetbuf(xrec_ptr, nblks);
6366 return (0);
6371 * makeDir - ensure that a directory with the pathname denoted by name
6372 * exists, and return 1 on success, and 0 on failure (e.g.,
6373 * read-only file system, exists but not-a-directory).
6376 static int
6377 makeDir(char *name)
6379 struct stat buf;
6381 if (access(name, 0) < 0) { /* name doesn't exist */
6382 if (mkdir(name, 0777) < 0) {
6383 vperror(0, "%s", name);
6384 return (0);
6386 } else { /* name exists */
6387 if (stat(name, &buf) < 0) {
6388 vperror(0, "%s", name);
6389 return (0);
6392 return ((buf.st_mode & S_IFMT) == S_IFDIR);
6395 return (1);
6400 * Save this directory and its mtime on the stack, popping and setting
6401 * the mtimes of any stacked dirs which aren't parents of this one.
6402 * A null name causes the entire stack to be unwound and set.
6404 * Since all the elements of the directory "stack" share a common
6405 * prefix, we can make do with one string. We keep only the current
6406 * directory path, with an associated array of mtime's. A negative
6407 * mtime means no mtime.
6409 * This stack algorithm is not guaranteed to work for tapes created
6410 * with the 'r' function letter, but the vast majority of tapes with
6411 * directories are not. This avoids saving every directory record on
6412 * the tape and setting all the times at the end.
6414 * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6415 * environment)
6418 static void
6419 doDirTimes(char *name, timestruc_t modTime)
6421 static char dirstack[PATH_MAX+2];
6422 /* Add spaces for the last slash and last NULL */
6423 static timestruc_t modtimes[PATH_MAX+1]; /* hash table */
6424 char *p = dirstack;
6425 char *q = name;
6426 char *savp;
6428 if (q) {
6430 * Find common prefix
6433 while (*p == *q && *p) {
6434 p++; q++;
6438 savp = p;
6439 while (*p) {
6441 * Not a child: unwind the stack, setting the times.
6442 * The order we do this doesn't matter, so we go "forward."
6445 if (*p == '/')
6446 if (modtimes[p - dirstack].tv_sec >= 0) {
6447 *p = '\0'; /* zap the slash */
6448 setPathTimes(AT_FDCWD, dirstack,
6449 modtimes[p - dirstack]);
6450 *p = '/';
6452 ++p;
6455 p = savp;
6458 * Push this one on the "stack"
6461 if (q) {
6464 * Since the name parameter points the dir pathname
6465 * which is limited only to contain PATH_MAX chars
6466 * at maximum, we can ignore the overflow case of p.
6469 while ((*p = *q++)) { /* append the rest of the new dir */
6470 modtimes[p - dirstack].tv_sec = -1;
6471 p++;
6475 * If the tar file had used 'P' or 'E' function modifier,
6476 * append the last slash.
6478 if (*(p - 1) != '/') {
6479 *p++ = '/';
6480 *p = '\0';
6482 /* overwrite the last one */
6483 modtimes[p - dirstack - 1] = modTime;
6489 * setPathTimes - set the modification time for given path. Return 1 if
6490 * successful and 0 if not successful.
6493 static void
6494 setPathTimes(int dirfd, char *path, timestruc_t modTime)
6496 struct timeval timebuf[2];
6499 * futimesat takes an array of two timeval structs.
6500 * The first entry contains access time.
6501 * The second entry contains modification time.
6502 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6503 * microseconds.
6505 timebuf[0].tv_sec = time((time_t *)0);
6506 timebuf[0].tv_usec = 0;
6507 timebuf[1].tv_sec = modTime.tv_sec;
6509 /* Extended header: use microseconds */
6510 timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
6512 if (futimesat(dirfd, path, timebuf) < 0)
6513 vperror(0, gettext("can't set time on %s"), path);
6518 * If hflag is set then delete the symbolic link's target.
6519 * If !hflag then delete the target.
6522 static void
6523 delete_target(int fd, char *comp, char *namep)
6525 struct stat xtractbuf;
6526 char buf[PATH_MAX + 1];
6527 int n;
6530 if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
6531 if (errno == ENOTDIR && !hflag) {
6532 (void) unlinkat(fd, comp, 0);
6533 } else if (errno == ENOTDIR && hflag) {
6534 if (!lstat(namep, &xtractbuf)) {
6535 if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
6536 (void) unlinkat(fd, comp, 0);
6537 } else if ((n = readlink(namep, buf,
6538 PATH_MAX)) != -1) {
6539 buf[n] = '\0';
6540 (void) unlinkat(fd, buf,
6541 AT_REMOVEDIR);
6542 if (errno == ENOTDIR)
6543 (void) unlinkat(fd, buf, 0);
6544 } else {
6545 (void) unlinkat(fd, comp, 0);
6547 } else {
6548 (void) unlinkat(fd, comp, 0);
6556 * ACL changes:
6557 * putfile():
6558 * Get acl info after stat. Write out ancillary file
6559 * before the normal file, i.e. directory, regular, FIFO,
6560 * link, special. If acl count is less than 4, no need to
6561 * create ancillary file. (i.e. standard permission is in
6562 * use.
6563 * doxtract():
6564 * Process ancillary file. Read it in and set acl info.
6565 * watch out for 'o' function modifier.
6566 * 't' function letter to display table
6570 * New functions for ACLs and other security attributes
6574 * The function appends the new security attribute info to the end of
6575 * existing secinfo.
6578 append_secattr(
6579 char **secinfo, /* existing security info */
6580 int *secinfo_len, /* length of existing security info */
6581 int size, /* new attribute size: unit depends on type */
6582 char *attrtext, /* new attribute text */
6583 char attr_type) /* new attribute type */
6585 char *new_secinfo;
6586 int newattrsize;
6587 int oldsize;
6588 struct sec_attr *attr;
6590 if (attrtext == NULL)
6591 return (0);
6593 switch (attr_type) {
6594 case UFSD_ACL:
6595 case ACE_ACL:
6596 if (attrtext == NULL) {
6597 (void) fprintf(stderr, gettext("acltotext failed\n"));
6598 return (-1);
6600 /* header: type + size = 8 */
6601 newattrsize = 8 + (int)strlen(attrtext) + 1;
6602 attr = (struct sec_attr *)malloc(newattrsize);
6603 if (attr == NULL) {
6604 (void) fprintf(stderr,
6605 gettext("can't allocate memory\n"));
6606 return (-1);
6608 attr->attr_type = attr_type;
6609 (void) sprintf(attr->attr_len,
6610 "%06o", size); /* acl entry count */
6611 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6612 free(attrtext);
6613 break;
6614 default:
6615 (void) fprintf(stderr,
6616 gettext("unrecognized attribute type\n"));
6617 return (-1);
6620 /* old security info + new attr header(8) + new attr */
6621 oldsize = *secinfo_len;
6622 *secinfo_len += newattrsize;
6623 new_secinfo = (char *)malloc(*secinfo_len);
6624 if (new_secinfo == NULL) {
6625 (void) fprintf(stderr, gettext("can't allocate memory\n"));
6626 *secinfo_len -= newattrsize;
6627 free(attr);
6628 return (-1);
6631 (void) memcpy(new_secinfo, *secinfo, oldsize);
6632 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6634 free(*secinfo);
6635 free(attr);
6636 *secinfo = new_secinfo;
6637 return (0);
6641 * write_ancillary(): write out an ancillary file.
6642 * The file has the same header as normal file except the type and size
6643 * fields. The type is 'A' and size is the sum of all attributes
6644 * in bytes.
6645 * The body contains a list of attribute type, size and info. Currently,
6646 * there is only ACL info. This file is put before the normal file.
6648 void
6649 write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
6651 long blocks;
6652 int savflag;
6653 int savsize;
6655 /* Just tranditional permissions or no security attribute info */
6656 if (len == 0 || secinfo == NULL)
6657 return;
6659 /* save flag and size */
6660 savflag = (dblockp->dbuf).typeflag;
6661 (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
6663 /* special flag for ancillary file */
6664 if (hdrtype == _XATTR_HDRTYPE)
6665 dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
6666 else
6667 dblockp->dbuf.typeflag = 'A';
6669 /* for pre-2.5 versions of tar, need to make sure */
6670 /* the ACL file is readable */
6671 (void) sprintf(dblock.dbuf.mode, "%07lo",
6672 (stbuf.st_mode & POSIXMODES) | 0000200);
6673 (void) sprintf(dblockp->dbuf.size, "%011o", len);
6674 (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
6676 /* write out the header */
6677 (void) writetbuf((char *)dblockp, 1);
6679 /* write out security info */
6680 blocks = TBLOCKS(len);
6681 (void) writetbuf((char *)secinfo, (int)blocks);
6683 /* restore mode, flag and size */
6684 (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
6685 dblockp->dbuf.typeflag = savflag;
6686 (void) sprintf(dblockp->dbuf.size, "%011o", savsize);
6690 * Read the data record for extended headers and then the regular header.
6691 * The data are read into the buffer and then null-terminated. Entries
6692 * for typeflag 'X' extended headers are of the format:
6693 * "%d %s=%s\n"
6695 * When an extended header record is found, the extended header must
6696 * be processed and its values used to override the values in the
6697 * normal header. The way this is done is to process the extended
6698 * header data record and set the data values, then call getdir
6699 * to process the regular header, then then to reconcile the two
6700 * sets of data.
6703 static int
6704 get_xdata(void)
6706 struct keylist_pair {
6707 int keynum;
6708 char *keylist;
6709 } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor",
6710 _X_DEVMINOR, "SUN.devminor",
6711 _X_GID, "gid",
6712 _X_GNAME, "gname",
6713 _X_LINKPATH, "linkpath",
6714 _X_PATH, "path",
6715 _X_SIZE, "size",
6716 _X_UID, "uid",
6717 _X_UNAME, "uname",
6718 _X_MTIME, "mtime",
6719 _X_LAST, "NULL" };
6720 char *lineloc;
6721 int length, i;
6722 char *keyword, *value;
6723 blkcnt_t nblocks;
6724 int bufneeded;
6725 int errors;
6727 (void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
6728 xhdr_count++;
6729 errors = 0;
6731 nblocks = TBLOCKS(stbuf.st_size);
6732 bufneeded = nblocks * TBLOCK;
6733 if (bufneeded >= xrec_size) {
6734 free(xrec_ptr);
6735 xrec_size = bufneeded + 1;
6736 if ((xrec_ptr = malloc(xrec_size)) == NULL)
6737 fatal(gettext("cannot allocate buffer"));
6740 lineloc = xrec_ptr;
6742 while (nblocks-- > 0) {
6743 readtape(lineloc);
6744 lineloc += TBLOCK;
6746 lineloc = xrec_ptr;
6747 xrec_ptr[stbuf.st_size] = '\0';
6748 while (lineloc < xrec_ptr + stbuf.st_size) {
6749 if (dblock.dbuf.typeflag == 'L') {
6750 length = xrec_size;
6751 keyword = "path";
6752 value = lineloc;
6753 } else {
6754 length = atoi(lineloc);
6755 *(lineloc + length - 1) = '\0';
6756 keyword = strchr(lineloc, ' ') + 1;
6757 value = strchr(keyword, '=') + 1;
6758 *(value - 1) = '\0';
6760 i = 0;
6761 lineloc += length;
6762 while (keylist_pair[i].keynum != (int)_X_LAST) {
6763 if (strcmp(keyword, keylist_pair[i].keylist) == 0)
6764 break;
6765 i++;
6767 errno = 0;
6768 switch (keylist_pair[i].keynum) {
6769 case _X_DEVMAJOR:
6770 Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
6771 if (errno) {
6772 (void) fprintf(stderr, gettext(
6773 "tar: Extended header major value error "
6774 "for file # %llu.\n"), xhdr_count);
6775 errors++;
6776 } else
6777 xhdr_flgs |= _X_DEVMAJOR;
6778 break;
6779 case _X_DEVMINOR:
6780 Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
6781 if (errno) {
6782 (void) fprintf(stderr, gettext(
6783 "tar: Extended header minor value error "
6784 "for file # %llu.\n"), xhdr_count);
6785 errors++;
6786 } else
6787 xhdr_flgs |= _X_DEVMINOR;
6788 break;
6789 case _X_GID:
6790 xhdr_flgs |= _X_GID;
6791 Xtarhdr.x_gid = strtol(value, NULL, 0);
6792 if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
6793 (void) fprintf(stderr, gettext(
6794 "tar: Extended header gid value error "
6795 "for file # %llu.\n"), xhdr_count);
6796 Xtarhdr.x_gid = GID_NOBODY;
6798 break;
6799 case _X_GNAME:
6800 if (utf8_local("gname", &Xtarhdr.x_gname,
6801 local_gname, value, _POSIX_NAME_MAX) == 0)
6802 xhdr_flgs |= _X_GNAME;
6803 break;
6804 case _X_LINKPATH:
6805 if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
6806 local_linkpath, value, PATH_MAX) == 0)
6807 xhdr_flgs |= _X_LINKPATH;
6808 else
6809 errors++;
6810 break;
6811 case _X_PATH:
6812 if (utf8_local("path", &Xtarhdr.x_path,
6813 local_path, value, PATH_MAX) == 0)
6814 xhdr_flgs |= _X_PATH;
6815 else
6816 errors++;
6817 break;
6818 case _X_SIZE:
6819 Xtarhdr.x_filesz = strtoull(value, NULL, 0);
6820 if (errno) {
6821 (void) fprintf(stderr, gettext(
6822 "tar: Extended header invalid filesize "
6823 "for file # %llu.\n"), xhdr_count);
6824 errors++;
6825 } else
6826 xhdr_flgs |= _X_SIZE;
6827 break;
6828 case _X_UID:
6829 xhdr_flgs |= _X_UID;
6830 Xtarhdr.x_uid = strtol(value, NULL, 0);
6831 if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
6832 (void) fprintf(stderr, gettext(
6833 "tar: Extended header uid value error "
6834 "for file # %llu.\n"), xhdr_count);
6835 Xtarhdr.x_uid = UID_NOBODY;
6837 break;
6838 case _X_UNAME:
6839 if (utf8_local("uname", &Xtarhdr.x_uname,
6840 local_uname, value, _POSIX_NAME_MAX) == 0)
6841 xhdr_flgs |= _X_UNAME;
6842 break;
6843 case _X_MTIME:
6844 get_xtime(value, &(Xtarhdr.x_mtime));
6845 if (errno)
6846 (void) fprintf(stderr, gettext(
6847 "tar: Extended header modification time "
6848 "value error for file # %llu.\n"),
6849 xhdr_count);
6850 else
6851 xhdr_flgs |= _X_MTIME;
6852 break;
6853 default:
6854 (void) fprintf(stderr,
6855 gettext("tar: unrecognized extended"
6856 " header keyword '%s'. Ignored.\n"), keyword);
6857 break;
6861 getdir(); /* get regular header */
6862 if (errors && errflag)
6863 done(1);
6864 else
6865 if (errors)
6866 Errflg = 1;
6867 return (errors);
6871 * load_info_from_xtarhdr - sets Gen and stbuf variables from
6872 * extended header
6873 * load_info_from_xtarhdr(flag, xhdrp);
6874 * u_longlong_t flag; xhdr_flgs
6875 * struct xtar_hdr *xhdrp; pointer to extended header
6876 * NOTE: called when typeflag is not 'A' and xhdr_flgs
6877 * is set.
6879 static void
6880 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
6882 if (flag & _X_DEVMAJOR) {
6883 Gen.g_devmajor = xhdrp->x_devmajor;
6885 if (flag & _X_DEVMINOR) {
6886 Gen.g_devminor = xhdrp->x_devminor;
6888 if (flag & _X_GID) {
6889 Gen.g_gid = xhdrp->x_gid;
6890 stbuf.st_gid = xhdrp->x_gid;
6892 if (flag & _X_UID) {
6893 Gen.g_uid = xhdrp->x_uid;
6894 stbuf.st_uid = xhdrp->x_uid;
6896 if (flag & _X_SIZE) {
6897 Gen.g_filesz = xhdrp->x_filesz;
6898 stbuf.st_size = xhdrp->x_filesz;
6900 if (flag & _X_MTIME) {
6901 Gen.g_mtime = xhdrp->x_mtime.tv_sec;
6902 stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
6903 stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
6908 * gen_num creates a string from a keyword and an usigned long long in the
6909 * format: %d %s=%s\n
6910 * This is part of the extended header data record.
6913 void
6914 gen_num(const char *keyword, const u_longlong_t number)
6916 char save_val[ULONGLONG_MAX_DIGITS + 1];
6917 int len;
6918 char *curr_ptr;
6920 (void) sprintf(save_val, "%llu", number);
6922 * len = length of entire line, including itself. len will be
6923 * two digits. So, add the string lengths plus the length of len,
6924 * plus a blank, an equal sign, and a newline.
6926 len = strlen(save_val) + strlen(keyword) + 5;
6927 if (xrec_offset + len > xrec_size) {
6928 if (((curr_ptr = reallocarray(xrec_ptr, 2, xrec_size)) == NULL))
6929 fatal(gettext(
6930 "cannot allocate extended header buffer"));
6931 xrec_ptr = curr_ptr;
6932 xrec_size *= 2;
6934 (void) sprintf(&xrec_ptr[xrec_offset],
6935 "%d %s=%s\n", len, keyword, save_val);
6936 xrec_offset += len;
6940 * gen_date creates a string from a keyword and a timestruc_t in the
6941 * format: %d %s=%s\n
6942 * This is part of the extended header data record.
6943 * Currently, granularity is only microseconds, so the low-order three digits
6944 * will be truncated.
6947 void
6948 gen_date(const char *keyword, const timestruc_t time_value)
6950 /* Allow for <seconds>.<nanoseconds>\n */
6951 char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
6952 int len;
6953 char *curr_ptr;
6955 (void) sprintf(save_val, "%ld", time_value.tv_sec);
6956 len = strlen(save_val);
6957 save_val[len] = '.';
6958 (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
6961 * len = length of entire line, including itself. len will be
6962 * two digits. So, add the string lengths plus the length of len,
6963 * plus a blank, an equal sign, and a newline.
6965 len = strlen(save_val) + strlen(keyword) + 5;
6966 if (xrec_offset + len > xrec_size) {
6967 if (((curr_ptr = reallocarray(xrec_ptr, 2, xrec_size)) == NULL))
6968 fatal(gettext(
6969 "cannot allocate extended header buffer"));
6970 xrec_ptr = curr_ptr;
6971 xrec_size *= 2;
6973 (void) sprintf(&xrec_ptr[xrec_offset],
6974 "%d %s=%s\n", len, keyword, save_val);
6975 xrec_offset += len;
6979 * gen_string creates a string from a keyword and a char * in the
6980 * format: %d %s=%s\n
6981 * This is part of the extended header data record.
6984 void
6985 gen_string(const char *keyword, const char *value)
6987 int len;
6988 char *curr_ptr;
6991 * len = length of entire line, including itself. The character length
6992 * of len must be 1-4 characters, because the maximum size of the path
6993 * or the name is PATH_MAX, which is 1024. So, assume 1 character
6994 * for len, one for the space, one for the "=", and one for the newline.
6995 * Then adjust as needed.
6997 /* LINTED constant expression */
6998 assert(PATH_MAX <= 9996);
6999 len = strlen(value) + strlen(keyword) + 4;
7000 if (len > 997)
7001 len += 3;
7002 else if (len > 98)
7003 len += 2;
7004 else if (len > 9)
7005 len += 1;
7006 if (xrec_offset + len > xrec_size) {
7007 if (((curr_ptr = reallocarray(xrec_ptr, 2, xrec_size)) == NULL))
7008 fatal(gettext(
7009 "cannot allocate extended header buffer"));
7010 xrec_ptr = curr_ptr;
7011 xrec_size *= 2;
7013 #ifdef XHDR_DEBUG
7014 if (strcmp(keyword+1, "name") != 0)
7015 #endif
7016 (void) sprintf(&xrec_ptr[xrec_offset],
7017 "%d %s=%s\n", len, keyword, value);
7018 #ifdef XHDR_DEBUG
7019 else {
7020 len += 11;
7021 (void) sprintf(&xrec_ptr[xrec_offset],
7022 "%d %s=%snametoolong\n", len, keyword, value);
7024 #endif
7025 xrec_offset += len;
7029 * Convert time found in the extended header data to seconds and nanoseconds.
7032 void
7033 get_xtime(char *value, timestruc_t *xtime)
7035 char nanosec[10];
7036 char *period;
7037 int i;
7039 (void) memset(nanosec, '0', 9);
7040 nanosec[9] = '\0';
7042 period = strchr(value, '.');
7043 if (period != NULL)
7044 period[0] = '\0';
7045 xtime->tv_sec = strtol(value, NULL, 10);
7046 if (period == NULL)
7047 xtime->tv_nsec = 0;
7048 else {
7049 i = strlen(period +1);
7050 (void) strncpy(nanosec, period + 1, min(i, 9));
7051 xtime->tv_nsec = strtol(nanosec, NULL, 10);
7056 * Check linkpath for length.
7057 * Emit an error message and return 1 if too long.
7061 chk_path_build(
7062 char *name,
7063 char *longname,
7064 char *linkname,
7065 char *prefix,
7066 char type,
7067 int filetype)
7070 if (strlen(linkname) > (size_t)NAMSIZ) {
7071 if (Eflag > 0) {
7072 xhdr_flgs |= _X_LINKPATH;
7073 Xtarhdr.x_linkpath = linkname;
7074 } else {
7075 (void) fprintf(stderr, gettext(
7076 "tar: %s: linked to %s\n"), longname, linkname);
7077 (void) fprintf(stderr, gettext(
7078 "tar: %s: linked name too long\n"), linkname);
7079 if (errflag)
7080 done(1);
7081 else
7082 Errflg = 1;
7083 return (1);
7086 if (xhdr_flgs & _X_LINKPATH)
7087 return (build_dblock(name, tchar, type,
7088 filetype, &stbuf, stbuf.st_dev,
7089 prefix));
7090 else
7091 return (build_dblock(name, linkname, type,
7092 filetype, &stbuf, stbuf.st_dev, prefix));
7096 * Convert from UTF-8 to local character set.
7099 static int
7100 utf8_local(
7101 char *option,
7102 char **Xhdr_ptrptr,
7103 char *target,
7104 const char *source,
7105 int max_val)
7107 static iconv_t iconv_cd;
7108 char *nl_target;
7109 const char *iconv_src;
7110 char *iconv_trg;
7111 size_t inlen;
7112 size_t outlen;
7114 if (charset_type == -1) { /* iconv_open failed in earlier try */
7115 (void) fprintf(stderr, gettext(
7116 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7117 xhdr_count, source);
7118 return (1);
7119 } else if (charset_type == 0) { /* iconv_open has not yet been done */
7120 nl_target = nl_langinfo(CODESET);
7121 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7122 nl_target = "US-ASCII";
7123 if (strcmp(nl_target, "US-ASCII") == 0)
7124 charset_type = 1;
7125 else if (strcmp(nl_target, "UTF-8") == 0)
7126 charset_type = 3;
7127 else {
7128 if (strncmp(nl_target, "ISO", 3) == 0)
7129 nl_target += 3;
7130 charset_type = 2;
7131 errno = 0;
7132 if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
7133 (iconv_t)-1) {
7134 if (errno == EINVAL)
7135 (void) fprintf(stderr, gettext(
7136 "tar: conversion routines not "
7137 "available for current locale. "));
7138 (void) fprintf(stderr, gettext(
7139 "file # %llu: (%s) UTF-8 conversion"
7140 " failed.\n"), xhdr_count, source);
7141 charset_type = -1;
7142 return (1);
7147 /* locale using 7-bit codeset or UTF-8 locale */
7148 if (charset_type == 1 || charset_type == 3) {
7149 if (strlen(source) > max_val) {
7150 (void) fprintf(stderr, gettext(
7151 "tar: file # %llu: Extended header %s too long.\n"),
7152 xhdr_count, option);
7153 return (1);
7155 if (charset_type == 3)
7156 (void) strcpy(target, source);
7157 else if (c_utf8(target, source) != 0) {
7158 (void) fprintf(stderr, gettext(
7159 "tar: file # %llu: (%s) UTF-8 conversion"
7160 " failed.\n"), xhdr_count, source);
7161 return (1);
7163 *Xhdr_ptrptr = target;
7164 return (0);
7167 iconv_src = source;
7168 iconv_trg = target;
7169 inlen = strlen(source);
7170 outlen = max_val * UTF_8_FACTOR;
7171 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7172 (size_t)-1) { /* Error occurred: didn't convert */
7173 (void) fprintf(stderr, gettext(
7174 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7175 xhdr_count, source);
7176 /* Get remaining output; reinitialize conversion descriptor */
7177 iconv_src = (const char *)NULL;
7178 inlen = 0;
7179 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7180 return (1);
7182 /* Get remaining output; reinitialize conversion descriptor */
7183 iconv_src = (const char *)NULL;
7184 inlen = 0;
7185 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7186 (size_t)-1) { /* Error occurred: didn't convert */
7187 (void) fprintf(stderr, gettext(
7188 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7189 xhdr_count, source);
7190 return (1);
7193 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7194 if (strlen(target) > max_val) {
7195 (void) fprintf(stderr, gettext(
7196 "tar: file # %llu: Extended header %s too long.\n"),
7197 xhdr_count, option);
7198 return (1);
7200 *Xhdr_ptrptr = target;
7201 return (0);
7205 * Check gname, uname, path, and linkpath to see if they need to go in an
7206 * extended header. If they are already slated to be in an extended header,
7207 * or if they are not ascii, then they need to be in the extended header.
7208 * Then, convert all extended names to UTF-8.
7212 gen_utf8_names(const char *filename)
7214 static iconv_t iconv_cd;
7215 char *nl_target;
7216 char tempbuf[MAXNAM + 1];
7217 int nbytes;
7218 int errors;
7220 if (charset_type == -1) { /* Previous failure to open. */
7221 (void) fprintf(stderr, gettext(
7222 "tar: file # %llu: UTF-8 conversion failed.\n"),
7223 xhdr_count);
7224 return (1);
7227 if (charset_type == 0) { /* Need to get conversion descriptor */
7228 nl_target = nl_langinfo(CODESET);
7229 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7230 nl_target = "US-ASCII";
7231 if (strcmp(nl_target, "US-ASCII") == 0)
7232 charset_type = 1;
7233 else if (strcmp(nl_target, "UTF-8") == 0)
7234 charset_type = 3;
7235 else {
7236 if (strncmp(nl_target, "ISO", 3) == 0)
7237 nl_target += 3;
7238 charset_type = 2;
7239 errno = 0;
7240 #ifdef ICONV_DEBUG
7241 (void) fprintf(stderr,
7242 gettext("Opening iconv_cd with target %s\n"),
7243 nl_target);
7244 #endif
7245 if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
7246 (iconv_t)-1) {
7247 if (errno == EINVAL)
7248 (void) fprintf(stderr, gettext(
7249 "tar: conversion routines not "
7250 "available for current locale. "));
7251 (void) fprintf(stderr, gettext(
7252 "file (%s): UTF-8 conversion failed.\n"),
7253 filename);
7254 charset_type = -1;
7255 return (1);
7260 errors = 0;
7262 errors += local_utf8(&Xtarhdr.x_gname, local_gname,
7263 dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
7264 errors += local_utf8(&Xtarhdr.x_uname, local_uname,
7265 dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX);
7266 if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */
7267 (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
7268 tempbuf[NAMSIZ] = '\0';
7270 errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
7271 tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
7272 if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */
7273 (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
7274 tempbuf[PRESIZ] = '\0';
7275 nbytes = strlen(tempbuf);
7276 if (nbytes > 0) {
7277 tempbuf[nbytes++] = '/';
7278 tempbuf[nbytes] = '\0';
7280 (void) strncat(tempbuf + nbytes, dblock.dbuf.name,
7281 (MAXNAM - nbytes));
7282 tempbuf[MAXNAM] = '\0';
7284 errors += local_utf8(&Xtarhdr.x_path, local_path,
7285 tempbuf, iconv_cd, _X_PATH, PATH_MAX);
7287 if (errors > 0)
7288 (void) fprintf(stderr, gettext(
7289 "tar: file (%s): UTF-8 conversion failed.\n"), filename);
7291 if (errors && errflag)
7292 done(1);
7293 else
7294 if (errors)
7295 Errflg = 1;
7296 return (errors);
7299 static int
7300 local_utf8(
7301 char **Xhdr_ptrptr,
7302 char *target,
7303 const char *source,
7304 iconv_t iconv_cd,
7305 int xhdrflg,
7306 int max_val)
7308 const char *iconv_src;
7309 const char *starting_src;
7310 char *iconv_trg;
7311 size_t inlen;
7312 size_t outlen;
7313 #ifdef ICONV_DEBUG
7314 unsigned char c_to_hex;
7315 #endif
7318 * If the item is already slated for extended format, get the string
7319 * to convert from the extended header record. Otherwise, get it from
7320 * the regular (dblock) area.
7322 if (xhdr_flgs & xhdrflg) {
7323 if (charset_type == 3) { /* Already UTF-8, just copy */
7324 (void) strcpy(target, *Xhdr_ptrptr);
7325 *Xhdr_ptrptr = target;
7326 return (0);
7327 } else
7328 iconv_src = (const char *) *Xhdr_ptrptr;
7329 } else {
7330 if (charset_type == 3) /* Already in UTF-8 format */
7331 return (0); /* Don't create xhdr record */
7332 iconv_src = source;
7334 starting_src = iconv_src;
7335 iconv_trg = target;
7336 if ((inlen = strlen(iconv_src)) == 0)
7337 return (0);
7339 if (charset_type == 1) { /* locale using 7-bit codeset */
7340 if (c_utf8(target, starting_src) != 0) {
7341 (void) fprintf(stderr,
7342 gettext("tar: invalid character in"
7343 " UTF-8 conversion of '%s'\n"), starting_src);
7344 return (1);
7346 return (0);
7349 outlen = max_val * UTF_8_FACTOR;
7350 errno = 0;
7351 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7352 (size_t)-1) {
7353 /* An error occurred, or not all characters were converted */
7354 if (errno == EILSEQ)
7355 (void) fprintf(stderr,
7356 gettext("tar: invalid character in"
7357 " UTF-8 conversion of '%s'\n"), starting_src);
7358 else
7359 (void) fprintf(stderr, gettext(
7360 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7361 starting_src);
7362 /* Get remaining output; reinitialize conversion descriptor */
7363 iconv_src = (const char *)NULL;
7364 inlen = 0;
7365 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7366 return (1);
7368 /* Get remaining output; reinitialize conversion descriptor */
7369 iconv_src = (const char *)NULL;
7370 inlen = 0;
7371 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7372 (size_t)-1) { /* Error occurred: didn't convert */
7373 if (errno == EILSEQ)
7374 (void) fprintf(stderr,
7375 gettext("tar: invalid character in"
7376 " UTF-8 conversion of '%s'\n"), starting_src);
7377 else
7378 (void) fprintf(stderr, gettext(
7379 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7380 starting_src);
7381 return (1);
7384 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7385 if (strcmp(starting_src, target) != 0) {
7386 *Xhdr_ptrptr = target;
7387 xhdr_flgs |= xhdrflg;
7388 #ifdef ICONV_DEBUG
7389 (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n",
7390 strlen(starting_src), inlen, max_val, outlen);
7391 (void) fprintf(stderr, "Input string:\n ");
7392 for (inlen = 0; inlen < strlen(starting_src); inlen++) {
7393 c_to_hex = (unsigned char)starting_src[inlen];
7394 (void) fprintf(stderr, " %2.2x", c_to_hex);
7395 if (inlen % 20 == 19)
7396 (void) fprintf(stderr, "\n ");
7398 (void) fprintf(stderr, "\nOutput string:\n ");
7399 for (inlen = 0; inlen < strlen(target); inlen++) {
7400 c_to_hex = (unsigned char)target[inlen];
7401 (void) fprintf(stderr, " %2.2x", c_to_hex);
7402 if (inlen % 20 == 19)
7403 (void) fprintf(stderr, "\n ");
7405 (void) fprintf(stderr, "\n");
7406 #endif
7409 return (0);
7413 * Function to test each byte of the source string to make sure it is
7414 * in within bounds (value between 0 and 127).
7415 * If valid, copy source to target.
7419 c_utf8(char *target, const char *source)
7421 size_t len;
7422 const char *thischar;
7424 len = strlen(source);
7425 thischar = source;
7426 while (len-- > 0) {
7427 if (!isascii((int)(*thischar++)))
7428 return (1);
7431 (void) strcpy(target, source);
7432 return (0);
7436 #if defined(O_XATTR)
7437 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
7439 static void
7440 prepare_xattr(
7441 char **attrbuf,
7442 char *filename,
7443 char *attrpath,
7444 char typeflag,
7445 struct linkbuf *linkinfo,
7446 int *rlen)
7448 char *bufhead; /* ptr to full buffer */
7449 char *aptr;
7450 struct xattr_hdr *hptr; /* ptr to header in bufhead */
7451 struct xattr_buf *tptr; /* ptr to pathing pieces */
7452 int totalen; /* total buffer length */
7453 int len; /* length returned to user */
7454 int stringlen; /* length of filename + attr */
7456 * length of filename + attr
7457 * in link section
7459 int linkstringlen;
7460 int complen; /* length of pathing section */
7461 int linklen; /* length of link section */
7462 int attrnames_index; /* attrnames starting index */
7465 * Release previous buffer
7468 if (*attrbuf != NULL) {
7469 free(*attrbuf);
7470 *attrbuf = NULL;
7474 * First add in fixed size stuff
7476 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7479 * Add space for two nulls
7481 stringlen = strlen(attrpath) + strlen(filename) + 2;
7482 complen = stringlen + sizeof (struct xattr_buf);
7484 len += stringlen;
7487 * Now add on space for link info if any
7490 if (linkinfo != NULL) {
7492 * Again add space for two nulls
7494 linkstringlen = strlen(linkinfo->pathname) +
7495 strlen(linkinfo->attrname) + 2;
7496 linklen = linkstringlen + sizeof (struct xattr_buf);
7497 len += linklen;
7498 } else {
7499 linklen = 0;
7503 * Now add padding to end to fill out TBLOCK
7505 * Function returns size of real data and not size + padding.
7508 totalen = ROUNDTOTBLOCK(len);
7510 if ((bufhead = calloc(1, totalen)) == NULL) {
7511 fatal(gettext("Out of memory."));
7516 * Now we can fill in the necessary pieces
7520 * first fill in the fixed header
7522 hptr = (struct xattr_hdr *)bufhead;
7523 (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7524 (void) sprintf(hptr->h_component_len, "%0*d",
7525 sizeof (hptr->h_component_len) - 1, complen);
7526 (void) sprintf(hptr->h_link_component_len, "%0*d",
7527 sizeof (hptr->h_link_component_len) - 1, linklen);
7528 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7531 * Now fill in the filename + attrnames section
7532 * The filename and attrnames section can be composed of two or more
7533 * path segments separated by a null character. The first segment
7534 * is the path to the parent file that roots the entire sequence in
7535 * the normal name space. The remaining segments describes a path
7536 * rooted at the hidden extended attribute directory of the leaf file of
7537 * the previous segment, making it possible to name attributes on
7538 * attributes. Thus, if we are just archiving an extended attribute,
7539 * the second segment will contain the attribute name. If we are
7540 * archiving a system attribute of an extended attribute, then the
7541 * second segment will contain the attribute name, and a third segment
7542 * will contain the system attribute name. The attribute pathing
7543 * information is obtained from 'attrpath'.
7546 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7547 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7548 stringlen);
7549 (void) strcpy(tptr->h_names, filename);
7550 attrnames_index = strlen(filename) + 1;
7551 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
7552 tptr->h_typeflag = typeflag;
7555 * Split the attrnames section into two segments if 'attrpath'
7556 * contains pathing information for a system attribute of an
7557 * extended attribute. We split them by replacing the '/' with
7558 * a '\0'.
7560 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
7561 *aptr = '\0';
7565 * Now fill in the optional link section if we have one
7568 if (linkinfo != NULL) {
7569 tptr = (struct xattr_buf *)(bufhead +
7570 sizeof (struct xattr_hdr) + complen);
7572 (void) sprintf(tptr->h_namesz, "%0*d",
7573 sizeof (tptr->h_namesz) - 1, linkstringlen);
7574 (void) strcpy(tptr->h_names, linkinfo->pathname);
7575 (void) strcpy(
7576 &tptr->h_names[strlen(linkinfo->pathname) + 1],
7577 linkinfo->attrname);
7578 tptr->h_typeflag = typeflag;
7580 *attrbuf = (char *)bufhead;
7581 *rlen = len;
7584 #else
7585 static void
7586 prepare_xattr(
7587 char **attrbuf,
7588 char *filename,
7589 char *attrname,
7590 char typeflag,
7591 struct linkbuf *linkinfo,
7592 int *rlen)
7594 *attrbuf = NULL;
7595 *rlen = 0;
7597 #endif
7600 getstat(int dirfd, char *longname, char *shortname, char *attrparent)
7603 int i, j;
7604 int printerr;
7605 int slnkerr;
7606 struct stat symlnbuf;
7608 if (!hflag)
7609 i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
7610 else
7611 i = fstatat(dirfd, shortname, &stbuf, 0);
7613 if (i < 0) {
7614 /* Initialize flag to print error mesg. */
7615 printerr = 1;
7617 * If stat is done, then need to do lstat
7618 * to determine whether it's a sym link
7620 if (hflag) {
7621 /* Save returned error */
7622 slnkerr = errno;
7624 j = fstatat(dirfd, shortname,
7625 &symlnbuf, AT_SYMLINK_NOFOLLOW);
7627 * Suppress error message when file is a symbolic link
7628 * and function modifier 'l' is off. Exception: when
7629 * a symlink points to a symlink points to a
7630 * symlink ... and we get past MAXSYMLINKS. That
7631 * error will cause a file not to be archived, and
7632 * needs to be printed.
7634 if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
7635 (S_ISLNK(symlnbuf.st_mode)))
7636 printerr = 0;
7639 * Restore errno in case the lstat
7640 * on symbolic link change
7642 errno = slnkerr;
7645 if (printerr) {
7646 (void) fprintf(stderr, gettext(
7647 "tar: %s%s%s%s: %s\n"),
7648 (attrparent == NULL) ? "" : gettext("attribute "),
7649 (attrparent == NULL) ? "" : attrparent,
7650 (attrparent == NULL) ? "" : gettext(" of "),
7651 longname, strerror(errno));
7652 Errflg = 1;
7654 return (1);
7656 return (0);
7660 * Recursively archive the extended attributes and/or extended system attributes
7661 * of the base file, longname. Note: extended system attribute files will be
7662 * archived only if the extended system attributes are not transient (i.e. the
7663 * extended system attributes are other than the default values).
7665 * If -@ was specified and the underlying file system supports it, archive the
7666 * extended attributes, and if there is a system attribute associated with the
7667 * extended attribute, then recursively call xattrs_put() to archive the
7668 * hidden attribute directory and the extended system attribute. If -/ was
7669 * specified and the underlying file system supports it, archive the extended
7670 * system attributes. Read-only extended system attributes are never archived.
7672 * Currently, there cannot be attributes on attributes; only system
7673 * attributes on attributes. In addition, there cannot be attributes on
7674 * system attributes. A file and it's attribute directory hierarchy looks as
7675 * follows:
7676 * longname ----> . ("." is the hidden attribute directory)
7678 * ----------------------------
7679 * | |
7680 * <sys_attr_name> <attr_name> ----> .
7682 * <sys_attr_name>
7685 #if defined(O_XATTR)
7686 static void
7687 xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
7689 char *filename = (attrparent == NULL) ? shortname : attrparent;
7690 int arc_rwsysattr = 0;
7691 int dirfd;
7692 int fd = -1;
7693 int rw_sysattr = 0;
7694 int ext_attr = 0;
7695 int rc;
7696 DIR *dirp;
7697 struct dirent *dp;
7698 attr_data_t *attrinfo = NULL;
7701 * If the underlying file system supports it, then archive the extended
7702 * attributes if -@ was specified, and the extended system attributes
7703 * if -/ was specified.
7705 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
7706 &ext_attr) != ATTR_OK) {
7707 return;
7711 * Only want to archive a read-write extended system attribute file
7712 * if it contains extended system attribute settings that are not the
7713 * default values.
7715 #if defined(_PC_SATTR_ENABLED)
7716 if (saflag) {
7717 int filefd;
7718 nvlist_t *slist = NULL;
7720 /* Determine if there are non-transient system attributes */
7721 errno = 0;
7722 if ((filefd = open(filename, O_RDONLY)) == -1) {
7723 if (attrparent == NULL) {
7724 vperror(0, gettext(
7725 "unable to open file %s"), longname);
7727 return;
7729 if (((slist = sysattr_list(basename(myname), filefd,
7730 filename)) != NULL) || (errno != 0)) {
7731 arc_rwsysattr = 1;
7733 if (slist != NULL) {
7734 (void) nvlist_free(slist);
7735 slist = NULL;
7737 (void) close(filefd);
7741 * If we aren't archiving extended system attributes, and we are
7742 * processing an attribute, or if we are archiving extended system
7743 * attributes, and there are are no extended attributes, then there's
7744 * no need to open up the attribute directory of the file unless the
7745 * extended system attributes are not transient (i.e, the system
7746 * attributes are not the default values).
7748 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
7749 (saflag && !ext_attr))) {
7750 return;
7752 #endif /* _PC_SATTR_ENABLED */
7754 /* open the parent attribute directory */
7755 fd = attropen(filename, ".", O_RDONLY);
7756 if (fd < 0) {
7757 vperror(0, gettext(
7758 "unable to open attribute directory for %s%s%sfile %s"),
7759 (attrparent == NULL) ? "" : gettext("attribute "),
7760 (attrparent == NULL) ? "" : attrparent,
7761 (attrparent == NULL) ? "" : gettext(" of "),
7762 longname);
7763 return;
7767 * We need to change into the parent's attribute directory to determine
7768 * if each of the attributes should be archived.
7770 if (fchdir(fd) < 0) {
7771 vperror(0, gettext(
7772 "cannot change to attribute directory of %s%s%sfile %s"),
7773 (attrparent == NULL) ? "" : gettext("attribute "),
7774 (attrparent == NULL) ? "" : attrparent,
7775 (attrparent == NULL) ? "" : gettext(" of "),
7776 longname);
7777 (void) close(fd);
7778 return;
7781 if (((dirfd = dup(fd)) == -1) ||
7782 ((dirp = fdopendir(dirfd)) == NULL)) {
7783 (void) fprintf(stderr, gettext(
7784 "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7785 (attrparent == NULL) ? "" : gettext("attribute "),
7786 (attrparent == NULL) ? "" : attrparent,
7787 (attrparent == NULL) ? "" : gettext(" of "),
7788 longname);
7789 if (fd > 0) {
7790 (void) close(fd);
7792 return;
7795 while ((dp = readdir(dirp)) != NULL) {
7796 if (strcmp(dp->d_name, "..") == 0) {
7797 continue;
7798 } else if (strcmp(dp->d_name, ".") == 0) {
7799 Hiddendir = 1;
7800 } else {
7801 Hiddendir = 0;
7804 /* Determine if this attribute should be archived */
7805 if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
7806 &rw_sysattr) != ATTR_OK) {
7807 continue;
7810 /* gather the attribute's information to pass to putfile() */
7811 if ((fill_in_attr_info(dp->d_name, longname, attrparent,
7812 fd, rw_sysattr, &attrinfo)) == 1) {
7813 continue;
7816 /* add the attribute to the archive */
7817 rc = putfile(longname, dp->d_name, parent, attrinfo,
7818 XATTR_FILE, LEV0, SYMLINK_LEV0);
7820 if (exitflag) {
7821 break;
7824 #if defined(_PC_SATTR_ENABLED)
7826 * If both -/ and -@ were specified, then archive the
7827 * attribute's extended system attributes and hidden directory
7828 * by making a recursive call to xattrs_put().
7830 if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
7831 (Hiddendir == 0)) {
7833 xattrs_put(longname, shortname, parent, dp->d_name);
7836 * Change back to the parent's attribute directory
7837 * to process any further attributes.
7839 if (fchdir(fd) < 0) {
7840 vperror(0, gettext(
7841 "cannot change back to attribute directory "
7842 "of file %s"), longname);
7843 break;
7846 #endif /* _PC_SATTR_ENABLED */
7849 if (attrinfo != NULL) {
7850 if (attrinfo->attr_parent != NULL) {
7851 free(attrinfo->attr_parent);
7853 free(attrinfo->attr_path);
7854 free(attrinfo);
7856 (void) closedir(dirp);
7857 if (fd != -1) {
7858 (void) close(fd);
7861 /* Change back to the parent directory of the base file */
7862 if (attrparent == NULL) {
7863 (void) tar_chdir(parent);
7865 Hiddendir = 0;
7867 #else
7868 static void
7869 xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
7872 #endif /* O_XATTR */
7874 static int
7875 put_link(char *name, char *longname, char *component, char *longattrname,
7876 char *prefix, int filetype, char type)
7879 if (stbuf.st_nlink > 1) {
7880 struct linkbuf *lp;
7881 int found = 0;
7883 for (lp = ihead; lp != NULL; lp = lp->nextp)
7884 if (lp->inum == stbuf.st_ino &&
7885 lp->devnum == stbuf.st_dev) {
7886 found++;
7887 break;
7889 if (found) {
7890 #if defined(O_XATTR)
7891 if (filetype == XATTR_FILE)
7892 if (put_xattr_hdr(longname, component,
7893 longattrname, prefix, type, filetype, lp)) {
7894 goto out;
7896 #endif
7897 stbuf.st_size = (off_t)0;
7898 if (filetype != XATTR_FILE) {
7899 tomodes(&stbuf);
7900 if (chk_path_build(name, longname, lp->pathname,
7901 prefix, type, filetype) > 0) {
7902 goto out;
7906 if (mulvol && tapepos + 1 >= blocklim)
7907 newvol();
7908 (void) writetbuf((char *)&dblock, 1);
7910 * write_ancillary() is not needed here.
7911 * The first link is handled in the following
7912 * else statement. No need to process ACLs
7913 * for other hard links since they are the
7914 * same file.
7917 if (vflag) {
7918 if (NotTape)
7919 dlog("seek = %" FMT_blkcnt_t
7920 "K\n", K(tapepos));
7921 if (filetype == XATTR_FILE) {
7922 (void) fprintf(vfile, gettext(
7923 "a %s attribute %s link to "
7924 "%s attribute %s\n"),
7925 name, component, name,
7926 lp->attrname);
7927 } else {
7928 (void) fprintf(vfile, gettext(
7929 "a %s link to %s\n"),
7930 longname, lp->pathname);
7933 lp->count--;
7934 return (0);
7935 } else {
7936 lp = (struct linkbuf *)getmem(sizeof (*lp));
7937 if (lp != NULL) {
7938 lp->nextp = ihead;
7939 ihead = lp;
7940 lp->inum = stbuf.st_ino;
7941 lp->devnum = stbuf.st_dev;
7942 lp->count = stbuf.st_nlink - 1;
7943 if (filetype == XATTR_FILE) {
7944 (void) strcpy(lp->pathname, longname);
7945 (void) strcpy(lp->attrname,
7946 component);
7947 } else {
7948 (void) strcpy(lp->pathname, longname);
7949 (void) strcpy(lp->attrname, "");
7955 out:
7956 return (1);
7959 static int
7960 put_extra_attributes(char *longname, char *shortname, char *longattrname,
7961 char *prefix, int filetype, char typeflag)
7963 static acl_t *aclp = NULL;
7964 int error;
7966 if (aclp != NULL) {
7967 acl_free(aclp);
7968 aclp = NULL;
7970 #if defined(O_XATTR)
7971 if ((atflag || saflag) && (filetype == XATTR_FILE)) {
7972 if (put_xattr_hdr(longname, shortname, longattrname, prefix,
7973 typeflag, filetype, NULL)) {
7974 return (1);
7977 #endif
7979 /* ACL support */
7980 if (pflag) {
7981 char *secinfo = NULL;
7982 int len = 0;
7984 /* ACL support */
7985 if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
7987 * Get ACL info: dont bother allocating space if
7988 * there is only a trivial ACL.
7990 if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
7991 &aclp)) != 0) {
7992 (void) fprintf(stderr, gettext(
7993 "%s: failed to retrieve acl : %s\n"),
7994 longname, acl_strerror(error));
7995 return (1);
7999 /* append security attributes if any */
8000 if (aclp != NULL) {
8001 (void) append_secattr(&secinfo, &len, acl_cnt(aclp),
8002 acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8003 ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
8004 UFSD_ACL : ACE_ACL);
8007 if (aclp != NULL) {
8008 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8011 return (0);
8014 #if defined(O_XATTR)
8015 static int
8016 put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
8017 int typeflag, int filetype, struct linkbuf *lp)
8019 char *lname = NULL;
8020 char *sname = NULL;
8021 int error = 0;
8022 static char *attrbuf = NULL;
8023 int attrlen;
8025 lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
8026 strlen(shortname) + strlen(".hdr") + 1);
8028 if (lname == NULL) {
8029 fatal(gettext("Out of Memory."));
8031 sname = malloc(sizeof (char) * strlen(shortname) +
8032 strlen(".hdr") + 1);
8033 if (sname == NULL) {
8034 fatal(gettext("Out of Memory."));
8037 (void) sprintf(sname, "%s.hdr", shortname);
8038 (void) sprintf(lname, "/dev/null/%s", sname);
8040 if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
8041 sizeof (dblock.dbuf.name)) {
8042 fatal(gettext(
8043 "Buffer overflow writing extended attribute file name"));
8047 * dump extended attr lookup info
8049 prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
8050 write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
8052 (void) sprintf(lname, "/dev/null/%s", shortname);
8053 (void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
8056 * Set up filename for attribute
8059 error = build_dblock(lname, tchar, '0', filetype,
8060 &stbuf, stbuf.st_dev, prefix);
8061 free(lname);
8062 free(sname);
8064 return (error);
8066 #endif
8068 #if defined(O_XATTR)
8069 static int
8070 read_xattr_hdr(attr_data_t **attrinfo)
8072 char buf[TBLOCK];
8073 char *attrparent = NULL;
8074 blkcnt_t blocks;
8075 char *tp;
8076 off_t bytes;
8077 int comp_len, link_len;
8078 int namelen;
8079 int attrparentlen;
8080 int parentfilelen;
8082 if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
8083 return (1);
8085 bytes = stbuf.st_size;
8086 if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
8087 (void) fprintf(stderr, gettext(
8088 "Insufficient memory for extended attribute\n"));
8089 return (1);
8092 tp = (char *)xattrhead;
8093 blocks = TBLOCKS(bytes);
8094 while (blocks-- > 0) {
8095 readtape(buf);
8096 if (bytes <= TBLOCK) {
8097 (void) memcpy(tp, buf, (size_t)bytes);
8098 break;
8099 } else {
8100 (void) memcpy(tp, buf, TBLOCK);
8101 tp += TBLOCK;
8103 bytes -= TBLOCK;
8107 * Validate that we can handle header format
8109 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8110 (void) fprintf(stderr,
8111 gettext("Unknown extended attribute format encountered\n"));
8112 (void) fprintf(stderr,
8113 gettext("Disabling extended attribute parsing\n"));
8114 xattrbadhead = 1;
8115 return (0);
8117 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8118 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8119 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8120 sizeof (struct xattr_hdr));
8121 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8122 if (link_len > 0)
8123 xattr_linkp = (struct xattr_buf *)
8124 ((int)xattrp + (int)comp_len);
8125 else
8126 xattr_linkp = NULL;
8129 * Gather the attribute path from the filename and attrnames section.
8130 * The filename and attrnames section can be composed of two or more
8131 * path segments separated by a null character. The first segment
8132 * is the path to the parent file that roots the entire sequence in
8133 * the normal name space. The remaining segments describes a path
8134 * rooted at the hidden extended attribute directory of the leaf file of
8135 * the previous segment, making it possible to name attributes on
8136 * attributes.
8138 parentfilelen = strlen(xattrp->h_names);
8139 xattrapath = xattrp->h_names + parentfilelen + 1;
8140 if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
8142 * The attrnames section contains a system attribute on an
8143 * attribute. Save the name of the attribute for use later,
8144 * and replace the null separating the attribute name from
8145 * the system attribute name with a '/' so that xattrapath can
8146 * be used to display messages with the full attribute path name
8147 * rooted at the hidden attribute directory of the base file
8148 * in normal name space.
8150 attrparent = strdup(xattrapath);
8151 attrparentlen = strlen(attrparent);
8152 xattrapath[attrparentlen] = '/';
8154 if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
8155 xattrapath + attrparentlen + 1, xattrapath, attrparent,
8156 -1, 0, attrinfo)) == 1) {
8157 free(attrparent);
8158 return (1);
8161 /* Gather link info */
8162 if (xattr_linkp) {
8163 xattr_linkaname = xattr_linkp->h_names +
8164 strlen(xattr_linkp->h_names) + 1;
8165 } else {
8166 xattr_linkaname = NULL;
8169 return (0);
8171 #else
8172 static int
8173 read_xattr_hdr(attr_data_t **attrinfo)
8175 return (0);
8177 #endif
8180 * skip over extra slashes in string.
8182 * For example:
8183 * /usr/tmp/////
8185 * would return pointer at
8186 * /usr/tmp/////
8189 static char *
8190 skipslashes(char *string, char *start)
8192 while ((string > start) && *(string - 1) == '/') {
8193 string--;
8196 return (string);
8200 * Return the parent directory of a given path.
8202 * Examples:
8203 * /usr/tmp return /usr
8204 * /usr/tmp/file return /usr/tmp
8205 * / returns .
8206 * /usr returns /
8207 * file returns .
8209 * dir is assumed to be at least as big as path.
8211 static void
8212 get_parent(char *path, char *dir)
8214 char *s;
8215 char tmpdir[PATH_MAX + 1];
8217 if (strlen(path) > PATH_MAX) {
8218 fatal(gettext("pathname is too long"));
8220 (void) strcpy(tmpdir, path);
8221 chop_endslashes(tmpdir);
8223 if ((s = strrchr(tmpdir, '/')) == NULL) {
8224 (void) strcpy(dir, ".");
8225 } else {
8226 s = skipslashes(s, tmpdir);
8227 *s = '\0';
8228 if (s == tmpdir)
8229 (void) strcpy(dir, "/");
8230 else
8231 (void) strcpy(dir, tmpdir);
8235 #if defined(O_XATTR)
8236 static char *
8237 get_component(char *path)
8239 char *ptr;
8241 ptr = strrchr(path, '/');
8242 if (ptr == NULL) {
8243 return (path);
8244 } else {
8246 * Handle trailing slash
8248 if (*(ptr + 1) == '\0')
8249 return (ptr);
8250 else
8251 return (ptr + 1);
8254 #else
8255 static char *
8256 get_component(char *path)
8258 return (path);
8260 #endif
8262 #if defined(O_XATTR)
8263 static int
8264 retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
8265 int oflag, mode_t mode)
8267 int dirfd;
8268 int ofilefd = -1;
8269 struct timeval times[2];
8270 mode_t newmode;
8271 struct stat parentstat;
8272 acl_t *aclp = NULL;
8273 int error;
8276 * We couldn't get to attrdir. See if its
8277 * just a mode problem on the parent file.
8278 * for example: a mode such as r-xr--r--
8279 * on a ufs file system without extended
8280 * system attribute support won't let us
8281 * create an attribute dir if it doesn't
8282 * already exist, and on a ufs file system
8283 * with extended system attribute support
8284 * won't let us open the attribute for
8285 * write.
8287 * If file has a non-trivial ACL, then save it
8288 * off so that we can place it back on after doing
8289 * chmod's.
8291 if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
8292 O_RDONLY)) == -1) {
8293 return (-1);
8295 if (fstat(dirfd, &parentstat) == -1) {
8296 (void) fprintf(stderr, gettext(
8297 "tar: cannot stat %sfile %s: %s\n"),
8298 (pdirfd == -1) ? "" : gettext("parent of "),
8299 (pdirfd == -1) ? dirp : name, strerror(errno));
8300 return (-1);
8302 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
8303 (void) fprintf(stderr, gettext(
8304 "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8305 (pdirfd == -1) ? "" : gettext("parent of "),
8306 (pdirfd == -1) ? dirp : name, strerror(errno));
8307 return (-1);
8310 newmode = S_IWUSR | parentstat.st_mode;
8311 if (fchmod(dirfd, newmode) == -1) {
8312 (void) fprintf(stderr,
8313 gettext(
8314 "tar: cannot fchmod %sfile %s to %o: %s\n"),
8315 (pdirfd == -1) ? "" : gettext("parent of "),
8316 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8317 if (aclp)
8318 acl_free(aclp);
8319 return (-1);
8323 if (pdirfd == -1) {
8325 * We weren't able to create the attribute directory before.
8326 * Now try again.
8328 ofilefd = attropen(dirp, ".", oflag);
8329 } else {
8331 * We weren't able to create open the attribute before.
8332 * Now try again.
8334 ofilefd = openat(pdirfd, name, oflag, mode);
8338 * Put mode back to original
8340 if (fchmod(dirfd, parentstat.st_mode) == -1) {
8341 (void) fprintf(stderr,
8342 gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8343 (pdirfd == -1) ? "" : gettext("parent of "),
8344 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8347 if (aclp) {
8348 error = facl_set(dirfd, aclp);
8349 if (error) {
8350 (void) fprintf(stderr,
8351 gettext("tar: failed to set acl entries on "
8352 "%sfile %s\n"),
8353 (pdirfd == -1) ? "" : gettext("parent of "),
8354 (pdirfd == -1) ? dirp : name);
8356 acl_free(aclp);
8360 * Put back time stamps
8363 times[0].tv_sec = parentstat.st_atime;
8364 times[0].tv_usec = 0;
8365 times[1].tv_sec = parentstat.st_mtime;
8366 times[1].tv_usec = 0;
8368 (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
8370 (void) close(dirfd);
8372 return (ofilefd);
8374 #endif
8376 #if !defined(O_XATTR)
8377 static int
8378 openat(int fd, const char *name, int oflag, mode_t cmode)
8380 return (open(name, oflag, cmode));
8383 static int
8384 openat(int fd, const char *name, int oflag, mode_t cmode)
8386 return (open(name, oflag, cmode));
8389 static int
8390 fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
8392 if (flag == AT_SYMLINK_NOFOLLOW)
8393 return (lchown(name, owner, group));
8394 else
8395 return (chown(name, owner, group));
8398 static int
8399 renameat(int fromfd, char *old, int tofd, char *new)
8401 return (rename(old, new));
8404 static int
8405 futimesat(int fd, char *path, struct timeval times[2])
8407 return (utimes(path, times));
8410 static int
8411 unlinkat(int dirfd, char *path, int flag)
8413 if (flag == AT_REMOVEDIR)
8414 return (rmdir(path));
8415 else
8416 return (unlink(path));
8419 static int
8420 fstatat(int fd, char *path, struct stat *buf, int flag)
8422 if (flag == AT_SYMLINK_NOFOLLOW)
8423 return (lstat(path, buf));
8424 else
8425 return (stat(path, buf));
8428 static int
8429 attropen(char *file, char *attr, int omode, mode_t cmode)
8431 errno = ENOTSUP;
8432 return (-1);
8434 #endif
8436 static void
8437 chop_endslashes(char *path)
8439 char *end, *ptr;
8442 * Chop of slashes, but not if all we have is slashes
8443 * for example: ////
8444 * should make no changes, otherwise it will screw up
8445 * checkdir
8447 end = &path[strlen(path) -1];
8448 if (*end == '/' && end != path) {
8449 ptr = skipslashes(end, path);
8450 if (ptr != NULL && ptr != path) {
8451 *ptr = '\0';
8456 /* Compressing a tar file using compression method provided in 'opt' */
8458 static void
8459 compress_back()
8461 pid_t pid;
8463 if (vflag) {
8464 (void) fprintf(vfile,
8465 gettext("Compressing '%s' with '%s'...\n"),
8466 usefile, compress_opt);
8468 if ((pid = fork()) == 0) {
8469 verify_compress_opt(compress_opt);
8470 (void) execlp(compress_opt, compress_opt,
8471 usefile, NULL);
8472 } else if (pid == -1) {
8473 vperror(1, "%s", gettext("Could not fork"));
8475 wait_pid(pid);
8476 if (suffix == 0) {
8477 (void) rename(tfname, usefile);
8481 /* The magic numbers from /etc/magic */
8483 #define GZIP_MAGIC "\037\213"
8484 #define BZIP_MAGIC "BZh"
8485 #define COMP_MAGIC "\037\235"
8486 #define XZ_MAGIC "\375\067\172\130\132\000"
8488 void
8489 check_compression(void)
8491 char magic[16];
8492 FILE *fp;
8494 if ((fp = fopen(usefile, "r")) != NULL) {
8495 (void) fread(magic, sizeof (char), 6, fp);
8496 (void) fclose(fp);
8499 if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
8500 if (xflag || tflag) {
8501 compress_opt = compress_malloc(strlen(GZCAT) + 1);
8502 (void) strcpy(compress_opt, GZCAT);
8503 } else if (uflag || rflag) {
8504 compress_opt = compress_malloc(strlen(GZIP) + 1);
8505 (void) strcpy(compress_opt, GZIP);
8507 } else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
8508 if (xflag || tflag) {
8509 compress_opt = compress_malloc(strlen(BZCAT) + 1);
8510 (void) strcpy(compress_opt, BZCAT);
8511 } else if (uflag || rflag) {
8512 compress_opt = compress_malloc(strlen(BZIP) + 1);
8513 (void) strcpy(compress_opt, BZIP);
8515 } else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
8516 if (xflag || tflag) {
8517 compress_opt = compress_malloc(strlen(ZCAT) + 1);
8518 (void) strcpy(compress_opt, ZCAT);
8519 } else if (uflag || rflag) {
8520 compress_opt = compress_malloc(strlen(COMPRESS) + 1);
8521 (void) strcpy(compress_opt, COMPRESS);
8523 } else if (memcmp(magic, XZ_MAGIC, 6) == 0) {
8524 if (xflag || tflag) {
8525 compress_opt = compress_malloc(strlen(XZCAT) + 1);
8526 (void) strcpy(compress_opt, XZCAT);
8527 } else if (uflag || rflag) {
8528 compress_opt = compress_malloc(strlen(XZ) + 1);
8529 (void) strcpy(compress_opt, XZ);
8534 char *
8535 add_suffix()
8537 (void) strcpy(tfname, usefile);
8538 if (strcmp(compress_opt, GZIP) == 0) {
8539 if ((suffix = gz_suffix()) == NULL) {
8540 strlcat(tfname, gsuffix[0], sizeof (tfname));
8541 return (gsuffix[0]);
8543 } else if (strcmp(compress_opt, COMPRESS) == 0) {
8544 if ((suffix = gz_suffix()) == NULL) {
8545 strlcat(tfname, gsuffix[6], sizeof (tfname));
8546 return (gsuffix[6]);
8548 } else if (strcmp(compress_opt, BZIP) == 0) {
8549 if ((suffix = bz_suffix()) == NULL) {
8550 strlcat(tfname, bsuffix[0], sizeof (tfname));
8551 return (bsuffix[0]);
8553 } else if (strcmp(compress_opt, XZ) == 0) {
8554 if ((suffix = xz_suffix()) == NULL) {
8555 strlcat(tfname, xsuffix[0], sizeof (tfname));
8556 return (xsuffix[0]);
8559 return (NULL);
8562 /* Decompressing a tar file using compression method from the file type */
8563 void
8564 decompress_file(void)
8566 pid_t pid;
8567 char *added_suffix;
8570 added_suffix = add_suffix();
8571 if (added_suffix != NULL) {
8572 (void) rename(usefile, tfname);
8574 if ((pid = fork()) == 0) {
8575 if (vflag) {
8576 (void) fprintf(vfile,
8577 gettext("Decompressing '%s' with "
8578 "'%s'...\n"), usefile, compress_opt);
8580 verify_compress_opt(compress_opt);
8581 (void) execlp(compress_opt, compress_opt, "-df",
8582 tfname, NULL);
8583 vperror(1, gettext("Could not exec %s"), compress_opt);
8584 } else if (pid == -1) {
8585 vperror(1, gettext("Could not fork"));
8587 wait_pid(pid);
8588 if (suffix != NULL) {
8589 /* restore the file name - original file was without suffix */
8590 *(usefile + strlen(usefile) - strlen(suffix)) = '\0';
8594 /* Set the archive for writing and then compress the archive */
8595 pid_t
8596 compress_file(void)
8598 int fd[2];
8599 pid_t pid;
8601 if (vflag) {
8602 (void) fprintf(vfile, gettext("Compressing '%s' with "
8603 "'%s'...\n"), usefile, compress_opt);
8606 if (pipe(fd) < 0) {
8607 vperror(1, gettext("Could not create pipe"));
8609 if ((pid = fork()) > 0) {
8610 mt = fd[1];
8611 (void) close(fd[0]);
8612 return (pid);
8614 /* child */
8615 (void) dup2(fd[0], STDIN_FILENO);
8616 (void) close(fd[1]);
8617 (void) dup2(mt, STDOUT_FILENO);
8618 verify_compress_opt(compress_opt);
8619 (void) execlp(compress_opt, compress_opt, NULL);
8620 vperror(1, gettext("Could not exec %s"), compress_opt);
8621 return (0); /*NOTREACHED*/
8624 pid_t
8625 uncompress_file(void)
8627 int fd[2];
8628 pid_t pid;
8630 if (vflag) {
8631 (void) fprintf(vfile, gettext("Decompressing '%s' with "
8632 "'%s'...\n"), usefile, compress_opt);
8635 if (pipe(fd) < 0) {
8636 vperror(1, gettext("Could not create pipe"));
8638 if ((pid = fork()) > 0) {
8639 mt = fd[0];
8640 (void) close(fd[1]);
8641 return (pid);
8643 /* child */
8644 (void) dup2(fd[1], STDOUT_FILENO);
8645 (void) close(fd[0]);
8646 (void) dup2(mt, STDIN_FILENO);
8647 verify_compress_opt(compress_opt);
8648 (void) execlp(compress_opt, compress_opt, NULL);
8649 vperror(1, gettext("Could not exec %s"), compress_opt);
8650 return (0); /*NOTREACHED*/
8653 /* Checking suffix validity */
8654 char *
8655 check_suffix(char **suf, int size)
8657 int i;
8658 int slen;
8659 int nlen = strlen(usefile);
8661 for (i = 0; i < size; i++) {
8662 slen = strlen(suf[i]);
8663 if (nlen < slen)
8664 return (NULL);
8665 if (strcmp(usefile + nlen - slen, suf[i]) == 0)
8666 return (suf[i]);
8668 return (NULL);
8671 /* Checking valid 'bzip2' suffix */
8672 char *
8673 bz_suffix(void)
8675 return (check_suffix(bsuffix, BSUF));
8678 /* Checking valid 'gzip' suffix */
8679 char *
8680 gz_suffix(void)
8682 return (check_suffix(gsuffix, GSUF));
8685 /* Checking valid 'xz' suffix */
8686 char *
8687 xz_suffix(void)
8689 return (check_suffix(xsuffix, XSUF));
8692 void *
8693 compress_malloc(size_t size)
8695 void *opt;
8697 if ((opt = malloc(size)) == NULL) {
8698 vperror(1, "%s",
8699 gettext("Could not allocate compress buffer\n"));
8701 return (opt);
8704 void
8705 wait_pid(pid_t pid)
8707 int status;
8709 while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
8713 static void
8714 verify_compress_opt(const char *t)
8716 struct stat statbuf;
8718 if (stat(t, &statbuf) == -1)
8719 vperror(1, "%s %s: %s\n", gettext("Could not stat"),
8720 t, strerror(errno));
8723 static void
8724 detect_compress(void)
8726 char *zsuf[] = {".Z"};
8727 if (check_suffix(zsuf, 1) != NULL) {
8728 Zflag = 1;
8729 } else if (check_suffix(bsuffix, BSUF) != NULL) {
8730 jflag = 1;
8731 } else if (check_suffix(gsuffix, GSUF) != NULL) {
8732 zflag = 1;
8733 } else if (check_suffix(xsuffix, XSUF) != NULL) {
8734 Jflag = 1;
8735 } else {
8736 vperror(1, "%s\n", gettext("No compression method detected"));