6930152 6192139 (no reboot audit -- PSARC/2009/354) points out less than optimal...
[unleashed.git] / usr / src / cmd / tar / tar.c
blob0b27fab2c9ad7db2ee2ff43091d2ae51cbfd2bff
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.
25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
28 /* Copyright (c) 1987, 1988 Microsoft Corporation */
29 /* All Rights Reserved */
32 * Portions of this source code were derived from Berkeley 4.3 BSD
33 * under license from the Regents of the University of California.
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/stat.h>
40 #include <sys/mkdev.h>
41 #include <sys/wait.h>
42 #include <dirent.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <signal.h>
46 #include <ctype.h>
47 #include <locale.h>
48 #include <nl_types.h>
49 #include <langinfo.h>
50 #include <pwd.h>
51 #include <grp.h>
52 #include <fcntl.h>
53 #include <string.h>
54 #include <malloc.h>
55 #include <time.h>
56 #include <utime.h>
57 #include <stdlib.h>
58 #include <stdarg.h>
59 #include <widec.h>
60 #include <sys/mtio.h>
61 #include <sys/acl.h>
62 #include <strings.h>
63 #include <deflt.h>
64 #include <limits.h>
65 #include <iconv.h>
66 #include <assert.h>
67 #include <libgen.h>
68 #include <libintl.h>
69 #include <aclutils.h>
70 #include <libnvpair.h>
71 #include <archives.h>
73 #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
74 extern int defcntl();
75 #endif
76 #if defined(_PC_SATTR_ENABLED)
77 #include <attr.h>
78 #include <libcmdutils.h>
79 #endif
81 /* Trusted Extensions */
82 #include <zone.h>
83 #include <tsol/label.h>
84 #include <sys/tsol/label_macro.h>
86 #include "getresponse.h"
88 * Source compatibility
92 * These constants come from archives.h and sys/fcntl.h
93 * and were introduced by the extended attributes project
94 * in Solaris 9.
96 #if !defined(O_XATTR)
97 #define AT_SYMLINK_NOFOLLOW 0x1000
98 #define AT_REMOVEDIR 0x1
99 #define AT_FDCWD 0xffd19553
100 #define _XATTR_HDRTYPE 'E'
101 static int attropen();
102 static int fstatat();
103 static int renameat();
104 static int unlinkat();
105 static int openat();
106 static int fchownat();
107 static int futimesat();
108 #endif
111 * Compiling with -D_XPG4_2 gets this but produces other problems, so
112 * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
113 * explicitly doing the declaration here.
115 int utimes(const char *path, const struct timeval timeval_ptr[]);
117 #ifndef MINSIZE
118 #define MINSIZE 250
119 #endif
120 #define DEF_FILE "/etc/default/tar"
122 #define min(a, b) ((a) < (b) ? (a) : (b))
123 #define max(a, b) ((a) > (b) ? (a) : (b))
125 /* -DDEBUG ONLY for debugging */
126 #ifdef DEBUG
127 #undef DEBUG
128 #define DEBUG(a, b, c)\
129 (void) fprintf(stderr, "DEBUG - "), (void) fprintf(stderr, a, b, c)
130 #endif
132 #define TBLOCK 512 /* tape block size--should be universal */
134 #ifdef BSIZE
135 #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
136 #else /* BSIZE */
137 #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
138 #endif /* BSIZE */
140 #define NBLOCK 20
141 #define NAMSIZ 100
142 #define PRESIZ 155
143 #define MAXNAM 256
144 #define MODEMASK 0777777 /* file creation mode mask */
145 #define POSIXMODES 07777 /* mask for POSIX mode bits */
146 #define MAXEXT 9 /* reasonable max # extents for a file */
147 #define EXTMIN 50 /* min blks left on floppy to split a file */
149 /* max value dblock.dbuf.efsize can store */
150 #define TAR_EFSIZE_MAX 0777777777
153 * Symbols which specify the values at which the use of the 'E' function
154 * modifier is required to properly store a file.
156 * TAR_OFFSET_MAX - the largest file size we can archive
157 * OCTAL7CHAR - the limit for ustar gid, uid, dev
160 #ifdef XHDR_DEBUG
161 /* tiny values which force the creation of extended header entries */
162 #define TAR_OFFSET_MAX 9
163 #define OCTAL7CHAR 2
164 #else
165 /* normal values */
166 #define TAR_OFFSET_MAX 077777777777ULL
167 #define OCTAL7CHAR 07777777
168 #endif
170 #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
171 #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
173 #define MAXLEV (PATH_MAX / 2)
174 #define LEV0 1
175 #define SYMLINK_LEV0 0
177 #define TRUE 1
178 #define FALSE 0
180 #define XATTR_FILE 1
181 #define NORMAL_FILE 0
183 #define PUT_AS_LINK 1
184 #define PUT_NOTAS_LINK 0
186 #ifndef VIEW_READONLY
187 #define VIEW_READONLY "SUNWattr_ro"
188 #endif
190 #ifndef VIEW_READWRITE
191 #define VIEW_READWRITE "SUNWattr_rw"
192 #endif
194 #if _FILE_OFFSET_BITS == 64
195 #define FMT_off_t "lld"
196 #define FMT_off_t_o "llo"
197 #define FMT_blkcnt_t "lld"
198 #else
199 #define FMT_off_t "ld"
200 #define FMT_off_t_o "lo"
201 #define FMT_blkcnt_t "ld"
202 #endif
204 /* ACL support */
206 static
207 struct sec_attr {
208 char attr_type;
209 char attr_len[7];
210 char attr_info[1];
211 } *attr;
213 #if defined(O_XATTR)
214 typedef enum {
215 ATTR_OK,
216 ATTR_SKIP,
217 ATTR_CHDIR_ERR,
218 ATTR_OPEN_ERR,
219 ATTR_XATTR_ERR,
220 ATTR_SATTR_ERR
221 } attr_status_t;
222 #endif
224 #if defined(O_XATTR)
225 typedef enum {
226 ARC_CREATE,
227 ARC_RESTORE
228 } arc_action_t;
229 #endif
231 typedef struct attr_data {
232 char *attr_parent;
233 char *attr_path;
234 int attr_parentfd;
235 int attr_rw_sysattr;
236 } attr_data_t;
240 * Tar has been changed to support extended attributes.
242 * As part of this change tar now uses the new *at() syscalls
243 * such as openat, fchownat(), unlinkat()...
245 * This was done so that attributes can be handled with as few code changes
246 * as possible.
248 * What this means is that tar now opens the directory that a file or directory
249 * resides in and then performs *at() functions to manipulate the entry.
251 * For example a new file is now created like this:
253 * dfd = open(<some dir path>)
254 * fd = openat(dfd, <name>,....);
256 * or in the case of an extended attribute
258 * dfd = attropen(<pathname>, ".", ....)
260 * Once we have a directory file descriptor all of the *at() functions can
261 * be applied to it.
263 * unlinkat(dfd, <component name>,...)
264 * fchownat(dfd, <component name>,..)
266 * This works for both normal namespace files and extended attribute file
272 * Extended attribute Format
274 * Extended attributes are stored in two pieces.
275 * 1. An attribute header which has information about
276 * what file the attribute is for and what the attribute
277 * is named.
278 * 2. The attribute record itself. Stored as a normal file type
279 * of entry.
280 * Both the header and attribute record have special modes/typeflags
281 * associated with them.
283 * The names of the header in the archive look like:
284 * /dev/null/attr.hdr
286 * The name of the attribute looks like:
287 * /dev/null/attr
289 * This is done so that an archiver that doesn't understand these formats
290 * can just dispose of the attribute records.
292 * The format is composed of a fixed size header followed
293 * by a variable sized xattr_buf. If the attribute is a hard link
294 * to another attribute then another xattr_buf section is included
295 * for the link.
297 * The xattr_buf is used to define the necessary "pathing" steps
298 * to get to the extended attribute. This is necessary to support
299 * a fully recursive attribute model where an attribute may itself
300 * have an attribute.
302 * The basic layout looks like this.
304 * --------------------------------
305 * | |
306 * | xattr_hdr |
307 * | |
308 * --------------------------------
309 * --------------------------------
310 * | |
311 * | xattr_buf |
312 * | |
313 * --------------------------------
314 * --------------------------------
315 * | |
316 * | (optional link info) |
317 * | |
318 * --------------------------------
319 * --------------------------------
320 * | |
321 * | attribute itself |
322 * | stored as normal tar |
323 * | or cpio data with |
324 * | special mode or |
325 * | typeflag |
326 * | |
327 * --------------------------------
332 * xattrhead is a pointer to the xattr_hdr
334 * xattrp is a pointer to the xattr_buf structure
335 * which contains the "pathing" steps to get to attributes
337 * xattr_linkp is a pointer to another xattr_buf structure that is
338 * only used when an attribute is actually linked to another attribute
342 static struct xattr_hdr *xattrhead;
343 static struct xattr_buf *xattrp;
344 static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
345 static char *xattrapath; /* attribute name */
346 static char *xattr_linkaname; /* attribute attribute is linked to */
347 static char Hiddendir; /* are we processing hidden xattr dir */
348 static char xattrbadhead;
350 /* Was statically allocated tbuf[NBLOCK] */
351 static
352 union hblock {
353 char dummy[TBLOCK];
354 struct header {
355 char name[NAMSIZ]; /* If non-null prefix, path is */
356 /* <prefix>/<name>; otherwise */
357 /* <name> */
358 char mode[8];
359 char uid[8];
360 char gid[8];
361 char size[12]; /* size of this extent if file split */
362 char mtime[12];
363 char chksum[8];
364 char typeflag;
365 char linkname[NAMSIZ];
366 char magic[6];
367 char version[2];
368 char uname[32];
369 char gname[32];
370 char devmajor[8];
371 char devminor[8];
372 char prefix[PRESIZ]; /* Together with "name", the path of */
373 /* the file: <prefix>/<name> */
374 char extno; /* extent #, null if not split */
375 char extotal; /* total extents */
376 char efsize[10]; /* size of entire file */
377 } dbuf;
378 } dblock, *tbuf, xhdr_buf;
380 static
381 struct xtar_hdr {
382 uid_t x_uid, /* Uid of file */
383 x_gid; /* Gid of file */
384 major_t x_devmajor; /* Device major node */
385 minor_t x_devminor; /* Device minor node */
386 off_t x_filesz; /* Length of file */
387 char *x_uname, /* Pointer to name of user */
388 *x_gname, /* Pointer to gid of user */
389 *x_linkpath, /* Path for a hard/symbolic link */
390 *x_path; /* Path of file */
391 timestruc_t x_mtime; /* Seconds and nanoseconds */
392 } Xtarhdr;
394 static
395 struct gen_hdr {
396 ulong_t g_mode; /* Mode of file */
397 uid_t g_uid, /* Uid of file */
398 g_gid; /* Gid of file */
399 off_t g_filesz; /* Length of file */
400 time_t g_mtime; /* Modification time */
401 uint_t g_cksum; /* Checksum of file */
402 ulong_t g_devmajor, /* File system of file */
403 g_devminor; /* Major/minor of special files */
404 } Gen;
406 static
407 struct linkbuf {
408 ino_t inum;
409 dev_t devnum;
410 int count;
411 char pathname[MAXNAM+1]; /* added 1 for last NULL */
412 char attrname[MAXNAM+1];
413 struct linkbuf *nextp;
414 } *ihead;
416 /* see comments before build_table() */
417 #define TABLE_SIZE 512
418 typedef struct file_list {
419 char *name; /* Name of file to {in,ex}clude */
420 struct file_list *next; /* Linked list */
421 } file_list_t;
422 static file_list_t *exclude_tbl[TABLE_SIZE],
423 *include_tbl[TABLE_SIZE];
425 static int append_secattr(char **, int *, int, char *, char);
426 static void write_ancillary(union hblock *, char *, int, char);
428 static void add_file_to_table(file_list_t *table[], char *str);
429 static void assert_string(char *s, char *msg);
430 static int istape(int fd, int type);
431 static void backtape(void);
432 static void build_table(file_list_t *table[], char *file);
433 static int check_prefix(char **namep, char **dirp, char **compp);
434 static void closevol(void);
435 static void copy(void *dst, void *src);
436 static int convtoreg(off_t);
437 static void delete_target(int fd, char *comp, char *namep);
438 static void doDirTimes(char *name, timestruc_t modTime);
439 static void done(int n);
440 static void dorep(char *argv[]);
441 #ifdef _iBCS2
442 static void dotable(char *argv[], int cnt);
443 static void doxtract(char *argv[], int cnt);
444 #else
445 static void dotable(char *argv[]);
446 static void doxtract(char *argv[]);
447 #endif
448 static void fatal(char *format, ...);
449 static void vperror(int exit_status, char *fmt, ...);
450 static void flushtape(void);
451 static void getdir(void);
452 static void *getmem(size_t);
453 static void longt(struct stat *st, char aclchar);
454 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
455 static int makeDir(char *name);
456 static void mterr(char *operation, int i, int exitcode);
457 static void newvol(void);
458 static void passtape(void);
459 static void putempty(blkcnt_t n);
460 static int putfile(char *longname, char *shortname, char *parent,
461 attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
462 static void readtape(char *buffer);
463 static void seekdisk(blkcnt_t blocks);
464 static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
465 static void setbytes_to_skip(struct stat *st, int err);
466 static void splitfile(char *longname, int ifd, char *name,
467 char *prefix, int filetype);
468 static void tomodes(struct stat *sp);
469 static void usage(void);
470 static int xblocks(int issysattr, off_t bytes, int ofile);
471 static int xsfile(int issysattr, int ofd);
472 static void resugname(int dirfd, char *name, int symflag);
473 static int bcheck(char *bstr);
474 static int checkdir(char *name);
475 static int checksum(union hblock *dblockp);
476 #ifdef EUC
477 static int checksum_signed(union hblock *dblockp);
478 #endif /* EUC */
479 static int checkupdate(char *arg);
480 static int checkw(char c, char *name);
481 static int cmp(char *b, char *s, int n);
482 static int defset(char *arch);
483 static int endtape(void);
484 static int is_in_table(file_list_t *table[], char *str);
485 static int notsame(void);
486 static int is_prefix(char *s1, char *s2);
487 static int response(void);
488 static int build_dblock(const char *, const char *, const char,
489 const int filetype, const struct stat *, const dev_t, const char *);
490 static unsigned int hash(char *str);
492 #ifdef _iBCS2
493 static void initarg(char *argv[], char *file);
494 static char *nextarg();
495 #endif
496 static blkcnt_t kcheck(char *kstr);
497 static off_t bsrch(char *s, int n, off_t l, off_t h);
498 static void onintr(int sig);
499 static void onquit(int sig);
500 static void onhup(int sig);
501 static uid_t getuidbyname(char *);
502 static gid_t getgidbyname(char *);
503 static char *getname(gid_t);
504 static char *getgroup(gid_t);
505 static int checkf(char *name, int mode, int howmuch);
506 static int writetbuf(char *buffer, int n);
507 static int wantit(char *argv[], char **namep, char **dirp, char **comp,
508 attr_data_t **attrinfo);
509 static void append_ext_attr(char *shortname, char **secinfo, int *len);
510 static int get_xdata(void);
511 static void gen_num(const char *keyword, const u_longlong_t number);
512 static void gen_date(const char *keyword, const timestruc_t time_value);
513 static void gen_string(const char *keyword, const char *value);
514 static void get_xtime(char *value, timestruc_t *xtime);
515 static int chk_path_build(char *name, char *longname, char *linkname,
516 char *prefix, char type, int filetype);
517 static int gen_utf8_names(const char *filename);
518 static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
519 const char *src, int max_val);
520 static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
521 iconv_t iconv_cd, int xhdrflg, int max_val);
522 static int c_utf8(char *target, const char *source);
523 static int getstat(int dirfd, char *longname, char *shortname,
524 char *attrparent);
525 static void xattrs_put(char *, char *, char *, char *);
526 static void prepare_xattr(char **, char *, char *,
527 char, struct linkbuf *, int *);
528 static int put_link(char *name, char *longname, char *component,
529 char *longattrname, char *prefix, int filetype, char typeflag);
530 static int put_extra_attributes(char *longname, char *shortname,
531 char *longattrname, char *prefix, int filetype, char typeflag);
532 static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
533 char *prefix, int typeflag, int filetype, struct linkbuf *lp);
534 static int read_xattr_hdr(attr_data_t **attrinfo);
536 /* Trusted Extensions */
537 #define AUTO_ZONE "/zone"
539 static void extract_attr(char **file_ptr, struct sec_attr *);
540 static int check_ext_attr(char *filename);
541 static void rebuild_comp_path(char *str, char **namep);
542 static int rebuild_lk_comp_path(char *str, char **namep);
544 static void get_parent(char *path, char *dir);
545 static char *get_component(char *path);
546 static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
547 char *name, int oflag, mode_t mode);
548 static char *skipslashes(char *string, char *start);
549 static void chop_endslashes(char *path);
550 static pid_t compress_file(void);
551 static void compress_back(void);
552 static void decompress_file(void);
553 static pid_t uncompress_file(void);
554 static void *compress_malloc(size_t);
555 static void check_compression();
556 static char *bz_suffix();
557 static char *gz_suffix();
558 static char *add_suffix();
559 static void wait_pid(pid_t);
561 static struct stat stbuf;
563 static char *myname;
564 static int checkflag = 0;
565 #ifdef _iBCS2
566 static int Fileflag;
567 char *sysv3_env;
568 #endif
569 static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
570 static int rflag, xflag, vflag, tflag, mt, svmt, cflag, mflag, pflag;
571 static int uflag;
572 static int eflag, errflag, qflag;
573 static int oflag;
574 static int bflag, kflag, Aflag;
575 static int Pflag; /* POSIX conformant archive */
576 static int Eflag; /* Allow files greater than 8GB */
577 static int atflag; /* traverse extended attributes */
578 static int saflag; /* traverse extended sys attributes */
579 static int Dflag; /* Data change flag */
580 static int jflag; /* flag to use 'bzip2' */
581 static int zflag; /* flag to use 'gzip' */
582 static int Zflag; /* flag to use 'compress' */
584 /* Trusted Extensions */
585 static int Tflag; /* Trusted Extensions attr flags */
586 static int dir_flag; /* for attribute extract */
587 static int mld_flag; /* for attribute extract */
588 static char *orig_namep; /* original namep - unadorned */
589 static int rpath_flag; /* MLD real path is rebuilt */
590 static char real_path[MAXPATHLEN]; /* MLD real path */
591 static int lk_rpath_flag; /* linked to real path is rebuilt */
592 static char lk_real_path[MAXPATHLEN]; /* linked real path */
593 static bslabel_t bs_label; /* for attribute extract */
594 static bslabel_t admin_low;
595 static bslabel_t admin_high;
596 static int ignored_aprivs = 0;
597 static int ignored_fprivs = 0;
598 static int ignored_fattrs = 0;
600 static int term, chksum, wflag,
601 first = TRUE, defaults_used = FALSE, linkerrok;
602 static blkcnt_t recno;
603 static int freemem = 1;
604 static int nblock = NBLOCK;
605 static int Errflg = 0;
606 static int exitflag = 0;
608 static dev_t mt_dev; /* device containing output file */
609 static ino_t mt_ino; /* inode number of output file */
610 static int mt_devtype; /* dev type of archive, from stat structure */
612 static int update = 1; /* for `open' call */
614 static off_t low;
615 static off_t high;
617 static FILE *tfile;
618 static FILE *vfile = stdout;
619 static char tname[] = "/tmp/tarXXXXXX";
620 static char archive[] = "archive0=";
621 static char *Xfile;
622 static char *usefile;
623 static char tfname[1024];
624 static char *Filefile;
626 static int mulvol; /* multi-volume option selected */
627 static blkcnt_t blocklim; /* number of blocks to accept per volume */
628 static blkcnt_t tapepos; /* current block number to be written */
629 static int NotTape; /* true if tape is a disk */
630 static int dumping; /* true if writing a tape or other archive */
631 static int extno; /* number of extent: starts at 1 */
632 static int extotal; /* total extents in this file */
633 static off_t extsize; /* size of current extent during extraction */
634 static ushort_t Oumask = 0; /* old umask value */
635 static int is_posix; /* true if archive we're reading is POSIX-conformant */
636 static const char *magic_type = "ustar";
637 static size_t xrec_size = 8 * PATH_MAX; /* extended rec initial size */
638 static char *xrec_ptr;
639 static off_t xrec_offset = 0;
640 static int Xhdrflag;
641 static int charset_type = 0;
643 static u_longlong_t xhdr_flgs; /* Bits set determine which items */
644 /* need to be in extended header. */
645 #define _X_DEVMAJOR 0x1
646 #define _X_DEVMINOR 0x2
647 #define _X_GID 0x4
648 #define _X_GNAME 0x8
649 #define _X_LINKPATH 0x10
650 #define _X_PATH 0x20
651 #define _X_SIZE 0x40
652 #define _X_UID 0x80
653 #define _X_UNAME 0x100
654 #define _X_ATIME 0x200
655 #define _X_CTIME 0x400
656 #define _X_MTIME 0x800
657 #define _X_XHDR 0x1000 /* Bit flag that determines whether 'X' */
658 /* typeflag was followed by 'A' or non 'A' */
659 /* typeflag. */
660 #define _X_LAST 0x40000000
662 #define PID_MAX_DIGITS (10 * sizeof (pid_t) / 4)
663 #define TIME_MAX_DIGITS (10 * sizeof (time_t) / 4)
664 #define LONG_MAX_DIGITS (10 * sizeof (long) / 4)
665 #define ULONGLONG_MAX_DIGITS (10 * sizeof (u_longlong_t) / 4)
667 * UTF_8 encoding requires more space than the current codeset equivalent.
668 * Currently a factor of 2-3 would suffice, but it is possible for a factor
669 * of 6 to be needed in the future, so for saftey, we use that here.
671 #define UTF_8_FACTOR 6
673 static u_longlong_t xhdr_count = 0;
674 static char xhdr_dirname[PRESIZ + 1];
675 static char pidchars[PID_MAX_DIGITS + 1];
676 static char *tchar = ""; /* null linkpath */
678 static char local_path[UTF_8_FACTOR * PATH_MAX + 1];
679 static char local_linkpath[UTF_8_FACTOR * PATH_MAX + 1];
680 static char local_gname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
681 static char local_uname[UTF_8_FACTOR * _POSIX_NAME_MAX + 1];
684 * The following mechanism is provided to allow us to debug tar in complicated
685 * situations, like when it is part of a pipe. The idea is that you compile
686 * with -DWAITAROUND defined, and then add the 'D' function modifier to the
687 * target tar invocation, eg. "tar cDf tarfile file". If stderr is available,
688 * it will tell you to which pid to attach the debugger; otherwise, use ps to
689 * find it. Attach to the process from the debugger, and, *PRESTO*, you are
690 * there!
692 * Simply assign "waitaround = 0" once you attach to the process, and then
693 * proceed from there as usual.
696 #ifdef WAITAROUND
697 int waitaround = 0; /* wait for rendezvous with the debugger */
698 #endif
700 #define BZIP "/usr/bin/bzip2"
701 #define GZIP "/usr/bin/gzip"
702 #define COMPRESS "/usr/bin/compress"
703 #define BZCAT "/usr/bin/bzcat"
704 #define GZCAT "/usr/bin/gzcat"
705 #define ZCAT "/usr/bin/zcat"
706 #define GS 8 /* number of valid 'gzip' sufixes */
707 #define BS 4 /* number of valid 'bzip2' sufixes */
709 static char *compress_opt; /* compression type */
711 static char *gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
712 ".tgz", ".taz"};
713 static char *bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
714 static char *suffix;
718 main(int argc, char *argv[])
720 char *cp;
721 char *tmpdirp;
722 pid_t thispid;
723 pid_t pid;
724 int wstat;
726 #ifdef _iBCS2
727 int tbl_cnt = 0;
728 sysv3_env = getenv("SYSV3");
729 #endif
730 (void) setlocale(LC_ALL, "");
731 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
732 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
733 #endif
734 (void) textdomain(TEXT_DOMAIN);
735 if (argc < 2)
736 usage();
738 tfile = NULL;
739 if ((myname = strdup(argv[0])) == NULL) {
740 (void) fprintf(stderr, gettext(
741 "tar: cannot allocate program name\n"));
742 exit(1);
745 if (init_yes() < 0) {
746 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
747 strerror(errno));
748 exit(2);
752 * For XPG4 compatibility, we must be able to accept the "--"
753 * argument normally recognized by getopt; it is used to delimit
754 * the end opt the options section, and so can only appear in
755 * the position of the first argument. We simply skip it.
758 if (strcmp(argv[1], "--") == 0) {
759 argv++;
760 argc--;
761 if (argc < 3)
762 usage();
765 argv[argc] = NULL;
766 argv++;
769 * Set up default values.
770 * Search the operand string looking for the first digit or an 'f'.
771 * If you find a digit, use the 'archive#' entry in DEF_FILE.
772 * If 'f' is given, bypass looking in DEF_FILE altogether.
773 * If no digit or 'f' is given, still look in DEF_FILE but use '0'.
775 if ((usefile = getenv("TAPE")) == (char *)NULL) {
776 for (cp = *argv; *cp; ++cp)
777 if (isdigit(*cp) || *cp == 'f')
778 break;
779 if (*cp != 'f') {
780 archive[7] = (*cp)? *cp: '0';
781 if (!(defaults_used = defset(archive))) {
782 usefile = NULL;
783 nblock = 1;
784 blocklim = 0;
785 NotTape = 0;
790 for (cp = *argv++; *cp; cp++)
791 switch (*cp) {
792 #ifdef WAITAROUND
793 case 'D':
794 /* rendezvous with the debugger */
795 waitaround = 1;
796 break;
797 #endif
798 case 'f':
799 assert_string(*argv, gettext(
800 "tar: tarfile must be specified with 'f' "
801 "function modifier\n"));
802 usefile = *argv++;
803 break;
804 case 'F':
805 #ifdef _iBCS2
806 if (sysv3_env) {
807 assert_string(*argv, gettext(
808 "tar: 'F' requires a file name\n"));
809 Filefile = *argv++;
810 Fileflag++;
811 } else
812 #endif /* _iBCS2 */
813 Fflag++;
814 break;
815 case 'c':
816 cflag++;
817 rflag++;
818 update = 1;
819 break;
820 #if defined(O_XATTR)
821 case '@':
822 atflag++;
823 break;
824 #endif /* O_XATTR */
825 #if defined(_PC_SATTR_ENABLED)
826 case '/':
827 saflag++;
828 break;
829 #endif /* _PC_SATTR_ENABLED */
830 case 'u':
831 uflag++; /* moved code after signals caught */
832 rflag++;
833 update = 2;
834 break;
835 case 'r':
836 rflag++;
837 update = 2;
838 break;
839 case 'v':
840 vflag++;
841 break;
842 case 'w':
843 wflag++;
844 break;
845 case 'x':
846 xflag++;
847 break;
848 case 'X':
849 assert_string(*argv, gettext(
850 "tar: exclude file must be specified with 'X' "
851 "function modifier\n"));
852 Xflag = 1;
853 Xfile = *argv++;
854 build_table(exclude_tbl, Xfile);
855 break;
856 case 't':
857 tflag++;
858 break;
859 case 'm':
860 mflag++;
861 break;
862 case 'p':
863 pflag++;
864 break;
865 case 'D':
866 Dflag++;
867 break;
868 case '-':
869 /* ignore this silently */
870 break;
871 case '0': /* numeric entries used only for defaults */
872 case '1':
873 case '2':
874 case '3':
875 case '4':
876 case '5':
877 case '6':
878 case '7':
879 break;
880 case 'b':
881 assert_string(*argv, gettext(
882 "tar: blocking factor must be specified "
883 "with 'b' function modifier\n"));
884 bflag++;
885 nblock = bcheck(*argv++);
886 break;
887 case 'q':
888 qflag++;
889 break;
890 case 'k':
891 assert_string(*argv, gettext(
892 "tar: size value must be specified with 'k' "
893 "function modifier\n"));
894 kflag++;
895 blocklim = kcheck(*argv++);
896 break;
897 case 'n': /* not a magtape (instead of 'k') */
898 NotTape++; /* assume non-magtape */
899 break;
900 case 'l':
901 linkerrok++;
902 break;
903 case 'e':
904 #ifdef _iBCS2
905 /* If sysv3 IS set, don't be as verbose */
906 if (!sysv3_env)
907 #endif /* _iBCS2 */
908 errflag++;
909 eflag++;
910 break;
911 case 'o':
912 oflag++;
913 break;
914 case 'h':
915 hflag++;
916 break;
917 case 'i':
918 iflag++;
919 break;
920 case 'B':
921 Bflag++;
922 break;
923 case 'P':
924 Pflag++;
925 break;
926 case 'E':
927 Eflag++;
928 Pflag++; /* Only POSIX archive made */
929 break;
930 case 'T':
931 Tflag++; /* Handle Trusted Extensions attrs */
932 pflag++; /* also set flag for ACL */
933 break;
934 case 'j': /* compession "bzip2" */
935 jflag++;
936 break;
937 case 'z': /* compression "gzip" */
938 zflag++;
939 break;
940 case 'Z': /* compression "compress" */
941 Zflag++;
942 break;
943 default:
944 (void) fprintf(stderr, gettext(
945 "tar: %c: unknown function modifier\n"), *cp);
946 usage();
949 #ifdef _iBCS2
950 if (Xflag && Fileflag) {
951 (void) fprintf(stderr, gettext(
952 "tar: specify only one of X or F.\n"));
953 usage();
955 #endif /* _iBCS2 */
957 if (!rflag && !xflag && !tflag)
958 usage();
959 if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
960 (void) fprintf(stderr, gettext(
961 "tar: specify only one of [ctxru].\n"));
962 usage();
964 if (cflag) {
965 if ((zflag && jflag) || (zflag && Zflag) ||
966 (jflag && Zflag)) {
967 (void) fprintf(stderr, gettext(
968 "tar: specify only one of [jzZ] to "
969 "create a compressed file.\n"));
970 usage();
973 /* Trusted Extensions attribute handling */
974 if (Tflag && ((getzoneid() != GLOBAL_ZONEID) ||
975 !is_system_labeled())) {
976 (void) fprintf(stderr, gettext(
977 "tar: the 'T' option is only available with "
978 "Trusted Extensions\nand must be run from "
979 "the global zone.\n"));
980 usage();
982 if (cflag && *argv == NULL && Filefile == NULL)
983 fatal(gettext("Missing filenames"));
984 if (usefile == NULL)
985 fatal(gettext("device argument required"));
987 /* alloc a buffer of the right size */
988 if ((tbuf = (union hblock *)
989 calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
990 (union hblock *)NULL) {
991 (void) fprintf(stderr, gettext(
992 "tar: cannot allocate physio buffer\n"));
993 exit(1);
996 if ((xrec_ptr = malloc(xrec_size)) == NULL) {
997 (void) fprintf(stderr, gettext(
998 "tar: cannot allocate extended header buffer\n"));
999 exit(1);
1002 #ifdef WAITAROUND
1003 if (waitaround) {
1004 (void) fprintf(stderr, gettext("Rendezvous with tar on pid"
1005 " %d\n"), getpid());
1007 while (waitaround) {
1008 (void) sleep(10);
1011 #endif
1013 thispid = getpid();
1014 (void) sprintf(pidchars, "%ld", thispid);
1015 thispid = strlen(pidchars);
1017 if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL)
1018 (void) strcpy(xhdr_dirname, "/tmp");
1019 else {
1021 * Make sure that dir is no longer than what can
1022 * fit in the prefix part of the header.
1024 if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
1025 (void) strcpy(xhdr_dirname, "/tmp");
1026 if ((vflag > 0) && (Eflag > 0))
1027 (void) fprintf(stderr, gettext(
1028 "Ignoring TMPDIR\n"));
1029 } else
1030 (void) strcpy(xhdr_dirname, tmpdirp);
1032 (void) strcat(xhdr_dirname, "/PaxHeaders.");
1033 (void) strcat(xhdr_dirname, pidchars);
1035 if (rflag) {
1036 if (cflag && usefile != NULL) {
1037 /* Set the compression type */
1038 if (jflag) {
1039 compress_opt = compress_malloc(strlen(BZIP)
1040 + 1);
1041 (void) strcpy(compress_opt, BZIP);
1042 } else if (zflag) {
1043 compress_opt = compress_malloc(strlen(GZIP)
1044 + 1);
1045 (void) strcpy(compress_opt, GZIP);
1046 } else if (Zflag) {
1047 compress_opt =
1048 compress_malloc(strlen(COMPRESS) + 1);
1049 (void) strcpy(compress_opt, COMPRESS);
1051 } else {
1053 * Decompress if the file is compressed for
1054 * an update or replace.
1056 if (strcmp(usefile, "-") != 0) {
1057 check_compression();
1058 if (compress_opt != NULL) {
1059 decompress_file();
1064 if (cflag && tfile != NULL)
1065 usage();
1066 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1067 (void) signal(SIGINT, onintr);
1068 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1069 (void) signal(SIGHUP, onhup);
1070 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1071 (void) signal(SIGQUIT, onquit);
1072 if (uflag) {
1073 int tnum;
1074 if ((tnum = mkstemp(tname)) == -1)
1075 vperror(1, "%s", tname);
1076 if ((tfile = fdopen(tnum, "w")) == NULL)
1077 vperror(1, "%s", tname);
1079 if (strcmp(usefile, "-") == 0) {
1080 if (cflag == 0)
1081 fatal(gettext(
1082 "can only create standard output archives."));
1083 vfile = stderr;
1084 mt = dup(1);
1085 ++bflag;
1086 } else {
1087 if (cflag)
1088 mt = open(usefile,
1089 O_RDWR|O_CREAT|O_TRUNC, 0666);
1090 else
1091 mt = open(usefile, O_RDWR);
1093 if (mt < 0) {
1094 if (cflag == 0 || (mt = creat(usefile, 0666))
1095 < 0)
1096 vperror(1, "%s", usefile);
1099 /* Get inode and device number of output file */
1100 (void) fstat(mt, &stbuf);
1101 mt_ino = stbuf.st_ino;
1102 mt_dev = stbuf.st_dev;
1103 mt_devtype = stbuf.st_mode & S_IFMT;
1104 NotTape = !istape(mt, mt_devtype);
1106 if (rflag && !cflag && (mt_devtype == S_IFIFO))
1107 fatal(gettext("cannot append to pipe or FIFO."));
1109 if (Aflag && vflag)
1110 (void) printf(
1111 gettext("Suppressing absolute pathnames\n"));
1112 if (cflag && compress_opt != NULL) {
1113 pid = compress_file();
1114 wait_pid(pid);
1116 dorep(argv);
1117 if (rflag && !cflag && (compress_opt != NULL))
1118 compress_back();
1119 } else if (xflag || tflag) {
1121 * for each argument, check to see if there is a "-I file" pair.
1122 * if so, move the 3rd argument into "-I"'s place, build_table()
1123 * using "file"'s name and increment argc one (the second
1124 * increment appears in the for loop) which removes the two
1125 * args "-I" and "file" from the argument vector.
1127 for (argc = 0; argv[argc]; argc++) {
1128 if (strcmp(argv[argc], "-I") == 0) {
1129 if (!argv[argc+1]) {
1130 (void) fprintf(stderr, gettext(
1131 "tar: missing argument for -I flag\n"));
1132 done(2);
1133 } else {
1134 Iflag = 1;
1135 argv[argc] = argv[argc+2];
1136 build_table(include_tbl, argv[++argc]);
1137 #ifdef _iBCS2
1138 if (Fileflag) {
1139 (void) fprintf(stderr, gettext(
1140 "tar: only one of I or F.\n"));
1141 usage();
1143 #endif /* _iBCS2 */
1148 if (strcmp(usefile, "-") == 0) {
1149 mt = dup(0);
1150 ++bflag;
1151 /* try to recover from short reads when reading stdin */
1152 ++Bflag;
1153 } else if ((mt = open(usefile, 0)) < 0)
1154 vperror(1, "%s", usefile);
1156 /* Decompress if the file is compressed */
1158 if (strcmp(usefile, "-") != 0) {
1159 check_compression();
1160 if (compress_opt != NULL) {
1161 pid = uncompress_file();
1162 wait_pid(pid);
1165 if (xflag) {
1166 if (Aflag && vflag)
1167 (void) printf(gettext(
1168 "Suppressing absolute pathnames.\n"));
1170 #ifdef _iBCS2
1171 doxtract(argv, tbl_cnt);
1172 #else
1173 doxtract(argv);
1174 #endif
1175 } else if (tflag)
1177 #ifdef _iBCS2
1178 dotable(argv, tbl_cnt);
1179 #else
1180 dotable(argv);
1181 #endif
1183 else
1184 usage();
1186 done(Errflg);
1188 /* Not reached: keep compiler quiet */
1189 return (1);
1192 static void
1193 usage(void)
1196 #ifdef _iBCS2
1197 if (sysv3_env) {
1198 (void) fprintf(stderr, gettext(
1199 #if defined(O_XATTR)
1200 #if defined(_PC_SATTR_ENABLED)
1201 "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw@/[0-7]][bfFk][X...] "
1202 #else
1203 "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw@[0-7]][bfFk][X...] "
1204 #endif /* _PC_SATTR_ENABLED */
1205 #else
1206 "Usage: tar {c|r|t|u|x}[BDeEhilmnopPqTvw[0-7]][bfFk][X...] "
1207 #endif /* O_XATTR */
1208 "[j|z|Z] "
1209 "[blocksize] [tarfile] [filename] [size] [exclude-file...] "
1210 "{file | -I include-file | -C directory file}...\n"));
1211 } else
1212 #endif /* _iBCS2 */
1214 (void) fprintf(stderr, gettext(
1215 #if defined(O_XATTR)
1216 #if defined(_PC_SATTR_ENABLED)
1217 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw@/[0-7]][bfk][X...] "
1218 #else
1219 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw@[0-7]][bfk][X...] "
1220 #endif /* _PC_SATTR_ENABLED */
1221 #else
1222 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPqTvw[0-7]][bfk][X...] "
1223 #endif /* O_XATTR */
1224 "[j|z|Z] "
1225 "[blocksize] [tarfile] [size] [exclude-file...] "
1226 "{file | -I include-file | -C directory file}...\n"));
1228 done(1);
1232 * dorep - do "replacements"
1234 * Dorep is responsible for creating ('c'), appending ('r')
1235 * and updating ('u');
1238 static void
1239 dorep(char *argv[])
1241 char *cp, *cp2, *p;
1242 char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
1243 char file[PATH_MAX*2], origdir[PATH_MAX+1];
1244 FILE *fp = (FILE *)NULL;
1245 FILE *ff = (FILE *)NULL;
1246 int archtype;
1247 int ret;
1250 if (!cflag) {
1251 xhdr_flgs = 0;
1252 getdir(); /* read header for next file */
1253 if (Xhdrflag > 0) {
1254 if (!Eflag)
1255 fatal(gettext("Archive contains extended"
1256 " header. -E flag required.\n"));
1257 ret = get_xdata(); /* Get extended header items */
1258 /* and regular header */
1259 } else {
1260 if (Eflag)
1261 fatal(gettext("Archive contains no extended"
1262 " header. -E flag not allowed.\n"));
1264 while (!endtape()) { /* changed from a do while */
1265 setbytes_to_skip(&stbuf, ret);
1266 passtape(); /* skip the file data */
1267 if (term)
1268 done(Errflg); /* received signal to stop */
1269 xhdr_flgs = 0;
1270 getdir();
1271 if (Xhdrflag > 0)
1272 ret = get_xdata();
1274 if (ret == 0) {
1275 if ((dblock.dbuf.typeflag != 'A') &&
1276 (xhdr_flgs != 0)) {
1277 load_info_from_xtarhdr(xhdr_flgs,
1278 &Xtarhdr);
1279 xhdr_flgs |= _X_XHDR;
1282 backtape(); /* was called by endtape */
1283 if (tfile != NULL) {
1284 char buf[200];
1286 (void) sprintf(buf, "sort +0 -1 +1nr %s -o %s; awk '$1 "
1287 "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1288 tname, tname, tname, tname, tname, tname);
1289 (void) fflush(tfile);
1290 (void) system(buf);
1291 (void) freopen(tname, "r", tfile);
1292 (void) fstat(fileno(tfile), &stbuf);
1293 high = stbuf.st_size;
1297 dumping = 1;
1298 if (mulvol) { /* SP-1 */
1299 if (nblock && (blocklim%nblock) != 0)
1300 fatal(gettext(
1301 "Volume size not a multiple of block size."));
1302 blocklim -= 2; /* for trailer records */
1303 if (vflag)
1304 (void) fprintf(vfile, gettext("Volume ends at %"
1305 FMT_blkcnt_t "K, blocking factor = %dK\n"),
1306 K((blocklim - 1)), K(nblock));
1309 #ifdef _iBCS2
1310 if (Fileflag) {
1311 if (Filefile != NULL) {
1312 if ((ff = fopen(Filefile, "r")) == NULL)
1313 vperror(0, "%s", Filefile);
1314 } else {
1315 (void) fprintf(stderr, gettext(
1316 "tar: F requires a file name.\n"));
1317 usage();
1320 #endif /* _iBCS2 */
1323 * Save the original directory before it gets
1324 * changed.
1326 if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
1327 vperror(0, gettext("A parent directory cannot be read"));
1328 exit(1);
1331 (void) strcpy(wdir, origdir);
1333 while ((*argv || fp || ff) && !term) {
1334 if (fp || (strcmp(*argv, "-I") == 0)) {
1335 #ifdef _iBCS2
1336 if (Fileflag) {
1337 (void) fprintf(stderr, gettext(
1338 "tar: only one of I or F.\n"));
1339 usage();
1341 #endif /* _iBCS2 */
1342 if (fp == NULL) {
1343 if (*++argv == NULL)
1344 fatal(gettext(
1345 "missing file name for -I flag."));
1346 else if ((fp = fopen(*argv++, "r")) == NULL)
1347 vperror(0, "%s", argv[-1]);
1348 continue;
1349 } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
1350 (void) fclose(fp);
1351 fp = NULL;
1352 continue;
1353 } else {
1354 cp = cp2 = file;
1355 if ((p = strchr(cp2, '\n')))
1356 *p = 0;
1358 } else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
1359 #ifdef _iBCS2
1360 if (Fileflag) {
1361 (void) fprintf(stderr, gettext(
1362 "tar: only one of F or C\n"));
1363 usage();
1365 #endif /* _iBCS2 */
1367 if (chdir(*++argv) < 0)
1368 vperror(0, gettext(
1369 "can't change directories to %s"), *argv);
1370 else
1371 (void) getcwd(wdir, (sizeof (wdir)));
1372 argv++;
1373 continue;
1374 #ifdef _iBCS2
1375 } else if (Fileflag && (ff != NULL)) {
1376 if ((fgets(file, PATH_MAX-1, ff)) == NULL) {
1377 (void) fclose(ff);
1378 ff = NULL;
1379 continue;
1380 } else {
1381 cp = cp2 = file;
1382 if (p = strchr(cp2, '\n'))
1383 *p = 0;
1385 #endif /* _iBCS2 */
1386 } else
1387 cp = cp2 = strcpy(file, *argv++);
1390 * point cp2 to the last '/' in file, but not
1391 * to a trailing '/'
1393 for (; *cp; cp++) {
1394 if (*cp == '/') {
1395 while (*(cp+1) == '/') {
1396 ++cp;
1398 if (*(cp+1) != '\0') {
1399 /* not trailing slash */
1400 cp2 = cp;
1404 if (cp2 != file) {
1405 *cp2 = '\0';
1406 if (chdir(file) < 0) {
1407 vperror(0, gettext(
1408 "can't change directories to %s"), file);
1409 continue;
1411 *cp2 = '/';
1412 cp2++;
1415 parent = getcwd(tempdir, (sizeof (tempdir)));
1417 archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
1418 LEV0, SYMLINK_LEV0);
1420 #if defined(O_XATTR)
1421 if (!exitflag) {
1422 if ((atflag || saflag) &&
1423 (archtype == PUT_NOTAS_LINK)) {
1424 xattrs_put(file, cp2, parent, NULL);
1427 #endif
1429 if (chdir(origdir) < 0)
1430 vperror(0, gettext("cannot change back?: %s"), origdir);
1432 if (exitflag) {
1434 * If e function modifier has been specified
1435 * write the files (that are listed before the
1436 * file causing the error) to tape. exitflag is
1437 * used because only some of the error conditions
1438 * in putfile() recognize the e function modifier.
1440 break;
1444 putempty((blkcnt_t)2);
1445 flushtape();
1446 closevol(); /* SP-1 */
1447 if (linkerrok == 1)
1448 for (; ihead != NULL; ihead = ihead->nextp) {
1449 if (ihead->count == 0)
1450 continue;
1451 (void) fprintf(stderr, gettext(
1452 "tar: missing links to %s\n"), ihead->pathname);
1453 if (errflag)
1454 done(1);
1455 else
1456 Errflg = 1;
1462 * endtape - check for tape at end
1464 * endtape checks the entry in dblock.dbuf to see if its the
1465 * special EOT entry. Endtape is usually called after getdir().
1467 * endtape used to call backtape; it no longer does, he who
1468 * wants it backed up must call backtape himself
1469 * RETURNS: 0 if not EOT, tape position unaffected
1470 * 1 if EOT, tape position unaffected
1473 static int
1474 endtape(void)
1476 if (dblock.dbuf.name[0] == '\0') { /* null header = EOT */
1477 return (1);
1478 } else
1479 return (0);
1483 * getdir - get directory entry from tar tape
1485 * getdir reads the next tarblock off the tape and cracks
1486 * it as a directory. The checksum must match properly.
1488 * If tfile is non-null getdir writes the file name and mod date
1489 * to tfile.
1492 static void
1493 getdir(void)
1495 struct stat *sp;
1496 #ifdef EUC
1497 static int warn_chksum_sign = 0;
1498 #endif /* EUC */
1500 top:
1501 readtape((char *)&dblock);
1502 if (dblock.dbuf.name[0] == '\0')
1503 return;
1504 sp = &stbuf;
1505 (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
1506 (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
1507 (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
1508 (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
1509 (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
1510 (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
1511 (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
1512 (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
1514 is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
1516 sp->st_mode = Gen.g_mode;
1517 if (is_posix && (sp->st_mode & S_IFMT) == 0)
1518 switch (dblock.dbuf.typeflag) {
1519 case '0': case 0: case _XATTR_HDRTYPE:
1520 sp->st_mode |= S_IFREG;
1521 break;
1522 case '1': /* hard link */
1523 break;
1524 case '2':
1525 sp->st_mode |= S_IFLNK;
1526 break;
1527 case '3':
1528 sp->st_mode |= S_IFCHR;
1529 break;
1530 case '4':
1531 sp->st_mode |= S_IFBLK;
1532 break;
1533 case '5':
1534 sp->st_mode |= S_IFDIR;
1535 break;
1536 case '6':
1537 sp->st_mode |= S_IFIFO;
1538 break;
1539 default:
1540 if (convtoreg(Gen.g_filesz))
1541 sp->st_mode |= S_IFREG;
1542 break;
1545 if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
1546 Xhdrflag = 1; /* Currently processing extended header */
1547 } else {
1548 Xhdrflag = 0;
1551 sp->st_uid = Gen.g_uid;
1552 sp->st_gid = Gen.g_gid;
1553 sp->st_size = Gen.g_filesz;
1554 sp->st_mtime = Gen.g_mtime;
1555 chksum = Gen.g_cksum;
1557 if (dblock.dbuf.extno != '\0') { /* split file? */
1558 extno = dblock.dbuf.extno;
1559 extsize = Gen.g_filesz;
1560 extotal = dblock.dbuf.extotal;
1561 } else {
1562 extno = 0; /* tell others file not split */
1563 extsize = 0;
1564 extotal = 0;
1567 #ifdef EUC
1568 if (chksum != checksum(&dblock)) {
1569 if (chksum != checksum_signed(&dblock)) {
1570 (void) fprintf(stderr, gettext(
1571 "tar: directory checksum error\n"));
1572 if (iflag)
1573 goto top;
1574 done(2);
1575 } else {
1576 if (! warn_chksum_sign) {
1577 warn_chksum_sign = 1;
1578 (void) fprintf(stderr, gettext(
1579 "tar: warning: tar file made with signed checksum\n"));
1583 #else
1584 if (chksum != checksum(&dblock)) {
1585 (void) fprintf(stderr, gettext(
1586 "tar: directory checksum error\n"));
1587 if (iflag)
1588 goto top;
1589 done(2);
1591 #endif /* EUC */
1592 if (tfile != NULL && Xhdrflag == 0) {
1594 * If an extended header is present, then time is available
1595 * in nanoseconds in the extended header data, so set it.
1596 * Otherwise, give an invalid value so that checkupdate will
1597 * not test beyond seconds.
1599 if ((xhdr_flgs & _X_MTIME))
1600 sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
1601 else
1602 sp->st_mtim.tv_nsec = -1;
1604 if (xhdr_flgs & _X_PATH)
1605 (void) fprintf(tfile, "%s %10ld.%9.9ld\n",
1606 Xtarhdr.x_path, sp->st_mtim.tv_sec,
1607 sp->st_mtim.tv_nsec);
1608 else
1609 (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
1610 NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
1611 sp->st_mtim.tv_nsec);
1614 #if defined(O_XATTR)
1615 Hiddendir = 0;
1616 if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
1617 if (xattrbadhead) {
1618 free(xattrhead);
1619 xattrp = NULL;
1620 xattr_linkp = NULL;
1621 xattrhead = NULL;
1622 } else {
1623 char *aname = basename(xattrapath);
1624 size_t xindex = aname - xattrapath;
1626 if (xattrapath[xindex] == '.' &&
1627 xattrapath[xindex + 1] == '\0' &&
1628 xattrp->h_typeflag == '5') {
1629 Hiddendir = 1;
1630 sp->st_mode =
1631 (S_IFDIR | (sp->st_mode & POSIXMODES));
1633 dblock.dbuf.typeflag = xattrp->h_typeflag;
1636 #endif
1641 * passtape - skip over a file on the tape
1643 * passtape skips over the next data file on the tape.
1644 * The tape directory entry must be in dblock.dbuf. This
1645 * routine just eats the number of blocks computed from the
1646 * directory size entry; the tape must be (logically) positioned
1647 * right after thee directory info.
1650 static void
1651 passtape(void)
1653 blkcnt_t blocks;
1654 char buf[TBLOCK];
1657 * Types link(1), sym-link(2), char special(3), blk special(4),
1658 * directory(5), and FIFO(6) do not have data blocks associated
1659 * with them so just skip reading the data block.
1661 if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
1662 dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
1663 dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
1664 return;
1665 blocks = TBLOCKS(stbuf.st_size);
1667 /* if operating on disk, seek instead of reading */
1668 if (NotTape)
1669 seekdisk(blocks);
1670 else
1671 while (blocks-- > 0)
1672 readtape(buf);
1675 #if defined(O_XATTR)
1676 static int
1677 is_sysattr(char *name)
1679 return ((strcmp(name, VIEW_READONLY) == 0) ||
1680 (strcmp(name, VIEW_READWRITE) == 0));
1682 #endif
1684 #if defined(O_XATTR)
1686 * Verify the attribute, attrname, is an attribute we want to restore.
1687 * Never restore read-only system attribute files. Only restore read-write
1688 * system attributes files when -/ was specified, and only traverse into
1689 * the 2nd level attribute directory containing only system attributes if
1690 * -@ was specified. This keeps us from archiving
1691 * <attribute name>/<read-write system attribute file>
1692 * when -/ was specified without -@.
1694 * attrname - attribute file name
1695 * attrparent - attribute's parent name within the base file's attribute
1696 * directory hierarchy
1698 static attr_status_t
1699 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
1700 int *rw_sysattr)
1702 #if defined(_PC_SATTR_ENABLED)
1703 int attr_supported;
1705 /* Never restore read-only system attribute files */
1706 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
1707 *rw_sysattr = 0;
1708 return (ATTR_SKIP);
1709 } else {
1710 *rw_sysattr = (attr_supported == _RW_SATTR);
1712 #else
1714 * Only need to check if this attribute is an extended system
1715 * attribute.
1717 if (*rw_sysattr = is_sysattr(attrname)) {
1718 return (ATTR_SKIP);
1719 } else {
1720 return (ATTR_OK);
1722 #endif /* _PC_SATTR_ENABLED */
1725 * If the extended system attribute file is specified with the
1726 * arc_rwsysattr flag, as being transient (default extended
1727 * attributes), then don't archive it.
1729 if (*rw_sysattr && !arc_rwsysattr) {
1730 return (ATTR_SKIP);
1734 * Only restore read-write system attribute files
1735 * when -/ was specified. Only restore extended
1736 * attributes when -@ was specified.
1738 if (atflag) {
1739 if (!saflag) {
1741 * Only archive/restore the hidden directory "." if
1742 * we're processing the top level hidden attribute
1743 * directory. We don't want to process the
1744 * hidden attribute directory of the attribute
1745 * directory that contains only extended system
1746 * attributes.
1748 if (*rw_sysattr || (Hiddendir &&
1749 (attrparent != NULL))) {
1750 return (ATTR_SKIP);
1753 } else if (saflag) {
1755 * Only archive/restore read-write extended system attribute
1756 * files of the base file.
1758 if (!*rw_sysattr || (attrparent != NULL)) {
1759 return (ATTR_SKIP);
1761 } else {
1762 return (ATTR_SKIP);
1765 return (ATTR_OK);
1767 #endif
1769 static void
1770 free_children(file_list_t *children)
1772 file_list_t *child = children;
1773 file_list_t *cptr;
1775 while (child != NULL) {
1776 cptr = child->next;
1777 if (child->name != NULL) {
1778 free(child->name);
1780 child = cptr;
1784 static int
1785 putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
1786 int filetype, int lev, int symlink_lev)
1788 int infile = -1; /* deliberately invalid */
1789 blkcnt_t blocks;
1790 char buf[PATH_MAX + 2]; /* Add trailing slash and null */
1791 char *bigbuf;
1792 int maxread;
1793 int hint; /* amount to write to get "in sync" */
1794 char filetmp[PATH_MAX + 1];
1795 char *cp;
1796 char *name;
1797 char *attrparent = NULL;
1798 char *longattrname = NULL;
1799 file_list_t *child = NULL;
1800 file_list_t *child_end = NULL;
1801 file_list_t *cptr;
1802 struct dirent *dp;
1803 DIR *dirp;
1804 int i;
1805 int split;
1806 int dirfd = -1;
1807 int rc = PUT_NOTAS_LINK;
1808 int archtype = 0;
1809 int rw_sysattr = 0;
1810 char newparent[PATH_MAX + MAXNAMLEN + 1];
1811 char *prefix = "";
1812 char *tmpbuf;
1813 char goodbuf[PRESIZ + 2];
1814 char junkbuf[MAXNAM+1];
1815 char *lastslash;
1816 int j;
1817 struct stat sbuf;
1818 int readlink_max;
1820 (void) memset(goodbuf, '\0', sizeof (goodbuf));
1821 (void) memset(junkbuf, '\0', sizeof (junkbuf));
1823 xhdr_flgs = 0;
1825 if (filetype == XATTR_FILE) {
1826 attrparent = attrinfo->attr_parent;
1827 longattrname = attrinfo->attr_path;
1828 dirfd = attrinfo->attr_parentfd;
1829 rw_sysattr = attrinfo->attr_rw_sysattr;
1830 } else {
1831 dirfd = open(".", O_RDONLY);
1834 if (dirfd == -1) {
1835 (void) fprintf(stderr, gettext(
1836 "tar: unable to open%sdirectory %s%s%s%s\n"),
1837 (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
1838 (attrparent == NULL) ? "" : gettext("of attribute "),
1839 (attrparent == NULL) ? "" : attrparent,
1840 (attrparent == NULL) ? "" : gettext(" of "),
1841 (filetype == XATTR_FILE) ? longname : parent);
1842 goto out;
1845 if (lev > MAXLEV) {
1846 (void) fprintf(stderr,
1847 gettext("tar: directory nesting too deep, %s not dumped\n"),
1848 longname);
1849 goto out;
1852 if (getstat(dirfd, longname, shortname, attrparent))
1853 goto out;
1855 if (hflag) {
1857 * Catch nesting where a file is a symlink to its directory.
1859 j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
1860 if (S_ISLNK(sbuf.st_mode)) {
1861 if (symlink_lev++ >= MAXSYMLINKS) {
1862 (void) fprintf(stderr, gettext(
1863 "tar: %s: Number of symbolic links "
1864 "encountered during path name traversal "
1865 "exceeds MAXSYMLINKS\n"), longname);
1866 Errflg = 1;
1867 goto out;
1873 * Check if the input file is the same as the tar file we
1874 * are creating
1876 if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
1877 (void) fprintf(stderr, gettext(
1878 "tar: %s%s%s%s%s same as archive file\n"),
1879 rw_sysattr ? gettext("system ") : "",
1880 (longattrname == NULL) ? "" : gettext("attribute "),
1881 (longattrname == NULL) ? "" : longattrname,
1882 (longattrname == NULL) ? "" : gettext(" of "),
1883 longname);
1884 Errflg = 1;
1885 goto out;
1888 * Check size limit - we can't archive files that
1889 * exceed TAR_OFFSET_MAX bytes because of header
1890 * limitations. Exclude file types that set
1891 * st_size to zero below because they take no
1892 * archive space to represent contents.
1894 if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
1895 !S_ISDIR(stbuf.st_mode) &&
1896 !S_ISCHR(stbuf.st_mode) &&
1897 !S_ISBLK(stbuf.st_mode) &&
1898 (Eflag == 0)) {
1899 (void) fprintf(stderr, gettext(
1900 "tar: %s%s%s%s%s too large to archive. "
1901 "Use E function modifier.\n"),
1902 rw_sysattr ? gettext("system ") : "",
1903 (longattrname == NULL) ? "" : gettext("attribute "),
1904 (longattrname == NULL) ? "" : longattrname,
1905 (longattrname == NULL) ? "" : gettext(" of "),
1906 longname);
1907 if (errflag)
1908 exitflag = 1;
1909 Errflg = 1;
1910 goto out;
1913 if (tfile != NULL && checkupdate(longname) == 0) {
1914 goto out;
1916 if (checkw('r', longname) == 0) {
1917 goto out;
1920 if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0)
1921 goto out;
1923 if (Xflag) {
1924 if (is_in_table(exclude_tbl, longname)) {
1925 if (vflag) {
1926 (void) fprintf(vfile, gettext(
1927 "a %s excluded\n"), longname);
1929 goto out;
1934 * If the length of the fullname is greater than MAXNAM,
1935 * print out a message and return (unless extended headers are used,
1936 * in which case fullname is limited to PATH_MAX).
1939 if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
1940 (split > PATH_MAX)) {
1941 (void) fprintf(stderr, gettext(
1942 "tar: %s: file name too long\n"), longname);
1943 if (errflag)
1944 exitflag = 1;
1945 Errflg = 1;
1946 goto out;
1950 * We split the fullname into prefix and name components if any one
1951 * of three conditions holds:
1952 * -- the length of the fullname exceeds NAMSIZ,
1953 * -- the length of the fullname equals NAMSIZ, and the shortname
1954 * is less than NAMSIZ, (splitting in this case preserves
1955 * compatibility with 5.6 and 5.5.1 tar), or
1956 * -- the length of the fullname equals NAMSIZ, the file is a
1957 * directory and we are not in POSIX-conformant mode (where
1958 * trailing slashes are removed from directories).
1960 if ((split > NAMSIZ) ||
1961 (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1962 (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
1964 * Since path is limited to PRESIZ characters, look for the
1965 * last slash within PRESIZ + 1 characters only.
1967 (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
1968 tmpbuf = goodbuf;
1969 lastslash = strrchr(tmpbuf, '/');
1970 if (lastslash == NULL) {
1971 i = split; /* Length of name */
1972 j = 0; /* Length of prefix */
1973 goodbuf[0] = '\0';
1974 } else {
1975 *lastslash = '\0'; /* Terminate the prefix */
1976 j = strlen(tmpbuf);
1977 i = split - j - 1;
1980 * If the filename is greater than NAMSIZ we can't
1981 * archive the file unless we are using extended headers.
1983 if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
1984 !Pflag)) {
1985 /* Determine which (filename or path) is too long. */
1986 lastslash = strrchr(longname, '/');
1987 if (lastslash != NULL)
1988 i = strlen(lastslash + 1);
1989 if (Eflag > 0) {
1990 xhdr_flgs |= _X_PATH;
1991 Xtarhdr.x_path = longname;
1992 if (i <= NAMSIZ)
1993 (void) strcpy(junkbuf, lastslash + 1);
1994 else
1995 (void) sprintf(junkbuf, "%llu",
1996 xhdr_count + 1);
1997 if (split - i - 1 > PRESIZ)
1998 (void) strcpy(goodbuf, xhdr_dirname);
1999 } else {
2000 if ((i > NAMSIZ) || (i == NAMSIZ &&
2001 S_ISDIR(stbuf.st_mode) && !Pflag))
2002 (void) fprintf(stderr, gettext(
2003 "tar: %s: filename is greater than "
2004 "%d\n"), lastslash == NULL ?
2005 longname : lastslash + 1, NAMSIZ);
2006 else
2007 (void) fprintf(stderr, gettext(
2008 "tar: %s: prefix is greater than %d"
2009 "\n"), longname, PRESIZ);
2010 if (errflag)
2011 exitflag = 1;
2012 Errflg = 1;
2013 goto out;
2015 } else
2016 (void) strncpy(&junkbuf[0], longname + j + 1,
2017 strlen(longname + j + 1));
2018 name = junkbuf;
2019 prefix = goodbuf;
2020 } else {
2021 name = longname;
2023 if (Aflag) {
2024 if ((prefix != NULL) && (*prefix != '\0'))
2025 while (*prefix == '/')
2026 ++prefix;
2027 else
2028 while (*name == '/')
2029 ++name;
2032 switch (stbuf.st_mode & S_IFMT) {
2033 case S_IFDIR:
2034 stbuf.st_size = (off_t)0;
2035 blocks = TBLOCKS(stbuf.st_size);
2037 if (filetype != XATTR_FILE && Hiddendir == 0) {
2038 i = 0;
2039 cp = buf;
2040 while ((*cp++ = longname[i++]))
2042 *--cp = '/';
2043 *++cp = 0;
2045 if (!oflag) {
2046 tomodes(&stbuf);
2047 if (build_dblock(name, tchar, '5', filetype,
2048 &stbuf, stbuf.st_dev, prefix) != 0) {
2049 goto out;
2051 if (!Pflag) {
2053 * Old archives require a slash at the end
2054 * of a directory name.
2056 * XXX
2057 * If directory name is too long, will
2058 * slash overfill field?
2060 if (strlen(name) > (unsigned)NAMSIZ-1) {
2061 (void) fprintf(stderr, gettext(
2062 "tar: %s: filename is greater "
2063 "than %d\n"), name, NAMSIZ);
2064 if (errflag)
2065 exitflag = 1;
2066 Errflg = 1;
2067 goto out;
2068 } else {
2069 if (strlen(name) == (NAMSIZ - 1)) {
2070 (void) memcpy(dblock.dbuf.name,
2071 name, NAMSIZ);
2072 dblock.dbuf.name[NAMSIZ-1]
2073 = '/';
2074 } else
2075 (void) sprintf(dblock.dbuf.name,
2076 "%s/", name);
2079 * need to recalculate checksum
2080 * because the name changed.
2082 (void) sprintf(dblock.dbuf.chksum,
2083 "%07o", checksum(&dblock));
2087 if (put_extra_attributes(longname, shortname,
2088 longattrname, prefix, filetype, '5') != 0)
2089 goto out;
2091 #if defined(O_XATTR)
2093 * Reset header typeflag when archiving directory, since
2094 * build_dblock changed it on us.
2096 if (filetype == XATTR_FILE) {
2097 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2098 } else {
2099 dblock.dbuf.typeflag = '5';
2101 #else
2102 dblock.dbuf.typeflag = '5';
2103 #endif
2105 (void) sprintf(dblock.dbuf.chksum, "%07o",
2106 checksum(&dblock));
2108 (void) writetbuf((char *)&dblock, 1);
2110 if (vflag) {
2111 #ifdef DEBUG
2112 if (NotTape)
2113 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2115 #endif
2116 if (filetype == XATTR_FILE && Hiddendir) {
2117 (void) fprintf(vfile, "a %s attribute %s ",
2118 longname, longattrname);
2120 } else {
2121 (void) fprintf(vfile, "a %s/ ", longname);
2123 if (NotTape)
2124 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2125 K(blocks));
2126 else
2127 (void) fprintf(vfile, gettext("%" FMT_blkcnt_t
2128 " tape blocks\n"), blocks);
2132 * If hidden dir then break now since xattrs_put() will do
2133 * the iterating of the directory.
2135 * At the moment, there can only be system attributes on
2136 * attributes. There can be no attributes on attributes or
2137 * directories within the attributes hidden directory hierarchy.
2139 if (filetype == XATTR_FILE)
2140 break;
2142 if (*shortname != '/')
2143 (void) sprintf(newparent, "%s/%s", parent, shortname);
2144 else
2145 (void) sprintf(newparent, "%s", shortname);
2147 if (chdir(shortname) < 0) {
2148 vperror(0, "%s", newparent);
2149 goto out;
2152 if ((dirp = opendir(".")) == NULL) {
2153 vperror(0, gettext(
2154 "can't open directory %s"), longname);
2155 if (chdir(parent) < 0)
2156 vperror(0, gettext("cannot change back?: %s"),
2157 parent);
2158 goto out;
2162 * Create a list of files (children) in this directory to avoid
2163 * having to perform telldir()/seekdir().
2165 while ((dp = readdir(dirp)) != NULL && !term) {
2166 if ((strcmp(".", dp->d_name) == 0) ||
2167 (strcmp("..", dp->d_name) == 0))
2168 continue;
2169 if (((cptr = (file_list_t *)calloc(sizeof (char),
2170 sizeof (file_list_t))) == NULL) ||
2171 ((cptr->name = strdup(dp->d_name)) == NULL)) {
2172 vperror(1, gettext(
2173 "Insufficient memory for directory "
2174 "list entry %s/%s\n"),
2175 newparent, dp->d_name);
2178 /* Add the file to the list */
2179 if (child == NULL) {
2180 child = cptr;
2181 } else {
2182 child_end->next = cptr;
2184 child_end = cptr;
2186 (void) closedir(dirp);
2189 * Archive each of the files in the current directory.
2190 * If a file is a directory, putfile() is called
2191 * recursively to archive the file hierarchy of the
2192 * directory before archiving the next file in the
2193 * current directory.
2195 while ((child != NULL) && !term) {
2196 (void) strcpy(cp, child->name);
2197 archtype = putfile(buf, cp, newparent, NULL,
2198 NORMAL_FILE, lev + 1, symlink_lev);
2200 if (!exitflag) {
2201 if ((atflag || saflag) &&
2202 (archtype == PUT_NOTAS_LINK)) {
2203 xattrs_put(buf, cp, newparent, NULL);
2206 if (exitflag)
2207 break;
2209 /* Free each child as we are done processing it. */
2210 cptr = child;
2211 child = child->next;
2212 free(cptr->name);
2213 free(cptr);
2215 if ((child != NULL) && !term) {
2216 free_children(child);
2219 if (chdir(parent) < 0) {
2220 vperror(0, gettext("cannot change back?: %s"), parent);
2223 break;
2225 case S_IFLNK:
2226 readlink_max = NAMSIZ;
2227 if (stbuf.st_size > NAMSIZ) {
2228 if (Eflag > 0) {
2229 xhdr_flgs |= _X_LINKPATH;
2230 readlink_max = PATH_MAX;
2231 } else {
2232 (void) fprintf(stderr, gettext(
2233 "tar: %s: symbolic link too long\n"),
2234 longname);
2235 if (errflag)
2236 exitflag = 1;
2237 Errflg = 1;
2238 goto out;
2242 * Sym-links need header size of zero since you
2243 * don't store any data for this type.
2245 stbuf.st_size = (off_t)0;
2246 tomodes(&stbuf);
2247 i = readlink(shortname, filetmp, readlink_max);
2248 if (i < 0) {
2249 vperror(0, gettext(
2250 "can't read symbolic link %s"), longname);
2251 goto out;
2252 } else {
2253 filetmp[i] = 0;
2255 if (vflag)
2256 (void) fprintf(vfile, gettext(
2257 "a %s symbolic link to %s\n"),
2258 longname, filetmp);
2259 if (xhdr_flgs & _X_LINKPATH) {
2260 Xtarhdr.x_linkpath = filetmp;
2261 if (build_dblock(name, tchar, '2', filetype, &stbuf,
2262 stbuf.st_dev, prefix) != 0)
2263 goto out;
2264 } else
2265 if (build_dblock(name, filetmp, '2', filetype, &stbuf,
2266 stbuf.st_dev, prefix) != 0)
2267 goto out;
2268 (void) writetbuf((char *)&dblock, 1);
2270 * No acls for symlinks: mode is always 777
2271 * dont call write ancillary
2273 rc = PUT_AS_LINK;
2274 break;
2275 case S_IFREG:
2276 if ((infile = openat(dirfd, shortname, 0)) < 0) {
2277 vperror(0, "unable to open %s%s%s%s", longname,
2278 rw_sysattr ? gettext(" system") : "",
2279 (filetype == XATTR_FILE) ?
2280 gettext(" attribute ") : "",
2281 (filetype == XATTR_FILE) ? (longattrname == NULL) ?
2282 shortname : longattrname : "");
2283 goto out;
2286 blocks = TBLOCKS(stbuf.st_size);
2288 if (put_link(name, longname, shortname, longattrname,
2289 prefix, filetype, '1') == 0) {
2290 (void) close(infile);
2291 rc = PUT_AS_LINK;
2292 goto out;
2295 tomodes(&stbuf);
2297 /* correctly handle end of volume */
2298 while (mulvol && tapepos + blocks + 1 > blocklim) {
2299 /* file won't fit */
2300 if (eflag) {
2301 if (blocks <= blocklim) {
2302 newvol();
2303 break;
2305 (void) fprintf(stderr, gettext(
2306 "tar: Single file cannot fit on volume\n"));
2307 done(3);
2309 /* split if floppy has some room and file is large */
2310 if (((blocklim - tapepos) >= EXTMIN) &&
2311 ((blocks + 1) >= blocklim/10)) {
2312 splitfile(longname, infile,
2313 name, prefix, filetype);
2314 (void) close(dirfd);
2315 (void) close(infile);
2316 goto out;
2318 newvol(); /* not worth it--just get new volume */
2320 #ifdef DEBUG
2321 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2322 blocks);
2323 #endif
2324 if (build_dblock(name, tchar, '0', filetype,
2325 &stbuf, stbuf.st_dev, prefix) != 0) {
2326 goto out;
2328 if (vflag) {
2329 #ifdef DEBUG
2330 if (NotTape)
2331 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2333 #endif
2334 (void) fprintf(vfile, "a %s%s%s%s ", longname,
2335 rw_sysattr ? gettext(" system") : "",
2336 (filetype == XATTR_FILE) ? gettext(
2337 " attribute ") : "",
2338 (filetype == XATTR_FILE) ?
2339 longattrname : "");
2340 if (NotTape)
2341 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2342 K(blocks));
2343 else
2344 (void) fprintf(vfile,
2345 gettext("%" FMT_blkcnt_t " tape blocks\n"),
2346 blocks);
2349 if (put_extra_attributes(longname, shortname, longattrname,
2350 prefix, filetype, '0') != 0)
2351 goto out;
2354 * No need to reset typeflag for extended attribute here, since
2355 * put_extra_attributes already set it and we haven't called
2356 * build_dblock().
2358 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2359 hint = writetbuf((char *)&dblock, 1);
2360 maxread = max(min(stbuf.st_blksize, stbuf.st_size),
2361 (nblock * TBLOCK));
2362 if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
2363 maxread = TBLOCK;
2364 bigbuf = buf;
2367 while (((i = (int)
2368 read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
2369 blocks) {
2370 blkcnt_t nblks;
2372 nblks = ((i-1)/TBLOCK)+1;
2373 if (nblks > blocks)
2374 nblks = blocks;
2375 hint = writetbuf(bigbuf, nblks);
2376 blocks -= nblks;
2378 (void) close(infile);
2379 if (bigbuf != buf)
2380 free(bigbuf);
2381 if (i < 0)
2382 vperror(0, gettext("Read error on %s"), longname);
2383 else if (blocks != 0 || i != 0) {
2384 (void) fprintf(stderr, gettext(
2385 "tar: %s: file changed size\n"), longname);
2386 if (errflag) {
2387 exitflag = 1;
2388 Errflg = 1;
2389 } else if (!Dflag) {
2390 Errflg = 1;
2393 putempty(blocks);
2394 break;
2395 case S_IFIFO:
2396 blocks = TBLOCKS(stbuf.st_size);
2397 stbuf.st_size = (off_t)0;
2399 if (put_link(name, longname, shortname, longattrname,
2400 prefix, filetype, '6') == 0) {
2401 rc = PUT_AS_LINK;
2402 goto out;
2404 tomodes(&stbuf);
2406 while (mulvol && tapepos + blocks + 1 > blocklim) {
2407 if (eflag) {
2408 if (blocks <= blocklim) {
2409 newvol();
2410 break;
2412 (void) fprintf(stderr, gettext(
2413 "tar: Single file cannot fit on volume\n"));
2414 done(3);
2417 if (((blocklim - tapepos) >= EXTMIN) &&
2418 ((blocks + 1) >= blocklim/10)) {
2419 splitfile(longname, infile, name,
2420 prefix, filetype);
2421 (void) close(dirfd);
2422 (void) close(infile);
2423 goto out;
2425 newvol();
2427 #ifdef DEBUG
2428 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2429 blocks);
2430 #endif
2431 if (vflag) {
2432 #ifdef DEBUG
2433 if (NotTape)
2434 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2436 #endif
2437 if (NotTape)
2438 (void) fprintf(vfile, gettext("a %s %"
2439 FMT_blkcnt_t "K\n "), longname, K(blocks));
2440 else
2441 (void) fprintf(vfile, gettext(
2442 "a %s %" FMT_blkcnt_t " tape blocks\n"),
2443 longname, blocks);
2445 if (build_dblock(name, tchar, '6', filetype,
2446 &stbuf, stbuf.st_dev, prefix) != 0)
2447 goto out;
2449 if (put_extra_attributes(longname, shortname, longattrname,
2450 prefix, filetype, '6') != 0)
2451 goto out;
2453 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2454 dblock.dbuf.typeflag = '6';
2456 (void) writetbuf((char *)&dblock, 1);
2457 break;
2458 case S_IFCHR:
2459 stbuf.st_size = (off_t)0;
2460 blocks = TBLOCKS(stbuf.st_size);
2461 if (put_link(name, longname, shortname, longattrname,
2462 prefix, filetype, '3') == 0) {
2463 rc = PUT_AS_LINK;
2464 goto out;
2466 tomodes(&stbuf);
2468 while (mulvol && tapepos + blocks + 1 > blocklim) {
2469 if (eflag) {
2470 if (blocks <= blocklim) {
2471 newvol();
2472 break;
2474 (void) fprintf(stderr, gettext(
2475 "tar: Single file cannot fit on volume\n"));
2476 done(3);
2479 if (((blocklim - tapepos) >= EXTMIN) &&
2480 ((blocks + 1) >= blocklim/10)) {
2481 splitfile(longname, infile, name,
2482 prefix, filetype);
2483 (void) close(dirfd);
2484 goto out;
2486 newvol();
2488 #ifdef DEBUG
2489 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2490 blocks);
2491 #endif
2492 if (vflag) {
2493 #ifdef DEBUG
2494 if (NotTape)
2495 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2497 #endif
2498 if (NotTape)
2499 (void) fprintf(vfile, gettext("a %s %"
2500 FMT_blkcnt_t "K\n"), longname, K(blocks));
2501 else
2502 (void) fprintf(vfile, gettext("a %s %"
2503 FMT_blkcnt_t " tape blocks\n"), longname,
2504 blocks);
2506 if (build_dblock(name, tchar, '3',
2507 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2508 goto out;
2510 if (put_extra_attributes(longname, shortname, longattrname,
2511 prefix, filetype, '3') != 0)
2512 goto out;
2514 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2515 dblock.dbuf.typeflag = '3';
2517 (void) writetbuf((char *)&dblock, 1);
2518 break;
2519 case S_IFBLK:
2520 stbuf.st_size = (off_t)0;
2521 blocks = TBLOCKS(stbuf.st_size);
2522 if (put_link(name, longname, shortname, longattrname,
2523 prefix, filetype, '4') == 0) {
2524 rc = PUT_AS_LINK;
2525 goto out;
2527 tomodes(&stbuf);
2529 while (mulvol && tapepos + blocks + 1 > blocklim) {
2530 if (eflag) {
2531 if (blocks <= blocklim) {
2532 newvol();
2533 break;
2535 (void) fprintf(stderr, gettext(
2536 "tar: Single file cannot fit on volume\n"));
2537 done(3);
2540 if (((blocklim - tapepos) >= EXTMIN) &&
2541 ((blocks + 1) >= blocklim/10)) {
2542 splitfile(longname, infile,
2543 name, prefix, filetype);
2544 (void) close(dirfd);
2545 goto out;
2547 newvol();
2549 #ifdef DEBUG
2550 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2551 blocks);
2552 #endif
2553 if (vflag) {
2554 #ifdef DEBUG
2555 if (NotTape)
2556 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2558 #endif
2559 (void) fprintf(vfile, "a %s ", longname);
2560 if (NotTape)
2561 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2562 K(blocks));
2563 else
2564 (void) fprintf(vfile, gettext("%"
2565 FMT_blkcnt_t " tape blocks\n"), blocks);
2567 if (build_dblock(name, tchar, '4',
2568 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2569 goto out;
2571 if (put_extra_attributes(longname, shortname, longattrname,
2572 prefix, filetype, '4') != 0)
2573 goto out;
2575 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2576 dblock.dbuf.typeflag = '4';
2578 (void) writetbuf((char *)&dblock, 1);
2579 break;
2580 default:
2581 (void) fprintf(stderr, gettext(
2582 "tar: %s is not a file. Not dumped\n"), longname);
2583 if (errflag)
2584 exitflag = 1;
2585 Errflg = 1;
2586 goto out;
2589 out:
2590 if ((dirfd != -1) && (filetype != XATTR_FILE)) {
2591 (void) close(dirfd);
2593 return (rc);
2598 * splitfile dump a large file across volumes
2600 * splitfile(longname, fd);
2601 * char *longname; full name of file
2602 * int ifd; input file descriptor
2604 * NOTE: only called by putfile() to dump a large file.
2607 static void
2608 splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
2610 blkcnt_t blocks;
2611 off_t bytes, s;
2612 char buf[TBLOCK];
2613 int i, extents;
2615 blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */
2618 * # extents =
2619 * size of file after using up rest of this floppy
2620 * blocks - (blocklim - tapepos) + 1 (for header)
2621 * plus roundup value before divide by blocklim-1
2622 * + (blocklim - 1) - 1
2623 * all divided by blocklim-1 (one block for each header).
2624 * this gives
2625 * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2626 * which reduces to the expression used.
2627 * one is added to account for this first extent.
2629 * When one is dealing with extremely large archives, one may want
2630 * to allow for a large number of extents. This code should be
2631 * revisited to determine if extents should be changed to something
2632 * larger than an int.
2634 extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
2636 if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */
2637 (void) fprintf(stderr, gettext(
2638 "tar: %s needs unusual number of volumes to split\n"
2639 "tar: %s not dumped\n"), longname, longname);
2640 return;
2642 if (build_dblock(name, tchar, '0', filetype,
2643 &stbuf, stbuf.st_dev, prefix) != 0)
2644 return;
2646 dblock.dbuf.extotal = extents;
2647 bytes = stbuf.st_size;
2650 * The value contained in dblock.dbuf.efsize was formerly used when the
2651 * v flag was specified in conjunction with the t flag. Although it is
2652 * no longer used, older versions of tar will expect the former
2653 * behaviour, so we must continue to write it to the archive.
2655 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2656 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2657 * store 0.
2659 if (bytes <= TAR_EFSIZE_MAX)
2660 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
2661 else
2662 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
2664 (void) fprintf(stderr, gettext(
2665 "tar: large file %s needs %d extents.\n"
2666 "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
2667 longname, extents, K(tapepos));
2669 s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
2670 for (i = 1; i <= extents; i++) {
2671 if (i > 1) {
2672 newvol();
2673 if (i == extents)
2674 s = bytes; /* last ext. gets true bytes */
2675 else
2676 s = (off_t)(blocklim - 1)*TBLOCK; /* all */
2678 bytes -= s;
2679 blocks = TBLOCKS(s);
2681 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
2682 dblock.dbuf.extno = i;
2683 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2684 (void) writetbuf((char *)&dblock, 1);
2686 if (vflag)
2687 (void) fprintf(vfile,
2688 "+++ a %s %" FMT_blkcnt_t "K [extent #%d of %d]\n",
2689 longname, K(blocks), i, extents);
2690 while (blocks && read(ifd, buf, TBLOCK) > 0) {
2691 blocks--;
2692 (void) writetbuf(buf, 1);
2694 if (blocks != 0) {
2695 (void) fprintf(stderr, gettext(
2696 "tar: %s: file changed size\n"), longname);
2697 (void) fprintf(stderr, gettext(
2698 "tar: aborting split file %s\n"), longname);
2699 (void) close(ifd);
2700 return;
2703 (void) close(ifd);
2704 if (vflag)
2705 (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
2706 "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
2707 extents);
2711 * convtoreg - determines whether the file should be converted to a
2712 * regular file when extracted
2714 * Returns 1 when file size > 0 and typeflag is not recognized
2715 * Otherwise returns 0
2717 static int
2718 convtoreg(off_t size)
2720 if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
2721 (dblock.dbuf.typeflag != NULL) && (dblock.dbuf.typeflag != '1') &&
2722 (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
2723 (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
2724 (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
2725 (dblock.dbuf.typeflag != 'L') &&
2726 (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
2727 (dblock.dbuf.typeflag != 'X')) {
2728 return (1);
2730 return (0);
2733 #if defined(O_XATTR)
2734 static int
2735 save_cwd(void)
2737 return (open(".", O_RDONLY));
2739 #endif
2741 #if defined(O_XATTR)
2742 static void
2743 rest_cwd(int *cwd)
2745 if (*cwd != -1) {
2746 if (fchdir(*cwd) < 0) {
2747 vperror(0, gettext(
2748 "Cannot fchdir to attribute directory"));
2749 exit(1);
2751 (void) close(*cwd);
2752 *cwd = -1;
2755 #endif
2758 * Verify the underlying file system supports the attribute type.
2759 * Only archive extended attribute files when '-@' was specified.
2760 * Only archive system extended attribute files if '-/' was specified.
2762 #if defined(O_XATTR)
2763 static attr_status_t
2764 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
2765 int *ext_attrflg)
2768 * Verify extended attributes are supported/exist. We only
2769 * need to check if we are processing a base file, not an
2770 * extended attribute.
2772 if (attrflg) {
2773 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
2774 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
2777 if (atflag) {
2778 if (!*ext_attrflg) {
2779 #if defined(_PC_SATTR_ENABLED)
2780 if (saflag) {
2781 /* Verify system attributes are supported */
2782 if (sysattr_support(filename,
2783 (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
2784 _PC_SATTR_ENABLED) != 1) {
2785 return (ATTR_SATTR_ERR);
2787 } else
2788 return (ATTR_XATTR_ERR);
2789 #else
2790 return (ATTR_XATTR_ERR);
2791 #endif /* _PC_SATTR_ENABLED */
2794 #if defined(_PC_SATTR_ENABLED)
2795 } else if (saflag) {
2796 /* Verify system attributes are supported */
2797 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
2798 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
2799 return (ATTR_SATTR_ERR);
2801 #endif /* _PC_SATTR_ENABLED */
2802 } else {
2803 return (ATTR_SKIP);
2806 return (ATTR_OK);
2808 #endif
2810 #if defined(O_XATTR)
2812 * Recursively open attribute directories until the attribute directory
2813 * containing the specified attribute, attrname, is opened.
2815 * Currently, only 2 directory levels of attributes are supported, (i.e.,
2816 * extended system attributes on extended attributes). The following are
2817 * the possible input combinations:
2818 * 1. Open the attribute directory of the base file (don't change
2819 * into it).
2820 * attrinfo->parent = NULL
2821 * attrname = '.'
2822 * 2. Open the attribute directory of the base file and change into it.
2823 * attrinfo->parent = NULL
2824 * attrname = <attr> | <sys_attr>
2825 * 3. Open the attribute directory of the base file, change into it,
2826 * then recursively call open_attr_dir() to open the attribute's
2827 * parent directory (don't change into it).
2828 * attrinfo->parent = <attr>
2829 * attrname = '.'
2830 * 4. Open the attribute directory of the base file, change into it,
2831 * then recursively call open_attr_dir() to open the attribute's
2832 * parent directory and change into it.
2833 * attrinfo->parent = <attr>
2834 * attrname = <attr> | <sys_attr>
2836 * An attribute directory will be opened only if the underlying file system
2837 * supports the attribute type, and if the command line specifications (atflag
2838 * and saflag) enable the processing of the attribute type.
2840 * On succesful return, attrinfo->parentfd will be the file descriptor of the
2841 * opened attribute directory. In addition, if the attribute is a read-write
2842 * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2843 * it will be set to 0.
2845 * Possible return values:
2846 * ATTR_OK Successfully opened and, if needed, changed into the
2847 * attribute directory containing attrname.
2848 * ATTR_SKIP The command line specifications don't enable the
2849 * processing of the attribute type.
2850 * ATTR_CHDIR_ERR An error occurred while trying to change into an
2851 * attribute directory.
2852 * ATTR_OPEN_ERR An error occurred while trying to open an
2853 * attribute directory.
2854 * ATTR_XATTR_ERR The underlying file system doesn't support extended
2855 * attributes.
2856 * ATTR_SATTR_ERR The underlying file system doesn't support extended
2857 * system attributes.
2859 static int
2860 open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
2862 attr_status_t rc;
2863 int firsttime = (attrinfo->attr_parentfd == -1);
2864 int saveerrno;
2865 int ext_attr;
2868 * open_attr_dir() was recursively called (input combination number 4),
2869 * close the previously opened file descriptor as we've already changed
2870 * into it.
2872 if (!firsttime) {
2873 (void) close(attrinfo->attr_parentfd);
2874 attrinfo->attr_parentfd = -1;
2878 * Verify that the underlying file system supports the restoration
2879 * of the attribute.
2881 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
2882 &ext_attr)) != ATTR_OK) {
2883 return (rc);
2886 /* Open the base file's attribute directory */
2887 if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
2889 * Save the errno from the attropen so it can be reported
2890 * if the retry of the attropen fails.
2892 saveerrno = errno;
2893 if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
2894 NULL, ".", O_RDONLY, 0)) == -1) {
2896 * Reset typeflag back to real value so passtape
2897 * will skip ahead correctly.
2899 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2900 (void) close(attrinfo->attr_parentfd);
2901 attrinfo->attr_parentfd = -1;
2902 errno = saveerrno;
2903 return (ATTR_OPEN_ERR);
2908 * Change into the parent attribute's directory unless we are
2909 * processing the hidden attribute directory of the base file itself.
2911 if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
2912 if (fchdir(attrinfo->attr_parentfd) != 0) {
2913 saveerrno = errno;
2914 (void) close(attrinfo->attr_parentfd);
2915 attrinfo->attr_parentfd = -1;
2916 errno = saveerrno;
2917 return (ATTR_CHDIR_ERR);
2921 /* Determine if the attribute should be processed */
2922 if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
2923 &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
2924 saveerrno = errno;
2925 (void) close(attrinfo->attr_parentfd);
2926 attrinfo->attr_parentfd = -1;
2927 errno = saveerrno;
2928 return (rc);
2932 * If the attribute is an extended attribute, or extended system
2933 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2934 * recursively call open_attr_dir() to open the attribute directory
2935 * of the parent attribute.
2937 if (firsttime && (attrinfo->attr_parent != NULL)) {
2938 return (open_attr_dir(attrname, attrinfo->attr_parent,
2939 attrinfo->attr_parentfd, attrinfo));
2942 return (ATTR_OK);
2944 #endif
2946 static void
2947 #ifdef _iBCS2
2948 doxtract(char *argv[], int tbl_cnt)
2949 #else
2950 doxtract(char *argv[])
2951 #endif
2953 struct stat xtractbuf; /* stat on file after extracting */
2954 blkcnt_t blocks;
2955 off_t bytes;
2956 int ofile;
2957 int newfile; /* Does the file already exist */
2958 int xcnt = 0; /* count # files extracted */
2959 int fcnt = 0; /* count # files in argv list */
2960 int dir;
2961 int dirfd = -1;
2962 int cwd = -1;
2963 int rw_sysattr;
2964 int saveerrno;
2965 uid_t Uid;
2966 char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
2967 char dirname[PATH_MAX+1];
2968 char templink[PATH_MAX+1]; /* temp link with terminating NULL */
2969 int once = 1;
2970 int error;
2971 int symflag;
2972 int want;
2973 attr_data_t *attrinfo = NULL; /* attribute info */
2974 acl_t *aclp = NULL; /* acl info */
2975 char dot[] = "."; /* dirp for using realpath */
2976 timestruc_t time_zero; /* used for call to doDirTimes */
2977 int dircreate;
2978 int convflag;
2979 time_zero.tv_sec = 0;
2980 time_zero.tv_nsec = 0;
2982 /* reset Trusted Extensions variables */
2983 rpath_flag = 0;
2984 lk_rpath_flag = 0;
2985 dir_flag = 0;
2986 mld_flag = 0;
2987 bslundef(&bs_label);
2988 bsllow(&admin_low);
2989 bslhigh(&admin_high);
2990 orig_namep = 0;
2992 dumping = 0; /* for newvol(), et al: we are not writing */
2995 * Count the number of files that are to be extracted
2997 Uid = getuid();
2999 #ifdef _iBCS2
3000 initarg(argv, Filefile);
3001 while (nextarg() != NULL)
3002 ++fcnt;
3003 fcnt += tbl_cnt;
3004 #endif /* _iBCS2 */
3006 for (;;) {
3007 convflag = 0;
3008 symflag = 0;
3009 dir = 0;
3010 Hiddendir = 0;
3011 rw_sysattr = 0;
3012 ofile = -1;
3014 if (dirfd != -1) {
3015 (void) close(dirfd);
3016 dirfd = -1;
3018 if (ofile != -1) {
3019 if (close(ofile) != 0)
3020 vperror(2, gettext("close error"));
3023 #if defined(O_XATTR)
3024 if (cwd != -1) {
3025 rest_cwd(&cwd);
3027 #endif
3029 /* namep is set by wantit to point to the full name */
3030 if ((want = wantit(argv, &namep, &dirp, &comp,
3031 &attrinfo)) == 0) {
3032 #if defined(O_XATTR)
3033 if (xattrp != NULL) {
3034 free(xattrhead);
3035 xattrp = NULL;
3036 xattr_linkp = NULL;
3037 xattrhead = NULL;
3039 #endif
3040 continue;
3042 if (want == -1)
3043 break;
3045 /* Trusted Extensions */
3047 * During tar extract (x):
3048 * If the pathname of the restored file has been
3049 * reconstructed from the ancillary file,
3050 * use it to process the normal file.
3052 if (mld_flag) { /* Skip over .MLD. directory */
3053 mld_flag = 0;
3054 passtape();
3055 continue;
3057 orig_namep = namep; /* save original */
3058 if (rpath_flag) {
3059 namep = real_path; /* use zone path */
3060 comp = real_path; /* use zone path */
3061 dirp = dot; /* work from the top */
3062 rpath_flag = 0; /* reset */
3065 if (dirfd != -1)
3066 (void) close(dirfd);
3068 (void) strcpy(&dirname[0], namep);
3069 dircreate = checkdir(&dirname[0]);
3071 #if defined(O_XATTR)
3072 if (xattrp != NULL) {
3073 int rc;
3075 if (((cwd = save_cwd()) == -1) ||
3076 ((rc = open_attr_dir(comp, dirp, cwd,
3077 attrinfo)) != ATTR_OK)) {
3078 if (cwd == -1) {
3079 vperror(0, gettext(
3080 "unable to save current working "
3081 "directory while processing "
3082 "attribute %s of %s"),
3083 dirp, attrinfo->attr_path);
3084 } else if (rc != ATTR_SKIP) {
3085 (void) fprintf(vfile,
3086 gettext("tar: cannot open "
3087 "%sattribute %s of file %s: %s\n"),
3088 attrinfo->attr_rw_sysattr ? gettext(
3089 "system ") : "",
3090 comp, dirp, strerror(errno));
3092 free(xattrhead);
3093 xattrp = NULL;
3094 xattr_linkp = NULL;
3095 xattrhead = NULL;
3097 passtape();
3098 continue;
3099 } else {
3100 dirfd = attrinfo->attr_parentfd;
3101 rw_sysattr = attrinfo->attr_rw_sysattr;
3103 } else {
3104 dirfd = open(dirp, O_RDONLY);
3106 #else
3107 dirfd = open(dirp, O_RDONLY);
3108 #endif
3109 if (dirfd == -1) {
3110 (void) fprintf(vfile, gettext(
3111 "tar: cannot open %s: %s\n"),
3112 dirp, strerror(errno));
3113 passtape();
3114 continue;
3117 if (xhdr_flgs & _X_LINKPATH)
3118 (void) strcpy(templink, Xtarhdr.x_linkpath);
3119 else {
3120 #if defined(O_XATTR)
3121 if (xattrp && dblock.dbuf.typeflag == '1') {
3122 (void) sprintf(templink, "%.*s", NAMSIZ,
3123 xattrp->h_names);
3124 } else {
3125 (void) sprintf(templink, "%.*s", NAMSIZ,
3126 dblock.dbuf.linkname);
3128 #else
3129 (void) sprintf(templink, "%.*s", NAMSIZ,
3130 dblock.dbuf.linkname);
3131 #endif
3134 if (Fflag) {
3135 char *s;
3137 if ((s = strrchr(namep, '/')) == 0)
3138 s = namep;
3140 else
3141 s++;
3142 if (checkf(s, stbuf.st_mode, Fflag) == 0) {
3143 passtape();
3144 continue;
3148 if (checkw('x', namep) == 0) {
3149 passtape();
3150 continue;
3152 if (once) {
3153 if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
3154 if (geteuid() == (uid_t)0) {
3155 checkflag = 1;
3156 pflag = 1;
3157 } else {
3158 /* get file creation mask */
3159 Oumask = umask(0);
3160 (void) umask(Oumask);
3162 once = 0;
3163 } else {
3164 if (geteuid() == (uid_t)0) {
3165 pflag = 1;
3166 checkflag = 2;
3168 if (!pflag) {
3169 /* get file creation mask */
3170 Oumask = umask(0);
3171 (void) umask(Oumask);
3173 once = 0;
3177 #if defined(O_XATTR)
3179 * Handle extraction of hidden attr dir.
3180 * Dir is automatically created, we only
3181 * need to update mode and perm's.
3183 if ((xattrp != NULL) && Hiddendir == 1) {
3184 bytes = stbuf.st_size;
3185 blocks = TBLOCKS(bytes);
3186 if (vflag) {
3187 (void) fprintf(vfile,
3188 "x %s%s%s, %" FMT_off_t " bytes, ", namep,
3189 gettext(" attribute "),
3190 xattrapath, bytes);
3191 if (NotTape)
3192 (void) fprintf(vfile,
3193 "%" FMT_blkcnt_t "K\n", K(blocks));
3194 else
3195 (void) fprintf(vfile, gettext("%"
3196 FMT_blkcnt_t " tape blocks\n"),
3197 blocks);
3201 * Set the permissions and mode of the attribute
3202 * unless the attribute is a system attribute (can't
3203 * successfully do this) or the hidden attribute
3204 * directory (".") of an attribute (when the attribute
3205 * is restored, the hidden attribute directory of an
3206 * attribute is transient). Note: when the permissions
3207 * and mode are set for the hidden attribute directory
3208 * of a file on a system supporting extended system
3209 * attributes, even though it returns successfully, it
3210 * will not have any affect since the attribute
3211 * directory is transient.
3213 if (attrinfo->attr_parent == NULL) {
3214 if (fchownat(dirfd, ".", stbuf.st_uid,
3215 stbuf.st_gid, 0) != 0) {
3216 vperror(0, gettext(
3217 "%s%s%s: failed to set ownership "
3218 "of attribute directory"), namep,
3219 gettext(" attribute "), xattrapath);
3222 if (fchmod(dirfd, stbuf.st_mode) != 0) {
3223 vperror(0, gettext(
3224 "%s%s%s: failed to set permissions "
3225 "of attribute directory"), namep,
3226 gettext(" attribute "), xattrapath);
3229 goto filedone;
3231 #endif
3233 if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
3234 dir = 1;
3235 if (vflag) {
3236 (void) fprintf(vfile, "x %s, 0 bytes, ",
3237 &dirname[0]);
3238 if (NotTape)
3239 (void) fprintf(vfile, "0K\n");
3240 else
3241 (void) fprintf(vfile, gettext("%"
3242 FMT_blkcnt_t " tape blocks\n"),
3243 (blkcnt_t)0);
3245 goto filedone;
3248 if (dblock.dbuf.typeflag == '6') { /* FIFO */
3249 if (rmdir(namep) < 0) {
3250 if (errno == ENOTDIR)
3251 (void) unlink(namep);
3253 linkp = templink;
3254 if (*linkp != NULL) {
3255 if (Aflag && *linkp == '/')
3256 linkp++;
3257 if (link(linkp, namep) < 0) {
3258 (void) fprintf(stderr, gettext(
3259 "tar: %s: cannot link\n"), namep);
3260 continue;
3262 if (vflag)
3263 (void) fprintf(vfile, gettext(
3264 "x %s linked to %s\n"), namep,
3265 linkp);
3266 xcnt++; /* increment # files extracted */
3267 continue;
3269 if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
3270 (int)Gen.g_devmajor) < 0) {
3271 vperror(0, gettext("%s: mknod failed"), namep);
3272 continue;
3274 bytes = stbuf.st_size;
3275 blocks = TBLOCKS(bytes);
3276 if (vflag) {
3277 (void) fprintf(vfile, "x %s, %" FMT_off_t
3278 " bytes, ", namep, bytes);
3279 if (NotTape)
3280 (void) fprintf(vfile, "%" FMT_blkcnt_t
3281 "K\n", K(blocks));
3282 else
3283 (void) fprintf(vfile, gettext("%"
3284 FMT_blkcnt_t " tape blocks\n"),
3285 blocks);
3287 goto filedone;
3289 if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
3290 if (rmdir(namep) < 0) {
3291 if (errno == ENOTDIR)
3292 (void) unlink(namep);
3294 linkp = templink;
3295 if (*linkp != NULL) {
3296 if (Aflag && *linkp == '/')
3297 linkp++;
3298 if (link(linkp, namep) < 0) {
3299 (void) fprintf(stderr, gettext(
3300 "tar: %s: cannot link\n"), namep);
3301 continue;
3303 if (vflag)
3304 (void) fprintf(vfile, gettext(
3305 "x %s linked to %s\n"), namep,
3306 linkp);
3307 xcnt++; /* increment # files extracted */
3308 continue;
3310 if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
3311 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3312 vperror(0, gettext(
3313 "%s: mknod failed"), namep);
3314 continue;
3316 bytes = stbuf.st_size;
3317 blocks = TBLOCKS(bytes);
3318 if (vflag) {
3319 (void) fprintf(vfile, "x %s, %" FMT_off_t
3320 " bytes, ", namep, bytes);
3321 if (NotTape)
3322 (void) fprintf(vfile, "%" FMT_blkcnt_t
3323 "K\n", K(blocks));
3324 else
3325 (void) fprintf(vfile, gettext("%"
3326 FMT_blkcnt_t " tape blocks\n"),
3327 blocks);
3329 goto filedone;
3330 } else if (dblock.dbuf.typeflag == '3' && Uid) {
3331 (void) fprintf(stderr, gettext(
3332 "Can't create special %s\n"), namep);
3333 continue;
3336 /* BLOCK SPECIAL */
3338 if (dblock.dbuf.typeflag == '4' && !Uid) {
3339 if (rmdir(namep) < 0) {
3340 if (errno == ENOTDIR)
3341 (void) unlink(namep);
3343 linkp = templink;
3344 if (*linkp != NULL) {
3345 if (Aflag && *linkp == '/')
3346 linkp++;
3347 if (link(linkp, namep) < 0) {
3348 (void) fprintf(stderr, gettext(
3349 "tar: %s: cannot link\n"), namep);
3350 continue;
3352 if (vflag)
3353 (void) fprintf(vfile, gettext(
3354 "x %s linked to %s\n"), namep,
3355 linkp);
3356 xcnt++; /* increment # files extracted */
3357 continue;
3359 if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
3360 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3361 vperror(0, gettext("%s: mknod failed"), namep);
3362 continue;
3364 bytes = stbuf.st_size;
3365 blocks = TBLOCKS(bytes);
3366 if (vflag) {
3367 (void) fprintf(vfile, gettext("x %s, %"
3368 FMT_off_t " bytes, "), namep, bytes);
3369 if (NotTape)
3370 (void) fprintf(vfile, "%" FMT_blkcnt_t
3371 "K\n", K(blocks));
3372 else
3373 (void) fprintf(vfile, gettext("%"
3374 FMT_blkcnt_t " tape blocks\n"),
3375 blocks);
3377 goto filedone;
3378 } else if (dblock.dbuf.typeflag == '4' && Uid) {
3379 (void) fprintf(stderr,
3380 gettext("Can't create special %s\n"), namep);
3381 continue;
3383 if (dblock.dbuf.typeflag == '2') { /* symlink */
3384 if ((Tflag) && (lk_rpath_flag == 1))
3385 linkp = lk_real_path;
3386 else
3387 linkp = templink;
3388 if (Aflag && *linkp == '/')
3389 linkp++;
3390 if (rmdir(namep) < 0) {
3391 if (errno == ENOTDIR)
3392 (void) unlink(namep);
3394 if (symlink(linkp, namep) < 0) {
3395 vperror(0, gettext("%s: symbolic link failed"),
3396 namep);
3397 continue;
3399 if (vflag)
3400 (void) fprintf(vfile, gettext(
3401 "x %s symbolic link to %s\n"),
3402 namep, linkp);
3404 symflag = AT_SYMLINK_NOFOLLOW;
3405 goto filedone;
3407 if (dblock.dbuf.typeflag == '1') {
3408 linkp = templink;
3409 if (Aflag && *linkp == '/')
3410 linkp++;
3411 if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
3412 if (errno == ENOTDIR)
3413 (void) unlinkat(dirfd, comp, 0);
3415 #if defined(O_XATTR)
3416 if (xattrp && xattr_linkp) {
3417 if (fchdir(dirfd) < 0) {
3418 vperror(0, gettext(
3419 "Cannot fchdir to attribute "
3420 "directory %s"),
3421 (attrinfo->attr_parent == NULL) ?
3422 dirp : attrinfo->attr_parent);
3423 exit(1);
3426 error = link(xattr_linkaname, xattrapath);
3427 } else {
3428 error = link(linkp, namep);
3430 #else
3431 error = link(linkp, namep);
3432 #endif
3434 if (error < 0) {
3435 (void) fprintf(stderr, gettext(
3436 "tar: %s%s%s: cannot link\n"),
3437 namep, (xattr_linkp != NULL) ?
3438 gettext(" attribute ") : "",
3439 (xattr_linkp != NULL) ?
3440 xattrapath : "");
3441 continue;
3443 if (vflag)
3444 (void) fprintf(vfile, gettext(
3445 "x %s%s%s linked to %s%s%s\n"), namep,
3446 (xattr_linkp != NULL) ?
3447 gettext(" attribute ") : "",
3448 (xattr_linkp != NULL) ?
3449 xattr_linkaname : "",
3450 linkp,
3451 (xattr_linkp != NULL) ?
3452 gettext(" attribute ") : "",
3453 (xattr_linkp != NULL) ? xattrapath : "");
3454 xcnt++; /* increment # files extracted */
3455 #if defined(O_XATTR)
3456 if (xattrp != NULL) {
3457 free(xattrhead);
3458 xattrp = NULL;
3459 xattr_linkp = NULL;
3460 xattrhead = NULL;
3462 #endif
3463 continue;
3466 /* REGULAR FILES */
3468 if (convtoreg(stbuf.st_size)) {
3469 convflag = 1;
3470 if (errflag) {
3471 (void) fprintf(stderr, gettext(
3472 "tar: %s: typeflag '%c' not recognized\n"),
3473 namep, dblock.dbuf.typeflag);
3474 done(1);
3475 } else {
3476 (void) fprintf(stderr, gettext(
3477 "tar: %s: typeflag '%c' not recognized, "
3478 "converting to regular file\n"), namep,
3479 dblock.dbuf.typeflag);
3480 Errflg = 1;
3483 if (dblock.dbuf.typeflag == '0' ||
3484 dblock.dbuf.typeflag == NULL || convflag) {
3485 delete_target(dirfd, comp, namep);
3486 linkp = templink;
3487 if (*linkp != NULL) {
3488 if (Aflag && *linkp == '/')
3489 linkp++;
3490 if (link(linkp, comp) < 0) {
3491 (void) fprintf(stderr, gettext(
3492 "tar: %s: cannot link\n"), namep);
3493 continue;
3495 if (vflag)
3496 (void) fprintf(vfile, gettext(
3497 "x %s linked to %s\n"), comp,
3498 linkp);
3499 xcnt++; /* increment # files extracted */
3500 #if defined(O_XATTR)
3501 if (xattrp != NULL) {
3502 free(xattrhead);
3503 xattrp = NULL;
3504 xattr_linkp = NULL;
3505 xattrhead = NULL;
3507 #endif
3508 continue;
3510 newfile = ((fstatat(dirfd, comp,
3511 &xtractbuf, 0) == -1) ? TRUE : FALSE);
3512 ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
3513 stbuf.st_mode & MODEMASK);
3514 saveerrno = errno;
3516 #if defined(O_XATTR)
3517 if (xattrp != NULL) {
3518 if (ofile < 0) {
3519 ofile = retry_open_attr(dirfd, cwd,
3520 dirp, attrinfo->attr_parent, comp,
3521 O_RDWR|O_CREAT|O_TRUNC,
3522 stbuf.st_mode & MODEMASK);
3525 #endif
3526 if (ofile < 0) {
3527 errno = saveerrno;
3528 (void) fprintf(stderr, gettext(
3529 "tar: %s%s%s%s - cannot create\n"),
3530 (xattrp == NULL) ? "" : (rw_sysattr ?
3531 gettext("system attribure ") :
3532 gettext("attribute ")),
3533 (xattrp == NULL) ? "" : xattrapath,
3534 (xattrp == NULL) ? "" : gettext(" of "),
3535 (xattrp == NULL) ? comp : namep);
3536 if (errflag)
3537 done(1);
3538 else
3539 Errflg = 1;
3540 #if defined(O_XATTR)
3541 if (xattrp != NULL) {
3542 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
3543 free(xattrhead);
3544 xattrp = NULL;
3545 xattr_linkp = NULL;
3546 xattrhead = NULL;
3548 #endif
3549 passtape();
3550 continue;
3553 if (Tflag && (check_ext_attr(namep) == 0)) {
3554 if (errflag)
3555 done(1);
3556 else
3557 Errflg = 1;
3558 passtape();
3559 continue;
3562 if (extno != 0) { /* file is in pieces */
3563 if (extotal < 1 || extotal > MAXEXT)
3564 (void) fprintf(stderr, gettext(
3565 "tar: ignoring bad extent info for "
3566 "%s%s%s%s\n"),
3567 (xattrp == NULL) ? "" : (rw_sysattr ?
3568 gettext("system attribute ") :
3569 gettext("attribute ")),
3570 (xattrp == NULL) ? "" : xattrapath,
3571 (xattrp == NULL) ? "" : gettext(" of "),
3572 (xattrp == NULL) ? comp : namep);
3573 else {
3574 /* extract it */
3575 (void) xsfile(rw_sysattr, ofile);
3578 extno = 0; /* let everyone know file is not split */
3579 bytes = stbuf.st_size;
3580 blocks = TBLOCKS(bytes);
3581 if (vflag) {
3582 (void) fprintf(vfile,
3583 "x %s%s%s, %" FMT_off_t " bytes, ",
3584 (xattrp == NULL) ? "" : dirp,
3585 (xattrp == NULL) ? "" : (rw_sysattr ?
3586 gettext(" system attribute ") :
3587 gettext(" attribute ")),
3588 (xattrp == NULL) ? namep : xattrapath, bytes);
3589 if (NotTape)
3590 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
3591 K(blocks));
3592 else
3593 (void) fprintf(vfile, gettext("%"
3594 FMT_blkcnt_t " tape blocks\n"), blocks);
3597 if (xblocks(rw_sysattr, bytes, ofile) != 0) {
3598 #if defined(O_XATTR)
3599 if (xattrp != NULL) {
3600 free(xattrhead);
3601 xattrp = NULL;
3602 xattr_linkp = NULL;
3603 xattrhead = NULL;
3605 #endif
3606 continue;
3608 filedone:
3609 if (mflag == 0 && !symflag) {
3610 if (dir)
3611 doDirTimes(namep, stbuf.st_mtim);
3613 else
3614 #if defined(O_XATTR)
3615 if (xattrp != NULL) {
3617 * Set the time on the attribute unless
3618 * the attribute is a system attribute
3619 * (can't successfully do this) or the
3620 * hidden attribute directory, "." (the
3621 * time on the hidden attribute
3622 * directory will be updated when
3623 * attributes are restored, otherwise
3624 * it's transient).
3626 if (!rw_sysattr && (Hiddendir == 0)) {
3627 setPathTimes(dirfd, comp,
3628 stbuf.st_mtim);
3630 } else
3631 setPathTimes(dirfd, comp,
3632 stbuf.st_mtim);
3633 #else
3634 setPathTimes(dirfd, comp, stbuf.st_mtim);
3635 #endif
3638 /* moved this code from above */
3639 if (pflag && !symflag && Hiddendir == 0) {
3640 if (xattrp != NULL)
3641 (void) fchmod(ofile, stbuf.st_mode & MODEMASK);
3642 else
3643 (void) chmod(namep, stbuf.st_mode & MODEMASK);
3648 * Because ancillary file preceeds the normal file,
3649 * acl info may have been retrieved (in aclp).
3650 * All file types are directed here (go filedone).
3651 * Always restore ACLs if there are ACLs.
3653 if (aclp != NULL) {
3654 int ret;
3656 #if defined(O_XATTR)
3657 if (xattrp != NULL) {
3658 if (Hiddendir)
3659 ret = facl_set(dirfd, aclp);
3660 else
3661 ret = facl_set(ofile, aclp);
3662 } else {
3663 ret = acl_set(namep, aclp);
3665 #else
3666 ret = acl_set(namep, aclp);
3667 #endif
3668 if (ret < 0) {
3669 if (pflag) {
3670 (void) fprintf(stderr, gettext(
3671 "%s%s%s%s: failed to set acl "
3672 "entries\n"), namep,
3673 (xattrp == NULL) ? "" :
3674 (rw_sysattr ? gettext(
3675 " system attribute ") :
3676 gettext(" attribute ")),
3677 (xattrp == NULL) ? "" :
3678 xattrapath);
3680 /* else: silent and continue */
3682 acl_free(aclp);
3683 aclp = NULL;
3686 if (!oflag)
3687 resugname(dirfd, comp, symflag); /* set file ownership */
3689 if (pflag && newfile == TRUE && !dir &&
3690 (dblock.dbuf.typeflag == '0' ||
3691 dblock.dbuf.typeflag == NULL ||
3692 convflag || dblock.dbuf.typeflag == '1')) {
3693 if (fstat(ofile, &xtractbuf) == -1)
3694 (void) fprintf(stderr, gettext(
3695 "tar: cannot stat extracted file "
3696 "%s%s%s%s\n"),
3697 (xattrp == NULL) ? "" : (rw_sysattr ?
3698 gettext("system attribute ") :
3699 gettext("attribute ")),
3700 (xattrp == NULL) ? "" : xattrapath,
3701 (xattrp == NULL) ? "" :
3702 gettext(" of "), namep);
3704 else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
3705 != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
3706 (void) fprintf(stderr, gettext(
3707 "tar: warning - file permissions have "
3708 "changed for %s%s%s%s (are 0%o, should be "
3709 "0%o)\n"),
3710 (xattrp == NULL) ? "" : (rw_sysattr ?
3711 gettext("system attribute ") :
3712 gettext("attribute ")),
3713 (xattrp == NULL) ? "" : xattrapath,
3714 (xattrp == NULL) ? "" :
3715 gettext(" of "), namep,
3716 xtractbuf.st_mode, stbuf.st_mode);
3720 #if defined(O_XATTR)
3721 if (xattrp != NULL) {
3722 free(xattrhead);
3723 xattrp = NULL;
3724 xattr_linkp = NULL;
3725 xattrhead = NULL;
3727 #endif
3729 if (ofile != -1) {
3730 (void) close(dirfd);
3731 dirfd = -1;
3732 if (close(ofile) != 0)
3733 vperror(2, gettext("close error"));
3734 ofile = -1;
3736 xcnt++; /* increment # files extracted */
3740 * Process ancillary file.
3744 if (dblock.dbuf.typeflag == 'A') { /* acl info */
3745 char buf[TBLOCK];
3746 char *secp;
3747 char *tp;
3748 int attrsize;
3749 int cnt;
3751 /* reset Trusted Extensions flags */
3752 dir_flag = 0;
3753 mld_flag = 0;
3754 lk_rpath_flag = 0;
3755 rpath_flag = 0;
3757 if (pflag) {
3758 bytes = stbuf.st_size;
3759 if ((secp = malloc((int)bytes)) == NULL) {
3760 (void) fprintf(stderr, gettext(
3761 "Insufficient memory for acl\n"));
3762 passtape();
3763 continue;
3765 tp = secp;
3766 blocks = TBLOCKS(bytes);
3769 * Display a line for each ancillary file.
3771 if (vflag && Tflag)
3772 (void) fprintf(vfile, "x %s(A), %"
3773 FMT_blkcnt_t " bytes, %"
3774 FMT_blkcnt_t " tape blocks\n",
3775 namep, bytes, blocks);
3777 while (blocks-- > 0) {
3778 readtape(buf);
3779 if (bytes <= TBLOCK) {
3780 (void) memcpy(tp, buf,
3781 (size_t)bytes);
3782 break;
3783 } else {
3784 (void) memcpy(tp, buf,
3785 TBLOCK);
3786 tp += TBLOCK;
3788 bytes -= TBLOCK;
3790 bytes = stbuf.st_size;
3791 /* got all attributes in secp */
3792 tp = secp;
3793 do {
3794 attr = (struct sec_attr *)tp;
3795 switch (attr->attr_type) {
3796 case UFSD_ACL:
3797 case ACE_ACL:
3798 (void) sscanf(attr->attr_len,
3799 "%7o",
3800 (uint_t *)
3801 &cnt);
3802 /* header is 8 */
3803 attrsize = 8 + (int)strlen(
3804 &attr->attr_info[0]) + 1;
3805 error =
3806 acl_fromtext(
3807 &attr->attr_info[0], &aclp);
3809 if (error != 0) {
3810 (void) fprintf(stderr,
3811 gettext(
3812 "aclfromtext "
3813 "failed: %s\n"),
3814 acl_strerror(
3815 error));
3816 bytes -= attrsize;
3817 break;
3819 if (acl_cnt(aclp) != cnt) {
3820 (void) fprintf(stderr,
3821 gettext(
3822 "aclcnt error\n"));
3823 bytes -= attrsize;
3824 break;
3826 bytes -= attrsize;
3827 break;
3829 /* Trusted Extensions */
3831 case DIR_TYPE:
3832 case LBL_TYPE:
3833 case APRIV_TYPE:
3834 case FPRIV_TYPE:
3835 case COMP_TYPE:
3836 case LK_COMP_TYPE:
3837 case ATTR_FLAG_TYPE:
3838 attrsize =
3839 sizeof (struct sec_attr) +
3840 strlen(&attr->attr_info[0]);
3841 bytes -= attrsize;
3842 if (Tflag)
3843 extract_attr(&namep,
3844 attr);
3845 break;
3847 default:
3848 (void) fprintf(stderr, gettext(
3849 "unrecognized attr"
3850 " type\n"));
3851 bytes = (off_t)0;
3852 break;
3855 /* next attributes */
3856 tp += attrsize;
3857 } while (bytes != 0);
3858 free(secp);
3859 } else {
3860 passtape();
3862 } /* acl */
3864 } /* for */
3867 * Ensure that all the directories still on the directory stack
3868 * get their modification times set correctly by flushing the
3869 * stack.
3872 doDirTimes(NULL, time_zero);
3874 #if defined(O_XATTR)
3875 if (xattrp != NULL) {
3876 free(xattrhead);
3877 xattrp = NULL;
3878 xattr_linkp = NULL;
3879 xattrhead = NULL;
3881 #endif
3884 * Check if the number of files extracted is different from the
3885 * number of files listed on the command line
3887 if (fcnt > xcnt) {
3888 (void) fprintf(stderr,
3889 gettext("tar: %d file(s) not extracted\n"),
3890 fcnt-xcnt);
3891 Errflg = 1;
3896 * xblocks extract file/extent from tape to output file
3898 * xblocks(issysattr, bytes, ofile);
3900 * issysattr flag set if the files being extracted
3901 * is an extended system attribute file.
3902 * unsigned long long bytes size of extent or file to be extracted
3903 * ofile output file
3905 * called by doxtract() and xsfile()
3908 static int
3909 xblocks(int issysattr, off_t bytes, int ofile)
3911 char *buf;
3912 char tempname[NAMSIZ+1];
3913 size_t maxwrite;
3914 size_t bytesread;
3915 size_t piosize; /* preferred I/O size */
3916 struct stat tsbuf;
3918 /* Don't need to do anything if this is a zero size file */
3919 if (bytes <= 0) {
3920 return (0);
3924 * To figure out the size of the buffer used to accumulate data
3925 * from readtape() and to write to the file, we need to determine
3926 * the largest chunk of data to be written to the file at one time.
3927 * This is determined based on the smallest of the following two
3928 * things:
3929 * 1) The size of the archived file.
3930 * 2) The preferred I/O size of the file.
3932 if (issysattr || (bytes <= TBLOCK)) {
3934 * Writes to system attribute files must be
3935 * performed in one operation.
3937 maxwrite = bytes;
3938 } else {
3940 * fstat() the file to get the preferred I/O size.
3941 * If it fails, then resort back to just writing
3942 * one block at a time.
3944 if (fstat(ofile, &tsbuf) == 0) {
3945 piosize = tsbuf.st_blksize;
3946 } else {
3947 piosize = TBLOCK;
3949 maxwrite = min(bytes, piosize);
3953 * The buffer used to accumulate the data for the write operation
3954 * needs to be the maximum number of bytes to be written rounded up
3955 * to the nearest TBLOCK since readtape reads one block at a time.
3957 if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
3958 fatal(gettext("cannot allocate buffer"));
3961 while (bytes > 0) {
3964 * readtape() obtains one block (TBLOCK) of data at a time.
3965 * Accumulate as many blocks of data in buf as we can write
3966 * in one operation.
3968 for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
3969 readtape(buf + bytesread);
3972 if (write(ofile, buf, maxwrite) < 0) {
3973 int saveerrno = errno;
3975 if (xhdr_flgs & _X_PATH)
3976 (void) strlcpy(tempname, Xtarhdr.x_path,
3977 sizeof (tempname));
3978 else
3979 (void) sprintf(tempname, "%.*s", NAMSIZ,
3980 dblock.dbuf.name);
3982 * If the extended system attribute being extracted
3983 * contains attributes that the user needs privileges
3984 * for, then just display a warning message, skip
3985 * the extraction of this file, and return.
3987 if ((saveerrno == EPERM) && issysattr) {
3988 (void) fprintf(stderr, gettext(
3989 "tar: unable to extract system attribute "
3990 "%s: insufficient privileges\n"), tempname);
3991 Errflg = 1;
3992 (void) free(buf);
3993 return (1);
3994 } else {
3995 (void) fprintf(stderr, gettext(
3996 "tar: %s: HELP - extract write error\n"),
3997 tempname);
3998 done(2);
4001 bytes -= maxwrite;
4004 * If we've reached this point and there is still data
4005 * to be written, maxwrite had to have been determined
4006 * by the preferred I/O size. If the number of bytes
4007 * left to write is smaller than the preferred I/O size,
4008 * then we're about to do our final write to the file, so
4009 * just set maxwrite to the number of bytes left to write.
4011 if ((bytes > 0) && (bytes < maxwrite)) {
4012 maxwrite = bytes;
4015 free(buf);
4017 return (0);
4021 * xsfile extract split file
4023 * xsfile(ofd); ofd = output file descriptor
4025 * file extracted and put in ofd via xblocks()
4027 * NOTE: only called by doxtract() to extract one large file
4030 static union hblock savedblock; /* to ensure same file across volumes */
4032 static int
4033 xsfile(int issysattr, int ofd)
4035 int i, c;
4036 int sysattrerr = 0;
4037 char name[PATH_MAX+1]; /* holds name for diagnostics */
4038 int extents, totalext;
4039 off_t bytes, totalbytes;
4041 if (xhdr_flgs & _X_PATH)
4042 (void) strcpy(name, Xtarhdr.x_path);
4043 else
4044 (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
4046 totalbytes = (off_t)0; /* in case we read in half the file */
4047 totalext = 0; /* these keep count */
4049 (void) fprintf(stderr, gettext(
4050 "tar: %s split across %d volumes\n"), name, extotal);
4052 /* make sure we do extractions in order */
4053 if (extno != 1) { /* starting in middle of file? */
4054 (void) printf(gettext(
4055 "tar: first extent read is not #1\n"
4056 "OK to read file beginning with extent #%d (%s/%s) ? "),
4057 extno, yesstr, nostr);
4058 if (yes() == 0) {
4059 canit:
4060 passtape();
4061 if (close(ofd) != 0)
4062 vperror(2, gettext("close error"));
4063 if (sysattrerr) {
4064 return (1);
4065 } else {
4066 return (0);
4070 extents = extotal;
4071 i = extno;
4072 /*CONSTCOND*/
4073 while (1) {
4074 if (xhdr_flgs & _X_SIZE) {
4075 bytes = extsize;
4076 } else {
4077 bytes = stbuf.st_size;
4080 if (vflag)
4081 (void) fprintf(vfile, "+++ x %s [extent #%d], %"
4082 FMT_off_t " bytes, %ldK\n", name, extno, bytes,
4083 (long)K(TBLOCKS(bytes)));
4084 if (xblocks(issysattr, bytes, ofd) != 0) {
4085 sysattrerr = 1;
4086 goto canit;
4089 totalbytes += bytes;
4090 totalext++;
4091 if (++i > extents)
4092 break;
4094 /* get next volume and verify it's the right one */
4095 copy(&savedblock, &dblock);
4096 tryagain:
4097 newvol();
4098 xhdr_flgs = 0;
4099 getdir();
4100 if (Xhdrflag > 0)
4101 (void) get_xdata(); /* Get x-header & regular hdr */
4102 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
4103 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
4104 xhdr_flgs |= _X_XHDR;
4106 if (endtape()) { /* seemingly empty volume */
4107 (void) fprintf(stderr, gettext(
4108 "tar: first record is null\n"));
4109 asknicely:
4110 (void) fprintf(stderr, gettext(
4111 "tar: need volume with extent #%d of %s\n"),
4112 i, name);
4113 goto tryagain;
4115 if (notsame()) {
4116 (void) fprintf(stderr, gettext(
4117 "tar: first file on that volume is not "
4118 "the same file\n"));
4119 goto asknicely;
4121 if (i != extno) {
4122 (void) fprintf(stderr, gettext(
4123 "tar: extent #%d received out of order\ntar: "
4124 "should be #%d\n"), extno, i);
4125 (void) fprintf(stderr, gettext(
4126 "Ignore error, Abort this file, or "
4127 "load New volume (i/a/n) ? "));
4128 c = response();
4129 if (c == 'a')
4130 goto canit;
4131 if (c != 'i') /* default to new volume */
4132 goto asknicely;
4133 i = extno; /* okay, start from there */
4136 if (vflag)
4137 (void) fprintf(vfile, gettext(
4138 "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
4139 name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
4141 return (0);
4146 * notsame() check if extract file extent is invalid
4148 * returns true if anything differs between savedblock and dblock
4149 * except extno (extent number), checksum, or size (extent size).
4150 * Determines if this header belongs to the same file as the one we're
4151 * extracting.
4153 * NOTE: though rather bulky, it is only called once per file
4154 * extension, and it can withstand changes in the definition
4155 * of the header structure.
4157 * WARNING: this routine is local to xsfile() above
4160 static int
4161 notsame(void)
4163 return (
4164 (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
4165 (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
4166 (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
4167 (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
4168 (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
4169 (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
4170 (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
4171 (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
4172 (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
4175 static void
4176 #ifdef _iBCS2
4177 dotable(char *argv[], int tbl_cnt)
4178 #else
4179 dotable(char *argv[])
4180 #endif
4183 int tcnt; /* count # files tabled */
4184 int fcnt; /* count # files in argv list */
4185 char *namep, *dirp, *comp;
4186 int want;
4187 char aclchar = ' '; /* either blank or '+' */
4188 char templink[PATH_MAX+1];
4189 attr_data_t *attrinfo = NULL;
4191 dumping = 0;
4193 /* if not on magtape, maximize seek speed */
4194 if (NotTape && !bflag) {
4195 #if SYS_BLOCK > TBLOCK
4196 nblock = SYS_BLOCK / TBLOCK;
4197 #else
4198 nblock = 1;
4199 #endif
4202 * Count the number of files that are to be tabled
4204 fcnt = tcnt = 0;
4206 #ifdef _iBCS2
4207 initarg(argv, Filefile);
4208 while (nextarg() != NULL)
4209 ++fcnt;
4210 fcnt += tbl_cnt;
4211 #endif /* _iBCS2 */
4213 for (;;) {
4215 /* namep is set by wantit to point to the full name */
4216 if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
4217 continue;
4218 if (want == -1)
4219 break;
4220 if (dblock.dbuf.typeflag != 'A')
4221 ++tcnt;
4224 * ACL support:
4225 * aclchar is introduced to indicate if there are
4226 * acl entries. longt() now takes one extra argument.
4228 if (vflag) {
4229 if (dblock.dbuf.typeflag == 'A') {
4230 aclchar = '+';
4231 passtape();
4232 continue;
4234 longt(&stbuf, aclchar);
4235 aclchar = ' ';
4239 #if defined(O_XATTR)
4240 if (xattrp != NULL) {
4241 int issysattr;
4242 char *bn = basename(attrinfo->attr_path);
4245 * We could use sysattr_type() to test whether or not
4246 * the attribute we are processing is really an
4247 * extended system attribute, which as of this writing
4248 * just does a strcmp(), however, sysattr_type() may
4249 * be changed to issue a pathconf() call instead, which
4250 * would require being changed into the parent attribute
4251 * directory. So instead, just do simple string
4252 * comparisons to see if we are processing an extended
4253 * system attribute.
4255 issysattr = is_sysattr(bn);
4257 (void) printf(gettext("%s %sattribute %s"),
4258 xattrp->h_names,
4259 issysattr ? gettext("system ") : "",
4260 attrinfo->attr_path);
4261 } else {
4262 (void) printf("%s", namep);
4264 #else
4265 (void) printf("%s", namep);
4266 #endif
4268 if (extno != 0) {
4269 if (vflag) {
4270 /* keep the '\n' for backwards compatibility */
4271 (void) fprintf(vfile, gettext(
4272 "\n [extent #%d of %d]"), extno, extotal);
4273 } else {
4274 (void) fprintf(vfile, gettext(
4275 " [extent #%d of %d]"), extno, extotal);
4278 if (xhdr_flgs & _X_LINKPATH) {
4279 (void) strcpy(templink, Xtarhdr.x_linkpath);
4280 } else {
4281 #if defined(O_XATTR)
4282 if (xattrp != NULL) {
4283 (void) sprintf(templink,
4284 "file %.*s", NAMSIZ, xattrp->h_names);
4285 } else {
4286 (void) sprintf(templink, "%.*s", NAMSIZ,
4287 dblock.dbuf.linkname);
4289 #else
4290 (void) sprintf(templink, "%.*s", NAMSIZ,
4291 dblock.dbuf.linkname);
4292 #endif
4293 templink[NAMSIZ] = '\0';
4295 if (dblock.dbuf.typeflag == '1') {
4297 * TRANSLATION_NOTE
4298 * Subject is omitted here.
4299 * Translate this as if
4300 * <subject> linked to %s
4302 #if defined(O_XATTR)
4303 if (xattrp != NULL) {
4304 (void) printf(
4305 gettext(" linked to attribute %s"),
4306 xattr_linkp->h_names +
4307 strlen(xattr_linkp->h_names) + 1);
4308 } else {
4309 (void) printf(
4310 gettext(" linked to %s"), templink);
4312 #else
4313 (void) printf(
4314 gettext(" linked to %s"), templink);
4316 #endif
4318 if (dblock.dbuf.typeflag == '2')
4319 (void) printf(gettext(
4321 * TRANSLATION_NOTE
4322 * Subject is omitted here.
4323 * Translate this as if
4324 * <subject> symbolic link to %s
4326 " symbolic link to %s"), templink);
4327 (void) printf("\n");
4328 #if defined(O_XATTR)
4329 if (xattrp != NULL) {
4330 free(xattrhead);
4331 xattrp = NULL;
4332 xattrhead = NULL;
4334 #endif
4335 passtape();
4338 * Check if the number of files tabled is different from the
4339 * number of files listed on the command line
4341 if (fcnt > tcnt) {
4342 (void) fprintf(stderr, gettext(
4343 "tar: %d file(s) not found\n"), fcnt-tcnt);
4344 Errflg = 1;
4348 static void
4349 putempty(blkcnt_t n)
4351 char buf[TBLOCK];
4352 char *cp;
4354 for (cp = buf; cp < &buf[TBLOCK]; )
4355 *cp++ = '\0';
4356 while (n-- > 0)
4357 (void) writetbuf(buf, 1);
4360 static ushort_t Ftype = S_IFMT;
4362 static void
4363 verbose(struct stat *st, char aclchar)
4365 int i, j, temp;
4366 mode_t mode;
4367 char modestr[12];
4369 for (i = 0; i < 11; i++)
4370 modestr[i] = '-';
4371 modestr[i] = '\0';
4373 /* a '+' sign is printed if there is ACL */
4374 modestr[i-1] = aclchar;
4376 mode = st->st_mode;
4377 for (i = 0; i < 3; i++) {
4378 temp = (mode >> (6 - (i * 3)));
4379 j = (i * 3) + 1;
4380 if (S_IROTH & temp)
4381 modestr[j] = 'r';
4382 if (S_IWOTH & temp)
4383 modestr[j + 1] = 'w';
4384 if (S_IXOTH & temp)
4385 modestr[j + 2] = 'x';
4387 temp = st->st_mode & Ftype;
4388 switch (temp) {
4389 case (S_IFIFO):
4390 modestr[0] = 'p';
4391 break;
4392 case (S_IFCHR):
4393 modestr[0] = 'c';
4394 break;
4395 case (S_IFDIR):
4396 modestr[0] = 'd';
4397 break;
4398 case (S_IFBLK):
4399 modestr[0] = 'b';
4400 break;
4401 case (S_IFREG): /* was initialized to '-' */
4402 break;
4403 case (S_IFLNK):
4404 modestr[0] = 'l';
4405 break;
4406 default:
4407 /* This field may be zero in old archives. */
4408 if (is_posix && dblock.dbuf.typeflag != '1') {
4410 * For POSIX compliant archives, the mode field
4411 * consists of 12 bits, ie: the file type bits
4412 * are not stored in dblock.dbuf.mode.
4413 * For files other than hard links, getdir() sets
4414 * the file type bits in the st_mode field of the
4415 * stat structure based upon dblock.dbuf.typeflag.
4417 (void) fprintf(stderr, gettext(
4418 "tar: impossible file type"));
4422 if ((S_ISUID & Gen.g_mode) == S_ISUID)
4423 modestr[3] = 's';
4424 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
4425 modestr[9] = 't';
4426 if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
4427 modestr[6] = 's';
4428 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
4429 modestr[6] = 'l';
4430 (void) fprintf(vfile, "%s", modestr);
4433 static void
4434 longt(struct stat *st, char aclchar)
4436 char fileDate[30];
4437 struct tm *tm;
4439 verbose(st, aclchar);
4440 (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
4442 if (dblock.dbuf.typeflag == '2') {
4443 if (xhdr_flgs & _X_LINKPATH)
4444 st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
4445 else
4446 st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
4447 '\0', NAMSIZ) ?
4448 (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
4450 (void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
4452 tm = localtime(&(st->st_mtime));
4453 (void) strftime(fileDate, sizeof (fileDate),
4454 dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
4455 (void) fprintf(vfile, " %s ", fileDate);
4460 * checkdir - Attempt to ensure that the path represented in name
4461 * exists, and return 1 if this is true and name itself is a
4462 * directory.
4463 * Return 0 if this path cannot be created or if name is not
4464 * a directory.
4467 static int
4468 checkdir(char *name)
4470 char lastChar; /* the last character in name */
4471 char *cp; /* scratch pointer into name */
4472 char *firstSlash = NULL; /* first slash in name */
4473 char *lastSlash = NULL; /* last slash in name */
4474 int nameLen; /* length of name */
4475 int trailingSlash; /* true if name ends in slash */
4476 int leadingSlash; /* true if name begins with slash */
4477 int markedDir; /* true if name denotes a directory */
4478 int success; /* status of makeDir call */
4482 * Scan through the name, and locate first and last slashes.
4485 for (cp = name; *cp; cp++) {
4486 if (*cp == '/') {
4487 if (! firstSlash) {
4488 firstSlash = cp;
4490 lastSlash = cp;
4495 * Determine what you can from the proceeds of the scan.
4498 lastChar = *(cp - 1);
4499 nameLen = (int)(cp - name);
4500 trailingSlash = (lastChar == '/');
4501 leadingSlash = (*name == '/');
4502 markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash);
4504 if (! lastSlash && ! markedDir) {
4506 * The named file does not have any subdrectory
4507 * structure; just bail out.
4510 return (0);
4514 * Make sure that name doesn`t end with slash for the loop.
4515 * This ensures that the makeDir attempt after the loop is
4516 * meaningful.
4519 if (trailingSlash) {
4520 name[nameLen-1] = '\0';
4524 * Make the path one component at a time.
4527 for (cp = strchr(leadingSlash ? name+1 : name, '/');
4529 cp = strchr(cp+1, '/')) {
4530 *cp = '\0';
4531 success = makeDir(name);
4532 *cp = '/';
4534 if (!success) {
4535 name[nameLen-1] = lastChar;
4536 return (0);
4541 * This makes the last component of the name, if it is a
4542 * directory.
4545 if (markedDir) {
4546 if (! makeDir(name)) {
4547 name[nameLen-1] = lastChar;
4548 return (0);
4552 name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
4553 return (markedDir);
4557 * resugname - Restore the user name and group name. Search the NIS
4558 * before using the uid and gid.
4559 * (It is presumed that an archive entry cannot be
4560 * simultaneously a symlink and some other type.)
4563 static void
4564 resugname(int dirfd, /* dir fd file resides in */
4565 char *name, /* name of the file to be modified */
4566 int symflag) /* true if file is a symbolic link */
4568 uid_t duid;
4569 gid_t dgid;
4570 struct stat *sp = &stbuf;
4571 char *u_g_name;
4573 if (checkflag == 1) { /* Extended tar format and euid == 0 */
4576 * Try and extract the intended uid and gid from the name
4577 * service before believing the uid and gid in the header.
4579 * In the case where we archived a setuid or setgid file
4580 * owned by someone with a large uid, then it will
4581 * have made it into the archive with a uid of nobody. If
4582 * the corresponding username doesn't appear to exist, then we
4583 * want to make sure it *doesn't* end up as setuid nobody!
4585 * Our caller will print an error message about the fact
4586 * that the restore didn't work out quite right ..
4588 if (xhdr_flgs & _X_UNAME)
4589 u_g_name = Xtarhdr.x_uname;
4590 else
4591 u_g_name = dblock.dbuf.uname;
4592 if ((duid = getuidbyname(u_g_name)) == -1) {
4593 if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
4594 (sp->st_mode & S_ISUID) == S_ISUID)
4595 (void) chmod(name,
4596 MODEMASK & sp->st_mode & ~S_ISUID);
4597 duid = sp->st_uid;
4600 /* (Ditto for gids) */
4602 if (xhdr_flgs & _X_GNAME)
4603 u_g_name = Xtarhdr.x_gname;
4604 else
4605 u_g_name = dblock.dbuf.gname;
4606 if ((dgid = getgidbyname(u_g_name)) == -1) {
4607 if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
4608 (sp->st_mode & S_ISGID) == S_ISGID)
4609 (void) chmod(name,
4610 MODEMASK & sp->st_mode & ~S_ISGID);
4611 dgid = sp->st_gid;
4613 } else if (checkflag == 2) { /* tar format and euid == 0 */
4614 duid = sp->st_uid;
4615 dgid = sp->st_gid;
4617 if ((checkflag == 1) || (checkflag == 2))
4618 (void) fchownat(dirfd, name, duid, dgid, symflag);
4621 /*ARGSUSED*/
4622 static void
4623 onintr(int sig)
4625 (void) signal(SIGINT, SIG_IGN);
4626 term++;
4629 /*ARGSUSED*/
4630 static void
4631 onquit(int sig)
4633 (void) signal(SIGQUIT, SIG_IGN);
4634 term++;
4637 /*ARGSUSED*/
4638 static void
4639 onhup(int sig)
4641 (void) signal(SIGHUP, SIG_IGN);
4642 term++;
4645 static void
4646 tomodes(struct stat *sp)
4648 uid_t uid;
4649 gid_t gid;
4651 bzero(dblock.dummy, TBLOCK);
4654 * If the uid or gid is too large, we can't put it into
4655 * the archive. We could fail to put anything in the
4656 * archive at all .. but most of the time the name service
4657 * will save the day when we do a lookup at restore time.
4659 * Instead we choose a "safe" uid and gid, and fix up whether
4660 * or not the setuid and setgid bits are left set to extraction
4661 * time.
4663 if (Eflag) {
4664 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
4665 xhdr_flgs |= _X_UID;
4666 Xtarhdr.x_uid = uid;
4668 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
4669 xhdr_flgs |= _X_GID;
4670 Xtarhdr.x_gid = gid;
4672 if (sp->st_size > TAR_OFFSET_MAX) {
4673 xhdr_flgs |= _X_SIZE;
4674 Xtarhdr.x_filesz = sp->st_size;
4675 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4676 (off_t)0);
4677 } else
4678 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4679 sp->st_size);
4680 } else {
4681 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4682 sp->st_size);
4684 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
4685 uid = UID_NOBODY;
4686 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
4687 gid = GID_NOBODY;
4688 (void) sprintf(dblock.dbuf.gid, "%07lo", gid);
4689 (void) sprintf(dblock.dbuf.uid, "%07lo", uid);
4690 (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
4691 (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
4694 static int
4695 #ifdef EUC
4697 * Warning: the result of this function depends whether 'char' is a
4698 * signed or unsigned data type. This a source of potential
4699 * non-portability among heterogeneous systems. It is retained here
4700 * for backward compatibility.
4702 checksum_signed(union hblock *dblockp)
4703 #else
4704 checksum(union hblock *dblockp)
4705 #endif /* EUC */
4707 int i;
4708 char *cp;
4710 for (cp = dblockp->dbuf.chksum;
4711 cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
4712 *cp = ' ';
4713 i = 0;
4714 for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
4715 i += *cp;
4716 return (i);
4719 #ifdef EUC
4721 * Generate unsigned checksum, regardless of what C compiler is
4722 * used. Survives in the face of arbitrary 8-bit clean filenames,
4723 * e.g., internationalized filenames.
4725 static int
4726 checksum(union hblock *dblockp)
4728 unsigned i;
4729 unsigned char *cp;
4731 for (cp = (unsigned char *) dblockp->dbuf.chksum;
4732 cp < (unsigned char *)
4733 &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
4734 *cp = ' ';
4735 i = 0;
4736 for (cp = (unsigned char *) dblockp->dummy;
4737 cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
4738 i += *cp;
4740 return (i);
4742 #endif /* EUC */
4745 * If the w flag is set, output the action to be taken and the name of the
4746 * file. Perform the action if the user response is affirmative.
4749 static int
4750 checkw(char c, char *name)
4752 if (wflag) {
4753 (void) fprintf(vfile, "%c ", c);
4754 if (vflag)
4755 longt(&stbuf, ' '); /* do we have acl info here */
4756 (void) fprintf(vfile, "%s: ", name);
4757 if (yes() == 1) {
4758 return (1);
4760 return (0);
4762 return (1);
4766 * When the F flag is set, exclude RCS and SCCS directories. If F is set
4767 * twice, also exclude .o files, and files names errs, core, and a.out.
4770 static int
4771 checkf(char *name, int mode, int howmuch)
4773 int l;
4775 if ((mode & S_IFMT) == S_IFDIR) {
4776 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4777 return (0);
4778 return (1);
4780 if ((l = (int)strlen(name)) < 3)
4781 return (1);
4782 if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o')
4783 return (0);
4784 if (howmuch > 1) {
4785 if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
4786 strcmp(name, "a.out") == 0)
4787 return (0);
4790 /* SHOULD CHECK IF IT IS EXECUTABLE */
4791 return (1);
4794 static int
4795 response(void)
4797 int c;
4799 c = getchar();
4800 if (c != '\n')
4801 while (getchar() != '\n')
4803 else c = 'n';
4804 return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
4807 /* Has file been modified since being put into archive? If so, return > 0. */
4809 static off_t lookup(char *);
4811 static int
4812 checkupdate(char *arg)
4814 char name[PATH_MAX+1];
4815 time_t mtime;
4816 long nsecs;
4817 off_t seekp;
4819 rewind(tfile);
4820 if ((seekp = lookup(arg)) < 0)
4821 return (1);
4822 (void) fseek(tfile, seekp, 0);
4823 (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
4826 * Unless nanoseconds were stored in the file, only use seconds for
4827 * comparison of time. Nanoseconds are stored when -E is specified.
4829 if (Eflag == 0)
4830 return (stbuf.st_mtime > mtime);
4832 if ((stbuf.st_mtime < mtime) ||
4833 ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
4834 return (0);
4835 return (1);
4840 * newvol get new floppy (or tape) volume
4842 * newvol(); resets tapepos and first to TRUE, prompts for
4843 * for new volume, and waits.
4844 * if dumping, end-of-file is written onto the tape.
4847 static void
4848 newvol(void)
4850 int c;
4852 if (dumping) {
4853 #ifdef DEBUG
4854 DEBUG("newvol called with 'dumping' set\n", 0, 0);
4855 #endif
4856 putempty((blkcnt_t)2); /* 2 EOT marks */
4857 closevol();
4858 flushtape();
4859 sync();
4860 tapepos = 0;
4861 } else
4862 first = TRUE;
4863 if (close(mt) != 0)
4864 vperror(2, gettext("close error"));
4865 mt = 0;
4866 (void) fprintf(stderr, gettext(
4867 "tar: \007please insert new volume, then press RETURN."));
4868 (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */
4869 while ((c = getchar()) != '\n' && ! term)
4870 if (c == EOF)
4871 done(Errflg);
4872 if (term)
4873 done(Errflg);
4875 errno = 0;
4877 if (strcmp(usefile, "-") == 0) {
4878 mt = dup(1);
4879 } else {
4880 mt = open(usefile, dumping ? update : 0);
4883 if (mt < 0) {
4884 (void) fprintf(stderr, gettext(
4885 "tar: cannot reopen %s (%s)\n"),
4886 dumping ? gettext("output") : gettext("input"), usefile);
4888 (void) fprintf(stderr, "update=%d, usefile=%s, mt=%d, [%s]\n",
4889 update, usefile, mt, strerror(errno));
4891 done(2);
4896 * Write a trailer portion to close out the current output volume.
4899 static void
4900 closevol(void)
4902 if (mulvol) {
4904 * blocklim does not count the 2 EOT marks;
4905 * tapepos does count the 2 EOT marks;
4906 * therefore we need the +2 below.
4908 putempty(blocklim + (blkcnt_t)2 - tapepos);
4912 static void
4913 done(int n)
4915 (void) unlink(tname);
4916 if (compress_opt != NULL)
4917 (void) free(compress_opt);
4918 if (mt > 0) {
4919 if ((close(mt) != 0) || (fclose(stdout) != 0)) {
4920 perror(gettext("tar: close error"));
4921 exit(2);
4924 exit(n);
4928 * Determine if s1 is a prefix portion of s2 (or the same as s2).
4931 static int
4932 is_prefix(char *s1, char *s2)
4934 while (*s1)
4935 if (*s1++ != *s2++)
4936 return (0);
4937 if (*s2)
4938 return (*s2 == '/');
4939 return (1);
4943 * lookup and bsrch look through tfile entries to find a match for a name.
4944 * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
4945 * a pair of newline chars, so the buffer it uses must be long enough for
4946 * two lines: name and modification time as well as period, newline and space.
4948 * A kludge was added to bsrch to take care of matching on the first entry
4949 * in the file--there is no leading newline. So, if we are reading from the
4950 * start of the file, read into byte two and set the first byte to a newline.
4951 * Otherwise, the first entry cannot be matched.
4955 #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4956 static off_t
4957 lookup(char *s)
4959 int i;
4960 off_t a;
4962 for (i = 0; s[i]; i++)
4963 if (s[i] == ' ')
4964 break;
4965 a = bsrch(s, i, low, high);
4966 return (a);
4969 static off_t
4970 bsrch(char *s, int n, off_t l, off_t h)
4972 int i, j;
4973 char b[N];
4974 off_t m, m1;
4977 loop:
4978 if (l >= h)
4979 return ((off_t)-1);
4980 m = l + (h-l)/2 - N/2;
4981 if (m < l)
4982 m = l;
4983 (void) fseek(tfile, m, 0);
4984 if (m == 0) {
4985 (void) fread(b+1, 1, N-1, tfile);
4986 b[0] = '\n';
4987 m--;
4988 } else
4989 (void) fread(b, 1, N, tfile);
4990 for (i = 0; i < N; i++) {
4991 if (b[i] == '\n')
4992 break;
4993 m++;
4995 if (m >= h)
4996 return ((off_t)-1);
4997 m1 = m;
4998 j = i;
4999 for (i++; i < N; i++) {
5000 m1++;
5001 if (b[i] == '\n')
5002 break;
5004 i = cmp(b+j, s, n);
5005 if (i < 0) {
5006 h = m;
5007 goto loop;
5009 if (i > 0) {
5010 l = m1;
5011 goto loop;
5013 if (m < 0)
5014 m = 0;
5015 return (m);
5018 static int
5019 cmp(char *b, char *s, int n)
5021 int i;
5023 assert(b[0] == '\n');
5025 for (i = 0; i < n; i++) {
5026 if (b[i+1] > s[i])
5027 return (-1);
5028 if (b[i+1] < s[i])
5029 return (1);
5031 return (b[i+1] == ' '? 0 : -1);
5036 * seekdisk seek to next file on archive
5038 * called by passtape() only
5040 * WARNING: expects "nblock" to be set, that is, readtape() to have
5041 * already been called. Since passtape() is only called
5042 * after a file header block has been read (why else would
5043 * we skip to next file?), this is currently safe.
5045 * changed to guarantee SYS_BLOCK boundary
5048 static void
5049 seekdisk(blkcnt_t blocks)
5051 off_t seekval;
5052 #if SYS_BLOCK > TBLOCK
5053 /* handle non-multiple of SYS_BLOCK */
5054 blkcnt_t nxb; /* # extra blocks */
5055 #endif
5057 tapepos += blocks;
5058 #ifdef DEBUG
5059 DEBUG("seekdisk(%" FMT_blkcnt_t ") called\n", blocks, 0);
5060 #endif
5061 if (recno + blocks <= nblock) {
5062 recno += blocks;
5063 return;
5065 if (recno > nblock)
5066 recno = nblock;
5067 seekval = (off_t)blocks - (nblock - recno);
5068 recno = nblock; /* so readtape() reads next time through */
5069 #if SYS_BLOCK > TBLOCK
5070 nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
5071 #ifdef DEBUG
5072 DEBUG("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
5073 nxb, seekval);
5074 #endif
5075 if (nxb && nxb > seekval) /* don't seek--we'll read */
5076 goto noseek;
5077 seekval -= nxb; /* don't seek quite so far */
5078 #endif
5079 if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
5080 (void) fprintf(stderr, gettext(
5081 "tar: device seek error\n"));
5082 done(3);
5084 #if SYS_BLOCK > TBLOCK
5085 /* read those extra blocks */
5086 noseek:
5087 if (nxb) {
5088 #ifdef DEBUG
5089 DEBUG("reading extra blocks\n", 0, 0);
5090 #endif
5091 if (read(mt, tbuf, TBLOCK*nblock) < 0) {
5092 (void) fprintf(stderr, gettext(
5093 "tar: read error while skipping file\n"));
5094 done(8);
5096 recno = nxb; /* so we don't read in next readtape() */
5098 #endif
5101 static void
5102 readtape(char *buffer)
5104 int i, j;
5106 ++tapepos;
5107 if (recno >= nblock || first) {
5108 if (first) {
5110 * set the number of blocks to read initially, based on
5111 * the defined defaults for the device, or on the
5112 * explicit block factor given.
5114 if (bflag || defaults_used)
5115 j = nblock;
5116 else
5117 j = NBLOCK;
5118 } else
5119 j = nblock;
5121 if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
5122 (void) fprintf(stderr, gettext(
5123 "tar: tape read error\n"));
5124 done(3);
5126 * i == 0 and !rflag means that EOF is reached and we are
5127 * trying to update or replace an empty tar file, so exit
5128 * with an error.
5130 * If i == 0 and !first and NotTape, it means the pointer
5131 * has gone past the EOF. It could happen if two processes
5132 * try to update the same tar file simultaneously. So exit
5133 * with an error.
5136 } else if (i == 0) {
5137 if (first && !rflag) {
5138 (void) fprintf(stderr, gettext(
5139 "tar: blocksize = %d\n"), i);
5140 done(Errflg);
5141 } else if (!first && (!rflag || NotTape)) {
5142 mterr("read", 0, 2);
5144 } else if ((!first || Bflag) && i != TBLOCK*j) {
5146 * Short read - try to get the remaining bytes.
5149 int remaining = (TBLOCK * j) - i;
5150 char *b = (char *)tbuf + i;
5151 int r;
5153 do {
5154 if ((r = read(mt, b, remaining)) < 0) {
5155 (void) fprintf(stderr,
5156 gettext("tar: tape read error\n"));
5157 done(3);
5159 b += r;
5160 remaining -= r;
5161 i += r;
5162 } while (remaining > 0 && r != 0);
5164 if (first) {
5165 if ((i % TBLOCK) != 0) {
5166 (void) fprintf(stderr, gettext(
5167 "tar: tape blocksize error\n"));
5168 done(3);
5170 i /= TBLOCK;
5171 if (vflag && i != nblock && i != 1) {
5172 if (!NotTape)
5173 (void) fprintf(stderr, gettext(
5174 "tar: blocksize = %d\n"), i);
5178 * If we are reading a tape, then a short read is
5179 * understood to signify that the amount read is
5180 * the tape's actual blocking factor. We adapt
5181 * nblock accordingly. There is no reason to do
5182 * this when the device is not blocked.
5185 if (!NotTape)
5186 nblock = i;
5188 recno = 0;
5191 first = FALSE;
5192 copy(buffer, &tbuf[recno++]);
5197 * replacement for writetape.
5200 static int
5201 writetbuf(char *buffer, int n)
5203 int i;
5205 tapepos += n; /* output block count */
5207 if (recno >= nblock) {
5208 i = write(mt, (char *)tbuf, TBLOCK*nblock);
5209 if (i != TBLOCK*nblock)
5210 mterr("write", i, 2);
5211 recno = 0;
5215 * Special case: We have an empty tape buffer, and the
5216 * users data size is >= the tape block size: Avoid
5217 * the bcopy and dma direct to tape. BIG WIN. Add the
5218 * residual to the tape buffer.
5220 while (recno == 0 && n >= nblock) {
5221 i = (int)write(mt, buffer, TBLOCK*nblock);
5222 if (i != TBLOCK*nblock)
5223 mterr("write", i, 2);
5224 n -= nblock;
5225 buffer += (nblock * TBLOCK);
5228 while (n-- > 0) {
5229 (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
5230 buffer += TBLOCK;
5231 if (recno >= nblock) {
5232 i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
5233 if (i != TBLOCK*nblock)
5234 mterr("write", i, 2);
5235 recno = 0;
5239 /* Tell the user how much to write to get in sync */
5240 return (nblock - recno);
5244 * backtape - reposition tape after reading soft "EOF" record
5246 * Backtape tries to reposition the tape back over the EOF
5247 * record. This is for the 'u' and 'r' function letters so that the
5248 * tape can be extended. This code is not well designed, but
5249 * I'm confident that the only callers who care about the
5250 * backspace-over-EOF feature are those involved in 'u' and 'r'.
5252 * The proper way to backup the tape is through the use of mtio.
5253 * Earlier spins used lseek combined with reads in a confusing
5254 * maneuver that only worked on 4.x, but shouldn't have, even
5255 * there. Lseeks are explicitly not supported for tape devices.
5258 static void
5259 backtape(void)
5261 struct mtop mtcmd;
5262 #ifdef DEBUG
5263 DEBUG("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
5264 nblock);
5265 #endif
5267 * Backup to the position in the archive where the record
5268 * currently sitting in the tbuf buffer is situated.
5271 if (NotTape) {
5273 * For non-tape devices, this means lseeking to the
5274 * correct position. The absolute location tapepos-recno
5275 * should be the beginning of the current record.
5278 if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
5279 (off_t)-1) {
5280 (void) fprintf(stderr,
5281 gettext("tar: lseek to end of archive failed\n"));
5282 done(4);
5284 } else {
5286 * For tape devices, we backup over the most recently
5287 * read record.
5290 mtcmd.mt_op = MTBSR;
5291 mtcmd.mt_count = 1;
5293 if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
5294 (void) fprintf(stderr,
5295 gettext("tar: backspace over record failed\n"));
5296 done(4);
5301 * Decrement the tape and tbuf buffer indices to prepare for the
5302 * coming write to overwrite the soft EOF record.
5305 recno--;
5306 tapepos--;
5311 * flushtape write buffered block(s) onto tape
5313 * recno points to next free block in tbuf. If nonzero, a write is done.
5314 * Care is taken to write in multiples of SYS_BLOCK when device is
5315 * non-magtape in case raw i/o is used.
5317 * NOTE: this is called by writetape() to do the actual writing
5320 static void
5321 flushtape(void)
5323 #ifdef DEBUG
5324 DEBUG("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno, 0);
5325 #endif
5326 if (recno > 0) { /* anything buffered? */
5327 if (NotTape) {
5328 #if SYS_BLOCK > TBLOCK
5329 int i;
5332 * an odd-block write can only happen when
5333 * we are at the end of a volume that is not a tape.
5334 * Here we round recno up to an even SYS_BLOCK
5335 * boundary.
5337 if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
5338 #ifdef DEBUG
5339 DEBUG("flushtape() %d rounding blocks\n", i, 0);
5340 #endif
5341 recno += i; /* round up to even SYS_BLOCK */
5343 #endif
5344 if (recno > nblock)
5345 recno = nblock;
5347 #ifdef DEBUG
5348 DEBUG("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
5349 " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
5350 (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
5351 #endif
5352 if (write(mt, tbuf,
5353 (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
5354 (void) fprintf(stderr, gettext(
5355 "tar: tape write error\n"));
5356 done(2);
5358 recno = 0;
5362 static void
5363 copy(void *dst, void *src)
5365 (void) memcpy(dst, src, TBLOCK);
5368 #ifdef _iBCS2
5370 * initarg -- initialize things for nextarg.
5372 * argv filename list, a la argv.
5373 * filefile name of file containing filenames. Unless doing
5374 * a create, seeks must be allowable (e.g. no named pipes).
5376 * - if filefile is non-NULL, it will be used first, and argv will
5377 * be used when the data in filefile are exhausted.
5378 * - otherwise argv will be used.
5380 static char **Cmdargv = NULL;
5381 static FILE *FILEFile = NULL;
5382 static long seekFile = -1;
5383 static char *ptrtoFile, *begofFile, *endofFile;
5385 static void
5386 initarg(char *argv[], char *filefile)
5388 struct stat statbuf;
5389 char *p;
5390 int nbytes;
5392 Cmdargv = argv;
5393 if (filefile == NULL)
5394 return; /* no -F file */
5395 if (FILEFile != NULL) {
5397 * need to REinitialize
5399 if (seekFile != -1)
5400 (void) fseek(FILEFile, seekFile, 0);
5401 ptrtoFile = begofFile;
5402 return;
5405 * first time initialization
5407 if ((FILEFile = fopen(filefile, "r")) == NULL)
5408 fatal(gettext("cannot open (%s)"), filefile);
5409 (void) fstat(fileno(FILEFile), &statbuf);
5410 if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
5411 (void) fprintf(stderr, gettext(
5412 "tar: %s is not a regular file\n"), filefile);
5413 (void) fclose(FILEFile);
5414 done(1);
5416 ptrtoFile = begofFile = endofFile;
5417 seekFile = 0;
5418 if (!xflag)
5419 return; /* the file will be read only once anyway */
5420 nbytes = statbuf.st_size;
5421 while ((begofFile = calloc(nbytes, sizeof (char))) == NULL)
5422 nbytes -= 20;
5423 if (nbytes < 50) {
5424 free(begofFile);
5425 begofFile = endofFile;
5426 return; /* no room so just do plain reads */
5428 if (fread(begofFile, 1, nbytes, FILEFile) != nbytes)
5429 fatal(gettext("could not read %s"), filefile);
5430 ptrtoFile = begofFile;
5431 endofFile = begofFile + nbytes;
5432 for (p = begofFile; p < endofFile; ++p)
5433 if (*p == '\n')
5434 *p = '\0';
5435 if (nbytes != statbuf.st_size)
5436 seekFile = nbytes + 1;
5437 else
5438 (void) fclose(FILEFile);
5442 * nextarg -- get next argument of arglist.
5444 * The argument is taken from wherever is appropriate.
5446 * If the 'F file' function modifier has been specified, the argument
5447 * will be taken from the file, unless EOF has been reached.
5448 * Otherwise the argument will be taken from argv.
5450 * WARNING:
5451 * Return value may point to static data, whose contents are over-
5452 * written on each call.
5454 static char *
5455 nextarg(void)
5457 static char nameFile[PATH_MAX + 1];
5458 int n;
5459 char *p;
5461 if (FILEFile) {
5462 if (ptrtoFile < endofFile) {
5463 p = ptrtoFile;
5464 while (*ptrtoFile)
5465 ++ptrtoFile;
5466 ++ptrtoFile;
5467 return (p);
5469 if (fgets(nameFile, PATH_MAX + 1, FILEFile) != NULL) {
5470 n = strlen(nameFile);
5471 if (n > 0 && nameFile[n-1] == '\n')
5472 nameFile[n-1] = '\0';
5473 return (nameFile);
5476 return (*Cmdargv++);
5478 #endif /* _iBCS2 */
5481 * kcheck()
5482 * - checks the validity of size values for non-tape devices
5483 * - if size is zero, mulvol tar is disabled and size is
5484 * assumed to be infinite.
5485 * - returns volume size in TBLOCKS
5488 static blkcnt_t
5489 kcheck(char *kstr)
5491 blkcnt_t kval;
5493 kval = strtoll(kstr, NULL, 0);
5494 if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */
5495 mulvol = 0; /* definitely not mulvol, but we must */
5496 return (0); /* took out setting of NotTape */
5498 if (kval < (blkcnt_t)MINSIZE) {
5499 (void) fprintf(stderr, gettext(
5500 "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5501 ").\n"), (ulong_t)MINSIZE, kval);
5502 if (!kflag)
5503 (void) fprintf(stderr, gettext(
5504 "bad size entry for %s in %s.\n"),
5505 archive, DEF_FILE);
5506 done(1);
5508 mulvol++;
5509 NotTape++; /* implies non-tape */
5510 return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */
5515 * bcheck()
5516 * - checks the validity of blocking factors
5517 * - returns blocking factor
5520 static int
5521 bcheck(char *bstr)
5523 blkcnt_t bval;
5525 bval = strtoll(bstr, NULL, 0);
5526 if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
5527 (void) fprintf(stderr, gettext(
5528 "tar: invalid blocksize \"%s\".\n"), bstr);
5529 if (!bflag)
5530 (void) fprintf(stderr, gettext(
5531 "bad blocksize entry for '%s' in %s.\n"),
5532 archive, DEF_FILE);
5533 done(1);
5536 return ((int)bval);
5541 * defset()
5542 * - reads DEF_FILE for the set of default values specified.
5543 * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5544 * - 'usefile' points to static data, so will be overwritten
5545 * if this routine is called a second time.
5546 * - the pattern specified by 'arch' must be followed by four
5547 * blank-separated fields (1) device (2) blocking,
5548 * (3) size(K), and (4) tape
5549 * for example: archive0=/dev/fd 1 400 n
5552 static int
5553 defset(char *arch)
5555 char *bp;
5557 if (defopen(DEF_FILE) != 0)
5558 return (FALSE);
5559 if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
5560 (void) fprintf(stderr, gettext(
5561 "tar: error setting parameters for %s.\n"), DEF_FILE);
5562 return (FALSE); /* & following ones too */
5564 if ((bp = defread(arch)) == NULL) {
5565 (void) fprintf(stderr, gettext(
5566 "tar: missing or invalid '%s' entry in %s.\n"),
5567 arch, DEF_FILE);
5568 return (FALSE);
5570 if ((usefile = strtok(bp, " \t")) == NULL) {
5571 (void) fprintf(stderr, gettext(
5572 "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
5573 return (FALSE);
5575 if ((bp = strtok(NULL, " \t")) == NULL) {
5576 (void) fprintf(stderr, gettext(
5577 "tar: block component missing in '%s' entry in %s.\n"),
5578 arch, DEF_FILE);
5579 return (FALSE);
5581 nblock = bcheck(bp);
5582 if ((bp = strtok(NULL, " \t")) == NULL) {
5583 (void) fprintf(stderr, gettext(
5584 "tar: size component missing in '%s' entry in %s.\n"),
5585 arch, DEF_FILE);
5586 return (FALSE);
5588 blocklim = kcheck(bp);
5589 if ((bp = strtok(NULL, " \t")) != NULL)
5590 NotTape = (*bp == 'n' || *bp == 'N');
5591 else
5592 NotTape = (blocklim != 0);
5593 (void) defopen(NULL);
5594 #ifdef DEBUG
5595 DEBUG("defset: archive='%s'; usefile='%s'\n", arch, usefile);
5596 DEBUG("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
5597 nblock, blocklim);
5598 DEBUG("defset: not tape = %d\n", NotTape, 0);
5599 #endif
5600 return (TRUE);
5605 * Following code handles excluded and included files.
5606 * A hash table of file names to be {in,ex}cluded is built.
5607 * For excluded files, before writing or extracting a file
5608 * check to see if it is in the exclude_tbl.
5609 * For included files, the wantit() procedure will check to
5610 * see if the named file is in the include_tbl.
5613 static void
5614 build_table(file_list_t *table[], char *file)
5616 FILE *fp;
5617 char buf[PATH_MAX + 1];
5619 if ((fp = fopen(file, "r")) == (FILE *)NULL)
5620 vperror(1, gettext("could not open %s"), file);
5621 while (fgets(buf, sizeof (buf), fp) != NULL) {
5622 if (buf[strlen(buf) - 1] == '\n')
5623 buf[strlen(buf) - 1] = '\0';
5624 /* Only add to table if line has something in it */
5625 if (strspn(buf, " \t") != strlen(buf))
5626 add_file_to_table(table, buf);
5628 (void) fclose(fp);
5633 * Add a file name to the the specified table, if the file name has any
5634 * trailing '/'s then delete them before inserting into the table
5637 static void
5638 add_file_to_table(file_list_t *table[], char *str)
5640 char name[PATH_MAX + 1];
5641 unsigned int h;
5642 file_list_t *exp;
5644 (void) strcpy(name, str);
5645 while (name[strlen(name) - 1] == '/') {
5646 name[strlen(name) - 1] = NULL;
5649 h = hash(name);
5650 if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
5651 sizeof (char))) == NULL) {
5652 (void) fprintf(stderr, gettext(
5653 "tar: out of memory, exclude/include table(entry)\n"));
5654 exit(1);
5657 if ((exp->name = strdup(name)) == NULL) {
5658 (void) fprintf(stderr, gettext(
5659 "tar: out of memory, exclude/include table(file name)\n"));
5660 exit(1);
5663 exp->next = table[h];
5664 table[h] = exp;
5669 * See if a file name or any of the file's parent directories is in the
5670 * specified table, if the file name has any trailing '/'s then delete
5671 * them before searching the table
5674 static int
5675 is_in_table(file_list_t *table[], char *str)
5677 char name[PATH_MAX + 1];
5678 unsigned int h;
5679 file_list_t *exp;
5680 char *ptr;
5682 (void) strcpy(name, str);
5683 while (name[strlen(name) - 1] == '/') {
5684 name[strlen(name) - 1] = NULL;
5688 * check for the file name in the passed list
5690 h = hash(name);
5691 exp = table[h];
5692 while (exp != NULL) {
5693 if (strcmp(name, exp->name) == 0) {
5694 return (1);
5696 exp = exp->next;
5700 * check for any parent directories in the file list
5702 while ((ptr = strrchr(name, '/'))) {
5703 *ptr = NULL;
5704 h = hash(name);
5705 exp = table[h];
5706 while (exp != NULL) {
5707 if (strcmp(name, exp->name) == 0) {
5708 return (1);
5710 exp = exp->next;
5714 return (0);
5719 * Compute a hash from a string.
5722 static unsigned int
5723 hash(char *str)
5725 char *cp;
5726 unsigned int h;
5728 h = 0;
5729 for (cp = str; *cp; cp++) {
5730 h += *cp;
5732 return (h % TABLE_SIZE);
5735 static void *
5736 getmem(size_t size)
5738 void *p = calloc((unsigned)size, sizeof (char));
5740 if (p == NULL && freemem) {
5741 (void) fprintf(stderr, gettext(
5742 "tar: out of memory, link and directory modtime "
5743 "info lost\n"));
5744 freemem = 0;
5745 if (errflag)
5746 done(1);
5747 else
5748 Errflg = 1;
5750 return (p);
5754 * vperror() --variable argument perror.
5755 * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
5756 * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5757 * with the value of whatever "errno" is set to. If exit_status is not
5758 * zero, then tar exits with that error status. If errflag and exit_status
5759 * are both zero, the routine returns to where it was called and sets Errflg
5760 * to errno.
5763 static void
5764 vperror(int exit_status, char *fmt, ...)
5766 va_list ap;
5768 va_start(ap, fmt);
5769 (void) fputs("tar: ", stderr);
5770 (void) vfprintf(stderr, fmt, ap);
5771 (void) fprintf(stderr, ": %s\n", strerror(errno));
5772 va_end(ap);
5773 if (exit_status)
5774 done(exit_status);
5775 else
5776 if (errflag)
5777 done(errno);
5778 else
5779 Errflg = errno;
5783 static void
5784 fatal(char *format, ...)
5786 va_list ap;
5788 va_start(ap, format);
5789 (void) fprintf(stderr, "tar: ");
5790 (void) vfprintf(stderr, format, ap);
5791 (void) fprintf(stderr, "\n");
5792 va_end(ap);
5793 done(1);
5798 * Check to make sure that argument is a char * ptr.
5799 * Actually, we just check to see that it is non-null.
5800 * If it is null, print out the message and call usage(), bailing out.
5803 static void
5804 assert_string(char *s, char *msg)
5806 if (s == NULL) {
5807 (void) fprintf(stderr, msg);
5808 usage();
5813 static void
5814 mterr(char *operation, int i, int exitcode)
5816 (void) fprintf(stderr, gettext(
5817 "tar: %s error: "), operation);
5818 if (i < 0)
5819 perror("");
5820 else
5821 (void) fprintf(stderr, gettext("unexpected EOF\n"));
5822 done(exitcode);
5825 static int
5826 wantit(char *argv[], char **namep, char **dirp, char **component,
5827 attr_data_t **attrinfo)
5829 char **cp;
5830 int gotit; /* true if we've found a match */
5831 int ret;
5833 top:
5834 if (xhdr_flgs & _X_XHDR) {
5835 xhdr_flgs = 0;
5837 getdir();
5838 if (Xhdrflag > 0) {
5839 ret = get_xdata();
5840 if (ret != 0) { /* Xhdr items and regular header */
5841 setbytes_to_skip(&stbuf, ret);
5842 passtape();
5843 return (0); /* Error--don't want to extract */
5848 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5849 * of ancillary file is either over or ancillary file
5850 * processing is not required, load info from Xtarhdr and set
5851 * _X_XHDR bit in xhdr_flgs.
5853 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
5854 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
5855 xhdr_flgs |= _X_XHDR;
5858 #if defined(O_XATTR)
5859 if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
5861 * Always needs to read the extended header. If atflag, saflag,
5862 * or tflag isn't set, then we'll have the correct info for
5863 * passtape() later.
5865 (void) read_xattr_hdr(attrinfo);
5866 goto top;
5869 * Now that we've read the extended header, call passtape()
5870 * if we don't want to restore attributes or system attributes.
5871 * Don't restore the attribute if we are extracting
5872 * a file from an archive (as opposed to doing a table of
5873 * contents) and any of the following are true:
5874 * 1. neither -@ or -/ was specified.
5875 * 2. -@ was specified, -/ wasn't specified, and we're
5876 * processing a hidden attribute directory of an attribute
5877 * or we're processing a read-write system attribute file.
5878 * 3. -@ wasn't specified, -/ was specified, and the file
5879 * we're processing is not a read-write system attribute file,
5880 * or we're processing the hidden attribute directory of an
5881 * attribute.
5883 * We always process the attributes if we're just generating
5884 * generating a table of contents, or if both -@ and -/ were
5885 * specified.
5887 if (xattrp != NULL) {
5888 attr_data_t *ainfo = *attrinfo;
5890 if (!tflag &&
5891 ((!atflag && !saflag) ||
5892 (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
5893 ainfo->attr_rw_sysattr)) ||
5894 (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
5895 !ainfo->attr_rw_sysattr)))) {
5896 passtape();
5897 return (0);
5900 #endif
5902 /* sets *namep to point at the proper name */
5903 if (check_prefix(namep, dirp, component) != 0) {
5904 passtape();
5905 return (0);
5908 if (endtape()) {
5909 if (Bflag) {
5911 * Logically at EOT - consume any extra blocks
5912 * so that write to our stdin won't fail and
5913 * emit an error message; otherwise something
5914 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5915 * will produce a bogus error message from "dd".
5918 while (read(mt, tbuf, TBLOCK*nblock) > 0) {
5919 /* empty body */
5922 return (-1);
5925 gotit = 0;
5927 if ((Iflag && is_in_table(include_tbl, *namep)) ||
5928 (! Iflag && *argv == NULL)) {
5929 gotit = 1;
5930 } else {
5931 for (cp = argv; *cp; cp++) {
5932 if (is_prefix(*cp, *namep)) {
5933 gotit = 1;
5934 break;
5939 if (! gotit) {
5940 passtape();
5941 return (0);
5944 if (Xflag && is_in_table(exclude_tbl, *namep)) {
5945 if (vflag) {
5946 (void) fprintf(stderr, gettext("%s excluded\n"),
5947 *namep);
5949 passtape();
5950 return (0);
5953 return (1);
5957 static void
5958 setbytes_to_skip(struct stat *st, int err)
5961 * In a scenario where a typeflag 'X' was followed by
5962 * a typeflag 'A' and typeflag 'O', then the number of
5963 * bytes to skip should be the size of ancillary file,
5964 * plus the dblock for regular file, and the size
5965 * from Xtarhdr. However, if the typeflag was just 'X'
5966 * followed by typeflag 'O', then the number of bytes
5967 * to skip should be the size from Xtarhdr.
5969 if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
5970 (xhdr_flgs & _X_SIZE)) {
5971 st->st_size += TBLOCK + Xtarhdr.x_filesz;
5972 xhdr_flgs |= _X_XHDR;
5973 } else if ((dblock.dbuf.typeflag != 'A') &&
5974 (xhdr_flgs & _X_SIZE)) {
5975 st->st_size += Xtarhdr.x_filesz;
5976 xhdr_flgs |= _X_XHDR;
5980 static int
5981 fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
5982 int rw_sysattr, attr_data_t **attrinfo)
5984 size_t pathlen;
5985 char *tpath;
5986 char *tparent;
5988 /* parent info */
5989 if (attrparent != NULL) {
5990 if ((tparent = strdup(attrparent)) == NULL) {
5991 vperror(0, gettext(
5992 "unable to allocate memory for attribute parent "
5993 "name for %sattribute %s/%s of %s"),
5994 rw_sysattr ? gettext("system ") : "",
5995 attrparent, attr, longname);
5996 return (1);
5998 } else {
5999 tparent = NULL;
6002 /* path info */
6003 pathlen = strlen(attr) + 1;
6004 if (attrparent != NULL) {
6005 pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
6007 if ((tpath = calloc(1, pathlen)) == NULL) {
6008 vperror(0, gettext(
6009 "unable to allocate memory for full "
6010 "attribute path name for %sattribute %s%s%s of %s"),
6011 rw_sysattr ? gettext("system ") : "",
6012 (attrparent == NULL) ? "" : attrparent,
6013 (attrparent == NULL) ? "" : "/",
6014 attr, longname);
6015 if (tparent != NULL) {
6016 free(tparent);
6018 return (1);
6020 (void) snprintf(tpath, pathlen, "%s%s%s",
6021 (attrparent == NULL) ? "" : attrparent,
6022 (attrparent == NULL) ? "" : "/",
6023 attr);
6025 /* fill in the attribute info */
6026 if (*attrinfo == NULL) {
6027 if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
6028 vperror(0, gettext(
6029 "unable to allocate memory for attribute "
6030 "information for %sattribute %s%s%s of %s"),
6031 rw_sysattr ? gettext("system ") : "",
6032 (attrparent == NULL) ? "" : attrparent,
6033 (attrparent == NULL) ? "" : gettext("/"),
6034 attr, longname);
6035 if (tparent != NULL) {
6036 free(tparent);
6038 free(tpath);
6039 return (1);
6041 } else {
6042 if ((*attrinfo)->attr_parent != NULL) {
6043 free((*attrinfo)->attr_parent);
6045 if ((*attrinfo)->attr_path != NULL) {
6046 free((*attrinfo)->attr_path);
6049 * The parent file descriptor is passed in, so don't
6050 * close it here as it should be closed by the function
6051 * that opened it.
6054 (*attrinfo)->attr_parent = tparent;
6055 (*attrinfo)->attr_path = tpath;
6056 (*attrinfo)->attr_rw_sysattr = rw_sysattr;
6057 (*attrinfo)->attr_parentfd = atparentfd;
6059 return (0);
6063 * Return through *namep a pointer to the proper fullname (i.e "<name> |
6064 * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6066 * Returns 0 if successful, otherwise returns 1.
6069 static int
6070 check_prefix(char **namep, char **dirp, char **compp)
6072 static char fullname[PATH_MAX + 1];
6073 static char dir[PATH_MAX + 1];
6074 static char component[PATH_MAX + 1];
6075 static char savename[PATH_MAX + 1];
6076 char *s;
6078 (void) memset(dir, 0, sizeof (dir));
6079 (void) memset(component, 0, sizeof (component));
6081 if (xhdr_flgs & _X_PATH) {
6082 (void) strcpy(fullname, Xtarhdr.x_path);
6083 } else {
6084 if (dblock.dbuf.prefix[0] != '\0')
6085 (void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
6086 dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
6087 else
6088 (void) sprintf(fullname, "%.*s", NAMSIZ,
6089 dblock.dbuf.name);
6093 * Set dir and component names
6096 get_parent(fullname, dir);
6098 #if defined(O_XATTR)
6099 if (xattrp == NULL) {
6100 #endif
6102 * Save of real name since were going to chop off the
6103 * trailing slashes.
6105 (void) strcpy(savename, fullname);
6107 * first strip of trailing slashes.
6109 chop_endslashes(savename);
6110 s = get_component(savename);
6111 (void) strcpy(component, s);
6113 #if defined(O_XATTR)
6114 } else {
6115 (void) strcpy(fullname, xattrp->h_names);
6116 (void) strcpy(dir, fullname);
6117 (void) strcpy(component, basename(xattrp->h_names +
6118 strlen(xattrp->h_names) + 1));
6120 #endif
6121 *namep = fullname;
6122 *dirp = dir;
6123 *compp = component;
6125 return (0);
6129 * Return true if the object indicated by the file descriptor and type
6130 * is a tape device, false otherwise
6133 static int
6134 istape(int fd, int type)
6136 int result = 0;
6138 if (S_ISCHR(type)) {
6139 struct mtget mtg;
6141 if (ioctl(fd, MTIOCGET, &mtg) != -1) {
6142 result = 1;
6146 return (result);
6149 #include <utmpx.h>
6151 struct utmpx utmpx;
6153 #define NMAX (sizeof (utmpx.ut_name))
6155 typedef struct cachenode { /* this struct must be zeroed before using */
6156 struct cachenode *next; /* next in hash chain */
6157 int val; /* the uid or gid of this entry */
6158 int namehash; /* name's hash signature */
6159 char name[NMAX+1]; /* the string that val maps to */
6160 } cachenode_t;
6162 #define HASHSIZE 256
6164 static cachenode_t *names[HASHSIZE];
6165 static cachenode_t *groups[HASHSIZE];
6166 static cachenode_t *uids[HASHSIZE];
6167 static cachenode_t *gids[HASHSIZE];
6169 static int
6170 hash_byname(char *name)
6172 int i, c, h = 0;
6174 for (i = 0; i < NMAX; i++) {
6175 c = name[i];
6176 if (c == '\0')
6177 break;
6178 h = (h << 4) + h + c;
6180 return (h);
6183 static cachenode_t *
6184 hash_lookup_byval(cachenode_t *table[], int val)
6186 int h = val;
6187 cachenode_t *c;
6189 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6190 if (c->val == val)
6191 return (c);
6193 return (NULL);
6196 static cachenode_t *
6197 hash_lookup_byname(cachenode_t *table[], char *name)
6199 int h = hash_byname(name);
6200 cachenode_t *c;
6202 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6203 if (c->namehash == h && strcmp(c->name, name) == 0)
6204 return (c);
6206 return (NULL);
6209 static cachenode_t *
6210 hash_insert(cachenode_t *table[], char *name, int value)
6212 cachenode_t *c;
6213 int signature;
6215 c = calloc(1, sizeof (cachenode_t));
6216 if (c == NULL) {
6217 perror("malloc");
6218 exit(1);
6220 if (name != NULL) {
6221 (void) strncpy(c->name, name, NMAX);
6222 c->namehash = hash_byname(name);
6224 c->val = value;
6225 if (table == uids || table == gids)
6226 signature = c->val;
6227 else
6228 signature = c->namehash;
6229 c->next = table[signature & (HASHSIZE - 1)];
6230 table[signature & (HASHSIZE - 1)] = c;
6231 return (c);
6234 static char *
6235 getname(uid_t uid)
6237 cachenode_t *c;
6239 if ((c = hash_lookup_byval(uids, uid)) == NULL) {
6240 struct passwd *pwent = getpwuid(uid);
6241 c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
6243 return (c->name);
6246 static char *
6247 getgroup(gid_t gid)
6249 cachenode_t *c;
6251 if ((c = hash_lookup_byval(gids, gid)) == NULL) {
6252 struct group *grent = getgrgid(gid);
6253 c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
6255 return (c->name);
6258 static uid_t
6259 getuidbyname(char *name)
6261 cachenode_t *c;
6263 if ((c = hash_lookup_byname(names, name)) == NULL) {
6264 struct passwd *pwent = getpwnam(name);
6265 c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
6267 return ((uid_t)c->val);
6270 static gid_t
6271 getgidbyname(char *group)
6273 cachenode_t *c;
6275 if ((c = hash_lookup_byname(groups, group)) == NULL) {
6276 struct group *grent = getgrnam(group);
6277 c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
6279 return ((gid_t)c->val);
6283 * Build the header.
6284 * Determine whether or not an extended header is also needed. If needed,
6285 * create and write the extended header and its data.
6286 * Writing of the extended header assumes that "tomodes" has been called and
6287 * the relevant information has been placed in the header block.
6290 static int
6291 build_dblock(
6292 const char *name,
6293 const char *linkname,
6294 const char typeflag,
6295 const int filetype,
6296 const struct stat *sp,
6297 const dev_t device,
6298 const char *prefix)
6300 int nblks;
6301 major_t dev;
6302 const char *filename;
6303 const char *lastslash;
6305 if (filetype == XATTR_FILE)
6306 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
6307 else
6308 dblock.dbuf.typeflag = typeflag;
6309 (void) memset(dblock.dbuf.name, '\0', NAMSIZ);
6310 (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
6311 (void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
6313 if (xhdr_flgs & _X_PATH)
6314 filename = Xtarhdr.x_path;
6315 else
6316 filename = name;
6318 if ((dev = major(device)) > OCTAL7CHAR) {
6319 if (Eflag) {
6320 xhdr_flgs |= _X_DEVMAJOR;
6321 Xtarhdr.x_devmajor = dev;
6322 } else {
6323 (void) fprintf(stderr, gettext(
6324 "Device major too large for %s. Use -E flag."),
6325 filename);
6326 if (errflag)
6327 done(1);
6328 else
6329 Errflg = 1;
6331 dev = 0;
6333 (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
6334 if ((dev = minor(device)) > OCTAL7CHAR) {
6335 if (Eflag) {
6336 xhdr_flgs |= _X_DEVMINOR;
6337 Xtarhdr.x_devminor = dev;
6338 } else {
6339 (void) fprintf(stderr, gettext(
6340 "Device minor too large for %s. Use -E flag."),
6341 filename);
6342 if (errflag)
6343 done(1);
6344 else
6345 Errflg = 1;
6347 dev = 0;
6349 (void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
6351 (void) strncpy(dblock.dbuf.name, name, NAMSIZ);
6352 (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
6353 (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
6354 (void) sprintf(dblock.dbuf.version, "00");
6355 (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
6356 (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
6357 (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
6358 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
6360 if (Eflag) {
6361 (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
6362 (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
6363 lastslash = strrchr(name, '/');
6364 if (lastslash == NULL)
6365 lastslash = name;
6366 else
6367 lastslash++;
6368 (void) strcpy(xhdr_buf.dbuf.name, lastslash);
6369 (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
6370 (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
6371 (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
6372 xhdr_count++;
6373 xrec_offset = 0;
6374 gen_date("mtime", sp->st_mtim);
6375 xhdr_buf.dbuf.typeflag = 'X';
6376 if (gen_utf8_names(filename) != 0)
6377 return (1);
6379 #ifdef XHDR_DEBUG
6380 Xtarhdr.x_uname = dblock.dbuf.uname;
6381 Xtarhdr.x_gname = dblock.dbuf.gname;
6382 xhdr_flgs |= (_X_UNAME | _X_GNAME);
6383 #endif
6384 if (xhdr_flgs) {
6385 if (xhdr_flgs & _X_DEVMAJOR)
6386 gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
6387 if (xhdr_flgs & _X_DEVMINOR)
6388 gen_num("SUN.devminor", Xtarhdr.x_devminor);
6389 if (xhdr_flgs & _X_GID)
6390 gen_num("gid", Xtarhdr.x_gid);
6391 if (xhdr_flgs & _X_UID)
6392 gen_num("uid", Xtarhdr.x_uid);
6393 if (xhdr_flgs & _X_SIZE)
6394 gen_num("size", Xtarhdr.x_filesz);
6395 if (xhdr_flgs & _X_PATH)
6396 gen_string("path", Xtarhdr.x_path);
6397 if (xhdr_flgs & _X_LINKPATH)
6398 gen_string("linkpath", Xtarhdr.x_linkpath);
6399 if (xhdr_flgs & _X_GNAME)
6400 gen_string("gname", Xtarhdr.x_gname);
6401 if (xhdr_flgs & _X_UNAME)
6402 gen_string("uname", Xtarhdr.x_uname);
6404 (void) sprintf(xhdr_buf.dbuf.size,
6405 "%011" FMT_off_t_o, xrec_offset);
6406 (void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
6407 checksum(&xhdr_buf));
6408 (void) writetbuf((char *)&xhdr_buf, 1);
6409 nblks = TBLOCKS(xrec_offset);
6410 (void) writetbuf(xrec_ptr, nblks);
6412 return (0);
6417 * makeDir - ensure that a directory with the pathname denoted by name
6418 * exists, and return 1 on success, and 0 on failure (e.g.,
6419 * read-only file system, exists but not-a-directory).
6422 static int
6423 makeDir(char *name)
6425 struct stat buf;
6427 if (access(name, 0) < 0) { /* name doesn't exist */
6428 if (mkdir(name, 0777) < 0) {
6429 vperror(0, "%s", name);
6430 return (0);
6432 } else { /* name exists */
6433 if (stat(name, &buf) < 0) {
6434 vperror(0, "%s", name);
6435 return (0);
6438 return ((buf.st_mode & S_IFMT) == S_IFDIR);
6441 return (1);
6446 * Save this directory and its mtime on the stack, popping and setting
6447 * the mtimes of any stacked dirs which aren't parents of this one.
6448 * A null name causes the entire stack to be unwound and set.
6450 * Since all the elements of the directory "stack" share a common
6451 * prefix, we can make do with one string. We keep only the current
6452 * directory path, with an associated array of mtime's. A negative
6453 * mtime means no mtime.
6455 * This stack algorithm is not guaranteed to work for tapes created
6456 * with the 'r' function letter, but the vast majority of tapes with
6457 * directories are not. This avoids saving every directory record on
6458 * the tape and setting all the times at the end.
6460 * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6461 * environment)
6464 static void
6465 doDirTimes(char *name, timestruc_t modTime)
6467 static char dirstack[PATH_MAX+2];
6468 /* Add spaces for the last slash and last NULL */
6469 static timestruc_t modtimes[PATH_MAX+1]; /* hash table */
6470 char *p = dirstack;
6471 char *q = name;
6472 char *savp;
6474 if (q) {
6476 * Find common prefix
6479 while (*p == *q && *p) {
6480 p++; q++;
6484 savp = p;
6485 while (*p) {
6487 * Not a child: unwind the stack, setting the times.
6488 * The order we do this doesn't matter, so we go "forward."
6491 if (*p == '/')
6492 if (modtimes[p - dirstack].tv_sec >= 0) {
6493 *p = '\0'; /* zap the slash */
6494 setPathTimes(AT_FDCWD, dirstack,
6495 modtimes[p - dirstack]);
6496 *p = '/';
6498 ++p;
6501 p = savp;
6504 * Push this one on the "stack"
6507 if (q) {
6510 * Since the name parameter points the dir pathname
6511 * which is limited only to contain PATH_MAX chars
6512 * at maximum, we can ignore the overflow case of p.
6515 while ((*p = *q++)) { /* append the rest of the new dir */
6516 modtimes[p - dirstack].tv_sec = -1;
6517 p++;
6521 * If the tar file had used 'P' or 'E' function modifier,
6522 * append the last slash.
6524 if (*(p - 1) != '/') {
6525 *p++ = '/';
6526 *p = '\0';
6528 /* overwrite the last one */
6529 modtimes[p - dirstack - 1] = modTime;
6535 * setPathTimes - set the modification time for given path. Return 1 if
6536 * successful and 0 if not successful.
6539 static void
6540 setPathTimes(int dirfd, char *path, timestruc_t modTime)
6543 struct timeval timebuf[2];
6546 * futimesat takes an array of two timeval structs.
6547 * The first entry contains access time.
6548 * The second entry contains modification time.
6549 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6550 * microseconds.
6552 timebuf[0].tv_sec = time((time_t *)0);
6553 timebuf[0].tv_usec = 0;
6554 timebuf[1].tv_sec = modTime.tv_sec;
6556 /* Extended header: use microseconds */
6557 timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
6559 if (futimesat(dirfd, path, timebuf) < 0)
6560 vperror(0, "can't set time on %s", path);
6565 * If hflag is set then delete the symbolic link's target.
6566 * If !hflag then delete the target.
6569 static void
6570 delete_target(int fd, char *comp, char *namep)
6572 struct stat xtractbuf;
6573 char buf[PATH_MAX + 1];
6574 int n;
6577 if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
6578 if (errno == ENOTDIR && !hflag) {
6579 (void) unlinkat(fd, comp, 0);
6580 } else if (errno == ENOTDIR && hflag) {
6581 if (!lstat(namep, &xtractbuf)) {
6582 if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
6583 (void) unlinkat(fd, comp, 0);
6584 } else if ((n = readlink(namep, buf,
6585 PATH_MAX)) != -1) {
6586 buf[n] = (char)NULL;
6587 (void) unlinkat(fd, buf,
6588 AT_REMOVEDIR);
6589 if (errno == ENOTDIR)
6590 (void) unlinkat(fd, buf, 0);
6591 } else {
6592 (void) unlinkat(fd, comp, 0);
6594 } else {
6595 (void) unlinkat(fd, comp, 0);
6603 * ACL changes:
6604 * putfile():
6605 * Get acl info after stat. Write out ancillary file
6606 * before the normal file, i.e. directory, regular, FIFO,
6607 * link, special. If acl count is less than 4, no need to
6608 * create ancillary file. (i.e. standard permission is in
6609 * use.
6610 * doxtract():
6611 * Process ancillary file. Read it in and set acl info.
6612 * watch out for 'o' function modifier.
6613 * 't' function letter to display table
6617 * New functions for ACLs and other security attributes
6621 * The function appends the new security attribute info to the end of
6622 * existing secinfo.
6625 append_secattr(
6626 char **secinfo, /* existing security info */
6627 int *secinfo_len, /* length of existing security info */
6628 int size, /* new attribute size: unit depends on type */
6629 char *attrtext, /* new attribute text */
6630 char attr_type) /* new attribute type */
6632 char *new_secinfo;
6633 int newattrsize;
6634 int oldsize;
6635 struct sec_attr *attr;
6637 /* no need to add */
6638 if (attr_type != DIR_TYPE) {
6639 if (attrtext == NULL)
6640 return (0);
6643 switch (attr_type) {
6644 case UFSD_ACL:
6645 case ACE_ACL:
6646 if (attrtext == NULL) {
6647 (void) fprintf(stderr, "acltotext failed\n");
6648 return (-1);
6650 /* header: type + size = 8 */
6651 newattrsize = 8 + (int)strlen(attrtext) + 1;
6652 attr = (struct sec_attr *)malloc(newattrsize);
6653 if (attr == NULL) {
6654 (void) fprintf(stderr, "can't allocate memory\n");
6655 return (-1);
6657 attr->attr_type = attr_type;
6658 (void) sprintf(attr->attr_len,
6659 "%06o", size); /* acl entry count */
6660 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6661 free(attrtext);
6662 break;
6664 /* Trusted Extensions */
6665 case DIR_TYPE:
6666 case LBL_TYPE:
6667 newattrsize = sizeof (struct sec_attr) + strlen(attrtext);
6668 attr = (struct sec_attr *)malloc(newattrsize);
6669 if (attr == NULL) {
6670 (void) fprintf(stderr,
6671 gettext("can't allocate memory\n"));
6672 return (-1);
6674 attr->attr_type = attr_type;
6675 (void) sprintf(attr->attr_len,
6676 "%06d", size); /* len of attr data */
6677 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6678 break;
6680 default:
6681 (void) fprintf(stderr, "unrecognized attribute type\n");
6682 return (-1);
6685 /* old security info + new attr header(8) + new attr */
6686 oldsize = *secinfo_len;
6687 *secinfo_len += newattrsize;
6688 new_secinfo = (char *)malloc(*secinfo_len);
6689 if (new_secinfo == NULL) {
6690 (void) fprintf(stderr, "can't allocate memory\n");
6691 *secinfo_len -= newattrsize;
6692 free(attr);
6693 return (-1);
6696 (void) memcpy(new_secinfo, *secinfo, oldsize);
6697 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6699 free(*secinfo);
6700 free(attr);
6701 *secinfo = new_secinfo;
6702 return (0);
6706 * write_ancillary(): write out an ancillary file.
6707 * The file has the same header as normal file except the type and size
6708 * fields. The type is 'A' and size is the sum of all attributes
6709 * in bytes.
6710 * The body contains a list of attribute type, size and info. Currently,
6711 * there is only ACL info. This file is put before the normal file.
6713 void
6714 write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
6716 long blocks;
6717 int savflag;
6718 int savsize;
6720 /* Just tranditional permissions or no security attribute info */
6721 if (len == 0 || secinfo == NULL)
6722 return;
6724 /* save flag and size */
6725 savflag = (dblockp->dbuf).typeflag;
6726 (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
6728 /* special flag for ancillary file */
6729 if (hdrtype == _XATTR_HDRTYPE)
6730 dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
6731 else
6732 dblockp->dbuf.typeflag = 'A';
6734 /* for pre-2.5 versions of tar, need to make sure */
6735 /* the ACL file is readable */
6736 (void) sprintf(dblock.dbuf.mode, "%07lo",
6737 (stbuf.st_mode & POSIXMODES) | 0000200);
6738 (void) sprintf(dblockp->dbuf.size, "%011o", len);
6739 (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
6741 /* write out the header */
6742 (void) writetbuf((char *)dblockp, 1);
6744 /* write out security info */
6745 blocks = TBLOCKS(len);
6746 (void) writetbuf((char *)secinfo, (int)blocks);
6748 /* restore mode, flag and size */
6749 (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
6750 dblockp->dbuf.typeflag = savflag;
6751 (void) sprintf(dblockp->dbuf.size, "%011o", savsize);
6755 * Read the data record for extended headers and then the regular header.
6756 * The data are read into the buffer and then null-terminated. Entries
6757 * for typeflag 'X' extended headers are of the format:
6758 * "%d %s=%s\n"
6760 * When an extended header record is found, the extended header must
6761 * be processed and its values used to override the values in the
6762 * normal header. The way this is done is to process the extended
6763 * header data record and set the data values, then call getdir
6764 * to process the regular header, then then to reconcile the two
6765 * sets of data.
6768 static int
6769 get_xdata(void)
6771 struct keylist_pair {
6772 int keynum;
6773 char *keylist;
6774 } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor",
6775 _X_DEVMINOR, "SUN.devminor",
6776 _X_GID, "gid",
6777 _X_GNAME, "gname",
6778 _X_LINKPATH, "linkpath",
6779 _X_PATH, "path",
6780 _X_SIZE, "size",
6781 _X_UID, "uid",
6782 _X_UNAME, "uname",
6783 _X_MTIME, "mtime",
6784 _X_LAST, "NULL" };
6785 char *lineloc;
6786 int length, i;
6787 char *keyword, *value;
6788 blkcnt_t nblocks;
6789 int bufneeded;
6790 int errors;
6792 (void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
6793 xhdr_count++;
6794 errors = 0;
6796 nblocks = TBLOCKS(stbuf.st_size);
6797 bufneeded = nblocks * TBLOCK;
6798 if (bufneeded >= xrec_size) {
6799 free(xrec_ptr);
6800 xrec_size = bufneeded + 1;
6801 if ((xrec_ptr = malloc(xrec_size)) == NULL)
6802 fatal(gettext("cannot allocate buffer"));
6805 lineloc = xrec_ptr;
6807 while (nblocks-- > 0) {
6808 readtape(lineloc);
6809 lineloc += TBLOCK;
6811 lineloc = xrec_ptr;
6812 xrec_ptr[stbuf.st_size] = '\0';
6813 while (lineloc < xrec_ptr + stbuf.st_size) {
6814 if (dblock.dbuf.typeflag == 'L') {
6815 length = xrec_size;
6816 keyword = "path";
6817 value = lineloc;
6818 } else {
6819 length = atoi(lineloc);
6820 *(lineloc + length - 1) = '\0';
6821 keyword = strchr(lineloc, ' ') + 1;
6822 value = strchr(keyword, '=') + 1;
6823 *(value - 1) = '\0';
6825 i = 0;
6826 lineloc += length;
6827 while (keylist_pair[i].keynum != (int)_X_LAST) {
6828 if (strcmp(keyword, keylist_pair[i].keylist) == 0)
6829 break;
6830 i++;
6832 errno = 0;
6833 switch (keylist_pair[i].keynum) {
6834 case _X_DEVMAJOR:
6835 Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
6836 if (errno) {
6837 (void) fprintf(stderr, gettext(
6838 "tar: Extended header major value error "
6839 "for file # %llu.\n"), xhdr_count);
6840 errors++;
6841 } else
6842 xhdr_flgs |= _X_DEVMAJOR;
6843 break;
6844 case _X_DEVMINOR:
6845 Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
6846 if (errno) {
6847 (void) fprintf(stderr, gettext(
6848 "tar: Extended header minor value error "
6849 "for file # %llu.\n"), xhdr_count);
6850 errors++;
6851 } else
6852 xhdr_flgs |= _X_DEVMINOR;
6853 break;
6854 case _X_GID:
6855 xhdr_flgs |= _X_GID;
6856 Xtarhdr.x_gid = strtol(value, NULL, 0);
6857 if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
6858 (void) fprintf(stderr, gettext(
6859 "tar: Extended header gid value error "
6860 "for file # %llu.\n"), xhdr_count);
6861 Xtarhdr.x_gid = GID_NOBODY;
6863 break;
6864 case _X_GNAME:
6865 if (utf8_local("gname", &Xtarhdr.x_gname,
6866 local_gname, value, _POSIX_NAME_MAX) == 0)
6867 xhdr_flgs |= _X_GNAME;
6868 break;
6869 case _X_LINKPATH:
6870 if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
6871 local_linkpath, value, PATH_MAX) == 0)
6872 xhdr_flgs |= _X_LINKPATH;
6873 else
6874 errors++;
6875 break;
6876 case _X_PATH:
6877 if (utf8_local("path", &Xtarhdr.x_path,
6878 local_path, value, PATH_MAX) == 0)
6879 xhdr_flgs |= _X_PATH;
6880 else
6881 errors++;
6882 break;
6883 case _X_SIZE:
6884 Xtarhdr.x_filesz = strtoull(value, NULL, 0);
6885 if (errno) {
6886 (void) fprintf(stderr, gettext(
6887 "tar: Extended header invalid filesize "
6888 "for file # %llu.\n"), xhdr_count);
6889 errors++;
6890 } else
6891 xhdr_flgs |= _X_SIZE;
6892 break;
6893 case _X_UID:
6894 xhdr_flgs |= _X_UID;
6895 Xtarhdr.x_uid = strtol(value, NULL, 0);
6896 if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
6897 (void) fprintf(stderr, gettext(
6898 "tar: Extended header uid value error "
6899 "for file # %llu.\n"), xhdr_count);
6900 Xtarhdr.x_uid = UID_NOBODY;
6902 break;
6903 case _X_UNAME:
6904 if (utf8_local("uname", &Xtarhdr.x_uname,
6905 local_uname, value, _POSIX_NAME_MAX) == 0)
6906 xhdr_flgs |= _X_UNAME;
6907 break;
6908 case _X_MTIME:
6909 get_xtime(value, &(Xtarhdr.x_mtime));
6910 if (errno)
6911 (void) fprintf(stderr, gettext(
6912 "tar: Extended header modification time "
6913 "value error for file # %llu.\n"),
6914 xhdr_count);
6915 else
6916 xhdr_flgs |= _X_MTIME;
6917 break;
6918 default:
6919 (void) fprintf(stderr,
6920 gettext("tar: unrecognized extended"
6921 " header keyword '%s'. Ignored.\n"), keyword);
6922 break;
6926 getdir(); /* get regular header */
6927 if (errors && errflag)
6928 done(1);
6929 else
6930 if (errors)
6931 Errflg = 1;
6932 return (errors);
6936 * load_info_from_xtarhdr - sets Gen and stbuf variables from
6937 * extended header
6938 * load_info_from_xtarhdr(flag, xhdrp);
6939 * u_longlong_t flag; xhdr_flgs
6940 * struct xtar_hdr *xhdrp; pointer to extended header
6941 * NOTE: called when typeflag is not 'A' and xhdr_flgs
6942 * is set.
6944 static void
6945 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
6947 if (flag & _X_DEVMAJOR) {
6948 Gen.g_devmajor = xhdrp->x_devmajor;
6950 if (flag & _X_DEVMINOR) {
6951 Gen.g_devminor = xhdrp->x_devminor;
6953 if (flag & _X_GID) {
6954 Gen.g_gid = xhdrp->x_gid;
6955 stbuf.st_gid = xhdrp->x_gid;
6957 if (flag & _X_UID) {
6958 Gen.g_uid = xhdrp->x_uid;
6959 stbuf.st_uid = xhdrp->x_uid;
6961 if (flag & _X_SIZE) {
6962 Gen.g_filesz = xhdrp->x_filesz;
6963 stbuf.st_size = xhdrp->x_filesz;
6965 if (flag & _X_MTIME) {
6966 Gen.g_mtime = xhdrp->x_mtime.tv_sec;
6967 stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
6968 stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
6973 * gen_num creates a string from a keyword and an usigned long long in the
6974 * format: %d %s=%s\n
6975 * This is part of the extended header data record.
6978 void
6979 gen_num(const char *keyword, const u_longlong_t number)
6981 char save_val[ULONGLONG_MAX_DIGITS + 1];
6982 int len;
6983 char *curr_ptr;
6985 (void) sprintf(save_val, "%llu", number);
6987 * len = length of entire line, including itself. len will be
6988 * two digits. So, add the string lengths plus the length of len,
6989 * plus a blank, an equal sign, and a newline.
6991 len = strlen(save_val) + strlen(keyword) + 5;
6992 if (xrec_offset + len > xrec_size) {
6993 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
6994 fatal(gettext(
6995 "cannot allocate extended header buffer"));
6996 xrec_ptr = curr_ptr;
6997 xrec_size *= 2;
6999 (void) sprintf(&xrec_ptr[xrec_offset],
7000 "%d %s=%s\n", len, keyword, save_val);
7001 xrec_offset += len;
7005 * gen_date creates a string from a keyword and a timestruc_t in the
7006 * format: %d %s=%s\n
7007 * This is part of the extended header data record.
7008 * Currently, granularity is only microseconds, so the low-order three digits
7009 * will be truncated.
7012 void
7013 gen_date(const char *keyword, const timestruc_t time_value)
7015 /* Allow for <seconds>.<nanoseconds>\n */
7016 char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
7017 int len;
7018 char *curr_ptr;
7020 (void) sprintf(save_val, "%ld", time_value.tv_sec);
7021 len = strlen(save_val);
7022 save_val[len] = '.';
7023 (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
7026 * len = length of entire line, including itself. len will be
7027 * two digits. So, add the string lengths plus the length of len,
7028 * plus a blank, an equal sign, and a newline.
7030 len = strlen(save_val) + strlen(keyword) + 5;
7031 if (xrec_offset + len > xrec_size) {
7032 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7033 fatal(gettext(
7034 "cannot allocate extended header buffer"));
7035 xrec_ptr = curr_ptr;
7036 xrec_size *= 2;
7038 (void) sprintf(&xrec_ptr[xrec_offset],
7039 "%d %s=%s\n", len, keyword, save_val);
7040 xrec_offset += len;
7044 * gen_string creates a string from a keyword and a char * in the
7045 * format: %d %s=%s\n
7046 * This is part of the extended header data record.
7049 void
7050 gen_string(const char *keyword, const char *value)
7052 int len;
7053 char *curr_ptr;
7056 * len = length of entire line, including itself. The character length
7057 * of len must be 1-4 characters, because the maximum size of the path
7058 * or the name is PATH_MAX, which is 1024. So, assume 1 character
7059 * for len, one for the space, one for the "=", and one for the newline.
7060 * Then adjust as needed.
7062 /* LINTED constant expression */
7063 assert(PATH_MAX <= 9996);
7064 len = strlen(value) + strlen(keyword) + 4;
7065 if (len > 997)
7066 len += 3;
7067 else if (len > 98)
7068 len += 2;
7069 else if (len > 9)
7070 len += 1;
7071 if (xrec_offset + len > xrec_size) {
7072 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7073 fatal(gettext(
7074 "cannot allocate extended header buffer"));
7075 xrec_ptr = curr_ptr;
7076 xrec_size *= 2;
7078 #ifdef XHDR_DEBUG
7079 if (strcmp(keyword+1, "name") != 0)
7080 #endif
7081 (void) sprintf(&xrec_ptr[xrec_offset],
7082 "%d %s=%s\n", len, keyword, value);
7083 #ifdef XHDR_DEBUG
7084 else {
7085 len += 11;
7086 (void) sprintf(&xrec_ptr[xrec_offset],
7087 "%d %s=%snametoolong\n", len, keyword, value);
7089 #endif
7090 xrec_offset += len;
7094 * Convert time found in the extended header data to seconds and nanoseconds.
7097 void
7098 get_xtime(char *value, timestruc_t *xtime)
7100 char nanosec[10];
7101 char *period;
7102 int i;
7104 (void) memset(nanosec, '0', 9);
7105 nanosec[9] = '\0';
7107 period = strchr(value, '.');
7108 if (period != NULL)
7109 period[0] = '\0';
7110 xtime->tv_sec = strtol(value, NULL, 10);
7111 if (period == NULL)
7112 xtime->tv_nsec = 0;
7113 else {
7114 i = strlen(period +1);
7115 (void) strncpy(nanosec, period + 1, min(i, 9));
7116 xtime->tv_nsec = strtol(nanosec, NULL, 10);
7121 * Check linkpath for length.
7122 * Emit an error message and return 1 if too long.
7126 chk_path_build(
7127 char *name,
7128 char *longname,
7129 char *linkname,
7130 char *prefix,
7131 char type,
7132 int filetype)
7135 if (strlen(linkname) > (size_t)NAMSIZ) {
7136 if (Eflag > 0) {
7137 xhdr_flgs |= _X_LINKPATH;
7138 Xtarhdr.x_linkpath = linkname;
7139 } else {
7140 (void) fprintf(stderr, gettext(
7141 "tar: %s: linked to %s\n"), longname, linkname);
7142 (void) fprintf(stderr, gettext(
7143 "tar: %s: linked name too long\n"), linkname);
7144 if (errflag)
7145 done(1);
7146 else
7147 Errflg = 1;
7148 return (1);
7151 if (xhdr_flgs & _X_LINKPATH)
7152 return (build_dblock(name, tchar, type,
7153 filetype, &stbuf, stbuf.st_dev,
7154 prefix));
7155 else
7156 return (build_dblock(name, linkname, type,
7157 filetype, &stbuf, stbuf.st_dev, prefix));
7161 * Convert from UTF-8 to local character set.
7164 static int
7165 utf8_local(
7166 char *option,
7167 char **Xhdr_ptrptr,
7168 char *target,
7169 const char *source,
7170 int max_val)
7172 static iconv_t iconv_cd;
7173 char *nl_target;
7174 const char *iconv_src;
7175 char *iconv_trg;
7176 size_t inlen;
7177 size_t outlen;
7179 if (charset_type == -1) { /* iconv_open failed in earlier try */
7180 (void) fprintf(stderr, gettext(
7181 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7182 xhdr_count, source);
7183 return (1);
7184 } else if (charset_type == 0) { /* iconv_open has not yet been done */
7185 nl_target = nl_langinfo(CODESET);
7186 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7187 nl_target = "646";
7188 if (strcmp(nl_target, "646") == 0)
7189 charset_type = 1;
7190 else if (strcmp(nl_target, "UTF-8") == 0)
7191 charset_type = 3;
7192 else {
7193 if (strncmp(nl_target, "ISO", 3) == 0)
7194 nl_target += 3;
7195 charset_type = 2;
7196 errno = 0;
7197 if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
7198 (iconv_t)-1) {
7199 if (errno == EINVAL)
7200 (void) fprintf(stderr, gettext(
7201 "tar: conversion routines not "
7202 "available for current locale. "));
7203 (void) fprintf(stderr, gettext(
7204 "file # %llu: (%s) UTF-8 conversion"
7205 " failed.\n"), xhdr_count, source);
7206 charset_type = -1;
7207 return (1);
7212 /* locale using 7-bit codeset or UTF-8 locale */
7213 if (charset_type == 1 || charset_type == 3) {
7214 if (strlen(source) > max_val) {
7215 (void) fprintf(stderr, gettext(
7216 "tar: file # %llu: Extended header %s too long.\n"),
7217 xhdr_count, option);
7218 return (1);
7220 if (charset_type == 3)
7221 (void) strcpy(target, source);
7222 else if (c_utf8(target, source) != 0) {
7223 (void) fprintf(stderr, gettext(
7224 "tar: file # %llu: (%s) UTF-8 conversion"
7225 " failed.\n"), xhdr_count, source);
7226 return (1);
7228 *Xhdr_ptrptr = target;
7229 return (0);
7232 iconv_src = source;
7233 iconv_trg = target;
7234 inlen = strlen(source);
7235 outlen = max_val * UTF_8_FACTOR;
7236 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7237 (size_t)-1) { /* Error occurred: didn't convert */
7238 (void) fprintf(stderr, gettext(
7239 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7240 xhdr_count, source);
7241 /* Get remaining output; reinitialize conversion descriptor */
7242 iconv_src = (const char *)NULL;
7243 inlen = 0;
7244 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7245 return (1);
7247 /* Get remaining output; reinitialize conversion descriptor */
7248 iconv_src = (const char *)NULL;
7249 inlen = 0;
7250 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7251 (size_t)-1) { /* Error occurred: didn't convert */
7252 (void) fprintf(stderr, gettext(
7253 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7254 xhdr_count, source);
7255 return (1);
7258 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7259 if (strlen(target) > max_val) {
7260 (void) fprintf(stderr, gettext(
7261 "tar: file # %llu: Extended header %s too long.\n"),
7262 xhdr_count, option);
7263 return (1);
7265 *Xhdr_ptrptr = target;
7266 return (0);
7270 * Check gname, uname, path, and linkpath to see if they need to go in an
7271 * extended header. If they are already slated to be in an extended header,
7272 * or if they are not ascii, then they need to be in the extended header.
7273 * Then, convert all extended names to UTF-8.
7277 gen_utf8_names(const char *filename)
7279 static iconv_t iconv_cd;
7280 char *nl_target;
7281 char tempbuf[MAXNAM + 1];
7282 int nbytes;
7283 int errors;
7285 if (charset_type == -1) { /* Previous failure to open. */
7286 (void) fprintf(stderr, gettext(
7287 "tar: file # %llu: UTF-8 conversion failed.\n"),
7288 xhdr_count);
7289 return (1);
7292 if (charset_type == 0) { /* Need to get conversion descriptor */
7293 nl_target = nl_langinfo(CODESET);
7294 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7295 nl_target = "646";
7296 if (strcmp(nl_target, "646") == 0)
7297 charset_type = 1;
7298 else if (strcmp(nl_target, "UTF-8") == 0)
7299 charset_type = 3;
7300 else {
7301 if (strncmp(nl_target, "ISO", 3) == 0)
7302 nl_target += 3;
7303 charset_type = 2;
7304 errno = 0;
7305 #ifdef ICONV_DEBUG
7306 (void) fprintf(stderr,
7307 "Opening iconv_cd with target %s\n",
7308 nl_target);
7309 #endif
7310 if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
7311 (iconv_t)-1) {
7312 if (errno == EINVAL)
7313 (void) fprintf(stderr, gettext(
7314 "tar: conversion routines not "
7315 "available for current locale. "));
7316 (void) fprintf(stderr, gettext(
7317 "file (%s): UTF-8 conversion failed.\n"),
7318 filename);
7319 charset_type = -1;
7320 return (1);
7325 errors = 0;
7327 errors += local_utf8(&Xtarhdr.x_gname, local_gname,
7328 dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
7329 errors += local_utf8(&Xtarhdr.x_uname, local_uname,
7330 dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX);
7331 if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */
7332 (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
7333 tempbuf[NAMSIZ] = '\0';
7335 errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
7336 tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
7337 if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */
7338 (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
7339 tempbuf[PRESIZ] = '\0';
7340 nbytes = strlen(tempbuf);
7341 if (nbytes > 0) {
7342 tempbuf[nbytes++] = '/';
7343 tempbuf[nbytes] = '\0';
7345 (void) strncat(tempbuf + nbytes, dblock.dbuf.name,
7346 (MAXNAM - nbytes));
7347 tempbuf[MAXNAM] = '\0';
7349 errors += local_utf8(&Xtarhdr.x_path, local_path,
7350 tempbuf, iconv_cd, _X_PATH, PATH_MAX);
7352 if (errors > 0)
7353 (void) fprintf(stderr, gettext(
7354 "tar: file (%s): UTF-8 conversion failed.\n"), filename);
7356 if (errors && errflag)
7357 done(1);
7358 else
7359 if (errors)
7360 Errflg = 1;
7361 return (errors);
7364 static int
7365 local_utf8(
7366 char **Xhdr_ptrptr,
7367 char *target,
7368 const char *source,
7369 iconv_t iconv_cd,
7370 int xhdrflg,
7371 int max_val)
7373 const char *iconv_src;
7374 const char *starting_src;
7375 char *iconv_trg;
7376 size_t inlen;
7377 size_t outlen;
7378 #ifdef ICONV_DEBUG
7379 unsigned char c_to_hex;
7380 #endif
7383 * If the item is already slated for extended format, get the string
7384 * to convert from the extended header record. Otherwise, get it from
7385 * the regular (dblock) area.
7387 if (xhdr_flgs & xhdrflg) {
7388 if (charset_type == 3) { /* Already UTF-8, just copy */
7389 (void) strcpy(target, *Xhdr_ptrptr);
7390 *Xhdr_ptrptr = target;
7391 return (0);
7392 } else
7393 iconv_src = (const char *) *Xhdr_ptrptr;
7394 } else {
7395 if (charset_type == 3) /* Already in UTF-8 format */
7396 return (0); /* Don't create xhdr record */
7397 iconv_src = source;
7399 starting_src = iconv_src;
7400 iconv_trg = target;
7401 if ((inlen = strlen(iconv_src)) == 0)
7402 return (0);
7404 if (charset_type == 1) { /* locale using 7-bit codeset */
7405 if (c_utf8(target, starting_src) != 0) {
7406 (void) fprintf(stderr,
7407 gettext("tar: invalid character in"
7408 " UTF-8 conversion of '%s'\n"), starting_src);
7409 return (1);
7411 return (0);
7414 outlen = max_val * UTF_8_FACTOR;
7415 errno = 0;
7416 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7417 (size_t)-1) {
7418 /* An error occurred, or not all characters were converted */
7419 if (errno == EILSEQ)
7420 (void) fprintf(stderr,
7421 gettext("tar: invalid character in"
7422 " UTF-8 conversion of '%s'\n"), starting_src);
7423 else
7424 (void) fprintf(stderr, gettext(
7425 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7426 starting_src);
7427 /* Get remaining output; reinitialize conversion descriptor */
7428 iconv_src = (const char *)NULL;
7429 inlen = 0;
7430 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7431 return (1);
7433 /* Get remaining output; reinitialize conversion descriptor */
7434 iconv_src = (const char *)NULL;
7435 inlen = 0;
7436 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7437 (size_t)-1) { /* Error occurred: didn't convert */
7438 if (errno == EILSEQ)
7439 (void) fprintf(stderr,
7440 gettext("tar: invalid character in"
7441 " UTF-8 conversion of '%s'\n"), starting_src);
7442 else
7443 (void) fprintf(stderr, gettext(
7444 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7445 starting_src);
7446 return (1);
7449 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7450 if (strcmp(starting_src, target) != 0) {
7451 *Xhdr_ptrptr = target;
7452 xhdr_flgs |= xhdrflg;
7453 #ifdef ICONV_DEBUG
7454 (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n",
7455 strlen(starting_src), inlen, max_val, outlen);
7456 (void) fprintf(stderr, "Input string:\n ");
7457 for (inlen = 0; inlen < strlen(starting_src); inlen++) {
7458 c_to_hex = (unsigned char)starting_src[inlen];
7459 (void) fprintf(stderr, " %2.2x", c_to_hex);
7460 if (inlen % 20 == 19)
7461 (void) fprintf(stderr, "\n ");
7463 (void) fprintf(stderr, "\nOutput string:\n ");
7464 for (inlen = 0; inlen < strlen(target); inlen++) {
7465 c_to_hex = (unsigned char)target[inlen];
7466 (void) fprintf(stderr, " %2.2x", c_to_hex);
7467 if (inlen % 20 == 19)
7468 (void) fprintf(stderr, "\n ");
7470 (void) fprintf(stderr, "\n");
7471 #endif
7474 return (0);
7478 * Function to test each byte of the source string to make sure it is
7479 * in within bounds (value between 0 and 127).
7480 * If valid, copy source to target.
7484 c_utf8(char *target, const char *source)
7486 size_t len;
7487 const char *thischar;
7489 len = strlen(source);
7490 thischar = source;
7491 while (len-- > 0) {
7492 if (!isascii((int)(*thischar++)))
7493 return (1);
7496 (void) strcpy(target, source);
7497 return (0);
7501 #if defined(O_XATTR)
7502 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
7504 static void
7505 prepare_xattr(
7506 char **attrbuf,
7507 char *filename,
7508 char *attrpath,
7509 char typeflag,
7510 struct linkbuf *linkinfo,
7511 int *rlen)
7513 char *bufhead; /* ptr to full buffer */
7514 char *aptr;
7515 struct xattr_hdr *hptr; /* ptr to header in bufhead */
7516 struct xattr_buf *tptr; /* ptr to pathing pieces */
7517 int totalen; /* total buffer length */
7518 int len; /* length returned to user */
7519 int stringlen; /* length of filename + attr */
7521 * length of filename + attr
7522 * in link section
7524 int linkstringlen;
7525 int complen; /* length of pathing section */
7526 int linklen; /* length of link section */
7527 int attrnames_index; /* attrnames starting index */
7530 * Release previous buffer
7533 if (*attrbuf != (char *)NULL) {
7534 free(*attrbuf);
7535 *attrbuf = NULL;
7539 * First add in fixed size stuff
7541 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7544 * Add space for two nulls
7546 stringlen = strlen(attrpath) + strlen(filename) + 2;
7547 complen = stringlen + sizeof (struct xattr_buf);
7549 len += stringlen;
7552 * Now add on space for link info if any
7555 if (linkinfo != NULL) {
7557 * Again add space for two nulls
7559 linkstringlen = strlen(linkinfo->pathname) +
7560 strlen(linkinfo->attrname) + 2;
7561 linklen = linkstringlen + sizeof (struct xattr_buf);
7562 len += linklen;
7563 } else {
7564 linklen = 0;
7568 * Now add padding to end to fill out TBLOCK
7570 * Function returns size of real data and not size + padding.
7573 totalen = ROUNDTOTBLOCK(len);
7575 if ((bufhead = calloc(1, totalen)) == NULL) {
7576 fatal(gettext("Out of memory."));
7581 * Now we can fill in the necessary pieces
7585 * first fill in the fixed header
7587 hptr = (struct xattr_hdr *)bufhead;
7588 (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7589 (void) sprintf(hptr->h_component_len, "%0*d",
7590 sizeof (hptr->h_component_len) - 1, complen);
7591 (void) sprintf(hptr->h_link_component_len, "%0*d",
7592 sizeof (hptr->h_link_component_len) - 1, linklen);
7593 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7596 * Now fill in the filename + attrnames section
7597 * The filename and attrnames section can be composed of two or more
7598 * path segments separated by a null character. The first segment
7599 * is the path to the parent file that roots the entire sequence in
7600 * the normal name space. The remaining segments describes a path
7601 * rooted at the hidden extended attribute directory of the leaf file of
7602 * the previous segment, making it possible to name attributes on
7603 * attributes. Thus, if we are just archiving an extended attribute,
7604 * the second segment will contain the attribute name. If we are
7605 * archiving a system attribute of an extended attribute, then the
7606 * second segment will contain the attribute name, and a third segment
7607 * will contain the system attribute name. The attribute pathing
7608 * information is obtained from 'attrpath'.
7611 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7612 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7613 stringlen);
7614 (void) strcpy(tptr->h_names, filename);
7615 attrnames_index = strlen(filename) + 1;
7616 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
7617 tptr->h_typeflag = typeflag;
7620 * Split the attrnames section into two segments if 'attrpath'
7621 * contains pathing information for a system attribute of an
7622 * extended attribute. We split them by replacing the '/' with
7623 * a '\0'.
7625 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
7626 *aptr = '\0';
7630 * Now fill in the optional link section if we have one
7633 if (linkinfo != (struct linkbuf *)NULL) {
7634 tptr = (struct xattr_buf *)(bufhead +
7635 sizeof (struct xattr_hdr) + complen);
7637 (void) sprintf(tptr->h_namesz, "%0*d",
7638 sizeof (tptr->h_namesz) - 1, linkstringlen);
7639 (void) strcpy(tptr->h_names, linkinfo->pathname);
7640 (void) strcpy(
7641 &tptr->h_names[strlen(linkinfo->pathname) + 1],
7642 linkinfo->attrname);
7643 tptr->h_typeflag = typeflag;
7645 *attrbuf = (char *)bufhead;
7646 *rlen = len;
7649 #else
7650 static void
7651 prepare_xattr(
7652 char **attrbuf,
7653 char *filename,
7654 char *attrname,
7655 char typeflag,
7656 struct linkbuf *linkinfo,
7657 int *rlen)
7659 *attrbuf = NULL;
7660 *rlen = 0;
7662 #endif
7665 getstat(int dirfd, char *longname, char *shortname, char *attrparent)
7668 int i, j;
7669 int printerr;
7670 int slnkerr;
7671 struct stat symlnbuf;
7673 if (!hflag)
7674 i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
7675 else
7676 i = fstatat(dirfd, shortname, &stbuf, 0);
7678 if (i < 0) {
7679 /* Initialize flag to print error mesg. */
7680 printerr = 1;
7682 * If stat is done, then need to do lstat
7683 * to determine whether it's a sym link
7685 if (hflag) {
7686 /* Save returned error */
7687 slnkerr = errno;
7689 j = fstatat(dirfd, shortname,
7690 &symlnbuf, AT_SYMLINK_NOFOLLOW);
7692 * Suppress error message when file is a symbolic link
7693 * and function modifier 'l' is off. Exception: when
7694 * a symlink points to a symlink points to a
7695 * symlink ... and we get past MAXSYMLINKS. That
7696 * error will cause a file not to be archived, and
7697 * needs to be printed.
7699 if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
7700 (S_ISLNK(symlnbuf.st_mode)))
7701 printerr = 0;
7704 * Restore errno in case the lstat
7705 * on symbolic link change
7707 errno = slnkerr;
7710 if (printerr) {
7711 (void) fprintf(stderr, gettext(
7712 "tar: %s%s%s%s: %s\n"),
7713 (attrparent == NULL) ? "" : gettext("attribute "),
7714 (attrparent == NULL) ? "" : attrparent,
7715 (attrparent == NULL) ? "" : gettext(" of "),
7716 longname, strerror(errno));
7717 Errflg = 1;
7719 return (1);
7721 return (0);
7725 * Recursively archive the extended attributes and/or extended system attributes
7726 * of the base file, longname. Note: extended system attribute files will be
7727 * archived only if the extended system attributes are not transient (i.e. the
7728 * extended system attributes are other than the default values).
7730 * If -@ was specified and the underlying file system supports it, archive the
7731 * extended attributes, and if there is a system attribute associated with the
7732 * extended attribute, then recursively call xattrs_put() to archive the
7733 * hidden attribute directory and the extended system attribute. If -/ was
7734 * specified and the underlying file system supports it, archive the extended
7735 * system attributes. Read-only extended system attributes are never archived.
7737 * Currently, there cannot be attributes on attributes; only system
7738 * attributes on attributes. In addition, there cannot be attributes on
7739 * system attributes. A file and it's attribute directory hierarchy looks as
7740 * follows:
7741 * longname ----> . ("." is the hidden attribute directory)
7743 * ----------------------------
7744 * | |
7745 * <sys_attr_name> <attr_name> ----> .
7747 * <sys_attr_name>
7750 #if defined(O_XATTR)
7751 static void
7752 xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
7754 char *filename = (attrparent == NULL) ? shortname : attrparent;
7755 int arc_rwsysattr = 0;
7756 int dirfd;
7757 int fd = -1;
7758 int rw_sysattr = 0;
7759 int ext_attr = 0;
7760 int rc;
7761 DIR *dirp;
7762 struct dirent *dp;
7763 attr_data_t *attrinfo = NULL;
7766 * If the underlying file system supports it, then archive the extended
7767 * attributes if -@ was specified, and the extended system attributes
7768 * if -/ was specified.
7770 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
7771 &ext_attr) != ATTR_OK) {
7772 return;
7776 * Only want to archive a read-write extended system attribute file
7777 * if it contains extended system attribute settings that are not the
7778 * default values.
7780 #if defined(_PC_SATTR_ENABLED)
7781 if (saflag) {
7782 int filefd;
7783 nvlist_t *slist = NULL;
7785 /* Determine if there are non-transient system attributes */
7786 errno = 0;
7787 if ((filefd = open(filename, O_RDONLY)) == -1) {
7788 if (attrparent == NULL) {
7789 vperror(0, gettext(
7790 "unable to open file %s"), longname);
7792 return;
7794 if (((slist = sysattr_list(basename(myname), filefd,
7795 filename)) != NULL) || (errno != 0)) {
7796 arc_rwsysattr = 1;
7798 if (slist != NULL) {
7799 (void) nvlist_free(slist);
7800 slist = NULL;
7802 (void) close(filefd);
7806 * If we aren't archiving extended system attributes, and we are
7807 * processing an attribute, or if we are archiving extended system
7808 * attributes, and there are are no extended attributes, then there's
7809 * no need to open up the attribute directory of the file unless the
7810 * extended system attributes are not transient (i.e, the system
7811 * attributes are not the default values).
7813 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
7814 (saflag && !ext_attr))) {
7815 return;
7817 #endif /* _PC_SATTR_ENABLED */
7819 /* open the parent attribute directory */
7820 fd = attropen(filename, ".", O_RDONLY);
7821 if (fd < 0) {
7822 vperror(0, gettext(
7823 "unable to open attribute directory for %s%s%sfile %s"),
7824 (attrparent == NULL) ? "" : gettext("attribute "),
7825 (attrparent == NULL) ? "" : attrparent,
7826 (attrparent == NULL) ? "" : gettext(" of "),
7827 longname);
7828 return;
7832 * We need to change into the parent's attribute directory to determine
7833 * if each of the attributes should be archived.
7835 if (fchdir(fd) < 0) {
7836 vperror(0, gettext(
7837 "cannot change to attribute directory of %s%s%sfile %s"),
7838 (attrparent == NULL) ? "" : gettext("attribute "),
7839 (attrparent == NULL) ? "" : attrparent,
7840 (attrparent == NULL) ? "" : gettext(" of "),
7841 longname);
7842 (void) close(fd);
7843 return;
7846 if (((dirfd = dup(fd)) == -1) ||
7847 ((dirp = fdopendir(dirfd)) == NULL)) {
7848 (void) fprintf(stderr, gettext(
7849 "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7850 (attrparent == NULL) ? "" : gettext("attribute "),
7851 (attrparent == NULL) ? "" : attrparent,
7852 (attrparent == NULL) ? "" : gettext(" of "),
7853 longname);
7854 if (fd > 0) {
7855 (void) close(fd);
7857 return;
7860 while (dp = readdir(dirp)) {
7861 if (strcmp(dp->d_name, "..") == 0) {
7862 continue;
7863 } else if (strcmp(dp->d_name, ".") == 0) {
7864 Hiddendir = 1;
7865 } else {
7866 Hiddendir = 0;
7869 /* Determine if this attribute should be archived */
7870 if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
7871 &rw_sysattr) != ATTR_OK) {
7872 continue;
7875 /* gather the attribute's information to pass to putfile() */
7876 if ((fill_in_attr_info(dp->d_name, longname, attrparent,
7877 fd, rw_sysattr, &attrinfo)) == 1) {
7878 continue;
7881 /* add the attribute to the archive */
7882 rc = putfile(longname, dp->d_name, parent, attrinfo,
7883 XATTR_FILE, LEV0, SYMLINK_LEV0);
7885 if (exitflag) {
7886 break;
7889 #if defined(_PC_SATTR_ENABLED)
7891 * If both -/ and -@ were specified, then archive the
7892 * attribute's extended system attributes and hidden directory
7893 * by making a recursive call to xattrs_put().
7895 if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
7896 (Hiddendir == 0)) {
7898 xattrs_put(longname, shortname, parent, dp->d_name);
7901 * Change back to the parent's attribute directory
7902 * to process any further attributes.
7904 if (fchdir(fd) < 0) {
7905 vperror(0, gettext(
7906 "cannot change back to attribute directory "
7907 "of file %s"), longname);
7908 break;
7911 #endif /* _PC_SATTR_ENABLED */
7914 if (attrinfo != NULL) {
7915 if (attrinfo->attr_parent != NULL) {
7916 free(attrinfo->attr_parent);
7918 free(attrinfo->attr_path);
7919 free(attrinfo);
7921 (void) closedir(dirp);
7922 if (fd != -1) {
7923 (void) close(fd);
7926 /* Change back to the parent directory of the base file */
7927 if (attrparent == NULL) {
7928 (void) chdir(parent);
7930 Hiddendir = 0;
7932 #else
7933 static void
7934 xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
7937 #endif /* O_XATTR */
7939 static int
7940 put_link(char *name, char *longname, char *component, char *longattrname,
7941 char *prefix, int filetype, char type)
7944 if (stbuf.st_nlink > 1) {
7945 struct linkbuf *lp;
7946 int found = 0;
7948 for (lp = ihead; lp != NULL; lp = lp->nextp)
7949 if (lp->inum == stbuf.st_ino &&
7950 lp->devnum == stbuf.st_dev) {
7951 found++;
7952 break;
7954 if (found) {
7955 #if defined(O_XATTR)
7956 if (filetype == XATTR_FILE)
7957 if (put_xattr_hdr(longname, component,
7958 longattrname, prefix, type, filetype, lp)) {
7959 goto out;
7961 #endif
7962 stbuf.st_size = (off_t)0;
7963 if (filetype != XATTR_FILE) {
7964 tomodes(&stbuf);
7965 if (chk_path_build(name, longname, lp->pathname,
7966 prefix, type, filetype) > 0) {
7967 goto out;
7971 if (mulvol && tapepos + 1 >= blocklim)
7972 newvol();
7973 (void) writetbuf((char *)&dblock, 1);
7975 * write_ancillary() is not needed here.
7976 * The first link is handled in the following
7977 * else statement. No need to process ACLs
7978 * for other hard links since they are the
7979 * same file.
7982 if (vflag) {
7983 #ifdef DEBUG
7984 if (NotTape)
7985 DEBUG("seek = %" FMT_blkcnt_t
7986 "K\t", K(tapepos), 0);
7987 #endif
7988 if (filetype == XATTR_FILE) {
7989 (void) fprintf(vfile, gettext(
7990 "a %s attribute %s link to "
7991 "%s attribute %s\n"),
7992 name, component, name,
7993 lp->attrname);
7994 } else {
7995 (void) fprintf(vfile, gettext(
7996 "a %s link to %s\n"),
7997 longname, lp->pathname);
8000 lp->count--;
8001 return (0);
8002 } else {
8003 lp = (struct linkbuf *)getmem(sizeof (*lp));
8004 if (lp != (struct linkbuf *)NULL) {
8005 lp->nextp = ihead;
8006 ihead = lp;
8007 lp->inum = stbuf.st_ino;
8008 lp->devnum = stbuf.st_dev;
8009 lp->count = stbuf.st_nlink - 1;
8010 if (filetype == XATTR_FILE) {
8011 (void) strcpy(lp->pathname, longname);
8012 (void) strcpy(lp->attrname,
8013 component);
8014 } else {
8015 (void) strcpy(lp->pathname, longname);
8016 (void) strcpy(lp->attrname, "");
8022 out:
8023 return (1);
8026 static int
8027 put_extra_attributes(char *longname, char *shortname, char *longattrname,
8028 char *prefix, int filetype, char typeflag)
8030 static acl_t *aclp = NULL;
8031 int error;
8033 if (aclp != NULL) {
8034 acl_free(aclp);
8035 aclp = NULL;
8037 #if defined(O_XATTR)
8038 if ((atflag || saflag) && (filetype == XATTR_FILE)) {
8039 if (put_xattr_hdr(longname, shortname, longattrname, prefix,
8040 typeflag, filetype, NULL)) {
8041 return (1);
8044 #endif
8046 /* ACL support */
8047 if (pflag) {
8048 char *secinfo = NULL;
8049 int len = 0;
8051 /* ACL support */
8052 if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
8054 * Get ACL info: dont bother allocating space if
8055 * there is only a trivial ACL.
8057 if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
8058 &aclp)) != 0) {
8059 (void) fprintf(stderr, gettext(
8060 "%s: failed to retrieve acl : %s\n"),
8061 longname, acl_strerror(error));
8062 return (1);
8066 /* append security attributes if any */
8067 if (aclp != NULL) {
8068 (void) append_secattr(&secinfo, &len, acl_cnt(aclp),
8069 acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8070 ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
8071 UFSD_ACL : ACE_ACL);
8074 if (Tflag) {
8075 /* append Trusted Extensions extended attributes */
8076 append_ext_attr(shortname, &secinfo, &len);
8077 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8079 } else if (aclp != NULL) {
8080 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8083 return (0);
8086 #if defined(O_XATTR)
8087 static int
8088 put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
8089 int typeflag, int filetype, struct linkbuf *lp)
8091 char *lname = NULL;
8092 char *sname = NULL;
8093 int error = 0;
8094 static char *attrbuf = NULL;
8095 int attrlen;
8097 lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
8098 strlen(shortname) + strlen(".hdr") + 1);
8100 if (lname == NULL) {
8101 fatal(gettext("Out of Memory."));
8103 sname = malloc(sizeof (char) * strlen(shortname) +
8104 strlen(".hdr") + 1);
8105 if (sname == NULL) {
8106 fatal(gettext("Out of Memory."));
8109 (void) sprintf(sname, "%s.hdr", shortname);
8110 (void) sprintf(lname, "/dev/null/%s", sname);
8112 if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
8113 sizeof (dblock.dbuf.name)) {
8114 fatal(gettext(
8115 "Buffer overflow writing extended attribute file name"));
8119 * dump extended attr lookup info
8121 prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
8122 write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
8124 (void) sprintf(lname, "/dev/null/%s", shortname);
8125 (void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
8128 * Set up filename for attribute
8131 error = build_dblock(lname, tchar, '0', filetype,
8132 &stbuf, stbuf.st_dev, prefix);
8133 free(lname);
8134 free(sname);
8136 return (error);
8138 #endif
8140 #if defined(O_XATTR)
8141 static int
8142 read_xattr_hdr(attr_data_t **attrinfo)
8144 char buf[TBLOCK];
8145 char *attrparent = NULL;
8146 blkcnt_t blocks;
8147 char *tp;
8148 off_t bytes;
8149 int comp_len, link_len;
8150 int namelen;
8151 int attrparentlen;
8152 int parentfilelen;
8154 if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
8155 return (1);
8157 bytes = stbuf.st_size;
8158 if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
8159 (void) fprintf(stderr, gettext(
8160 "Insufficient memory for extended attribute\n"));
8161 return (1);
8164 tp = (char *)xattrhead;
8165 blocks = TBLOCKS(bytes);
8166 while (blocks-- > 0) {
8167 readtape(buf);
8168 if (bytes <= TBLOCK) {
8169 (void) memcpy(tp, buf, (size_t)bytes);
8170 break;
8171 } else {
8172 (void) memcpy(tp, buf, TBLOCK);
8173 tp += TBLOCK;
8175 bytes -= TBLOCK;
8179 * Validate that we can handle header format
8181 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8182 (void) fprintf(stderr,
8183 gettext("Unknown extended attribute format encountered\n"));
8184 (void) fprintf(stderr,
8185 gettext("Disabling extended attribute parsing\n"));
8186 xattrbadhead = 1;
8187 return (0);
8189 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8190 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8191 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8192 sizeof (struct xattr_hdr));
8193 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8194 if (link_len > 0)
8195 xattr_linkp = (struct xattr_buf *)
8196 ((int)xattrp + (int)comp_len);
8197 else
8198 xattr_linkp = NULL;
8201 * Gather the attribute path from the filename and attrnames section.
8202 * The filename and attrnames section can be composed of two or more
8203 * path segments separated by a null character. The first segment
8204 * is the path to the parent file that roots the entire sequence in
8205 * the normal name space. The remaining segments describes a path
8206 * rooted at the hidden extended attribute directory of the leaf file of
8207 * the previous segment, making it possible to name attributes on
8208 * attributes.
8210 parentfilelen = strlen(xattrp->h_names);
8211 xattrapath = xattrp->h_names + parentfilelen + 1;
8212 if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
8214 * The attrnames section contains a system attribute on an
8215 * attribute. Save the name of the attribute for use later,
8216 * and replace the null separating the attribute name from
8217 * the system attribute name with a '/' so that xattrapath can
8218 * be used to display messages with the full attribute path name
8219 * rooted at the hidden attribute directory of the base file
8220 * in normal name space.
8222 attrparent = strdup(xattrapath);
8223 attrparentlen = strlen(attrparent);
8224 xattrapath[attrparentlen] = '/';
8226 if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
8227 xattrapath + attrparentlen + 1, xattrapath, attrparent,
8228 -1, 0, attrinfo)) == 1) {
8229 free(attrparent);
8230 return (1);
8233 /* Gather link info */
8234 if (xattr_linkp) {
8235 xattr_linkaname = xattr_linkp->h_names +
8236 strlen(xattr_linkp->h_names) + 1;
8237 } else {
8238 xattr_linkaname = NULL;
8241 return (0);
8243 #else
8244 static int
8245 read_xattr_hdr(attr_data_t **attrinfo)
8247 return (0);
8249 #endif
8252 * skip over extra slashes in string.
8254 * For example:
8255 * /usr/tmp/////
8257 * would return pointer at
8258 * /usr/tmp/////
8261 static char *
8262 skipslashes(char *string, char *start)
8264 while ((string > start) && *(string - 1) == '/') {
8265 string--;
8268 return (string);
8272 * Return the parent directory of a given path.
8274 * Examples:
8275 * /usr/tmp return /usr
8276 * /usr/tmp/file return /usr/tmp
8277 * / returns .
8278 * /usr returns /
8279 * file returns .
8281 * dir is assumed to be at least as big as path.
8283 static void
8284 get_parent(char *path, char *dir)
8286 char *s;
8287 char tmpdir[PATH_MAX + 1];
8289 if (strlen(path) > PATH_MAX) {
8290 fatal(gettext("pathname is too long"));
8292 (void) strcpy(tmpdir, path);
8293 chop_endslashes(tmpdir);
8295 if ((s = strrchr(tmpdir, '/')) == NULL) {
8296 (void) strcpy(dir, ".");
8297 } else {
8298 s = skipslashes(s, tmpdir);
8299 *s = '\0';
8300 if (s == tmpdir)
8301 (void) strcpy(dir, "/");
8302 else
8303 (void) strcpy(dir, tmpdir);
8307 #if defined(O_XATTR)
8308 static char *
8309 get_component(char *path)
8311 char *ptr;
8313 ptr = strrchr(path, '/');
8314 if (ptr == NULL) {
8315 return (path);
8316 } else {
8318 * Handle trailing slash
8320 if (*(ptr + 1) == '\0')
8321 return (ptr);
8322 else
8323 return (ptr + 1);
8326 #else
8327 static char *
8328 get_component(char *path)
8330 return (path);
8332 #endif
8334 #if defined(O_XATTR)
8335 static int
8336 retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
8337 int oflag, mode_t mode)
8339 int dirfd;
8340 int ofilefd = -1;
8341 struct timeval times[2];
8342 mode_t newmode;
8343 struct stat parentstat;
8344 acl_t *aclp = NULL;
8345 int error;
8348 * We couldn't get to attrdir. See if its
8349 * just a mode problem on the parent file.
8350 * for example: a mode such as r-xr--r--
8351 * on a ufs file system without extended
8352 * system attribute support won't let us
8353 * create an attribute dir if it doesn't
8354 * already exist, and on a ufs file system
8355 * with extended system attribute support
8356 * won't let us open the attribute for
8357 * write.
8359 * If file has a non-trivial ACL, then save it
8360 * off so that we can place it back on after doing
8361 * chmod's.
8363 if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
8364 O_RDONLY)) == -1) {
8365 return (-1);
8367 if (fstat(dirfd, &parentstat) == -1) {
8368 (void) fprintf(stderr, gettext(
8369 "tar: cannot stat %sfile %s: %s\n"),
8370 (pdirfd == -1) ? "" : gettext("parent of "),
8371 (pdirfd == -1) ? dirp : name, strerror(errno));
8372 return (-1);
8374 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
8375 (void) fprintf(stderr, gettext(
8376 "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8377 (pdirfd == -1) ? "" : gettext("parent of "),
8378 (pdirfd == -1) ? dirp : name, strerror(errno));
8379 return (-1);
8382 newmode = S_IWUSR | parentstat.st_mode;
8383 if (fchmod(dirfd, newmode) == -1) {
8384 (void) fprintf(stderr,
8385 gettext(
8386 "tar: cannot fchmod %sfile %s to %o: %s\n"),
8387 (pdirfd == -1) ? "" : gettext("parent of "),
8388 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8389 if (aclp)
8390 acl_free(aclp);
8391 return (-1);
8395 if (pdirfd == -1) {
8397 * We weren't able to create the attribute directory before.
8398 * Now try again.
8400 ofilefd = attropen(dirp, ".", oflag);
8401 } else {
8403 * We weren't able to create open the attribute before.
8404 * Now try again.
8406 ofilefd = openat(pdirfd, name, oflag, mode);
8410 * Put mode back to original
8412 if (fchmod(dirfd, parentstat.st_mode) == -1) {
8413 (void) fprintf(stderr,
8414 gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8415 (pdirfd == -1) ? "" : gettext("parent of "),
8416 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8419 if (aclp) {
8420 error = facl_set(dirfd, aclp);
8421 if (error) {
8422 (void) fprintf(stderr,
8423 gettext("tar: failed to set acl entries on "
8424 "%sfile %s\n"),
8425 (pdirfd == -1) ? "" : gettext("parent of "),
8426 (pdirfd == -1) ? dirp : name);
8428 acl_free(aclp);
8432 * Put back time stamps
8435 times[0].tv_sec = parentstat.st_atime;
8436 times[0].tv_usec = 0;
8437 times[1].tv_sec = parentstat.st_mtime;
8438 times[1].tv_usec = 0;
8440 (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
8442 (void) close(dirfd);
8444 return (ofilefd);
8446 #endif
8448 #if !defined(O_XATTR)
8449 static int
8450 openat64(int fd, const char *name, int oflag, mode_t cmode)
8452 return (open64(name, oflag, cmode));
8455 static int
8456 openat(int fd, const char *name, int oflag, mode_t cmode)
8458 return (open(name, oflag, cmode));
8461 static int
8462 fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
8464 if (flag == AT_SYMLINK_NOFOLLOW)
8465 return (lchown(name, owner, group));
8466 else
8467 return (chown(name, owner, group));
8470 static int
8471 renameat(int fromfd, char *old, int tofd, char *new)
8473 return (rename(old, new));
8476 static int
8477 futimesat(int fd, char *path, struct timeval times[2])
8479 return (utimes(path, times));
8482 static int
8483 unlinkat(int dirfd, char *path, int flag)
8485 if (flag == AT_REMOVEDIR)
8486 return (rmdir(path));
8487 else
8488 return (unlink(path));
8491 static int
8492 fstatat(int fd, char *path, struct stat *buf, int flag)
8494 if (flag == AT_SYMLINK_NOFOLLOW)
8495 return (lstat(path, buf));
8496 else
8497 return (stat(path, buf));
8500 static int
8501 attropen(char *file, char *attr, int omode, mode_t cmode)
8503 errno = ENOTSUP;
8504 return (-1);
8506 #endif
8508 static void
8509 chop_endslashes(char *path)
8511 char *end, *ptr;
8514 * Chop of slashes, but not if all we have is slashes
8515 * for example: ////
8516 * should make no changes, otherwise it will screw up
8517 * checkdir
8519 end = &path[strlen(path) -1];
8520 if (*end == '/' && end != path) {
8521 ptr = skipslashes(end, path);
8522 if (ptr != NULL && ptr != path) {
8523 *ptr = '\0';
8527 /* Trusted Extensions */
8530 * append_ext_attr():
8532 * Append extended attributes and other information into the buffer
8533 * that gets written to the ancillary file.
8535 * With option 'T', we create a tarfile which
8536 * has an ancillary file each corresponding archived file.
8537 * Each ancillary file contains 1 or more of the
8538 * following attributes:
8540 * attribute type attribute process procedure
8541 * ---------------- ---------------- --------------------------
8542 * DIR_TYPE = 'D' directory flag append if a directory
8543 * LBL_TYPE = 'L' SL[IL] or SL append ascii label
8547 static void
8548 append_ext_attr(char *shortname, char **secinfo, int *len)
8550 bslabel_t b_slabel; /* binary sensitvity label */
8551 char *ascii = NULL; /* ascii label */
8554 * For each attribute type, append it if it is
8555 * relevant to the file type.
8559 * For attribute type DIR_TYPE,
8560 * append it to the following file type:
8562 * S_IFDIR: directories
8566 * For attribute type LBL_TYPE,
8567 * append it to the following file type:
8569 * S_IFDIR: directories (including mld, sld)
8570 * S_IFLNK: symbolic link
8571 * S_IFREG: regular file but not hard link
8572 * S_IFIFO: FIFO file but not hard link
8573 * S_IFCHR: char special file but not hard link
8574 * S_IFBLK: block special file but not hard link
8576 switch (stbuf.st_mode & S_IFMT) {
8578 case S_IFDIR:
8581 * append DIR_TYPE
8583 (void) append_secattr(secinfo, len, 1,
8584 "\0", DIR_TYPE);
8587 * Get and append attribute types LBL_TYPE.
8588 * For directories, LBL_TYPE contains SL.
8590 /* get binary sensitivity label */
8591 if (getlabel(shortname, &b_slabel) != 0) {
8592 (void) fprintf(stderr,
8593 gettext("tar: can't get sensitvity label for "
8594 " %s, getlabel() error: %s\n"),
8595 shortname, strerror(errno));
8596 } else {
8597 /* get ascii SL */
8598 if (bsltos(&b_slabel, &ascii,
8599 0, 0) <= 0) {
8600 (void) fprintf(stderr,
8601 gettext("tar: can't get ascii SL for"
8602 " %s\n"), shortname);
8603 } else {
8604 /* append LBL_TYPE */
8605 (void) append_secattr(secinfo, len,
8606 strlen(ascii) + 1, ascii,
8607 LBL_TYPE);
8609 /* free storage */
8610 if (ascii != NULL) {
8611 free(ascii);
8612 ascii = (char *)0;
8617 break;
8619 case S_IFLNK:
8620 case S_IFREG:
8621 case S_IFIFO:
8622 case S_IFCHR:
8623 case S_IFBLK:
8625 /* get binary sensitivity label */
8626 if (getlabel(shortname, &b_slabel) != 0) {
8627 (void) fprintf(stderr,
8628 gettext("tar: can't get sensitivty label for %s, "
8629 "getlabel() error: %s\n"),
8630 shortname, strerror(errno));
8631 } else {
8632 /* get ascii IL[SL] */
8633 if (bsltos(&b_slabel, &ascii, 0, 0) <= 0) {
8634 (void) fprintf(stderr,
8635 gettext("tar: can't translate sensitivity "
8636 " label for %s\n"), shortname);
8637 } else {
8638 char *cmw_label;
8639 size_t cmw_length;
8641 cmw_length = strlen("ADMIN_LOW [] ") +
8642 strlen(ascii);
8643 if ((cmw_label = malloc(cmw_length)) == NULL) {
8644 (void) fprintf(stderr, gettext(
8645 "Insufficient memory for label\n"));
8646 exit(1);
8648 /* append LBL_TYPE */
8649 (void) snprintf(cmw_label, cmw_length,
8650 "ADMIN_LOW [%s]", ascii);
8651 (void) append_secattr(secinfo, len,
8652 strlen(cmw_label) + 1, cmw_label,
8653 LBL_TYPE);
8655 /* free storage */
8656 if (ascii != NULL) {
8657 free(cmw_label);
8658 free(ascii);
8659 ascii = (char *)0;
8663 break;
8665 default:
8666 break;
8667 } /* end switch for LBL_TYPE */
8670 /* DONE !! */
8671 return;
8673 } /* end of append_ext_attr */
8677 * Name: extract_attr()
8679 * Description:
8680 * Process attributes from the ancillary file due to
8681 * the T option.
8683 * Call by doxtract() as part of the switch case structure.
8684 * Making this a separate routine because the nesting are too
8685 * deep in doxtract, thus, leaving very little space
8686 * on each line for instructions.
8688 * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
8690 * For option 'T', following are possible attributes in
8691 * a TS 8 ancillary file: (NOTE: No IL support)
8693 * attribute type attribute process procedure
8694 * ---------------- ---------------- -------------------------
8695 * # LBL_TYPE = 'L' SL construct binary label
8696 * # APRIV_TYPE = 'P' allowed priv construct privileges
8697 * # FPRIV_TYPE = 'p' forced priv construct privileges
8698 * # COMP_TYPE = 'C' path component construct real path
8699 * # DIR_TYPE = 'D' directory flag note it is a directory
8700 * $ UFSD_ACL = '1' ACL data construct ACL entries
8701 * ATTR_FLAG_TYPE = 'F' file attr flags construct binary flags
8702 * LK_COMP_TYPE = 'K' linked path comp construct linked real path
8704 * note: # = attribute names common between TS 8 & TS 2.5 ancillary
8705 * files.
8706 * $ = ACL attribute is processed for the option 'p', it doesn't
8707 * need option 'T'.
8709 * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
8712 static void
8713 extract_attr(char **file_ptr, struct sec_attr *attr)
8715 int reterr, err;
8716 char *dummy_buf; /* for attribute extract */
8718 dummy_buf = attr->attr_info;
8720 switch (attr->attr_type) {
8722 case DIR_TYPE:
8724 dir_flag++;
8725 break;
8727 case LBL_TYPE:
8730 * LBL_TYPE is used to indicate SL for directory, and
8731 * CMW label for other file types.
8734 if (!dir_flag) { /* not directory */
8735 /* Skip over IL portion */
8736 char *sl_ptr = strchr(dummy_buf, '[');
8738 if (sl_ptr == NULL)
8739 err = 0;
8740 else
8741 err = stobsl(sl_ptr, &bs_label,
8742 NEW_LABEL, &reterr);
8743 } else { /* directory */
8744 err = stobsl(dummy_buf, &bs_label,
8745 NEW_LABEL, &reterr);
8747 if (err == 0) {
8748 (void) fprintf(stderr, gettext("tar: "
8749 "can't convert %s to binary label\n"),
8750 dummy_buf);
8751 bslundef(&bs_label);
8752 } else if (!blequal(&bs_label, &admin_low) &&
8753 !blequal(&bs_label, &admin_high)) {
8754 bslabel_t *from_label;
8755 char *buf;
8756 char tempbuf[MAXPATHLEN];
8758 if (*orig_namep != '/') {
8759 /* got relative linked to path */
8760 (void) getcwd(tempbuf, (sizeof (tempbuf)));
8761 (void) strncat(tempbuf, "/", MAXPATHLEN);
8762 } else
8763 *tempbuf = '\0';
8765 buf = real_path;
8766 (void) strncat(tempbuf, orig_namep, MAXPATHLEN);
8767 from_label = getlabelbypath(tempbuf);
8768 if (from_label != NULL) {
8769 if (blequal(from_label, &admin_low)) {
8770 if ((getpathbylabel(tempbuf, buf,
8771 MAXPATHLEN, &bs_label) == NULL)) {
8772 (void) fprintf(stderr,
8773 gettext("tar: "
8774 "can't get zone root path for "
8775 "%s\n"), tempbuf);
8776 } else
8777 rpath_flag = 1;
8779 free(from_label);
8782 break;
8784 case COMP_TYPE:
8786 rebuild_comp_path(dummy_buf, file_ptr);
8787 break;
8789 case LK_COMP_TYPE:
8791 if (rebuild_lk_comp_path(dummy_buf, file_ptr)
8792 == 0) {
8793 lk_rpath_flag = 1;
8794 } else {
8795 (void) fprintf(stderr, gettext("tar: warning: link's "
8796 "target pathname might be invalid.\n"));
8797 lk_rpath_flag = 0;
8799 break;
8800 case APRIV_TYPE:
8801 ignored_aprivs++;
8802 break;
8803 case FPRIV_TYPE:
8804 ignored_fprivs++;
8805 break;
8806 case ATTR_FLAG_TYPE:
8807 ignored_fattrs++;
8808 break;
8810 default:
8812 break;
8815 /* done */
8816 return;
8818 } /* end extract_attr */
8823 * Name: rebuild_comp_path()
8825 * Description:
8826 * Take the string of components passed down by the calling
8827 * routine and parse the values and rebuild the path.
8828 * This routine no longer needs to produce a new real_path
8829 * string because it is produced when the 'L' LABEL_TYPE is
8830 * interpreted. So the only thing done here is to distinguish
8831 * between an SLD and an MLD entry. We only want one, so we
8832 * ignore the MLD entry by setting the mld_flag.
8834 * return value:
8835 * none
8837 static void
8838 rebuild_comp_path(char *str, char **namep)
8840 char *cp;
8842 while (*str != '\0') {
8844 switch (*str) {
8846 case MLD_TYPE:
8848 str++;
8849 if ((cp = strstr(str, ";;")) != NULL) {
8850 *cp = '\0';
8851 str = cp + 2;
8852 *cp = ';';
8854 mld_flag = 1;
8855 break;
8857 case SLD_TYPE:
8859 str++;
8860 if ((cp = strstr(str, ";;")) != NULL) {
8861 *cp = '\0';
8862 str = cp + 2;
8863 *cp = ';';
8865 mld_flag = 0;
8866 break;
8868 case PATH_TYPE:
8870 str++;
8871 if ((cp = strstr(str, ";;")) != NULL) {
8872 *cp = '\0';
8873 str = cp + 2;
8874 *cp = ';';
8876 break;
8879 if (rpath_flag)
8880 *namep = real_path;
8881 return;
8883 } /* end rebuild_comp_path() */
8886 * Name: rebuild_lk_comp_path()
8888 * Description:
8889 * Take the string of components passed down by the calling
8890 * routine and parse the values and rebuild the path.
8892 * return value:
8893 * 0 = succeeded
8894 * -1 = failed
8896 static int
8897 rebuild_lk_comp_path(char *str, char **namep)
8899 char *cp;
8900 int reterr;
8901 bslabel_t bslabel;
8902 char *buf;
8903 char pbuf[MAXPATHLEN];
8904 char *ptr1, *ptr2;
8905 int plen;
8906 int use_pbuf;
8907 char tempbuf[MAXPATHLEN];
8908 int mismatch;
8909 bslabel_t *from_label;
8910 char zonename[ZONENAME_MAX];
8911 zoneid_t zoneid;
8913 /* init stuff */
8914 use_pbuf = 0;
8915 mismatch = 0;
8918 * For linked to pathname (LK_COMP_TYPE):
8919 * - If the linked to pathname is absolute (start with /), we
8920 * will use it as is.
8921 * - If it is a relative pathname then it is relative to 1 of 2
8922 * directories. For a hardlink, it is relative to the current
8923 * directory. For a symbolic link, it is relative to the
8924 * directory the symbolic link is in. For the symbolic link
8925 * case, set a flag to indicate we need to use the prefix of
8926 * the restored file's pathname with the linked to pathname.
8928 * NOTE: At this point, we have no way to determine if we have
8929 * a hardlink or a symbolic link. We will compare the 1st
8930 * component in the prefix portion of the restore file's
8931 * pathname to the 1st component in the attribute data
8932 * (the linked pathname). If they are the same, we will assume
8933 * the link pathname to reconstruct is relative to the current
8934 * directory. Otherwise, we will set a flag indicate we need
8935 * to use a prefix with the reconstructed name. Need to compare
8936 * both the adorned and unadorned version before deciding a
8937 * mismatch.
8940 buf = lk_real_path;
8941 if (*(str + 1) != '/') { /* got relative linked to path */
8942 ptr1 = orig_namep;
8943 ptr2 = strrchr(ptr1, '/');
8944 plen = ptr2 - ptr1;
8945 if (plen > 0) {
8946 pbuf[0] = '\0';
8947 plen++; /* include '/' */
8948 (void) strncpy(pbuf, ptr1, plen);
8949 *(pbuf + plen) = '\0';
8950 ptr2 = strchr(pbuf, '/');
8951 if (strncmp(pbuf, str + 1, ptr2 - pbuf) != 0)
8952 mismatch = 1;
8955 if (mismatch == 1)
8956 use_pbuf = 1;
8959 buf[0] = '\0';
8961 while (*str != '\0') {
8963 switch (*str) {
8965 case MLD_TYPE:
8967 str++;
8968 if ((cp = strstr(str, ";;")) != NULL) {
8969 *cp = '\0';
8972 * Ignore attempts to backup over .MLD.
8974 if (strcmp(str, "../") != 0)
8975 (void) strncat(buf, str, MAXPATHLEN);
8976 str = cp + 2;
8977 *cp = ';';
8979 break;
8981 case SLD_TYPE:
8983 str++;
8984 if ((cp = strstr(str, ";;")) != NULL) {
8985 *cp = '\0';
8988 * Use the path name in the header if
8989 * error occurs when processing the
8990 * SLD type.
8993 if (!stobsl(str, &bslabel,
8994 NO_CORRECTION, &reterr)) {
8995 (void) fprintf(stderr, gettext(
8996 "tar: can't translate to binary"
8997 "SL for SLD, stobsl() error:"
8998 " %s\n"), strerror(errno));
8999 return (-1);
9002 str = cp + 2;
9003 *cp = ';';
9005 if (use_pbuf == 1) {
9006 if (*pbuf != '/') {
9007 /* relative linked to path */
9009 (void) getcwd(tempbuf,
9010 (sizeof (tempbuf)));
9011 (void) strncat(tempbuf, "/",
9012 MAXPATHLEN);
9013 (void) strncat(tempbuf, pbuf,
9014 MAXPATHLEN);
9016 else
9017 (void) strcpy(tempbuf, pbuf);
9019 } else if (*buf != '/') {
9020 /* got relative linked to path */
9022 (void) getcwd(tempbuf,
9023 (sizeof (tempbuf)));
9024 (void) strncat(tempbuf, "/",
9025 MAXPATHLEN);
9026 } else
9027 *tempbuf = '\0';
9029 (void) strncat(tempbuf, buf, MAXPATHLEN);
9030 *buf = '\0';
9032 if (blequal(&bslabel, &admin_high)) {
9033 bslabel = admin_low;
9038 * Check for cross-zone symbolic links
9040 from_label = getlabelbypath(real_path);
9041 if (rpath_flag && (from_label != NULL) &&
9042 !blequal(&bslabel, from_label)) {
9043 if ((zoneid =
9044 getzoneidbylabel(&bslabel)) == -1) {
9045 (void) fprintf(stderr,
9046 gettext("tar: can't get "
9047 "zone ID for %s\n"),
9048 tempbuf);
9049 return (-1);
9051 if (zone_getattr(zoneid, ZONE_ATTR_NAME,
9052 &zonename, ZONENAME_MAX) == -1) {
9053 /* Badly configured zone info */
9054 (void) fprintf(stderr,
9055 gettext("tar: can't get "
9056 "zonename for %s\n"),
9057 tempbuf);
9058 return (-1);
9060 (void) strncpy(buf, AUTO_ZONE,
9061 MAXPATHLEN);
9062 (void) strncat(buf, "/",
9063 MAXPATHLEN);
9064 (void) strncat(buf, zonename,
9065 MAXPATHLEN);
9067 if (from_label != NULL)
9068 free(from_label);
9069 (void) strncat(buf, tempbuf, MAXPATHLEN);
9070 break;
9072 mld_flag = 0;
9073 break;
9075 case PATH_TYPE:
9077 str++;
9078 if ((cp = strstr(str, ";;")) != NULL) {
9079 *cp = '\0';
9080 (void) strncat(buf, str, MAXPATHLEN);
9081 str = cp + 2;
9082 *cp = ';';
9084 break;
9086 default:
9088 (void) fprintf(stderr, gettext(
9089 "tar: error rebuilding path %s\n"),
9090 *namep);
9091 *buf = '\0';
9092 str++;
9093 return (-1);
9098 * Done for LK_COMP_TYPE
9101 return (0); /* component path is rebuilt successfully */
9103 } /* end rebuild_lk_comp_path() */
9106 * Name: check_ext_attr()
9108 * Description:
9109 * Check the extended attributes for a file being extracted.
9110 * The attributes being checked here are CMW labels.
9111 * ACLs are not set here because they are set by the
9112 * pflag in doxtract().
9114 * If the label doesn't match, return 0
9115 * else return 1
9117 static int
9118 check_ext_attr(char *filename)
9120 bslabel_t currentlabel; /* label from zone */
9122 if (bltype(&bs_label, SUN_SL_UN)) {
9123 /* No label check possible */
9124 return (0);
9126 if (getlabel(filename, &currentlabel) != 0) {
9127 (void) fprintf(stderr,
9128 gettext("tar: can't get label for "
9129 " %s, getlabel() error: %s\n"),
9130 filename, strerror(errno));
9131 return (0);
9132 } else if ((blequal(&currentlabel, &bs_label)) == 0) {
9133 char *src_label = NULL; /* ascii label */
9135 /* get current src SL */
9136 if (bsltos(&bs_label, &src_label, 0, 0) <= 0) {
9137 (void) fprintf(stderr,
9138 gettext("tar: can't interpret requested label for"
9139 " %s\n"), filename);
9140 } else {
9141 (void) fprintf(stderr,
9142 gettext("tar: can't apply label %s to %s\n"),
9143 src_label, filename);
9144 free(src_label);
9146 (void) fprintf(stderr,
9147 gettext("tar: %s not restored\n"), filename);
9148 return (0);
9150 return (1);
9152 } /* end check_ext_attr */
9154 /* Compressing a tar file using compression method provided in 'opt' */
9156 static void
9157 compress_back()
9159 pid_t pid;
9160 int status;
9161 int wret;
9162 struct stat statb;
9164 if (vflag) {
9165 (void) fprintf(vfile,
9166 gettext("Compressing '%s' with '%s'...\n"),
9167 usefile, compress_opt);
9169 if ((pid = fork()) == 0) {
9170 (void) execlp(compress_opt, compress_opt,
9171 usefile, NULL);
9172 } else if (pid == -1) {
9173 vperror(1, "%s", gettext("Could not fork"));
9175 wait_pid(pid);
9176 if (suffix == 0) {
9177 (void) rename(tfname, usefile);
9181 /* The magic numbers from /etc/magic */
9183 #define GZIP_MAGIC "\037\213"
9184 #define BZIP_MAGIC "BZh"
9185 #define COMP_MAGIC "\037\235"
9187 void
9188 check_compression()
9190 char magic[2];
9191 char buf[16];
9192 FILE *fp;
9194 if ((fp = fopen(usefile, "r")) != NULL) {
9195 (void) fread(buf, sizeof (char), 6, fp);
9196 magic[0] = buf[0];
9197 magic[1] = buf[1];
9198 (void) fclose(fp);
9201 if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
9202 if (xflag || tflag) {
9203 compress_opt = compress_malloc(strlen(GZCAT) + 1);
9204 (void) strcpy(compress_opt, GZCAT);
9205 } else if (uflag || rflag) {
9206 compress_opt = compress_malloc(strlen(GZIP) + 1);
9207 (void) strcpy(compress_opt, GZIP);
9209 } else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
9210 if (xflag || tflag) {
9211 compress_opt = compress_malloc(strlen(BZCAT) + 1);
9212 (void) strcpy(compress_opt, BZCAT);
9213 } else if (uflag || rflag) {
9214 compress_opt = compress_malloc(strlen(BZIP) + 1);
9215 (void) strcpy(compress_opt, BZIP);
9217 } else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
9218 if (xflag || tflag) {
9219 compress_opt = compress_malloc(strlen(ZCAT) + 1);
9220 (void) strcpy(compress_opt, ZCAT);
9221 } else if (uflag || rflag) {
9222 compress_opt = compress_malloc(strlen(COMPRESS) + 1);
9223 (void) strcpy(compress_opt, COMPRESS);
9228 char *
9229 add_suffix()
9231 (void) strcpy(tfname, usefile);
9232 if (strcmp(compress_opt, GZIP) == 0) {
9233 if ((suffix = gz_suffix()) == NULL) {
9234 strlcat(tfname, gsuffix[0], sizeof (tfname));
9235 return (gsuffix[0]);
9237 } else if (strcmp(compress_opt, COMPRESS) == 0) {
9238 if ((suffix = gz_suffix()) == NULL) {
9239 strlcat(tfname, gsuffix[6], sizeof (tfname));
9240 return (gsuffix[6]);
9242 } else if (strcmp(compress_opt, BZIP) == 0) {
9243 if ((suffix = bz_suffix()) == NULL) {
9244 strlcat(tfname, bsuffix[0], sizeof (tfname));
9245 return (bsuffix[0]);
9248 return (NULL);
9251 /* Decompressing a tar file using compression method from the file type */
9252 void
9253 decompress_file(void)
9255 pid_t pid;
9256 int status;
9257 char cmdstr[PATH_MAX];
9258 char fname[PATH_MAX];
9259 char *added_suffix;
9262 added_suffix = add_suffix();
9263 if (added_suffix != NULL) {
9264 (void) rename(usefile, tfname);
9266 if ((pid = fork()) == 0) {
9267 if (vflag) {
9268 (void) fprintf(vfile,
9269 gettext("Decompressing '%s' with "
9270 "'%s'...\n"), usefile, compress_opt);
9272 (void) execlp(compress_opt, compress_opt, "-df",
9273 tfname, NULL);
9274 (void) fprintf(vfile, gettext("Could not exec %s: %s\n"),
9275 compress_opt, usefile, strerror(errno));
9276 } else if (pid == -1) {
9277 vperror(1, "Could not fork");
9279 wait_pid(pid);
9280 if (suffix != NULL) {
9281 /* restore the file name - original file was without suffix */
9282 *(usefile + strlen(usefile) - strlen(suffix)) = '\0';
9286 /* Set the archive for writing and then compress the archive */
9287 pid_t
9288 compress_file(void)
9290 int fd[2];
9291 pid_t pid;
9293 if (vflag) {
9294 (void) fprintf(vfile, gettext("Compressing '%s' with "
9295 "'%s'...\n"), usefile, compress_opt);
9298 if (pipe(fd) < 0) {
9299 vperror(1, gettext("Could not create pipe"));
9301 if (pid = fork() > 0) {
9302 mt = fd[1];
9303 (void) close(fd[0]);
9304 return (pid);
9306 /* child */
9307 (void) dup2(fd[0], STDIN_FILENO);
9308 (void) close(fd[1]);
9309 (void) dup2(mt, STDOUT_FILENO);
9310 (void) execlp(compress_opt, compress_opt, NULL);
9311 vperror(1, "%s", gettext("Could not exec %s"), compress_opt);
9312 return (0); /*NOTREACHED*/
9315 pid_t
9316 uncompress_file(void)
9318 int fd[2];
9319 pid_t pid;
9321 if (vflag) {
9322 (void) fprintf(vfile, gettext("Decompressing '%s' with "
9323 "'%s'...\n"), usefile, compress_opt);
9326 if (pipe(fd) < 0) {
9327 vperror(1, gettext("Could not create pipe"));
9329 if (pid = fork() > 0) {
9330 mt = fd[0];
9331 (void) close(fd[1]);
9332 return (pid);
9334 /* child */
9335 (void) dup2(fd[1], STDOUT_FILENO);
9336 (void) close(fd[0]);
9337 (void) dup2(mt, STDIN_FILENO);
9338 (void) execlp(compress_opt, compress_opt, NULL);
9339 vperror(1, "%s", gettext("Could not exec %s"), compress_opt);
9340 return (0); /*NOTREACHED*/
9343 /* Checking valid 'bzip2' suffix */
9344 char *
9345 bz_suffix()
9347 int i;
9348 int slen;
9349 int nlen = strlen(usefile);
9351 for (i = 0; i < BS; i++) {
9352 slen = strlen(bsuffix[i]);
9353 if (nlen < slen)
9354 return (NULL);
9355 if (strcmp(usefile + nlen - slen, bsuffix[i]) == 0)
9356 return (bsuffix[i]);
9358 return (NULL);
9361 /* Checking valid 'gzip' suffix */
9362 char *
9363 gz_suffix()
9365 int i;
9366 int slen;
9367 int nlen = strlen(usefile);
9369 for (i = 0; i < GS; i++) {
9370 slen = strlen(gsuffix[i]);
9371 if (nlen < slen)
9372 return (NULL);
9373 if (strcmp(usefile + nlen - slen, gsuffix[i]) == 0)
9374 return (gsuffix[i]);
9376 return (NULL);
9379 void *
9380 compress_malloc(size_t size)
9382 void *opt;
9384 if ((opt = malloc(size)) == NULL) {
9385 vperror(1, "%s",
9386 gettext("Could not allocate compress buffer\n"));
9388 return (opt);
9391 void
9392 wait_pid(pid_t pid)
9394 int status;
9396 while (waitpid(pid, &status, 0) == -1 && errno == EINTR)