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