1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 */
25
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /* Copyright (c) 1987, 1988 Microsoft Corporation */
30 /* All Rights Reserved */
31
32 /*
33 * Portions of this source code were derived from Berkeley 4.3 BSD
34 * under license from the Regents of the University of California.
35 */
36
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/stat.h>
41 #include <sys/mkdev.h>
42 #include <sys/wait.h>
43 #include <dirent.h>
44 #include <errno.h>
45 #include <stdio.h>
46 #include <signal.h>
47 #include <ctype.h>
48 #include <locale.h>
49 #include <nl_types.h>
50 #include <langinfo.h>
51 #include <pwd.h>
52 #include <grp.h>
53 #include <fcntl.h>
54 #include <string.h>
55 #include <malloc.h>
56 #include <time.h>
57 #include <utime.h>
58 #include <stdlib.h>
59 #include <stdarg.h>
60 #include <widec.h>
61 #include <sys/mtio.h>
62 #include <sys/acl.h>
63 #include <strings.h>
64 #include <deflt.h>
65 #include <limits.h>
66 #include <iconv.h>
67 #include <assert.h>
68 #include <libgen.h>
69 #include <libintl.h>
70 #include <aclutils.h>
71 #include <libnvpair.h>
72 #include <archives.h>
73
74 #if defined(__SunOS_5_6) || defined(__SunOS_5_7)
75 extern int defcntl();
76 #endif
77 #if defined(_PC_SATTR_ENABLED)
78 #include <attr.h>
79 #include <libcmdutils.h>
80 #endif
81
82 /* Trusted Extensions */
83 #include <zone.h>
84 #include <tsol/label.h>
85 #include <sys/tsol/label_macro.h>
86
87 #include "getresponse.h"
88 /*
89 * Source compatibility
90 */
91
92 /*
93 * These constants come from archives.h and sys/fcntl.h
94 * and were introduced by the extended attributes project
95 * in Solaris 9.
96 */
97 #if !defined(O_XATTR)
98 #define AT_SYMLINK_NOFOLLOW 0x1000
99 #define AT_REMOVEDIR 0x1
100 #define AT_FDCWD 0xffd19553
101 #define _XATTR_HDRTYPE 'E'
102 static int attropen();
103 static int fstatat();
104 static int renameat();
105 static int unlinkat();
106 static int openat();
107 static int fchownat();
108 static int futimesat();
109 #endif
110
111 /*
112 * Compiling with -D_XPG4_2 gets this but produces other problems, so
113 * instead of including sys/time.h and compiling with -D_XPG4_2, I'm
114 * explicitly doing the declaration here.
115 */
116 int utimes(const char *path, const struct timeval timeval_ptr[]);
117
118 #ifndef MINSIZE
119 #define MINSIZE 250
120 #endif
121 #define DEF_FILE "/etc/default/tar"
122
123 #define min(a, b) ((a) < (b) ? (a) : (b))
124 #define max(a, b) ((a) > (b) ? (a) : (b))
125
126 /* -DDEBUG ONLY for debugging */
127 #ifdef DEBUG
128 #undef DEBUG
129 #define DEBUG(a, b, c)\
130 (void) fprintf(stderr, "DEBUG - "), (void) fprintf(stderr, a, b, c)
131 #endif
132
133 #define TBLOCK 512 /* tape block size--should be universal */
134
135 #ifdef BSIZE
136 #define SYS_BLOCK BSIZE /* from sys/param.h: secondary block size */
137 #else /* BSIZE */
138 #define SYS_BLOCK 512 /* default if no BSIZE in param.h */
139 #endif /* BSIZE */
140
141 #define NBLOCK 20
142 #define NAMSIZ 100
143 #define PRESIZ 155
144 #define MAXNAM 256
145 #define MODEMASK 0777777 /* file creation mode mask */
146 #define POSIXMODES 07777 /* mask for POSIX mode bits */
147 #define MAXEXT 9 /* reasonable max # extents for a file */
148 #define EXTMIN 50 /* min blks left on floppy to split a file */
149
150 /* max value dblock.dbuf.efsize can store */
151 #define TAR_EFSIZE_MAX 0777777777
152
153 /*
154 * Symbols which specify the values at which the use of the 'E' function
155 * modifier is required to properly store a file.
156 *
157 * TAR_OFFSET_MAX - the largest file size we can archive
158 * OCTAL7CHAR - the limit for ustar gid, uid, dev
159 */
160
161 #ifdef XHDR_DEBUG
162 /* tiny values which force the creation of extended header entries */
163 #define TAR_OFFSET_MAX 9
164 #define OCTAL7CHAR 2
165 #else
166 /* normal values */
167 #define TAR_OFFSET_MAX 077777777777ULL
168 #define OCTAL7CHAR 07777777
169 #endif
170
171 #define TBLOCKS(bytes) (((bytes) + TBLOCK - 1) / TBLOCK)
172 #define K(tblocks) ((tblocks+1)/2) /* tblocks to Kbytes for printing */
173
174 #define MAXLEV (PATH_MAX / 2)
175 #define LEV0 1
176 #define SYMLINK_LEV0 0
177
178 #define TRUE 1
179 #define FALSE 0
180
181 #define XATTR_FILE 1
182 #define NORMAL_FILE 0
183
184 #define PUT_AS_LINK 1
185 #define PUT_NOTAS_LINK 0
186
187 #ifndef VIEW_READONLY
188 #define VIEW_READONLY "SUNWattr_ro"
189 #endif
190
191 #ifndef VIEW_READWRITE
192 #define VIEW_READWRITE "SUNWattr_rw"
193 #endif
194
195 #if _FILE_OFFSET_BITS == 64
196 #define FMT_off_t "lld"
197 #define FMT_off_t_o "llo"
198 #define FMT_blkcnt_t "lld"
199 #else
200 #define FMT_off_t "ld"
201 #define FMT_off_t_o "lo"
202 #define FMT_blkcnt_t "ld"
203 #endif
204
205 /* ACL support */
206
207 static
208 struct sec_attr {
209 char attr_type;
210 char attr_len[7];
211 char attr_info[1];
212 } *attr;
213
214 #if defined(O_XATTR)
215 typedef enum {
216 ATTR_OK,
217 ATTR_SKIP,
218 ATTR_CHDIR_ERR,
219 ATTR_OPEN_ERR,
220 ATTR_XATTR_ERR,
221 ATTR_SATTR_ERR
222 } attr_status_t;
223 #endif
224
225 #if defined(O_XATTR)
226 typedef enum {
227 ARC_CREATE,
228 ARC_RESTORE
229 } arc_action_t;
230 #endif
231
232 typedef struct attr_data {
233 char *attr_parent;
234 char *attr_path;
235 int attr_parentfd;
236 int attr_rw_sysattr;
237 } attr_data_t;
238
239 /*
240 *
241 * Tar has been changed to support extended attributes.
242 *
243 * As part of this change tar now uses the new *at() syscalls
244 * such as openat, fchownat(), unlinkat()...
245 *
246 * This was done so that attributes can be handled with as few code changes
247 * as possible.
248 *
249 * What this means is that tar now opens the directory that a file or directory
250 * resides in and then performs *at() functions to manipulate the entry.
251 *
252 * For example a new file is now created like this:
253 *
254 * dfd = open(<some dir path>)
255 * fd = openat(dfd, <name>,....);
256 *
257 * or in the case of an extended attribute
258 *
259 * dfd = attropen(<pathname>, ".", ....)
260 *
261 * Once we have a directory file descriptor all of the *at() functions can
262 * be applied to it.
263 *
264 * unlinkat(dfd, <component name>,...)
265 * fchownat(dfd, <component name>,..)
266 *
267 * This works for both normal namespace files and extended attribute file
268 *
269 */
270
271 /*
272 *
273 * Extended attribute Format
274 *
275 * Extended attributes are stored in two pieces.
276 * 1. An attribute header which has information about
277 * what file the attribute is for and what the attribute
278 * is named.
279 * 2. The attribute record itself. Stored as a normal file type
280 * of entry.
281 * Both the header and attribute record have special modes/typeflags
282 * associated with them.
283 *
284 * The names of the header in the archive look like:
285 * /dev/null/attr.hdr
286 *
287 * The name of the attribute looks like:
288 * /dev/null/attr
289 *
290 * This is done so that an archiver that doesn't understand these formats
291 * can just dispose of the attribute records.
292 *
293 * The format is composed of a fixed size header followed
294 * by a variable sized xattr_buf. If the attribute is a hard link
295 * to another attribute then another xattr_buf section is included
296 * for the link.
297 *
298 * The xattr_buf is used to define the necessary "pathing" steps
299 * to get to the extended attribute. This is necessary to support
300 * a fully recursive attribute model where an attribute may itself
301 * have an attribute.
302 *
303 * The basic layout looks like this.
304 *
305 * --------------------------------
306 * | |
307 * | xattr_hdr |
308 * | |
309 * --------------------------------
310 * --------------------------------
311 * | |
312 * | xattr_buf |
313 * | |
314 * --------------------------------
315 * --------------------------------
316 * | |
317 * | (optional link info) |
318 * | |
319 * --------------------------------
320 * --------------------------------
321 * | |
322 * | attribute itself |
323 * | stored as normal tar |
324 * | or cpio data with |
325 * | special mode or |
326 * | typeflag |
327 * | |
328 * --------------------------------
329 *
330 */
331
332 /*
333 * xattrhead is a pointer to the xattr_hdr
334 *
335 * xattrp is a pointer to the xattr_buf structure
336 * which contains the "pathing" steps to get to attributes
337 *
338 * xattr_linkp is a pointer to another xattr_buf structure that is
339 * only used when an attribute is actually linked to another attribute
340 *
341 */
342
343 static struct xattr_hdr *xattrhead;
344 static struct xattr_buf *xattrp;
345 static struct xattr_buf *xattr_linkp; /* pointer to link info, if any */
346 static char *xattrapath; /* attribute name */
347 static char *xattr_linkaname; /* attribute attribute is linked to */
348 static char Hiddendir; /* are we processing hidden xattr dir */
349 static char xattrbadhead;
350
351 /* Was statically allocated tbuf[NBLOCK] */
352 static
353 union hblock {
354 char dummy[TBLOCK];
355 struct header {
356 char name[NAMSIZ]; /* If non-null prefix, path is */
357 /* <prefix>/<name>; otherwise */
358 /* <name> */
359 char mode[8];
360 char uid[8];
361 char gid[8];
362 char size[12]; /* size of this extent if file split */
363 char mtime[12];
364 char chksum[8];
365 char typeflag;
366 char linkname[NAMSIZ];
367 char magic[6];
368 char version[2];
369 char uname[32];
370 char gname[32];
371 char devmajor[8];
372 char devminor[8];
373 char prefix[PRESIZ]; /* Together with "name", the path of */
374 /* the file: <prefix>/<name> */
375 char extno; /* extent #, null if not split */
376 char extotal; /* total extents */
377 char efsize[10]; /* size of entire file */
378 } dbuf;
379 } dblock, *tbuf, xhdr_buf;
380
381 static
382 struct xtar_hdr {
383 uid_t x_uid, /* Uid of file */
384 x_gid; /* Gid of file */
385 major_t x_devmajor; /* Device major node */
386 minor_t x_devminor; /* Device minor node */
387 off_t x_filesz; /* Length of file */
388 char *x_uname, /* Pointer to name of user */
389 *x_gname, /* Pointer to gid of user */
390 *x_linkpath, /* Path for a hard/symbolic link */
391 *x_path; /* Path of file */
392 timestruc_t x_mtime; /* Seconds and nanoseconds */
393 } Xtarhdr;
394
395 static
396 struct gen_hdr {
397 ulong_t g_mode; /* Mode of file */
398 uid_t g_uid, /* Uid of file */
399 g_gid; /* Gid of file */
400 off_t g_filesz; /* Length of file */
401 time_t g_mtime; /* Modification time */
402 uint_t g_cksum; /* Checksum of file */
403 ulong_t g_devmajor, /* File system of file */
404 g_devminor; /* Major/minor of special files */
405 } Gen;
406
407 static
408 struct linkbuf {
409 ino_t inum;
410 dev_t devnum;
411 int count;
412 char pathname[MAXNAM+1]; /* added 1 for last NULL */
413 char attrname[MAXNAM+1];
414 struct linkbuf *nextp;
415 } *ihead;
416
417 /* see comments before build_table() */
418 #define TABLE_SIZE 512
419 typedef struct file_list {
420 char *name; /* Name of file to {in,ex}clude */
421 struct file_list *next; /* Linked list */
422 } file_list_t;
423 static file_list_t *exclude_tbl[TABLE_SIZE],
424 *include_tbl[TABLE_SIZE];
425
426 static int append_secattr(char **, int *, int, char *, char);
427 static void write_ancillary(union hblock *, char *, int, char);
428
429 static void add_file_to_table(file_list_t *table[], char *str);
430 static void assert_string(char *s, char *msg);
431 static int istape(int fd, int type);
432 static void backtape(void);
433 static void build_table(file_list_t *table[], char *file);
434 static int check_prefix(char **namep, char **dirp, char **compp);
435 static void closevol(void);
436 static void copy(void *dst, void *src);
437 static int convtoreg(off_t);
438 static void delete_target(int fd, char *comp, char *namep);
439 static void doDirTimes(char *name, timestruc_t modTime);
440 static void done(int n);
441 static void dorep(char *argv[]);
442 static void dotable(char *argv[]);
443 static void doxtract(char *argv[]);
444 static int tar_chdir(const char *path);
445 static int is_directory(char *name);
446 static int has_dot_dot(char *name);
447 static int is_absolute(char *name);
448 static char *make_relative_name(char *name, char **stripped_prefix);
449 static void fatal(char *format, ...);
450 static void vperror(int exit_status, char *fmt, ...);
451 static void flushtape(void);
452 static void getdir(void);
453 static void *getmem(size_t);
454 static void longt(struct stat *st, char aclchar);
455 static void load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp);
456 static int makeDir(char *name);
457 static void mterr(char *operation, int i, int exitcode);
458 static void newvol(void);
459 static void passtape(void);
460 static void putempty(blkcnt_t n);
461 static int putfile(char *longname, char *shortname, char *parent,
462 attr_data_t *attrinfo, int filetype, int lev, int symlink_lev);
463 static void readtape(char *buffer);
464 static void seekdisk(blkcnt_t blocks);
465 static void setPathTimes(int dirfd, char *path, timestruc_t modTime);
466 static void setbytes_to_skip(struct stat *st, int err);
467 static void splitfile(char *longname, int ifd, char *name,
468 char *prefix, int filetype);
469 static void tomodes(struct stat *sp);
470 static void usage(void);
471 static int xblocks(int issysattr, off_t bytes, int ofile);
472 static int xsfile(int issysattr, int ofd);
473 static void resugname(int dirfd, char *name, int symflag);
474 static int bcheck(char *bstr);
475 static int checkdir(char *name);
476 static int checksum(union hblock *dblockp);
477 #ifdef EUC
478 static int checksum_signed(union hblock *dblockp);
479 #endif /* EUC */
480 static int checkupdate(char *arg);
481 static int checkw(char c, char *name);
482 static int cmp(char *b, char *s, int n);
483 static int defset(char *arch);
484 static int endtape(void);
485 static int is_in_table(file_list_t *table[], char *str);
486 static int notsame(void);
487 static int is_prefix(char *s1, char *s2);
488 static int response(void);
489 static int build_dblock(const char *, const char *, const char,
490 const int filetype, const struct stat *, const dev_t, const char *);
491 static unsigned int hash(char *str);
492
493 static blkcnt_t kcheck(char *kstr);
494 static off_t bsrch(char *s, int n, off_t l, off_t h);
495 static void onintr(int sig);
496 static void onquit(int sig);
497 static void onhup(int sig);
498 static uid_t getuidbyname(char *);
499 static gid_t getgidbyname(char *);
500 static char *getname(gid_t);
501 static char *getgroup(gid_t);
502 static int checkf(char *name, int mode, int howmuch);
503 static int writetbuf(char *buffer, int n);
504 static int wantit(char *argv[], char **namep, char **dirp, char **comp,
505 attr_data_t **attrinfo);
506 static void append_ext_attr(char *shortname, char **secinfo, int *len);
507 static int get_xdata(void);
508 static void gen_num(const char *keyword, const u_longlong_t number);
509 static void gen_date(const char *keyword, const timestruc_t time_value);
510 static void gen_string(const char *keyword, const char *value);
511 static void get_xtime(char *value, timestruc_t *xtime);
512 static int chk_path_build(char *name, char *longname, char *linkname,
513 char *prefix, char type, int filetype);
514 static int gen_utf8_names(const char *filename);
515 static int utf8_local(char *option, char **Xhdr_ptrptr, char *target,
516 const char *src, int max_val);
517 static int local_utf8(char **Xhdr_ptrptr, char *target, const char *src,
518 iconv_t iconv_cd, int xhdrflg, int max_val);
519 static int c_utf8(char *target, const char *source);
520 static int getstat(int dirfd, char *longname, char *shortname,
521 char *attrparent);
522 static void xattrs_put(char *, char *, char *, char *);
523 static void prepare_xattr(char **, char *, char *,
524 char, struct linkbuf *, int *);
525 static int put_link(char *name, char *longname, char *component,
526 char *longattrname, char *prefix, int filetype, char typeflag);
527 static int put_extra_attributes(char *longname, char *shortname,
528 char *longattrname, char *prefix, int filetype, char typeflag);
529 static int put_xattr_hdr(char *longname, char *shortname, char *longattrname,
530 char *prefix, int typeflag, int filetype, struct linkbuf *lp);
531 static int read_xattr_hdr(attr_data_t **attrinfo);
532
533 /* Trusted Extensions */
534 #define AUTO_ZONE "/zone"
535
536 static void extract_attr(char **file_ptr, struct sec_attr *);
537 static int check_ext_attr(char *filename);
538 static void rebuild_comp_path(char *str, char **namep);
539 static int rebuild_lk_comp_path(char *str, char **namep);
540
541 static void get_parent(char *path, char *dir);
542 static char *get_component(char *path);
543 static int retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr,
544 char *name, int oflag, mode_t mode);
545 static char *skipslashes(char *string, char *start);
546 static void chop_endslashes(char *path);
547 static pid_t compress_file(void);
548 static void compress_back(void);
549 static void decompress_file(void);
550 static pid_t uncompress_file(void);
551 static void *compress_malloc(size_t);
552 static void check_compression(void);
553 static char *bz_suffix(void);
554 static char *gz_suffix(void);
555 static char *xz_suffix(void);
556 static char *add_suffix();
557 static void wait_pid(pid_t);
558 static void verify_compress_opt(const char *t);
559 static void detect_compress(void);
560
561 static struct stat stbuf;
562
563 static char *myname;
564 static char *xtract_chdir = NULL;
565 static int checkflag = 0;
566 static int Xflag, Fflag, iflag, hflag, Bflag, Iflag;
567 static int rflag, xflag, vflag, tflag, mt, svmt, cflag, mflag, pflag;
568 static int uflag;
569 static int errflag;
570 static int oflag;
571 static int bflag, Aflag;
572 static int Pflag; /* POSIX conformant archive */
573 static int Eflag; /* Allow files greater than 8GB */
574 static int atflag; /* traverse extended attributes */
575 static int saflag; /* traverse extended sys attributes */
576 static int Dflag; /* Data change flag */
577 static int jflag; /* flag to use 'bzip2' */
578 static int zflag; /* flag to use 'gzip' */
579 static int Zflag; /* flag to use 'compress' */
580 static int Jflag; /* flag to use 'xz' */
581 static int aflag; /* flag to use autocompression */
582
583 /* Trusted Extensions */
584 static int Tflag; /* Trusted Extensions attr flags */
585 static int dir_flag; /* for attribute extract */
586 static int mld_flag; /* for attribute extract */
587 static char *orig_namep; /* original namep - unadorned */
588 static int rpath_flag; /* MLD real path is rebuilt */
589 static char real_path[MAXPATHLEN]; /* MLD real path */
590 static int lk_rpath_flag; /* linked to real path is rebuilt */
591 static char lk_real_path[MAXPATHLEN]; /* linked real path */
592 static bslabel_t bs_label; /* for attribute extract */
593 static bslabel_t admin_low;
594 static bslabel_t admin_high;
595 static int ignored_aprivs = 0;
596 static int ignored_fprivs = 0;
597 static int ignored_fattrs = 0;
598
599 static int term, chksum, wflag,
600 first = TRUE, defaults_used = FALSE, linkerrok;
601 static blkcnt_t recno;
602 static int freemem = 1;
603 static int nblock = NBLOCK;
604 static int Errflg = 0;
605 static int exitflag = 0;
606
607 static dev_t mt_dev; /* device containing output file */
608 static ino_t mt_ino; /* inode number of output file */
609 static int mt_devtype; /* dev type of archive, from stat structure */
610
611 static int update = 1; /* for `open' call */
612
613 static off_t low;
614 static off_t high;
615
616 static FILE *tfile;
617 static FILE *vfile = stdout;
618 static char *tmpdir;
619 static char *tmp_suffix = "/tarXXXXXX";
620 static char *tname;
621 static char archive[] = "archive0=";
622 static char *Xfile;
623 static char *usefile;
624 static char tfname[1024];
625
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;
642
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
661
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)
666 /*
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.
670 */
671 #define UTF_8_FACTOR 6
672
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 */
677
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];
682
683 /*
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!
691 *
692 * Simply assign "waitaround = 0" once you attach to the process, and then
693 * proceed from there as usual.
694 */
695
696 #ifdef WAITAROUND
697 int waitaround = 0; /* wait for rendezvous with the debugger */
698 #endif
699
700 #define BZIP "/usr/bin/bzip2"
701 #define GZIP "/usr/bin/gzip"
702 #define COMPRESS "/usr/bin/compress"
703 #define XZ "/usr/bin/xz"
704 #define BZCAT "/usr/bin/bzcat"
705 #define GZCAT "/usr/bin/gzcat"
706 #define ZCAT "/usr/bin/zcat"
707 #define XZCAT "/usr/bin/xzcat"
708 #define GSUF 8 /* number of valid 'gzip' sufixes */
709 #define BSUF 4 /* number of valid 'bzip2' sufixes */
710 #define XSUF 1 /* number of valid 'xz' suffixes */
711
712 static char *compress_opt; /* compression type */
713
714 static char *gsuffix[] = {".gz", "-gz", ".z", "-z", "_z", ".Z",
715 ".tgz", ".taz"};
716 static char *bsuffix[] = {".bz2", ".bz", ".tbz2", ".tbz"};
717 static char *xsuffix[] = {".xz"};
718 static char *suffix;
719
720
721 int
722 main(int argc, char *argv[])
723 {
724 char *cp;
725 char *tmpdirp;
726 pid_t thispid;
727 pid_t pid;
728 int wstat;
729
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();
737
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);
743 }
744
745 if (init_yes() < 0) {
746 (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES),
747 strerror(errno));
748 exit(2);
749 }
750
751 /*
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.
756 */
757
758 if (strcmp(argv[1], "--") == 0) {
759 argv++;
760 argc--;
761 if (argc < 3)
762 usage();
763 }
764
765 argv[argc] = NULL;
766 argv++;
767
768 /*
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'.
774 */
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;
786 }
787 }
788 }
789
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 Fflag++;
806 break;
807 case 'c':
808 cflag++;
809 rflag++;
810 update = 1;
811 break;
812 #if defined(O_XATTR)
813 case '@':
814 atflag++;
815 break;
816 #endif /* O_XATTR */
817 #if defined(_PC_SATTR_ENABLED)
818 case '/':
819 saflag++;
820 break;
821 #endif /* _PC_SATTR_ENABLED */
822 case 'u':
823 uflag++; /* moved code after signals caught */
824 rflag++;
825 update = 2;
826 break;
827 case 'r':
828 rflag++;
829 update = 2;
830 break;
831 case 'v':
832 vflag++;
833 break;
834 case 'w':
835 wflag++;
836 break;
837 case 'x':
838 xflag++;
839 break;
840 case 'X':
841 assert_string(*argv, gettext(
842 "tar: exclude file must be specified with 'X' "
843 "function modifier\n"));
844 Xflag = 1;
845 Xfile = *argv++;
846 build_table(exclude_tbl, Xfile);
847 break;
848 case 't':
849 tflag++;
850 break;
851 case 'm':
852 mflag++;
853 break;
854 case 'p':
855 pflag++;
856 break;
857 case 'D':
858 Dflag++;
859 break;
860 case '-':
861 /* ignore this silently */
862 break;
863 case '0': /* numeric entries used only for defaults */
864 case '1':
865 case '2':
866 case '3':
867 case '4':
868 case '5':
869 case '6':
870 case '7':
871 break;
872 case 'b':
873 assert_string(*argv, gettext(
874 "tar: blocking factor must be specified "
875 "with 'b' function modifier\n"));
876 bflag++;
877 nblock = bcheck(*argv++);
878 break;
879 case 'n': /* not a magtape (instead of 'k') */
880 NotTape++; /* assume non-magtape */
881 break;
882 case 'l':
883 linkerrok++;
884 break;
885 case 'e':
886 errflag++;
887 case 'o':
888 oflag++;
889 break;
890 case 'h':
891 hflag++;
892 break;
893 case 'i':
894 iflag++;
895 break;
896 case 'B':
897 Bflag++;
898 break;
899 case 'P':
900 Pflag++;
901 break;
902 case 'E':
903 Eflag++;
904 Pflag++; /* Only POSIX archive made */
905 break;
906 case 'T':
907 Tflag++; /* Handle Trusted Extensions attrs */
908 pflag++; /* also set flag for ACL */
909 break;
910 case 'j': /* compession "bzip2" */
911 jflag = 1;
912 break;
913 case 'z': /* compression "gzip" */
914 zflag = 1;
915 break;
916 case 'Z': /* compression "compress" */
917 Zflag = 1;
918 break;
919 case 'J': /* compression "xz" */
920 Jflag = 1;
921 break;
922 case 'a':
923 aflag = 1; /* autocompression */
924 break;
925 default:
926 (void) fprintf(stderr, gettext(
927 "tar: %c: unknown function modifier\n"), *cp);
928 usage();
929 }
930
931 if (!rflag && !xflag && !tflag)
932 usage();
933 if ((rflag && xflag) || (xflag && tflag) || (rflag && tflag)) {
934 (void) fprintf(stderr, gettext(
935 "tar: specify only one of [ctxru].\n"));
936 usage();
937 }
938 if (cflag) {
939 if ((jflag + zflag + Zflag + Jflag + aflag) > 1) {
940 (void) fprintf(stderr, gettext(
941 "tar: specify only one of [ajJzZ] to "
942 "create a compressed file.\n"));
943 usage();
944 }
945 }
946 /* Trusted Extensions attribute handling */
947 if (Tflag && ((getzoneid() != GLOBAL_ZONEID) ||
948 !is_system_labeled())) {
949 (void) fprintf(stderr, gettext(
950 "tar: the 'T' option is only available with "
951 "Trusted Extensions\nand must be run from "
952 "the global zone.\n"));
953 usage();
954 }
955 if (cflag && *argv == NULL)
956 fatal(gettext("Missing filenames"));
957 if (usefile == NULL)
958 fatal(gettext("device argument required"));
959
960 /* alloc a buffer of the right size */
961 if ((tbuf = (union hblock *)
962 calloc(sizeof (union hblock) * nblock, sizeof (char))) ==
963 (union hblock *)NULL) {
964 (void) fprintf(stderr, gettext(
965 "tar: cannot allocate physio buffer\n"));
966 exit(1);
967 }
968
969 if ((xrec_ptr = malloc(xrec_size)) == NULL) {
970 (void) fprintf(stderr, gettext(
971 "tar: cannot allocate extended header buffer\n"));
972 exit(1);
973 }
974
975 #ifdef WAITAROUND
976 if (waitaround) {
977 (void) fprintf(stderr, gettext("Rendezvous with tar on pid"
978 " %d\n"), getpid());
979
980 while (waitaround) {
981 (void) sleep(10);
982 }
983 }
984 #endif
985
986 thispid = getpid();
987 (void) sprintf(pidchars, "%ld", thispid);
988 thispid = strlen(pidchars);
989
990 if ((tmpdirp = getenv("TMPDIR")) == (char *)NULL)
991 (void) strcpy(xhdr_dirname, "/tmp");
992 else {
993 /*
994 * Make sure that dir is no longer than what can
995 * fit in the prefix part of the header.
996 */
997 if (strlen(tmpdirp) > (size_t)(PRESIZ - thispid - 12)) {
998 (void) strcpy(xhdr_dirname, "/tmp");
999 if ((vflag > 0) && (Eflag > 0))
1000 (void) fprintf(stderr, gettext(
1001 "Ignoring TMPDIR\n"));
1002 } else
1003 (void) strcpy(xhdr_dirname, tmpdirp);
1004 }
1005 (void) strcat(xhdr_dirname, "/PaxHeaders.");
1006 (void) strcat(xhdr_dirname, pidchars);
1007
1008 if (rflag) {
1009 if (cflag && usefile != NULL) {
1010 /* Set the compression type */
1011 if (aflag)
1012 detect_compress();
1013
1014 if (jflag) {
1015 compress_opt = compress_malloc(strlen(BZIP)
1016 + 1);
1017 (void) strcpy(compress_opt, BZIP);
1018 } else if (zflag) {
1019 compress_opt = compress_malloc(strlen(GZIP)
1020 + 1);
1021 (void) strcpy(compress_opt, GZIP);
1022 } else if (Zflag) {
1023 compress_opt =
1024 compress_malloc(strlen(COMPRESS) + 1);
1025 (void) strcpy(compress_opt, COMPRESS);
1026 } else if (Jflag) {
1027 compress_opt = compress_malloc(strlen(XZ) + 1);
1028 (void) strcpy(compress_opt, XZ);
1029 }
1030 } else {
1031 /*
1032 * Decompress if the file is compressed for
1033 * an update or replace.
1034 */
1035 if (strcmp(usefile, "-") != 0) {
1036 check_compression();
1037 if (compress_opt != NULL) {
1038 decompress_file();
1039 }
1040 }
1041 }
1042
1043 if (cflag && tfile != NULL)
1044 usage();
1045 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1046 (void) signal(SIGINT, onintr);
1047 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1048 (void) signal(SIGHUP, onhup);
1049 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
1050 (void) signal(SIGQUIT, onquit);
1051 if (uflag) {
1052 int tnum;
1053 struct stat sbuf;
1054
1055 tmpdir = getenv("TMPDIR");
1056 /*
1057 * If the name is invalid or this isn't a directory,
1058 * or the directory is not writable, then reset to
1059 * a default temporary directory.
1060 */
1061 if (tmpdir == NULL || *tmpdir == '\0' ||
1062 (strlen(tmpdir) + strlen(tmp_suffix)) > PATH_MAX) {
1063 tmpdir = "/tmp";
1064 } else if (stat(tmpdir, &sbuf) < 0 ||
1065 (sbuf.st_mode & S_IFMT) != S_IFDIR ||
1066 (sbuf.st_mode & S_IWRITE) == 0) {
1067 tmpdir = "/tmp";
1068 }
1069
1070 if ((tname = calloc(1, strlen(tmpdir) +
1071 strlen(tmp_suffix) + 1)) == NULL) {
1072 vperror(1, gettext("tar: out of memory, "
1073 "cannot create temporary file\n"));
1074 }
1075 (void) strcpy(tname, tmpdir);
1076 (void) strcat(tname, tmp_suffix);
1077
1078 if ((tnum = mkstemp(tname)) == -1)
1079 vperror(1, "%s", tname);
1080 if ((tfile = fdopen(tnum, "w")) == NULL)
1081 vperror(1, "%s", tname);
1082 }
1083 if (strcmp(usefile, "-") == 0) {
1084 if (cflag == 0)
1085 fatal(gettext(
1086 "can only create standard output archives."));
1087 vfile = stderr;
1088 mt = dup(1);
1089 ++bflag;
1090 } else {
1091 if (cflag)
1092 mt = open(usefile,
1093 O_RDWR|O_CREAT|O_TRUNC, 0666);
1094 else
1095 mt = open(usefile, O_RDWR);
1096
1097 if (mt < 0) {
1098 if (cflag == 0 || (mt = creat(usefile, 0666))
1099 < 0)
1100 vperror(1, "%s", usefile);
1101 }
1102 }
1103 /* Get inode and device number of output file */
1104 (void) fstat(mt, &stbuf);
1105 mt_ino = stbuf.st_ino;
1106 mt_dev = stbuf.st_dev;
1107 mt_devtype = stbuf.st_mode & S_IFMT;
1108 NotTape = !istape(mt, mt_devtype);
1109
1110 if (rflag && !cflag && (mt_devtype == S_IFIFO))
1111 fatal(gettext("cannot append to pipe or FIFO."));
1112
1113 if (Aflag && vflag)
1114 (void) printf(
1115 gettext("Suppressing absolute pathnames\n"));
1116 if (cflag && compress_opt != NULL) {
1117 pid = compress_file();
1118 wait_pid(pid);
1119 }
1120 dorep(argv);
1121 if (rflag && !cflag && (compress_opt != NULL))
1122 compress_back();
1123 } else if (xflag || tflag) {
1124 /*
1125 * for each argument, check to see if there is a "-I file" pair.
1126 * if so, move the 3rd argument into "-I"'s place, build_table()
1127 * using "file"'s name and increment argc one (the second
1128 * increment appears in the for loop) which removes the two
1129 * args "-I" and "file" from the argument vector.
1130 */
1131 for (argc = 0; argv[argc]; argc++) {
1132 if (strcmp(argv[argc], "-I") == 0) {
1133 if (!argv[argc+1]) {
1134 (void) fprintf(stderr, gettext(
1135 "tar: missing argument for -I flag\n"));
1136 done(2);
1137 } else {
1138 Iflag = 1;
1139 argv[argc] = argv[argc+2];
1140 build_table(include_tbl, argv[++argc]);
1141 }
1142 } else if (strcmp(argv[argc], "-C") == 0) {
1143 if (!argv[argc+1]) {
1144 (void) fprintf(stderr, gettext("tar: "
1145 "missing argument for -C flag\n"));
1146 done(2);
1147 } else if (xtract_chdir != NULL) {
1148 (void) fprintf(stderr, gettext("tar: "
1149 "extract should have only one -C "
1150 "flag\n"));
1151 done(2);
1152 } else {
1153 argv[argc] = argv[argc+2];
1154 xtract_chdir = argv[++argc];
1155 }
1156 }
1157 }
1158 if (strcmp(usefile, "-") == 0) {
1159 mt = dup(0);
1160 ++bflag;
1161 /* try to recover from short reads when reading stdin */
1162 ++Bflag;
1163 } else if ((mt = open(usefile, 0)) < 0)
1164 vperror(1, "%s", usefile);
1165
1166 /* Decompress if the file is compressed */
1167
1168 if (strcmp(usefile, "-") != 0) {
1169 check_compression();
1170 if (compress_opt != NULL) {
1171 pid = uncompress_file();
1172 wait_pid(pid);
1173 }
1174 }
1175 if (xflag) {
1176 if (xtract_chdir != NULL) {
1177 if (tar_chdir(xtract_chdir) < 0) {
1178 vperror(1, gettext("can't change "
1179 "directories to %s"), xtract_chdir);
1180 }
1181 }
1182 if (Aflag && vflag)
1183 (void) printf(gettext(
1184 "Suppressing absolute pathnames.\n"));
1185
1186 doxtract(argv);
1187 } else if (tflag)
1188 dotable(argv);
1189 }
1190 else
1191 usage();
1192
1193 done(Errflg);
1194
1195 /* Not reached: keep compiler quiet */
1196 return (1);
1197 }
1198
1199 static void
1200 usage(void)
1201 {
1202 (void) fprintf(stderr, gettext(
1203 #if defined(O_XATTR)
1204 #if defined(_PC_SATTR_ENABLED)
1205 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@/[0-7]][bf][X...] "
1206 #else
1207 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw@[0-7]][bf][X...] "
1208 #endif /* _PC_SATTR_ENABLED */
1209 #else
1210 "Usage: tar {c|r|t|u|x}[BDeEFhilmnopPTvw[0-7]][bf][X...] "
1211 #endif /* O_XATTR */
1212 "[j|J|z|Z] "
1213 "[blocksize] [tarfile] [size] [exclude-file...] "
1214 "{file | -I include-file | -C directory file}...\n"));
1215 done(1);
1216 }
1217
1218 /*
1219 * dorep - do "replacements"
1220 *
1221 * Dorep is responsible for creating ('c'), appending ('r')
1222 * and updating ('u');
1223 */
1224
1225 static void
1226 dorep(char *argv[])
1227 {
1228 char *cp, *cp2, *p;
1229 char wdir[PATH_MAX+2], tempdir[PATH_MAX+2], *parent;
1230 char file[PATH_MAX*2], origdir[PATH_MAX+1];
1231 FILE *fp = (FILE *)NULL;
1232 int archtype;
1233 int ret;
1234
1235
1236 if (!cflag) {
1237 xhdr_flgs = 0;
1238 getdir(); /* read header for next file */
1239 if (Xhdrflag > 0) {
1240 if (!Eflag)
1241 fatal(gettext("Archive contains extended"
1242 " header. -E flag required.\n"));
1243 ret = get_xdata(); /* Get extended header items */
1244 /* and regular header */
1245 } else {
1246 if (Eflag)
1247 fatal(gettext("Archive contains no extended"
1248 " header. -E flag not allowed.\n"));
1249 }
1250 while (!endtape()) { /* changed from a do while */
1251 setbytes_to_skip(&stbuf, ret);
1252 passtape(); /* skip the file data */
1253 if (term)
1254 done(Errflg); /* received signal to stop */
1255 xhdr_flgs = 0;
1256 getdir();
1257 if (Xhdrflag > 0)
1258 ret = get_xdata();
1259 }
1260 if (ret == 0) {
1261 if ((dblock.dbuf.typeflag != 'A') &&
1262 (xhdr_flgs != 0)) {
1263 load_info_from_xtarhdr(xhdr_flgs,
1264 &Xtarhdr);
1265 xhdr_flgs |= _X_XHDR;
1266 }
1267 }
1268 backtape(); /* was called by endtape */
1269 if (tfile != NULL) {
1270 /*
1271 * Buffer size is calculated to be the size of the
1272 * tmpdir string, plus 6 times the size of the tname
1273 * string, plus a value that is known to be greater
1274 * than the command pipeline string.
1275 */
1276 int buflen = strlen(tmpdir) + (6 * strlen(tname)) + 100;
1277 char *buf;
1278
1279 if ((buf = (char *)calloc(1, buflen)) == NULL) {
1280 vperror(1, gettext("tar: out of memory, "
1281 "cannot create sort command file\n"));
1282 }
1283
1284 (void) snprintf(buf, buflen, "env 'TMPDIR=%s' "
1285 "sort +0 -1 +1nr %s -o %s; awk '$1 "
1286 "!= prev {print; prev=$1}' %s >%sX;mv %sX %s",
1287 tmpdir, tname, tname, tname, tname, tname, tname);
1288 (void) fflush(tfile);
1289 (void) system(buf);
1290 free(buf);
1291 (void) freopen(tname, "r", tfile);
1292 (void) fstat(fileno(tfile), &stbuf);
1293 high = stbuf.st_size;
1294 }
1295 }
1296
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));
1307 }
1308
1309 /*
1310 * Save the original directory before it gets
1311 * changed.
1312 */
1313 if (getcwd(origdir, (PATH_MAX+1)) == NULL) {
1314 vperror(0, gettext("A parent directory cannot be read"));
1315 exit(1);
1316 }
1317
1318 (void) strcpy(wdir, origdir);
1319
1320 while ((*argv || fp) && !term) {
1321 if (fp || (strcmp(*argv, "-I") == 0)) {
1322 if (fp == NULL) {
1323 if (*++argv == NULL)
1324 fatal(gettext(
1325 "missing file name for -I flag."));
1326 else if ((fp = fopen(*argv++, "r")) == NULL)
1327 vperror(0, "%s", argv[-1]);
1328 continue;
1329 } else if ((fgets(file, PATH_MAX-1, fp)) == NULL) {
1330 (void) fclose(fp);
1331 fp = NULL;
1332 continue;
1333 } else {
1334 cp = cp2 = file;
1335 if ((p = strchr(cp2, '\n')))
1336 *p = 0;
1337 }
1338 } else if ((strcmp(*argv, "-C") == 0) && argv[1]) {
1339 if (tar_chdir(*++argv) < 0)
1340 vperror(0, gettext(
1341 "can't change directories to %s"), *argv);
1342 else
1343 (void) getcwd(wdir, (sizeof (wdir)));
1344 argv++;
1345 continue;
1346 } else
1347 cp = cp2 = strcpy(file, *argv++);
1348
1349 /*
1350 * point cp2 to the last '/' in file, but not
1351 * to a trailing '/'
1352 */
1353 for (; *cp; cp++) {
1354 if (*cp == '/') {
1355 while (*(cp+1) == '/') {
1356 ++cp;
1357 }
1358 if (*(cp+1) != '\0') {
1359 /* not trailing slash */
1360 cp2 = cp;
1361 }
1362 }
1363 }
1364 if (cp2 != file) {
1365 *cp2 = '\0';
1366 if (tar_chdir(file) < 0) {
1367 vperror(0, gettext(
1368 "can't change directories to %s"), file);
1369 continue;
1370 }
1371 *cp2 = '/';
1372 cp2++;
1373 }
1374
1375 parent = getcwd(tempdir, (sizeof (tempdir)));
1376
1377 archtype = putfile(file, cp2, parent, NULL, NORMAL_FILE,
1378 LEV0, SYMLINK_LEV0);
1379
1380 #if defined(O_XATTR)
1381 if (!exitflag) {
1382 if ((atflag || saflag) &&
1383 (archtype == PUT_NOTAS_LINK)) {
1384 xattrs_put(file, cp2, parent, NULL);
1385 }
1386 }
1387 #endif
1388
1389 if (tar_chdir(origdir) < 0)
1390 vperror(0, gettext("cannot change back?: %s"), origdir);
1391
1392 if (exitflag) {
1393 /*
1394 * If e function modifier has been specified
1395 * write the files (that are listed before the
1396 * file causing the error) to tape. exitflag is
1397 * used because only some of the error conditions
1398 * in putfile() recognize the e function modifier.
1399 */
1400 break;
1401 }
1402 }
1403
1404 putempty((blkcnt_t)2);
1405 flushtape();
1406 closevol(); /* SP-1 */
1407 if (linkerrok == 1)
1408 for (; ihead != NULL; ihead = ihead->nextp) {
1409 if (ihead->count == 0)
1410 continue;
1411 (void) fprintf(stderr, gettext(
1412 "tar: missing links to %s\n"), ihead->pathname);
1413 if (errflag)
1414 done(1);
1415 else
1416 Errflg = 1;
1417 }
1418 }
1419
1420
1421 /*
1422 * endtape - check for tape at end
1423 *
1424 * endtape checks the entry in dblock.dbuf to see if its the
1425 * special EOT entry. Endtape is usually called after getdir().
1426 *
1427 * endtape used to call backtape; it no longer does, he who
1428 * wants it backed up must call backtape himself
1429 * RETURNS: 0 if not EOT, tape position unaffected
1430 * 1 if EOT, tape position unaffected
1431 */
1432
1433 static int
1434 endtape(void)
1435 {
1436 if (dblock.dbuf.name[0] == '\0') { /* null header = EOT */
1437 return (1);
1438 } else
1439 return (0);
1440 }
1441
1442 /*
1443 * getdir - get directory entry from tar tape
1444 *
1445 * getdir reads the next tarblock off the tape and cracks
1446 * it as a directory. The checksum must match properly.
1447 *
1448 * If tfile is non-null getdir writes the file name and mod date
1449 * to tfile.
1450 */
1451
1452 static void
1453 getdir(void)
1454 {
1455 struct stat *sp;
1456 #ifdef EUC
1457 static int warn_chksum_sign = 0;
1458 #endif /* EUC */
1459
1460 top:
1461 readtape((char *)&dblock);
1462 if (dblock.dbuf.name[0] == '\0')
1463 return;
1464 sp = &stbuf;
1465 (void) sscanf(dblock.dbuf.mode, "%8lo", &Gen.g_mode);
1466 (void) sscanf(dblock.dbuf.uid, "%8lo", (ulong_t *)&Gen.g_uid);
1467 (void) sscanf(dblock.dbuf.gid, "%8lo", (ulong_t *)&Gen.g_gid);
1468 (void) sscanf(dblock.dbuf.size, "%12" FMT_off_t_o, &Gen.g_filesz);
1469 (void) sscanf(dblock.dbuf.mtime, "%12lo", (ulong_t *)&Gen.g_mtime);
1470 (void) sscanf(dblock.dbuf.chksum, "%8o", &Gen.g_cksum);
1471 (void) sscanf(dblock.dbuf.devmajor, "%8lo", &Gen.g_devmajor);
1472 (void) sscanf(dblock.dbuf.devminor, "%8lo", &Gen.g_devminor);
1473
1474 is_posix = (strcmp(dblock.dbuf.magic, magic_type) == 0);
1475
1476 sp->st_mode = Gen.g_mode;
1477 if (is_posix && (sp->st_mode & S_IFMT) == 0)
1478 switch (dblock.dbuf.typeflag) {
1479 case '0': case 0: case _XATTR_HDRTYPE:
1480 sp->st_mode |= S_IFREG;
1481 break;
1482 case '1': /* hard link */
1483 break;
1484 case '2':
1485 sp->st_mode |= S_IFLNK;
1486 break;
1487 case '3':
1488 sp->st_mode |= S_IFCHR;
1489 break;
1490 case '4':
1491 sp->st_mode |= S_IFBLK;
1492 break;
1493 case '5':
1494 sp->st_mode |= S_IFDIR;
1495 break;
1496 case '6':
1497 sp->st_mode |= S_IFIFO;
1498 break;
1499 default:
1500 if (convtoreg(Gen.g_filesz))
1501 sp->st_mode |= S_IFREG;
1502 break;
1503 }
1504
1505 if ((dblock.dbuf.typeflag == 'X') || (dblock.dbuf.typeflag == 'L')) {
1506 Xhdrflag = 1; /* Currently processing extended header */
1507 } else {
1508 Xhdrflag = 0;
1509 }
1510
1511 sp->st_uid = Gen.g_uid;
1512 sp->st_gid = Gen.g_gid;
1513 sp->st_size = Gen.g_filesz;
1514 sp->st_mtime = Gen.g_mtime;
1515 chksum = Gen.g_cksum;
1516
1517 if (dblock.dbuf.extno != '\0') { /* split file? */
1518 extno = dblock.dbuf.extno;
1519 extsize = Gen.g_filesz;
1520 extotal = dblock.dbuf.extotal;
1521 } else {
1522 extno = 0; /* tell others file not split */
1523 extsize = 0;
1524 extotal = 0;
1525 }
1526
1527 #ifdef EUC
1528 if (chksum != checksum(&dblock)) {
1529 if (chksum != checksum_signed(&dblock)) {
1530 (void) fprintf(stderr, gettext(
1531 "tar: directory checksum error\n"));
1532 if (iflag) {
1533 Errflg = 2;
1534 goto top;
1535 }
1536 done(2);
1537 } else {
1538 if (! warn_chksum_sign) {
1539 warn_chksum_sign = 1;
1540 (void) fprintf(stderr, gettext(
1541 "tar: warning: tar file made with signed checksum\n"));
1542 }
1543 }
1544 }
1545 #else
1546 if (chksum != checksum(&dblock)) {
1547 (void) fprintf(stderr, gettext(
1548 "tar: directory checksum error\n"));
1549 if (iflag) {
1550 Errflg = 2;
1551 goto top;
1552 }
1553 done(2);
1554 }
1555 #endif /* EUC */
1556 if (tfile != NULL && Xhdrflag == 0) {
1557 /*
1558 * If an extended header is present, then time is available
1559 * in nanoseconds in the extended header data, so set it.
1560 * Otherwise, give an invalid value so that checkupdate will
1561 * not test beyond seconds.
1562 */
1563 if ((xhdr_flgs & _X_MTIME))
1564 sp->st_mtim.tv_nsec = Xtarhdr.x_mtime.tv_nsec;
1565 else
1566 sp->st_mtim.tv_nsec = -1;
1567
1568 if (xhdr_flgs & _X_PATH)
1569 (void) fprintf(tfile, "%s %10ld.%9.9ld\n",
1570 Xtarhdr.x_path, sp->st_mtim.tv_sec,
1571 sp->st_mtim.tv_nsec);
1572 else
1573 (void) fprintf(tfile, "%.*s %10ld.%9.9ld\n",
1574 NAMSIZ, dblock.dbuf.name, sp->st_mtim.tv_sec,
1575 sp->st_mtim.tv_nsec);
1576 }
1577
1578 #if defined(O_XATTR)
1579 Hiddendir = 0;
1580 if (xattrp && dblock.dbuf.typeflag == _XATTR_HDRTYPE) {
1581 if (xattrbadhead) {
1582 free(xattrhead);
1583 xattrp = NULL;
1584 xattr_linkp = NULL;
1585 xattrhead = NULL;
1586 } else {
1587 char *aname = basename(xattrapath);
1588 size_t xindex = aname - xattrapath;
1589
1590 if (xattrapath[xindex] == '.' &&
1591 xattrapath[xindex + 1] == '\0' &&
1592 xattrp->h_typeflag == '5') {
1593 Hiddendir = 1;
1594 sp->st_mode =
1595 (S_IFDIR | (sp->st_mode & POSIXMODES));
1596 }
1597 dblock.dbuf.typeflag = xattrp->h_typeflag;
1598 }
1599 }
1600 #endif
1601 }
1602
1603
1604 /*
1605 * passtape - skip over a file on the tape
1606 *
1607 * passtape skips over the next data file on the tape.
1608 * The tape directory entry must be in dblock.dbuf. This
1609 * routine just eats the number of blocks computed from the
1610 * directory size entry; the tape must be (logically) positioned
1611 * right after thee directory info.
1612 */
1613
1614 static void
1615 passtape(void)
1616 {
1617 blkcnt_t blocks;
1618 char buf[TBLOCK];
1619
1620 /*
1621 * Types link(1), sym-link(2), char special(3), blk special(4),
1622 * directory(5), and FIFO(6) do not have data blocks associated
1623 * with them so just skip reading the data block.
1624 */
1625 if (dblock.dbuf.typeflag == '1' || dblock.dbuf.typeflag == '2' ||
1626 dblock.dbuf.typeflag == '3' || dblock.dbuf.typeflag == '4' ||
1627 dblock.dbuf.typeflag == '5' || dblock.dbuf.typeflag == '6')
1628 return;
1629 blocks = TBLOCKS(stbuf.st_size);
1630
1631 /* if operating on disk, seek instead of reading */
1632 if (NotTape)
1633 seekdisk(blocks);
1634 else
1635 while (blocks-- > 0)
1636 readtape(buf);
1637 }
1638
1639 #if defined(O_XATTR)
1640 static int
1641 is_sysattr(char *name)
1642 {
1643 return ((strcmp(name, VIEW_READONLY) == 0) ||
1644 (strcmp(name, VIEW_READWRITE) == 0));
1645 }
1646 #endif
1647
1648 #if defined(O_XATTR)
1649 /*
1650 * Verify the attribute, attrname, is an attribute we want to restore.
1651 * Never restore read-only system attribute files. Only restore read-write
1652 * system attributes files when -/ was specified, and only traverse into
1653 * the 2nd level attribute directory containing only system attributes if
1654 * -@ was specified. This keeps us from archiving
1655 * <attribute name>/<read-write system attribute file>
1656 * when -/ was specified without -@.
1657 *
1658 * attrname - attribute file name
1659 * attrparent - attribute's parent name within the base file's attribute
1660 * directory hierarchy
1661 */
1662 static attr_status_t
1663 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
1664 int *rw_sysattr)
1665 {
1666 #if defined(_PC_SATTR_ENABLED)
1667 int attr_supported;
1668
1669 /* Never restore read-only system attribute files */
1670 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
1671 *rw_sysattr = 0;
1672 return (ATTR_SKIP);
1673 } else {
1674 *rw_sysattr = (attr_supported == _RW_SATTR);
1675 }
1676 #else
1677 /*
1678 * Only need to check if this attribute is an extended system
1679 * attribute.
1680 */
1681 if (*rw_sysattr = is_sysattr(attrname)) {
1682 return (ATTR_SKIP);
1683 } else {
1684 return (ATTR_OK);
1685 }
1686 #endif /* _PC_SATTR_ENABLED */
1687
1688 /*
1689 * If the extended system attribute file is specified with the
1690 * arc_rwsysattr flag, as being transient (default extended
1691 * attributes), then don't archive it.
1692 */
1693 if (*rw_sysattr && !arc_rwsysattr) {
1694 return (ATTR_SKIP);
1695 }
1696
1697 /*
1698 * Only restore read-write system attribute files
1699 * when -/ was specified. Only restore extended
1700 * attributes when -@ was specified.
1701 */
1702 if (atflag) {
1703 if (!saflag) {
1704 /*
1705 * Only archive/restore the hidden directory "." if
1706 * we're processing the top level hidden attribute
1707 * directory. We don't want to process the
1708 * hidden attribute directory of the attribute
1709 * directory that contains only extended system
1710 * attributes.
1711 */
1712 if (*rw_sysattr || (Hiddendir &&
1713 (attrparent != NULL))) {
1714 return (ATTR_SKIP);
1715 }
1716 }
1717 } else if (saflag) {
1718 /*
1719 * Only archive/restore read-write extended system attribute
1720 * files of the base file.
1721 */
1722 if (!*rw_sysattr || (attrparent != NULL)) {
1723 return (ATTR_SKIP);
1724 }
1725 } else {
1726 return (ATTR_SKIP);
1727 }
1728
1729 return (ATTR_OK);
1730 }
1731 #endif
1732
1733 static void
1734 free_children(file_list_t *children)
1735 {
1736 file_list_t *child = children;
1737 file_list_t *cptr;
1738
1739 while (child != NULL) {
1740 cptr = child->next;
1741 if (child->name != NULL) {
1742 free(child->name);
1743 }
1744 child = cptr;
1745 }
1746 }
1747
1748 static int
1749 putfile(char *longname, char *shortname, char *parent, attr_data_t *attrinfo,
1750 int filetype, int lev, int symlink_lev)
1751 {
1752 int infile = -1; /* deliberately invalid */
1753 blkcnt_t blocks;
1754 char buf[PATH_MAX + 2]; /* Add trailing slash and null */
1755 char *bigbuf;
1756 int maxread;
1757 int hint; /* amount to write to get "in sync" */
1758 char filetmp[PATH_MAX + 1];
1759 char *cp;
1760 char *name;
1761 char *attrparent = NULL;
1762 char *longattrname = NULL;
1763 file_list_t *child = NULL;
1764 file_list_t *child_end = NULL;
1765 file_list_t *cptr;
1766 struct dirent *dp;
1767 DIR *dirp;
1768 int i;
1769 int split;
1770 int dirfd = -1;
1771 int rc = PUT_NOTAS_LINK;
1772 int archtype = 0;
1773 int rw_sysattr = 0;
1774 char newparent[PATH_MAX + MAXNAMLEN + 1];
1775 char *prefix = "";
1776 char *tmpbuf;
1777 char goodbuf[PRESIZ + 2];
1778 char junkbuf[MAXNAM+1];
1779 char *lastslash;
1780 int j;
1781 struct stat sbuf;
1782 int readlink_max;
1783
1784 (void) memset(goodbuf, '\0', sizeof (goodbuf));
1785 (void) memset(junkbuf, '\0', sizeof (junkbuf));
1786
1787 xhdr_flgs = 0;
1788
1789 if (filetype == XATTR_FILE) {
1790 attrparent = attrinfo->attr_parent;
1791 longattrname = attrinfo->attr_path;
1792 dirfd = attrinfo->attr_parentfd;
1793 rw_sysattr = attrinfo->attr_rw_sysattr;
1794 } else {
1795 dirfd = open(".", O_RDONLY);
1796 }
1797
1798 if (dirfd == -1) {
1799 (void) fprintf(stderr, gettext(
1800 "tar: unable to open%sdirectory %s%s%s%s\n"),
1801 (filetype == XATTR_FILE) ? gettext(" attribute ") : " ",
1802 (attrparent == NULL) ? "" : gettext("of attribute "),
1803 (attrparent == NULL) ? "" : attrparent,
1804 (attrparent == NULL) ? "" : gettext(" of "),
1805 (filetype == XATTR_FILE) ? longname : parent);
1806 goto out;
1807 }
1808
1809 if (lev > MAXLEV) {
1810 (void) fprintf(stderr,
1811 gettext("tar: directory nesting too deep, %s not dumped\n"),
1812 longname);
1813 goto out;
1814 }
1815
1816 if (getstat(dirfd, longname, shortname, attrparent))
1817 goto out;
1818
1819 if (hflag) {
1820 /*
1821 * Catch nesting where a file is a symlink to its directory.
1822 */
1823 j = fstatat(dirfd, shortname, &sbuf, AT_SYMLINK_NOFOLLOW);
1824 if (S_ISLNK(sbuf.st_mode)) {
1825 if (symlink_lev++ >= MAXSYMLINKS) {
1826 (void) fprintf(stderr, gettext(
1827 "tar: %s: Number of symbolic links "
1828 "encountered during path name traversal "
1829 "exceeds MAXSYMLINKS\n"), longname);
1830 Errflg = 1;
1831 goto out;
1832 }
1833 }
1834 }
1835
1836 /*
1837 * Check if the input file is the same as the tar file we
1838 * are creating
1839 */
1840 if ((mt_ino == stbuf.st_ino) && (mt_dev == stbuf.st_dev)) {
1841 (void) fprintf(stderr, gettext(
1842 "tar: %s%s%s%s%s same as archive file\n"),
1843 rw_sysattr ? gettext("system ") : "",
1844 (longattrname == NULL) ? "" : gettext("attribute "),
1845 (longattrname == NULL) ? "" : longattrname,
1846 (longattrname == NULL) ? "" : gettext(" of "),
1847 longname);
1848 Errflg = 1;
1849 goto out;
1850 }
1851 /*
1852 * Check size limit - we can't archive files that
1853 * exceed TAR_OFFSET_MAX bytes because of header
1854 * limitations. Exclude file types that set
1855 * st_size to zero below because they take no
1856 * archive space to represent contents.
1857 */
1858 if ((stbuf.st_size > (off_t)TAR_OFFSET_MAX) &&
1859 !S_ISDIR(stbuf.st_mode) &&
1860 !S_ISCHR(stbuf.st_mode) &&
1861 !S_ISBLK(stbuf.st_mode) &&
1862 (Eflag == 0)) {
1863 (void) fprintf(stderr, gettext(
1864 "tar: %s%s%s%s%s too large to archive. "
1865 "Use E function modifier.\n"),
1866 rw_sysattr ? gettext("system ") : "",
1867 (longattrname == NULL) ? "" : gettext("attribute "),
1868 (longattrname == NULL) ? "" : longattrname,
1869 (longattrname == NULL) ? "" : gettext(" of "),
1870 longname);
1871 if (errflag)
1872 exitflag = 1;
1873 Errflg = 1;
1874 goto out;
1875 }
1876
1877 if (tfile != NULL && checkupdate(longname) == 0) {
1878 goto out;
1879 }
1880 if (checkw('r', longname) == 0) {
1881 goto out;
1882 }
1883
1884 if (Fflag &&
1885 checkf(longname, (stbuf.st_mode & S_IFMT) == S_IFDIR, Fflag) == 0)
1886 goto out;
1887
1888 if (Xflag) {
1889 if (is_in_table(exclude_tbl, longname)) {
1890 if (vflag) {
1891 (void) fprintf(vfile, gettext(
1892 "a %s excluded\n"), longname);
1893 }
1894 goto out;
1895 }
1896 }
1897
1898 /*
1899 * If the length of the fullname is greater than MAXNAM,
1900 * print out a message and return (unless extended headers are used,
1901 * in which case fullname is limited to PATH_MAX).
1902 */
1903
1904 if ((((split = (int)strlen(longname)) > MAXNAM) && (Eflag == 0)) ||
1905 (split > PATH_MAX)) {
1906 (void) fprintf(stderr, gettext(
1907 "tar: %s: file name too long\n"), longname);
1908 if (errflag)
1909 exitflag = 1;
1910 Errflg = 1;
1911 goto out;
1912 }
1913
1914 /*
1915 * We split the fullname into prefix and name components if any one
1916 * of three conditions holds:
1917 * -- the length of the fullname exceeds NAMSIZ,
1918 * -- the length of the fullname equals NAMSIZ, and the shortname
1919 * is less than NAMSIZ, (splitting in this case preserves
1920 * compatibility with 5.6 and 5.5.1 tar), or
1921 * -- the length of the fullname equals NAMSIZ, the file is a
1922 * directory and we are not in POSIX-conformant mode (where
1923 * trailing slashes are removed from directories).
1924 */
1925 if ((split > NAMSIZ) ||
1926 (split == NAMSIZ && strlen(shortname) < NAMSIZ) ||
1927 (split == NAMSIZ && S_ISDIR(stbuf.st_mode) && !Pflag)) {
1928 /*
1929 * Since path is limited to PRESIZ characters, look for the
1930 * last slash within PRESIZ + 1 characters only.
1931 */
1932 (void) strncpy(&goodbuf[0], longname, min(split, PRESIZ + 1));
1933 tmpbuf = goodbuf;
1934 lastslash = strrchr(tmpbuf, '/');
1935 if (lastslash == NULL) {
1936 i = split; /* Length of name */
1937 j = 0; /* Length of prefix */
1938 goodbuf[0] = '\0';
1939 } else {
1940 *lastslash = '\0'; /* Terminate the prefix */
1941 j = strlen(tmpbuf);
1942 i = split - j - 1;
1943 }
1944 /*
1945 * If the filename is greater than NAMSIZ we can't
1946 * archive the file unless we are using extended headers.
1947 */
1948 if ((i > NAMSIZ) || (i == NAMSIZ && S_ISDIR(stbuf.st_mode) &&
1949 !Pflag)) {
1950 /* Determine which (filename or path) is too long. */
1951 lastslash = strrchr(longname, '/');
1952 if (lastslash != NULL)
1953 i = strlen(lastslash + 1);
1954 if (Eflag > 0) {
1955 xhdr_flgs |= _X_PATH;
1956 Xtarhdr.x_path = longname;
1957 if (i <= NAMSIZ)
1958 (void) strcpy(junkbuf, lastslash + 1);
1959 else
1960 (void) sprintf(junkbuf, "%llu",
1961 xhdr_count + 1);
1962 if (split - i - 1 > PRESIZ)
1963 (void) strcpy(goodbuf, xhdr_dirname);
1964 } else {
1965 if ((i > NAMSIZ) || (i == NAMSIZ &&
1966 S_ISDIR(stbuf.st_mode) && !Pflag))
1967 (void) fprintf(stderr, gettext(
1968 "tar: %s: filename is greater than "
1969 "%d\n"), lastslash == NULL ?
1970 longname : lastslash + 1, NAMSIZ);
1971 else
1972 (void) fprintf(stderr, gettext(
1973 "tar: %s: prefix is greater than %d"
1974 "\n"), longname, PRESIZ);
1975 if (errflag)
1976 exitflag = 1;
1977 Errflg = 1;
1978 goto out;
1979 }
1980 } else
1981 (void) strncpy(&junkbuf[0], longname + j + 1,
1982 strlen(longname + j + 1));
1983 name = junkbuf;
1984 prefix = goodbuf;
1985 } else {
1986 name = longname;
1987 }
1988 if (Aflag) {
1989 if ((prefix != NULL) && (*prefix != '\0'))
1990 while (*prefix == '/')
1991 ++prefix;
1992 else
1993 while (*name == '/')
1994 ++name;
1995 }
1996
1997 switch (stbuf.st_mode & S_IFMT) {
1998 case S_IFDIR:
1999 stbuf.st_size = (off_t)0;
2000 blocks = TBLOCKS(stbuf.st_size);
2001
2002 if (filetype != XATTR_FILE && Hiddendir == 0) {
2003 i = 0;
2004 cp = buf;
2005 while ((*cp++ = longname[i++]))
2006 ;
2007 *--cp = '/';
2008 *++cp = 0;
2009 }
2010 if (!oflag) {
2011 tomodes(&stbuf);
2012 if (build_dblock(name, tchar, '5', filetype,
2013 &stbuf, stbuf.st_dev, prefix) != 0) {
2014 goto out;
2015 }
2016 if (!Pflag) {
2017 /*
2018 * Old archives require a slash at the end
2019 * of a directory name.
2020 *
2021 * XXX
2022 * If directory name is too long, will
2023 * slash overfill field?
2024 */
2025 if (strlen(name) > (unsigned)NAMSIZ-1) {
2026 (void) fprintf(stderr, gettext(
2027 "tar: %s: filename is greater "
2028 "than %d\n"), name, NAMSIZ);
2029 if (errflag)
2030 exitflag = 1;
2031 Errflg = 1;
2032 goto out;
2033 } else {
2034 if (strlen(name) == (NAMSIZ - 1)) {
2035 (void) memcpy(dblock.dbuf.name,
2036 name, NAMSIZ);
2037 dblock.dbuf.name[NAMSIZ-1]
2038 = '/';
2039 } else
2040 (void) sprintf(dblock.dbuf.name,
2041 "%s/", name);
2042
2043 /*
2044 * need to recalculate checksum
2045 * because the name changed.
2046 */
2047 (void) sprintf(dblock.dbuf.chksum,
2048 "%07o", checksum(&dblock));
2049 }
2050 }
2051
2052 if (put_extra_attributes(longname, shortname,
2053 longattrname, prefix, filetype, '5') != 0)
2054 goto out;
2055
2056 #if defined(O_XATTR)
2057 /*
2058 * Reset header typeflag when archiving directory, since
2059 * build_dblock changed it on us.
2060 */
2061 if (filetype == XATTR_FILE) {
2062 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2063 } else {
2064 dblock.dbuf.typeflag = '5';
2065 }
2066 #else
2067 dblock.dbuf.typeflag = '5';
2068 #endif
2069
2070 (void) sprintf(dblock.dbuf.chksum, "%07o",
2071 checksum(&dblock));
2072
2073 (void) writetbuf((char *)&dblock, 1);
2074 }
2075 if (vflag) {
2076 #ifdef DEBUG
2077 if (NotTape)
2078 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2079 0);
2080 #endif
2081 if (filetype == XATTR_FILE && Hiddendir) {
2082 (void) fprintf(vfile,
2083 gettext("a %s attribute %s "),
2084 longname, longattrname);
2085
2086 } else {
2087 (void) fprintf(vfile, "a %s/ ", longname);
2088 }
2089 if (NotTape)
2090 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2091 K(blocks));
2092 else
2093 (void) fprintf(vfile, gettext("%" FMT_blkcnt_t
2094 " tape blocks\n"), blocks);
2095 }
2096
2097 /*
2098 * If hidden dir then break now since xattrs_put() will do
2099 * the iterating of the directory.
2100 *
2101 * At the moment, there can only be system attributes on
2102 * attributes. There can be no attributes on attributes or
2103 * directories within the attributes hidden directory hierarchy.
2104 */
2105 if (filetype == XATTR_FILE)
2106 break;
2107
2108 if (*shortname != '/')
2109 (void) sprintf(newparent, "%s/%s", parent, shortname);
2110 else
2111 (void) sprintf(newparent, "%s", shortname);
2112
2113 if (tar_chdir(shortname) < 0) {
2114 vperror(0, "%s", newparent);
2115 goto out;
2116 }
2117
2118 if ((dirp = opendir(".")) == NULL) {
2119 vperror(0, gettext(
2120 "can't open directory %s"), longname);
2121 if (tar_chdir(parent) < 0)
2122 vperror(0, gettext("cannot change back?: %s"),
2123 parent);
2124 goto out;
2125 }
2126
2127 /*
2128 * Create a list of files (children) in this directory to avoid
2129 * having to perform telldir()/seekdir().
2130 */
2131 while ((dp = readdir(dirp)) != NULL && !term) {
2132 if ((strcmp(".", dp->d_name) == 0) ||
2133 (strcmp("..", dp->d_name) == 0))
2134 continue;
2135 if (((cptr = (file_list_t *)calloc(sizeof (char),
2136 sizeof (file_list_t))) == NULL) ||
2137 ((cptr->name = strdup(dp->d_name)) == NULL)) {
2138 vperror(1, gettext(
2139 "Insufficient memory for directory "
2140 "list entry %s/%s\n"),
2141 newparent, dp->d_name);
2142 }
2143
2144 /* Add the file to the list */
2145 if (child == NULL) {
2146 child = cptr;
2147 } else {
2148 child_end->next = cptr;
2149 }
2150 child_end = cptr;
2151 }
2152 (void) closedir(dirp);
2153
2154 /*
2155 * Archive each of the files in the current directory.
2156 * If a file is a directory, putfile() is called
2157 * recursively to archive the file hierarchy of the
2158 * directory before archiving the next file in the
2159 * current directory.
2160 */
2161 while ((child != NULL) && !term) {
2162 (void) strcpy(cp, child->name);
2163 archtype = putfile(buf, cp, newparent, NULL,
2164 NORMAL_FILE, lev + 1, symlink_lev);
2165
2166 if (!exitflag) {
2167 if ((atflag || saflag) &&
2168 (archtype == PUT_NOTAS_LINK)) {
2169 xattrs_put(buf, cp, newparent, NULL);
2170 }
2171 }
2172 if (exitflag)
2173 break;
2174
2175 /* Free each child as we are done processing it. */
2176 cptr = child;
2177 child = child->next;
2178 free(cptr->name);
2179 free(cptr);
2180 }
2181 if ((child != NULL) && !term) {
2182 free_children(child);
2183 }
2184
2185 if (tar_chdir(parent) < 0) {
2186 vperror(0, gettext("cannot change back?: %s"), parent);
2187 }
2188
2189 break;
2190
2191 case S_IFLNK:
2192 readlink_max = NAMSIZ;
2193 if (stbuf.st_size > NAMSIZ) {
2194 if (Eflag > 0) {
2195 xhdr_flgs |= _X_LINKPATH;
2196 readlink_max = PATH_MAX;
2197 } else {
2198 (void) fprintf(stderr, gettext(
2199 "tar: %s: symbolic link too long\n"),
2200 longname);
2201 if (errflag)
2202 exitflag = 1;
2203 Errflg = 1;
2204 goto out;
2205 }
2206 }
2207 /*
2208 * Sym-links need header size of zero since you
2209 * don't store any data for this type.
2210 */
2211 stbuf.st_size = (off_t)0;
2212 tomodes(&stbuf);
2213 i = readlink(shortname, filetmp, readlink_max);
2214 if (i < 0) {
2215 vperror(0, gettext(
2216 "can't read symbolic link %s"), longname);
2217 goto out;
2218 } else {
2219 filetmp[i] = 0;
2220 }
2221 if (vflag)
2222 (void) fprintf(vfile, gettext(
2223 "a %s symbolic link to %s\n"),
2224 longname, filetmp);
2225 if (xhdr_flgs & _X_LINKPATH) {
2226 Xtarhdr.x_linkpath = filetmp;
2227 if (build_dblock(name, tchar, '2', filetype, &stbuf,
2228 stbuf.st_dev, prefix) != 0)
2229 goto out;
2230 } else
2231 if (build_dblock(name, filetmp, '2', filetype, &stbuf,
2232 stbuf.st_dev, prefix) != 0)
2233 goto out;
2234 (void) writetbuf((char *)&dblock, 1);
2235 /*
2236 * No acls for symlinks: mode is always 777
2237 * dont call write ancillary
2238 */
2239 rc = PUT_AS_LINK;
2240 break;
2241 case S_IFREG:
2242 if ((infile = openat(dirfd, shortname, 0)) < 0) {
2243 vperror(0, gettext("unable to open %s%s%s%s"), longname,
2244 rw_sysattr ? gettext(" system") : "",
2245 (filetype == XATTR_FILE) ?
2246 gettext(" attribute ") : "",
2247 (filetype == XATTR_FILE) ? (longattrname == NULL) ?
2248 shortname : longattrname : "");
2249 goto out;
2250 }
2251
2252 blocks = TBLOCKS(stbuf.st_size);
2253
2254 if (put_link(name, longname, shortname, longattrname,
2255 prefix, filetype, '1') == 0) {
2256 (void) close(infile);
2257 rc = PUT_AS_LINK;
2258 goto out;
2259 }
2260
2261 tomodes(&stbuf);
2262
2263 /* correctly handle end of volume */
2264 while (mulvol && tapepos + blocks + 1 > blocklim) {
2265 /* split if floppy has some room and file is large */
2266 if (((blocklim - tapepos) >= EXTMIN) &&
2267 ((blocks + 1) >= blocklim/10)) {
2268 splitfile(longname, infile,
2269 name, prefix, filetype);
2270 (void) close(dirfd);
2271 (void) close(infile);
2272 goto out;
2273 }
2274 newvol(); /* not worth it--just get new volume */
2275 }
2276 #ifdef DEBUG
2277 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2278 blocks);
2279 #endif
2280 if (build_dblock(name, tchar, '0', filetype,
2281 &stbuf, stbuf.st_dev, prefix) != 0) {
2282 goto out;
2283 }
2284 if (vflag) {
2285 #ifdef DEBUG
2286 if (NotTape)
2287 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2288 0);
2289 #endif
2290 (void) fprintf(vfile, "a %s%s%s%s ", longname,
2291 rw_sysattr ? gettext(" system") : "",
2292 (filetype == XATTR_FILE) ? gettext(
2293 " attribute ") : "",
2294 (filetype == XATTR_FILE) ?
2295 longattrname : "");
2296 if (NotTape)
2297 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2298 K(blocks));
2299 else
2300 (void) fprintf(vfile,
2301 gettext("%" FMT_blkcnt_t " tape blocks\n"),
2302 blocks);
2303 }
2304
2305 if (put_extra_attributes(longname, shortname, longattrname,
2306 prefix, filetype, '0') != 0)
2307 goto out;
2308
2309 /*
2310 * No need to reset typeflag for extended attribute here, since
2311 * put_extra_attributes already set it and we haven't called
2312 * build_dblock().
2313 */
2314 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2315 hint = writetbuf((char *)&dblock, 1);
2316 maxread = max(min(stbuf.st_blksize, stbuf.st_size),
2317 (nblock * TBLOCK));
2318 if ((bigbuf = calloc((unsigned)maxread, sizeof (char))) == 0) {
2319 maxread = TBLOCK;
2320 bigbuf = buf;
2321 }
2322
2323 while (((i = (int)
2324 read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0) &&
2325 blocks) {
2326 blkcnt_t nblks;
2327
2328 nblks = ((i-1)/TBLOCK)+1;
2329 if (nblks > blocks)
2330 nblks = blocks;
2331 hint = writetbuf(bigbuf, nblks);
2332 blocks -= nblks;
2333 }
2334 (void) close(infile);
2335 if (bigbuf != buf)
2336 free(bigbuf);
2337 if (i < 0)
2338 vperror(0, gettext("Read error on %s"), longname);
2339 else if (blocks != 0 || i != 0) {
2340 (void) fprintf(stderr, gettext(
2341 "tar: %s: file changed size\n"), longname);
2342 if (errflag) {
2343 exitflag = 1;
2344 Errflg = 1;
2345 } else if (!Dflag) {
2346 Errflg = 1;
2347 }
2348 }
2349 putempty(blocks);
2350 break;
2351 case S_IFIFO:
2352 blocks = TBLOCKS(stbuf.st_size);
2353 stbuf.st_size = (off_t)0;
2354
2355 if (put_link(name, longname, shortname, longattrname,
2356 prefix, filetype, '6') == 0) {
2357 rc = PUT_AS_LINK;
2358 goto out;
2359 }
2360 tomodes(&stbuf);
2361
2362 while (mulvol && tapepos + blocks + 1 > blocklim) {
2363 if (((blocklim - tapepos) >= EXTMIN) &&
2364 ((blocks + 1) >= blocklim/10)) {
2365 splitfile(longname, infile, name,
2366 prefix, filetype);
2367 (void) close(dirfd);
2368 (void) close(infile);
2369 goto out;
2370 }
2371 newvol();
2372 }
2373 #ifdef DEBUG
2374 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2375 blocks);
2376 #endif
2377 if (vflag) {
2378 #ifdef DEBUG
2379 if (NotTape)
2380 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2381 0);
2382 #endif
2383 if (NotTape)
2384 (void) fprintf(vfile, gettext("a %s %"
2385 FMT_blkcnt_t "K\n "), longname, K(blocks));
2386 else
2387 (void) fprintf(vfile, gettext(
2388 "a %s %" FMT_blkcnt_t " tape blocks\n"),
2389 longname, blocks);
2390 }
2391 if (build_dblock(name, tchar, '6', filetype,
2392 &stbuf, stbuf.st_dev, prefix) != 0)
2393 goto out;
2394
2395 if (put_extra_attributes(longname, shortname, longattrname,
2396 prefix, filetype, '6') != 0)
2397 goto out;
2398
2399 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2400 dblock.dbuf.typeflag = '6';
2401
2402 (void) writetbuf((char *)&dblock, 1);
2403 break;
2404 case S_IFCHR:
2405 stbuf.st_size = (off_t)0;
2406 blocks = TBLOCKS(stbuf.st_size);
2407 if (put_link(name, longname, shortname, longattrname,
2408 prefix, filetype, '3') == 0) {
2409 rc = PUT_AS_LINK;
2410 goto out;
2411 }
2412 tomodes(&stbuf);
2413
2414 while (mulvol && tapepos + blocks + 1 > blocklim) {
2415 if (((blocklim - tapepos) >= EXTMIN) &&
2416 ((blocks + 1) >= blocklim/10)) {
2417 splitfile(longname, infile, name,
2418 prefix, filetype);
2419 (void) close(dirfd);
2420 goto out;
2421 }
2422 newvol();
2423 }
2424 #ifdef DEBUG
2425 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2426 blocks);
2427 #endif
2428 if (vflag) {
2429 #ifdef DEBUG
2430 if (NotTape)
2431 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2432 0);
2433 #endif
2434 if (NotTape)
2435 (void) fprintf(vfile, gettext("a %s %"
2436 FMT_blkcnt_t "K\n"), longname, K(blocks));
2437 else
2438 (void) fprintf(vfile, gettext("a %s %"
2439 FMT_blkcnt_t " tape blocks\n"), longname,
2440 blocks);
2441 }
2442 if (build_dblock(name, tchar, '3',
2443 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2444 goto out;
2445
2446 if (put_extra_attributes(longname, shortname, longattrname,
2447 prefix, filetype, '3') != 0)
2448 goto out;
2449
2450 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2451 dblock.dbuf.typeflag = '3';
2452
2453 (void) writetbuf((char *)&dblock, 1);
2454 break;
2455 case S_IFBLK:
2456 stbuf.st_size = (off_t)0;
2457 blocks = TBLOCKS(stbuf.st_size);
2458 if (put_link(name, longname, shortname, longattrname,
2459 prefix, filetype, '4') == 0) {
2460 rc = PUT_AS_LINK;
2461 goto out;
2462 }
2463 tomodes(&stbuf);
2464
2465 while (mulvol && tapepos + blocks + 1 > blocklim) {
2466 if (((blocklim - tapepos) >= EXTMIN) &&
2467 ((blocks + 1) >= blocklim/10)) {
2468 splitfile(longname, infile,
2469 name, prefix, filetype);
2470 (void) close(dirfd);
2471 goto out;
2472 }
2473 newvol();
2474 }
2475 #ifdef DEBUG
2476 DEBUG("putfile: %s wants %" FMT_blkcnt_t " blocks\n", longname,
2477 blocks);
2478 #endif
2479 if (vflag) {
2480 #ifdef DEBUG
2481 if (NotTape)
2482 DEBUG("seek = %" FMT_blkcnt_t "K\t", K(tapepos),
2483 0);
2484 #endif
2485 (void) fprintf(vfile, "a %s ", longname);
2486 if (NotTape)
2487 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
2488 K(blocks));
2489 else
2490 (void) fprintf(vfile, gettext("%"
2491 FMT_blkcnt_t " tape blocks\n"), blocks);
2492 }
2493 if (build_dblock(name, tchar, '4',
2494 filetype, &stbuf, stbuf.st_rdev, prefix) != 0)
2495 goto out;
2496
2497 if (put_extra_attributes(longname, shortname, longattrname,
2498 prefix, filetype, '4') != 0)
2499 goto out;
2500
2501 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2502 dblock.dbuf.typeflag = '4';
2503
2504 (void) writetbuf((char *)&dblock, 1);
2505 break;
2506 default:
2507 (void) fprintf(stderr, gettext(
2508 "tar: %s is not a file. Not dumped\n"), longname);
2509 if (errflag)
2510 exitflag = 1;
2511 Errflg = 1;
2512 goto out;
2513 }
2514
2515 out:
2516 if ((dirfd != -1) && (filetype != XATTR_FILE)) {
2517 (void) close(dirfd);
2518 }
2519 return (rc);
2520 }
2521
2522
2523 /*
2524 * splitfile dump a large file across volumes
2525 *
2526 * splitfile(longname, fd);
2527 * char *longname; full name of file
2528 * int ifd; input file descriptor
2529 *
2530 * NOTE: only called by putfile() to dump a large file.
2531 */
2532
2533 static void
2534 splitfile(char *longname, int ifd, char *name, char *prefix, int filetype)
2535 {
2536 blkcnt_t blocks;
2537 off_t bytes, s;
2538 char buf[TBLOCK];
2539 int i, extents;
2540
2541 blocks = TBLOCKS(stbuf.st_size); /* blocks file needs */
2542
2543 /*
2544 * # extents =
2545 * size of file after using up rest of this floppy
2546 * blocks - (blocklim - tapepos) + 1 (for header)
2547 * plus roundup value before divide by blocklim-1
2548 * + (blocklim - 1) - 1
2549 * all divided by blocklim-1 (one block for each header).
2550 * this gives
2551 * (blocks - blocklim + tapepos + 1 + blocklim - 2)/(blocklim-1)
2552 * which reduces to the expression used.
2553 * one is added to account for this first extent.
2554 *
2555 * When one is dealing with extremely large archives, one may want
2556 * to allow for a large number of extents. This code should be
2557 * revisited to determine if extents should be changed to something
2558 * larger than an int.
2559 */
2560 extents = (int)((blocks + tapepos - 1ULL)/(blocklim - 1ULL) + 1);
2561
2562 if (extents < 2 || extents > MAXEXT) { /* let's be reasonable */
2563 (void) fprintf(stderr, gettext(
2564 "tar: %s needs unusual number of volumes to split\n"
2565 "tar: %s not dumped\n"), longname, longname);
2566 return;
2567 }
2568 if (build_dblock(name, tchar, '0', filetype,
2569 &stbuf, stbuf.st_dev, prefix) != 0)
2570 return;
2571
2572 dblock.dbuf.extotal = extents;
2573 bytes = stbuf.st_size;
2574
2575 /*
2576 * The value contained in dblock.dbuf.efsize was formerly used when the
2577 * v flag was specified in conjunction with the t flag. Although it is
2578 * no longer used, older versions of tar will expect the former
2579 * behaviour, so we must continue to write it to the archive.
2580 *
2581 * Since dblock.dbuf.efsize is 10 chars in size, the maximum value it
2582 * can store is TAR_EFSIZE_MAX. If bytes exceeds that value, simply
2583 * store 0.
2584 */
2585 if (bytes <= TAR_EFSIZE_MAX)
2586 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, bytes);
2587 else
2588 (void) sprintf(dblock.dbuf.efsize, "%9" FMT_off_t_o, (off_t)0);
2589
2590 (void) fprintf(stderr, gettext(
2591 "tar: large file %s needs %d extents.\n"
2592 "tar: current device seek position = %" FMT_blkcnt_t "K\n"),
2593 longname, extents, K(tapepos));
2594
2595 s = (off_t)(blocklim - tapepos - 1) * TBLOCK;
2596 for (i = 1; i <= extents; i++) {
2597 if (i > 1) {
2598 newvol();
2599 if (i == extents)
2600 s = bytes; /* last ext. gets true bytes */
2601 else
2602 s = (off_t)(blocklim - 1)*TBLOCK; /* all */
2603 }
2604 bytes -= s;
2605 blocks = TBLOCKS(s);
2606
2607 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o, s);
2608 dblock.dbuf.extno = i;
2609 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
2610 (void) writetbuf((char *)&dblock, 1);
2611
2612 if (vflag)
2613 (void) fprintf(vfile,
2614 gettext("+++ a %s %" FMT_blkcnt_t
2615 "K [extent #%d of %d]\n"),
2616 longname, K(blocks), i, extents);
2617 while (blocks && read(ifd, buf, TBLOCK) > 0) {
2618 blocks--;
2619 (void) writetbuf(buf, 1);
2620 }
2621 if (blocks != 0) {
2622 (void) fprintf(stderr, gettext(
2623 "tar: %s: file changed size\n"), longname);
2624 (void) fprintf(stderr, gettext(
2625 "tar: aborting split file %s\n"), longname);
2626 (void) close(ifd);
2627 return;
2628 }
2629 }
2630 (void) close(ifd);
2631 if (vflag)
2632 (void) fprintf(vfile, gettext("a %s %" FMT_off_t "K (in %d "
2633 "extents)\n"), longname, K(TBLOCKS(stbuf.st_size)),
2634 extents);
2635 }
2636
2637 /*
2638 * convtoreg - determines whether the file should be converted to a
2639 * regular file when extracted
2640 *
2641 * Returns 1 when file size > 0 and typeflag is not recognized
2642 * Otherwise returns 0
2643 */
2644 static int
2645 convtoreg(off_t size)
2646 {
2647 if ((size > 0) && (dblock.dbuf.typeflag != '0') &&
2648 (dblock.dbuf.typeflag != NULL) && (dblock.dbuf.typeflag != '1') &&
2649 (dblock.dbuf.typeflag != '2') && (dblock.dbuf.typeflag != '3') &&
2650 (dblock.dbuf.typeflag != '4') && (dblock.dbuf.typeflag != '5') &&
2651 (dblock.dbuf.typeflag != '6') && (dblock.dbuf.typeflag != 'A') &&
2652 (dblock.dbuf.typeflag != 'L') &&
2653 (dblock.dbuf.typeflag != _XATTR_HDRTYPE) &&
2654 (dblock.dbuf.typeflag != 'X')) {
2655 return (1);
2656 }
2657 return (0);
2658 }
2659
2660 #if defined(O_XATTR)
2661 static int
2662 save_cwd(void)
2663 {
2664 return (open(".", O_RDONLY));
2665 }
2666 #endif
2667
2668 #if defined(O_XATTR)
2669 static void
2670 rest_cwd(int *cwd)
2671 {
2672 if (*cwd != -1) {
2673 if (fchdir(*cwd) < 0) {
2674 vperror(0, gettext(
2675 "Cannot fchdir to attribute directory"));
2676 exit(1);
2677 }
2678 (void) close(*cwd);
2679 *cwd = -1;
2680 }
2681 }
2682 #endif
2683
2684 /*
2685 * Verify the underlying file system supports the attribute type.
2686 * Only archive extended attribute files when '-@' was specified.
2687 * Only archive system extended attribute files if '-/' was specified.
2688 */
2689 #if defined(O_XATTR)
2690 static attr_status_t
2691 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
2692 int *ext_attrflg)
2693 {
2694 /*
2695 * Verify extended attributes are supported/exist. We only
2696 * need to check if we are processing a base file, not an
2697 * extended attribute.
2698 */
2699 if (attrflg) {
2700 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
2701 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
2702 }
2703
2704 if (atflag) {
2705 if (!*ext_attrflg) {
2706 #if defined(_PC_SATTR_ENABLED)
2707 if (saflag) {
2708 /* Verify system attributes are supported */
2709 if (sysattr_support(filename,
2710 (actflag == ARC_CREATE) ? _PC_SATTR_EXISTS :
2711 _PC_SATTR_ENABLED) != 1) {
2712 return (ATTR_SATTR_ERR);
2713 }
2714 } else
2715 return (ATTR_XATTR_ERR);
2716 #else
2717 return (ATTR_XATTR_ERR);
2718 #endif /* _PC_SATTR_ENABLED */
2719 }
2720
2721 #if defined(_PC_SATTR_ENABLED)
2722 } else if (saflag) {
2723 /* Verify system attributes are supported */
2724 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
2725 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
2726 return (ATTR_SATTR_ERR);
2727 }
2728 #endif /* _PC_SATTR_ENABLED */
2729 } else {
2730 return (ATTR_SKIP);
2731 }
2732
2733 return (ATTR_OK);
2734 }
2735 #endif
2736
2737 #if defined(O_XATTR)
2738 /*
2739 * Recursively open attribute directories until the attribute directory
2740 * containing the specified attribute, attrname, is opened.
2741 *
2742 * Currently, only 2 directory levels of attributes are supported, (i.e.,
2743 * extended system attributes on extended attributes). The following are
2744 * the possible input combinations:
2745 * 1. Open the attribute directory of the base file (don't change
2746 * into it).
2747 * attrinfo->parent = NULL
2748 * attrname = '.'
2749 * 2. Open the attribute directory of the base file and change into it.
2750 * attrinfo->parent = NULL
2751 * attrname = <attr> | <sys_attr>
2752 * 3. Open the attribute directory of the base file, change into it,
2753 * then recursively call open_attr_dir() to open the attribute's
2754 * parent directory (don't change into it).
2755 * attrinfo->parent = <attr>
2756 * attrname = '.'
2757 * 4. Open the attribute directory of the base file, change into it,
2758 * then recursively call open_attr_dir() to open the attribute's
2759 * parent directory and change into it.
2760 * attrinfo->parent = <attr>
2761 * attrname = <attr> | <sys_attr>
2762 *
2763 * An attribute directory will be opened only if the underlying file system
2764 * supports the attribute type, and if the command line specifications (atflag
2765 * and saflag) enable the processing of the attribute type.
2766 *
2767 * On succesful return, attrinfo->parentfd will be the file descriptor of the
2768 * opened attribute directory. In addition, if the attribute is a read-write
2769 * extended system attribute, attrinfo->rw_sysattr will be set to 1, otherwise
2770 * it will be set to 0.
2771 *
2772 * Possible return values:
2773 * ATTR_OK Successfully opened and, if needed, changed into the
2774 * attribute directory containing attrname.
2775 * ATTR_SKIP The command line specifications don't enable the
2776 * processing of the attribute type.
2777 * ATTR_CHDIR_ERR An error occurred while trying to change into an
2778 * attribute directory.
2779 * ATTR_OPEN_ERR An error occurred while trying to open an
2780 * attribute directory.
2781 * ATTR_XATTR_ERR The underlying file system doesn't support extended
2782 * attributes.
2783 * ATTR_SATTR_ERR The underlying file system doesn't support extended
2784 * system attributes.
2785 */
2786 static int
2787 open_attr_dir(char *attrname, char *dirp, int cwd, attr_data_t *attrinfo)
2788 {
2789 attr_status_t rc;
2790 int firsttime = (attrinfo->attr_parentfd == -1);
2791 int saveerrno;
2792 int ext_attr;
2793
2794 /*
2795 * open_attr_dir() was recursively called (input combination number 4),
2796 * close the previously opened file descriptor as we've already changed
2797 * into it.
2798 */
2799 if (!firsttime) {
2800 (void) close(attrinfo->attr_parentfd);
2801 attrinfo->attr_parentfd = -1;
2802 }
2803
2804 /*
2805 * Verify that the underlying file system supports the restoration
2806 * of the attribute.
2807 */
2808 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
2809 &ext_attr)) != ATTR_OK) {
2810 return (rc);
2811 }
2812
2813 /* Open the base file's attribute directory */
2814 if ((attrinfo->attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
2815 /*
2816 * Save the errno from the attropen so it can be reported
2817 * if the retry of the attropen fails.
2818 */
2819 saveerrno = errno;
2820 if ((attrinfo->attr_parentfd = retry_open_attr(-1, cwd, dirp,
2821 NULL, ".", O_RDONLY, 0)) == -1) {
2822 /*
2823 * Reset typeflag back to real value so passtape
2824 * will skip ahead correctly.
2825 */
2826 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
2827 (void) close(attrinfo->attr_parentfd);
2828 attrinfo->attr_parentfd = -1;
2829 errno = saveerrno;
2830 return (ATTR_OPEN_ERR);
2831 }
2832 }
2833
2834 /*
2835 * Change into the parent attribute's directory unless we are
2836 * processing the hidden attribute directory of the base file itself.
2837 */
2838 if ((Hiddendir == 0) || (firsttime && attrinfo->attr_parent != NULL)) {
2839 if (fchdir(attrinfo->attr_parentfd) != 0) {
2840 saveerrno = errno;
2841 (void) close(attrinfo->attr_parentfd);
2842 attrinfo->attr_parentfd = -1;
2843 errno = saveerrno;
2844 return (ATTR_CHDIR_ERR);
2845 }
2846 }
2847
2848 /* Determine if the attribute should be processed */
2849 if ((rc = verify_attr(attrname, attrinfo->attr_parent, 1,
2850 &attrinfo->attr_rw_sysattr)) != ATTR_OK) {
2851 saveerrno = errno;
2852 (void) close(attrinfo->attr_parentfd);
2853 attrinfo->attr_parentfd = -1;
2854 errno = saveerrno;
2855 return (rc);
2856 }
2857
2858 /*
2859 * If the attribute is an extended attribute, or extended system
2860 * attribute, of an attribute (i.e., <attr>/<sys_attr>), then
2861 * recursively call open_attr_dir() to open the attribute directory
2862 * of the parent attribute.
2863 */
2864 if (firsttime && (attrinfo->attr_parent != NULL)) {
2865 return (open_attr_dir(attrname, attrinfo->attr_parent,
2866 attrinfo->attr_parentfd, attrinfo));
2867 }
2868
2869 return (ATTR_OK);
2870 }
2871 #endif
2872
2873 static void
2874 doxtract(char *argv[])
2875 {
2876 struct stat xtractbuf; /* stat on file after extracting */
2877 blkcnt_t blocks;
2878 off_t bytes;
2879 int ofile;
2880 int newfile; /* Does the file already exist */
2881 int xcnt = 0; /* count # files extracted */
2882 int fcnt = 0; /* count # files in argv list */
2883 int dir;
2884 int dirfd = -1;
2885 int cwd = -1;
2886 int rw_sysattr;
2887 int saveerrno;
2888 uid_t Uid;
2889 char *namep, *dirp, *comp, *linkp; /* for removing absolute paths */
2890 char dirname[PATH_MAX+1];
2891 char templink[PATH_MAX+1]; /* temp link with terminating NULL */
2892 int once = 1;
2893 int error;
2894 int symflag;
2895 int want;
2896 attr_data_t *attrinfo = NULL; /* attribute info */
2897 acl_t *aclp = NULL; /* acl info */
2898 char dot[] = "."; /* dirp for using realpath */
2899 timestruc_t time_zero; /* used for call to doDirTimes */
2900 int dircreate;
2901 int convflag;
2902 time_zero.tv_sec = 0;
2903 time_zero.tv_nsec = 0;
2904
2905 /* reset Trusted Extensions variables */
2906 rpath_flag = 0;
2907 lk_rpath_flag = 0;
2908 dir_flag = 0;
2909 mld_flag = 0;
2910 bslundef(&bs_label);
2911 bsllow(&admin_low);
2912 bslhigh(&admin_high);
2913 orig_namep = 0;
2914
2915 dumping = 0; /* for newvol(), et al: we are not writing */
2916
2917 Uid = getuid();
2918
2919 for (;;) {
2920 convflag = 0;
2921 symflag = 0;
2922 dir = 0;
2923 Hiddendir = 0;
2924 rw_sysattr = 0;
2925 ofile = -1;
2926
2927 if (dirfd != -1) {
2928 (void) close(dirfd);
2929 dirfd = -1;
2930 }
2931 if (ofile != -1) {
2932 if (close(ofile) != 0)
2933 vperror(2, gettext("close error"));
2934 }
2935
2936 #if defined(O_XATTR)
2937 if (cwd != -1) {
2938 rest_cwd(&cwd);
2939 }
2940 #endif
2941
2942 /* namep is set by wantit to point to the full name */
2943 if ((want = wantit(argv, &namep, &dirp, &comp,
2944 &attrinfo)) == 0) {
2945 #if defined(O_XATTR)
2946 if (xattrp != NULL) {
2947 free(xattrhead);
2948 xattrp = NULL;
2949 xattr_linkp = NULL;
2950 xattrhead = NULL;
2951 }
2952 #endif
2953 continue;
2954 }
2955 if (want == -1)
2956 break;
2957
2958 /* Trusted Extensions */
2959 /*
2960 * During tar extract (x):
2961 * If the pathname of the restored file has been
2962 * reconstructed from the ancillary file,
2963 * use it to process the normal file.
2964 */
2965 if (mld_flag) { /* Skip over .MLD. directory */
2966 mld_flag = 0;
2967 passtape();
2968 continue;
2969 }
2970 orig_namep = namep; /* save original */
2971 if (rpath_flag) {
2972 namep = real_path; /* use zone path */
2973 comp = real_path; /* use zone path */
2974 dirp = dot; /* work from the top */
2975 rpath_flag = 0; /* reset */
2976 }
2977
2978 if (dirfd != -1)
2979 (void) close(dirfd);
2980
2981 (void) strcpy(&dirname[0], namep);
2982 dircreate = checkdir(&dirname[0]);
2983
2984 #if defined(O_XATTR)
2985 if (xattrp != NULL) {
2986 int rc;
2987
2988 if (((cwd = save_cwd()) == -1) ||
2989 ((rc = open_attr_dir(comp, dirp, cwd,
2990 attrinfo)) != ATTR_OK)) {
2991 if (cwd == -1) {
2992 vperror(0, gettext(
2993 "unable to save current working "
2994 "directory while processing "
2995 "attribute %s of %s"),
2996 dirp, attrinfo->attr_path);
2997 } else if (rc != ATTR_SKIP) {
2998 (void) fprintf(vfile,
2999 gettext("tar: cannot open "
3000 "%sattribute %s of file %s: %s\n"),
3001 attrinfo->attr_rw_sysattr ? gettext(
3002 "system ") : "",
3003 comp, dirp, strerror(errno));
3004 }
3005 free(xattrhead);
3006 xattrp = NULL;
3007 xattr_linkp = NULL;
3008 xattrhead = NULL;
3009
3010 passtape();
3011 continue;
3012 } else {
3013 dirfd = attrinfo->attr_parentfd;
3014 rw_sysattr = attrinfo->attr_rw_sysattr;
3015 }
3016 } else {
3017 dirfd = open(dirp, O_RDONLY);
3018 }
3019 #else
3020 dirfd = open(dirp, O_RDONLY);
3021 #endif
3022 if (dirfd == -1) {
3023 (void) fprintf(vfile, gettext(
3024 "tar: cannot open %s: %s\n"),
3025 dirp, strerror(errno));
3026 passtape();
3027 continue;
3028 }
3029
3030 if (xhdr_flgs & _X_LINKPATH)
3031 (void) strcpy(templink, Xtarhdr.x_linkpath);
3032 else {
3033 #if defined(O_XATTR)
3034 if (xattrp && dblock.dbuf.typeflag == '1') {
3035 (void) sprintf(templink, "%.*s", NAMSIZ,
3036 xattrp->h_names);
3037 } else {
3038 (void) sprintf(templink, "%.*s", NAMSIZ,
3039 dblock.dbuf.linkname);
3040 }
3041 #else
3042 (void) sprintf(templink, "%.*s", NAMSIZ,
3043 dblock.dbuf.linkname);
3044 #endif
3045 }
3046
3047 if (Fflag) {
3048 if (checkf(namep, is_directory(namep), Fflag) == 0) {
3049 passtape();
3050 continue;
3051 }
3052 }
3053
3054 if (checkw('x', namep) == 0) {
3055 passtape();
3056 continue;
3057 }
3058 if (once) {
3059 if (strcmp(dblock.dbuf.magic, magic_type) == 0) {
3060 if (geteuid() == (uid_t)0) {
3061 checkflag = 1;
3062 pflag = 1;
3063 } else {
3064 /* get file creation mask */
3065 Oumask = umask(0);
3066 (void) umask(Oumask);
3067 }
3068 once = 0;
3069 } else {
3070 if (geteuid() == (uid_t)0) {
3071 pflag = 1;
3072 checkflag = 2;
3073 }
3074 if (!pflag) {
3075 /* get file creation mask */
3076 Oumask = umask(0);
3077 (void) umask(Oumask);
3078 }
3079 once = 0;
3080 }
3081 }
3082
3083 #if defined(O_XATTR)
3084 /*
3085 * Handle extraction of hidden attr dir.
3086 * Dir is automatically created, we only
3087 * need to update mode and perm's.
3088 */
3089 if ((xattrp != NULL) && Hiddendir == 1) {
3090 bytes = stbuf.st_size;
3091 blocks = TBLOCKS(bytes);
3092 if (vflag) {
3093 (void) fprintf(vfile,
3094 "x %s%s%s, %" FMT_off_t " %s, ", namep,
3095 gettext(" attribute "),
3096 xattrapath, bytes,
3097 gettext("bytes"));
3098 if (NotTape)
3099 (void) fprintf(vfile,
3100 "%" FMT_blkcnt_t "K\n", K(blocks));
3101 else
3102 (void) fprintf(vfile, gettext("%"
3103 FMT_blkcnt_t " tape blocks\n"),
3104 blocks);
3105 }
3106
3107 /*
3108 * Set the permissions and mode of the attribute
3109 * unless the attribute is a system attribute (can't
3110 * successfully do this) or the hidden attribute
3111 * directory (".") of an attribute (when the attribute
3112 * is restored, the hidden attribute directory of an
3113 * attribute is transient). Note: when the permissions
3114 * and mode are set for the hidden attribute directory
3115 * of a file on a system supporting extended system
3116 * attributes, even though it returns successfully, it
3117 * will not have any affect since the attribute
3118 * directory is transient.
3119 */
3120 if (attrinfo->attr_parent == NULL) {
3121 if (fchownat(dirfd, ".", stbuf.st_uid,
3122 stbuf.st_gid, 0) != 0) {
3123 vperror(0, gettext(
3124 "%s%s%s: failed to set ownership "
3125 "of attribute directory"), namep,
3126 gettext(" attribute "), xattrapath);
3127 }
3128
3129 if (fchmod(dirfd, stbuf.st_mode) != 0) {
3130 vperror(0, gettext(
3131 "%s%s%s: failed to set permissions "
3132 "of attribute directory"), namep,
3133 gettext(" attribute "), xattrapath);
3134 }
3135 }
3136 goto filedone;
3137 }
3138 #endif
3139
3140 if (dircreate && (!is_posix || dblock.dbuf.typeflag == '5')) {
3141 dir = 1;
3142 if (vflag) {
3143 (void) fprintf(vfile, "x %s, 0 %s, ",
3144 &dirname[0], gettext("bytes"));
3145 if (NotTape)
3146 (void) fprintf(vfile, "0K\n");
3147 else
3148 (void) fprintf(vfile, gettext("%"
3149 FMT_blkcnt_t " tape blocks\n"),
3150 (blkcnt_t)0);
3151 }
3152 goto filedone;
3153 }
3154
3155 if (dblock.dbuf.typeflag == '6') { /* FIFO */
3156 if (rmdir(namep) < 0) {
3157 if (errno == ENOTDIR)
3158 (void) unlink(namep);
3159 }
3160 linkp = templink;
3161 if (*linkp != NULL) {
3162 if (Aflag && *linkp == '/')
3163 linkp++;
3164 if (link(linkp, namep) < 0) {
3165 (void) fprintf(stderr, gettext(
3166 "tar: %s: cannot link\n"), namep);
3167 continue;
3168 }
3169 if (vflag)
3170 (void) fprintf(vfile, gettext(
3171 "x %s linked to %s\n"), namep,
3172 linkp);
3173 xcnt++; /* increment # files extracted */
3174 continue;
3175 }
3176 if (mknod(namep, (int)(Gen.g_mode|S_IFIFO),
3177 (int)Gen.g_devmajor) < 0) {
3178 vperror(0, gettext("%s: mknod failed"), namep);
3179 continue;
3180 }
3181 bytes = stbuf.st_size;
3182 blocks = TBLOCKS(bytes);
3183 if (vflag) {
3184 (void) fprintf(vfile, "x %s, %" FMT_off_t
3185 " %s, ", namep, bytes, gettext("bytes"));
3186 if (NotTape)
3187 (void) fprintf(vfile, "%" FMT_blkcnt_t
3188 "K\n", K(blocks));
3189 else
3190 (void) fprintf(vfile, gettext("%"
3191 FMT_blkcnt_t " tape blocks\n"),
3192 blocks);
3193 }
3194 goto filedone;
3195 }
3196 if (dblock.dbuf.typeflag == '3' && !Uid) { /* CHAR SPECIAL */
3197 if (rmdir(namep) < 0) {
3198 if (errno == ENOTDIR)
3199 (void) unlink(namep);
3200 }
3201 linkp = templink;
3202 if (*linkp != NULL) {
3203 if (Aflag && *linkp == '/')
3204 linkp++;
3205 if (link(linkp, namep) < 0) {
3206 (void) fprintf(stderr, gettext(
3207 "tar: %s: cannot link\n"), namep);
3208 continue;
3209 }
3210 if (vflag)
3211 (void) fprintf(vfile, gettext(
3212 "x %s linked to %s\n"), namep,
3213 linkp);
3214 xcnt++; /* increment # files extracted */
3215 continue;
3216 }
3217 if (mknod(namep, (int)(Gen.g_mode|S_IFCHR),
3218 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3219 vperror(0, gettext(
3220 "%s: mknod failed"), namep);
3221 continue;
3222 }
3223 bytes = stbuf.st_size;
3224 blocks = TBLOCKS(bytes);
3225 if (vflag) {
3226 (void) fprintf(vfile, "x %s, %" FMT_off_t
3227 " %s, ", namep, bytes, gettext("bytes"));
3228 if (NotTape)
3229 (void) fprintf(vfile, "%" FMT_blkcnt_t
3230 "K\n", K(blocks));
3231 else
3232 (void) fprintf(vfile, gettext("%"
3233 FMT_blkcnt_t " tape blocks\n"),
3234 blocks);
3235 }
3236 goto filedone;
3237 } else if (dblock.dbuf.typeflag == '3' && Uid) {
3238 (void) fprintf(stderr, gettext(
3239 "Can't create special %s\n"), namep);
3240 continue;
3241 }
3242
3243 /* BLOCK SPECIAL */
3244
3245 if (dblock.dbuf.typeflag == '4' && !Uid) {
3246 if (rmdir(namep) < 0) {
3247 if (errno == ENOTDIR)
3248 (void) unlink(namep);
3249 }
3250 linkp = templink;
3251 if (*linkp != NULL) {
3252 if (Aflag && *linkp == '/')
3253 linkp++;
3254 if (link(linkp, namep) < 0) {
3255 (void) fprintf(stderr, gettext(
3256 "tar: %s: cannot link\n"), namep);
3257 continue;
3258 }
3259 if (vflag)
3260 (void) fprintf(vfile, gettext(
3261 "x %s linked to %s\n"), namep,
3262 linkp);
3263 xcnt++; /* increment # files extracted */
3264 continue;
3265 }
3266 if (mknod(namep, (int)(Gen.g_mode|S_IFBLK),
3267 (int)makedev(Gen.g_devmajor, Gen.g_devminor)) < 0) {
3268 vperror(0, gettext("%s: mknod failed"), namep);
3269 continue;
3270 }
3271 bytes = stbuf.st_size;
3272 blocks = TBLOCKS(bytes);
3273 if (vflag) {
3274 (void) fprintf(vfile, gettext("x %s, %"
3275 FMT_off_t " bytes, "), namep, bytes);
3276 if (NotTape)
3277 (void) fprintf(vfile, "%" FMT_blkcnt_t
3278 "K\n", K(blocks));
3279 else
3280 (void) fprintf(vfile, gettext("%"
3281 FMT_blkcnt_t " tape blocks\n"),
3282 blocks);
3283 }
3284 goto filedone;
3285 } else if (dblock.dbuf.typeflag == '4' && Uid) {
3286 (void) fprintf(stderr,
3287 gettext("Can't create special %s\n"), namep);
3288 continue;
3289 }
3290 if (dblock.dbuf.typeflag == '2') { /* symlink */
3291 if ((Tflag) && (lk_rpath_flag == 1))
3292 linkp = lk_real_path;
3293 else
3294 linkp = templink;
3295 if (Aflag && *linkp == '/')
3296 linkp++;
3297 if (rmdir(namep) < 0) {
3298 if (errno == ENOTDIR)
3299 (void) unlink(namep);
3300 }
3301 if (symlink(linkp, namep) < 0) {
3302 vperror(0, gettext("%s: symbolic link failed"),
3303 namep);
3304 continue;
3305 }
3306 if (vflag)
3307 (void) fprintf(vfile, gettext(
3308 "x %s symbolic link to %s\n"),
3309 namep, linkp);
3310
3311 symflag = AT_SYMLINK_NOFOLLOW;
3312 goto filedone;
3313 }
3314 if (dblock.dbuf.typeflag == '1') {
3315 linkp = templink;
3316 if (Aflag && *linkp == '/')
3317 linkp++;
3318 if (unlinkat(dirfd, comp, AT_REMOVEDIR) < 0) {
3319 if (errno == ENOTDIR)
3320 (void) unlinkat(dirfd, comp, 0);
3321 }
3322 #if defined(O_XATTR)
3323 if (xattrp && xattr_linkp) {
3324 if (fchdir(dirfd) < 0) {
3325 vperror(0, gettext(
3326 "Cannot fchdir to attribute "
3327 "directory %s"),
3328 (attrinfo->attr_parent == NULL) ?
3329 dirp : attrinfo->attr_parent);
3330 exit(1);
3331 }
3332
3333 error = link(xattr_linkaname, xattrapath);
3334 } else {
3335 error = link(linkp, namep);
3336 }
3337 #else
3338 error = link(linkp, namep);
3339 #endif
3340
3341 if (error < 0) {
3342 (void) fprintf(stderr, gettext(
3343 "tar: %s%s%s: cannot link\n"),
3344 namep, (xattr_linkp != NULL) ?
3345 gettext(" attribute ") : "",
3346 (xattr_linkp != NULL) ?
3347 xattrapath : "");
3348 continue;
3349 }
3350 if (vflag)
3351 (void) fprintf(vfile, gettext(
3352 "x %s%s%s linked to %s%s%s\n"), namep,
3353 (xattr_linkp != NULL) ?
3354 gettext(" attribute ") : "",
3355 (xattr_linkp != NULL) ?
3356 xattr_linkaname : "",
3357 linkp,
3358 (xattr_linkp != NULL) ?
3359 gettext(" attribute ") : "",
3360 (xattr_linkp != NULL) ? xattrapath : "");
3361 xcnt++; /* increment # files extracted */
3362 #if defined(O_XATTR)
3363 if (xattrp != NULL) {
3364 free(xattrhead);
3365 xattrp = NULL;
3366 xattr_linkp = NULL;
3367 xattrhead = NULL;
3368 }
3369 #endif
3370 continue;
3371 }
3372
3373 /* REGULAR FILES */
3374
3375 if (convtoreg(stbuf.st_size)) {
3376 convflag = 1;
3377 if (errflag) {
3378 (void) fprintf(stderr, gettext(
3379 "tar: %s: typeflag '%c' not recognized\n"),
3380 namep, dblock.dbuf.typeflag);
3381 done(1);
3382 } else {
3383 (void) fprintf(stderr, gettext(
3384 "tar: %s: typeflag '%c' not recognized, "
3385 "converting to regular file\n"), namep,
3386 dblock.dbuf.typeflag);
3387 Errflg = 1;
3388 }
3389 }
3390 if (dblock.dbuf.typeflag == '0' ||
3391 dblock.dbuf.typeflag == NULL || convflag) {
3392 delete_target(dirfd, comp, namep);
3393 linkp = templink;
3394 if (*linkp != NULL) {
3395 if (Aflag && *linkp == '/')
3396 linkp++;
3397 if (link(linkp, comp) < 0) {
3398 (void) fprintf(stderr, gettext(
3399 "tar: %s: cannot link\n"), namep);
3400 continue;
3401 }
3402 if (vflag)
3403 (void) fprintf(vfile, gettext(
3404 "x %s linked to %s\n"), comp,
3405 linkp);
3406 xcnt++; /* increment # files extracted */
3407 #if defined(O_XATTR)
3408 if (xattrp != NULL) {
3409 free(xattrhead);
3410 xattrp = NULL;
3411 xattr_linkp = NULL;
3412 xattrhead = NULL;
3413 }
3414 #endif
3415 continue;
3416 }
3417 newfile = ((fstatat(dirfd, comp,
3418 &xtractbuf, 0) == -1) ? TRUE : FALSE);
3419 ofile = openat(dirfd, comp, O_RDWR|O_CREAT|O_TRUNC,
3420 stbuf.st_mode & MODEMASK);
3421 saveerrno = errno;
3422
3423 #if defined(O_XATTR)
3424 if (xattrp != NULL) {
3425 if (ofile < 0) {
3426 ofile = retry_open_attr(dirfd, cwd,
3427 dirp, attrinfo->attr_parent, comp,
3428 O_RDWR|O_CREAT|O_TRUNC,
3429 stbuf.st_mode & MODEMASK);
3430 }
3431 }
3432 #endif
3433 if (ofile < 0) {
3434 errno = saveerrno;
3435 (void) fprintf(stderr, gettext(
3436 "tar: %s%s%s%s - cannot create\n"),
3437 (xattrp == NULL) ? "" : (rw_sysattr ?
3438 gettext("system attribute ") :
3439 gettext("attribute ")),
3440 (xattrp == NULL) ? "" : xattrapath,
3441 (xattrp == NULL) ? "" : gettext(" of "),
3442 (xattrp == NULL) ? comp : namep);
3443 if (errflag)
3444 done(1);
3445 else
3446 Errflg = 1;
3447 #if defined(O_XATTR)
3448 if (xattrp != NULL) {
3449 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
3450 free(xattrhead);
3451 xattrp = NULL;
3452 xattr_linkp = NULL;
3453 xattrhead = NULL;
3454 }
3455 #endif
3456 passtape();
3457 continue;
3458 }
3459
3460 if (Tflag && (check_ext_attr(namep) == 0)) {
3461 if (errflag)
3462 done(1);
3463 else
3464 Errflg = 1;
3465 passtape();
3466 continue;
3467 }
3468
3469 if (extno != 0) { /* file is in pieces */
3470 if (extotal < 1 || extotal > MAXEXT)
3471 (void) fprintf(stderr, gettext(
3472 "tar: ignoring bad extent info for "
3473 "%s%s%s%s\n"),
3474 (xattrp == NULL) ? "" : (rw_sysattr ?
3475 gettext("system attribute ") :
3476 gettext("attribute ")),
3477 (xattrp == NULL) ? "" : xattrapath,
3478 (xattrp == NULL) ? "" : gettext(" of "),
3479 (xattrp == NULL) ? comp : namep);
3480 else {
3481 /* extract it */
3482 (void) xsfile(rw_sysattr, ofile);
3483 }
3484 }
3485 extno = 0; /* let everyone know file is not split */
3486 bytes = stbuf.st_size;
3487 blocks = TBLOCKS(bytes);
3488 if (vflag) {
3489 (void) fprintf(vfile,
3490 "x %s%s%s, %" FMT_off_t " %s, ",
3491 (xattrp == NULL) ? "" : dirp,
3492 (xattrp == NULL) ? "" : (rw_sysattr ?
3493 gettext(" system attribute ") :
3494 gettext(" attribute ")),
3495 (xattrp == NULL) ? namep : xattrapath, bytes,
3496 gettext("bytes"));
3497 if (NotTape)
3498 (void) fprintf(vfile, "%" FMT_blkcnt_t "K\n",
3499 K(blocks));
3500 else
3501 (void) fprintf(vfile, gettext("%"
3502 FMT_blkcnt_t " tape blocks\n"), blocks);
3503 }
3504
3505 if (xblocks(rw_sysattr, bytes, ofile) != 0) {
3506 #if defined(O_XATTR)
3507 if (xattrp != NULL) {
3508 free(xattrhead);
3509 xattrp = NULL;
3510 xattr_linkp = NULL;
3511 xattrhead = NULL;
3512 }
3513 #endif
3514 continue;
3515 }
3516 filedone:
3517 if (mflag == 0 && !symflag) {
3518 if (dir)
3519 doDirTimes(namep, stbuf.st_mtim);
3520
3521 else
3522 #if defined(O_XATTR)
3523 if (xattrp != NULL) {
3524 /*
3525 * Set the time on the attribute unless
3526 * the attribute is a system attribute
3527 * (can't successfully do this) or the
3528 * hidden attribute directory, "." (the
3529 * time on the hidden attribute
3530 * directory will be updated when
3531 * attributes are restored, otherwise
3532 * it's transient).
3533 */
3534 if (!rw_sysattr && (Hiddendir == 0)) {
3535 setPathTimes(dirfd, comp,
3536 stbuf.st_mtim);
3537 }
3538 } else
3539 setPathTimes(dirfd, comp,
3540 stbuf.st_mtim);
3541 #else
3542 setPathTimes(dirfd, comp, stbuf.st_mtim);
3543 #endif
3544 }
3545
3546 /* moved this code from above */
3547 if (pflag && !symflag && Hiddendir == 0) {
3548 if (xattrp != NULL)
3549 (void) fchmod(ofile, stbuf.st_mode & MODEMASK);
3550 else
3551 (void) chmod(namep, stbuf.st_mode & MODEMASK);
3552 }
3553
3554
3555 /*
3556 * Because ancillary file preceeds the normal file,
3557 * acl info may have been retrieved (in aclp).
3558 * All file types are directed here (go filedone).
3559 * Always restore ACLs if there are ACLs.
3560 */
3561 if (aclp != NULL) {
3562 int ret;
3563
3564 #if defined(O_XATTR)
3565 if (xattrp != NULL) {
3566 if (Hiddendir)
3567 ret = facl_set(dirfd, aclp);
3568 else
3569 ret = facl_set(ofile, aclp);
3570 } else {
3571 ret = acl_set(namep, aclp);
3572 }
3573 #else
3574 ret = acl_set(namep, aclp);
3575 #endif
3576 if (ret < 0) {
3577 if (pflag) {
3578 (void) fprintf(stderr, gettext(
3579 "%s%s%s%s: failed to set acl "
3580 "entries\n"), namep,
3581 (xattrp == NULL) ? "" :
3582 (rw_sysattr ? gettext(
3583 " system attribute ") :
3584 gettext(" attribute ")),
3585 (xattrp == NULL) ? "" :
3586 xattrapath);
3587 }
3588 /* else: silent and continue */
3589 }
3590 acl_free(aclp);
3591 aclp = NULL;
3592 }
3593
3594 if (!oflag)
3595 /* set file ownership */
3596 resugname(dirfd, comp, symflag);
3597
3598 if (pflag && newfile == TRUE && !dir &&
3599 (dblock.dbuf.typeflag == '0' ||
3600 dblock.dbuf.typeflag == NULL ||
3601 convflag || dblock.dbuf.typeflag == '1')) {
3602 if (fstat(ofile, &xtractbuf) == -1)
3603 (void) fprintf(stderr, gettext(
3604 "tar: cannot stat extracted file "
3605 "%s%s%s%s\n"),
3606 (xattrp == NULL) ? "" : (rw_sysattr ?
3607 gettext("system attribute ") :
3608 gettext("attribute ")),
3609 (xattrp == NULL) ? "" : xattrapath,
3610 (xattrp == NULL) ? "" :
3611 gettext(" of "), namep);
3612
3613 else if ((xtractbuf.st_mode & (MODEMASK & ~S_IFMT))
3614 != (stbuf.st_mode & (MODEMASK & ~S_IFMT))) {
3615 (void) fprintf(stderr, gettext(
3616 "tar: warning - file permissions have "
3617 "changed for %s%s%s%s (are 0%o, should be "
3618 "0%o)\n"),
3619 (xattrp == NULL) ? "" : (rw_sysattr ?
3620 gettext("system attribute ") :
3621 gettext("attribute ")),
3622 (xattrp == NULL) ? "" : xattrapath,
3623 (xattrp == NULL) ? "" :
3624 gettext(" of "), namep,
3625 xtractbuf.st_mode, stbuf.st_mode);
3626
3627 }
3628 }
3629 #if defined(O_XATTR)
3630 if (xattrp != NULL) {
3631 free(xattrhead);
3632 xattrp = NULL;
3633 xattr_linkp = NULL;
3634 xattrhead = NULL;
3635 }
3636 #endif
3637
3638 if (ofile != -1) {
3639 (void) close(dirfd);
3640 dirfd = -1;
3641 if (close(ofile) != 0)
3642 vperror(2, gettext("close error"));
3643 ofile = -1;
3644 }
3645 xcnt++; /* increment # files extracted */
3646 }
3647
3648 /*
3649 * Process ancillary file.
3650 *
3651 */
3652
3653 if (dblock.dbuf.typeflag == 'A') { /* acl info */
3654 char buf[TBLOCK];
3655 char *secp;
3656 char *tp;
3657 int attrsize;
3658 int cnt;
3659
3660 /* reset Trusted Extensions flags */
3661 dir_flag = 0;
3662 mld_flag = 0;
3663 lk_rpath_flag = 0;
3664 rpath_flag = 0;
3665
3666 if (pflag) {
3667 bytes = stbuf.st_size;
3668 if ((secp = malloc((int)bytes)) == NULL) {
3669 (void) fprintf(stderr, gettext(
3670 "Insufficient memory for acl\n"));
3671 passtape();
3672 continue;
3673 }
3674 tp = secp;
3675 blocks = TBLOCKS(bytes);
3676
3677 /*
3678 * Display a line for each ancillary file.
3679 */
3680 if (vflag && Tflag)
3681 (void) fprintf(vfile, "x %s(A), %"
3682 FMT_blkcnt_t " %s, %"
3683 FMT_blkcnt_t " %s\n",
3684 namep, bytes, gettext("bytes"),
3685 blocks, gettext("tape blocks"));
3686
3687 while (blocks-- > 0) {
3688 readtape(buf);
3689 if (bytes <= TBLOCK) {
3690 (void) memcpy(tp, buf,
3691 (size_t)bytes);
3692 break;
3693 } else {
3694 (void) memcpy(tp, buf,
3695 TBLOCK);
3696 tp += TBLOCK;
3697 }
3698 bytes -= TBLOCK;
3699 }
3700 bytes = stbuf.st_size;
3701 /* got all attributes in secp */
3702 tp = secp;
3703 do {
3704 attr = (struct sec_attr *)tp;
3705 switch (attr->attr_type) {
3706 case UFSD_ACL:
3707 case ACE_ACL:
3708 (void) sscanf(attr->attr_len,
3709 "%7o",
3710 (uint_t *)
3711 &cnt);
3712 /* header is 8 */
3713 attrsize = 8 + (int)strlen(
3714 &attr->attr_info[0]) + 1;
3715 error =
3716 acl_fromtext(
3717 &attr->attr_info[0], &aclp);
3718
3719 if (error != 0) {
3720 (void) fprintf(stderr,
3721 gettext(
3722 "aclfromtext "
3723 "failed: %s\n"),
3724 acl_strerror(
3725 error));
3726 bytes -= attrsize;
3727 break;
3728 }
3729 if (acl_cnt(aclp) != cnt) {
3730 (void) fprintf(stderr,
3731 gettext(
3732 "aclcnt error\n"));
3733 bytes -= attrsize;
3734 break;
3735 }
3736 bytes -= attrsize;
3737 break;
3738
3739 /* Trusted Extensions */
3740
3741 case DIR_TYPE:
3742 case LBL_TYPE:
3743 case APRIV_TYPE:
3744 case FPRIV_TYPE:
3745 case COMP_TYPE:
3746 case LK_COMP_TYPE:
3747 case ATTR_FLAG_TYPE:
3748 attrsize =
3749 sizeof (struct sec_attr) +
3750 strlen(&attr->attr_info[0]);
3751 bytes -= attrsize;
3752 if (Tflag)
3753 extract_attr(&namep,
3754 attr);
3755 break;
3756
3757 default:
3758 (void) fprintf(stderr, gettext(
3759 "unrecognized attr"
3760 " type\n"));
3761 bytes = (off_t)0;
3762 break;
3763 }
3764
3765 /* next attributes */
3766 tp += attrsize;
3767 } while (bytes != 0);
3768 free(secp);
3769 } else {
3770 passtape();
3771 }
3772 } /* acl */
3773
3774 } /* for */
3775
3776 /*
3777 * Ensure that all the directories still on the directory stack
3778 * get their modification times set correctly by flushing the
3779 * stack.
3780 */
3781
3782 doDirTimes(NULL, time_zero);
3783
3784 #if defined(O_XATTR)
3785 if (xattrp != NULL) {
3786 free(xattrhead);
3787 xattrp = NULL;
3788 xattr_linkp = NULL;
3789 xattrhead = NULL;
3790 }
3791 #endif
3792
3793 /*
3794 * Check if the number of files extracted is different from the
3795 * number of files listed on the command line
3796 */
3797 if (fcnt > xcnt) {
3798 (void) fprintf(stderr,
3799 gettext("tar: %d file(s) not extracted\n"),
3800 fcnt-xcnt);
3801 Errflg = 1;
3802 }
3803 }
3804
3805 /*
3806 * xblocks extract file/extent from tape to output file
3807 *
3808 * xblocks(issysattr, bytes, ofile);
3809 *
3810 * issysattr flag set if the files being extracted
3811 * is an extended system attribute file.
3812 * unsigned long long bytes size of extent or file to be extracted
3813 * ofile output file
3814 *
3815 * called by doxtract() and xsfile()
3816 */
3817
3818 static int
3819 xblocks(int issysattr, off_t bytes, int ofile)
3820 {
3821 char *buf;
3822 char tempname[NAMSIZ+1];
3823 size_t maxwrite;
3824 size_t bytesread;
3825 size_t piosize; /* preferred I/O size */
3826 struct stat tsbuf;
3827
3828 /* Don't need to do anything if this is a zero size file */
3829 if (bytes <= 0) {
3830 return (0);
3831 }
3832
3833 /*
3834 * To figure out the size of the buffer used to accumulate data
3835 * from readtape() and to write to the file, we need to determine
3836 * the largest chunk of data to be written to the file at one time.
3837 * This is determined based on the smallest of the following two
3838 * things:
3839 * 1) The size of the archived file.
3840 * 2) The preferred I/O size of the file.
3841 */
3842 if (issysattr || (bytes <= TBLOCK)) {
3843 /*
3844 * Writes to system attribute files must be
3845 * performed in one operation.
3846 */
3847 maxwrite = bytes;
3848 } else {
3849 /*
3850 * fstat() the file to get the preferred I/O size.
3851 * If it fails, then resort back to just writing
3852 * one block at a time.
3853 */
3854 if (fstat(ofile, &tsbuf) == 0) {
3855 piosize = tsbuf.st_blksize;
3856 } else {
3857 piosize = TBLOCK;
3858 }
3859 maxwrite = min(bytes, piosize);
3860 }
3861
3862 /*
3863 * The buffer used to accumulate the data for the write operation
3864 * needs to be the maximum number of bytes to be written rounded up
3865 * to the nearest TBLOCK since readtape reads one block at a time.
3866 */
3867 if ((buf = malloc(TBLOCKS(maxwrite) * TBLOCK)) == NULL) {
3868 fatal(gettext("cannot allocate buffer"));
3869 }
3870
3871 while (bytes > 0) {
3872
3873 /*
3874 * readtape() obtains one block (TBLOCK) of data at a time.
3875 * Accumulate as many blocks of data in buf as we can write
3876 * in one operation.
3877 */
3878 for (bytesread = 0; bytesread < maxwrite; bytesread += TBLOCK) {
3879 readtape(buf + bytesread);
3880 }
3881
3882 if (write(ofile, buf, maxwrite) < 0) {
3883 int saveerrno = errno;
3884
3885 if (xhdr_flgs & _X_PATH)
3886 (void) strlcpy(tempname, Xtarhdr.x_path,
3887 sizeof (tempname));
3888 else
3889 (void) sprintf(tempname, "%.*s", NAMSIZ,
3890 dblock.dbuf.name);
3891 /*
3892 * If the extended system attribute being extracted
3893 * contains attributes that the user needs privileges
3894 * for, then just display a warning message, skip
3895 * the extraction of this file, and return.
3896 */
3897 if ((saveerrno == EPERM) && issysattr) {
3898 (void) fprintf(stderr, gettext(
3899 "tar: unable to extract system attribute "
3900 "%s: insufficient privileges\n"), tempname);
3901 Errflg = 1;
3902 (void) free(buf);
3903 return (1);
3904 } else {
3905 (void) fprintf(stderr, gettext(
3906 "tar: %s: HELP - extract write error\n"),
3907 tempname);
3908 done(2);
3909 }
3910 }
3911 bytes -= maxwrite;
3912
3913 /*
3914 * If we've reached this point and there is still data
3915 * to be written, maxwrite had to have been determined
3916 * by the preferred I/O size. If the number of bytes
3917 * left to write is smaller than the preferred I/O size,
3918 * then we're about to do our final write to the file, so
3919 * just set maxwrite to the number of bytes left to write.
3920 */
3921 if ((bytes > 0) && (bytes < maxwrite)) {
3922 maxwrite = bytes;
3923 }
3924 }
3925 free(buf);
3926
3927 return (0);
3928 }
3929
3930 /*
3931 * xsfile extract split file
3932 *
3933 * xsfile(ofd); ofd = output file descriptor
3934 *
3935 * file extracted and put in ofd via xblocks()
3936 *
3937 * NOTE: only called by doxtract() to extract one large file
3938 */
3939
3940 static union hblock savedblock; /* to ensure same file across volumes */
3941
3942 static int
3943 xsfile(int issysattr, int ofd)
3944 {
3945 int i, c;
3946 int sysattrerr = 0;
3947 char name[PATH_MAX+1]; /* holds name for diagnostics */
3948 int extents, totalext;
3949 off_t bytes, totalbytes;
3950
3951 if (xhdr_flgs & _X_PATH)
3952 (void) strcpy(name, Xtarhdr.x_path);
3953 else
3954 (void) sprintf(name, "%.*s", NAMSIZ, dblock.dbuf.name);
3955
3956 totalbytes = (off_t)0; /* in case we read in half the file */
3957 totalext = 0; /* these keep count */
3958
3959 (void) fprintf(stderr, gettext(
3960 "tar: %s split across %d volumes\n"), name, extotal);
3961
3962 /* make sure we do extractions in order */
3963 if (extno != 1) { /* starting in middle of file? */
3964 (void) printf(gettext(
3965 "tar: first extent read is not #1\n"
3966 "OK to read file beginning with extent #%d (%s/%s) ? "),
3967 extno, yesstr, nostr);
3968 if (yes() == 0) {
3969 canit:
3970 passtape();
3971 if (close(ofd) != 0)
3972 vperror(2, gettext("close error"));
3973 if (sysattrerr) {
3974 return (1);
3975 } else {
3976 return (0);
3977 }
3978 }
3979 }
3980 extents = extotal;
3981 i = extno;
3982 /*CONSTCOND*/
3983 while (1) {
3984 if (xhdr_flgs & _X_SIZE) {
3985 bytes = extsize;
3986 } else {
3987 bytes = stbuf.st_size;
3988 }
3989
3990 if (vflag)
3991 (void) fprintf(vfile, "+++ x %s [%s #%d], %"
3992 FMT_off_t " %s, %ldK\n",
3993 name, gettext("extent"), extno,
3994 bytes, gettext("bytes"),
3995 (long)K(TBLOCKS(bytes)));
3996 if (xblocks(issysattr, bytes, ofd) != 0) {
3997 sysattrerr = 1;
3998 goto canit;
3999 }
4000
4001 totalbytes += bytes;
4002 totalext++;
4003 if (++i > extents)
4004 break;
4005
4006 /* get next volume and verify it's the right one */
4007 copy(&savedblock, &dblock);
4008 tryagain:
4009 newvol();
4010 xhdr_flgs = 0;
4011 getdir();
4012 if (Xhdrflag > 0)
4013 (void) get_xdata(); /* Get x-header & regular hdr */
4014 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
4015 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
4016 xhdr_flgs |= _X_XHDR;
4017 }
4018 if (endtape()) { /* seemingly empty volume */
4019 (void) fprintf(stderr, gettext(
4020 "tar: first record is null\n"));
4021 asknicely:
4022 (void) fprintf(stderr, gettext(
4023 "tar: need volume with extent #%d of %s\n"),
4024 i, name);
4025 goto tryagain;
4026 }
4027 if (notsame()) {
4028 (void) fprintf(stderr, gettext(
4029 "tar: first file on that volume is not "
4030 "the same file\n"));
4031 goto asknicely;
4032 }
4033 if (i != extno) {
4034 (void) fprintf(stderr, gettext(
4035 "tar: extent #%d received out of order\ntar: "
4036 "should be #%d\n"), extno, i);
4037 (void) fprintf(stderr, gettext(
4038 "Ignore error, Abort this file, or "
4039 "load New volume (i/a/n) ? "));
4040 c = response();
4041 if (c == 'a')
4042 goto canit;
4043 if (c != 'i') /* default to new volume */
4044 goto asknicely;
4045 i = extno; /* okay, start from there */
4046 }
4047 }
4048 if (vflag)
4049 (void) fprintf(vfile, gettext(
4050 "x %s (in %d extents), %" FMT_off_t " bytes, %ldK\n"),
4051 name, totalext, totalbytes, (long)K(TBLOCKS(totalbytes)));
4052
4053 return (0);
4054 }
4055
4056
4057 /*
4058 * notsame() check if extract file extent is invalid
4059 *
4060 * returns true if anything differs between savedblock and dblock
4061 * except extno (extent number), checksum, or size (extent size).
4062 * Determines if this header belongs to the same file as the one we're
4063 * extracting.
4064 *
4065 * NOTE: though rather bulky, it is only called once per file
4066 * extension, and it can withstand changes in the definition
4067 * of the header structure.
4068 *
4069 * WARNING: this routine is local to xsfile() above
4070 */
4071
4072 static int
4073 notsame(void)
4074 {
4075 return (
4076 (strncmp(savedblock.dbuf.name, dblock.dbuf.name, NAMSIZ)) ||
4077 (strcmp(savedblock.dbuf.mode, dblock.dbuf.mode)) ||
4078 (strcmp(savedblock.dbuf.uid, dblock.dbuf.uid)) ||
4079 (strcmp(savedblock.dbuf.gid, dblock.dbuf.gid)) ||
4080 (strcmp(savedblock.dbuf.mtime, dblock.dbuf.mtime)) ||
4081 (savedblock.dbuf.typeflag != dblock.dbuf.typeflag) ||
4082 (strncmp(savedblock.dbuf.linkname, dblock.dbuf.linkname, NAMSIZ)) ||
4083 (savedblock.dbuf.extotal != dblock.dbuf.extotal) ||
4084 (strcmp(savedblock.dbuf.efsize, dblock.dbuf.efsize)));
4085 }
4086
4087 static void
4088 dotable(char *argv[])
4089 {
4090 int tcnt = 0; /* count # files tabled */
4091 int fcnt = 0; /* count # files in argv list */
4092 char *namep, *dirp, *comp;
4093 int want;
4094 char aclchar = ' '; /* either blank or '+' */
4095 char templink[PATH_MAX+1];
4096 attr_data_t *attrinfo = NULL;
4097
4098 dumping = 0;
4099
4100 /* if not on magtape, maximize seek speed */
4101 if (NotTape && !bflag) {
4102 #if SYS_BLOCK > TBLOCK
4103 nblock = SYS_BLOCK / TBLOCK;
4104 #else
4105 nblock = 1;
4106 #endif
4107 }
4108
4109 for (;;) {
4110
4111 /* namep is set by wantit to point to the full name */
4112 if ((want = wantit(argv, &namep, &dirp, &comp, &attrinfo)) == 0)
4113 continue;
4114 if (want == -1)
4115 break;
4116 if (dblock.dbuf.typeflag != 'A')
4117 ++tcnt;
4118
4119 if (Fflag) {
4120 if (checkf(namep, is_directory(namep), Fflag) == 0) {
4121 passtape();
4122 continue;
4123 }
4124 }
4125 /*
4126 * ACL support:
4127 * aclchar is introduced to indicate if there are
4128 * acl entries. longt() now takes one extra argument.
4129 */
4130 if (vflag) {
4131 if (dblock.dbuf.typeflag == 'A') {
4132 aclchar = '+';
4133 passtape();
4134 continue;
4135 }
4136 longt(&stbuf, aclchar);
4137 aclchar = ' ';
4138 }
4139
4140
4141 #if defined(O_XATTR)
4142 if (xattrp != NULL) {
4143 int issysattr;
4144 char *bn = basename(attrinfo->attr_path);
4145
4146 /*
4147 * We could use sysattr_type() to test whether or not
4148 * the attribute we are processing is really an
4149 * extended system attribute, which as of this writing
4150 * just does a strcmp(), however, sysattr_type() may
4151 * be changed to issue a pathconf() call instead, which
4152 * would require being changed into the parent attribute
4153 * directory. So instead, just do simple string
4154 * comparisons to see if we are processing an extended
4155 * system attribute.
4156 */
4157 issysattr = is_sysattr(bn);
4158
4159 (void) printf(gettext("%s %sattribute %s"),
4160 xattrp->h_names,
4161 issysattr ? gettext("system ") : "",
4162 attrinfo->attr_path);
4163 } else {
4164 (void) printf("%s", namep);
4165 }
4166 #else
4167 (void) printf("%s", namep);
4168 #endif
4169
4170 if (extno != 0) {
4171 if (vflag) {
4172 /* keep the '\n' for backwards compatibility */
4173 (void) fprintf(vfile, gettext(
4174 "\n [extent #%d of %d]"), extno, extotal);
4175 } else {
4176 (void) fprintf(vfile, gettext(
4177 " [extent #%d of %d]"), extno, extotal);
4178 }
4179 }
4180 if (xhdr_flgs & _X_LINKPATH) {
4181 (void) strcpy(templink, Xtarhdr.x_linkpath);
4182 } else {
4183 #if defined(O_XATTR)
4184 if (xattrp != NULL) {
4185 (void) sprintf(templink,
4186 "file %.*s", NAMSIZ, xattrp->h_names);
4187 } else {
4188 (void) sprintf(templink, "%.*s", NAMSIZ,
4189 dblock.dbuf.linkname);
4190 }
4191 #else
4192 (void) sprintf(templink, "%.*s", NAMSIZ,
4193 dblock.dbuf.linkname);
4194 #endif
4195 templink[NAMSIZ] = '\0';
4196 }
4197 if (dblock.dbuf.typeflag == '1') {
4198 /*
4199 * TRANSLATION_NOTE
4200 * Subject is omitted here.
4201 * Translate this as if
4202 * <subject> linked to %s
4203 */
4204 #if defined(O_XATTR)
4205 if (xattrp != NULL) {
4206 (void) printf(
4207 gettext(" linked to attribute %s"),
4208 xattr_linkp->h_names +
4209 strlen(xattr_linkp->h_names) + 1);
4210 } else {
4211 (void) printf(
4212 gettext(" linked to %s"), templink);
4213 }
4214 #else
4215 (void) printf(
4216 gettext(" linked to %s"), templink);
4217
4218 #endif
4219 }
4220 if (dblock.dbuf.typeflag == '2')
4221 (void) printf(gettext(
4222 /*
4223 * TRANSLATION_NOTE
4224 * Subject is omitted here.
4225 * Translate this as if
4226 * <subject> symbolic link to %s
4227 */
4228 " symbolic link to %s"), templink);
4229 (void) printf("\n");
4230 #if defined(O_XATTR)
4231 if (xattrp != NULL) {
4232 free(xattrhead);
4233 xattrp = NULL;
4234 xattrhead = NULL;
4235 }
4236 #endif
4237 passtape();
4238 }
4239 /*
4240 * Check if the number of files tabled is different from the
4241 * number of files listed on the command line
4242 */
4243 if (fcnt > tcnt) {
4244 (void) fprintf(stderr, gettext(
4245 "tar: %d file(s) not found\n"), fcnt-tcnt);
4246 Errflg = 1;
4247 }
4248 }
4249
4250 static void
4251 putempty(blkcnt_t n)
4252 {
4253 char buf[TBLOCK];
4254 char *cp;
4255
4256 for (cp = buf; cp < &buf[TBLOCK]; )
4257 *cp++ = '\0';
4258 while (n-- > 0)
4259 (void) writetbuf(buf, 1);
4260 }
4261
4262 static ushort_t Ftype = S_IFMT;
4263
4264 static void
4265 verbose(struct stat *st, char aclchar)
4266 {
4267 int i, j, temp;
4268 mode_t mode;
4269 char modestr[12];
4270
4271 for (i = 0; i < 11; i++)
4272 modestr[i] = '-';
4273 modestr[i] = '\0';
4274
4275 /* a '+' sign is printed if there is ACL */
4276 modestr[i-1] = aclchar;
4277
4278 mode = st->st_mode;
4279 for (i = 0; i < 3; i++) {
4280 temp = (mode >> (6 - (i * 3)));
4281 j = (i * 3) + 1;
4282 if (S_IROTH & temp)
4283 modestr[j] = 'r';
4284 if (S_IWOTH & temp)
4285 modestr[j + 1] = 'w';
4286 if (S_IXOTH & temp)
4287 modestr[j + 2] = 'x';
4288 }
4289 temp = st->st_mode & Ftype;
4290 switch (temp) {
4291 case (S_IFIFO):
4292 modestr[0] = 'p';
4293 break;
4294 case (S_IFCHR):
4295 modestr[0] = 'c';
4296 break;
4297 case (S_IFDIR):
4298 modestr[0] = 'd';
4299 break;
4300 case (S_IFBLK):
4301 modestr[0] = 'b';
4302 break;
4303 case (S_IFREG): /* was initialized to '-' */
4304 break;
4305 case (S_IFLNK):
4306 modestr[0] = 'l';
4307 break;
4308 default:
4309 /* This field may be zero in old archives. */
4310 if (is_posix && dblock.dbuf.typeflag != '1') {
4311 /*
4312 * For POSIX compliant archives, the mode field
4313 * consists of 12 bits, ie: the file type bits
4314 * are not stored in dblock.dbuf.mode.
4315 * For files other than hard links, getdir() sets
4316 * the file type bits in the st_mode field of the
4317 * stat structure based upon dblock.dbuf.typeflag.
4318 */
4319 (void) fprintf(stderr, gettext(
4320 "tar: impossible file type"));
4321 }
4322 }
4323
4324 if ((S_ISUID & Gen.g_mode) == S_ISUID)
4325 modestr[3] = 's';
4326 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
4327 modestr[9] = 't';
4328 if ((S_ISGID & Gen.g_mode) == S_ISGID && modestr[6] == 'x')
4329 modestr[6] = 's';
4330 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
4331 modestr[6] = 'l';
4332 (void) fprintf(vfile, "%s", modestr);
4333 }
4334
4335 static void
4336 longt(struct stat *st, char aclchar)
4337 {
4338 char fileDate[30];
4339 struct tm *tm;
4340
4341 verbose(st, aclchar);
4342 (void) fprintf(vfile, "%3ld/%-3ld", st->st_uid, st->st_gid);
4343
4344 if (dblock.dbuf.typeflag == '2') {
4345 if (xhdr_flgs & _X_LINKPATH)
4346 st->st_size = (off_t)strlen(Xtarhdr.x_linkpath);
4347 else
4348 st->st_size = (off_t)(memchr(dblock.dbuf.linkname,
4349 '\0', NAMSIZ) ?
4350 (strlen(dblock.dbuf.linkname)) : (NAMSIZ));
4351 }
4352 (void) fprintf(vfile, " %6" FMT_off_t, st->st_size);
4353
4354 tm = localtime(&(st->st_mtime));
4355 (void) strftime(fileDate, sizeof (fileDate),
4356 dcgettext((const char *)0, "%b %e %R %Y", LC_TIME), tm);
4357 (void) fprintf(vfile, " %s ", fileDate);
4358 }
4359
4360
4361 /*
4362 * checkdir - Attempt to ensure that the path represented in name
4363 * exists, and return 1 if this is true and name itself is a
4364 * directory.
4365 * Return 0 if this path cannot be created or if name is not
4366 * a directory.
4367 */
4368
4369 static int
4370 checkdir(char *name)
4371 {
4372 char lastChar; /* the last character in name */
4373 char *cp; /* scratch pointer into name */
4374 char *firstSlash = NULL; /* first slash in name */
4375 char *lastSlash = NULL; /* last slash in name */
4376 int nameLen; /* length of name */
4377 int trailingSlash; /* true if name ends in slash */
4378 int leadingSlash; /* true if name begins with slash */
4379 int markedDir; /* true if name denotes a directory */
4380 int success; /* status of makeDir call */
4381
4382
4383 /*
4384 * Scan through the name, and locate first and last slashes.
4385 */
4386
4387 for (cp = name; *cp; cp++) {
4388 if (*cp == '/') {
4389 if (! firstSlash) {
4390 firstSlash = cp;
4391 }
4392 lastSlash = cp;
4393 }
4394 }
4395
4396 /*
4397 * Determine what you can from the proceeds of the scan.
4398 */
4399
4400 lastChar = *(cp - 1);
4401 nameLen = (int)(cp - name);
4402 trailingSlash = (lastChar == '/');
4403 leadingSlash = (*name == '/');
4404 markedDir = (dblock.dbuf.typeflag == '5' || trailingSlash);
4405
4406 if (! lastSlash && ! markedDir) {
4407 /*
4408 * The named file does not have any subdrectory
4409 * structure; just bail out.
4410 */
4411
4412 return (0);
4413 }
4414
4415 /*
4416 * Make sure that name doesn`t end with slash for the loop.
4417 * This ensures that the makeDir attempt after the loop is
4418 * meaningful.
4419 */
4420
4421 if (trailingSlash) {
4422 name[nameLen-1] = '\0';
4423 }
4424
4425 /*
4426 * Make the path one component at a time.
4427 */
4428
4429 for (cp = strchr(leadingSlash ? name+1 : name, '/');
4430 cp;
4431 cp = strchr(cp+1, '/')) {
4432 *cp = '\0';
4433 success = makeDir(name);
4434 *cp = '/';
4435
4436 if (!success) {
4437 name[nameLen-1] = lastChar;
4438 return (0);
4439 }
4440 }
4441
4442 /*
4443 * This makes the last component of the name, if it is a
4444 * directory.
4445 */
4446
4447 if (markedDir) {
4448 if (! makeDir(name)) {
4449 name[nameLen-1] = lastChar;
4450 return (0);
4451 }
4452 }
4453
4454 name[nameLen-1] = (lastChar == '/') ? '\0' : lastChar;
4455 return (markedDir);
4456 }
4457
4458 /*
4459 * resugname - Restore the user name and group name. Search the NIS
4460 * before using the uid and gid.
4461 * (It is presumed that an archive entry cannot be
4462 * simultaneously a symlink and some other type.)
4463 */
4464
4465 static void
4466 resugname(int dirfd, /* dir fd file resides in */
4467 char *name, /* name of the file to be modified */
4468 int symflag) /* true if file is a symbolic link */
4469 {
4470 uid_t duid;
4471 gid_t dgid;
4472 struct stat *sp = &stbuf;
4473 char *u_g_name;
4474
4475 if (checkflag == 1) { /* Extended tar format and euid == 0 */
4476
4477 /*
4478 * Try and extract the intended uid and gid from the name
4479 * service before believing the uid and gid in the header.
4480 *
4481 * In the case where we archived a setuid or setgid file
4482 * owned by someone with a large uid, then it will
4483 * have made it into the archive with a uid of nobody. If
4484 * the corresponding username doesn't appear to exist, then we
4485 * want to make sure it *doesn't* end up as setuid nobody!
4486 *
4487 * Our caller will print an error message about the fact
4488 * that the restore didn't work out quite right ..
4489 */
4490 if (xhdr_flgs & _X_UNAME)
4491 u_g_name = Xtarhdr.x_uname;
4492 else
4493 u_g_name = dblock.dbuf.uname;
4494 if ((duid = getuidbyname(u_g_name)) == -1) {
4495 if (S_ISREG(sp->st_mode) && sp->st_uid == UID_NOBODY &&
4496 (sp->st_mode & S_ISUID) == S_ISUID)
4497 (void) chmod(name,
4498 MODEMASK & sp->st_mode & ~S_ISUID);
4499 duid = sp->st_uid;
4500 }
4501
4502 /* (Ditto for gids) */
4503
4504 if (xhdr_flgs & _X_GNAME)
4505 u_g_name = Xtarhdr.x_gname;
4506 else
4507 u_g_name = dblock.dbuf.gname;
4508 if ((dgid = getgidbyname(u_g_name)) == -1) {
4509 if (S_ISREG(sp->st_mode) && sp->st_gid == GID_NOBODY &&
4510 (sp->st_mode & S_ISGID) == S_ISGID)
4511 (void) chmod(name,
4512 MODEMASK & sp->st_mode & ~S_ISGID);
4513 dgid = sp->st_gid;
4514 }
4515 } else if (checkflag == 2) { /* tar format and euid == 0 */
4516 duid = sp->st_uid;
4517 dgid = sp->st_gid;
4518 }
4519 if ((checkflag == 1) || (checkflag == 2))
4520 (void) fchownat(dirfd, name, duid, dgid, symflag);
4521 }
4522
4523 /*ARGSUSED*/
4524 static void
4525 onintr(int sig)
4526 {
4527 (void) signal(SIGINT, SIG_IGN);
4528 term++;
4529 }
4530
4531 /*ARGSUSED*/
4532 static void
4533 onquit(int sig)
4534 {
4535 (void) signal(SIGQUIT, SIG_IGN);
4536 term++;
4537 }
4538
4539 /*ARGSUSED*/
4540 static void
4541 onhup(int sig)
4542 {
4543 (void) signal(SIGHUP, SIG_IGN);
4544 term++;
4545 }
4546
4547 static void
4548 tomodes(struct stat *sp)
4549 {
4550 uid_t uid;
4551 gid_t gid;
4552
4553 bzero(dblock.dummy, TBLOCK);
4554
4555 /*
4556 * If the uid or gid is too large, we can't put it into
4557 * the archive. We could fail to put anything in the
4558 * archive at all .. but most of the time the name service
4559 * will save the day when we do a lookup at restore time.
4560 *
4561 * Instead we choose a "safe" uid and gid, and fix up whether
4562 * or not the setuid and setgid bits are left set to extraction
4563 * time.
4564 */
4565 if (Eflag) {
4566 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR) {
4567 xhdr_flgs |= _X_UID;
4568 Xtarhdr.x_uid = uid;
4569 }
4570 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR) {
4571 xhdr_flgs |= _X_GID;
4572 Xtarhdr.x_gid = gid;
4573 }
4574 if (sp->st_size > TAR_OFFSET_MAX) {
4575 xhdr_flgs |= _X_SIZE;
4576 Xtarhdr.x_filesz = sp->st_size;
4577 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4578 (off_t)0);
4579 } else
4580 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4581 sp->st_size);
4582 } else {
4583 (void) sprintf(dblock.dbuf.size, "%011" FMT_off_t_o,
4584 sp->st_size);
4585 }
4586 if ((ulong_t)(uid = sp->st_uid) > (ulong_t)OCTAL7CHAR)
4587 uid = UID_NOBODY;
4588 if ((ulong_t)(gid = sp->st_gid) > (ulong_t)OCTAL7CHAR)
4589 gid = GID_NOBODY;
4590 (void) sprintf(dblock.dbuf.gid, "%07lo", gid);
4591 (void) sprintf(dblock.dbuf.uid, "%07lo", uid);
4592 (void) sprintf(dblock.dbuf.mode, "%07lo", sp->st_mode & POSIXMODES);
4593 (void) sprintf(dblock.dbuf.mtime, "%011lo", sp->st_mtime);
4594 }
4595
4596 static int
4597 #ifdef EUC
4598 /*
4599 * Warning: the result of this function depends whether 'char' is a
4600 * signed or unsigned data type. This a source of potential
4601 * non-portability among heterogeneous systems. It is retained here
4602 * for backward compatibility.
4603 */
4604 checksum_signed(union hblock *dblockp)
4605 #else
4606 checksum(union hblock *dblockp)
4607 #endif /* EUC */
4608 {
4609 int i;
4610 char *cp;
4611
4612 for (cp = dblockp->dbuf.chksum;
4613 cp < &dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]; cp++)
4614 *cp = ' ';
4615 i = 0;
4616 for (cp = dblockp->dummy; cp < &(dblockp->dummy[TBLOCK]); cp++)
4617 i += *cp;
4618 return (i);
4619 }
4620
4621 #ifdef EUC
4622 /*
4623 * Generate unsigned checksum, regardless of what C compiler is
4624 * used. Survives in the face of arbitrary 8-bit clean filenames,
4625 * e.g., internationalized filenames.
4626 */
4627 static int
4628 checksum(union hblock *dblockp)
4629 {
4630 unsigned i;
4631 unsigned char *cp;
4632
4633 for (cp = (unsigned char *) dblockp->dbuf.chksum;
4634 cp < (unsigned char *)
4635 &(dblockp->dbuf.chksum[sizeof (dblockp->dbuf.chksum)]); cp++)
4636 *cp = ' ';
4637 i = 0;
4638 for (cp = (unsigned char *) dblockp->dummy;
4639 cp < (unsigned char *) &(dblockp->dummy[TBLOCK]); cp++)
4640 i += *cp;
4641
4642 return (i);
4643 }
4644 #endif /* EUC */
4645
4646 /*
4647 * If the w flag is set, output the action to be taken and the name of the
4648 * file. Perform the action if the user response is affirmative.
4649 */
4650
4651 static int
4652 checkw(char c, char *name)
4653 {
4654 if (wflag) {
4655 (void) fprintf(vfile, "%c ", c);
4656 if (vflag)
4657 longt(&stbuf, ' '); /* do we have acl info here */
4658 (void) fprintf(vfile, "%s: ", name);
4659 if (yes() == 1) {
4660 return (1);
4661 }
4662 return (0);
4663 }
4664 return (1);
4665 }
4666
4667 /*
4668 * When the F flag is set, exclude RCS and SCCS directories (and any files
4669 * or directories under them). If F is set twice, also exclude .o files,
4670 * and files names errs, core, and a.out.
4671 *
4672 * Return 0 if file should be excluded, 1 otherwise.
4673 */
4674
4675 static int
4676 checkf(char *longname, int is_dir, int howmuch)
4677 {
4678 static char fullname[PATH_MAX + 1];
4679 char *dir, *name;
4680
4681 #if defined(O_XATTR)
4682 /*
4683 * If there is an xattr_buf structure associated with this file,
4684 * always return 1.
4685 */
4686 if (xattrp) {
4687 return (1);
4688 }
4689 #endif
4690
4691 /*
4692 * First check to see if the base name is an RCS or SCCS directory.
4693 */
4694 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4695 return (1);
4696
4697 name = basename(fullname);
4698 if (is_dir) {
4699 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4700 return (0);
4701 }
4702
4703 /*
4704 * If two -F command line options were given then exclude .o files,
4705 * and files named errs, core, and a.out.
4706 */
4707 if (howmuch > 1 && !is_dir) {
4708 size_t l = strlen(name);
4709
4710 if (l >= 3 && name[l - 2] == '.' && name[l - 1] == 'o')
4711 return (0);
4712 if (strcmp(name, "core") == 0 || strcmp(name, "errs") == 0 ||
4713 strcmp(name, "a.out") == 0)
4714 return (0);
4715 }
4716
4717 /*
4718 * At this point, check to see if this file has a parent directory
4719 * named RCS or SCCS. If so, then this file should be excluded too.
4720 * The strcpy() operation is done again, because basename(3C) may
4721 * modify the path string passed to it.
4722 */
4723 if (strlcpy(fullname, longname, sizeof (fullname)) >= sizeof (fullname))
4724 return (1);
4725
4726 dir = dirname(fullname);
4727 while (strcmp(dir, ".") != 0) {
4728 name = basename(dir);
4729 if ((strcmp(name, "SCCS") == 0) || (strcmp(name, "RCS") == 0))
4730 return (0);
4731 dir = dirname(dir);
4732 }
4733
4734 return (1);
4735 }
4736
4737 static int
4738 response(void)
4739 {
4740 int c;
4741
4742 c = getchar();
4743 if (c != '\n')
4744 while (getchar() != '\n')
4745 ;
4746 else c = 'n';
4747 return ((c >= 'A' && c <= 'Z') ? c + ('a'-'A') : c);
4748 }
4749
4750 /* Has file been modified since being put into archive? If so, return > 0. */
4751
4752 static off_t lookup(char *);
4753
4754 static int
4755 checkupdate(char *arg)
4756 {
4757 char name[PATH_MAX+1];
4758 time_t mtime;
4759 long nsecs;
4760 off_t seekp;
4761
4762 rewind(tfile);
4763 if ((seekp = lookup(arg)) < 0)
4764 return (1);
4765 (void) fseek(tfile, seekp, 0);
4766 (void) fscanf(tfile, "%s %ld.%ld", name, &mtime, &nsecs);
4767
4768 /*
4769 * Unless nanoseconds were stored in the file, only use seconds for
4770 * comparison of time. Nanoseconds are stored when -E is specified.
4771 */
4772 if (Eflag == 0)
4773 return (stbuf.st_mtime > mtime);
4774
4775 if ((stbuf.st_mtime < mtime) ||
4776 ((stbuf.st_mtime == mtime) && (stbuf.st_mtim.tv_nsec <= nsecs)))
4777 return (0);
4778 return (1);
4779 }
4780
4781
4782 /*
4783 * newvol get new floppy (or tape) volume
4784 *
4785 * newvol(); resets tapepos and first to TRUE, prompts for
4786 * for new volume, and waits.
4787 * if dumping, end-of-file is written onto the tape.
4788 */
4789
4790 static void
4791 newvol(void)
4792 {
4793 int c;
4794
4795 if (dumping) {
4796 #ifdef DEBUG
4797 DEBUG("newvol called with 'dumping' set\n", 0, 0);
4798 #endif
4799 putempty((blkcnt_t)2); /* 2 EOT marks */
4800 closevol();
4801 flushtape();
4802 sync();
4803 tapepos = 0;
4804 } else
4805 first = TRUE;
4806 if (close(mt) != 0)
4807 vperror(2, gettext("close error"));
4808 mt = 0;
4809 (void) fprintf(stderr, gettext(
4810 "tar: \007please insert new volume, then press RETURN."));
4811 (void) fseek(stdin, (off_t)0, 2); /* scan over read-ahead */
4812 while ((c = getchar()) != '\n' && ! term)
4813 if (c == EOF)
4814 done(Errflg);
4815 if (term)
4816 done(Errflg);
4817
4818 errno = 0;
4819
4820 if (strcmp(usefile, "-") == 0) {
4821 mt = dup(1);
4822 } else {
4823 mt = open(usefile, dumping ? update : 0);
4824 }
4825
4826 if (mt < 0) {
4827 (void) fprintf(stderr, gettext(
4828 "tar: cannot reopen %s (%s)\n"),
4829 dumping ? gettext("output") : gettext("input"), usefile);
4830
4831 #ifdef DEBUG
4832 DEBUG("update=%d, usefile=%s ", update, usefile);
4833 DEBUG("mt=%d, [%s]\n", mt, strerror(errno));
4834 #endif
4835
4836 done(2);
4837 }
4838 }
4839
4840 /*
4841 * Write a trailer portion to close out the current output volume.
4842 */
4843
4844 static void
4845 closevol(void)
4846 {
4847 if (mulvol) {
4848 /*
4849 * blocklim does not count the 2 EOT marks;
4850 * tapepos does count the 2 EOT marks;
4851 * therefore we need the +2 below.
4852 */
4853 putempty(blocklim + (blkcnt_t)2 - tapepos);
4854 }
4855 }
4856
4857 static void
4858 done(int n)
4859 {
4860 /*
4861 * If we were terminated in some way, and we would otherwise have
4862 * exited with a value of 0, adjust to 1, so that external callers
4863 * can determine this by looking at the exit status.
4864 */
4865 if (term && n == 0)
4866 n = 1;
4867
4868 if (tfile != NULL)
4869 (void) unlink(tname);
4870 if (compress_opt != NULL)
4871 (void) free(compress_opt);
4872 if (mt > 0) {
4873 if ((close(mt) != 0) || (fclose(stdout) != 0)) {
4874 perror(gettext("tar: close error"));
4875 exit(2);
4876 }
4877 }
4878 exit(n);
4879 }
4880
4881 /*
4882 * Determine if s1 is a prefix portion of s2 (or the same as s2).
4883 */
4884
4885 static int
4886 is_prefix(char *s1, char *s2)
4887 {
4888 while (*s1)
4889 if (*s1++ != *s2++)
4890 return (0);
4891 if (*s2)
4892 return (*s2 == '/');
4893 return (1);
4894 }
4895
4896 /*
4897 * lookup and bsrch look through tfile entries to find a match for a name.
4898 * The name can be up to PATH_MAX bytes. bsrch compares what it sees between
4899 * a pair of newline chars, so the buffer it uses must be long enough for
4900 * two lines: name and modification time as well as period, newline and space.
4901 *
4902 * A kludge was added to bsrch to take care of matching on the first entry
4903 * in the file--there is no leading newline. So, if we are reading from the
4904 * start of the file, read into byte two and set the first byte to a newline.
4905 * Otherwise, the first entry cannot be matched.
4906 *
4907 */
4908
4909 #define N (2 * (PATH_MAX + TIME_MAX_DIGITS + LONG_MAX_DIGITS + 3))
4910 static off_t
4911 lookup(char *s)
4912 {
4913 int i;
4914 off_t a;
4915
4916 for (i = 0; s[i]; i++)
4917 if (s[i] == ' ')
4918 break;
4919 a = bsrch(s, i, low, high);
4920 return (a);
4921 }
4922
4923 static off_t
4924 bsrch(char *s, int n, off_t l, off_t h)
4925 {
4926 int i, j;
4927 char b[N];
4928 off_t m, m1;
4929
4930
4931 loop:
4932 if (l >= h)
4933 return ((off_t)-1);
4934 m = l + (h-l)/2 - N/2;
4935 if (m < l)
4936 m = l;
4937 (void) fseek(tfile, m, 0);
4938 if (m == 0) {
4939 (void) fread(b+1, 1, N-1, tfile);
4940 b[0] = '\n';
4941 m--;
4942 } else
4943 (void) fread(b, 1, N, tfile);
4944 for (i = 0; i < N; i++) {
4945 if (b[i] == '\n')
4946 break;
4947 m++;
4948 }
4949 if (m >= h)
4950 return ((off_t)-1);
4951 m1 = m;
4952 j = i;
4953 for (i++; i < N; i++) {
4954 m1++;
4955 if (b[i] == '\n')
4956 break;
4957 }
4958 i = cmp(b+j, s, n);
4959 if (i < 0) {
4960 h = m;
4961 goto loop;
4962 }
4963 if (i > 0) {
4964 l = m1;
4965 goto loop;
4966 }
4967 if (m < 0)
4968 m = 0;
4969 return (m);
4970 }
4971
4972 static int
4973 cmp(char *b, char *s, int n)
4974 {
4975 int i;
4976
4977 assert(b[0] == '\n');
4978
4979 for (i = 0; i < n; i++) {
4980 if (b[i+1] > s[i])
4981 return (-1);
4982 if (b[i+1] < s[i])
4983 return (1);
4984 }
4985 return (b[i+1] == ' '? 0 : -1);
4986 }
4987
4988
4989 /*
4990 * seekdisk seek to next file on archive
4991 *
4992 * called by passtape() only
4993 *
4994 * WARNING: expects "nblock" to be set, that is, readtape() to have
4995 * already been called. Since passtape() is only called
4996 * after a file header block has been read (why else would
4997 * we skip to next file?), this is currently safe.
4998 *
4999 * changed to guarantee SYS_BLOCK boundary
5000 */
5001
5002 static void
5003 seekdisk(blkcnt_t blocks)
5004 {
5005 off_t seekval;
5006 #if SYS_BLOCK > TBLOCK
5007 /* handle non-multiple of SYS_BLOCK */
5008 blkcnt_t nxb; /* # extra blocks */
5009 #endif
5010
5011 tapepos += blocks;
5012 #ifdef DEBUG
5013 DEBUG("seekdisk(%" FMT_blkcnt_t ") called\n", blocks, 0);
5014 #endif
5015 if (recno + blocks <= nblock) {
5016 recno += blocks;
5017 return;
5018 }
5019 if (recno > nblock)
5020 recno = nblock;
5021 seekval = (off_t)blocks - (nblock - recno);
5022 recno = nblock; /* so readtape() reads next time through */
5023 #if SYS_BLOCK > TBLOCK
5024 nxb = (blkcnt_t)(seekval % (off_t)(SYS_BLOCK / TBLOCK));
5025 #ifdef DEBUG
5026 DEBUG("xtrablks=%" FMT_blkcnt_t " seekval=%" FMT_blkcnt_t " blks\n",
5027 nxb, seekval);
5028 #endif
5029 if (nxb && nxb > seekval) /* don't seek--we'll read */
5030 goto noseek;
5031 seekval -= nxb; /* don't seek quite so far */
5032 #endif
5033 if (lseek(mt, (off_t)(TBLOCK * seekval), 1) == (off_t)-1) {
5034 (void) fprintf(stderr, gettext(
5035 "tar: device seek error\n"));
5036 done(3);
5037 }
5038 #if SYS_BLOCK > TBLOCK
5039 /* read those extra blocks */
5040 noseek:
5041 if (nxb) {
5042 #ifdef DEBUG
5043 DEBUG("reading extra blocks\n", 0, 0);
5044 #endif
5045 if (read(mt, tbuf, TBLOCK*nblock) < 0) {
5046 (void) fprintf(stderr, gettext(
5047 "tar: read error while skipping file\n"));
5048 done(8);
5049 }
5050 recno = nxb; /* so we don't read in next readtape() */
5051 }
5052 #endif
5053 }
5054
5055 static void
5056 readtape(char *buffer)
5057 {
5058 int i, j;
5059
5060 ++tapepos;
5061 if (recno >= nblock || first) {
5062 if (first) {
5063 /*
5064 * set the number of blocks to read initially, based on
5065 * the defined defaults for the device, or on the
5066 * explicit block factor given.
5067 */
5068 if (bflag || defaults_used || NotTape)
5069 j = nblock;
5070 else
5071 j = NBLOCK;
5072 } else
5073 j = nblock;
5074
5075 if ((i = read(mt, tbuf, TBLOCK*j)) < 0) {
5076 (void) fprintf(stderr, gettext(
5077 "tar: tape read error\n"));
5078 done(3);
5079 /*
5080 * i == 0 and !rflag means that EOF is reached and we are
5081 * trying to update or replace an empty tar file, so exit
5082 * with an error.
5083 *
5084 * If i == 0 and !first and NotTape, it means the pointer
5085 * has gone past the EOF. It could happen if two processes
5086 * try to update the same tar file simultaneously. So exit
5087 * with an error.
5088 */
5089
5090 } else if (i == 0) {
5091 if (first && !rflag) {
5092 (void) fprintf(stderr, gettext(
5093 "tar: blocksize = %d\n"), i);
5094 done(Errflg);
5095 } else if (!first && (!rflag || NotTape)) {
5096 mterr("read", 0, 2);
5097 }
5098 } else if ((!first || Bflag) && i != TBLOCK*j) {
5099 /*
5100 * Short read - try to get the remaining bytes.
5101 */
5102
5103 int remaining = (TBLOCK * j) - i;
5104 char *b = (char *)tbuf + i;
5105 int r;
5106
5107 do {
5108 if ((r = read(mt, b, remaining)) < 0) {
5109 (void) fprintf(stderr,
5110 gettext("tar: tape read error\n"));
5111 done(3);
5112 }
5113 b += r;
5114 remaining -= r;
5115 i += r;
5116 } while (remaining > 0 && r != 0);
5117 }
5118 if (first) {
5119 if ((i % TBLOCK) != 0) {
5120 (void) fprintf(stderr, gettext(
5121 "tar: tape blocksize error\n"));
5122 done(3);
5123 }
5124 i /= TBLOCK;
5125 if (vflag && i != nblock && i != 1) {
5126 if (!NotTape)
5127 (void) fprintf(stderr, gettext(
5128 "tar: blocksize = %d\n"), i);
5129 }
5130
5131 /*
5132 * If we are reading a tape, then a short read is
5133 * understood to signify that the amount read is
5134 * the tape's actual blocking factor. We adapt
5135 * nblock accordingly. There is no reason to do
5136 * this when the device is not blocked.
5137 */
5138
5139 if (!NotTape)
5140 nblock = i;
5141 }
5142 recno = 0;
5143 }
5144
5145 first = FALSE;
5146 copy(buffer, &tbuf[recno++]);
5147 }
5148
5149
5150 /*
5151 * replacement for writetape.
5152 */
5153
5154 static int
5155 writetbuf(char *buffer, int n)
5156 {
5157 int i;
5158
5159 tapepos += n; /* output block count */
5160
5161 if (recno >= nblock) {
5162 i = write(mt, (char *)tbuf, TBLOCK*nblock);
5163 if (i != TBLOCK*nblock)
5164 mterr("write", i, 2);
5165 recno = 0;
5166 }
5167
5168 /*
5169 * Special case: We have an empty tape buffer, and the
5170 * users data size is >= the tape block size: Avoid
5171 * the bcopy and dma direct to tape. BIG WIN. Add the
5172 * residual to the tape buffer.
5173 */
5174 while (recno == 0 && n >= nblock) {
5175 i = (int)write(mt, buffer, TBLOCK*nblock);
5176 if (i != TBLOCK*nblock)
5177 mterr("write", i, 2);
5178 n -= nblock;
5179 buffer += (nblock * TBLOCK);
5180 }
5181
5182 while (n-- > 0) {
5183 (void) memcpy((char *)&tbuf[recno++], buffer, TBLOCK);
5184 buffer += TBLOCK;
5185 if (recno >= nblock) {
5186 i = (int)write(mt, (char *)tbuf, TBLOCK*nblock);
5187 if (i != TBLOCK*nblock)
5188 mterr("write", i, 2);
5189 recno = 0;
5190 }
5191 }
5192
5193 /* Tell the user how much to write to get in sync */
5194 return (nblock - recno);
5195 }
5196
5197 /*
5198 * backtape - reposition tape after reading soft "EOF" record
5199 *
5200 * Backtape tries to reposition the tape back over the EOF
5201 * record. This is for the 'u' and 'r' function letters so that the
5202 * tape can be extended. This code is not well designed, but
5203 * I'm confident that the only callers who care about the
5204 * backspace-over-EOF feature are those involved in 'u' and 'r'.
5205 *
5206 * The proper way to backup the tape is through the use of mtio.
5207 * Earlier spins used lseek combined with reads in a confusing
5208 * maneuver that only worked on 4.x, but shouldn't have, even
5209 * there. Lseeks are explicitly not supported for tape devices.
5210 */
5211
5212 static void
5213 backtape(void)
5214 {
5215 struct mtop mtcmd;
5216 #ifdef DEBUG
5217 DEBUG("backtape() called, recno=%" FMT_blkcnt_t " nblock=%d\n", recno,
5218 nblock);
5219 #endif
5220 /*
5221 * Backup to the position in the archive where the record
5222 * currently sitting in the tbuf buffer is situated.
5223 */
5224
5225 if (NotTape) {
5226 /*
5227 * For non-tape devices, this means lseeking to the
5228 * correct position. The absolute location tapepos-recno
5229 * should be the beginning of the current record.
5230 */
5231
5232 if (lseek(mt, (off_t)(TBLOCK*(tapepos-recno)), SEEK_SET) ==
5233 (off_t)-1) {
5234 (void) fprintf(stderr,
5235 gettext("tar: lseek to end of archive failed\n"));
5236 done(4);
5237 }
5238 } else {
5239 /*
5240 * For tape devices, we backup over the most recently
5241 * read record.
5242 */
5243
5244 mtcmd.mt_op = MTBSR;
5245 mtcmd.mt_count = 1;
5246
5247 if (ioctl(mt, MTIOCTOP, &mtcmd) < 0) {
5248 (void) fprintf(stderr,
5249 gettext("tar: backspace over record failed\n"));
5250 done(4);
5251 }
5252 }
5253
5254 /*
5255 * Decrement the tape and tbuf buffer indices to prepare for the
5256 * coming write to overwrite the soft EOF record.
5257 */
5258
5259 recno--;
5260 tapepos--;
5261 }
5262
5263
5264 /*
5265 * flushtape write buffered block(s) onto tape
5266 *
5267 * recno points to next free block in tbuf. If nonzero, a write is done.
5268 * Care is taken to write in multiples of SYS_BLOCK when device is
5269 * non-magtape in case raw i/o is used.
5270 *
5271 * NOTE: this is called by writetape() to do the actual writing
5272 */
5273
5274 static void
5275 flushtape(void)
5276 {
5277 #ifdef DEBUG
5278 DEBUG("flushtape() called, recno=%" FMT_blkcnt_t "\n", recno, 0);
5279 #endif
5280 if (recno > 0) { /* anything buffered? */
5281 if (NotTape) {
5282 #if SYS_BLOCK > TBLOCK
5283 int i;
5284
5285 /*
5286 * an odd-block write can only happen when
5287 * we are at the end of a volume that is not a tape.
5288 * Here we round recno up to an even SYS_BLOCK
5289 * boundary.
5290 */
5291 if ((i = recno % (SYS_BLOCK / TBLOCK)) != 0) {
5292 #ifdef DEBUG
5293 DEBUG("flushtape() %d rounding blocks\n", i, 0);
5294 #endif
5295 recno += i; /* round up to even SYS_BLOCK */
5296 }
5297 #endif
5298 if (recno > nblock)
5299 recno = nblock;
5300 }
5301 #ifdef DEBUG
5302 DEBUG("writing out %" FMT_blkcnt_t " blocks of %" FMT_blkcnt_t
5303 " bytes\n", (blkcnt_t)(NotTape ? recno : nblock),
5304 (blkcnt_t)(NotTape ? recno : nblock) * TBLOCK);
5305 #endif
5306 if (write(mt, tbuf,
5307 (size_t)(NotTape ? recno : nblock) * TBLOCK) < 0) {
5308 (void) fprintf(stderr, gettext(
5309 "tar: tape write error\n"));
5310 done(2);
5311 }
5312 recno = 0;
5313 }
5314 }
5315
5316 static void
5317 copy(void *dst, void *src)
5318 {
5319 (void) memcpy(dst, src, TBLOCK);
5320 }
5321
5322 /*
5323 * kcheck()
5324 * - checks the validity of size values for non-tape devices
5325 * - if size is zero, mulvol tar is disabled and size is
5326 * assumed to be infinite.
5327 * - returns volume size in TBLOCKS
5328 */
5329
5330 static blkcnt_t
5331 kcheck(char *kstr)
5332 {
5333 blkcnt_t kval;
5334
5335 kval = strtoll(kstr, NULL, 0);
5336 if (kval == (blkcnt_t)0) { /* no multi-volume; size is infinity. */
5337 mulvol = 0; /* definitely not mulvol, but we must */
5338 return (0); /* took out setting of NotTape */
5339 }
5340 if (kval < (blkcnt_t)MINSIZE) {
5341 (void) fprintf(stderr, gettext(
5342 "tar: sizes below %luK not supported (%" FMT_blkcnt_t
5343 ").\n"), (ulong_t)MINSIZE, kval);
5344 (void) fprintf(stderr, gettext(
5345 "bad size entry for %s in %s.\n"),
5346 archive, DEF_FILE);
5347 done(1);
5348 }
5349 mulvol++;
5350 NotTape++; /* implies non-tape */
5351 return (kval * 1024 / TBLOCK); /* convert to TBLOCKS */
5352 }
5353
5354
5355 /*
5356 * bcheck()
5357 * - checks the validity of blocking factors
5358 * - returns blocking factor
5359 */
5360
5361 static int
5362 bcheck(char *bstr)
5363 {
5364 blkcnt_t bval;
5365
5366 bval = strtoll(bstr, NULL, 0);
5367 if ((bval <= 0) || (bval > INT_MAX / TBLOCK)) {
5368 (void) fprintf(stderr, gettext(
5369 "tar: invalid blocksize \"%s\".\n"), bstr);
5370 if (!bflag)
5371 (void) fprintf(stderr, gettext(
5372 "bad blocksize entry for '%s' in %s.\n"),
5373 archive, DEF_FILE);
5374 done(1);
5375 }
5376
5377 return ((int)bval);
5378 }
5379
5380
5381 /*
5382 * defset()
5383 * - reads DEF_FILE for the set of default values specified.
5384 * - initializes 'usefile', 'nblock', and 'blocklim', and 'NotTape'.
5385 * - 'usefile' points to static data, so will be overwritten
5386 * if this routine is called a second time.
5387 * - the pattern specified by 'arch' must be followed by four
5388 * blank-separated fields (1) device (2) blocking,
5389 * (3) size(K), and (4) tape
5390 * for example: archive0=/dev/fd 1 400 n
5391 */
5392
5393 static int
5394 defset(char *arch)
5395 {
5396 char *bp;
5397
5398 if (defopen(DEF_FILE) != 0)
5399 return (FALSE);
5400 if (defcntl(DC_SETFLAGS, (DC_STD & ~(DC_CASE))) == -1) {
5401 (void) fprintf(stderr, gettext(
5402 "tar: error setting parameters for %s.\n"), DEF_FILE);
5403 return (FALSE); /* & following ones too */
5404 }
5405 if ((bp = defread(arch)) == NULL) {
5406 (void) fprintf(stderr, gettext(
5407 "tar: missing or invalid '%s' entry in %s.\n"),
5408 arch, DEF_FILE);
5409 return (FALSE);
5410 }
5411 if ((usefile = strtok(bp, " \t")) == NULL) {
5412 (void) fprintf(stderr, gettext(
5413 "tar: '%s' entry in %s is empty!\n"), arch, DEF_FILE);
5414 return (FALSE);
5415 }
5416 if ((bp = strtok(NULL, " \t")) == NULL) {
5417 (void) fprintf(stderr, gettext(
5418 "tar: block component missing in '%s' entry in %s.\n"),
5419 arch, DEF_FILE);
5420 return (FALSE);
5421 }
5422 nblock = bcheck(bp);
5423 if ((bp = strtok(NULL, " \t")) == NULL) {
5424 (void) fprintf(stderr, gettext(
5425 "tar: size component missing in '%s' entry in %s.\n"),
5426 arch, DEF_FILE);
5427 return (FALSE);
5428 }
5429 blocklim = kcheck(bp);
5430 if ((bp = strtok(NULL, " \t")) != NULL)
5431 NotTape = (*bp == 'n' || *bp == 'N');
5432 else
5433 NotTape = (blocklim != 0);
5434 (void) defopen(NULL);
5435 #ifdef DEBUG
5436 DEBUG("defset: archive='%s'; usefile='%s'\n", arch, usefile);
5437 DEBUG("defset: nblock='%d'; blocklim='%" FMT_blkcnt_t "'\n",
5438 nblock, blocklim);
5439 DEBUG("defset: not tape = %d\n", NotTape, 0);
5440 #endif
5441 return (TRUE);
5442 }
5443
5444
5445 /*
5446 * Following code handles excluded and included files.
5447 * A hash table of file names to be {in,ex}cluded is built.
5448 * For excluded files, before writing or extracting a file
5449 * check to see if it is in the exclude_tbl.
5450 * For included files, the wantit() procedure will check to
5451 * see if the named file is in the include_tbl.
5452 */
5453
5454 static void
5455 build_table(file_list_t *table[], char *file)
5456 {
5457 FILE *fp;
5458 char buf[PATH_MAX + 1];
5459
5460 if ((fp = fopen(file, "r")) == (FILE *)NULL)
5461 vperror(1, gettext("could not open %s"), file);
5462 while (fgets(buf, sizeof (buf), fp) != NULL) {
5463 if (buf[strlen(buf) - 1] == '\n')
5464 buf[strlen(buf) - 1] = '\0';
5465 /* Only add to table if line has something in it */
5466 if (strspn(buf, " \t") != strlen(buf))
5467 add_file_to_table(table, buf);
5468 }
5469 (void) fclose(fp);
5470 }
5471
5472
5473 /*
5474 * Add a file name to the the specified table, if the file name has any
5475 * trailing '/'s then delete them before inserting into the table
5476 */
5477
5478 static void
5479 add_file_to_table(file_list_t *table[], char *str)
5480 {
5481 char name[PATH_MAX + 1];
5482 unsigned int h;
5483 file_list_t *exp;
5484
5485 (void) strcpy(name, str);
5486 while (name[strlen(name) - 1] == '/') {
5487 name[strlen(name) - 1] = NULL;
5488 }
5489
5490 h = hash(name);
5491 if ((exp = (file_list_t *)calloc(sizeof (file_list_t),
5492 sizeof (char))) == NULL) {
5493 (void) fprintf(stderr, gettext(
5494 "tar: out of memory, exclude/include table(entry)\n"));
5495 exit(1);
5496 }
5497
5498 if ((exp->name = strdup(name)) == NULL) {
5499 (void) fprintf(stderr, gettext(
5500 "tar: out of memory, exclude/include table(file name)\n"));
5501 exit(1);
5502 }
5503
5504 exp->next = table[h];
5505 table[h] = exp;
5506 }
5507
5508
5509 /*
5510 * See if a file name or any of the file's parent directories is in the
5511 * specified table, if the file name has any trailing '/'s then delete
5512 * them before searching the table
5513 */
5514
5515 static int
5516 is_in_table(file_list_t *table[], char *str)
5517 {
5518 char name[PATH_MAX + 1];
5519 unsigned int h;
5520 file_list_t *exp;
5521 char *ptr;
5522
5523 (void) strcpy(name, str);
5524 while (name[strlen(name) - 1] == '/') {
5525 name[strlen(name) - 1] = NULL;
5526 }
5527
5528 /*
5529 * check for the file name in the passed list
5530 */
5531 h = hash(name);
5532 exp = table[h];
5533 while (exp != NULL) {
5534 if (strcmp(name, exp->name) == 0) {
5535 return (1);
5536 }
5537 exp = exp->next;
5538 }
5539
5540 /*
5541 * check for any parent directories in the file list
5542 */
5543 while ((ptr = strrchr(name, '/'))) {
5544 *ptr = NULL;
5545 h = hash(name);
5546 exp = table[h];
5547 while (exp != NULL) {
5548 if (strcmp(name, exp->name) == 0) {
5549 return (1);
5550 }
5551 exp = exp->next;
5552 }
5553 }
5554
5555 return (0);
5556 }
5557
5558
5559 /*
5560 * Compute a hash from a string.
5561 */
5562
5563 static unsigned int
5564 hash(char *str)
5565 {
5566 char *cp;
5567 unsigned int h;
5568
5569 h = 0;
5570 for (cp = str; *cp; cp++) {
5571 h += *cp;
5572 }
5573 return (h % TABLE_SIZE);
5574 }
5575
5576 static void *
5577 getmem(size_t size)
5578 {
5579 void *p = calloc((unsigned)size, sizeof (char));
5580
5581 if (p == NULL && freemem) {
5582 (void) fprintf(stderr, gettext(
5583 "tar: out of memory, link and directory modtime "
5584 "info lost\n"));
5585 freemem = 0;
5586 if (errflag)
5587 done(1);
5588 else
5589 Errflg = 1;
5590 }
5591 return (p);
5592 }
5593
5594 /*
5595 * vperror() --variable argument perror.
5596 * Takes 3 args: exit_status, formats, args. If exit_status is 0, then
5597 * the errflag (exit on error) is checked -- if it is non-zero, tar exits
5598 * with the value of whatever "errno" is set to. If exit_status is not
5599 * zero, then tar exits with that error status. If errflag and exit_status
5600 * are both zero, the routine returns to where it was called and sets Errflg
5601 * to errno.
5602 */
5603
5604 static void
5605 vperror(int exit_status, char *fmt, ...)
5606 {
5607 va_list ap;
5608
5609 va_start(ap, fmt);
5610 (void) fputs("tar: ", stderr);
5611 (void) vfprintf(stderr, fmt, ap);
5612 (void) fprintf(stderr, ": %s\n", strerror(errno));
5613 va_end(ap);
5614 if (exit_status)
5615 done(exit_status);
5616 else
5617 if (errflag)
5618 done(errno);
5619 else
5620 Errflg = errno;
5621 }
5622
5623
5624 static void
5625 fatal(char *format, ...)
5626 {
5627 va_list ap;
5628
5629 va_start(ap, format);
5630 (void) fprintf(stderr, "tar: ");
5631 (void) vfprintf(stderr, format, ap);
5632 (void) fprintf(stderr, "\n");
5633 va_end(ap);
5634 done(1);
5635 }
5636
5637
5638 /*
5639 * Check to make sure that argument is a char * ptr.
5640 * Actually, we just check to see that it is non-null.
5641 * If it is null, print out the message and call usage(), bailing out.
5642 */
5643
5644 static void
5645 assert_string(char *s, char *msg)
5646 {
5647 if (s == NULL) {
5648 (void) fprintf(stderr, msg);
5649 usage();
5650 }
5651 }
5652
5653
5654 static void
5655 mterr(char *operation, int i, int exitcode)
5656 {
5657 (void) fprintf(stderr, gettext(
5658 "tar: %s error: "), operation);
5659 if (i < 0)
5660 perror("");
5661 else
5662 (void) fprintf(stderr, gettext("unexpected EOF\n"));
5663 done(exitcode);
5664 }
5665
5666 static int
5667 wantit(char *argv[], char **namep, char **dirp, char **component,
5668 attr_data_t **attrinfo)
5669 {
5670 char **cp;
5671 int gotit; /* true if we've found a match */
5672 int ret;
5673
5674 top:
5675 if (xhdr_flgs & _X_XHDR) {
5676 xhdr_flgs = 0;
5677 }
5678 getdir();
5679 if (Xhdrflag > 0) {
5680 ret = get_xdata();
5681 if (ret != 0) { /* Xhdr items and regular header */
5682 setbytes_to_skip(&stbuf, ret);
5683 passtape();
5684 return (0); /* Error--don't want to extract */
5685 }
5686 }
5687
5688 /*
5689 * If typeflag is not 'A' and xhdr_flgs is set, then processing
5690 * of ancillary file is either over or ancillary file
5691 * processing is not required, load info from Xtarhdr and set
5692 * _X_XHDR bit in xhdr_flgs.
5693 */
5694 if ((dblock.dbuf.typeflag != 'A') && (xhdr_flgs != 0)) {
5695 load_info_from_xtarhdr(xhdr_flgs, &Xtarhdr);
5696 xhdr_flgs |= _X_XHDR;
5697 }
5698
5699 #if defined(O_XATTR)
5700 if (dblock.dbuf.typeflag == _XATTR_HDRTYPE && xattrbadhead == 0) {
5701 /*
5702 * Always needs to read the extended header. If atflag, saflag,
5703 * or tflag isn't set, then we'll have the correct info for
5704 * passtape() later.
5705 */
5706 (void) read_xattr_hdr(attrinfo);
5707 goto top;
5708 }
5709 /*
5710 * Now that we've read the extended header, call passtape()
5711 * if we don't want to restore attributes or system attributes.
5712 * Don't restore the attribute if we are extracting
5713 * a file from an archive (as opposed to doing a table of
5714 * contents) and any of the following are true:
5715 * 1. neither -@ or -/ was specified.
5716 * 2. -@ was specified, -/ wasn't specified, and we're
5717 * processing a hidden attribute directory of an attribute
5718 * or we're processing a read-write system attribute file.
5719 * 3. -@ wasn't specified, -/ was specified, and the file
5720 * we're processing is not a read-write system attribute file,
5721 * or we're processing the hidden attribute directory of an
5722 * attribute.
5723 *
5724 * We always process the attributes if we're just generating
5725 * generating a table of contents, or if both -@ and -/ were
5726 * specified.
5727 */
5728 if (xattrp != NULL) {
5729 attr_data_t *ainfo = *attrinfo;
5730
5731 if (!tflag &&
5732 ((!atflag && !saflag) ||
5733 (atflag && !saflag && ((ainfo->attr_parent != NULL) ||
5734 ainfo->attr_rw_sysattr)) ||
5735 (!atflag && saflag && ((ainfo->attr_parent != NULL) ||
5736 !ainfo->attr_rw_sysattr)))) {
5737 passtape();
5738 return (0);
5739 }
5740 }
5741 #endif
5742
5743 /* sets *namep to point at the proper name */
5744 if (check_prefix(namep, dirp, component) != 0) {
5745 passtape();
5746 return (0);
5747 }
5748
5749 if (endtape()) {
5750 if (Bflag) {
5751 /*
5752 * Logically at EOT - consume any extra blocks
5753 * so that write to our stdin won't fail and
5754 * emit an error message; otherwise something
5755 * like "dd if=foo.tar | (cd bar; tar xvf -)"
5756 * will produce a bogus error message from "dd".
5757 */
5758
5759 while (read(mt, tbuf, TBLOCK*nblock) > 0) {
5760 /* empty body */
5761 }
5762 }
5763 return (-1);
5764 }
5765
5766 gotit = 0;
5767
5768 if ((Iflag && is_in_table(include_tbl, *namep)) ||
5769 (! Iflag && *argv == NULL)) {
5770 gotit = 1;
5771 } else {
5772 for (cp = argv; *cp; cp++) {
5773 if (is_prefix(*cp, *namep)) {
5774 gotit = 1;
5775 break;
5776 }
5777 }
5778 }
5779
5780 if (! gotit) {
5781 passtape();
5782 return (0);
5783 }
5784
5785 if (Xflag && is_in_table(exclude_tbl, *namep)) {
5786 if (vflag) {
5787 (void) fprintf(stderr, gettext("%s excluded\n"),
5788 *namep);
5789 }
5790 passtape();
5791 return (0);
5792 }
5793
5794 return (1);
5795 }
5796
5797
5798 static void
5799 setbytes_to_skip(struct stat *st, int err)
5800 {
5801 /*
5802 * In a scenario where a typeflag 'X' was followed by
5803 * a typeflag 'A' and typeflag 'O', then the number of
5804 * bytes to skip should be the size of ancillary file,
5805 * plus the dblock for regular file, and the size
5806 * from Xtarhdr. However, if the typeflag was just 'X'
5807 * followed by typeflag 'O', then the number of bytes
5808 * to skip should be the size from Xtarhdr.
5809 */
5810 if ((err != 0) && (dblock.dbuf.typeflag == 'A') &&
5811 (xhdr_flgs & _X_SIZE)) {
5812 st->st_size += TBLOCK + Xtarhdr.x_filesz;
5813 xhdr_flgs |= _X_XHDR;
5814 } else if ((dblock.dbuf.typeflag != 'A') &&
5815 (xhdr_flgs & _X_SIZE)) {
5816 st->st_size += Xtarhdr.x_filesz;
5817 xhdr_flgs |= _X_XHDR;
5818 }
5819 }
5820
5821 static int
5822 fill_in_attr_info(char *attr, char *longname, char *attrparent, int atparentfd,
5823 int rw_sysattr, attr_data_t **attrinfo)
5824 {
5825 size_t pathlen;
5826 char *tpath;
5827 char *tparent;
5828
5829 /* parent info */
5830 if (attrparent != NULL) {
5831 if ((tparent = strdup(attrparent)) == NULL) {
5832 vperror(0, gettext(
5833 "unable to allocate memory for attribute parent "
5834 "name for %sattribute %s/%s of %s"),
5835 rw_sysattr ? gettext("system ") : "",
5836 attrparent, attr, longname);
5837 return (1);
5838 }
5839 } else {
5840 tparent = NULL;
5841 }
5842
5843 /* path info */
5844 pathlen = strlen(attr) + 1;
5845 if (attrparent != NULL) {
5846 pathlen += strlen(attrparent) + 1; /* add 1 for '/' */
5847 }
5848 if ((tpath = calloc(1, pathlen)) == NULL) {
5849 vperror(0, gettext(
5850 "unable to allocate memory for full "
5851 "attribute path name for %sattribute %s%s%s of %s"),
5852 rw_sysattr ? gettext("system ") : "",
5853 (attrparent == NULL) ? "" : attrparent,
5854 (attrparent == NULL) ? "" : "/",
5855 attr, longname);
5856 if (tparent != NULL) {
5857 free(tparent);
5858 }
5859 return (1);
5860 }
5861 (void) snprintf(tpath, pathlen, "%s%s%s",
5862 (attrparent == NULL) ? "" : attrparent,
5863 (attrparent == NULL) ? "" : "/",
5864 attr);
5865
5866 /* fill in the attribute info */
5867 if (*attrinfo == NULL) {
5868 if ((*attrinfo = malloc(sizeof (attr_data_t))) == NULL) {
5869 vperror(0, gettext(
5870 "unable to allocate memory for attribute "
5871 "information for %sattribute %s%s%s of %s"),
5872 rw_sysattr ? gettext("system ") : "",
5873 (attrparent == NULL) ? "" : attrparent,
5874 (attrparent == NULL) ? "" : gettext("/"),
5875 attr, longname);
5876 if (tparent != NULL) {
5877 free(tparent);
5878 }
5879 free(tpath);
5880 return (1);
5881 }
5882 } else {
5883 if ((*attrinfo)->attr_parent != NULL) {
5884 free((*attrinfo)->attr_parent);
5885 }
5886 if ((*attrinfo)->attr_path != NULL) {
5887 free((*attrinfo)->attr_path);
5888 }
5889 /*
5890 * The parent file descriptor is passed in, so don't
5891 * close it here as it should be closed by the function
5892 * that opened it.
5893 */
5894 }
5895 (*attrinfo)->attr_parent = tparent;
5896 (*attrinfo)->attr_path = tpath;
5897 (*attrinfo)->attr_rw_sysattr = rw_sysattr;
5898 (*attrinfo)->attr_parentfd = atparentfd;
5899
5900 return (0);
5901 }
5902
5903 /*
5904 * Test to see if name is a directory.
5905 *
5906 * Return 1 if true, 0 otherwise.
5907 */
5908
5909 static int
5910 is_directory(char *name)
5911 {
5912 #if defined(O_XATTR)
5913 /*
5914 * If there is an xattr_buf structure associated with this file,
5915 * then the directory test is based on whether the name has a
5916 * trailing slash.
5917 */
5918 if (xattrp)
5919 return (name[strlen(name) - 1] == '/');
5920 #endif
5921 if (is_posix)
5922 return (dblock.dbuf.typeflag == '5');
5923 else
5924 return (name[strlen(name) - 1] == '/');
5925 }
5926
5927 /*
5928 * Version of chdir that handles directory pathnames of greater than PATH_MAX
5929 * length, by changing the working directory to manageable portions of the
5930 * complete directory pathname. If any of these attempts fail, then it exits
5931 * non-zero.
5932 *
5933 * If a segment (i.e. a portion of "path" between two "/"'s) of the overall
5934 * pathname is greater than PATH_MAX, then this still won't work, and this
5935 * routine will return -1 with errno set to ENAMETOOLONG.
5936 *
5937 * NOTE: this routine is semantically different to the system chdir in
5938 * that it is remotely possible for the currently working directory to be
5939 * changed to a different directory, if a chdir call fails when processing
5940 * one of the segments of a path that is greater than PATH_MAX. This isn't
5941 * a problem as this is tar's own specific version of chdir.
5942 */
5943
5944 static int
5945 tar_chdir(const char *path) {
5946 const char *sep = "/";
5947 char *path_copy = NULL;
5948 char *ptr = NULL;
5949
5950 /* The trivial case. */
5951 if (chdir(path) == 0) {
5952 return (0);
5953 }
5954 if (errno == ENAMETOOLONG) {
5955 if (path[0] == '/' && chdir(sep) != 0)
5956 return (-1);
5957
5958 /* strtok(3C) modifies the string, so make a copy. */
5959 if ((path_copy = strdup(path)) == NULL) {
5960 return (-1);
5961 }
5962
5963 /* chdir(2) for every path element. */
5964 for (ptr = strtok(path_copy, sep);
5965 ptr != NULL;
5966 ptr = strtok(NULL, sep)) {
5967 if (chdir(ptr) != 0) {
5968 free(path_copy);
5969 return (-1);
5970 }
5971 }
5972 free(path_copy);
5973 return (0);
5974 }
5975
5976 /* If chdir fails for any reason except ENAMETOOLONG. */
5977 return (-1);
5978 }
5979
5980 /*
5981 * Test if name has a '..' sequence in it.
5982 *
5983 * Return 1 if found, 0 otherwise.
5984 */
5985
5986 static int
5987 has_dot_dot(char *name)
5988 {
5989 char *s;
5990 size_t name_len = strlen(name);
5991
5992 for (s = name; s < (name + name_len - 2); s++) {
5993 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
5994 return (1);
5995
5996 while (! (*s == '/')) {
5997 if (! *s++)
5998 return (0);
5999 }
6000 }
6001
6002 return (0);
6003 }
6004
6005 /*
6006 * Test if name is an absolute path name.
6007 *
6008 * Return 1 if true, 0 otherwise.
6009 */
6010
6011 static int
6012 is_absolute(char *name)
6013 {
6014 #if defined(O_XATTR)
6015 /*
6016 * If this is an extended attribute (whose name will begin with
6017 * "/dev/null/", always return 0 as they should be extracted with
6018 * the name intact, to allow other tar archiving programs that
6019 * don't understand extended attributes, to correctly throw them away.
6020 */
6021 if (xattrp)
6022 return (0);
6023 #endif
6024
6025 return (name[0] == '/');
6026 }
6027
6028 /*
6029 * Adjust the pathname to make it a relative one. Strip off any leading
6030 * '/' characters and if the pathname contains any '..' sequences, strip
6031 * upto and including the last occurance of '../' (or '..' if found at
6032 * the very end of the pathname).
6033 *
6034 * Return the relative pathname. stripped_prefix will also return the
6035 * portion of name that was stripped off and should be freed by the
6036 * calling routine when no longer needed.
6037 */
6038
6039 static char *
6040 make_relative_name(char *name, char **stripped_prefix)
6041 {
6042 char *s;
6043 size_t prefix_len = 0;
6044 size_t name_len = strlen(name);
6045
6046 for (s = name + prefix_len; s < (name + name_len - 2); ) {
6047 if (s[0] == '.' && s[1] == '.' && ((s[2] == '/') || !s[2]))
6048 prefix_len = s + 2 - name;
6049
6050 do {
6051 char c = *s++;
6052
6053 if (c == '/')
6054 break;
6055 } while (*s);
6056 }
6057
6058 for (s = name + prefix_len; *s == '/'; s++)
6059 continue;
6060 prefix_len = s - name;
6061
6062 /* Create the portion of the name that was stripped off. */
6063 s = malloc(prefix_len + 1);
6064 memcpy(s, name, prefix_len);
6065 s[prefix_len] = 0;
6066 *stripped_prefix = s;
6067 s = &name[prefix_len];
6068
6069 return (s);
6070 }
6071
6072 /*
6073 * Return through *namep a pointer to the proper fullname (i.e "<name> |
6074 * <prefix>/<name>"), as represented in the header entry dblock.dbuf.
6075 *
6076 * Returns 0 if successful, otherwise returns 1.
6077 */
6078
6079 static int
6080 check_prefix(char **namep, char **dirp, char **compp)
6081 {
6082 static char fullname[PATH_MAX + 1];
6083 static char dir[PATH_MAX + 1];
6084 static char component[PATH_MAX + 1];
6085 static char savename[PATH_MAX + 1];
6086 char *s;
6087
6088 (void) memset(dir, 0, sizeof (dir));
6089 (void) memset(component, 0, sizeof (component));
6090
6091 if (xhdr_flgs & _X_PATH) {
6092 (void) strcpy(fullname, Xtarhdr.x_path);
6093 } else {
6094 if (dblock.dbuf.prefix[0] != '\0')
6095 (void) sprintf(fullname, "%.*s/%.*s", PRESIZ,
6096 dblock.dbuf.prefix, NAMSIZ, dblock.dbuf.name);
6097 else
6098 (void) sprintf(fullname, "%.*s", NAMSIZ,
6099 dblock.dbuf.name);
6100 }
6101
6102 /*
6103 * If we are printing a table of contents or extracting an archive,
6104 * make absolute pathnames relative and prohibit the unpacking of
6105 * files contain ".." in their name (unless the user has supplied
6106 * the -P option).
6107 */
6108 if ((tflag || xflag) && !Pflag) {
6109 if (is_absolute(fullname) || has_dot_dot(fullname)) {
6110 char *stripped_prefix;
6111 size_t prefix_len = 0;
6112
6113 (void) strcpy(savename, fullname);
6114 strcpy(fullname,
6115 make_relative_name(savename, &stripped_prefix));
6116 (void) fprintf(stderr,
6117 gettext("tar: Removing leading '%s' from '%s'\n"),
6118 stripped_prefix, savename);
6119 free(stripped_prefix);
6120 }
6121 }
6122
6123 /*
6124 * Set dir and component names
6125 */
6126
6127 get_parent(fullname, dir);
6128
6129 #if defined(O_XATTR)
6130 if (xattrp == NULL) {
6131 #endif
6132 /*
6133 * Save of real name since were going to chop off the
6134 * trailing slashes.
6135 */
6136 (void) strcpy(savename, fullname);
6137 /*
6138 * first strip of trailing slashes.
6139 */
6140 chop_endslashes(savename);
6141 s = get_component(savename);
6142 (void) strcpy(component, s);
6143
6144 #if defined(O_XATTR)
6145 } else {
6146 (void) strcpy(fullname, xattrp->h_names);
6147 (void) strcpy(dir, fullname);
6148 (void) strcpy(component, basename(xattrp->h_names +
6149 strlen(xattrp->h_names) + 1));
6150 }
6151 #endif
6152 *namep = fullname;
6153 *dirp = dir;
6154 *compp = component;
6155
6156 return (0);
6157 }
6158
6159 /*
6160 * Return true if the object indicated by the file descriptor and type
6161 * is a tape device, false otherwise
6162 */
6163
6164 static int
6165 istape(int fd, int type)
6166 {
6167 int result = 0;
6168
6169 if (S_ISCHR(type)) {
6170 struct mtget mtg;
6171
6172 if (ioctl(fd, MTIOCGET, &mtg) != -1) {
6173 result = 1;
6174 }
6175 }
6176
6177 return (result);
6178 }
6179
6180 #include <utmpx.h>
6181
6182 struct utmpx utmpx;
6183
6184 #define NMAX (sizeof (utmpx.ut_name))
6185
6186 typedef struct cachenode { /* this struct must be zeroed before using */
6187 struct cachenode *next; /* next in hash chain */
6188 int val; /* the uid or gid of this entry */
6189 int namehash; /* name's hash signature */
6190 char name[NMAX+1]; /* the string that val maps to */
6191 } cachenode_t;
6192
6193 #define HASHSIZE 256
6194
6195 static cachenode_t *names[HASHSIZE];
6196 static cachenode_t *groups[HASHSIZE];
6197 static cachenode_t *uids[HASHSIZE];
6198 static cachenode_t *gids[HASHSIZE];
6199
6200 static int
6201 hash_byname(char *name)
6202 {
6203 int i, c, h = 0;
6204
6205 for (i = 0; i < NMAX; i++) {
6206 c = name[i];
6207 if (c == '\0')
6208 break;
6209 h = (h << 4) + h + c;
6210 }
6211 return (h);
6212 }
6213
6214 static cachenode_t *
6215 hash_lookup_byval(cachenode_t *table[], int val)
6216 {
6217 int h = val;
6218 cachenode_t *c;
6219
6220 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6221 if (c->val == val)
6222 return (c);
6223 }
6224 return (NULL);
6225 }
6226
6227 static cachenode_t *
6228 hash_lookup_byname(cachenode_t *table[], char *name)
6229 {
6230 int h = hash_byname(name);
6231 cachenode_t *c;
6232
6233 for (c = table[h & (HASHSIZE - 1)]; c != NULL; c = c->next) {
6234 if (c->namehash == h && strcmp(c->name, name) == 0)
6235 return (c);
6236 }
6237 return (NULL);
6238 }
6239
6240 static cachenode_t *
6241 hash_insert(cachenode_t *table[], char *name, int value)
6242 {
6243 cachenode_t *c;
6244 int signature;
6245
6246 c = calloc(1, sizeof (cachenode_t));
6247 if (c == NULL) {
6248 perror("malloc");
6249 exit(1);
6250 }
6251 if (name != NULL) {
6252 (void) strncpy(c->name, name, NMAX);
6253 c->namehash = hash_byname(name);
6254 }
6255 c->val = value;
6256 if (table == uids || table == gids)
6257 signature = c->val;
6258 else
6259 signature = c->namehash;
6260 c->next = table[signature & (HASHSIZE - 1)];
6261 table[signature & (HASHSIZE - 1)] = c;
6262 return (c);
6263 }
6264
6265 static char *
6266 getname(uid_t uid)
6267 {
6268 cachenode_t *c;
6269
6270 if ((c = hash_lookup_byval(uids, uid)) == NULL) {
6271 struct passwd *pwent = getpwuid(uid);
6272 c = hash_insert(uids, pwent ? pwent->pw_name : NULL, uid);
6273 }
6274 return (c->name);
6275 }
6276
6277 static char *
6278 getgroup(gid_t gid)
6279 {
6280 cachenode_t *c;
6281
6282 if ((c = hash_lookup_byval(gids, gid)) == NULL) {
6283 struct group *grent = getgrgid(gid);
6284 c = hash_insert(gids, grent ? grent->gr_name : NULL, gid);
6285 }
6286 return (c->name);
6287 }
6288
6289 static uid_t
6290 getuidbyname(char *name)
6291 {
6292 cachenode_t *c;
6293
6294 if ((c = hash_lookup_byname(names, name)) == NULL) {
6295 struct passwd *pwent = getpwnam(name);
6296 c = hash_insert(names, name, pwent ? (int)pwent->pw_uid : -1);
6297 }
6298 return ((uid_t)c->val);
6299 }
6300
6301 static gid_t
6302 getgidbyname(char *group)
6303 {
6304 cachenode_t *c;
6305
6306 if ((c = hash_lookup_byname(groups, group)) == NULL) {
6307 struct group *grent = getgrnam(group);
6308 c = hash_insert(groups, group, grent ? (int)grent->gr_gid : -1);
6309 }
6310 return ((gid_t)c->val);
6311 }
6312
6313 /*
6314 * Build the header.
6315 * Determine whether or not an extended header is also needed. If needed,
6316 * create and write the extended header and its data.
6317 * Writing of the extended header assumes that "tomodes" has been called and
6318 * the relevant information has been placed in the header block.
6319 */
6320
6321 static int
6322 build_dblock(
6323 const char *name,
6324 const char *linkname,
6325 const char typeflag,
6326 const int filetype,
6327 const struct stat *sp,
6328 const dev_t device,
6329 const char *prefix)
6330 {
6331 int nblks;
6332 major_t dev;
6333 const char *filename;
6334 const char *lastslash;
6335
6336 if (filetype == XATTR_FILE)
6337 dblock.dbuf.typeflag = _XATTR_HDRTYPE;
6338 else
6339 dblock.dbuf.typeflag = typeflag;
6340 (void) memset(dblock.dbuf.name, '\0', NAMSIZ);
6341 (void) memset(dblock.dbuf.linkname, '\0', NAMSIZ);
6342 (void) memset(dblock.dbuf.prefix, '\0', PRESIZ);
6343
6344 if (xhdr_flgs & _X_PATH)
6345 filename = Xtarhdr.x_path;
6346 else
6347 filename = name;
6348
6349 if ((dev = major(device)) > OCTAL7CHAR) {
6350 if (Eflag) {
6351 xhdr_flgs |= _X_DEVMAJOR;
6352 Xtarhdr.x_devmajor = dev;
6353 } else {
6354 (void) fprintf(stderr, gettext(
6355 "Device major too large for %s. Use -E flag."),
6356 filename);
6357 if (errflag)
6358 done(1);
6359 else
6360 Errflg = 1;
6361 }
6362 dev = 0;
6363 }
6364 (void) sprintf(dblock.dbuf.devmajor, "%07lo", dev);
6365 if ((dev = minor(device)) > OCTAL7CHAR) {
6366 if (Eflag) {
6367 xhdr_flgs |= _X_DEVMINOR;
6368 Xtarhdr.x_devminor = dev;
6369 } else {
6370 (void) fprintf(stderr, gettext(
6371 "Device minor too large for %s. Use -E flag."),
6372 filename);
6373 if (errflag)
6374 done(1);
6375 else
6376 Errflg = 1;
6377 }
6378 dev = 0;
6379 }
6380 (void) sprintf(dblock.dbuf.devminor, "%07lo", dev);
6381
6382 (void) strncpy(dblock.dbuf.name, name, NAMSIZ);
6383 (void) strncpy(dblock.dbuf.linkname, linkname, NAMSIZ);
6384 (void) sprintf(dblock.dbuf.magic, "%.5s", magic_type);
6385 (void) sprintf(dblock.dbuf.version, "00");
6386 (void) sprintf(dblock.dbuf.uname, "%.31s", getname(sp->st_uid));
6387 (void) sprintf(dblock.dbuf.gname, "%.31s", getgroup(sp->st_gid));
6388 (void) strncpy(dblock.dbuf.prefix, prefix, PRESIZ);
6389 (void) sprintf(dblock.dbuf.chksum, "%07o", checksum(&dblock));
6390
6391 if (Eflag) {
6392 (void) bcopy(dblock.dummy, xhdr_buf.dummy, TBLOCK);
6393 (void) memset(xhdr_buf.dbuf.name, '\0', NAMSIZ);
6394 lastslash = strrchr(name, '/');
6395 if (lastslash == NULL)
6396 lastslash = name;
6397 else
6398 lastslash++;
6399 (void) strcpy(xhdr_buf.dbuf.name, lastslash);
6400 (void) memset(xhdr_buf.dbuf.linkname, '\0', NAMSIZ);
6401 (void) memset(xhdr_buf.dbuf.prefix, '\0', PRESIZ);
6402 (void) strcpy(xhdr_buf.dbuf.prefix, xhdr_dirname);
6403 xhdr_count++;
6404 xrec_offset = 0;
6405 gen_date("mtime", sp->st_mtim);
6406 xhdr_buf.dbuf.typeflag = 'X';
6407 if (gen_utf8_names(filename) != 0)
6408 return (1);
6409
6410 #ifdef XHDR_DEBUG
6411 Xtarhdr.x_uname = dblock.dbuf.uname;
6412 Xtarhdr.x_gname = dblock.dbuf.gname;
6413 xhdr_flgs |= (_X_UNAME | _X_GNAME);
6414 #endif
6415 if (xhdr_flgs) {
6416 if (xhdr_flgs & _X_DEVMAJOR)
6417 gen_num("SUN.devmajor", Xtarhdr.x_devmajor);
6418 if (xhdr_flgs & _X_DEVMINOR)
6419 gen_num("SUN.devminor", Xtarhdr.x_devminor);
6420 if (xhdr_flgs & _X_GID)
6421 gen_num("gid", Xtarhdr.x_gid);
6422 if (xhdr_flgs & _X_UID)
6423 gen_num("uid", Xtarhdr.x_uid);
6424 if (xhdr_flgs & _X_SIZE)
6425 gen_num("size", Xtarhdr.x_filesz);
6426 if (xhdr_flgs & _X_PATH)
6427 gen_string("path", Xtarhdr.x_path);
6428 if (xhdr_flgs & _X_LINKPATH)
6429 gen_string("linkpath", Xtarhdr.x_linkpath);
6430 if (xhdr_flgs & _X_GNAME)
6431 gen_string("gname", Xtarhdr.x_gname);
6432 if (xhdr_flgs & _X_UNAME)
6433 gen_string("uname", Xtarhdr.x_uname);
6434 }
6435 (void) sprintf(xhdr_buf.dbuf.size,
6436 "%011" FMT_off_t_o, xrec_offset);
6437 (void) sprintf(xhdr_buf.dbuf.chksum, "%07o",
6438 checksum(&xhdr_buf));
6439 (void) writetbuf((char *)&xhdr_buf, 1);
6440 nblks = TBLOCKS(xrec_offset);
6441 (void) writetbuf(xrec_ptr, nblks);
6442 }
6443 return (0);
6444 }
6445
6446
6447 /*
6448 * makeDir - ensure that a directory with the pathname denoted by name
6449 * exists, and return 1 on success, and 0 on failure (e.g.,
6450 * read-only file system, exists but not-a-directory).
6451 */
6452
6453 static int
6454 makeDir(char *name)
6455 {
6456 struct stat buf;
6457
6458 if (access(name, 0) < 0) { /* name doesn't exist */
6459 if (mkdir(name, 0777) < 0) {
6460 vperror(0, "%s", name);
6461 return (0);
6462 }
6463 } else { /* name exists */
6464 if (stat(name, &buf) < 0) {
6465 vperror(0, "%s", name);
6466 return (0);
6467 }
6468
6469 return ((buf.st_mode & S_IFMT) == S_IFDIR);
6470 }
6471
6472 return (1);
6473 }
6474
6475
6476 /*
6477 * Save this directory and its mtime on the stack, popping and setting
6478 * the mtimes of any stacked dirs which aren't parents of this one.
6479 * A null name causes the entire stack to be unwound and set.
6480 *
6481 * Since all the elements of the directory "stack" share a common
6482 * prefix, we can make do with one string. We keep only the current
6483 * directory path, with an associated array of mtime's. A negative
6484 * mtime means no mtime.
6485 *
6486 * This stack algorithm is not guaranteed to work for tapes created
6487 * with the 'r' function letter, but the vast majority of tapes with
6488 * directories are not. This avoids saving every directory record on
6489 * the tape and setting all the times at the end.
6490 *
6491 * (This was borrowed from the 4.1.3 source, and adapted to the 5.x
6492 * environment)
6493 */
6494
6495 static void
6496 doDirTimes(char *name, timestruc_t modTime)
6497 {
6498 static char dirstack[PATH_MAX+2];
6499 /* Add spaces for the last slash and last NULL */
6500 static timestruc_t modtimes[PATH_MAX+1]; /* hash table */
6501 char *p = dirstack;
6502 char *q = name;
6503 char *savp;
6504
6505 if (q) {
6506 /*
6507 * Find common prefix
6508 */
6509
6510 while (*p == *q && *p) {
6511 p++; q++;
6512 }
6513 }
6514
6515 savp = p;
6516 while (*p) {
6517 /*
6518 * Not a child: unwind the stack, setting the times.
6519 * The order we do this doesn't matter, so we go "forward."
6520 */
6521
6522 if (*p == '/')
6523 if (modtimes[p - dirstack].tv_sec >= 0) {
6524 *p = '\0'; /* zap the slash */
6525 setPathTimes(AT_FDCWD, dirstack,
6526 modtimes[p - dirstack]);
6527 *p = '/';
6528 }
6529 ++p;
6530 }
6531
6532 p = savp;
6533
6534 /*
6535 * Push this one on the "stack"
6536 */
6537
6538 if (q) {
6539
6540 /*
6541 * Since the name parameter points the dir pathname
6542 * which is limited only to contain PATH_MAX chars
6543 * at maximum, we can ignore the overflow case of p.
6544 */
6545
6546 while ((*p = *q++)) { /* append the rest of the new dir */
6547 modtimes[p - dirstack].tv_sec = -1;
6548 p++;
6549 }
6550
6551 /*
6552 * If the tar file had used 'P' or 'E' function modifier,
6553 * append the last slash.
6554 */
6555 if (*(p - 1) != '/') {
6556 *p++ = '/';
6557 *p = '\0';
6558 }
6559 /* overwrite the last one */
6560 modtimes[p - dirstack - 1] = modTime;
6561 }
6562 }
6563
6564
6565 /*
6566 * setPathTimes - set the modification time for given path. Return 1 if
6567 * successful and 0 if not successful.
6568 */
6569
6570 static void
6571 setPathTimes(int dirfd, char *path, timestruc_t modTime)
6572
6573 {
6574 struct timeval timebuf[2];
6575
6576 /*
6577 * futimesat takes an array of two timeval structs.
6578 * The first entry contains access time.
6579 * The second entry contains modification time.
6580 * Unlike a timestruc_t, which uses nanoseconds, timeval uses
6581 * microseconds.
6582 */
6583 timebuf[0].tv_sec = time((time_t *)0);
6584 timebuf[0].tv_usec = 0;
6585 timebuf[1].tv_sec = modTime.tv_sec;
6586
6587 /* Extended header: use microseconds */
6588 timebuf[1].tv_usec = (xhdr_flgs & _X_MTIME) ? modTime.tv_nsec/1000 : 0;
6589
6590 if (futimesat(dirfd, path, timebuf) < 0)
6591 vperror(0, gettext("can't set time on %s"), path);
6592 }
6593
6594
6595 /*
6596 * If hflag is set then delete the symbolic link's target.
6597 * If !hflag then delete the target.
6598 */
6599
6600 static void
6601 delete_target(int fd, char *comp, char *namep)
6602 {
6603 struct stat xtractbuf;
6604 char buf[PATH_MAX + 1];
6605 int n;
6606
6607
6608 if (unlinkat(fd, comp, AT_REMOVEDIR) < 0) {
6609 if (errno == ENOTDIR && !hflag) {
6610 (void) unlinkat(fd, comp, 0);
6611 } else if (errno == ENOTDIR && hflag) {
6612 if (!lstat(namep, &xtractbuf)) {
6613 if ((xtractbuf.st_mode & S_IFMT) != S_IFLNK) {
6614 (void) unlinkat(fd, comp, 0);
6615 } else if ((n = readlink(namep, buf,
6616 PATH_MAX)) != -1) {
6617 buf[n] = (char)NULL;
6618 (void) unlinkat(fd, buf,
6619 AT_REMOVEDIR);
6620 if (errno == ENOTDIR)
6621 (void) unlinkat(fd, buf, 0);
6622 } else {
6623 (void) unlinkat(fd, comp, 0);
6624 }
6625 } else {
6626 (void) unlinkat(fd, comp, 0);
6627 }
6628 }
6629 }
6630 }
6631
6632
6633 /*
6634 * ACL changes:
6635 * putfile():
6636 * Get acl info after stat. Write out ancillary file
6637 * before the normal file, i.e. directory, regular, FIFO,
6638 * link, special. If acl count is less than 4, no need to
6639 * create ancillary file. (i.e. standard permission is in
6640 * use.
6641 * doxtract():
6642 * Process ancillary file. Read it in and set acl info.
6643 * watch out for 'o' function modifier.
6644 * 't' function letter to display table
6645 */
6646
6647 /*
6648 * New functions for ACLs and other security attributes
6649 */
6650
6651 /*
6652 * The function appends the new security attribute info to the end of
6653 * existing secinfo.
6654 */
6655 int
6656 append_secattr(
6657 char **secinfo, /* existing security info */
6658 int *secinfo_len, /* length of existing security info */
6659 int size, /* new attribute size: unit depends on type */
6660 char *attrtext, /* new attribute text */
6661 char attr_type) /* new attribute type */
6662 {
6663 char *new_secinfo;
6664 int newattrsize;
6665 int oldsize;
6666 struct sec_attr *attr;
6667
6668 /* no need to add */
6669 if (attr_type != DIR_TYPE) {
6670 if (attrtext == NULL)
6671 return (0);
6672 }
6673
6674 switch (attr_type) {
6675 case UFSD_ACL:
6676 case ACE_ACL:
6677 if (attrtext == NULL) {
6678 (void) fprintf(stderr, gettext("acltotext failed\n"));
6679 return (-1);
6680 }
6681 /* header: type + size = 8 */
6682 newattrsize = 8 + (int)strlen(attrtext) + 1;
6683 attr = (struct sec_attr *)malloc(newattrsize);
6684 if (attr == NULL) {
6685 (void) fprintf(stderr,
6686 gettext("can't allocate memory\n"));
6687 return (-1);
6688 }
6689 attr->attr_type = attr_type;
6690 (void) sprintf(attr->attr_len,
6691 "%06o", size); /* acl entry count */
6692 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6693 free(attrtext);
6694 break;
6695
6696 /* Trusted Extensions */
6697 case DIR_TYPE:
6698 case LBL_TYPE:
6699 newattrsize = sizeof (struct sec_attr) + strlen(attrtext);
6700 attr = (struct sec_attr *)malloc(newattrsize);
6701 if (attr == NULL) {
6702 (void) fprintf(stderr,
6703 gettext("can't allocate memory\n"));
6704 return (-1);
6705 }
6706 attr->attr_type = attr_type;
6707 (void) sprintf(attr->attr_len,
6708 "%06d", size); /* len of attr data */
6709 (void) strcpy((char *)&attr->attr_info[0], attrtext);
6710 break;
6711
6712 default:
6713 (void) fprintf(stderr,
6714 gettext("unrecognized attribute type\n"));
6715 return (-1);
6716 }
6717
6718 /* old security info + new attr header(8) + new attr */
6719 oldsize = *secinfo_len;
6720 *secinfo_len += newattrsize;
6721 new_secinfo = (char *)malloc(*secinfo_len);
6722 if (new_secinfo == NULL) {
6723 (void) fprintf(stderr, gettext("can't allocate memory\n"));
6724 *secinfo_len -= newattrsize;
6725 free(attr);
6726 return (-1);
6727 }
6728
6729 (void) memcpy(new_secinfo, *secinfo, oldsize);
6730 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
6731
6732 free(*secinfo);
6733 free(attr);
6734 *secinfo = new_secinfo;
6735 return (0);
6736 }
6737
6738 /*
6739 * write_ancillary(): write out an ancillary file.
6740 * The file has the same header as normal file except the type and size
6741 * fields. The type is 'A' and size is the sum of all attributes
6742 * in bytes.
6743 * The body contains a list of attribute type, size and info. Currently,
6744 * there is only ACL info. This file is put before the normal file.
6745 */
6746 void
6747 write_ancillary(union hblock *dblockp, char *secinfo, int len, char hdrtype)
6748 {
6749 long blocks;
6750 int savflag;
6751 int savsize;
6752
6753 /* Just tranditional permissions or no security attribute info */
6754 if (len == 0 || secinfo == NULL)
6755 return;
6756
6757 /* save flag and size */
6758 savflag = (dblockp->dbuf).typeflag;
6759 (void) sscanf(dblockp->dbuf.size, "%12o", (uint_t *)&savsize);
6760
6761 /* special flag for ancillary file */
6762 if (hdrtype == _XATTR_HDRTYPE)
6763 dblockp->dbuf.typeflag = _XATTR_HDRTYPE;
6764 else
6765 dblockp->dbuf.typeflag = 'A';
6766
6767 /* for pre-2.5 versions of tar, need to make sure */
6768 /* the ACL file is readable */
6769 (void) sprintf(dblock.dbuf.mode, "%07lo",
6770 (stbuf.st_mode & POSIXMODES) | 0000200);
6771 (void) sprintf(dblockp->dbuf.size, "%011o", len);
6772 (void) sprintf(dblockp->dbuf.chksum, "%07o", checksum(dblockp));
6773
6774 /* write out the header */
6775 (void) writetbuf((char *)dblockp, 1);
6776
6777 /* write out security info */
6778 blocks = TBLOCKS(len);
6779 (void) writetbuf((char *)secinfo, (int)blocks);
6780
6781 /* restore mode, flag and size */
6782 (void) sprintf(dblock.dbuf.mode, "%07lo", stbuf.st_mode & POSIXMODES);
6783 dblockp->dbuf.typeflag = savflag;
6784 (void) sprintf(dblockp->dbuf.size, "%011o", savsize);
6785 }
6786
6787 /*
6788 * Read the data record for extended headers and then the regular header.
6789 * The data are read into the buffer and then null-terminated. Entries
6790 * for typeflag 'X' extended headers are of the format:
6791 * "%d %s=%s\n"
6792 *
6793 * When an extended header record is found, the extended header must
6794 * be processed and its values used to override the values in the
6795 * normal header. The way this is done is to process the extended
6796 * header data record and set the data values, then call getdir
6797 * to process the regular header, then then to reconcile the two
6798 * sets of data.
6799 */
6800
6801 static int
6802 get_xdata(void)
6803 {
6804 struct keylist_pair {
6805 int keynum;
6806 char *keylist;
6807 } keylist_pair[] = { _X_DEVMAJOR, "SUN.devmajor",
6808 _X_DEVMINOR, "SUN.devminor",
6809 _X_GID, "gid",
6810 _X_GNAME, "gname",
6811 _X_LINKPATH, "linkpath",
6812 _X_PATH, "path",
6813 _X_SIZE, "size",
6814 _X_UID, "uid",
6815 _X_UNAME, "uname",
6816 _X_MTIME, "mtime",
6817 _X_LAST, "NULL" };
6818 char *lineloc;
6819 int length, i;
6820 char *keyword, *value;
6821 blkcnt_t nblocks;
6822 int bufneeded;
6823 int errors;
6824
6825 (void) memset(&Xtarhdr, 0, sizeof (Xtarhdr));
6826 xhdr_count++;
6827 errors = 0;
6828
6829 nblocks = TBLOCKS(stbuf.st_size);
6830 bufneeded = nblocks * TBLOCK;
6831 if (bufneeded >= xrec_size) {
6832 free(xrec_ptr);
6833 xrec_size = bufneeded + 1;
6834 if ((xrec_ptr = malloc(xrec_size)) == NULL)
6835 fatal(gettext("cannot allocate buffer"));
6836 }
6837
6838 lineloc = xrec_ptr;
6839
6840 while (nblocks-- > 0) {
6841 readtape(lineloc);
6842 lineloc += TBLOCK;
6843 }
6844 lineloc = xrec_ptr;
6845 xrec_ptr[stbuf.st_size] = '\0';
6846 while (lineloc < xrec_ptr + stbuf.st_size) {
6847 if (dblock.dbuf.typeflag == 'L') {
6848 length = xrec_size;
6849 keyword = "path";
6850 value = lineloc;
6851 } else {
6852 length = atoi(lineloc);
6853 *(lineloc + length - 1) = '\0';
6854 keyword = strchr(lineloc, ' ') + 1;
6855 value = strchr(keyword, '=') + 1;
6856 *(value - 1) = '\0';
6857 }
6858 i = 0;
6859 lineloc += length;
6860 while (keylist_pair[i].keynum != (int)_X_LAST) {
6861 if (strcmp(keyword, keylist_pair[i].keylist) == 0)
6862 break;
6863 i++;
6864 }
6865 errno = 0;
6866 switch (keylist_pair[i].keynum) {
6867 case _X_DEVMAJOR:
6868 Xtarhdr.x_devmajor = (major_t)strtoul(value, NULL, 0);
6869 if (errno) {
6870 (void) fprintf(stderr, gettext(
6871 "tar: Extended header major value error "
6872 "for file # %llu.\n"), xhdr_count);
6873 errors++;
6874 } else
6875 xhdr_flgs |= _X_DEVMAJOR;
6876 break;
6877 case _X_DEVMINOR:
6878 Xtarhdr.x_devminor = (minor_t)strtoul(value, NULL, 0);
6879 if (errno) {
6880 (void) fprintf(stderr, gettext(
6881 "tar: Extended header minor value error "
6882 "for file # %llu.\n"), xhdr_count);
6883 errors++;
6884 } else
6885 xhdr_flgs |= _X_DEVMINOR;
6886 break;
6887 case _X_GID:
6888 xhdr_flgs |= _X_GID;
6889 Xtarhdr.x_gid = strtol(value, NULL, 0);
6890 if ((errno) || (Xtarhdr.x_gid > UID_MAX)) {
6891 (void) fprintf(stderr, gettext(
6892 "tar: Extended header gid value error "
6893 "for file # %llu.\n"), xhdr_count);
6894 Xtarhdr.x_gid = GID_NOBODY;
6895 }
6896 break;
6897 case _X_GNAME:
6898 if (utf8_local("gname", &Xtarhdr.x_gname,
6899 local_gname, value, _POSIX_NAME_MAX) == 0)
6900 xhdr_flgs |= _X_GNAME;
6901 break;
6902 case _X_LINKPATH:
6903 if (utf8_local("linkpath", &Xtarhdr.x_linkpath,
6904 local_linkpath, value, PATH_MAX) == 0)
6905 xhdr_flgs |= _X_LINKPATH;
6906 else
6907 errors++;
6908 break;
6909 case _X_PATH:
6910 if (utf8_local("path", &Xtarhdr.x_path,
6911 local_path, value, PATH_MAX) == 0)
6912 xhdr_flgs |= _X_PATH;
6913 else
6914 errors++;
6915 break;
6916 case _X_SIZE:
6917 Xtarhdr.x_filesz = strtoull(value, NULL, 0);
6918 if (errno) {
6919 (void) fprintf(stderr, gettext(
6920 "tar: Extended header invalid filesize "
6921 "for file # %llu.\n"), xhdr_count);
6922 errors++;
6923 } else
6924 xhdr_flgs |= _X_SIZE;
6925 break;
6926 case _X_UID:
6927 xhdr_flgs |= _X_UID;
6928 Xtarhdr.x_uid = strtol(value, NULL, 0);
6929 if ((errno) || (Xtarhdr.x_uid > UID_MAX)) {
6930 (void) fprintf(stderr, gettext(
6931 "tar: Extended header uid value error "
6932 "for file # %llu.\n"), xhdr_count);
6933 Xtarhdr.x_uid = UID_NOBODY;
6934 }
6935 break;
6936 case _X_UNAME:
6937 if (utf8_local("uname", &Xtarhdr.x_uname,
6938 local_uname, value, _POSIX_NAME_MAX) == 0)
6939 xhdr_flgs |= _X_UNAME;
6940 break;
6941 case _X_MTIME:
6942 get_xtime(value, &(Xtarhdr.x_mtime));
6943 if (errno)
6944 (void) fprintf(stderr, gettext(
6945 "tar: Extended header modification time "
6946 "value error for file # %llu.\n"),
6947 xhdr_count);
6948 else
6949 xhdr_flgs |= _X_MTIME;
6950 break;
6951 default:
6952 (void) fprintf(stderr,
6953 gettext("tar: unrecognized extended"
6954 " header keyword '%s'. Ignored.\n"), keyword);
6955 break;
6956 }
6957 }
6958
6959 getdir(); /* get regular header */
6960 if (errors && errflag)
6961 done(1);
6962 else
6963 if (errors)
6964 Errflg = 1;
6965 return (errors);
6966 }
6967
6968 /*
6969 * load_info_from_xtarhdr - sets Gen and stbuf variables from
6970 * extended header
6971 * load_info_from_xtarhdr(flag, xhdrp);
6972 * u_longlong_t flag; xhdr_flgs
6973 * struct xtar_hdr *xhdrp; pointer to extended header
6974 * NOTE: called when typeflag is not 'A' and xhdr_flgs
6975 * is set.
6976 */
6977 static void
6978 load_info_from_xtarhdr(u_longlong_t flag, struct xtar_hdr *xhdrp)
6979 {
6980 if (flag & _X_DEVMAJOR) {
6981 Gen.g_devmajor = xhdrp->x_devmajor;
6982 }
6983 if (flag & _X_DEVMINOR) {
6984 Gen.g_devminor = xhdrp->x_devminor;
6985 }
6986 if (flag & _X_GID) {
6987 Gen.g_gid = xhdrp->x_gid;
6988 stbuf.st_gid = xhdrp->x_gid;
6989 }
6990 if (flag & _X_UID) {
6991 Gen.g_uid = xhdrp->x_uid;
6992 stbuf.st_uid = xhdrp->x_uid;
6993 }
6994 if (flag & _X_SIZE) {
6995 Gen.g_filesz = xhdrp->x_filesz;
6996 stbuf.st_size = xhdrp->x_filesz;
6997 }
6998 if (flag & _X_MTIME) {
6999 Gen.g_mtime = xhdrp->x_mtime.tv_sec;
7000 stbuf.st_mtim.tv_sec = xhdrp->x_mtime.tv_sec;
7001 stbuf.st_mtim.tv_nsec = xhdrp->x_mtime.tv_nsec;
7002 }
7003 }
7004
7005 /*
7006 * gen_num creates a string from a keyword and an usigned long long in the
7007 * format: %d %s=%s\n
7008 * This is part of the extended header data record.
7009 */
7010
7011 void
7012 gen_num(const char *keyword, const u_longlong_t number)
7013 {
7014 char save_val[ULONGLONG_MAX_DIGITS + 1];
7015 int len;
7016 char *curr_ptr;
7017
7018 (void) sprintf(save_val, "%llu", number);
7019 /*
7020 * len = length of entire line, including itself. len will be
7021 * two digits. So, add the string lengths plus the length of len,
7022 * plus a blank, an equal sign, and a newline.
7023 */
7024 len = strlen(save_val) + strlen(keyword) + 5;
7025 if (xrec_offset + len > xrec_size) {
7026 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7027 fatal(gettext(
7028 "cannot allocate extended header buffer"));
7029 xrec_ptr = curr_ptr;
7030 xrec_size *= 2;
7031 }
7032 (void) sprintf(&xrec_ptr[xrec_offset],
7033 "%d %s=%s\n", len, keyword, save_val);
7034 xrec_offset += len;
7035 }
7036
7037 /*
7038 * gen_date creates a string from a keyword and a timestruc_t in the
7039 * format: %d %s=%s\n
7040 * This is part of the extended header data record.
7041 * Currently, granularity is only microseconds, so the low-order three digits
7042 * will be truncated.
7043 */
7044
7045 void
7046 gen_date(const char *keyword, const timestruc_t time_value)
7047 {
7048 /* Allow for <seconds>.<nanoseconds>\n */
7049 char save_val[TIME_MAX_DIGITS + LONG_MAX_DIGITS + 2];
7050 int len;
7051 char *curr_ptr;
7052
7053 (void) sprintf(save_val, "%ld", time_value.tv_sec);
7054 len = strlen(save_val);
7055 save_val[len] = '.';
7056 (void) sprintf(&save_val[len + 1], "%9.9ld", time_value.tv_nsec);
7057
7058 /*
7059 * len = length of entire line, including itself. len will be
7060 * two digits. So, add the string lengths plus the length of len,
7061 * plus a blank, an equal sign, and a newline.
7062 */
7063 len = strlen(save_val) + strlen(keyword) + 5;
7064 if (xrec_offset + len > xrec_size) {
7065 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7066 fatal(gettext(
7067 "cannot allocate extended header buffer"));
7068 xrec_ptr = curr_ptr;
7069 xrec_size *= 2;
7070 }
7071 (void) sprintf(&xrec_ptr[xrec_offset],
7072 "%d %s=%s\n", len, keyword, save_val);
7073 xrec_offset += len;
7074 }
7075
7076 /*
7077 * gen_string creates a string from a keyword and a char * in the
7078 * format: %d %s=%s\n
7079 * This is part of the extended header data record.
7080 */
7081
7082 void
7083 gen_string(const char *keyword, const char *value)
7084 {
7085 int len;
7086 char *curr_ptr;
7087
7088 /*
7089 * len = length of entire line, including itself. The character length
7090 * of len must be 1-4 characters, because the maximum size of the path
7091 * or the name is PATH_MAX, which is 1024. So, assume 1 character
7092 * for len, one for the space, one for the "=", and one for the newline.
7093 * Then adjust as needed.
7094 */
7095 /* LINTED constant expression */
7096 assert(PATH_MAX <= 9996);
7097 len = strlen(value) + strlen(keyword) + 4;
7098 if (len > 997)
7099 len += 3;
7100 else if (len > 98)
7101 len += 2;
7102 else if (len > 9)
7103 len += 1;
7104 if (xrec_offset + len > xrec_size) {
7105 if (((curr_ptr = realloc(xrec_ptr, 2 * xrec_size)) == NULL))
7106 fatal(gettext(
7107 "cannot allocate extended header buffer"));
7108 xrec_ptr = curr_ptr;
7109 xrec_size *= 2;
7110 }
7111 #ifdef XHDR_DEBUG
7112 if (strcmp(keyword+1, "name") != 0)
7113 #endif
7114 (void) sprintf(&xrec_ptr[xrec_offset],
7115 "%d %s=%s\n", len, keyword, value);
7116 #ifdef XHDR_DEBUG
7117 else {
7118 len += 11;
7119 (void) sprintf(&xrec_ptr[xrec_offset],
7120 "%d %s=%snametoolong\n", len, keyword, value);
7121 }
7122 #endif
7123 xrec_offset += len;
7124 }
7125
7126 /*
7127 * Convert time found in the extended header data to seconds and nanoseconds.
7128 */
7129
7130 void
7131 get_xtime(char *value, timestruc_t *xtime)
7132 {
7133 char nanosec[10];
7134 char *period;
7135 int i;
7136
7137 (void) memset(nanosec, '0', 9);
7138 nanosec[9] = '\0';
7139
7140 period = strchr(value, '.');
7141 if (period != NULL)
7142 period[0] = '\0';
7143 xtime->tv_sec = strtol(value, NULL, 10);
7144 if (period == NULL)
7145 xtime->tv_nsec = 0;
7146 else {
7147 i = strlen(period +1);
7148 (void) strncpy(nanosec, period + 1, min(i, 9));
7149 xtime->tv_nsec = strtol(nanosec, NULL, 10);
7150 }
7151 }
7152
7153 /*
7154 * Check linkpath for length.
7155 * Emit an error message and return 1 if too long.
7156 */
7157
7158 int
7159 chk_path_build(
7160 char *name,
7161 char *longname,
7162 char *linkname,
7163 char *prefix,
7164 char type,
7165 int filetype)
7166 {
7167
7168 if (strlen(linkname) > (size_t)NAMSIZ) {
7169 if (Eflag > 0) {
7170 xhdr_flgs |= _X_LINKPATH;
7171 Xtarhdr.x_linkpath = linkname;
7172 } else {
7173 (void) fprintf(stderr, gettext(
7174 "tar: %s: linked to %s\n"), longname, linkname);
7175 (void) fprintf(stderr, gettext(
7176 "tar: %s: linked name too long\n"), linkname);
7177 if (errflag)
7178 done(1);
7179 else
7180 Errflg = 1;
7181 return (1);
7182 }
7183 }
7184 if (xhdr_flgs & _X_LINKPATH)
7185 return (build_dblock(name, tchar, type,
7186 filetype, &stbuf, stbuf.st_dev,
7187 prefix));
7188 else
7189 return (build_dblock(name, linkname, type,
7190 filetype, &stbuf, stbuf.st_dev, prefix));
7191 }
7192
7193 /*
7194 * Convert from UTF-8 to local character set.
7195 */
7196
7197 static int
7198 utf8_local(
7199 char *option,
7200 char **Xhdr_ptrptr,
7201 char *target,
7202 const char *source,
7203 int max_val)
7204 {
7205 static iconv_t iconv_cd;
7206 char *nl_target;
7207 const char *iconv_src;
7208 char *iconv_trg;
7209 size_t inlen;
7210 size_t outlen;
7211
7212 if (charset_type == -1) { /* iconv_open failed in earlier try */
7213 (void) fprintf(stderr, gettext(
7214 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7215 xhdr_count, source);
7216 return (1);
7217 } else if (charset_type == 0) { /* iconv_open has not yet been done */
7218 nl_target = nl_langinfo(CODESET);
7219 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7220 nl_target = "646";
7221 if (strcmp(nl_target, "646") == 0)
7222 charset_type = 1;
7223 else if (strcmp(nl_target, "UTF-8") == 0)
7224 charset_type = 3;
7225 else {
7226 if (strncmp(nl_target, "ISO", 3) == 0)
7227 nl_target += 3;
7228 charset_type = 2;
7229 errno = 0;
7230 if ((iconv_cd = iconv_open(nl_target, "UTF-8")) ==
7231 (iconv_t)-1) {
7232 if (errno == EINVAL)
7233 (void) fprintf(stderr, gettext(
7234 "tar: conversion routines not "
7235 "available for current locale. "));
7236 (void) fprintf(stderr, gettext(
7237 "file # %llu: (%s) UTF-8 conversion"
7238 " failed.\n"), xhdr_count, source);
7239 charset_type = -1;
7240 return (1);
7241 }
7242 }
7243 }
7244
7245 /* locale using 7-bit codeset or UTF-8 locale */
7246 if (charset_type == 1 || charset_type == 3) {
7247 if (strlen(source) > max_val) {
7248 (void) fprintf(stderr, gettext(
7249 "tar: file # %llu: Extended header %s too long.\n"),
7250 xhdr_count, option);
7251 return (1);
7252 }
7253 if (charset_type == 3)
7254 (void) strcpy(target, source);
7255 else if (c_utf8(target, source) != 0) {
7256 (void) fprintf(stderr, gettext(
7257 "tar: file # %llu: (%s) UTF-8 conversion"
7258 " failed.\n"), xhdr_count, source);
7259 return (1);
7260 }
7261 *Xhdr_ptrptr = target;
7262 return (0);
7263 }
7264
7265 iconv_src = source;
7266 iconv_trg = target;
7267 inlen = strlen(source);
7268 outlen = max_val * UTF_8_FACTOR;
7269 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7270 (size_t)-1) { /* Error occurred: didn't convert */
7271 (void) fprintf(stderr, gettext(
7272 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7273 xhdr_count, source);
7274 /* Get remaining output; reinitialize conversion descriptor */
7275 iconv_src = (const char *)NULL;
7276 inlen = 0;
7277 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7278 return (1);
7279 }
7280 /* Get remaining output; reinitialize conversion descriptor */
7281 iconv_src = (const char *)NULL;
7282 inlen = 0;
7283 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7284 (size_t)-1) { /* Error occurred: didn't convert */
7285 (void) fprintf(stderr, gettext(
7286 "tar: file # %llu: (%s) UTF-8 conversion failed.\n"),
7287 xhdr_count, source);
7288 return (1);
7289 }
7290
7291 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7292 if (strlen(target) > max_val) {
7293 (void) fprintf(stderr, gettext(
7294 "tar: file # %llu: Extended header %s too long.\n"),
7295 xhdr_count, option);
7296 return (1);
7297 }
7298 *Xhdr_ptrptr = target;
7299 return (0);
7300 }
7301
7302 /*
7303 * Check gname, uname, path, and linkpath to see if they need to go in an
7304 * extended header. If they are already slated to be in an extended header,
7305 * or if they are not ascii, then they need to be in the extended header.
7306 * Then, convert all extended names to UTF-8.
7307 */
7308
7309 int
7310 gen_utf8_names(const char *filename)
7311 {
7312 static iconv_t iconv_cd;
7313 char *nl_target;
7314 char tempbuf[MAXNAM + 1];
7315 int nbytes;
7316 int errors;
7317
7318 if (charset_type == -1) { /* Previous failure to open. */
7319 (void) fprintf(stderr, gettext(
7320 "tar: file # %llu: UTF-8 conversion failed.\n"),
7321 xhdr_count);
7322 return (1);
7323 }
7324
7325 if (charset_type == 0) { /* Need to get conversion descriptor */
7326 nl_target = nl_langinfo(CODESET);
7327 if (strlen(nl_target) == 0) /* locale using 7-bit codeset */
7328 nl_target = "646";
7329 if (strcmp(nl_target, "646") == 0)
7330 charset_type = 1;
7331 else if (strcmp(nl_target, "UTF-8") == 0)
7332 charset_type = 3;
7333 else {
7334 if (strncmp(nl_target, "ISO", 3) == 0)
7335 nl_target += 3;
7336 charset_type = 2;
7337 errno = 0;
7338 #ifdef ICONV_DEBUG
7339 (void) fprintf(stderr,
7340 gettext("Opening iconv_cd with target %s\n"),
7341 nl_target);
7342 #endif
7343 if ((iconv_cd = iconv_open("UTF-8", nl_target)) ==
7344 (iconv_t)-1) {
7345 if (errno == EINVAL)
7346 (void) fprintf(stderr, gettext(
7347 "tar: conversion routines not "
7348 "available for current locale. "));
7349 (void) fprintf(stderr, gettext(
7350 "file (%s): UTF-8 conversion failed.\n"),
7351 filename);
7352 charset_type = -1;
7353 return (1);
7354 }
7355 }
7356 }
7357
7358 errors = 0;
7359
7360 errors += local_utf8(&Xtarhdr.x_gname, local_gname,
7361 dblock.dbuf.gname, iconv_cd, _X_GNAME, _POSIX_NAME_MAX);
7362 errors += local_utf8(&Xtarhdr.x_uname, local_uname,
7363 dblock.dbuf.uname, iconv_cd, _X_UNAME, _POSIX_NAME_MAX);
7364 if ((xhdr_flgs & _X_LINKPATH) == 0) { /* Need null-terminated str. */
7365 (void) strncpy(tempbuf, dblock.dbuf.linkname, NAMSIZ);
7366 tempbuf[NAMSIZ] = '\0';
7367 }
7368 errors += local_utf8(&Xtarhdr.x_linkpath, local_linkpath,
7369 tempbuf, iconv_cd, _X_LINKPATH, PATH_MAX);
7370 if ((xhdr_flgs & _X_PATH) == 0) { /* Concatenate prefix & name */
7371 (void) strncpy(tempbuf, dblock.dbuf.prefix, PRESIZ);
7372 tempbuf[PRESIZ] = '\0';
7373 nbytes = strlen(tempbuf);
7374 if (nbytes > 0) {
7375 tempbuf[nbytes++] = '/';
7376 tempbuf[nbytes] = '\0';
7377 }
7378 (void) strncat(tempbuf + nbytes, dblock.dbuf.name,
7379 (MAXNAM - nbytes));
7380 tempbuf[MAXNAM] = '\0';
7381 }
7382 errors += local_utf8(&Xtarhdr.x_path, local_path,
7383 tempbuf, iconv_cd, _X_PATH, PATH_MAX);
7384
7385 if (errors > 0)
7386 (void) fprintf(stderr, gettext(
7387 "tar: file (%s): UTF-8 conversion failed.\n"), filename);
7388
7389 if (errors && errflag)
7390 done(1);
7391 else
7392 if (errors)
7393 Errflg = 1;
7394 return (errors);
7395 }
7396
7397 static int
7398 local_utf8(
7399 char **Xhdr_ptrptr,
7400 char *target,
7401 const char *source,
7402 iconv_t iconv_cd,
7403 int xhdrflg,
7404 int max_val)
7405 {
7406 const char *iconv_src;
7407 const char *starting_src;
7408 char *iconv_trg;
7409 size_t inlen;
7410 size_t outlen;
7411 #ifdef ICONV_DEBUG
7412 unsigned char c_to_hex;
7413 #endif
7414
7415 /*
7416 * If the item is already slated for extended format, get the string
7417 * to convert from the extended header record. Otherwise, get it from
7418 * the regular (dblock) area.
7419 */
7420 if (xhdr_flgs & xhdrflg) {
7421 if (charset_type == 3) { /* Already UTF-8, just copy */
7422 (void) strcpy(target, *Xhdr_ptrptr);
7423 *Xhdr_ptrptr = target;
7424 return (0);
7425 } else
7426 iconv_src = (const char *) *Xhdr_ptrptr;
7427 } else {
7428 if (charset_type == 3) /* Already in UTF-8 format */
7429 return (0); /* Don't create xhdr record */
7430 iconv_src = source;
7431 }
7432 starting_src = iconv_src;
7433 iconv_trg = target;
7434 if ((inlen = strlen(iconv_src)) == 0)
7435 return (0);
7436
7437 if (charset_type == 1) { /* locale using 7-bit codeset */
7438 if (c_utf8(target, starting_src) != 0) {
7439 (void) fprintf(stderr,
7440 gettext("tar: invalid character in"
7441 " UTF-8 conversion of '%s'\n"), starting_src);
7442 return (1);
7443 }
7444 return (0);
7445 }
7446
7447 outlen = max_val * UTF_8_FACTOR;
7448 errno = 0;
7449 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7450 (size_t)-1) {
7451 /* An error occurred, or not all characters were converted */
7452 if (errno == EILSEQ)
7453 (void) fprintf(stderr,
7454 gettext("tar: invalid character in"
7455 " UTF-8 conversion of '%s'\n"), starting_src);
7456 else
7457 (void) fprintf(stderr, gettext(
7458 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7459 starting_src);
7460 /* Get remaining output; reinitialize conversion descriptor */
7461 iconv_src = (const char *)NULL;
7462 inlen = 0;
7463 (void) iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen);
7464 return (1);
7465 }
7466 /* Get remaining output; reinitialize conversion descriptor */
7467 iconv_src = (const char *)NULL;
7468 inlen = 0;
7469 if (iconv(iconv_cd, &iconv_src, &inlen, &iconv_trg, &outlen) ==
7470 (size_t)-1) { /* Error occurred: didn't convert */
7471 if (errno == EILSEQ)
7472 (void) fprintf(stderr,
7473 gettext("tar: invalid character in"
7474 " UTF-8 conversion of '%s'\n"), starting_src);
7475 else
7476 (void) fprintf(stderr, gettext(
7477 "tar: conversion to UTF-8 aborted for '%s'.\n"),
7478 starting_src);
7479 return (1);
7480 }
7481
7482 *iconv_trg = '\0'; /* Null-terminate iconv output string */
7483 if (strcmp(starting_src, target) != 0) {
7484 *Xhdr_ptrptr = target;
7485 xhdr_flgs |= xhdrflg;
7486 #ifdef ICONV_DEBUG
7487 (void) fprintf(stderr, "*** inlen: %d %d; outlen: %d %d\n",
7488 strlen(starting_src), inlen, max_val, outlen);
7489 (void) fprintf(stderr, "Input string:\n ");
7490 for (inlen = 0; inlen < strlen(starting_src); inlen++) {
7491 c_to_hex = (unsigned char)starting_src[inlen];
7492 (void) fprintf(stderr, " %2.2x", c_to_hex);
7493 if (inlen % 20 == 19)
7494 (void) fprintf(stderr, "\n ");
7495 }
7496 (void) fprintf(stderr, "\nOutput string:\n ");
7497 for (inlen = 0; inlen < strlen(target); inlen++) {
7498 c_to_hex = (unsigned char)target[inlen];
7499 (void) fprintf(stderr, " %2.2x", c_to_hex);
7500 if (inlen % 20 == 19)
7501 (void) fprintf(stderr, "\n ");
7502 }
7503 (void) fprintf(stderr, "\n");
7504 #endif
7505 }
7506
7507 return (0);
7508 }
7509
7510 /*
7511 * Function to test each byte of the source string to make sure it is
7512 * in within bounds (value between 0 and 127).
7513 * If valid, copy source to target.
7514 */
7515
7516 int
7517 c_utf8(char *target, const char *source)
7518 {
7519 size_t len;
7520 const char *thischar;
7521
7522 len = strlen(source);
7523 thischar = source;
7524 while (len-- > 0) {
7525 if (!isascii((int)(*thischar++)))
7526 return (1);
7527 }
7528
7529 (void) strcpy(target, source);
7530 return (0);
7531 }
7532
7533
7534 #if defined(O_XATTR)
7535 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
7536
7537 static void
7538 prepare_xattr(
7539 char **attrbuf,
7540 char *filename,
7541 char *attrpath,
7542 char typeflag,
7543 struct linkbuf *linkinfo,
7544 int *rlen)
7545 {
7546 char *bufhead; /* ptr to full buffer */
7547 char *aptr;
7548 struct xattr_hdr *hptr; /* ptr to header in bufhead */
7549 struct xattr_buf *tptr; /* ptr to pathing pieces */
7550 int totalen; /* total buffer length */
7551 int len; /* length returned to user */
7552 int stringlen; /* length of filename + attr */
7553 /*
7554 * length of filename + attr
7555 * in link section
7556 */
7557 int linkstringlen;
7558 int complen; /* length of pathing section */
7559 int linklen; /* length of link section */
7560 int attrnames_index; /* attrnames starting index */
7561
7562 /*
7563 * Release previous buffer
7564 */
7565
7566 if (*attrbuf != (char *)NULL) {
7567 free(*attrbuf);
7568 *attrbuf = NULL;
7569 }
7570
7571 /*
7572 * First add in fixed size stuff
7573 */
7574 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
7575
7576 /*
7577 * Add space for two nulls
7578 */
7579 stringlen = strlen(attrpath) + strlen(filename) + 2;
7580 complen = stringlen + sizeof (struct xattr_buf);
7581
7582 len += stringlen;
7583
7584 /*
7585 * Now add on space for link info if any
7586 */
7587
7588 if (linkinfo != NULL) {
7589 /*
7590 * Again add space for two nulls
7591 */
7592 linkstringlen = strlen(linkinfo->pathname) +
7593 strlen(linkinfo->attrname) + 2;
7594 linklen = linkstringlen + sizeof (struct xattr_buf);
7595 len += linklen;
7596 } else {
7597 linklen = 0;
7598 }
7599
7600 /*
7601 * Now add padding to end to fill out TBLOCK
7602 *
7603 * Function returns size of real data and not size + padding.
7604 */
7605
7606 totalen = ROUNDTOTBLOCK(len);
7607
7608 if ((bufhead = calloc(1, totalen)) == NULL) {
7609 fatal(gettext("Out of memory."));
7610 }
7611
7612
7613 /*
7614 * Now we can fill in the necessary pieces
7615 */
7616
7617 /*
7618 * first fill in the fixed header
7619 */
7620 hptr = (struct xattr_hdr *)bufhead;
7621 (void) sprintf(hptr->h_version, "%s", XATTR_ARCH_VERS);
7622 (void) sprintf(hptr->h_component_len, "%0*d",
7623 sizeof (hptr->h_component_len) - 1, complen);
7624 (void) sprintf(hptr->h_link_component_len, "%0*d",
7625 sizeof (hptr->h_link_component_len) - 1, linklen);
7626 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
7627
7628 /*
7629 * Now fill in the filename + attrnames section
7630 * The filename and attrnames section can be composed of two or more
7631 * path segments separated by a null character. The first segment
7632 * is the path to the parent file that roots the entire sequence in
7633 * the normal name space. The remaining segments describes a path
7634 * rooted at the hidden extended attribute directory of the leaf file of
7635 * the previous segment, making it possible to name attributes on
7636 * attributes. Thus, if we are just archiving an extended attribute,
7637 * the second segment will contain the attribute name. If we are
7638 * archiving a system attribute of an extended attribute, then the
7639 * second segment will contain the attribute name, and a third segment
7640 * will contain the system attribute name. The attribute pathing
7641 * information is obtained from 'attrpath'.
7642 */
7643
7644 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
7645 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
7646 stringlen);
7647 (void) strcpy(tptr->h_names, filename);
7648 attrnames_index = strlen(filename) + 1;
7649 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
7650 tptr->h_typeflag = typeflag;
7651
7652 /*
7653 * Split the attrnames section into two segments if 'attrpath'
7654 * contains pathing information for a system attribute of an
7655 * extended attribute. We split them by replacing the '/' with
7656 * a '\0'.
7657 */
7658 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
7659 *aptr = '\0';
7660 }
7661
7662 /*
7663 * Now fill in the optional link section if we have one
7664 */
7665
7666 if (linkinfo != (struct linkbuf *)NULL) {
7667 tptr = (struct xattr_buf *)(bufhead +
7668 sizeof (struct xattr_hdr) + complen);
7669
7670 (void) sprintf(tptr->h_namesz, "%0*d",
7671 sizeof (tptr->h_namesz) - 1, linkstringlen);
7672 (void) strcpy(tptr->h_names, linkinfo->pathname);
7673 (void) strcpy(
7674 &tptr->h_names[strlen(linkinfo->pathname) + 1],
7675 linkinfo->attrname);
7676 tptr->h_typeflag = typeflag;
7677 }
7678 *attrbuf = (char *)bufhead;
7679 *rlen = len;
7680 }
7681
7682 #else
7683 static void
7684 prepare_xattr(
7685 char **attrbuf,
7686 char *filename,
7687 char *attrname,
7688 char typeflag,
7689 struct linkbuf *linkinfo,
7690 int *rlen)
7691 {
7692 *attrbuf = NULL;
7693 *rlen = 0;
7694 }
7695 #endif
7696
7697 int
7698 getstat(int dirfd, char *longname, char *shortname, char *attrparent)
7699 {
7700
7701 int i, j;
7702 int printerr;
7703 int slnkerr;
7704 struct stat symlnbuf;
7705
7706 if (!hflag)
7707 i = fstatat(dirfd, shortname, &stbuf, AT_SYMLINK_NOFOLLOW);
7708 else
7709 i = fstatat(dirfd, shortname, &stbuf, 0);
7710
7711 if (i < 0) {
7712 /* Initialize flag to print error mesg. */
7713 printerr = 1;
7714 /*
7715 * If stat is done, then need to do lstat
7716 * to determine whether it's a sym link
7717 */
7718 if (hflag) {
7719 /* Save returned error */
7720 slnkerr = errno;
7721
7722 j = fstatat(dirfd, shortname,
7723 &symlnbuf, AT_SYMLINK_NOFOLLOW);
7724 /*
7725 * Suppress error message when file is a symbolic link
7726 * and function modifier 'l' is off. Exception: when
7727 * a symlink points to a symlink points to a
7728 * symlink ... and we get past MAXSYMLINKS. That
7729 * error will cause a file not to be archived, and
7730 * needs to be printed.
7731 */
7732 if ((j == 0) && (!linkerrok) && (slnkerr != ELOOP) &&
7733 (S_ISLNK(symlnbuf.st_mode)))
7734 printerr = 0;
7735
7736 /*
7737 * Restore errno in case the lstat
7738 * on symbolic link change
7739 */
7740 errno = slnkerr;
7741 }
7742
7743 if (printerr) {
7744 (void) fprintf(stderr, gettext(
7745 "tar: %s%s%s%s: %s\n"),
7746 (attrparent == NULL) ? "" : gettext("attribute "),
7747 (attrparent == NULL) ? "" : attrparent,
7748 (attrparent == NULL) ? "" : gettext(" of "),
7749 longname, strerror(errno));
7750 Errflg = 1;
7751 }
7752 return (1);
7753 }
7754 return (0);
7755 }
7756
7757 /*
7758 * Recursively archive the extended attributes and/or extended system attributes
7759 * of the base file, longname. Note: extended system attribute files will be
7760 * archived only if the extended system attributes are not transient (i.e. the
7761 * extended system attributes are other than the default values).
7762 *
7763 * If -@ was specified and the underlying file system supports it, archive the
7764 * extended attributes, and if there is a system attribute associated with the
7765 * extended attribute, then recursively call xattrs_put() to archive the
7766 * hidden attribute directory and the extended system attribute. If -/ was
7767 * specified and the underlying file system supports it, archive the extended
7768 * system attributes. Read-only extended system attributes are never archived.
7769 *
7770 * Currently, there cannot be attributes on attributes; only system
7771 * attributes on attributes. In addition, there cannot be attributes on
7772 * system attributes. A file and it's attribute directory hierarchy looks as
7773 * follows:
7774 * longname ----> . ("." is the hidden attribute directory)
7775 * |
7776 * ----------------------------
7777 * | |
7778 * <sys_attr_name> <attr_name> ----> .
7779 * |
7780 * <sys_attr_name>
7781 *
7782 */
7783 #if defined(O_XATTR)
7784 static void
7785 xattrs_put(char *longname, char *shortname, char *parent, char *attrparent)
7786 {
7787 char *filename = (attrparent == NULL) ? shortname : attrparent;
7788 int arc_rwsysattr = 0;
7789 int dirfd;
7790 int fd = -1;
7791 int rw_sysattr = 0;
7792 int ext_attr = 0;
7793 int rc;
7794 DIR *dirp;
7795 struct dirent *dp;
7796 attr_data_t *attrinfo = NULL;
7797
7798 /*
7799 * If the underlying file system supports it, then archive the extended
7800 * attributes if -@ was specified, and the extended system attributes
7801 * if -/ was specified.
7802 */
7803 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
7804 &ext_attr) != ATTR_OK) {
7805 return;
7806 }
7807
7808 /*
7809 * Only want to archive a read-write extended system attribute file
7810 * if it contains extended system attribute settings that are not the
7811 * default values.
7812 */
7813 #if defined(_PC_SATTR_ENABLED)
7814 if (saflag) {
7815 int filefd;
7816 nvlist_t *slist = NULL;
7817
7818 /* Determine if there are non-transient system attributes */
7819 errno = 0;
7820 if ((filefd = open(filename, O_RDONLY)) == -1) {
7821 if (attrparent == NULL) {
7822 vperror(0, gettext(
7823 "unable to open file %s"), longname);
7824 }
7825 return;
7826 }
7827 if (((slist = sysattr_list(basename(myname), filefd,
7828 filename)) != NULL) || (errno != 0)) {
7829 arc_rwsysattr = 1;
7830 }
7831 if (slist != NULL) {
7832 (void) nvlist_free(slist);
7833 slist = NULL;
7834 }
7835 (void) close(filefd);
7836 }
7837
7838 /*
7839 * If we aren't archiving extended system attributes, and we are
7840 * processing an attribute, or if we are archiving extended system
7841 * attributes, and there are are no extended attributes, then there's
7842 * no need to open up the attribute directory of the file unless the
7843 * extended system attributes are not transient (i.e, the system
7844 * attributes are not the default values).
7845 */
7846 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
7847 (saflag && !ext_attr))) {
7848 return;
7849 }
7850 #endif /* _PC_SATTR_ENABLED */
7851
7852 /* open the parent attribute directory */
7853 fd = attropen(filename, ".", O_RDONLY);
7854 if (fd < 0) {
7855 vperror(0, gettext(
7856 "unable to open attribute directory for %s%s%sfile %s"),
7857 (attrparent == NULL) ? "" : gettext("attribute "),
7858 (attrparent == NULL) ? "" : attrparent,
7859 (attrparent == NULL) ? "" : gettext(" of "),
7860 longname);
7861 return;
7862 }
7863
7864 /*
7865 * We need to change into the parent's attribute directory to determine
7866 * if each of the attributes should be archived.
7867 */
7868 if (fchdir(fd) < 0) {
7869 vperror(0, gettext(
7870 "cannot change to attribute directory of %s%s%sfile %s"),
7871 (attrparent == NULL) ? "" : gettext("attribute "),
7872 (attrparent == NULL) ? "" : attrparent,
7873 (attrparent == NULL) ? "" : gettext(" of "),
7874 longname);
7875 (void) close(fd);
7876 return;
7877 }
7878
7879 if (((dirfd = dup(fd)) == -1) ||
7880 ((dirp = fdopendir(dirfd)) == NULL)) {
7881 (void) fprintf(stderr, gettext(
7882 "tar: unable to open dir pointer for %s%s%sfile %s\n"),
7883 (attrparent == NULL) ? "" : gettext("attribute "),
7884 (attrparent == NULL) ? "" : attrparent,
7885 (attrparent == NULL) ? "" : gettext(" of "),
7886 longname);
7887 if (fd > 0) {
7888 (void) close(fd);
7889 }
7890 return;
7891 }
7892
7893 while (dp = readdir(dirp)) {
7894 if (strcmp(dp->d_name, "..") == 0) {
7895 continue;
7896 } else if (strcmp(dp->d_name, ".") == 0) {
7897 Hiddendir = 1;
7898 } else {
7899 Hiddendir = 0;
7900 }
7901
7902 /* Determine if this attribute should be archived */
7903 if (verify_attr(dp->d_name, attrparent, arc_rwsysattr,
7904 &rw_sysattr) != ATTR_OK) {
7905 continue;
7906 }
7907
7908 /* gather the attribute's information to pass to putfile() */
7909 if ((fill_in_attr_info(dp->d_name, longname, attrparent,
7910 fd, rw_sysattr, &attrinfo)) == 1) {
7911 continue;
7912 }
7913
7914 /* add the attribute to the archive */
7915 rc = putfile(longname, dp->d_name, parent, attrinfo,
7916 XATTR_FILE, LEV0, SYMLINK_LEV0);
7917
7918 if (exitflag) {
7919 break;
7920 }
7921
7922 #if defined(_PC_SATTR_ENABLED)
7923 /*
7924 * If both -/ and -@ were specified, then archive the
7925 * attribute's extended system attributes and hidden directory
7926 * by making a recursive call to xattrs_put().
7927 */
7928 if (!rw_sysattr && saflag && atflag && (rc != PUT_AS_LINK) &&
7929 (Hiddendir == 0)) {
7930
7931 xattrs_put(longname, shortname, parent, dp->d_name);
7932
7933 /*
7934 * Change back to the parent's attribute directory
7935 * to process any further attributes.
7936 */
7937 if (fchdir(fd) < 0) {
7938 vperror(0, gettext(
7939 "cannot change back to attribute directory "
7940 "of file %s"), longname);
7941 break;
7942 }
7943 }
7944 #endif /* _PC_SATTR_ENABLED */
7945 }
7946
7947 if (attrinfo != NULL) {
7948 if (attrinfo->attr_parent != NULL) {
7949 free(attrinfo->attr_parent);
7950 }
7951 free(attrinfo->attr_path);
7952 free(attrinfo);
7953 }
7954 (void) closedir(dirp);
7955 if (fd != -1) {
7956 (void) close(fd);
7957 }
7958
7959 /* Change back to the parent directory of the base file */
7960 if (attrparent == NULL) {
7961 (void) tar_chdir(parent);
7962 }
7963 Hiddendir = 0;
7964 }
7965 #else
7966 static void
7967 xattrs_put(char *longname, char *shortname, char *parent, char *attrppath)
7968 {
7969 }
7970 #endif /* O_XATTR */
7971
7972 static int
7973 put_link(char *name, char *longname, char *component, char *longattrname,
7974 char *prefix, int filetype, char type)
7975 {
7976
7977 if (stbuf.st_nlink > 1) {
7978 struct linkbuf *lp;
7979 int found = 0;
7980
7981 for (lp = ihead; lp != NULL; lp = lp->nextp)
7982 if (lp->inum == stbuf.st_ino &&
7983 lp->devnum == stbuf.st_dev) {
7984 found++;
7985 break;
7986 }
7987 if (found) {
7988 #if defined(O_XATTR)
7989 if (filetype == XATTR_FILE)
7990 if (put_xattr_hdr(longname, component,
7991 longattrname, prefix, type, filetype, lp)) {
7992 goto out;
7993 }
7994 #endif
7995 stbuf.st_size = (off_t)0;
7996 if (filetype != XATTR_FILE) {
7997 tomodes(&stbuf);
7998 if (chk_path_build(name, longname, lp->pathname,
7999 prefix, type, filetype) > 0) {
8000 goto out;
8001 }
8002 }
8003
8004 if (mulvol && tapepos + 1 >= blocklim)
8005 newvol();
8006 (void) writetbuf((char *)&dblock, 1);
8007 /*
8008 * write_ancillary() is not needed here.
8009 * The first link is handled in the following
8010 * else statement. No need to process ACLs
8011 * for other hard links since they are the
8012 * same file.
8013 */
8014
8015 if (vflag) {
8016 #ifdef DEBUG
8017 if (NotTape)
8018 DEBUG("seek = %" FMT_blkcnt_t
8019 "K\t", K(tapepos), 0);
8020 #endif
8021 if (filetype == XATTR_FILE) {
8022 (void) fprintf(vfile, gettext(
8023 "a %s attribute %s link to "
8024 "%s attribute %s\n"),
8025 name, component, name,
8026 lp->attrname);
8027 } else {
8028 (void) fprintf(vfile, gettext(
8029 "a %s link to %s\n"),
8030 longname, lp->pathname);
8031 }
8032 }
8033 lp->count--;
8034 return (0);
8035 } else {
8036 lp = (struct linkbuf *)getmem(sizeof (*lp));
8037 if (lp != (struct linkbuf *)NULL) {
8038 lp->nextp = ihead;
8039 ihead = lp;
8040 lp->inum = stbuf.st_ino;
8041 lp->devnum = stbuf.st_dev;
8042 lp->count = stbuf.st_nlink - 1;
8043 if (filetype == XATTR_FILE) {
8044 (void) strcpy(lp->pathname, longname);
8045 (void) strcpy(lp->attrname,
8046 component);
8047 } else {
8048 (void) strcpy(lp->pathname, longname);
8049 (void) strcpy(lp->attrname, "");
8050 }
8051 }
8052 }
8053 }
8054
8055 out:
8056 return (1);
8057 }
8058
8059 static int
8060 put_extra_attributes(char *longname, char *shortname, char *longattrname,
8061 char *prefix, int filetype, char typeflag)
8062 {
8063 static acl_t *aclp = NULL;
8064 int error;
8065
8066 if (aclp != NULL) {
8067 acl_free(aclp);
8068 aclp = NULL;
8069 }
8070 #if defined(O_XATTR)
8071 if ((atflag || saflag) && (filetype == XATTR_FILE)) {
8072 if (put_xattr_hdr(longname, shortname, longattrname, prefix,
8073 typeflag, filetype, NULL)) {
8074 return (1);
8075 }
8076 }
8077 #endif
8078
8079 /* ACL support */
8080 if (pflag) {
8081 char *secinfo = NULL;
8082 int len = 0;
8083
8084 /* ACL support */
8085 if (((stbuf.st_mode & S_IFMT) != S_IFLNK)) {
8086 /*
8087 * Get ACL info: dont bother allocating space if
8088 * there is only a trivial ACL.
8089 */
8090 if ((error = acl_get(shortname, ACL_NO_TRIVIAL,
8091 &aclp)) != 0) {
8092 (void) fprintf(stderr, gettext(
8093 "%s: failed to retrieve acl : %s\n"),
8094 longname, acl_strerror(error));
8095 return (1);
8096 }
8097 }
8098
8099 /* append security attributes if any */
8100 if (aclp != NULL) {
8101 (void) append_secattr(&secinfo, &len, acl_cnt(aclp),
8102 acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8103 ACL_SID_FMT), (acl_type(aclp) == ACLENT_T) ?
8104 UFSD_ACL : ACE_ACL);
8105 }
8106
8107 if (Tflag) {
8108 /* append Trusted Extensions extended attributes */
8109 append_ext_attr(shortname, &secinfo, &len);
8110 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8111
8112 } else if (aclp != NULL) {
8113 (void) write_ancillary(&dblock, secinfo, len, ACL_HDR);
8114 }
8115 }
8116 return (0);
8117 }
8118
8119 #if defined(O_XATTR)
8120 static int
8121 put_xattr_hdr(char *longname, char *shortname, char *longattrname, char *prefix,
8122 int typeflag, int filetype, struct linkbuf *lp)
8123 {
8124 char *lname = NULL;
8125 char *sname = NULL;
8126 int error = 0;
8127 static char *attrbuf = NULL;
8128 int attrlen;
8129
8130 lname = malloc(sizeof (char) * strlen("/dev/null") + 1 +
8131 strlen(shortname) + strlen(".hdr") + 1);
8132
8133 if (lname == NULL) {
8134 fatal(gettext("Out of Memory."));
8135 }
8136 sname = malloc(sizeof (char) * strlen(shortname) +
8137 strlen(".hdr") + 1);
8138 if (sname == NULL) {
8139 fatal(gettext("Out of Memory."));
8140 }
8141
8142 (void) sprintf(sname, "%s.hdr", shortname);
8143 (void) sprintf(lname, "/dev/null/%s", sname);
8144
8145 if (strlcpy(dblock.dbuf.name, lname, sizeof (dblock.dbuf.name)) >=
8146 sizeof (dblock.dbuf.name)) {
8147 fatal(gettext(
8148 "Buffer overflow writing extended attribute file name"));
8149 }
8150
8151 /*
8152 * dump extended attr lookup info
8153 */
8154 prepare_xattr(&attrbuf, longname, longattrname, typeflag, lp, &attrlen);
8155 write_ancillary(&dblock, attrbuf, attrlen, _XATTR_HDRTYPE);
8156
8157 (void) sprintf(lname, "/dev/null/%s", shortname);
8158 (void) strncpy(dblock.dbuf.name, sname, NAMSIZ);
8159
8160 /*
8161 * Set up filename for attribute
8162 */
8163
8164 error = build_dblock(lname, tchar, '0', filetype,
8165 &stbuf, stbuf.st_dev, prefix);
8166 free(lname);
8167 free(sname);
8168
8169 return (error);
8170 }
8171 #endif
8172
8173 #if defined(O_XATTR)
8174 static int
8175 read_xattr_hdr(attr_data_t **attrinfo)
8176 {
8177 char buf[TBLOCK];
8178 char *attrparent = NULL;
8179 blkcnt_t blocks;
8180 char *tp;
8181 off_t bytes;
8182 int comp_len, link_len;
8183 int namelen;
8184 int attrparentlen;
8185 int parentfilelen;
8186
8187 if (dblock.dbuf.typeflag != _XATTR_HDRTYPE)
8188 return (1);
8189
8190 bytes = stbuf.st_size;
8191 if ((xattrhead = calloc(1, (int)bytes)) == NULL) {
8192 (void) fprintf(stderr, gettext(
8193 "Insufficient memory for extended attribute\n"));
8194 return (1);
8195 }
8196
8197 tp = (char *)xattrhead;
8198 blocks = TBLOCKS(bytes);
8199 while (blocks-- > 0) {
8200 readtape(buf);
8201 if (bytes <= TBLOCK) {
8202 (void) memcpy(tp, buf, (size_t)bytes);
8203 break;
8204 } else {
8205 (void) memcpy(tp, buf, TBLOCK);
8206 tp += TBLOCK;
8207 }
8208 bytes -= TBLOCK;
8209 }
8210
8211 /*
8212 * Validate that we can handle header format
8213 */
8214 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8215 (void) fprintf(stderr,
8216 gettext("Unknown extended attribute format encountered\n"));
8217 (void) fprintf(stderr,
8218 gettext("Disabling extended attribute parsing\n"));
8219 xattrbadhead = 1;
8220 return (0);
8221 }
8222 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8223 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8224 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8225 sizeof (struct xattr_hdr));
8226 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8227 if (link_len > 0)
8228 xattr_linkp = (struct xattr_buf *)
8229 ((int)xattrp + (int)comp_len);
8230 else
8231 xattr_linkp = NULL;
8232
8233 /*
8234 * Gather the attribute path from the filename and attrnames section.
8235 * The filename and attrnames section can be composed of two or more
8236 * path segments separated by a null character. The first segment
8237 * is the path to the parent file that roots the entire sequence in
8238 * the normal name space. The remaining segments describes a path
8239 * rooted at the hidden extended attribute directory of the leaf file of
8240 * the previous segment, making it possible to name attributes on
8241 * attributes.
8242 */
8243 parentfilelen = strlen(xattrp->h_names);
8244 xattrapath = xattrp->h_names + parentfilelen + 1;
8245 if ((strlen(xattrapath) + parentfilelen + 2) < namelen) {
8246 /*
8247 * The attrnames section contains a system attribute on an
8248 * attribute. Save the name of the attribute for use later,
8249 * and replace the null separating the attribute name from
8250 * the system attribute name with a '/' so that xattrapath can
8251 * be used to display messages with the full attribute path name
8252 * rooted at the hidden attribute directory of the base file
8253 * in normal name space.
8254 */
8255 attrparent = strdup(xattrapath);
8256 attrparentlen = strlen(attrparent);
8257 xattrapath[attrparentlen] = '/';
8258 }
8259 if ((fill_in_attr_info((attrparent == NULL) ? xattrapath :
8260 xattrapath + attrparentlen + 1, xattrapath, attrparent,
8261 -1, 0, attrinfo)) == 1) {
8262 free(attrparent);
8263 return (1);
8264 }
8265
8266 /* Gather link info */
8267 if (xattr_linkp) {
8268 xattr_linkaname = xattr_linkp->h_names +
8269 strlen(xattr_linkp->h_names) + 1;
8270 } else {
8271 xattr_linkaname = NULL;
8272 }
8273
8274 return (0);
8275 }
8276 #else
8277 static int
8278 read_xattr_hdr(attr_data_t **attrinfo)
8279 {
8280 return (0);
8281 }
8282 #endif
8283
8284 /*
8285 * skip over extra slashes in string.
8286 *
8287 * For example:
8288 * /usr/tmp/////
8289 *
8290 * would return pointer at
8291 * /usr/tmp/////
8292 * ^
8293 */
8294 static char *
8295 skipslashes(char *string, char *start)
8296 {
8297 while ((string > start) && *(string - 1) == '/') {
8298 string--;
8299 }
8300
8301 return (string);
8302 }
8303
8304 /*
8305 * Return the parent directory of a given path.
8306 *
8307 * Examples:
8308 * /usr/tmp return /usr
8309 * /usr/tmp/file return /usr/tmp
8310 * / returns .
8311 * /usr returns /
8312 * file returns .
8313 *
8314 * dir is assumed to be at least as big as path.
8315 */
8316 static void
8317 get_parent(char *path, char *dir)
8318 {
8319 char *s;
8320 char tmpdir[PATH_MAX + 1];
8321
8322 if (strlen(path) > PATH_MAX) {
8323 fatal(gettext("pathname is too long"));
8324 }
8325 (void) strcpy(tmpdir, path);
8326 chop_endslashes(tmpdir);
8327
8328 if ((s = strrchr(tmpdir, '/')) == NULL) {
8329 (void) strcpy(dir, ".");
8330 } else {
8331 s = skipslashes(s, tmpdir);
8332 *s = '\0';
8333 if (s == tmpdir)
8334 (void) strcpy(dir, "/");
8335 else
8336 (void) strcpy(dir, tmpdir);
8337 }
8338 }
8339
8340 #if defined(O_XATTR)
8341 static char *
8342 get_component(char *path)
8343 {
8344 char *ptr;
8345
8346 ptr = strrchr(path, '/');
8347 if (ptr == NULL) {
8348 return (path);
8349 } else {
8350 /*
8351 * Handle trailing slash
8352 */
8353 if (*(ptr + 1) == '\0')
8354 return (ptr);
8355 else
8356 return (ptr + 1);
8357 }
8358 }
8359 #else
8360 static char *
8361 get_component(char *path)
8362 {
8363 return (path);
8364 }
8365 #endif
8366
8367 #if defined(O_XATTR)
8368 static int
8369 retry_open_attr(int pdirfd, int cwd, char *dirp, char *pattr, char *name,
8370 int oflag, mode_t mode)
8371 {
8372 int dirfd;
8373 int ofilefd = -1;
8374 struct timeval times[2];
8375 mode_t newmode;
8376 struct stat parentstat;
8377 acl_t *aclp = NULL;
8378 int error;
8379
8380 /*
8381 * We couldn't get to attrdir. See if its
8382 * just a mode problem on the parent file.
8383 * for example: a mode such as r-xr--r--
8384 * on a ufs file system without extended
8385 * system attribute support won't let us
8386 * create an attribute dir if it doesn't
8387 * already exist, and on a ufs file system
8388 * with extended system attribute support
8389 * won't let us open the attribute for
8390 * write.
8391 *
8392 * If file has a non-trivial ACL, then save it
8393 * off so that we can place it back on after doing
8394 * chmod's.
8395 */
8396 if ((dirfd = openat(cwd, (pattr == NULL) ? dirp : pattr,
8397 O_RDONLY)) == -1) {
8398 return (-1);
8399 }
8400 if (fstat(dirfd, &parentstat) == -1) {
8401 (void) fprintf(stderr, gettext(
8402 "tar: cannot stat %sfile %s: %s\n"),
8403 (pdirfd == -1) ? "" : gettext("parent of "),
8404 (pdirfd == -1) ? dirp : name, strerror(errno));
8405 return (-1);
8406 }
8407 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
8408 (void) fprintf(stderr, gettext(
8409 "tar: failed to retrieve ACL on %sfile %s: %s\n"),
8410 (pdirfd == -1) ? "" : gettext("parent of "),
8411 (pdirfd == -1) ? dirp : name, strerror(errno));
8412 return (-1);
8413 }
8414
8415 newmode = S_IWUSR | parentstat.st_mode;
8416 if (fchmod(dirfd, newmode) == -1) {
8417 (void) fprintf(stderr,
8418 gettext(
8419 "tar: cannot fchmod %sfile %s to %o: %s\n"),
8420 (pdirfd == -1) ? "" : gettext("parent of "),
8421 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8422 if (aclp)
8423 acl_free(aclp);
8424 return (-1);
8425 }
8426
8427
8428 if (pdirfd == -1) {
8429 /*
8430 * We weren't able to create the attribute directory before.
8431 * Now try again.
8432 */
8433 ofilefd = attropen(dirp, ".", oflag);
8434 } else {
8435 /*
8436 * We weren't able to create open the attribute before.
8437 * Now try again.
8438 */
8439 ofilefd = openat(pdirfd, name, oflag, mode);
8440 }
8441
8442 /*
8443 * Put mode back to original
8444 */
8445 if (fchmod(dirfd, parentstat.st_mode) == -1) {
8446 (void) fprintf(stderr,
8447 gettext("tar: cannot chmod %sfile %s to %o: %s\n"),
8448 (pdirfd == -1) ? "" : gettext("parent of "),
8449 (pdirfd == -1) ? dirp : name, newmode, strerror(errno));
8450 }
8451
8452 if (aclp) {
8453 error = facl_set(dirfd, aclp);
8454 if (error) {
8455 (void) fprintf(stderr,
8456 gettext("tar: failed to set acl entries on "
8457 "%sfile %s\n"),
8458 (pdirfd == -1) ? "" : gettext("parent of "),
8459 (pdirfd == -1) ? dirp : name);
8460 }
8461 acl_free(aclp);
8462 }
8463
8464 /*
8465 * Put back time stamps
8466 */
8467
8468 times[0].tv_sec = parentstat.st_atime;
8469 times[0].tv_usec = 0;
8470 times[1].tv_sec = parentstat.st_mtime;
8471 times[1].tv_usec = 0;
8472
8473 (void) futimesat(cwd, (pattr == NULL) ? dirp : pattr, times);
8474
8475 (void) close(dirfd);
8476
8477 return (ofilefd);
8478 }
8479 #endif
8480
8481 #if !defined(O_XATTR)
8482 static int
8483 openat64(int fd, const char *name, int oflag, mode_t cmode)
8484 {
8485 return (open64(name, oflag, cmode));
8486 }
8487
8488 static int
8489 openat(int fd, const char *name, int oflag, mode_t cmode)
8490 {
8491 return (open(name, oflag, cmode));
8492 }
8493
8494 static int
8495 fchownat(int fd, const char *name, uid_t owner, gid_t group, int flag)
8496 {
8497 if (flag == AT_SYMLINK_NOFOLLOW)
8498 return (lchown(name, owner, group));
8499 else
8500 return (chown(name, owner, group));
8501 }
8502
8503 static int
8504 renameat(int fromfd, char *old, int tofd, char *new)
8505 {
8506 return (rename(old, new));
8507 }
8508
8509 static int
8510 futimesat(int fd, char *path, struct timeval times[2])
8511 {
8512 return (utimes(path, times));
8513 }
8514
8515 static int
8516 unlinkat(int dirfd, char *path, int flag)
8517 {
8518 if (flag == AT_REMOVEDIR)
8519 return (rmdir(path));
8520 else
8521 return (unlink(path));
8522 }
8523
8524 static int
8525 fstatat(int fd, char *path, struct stat *buf, int flag)
8526 {
8527 if (flag == AT_SYMLINK_NOFOLLOW)
8528 return (lstat(path, buf));
8529 else
8530 return (stat(path, buf));
8531 }
8532
8533 static int
8534 attropen(char *file, char *attr, int omode, mode_t cmode)
8535 {
8536 errno = ENOTSUP;
8537 return (-1);
8538 }
8539 #endif
8540
8541 static void
8542 chop_endslashes(char *path)
8543 {
8544 char *end, *ptr;
8545
8546 /*
8547 * Chop of slashes, but not if all we have is slashes
8548 * for example: ////
8549 * should make no changes, otherwise it will screw up
8550 * checkdir
8551 */
8552 end = &path[strlen(path) -1];
8553 if (*end == '/' && end != path) {
8554 ptr = skipslashes(end, path);
8555 if (ptr != NULL && ptr != path) {
8556 *ptr = '\0';
8557 }
8558 }
8559 }
8560 /* Trusted Extensions */
8561
8562 /*
8563 * append_ext_attr():
8564 *
8565 * Append extended attributes and other information into the buffer
8566 * that gets written to the ancillary file.
8567 *
8568 * With option 'T', we create a tarfile which
8569 * has an ancillary file each corresponding archived file.
8570 * Each ancillary file contains 1 or more of the
8571 * following attributes:
8572 *
8573 * attribute type attribute process procedure
8574 * ---------------- ---------------- --------------------------
8575 * DIR_TYPE = 'D' directory flag append if a directory
8576 * LBL_TYPE = 'L' SL[IL] or SL append ascii label
8577 *
8578 *
8579 */
8580 static void
8581 append_ext_attr(char *shortname, char **secinfo, int *len)
8582 {
8583 bslabel_t b_slabel; /* binary sensitvity label */
8584 char *ascii = NULL; /* ascii label */
8585
8586 /*
8587 * For each attribute type, append it if it is
8588 * relevant to the file type.
8589 */
8590
8591 /*
8592 * For attribute type DIR_TYPE,
8593 * append it to the following file type:
8594 *
8595 * S_IFDIR: directories
8596 */
8597
8598 /*
8599 * For attribute type LBL_TYPE,
8600 * append it to the following file type:
8601 *
8602 * S_IFDIR: directories (including mld, sld)
8603 * S_IFLNK: symbolic link
8604 * S_IFREG: regular file but not hard link
8605 * S_IFIFO: FIFO file but not hard link
8606 * S_IFCHR: char special file but not hard link
8607 * S_IFBLK: block special file but not hard link
8608 */
8609 switch (stbuf.st_mode & S_IFMT) {
8610
8611 case S_IFDIR:
8612
8613 /*
8614 * append DIR_TYPE
8615 */
8616 (void) append_secattr(secinfo, len, 1,
8617 "\0", DIR_TYPE);
8618
8619 /*
8620 * Get and append attribute types LBL_TYPE.
8621 * For directories, LBL_TYPE contains SL.
8622 */
8623 /* get binary sensitivity label */
8624 if (getlabel(shortname, &b_slabel) != 0) {
8625 (void) fprintf(stderr,
8626 gettext("tar: can't get sensitvity label for "
8627 " %s, getlabel() error: %s\n"),
8628 shortname, strerror(errno));
8629 } else {
8630 /* get ascii SL */
8631 if (bsltos(&b_slabel, &ascii,
8632 0, 0) <= 0) {
8633 (void) fprintf(stderr,
8634 gettext("tar: can't get ascii SL for"
8635 " %s\n"), shortname);
8636 } else {
8637 /* append LBL_TYPE */
8638 (void) append_secattr(secinfo, len,
8639 strlen(ascii) + 1, ascii,
8640 LBL_TYPE);
8641
8642 /* free storage */
8643 if (ascii != NULL) {
8644 free(ascii);
8645 ascii = (char *)0;
8646 }
8647 }
8648
8649 }
8650 break;
8651
8652 case S_IFLNK:
8653 case S_IFREG:
8654 case S_IFIFO:
8655 case S_IFCHR:
8656 case S_IFBLK:
8657
8658 /* get binary sensitivity label */
8659 if (getlabel(shortname, &b_slabel) != 0) {
8660 (void) fprintf(stderr,
8661 gettext("tar: can't get sensitivty label for %s, "
8662 "getlabel() error: %s\n"),
8663 shortname, strerror(errno));
8664 } else {
8665 /* get ascii IL[SL] */
8666 if (bsltos(&b_slabel, &ascii, 0, 0) <= 0) {
8667 (void) fprintf(stderr,
8668 gettext("tar: can't translate sensitivity "
8669 " label for %s\n"), shortname);
8670 } else {
8671 char *cmw_label;
8672 size_t cmw_length;
8673
8674 cmw_length = strlen("ADMIN_LOW [] ") +
8675 strlen(ascii);
8676 if ((cmw_label = malloc(cmw_length)) == NULL) {
8677 (void) fprintf(stderr, gettext(
8678 "Insufficient memory for label\n"));
8679 exit(1);
8680 }
8681 /* append LBL_TYPE */
8682 (void) snprintf(cmw_label, cmw_length,
8683 "ADMIN_LOW [%s]", ascii);
8684 (void) append_secattr(secinfo, len,
8685 strlen(cmw_label) + 1, cmw_label,
8686 LBL_TYPE);
8687
8688 /* free storage */
8689 if (ascii != NULL) {
8690 free(cmw_label);
8691 free(ascii);
8692 ascii = (char *)0;
8693 }
8694 }
8695 }
8696 break;
8697
8698 default:
8699 break;
8700 } /* end switch for LBL_TYPE */
8701
8702
8703 /* DONE !! */
8704 return;
8705
8706 } /* end of append_ext_attr */
8707
8708
8709 /*
8710 * Name: extract_attr()
8711 *
8712 * Description:
8713 * Process attributes from the ancillary file due to
8714 * the T option.
8715 *
8716 * Call by doxtract() as part of the switch case structure.
8717 * Making this a separate routine because the nesting are too
8718 * deep in doxtract, thus, leaving very little space
8719 * on each line for instructions.
8720 *
8721 * With option 'T', we extract from a TS 8 or TS 2.5 ancillary file
8722 *
8723 * For option 'T', following are possible attributes in
8724 * a TS 8 ancillary file: (NOTE: No IL support)
8725 *
8726 * attribute type attribute process procedure
8727 * ---------------- ---------------- -------------------------
8728 * # LBL_TYPE = 'L' SL construct binary label
8729 * # APRIV_TYPE = 'P' allowed priv construct privileges
8730 * # FPRIV_TYPE = 'p' forced priv construct privileges
8731 * # COMP_TYPE = 'C' path component construct real path
8732 * # DIR_TYPE = 'D' directory flag note it is a directory
8733 * $ UFSD_ACL = '1' ACL data construct ACL entries
8734 * ATTR_FLAG_TYPE = 'F' file attr flags construct binary flags
8735 * LK_COMP_TYPE = 'K' linked path comp construct linked real path
8736 *
8737 * note: # = attribute names common between TS 8 & TS 2.5 ancillary
8738 * files.
8739 * $ = ACL attribute is processed for the option 'p', it doesn't
8740 * need option 'T'.
8741 *
8742 * Trusted Extensions ignores APRIV_TYPE, FPRIV_TYPE, and ATTR_FLAG_TYPE
8743 *
8744 */
8745 static void
8746 extract_attr(char **file_ptr, struct sec_attr *attr)
8747 {
8748 int reterr, err;
8749 char *dummy_buf; /* for attribute extract */
8750
8751 dummy_buf = attr->attr_info;
8752
8753 switch (attr->attr_type) {
8754
8755 case DIR_TYPE:
8756
8757 dir_flag++;
8758 break;
8759
8760 case LBL_TYPE:
8761
8762 /*
8763 * LBL_TYPE is used to indicate SL for directory, and
8764 * CMW label for other file types.
8765 */
8766
8767 if (!dir_flag) { /* not directory */
8768 /* Skip over IL portion */
8769 char *sl_ptr = strchr(dummy_buf, '[');
8770
8771 if (sl_ptr == NULL)
8772 err = 0;
8773 else
8774 err = stobsl(sl_ptr, &bs_label,
8775 NEW_LABEL, &reterr);
8776 } else { /* directory */
8777 err = stobsl(dummy_buf, &bs_label,
8778 NEW_LABEL, &reterr);
8779 }
8780 if (err == 0) {
8781 (void) fprintf(stderr, gettext("tar: "
8782 "can't convert %s to binary label\n"),
8783 dummy_buf);
8784 bslundef(&bs_label);
8785 } else if (!blequal(&bs_label, &admin_low) &&
8786 !blequal(&bs_label, &admin_high)) {
8787 bslabel_t *from_label;
8788 char *buf;
8789 char tempbuf[MAXPATHLEN];
8790
8791 if (*orig_namep != '/') {
8792 /* got relative linked to path */
8793 (void) getcwd(tempbuf, (sizeof (tempbuf)));
8794 (void) strncat(tempbuf, "/", MAXPATHLEN);
8795 } else
8796 *tempbuf = '\0';
8797
8798 buf = real_path;
8799 (void) strncat(tempbuf, orig_namep, MAXPATHLEN);
8800 from_label = getlabelbypath(tempbuf);
8801 if (from_label != NULL) {
8802 if (blequal(from_label, &admin_low)) {
8803 if ((getpathbylabel(tempbuf, buf,
8804 MAXPATHLEN, &bs_label) == NULL)) {
8805 (void) fprintf(stderr,
8806 gettext("tar: "
8807 "can't get zone root path for "
8808 "%s\n"), tempbuf);
8809 } else
8810 rpath_flag = 1;
8811 }
8812 free(from_label);
8813 }
8814 }
8815 break;
8816
8817 case COMP_TYPE:
8818
8819 rebuild_comp_path(dummy_buf, file_ptr);
8820 break;
8821
8822 case LK_COMP_TYPE:
8823
8824 if (rebuild_lk_comp_path(dummy_buf, file_ptr)
8825 == 0) {
8826 lk_rpath_flag = 1;
8827 } else {
8828 (void) fprintf(stderr, gettext("tar: warning: link's "
8829 "target pathname might be invalid.\n"));
8830 lk_rpath_flag = 0;
8831 }
8832 break;
8833 case APRIV_TYPE:
8834 ignored_aprivs++;
8835 break;
8836 case FPRIV_TYPE:
8837 ignored_fprivs++;
8838 break;
8839 case ATTR_FLAG_TYPE:
8840 ignored_fattrs++;
8841 break;
8842
8843 default:
8844
8845 break;
8846 }
8847
8848 /* done */
8849 return;
8850
8851 } /* end extract_attr */
8852
8853
8854
8855 /*
8856 * Name: rebuild_comp_path()
8857 *
8858 * Description:
8859 * Take the string of components passed down by the calling
8860 * routine and parse the values and rebuild the path.
8861 * This routine no longer needs to produce a new real_path
8862 * string because it is produced when the 'L' LABEL_TYPE is
8863 * interpreted. So the only thing done here is to distinguish
8864 * between an SLD and an MLD entry. We only want one, so we
8865 * ignore the MLD entry by setting the mld_flag.
8866 *
8867 * return value:
8868 * none
8869 */
8870 static void
8871 rebuild_comp_path(char *str, char **namep)
8872 {
8873 char *cp;
8874
8875 while (*str != '\0') {
8876
8877 switch (*str) {
8878
8879 case MLD_TYPE:
8880
8881 str++;
8882 if ((cp = strstr(str, ";;")) != NULL) {
8883 *cp = '\0';
8884 str = cp + 2;
8885 *cp = ';';
8886 }
8887 mld_flag = 1;
8888 break;
8889
8890 case SLD_TYPE:
8891
8892 str++;
8893 if ((cp = strstr(str, ";;")) != NULL) {
8894 *cp = '\0';
8895 str = cp + 2;
8896 *cp = ';';
8897 }
8898 mld_flag = 0;
8899 break;
8900
8901 case PATH_TYPE:
8902
8903 str++;
8904 if ((cp = strstr(str, ";;")) != NULL) {
8905 *cp = '\0';
8906 str = cp + 2;
8907 *cp = ';';
8908 }
8909 break;
8910 }
8911 }
8912 if (rpath_flag)
8913 *namep = real_path;
8914 return;
8915
8916 } /* end rebuild_comp_path() */
8917
8918 /*
8919 * Name: rebuild_lk_comp_path()
8920 *
8921 * Description:
8922 * Take the string of components passed down by the calling
8923 * routine and parse the values and rebuild the path.
8924 *
8925 * return value:
8926 * 0 = succeeded
8927 * -1 = failed
8928 */
8929 static int
8930 rebuild_lk_comp_path(char *str, char **namep)
8931 {
8932 char *cp;
8933 int reterr;
8934 bslabel_t bslabel;
8935 char *buf;
8936 char pbuf[MAXPATHLEN];
8937 char *ptr1, *ptr2;
8938 int plen;
8939 int use_pbuf;
8940 char tempbuf[MAXPATHLEN];
8941 int mismatch;
8942 bslabel_t *from_label;
8943 char zonename[ZONENAME_MAX];
8944 zoneid_t zoneid;
8945
8946 /* init stuff */
8947 use_pbuf = 0;
8948 mismatch = 0;
8949
8950 /*
8951 * For linked to pathname (LK_COMP_TYPE):
8952 * - If the linked to pathname is absolute (start with /), we
8953 * will use it as is.
8954 * - If it is a relative pathname then it is relative to 1 of 2
8955 * directories. For a hardlink, it is relative to the current
8956 * directory. For a symbolic link, it is relative to the
8957 * directory the symbolic link is in. For the symbolic link
8958 * case, set a flag to indicate we need to use the prefix of
8959 * the restored file's pathname with the linked to pathname.
8960 *
8961 * NOTE: At this point, we have no way to determine if we have
8962 * a hardlink or a symbolic link. We will compare the 1st
8963 * component in the prefix portion of the restore file's
8964 * pathname to the 1st component in the attribute data
8965 * (the linked pathname). If they are the same, we will assume
8966 * the link pathname to reconstruct is relative to the current
8967 * directory. Otherwise, we will set a flag indicate we need
8968 * to use a prefix with the reconstructed name. Need to compare
8969 * both the adorned and unadorned version before deciding a
8970 * mismatch.
8971 */
8972
8973 buf = lk_real_path;
8974 if (*(str + 1) != '/') { /* got relative linked to path */
8975 ptr1 = orig_namep;
8976 ptr2 = strrchr(ptr1, '/');
8977 plen = ptr2 - ptr1;
8978 if (plen > 0) {
8979 pbuf[0] = '\0';
8980 plen++; /* include '/' */
8981 (void) strncpy(pbuf, ptr1, plen);
8982 *(pbuf + plen) = '\0';
8983 ptr2 = strchr(pbuf, '/');
8984 if (strncmp(pbuf, str + 1, ptr2 - pbuf) != 0)
8985 mismatch = 1;
8986 }
8987
8988 if (mismatch == 1)
8989 use_pbuf = 1;
8990 }
8991
8992 buf[0] = '\0';
8993
8994 while (*str != '\0') {
8995
8996 switch (*str) {
8997
8998 case MLD_TYPE:
8999
9000 str++;
9001 if ((cp = strstr(str, ";;")) != NULL) {
9002 *cp = '\0';
9003
9004 /*
9005 * Ignore attempts to backup over .MLD.
9006 */
9007 if (strcmp(str, "../") != 0)
9008 (void) strncat(buf, str, MAXPATHLEN);
9009 str = cp + 2;
9010 *cp = ';';
9011 }
9012 break;
9013
9014 case SLD_TYPE:
9015
9016 str++;
9017 if ((cp = strstr(str, ";;")) != NULL) {
9018 *cp = '\0';
9019
9020 /*
9021 * Use the path name in the header if
9022 * error occurs when processing the
9023 * SLD type.
9024 */
9025
9026 if (!stobsl(str, &bslabel,
9027 NO_CORRECTION, &reterr)) {
9028 (void) fprintf(stderr, gettext(
9029 "tar: can't translate to binary"
9030 "SL for SLD, stobsl() error:"
9031 " %s\n"), strerror(errno));
9032 return (-1);
9033 }
9034
9035 str = cp + 2;
9036 *cp = ';';
9037
9038 if (use_pbuf == 1) {
9039 if (*pbuf != '/') {
9040 /* relative linked to path */
9041
9042 (void) getcwd(tempbuf,
9043 (sizeof (tempbuf)));
9044 (void) strncat(tempbuf, "/",
9045 MAXPATHLEN);
9046 (void) strncat(tempbuf, pbuf,
9047 MAXPATHLEN);
9048 }
9049 else
9050 (void) strcpy(tempbuf, pbuf);
9051
9052 } else if (*buf != '/') {
9053 /* got relative linked to path */
9054
9055 (void) getcwd(tempbuf,
9056 (sizeof (tempbuf)));
9057 (void) strncat(tempbuf, "/",
9058 MAXPATHLEN);
9059 } else
9060 *tempbuf = '\0';
9061
9062 (void) strncat(tempbuf, buf, MAXPATHLEN);
9063 *buf = '\0';
9064
9065 if (blequal(&bslabel, &admin_high)) {
9066 bslabel = admin_low;
9067 }
9068
9069
9070 /*
9071 * Check for cross-zone symbolic links
9072 */
9073 from_label = getlabelbypath(real_path);
9074 if (rpath_flag && (from_label != NULL) &&
9075 !blequal(&bslabel, from_label)) {
9076 if ((zoneid =
9077 getzoneidbylabel(&bslabel)) == -1) {
9078 (void) fprintf(stderr,
9079 gettext("tar: can't get "
9080 "zone ID for %s\n"),
9081 tempbuf);
9082 return (-1);
9083 }
9084 if (zone_getattr(zoneid, ZONE_ATTR_NAME,
9085 &zonename, ZONENAME_MAX) == -1) {
9086 /* Badly configured zone info */
9087 (void) fprintf(stderr,
9088 gettext("tar: can't get "
9089 "zonename for %s\n"),
9090 tempbuf);
9091 return (-1);
9092 }
9093 (void) strncpy(buf, AUTO_ZONE,
9094 MAXPATHLEN);
9095 (void) strncat(buf, "/",
9096 MAXPATHLEN);
9097 (void) strncat(buf, zonename,
9098 MAXPATHLEN);
9099 }
9100 if (from_label != NULL)
9101 free(from_label);
9102 (void) strncat(buf, tempbuf, MAXPATHLEN);
9103 break;
9104 }
9105 mld_flag = 0;
9106 break;
9107
9108 case PATH_TYPE:
9109
9110 str++;
9111 if ((cp = strstr(str, ";;")) != NULL) {
9112 *cp = '\0';
9113 (void) strncat(buf, str, MAXPATHLEN);
9114 str = cp + 2;
9115 *cp = ';';
9116 }
9117 break;
9118
9119 default:
9120
9121 (void) fprintf(stderr, gettext(
9122 "tar: error rebuilding path %s\n"),
9123 *namep);
9124 *buf = '\0';
9125 str++;
9126 return (-1);
9127 }
9128 }
9129
9130 /*
9131 * Done for LK_COMP_TYPE
9132 */
9133
9134 return (0); /* component path is rebuilt successfully */
9135
9136 } /* end rebuild_lk_comp_path() */
9137
9138 /*
9139 * Name: check_ext_attr()
9140 *
9141 * Description:
9142 * Check the extended attributes for a file being extracted.
9143 * The attributes being checked here are CMW labels.
9144 * ACLs are not set here because they are set by the
9145 * pflag in doxtract().
9146 *
9147 * If the label doesn't match, return 0
9148 * else return 1
9149 */
9150 static int
9151 check_ext_attr(char *filename)
9152 {
9153 bslabel_t currentlabel; /* label from zone */
9154
9155 if (bltype(&bs_label, SUN_SL_UN)) {
9156 /* No label check possible */
9157 return (0);
9158 }
9159 if (getlabel(filename, ¤tlabel) != 0) {
9160 (void) fprintf(stderr,
9161 gettext("tar: can't get label for "
9162 " %s, getlabel() error: %s\n"),
9163 filename, strerror(errno));
9164 return (0);
9165 } else if ((blequal(¤tlabel, &bs_label)) == 0) {
9166 char *src_label = NULL; /* ascii label */
9167
9168 /* get current src SL */
9169 if (bsltos(&bs_label, &src_label, 0, 0) <= 0) {
9170 (void) fprintf(stderr,
9171 gettext("tar: can't interpret requested label for"
9172 " %s\n"), filename);
9173 } else {
9174 (void) fprintf(stderr,
9175 gettext("tar: can't apply label %s to %s\n"),
9176 src_label, filename);
9177 free(src_label);
9178 }
9179 (void) fprintf(stderr,
9180 gettext("tar: %s not restored\n"), filename);
9181 return (0);
9182 }
9183 return (1);
9184
9185 } /* end check_ext_attr */
9186
9187 /* Compressing a tar file using compression method provided in 'opt' */
9188
9189 static void
9190 compress_back()
9191 {
9192 pid_t pid;
9193 int status;
9194 int wret;
9195 struct stat statb;
9196
9197 if (vflag) {
9198 (void) fprintf(vfile,
9199 gettext("Compressing '%s' with '%s'...\n"),
9200 usefile, compress_opt);
9201 }
9202 if ((pid = fork()) == 0) {
9203 verify_compress_opt(compress_opt);
9204 (void) execlp(compress_opt, compress_opt,
9205 usefile, NULL);
9206 } else if (pid == -1) {
9207 vperror(1, "%s", gettext("Could not fork"));
9208 }
9209 wait_pid(pid);
9210 if (suffix == 0) {
9211 (void) rename(tfname, usefile);
9212 }
9213 }
9214
9215 /* The magic numbers from /etc/magic */
9216
9217 #define GZIP_MAGIC "\037\213"
9218 #define BZIP_MAGIC "BZh"
9219 #define COMP_MAGIC "\037\235"
9220 #define XZ_MAGIC "\375\067\172\130\132\000"
9221
9222 void
9223 check_compression(void)
9224 {
9225 char magic[16];
9226 FILE *fp;
9227
9228 if ((fp = fopen(usefile, "r")) != NULL) {
9229 (void) fread(magic, sizeof (char), 6, fp);
9230 (void) fclose(fp);
9231 }
9232
9233 if (memcmp(magic, GZIP_MAGIC, 2) == 0) {
9234 if (xflag || tflag) {
9235 compress_opt = compress_malloc(strlen(GZCAT) + 1);
9236 (void) strcpy(compress_opt, GZCAT);
9237 } else if (uflag || rflag) {
9238 compress_opt = compress_malloc(strlen(GZIP) + 1);
9239 (void) strcpy(compress_opt, GZIP);
9240 }
9241 } else if (memcmp(magic, BZIP_MAGIC, 2) == 0) {
9242 if (xflag || tflag) {
9243 compress_opt = compress_malloc(strlen(BZCAT) + 1);
9244 (void) strcpy(compress_opt, BZCAT);
9245 } else if (uflag || rflag) {
9246 compress_opt = compress_malloc(strlen(BZIP) + 1);
9247 (void) strcpy(compress_opt, BZIP);
9248 }
9249 } else if (memcmp(magic, COMP_MAGIC, 2) == 0) {
9250 if (xflag || tflag) {
9251 compress_opt = compress_malloc(strlen(ZCAT) + 1);
9252 (void) strcpy(compress_opt, ZCAT);
9253 } else if (uflag || rflag) {
9254 compress_opt = compress_malloc(strlen(COMPRESS) + 1);
9255 (void) strcpy(compress_opt, COMPRESS);
9256 }
9257 } else if (memcmp(magic, XZ_MAGIC, 6) == 0) {
9258 if (xflag || tflag) {
9259 compress_opt = compress_malloc(strlen(XZCAT) + 1);
9260 (void) strcpy(compress_opt, XZCAT);
9261 } else if (uflag || rflag) {
9262 compress_opt = compress_malloc(strlen(XZ) + 1);
9263 (void) strcpy(compress_opt, XZ);
9264 }
9265 }
9266 }
9267
9268 char *
9269 add_suffix()
9270 {
9271 (void) strcpy(tfname, usefile);
9272 if (strcmp(compress_opt, GZIP) == 0) {
9273 if ((suffix = gz_suffix()) == NULL) {
9274 strlcat(tfname, gsuffix[0], sizeof (tfname));
9275 return (gsuffix[0]);
9276 }
9277 } else if (strcmp(compress_opt, COMPRESS) == 0) {
9278 if ((suffix = gz_suffix()) == NULL) {
9279 strlcat(tfname, gsuffix[6], sizeof (tfname));
9280 return (gsuffix[6]);
9281 }
9282 } else if (strcmp(compress_opt, BZIP) == 0) {
9283 if ((suffix = bz_suffix()) == NULL) {
9284 strlcat(tfname, bsuffix[0], sizeof (tfname));
9285 return (bsuffix[0]);
9286 }
9287 } else if (strcmp(compress_opt, XZ) == 0) {
9288 if ((suffix = xz_suffix()) == NULL) {
9289 strlcat(tfname, xsuffix[0], sizeof (tfname));
9290 return (xsuffix[0]);
9291 }
9292 }
9293 return (NULL);
9294 }
9295
9296 /* Decompressing a tar file using compression method from the file type */
9297 void
9298 decompress_file(void)
9299 {
9300 pid_t pid;
9301 int status;
9302 char cmdstr[PATH_MAX];
9303 char fname[PATH_MAX];
9304 char *added_suffix;
9305
9306
9307 added_suffix = add_suffix();
9308 if (added_suffix != NULL) {
9309 (void) rename(usefile, tfname);
9310 }
9311 if ((pid = fork()) == 0) {
9312 if (vflag) {
9313 (void) fprintf(vfile,
9314 gettext("Decompressing '%s' with "
9315 "'%s'...\n"), usefile, compress_opt);
9316 }
9317 verify_compress_opt(compress_opt);
9318 (void) execlp(compress_opt, compress_opt, "-df",
9319 tfname, NULL);
9320 vperror(1, gettext("Could not exec %s"), compress_opt);
9321 } else if (pid == -1) {
9322 vperror(1, gettext("Could not fork"));
9323 }
9324 wait_pid(pid);
9325 if (suffix != NULL) {
9326 /* restore the file name - original file was without suffix */
9327 *(usefile + strlen(usefile) - strlen(suffix)) = '\0';
9328 }
9329 }
9330
9331 /* Set the archive for writing and then compress the archive */
9332 pid_t
9333 compress_file(void)
9334 {
9335 int fd[2];
9336 pid_t pid;
9337
9338 if (vflag) {
9339 (void) fprintf(vfile, gettext("Compressing '%s' with "
9340 "'%s'...\n"), usefile, compress_opt);
9341 }
9342
9343 if (pipe(fd) < 0) {
9344 vperror(1, gettext("Could not create pipe"));
9345 }
9346 if (pid = fork() > 0) {
9347 mt = fd[1];
9348 (void) close(fd[0]);
9349 return (pid);
9350 }
9351 /* child */
9352 (void) dup2(fd[0], STDIN_FILENO);
9353 (void) close(fd[1]);
9354 (void) dup2(mt, STDOUT_FILENO);
9355 verify_compress_opt(compress_opt);
9356 (void) execlp(compress_opt, compress_opt, NULL);
9357 vperror(1, gettext("Could not exec %s"), compress_opt);
9358 return (0); /*NOTREACHED*/
9359 }
9360
9361 pid_t
9362 uncompress_file(void)
9363 {
9364 int fd[2];
9365 pid_t pid;
9366
9367 if (vflag) {
9368 (void) fprintf(vfile, gettext("Decompressing '%s' with "
9369 "'%s'...\n"), usefile, compress_opt);
9370 }
9371
9372 if (pipe(fd) < 0) {
9373 vperror(1, gettext("Could not create pipe"));
9374 }
9375 if (pid = fork() > 0) {
9376 mt = fd[0];
9377 (void) close(fd[1]);
9378 return (pid);
9379 }
9380 /* child */
9381 (void) dup2(fd[1], STDOUT_FILENO);
9382 (void) close(fd[0]);
9383 (void) dup2(mt, STDIN_FILENO);
9384 verify_compress_opt(compress_opt);
9385 (void) execlp(compress_opt, compress_opt, NULL);
9386 vperror(1, gettext("Could not exec %s"), compress_opt);
9387 return (0); /*NOTREACHED*/
9388 }
9389
9390 /* Checking suffix validity */
9391 char *
9392 check_suffix(char **suf, int size)
9393 {
9394 int i;
9395 int slen;
9396 int nlen = strlen(usefile);
9397
9398 for (i = 0; i < size; i++) {
9399 slen = strlen(suf[i]);
9400 if (nlen < slen)
9401 return (NULL);
9402 if (strcmp(usefile + nlen - slen, suf[i]) == 0)
9403 return (suf[i]);
9404 }
9405 return (NULL);
9406 }
9407
9408 /* Checking valid 'bzip2' suffix */
9409 char *
9410 bz_suffix(void)
9411 {
9412 return (check_suffix(bsuffix, BSUF));
9413 }
9414
9415 /* Checking valid 'gzip' suffix */
9416 char *
9417 gz_suffix(void)
9418 {
9419 return (check_suffix(gsuffix, GSUF));
9420 }
9421
9422 /* Checking valid 'xz' suffix */
9423 char *
9424 xz_suffix(void)
9425 {
9426 return (check_suffix(xsuffix, XSUF));
9427 }
9428
9429 void *
9430 compress_malloc(size_t size)
9431 {
9432 void *opt;
9433
9434 if ((opt = malloc(size)) == NULL) {
9435 vperror(1, "%s",
9436 gettext("Could not allocate compress buffer\n"));
9437 }
9438 return (opt);
9439 }
9440
9441 void
9442 wait_pid(pid_t pid)
9443 {
9444 int status;
9445
9446 while (waitpid(pid, &status, 0) == -1 && errno == EINTR)
9447 ;
9448 }
9449
9450 static void
9451 verify_compress_opt(const char *t)
9452 {
9453 struct stat statbuf;
9454
9455 if (stat(t, &statbuf) == -1)
9456 vperror(1, "%s %s: %s\n", gettext("Could not stat"),
9457 t, strerror(errno));
9458 }
9459
9460 static void
9461 detect_compress(void)
9462 {
9463 char *zsuf[] = {".Z"};
9464 if (check_suffix(zsuf, 1) != NULL) {
9465 Zflag = 1;
9466 } else if (check_suffix(bsuffix, BSUF) != NULL) {
9467 jflag = 1;
9468 } else if (check_suffix(gsuffix, GSUF) != NULL) {
9469 zflag = 1;
9470 } else if (check_suffix(xsuffix, XSUF) != NULL) {
9471 Jflag = 1;
9472 } else {
9473 vperror(1, "%s\n", gettext("No compression method detected"));
9474 }
9475 }