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