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