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