Fix NULL pointer constant issues in cmd
[unleashed.git] / usr / src / cmd / tar / tar.c
blob5b50e1eab9591f811a47e38241ab82f4c7e4f3ee
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 * Copyright 2015 Joyent, Inc.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 /* Copyright (c) 1987, 1988 Microsoft Corporation */
31 /* All Rights Reserved */
34 * Portions of this source code were derived from Berkeley 4.3 BSD
35 * under license from the Regents of the University of California.
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <sys/stat.h>
42 #include <sys/mkdev.h>
43 #include <sys/wait.h>
44 #include <dirent.h>
45 #include <errno.h>
46 #include <stdio.h>
47 #include <signal.h>
48 #include <ctype.h>
49 #include <locale.h>
50 #include <nl_types.h>
51 #include <langinfo.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <fcntl.h>
55 #include <string.h>
56 #include <malloc.h>
57 #include <time.h>
58 #include <utime.h>
59 #include <stdlib.h>
60 #include <stdarg.h>
61 #include <widec.h>
62 #include <sys/mtio.h>
63 #include <sys/acl.h>
64 #include <strings.h>
65 #include <deflt.h>
66 #include <limits.h>
67 #include <iconv.h>
68 #include <assert.h>
69 #include <libgen.h>
70 #include <libintl.h>
71 #include <aclutils.h>
72 #include <libnvpair.h>
73 #include <archives.h>
75 #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
76 extern int defcntl();
77 #endif
78 #if defined(_PC_SATTR_ENABLED)
79 #include <attr.h>
80 #include <libcmdutils.h>
81 #endif
83 #include "getresponse.h"
85 * Source compatibility
89 * These constants come from archives.h and sys/fcntl.h
90 * and were introduced by the extended attributes project
91 * in Solaris 9.
93 #if !defined(O_XATTR)
94 #define AT_SYMLINK_NOFOLLOW 0x1000
95 #define AT_REMOVEDIR 0x1
96 #define AT_FDCWD 0xffd19553
97 #define _XATTR_HDRTYPE 'E'
98 static int attropen();
99 static int fstatat();
100 static int renameat();
101 static int unlinkat();
102 static int openat();
103 static int fchownat();
104 static int futimesat();
105 #endif
108 * Compiling with -D_XPG4_2 gets this but produces other problems, so
109 * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
110 * explicitly doing the declaration here.
112 int utimes(const char *path, const struct timeval timeval_ptr[]);
114 #ifndef MINSIZE
115 #define MINSIZE 250
116 #endif
117 #define DEF_FILE "/etc/default/tar"
119 #define min(a, b) ((a) < (b) ? (a) : (b))
120 #define max(a, b) ((a) > (b) ? (a) : (b))
122 #define TBLOCK 512 /* tape block size--should be universal */
124 #ifdef BSIZE
125 #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
126 #else /* BSIZE */
127 #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
128 #endif /* BSIZE */
130 #define NBLOCK 20
131 #define NAMSIZ 100
132 #define PRESIZ 155
133 #define MAXNAM 256
134 #define MODEMASK 0777777 /* file creation mode mask */
135 #define POSIXMODES 07777 /* mask for POSIX mode bits */
136 #define MAXEXT 9 /* reasonable max # extents for a file */
137 #define EXTMIN 50 /* min blks left on floppy to split a file */
139 /* max value dblock.dbuf.efsize can store */
140 #define TAR_EFSIZE_MAX 0777777777
143 * Symbols which specify the values at which the use of the 'E' function
144 * modifier is required to properly store a file.
146 * TAR_OFFSET_MAX - the largest file size we can archive
147 * OCTAL7CHAR - the limit for ustar gid, uid, dev
150 #ifdef XHDR_DEBUG
151 /* tiny values which force the creation of extended header entries */
152 #define TAR_OFFSET_MAX 9
153 #define OCTAL7CHAR 2
154 #else
155 /* normal values */
156 #define TAR_OFFSET_MAX 077777777777ULL
157 #define OCTAL7CHAR 07777777
158 #endif
160 #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
161 #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
163 #define MAXLEV (PATH_MAX / 2)
164 #define LEV0 1
165 #define SYMLINK_LEV0 0
167 #define TRUE 1
168 #define FALSE 0
170 #define XATTR_FILE 1
171 #define NORMAL_FILE 0
173 #define PUT_AS_LINK 1
174 #define PUT_NOTAS_LINK 0
176 #ifndef VIEW_READONLY
177 #define VIEW_READONLY "SUNWattr_ro"
178 #endif
180 #ifndef VIEW_READWRITE
181 #define VIEW_READWRITE "SUNWattr_rw"
182 #endif
184 #if _FILE_OFFSET_BITS == 64
185 #define FMT_off_t "lld"
186 #define FMT_off_t_o "llo"
187 #define FMT_blkcnt_t "lld"
188 #else
189 #define FMT_off_t "ld"
190 #define FMT_off_t_o "lo"
191 #define FMT_blkcnt_t "ld"
192 #endif
194 /* ACL support */
196 static
197 struct sec_attr {
198 char attr_type;
199 char attr_len[7];
200 char attr_info[1];
201 } *attr;
203 #if defined(O_XATTR)
204 typedef enum {
205 ATTR_OK,
206 ATTR_SKIP,
207 ATTR_CHDIR_ERR,
208 ATTR_OPEN_ERR,
209 ATTR_XATTR_ERR,
210 ATTR_SATTR_ERR
211 } attr_status_t;
212 #endif
214 #if defined(O_XATTR)
215 typedef enum {
216 ARC_CREATE,
217 ARC_RESTORE
218 } arc_action_t;
219 #endif
221 typedef struct attr_data {
222 char *attr_parent;
223 char *attr_path;
224 int attr_parentfd;
225 int attr_rw_sysattr;
226 } attr_data_t;
230 * Tar has been changed to support extended attributes.
232 * As part of this change tar now uses the new *at() syscalls
233 * such as openat, fchownat(), unlinkat()...
235 * This was done so that attributes can be handled with as few code changes
236 * as possible.
238 * What this means is that tar now opens the directory that a file or directory
239 * resides in and then performs *at() functions to manipulate the entry.
241 * For example a new file is now created like this:
243 * dfd = open(<some dir path>)
244 * fd = openat(dfd, <name>,....);
246 * or in the case of an extended attribute
248 * dfd = attropen(<pathname>, ".", ....)
250 * Once we have a directory file descriptor all of the *at() functions can
251 * be applied to it.
253 * unlinkat(dfd, <component name>,...)
254 * fchownat(dfd, <component name>,..)
256 * This works for both normal namespace files and extended attribute file
262 * Extended attribute Format
264 * Extended attributes are stored in two pieces.
265 * 1. An attribute header which has information about
266 * what file the attribute is for and what the attribute
267 * is named.
268 * 2. The attribute record itself. Stored as a normal file type
269 * of entry.
270 * Both the header and attribute record have special modes/typeflags
271 * associated with them.
273 * The names of the header in the archive look like:
274 * /dev/null/attr.hdr
276 * The name of the attribute looks like:
277 * /dev/null/attr
279 * This is done so that an archiver that doesn't understand these formats
280 * can just dispose of the attribute records.
282 * The format is composed of a fixed size header followed
283 * by a variable sized xattr_buf. If the attribute is a hard link
284 * to another attribute then another xattr_buf section is included
285 * for the link.
287 * The xattr_buf is used to define the necessary "pathing" steps
288 * to get to the extended attribute. This is necessary to support
289 * a fully recursive attribute model where an attribute may itself
290 * have an attribute.
292 * The basic layout looks like this.
294 * --------------------------------
295 * | |
296 * | xattr_hdr |
297 * | |
298 * --------------------------------
299 * --------------------------------
300 * | |
301 * | xattr_buf |
302 * | |
303 * --------------------------------
304 * --------------------------------
305 * | |
306 * | (optional link info) |
307 * | |
308 * --------------------------------
309 * --------------------------------
310 * | |
311 * | attribute itself |
312 * | stored as normal tar |
313 * | or cpio data with |
314 * | special mode or |
315 * | typeflag |
316 * | |
317 * --------------------------------
322 * xattrhead is a pointer to the xattr_hdr
324 * xattrp is a pointer to the xattr_buf structure
325 * which contains the "pathing" steps to get to attributes
327 * xattr_linkp is a pointer to another xattr_buf structure that is
328 * only used when an attribute is actually linked to another attribute
332 static struct xattr_hdr *xattrhead;
333 static struct xattr_buf *xattrp;
334 static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
335 static char *xattrapath; /* attribute name */
336 static char *xattr_linkaname; /* attribute attribute is linked to */
337 static char Hiddendir; /* are we processing hidden xattr dir */
338 static char xattrbadhead;
340 /* Was statically allocated tbuf[NBLOCK] */
341 static
342 union hblock {
343 char dummy[TBLOCK];
344 struct header {
345 char name[NAMSIZ]; /* If non-null prefix, path is */
346 /* <prefix>/<name>; otherwise */
347 /* <name> */
348 char mode[8];
349 char uid[8];
350 char gid[8];
351 char size[12]; /* size of this extent if file split */
352 char mtime[12];
353 char chksum[8];
354 char typeflag;
355 char linkname[NAMSIZ];
356 char magic[6];
357 char version[2];
358 char uname[32];
359 char gname[32];
360 char devmajor[8];
361 char devminor[8];
362 char prefix[PRESIZ]; /* Together with "name", the path of */
363 /* the file: <prefix>/<name> */
364 char extno; /* extent #, null if not split */
365 char extotal; /* total extents */
366 char efsize[10]; /* size of entire file */
367 } dbuf;
368 } dblock, *tbuf, xhdr_buf;
370 static
371 struct xtar_hdr {
372 uid_t x_uid, /* Uid of file */
373 x_gid; /* Gid of file */
374 major_t x_devmajor; /* Device major node */
375 minor_t x_devminor; /* Device minor node */
376 off_t x_filesz; /* Length of file */
377 char *x_uname, /* Pointer to name of user */
378 *x_gname, /* Pointer to gid of user */
379 *x_linkpath, /* Path for a hard/symbolic link */
380 *x_path; /* Path of file */
381 timestruc_t x_mtime; /* Seconds and nanoseconds */
382 } Xtarhdr;
384 static
385 struct gen_hdr {
386 ulong_t g_mode; /* Mode of file */
387 uid_t g_uid, /* Uid of file */
388 g_gid; /* Gid of file */
389 off_t g_filesz; /* Length of file */
390 time_t g_mtime; /* Modification time */
391 uint_t g_cksum; /* Checksum of file */
392 ulong_t g_devmajor, /* File system of file */
393 g_devminor; /* Major/minor of special files */
394 } Gen;
396 static
397 struct linkbuf {
398 ino_t inum;
399 dev_t devnum;
400 int count;
401 char pathname[MAXNAM+1]; /* added 1 for last NULL */
402 char attrname[MAXNAM+1];
403 struct linkbuf *nextp;
404 } *ihead;
406 /* see comments before build_table() */
407 #define TABLE_SIZE 512
408 typedef struct file_list {
409 char *name; /* Name of file to {in,ex}clude */
410 struct file_list *next; /* Linked list */
411 } file_list_t;
412 static file_list_t *exclude_tbl[TABLE_SIZE],
413 *include_tbl[TABLE_SIZE];
415 static int append_secattr(char **, int *, int, char *, char);
416 static void write_ancillary(union hblock *, char *, int, char);
418 static void add_file_to_table(file_list_t *table[], char *str);
419 static void assert_string(char *s, char *msg);
420 static int istape(int fd, int type);
421 static void backtape(void);
422 static void build_table(file_list_t *table[], char *file);
423 static int check_prefix(char **namep, char **dirp, char **compp);
424 static void closevol(void);
425 static void copy(void *dst, void *src);
426 static int convtoreg(off_t);
427 static void delete_target(int fd, char *comp, char *namep);
428 static void doDirTimes(char *name, timestruc_t modTime);
429 static void done(int n);
430 static void dorep(char *argv[]);
431 static void dotable(char *argv[]);
432 static void doxtract(char *argv[]);
433 static int tar_chdir(const char *path);
434 static int is_directory(char *name);
435 static int has_dot_dot(char *name);
436 static int is_absolute(char *name);
437 static char *make_relative_name(char *name, char **stripped_prefix);
438 static void fatal(char *format, ...);
439 static void vperror(int exit_status, char *fmt, ...);
440 static void flushtape(void);
441 static void getdir(void);
442 static void *getmem(size_t);
443 static void longt(struct stat *st, char aclchar);
444 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
445 static int makeDir(char *name);
446 static void mterr(char *operation, int i, int exitcode);
447 static void newvol(void);
448 static void passtape(void);
449 static void putempty(blkcnt_t n);
450 static int putfile(char *longname, char *shortname, char *parent,
451 attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
452 static void readtape(char *buffer);
453 static void seekdisk(blkcnt_t blocks);
454 static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
455 static void setbytes_to_skip(struct stat *st, int err);
456 static void splitfile(char *longname, int ifd, char *name,
457 char *prefix, int filetype);
458 static void tomodes(struct stat *sp);
459 static void usage(void);
460 static int xblocks(int issysattr, off_t bytes, int ofile);
461 static int xsfile(int issysattr, int ofd);
462 static void resugname(int dirfd, char *name, int symflag);
463 static int bcheck(char *bstr);
464 static int checkdir(char *name);
465 static int checksum(union hblock *dblockp);
466 #ifdef EUC
467 static int checksum_signed(union hblock *dblockp);
468 #endif /* EUC */
469 static int checkupdate(char *arg);
470 static int checkw(char c, char *name);
471 static int cmp(char *b, char *s, int n);
472 static int defset(char *arch);
473 static boolean_t endtape(void);
474 static int is_in_table(file_list_t *table[], char *str);
475 static int notsame(void);
476 static int is_prefix(char *s1, char *s2);
477 static int response(void);
478 static int build_dblock(const char *, const char *, const char,
479 const int filetype, const struct stat *, const dev_t, const char *);
480 static unsigned int hash(char *str);
482 static blkcnt_t kcheck(char *kstr);
483 static off_t bsrch(char *s, int n, off_t l, off_t h);
484 static void onintr(int sig);
485 static void onquit(int sig);
486 static void onhup(int sig);
487 static uid_t getuidbyname(char *);
488 static gid_t getgidbyname(char *);
489 static char *getname(gid_t);
490 static char *getgroup(gid_t);
491 static int checkf(char *name, int mode, int howmuch);
492 static int writetbuf(char *buffer, int n);
493 static int wantit(char *argv[], char **namep, char **dirp, char **comp,
494 attr_data_t **attrinfo);
495 static int get_xdata(void);
496 static void gen_num(const char *keyword, const u_longlong_t number);
497 static void gen_date(const char *keyword, const timestruc_t time_value);
498 static void gen_string(const char *keyword, const char *value);
499 static void get_xtime(char *value, timestruc_t *xtime);
500 static int chk_path_build(char *name, char *longname, char *linkname,
501 char *prefix, char type, int filetype);
502 static int gen_utf8_names(const char *filename);
503 static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
504 const char *src, int max_val);
505 static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
506 iconv_t iconv_cd, int xhdrflg, int max_val);
507 static int c_utf8(char *target, const char *source);
508 static int getstat(int dirfd, char *longname, char *shortname,
509 char *attrparent);
510 static void xattrs_put(char *, char *, char *, char *);
511 static void prepare_xattr(char **, char *, char *,
512 char, struct linkbuf *, int *);
513 static int put_link(char *name, char *longname, char *component,
514 char *longattrname, char *prefix, int filetype, char typeflag);
515 static int put_extra_attributes(char *longname, char *shortname,
516 char *longattrname, char *prefix, int filetype, char typeflag);
517 static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
518 char *prefix, int typeflag, int filetype, struct linkbuf *lp);
519 static int read_xattr_hdr(attr_data_t **attrinfo);
521 static void get_parent(char *path, char *dir);
522 static char *get_component(char *path);
523 static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
524 char *name, int oflag, mode_t mode);
525 static char *skipslashes(char *string, char *start);
526 static void chop_endslashes(char *path);
527 static pid_t compress_file(void);
528 static void compress_back(void);
529 static void decompress_file(void);
530 static pid_t uncompress_file(void);
531 static void *compress_malloc(size_t);
532 static void check_compression(void);
533 static char *bz_suffix(void);
534 static char *gz_suffix(void);
535 static char *xz_suffix(void);
536 static char *add_suffix();
537 static void wait_pid(pid_t);
538 static void verify_compress_opt(const char *t);
539 static void detect_compress(void);
540 static void dlog(const char *, ...);
541 static boolean_t should_enable_debug(void);
543 static struct stat stbuf;
545 static char *myname;
546 static char *xtract_chdir = NULL;
547 static int checkflag = 0;
548 static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
549 static int rflag, xflag, vflag, tflag, mt, cflag, mflag, pflag;
550 static int uflag;
551 static int errflag;
552 static int oflag;
553 static int bflag, Aflag;
554 static int Pflag; /* POSIX conformant archive */
555 static int Eflag; /* Allow files greater than 8GB */
556 static int atflag; /* traverse extended attributes */
557 static int saflag; /* traverse extended sys attributes */
558 static int Dflag; /* Data change flag */
559 static int jflag; /* flag to use 'bzip2' */
560 static int zflag; /* flag to use 'gzip' */
561 static int Zflag; /* flag to use 'compress' */
562 static int Jflag; /* flag to use 'xz' */
563 static int aflag; /* flag to use autocompression */
565 static int term, chksum, wflag,
566 first = TRUE, defaults_used = FALSE, linkerrok;
567 static blkcnt_t recno;
568 static int freemem = 1;
569 static int nblock = NBLOCK;
570 static int Errflg = 0;
571 static int exitflag = 0;
573 static dev_t mt_dev; /* device containing output file */
574 static ino_t mt_ino; /* inode number of output file */
575 static int mt_devtype; /* dev type of archive, from stat structure */
577 static int update = 1; /* for `open' call */
579 static off_t low;
580 static off_t high;
582 static FILE *tfile;
583 static FILE *vfile = stdout;
584 static char *tmpdir;
585 static char *tmp_suffix = "/tarXXXXXX";
586 static char *tname;
587 static char archive[] = "archive0=";
588 static char *Xfile;
589 static char *usefile;
590 static char tfname[1024];
592 static int mulvol; /* multi-volume option selected */
593 static blkcnt_t blocklim; /* number of blocks to accept per volume */
594 static blkcnt_t tapepos; /* current block number to be written */
595 static int NotTape; /* true if tape is a disk */
596 static int dumping; /* true if writing a tape or other archive */
597 static int extno; /* number of extent: starts at 1 */
598 static int extotal; /* total extents in this file */
599 static off_t extsize; /* size of current extent during extraction */
600 static ushort_t Oumask = 0; /* old umask value */
601 static boolean_t is_posix; /* true if archive is POSIX-conformant */
602 static const char *magic_type = "ustar";
603 static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */
604 static char *xrec_ptr;
605 static off_t xrec_offset = 0;
606 static int Xhdrflag;
607 static int charset_type = 0;
609 static u_longlong_t xhdr_flgs; /* Bits set determine which items */
610 /* need to be in extended header. */
611 static pid_t comp_pid = 0;
613 static boolean_t debug_output = B_FALSE;
615 #define _X_DEVMAJOR 0x1
616 #define _X_DEVMINOR 0x2
617 #define _X_GID 0x4
618 #define _X_GNAME 0x8
619 #define _X_LINKPATH 0x10
620 #define _X_PATH 0x20
621 #define _X_SIZE 0x40
622 #define _X_UID 0x80
623 #define _X_UNAME 0x100
624 #define _X_ATIME 0x200
625 #define _X_CTIME 0x400
626 #define _X_MTIME 0x800
627 #define _X_XHDR 0x1000 /* Bit flag that determines whether 'X' */
628 /* typeflag was followed by 'A' or non 'A' */
629 /* typeflag. */
630 #define _X_LAST 0x40000000
632 #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4)
633 #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4)
634 #define LONG_MAX_DIGITS (10 * sizeof (long) / 4)
635 #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4)
637 * UTF_8 encoding requires more space than the current codeset equivalent.
638 * Currently a factor of 2-3 would suffice, but it is possible for a factor
639 * of 6 to be needed in the future, so for saftey, we use that here.
641 #define UTF_8_FACTOR 6
643 static u_longlong_t xhdr_count = 0;
644 static char xhdr_dirname[PRESIZ + 1];
645 static char pidchars[PID_MAX_DIGITS + 1];
646 static char *tchar = ""; /* null linkpath */
648 static char local_path[UTF_8_FACTOR * PATH_MAX + 1];
649 static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
650 static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
651 static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
654 * The following mechanism is provided to allow us to debug tar in complicated
655 * situations, like when it is part of a pipe. The idea is that you compile
656 * with -DWAITAROUND defined, and then add the 'D' function modifier to the
657 * target tar invocation, eg. "tar cDf tarfile file". If stderr is available,
658 * it will tell you to which pid to attach the debugger; otherwise, use ps to
659 * find it. Attach to the process from the debugger, and, *PRESTO*, you are
660 * there!
662 * Simply assign "waitaround = 0" once you attach to the process, and then
663 * proceed from there as usual.
666 #ifdef WAITAROUND
667 int waitaround = 0; /* wait for rendezvous with the debugger */
668 #endif
670 #define BZIP "/usr/bin/bzip2"
671 #define GZIP "/usr/bin/gzip"
672 #define COMPRESS "/usr/bin/compress"
673 #define XZ "/usr/bin/xz"
674 #define BZCAT "/usr/bin/bzcat"
675 #define GZCAT "/usr/bin/gzcat"
676 #define ZCAT "/usr/bin/zcat"
677 #define XZCAT "/usr/bin/xzcat"
678 #define GSUF 8 /* number of valid 'gzip' sufixes */
679 #define BSUF 4 /* number of valid 'bzip2' sufixes */
680 #define XSUF 1 /* number of valid 'xz' suffixes */
682 static char *compress_opt; /* compression type */
684 static char *gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
685 ".tgz", ".taz"};
686 static char *bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
687 static char *xsuffix[] = {".xz"};
688 static char *suffix;
692 main(int argc, char *argv[])
694 char *cp;
695 char *tmpdirp;
696 pid_t thispid;
698 (void) setlocale(LC_ALL, "");
699 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
700 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
701 #endif
702 (void) textdomain(TEXT_DOMAIN);
703 if (argc < 2)
704 usage();
706 debug_output = should_enable_debug();
708 tfile = NULL;
709 if ((myname = strdup(argv[0])) == NULL) {
710 (void) fprintf(stderr, gettext(
711 "tar: cannot allocate program name\n"));
712 exit(1);
715 if (init_yes() < 0) {
716 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
717 strerror(errno));
718 exit(2);
722 * For XPG4 compatibility, we must be able to accept the "--"
723 * argument normally recognized by getopt; it is used to delimit
724 * the end opt the options section, and so can only appear in
725 * the position of the first argument. We simply skip it.
728 if (strcmp(argv[1], "--") == 0) {
729 argv++;
730 argc--;
731 if (argc < 3)
732 usage();
735 argv[argc] = NULL;
736 argv++;
739 * Set up default values.
740 * Search the operand string looking for the first digit or an 'f'.
741 * If you find a digit, use the 'archive#' entry in DEF_FILE.
742 * If 'f' is given, bypass looking in DEF_FILE altogether.
743 * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
745 if ((usefile = getenv("TAPE")) == (char *)NULL) {
746 for (cp = *argv; *cp; ++cp)
747 if (isdigit(*cp) || *cp == 'f')
748 break;
749 if (*cp != 'f') {
750 archive[7] = (*cp)? *cp: '0';
751 if (!(defaults_used = defset(archive))) {
752 usefile = NULL;
753 nblock = 1;
754 blocklim = 0;
755 NotTape = 0;
760 for (cp = *argv++; *cp; cp++)
761 switch (*cp) {
762 #ifdef WAITAROUND
763 case 'D':
764 /* rendezvous with the debugger */
765 waitaround = 1;
766 break;
767 #endif
768 case 'f':
769 assert_string(*argv, gettext(
770 "tar: tarfile must be specified with 'f' "
771 "function modifier\n"));
772 usefile = *argv++;
773 break;
774 case 'F':
775 Fflag++;
776 break;
777 case 'c':
778 cflag++;
779 rflag++;
780 update = 1;
781 break;
782 #if defined(O_XATTR)
783 case '@':
784 atflag++;
785 break;
786 #endif /* O_XATTR */
787 #if defined(_PC_SATTR_ENABLED)
788 case '/':
789 saflag++;
790 break;
791 #endif /* _PC_SATTR_ENABLED */
792 case 'u':
793 uflag++; /* moved code after signals caught */
794 rflag++;
795 update = 2;
796 break;
797 case 'r':
798 rflag++;
799 update = 2;
800 break;
801 case 'v':
802 vflag++;
803 break;
804 case 'w':
805 wflag++;
806 break;
807 case 'x':
808 xflag++;
809 break;
810 case 'X':
811 assert_string(*argv, gettext(
812 "tar: exclude file must be specified with 'X' "
813 "function modifier\n"));
814 Xflag = 1;
815 Xfile = *argv++;
816 build_table(exclude_tbl, Xfile);
817 break;
818 case 't':
819 tflag++;
820 break;
821 case 'm':
822 mflag++;
823 break;
824 case 'p':
825 pflag++;
826 break;
827 case 'D':
828 Dflag++;
829 break;
830 case '-':
831 /* ignore this silently */
832 break;
833 case '0': /* numeric entries used only for defaults */
834 case '1':
835 case '2':
836 case '3':
837 case '4':
838 case '5':
839 case '6':
840 case '7':
841 break;
842 case 'b':
843 assert_string(*argv, gettext(
844 "tar: blocking factor must be specified "
845 "with 'b' function modifier\n"));
846 bflag++;
847 nblock = bcheck(*argv++);
848 break;
849 case 'n': /* not a magtape (instead of 'k') */
850 NotTape++; /* assume non-magtape */
851 break;
852 case 'l':
853 linkerrok++;
854 break;
855 case 'e':
856 errflag++;
857 break;
858 case 'o':
859 oflag++;
860 break;
861 case 'h':
862 hflag++;
863 break;
864 case 'i':
865 iflag++;
866 break;
867 case 'B':
868 Bflag++;
869 break;
870 case 'P':
871 Pflag++;
872 break;
873 case 'E':
874 Eflag++;
875 Pflag++; /* Only POSIX archive made */
876 break;
877 case 'j': /* compession "bzip2" */
878 jflag = 1;
879 break;
880 case 'z': /* compression "gzip" */
881 zflag = 1;
882 break;
883 case 'Z': /* compression "compress" */
884 Zflag = 1;
885 break;
886 case 'J': /* compression "xz" */
887 Jflag = 1;
888 break;
889 case 'a':
890 aflag = 1; /* autocompression */
891 break;
892 default:
893 (void) fprintf(stderr, gettext(
894 "tar: %c: unknown function modifier\n"), *cp);
895 usage();
898 if (!rflag && !xflag && !tflag)
899 usage();
900 if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
901 (void) fprintf(stderr, gettext(
902 "tar: specify only one of [ctxru].\n"));
903 usage();
905 if (cflag) {
906 if ((jflag + zflag + Zflag + Jflag + aflag) > 1) {
907 (void) fprintf(stderr, gettext(
908 "tar: specify only one of [ajJzZ] to "
909 "create a compressed file.\n"));
910 usage();
913 if (cflag && *argv == NULL)
914 fatal(gettext("Missing filenames"));
915 if (usefile == NULL)
916 fatal(gettext("device argument required"));
918 /* alloc a buffer of the right size */
919 if ((tbuf = (union hblock *)
920 calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
921 (union hblock *)NULL) {
922 (void) fprintf(stderr, gettext(
923 "tar: cannot allocate physio buffer\n"));
924 exit(1);
927 if ((xrec_ptr = malloc(xrec_size)) == NULL) {
928 (void) fprintf(stderr, gettext(
929 "tar: cannot allocate extended header buffer\n"));
930 exit(1);
933 #ifdef WAITAROUND
934 if (waitaround) {
935 (void) fprintf(stderr, gettext("Rendezvous with tar on pid"
936 " %d\n"), getpid());
938 while (waitaround) {
939 (void) sleep(10);
942 #endif
944 thispid = getpid();
945 (void) sprintf(pidchars, "%ld", thispid);
946 thispid = strlen(pidchars);
948 if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL)
949 (void) strcpy(xhdr_dirname, "/tmp");
950 else {
952 * Make sure that dir is no longer than what can
953 * fit in the prefix part of the header.
955 if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
956 (void) strcpy(xhdr_dirname, "/tmp");
957 if ((vflag > 0) && (Eflag > 0))
958 (void) fprintf(stderr, gettext(
959 "Ignoring TMPDIR\n"));
960 } else
961 (void) strcpy(xhdr_dirname, tmpdirp);
963 (void) strcat(xhdr_dirname, "/PaxHeaders.");
964 (void) strcat(xhdr_dirname, pidchars);
966 if (rflag) {
967 if (cflag && usefile != NULL) {
968 /* Set the compression type */
969 if (aflag)
970 detect_compress();
972 if (jflag) {
973 compress_opt = compress_malloc(strlen(BZIP)
974 + 1);
975 (void) strcpy(compress_opt, BZIP);
976 } else if (zflag) {
977 compress_opt = compress_malloc(strlen(GZIP)
978 + 1);
979 (void) strcpy(compress_opt, GZIP);
980 } else if (Zflag) {
981 compress_opt =
982 compress_malloc(strlen(COMPRESS) + 1);
983 (void) strcpy(compress_opt, COMPRESS);
984 } else if (Jflag) {
985 compress_opt = compress_malloc(strlen(XZ) + 1);
986 (void) strcpy(compress_opt, XZ);
988 } else {
990 * Decompress if the file is compressed for
991 * an update or replace.
993 if (strcmp(usefile, "-") != 0) {
994 check_compression();
995 if (compress_opt != NULL) {
996 decompress_file();
1001 if (cflag && tfile != NULL)
1002 usage();
1003 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1004 (void) signal(SIGINT, onintr);
1005 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1006 (void) signal(SIGHUP, onhup);
1007 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1008 (void) signal(SIGQUIT, onquit);
1009 if (uflag) {
1010 int tnum;
1011 struct stat sbuf;
1013 tmpdir = getenv("TMPDIR");
1015 * If the name is invalid or this isn't a directory,
1016 * or the directory is not writable, then reset to
1017 * a default temporary directory.
1019 if (tmpdir == NULL || *tmpdir == '\0' ||
1020 (strlen(tmpdir) + strlen(tmp_suffix)) > PATH_MAX) {
1021 tmpdir = "/tmp";
1022 } else if (stat(tmpdir, &sbuf) < 0 ||
1023 (sbuf.st_mode & S_IFMT) != S_IFDIR ||
1024 (sbuf.st_mode & S_IWRITE) == 0) {
1025 tmpdir = "/tmp";
1028 if ((tname = calloc(1, strlen(tmpdir) +
1029 strlen(tmp_suffix) + 1)) == NULL) {
1030 vperror(1, gettext("tar: out of memory, "
1031 "cannot create temporary file\n"));
1033 (void) strcpy(tname, tmpdir);
1034 (void) strcat(tname, tmp_suffix);
1036 if ((tnum = mkstemp(tname)) == -1)
1037 vperror(1, "%s", tname);
1038 if ((tfile = fdopen(tnum, "w")) == NULL)
1039 vperror(1, "%s", tname);
1041 if (strcmp(usefile, "-") == 0) {
1042 if (cflag == 0)
1043 fatal(gettext(
1044 "can only create standard output archives."));
1045 vfile = stderr;
1046 mt = dup(1);
1047 ++bflag;
1048 } else {
1049 if (cflag)
1050 mt = open(usefile,
1051 O_RDWR|O_CREAT|O_TRUNC, 0666);
1052 else
1053 mt = open(usefile, O_RDWR);
1055 if (mt < 0) {
1056 if (cflag == 0 || (mt = creat(usefile, 0666))
1057 < 0)
1058 vperror(1, "%s", usefile);
1061 /* Get inode and device number of output file */
1062 (void) fstat(mt, &stbuf);
1063 mt_ino = stbuf.st_ino;
1064 mt_dev = stbuf.st_dev;
1065 mt_devtype = stbuf.st_mode & S_IFMT;
1066 NotTape = !istape(mt, mt_devtype);
1068 if (rflag && !cflag && (mt_devtype == S_IFIFO))
1069 fatal(gettext("cannot append to pipe or FIFO."));
1071 if (Aflag && vflag)
1072 (void) printf(
1073 gettext("Suppressing absolute pathnames\n"));
1074 if (cflag && compress_opt != NULL)
1075 comp_pid = compress_file();
1076 dorep(argv);
1077 if (rflag && !cflag && (compress_opt != NULL))
1078 compress_back();
1079 } else if (xflag || tflag) {
1081 * for each argument, check to see if there is a "-I file" pair.
1082 * if so, move the 3rd argument into "-I"'s place, build_table()
1083 * using "file"'s name and increment argc one (the second
1084 * increment appears in the for loop) which removes the two
1085 * args "-I" and "file" from the argument vector.
1087 for (argc = 0; argv[argc]; argc++) {
1088 if (strcmp(argv[argc], "-I") == 0) {
1089 if (!argv[argc+1]) {
1090 (void) fprintf(stderr, gettext(
1091 "tar: missing argument for -I flag\n"));
1092 done(2);
1093 } else {
1094 Iflag = 1;
1095 argv[argc] = argv[argc+2];
1096 build_table(include_tbl, argv[++argc]);
1098 } else if (strcmp(argv[argc], "-C") == 0) {
1099 if (!argv[argc+1]) {
1100 (void) fprintf(stderr, gettext("tar: "
1101 "missing argument for -C flag\n"));
1102 done(2);
1103 } else if (xtract_chdir != NULL) {
1104 (void) fprintf(stderr, gettext("tar: "
1105 "extract should have only one -C "
1106 "flag\n"));
1107 done(2);
1108 } else {
1109 argv[argc] = argv[argc+2];
1110 xtract_chdir = argv[++argc];
1114 if (strcmp(usefile, "-") == 0) {
1115 mt = dup(0);
1116 ++bflag;
1117 /* try to recover from short reads when reading stdin */
1118 ++Bflag;
1119 } else if ((mt = open(usefile, 0)) < 0)
1120 vperror(1, "%s", usefile);
1122 /* Decompress if the file is compressed */
1124 if (strcmp(usefile, "-") != 0) {
1125 check_compression();
1126 if (compress_opt != NULL)
1127 comp_pid = uncompress_file();
1129 if (xflag) {
1130 if (xtract_chdir != NULL) {
1131 if (tar_chdir(xtract_chdir) < 0) {
1132 vperror(1, gettext("can't change "
1133 "directories to %s"), xtract_chdir);
1136 if (Aflag && vflag)
1137 (void) printf(gettext(
1138 "Suppressing absolute pathnames.\n"));
1140 doxtract(argv);
1141 } else if (tflag)
1142 dotable(argv);
1144 else
1145 usage();
1147 done(Errflg);
1149 /* Not reached: keep compiler quiet */
1150 return (1);
1153 static boolean_t
1154 should_enable_debug(void)
1156 const char *val;
1157 const char *truth[] = {
1158 "true",
1159 "1",
1160 "yes",
1161 "y",
1162 "please",
1163 NULL
1165 unsigned int i;
1167 if ((val = getenv("DEBUG_TAR")) == NULL) {
1168 return (B_FALSE);
1171 for (i = 0; truth[i] != NULL; i++) {
1172 if (strcmp(val, truth[i]) == 0) {
1173 return (B_TRUE);
1177 return (B_FALSE);
1180 /*PRINTFLIKE1*/
1181 static void
1182 dlog(const char *format, ...)
1184 va_list ap;
1186 if (!debug_output) {
1187 return;
1190 va_start(ap, format);
1191 (void) fprintf(stderr, "tar: DEBUG: ");
1192 (void) vfprintf(stderr, format, ap);
1193 va_end(ap);
1196 static void
1197 usage(void)
1199 (void) fprintf(stderr, gettext(
1200 #if defined(O_XATTR)
1201 #if defined(_PC_SATTR_ENABLED)
1202 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPvw@/[0-7]][bf][X...] "
1203 #else
1204 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPvw@[0-7]][bf][X...] "
1205 #endif /* _PC_SATTR_ENABLED */
1206 #else
1207 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPvw[0-7]][bf][X...] "
1208 #endif /* O_XATTR */
1209 "[j|J|z|Z] "
1210 "[blocksize] [tarfile] [size] [exclude-file...] "
1211 "{file | -I include-file | -C directory file}...\n"));
1212 done(1);
1216 * dorep - do "replacements"
1218 * Dorep is responsible for creating ('c'), appending ('r')
1219 * and updating ('u');
1222 static void
1223 dorep(char *argv[])
1225 char *cp, *cp2, *p;
1226 char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
1227 char file[PATH_MAX*2], origdir[PATH_MAX+1];
1228 FILE *fp = (FILE *)NULL;
1229 int archtype;
1230 int ret;
1233 if (!cflag) {
1234 xhdr_flgs = 0;
1235 getdir(); /* read header for next file */
1236 if (Xhdrflag > 0) {
1237 if (!Eflag)
1238 fatal(gettext("Archive contains extended"
1239 " header. -E flag required.\n"));
1240 ret = get_xdata(); /* Get extended header items */
1241 /* and regular header */
1242 } else {
1243 if (Eflag)
1244 fatal(gettext("Archive contains no extended"
1245 " header. -E flag not allowed.\n"));
1247 while (!endtape()) { /* changed from a do while */
1248 setbytes_to_skip(&stbuf, ret);
1249 passtape(); /* skip the file data */
1250 if (term)
1251 done(Errflg); /* received signal to stop */
1252 xhdr_flgs = 0;
1253 getdir();
1254 if (Xhdrflag > 0)
1255 ret = get_xdata();
1257 if (ret == 0) {
1258 if ((dblock.dbuf.typeflag != 'A') &&
1259 (xhdr_flgs != 0)) {
1260 load_info_from_xtarhdr(xhdr_flgs,
1261 &Xtarhdr);
1262 xhdr_flgs |= _X_XHDR;
1265 backtape(); /* was called by endtape */
1266 if (tfile != NULL) {
1268 * Buffer size is calculated to be the size of the
1269 * tmpdir string, plus 6 times the size of the tname
1270 * string, plus a value that is known to be greater
1271 * than the command pipeline string.
1273 int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
1274 char *buf;
1276 if ((buf = (char *)calloc(1, buflen)) == NULL) {
1277 vperror(1, gettext("tar: out of memory, "
1278 "cannot create sort command file\n"));
1281 (void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
1282 "sort +0 -1 +1nr %s -o %s; awk '$1 "
1283 "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1284 tmpdir, tname, tname, tname, tname, tname, tname);
1285 (void) fflush(tfile);
1286 (void) system(buf);
1287 free(buf);
1288 (void) freopen(tname, "r", tfile);
1289 (void) fstat(fileno(tfile), &stbuf);
1290 high = stbuf.st_size;
1294 dumping = 1;
1295 if (mulvol) { /* SP-1 */
1296 if (nblock && (blocklim%nblock) != 0)
1297 fatal(gettext(
1298 "Volume size not a multiple of block size."));
1299 blocklim -= 2; /* for trailer records */
1300 if (vflag)
1301 (void) fprintf(vfile, gettext("Volume ends at %"
1302 FMT_blkcnt_t "K, blocking factor = %dK\n"),
1303 K((blocklim - 1)), K(nblock));
1307 * Save the original directory before it gets
1308 * changed.
1310 if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
1311 vperror(0, gettext("A parent directory cannot be read"));
1312 exit(1);
1315 (void) strcpy(wdir, origdir);
1317 while ((*argv || fp) && !term) {
1318 if (fp || (strcmp(*argv, "-I") == 0)) {
1319 if (fp == NULL) {
1320 if (*++argv == NULL)
1321 fatal(gettext(
1322 "missing file name for -I flag."));
1323 else if ((fp = fopen(*argv++, "r")) == NULL)
1324 vperror(0, "%s", argv[-1]);
1325 continue;
1326 } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
1327 (void) fclose(fp);
1328 fp = NULL;
1329 continue;
1330 } else {
1331 cp = cp2 = file;
1332 if ((p = strchr(cp2, '\n')))
1333 *p = 0;
1335 } else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
1336 if (tar_chdir(*++argv) < 0)
1337 vperror(0, gettext(
1338 "can't change directories to %s"), *argv);
1339 else
1340 (void) getcwd(wdir, (sizeof (wdir)));
1341 argv++;
1342 continue;
1343 } else
1344 cp = cp2 = strcpy(file, *argv++);
1347 * point cp2 to the last '/' in file, but not
1348 * to a trailing '/'
1350 for (; *cp; cp++) {
1351 if (*cp == '/') {
1352 while (*(cp+1) == '/') {
1353 ++cp;
1355 if (*(cp+1) != '\0') {
1356 /* not trailing slash */
1357 cp2 = cp;
1361 if (cp2 != file) {
1362 *cp2 = '\0';
1363 if (tar_chdir(file) < 0) {
1364 vperror(0, gettext(
1365 "can't change directories to %s"), file);
1366 continue;
1368 *cp2 = '/';
1369 cp2++;
1372 parent = getcwd(tempdir, (sizeof (tempdir)));
1374 archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
1375 LEV0, SYMLINK_LEV0);
1377 #if defined(O_XATTR)
1378 if (!exitflag) {
1379 if ((atflag || saflag) &&
1380 (archtype == PUT_NOTAS_LINK)) {
1381 xattrs_put(file, cp2, parent, NULL);
1384 #endif
1386 if (tar_chdir(origdir) < 0)
1387 vperror(0, gettext("cannot change back?: %s"), origdir);
1389 if (exitflag) {
1391 * If e function modifier has been specified
1392 * write the files (that are listed before the
1393 * file causing the error) to tape. exitflag is
1394 * used because only some of the error conditions
1395 * in putfile() recognize the e function modifier.
1397 break;
1401 putempty((blkcnt_t)2);
1402 flushtape();
1403 closevol(); /* SP-1 */
1404 if (linkerrok == 1)
1405 for (; ihead != NULL; ihead = ihead->nextp) {
1406 if (ihead->count == 0)
1407 continue;
1408 (void) fprintf(stderr, gettext(
1409 "tar: missing links to %s\n"), ihead->pathname);
1410 if (errflag)
1411 done(1);
1412 else
1413 Errflg = 1;
1419 * endtape - check for tape at end
1421 * endtape checks the entry in dblock.dbuf to see if its the
1422 * special EOT entry. Endtape is usually called after getdir().
1424 * endtape used to call backtape; it no longer does, he who
1425 * wants it backed up must call backtape himself
1426 * RETURNS: 0 if not EOT, tape position unaffected
1427 * 1 if EOT, tape position unaffected
1430 static boolean_t
1431 endtape(void)
1433 if (dblock.dbuf.name[0] != '\0') {
1435 * The name field is populated.
1437 return (B_FALSE);
1440 if (is_posix && dblock.dbuf.prefix[0] != '\0') {
1442 * This is a ustar/POSIX archive, and although the name
1443 * field is empty the prefix field is not.
1445 return (B_FALSE);
1448 dlog("endtape(): found null header; EOT\n");
1449 return (B_TRUE);
1453 * getdir - get directory entry from tar tape
1455 * getdir reads the next tarblock off the tape and cracks
1456 * it as a directory. The checksum must match properly.
1458 * If tfile is non-null getdir writes the file name and mod date
1459 * to tfile.
1462 static void
1463 getdir(void)
1465 struct stat *sp;
1466 #ifdef EUC
1467 static int warn_chksum_sign = 0;
1468 #endif /* EUC */
1470 top:
1471 readtape((char *)&dblock);
1472 if (dblock.dbuf.name[0] == '\0')
1473 return;
1474 sp = &stbuf;
1475 (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
1476 (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
1477 (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
1478 (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
1479 (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
1480 (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
1481 (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
1482 (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
1484 is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
1486 sp->st_mode = Gen.g_mode;
1487 if (is_posix && (sp->st_mode & S_IFMT) == 0) {
1488 switch (dblock.dbuf.typeflag) {
1489 case '0':
1490 case 0:
1491 case _XATTR_HDRTYPE:
1492 sp->st_mode |= S_IFREG;
1493 break;
1494 case '1': /* hard link */
1495 break;
1496 case '2':
1497 sp->st_mode |= S_IFLNK;
1498 break;
1499 case '3':
1500 sp->st_mode |= S_IFCHR;
1501 break;
1502 case '4':
1503 sp->st_mode |= S_IFBLK;
1504 break;
1505 case '5':
1506 sp->st_mode |= S_IFDIR;
1507 break;
1508 case '6':
1509 sp->st_mode |= S_IFIFO;
1510 break;
1511 default:
1512 if (convtoreg(Gen.g_filesz))
1513 sp->st_mode |= S_IFREG;
1514 break;
1518 if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
1519 Xhdrflag = 1; /* Currently processing extended header */
1520 } else {
1521 Xhdrflag = 0;
1524 sp->st_uid = Gen.g_uid;
1525 sp->st_gid = Gen.g_gid;
1526 sp->st_size = Gen.g_filesz;
1527 sp->st_mtime = Gen.g_mtime;
1528 chksum = Gen.g_cksum;
1530 if (dblock.dbuf.extno != '\0') { /* split file? */
1531 extno = dblock.dbuf.extno;
1532 extsize = Gen.g_filesz;
1533 extotal = dblock.dbuf.extotal;
1534 } else {
1535 extno = 0; /* tell others file not split */
1536 extsize = 0;
1537 extotal = 0;
1540 #ifdef EUC
1541 if (chksum != checksum(&dblock)) {
1542 if (chksum != checksum_signed(&dblock)) {
1543 (void) fprintf(stderr, gettext(
1544 "tar: directory checksum error\n"));
1545 if (iflag) {
1546 Errflg = 2;
1547 goto top;
1549 done(2);
1550 } else {
1551 if (! warn_chksum_sign) {
1552 warn_chksum_sign = 1;
1553 (void) fprintf(stderr, gettext(
1554 "tar: warning: tar file made with signed checksum\n"));
1558 #else
1559 if (chksum != checksum(&dblock)) {
1560 (void) fprintf(stderr, gettext(
1561 "tar: directory checksum error\n"));
1562 if (iflag) {
1563 Errflg = 2;
1564 goto top;
1566 done(2);
1568 #endif /* EUC */
1569 if (tfile != NULL && Xhdrflag == 0) {
1571 * If an extended header is present, then time is available
1572 * in nanoseconds in the extended header data, so set it.
1573 * Otherwise, give an invalid value so that checkupdate will
1574 * not test beyond seconds.
1576 if ((xhdr_flgs & _X_MTIME))
1577 sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
1578 else
1579 sp->st_mtim.tv_nsec = -1;
1581 if (xhdr_flgs & _X_PATH)
1582 (void) fprintf(tfile, "%s %10ld.%9.9ld\n",
1583 Xtarhdr.x_path, sp->st_mtim.tv_sec,
1584 sp->st_mtim.tv_nsec);
1585 else
1586 (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
1587 NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
1588 sp->st_mtim.tv_nsec);
1591 #if defined(O_XATTR)
1592 Hiddendir = 0;
1593 if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
1594 if (xattrbadhead) {
1595 free(xattrhead);
1596 xattrp = NULL;
1597 xattr_linkp = NULL;
1598 xattrhead = NULL;
1599 } else {
1600 char *aname = basename(xattrapath);
1601 size_t xindex = aname - xattrapath;
1603 if (xattrapath[xindex] == '.' &&
1604 xattrapath[xindex + 1] == '\0' &&
1605 xattrp->h_typeflag == '5') {
1606 Hiddendir = 1;
1607 sp->st_mode =
1608 (S_IFDIR | (sp->st_mode & POSIXMODES));
1610 dblock.dbuf.typeflag = xattrp->h_typeflag;
1613 #endif
1618 * passtape - skip over a file on the tape
1620 * passtape skips over the next data file on the tape.
1621 * The tape directory entry must be in dblock.dbuf. This
1622 * routine just eats the number of blocks computed from the
1623 * directory size entry; the tape must be (logically) positioned
1624 * right after the directory info.
1627 static void
1628 passtape(void)
1630 blkcnt_t blocks;
1631 char buf[TBLOCK];
1634 * Print some debugging information about the directory entry
1635 * we are skipping over:
1637 dlog("passtape: typeflag \"%c\"\n", dblock.dbuf.typeflag);
1638 if (dblock.dbuf.name[0] != '\0') {
1639 dlog("passtape: name \"%s\"\n", dblock.dbuf.name);
1641 if (is_posix && dblock.dbuf.prefix[0] != '\0') {
1642 dlog("passtape: prefix \"%s\"\n", dblock.dbuf.prefix);
1646 * Types link(1), sym-link(2), char special(3), blk special(4),
1647 * directory(5), and FIFO(6) do not have data blocks associated
1648 * with them so just skip reading the data block.
1650 if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
1651 dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
1652 dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
1653 return;
1654 blocks = TBLOCKS(stbuf.st_size);
1656 dlog("passtape: block count %" FMT_blkcnt_t "\n", blocks);
1658 /* if operating on disk, seek instead of reading */
1659 if (NotTape)
1660 seekdisk(blocks);
1661 else
1662 while (blocks-- > 0)
1663 readtape(buf);
1666 #if defined(O_XATTR)
1667 static int
1668 is_sysattr(char *name)
1670 return ((strcmp(name, VIEW_READONLY) == 0) ||
1671 (strcmp(name, VIEW_READWRITE) == 0));
1673 #endif
1675 #if defined(O_XATTR)
1677 * Verify the attribute, attrname, is an attribute we want to restore.
1678 * Never restore read-only system attribute files. Only restore read-write
1679 * system attributes files when -/ was specified, and only traverse into
1680 * the 2nd level attribute directory containing only system attributes if
1681 * -@ was specified. This keeps us from archiving
1682 * <attribute name>/<read-write system attribute file>
1683 * when -/ was specified without -@.
1685 * attrname - attribute file name
1686 * attrparent - attribute's parent name within the base file's attribute
1687 * directory hierarchy
1689 static attr_status_t
1690 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
1691 int *rw_sysattr)
1693 #if defined(_PC_SATTR_ENABLED)
1694 int attr_supported;
1696 /* Never restore read-only system attribute files */
1697 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
1698 *rw_sysattr = 0;
1699 return (ATTR_SKIP);
1700 } else {
1701 *rw_sysattr = (attr_supported == _RW_SATTR);
1703 #else
1705 * Only need to check if this attribute is an extended system
1706 * attribute.
1708 if (*rw_sysattr = is_sysattr(attrname)) {
1709 return (ATTR_SKIP);
1710 } else {
1711 return (ATTR_OK);
1713 #endif /* _PC_SATTR_ENABLED */
1716 * If the extended system attribute file is specified with the
1717 * arc_rwsysattr flag, as being transient (default extended
1718 * attributes), then don't archive it.
1720 if (*rw_sysattr && !arc_rwsysattr) {
1721 return (ATTR_SKIP);
1725 * Only restore read-write system attribute files
1726 * when -/ was specified. Only restore extended
1727 * attributes when -@ was specified.
1729 if (atflag) {
1730 if (!saflag) {
1732 * Only archive/restore the hidden directory "." if
1733 * we're processing the top level hidden attribute
1734 * directory. We don't want to process the
1735 * hidden attribute directory of the attribute
1736 * directory that contains only extended system
1737 * attributes.
1739 if (*rw_sysattr || (Hiddendir &&
1740 (attrparent != NULL))) {
1741 return (ATTR_SKIP);
1744 } else if (saflag) {
1746 * Only archive/restore read-write extended system attribute
1747 * files of the base file.
1749 if (!*rw_sysattr || (attrparent != NULL)) {
1750 return (ATTR_SKIP);
1752 } else {
1753 return (ATTR_SKIP);
1756 return (ATTR_OK);
1758 #endif
1760 static void
1761 free_children(file_list_t *children)
1763 file_list_t *child = children;
1764 file_list_t *cptr;
1766 while (child != NULL) {
1767 cptr = child->next;
1768 if (child->name != NULL) {
1769 free(child->name);
1771 child = cptr;
1775 static int
1776 putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
1777 int filetype, int lev, int symlink_lev)
1779 int infile = -1; /* deliberately invalid */
1780 blkcnt_t blocks;
1781 char buf[PATH_MAX + 2]; /* Add trailing slash and null */
1782 char *bigbuf;
1783 int maxread;
1784 int hint; /* amount to write to get "in sync" */
1785 char filetmp[PATH_MAX + 1];
1786 char *cp;
1787 char *name;
1788 char *attrparent = NULL;
1789 char *longattrname = NULL;
1790 file_list_t *child = NULL;
1791 file_list_t *child_end = NULL;
1792 file_list_t *cptr;
1793 struct dirent *dp;
1794 DIR *dirp;
1795 int i;
1796 int split;
1797 int dirfd = -1;
1798 int rc = PUT_NOTAS_LINK;
1799 int archtype = 0;
1800 int rw_sysattr = 0;
1801 char newparent[PATH_MAX + MAXNAMLEN + 1];
1802 char *prefix = "";
1803 char *tmpbuf;
1804 char goodbuf[PRESIZ + 2];
1805 char junkbuf[MAXNAM+1];
1806 char *lastslash;
1807 int j;
1808 struct stat sbuf;
1809 int readlink_max;
1811 (void) memset(goodbuf, '\0', sizeof (goodbuf));
1812 (void) memset(junkbuf, '\0', sizeof (junkbuf));
1814 xhdr_flgs = 0;
1816 if (filetype == XATTR_FILE) {
1817 attrparent = attrinfo->attr_parent;
1818 longattrname = attrinfo->attr_path;
1819 dirfd = attrinfo->attr_parentfd;
1820 rw_sysattr = attrinfo->attr_rw_sysattr;
1821 } else {
1822 dirfd = open(".", O_RDONLY);
1825 if (dirfd == -1) {
1826 (void) fprintf(stderr, gettext(
1827 "tar: unable to open%sdirectory %s%s%s%s\n"),
1828 (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
1829 (attrparent == NULL) ? "" : gettext("of attribute "),
1830 (attrparent == NULL) ? "" : attrparent,
1831 (attrparent == NULL) ? "" : gettext(" of "),
1832 (filetype == XATTR_FILE) ? longname : parent);
1833 goto out;
1836 if (lev > MAXLEV) {
1837 (void) fprintf(stderr,
1838 gettext("tar: directory nesting too deep, %s not dumped\n"),
1839 longname);
1840 goto out;
1843 if (getstat(dirfd, longname, shortname, attrparent))
1844 goto out;
1846 if (hflag) {
1848 * Catch nesting where a file is a symlink to its directory.
1850 j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
1851 if (S_ISLNK(sbuf.st_mode)) {
1852 if (symlink_lev++ >= MAXSYMLINKS) {
1853 (void) fprintf(stderr, gettext(
1854 "tar: %s: Number of symbolic links "
1855 "encountered during path name traversal "
1856 "exceeds MAXSYMLINKS\n"), longname);
1857 Errflg = 1;
1858 goto out;
1864 * Check if the input file is the same as the tar file we
1865 * are creating
1867 if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
1868 (void) fprintf(stderr, gettext(
1869 "tar: %s%s%s%s%s same as archive file\n"),
1870 rw_sysattr ? gettext("system ") : "",
1871 (longattrname == NULL) ? "" : gettext("attribute "),
1872 (longattrname == NULL) ? "" : longattrname,
1873 (longattrname == NULL) ? "" : gettext(" of "),
1874 longname);
1875 Errflg = 1;
1876 goto out;
1879 * Check size limit - we can't archive files that
1880 * exceed TAR_OFFSET_MAX bytes because of header
1881 * limitations. Exclude file types that set
1882 * st_size to zero below because they take no
1883 * archive space to represent contents.
1885 if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
1886 !S_ISDIR(stbuf.st_mode) &&
1887 !S_ISCHR(stbuf.st_mode) &&
1888 !S_ISBLK(stbuf.st_mode) &&
1889 (Eflag == 0)) {
1890 (void) fprintf(stderr, gettext(
1891 "tar: %s%s%s%s%s too large to archive. "
1892 "Use E function modifier.\n"),
1893 rw_sysattr ? gettext("system ") : "",
1894 (longattrname == NULL) ? "" : gettext("attribute "),
1895 (longattrname == NULL) ? "" : longattrname,
1896 (longattrname == NULL) ? "" : gettext(" of "),
1897 longname);
1898 if (errflag)
1899 exitflag = 1;
1900 Errflg = 1;
1901 goto out;
1904 if (tfile != NULL && checkupdate(longname) == 0) {
1905 goto out;
1907 if (checkw('r', longname) == 0) {
1908 goto out;
1911 if (Fflag &&
1912 checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
1913 goto out;
1915 if (Xflag) {
1916 if (is_in_table(exclude_tbl, longname)) {
1917 if (vflag) {
1918 (void) fprintf(vfile, gettext(
1919 "a %s excluded\n"), longname);
1921 goto out;
1926 * If the length of the fullname is greater than MAXNAM,
1927 * print out a message and return (unless extended headers are used,
1928 * in which case fullname is limited to PATH_MAX).
1931 if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
1932 (split > PATH_MAX)) {
1933 (void) fprintf(stderr, gettext(
1934 "tar: %s: file name too long\n"), longname);
1935 if (errflag)
1936 exitflag = 1;
1937 Errflg = 1;
1938 goto out;
1942 * We split the fullname into prefix and name components if any one
1943 * of three conditions holds:
1944 * -- the length of the fullname exceeds NAMSIZ,
1945 * -- the length of the fullname equals NAMSIZ, and the shortname
1946 * is less than NAMSIZ, (splitting in this case preserves
1947 * compatibility with 5.6 and 5.5.1 tar), or
1948 * -- the length of the fullname equals NAMSIZ, the file is a
1949 * directory and we are not in POSIX-conformant mode (where
1950 * trailing slashes are removed from directories).
1952 if ((split > NAMSIZ) ||
1953 (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1954 (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
1956 * Since path is limited to PRESIZ characters, look for the
1957 * last slash within PRESIZ + 1 characters only.
1959 (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
1960 tmpbuf = goodbuf;
1961 lastslash = strrchr(tmpbuf, '/');
1962 if (lastslash == NULL) {
1963 i = split; /* Length of name */
1964 j = 0; /* Length of prefix */
1965 goodbuf[0] = '\0';
1966 } else {
1967 *lastslash = '\0'; /* Terminate the prefix */
1968 j = strlen(tmpbuf);
1969 i = split - j - 1;
1972 * If the filename is greater than NAMSIZ we can't
1973 * archive the file unless we are using extended headers.
1975 if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
1976 !Pflag)) {
1977 /* Determine which (filename or path) is too long. */
1978 lastslash = strrchr(longname, '/');
1979 if (lastslash != NULL)
1980 i = strlen(lastslash + 1);
1981 if (Eflag > 0) {
1982 xhdr_flgs |= _X_PATH;
1983 Xtarhdr.x_path = longname;
1984 if (i <= NAMSIZ)
1985 (void) strcpy(junkbuf, lastslash + 1);
1986 else
1987 (void) sprintf(junkbuf, "%llu",
1988 xhdr_count + 1);
1989 if (split - i - 1 > PRESIZ)
1990 (void) strcpy(goodbuf, xhdr_dirname);
1991 } else {
1992 if ((i > NAMSIZ) || (i == NAMSIZ &&
1993 S_ISDIR(stbuf.st_mode) && !Pflag))
1994 (void) fprintf(stderr, gettext(
1995 "tar: %s: filename is greater than "
1996 "%d\n"), lastslash == NULL ?
1997 longname : lastslash + 1, NAMSIZ);
1998 else
1999 (void) fprintf(stderr, gettext(
2000 "tar: %s: prefix is greater than %d"
2001 "\n"), longname, PRESIZ);
2002 if (errflag)
2003 exitflag = 1;
2004 Errflg = 1;
2005 goto out;
2007 } else
2008 (void) strncpy(&junkbuf[0], longname + j + 1,
2009 strlen(longname + j + 1));
2010 name = junkbuf;
2011 prefix = goodbuf;
2012 } else {
2013 name = longname;
2015 if (Aflag) {
2016 if ((prefix != NULL) && (*prefix != '\0'))
2017 while (*prefix == '/')
2018 ++prefix;
2019 else
2020 while (*name == '/')
2021 ++name;
2024 switch (stbuf.st_mode & S_IFMT) {
2025 case S_IFDIR:
2026 stbuf.st_size = (off_t)0;
2027 blocks = TBLOCKS(stbuf.st_size);
2029 if (filetype != XATTR_FILE && Hiddendir == 0) {
2030 i = 0;
2031 cp = buf;
2032 while ((*cp++ = longname[i++]))
2034 *--cp = '/';
2035 *++cp = 0;
2037 if (!oflag) {
2038 tomodes(&stbuf);
2039 if (build_dblock(name, tchar, '5', filetype,
2040 &stbuf, stbuf.st_dev, prefix) != 0) {
2041 goto out;
2043 if (!Pflag) {
2045 * Old archives require a slash at the end
2046 * of a directory name.
2048 * XXX
2049 * If directory name is too long, will
2050 * slash overfill field?
2052 if (strlen(name) > (unsigned)NAMSIZ-1) {
2053 (void) fprintf(stderr, gettext(
2054 "tar: %s: filename is greater "
2055 "than %d\n"), name, NAMSIZ);
2056 if (errflag)
2057 exitflag = 1;
2058 Errflg = 1;
2059 goto out;
2060 } else {
2061 if (strlen(name) == (NAMSIZ - 1)) {
2062 (void) memcpy(dblock.dbuf.name,
2063 name, NAMSIZ);
2064 dblock.dbuf.name[NAMSIZ-1]
2065 = '/';
2066 } else
2067 (void) sprintf(dblock.dbuf.name,
2068 "%s/", name);
2071 * need to recalculate checksum
2072 * because the name changed.
2074 (void) sprintf(dblock.dbuf.chksum,
2075 "%07o", checksum(&dblock));
2079 if (put_extra_attributes(longname, shortname,
2080 longattrname, prefix, filetype, '5') != 0)
2081 goto out;
2083 #if defined(O_XATTR)
2085 * Reset header typeflag when archiving directory, since
2086 * build_dblock changed it on us.
2088 if (filetype == XATTR_FILE) {
2089 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2090 } else {
2091 dblock.dbuf.typeflag = '5';
2093 #else
2094 dblock.dbuf.typeflag = '5';
2095 #endif
2097 (void) sprintf(dblock.dbuf.chksum, "%07o",
2098 checksum(&dblock));
2100 (void) writetbuf((char *)&dblock, 1);
2102 if (vflag) {
2103 if (NotTape) {
2104 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2106 if (filetype == XATTR_FILE && Hiddendir) {
2107 (void) fprintf(vfile,
2108 gettext("a %s attribute %s "),
2109 longname, longattrname);
2111 } else {
2112 (void) fprintf(vfile, "a %s/ ", longname);
2114 if (NotTape) {
2115 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2116 K(blocks));
2117 } else {
2118 (void) fprintf(vfile, gettext("%" FMT_blkcnt_t
2119 " tape blocks\n"), blocks);
2124 * If hidden dir then break now since xattrs_put() will do
2125 * the iterating of the directory.
2127 * At the moment, there can only be system attributes on
2128 * attributes. There can be no attributes on attributes or
2129 * directories within the attributes hidden directory hierarchy.
2131 if (filetype == XATTR_FILE)
2132 break;
2134 if (*shortname != '/')
2135 (void) sprintf(newparent, "%s/%s", parent, shortname);
2136 else
2137 (void) sprintf(newparent, "%s", shortname);
2139 if (tar_chdir(shortname) < 0) {
2140 vperror(0, "%s", newparent);
2141 goto out;
2144 if ((dirp = opendir(".")) == NULL) {
2145 vperror(0, gettext(
2146 "can't open directory %s"), longname);
2147 if (tar_chdir(parent) < 0)
2148 vperror(0, gettext("cannot change back?: %s"),
2149 parent);
2150 goto out;
2154 * Create a list of files (children) in this directory to avoid
2155 * having to perform telldir()/seekdir().
2157 while ((dp = readdir(dirp)) != NULL && !term) {
2158 if ((strcmp(".", dp->d_name) == 0) ||
2159 (strcmp("..", dp->d_name) == 0))
2160 continue;
2161 if (((cptr = (file_list_t *)calloc(sizeof (char),
2162 sizeof (file_list_t))) == NULL) ||
2163 ((cptr->name = strdup(dp->d_name)) == NULL)) {
2164 vperror(1, gettext(
2165 "Insufficient memory for directory "
2166 "list entry %s/%s\n"),
2167 newparent, dp->d_name);
2170 /* Add the file to the list */
2171 if (child == NULL) {
2172 child = cptr;
2173 } else {
2174 child_end->next = cptr;
2176 child_end = cptr;
2178 (void) closedir(dirp);
2181 * Archive each of the files in the current directory.
2182 * If a file is a directory, putfile() is called
2183 * recursively to archive the file hierarchy of the
2184 * directory before archiving the next file in the
2185 * current directory.
2187 while ((child != NULL) && !term) {
2188 (void) strcpy(cp, child->name);
2189 archtype = putfile(buf, cp, newparent, NULL,
2190 NORMAL_FILE, lev + 1, symlink_lev);
2192 if (!exitflag) {
2193 if ((atflag || saflag) &&
2194 (archtype == PUT_NOTAS_LINK)) {
2195 xattrs_put(buf, cp, newparent, NULL);
2198 if (exitflag)
2199 break;
2201 /* Free each child as we are done processing it. */
2202 cptr = child;
2203 child = child->next;
2204 free(cptr->name);
2205 free(cptr);
2207 if ((child != NULL) && !term) {
2208 free_children(child);
2211 if (tar_chdir(parent) < 0) {
2212 vperror(0, gettext("cannot change back?: %s"), parent);
2215 break;
2217 case S_IFLNK:
2218 readlink_max = NAMSIZ;
2219 if (stbuf.st_size > NAMSIZ) {
2220 if (Eflag > 0) {
2221 xhdr_flgs |= _X_LINKPATH;
2222 readlink_max = PATH_MAX;
2223 } else {
2224 (void) fprintf(stderr, gettext(
2225 "tar: %s: symbolic link too long\n"),
2226 longname);
2227 if (errflag)
2228 exitflag = 1;
2229 Errflg = 1;
2230 goto out;
2234 * Sym-links need header size of zero since you
2235 * don't store any data for this type.
2237 stbuf.st_size = (off_t)0;
2238 tomodes(&stbuf);
2239 i = readlink(shortname, filetmp, readlink_max);
2240 if (i < 0) {
2241 vperror(0, gettext(
2242 "can't read symbolic link %s"), longname);
2243 goto out;
2244 } else {
2245 filetmp[i] = 0;
2247 if (vflag)
2248 (void) fprintf(vfile, gettext(
2249 "a %s symbolic link to %s\n"),
2250 longname, filetmp);
2251 if (xhdr_flgs & _X_LINKPATH) {
2252 Xtarhdr.x_linkpath = filetmp;
2253 if (build_dblock(name, tchar, '2', filetype, &stbuf,
2254 stbuf.st_dev, prefix) != 0)
2255 goto out;
2256 } else
2257 if (build_dblock(name, filetmp, '2', filetype, &stbuf,
2258 stbuf.st_dev, prefix) != 0)
2259 goto out;
2260 (void) writetbuf((char *)&dblock, 1);
2262 * No acls for symlinks: mode is always 777
2263 * dont call write ancillary
2265 rc = PUT_AS_LINK;
2266 break;
2267 case S_IFREG:
2268 if ((infile = openat(dirfd, shortname, 0)) < 0) {
2269 vperror(0, gettext("unable to open %s%s%s%s"), longname,
2270 rw_sysattr ? gettext(" system") : "",
2271 (filetype == XATTR_FILE) ?
2272 gettext(" attribute ") : "",
2273 (filetype == XATTR_FILE) ? (longattrname == NULL) ?
2274 shortname : longattrname : "");
2275 goto out;
2278 blocks = TBLOCKS(stbuf.st_size);
2280 if (put_link(name, longname, shortname, longattrname,
2281 prefix, filetype, '1') == 0) {
2282 (void) close(infile);
2283 rc = PUT_AS_LINK;
2284 goto out;
2287 tomodes(&stbuf);
2289 /* correctly handle end of volume */
2290 while (mulvol && tapepos + blocks + 1 > blocklim) {
2291 /* split if floppy has some room and file is large */
2292 if (((blocklim - tapepos) >= EXTMIN) &&
2293 ((blocks + 1) >= blocklim/10)) {
2294 splitfile(longname, infile,
2295 name, prefix, filetype);
2296 (void) close(dirfd);
2297 (void) close(infile);
2298 goto out;
2300 newvol(); /* not worth it--just get new volume */
2302 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2303 blocks);
2304 if (build_dblock(name, tchar, '0', filetype,
2305 &stbuf, stbuf.st_dev, prefix) != 0) {
2306 goto out;
2308 if (vflag) {
2309 if (NotTape) {
2310 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2312 (void) fprintf(vfile, "a %s%s%s%s ", longname,
2313 rw_sysattr ? gettext(" system") : "",
2314 (filetype == XATTR_FILE) ? gettext(
2315 " attribute ") : "",
2316 (filetype == XATTR_FILE) ?
2317 longattrname : "");
2318 if (NotTape)
2319 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2320 K(blocks));
2321 else
2322 (void) fprintf(vfile,
2323 gettext("%" FMT_blkcnt_t " tape blocks\n"),
2324 blocks);
2327 if (put_extra_attributes(longname, shortname, longattrname,
2328 prefix, filetype, '0') != 0)
2329 goto out;
2332 * No need to reset typeflag for extended attribute here, since
2333 * put_extra_attributes already set it and we haven't called
2334 * build_dblock().
2336 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2337 hint = writetbuf((char *)&dblock, 1);
2338 maxread = max(min(stbuf.st_blksize, stbuf.st_size),
2339 (nblock * TBLOCK));
2340 if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
2341 maxread = TBLOCK;
2342 bigbuf = buf;
2345 while (((i = (int)
2346 read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
2347 blocks) {
2348 blkcnt_t nblks;
2350 nblks = ((i-1)/TBLOCK)+1;
2351 if (nblks > blocks)
2352 nblks = blocks;
2353 hint = writetbuf(bigbuf, nblks);
2354 blocks -= nblks;
2356 (void) close(infile);
2357 if (bigbuf != buf)
2358 free(bigbuf);
2359 if (i < 0)
2360 vperror(0, gettext("Read error on %s"), longname);
2361 else if (blocks != 0 || i != 0) {
2362 (void) fprintf(stderr, gettext(
2363 "tar: %s: file changed size\n"), longname);
2364 if (errflag) {
2365 exitflag = 1;
2366 Errflg = 1;
2367 } else if (!Dflag) {
2368 Errflg = 1;
2371 putempty(blocks);
2372 break;
2373 case S_IFIFO:
2374 blocks = TBLOCKS(stbuf.st_size);
2375 stbuf.st_size = (off_t)0;
2377 if (put_link(name, longname, shortname, longattrname,
2378 prefix, filetype, '6') == 0) {
2379 rc = PUT_AS_LINK;
2380 goto out;
2382 tomodes(&stbuf);
2384 while (mulvol && tapepos + blocks + 1 > blocklim) {
2385 if (((blocklim - tapepos) >= EXTMIN) &&
2386 ((blocks + 1) >= blocklim/10)) {
2387 splitfile(longname, infile, name,
2388 prefix, filetype);
2389 (void) close(dirfd);
2390 (void) close(infile);
2391 goto out;
2393 newvol();
2395 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2396 blocks);
2397 if (vflag) {
2398 if (NotTape) {
2399 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2401 (void) fprintf(vfile, gettext("a %s %"
2402 FMT_blkcnt_t "K\n "), longname, K(blocks));
2403 } else {
2404 (void) fprintf(vfile, gettext(
2405 "a %s %" FMT_blkcnt_t " tape blocks\n"),
2406 longname, blocks);
2409 if (build_dblock(name, tchar, '6', filetype,
2410 &stbuf, stbuf.st_dev, prefix) != 0)
2411 goto out;
2413 if (put_extra_attributes(longname, shortname, longattrname,
2414 prefix, filetype, '6') != 0)
2415 goto out;
2417 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2418 dblock.dbuf.typeflag = '6';
2420 (void) writetbuf((char *)&dblock, 1);
2421 break;
2422 case S_IFCHR:
2423 stbuf.st_size = (off_t)0;
2424 blocks = TBLOCKS(stbuf.st_size);
2425 if (put_link(name, longname, shortname, longattrname,
2426 prefix, filetype, '3') == 0) {
2427 rc = PUT_AS_LINK;
2428 goto out;
2430 tomodes(&stbuf);
2432 while (mulvol && tapepos + blocks + 1 > blocklim) {
2433 if (((blocklim - tapepos) >= EXTMIN) &&
2434 ((blocks + 1) >= blocklim/10)) {
2435 splitfile(longname, infile, name,
2436 prefix, filetype);
2437 (void) close(dirfd);
2438 goto out;
2440 newvol();
2442 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2443 blocks);
2444 if (vflag) {
2445 if (NotTape) {
2446 dlog("seek = %" FMT_blkcnt_t "K\t", K(tapepos));
2448 (void) fprintf(vfile, gettext("a %s %"
2449 FMT_blkcnt_t "K\n"), longname, K(blocks));
2450 } else {
2451 (void) fprintf(vfile, gettext("a %s %"
2452 FMT_blkcnt_t " tape blocks\n"), longname,
2453 blocks);
2456 if (build_dblock(name, tchar, '3',
2457 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2458 goto out;
2460 if (put_extra_attributes(longname, shortname, longattrname,
2461 prefix, filetype, '3') != 0)
2462 goto out;
2464 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2465 dblock.dbuf.typeflag = '3';
2467 (void) writetbuf((char *)&dblock, 1);
2468 break;
2469 case S_IFBLK:
2470 stbuf.st_size = (off_t)0;
2471 blocks = TBLOCKS(stbuf.st_size);
2472 if (put_link(name, longname, shortname, longattrname,
2473 prefix, filetype, '4') == 0) {
2474 rc = PUT_AS_LINK;
2475 goto out;
2477 tomodes(&stbuf);
2479 while (mulvol && tapepos + blocks + 1 > blocklim) {
2480 if (((blocklim - tapepos) >= EXTMIN) &&
2481 ((blocks + 1) >= blocklim/10)) {
2482 splitfile(longname, infile,
2483 name, prefix, filetype);
2484 (void) close(dirfd);
2485 goto out;
2487 newvol();
2489 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2490 blocks);
2491 if (vflag) {
2492 if (NotTape) {
2493 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2496 (void) fprintf(vfile, "a %s ", longname);
2497 if (NotTape)
2498 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2499 K(blocks));
2500 else
2501 (void) fprintf(vfile, gettext("%"
2502 FMT_blkcnt_t " tape blocks\n"), blocks);
2504 if (build_dblock(name, tchar, '4',
2505 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2506 goto out;
2508 if (put_extra_attributes(longname, shortname, longattrname,
2509 prefix, filetype, '4') != 0)
2510 goto out;
2512 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2513 dblock.dbuf.typeflag = '4';
2515 (void) writetbuf((char *)&dblock, 1);
2516 break;
2517 default:
2518 (void) fprintf(stderr, gettext(
2519 "tar: %s is not a file. Not dumped\n"), longname);
2520 if (errflag)
2521 exitflag = 1;
2522 Errflg = 1;
2523 goto out;
2526 out:
2527 if ((dirfd != -1) && (filetype != XATTR_FILE)) {
2528 (void) close(dirfd);
2530 return (rc);
2535 * splitfile dump a large file across volumes
2537 * splitfile(longname, fd);
2538 * char *longname; full name of file
2539 * int ifd; input file descriptor
2541 * NOTE: only called by putfile() to dump a large file.
2544 static void
2545 splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
2547 blkcnt_t blocks;
2548 off_t bytes, s;
2549 char buf[TBLOCK];
2550 int i, extents;
2552 blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */
2555 * # extents =
2556 * size of file after using up rest of this floppy
2557 * blocks - (blocklim - tapepos) + 1 (for header)
2558 * plus roundup value before divide by blocklim-1
2559 * + (blocklim - 1) - 1
2560 * all divided by blocklim-1 (one block for each header).
2561 * this gives
2562 * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2563 * which reduces to the expression used.
2564 * one is added to account for this first extent.
2566 * When one is dealing with extremely large archives, one may want
2567 * to allow for a large number of extents. This code should be
2568 * revisited to determine if extents should be changed to something
2569 * larger than an int.
2571 extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
2573 if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */
2574 (void) fprintf(stderr, gettext(
2575 "tar: %s needs unusual number of volumes to split\n"
2576 "tar: %s not dumped\n"), longname, longname);
2577 return;
2579 if (build_dblock(name, tchar, '0', filetype,
2580 &stbuf, stbuf.st_dev, prefix) != 0)
2581 return;
2583 dblock.dbuf.extotal = extents;
2584 bytes = stbuf.st_size;
2587 * The value contained in dblock.dbuf.efsize was formerly used when the
2588 * v flag was specified in conjunction with the t flag. Although it is
2589 * no longer used, older versions of tar will expect the former
2590 * behaviour, so we must continue to write it to the archive.
2592 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2593 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2594 * store 0.
2596 if (bytes <= TAR_EFSIZE_MAX)
2597 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
2598 else
2599 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
2601 (void) fprintf(stderr, gettext(
2602 "tar: large file %s needs %d extents.\n"
2603 "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
2604 longname, extents, K(tapepos));
2606 s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
2607 for (i = 1; i <= extents; i++) {
2608 if (i > 1) {
2609 newvol();
2610 if (i == extents)
2611 s = bytes; /* last ext. gets true bytes */
2612 else
2613 s = (off_t)(blocklim - 1)*TBLOCK; /* all */
2615 bytes -= s;
2616 blocks = TBLOCKS(s);
2618 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
2619 dblock.dbuf.extno = i;
2620 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2621 (void) writetbuf((char *)&dblock, 1);
2623 if (vflag)
2624 (void) fprintf(vfile,
2625 gettext("+++ a %s %" FMT_blkcnt_t
2626 "K [extent #%d of %d]\n"),
2627 longname, K(blocks), i, extents);
2628 while (blocks && read(ifd, buf, TBLOCK) > 0) {
2629 blocks--;
2630 (void) writetbuf(buf, 1);
2632 if (blocks != 0) {
2633 (void) fprintf(stderr, gettext(
2634 "tar: %s: file changed size\n"), longname);
2635 (void) fprintf(stderr, gettext(
2636 "tar: aborting split file %s\n"), longname);
2637 (void) close(ifd);
2638 return;
2641 (void) close(ifd);
2642 if (vflag)
2643 (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
2644 "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
2645 extents);
2649 * convtoreg - determines whether the file should be converted to a
2650 * regular file when extracted
2652 * Returns 1 when file size > 0 and typeflag is not recognized
2653 * Otherwise returns 0
2655 static int
2656 convtoreg(off_t size)
2658 if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
2659 (dblock.dbuf.typeflag != '\0') && (dblock.dbuf.typeflag != '1') &&
2660 (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
2661 (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
2662 (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
2663 (dblock.dbuf.typeflag != 'L') &&
2664 (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
2665 (dblock.dbuf.typeflag != 'X')) {
2666 return (1);
2668 return (0);
2671 #if defined(O_XATTR)
2672 static int
2673 save_cwd(void)
2675 return (open(".", O_RDONLY));
2677 #endif
2679 #if defined(O_XATTR)
2680 static void
2681 rest_cwd(int *cwd)
2683 if (*cwd != -1) {
2684 if (fchdir(*cwd) < 0) {
2685 vperror(0, gettext(
2686 "Cannot fchdir to attribute directory"));
2687 exit(1);
2689 (void) close(*cwd);
2690 *cwd = -1;
2693 #endif
2696 * Verify the underlying file system supports the attribute type.
2697 * Only archive extended attribute files when '-@' was specified.
2698 * Only archive system extended attribute files if '-/' was specified.
2700 #if defined(O_XATTR)
2701 static attr_status_t
2702 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
2703 int *ext_attrflg)
2706 * Verify extended attributes are supported/exist. We only
2707 * need to check if we are processing a base file, not an
2708 * extended attribute.
2710 if (attrflg) {
2711 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
2712 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
2715 if (atflag) {
2716 if (!*ext_attrflg) {
2717 #if defined(_PC_SATTR_ENABLED)
2718 if (saflag) {
2719 /* Verify system attributes are supported */
2720 if (sysattr_support(filename,
2721 (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
2722 _PC_SATTR_ENABLED) != 1) {
2723 return (ATTR_SATTR_ERR);
2725 } else
2726 return (ATTR_XATTR_ERR);
2727 #else
2728 return (ATTR_XATTR_ERR);
2729 #endif /* _PC_SATTR_ENABLED */
2732 #if defined(_PC_SATTR_ENABLED)
2733 } else if (saflag) {
2734 /* Verify system attributes are supported */
2735 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
2736 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
2737 return (ATTR_SATTR_ERR);
2739 #endif /* _PC_SATTR_ENABLED */
2740 } else {
2741 return (ATTR_SKIP);
2744 return (ATTR_OK);
2746 #endif
2748 #if defined(O_XATTR)
2750 * Recursively open attribute directories until the attribute directory
2751 * containing the specified attribute, attrname, is opened.
2753 * Currently, only 2 directory levels of attributes are supported, (i.e.,
2754 * extended system attributes on extended attributes). The following are
2755 * the possible input combinations:
2756 * 1. Open the attribute directory of the base file (don't change
2757 * into it).
2758 * attrinfo->parent = NULL
2759 * attrname = '.'
2760 * 2. Open the attribute directory of the base file and change into it.
2761 * attrinfo->parent = NULL
2762 * attrname = <attr> | <sys_attr>
2763 * 3. Open the attribute directory of the base file, change into it,
2764 * then recursively call open_attr_dir() to open the attribute's
2765 * parent directory (don't change into it).
2766 * attrinfo->parent = <attr>
2767 * attrname = '.'
2768 * 4. Open the attribute directory of the base file, change into it,
2769 * then recursively call open_attr_dir() to open the attribute's
2770 * parent directory and change into it.
2771 * attrinfo->parent = <attr>
2772 * attrname = <attr> | <sys_attr>
2774 * An attribute directory will be opened only if the underlying file system
2775 * supports the attribute type, and if the command line specifications (atflag
2776 * and saflag) enable the processing of the attribute type.
2778 * On succesful return, attrinfo->parentfd will be the file descriptor of the
2779 * opened attribute directory. In addition, if the attribute is a read-write
2780 * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2781 * it will be set to 0.
2783 * Possible return values:
2784 * ATTR_OK Successfully opened and, if needed, changed into the
2785 * attribute directory containing attrname.
2786 * ATTR_SKIP The command line specifications don't enable the
2787 * processing of the attribute type.
2788 * ATTR_CHDIR_ERR An error occurred while trying to change into an
2789 * attribute directory.
2790 * ATTR_OPEN_ERR An error occurred while trying to open an
2791 * attribute directory.
2792 * ATTR_XATTR_ERR The underlying file system doesn't support extended
2793 * attributes.
2794 * ATTR_SATTR_ERR The underlying file system doesn't support extended
2795 * system attributes.
2797 static int
2798 open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
2800 attr_status_t rc;
2801 int firsttime = (attrinfo->attr_parentfd == -1);
2802 int saveerrno;
2803 int ext_attr;
2806 * open_attr_dir() was recursively called (input combination number 4),
2807 * close the previously opened file descriptor as we've already changed
2808 * into it.
2810 if (!firsttime) {
2811 (void) close(attrinfo->attr_parentfd);
2812 attrinfo->attr_parentfd = -1;
2816 * Verify that the underlying file system supports the restoration
2817 * of the attribute.
2819 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
2820 &ext_attr)) != ATTR_OK) {
2821 return (rc);
2824 /* Open the base file's attribute directory */
2825 if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
2827 * Save the errno from the attropen so it can be reported
2828 * if the retry of the attropen fails.
2830 saveerrno = errno;
2831 if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
2832 NULL, ".", O_RDONLY, 0)) == -1) {
2834 * Reset typeflag back to real value so passtape
2835 * will skip ahead correctly.
2837 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2838 (void) close(attrinfo->attr_parentfd);
2839 attrinfo->attr_parentfd = -1;
2840 errno = saveerrno;
2841 return (ATTR_OPEN_ERR);
2846 * Change into the parent attribute's directory unless we are
2847 * processing the hidden attribute directory of the base file itself.
2849 if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
2850 if (fchdir(attrinfo->attr_parentfd) != 0) {
2851 saveerrno = errno;
2852 (void) close(attrinfo->attr_parentfd);
2853 attrinfo->attr_parentfd = -1;
2854 errno = saveerrno;
2855 return (ATTR_CHDIR_ERR);
2859 /* Determine if the attribute should be processed */
2860 if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
2861 &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
2862 saveerrno = errno;
2863 (void) close(attrinfo->attr_parentfd);
2864 attrinfo->attr_parentfd = -1;
2865 errno = saveerrno;
2866 return (rc);
2870 * If the attribute is an extended attribute, or extended system
2871 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2872 * recursively call open_attr_dir() to open the attribute directory
2873 * of the parent attribute.
2875 if (firsttime && (attrinfo->attr_parent != NULL)) {
2876 return (open_attr_dir(attrname, attrinfo->attr_parent,
2877 attrinfo->attr_parentfd, attrinfo));
2880 return (ATTR_OK);
2882 #endif
2884 static void
2885 doxtract(char *argv[])
2887 struct stat xtractbuf; /* stat on file after extracting */
2888 blkcnt_t blocks;
2889 off_t bytes;
2890 int ofile;
2891 int newfile; /* Does the file already exist */
2892 int xcnt = 0; /* count # files extracted */
2893 int fcnt = 0; /* count # files in argv list */
2894 int dir;
2895 int dirfd = -1;
2896 int cwd = -1;
2897 int rw_sysattr;
2898 int saveerrno;
2899 uid_t Uid;
2900 char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
2901 char dirname[PATH_MAX+1];
2902 char templink[PATH_MAX+1]; /* temp link with terminating NULL */
2903 int once = 1;
2904 int error;
2905 int symflag;
2906 int want;
2907 attr_data_t *attrinfo = NULL; /* attribute info */
2908 acl_t *aclp = NULL; /* acl info */
2909 timestruc_t time_zero; /* used for call to doDirTimes */
2910 int dircreate;
2911 int convflag;
2912 time_zero.tv_sec = 0;
2913 time_zero.tv_nsec = 0;
2915 dumping = 0; /* for newvol(), et al: we are not writing */
2917 Uid = getuid();
2919 for (;;) {
2920 convflag = 0;
2921 symflag = 0;
2922 dir = 0;
2923 Hiddendir = 0;
2924 rw_sysattr = 0;
2925 ofile = -1;
2927 if (dirfd != -1) {
2928 (void) close(dirfd);
2929 dirfd = -1;
2931 if (ofile != -1) {
2932 if (close(ofile) != 0)
2933 vperror(2, gettext("close error"));
2936 #if defined(O_XATTR)
2937 if (cwd != -1) {
2938 rest_cwd(&cwd);
2940 #endif
2942 /* namep is set by wantit to point to the full name */
2943 if ((want = wantit(argv, &namep, &dirp, &comp,
2944 &attrinfo)) == 0) {
2945 #if defined(O_XATTR)
2946 if (xattrp != NULL) {
2947 free(xattrhead);
2948 xattrp = NULL;
2949 xattr_linkp = NULL;
2950 xattrhead = NULL;
2952 #endif
2953 continue;
2955 if (want == -1)
2956 break;
2958 if (dirfd != -1)
2959 (void) close(dirfd);
2961 (void) strcpy(&dirname[0], namep);
2962 dircreate = checkdir(&dirname[0]);
2964 #if defined(O_XATTR)
2965 if (xattrp != NULL) {
2966 int rc;
2968 if (((cwd = save_cwd()) == -1) ||
2969 ((rc = open_attr_dir(comp, dirp, cwd,
2970 attrinfo)) != ATTR_OK)) {
2971 if (cwd == -1) {
2972 vperror(0, gettext(
2973 "unable to save current working "
2974 "directory while processing "
2975 "attribute %s of %s"),
2976 dirp, attrinfo->attr_path);
2977 } else if (rc != ATTR_SKIP) {
2978 (void) fprintf(vfile,
2979 gettext("tar: cannot open "
2980 "%sattribute %s of file %s: %s\n"),
2981 attrinfo->attr_rw_sysattr ? gettext(
2982 "system ") : "",
2983 comp, dirp, strerror(errno));
2985 free(xattrhead);
2986 xattrp = NULL;
2987 xattr_linkp = NULL;
2988 xattrhead = NULL;
2990 passtape();
2991 continue;
2992 } else {
2993 dirfd = attrinfo->attr_parentfd;
2994 rw_sysattr = attrinfo->attr_rw_sysattr;
2996 } else {
2997 dirfd = open(dirp, O_RDONLY);
2999 #else
3000 dirfd = open(dirp, O_RDONLY);
3001 #endif
3002 if (dirfd == -1) {
3003 (void) fprintf(vfile, gettext(
3004 "tar: cannot open %s: %s\n"),
3005 dirp, strerror(errno));
3006 passtape();
3007 continue;
3010 if (xhdr_flgs & _X_LINKPATH)
3011 (void) strcpy(templink, Xtarhdr.x_linkpath);
3012 else {
3013 #if defined(O_XATTR)
3014 if (xattrp && dblock.dbuf.typeflag == '1') {
3015 (void) sprintf(templink, "%.*s", NAMSIZ,
3016 xattrp->h_names);
3017 } else {
3018 (void) sprintf(templink, "%.*s", NAMSIZ,
3019 dblock.dbuf.linkname);
3021 #else
3022 (void) sprintf(templink, "%.*s", NAMSIZ,
3023 dblock.dbuf.linkname);
3024 #endif
3027 if (Fflag) {
3028 if (checkf(namep, is_directory(namep), Fflag) == 0) {
3029 passtape();
3030 continue;
3034 if (checkw('x', namep) == 0) {
3035 passtape();
3036 continue;
3038 if (once) {
3039 if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
3040 if (geteuid() == (uid_t)0) {
3041 checkflag = 1;
3042 pflag = 1;
3043 } else {
3044 /* get file creation mask */
3045 Oumask = umask(0);
3046 (void) umask(Oumask);
3048 once = 0;
3049 } else {
3050 if (geteuid() == (uid_t)0) {
3051 pflag = 1;
3052 checkflag = 2;
3054 if (!pflag) {
3055 /* get file creation mask */
3056 Oumask = umask(0);
3057 (void) umask(Oumask);
3059 once = 0;
3063 #if defined(O_XATTR)
3065 * Handle extraction of hidden attr dir.
3066 * Dir is automatically created, we only
3067 * need to update mode and perm's.
3069 if ((xattrp != NULL) && Hiddendir == 1) {
3070 bytes = stbuf.st_size;
3071 blocks = TBLOCKS(bytes);
3072 if (vflag) {
3073 (void) fprintf(vfile,
3074 "x %s%s%s, %" FMT_off_t " %s, ", namep,
3075 gettext(" attribute "),
3076 xattrapath, bytes,
3077 gettext("bytes"));
3078 if (NotTape)
3079 (void) fprintf(vfile,
3080 "%" FMT_blkcnt_t "K\n", K(blocks));
3081 else
3082 (void) fprintf(vfile, gettext("%"
3083 FMT_blkcnt_t " tape blocks\n"),
3084 blocks);
3088 * Set the permissions and mode of the attribute
3089 * unless the attribute is a system attribute (can't
3090 * successfully do this) or the hidden attribute
3091 * directory (".") of an attribute (when the attribute
3092 * is restored, the hidden attribute directory of an
3093 * attribute is transient). Note: when the permissions
3094 * and mode are set for the hidden attribute directory
3095 * of a file on a system supporting extended system
3096 * attributes, even though it returns successfully, it
3097 * will not have any affect since the attribute
3098 * directory is transient.
3100 if (attrinfo->attr_parent == NULL) {
3101 if (fchownat(dirfd, ".", stbuf.st_uid,
3102 stbuf.st_gid, 0) != 0) {
3103 vperror(0, gettext(
3104 "%s%s%s: failed to set ownership "
3105 "of attribute directory"), namep,
3106 gettext(" attribute "), xattrapath);
3109 if (fchmod(dirfd, stbuf.st_mode) != 0) {
3110 vperror(0, gettext(
3111 "%s%s%s: failed to set permissions "
3112 "of attribute directory"), namep,
3113 gettext(" attribute "), xattrapath);
3116 goto filedone;
3118 #endif
3120 if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
3121 dir = 1;
3122 if (vflag) {
3123 (void) fprintf(vfile, "x %s, 0 %s, ",
3124 &dirname[0], gettext("bytes"));
3125 if (NotTape)
3126 (void) fprintf(vfile, "0K\n");
3127 else
3128 (void) fprintf(vfile, gettext("%"
3129 FMT_blkcnt_t " tape blocks\n"),
3130 (blkcnt_t)0);
3132 goto filedone;
3135 if (dblock.dbuf.typeflag == '6') { /* FIFO */
3136 if (rmdir(namep) < 0) {
3137 if (errno == ENOTDIR)
3138 (void) unlink(namep);
3140 linkp = templink;
3141 if (*linkp != '\0') {
3142 if (Aflag && *linkp == '/')
3143 linkp++;
3144 if (link(linkp, namep) < 0) {
3145 (void) fprintf(stderr, gettext(
3146 "tar: %s: cannot link\n"), namep);
3147 continue;
3149 if (vflag)
3150 (void) fprintf(vfile, gettext(
3151 "x %s linked to %s\n"), namep,
3152 linkp);
3153 xcnt++; /* increment # files extracted */
3154 continue;
3156 if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
3157 (int)Gen.g_devmajor) < 0) {
3158 vperror(0, gettext("%s: mknod failed"), namep);
3159 continue;
3161 bytes = stbuf.st_size;
3162 blocks = TBLOCKS(bytes);
3163 if (vflag) {
3164 (void) fprintf(vfile, "x %s, %" FMT_off_t
3165 " %s, ", namep, bytes, gettext("bytes"));
3166 if (NotTape)
3167 (void) fprintf(vfile, "%" FMT_blkcnt_t
3168 "K\n", K(blocks));
3169 else
3170 (void) fprintf(vfile, gettext("%"
3171 FMT_blkcnt_t " tape blocks\n"),
3172 blocks);
3174 goto filedone;
3176 if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
3177 if (rmdir(namep) < 0) {
3178 if (errno == ENOTDIR)
3179 (void) unlink(namep);
3181 linkp = templink;
3182 if (*linkp != '\0') {
3183 if (Aflag && *linkp == '/')
3184 linkp++;
3185 if (link(linkp, namep) < 0) {
3186 (void) fprintf(stderr, gettext(
3187 "tar: %s: cannot link\n"), namep);
3188 continue;
3190 if (vflag)
3191 (void) fprintf(vfile, gettext(
3192 "x %s linked to %s\n"), namep,
3193 linkp);
3194 xcnt++; /* increment # files extracted */
3195 continue;
3197 if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
3198 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3199 vperror(0, gettext(
3200 "%s: mknod failed"), namep);
3201 continue;
3203 bytes = stbuf.st_size;
3204 blocks = TBLOCKS(bytes);
3205 if (vflag) {
3206 (void) fprintf(vfile, "x %s, %" FMT_off_t
3207 " %s, ", namep, bytes, gettext("bytes"));
3208 if (NotTape)
3209 (void) fprintf(vfile, "%" FMT_blkcnt_t
3210 "K\n", K(blocks));
3211 else
3212 (void) fprintf(vfile, gettext("%"
3213 FMT_blkcnt_t " tape blocks\n"),
3214 blocks);
3216 goto filedone;
3217 } else if (dblock.dbuf.typeflag == '3' && Uid) {
3218 (void) fprintf(stderr, gettext(
3219 "Can't create special %s\n"), namep);
3220 continue;
3223 /* BLOCK SPECIAL */
3225 if (dblock.dbuf.typeflag == '4' && !Uid) {
3226 if (rmdir(namep) < 0) {
3227 if (errno == ENOTDIR)
3228 (void) unlink(namep);
3230 linkp = templink;
3231 if (*linkp != '\0') {
3232 if (Aflag && *linkp == '/')
3233 linkp++;
3234 if (link(linkp, namep) < 0) {
3235 (void) fprintf(stderr, gettext(
3236 "tar: %s: cannot link\n"), namep);
3237 continue;
3239 if (vflag)
3240 (void) fprintf(vfile, gettext(
3241 "x %s linked to %s\n"), namep,
3242 linkp);
3243 xcnt++; /* increment # files extracted */
3244 continue;
3246 if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
3247 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3248 vperror(0, gettext("%s: mknod failed"), namep);
3249 continue;
3251 bytes = stbuf.st_size;
3252 blocks = TBLOCKS(bytes);
3253 if (vflag) {
3254 (void) fprintf(vfile, gettext("x %s, %"
3255 FMT_off_t " bytes, "), namep, bytes);
3256 if (NotTape)
3257 (void) fprintf(vfile, "%" FMT_blkcnt_t
3258 "K\n", K(blocks));
3259 else
3260 (void) fprintf(vfile, gettext("%"
3261 FMT_blkcnt_t " tape blocks\n"),
3262 blocks);
3264 goto filedone;
3265 } else if (dblock.dbuf.typeflag == '4' && Uid) {
3266 (void) fprintf(stderr,
3267 gettext("Can't create special %s\n"), namep);
3268 continue;
3270 if (dblock.dbuf.typeflag == '2') { /* symlink */
3271 linkp = templink;
3272 if (Aflag && *linkp == '/')
3273 linkp++;
3274 if (rmdir(namep) < 0) {
3275 if (errno == ENOTDIR)
3276 (void) unlink(namep);
3278 if (symlink(linkp, namep) < 0) {
3279 vperror(0, gettext("%s: symbolic link failed"),
3280 namep);
3281 continue;
3283 if (vflag)
3284 (void) fprintf(vfile, gettext(
3285 "x %s symbolic link to %s\n"),
3286 namep, linkp);
3288 symflag = AT_SYMLINK_NOFOLLOW;
3289 goto filedone;
3291 if (dblock.dbuf.typeflag == '1') {
3292 linkp = templink;
3293 if (Aflag && *linkp == '/')
3294 linkp++;
3295 if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
3296 if (errno == ENOTDIR)
3297 (void) unlinkat(dirfd, comp, 0);
3299 #if defined(O_XATTR)
3300 if (xattrp && xattr_linkp) {
3301 if (fchdir(dirfd) < 0) {
3302 vperror(0, gettext(
3303 "Cannot fchdir to attribute "
3304 "directory %s"),
3305 (attrinfo->attr_parent == NULL) ?
3306 dirp : attrinfo->attr_parent);
3307 exit(1);
3310 error = link(xattr_linkaname, xattrapath);
3311 } else {
3312 error = link(linkp, namep);
3314 #else
3315 error = link(linkp, namep);
3316 #endif
3318 if (error < 0) {
3319 (void) fprintf(stderr, gettext(
3320 "tar: %s%s%s: cannot link\n"),
3321 namep, (xattr_linkp != NULL) ?
3322 gettext(" attribute ") : "",
3323 (xattr_linkp != NULL) ?
3324 xattrapath : "");
3325 continue;
3327 if (vflag)
3328 (void) fprintf(vfile, gettext(
3329 "x %s%s%s linked to %s%s%s\n"), namep,
3330 (xattr_linkp != NULL) ?
3331 gettext(" attribute ") : "",
3332 (xattr_linkp != NULL) ?
3333 xattr_linkaname : "",
3334 linkp,
3335 (xattr_linkp != NULL) ?
3336 gettext(" attribute ") : "",
3337 (xattr_linkp != NULL) ? xattrapath : "");
3338 xcnt++; /* increment # files extracted */
3339 #if defined(O_XATTR)
3340 if (xattrp != NULL) {
3341 free(xattrhead);
3342 xattrp = NULL;
3343 xattr_linkp = NULL;
3344 xattrhead = NULL;
3346 #endif
3347 continue;
3350 /* REGULAR FILES */
3352 if (convtoreg(stbuf.st_size)) {
3353 convflag = 1;
3354 if (errflag) {
3355 (void) fprintf(stderr, gettext(
3356 "tar: %s: typeflag '%c' not recognized\n"),
3357 namep, dblock.dbuf.typeflag);
3358 done(1);
3359 } else {
3360 (void) fprintf(stderr, gettext(
3361 "tar: %s: typeflag '%c' not recognized, "
3362 "converting to regular file\n"), namep,
3363 dblock.dbuf.typeflag);
3364 Errflg = 1;
3367 if (dblock.dbuf.typeflag == '0' ||
3368 dblock.dbuf.typeflag == '\0' || convflag) {
3369 delete_target(dirfd, comp, namep);
3370 linkp = templink;
3371 if (*linkp != '\0') {
3372 if (Aflag && *linkp == '/')
3373 linkp++;
3374 if (link(linkp, comp) < 0) {
3375 (void) fprintf(stderr, gettext(
3376 "tar: %s: cannot link\n"), namep);
3377 continue;
3379 if (vflag)
3380 (void) fprintf(vfile, gettext(
3381 "x %s linked to %s\n"), comp,
3382 linkp);
3383 xcnt++; /* increment # files extracted */
3384 #if defined(O_XATTR)
3385 if (xattrp != NULL) {
3386 free(xattrhead);
3387 xattrp = NULL;
3388 xattr_linkp = NULL;
3389 xattrhead = NULL;
3391 #endif
3392 continue;
3394 newfile = ((fstatat(dirfd, comp,
3395 &xtractbuf, 0) == -1) ? TRUE : FALSE);
3396 ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
3397 stbuf.st_mode & MODEMASK);
3398 saveerrno = errno;
3400 #if defined(O_XATTR)
3401 if (xattrp != NULL) {
3402 if (ofile < 0) {
3403 ofile = retry_open_attr(dirfd, cwd,
3404 dirp, attrinfo->attr_parent, comp,
3405 O_RDWR|O_CREAT|O_TRUNC,
3406 stbuf.st_mode & MODEMASK);
3409 #endif
3410 if (ofile < 0) {
3411 errno = saveerrno;
3412 (void) fprintf(stderr, gettext(
3413 "tar: %s%s%s%s - cannot create\n"),
3414 (xattrp == NULL) ? "" : (rw_sysattr ?
3415 gettext("system attribute ") :
3416 gettext("attribute ")),
3417 (xattrp == NULL) ? "" : xattrapath,
3418 (xattrp == NULL) ? "" : gettext(" of "),
3419 (xattrp == NULL) ? comp : namep);
3420 if (errflag)
3421 done(1);
3422 else
3423 Errflg = 1;
3424 #if defined(O_XATTR)
3425 if (xattrp != NULL) {
3426 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
3427 free(xattrhead);
3428 xattrp = NULL;
3429 xattr_linkp = NULL;
3430 xattrhead = NULL;
3432 #endif
3433 passtape();
3434 continue;
3437 if (extno != 0) { /* file is in pieces */
3438 if (extotal < 1 || extotal > MAXEXT)
3439 (void) fprintf(stderr, gettext(
3440 "tar: ignoring bad extent info for "
3441 "%s%s%s%s\n"),
3442 (xattrp == NULL) ? "" : (rw_sysattr ?
3443 gettext("system attribute ") :
3444 gettext("attribute ")),
3445 (xattrp == NULL) ? "" : xattrapath,
3446 (xattrp == NULL) ? "" : gettext(" of "),
3447 (xattrp == NULL) ? comp : namep);
3448 else {
3449 /* extract it */
3450 (void) xsfile(rw_sysattr, ofile);
3453 extno = 0; /* let everyone know file is not split */
3454 bytes = stbuf.st_size;
3455 blocks = TBLOCKS(bytes);
3456 if (vflag) {
3457 (void) fprintf(vfile,
3458 "x %s%s%s, %" FMT_off_t " %s, ",
3459 (xattrp == NULL) ? "" : dirp,
3460 (xattrp == NULL) ? "" : (rw_sysattr ?
3461 gettext(" system attribute ") :
3462 gettext(" attribute ")),
3463 (xattrp == NULL) ? namep : xattrapath, bytes,
3464 gettext("bytes"));
3465 if (NotTape)
3466 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
3467 K(blocks));
3468 else
3469 (void) fprintf(vfile, gettext("%"
3470 FMT_blkcnt_t " tape blocks\n"), blocks);
3473 if (xblocks(rw_sysattr, bytes, ofile) != 0) {
3474 #if defined(O_XATTR)
3475 if (xattrp != NULL) {
3476 free(xattrhead);
3477 xattrp = NULL;
3478 xattr_linkp = NULL;
3479 xattrhead = NULL;
3481 #endif
3482 continue;
3484 filedone:
3485 if (mflag == 0 && !symflag) {
3486 if (dir)
3487 doDirTimes(namep, stbuf.st_mtim);
3489 else
3490 #if defined(O_XATTR)
3491 if (xattrp != NULL) {
3493 * Set the time on the attribute unless
3494 * the attribute is a system attribute
3495 * (can't successfully do this) or the
3496 * hidden attribute directory, "." (the
3497 * time on the hidden attribute
3498 * directory will be updated when
3499 * attributes are restored, otherwise
3500 * it's transient).
3502 if (!rw_sysattr && (Hiddendir == 0)) {
3503 setPathTimes(dirfd, comp,
3504 stbuf.st_mtim);
3506 } else
3507 setPathTimes(dirfd, comp,
3508 stbuf.st_mtim);
3509 #else
3510 setPathTimes(dirfd, comp, stbuf.st_mtim);
3511 #endif
3514 /* moved this code from above */
3515 if (pflag && !symflag && Hiddendir == 0) {
3516 if (xattrp != NULL)
3517 (void) fchmod(ofile, stbuf.st_mode & MODEMASK);
3518 else
3519 (void) chmod(namep, stbuf.st_mode & MODEMASK);
3524 * Because ancillary file preceeds the normal file,
3525 * acl info may have been retrieved (in aclp).
3526 * All file types are directed here (go filedone).
3527 * Always restore ACLs if there are ACLs.
3529 if (aclp != NULL) {
3530 int ret;
3532 #if defined(O_XATTR)
3533 if (xattrp != NULL) {
3534 if (Hiddendir)
3535 ret = facl_set(dirfd, aclp);
3536 else
3537 ret = facl_set(ofile, aclp);
3538 } else {
3539 ret = acl_set(namep, aclp);
3541 #else
3542 ret = acl_set(namep, aclp);
3543 #endif
3544 if (ret < 0) {
3545 if (pflag) {
3546 (void) fprintf(stderr, gettext(
3547 "%s%s%s%s: failed to set acl "
3548 "entries\n"), namep,
3549 (xattrp == NULL) ? "" :
3550 (rw_sysattr ? gettext(
3551 " system attribute ") :
3552 gettext(" attribute ")),
3553 (xattrp == NULL) ? "" :
3554 xattrapath);
3556 /* else: silent and continue */
3558 acl_free(aclp);
3559 aclp = NULL;
3562 if (!oflag)
3563 /* set file ownership */
3564 resugname(dirfd, comp, symflag);
3566 if (pflag && newfile == TRUE && !dir &&
3567 (dblock.dbuf.typeflag == '0' ||
3568 dblock.dbuf.typeflag == '\0' ||
3569 convflag || dblock.dbuf.typeflag == '1')) {
3570 if (fstat(ofile, &xtractbuf) == -1)
3571 (void) fprintf(stderr, gettext(
3572 "tar: cannot stat extracted file "
3573 "%s%s%s%s\n"),
3574 (xattrp == NULL) ? "" : (rw_sysattr ?
3575 gettext("system attribute ") :
3576 gettext("attribute ")),
3577 (xattrp == NULL) ? "" : xattrapath,
3578 (xattrp == NULL) ? "" :
3579 gettext(" of "), namep);
3581 else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
3582 != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
3583 (void) fprintf(stderr, gettext(
3584 "tar: warning - file permissions have "
3585 "changed for %s%s%s%s (are 0%o, should be "
3586 "0%o)\n"),
3587 (xattrp == NULL) ? "" : (rw_sysattr ?
3588 gettext("system attribute ") :
3589 gettext("attribute ")),
3590 (xattrp == NULL) ? "" : xattrapath,
3591 (xattrp == NULL) ? "" :
3592 gettext(" of "), namep,
3593 xtractbuf.st_mode, stbuf.st_mode);
3597 #if defined(O_XATTR)
3598 if (xattrp != NULL) {
3599 free(xattrhead);
3600 xattrp = NULL;
3601 xattr_linkp = NULL;
3602 xattrhead = NULL;
3604 #endif
3606 if (ofile != -1) {
3607 (void) close(dirfd);
3608 dirfd = -1;
3609 if (close(ofile) != 0)
3610 vperror(2, gettext("close error"));
3611 ofile = -1;
3613 xcnt++; /* increment # files extracted */
3617 * Process ancillary file.
3621 if (dblock.dbuf.typeflag == 'A') { /* acl info */
3622 char buf[TBLOCK];
3623 char *secp;
3624 char *tp;
3625 int attrsize;
3626 int cnt;
3628 if (pflag) {
3629 bytes = stbuf.st_size;
3630 if ((secp = malloc((int)bytes)) == NULL) {
3631 (void) fprintf(stderr, gettext(
3632 "Insufficient memory for acl\n"));
3633 passtape();
3634 continue;
3636 tp = secp;
3637 blocks = TBLOCKS(bytes);
3639 while (blocks-- > 0) {
3640 readtape(buf);
3641 if (bytes <= TBLOCK) {
3642 (void) memcpy(tp, buf,
3643 (size_t)bytes);
3644 break;
3645 } else {
3646 (void) memcpy(tp, buf,
3647 TBLOCK);
3648 tp += TBLOCK;
3650 bytes -= TBLOCK;
3652 bytes = stbuf.st_size;
3653 /* got all attributes in secp */
3654 tp = secp;
3655 do {
3656 attr = (struct sec_attr *)tp;
3657 switch (attr->attr_type) {
3658 case UFSD_ACL:
3659 case ACE_ACL:
3660 (void) sscanf(attr->attr_len,
3661 "%7o",
3662 (uint_t *)
3663 &cnt);
3664 /* header is 8 */
3665 attrsize = 8 + (int)strlen(
3666 &attr->attr_info[0]) + 1;
3667 error =
3668 acl_fromtext(
3669 &attr->attr_info[0], &aclp);
3671 if (error != 0) {
3672 (void) fprintf(stderr,
3673 gettext(
3674 "aclfromtext "
3675 "failed: %s\n"),
3676 acl_strerror(
3677 error));
3678 bytes -= attrsize;
3679 break;
3681 if (acl_cnt(aclp) != cnt) {
3682 (void) fprintf(stderr,
3683 gettext(
3684 "aclcnt error\n"));
3685 bytes -= attrsize;
3686 break;
3688 bytes -= attrsize;
3689 break;
3691 default:
3692 (void) fprintf(stderr, gettext(
3693 "unrecognized attr"
3694 " type\n"));
3695 bytes = (off_t)0;
3696 break;
3699 /* next attributes */
3700 tp += attrsize;
3701 } while (bytes != 0);
3702 free(secp);
3703 } else {
3704 passtape();
3706 } /* acl */
3708 } /* for */
3711 * Ensure that all the directories still on the directory stack
3712 * get their modification times set correctly by flushing the
3713 * stack.
3716 doDirTimes(NULL, time_zero);
3718 #if defined(O_XATTR)
3719 if (xattrp != NULL) {
3720 free(xattrhead);
3721 xattrp = NULL;
3722 xattr_linkp = NULL;
3723 xattrhead = NULL;
3725 #endif
3728 * Check if the number of files extracted is different from the
3729 * number of files listed on the command line
3731 if (fcnt > xcnt) {
3732 (void) fprintf(stderr,
3733 gettext("tar: %d file(s) not extracted\n"),
3734 fcnt-xcnt);
3735 Errflg = 1;
3740 * xblocks extract file/extent from tape to output file
3742 * xblocks(issysattr, bytes, ofile);
3744 * issysattr flag set if the files being extracted
3745 * is an extended system attribute file.
3746 * unsigned long long bytes size of extent or file to be extracted
3747 * ofile output file
3749 * called by doxtract() and xsfile()
3752 static int
3753 xblocks(int issysattr, off_t bytes, int ofile)
3755 char *buf;
3756 char tempname[NAMSIZ+1];
3757 size_t maxwrite;
3758 size_t bytesread;
3759 size_t piosize; /* preferred I/O size */
3760 struct stat tsbuf;
3762 /* Don't need to do anything if this is a zero size file */
3763 if (bytes <= 0) {
3764 return (0);
3768 * To figure out the size of the buffer used to accumulate data
3769 * from readtape() and to write to the file, we need to determine
3770 * the largest chunk of data to be written to the file at one time.
3771 * This is determined based on the smallest of the following two
3772 * things:
3773 * 1) The size of the archived file.
3774 * 2) The preferred I/O size of the file.
3776 if (issysattr || (bytes <= TBLOCK)) {
3778 * Writes to system attribute files must be
3779 * performed in one operation.
3781 maxwrite = bytes;
3782 } else {
3784 * fstat() the file to get the preferred I/O size.
3785 * If it fails, then resort back to just writing
3786 * one block at a time.
3788 if (fstat(ofile, &tsbuf) == 0) {
3789 piosize = tsbuf.st_blksize;
3790 } else {
3791 piosize = TBLOCK;
3793 maxwrite = min(bytes, piosize);
3797 * The buffer used to accumulate the data for the write operation
3798 * needs to be the maximum number of bytes to be written rounded up
3799 * to the nearest TBLOCK since readtape reads one block at a time.
3801 if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
3802 fatal(gettext("cannot allocate buffer"));
3805 while (bytes > 0) {
3808 * readtape() obtains one block (TBLOCK) of data at a time.
3809 * Accumulate as many blocks of data in buf as we can write
3810 * in one operation.
3812 for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
3813 readtape(buf + bytesread);
3816 if (write(ofile, buf, maxwrite) < 0) {
3817 int saveerrno = errno;
3819 if (xhdr_flgs & _X_PATH)
3820 (void) strlcpy(tempname, Xtarhdr.x_path,
3821 sizeof (tempname));
3822 else
3823 (void) sprintf(tempname, "%.*s", NAMSIZ,
3824 dblock.dbuf.name);
3826 * If the extended system attribute being extracted
3827 * contains attributes that the user needs privileges
3828 * for, then just display a warning message, skip
3829 * the extraction of this file, and return.
3831 if ((saveerrno == EPERM) && issysattr) {
3832 (void) fprintf(stderr, gettext(
3833 "tar: unable to extract system attribute "
3834 "%s: insufficient privileges\n"), tempname);
3835 Errflg = 1;
3836 (void) free(buf);
3837 return (1);
3838 } else {
3839 (void) fprintf(stderr, gettext(
3840 "tar: %s: HELP - extract write error\n"),
3841 tempname);
3842 done(2);
3845 bytes -= maxwrite;
3848 * If we've reached this point and there is still data
3849 * to be written, maxwrite had to have been determined
3850 * by the preferred I/O size. If the number of bytes
3851 * left to write is smaller than the preferred I/O size,
3852 * then we're about to do our final write to the file, so
3853 * just set maxwrite to the number of bytes left to write.
3855 if ((bytes > 0) && (bytes < maxwrite)) {
3856 maxwrite = bytes;
3859 free(buf);
3861 return (0);
3865 * xsfile extract split file
3867 * xsfile(ofd); ofd = output file descriptor
3869 * file extracted and put in ofd via xblocks()
3871 * NOTE: only called by doxtract() to extract one large file
3874 static union hblock savedblock; /* to ensure same file across volumes */
3876 static int
3877 xsfile(int issysattr, int ofd)
3879 int i, c;
3880 int sysattrerr = 0;
3881 char name[PATH_MAX+1]; /* holds name for diagnostics */
3882 int extents, totalext;
3883 off_t bytes, totalbytes;
3885 if (xhdr_flgs & _X_PATH)
3886 (void) strcpy(name, Xtarhdr.x_path);
3887 else
3888 (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
3890 totalbytes = (off_t)0; /* in case we read in half the file */
3891 totalext = 0; /* these keep count */
3893 (void) fprintf(stderr, gettext(
3894 "tar: %s split across %d volumes\n"), name, extotal);
3896 /* make sure we do extractions in order */
3897 if (extno != 1) { /* starting in middle of file? */
3898 (void) printf(gettext(
3899 "tar: first extent read is not #1\n"
3900 "OK to read file beginning with extent #%d? "),
3901 extno);
3902 if (yes() == 0) {
3903 canit:
3904 passtape();
3905 if (close(ofd) != 0)
3906 vperror(2, gettext("close error"));
3907 if (sysattrerr) {
3908 return (1);
3909 } else {
3910 return (0);
3914 extents = extotal;
3915 i = extno;
3916 /*CONSTCOND*/
3917 while (1) {
3918 if (xhdr_flgs & _X_SIZE) {
3919 bytes = extsize;
3920 } else {
3921 bytes = stbuf.st_size;
3924 if (vflag)
3925 (void) fprintf(vfile, "+++ x %s [%s #%d], %"
3926 FMT_off_t " %s, %ldK\n",
3927 name, gettext("extent"), extno,
3928 bytes, gettext("bytes"),
3929 (long)K(TBLOCKS(bytes)));
3930 if (xblocks(issysattr, bytes, ofd) != 0) {
3931 sysattrerr = 1;
3932 goto canit;
3935 totalbytes += bytes;
3936 totalext++;
3937 if (++i > extents)
3938 break;
3940 /* get next volume and verify it's the right one */
3941 copy(&savedblock, &dblock);
3942 tryagain:
3943 newvol();
3944 xhdr_flgs = 0;
3945 getdir();
3946 if (Xhdrflag > 0)
3947 (void) get_xdata(); /* Get x-header & regular hdr */
3948 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
3949 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
3950 xhdr_flgs |= _X_XHDR;
3952 if (endtape()) { /* seemingly empty volume */
3953 (void) fprintf(stderr, gettext(
3954 "tar: first record is null\n"));
3955 asknicely:
3956 (void) fprintf(stderr, gettext(
3957 "tar: need volume with extent #%d of %s\n"),
3958 i, name);
3959 goto tryagain;
3961 if (notsame()) {
3962 (void) fprintf(stderr, gettext(
3963 "tar: first file on that volume is not "
3964 "the same file\n"));
3965 goto asknicely;
3967 if (i != extno) {
3968 (void) fprintf(stderr, gettext(
3969 "tar: extent #%d received out of order\ntar: "
3970 "should be #%d\n"), extno, i);
3971 (void) fprintf(stderr, gettext(
3972 "Ignore error, Abort this file, or "
3973 "load New volume (i/a/n) ? "));
3974 c = response();
3975 if (c == 'a')
3976 goto canit;
3977 if (c != 'i') /* default to new volume */
3978 goto asknicely;
3979 i = extno; /* okay, start from there */
3982 if (vflag)
3983 (void) fprintf(vfile, gettext(
3984 "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
3985 name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
3987 return (0);
3992 * notsame() check if extract file extent is invalid
3994 * returns true if anything differs between savedblock and dblock
3995 * except extno (extent number), checksum, or size (extent size).
3996 * Determines if this header belongs to the same file as the one we're
3997 * extracting.
3999 * NOTE: though rather bulky, it is only called once per file
4000 * extension, and it can withstand changes in the definition
4001 * of the header structure.
4003 * WARNING: this routine is local to xsfile() above
4006 static int
4007 notsame(void)
4009 return (
4010 (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
4011 (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
4012 (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
4013 (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
4014 (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
4015 (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
4016 (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
4017 (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
4018 (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
4021 static void
4022 dotable(char *argv[])
4024 int tcnt = 0; /* count # files tabled */
4025 int fcnt = 0; /* count # files in argv list */
4026 char *namep, *dirp, *comp;
4027 int want;
4028 char aclchar = ' '; /* either blank or '+' */
4029 char templink[PATH_MAX+1];
4030 attr_data_t *attrinfo = NULL;
4032 dumping = 0;
4034 /* if not on magtape, maximize seek speed */
4035 if (NotTape && !bflag) {
4036 #if SYS_BLOCK > TBLOCK
4037 nblock = SYS_BLOCK / TBLOCK;
4038 #else
4039 nblock = 1;
4040 #endif
4043 for (;;) {
4045 /* namep is set by wantit to point to the full name */
4046 if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
4047 continue;
4048 if (want == -1)
4049 break;
4050 if (dblock.dbuf.typeflag != 'A')
4051 ++tcnt;
4053 if (Fflag) {
4054 if (checkf(namep, is_directory(namep), Fflag) == 0) {
4055 passtape();
4056 continue;
4060 * ACL support:
4061 * aclchar is introduced to indicate if there are
4062 * acl entries. longt() now takes one extra argument.
4064 if (vflag) {
4065 if (dblock.dbuf.typeflag == 'A') {
4066 aclchar = '+';
4067 passtape();
4068 continue;
4070 longt(&stbuf, aclchar);
4071 aclchar = ' ';
4075 #if defined(O_XATTR)
4076 if (xattrp != NULL) {
4077 int issysattr;
4078 char *bn = basename(attrinfo->attr_path);
4081 * We could use sysattr_type() to test whether or not
4082 * the attribute we are processing is really an
4083 * extended system attribute, which as of this writing
4084 * just does a strcmp(), however, sysattr_type() may
4085 * be changed to issue a pathconf() call instead, which
4086 * would require being changed into the parent attribute
4087 * directory. So instead, just do simple string
4088 * comparisons to see if we are processing an extended
4089 * system attribute.
4091 issysattr = is_sysattr(bn);
4093 (void) printf(gettext("%s %sattribute %s"),
4094 xattrp->h_names,
4095 issysattr ? gettext("system ") : "",
4096 attrinfo->attr_path);
4097 } else {
4098 (void) printf("%s", namep);
4100 #else
4101 (void) printf("%s", namep);
4102 #endif
4104 if (extno != 0) {
4105 if (vflag) {
4106 /* keep the '\n' for backwards compatibility */
4107 (void) fprintf(vfile, gettext(
4108 "\n [extent #%d of %d]"), extno, extotal);
4109 } else {
4110 (void) fprintf(vfile, gettext(
4111 " [extent #%d of %d]"), extno, extotal);
4114 if (xhdr_flgs & _X_LINKPATH) {
4115 (void) strcpy(templink, Xtarhdr.x_linkpath);
4116 } else {
4117 #if defined(O_XATTR)
4118 if (xattrp != NULL) {
4119 (void) sprintf(templink,
4120 "file %.*s", NAMSIZ, xattrp->h_names);
4121 } else {
4122 (void) sprintf(templink, "%.*s", NAMSIZ,
4123 dblock.dbuf.linkname);
4125 #else
4126 (void) sprintf(templink, "%.*s", NAMSIZ,
4127 dblock.dbuf.linkname);
4128 #endif
4129 templink[NAMSIZ] = '\0';
4131 if (dblock.dbuf.typeflag == '1') {
4133 * TRANSLATION_NOTE
4134 * Subject is omitted here.
4135 * Translate this as if
4136 * <subject> linked to %s
4138 #if defined(O_XATTR)
4139 if (xattrp != NULL) {
4140 (void) printf(
4141 gettext(" linked to attribute %s"),
4142 xattr_linkp->h_names +
4143 strlen(xattr_linkp->h_names) + 1);
4144 } else {
4145 (void) printf(
4146 gettext(" linked to %s"), templink);
4148 #else
4149 (void) printf(
4150 gettext(" linked to %s"), templink);
4152 #endif
4154 if (dblock.dbuf.typeflag == '2')
4155 (void) printf(gettext(
4157 * TRANSLATION_NOTE
4158 * Subject is omitted here.
4159 * Translate this as if
4160 * <subject> symbolic link to %s
4162 " symbolic link to %s"), templink);
4163 (void) printf("\n");
4164 #if defined(O_XATTR)
4165 if (xattrp != NULL) {
4166 free(xattrhead);
4167 xattrp = NULL;
4168 xattrhead = NULL;
4170 #endif
4171 passtape();
4174 * Check if the number of files tabled is different from the
4175 * number of files listed on the command line
4177 if (fcnt > tcnt) {
4178 (void) fprintf(stderr, gettext(
4179 "tar: %d file(s) not found\n"), fcnt-tcnt);
4180 Errflg = 1;
4184 static void
4185 putempty(blkcnt_t n)
4187 char buf[TBLOCK];
4188 char *cp;
4190 for (cp = buf; cp < &buf[TBLOCK]; )
4191 *cp++ = '\0';
4192 while (n-- > 0)
4193 (void) writetbuf(buf, 1);
4196 static ushort_t Ftype = S_IFMT;
4198 static void
4199 verbose(struct stat *st, char aclchar)
4201 int i, j, temp;
4202 mode_t mode;
4203 char modestr[12];
4205 for (i = 0; i < 11; i++)
4206 modestr[i] = '-';
4207 modestr[i] = '\0';
4209 /* a '+' sign is printed if there is ACL */
4210 modestr[i-1] = aclchar;
4212 mode = st->st_mode;
4213 for (i = 0; i < 3; i++) {
4214 temp = (mode >> (6 - (i * 3)));
4215 j = (i * 3) + 1;
4216 if (S_IROTH & temp)
4217 modestr[j] = 'r';
4218 if (S_IWOTH & temp)
4219 modestr[j + 1] = 'w';
4220 if (S_IXOTH & temp)
4221 modestr[j + 2] = 'x';
4223 temp = st->st_mode & Ftype;
4224 switch (temp) {
4225 case (S_IFIFO):
4226 modestr[0] = 'p';
4227 break;
4228 case (S_IFCHR):
4229 modestr[0] = 'c';
4230 break;
4231 case (S_IFDIR):
4232 modestr[0] = 'd';
4233 break;
4234 case (S_IFBLK):
4235 modestr[0] = 'b';
4236 break;
4237 case (S_IFREG): /* was initialized to '-' */
4238 break;
4239 case (S_IFLNK):
4240 modestr[0] = 'l';
4241 break;
4242 default:
4243 /* This field may be zero in old archives. */
4244 if (is_posix && dblock.dbuf.typeflag != '1') {
4246 * For POSIX compliant archives, the mode field
4247 * consists of 12 bits, ie: the file type bits
4248 * are not stored in dblock.dbuf.mode.
4249 * For files other than hard links, getdir() sets
4250 * the file type bits in the st_mode field of the
4251 * stat structure based upon dblock.dbuf.typeflag.
4253 (void) fprintf(stderr, gettext(
4254 "tar: impossible file type"));
4258 if ((S_ISUID & Gen.g_mode) == S_ISUID)
4259 modestr[3] = 's';
4260 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
4261 modestr[9] = 't';
4262 if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
4263 modestr[6] = 's';
4264 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
4265 modestr[6] = 'l';
4266 (void) fprintf(vfile, "%s", modestr);
4269 static void
4270 longt(struct stat *st, char aclchar)
4272 char fileDate[30];
4273 struct tm *tm;
4275 verbose(st, aclchar);
4276 (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
4278 if (dblock.dbuf.typeflag == '2') {
4279 if (xhdr_flgs & _X_LINKPATH)
4280 st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
4281 else
4282 st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
4283 '\0', NAMSIZ) ?
4284 (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
4286 (void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
4288 tm = localtime(&(st->st_mtime));
4289 (void) strftime(fileDate, sizeof (fileDate),
4290 dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
4291 (void) fprintf(vfile, " %s ", fileDate);
4296 * checkdir - Attempt to ensure that the path represented in name
4297 * exists, and return 1 if this is true and name itself is a
4298 * directory.
4299 * Return 0 if this path cannot be created or if name is not
4300 * a directory.
4303 static int
4304 checkdir(char *name)
4306 char lastChar; /* the last character in name */
4307 char *cp; /* scratch pointer into name */
4308 char *firstSlash = NULL; /* first slash in name */
4309 char *lastSlash = NULL; /* last slash in name */
4310 int nameLen; /* length of name */
4311 int trailingSlash; /* true if name ends in slash */
4312 int leadingSlash; /* true if name begins with slash */
4313 int markedDir; /* true if name denotes a directory */
4314 int success; /* status of makeDir call */
4318 * Scan through the name, and locate first and last slashes.
4321 for (cp = name; *cp; cp++) {
4322 if (*cp == '/') {
4323 if (! firstSlash) {
4324 firstSlash = cp;
4326 lastSlash = cp;
4331 * Determine what you can from the proceeds of the scan.
4334 lastChar = *(cp - 1);
4335 nameLen = (int)(cp - name);
4336 trailingSlash = (lastChar == '/');
4337 leadingSlash = (*name == '/');
4338 markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash);
4340 if (! lastSlash && ! markedDir) {
4342 * The named file does not have any subdrectory
4343 * structure; just bail out.
4346 return (0);
4350 * Make sure that name doesn`t end with slash for the loop.
4351 * This ensures that the makeDir attempt after the loop is
4352 * meaningful.
4355 if (trailingSlash) {
4356 name[nameLen-1] = '\0';
4360 * Make the path one component at a time.
4363 for (cp = strchr(leadingSlash ? name+1 : name, '/');
4365 cp = strchr(cp+1, '/')) {
4366 *cp = '\0';
4367 success = makeDir(name);
4368 *cp = '/';
4370 if (!success) {
4371 name[nameLen-1] = lastChar;
4372 return (0);
4377 * This makes the last component of the name, if it is a
4378 * directory.
4381 if (markedDir) {
4382 if (! makeDir(name)) {
4383 name[nameLen-1] = lastChar;
4384 return (0);
4388 name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
4389 return (markedDir);
4393 * resugname - Restore the user name and group name. Search the NIS
4394 * before using the uid and gid.
4395 * (It is presumed that an archive entry cannot be
4396 * simultaneously a symlink and some other type.)
4399 static void
4400 resugname(int dirfd, /* dir fd file resides in */
4401 char *name, /* name of the file to be modified */
4402 int symflag) /* true if file is a symbolic link */
4404 uid_t duid;
4405 gid_t dgid;
4406 struct stat *sp = &stbuf;
4407 char *u_g_name;
4409 if (checkflag == 1) { /* Extended tar format and euid == 0 */
4412 * Try and extract the intended uid and gid from the name
4413 * service before believing the uid and gid in the header.
4415 * In the case where we archived a setuid or setgid file
4416 * owned by someone with a large uid, then it will
4417 * have made it into the archive with a uid of nobody. If
4418 * the corresponding username doesn't appear to exist, then we
4419 * want to make sure it *doesn't* end up as setuid nobody!
4421 * Our caller will print an error message about the fact
4422 * that the restore didn't work out quite right ..
4424 if (xhdr_flgs & _X_UNAME)
4425 u_g_name = Xtarhdr.x_uname;
4426 else
4427 u_g_name = dblock.dbuf.uname;
4428 if ((duid = getuidbyname(u_g_name)) == -1) {
4429 if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
4430 (sp->st_mode & S_ISUID) == S_ISUID)
4431 (void) chmod(name,
4432 MODEMASK & sp->st_mode & ~S_ISUID);
4433 duid = sp->st_uid;
4436 /* (Ditto for gids) */
4438 if (xhdr_flgs & _X_GNAME)
4439 u_g_name = Xtarhdr.x_gname;
4440 else
4441 u_g_name = dblock.dbuf.gname;
4442 if ((dgid = getgidbyname(u_g_name)) == -1) {
4443 if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
4444 (sp->st_mode & S_ISGID) == S_ISGID)
4445 (void) chmod(name,
4446 MODEMASK & sp->st_mode & ~S_ISGID);
4447 dgid = sp->st_gid;
4449 } else if (checkflag == 2) { /* tar format and euid == 0 */
4450 duid = sp->st_uid;
4451 dgid = sp->st_gid;
4453 if ((checkflag == 1) || (checkflag == 2))
4454 (void) fchownat(dirfd, name, duid, dgid, symflag);
4457 /*ARGSUSED*/
4458 static void
4459 onintr(int sig)
4461 (void) signal(SIGINT, SIG_IGN);
4462 term++;
4465 /*ARGSUSED*/
4466 static void
4467 onquit(int sig)
4469 (void) signal(SIGQUIT, SIG_IGN);
4470 term++;
4473 /*ARGSUSED*/
4474 static void
4475 onhup(int sig)
4477 (void) signal(SIGHUP, SIG_IGN);
4478 term++;
4481 static void
4482 tomodes(struct stat *sp)
4484 uid_t uid;
4485 gid_t gid;
4487 bzero(dblock.dummy, TBLOCK);
4490 * If the uid or gid is too large, we can't put it into
4491 * the archive. We could fail to put anything in the
4492 * archive at all .. but most of the time the name service
4493 * will save the day when we do a lookup at restore time.
4495 * Instead we choose a "safe" uid and gid, and fix up whether
4496 * or not the setuid and setgid bits are left set to extraction
4497 * time.
4499 if (Eflag) {
4500 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
4501 xhdr_flgs |= _X_UID;
4502 Xtarhdr.x_uid = uid;
4504 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
4505 xhdr_flgs |= _X_GID;
4506 Xtarhdr.x_gid = gid;
4508 if (sp->st_size > TAR_OFFSET_MAX) {
4509 xhdr_flgs |= _X_SIZE;
4510 Xtarhdr.x_filesz = sp->st_size;
4511 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4512 (off_t)0);
4513 } else
4514 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4515 sp->st_size);
4516 } else {
4517 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4518 sp->st_size);
4520 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
4521 uid = UID_NOBODY;
4522 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
4523 gid = GID_NOBODY;
4524 (void) sprintf(dblock.dbuf.gid, "%07lo", gid);
4525 (void) sprintf(dblock.dbuf.uid, "%07lo", uid);
4526 (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
4527 (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
4530 static int
4531 #ifdef EUC
4533 * Warning: the result of this function depends whether 'char' is a
4534 * signed or unsigned data type. This a source of potential
4535 * non-portability among heterogeneous systems. It is retained here
4536 * for backward compatibility.
4538 checksum_signed(union hblock *dblockp)
4539 #else
4540 checksum(union hblock *dblockp)
4541 #endif /* EUC */
4543 int i;
4544 char *cp;
4546 for (cp = dblockp->dbuf.chksum;
4547 cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
4548 *cp = ' ';
4549 i = 0;
4550 for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
4551 i += *cp;
4552 return (i);
4555 #ifdef EUC
4557 * Generate unsigned checksum, regardless of what C compiler is
4558 * used. Survives in the face of arbitrary 8-bit clean filenames,
4559 * e.g., internationalized filenames.
4561 static int
4562 checksum(union hblock *dblockp)
4564 unsigned i;
4565 unsigned char *cp;
4567 for (cp = (unsigned char *) dblockp->dbuf.chksum;
4568 cp < (unsigned char *)
4569 &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
4570 *cp = ' ';
4571 i = 0;
4572 for (cp = (unsigned char *) dblockp->dummy;
4573 cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
4574 i += *cp;
4576 return (i);
4578 #endif /* EUC */
4581 * If the w flag is set, output the action to be taken and the name of the
4582 * file. Perform the action if the user response is affirmative.
4585 static int
4586 checkw(char c, char *name)
4588 if (wflag) {
4589 (void) fprintf(vfile, "%c ", c);
4590 if (vflag)
4591 longt(&stbuf, ' '); /* do we have acl info here */
4592 (void) fprintf(vfile, "%s: ", name);
4593 if (yes() == 1) {
4594 return (1);
4596 return (0);
4598 return (1);
4602 * When the F flag is set, exclude RCS and SCCS directories (and any files
4603 * or directories under them). If F is set twice, also exclude .o files,
4604 * and files names errs, core, and a.out.
4606 * Return 0 if file should be excluded, 1 otherwise.
4609 static int
4610 checkf(char *longname, int is_dir, int howmuch)
4612 static char fullname[PATH_MAX + 1];
4613 char *dir, *name;
4615 #if defined(O_XATTR)
4617 * If there is an xattr_buf structure associated with this file,
4618 * always return 1.
4620 if (xattrp) {
4621 return (1);
4623 #endif
4626 * First check to see if the base name is an RCS or SCCS directory.
4628 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4629 return (1);
4631 name = basename(fullname);
4632 if (is_dir) {
4633 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4634 return (0);
4638 * If two -F command line options were given then exclude .o files,
4639 * and files named errs, core, and a.out.
4641 if (howmuch > 1 && !is_dir) {
4642 size_t l = strlen(name);
4644 if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
4645 return (0);
4646 if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
4647 strcmp(name, "a.out") == 0)
4648 return (0);
4652 * At this point, check to see if this file has a parent directory
4653 * named RCS or SCCS. If so, then this file should be excluded too.
4654 * The strcpy() operation is done again, because basename(3C) may
4655 * modify the path string passed to it.
4657 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4658 return (1);
4660 dir = dirname(fullname);
4661 while (strcmp(dir, ".") != 0) {
4662 name = basename(dir);
4663 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4664 return (0);
4665 dir = dirname(dir);
4668 return (1);
4671 static int
4672 response(void)
4674 int c;
4676 c = getchar();
4677 if (c != '\n')
4678 while (getchar() != '\n')
4680 else c = 'n';
4681 return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
4684 /* Has file been modified since being put into archive? If so, return > 0. */
4686 static off_t lookup(char *);
4688 static int
4689 checkupdate(char *arg)
4691 char name[PATH_MAX+1];
4692 time_t mtime;
4693 long nsecs;
4694 off_t seekp;
4696 rewind(tfile);
4697 if ((seekp = lookup(arg)) < 0)
4698 return (1);
4699 (void) fseek(tfile, seekp, 0);
4700 (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
4703 * Unless nanoseconds were stored in the file, only use seconds for
4704 * comparison of time. Nanoseconds are stored when -E is specified.
4706 if (Eflag == 0)
4707 return (stbuf.st_mtime > mtime);
4709 if ((stbuf.st_mtime < mtime) ||
4710 ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
4711 return (0);
4712 return (1);
4717 * newvol get new floppy (or tape) volume
4719 * newvol(); resets tapepos and first to TRUE, prompts for
4720 * for new volume, and waits.
4721 * if dumping, end-of-file is written onto the tape.
4724 static void
4725 newvol(void)
4727 int c;
4729 if (dumping) {
4730 dlog("newvol called with 'dumping' set\n");
4731 putempty((blkcnt_t)2); /* 2 EOT marks */
4732 closevol();
4733 flushtape();
4734 sync();
4735 tapepos = 0;
4736 } else
4737 first = TRUE;
4738 if (close(mt) != 0)
4739 vperror(2, gettext("close error"));
4740 mt = 0;
4741 (void) fprintf(stderr, gettext(
4742 "tar: \007please insert new volume, then press RETURN."));
4743 (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */
4744 while ((c = getchar()) != '\n' && ! term)
4745 if (c == EOF)
4746 done(Errflg);
4747 if (term)
4748 done(Errflg);
4750 errno = 0;
4752 if (strcmp(usefile, "-") == 0) {
4753 mt = dup(1);
4754 } else {
4755 mt = open(usefile, dumping ? update : 0);
4758 if (mt < 0) {
4759 (void) fprintf(stderr, gettext(
4760 "tar: cannot reopen %s (%s)\n"),
4761 dumping ? gettext("output") : gettext("input"), usefile);
4763 dlog("update=%d, usefile=%s ", update, usefile);
4764 dlog("mt=%d, [%s]\n", mt, strerror(errno));
4766 done(2);
4771 * Write a trailer portion to close out the current output volume.
4774 static void
4775 closevol(void)
4777 if (mulvol) {
4779 * blocklim does not count the 2 EOT marks;
4780 * tapepos does count the 2 EOT marks;
4781 * therefore we need the +2 below.
4783 putempty(blocklim + (blkcnt_t)2 - tapepos);
4787 static void
4788 done(int n)
4791 * If we were terminated in some way, and we would otherwise have
4792 * exited with a value of 0, adjust to 1, so that external callers
4793 * can determine this by looking at the exit status.
4795 if (term && n == 0)
4796 n = 1;
4798 if (tfile != NULL)
4799 (void) unlink(tname);
4800 if (compress_opt != NULL)
4801 (void) free(compress_opt);
4802 if (mt > 0) {
4803 if ((close(mt) != 0) || (fclose(stdout) != 0)) {
4804 perror(gettext("tar: close error"));
4805 exit(2);
4809 * If we have a compression child, we should have a child process that
4810 * we're waiting for to finish compressing or uncompressing the tar
4811 * stream.
4813 if (comp_pid != 0)
4814 wait_pid(comp_pid);
4815 exit(n);
4819 * Determine if s1 is a prefix portion of s2 (or the same as s2).
4822 static int
4823 is_prefix(char *s1, char *s2)
4825 while (*s1)
4826 if (*s1++ != *s2++)
4827 return (0);
4828 if (*s2)
4829 return (*s2 == '/');
4830 return (1);
4834 * lookup and bsrch look through tfile entries to find a match for a name.
4835 * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
4836 * a pair of newline chars, so the buffer it uses must be long enough for
4837 * two lines: name and modification time as well as period, newline and space.
4839 * A kludge was added to bsrch to take care of matching on the first entry
4840 * in the file--there is no leading newline. So, if we are reading from the
4841 * start of the file, read into byte two and set the first byte to a newline.
4842 * Otherwise, the first entry cannot be matched.
4846 #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4847 static off_t
4848 lookup(char *s)
4850 int i;
4851 off_t a;
4853 for (i = 0; s[i]; i++)
4854 if (s[i] == ' ')
4855 break;
4856 a = bsrch(s, i, low, high);
4857 return (a);
4860 static off_t
4861 bsrch(char *s, int n, off_t l, off_t h)
4863 int i, j;
4864 char b[N];
4865 off_t m, m1;
4868 loop:
4869 if (l >= h)
4870 return ((off_t)-1);
4871 m = l + (h-l)/2 - N/2;
4872 if (m < l)
4873 m = l;
4874 (void) fseek(tfile, m, 0);
4875 if (m == 0) {
4876 (void) fread(b+1, 1, N-1, tfile);
4877 b[0] = '\n';
4878 m--;
4879 } else
4880 (void) fread(b, 1, N, tfile);
4881 for (i = 0; i < N; i++) {
4882 if (b[i] == '\n')
4883 break;
4884 m++;
4886 if (m >= h)
4887 return ((off_t)-1);
4888 m1 = m;
4889 j = i;
4890 for (i++; i < N; i++) {
4891 m1++;
4892 if (b[i] == '\n')
4893 break;
4895 i = cmp(b+j, s, n);
4896 if (i < 0) {
4897 h = m;
4898 goto loop;
4900 if (i > 0) {
4901 l = m1;
4902 goto loop;
4904 if (m < 0)
4905 m = 0;
4906 return (m);
4909 static int
4910 cmp(char *b, char *s, int n)
4912 int i;
4914 assert(b[0] == '\n');
4916 for (i = 0; i < n; i++) {
4917 if (b[i+1] > s[i])
4918 return (-1);
4919 if (b[i+1] < s[i])
4920 return (1);
4922 return (b[i+1] == ' '? 0 : -1);
4927 * seekdisk seek to next file on archive
4929 * called by passtape() only
4931 * WARNING: expects "nblock" to be set, that is, readtape() to have
4932 * already been called. Since passtape() is only called
4933 * after a file header block has been read (why else would
4934 * we skip to next file?), this is currently safe.
4936 * changed to guarantee SYS_BLOCK boundary
4939 static void
4940 seekdisk(blkcnt_t blocks)
4942 off_t seekval;
4943 #if SYS_BLOCK > TBLOCK
4944 /* handle non-multiple of SYS_BLOCK */
4945 blkcnt_t nxb; /* # extra blocks */
4946 #endif
4948 tapepos += blocks;
4949 dlog("seekdisk(%" FMT_blkcnt_t ") called\n", blocks);
4950 if (recno + blocks <= nblock) {
4951 recno += blocks;
4952 return;
4954 if (recno > nblock)
4955 recno = nblock;
4956 seekval = (off_t)blocks - (nblock - recno);
4957 recno = nblock; /* so readtape() reads next time through */
4958 #if SYS_BLOCK > TBLOCK
4959 nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
4960 dlog("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
4961 nxb, seekval);
4962 if (nxb && nxb > seekval) /* don't seek--we'll read */
4963 goto noseek;
4964 seekval -= nxb; /* don't seek quite so far */
4965 #endif
4966 if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
4967 (void) fprintf(stderr, gettext(
4968 "tar: device seek error\n"));
4969 done(3);
4971 #if SYS_BLOCK > TBLOCK
4972 /* read those extra blocks */
4973 noseek:
4974 if (nxb) {
4975 dlog("reading extra blocks\n");
4976 if (read(mt, tbuf, TBLOCK*nblock) < 0) {
4977 (void) fprintf(stderr, gettext(
4978 "tar: read error while skipping file\n"));
4979 done(8);
4981 recno = nxb; /* so we don't read in next readtape() */
4983 #endif
4986 static void
4987 readtape(char *buffer)
4989 int i, j;
4991 ++tapepos;
4992 if (recno >= nblock || first) {
4993 if (first) {
4995 * set the number of blocks to read initially, based on
4996 * the defined defaults for the device, or on the
4997 * explicit block factor given.
4999 if (bflag || defaults_used || NotTape)
5000 j = nblock;
5001 else
5002 j = NBLOCK;
5003 } else
5004 j = nblock;
5006 if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
5007 (void) fprintf(stderr, gettext(
5008 "tar: tape read error\n"));
5009 done(3);
5011 * i == 0 and !rflag means that EOF is reached and we are
5012 * trying to update or replace an empty tar file, so exit
5013 * with an error.
5015 * If i == 0 and !first and NotTape, it means the pointer
5016 * has gone past the EOF. It could happen if two processes
5017 * try to update the same tar file simultaneously. So exit
5018 * with an error.
5021 } else if (i == 0) {
5022 if (first && !rflag) {
5023 (void) fprintf(stderr, gettext(
5024 "tar: blocksize = %d\n"), i);
5025 done(Errflg);
5026 } else if (!first && (!rflag || NotTape)) {
5027 mterr("read", 0, 2);
5029 } else if ((!first || Bflag) && i != TBLOCK*j) {
5031 * Short read - try to get the remaining bytes.
5034 int remaining = (TBLOCK * j) - i;
5035 char *b = (char *)tbuf + i;
5036 int r;
5038 do {
5039 if ((r = read(mt, b, remaining)) < 0) {
5040 (void) fprintf(stderr,
5041 gettext("tar: tape read error\n"));
5042 done(3);
5044 b += r;
5045 remaining -= r;
5046 i += r;
5047 } while (remaining > 0 && r != 0);
5049 if (first) {
5050 if ((i % TBLOCK) != 0) {
5051 (void) fprintf(stderr, gettext(
5052 "tar: tape blocksize error\n"));
5053 done(3);
5055 i /= TBLOCK;
5056 if (vflag && i != nblock && i != 1) {
5057 if (!NotTape)
5058 (void) fprintf(stderr, gettext(
5059 "tar: blocksize = %d\n"), i);
5063 * If we are reading a tape, then a short read is
5064 * understood to signify that the amount read is
5065 * the tape's actual blocking factor. We adapt
5066 * nblock accordingly. There is no reason to do
5067 * this when the device is not blocked.
5070 if (!NotTape)
5071 nblock = i;
5073 recno = 0;
5076 first = FALSE;
5077 copy(buffer, &tbuf[recno++]);
5082 * replacement for writetape.
5085 static int
5086 writetbuf(char *buffer, int n)
5088 int i;
5090 tapepos += n; /* output block count */
5092 if (recno >= nblock) {
5093 i = write(mt, (char *)tbuf, TBLOCK*nblock);
5094 if (i != TBLOCK*nblock)
5095 mterr("write", i, 2);
5096 recno = 0;
5100 * Special case: We have an empty tape buffer, and the
5101 * users data size is >= the tape block size: Avoid
5102 * the bcopy and dma direct to tape. BIG WIN. Add the
5103 * residual to the tape buffer.
5105 while (recno == 0 && n >= nblock) {
5106 i = (int)write(mt, buffer, TBLOCK*nblock);
5107 if (i != TBLOCK*nblock)
5108 mterr("write", i, 2);
5109 n -= nblock;
5110 buffer += (nblock * TBLOCK);
5113 while (n-- > 0) {
5114 (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
5115 buffer += TBLOCK;
5116 if (recno >= nblock) {
5117 i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
5118 if (i != TBLOCK*nblock)
5119 mterr("write", i, 2);
5120 recno = 0;
5124 /* Tell the user how much to write to get in sync */
5125 return (nblock - recno);
5129 * backtape - reposition tape after reading soft "EOF" record
5131 * Backtape tries to reposition the tape back over the EOF
5132 * record. This is for the 'u' and 'r' function letters so that the
5133 * tape can be extended. This code is not well designed, but
5134 * I'm confident that the only callers who care about the
5135 * backspace-over-EOF feature are those involved in 'u' and 'r'.
5137 * The proper way to backup the tape is through the use of mtio.
5138 * Earlier spins used lseek combined with reads in a confusing
5139 * maneuver that only worked on 4.x, but shouldn't have, even
5140 * there. Lseeks are explicitly not supported for tape devices.
5143 static void
5144 backtape(void)
5146 struct mtop mtcmd;
5147 dlog("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
5148 nblock);
5150 * Backup to the position in the archive where the record
5151 * currently sitting in the tbuf buffer is situated.
5154 if (NotTape) {
5156 * For non-tape devices, this means lseeking to the
5157 * correct position. The absolute location tapepos-recno
5158 * should be the beginning of the current record.
5161 if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
5162 (off_t)-1) {
5163 (void) fprintf(stderr,
5164 gettext("tar: lseek to end of archive failed\n"));
5165 done(4);
5167 } else {
5169 * For tape devices, we backup over the most recently
5170 * read record.
5173 mtcmd.mt_op = MTBSR;
5174 mtcmd.mt_count = 1;
5176 if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
5177 (void) fprintf(stderr,
5178 gettext("tar: backspace over record failed\n"));
5179 done(4);
5184 * Decrement the tape and tbuf buffer indices to prepare for the
5185 * coming write to overwrite the soft EOF record.
5188 recno--;
5189 tapepos--;
5194 * flushtape write buffered block(s) onto tape
5196 * recno points to next free block in tbuf. If nonzero, a write is done.
5197 * Care is taken to write in multiples of SYS_BLOCK when device is
5198 * non-magtape in case raw i/o is used.
5200 * NOTE: this is called by writetape() to do the actual writing
5203 static void
5204 flushtape(void)
5206 dlog("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno);
5207 if (recno > 0) { /* anything buffered? */
5208 if (NotTape) {
5209 #if SYS_BLOCK > TBLOCK
5210 int i;
5213 * an odd-block write can only happen when
5214 * we are at the end of a volume that is not a tape.
5215 * Here we round recno up to an even SYS_BLOCK
5216 * boundary.
5218 if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
5219 dlog("flushtape() %d rounding blocks\n", i);
5220 recno += i; /* round up to even SYS_BLOCK */
5222 #endif
5223 if (recno > nblock)
5224 recno = nblock;
5226 dlog("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
5227 " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
5228 (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
5229 if (write(mt, tbuf,
5230 (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
5231 (void) fprintf(stderr, gettext(
5232 "tar: tape write error\n"));
5233 done(2);
5235 recno = 0;
5239 static void
5240 copy(void *dst, void *src)
5242 (void) memcpy(dst, src, TBLOCK);
5246 * kcheck()
5247 * - checks the validity of size values for non-tape devices
5248 * - if size is zero, mulvol tar is disabled and size is
5249 * assumed to be infinite.
5250 * - returns volume size in TBLOCKS
5253 static blkcnt_t
5254 kcheck(char *kstr)
5256 blkcnt_t kval;
5258 kval = strtoll(kstr, NULL, 0);
5259 if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */
5260 mulvol = 0; /* definitely not mulvol, but we must */
5261 return (0); /* took out setting of NotTape */
5263 if (kval < (blkcnt_t)MINSIZE) {
5264 (void) fprintf(stderr, gettext(
5265 "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5266 ").\n"), (ulong_t)MINSIZE, kval);
5267 (void) fprintf(stderr, gettext(
5268 "bad size entry for %s in %s.\n"),
5269 archive, DEF_FILE);
5270 done(1);
5272 mulvol++;
5273 NotTape++; /* implies non-tape */
5274 return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */
5279 * bcheck()
5280 * - checks the validity of blocking factors
5281 * - returns blocking factor
5284 static int
5285 bcheck(char *bstr)
5287 blkcnt_t bval;
5289 bval = strtoll(bstr, NULL, 0);
5290 if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
5291 (void) fprintf(stderr, gettext(
5292 "tar: invalid blocksize \"%s\".\n"), bstr);
5293 if (!bflag)
5294 (void) fprintf(stderr, gettext(
5295 "bad blocksize entry for '%s' in %s.\n"),
5296 archive, DEF_FILE);
5297 done(1);
5300 return ((int)bval);
5305 * defset()
5306 * - reads DEF_FILE for the set of default values specified.
5307 * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5308 * - 'usefile' points to static data, so will be overwritten
5309 * if this routine is called a second time.
5310 * - the pattern specified by 'arch' must be followed by four
5311 * blank-separated fields (1) device (2) blocking,
5312 * (3) size(K), and (4) tape
5313 * for example: archive0=/dev/fd 1 400 n
5316 static int
5317 defset(char *arch)
5319 char *bp;
5321 if (defopen(DEF_FILE) != 0)
5322 return (FALSE);
5323 if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
5324 (void) fprintf(stderr, gettext(
5325 "tar: error setting parameters for %s.\n"), DEF_FILE);
5326 return (FALSE); /* & following ones too */
5328 if ((bp = defread(arch)) == NULL) {
5329 (void) fprintf(stderr, gettext(
5330 "tar: missing or invalid '%s' entry in %s.\n"),
5331 arch, DEF_FILE);
5332 return (FALSE);
5334 if ((usefile = strtok(bp, " \t")) == NULL) {
5335 (void) fprintf(stderr, gettext(
5336 "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
5337 return (FALSE);
5339 if ((bp = strtok(NULL, " \t")) == NULL) {
5340 (void) fprintf(stderr, gettext(
5341 "tar: block component missing in '%s' entry in %s.\n"),
5342 arch, DEF_FILE);
5343 return (FALSE);
5345 nblock = bcheck(bp);
5346 if ((bp = strtok(NULL, " \t")) == NULL) {
5347 (void) fprintf(stderr, gettext(
5348 "tar: size component missing in '%s' entry in %s.\n"),
5349 arch, DEF_FILE);
5350 return (FALSE);
5352 blocklim = kcheck(bp);
5353 if ((bp = strtok(NULL, " \t")) != NULL)
5354 NotTape = (*bp == 'n' || *bp == 'N');
5355 else
5356 NotTape = (blocklim != 0);
5357 (void) defopen(NULL);
5358 dlog("defset: archive='%s'; usefile='%s'\n", arch, usefile);
5359 dlog("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
5360 nblock, blocklim);
5361 dlog("defset: not tape = %d\n", NotTape);
5362 return (TRUE);
5367 * Following code handles excluded and included files.
5368 * A hash table of file names to be {in,ex}cluded is built.
5369 * For excluded files, before writing or extracting a file
5370 * check to see if it is in the exclude_tbl.
5371 * For included files, the wantit() procedure will check to
5372 * see if the named file is in the include_tbl.
5375 static void
5376 build_table(file_list_t *table[], char *file)
5378 FILE *fp;
5379 char buf[PATH_MAX + 1];
5381 if ((fp = fopen(file, "r")) == (FILE *)NULL)
5382 vperror(1, gettext("could not open %s"), file);
5383 while (fgets(buf, sizeof (buf), fp) != NULL) {
5384 if (buf[strlen(buf) - 1] == '\n')
5385 buf[strlen(buf) - 1] = '\0';
5386 /* Only add to table if line has something in it */
5387 if (strspn(buf, " \t") != strlen(buf))
5388 add_file_to_table(table, buf);
5390 (void) fclose(fp);
5395 * Add a file name to the the specified table, if the file name has any
5396 * trailing '/'s then delete them before inserting into the table
5399 static void
5400 add_file_to_table(file_list_t *table[], char *str)
5402 char name[PATH_MAX + 1];
5403 unsigned int h;
5404 file_list_t *exp;
5406 (void) strcpy(name, str);
5407 while (name[strlen(name) - 1] == '/') {
5408 name[strlen(name) - 1] = '\0';
5411 h = hash(name);
5412 if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
5413 sizeof (char))) == NULL) {
5414 (void) fprintf(stderr, gettext(
5415 "tar: out of memory, exclude/include table(entry)\n"));
5416 exit(1);
5419 if ((exp->name = strdup(name)) == NULL) {
5420 (void) fprintf(stderr, gettext(
5421 "tar: out of memory, exclude/include table(file name)\n"));
5422 exit(1);
5425 exp->next = table[h];
5426 table[h] = exp;
5431 * See if a file name or any of the file's parent directories is in the
5432 * specified table, if the file name has any trailing '/'s then delete
5433 * them before searching the table
5436 static int
5437 is_in_table(file_list_t *table[], char *str)
5439 char name[PATH_MAX + 1];
5440 unsigned int h;
5441 file_list_t *exp;
5442 char *ptr;
5444 (void) strcpy(name, str);
5445 while (name[strlen(name) - 1] == '/') {
5446 name[strlen(name) - 1] = '\0';
5450 * check for the file name in the passed list
5452 h = hash(name);
5453 exp = table[h];
5454 while (exp != NULL) {
5455 if (strcmp(name, exp->name) == 0) {
5456 return (1);
5458 exp = exp->next;
5462 * check for any parent directories in the file list
5464 while ((ptr = strrchr(name, '/'))) {
5465 *ptr = '\0';
5466 h = hash(name);
5467 exp = table[h];
5468 while (exp != NULL) {
5469 if (strcmp(name, exp->name) == 0) {
5470 return (1);
5472 exp = exp->next;
5476 return (0);
5481 * Compute a hash from a string.
5484 static unsigned int
5485 hash(char *str)
5487 char *cp;
5488 unsigned int h;
5490 h = 0;
5491 for (cp = str; *cp; cp++) {
5492 h += *cp;
5494 return (h % TABLE_SIZE);
5497 static void *
5498 getmem(size_t size)
5500 void *p = calloc((unsigned)size, sizeof (char));
5502 if (p == NULL && freemem) {
5503 (void) fprintf(stderr, gettext(
5504 "tar: out of memory, link and directory modtime "
5505 "info lost\n"));
5506 freemem = 0;
5507 if (errflag)
5508 done(1);
5509 else
5510 Errflg = 1;
5512 return (p);
5516 * vperror() --variable argument perror.
5517 * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
5518 * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5519 * with the value of whatever "errno" is set to. If exit_status is not
5520 * zero, then tar exits with that error status. If errflag and exit_status
5521 * are both zero, the routine returns to where it was called and sets Errflg
5522 * to errno.
5525 static void
5526 vperror(int exit_status, char *fmt, ...)
5528 va_list ap;
5530 va_start(ap, fmt);
5531 (void) fputs("tar: ", stderr);
5532 (void) vfprintf(stderr, fmt, ap);
5533 (void) fprintf(stderr, ": %s\n", strerror(errno));
5534 va_end(ap);
5535 if (exit_status)
5536 done(exit_status);
5537 else
5538 if (errflag)
5539 done(errno);
5540 else
5541 Errflg = errno;
5545 static void
5546 fatal(char *format, ...)
5548 va_list ap;
5550 va_start(ap, format);
5551 (void) fprintf(stderr, "tar: ");
5552 (void) vfprintf(stderr, format, ap);
5553 (void) fprintf(stderr, "\n");
5554 va_end(ap);
5555 done(1);
5560 * Check to make sure that argument is a char * ptr.
5561 * Actually, we just check to see that it is non-null.
5562 * If it is null, print out the message and call usage(), bailing out.
5565 static void
5566 assert_string(char *s, char *msg)
5568 if (s == NULL) {
5569 (void) fprintf(stderr, msg);
5570 usage();
5575 static void
5576 mterr(char *operation, int i, int exitcode)
5578 (void) fprintf(stderr, gettext(
5579 "tar: %s error: "), operation);
5580 if (i < 0)
5581 perror("");
5582 else
5583 (void) fprintf(stderr, gettext("unexpected EOF\n"));
5584 done(exitcode);
5587 static int
5588 wantit(char *argv[], char **namep, char **dirp, char **component,
5589 attr_data_t **attrinfo)
5591 char **cp;
5592 int gotit; /* true if we've found a match */
5593 int ret;
5595 top:
5596 if (xhdr_flgs & _X_XHDR) {
5597 xhdr_flgs = 0;
5599 getdir();
5600 if (Xhdrflag > 0) {
5601 ret = get_xdata();
5602 if (ret != 0) { /* Xhdr items and regular header */
5603 setbytes_to_skip(&stbuf, ret);
5604 passtape();
5605 return (0); /* Error--don't want to extract */
5610 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5611 * of ancillary file is either over or ancillary file
5612 * processing is not required, load info from Xtarhdr and set
5613 * _X_XHDR bit in xhdr_flgs.
5615 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
5616 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
5617 xhdr_flgs |= _X_XHDR;
5620 #if defined(O_XATTR)
5621 if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
5623 * Always needs to read the extended header. If atflag, saflag,
5624 * or tflag isn't set, then we'll have the correct info for
5625 * passtape() later.
5627 (void) read_xattr_hdr(attrinfo);
5628 goto top;
5631 * Now that we've read the extended header, call passtape()
5632 * if we don't want to restore attributes or system attributes.
5633 * Don't restore the attribute if we are extracting
5634 * a file from an archive (as opposed to doing a table of
5635 * contents) and any of the following are true:
5636 * 1. neither -@ or -/ was specified.
5637 * 2. -@ was specified, -/ wasn't specified, and we're
5638 * processing a hidden attribute directory of an attribute
5639 * or we're processing a read-write system attribute file.
5640 * 3. -@ wasn't specified, -/ was specified, and the file
5641 * we're processing is not a read-write system attribute file,
5642 * or we're processing the hidden attribute directory of an
5643 * attribute.
5645 * We always process the attributes if we're just generating
5646 * generating a table of contents, or if both -@ and -/ were
5647 * specified.
5649 if (xattrp != NULL) {
5650 attr_data_t *ainfo = *attrinfo;
5652 if (!tflag &&
5653 ((!atflag && !saflag) ||
5654 (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
5655 ainfo->attr_rw_sysattr)) ||
5656 (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
5657 !ainfo->attr_rw_sysattr)))) {
5658 passtape();
5659 return (0);
5662 #endif
5664 /* sets *namep to point at the proper name */
5665 if (check_prefix(namep, dirp, component) != 0) {
5666 passtape();
5667 return (0);
5670 if (endtape()) {
5671 if (Bflag) {
5672 ssize_t sz;
5673 size_t extra_blocks = 0;
5676 * Logically at EOT - consume any extra blocks
5677 * so that write to our stdin won't fail and
5678 * emit an error message; otherwise something
5679 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5680 * will produce a bogus error message from "dd".
5683 while ((sz = read(mt, tbuf, TBLOCK*nblock)) > 0) {
5684 extra_blocks += sz;
5686 dlog("wantit(): %d bytes of extra blocks\n",
5687 extra_blocks);
5689 dlog("wantit(): at end of tape.\n");
5690 return (-1);
5693 gotit = 0;
5695 if ((Iflag && is_in_table(include_tbl, *namep)) ||
5696 (! Iflag && *argv == NULL)) {
5697 gotit = 1;
5698 } else {
5699 for (cp = argv; *cp; cp++) {
5700 if (is_prefix(*cp, *namep)) {
5701 gotit = 1;
5702 break;
5707 if (! gotit) {
5708 passtape();
5709 return (0);
5712 if (Xflag && is_in_table(exclude_tbl, *namep)) {
5713 if (vflag) {
5714 (void) fprintf(stderr, gettext("%s excluded\n"),
5715 *namep);
5717 passtape();
5718 return (0);
5721 return (1);
5725 static void
5726 setbytes_to_skip(struct stat *st, int err)
5729 * In a scenario where a typeflag 'X' was followed by
5730 * a typeflag 'A' and typeflag 'O', then the number of
5731 * bytes to skip should be the size of ancillary file,
5732 * plus the dblock for regular file, and the size
5733 * from Xtarhdr. However, if the typeflag was just 'X'
5734 * followed by typeflag 'O', then the number of bytes
5735 * to skip should be the size from Xtarhdr.
5737 if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
5738 (xhdr_flgs & _X_SIZE)) {
5739 st->st_size += TBLOCK + Xtarhdr.x_filesz;
5740 xhdr_flgs |= _X_XHDR;
5741 } else if ((dblock.dbuf.typeflag != 'A') &&
5742 (xhdr_flgs & _X_SIZE)) {
5743 st->st_size += Xtarhdr.x_filesz;
5744 xhdr_flgs |= _X_XHDR;
5748 static int
5749 fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
5750 int rw_sysattr, attr_data_t **attrinfo)
5752 size_t pathlen;
5753 char *tpath;
5754 char *tparent;
5756 /* parent info */
5757 if (attrparent != NULL) {
5758 if ((tparent = strdup(attrparent)) == NULL) {
5759 vperror(0, gettext(
5760 "unable to allocate memory for attribute parent "
5761 "name for %sattribute %s/%s of %s"),
5762 rw_sysattr ? gettext("system ") : "",
5763 attrparent, attr, longname);
5764 return (1);
5766 } else {
5767 tparent = NULL;
5770 /* path info */
5771 pathlen = strlen(attr) + 1;
5772 if (attrparent != NULL) {
5773 pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
5775 if ((tpath = calloc(1, pathlen)) == NULL) {
5776 vperror(0, gettext(
5777 "unable to allocate memory for full "
5778 "attribute path name for %sattribute %s%s%s of %s"),
5779 rw_sysattr ? gettext("system ") : "",
5780 (attrparent == NULL) ? "" : attrparent,
5781 (attrparent == NULL) ? "" : "/",
5782 attr, longname);
5783 if (tparent != NULL) {
5784 free(tparent);
5786 return (1);
5788 (void) snprintf(tpath, pathlen, "%s%s%s",
5789 (attrparent == NULL) ? "" : attrparent,
5790 (attrparent == NULL) ? "" : "/",
5791 attr);
5793 /* fill in the attribute info */
5794 if (*attrinfo == NULL) {
5795 if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
5796 vperror(0, gettext(
5797 "unable to allocate memory for attribute "
5798 "information for %sattribute %s%s%s of %s"),
5799 rw_sysattr ? gettext("system ") : "",
5800 (attrparent == NULL) ? "" : attrparent,
5801 (attrparent == NULL) ? "" : gettext("/"),
5802 attr, longname);
5803 if (tparent != NULL) {
5804 free(tparent);
5806 free(tpath);
5807 return (1);
5809 } else {
5810 if ((*attrinfo)->attr_parent != NULL) {
5811 free((*attrinfo)->attr_parent);
5813 if ((*attrinfo)->attr_path != NULL) {
5814 free((*attrinfo)->attr_path);
5817 * The parent file descriptor is passed in, so don't
5818 * close it here as it should be closed by the function
5819 * that opened it.
5822 (*attrinfo)->attr_parent = tparent;
5823 (*attrinfo)->attr_path = tpath;
5824 (*attrinfo)->attr_rw_sysattr = rw_sysattr;
5825 (*attrinfo)->attr_parentfd = atparentfd;
5827 return (0);
5831 * Test to see if name is a directory.
5833 * Return 1 if true, 0 otherwise.
5836 static int
5837 is_directory(char *name)
5839 #if defined(O_XATTR)
5841 * If there is an xattr_buf structure associated with this file,
5842 * then the directory test is based on whether the name has a
5843 * trailing slash.
5845 if (xattrp)
5846 return (name[strlen(name) - 1] == '/');
5847 #endif
5848 if (is_posix)
5849 return (dblock.dbuf.typeflag == '5');
5850 else
5851 return (name[strlen(name) - 1] == '/');
5855 * Version of chdir that handles directory pathnames of greater than PATH_MAX
5856 * length, by changing the working directory to manageable portions of the
5857 * complete directory pathname. If any of these attempts fail, then it exits
5858 * non-zero.
5860 * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
5861 * pathname is greater than PATH_MAX, then this still won't work, and this
5862 * routine will return -1 with errno set to ENAMETOOLONG.
5864 * NOTE: this routine is semantically different to the system chdir in
5865 * that it is remotely possible for the currently working directory to be
5866 * changed to a different directory, if a chdir call fails when processing
5867 * one of the segments of a path that is greater than PATH_MAX. This isn't
5868 * a problem as this is tar's own specific version of chdir.
5871 static int
5872 tar_chdir(const char *path)
5874 const char *sep = "/";
5875 char *path_copy = NULL;
5876 char *ptr = NULL;
5878 /* The trivial case. */
5879 if (chdir(path) == 0) {
5880 return (0);
5882 if (errno == ENAMETOOLONG) {
5883 if (path[0] == '/' && chdir(sep) != 0)
5884 return (-1);
5886 /* strtok(3C) modifies the string, so make a copy. */
5887 if ((path_copy = strdup(path)) == NULL) {
5888 return (-1);
5891 /* chdir(2) for every path element. */
5892 for (ptr = strtok(path_copy, sep);
5893 ptr != NULL;
5894 ptr = strtok(NULL, sep)) {
5895 if (chdir(ptr) != 0) {
5896 free(path_copy);
5897 return (-1);
5900 free(path_copy);
5901 return (0);
5904 /* If chdir fails for any reason except ENAMETOOLONG. */
5905 return (-1);
5909 * Test if name has a '..' sequence in it.
5911 * Return 1 if found, 0 otherwise.
5914 static int
5915 has_dot_dot(char *name)
5917 char *s;
5918 size_t name_len = strlen(name);
5920 for (s = name; s < (name + name_len - 2); s++) {
5921 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
5922 return (1);
5924 while (! (*s == '/')) {
5925 if (! *s++)
5926 return (0);
5930 return (0);
5934 * Test if name is an absolute path name.
5936 * Return 1 if true, 0 otherwise.
5939 static int
5940 is_absolute(char *name)
5942 #if defined(O_XATTR)
5944 * If this is an extended attribute (whose name will begin with
5945 * "/dev/null/", always return 0 as they should be extracted with
5946 * the name intact, to allow other tar archiving programs that
5947 * don't understand extended attributes, to correctly throw them away.
5949 if (xattrp)
5950 return (0);
5951 #endif
5953 return (name[0] == '/');
5957 * Adjust the pathname to make it a relative one. Strip off any leading
5958 * '/' characters and if the pathname contains any '..' sequences, strip
5959 * upto and including the last occurance of '../' (or '..' if found at
5960 * the very end of the pathname).
5962 * Return the relative pathname. stripped_prefix will also return the
5963 * portion of name that was stripped off and should be freed by the
5964 * calling routine when no longer needed.
5967 static char *
5968 make_relative_name(char *name, char **stripped_prefix)
5970 char *s;
5971 size_t prefix_len = 0;
5972 size_t name_len = strlen(name);
5974 for (s = name + prefix_len; s < (name + name_len - 2); ) {
5975 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
5976 prefix_len = s + 2 - name;
5978 do {
5979 char c = *s++;
5981 if (c == '/')
5982 break;
5983 } while (*s);
5986 for (s = name + prefix_len; *s == '/'; s++)
5987 continue;
5988 prefix_len = s - name;
5990 /* Create the portion of the name that was stripped off. */
5991 s = malloc(prefix_len + 1);
5992 memcpy(s, name, prefix_len);
5993 s[prefix_len] = 0;
5994 *stripped_prefix = s;
5995 s = &name[prefix_len];
5997 return (s);
6001 * Return through *namep a pointer to the proper fullname (i.e "<name> |
6002 * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6004 * Returns 0 if successful, otherwise returns 1.
6007 static int
6008 check_prefix(char **namep, char **dirp, char **compp)
6010 static char fullname[PATH_MAX + 1];
6011 static char dir[PATH_MAX + 1];
6012 static char component[PATH_MAX + 1];
6013 static char savename[PATH_MAX + 1];
6014 char *s;
6016 (void) memset(dir, 0, sizeof (dir));
6017 (void) memset(component, 0, sizeof (component));
6019 if (xhdr_flgs & _X_PATH) {
6020 (void) strcpy(fullname, Xtarhdr.x_path);
6021 } else {
6022 if (dblock.dbuf.prefix[0] != '\0')
6023 (void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
6024 dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
6025 else
6026 (void) sprintf(fullname, "%.*s", NAMSIZ,
6027 dblock.dbuf.name);
6031 * If we are printing a table of contents or extracting an archive,
6032 * make absolute pathnames relative and prohibit the unpacking of
6033 * files contain ".." in their name (unless the user has supplied
6034 * the -P option).
6036 if ((tflag || xflag) && !Pflag) {
6037 if (is_absolute(fullname) || has_dot_dot(fullname)) {
6038 char *stripped_prefix;
6040 (void) strcpy(savename, fullname);
6041 strcpy(fullname,
6042 make_relative_name(savename, &stripped_prefix));
6043 (void) fprintf(stderr,
6044 gettext("tar: Removing leading '%s' from '%s'\n"),
6045 stripped_prefix, savename);
6046 free(stripped_prefix);
6051 * Set dir and component names
6054 get_parent(fullname, dir);
6056 #if defined(O_XATTR)
6057 if (xattrp == NULL) {
6058 #endif
6060 * Save of real name since were going to chop off the
6061 * trailing slashes.
6063 (void) strcpy(savename, fullname);
6065 * first strip of trailing slashes.
6067 chop_endslashes(savename);
6068 s = get_component(savename);
6069 (void) strcpy(component, s);
6071 #if defined(O_XATTR)
6072 } else {
6073 (void) strcpy(fullname, xattrp->h_names);
6074 (void) strcpy(dir, fullname);
6075 (void) strcpy(component, basename(xattrp->h_names +
6076 strlen(xattrp->h_names) + 1));
6078 #endif
6079 *namep = fullname;
6080 *dirp = dir;
6081 *compp = component;
6083 return (0);
6087 * Return true if the object indicated by the file descriptor and type
6088 * is a tape device, false otherwise
6091 static int
6092 istape(int fd, int type)
6094 int result = 0;
6096 if (S_ISCHR(type)) {
6097 struct mtget mtg;
6099 if (ioctl(fd, MTIOCGET, &mtg) != -1) {
6100 result = 1;
6104 return (result);
6107 #include <utmpx.h>
6109 struct utmpx utmpx;
6111 #define NMAX (sizeof (utmpx.ut_name))
6113 typedef struct cachenode { /* this struct must be zeroed before using */
6114 struct cachenode *next; /* next in hash chain */
6115 int val; /* the uid or gid of this entry */
6116 int namehash; /* name's hash signature */
6117 char name[NMAX+1]; /* the string that val maps to */
6118 } cachenode_t;
6120 #define HASHSIZE 256
6122 static cachenode_t *names[HASHSIZE];
6123 static cachenode_t *groups[HASHSIZE];
6124 static cachenode_t *uids[HASHSIZE];
6125 static cachenode_t *gids[HASHSIZE];
6127 static int
6128 hash_byname(char *name)
6130 int i, c, h = 0;
6132 for (i = 0; i < NMAX; i++) {
6133 c = name[i];
6134 if (c == '\0')
6135 break;
6136 h = (h << 4) + h + c;
6138 return (h);
6141 static cachenode_t *
6142 hash_lookup_byval(cachenode_t *table[], int val)
6144 int h = val;
6145 cachenode_t *c;
6147 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6148 if (c->val == val)
6149 return (c);
6151 return (NULL);
6154 static cachenode_t *
6155 hash_lookup_byname(cachenode_t *table[], char *name)
6157 int h = hash_byname(name);
6158 cachenode_t *c;
6160 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6161 if (c->namehash == h && strcmp(c->name, name) == 0)
6162 return (c);
6164 return (NULL);
6167 static cachenode_t *
6168 hash_insert(cachenode_t *table[], char *name, int value)
6170 cachenode_t *c;
6171 int signature;
6173 c = calloc(1, sizeof (cachenode_t));
6174 if (c == NULL) {
6175 perror("malloc");
6176 exit(1);
6178 if (name != NULL) {
6179 (void) strncpy(c->name, name, NMAX);
6180 c->namehash = hash_byname(name);
6182 c->val = value;
6183 if (table == uids || table == gids)
6184 signature = c->val;
6185 else
6186 signature = c->namehash;
6187 c->next = table[signature & (HASHSIZE - 1)];
6188 table[signature & (HASHSIZE - 1)] = c;
6189 return (c);
6192 static char *
6193 getname(uid_t uid)
6195 cachenode_t *c;
6197 if ((c = hash_lookup_byval(uids, uid)) == NULL) {
6198 struct passwd *pwent = getpwuid(uid);
6199 c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
6201 return (c->name);
6204 static char *
6205 getgroup(gid_t gid)
6207 cachenode_t *c;
6209 if ((c = hash_lookup_byval(gids, gid)) == NULL) {
6210 struct group *grent = getgrgid(gid);
6211 c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
6213 return (c->name);
6216 static uid_t
6217 getuidbyname(char *name)
6219 cachenode_t *c;
6221 if ((c = hash_lookup_byname(names, name)) == NULL) {
6222 struct passwd *pwent = getpwnam(name);
6223 c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
6225 return ((uid_t)c->val);
6228 static gid_t
6229 getgidbyname(char *group)
6231 cachenode_t *c;
6233 if ((c = hash_lookup_byname(groups, group)) == NULL) {
6234 struct group *grent = getgrnam(group);
6235 c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
6237 return ((gid_t)c->val);
6241 * Build the header.
6242 * Determine whether or not an extended header is also needed. If needed,
6243 * create and write the extended header and its data.
6244 * Writing of the extended header assumes that "tomodes" has been called and
6245 * the relevant information has been placed in the header block.
6248 static int
6249 build_dblock(
6250 const char *name,
6251 const char *linkname,
6252 const char typeflag,
6253 const int filetype,
6254 const struct stat *sp,
6255 const dev_t device,
6256 const char *prefix)
6258 int nblks;
6259 major_t dev;
6260 const char *filename;
6261 const char *lastslash;
6263 if (filetype == XATTR_FILE)
6264 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
6265 else
6266 dblock.dbuf.typeflag = typeflag;
6267 (void) memset(dblock.dbuf.name, '\0', NAMSIZ);
6268 (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
6269 (void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
6271 if (xhdr_flgs & _X_PATH)
6272 filename = Xtarhdr.x_path;
6273 else
6274 filename = name;
6276 if ((dev = major(device)) > OCTAL7CHAR) {
6277 if (Eflag) {
6278 xhdr_flgs |= _X_DEVMAJOR;
6279 Xtarhdr.x_devmajor = dev;
6280 } else {
6281 (void) fprintf(stderr, gettext(
6282 "Device major too large for %s. Use -E flag."),
6283 filename);
6284 if (errflag)
6285 done(1);
6286 else
6287 Errflg = 1;
6289 dev = 0;
6291 (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
6292 if ((dev = minor(device)) > OCTAL7CHAR) {
6293 if (Eflag) {
6294 xhdr_flgs |= _X_DEVMINOR;
6295 Xtarhdr.x_devminor = dev;
6296 } else {
6297 (void) fprintf(stderr, gettext(
6298 "Device minor too large for %s. Use -E flag."),
6299 filename);
6300 if (errflag)
6301 done(1);
6302 else
6303 Errflg = 1;
6305 dev = 0;
6307 (void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
6309 (void) strncpy(dblock.dbuf.name, name, NAMSIZ);
6310 (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
6311 (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
6312 (void) sprintf(dblock.dbuf.version, "00");
6313 (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
6314 (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
6315 (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
6316 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
6318 if (Eflag) {
6319 (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
6320 (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
6321 lastslash = strrchr(name, '/');
6322 if (lastslash == NULL)
6323 lastslash = name;
6324 else
6325 lastslash++;
6326 (void) strcpy(xhdr_buf.dbuf.name, lastslash);
6327 (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
6328 (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
6329 (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
6330 xhdr_count++;
6331 xrec_offset = 0;
6332 gen_date("mtime", sp->st_mtim);
6333 xhdr_buf.dbuf.typeflag = 'X';
6334 if (gen_utf8_names(filename) != 0)
6335 return (1);
6337 #ifdef XHDR_DEBUG
6338 Xtarhdr.x_uname = dblock.dbuf.uname;
6339 Xtarhdr.x_gname = dblock.dbuf.gname;
6340 xhdr_flgs |= (_X_UNAME | _X_GNAME);
6341 #endif
6342 if (xhdr_flgs) {
6343 if (xhdr_flgs & _X_DEVMAJOR)
6344 gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
6345 if (xhdr_flgs & _X_DEVMINOR)
6346 gen_num("SUN.devminor", Xtarhdr.x_devminor);
6347 if (xhdr_flgs & _X_GID)
6348 gen_num("gid", Xtarhdr.x_gid);
6349 if (xhdr_flgs & _X_UID)
6350 gen_num("uid", Xtarhdr.x_uid);
6351 if (xhdr_flgs & _X_SIZE)
6352 gen_num("size", Xtarhdr.x_filesz);
6353 if (xhdr_flgs & _X_PATH)
6354 gen_string("path", Xtarhdr.x_path);
6355 if (xhdr_flgs & _X_LINKPATH)
6356 gen_string("linkpath", Xtarhdr.x_linkpath);
6357 if (xhdr_flgs & _X_GNAME)
6358 gen_string("gname", Xtarhdr.x_gname);
6359 if (xhdr_flgs & _X_UNAME)
6360 gen_string("uname", Xtarhdr.x_uname);
6362 (void) sprintf(xhdr_buf.dbuf.size,
6363 "%011" FMT_off_t_o, xrec_offset);
6364 (void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
6365 checksum(&xhdr_buf));
6366 (void) writetbuf((char *)&xhdr_buf, 1);
6367 nblks = TBLOCKS(xrec_offset);
6368 (void) writetbuf(xrec_ptr, nblks);
6370 return (0);
6375 * makeDir - ensure that a directory with the pathname denoted by name
6376 * exists, and return 1 on success, and 0 on failure (e.g.,
6377 * read-only file system, exists but not-a-directory).
6380 static int
6381 makeDir(char *name)
6383 struct stat buf;
6385 if (access(name, 0) < 0) { /* name doesn't exist */
6386 if (mkdir(name, 0777) < 0) {
6387 vperror(0, "%s", name);
6388 return (0);
6390 } else { /* name exists */
6391 if (stat(name, &buf) < 0) {
6392 vperror(0, "%s", name);
6393 return (0);
6396 return ((buf.st_mode & S_IFMT) == S_IFDIR);
6399 return (1);
6404 * Save this directory and its mtime on the stack, popping and setting
6405 * the mtimes of any stacked dirs which aren't parents of this one.
6406 * A null name causes the entire stack to be unwound and set.
6408 * Since all the elements of the directory "stack" share a common
6409 * prefix, we can make do with one string. We keep only the current
6410 * directory path, with an associated array of mtime's. A negative
6411 * mtime means no mtime.
6413 * This stack algorithm is not guaranteed to work for tapes created
6414 * with the 'r' function letter, but the vast majority of tapes with
6415 * directories are not. This avoids saving every directory record on
6416 * the tape and setting all the times at the end.
6418 * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6419 * environment)
6422 static void
6423 doDirTimes(char *name, timestruc_t modTime)
6425 static char dirstack[PATH_MAX+2];
6426 /* Add spaces for the last slash and last NULL */
6427 static timestruc_t modtimes[PATH_MAX+1]; /* hash table */
6428 char *p = dirstack;
6429 char *q = name;
6430 char *savp;
6432 if (q) {
6434 * Find common prefix
6437 while (*p == *q && *p) {
6438 p++; q++;
6442 savp = p;
6443 while (*p) {
6445 * Not a child: unwind the stack, setting the times.
6446 * The order we do this doesn't matter, so we go "forward."
6449 if (*p == '/')
6450 if (modtimes[p - dirstack].tv_sec >= 0) {
6451 *p = '\0'; /* zap the slash */
6452 setPathTimes(AT_FDCWD, dirstack,
6453 modtimes[p - dirstack]);
6454 *p = '/';
6456 ++p;
6459 p = savp;
6462 * Push this one on the "stack"
6465 if (q) {
6468 * Since the name parameter points the dir pathname
6469 * which is limited only to contain PATH_MAX chars
6470 * at maximum, we can ignore the overflow case of p.
6473 while ((*p = *q++)) { /* append the rest of the new dir */
6474 modtimes[p - dirstack].tv_sec = -1;
6475 p++;
6479 * If the tar file had used 'P' or 'E' function modifier,
6480 * append the last slash.
6482 if (*(p - 1) != '/') {
6483 *p++ = '/';
6484 *p = '\0';
6486 /* overwrite the last one */
6487 modtimes[p - dirstack - 1] = modTime;
6493 * setPathTimes - set the modification time for given path. Return 1 if
6494 * successful and 0 if not successful.
6497 static void
6498 setPathTimes(int dirfd, char *path, timestruc_t modTime)
6500 struct timeval timebuf[2];
6503 * futimesat takes an array of two timeval structs.
6504 * The first entry contains access time.
6505 * The second entry contains modification time.
6506 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6507 * microseconds.
6509 timebuf[0].tv_sec = time((time_t *)0);
6510 timebuf[0].tv_usec = 0;
6511 timebuf[1].tv_sec = modTime.tv_sec;
6513 /* Extended header: use microseconds */
6514 timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
6516 if (futimesat(dirfd, path, timebuf) < 0)
6517 vperror(0, gettext("can't set time on %s"), path);
6522 * If hflag is set then delete the symbolic link's target.
6523 * If !hflag then delete the target.
6526 static void
6527 delete_target(int fd, char *comp, char *namep)
6529 struct stat xtractbuf;
6530 char buf[PATH_MAX + 1];
6531 int n;
6534 if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
6535 if (errno == ENOTDIR && !hflag) {
6536 (void) unlinkat(fd, comp, 0);
6537 } else if (errno == ENOTDIR && hflag) {
6538 if (!lstat(namep, &xtractbuf)) {
6539 if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
6540 (void) unlinkat(fd, comp, 0);
6541 } else if ((n = readlink(namep, buf,
6542 PATH_MAX)) != -1) {
6543 buf[n] = '\0';
6544 (void) unlinkat(fd, buf,
6545 AT_REMOVEDIR);
6546 if (errno == ENOTDIR)
6547 (void) unlinkat(fd, buf, 0);
6548 } else {
6549 (void) unlinkat(fd, comp, 0);
6551 } else {
6552 (void) unlinkat(fd, comp, 0);
6560 * ACL changes:
6561 * putfile():
6562 * Get acl info after stat. Write out ancillary file
6563 * before the normal file, i.e. directory, regular, FIFO,
6564 * link, special. If acl count is less than 4, no need to
6565 * create ancillary file. (i.e. standard permission is in
6566 * use.
6567 * doxtract():
6568 * Process ancillary file. Read it in and set acl info.
6569 * watch out for 'o' function modifier.
6570 * 't' function letter to display table
6574 * New functions for ACLs and other security attributes
6578 * The function appends the new security attribute info to the end of
6579 * existing secinfo.
6582 append_secattr(
6583 char **secinfo, /* existing security info */
6584 int *secinfo_len, /* length of existing security info */
6585 int size, /* new attribute size: unit depends on type */
6586 char *attrtext, /* new attribute text */
6587 char attr_type) /* new attribute type */
6589 char *new_secinfo;
6590 int newattrsize;
6591 int oldsize;
6592 struct sec_attr *attr;
6594 if (attrtext == NULL)
6595 return (0);
6597 switch (attr_type) {
6598 case UFSD_ACL:
6599 case ACE_ACL:
6600 if (attrtext == NULL) {
6601 (void) fprintf(stderr, gettext("acltotext failed\n"));
6602 return (-1);
6604 /* header: type + size = 8 */
6605 newattrsize = 8 + (int)strlen(attrtext) + 1;
6606 attr = (struct sec_attr *)malloc(newattrsize);
6607 if (attr == NULL) {
6608 (void) fprintf(stderr,
6609 gettext("can't allocate memory\n"));
6610 return (-1);
6612 attr->attr_type = attr_type;
6613 (void) sprintf(attr->attr_len,
6614 "%06o", size); /* acl entry count */
6615 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6616 free(attrtext);
6617 break;
6618 default:
6619 (void) fprintf(stderr,
6620 gettext("unrecognized attribute type\n"));
6621 return (-1);
6624 /* old security info + new attr header(8) + new attr */
6625 oldsize = *secinfo_len;
6626 *secinfo_len += newattrsize;
6627 new_secinfo = (char *)malloc(*secinfo_len);
6628 if (new_secinfo == NULL) {
6629 (void) fprintf(stderr, gettext("can't allocate memory\n"));
6630 *secinfo_len -= newattrsize;
6631 free(attr);
6632 return (-1);
6635 (void) memcpy(new_secinfo, *secinfo, oldsize);
6636 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6638 free(*secinfo);
6639 free(attr);
6640 *secinfo = new_secinfo;
6641 return (0);
6645 * write_ancillary(): write out an ancillary file.
6646 * The file has the same header as normal file except the type and size
6647 * fields. The type is 'A' and size is the sum of all attributes
6648 * in bytes.
6649 * The body contains a list of attribute type, size and info. Currently,
6650 * there is only ACL info. This file is put before the normal file.
6652 void
6653 write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
6655 long blocks;
6656 int savflag;
6657 int savsize;
6659 /* Just tranditional permissions or no security attribute info */
6660 if (len == 0 || secinfo == NULL)
6661 return;
6663 /* save flag and size */
6664 savflag = (dblockp->dbuf).typeflag;
6665 (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
6667 /* special flag for ancillary file */
6668 if (hdrtype == _XATTR_HDRTYPE)
6669 dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
6670 else
6671 dblockp->dbuf.typeflag = 'A';
6673 /* for pre-2.5 versions of tar, need to make sure */
6674 /* the ACL file is readable */
6675 (void) sprintf(dblock.dbuf.mode, "%07lo",
6676 (stbuf.st_mode & POSIXMODES) | 0000200);
6677 (void) sprintf(dblockp->dbuf.size, "%011o", len);
6678 (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
6680 /* write out the header */
6681 (void) writetbuf((char *)dblockp, 1);
6683 /* write out security info */
6684 blocks = TBLOCKS(len);
6685 (void) writetbuf((char *)secinfo, (int)blocks);
6687 /* restore mode, flag and size */
6688 (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
6689 dblockp->dbuf.typeflag = savflag;
6690 (void) sprintf(dblockp->dbuf.size, "%011o", savsize);
6694 * Read the data record for extended headers and then the regular header.
6695 * The data are read into the buffer and then null-terminated. Entries
6696 * for typeflag 'X' extended headers are of the format:
6697 * "%d %s=%s\n"
6699 * When an extended header record is found, the extended header must
6700 * be processed and its values used to override the values in the
6701 * normal header. The way this is done is to process the extended
6702 * header data record and set the data values, then call getdir
6703 * to process the regular header, then then to reconcile the two
6704 * sets of data.
6707 static int
6708 get_xdata(void)
6710 struct keylist_pair {
6711 int keynum;
6712 char *keylist;
6713 } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor",
6714 _X_DEVMINOR, "SUN.devminor",
6715 _X_GID, "gid",
6716 _X_GNAME, "gname",
6717 _X_LINKPATH, "linkpath",
6718 _X_PATH, "path",
6719 _X_SIZE, "size",
6720 _X_UID, "uid",
6721 _X_UNAME, "uname",
6722 _X_MTIME, "mtime",
6723 _X_LAST, "NULL" };
6724 char *lineloc;
6725 int length, i;
6726 char *keyword, *value;
6727 blkcnt_t nblocks;
6728 int bufneeded;
6729 int errors;
6731 (void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
6732 xhdr_count++;
6733 errors = 0;
6735 nblocks = TBLOCKS(stbuf.st_size);
6736 bufneeded = nblocks * TBLOCK;
6737 if (bufneeded >= xrec_size) {
6738 free(xrec_ptr);
6739 xrec_size = bufneeded + 1;
6740 if ((xrec_ptr = malloc(xrec_size)) == NULL)
6741 fatal(gettext("cannot allocate buffer"));
6744 lineloc = xrec_ptr;
6746 while (nblocks-- > 0) {
6747 readtape(lineloc);
6748 lineloc += TBLOCK;
6750 lineloc = xrec_ptr;
6751 xrec_ptr[stbuf.st_size] = '\0';
6752 while (lineloc < xrec_ptr + stbuf.st_size) {
6753 if (dblock.dbuf.typeflag == 'L') {
6754 length = xrec_size;
6755 keyword = "path";
6756 value = lineloc;
6757 } else {
6758 length = atoi(lineloc);
6759 *(lineloc + length - 1) = '\0';
6760 keyword = strchr(lineloc, ' ') + 1;
6761 value = strchr(keyword, '=') + 1;
6762 *(value - 1) = '\0';
6764 i = 0;
6765 lineloc += length;
6766 while (keylist_pair[i].keynum != (int)_X_LAST) {
6767 if (strcmp(keyword, keylist_pair[i].keylist) == 0)
6768 break;
6769 i++;
6771 errno = 0;
6772 switch (keylist_pair[i].keynum) {
6773 case _X_DEVMAJOR:
6774 Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
6775 if (errno) {
6776 (void) fprintf(stderr, gettext(
6777 "tar: Extended header major value error "
6778 "for file # %llu.\n"), xhdr_count);
6779 errors++;
6780 } else
6781 xhdr_flgs |= _X_DEVMAJOR;
6782 break;
6783 case _X_DEVMINOR:
6784 Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
6785 if (errno) {
6786 (void) fprintf(stderr, gettext(
6787 "tar: Extended header minor value error "
6788 "for file # %llu.\n"), xhdr_count);
6789 errors++;
6790 } else
6791 xhdr_flgs |= _X_DEVMINOR;
6792 break;
6793 case _X_GID:
6794 xhdr_flgs |= _X_GID;
6795 Xtarhdr.x_gid = strtol(value, NULL, 0);
6796 if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
6797 (void) fprintf(stderr, gettext(
6798 "tar: Extended header gid value error "
6799 "for file # %llu.\n"), xhdr_count);
6800 Xtarhdr.x_gid = GID_NOBODY;
6802 break;
6803 case _X_GNAME:
6804 if (utf8_local("gname", &Xtarhdr.x_gname,
6805 local_gname, value, _POSIX_NAME_MAX) == 0)
6806 xhdr_flgs |= _X_GNAME;
6807 break;
6808 case _X_LINKPATH:
6809 if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
6810 local_linkpath, value, PATH_MAX) == 0)
6811 xhdr_flgs |= _X_LINKPATH;
6812 else
6813 errors++;
6814 break;
6815 case _X_PATH:
6816 if (utf8_local("path", &Xtarhdr.x_path,
6817 local_path, value, PATH_MAX) == 0)
6818 xhdr_flgs |= _X_PATH;
6819 else
6820 errors++;
6821 break;
6822 case _X_SIZE:
6823 Xtarhdr.x_filesz = strtoull(value, NULL, 0);
6824 if (errno) {
6825 (void) fprintf(stderr, gettext(
6826 "tar: Extended header invalid filesize "
6827 "for file # %llu.\n"), xhdr_count);
6828 errors++;
6829 } else
6830 xhdr_flgs |= _X_SIZE;
6831 break;
6832 case _X_UID:
6833 xhdr_flgs |= _X_UID;
6834 Xtarhdr.x_uid = strtol(value, NULL, 0);
6835 if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
6836 (void) fprintf(stderr, gettext(
6837 "tar: Extended header uid value error "
6838 "for file # %llu.\n"), xhdr_count);
6839 Xtarhdr.x_uid = UID_NOBODY;
6841 break;
6842 case _X_UNAME:
6843 if (utf8_local("uname", &Xtarhdr.x_uname,
6844 local_uname, value, _POSIX_NAME_MAX) == 0)
6845 xhdr_flgs |= _X_UNAME;
6846 break;
6847 case _X_MTIME:
6848 get_xtime(value, &(Xtarhdr.x_mtime));
6849 if (errno)
6850 (void) fprintf(stderr, gettext(
6851 "tar: Extended header modification time "
6852 "value error for file # %llu.\n"),
6853 xhdr_count);
6854 else
6855 xhdr_flgs |= _X_MTIME;
6856 break;
6857 default:
6858 (void) fprintf(stderr,
6859 gettext("tar: unrecognized extended"
6860 " header keyword '%s'. Ignored.\n"), keyword);
6861 break;
6865 getdir(); /* get regular header */
6866 if (errors && errflag)
6867 done(1);
6868 else
6869 if (errors)
6870 Errflg = 1;
6871 return (errors);
6875 * load_info_from_xtarhdr - sets Gen and stbuf variables from
6876 * extended header
6877 * load_info_from_xtarhdr(flag, xhdrp);
6878 * u_longlong_t flag; xhdr_flgs
6879 * struct xtar_hdr *xhdrp; pointer to extended header
6880 * NOTE: called when typeflag is not 'A' and xhdr_flgs
6881 * is set.
6883 static void
6884 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
6886 if (flag & _X_DEVMAJOR) {
6887 Gen.g_devmajor = xhdrp->x_devmajor;
6889 if (flag & _X_DEVMINOR) {
6890 Gen.g_devminor = xhdrp->x_devminor;
6892 if (flag & _X_GID) {
6893 Gen.g_gid = xhdrp->x_gid;
6894 stbuf.st_gid = xhdrp->x_gid;
6896 if (flag & _X_UID) {
6897 Gen.g_uid = xhdrp->x_uid;
6898 stbuf.st_uid = xhdrp->x_uid;
6900 if (flag & _X_SIZE) {
6901 Gen.g_filesz = xhdrp->x_filesz;
6902 stbuf.st_size = xhdrp->x_filesz;
6904 if (flag & _X_MTIME) {
6905 Gen.g_mtime = xhdrp->x_mtime.tv_sec;
6906 stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
6907 stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
6912 * gen_num creates a string from a keyword and an usigned long long in the
6913 * format: %d %s=%s\n
6914 * This is part of the extended header data record.
6917 void
6918 gen_num(const char *keyword, const u_longlong_t number)
6920 char save_val[ULONGLONG_MAX_DIGITS + 1];
6921 int len;
6922 char *curr_ptr;
6924 (void) sprintf(save_val, "%llu", number);
6926 * len = length of entire line, including itself. len will be
6927 * two digits. So, add the string lengths plus the length of len,
6928 * plus a blank, an equal sign, and a newline.
6930 len = strlen(save_val) + strlen(keyword) + 5;
6931 if (xrec_offset + len > xrec_size) {
6932 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
6933 fatal(gettext(
6934 "cannot allocate extended header buffer"));
6935 xrec_ptr = curr_ptr;
6936 xrec_size *= 2;
6938 (void) sprintf(&xrec_ptr[xrec_offset],
6939 "%d %s=%s\n", len, keyword, save_val);
6940 xrec_offset += len;
6944 * gen_date creates a string from a keyword and a timestruc_t in the
6945 * format: %d %s=%s\n
6946 * This is part of the extended header data record.
6947 * Currently, granularity is only microseconds, so the low-order three digits
6948 * will be truncated.
6951 void
6952 gen_date(const char *keyword, const timestruc_t time_value)
6954 /* Allow for <seconds>.<nanoseconds>\n */
6955 char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
6956 int len;
6957 char *curr_ptr;
6959 (void) sprintf(save_val, "%ld", time_value.tv_sec);
6960 len = strlen(save_val);
6961 save_val[len] = '.';
6962 (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
6965 * len = length of entire line, including itself. len will be
6966 * two digits. So, add the string lengths plus the length of len,
6967 * plus a blank, an equal sign, and a newline.
6969 len = strlen(save_val) + strlen(keyword) + 5;
6970 if (xrec_offset + len > xrec_size) {
6971 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
6972 fatal(gettext(
6973 "cannot allocate extended header buffer"));
6974 xrec_ptr = curr_ptr;
6975 xrec_size *= 2;
6977 (void) sprintf(&xrec_ptr[xrec_offset],
6978 "%d %s=%s\n", len, keyword, save_val);
6979 xrec_offset += len;
6983 * gen_string creates a string from a keyword and a char * in the
6984 * format: %d %s=%s\n
6985 * This is part of the extended header data record.
6988 void
6989 gen_string(const char *keyword, const char *value)
6991 int len;
6992 char *curr_ptr;
6995 * len = length of entire line, including itself. The character length
6996 * of len must be 1-4 characters, because the maximum size of the path
6997 * or the name is PATH_MAX, which is 1024. So, assume 1 character
6998 * for len, one for the space, one for the "=", and one for the newline.
6999 * Then adjust as needed.
7001 /* LINTED constant expression */
7002 assert(PATH_MAX <= 9996);
7003 len = strlen(value) + strlen(keyword) + 4;
7004 if (len > 997)
7005 len += 3;
7006 else if (len > 98)
7007 len += 2;
7008 else if (len > 9)
7009 len += 1;
7010 if (xrec_offset + len > xrec_size) {
7011 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7012 fatal(gettext(
7013 "cannot allocate extended header buffer"));
7014 xrec_ptr = curr_ptr;
7015 xrec_size *= 2;
7017 #ifdef XHDR_DEBUG
7018 if (strcmp(keyword+1, "name") != 0)
7019 #endif
7020 (void) sprintf(&xrec_ptr[xrec_offset],
7021 "%d %s=%s\n", len, keyword, value);
7022 #ifdef XHDR_DEBUG
7023 else {
7024 len += 11;
7025 (void) sprintf(&xrec_ptr[xrec_offset],
7026 "%d %s=%snametoolong\n", len, keyword, value);
7028 #endif
7029 xrec_offset += len;
7033 * Convert time found in the extended header data to seconds and nanoseconds.
7036 void
7037 get_xtime(char *value, timestruc_t *xtime)
7039 char nanosec[10];
7040 char *period;
7041 int i;
7043 (void) memset(nanosec, '0', 9);
7044 nanosec[9] = '\0';
7046 period = strchr(value, '.');
7047 if (period != NULL)
7048 period[0] = '\0';
7049 xtime->tv_sec = strtol(value, NULL, 10);
7050 if (period == NULL)
7051 xtime->tv_nsec = 0;
7052 else {
7053 i = strlen(period +1);
7054 (void) strncpy(nanosec, period + 1, min(i, 9));
7055 xtime->tv_nsec = strtol(nanosec, NULL, 10);
7060 * Check linkpath for length.
7061 * Emit an error message and return 1 if too long.
7065 chk_path_build(
7066 char *name,
7067 char *longname,
7068 char *linkname,
7069 char *prefix,
7070 char type,
7071 int filetype)
7074 if (strlen(linkname) > (size_t)NAMSIZ) {
7075 if (Eflag > 0) {
7076 xhdr_flgs |= _X_LINKPATH;
7077 Xtarhdr.x_linkpath = linkname;
7078 } else {
7079 (void) fprintf(stderr, gettext(
7080 "tar: %s: linked to %s\n"), longname, linkname);
7081 (void) fprintf(stderr, gettext(
7082 "tar: %s: linked name too long\n"), linkname);
7083 if (errflag)
7084 done(1);
7085 else
7086 Errflg = 1;
7087 return (1);
7090 if (xhdr_flgs & _X_LINKPATH)
7091 return (build_dblock(name, tchar, type,
7092 filetype, &stbuf, stbuf.st_dev,
7093 prefix));
7094 else
7095 return (build_dblock(name, linkname, type,
7096 filetype, &stbuf, stbuf.st_dev, prefix));
7100 * Convert from UTF-8 to local character set.
7103 static int
7104 utf8_local(
7105 char *option,
7106 char **Xhdr_ptrptr,
7107 char *target,
7108 const char *source,
7109 int max_val)
7111 static iconv_t iconv_cd;
7112 char *nl_target;
7113 const char *iconv_src;
7114 char *iconv_trg;
7115 size_t inlen;
7116 size_t outlen;
7118 if (charset_type == -1) { /* iconv_open failed in earlier try */
7119 (void) fprintf(stderr, gettext(
7120 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7121 xhdr_count, source);
7122 return (1);
7123 } else if (charset_type == 0) { /* iconv_open has not yet been done */
7124 nl_target = nl_langinfo(CODESET);
7125 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7126 nl_target = "US-ASCII";
7127 if (strcmp(nl_target, "US-ASCII") == 0)
7128 charset_type = 1;
7129 else if (strcmp(nl_target, "UTF-8") == 0)
7130 charset_type = 3;
7131 else {
7132 if (strncmp(nl_target, "ISO", 3) == 0)
7133 nl_target += 3;
7134 charset_type = 2;
7135 errno = 0;
7136 if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
7137 (iconv_t)-1) {
7138 if (errno == EINVAL)
7139 (void) fprintf(stderr, gettext(
7140 "tar: conversion routines not "
7141 "available for current locale. "));
7142 (void) fprintf(stderr, gettext(
7143 "file # %llu: (%s) UTF-8 conversion"
7144 " failed.\n"), xhdr_count, source);
7145 charset_type = -1;
7146 return (1);
7151 /* locale using 7-bit codeset or UTF-8 locale */
7152 if (charset_type == 1 || charset_type == 3) {
7153 if (strlen(source) > max_val) {
7154 (void) fprintf(stderr, gettext(
7155 "tar: file # %llu: Extended header %s too long.\n"),
7156 xhdr_count, option);
7157 return (1);
7159 if (charset_type == 3)
7160 (void) strcpy(target, source);
7161 else if (c_utf8(target, source) != 0) {
7162 (void) fprintf(stderr, gettext(
7163 "tar: file # %llu: (%s) UTF-8 conversion"
7164 " failed.\n"), xhdr_count, source);
7165 return (1);
7167 *Xhdr_ptrptr = target;
7168 return (0);
7171 iconv_src = source;
7172 iconv_trg = target;
7173 inlen = strlen(source);
7174 outlen = max_val * UTF_8_FACTOR;
7175 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7176 (size_t)-1) { /* Error occurred: didn't convert */
7177 (void) fprintf(stderr, gettext(
7178 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7179 xhdr_count, source);
7180 /* Get remaining output; reinitialize conversion descriptor */
7181 iconv_src = (const char *)NULL;
7182 inlen = 0;
7183 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7184 return (1);
7186 /* Get remaining output; reinitialize conversion descriptor */
7187 iconv_src = (const char *)NULL;
7188 inlen = 0;
7189 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7190 (size_t)-1) { /* Error occurred: didn't convert */
7191 (void) fprintf(stderr, gettext(
7192 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7193 xhdr_count, source);
7194 return (1);
7197 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7198 if (strlen(target) > max_val) {
7199 (void) fprintf(stderr, gettext(
7200 "tar: file # %llu: Extended header %s too long.\n"),
7201 xhdr_count, option);
7202 return (1);
7204 *Xhdr_ptrptr = target;
7205 return (0);
7209 * Check gname, uname, path, and linkpath to see if they need to go in an
7210 * extended header. If they are already slated to be in an extended header,
7211 * or if they are not ascii, then they need to be in the extended header.
7212 * Then, convert all extended names to UTF-8.
7216 gen_utf8_names(const char *filename)
7218 static iconv_t iconv_cd;
7219 char *nl_target;
7220 char tempbuf[MAXNAM + 1];
7221 int nbytes;
7222 int errors;
7224 if (charset_type == -1) { /* Previous failure to open. */
7225 (void) fprintf(stderr, gettext(
7226 "tar: file # %llu: UTF-8 conversion failed.\n"),
7227 xhdr_count);
7228 return (1);
7231 if (charset_type == 0) { /* Need to get conversion descriptor */
7232 nl_target = nl_langinfo(CODESET);
7233 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7234 nl_target = "US-ASCII";
7235 if (strcmp(nl_target, "US-ASCII") == 0)
7236 charset_type = 1;
7237 else if (strcmp(nl_target, "UTF-8") == 0)
7238 charset_type = 3;
7239 else {
7240 if (strncmp(nl_target, "ISO", 3) == 0)
7241 nl_target += 3;
7242 charset_type = 2;
7243 errno = 0;
7244 #ifdef ICONV_DEBUG
7245 (void) fprintf(stderr,
7246 gettext("Opening iconv_cd with target %s\n"),
7247 nl_target);
7248 #endif
7249 if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
7250 (iconv_t)-1) {
7251 if (errno == EINVAL)
7252 (void) fprintf(stderr, gettext(
7253 "tar: conversion routines not "
7254 "available for current locale. "));
7255 (void) fprintf(stderr, gettext(
7256 "file (%s): UTF-8 conversion failed.\n"),
7257 filename);
7258 charset_type = -1;
7259 return (1);
7264 errors = 0;
7266 errors += local_utf8(&Xtarhdr.x_gname, local_gname,
7267 dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
7268 errors += local_utf8(&Xtarhdr.x_uname, local_uname,
7269 dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX);
7270 if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */
7271 (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
7272 tempbuf[NAMSIZ] = '\0';
7274 errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
7275 tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
7276 if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */
7277 (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
7278 tempbuf[PRESIZ] = '\0';
7279 nbytes = strlen(tempbuf);
7280 if (nbytes > 0) {
7281 tempbuf[nbytes++] = '/';
7282 tempbuf[nbytes] = '\0';
7284 (void) strncat(tempbuf + nbytes, dblock.dbuf.name,
7285 (MAXNAM - nbytes));
7286 tempbuf[MAXNAM] = '\0';
7288 errors += local_utf8(&Xtarhdr.x_path, local_path,
7289 tempbuf, iconv_cd, _X_PATH, PATH_MAX);
7291 if (errors > 0)
7292 (void) fprintf(stderr, gettext(
7293 "tar: file (%s): UTF-8 conversion failed.\n"), filename);
7295 if (errors && errflag)
7296 done(1);
7297 else
7298 if (errors)
7299 Errflg = 1;
7300 return (errors);
7303 static int
7304 local_utf8(
7305 char **Xhdr_ptrptr,
7306 char *target,
7307 const char *source,
7308 iconv_t iconv_cd,
7309 int xhdrflg,
7310 int max_val)
7312 const char *iconv_src;
7313 const char *starting_src;
7314 char *iconv_trg;
7315 size_t inlen;
7316 size_t outlen;
7317 #ifdef ICONV_DEBUG
7318 unsigned char c_to_hex;
7319 #endif
7322 * If the item is already slated for extended format, get the string
7323 * to convert from the extended header record. Otherwise, get it from
7324 * the regular (dblock) area.
7326 if (xhdr_flgs & xhdrflg) {
7327 if (charset_type == 3) { /* Already UTF-8, just copy */
7328 (void) strcpy(target, *Xhdr_ptrptr);
7329 *Xhdr_ptrptr = target;
7330 return (0);
7331 } else
7332 iconv_src = (const char *) *Xhdr_ptrptr;
7333 } else {
7334 if (charset_type == 3) /* Already in UTF-8 format */
7335 return (0); /* Don't create xhdr record */
7336 iconv_src = source;
7338 starting_src = iconv_src;
7339 iconv_trg = target;
7340 if ((inlen = strlen(iconv_src)) == 0)
7341 return (0);
7343 if (charset_type == 1) { /* locale using 7-bit codeset */
7344 if (c_utf8(target, starting_src) != 0) {
7345 (void) fprintf(stderr,
7346 gettext("tar: invalid character in"
7347 " UTF-8 conversion of '%s'\n"), starting_src);
7348 return (1);
7350 return (0);
7353 outlen = max_val * UTF_8_FACTOR;
7354 errno = 0;
7355 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7356 (size_t)-1) {
7357 /* An error occurred, or not all characters were converted */
7358 if (errno == EILSEQ)
7359 (void) fprintf(stderr,
7360 gettext("tar: invalid character in"
7361 " UTF-8 conversion of '%s'\n"), starting_src);
7362 else
7363 (void) fprintf(stderr, gettext(
7364 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7365 starting_src);
7366 /* Get remaining output; reinitialize conversion descriptor */
7367 iconv_src = (const char *)NULL;
7368 inlen = 0;
7369 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7370 return (1);
7372 /* Get remaining output; reinitialize conversion descriptor */
7373 iconv_src = (const char *)NULL;
7374 inlen = 0;
7375 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7376 (size_t)-1) { /* Error occurred: didn't convert */
7377 if (errno == EILSEQ)
7378 (void) fprintf(stderr,
7379 gettext("tar: invalid character in"
7380 " UTF-8 conversion of '%s'\n"), starting_src);
7381 else
7382 (void) fprintf(stderr, gettext(
7383 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7384 starting_src);
7385 return (1);
7388 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7389 if (strcmp(starting_src, target) != 0) {
7390 *Xhdr_ptrptr = target;
7391 xhdr_flgs |= xhdrflg;
7392 #ifdef ICONV_DEBUG
7393 (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n",
7394 strlen(starting_src), inlen, max_val, outlen);
7395 (void) fprintf(stderr, "Input string:\n ");
7396 for (inlen = 0; inlen < strlen(starting_src); inlen++) {
7397 c_to_hex = (unsigned char)starting_src[inlen];
7398 (void) fprintf(stderr, " %2.2x", c_to_hex);
7399 if (inlen % 20 == 19)
7400 (void) fprintf(stderr, "\n ");
7402 (void) fprintf(stderr, "\nOutput string:\n ");
7403 for (inlen = 0; inlen < strlen(target); inlen++) {
7404 c_to_hex = (unsigned char)target[inlen];
7405 (void) fprintf(stderr, " %2.2x", c_to_hex);
7406 if (inlen % 20 == 19)
7407 (void) fprintf(stderr, "\n ");
7409 (void) fprintf(stderr, "\n");
7410 #endif
7413 return (0);
7417 * Function to test each byte of the source string to make sure it is
7418 * in within bounds (value between 0 and 127).
7419 * If valid, copy source to target.
7423 c_utf8(char *target, const char *source)
7425 size_t len;
7426 const char *thischar;
7428 len = strlen(source);
7429 thischar = source;
7430 while (len-- > 0) {
7431 if (!isascii((int)(*thischar++)))
7432 return (1);
7435 (void) strcpy(target, source);
7436 return (0);
7440 #if defined(O_XATTR)
7441 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
7443 static void
7444 prepare_xattr(
7445 char **attrbuf,
7446 char *filename,
7447 char *attrpath,
7448 char typeflag,
7449 struct linkbuf *linkinfo,
7450 int *rlen)
7452 char *bufhead; /* ptr to full buffer */
7453 char *aptr;
7454 struct xattr_hdr *hptr; /* ptr to header in bufhead */
7455 struct xattr_buf *tptr; /* ptr to pathing pieces */
7456 int totalen; /* total buffer length */
7457 int len; /* length returned to user */
7458 int stringlen; /* length of filename + attr */
7460 * length of filename + attr
7461 * in link section
7463 int linkstringlen;
7464 int complen; /* length of pathing section */
7465 int linklen; /* length of link section */
7466 int attrnames_index; /* attrnames starting index */
7469 * Release previous buffer
7472 if (*attrbuf != (char *)NULL) {
7473 free(*attrbuf);
7474 *attrbuf = NULL;
7478 * First add in fixed size stuff
7480 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7483 * Add space for two nulls
7485 stringlen = strlen(attrpath) + strlen(filename) + 2;
7486 complen = stringlen + sizeof (struct xattr_buf);
7488 len += stringlen;
7491 * Now add on space for link info if any
7494 if (linkinfo != NULL) {
7496 * Again add space for two nulls
7498 linkstringlen = strlen(linkinfo->pathname) +
7499 strlen(linkinfo->attrname) + 2;
7500 linklen = linkstringlen + sizeof (struct xattr_buf);
7501 len += linklen;
7502 } else {
7503 linklen = 0;
7507 * Now add padding to end to fill out TBLOCK
7509 * Function returns size of real data and not size + padding.
7512 totalen = ROUNDTOTBLOCK(len);
7514 if ((bufhead = calloc(1, totalen)) == NULL) {
7515 fatal(gettext("Out of memory."));
7520 * Now we can fill in the necessary pieces
7524 * first fill in the fixed header
7526 hptr = (struct xattr_hdr *)bufhead;
7527 (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7528 (void) sprintf(hptr->h_component_len, "%0*d",
7529 sizeof (hptr->h_component_len) - 1, complen);
7530 (void) sprintf(hptr->h_link_component_len, "%0*d",
7531 sizeof (hptr->h_link_component_len) - 1, linklen);
7532 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7535 * Now fill in the filename + attrnames section
7536 * The filename and attrnames section can be composed of two or more
7537 * path segments separated by a null character. The first segment
7538 * is the path to the parent file that roots the entire sequence in
7539 * the normal name space. The remaining segments describes a path
7540 * rooted at the hidden extended attribute directory of the leaf file of
7541 * the previous segment, making it possible to name attributes on
7542 * attributes. Thus, if we are just archiving an extended attribute,
7543 * the second segment will contain the attribute name. If we are
7544 * archiving a system attribute of an extended attribute, then the
7545 * second segment will contain the attribute name, and a third segment
7546 * will contain the system attribute name. The attribute pathing
7547 * information is obtained from 'attrpath'.
7550 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7551 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7552 stringlen);
7553 (void) strcpy(tptr->h_names, filename);
7554 attrnames_index = strlen(filename) + 1;
7555 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
7556 tptr->h_typeflag = typeflag;
7559 * Split the attrnames section into two segments if 'attrpath'
7560 * contains pathing information for a system attribute of an
7561 * extended attribute. We split them by replacing the '/' with
7562 * a '\0'.
7564 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
7565 *aptr = '\0';
7569 * Now fill in the optional link section if we have one
7572 if (linkinfo != (struct linkbuf *)NULL) {
7573 tptr = (struct xattr_buf *)(bufhead +
7574 sizeof (struct xattr_hdr) + complen);
7576 (void) sprintf(tptr->h_namesz, "%0*d",
7577 sizeof (tptr->h_namesz) - 1, linkstringlen);
7578 (void) strcpy(tptr->h_names, linkinfo->pathname);
7579 (void) strcpy(
7580 &tptr->h_names[strlen(linkinfo->pathname) + 1],
7581 linkinfo->attrname);
7582 tptr->h_typeflag = typeflag;
7584 *attrbuf = (char *)bufhead;
7585 *rlen = len;
7588 #else
7589 static void
7590 prepare_xattr(
7591 char **attrbuf,
7592 char *filename,
7593 char *attrname,
7594 char typeflag,
7595 struct linkbuf *linkinfo,
7596 int *rlen)
7598 *attrbuf = NULL;
7599 *rlen = 0;
7601 #endif
7604 getstat(int dirfd, char *longname, char *shortname, char *attrparent)
7607 int i, j;
7608 int printerr;
7609 int slnkerr;
7610 struct stat symlnbuf;
7612 if (!hflag)
7613 i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
7614 else
7615 i = fstatat(dirfd, shortname, &stbuf, 0);
7617 if (i < 0) {
7618 /* Initialize flag to print error mesg. */
7619 printerr = 1;
7621 * If stat is done, then need to do lstat
7622 * to determine whether it's a sym link
7624 if (hflag) {
7625 /* Save returned error */
7626 slnkerr = errno;
7628 j = fstatat(dirfd, shortname,
7629 &symlnbuf, AT_SYMLINK_NOFOLLOW);
7631 * Suppress error message when file is a symbolic link
7632 * and function modifier 'l' is off. Exception: when
7633 * a symlink points to a symlink points to a
7634 * symlink ... and we get past MAXSYMLINKS. That
7635 * error will cause a file not to be archived, and
7636 * needs to be printed.
7638 if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
7639 (S_ISLNK(symlnbuf.st_mode)))
7640 printerr = 0;
7643 * Restore errno in case the lstat
7644 * on symbolic link change
7646 errno = slnkerr;
7649 if (printerr) {
7650 (void) fprintf(stderr, gettext(
7651 "tar: %s%s%s%s: %s\n"),
7652 (attrparent == NULL) ? "" : gettext("attribute "),
7653 (attrparent == NULL) ? "" : attrparent,
7654 (attrparent == NULL) ? "" : gettext(" of "),
7655 longname, strerror(errno));
7656 Errflg = 1;
7658 return (1);
7660 return (0);
7664 * Recursively archive the extended attributes and/or extended system attributes
7665 * of the base file, longname. Note: extended system attribute files will be
7666 * archived only if the extended system attributes are not transient (i.e. the
7667 * extended system attributes are other than the default values).
7669 * If -@ was specified and the underlying file system supports it, archive the
7670 * extended attributes, and if there is a system attribute associated with the
7671 * extended attribute, then recursively call xattrs_put() to archive the
7672 * hidden attribute directory and the extended system attribute. If -/ was
7673 * specified and the underlying file system supports it, archive the extended
7674 * system attributes. Read-only extended system attributes are never archived.
7676 * Currently, there cannot be attributes on attributes; only system
7677 * attributes on attributes. In addition, there cannot be attributes on
7678 * system attributes. A file and it's attribute directory hierarchy looks as
7679 * follows:
7680 * longname ----> . ("." is the hidden attribute directory)
7682 * ----------------------------
7683 * | |
7684 * <sys_attr_name> <attr_name> ----> .
7686 * <sys_attr_name>
7689 #if defined(O_XATTR)
7690 static void
7691 xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
7693 char *filename = (attrparent == NULL) ? shortname : attrparent;
7694 int arc_rwsysattr = 0;
7695 int dirfd;
7696 int fd = -1;
7697 int rw_sysattr = 0;
7698 int ext_attr = 0;
7699 int rc;
7700 DIR *dirp;
7701 struct dirent *dp;
7702 attr_data_t *attrinfo = NULL;
7705 * If the underlying file system supports it, then archive the extended
7706 * attributes if -@ was specified, and the extended system attributes
7707 * if -/ was specified.
7709 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
7710 &ext_attr) != ATTR_OK) {
7711 return;
7715 * Only want to archive a read-write extended system attribute file
7716 * if it contains extended system attribute settings that are not the
7717 * default values.
7719 #if defined(_PC_SATTR_ENABLED)
7720 if (saflag) {
7721 int filefd;
7722 nvlist_t *slist = NULL;
7724 /* Determine if there are non-transient system attributes */
7725 errno = 0;
7726 if ((filefd = open(filename, O_RDONLY)) == -1) {
7727 if (attrparent == NULL) {
7728 vperror(0, gettext(
7729 "unable to open file %s"), longname);
7731 return;
7733 if (((slist = sysattr_list(basename(myname), filefd,
7734 filename)) != NULL) || (errno != 0)) {
7735 arc_rwsysattr = 1;
7737 if (slist != NULL) {
7738 (void) nvlist_free(slist);
7739 slist = NULL;
7741 (void) close(filefd);
7745 * If we aren't archiving extended system attributes, and we are
7746 * processing an attribute, or if we are archiving extended system
7747 * attributes, and there are are no extended attributes, then there's
7748 * no need to open up the attribute directory of the file unless the
7749 * extended system attributes are not transient (i.e, the system
7750 * attributes are not the default values).
7752 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
7753 (saflag && !ext_attr))) {
7754 return;
7756 #endif /* _PC_SATTR_ENABLED */
7758 /* open the parent attribute directory */
7759 fd = attropen(filename, ".", O_RDONLY);
7760 if (fd < 0) {
7761 vperror(0, gettext(
7762 "unable to open attribute directory for %s%s%sfile %s"),
7763 (attrparent == NULL) ? "" : gettext("attribute "),
7764 (attrparent == NULL) ? "" : attrparent,
7765 (attrparent == NULL) ? "" : gettext(" of "),
7766 longname);
7767 return;
7771 * We need to change into the parent's attribute directory to determine
7772 * if each of the attributes should be archived.
7774 if (fchdir(fd) < 0) {
7775 vperror(0, gettext(
7776 "cannot change to attribute directory of %s%s%sfile %s"),
7777 (attrparent == NULL) ? "" : gettext("attribute "),
7778 (attrparent == NULL) ? "" : attrparent,
7779 (attrparent == NULL) ? "" : gettext(" of "),
7780 longname);
7781 (void) close(fd);
7782 return;
7785 if (((dirfd = dup(fd)) == -1) ||
7786 ((dirp = fdopendir(dirfd)) == NULL)) {
7787 (void) fprintf(stderr, gettext(
7788 "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7789 (attrparent == NULL) ? "" : gettext("attribute "),
7790 (attrparent == NULL) ? "" : attrparent,
7791 (attrparent == NULL) ? "" : gettext(" of "),
7792 longname);
7793 if (fd > 0) {
7794 (void) close(fd);
7796 return;
7799 while ((dp = readdir(dirp)) != NULL) {
7800 if (strcmp(dp->d_name, "..") == 0) {
7801 continue;
7802 } else if (strcmp(dp->d_name, ".") == 0) {
7803 Hiddendir = 1;
7804 } else {
7805 Hiddendir = 0;
7808 /* Determine if this attribute should be archived */
7809 if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
7810 &rw_sysattr) != ATTR_OK) {
7811 continue;
7814 /* gather the attribute's information to pass to putfile() */
7815 if ((fill_in_attr_info(dp->d_name, longname, attrparent,
7816 fd, rw_sysattr, &attrinfo)) == 1) {
7817 continue;
7820 /* add the attribute to the archive */
7821 rc = putfile(longname, dp->d_name, parent, attrinfo,
7822 XATTR_FILE, LEV0, SYMLINK_LEV0);
7824 if (exitflag) {
7825 break;
7828 #if defined(_PC_SATTR_ENABLED)
7830 * If both -/ and -@ were specified, then archive the
7831 * attribute's extended system attributes and hidden directory
7832 * by making a recursive call to xattrs_put().
7834 if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
7835 (Hiddendir == 0)) {
7837 xattrs_put(longname, shortname, parent, dp->d_name);
7840 * Change back to the parent's attribute directory
7841 * to process any further attributes.
7843 if (fchdir(fd) < 0) {
7844 vperror(0, gettext(
7845 "cannot change back to attribute directory "
7846 "of file %s"), longname);
7847 break;
7850 #endif /* _PC_SATTR_ENABLED */
7853 if (attrinfo != NULL) {
7854 if (attrinfo->attr_parent != NULL) {
7855 free(attrinfo->attr_parent);
7857 free(attrinfo->attr_path);
7858 free(attrinfo);
7860 (void) closedir(dirp);
7861 if (fd != -1) {
7862 (void) close(fd);
7865 /* Change back to the parent directory of the base file */
7866 if (attrparent == NULL) {
7867 (void) tar_chdir(parent);
7869 Hiddendir = 0;
7871 #else
7872 static void
7873 xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
7876 #endif /* O_XATTR */
7878 static int
7879 put_link(char *name, char *longname, char *component, char *longattrname,
7880 char *prefix, int filetype, char type)
7883 if (stbuf.st_nlink > 1) {
7884 struct linkbuf *lp;
7885 int found = 0;
7887 for (lp = ihead; lp != NULL; lp = lp->nextp)
7888 if (lp->inum == stbuf.st_ino &&
7889 lp->devnum == stbuf.st_dev) {
7890 found++;
7891 break;
7893 if (found) {
7894 #if defined(O_XATTR)
7895 if (filetype == XATTR_FILE)
7896 if (put_xattr_hdr(longname, component,
7897 longattrname, prefix, type, filetype, lp)) {
7898 goto out;
7900 #endif
7901 stbuf.st_size = (off_t)0;
7902 if (filetype != XATTR_FILE) {
7903 tomodes(&stbuf);
7904 if (chk_path_build(name, longname, lp->pathname,
7905 prefix, type, filetype) > 0) {
7906 goto out;
7910 if (mulvol && tapepos + 1 >= blocklim)
7911 newvol();
7912 (void) writetbuf((char *)&dblock, 1);
7914 * write_ancillary() is not needed here.
7915 * The first link is handled in the following
7916 * else statement. No need to process ACLs
7917 * for other hard links since they are the
7918 * same file.
7921 if (vflag) {
7922 if (NotTape)
7923 dlog("seek = %" FMT_blkcnt_t
7924 "K\n", K(tapepos));
7925 if (filetype == XATTR_FILE) {
7926 (void) fprintf(vfile, gettext(
7927 "a %s attribute %s link to "
7928 "%s attribute %s\n"),
7929 name, component, name,
7930 lp->attrname);
7931 } else {
7932 (void) fprintf(vfile, gettext(
7933 "a %s link to %s\n"),
7934 longname, lp->pathname);
7937 lp->count--;
7938 return (0);
7939 } else {
7940 lp = (struct linkbuf *)getmem(sizeof (*lp));
7941 if (lp != (struct linkbuf *)NULL) {
7942 lp->nextp = ihead;
7943 ihead = lp;
7944 lp->inum = stbuf.st_ino;
7945 lp->devnum = stbuf.st_dev;
7946 lp->count = stbuf.st_nlink - 1;
7947 if (filetype == XATTR_FILE) {
7948 (void) strcpy(lp->pathname, longname);
7949 (void) strcpy(lp->attrname,
7950 component);
7951 } else {
7952 (void) strcpy(lp->pathname, longname);
7953 (void) strcpy(lp->attrname, "");
7959 out:
7960 return (1);
7963 static int
7964 put_extra_attributes(char *longname, char *shortname, char *longattrname,
7965 char *prefix, int filetype, char typeflag)
7967 static acl_t *aclp = NULL;
7968 int error;
7970 if (aclp != NULL) {
7971 acl_free(aclp);
7972 aclp = NULL;
7974 #if defined(O_XATTR)
7975 if ((atflag || saflag) && (filetype == XATTR_FILE)) {
7976 if (put_xattr_hdr(longname, shortname, longattrname, prefix,
7977 typeflag, filetype, NULL)) {
7978 return (1);
7981 #endif
7983 /* ACL support */
7984 if (pflag) {
7985 char *secinfo = NULL;
7986 int len = 0;
7988 /* ACL support */
7989 if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
7991 * Get ACL info: dont bother allocating space if
7992 * there is only a trivial ACL.
7994 if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
7995 &aclp)) != 0) {
7996 (void) fprintf(stderr, gettext(
7997 "%s: failed to retrieve acl : %s\n"),
7998 longname, acl_strerror(error));
7999 return (1);
8003 /* append security attributes if any */
8004 if (aclp != NULL) {
8005 (void) append_secattr(&secinfo, &len, acl_cnt(aclp),
8006 acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8007 ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
8008 UFSD_ACL : ACE_ACL);
8011 if (aclp != NULL) {
8012 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8015 return (0);
8018 #if defined(O_XATTR)
8019 static int
8020 put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
8021 int typeflag, int filetype, struct linkbuf *lp)
8023 char *lname = NULL;
8024 char *sname = NULL;
8025 int error = 0;
8026 static char *attrbuf = NULL;
8027 int attrlen;
8029 lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
8030 strlen(shortname) + strlen(".hdr") + 1);
8032 if (lname == NULL) {
8033 fatal(gettext("Out of Memory."));
8035 sname = malloc(sizeof (char) * strlen(shortname) +
8036 strlen(".hdr") + 1);
8037 if (sname == NULL) {
8038 fatal(gettext("Out of Memory."));
8041 (void) sprintf(sname, "%s.hdr", shortname);
8042 (void) sprintf(lname, "/dev/null/%s", sname);
8044 if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
8045 sizeof (dblock.dbuf.name)) {
8046 fatal(gettext(
8047 "Buffer overflow writing extended attribute file name"));
8051 * dump extended attr lookup info
8053 prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
8054 write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
8056 (void) sprintf(lname, "/dev/null/%s", shortname);
8057 (void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
8060 * Set up filename for attribute
8063 error = build_dblock(lname, tchar, '0', filetype,
8064 &stbuf, stbuf.st_dev, prefix);
8065 free(lname);
8066 free(sname);
8068 return (error);
8070 #endif
8072 #if defined(O_XATTR)
8073 static int
8074 read_xattr_hdr(attr_data_t **attrinfo)
8076 char buf[TBLOCK];
8077 char *attrparent = NULL;
8078 blkcnt_t blocks;
8079 char *tp;
8080 off_t bytes;
8081 int comp_len, link_len;
8082 int namelen;
8083 int attrparentlen;
8084 int parentfilelen;
8086 if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
8087 return (1);
8089 bytes = stbuf.st_size;
8090 if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
8091 (void) fprintf(stderr, gettext(
8092 "Insufficient memory for extended attribute\n"));
8093 return (1);
8096 tp = (char *)xattrhead;
8097 blocks = TBLOCKS(bytes);
8098 while (blocks-- > 0) {
8099 readtape(buf);
8100 if (bytes <= TBLOCK) {
8101 (void) memcpy(tp, buf, (size_t)bytes);
8102 break;
8103 } else {
8104 (void) memcpy(tp, buf, TBLOCK);
8105 tp += TBLOCK;
8107 bytes -= TBLOCK;
8111 * Validate that we can handle header format
8113 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8114 (void) fprintf(stderr,
8115 gettext("Unknown extended attribute format encountered\n"));
8116 (void) fprintf(stderr,
8117 gettext("Disabling extended attribute parsing\n"));
8118 xattrbadhead = 1;
8119 return (0);
8121 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8122 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8123 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8124 sizeof (struct xattr_hdr));
8125 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8126 if (link_len > 0)
8127 xattr_linkp = (struct xattr_buf *)
8128 ((int)xattrp + (int)comp_len);
8129 else
8130 xattr_linkp = NULL;
8133 * Gather the attribute path from the filename and attrnames section.
8134 * The filename and attrnames section can be composed of two or more
8135 * path segments separated by a null character. The first segment
8136 * is the path to the parent file that roots the entire sequence in
8137 * the normal name space. The remaining segments describes a path
8138 * rooted at the hidden extended attribute directory of the leaf file of
8139 * the previous segment, making it possible to name attributes on
8140 * attributes.
8142 parentfilelen = strlen(xattrp->h_names);
8143 xattrapath = xattrp->h_names + parentfilelen + 1;
8144 if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
8146 * The attrnames section contains a system attribute on an
8147 * attribute. Save the name of the attribute for use later,
8148 * and replace the null separating the attribute name from
8149 * the system attribute name with a '/' so that xattrapath can
8150 * be used to display messages with the full attribute path name
8151 * rooted at the hidden attribute directory of the base file
8152 * in normal name space.
8154 attrparent = strdup(xattrapath);
8155 attrparentlen = strlen(attrparent);
8156 xattrapath[attrparentlen] = '/';
8158 if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
8159 xattrapath + attrparentlen + 1, xattrapath, attrparent,
8160 -1, 0, attrinfo)) == 1) {
8161 free(attrparent);
8162 return (1);
8165 /* Gather link info */
8166 if (xattr_linkp) {
8167 xattr_linkaname = xattr_linkp->h_names +
8168 strlen(xattr_linkp->h_names) + 1;
8169 } else {
8170 xattr_linkaname = NULL;
8173 return (0);
8175 #else
8176 static int
8177 read_xattr_hdr(attr_data_t **attrinfo)
8179 return (0);
8181 #endif
8184 * skip over extra slashes in string.
8186 * For example:
8187 * /usr/tmp/////
8189 * would return pointer at
8190 * /usr/tmp/////
8193 static char *
8194 skipslashes(char *string, char *start)
8196 while ((string > start) && *(string - 1) == '/') {
8197 string--;
8200 return (string);
8204 * Return the parent directory of a given path.
8206 * Examples:
8207 * /usr/tmp return /usr
8208 * /usr/tmp/file return /usr/tmp
8209 * / returns .
8210 * /usr returns /
8211 * file returns .
8213 * dir is assumed to be at least as big as path.
8215 static void
8216 get_parent(char *path, char *dir)
8218 char *s;
8219 char tmpdir[PATH_MAX + 1];
8221 if (strlen(path) > PATH_MAX) {
8222 fatal(gettext("pathname is too long"));
8224 (void) strcpy(tmpdir, path);
8225 chop_endslashes(tmpdir);
8227 if ((s = strrchr(tmpdir, '/')) == NULL) {
8228 (void) strcpy(dir, ".");
8229 } else {
8230 s = skipslashes(s, tmpdir);
8231 *s = '\0';
8232 if (s == tmpdir)
8233 (void) strcpy(dir, "/");
8234 else
8235 (void) strcpy(dir, tmpdir);
8239 #if defined(O_XATTR)
8240 static char *
8241 get_component(char *path)
8243 char *ptr;
8245 ptr = strrchr(path, '/');
8246 if (ptr == NULL) {
8247 return (path);
8248 } else {
8250 * Handle trailing slash
8252 if (*(ptr + 1) == '\0')
8253 return (ptr);
8254 else
8255 return (ptr + 1);
8258 #else
8259 static char *
8260 get_component(char *path)
8262 return (path);
8264 #endif
8266 #if defined(O_XATTR)
8267 static int
8268 retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
8269 int oflag, mode_t mode)
8271 int dirfd;
8272 int ofilefd = -1;
8273 struct timeval times[2];
8274 mode_t newmode;
8275 struct stat parentstat;
8276 acl_t *aclp = NULL;
8277 int error;
8280 * We couldn't get to attrdir. See if its
8281 * just a mode problem on the parent file.
8282 * for example: a mode such as r-xr--r--
8283 * on a ufs file system without extended
8284 * system attribute support won't let us
8285 * create an attribute dir if it doesn't
8286 * already exist, and on a ufs file system
8287 * with extended system attribute support
8288 * won't let us open the attribute for
8289 * write.
8291 * If file has a non-trivial ACL, then save it
8292 * off so that we can place it back on after doing
8293 * chmod's.
8295 if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
8296 O_RDONLY)) == -1) {
8297 return (-1);
8299 if (fstat(dirfd, &parentstat) == -1) {
8300 (void) fprintf(stderr, gettext(
8301 "tar: cannot stat %sfile %s: %s\n"),
8302 (pdirfd == -1) ? "" : gettext("parent of "),
8303 (pdirfd == -1) ? dirp : name, strerror(errno));
8304 return (-1);
8306 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
8307 (void) fprintf(stderr, gettext(
8308 "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8309 (pdirfd == -1) ? "" : gettext("parent of "),
8310 (pdirfd == -1) ? dirp : name, strerror(errno));
8311 return (-1);
8314 newmode = S_IWUSR | parentstat.st_mode;
8315 if (fchmod(dirfd, newmode) == -1) {
8316 (void) fprintf(stderr,
8317 gettext(
8318 "tar: cannot fchmod %sfile %s to %o: %s\n"),
8319 (pdirfd == -1) ? "" : gettext("parent of "),
8320 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8321 if (aclp)
8322 acl_free(aclp);
8323 return (-1);
8327 if (pdirfd == -1) {
8329 * We weren't able to create the attribute directory before.
8330 * Now try again.
8332 ofilefd = attropen(dirp, ".", oflag);
8333 } else {
8335 * We weren't able to create open the attribute before.
8336 * Now try again.
8338 ofilefd = openat(pdirfd, name, oflag, mode);
8342 * Put mode back to original
8344 if (fchmod(dirfd, parentstat.st_mode) == -1) {
8345 (void) fprintf(stderr,
8346 gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8347 (pdirfd == -1) ? "" : gettext("parent of "),
8348 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8351 if (aclp) {
8352 error = facl_set(dirfd, aclp);
8353 if (error) {
8354 (void) fprintf(stderr,
8355 gettext("tar: failed to set acl entries on "
8356 "%sfile %s\n"),
8357 (pdirfd == -1) ? "" : gettext("parent of "),
8358 (pdirfd == -1) ? dirp : name);
8360 acl_free(aclp);
8364 * Put back time stamps
8367 times[0].tv_sec = parentstat.st_atime;
8368 times[0].tv_usec = 0;
8369 times[1].tv_sec = parentstat.st_mtime;
8370 times[1].tv_usec = 0;
8372 (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
8374 (void) close(dirfd);
8376 return (ofilefd);
8378 #endif
8380 #if !defined(O_XATTR)
8381 static int
8382 openat64(int fd, const char *name, int oflag, mode_t cmode)
8384 return (open64(name, oflag, cmode));
8387 static int
8388 openat(int fd, const char *name, int oflag, mode_t cmode)
8390 return (open(name, oflag, cmode));
8393 static int
8394 fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
8396 if (flag == AT_SYMLINK_NOFOLLOW)
8397 return (lchown(name, owner, group));
8398 else
8399 return (chown(name, owner, group));
8402 static int
8403 renameat(int fromfd, char *old, int tofd, char *new)
8405 return (rename(old, new));
8408 static int
8409 futimesat(int fd, char *path, struct timeval times[2])
8411 return (utimes(path, times));
8414 static int
8415 unlinkat(int dirfd, char *path, int flag)
8417 if (flag == AT_REMOVEDIR)
8418 return (rmdir(path));
8419 else
8420 return (unlink(path));
8423 static int
8424 fstatat(int fd, char *path, struct stat *buf, int flag)
8426 if (flag == AT_SYMLINK_NOFOLLOW)
8427 return (lstat(path, buf));
8428 else
8429 return (stat(path, buf));
8432 static int
8433 attropen(char *file, char *attr, int omode, mode_t cmode)
8435 errno = ENOTSUP;
8436 return (-1);
8438 #endif
8440 static void
8441 chop_endslashes(char *path)
8443 char *end, *ptr;
8446 * Chop of slashes, but not if all we have is slashes
8447 * for example: ////
8448 * should make no changes, otherwise it will screw up
8449 * checkdir
8451 end = &path[strlen(path) -1];
8452 if (*end == '/' && end != path) {
8453 ptr = skipslashes(end, path);
8454 if (ptr != NULL && ptr != path) {
8455 *ptr = '\0';
8460 /* Compressing a tar file using compression method provided in 'opt' */
8462 static void
8463 compress_back()
8465 pid_t pid;
8467 if (vflag) {
8468 (void) fprintf(vfile,
8469 gettext("Compressing '%s' with '%s'...\n"),
8470 usefile, compress_opt);
8472 if ((pid = fork()) == 0) {
8473 verify_compress_opt(compress_opt);
8474 (void) execlp(compress_opt, compress_opt,
8475 usefile, NULL);
8476 } else if (pid == -1) {
8477 vperror(1, "%s", gettext("Could not fork"));
8479 wait_pid(pid);
8480 if (suffix == 0) {
8481 (void) rename(tfname, usefile);
8485 /* The magic numbers from /etc/magic */
8487 #define GZIP_MAGIC "\037\213"
8488 #define BZIP_MAGIC "BZh"
8489 #define COMP_MAGIC "\037\235"
8490 #define XZ_MAGIC "\375\067\172\130\132\000"
8492 void
8493 check_compression(void)
8495 char magic[16];
8496 FILE *fp;
8498 if ((fp = fopen(usefile, "r")) != NULL) {
8499 (void) fread(magic, sizeof (char), 6, fp);
8500 (void) fclose(fp);
8503 if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
8504 if (xflag || tflag) {
8505 compress_opt = compress_malloc(strlen(GZCAT) + 1);
8506 (void) strcpy(compress_opt, GZCAT);
8507 } else if (uflag || rflag) {
8508 compress_opt = compress_malloc(strlen(GZIP) + 1);
8509 (void) strcpy(compress_opt, GZIP);
8511 } else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
8512 if (xflag || tflag) {
8513 compress_opt = compress_malloc(strlen(BZCAT) + 1);
8514 (void) strcpy(compress_opt, BZCAT);
8515 } else if (uflag || rflag) {
8516 compress_opt = compress_malloc(strlen(BZIP) + 1);
8517 (void) strcpy(compress_opt, BZIP);
8519 } else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
8520 if (xflag || tflag) {
8521 compress_opt = compress_malloc(strlen(ZCAT) + 1);
8522 (void) strcpy(compress_opt, ZCAT);
8523 } else if (uflag || rflag) {
8524 compress_opt = compress_malloc(strlen(COMPRESS) + 1);
8525 (void) strcpy(compress_opt, COMPRESS);
8527 } else if (memcmp(magic, XZ_MAGIC, 6) == 0) {
8528 if (xflag || tflag) {
8529 compress_opt = compress_malloc(strlen(XZCAT) + 1);
8530 (void) strcpy(compress_opt, XZCAT);
8531 } else if (uflag || rflag) {
8532 compress_opt = compress_malloc(strlen(XZ) + 1);
8533 (void) strcpy(compress_opt, XZ);
8538 char *
8539 add_suffix()
8541 (void) strcpy(tfname, usefile);
8542 if (strcmp(compress_opt, GZIP) == 0) {
8543 if ((suffix = gz_suffix()) == NULL) {
8544 strlcat(tfname, gsuffix[0], sizeof (tfname));
8545 return (gsuffix[0]);
8547 } else if (strcmp(compress_opt, COMPRESS) == 0) {
8548 if ((suffix = gz_suffix()) == NULL) {
8549 strlcat(tfname, gsuffix[6], sizeof (tfname));
8550 return (gsuffix[6]);
8552 } else if (strcmp(compress_opt, BZIP) == 0) {
8553 if ((suffix = bz_suffix()) == NULL) {
8554 strlcat(tfname, bsuffix[0], sizeof (tfname));
8555 return (bsuffix[0]);
8557 } else if (strcmp(compress_opt, XZ) == 0) {
8558 if ((suffix = xz_suffix()) == NULL) {
8559 strlcat(tfname, xsuffix[0], sizeof (tfname));
8560 return (xsuffix[0]);
8563 return (NULL);
8566 /* Decompressing a tar file using compression method from the file type */
8567 void
8568 decompress_file(void)
8570 pid_t pid;
8571 char *added_suffix;
8574 added_suffix = add_suffix();
8575 if (added_suffix != NULL) {
8576 (void) rename(usefile, tfname);
8578 if ((pid = fork()) == 0) {
8579 if (vflag) {
8580 (void) fprintf(vfile,
8581 gettext("Decompressing '%s' with "
8582 "'%s'...\n"), usefile, compress_opt);
8584 verify_compress_opt(compress_opt);
8585 (void) execlp(compress_opt, compress_opt, "-df",
8586 tfname, NULL);
8587 vperror(1, gettext("Could not exec %s"), compress_opt);
8588 } else if (pid == -1) {
8589 vperror(1, gettext("Could not fork"));
8591 wait_pid(pid);
8592 if (suffix != NULL) {
8593 /* restore the file name - original file was without suffix */
8594 *(usefile + strlen(usefile) - strlen(suffix)) = '\0';
8598 /* Set the archive for writing and then compress the archive */
8599 pid_t
8600 compress_file(void)
8602 int fd[2];
8603 pid_t pid;
8605 if (vflag) {
8606 (void) fprintf(vfile, gettext("Compressing '%s' with "
8607 "'%s'...\n"), usefile, compress_opt);
8610 if (pipe(fd) < 0) {
8611 vperror(1, gettext("Could not create pipe"));
8613 if ((pid = fork()) > 0) {
8614 mt = fd[1];
8615 (void) close(fd[0]);
8616 return (pid);
8618 /* child */
8619 (void) dup2(fd[0], STDIN_FILENO);
8620 (void) close(fd[1]);
8621 (void) dup2(mt, STDOUT_FILENO);
8622 verify_compress_opt(compress_opt);
8623 (void) execlp(compress_opt, compress_opt, NULL);
8624 vperror(1, gettext("Could not exec %s"), compress_opt);
8625 return (0); /*NOTREACHED*/
8628 pid_t
8629 uncompress_file(void)
8631 int fd[2];
8632 pid_t pid;
8634 if (vflag) {
8635 (void) fprintf(vfile, gettext("Decompressing '%s' with "
8636 "'%s'...\n"), usefile, compress_opt);
8639 if (pipe(fd) < 0) {
8640 vperror(1, gettext("Could not create pipe"));
8642 if ((pid = fork()) > 0) {
8643 mt = fd[0];
8644 (void) close(fd[1]);
8645 return (pid);
8647 /* child */
8648 (void) dup2(fd[1], STDOUT_FILENO);
8649 (void) close(fd[0]);
8650 (void) dup2(mt, STDIN_FILENO);
8651 verify_compress_opt(compress_opt);
8652 (void) execlp(compress_opt, compress_opt, NULL);
8653 vperror(1, gettext("Could not exec %s"), compress_opt);
8654 return (0); /*NOTREACHED*/
8657 /* Checking suffix validity */
8658 char *
8659 check_suffix(char **suf, int size)
8661 int i;
8662 int slen;
8663 int nlen = strlen(usefile);
8665 for (i = 0; i < size; i++) {
8666 slen = strlen(suf[i]);
8667 if (nlen < slen)
8668 return (NULL);
8669 if (strcmp(usefile + nlen - slen, suf[i]) == 0)
8670 return (suf[i]);
8672 return (NULL);
8675 /* Checking valid 'bzip2' suffix */
8676 char *
8677 bz_suffix(void)
8679 return (check_suffix(bsuffix, BSUF));
8682 /* Checking valid 'gzip' suffix */
8683 char *
8684 gz_suffix(void)
8686 return (check_suffix(gsuffix, GSUF));
8689 /* Checking valid 'xz' suffix */
8690 char *
8691 xz_suffix(void)
8693 return (check_suffix(xsuffix, XSUF));
8696 void *
8697 compress_malloc(size_t size)
8699 void *opt;
8701 if ((opt = malloc(size)) == NULL) {
8702 vperror(1, "%s",
8703 gettext("Could not allocate compress buffer\n"));
8705 return (opt);
8708 void
8709 wait_pid(pid_t pid)
8711 int status;
8713 while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
8717 static void
8718 verify_compress_opt(const char *t)
8720 struct stat statbuf;
8722 if (stat(t, &statbuf) == -1)
8723 vperror(1, "%s %s: %s\n", gettext("Could not stat"),
8724 t, strerror(errno));
8727 static void
8728 detect_compress(void)
8730 char *zsuf[] = {".Z"};
8731 if (check_suffix(zsuf, 1) != NULL) {
8732 Zflag = 1;
8733 } else if (check_suffix(bsuffix, BSUF) != NULL) {
8734 jflag = 1;
8735 } else if (check_suffix(gsuffix, GSUF) != NULL) {
8736 zflag = 1;
8737 } else if (check_suffix(xsuffix, XSUF) != NULL) {
8738 Jflag = 1;
8739 } else {
8740 vperror(1, "%s\n", gettext("No compression method detected"));