dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / tar / tar.c
blob77e5c924ebd0f407a0806a0b3e3083225e09d60b
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 * Copyright 2015 Joyent, Inc.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
28 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
31 /* Copyright (c) 1987, 1988 Microsoft Corporation */
32 /* All Rights Reserved */
35 * Portions of this source code were derived from Berkeley 4.3 BSD
36 * under license from the Regents of the University of California.
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/stat.h>
43 #include <sys/mkdev.h>
44 #include <sys/wait.h>
45 #include <dirent.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <signal.h>
49 #include <ctype.h>
50 #include <locale.h>
51 #include <nl_types.h>
52 #include <langinfo.h>
53 #include <pwd.h>
54 #include <grp.h>
55 #include <fcntl.h>
56 #include <string.h>
57 #include <malloc.h>
58 #include <time.h>
59 #include <utime.h>
60 #include <stdlib.h>
61 #include <stdarg.h>
62 #include <widec.h>
63 #include <sys/mtio.h>
64 #include <sys/acl.h>
65 #include <strings.h>
66 #include <deflt.h>
67 #include <limits.h>
68 #include <iconv.h>
69 #include <assert.h>
70 #include <libgen.h>
71 #include <libintl.h>
72 #include <aclutils.h>
73 #include <libnvpair.h>
74 #include <archives.h>
75 #include <err.h>
77 #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
78 extern int defcntl();
79 #endif
80 #if defined(_PC_SATTR_ENABLED)
81 #include <attr.h>
82 #include <libcmdutils.h>
83 #endif
85 #include "getresponse.h"
87 * Source compatibility
91 * These constants come from archives.h and sys/fcntl.h
92 * and were introduced by the extended attributes project
93 * in Solaris 9.
95 #if !defined(O_XATTR)
96 #define AT_SYMLINK_NOFOLLOW 0x1000
97 #define AT_REMOVEDIR 0x1
98 #define AT_FDCWD 0xffd19553
99 #define _XATTR_HDRTYPE 'E'
100 static int attropen();
101 static int fstatat();
102 static int renameat();
103 static int unlinkat();
104 static int openat();
105 static int fchownat();
106 static int futimesat();
107 #endif
110 * Compiling with -D_XPG4_2 gets this but produces other problems, so
111 * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
112 * explicitly doing the declaration here.
114 int utimes(const char *path, const struct timeval timeval_ptr[]);
116 #ifndef MINSIZE
117 #define MINSIZE 250
118 #endif
119 #define DEF_FILE "/etc/default/tar"
121 #define min(a, b) ((a) < (b) ? (a) : (b))
122 #define max(a, b) ((a) > (b) ? (a) : (b))
124 #define TBLOCK 512 /* tape block size--should be universal */
126 #ifdef BSIZE
127 #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
128 #else /* BSIZE */
129 #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
130 #endif /* BSIZE */
132 #define NBLOCK 20
133 #define NAMSIZ 100
134 #define PRESIZ 155
135 #define MAXNAM 256
136 #define MODEMASK 0777777 /* file creation mode mask */
137 #define POSIXMODES 07777 /* mask for POSIX mode bits */
138 #define MAXEXT 9 /* reasonable max # extents for a file */
139 #define EXTMIN 50 /* min blks left on floppy to split a file */
141 /* max value dblock.dbuf.efsize can store */
142 #define TAR_EFSIZE_MAX 0777777777
145 * Symbols which specify the values at which the use of the 'E' function
146 * modifier is required to properly store a file.
148 * TAR_OFFSET_MAX - the largest file size we can archive
149 * OCTAL7CHAR - the limit for ustar gid, uid, dev
152 #ifdef XHDR_DEBUG
153 /* tiny values which force the creation of extended header entries */
154 #define TAR_OFFSET_MAX 9
155 #define OCTAL7CHAR 2
156 #else
157 /* normal values */
158 #define TAR_OFFSET_MAX 077777777777ULL
159 #define OCTAL7CHAR 07777777
160 #endif
162 #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
163 #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
165 #define MAXLEV (PATH_MAX / 2)
166 #define LEV0 1
167 #define SYMLINK_LEV0 0
169 #define TRUE 1
170 #define FALSE 0
172 #define XATTR_FILE 1
173 #define NORMAL_FILE 0
175 #define PUT_AS_LINK 1
176 #define PUT_NOTAS_LINK 0
178 #ifndef VIEW_READONLY
179 #define VIEW_READONLY "SUNWattr_ro"
180 #endif
182 #ifndef VIEW_READWRITE
183 #define VIEW_READWRITE "SUNWattr_rw"
184 #endif
186 #if _FILE_OFFSET_BITS == 64
187 #define FMT_off_t "lld"
188 #define FMT_off_t_o "llo"
189 #define FMT_blkcnt_t "lld"
190 #else
191 #define FMT_off_t "ld"
192 #define FMT_off_t_o "lo"
193 #define FMT_blkcnt_t "ld"
194 #endif
196 /* ACL support */
198 static
199 struct sec_attr {
200 char attr_type;
201 char attr_len[7];
202 char attr_info[1];
203 } *attr;
205 #if defined(O_XATTR)
206 typedef enum {
207 ATTR_OK,
208 ATTR_SKIP,
209 ATTR_CHDIR_ERR,
210 ATTR_OPEN_ERR,
211 ATTR_XATTR_ERR,
212 ATTR_SATTR_ERR
213 } attr_status_t;
214 #endif
216 #if defined(O_XATTR)
217 typedef enum {
218 ARC_CREATE,
219 ARC_RESTORE
220 } arc_action_t;
221 #endif
223 typedef struct attr_data {
224 char *attr_parent;
225 char *attr_path;
226 int attr_parentfd;
227 int attr_rw_sysattr;
228 } attr_data_t;
232 * Tar has been changed to support extended attributes.
234 * As part of this change tar now uses the new *at() syscalls
235 * such as openat, fchownat(), unlinkat()...
237 * This was done so that attributes can be handled with as few code changes
238 * as possible.
240 * What this means is that tar now opens the directory that a file or directory
241 * resides in and then performs *at() functions to manipulate the entry.
243 * For example a new file is now created like this:
245 * dfd = open(<some dir path>)
246 * fd = openat(dfd, <name>,....);
248 * or in the case of an extended attribute
250 * dfd = attropen(<pathname>, ".", ....)
252 * Once we have a directory file descriptor all of the *at() functions can
253 * be applied to it.
255 * unlinkat(dfd, <component name>,...)
256 * fchownat(dfd, <component name>,..)
258 * This works for both normal namespace files and extended attribute file
264 * Extended attribute Format
266 * Extended attributes are stored in two pieces.
267 * 1. An attribute header which has information about
268 * what file the attribute is for and what the attribute
269 * is named.
270 * 2. The attribute record itself. Stored as a normal file type
271 * of entry.
272 * Both the header and attribute record have special modes/typeflags
273 * associated with them.
275 * The names of the header in the archive look like:
276 * /dev/null/attr.hdr
278 * The name of the attribute looks like:
279 * /dev/null/attr
281 * This is done so that an archiver that doesn't understand these formats
282 * can just dispose of the attribute records.
284 * The format is composed of a fixed size header followed
285 * by a variable sized xattr_buf. If the attribute is a hard link
286 * to another attribute then another xattr_buf section is included
287 * for the link.
289 * The xattr_buf is used to define the necessary "pathing" steps
290 * to get to the extended attribute. This is necessary to support
291 * a fully recursive attribute model where an attribute may itself
292 * have an attribute.
294 * The basic layout looks like this.
296 * --------------------------------
297 * | |
298 * | xattr_hdr |
299 * | |
300 * --------------------------------
301 * --------------------------------
302 * | |
303 * | xattr_buf |
304 * | |
305 * --------------------------------
306 * --------------------------------
307 * | |
308 * | (optional link info) |
309 * | |
310 * --------------------------------
311 * --------------------------------
312 * | |
313 * | attribute itself |
314 * | stored as normal tar |
315 * | or cpio data with |
316 * | special mode or |
317 * | typeflag |
318 * | |
319 * --------------------------------
324 * xattrhead is a pointer to the xattr_hdr
326 * xattrp is a pointer to the xattr_buf structure
327 * which contains the "pathing" steps to get to attributes
329 * xattr_linkp is a pointer to another xattr_buf structure that is
330 * only used when an attribute is actually linked to another attribute
334 static struct xattr_hdr *xattrhead;
335 static struct xattr_buf *xattrp;
336 static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
337 static char *xattrapath; /* attribute name */
338 static char *xattr_linkaname; /* attribute attribute is linked to */
339 static char Hiddendir; /* are we processing hidden xattr dir */
340 static char xattrbadhead;
342 /* Was statically allocated tbuf[NBLOCK] */
343 static
344 union hblock {
345 char dummy[TBLOCK];
346 struct header {
347 char name[NAMSIZ]; /* If non-null prefix, path is */
348 /* <prefix>/<name>; otherwise */
349 /* <name> */
350 char mode[8];
351 char uid[8];
352 char gid[8];
353 char size[12]; /* size of this extent if file split */
354 char mtime[12];
355 char chksum[8];
356 char typeflag;
357 char linkname[NAMSIZ];
358 char magic[6];
359 char version[2];
360 char uname[32];
361 char gname[32];
362 char devmajor[8];
363 char devminor[8];
364 char prefix[PRESIZ]; /* Together with "name", the path of */
365 /* the file: <prefix>/<name> */
366 char extno; /* extent #, null if not split */
367 char extotal; /* total extents */
368 char efsize[10]; /* size of entire file */
369 } dbuf;
370 } dblock, *tbuf, xhdr_buf;
372 static
373 struct xtar_hdr {
374 uid_t x_uid, /* Uid of file */
375 x_gid; /* Gid of file */
376 major_t x_devmajor; /* Device major node */
377 minor_t x_devminor; /* Device minor node */
378 off_t x_filesz; /* Length of file */
379 char *x_uname, /* Pointer to name of user */
380 *x_gname, /* Pointer to gid of user */
381 *x_linkpath, /* Path for a hard/symbolic link */
382 *x_path; /* Path of file */
383 timestruc_t x_mtime; /* Seconds and nanoseconds */
384 } Xtarhdr;
386 static
387 struct gen_hdr {
388 ulong_t g_mode; /* Mode of file */
389 uid_t g_uid, /* Uid of file */
390 g_gid; /* Gid of file */
391 off_t g_filesz; /* Length of file */
392 time_t g_mtime; /* Modification time */
393 uint_t g_cksum; /* Checksum of file */
394 ulong_t g_devmajor, /* File system of file */
395 g_devminor; /* Major/minor of special files */
396 } Gen;
398 static
399 struct linkbuf {
400 ino_t inum;
401 dev_t devnum;
402 int count;
403 char pathname[MAXNAM+1]; /* added 1 for last NULL */
404 char attrname[MAXNAM+1];
405 struct linkbuf *nextp;
406 } *ihead;
408 /* see comments before build_table() */
409 #define TABLE_SIZE 512
410 typedef struct file_list {
411 char *name; /* Name of file to {in,ex}clude */
412 struct file_list *next; /* Linked list */
413 } file_list_t;
414 static file_list_t *exclude_tbl[TABLE_SIZE],
415 *include_tbl[TABLE_SIZE];
417 static int append_secattr(char **, int *, int, char *, char);
418 static void write_ancillary(union hblock *, char *, int, char);
420 static void add_file_to_table(file_list_t *table[], char *str);
421 static void assert_string(char *s, char *msg);
422 static int istape(int fd, int type);
423 static void backtape(void);
424 static void build_table(file_list_t *table[], char *file);
425 static int check_prefix(char **namep, char **dirp, char **compp);
426 static void closevol(void);
427 static void copy(void *dst, void *src);
428 static int convtoreg(off_t);
429 static void delete_target(int fd, char *comp, char *namep);
430 static void doDirTimes(char *name, timestruc_t modTime);
431 static void done(int n);
432 static void dorep(char *argv[]);
433 static void dotable(char *argv[]);
434 static void doxtract(char *argv[]);
435 static int tar_chdir(const char *path);
436 static int is_directory(char *name);
437 static int has_dot_dot(char *name);
438 static int is_absolute(char *name);
439 static char *make_relative_name(char *name, char **stripped_prefix);
440 static void fatal(char *format, ...);
441 static void vperror(int exit_status, char *fmt, ...);
442 static void flushtape(void);
443 static void getdir(void);
444 static void *getmem(size_t);
445 static void longt(struct stat *st, char aclchar);
446 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
447 static int makeDir(char *name);
448 static void mterr(char *operation, int i, int exitcode);
449 static void newvol(void);
450 static void passtape(void);
451 static void putempty(blkcnt_t n);
452 static int putfile(char *longname, char *shortname, char *parent,
453 attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
454 static void readtape(char *buffer);
455 static void seekdisk(blkcnt_t blocks);
456 static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
457 static void setbytes_to_skip(struct stat *st, int err);
458 static void splitfile(char *longname, int ifd, char *name,
459 char *prefix, int filetype);
460 static void tomodes(struct stat *sp);
461 static void usage(void);
462 static int xblocks(int issysattr, off_t bytes, int ofile);
463 static int xsfile(int issysattr, int ofd);
464 static void resugname(int dirfd, char *name, int symflag);
465 static int bcheck(char *bstr);
466 static int checkdir(char *name);
467 static int checksum(union hblock *dblockp);
468 #ifdef EUC
469 static int checksum_signed(union hblock *dblockp);
470 #endif /* EUC */
471 static int checkupdate(char *arg);
472 static int checkw(char c, char *name);
473 static int cmp(char *b, char *s, int n);
474 static int defset(char *arch);
475 static boolean_t endtape(void);
476 static int is_in_table(file_list_t *table[], char *str);
477 static int notsame(void);
478 static int is_prefix(char *s1, char *s2);
479 static int response(void);
480 static int build_dblock(const char *, const char *, const char,
481 const int filetype, const struct stat *, const dev_t, const char *);
482 static unsigned int hash(char *str);
484 static blkcnt_t kcheck(char *kstr);
485 static off_t bsrch(char *s, int n, off_t l, off_t h);
486 static void onintr(int sig);
487 static void onquit(int sig);
488 static void onhup(int sig);
489 static uid_t getuidbyname(char *);
490 static gid_t getgidbyname(char *);
491 static char *getname(gid_t);
492 static char *getgroup(gid_t);
493 static int checkf(char *name, int mode, int howmuch);
494 static int writetbuf(char *buffer, int n);
495 static int wantit(char *argv[], char **namep, char **dirp, char **comp,
496 attr_data_t **attrinfo);
497 static int get_xdata(void);
498 static void gen_num(const char *keyword, const u_longlong_t number);
499 static void gen_date(const char *keyword, const timestruc_t time_value);
500 static void gen_string(const char *keyword, const char *value);
501 static void get_xtime(char *value, timestruc_t *xtime);
502 static int chk_path_build(char *name, char *longname, char *linkname,
503 char *prefix, char type, int filetype);
504 static int gen_utf8_names(const char *filename);
505 static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
506 const char *src, int max_val);
507 static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
508 iconv_t iconv_cd, int xhdrflg, int max_val);
509 static int c_utf8(char *target, const char *source);
510 static int getstat(int dirfd, char *longname, char *shortname,
511 char *attrparent);
512 static void xattrs_put(char *, char *, char *, char *);
513 static void prepare_xattr(char **, char *, char *,
514 char, struct linkbuf *, int *);
515 static int put_link(char *name, char *longname, char *component,
516 char *longattrname, char *prefix, int filetype, char typeflag);
517 static int put_extra_attributes(char *longname, char *shortname,
518 char *longattrname, char *prefix, int filetype, char typeflag);
519 static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
520 char *prefix, int typeflag, int filetype, struct linkbuf *lp);
521 static int read_xattr_hdr(attr_data_t **attrinfo);
523 static void get_parent(char *path, char *dir);
524 static char *get_component(char *path);
525 static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
526 char *name, int oflag, mode_t mode);
527 static char *skipslashes(char *string, char *start);
528 static void chop_endslashes(char *path);
529 static pid_t compress_file(void);
530 static void compress_back(void);
531 static void decompress_file(void);
532 static pid_t uncompress_file(void);
533 static void *compress_malloc(size_t);
534 static void check_compression(void);
535 static char *bz_suffix(void);
536 static char *gz_suffix(void);
537 static char *xz_suffix(void);
538 static char *add_suffix();
539 static void wait_pid(pid_t);
540 static void verify_compress_opt(const char *t);
541 static void detect_compress(void);
542 static void dlog(const char *, ...);
543 static boolean_t should_enable_debug(void);
545 static struct stat stbuf;
547 static char *myname;
548 static char *xtract_chdir = NULL;
549 static int checkflag = 0;
550 static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
551 static int rflag, xflag, vflag, tflag, mt, cflag, mflag, pflag;
552 static int uflag;
553 static int errflag;
554 static int oflag;
555 static int bflag, Aflag;
556 static int Pflag; /* POSIX conformant archive */
557 static int Eflag; /* Allow files greater than 8GB */
558 static int atflag; /* traverse extended attributes */
559 static int saflag; /* traverse extended sys attributes */
560 static int Dflag; /* Data change flag */
561 static int jflag; /* flag to use 'bzip2' */
562 static int zflag; /* flag to use 'gzip' */
563 static int Zflag; /* flag to use 'compress' */
564 static int Jflag; /* flag to use 'xz' */
565 static int aflag; /* flag to use autocompression */
567 static int term, chksum, wflag,
568 first = TRUE, defaults_used = FALSE, linkerrok;
569 static blkcnt_t recno;
570 static int freemem = 1;
571 static int nblock = NBLOCK;
572 static int Errflg = 0;
573 static int exitflag = 0;
575 static dev_t mt_dev; /* device containing output file */
576 static ino_t mt_ino; /* inode number of output file */
577 static int mt_devtype; /* dev type of archive, from stat structure */
579 static int update = 1; /* for `open' call */
581 static off_t low;
582 static off_t high;
584 static FILE *tfile;
585 static FILE *vfile;
586 static char *tmpdir;
587 static char *tmp_suffix = "/tarXXXXXX";
588 static char *tname;
589 static char archive[] = "archive0=";
590 static char *Xfile;
591 static char *usefile;
592 static char tfname[1024];
594 static int mulvol; /* multi-volume option selected */
595 static blkcnt_t blocklim; /* number of blocks to accept per volume */
596 static blkcnt_t tapepos; /* current block number to be written */
597 static int NotTape; /* true if tape is a disk */
598 static int dumping; /* true if writing a tape or other archive */
599 static int extno; /* number of extent: starts at 1 */
600 static int extotal; /* total extents in this file */
601 static off_t extsize; /* size of current extent during extraction */
602 static ushort_t Oumask = 0; /* old umask value */
603 static boolean_t is_posix; /* true if archive is POSIX-conformant */
604 static const char *magic_type = "ustar";
605 static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */
606 static char *xrec_ptr;
607 static off_t xrec_offset = 0;
608 static int Xhdrflag;
609 static int charset_type = 0;
611 static u_longlong_t xhdr_flgs; /* Bits set determine which items */
612 /* need to be in extended header. */
613 static pid_t comp_pid = 0;
615 static boolean_t debug_output = B_FALSE;
617 #define _X_DEVMAJOR 0x1
618 #define _X_DEVMINOR 0x2
619 #define _X_GID 0x4
620 #define _X_GNAME 0x8
621 #define _X_LINKPATH 0x10
622 #define _X_PATH 0x20
623 #define _X_SIZE 0x40
624 #define _X_UID 0x80
625 #define _X_UNAME 0x100
626 #define _X_ATIME 0x200
627 #define _X_CTIME 0x400
628 #define _X_MTIME 0x800
629 #define _X_XHDR 0x1000 /* Bit flag that determines whether 'X' */
630 /* typeflag was followed by 'A' or non 'A' */
631 /* typeflag. */
632 #define _X_LAST 0x40000000
634 #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4)
635 #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4)
636 #define LONG_MAX_DIGITS (10 * sizeof (long) / 4)
637 #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4)
639 * UTF_8 encoding requires more space than the current codeset equivalent.
640 * Currently a factor of 2-3 would suffice, but it is possible for a factor
641 * of 6 to be needed in the future, so for saftey, we use that here.
643 #define UTF_8_FACTOR 6
645 static u_longlong_t xhdr_count = 0;
646 static char xhdr_dirname[PRESIZ + 1];
647 static char pidchars[PID_MAX_DIGITS + 1];
648 static char *tchar = ""; /* null linkpath */
650 static char local_path[UTF_8_FACTOR * PATH_MAX + 1];
651 static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
652 static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
653 static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
656 * The following mechanism is provided to allow us to debug tar in complicated
657 * situations, like when it is part of a pipe. The idea is that you compile
658 * with -DWAITAROUND defined, and then add the 'D' function modifier to the
659 * target tar invocation, eg. "tar cDf tarfile file". If stderr is available,
660 * it will tell you to which pid to attach the debugger; otherwise, use ps to
661 * find it. Attach to the process from the debugger, and, *PRESTO*, you are
662 * there!
664 * Simply assign "waitaround = 0" once you attach to the process, and then
665 * proceed from there as usual.
668 #ifdef WAITAROUND
669 int waitaround = 0; /* wait for rendezvous with the debugger */
670 #endif
672 #define BZIP "/usr/bin/bzip2"
673 #define GZIP "/usr/bin/gzip"
674 #define COMPRESS "/usr/bin/compress"
675 #define XZ "/usr/bin/xz"
676 #define BZCAT "/usr/bin/bzcat"
677 #define GZCAT "/usr/bin/gzcat"
678 #define ZCAT "/usr/bin/zcat"
679 #define XZCAT "/usr/bin/xzcat"
680 #define GSUF 8 /* number of valid 'gzip' sufixes */
681 #define BSUF 4 /* number of valid 'bzip2' sufixes */
682 #define XSUF 1 /* number of valid 'xz' suffixes */
684 static char *compress_opt; /* compression type */
686 static char *gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
687 ".tgz", ".taz"};
688 static char *bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
689 static char *xsuffix[] = {".xz"};
690 static char *suffix;
694 main(int argc, char *argv[])
696 char *cp;
697 char *tmpdirp;
698 pid_t thispid;
700 vfile = stdout;
702 (void) setlocale(LC_ALL, "");
703 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
704 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
705 #endif
706 (void) textdomain(TEXT_DOMAIN);
707 if (argc < 2)
708 usage();
710 debug_output = should_enable_debug();
712 tfile = NULL;
713 if ((myname = strdup(argv[0])) == NULL) {
714 (void) fprintf(stderr, gettext(
715 "tar: cannot allocate program name\n"));
716 exit(1);
719 if (init_yes() < 0) {
720 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
721 strerror(errno));
722 exit(2);
726 * For XPG4 compatibility, we must be able to accept the "--"
727 * argument normally recognized by getopt; it is used to delimit
728 * the end opt the options section, and so can only appear in
729 * the position of the first argument. We simply skip it.
732 if (strcmp(argv[1], "--") == 0) {
733 argv++;
734 argc--;
735 if (argc < 3)
736 usage();
739 argv[argc] = NULL;
740 argv++;
743 * Set up default values.
744 * Search the operand string looking for the first digit or an 'f'.
745 * If you find a digit, use the 'archive#' entry in DEF_FILE.
746 * If 'f' is given, bypass looking in DEF_FILE altogether.
747 * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
749 if ((usefile = getenv("TAPE")) == NULL) {
750 for (cp = *argv; *cp; ++cp)
751 if (isdigit(*cp) || *cp == 'f')
752 break;
753 if (*cp != 'f') {
754 archive[7] = (*cp)? *cp: '0';
755 if (!(defaults_used = defset(archive))) {
756 usefile = NULL;
757 nblock = 1;
758 blocklim = 0;
759 NotTape = 0;
764 for (cp = *argv++; *cp; cp++)
765 switch (*cp) {
766 #ifdef WAITAROUND
767 case 'D':
768 /* rendezvous with the debugger */
769 waitaround = 1;
770 break;
771 #endif
772 case 'f':
773 assert_string(*argv, gettext(
774 "tar: tarfile must be specified with 'f' "
775 "function modifier\n"));
776 usefile = *argv++;
777 break;
778 case 'F':
779 Fflag++;
780 break;
781 case 'c':
782 cflag++;
783 rflag++;
784 update = 1;
785 break;
786 #if defined(O_XATTR)
787 case '@':
788 atflag++;
789 break;
790 #endif /* O_XATTR */
791 #if defined(_PC_SATTR_ENABLED)
792 case '/':
793 saflag++;
794 break;
795 #endif /* _PC_SATTR_ENABLED */
796 case 'u':
797 uflag++; /* moved code after signals caught */
798 rflag++;
799 update = 2;
800 break;
801 case 'r':
802 rflag++;
803 update = 2;
804 break;
805 case 'v':
806 vflag++;
807 break;
808 case 'w':
809 wflag++;
810 break;
811 case 'x':
812 xflag++;
813 break;
814 case 'X':
815 assert_string(*argv, gettext(
816 "tar: exclude file must be specified with 'X' "
817 "function modifier\n"));
818 Xflag = 1;
819 Xfile = *argv++;
820 build_table(exclude_tbl, Xfile);
821 break;
822 case 't':
823 tflag++;
824 break;
825 case 'm':
826 mflag++;
827 break;
828 case 'p':
829 pflag++;
830 break;
831 case 'D':
832 Dflag++;
833 break;
834 case '-':
835 /* ignore this silently */
836 break;
837 case '0': /* numeric entries used only for defaults */
838 case '1':
839 case '2':
840 case '3':
841 case '4':
842 case '5':
843 case '6':
844 case '7':
845 break;
846 case 'b':
847 assert_string(*argv, gettext(
848 "tar: blocking factor must be specified "
849 "with 'b' function modifier\n"));
850 bflag++;
851 nblock = bcheck(*argv++);
852 break;
853 case 'n': /* not a magtape (instead of 'k') */
854 NotTape++; /* assume non-magtape */
855 break;
856 case 'l':
857 linkerrok++;
858 break;
859 case 'e':
860 errflag++;
861 break;
862 case 'o':
863 oflag++;
864 break;
865 case 'h':
866 hflag++;
867 break;
868 case 'i':
869 iflag++;
870 break;
871 case 'B':
872 Bflag++;
873 break;
874 case 'P':
875 Pflag++;
876 break;
877 case 'E':
878 Eflag++;
879 Pflag++; /* Only POSIX archive made */
880 break;
881 case 'j': /* compession "bzip2" */
882 jflag = 1;
883 break;
884 case 'z': /* compression "gzip" */
885 zflag = 1;
886 break;
887 case 'Z': /* compression "compress" */
888 Zflag = 1;
889 break;
890 case 'J': /* compression "xz" */
891 Jflag = 1;
892 break;
893 case 'a':
894 aflag = 1; /* autocompression */
895 break;
896 default:
897 (void) fprintf(stderr, gettext(
898 "tar: %c: unknown function modifier\n"), *cp);
899 usage();
902 if (!rflag && !xflag && !tflag)
903 usage();
904 if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
905 (void) fprintf(stderr, gettext(
906 "tar: specify only one of [ctxru].\n"));
907 usage();
909 if (cflag) {
910 if ((jflag + zflag + Zflag + Jflag + aflag) > 1) {
911 (void) fprintf(stderr, gettext(
912 "tar: specify only one of [ajJzZ] to "
913 "create a compressed file.\n"));
914 usage();
917 if (cflag && *argv == NULL)
918 fatal(gettext("Missing filenames"));
919 if (usefile == NULL)
920 fatal(gettext("device argument required"));
922 /* alloc a buffer of the right size */
923 if ((tbuf = (union hblock *)
924 calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
925 (union hblock *)NULL) {
926 (void) fprintf(stderr, gettext(
927 "tar: cannot allocate physio buffer\n"));
928 exit(1);
931 if ((xrec_ptr = malloc(xrec_size)) == NULL) {
932 (void) fprintf(stderr, gettext(
933 "tar: cannot allocate extended header buffer\n"));
934 exit(1);
937 #ifdef WAITAROUND
938 if (waitaround) {
939 (void) fprintf(stderr, gettext("Rendezvous with tar on pid"
940 " %d\n"), getpid());
942 while (waitaround) {
943 (void) sleep(10);
946 #endif
948 thispid = getpid();
949 (void) sprintf(pidchars, "%ld", thispid);
950 thispid = strlen(pidchars);
952 if ((tmpdirp = getenv("TMPDIR")) == NULL)
953 (void) strcpy(xhdr_dirname, "/tmp");
954 else {
956 * Make sure that dir is no longer than what can
957 * fit in the prefix part of the header.
959 if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
960 (void) strcpy(xhdr_dirname, "/tmp");
961 if ((vflag > 0) && (Eflag > 0))
962 (void) fprintf(stderr, gettext(
963 "Ignoring TMPDIR\n"));
964 } else
965 (void) strcpy(xhdr_dirname, tmpdirp);
967 (void) strcat(xhdr_dirname, "/PaxHeaders.");
968 (void) strcat(xhdr_dirname, pidchars);
970 if (rflag) {
971 if (cflag && usefile != NULL) {
972 /* Set the compression type */
973 if (aflag)
974 detect_compress();
976 if (jflag) {
977 compress_opt = compress_malloc(strlen(BZIP)
978 + 1);
979 (void) strcpy(compress_opt, BZIP);
980 } else if (zflag) {
981 compress_opt = compress_malloc(strlen(GZIP)
982 + 1);
983 (void) strcpy(compress_opt, GZIP);
984 } else if (Zflag) {
985 compress_opt =
986 compress_malloc(strlen(COMPRESS) + 1);
987 (void) strcpy(compress_opt, COMPRESS);
988 } else if (Jflag) {
989 compress_opt = compress_malloc(strlen(XZ) + 1);
990 (void) strcpy(compress_opt, XZ);
992 } else {
994 * Decompress if the file is compressed for
995 * an update or replace.
997 if (strcmp(usefile, "-") != 0) {
998 check_compression();
999 if (compress_opt != NULL) {
1000 decompress_file();
1005 if (cflag && tfile != NULL)
1006 usage();
1007 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1008 (void) signal(SIGINT, onintr);
1009 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1010 (void) signal(SIGHUP, onhup);
1011 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1012 (void) signal(SIGQUIT, onquit);
1013 if (uflag) {
1014 int tnum;
1015 struct stat sbuf;
1017 tmpdir = getenv("TMPDIR");
1019 * If the name is invalid or this isn't a directory,
1020 * or the directory is not writable, then reset to
1021 * a default temporary directory.
1023 if (tmpdir == NULL || *tmpdir == '\0' ||
1024 (strlen(tmpdir) + strlen(tmp_suffix)) > PATH_MAX) {
1025 tmpdir = "/tmp";
1026 } else if (stat(tmpdir, &sbuf) < 0 ||
1027 (sbuf.st_mode & S_IFMT) != S_IFDIR ||
1028 (sbuf.st_mode & S_IWRITE) == 0) {
1029 tmpdir = "/tmp";
1032 if ((tname = calloc(1, strlen(tmpdir) +
1033 strlen(tmp_suffix) + 1)) == NULL) {
1034 vperror(1, gettext("tar: out of memory, "
1035 "cannot create temporary file\n"));
1037 (void) strcpy(tname, tmpdir);
1038 (void) strcat(tname, tmp_suffix);
1040 if ((tnum = mkstemp(tname)) == -1)
1041 vperror(1, "%s", tname);
1042 if ((tfile = fdopen(tnum, "w")) == NULL)
1043 vperror(1, "%s", tname);
1045 if (strcmp(usefile, "-") == 0) {
1046 if (cflag == 0)
1047 fatal(gettext(
1048 "can only create standard output archives."));
1049 vfile = stderr;
1050 mt = dup(1);
1051 ++bflag;
1052 } else {
1053 if (cflag)
1054 mt = open(usefile,
1055 O_RDWR|O_CREAT|O_TRUNC, 0666);
1056 else
1057 mt = open(usefile, O_RDWR);
1059 if (mt < 0) {
1060 if (cflag == 0 || (mt = creat(usefile, 0666))
1061 < 0)
1062 vperror(1, "%s", usefile);
1065 /* Get inode and device number of output file */
1066 (void) fstat(mt, &stbuf);
1067 mt_ino = stbuf.st_ino;
1068 mt_dev = stbuf.st_dev;
1069 mt_devtype = stbuf.st_mode & S_IFMT;
1070 NotTape = !istape(mt, mt_devtype);
1072 if (rflag && !cflag && (mt_devtype == S_IFIFO))
1073 fatal(gettext("cannot append to pipe or FIFO."));
1075 if (Aflag && vflag)
1076 (void) printf(
1077 gettext("Suppressing absolute pathnames\n"));
1078 if (cflag && compress_opt != NULL)
1079 comp_pid = compress_file();
1080 dorep(argv);
1081 if (rflag && !cflag && (compress_opt != NULL))
1082 compress_back();
1083 } else if (xflag || tflag) {
1085 * for each argument, check to see if there is a "-I file" pair.
1086 * if so, move the 3rd argument into "-I"'s place, build_table()
1087 * using "file"'s name and increment argc one (the second
1088 * increment appears in the for loop) which removes the two
1089 * args "-I" and "file" from the argument vector.
1091 for (argc = 0; argv[argc]; argc++) {
1092 if (strcmp(argv[argc], "-I") == 0) {
1093 if (!argv[argc+1]) {
1094 (void) fprintf(stderr, gettext(
1095 "tar: missing argument for -I flag\n"));
1096 done(2);
1097 } else {
1098 Iflag = 1;
1099 argv[argc] = argv[argc+2];
1100 build_table(include_tbl, argv[++argc]);
1102 } else if (strcmp(argv[argc], "-C") == 0) {
1103 if (!argv[argc+1]) {
1104 (void) fprintf(stderr, gettext("tar: "
1105 "missing argument for -C flag\n"));
1106 done(2);
1107 } else if (xtract_chdir != NULL) {
1108 (void) fprintf(stderr, gettext("tar: "
1109 "extract should have only one -C "
1110 "flag\n"));
1111 done(2);
1112 } else {
1113 argv[argc] = argv[argc+2];
1114 xtract_chdir = argv[++argc];
1118 if (strcmp(usefile, "-") == 0) {
1119 mt = dup(0);
1120 ++bflag;
1121 /* try to recover from short reads when reading stdin */
1122 ++Bflag;
1123 } else if ((mt = open(usefile, O_RDONLY)) < 0)
1124 vperror(1, "%s", usefile);
1126 /* Decompress if the file is compressed */
1128 if (strcmp(usefile, "-") != 0) {
1129 check_compression();
1130 if (compress_opt != NULL)
1131 comp_pid = uncompress_file();
1133 if (xflag) {
1134 if (xtract_chdir != NULL) {
1135 if (tar_chdir(xtract_chdir) < 0) {
1136 vperror(1, gettext("can't change "
1137 "directories to %s"), xtract_chdir);
1140 if (Aflag && vflag)
1141 (void) printf(gettext(
1142 "Suppressing absolute pathnames.\n"));
1144 doxtract(argv);
1145 } else if (tflag)
1146 dotable(argv);
1148 else
1149 usage();
1151 done(Errflg);
1153 /* Not reached: keep compiler quiet */
1154 return (1);
1157 static boolean_t
1158 should_enable_debug(void)
1160 const char *val;
1161 const char *truth[] = {
1162 "true",
1163 "1",
1164 "yes",
1165 "y",
1166 "please",
1167 NULL
1169 unsigned int i;
1171 if ((val = getenv("DEBUG_TAR")) == NULL) {
1172 return (B_FALSE);
1175 for (i = 0; truth[i] != NULL; i++) {
1176 if (strcmp(val, truth[i]) == 0) {
1177 return (B_TRUE);
1181 return (B_FALSE);
1184 /*PRINTFLIKE1*/
1185 static void
1186 dlog(const char *format, ...)
1188 va_list ap;
1190 if (!debug_output) {
1191 return;
1194 va_start(ap, format);
1195 (void) fprintf(stderr, "tar: DEBUG: ");
1196 (void) vfprintf(stderr, format, ap);
1197 va_end(ap);
1200 static void
1201 usage(void)
1203 (void) fprintf(stderr, gettext(
1204 #if defined(O_XATTR)
1205 #if defined(_PC_SATTR_ENABLED)
1206 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPvw@/[0-7]][bf][X...] "
1207 #else
1208 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPvw@[0-7]][bf][X...] "
1209 #endif /* _PC_SATTR_ENABLED */
1210 #else
1211 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPvw[0-7]][bf][X...] "
1212 #endif /* O_XATTR */
1213 "[j|J|z|Z] "
1214 "[blocksize] [tarfile] [size] [exclude-file...] "
1215 "{file | -I include-file | -C directory file}...\n"));
1216 done(1);
1220 * dorep - do "replacements"
1222 * Dorep is responsible for creating ('c'), appending ('r')
1223 * and updating ('u');
1226 static void
1227 dorep(char *argv[])
1229 char *cp, *cp2, *p;
1230 char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
1231 char file[PATH_MAX*2], origdir[PATH_MAX+1];
1232 FILE *fp = NULL;
1233 int archtype;
1234 int ret;
1237 if (!cflag) {
1238 xhdr_flgs = 0;
1239 getdir(); /* read header for next file */
1240 if (Xhdrflag > 0) {
1241 if (!Eflag)
1242 fatal(gettext("Archive contains extended"
1243 " header. -E flag required.\n"));
1244 ret = get_xdata(); /* Get extended header items */
1245 /* and regular header */
1246 } else {
1247 if (Eflag)
1248 fatal(gettext("Archive contains no extended"
1249 " header. -E flag not allowed.\n"));
1251 while (!endtape()) { /* changed from a do while */
1252 setbytes_to_skip(&stbuf, ret);
1253 passtape(); /* skip the file data */
1254 if (term)
1255 done(Errflg); /* received signal to stop */
1256 xhdr_flgs = 0;
1257 getdir();
1258 if (Xhdrflag > 0)
1259 ret = get_xdata();
1261 if (ret == 0) {
1262 if ((dblock.dbuf.typeflag != 'A') &&
1263 (xhdr_flgs != 0)) {
1264 load_info_from_xtarhdr(xhdr_flgs,
1265 &Xtarhdr);
1266 xhdr_flgs |= _X_XHDR;
1269 backtape(); /* was called by endtape */
1270 if (tfile != NULL) {
1272 * Buffer size is calculated to be the size of the
1273 * tmpdir string, plus 6 times the size of the tname
1274 * string, plus a value that is known to be greater
1275 * than the command pipeline string.
1277 int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
1278 char *buf;
1280 if ((buf = (char *)calloc(1, buflen)) == NULL) {
1281 vperror(1, gettext("tar: out of memory, "
1282 "cannot create sort command file\n"));
1285 (void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
1286 "sort +0 -1 +1nr %s -o %s; awk '$1 "
1287 "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1288 tmpdir, tname, tname, tname, tname, tname, tname);
1289 (void) fflush(tfile);
1290 (void) system(buf);
1291 free(buf);
1292 (void) freopen(tname, "r", tfile);
1293 (void) fstat(fileno(tfile), &stbuf);
1294 high = stbuf.st_size;
1298 dumping = 1;
1299 if (mulvol) { /* SP-1 */
1300 if (nblock && (blocklim%nblock) != 0)
1301 fatal(gettext(
1302 "Volume size not a multiple of block size."));
1303 blocklim -= 2; /* for trailer records */
1304 if (vflag)
1305 (void) fprintf(vfile, gettext("Volume ends at %"
1306 FMT_blkcnt_t "K, blocking factor = %dK\n"),
1307 K((blocklim - 1)), K(nblock));
1311 * Save the original directory before it gets
1312 * changed.
1314 if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
1315 vperror(0, gettext("A parent directory cannot be read"));
1316 exit(1);
1319 (void) strcpy(wdir, origdir);
1321 while ((*argv || fp) && !term) {
1322 if (fp || (strcmp(*argv, "-I") == 0)) {
1323 if (fp == NULL) {
1324 if (*++argv == NULL)
1325 fatal(gettext(
1326 "missing file name for -I flag."));
1327 else if ((fp = fopen(*argv++, "r")) == NULL)
1328 vperror(0, "%s", argv[-1]);
1329 continue;
1330 } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
1331 (void) fclose(fp);
1332 fp = NULL;
1333 continue;
1334 } else {
1335 cp = cp2 = file;
1336 if ((p = strchr(cp2, '\n')))
1337 *p = 0;
1339 } else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
1340 if (tar_chdir(*++argv) < 0)
1341 vperror(0, gettext(
1342 "can't change directories to %s"), *argv);
1343 else
1344 (void) getcwd(wdir, (sizeof (wdir)));
1345 argv++;
1346 continue;
1347 } else
1348 cp = cp2 = strcpy(file, *argv++);
1351 * point cp2 to the last '/' in file, but not
1352 * to a trailing '/'
1354 for (; *cp; cp++) {
1355 if (*cp == '/') {
1356 while (*(cp+1) == '/') {
1357 ++cp;
1359 if (*(cp+1) != '\0') {
1360 /* not trailing slash */
1361 cp2 = cp;
1365 if (cp2 != file) {
1366 *cp2 = '\0';
1367 if (tar_chdir(file) < 0) {
1368 vperror(0, gettext(
1369 "can't change directories to %s"), file);
1370 continue;
1372 *cp2 = '/';
1373 cp2++;
1376 parent = getcwd(tempdir, (sizeof (tempdir)));
1378 archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
1379 LEV0, SYMLINK_LEV0);
1381 #if defined(O_XATTR)
1382 if (!exitflag) {
1383 if ((atflag || saflag) &&
1384 (archtype == PUT_NOTAS_LINK)) {
1385 xattrs_put(file, cp2, parent, NULL);
1388 #endif
1390 if (tar_chdir(origdir) < 0)
1391 vperror(0, gettext("cannot change back?: %s"), origdir);
1393 if (exitflag) {
1395 * If e function modifier has been specified
1396 * write the files (that are listed before the
1397 * file causing the error) to tape. exitflag is
1398 * used because only some of the error conditions
1399 * in putfile() recognize the e function modifier.
1401 break;
1405 putempty((blkcnt_t)2);
1406 flushtape();
1407 closevol(); /* SP-1 */
1408 if (linkerrok == 1)
1409 for (; ihead != NULL; ihead = ihead->nextp) {
1410 if (ihead->count == 0)
1411 continue;
1412 (void) fprintf(stderr, gettext(
1413 "tar: missing links to %s\n"), ihead->pathname);
1414 if (errflag)
1415 done(1);
1416 else
1417 Errflg = 1;
1423 * endtape - check for tape at end
1425 * endtape checks the entry in dblock.dbuf to see if its the
1426 * special EOT entry. Endtape is usually called after getdir().
1428 * endtape used to call backtape; it no longer does, it who
1429 * wants it backed up must call backtape himself
1430 * RETURNS: 0 if not EOT, tape position unaffected
1431 * 1 if EOT, tape position unaffected
1434 static boolean_t
1435 endtape(void)
1437 if (dblock.dbuf.name[0] != '\0') {
1439 * The name field is populated.
1441 return (B_FALSE);
1444 if (is_posix && dblock.dbuf.prefix[0] != '\0') {
1446 * This is a ustar/POSIX archive, and although the name
1447 * field is empty the prefix field is not.
1449 return (B_FALSE);
1452 dlog("endtape(): found null header; EOT\n");
1453 return (B_TRUE);
1457 * getdir - get directory entry from tar tape
1459 * getdir reads the next tarblock off the tape and cracks
1460 * it as a directory. The checksum must match properly.
1462 * If tfile is non-null getdir writes the file name and mod date
1463 * to tfile.
1466 static void
1467 getdir(void)
1469 struct stat *sp;
1470 #ifdef EUC
1471 static int warn_chksum_sign = 0;
1472 #endif /* EUC */
1474 top:
1475 readtape((char *)&dblock);
1476 if (dblock.dbuf.name[0] == '\0')
1477 return;
1478 sp = &stbuf;
1479 (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
1480 (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
1481 (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
1482 (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
1483 (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
1484 (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
1485 (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
1486 (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
1488 is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
1490 sp->st_mode = Gen.g_mode;
1491 if (is_posix && (sp->st_mode & S_IFMT) == 0) {
1492 switch (dblock.dbuf.typeflag) {
1493 case '0':
1494 case 0:
1495 case _XATTR_HDRTYPE:
1496 sp->st_mode |= S_IFREG;
1497 break;
1498 case '1': /* hard link */
1499 break;
1500 case '2':
1501 sp->st_mode |= S_IFLNK;
1502 break;
1503 case '3':
1504 sp->st_mode |= S_IFCHR;
1505 break;
1506 case '4':
1507 sp->st_mode |= S_IFBLK;
1508 break;
1509 case '5':
1510 sp->st_mode |= S_IFDIR;
1511 break;
1512 case '6':
1513 sp->st_mode |= S_IFIFO;
1514 break;
1515 default:
1516 if (convtoreg(Gen.g_filesz))
1517 sp->st_mode |= S_IFREG;
1518 break;
1522 if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
1523 Xhdrflag = 1; /* Currently processing extended header */
1524 } else {
1525 Xhdrflag = 0;
1528 sp->st_uid = Gen.g_uid;
1529 sp->st_gid = Gen.g_gid;
1530 sp->st_size = Gen.g_filesz;
1531 sp->st_mtime = Gen.g_mtime;
1532 chksum = Gen.g_cksum;
1534 if (dblock.dbuf.extno != '\0') { /* split file? */
1535 extno = dblock.dbuf.extno;
1536 extsize = Gen.g_filesz;
1537 extotal = dblock.dbuf.extotal;
1538 } else {
1539 extno = 0; /* tell others file not split */
1540 extsize = 0;
1541 extotal = 0;
1544 #ifdef EUC
1545 if (chksum != checksum(&dblock)) {
1546 if (chksum != checksum_signed(&dblock)) {
1547 (void) fprintf(stderr, gettext(
1548 "tar: directory checksum error\n"));
1549 if (iflag) {
1550 Errflg = 2;
1551 goto top;
1553 done(2);
1554 } else {
1555 if (! warn_chksum_sign) {
1556 warn_chksum_sign = 1;
1557 (void) fprintf(stderr, gettext(
1558 "tar: warning: tar file made with signed checksum\n"));
1562 #else
1563 if (chksum != checksum(&dblock)) {
1564 (void) fprintf(stderr, gettext(
1565 "tar: directory checksum error\n"));
1566 if (iflag) {
1567 Errflg = 2;
1568 goto top;
1570 done(2);
1572 #endif /* EUC */
1573 if (tfile != NULL && Xhdrflag == 0) {
1575 * If an extended header is present, then time is available
1576 * in nanoseconds in the extended header data, so set it.
1577 * Otherwise, give an invalid value so that checkupdate will
1578 * not test beyond seconds.
1580 if ((xhdr_flgs & _X_MTIME))
1581 sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
1582 else
1583 sp->st_mtim.tv_nsec = -1;
1585 if (xhdr_flgs & _X_PATH)
1586 (void) fprintf(tfile, "%s %10ld.%9.9ld\n",
1587 Xtarhdr.x_path, sp->st_mtim.tv_sec,
1588 sp->st_mtim.tv_nsec);
1589 else
1590 (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
1591 NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
1592 sp->st_mtim.tv_nsec);
1595 #if defined(O_XATTR)
1596 Hiddendir = 0;
1597 if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
1598 if (xattrbadhead) {
1599 free(xattrhead);
1600 xattrp = NULL;
1601 xattr_linkp = NULL;
1602 xattrhead = NULL;
1603 } else {
1604 char *aname = basename(xattrapath);
1605 size_t xindex = aname - xattrapath;
1607 if (xattrapath[xindex] == '.' &&
1608 xattrapath[xindex + 1] == '\0' &&
1609 xattrp->h_typeflag == '5') {
1610 Hiddendir = 1;
1611 sp->st_mode =
1612 (S_IFDIR | (sp->st_mode & POSIXMODES));
1614 dblock.dbuf.typeflag = xattrp->h_typeflag;
1617 #endif
1622 * passtape - skip over a file on the tape
1624 * passtape skips over the next data file on the tape.
1625 * The tape directory entry must be in dblock.dbuf. This
1626 * routine just eats the number of blocks computed from the
1627 * directory size entry; the tape must be (logically) positioned
1628 * right after the directory info.
1631 static void
1632 passtape(void)
1634 blkcnt_t blocks;
1635 char buf[TBLOCK];
1638 * Print some debugging information about the directory entry
1639 * we are skipping over:
1641 dlog("passtape: typeflag \"%c\"\n", dblock.dbuf.typeflag);
1642 if (dblock.dbuf.name[0] != '\0') {
1643 dlog("passtape: name \"%s\"\n", dblock.dbuf.name);
1645 if (is_posix && dblock.dbuf.prefix[0] != '\0') {
1646 dlog("passtape: prefix \"%s\"\n", dblock.dbuf.prefix);
1650 * Types link(1), sym-link(2), char special(3), blk special(4),
1651 * directory(5), and FIFO(6) do not have data blocks associated
1652 * with them so just skip reading the data block.
1654 if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
1655 dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
1656 dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
1657 return;
1658 blocks = TBLOCKS(stbuf.st_size);
1660 dlog("passtape: block count %" FMT_blkcnt_t "\n", blocks);
1662 /* if operating on disk, seek instead of reading */
1663 if (NotTape)
1664 seekdisk(blocks);
1665 else
1666 while (blocks-- > 0)
1667 readtape(buf);
1670 #if defined(O_XATTR)
1671 static int
1672 is_sysattr(char *name)
1674 return ((strcmp(name, VIEW_READONLY) == 0) ||
1675 (strcmp(name, VIEW_READWRITE) == 0));
1677 #endif
1679 #if defined(O_XATTR)
1681 * Verify the attribute, attrname, is an attribute we want to restore.
1682 * Never restore read-only system attribute files. Only restore read-write
1683 * system attributes files when -/ was specified, and only traverse into
1684 * the 2nd level attribute directory containing only system attributes if
1685 * -@ was specified. This keeps us from archiving
1686 * <attribute name>/<read-write system attribute file>
1687 * when -/ was specified without -@.
1689 * attrname - attribute file name
1690 * attrparent - attribute's parent name within the base file's attribute
1691 * directory hierarchy
1693 static attr_status_t
1694 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
1695 int *rw_sysattr)
1697 #if defined(_PC_SATTR_ENABLED)
1698 int attr_supported;
1700 /* Never restore read-only system attribute files */
1701 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
1702 *rw_sysattr = 0;
1703 return (ATTR_SKIP);
1704 } else {
1705 *rw_sysattr = (attr_supported == _RW_SATTR);
1707 #else
1709 * Only need to check if this attribute is an extended system
1710 * attribute.
1712 if (*rw_sysattr = is_sysattr(attrname)) {
1713 return (ATTR_SKIP);
1714 } else {
1715 return (ATTR_OK);
1717 #endif /* _PC_SATTR_ENABLED */
1720 * If the extended system attribute file is specified with the
1721 * arc_rwsysattr flag, as being transient (default extended
1722 * attributes), then don't archive it.
1724 if (*rw_sysattr && !arc_rwsysattr) {
1725 return (ATTR_SKIP);
1729 * Only restore read-write system attribute files
1730 * when -/ was specified. Only restore extended
1731 * attributes when -@ was specified.
1733 if (atflag) {
1734 if (!saflag) {
1736 * Only archive/restore the hidden directory "." if
1737 * we're processing the top level hidden attribute
1738 * directory. We don't want to process the
1739 * hidden attribute directory of the attribute
1740 * directory that contains only extended system
1741 * attributes.
1743 if (*rw_sysattr || (Hiddendir &&
1744 (attrparent != NULL))) {
1745 return (ATTR_SKIP);
1748 } else if (saflag) {
1750 * Only archive/restore read-write extended system attribute
1751 * files of the base file.
1753 if (!*rw_sysattr || (attrparent != NULL)) {
1754 return (ATTR_SKIP);
1756 } else {
1757 return (ATTR_SKIP);
1760 return (ATTR_OK);
1762 #endif
1764 static void
1765 free_children(file_list_t *children)
1767 file_list_t *child = children;
1768 file_list_t *cptr;
1770 while (child != NULL) {
1771 cptr = child->next;
1772 if (child->name != NULL) {
1773 free(child->name);
1775 child = cptr;
1779 static int
1780 putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
1781 int filetype, int lev, int symlink_lev)
1783 int infile = -1; /* deliberately invalid */
1784 blkcnt_t blocks;
1785 char buf[PATH_MAX + 2]; /* Add trailing slash and null */
1786 char *bigbuf;
1787 int maxread;
1788 int hint; /* amount to write to get "in sync" */
1789 char filetmp[PATH_MAX + 1];
1790 char *cp;
1791 char *name;
1792 char *attrparent = NULL;
1793 char *longattrname = NULL;
1794 file_list_t *child = NULL;
1795 file_list_t *child_end = NULL;
1796 file_list_t *cptr;
1797 struct dirent *dp;
1798 DIR *dirp;
1799 int i;
1800 int split;
1801 int dirfd = -1;
1802 int rc = PUT_NOTAS_LINK;
1803 int archtype = 0;
1804 int rw_sysattr = 0;
1805 char newparent[PATH_MAX + MAXNAMLEN + 1];
1806 char *prefix = "";
1807 char *tmpbuf;
1808 char goodbuf[PRESIZ + 2];
1809 char junkbuf[MAXNAM+1];
1810 char *lastslash;
1811 int j;
1812 struct stat sbuf;
1813 int readlink_max;
1815 (void) memset(goodbuf, '\0', sizeof (goodbuf));
1816 (void) memset(junkbuf, '\0', sizeof (junkbuf));
1818 xhdr_flgs = 0;
1820 if (filetype == XATTR_FILE) {
1821 attrparent = attrinfo->attr_parent;
1822 longattrname = attrinfo->attr_path;
1823 dirfd = attrinfo->attr_parentfd;
1824 rw_sysattr = attrinfo->attr_rw_sysattr;
1825 } else {
1826 dirfd = open(".", O_RDONLY);
1829 if (dirfd == -1) {
1830 (void) fprintf(stderr, gettext(
1831 "tar: unable to open%sdirectory %s%s%s%s\n"),
1832 (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
1833 (attrparent == NULL) ? "" : gettext("of attribute "),
1834 (attrparent == NULL) ? "" : attrparent,
1835 (attrparent == NULL) ? "" : gettext(" of "),
1836 (filetype == XATTR_FILE) ? longname : parent);
1837 goto out;
1840 if (lev > MAXLEV) {
1841 (void) fprintf(stderr,
1842 gettext("tar: directory nesting too deep, %s not dumped\n"),
1843 longname);
1844 goto out;
1847 if (getstat(dirfd, longname, shortname, attrparent))
1848 goto out;
1850 if (hflag) {
1852 * Catch nesting where a file is a symlink to its directory.
1854 j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
1855 if (S_ISLNK(sbuf.st_mode)) {
1856 if (symlink_lev++ >= MAXSYMLINKS) {
1857 (void) fprintf(stderr, gettext(
1858 "tar: %s: Number of symbolic links "
1859 "encountered during path name traversal "
1860 "exceeds MAXSYMLINKS\n"), longname);
1861 Errflg = 1;
1862 goto out;
1868 * Check if the input file is the same as the tar file we
1869 * are creating
1871 if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
1872 (void) fprintf(stderr, gettext(
1873 "tar: %s%s%s%s%s same as archive file\n"),
1874 rw_sysattr ? gettext("system ") : "",
1875 (longattrname == NULL) ? "" : gettext("attribute "),
1876 (longattrname == NULL) ? "" : longattrname,
1877 (longattrname == NULL) ? "" : gettext(" of "),
1878 longname);
1879 Errflg = 1;
1880 goto out;
1883 * Check size limit - we can't archive files that
1884 * exceed TAR_OFFSET_MAX bytes because of header
1885 * limitations. Exclude file types that set
1886 * st_size to zero below because they take no
1887 * archive space to represent contents.
1889 if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
1890 !S_ISDIR(stbuf.st_mode) &&
1891 !S_ISCHR(stbuf.st_mode) &&
1892 !S_ISBLK(stbuf.st_mode) &&
1893 (Eflag == 0)) {
1894 (void) fprintf(stderr, gettext(
1895 "tar: %s%s%s%s%s too large to archive. "
1896 "Use E function modifier.\n"),
1897 rw_sysattr ? gettext("system ") : "",
1898 (longattrname == NULL) ? "" : gettext("attribute "),
1899 (longattrname == NULL) ? "" : longattrname,
1900 (longattrname == NULL) ? "" : gettext(" of "),
1901 longname);
1902 if (errflag)
1903 exitflag = 1;
1904 Errflg = 1;
1905 goto out;
1908 if (tfile != NULL && checkupdate(longname) == 0) {
1909 goto out;
1911 if (checkw('r', longname) == 0) {
1912 goto out;
1915 if (Fflag &&
1916 checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
1917 goto out;
1919 if (Xflag) {
1920 if (is_in_table(exclude_tbl, longname)) {
1921 if (vflag) {
1922 (void) fprintf(vfile, gettext(
1923 "a %s excluded\n"), longname);
1925 goto out;
1930 * If the length of the fullname is greater than MAXNAM,
1931 * print out a message and return (unless extended headers are used,
1932 * in which case fullname is limited to PATH_MAX).
1935 if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
1936 (split > PATH_MAX)) {
1937 (void) fprintf(stderr, gettext(
1938 "tar: %s: file name too long\n"), longname);
1939 if (errflag)
1940 exitflag = 1;
1941 Errflg = 1;
1942 goto out;
1946 * We split the fullname into prefix and name components if any one
1947 * of three conditions holds:
1948 * -- the length of the fullname exceeds NAMSIZ,
1949 * -- the length of the fullname equals NAMSIZ, and the shortname
1950 * is less than NAMSIZ, (splitting in this case preserves
1951 * compatibility with 5.6 and 5.5.1 tar), or
1952 * -- the length of the fullname equals NAMSIZ, the file is a
1953 * directory and we are not in POSIX-conformant mode (where
1954 * trailing slashes are removed from directories).
1956 if ((split > NAMSIZ) ||
1957 (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1958 (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
1960 * Since path is limited to PRESIZ characters, look for the
1961 * last slash within PRESIZ + 1 characters only.
1963 (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
1964 tmpbuf = goodbuf;
1965 lastslash = strrchr(tmpbuf, '/');
1966 if (lastslash == NULL) {
1967 i = split; /* Length of name */
1968 j = 0; /* Length of prefix */
1969 goodbuf[0] = '\0';
1970 } else {
1971 *lastslash = '\0'; /* Terminate the prefix */
1972 j = strlen(tmpbuf);
1973 i = split - j - 1;
1976 * If the filename is greater than NAMSIZ we can't
1977 * archive the file unless we are using extended headers.
1979 if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
1980 !Pflag)) {
1981 /* Determine which (filename or path) is too long. */
1982 lastslash = strrchr(longname, '/');
1983 if (lastslash != NULL)
1984 i = strlen(lastslash + 1);
1985 if (Eflag > 0) {
1986 xhdr_flgs |= _X_PATH;
1987 Xtarhdr.x_path = longname;
1988 if (i <= NAMSIZ)
1989 (void) strcpy(junkbuf, lastslash + 1);
1990 else
1991 (void) sprintf(junkbuf, "%llu",
1992 xhdr_count + 1);
1993 if (split - i - 1 > PRESIZ)
1994 (void) strcpy(goodbuf, xhdr_dirname);
1995 } else {
1996 if ((i > NAMSIZ) || (i == NAMSIZ &&
1997 S_ISDIR(stbuf.st_mode) && !Pflag))
1998 (void) fprintf(stderr, gettext(
1999 "tar: %s: filename is greater than "
2000 "%d\n"), lastslash == NULL ?
2001 longname : lastslash + 1, NAMSIZ);
2002 else
2003 (void) fprintf(stderr, gettext(
2004 "tar: %s: prefix is greater than %d"
2005 "\n"), longname, PRESIZ);
2006 if (errflag)
2007 exitflag = 1;
2008 Errflg = 1;
2009 goto out;
2011 } else
2012 (void) strncpy(&junkbuf[0], longname + j + 1,
2013 strlen(longname + j + 1));
2014 name = junkbuf;
2015 prefix = goodbuf;
2016 } else {
2017 name = longname;
2019 if (Aflag) {
2020 if ((prefix != NULL) && (*prefix != '\0'))
2021 while (*prefix == '/')
2022 ++prefix;
2023 else
2024 while (*name == '/')
2025 ++name;
2028 switch (stbuf.st_mode & S_IFMT) {
2029 case S_IFDIR:
2030 stbuf.st_size = (off_t)0;
2031 blocks = TBLOCKS(stbuf.st_size);
2033 if (filetype != XATTR_FILE && Hiddendir == 0) {
2034 i = 0;
2035 cp = buf;
2036 while ((*cp++ = longname[i++]))
2038 *--cp = '/';
2039 *++cp = 0;
2041 if (!oflag) {
2042 tomodes(&stbuf);
2043 if (build_dblock(name, tchar, '5', filetype,
2044 &stbuf, stbuf.st_dev, prefix) != 0) {
2045 goto out;
2047 if (!Pflag) {
2049 * Old archives require a slash at the end
2050 * of a directory name.
2052 * XXX
2053 * If directory name is too long, will
2054 * slash overfill field?
2056 if (strlen(name) > (unsigned)NAMSIZ-1) {
2057 (void) fprintf(stderr, gettext(
2058 "tar: %s: filename is greater "
2059 "than %d\n"), name, NAMSIZ);
2060 if (errflag)
2061 exitflag = 1;
2062 Errflg = 1;
2063 goto out;
2064 } else {
2065 if (strlen(name) == (NAMSIZ - 1)) {
2066 (void) memcpy(dblock.dbuf.name,
2067 name, NAMSIZ);
2068 dblock.dbuf.name[NAMSIZ-1]
2069 = '/';
2070 } else
2071 (void) sprintf(dblock.dbuf.name,
2072 "%s/", name);
2075 * need to recalculate checksum
2076 * because the name changed.
2078 (void) sprintf(dblock.dbuf.chksum,
2079 "%07o", checksum(&dblock));
2083 if (put_extra_attributes(longname, shortname,
2084 longattrname, prefix, filetype, '5') != 0)
2085 goto out;
2087 #if defined(O_XATTR)
2089 * Reset header typeflag when archiving directory, since
2090 * build_dblock changed it on us.
2092 if (filetype == XATTR_FILE) {
2093 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2094 } else {
2095 dblock.dbuf.typeflag = '5';
2097 #else
2098 dblock.dbuf.typeflag = '5';
2099 #endif
2101 (void) sprintf(dblock.dbuf.chksum, "%07o",
2102 checksum(&dblock));
2104 (void) writetbuf((char *)&dblock, 1);
2106 if (vflag) {
2107 if (NotTape) {
2108 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2110 if (filetype == XATTR_FILE && Hiddendir) {
2111 (void) fprintf(vfile,
2112 gettext("a %s attribute %s "),
2113 longname, longattrname);
2115 } else {
2116 (void) fprintf(vfile, "a %s/ ", longname);
2118 if (NotTape) {
2119 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2120 K(blocks));
2121 } else {
2122 (void) fprintf(vfile, gettext("%" FMT_blkcnt_t
2123 " tape blocks\n"), blocks);
2128 * If hidden dir then break now since xattrs_put() will do
2129 * the iterating of the directory.
2131 * At the moment, there can only be system attributes on
2132 * attributes. There can be no attributes on attributes or
2133 * directories within the attributes hidden directory hierarchy.
2135 if (filetype == XATTR_FILE)
2136 break;
2138 if (*shortname != '/')
2139 (void) sprintf(newparent, "%s/%s", parent, shortname);
2140 else
2141 (void) sprintf(newparent, "%s", shortname);
2143 if (tar_chdir(shortname) < 0) {
2144 vperror(0, "%s", newparent);
2145 goto out;
2148 if ((dirp = opendir(".")) == NULL) {
2149 vperror(0, gettext(
2150 "can't open directory %s"), longname);
2151 if (tar_chdir(parent) < 0)
2152 vperror(0, gettext("cannot change back?: %s"),
2153 parent);
2154 goto out;
2158 * Create a list of files (children) in this directory to avoid
2159 * having to perform telldir()/seekdir().
2161 while ((dp = readdir(dirp)) != NULL && !term) {
2162 if ((strcmp(".", dp->d_name) == 0) ||
2163 (strcmp("..", dp->d_name) == 0))
2164 continue;
2165 if (((cptr = (file_list_t *)calloc(sizeof (char),
2166 sizeof (file_list_t))) == NULL) ||
2167 ((cptr->name = strdup(dp->d_name)) == NULL)) {
2168 vperror(1, gettext(
2169 "Insufficient memory for directory "
2170 "list entry %s/%s\n"),
2171 newparent, dp->d_name);
2174 /* Add the file to the list */
2175 if (child == NULL) {
2176 child = cptr;
2177 } else {
2178 child_end->next = cptr;
2180 child_end = cptr;
2182 (void) closedir(dirp);
2185 * Archive each of the files in the current directory.
2186 * If a file is a directory, putfile() is called
2187 * recursively to archive the file hierarchy of the
2188 * directory before archiving the next file in the
2189 * current directory.
2191 while ((child != NULL) && !term) {
2192 (void) strcpy(cp, child->name);
2193 archtype = putfile(buf, cp, newparent, NULL,
2194 NORMAL_FILE, lev + 1, symlink_lev);
2196 if (!exitflag) {
2197 if ((atflag || saflag) &&
2198 (archtype == PUT_NOTAS_LINK)) {
2199 xattrs_put(buf, cp, newparent, NULL);
2202 if (exitflag)
2203 break;
2205 /* Free each child as we are done processing it. */
2206 cptr = child;
2207 child = child->next;
2208 free(cptr->name);
2209 free(cptr);
2211 if ((child != NULL) && !term) {
2212 free_children(child);
2215 if (tar_chdir(parent) < 0) {
2216 vperror(0, gettext("cannot change back?: %s"), parent);
2219 break;
2221 case S_IFLNK:
2222 readlink_max = NAMSIZ;
2223 if (stbuf.st_size > NAMSIZ) {
2224 if (Eflag > 0) {
2225 xhdr_flgs |= _X_LINKPATH;
2226 readlink_max = PATH_MAX;
2227 } else {
2228 (void) fprintf(stderr, gettext(
2229 "tar: %s: symbolic link too long\n"),
2230 longname);
2231 if (errflag)
2232 exitflag = 1;
2233 Errflg = 1;
2234 goto out;
2238 * Sym-links need header size of zero since you
2239 * don't store any data for this type.
2241 stbuf.st_size = (off_t)0;
2242 tomodes(&stbuf);
2243 i = readlink(shortname, filetmp, readlink_max);
2244 if (i < 0) {
2245 vperror(0, gettext(
2246 "can't read symbolic link %s"), longname);
2247 goto out;
2248 } else {
2249 filetmp[i] = 0;
2251 if (vflag)
2252 (void) fprintf(vfile, gettext(
2253 "a %s symbolic link to %s\n"),
2254 longname, filetmp);
2255 if (xhdr_flgs & _X_LINKPATH) {
2256 Xtarhdr.x_linkpath = filetmp;
2257 if (build_dblock(name, tchar, '2', filetype, &stbuf,
2258 stbuf.st_dev, prefix) != 0)
2259 goto out;
2260 } else
2261 if (build_dblock(name, filetmp, '2', filetype, &stbuf,
2262 stbuf.st_dev, prefix) != 0)
2263 goto out;
2264 (void) writetbuf((char *)&dblock, 1);
2266 * No acls for symlinks: mode is always 777
2267 * dont call write ancillary
2269 rc = PUT_AS_LINK;
2270 break;
2271 case S_IFREG:
2272 if ((infile = openat(dirfd, shortname, 0)) < 0) {
2273 vperror(0, gettext("unable to open %s%s%s%s"), longname,
2274 rw_sysattr ? gettext(" system") : "",
2275 (filetype == XATTR_FILE) ?
2276 gettext(" attribute ") : "",
2277 (filetype == XATTR_FILE) ? (longattrname == NULL) ?
2278 shortname : longattrname : "");
2279 goto out;
2282 blocks = TBLOCKS(stbuf.st_size);
2284 if (put_link(name, longname, shortname, longattrname,
2285 prefix, filetype, '1') == 0) {
2286 (void) close(infile);
2287 rc = PUT_AS_LINK;
2288 goto out;
2291 tomodes(&stbuf);
2293 /* correctly handle end of volume */
2294 while (mulvol && tapepos + blocks + 1 > blocklim) {
2295 /* split if floppy has some room and file is large */
2296 if (((blocklim - tapepos) >= EXTMIN) &&
2297 ((blocks + 1) >= blocklim/10)) {
2298 splitfile(longname, infile,
2299 name, prefix, filetype);
2300 (void) close(dirfd);
2301 (void) close(infile);
2302 goto out;
2304 newvol(); /* not worth it--just get new volume */
2306 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2307 blocks);
2308 if (build_dblock(name, tchar, '0', filetype,
2309 &stbuf, stbuf.st_dev, prefix) != 0) {
2310 goto out;
2312 if (vflag) {
2313 if (NotTape) {
2314 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2316 (void) fprintf(vfile, "a %s%s%s%s ", longname,
2317 rw_sysattr ? gettext(" system") : "",
2318 (filetype == XATTR_FILE) ? gettext(
2319 " attribute ") : "",
2320 (filetype == XATTR_FILE) ?
2321 longattrname : "");
2322 if (NotTape)
2323 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2324 K(blocks));
2325 else
2326 (void) fprintf(vfile,
2327 gettext("%" FMT_blkcnt_t " tape blocks\n"),
2328 blocks);
2331 if (put_extra_attributes(longname, shortname, longattrname,
2332 prefix, filetype, '0') != 0)
2333 goto out;
2336 * No need to reset typeflag for extended attribute here, since
2337 * put_extra_attributes already set it and we haven't called
2338 * build_dblock().
2340 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2341 hint = writetbuf((char *)&dblock, 1);
2342 maxread = max(min(stbuf.st_blksize, stbuf.st_size),
2343 (nblock * TBLOCK));
2344 if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
2345 maxread = TBLOCK;
2346 bigbuf = buf;
2349 while (((i = (int)
2350 read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
2351 blocks) {
2352 blkcnt_t nblks;
2354 nblks = ((i-1)/TBLOCK)+1;
2355 if (nblks > blocks)
2356 nblks = blocks;
2357 hint = writetbuf(bigbuf, nblks);
2358 blocks -= nblks;
2360 (void) close(infile);
2361 if (bigbuf != buf)
2362 free(bigbuf);
2363 if (i < 0)
2364 vperror(0, gettext("Read error on %s"), longname);
2365 else if (blocks != 0 || i != 0) {
2366 (void) fprintf(stderr, gettext(
2367 "tar: %s: file changed size\n"), longname);
2368 if (errflag) {
2369 exitflag = 1;
2370 Errflg = 1;
2371 } else if (!Dflag) {
2372 Errflg = 1;
2375 putempty(blocks);
2376 break;
2377 case S_IFIFO:
2378 blocks = TBLOCKS(stbuf.st_size);
2379 stbuf.st_size = (off_t)0;
2381 if (put_link(name, longname, shortname, longattrname,
2382 prefix, filetype, '6') == 0) {
2383 rc = PUT_AS_LINK;
2384 goto out;
2386 tomodes(&stbuf);
2388 while (mulvol && tapepos + blocks + 1 > blocklim) {
2389 if (((blocklim - tapepos) >= EXTMIN) &&
2390 ((blocks + 1) >= blocklim/10)) {
2391 splitfile(longname, infile, name,
2392 prefix, filetype);
2393 (void) close(dirfd);
2394 (void) close(infile);
2395 goto out;
2397 newvol();
2399 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2400 blocks);
2401 if (vflag) {
2402 if (NotTape) {
2403 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2405 (void) fprintf(vfile, gettext("a %s %"
2406 FMT_blkcnt_t "K\n "), longname, K(blocks));
2407 } else {
2408 (void) fprintf(vfile, gettext(
2409 "a %s %" FMT_blkcnt_t " tape blocks\n"),
2410 longname, blocks);
2413 if (build_dblock(name, tchar, '6', filetype,
2414 &stbuf, stbuf.st_dev, prefix) != 0)
2415 goto out;
2417 if (put_extra_attributes(longname, shortname, longattrname,
2418 prefix, filetype, '6') != 0)
2419 goto out;
2421 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2422 dblock.dbuf.typeflag = '6';
2424 (void) writetbuf((char *)&dblock, 1);
2425 break;
2426 case S_IFCHR:
2427 stbuf.st_size = (off_t)0;
2428 blocks = TBLOCKS(stbuf.st_size);
2429 if (put_link(name, longname, shortname, longattrname,
2430 prefix, filetype, '3') == 0) {
2431 rc = PUT_AS_LINK;
2432 goto out;
2434 tomodes(&stbuf);
2436 while (mulvol && tapepos + blocks + 1 > blocklim) {
2437 if (((blocklim - tapepos) >= EXTMIN) &&
2438 ((blocks + 1) >= blocklim/10)) {
2439 splitfile(longname, infile, name,
2440 prefix, filetype);
2441 (void) close(dirfd);
2442 goto out;
2444 newvol();
2446 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2447 blocks);
2448 if (vflag) {
2449 if (NotTape) {
2450 dlog("seek = %" FMT_blkcnt_t "K\t", K(tapepos));
2452 (void) fprintf(vfile, gettext("a %s %"
2453 FMT_blkcnt_t "K\n"), longname, K(blocks));
2454 } else {
2455 (void) fprintf(vfile, gettext("a %s %"
2456 FMT_blkcnt_t " tape blocks\n"), longname,
2457 blocks);
2460 if (build_dblock(name, tchar, '3',
2461 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2462 goto out;
2464 if (put_extra_attributes(longname, shortname, longattrname,
2465 prefix, filetype, '3') != 0)
2466 goto out;
2468 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2469 dblock.dbuf.typeflag = '3';
2471 (void) writetbuf((char *)&dblock, 1);
2472 break;
2473 case S_IFBLK:
2474 stbuf.st_size = (off_t)0;
2475 blocks = TBLOCKS(stbuf.st_size);
2476 if (put_link(name, longname, shortname, longattrname,
2477 prefix, filetype, '4') == 0) {
2478 rc = PUT_AS_LINK;
2479 goto out;
2481 tomodes(&stbuf);
2483 while (mulvol && tapepos + blocks + 1 > blocklim) {
2484 if (((blocklim - tapepos) >= EXTMIN) &&
2485 ((blocks + 1) >= blocklim/10)) {
2486 splitfile(longname, infile,
2487 name, prefix, filetype);
2488 (void) close(dirfd);
2489 goto out;
2491 newvol();
2493 dlog("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2494 blocks);
2495 if (vflag) {
2496 if (NotTape) {
2497 dlog("seek = %" FMT_blkcnt_t "K\n", K(tapepos));
2500 (void) fprintf(vfile, "a %s ", longname);
2501 if (NotTape)
2502 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2503 K(blocks));
2504 else
2505 (void) fprintf(vfile, gettext("%"
2506 FMT_blkcnt_t " tape blocks\n"), blocks);
2508 if (build_dblock(name, tchar, '4',
2509 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2510 goto out;
2512 if (put_extra_attributes(longname, shortname, longattrname,
2513 prefix, filetype, '4') != 0)
2514 goto out;
2516 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2517 dblock.dbuf.typeflag = '4';
2519 (void) writetbuf((char *)&dblock, 1);
2520 break;
2521 default:
2522 (void) fprintf(stderr, gettext(
2523 "tar: %s is not a file. Not dumped\n"), longname);
2524 if (errflag)
2525 exitflag = 1;
2526 Errflg = 1;
2527 goto out;
2530 out:
2531 if ((dirfd != -1) && (filetype != XATTR_FILE)) {
2532 (void) close(dirfd);
2534 return (rc);
2539 * splitfile dump a large file across volumes
2541 * splitfile(longname, fd);
2542 * char *longname; full name of file
2543 * int ifd; input file descriptor
2545 * NOTE: only called by putfile() to dump a large file.
2548 static void
2549 splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
2551 blkcnt_t blocks;
2552 off_t bytes, s;
2553 char buf[TBLOCK];
2554 int i, extents;
2556 blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */
2559 * # extents =
2560 * size of file after using up rest of this floppy
2561 * blocks - (blocklim - tapepos) + 1 (for header)
2562 * plus roundup value before divide by blocklim-1
2563 * + (blocklim - 1) - 1
2564 * all divided by blocklim-1 (one block for each header).
2565 * this gives
2566 * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2567 * which reduces to the expression used.
2568 * one is added to account for this first extent.
2570 * When one is dealing with extremely large archives, one may want
2571 * to allow for a large number of extents. This code should be
2572 * revisited to determine if extents should be changed to something
2573 * larger than an int.
2575 extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
2577 if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */
2578 (void) fprintf(stderr, gettext(
2579 "tar: %s needs unusual number of volumes to split\n"
2580 "tar: %s not dumped\n"), longname, longname);
2581 return;
2583 if (build_dblock(name, tchar, '0', filetype,
2584 &stbuf, stbuf.st_dev, prefix) != 0)
2585 return;
2587 dblock.dbuf.extotal = extents;
2588 bytes = stbuf.st_size;
2591 * The value contained in dblock.dbuf.efsize was formerly used when the
2592 * v flag was specified in conjunction with the t flag. Although it is
2593 * no longer used, older versions of tar will expect the former
2594 * behaviour, so we must continue to write it to the archive.
2596 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2597 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2598 * store 0.
2600 if (bytes <= TAR_EFSIZE_MAX)
2601 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
2602 else
2603 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
2605 (void) fprintf(stderr, gettext(
2606 "tar: large file %s needs %d extents.\n"
2607 "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
2608 longname, extents, K(tapepos));
2610 s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
2611 for (i = 1; i <= extents; i++) {
2612 if (i > 1) {
2613 newvol();
2614 if (i == extents)
2615 s = bytes; /* last ext. gets true bytes */
2616 else
2617 s = (off_t)(blocklim - 1)*TBLOCK; /* all */
2619 bytes -= s;
2620 blocks = TBLOCKS(s);
2622 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
2623 dblock.dbuf.extno = i;
2624 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2625 (void) writetbuf((char *)&dblock, 1);
2627 if (vflag)
2628 (void) fprintf(vfile,
2629 gettext("+++ a %s %" FMT_blkcnt_t
2630 "K [extent #%d of %d]\n"),
2631 longname, K(blocks), i, extents);
2632 while (blocks && read(ifd, buf, TBLOCK) > 0) {
2633 blocks--;
2634 (void) writetbuf(buf, 1);
2636 if (blocks != 0) {
2637 (void) fprintf(stderr, gettext(
2638 "tar: %s: file changed size\n"), longname);
2639 (void) fprintf(stderr, gettext(
2640 "tar: aborting split file %s\n"), longname);
2641 (void) close(ifd);
2642 return;
2645 (void) close(ifd);
2646 if (vflag)
2647 (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
2648 "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
2649 extents);
2653 * convtoreg - determines whether the file should be converted to a
2654 * regular file when extracted
2656 * Returns 1 when file size > 0 and typeflag is not recognized
2657 * Otherwise returns 0
2659 static int
2660 convtoreg(off_t size)
2662 if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
2663 (dblock.dbuf.typeflag != '\0') && (dblock.dbuf.typeflag != '1') &&
2664 (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
2665 (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
2666 (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
2667 (dblock.dbuf.typeflag != 'L') &&
2668 (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
2669 (dblock.dbuf.typeflag != 'X')) {
2670 return (1);
2672 return (0);
2675 #if defined(O_XATTR)
2676 static int
2677 save_cwd(void)
2679 return (open(".", O_RDONLY));
2681 #endif
2683 #if defined(O_XATTR)
2684 static void
2685 rest_cwd(int *cwd)
2687 if (*cwd != -1) {
2688 if (fchdir(*cwd) < 0) {
2689 vperror(0, gettext(
2690 "Cannot fchdir to attribute directory"));
2691 exit(1);
2693 (void) close(*cwd);
2694 *cwd = -1;
2697 #endif
2700 * Verify the underlying file system supports the attribute type.
2701 * Only archive extended attribute files when '-@' was specified.
2702 * Only archive system extended attribute files if '-/' was specified.
2704 #if defined(O_XATTR)
2705 static attr_status_t
2706 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
2707 int *ext_attrflg)
2710 * Verify extended attributes are supported/exist. We only
2711 * need to check if we are processing a base file, not an
2712 * extended attribute.
2714 if (attrflg) {
2715 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
2716 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
2719 if (atflag) {
2720 if (!*ext_attrflg) {
2721 #if defined(_PC_SATTR_ENABLED)
2722 if (saflag) {
2723 /* Verify system attributes are supported */
2724 if (sysattr_support(filename,
2725 (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
2726 _PC_SATTR_ENABLED) != 1) {
2727 return (ATTR_SATTR_ERR);
2729 } else
2730 return (ATTR_XATTR_ERR);
2731 #else
2732 return (ATTR_XATTR_ERR);
2733 #endif /* _PC_SATTR_ENABLED */
2736 #if defined(_PC_SATTR_ENABLED)
2737 } else if (saflag) {
2738 /* Verify system attributes are supported */
2739 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
2740 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
2741 return (ATTR_SATTR_ERR);
2743 #endif /* _PC_SATTR_ENABLED */
2744 } else {
2745 return (ATTR_SKIP);
2748 return (ATTR_OK);
2750 #endif
2752 #if defined(O_XATTR)
2754 * Recursively open attribute directories until the attribute directory
2755 * containing the specified attribute, attrname, is opened.
2757 * Currently, only 2 directory levels of attributes are supported, (i.e.,
2758 * extended system attributes on extended attributes). The following are
2759 * the possible input combinations:
2760 * 1. Open the attribute directory of the base file (don't change
2761 * into it).
2762 * attrinfo->parent = NULL
2763 * attrname = '.'
2764 * 2. Open the attribute directory of the base file and change into it.
2765 * attrinfo->parent = NULL
2766 * attrname = <attr> | <sys_attr>
2767 * 3. Open the attribute directory of the base file, change into it,
2768 * then recursively call open_attr_dir() to open the attribute's
2769 * parent directory (don't change into it).
2770 * attrinfo->parent = <attr>
2771 * attrname = '.'
2772 * 4. Open the attribute directory of the base file, change into it,
2773 * then recursively call open_attr_dir() to open the attribute's
2774 * parent directory and change into it.
2775 * attrinfo->parent = <attr>
2776 * attrname = <attr> | <sys_attr>
2778 * An attribute directory will be opened only if the underlying file system
2779 * supports the attribute type, and if the command line specifications (atflag
2780 * and saflag) enable the processing of the attribute type.
2782 * On succesful return, attrinfo->parentfd will be the file descriptor of the
2783 * opened attribute directory. In addition, if the attribute is a read-write
2784 * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2785 * it will be set to 0.
2787 * Possible return values:
2788 * ATTR_OK Successfully opened and, if needed, changed into the
2789 * attribute directory containing attrname.
2790 * ATTR_SKIP The command line specifications don't enable the
2791 * processing of the attribute type.
2792 * ATTR_CHDIR_ERR An error occurred while trying to change into an
2793 * attribute directory.
2794 * ATTR_OPEN_ERR An error occurred while trying to open an
2795 * attribute directory.
2796 * ATTR_XATTR_ERR The underlying file system doesn't support extended
2797 * attributes.
2798 * ATTR_SATTR_ERR The underlying file system doesn't support extended
2799 * system attributes.
2801 static int
2802 open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
2804 attr_status_t rc;
2805 int firsttime = (attrinfo->attr_parentfd == -1);
2806 int saveerrno;
2807 int ext_attr;
2810 * open_attr_dir() was recursively called (input combination number 4),
2811 * close the previously opened file descriptor as we've already changed
2812 * into it.
2814 if (!firsttime) {
2815 (void) close(attrinfo->attr_parentfd);
2816 attrinfo->attr_parentfd = -1;
2820 * Verify that the underlying file system supports the restoration
2821 * of the attribute.
2823 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
2824 &ext_attr)) != ATTR_OK) {
2825 return (rc);
2828 /* Open the base file's attribute directory */
2829 if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
2831 * Save the errno from the attropen so it can be reported
2832 * if the retry of the attropen fails.
2834 saveerrno = errno;
2835 if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
2836 NULL, ".", O_RDONLY, 0)) == -1) {
2838 * Reset typeflag back to real value so passtape
2839 * will skip ahead correctly.
2841 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2842 (void) close(attrinfo->attr_parentfd);
2843 attrinfo->attr_parentfd = -1;
2844 errno = saveerrno;
2845 return (ATTR_OPEN_ERR);
2850 * Change into the parent attribute's directory unless we are
2851 * processing the hidden attribute directory of the base file itself.
2853 if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
2854 if (fchdir(attrinfo->attr_parentfd) != 0) {
2855 saveerrno = errno;
2856 (void) close(attrinfo->attr_parentfd);
2857 attrinfo->attr_parentfd = -1;
2858 errno = saveerrno;
2859 return (ATTR_CHDIR_ERR);
2863 /* Determine if the attribute should be processed */
2864 if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
2865 &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
2866 saveerrno = errno;
2867 (void) close(attrinfo->attr_parentfd);
2868 attrinfo->attr_parentfd = -1;
2869 errno = saveerrno;
2870 return (rc);
2874 * If the attribute is an extended attribute, or extended system
2875 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2876 * recursively call open_attr_dir() to open the attribute directory
2877 * of the parent attribute.
2879 if (firsttime && (attrinfo->attr_parent != NULL)) {
2880 return (open_attr_dir(attrname, attrinfo->attr_parent,
2881 attrinfo->attr_parentfd, attrinfo));
2884 return (ATTR_OK);
2886 #endif
2888 static void
2889 doxtract(char *argv[])
2891 struct stat xtractbuf; /* stat on file after extracting */
2892 blkcnt_t blocks;
2893 off_t bytes;
2894 int ofile;
2895 int newfile; /* Does the file already exist */
2896 int xcnt = 0; /* count # files extracted */
2897 int fcnt = 0; /* count # files in argv list */
2898 int dir;
2899 int dirfd = -1;
2900 int cwd = -1;
2901 int rw_sysattr;
2902 int saveerrno;
2903 uid_t Uid;
2904 char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
2905 char dirname[PATH_MAX+1];
2906 char templink[PATH_MAX+1]; /* temp link with terminating NULL */
2907 int once = 1;
2908 int error;
2909 int symflag;
2910 int want;
2911 attr_data_t *attrinfo = NULL; /* attribute info */
2912 acl_t *aclp = NULL; /* acl info */
2913 timestruc_t time_zero; /* used for call to doDirTimes */
2914 int dircreate;
2915 int convflag;
2916 time_zero.tv_sec = 0;
2917 time_zero.tv_nsec = 0;
2919 dumping = 0; /* for newvol(), et al: we are not writing */
2921 Uid = getuid();
2923 for (;;) {
2924 convflag = 0;
2925 symflag = 0;
2926 dir = 0;
2927 Hiddendir = 0;
2928 rw_sysattr = 0;
2929 ofile = -1;
2931 if (dirfd != -1) {
2932 (void) close(dirfd);
2933 dirfd = -1;
2935 if (ofile != -1) {
2936 if (close(ofile) != 0)
2937 vperror(2, gettext("close error"));
2940 #if defined(O_XATTR)
2941 if (cwd != -1) {
2942 rest_cwd(&cwd);
2944 #endif
2946 /* namep is set by wantit to point to the full name */
2947 if ((want = wantit(argv, &namep, &dirp, &comp,
2948 &attrinfo)) == 0) {
2949 #if defined(O_XATTR)
2950 if (xattrp != NULL) {
2951 free(xattrhead);
2952 xattrp = NULL;
2953 xattr_linkp = NULL;
2954 xattrhead = NULL;
2956 #endif
2957 continue;
2959 if (want == -1)
2960 break;
2962 if (dirfd != -1)
2963 (void) close(dirfd);
2965 (void) strcpy(&dirname[0], namep);
2966 dircreate = checkdir(&dirname[0]);
2968 #if defined(O_XATTR)
2969 if (xattrp != NULL) {
2970 int rc;
2972 if (((cwd = save_cwd()) == -1) ||
2973 ((rc = open_attr_dir(comp, dirp, cwd,
2974 attrinfo)) != ATTR_OK)) {
2975 if (cwd == -1) {
2976 vperror(0, gettext(
2977 "unable to save current working "
2978 "directory while processing "
2979 "attribute %s of %s"),
2980 dirp, attrinfo->attr_path);
2981 } else if (rc != ATTR_SKIP) {
2982 (void) fprintf(vfile,
2983 gettext("tar: cannot open "
2984 "%sattribute %s of file %s: %s\n"),
2985 attrinfo->attr_rw_sysattr ? gettext(
2986 "system ") : "",
2987 comp, dirp, strerror(errno));
2989 free(xattrhead);
2990 xattrp = NULL;
2991 xattr_linkp = NULL;
2992 xattrhead = NULL;
2994 passtape();
2995 continue;
2996 } else {
2997 dirfd = attrinfo->attr_parentfd;
2998 rw_sysattr = attrinfo->attr_rw_sysattr;
3000 } else {
3001 dirfd = open(dirp, O_RDONLY);
3003 #else
3004 dirfd = open(dirp, O_RDONLY);
3005 #endif
3006 if (dirfd == -1) {
3007 (void) fprintf(vfile, gettext(
3008 "tar: cannot open %s: %s\n"),
3009 dirp, strerror(errno));
3010 passtape();
3011 continue;
3014 if (xhdr_flgs & _X_LINKPATH)
3015 (void) strcpy(templink, Xtarhdr.x_linkpath);
3016 else {
3017 #if defined(O_XATTR)
3018 if (xattrp && dblock.dbuf.typeflag == '1') {
3019 (void) sprintf(templink, "%.*s", NAMSIZ,
3020 xattrp->h_names);
3021 } else {
3022 (void) sprintf(templink, "%.*s", NAMSIZ,
3023 dblock.dbuf.linkname);
3025 #else
3026 (void) sprintf(templink, "%.*s", NAMSIZ,
3027 dblock.dbuf.linkname);
3028 #endif
3031 if (Fflag) {
3032 if (checkf(namep, is_directory(namep), Fflag) == 0) {
3033 passtape();
3034 continue;
3038 if (checkw('x', namep) == 0) {
3039 passtape();
3040 continue;
3042 if (once) {
3043 if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
3044 if (geteuid() == (uid_t)0) {
3045 checkflag = 1;
3046 pflag = 1;
3047 } else {
3048 /* get file creation mask */
3049 Oumask = umask(0);
3050 (void) umask(Oumask);
3052 once = 0;
3053 } else {
3054 if (geteuid() == (uid_t)0) {
3055 pflag = 1;
3056 checkflag = 2;
3058 if (!pflag) {
3059 /* get file creation mask */
3060 Oumask = umask(0);
3061 (void) umask(Oumask);
3063 once = 0;
3067 #if defined(O_XATTR)
3069 * Handle extraction of hidden attr dir.
3070 * Dir is automatically created, we only
3071 * need to update mode and perm's.
3073 if ((xattrp != NULL) && Hiddendir == 1) {
3074 bytes = stbuf.st_size;
3075 blocks = TBLOCKS(bytes);
3076 if (vflag) {
3077 (void) fprintf(vfile,
3078 "x %s%s%s, %" FMT_off_t " %s, ", namep,
3079 gettext(" attribute "),
3080 xattrapath, bytes,
3081 gettext("bytes"));
3082 if (NotTape)
3083 (void) fprintf(vfile,
3084 "%" FMT_blkcnt_t "K\n", K(blocks));
3085 else
3086 (void) fprintf(vfile, gettext("%"
3087 FMT_blkcnt_t " tape blocks\n"),
3088 blocks);
3092 * Set the permissions and mode of the attribute
3093 * unless the attribute is a system attribute (can't
3094 * successfully do this) or the hidden attribute
3095 * directory (".") of an attribute (when the attribute
3096 * is restored, the hidden attribute directory of an
3097 * attribute is transient). Note: when the permissions
3098 * and mode are set for the hidden attribute directory
3099 * of a file on a system supporting extended system
3100 * attributes, even though it returns successfully, it
3101 * will not have any affect since the attribute
3102 * directory is transient.
3104 if (attrinfo->attr_parent == NULL) {
3105 if (fchownat(dirfd, ".", stbuf.st_uid,
3106 stbuf.st_gid, 0) != 0) {
3107 vperror(0, gettext(
3108 "%s%s%s: failed to set ownership "
3109 "of attribute directory"), namep,
3110 gettext(" attribute "), xattrapath);
3113 if (fchmod(dirfd, stbuf.st_mode) != 0) {
3114 vperror(0, gettext(
3115 "%s%s%s: failed to set permissions "
3116 "of attribute directory"), namep,
3117 gettext(" attribute "), xattrapath);
3120 goto filedone;
3122 #endif
3124 if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
3125 dir = 1;
3126 if (vflag) {
3127 (void) fprintf(vfile, "x %s, 0 %s, ",
3128 &dirname[0], gettext("bytes"));
3129 if (NotTape)
3130 (void) fprintf(vfile, "0K\n");
3131 else
3132 (void) fprintf(vfile, gettext("%"
3133 FMT_blkcnt_t " tape blocks\n"),
3134 (blkcnt_t)0);
3136 goto filedone;
3139 if (dblock.dbuf.typeflag == '6') { /* FIFO */
3140 if (rmdir(namep) < 0) {
3141 if (errno == ENOTDIR)
3142 (void) unlink(namep);
3144 linkp = templink;
3145 if (*linkp != '\0') {
3146 if (Aflag && *linkp == '/')
3147 linkp++;
3148 if (link(linkp, namep) < 0) {
3149 (void) fprintf(stderr, gettext(
3150 "tar: %s: cannot link\n"), namep);
3151 continue;
3153 if (vflag)
3154 (void) fprintf(vfile, gettext(
3155 "x %s linked to %s\n"), namep,
3156 linkp);
3157 xcnt++; /* increment # files extracted */
3158 continue;
3160 if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
3161 (int)Gen.g_devmajor) < 0) {
3162 vperror(0, gettext("%s: mknod failed"), namep);
3163 continue;
3165 bytes = stbuf.st_size;
3166 blocks = TBLOCKS(bytes);
3167 if (vflag) {
3168 (void) fprintf(vfile, "x %s, %" FMT_off_t
3169 " %s, ", namep, bytes, gettext("bytes"));
3170 if (NotTape)
3171 (void) fprintf(vfile, "%" FMT_blkcnt_t
3172 "K\n", K(blocks));
3173 else
3174 (void) fprintf(vfile, gettext("%"
3175 FMT_blkcnt_t " tape blocks\n"),
3176 blocks);
3178 goto filedone;
3180 if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
3181 if (rmdir(namep) < 0) {
3182 if (errno == ENOTDIR)
3183 (void) unlink(namep);
3185 linkp = templink;
3186 if (*linkp != '\0') {
3187 if (Aflag && *linkp == '/')
3188 linkp++;
3189 if (link(linkp, namep) < 0) {
3190 (void) fprintf(stderr, gettext(
3191 "tar: %s: cannot link\n"), namep);
3192 continue;
3194 if (vflag)
3195 (void) fprintf(vfile, gettext(
3196 "x %s linked to %s\n"), namep,
3197 linkp);
3198 xcnt++; /* increment # files extracted */
3199 continue;
3201 if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
3202 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3203 vperror(0, gettext(
3204 "%s: mknod failed"), namep);
3205 continue;
3207 bytes = stbuf.st_size;
3208 blocks = TBLOCKS(bytes);
3209 if (vflag) {
3210 (void) fprintf(vfile, "x %s, %" FMT_off_t
3211 " %s, ", namep, bytes, gettext("bytes"));
3212 if (NotTape)
3213 (void) fprintf(vfile, "%" FMT_blkcnt_t
3214 "K\n", K(blocks));
3215 else
3216 (void) fprintf(vfile, gettext("%"
3217 FMT_blkcnt_t " tape blocks\n"),
3218 blocks);
3220 goto filedone;
3221 } else if (dblock.dbuf.typeflag == '3' && Uid) {
3222 (void) fprintf(stderr, gettext(
3223 "Can't create special %s\n"), namep);
3224 continue;
3227 /* BLOCK SPECIAL */
3229 if (dblock.dbuf.typeflag == '4' && !Uid) {
3230 if (rmdir(namep) < 0) {
3231 if (errno == ENOTDIR)
3232 (void) unlink(namep);
3234 linkp = templink;
3235 if (*linkp != '\0') {
3236 if (Aflag && *linkp == '/')
3237 linkp++;
3238 if (link(linkp, namep) < 0) {
3239 (void) fprintf(stderr, gettext(
3240 "tar: %s: cannot link\n"), namep);
3241 continue;
3243 if (vflag)
3244 (void) fprintf(vfile, gettext(
3245 "x %s linked to %s\n"), namep,
3246 linkp);
3247 xcnt++; /* increment # files extracted */
3248 continue;
3250 if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
3251 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3252 vperror(0, gettext("%s: mknod failed"), namep);
3253 continue;
3255 bytes = stbuf.st_size;
3256 blocks = TBLOCKS(bytes);
3257 if (vflag) {
3258 (void) fprintf(vfile, gettext("x %s, %"
3259 FMT_off_t " bytes, "), namep, bytes);
3260 if (NotTape)
3261 (void) fprintf(vfile, "%" FMT_blkcnt_t
3262 "K\n", K(blocks));
3263 else
3264 (void) fprintf(vfile, gettext("%"
3265 FMT_blkcnt_t " tape blocks\n"),
3266 blocks);
3268 goto filedone;
3269 } else if (dblock.dbuf.typeflag == '4' && Uid) {
3270 (void) fprintf(stderr,
3271 gettext("Can't create special %s\n"), namep);
3272 continue;
3274 if (dblock.dbuf.typeflag == '2') { /* symlink */
3275 linkp = templink;
3276 if (Aflag && *linkp == '/')
3277 linkp++;
3278 if (rmdir(namep) < 0) {
3279 if (errno == ENOTDIR)
3280 (void) unlink(namep);
3282 if (symlink(linkp, namep) < 0) {
3283 vperror(0, gettext("%s: symbolic link failed"),
3284 namep);
3285 continue;
3287 if (vflag)
3288 (void) fprintf(vfile, gettext(
3289 "x %s symbolic link to %s\n"),
3290 namep, linkp);
3292 symflag = AT_SYMLINK_NOFOLLOW;
3293 goto filedone;
3295 if (dblock.dbuf.typeflag == '1') {
3296 linkp = templink;
3297 if (Aflag && *linkp == '/')
3298 linkp++;
3299 if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
3300 if (errno == ENOTDIR)
3301 (void) unlinkat(dirfd, comp, 0);
3303 #if defined(O_XATTR)
3304 if (xattrp && xattr_linkp) {
3305 if (fchdir(dirfd) < 0) {
3306 vperror(0, gettext(
3307 "Cannot fchdir to attribute "
3308 "directory %s"),
3309 (attrinfo->attr_parent == NULL) ?
3310 dirp : attrinfo->attr_parent);
3311 exit(1);
3314 error = link(xattr_linkaname, xattrapath);
3315 } else {
3316 error = link(linkp, namep);
3318 #else
3319 error = link(linkp, namep);
3320 #endif
3322 if (error < 0) {
3323 (void) fprintf(stderr, gettext(
3324 "tar: %s%s%s: cannot link\n"),
3325 namep, (xattr_linkp != NULL) ?
3326 gettext(" attribute ") : "",
3327 (xattr_linkp != NULL) ?
3328 xattrapath : "");
3329 continue;
3331 if (vflag)
3332 (void) fprintf(vfile, gettext(
3333 "x %s%s%s linked to %s%s%s\n"), namep,
3334 (xattr_linkp != NULL) ?
3335 gettext(" attribute ") : "",
3336 (xattr_linkp != NULL) ?
3337 xattr_linkaname : "",
3338 linkp,
3339 (xattr_linkp != NULL) ?
3340 gettext(" attribute ") : "",
3341 (xattr_linkp != NULL) ? xattrapath : "");
3342 xcnt++; /* increment # files extracted */
3343 #if defined(O_XATTR)
3344 if (xattrp != NULL) {
3345 free(xattrhead);
3346 xattrp = NULL;
3347 xattr_linkp = NULL;
3348 xattrhead = NULL;
3350 #endif
3351 continue;
3354 /* REGULAR FILES */
3356 if (convtoreg(stbuf.st_size)) {
3357 convflag = 1;
3358 if (errflag) {
3359 (void) fprintf(stderr, gettext(
3360 "tar: %s: typeflag '%c' not recognized\n"),
3361 namep, dblock.dbuf.typeflag);
3362 done(1);
3363 } else {
3364 (void) fprintf(stderr, gettext(
3365 "tar: %s: typeflag '%c' not recognized, "
3366 "converting to regular file\n"), namep,
3367 dblock.dbuf.typeflag);
3368 Errflg = 1;
3371 if (dblock.dbuf.typeflag == '0' ||
3372 dblock.dbuf.typeflag == '\0' || convflag) {
3373 delete_target(dirfd, comp, namep);
3374 linkp = templink;
3375 if (*linkp != '\0') {
3376 if (Aflag && *linkp == '/')
3377 linkp++;
3378 if (link(linkp, comp) < 0) {
3379 (void) fprintf(stderr, gettext(
3380 "tar: %s: cannot link\n"), namep);
3381 continue;
3383 if (vflag)
3384 (void) fprintf(vfile, gettext(
3385 "x %s linked to %s\n"), comp,
3386 linkp);
3387 xcnt++; /* increment # files extracted */
3388 #if defined(O_XATTR)
3389 if (xattrp != NULL) {
3390 free(xattrhead);
3391 xattrp = NULL;
3392 xattr_linkp = NULL;
3393 xattrhead = NULL;
3395 #endif
3396 continue;
3398 newfile = ((fstatat(dirfd, comp,
3399 &xtractbuf, 0) == -1) ? TRUE : FALSE);
3400 ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
3401 stbuf.st_mode & MODEMASK);
3402 saveerrno = errno;
3404 #if defined(O_XATTR)
3405 if (xattrp != NULL) {
3406 if (ofile < 0) {
3407 ofile = retry_open_attr(dirfd, cwd,
3408 dirp, attrinfo->attr_parent, comp,
3409 O_RDWR|O_CREAT|O_TRUNC,
3410 stbuf.st_mode & MODEMASK);
3413 #endif
3414 if (ofile < 0) {
3415 errno = saveerrno;
3416 (void) fprintf(stderr, gettext(
3417 "tar: %s%s%s%s - cannot create\n"),
3418 (xattrp == NULL) ? "" : (rw_sysattr ?
3419 gettext("system attribute ") :
3420 gettext("attribute ")),
3421 (xattrp == NULL) ? "" : xattrapath,
3422 (xattrp == NULL) ? "" : gettext(" of "),
3423 (xattrp == NULL) ? comp : namep);
3424 if (errflag)
3425 done(1);
3426 else
3427 Errflg = 1;
3428 #if defined(O_XATTR)
3429 if (xattrp != NULL) {
3430 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
3431 free(xattrhead);
3432 xattrp = NULL;
3433 xattr_linkp = NULL;
3434 xattrhead = NULL;
3436 #endif
3437 passtape();
3438 continue;
3441 if (extno != 0) { /* file is in pieces */
3442 if (extotal < 1 || extotal > MAXEXT)
3443 (void) fprintf(stderr, gettext(
3444 "tar: ignoring bad extent info for "
3445 "%s%s%s%s\n"),
3446 (xattrp == NULL) ? "" : (rw_sysattr ?
3447 gettext("system attribute ") :
3448 gettext("attribute ")),
3449 (xattrp == NULL) ? "" : xattrapath,
3450 (xattrp == NULL) ? "" : gettext(" of "),
3451 (xattrp == NULL) ? comp : namep);
3452 else {
3453 /* extract it */
3454 (void) xsfile(rw_sysattr, ofile);
3457 extno = 0; /* let everyone know file is not split */
3458 bytes = stbuf.st_size;
3459 blocks = TBLOCKS(bytes);
3460 if (vflag) {
3461 (void) fprintf(vfile,
3462 "x %s%s%s, %" FMT_off_t " %s, ",
3463 (xattrp == NULL) ? "" : dirp,
3464 (xattrp == NULL) ? "" : (rw_sysattr ?
3465 gettext(" system attribute ") :
3466 gettext(" attribute ")),
3467 (xattrp == NULL) ? namep : xattrapath, bytes,
3468 gettext("bytes"));
3469 if (NotTape)
3470 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
3471 K(blocks));
3472 else
3473 (void) fprintf(vfile, gettext("%"
3474 FMT_blkcnt_t " tape blocks\n"), blocks);
3477 if (xblocks(rw_sysattr, bytes, ofile) != 0) {
3478 #if defined(O_XATTR)
3479 if (xattrp != NULL) {
3480 free(xattrhead);
3481 xattrp = NULL;
3482 xattr_linkp = NULL;
3483 xattrhead = NULL;
3485 #endif
3486 continue;
3488 filedone:
3489 if (mflag == 0 && !symflag) {
3490 if (dir)
3491 doDirTimes(namep, stbuf.st_mtim);
3493 else
3494 #if defined(O_XATTR)
3495 if (xattrp != NULL) {
3497 * Set the time on the attribute unless
3498 * the attribute is a system attribute
3499 * (can't successfully do this) or the
3500 * hidden attribute directory, "." (the
3501 * time on the hidden attribute
3502 * directory will be updated when
3503 * attributes are restored, otherwise
3504 * it's transient).
3506 if (!rw_sysattr && (Hiddendir == 0)) {
3507 setPathTimes(dirfd, comp,
3508 stbuf.st_mtim);
3510 } else
3511 setPathTimes(dirfd, comp,
3512 stbuf.st_mtim);
3513 #else
3514 setPathTimes(dirfd, comp, stbuf.st_mtim);
3515 #endif
3518 /* moved this code from above */
3519 if (pflag && !symflag && Hiddendir == 0) {
3520 if (xattrp != NULL)
3521 (void) fchmod(ofile, stbuf.st_mode & MODEMASK);
3522 else
3523 (void) chmod(namep, stbuf.st_mode & MODEMASK);
3528 * Because ancillary file preceeds the normal file,
3529 * acl info may have been retrieved (in aclp).
3530 * All file types are directed here (go filedone).
3531 * Always restore ACLs if there are ACLs.
3533 if (aclp != NULL) {
3534 int ret;
3536 #if defined(O_XATTR)
3537 if (xattrp != NULL) {
3538 if (Hiddendir)
3539 ret = facl_set(dirfd, aclp);
3540 else
3541 ret = facl_set(ofile, aclp);
3542 } else {
3543 ret = acl_set(namep, aclp);
3545 #else
3546 ret = acl_set(namep, aclp);
3547 #endif
3548 if (ret < 0) {
3549 if (pflag) {
3550 (void) fprintf(stderr, gettext(
3551 "%s%s%s%s: failed to set acl "
3552 "entries\n"), namep,
3553 (xattrp == NULL) ? "" :
3554 (rw_sysattr ? gettext(
3555 " system attribute ") :
3556 gettext(" attribute ")),
3557 (xattrp == NULL) ? "" :
3558 xattrapath);
3560 /* else: silent and continue */
3562 acl_free(aclp);
3563 aclp = NULL;
3566 if (!oflag)
3567 /* set file ownership */
3568 resugname(dirfd, comp, symflag);
3570 if (pflag && newfile == TRUE && !dir &&
3571 (dblock.dbuf.typeflag == '0' ||
3572 dblock.dbuf.typeflag == '\0' ||
3573 convflag || dblock.dbuf.typeflag == '1')) {
3574 if (fstat(ofile, &xtractbuf) == -1)
3575 (void) fprintf(stderr, gettext(
3576 "tar: cannot stat extracted file "
3577 "%s%s%s%s\n"),
3578 (xattrp == NULL) ? "" : (rw_sysattr ?
3579 gettext("system attribute ") :
3580 gettext("attribute ")),
3581 (xattrp == NULL) ? "" : xattrapath,
3582 (xattrp == NULL) ? "" :
3583 gettext(" of "), namep);
3585 else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
3586 != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
3587 (void) fprintf(stderr, gettext(
3588 "tar: warning - file permissions have "
3589 "changed for %s%s%s%s (are 0%o, should be "
3590 "0%o)\n"),
3591 (xattrp == NULL) ? "" : (rw_sysattr ?
3592 gettext("system attribute ") :
3593 gettext("attribute ")),
3594 (xattrp == NULL) ? "" : xattrapath,
3595 (xattrp == NULL) ? "" :
3596 gettext(" of "), namep,
3597 xtractbuf.st_mode, stbuf.st_mode);
3601 #if defined(O_XATTR)
3602 if (xattrp != NULL) {
3603 free(xattrhead);
3604 xattrp = NULL;
3605 xattr_linkp = NULL;
3606 xattrhead = NULL;
3608 #endif
3610 if (ofile != -1) {
3611 (void) close(dirfd);
3612 dirfd = -1;
3613 if (close(ofile) != 0)
3614 vperror(2, gettext("close error"));
3615 ofile = -1;
3617 xcnt++; /* increment # files extracted */
3621 * Process ancillary file.
3625 if (dblock.dbuf.typeflag == 'A') { /* acl info */
3626 char buf[TBLOCK];
3627 char *secp;
3628 char *tp;
3629 int attrsize;
3630 int cnt;
3632 if (pflag) {
3633 bytes = stbuf.st_size;
3634 if ((secp = malloc((int)bytes)) == NULL) {
3635 (void) fprintf(stderr, gettext(
3636 "Insufficient memory for acl\n"));
3637 passtape();
3638 continue;
3640 tp = secp;
3641 blocks = TBLOCKS(bytes);
3643 while (blocks-- > 0) {
3644 readtape(buf);
3645 if (bytes <= TBLOCK) {
3646 (void) memcpy(tp, buf,
3647 (size_t)bytes);
3648 break;
3649 } else {
3650 (void) memcpy(tp, buf,
3651 TBLOCK);
3652 tp += TBLOCK;
3654 bytes -= TBLOCK;
3656 bytes = stbuf.st_size;
3657 /* got all attributes in secp */
3658 tp = secp;
3659 do {
3660 attr = (struct sec_attr *)tp;
3661 switch (attr->attr_type) {
3662 case UFSD_ACL:
3663 case ACE_ACL:
3664 (void) sscanf(attr->attr_len,
3665 "%7o",
3666 (uint_t *)
3667 &cnt);
3668 /* header is 8 */
3669 attrsize = 8 + (int)strlen(
3670 &attr->attr_info[0]) + 1;
3671 error =
3672 acl_fromtext(
3673 &attr->attr_info[0], &aclp);
3675 if (error != 0) {
3676 (void) fprintf(stderr,
3677 gettext(
3678 "aclfromtext "
3679 "failed: %s\n"),
3680 acl_strerror(
3681 error));
3682 bytes -= attrsize;
3683 break;
3685 if (acl_cnt(aclp) != cnt) {
3686 (void) fprintf(stderr,
3687 gettext(
3688 "aclcnt error\n"));
3689 bytes -= attrsize;
3690 break;
3692 bytes -= attrsize;
3693 break;
3695 default:
3696 (void) fprintf(stderr, gettext(
3697 "unrecognized attr"
3698 " type\n"));
3699 bytes = (off_t)0;
3700 break;
3703 /* next attributes */
3704 tp += attrsize;
3705 } while (bytes != 0);
3706 free(secp);
3707 } else {
3708 passtape();
3710 } /* acl */
3712 } /* for */
3715 * Ensure that all the directories still on the directory stack
3716 * get their modification times set correctly by flushing the
3717 * stack.
3720 doDirTimes(NULL, time_zero);
3722 #if defined(O_XATTR)
3723 if (xattrp != NULL) {
3724 free(xattrhead);
3725 xattrp = NULL;
3726 xattr_linkp = NULL;
3727 xattrhead = NULL;
3729 #endif
3732 * Check if the number of files extracted is different from the
3733 * number of files listed on the command line
3735 if (fcnt > xcnt) {
3736 (void) fprintf(stderr,
3737 gettext("tar: %d file(s) not extracted\n"),
3738 fcnt-xcnt);
3739 Errflg = 1;
3744 * xblocks extract file/extent from tape to output file
3746 * xblocks(issysattr, bytes, ofile);
3748 * issysattr flag set if the files being extracted
3749 * is an extended system attribute file.
3750 * unsigned long long bytes size of extent or file to be extracted
3751 * ofile output file
3753 * called by doxtract() and xsfile()
3756 static int
3757 xblocks(int issysattr, off_t bytes, int ofile)
3759 char *buf;
3760 char tempname[NAMSIZ+1];
3761 size_t maxwrite;
3762 size_t bytesread;
3763 size_t piosize; /* preferred I/O size */
3764 struct stat tsbuf;
3766 /* Don't need to do anything if this is a zero size file */
3767 if (bytes <= 0) {
3768 return (0);
3772 * To figure out the size of the buffer used to accumulate data
3773 * from readtape() and to write to the file, we need to determine
3774 * the largest chunk of data to be written to the file at one time.
3775 * This is determined based on the smallest of the following two
3776 * things:
3777 * 1) The size of the archived file.
3778 * 2) The preferred I/O size of the file.
3780 if (issysattr || (bytes <= TBLOCK)) {
3782 * Writes to system attribute files must be
3783 * performed in one operation.
3785 maxwrite = bytes;
3786 } else {
3788 * fstat() the file to get the preferred I/O size.
3789 * If it fails, then resort back to just writing
3790 * one block at a time.
3792 if (fstat(ofile, &tsbuf) == 0) {
3793 piosize = tsbuf.st_blksize;
3794 } else {
3795 piosize = TBLOCK;
3797 maxwrite = min(bytes, piosize);
3801 * The buffer used to accumulate the data for the write operation
3802 * needs to be the maximum number of bytes to be written rounded up
3803 * to the nearest TBLOCK since readtape reads one block at a time.
3805 if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
3806 fatal(gettext("cannot allocate buffer"));
3809 while (bytes > 0) {
3812 * readtape() obtains one block (TBLOCK) of data at a time.
3813 * Accumulate as many blocks of data in buf as we can write
3814 * in one operation.
3816 for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
3817 readtape(buf + bytesread);
3820 if (write(ofile, buf, maxwrite) < 0) {
3821 int saveerrno = errno;
3823 if (xhdr_flgs & _X_PATH)
3824 (void) strlcpy(tempname, Xtarhdr.x_path,
3825 sizeof (tempname));
3826 else
3827 (void) sprintf(tempname, "%.*s", NAMSIZ,
3828 dblock.dbuf.name);
3830 * If the extended system attribute being extracted
3831 * contains attributes that the user needs privileges
3832 * for, then just display a warning message, skip
3833 * the extraction of this file, and return.
3835 if ((saveerrno == EPERM) && issysattr) {
3836 (void) fprintf(stderr, gettext(
3837 "tar: unable to extract system attribute "
3838 "%s: insufficient privileges\n"), tempname);
3839 Errflg = 1;
3840 (void) free(buf);
3841 return (1);
3842 } else {
3843 warnc(saveerrno, "extracting %s", tempname);
3844 done(2);
3847 bytes -= maxwrite;
3850 * If we've reached this point and there is still data
3851 * to be written, maxwrite had to have been determined
3852 * by the preferred I/O size. If the number of bytes
3853 * left to write is smaller than the preferred I/O size,
3854 * then we're about to do our final write to the file, so
3855 * just set maxwrite to the number of bytes left to write.
3857 if ((bytes > 0) && (bytes < maxwrite)) {
3858 maxwrite = bytes;
3861 free(buf);
3863 return (0);
3867 * xsfile extract split file
3869 * xsfile(ofd); ofd = output file descriptor
3871 * file extracted and put in ofd via xblocks()
3873 * NOTE: only called by doxtract() to extract one large file
3876 static union hblock savedblock; /* to ensure same file across volumes */
3878 static int
3879 xsfile(int issysattr, int ofd)
3881 int i, c;
3882 int sysattrerr = 0;
3883 char name[PATH_MAX+1]; /* holds name for diagnostics */
3884 int extents, totalext;
3885 off_t bytes, totalbytes;
3887 if (xhdr_flgs & _X_PATH)
3888 (void) strcpy(name, Xtarhdr.x_path);
3889 else
3890 (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
3892 totalbytes = (off_t)0; /* in case we read in half the file */
3893 totalext = 0; /* these keep count */
3895 (void) fprintf(stderr, gettext(
3896 "tar: %s split across %d volumes\n"), name, extotal);
3898 /* make sure we do extractions in order */
3899 if (extno != 1) { /* starting in middle of file? */
3900 (void) printf(gettext(
3901 "tar: first extent read is not #1\n"
3902 "OK to read file beginning with extent #%d? "),
3903 extno);
3904 if (yes() == 0) {
3905 canit:
3906 passtape();
3907 if (close(ofd) != 0)
3908 vperror(2, gettext("close error"));
3909 if (sysattrerr) {
3910 return (1);
3911 } else {
3912 return (0);
3916 extents = extotal;
3917 i = extno;
3918 /*CONSTCOND*/
3919 while (1) {
3920 if (xhdr_flgs & _X_SIZE) {
3921 bytes = extsize;
3922 } else {
3923 bytes = stbuf.st_size;
3926 if (vflag)
3927 (void) fprintf(vfile, "+++ x %s [%s #%d], %"
3928 FMT_off_t " %s, %ldK\n",
3929 name, gettext("extent"), extno,
3930 bytes, gettext("bytes"),
3931 (long)K(TBLOCKS(bytes)));
3932 if (xblocks(issysattr, bytes, ofd) != 0) {
3933 sysattrerr = 1;
3934 goto canit;
3937 totalbytes += bytes;
3938 totalext++;
3939 if (++i > extents)
3940 break;
3942 /* get next volume and verify it's the right one */
3943 copy(&savedblock, &dblock);
3944 tryagain:
3945 newvol();
3946 xhdr_flgs = 0;
3947 getdir();
3948 if (Xhdrflag > 0)
3949 (void) get_xdata(); /* Get x-header & regular hdr */
3950 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
3951 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
3952 xhdr_flgs |= _X_XHDR;
3954 if (endtape()) { /* seemingly empty volume */
3955 (void) fprintf(stderr, gettext(
3956 "tar: first record is null\n"));
3957 asknicely:
3958 (void) fprintf(stderr, gettext(
3959 "tar: need volume with extent #%d of %s\n"),
3960 i, name);
3961 goto tryagain;
3963 if (notsame()) {
3964 (void) fprintf(stderr, gettext(
3965 "tar: first file on that volume is not "
3966 "the same file\n"));
3967 goto asknicely;
3969 if (i != extno) {
3970 (void) fprintf(stderr, gettext(
3971 "tar: extent #%d received out of order\ntar: "
3972 "should be #%d\n"), extno, i);
3973 (void) fprintf(stderr, gettext(
3974 "Ignore error, Abort this file, or "
3975 "load New volume (i/a/n) ? "));
3976 c = response();
3977 if (c == 'a')
3978 goto canit;
3979 if (c != 'i') /* default to new volume */
3980 goto asknicely;
3981 i = extno; /* okay, start from there */
3984 if (vflag)
3985 (void) fprintf(vfile, gettext(
3986 "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
3987 name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
3989 return (0);
3994 * notsame() check if extract file extent is invalid
3996 * returns true if anything differs between savedblock and dblock
3997 * except extno (extent number), checksum, or size (extent size).
3998 * Determines if this header belongs to the same file as the one we're
3999 * extracting.
4001 * NOTE: though rather bulky, it is only called once per file
4002 * extension, and it can withstand changes in the definition
4003 * of the header structure.
4005 * WARNING: this routine is local to xsfile() above
4008 static int
4009 notsame(void)
4011 return (
4012 (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
4013 (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
4014 (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
4015 (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
4016 (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
4017 (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
4018 (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
4019 (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
4020 (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
4023 static void
4024 dotable(char *argv[])
4026 int tcnt = 0; /* count # files tabled */
4027 int fcnt = 0; /* count # files in argv list */
4028 char *namep, *dirp, *comp;
4029 int want;
4030 char aclchar = ' '; /* either blank or '+' */
4031 char templink[PATH_MAX+1];
4032 attr_data_t *attrinfo = NULL;
4034 dumping = 0;
4036 /* if not on magtape, maximize seek speed */
4037 if (NotTape && !bflag) {
4038 #if SYS_BLOCK > TBLOCK
4039 nblock = SYS_BLOCK / TBLOCK;
4040 #else
4041 nblock = 1;
4042 #endif
4045 for (;;) {
4047 /* namep is set by wantit to point to the full name */
4048 if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
4049 continue;
4050 if (want == -1)
4051 break;
4052 if (dblock.dbuf.typeflag != 'A')
4053 ++tcnt;
4055 if (Fflag) {
4056 if (checkf(namep, is_directory(namep), Fflag) == 0) {
4057 passtape();
4058 continue;
4062 * ACL support:
4063 * aclchar is introduced to indicate if there are
4064 * acl entries. longt() now takes one extra argument.
4066 if (vflag) {
4067 if (dblock.dbuf.typeflag == 'A') {
4068 aclchar = '+';
4069 passtape();
4070 continue;
4072 longt(&stbuf, aclchar);
4073 aclchar = ' ';
4077 #if defined(O_XATTR)
4078 if (xattrp != NULL) {
4079 int issysattr;
4080 char *bn = basename(attrinfo->attr_path);
4083 * We could use sysattr_type() to test whether or not
4084 * the attribute we are processing is really an
4085 * extended system attribute, which as of this writing
4086 * just does a strcmp(), however, sysattr_type() may
4087 * be changed to issue a pathconf() call instead, which
4088 * would require being changed into the parent attribute
4089 * directory. So instead, just do simple string
4090 * comparisons to see if we are processing an extended
4091 * system attribute.
4093 issysattr = is_sysattr(bn);
4095 (void) printf(gettext("%s %sattribute %s"),
4096 xattrp->h_names,
4097 issysattr ? gettext("system ") : "",
4098 attrinfo->attr_path);
4099 } else {
4100 (void) printf("%s", namep);
4102 #else
4103 (void) printf("%s", namep);
4104 #endif
4106 if (extno != 0) {
4107 if (vflag) {
4108 /* keep the '\n' for backwards compatibility */
4109 (void) fprintf(vfile, gettext(
4110 "\n [extent #%d of %d]"), extno, extotal);
4111 } else {
4112 (void) fprintf(vfile, gettext(
4113 " [extent #%d of %d]"), extno, extotal);
4116 if (xhdr_flgs & _X_LINKPATH) {
4117 (void) strcpy(templink, Xtarhdr.x_linkpath);
4118 } else {
4119 #if defined(O_XATTR)
4120 if (xattrp != NULL) {
4121 (void) sprintf(templink,
4122 "file %.*s", NAMSIZ, xattrp->h_names);
4123 } else {
4124 (void) sprintf(templink, "%.*s", NAMSIZ,
4125 dblock.dbuf.linkname);
4127 #else
4128 (void) sprintf(templink, "%.*s", NAMSIZ,
4129 dblock.dbuf.linkname);
4130 #endif
4131 templink[NAMSIZ] = '\0';
4133 if (dblock.dbuf.typeflag == '1') {
4135 * TRANSLATION_NOTE
4136 * Subject is omitted here.
4137 * Translate this as if
4138 * <subject> linked to %s
4140 #if defined(O_XATTR)
4141 if (xattrp != NULL) {
4142 (void) printf(
4143 gettext(" linked to attribute %s"),
4144 xattr_linkp->h_names +
4145 strlen(xattr_linkp->h_names) + 1);
4146 } else {
4147 (void) printf(
4148 gettext(" linked to %s"), templink);
4150 #else
4151 (void) printf(
4152 gettext(" linked to %s"), templink);
4154 #endif
4156 if (dblock.dbuf.typeflag == '2')
4157 (void) printf(gettext(
4159 * TRANSLATION_NOTE
4160 * Subject is omitted here.
4161 * Translate this as if
4162 * <subject> symbolic link to %s
4164 " symbolic link to %s"), templink);
4165 (void) printf("\n");
4166 #if defined(O_XATTR)
4167 if (xattrp != NULL) {
4168 free(xattrhead);
4169 xattrp = NULL;
4170 xattrhead = NULL;
4172 #endif
4173 passtape();
4176 * Check if the number of files tabled is different from the
4177 * number of files listed on the command line
4179 if (fcnt > tcnt) {
4180 (void) fprintf(stderr, gettext(
4181 "tar: %d file(s) not found\n"), fcnt-tcnt);
4182 Errflg = 1;
4186 static void
4187 putempty(blkcnt_t n)
4189 char buf[TBLOCK];
4190 char *cp;
4192 for (cp = buf; cp < &buf[TBLOCK]; )
4193 *cp++ = '\0';
4194 while (n-- > 0)
4195 (void) writetbuf(buf, 1);
4198 static ushort_t Ftype = S_IFMT;
4200 static void
4201 verbose(struct stat *st, char aclchar)
4203 int i, j, temp;
4204 mode_t mode;
4205 char modestr[12];
4207 for (i = 0; i < 11; i++)
4208 modestr[i] = '-';
4209 modestr[i] = '\0';
4211 /* a '+' sign is printed if there is ACL */
4212 modestr[i-1] = aclchar;
4214 mode = st->st_mode;
4215 for (i = 0; i < 3; i++) {
4216 temp = (mode >> (6 - (i * 3)));
4217 j = (i * 3) + 1;
4218 if (S_IROTH & temp)
4219 modestr[j] = 'r';
4220 if (S_IWOTH & temp)
4221 modestr[j + 1] = 'w';
4222 if (S_IXOTH & temp)
4223 modestr[j + 2] = 'x';
4225 temp = st->st_mode & Ftype;
4226 switch (temp) {
4227 case (S_IFIFO):
4228 modestr[0] = 'p';
4229 break;
4230 case (S_IFCHR):
4231 modestr[0] = 'c';
4232 break;
4233 case (S_IFDIR):
4234 modestr[0] = 'd';
4235 break;
4236 case (S_IFBLK):
4237 modestr[0] = 'b';
4238 break;
4239 case (S_IFREG): /* was initialized to '-' */
4240 break;
4241 case (S_IFLNK):
4242 modestr[0] = 'l';
4243 break;
4244 default:
4245 /* This field may be zero in old archives. */
4246 if (is_posix && dblock.dbuf.typeflag != '1') {
4248 * For POSIX compliant archives, the mode field
4249 * consists of 12 bits, ie: the file type bits
4250 * are not stored in dblock.dbuf.mode.
4251 * For files other than hard links, getdir() sets
4252 * the file type bits in the st_mode field of the
4253 * stat structure based upon dblock.dbuf.typeflag.
4255 (void) fprintf(stderr, gettext(
4256 "tar: impossible file type"));
4260 if ((S_ISUID & Gen.g_mode) == S_ISUID)
4261 modestr[3] = 's';
4262 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
4263 modestr[9] = 't';
4264 if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
4265 modestr[6] = 's';
4266 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
4267 modestr[6] = 'l';
4268 (void) fprintf(vfile, "%s", modestr);
4271 static void
4272 longt(struct stat *st, char aclchar)
4274 char fileDate[30];
4275 struct tm *tm;
4277 verbose(st, aclchar);
4278 (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
4280 if (dblock.dbuf.typeflag == '2') {
4281 if (xhdr_flgs & _X_LINKPATH)
4282 st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
4283 else
4284 st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
4285 '\0', NAMSIZ) ?
4286 (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
4288 (void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
4290 tm = localtime(&(st->st_mtime));
4291 (void) strftime(fileDate, sizeof (fileDate),
4292 dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
4293 (void) fprintf(vfile, " %s ", fileDate);
4298 * checkdir - Attempt to ensure that the path represented in name
4299 * exists, and return 1 if this is true and name itself is a
4300 * directory.
4301 * Return 0 if this path cannot be created or if name is not
4302 * a directory.
4305 static int
4306 checkdir(char *name)
4308 char lastChar; /* the last character in name */
4309 char *cp; /* scratch pointer into name */
4310 char *firstSlash = NULL; /* first slash in name */
4311 char *lastSlash = NULL; /* last slash in name */
4312 int nameLen; /* length of name */
4313 int trailingSlash; /* true if name ends in slash */
4314 int leadingSlash; /* true if name begins with slash */
4315 int markedDir; /* true if name denotes a directory */
4316 int success; /* status of makeDir call */
4320 * Scan through the name, and locate first and last slashes.
4323 for (cp = name; *cp; cp++) {
4324 if (*cp == '/') {
4325 if (! firstSlash) {
4326 firstSlash = cp;
4328 lastSlash = cp;
4333 * Determine what you can from the proceeds of the scan.
4336 lastChar = *(cp - 1);
4337 nameLen = (int)(cp - name);
4338 trailingSlash = (lastChar == '/');
4339 leadingSlash = (*name == '/');
4340 markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash);
4342 if (! lastSlash && ! markedDir) {
4344 * The named file does not have any subdrectory
4345 * structure; just bail out.
4348 return (0);
4352 * Make sure that name doesn`t end with slash for the loop.
4353 * This ensures that the makeDir attempt after the loop is
4354 * meaningful.
4357 if (trailingSlash) {
4358 name[nameLen-1] = '\0';
4362 * Make the path one component at a time.
4365 for (cp = strchr(leadingSlash ? name+1 : name, '/');
4367 cp = strchr(cp+1, '/')) {
4368 *cp = '\0';
4369 success = makeDir(name);
4370 *cp = '/';
4372 if (!success) {
4373 name[nameLen-1] = lastChar;
4374 return (0);
4379 * This makes the last component of the name, if it is a
4380 * directory.
4383 if (markedDir) {
4384 if (! makeDir(name)) {
4385 name[nameLen-1] = lastChar;
4386 return (0);
4390 name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
4391 return (markedDir);
4395 * resugname - Restore the user name and group name. Search the NIS
4396 * before using the uid and gid.
4397 * (It is presumed that an archive entry cannot be
4398 * simultaneously a symlink and some other type.)
4401 static void
4402 resugname(int dirfd, /* dir fd file resides in */
4403 char *name, /* name of the file to be modified */
4404 int symflag) /* true if file is a symbolic link */
4406 uid_t duid;
4407 gid_t dgid;
4408 struct stat *sp = &stbuf;
4409 char *u_g_name;
4411 if (checkflag == 1) { /* Extended tar format and euid == 0 */
4414 * Try and extract the intended uid and gid from the name
4415 * service before believing the uid and gid in the header.
4417 * In the case where we archived a setuid or setgid file
4418 * owned by someone with a large uid, then it will
4419 * have made it into the archive with a uid of nobody. If
4420 * the corresponding username doesn't appear to exist, then we
4421 * want to make sure it *doesn't* end up as setuid nobody!
4423 * Our caller will print an error message about the fact
4424 * that the restore didn't work out quite right ..
4426 if (xhdr_flgs & _X_UNAME)
4427 u_g_name = Xtarhdr.x_uname;
4428 else
4429 u_g_name = dblock.dbuf.uname;
4430 if ((duid = getuidbyname(u_g_name)) == -1) {
4431 if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
4432 (sp->st_mode & S_ISUID) == S_ISUID)
4433 (void) chmod(name,
4434 MODEMASK & sp->st_mode & ~S_ISUID);
4435 duid = sp->st_uid;
4438 /* (Ditto for gids) */
4440 if (xhdr_flgs & _X_GNAME)
4441 u_g_name = Xtarhdr.x_gname;
4442 else
4443 u_g_name = dblock.dbuf.gname;
4444 if ((dgid = getgidbyname(u_g_name)) == -1) {
4445 if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
4446 (sp->st_mode & S_ISGID) == S_ISGID)
4447 (void) chmod(name,
4448 MODEMASK & sp->st_mode & ~S_ISGID);
4449 dgid = sp->st_gid;
4451 } else if (checkflag == 2) { /* tar format and euid == 0 */
4452 duid = sp->st_uid;
4453 dgid = sp->st_gid;
4455 if ((checkflag == 1) || (checkflag == 2))
4456 (void) fchownat(dirfd, name, duid, dgid, symflag);
4459 /*ARGSUSED*/
4460 static void
4461 onintr(int sig)
4463 (void) signal(SIGINT, SIG_IGN);
4464 term++;
4467 /*ARGSUSED*/
4468 static void
4469 onquit(int sig)
4471 (void) signal(SIGQUIT, SIG_IGN);
4472 term++;
4475 /*ARGSUSED*/
4476 static void
4477 onhup(int sig)
4479 (void) signal(SIGHUP, SIG_IGN);
4480 term++;
4483 static void
4484 tomodes(struct stat *sp)
4486 uid_t uid;
4487 gid_t gid;
4489 bzero(dblock.dummy, TBLOCK);
4492 * If the uid or gid is too large, we can't put it into
4493 * the archive. We could fail to put anything in the
4494 * archive at all .. but most of the time the name service
4495 * will save the day when we do a lookup at restore time.
4497 * Instead we choose a "safe" uid and gid, and fix up whether
4498 * or not the setuid and setgid bits are left set to extraction
4499 * time.
4501 if (Eflag) {
4502 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
4503 xhdr_flgs |= _X_UID;
4504 Xtarhdr.x_uid = uid;
4506 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
4507 xhdr_flgs |= _X_GID;
4508 Xtarhdr.x_gid = gid;
4510 if (sp->st_size > TAR_OFFSET_MAX) {
4511 xhdr_flgs |= _X_SIZE;
4512 Xtarhdr.x_filesz = sp->st_size;
4513 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4514 (off_t)0);
4515 } else
4516 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4517 sp->st_size);
4518 } else {
4519 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4520 sp->st_size);
4522 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
4523 uid = UID_NOBODY;
4524 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
4525 gid = GID_NOBODY;
4526 (void) sprintf(dblock.dbuf.gid, "%07lo", gid);
4527 (void) sprintf(dblock.dbuf.uid, "%07lo", uid);
4528 (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
4529 (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
4532 static int
4533 #ifdef EUC
4535 * Warning: the result of this function depends whether 'char' is a
4536 * signed or unsigned data type. This a source of potential
4537 * non-portability among heterogeneous systems. It is retained here
4538 * for backward compatibility.
4540 checksum_signed(union hblock *dblockp)
4541 #else
4542 checksum(union hblock *dblockp)
4543 #endif /* EUC */
4545 int i;
4546 char *cp;
4548 for (cp = dblockp->dbuf.chksum;
4549 cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
4550 *cp = ' ';
4551 i = 0;
4552 for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
4553 i += *cp;
4554 return (i);
4557 #ifdef EUC
4559 * Generate unsigned checksum, regardless of what C compiler is
4560 * used. Survives in the face of arbitrary 8-bit clean filenames,
4561 * e.g., internationalized filenames.
4563 static int
4564 checksum(union hblock *dblockp)
4566 unsigned i;
4567 unsigned char *cp;
4569 for (cp = (unsigned char *) dblockp->dbuf.chksum;
4570 cp < (unsigned char *)
4571 &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
4572 *cp = ' ';
4573 i = 0;
4574 for (cp = (unsigned char *) dblockp->dummy;
4575 cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
4576 i += *cp;
4578 return (i);
4580 #endif /* EUC */
4583 * If the w flag is set, output the action to be taken and the name of the
4584 * file. Perform the action if the user response is affirmative.
4587 static int
4588 checkw(char c, char *name)
4590 if (wflag) {
4591 (void) fprintf(vfile, "%c ", c);
4592 if (vflag)
4593 longt(&stbuf, ' '); /* do we have acl info here */
4594 (void) fprintf(vfile, "%s: ", name);
4595 if (yes() == 1) {
4596 return (1);
4598 return (0);
4600 return (1);
4604 * When the F flag is set, exclude RCS and SCCS directories (and any files
4605 * or directories under them). If F is set twice, also exclude .o files,
4606 * and files names errs, core, and a.out.
4608 * Return 0 if file should be excluded, 1 otherwise.
4611 static int
4612 checkf(char *longname, int is_dir, int howmuch)
4614 static char fullname[PATH_MAX + 1];
4615 char *dir, *name;
4617 #if defined(O_XATTR)
4619 * If there is an xattr_buf structure associated with this file,
4620 * always return 1.
4622 if (xattrp) {
4623 return (1);
4625 #endif
4628 * First check to see if the base name is an RCS or SCCS directory.
4630 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4631 return (1);
4633 name = basename(fullname);
4634 if (is_dir) {
4635 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4636 return (0);
4640 * If two -F command line options were given then exclude .o files,
4641 * and files named errs, core, and a.out.
4643 if (howmuch > 1 && !is_dir) {
4644 size_t l = strlen(name);
4646 if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
4647 return (0);
4648 if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
4649 strcmp(name, "a.out") == 0)
4650 return (0);
4654 * At this point, check to see if this file has a parent directory
4655 * named RCS or SCCS. If so, then this file should be excluded too.
4656 * The strcpy() operation is done again, because basename(3C) may
4657 * modify the path string passed to it.
4659 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4660 return (1);
4662 dir = dirname(fullname);
4663 while (strcmp(dir, ".") != 0) {
4664 name = basename(dir);
4665 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4666 return (0);
4667 dir = dirname(dir);
4670 return (1);
4673 static int
4674 response(void)
4676 int c;
4678 c = getchar();
4679 if (c != '\n')
4680 while (getchar() != '\n')
4682 else c = 'n';
4683 return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
4686 /* Has file been modified since being put into archive? If so, return > 0. */
4688 static off_t lookup(char *);
4690 static int
4691 checkupdate(char *arg)
4693 char name[PATH_MAX+1];
4694 time_t mtime;
4695 long nsecs;
4696 off_t seekp;
4698 rewind(tfile);
4699 if ((seekp = lookup(arg)) < 0)
4700 return (1);
4701 (void) fseek(tfile, seekp, 0);
4702 (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
4705 * Unless nanoseconds were stored in the file, only use seconds for
4706 * comparison of time. Nanoseconds are stored when -E is specified.
4708 if (Eflag == 0)
4709 return (stbuf.st_mtime > mtime);
4711 if ((stbuf.st_mtime < mtime) ||
4712 ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
4713 return (0);
4714 return (1);
4719 * newvol get new floppy (or tape) volume
4721 * newvol(); resets tapepos and first to TRUE, prompts for
4722 * for new volume, and waits.
4723 * if dumping, end-of-file is written onto the tape.
4726 static void
4727 newvol(void)
4729 int c;
4731 if (dumping) {
4732 dlog("newvol called with 'dumping' set\n");
4733 putempty((blkcnt_t)2); /* 2 EOT marks */
4734 closevol();
4735 flushtape();
4736 sync();
4737 tapepos = 0;
4738 } else
4739 first = TRUE;
4740 if (close(mt) != 0)
4741 vperror(2, gettext("close error"));
4742 mt = 0;
4743 (void) fprintf(stderr, gettext(
4744 "tar: \007please insert new volume, then press RETURN."));
4745 (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */
4746 while ((c = getchar()) != '\n' && ! term)
4747 if (c == EOF)
4748 done(Errflg);
4749 if (term)
4750 done(Errflg);
4752 errno = 0;
4754 if (strcmp(usefile, "-") == 0) {
4755 mt = dup(1);
4756 } else {
4757 mt = open(usefile, dumping ? update : 0);
4760 if (mt < 0) {
4761 (void) fprintf(stderr, gettext(
4762 "tar: cannot reopen %s (%s)\n"),
4763 dumping ? gettext("output") : gettext("input"), usefile);
4765 dlog("update=%d, usefile=%s ", update, usefile);
4766 dlog("mt=%d, [%s]\n", mt, strerror(errno));
4768 done(2);
4773 * Write a trailer portion to close out the current output volume.
4776 static void
4777 closevol(void)
4779 if (mulvol) {
4781 * blocklim does not count the 2 EOT marks;
4782 * tapepos does count the 2 EOT marks;
4783 * therefore we need the +2 below.
4785 putempty(blocklim + (blkcnt_t)2 - tapepos);
4789 static void
4790 done(int n)
4793 * If we were terminated in some way, and we would otherwise have
4794 * exited with a value of 0, adjust to 1, so that external callers
4795 * can determine this by looking at the exit status.
4797 if (term && n == 0)
4798 n = 1;
4800 if (tfile != NULL)
4801 (void) unlink(tname);
4802 if (compress_opt != NULL)
4803 (void) free(compress_opt);
4804 if (mt > 0) {
4805 if ((close(mt) != 0) || (fclose(stdout) != 0)) {
4806 perror(gettext("tar: close error"));
4807 exit(2);
4811 * If we have a compression child, we should have a child process that
4812 * we're waiting for to finish compressing or uncompressing the tar
4813 * stream.
4815 if (comp_pid != 0)
4816 wait_pid(comp_pid);
4817 exit(n);
4821 * Determine if s1 is a prefix portion of s2 (or the same as s2).
4824 static int
4825 is_prefix(char *s1, char *s2)
4827 while (*s1)
4828 if (*s1++ != *s2++)
4829 return (0);
4830 if (*s2)
4831 return (*s2 == '/');
4832 return (1);
4836 * lookup and bsrch look through tfile entries to find a match for a name.
4837 * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
4838 * a pair of newline chars, so the buffer it uses must be long enough for
4839 * two lines: name and modification time as well as period, newline and space.
4841 * A kludge was added to bsrch to take care of matching on the first entry
4842 * in the file--there is no leading newline. So, if we are reading from the
4843 * start of the file, read into byte two and set the first byte to a newline.
4844 * Otherwise, the first entry cannot be matched.
4848 #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4849 static off_t
4850 lookup(char *s)
4852 int i;
4853 off_t a;
4855 for (i = 0; s[i]; i++)
4856 if (s[i] == ' ')
4857 break;
4858 a = bsrch(s, i, low, high);
4859 return (a);
4862 static off_t
4863 bsrch(char *s, int n, off_t l, off_t h)
4865 int i, j;
4866 char b[N];
4867 off_t m, m1;
4870 loop:
4871 if (l >= h)
4872 return ((off_t)-1);
4873 m = l + (h-l)/2 - N/2;
4874 if (m < l)
4875 m = l;
4876 (void) fseek(tfile, m, 0);
4877 if (m == 0) {
4878 (void) fread(b+1, 1, N-1, tfile);
4879 b[0] = '\n';
4880 m--;
4881 } else
4882 (void) fread(b, 1, N, tfile);
4883 for (i = 0; i < N; i++) {
4884 if (b[i] == '\n')
4885 break;
4886 m++;
4888 if (m >= h)
4889 return ((off_t)-1);
4890 m1 = m;
4891 j = i;
4892 for (i++; i < N; i++) {
4893 m1++;
4894 if (b[i] == '\n')
4895 break;
4897 i = cmp(b+j, s, n);
4898 if (i < 0) {
4899 h = m;
4900 goto loop;
4902 if (i > 0) {
4903 l = m1;
4904 goto loop;
4906 if (m < 0)
4907 m = 0;
4908 return (m);
4911 static int
4912 cmp(char *b, char *s, int n)
4914 int i;
4916 assert(b[0] == '\n');
4918 for (i = 0; i < n; i++) {
4919 if (b[i+1] > s[i])
4920 return (-1);
4921 if (b[i+1] < s[i])
4922 return (1);
4924 return (b[i+1] == ' '? 0 : -1);
4929 * seekdisk seek to next file on archive
4931 * called by passtape() only
4933 * WARNING: expects "nblock" to be set, that is, readtape() to have
4934 * already been called. Since passtape() is only called
4935 * after a file header block has been read (why else would
4936 * we skip to next file?), this is currently safe.
4938 * changed to guarantee SYS_BLOCK boundary
4941 static void
4942 seekdisk(blkcnt_t blocks)
4944 off_t seekval;
4945 #if SYS_BLOCK > TBLOCK
4946 /* handle non-multiple of SYS_BLOCK */
4947 blkcnt_t nxb; /* # extra blocks */
4948 #endif
4950 tapepos += blocks;
4951 dlog("seekdisk(%" FMT_blkcnt_t ") called\n", blocks);
4952 if (recno + blocks <= nblock) {
4953 recno += blocks;
4954 return;
4956 if (recno > nblock)
4957 recno = nblock;
4958 seekval = (off_t)blocks - (nblock - recno);
4959 recno = nblock; /* so readtape() reads next time through */
4960 #if SYS_BLOCK > TBLOCK
4961 nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
4962 dlog("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
4963 nxb, seekval);
4964 if (nxb && nxb > seekval) /* don't seek--we'll read */
4965 goto noseek;
4966 seekval -= nxb; /* don't seek quite so far */
4967 #endif
4968 if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
4969 (void) fprintf(stderr, gettext(
4970 "tar: device seek error\n"));
4971 done(3);
4973 #if SYS_BLOCK > TBLOCK
4974 /* read those extra blocks */
4975 noseek:
4976 if (nxb) {
4977 dlog("reading extra blocks\n");
4978 if (read(mt, tbuf, TBLOCK*nblock) < 0) {
4979 (void) fprintf(stderr, gettext(
4980 "tar: read error while skipping file\n"));
4981 done(8);
4983 recno = nxb; /* so we don't read in next readtape() */
4985 #endif
4988 static void
4989 readtape(char *buffer)
4991 int i, j;
4993 ++tapepos;
4994 if (recno >= nblock || first) {
4995 if (first) {
4997 * set the number of blocks to read initially, based on
4998 * the defined defaults for the device, or on the
4999 * explicit block factor given.
5001 if (bflag || defaults_used || NotTape)
5002 j = nblock;
5003 else
5004 j = NBLOCK;
5005 } else
5006 j = nblock;
5008 if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
5009 (void) fprintf(stderr, gettext(
5010 "tar: tape read error\n"));
5011 done(3);
5013 * i == 0 and !rflag means that EOF is reached and we are
5014 * trying to update or replace an empty tar file, so exit
5015 * with an error.
5017 * If i == 0 and !first and NotTape, it means the pointer
5018 * has gone past the EOF. It could happen if two processes
5019 * try to update the same tar file simultaneously. So exit
5020 * with an error.
5023 } else if (i == 0) {
5024 if (first && !rflag) {
5025 (void) fprintf(stderr, gettext(
5026 "tar: blocksize = %d\n"), i);
5027 done(Errflg);
5028 } else if (!first && (!rflag || NotTape)) {
5029 mterr("read", 0, 2);
5031 } else if ((!first || Bflag) && i != TBLOCK*j) {
5033 * Short read - try to get the remaining bytes.
5036 int remaining = (TBLOCK * j) - i;
5037 char *b = (char *)tbuf + i;
5038 int r;
5040 do {
5041 if ((r = read(mt, b, remaining)) < 0) {
5042 (void) fprintf(stderr,
5043 gettext("tar: tape read error\n"));
5044 done(3);
5046 b += r;
5047 remaining -= r;
5048 i += r;
5049 } while (remaining > 0 && r != 0);
5051 if (first) {
5052 if ((i % TBLOCK) != 0) {
5053 (void) fprintf(stderr, gettext(
5054 "tar: tape blocksize error\n"));
5055 done(3);
5057 i /= TBLOCK;
5058 if (vflag && i != nblock && i != 1) {
5059 if (!NotTape)
5060 (void) fprintf(stderr, gettext(
5061 "tar: blocksize = %d\n"), i);
5065 * If we are reading a tape, then a short read is
5066 * understood to signify that the amount read is
5067 * the tape's actual blocking factor. We adapt
5068 * nblock accordingly. There is no reason to do
5069 * this when the device is not blocked.
5072 if (!NotTape)
5073 nblock = i;
5075 recno = 0;
5078 first = FALSE;
5079 copy(buffer, &tbuf[recno++]);
5084 * replacement for writetape.
5087 static int
5088 writetbuf(char *buffer, int n)
5090 int i;
5092 tapepos += n; /* output block count */
5094 if (recno >= nblock) {
5095 i = write(mt, (char *)tbuf, TBLOCK*nblock);
5096 if (i != TBLOCK*nblock)
5097 mterr("write", i, 2);
5098 recno = 0;
5102 * Special case: We have an empty tape buffer, and the
5103 * users data size is >= the tape block size: Avoid
5104 * the bcopy and dma direct to tape. BIG WIN. Add the
5105 * residual to the tape buffer.
5107 while (recno == 0 && n >= nblock) {
5108 i = (int)write(mt, buffer, TBLOCK*nblock);
5109 if (i != TBLOCK*nblock)
5110 mterr("write", i, 2);
5111 n -= nblock;
5112 buffer += (nblock * TBLOCK);
5115 while (n-- > 0) {
5116 (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
5117 buffer += TBLOCK;
5118 if (recno >= nblock) {
5119 i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
5120 if (i != TBLOCK*nblock)
5121 mterr("write", i, 2);
5122 recno = 0;
5126 /* Tell the user how much to write to get in sync */
5127 return (nblock - recno);
5131 * backtape - reposition tape after reading soft "EOF" record
5133 * Backtape tries to reposition the tape back over the EOF
5134 * record. This is for the 'u' and 'r' function letters so that the
5135 * tape can be extended. This code is not well designed, but
5136 * I'm confident that the only callers who care about the
5137 * backspace-over-EOF feature are those involved in 'u' and 'r'.
5139 * The proper way to backup the tape is through the use of mtio.
5140 * Earlier spins used lseek combined with reads in a confusing
5141 * maneuver that only worked on 4.x, but shouldn't have, even
5142 * there. Lseeks are explicitly not supported for tape devices.
5145 static void
5146 backtape(void)
5148 struct mtop mtcmd;
5149 dlog("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
5150 nblock);
5152 * Backup to the position in the archive where the record
5153 * currently sitting in the tbuf buffer is situated.
5156 if (NotTape) {
5158 * For non-tape devices, this means lseeking to the
5159 * correct position. The absolute location tapepos-recno
5160 * should be the beginning of the current record.
5163 if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
5164 (off_t)-1) {
5165 (void) fprintf(stderr,
5166 gettext("tar: lseek to end of archive failed\n"));
5167 done(4);
5169 } else {
5171 * For tape devices, we backup over the most recently
5172 * read record.
5175 mtcmd.mt_op = MTBSR;
5176 mtcmd.mt_count = 1;
5178 if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
5179 (void) fprintf(stderr,
5180 gettext("tar: backspace over record failed\n"));
5181 done(4);
5186 * Decrement the tape and tbuf buffer indices to prepare for the
5187 * coming write to overwrite the soft EOF record.
5190 recno--;
5191 tapepos--;
5196 * flushtape write buffered block(s) onto tape
5198 * recno points to next free block in tbuf. If nonzero, a write is done.
5199 * Care is taken to write in multiples of SYS_BLOCK when device is
5200 * non-magtape in case raw i/o is used.
5202 * NOTE: this is called by writetape() to do the actual writing
5205 static void
5206 flushtape(void)
5208 dlog("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno);
5209 if (recno > 0) { /* anything buffered? */
5210 if (NotTape) {
5211 #if SYS_BLOCK > TBLOCK
5212 int i;
5215 * an odd-block write can only happen when
5216 * we are at the end of a volume that is not a tape.
5217 * Here we round recno up to an even SYS_BLOCK
5218 * boundary.
5220 if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
5221 dlog("flushtape() %d rounding blocks\n", i);
5222 recno += i; /* round up to even SYS_BLOCK */
5224 #endif
5225 if (recno > nblock)
5226 recno = nblock;
5228 dlog("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
5229 " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
5230 (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
5231 if (write(mt, tbuf,
5232 (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
5233 (void) fprintf(stderr, gettext(
5234 "tar: tape write error\n"));
5235 done(2);
5237 recno = 0;
5241 static void
5242 copy(void *dst, void *src)
5244 (void) memcpy(dst, src, TBLOCK);
5248 * kcheck()
5249 * - checks the validity of size values for non-tape devices
5250 * - if size is zero, mulvol tar is disabled and size is
5251 * assumed to be infinite.
5252 * - returns volume size in TBLOCKS
5255 static blkcnt_t
5256 kcheck(char *kstr)
5258 blkcnt_t kval;
5260 kval = strtoll(kstr, NULL, 0);
5261 if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */
5262 mulvol = 0; /* definitely not mulvol, but we must */
5263 return (0); /* took out setting of NotTape */
5265 if (kval < (blkcnt_t)MINSIZE) {
5266 (void) fprintf(stderr, gettext(
5267 "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5268 ").\n"), (ulong_t)MINSIZE, kval);
5269 (void) fprintf(stderr, gettext(
5270 "bad size entry for %s in %s.\n"),
5271 archive, DEF_FILE);
5272 done(1);
5274 mulvol++;
5275 NotTape++; /* implies non-tape */
5276 return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */
5281 * bcheck()
5282 * - checks the validity of blocking factors
5283 * - returns blocking factor
5286 static int
5287 bcheck(char *bstr)
5289 blkcnt_t bval;
5291 bval = strtoll(bstr, NULL, 0);
5292 if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
5293 (void) fprintf(stderr, gettext(
5294 "tar: invalid blocksize \"%s\".\n"), bstr);
5295 if (!bflag)
5296 (void) fprintf(stderr, gettext(
5297 "bad blocksize entry for '%s' in %s.\n"),
5298 archive, DEF_FILE);
5299 done(1);
5302 return ((int)bval);
5307 * defset()
5308 * - reads DEF_FILE for the set of default values specified.
5309 * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5310 * - 'usefile' points to static data, so will be overwritten
5311 * if this routine is called a second time.
5312 * - the pattern specified by 'arch' must be followed by four
5313 * blank-separated fields (1) device (2) blocking,
5314 * (3) size(K), and (4) tape
5315 * for example: archive0=/dev/fd 1 400 n
5318 static int
5319 defset(char *arch)
5321 char *bp;
5323 if (defopen(DEF_FILE) != 0)
5324 return (FALSE);
5325 if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
5326 (void) fprintf(stderr, gettext(
5327 "tar: error setting parameters for %s.\n"), DEF_FILE);
5328 return (FALSE); /* & following ones too */
5330 if ((bp = defread(arch)) == NULL) {
5331 (void) fprintf(stderr, gettext(
5332 "tar: missing or invalid '%s' entry in %s.\n"),
5333 arch, DEF_FILE);
5334 return (FALSE);
5336 if ((usefile = strtok(bp, " \t")) == NULL) {
5337 (void) fprintf(stderr, gettext(
5338 "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
5339 return (FALSE);
5341 if ((bp = strtok(NULL, " \t")) == NULL) {
5342 (void) fprintf(stderr, gettext(
5343 "tar: block component missing in '%s' entry in %s.\n"),
5344 arch, DEF_FILE);
5345 return (FALSE);
5347 nblock = bcheck(bp);
5348 if ((bp = strtok(NULL, " \t")) == NULL) {
5349 (void) fprintf(stderr, gettext(
5350 "tar: size component missing in '%s' entry in %s.\n"),
5351 arch, DEF_FILE);
5352 return (FALSE);
5354 blocklim = kcheck(bp);
5355 if ((bp = strtok(NULL, " \t")) != NULL)
5356 NotTape = (*bp == 'n' || *bp == 'N');
5357 else
5358 NotTape = (blocklim != 0);
5359 (void) defopen(NULL);
5360 dlog("defset: archive='%s'; usefile='%s'\n", arch, usefile);
5361 dlog("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
5362 nblock, blocklim);
5363 dlog("defset: not tape = %d\n", NotTape);
5364 return (TRUE);
5369 * Following code handles excluded and included files.
5370 * A hash table of file names to be {in,ex}cluded is built.
5371 * For excluded files, before writing or extracting a file
5372 * check to see if it is in the exclude_tbl.
5373 * For included files, the wantit() procedure will check to
5374 * see if the named file is in the include_tbl.
5377 static void
5378 build_table(file_list_t *table[], char *file)
5380 FILE *fp;
5381 char buf[PATH_MAX + 1];
5383 if ((fp = fopen(file, "r")) == NULL)
5384 vperror(1, gettext("could not open %s"), file);
5385 while (fgets(buf, sizeof (buf), fp) != NULL) {
5386 if (buf[strlen(buf) - 1] == '\n')
5387 buf[strlen(buf) - 1] = '\0';
5388 /* Only add to table if line has something in it */
5389 if (strspn(buf, " \t") != strlen(buf))
5390 add_file_to_table(table, buf);
5392 (void) fclose(fp);
5397 * Add a file name to the the specified table, if the file name has any
5398 * trailing '/'s then delete them before inserting into the table
5401 static void
5402 add_file_to_table(file_list_t *table[], char *str)
5404 char name[PATH_MAX + 1];
5405 unsigned int h;
5406 file_list_t *exp;
5408 (void) strcpy(name, str);
5409 while (name[strlen(name) - 1] == '/') {
5410 name[strlen(name) - 1] = '\0';
5413 h = hash(name);
5414 if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
5415 sizeof (char))) == NULL) {
5416 (void) fprintf(stderr, gettext(
5417 "tar: out of memory, exclude/include table(entry)\n"));
5418 exit(1);
5421 if ((exp->name = strdup(name)) == NULL) {
5422 (void) fprintf(stderr, gettext(
5423 "tar: out of memory, exclude/include table(file name)\n"));
5424 exit(1);
5427 exp->next = table[h];
5428 table[h] = exp;
5433 * See if a file name or any of the file's parent directories is in the
5434 * specified table, if the file name has any trailing '/'s then delete
5435 * them before searching the table
5438 static int
5439 is_in_table(file_list_t *table[], char *str)
5441 char name[PATH_MAX + 1];
5442 unsigned int h;
5443 file_list_t *exp;
5444 char *ptr;
5446 (void) strcpy(name, str);
5447 while (name[strlen(name) - 1] == '/') {
5448 name[strlen(name) - 1] = '\0';
5452 * check for the file name in the passed list
5454 h = hash(name);
5455 exp = table[h];
5456 while (exp != NULL) {
5457 if (strcmp(name, exp->name) == 0) {
5458 return (1);
5460 exp = exp->next;
5464 * check for any parent directories in the file list
5466 while ((ptr = strrchr(name, '/'))) {
5467 *ptr = '\0';
5468 h = hash(name);
5469 exp = table[h];
5470 while (exp != NULL) {
5471 if (strcmp(name, exp->name) == 0) {
5472 return (1);
5474 exp = exp->next;
5478 return (0);
5483 * Compute a hash from a string.
5486 static unsigned int
5487 hash(char *str)
5489 char *cp;
5490 unsigned int h;
5492 h = 0;
5493 for (cp = str; *cp; cp++) {
5494 h += *cp;
5496 return (h % TABLE_SIZE);
5499 static void *
5500 getmem(size_t size)
5502 void *p = calloc((unsigned)size, sizeof (char));
5504 if (p == NULL && freemem) {
5505 (void) fprintf(stderr, gettext(
5506 "tar: out of memory, link and directory modtime "
5507 "info lost\n"));
5508 freemem = 0;
5509 if (errflag)
5510 done(1);
5511 else
5512 Errflg = 1;
5514 return (p);
5518 * vperror() --variable argument perror.
5519 * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
5520 * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5521 * with the value of whatever "errno" is set to. If exit_status is not
5522 * zero, then tar exits with that error status. If errflag and exit_status
5523 * are both zero, the routine returns to where it was called and sets Errflg
5524 * to errno.
5527 static void
5528 vperror(int exit_status, char *fmt, ...)
5530 va_list ap;
5532 va_start(ap, fmt);
5533 (void) fputs("tar: ", stderr);
5534 (void) vfprintf(stderr, fmt, ap);
5535 (void) fprintf(stderr, ": %s\n", strerror(errno));
5536 va_end(ap);
5537 if (exit_status)
5538 done(exit_status);
5539 else
5540 if (errflag)
5541 done(errno);
5542 else
5543 Errflg = errno;
5547 static void
5548 fatal(char *format, ...)
5550 va_list ap;
5552 va_start(ap, format);
5553 (void) fprintf(stderr, "tar: ");
5554 (void) vfprintf(stderr, format, ap);
5555 (void) fprintf(stderr, "\n");
5556 va_end(ap);
5557 done(1);
5562 * Check to make sure that argument is a char * ptr.
5563 * Actually, we just check to see that it is non-null.
5564 * If it is null, print out the message and call usage(), bailing out.
5567 static void
5568 assert_string(char *s, char *msg)
5570 if (s == NULL) {
5571 (void) fprintf(stderr, msg);
5572 usage();
5577 static void
5578 mterr(char *operation, int i, int exitcode)
5580 (void) fprintf(stderr, gettext(
5581 "tar: %s error: "), operation);
5582 if (i < 0)
5583 perror("");
5584 else
5585 (void) fprintf(stderr, gettext("unexpected EOF\n"));
5586 done(exitcode);
5589 static int
5590 wantit(char *argv[], char **namep, char **dirp, char **component,
5591 attr_data_t **attrinfo)
5593 char **cp;
5594 int gotit; /* true if we've found a match */
5595 int ret;
5597 top:
5598 if (xhdr_flgs & _X_XHDR) {
5599 xhdr_flgs = 0;
5601 getdir();
5602 if (Xhdrflag > 0) {
5603 ret = get_xdata();
5604 if (ret != 0) { /* Xhdr items and regular header */
5605 setbytes_to_skip(&stbuf, ret);
5606 passtape();
5607 return (0); /* Error--don't want to extract */
5612 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5613 * of ancillary file is either over or ancillary file
5614 * processing is not required, load info from Xtarhdr and set
5615 * _X_XHDR bit in xhdr_flgs.
5617 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
5618 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
5619 xhdr_flgs |= _X_XHDR;
5622 #if defined(O_XATTR)
5623 if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
5625 * Always needs to read the extended header. If atflag, saflag,
5626 * or tflag isn't set, then we'll have the correct info for
5627 * passtape() later.
5629 (void) read_xattr_hdr(attrinfo);
5630 goto top;
5633 * Now that we've read the extended header, call passtape()
5634 * if we don't want to restore attributes or system attributes.
5635 * Don't restore the attribute if we are extracting
5636 * a file from an archive (as opposed to doing a table of
5637 * contents) and any of the following are true:
5638 * 1. neither -@ or -/ was specified.
5639 * 2. -@ was specified, -/ wasn't specified, and we're
5640 * processing a hidden attribute directory of an attribute
5641 * or we're processing a read-write system attribute file.
5642 * 3. -@ wasn't specified, -/ was specified, and the file
5643 * we're processing is not a read-write system attribute file,
5644 * or we're processing the hidden attribute directory of an
5645 * attribute.
5647 * We always process the attributes if we're just generating
5648 * generating a table of contents, or if both -@ and -/ were
5649 * specified.
5651 if (xattrp != NULL) {
5652 attr_data_t *ainfo = *attrinfo;
5654 if (!tflag &&
5655 ((!atflag && !saflag) ||
5656 (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
5657 ainfo->attr_rw_sysattr)) ||
5658 (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
5659 !ainfo->attr_rw_sysattr)))) {
5660 passtape();
5661 return (0);
5664 #endif
5666 /* sets *namep to point at the proper name */
5667 if (check_prefix(namep, dirp, component) != 0) {
5668 passtape();
5669 return (0);
5672 if (endtape()) {
5673 if (Bflag) {
5674 ssize_t sz;
5675 size_t extra_blocks = 0;
5678 * Logically at EOT - consume any extra blocks
5679 * so that write to our stdin won't fail and
5680 * emit an error message; otherwise something
5681 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5682 * will produce a bogus error message from "dd".
5685 while ((sz = read(mt, tbuf, TBLOCK*nblock)) > 0) {
5686 extra_blocks += sz;
5688 dlog("wantit(): %d bytes of extra blocks\n",
5689 extra_blocks);
5691 dlog("wantit(): at end of tape.\n");
5692 return (-1);
5695 gotit = 0;
5697 if ((Iflag && is_in_table(include_tbl, *namep)) ||
5698 (! Iflag && *argv == NULL)) {
5699 gotit = 1;
5700 } else {
5701 for (cp = argv; *cp; cp++) {
5702 if (is_prefix(*cp, *namep)) {
5703 gotit = 1;
5704 break;
5709 if (! gotit) {
5710 passtape();
5711 return (0);
5714 if (Xflag && is_in_table(exclude_tbl, *namep)) {
5715 if (vflag) {
5716 (void) fprintf(stderr, gettext("%s excluded\n"),
5717 *namep);
5719 passtape();
5720 return (0);
5723 return (1);
5727 static void
5728 setbytes_to_skip(struct stat *st, int err)
5731 * In a scenario where a typeflag 'X' was followed by
5732 * a typeflag 'A' and typeflag 'O', then the number of
5733 * bytes to skip should be the size of ancillary file,
5734 * plus the dblock for regular file, and the size
5735 * from Xtarhdr. However, if the typeflag was just 'X'
5736 * followed by typeflag 'O', then the number of bytes
5737 * to skip should be the size from Xtarhdr.
5739 if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
5740 (xhdr_flgs & _X_SIZE)) {
5741 st->st_size += TBLOCK + Xtarhdr.x_filesz;
5742 xhdr_flgs |= _X_XHDR;
5743 } else if ((dblock.dbuf.typeflag != 'A') &&
5744 (xhdr_flgs & _X_SIZE)) {
5745 st->st_size += Xtarhdr.x_filesz;
5746 xhdr_flgs |= _X_XHDR;
5750 static int
5751 fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
5752 int rw_sysattr, attr_data_t **attrinfo)
5754 size_t pathlen;
5755 char *tpath;
5756 char *tparent;
5758 /* parent info */
5759 if (attrparent != NULL) {
5760 if ((tparent = strdup(attrparent)) == NULL) {
5761 vperror(0, gettext(
5762 "unable to allocate memory for attribute parent "
5763 "name for %sattribute %s/%s of %s"),
5764 rw_sysattr ? gettext("system ") : "",
5765 attrparent, attr, longname);
5766 return (1);
5768 } else {
5769 tparent = NULL;
5772 /* path info */
5773 pathlen = strlen(attr) + 1;
5774 if (attrparent != NULL) {
5775 pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
5777 if ((tpath = calloc(1, pathlen)) == NULL) {
5778 vperror(0, gettext(
5779 "unable to allocate memory for full "
5780 "attribute path name for %sattribute %s%s%s of %s"),
5781 rw_sysattr ? gettext("system ") : "",
5782 (attrparent == NULL) ? "" : attrparent,
5783 (attrparent == NULL) ? "" : "/",
5784 attr, longname);
5785 if (tparent != NULL) {
5786 free(tparent);
5788 return (1);
5790 (void) snprintf(tpath, pathlen, "%s%s%s",
5791 (attrparent == NULL) ? "" : attrparent,
5792 (attrparent == NULL) ? "" : "/",
5793 attr);
5795 /* fill in the attribute info */
5796 if (*attrinfo == NULL) {
5797 if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
5798 vperror(0, gettext(
5799 "unable to allocate memory for attribute "
5800 "information for %sattribute %s%s%s of %s"),
5801 rw_sysattr ? gettext("system ") : "",
5802 (attrparent == NULL) ? "" : attrparent,
5803 (attrparent == NULL) ? "" : gettext("/"),
5804 attr, longname);
5805 if (tparent != NULL) {
5806 free(tparent);
5808 free(tpath);
5809 return (1);
5811 } else {
5812 if ((*attrinfo)->attr_parent != NULL) {
5813 free((*attrinfo)->attr_parent);
5815 if ((*attrinfo)->attr_path != NULL) {
5816 free((*attrinfo)->attr_path);
5819 * The parent file descriptor is passed in, so don't
5820 * close it here as it should be closed by the function
5821 * that opened it.
5824 (*attrinfo)->attr_parent = tparent;
5825 (*attrinfo)->attr_path = tpath;
5826 (*attrinfo)->attr_rw_sysattr = rw_sysattr;
5827 (*attrinfo)->attr_parentfd = atparentfd;
5829 return (0);
5833 * Test to see if name is a directory.
5835 * Return 1 if true, 0 otherwise.
5838 static int
5839 is_directory(char *name)
5841 #if defined(O_XATTR)
5843 * If there is an xattr_buf structure associated with this file,
5844 * then the directory test is based on whether the name has a
5845 * trailing slash.
5847 if (xattrp)
5848 return (name[strlen(name) - 1] == '/');
5849 #endif
5850 if (is_posix)
5851 return (dblock.dbuf.typeflag == '5');
5852 else
5853 return (name[strlen(name) - 1] == '/');
5857 * Version of chdir that handles directory pathnames of greater than PATH_MAX
5858 * length, by changing the working directory to manageable portions of the
5859 * complete directory pathname. If any of these attempts fail, then it exits
5860 * non-zero.
5862 * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
5863 * pathname is greater than PATH_MAX, then this still won't work, and this
5864 * routine will return -1 with errno set to ENAMETOOLONG.
5866 * NOTE: this routine is semantically different to the system chdir in
5867 * that it is remotely possible for the currently working directory to be
5868 * changed to a different directory, if a chdir call fails when processing
5869 * one of the segments of a path that is greater than PATH_MAX. This isn't
5870 * a problem as this is tar's own specific version of chdir.
5873 static int
5874 tar_chdir(const char *path)
5876 const char *sep = "/";
5877 char *path_copy = NULL;
5878 char *ptr = NULL;
5880 /* The trivial case. */
5881 if (chdir(path) == 0) {
5882 return (0);
5884 if (errno == ENAMETOOLONG) {
5885 if (path[0] == '/' && chdir(sep) != 0)
5886 return (-1);
5888 /* strtok(3C) modifies the string, so make a copy. */
5889 if ((path_copy = strdup(path)) == NULL) {
5890 return (-1);
5893 /* chdir(2) for every path element. */
5894 for (ptr = strtok(path_copy, sep);
5895 ptr != NULL;
5896 ptr = strtok(NULL, sep)) {
5897 if (chdir(ptr) != 0) {
5898 free(path_copy);
5899 return (-1);
5902 free(path_copy);
5903 return (0);
5906 /* If chdir fails for any reason except ENAMETOOLONG. */
5907 return (-1);
5911 * Test if name has a '..' sequence in it.
5913 * Return 1 if found, 0 otherwise.
5916 static int
5917 has_dot_dot(char *name)
5919 char *s;
5920 size_t name_len = strlen(name);
5922 for (s = name; s < (name + name_len - 2); s++) {
5923 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
5924 return (1);
5926 while (! (*s == '/')) {
5927 if (! *s++)
5928 return (0);
5932 return (0);
5936 * Test if name is an absolute path name.
5938 * Return 1 if true, 0 otherwise.
5941 static int
5942 is_absolute(char *name)
5944 #if defined(O_XATTR)
5946 * If this is an extended attribute (whose name will begin with
5947 * "/dev/null/", always return 0 as they should be extracted with
5948 * the name intact, to allow other tar archiving programs that
5949 * don't understand extended attributes, to correctly throw them away.
5951 if (xattrp)
5952 return (0);
5953 #endif
5955 return (name[0] == '/');
5959 * Adjust the pathname to make it a relative one. Strip off any leading
5960 * '/' characters and if the pathname contains any '..' sequences, strip
5961 * upto and including the last occurance of '../' (or '..' if found at
5962 * the very end of the pathname).
5964 * Return the relative pathname. stripped_prefix will also return the
5965 * portion of name that was stripped off and should be freed by the
5966 * calling routine when no longer needed.
5969 static char *
5970 make_relative_name(char *name, char **stripped_prefix)
5972 char *s;
5973 size_t prefix_len = 0;
5974 size_t name_len = strlen(name);
5976 for (s = name + prefix_len; s < (name + name_len - 2); ) {
5977 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
5978 prefix_len = s + 2 - name;
5980 do {
5981 char c = *s++;
5983 if (c == '/')
5984 break;
5985 } while (*s);
5988 for (s = name + prefix_len; *s == '/'; s++)
5989 continue;
5990 prefix_len = s - name;
5992 /* Create the portion of the name that was stripped off. */
5993 s = malloc(prefix_len + 1);
5994 memcpy(s, name, prefix_len);
5995 s[prefix_len] = 0;
5996 *stripped_prefix = s;
5997 s = &name[prefix_len];
5999 return (s);
6003 * Return through *namep a pointer to the proper fullname (i.e "<name> |
6004 * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6006 * Returns 0 if successful, otherwise returns 1.
6009 static int
6010 check_prefix(char **namep, char **dirp, char **compp)
6012 static char fullname[PATH_MAX + 1];
6013 static char dir[PATH_MAX + 1];
6014 static char component[PATH_MAX + 1];
6015 static char savename[PATH_MAX + 1];
6016 char *s;
6018 (void) memset(dir, 0, sizeof (dir));
6019 (void) memset(component, 0, sizeof (component));
6021 if (xhdr_flgs & _X_PATH) {
6022 (void) strcpy(fullname, Xtarhdr.x_path);
6023 } else {
6024 if (dblock.dbuf.prefix[0] != '\0')
6025 (void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
6026 dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
6027 else
6028 (void) sprintf(fullname, "%.*s", NAMSIZ,
6029 dblock.dbuf.name);
6033 * If we are printing a table of contents or extracting an archive,
6034 * make absolute pathnames relative and prohibit the unpacking of
6035 * files contain ".." in their name (unless the user has supplied
6036 * the -P option).
6038 if ((tflag || xflag) && !Pflag) {
6039 if (is_absolute(fullname) || has_dot_dot(fullname)) {
6040 char *stripped_prefix;
6042 (void) strcpy(savename, fullname);
6043 strcpy(fullname,
6044 make_relative_name(savename, &stripped_prefix));
6045 (void) fprintf(stderr,
6046 gettext("tar: Removing leading '%s' from '%s'\n"),
6047 stripped_prefix, savename);
6048 free(stripped_prefix);
6053 * Set dir and component names
6056 get_parent(fullname, dir);
6058 #if defined(O_XATTR)
6059 if (xattrp == NULL) {
6060 #endif
6062 * Save of real name since were going to chop off the
6063 * trailing slashes.
6065 (void) strcpy(savename, fullname);
6067 * first strip of trailing slashes.
6069 chop_endslashes(savename);
6070 s = get_component(savename);
6071 (void) strcpy(component, s);
6073 #if defined(O_XATTR)
6074 } else {
6075 (void) strcpy(fullname, xattrp->h_names);
6076 (void) strcpy(dir, fullname);
6077 (void) strcpy(component, basename(xattrp->h_names +
6078 strlen(xattrp->h_names) + 1));
6080 #endif
6081 *namep = fullname;
6082 *dirp = dir;
6083 *compp = component;
6085 return (0);
6089 * Return true if the object indicated by the file descriptor and type
6090 * is a tape device, false otherwise
6093 static int
6094 istape(int fd, int type)
6096 int result = 0;
6098 if (S_ISCHR(type)) {
6099 struct mtget mtg;
6101 if (ioctl(fd, MTIOCGET, &mtg) != -1) {
6102 result = 1;
6106 return (result);
6109 #include <utmpx.h>
6111 struct utmpx utmpx;
6113 #define NMAX (sizeof (utmpx.ut_name))
6115 typedef struct cachenode { /* this struct must be zeroed before using */
6116 struct cachenode *next; /* next in hash chain */
6117 int val; /* the uid or gid of this entry */
6118 int namehash; /* name's hash signature */
6119 char name[NMAX+1]; /* the string that val maps to */
6120 } cachenode_t;
6122 #define HASHSIZE 256
6124 static cachenode_t *names[HASHSIZE];
6125 static cachenode_t *groups[HASHSIZE];
6126 static cachenode_t *uids[HASHSIZE];
6127 static cachenode_t *gids[HASHSIZE];
6129 static int
6130 hash_byname(char *name)
6132 int i, c, h = 0;
6134 for (i = 0; i < NMAX; i++) {
6135 c = name[i];
6136 if (c == '\0')
6137 break;
6138 h = (h << 4) + h + c;
6140 return (h);
6143 static cachenode_t *
6144 hash_lookup_byval(cachenode_t *table[], int val)
6146 int h = val;
6147 cachenode_t *c;
6149 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6150 if (c->val == val)
6151 return (c);
6153 return (NULL);
6156 static cachenode_t *
6157 hash_lookup_byname(cachenode_t *table[], char *name)
6159 int h = hash_byname(name);
6160 cachenode_t *c;
6162 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6163 if (c->namehash == h && strcmp(c->name, name) == 0)
6164 return (c);
6166 return (NULL);
6169 static cachenode_t *
6170 hash_insert(cachenode_t *table[], char *name, int value)
6172 cachenode_t *c;
6173 int signature;
6175 c = calloc(1, sizeof (cachenode_t));
6176 if (c == NULL) {
6177 perror("malloc");
6178 exit(1);
6180 if (name != NULL) {
6181 (void) strncpy(c->name, name, NMAX);
6182 c->namehash = hash_byname(name);
6184 c->val = value;
6185 if (table == uids || table == gids)
6186 signature = c->val;
6187 else
6188 signature = c->namehash;
6189 c->next = table[signature & (HASHSIZE - 1)];
6190 table[signature & (HASHSIZE - 1)] = c;
6191 return (c);
6194 static char *
6195 getname(uid_t uid)
6197 cachenode_t *c;
6199 if ((c = hash_lookup_byval(uids, uid)) == NULL) {
6200 struct passwd *pwent = getpwuid(uid);
6201 c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
6203 return (c->name);
6206 static char *
6207 getgroup(gid_t gid)
6209 cachenode_t *c;
6211 if ((c = hash_lookup_byval(gids, gid)) == NULL) {
6212 struct group *grent = getgrgid(gid);
6213 c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
6215 return (c->name);
6218 static uid_t
6219 getuidbyname(char *name)
6221 cachenode_t *c;
6223 if ((c = hash_lookup_byname(names, name)) == NULL) {
6224 struct passwd *pwent = getpwnam(name);
6225 c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
6227 return ((uid_t)c->val);
6230 static gid_t
6231 getgidbyname(char *group)
6233 cachenode_t *c;
6235 if ((c = hash_lookup_byname(groups, group)) == NULL) {
6236 struct group *grent = getgrnam(group);
6237 c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
6239 return ((gid_t)c->val);
6243 * Build the header.
6244 * Determine whether or not an extended header is also needed. If needed,
6245 * create and write the extended header and its data.
6246 * Writing of the extended header assumes that "tomodes" has been called and
6247 * the relevant information has been placed in the header block.
6250 static int
6251 build_dblock(
6252 const char *name,
6253 const char *linkname,
6254 const char typeflag,
6255 const int filetype,
6256 const struct stat *sp,
6257 const dev_t device,
6258 const char *prefix)
6260 int nblks;
6261 major_t dev;
6262 const char *filename;
6263 const char *lastslash;
6265 if (filetype == XATTR_FILE)
6266 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
6267 else
6268 dblock.dbuf.typeflag = typeflag;
6269 (void) memset(dblock.dbuf.name, '\0', NAMSIZ);
6270 (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
6271 (void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
6273 if (xhdr_flgs & _X_PATH)
6274 filename = Xtarhdr.x_path;
6275 else
6276 filename = name;
6278 if ((dev = major(device)) > OCTAL7CHAR) {
6279 if (Eflag) {
6280 xhdr_flgs |= _X_DEVMAJOR;
6281 Xtarhdr.x_devmajor = dev;
6282 } else {
6283 (void) fprintf(stderr, gettext(
6284 "Device major too large for %s. Use -E flag."),
6285 filename);
6286 if (errflag)
6287 done(1);
6288 else
6289 Errflg = 1;
6291 dev = 0;
6293 (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
6294 if ((dev = minor(device)) > OCTAL7CHAR) {
6295 if (Eflag) {
6296 xhdr_flgs |= _X_DEVMINOR;
6297 Xtarhdr.x_devminor = dev;
6298 } else {
6299 (void) fprintf(stderr, gettext(
6300 "Device minor too large for %s. Use -E flag."),
6301 filename);
6302 if (errflag)
6303 done(1);
6304 else
6305 Errflg = 1;
6307 dev = 0;
6309 (void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
6311 (void) strncpy(dblock.dbuf.name, name, NAMSIZ);
6312 (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
6313 (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
6314 (void) sprintf(dblock.dbuf.version, "00");
6315 (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
6316 (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
6317 (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
6318 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
6320 if (Eflag) {
6321 (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
6322 (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
6323 lastslash = strrchr(name, '/');
6324 if (lastslash == NULL)
6325 lastslash = name;
6326 else
6327 lastslash++;
6328 (void) strcpy(xhdr_buf.dbuf.name, lastslash);
6329 (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
6330 (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
6331 (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
6332 xhdr_count++;
6333 xrec_offset = 0;
6334 gen_date("mtime", sp->st_mtim);
6335 xhdr_buf.dbuf.typeflag = 'X';
6336 if (gen_utf8_names(filename) != 0)
6337 return (1);
6339 #ifdef XHDR_DEBUG
6340 Xtarhdr.x_uname = dblock.dbuf.uname;
6341 Xtarhdr.x_gname = dblock.dbuf.gname;
6342 xhdr_flgs |= (_X_UNAME | _X_GNAME);
6343 #endif
6344 if (xhdr_flgs) {
6345 if (xhdr_flgs & _X_DEVMAJOR)
6346 gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
6347 if (xhdr_flgs & _X_DEVMINOR)
6348 gen_num("SUN.devminor", Xtarhdr.x_devminor);
6349 if (xhdr_flgs & _X_GID)
6350 gen_num("gid", Xtarhdr.x_gid);
6351 if (xhdr_flgs & _X_UID)
6352 gen_num("uid", Xtarhdr.x_uid);
6353 if (xhdr_flgs & _X_SIZE)
6354 gen_num("size", Xtarhdr.x_filesz);
6355 if (xhdr_flgs & _X_PATH)
6356 gen_string("path", Xtarhdr.x_path);
6357 if (xhdr_flgs & _X_LINKPATH)
6358 gen_string("linkpath", Xtarhdr.x_linkpath);
6359 if (xhdr_flgs & _X_GNAME)
6360 gen_string("gname", Xtarhdr.x_gname);
6361 if (xhdr_flgs & _X_UNAME)
6362 gen_string("uname", Xtarhdr.x_uname);
6364 (void) sprintf(xhdr_buf.dbuf.size,
6365 "%011" FMT_off_t_o, xrec_offset);
6366 (void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
6367 checksum(&xhdr_buf));
6368 (void) writetbuf((char *)&xhdr_buf, 1);
6369 nblks = TBLOCKS(xrec_offset);
6370 (void) writetbuf(xrec_ptr, nblks);
6372 return (0);
6377 * makeDir - ensure that a directory with the pathname denoted by name
6378 * exists, and return 1 on success, and 0 on failure (e.g.,
6379 * read-only file system, exists but not-a-directory).
6382 static int
6383 makeDir(char *name)
6385 struct stat buf;
6387 if (access(name, 0) < 0) { /* name doesn't exist */
6388 if (mkdir(name, 0777) < 0) {
6389 vperror(0, "%s", name);
6390 return (0);
6392 } else { /* name exists */
6393 if (stat(name, &buf) < 0) {
6394 vperror(0, "%s", name);
6395 return (0);
6398 return ((buf.st_mode & S_IFMT) == S_IFDIR);
6401 return (1);
6406 * Save this directory and its mtime on the stack, popping and setting
6407 * the mtimes of any stacked dirs which aren't parents of this one.
6408 * A null name causes the entire stack to be unwound and set.
6410 * Since all the elements of the directory "stack" share a common
6411 * prefix, we can make do with one string. We keep only the current
6412 * directory path, with an associated array of mtime's. A negative
6413 * mtime means no mtime.
6415 * This stack algorithm is not guaranteed to work for tapes created
6416 * with the 'r' function letter, but the vast majority of tapes with
6417 * directories are not. This avoids saving every directory record on
6418 * the tape and setting all the times at the end.
6420 * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6421 * environment)
6424 static void
6425 doDirTimes(char *name, timestruc_t modTime)
6427 static char dirstack[PATH_MAX+2];
6428 /* Add spaces for the last slash and last NULL */
6429 static timestruc_t modtimes[PATH_MAX+1]; /* hash table */
6430 char *p = dirstack;
6431 char *q = name;
6432 char *savp;
6434 if (q) {
6436 * Find common prefix
6439 while (*p == *q && *p) {
6440 p++; q++;
6444 savp = p;
6445 while (*p) {
6447 * Not a child: unwind the stack, setting the times.
6448 * The order we do this doesn't matter, so we go "forward."
6451 if (*p == '/')
6452 if (modtimes[p - dirstack].tv_sec >= 0) {
6453 *p = '\0'; /* zap the slash */
6454 setPathTimes(AT_FDCWD, dirstack,
6455 modtimes[p - dirstack]);
6456 *p = '/';
6458 ++p;
6461 p = savp;
6464 * Push this one on the "stack"
6467 if (q) {
6470 * Since the name parameter points the dir pathname
6471 * which is limited only to contain PATH_MAX chars
6472 * at maximum, we can ignore the overflow case of p.
6475 while ((*p = *q++)) { /* append the rest of the new dir */
6476 modtimes[p - dirstack].tv_sec = -1;
6477 p++;
6481 * If the tar file had used 'P' or 'E' function modifier,
6482 * append the last slash.
6484 if (*(p - 1) != '/') {
6485 *p++ = '/';
6486 *p = '\0';
6488 /* overwrite the last one */
6489 modtimes[p - dirstack - 1] = modTime;
6495 * setPathTimes - set the modification time for given path. Return 1 if
6496 * successful and 0 if not successful.
6499 static void
6500 setPathTimes(int dirfd, char *path, timestruc_t modTime)
6502 struct timeval timebuf[2];
6505 * futimesat takes an array of two timeval structs.
6506 * The first entry contains access time.
6507 * The second entry contains modification time.
6508 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6509 * microseconds.
6511 timebuf[0].tv_sec = time((time_t *)0);
6512 timebuf[0].tv_usec = 0;
6513 timebuf[1].tv_sec = modTime.tv_sec;
6515 /* Extended header: use microseconds */
6516 timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
6518 if (futimesat(dirfd, path, timebuf) < 0)
6519 vperror(0, gettext("can't set time on %s"), path);
6524 * If hflag is set then delete the symbolic link's target.
6525 * If !hflag then delete the target.
6528 static void
6529 delete_target(int fd, char *comp, char *namep)
6531 struct stat xtractbuf;
6532 char buf[PATH_MAX + 1];
6533 int n;
6536 if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
6537 if (errno == ENOTDIR && !hflag) {
6538 (void) unlinkat(fd, comp, 0);
6539 } else if (errno == ENOTDIR && hflag) {
6540 if (!lstat(namep, &xtractbuf)) {
6541 if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
6542 (void) unlinkat(fd, comp, 0);
6543 } else if ((n = readlink(namep, buf,
6544 PATH_MAX)) != -1) {
6545 buf[n] = '\0';
6546 (void) unlinkat(fd, buf,
6547 AT_REMOVEDIR);
6548 if (errno == ENOTDIR)
6549 (void) unlinkat(fd, buf, 0);
6550 } else {
6551 (void) unlinkat(fd, comp, 0);
6553 } else {
6554 (void) unlinkat(fd, comp, 0);
6562 * ACL changes:
6563 * putfile():
6564 * Get acl info after stat. Write out ancillary file
6565 * before the normal file, i.e. directory, regular, FIFO,
6566 * link, special. If acl count is less than 4, no need to
6567 * create ancillary file. (i.e. standard permission is in
6568 * use.
6569 * doxtract():
6570 * Process ancillary file. Read it in and set acl info.
6571 * watch out for 'o' function modifier.
6572 * 't' function letter to display table
6576 * New functions for ACLs and other security attributes
6580 * The function appends the new security attribute info to the end of
6581 * existing secinfo.
6584 append_secattr(
6585 char **secinfo, /* existing security info */
6586 int *secinfo_len, /* length of existing security info */
6587 int size, /* new attribute size: unit depends on type */
6588 char *attrtext, /* new attribute text */
6589 char attr_type) /* new attribute type */
6591 char *new_secinfo;
6592 int newattrsize;
6593 int oldsize;
6594 struct sec_attr *attr;
6596 if (attrtext == NULL)
6597 return (0);
6599 switch (attr_type) {
6600 case UFSD_ACL:
6601 case ACE_ACL:
6602 if (attrtext == NULL) {
6603 (void) fprintf(stderr, gettext("acltotext failed\n"));
6604 return (-1);
6606 /* header: type + size = 8 */
6607 newattrsize = 8 + (int)strlen(attrtext) + 1;
6608 attr = (struct sec_attr *)malloc(newattrsize);
6609 if (attr == NULL) {
6610 (void) fprintf(stderr,
6611 gettext("can't allocate memory\n"));
6612 return (-1);
6614 attr->attr_type = attr_type;
6615 (void) sprintf(attr->attr_len,
6616 "%06o", size); /* acl entry count */
6617 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6618 free(attrtext);
6619 break;
6620 default:
6621 (void) fprintf(stderr,
6622 gettext("unrecognized attribute type\n"));
6623 return (-1);
6626 /* old security info + new attr header(8) + new attr */
6627 oldsize = *secinfo_len;
6628 *secinfo_len += newattrsize;
6629 new_secinfo = (char *)malloc(*secinfo_len);
6630 if (new_secinfo == NULL) {
6631 (void) fprintf(stderr, gettext("can't allocate memory\n"));
6632 *secinfo_len -= newattrsize;
6633 free(attr);
6634 return (-1);
6637 (void) memcpy(new_secinfo, *secinfo, oldsize);
6638 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6640 free(*secinfo);
6641 free(attr);
6642 *secinfo = new_secinfo;
6643 return (0);
6647 * write_ancillary(): write out an ancillary file.
6648 * The file has the same header as normal file except the type and size
6649 * fields. The type is 'A' and size is the sum of all attributes
6650 * in bytes.
6651 * The body contains a list of attribute type, size and info. Currently,
6652 * there is only ACL info. This file is put before the normal file.
6654 void
6655 write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
6657 long blocks;
6658 int savflag;
6659 int savsize;
6661 /* Just tranditional permissions or no security attribute info */
6662 if (len == 0 || secinfo == NULL)
6663 return;
6665 /* save flag and size */
6666 savflag = (dblockp->dbuf).typeflag;
6667 (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
6669 /* special flag for ancillary file */
6670 if (hdrtype == _XATTR_HDRTYPE)
6671 dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
6672 else
6673 dblockp->dbuf.typeflag = 'A';
6675 /* for pre-2.5 versions of tar, need to make sure */
6676 /* the ACL file is readable */
6677 (void) sprintf(dblock.dbuf.mode, "%07lo",
6678 (stbuf.st_mode & POSIXMODES) | 0000200);
6679 (void) sprintf(dblockp->dbuf.size, "%011o", len);
6680 (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
6682 /* write out the header */
6683 (void) writetbuf((char *)dblockp, 1);
6685 /* write out security info */
6686 blocks = TBLOCKS(len);
6687 (void) writetbuf((char *)secinfo, (int)blocks);
6689 /* restore mode, flag and size */
6690 (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
6691 dblockp->dbuf.typeflag = savflag;
6692 (void) sprintf(dblockp->dbuf.size, "%011o", savsize);
6696 * Read the data record for extended headers and then the regular header.
6697 * The data are read into the buffer and then null-terminated. Entries
6698 * for typeflag 'X' extended headers are of the format:
6699 * "%d %s=%s\n"
6701 * When an extended header record is found, the extended header must
6702 * be processed and its values used to override the values in the
6703 * normal header. The way this is done is to process the extended
6704 * header data record and set the data values, then call getdir
6705 * to process the regular header, then then to reconcile the two
6706 * sets of data.
6709 static int
6710 get_xdata(void)
6712 struct keylist_pair {
6713 int keynum;
6714 char *keylist;
6715 } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor",
6716 _X_DEVMINOR, "SUN.devminor",
6717 _X_GID, "gid",
6718 _X_GNAME, "gname",
6719 _X_LINKPATH, "linkpath",
6720 _X_PATH, "path",
6721 _X_SIZE, "size",
6722 _X_UID, "uid",
6723 _X_UNAME, "uname",
6724 _X_MTIME, "mtime",
6725 _X_LAST, "NULL" };
6726 char *lineloc;
6727 int length, i;
6728 char *keyword, *value;
6729 blkcnt_t nblocks;
6730 int bufneeded;
6731 int errors;
6733 (void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
6734 xhdr_count++;
6735 errors = 0;
6737 nblocks = TBLOCKS(stbuf.st_size);
6738 bufneeded = nblocks * TBLOCK;
6739 if (bufneeded >= xrec_size) {
6740 free(xrec_ptr);
6741 xrec_size = bufneeded + 1;
6742 if ((xrec_ptr = malloc(xrec_size)) == NULL)
6743 fatal(gettext("cannot allocate buffer"));
6746 lineloc = xrec_ptr;
6748 while (nblocks-- > 0) {
6749 readtape(lineloc);
6750 lineloc += TBLOCK;
6752 lineloc = xrec_ptr;
6753 xrec_ptr[stbuf.st_size] = '\0';
6754 while (lineloc < xrec_ptr + stbuf.st_size) {
6755 if (dblock.dbuf.typeflag == 'L') {
6756 length = xrec_size;
6757 keyword = "path";
6758 value = lineloc;
6759 } else {
6760 length = atoi(lineloc);
6761 *(lineloc + length - 1) = '\0';
6762 keyword = strchr(lineloc, ' ') + 1;
6763 value = strchr(keyword, '=') + 1;
6764 *(value - 1) = '\0';
6766 i = 0;
6767 lineloc += length;
6768 while (keylist_pair[i].keynum != (int)_X_LAST) {
6769 if (strcmp(keyword, keylist_pair[i].keylist) == 0)
6770 break;
6771 i++;
6773 errno = 0;
6774 switch (keylist_pair[i].keynum) {
6775 case _X_DEVMAJOR:
6776 Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
6777 if (errno) {
6778 (void) fprintf(stderr, gettext(
6779 "tar: Extended header major value error "
6780 "for file # %llu.\n"), xhdr_count);
6781 errors++;
6782 } else
6783 xhdr_flgs |= _X_DEVMAJOR;
6784 break;
6785 case _X_DEVMINOR:
6786 Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
6787 if (errno) {
6788 (void) fprintf(stderr, gettext(
6789 "tar: Extended header minor value error "
6790 "for file # %llu.\n"), xhdr_count);
6791 errors++;
6792 } else
6793 xhdr_flgs |= _X_DEVMINOR;
6794 break;
6795 case _X_GID:
6796 xhdr_flgs |= _X_GID;
6797 Xtarhdr.x_gid = strtol(value, NULL, 0);
6798 if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
6799 (void) fprintf(stderr, gettext(
6800 "tar: Extended header gid value error "
6801 "for file # %llu.\n"), xhdr_count);
6802 Xtarhdr.x_gid = GID_NOBODY;
6804 break;
6805 case _X_GNAME:
6806 if (utf8_local("gname", &Xtarhdr.x_gname,
6807 local_gname, value, _POSIX_NAME_MAX) == 0)
6808 xhdr_flgs |= _X_GNAME;
6809 break;
6810 case _X_LINKPATH:
6811 if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
6812 local_linkpath, value, PATH_MAX) == 0)
6813 xhdr_flgs |= _X_LINKPATH;
6814 else
6815 errors++;
6816 break;
6817 case _X_PATH:
6818 if (utf8_local("path", &Xtarhdr.x_path,
6819 local_path, value, PATH_MAX) == 0)
6820 xhdr_flgs |= _X_PATH;
6821 else
6822 errors++;
6823 break;
6824 case _X_SIZE:
6825 Xtarhdr.x_filesz = strtoull(value, NULL, 0);
6826 if (errno) {
6827 (void) fprintf(stderr, gettext(
6828 "tar: Extended header invalid filesize "
6829 "for file # %llu.\n"), xhdr_count);
6830 errors++;
6831 } else
6832 xhdr_flgs |= _X_SIZE;
6833 break;
6834 case _X_UID:
6835 xhdr_flgs |= _X_UID;
6836 Xtarhdr.x_uid = strtol(value, NULL, 0);
6837 if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
6838 (void) fprintf(stderr, gettext(
6839 "tar: Extended header uid value error "
6840 "for file # %llu.\n"), xhdr_count);
6841 Xtarhdr.x_uid = UID_NOBODY;
6843 break;
6844 case _X_UNAME:
6845 if (utf8_local("uname", &Xtarhdr.x_uname,
6846 local_uname, value, _POSIX_NAME_MAX) == 0)
6847 xhdr_flgs |= _X_UNAME;
6848 break;
6849 case _X_MTIME:
6850 get_xtime(value, &(Xtarhdr.x_mtime));
6851 if (errno)
6852 (void) fprintf(stderr, gettext(
6853 "tar: Extended header modification time "
6854 "value error for file # %llu.\n"),
6855 xhdr_count);
6856 else
6857 xhdr_flgs |= _X_MTIME;
6858 break;
6859 default:
6860 (void) fprintf(stderr,
6861 gettext("tar: unrecognized extended"
6862 " header keyword '%s'. Ignored.\n"), keyword);
6863 break;
6867 getdir(); /* get regular header */
6868 if (errors && errflag)
6869 done(1);
6870 else
6871 if (errors)
6872 Errflg = 1;
6873 return (errors);
6877 * load_info_from_xtarhdr - sets Gen and stbuf variables from
6878 * extended header
6879 * load_info_from_xtarhdr(flag, xhdrp);
6880 * u_longlong_t flag; xhdr_flgs
6881 * struct xtar_hdr *xhdrp; pointer to extended header
6882 * NOTE: called when typeflag is not 'A' and xhdr_flgs
6883 * is set.
6885 static void
6886 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
6888 if (flag & _X_DEVMAJOR) {
6889 Gen.g_devmajor = xhdrp->x_devmajor;
6891 if (flag & _X_DEVMINOR) {
6892 Gen.g_devminor = xhdrp->x_devminor;
6894 if (flag & _X_GID) {
6895 Gen.g_gid = xhdrp->x_gid;
6896 stbuf.st_gid = xhdrp->x_gid;
6898 if (flag & _X_UID) {
6899 Gen.g_uid = xhdrp->x_uid;
6900 stbuf.st_uid = xhdrp->x_uid;
6902 if (flag & _X_SIZE) {
6903 Gen.g_filesz = xhdrp->x_filesz;
6904 stbuf.st_size = xhdrp->x_filesz;
6906 if (flag & _X_MTIME) {
6907 Gen.g_mtime = xhdrp->x_mtime.tv_sec;
6908 stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
6909 stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
6914 * gen_num creates a string from a keyword and an usigned long long in the
6915 * format: %d %s=%s\n
6916 * This is part of the extended header data record.
6919 void
6920 gen_num(const char *keyword, const u_longlong_t number)
6922 char save_val[ULONGLONG_MAX_DIGITS + 1];
6923 int len;
6924 char *curr_ptr;
6926 (void) sprintf(save_val, "%llu", number);
6928 * len = length of entire line, including itself. len will be
6929 * two digits. So, add the string lengths plus the length of len,
6930 * plus a blank, an equal sign, and a newline.
6932 len = strlen(save_val) + strlen(keyword) + 5;
6933 if (xrec_offset + len > xrec_size) {
6934 if (((curr_ptr = reallocarray(xrec_ptr, 2, xrec_size)) == NULL))
6935 fatal(gettext(
6936 "cannot allocate extended header buffer"));
6937 xrec_ptr = curr_ptr;
6938 xrec_size *= 2;
6940 (void) sprintf(&xrec_ptr[xrec_offset],
6941 "%d %s=%s\n", len, keyword, save_val);
6942 xrec_offset += len;
6946 * gen_date creates a string from a keyword and a timestruc_t in the
6947 * format: %d %s=%s\n
6948 * This is part of the extended header data record.
6949 * Currently, granularity is only microseconds, so the low-order three digits
6950 * will be truncated.
6953 void
6954 gen_date(const char *keyword, const timestruc_t time_value)
6956 /* Allow for <seconds>.<nanoseconds>\n */
6957 char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
6958 int len;
6959 char *curr_ptr;
6961 (void) sprintf(save_val, "%ld", time_value.tv_sec);
6962 len = strlen(save_val);
6963 save_val[len] = '.';
6964 (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
6967 * len = length of entire line, including itself. len will be
6968 * two digits. So, add the string lengths plus the length of len,
6969 * plus a blank, an equal sign, and a newline.
6971 len = strlen(save_val) + strlen(keyword) + 5;
6972 if (xrec_offset + len > xrec_size) {
6973 if (((curr_ptr = reallocarray(xrec_ptr, 2, xrec_size)) == NULL))
6974 fatal(gettext(
6975 "cannot allocate extended header buffer"));
6976 xrec_ptr = curr_ptr;
6977 xrec_size *= 2;
6979 (void) sprintf(&xrec_ptr[xrec_offset],
6980 "%d %s=%s\n", len, keyword, save_val);
6981 xrec_offset += len;
6985 * gen_string creates a string from a keyword and a char * in the
6986 * format: %d %s=%s\n
6987 * This is part of the extended header data record.
6990 void
6991 gen_string(const char *keyword, const char *value)
6993 int len;
6994 char *curr_ptr;
6997 * len = length of entire line, including itself. The character length
6998 * of len must be 1-4 characters, because the maximum size of the path
6999 * or the name is PATH_MAX, which is 1024. So, assume 1 character
7000 * for len, one for the space, one for the "=", and one for the newline.
7001 * Then adjust as needed.
7003 /* LINTED constant expression */
7004 assert(PATH_MAX <= 9996);
7005 len = strlen(value) + strlen(keyword) + 4;
7006 if (len > 997)
7007 len += 3;
7008 else if (len > 98)
7009 len += 2;
7010 else if (len > 9)
7011 len += 1;
7012 if (xrec_offset + len > xrec_size) {
7013 if (((curr_ptr = reallocarray(xrec_ptr, 2, xrec_size)) == NULL))
7014 fatal(gettext(
7015 "cannot allocate extended header buffer"));
7016 xrec_ptr = curr_ptr;
7017 xrec_size *= 2;
7019 #ifdef XHDR_DEBUG
7020 if (strcmp(keyword+1, "name") != 0)
7021 #endif
7022 (void) sprintf(&xrec_ptr[xrec_offset],
7023 "%d %s=%s\n", len, keyword, value);
7024 #ifdef XHDR_DEBUG
7025 else {
7026 len += 11;
7027 (void) sprintf(&xrec_ptr[xrec_offset],
7028 "%d %s=%snametoolong\n", len, keyword, value);
7030 #endif
7031 xrec_offset += len;
7035 * Convert time found in the extended header data to seconds and nanoseconds.
7038 void
7039 get_xtime(char *value, timestruc_t *xtime)
7041 char nanosec[10];
7042 char *period;
7043 int i;
7045 (void) memset(nanosec, '0', 9);
7046 nanosec[9] = '\0';
7048 period = strchr(value, '.');
7049 if (period != NULL)
7050 period[0] = '\0';
7051 xtime->tv_sec = strtol(value, NULL, 10);
7052 if (period == NULL)
7053 xtime->tv_nsec = 0;
7054 else {
7055 i = strlen(period +1);
7056 (void) strncpy(nanosec, period + 1, min(i, 9));
7057 xtime->tv_nsec = strtol(nanosec, NULL, 10);
7062 * Check linkpath for length.
7063 * Emit an error message and return 1 if too long.
7067 chk_path_build(
7068 char *name,
7069 char *longname,
7070 char *linkname,
7071 char *prefix,
7072 char type,
7073 int filetype)
7076 if (strlen(linkname) > (size_t)NAMSIZ) {
7077 if (Eflag > 0) {
7078 xhdr_flgs |= _X_LINKPATH;
7079 Xtarhdr.x_linkpath = linkname;
7080 } else {
7081 (void) fprintf(stderr, gettext(
7082 "tar: %s: linked to %s\n"), longname, linkname);
7083 (void) fprintf(stderr, gettext(
7084 "tar: %s: linked name too long\n"), linkname);
7085 if (errflag)
7086 done(1);
7087 else
7088 Errflg = 1;
7089 return (1);
7092 if (xhdr_flgs & _X_LINKPATH)
7093 return (build_dblock(name, tchar, type,
7094 filetype, &stbuf, stbuf.st_dev,
7095 prefix));
7096 else
7097 return (build_dblock(name, linkname, type,
7098 filetype, &stbuf, stbuf.st_dev, prefix));
7102 * Convert from UTF-8 to local character set.
7105 static int
7106 utf8_local(
7107 char *option,
7108 char **Xhdr_ptrptr,
7109 char *target,
7110 const char *source,
7111 int max_val)
7113 static iconv_t iconv_cd;
7114 char *nl_target;
7115 const char *iconv_src;
7116 char *iconv_trg;
7117 size_t inlen;
7118 size_t outlen;
7120 if (charset_type == -1) { /* iconv_open failed in earlier try */
7121 (void) fprintf(stderr, gettext(
7122 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7123 xhdr_count, source);
7124 return (1);
7125 } else if (charset_type == 0) { /* iconv_open has not yet been done */
7126 nl_target = nl_langinfo(CODESET);
7127 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7128 nl_target = "US-ASCII";
7129 if (strcmp(nl_target, "US-ASCII") == 0)
7130 charset_type = 1;
7131 else if (strcmp(nl_target, "UTF-8") == 0)
7132 charset_type = 3;
7133 else {
7134 if (strncmp(nl_target, "ISO", 3) == 0)
7135 nl_target += 3;
7136 charset_type = 2;
7137 errno = 0;
7138 if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
7139 (iconv_t)-1) {
7140 if (errno == EINVAL)
7141 (void) fprintf(stderr, gettext(
7142 "tar: conversion routines not "
7143 "available for current locale. "));
7144 (void) fprintf(stderr, gettext(
7145 "file # %llu: (%s) UTF-8 conversion"
7146 " failed.\n"), xhdr_count, source);
7147 charset_type = -1;
7148 return (1);
7153 /* locale using 7-bit codeset or UTF-8 locale */
7154 if (charset_type == 1 || charset_type == 3) {
7155 if (strlen(source) > max_val) {
7156 (void) fprintf(stderr, gettext(
7157 "tar: file # %llu: Extended header %s too long.\n"),
7158 xhdr_count, option);
7159 return (1);
7161 if (charset_type == 3)
7162 (void) strcpy(target, source);
7163 else if (c_utf8(target, source) != 0) {
7164 (void) fprintf(stderr, gettext(
7165 "tar: file # %llu: (%s) UTF-8 conversion"
7166 " failed.\n"), xhdr_count, source);
7167 return (1);
7169 *Xhdr_ptrptr = target;
7170 return (0);
7173 iconv_src = source;
7174 iconv_trg = target;
7175 inlen = strlen(source);
7176 outlen = max_val * UTF_8_FACTOR;
7177 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7178 (size_t)-1) { /* Error occurred: didn't convert */
7179 (void) fprintf(stderr, gettext(
7180 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7181 xhdr_count, source);
7182 /* Get remaining output; reinitialize conversion descriptor */
7183 iconv_src = (const char *)NULL;
7184 inlen = 0;
7185 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7186 return (1);
7188 /* Get remaining output; reinitialize conversion descriptor */
7189 iconv_src = (const char *)NULL;
7190 inlen = 0;
7191 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7192 (size_t)-1) { /* Error occurred: didn't convert */
7193 (void) fprintf(stderr, gettext(
7194 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7195 xhdr_count, source);
7196 return (1);
7199 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7200 if (strlen(target) > max_val) {
7201 (void) fprintf(stderr, gettext(
7202 "tar: file # %llu: Extended header %s too long.\n"),
7203 xhdr_count, option);
7204 return (1);
7206 *Xhdr_ptrptr = target;
7207 return (0);
7211 * Check gname, uname, path, and linkpath to see if they need to go in an
7212 * extended header. If they are already slated to be in an extended header,
7213 * or if they are not ascii, then they need to be in the extended header.
7214 * Then, convert all extended names to UTF-8.
7218 gen_utf8_names(const char *filename)
7220 static iconv_t iconv_cd;
7221 char *nl_target;
7222 char tempbuf[MAXNAM + 1];
7223 int nbytes;
7224 int errors;
7226 if (charset_type == -1) { /* Previous failure to open. */
7227 (void) fprintf(stderr, gettext(
7228 "tar: file # %llu: UTF-8 conversion failed.\n"),
7229 xhdr_count);
7230 return (1);
7233 if (charset_type == 0) { /* Need to get conversion descriptor */
7234 nl_target = nl_langinfo(CODESET);
7235 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7236 nl_target = "US-ASCII";
7237 if (strcmp(nl_target, "US-ASCII") == 0)
7238 charset_type = 1;
7239 else if (strcmp(nl_target, "UTF-8") == 0)
7240 charset_type = 3;
7241 else {
7242 if (strncmp(nl_target, "ISO", 3) == 0)
7243 nl_target += 3;
7244 charset_type = 2;
7245 errno = 0;
7246 #ifdef ICONV_DEBUG
7247 (void) fprintf(stderr,
7248 gettext("Opening iconv_cd with target %s\n"),
7249 nl_target);
7250 #endif
7251 if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
7252 (iconv_t)-1) {
7253 if (errno == EINVAL)
7254 (void) fprintf(stderr, gettext(
7255 "tar: conversion routines not "
7256 "available for current locale. "));
7257 (void) fprintf(stderr, gettext(
7258 "file (%s): UTF-8 conversion failed.\n"),
7259 filename);
7260 charset_type = -1;
7261 return (1);
7266 errors = 0;
7268 errors += local_utf8(&Xtarhdr.x_gname, local_gname,
7269 dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
7270 errors += local_utf8(&Xtarhdr.x_uname, local_uname,
7271 dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX);
7272 if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */
7273 (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
7274 tempbuf[NAMSIZ] = '\0';
7276 errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
7277 tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
7278 if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */
7279 (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
7280 tempbuf[PRESIZ] = '\0';
7281 nbytes = strlen(tempbuf);
7282 if (nbytes > 0) {
7283 tempbuf[nbytes++] = '/';
7284 tempbuf[nbytes] = '\0';
7286 (void) strncat(tempbuf + nbytes, dblock.dbuf.name,
7287 (MAXNAM - nbytes));
7288 tempbuf[MAXNAM] = '\0';
7290 errors += local_utf8(&Xtarhdr.x_path, local_path,
7291 tempbuf, iconv_cd, _X_PATH, PATH_MAX);
7293 if (errors > 0)
7294 (void) fprintf(stderr, gettext(
7295 "tar: file (%s): UTF-8 conversion failed.\n"), filename);
7297 if (errors && errflag)
7298 done(1);
7299 else
7300 if (errors)
7301 Errflg = 1;
7302 return (errors);
7305 static int
7306 local_utf8(
7307 char **Xhdr_ptrptr,
7308 char *target,
7309 const char *source,
7310 iconv_t iconv_cd,
7311 int xhdrflg,
7312 int max_val)
7314 const char *iconv_src;
7315 const char *starting_src;
7316 char *iconv_trg;
7317 size_t inlen;
7318 size_t outlen;
7319 #ifdef ICONV_DEBUG
7320 unsigned char c_to_hex;
7321 #endif
7324 * If the item is already slated for extended format, get the string
7325 * to convert from the extended header record. Otherwise, get it from
7326 * the regular (dblock) area.
7328 if (xhdr_flgs & xhdrflg) {
7329 if (charset_type == 3) { /* Already UTF-8, just copy */
7330 (void) strcpy(target, *Xhdr_ptrptr);
7331 *Xhdr_ptrptr = target;
7332 return (0);
7333 } else
7334 iconv_src = (const char *) *Xhdr_ptrptr;
7335 } else {
7336 if (charset_type == 3) /* Already in UTF-8 format */
7337 return (0); /* Don't create xhdr record */
7338 iconv_src = source;
7340 starting_src = iconv_src;
7341 iconv_trg = target;
7342 if ((inlen = strlen(iconv_src)) == 0)
7343 return (0);
7345 if (charset_type == 1) { /* locale using 7-bit codeset */
7346 if (c_utf8(target, starting_src) != 0) {
7347 (void) fprintf(stderr,
7348 gettext("tar: invalid character in"
7349 " UTF-8 conversion of '%s'\n"), starting_src);
7350 return (1);
7352 return (0);
7355 outlen = max_val * UTF_8_FACTOR;
7356 errno = 0;
7357 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7358 (size_t)-1) {
7359 /* An error occurred, or not all characters were converted */
7360 if (errno == EILSEQ)
7361 (void) fprintf(stderr,
7362 gettext("tar: invalid character in"
7363 " UTF-8 conversion of '%s'\n"), starting_src);
7364 else
7365 (void) fprintf(stderr, gettext(
7366 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7367 starting_src);
7368 /* Get remaining output; reinitialize conversion descriptor */
7369 iconv_src = (const char *)NULL;
7370 inlen = 0;
7371 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7372 return (1);
7374 /* Get remaining output; reinitialize conversion descriptor */
7375 iconv_src = (const char *)NULL;
7376 inlen = 0;
7377 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7378 (size_t)-1) { /* Error occurred: didn't convert */
7379 if (errno == EILSEQ)
7380 (void) fprintf(stderr,
7381 gettext("tar: invalid character in"
7382 " UTF-8 conversion of '%s'\n"), starting_src);
7383 else
7384 (void) fprintf(stderr, gettext(
7385 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7386 starting_src);
7387 return (1);
7390 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7391 if (strcmp(starting_src, target) != 0) {
7392 *Xhdr_ptrptr = target;
7393 xhdr_flgs |= xhdrflg;
7394 #ifdef ICONV_DEBUG
7395 (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n",
7396 strlen(starting_src), inlen, max_val, outlen);
7397 (void) fprintf(stderr, "Input string:\n ");
7398 for (inlen = 0; inlen < strlen(starting_src); inlen++) {
7399 c_to_hex = (unsigned char)starting_src[inlen];
7400 (void) fprintf(stderr, " %2.2x", c_to_hex);
7401 if (inlen % 20 == 19)
7402 (void) fprintf(stderr, "\n ");
7404 (void) fprintf(stderr, "\nOutput string:\n ");
7405 for (inlen = 0; inlen < strlen(target); inlen++) {
7406 c_to_hex = (unsigned char)target[inlen];
7407 (void) fprintf(stderr, " %2.2x", c_to_hex);
7408 if (inlen % 20 == 19)
7409 (void) fprintf(stderr, "\n ");
7411 (void) fprintf(stderr, "\n");
7412 #endif
7415 return (0);
7419 * Function to test each byte of the source string to make sure it is
7420 * in within bounds (value between 0 and 127).
7421 * If valid, copy source to target.
7425 c_utf8(char *target, const char *source)
7427 size_t len;
7428 const char *thischar;
7430 len = strlen(source);
7431 thischar = source;
7432 while (len-- > 0) {
7433 if (!isascii((int)(*thischar++)))
7434 return (1);
7437 (void) strcpy(target, source);
7438 return (0);
7442 #if defined(O_XATTR)
7443 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
7445 static void
7446 prepare_xattr(
7447 char **attrbuf,
7448 char *filename,
7449 char *attrpath,
7450 char typeflag,
7451 struct linkbuf *linkinfo,
7452 int *rlen)
7454 char *bufhead; /* ptr to full buffer */
7455 char *aptr;
7456 struct xattr_hdr *hptr; /* ptr to header in bufhead */
7457 struct xattr_buf *tptr; /* ptr to pathing pieces */
7458 int totalen; /* total buffer length */
7459 int len; /* length returned to user */
7460 int stringlen; /* length of filename + attr */
7462 * length of filename + attr
7463 * in link section
7465 int linkstringlen;
7466 int complen; /* length of pathing section */
7467 int linklen; /* length of link section */
7468 int attrnames_index; /* attrnames starting index */
7471 * Release previous buffer
7474 if (*attrbuf != NULL) {
7475 free(*attrbuf);
7476 *attrbuf = NULL;
7480 * First add in fixed size stuff
7482 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7485 * Add space for two nulls
7487 stringlen = strlen(attrpath) + strlen(filename) + 2;
7488 complen = stringlen + sizeof (struct xattr_buf);
7490 len += stringlen;
7493 * Now add on space for link info if any
7496 if (linkinfo != NULL) {
7498 * Again add space for two nulls
7500 linkstringlen = strlen(linkinfo->pathname) +
7501 strlen(linkinfo->attrname) + 2;
7502 linklen = linkstringlen + sizeof (struct xattr_buf);
7503 len += linklen;
7504 } else {
7505 linklen = 0;
7509 * Now add padding to end to fill out TBLOCK
7511 * Function returns size of real data and not size + padding.
7514 totalen = ROUNDTOTBLOCK(len);
7516 if ((bufhead = calloc(1, totalen)) == NULL) {
7517 fatal(gettext("Out of memory."));
7522 * Now we can fill in the necessary pieces
7526 * first fill in the fixed header
7528 hptr = (struct xattr_hdr *)bufhead;
7529 (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7530 (void) sprintf(hptr->h_component_len, "%0*d",
7531 sizeof (hptr->h_component_len) - 1, complen);
7532 (void) sprintf(hptr->h_link_component_len, "%0*d",
7533 sizeof (hptr->h_link_component_len) - 1, linklen);
7534 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7537 * Now fill in the filename + attrnames section
7538 * The filename and attrnames section can be composed of two or more
7539 * path segments separated by a null character. The first segment
7540 * is the path to the parent file that roots the entire sequence in
7541 * the normal name space. The remaining segments describes a path
7542 * rooted at the hidden extended attribute directory of the leaf file of
7543 * the previous segment, making it possible to name attributes on
7544 * attributes. Thus, if we are just archiving an extended attribute,
7545 * the second segment will contain the attribute name. If we are
7546 * archiving a system attribute of an extended attribute, then the
7547 * second segment will contain the attribute name, and a third segment
7548 * will contain the system attribute name. The attribute pathing
7549 * information is obtained from 'attrpath'.
7552 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7553 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7554 stringlen);
7555 (void) strcpy(tptr->h_names, filename);
7556 attrnames_index = strlen(filename) + 1;
7557 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
7558 tptr->h_typeflag = typeflag;
7561 * Split the attrnames section into two segments if 'attrpath'
7562 * contains pathing information for a system attribute of an
7563 * extended attribute. We split them by replacing the '/' with
7564 * a '\0'.
7566 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
7567 *aptr = '\0';
7571 * Now fill in the optional link section if we have one
7574 if (linkinfo != NULL) {
7575 tptr = (struct xattr_buf *)(bufhead +
7576 sizeof (struct xattr_hdr) + complen);
7578 (void) sprintf(tptr->h_namesz, "%0*d",
7579 sizeof (tptr->h_namesz) - 1, linkstringlen);
7580 (void) strcpy(tptr->h_names, linkinfo->pathname);
7581 (void) strcpy(
7582 &tptr->h_names[strlen(linkinfo->pathname) + 1],
7583 linkinfo->attrname);
7584 tptr->h_typeflag = typeflag;
7586 *attrbuf = (char *)bufhead;
7587 *rlen = len;
7590 #else
7591 static void
7592 prepare_xattr(
7593 char **attrbuf,
7594 char *filename,
7595 char *attrname,
7596 char typeflag,
7597 struct linkbuf *linkinfo,
7598 int *rlen)
7600 *attrbuf = NULL;
7601 *rlen = 0;
7603 #endif
7606 getstat(int dirfd, char *longname, char *shortname, char *attrparent)
7609 int i, j;
7610 int printerr;
7611 int slnkerr;
7612 struct stat symlnbuf;
7614 if (!hflag)
7615 i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
7616 else
7617 i = fstatat(dirfd, shortname, &stbuf, 0);
7619 if (i < 0) {
7620 /* Initialize flag to print error mesg. */
7621 printerr = 1;
7623 * If stat is done, then need to do lstat
7624 * to determine whether it's a sym link
7626 if (hflag) {
7627 /* Save returned error */
7628 slnkerr = errno;
7630 j = fstatat(dirfd, shortname,
7631 &symlnbuf, AT_SYMLINK_NOFOLLOW);
7633 * Suppress error message when file is a symbolic link
7634 * and function modifier 'l' is off. Exception: when
7635 * a symlink points to a symlink points to a
7636 * symlink ... and we get past MAXSYMLINKS. That
7637 * error will cause a file not to be archived, and
7638 * needs to be printed.
7640 if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
7641 (S_ISLNK(symlnbuf.st_mode)))
7642 printerr = 0;
7645 * Restore errno in case the lstat
7646 * on symbolic link change
7648 errno = slnkerr;
7651 if (printerr) {
7652 (void) fprintf(stderr, gettext(
7653 "tar: %s%s%s%s: %s\n"),
7654 (attrparent == NULL) ? "" : gettext("attribute "),
7655 (attrparent == NULL) ? "" : attrparent,
7656 (attrparent == NULL) ? "" : gettext(" of "),
7657 longname, strerror(errno));
7658 Errflg = 1;
7660 return (1);
7662 return (0);
7666 * Recursively archive the extended attributes and/or extended system attributes
7667 * of the base file, longname. Note: extended system attribute files will be
7668 * archived only if the extended system attributes are not transient (i.e. the
7669 * extended system attributes are other than the default values).
7671 * If -@ was specified and the underlying file system supports it, archive the
7672 * extended attributes, and if there is a system attribute associated with the
7673 * extended attribute, then recursively call xattrs_put() to archive the
7674 * hidden attribute directory and the extended system attribute. If -/ was
7675 * specified and the underlying file system supports it, archive the extended
7676 * system attributes. Read-only extended system attributes are never archived.
7678 * Currently, there cannot be attributes on attributes; only system
7679 * attributes on attributes. In addition, there cannot be attributes on
7680 * system attributes. A file and it's attribute directory hierarchy looks as
7681 * follows:
7682 * longname ----> . ("." is the hidden attribute directory)
7684 * ----------------------------
7685 * | |
7686 * <sys_attr_name> <attr_name> ----> .
7688 * <sys_attr_name>
7691 #if defined(O_XATTR)
7692 static void
7693 xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
7695 char *filename = (attrparent == NULL) ? shortname : attrparent;
7696 int arc_rwsysattr = 0;
7697 int dirfd;
7698 int fd = -1;
7699 int rw_sysattr = 0;
7700 int ext_attr = 0;
7701 int rc;
7702 DIR *dirp;
7703 struct dirent *dp;
7704 attr_data_t *attrinfo = NULL;
7707 * If the underlying file system supports it, then archive the extended
7708 * attributes if -@ was specified, and the extended system attributes
7709 * if -/ was specified.
7711 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
7712 &ext_attr) != ATTR_OK) {
7713 return;
7717 * Only want to archive a read-write extended system attribute file
7718 * if it contains extended system attribute settings that are not the
7719 * default values.
7721 #if defined(_PC_SATTR_ENABLED)
7722 if (saflag) {
7723 int filefd;
7724 nvlist_t *slist = NULL;
7726 /* Determine if there are non-transient system attributes */
7727 errno = 0;
7728 if ((filefd = open(filename, O_RDONLY)) == -1) {
7729 if (attrparent == NULL) {
7730 vperror(0, gettext(
7731 "unable to open file %s"), longname);
7733 return;
7735 if (((slist = sysattr_list(basename(myname), filefd,
7736 filename)) != NULL) || (errno != 0)) {
7737 arc_rwsysattr = 1;
7739 if (slist != NULL) {
7740 (void) nvlist_free(slist);
7741 slist = NULL;
7743 (void) close(filefd);
7747 * If we aren't archiving extended system attributes, and we are
7748 * processing an attribute, or if we are archiving extended system
7749 * attributes, and there are are no extended attributes, then there's
7750 * no need to open up the attribute directory of the file unless the
7751 * extended system attributes are not transient (i.e, the system
7752 * attributes are not the default values).
7754 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
7755 (saflag && !ext_attr))) {
7756 return;
7758 #endif /* _PC_SATTR_ENABLED */
7760 /* open the parent attribute directory */
7761 fd = attropen(filename, ".", O_RDONLY);
7762 if (fd < 0) {
7763 vperror(0, gettext(
7764 "unable to open attribute directory for %s%s%sfile %s"),
7765 (attrparent == NULL) ? "" : gettext("attribute "),
7766 (attrparent == NULL) ? "" : attrparent,
7767 (attrparent == NULL) ? "" : gettext(" of "),
7768 longname);
7769 return;
7773 * We need to change into the parent's attribute directory to determine
7774 * if each of the attributes should be archived.
7776 if (fchdir(fd) < 0) {
7777 vperror(0, gettext(
7778 "cannot change to attribute directory of %s%s%sfile %s"),
7779 (attrparent == NULL) ? "" : gettext("attribute "),
7780 (attrparent == NULL) ? "" : attrparent,
7781 (attrparent == NULL) ? "" : gettext(" of "),
7782 longname);
7783 (void) close(fd);
7784 return;
7787 if (((dirfd = dup(fd)) == -1) ||
7788 ((dirp = fdopendir(dirfd)) == NULL)) {
7789 (void) fprintf(stderr, gettext(
7790 "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7791 (attrparent == NULL) ? "" : gettext("attribute "),
7792 (attrparent == NULL) ? "" : attrparent,
7793 (attrparent == NULL) ? "" : gettext(" of "),
7794 longname);
7795 if (fd > 0) {
7796 (void) close(fd);
7798 return;
7801 while ((dp = readdir(dirp)) != NULL) {
7802 if (strcmp(dp->d_name, "..") == 0) {
7803 continue;
7804 } else if (strcmp(dp->d_name, ".") == 0) {
7805 Hiddendir = 1;
7806 } else {
7807 Hiddendir = 0;
7810 /* Determine if this attribute should be archived */
7811 if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
7812 &rw_sysattr) != ATTR_OK) {
7813 continue;
7816 /* gather the attribute's information to pass to putfile() */
7817 if ((fill_in_attr_info(dp->d_name, longname, attrparent,
7818 fd, rw_sysattr, &attrinfo)) == 1) {
7819 continue;
7822 /* add the attribute to the archive */
7823 rc = putfile(longname, dp->d_name, parent, attrinfo,
7824 XATTR_FILE, LEV0, SYMLINK_LEV0);
7826 if (exitflag) {
7827 break;
7830 #if defined(_PC_SATTR_ENABLED)
7832 * If both -/ and -@ were specified, then archive the
7833 * attribute's extended system attributes and hidden directory
7834 * by making a recursive call to xattrs_put().
7836 if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
7837 (Hiddendir == 0)) {
7839 xattrs_put(longname, shortname, parent, dp->d_name);
7842 * Change back to the parent's attribute directory
7843 * to process any further attributes.
7845 if (fchdir(fd) < 0) {
7846 vperror(0, gettext(
7847 "cannot change back to attribute directory "
7848 "of file %s"), longname);
7849 break;
7852 #endif /* _PC_SATTR_ENABLED */
7855 if (attrinfo != NULL) {
7856 if (attrinfo->attr_parent != NULL) {
7857 free(attrinfo->attr_parent);
7859 free(attrinfo->attr_path);
7860 free(attrinfo);
7862 (void) closedir(dirp);
7863 if (fd != -1) {
7864 (void) close(fd);
7867 /* Change back to the parent directory of the base file */
7868 if (attrparent == NULL) {
7869 (void) tar_chdir(parent);
7871 Hiddendir = 0;
7873 #else
7874 static void
7875 xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
7878 #endif /* O_XATTR */
7880 static int
7881 put_link(char *name, char *longname, char *component, char *longattrname,
7882 char *prefix, int filetype, char type)
7885 if (stbuf.st_nlink > 1) {
7886 struct linkbuf *lp;
7887 int found = 0;
7889 for (lp = ihead; lp != NULL; lp = lp->nextp)
7890 if (lp->inum == stbuf.st_ino &&
7891 lp->devnum == stbuf.st_dev) {
7892 found++;
7893 break;
7895 if (found) {
7896 #if defined(O_XATTR)
7897 if (filetype == XATTR_FILE)
7898 if (put_xattr_hdr(longname, component,
7899 longattrname, prefix, type, filetype, lp)) {
7900 goto out;
7902 #endif
7903 stbuf.st_size = (off_t)0;
7904 if (filetype != XATTR_FILE) {
7905 tomodes(&stbuf);
7906 if (chk_path_build(name, longname, lp->pathname,
7907 prefix, type, filetype) > 0) {
7908 goto out;
7912 if (mulvol && tapepos + 1 >= blocklim)
7913 newvol();
7914 (void) writetbuf((char *)&dblock, 1);
7916 * write_ancillary() is not needed here.
7917 * The first link is handled in the following
7918 * else statement. No need to process ACLs
7919 * for other hard links since they are the
7920 * same file.
7923 if (vflag) {
7924 if (NotTape)
7925 dlog("seek = %" FMT_blkcnt_t
7926 "K\n", K(tapepos));
7927 if (filetype == XATTR_FILE) {
7928 (void) fprintf(vfile, gettext(
7929 "a %s attribute %s link to "
7930 "%s attribute %s\n"),
7931 name, component, name,
7932 lp->attrname);
7933 } else {
7934 (void) fprintf(vfile, gettext(
7935 "a %s link to %s\n"),
7936 longname, lp->pathname);
7939 lp->count--;
7940 return (0);
7941 } else {
7942 lp = (struct linkbuf *)getmem(sizeof (*lp));
7943 if (lp != NULL) {
7944 lp->nextp = ihead;
7945 ihead = lp;
7946 lp->inum = stbuf.st_ino;
7947 lp->devnum = stbuf.st_dev;
7948 lp->count = stbuf.st_nlink - 1;
7949 if (filetype == XATTR_FILE) {
7950 (void) strcpy(lp->pathname, longname);
7951 (void) strcpy(lp->attrname,
7952 component);
7953 } else {
7954 (void) strcpy(lp->pathname, longname);
7955 (void) strcpy(lp->attrname, "");
7961 out:
7962 return (1);
7965 static int
7966 put_extra_attributes(char *longname, char *shortname, char *longattrname,
7967 char *prefix, int filetype, char typeflag)
7969 static acl_t *aclp = NULL;
7970 int error;
7972 if (aclp != NULL) {
7973 acl_free(aclp);
7974 aclp = NULL;
7976 #if defined(O_XATTR)
7977 if ((atflag || saflag) && (filetype == XATTR_FILE)) {
7978 if (put_xattr_hdr(longname, shortname, longattrname, prefix,
7979 typeflag, filetype, NULL)) {
7980 return (1);
7983 #endif
7985 /* ACL support */
7986 if (pflag) {
7987 char *secinfo = NULL;
7988 int len = 0;
7990 /* ACL support */
7991 if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
7993 * Get ACL info: dont bother allocating space if
7994 * there is only a trivial ACL.
7996 if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
7997 &aclp)) != 0) {
7998 (void) fprintf(stderr, gettext(
7999 "%s: failed to retrieve acl : %s\n"),
8000 longname, acl_strerror(error));
8001 return (1);
8005 /* append security attributes if any */
8006 if (aclp != NULL) {
8007 (void) append_secattr(&secinfo, &len, acl_cnt(aclp),
8008 acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8009 ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
8010 UFSD_ACL : ACE_ACL);
8013 if (aclp != NULL) {
8014 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8017 return (0);
8020 #if defined(O_XATTR)
8021 static int
8022 put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
8023 int typeflag, int filetype, struct linkbuf *lp)
8025 char *lname = NULL;
8026 char *sname = NULL;
8027 int error = 0;
8028 static char *attrbuf = NULL;
8029 int attrlen;
8031 lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
8032 strlen(shortname) + strlen(".hdr") + 1);
8034 if (lname == NULL) {
8035 fatal(gettext("Out of Memory."));
8037 sname = malloc(sizeof (char) * strlen(shortname) +
8038 strlen(".hdr") + 1);
8039 if (sname == NULL) {
8040 fatal(gettext("Out of Memory."));
8043 (void) sprintf(sname, "%s.hdr", shortname);
8044 (void) sprintf(lname, "/dev/null/%s", sname);
8046 if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
8047 sizeof (dblock.dbuf.name)) {
8048 fatal(gettext(
8049 "Buffer overflow writing extended attribute file name"));
8053 * dump extended attr lookup info
8055 prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
8056 write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
8058 (void) sprintf(lname, "/dev/null/%s", shortname);
8059 (void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
8062 * Set up filename for attribute
8065 error = build_dblock(lname, tchar, '0', filetype,
8066 &stbuf, stbuf.st_dev, prefix);
8067 free(lname);
8068 free(sname);
8070 return (error);
8072 #endif
8074 #if defined(O_XATTR)
8075 static int
8076 read_xattr_hdr(attr_data_t **attrinfo)
8078 char buf[TBLOCK];
8079 char *attrparent = NULL;
8080 blkcnt_t blocks;
8081 char *tp;
8082 off_t bytes;
8083 int comp_len, link_len;
8084 int namelen;
8085 int attrparentlen;
8086 int parentfilelen;
8088 if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
8089 return (1);
8091 bytes = stbuf.st_size;
8092 if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
8093 (void) fprintf(stderr, gettext(
8094 "Insufficient memory for extended attribute\n"));
8095 return (1);
8098 tp = (char *)xattrhead;
8099 blocks = TBLOCKS(bytes);
8100 while (blocks-- > 0) {
8101 readtape(buf);
8102 if (bytes <= TBLOCK) {
8103 (void) memcpy(tp, buf, (size_t)bytes);
8104 break;
8105 } else {
8106 (void) memcpy(tp, buf, TBLOCK);
8107 tp += TBLOCK;
8109 bytes -= TBLOCK;
8113 * Validate that we can handle header format
8115 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8116 (void) fprintf(stderr,
8117 gettext("Unknown extended attribute format encountered\n"));
8118 (void) fprintf(stderr,
8119 gettext("Disabling extended attribute parsing\n"));
8120 xattrbadhead = 1;
8121 return (0);
8123 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8124 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8125 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8126 sizeof (struct xattr_hdr));
8127 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8128 if (link_len > 0)
8129 xattr_linkp = (struct xattr_buf *)
8130 ((int)xattrp + (int)comp_len);
8131 else
8132 xattr_linkp = NULL;
8135 * Gather the attribute path from the filename and attrnames section.
8136 * The filename and attrnames section can be composed of two or more
8137 * path segments separated by a null character. The first segment
8138 * is the path to the parent file that roots the entire sequence in
8139 * the normal name space. The remaining segments describes a path
8140 * rooted at the hidden extended attribute directory of the leaf file of
8141 * the previous segment, making it possible to name attributes on
8142 * attributes.
8144 parentfilelen = strlen(xattrp->h_names);
8145 xattrapath = xattrp->h_names + parentfilelen + 1;
8146 if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
8148 * The attrnames section contains a system attribute on an
8149 * attribute. Save the name of the attribute for use later,
8150 * and replace the null separating the attribute name from
8151 * the system attribute name with a '/' so that xattrapath can
8152 * be used to display messages with the full attribute path name
8153 * rooted at the hidden attribute directory of the base file
8154 * in normal name space.
8156 attrparent = strdup(xattrapath);
8157 attrparentlen = strlen(attrparent);
8158 xattrapath[attrparentlen] = '/';
8160 if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
8161 xattrapath + attrparentlen + 1, xattrapath, attrparent,
8162 -1, 0, attrinfo)) == 1) {
8163 free(attrparent);
8164 return (1);
8167 /* Gather link info */
8168 if (xattr_linkp) {
8169 xattr_linkaname = xattr_linkp->h_names +
8170 strlen(xattr_linkp->h_names) + 1;
8171 } else {
8172 xattr_linkaname = NULL;
8175 return (0);
8177 #else
8178 static int
8179 read_xattr_hdr(attr_data_t **attrinfo)
8181 return (0);
8183 #endif
8186 * skip over extra slashes in string.
8188 * For example:
8189 * /usr/tmp/////
8191 * would return pointer at
8192 * /usr/tmp/////
8195 static char *
8196 skipslashes(char *string, char *start)
8198 while ((string > start) && *(string - 1) == '/') {
8199 string--;
8202 return (string);
8206 * Return the parent directory of a given path.
8208 * Examples:
8209 * /usr/tmp return /usr
8210 * /usr/tmp/file return /usr/tmp
8211 * / returns .
8212 * /usr returns /
8213 * file returns .
8215 * dir is assumed to be at least as big as path.
8217 static void
8218 get_parent(char *path, char *dir)
8220 char *s;
8221 char tmpdir[PATH_MAX + 1];
8223 if (strlen(path) > PATH_MAX) {
8224 fatal(gettext("pathname is too long"));
8226 (void) strcpy(tmpdir, path);
8227 chop_endslashes(tmpdir);
8229 if ((s = strrchr(tmpdir, '/')) == NULL) {
8230 (void) strcpy(dir, ".");
8231 } else {
8232 s = skipslashes(s, tmpdir);
8233 *s = '\0';
8234 if (s == tmpdir)
8235 (void) strcpy(dir, "/");
8236 else
8237 (void) strcpy(dir, tmpdir);
8241 #if defined(O_XATTR)
8242 static char *
8243 get_component(char *path)
8245 char *ptr;
8247 ptr = strrchr(path, '/');
8248 if (ptr == NULL) {
8249 return (path);
8250 } else {
8252 * Handle trailing slash
8254 if (*(ptr + 1) == '\0')
8255 return (ptr);
8256 else
8257 return (ptr + 1);
8260 #else
8261 static char *
8262 get_component(char *path)
8264 return (path);
8266 #endif
8268 #if defined(O_XATTR)
8269 static int
8270 retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
8271 int oflag, mode_t mode)
8273 int dirfd;
8274 int ofilefd = -1;
8275 struct timeval times[2];
8276 mode_t newmode;
8277 struct stat parentstat;
8278 acl_t *aclp = NULL;
8279 int error;
8282 * We couldn't get to attrdir. See if its
8283 * just a mode problem on the parent file.
8284 * for example: a mode such as r-xr--r--
8285 * on a ufs file system without extended
8286 * system attribute support won't let us
8287 * create an attribute dir if it doesn't
8288 * already exist, and on a ufs file system
8289 * with extended system attribute support
8290 * won't let us open the attribute for
8291 * write.
8293 * If file has a non-trivial ACL, then save it
8294 * off so that we can place it back on after doing
8295 * chmod's.
8297 if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
8298 O_RDONLY)) == -1) {
8299 return (-1);
8301 if (fstat(dirfd, &parentstat) == -1) {
8302 (void) fprintf(stderr, gettext(
8303 "tar: cannot stat %sfile %s: %s\n"),
8304 (pdirfd == -1) ? "" : gettext("parent of "),
8305 (pdirfd == -1) ? dirp : name, strerror(errno));
8306 return (-1);
8308 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
8309 (void) fprintf(stderr, gettext(
8310 "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8311 (pdirfd == -1) ? "" : gettext("parent of "),
8312 (pdirfd == -1) ? dirp : name, strerror(errno));
8313 return (-1);
8316 newmode = S_IWUSR | parentstat.st_mode;
8317 if (fchmod(dirfd, newmode) == -1) {
8318 (void) fprintf(stderr,
8319 gettext(
8320 "tar: cannot fchmod %sfile %s to %o: %s\n"),
8321 (pdirfd == -1) ? "" : gettext("parent of "),
8322 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8323 if (aclp)
8324 acl_free(aclp);
8325 return (-1);
8329 if (pdirfd == -1) {
8331 * We weren't able to create the attribute directory before.
8332 * Now try again.
8334 ofilefd = attropen(dirp, ".", oflag);
8335 } else {
8337 * We weren't able to create open the attribute before.
8338 * Now try again.
8340 ofilefd = openat(pdirfd, name, oflag, mode);
8344 * Put mode back to original
8346 if (fchmod(dirfd, parentstat.st_mode) == -1) {
8347 (void) fprintf(stderr,
8348 gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8349 (pdirfd == -1) ? "" : gettext("parent of "),
8350 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8353 if (aclp) {
8354 error = facl_set(dirfd, aclp);
8355 if (error) {
8356 (void) fprintf(stderr,
8357 gettext("tar: failed to set acl entries on "
8358 "%sfile %s\n"),
8359 (pdirfd == -1) ? "" : gettext("parent of "),
8360 (pdirfd == -1) ? dirp : name);
8362 acl_free(aclp);
8366 * Put back time stamps
8369 times[0].tv_sec = parentstat.st_atime;
8370 times[0].tv_usec = 0;
8371 times[1].tv_sec = parentstat.st_mtime;
8372 times[1].tv_usec = 0;
8374 (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
8376 (void) close(dirfd);
8378 return (ofilefd);
8380 #endif
8382 #if !defined(O_XATTR)
8383 static int
8384 openat64(int fd, const char *name, int oflag, mode_t cmode)
8386 return (open64(name, oflag, cmode));
8389 static int
8390 openat(int fd, const char *name, int oflag, mode_t cmode)
8392 return (open(name, oflag, cmode));
8395 static int
8396 fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
8398 if (flag == AT_SYMLINK_NOFOLLOW)
8399 return (lchown(name, owner, group));
8400 else
8401 return (chown(name, owner, group));
8404 static int
8405 renameat(int fromfd, char *old, int tofd, char *new)
8407 return (rename(old, new));
8410 static int
8411 futimesat(int fd, char *path, struct timeval times[2])
8413 return (utimes(path, times));
8416 static int
8417 unlinkat(int dirfd, char *path, int flag)
8419 if (flag == AT_REMOVEDIR)
8420 return (rmdir(path));
8421 else
8422 return (unlink(path));
8425 static int
8426 fstatat(int fd, char *path, struct stat *buf, int flag)
8428 if (flag == AT_SYMLINK_NOFOLLOW)
8429 return (lstat(path, buf));
8430 else
8431 return (stat(path, buf));
8434 static int
8435 attropen(char *file, char *attr, int omode, mode_t cmode)
8437 errno = ENOTSUP;
8438 return (-1);
8440 #endif
8442 static void
8443 chop_endslashes(char *path)
8445 char *end, *ptr;
8448 * Chop of slashes, but not if all we have is slashes
8449 * for example: ////
8450 * should make no changes, otherwise it will screw up
8451 * checkdir
8453 end = &path[strlen(path) -1];
8454 if (*end == '/' && end != path) {
8455 ptr = skipslashes(end, path);
8456 if (ptr != NULL && ptr != path) {
8457 *ptr = '\0';
8462 /* Compressing a tar file using compression method provided in 'opt' */
8464 static void
8465 compress_back()
8467 pid_t pid;
8469 if (vflag) {
8470 (void) fprintf(vfile,
8471 gettext("Compressing '%s' with '%s'...\n"),
8472 usefile, compress_opt);
8474 if ((pid = fork()) == 0) {
8475 verify_compress_opt(compress_opt);
8476 (void) execlp(compress_opt, compress_opt,
8477 usefile, NULL);
8478 } else if (pid == -1) {
8479 vperror(1, "%s", gettext("Could not fork"));
8481 wait_pid(pid);
8482 if (suffix == 0) {
8483 (void) rename(tfname, usefile);
8487 /* The magic numbers from /etc/magic */
8489 #define GZIP_MAGIC "\037\213"
8490 #define BZIP_MAGIC "BZh"
8491 #define COMP_MAGIC "\037\235"
8492 #define XZ_MAGIC "\375\067\172\130\132\000"
8494 void
8495 check_compression(void)
8497 char magic[16];
8498 FILE *fp;
8500 if ((fp = fopen(usefile, "r")) != NULL) {
8501 (void) fread(magic, sizeof (char), 6, fp);
8502 (void) fclose(fp);
8505 if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
8506 if (xflag || tflag) {
8507 compress_opt = compress_malloc(strlen(GZCAT) + 1);
8508 (void) strcpy(compress_opt, GZCAT);
8509 } else if (uflag || rflag) {
8510 compress_opt = compress_malloc(strlen(GZIP) + 1);
8511 (void) strcpy(compress_opt, GZIP);
8513 } else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
8514 if (xflag || tflag) {
8515 compress_opt = compress_malloc(strlen(BZCAT) + 1);
8516 (void) strcpy(compress_opt, BZCAT);
8517 } else if (uflag || rflag) {
8518 compress_opt = compress_malloc(strlen(BZIP) + 1);
8519 (void) strcpy(compress_opt, BZIP);
8521 } else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
8522 if (xflag || tflag) {
8523 compress_opt = compress_malloc(strlen(ZCAT) + 1);
8524 (void) strcpy(compress_opt, ZCAT);
8525 } else if (uflag || rflag) {
8526 compress_opt = compress_malloc(strlen(COMPRESS) + 1);
8527 (void) strcpy(compress_opt, COMPRESS);
8529 } else if (memcmp(magic, XZ_MAGIC, 6) == 0) {
8530 if (xflag || tflag) {
8531 compress_opt = compress_malloc(strlen(XZCAT) + 1);
8532 (void) strcpy(compress_opt, XZCAT);
8533 } else if (uflag || rflag) {
8534 compress_opt = compress_malloc(strlen(XZ) + 1);
8535 (void) strcpy(compress_opt, XZ);
8540 char *
8541 add_suffix()
8543 (void) strcpy(tfname, usefile);
8544 if (strcmp(compress_opt, GZIP) == 0) {
8545 if ((suffix = gz_suffix()) == NULL) {
8546 strlcat(tfname, gsuffix[0], sizeof (tfname));
8547 return (gsuffix[0]);
8549 } else if (strcmp(compress_opt, COMPRESS) == 0) {
8550 if ((suffix = gz_suffix()) == NULL) {
8551 strlcat(tfname, gsuffix[6], sizeof (tfname));
8552 return (gsuffix[6]);
8554 } else if (strcmp(compress_opt, BZIP) == 0) {
8555 if ((suffix = bz_suffix()) == NULL) {
8556 strlcat(tfname, bsuffix[0], sizeof (tfname));
8557 return (bsuffix[0]);
8559 } else if (strcmp(compress_opt, XZ) == 0) {
8560 if ((suffix = xz_suffix()) == NULL) {
8561 strlcat(tfname, xsuffix[0], sizeof (tfname));
8562 return (xsuffix[0]);
8565 return (NULL);
8568 /* Decompressing a tar file using compression method from the file type */
8569 void
8570 decompress_file(void)
8572 pid_t pid;
8573 char *added_suffix;
8576 added_suffix = add_suffix();
8577 if (added_suffix != NULL) {
8578 (void) rename(usefile, tfname);
8580 if ((pid = fork()) == 0) {
8581 if (vflag) {
8582 (void) fprintf(vfile,
8583 gettext("Decompressing '%s' with "
8584 "'%s'...\n"), usefile, compress_opt);
8586 verify_compress_opt(compress_opt);
8587 (void) execlp(compress_opt, compress_opt, "-df",
8588 tfname, NULL);
8589 vperror(1, gettext("Could not exec %s"), compress_opt);
8590 } else if (pid == -1) {
8591 vperror(1, gettext("Could not fork"));
8593 wait_pid(pid);
8594 if (suffix != NULL) {
8595 /* restore the file name - original file was without suffix */
8596 *(usefile + strlen(usefile) - strlen(suffix)) = '\0';
8600 /* Set the archive for writing and then compress the archive */
8601 pid_t
8602 compress_file(void)
8604 int fd[2];
8605 pid_t pid;
8607 if (vflag) {
8608 (void) fprintf(vfile, gettext("Compressing '%s' with "
8609 "'%s'...\n"), usefile, compress_opt);
8612 if (pipe(fd) < 0) {
8613 vperror(1, gettext("Could not create pipe"));
8615 if ((pid = fork()) > 0) {
8616 mt = fd[1];
8617 (void) close(fd[0]);
8618 return (pid);
8620 /* child */
8621 (void) dup2(fd[0], STDIN_FILENO);
8622 (void) close(fd[1]);
8623 (void) dup2(mt, STDOUT_FILENO);
8624 verify_compress_opt(compress_opt);
8625 (void) execlp(compress_opt, compress_opt, NULL);
8626 vperror(1, gettext("Could not exec %s"), compress_opt);
8627 return (0); /*NOTREACHED*/
8630 pid_t
8631 uncompress_file(void)
8633 int fd[2];
8634 pid_t pid;
8636 if (vflag) {
8637 (void) fprintf(vfile, gettext("Decompressing '%s' with "
8638 "'%s'...\n"), usefile, compress_opt);
8641 if (pipe(fd) < 0) {
8642 vperror(1, gettext("Could not create pipe"));
8644 if ((pid = fork()) > 0) {
8645 mt = fd[0];
8646 (void) close(fd[1]);
8647 return (pid);
8649 /* child */
8650 (void) dup2(fd[1], STDOUT_FILENO);
8651 (void) close(fd[0]);
8652 (void) dup2(mt, STDIN_FILENO);
8653 verify_compress_opt(compress_opt);
8654 (void) execlp(compress_opt, compress_opt, NULL);
8655 vperror(1, gettext("Could not exec %s"), compress_opt);
8656 return (0); /*NOTREACHED*/
8659 /* Checking suffix validity */
8660 char *
8661 check_suffix(char **suf, int size)
8663 int i;
8664 int slen;
8665 int nlen = strlen(usefile);
8667 for (i = 0; i < size; i++) {
8668 slen = strlen(suf[i]);
8669 if (nlen < slen)
8670 return (NULL);
8671 if (strcmp(usefile + nlen - slen, suf[i]) == 0)
8672 return (suf[i]);
8674 return (NULL);
8677 /* Checking valid 'bzip2' suffix */
8678 char *
8679 bz_suffix(void)
8681 return (check_suffix(bsuffix, BSUF));
8684 /* Checking valid 'gzip' suffix */
8685 char *
8686 gz_suffix(void)
8688 return (check_suffix(gsuffix, GSUF));
8691 /* Checking valid 'xz' suffix */
8692 char *
8693 xz_suffix(void)
8695 return (check_suffix(xsuffix, XSUF));
8698 void *
8699 compress_malloc(size_t size)
8701 void *opt;
8703 if ((opt = malloc(size)) == NULL) {
8704 vperror(1, "%s",
8705 gettext("Could not allocate compress buffer\n"));
8707 return (opt);
8710 void
8711 wait_pid(pid_t pid)
8713 int status;
8715 while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
8719 static void
8720 verify_compress_opt(const char *t)
8722 struct stat statbuf;
8724 if (stat(t, &statbuf) == -1)
8725 vperror(1, "%s %s: %s\n", gettext("Could not stat"),
8726 t, strerror(errno));
8729 static void
8730 detect_compress(void)
8732 char *zsuf[] = {".Z"};
8733 if (check_suffix(zsuf, 1) != NULL) {
8734 Zflag = 1;
8735 } else if (check_suffix(bsuffix, BSUF) != NULL) {
8736 jflag = 1;
8737 } else if (check_suffix(gsuffix, GSUF) != NULL) {
8738 zflag = 1;
8739 } else if (check_suffix(xsuffix, XSUF) != NULL) {
8740 Jflag = 1;
8741 } else {
8742 vperror(1, "%s\n", gettext("No compression method detected"));