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