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