Print this page
1154 cpio needs a quiet option
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/cpio/cpio.c
+++ new/usr/src/cmd/cpio/cpio.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) 2012 Gary Mills
24 25 */
25 26
26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 28 /* All Rights Reserved */
28 29
29 30 /*
30 31 * Portions of this source code were derived from Berkeley 4.3 BSD
31 32 * under license from the Regents of the University of California.
32 33 */
33 34
34 35 #include <stdio.h>
35 36 #include <sys/types.h>
36 37 #include <errno.h>
37 38 #include <unistd.h>
38 39 #include <stdlib.h>
39 40 #include <fcntl.h>
40 41 #include <memory.h>
41 42 #include <string.h>
42 43 #include <stdarg.h>
43 44 #include <sys/stat.h>
44 45 #include <sys/statvfs.h>
45 46 #include <sys/mkdev.h>
46 47 #include <sys/param.h>
47 48 #include <utime.h>
48 49 #include <pwd.h>
49 50 #include <grp.h>
50 51 #include <signal.h>
51 52 #include <ctype.h>
52 53 #include <locale.h>
53 54 #include <sys/ioctl.h>
54 55 #include <sys/mtio.h>
55 56 #include <sys/fdio.h>
56 57 #include "cpio.h"
57 58 #include <sys/acl.h>
58 59 #include <sys/time.h>
59 60 #include <sys/resource.h>
60 61 #include <fnmatch.h>
61 62 #include <libgen.h>
62 63 #include <libintl.h>
63 64 #include <dirent.h>
64 65 #include <limits.h>
65 66 #include <aclutils.h>
66 67 #if defined(_PC_SATTR_ENABLED)
67 68 #include <libnvpair.h>
68 69 #include <attr.h>
69 70 #include <libcmdutils.h>
70 71 #endif /* _PC_SATTR_ENABLED */
71 72 #ifdef SOLARIS_PRIVS
72 73 #include <priv.h>
73 74 #endif /* SOLARIS_PRIVS */
74 75
75 76 /*
76 77 * Special kludge for off_t being a signed quantity.
77 78 */
78 79 #if _FILE_OFFSET_BITS == 64
79 80 typedef u_longlong_t u_off_t;
80 81 #else
81 82 typedef ulong_t u_off_t;
82 83 #endif
83 84
84 85 #define SECMODE 0xe080
85 86
86 87 #define DEVNULL "/dev/null"
87 88 #define XATTRHDR ".hdr"
88 89
89 90 #define NAMELEN 32
90 91 #define TYPELEN 16
91 92 #define PERMLEN 4
92 93
93 94 #define FILE_COPIED 1
94 95 #define FILE_LINKED 2
95 96 #define FILE_PASS_ERR -1
96 97
97 98 #define ARCHIVE_NORMAL 0
98 99 #define ARCHIVE_ACL 1
99 100 #define ARCHIVE_XATTR 2
100 101 #define ARCHIVE_SPARSE 3
101 102
102 103 #ifndef VIEW_READONLY
103 104 #define VIEW_READONLY "SUNWattr_ro"
104 105 #endif
105 106
106 107 #ifndef VIEW_READWRITE
107 108 #define VIEW_READWRITE "SUNWattr_rw"
108 109 #endif
109 110
110 111
111 112 #define LSTAT(dir, path, statbuf) fstatat(dir, \
112 113 get_component((Gen.g_attrnam_p == NULL) ? \
113 114 path : Gen.g_attrnam_p), statbuf, AT_SYMLINK_NOFOLLOW)
114 115 #define STAT(dir, path, statbuf) fstatat(dir, \
115 116 get_component((Gen.g_attrnam_p == NULL) ? \
116 117 path : Gen.g_attrnam_p), statbuf, 0)
117 118
118 119 /*
119 120 * These limits reflect the maximum size regular file that
120 121 * can be archived, depending on the archive type. For archives
121 122 * with character-format headers (odc, tar, ustar) we use
122 123 * CHAR_OFFSET_MAX. For archives with SVR4 ASCII headers (-c, -H crc)
123 124 * we store filesize in an 8-char hexadecimal string and use
124 125 * ASC_OFFSET_MAX. Otherwise, we are limited to the size that will
125 126 * fit in a signed long value.
126 127 */
127 128 #define CHAR_OFFSET_MAX 077777777777ULL /* 11 octal digits */
128 129 #define ASC_OFFSET_MAX 0XFFFFFFFF /* 8 hexadecimal digits */
129 130 #define BIN_OFFSET_MAX LONG_MAX /* signed long max value */
130 131
131 132 #define POSIXMODES 07777
132 133
133 134 static char aclchar = ' ';
134 135
135 136 static struct Lnk *add_lnk(struct Lnk **);
136 137 static int bfill(void);
137 138 static void bflush(void);
138 139 static int chgreel(int dir);
139 140 static int ckname(int);
140 141 static void ckopts(long mask);
141 142 static long cksum(char hdr, int byt_cnt, int *err);
142 143 static int creat_hdr(void);
143 144 static int creat_lnk(int dirfd, char *name1_p, char *name2_p);
144 145 static int creat_spec(int dirfd);
145 146 static int creat_tmp(char *nam_p);
146 147 static void data_in(int proc_mode);
147 148 static void data_out(void);
148 149 static void data_pass(void);
149 150 static void file_in(void);
150 151 static int file_out(void);
151 152 static int file_pass(void);
152 153 static void flush_lnks(void);
153 154 static int gethdr(void);
154 155 static int getname(void);
155 156 static void getpats(int largc, char **largv);
156 157 static void ioerror(int dir);
157 158 static int matched(void);
158 159 static int missdir(char *nam_p);
159 160 static long mklong(short v[]);
160 161 static void mkshort(short sval[], long v);
161 162 static int openout(int dirfd);
162 163 static int read_hdr(int hdr);
163 164 static void reclaim(struct Lnk *l_p);
164 165 static void rstbuf(void);
165 166 static void setpasswd(char *nam);
166 167 static void rstfiles(int over, int dirfd);
167 168 static void scan4trail(void);
168 169 static void setup(int largc, char **largv);
169 170 static void set_tym(int dirfd, char *nam_p, time_t atime, time_t mtime);
170 171 static void sigint(int sig);
171 172 static void swap(char *buf_p, int cnt);
172 173 static void usage(void);
173 174 static void verbose(char *nam_p);
174 175 static void write_hdr(int arcflag, off_t len);
175 176 static void write_trail(void);
176 177 static int ustar_dir(void);
177 178 static int ustar_spec(void);
178 179 static struct stat *convert_to_old_stat(struct stat *, char *, char *);
179 180 static void read_bar_vol_hdr(void);
180 181 static void read_bar_file_hdr(void);
181 182 static void setup_uncompress(FILE **);
182 183 static void skip_bar_volhdr(void);
183 184 static void bar_file_in(void);
184 185 static int g_init(int *devtype, int *fdes);
185 186 static int g_read(int, int, char *, unsigned);
186 187 static int g_write(int, int, char *, unsigned);
187 188 static int is_floppy(int);
188 189 static int is_tape(int);
189 190 static void write_ancillary(char *buf, size_t len, boolean_t padding);
190 191 static int remove_dir(char *);
191 192 static int save_cwd(void);
192 193 static void rest_cwd(int cwd);
193 194
194 195 static void xattrs_out(int (*func)());
195 196 static void get_parent(char *path, char *dir);
196 197 static void prepare_xattr_hdr(char **attrbuf, char *filename,
197 198 char *attrname, char typeflag, struct Lnk *linkinfo, int *rlen);
198 199 static char tartype(int type);
199 200 static int openfile(int omode);
200 201 static mode_t attrmode(char type);
201 202 static char *get_component(char *path);
202 203 static int open_dir(char *name);
203 204 static int open_dirfd();
204 205 static void close_dirfd();
205 206 static void write_xattr_hdr();
206 207 static char *skipslashes(char *string, char *start);
207 208 static int read_xattr_hdr();
208 209 static void chop_endslashes(char *path);
209 210
210 211
211 212 /* helpful types */
212 213
213 214 static
214 215 struct passwd *Curpw_p, /* Current password entry for -t option */
215 216 *Rpw_p, /* Password entry for -R option */
216 217 *dpasswd;
217 218
218 219 static
219 220 struct group *Curgr_p, /* Current group entry for -t option */
220 221 *dgroup;
221 222
222 223 /* Data structure for buffered I/O. */
223 224
224 225 static
225 226 struct buf_info {
226 227 char *b_base_p, /* Pointer to base of buffer */
227 228 *b_out_p, /* Position to take bytes from buffer at */
228 229 *b_in_p, /* Position to put bytes into buffer at */
229 230 *b_end_p; /* Pointer to end of buffer */
230 231 long b_cnt, /* Count of unprocessed bytes */
231 232 b_size; /* Size of buffer in bytes */
232 233 } Buffr;
233 234
234 235 /* Generic header format */
235 236
236 237 static
237 238 struct gen_hdr {
238 239 ulong_t g_magic, /* Magic number field */
239 240 g_ino, /* Inode number of file */
240 241 g_mode, /* Mode of file */
241 242 g_uid, /* Uid of file */
242 243 g_gid, /* Gid of file */
243 244 g_nlink, /* Number of links */
244 245 g_mtime; /* Modification time */
245 246 off_t g_filesz; /* Length of file */
246 247 ulong_t g_dev, /* File system of file */
247 248 g_rdev, /* Major/minor numbers of special files */
248 249 g_namesz, /* Length of filename */
249 250 g_cksum; /* Checksum of file */
250 251 char g_gname[32],
251 252 g_uname[32],
252 253 g_version[2],
253 254 g_tmagic[6],
254 255 g_typeflag;
255 256 char *g_tname,
256 257 *g_prefix,
257 258 *g_nam_p, /* Filename */
258 259 *g_attrparent_p, /* attribute parent */
259 260 *g_attrpath_p, /* attribute path */
260 261 *g_attrnam_p, /* attribute */
261 262 *g_attrfnam_p, /* Real file name attr belongs to */
262 263 *g_linktoattrfnam_p, /* file linked attribute belongs to */
263 264 *g_linktoattrnam_p, /* attribute g_attrnam_p is linked to */
264 265 *g_dirpath; /* dirname currently opened */
265 266 int g_dirfd; /* directory file descriptor */
266 267 int g_passdirfd; /* directory fd to pass to */
267 268 int g_rw_sysattr; /* read-write system attribute */
268 269 int g_baseparent_fd; /* base file's parent fd */
269 270 holes_info_t *g_holes; /* sparse file information */
270 271
271 272 } Gen, *G_p;
272 273
273 274 /* Data structure for handling multiply-linked files */
274 275 static
275 276 char prebuf[PRESIZ+1],
276 277 nambuf[NAMSIZ+1],
277 278 fullnam[MAXNAM+1];
278 279
279 280
280 281 static
281 282 struct Lnk {
282 283 short L_cnt, /* Number of links encountered */
283 284 L_data; /* Data has been encountered if 1 */
284 285 struct gen_hdr L_gen; /* gen_hdr information for this file */
285 286 struct Lnk *L_nxt_p, /* Next file in list */
286 287 *L_bck_p, /* Previous file in list */
287 288 *L_lnk_p; /* Next link for this file */
288 289 } Lnk_hd;
289 290
290 291 static
291 292 struct hdr_cpio Hdr;
292 293
293 294 /*
294 295 * -------------------------------------------------------------------------
295 296 * Stuff needed to pre-view the name stream
296 297 *
297 298 * issymlink is used to remember that the current file is a symlink between
298 299 * getname() and file_pass(); the former trashes this information immediately
299 300 * when -L is specified.
300 301 */
301 302
302 303 static
303 304 int issymlink = 0;
304 305
305 306 static
306 307 FILE *In_p = stdin; /* Where the input comes from */
307 308
308 309 typedef struct sl_info
309 310 {
310 311 struct sl_info *llink; /* Left subtree ptr (tree depth in *sl_head) */
311 312 struct sl_info *rlink; /* Right subtree ptr */
312 313 int bal; /* Subtree balance factor */
313 314 ulong_t sl_count; /* Number of symlinks */
314 315 int sl_ftype; /* file type of inode */
315 316 ino_t sl_ino; /* Inode of file */
316 317 ino_t sl_ino2; /* alternate inode for -Hodc */
317 318 } sl_info_t;
318 319
319 320 typedef struct data_in
320 321 {
321 322 int data_in_errno;
322 323 char data_in_swapfile;
323 324 char data_in_proc_mode;
324 325 char data_in_rd_eof;
325 326 char data_in_wr_part;
326 327 char data_in_compress_flag;
327 328 long data_in_cksumval;
328 329 FILE *data_in_pipef;
329 330 } data_in_t;
330 331
331 332 /*
332 333 * The following structure maintains a hash entry for the
333 334 * balancing trees which are allocated for each device nodes.
334 335 */
335 336 typedef struct sl_info_link
336 337 {
337 338 dev_t dev;
338 339 sl_info_t *head;
339 340 struct sl_info_link *next;
340 341 } sl_info_link_t;
341 342
342 343 #define SL_INFO_ALLOC_CHUNK 1024
343 344 #define NDEVHENTRY 0x40
344 345 #define DEV_HASHKEY(x) ((x) & (NDEVHENTRY -1))
345 346
346 347 /*
347 348 * For remapping dev,inode for -Hodc archives.
348 349 */
349 350
350 351 typedef struct sl_remap
351 352 {
352 353 dev_t dev; /* device */
353 354 int inode_count; /* # inodes seen on dev */
354 355 struct sl_remap *next; /* next in the chain */
355 356 } sl_remap_t;
356 357
357 358 /* forward declarations */
358 359
359 360 static sl_info_t *sl_info_alloc(void);
360 361 static sl_info_t *sl_insert(dev_t, ino_t, int);
361 362 static ulong_t sl_numlinks(dev_t, ino_t, int);
362 363 static void sl_preview_synonyms(void);
363 364 static void sl_remember_tgt(const struct stat *, int, int);
364 365 static sl_info_t *sl_search(dev_t, ino_t, int);
365 366 static sl_info_t *sl_devhash_lookup(dev_t);
366 367 static void sl_devhash_insert(dev_t, sl_info_t *);
367 368
368 369 extern int sl_compare(ino_t, int, ino_t, int);
369 370 #define sl_compare(lino, lftype, rino, rftype) (lino < rino ? -1 : \
370 371 (lino > rino ? 1 : (lftype < rftype ? -1 : \
371 372 (lftype > rftype ? 1 : 0))))
372 373
373 374 /* global storage */
374 375
375 376 static sl_remap_t *sl_remap_head = NULL; /* head of the inode-remap list */
376 377 static sl_info_link_t *sl_devhash[NDEVHENTRY]; /* hash table */
377 378
378 379 /*
379 380 * -------------------------------------------------------------------------
380 381 */
381 382
382 383 static
383 384 struct stat ArchSt, /* stat(2) information of the archive */
384 385 SrcSt, /* stat(2) information of source file */
385 386 DesSt, /* stat(2) of destination file */
386 387 *OldSt = NULL; /* stat info converted to svr32 format */
387 388
388 389 /*
389 390 * bin_mag: Used to validate a binary magic number,
390 391 * by combining to bytes into an unsigned short.
391 392 */
392 393
393 394 static
394 395 union bin_mag {
395 396 unsigned char b_byte[2];
396 397 ushort_t b_half;
397 398 } Binmag;
398 399
399 400 static
400 401 union tblock *Thdr_p; /* TAR header pointer */
401 402
402 403 static union b_block *bar_Vhdr;
403 404 static struct gen_hdr Gen_bar_vol;
404 405
405 406 /*
406 407 * swpbuf: Used in swap() to swap bytes within a halfword,
407 408 * halfwords within a word, or to reverse the order of the
408 409 * bytes within a word. Also used in mklong() and mkshort().
409 410 */
410 411
411 412 static
412 413 union swpbuf {
413 414 unsigned char s_byte[4];
414 415 ushort_t s_half[2];
415 416 ulong_t s_word;
416 417 } *Swp_p;
417 418
418 419 static
419 420 char *myname, /* program name */
420 421 Adir, /* Flags object as a directory */
421 422 Hiddendir, /* Processing hidden attribute directory */
422 423 Aspec, /* Flags object as a special file */
423 424 Do_rename, /* Indicates rename() is to be used */
424 425 Time[50], /* Array to hold date and time */
425 426 Ttyname[] = "/dev/tty", /* Controlling console */
426 427 T_lname[MAXPATHLEN], /* Array to hold links name for tar */
427 428 *Buf_p, /* Buffer for file system I/O */
428 429 *Full_p, /* Pointer to full pathname */
429 430 *Efil_p, /* -E pattern file string */
430 431 *Eom_p = "Change to part %d and press RETURN key. [q] ",
431 432 *Fullnam_p, /* Full pathname */
432 433 *Attrfile_p, /* attribute file */
433 434 *Hdr_p, /* -H header type string */
434 435 *IOfil_p, /* -I/-O input/output archive string */
435 436 *Lnkend_p, /* Pointer to end of Lnknam_p */
436 437 *Lnknam_p, /* Buffer for linking files with -p option */
437 438 *Nam_p, /* Array to hold filename */
438 439 *Savenam_p, /* copy of filename xattr belongs to */
439 440 *Own_p, /* New owner login id string */
440 441 *Renam_p, /* Buffer for renaming files */
441 442 *Renam_attr_p, /* Buffer for renaming attr with sys attrs */
442 443 *Renametmp_p, /* Tmp Buffer for renaming files */
443 444 *Symlnk_p, /* Buffer for holding symbolic link name */
444 445 *Over_p, /* Holds temporary filename when overwriting */
445 446 **Pat_pp = 0, /* Pattern strings */
446 447 bar_linkflag, /* flag to indicate if the file is a link */
447 448 bar_linkname[MAXPATHLEN]; /* store the name of the link */
448 449
449 450 static
450 451 int Append = 0, /* Flag set while searching to end of archive */
451 452 Archive, /* File descriptor of the archive */
452 453 Buf_error = 0, /* I/O error occurred during buffer fill */
453 454 Compress_sparse = 0, /* Compress sparse files */
454 455 Def_mode = 0777, /* Default file/directory protection modes */
455 456 Device, /* Device type being accessed (used with libgenIO) */
456 457 Error_cnt = 0, /* Cumulative count of I/O errors */
457 458 Finished = 1, /* Indicates that a file transfer has completed */
458 459 Hdrsz = ASCSZ, /* Fixed length portion of the header */
459 460 Hdr_type, /* Flag to indicate type of header selected */
460 461 Ifile, /* File des. of file being archived */
461 462 Ofile, /* File des. of file being extracted from archive */
462 463 Use_old_stat = 0, /* Create an old style -Hodc hdr (small dev's) */
463 464 Onecopy = 0, /* Flags old vs. new link handling */
464 465 Pad_val = 0, /* Indicates the number of bytes to pad (if any) */
465 466 PageSize = 0, /* The native page size, used for figuring block size */
466 467 Volcnt = 1, /* Number of archive volumes processed */
467 468 Verbcnt = 0, /* Count of number of dots '.' output */
468 469 Eomflag = 0,
469 470 Dflag = 0,
470 471 Atflag = 0, /* Archive/restore extended attributes */
471 472 SysAtflag = 0, /* Archive/restore extended system attributes */
472 473 Compressed, /* Flag to indicate if the bar archive is compressed */
473 474 Bar_vol_num = 0, /* Volume number count for bar archive */
474 475 privileged = 0, /* Flag set if running with higher privileges */
475 476 attr_baseparent_fd = -1; /* attribute's base file descriptor */
476 477
477 478
478 479 static
479 480 gid_t Lastgid = (gid_t)-1; /* Used with -t & -v to record current gid */
480 481
481 482 static
482 483 uid_t Lastuid = (uid_t)-1; /* Used with -t & -v to record current uid */
483 484
484 485 static
485 486 long Args, /* Mask of selected options */
486 487 Max_namesz = CPATH; /* Maximum size of pathnames/filenames */
487 488
488 489 static
489 490 int Bufsize = BUFSZ; /* Default block size */
490 491
491 492
492 493 static u_longlong_t Blocks; /* full blocks transferred */
493 494 static u_longlong_t SBlocks; /* cumulative char count from short reads */
494 495
495 496
496 497 static off_t Max_offset = BIN_OFFSET_MAX; /* largest file size */
497 498 static off_t Max_filesz; /* from getrlimit */
498 499
499 500 static ulong_t Savedev;
500 501
501 502 static
502 503 FILE *Ef_p, /* File pointer of pattern input file */
503 504 *Err_p = stderr, /* File pointer for error reporting */
504 505 *Out_p = stdout, /* File pointer for non-archive output */
505 506 *Rtty_p, /* Input file pointer for interactive rename */
506 507 *Wtty_p; /* Output file ptr for interactive rename */
507 508
508 509 static
509 510 ushort_t Ftype = S_IFMT; /* File type mask */
510 511
511 512 /* ACL support */
512 513 static struct sec_attr {
513 514 char attr_type;
514 515 char attr_len[7];
515 516 char attr_info[1];
516 517 } *attr;
517 518
518 519 static int Pflag = 0; /* flag indicates that acl is preserved */
519 520 static int acl_is_set = 0; /* True if an acl was set on the file */
520 521
521 522 acl_t *aclp;
522 523
523 524 #if defined(O_XATTR)
524 525 typedef enum {
525 526 ATTR_OK,
526 527 ATTR_SKIP,
527 528 ATTR_CHDIR_ERR,
528 529 ATTR_OPEN_ERR,
529 530 ATTR_XATTR_ERR,
530 531 ATTR_SATTR_ERR
531 532 } attr_status_t;
532 533 #endif
533 534
534 535 #if defined(O_XATTR)
535 536 typedef enum {
536 537 ARC_CREATE,
537 538 ARC_RESTORE
538 539 } arc_action_t;
539 540 #endif
540 541
541 542
542 543 /*
543 544 *
544 545 * cpio has been changed to support extended attributes.
545 546 *
546 547 * As part of this change cpio has been changed to use the new *at() syscalls
547 548 * such as openat, fchownat(), unlinkat()...
548 549 *
549 550 * This was done so that attributes can be handled with as few code changes
550 551 * as possible.
551 552 *
552 553 * What this means is that cpio now opens the directory that a file or directory
553 554 * resides in and then performs *at() functions to manipulate the entry.
554 555 *
555 556 * For example a new file is now created like this:
556 557 *
557 558 * dfd = open(<some dir path>)
558 559 * fd = openat(dfd, <name>,....);
559 560 *
560 561 * or in the case of an extended attribute
561 562 *
562 563 * dfd = attropen(<pathname>, ".", ....)
563 564 *
564 565 * Once we have a directory file descriptor all of the *at() functions can
565 566 * be applied to it.
566 567 *
567 568 * unlinkat(dfd, <component name>,...)
568 569 * fchownat(dfd, <component name>,..)
569 570 *
570 571 * This works for both normal namespace files and extended attribute file
571 572 *
572 573 */
573 574
574 575 /*
575 576 * Extended attribute layout
576 577 *
577 578 * Extended attributes are stored in two pieces.
578 579 * 1. An attribute header which has information about
579 580 * what file the attribute is for and what the attribute
580 581 * is named.
581 582 * 2. The attribute record itself. Stored as a normal file type
582 583 * of entry.
583 584 * Both the header and attribute record have special modes/typeflags
584 585 * associated with them.
585 586 *
586 587 * The names of the header in the archive look like:
587 588 * /dev/null/attr.hdr
588 589 *
589 590 * The name of the attribute looks like:
590 591 * /dev/null/attr.
591 592 *
592 593 * This is done so that an archiver that doesn't understand these formats
593 594 * can just dispose of the attribute records unless the user chooses to
594 595 * rename them via cpio -r or pax -i
595 596 *
596 597 * The format is composed of a fixed size header followed
597 598 * by a variable sized xattr_buf. If the attribute is a hard link
598 599 * to another attribute, then another xattr_buf section is included
599 600 * for the link.
600 601 *
601 602 * The xattr_buf is used to define the necessary "pathing" steps
602 603 * to get to the extended attribute. This is necessary to support
603 604 * a fully recursive attribute model where an attribute may itself
604 605 * have an attribute.
605 606 *
606 607 * The basic layout looks like this.
607 608 *
608 609 * --------------------------------
609 610 * | |
610 611 * | xattr_hdr |
611 612 * | |
612 613 * --------------------------------
613 614 * --------------------------------
614 615 * | |
615 616 * | xattr_buf |
616 617 * | |
617 618 * --------------------------------
618 619 * --------------------------------
619 620 * | |
620 621 * | (optional link info) |
621 622 * | |
622 623 * --------------------------------
623 624 * --------------------------------
624 625 * | |
625 626 * | attribute itself |
626 627 * | stored as normal tar |
627 628 * | or cpio data with |
628 629 * | special mode or |
629 630 * | typeflag |
630 631 * | |
631 632 * --------------------------------
632 633 *
633 634 */
634 635
635 636 /*
636 637 * Extended attributes structures
637 638 *
638 639 * xattrhead is the complete extended attribute header, as read of off
639 640 * disk/tape. It includes the variable xattr_buf portion.
640 641 *
641 642 * xattrp is basically an offset into xattrhead that points to the
642 643 * "pathing" section which defines how to get to the attribute.
643 644 *
644 645 * xattr_linkp is identical to xattrp except that it is used for linked
645 646 * attributes. It provides the pathing steps to get to the linked
646 647 * attribute.
647 648 *
648 649 * These structures are updated when an extended attribute header is read off
649 650 * of disk/tape.
650 651 */
651 652 static struct xattr_hdr *xattrhead;
652 653 static struct xattr_buf *xattrp;
653 654 static struct xattr_buf *xattr_linkp;
654 655 static int xattrbadhead; /* is extended attribute header bad? */
655 656
656 657 static int append_secattr(char **, int *, acl_t *);
657 658
658 659 /*
659 660 * Note regarding cpio and changes to ensure cpio doesn't try to second
660 661 * guess whether it runs with sufficient privileges or not:
661 662 *
662 663 * cpio has been changed so that it doesn't carry a second implementation of
663 664 * the kernel's policy with respect to privileges. Instead of attempting
664 665 * to restore uid and gid from an archive only if cpio is run as uid 0,
665 666 * cpio now *always* tries to restore the uid and gid from the archive
666 667 * except when the -R option is specified. When the -R is specified,
667 668 * the uid and gid of the restored file will be changed to those of the
668 669 * login id specified. In addition, chown(), set_tym(), and chmod() should
669 670 * only be executed once during archive extraction, and to ensure
670 671 * setuid/setgid bits are restored properly, chown() should always be
671 672 * executed before chmod().
672 673 *
673 674 * Note regarding debugging mechanism for cpio:
674 675 *
675 676 * The following mechanism is provided to allow us to debug cpio in complicated
676 677 * situations, like when it is part of a pipe. The idea is that you compile
677 678 * with -DWAITAROUND defined, and then add the "-z" command line option to the
678 679 * target cpio invocation. If stderr is available, it will tell you to which
679 680 * pid to attach the debugger; otherwise, use ps to find it. Attach to the
680 681 * process from the debugger, and, *PRESTO*, you are there!
681 682 *
682 683 * Simply assign "waitaround = 0" once you attach to the process, and then
683 684 * proceed from there as usual.
684 685 */
685 686
686 687 #ifdef WAITAROUND
687 688 int waitaround = 0; /* wait for rendezvous with the debugger */
688 689 #endif
689 690
690 691 #define EXIT_CODE (Error_cnt > 255 ? 255 : Error_cnt)
691 692
692 693 /*
693 694 * main: Call setup() to process options and perform initializations,
694 695 * and then select either copy in (-i), copy out (-o), or pass (-p) action.
695 696 */
696 697
697 698 int
698 699 main(int argc, char **argv)
699 700 {
700 701 int i;
701 702 int passret;
702 703
703 704 (void) setlocale(LC_ALL, "");
704 705 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
705 706 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
706 707 #endif
707 708 (void) textdomain(TEXT_DOMAIN);
708 709
709 710 (void) memset(&Gen, 0, sizeof (Gen));
710 711 myname = e_strdup(E_EXIT, basename(argv[0]));
711 712 setup(argc, argv);
712 713
713 714 if (signal(SIGINT, sigint) == SIG_IGN)
714 715 (void) signal(SIGINT, SIG_IGN);
715 716 switch (Args & (OCi | OCo | OCp)) {
716 717 case OCi: /* COPY IN */
717 718 Hdr_type = NONE;
718 719 if (Atflag || SysAtflag) {
719 720 /*
720 721 * Save the current working directory, so
721 722 * we can change back here after cd'ing into
722 723 * the attribute directory when processing
723 724 * attributes.
724 725 */
725 726 if ((attr_baseparent_fd = save_cwd()) < 0) {
726 727 msg(EXT, "Unable to open current directory.");
727 728 }
728 729 }
729 730 while ((i = gethdr()) != 0) {
730 731 Gen.g_dirfd = -1;
731 732 if (i == 1) {
732 733 file_in();
733 734 /*
734 735 * Any ACL info for this file would or should
735 736 * have been used after file_in(); clear out
736 737 * aclp so it is is not erroneously used on
737 738 * the next file.
738 739 */
739 740 if (aclp != NULL) {
740 741 acl_free(aclp);
741 742 aclp = NULL;
742 743 }
743 744 acl_is_set = 0;
744 745 }
745 746 (void) memset(&Gen, 0, sizeof (Gen));
746 747 }
747 748 /* Do not count "extra" "read-ahead" buffered data */
748 749 if (Buffr.b_cnt > Bufsize)
749 750 Blocks -= (u_longlong_t)(Buffr.b_cnt / Bufsize);
750 751 break;
751 752 case OCo: /* COPY OUT */
752 753 if (Args & OCA) {
753 754 scan4trail();
754 755 }
755 756
756 757 Gen.g_dirfd = -1;
757 758 Gen.g_dirpath = NULL;
758 759 sl_preview_synonyms();
759 760
760 761 while ((i = getname()) != 0) {
761 762 if (i == 1) {
762 763 (void) file_out();
763 764 if (Atflag || SysAtflag) {
764 765 if (Gen.g_dirfd != -1) {
765 766 (void) close(Gen.g_dirfd);
766 767 }
767 768 Gen.g_dirfd = -1;
768 769 xattrs_out(file_out);
769 770 }
770 771 }
771 772 if (aclp != NULL) {
772 773 acl_free(aclp);
773 774 aclp = NULL;
774 775 acl_is_set = 0;
775 776 }
776 777 }
777 778 write_trail();
778 779 break;
779 780 case OCp: /* PASS */
780 781 sl_preview_synonyms();
781 782
782 783 Gen.g_dirfd = -1;
783 784 Gen.g_passdirfd = -1;
784 785 Gen.g_dirpath = NULL;
785 786 Compress_sparse = 1;
786 787 while (getname()) {
787 788 /*
788 789 * If file is a fully qualified path then
789 790 * file_pass will strip off the leading '/'
790 791 * and we need to save off the unstripped
791 792 * name for attribute traversal.
792 793 */
793 794 if (Atflag || SysAtflag) {
794 795 (void) strcpy(Savenam_p, Gen.g_nam_p);
795 796 }
796 797 passret = file_pass();
797 798 if (aclp != NULL) {
798 799 acl_free(aclp);
799 800 aclp = NULL;
800 801 acl_is_set = 0;
801 802 }
802 803 if (Gen.g_passdirfd != -1)
803 804 (void) close(Gen.g_passdirfd);
804 805 Gen.g_passdirfd = -1;
805 806 if (Atflag || SysAtflag) {
806 807 if (Gen.g_dirfd != -1) {
807 808 (void) close(Gen.g_dirfd);
808 809 }
809 810 Gen.g_dirfd = -1;
810 811 if (passret != FILE_LINKED) {
811 812 Gen.g_nam_p = Savenam_p;
812 813 xattrs_out(file_pass);
813 814 }
814 815 }
815 816 }
816 817 break;
817 818 default:
↓ open down ↓ |
784 lines elided |
↑ open up ↑ |
818 819 msg(EXT, "Impossible action.");
819 820 }
820 821 if (Ofile > 0) {
821 822 if (close(Ofile) != 0)
822 823 msg(EXTN, "close error");
823 824 }
824 825 if (Archive > 0) {
825 826 if (close(Archive) != 0)
826 827 msg(EXTN, "close error");
827 828 }
828 - Blocks = (u_longlong_t)(Blocks * Bufsize + SBlocks + 0x1FF) >> 9;
829 - msg(EPOST, "%lld blocks", Blocks);
829 + if ((Args & OCq) == 0) {
830 + Blocks = (u_longlong_t)(Blocks * Bufsize + SBlocks +
831 + 0x1FF) >> 9;
832 + msg(EPOST, "%lld blocks", Blocks);
833 + }
830 834 if (Error_cnt)
831 835 msg(EPOST, "%d error(s)", Error_cnt);
832 836 return (EXIT_CODE);
833 837 }
834 838
835 839 /*
836 840 * add_lnk: Add a linked file's header to the linked file data structure, by
837 841 * either adding it to the end of an existing sub-list or starting
838 842 * a new sub-list. Each sub-list saves the links to a given file.
839 843 *
840 844 * Directly returns a pointer to the new entry; returns a pointer to the head
841 845 * of the sub-list in which that entry is located through the argument.
842 846 */
843 847
844 848 static struct Lnk *
845 849 add_lnk(struct Lnk **sublist_return)
846 850 {
847 851 struct Lnk *new_entry, *sublist;
848 852
849 853 for (sublist = Lnk_hd.L_nxt_p;
850 854 sublist != &Lnk_hd;
851 855 sublist = sublist->L_nxt_p) {
852 856 if (sublist->L_gen.g_ino == G_p->g_ino &&
853 857 sublist->L_gen.g_dev == G_p->g_dev) {
854 858 /* found */
855 859 break;
856 860 }
857 861 }
858 862
859 863 new_entry = e_zalloc(E_EXIT, sizeof (struct Lnk));
860 864
861 865 new_entry->L_lnk_p = NULL;
862 866 new_entry->L_gen = *G_p; /* structure copy */
863 867
864 868 new_entry->L_gen.g_nam_p = e_zalloc(E_EXIT, (size_t)G_p->g_namesz);
865 869
866 870 (void) strcpy(new_entry->L_gen.g_nam_p, G_p->g_nam_p);
867 871
868 872 if (sublist == &Lnk_hd) {
869 873 /* start new sub-list */
870 874 new_entry->L_nxt_p = &Lnk_hd;
871 875 new_entry->L_bck_p = Lnk_hd.L_bck_p;
872 876 Lnk_hd.L_bck_p = new_entry->L_bck_p->L_nxt_p = new_entry;
873 877 new_entry->L_lnk_p = NULL;
874 878 new_entry->L_cnt = 1;
875 879 new_entry->L_data = Onecopy ? 0 : 1;
876 880 sublist = new_entry;
877 881 } else {
878 882 /* add to existing sub-list */
879 883 struct Lnk *ptr;
880 884
881 885 sublist->L_cnt++;
882 886
883 887 for (ptr = sublist;
884 888 ptr->L_lnk_p != NULL;
885 889 ptr = ptr->L_lnk_p) {
886 890 ptr->L_gen.g_filesz = G_p->g_filesz;
887 891 }
888 892
889 893 ptr->L_gen.g_filesz = G_p->g_filesz;
890 894 ptr->L_lnk_p = new_entry;
891 895 }
892 896
893 897 *sublist_return = sublist;
894 898 return (new_entry);
895 899 }
896 900
897 901 /*
898 902 * bfill: Read req_cnt bytes (out of filelen bytes) from the I/O buffer,
899 903 * moving them to rd_buf_p. When there are no bytes left in the I/O buffer,
900 904 * Fillbuf is set and the I/O buffer is filled. The variable dist is the
901 905 * distance to lseek if an I/O error is encountered with the -k option set
902 906 * (converted to a multiple of Bufsize).
903 907 */
904 908
905 909 static int
906 910 bfill(void)
907 911 {
908 912 int i = 0, rv;
909 913 static int eof = 0;
910 914
911 915 if (!Dflag) {
912 916 while ((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) {
913 917 errno = 0;
914 918 if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
915 919 if (((Buffr.b_end_p - Buffr.b_in_p) >= Bufsize) &&
916 920 (Eomflag == 0)) {
917 921 Eomflag = 1;
918 922 return (1);
919 923 }
920 924 if (errno == ENOSPC) {
921 925 (void) chgreel(INPUT);
922 926 if (Hdr_type == BAR) {
923 927 skip_bar_volhdr();
924 928 }
925 929 continue;
926 930 } else if (Args & OCk) {
927 931 if (i++ > MX_SEEKS)
928 932 msg(EXT, "Cannot recover.");
929 933 if (lseek(Archive, Bufsize, SEEK_REL) < 0)
930 934 msg(EXTN, "Cannot lseek()");
931 935 Error_cnt++;
932 936 Buf_error++;
933 937 rv = 0;
934 938 continue;
935 939 } else
936 940 ioerror(INPUT);
937 941 } /* (rv = g_read(Device, Archive ... */
938 942 if (Hdr_type != BAR || rv == Bufsize) {
939 943 Buffr.b_in_p += rv;
940 944 Buffr.b_cnt += (long)rv;
941 945 }
942 946 if (rv == Bufsize) {
943 947 eof = 0;
944 948 Blocks++;
945 949 } else if (rv == 0) {
946 950 if (!eof) {
947 951 eof = 1;
948 952 break;
949 953 }
950 954 (void) chgreel(INPUT);
951 955 eof = 0; /* reset the eof after chgreel */
952 956
953 957 /*
954 958 * if spans multiple volume, skip the volume header of
955 959 * the next volume so that the file currently being
956 960 * extracted can continue to be extracted.
957 961 */
958 962 if (Hdr_type == BAR) {
959 963 skip_bar_volhdr();
960 964 }
961 965
962 966 continue;
963 967 } else {
964 968 eof = 0;
965 969 SBlocks += (u_longlong_t)rv;
966 970 }
967 971 } /* (Buffr.b_end_p - Buffr.b_in_p) <= Bufsize */
968 972
969 973 } else { /* Dflag */
970 974 errno = 0;
971 975 if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0) {
972 976 return (-1);
973 977 } /* (rv = g_read(Device, Archive ... */
974 978 Buffr.b_in_p += rv;
975 979 Buffr.b_cnt += (long)rv;
976 980 if (rv == Bufsize) {
977 981 eof = 0;
978 982 Blocks++;
979 983 } else if (!rv) {
980 984 if (!eof) {
981 985 eof = 1;
982 986 return (rv);
983 987 }
984 988 return (-1);
985 989 } else {
986 990 eof = 0;
987 991 SBlocks += (u_longlong_t)rv;
988 992 }
989 993 }
990 994 return (rv);
991 995 }
992 996
993 997 /*
994 998 * bflush: Move wr_cnt bytes from data_p into the I/O buffer. When the
995 999 * I/O buffer is full, Flushbuf is set and the buffer is written out.
996 1000 */
997 1001
998 1002 static void
999 1003 bflush(void)
1000 1004 {
1001 1005 int rv;
1002 1006
1003 1007 while (Buffr.b_cnt >= Bufsize) {
1004 1008 errno = 0;
1005 1009 if ((rv = g_write(Device, Archive, Buffr.b_out_p,
1006 1010 Bufsize)) < 0) {
1007 1011 if (errno == ENOSPC && !Dflag)
1008 1012 rv = chgreel(OUTPUT);
1009 1013 else
1010 1014 ioerror(OUTPUT);
1011 1015 }
1012 1016 Buffr.b_out_p += rv;
1013 1017 Buffr.b_cnt -= (long)rv;
1014 1018 if (rv == Bufsize)
1015 1019 Blocks++;
1016 1020 else if (rv > 0)
1017 1021 SBlocks += (u_longlong_t)rv;
1018 1022 }
1019 1023 rstbuf();
1020 1024 }
1021 1025
1022 1026 /*
1023 1027 * chgreel: Determine if end-of-medium has been reached. If it has,
1024 1028 * close the current medium and prompt the user for the next medium.
1025 1029 */
1026 1030
1027 1031 static int
1028 1032 chgreel(int dir)
1029 1033 {
1030 1034 int lastchar, tryagain, askagain, rv;
1031 1035 int tmpdev;
1032 1036 char str[APATH];
1033 1037 struct stat statb;
1034 1038
1035 1039 rv = 0;
1036 1040 if (fstat(Archive, &statb) < 0)
1037 1041 msg(EXTN, "Error during stat() of archive");
1038 1042 if ((statb.st_mode & S_IFMT) != S_IFCHR) {
1039 1043 if (dir == INPUT) {
1040 1044 msg(EXT, "%s%s\n",
1041 1045 "Can't read input: end of file encountered ",
1042 1046 "prior to expected end of archive.");
1043 1047 }
1044 1048 }
1045 1049 msg(EPOST, "\007End of medium on \"%s\".", dir ? "output" : "input");
1046 1050 if (is_floppy(Archive))
1047 1051 (void) ioctl(Archive, FDEJECT, NULL);
1048 1052 if ((close(Archive) != 0) && (dir == OUTPUT))
1049 1053 msg(EXTN, "close error");
1050 1054 Archive = 0;
1051 1055 Volcnt++;
1052 1056 for (;;) {
1053 1057 if (Rtty_p == NULL)
1054 1058 Rtty_p = fopen(Ttyname, "r");
1055 1059 do { /* tryagain */
1056 1060 if (IOfil_p) {
1057 1061 do {
1058 1062 msg(EPOST, Eom_p, Volcnt);
1059 1063 if (!Rtty_p || fgets(str, sizeof (str),
1060 1064 Rtty_p) == NULL)
1061 1065 msg(EXT, "Cannot read tty.");
1062 1066 askagain = 0;
1063 1067 switch (*str) {
1064 1068 case '\n':
1065 1069 (void) strcpy(str, IOfil_p);
1066 1070 break;
1067 1071 case 'q':
1068 1072 exit(EXIT_CODE);
1069 1073 default:
1070 1074 askagain = 1;
1071 1075 }
1072 1076 } while (askagain);
1073 1077 } else {
1074 1078
1075 1079 if (Hdr_type == BAR)
1076 1080 Bar_vol_num++;
1077 1081
1078 1082 msg(EPOST,
1079 1083 "To continue, type device/file name when "
1080 1084 "ready.");
1081 1085 if (!Rtty_p || fgets(str, sizeof (str),
1082 1086 Rtty_p) == NULL)
1083 1087 msg(EXT, "Cannot read tty.");
1084 1088 lastchar = strlen(str) - 1;
1085 1089 if (*(str + lastchar) == '\n') /* remove '\n' */
1086 1090 *(str + lastchar) = '\0';
1087 1091 if (!*str)
1088 1092 exit(EXIT_CODE);
1089 1093 }
1090 1094 tryagain = 0;
1091 1095 if ((Archive = open(str, dir)) < 0) {
1092 1096 msg(ERRN, "Cannot open \"%s\"", str);
1093 1097 tryagain = 1;
1094 1098 }
1095 1099 } while (tryagain);
1096 1100 (void) g_init(&tmpdev, &Archive);
1097 1101 if (tmpdev != Device)
1098 1102 msg(EXT, "Cannot change media types in mid-stream.");
1099 1103 if (dir == INPUT)
1100 1104 break;
1101 1105 else { /* dir == OUTPUT */
1102 1106 errno = 0;
1103 1107 if ((rv = g_write(Device, Archive, Buffr.b_out_p,
1104 1108 Bufsize)) == Bufsize)
1105 1109 break;
1106 1110 else
1107 1111 msg(ERR,
1108 1112 "Unable to write this medium, try "
1109 1113 "another.");
1110 1114 }
1111 1115 } /* ;; */
1112 1116 Eomflag = 0;
1113 1117 return (rv);
1114 1118 }
1115 1119
1116 1120 /*
1117 1121 * ckname: Check filenames against user specified patterns,
1118 1122 * and/or ask the user for new name when -r is used.
1119 1123 */
1120 1124
1121 1125 static int
1122 1126 ckname(int flag)
1123 1127 {
1124 1128 int lastchar;
1125 1129 size_t rename_bufsz = Max_namesz + 1;
1126 1130
1127 1131 if (Hdr_type != TAR && Hdr_type != USTAR && Hdr_type != BAR) {
1128 1132 /* Re-visit tar size issues later */
1129 1133 if (G_p->g_namesz - 1 > Max_namesz) {
1130 1134 msg(ERR, "Name exceeds maximum length - skipped.");
1131 1135 return (F_SKIP);
1132 1136 }
1133 1137 }
1134 1138
1135 1139 if (Pat_pp && !matched())
1136 1140 return (F_SKIP);
1137 1141
1138 1142 /* rename interactively */
1139 1143 if ((Args & OCr) && !Adir && !G_p->g_rw_sysattr) {
1140 1144 (void) fprintf(Wtty_p, gettext("Rename \"%s%s%s\"? "),
1141 1145 (G_p->g_attrnam_p == NULL) ? G_p->g_nam_p : Renam_p,
1142 1146 (G_p->g_attrnam_p == NULL) ? "" : gettext(" Attribute "),
1143 1147 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
1144 1148 (void) fflush(Wtty_p);
1145 1149 if (fgets(Renametmp_p, rename_bufsz, Rtty_p) == NULL)
1146 1150 msg(EXT, "Cannot read tty.");
1147 1151 if (feof(Rtty_p))
1148 1152 exit(EXIT_CODE);
1149 1153 lastchar = strlen(Renametmp_p) - 1;
1150 1154
1151 1155 /* remove trailing '\n' */
1152 1156 if (*(Renametmp_p + lastchar) == '\n')
1153 1157 *(Renametmp_p + lastchar) = '\0';
1154 1158 if (*Renametmp_p == '\0') {
1155 1159 msg(POST, "%s%s%s Skipped.",
1156 1160 (G_p->g_attrnam_p == NULL) ? G_p->g_nam_p :
1157 1161 G_p->g_attrfnam_p,
1158 1162 (G_p->g_attrnam_p == NULL) ? "" :
1159 1163 gettext(" Attribute "),
1160 1164 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
1161 1165 if (G_p->g_attrparent_p == NULL) {
1162 1166 *G_p->g_nam_p = '\0';
1163 1167 }
1164 1168 if (Renam_attr_p) {
1165 1169 *Renam_attr_p = '\0';
1166 1170 }
1167 1171 return (F_SKIP);
1168 1172 } else if (strcmp(Renametmp_p, ".") != 0) {
1169 1173 if (G_p->g_attrnam_p == NULL) {
1170 1174 if (strlen(Renametmp_p) > strlen(
1171 1175 G_p->g_nam_p)) {
1172 1176 if ((G_p->g_nam_p != &nambuf[0]) &&
1173 1177 (G_p->g_nam_p != &fullnam[0])) {
1174 1178 free(G_p->g_nam_p);
1175 1179 G_p->g_nam_p = e_zalloc(E_EXIT,
1176 1180 rename_bufsz);
1177 1181 }
1178 1182 }
1179 1183 if (Renam_attr_p) {
1180 1184 *Renam_attr_p = '\0';
1181 1185 }
1182 1186 if ((strlcpy(Renam_p, Renametmp_p,
1183 1187 rename_bufsz) > rename_bufsz) ||
1184 1188 (strlcpy(G_p->g_nam_p, Renametmp_p,
1185 1189 rename_bufsz) > rename_bufsz)) {
1186 1190 msg(EXTN, "buffer overflow");
1187 1191 }
1188 1192 } else {
1189 1193 if (G_p->g_attrnam_p != NULL) {
1190 1194 free(G_p->g_attrnam_p);
1191 1195 G_p->g_attrnam_p = e_strdup(E_EXIT,
1192 1196 Renametmp_p);
1193 1197 (void) strcpy(G_p->g_nam_p, Renam_p);
1194 1198 if (Renam_attr_p) {
1195 1199 if (strlcpy(Renam_attr_p,
1196 1200 Renametmp_p, rename_bufsz) >
1197 1201 rename_bufsz) {
1198 1202 msg(EXTN,
1199 1203 "buffer overflow");
1200 1204 }
1201 1205 }
1202 1206 }
1203 1207 }
1204 1208 } else {
1205 1209 if (G_p->g_attrnam_p == NULL) {
1206 1210 *Renam_p = '\0';
1207 1211 }
1208 1212 if (Renam_attr_p) {
1209 1213 *Renam_attr_p = '\0';
1210 1214 }
1211 1215 }
1212 1216 }
1213 1217 if (flag != 0 || Onecopy == 0) {
1214 1218 VERBOSE((Args & OCt), G_p->g_nam_p);
1215 1219 }
1216 1220 if (Args & OCt)
1217 1221 return (F_SKIP);
1218 1222 return (F_EXTR);
1219 1223 }
1220 1224
1221 1225 /*
1222 1226 * ckopts: Check the validity of all command line options.
1223 1227 */
1224 1228
1225 1229 static void
1226 1230 ckopts(long mask)
1227 1231 {
1228 1232 int oflag;
1229 1233 char *t_p;
1230 1234 long errmsk;
1231 1235 uid_t Euid = geteuid(); /* Effective uid of invoker */
1232 1236 #ifdef SOLARIS_PRIVS
1233 1237 priv_set_t *privset;
1234 1238 priv_set_t *zones_privset;
1235 1239 #endif /* SOLARIS_PRIVS */
1236 1240
1237 1241 if (mask & OCi) {
1238 1242 errmsk = mask & INV_MSK4i;
1239 1243 } else if (mask & OCo) {
1240 1244 errmsk = mask & INV_MSK4o;
1241 1245 } else if (mask & OCp) {
1242 1246 errmsk = mask & INV_MSK4p;
1243 1247 } else {
1244 1248 msg(ERR, "One of -i, -o or -p must be specified.");
1245 1249 errmsk = 0;
1246 1250 }
1247 1251
1248 1252 if (errmsk) {
1249 1253 /* if non-zero, invalid options were specified */
1250 1254 Error_cnt++;
1251 1255 }
1252 1256
1253 1257 if ((mask & OCa) && (mask & OCm) && ((mask & OCi) ||
1254 1258 (mask & OCo))) {
1255 1259 msg(ERR, "-a and -m are mutually exclusive.");
1256 1260 }
1257 1261
1258 1262 if ((mask & OCc) && (mask & OCH) &&
1259 1263 (strcmp("odc", Hdr_p) != 0 && strcmp("odc_sparse", Hdr_p) != 0)) {
1260 1264 msg(ERR, "-c and -H are mutually exclusive.");
1261 1265 }
1262 1266
1263 1267 if ((mask & OCv) && (mask & OCV)) {
1264 1268 msg(ERR, "-v and -V are mutually exclusive.");
1265 1269 }
1266 1270
1267 1271 if ((mask & OCt) && (mask & OCV)) {
1268 1272 msg(ERR, "-t and -V are mutually exclusive.");
1269 1273 }
1270 1274
1271 1275 if ((mask & OCB) && (mask & OCC)) {
1272 1276 msg(ERR, "-B and -C are mutually exclusive.");
1273 1277 }
1274 1278
1275 1279 if ((mask & OCH) && (mask & OC6)) {
1276 1280 msg(ERR, "-H and -6 are mutually exclusive.");
1277 1281 }
1278 1282
1279 1283 if ((mask & OCM) && !((mask & OCI) || (mask & OCO))) {
1280 1284 msg(ERR, "-M not meaningful without -O or -I.");
1281 1285 }
1282 1286
1283 1287 if ((mask & OCA) && !(mask & OCO)) {
1284 1288 msg(ERR, "-A requires the -O option.");
1285 1289 }
1286 1290
1287 1291 if (Bufsize <= 0) {
1288 1292 msg(ERR, "Illegal size given for -C option.");
1289 1293 }
1290 1294
1291 1295 if (mask & OCH) {
1292 1296 t_p = Hdr_p;
1293 1297
1294 1298 while (*t_p != NULL) {
1295 1299 if (isupper(*t_p)) {
1296 1300 *t_p = 'a' + (*t_p - 'A');
1297 1301 }
1298 1302
1299 1303 t_p++;
1300 1304 }
1301 1305
1302 1306 if (!(strcmp("odc", Hdr_p))) {
1303 1307 Hdr_type = CHR;
1304 1308 Max_namesz = CPATH;
1305 1309 Onecopy = 0;
1306 1310 Use_old_stat = 1;
1307 1311 } else if (!(strcmp("odc_sparse", Hdr_p))) {
1308 1312 Hdr_type = CHR;
1309 1313 Max_namesz = CPATH;
1310 1314 Onecopy = 0;
1311 1315 Use_old_stat = 1;
1312 1316 Compress_sparse = 1;
1313 1317 } else if (!(strcmp("ascii_sparse", Hdr_p))) {
1314 1318 Hdr_type = ASC;
1315 1319 Max_namesz = APATH;
1316 1320 Onecopy = 1;
1317 1321 Compress_sparse = 1;
1318 1322 } else if (!(strcmp("crc", Hdr_p))) {
1319 1323 Hdr_type = CRC;
1320 1324 Max_namesz = APATH;
1321 1325 Onecopy = 1;
1322 1326 } else if (!(strcmp("tar", Hdr_p))) {
1323 1327 if (Args & OCo) {
1324 1328 Hdr_type = USTAR;
1325 1329 Max_namesz = HNAMLEN - 1;
1326 1330 } else {
1327 1331 Hdr_type = TAR;
1328 1332 Max_namesz = TNAMLEN - 1;
1329 1333 }
1330 1334 Onecopy = 0;
1331 1335 } else if (!(strcmp("ustar", Hdr_p))) {
1332 1336 Hdr_type = USTAR;
1333 1337 Max_namesz = HNAMLEN - 1;
1334 1338 Onecopy = 0;
1335 1339 } else if (!(strcmp("bar", Hdr_p))) {
1336 1340 if ((Args & OCo) || (Args & OCp)) {
1337 1341 msg(ERR,
1338 1342 "Header type bar can only be used with -i");
1339 1343 }
1340 1344
1341 1345 if (Args & OCP) {
1342 1346 msg(ERR,
1343 1347 "Can't preserve using bar header");
1344 1348 }
1345 1349
1346 1350 Hdr_type = BAR;
1347 1351 Max_namesz = TNAMLEN - 1;
1348 1352 Onecopy = 0;
1349 1353 } else {
1350 1354 msg(ERR, "Invalid header \"%s\" specified", Hdr_p);
1351 1355 }
1352 1356 }
1353 1357
1354 1358 if (mask & OCr) {
1355 1359 Rtty_p = fopen(Ttyname, "r");
1356 1360 Wtty_p = fopen(Ttyname, "w");
1357 1361
1358 1362 if (Rtty_p == NULL || Wtty_p == NULL) {
1359 1363 msg(ERR, "Cannot rename, \"%s\" missing", Ttyname);
1360 1364 }
1361 1365 }
1362 1366
1363 1367 if ((mask & OCE) && (Ef_p = fopen(Efil_p, "r")) == NULL) {
1364 1368 msg(ERR, "Cannot open \"%s\" to read patterns", Efil_p);
1365 1369 }
1366 1370
1367 1371 if ((mask & OCI) && (Archive = open(IOfil_p, O_RDONLY)) < 0) {
1368 1372 msg(ERR, "Cannot open \"%s\" for input", IOfil_p);
1369 1373 }
1370 1374
1371 1375 if (mask & OCO) {
1372 1376 if (mask & OCA) {
1373 1377 if ((Archive = open(IOfil_p, O_RDWR)) < 0) {
1374 1378 msg(ERR,
1375 1379 "Cannot open \"%s\" for append",
1376 1380 IOfil_p);
1377 1381 }
1378 1382 } else {
1379 1383 oflag = (O_WRONLY | O_CREAT | O_TRUNC);
1380 1384
1381 1385 if ((Archive = open(IOfil_p, oflag, 0777)) < 0) {
1382 1386 msg(ERR,
1383 1387 "Cannot open \"%s\" for output",
1384 1388 IOfil_p);
1385 1389 }
1386 1390 }
1387 1391 }
1388 1392
1389 1393 #ifdef SOLARIS_PRIVS
1390 1394 if ((privset = priv_allocset()) == NULL) {
1391 1395 msg(ERR, "Unable to allocate privilege set");
1392 1396 } else if (getppriv(PRIV_EFFECTIVE, privset) != 0) {
1393 1397 msg(ERR, "Unable to obtain privilege set");
1394 1398 } else {
1395 1399 zones_privset = priv_str_to_set("zone", "", NULL);
1396 1400 if (zones_privset != NULL) {
1397 1401 privileged = (priv_issubset(zones_privset,
1398 1402 privset) == B_TRUE);
1399 1403 priv_freeset(zones_privset);
1400 1404 } else {
1401 1405 msg(ERR, "Unable to map privilege to privilege set");
1402 1406 }
1403 1407 }
1404 1408 if (privset != NULL) {
1405 1409 priv_freeset(privset);
1406 1410 }
1407 1411 #else
1408 1412 privileged = (Euid == 0);
1409 1413 #endif /* SOLARIS_PRIVS */
1410 1414
1411 1415 if (mask & OCR) {
1412 1416 if ((Rpw_p = getpwnam(Own_p)) == NULL) {
1413 1417 msg(ERR, "\"%s\" is not a valid user id", Own_p);
1414 1418 } else if ((Euid != Rpw_p->pw_uid) && !privileged) {
1415 1419 msg(ERR, "R option only valid for super-user or "
1416 1420 "id matches login id of user executing cpio");
1417 1421 }
1418 1422 }
1419 1423
1420 1424 if ((mask & OCo) && !(mask & OCO)) {
1421 1425 Out_p = stderr;
1422 1426 }
1423 1427
1424 1428 if ((mask & OCp) && ((mask & (OCB|OCC)) == 0)) {
1425 1429 /*
1426 1430 * We are in pass mode with no block size specified. Use the
1427 1431 * larger of the native page size and 8192.
1428 1432 */
1429 1433
1430 1434 Bufsize = (PageSize > 8192) ? PageSize : 8192;
1431 1435 }
1432 1436 }
1433 1437
1434 1438 /*
1435 1439 * cksum: Calculate the simple checksum of a file (CRC) or header
1436 1440 * (TARTYP (TAR and USTAR)). For -o and the CRC header, the file is opened and
1437 1441 * the checksum is calculated. For -i and the CRC header, the checksum
1438 1442 * is calculated as each block is transferred from the archive I/O buffer
1439 1443 * to the file system I/O buffer. The TARTYP (TAR and USTAR) headers calculate
1440 1444 * the simple checksum of the header (with the checksum field of the
1441 1445 * header initialized to all spaces (\040).
1442 1446 */
1443 1447
1444 1448 static long
1445 1449 cksum(char hdr, int byt_cnt, int *err)
1446 1450 {
1447 1451 char *crc_p, *end_p;
1448 1452 int cnt;
1449 1453 long checksum = 0L, have;
1450 1454 off_t lcnt;
1451 1455
1452 1456 if (err != NULL)
1453 1457 *err = 0;
1454 1458 switch (hdr) {
1455 1459 case CRC:
1456 1460 if (Args & OCi) { /* do running checksum */
1457 1461 end_p = Buffr.b_out_p + byt_cnt;
1458 1462 for (crc_p = Buffr.b_out_p; crc_p < end_p; crc_p++)
1459 1463 checksum += (long)*crc_p;
1460 1464 break;
1461 1465 }
1462 1466 /* OCo - do checksum of file */
1463 1467 lcnt = G_p->g_filesz;
1464 1468
1465 1469 while (lcnt > 0) {
1466 1470 have = (lcnt < Bufsize) ? lcnt : Bufsize;
1467 1471 errno = 0;
1468 1472 if (read(Ifile, Buf_p, have) != have) {
1469 1473 msg(ERR, "Error computing checksum.");
1470 1474 if (err != NULL)
1471 1475 *err = 1;
1472 1476 break;
1473 1477 }
1474 1478 end_p = Buf_p + have;
1475 1479 for (crc_p = Buf_p; crc_p < end_p; crc_p++)
1476 1480 checksum += (long)*crc_p;
1477 1481 lcnt -= have;
1478 1482 }
1479 1483 if (lseek(Ifile, (off_t)0, SEEK_ABS) < 0)
1480 1484 msg(ERRN, "Cannot reset file after checksum");
1481 1485 break;
1482 1486 case TARTYP: /* TAR and USTAR */
1483 1487 crc_p = Thdr_p->tbuf.t_cksum;
1484 1488 for (cnt = 0; cnt < TCRCLEN; cnt++) {
1485 1489 *crc_p = '\040';
1486 1490 crc_p++;
1487 1491 }
1488 1492 crc_p = (char *)Thdr_p;
1489 1493 for (cnt = 0; cnt < TARSZ; cnt++) {
1490 1494 /*
1491 1495 * tar uses unsigned checksum, so we must use unsigned
1492 1496 * here in order to be able to read tar archives.
1493 1497 */
1494 1498 checksum += (long)((unsigned char)(*crc_p));
1495 1499 crc_p++;
1496 1500 }
1497 1501 break;
1498 1502 default:
1499 1503 msg(EXT, "Impossible header type.");
1500 1504 } /* hdr */
1501 1505 return (checksum);
1502 1506 }
1503 1507
1504 1508 /*
1505 1509 * creat_hdr: Fill in the generic header structure with the specific
1506 1510 * header information based on the value of Hdr_type.
1507 1511 *
1508 1512 * return (1) if this process was successful, and (0) otherwise.
1509 1513 */
1510 1514
1511 1515 static int
1512 1516 creat_hdr(void)
1513 1517 {
1514 1518 ushort_t ftype;
1515 1519 int fullnamesize;
1516 1520 dev_t dev;
1517 1521 ino_t ino;
1518 1522
1519 1523 ftype = SrcSt.st_mode & Ftype;
1520 1524 Adir = (ftype == S_IFDIR);
1521 1525 Aspec = (ftype == S_IFBLK || ftype == S_IFCHR || ftype == S_IFIFO ||
1522 1526 ftype == S_IFSOCK);
1523 1527 switch (Hdr_type) {
1524 1528 case BIN:
1525 1529 Gen.g_magic = CMN_BIN;
1526 1530 break;
1527 1531 case CHR:
1528 1532 Gen.g_magic = CMN_BIN;
1529 1533 break;
1530 1534 case ASC:
1531 1535 Gen.g_magic = CMN_ASC;
1532 1536 break;
1533 1537 case CRC:
1534 1538 Gen.g_magic = CMN_CRC;
1535 1539 break;
1536 1540 case USTAR:
1537 1541 /*
1538 1542 * If the length of the full name is greater than 256,
1539 1543 * print out a message and return.
1540 1544 */
1541 1545 if ((fullnamesize = strlen(Gen.g_nam_p)) > MAXNAM) {
1542 1546 msg(ERR,
1543 1547 "%s: file name too long", Gen.g_nam_p);
1544 1548 return (0);
1545 1549 } else if (fullnamesize > NAMSIZ) {
1546 1550 /*
1547 1551 * The length of the full name is greater than
1548 1552 * 100, so we must split the filename from the
1549 1553 * path
1550 1554 */
1551 1555 char namebuff[NAMSIZ+1];
1552 1556 char prebuff[PRESIZ+1];
1553 1557 char *lastslash;
1554 1558 int presize, namesize;
1555 1559
1556 1560 (void) memset(namebuff, '\0',
1557 1561 sizeof (namebuff));
1558 1562 (void) memset(prebuff, '\0', sizeof (prebuff));
1559 1563
1560 1564 lastslash = strrchr(Gen.g_nam_p, '/');
1561 1565
1562 1566 if (lastslash != NULL) {
1563 1567 namesize = strlen(++lastslash);
1564 1568 presize = fullnamesize - namesize - 1;
1565 1569 } else {
1566 1570 namesize = fullnamesize;
1567 1571 lastslash = Gen.g_nam_p;
1568 1572 presize = 0;
1569 1573 }
1570 1574
1571 1575 /*
1572 1576 * If the filename is greater than 100 we can't
1573 1577 * archive the file
1574 1578 */
1575 1579 if (namesize > NAMSIZ) {
1576 1580 msg(ERR,
1577 1581 "%s: filename is greater than %d",
1578 1582 lastslash, NAMSIZ);
1579 1583 return (0);
1580 1584 }
1581 1585 (void) strncpy(&namebuff[0], lastslash,
1582 1586 namesize);
1583 1587 /*
1584 1588 * If the prefix is greater than 155 we can't
1585 1589 * archive the file.
1586 1590 */
1587 1591 if (presize > PRESIZ) {
1588 1592 msg(ERR,
1589 1593 "%s: prefix is greater than %d",
1590 1594 Gen.g_nam_p, PRESIZ);
1591 1595 return (0);
1592 1596 }
1593 1597 (void) strncpy(&prebuff[0], Gen.g_nam_p,
1594 1598 presize);
1595 1599
1596 1600 Gen.g_tname = e_zalloc(E_EXIT, namesize + 1);
1597 1601 (void) strcpy(Gen.g_tname, namebuff);
1598 1602
1599 1603 Gen.g_prefix = e_zalloc(E_EXIT, presize + 1);
1600 1604 (void) strcpy(Gen.g_prefix, prebuff);
1601 1605 } else {
1602 1606 Gen.g_tname = Gen.g_nam_p;
1603 1607 }
1604 1608 (void) strcpy(Gen.g_tmagic, "ustar");
1605 1609 (void) strcpy(Gen.g_version, "00");
1606 1610
1607 1611 dpasswd = getpwuid(SrcSt.st_uid);
1608 1612 if (dpasswd == NULL) {
1609 1613 msg(EPOST,
1610 1614 "cpio: could not get passwd information "
1611 1615 "for %s%s%s",
1612 1616 (Gen.g_attrnam_p == NULL) ?
1613 1617 Gen.g_nam_p : Gen.g_attrfnam_p,
1614 1618 (Gen.g_attrnam_p == NULL) ?
1615 1619 "" : Gen.g_rw_sysattr ?
1616 1620 gettext(" System Attribute ") :
1617 1621 gettext(" Attribute "),
1618 1622 (Gen.g_attrnam_p == NULL) ?
1619 1623 "" : Gen.g_attrnam_p);
1620 1624 /* make name null string */
1621 1625 Gen.g_uname[0] = '\0';
1622 1626 } else {
1623 1627 (void) strncpy(&Gen.g_uname[0],
1624 1628 dpasswd->pw_name, 32);
1625 1629 }
1626 1630 dgroup = getgrgid(SrcSt.st_gid);
1627 1631 if (dgroup == NULL) {
1628 1632 msg(EPOST,
1629 1633 "cpio: could not get group information "
1630 1634 "for %s%s%s",
1631 1635 (Gen.g_attrnam_p == NULL) ?
1632 1636 Gen.g_nam_p : Gen.g_attrfnam_p,
1633 1637 (Gen.g_attrnam_p == NULL) ?
1634 1638 "" : Gen.g_rw_sysattr ?
1635 1639 gettext(" System Attribute ") :
1636 1640 gettext(" Attribute "),
1637 1641 (Gen.g_attrnam_p == NULL) ?
1638 1642 "" : Gen.g_attrnam_p);
1639 1643 /* make name null string */
1640 1644 Gen.g_gname[0] = '\0';
1641 1645 } else {
1642 1646 (void) strncpy(&Gen.g_gname[0],
1643 1647 dgroup->gr_name, 32);
1644 1648 }
1645 1649 Gen.g_typeflag = tartype(ftype);
1646 1650 /* FALLTHROUGH */
1647 1651 case TAR:
1648 1652 (void) memset(T_lname, '\0', sizeof (T_lname));
1649 1653 break;
1650 1654 default:
1651 1655 msg(EXT, "Impossible header type.");
1652 1656 }
1653 1657
1654 1658 if (Use_old_stat && (Gen.g_attrnam_p != NULL)) {
1655 1659 /*
1656 1660 * When processing extended attributes, creat_hdr()
1657 1661 * can get called multiple times which means that
1658 1662 * SrcSt.st.st_dev would have gotten converted to
1659 1663 * -Hodc format. We should always use the original
1660 1664 * device here as we need to be able to match on
1661 1665 * the original device id from the file that was
1662 1666 * previewed in sl_preview_synonyms().
1663 1667 */
1664 1668 dev = Savedev;
1665 1669 } else {
1666 1670 dev = SrcSt.st_dev;
1667 1671 }
1668 1672 ino = SrcSt.st_ino;
1669 1673
1670 1674 if (Use_old_stat) {
1671 1675 SrcSt = *OldSt;
1672 1676 }
1673 1677
1674 1678 Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
1675 1679 Gen.g_uid = SrcSt.st_uid;
1676 1680 Gen.g_gid = SrcSt.st_gid;
1677 1681 Gen.g_dev = SrcSt.st_dev;
1678 1682
1679 1683 if (Use_old_stat) {
1680 1684 /* -Hodc */
1681 1685
1682 1686 sl_info_t *p = sl_search(dev, ino, ftype);
1683 1687 Gen.g_ino = p ? p->sl_ino2 : -1;
1684 1688
1685 1689 if (Gen.g_ino == (ulong_t)-1) {
1686 1690 msg(ERR, "%s%s%s: cannot be archived - inode too big "
1687 1691 "for -Hodc format",
1688 1692 (Gen.g_attrnam_p == NULL) ?
1689 1693 Gen.g_nam_p : Gen.g_attrfnam_p,
1690 1694 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
1691 1695 gettext(" System Attribute ") :
1692 1696 gettext(" Attribute "),
1693 1697 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_attrnam_p);
1694 1698 return (0);
1695 1699 }
1696 1700 } else {
1697 1701 Gen.g_ino = SrcSt.st_ino;
1698 1702 }
1699 1703
1700 1704 Gen.g_mode = SrcSt.st_mode;
1701 1705 Gen.g_mtime = SrcSt.st_mtime;
1702 1706 Gen.g_nlink = Adir ? SrcSt.st_nlink : sl_numlinks(dev, ino, ftype);
1703 1707
1704 1708 if (ftype == S_IFREG || ftype == S_IFLNK)
1705 1709 Gen.g_filesz = (off_t)SrcSt.st_size;
1706 1710 else
1707 1711 Gen.g_filesz = (off_t)0;
1708 1712 Gen.g_rdev = SrcSt.st_rdev;
1709 1713 return (1);
1710 1714 }
1711 1715
1712 1716 /*
1713 1717 * creat_lnk: Create a link from the existing name1_p to name2_p.
1714 1718 */
1715 1719
1716 1720 static
1717 1721 int
1718 1722 creat_lnk(int dirfd, char *name1_p, char *name2_p)
1719 1723 {
1720 1724 int cnt = 0;
1721 1725
1722 1726 do {
1723 1727 errno = 0;
1724 1728 if (!link(name1_p, name2_p)) {
1725 1729 if (aclp != NULL) {
1726 1730 acl_free(aclp);
1727 1731 aclp = NULL;
1728 1732 acl_is_set = 0;
1729 1733 }
1730 1734 cnt = 0;
1731 1735 break;
1732 1736 } else if ((errno == EEXIST) && (cnt == 0)) {
1733 1737 struct stat lsb1;
1734 1738 struct stat lsb2;
1735 1739
1736 1740 /*
1737 1741 * Check to see if we are trying to link this
1738 1742 * file to itself. If so, count the effort as
1739 1743 * successful. If the two files are different,
1740 1744 * or if either lstat is unsuccessful, proceed
1741 1745 * as we would have otherwise; the appropriate
1742 1746 * error will be reported subsequently.
1743 1747 */
1744 1748
1745 1749 if (lstat(name1_p, &lsb1) != 0) {
1746 1750 msg(ERR, "Cannot lstat source file %s",
1747 1751 name1_p);
1748 1752 } else {
1749 1753 if (lstat(name2_p, &lsb2) != 0) {
1750 1754 msg(ERR, "Cannot lstat "
1751 1755 "destination file %s", name2_p);
1752 1756 } else {
1753 1757 if (lsb1.st_dev == lsb2.st_dev &&
1754 1758 lsb1.st_ino == lsb2.st_ino) {
1755 1759 VERBOSE((Args & (OCv | OCV)),
1756 1760 name2_p);
1757 1761 return (0);
1758 1762 }
1759 1763 }
1760 1764 }
1761 1765
1762 1766 if (!(Args & OCu) && G_p->g_mtime <= DesSt.st_mtime)
1763 1767 msg(ERR, "Existing \"%s\" same age or newer",
1764 1768 name2_p);
1765 1769 else if (unlinkat(dirfd, get_component(name2_p), 0) < 0)
1766 1770 msg(ERRN, "Error cannot unlink \"%s\"",
1767 1771 name2_p);
1768 1772 }
1769 1773 cnt++;
1770 1774 } while ((cnt < 2) && missdir(name2_p) == 0);
1771 1775 if (!cnt) {
1772 1776 char *newname;
1773 1777 char *fromname;
1774 1778 char *attrname;
1775 1779
1776 1780 newname = name2_p;
1777 1781 fromname = name1_p;
1778 1782 attrname = Gen.g_attrnam_p;
1779 1783 if (attrname) {
1780 1784 if (Args & OCp) {
1781 1785 newname = fromname = Fullnam_p;
1782 1786 } else {
1783 1787 newname = Gen.g_attrfnam_p;
1784 1788 }
1785 1789 }
1786 1790 if (Args & OCv) {
1787 1791 (void) fprintf(Err_p,
1788 1792 gettext("%s%s%s linked to %s%s%s\n"), newname,
1789 1793 (attrname == NULL) ? "" : gettext(" attribute "),
1790 1794 (attrname == NULL) ? "" : attrname,
1791 1795 (attrname == NULL) ? fromname : newname,
1792 1796 (attrname == NULL) ? "" : gettext(" attribute "),
1793 1797 (attrname == NULL) ? "" : name1_p);
1794 1798 } else {
1795 1799 VERBOSE((Args & (OCv | OCV)), newname);
1796 1800 }
1797 1801 } else if (cnt == 1)
1798 1802 msg(ERRN,
1799 1803 "Unable to create directory for \"%s\"", name2_p);
1800 1804 else if (cnt == 2)
1801 1805 msg(ERRN,
1802 1806 "Cannot link \"%s\" and \"%s\"", name1_p, name2_p);
1803 1807 return (cnt);
1804 1808 }
1805 1809
1806 1810 /*
1807 1811 * creat_spec:
1808 1812 * Create one of the following:
1809 1813 * directory
1810 1814 * character special file
1811 1815 * block special file
1812 1816 * fifo
1813 1817 * socket
1814 1818 */
1815 1819
1816 1820 static int
1817 1821 creat_spec(int dirfd)
1818 1822 {
1819 1823 char *nam_p;
1820 1824 int cnt, result, rv = 0;
1821 1825 char *curdir;
1822 1826 char *lastslash;
1823 1827
1824 1828 Do_rename = 0; /* creat_tmp() may reset this */
1825 1829
1826 1830 if (Args & OCp) {
1827 1831 nam_p = Fullnam_p;
1828 1832 } else {
1829 1833 nam_p = G_p->g_nam_p;
1830 1834 }
1831 1835
1832 1836 /*
1833 1837 * Is this the extraction of the hidden attribute directory?
1834 1838 * If we are processing the hidden attribute directory of an
1835 1839 * attribute, then just return as modes and times cannot be set.
1836 1840 * Otherwise, if we are processing a hidden attribute, just set
1837 1841 * the mode/times correctly and return.
1838 1842 */
1839 1843
1840 1844 if (Hiddendir) {
1841 1845 if (G_p->g_attrparent_p == NULL) {
1842 1846 if (Args & OCR) {
1843 1847 if (fchownat(dirfd, ".", Rpw_p->pw_uid,
1844 1848 Rpw_p->pw_gid, 0) != 0) {
1845 1849 msg(ERRN,
1846 1850 "Cannot chown() \"attribute "
1847 1851 "directory of file %s\"",
1848 1852 G_p->g_attrfnam_p);
1849 1853 }
1850 1854 } else if ((fchownat(dirfd, ".", G_p->g_uid,
1851 1855 G_p->g_gid, 0) != 0) && privileged) {
1852 1856 msg(ERRN,
1853 1857 "Cannot chown() \"attribute directory of "
1854 1858 "file %s\"", G_p->g_attrfnam_p);
1855 1859 }
1856 1860
1857 1861 if (fchmod(dirfd, G_p->g_mode) != 0) {
1858 1862 msg(ERRN,
1859 1863 "Cannot chmod() \"attribute directory of "
1860 1864 "file %s\"", G_p->g_attrfnam_p);
1861 1865 }
1862 1866
1863 1867 acl_is_set = 0;
1864 1868 if (Pflag && aclp != NULL) {
1865 1869 if (facl_set(dirfd, aclp) < 0) {
1866 1870 msg(ERRN,
1867 1871 "failed to set acl on attribute"
1868 1872 " directory of %s ",
1869 1873 G_p->g_attrfnam_p);
1870 1874 } else {
1871 1875 acl_is_set = 1;
1872 1876 }
1873 1877 acl_free(aclp);
1874 1878 aclp = NULL;
1875 1879 }
1876 1880 }
1877 1881
1878 1882 return (1);
1879 1883 }
1880 1884
1881 1885 result = stat(nam_p, &DesSt);
1882 1886
1883 1887 if (ustar_dir() || Adir) {
1884 1888 /*
1885 1889 * The archive file is a directory.
1886 1890 * Skip "." and ".."
1887 1891 */
1888 1892
1889 1893 curdir = strrchr(nam_p, '.');
1890 1894
1891 1895 if (curdir != NULL && curdir[1] == NULL) {
1892 1896 lastslash = strrchr(nam_p, '/');
1893 1897
1894 1898 if (lastslash != NULL) {
1895 1899 lastslash++;
1896 1900 } else {
1897 1901 lastslash = nam_p;
1898 1902 }
1899 1903
1900 1904 if (!(strcmp(lastslash, ".")) ||
1901 1905 !(strcmp(lastslash, ".."))) {
1902 1906 return (1);
1903 1907 }
1904 1908 }
1905 1909
1906 1910 if (result == 0) {
1907 1911 /* A file by the same name exists. */
1908 1912
1909 1913 /* Take care of ACLs */
1910 1914 acl_is_set = 0;
1911 1915
1912 1916 if (Pflag && aclp != NULL) {
1913 1917 if (acl_set(nam_p, aclp) < 0) {
1914 1918 msg(ERRN,
1915 1919 "\"%s\": failed to set acl",
1916 1920 nam_p);
1917 1921 } else {
1918 1922 acl_is_set = 1;
1919 1923 }
1920 1924
1921 1925 acl_free(aclp);
1922 1926 aclp = NULL;
1923 1927 }
1924 1928 if (Args & OCd) {
1925 1929 /*
1926 1930 * We are creating directories. Keep the
1927 1931 * existing file.
1928 1932 */
1929 1933
1930 1934 rstfiles(U_KEEP, dirfd);
1931 1935 }
1932 1936
1933 1937 /* Report success. */
1934 1938
1935 1939 return (1);
1936 1940 }
1937 1941 } else {
1938 1942 /* The archive file is not a directory. */
1939 1943
1940 1944 if (result == 0) {
1941 1945 /*
1942 1946 * A file by the same name exists. Move it to a
1943 1947 * temporary file.
1944 1948 */
1945 1949
1946 1950 if (creat_tmp(nam_p) < 0) {
1947 1951 /*
1948 1952 * We weren't able to create the temp file.
1949 1953 * Report failure.
1950 1954 */
1951 1955
1952 1956 return (0);
1953 1957 }
1954 1958 }
1955 1959 }
1956 1960
1957 1961 /*
1958 1962 * This pile tries to create the file directly, and, if there is a
1959 1963 * problem, creates missing directories, and then tries to create the
1960 1964 * file again. Two strikes and you're out.
1961 1965 */
1962 1966
1963 1967 cnt = 0;
1964 1968
1965 1969 do {
1966 1970 if (ustar_dir() || Adir) {
1967 1971 /* The archive file is a directory. */
1968 1972
1969 1973 result = mkdir(nam_p, G_p->g_mode);
1970 1974 } else if (ustar_spec() || Aspec) {
1971 1975 /*
1972 1976 * The archive file is block special,
1973 1977 * char special, socket, or a fifo.
1974 1978 * Note that, for a socket, the third
1975 1979 * parameter to mknod() is ignored.
1976 1980 */
1977 1981
1978 1982 result = mknod(nam_p, (int)G_p->g_mode,
1979 1983 (int)G_p->g_rdev);
1980 1984 }
1981 1985
1982 1986 if (result >= 0) {
1983 1987 /*
1984 1988 * The file creation succeeded. Take care of the ACLs.
1985 1989 */
1986 1990
1987 1991 acl_is_set = 0;
1988 1992
1989 1993 if (Pflag && aclp != NULL) {
1990 1994 if (acl_set(nam_p, aclp) < 0) {
1991 1995 msg(ERRN,
1992 1996 "\"%s\": failed to set acl", nam_p);
1993 1997 } else {
1994 1998 acl_is_set = 1;
1995 1999 }
1996 2000
1997 2001 acl_free(aclp);
1998 2002 aclp = NULL;
1999 2003 }
2000 2004
2001 2005 cnt = 0;
2002 2006 break;
2003 2007 }
2004 2008
2005 2009 cnt++;
2006 2010 } while (cnt < 2 && missdir(nam_p) == 0);
2007 2011
2008 2012 switch (cnt) {
2009 2013 case 0:
2010 2014 rv = 1;
2011 2015 rstfiles(U_OVER, dirfd);
2012 2016 break;
2013 2017
2014 2018 case 1:
2015 2019 msg(ERRN,
2016 2020 "Cannot create directory for \"%s\"", nam_p);
2017 2021
2018 2022 if (*Over_p == '\0') {
2019 2023 rstfiles(U_KEEP, dirfd);
2020 2024 }
2021 2025
2022 2026 break;
2023 2027
2024 2028 case 2:
2025 2029 if (ustar_dir() || Adir) {
2026 2030 msg(ERRN, "Cannot create directory \"%s\"", nam_p);
2027 2031 } else if (ustar_spec() || Aspec) {
2028 2032 msg(ERRN, "Cannot mknod() \"%s\"", nam_p);
2029 2033 }
2030 2034
2031 2035 if (*Over_p == '\0') {
2032 2036 rstfiles(U_KEEP, dirfd);
2033 2037 }
2034 2038
2035 2039 break;
2036 2040
2037 2041 default:
2038 2042 msg(EXT, "Impossible case.");
2039 2043 }
2040 2044
2041 2045 return (rv);
2042 2046 }
2043 2047
2044 2048 /*
2045 2049 * creat_tmp:
2046 2050 */
2047 2051
2048 2052 static int
2049 2053 creat_tmp(char *nam_p)
2050 2054 {
2051 2055 char *t_p;
2052 2056 int cwd;
2053 2057
2054 2058 if ((Args & OCp) && G_p->g_ino == DesSt.st_ino &&
2055 2059 G_p->g_dev == DesSt.st_dev) {
2056 2060 msg(ERR, "Attempt to pass a file to itself.");
2057 2061 return (-1);
2058 2062 }
2059 2063
2060 2064 if (G_p->g_mtime <= DesSt.st_mtime && !(Args & OCu)) {
2061 2065 msg(ERR, "Existing \"%s\" same age or newer", nam_p);
2062 2066 return (-1);
2063 2067 }
2064 2068
2065 2069 /* Make the temporary file name. */
2066 2070
2067 2071 (void) strcpy(Over_p, nam_p);
2068 2072 t_p = Over_p + strlen(Over_p);
2069 2073
2070 2074 while (t_p != Over_p) {
2071 2075 if (*(t_p - 1) == '/')
2072 2076 break;
2073 2077 t_p--;
2074 2078 }
2075 2079
2076 2080 (void) strcpy(t_p, "XXXXXX");
2077 2081
2078 2082 if (G_p->g_attrnam_p != NULL) {
2079 2083 /*
2080 2084 * Save our current directory, so we can go into
2081 2085 * the attribute directory to make the temp file
2082 2086 * and then return.
2083 2087 */
2084 2088
2085 2089 cwd = save_cwd();
2086 2090 (void) fchdir(G_p->g_dirfd);
2087 2091 }
2088 2092
2089 2093 (void) mktemp(Over_p);
2090 2094
2091 2095 if (G_p->g_attrnam_p != NULL) {
2092 2096 /* Return to the current directory. */
2093 2097
2094 2098 rest_cwd(cwd);
2095 2099 }
2096 2100
2097 2101 if (*Over_p == '\0') {
2098 2102 /* mktemp reports a failure. */
2099 2103
2100 2104 msg(ERR, "Cannot get temporary file name.");
2101 2105 return (-1);
2102 2106 }
2103 2107
2104 2108 /*
2105 2109 * If it's a regular file, write to the temporary file, and then rename
2106 2110 * in order to accommodate potential executables.
2107 2111 *
2108 2112 * Note: g_typeflag is only defined (set) for USTAR archive types. It
2109 2113 * defaults to 0 in the cpio-format-regular file case, so this test
2110 2114 * succeeds.
2111 2115 */
2112 2116
2113 2117 if (G_p->g_typeflag == 0 &&
2114 2118 (DesSt.st_mode & (ulong_t)Ftype) == S_IFREG &&
2115 2119 (G_p->g_mode & (ulong_t)Ftype) == S_IFREG) {
2116 2120 /*
2117 2121 * The archive file and the filesystem file are both regular
2118 2122 * files. We write to the temporary file in this case.
2119 2123 */
2120 2124
2121 2125 if (Args & OCp) {
2122 2126 if (G_p->g_attrnam_p == NULL) {
2123 2127 Fullnam_p = Over_p;
2124 2128 } else {
2125 2129 Attrfile_p = Over_p;
2126 2130 }
2127 2131 } else {
2128 2132 G_p->g_nam_p = Over_p;
2129 2133 if (G_p->g_attrnam_p != NULL) {
2130 2134 Attrfile_p = Over_p;
2131 2135 }
2132 2136 }
2133 2137
2134 2138 if (G_p->g_attrnam_p == NULL) {
2135 2139 Over_p = nam_p;
2136 2140 } else {
2137 2141 Over_p = G_p->g_attrnam_p;
2138 2142 }
2139 2143
2140 2144 Do_rename = 1;
2141 2145 } else {
2142 2146 /*
2143 2147 * Either the archive file or the filesystem file is not a
2144 2148 * regular file.
2145 2149 */
2146 2150
2147 2151 Do_rename = 0;
2148 2152
2149 2153 if (S_ISDIR(DesSt.st_mode)) {
2150 2154 /*
2151 2155 * The filesystem file is a directory.
2152 2156 *
2153 2157 * Save the current working directory because we will
2154 2158 * want to restore it back just in case remove_dir()
2155 2159 * fails or get confused about where we should be.
2156 2160 */
2157 2161
2158 2162 *Over_p = '\0';
2159 2163 cwd = save_cwd();
2160 2164
2161 2165 if (remove_dir(nam_p) < 0) {
2162 2166 msg(ERRN,
2163 2167 "Cannot remove the directory \"%s\"",
2164 2168 nam_p);
2165 2169 /*
2166 2170 * Restore working directory back to the one
2167 2171 * saved earlier.
2168 2172 */
2169 2173
2170 2174 rest_cwd(cwd);
2171 2175 return (-1);
2172 2176 }
2173 2177
2174 2178 /*
2175 2179 * Restore working directory back to the one
2176 2180 * saved earlier
2177 2181 */
2178 2182
2179 2183 rest_cwd(cwd);
2180 2184 } else {
2181 2185 /*
2182 2186 * The file is not a directory. Will use the original
2183 2187 * link/unlink construct, however, if the file is
2184 2188 * namefs, link would fail with EXDEV. Therefore, we
2185 2189 * use rename() first to back up the file.
2186 2190 */
2187 2191 if (rename(nam_p, Over_p) < 0) {
2188 2192 /*
2189 2193 * If rename failed, try old construction
2190 2194 * method.
2191 2195 */
2192 2196 if (link(nam_p, Over_p) < 0) {
2193 2197 msg(ERRN,
2194 2198 "Cannot rename temporary file "
2195 2199 "\"%s\" to \"%s\"", Over_p, nam_p);
2196 2200 *Over_p = '\0';
2197 2201 return (-1);
2198 2202 }
2199 2203
2200 2204 if (unlink(nam_p) < 0) {
2201 2205 msg(ERRN,
2202 2206 "Cannot unlink() current \"%s\"",
2203 2207 nam_p);
2204 2208 (void) unlink(Over_p);
2205 2209 *Over_p = '\0';
2206 2210 return (-1);
2207 2211 }
2208 2212 }
2209 2213 }
2210 2214 }
2211 2215
2212 2216 return (1);
2213 2217 }
2214 2218
2215 2219 /*
2216 2220 * Copy the datasize amount of data from the input file to buffer.
2217 2221 *
2218 2222 * ifd - Input file descriptor.
2219 2223 * buffer - Buffer (allocated by caller) to copy data to.
2220 2224 * datasize - The amount of data to read from the input file
2221 2225 * and copy to the buffer.
2222 2226 * error - When reading from an Archive file, indicates unreadable
2223 2227 * data was encountered, otherwise indicates errno.
2224 2228 * data_in_info - Information needed when called from data_in().
2225 2229 */
2226 2230 static ssize_t
2227 2231 read_chunk(int ifd, char *buffer, size_t datasize, data_in_t *data_in_info)
2228 2232 {
2229 2233 if (Args & OCp) {
2230 2234 return (read(ifd, buffer, datasize));
2231 2235 } else {
2232 2236 FILL(datasize);
2233 2237 if (data_in_info->data_in_proc_mode != P_SKIP) {
2234 2238 if (Hdr_type == CRC)
2235 2239 data_in_info->data_in_cksumval += cksum(CRC,
2236 2240 datasize, NULL);
2237 2241 if (data_in_info->data_in_swapfile)
2238 2242 swap(Buffr.b_out_p, datasize);
2239 2243
2240 2244
2241 2245 /*
2242 2246 * if the bar archive is compressed, set up a pipe and
2243 2247 * do the de-compression while reading in the file
2244 2248 */
2245 2249 if (Hdr_type == BAR) {
2246 2250 if (data_in_info->data_in_compress_flag == 0 &&
2247 2251 Compressed) {
2248 2252 setup_uncompress(
2249 2253 &(data_in_info->data_in_pipef));
2250 2254 data_in_info->data_in_compress_flag++;
2251 2255 }
2252 2256 }
2253 2257 }
2254 2258 (void) memcpy(buffer, Buffr.b_out_p, datasize);
2255 2259 Buffr.b_out_p += datasize;
2256 2260 Buffr.b_cnt -= datasize;
2257 2261 return (datasize);
2258 2262 }
2259 2263 }
2260 2264
2261 2265 /*
2262 2266 * Read as much data as we can.
2263 2267 *
2264 2268 * ifd - input file descriptor.
2265 2269 * buf - Buffer (allocated by caller) to copy data to.
2266 2270 * bytes - The amount of data to read from the input file
2267 2271 * and copy to the buffer.
2268 2272 * rdblocksz - The size of the chunk of data to read.
2269 2273 *
2270 2274 * Return number of bytes failed to read.
2271 2275 * Return -1 when buffer is empty and read failed.
2272 2276 */
2273 2277 static int
2274 2278 read_bytes(int ifd, char *buf, size_t bytes, size_t rdblocksz,
2275 2279 data_in_t *data_in_info)
2276 2280 {
2277 2281 size_t bytesread;
2278 2282 ssize_t got;
2279 2283
2280 2284 for (bytesread = 0; bytesread < bytes; bytesread += got) {
2281 2285 /*
2282 2286 * Read the data from either the input file descriptor
2283 2287 * or the archive file. read_chunk() will only return
2284 2288 * <= 0 if data_copy() was called from data_pass().
2285 2289 */
2286 2290 if ((got = read_chunk(ifd, buf + bytesread,
2287 2291 min(bytes - bytesread, rdblocksz),
2288 2292 data_in_info)) <= 0) {
2289 2293 /*
2290 2294 * We come here only in the pass mode.
2291 2295 * If data couldn't be read from the input file
2292 2296 * descriptor, return number of bytes in the buf.
2293 2297 * If buffer is empty, return -1.
2294 2298 */
2295 2299 if (bytesread == 0) {
2296 2300 if (got == 0) /* EOF */
2297 2301 data_in_info->data_in_rd_eof = 1;
2298 2302 return (-1);
2299 2303 }
2300 2304 return (bytes - bytesread);
2301 2305 }
2302 2306 }
2303 2307 return (0);
2304 2308 }
2305 2309
2306 2310 /*
2307 2311 * Write as much data as we can.
2308 2312 *
2309 2313 * ofd - output file descriptor.
2310 2314 * buf - Source buffer to output data from.
2311 2315 * maxwrite - The amount of data to write to the output.
2312 2316 *
2313 2317 * return 0 upon success.
2314 2318 */
2315 2319 static int
2316 2320 write_bytes(int ofd, char *buf, size_t maxwrite, data_in_t *data_in_info)
2317 2321 {
2318 2322 ssize_t cnt;
2319 2323
2320 2324 errno = 0;
2321 2325 if ((cnt = write(ofd, buf, maxwrite)) < (ssize_t)maxwrite) {
2322 2326 data_in_info->data_in_errno = errno;
2323 2327 /*
2324 2328 * data_in() needs to know if it was an actual write(2)
2325 2329 * failure, or if we just couldn't write all of the data
2326 2330 * requested so that we know that the rest of the file's
2327 2331 * data can be read but not written.
2328 2332 */
2329 2333 if (cnt != -1)
2330 2334 data_in_info->data_in_wr_part = 1;
2331 2335 return (1);
2332 2336 } else if (Args & OCp) {
2333 2337 Blocks += (u_longlong_t)((cnt + (Bufsize - 1)) / Bufsize);
2334 2338 }
2335 2339 return (0);
2336 2340 }
2337 2341
2338 2342 /*
2339 2343 * Perform I/O for given byte size with using limited i/o block size
2340 2344 * and supplied buffer.
2341 2345 *
2342 2346 * ifd/ofd - i/o file descriptor
2343 2347 * buf - buffer to be used for i/o
2344 2348 * bytes - Amount to read/write
2345 2349 * wrblocksz - Output block size.
2346 2350 * rdblocksz - Read block size.
2347 2351 *
2348 2352 * Return 0 upon success. Return negative if read failed.
2349 2353 * Return positive non-zero if write failed.
2350 2354 */
2351 2355 static int
2352 2356 rdwr_bytes(int ifd, int ofd, char *buf, off_t bytes,
2353 2357 size_t wrblocksz, size_t rdblocksz, data_in_t *data_in_info)
2354 2358 {
2355 2359 int rv, sz;
2356 2360 int error = 0;
2357 2361 int write_it = (data_in_info->data_in_proc_mode != P_SKIP);
2358 2362
2359 2363 while (bytes > 0) {
2360 2364 /*
2361 2365 * If the number of bytes left to write is smaller than
2362 2366 * the preferred I/O size, then we're about to do our final
2363 2367 * write to the file, so just set wrblocksz to the number of
2364 2368 * bytes left to write.
2365 2369 */
2366 2370 if (bytes < wrblocksz)
2367 2371 wrblocksz = bytes;
2368 2372
2369 2373 /* Read input till satisfy output block size */
2370 2374 sz = read_bytes(ifd, buf, wrblocksz, rdblocksz, data_in_info);
2371 2375 if (sz < 0)
2372 2376 return (sz);
2373 2377
2374 2378 if (write_it) {
2375 2379 rv = write_bytes(ofd, buf,
2376 2380 wrblocksz - sz, data_in_info);
2377 2381 if (rv != 0) {
2378 2382 /*
2379 2383 * If we wrote partial, we return and quits.
2380 2384 * Otherwise, read through the rest of input
2381 2385 * to go to the next file.
2382 2386 */
2383 2387 if ((Args & OCp) ||
2384 2388 data_in_info->data_in_wr_part) {
2385 2389 return (rv);
2386 2390 } else {
2387 2391 write_it = 0;
2388 2392 }
2389 2393 error = 1;
2390 2394 }
2391 2395 }
2392 2396 bytes -= (wrblocksz - sz);
2393 2397 }
2394 2398 return (error);
2395 2399 }
2396 2400
2397 2401 /*
2398 2402 * Write zeros for give size.
2399 2403 *
2400 2404 * ofd - output file descriptor
2401 2405 * buf - buffer to fill with zeros
2402 2406 * bytes - Amount to write
2403 2407 * wrblocksz - Write block size
2404 2408 *
2405 2409 * return 0 upon success.
2406 2410 */
2407 2411 static int
2408 2412 write_zeros(int ofd, char *buf, off_t bytes, size_t wrblocksz,
2409 2413 data_in_t *data_in_info)
2410 2414 {
2411 2415 int rv;
2412 2416
2413 2417 (void) memset(buf, 0, min(bytes, wrblocksz));
2414 2418 while (bytes > 0) {
2415 2419 if (bytes < wrblocksz)
2416 2420 wrblocksz = bytes;
2417 2421 rv = write_bytes(ofd, buf, wrblocksz, data_in_info);
2418 2422 if (rv != 0)
2419 2423 return (rv);
2420 2424 bytes -= wrblocksz;
2421 2425 }
2422 2426 return (0);
2423 2427 }
2424 2428
2425 2429 /*
2426 2430 * To figure out the size of the buffer used to accumulate data from
2427 2431 * readtape() and to write to the file, we need to determine the largest
2428 2432 * chunk of data to be written to the file at one time. This is determined
2429 2433 * based on the following three things:
2430 2434 * 1) The size of the archived file.
2431 2435 * 2) The preferred I/O size of the file.
2432 2436 * 3) If the file is a read-write system attribute file.
2433 2437 * If the size of the file is less than the preferred I/O size or it's a
2434 2438 * read-write system attribute file, which must be written in one operation,
2435 2439 * then set the maximum write size to the size of the archived file.
2436 2440 * Otherwise, the maximum write size is preferred I/O size.
2437 2441 */
2438 2442 static int
2439 2443 calc_maxwrite(int ofd, int rw_sysattr, off_t bytes, size_t blocksize)
2440 2444 {
2441 2445 struct stat tsbuf;
2442 2446 size_t maxwrite;
2443 2447 size_t piosize; /* preferred I/O size */
2444 2448
2445 2449 if (rw_sysattr || bytes < blocksize) {
2446 2450 maxwrite = bytes;
2447 2451 } else {
2448 2452 if (fstat(ofd, &tsbuf) == 0) {
2449 2453 piosize = tsbuf.st_blksize;
2450 2454 } else {
2451 2455 piosize = blocksize;
2452 2456 }
2453 2457 maxwrite = min(bytes, piosize);
2454 2458 }
2455 2459 return (maxwrite);
2456 2460 }
2457 2461 /*
2458 2462 * data_copy() and data_copy_with_holes() copy data from the input
2459 2463 * file to output file descriptor. If ifd is -1, then the input file is
2460 2464 * the archive file.
2461 2465 *
2462 2466 * Parameters
2463 2467 * ifd - Input file descriptor to read from.
2464 2468 * ofd - Output file descriptor of extracted file.
2465 2469 * rw_sysattr - Flag indicating if a file is an extended
2466 2470 * system attribute file.
2467 2471 * bytes - Amount of data (file size) of copy/write.
2468 2472 * blocksize - Amount of data to read at a time from either
2469 2473 * the input file descriptor or from the archive.
2470 2474 * data_in_info - information needed while reading data when
2471 2475 * called by data_in().
2472 2476 * holes - Information of holes in the input file.
2473 2477 *
2474 2478 * Return code
2475 2479 * 0 Success
2476 2480 * < 0 An error occurred during the read of the input
2477 2481 * file
2478 2482 * > 0 An error occurred during the write of the output
2479 2483 * file descriptor.
2480 2484 */
2481 2485 static int
2482 2486 data_copy(int ifd, int ofd, int rw_sysattr, off_t bytes,
2483 2487 size_t blocksize, data_in_t *data_in_info)
2484 2488 {
2485 2489 char *buf;
2486 2490 size_t maxwrite;
2487 2491 int rv;
2488 2492
2489 2493 /* No data to copy. */
2490 2494 if (bytes == 0)
2491 2495 return (0);
2492 2496
2493 2497 maxwrite = calc_maxwrite(ofd, rw_sysattr, bytes, blocksize);
2494 2498 buf = e_zalloc(E_EXIT, maxwrite);
2495 2499
2496 2500 rv = rdwr_bytes(ifd, ofd, buf, bytes, maxwrite,
2497 2501 blocksize, data_in_info);
2498 2502
2499 2503 free(buf);
2500 2504 return (rv);
2501 2505 }
2502 2506
2503 2507 static int
2504 2508 data_copy_with_holes(int ifd, int ofd, int rw_sysattr, off_t bytes,
2505 2509 size_t blocksize, data_in_t *data_in_info, holes_info_t *holes)
2506 2510 {
2507 2511 holes_list_t *hl;
2508 2512 off_t curpos, noff, datasize;
2509 2513 char *buf;
2510 2514 size_t maxwrite;
2511 2515 int rv, error;
2512 2516
2513 2517 if (bytes == 0)
2514 2518 return (0);
2515 2519
2516 2520 maxwrite = calc_maxwrite(ofd, rw_sysattr, bytes, blocksize);
2517 2521 buf = e_zalloc(E_EXIT, maxwrite);
2518 2522
2519 2523 error = 0;
2520 2524 curpos = 0;
2521 2525 for (hl = holes->holes_list; hl != NULL; hl = hl->hl_next) {
2522 2526 if (curpos != hl->hl_data) {
2523 2527 /* adjust output position */
2524 2528 noff = lseek(ofd, hl->hl_data, SEEK_SET);
2525 2529 if (noff != hl->hl_data) {
2526 2530 /*
2527 2531 * Can't seek to the target, try to adjust
2528 2532 * position by filling with zeros.
2529 2533 */
2530 2534 datasize = hl->hl_data - curpos;
2531 2535 rv = write_zeros(ofd, buf, datasize,
2532 2536 maxwrite, data_in_info);
2533 2537 if (rv != 0)
2534 2538 goto errout;
2535 2539 }
2536 2540 /*
2537 2541 * Data is contiguous in the archive, but fragmented
2538 2542 * in the regular file, so we also adjust the input
2539 2543 * file position in pass mode.
2540 2544 */
2541 2545 if (Args & OCp) {
2542 2546 /* adjust input position */
2543 2547 (void) lseek(ifd, hl->hl_data, SEEK_SET);
2544 2548 }
2545 2549 curpos = hl->hl_data;
2546 2550 }
2547 2551 datasize = hl->hl_hole - hl->hl_data;
2548 2552 if (datasize == 0) {
2549 2553 /*
2550 2554 * There is a hole at the end of file. To create
2551 2555 * such hole, we append one byte, and truncate the
2552 2556 * last block. This is necessary because ftruncate(2)
2553 2557 * alone allocates one block on the end of file.
2554 2558 */
2555 2559 rv = write_zeros(ofd, buf, 1, maxwrite, data_in_info);
2556 2560 if (rv != 0)
2557 2561 goto errout;
2558 2562 (void) ftruncate(ofd, hl->hl_data);
2559 2563 break;
2560 2564 }
2561 2565 rv = rdwr_bytes(ifd, ofd, buf, datasize, maxwrite,
2562 2566 blocksize, data_in_info);
2563 2567 if (rv != 0) {
2564 2568 errout:
2565 2569 /*
2566 2570 * Return if we got a read error or in pass mode,
2567 2571 * or failed with partial write. Otherwise, we'll
2568 2572 * read through the input stream till next file.
2569 2573 */
2570 2574 if (rv < 0 || (Args & OCp) ||
2571 2575 data_in_info->data_in_wr_part) {
2572 2576 free(buf);
2573 2577 return (rv);
2574 2578 }
2575 2579 error = 1;
2576 2580 hl = hl->hl_next;
2577 2581 break;
2578 2582 }
2579 2583 curpos += datasize;
2580 2584 }
2581 2585
2582 2586 /*
2583 2587 * We should read through the input data to go to the next
2584 2588 * header when non-fatal error occured.
2585 2589 */
2586 2590 if (error && !(Args & OCp)) {
2587 2591 data_in_info->data_in_proc_mode = P_SKIP;
2588 2592 while (hl != NULL) {
2589 2593 datasize = hl->hl_hole - hl->hl_data;
2590 2594 rv = rdwr_bytes(ifd, ofd, buf, datasize, maxwrite,
2591 2595 blocksize, data_in_info);
2592 2596 if (rv != 0)
2593 2597 break;
2594 2598 hl = hl->hl_next;
2595 2599 }
2596 2600 }
2597 2601
2598 2602 free(buf);
2599 2603 return (error);
2600 2604 }
2601 2605
2602 2606 /*
2603 2607 * Strip off the sparse file information that is prepended to
2604 2608 * the compressed sparse file. The information is in the following
2605 2609 * format:
2606 2610 * <prepended info size><SP><orig file size><SP><holes info>
2607 2611 * where prepended info size is long right justified in 10 bytes.
2608 2612 * Holesdata consists of the series of offset pairs:
2609 2613 * <data offset><SP><hole offset><SP><data offset><SP><hole offset>...
2610 2614 * prepended info size and original file size have been read in gethdr().
2611 2615 * We read the rest of holes information here in this function.
2612 2616 */
2613 2617 static int
2614 2618 read_holesdata(holes_info_t *holes, off_t *fileszp,
2615 2619 char *nam_p, data_in_t *data_in_info)
2616 2620 {
2617 2621 char *holesdata;
2618 2622 size_t holesdata_sz;
2619 2623
2620 2624 /* We've already read the header. */
2621 2625 holesdata_sz = holes->holesdata_sz - MIN_HOLES_HDRSIZE;
2622 2626
2623 2627 if ((holesdata = e_zalloc(E_NORMAL, holesdata_sz)) == NULL) {
2624 2628 msg(ERRN, "Could not allocate memory for "
2625 2629 "sparse file information", nam_p);
2626 2630 return (1);
2627 2631 }
2628 2632 /*
2629 2633 * This function is called only in OCi mode. Therefore,
2630 2634 * read_bytes() won't fail, and won't return if error occurs in
2631 2635 * input stream. See rstbuf().
2632 2636 */
2633 2637 (void) read_bytes(-1, holesdata, holesdata_sz, CPIOBSZ, data_in_info);
2634 2638 *fileszp -= holesdata_sz;
2635 2639
2636 2640 /* The string should be terminated. */
2637 2641 if (holesdata[holesdata_sz - 1] != '\0') {
2638 2642 invalid:
2639 2643 free(holesdata);
2640 2644 msg(ERR, "invalid sparse file information", nam_p);
2641 2645 return (1);
2642 2646 }
2643 2647 if (parse_holesdata(holes, holesdata) != 0)
2644 2648 goto invalid;
2645 2649
2646 2650 /* sanity check */
2647 2651 if (*fileszp != holes->data_size)
2648 2652 goto invalid;
2649 2653
2650 2654 free(holesdata);
2651 2655 return (0);
2652 2656 }
2653 2657
2654 2658 /*
2655 2659 * data_in: If proc_mode == P_PROC, bread() the file's data from the archive
2656 2660 * and write(2) it to the open fdes gotten from openout(). If proc_mode ==
2657 2661 * P_SKIP, or becomes P_SKIP (due to errors etc), bread(2) the file's data
2658 2662 * and ignore it. If the user specified any of the "swap" options (b, s or S),
2659 2663 * and the length of the file is not appropriate for that action, do not
2660 2664 * perform the "swap", otherwise perform the action on a buffer by buffer basis.
2661 2665 * If the CRC header was selected, calculate a running checksum as each buffer
2662 2666 * is processed.
2663 2667 */
2664 2668 static void
2665 2669 data_in(int proc_mode)
2666 2670 {
2667 2671 char *nam_p;
2668 2672 int pad, rv;
2669 2673 int error = 0;
2670 2674 int swapfile = 0;
2671 2675 int cstatus = 0;
2672 2676 off_t filesz;
2673 2677 data_in_t *data_in_info;
2674 2678
2675 2679 if (G_p->g_attrnam_p != NULL) {
2676 2680 nam_p = G_p->g_attrnam_p;
2677 2681 } else {
2678 2682 nam_p = G_p->g_nam_p;
2679 2683 }
2680 2684
2681 2685 if (((G_p->g_mode & Ftype) == S_IFLNK && proc_mode != P_SKIP) ||
2682 2686 (Hdr_type == BAR && bar_linkflag == '2' && proc_mode != P_SKIP)) {
2683 2687 proc_mode = P_SKIP;
2684 2688 VERBOSE((Args & (OCv | OCV)), nam_p);
2685 2689 }
2686 2690 if (Args & (OCb | OCs | OCS)) { /* verfify that swapping is possible */
2687 2691 swapfile = 1;
2688 2692 if (Args & (OCs | OCb) && G_p->g_filesz % 2) {
2689 2693 msg(ERR,
2690 2694 "Cannot swap bytes of \"%s\", odd number of bytes",
2691 2695 nam_p);
2692 2696 swapfile = 0;
2693 2697 }
2694 2698 if (Args & (OCS | OCb) && G_p->g_filesz % 4) {
2695 2699 msg(ERR,
2696 2700 "Cannot swap halfwords of \"%s\", odd number "
2697 2701 "of halfwords", nam_p);
2698 2702 swapfile = 0;
2699 2703 }
2700 2704 }
2701 2705
2702 2706 data_in_info = e_zalloc(E_EXIT, sizeof (data_in_t));
2703 2707 data_in_info->data_in_swapfile = swapfile;
2704 2708 data_in_info->data_in_proc_mode = proc_mode;
2705 2709
2706 2710 filesz = G_p->g_filesz;
2707 2711
2708 2712 if (S_ISSPARSE(G_p->g_mode) && G_p->g_holes != NULL) {
2709 2713 /* We've already read the header in gethdr() */
2710 2714 filesz -= MIN_HOLES_HDRSIZE;
2711 2715
2712 2716 /*
2713 2717 * Strip rest of the sparse file information. This includes
2714 2718 * the data/hole offset pairs which will be used to restore
2715 2719 * the holes in the file.
2716 2720 */
2717 2721 if (proc_mode == P_SKIP) {
2718 2722 /* holes info isn't necessary to skip file */
2719 2723 free_holes_info(G_p->g_holes);
2720 2724 G_p->g_holes = NULL;
2721 2725 } else {
2722 2726 rv = read_holesdata(G_p->g_holes, &filesz,
2723 2727 nam_p, data_in_info);
2724 2728 if (rv != 0) {
2725 2729 /*
2726 2730 * We got an error. Skip this file. holes info
2727 2731 * is no longer necessary.
2728 2732 */
2729 2733 free_holes_info(G_p->g_holes);
2730 2734 G_p->g_holes = NULL;
2731 2735
2732 2736 data_in_info->data_in_proc_mode = P_SKIP;
2733 2737 error = 1;
2734 2738 }
2735 2739 }
2736 2740 }
2737 2741
2738 2742 if (G_p->g_holes != NULL) {
2739 2743 rv = data_copy_with_holes(-1, Ofile,
2740 2744 (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
2741 2745 G_p->g_holes->orig_size,
2742 2746 CPIOBSZ, data_in_info, G_p->g_holes);
2743 2747
2744 2748 free_holes_info(G_p->g_holes);
2745 2749 G_p->g_holes = NULL;
2746 2750 } else {
2747 2751 rv = data_copy(-1, Ofile,
2748 2752 (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
2749 2753 filesz, CPIOBSZ, data_in_info);
2750 2754 }
2751 2755
2752 2756 /* This writes out the file from the archive */
2753 2757 if (rv != 0 || error) {
2754 2758 errno = data_in_info->data_in_errno;
2755 2759
2756 2760 if (!error) {
2757 2761 msg(data_in_info->data_in_wr_part ? EXTN : ERRN,
2758 2762 "Cannot write \"%s%s%s\"",
2759 2763 (G_p->g_attrnam_p == NULL) ? "" :
2760 2764 G_p->g_attrfnam_p,
2761 2765 (G_p->g_attrnam_p == NULL) ? "" :
2762 2766 G_p->g_rw_sysattr ?
2763 2767 gettext(" System Attribute ") :
2764 2768 gettext(" Attribute "), nam_p);
2765 2769 }
2766 2770 /*
2767 2771 * We've failed to write to the file, and input data
2768 2772 * has been skiped to the next file. We'll need to restore
2769 2773 * the original file, and skip the rest of work.
2770 2774 */
2771 2775 proc_mode = P_SKIP;
2772 2776 rstfiles(U_KEEP, G_p->g_dirfd);
2773 2777 cstatus = close(Ofile);
2774 2778 Ofile = 0;
2775 2779 if (cstatus != 0) {
2776 2780 msg(EXTN, "close error");
2777 2781 }
2778 2782 }
2779 2783
2780 2784 /* we must use g_filesz for the amount of padding */
2781 2785 pad = (Pad_val + 1 - (G_p->g_filesz & Pad_val)) & Pad_val;
2782 2786 if (pad != 0) {
2783 2787 FILL(pad);
2784 2788 Buffr.b_out_p += pad;
2785 2789 Buffr.b_cnt -= pad;
2786 2790 }
2787 2791 if (proc_mode != P_SKIP) {
2788 2792 if (Hdr_type == CRC &&
2789 2793 Gen.g_cksum != data_in_info->data_in_cksumval) {
2790 2794 msg(ERR, "\"%s\" - checksum error", nam_p);
2791 2795 rstfiles(U_KEEP, G_p->g_dirfd);
2792 2796 } else
2793 2797 rstfiles(U_OVER, G_p->g_dirfd);
2794 2798 if (Hdr_type == BAR && data_in_info->data_in_compress_flag) {
2795 2799 (void) pclose(data_in_info->data_in_pipef);
2796 2800 } else {
2797 2801 cstatus = close(Ofile);
2798 2802 }
2799 2803 Ofile = 0;
2800 2804 if (cstatus != 0) {
2801 2805 msg(EXTN, "close error");
2802 2806 }
2803 2807 }
2804 2808 (void) free(data_in_info);
2805 2809
2806 2810 VERBOSE((proc_mode != P_SKIP && (Args & (OCv | OCV))),
2807 2811 (G_p->g_attrparent_p == NULL) ? G_p->g_nam_p : G_p->g_attrpath_p);
2808 2812 Finished = 1;
2809 2813 }
2810 2814
2811 2815 /*
2812 2816 * Read regular file. Return number of bytes which weren't read.
2813 2817 * Upon return, real_filesz will be real file size of input file.
2814 2818 * When read_exact is specified, read size is adjusted to the given
2815 2819 * file size.
2816 2820 */
2817 2821 static off_t
2818 2822 read_file(char *nam_p, off_t file_size, off_t *real_filesz,
2819 2823 boolean_t read_exact)
2820 2824 {
2821 2825 int amount_read;
2822 2826 off_t amt_to_read;
2823 2827 off_t readsz;
2824 2828
2825 2829 if (file_size == 0)
2826 2830 return (0);
2827 2831
2828 2832 amt_to_read = file_size;
2829 2833 do {
2830 2834 if (read_exact && amt_to_read < CPIOBSZ)
2831 2835 readsz = amt_to_read;
2832 2836 else
2833 2837 readsz = CPIOBSZ;
2834 2838
2835 2839 FLUSH(readsz);
2836 2840 errno = 0;
2837 2841
2838 2842 if ((amount_read = read(Ifile, Buffr.b_in_p, readsz)) < 0) {
2839 2843 msg(EXTN, "Cannot read \"%s%s%s\"",
2840 2844 (Gen.g_attrnam_p == NULL) ?
2841 2845 nam_p : Gen.g_attrfnam_p,
2842 2846 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
2843 2847 gettext(" System Attribute ") :
2844 2848 gettext(" Attribute "),
2845 2849 (Gen.g_attrnam_p == NULL) ? "" : nam_p);
2846 2850 break;
2847 2851 }
2848 2852
2849 2853 if (amount_read == 0) {
2850 2854 /* got EOF. the file has shrunk */
2851 2855 *real_filesz = file_size - amt_to_read;
2852 2856 break;
2853 2857 } else if (amount_read > amt_to_read) {
2854 2858 /* the file has grown */
2855 2859 *real_filesz = file_size +
2856 2860 (amount_read - amt_to_read);
2857 2861 amount_read = amt_to_read;
2858 2862 } else if (amount_read == amt_to_read) {
2859 2863 /* the file is the same size */
2860 2864 *real_filesz = file_size;
2861 2865 }
2862 2866
2863 2867 Buffr.b_in_p += amount_read;
2864 2868 Buffr.b_cnt += (long)amount_read;
2865 2869
2866 2870 amt_to_read -= (off_t)amount_read;
2867 2871 if (!read_exact &&
2868 2872 amt_to_read == 0 && amount_read == CPIOBSZ) {
2869 2873 /*
2870 2874 * If the file size is multiple of CPIOBSZ, we may
2871 2875 * be able to read more from the file even though
2872 2876 * amt_to_read already gets 0.
2873 2877 */
2874 2878 FLUSH(CPIOBSZ);
2875 2879 amount_read = read(Ifile, Buffr.b_in_p, CPIOBSZ);
2876 2880 if (amount_read != 0) {
2877 2881 /* the file has grown */
2878 2882 *real_filesz = file_size + amount_read;
2879 2883 }
2880 2884 }
2881 2885 } while (amt_to_read != 0);
2882 2886
2883 2887 return (amt_to_read);
2884 2888 }
2885 2889
2886 2890 /*
2887 2891 * Read through the data in files skipping holes.
2888 2892 */
2889 2893 static off_t
2890 2894 read_compress_holes(char *nam_p, off_t file_size, off_t *real_filesz,
2891 2895 holes_info_t *holes, int *hole_changed)
2892 2896 {
2893 2897 off_t left;
2894 2898 off_t datasize, realsz;
2895 2899 off_t curpos, npos;
2896 2900 holes_list_t *hl = holes->holes_list;
2897 2901
2898 2902 curpos = 0;
2899 2903 for (hl = holes->holes_list; hl != NULL; hl = hl->hl_next) {
2900 2904 datasize = hl->hl_hole - hl->hl_data;
2901 2905
2902 2906 npos = lseek(Ifile, curpos, SEEK_DATA);
2903 2907 if (npos == -1 && errno == ENXIO) {
2904 2908 /*
2905 2909 * No more data. There are two cases.
2906 2910 * - we have a hole toward the end of file.
2907 2911 * - file has been shrunk, and we've reached EOF.
2908 2912 */
2909 2913 *real_filesz = lseek(Ifile, 0, SEEK_END);
2910 2914 if (hl->hl_data == file_size)
2911 2915 return (0);
2912 2916 /*
2913 2917 * File has been shrunk. Check the amount of data
2914 2918 * left.
2915 2919 */
2916 2920 left = 0;
2917 2921 while (hl != NULL) {
2918 2922 left += (hl->hl_hole - hl->hl_data);
2919 2923 hl = hl->hl_next;
2920 2924 }
2921 2925 return (left);
2922 2926 }
2923 2927
2924 2928 /* found data */
2925 2929 curpos = npos;
2926 2930 if (curpos != hl->hl_data) {
2927 2931 /*
2928 2932 * File has been changed. We shouldn't read data
2929 2933 * from different offset since we've already put
2930 2934 * the holes data.
2931 2935 */
2932 2936 *hole_changed = 1;
2933 2937 (void) lseek(Ifile, hl->hl_data, SEEK_SET);
2934 2938 curpos = hl->hl_data;
2935 2939 }
2936 2940 left = read_file(nam_p, datasize, &realsz, B_TRUE);
2937 2941 if (left != 0) {
2938 2942 /* file has been shrunk */
2939 2943 *real_filesz = curpos + datasize - left;
2940 2944 left = file_size - *real_filesz;
2941 2945 return (left);
2942 2946 }
2943 2947 curpos += datasize;
2944 2948 }
2945 2949 /*
2946 2950 * We've read exact size of holes. We need to make sure
2947 2951 * that file hasn't grown by reading from the EOF.
2948 2952 */
2949 2953 realsz = 0;
2950 2954 (void) read_file(nam_p, CPIOBSZ, &realsz, B_FALSE);
2951 2955
2952 2956 *real_filesz = curpos + realsz;
2953 2957 return (0);
2954 2958 }
2955 2959
2956 2960 /*
2957 2961 * data_out: open(2) the file to be archived, compute the checksum
2958 2962 * of it's data if the CRC header was specified and write the header.
2959 2963 * read(2) each block of data and bwrite() it to the archive. For TARTYP (TAR
2960 2964 * and USTAR) archives, pad the data with NULLs to the next 512 byte boundary.
2961 2965 */
2962 2966 static void
2963 2967 data_out(void)
2964 2968 {
2965 2969 char *nam_p;
2966 2970 int cnt, pad;
2967 2971 off_t amt_to_read;
2968 2972 off_t real_filesz;
2969 2973 int errret = 0;
2970 2974 int hole_changed = 0;
2971 2975 off_t orig_filesz;
2972 2976 holes_info_t *holes = NULL;
2973 2977
2974 2978 nam_p = G_p->g_nam_p;
2975 2979 if (Aspec) {
2976 2980 if (Pflag && aclp != NULL) {
2977 2981 char *secinfo = NULL;
2978 2982 int len = 0;
2979 2983
2980 2984 /* append security attributes */
2981 2985 if (append_secattr(&secinfo, &len, aclp) == -1) {
2982 2986 msg(ERR,
2983 2987 "can create security information");
2984 2988 }
2985 2989 /* call append_secattr() if more than one */
2986 2990
2987 2991 if (len > 0) {
2988 2992 /* write ancillary only if there is sec info */
2989 2993 write_hdr(ARCHIVE_ACL, (off_t)len);
2990 2994 write_ancillary(secinfo, len, B_TRUE);
2991 2995 }
2992 2996 }
2993 2997 write_hdr(ARCHIVE_NORMAL, (off_t)0);
2994 2998 rstfiles(U_KEEP, G_p->g_dirfd);
2995 2999 VERBOSE((Args & (OCv | OCV)), nam_p);
2996 3000 return;
2997 3001 }
2998 3002 if ((G_p->g_mode & Ftype) == S_IFLNK && (Hdr_type !=
2999 3003 USTAR && Hdr_type != TAR)) { /* symbolic link */
3000 3004 int size;
3001 3005 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3002 3006
3003 3007 FLUSH(G_p->g_filesz);
3004 3008 errno = 0;
3005 3009
3006 3010 /* Note that "size" and G_p->g_filesz are the same number */
3007 3011
3008 3012 if ((size = readlink(nam_p, Buffr.b_in_p, G_p->g_filesz)) <
3009 3013 0) {
3010 3014 msg(ERRN, "Cannot read symbolic link \"%s\"", nam_p);
3011 3015 return;
3012 3016 }
3013 3017
3014 3018 /*
3015 3019 * Note that it is OK not to add the NUL after the name read by
3016 3020 * readlink, because it is not being used subsequently.
3017 3021 */
3018 3022
3019 3023 Buffr.b_in_p += size;
3020 3024 Buffr.b_cnt += size;
3021 3025 pad = (Pad_val + 1 - (size & Pad_val)) & Pad_val;
3022 3026 if (pad != 0) {
3023 3027 FLUSH(pad);
3024 3028 (void) memset(Buffr.b_in_p, 0, pad);
3025 3029 Buffr.b_in_p += pad;
3026 3030 Buffr.b_cnt += pad;
3027 3031 }
3028 3032 VERBOSE((Args & (OCv | OCV)), nam_p);
3029 3033 return;
3030 3034 } else if ((G_p->g_mode & Ftype) == S_IFLNK &&
3031 3035 (Hdr_type == USTAR || Hdr_type == TAR)) {
3032 3036 int size;
3033 3037
3034 3038 /*
3035 3039 * G_p->g_filesz is the length of the right-hand side of
3036 3040 * the symlink "x -> y".
3037 3041 * The tar link field is only NAMSIZ long.
3038 3042 */
3039 3043
3040 3044 if (G_p->g_filesz > NAMSIZ) {
3041 3045 msg(ERRN,
3042 3046 "Symbolic link too long \"%s\"", nam_p);
3043 3047 return;
3044 3048 }
3045 3049 if ((size = readlink(nam_p, T_lname, G_p->g_filesz)) < 0) {
3046 3050 msg(ERRN,
3047 3051 "Cannot read symbolic link \"%s\"", nam_p);
3048 3052 return;
3049 3053 }
3050 3054 T_lname[size] = '\0';
3051 3055 G_p->g_filesz = (off_t)0;
3052 3056 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3053 3057 VERBOSE((Args & (OCv | OCV)), nam_p);
3054 3058 return;
3055 3059 }
3056 3060 if ((Ifile = openfile(O_RDONLY)) < 0) {
3057 3061 msg(ERR, "\"%s%s%s\" ?",
3058 3062 (Gen.g_attrnam_p == NULL) ? nam_p : Gen.g_attrfnam_p,
3059 3063 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3060 3064 gettext(" System Attribute ") : gettext(" Attribute "),
3061 3065 (Gen.g_attrnam_p == NULL) ? "" :
3062 3066 (Gen.g_attrparent_p == NULL) ? Gen.g_attrnam_p :
3063 3067 Gen.g_attrparent_p);
3064 3068 return;
3065 3069 }
3066 3070
3067 3071 /* save original file size */
3068 3072 orig_filesz = G_p->g_filesz;
3069 3073
3070 3074 /*
3071 3075 * Calculate the new compressed file size of a sparse file
3072 3076 * before any of the header information is written
3073 3077 * to the archive.
3074 3078 */
3075 3079 if (Compress_sparse && S_ISREG(G_p->g_mode)) {
3076 3080 /*
3077 3081 * If the file being processed is a sparse file, gather the
3078 3082 * hole information and the compressed file size.
3079 3083 * G_p->g_filesz will need to be changed to be the size of
3080 3084 * the compressed sparse file plus the the size of the hole
3081 3085 * information that will be prepended to the compressed file
3082 3086 * in the archive.
3083 3087 */
3084 3088 holes = get_holes_info(Ifile, G_p->g_filesz, B_FALSE);
3085 3089 if (holes != NULL)
3086 3090 G_p->g_filesz = holes->holesdata_sz + holes->data_size;
3087 3091
3088 3092 if (G_p->g_filesz > Max_offset) {
3089 3093 msg(ERR, "%s%s%s: too large to archive "
3090 3094 "in current mode",
3091 3095 G_p->g_nam_p,
3092 3096 (G_p->g_attrnam_p == NULL) ? "" :
3093 3097 G_p->g_rw_sysattr ?
3094 3098 gettext(" System Attribute ") :
3095 3099 gettext(" Attribute "),
3096 3100 (G_p->g_attrnam_p == NULL) ? "" :
3097 3101 ((G_p->g_attrparent_p == NULL) ?
3098 3102 G_p->g_attrnam_p:
3099 3103 G_p->g_attrpath_p));
3100 3104
3101 3105 (void) close(Ifile);
3102 3106 if (holes != NULL)
3103 3107 free_holes_info(holes);
3104 3108 return; /* do not archive if it's too big */
3105 3109 }
3106 3110 }
3107 3111
3108 3112 /*
3109 3113 * Dump extended attribute header.
3110 3114 */
3111 3115
3112 3116 if (Gen.g_attrnam_p != NULL) {
3113 3117 write_xattr_hdr();
3114 3118 }
3115 3119
3116 3120 if (Hdr_type == CRC) {
3117 3121 long csum = cksum(CRC, 0, &errret);
3118 3122 if (errret != 0) {
3119 3123 G_p->g_cksum = (ulong_t)-1;
3120 3124 msg(POST, "\"%s%s%s\" skipped",
3121 3125 (Gen.g_attrnam_p == NULL) ?
3122 3126 nam_p : Gen.g_attrfnam_p,
3123 3127 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3124 3128 gettext(" System Attribute ") :
3125 3129 gettext(" Attribute "),
3126 3130 (Gen.g_attrnam_p == NULL) ? "" : nam_p);
3127 3131 if (holes != NULL)
3128 3132 free_holes_info(holes);
3129 3133 (void) close(Ifile);
3130 3134 return;
3131 3135 }
3132 3136 G_p->g_cksum = csum;
3133 3137 } else {
3134 3138 G_p->g_cksum = 0;
3135 3139 }
3136 3140
3137 3141 /*
3138 3142 * ACL has been retrieved in getname().
3139 3143 */
3140 3144 if (Pflag) {
3141 3145 char *secinfo = NULL;
3142 3146 int len = 0;
3143 3147
3144 3148 /* append security attributes */
3145 3149 if ((append_secattr(&secinfo, &len, aclp)) == -1)
3146 3150 msg(ERR, "can create security information");
3147 3151
3148 3152 /* call append_secattr() if more than one */
3149 3153
3150 3154 if (len > 0) {
3151 3155 /* write ancillary only if there is sec info */
3152 3156 write_hdr(ARCHIVE_ACL, (off_t)len);
3153 3157 write_ancillary(secinfo, len, B_TRUE);
3154 3158 }
3155 3159 }
3156 3160
3157 3161 if (holes != NULL) {
3158 3162 /*
3159 3163 * Write the header info with a modified c_mode field to
3160 3164 * indicate a compressed sparse file is being archived,
3161 3165 * as well as the new file size, including the size of the
3162 3166 * compressed file as well as all the prepended data.
3163 3167 */
3164 3168 write_hdr(ARCHIVE_SPARSE, (off_t)0);
3165 3169 /* Prepend sparse file info */
3166 3170 write_ancillary(holes->holesdata,
3167 3171 holes->holesdata_sz, B_FALSE);
3168 3172 } else {
3169 3173 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3170 3174 }
3171 3175
3172 3176 real_filesz = 0;
3173 3177
3174 3178 if (holes != NULL) {
3175 3179 amt_to_read = read_compress_holes(nam_p, G_p->g_filesz,
3176 3180 &real_filesz, holes, &hole_changed);
3177 3181 } else {
3178 3182 amt_to_read = read_file(nam_p, G_p->g_filesz,
3179 3183 &real_filesz, B_FALSE);
3180 3184 }
3181 3185
3182 3186 while (amt_to_read > 0) {
3183 3187 cnt = (amt_to_read > CPIOBSZ) ? CPIOBSZ : (int)amt_to_read;
3184 3188 FLUSH(cnt);
3185 3189 (void) memset(Buffr.b_in_p, 0, cnt);
3186 3190 Buffr.b_in_p += cnt;
3187 3191 Buffr.b_cnt += cnt;
3188 3192 amt_to_read -= cnt;
3189 3193 }
3190 3194
3191 3195 pad = (Pad_val + 1 - (G_p->g_filesz & Pad_val)) & Pad_val;
3192 3196 if (pad != 0) {
3193 3197 FLUSH(pad);
3194 3198 (void) memset(Buffr.b_in_p, 0, pad);
3195 3199 Buffr.b_in_p += pad;
3196 3200 Buffr.b_cnt += pad;
3197 3201 }
3198 3202
3199 3203 if (hole_changed == 1) {
3200 3204 msg(ERR,
3201 3205 "File data and hole offsets of \"%s%s%s\" have changed",
3202 3206 (Gen.g_attrnam_p == NULL) ?
3203 3207 G_p->g_nam_p : Gen.g_attrfnam_p,
3204 3208 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3205 3209 gettext(" System Attribute ") : gettext(" Attribute "),
3206 3210 (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p);
3207 3211 }
3208 3212 if (real_filesz > orig_filesz) {
3209 3213 msg(ERR, "File size of \"%s%s%s\" has increased by %lld",
3210 3214 (Gen.g_attrnam_p == NULL) ?
3211 3215 G_p->g_nam_p : Gen.g_attrfnam_p,
3212 3216 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3213 3217 gettext(" System Attribute ") : gettext(" Attribute "),
3214 3218 (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p,
3215 3219 (real_filesz - orig_filesz));
3216 3220 }
3217 3221 if (real_filesz < orig_filesz) {
3218 3222 msg(ERR, "File size of \"%s%s%s\" has decreased by %lld",
3219 3223 (Gen.g_attrnam_p == NULL) ?
3220 3224 G_p->g_nam_p : Gen.g_attrfnam_p,
3221 3225 (Gen.g_attrnam_p == NULL) ? "" : Gen.g_rw_sysattr ?
3222 3226 gettext(" System Attribute ") : gettext(" Attribute "),
3223 3227 (Gen.g_attrnam_p == NULL) ? "" : G_p->g_nam_p,
3224 3228 (orig_filesz - real_filesz));
3225 3229 }
3226 3230
3227 3231 if (holes != NULL)
3228 3232 free_holes_info(holes);
3229 3233
3230 3234 (void) close(Ifile);
3231 3235 rstfiles(U_KEEP, G_p->g_dirfd);
3232 3236 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3233 3237 }
3234 3238
3235 3239 /*
3236 3240 * data_pass: If not a special file (Aspec), open(2) the file to be
3237 3241 * transferred, read(2) each block of data and write(2) it to the output file
3238 3242 * Ofile, which was opened in file_pass().
3239 3243 */
3240 3244 static void
3241 3245 data_pass(void)
3242 3246 {
3243 3247 int rv;
3244 3248 int cstatus;
3245 3249 char *namep = Nam_p;
3246 3250 holes_info_t *holes = NULL;
3247 3251 data_in_t *data_in_info;
3248 3252
3249 3253 if (G_p->g_attrnam_p != NULL) {
3250 3254 namep = G_p->g_attrnam_p;
3251 3255 }
3252 3256 if (Aspec) {
3253 3257 rstfiles(U_KEEP, G_p->g_passdirfd);
3254 3258 cstatus = close(Ofile);
3255 3259 Ofile = 0;
3256 3260 VERBOSE((Args & (OCv | OCV)), Nam_p);
3257 3261 if (cstatus != 0) {
3258 3262 msg(EXTN, "close error");
3259 3263 }
3260 3264 return;
3261 3265 }
3262 3266 if ((Ifile = openat(G_p->g_dirfd, get_component(namep), 0)) < 0) {
3263 3267 msg(ERRN, "Cannot open \"%s%s%s\", skipped",
3264 3268 (G_p->g_attrnam_p == NULL) ? Nam_p : G_p->g_attrfnam_p,
3265 3269 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
3266 3270 gettext(" System Attribute ") : gettext(" Attribute "),
3267 3271 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3268 3272 rstfiles(U_KEEP, G_p->g_passdirfd);
3269 3273 cstatus = close(Ofile);
3270 3274 Ofile = 0;
3271 3275 if (cstatus != 0) {
3272 3276 msg(EXTN, "close error");
3273 3277 }
3274 3278 return;
3275 3279 }
3276 3280
3277 3281 data_in_info = e_zalloc(E_EXIT, sizeof (data_in_t));
3278 3282 data_in_info->data_in_proc_mode = P_PROC;
3279 3283
3280 3284 if (S_ISREG(G_p->g_mode))
3281 3285 holes = get_holes_info(Ifile, G_p->g_filesz, B_TRUE);
3282 3286
3283 3287 if (holes != NULL) {
3284 3288 rv = data_copy_with_holes(Ifile, Ofile,
3285 3289 (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
3286 3290 G_p->g_filesz, Bufsize, data_in_info, holes);
3287 3291
3288 3292 free_holes_info(holes);
3289 3293 } else {
3290 3294 rv = data_copy(Ifile, Ofile,
3291 3295 (G_p->g_attrnam_p == NULL) ? 0 : G_p->g_rw_sysattr,
3292 3296 G_p->g_filesz, Bufsize, data_in_info);
3293 3297 }
3294 3298
3295 3299 if (rv < 0) {
3296 3300 /* read error or unexpected EOF */
3297 3301 if (data_in_info->data_in_rd_eof) {
3298 3302 /*
3299 3303 * read has reached EOF unexpectedly, but this isn't
3300 3304 * an error since it's the latest shape of the file.
3301 3305 */
3302 3306 msg(EPOST, "File size of \"%s%s%s\" has decreased",
3303 3307 (G_p->g_attrnam_p == NULL) ?
3304 3308 Nam_p : G_p->g_attrfnam_p,
3305 3309 (G_p->g_attrnam_p == NULL) ? "" :
3306 3310 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3307 3311 gettext(" Attribute "),
3308 3312 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3309 3313
3310 3314 /* It's not error. We'll use the new file */
3311 3315 rv = 0;
3312 3316 } else {
3313 3317 /* read error */
3314 3318 msg(ERRN, "Cannot read \"%s%s%s\"",
3315 3319 (G_p->g_attrnam_p == NULL) ?
3316 3320 Nam_p : G_p->g_attrfnam_p,
3317 3321 (G_p->g_attrnam_p == NULL) ? "" :
3318 3322 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3319 3323 gettext(" Attribute "),
3320 3324 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3321 3325 }
3322 3326 } else if (rv > 0) {
3323 3327 /* write error */
3324 3328 if (Do_rename) {
3325 3329 msg(ERRN, "Cannot write \"%s%s%s\"", Over_p,
3326 3330 (G_p->g_attrnam_p == NULL) ? "" :
3327 3331 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3328 3332 gettext(" Attribute "),
3329 3333 (G_p->g_attrnam_p == NULL) ? "" : Over_p);
3330 3334 } else {
3331 3335 msg(ERRN, "Cannot write \"%s%s%s\"",
3332 3336 Fullnam_p,
3333 3337 (G_p->g_attrnam_p == NULL) ? "" :
3334 3338 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
3335 3339 gettext(" Attribute "),
3336 3340 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p);
3337 3341 }
3338 3342 }
3339 3343
3340 3344 free(data_in_info);
3341 3345
3342 3346 if (rv == 0) {
3343 3347 rstfiles(U_OVER, G_p->g_passdirfd);
3344 3348 } else {
3345 3349 rstfiles(U_KEEP, G_p->g_passdirfd);
3346 3350 }
3347 3351
3348 3352 (void) close(Ifile);
3349 3353 cstatus = close(Ofile);
3350 3354 Ofile = 0;
3351 3355 if (cstatus != 0) {
3352 3356 msg(EXTN, "close error");
3353 3357 }
3354 3358 VERBOSE((Args & (OCv | OCV)), Fullnam_p);
3355 3359 Finished = 1;
3356 3360 }
3357 3361
3358 3362 /*
3359 3363 * file_in: Process an object from the archive. If a TARTYP (TAR or USTAR)
3360 3364 * archive and g_nlink == 1, link this file to the file name in t_linkname
3361 3365 * and return. Handle linked files in one of two ways. If Onecopy == 0, this
3362 3366 * is an old style (binary or -c) archive, create and extract the data for the
3363 3367 * first link found, link all subsequent links to this file and skip their data.
3364 3368 * If Oncecopy == 1, save links until all have been processed, and then
3365 3369 * process the links first to last checking their names against the patterns
3366 3370 * and/or asking the user to rename them. The first link that is accepted
3367 3371 * for xtraction is created and the data is read from the archive.
3368 3372 * All subsequent links that are accepted are linked to this file.
3369 3373 */
3370 3374 static void
3371 3375 file_in(void)
3372 3376 {
3373 3377 struct Lnk *l_p, *tl_p;
3374 3378 int lnkem = 0, cleanup = 0;
3375 3379 int proc_file;
3376 3380 struct Lnk *ttl_p;
3377 3381 int typeflag;
3378 3382 char savacl;
3379 3383 int cwd;
3380 3384
3381 3385 G_p = &Gen;
3382 3386
3383 3387 /*
3384 3388 * Now that we've read the extended header,
3385 3389 * determine if we should restore attributes.
3386 3390 * Don't restore the attribute if we are extracting
3387 3391 * a file from an archive (as opposed to doing a table of
3388 3392 * contents) and any of the following are true:
3389 3393 * 1. neither -@ or -/ was specified.
3390 3394 * 2. -@ was specified, -/ wasn't specified, and we're
3391 3395 * processing a hidden attribute directory of an attribute
3392 3396 * or we're processing a read-write system attribute file.
3393 3397 * 3. -@ wasn't specified, -/ was specified, and the file
3394 3398 * we're processing it not a read-write system attribute file,
3395 3399 * or we're processing the hidden attribute directory of an
3396 3400 * attribute.
3397 3401 *
3398 3402 * We always process the attributes if we're just generating
3399 3403 * generating a table of contents, or if both -@ and -/ were
3400 3404 * specified.
3401 3405 */
3402 3406 if (G_p->g_attrnam_p != NULL) {
3403 3407 if (((Args & OCt) == 0) &&
3404 3408 ((!Atflag && !SysAtflag) ||
3405 3409 (Atflag && !SysAtflag && ((G_p->g_attrparent_p != NULL) ||
3406 3410 G_p->g_rw_sysattr)) ||
3407 3411 (!Atflag && SysAtflag && ((G_p->g_attrparent_p != NULL) ||
3408 3412 !G_p->g_rw_sysattr)))) {
3409 3413 proc_file = F_SKIP;
3410 3414 data_in(P_SKIP);
3411 3415 return;
3412 3416 }
3413 3417 }
3414 3418
3415 3419 /*
3416 3420 * Open target directory if this isn't a skipped file
3417 3421 * and g_nlink == 1
3418 3422 *
3419 3423 * Links are handled further down in this function.
3420 3424 */
3421 3425
3422 3426 proc_file = ckname(0);
3423 3427
3424 3428 if (proc_file == F_SKIP && G_p->g_nlink == 1) {
3425 3429 /*
3426 3430 * Normally ckname() prints out the file as a side
3427 3431 * effect except for table of contents listing
3428 3432 * when its parameter is zero and Onecopy isn't
3429 3433 * Zero. Due to this we need to force the name
3430 3434 * to be printed here.
3431 3435 */
3432 3436 if (Onecopy == 1) {
3433 3437 VERBOSE((Args & OCt), G_p->g_nam_p);
3434 3438 }
3435 3439 data_in(P_SKIP);
3436 3440 return;
3437 3441 }
3438 3442
3439 3443 if (proc_file != F_SKIP && open_dirfd() != 0) {
3440 3444 data_in(P_SKIP);
3441 3445 return;
3442 3446 }
3443 3447
3444 3448 if (Hdr_type == BAR) {
3445 3449 bar_file_in();
3446 3450 close_dirfd();
3447 3451 return;
3448 3452 }
3449 3453
3450 3454 /*
3451 3455 * For archives in USTAR format, the files are extracted according
3452 3456 * to the typeflag.
3453 3457 */
3454 3458 if (Hdr_type == USTAR || Hdr_type == TAR) {
3455 3459 typeflag = Thdr_p->tbuf.t_typeflag;
3456 3460 if (G_p->g_nlink == 1) { /* hard link */
3457 3461 if (proc_file != F_SKIP) {
3458 3462 int i;
3459 3463 char lname[NAMSIZ+1];
3460 3464 (void) memset(lname, '\0', sizeof (lname));
3461 3465
3462 3466 (void) strncpy(lname, Thdr_p->tbuf.t_linkname,
3463 3467 NAMSIZ);
3464 3468 for (i = 0; i <= NAMSIZ && lname[i] != 0; i++)
3465 3469 ;
3466 3470
3467 3471 lname[i] = 0;
3468 3472 (void) creat_lnk(G_p->g_dirfd,
3469 3473 &lname[0], G_p->g_nam_p);
3470 3474 }
3471 3475 close_dirfd();
3472 3476 return;
3473 3477 }
3474 3478 if (typeflag == '3' || typeflag == '4' || typeflag == '5' ||
3475 3479 typeflag == '6') {
3476 3480 if (proc_file != F_SKIP &&
3477 3481 creat_spec(G_p->g_dirfd) > 0) {
3478 3482 VERBOSE((Args & (OCv | OCV)),
3479 3483 (G_p->g_attrparent_p == NULL) ?
3480 3484 G_p->g_nam_p : G_p->g_attrpath_p);
3481 3485 }
3482 3486 close_dirfd();
3483 3487 return;
3484 3488 } else if (Adir || Aspec) {
3485 3489 if ((proc_file == F_SKIP) ||
3486 3490 (Ofile = openout(G_p->g_dirfd)) < 0) {
3487 3491 data_in(P_SKIP);
3488 3492 } else {
3489 3493 data_in(P_PROC);
3490 3494 }
3491 3495 close_dirfd();
3492 3496 return;
3493 3497 }
3494 3498 }
3495 3499
3496 3500 if (Adir) {
3497 3501 if (proc_file != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
3498 3502 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3499 3503 }
3500 3504 close_dirfd();
3501 3505 if (Onecopy == 1) {
3502 3506 VERBOSE((Args & OCt), G_p->g_nam_p);
3503 3507 }
3504 3508 return;
3505 3509 }
3506 3510 if (G_p->g_nlink == 1 || (Hdr_type == TAR ||
3507 3511 Hdr_type == USTAR)) {
3508 3512 if (Aspec) {
3509 3513 if (proc_file != F_SKIP && creat_spec(G_p->g_dirfd) > 0)
3510 3514 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3511 3515 } else {
3512 3516 if ((proc_file == F_SKIP) ||
3513 3517 (Ofile = openout(G_p->g_dirfd)) < 0) {
3514 3518 data_in(P_SKIP);
3515 3519 } else {
3516 3520 data_in(P_PROC);
3517 3521 }
3518 3522 }
3519 3523 close_dirfd();
3520 3524 return;
3521 3525 }
3522 3526 close_dirfd();
3523 3527
3524 3528 tl_p = add_lnk(&ttl_p);
3525 3529 l_p = ttl_p;
3526 3530 if (l_p->L_cnt == l_p->L_gen.g_nlink)
3527 3531 cleanup = 1;
3528 3532 if (!Onecopy || G_p->g_attrnam_p != NULL) {
3529 3533 lnkem = (tl_p != l_p) ? 1 : 0;
3530 3534 G_p = &tl_p->L_gen;
3531 3535 if (proc_file == F_SKIP) {
3532 3536 data_in(P_SKIP);
3533 3537 } else {
3534 3538 if (open_dirfd() != 0)
3535 3539 return;
3536 3540 if (!lnkem) {
3537 3541 if (Aspec) {
3538 3542 if (creat_spec(G_p->g_dirfd) > 0)
3539 3543 VERBOSE((Args & (OCv | OCV)),
3540 3544 G_p->g_nam_p);
3541 3545 } else if ((Ofile =
3542 3546 openout(G_p->g_dirfd)) < 0) {
3543 3547 data_in(P_SKIP);
3544 3548 close_dirfd();
3545 3549 reclaim(l_p);
3546 3550 } else {
3547 3551 data_in(P_PROC);
3548 3552 close_dirfd();
3549 3553 }
3550 3554 } else {
3551 3555 /*
3552 3556 * Are we linking an attribute?
3553 3557 */
3554 3558 cwd = -1;
3555 3559 if (l_p->L_gen.g_attrnam_p != NULL) {
3556 3560 (void) strcpy(Lnkend_p,
3557 3561 l_p->L_gen.g_attrnam_p);
3558 3562 (void) strcpy(Full_p,
3559 3563 tl_p->L_gen.g_attrnam_p);
3560 3564 cwd = save_cwd();
3561 3565 (void) fchdir(G_p->g_dirfd);
3562 3566 } else {
3563 3567 (void) strcpy(Lnkend_p,
3564 3568 l_p->L_gen.g_nam_p);
3565 3569 (void) strcpy(Full_p,
3566 3570 tl_p->L_gen.g_nam_p);
3567 3571 }
3568 3572 (void) creat_lnk(G_p->g_dirfd,
3569 3573 Lnkend_p, Full_p);
3570 3574 data_in(P_SKIP);
3571 3575 close_dirfd();
3572 3576 l_p->L_lnk_p = NULL;
3573 3577 free(tl_p->L_gen.g_nam_p);
3574 3578 free(tl_p);
3575 3579 if (cwd != -1)
3576 3580 rest_cwd(cwd);
3577 3581 }
3578 3582 }
3579 3583 } else { /* Onecopy */
3580 3584 if (tl_p->L_gen.g_filesz)
3581 3585 cleanup = 1;
3582 3586 if (!cleanup) {
3583 3587 close_dirfd();
3584 3588 return; /* don't do anything yet */
3585 3589 }
3586 3590 tl_p = l_p;
3587 3591 /*
3588 3592 * ckname will clear aclchar. We need to keep aclchar for
3589 3593 * all links.
3590 3594 */
3591 3595 savacl = aclchar;
3592 3596 while (tl_p != NULL) {
3593 3597 G_p = &tl_p->L_gen;
3594 3598 aclchar = savacl;
3595 3599 if ((proc_file = ckname(1)) != F_SKIP) {
3596 3600 if (open_dirfd() != 0) {
3597 3601 return;
3598 3602 }
3599 3603 if (l_p->L_data) {
3600 3604 (void) creat_lnk(G_p->g_dirfd,
3601 3605 l_p->L_gen.g_nam_p,
3602 3606 G_p->g_nam_p);
3603 3607 } else if (Aspec) {
3604 3608 (void) creat_spec(G_p->g_dirfd);
3605 3609 l_p->L_data = 1;
3606 3610 VERBOSE((Args & (OCv | OCV)),
3607 3611 G_p->g_nam_p);
3608 3612 } else if ((Ofile =
3609 3613 openout(G_p->g_dirfd)) < 0) {
3610 3614 proc_file = F_SKIP;
3611 3615 } else {
3612 3616 data_in(P_PROC);
3613 3617 l_p->L_data = 1;
3614 3618 }
3615 3619 } /* (proc_file = ckname(1)) != F_SKIP */
3616 3620
3617 3621 tl_p = tl_p->L_lnk_p;
3618 3622
3619 3623 close_dirfd();
3620 3624
3621 3625 if (proc_file == F_SKIP && !cleanup) {
3622 3626 tl_p->L_nxt_p = l_p->L_nxt_p;
3623 3627 tl_p->L_bck_p = l_p->L_bck_p;
3624 3628 l_p->L_bck_p->L_nxt_p = tl_p;
3625 3629 l_p->L_nxt_p->L_bck_p = tl_p;
3626 3630 free(l_p->L_gen.g_nam_p);
3627 3631 free(l_p);
3628 3632 }
3629 3633 } /* tl_p->L_lnk_p != NULL */
3630 3634 if (l_p->L_data == 0) {
3631 3635 data_in(P_SKIP);
3632 3636 }
3633 3637 }
3634 3638 if (cleanup) {
3635 3639 reclaim(l_p);
3636 3640 }
3637 3641 }
3638 3642
3639 3643 /*
3640 3644 * file_out: If the current file is not a special file (!Aspec) and it
3641 3645 * is identical to the archive, skip it (do not archive the archive if it
3642 3646 * is a regular file). If creating a TARTYP (TAR or USTAR) archive, the first
3643 3647 * time a link to a file is encountered, write the header and file out normally.
3644 3648 * Subsequent links to this file put this file name in their t_linkname field.
3645 3649 * Otherwise, links are handled in one of two ways, for the old headers
3646 3650 * (i.e. binary and -c), linked files are written out as they are encountered.
3647 3651 * For the new headers (ASC and CRC), links are saved up until all the links
3648 3652 * to each file are found. For a file with n links, write n - 1 headers with
3649 3653 * g_filesz set to 0, write the final (nth) header with the correct g_filesz
3650 3654 * value and write the data for the file to the archive.
3651 3655 */
3652 3656 static
3653 3657 int
3654 3658 file_out(void)
3655 3659 {
3656 3660 struct Lnk *l_p, *tl_p;
3657 3661 int cleanup = 0;
3658 3662 struct Lnk *ttl_p;
3659 3663
3660 3664 G_p = &Gen;
3661 3665 if (!Aspec && IDENT(SrcSt, ArchSt))
3662 3666 return (1); /* do not archive the archive if it's a reg file */
3663 3667 /*
3664 3668 * If compressing sparse files, wait until the compressed file size
3665 3669 * is known to check if file size is too big.
3666 3670 */
3667 3671 if (Compress_sparse == 0 && G_p->g_filesz > Max_offset) {
3668 3672 msg(ERR, "%s%s%s: too large to archive in current mode",
3669 3673 G_p->g_nam_p,
3670 3674 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
3671 3675 gettext(" System Attribute ") : gettext(" Attribute "),
3672 3676 (G_p->g_attrnam_p == NULL) ? "" :
3673 3677 ((G_p->g_attrparent_p == NULL) ? G_p->g_attrnam_p:
3674 3678 G_p->g_attrpath_p));
3675 3679 return (1); /* do not archive if it's too big */
3676 3680 }
3677 3681 if (Hdr_type == TAR || Hdr_type == USTAR) { /* TAR and USTAR */
3678 3682 if (Adir) {
3679 3683 if (Gen.g_attrnam_p != NULL) {
3680 3684 write_xattr_hdr();
3681 3685 }
3682 3686 write_hdr(ARCHIVE_NORMAL, 0);
3683 3687 return (0);
3684 3688 }
3685 3689 if (G_p->g_nlink == 1) {
3686 3690 data_out();
3687 3691 return (0);
3688 3692 }
3689 3693 tl_p = add_lnk(&ttl_p);
3690 3694 l_p = ttl_p;
3691 3695 if (tl_p == l_p) { /* first link to this file encountered */
3692 3696 data_out();
3693 3697 return (0);
3694 3698 }
3695 3699 (void) strncpy(T_lname, l_p->L_gen.g_nam_p,
3696 3700 l_p->L_gen.g_namesz);
3697 3701
3698 3702 /*
3699 3703 * check if linkname is greater than 100 characters
3700 3704 */
3701 3705 if (strlen(T_lname) > NAMSIZ) {
3702 3706 msg(EPOST, "cpio: %s: linkname %s is greater than %d",
3703 3707 G_p->g_nam_p, T_lname, NAMSIZ);
3704 3708 return (1);
3705 3709 }
3706 3710
3707 3711 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3708 3712 VERBOSE((Args & (OCv | OCV)), tl_p->L_gen.g_nam_p);
3709 3713
3710 3714 /* find the lnk entry in sublist, unlink it, and free it */
3711 3715 for (; ttl_p->L_lnk_p != NULL;
3712 3716 ttl_p = ttl_p->L_lnk_p) {
3713 3717 if (ttl_p->L_lnk_p == tl_p) {
3714 3718 ttl_p->L_lnk_p = tl_p->L_lnk_p;
3715 3719 free(tl_p->L_gen.g_nam_p);
3716 3720 free(tl_p);
3717 3721 break;
3718 3722 }
3719 3723 }
3720 3724
3721 3725 return (0);
3722 3726 }
3723 3727 if (Adir) {
3724 3728 /*
3725 3729 * ACL has been retrieved in getname().
3726 3730 */
3727 3731 if (Pflag) {
3728 3732 char *secinfo = NULL;
3729 3733 int len = 0;
3730 3734
3731 3735 /* append security attributes */
3732 3736 if ((append_secattr(&secinfo, &len, aclp)) == -1)
3733 3737 msg(ERR, "can create security information");
3734 3738
3735 3739 /* call append_secattr() if more than one */
3736 3740
3737 3741 if (len > 0) {
3738 3742 /* write ancillary */
3739 3743 write_hdr(ARCHIVE_ACL, (off_t)len);
3740 3744 write_ancillary(secinfo, len, B_TRUE);
3741 3745 }
3742 3746 }
3743 3747
3744 3748 if (Gen.g_attrnam_p != NULL) {
3745 3749 write_xattr_hdr();
3746 3750 }
3747 3751 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3748 3752 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3749 3753 return (0);
3750 3754 }
3751 3755 if (G_p->g_nlink == 1) {
3752 3756 data_out();
3753 3757 return (0);
3754 3758 } else {
3755 3759 tl_p = add_lnk(&ttl_p);
3756 3760 l_p = ttl_p;
3757 3761
3758 3762 if (l_p->L_cnt == l_p->L_gen.g_nlink)
3759 3763 cleanup = 1;
3760 3764 else if (Onecopy && G_p->g_attrnam_p == NULL) {
3761 3765 return (0); /* don't process data yet */
3762 3766 }
3763 3767 }
3764 3768 if (Onecopy && G_p->g_attrnam_p == NULL) {
3765 3769 tl_p = l_p;
3766 3770 while (tl_p->L_lnk_p != NULL) {
3767 3771 G_p = &tl_p->L_gen;
3768 3772 G_p->g_filesz = (off_t)0;
3769 3773 /* one link with the acl is sufficient */
3770 3774 write_hdr(ARCHIVE_NORMAL, (off_t)0);
3771 3775 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
3772 3776 tl_p = tl_p->L_lnk_p;
3773 3777 }
3774 3778 G_p = &tl_p->L_gen;
3775 3779 if (open_dirfd() != 0)
3776 3780 return (1);
3777 3781 }
3778 3782 /* old style: has acl and data for every link */
3779 3783 data_out();
3780 3784 if (cleanup)
3781 3785 reclaim(l_p);
3782 3786 return (0);
3783 3787 }
3784 3788
3785 3789 /*
3786 3790 * Verify the underlying file system supports the attribute type.
3787 3791 * Only archive extended attribute files when '-@' was specified.
3788 3792 * Only archive system extended attribute files if '-/' was specified.
3789 3793 */
3790 3794 #if defined(O_XATTR)
3791 3795 static attr_status_t
3792 3796 verify_attr_support(char *filename, int attrflg, arc_action_t actflag,
3793 3797 int *ext_attrflg)
3794 3798 {
3795 3799 /*
3796 3800 * Verify extended attributes are supported/exist. We only
3797 3801 * need to check if we are processing a base file, not an
3798 3802 * extended attribute.
3799 3803 */
3800 3804 if (attrflg) {
3801 3805 *ext_attrflg = (pathconf(filename, (actflag == ARC_CREATE) ?
3802 3806 _PC_XATTR_EXISTS : _PC_XATTR_ENABLED) == 1);
3803 3807 }
3804 3808 if (Atflag) {
3805 3809 #if defined(_PC_SATTR_ENABLED)
3806 3810 if (!*ext_attrflg) {
3807 3811 if (SysAtflag) {
3808 3812 /* Verify system attributes are supported */
3809 3813 if (sysattr_support(filename,
3810 3814 (actflag == ARC_CREATE) ?_PC_SATTR_EXISTS :
3811 3815 _PC_SATTR_ENABLED) != 1) {
3812 3816 return (ATTR_SATTR_ERR);
3813 3817 }
3814 3818 } else
3815 3819 return (ATTR_XATTR_ERR);
3816 3820 #else
3817 3821 return (ATTR_XATTR_ERR);
3818 3822 #endif /* _PC_SATTR_ENABLED */
3819 3823 }
3820 3824
3821 3825 #if defined(_PC_SATTR_ENABLED)
3822 3826 } else if (SysAtflag) {
3823 3827 /* Verify system attributes are supported */
3824 3828 if (sysattr_support(filename, (actflag == ARC_CREATE) ?
3825 3829 _PC_SATTR_EXISTS : _PC_SATTR_ENABLED) != 1) {
3826 3830 return (ATTR_SATTR_ERR);
3827 3831 }
3828 3832 #endif /* _PC_SATTR_ENABLED */
3829 3833 } else {
3830 3834 return (ATTR_SKIP);
3831 3835 }
3832 3836
3833 3837 return (ATTR_OK);
3834 3838 }
3835 3839 #endif
3836 3840
3837 3841 #if defined(O_XATTR)
3838 3842 /*
3839 3843 * Verify the attribute, attrname, is an attribute we want to restore.
3840 3844 * Never restore read-only system attribute files. Only restore read-write
3841 3845 * system attributes files when -/ was specified, and only traverse into
3842 3846 * the 2nd level attribute directory containing only system attributes if
3843 3847 * -@ was specified. This keeps us from archiving
3844 3848 * <attribute name>/<read-write system attribute file>
3845 3849 * when -/ was specified without -@.
3846 3850 *
3847 3851 * attrname - attribute file name
3848 3852 * attrparent - attribute's parent name within the base file's
3849 3853 * attribute digrectory hierarchy
3850 3854 * arc_rwsysattr - flag that indicates that read-write system attribute
3851 3855 * file should be archived as it contains other than
3852 3856 * the default system attributes.
3853 3857 * rw_sysattr - on return, flag will indicate if attrname is a
3854 3858 * read-write system attribute file.
3855 3859 */
3856 3860 static attr_status_t
3857 3861 verify_attr(char *attrname, char *attrparent, int arc_rwsysattr,
3858 3862 int *rw_sysattr)
3859 3863 {
3860 3864 #if defined(_PC_SATTR_ENABLED)
3861 3865 int attr_supported;
3862 3866
3863 3867 /* Never restore read-only system attribute files */
3864 3868 if ((attr_supported = sysattr_type(attrname)) == _RO_SATTR) {
3865 3869 *rw_sysattr = 0;
3866 3870 return (ATTR_SKIP);
3867 3871 } else {
3868 3872 *rw_sysattr = (attr_supported == _RW_SATTR);
3869 3873 }
3870 3874
3871 3875 /*
3872 3876 * Don't archive a read-write system attribute file if
3873 3877 * it contains only the default system attributes.
3874 3878 */
3875 3879 if (*rw_sysattr && !arc_rwsysattr) {
3876 3880 return (ATTR_SKIP);
3877 3881 }
3878 3882
3879 3883 #else
3880 3884 /* Never restore read-only system attribute files */
3881 3885 if ((*rw_sysattr = is_sysattr(attrname)) == 1) {
3882 3886 return (ATTR_SKIP);
3883 3887 }
3884 3888 #endif /* _PC_SATTR_ENABLED */
3885 3889
3886 3890 /*
3887 3891 * Only restore read-write system attribute files
3888 3892 * when -/ was specified. Only restore extended
3889 3893 * attributes when -@ was specified.
3890 3894 */
3891 3895 if (Atflag) {
3892 3896 if (!SysAtflag) {
3893 3897 /*
3894 3898 * Only archive/restore the hidden directory "." if
3895 3899 * we're processing the top level hidden attribute
3896 3900 * directory. We don't want to process the
3897 3901 * hidden attribute directory of the attribute
3898 3902 * directory that contains only extended system
3899 3903 * attributes.
3900 3904 */
3901 3905 if (*rw_sysattr || (Hiddendir &&
3902 3906 (attrparent != NULL))) {
3903 3907 return (ATTR_SKIP);
3904 3908 }
3905 3909 }
3906 3910 } else if (SysAtflag) {
3907 3911 /*
3908 3912 * Only archive/restore read-write extended system attribute
3909 3913 * files of the base file.
3910 3914 */
3911 3915 if (!*rw_sysattr || (attrparent != NULL)) {
3912 3916 return (ATTR_SKIP);
3913 3917 }
3914 3918 } else {
3915 3919 return (ATTR_SKIP);
3916 3920 }
3917 3921
3918 3922 return (ATTR_OK);
3919 3923 }
3920 3924 #endif
3921 3925
3922 3926 #if defined(O_XATTR)
3923 3927 static int
3924 3928 retry_open_attr(int pdirfd, int cwd, char *fullname, char *pattr, char *name,
3925 3929 int oflag, mode_t mode)
3926 3930 {
3927 3931 int dirfd;
3928 3932 int ofilefd = -1;
3929 3933 struct timeval times[2];
3930 3934 mode_t newmode;
3931 3935 struct stat parentstat;
3932 3936 acl_t *aclp = NULL;
3933 3937 int error;
3934 3938
3935 3939 /*
3936 3940 * We couldn't get to attrdir. See if its
3937 3941 * just a mode problem on the parent file.
3938 3942 * for example: a mode such as r-xr--r--
3939 3943 * on a ufs file system without extended
3940 3944 * system attribute support won't let us
3941 3945 * create an attribute dir if it doesn't
3942 3946 * already exist, and on a ufs file system
3943 3947 * with extended system attribute support
3944 3948 * won't let us open the attribute for
3945 3949 * write.
3946 3950 *
3947 3951 * If file has a non-trivial ACL, then save it
3948 3952 * off so that we can place it back on after doing
3949 3953 * chmod's.
3950 3954 */
3951 3955 if ((dirfd = openat(cwd, (pattr == NULL) ? fullname : pattr,
3952 3956 O_RDONLY)) == -1) {
3953 3957 return (-1);
3954 3958 }
3955 3959 if (fstat(dirfd, &parentstat) == -1) {
3956 3960 msg(ERRN, "Cannot stat %sfile %s",
3957 3961 (pdirfd == -1) ? "" : gettext("parent of "),
3958 3962 (pdirfd == -1) ? fullname : name);
3959 3963 (void) close(dirfd);
3960 3964 return (-1);
3961 3965 }
3962 3966 if ((error = facl_get(dirfd, ACL_NO_TRIVIAL, &aclp)) != 0) {
3963 3967 msg(ERRN, "Failed to retrieve ACL on %sfile %s",
3964 3968 (pdirfd == -1) ? "" : gettext("parent of "),
3965 3969 (pdirfd == -1) ? fullname : name);
3966 3970 (void) close(dirfd);
3967 3971 return (-1);
3968 3972 }
3969 3973
3970 3974 newmode = S_IWUSR | parentstat.st_mode;
3971 3975 if (fchmod(dirfd, newmode) == -1) {
3972 3976 msg(ERRN, "Cannot change mode of %sfile %s to %o",
3973 3977 (pdirfd == -1) ? "" : gettext("parent of "),
3974 3978 (pdirfd == -1) ? fullname : name, newmode);
3975 3979 if (aclp)
3976 3980 acl_free(aclp);
3977 3981 (void) close(dirfd);
3978 3982 return (-1);
3979 3983 }
3980 3984
3981 3985
3982 3986 if (pdirfd == -1) {
3983 3987 /*
3984 3988 * We weren't able to create the attribute directory before.
3985 3989 * Now try again.
3986 3990 */
3987 3991 ofilefd = attropen(fullname, ".", oflag);
3988 3992 } else {
3989 3993 /*
3990 3994 * We weren't able to create open the attribute before.
3991 3995 * Now try again.
3992 3996 */
3993 3997 ofilefd = openat(pdirfd, name, oflag, mode);
3994 3998 }
3995 3999
3996 4000 /*
3997 4001 * Put mode back to original
3998 4002 */
3999 4003 if (fchmod(dirfd, parentstat.st_mode) == -1) {
4000 4004 msg(ERRN, "Cannot restore permissions of %sfile %s to %o",
4001 4005 (pdirfd == -1) ? "" : gettext("parent of "),
4002 4006 (pdirfd == -1) ? fullname : name, newmode);
4003 4007 }
4004 4008
4005 4009 if (aclp) {
4006 4010 error = facl_set(dirfd, aclp);
4007 4011 if (error) {
4008 4012 msg(ERRN, "failed to set acl entries on %sfile %s\n",
4009 4013 (pdirfd == -1) ? "" : gettext("parent of "),
4010 4014 (pdirfd == -1) ? fullname : name);
4011 4015 }
4012 4016 acl_free(aclp);
4013 4017 }
4014 4018
4015 4019 /*
4016 4020 * Put back time stamps
4017 4021 */
4018 4022
4019 4023 times[0].tv_sec = parentstat.st_atime;
4020 4024 times[0].tv_usec = 0;
4021 4025 times[1].tv_sec = parentstat.st_mtime;
4022 4026 times[1].tv_usec = 0;
4023 4027
4024 4028 (void) futimesat(cwd, (pattr == NULL) ? fullname : pattr, times);
4025 4029
4026 4030 (void) close(dirfd);
4027 4031
4028 4032 return (ofilefd);
4029 4033 }
4030 4034 #endif
4031 4035
4032 4036 #if defined(O_XATTR)
4033 4037 /*
4034 4038 * Recursively open attribute directories until the attribute directory
4035 4039 * containing the specified attribute, attrname, is opened.
4036 4040 *
4037 4041 * Currently, only 2 directory levels of attributes are supported, (i.e.,
4038 4042 * extended system attributes on extended attributes). The following are
4039 4043 * the possible input combinations:
4040 4044 * 1. Open the attribute directory of the base file (don't change
4041 4045 * into it).
4042 4046 * attr_parent = NULL
4043 4047 * attrname = '.'
4044 4048 * 2. Open the attribute directory of the base file and change into it.
4045 4049 * attr_parent = NULL
4046 4050 * attrname = <attr> | <sys_attr>
4047 4051 * 3. Open the attribute directory of the base file, change into it,
4048 4052 * then recursively call open_attr_dir() to open the attribute's
4049 4053 * parent directory (don't change into it).
4050 4054 * attr_parent = <attr>
4051 4055 * attrname = '.'
4052 4056 * 4. Open the attribute directory of the base file, change into it,
4053 4057 * then recursively call open_attr_dir() to open the attribute's
4054 4058 * parent directory and change into it.
4055 4059 * attr_parent = <attr>
4056 4060 * attrname = <attr> | <sys_attr>
4057 4061 *
4058 4062 * An attribute directory will be opened only if the underlying file system
4059 4063 * supports the attribute type, and if the command line specifications
4060 4064 * (f_extended_attr and f_sys_attr) enable the processing of the attribute
4061 4065 * type.
4062 4066 *
4063 4067 * On succesful return, attr_parentfd will be the file descriptor of the
4064 4068 * opened attribute directory. In addition, if the attribute is a read-write
4065 4069 * extended system attribute, rw_sysattr will be set to 1, otherwise
4066 4070 * it will be set to 0.
4067 4071 *
4068 4072 * Possible return values:
4069 4073 * ATTR_OK Successfully opened and, if needed, changed into the
4070 4074 * attribute directory containing attrname.
4071 4075 * ATTR_SKIP The command line specifications don't enable the
4072 4076 * processing of the attribute type.
4073 4077 * ATTR_CHDIR_ERR An error occurred while trying to change into an
4074 4078 * attribute directory.
4075 4079 * ATTR_OPEN_ERR An error occurred while trying to open an
4076 4080 * attribute directory.
4077 4081 * ATTR_XATTR_ERR The underlying file system doesn't support extended
4078 4082 * attributes.
4079 4083 * ATTR_SATTR_ERR The underlying file system doesn't support extended
4080 4084 * system attributes.
4081 4085 */
4082 4086 static int
4083 4087 open_attr_dir(char *attrname, char *dirp, int cwd, char *attr_parent,
4084 4088 int *attr_parentfd, int *rw_sysattr)
4085 4089 {
4086 4090 attr_status_t rc;
4087 4091 int firsttime = (*attr_parentfd == -1);
4088 4092 int saveerrno;
4089 4093 int ext_attr;
4090 4094
4091 4095 /*
4092 4096 * open_attr_dir() was recursively called (input combination number 4),
4093 4097 * close the previously opened file descriptor as we've already changed
4094 4098 * into it.
4095 4099 */
4096 4100 if (!firsttime) {
4097 4101 (void) close(*attr_parentfd);
4098 4102 *attr_parentfd = -1;
4099 4103 }
4100 4104
4101 4105 /*
4102 4106 * Verify that the underlying file system supports the restoration
4103 4107 * of the attribute.
4104 4108 */
4105 4109 if ((rc = verify_attr_support(dirp, firsttime, ARC_RESTORE,
4106 4110 &ext_attr)) != ATTR_OK) {
4107 4111 return (rc);
4108 4112 }
4109 4113
4110 4114 /* Open the base file's attribute directory */
4111 4115 if ((*attr_parentfd = attropen(dirp, ".", O_RDONLY)) == -1) {
4112 4116 /*
4113 4117 * Save the errno from the attropen so it can be reported
4114 4118 * if the retry of the attropen fails.
4115 4119 */
4116 4120 saveerrno = errno;
4117 4121 if ((*attr_parentfd = retry_open_attr(-1, cwd, dirp,
4118 4122 NULL, ".", O_RDONLY, 0)) == -1) {
4119 4123 (void) close(*attr_parentfd);
4120 4124 *attr_parentfd = -1;
4121 4125 errno = saveerrno;
4122 4126 return (ATTR_OPEN_ERR);
4123 4127 }
4124 4128 }
4125 4129
4126 4130 /*
4127 4131 * Change into the parent attribute's directory unless we are
4128 4132 * processing the hidden attribute directory of the base file itself.
4129 4133 */
4130 4134 if ((Hiddendir == 0) || (firsttime && (attr_parent != NULL))) {
4131 4135 if (fchdir(*attr_parentfd) != 0) {
4132 4136 saveerrno = errno;
4133 4137 (void) close(*attr_parentfd);
4134 4138 *attr_parentfd = -1;
4135 4139 errno = saveerrno;
4136 4140 return (ATTR_CHDIR_ERR);
4137 4141 }
4138 4142 }
4139 4143
4140 4144 /* Determine if the attribute should be processed */
4141 4145 if ((rc = verify_attr(attrname, attr_parent, 1,
4142 4146 rw_sysattr)) != ATTR_OK) {
4143 4147 saveerrno = errno;
4144 4148 (void) close(*attr_parentfd);
4145 4149 *attr_parentfd = -1;
4146 4150 errno = saveerrno;
4147 4151 return (rc);
4148 4152 }
4149 4153
4150 4154 /*
4151 4155 * If the attribute is an extended system attribute of an attribute
4152 4156 * (i.e., <attr>/<sys_attr>), then recursively call open_attr_dir() to
4153 4157 * open the attribute directory of the parent attribute.
4154 4158 */
4155 4159 if (firsttime && (attr_parent != NULL)) {
4156 4160 return (open_attr_dir(attrname, attr_parent, *attr_parentfd,
4157 4161 attr_parent, attr_parentfd, rw_sysattr));
4158 4162 }
4159 4163
4160 4164 return (ATTR_OK);
4161 4165 }
4162 4166 #endif
4163 4167
4164 4168 /*
4165 4169 * file_pass: If the -l option is set (link files when possible), and the
4166 4170 * source and destination file systems are the same, link the source file
4167 4171 * (G_p->g_nam_p) to the destination file (Fullnam) and return. If not a
4168 4172 * linked file, transfer the data. Otherwise, the first link to a file
4169 4173 * encountered is transferred normally and subsequent links are linked to it.
4170 4174 */
4171 4175
4172 4176 static int
4173 4177 file_pass(void)
4174 4178 {
4175 4179 struct Lnk *l_p, *tl_p;
4176 4180 struct Lnk *ttl_p;
4177 4181 char *save_name;
4178 4182 int size;
4179 4183 int cwd;
4180 4184 char *lfrom, *lto;
4181 4185
4182 4186 G_p = &Gen;
4183 4187
4184 4188 if (Adir && !(Args & OCd)) {
4185 4189 msg(ERR, "Use -d option to copy \"%s\"", G_p->g_nam_p);
4186 4190 return (FILE_PASS_ERR);
4187 4191 }
4188 4192
4189 4193 save_name = G_p->g_nam_p;
4190 4194
4191 4195 while (*(G_p->g_nam_p) == '/') {
4192 4196 G_p->g_nam_p++;
4193 4197 }
4194 4198
4195 4199 (void) strcpy(Full_p, (G_p->g_attrfnam_p == NULL) ?
4196 4200 G_p->g_nam_p : G_p->g_attrfnam_p);
4197 4201
4198 4202 if (G_p->g_attrnam_p == NULL) {
4199 4203 G_p->g_passdirfd = open_dir(Fullnam_p);
4200 4204
4201 4205 if (G_p->g_passdirfd == -1) {
4202 4206 msg(ERRN,
4203 4207 "Cannot open/create \"%s\"", Fullnam_p);
4204 4208 return (FILE_PASS_ERR);
4205 4209 }
4206 4210 } else {
4207 4211 int rw_sysattr;
4208 4212
4209 4213 /*
4210 4214 * Open the file's attribute directory.
4211 4215 * Change into the base file's starting directory then call
4212 4216 * open_attr_dir() to open the attribute directory of either
4213 4217 * the base file (if G_p->g_attrparent_p is NULL) or the
4214 4218 * attribute (if G_p->g_attrparent_p is set) of the base file.
4215 4219 */
4216 4220
4217 4221 G_p->g_passdirfd = -1;
4218 4222 (void) fchdir(G_p->g_baseparent_fd);
4219 4223 (void) open_attr_dir(G_p->g_attrnam_p, Fullnam_p,
4220 4224 G_p->g_baseparent_fd, (G_p->g_attrparent_p == NULL) ? NULL :
4221 4225 G_p->g_attrparent_p, &G_p->g_passdirfd, &rw_sysattr);
4222 4226 if (G_p->g_passdirfd == -1) {
4223 4227 msg(ERRN,
4224 4228 "Cannot open attribute directory of "
4225 4229 "%s%s%sfile \"%s\"",
4226 4230 (G_p->g_attrparent_p == NULL) ? "" :
4227 4231 gettext("attribute \""),
4228 4232 (G_p->g_attrparent_p == NULL) ? "" :
4229 4233 G_p->g_attrparent_p,
4230 4234 (G_p->g_attrparent_p == NULL) ? "" :
4231 4235 gettext("\" of "), Fullnam_p);
4232 4236 return (FILE_PASS_ERR);
4233 4237 }
4234 4238 }
4235 4239
4236 4240 if (Args & OCl) {
4237 4241 /* We are linking back to the source directory. */
4238 4242
4239 4243 if (!Adir) {
4240 4244 char *existingfile = save_name;
4241 4245
4242 4246 if ((Args & OCL) && issymlink) {
4243 4247 /* We are chasing symlinks. */
4244 4248
4245 4249 if ((size = readlink(save_name, Symlnk_p,
4246 4250 MAXPATHLEN)) < 0) {
4247 4251 msg(ERRN,
4248 4252 "Cannot read symbolic link \"%s\"",
4249 4253 save_name);
4250 4254 return (FILE_PASS_ERR);
4251 4255 }
4252 4256
4253 4257 Symlnk_p[size] = '\0';
4254 4258 existingfile = Symlnk_p;
4255 4259 }
4256 4260
4257 4261 if (G_p->g_attrnam_p == NULL) {
4258 4262 if (creat_lnk(G_p->g_passdirfd,
4259 4263 existingfile, Fullnam_p) == 0) {
4260 4264 return (FILE_LINKED);
4261 4265 }
4262 4266 }
4263 4267 }
4264 4268 }
4265 4269
4266 4270 if ((G_p->g_mode & Ftype) == S_IFLNK && !(Args & OCL)) {
4267 4271 /* The archive file is a symlink. */
4268 4272
4269 4273 errno = 0;
4270 4274
4271 4275 if ((size = readlink(save_name, Symlnk_p, MAXPATHLEN)) < 0) {
4272 4276 msg(ERRN,
4273 4277 "Cannot read symbolic link \"%s\"", save_name);
4274 4278 return (FILE_PASS_ERR);
4275 4279 }
4276 4280
4277 4281 errno = 0;
4278 4282 (void) missdir(Fullnam_p);
4279 4283 *(Symlnk_p + size) = '\0';
4280 4284
4281 4285 if (symlink(Symlnk_p, Fullnam_p) < 0) {
4282 4286 if (errno == EEXIST) {
4283 4287 if (openout(G_p->g_passdirfd) < 0) {
4284 4288 if (errno != EEXIST) {
4285 4289 msg(ERRN,
4286 4290 "Cannot create \"%s\"",
4287 4291 Fullnam_p);
4288 4292 }
4289 4293 return (FILE_PASS_ERR);
4290 4294 }
4291 4295 } else {
4292 4296 msg(ERRN, "Cannot create \"%s\"", Fullnam_p);
4293 4297 return (FILE_PASS_ERR);
4294 4298 }
4295 4299 } else {
4296 4300 if (Args & OCR) {
4297 4301 if (lchown(Fullnam_p, (int)Rpw_p->pw_uid,
4298 4302 (int)Rpw_p->pw_gid) < 0) {
4299 4303 msg(ERRN,
4300 4304 "Error during chown() of \"%s\"",
4301 4305 Fullnam_p);
4302 4306 }
4303 4307 } else if ((lchown(Fullnam_p, (int)G_p->g_uid,
4304 4308 (int)G_p->g_gid) < 0) && privileged) {
4305 4309 msg(ERRN,
4306 4310 "Error during chown() of \"%s\"",
4307 4311 Fullnam_p);
4308 4312 }
4309 4313 }
4310 4314
4311 4315 VERBOSE((Args & (OCv | OCV)), Fullnam_p);
4312 4316 return (FILE_PASS_ERR);
4313 4317 }
4314 4318
4315 4319 if (!Adir && G_p->g_nlink > 1) {
4316 4320 /* The archive file has hard links. */
4317 4321
4318 4322 tl_p = add_lnk(&ttl_p);
4319 4323 l_p = ttl_p;
4320 4324
4321 4325 if (tl_p == l_p) {
4322 4326 /* The archive file was not found. */
4323 4327
4324 4328 G_p = &tl_p->L_gen;
4325 4329 } else {
4326 4330 /* The archive file was found. */
4327 4331
4328 4332 cwd = -1;
4329 4333
4330 4334 if (l_p->L_gen.g_attrnam_p != NULL) {
4331 4335 /* We are linking an attribute */
4332 4336
4333 4337 (void) strcpy(Lnkend_p, l_p->L_gen.g_attrnam_p);
4334 4338 cwd = save_cwd();
4335 4339 (void) fchdir(G_p->g_passdirfd);
4336 4340 lfrom = get_component(Lnknam_p);
4337 4341 lto = tl_p->L_gen.g_attrnam_p;
4338 4342 } else {
4339 4343 /* We are not linking an attribute */
4340 4344
4341 4345 (void) strcpy(Lnkend_p, l_p->L_gen.g_nam_p);
4342 4346 (void) strcpy(Full_p, tl_p->L_gen.g_nam_p);
4343 4347 lfrom = Lnknam_p;
4344 4348 lto = Fullnam_p;
4345 4349 }
4346 4350
4347 4351 (void) creat_lnk(G_p->g_passdirfd, lfrom, lto);
4348 4352
4349 4353 if (cwd) {
4350 4354 rest_cwd(cwd);
4351 4355 }
4352 4356
4353 4357 l_p->L_lnk_p = NULL;
4354 4358 free(tl_p->L_gen.g_nam_p);
4355 4359 free(tl_p);
4356 4360
4357 4361 if (l_p->L_cnt == G_p->g_nlink) {
4358 4362 reclaim(l_p);
4359 4363 }
4360 4364
4361 4365 return (FILE_LINKED);
4362 4366 }
4363 4367 }
4364 4368
4365 4369 if (Adir || Aspec) {
4366 4370 /*
4367 4371 * The archive file is a directory, block special, char
4368 4372 * special or a fifo.
4369 4373 */
4370 4374
4371 4375 if (creat_spec(G_p->g_passdirfd) > 0) {
4372 4376 VERBOSE((Args & (OCv | OCV)), Fullnam_p);
4373 4377 }
4374 4378 } else if ((Ofile = openout(G_p->g_passdirfd)) > 0) {
4375 4379 data_pass();
4376 4380 }
4377 4381
4378 4382 return (FILE_COPIED);
4379 4383 }
4380 4384
4381 4385 /*
4382 4386 * flush_lnks: With new linked file handling, linked files are not archived
4383 4387 * until all links have been collected. When the end of the list of filenames
4384 4388 * to archive has been reached, all files that did not encounter all their links
4385 4389 * are written out with actual (encountered) link counts. A file with n links
4386 4390 * (that are archived) will be represented by n headers (one for each link (the
4387 4391 * first n - 1 have g_filesz set to 0)) followed by the data for the file.
4388 4392 */
4389 4393
4390 4394 static void
4391 4395 flush_lnks(void)
4392 4396 {
4393 4397 struct Lnk *l_p, *tl_p;
4394 4398 off_t tfsize;
4395 4399
4396 4400 l_p = Lnk_hd.L_nxt_p;
4397 4401 while (l_p != &Lnk_hd) {
4398 4402 (void) strcpy(Gen.g_nam_p, l_p->L_gen.g_nam_p);
4399 4403 if (stat(Gen.g_nam_p, &SrcSt) == 0) { /* check if file exists */
4400 4404 tl_p = l_p;
4401 4405 (void) creat_hdr();
4402 4406 Gen.g_nlink = l_p->L_cnt; /* "actual" link count */
4403 4407 tfsize = Gen.g_filesz;
4404 4408 Gen.g_filesz = (off_t)0;
4405 4409 G_p = &Gen;
4406 4410 while (tl_p != NULL) {
4407 4411 Gen.g_nam_p = tl_p->L_gen.g_nam_p;
4408 4412 Gen.g_namesz = tl_p->L_gen.g_namesz;
4409 4413 if (tl_p->L_lnk_p == NULL) {
4410 4414 Gen.g_filesz = tfsize;
4411 4415 if (open_dirfd() != 0) {
4412 4416 break;
4413 4417 }
4414 4418 data_out();
4415 4419 break;
4416 4420 }
4417 4421 write_hdr(ARCHIVE_NORMAL,
4418 4422 (off_t)0); /* header only */
4419 4423 VERBOSE((Args & (OCv | OCV)), Gen.g_nam_p);
4420 4424 tl_p = tl_p->L_lnk_p;
4421 4425 }
4422 4426 Gen.g_nam_p = Nam_p;
4423 4427 } else /* stat(Gen.g_nam_p, &SrcSt) == 0 */
4424 4428 msg(ERR, "\"%s%s%s\" has disappeared",
4425 4429 (Gen.g_attrnam_p == NULL) ?
4426 4430 Gen.g_nam_p : Gen.g_attrfnam_p,
4427 4431 (Gen.g_attrnam_p == NULL) ?
4428 4432 "" : Gen.g_rw_sysattr ?
4429 4433 gettext(" System Attribute ") :
4430 4434 gettext(" Attribute "),
4431 4435 (Gen.g_attrnam_p == NULL) ?
4432 4436 "" : Gen.g_attrnam_p);
4433 4437 tl_p = l_p;
4434 4438 l_p = l_p->L_nxt_p;
4435 4439 reclaim(tl_p);
4436 4440 } /* l_p != &Lnk_hd */
4437 4441 }
4438 4442
4439 4443 #if defined(O_XATTR)
4440 4444 static int
4441 4445 is_sysattr(char *name)
4442 4446 {
4443 4447 return ((strcmp(name, VIEW_READONLY) == 0) ||
4444 4448 (strcmp(name, VIEW_READWRITE) == 0));
4445 4449 }
4446 4450 #endif
4447 4451
4448 4452 /*
4449 4453 * gethdr: Get a header from the archive, validate it and check for the trailer.
4450 4454 * Any user specified Hdr_type is ignored (set to NONE in main). Hdr_type is
4451 4455 * set appropriately after a valid header is found. Unless the -k option is
4452 4456 * set a corrupted header causes an exit with an error. I/O errors during
4453 4457 * examination of any part of the header cause gethdr to throw away any current
4454 4458 * data and start over. Other errors during examination of any part of the
4455 4459 * header cause gethdr to advance one byte and continue the examination.
4456 4460 */
4457 4461
4458 4462 static int
4459 4463 gethdr(void)
4460 4464 {
4461 4465 ushort_t ftype;
4462 4466 int hit = NONE, cnt = 0;
4463 4467 int goodhdr, hsize, offset;
4464 4468 int bswap = 0;
4465 4469 char *preptr;
4466 4470 int k = 0;
4467 4471 int j;
4468 4472 int error;
4469 4473 int aclcnt;
4470 4474
4471 4475 Gen.g_nam_p = Nam_p;
4472 4476 do { /* hit == NONE && (Args & OCk) && Buffr.b_cnt > 0 */
4473 4477 FILL(Hdrsz);
4474 4478 switch (Hdr_type) {
4475 4479 case NONE:
4476 4480 case BIN:
4477 4481 Binmag.b_byte[0] = Buffr.b_out_p[0];
4478 4482 Binmag.b_byte[1] = Buffr.b_out_p[1];
4479 4483 if ((Binmag.b_half == CMN_BIN) ||
4480 4484 (Binmag.b_half == CMN_BBS)) {
4481 4485 hit = read_hdr(BIN);
4482 4486 if (Hdr_type == NONE)
4483 4487 bswap = 1;
4484 4488 hsize = HDRSZ + Gen.g_namesz;
4485 4489 break;
4486 4490 }
4487 4491 if (Hdr_type != NONE)
4488 4492 break;
4489 4493 /*FALLTHROUGH*/
4490 4494 case CHR:
4491 4495 if (!(strncmp(Buffr.b_out_p, CMS_CHR, CMS_LEN))) {
4492 4496 hit = read_hdr(CHR);
4493 4497 hsize = CHRSZ + Gen.g_namesz;
4494 4498 break;
4495 4499 }
4496 4500 if (Hdr_type != NONE)
4497 4501 break;
4498 4502 /*FALLTHROUGH*/
4499 4503 case ASC:
4500 4504 if (!(strncmp(Buffr.b_out_p, CMS_ASC, CMS_LEN))) {
4501 4505 hit = read_hdr(ASC);
4502 4506 hsize = ASCSZ + Gen.g_namesz;
4503 4507 Max_namesz = APATH;
4504 4508 break;
4505 4509 }
4506 4510 if (Hdr_type != NONE)
4507 4511 break;
4508 4512 /*FALLTHROUGH*/
4509 4513 case CRC:
4510 4514 if (!(strncmp(Buffr.b_out_p, CMS_CRC, CMS_LEN))) {
4511 4515 hit = read_hdr(CRC);
4512 4516 hsize = ASCSZ + Gen.g_namesz;
4513 4517 Max_namesz = APATH;
4514 4518 break;
4515 4519 }
4516 4520 if (Hdr_type != NONE)
4517 4521 break;
4518 4522 /*FALLTHROUGH*/
4519 4523
4520 4524 case BAR:
4521 4525 if (Hdr_p != NULL && strcmp(Hdr_p, "bar") == 0) {
4522 4526 Hdrsz = BARSZ;
4523 4527 FILL(Hdrsz);
4524 4528 if ((hit = read_hdr(BAR)) == NONE) {
4525 4529 Hdrsz = ASCSZ;
4526 4530 break;
4527 4531 }
4528 4532 hit = BAR;
4529 4533 hsize = BARSZ;
4530 4534 break;
4531 4535 }
4532 4536 /*FALLTHROUGH*/
4533 4537
4534 4538 case USTAR:
4535 4539 if (Hdr_p != NULL && strcmp(Hdr_p, "ustar") == 0) {
4536 4540 Hdrsz = TARSZ;
4537 4541 FILL(Hdrsz);
4538 4542 if ((hit = read_hdr(USTAR)) == NONE) {
4539 4543 Hdrsz = ASCSZ;
4540 4544 break;
4541 4545 }
4542 4546 hit = USTAR;
4543 4547 hsize = TARSZ;
4544 4548 break;
4545 4549 }
4546 4550 /*FALLTHROUGH*/
4547 4551 case TAR:
4548 4552 if (Hdr_p != NULL && strcmp(Hdr_p, "tar") == 0) {
4549 4553 Hdrsz = TARSZ;
4550 4554 FILL(Hdrsz);
4551 4555 if ((hit = read_hdr(TAR)) == NONE) {
4552 4556 Hdrsz = ASCSZ;
4553 4557 break;
4554 4558 }
4555 4559 hit = TAR;
4556 4560 hsize = TARSZ;
4557 4561 break;
4558 4562 }
4559 4563 /*FALLTHROUGH*/
4560 4564 default:
4561 4565 msg(EXT, "Impossible header type.");
4562 4566 } /* Hdr_type */
4563 4567
4564 4568 if (hit == TAR || hit == USTAR) {
4565 4569 Gen.g_nam_p = &nambuf[0];
4566 4570 }
4567 4571
4568 4572 if (hit != NONE) {
4569 4573 FILL(hsize);
4570 4574 goodhdr = 1;
4571 4575 if (Gen.g_filesz < (off_t)0 || Gen.g_namesz < 1)
4572 4576 goodhdr = 0;
4573 4577 if ((hit != USTAR) && (hit != TAR))
4574 4578 if (Gen.g_namesz - 1 > Max_namesz)
4575 4579 goodhdr = 0;
4576 4580 /* TAR and USTAR */
4577 4581 if ((hit == USTAR) || (hit == TAR)) {
4578 4582 if (*Gen.g_nam_p == '\0') { /* tar trailer */
4579 4583 goodhdr = 1;
4580 4584 } else {
4581 4585
4582 4586 G_p = &Gen;
4583 4587 if (G_p->g_cksum !=
4584 4588 cksum(TARTYP, 0, NULL)) {
4585 4589 goodhdr = 0;
4586 4590 msg(ERR,
4587 4591 "Bad header - checksum "
4588 4592 "error.");
4589 4593 }
4590 4594 }
4591 4595 } else if (hit != BAR) { /* binary, -c, ASC and CRC */
4592 4596 if (Gen.g_nlink <= (ulong_t)0)
4593 4597 goodhdr = 0;
4594 4598 if (*(Buffr.b_out_p + hsize - 1) != '\0')
4595 4599 goodhdr = 0;
4596 4600 }
4597 4601 if (!goodhdr) {
4598 4602 hit = NONE;
4599 4603 if (!(Args & OCk))
4600 4604 break;
4601 4605 msg(ERR,
4602 4606 "Corrupt header, file(s) may be lost.");
4603 4607 } else {
4604 4608 FILL(hsize);
4605 4609 }
4606 4610 } /* hit != NONE */
4607 4611 if (hit == NONE) {
4608 4612 Buffr.b_out_p++;
4609 4613 Buffr.b_cnt--;
4610 4614 if (!(Args & OCk))
4611 4615 break;
4612 4616 if (!cnt++)
4613 4617 msg(ERR, "Searching for magic number/header.");
4614 4618 }
4615 4619 } while (hit == NONE);
4616 4620 if (hit == NONE) {
4617 4621 if (Hdr_type == NONE)
4618 4622 msg(EXT, "Not a cpio file, bad header.");
4619 4623 else
4620 4624 msg(EXT, "Bad magic number/header.");
4621 4625 } else if (cnt > 0) {
4622 4626 msg(EPOST, "Re-synchronized on magic number/header.");
4623 4627 }
4624 4628 if (Hdr_type == NONE) {
4625 4629 Hdr_type = hit;
4626 4630 switch (Hdr_type) {
4627 4631 case BIN:
4628 4632 if (bswap)
4629 4633 Args |= BSM;
4630 4634 Hdrsz = HDRSZ;
4631 4635 Max_namesz = CPATH;
4632 4636 Pad_val = HALFWD;
4633 4637 Onecopy = 0;
4634 4638 break;
4635 4639 case CHR:
4636 4640 Hdrsz = CHRSZ;
4637 4641 Max_namesz = CPATH;
4638 4642 Pad_val = 0;
4639 4643 Onecopy = 0;
4640 4644 break;
4641 4645 case ASC:
4642 4646 case CRC:
4643 4647 Hdrsz = ASCSZ;
4644 4648 Max_namesz = APATH;
4645 4649 Pad_val = FULLWD;
4646 4650 Onecopy = 1;
4647 4651 break;
4648 4652 case USTAR:
4649 4653 Hdrsz = TARSZ;
4650 4654 Max_namesz = HNAMLEN - 1;
4651 4655 Pad_val = FULLBK;
4652 4656 Onecopy = 0;
4653 4657 break;
4654 4658 case BAR:
4655 4659 case TAR:
4656 4660 Hdrsz = TARSZ;
4657 4661 Max_namesz = TNAMLEN - 1;
4658 4662 Pad_val = FULLBK;
4659 4663 Onecopy = 0;
4660 4664 break;
4661 4665 default:
4662 4666 msg(EXT, "Impossible header type.");
4663 4667 } /* Hdr_type */
4664 4668 } /* Hdr_type == NONE */
4665 4669 if ((Hdr_type == USTAR) || (Hdr_type == TAR) ||
4666 4670 (Hdr_type == BAR)) { /* TAR, USTAR, BAR */
4667 4671 Gen.g_namesz = 0;
4668 4672 if (Gen.g_nam_p[0] == '\0')
4669 4673 return (0);
4670 4674 else {
4671 4675 preptr = &prebuf[0];
4672 4676 if (*preptr != NULL) {
4673 4677 k = strlen(&prebuf[0]);
4674 4678 if (k < PRESIZ) {
4675 4679 (void) strcpy(&fullnam[0], &prebuf[0]);
4676 4680 j = 0;
4677 4681 fullnam[k++] = '/';
4678 4682 while ((j < NAMSIZ) && (&nambuf[j] !=
4679 4683 '\0')) {
4680 4684 fullnam[k] = nambuf[j];
4681 4685 k++; j++;
4682 4686 }
4683 4687 fullnam[k] = '\0';
4684 4688 } else if (k >= PRESIZ) {
4685 4689 k = 0;
4686 4690 while ((k < PRESIZ) && (prebuf[k] !=
4687 4691 '\0')) {
4688 4692 fullnam[k] = prebuf[k];
4689 4693 k++;
4690 4694 }
4691 4695 fullnam[k++] = '/';
4692 4696 j = 0;
4693 4697 while ((j < NAMSIZ) && (nambuf[j] !=
4694 4698 '\0')) {
4695 4699 fullnam[k] = nambuf[j];
4696 4700 k++; j++;
4697 4701 }
4698 4702 fullnam[k] = '\0';
4699 4703 }
4700 4704 Gen.g_nam_p = &fullnam[0];
4701 4705 } else
4702 4706 Gen.g_nam_p = &nambuf[0];
4703 4707
4704 4708 /*
4705 4709 * initialize the buffer so that the prefix will not
4706 4710 * applied to the next entry in the archive
4707 4711 */
4708 4712 (void) memset(prebuf, 0, sizeof (prebuf));
4709 4713 }
4710 4714 } else if (Hdr_type != BAR) {
4711 4715 (void) memcpy(Gen.g_nam_p, Buffr.b_out_p + Hdrsz, Gen.g_namesz);
4712 4716 if (!(strcmp(Gen.g_nam_p, "TRAILER!!!")))
4713 4717 return (0);
4714 4718 }
4715 4719 offset = ((hsize + Pad_val) & ~Pad_val);
4716 4720 FILL(offset + Hdrsz);
4717 4721 Thdr_p = (union tblock *)Buffr.b_out_p;
4718 4722 Buffr.b_out_p += offset;
4719 4723 Buffr.b_cnt -= (off_t)offset;
4720 4724 ftype = Gen.g_mode & Ftype;
4721 4725
4722 4726 #if defined(O_XATTR)
4723 4727 /* extended attribute support */
4724 4728 if (((Gen.g_mode & S_IFMT) == _XATTR_CPIO_MODE) ||
4725 4729 ((Hdr_type == USTAR || Hdr_type == TAR) &&
4726 4730 Thdr_p->tbuf.t_typeflag == _XATTR_HDRTYPE)) {
4727 4731 char *aname;
4728 4732 char *attrparent = NULL;
4729 4733 char *attrpath = NULL;
4730 4734 char *tapath;
4731 4735 char *taname;
4732 4736
4733 4737 if (xattrp != NULL) {
4734 4738 if (xattrbadhead) {
4735 4739 free(xattrhead);
4736 4740 xattrp = NULL;
4737 4741 xattr_linkp = NULL;
4738 4742 xattrhead = NULL;
4739 4743 return (1);
4740 4744 }
4741 4745
4742 4746 /*
4743 4747 * At this point, the attribute path contains
4744 4748 * the path to the attribute rooted at the hidden
4745 4749 * attribute directory of the base file. This can
4746 4750 * be a simple attribute or extended attribute name,
4747 4751 * or it can be something like <attr>/<sys attr> if
4748 4752 * we are processing a system attribute of an attribute.
4749 4753 * Determine the attribute name and attribute parent
4750 4754 * (if there is one). When we are processing a simple
4751 4755 * attribute or extended attribute name, the attribute
4752 4756 * parent will be set to NULL. When we are processing
4753 4757 * something like <attr>/<sys attr>, the attribute
4754 4758 * parent will be contain <attr>, and the attribute
4755 4759 * name will contain <sys attr>.
4756 4760 */
4757 4761 tapath = xattrp->h_names +
4758 4762 strlen(xattrp->h_names) + 1;
4759 4763 attrpath = e_strdup(E_EXIT, tapath);
4760 4764 if ((taname = strpbrk(tapath, "/")) != NULL) {
4761 4765 aname = taname + 1;
4762 4766 *taname = '\0';
4763 4767 attrparent = tapath;
4764 4768 } else {
4765 4769 aname = tapath;
4766 4770 }
4767 4771
4768 4772 Gen.g_rw_sysattr = is_sysattr(aname);
4769 4773 Gen.g_baseparent_fd = attr_baseparent_fd;
4770 4774
4771 4775 if (Gen.g_attrfnam_p != NULL) {
4772 4776 free(Gen.g_attrfnam_p);
4773 4777 Gen.g_attrfnam_p = NULL;
4774 4778 }
4775 4779 if (Gen.g_attrnam_p != NULL) {
4776 4780 free(Gen.g_attrnam_p);
4777 4781 Gen.g_attrnam_p = NULL;
4778 4782 }
4779 4783 if (Gen.g_attrparent_p != NULL) {
4780 4784 free(Gen.g_attrparent_p);
4781 4785 Gen.g_attrparent_p = NULL;
4782 4786 }
4783 4787 if (Gen.g_attrpath_p != NULL) {
4784 4788 free(Gen.g_attrpath_p);
4785 4789 Gen.g_attrpath_p = NULL;
4786 4790 }
4787 4791 if (Renam_p && Renam_p[0] != '\0') {
4788 4792 Gen.g_attrfnam_p = e_strdup(E_EXIT, Renam_p);
4789 4793 } else {
4790 4794 Gen.g_attrfnam_p = e_strdup(E_EXIT,
4791 4795 xattrp->h_names);
4792 4796 }
4793 4797 Gen.g_attrnam_p = e_strdup(E_EXIT, aname);
4794 4798
4795 4799 if (attrparent != NULL) {
4796 4800 if (Renam_attr_p && Renam_attr_p[0] != '\0') {
4797 4801 size_t apathlen = strlen(attrparent) +
4798 4802 strlen(aname) + 2;
4799 4803 Gen.g_attrparent_p = e_strdup(E_EXIT,
4800 4804 Renam_attr_p);
4801 4805 Gen.g_attrpath_p = e_zalloc(E_EXIT,
4802 4806 apathlen);
4803 4807 (void) snprintf(Gen.g_attrpath_p,
4804 4808 apathlen, "%s/%s", Renam_attr_p,
4805 4809 aname);
4806 4810 (void) free(attrparent);
4807 4811 (void) free(attrpath);
4808 4812 } else {
4809 4813 Gen.g_attrparent_p = attrparent;
4810 4814 Gen.g_attrpath_p = attrpath;
4811 4815 }
4812 4816 } else {
4813 4817 Gen.g_attrpath_p = attrpath;
4814 4818 }
4815 4819
4816 4820 if (xattr_linkp != NULL) {
4817 4821 if (Gen.g_linktoattrfnam_p != NULL) {
4818 4822 free(Gen.g_linktoattrfnam_p);
4819 4823 Gen.g_linktoattrfnam_p = NULL;
4820 4824 }
4821 4825 if (Gen.g_linktoattrnam_p != NULL) {
4822 4826 free(Gen.g_linktoattrnam_p);
4823 4827 Gen.g_linktoattrnam_p = NULL;
4824 4828 }
4825 4829 if (Renam_attr_p && Renam_attr_p[0] != '\0') {
4826 4830 Gen.g_linktoattrfnam_p = e_strdup(
4827 4831 E_EXIT, Renam_attr_p);
4828 4832 } else {
4829 4833 Gen.g_linktoattrfnam_p = e_strdup(
4830 4834 E_EXIT, xattr_linkp->h_names);
4831 4835 }
4832 4836 Gen.g_linktoattrnam_p = e_strdup(E_EXIT,
4833 4837 aname);
4834 4838 xattr_linkp = NULL;
4835 4839 }
4836 4840 if (Hdr_type != USTAR && Hdr_type != TAR) {
4837 4841 Gen.g_mode = Gen.g_mode & (~_XATTR_CPIO_MODE);
4838 4842 Gen.g_mode |= attrmode(xattrp->h_typeflag);
4839 4843 } else if (Hdr_type == USTAR || Hdr_type == TAR) {
4840 4844 Thdr_p->tbuf.t_typeflag = xattrp->h_typeflag;
4841 4845 }
4842 4846
4843 4847 ftype = Gen.g_mode & Ftype;
4844 4848 Adir = ftype == S_IFDIR;
4845 4849 Aspec = (ftype == S_IFBLK || ftype == S_IFCHR ||
4846 4850 ftype == S_IFIFO || ftype == S_IFSOCK);
4847 4851
4848 4852 if (Gen.g_attrnam_p[0] == '.' &&
4849 4853 Gen.g_attrnam_p[1] == '\0' &&
4850 4854 xattrp->h_typeflag == DIRTYPE) {
4851 4855 Hiddendir = 1;
4852 4856 } else {
4853 4857 Hiddendir = 0;
4854 4858 }
4855 4859
4856 4860 free(xattrhead);
4857 4861 xattrhead = NULL;
4858 4862 xattrp = NULL;
4859 4863 } else {
4860 4864 if (xattrbadhead == 0) {
4861 4865 (void) read_xattr_hdr();
4862 4866 return (2);
4863 4867 }
4864 4868 }
4865 4869 } else {
4866 4870 Hiddendir = 0;
4867 4871 }
4868 4872 #endif /* O_XATTR */
4869 4873
4870 4874 /* acl support: grab acl info */
4871 4875 if ((Gen.g_mode == SECMODE) || ((Hdr_type == USTAR ||
4872 4876 Hdr_type == TAR) && Thdr_p->tbuf.t_typeflag == 'A')) {
4873 4877 /* this is an ancillary file */
4874 4878 off_t bytes;
4875 4879 char *secp;
4876 4880 int pad;
4877 4881 int cnt;
4878 4882 char *tp;
4879 4883 int attrsize;
4880 4884
4881 4885 if (Pflag) {
4882 4886 bytes = Gen.g_filesz;
4883 4887 secp = e_zalloc(E_EXIT, (uint_t)bytes);
4884 4888 tp = secp;
4885 4889
4886 4890 while (bytes > 0) {
4887 4891 cnt = (int)(bytes > CPIOBSZ) ? CPIOBSZ : bytes;
4888 4892 FILL(cnt);
4889 4893 (void) memcpy(tp, Buffr.b_out_p, cnt);
4890 4894 tp += cnt;
4891 4895 Buffr.b_out_p += cnt;
4892 4896 Buffr.b_cnt -= (off_t)cnt;
4893 4897 bytes -= (off_t)cnt;
4894 4898 }
4895 4899
4896 4900 pad = (Pad_val + 1 - (Gen.g_filesz & Pad_val)) &
4897 4901 Pad_val;
4898 4902 if (pad != 0) {
4899 4903 FILL(pad);
4900 4904 Buffr.b_out_p += pad;
4901 4905 Buffr.b_cnt -= (off_t)pad;
4902 4906 }
4903 4907
4904 4908 /* got all attributes in secp */
4905 4909 tp = secp;
4906 4910 do {
4907 4911 attr = (struct sec_attr *)tp;
4908 4912 switch (attr->attr_type) {
4909 4913 case UFSD_ACL:
4910 4914 case ACE_ACL:
4911 4915 (void) sscanf(attr->attr_len, "%7lo",
4912 4916 (ulong_t *)&aclcnt);
4913 4917 /* header is 8 */
4914 4918 attrsize = 8 +
4915 4919 strlen(&attr->attr_info[0])
4916 4920 + 1;
4917 4921
4918 4922 error =
4919 4923 acl_fromtext(&attr->attr_info[0],
4920 4924 &aclp);
4921 4925
4922 4926 if (error != 0) {
4923 4927 msg(ERR,
4924 4928 "aclfromtext failed: %s",
4925 4929 acl_strerror(error));
4926 4930 bytes -= attrsize;
4927 4931 break;
4928 4932 }
4929 4933
4930 4934 if (aclcnt != acl_cnt(aclp)) {
4931 4935 msg(ERR, "acl count error");
4932 4936 bytes -= attrsize;
4933 4937 break;
4934 4938 }
4935 4939 bytes -= attrsize;
4936 4940 break;
4937 4941
4938 4942 /* SunFed case goes here */
4939 4943
4940 4944 default:
4941 4945 msg(EXT, "unrecognized attr type");
4942 4946 break;
4943 4947 }
4944 4948 /* next attributes */
4945 4949 tp += attrsize;
4946 4950 } while (bytes > 0);
4947 4951 free(secp);
4948 4952 } else {
4949 4953 /* skip security info */
4950 4954 G_p = &Gen;
4951 4955 data_in(P_SKIP);
4952 4956 }
4953 4957 /*
4954 4958 * We already got the file content, dont call file_in()
4955 4959 * when return. The new return code(2) is used to
4956 4960 * indicate that.
4957 4961 */
4958 4962 VERBOSE((Args & OCt), Gen.g_nam_p);
4959 4963 return (2);
4960 4964 } /* acl */
4961 4965
4962 4966 /*
4963 4967 * Sparse file support
4964 4968 * Read header of holesdata to get original file size.
4965 4969 * This is necessary because ckname() or file_in() shows file size
4966 4970 * with OCt before data_in() extracts the holesdata. data_in()
4967 4971 * actually doesn't extract the holesdata since proc_mode will be
4968 4972 * P_SKIP in the OCt mode.
4969 4973 */
4970 4974 if ((Hdr_type == CHR || Hdr_type == ASC) &&
4971 4975 S_ISSPARSE(Gen.g_mode) && Gen.g_filesz > MIN_HOLES_HDRSIZE) {
4972 4976 char holesdata[MIN_HOLES_HDRSIZE + 1];
4973 4977
4974 4978 FILL(MIN_HOLES_HDRSIZE);
4975 4979 (void) memcpy(holesdata, Buffr.b_out_p, MIN_HOLES_HDRSIZE);
4976 4980 holesdata[MIN_HOLES_HDRSIZE] = '\0';
4977 4981
4978 4982 Gen.g_holes = read_holes_header(holesdata, Gen.g_filesz);
4979 4983 if (Gen.g_holes == NULL) {
4980 4984 msg(EXT, "invalid sparse file information");
4981 4985 } else {
4982 4986 Buffr.b_out_p += MIN_HOLES_HDRSIZE;
4983 4987 Buffr.b_cnt -= MIN_HOLES_HDRSIZE;
4984 4988 }
4985 4989 }
4986 4990
4987 4991 Adir = (ftype == S_IFDIR);
4988 4992 Aspec = (ftype == S_IFBLK || ftype == S_IFCHR || ftype == S_IFIFO ||
4989 4993 ftype == S_IFSOCK);
4990 4994
4991 4995 /*
4992 4996 * Skip any trailing slashes
4993 4997 */
4994 4998 chop_endslashes(Gen.g_nam_p);
4995 4999 return (1);
4996 5000 }
4997 5001
4998 5002 /*
4999 5003 * getname: Get file names for inclusion in the archive. When end of file
5000 5004 * on the input stream of file names is reached, flush the link buffer out.
5001 5005 * For each filename, remove leading "./"s and multiple "/"s, and remove
5002 5006 * any trailing newline "\n". Finally, verify the existence of the file,
5003 5007 * and call creat_hdr() to fill in the gen_hdr structure.
5004 5008 */
5005 5009
5006 5010 static int
5007 5011 getname(void)
5008 5012 {
5009 5013 int goodfile = 0, lastchar, err;
5010 5014 char *s;
5011 5015 char *dir;
5012 5016
5013 5017 Gen.g_nam_p = Nam_p;
5014 5018 Hiddendir = 0;
5015 5019
5016 5020 while (!goodfile) {
5017 5021 err = 0;
5018 5022
5019 5023 while ((s = fgets(Gen.g_nam_p, APATH+1, In_p)) != NULL) {
5020 5024 lastchar = strlen(s) - 1;
5021 5025 issymlink = 0;
5022 5026
5023 5027 if (s[lastchar] != '\n') {
5024 5028 if (lastchar == APATH - 1) {
5025 5029 if (!err) {
5026 5030 msg(ERR,
5027 5031 "%s name too long.",
5028 5032 Nam_p);
5029 5033 }
5030 5034 goodfile = 0;
5031 5035 err = 1;
5032 5036 } else {
5033 5037 break;
5034 5038 }
5035 5039 } else {
5036 5040 s[lastchar] = '\0';
5037 5041 break;
5038 5042 }
5039 5043 }
5040 5044
5041 5045 if (s == NULL) {
5042 5046 if (Gen.g_dirfd != -1) {
5043 5047 (void) close(Gen.g_dirfd);
5044 5048 Gen.g_dirfd = -1;
5045 5049 }
5046 5050 if (Onecopy && (Args & OCo)) {
5047 5051 flush_lnks();
5048 5052 }
5049 5053 return (0);
5050 5054 }
5051 5055
5052 5056 while (*Gen.g_nam_p == '.' && Gen.g_nam_p[1] == '/') {
5053 5057 Gen.g_nam_p += 2;
5054 5058 while (*Gen.g_nam_p == '/')
5055 5059 Gen.g_nam_p++;
5056 5060 }
5057 5061
5058 5062 /*
5059 5063 * Skip any trailing slashes
5060 5064 */
5061 5065 chop_endslashes(Gen.g_nam_p);
5062 5066
5063 5067 /*
5064 5068 * Figure out parent directory
5065 5069 */
5066 5070
5067 5071 if (Gen.g_attrnam_p != NULL) {
5068 5072 if (Gen.g_dirfd != -1) {
5069 5073 (void) close(Gen.g_dirfd);
5070 5074 }
5071 5075 Gen.g_dirfd = attropen(Gen.g_attrfnam_p, ".", O_RDONLY);
5072 5076 if (Gen.g_dirfd == -1) {
5073 5077 msg(ERRN,
5074 5078 "Cannot open attribute directory"
5075 5079 " of file %s", Gen.g_attrfnam_p);
5076 5080 continue;
5077 5081 }
5078 5082 } else {
5079 5083 #ifdef O_XATTR
5080 5084 char dirpath[PATH_MAX];
5081 5085
5082 5086 get_parent(Gen.g_nam_p, dirpath);
5083 5087 if (Atflag || SysAtflag) {
5084 5088 dir = dirpath;
5085 5089 if (Gen.g_dirfd != -1) {
5086 5090 (void) close(Gen.g_dirfd);
5087 5091 }
5088 5092 Gen.g_dirfd = open(dir, O_RDONLY);
5089 5093 if (Gen.g_dirfd == -1) {
5090 5094 msg(ERRN,
5091 5095 "Cannot open directory %s", dir);
5092 5096 continue;
5093 5097 }
5094 5098 } else {
5095 5099 /*
5096 5100 * g_dirpath is the pathname cache maintaining
5097 5101 * the dirname which is currently opened.
5098 5102 * We first check the g_dirpath to see if the
5099 5103 * given dirname matches. If so, we don't need
5100 5104 * to open the dir, but we can use the g_dirfd
5101 5105 * as is if it is still available.
5102 5106 */
5103 5107 dir = NULL;
5104 5108 if (Gen.g_dirpath == NULL ||
5105 5109 Gen.g_dirfd == -1) {
5106 5110 /*
5107 5111 * It's the first time or it has
5108 5112 * all gone.
5109 5113 */
5110 5114 dir = e_strdup(E_EXIT, dirpath);
5111 5115 } else {
5112 5116 if (strcmp(Gen.g_dirpath,
5113 5117 dirpath) != 0) {
5114 5118 /* different directory */
5115 5119 dir = e_strdup(E_EXIT, dirpath);
5116 5120 }
5117 5121 }
5118 5122 if (dir != NULL) {
5119 5123 /*
5120 5124 * We need to open the new directory.
5121 5125 * discard the pathname and dirfd
5122 5126 * for the previous directory.
5123 5127 */
5124 5128 if (Gen.g_dirpath != NULL) {
5125 5129 free(Gen.g_dirpath);
5126 5130 Gen.g_dirpath = NULL;
5127 5131 }
5128 5132 if (Gen.g_dirfd != -1) {
5129 5133 (void) close(Gen.g_dirfd);
5130 5134 }
5131 5135 /* open the new dir */
5132 5136 Gen.g_dirfd = open(dir, O_RDONLY);
5133 5137 if (Gen.g_dirfd == -1) {
5134 5138 msg(ERRN, "Cannot open "
5135 5139 "directory %s", dir);
5136 5140 continue;
5137 5141 }
5138 5142 Gen.g_dirpath = dir;
5139 5143 }
5140 5144 }
5141 5145 #else
5142 5146 Gen.g_dirfd = -1;
5143 5147 #endif
5144 5148 }
5145 5149
5146 5150 /* creat_hdr checks for USTAR filename length */
5147 5151
5148 5152 if (Hdr_type != USTAR && strlen(Gen.g_nam_p) >
5149 5153 Max_namesz) {
5150 5154 if (!err) {
5151 5155 msg(ERR, "%s%s%s name too long.",
5152 5156 (Gen.g_attrnam_p == NULL) ?
5153 5157 Nam_p : Gen.g_attrfnam_p,
5154 5158 (Gen.g_attrnam_p == NULL) ?
5155 5159 "" : Gen.g_rw_sysattr ?
5156 5160 gettext(" System Attribute ") :
5157 5161 gettext(" Attribute "),
5158 5162 (Gen.g_attrnam_p == NULL) ?
5159 5163 "" : Gen.g_attrnam_p);
5160 5164 }
5161 5165 goodfile = 0;
5162 5166 err = 1;
5163 5167 }
5164 5168
5165 5169 if (err) {
5166 5170 continue;
5167 5171 } else {
5168 5172 G_p = &Gen;
5169 5173 if (!LSTAT(Gen.g_dirfd, Gen.g_nam_p, &SrcSt)) {
5170 5174 goodfile = 1;
5171 5175
5172 5176 if ((SrcSt.st_mode & Ftype) == S_IFLNK) {
5173 5177 issymlink = 1;
5174 5178
5175 5179 if ((Args & OCL)) {
5176 5180 errno = 0;
5177 5181 if (STAT(Gen.g_dirfd,
5178 5182 G_p->g_nam_p,
5179 5183 &SrcSt) < 0) {
5180 5184 msg(ERRN,
5181 5185 "Cannot follow"
5182 5186 " \"%s%s%s\"",
5183 5187 (Gen.g_attrnam_p ==
5184 5188 NULL) ?
5185 5189 Gen.g_nam_p :
5186 5190 Gen.g_attrfnam_p,
5187 5191 (Gen.g_attrnam_p ==
5188 5192 NULL) ? "" :
5189 5193 Gen.g_rw_sysattr ?
5190 5194 gettext(
5191 5195 " System "
5192 5196 "Attribute ") :
5193 5197 gettext(
5194 5198 " Attribute "),
5195 5199 (Gen.g_attrnam_p ==
5196 5200 NULL) ? "" :
5197 5201 Gen.g_attrnam_p);
5198 5202 goodfile = 0;
5199 5203 }
5200 5204 }
5201 5205 }
5202 5206
5203 5207 if (Use_old_stat) {
5204 5208 OldSt = convert_to_old_stat(&SrcSt,
5205 5209 Gen.g_nam_p, Gen.g_attrnam_p);
5206 5210
5207 5211 if (OldSt == NULL) {
5208 5212 goodfile = 0;
5209 5213 }
5210 5214 }
5211 5215 } else {
5212 5216 msg(ERRN,
5213 5217 "Error with fstatat() of \"%s%s%s\"",
5214 5218 (Gen.g_attrnam_p == NULL) ?
5215 5219 Gen.g_nam_p : Gen.g_attrfnam_p,
5216 5220 (Gen.g_attrnam_p == NULL) ? "" :
5217 5221 Gen.g_rw_sysattr ?
5218 5222 gettext(" System Attribute ") :
5219 5223 gettext(" Attribute "),
5220 5224 (Gen.g_attrnam_p == NULL) ?
5221 5225 "" : Gen.g_attrnam_p);
5222 5226 }
5223 5227 }
5224 5228 }
5225 5229
5226 5230 /*
5227 5231 * Get ACL info: dont bother allocating space if there are only
5228 5232 * standard permissions, i.e. ACL count < 4
5229 5233 */
5230 5234 if ((SrcSt.st_mode & Ftype) != S_IFLNK && Pflag) {
5231 5235 if (acl_get(Gen.g_nam_p, ACL_NO_TRIVIAL, &aclp) != 0)
5232 5236 msg(ERRN, "Error with acl() of \"%s\"", Gen.g_nam_p);
5233 5237 }
5234 5238 /* else: only traditional permissions, so proceed as usual */
5235 5239 if (creat_hdr())
5236 5240 return (1);
5237 5241 else return (2);
5238 5242 }
5239 5243
5240 5244 /*
5241 5245 * getpats: Save any filenames/patterns specified as arguments.
5242 5246 * Read additional filenames/patterns from the file specified by the
5243 5247 * user. The filenames/patterns must occur one per line.
5244 5248 */
5245 5249
5246 5250 static void
5247 5251 getpats(int largc, char **largv)
5248 5252 {
5249 5253 char **t_pp;
5250 5254 size_t len;
5251 5255 unsigned numpat = largc, maxpat = largc + 2;
5252 5256
5253 5257 Pat_pp = e_zalloc(E_EXIT, maxpat * sizeof (char *));
5254 5258 t_pp = Pat_pp;
5255 5259 while (*largv) {
5256 5260 *t_pp = e_zalloc(E_EXIT, strlen(*largv) + 1);
5257 5261 (void) strcpy(*t_pp, *largv);
5258 5262 t_pp++;
5259 5263 largv++;
5260 5264 }
5261 5265 while (fgets(Nam_p, Max_namesz + 1, Ef_p) != NULL) {
5262 5266 if (numpat == maxpat - 1) {
5263 5267 maxpat += 10;
5264 5268 Pat_pp = e_realloc(E_EXIT, Pat_pp,
5265 5269 maxpat * sizeof (char *));
5266 5270 t_pp = Pat_pp + numpat;
5267 5271 }
5268 5272 len = strlen(Nam_p); /* includes the \n */
5269 5273 *(Nam_p + len - 1) = '\0'; /* remove the \n */
5270 5274 *t_pp = e_zalloc(E_EXIT, len);
5271 5275 (void) strcpy(*t_pp, Nam_p);
5272 5276 t_pp++;
5273 5277 numpat++;
5274 5278 }
5275 5279 *t_pp = NULL;
5276 5280 }
5277 5281
5278 5282 static void
5279 5283 ioerror(int dir)
5280 5284 {
5281 5285 int t_errno;
5282 5286
5283 5287 t_errno = errno;
5284 5288 errno = 0;
5285 5289 if (fstat(Archive, &ArchSt) < 0)
5286 5290 msg(EXTN, "Error during stat() of archive");
5287 5291 errno = t_errno;
5288 5292 if ((ArchSt.st_mode & Ftype) != S_IFCHR) {
5289 5293 if (dir) {
5290 5294 if (errno == EFBIG)
5291 5295 msg(EXT, "ulimit reached for output file.");
5292 5296 else if (errno == ENOSPC)
5293 5297 msg(EXT, "No space left for output file.");
5294 5298 else
5295 5299 msg(EXTN, "I/O error - cannot continue");
5296 5300 } else
5297 5301 msg(EXT, "Unexpected end-of-file encountered.");
5298 5302 } else
5299 5303 msg(EXTN, "\007I/O error on \"%s\"", dir ? "output" : "input");
5300 5304 }
5301 5305
5302 5306 /*
5303 5307 * matched: Determine if a filename matches the specified pattern(s). If the
5304 5308 * pattern is matched (the second return), return 0 if -f was specified, else
5305 5309 * return != 0. If the pattern is not matched (the first and third
5306 5310 * returns), return 0 if -f was not specified, else return != 0.
5307 5311 */
5308 5312
5309 5313 static int
5310 5314 matched(void)
5311 5315 {
5312 5316 char *str_p = G_p->g_nam_p;
5313 5317 char **pat_pp = Pat_pp;
5314 5318 int negatep, result;
5315 5319
5316 5320 /*
5317 5321 * Check for attribute
5318 5322 */
5319 5323 if (G_p->g_attrfnam_p != NULL)
5320 5324 str_p = G_p->g_attrfnam_p;
5321 5325
5322 5326 for (pat_pp = Pat_pp; *pat_pp; pat_pp++) {
5323 5327 negatep = (**pat_pp == '!');
5324 5328
5325 5329 result = fnmatch(negatep ? (*pat_pp+1) : *pat_pp, str_p, 0);
5326 5330
5327 5331 if (result != 0 && result != FNM_NOMATCH) {
5328 5332 msg(POST, "error matching file %s with pattern"
5329 5333 " %s\n", str_p, *pat_pp);
5330 5334 return (Args & OCf);
5331 5335 }
5332 5336
5333 5337 if ((result == 0 && ! negatep) ||
5334 5338 (result == FNM_NOMATCH && negatep)) {
5335 5339 /* match occurred */
5336 5340 return (!(Args & OCf));
5337 5341 }
5338 5342 }
5339 5343 return (Args & OCf); /* not matched */
5340 5344 }
5341 5345
5342 5346 /*
5343 5347 * missdir: Create missing directories for files.
5344 5348 * (Possible future performance enhancement, if missdir is called, we know
5345 5349 * that at least the very last directory of the path does not exist, therefore,
5346 5350 * scan the path from the end
5347 5351 */
5348 5352
5349 5353 static int
5350 5354 missdir(char *nam_p)
5351 5355 {
5352 5356 char *c_p;
5353 5357 int cnt = 2;
5354 5358 char *lastp;
5355 5359
5356 5360 if (*(c_p = nam_p) == '/') /* skip over 'root slash' */
5357 5361 c_p++;
5358 5362
5359 5363 lastp = c_p + strlen(nam_p) - 1;
5360 5364 if (*lastp == '/')
5361 5365 *lastp = '\0';
5362 5366
5363 5367 for (; *c_p; ++c_p) {
5364 5368 if (*c_p == '/') {
5365 5369 *c_p = '\0';
5366 5370 if (stat(nam_p, &DesSt) < 0) {
5367 5371 if (Args & OCd) {
5368 5372 cnt = mkdir(nam_p, Def_mode);
5369 5373 if (cnt != 0) {
5370 5374 *c_p = '/';
5371 5375 return (cnt);
5372 5376 }
5373 5377 } else {
5374 5378 msg(ERR, "Missing -d option.");
5375 5379 *c_p = '/';
5376 5380 return (-1);
5377 5381 }
5378 5382 }
5379 5383 *c_p = '/';
5380 5384 }
5381 5385 }
5382 5386 if (cnt == 2) /* the file already exists */
5383 5387 cnt = 0;
5384 5388 return (cnt);
5385 5389 }
5386 5390
5387 5391 /*
5388 5392 * mklong: Convert two shorts into one long. For VAX, Interdata ...
5389 5393 */
5390 5394
5391 5395 static long
5392 5396 mklong(short v[])
5393 5397 {
5394 5398
5395 5399 union swpbuf swp_b;
5396 5400
5397 5401 swp_b.s_word = 1;
5398 5402 if (swp_b.s_byte[0]) {
5399 5403 swp_b.s_half[0] = v[1];
5400 5404 swp_b.s_half[1] = v[0];
5401 5405 } else {
5402 5406 swp_b.s_half[0] = v[0];
5403 5407 swp_b.s_half[1] = v[1];
5404 5408 }
5405 5409 return (swp_b.s_word);
5406 5410 }
5407 5411
5408 5412 /*
5409 5413 * mkshort: Convert a long into 2 shorts, for VAX, Interdata ...
5410 5414 */
5411 5415
5412 5416 static void
5413 5417 mkshort(short sval[], long v)
5414 5418 {
5415 5419 union swpbuf *swp_p, swp_b;
5416 5420
5417 5421 /* LINTED alignment */
5418 5422 swp_p = (union swpbuf *)sval;
5419 5423 swp_b.s_word = 1;
5420 5424 if (swp_b.s_byte[0]) {
5421 5425 swp_b.s_word = v;
5422 5426 swp_p->s_half[0] = swp_b.s_half[1];
5423 5427 swp_p->s_half[1] = swp_b.s_half[0];
5424 5428 } else {
5425 5429 swp_b.s_word = v;
5426 5430 swp_p->s_half[0] = swp_b.s_half[0];
5427 5431 swp_p->s_half[1] = swp_b.s_half[1];
5428 5432 }
5429 5433 }
5430 5434
5431 5435 /*
5432 5436 * msg: Print either a message (no error) (POST), an error message with or
5433 5437 * without the errno (ERRN or ERR), or print an error message with or without
5434 5438 * the errno and exit (EXTN or EXT).
5435 5439 */
5436 5440 void
5437 5441 msg(int severity, const char *fmt, ...)
5438 5442 {
5439 5443 FILE *file_p;
5440 5444 va_list ap;
5441 5445
5442 5446 if ((Args & OCV) && Verbcnt) { /* clear current line of dots */
5443 5447 (void) fputc('\n', Out_p);
5444 5448 Verbcnt = 0;
5445 5449 }
5446 5450 va_start(ap, fmt);
5447 5451 if (severity == POST)
5448 5452 file_p = Out_p;
5449 5453 else
5450 5454 if (severity == EPOST)
5451 5455 file_p = Err_p;
5452 5456 else {
5453 5457 file_p = Err_p;
5454 5458 Error_cnt++;
5455 5459 }
5456 5460 (void) fflush(Out_p);
5457 5461 (void) fflush(Err_p);
5458 5462 if ((severity != POST) && (severity != EPOST))
5459 5463 (void) fprintf(file_p, "cpio: ");
5460 5464
5461 5465 /* gettext replaces version of string */
5462 5466
5463 5467 (void) vfprintf(file_p, gettext(fmt), ap);
5464 5468 if (severity == ERRN || severity == EXTN) {
5465 5469 if (G_p && (G_p->g_attrnam_p != NULL) && G_p->g_rw_sysattr) {
5466 5470 if (errno == EPERM) {
5467 5471 (void) fprintf(file_p, ", errno %d, %s", errno,
5468 5472 gettext("insufficient privileges\n"));
5469 5473 } else if (errno == EINVAL) {
5470 5474 (void) fprintf(file_p, ", errno %d, %s",
5471 5475 errno, gettext(
5472 5476 "unsupported on underlying file system\n"));
5473 5477 } else {
5474 5478 (void) fprintf(file_p, ", errno %d, ", errno);
5475 5479 perror("");
5476 5480 }
5477 5481 } else {
5478 5482 (void) fprintf(file_p, ", errno %d, ", errno);
5479 5483 perror("");
5480 5484 }
5481 5485 } else
5482 5486 (void) fprintf(file_p, "\n");
5483 5487 (void) fflush(file_p);
5484 5488 va_end(ap);
5485 5489 if (severity == EXT || severity == EXTN) {
5486 5490 (void) fprintf(file_p, gettext("%d errors\n"), Error_cnt);
5487 5491 exit(EXIT_CODE);
5488 5492 }
5489 5493 }
5490 5494
5491 5495 /*
5492 5496 * openout: Open files for output and set all necessary information.
5493 5497 * If the u option is set (unconditionally overwrite existing files),
5494 5498 * and the current file exists, get a temporary file name from mktemp(3C),
5495 5499 * link the temporary file to the existing file, and remove the existing file.
5496 5500 * Finally either creat(2), mkdir(2) or mknod(2) as appropriate.
5497 5501 *
5498 5502 */
5499 5503
5500 5504 static int
5501 5505 openout(int dirfd)
5502 5506 {
5503 5507 char *nam_p;
5504 5508 int cnt, result;
5505 5509
5506 5510 Do_rename = 0; /* creat_tmp() may reset this */
5507 5511
5508 5512 if (G_p->g_attrnam_p != NULL) {
5509 5513 nam_p = G_p->g_attrnam_p;
5510 5514 } else {
5511 5515 if (Args & OCp) {
5512 5516 nam_p = Fullnam_p;
5513 5517 } else {
5514 5518 nam_p = G_p->g_nam_p;
5515 5519 }
5516 5520 }
5517 5521
5518 5522
5519 5523 if ((Max_filesz != RLIM_INFINITY) &&
5520 5524 (Max_filesz < (G_p->g_filesz >> 9))) {
5521 5525 /* ... divided by 512 ... */
5522 5526 msg(ERR, "Skipping \"%s%s%s\": exceeds ulimit by %lld bytes",
5523 5527 (G_p->g_attrnam_p == NULL) ? nam_p : G_p->g_attrfnam_p,
5524 5528 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
5525 5529 gettext(" System Attribute ") : gettext(" Attribute "),
5526 5530 (G_p->g_attrnam_p == NULL) ? "" : nam_p,
5527 5531 (off_t)(G_p->g_filesz - (Max_filesz << 9)));
5528 5532 return (-1);
5529 5533 }
5530 5534
5531 5535 if (LSTAT(dirfd, nam_p, &DesSt) == 0) {
5532 5536 /*
5533 5537 * A file by the same name exists. Move it to a temporary
5534 5538 * file unless it's a system attribute file. If we are
5535 5539 * restoring a system attribute file on a file system that
5536 5540 * supports system attributes, then the system attribute file
5537 5541 * will already exist (a default system attribute file will
5538 5542 * get created when the file it is associated with is created).
5539 5543 * If we create a temporary system attribute file, we can't
5540 5544 * overwrite the existing system attribute file using
5541 5545 * renameat(). In addition, only system attributes can exist
5542 5546 * for an attribute of a file, therefore, a temporary file
5543 5547 * cannot be created for a system attribute of an attribute.
5544 5548 * Thus, when restoring a system attribute, we won't move it
5545 5549 * to a temporary file, but will attempt to process it as if
5546 5550 * it didn't already exist.
5547 5551 */
5548 5552
5549 5553 #if defined(_PC_SATTR_ENABLED)
5550 5554 if (G_p->g_rw_sysattr == 0)
5551 5555 #endif /* _PC_SATTR_ENABLED */
5552 5556 if (creat_tmp(nam_p) < 0) {
5553 5557 /*
5554 5558 * We weren't able to create the temp file.
5555 5559 * Report failure.
5556 5560 */
5557 5561
5558 5562 return (-1);
5559 5563 }
5560 5564 }
5561 5565
5562 5566 if (Do_rename) {
5563 5567 /* nam_p was changed by creat_tmp() above. */
5564 5568
5565 5569 if (Args & OCp) {
5566 5570 if (G_p->g_attrnam_p != NULL) {
5567 5571 nam_p = Attrfile_p;
5568 5572 } else {
5569 5573 nam_p = Fullnam_p;
5570 5574 }
5571 5575 } else {
5572 5576 nam_p = G_p->g_nam_p;
5573 5577 }
5574 5578 }
5575 5579
5576 5580 /*
5577 5581 * This pile tries to create the file directly, and, if there is a
5578 5582 * problem, creates missing directories, and then tries to create the
5579 5583 * file again. Two strikes and you're out.
5580 5584 *
5581 5585 * On XATTR system, the directory has already been created by
5582 5586 * open_dirfd(), so error shouldn't happen in the loop. However,
5583 5587 * on non-XATTR system, symlink/open may fail with ENOENT. In such
5584 5588 * case, we go to create missing directories.
5585 5589 */
5586 5590
5587 5591 cnt = 0;
5588 5592
5589 5593 do {
5590 5594 errno = 0;
5591 5595
5592 5596 if (Hdr_type == TAR && Thdr_p->tbuf.t_typeflag == SYMTYPE) {
5593 5597 /* The archive file is a TAR symlink. */
5594 5598 if ((result =
5595 5599 symlink(Thdr_p->tbuf.t_linkname, nam_p)) >= 0) {
5596 5600 cnt = 0;
5597 5601 if (Over_p != NULL) {
5598 5602 (void) unlinkat(dirfd,
5599 5603 get_component(Over_p), 0);
5600 5604 *Over_p = '\0';
5601 5605 }
5602 5606 break;
5603 5607 } else if (errno != ENOENT) {
5604 5608 /* The attempt to symlink failed. */
5605 5609 msg(ERRN,
5606 5610 "Cannot create symbolic link \"%s\" -> "
5607 5611 "\"%s\"",
5608 5612 Thdr_p->tbuf.t_linkname, nam_p);
5609 5613
5610 5614 if (*Over_p != '\0') {
5611 5615 rstfiles(U_KEEP, dirfd);
5612 5616 }
5613 5617 return (-1);
5614 5618 }
5615 5619 } else if (Hdr_type == BAR && bar_linkflag == SYMTYPE) {
5616 5620 if ((result = symlink(bar_linkname, nam_p)) >= 0) {
5617 5621 cnt = 0;
5618 5622 if (Over_p != NULL) {
5619 5623 (void) unlinkat(dirfd,
5620 5624 get_component(Over_p), 0);
5621 5625 *Over_p = '\0';
5622 5626 }
5623 5627 break;
5624 5628 } else if (errno != ENOENT) {
5625 5629 /* The attempt to symlink failed. */
5626 5630 msg(ERRN,
5627 5631 "Cannot create symbolic link \"%s\" -> "
5628 5632 "\"%s\"",
5629 5633 bar_linkname, nam_p);
5630 5634 if (*Over_p != '\0') {
5631 5635 rstfiles(U_KEEP, dirfd);
5632 5636 }
5633 5637 return (-1);
5634 5638 }
5635 5639 } else if ((G_p->g_mode & Ftype) == S_IFLNK) {
5636 5640 if ((!(Args & OCp)) && !(Hdr_type == USTAR)) {
5637 5641 FILL(G_p->g_filesz);
5638 5642 (void) strncpy(Symlnk_p,
5639 5643 Buffr.b_out_p, G_p->g_filesz);
5640 5644 *(Symlnk_p + G_p->g_filesz) = '\0';
5641 5645 } else if ((!(Args & OCp)) && (Hdr_type == USTAR)) {
5642 5646 Symlnk_p[NAMSIZ] = '\0';
5643 5647 (void) strncpy(Symlnk_p,
5644 5648 &Thdr_p->tbuf.t_linkname[0], NAMSIZ);
5645 5649 }
5646 5650 if ((result = symlink(Symlnk_p, nam_p)) >= 0) {
5647 5651 cnt = 0;
5648 5652 if (Over_p != NULL) {
5649 5653 (void) unlinkat(dirfd,
5650 5654 get_component(Over_p), 0);
5651 5655 *Over_p = '\0';
5652 5656 }
5653 5657 break;
5654 5658 } else if (errno != ENOENT) {
5655 5659 /* The attempt to symlink failed. */
5656 5660 msg(ERRN,
5657 5661 "Cannot create symbolic link \"%s\" -> "
5658 5662 "\"%s\"",
5659 5663 Symlnk_p, nam_p);
5660 5664
5661 5665 if (*Over_p != '\0') {
5662 5666 rstfiles(U_KEEP, dirfd);
5663 5667 }
5664 5668 return (-1);
5665 5669 }
5666 5670 } else {
5667 5671 int saveerrno;
5668 5672
5669 5673 if ((result = openat(dirfd, get_component(nam_p),
5670 5674 O_CREAT|O_RDWR|O_TRUNC, (int)G_p->g_mode)) < 0) {
5671 5675 saveerrno = errno;
5672 5676 if (G_p->g_attrnam_p != NULL) {
5673 5677 result = retry_open_attr(dirfd,
5674 5678 Gen.g_baseparent_fd, Fullnam_p,
5675 5679 (G_p->g_attrparent_p == NULL) ?
5676 5680 NULL : G_p->g_attrparent_p, nam_p,
5677 5681 O_CREAT|O_RDWR|O_TRUNC,
5678 5682 (int)G_p->g_mode);
5679 5683 }
5680 5684 }
5681 5685 if (result < 0) {
5682 5686 errno = saveerrno;
5683 5687 if (errno != ENOENT) {
5684 5688 /* The attempt to open failed. */
5685 5689 msg(ERRN, "Cannot open file \"%s\"",
5686 5690 nam_p);
5687 5691 if (*Over_p != '\0') {
5688 5692 rstfiles(U_KEEP, dirfd);
5689 5693 }
5690 5694 return (-1);
5691 5695 }
5692 5696 } else {
5693 5697 /* acl support */
5694 5698 acl_is_set = 0;
5695 5699 if (Pflag && aclp != NULL) {
5696 5700 if (facl_set(result, aclp) < 0) {
5697 5701 msg(ERRN,
5698 5702 "\"%s\": failed to set acl",
5699 5703 nam_p);
5700 5704 } else {
5701 5705 acl_is_set = 1;
5702 5706 }
5703 5707 acl_free(aclp);
5704 5708 aclp = NULL;
5705 5709 }
5706 5710 cnt = 0;
5707 5711 break;
5708 5712 }
5709 5713 }
5710 5714 cnt++;
5711 5715 } while (cnt < 2 && missdir(nam_p) == 0);
5712 5716
5713 5717 switch (cnt) {
5714 5718 case 0:
5715 5719 if ((Args & OCi) && (Hdr_type == USTAR)) {
5716 5720 setpasswd(nam_p);
5717 5721 }
5718 5722 if ((G_p->g_mode & Ftype) == S_IFLNK ||
5719 5723 (Hdr_type == BAR && bar_linkflag == SYMTYPE)) {
5720 5724 if (Args & OCR) {
5721 5725 if (fchownat(dirfd,
5722 5726 get_component(nam_p),
5723 5727 (int)Rpw_p->pw_uid,
5724 5728 (int)Rpw_p->pw_gid,
5725 5729 AT_SYMLINK_NOFOLLOW) < 0) {
5726 5730 msg(ERRN,
5727 5731 "Error during chown() of "
5728 5732 "\"%s%s%s\"",
5729 5733 (G_p->g_attrnam_p == NULL) ?
5730 5734 nam_p : G_p->g_attrfnam_p,
5731 5735 (G_p->g_attrnam_p == NULL) ?
5732 5736 "" : G_p->g_rw_sysattr ?
5733 5737 gettext(" System Attribute ") :
5734 5738 gettext(" Attribute "),
5735 5739 (G_p->g_attrnam_p == NULL) ?
5736 5740 "" : nam_p);
5737 5741 }
5738 5742 } else if ((fchownat(dirfd, get_component(nam_p),
5739 5743 (int)G_p->g_uid, (int)G_p->g_gid,
5740 5744 AT_SYMLINK_NOFOLLOW) < 0) && privileged) {
5741 5745 msg(ERRN,
5742 5746 "Error during chown() of \"%s%s%s\"",
5743 5747 (G_p->g_attrnam_p == NULL) ?
5744 5748 nam_p : G_p->g_attrfnam_p,
5745 5749 (G_p->g_attrnam_p == NULL) ? "" :
5746 5750 G_p->g_rw_sysattr ?
5747 5751 gettext(" System Attribute ") :
5748 5752 gettext(" Attribute "),
5749 5753 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
5750 5754 }
5751 5755 }
5752 5756 break;
5753 5757
5754 5758 case 1:
5755 5759 if (Do_rename) {
5756 5760 msg(ERRN, "Cannot create directory for \"%s%s%s\"",
5757 5761 (G_p->g_attrnam_p == NULL) ? Over_p :
5758 5762 G_p->g_attrfnam_p,
5759 5763 (G_p->g_attrnam_p == NULL) ? "" :
5760 5764 G_p->g_rw_sysattr ?
5761 5765 gettext(" System Attribute ") :
5762 5766 gettext(" Attribute "),
5763 5767 (G_p->g_attrnam_p == NULL) ? "" : Over_p);
5764 5768 } else {
5765 5769 msg(ERRN, "Cannot create directory for \"%s%s%s\"",
5766 5770 (G_p->g_attrnam_p == NULL) ? nam_p :
5767 5771 G_p->g_attrfnam_p,
5768 5772 (G_p->g_attrnam_p == NULL) ? "" :
5769 5773 G_p->g_rw_sysattr ?
5770 5774 gettext(" System Attribute ") :
5771 5775 gettext(" Attribute "),
5772 5776 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
5773 5777 }
5774 5778 break;
5775 5779
5776 5780 case 2:
5777 5781 if (Do_rename) {
5778 5782 msg(ERRN, "Cannot create \"%s%s%s\"",
5779 5783 (G_p->g_attrnam_p == NULL) ? Over_p :
5780 5784 G_p->g_attrfnam_p,
5781 5785 (G_p->g_attrnam_p == NULL) ? "" :
5782 5786 G_p->g_rw_sysattr ?
5783 5787 gettext(" System Attribute ") :
5784 5788 gettext(" Attribute "),
5785 5789 (G_p->g_attrnam_p == NULL) ? "" :
5786 5790 Over_p);
5787 5791 } else {
5788 5792 msg(ERRN, "Cannot create \"%s%s%s\"",
5789 5793 (G_p->g_attrnam_p == NULL) ? nam_p :
5790 5794 G_p->g_attrfnam_p,
5791 5795 (G_p->g_attrnam_p == NULL) ? "" :
5792 5796 G_p->g_rw_sysattr ?
5793 5797 gettext(" System Attribute ") :
5794 5798 gettext(" Attribute "),
5795 5799 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
5796 5800 }
5797 5801 break;
5798 5802
5799 5803 default:
5800 5804 msg(EXT, "Impossible case.");
5801 5805 }
5802 5806
5803 5807 Finished = 0;
5804 5808 return (result);
5805 5809 }
5806 5810
5807 5811 /*
5808 5812 * read_hdr: Transfer headers from the selected format
5809 5813 * in the archive I/O buffer to the generic structure.
5810 5814 */
5811 5815
5812 5816 static
5813 5817 int
5814 5818 read_hdr(int hdr)
5815 5819 {
5816 5820 int rv = NONE;
5817 5821 major_t maj, rmaj;
5818 5822 minor_t min, rmin;
5819 5823 char tmpnull;
5820 5824 static int bar_read_cnt = 0;
5821 5825
5822 5826 if (hdr != BAR) {
5823 5827 if (Buffr.b_end_p != (Buffr.b_out_p + Hdrsz)) {
5824 5828 tmpnull = *(Buffr.b_out_p + Hdrsz);
5825 5829 *(Buffr.b_out_p + Hdrsz) = '\0';
5826 5830 }
5827 5831 }
5828 5832
5829 5833 switch (hdr) {
5830 5834 case BIN:
5831 5835 (void) memcpy(&Hdr, Buffr.b_out_p, HDRSZ);
5832 5836 if (Hdr.h_magic == (short)CMN_BBS) {
5833 5837 swap((char *)&Hdr, HDRSZ);
5834 5838 }
5835 5839 Gen.g_magic = Hdr.h_magic;
5836 5840 Gen.g_mode = Hdr.h_mode;
5837 5841 Gen.g_uid = Hdr.h_uid;
5838 5842 Gen.g_gid = Hdr.h_gid;
5839 5843 Gen.g_nlink = Hdr.h_nlink;
5840 5844 Gen.g_mtime = mklong(Hdr.h_mtime);
5841 5845 Gen.g_ino = Hdr.h_ino;
5842 5846 Gen.g_dev = Hdr.h_dev;
5843 5847 Gen.g_rdev = Hdr.h_rdev;
5844 5848 Gen.g_cksum = 0L;
5845 5849 Gen.g_filesz = (off_t)mklong(Hdr.h_filesize);
5846 5850 Gen.g_namesz = Hdr.h_namesize;
5847 5851 rv = BIN;
5848 5852 break;
5849 5853 case CHR:
5850 5854 if (sscanf(Buffr.b_out_p,
5851 5855 "%6lo%6lo%6lo%6lo%6lo%6lo%6lo%6lo%11lo%6o%11llo",
5852 5856 &Gen.g_magic, &Gen.g_dev, &Gen.g_ino, &Gen.g_mode,
5853 5857 &Gen.g_uid, &Gen.g_gid, &Gen.g_nlink, &Gen.g_rdev,
5854 5858 (ulong_t *)&Gen.g_mtime, (uint_t *)&Gen.g_namesz,
5855 5859 (u_off_t *)&Gen.g_filesz) == CHR_CNT) {
5856 5860 rv = CHR;
5857 5861 #define cpioMAJOR(x) (int)(((unsigned)x >> 8) & 0x7F)
5858 5862 #define cpioMINOR(x) (int)(x & 0xFF)
5859 5863 maj = cpioMAJOR(Gen.g_dev);
5860 5864 rmaj = cpioMAJOR(Gen.g_rdev);
5861 5865 min = cpioMINOR(Gen.g_dev);
5862 5866 rmin = cpioMINOR(Gen.g_rdev);
5863 5867 if (Use_old_stat) {
5864 5868 /* needs error checking */
5865 5869 Gen.g_dev = (maj << 8) | min;
5866 5870 Gen.g_rdev = (rmaj << 8) | rmin;
5867 5871 } else {
5868 5872 Gen.g_dev = makedev(maj, min);
5869 5873 Gen.g_rdev = makedev(rmaj, rmin);
5870 5874 }
5871 5875 }
5872 5876 break;
5873 5877 case ASC:
5874 5878 case CRC:
5875 5879 if (sscanf(Buffr.b_out_p,
5876 5880 "%6lx%8lx%8lx%8lx%8lx%8lx%8lx%8llx%8x%8x%8x%8x%8x%8lx",
5877 5881 &Gen.g_magic, &Gen.g_ino, &Gen.g_mode, &Gen.g_uid,
5878 5882 &Gen.g_gid, &Gen.g_nlink, &Gen.g_mtime,
5879 5883 (u_off_t *)&Gen.g_filesz, (uint_t *)&maj, (uint_t *)&min,
5880 5884 (uint_t *)&rmaj, (uint_t *)&rmin, (uint_t *)&Gen.g_namesz,
5881 5885 &Gen.g_cksum) == ASC_CNT) {
5882 5886 Gen.g_dev = makedev(maj, min);
5883 5887 Gen.g_rdev = makedev(rmaj, rmin);
5884 5888 rv = hdr;
5885 5889 }
5886 5890 break;
5887 5891 case USTAR: /* TAR and USTAR */
5888 5892 if (*Buffr.b_out_p == '\0') {
5889 5893 *Gen.g_nam_p = '\0';
5890 5894 nambuf[0] = '\0';
5891 5895 } else {
5892 5896 Thdr_p = (union tblock *)Buffr.b_out_p;
5893 5897 Gen.g_nam_p[0] = '\0';
5894 5898 (void) strncpy((char *)&nambuf,
5895 5899 Thdr_p->tbuf.t_name, NAMSIZ);
5896 5900 (void) sscanf(Thdr_p->tbuf.t_mode, "%8lo",
5897 5901 &Gen.g_mode);
5898 5902 (void) sscanf(Thdr_p->tbuf.t_uid, "%8lo", &Gen.g_uid);
5899 5903 (void) sscanf(Thdr_p->tbuf.t_gid, "%8lo", &Gen.g_gid);
5900 5904 (void) sscanf(Thdr_p->tbuf.t_size, "%11llo",
5901 5905 (u_off_t *)&Gen.g_filesz);
5902 5906 (void) sscanf(Thdr_p->tbuf.t_mtime, "%12lo",
5903 5907 (ulong_t *)&Gen.g_mtime);
5904 5908 (void) sscanf(Thdr_p->tbuf.t_cksum, "%8lo",
5905 5909 (ulong_t *)&Gen.g_cksum);
5906 5910 if (Thdr_p->tbuf.t_linkname[0] != '\0')
5907 5911 Gen.g_nlink = 1;
5908 5912 else
5909 5913 Gen.g_nlink = 0;
5910 5914
5911 5915 switch (Thdr_p->tbuf.t_typeflag) {
5912 5916 case SYMTYPE:
5913 5917 /* Symbolic Link */
5914 5918 Gen.g_nlink = 2;
5915 5919 break;
5916 5920 case CHRTYPE:
5917 5921 Gen.g_mode |= (S_IFMT & S_IFCHR);
5918 5922 break;
5919 5923 case BLKTYPE:
5920 5924 Gen.g_mode |= (S_IFMT & S_IFBLK);
5921 5925 break;
5922 5926 case DIRTYPE:
5923 5927 Gen.g_mode |= (S_IFMT & S_IFDIR);
5924 5928 break;
5925 5929 case FIFOTYPE:
5926 5930 Gen.g_mode |= (S_IFMT & S_IFIFO);
5927 5931 break;
5928 5932 }
5929 5933
5930 5934 (void) sscanf(Thdr_p->tbuf.t_magic, "%8lo",
5931 5935 /* LINTED alignment */
5932 5936 (ulong_t *)&Gen.g_tmagic);
5933 5937 (void) sscanf(Thdr_p->tbuf.t_version, "%8lo",
5934 5938 /* LINTED alignment */
5935 5939 (ulong_t *)&Gen.g_version);
5936 5940 (void) sscanf(Thdr_p->tbuf.t_uname, "%32s",
5937 5941 (char *)&Gen.g_uname);
5938 5942 (void) sscanf(Thdr_p->tbuf.t_gname, "%32s",
5939 5943 (char *)&Gen.g_gname);
5940 5944 (void) sscanf(Thdr_p->tbuf.t_devmajor, "%8lo",
5941 5945 &Gen.g_dev);
5942 5946 (void) sscanf(Thdr_p->tbuf.t_devminor, "%8lo",
5943 5947 &Gen.g_rdev);
5944 5948 (void) strncpy((char *)&prebuf,
5945 5949 Thdr_p->tbuf.t_prefix, PRESIZ);
5946 5950 Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
5947 5951 Gen.g_dev = makedev(maj, min);
5948 5952 }
5949 5953 rv = USTAR;
5950 5954 break;
5951 5955 case TAR:
5952 5956 if (*Buffr.b_out_p == '\0') {
5953 5957 *Gen.g_nam_p = '\0';
5954 5958 nambuf[0] = '\0';
5955 5959 } else {
5956 5960 Thdr_p = (union tblock *)Buffr.b_out_p;
5957 5961 Gen.g_nam_p[0] = '\0';
5958 5962 (void) sscanf(Thdr_p->tbuf.t_mode, "%lo", &Gen.g_mode);
5959 5963 (void) sscanf(Thdr_p->tbuf.t_uid, "%lo", &Gen.g_uid);
5960 5964 (void) sscanf(Thdr_p->tbuf.t_gid, "%lo", &Gen.g_gid);
5961 5965 (void) sscanf(Thdr_p->tbuf.t_size, "%llo",
5962 5966 (u_off_t *)&Gen.g_filesz);
5963 5967 (void) sscanf(Thdr_p->tbuf.t_mtime, "%lo",
5964 5968 &Gen.g_mtime);
5965 5969 (void) sscanf(Thdr_p->tbuf.t_cksum, "%lo",
5966 5970 &Gen.g_cksum);
5967 5971 if (Thdr_p->tbuf.t_typeflag == '1') /* hardlink */
5968 5972 Gen.g_nlink = 1;
5969 5973 else
5970 5974 Gen.g_nlink = 0;
5971 5975 (void) strncpy(Gen.g_nam_p,
5972 5976 Thdr_p->tbuf.t_name, NAMSIZ);
5973 5977 Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
5974 5978 (void) strcpy(nambuf, Gen.g_nam_p);
5975 5979 }
5976 5980 rv = TAR;
5977 5981 break;
5978 5982 case BAR:
5979 5983 if (Bar_vol_num == 0 && bar_read_cnt == 0) {
5980 5984 read_bar_vol_hdr();
5981 5985 bar_read_cnt++;
5982 5986 }
5983 5987 else
5984 5988 read_bar_file_hdr();
5985 5989 rv = BAR;
5986 5990 break;
5987 5991 default:
5988 5992 msg(EXT, "Impossible header type.");
5989 5993 }
5990 5994
5991 5995 if (hdr != BAR) {
5992 5996 if (Buffr.b_end_p != (Buffr.b_out_p + Hdrsz))
5993 5997 *(Buffr.b_out_p + Hdrsz) = tmpnull;
5994 5998 }
5995 5999
5996 6000 return (rv);
5997 6001 }
5998 6002
5999 6003 /*
6000 6004 * reclaim: Reclaim linked file structure storage.
6001 6005 */
6002 6006
6003 6007 static void
6004 6008 reclaim(struct Lnk *p)
6005 6009 {
6006 6010 p->L_bck_p->L_nxt_p = p->L_nxt_p;
6007 6011 p->L_nxt_p->L_bck_p = p->L_bck_p;
6008 6012
6009 6013 while (p != NULL) {
6010 6014 struct Lnk *new_p = p->L_lnk_p;
6011 6015
6012 6016 free(p->L_gen.g_nam_p);
6013 6017 free(p);
6014 6018 p = new_p;
6015 6019 }
6016 6020 }
6017 6021
6018 6022 /*
6019 6023 * rstbuf: Reset the I/O buffer, move incomplete potential headers to
6020 6024 * the front of the buffer and force bread() to refill the buffer. The
6021 6025 * return value from bread() is returned (to identify I/O errors). On the
6022 6026 * 3B2, reads must begin on a word boundary, therefore, with the -i option,
6023 6027 * any remaining bytes in the buffer must be moved to the base of the buffer
6024 6028 * in such a way that the destination locations of subsequent reads are
6025 6029 * word aligned.
6026 6030 */
6027 6031
6028 6032 static void
6029 6033 rstbuf(void)
6030 6034 {
6031 6035 int pad;
6032 6036
6033 6037 if ((Args & OCi) || Append) {
6034 6038 if (Buffr.b_out_p != Buffr.b_base_p) {
6035 6039 pad = ((Buffr.b_cnt + FULLWD) & ~FULLWD);
6036 6040 Buffr.b_in_p = Buffr.b_base_p + pad;
6037 6041 pad -= Buffr.b_cnt;
6038 6042 (void) memcpy(Buffr.b_base_p + pad, Buffr.b_out_p,
6039 6043 (int)Buffr.b_cnt);
6040 6044 Buffr.b_out_p = Buffr.b_base_p + pad;
6041 6045 }
6042 6046 if (bfill() < 0)
6043 6047 msg(EXT, "Unexpected end-of-archive encountered.");
6044 6048 } else { /* OCo */
6045 6049 (void) memcpy(Buffr.b_base_p, Buffr.b_out_p, (int)Buffr.b_cnt);
6046 6050 Buffr.b_out_p = Buffr.b_base_p;
6047 6051 Buffr.b_in_p = Buffr.b_base_p + Buffr.b_cnt;
6048 6052 }
6049 6053 }
6050 6054
6051 6055 static void
6052 6056 setpasswd(char *nam)
6053 6057 {
6054 6058 if ((dpasswd = getpwnam(&Gen.g_uname[0])) == NULL) {
6055 6059 msg(EPOST, "cpio: problem reading passwd entry");
6056 6060 msg(EPOST, "cpio: %s: owner not changed", nam);
6057 6061 if (Gen.g_uid == UID_NOBODY && S_ISREG(Gen.g_mode))
6058 6062 Gen.g_mode &= ~S_ISUID;
6059 6063 } else
6060 6064 Gen.g_uid = dpasswd->pw_uid;
6061 6065
6062 6066 if ((dgroup = getgrnam(&Gen.g_gname[0])) == NULL) {
6063 6067 msg(EPOST, "cpio: problem reading group entry");
6064 6068 msg(EPOST, "cpio: %s: group not changed", nam);
6065 6069 if (Gen.g_gid == GID_NOBODY && S_ISREG(Gen.g_mode))
6066 6070 Gen.g_mode &= ~S_ISGID;
6067 6071 } else
6068 6072 Gen.g_gid = dgroup->gr_gid;
6069 6073 G_p = &Gen;
6070 6074 }
6071 6075
6072 6076 /*
6073 6077 * rstfiles: Perform final changes to the file. If the -u option is set,
6074 6078 * and overwrite == U_OVER, remove the temporary file, else if overwrite
6075 6079 * == U_KEEP, unlink the current file, and restore the existing version
6076 6080 * of the file. In addition, where appropriate, set the access or modification
6077 6081 * times, change the owner and change the modes of the file.
6078 6082 *
6079 6083 * Note that if Do_rename is set, then the roles of original and temporary
6080 6084 * file are reversed. If all went well, we will rename() the temporary file
6081 6085 * over the original in order to accommodate potentially executing files.
6082 6086 */
6083 6087 static void
6084 6088 rstfiles(int over, int dirfd)
6085 6089 {
6086 6090 char *inam_p, *onam_p, *nam_p;
6087 6091 int error;
6088 6092
6089 6093 #if defined(_PC_SATTR_ENABLED)
6090 6094 /* Time or permissions cannot be set on system attribute files */
6091 6095 if ((Gen.g_attrnam_p != NULL) && (Gen.g_rw_sysattr == 1)) {
6092 6096 return;
6093 6097 }
6094 6098 #endif /* _PC_SATTR_ENABLED */
6095 6099
6096 6100 if (Args & OCp) {
6097 6101 if (G_p->g_attrnam_p == NULL) {
6098 6102 nam_p = Fullnam_p;
6099 6103 } else {
6100 6104 nam_p = G_p->g_attrnam_p;
6101 6105 }
6102 6106 } else {
6103 6107 if (Gen.g_nlink > (ulong_t)0) {
6104 6108 nam_p = G_p->g_nam_p;
6105 6109 } else {
6106 6110 nam_p = Gen.g_nam_p;
6107 6111 }
6108 6112 }
6109 6113 if (Gen.g_attrnam_p != NULL) {
6110 6114 nam_p = Gen.g_attrnam_p;
6111 6115 }
6112 6116
6113 6117 if ((Args & OCi) && (Hdr_type == USTAR)) {
6114 6118 setpasswd(nam_p);
6115 6119 }
6116 6120 if (over == U_KEEP && *Over_p != '\0') {
6117 6121 if (Do_rename) {
6118 6122 msg(POST, "Restoring existing \"%s%s%s\"",
6119 6123 (G_p->g_attrnam_p == NULL) ? Over_p : Fullnam_p,
6120 6124 (G_p->g_attrnam_p == NULL) ? "" :
6121 6125 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6122 6126 gettext(" Attribute "),
6123 6127 (G_p->g_attrnam_p == NULL) ? "" : Over_p);
6124 6128 } else {
6125 6129 msg(POST, "Restoring existing \"%s%s%s\"",
6126 6130 (G_p->g_attrnam_p == NULL) ? nam_p : Fullnam_p,
6127 6131 (G_p->g_attrnam_p == NULL) ? "" :
6128 6132 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6129 6133 gettext(" Attribute "),
6130 6134 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
6131 6135 }
6132 6136
6133 6137 /* delete what we just built */
6134 6138 (void) unlinkat(dirfd, get_component(nam_p), 0);
6135 6139
6136 6140 /* If the old file needs restoring, do the necessary links */
6137 6141 if (Do_rename) {
6138 6142 char *tmp_ptr;
6139 6143
6140 6144 if (Args & OCp) {
6141 6145 tmp_ptr = Fullnam_p;
6142 6146 Fullnam_p = Over_p;
6143 6147 } else {
6144 6148 tmp_ptr = G_p->g_nam_p;
6145 6149 G_p->g_nam_p = Over_p;
6146 6150 }
6147 6151 Over_p = tmp_ptr;
6148 6152
6149 6153 Do_rename = 0; /* names now have original values */
6150 6154 } else {
6151 6155 if (rename(Over_p, nam_p) < 0) {
6152 6156 if (link(Over_p, nam_p) < 0) {
6153 6157 msg(EXTN,
6154 6158 "Cannot recover original version"
6155 6159 " of \"%s%s%s\"",
6156 6160 (G_p->g_attrnam_p == NULL) ?
6157 6161 nam_p : Fullnam_p,
6158 6162 (G_p->g_attrnam_p == NULL) ? "" :
6159 6163 G_p->g_rw_sysattr ?
6160 6164 gettext(" System Attribute ") :
6161 6165 gettext(" Attribute "),
6162 6166 (G_p->g_attrnam_p == NULL) ?
6163 6167 "" : nam_p);
6164 6168 }
6165 6169 if (unlinkat(dirfd, get_component(Over_p), 0)) {
6166 6170 msg(ERRN,
6167 6171 "Cannot remove temp file "
6168 6172 "\"%s%s%s\"",
6169 6173 (G_p->g_attrnam_p == NULL) ?
6170 6174 Over_p : Fullnam_p,
6171 6175 (G_p->g_attrnam_p == NULL) ? "" :
6172 6176 G_p->g_rw_sysattr ?
6173 6177 gettext(" System Attribute ") :
6174 6178 gettext(" Attribute "),
6175 6179 (G_p->g_attrnam_p == NULL) ?
6176 6180 "" : Over_p);
6177 6181 }
6178 6182 }
6179 6183 }
6180 6184 *Over_p = '\0';
6181 6185 return;
6182 6186 } else if (over == U_OVER && *Over_p != '\0') {
6183 6187 if (Do_rename) {
6184 6188 char *tmp_ptr;
6185 6189
6186 6190 (void) renameat(dirfd, get_component(nam_p),
6187 6191 dirfd, get_component(Over_p));
6188 6192 if (Args & OCp) {
6189 6193 if (G_p->g_attrnam_p == NULL) {
6190 6194 tmp_ptr = Fullnam_p;
6191 6195 Fullnam_p = Over_p;
6192 6196 Over_p = tmp_ptr;
6193 6197 } else {
6194 6198 /*
6195 6199 * Over_p is pointing at g_attrnam_p
6196 6200 * which must be preserved.
6197 6201 *
6198 6202 * We don't want the tmp_ptr and so
6199 6203 * on to throw away our only copy of
6200 6204 * the name.
6201 6205 */
6202 6206 Over_p = Attrfile_p;
6203 6207 }
6204 6208 } else {
6205 6209 tmp_ptr = G_p->g_nam_p;
6206 6210 G_p->g_nam_p = Over_p;
6207 6211 Over_p = tmp_ptr;
6208 6212 }
6209 6213 Do_rename = 0; /* names now have original values */
6210 6214 } else {
6211 6215 if (unlinkat(dirfd, get_component(Over_p), 0) < 0) {
6212 6216 msg(ERRN,
6213 6217 "Cannot unlink() temp file \"%s%s%s\"",
6214 6218 (G_p->g_attrnam_p == NULL) ?
6215 6219 Over_p : Fullnam_p,
6216 6220 (G_p->g_attrnam_p == NULL) ? "" :
6217 6221 G_p->g_rw_sysattr ?
6218 6222 gettext(" System Attribute ") :
6219 6223 gettext(" Attribute "),
6220 6224 (G_p->g_attrnam_p == NULL) ? "" : Over_p);
6221 6225 }
6222 6226 }
6223 6227 *Over_p = '\0';
6224 6228 }
6225 6229 if (Args & OCp) {
6226 6230 if (G_p->g_attrnam_p != NULL) {
6227 6231 inam_p = G_p->g_attrfnam_p;
6228 6232 onam_p = G_p->g_attrnam_p;
6229 6233 } else {
6230 6234 inam_p = Nam_p;
6231 6235 onam_p = Fullnam_p;
6232 6236 }
6233 6237 } else /* OCi only uses onam_p, OCo only uses inam_p */
6234 6238 if (G_p->g_attrnam_p != NULL) {
6235 6239 inam_p = onam_p = G_p->g_attrnam_p;
6236 6240 } else {
6237 6241 inam_p = onam_p = G_p->g_nam_p;
6238 6242 }
6239 6243
6240 6244 /*
6241 6245 * Change the owner, time, and mode to those of the file
6242 6246 * originally created in the archive. Note: time and
6243 6247 * mode do not need to be restored for a symbolic link
6244 6248 * since rstfiles() is not called when the archived file
6245 6249 * is a symlink.
6246 6250 */
6247 6251 if (!(Args & OCo)) {
6248 6252 if (Args & OCR) {
6249 6253 if (fchownat(dirfd, get_component(onam_p),
6250 6254 Rpw_p->pw_uid, Rpw_p->pw_gid,
6251 6255 AT_SYMLINK_NOFOLLOW) < 0) {
6252 6256 msg(ERRN, "Cannot chown() \"%s%s%s\"",
6253 6257 onam_p,
6254 6258 (G_p->g_attrnam_p == NULL) ? "" :
6255 6259 G_p->g_rw_sysattr ?
6256 6260 gettext(" System Attribute ") :
6257 6261 gettext(" Attribute "),
6258 6262 (G_p->g_attrnam_p == NULL) ? "" : onam_p);
6259 6263 }
6260 6264 } else {
6261 6265 if ((fchownat(dirfd, get_component(onam_p),
6262 6266 G_p->g_uid, G_p->g_gid,
6263 6267 AT_SYMLINK_NOFOLLOW) < 0) && privileged) {
6264 6268 msg(ERRN, "Cannot chown() \"%s%s%s\"",
6265 6269 onam_p,
6266 6270 (G_p->g_attrnam_p == NULL) ? "" :
6267 6271 G_p->g_rw_sysattr ?
6268 6272 gettext(" System Attribute ") :
6269 6273 gettext(" Attribute "),
6270 6274 (G_p->g_attrnam_p == NULL) ? "" : onam_p);
6271 6275 }
6272 6276 }
6273 6277
6274 6278 if (Args & OCm) {
6275 6279 set_tym(dirfd, get_component(onam_p),
6276 6280 G_p->g_mtime, G_p->g_mtime);
6277 6281 }
6278 6282
6279 6283 /* Acl was not set, so we must chmod */
6280 6284 if (!acl_is_set) {
6281 6285 mode_t orig_mask, new_mask;
6282 6286
6283 6287 /*
6284 6288 * use fchmod for attributes, since
6285 6289 * we known they are always regular
6286 6290 * files, whereas when it isn't an
6287 6291 * attribute it could be for a fifo
6288 6292 * or something other that we don't
6289 6293 * open and don't have a valid Ofile
6290 6294 * for.
6291 6295 */
6292 6296 if (privileged) {
6293 6297 new_mask = G_p->g_mode;
6294 6298 } else {
6295 6299 orig_mask = umask(0);
6296 6300 new_mask = G_p->g_mode & ~orig_mask;
6297 6301 }
6298 6302
6299 6303 if (G_p->g_attrnam_p != NULL) {
6300 6304 error = fchmod(Ofile, new_mask);
6301 6305 } else {
6302 6306 error = chmod(onam_p, new_mask);
6303 6307 }
6304 6308 if (error < 0) {
6305 6309 msg(ERRN,
6306 6310 "Cannot chmod() \"%s%s%s\"",
6307 6311 (G_p->g_attrnam_p == NULL) ?
6308 6312 onam_p : G_p->g_attrfnam_p,
6309 6313 (G_p->g_attrnam_p == NULL) ? "" :
6310 6314 G_p->g_rw_sysattr ?
6311 6315 gettext(" System Attribute ") :
6312 6316 gettext(" Attribute "),
6313 6317 (G_p->g_attrnam_p == NULL) ? "" : onam_p);
6314 6318 }
6315 6319 if (!privileged) {
6316 6320 (void) umask(orig_mask);
6317 6321 }
6318 6322 }
6319 6323 }
6320 6324
6321 6325 if (!(Args & OCi) && (Args & OCa)) {
6322 6326 /*
6323 6327 * Use dirfd since we are updating original file
6324 6328 * and not just created file
6325 6329 */
6326 6330 set_tym(G_p->g_dirfd, get_component(inam_p),
6327 6331 (ulong_t)SrcSt.st_atime, (ulong_t)SrcSt.st_mtime);
6328 6332 }
6329 6333 }
6330 6334
6331 6335 /*
6332 6336 * scan4trail: Scan the archive looking for the trailer.
6333 6337 * When found, back the archive up over the trailer and overwrite
6334 6338 * the trailer with the files to be added to the archive.
6335 6339 */
6336 6340
6337 6341 static void
6338 6342 scan4trail(void)
6339 6343 {
6340 6344 int rv;
6341 6345 off_t off1, off2;
6342 6346
6343 6347 Append = 1;
6344 6348 Hdr_type = NONE;
6345 6349 G_p = NULL;
6346 6350 while (gethdr()) {
6347 6351 G_p = &Gen;
6348 6352 data_in(P_SKIP);
6349 6353 }
6350 6354 off1 = Buffr.b_cnt;
6351 6355 off2 = Bufsize - (Buffr.b_cnt % Bufsize);
6352 6356 Buffr.b_out_p = Buffr.b_in_p = Buffr.b_base_p;
6353 6357 Buffr.b_cnt = (off_t)0;
6354 6358 if (lseek(Archive, -(off1 + off2), SEEK_REL) < 0)
6355 6359 msg(EXTN, "Unable to append to this archive");
6356 6360 if ((rv = g_read(Device, Archive, Buffr.b_in_p, Bufsize)) < 0)
6357 6361 msg(EXTN, "Cannot append to this archive");
6358 6362 if (lseek(Archive, (off_t)-rv, SEEK_REL) < 0)
6359 6363 msg(EXTN, "Unable to append to this archive");
6360 6364 Buffr.b_cnt = off2;
6361 6365 Buffr.b_in_p = Buffr.b_base_p + Buffr.b_cnt;
6362 6366 Append = 0;
6363 6367 }
6364 6368
6365 6369 /*
6366 6370 * setup: Perform setup and initialization functions. Parse the options
6367 6371 * using getopt(3C), call ckopts to check the options and initialize various
6368 6372 * structures and pointers. Specifically, for the -i option, save any
6369 6373 * patterns, for the -o option, check (via stat(2)) the archive, and for
6370 6374 * the -p option, validate the destination directory.
6371 6375 */
↓ open down ↓ |
5532 lines elided |
↑ open up ↑ |
6372 6376
6373 6377 static void
6374 6378 setup(int largc, char **largv)
6375 6379 {
6376 6380 extern int optind;
6377 6381 extern char *optarg;
6378 6382
6379 6383 #if defined(O_XATTR)
6380 6384 #if defined(_PC_SATTR_ENABLED)
6381 6385 #ifdef WAITAROUND
6382 - char *opts_p = "zabcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6@/";
6386 + char *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
6383 6387 #else
6384 - char *opts_p = "abcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6@/";
6388 + char *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@/";
6385 6389 #endif /* WAITAROUND */
6386 6390
6387 6391 #else /* _PC_SATTR_ENABLED */
6388 6392 #ifdef WAITAROUND
6389 - char *opts_p = "zabcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6@";
6393 + char *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
6390 6394 #else
6391 - char *opts_p = "abcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6@";
6395 + char *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6@";
6392 6396 #endif /* WAITAROUND */
6393 6397 #endif /* _PC_SATTR_ENABLED */
6394 6398
6395 6399 #else /* O_XATTR */
6396 6400 #ifdef WAITAROUND
6397 - char *opts_p = "zabcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6";
6401 + char *opts_p = "zabcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
6398 6402 #else
6399 - char *opts_p = "abcdfiklmoprstuvABC:DE:H:I:LM:O:PR:SV6";
6403 + char *opts_p = "abcdfiklmopqrstuvABC:DE:H:I:LM:O:PR:SV6";
6400 6404 #endif /* WAITAROUND */
6401 6405 #endif /* O_XATTR */
6402 6406
6403 6407 char *dupl_p = "Only one occurrence of -%c allowed";
6404 6408 int option;
6405 6409 int blk_cnt, blk_cnt_max;
6406 6410 struct rlimit rlim;
6407 6411
6408 6412 /* Remember the native page size. */
6409 6413
6410 6414 PageSize = sysconf(_SC_PAGESIZE);
6411 6415
6412 6416 if (PageSize == -1) {
6413 6417 /*
6414 6418 * This sysconf call will almost certainly never fail. The
6415 6419 * symbol PAGESIZE itself resolves to the above sysconf call,
6416 6420 * so we should go ahead and define our own constant.
6417 6421 */
6418 6422 PageSize = 8192;
6419 6423 }
6420 6424
6421 6425 Hdr_type = BIN;
6422 6426 Max_offset = (off_t)(BIN_OFFSET_MAX);
6423 6427 Efil_p = Hdr_p = Own_p = IOfil_p = NULL;
6424 6428 while ((option = getopt(largc, largv, opts_p)) != EOF) {
6425 6429 switch (option) {
6426 6430 #ifdef WAITAROUND
6427 6431 case 'z':
6428 6432 /* rendezvous with the debugger */
6429 6433 waitaround = 1;
6430 6434 break;
6431 6435 #endif
6432 6436 case 'a': /* reset access time */
6433 6437 Args |= OCa;
6434 6438 break;
6435 6439 case 'b': /* swap bytes and halfwords */
6436 6440 Args |= OCb;
6437 6441 break;
6438 6442 case 'c': /* select character header */
6439 6443 Args |= OCc;
6440 6444 Hdr_type = ASC;
6441 6445 Max_namesz = APATH;
6442 6446 Onecopy = 1;
6443 6447 break;
6444 6448 case 'd': /* create directories as needed */
6445 6449 Args |= OCd;
6446 6450 break;
6447 6451 case 'f': /* select files not in patterns */
6448 6452 Args |= OCf;
6449 6453 break;
6450 6454 case 'i': /* "copy in" */
6451 6455 Args |= OCi;
6452 6456 Archive = 0;
6453 6457 break;
6454 6458 case 'k': /* retry after I/O errors */
6455 6459 Args |= OCk;
6456 6460 break;
6457 6461 case 'l': /* link files when possible */
6458 6462 Args |= OCl;
6459 6463 break;
6460 6464 case 'm': /* retain modification time */
↓ open down ↓ |
51 lines elided |
↑ open up ↑ |
6461 6465 Args |= OCm;
6462 6466 break;
6463 6467 case 'o': /* "copy out" */
6464 6468 Args |= OCo;
6465 6469 Archive = 1;
6466 6470 break;
6467 6471 case 'p': /* "pass" */
6468 6472 Max_namesz = APATH;
6469 6473 Args |= OCp;
6470 6474 break;
6475 + case 'q': /* "quiet" */
6476 + Args |= OCq;
6477 + break;
6471 6478 case 'r': /* rename files interactively */
6472 6479 Args |= OCr;
6473 6480 break;
6474 6481 case 's': /* swap bytes */
6475 6482 Args |= OCs;
6476 6483 break;
6477 6484 case 't': /* table of contents */
6478 6485 Args |= OCt;
6479 6486 break;
6480 6487 case 'u': /* copy unconditionally */
6481 6488 Args |= OCu;
6482 6489 break;
6483 6490 case 'v': /* verbose - print file names */
6484 6491 Args |= OCv;
6485 6492 break;
6486 6493 case 'A': /* append to existing archive */
6487 6494 Args |= OCA;
6488 6495 break;
6489 6496 case 'B': /* set block size to 5120 bytes */
6490 6497 Args |= OCB;
6491 6498 Bufsize = 5120;
6492 6499 break;
6493 6500 case 'C': /* set arbitrary block size */
6494 6501 if (Args & OCC)
6495 6502 msg(ERR, dupl_p, 'C');
6496 6503 else {
6497 6504 Args |= OCC;
6498 6505 Bufsize = atoi(optarg);
6499 6506 }
6500 6507 break;
6501 6508 case 'D':
6502 6509 Dflag = 1;
6503 6510 break;
6504 6511 case 'E': /* alternate file for pattern input */
6505 6512 if (Args & OCE)
6506 6513 msg(ERR, dupl_p, 'E');
6507 6514 else {
6508 6515 Args |= OCE;
6509 6516 Efil_p = optarg;
6510 6517 }
6511 6518 break;
6512 6519 case 'H': /* select header type */
6513 6520 if (Args & OCH)
6514 6521 msg(ERR, dupl_p, 'H');
6515 6522 else {
6516 6523 Args |= OCH;
6517 6524 Hdr_p = optarg;
6518 6525 }
6519 6526 break;
6520 6527 case 'I': /* alternate file for archive input */
6521 6528 if (Args & OCI)
6522 6529 msg(ERR, dupl_p, 'I');
6523 6530 else {
6524 6531 Args |= OCI;
6525 6532 IOfil_p = optarg;
6526 6533 }
6527 6534 break;
6528 6535 case 'L': /* follow symbolic links */
6529 6536 Args |= OCL;
6530 6537 break;
6531 6538 case 'M': /* specify new end-of-media message */
6532 6539 if (Args & OCM)
6533 6540 msg(ERR, dupl_p, 'M');
6534 6541 else {
6535 6542 Args |= OCM;
6536 6543 Eom_p = optarg;
6537 6544 }
6538 6545 break;
6539 6546 case 'O': /* alternate file for archive output */
6540 6547 if (Args & OCO)
6541 6548 msg(ERR, dupl_p, 'O');
6542 6549 else {
6543 6550 Args |= OCO;
6544 6551 IOfil_p = optarg;
6545 6552 }
6546 6553 break;
6547 6554 case 'P': /* preserve acls */
6548 6555 Args |= OCP;
6549 6556 Pflag++;
6550 6557 break;
6551 6558 case 'R': /* change owner/group of files */
6552 6559 if (Args & OCR)
6553 6560 msg(ERR, dupl_p, 'R');
6554 6561 else {
6555 6562 Args |= OCR;
6556 6563 Own_p = optarg;
6557 6564 }
6558 6565 break;
6559 6566 case 'S': /* swap halfwords */
6560 6567 Args |= OCS;
6561 6568 break;
6562 6569 case 'V': /* print a dot '.' for each file */
6563 6570 Args |= OCV;
6564 6571 break;
6565 6572 case '6': /* for old, sixth-edition files */
6566 6573 Args |= OC6;
6567 6574 Ftype = SIXTH;
6568 6575 break;
6569 6576 #if defined(O_XATTR)
6570 6577 case '@':
6571 6578 Atflag++;
6572 6579 break;
6573 6580 #if defined(_PC_SATTR_ENABLED)
6574 6581 case '/':
6575 6582 SysAtflag++;
6576 6583 break;
6577 6584 #endif /* _PC_SATTR_ENABLED */
6578 6585 #endif /* O_XATTR */
6579 6586 default:
6580 6587 Error_cnt++;
6581 6588 } /* option */
6582 6589 } /* (option = getopt(largc, largv, opts_p)) != EOF */
6583 6590
6584 6591 #ifdef WAITAROUND
6585 6592 if (waitaround) {
6586 6593 (void) fprintf(stderr, gettext("Rendezvous with cpio on pid"
6587 6594 " %d\n"), getpid());
6588 6595
6589 6596 while (waitaround) {
6590 6597 (void) sleep(10);
6591 6598 }
6592 6599 }
6593 6600 #endif
6594 6601
6595 6602 largc -= optind;
6596 6603 largv += optind;
6597 6604 ckopts(Args);
6598 6605 if (!Error_cnt) {
6599 6606 if (Args & OCr) {
6600 6607 Renam_p = e_zalloc(E_EXIT, APATH + 1);
6601 6608 Renametmp_p = e_zalloc(E_EXIT, APATH + 1);
6602 6609 #if defined(_PC_SATTR_ENABLED)
6603 6610 Renam_attr_p = e_zalloc(E_EXIT, APATH + 1);
6604 6611 #endif
6605 6612 }
6606 6613 Symlnk_p = e_zalloc(E_EXIT, APATH);
6607 6614 Over_p = e_zalloc(E_EXIT, APATH);
6608 6615 Nam_p = e_zalloc(E_EXIT, APATH + 1);
6609 6616 if (Args & OCp) {
6610 6617 Savenam_p = e_zalloc(E_EXIT, APATH + 1);
6611 6618 }
6612 6619 Fullnam_p = e_zalloc(E_EXIT, APATH);
6613 6620 Lnknam_p = e_zalloc(E_EXIT, APATH);
6614 6621 Gen.g_nam_p = Nam_p;
6615 6622 if ((Fullnam_p = getcwd(NULL, APATH)) == NULL)
6616 6623 msg(EXT, "Unable to determine current directory.");
6617 6624 if (Args & OCi) {
6618 6625 if (largc > 0) /* save patterns for -i option, if any */
6619 6626 Pat_pp = largv;
6620 6627 if (Args & OCE)
6621 6628 getpats(largc, largv);
6622 6629 } else if (Args & OCo) {
6623 6630 if (largc != 0) /* error if arguments left with -o */
6624 6631 Error_cnt++;
6625 6632 else if (fstat(Archive, &ArchSt) < 0)
6626 6633 msg(ERRN, "Error during stat() of archive");
6627 6634 switch (Hdr_type) {
6628 6635 case BIN:
6629 6636 Hdrsz = HDRSZ;
6630 6637 Pad_val = HALFWD;
6631 6638 break;
6632 6639 case CHR:
6633 6640 Hdrsz = CHRSZ;
6634 6641 Pad_val = 0;
6635 6642 Max_offset = (off_t)(CHAR_OFFSET_MAX);
6636 6643 break;
6637 6644 case ASC:
6638 6645 case CRC:
6639 6646 Hdrsz = ASCSZ;
6640 6647 Pad_val = FULLWD;
6641 6648 Max_offset = (off_t)(ASC_OFFSET_MAX);
6642 6649 break;
6643 6650 case TAR:
6644 6651 /* FALLTHROUGH */
6645 6652 case USTAR: /* TAR and USTAR */
6646 6653 Hdrsz = TARSZ;
6647 6654 Pad_val = FULLBK;
6648 6655 Max_offset = (off_t)(CHAR_OFFSET_MAX);
6649 6656 break;
6650 6657 default:
6651 6658 msg(EXT, "Impossible header type.");
6652 6659 }
6653 6660 } else { /* directory must be specified */
6654 6661 if (largc != 1)
6655 6662 Error_cnt++;
6656 6663 else if (access(*largv, 2) < 0 && (errno != EACCES))
6657 6664 /*
6658 6665 * EACCES is ignored here as it may occur
6659 6666 * when any directory component of the path
6660 6667 * does not have write permission, even though
6661 6668 * the destination subdirectory has write
6662 6669 * access. Writing to a read only directory
6663 6670 * is handled later, as in "copy in" mode.
6664 6671 */
6665 6672 msg(ERRN,
6666 6673 "Error during access() of \"%s\"", *largv);
6667 6674 }
6668 6675 }
6669 6676 if (Error_cnt)
6670 6677 usage(); /* exits! */
6671 6678 if (Args & (OCi | OCo)) {
6672 6679 if (!Dflag) {
6673 6680 if (Args & (OCB | OCC)) {
6674 6681 if (g_init(&Device, &Archive) < 0)
6675 6682 msg(EXTN,
6676 6683 "Error during initialization");
6677 6684 } else {
6678 6685 if ((Bufsize = g_init(&Device, &Archive)) < 0)
6679 6686 msg(EXTN,
6680 6687 "Error during initialization");
6681 6688 }
6682 6689 }
6683 6690
6684 6691 blk_cnt_max = _20K / Bufsize;
6685 6692 if (blk_cnt_max < MX_BUFS) {
6686 6693 blk_cnt_max = MX_BUFS;
6687 6694 }
6688 6695
6689 6696 Buffr.b_base_p = NULL;
6690 6697
6691 6698 for (blk_cnt = blk_cnt_max; blk_cnt > 1; blk_cnt--) {
6692 6699 Buffr.b_size = (size_t)(Bufsize * blk_cnt);
6693 6700 Buffr.b_base_p = e_valloc(E_NORMAL, Buffr.b_size);
6694 6701 if (Buffr.b_base_p != NULL) {
6695 6702 break;
6696 6703 }
6697 6704 }
6698 6705 if (Buffr.b_base_p == NULL || Buffr.b_size < (2 * CPIOBSZ)) {
6699 6706 msg(EXT, "Out of memory");
6700 6707 }
6701 6708
6702 6709 Buffr.b_out_p = Buffr.b_in_p = Buffr.b_base_p;
6703 6710 Buffr.b_cnt = 0L;
6704 6711 Buffr.b_end_p = Buffr.b_base_p + Buffr.b_size;
6705 6712 }
6706 6713
6707 6714 /*
6708 6715 * Now that Bufsize has stabilized, we can allocate our i/o buffer
6709 6716 */
6710 6717 Buf_p = e_valloc(E_EXIT, Bufsize);
6711 6718
6712 6719 if (Args & OCp) { /* get destination directory */
6713 6720 (void) strcpy(Fullnam_p, *largv);
6714 6721 if (stat(Fullnam_p, &DesSt) < 0)
6715 6722 msg(EXTN, "Error during stat() of \"%s\"", Fullnam_p);
6716 6723 if ((DesSt.st_mode & Ftype) != S_IFDIR)
6717 6724 msg(EXT, "\"%s\" is not a directory", Fullnam_p);
6718 6725 }
6719 6726 Full_p = Fullnam_p + strlen(Fullnam_p) - 1;
6720 6727 if (*Full_p != '/') {
6721 6728 Full_p++;
6722 6729 *Full_p = '/';
6723 6730 }
6724 6731 Full_p++;
6725 6732 *Full_p = '\0';
6726 6733 (void) strcpy(Lnknam_p, Fullnam_p);
6727 6734 Lnkend_p = Lnknam_p + strlen(Lnknam_p);
6728 6735 (void) getrlimit(RLIMIT_FSIZE, &rlim);
6729 6736 Max_filesz = (off_t)rlim.rlim_cur;
6730 6737 Lnk_hd.L_nxt_p = Lnk_hd.L_bck_p = &Lnk_hd;
6731 6738 Lnk_hd.L_lnk_p = NULL;
6732 6739 }
6733 6740
6734 6741 /*
6735 6742 * set_tym: Set the access and/or modification times for a file.
6736 6743 */
6737 6744
6738 6745 static void
6739 6746 set_tym(int dirfd, char *nam_p, time_t atime, time_t mtime)
6740 6747 {
6741 6748 struct timeval times[2];
6742 6749
6743 6750 times[0].tv_sec = atime;
6744 6751 times[0].tv_usec = 0;
6745 6752 times[1].tv_sec = mtime;
6746 6753 times[1].tv_usec = 0;
6747 6754
6748 6755 if (futimesat(dirfd, nam_p, times) < 0) {
6749 6756 if (Args & OCa) {
6750 6757 msg(ERRN,
6751 6758 "Unable to reset access time for \"%s%s%s\"",
6752 6759 (G_p->g_attrnam_p == NULL) ? nam_p : Fullnam_p,
6753 6760 (G_p->g_attrnam_p == NULL) ? "" :
6754 6761 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6755 6762 gettext(" Attribute "),
6756 6763 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
6757 6764 } else {
6758 6765 msg(ERRN,
6759 6766 "Unable to reset modification time for \"%s%s%s\"",
6760 6767 (G_p->g_attrnam_p == NULL) ? nam_p : Fullnam_p,
6761 6768 (G_p->g_attrnam_p == NULL) ? "" :
6762 6769 G_p->g_rw_sysattr ? gettext(" System Attribute ") :
6763 6770 gettext(" Attribute "),
6764 6771 (G_p->g_attrnam_p == NULL) ? "" : nam_p);
6765 6772 }
6766 6773 }
6767 6774 }
6768 6775
6769 6776 /*
6770 6777 * sigint: Catch interrupts. If an interrupt occurs during the extraction
6771 6778 * of a file from the archive with the -u option set, and the filename did
6772 6779 * exist, remove the current file and restore the original file. Then exit.
6773 6780 */
6774 6781
6775 6782 /*ARGSUSED*/
6776 6783 static void
6777 6784 sigint(int sig)
6778 6785 {
6779 6786 char *nam_p;
6780 6787
6781 6788 (void) signal(SIGINT, SIG_IGN); /* block further signals */
6782 6789 if (!Finished) {
6783 6790 if (Args & OCi)
6784 6791 nam_p = G_p->g_nam_p;
6785 6792 else /* OCp */
6786 6793 nam_p = Fullnam_p;
6787 6794 if (*Over_p != '\0') { /* There is a temp file */
6788 6795 if (unlink(nam_p) < 0) {
6789 6796 msg(ERRN,
6790 6797 "Cannot remove incomplete \"%s\"", nam_p);
6791 6798 }
6792 6799 if (rename(Over_p, nam_p) < 0) {
6793 6800 if (link(Over_p, nam_p) < 0) {
6794 6801 msg(ERRN,
6795 6802 "Cannot recover original \"%s\"",
6796 6803 nam_p);
6797 6804 }
6798 6805 if (unlink(Over_p)) {
6799 6806 msg(ERRN,
6800 6807 "Cannot remove temp file \"%s\"",
6801 6808 Over_p);
6802 6809 }
6803 6810 }
6804 6811 } else if (unlink(nam_p))
6805 6812 msg(ERRN,
6806 6813 "Cannot remove incomplete \"%s\"", nam_p);
6807 6814 *Over_p = '\0';
6808 6815 }
6809 6816 exit(EXIT_CODE);
6810 6817 }
6811 6818
6812 6819 /*
6813 6820 * swap: Swap bytes (-s), halfwords (-S) or or both halfwords and bytes (-b).
6814 6821 */
6815 6822
6816 6823 static void
6817 6824 swap(char *buf_p, int cnt)
6818 6825 {
6819 6826 unsigned char tbyte;
6820 6827 int tcnt;
6821 6828 int rcnt;
6822 6829 ushort_t thalf;
6823 6830
6824 6831 rcnt = cnt % 4;
6825 6832 cnt /= 4;
6826 6833 if (Args & (OCb | OCs | BSM)) {
6827 6834 tcnt = cnt;
6828 6835 /* LINTED alignment */
6829 6836 Swp_p = (union swpbuf *)buf_p;
6830 6837 while (tcnt-- > 0) {
6831 6838 tbyte = Swp_p->s_byte[0];
6832 6839 Swp_p->s_byte[0] = Swp_p->s_byte[1];
6833 6840 Swp_p->s_byte[1] = tbyte;
6834 6841 tbyte = Swp_p->s_byte[2];
6835 6842 Swp_p->s_byte[2] = Swp_p->s_byte[3];
6836 6843 Swp_p->s_byte[3] = tbyte;
6837 6844 Swp_p++;
6838 6845 }
6839 6846 if (rcnt >= 2) {
6840 6847 tbyte = Swp_p->s_byte[0];
6841 6848 Swp_p->s_byte[0] = Swp_p->s_byte[1];
6842 6849 Swp_p->s_byte[1] = tbyte;
6843 6850 tbyte = Swp_p->s_byte[2];
6844 6851 }
6845 6852 }
6846 6853 if (Args & (OCb | OCS)) {
6847 6854 tcnt = cnt;
6848 6855 /* LINTED alignment */
6849 6856 Swp_p = (union swpbuf *)buf_p;
6850 6857 while (tcnt-- > 0) {
6851 6858 thalf = Swp_p->s_half[0];
6852 6859 Swp_p->s_half[0] = Swp_p->s_half[1];
6853 6860 Swp_p->s_half[1] = thalf;
6854 6861 Swp_p++;
6855 6862 }
6856 6863 }
6857 6864 }
6858 6865
6859 6866 /*
↓ open down ↓ |
379 lines elided |
↑ open up ↑ |
6860 6867 * usage: Print the usage message on stderr and exit.
6861 6868 */
6862 6869
6863 6870 static void
6864 6871 usage(void)
6865 6872 {
6866 6873
6867 6874 (void) fflush(stdout);
6868 6875 #if defined(O_XATTR)
6869 6876 (void) fprintf(stderr, gettext("USAGE:\n"
6870 - "\tcpio -i[bcdfkmrstuv@BSV6] [-C size] "
6877 + "\tcpio -i[bcdfkmqrstuv@BSV6] [-C size] "
6871 6878 "[-E file] [-H hdr] [-I file [-M msg]] "
6872 6879 "[-R id] [patterns]\n"
6873 6880 "\tcpio -o[acv@ABLV] [-C size] "
6874 6881 "[-H hdr] [-O file [-M msg]]\n"
6875 6882 "\tcpio -p[adlmuv@LV] [-R id] directory\n"));
6876 6883 #else
6877 6884 (void) fprintf(stderr, gettext("USAGE:\n"
6878 - "\tcpio -i[bcdfkmrstuvBSV6] [-C size] "
6885 + "\tcpio -i[bcdfkmqrstuvBSV6] [-C size] "
6879 6886 "[-E file] [-H hdr] [-I file [-M msg]] "
6880 6887 "[-R id] [patterns]\n"
6881 6888 "\tcpio -o[acvABLV] [-C size] "
6882 6889 "[-H hdr] [-O file [-M msg]]\n"
6883 6890 "\tcpio -p[adlmuvLV] [-R id] directory\n"));
6884 6891 #endif
6885 6892 (void) fflush(stderr);
6886 6893 exit(EXIT_CODE);
6887 6894 }
6888 6895
6889 6896 /*
6890 6897 * verbose: For each file, print either the filename (-v) or a dot (-V).
6891 6898 * If the -t option (table of contents) is set, print either the filename,
6892 6899 * or if the -v option is also set, print an "ls -l"-like listing.
6893 6900 */
6894 6901
6895 6902 static void
6896 6903 verbose(char *nam_p)
6897 6904 {
6898 6905 int i, j, temp;
6899 6906 mode_t mode;
6900 6907 char modestr[12];
6901 6908 time_t ttime;
6902 6909
6903 6910 /*
6904 6911 * The printf format and associated arguments to print the current
6905 6912 * filename. Normally, just nam_p. If we're processing an extended
6906 6913 * attribute, these are overridden.
6907 6914 */
6908 6915 char *name_fmt = "%s";
6909 6916 const char *name = nam_p;
6910 6917 const char *attribute = NULL;
6911 6918
6912 6919 if (Gen.g_attrnam_p != NULL) {
6913 6920 /*
6914 6921 * Translation note:
6915 6922 * 'attribute' is a noun.
6916 6923 */
6917 6924
6918 6925 if (Gen.g_rw_sysattr) {
6919 6926 name_fmt = gettext("%s system attribute %s");
6920 6927 } else if ((Args & OCt) &&
6921 6928 (is_sysattr(basename(Gen.g_attrnam_p)))) {
6922 6929 name_fmt = gettext("%s system attribute %s");
6923 6930 } else {
6924 6931 name_fmt = gettext("%s attribute %s");
6925 6932 }
6926 6933
6927 6934 name = (Args & OCp) ? nam_p : Gen.g_attrfnam_p;
6928 6935 if (Gen.g_attrparent_p == NULL) {
6929 6936 attribute = Gen.g_attrnam_p;
6930 6937 } else {
6931 6938 attribute = Gen.g_attrpath_p;
6932 6939 }
6933 6940 }
6934 6941
6935 6942 if ((Gen.g_mode == SECMODE) || ((Hdr_type == USTAR ||
6936 6943 Hdr_type == TAR) && Thdr_p->tbuf.t_typeflag == 'A')) {
6937 6944 /* dont print ancillary file */
6938 6945 aclchar = '+';
6939 6946 return;
6940 6947 }
6941 6948 for (i = 0; i < 11; i++)
6942 6949 modestr[i] = '-';
6943 6950 modestr[i] = '\0';
6944 6951 modestr[i-1] = aclchar;
6945 6952 aclchar = ' ';
6946 6953
6947 6954 if ((Args & OCt) && (Args & OCv)) {
6948 6955 mode = Gen.g_mode;
6949 6956 for (i = 0; i < 3; i++) {
6950 6957 temp = (mode >> (6 - (i * 3)));
6951 6958 j = (i * 3) + 1;
6952 6959 if (S_IROTH & temp)
6953 6960 modestr[j] = 'r';
6954 6961 if (S_IWOTH & temp)
6955 6962 modestr[j + 1] = 'w';
6956 6963 if (S_IXOTH & temp)
6957 6964 modestr[j + 2] = 'x';
6958 6965 }
6959 6966
6960 6967 if (Hdr_type != BAR) {
6961 6968 temp = Gen.g_mode & Ftype;
6962 6969 switch (temp) {
6963 6970 case (S_IFIFO):
6964 6971 modestr[0] = 'p';
6965 6972 break;
6966 6973 case (S_IFSOCK):
6967 6974 modestr[0] = 's';
6968 6975 break;
6969 6976 case (S_IFCHR):
6970 6977 modestr[0] = 'c';
6971 6978 break;
6972 6979 case (S_IFDIR):
6973 6980 modestr[0] = 'd';
6974 6981 break;
6975 6982 case (S_IFBLK):
6976 6983 modestr[0] = 'b';
6977 6984 break;
6978 6985 case (S_IFREG): /* was initialized to '-' */
6979 6986 break;
6980 6987 case (S_IFLNK):
6981 6988 modestr[0] = 'l';
6982 6989 break;
6983 6990 default:
6984 6991 msg(ERR, "Impossible file type");
6985 6992 }
6986 6993 } else { /* bar */
6987 6994 temp = Gen.g_mode & Ftype;
6988 6995 switch (temp) {
6989 6996 case (S_IFIFO):
6990 6997 modestr[0] = 'p';
6991 6998 break;
6992 6999 case (S_IFSOCK):
6993 7000 modestr[0] = 's';
6994 7001 break;
6995 7002 case (S_IFCHR):
6996 7003 modestr[0] = 'c';
6997 7004 break;
6998 7005 case (S_IFDIR):
6999 7006 modestr[0] = 'd';
7000 7007 break;
7001 7008 case (S_IFBLK):
7002 7009 modestr[0] = 'b';
7003 7010 break;
7004 7011 }
7005 7012 if (bar_linkflag == SYMTYPE)
7006 7013 modestr[0] = 'l';
7007 7014 }
7008 7015 if ((S_ISUID & Gen.g_mode) == S_ISUID)
7009 7016 modestr[3] = 's';
7010 7017 if ((S_ISVTX & Gen.g_mode) == S_ISVTX)
7011 7018 modestr[9] = 't';
7012 7019 if ((S_ISGID & G_p->g_mode) == S_ISGID && modestr[6] == 'x')
7013 7020 modestr[6] = 's';
7014 7021 else if ((S_ENFMT & Gen.g_mode) == S_ENFMT && modestr[6] != 'x')
7015 7022 modestr[6] = 'l';
7016 7023 if ((Hdr_type == TAR || Hdr_type == USTAR) && Gen.g_nlink == 0)
7017 7024 (void) printf("%s%4d ", modestr, (int)Gen.g_nlink+1);
7018 7025 else
7019 7026 (void) printf("%s%4d ", modestr, (int)Gen.g_nlink);
7020 7027 if (Lastuid == (uid_t)Gen.g_uid) {
7021 7028 if (Lastuid == (uid_t)-1)
7022 7029 (void) printf("-1 ");
7023 7030 else
7024 7031 (void) printf("%-9s", Curpw_p->pw_name);
7025 7032 } else {
7026 7033 if (Curpw_p = getpwuid((int)Gen.g_uid)) {
7027 7034 (void) printf("%-9s", Curpw_p->pw_name);
7028 7035 Lastuid = (uid_t)Gen.g_uid;
7029 7036 } else {
7030 7037 (void) printf("%-9d", (int)Gen.g_uid);
7031 7038 Lastuid = (uid_t)-1;
7032 7039 }
7033 7040 }
7034 7041 if (Lastgid == (gid_t)Gen.g_gid) {
7035 7042 if (Lastgid == (gid_t)-1)
7036 7043 (void) printf("-1 ");
7037 7044 else
7038 7045 (void) printf("%-9s", Curgr_p->gr_name);
7039 7046 } else {
7040 7047 if (Curgr_p = getgrgid((int)Gen.g_gid)) {
7041 7048 (void) printf("%-9s", Curgr_p->gr_name);
7042 7049 Lastgid = (gid_t)Gen.g_gid;
7043 7050 } else {
7044 7051 (void) printf("%-9d", (int)Gen.g_gid);
7045 7052 Lastgid = (gid_t)-1;
7046 7053 }
7047 7054 }
7048 7055
7049 7056 /* print file size */
7050 7057 if (!Aspec || ((Gen.g_mode & Ftype) == S_IFIFO) ||
7051 7058 ((Gen.g_mode & Ftype) == S_IFSOCK) ||
7052 7059 (Hdr_type == BAR && bar_linkflag == SYMTYPE)) {
7053 7060 off_t filesz = Gen.g_filesz;
7054 7061
7055 7062 if (S_ISSPARSE(Gen.g_mode) && Gen.g_holes != NULL)
7056 7063 filesz = Gen.g_holes->orig_size;
7057 7064
7058 7065 if (filesz < (1LL << 31))
7059 7066 (void) printf("%7lld ", (offset_t)filesz);
7060 7067 else
7061 7068 (void) printf("%11lld ", (offset_t)filesz);
7062 7069 } else
7063 7070 (void) printf("%3d,%3d ", (int)major(Gen.g_rdev),
7064 7071 (int)minor(Gen.g_rdev));
7065 7072 ttime = Gen.g_mtime;
7066 7073 (void) strftime(Time, sizeof (Time),
7067 7074 dcgettext(NULL, FORMAT, LC_TIME), localtime(&ttime));
7068 7075 (void) printf("%s, ", Time);
7069 7076 str_fprintf(stdout, name_fmt, name, attribute);
7070 7077 if ((Gen.g_mode & Ftype) == S_IFLNK) {
7071 7078 if (Hdr_type == USTAR || Hdr_type == TAR)
7072 7079 (void) strcpy(Symlnk_p,
7073 7080 Thdr_p->tbuf.t_linkname);
7074 7081 else {
7075 7082 FILL(Gen.g_filesz);
7076 7083 (void) strncpy(Symlnk_p, Buffr.b_out_p,
7077 7084 Gen.g_filesz);
7078 7085 *(Symlnk_p + Gen.g_filesz) = '\0';
7079 7086 }
7080 7087 (void) printf(" -> %s", Symlnk_p);
7081 7088 }
7082 7089 if (Hdr_type == BAR) {
7083 7090 if (bar_linkflag == SYMTYPE)
7084 7091 (void) printf(gettext(" symbolic link to %s"),
7085 7092 bar_linkname);
7086 7093 else if (bar_linkflag == '1')
7087 7094 (void) printf(gettext(" linked to %s"),
7088 7095 bar_linkname);
7089 7096 }
7090 7097 if ((Hdr_type == USTAR || Hdr_type == TAR) &&
7091 7098 Thdr_p->tbuf.t_typeflag == '1') {
7092 7099 (void) printf(gettext(" linked to %s%s%s"),
7093 7100 (Gen.g_attrnam_p == NULL) ?
7094 7101 Thdr_p->tbuf.t_linkname : Gen.g_attrfnam_p,
7095 7102 (Gen.g_attrnam_p == NULL) ? "" :
7096 7103 gettext(" attribute "),
7097 7104 (Gen.g_attrnam_p == NULL) ?
7098 7105 "" : Gen.g_linktoattrnam_p);
7099 7106 }
7100 7107 (void) printf("\n");
7101 7108 } else if ((Args & OCt) || (Args & OCv)) {
7102 7109 str_fprintf(Out_p, name_fmt, name, attribute);
7103 7110 (void) fputc('\n', Out_p);
7104 7111 } else { /* OCV */
7105 7112 (void) fputc('.', Out_p);
7106 7113 if (Verbcnt++ >= 49) { /* start a new line of dots */
7107 7114 Verbcnt = 0;
7108 7115 (void) fputc('\n', Out_p);
7109 7116 }
7110 7117 }
7111 7118 (void) fflush(Out_p);
7112 7119 }
7113 7120
7114 7121 #define MK_USHORT(a) (a & 00000177777)
7115 7122
7116 7123 /*
7117 7124 * write_hdr: Transfer header information for the generic structure
7118 7125 * into the format for the selected header and bwrite() the header.
7119 7126 */
7120 7127
7121 7128 static void
7122 7129 write_hdr(int arcflag, off_t len)
7123 7130 {
7124 7131 int cnt, pad;
7125 7132 mode_t mode;
7126 7133 uid_t uid;
7127 7134 gid_t gid;
7128 7135 const char warnfmt[] = "%s%s%s : %s";
7129 7136
7130 7137 switch (arcflag) {
7131 7138 case ARCHIVE_ACL:
7132 7139 mode = SECMODE;
7133 7140 break;
7134 7141
7135 7142 case ARCHIVE_XATTR:
7136 7143 case ARCHIVE_NORMAL:
7137 7144 /*
7138 7145 * If attribute is being archived in cpio format then
7139 7146 * zap off the file type bits since those are truly a
7140 7147 * mask and reset them with _XATTR_CPIO_MODE
7141 7148 */
7142 7149 /*
7143 7150 * len is the value of g_filesz for normal files
7144 7151 * and the length of the special header buffer in
7145 7152 * the case of acl and xattr headers.
7146 7153 */
7147 7154 if (G_p->g_attrnam_p != NULL && Hdr_type != USTAR &&
7148 7155 Hdr_type != TAR) {
7149 7156 mode = (G_p->g_mode & POSIXMODES) | _XATTR_CPIO_MODE;
7150 7157 } else {
7151 7158 mode = G_p->g_mode;
7152 7159 }
7153 7160 if (arcflag != ARCHIVE_XATTR) {
7154 7161 len = G_p->g_filesz;
7155 7162 }
7156 7163 break;
7157 7164
7158 7165 case ARCHIVE_SPARSE:
7159 7166 mode = G_p->g_mode | C_ISSPARSE;
7160 7167 len = G_p->g_filesz;
7161 7168 break;
7162 7169 }
7163 7170
7164 7171 uid = G_p->g_uid;
7165 7172 gid = G_p->g_gid;
7166 7173 /*
7167 7174 * Handle EFT uids and gids. If they get too big
7168 7175 * to be represented in a particular format, force 'em to 'nobody'.
7169 7176 */
7170 7177 switch (Hdr_type) {
7171 7178 case BIN: /* 16-bits of u_short */
7172 7179 if ((ulong_t)uid > (ulong_t)USHRT_MAX)
7173 7180 uid = UID_NOBODY;
7174 7181 if ((ulong_t)gid > (ulong_t)USHRT_MAX)
7175 7182 gid = GID_NOBODY;
7176 7183 break;
7177 7184 case CHR: /* %.6lo => 262143 base 10 */
7178 7185 if ((ulong_t)uid > (ulong_t)0777777)
7179 7186 uid = UID_NOBODY;
7180 7187 if ((ulong_t)gid > (ulong_t)0777777)
7181 7188 gid = GID_NOBODY;
7182 7189 break;
7183 7190 case ASC: /* %.8lx => full 32 bits */
7184 7191 case CRC:
7185 7192 break;
7186 7193 case USTAR:
7187 7194 case TAR: /* %.7lo => 2097151 base 10 */
7188 7195 if ((ulong_t)uid > (ulong_t)07777777)
7189 7196 uid = UID_NOBODY;
7190 7197 if ((ulong_t)gid > (ulong_t)07777777)
7191 7198 gid = GID_NOBODY;
7192 7199 break;
7193 7200 default:
7194 7201 msg(EXT, "Impossible header type.");
7195 7202 }
7196 7203
7197 7204 /*
7198 7205 * Since cpio formats -don't- encode the symbolic names, print
7199 7206 * a warning message when we map the uid or gid this way.
7200 7207 * Also, if the ownership just changed, clear set[ug]id bits
7201 7208 *
7202 7209 * (Except for USTAR format of course, where we have a string
7203 7210 * representation of the username embedded in the header)
7204 7211 */
7205 7212 if (uid != G_p->g_uid && Hdr_type != USTAR) {
7206 7213 msg(ERR, warnfmt,
7207 7214 (G_p->g_attrnam_p == NULL) ?
7208 7215 G_p->g_nam_p : G_p->g_attrfnam_p,
7209 7216 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
7210 7217 gettext(" System Attribute ") : gettext(" Attribute "),
7211 7218 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p,
7212 7219 gettext("uid too large for archive format"));
7213 7220 if (S_ISREG(mode))
7214 7221 mode &= ~S_ISUID;
7215 7222 }
7216 7223 if (gid != G_p->g_gid && Hdr_type != USTAR) {
7217 7224 msg(ERR, warnfmt,
7218 7225 (G_p->g_attrnam_p == NULL) ?
7219 7226 G_p->g_nam_p : G_p->g_attrfnam_p,
7220 7227 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_rw_sysattr ?
7221 7228 gettext(" System Attribute ") : gettext(" Attribute "),
7222 7229 (G_p->g_attrnam_p == NULL) ? "" : G_p->g_attrnam_p,
7223 7230 gettext("gid too large for archive format"));
7224 7231 if (S_ISREG(mode))
7225 7232 mode &= ~S_ISGID;
7226 7233 }
7227 7234
7228 7235 switch (Hdr_type) {
7229 7236 case BIN:
7230 7237 case CHR:
7231 7238 case ASC:
7232 7239 case CRC:
7233 7240 cnt = Hdrsz + G_p->g_namesz;
7234 7241 break;
7235 7242 case TAR:
7236 7243 /*FALLTHROUGH*/
7237 7244 case USTAR: /* TAR and USTAR */
7238 7245 cnt = TARSZ;
7239 7246 break;
7240 7247 default:
7241 7248 msg(EXT, "Impossible header type.");
7242 7249 }
7243 7250 FLUSH(cnt);
7244 7251
7245 7252 switch (Hdr_type) {
7246 7253 case BIN:
7247 7254 Hdr.h_magic = (short)G_p->g_magic;
7248 7255 Hdr.h_dev = G_p->g_dev;
7249 7256 Hdr.h_ino = G_p->g_ino;
7250 7257 Hdr.h_uid = uid;
7251 7258 Hdr.h_gid = gid;
7252 7259 Hdr.h_mode = mode;
7253 7260 Hdr.h_nlink = G_p->g_nlink;
7254 7261 Hdr.h_rdev = G_p->g_rdev;
7255 7262 mkshort(Hdr.h_mtime, (long)G_p->g_mtime);
7256 7263 Hdr.h_namesize = (short)G_p->g_namesz;
7257 7264 mkshort(Hdr.h_filesize, (long)len);
7258 7265 (void) strcpy(Hdr.h_name, G_p->g_nam_p);
7259 7266 (void) memcpy(Buffr.b_in_p, &Hdr, cnt);
7260 7267 break;
7261 7268 case CHR:
7262 7269 /*LINTED*/
7263 7270 (void) sprintf(Buffr.b_in_p,
7264 7271 "%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.6lo%.11lo%.6lo%."
7265 7272 "11llo%s", G_p->g_magic, G_p->g_dev, G_p->g_ino, mode,
7266 7273 (long)uid, (long)gid, G_p->g_nlink, MK_USHORT(G_p->g_rdev),
7267 7274 G_p->g_mtime, (long)G_p->g_namesz, (offset_t)len,
7268 7275 G_p->g_nam_p);
7269 7276 break;
7270 7277 case ASC:
7271 7278 case CRC:
7272 7279 /*LINTED*/
7273 7280 (void) sprintf(Buffr.b_in_p,
7274 7281 "%.6lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%.8lx%."
7275 7282 "8lx%.8lx%.8lx%.8lx%s",
7276 7283 G_p->g_magic, G_p->g_ino, mode, G_p->g_uid,
7277 7284 G_p->g_gid, G_p->g_nlink, G_p->g_mtime, (ulong_t)len,
7278 7285 major(G_p->g_dev), minor(G_p->g_dev),
7279 7286 major(G_p->g_rdev), minor(G_p->g_rdev),
7280 7287 G_p->g_namesz, G_p->g_cksum, G_p->g_nam_p);
7281 7288 break;
7282 7289 case USTAR:
7283 7290 Thdr_p = (union tblock *)Buffr.b_in_p;
7284 7291 (void) memset(Thdr_p, 0, TARSZ);
7285 7292 (void) strncpy(Thdr_p->tbuf.t_name, G_p->g_tname,
7286 7293 (int)strlen(G_p->g_tname));
7287 7294 (void) sprintf(Thdr_p->tbuf.t_mode, "%07o", (int)mode);
7288 7295 (void) sprintf(Thdr_p->tbuf.t_uid, "%07o", (int)uid);
7289 7296 (void) sprintf(Thdr_p->tbuf.t_gid, "%07o", (int)gid);
7290 7297 (void) sprintf(Thdr_p->tbuf.t_size, "%011llo",
7291 7298 (offset_t)len);
7292 7299 (void) sprintf(Thdr_p->tbuf.t_mtime, "%011lo", G_p->g_mtime);
7293 7300 if (arcflag == ARCHIVE_ACL) {
7294 7301 Thdr_p->tbuf.t_typeflag = 'A'; /* ACL file type */
7295 7302 } else if (arcflag == ARCHIVE_XATTR ||
7296 7303 (G_p->g_attrnam_p != NULL)) {
7297 7304 Thdr_p->tbuf.t_typeflag = _XATTR_HDRTYPE;
7298 7305 } else {
7299 7306 Thdr_p->tbuf.t_typeflag = G_p->g_typeflag;
7300 7307 }
7301 7308 if (T_lname[0] != '\0') {
7302 7309 /*
7303 7310 * if not a symbolic link
7304 7311 */
7305 7312 if (((G_p->g_mode & Ftype) != S_IFLNK) &&
7306 7313 (G_p->g_attrnam_p == NULL)) {
7307 7314 Thdr_p->tbuf.t_typeflag = LNKTYPE;
7308 7315 (void) sprintf(Thdr_p->tbuf.t_size,
7309 7316 "%011lo", 0L);
7310 7317 }
7311 7318 (void) strncpy(Thdr_p->tbuf.t_linkname, T_lname,
7312 7319 strlen(T_lname));
7313 7320 }
7314 7321 (void) strcpy(Thdr_p->tbuf.t_magic, TMAGIC);
7315 7322 (void) strcpy(Thdr_p->tbuf.t_version, TVERSION);
7316 7323 (void) strcpy(Thdr_p->tbuf.t_uname, G_p->g_uname);
7317 7324 (void) strcpy(Thdr_p->tbuf.t_gname, G_p->g_gname);
7318 7325 (void) sprintf(Thdr_p->tbuf.t_devmajor, "%07o",
7319 7326 (int)major(G_p->g_rdev));
7320 7327 (void) sprintf(Thdr_p->tbuf.t_devminor, "%07o",
7321 7328 (int)minor(G_p->g_rdev));
7322 7329 if (Gen.g_prefix) {
7323 7330 (void) strcpy(Thdr_p->tbuf.t_prefix, Gen.g_prefix);
7324 7331 free(Gen.g_prefix);
7325 7332 Gen.g_prefix = NULL;
7326 7333 } else {
7327 7334 Thdr_p->tbuf.t_prefix[0] = '\0';
7328 7335 }
7329 7336 (void) sprintf(Thdr_p->tbuf.t_cksum, "%07o",
7330 7337 (int)cksum(TARTYP, 0, NULL));
7331 7338 break;
7332 7339 case TAR:
7333 7340 Thdr_p = (union tblock *)Buffr.b_in_p;
7334 7341 (void) memset(Thdr_p, 0, TARSZ);
7335 7342 (void) strncpy(Thdr_p->tbuf.t_name, G_p->g_nam_p,
7336 7343 G_p->g_namesz);
7337 7344 (void) sprintf(Thdr_p->tbuf.t_mode, "%07o ", (int)mode);
7338 7345 (void) sprintf(Thdr_p->tbuf.t_uid, "%07o ", (int)uid);
7339 7346 (void) sprintf(Thdr_p->tbuf.t_gid, "%07o ", (int)gid);
7340 7347 (void) sprintf(Thdr_p->tbuf.t_size, "%011llo ",
7341 7348 (offset_t)len);
7342 7349 (void) sprintf(Thdr_p->tbuf.t_mtime, "%011o ",
7343 7350 (int)G_p->g_mtime);
7344 7351 if (T_lname[0] != '\0') {
7345 7352 Thdr_p->tbuf.t_typeflag = '1';
7346 7353 } else {
7347 7354 Thdr_p->tbuf.t_typeflag = '\0';
7348 7355 }
7349 7356 (void) strncpy(Thdr_p->tbuf.t_linkname, T_lname,
7350 7357 strlen(T_lname));
7351 7358 break;
7352 7359 default:
7353 7360 msg(EXT, "Impossible header type.");
7354 7361 } /* Hdr_type */
7355 7362
7356 7363 Buffr.b_in_p += cnt;
7357 7364 Buffr.b_cnt += cnt;
7358 7365 pad = ((cnt + Pad_val) & ~Pad_val) - cnt;
7359 7366 if (pad != 0) {
7360 7367 FLUSH(pad);
7361 7368 (void) memset(Buffr.b_in_p, 0, pad);
7362 7369 Buffr.b_in_p += pad;
7363 7370 Buffr.b_cnt += pad;
7364 7371 }
7365 7372 }
7366 7373
7367 7374 /*
7368 7375 * write_trail: Create the appropriate trailer for the selected header type
7369 7376 * and bwrite the trailer. Pad the buffer with nulls out to the next Bufsize
7370 7377 * boundary, and force a write. If the write completes, or if the trailer is
7371 7378 * completely written (but not all of the padding nulls (as can happen on end
7372 7379 * of medium)) return. Otherwise, the trailer was not completely written out,
7373 7380 * so re-pad the buffer with nulls and try again.
7374 7381 */
7375 7382
7376 7383 static void
7377 7384 write_trail(void)
7378 7385 {
7379 7386 int cnt, need;
7380 7387
7381 7388 switch (Hdr_type) {
7382 7389 case BIN:
7383 7390 Gen.g_magic = CMN_BIN;
7384 7391 break;
7385 7392 case CHR:
7386 7393 Gen.g_magic = CMN_BIN;
7387 7394 break;
7388 7395 case ASC:
7389 7396 Gen.g_magic = CMN_ASC;
7390 7397 break;
7391 7398 case CRC:
7392 7399 Gen.g_magic = CMN_CRC;
7393 7400 break;
7394 7401 }
7395 7402
7396 7403 switch (Hdr_type) {
7397 7404 case BIN:
7398 7405 case CHR:
7399 7406 case ASC:
7400 7407 case CRC:
7401 7408 Gen.g_mode = Gen.g_uid = Gen.g_gid = 0;
7402 7409 Gen.g_nlink = 1;
7403 7410 Gen.g_mtime = Gen.g_ino = Gen.g_dev = 0;
7404 7411 Gen.g_rdev = Gen.g_cksum = 0;
7405 7412 Gen.g_filesz = (off_t)0;
7406 7413 Gen.g_namesz = strlen("TRAILER!!!") + 1;
7407 7414 (void) strcpy(Gen.g_nam_p, "TRAILER!!!");
7408 7415 G_p = &Gen;
7409 7416 write_hdr(ARCHIVE_NORMAL, (off_t)0);
7410 7417 break;
7411 7418 case TAR:
7412 7419 /*FALLTHROUGH*/
7413 7420 case USTAR: /* TAR and USTAR */
7414 7421 for (cnt = 0; cnt < 3; cnt++) {
7415 7422 FLUSH(TARSZ);
7416 7423 (void) memset(Buffr.b_in_p, 0, TARSZ);
7417 7424 Buffr.b_in_p += TARSZ;
7418 7425 Buffr.b_cnt += TARSZ;
7419 7426 }
7420 7427 break;
7421 7428 default:
7422 7429 msg(EXT, "Impossible header type.");
7423 7430 }
7424 7431 need = Bufsize - (Buffr.b_cnt % Bufsize);
7425 7432 if (need == Bufsize)
7426 7433 need = 0;
7427 7434
7428 7435 while (Buffr.b_cnt > 0) {
7429 7436 while (need > 0) {
7430 7437 cnt = (need < TARSZ) ? need : TARSZ;
7431 7438 need -= cnt;
7432 7439 FLUSH(cnt);
7433 7440 (void) memset(Buffr.b_in_p, 0, cnt);
7434 7441 Buffr.b_in_p += cnt;
7435 7442 Buffr.b_cnt += cnt;
7436 7443 }
7437 7444 bflush();
7438 7445 }
7439 7446 }
7440 7447
7441 7448 /*
7442 7449 * if archives in USTAR format, check if typeflag == '5' for directories
7443 7450 */
7444 7451 static int
7445 7452 ustar_dir(void)
7446 7453 {
7447 7454 if (Hdr_type == USTAR || Hdr_type == TAR) {
7448 7455 if (Thdr_p->tbuf.t_typeflag == '5')
7449 7456 return (1);
7450 7457 }
7451 7458 return (0);
7452 7459 }
7453 7460
7454 7461 /*
7455 7462 * if archives in USTAR format, check if typeflag == '3' || '4' || '6'
7456 7463 * for character, block, fifo special files
7457 7464 */
7458 7465 static int
7459 7466 ustar_spec(void)
7460 7467 {
7461 7468 int typeflag;
7462 7469
7463 7470 if (Hdr_type == USTAR || Hdr_type == TAR) {
7464 7471 typeflag = Thdr_p->tbuf.t_typeflag;
7465 7472 if (typeflag == '3' || typeflag == '4' || typeflag == '6')
7466 7473 return (1);
7467 7474 }
7468 7475 return (0);
7469 7476 }
7470 7477
7471 7478 /*
7472 7479 * The return value is a pointer to a converted copy of the information in
7473 7480 * FromStat if the file is representable in -Hodc format, and NULL otherwise.
7474 7481 */
7475 7482
7476 7483 static struct stat *
7477 7484 convert_to_old_stat(struct stat *FromStat, char *namep, char *attrp)
7478 7485 {
7479 7486 static struct stat ToSt;
7480 7487 cpioinfo_t TmpSt;
7481 7488
7482 7489 (void) memset(&TmpSt, 0, sizeof (cpioinfo_t));
7483 7490 stat_to_svr32_stat(&TmpSt, FromStat);
7484 7491 (void) memset(&ToSt, 0, sizeof (ToSt));
7485 7492
7486 7493 if (TmpSt.st_rdev == (o_dev_t)NODEV &&
7487 7494 (((TmpSt.st_mode & Ftype) == S_IFCHR) ||
7488 7495 ((TmpSt.st_mode & Ftype) == S_IFBLK))) {
7489 7496 /*
7490 7497 * Encountered a problem representing the rdev information.
7491 7498 * Don't archive it.
7492 7499 */
7493 7500
7494 7501 msg(ERR, "Error -Hodc format can't support expanded"
7495 7502 "types on %s%s%s",
7496 7503 namep,
7497 7504 (attrp == NULL) ? "" : gettext(" Attribute"),
7498 7505 (attrp == NULL) ? "" : attrp);
7499 7506 return (NULL);
7500 7507 }
7501 7508
7502 7509 if (TmpSt.st_dev == (o_dev_t)NODEV) {
7503 7510 /*
7504 7511 * Having trouble representing the device/inode pair. We can't
7505 7512 * track links in this case; break them all into separate
7506 7513 * files.
7507 7514 */
7508 7515
7509 7516 TmpSt.st_ino = 0;
7510 7517
7511 7518 if (((TmpSt.st_mode & Ftype) != S_IFDIR) &&
7512 7519 TmpSt.st_nlink > 1)
7513 7520 msg(POST,
7514 7521 "Warning: file %s%s%s has large "
7515 7522 "device number - linked "
7516 7523 "files will be restored as "
7517 7524 "separate files",
7518 7525 namep,
7519 7526 (attrp == NULL) ? "" : gettext(" Attribute"),
7520 7527 (attrp == NULL) ? "" : attrp);
7521 7528
7522 7529 /* ensure no links */
7523 7530
7524 7531 TmpSt.st_nlink = 1;
7525 7532 }
7526 7533
7527 7534 /* Start converting values */
7528 7535
7529 7536 if (TmpSt.st_dev < 0) {
7530 7537 ToSt.st_dev = 0;
7531 7538 } else {
7532 7539 ToSt.st_dev = (dev_t)TmpSt.st_dev;
7533 7540 }
7534 7541
7535 7542 /* -actual- not truncated uid */
7536 7543
7537 7544 ToSt.st_uid = TmpSt.st_uid;
7538 7545
7539 7546 /* -actual- not truncated gid */
7540 7547
7541 7548 ToSt.st_gid = TmpSt.st_gid;
7542 7549 ToSt.st_ino = (ino_t)TmpSt.st_ino;
7543 7550 ToSt.st_mode = (mode_t)TmpSt.st_mode;
7544 7551 ToSt.st_mtime = (ulong_t)TmpSt.st_modtime;
7545 7552 ToSt.st_nlink = (nlink_t)TmpSt.st_nlink;
7546 7553 ToSt.st_size = (off_t)TmpSt.st_size;
7547 7554 ToSt.st_rdev = (dev_t)TmpSt.st_rdev;
7548 7555
7549 7556 return (&ToSt);
7550 7557 }
7551 7558
7552 7559 /*
7553 7560 * In the beginning of each bar archive, there is a header which describes the
7554 7561 * current volume being created, followed by a header which describes the
7555 7562 * current file being created, followed by the file itself. If there is
7556 7563 * more than one file to be created, a separate header will be created for
7557 7564 * each additional file. This structure may be repeated if the bar archive
7558 7565 * contains multiple volumes. If a file spans across volumes, its header
7559 7566 * will not be repeated in the next volume.
7560 7567 * +------------------+
7561 7568 * | vol header |
7562 7569 * |------------------|
7563 7570 * | file header i | i = 0
7564 7571 * |------------------|
7565 7572 * | <file i> |
7566 7573 * |------------------|
7567 7574 * | file header i+1 |
7568 7575 * |------------------|
7569 7576 * | <file i+1> |
7570 7577 * |------------------|
7571 7578 * | . |
7572 7579 * | . |
7573 7580 * | . |
7574 7581 * +------------------+
7575 7582 */
7576 7583
7577 7584 /*
7578 7585 * read in the header that describes the current volume of the bar archive
7579 7586 * to be extracted.
7580 7587 */
7581 7588 static void
7582 7589 read_bar_vol_hdr(void)
7583 7590 {
7584 7591 union b_block *tmp_hdr;
7585 7592
7586 7593 tmp_hdr = (union b_block *)Buffr.b_out_p;
7587 7594 if (tmp_hdr->dbuf.bar_magic[0] == BAR_VOLUME_MAGIC) {
7588 7595
7589 7596 if (bar_Vhdr == NULL) {
7590 7597 bar_Vhdr = e_zalloc(E_EXIT, TBLOCK);
7591 7598 }
7592 7599 (void) memcpy(&(bar_Vhdr->dbuf), &(tmp_hdr->dbuf), TBLOCK);
7593 7600 } else {
7594 7601 (void) fprintf(stderr, gettext(
7595 7602 "bar error: cannot read volume header\n"));
7596 7603 exit(1);
7597 7604 }
7598 7605
7599 7606 (void) sscanf(bar_Vhdr->dbuf.mode, "%8lo", &Gen_bar_vol.g_mode);
7600 7607 (void) sscanf(bar_Vhdr->dbuf.uid, "%8d", (int *)&Gen_bar_vol.g_uid);
7601 7608 (void) sscanf(bar_Vhdr->dbuf.gid, "%8d", (int *)&Gen_bar_vol.g_gid);
7602 7609 (void) sscanf(bar_Vhdr->dbuf.size, "%12llo",
7603 7610 (u_off_t *)&Gen_bar_vol.g_filesz);
7604 7611 (void) sscanf(bar_Vhdr->dbuf.mtime, "%12lo", &Gen_bar_vol.g_mtime);
7605 7612 (void) sscanf(bar_Vhdr->dbuf.chksum, "%8lo", &Gen_bar_vol.g_cksum);
7606 7613
7607 7614 /* set the compress flag */
7608 7615 if (bar_Vhdr->dbuf.compressed == '1')
7609 7616 Compressed = 1;
7610 7617 else
7611 7618 Compressed = 0;
7612 7619
7613 7620 Buffr.b_out_p += 512;
7614 7621 Buffr.b_cnt -= 512;
7615 7622
7616 7623 /*
7617 7624 * not the first volume; exit
7618 7625 */
7619 7626 if (strcmp(bar_Vhdr->dbuf.volume_num, "1") != 0) {
7620 7627 (void) fprintf(stderr,
7621 7628 gettext("error: This is not volume 1. "));
7622 7629 (void) fprintf(stderr, gettext("This is volume %s. "),
7623 7630 bar_Vhdr->dbuf.volume_num);
7624 7631 (void) fprintf(stderr, gettext("Please insert volume 1.\n"));
7625 7632 exit(1);
7626 7633 }
7627 7634
7628 7635 read_bar_file_hdr();
7629 7636 }
7630 7637
7631 7638 /*
7632 7639 * read in the header that describes the current file to be extracted
7633 7640 */
7634 7641 static void
7635 7642 read_bar_file_hdr(void)
7636 7643 {
7637 7644 union b_block *tmp_hdr;
7638 7645 char *start_of_name, *name_p;
7639 7646 char *tmp;
7640 7647
7641 7648 if (*Buffr.b_out_p == '\0') {
7642 7649 *Gen.g_nam_p = '\0';
7643 7650 exit(0);
7644 7651 }
7645 7652
7646 7653 tmp_hdr = (union b_block *)Buffr.b_out_p;
7647 7654
7648 7655 tmp = &tmp_hdr->dbuf.mode[1];
7649 7656 (void) sscanf(tmp, "%8lo", &Gen.g_mode);
7650 7657 (void) sscanf(tmp_hdr->dbuf.uid, "%8lo", &Gen.g_uid);
7651 7658 (void) sscanf(tmp_hdr->dbuf.gid, "%8lo", &Gen.g_gid);
7652 7659 (void) sscanf(tmp_hdr->dbuf.size, "%12llo",
7653 7660 (u_off_t *)&Gen.g_filesz);
7654 7661 (void) sscanf(tmp_hdr->dbuf.mtime, "%12lo", &Gen.g_mtime);
7655 7662 (void) sscanf(tmp_hdr->dbuf.chksum, "%8lo", &Gen.g_cksum);
7656 7663 (void) sscanf(tmp_hdr->dbuf.rdev, "%8lo", &Gen.g_rdev);
7657 7664
7658 7665 #define to_new_major(x) (int)((unsigned)((x) & OMAXMAJ) << NBITSMINOR)
7659 7666 #define to_new_minor(x) (int)((x) & OMAXMIN)
7660 7667 Gen.g_rdev = to_new_major(Gen.g_rdev) | to_new_minor(Gen.g_rdev);
7661 7668 bar_linkflag = tmp_hdr->dbuf.linkflag;
7662 7669 start_of_name = &tmp_hdr->dbuf.start_of_name;
7663 7670
7664 7671
7665 7672 name_p = Gen.g_nam_p;
7666 7673 while (*name_p++ = *start_of_name++)
7667 7674 ;
7668 7675 *name_p = '\0';
7669 7676 if (bar_linkflag == LNKTYPE || bar_linkflag == SYMTYPE)
7670 7677 (void) strcpy(bar_linkname, start_of_name);
7671 7678
7672 7679 Gen.g_namesz = strlen(Gen.g_nam_p) + 1;
7673 7680 (void) strcpy(nambuf, Gen.g_nam_p);
7674 7681 }
7675 7682
7676 7683 /*
7677 7684 * if the bar archive is compressed, set up a pipe and do the de-compression
7678 7685 * as the compressed file is read in.
7679 7686 */
7680 7687 static void
7681 7688 setup_uncompress(FILE **pipef)
7682 7689 {
7683 7690 char *cmd_buf;
7684 7691 size_t cmdlen;
7685 7692
7686 7693 cmd_buf = e_zalloc(E_EXIT, MAXPATHLEN * 2);
7687 7694
7688 7695 if (access(Gen.g_nam_p, W_OK) != 0) {
7689 7696 cmdlen = snprintf(cmd_buf, MAXPATHLEN * 2,
7690 7697 "chmod +w '%s'; uncompress -c > '%s'; "
7691 7698 "chmod 0%o '%s'",
7692 7699 Gen.g_nam_p, Gen.g_nam_p, (int)G_p->g_mode, Gen.g_nam_p);
7693 7700 } else {
7694 7701 cmdlen = snprintf(cmd_buf, MAXPATHLEN * 2,
7695 7702 "uncompress -c > '%s'", Gen.g_nam_p);
7696 7703 }
7697 7704
7698 7705 if (cmdlen >= MAXPATHLEN * 2 ||
7699 7706 (*pipef = popen(cmd_buf, "w")) == NULL) {
7700 7707 (void) fprintf(stderr, gettext("error\n"));
7701 7708 exit(1);
7702 7709 }
7703 7710
7704 7711 if (close(Ofile) != 0)
7705 7712 msg(EXTN, "close error");
7706 7713 Ofile = fileno(*pipef);
7707 7714
7708 7715 free(cmd_buf);
7709 7716 }
7710 7717
7711 7718 /*
7712 7719 * if the bar archive spans multiple volumes, read in the header that
7713 7720 * describes the next volume.
7714 7721 */
7715 7722 static void
7716 7723 skip_bar_volhdr(void)
7717 7724 {
7718 7725 char *buff;
7719 7726 union b_block *tmp_hdr;
7720 7727
7721 7728 buff = e_zalloc(E_EXIT, (uint_t)Bufsize);
7722 7729
7723 7730 if (g_read(Device, Archive, buff, Bufsize) < 0) {
7724 7731 (void) fprintf(stderr, gettext(
7725 7732 "error in skip_bar_volhdr\n"));
7726 7733 } else {
7727 7734
7728 7735 tmp_hdr = (union b_block *)buff;
7729 7736 if (tmp_hdr->dbuf.bar_magic[0] == BAR_VOLUME_MAGIC) {
7730 7737
7731 7738 if (bar_Vhdr == NULL) {
7732 7739 bar_Vhdr = e_zalloc(E_EXIT, TBLOCK);
7733 7740 }
7734 7741 (void) memcpy(&(bar_Vhdr->dbuf),
7735 7742 &(tmp_hdr->dbuf), TBLOCK);
7736 7743 } else {
7737 7744 (void) fprintf(stderr,
7738 7745 gettext("cpio error: cannot read bar volume "
7739 7746 "header\n"));
7740 7747 exit(1);
7741 7748 }
7742 7749
7743 7750 (void) sscanf(bar_Vhdr->dbuf.mode, "%8lo",
7744 7751 &Gen_bar_vol.g_mode);
7745 7752 (void) sscanf(bar_Vhdr->dbuf.uid, "%8lo",
7746 7753 &Gen_bar_vol.g_uid);
7747 7754 (void) sscanf(bar_Vhdr->dbuf.gid, "%8lo",
7748 7755 &Gen_bar_vol.g_gid);
7749 7756 (void) sscanf(bar_Vhdr->dbuf.size, "%12llo",
7750 7757 (u_off_t *)&Gen_bar_vol.g_filesz);
7751 7758 (void) sscanf(bar_Vhdr->dbuf.mtime, "%12lo",
7752 7759 &Gen_bar_vol.g_mtime);
7753 7760 (void) sscanf(bar_Vhdr->dbuf.chksum, "%8lo",
7754 7761 &Gen_bar_vol.g_cksum);
7755 7762 if (bar_Vhdr->dbuf.compressed == '1')
7756 7763 Compressed = 1;
7757 7764 else
7758 7765 Compressed = 0;
7759 7766 }
7760 7767
7761 7768 /*
7762 7769 * Now put the rest of the bytes read in into the data buffer.
7763 7770 */
7764 7771 (void) memcpy(Buffr.b_in_p, &buff[512], (Bufsize - 512));
7765 7772 Buffr.b_in_p += (Bufsize - 512);
7766 7773 Buffr.b_cnt += (long)(Bufsize - 512);
7767 7774
7768 7775 free(buff);
7769 7776 }
7770 7777
7771 7778 /*
7772 7779 * check the linkflag which indicates the type of the file to be extracted,
7773 7780 * invoke the corresponding routine to extract the file.
7774 7781 */
7775 7782 static void
7776 7783 bar_file_in(void)
7777 7784 {
7778 7785 /*
7779 7786 * the file is a directory
7780 7787 */
7781 7788 if (Adir) {
7782 7789 if (ckname(1) != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
7783 7790 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
7784 7791 }
7785 7792 return;
7786 7793 }
7787 7794
7788 7795 switch (bar_linkflag) {
7789 7796 case REGTYPE:
7790 7797 /* regular file */
7791 7798 if ((ckname(1) == F_SKIP) ||
7792 7799 (Ofile = openout(G_p->g_dirfd)) < 0) {
7793 7800 data_in(P_SKIP);
7794 7801 } else {
7795 7802 data_in(P_PROC);
7796 7803 }
7797 7804 break;
7798 7805 case LNKTYPE:
7799 7806 /* hard link */
7800 7807 if (ckname(1) == F_SKIP) {
7801 7808 break;
7802 7809 }
7803 7810 (void) creat_lnk(G_p->g_dirfd, bar_linkname, G_p->g_nam_p);
7804 7811 break;
7805 7812 case SYMTYPE:
7806 7813 /* symbolic link */
7807 7814 if ((ckname(1) == F_SKIP) ||
7808 7815 (Ofile = openout(G_p->g_dirfd)) < 0) {
7809 7816 data_in(P_SKIP);
7810 7817 } else {
7811 7818 data_in(P_PROC);
7812 7819 }
7813 7820 break;
7814 7821 case CHRTYPE:
7815 7822 /* character device or FIFO */
7816 7823 if (ckname(1) != F_SKIP && creat_spec(G_p->g_dirfd) > 0) {
7817 7824 VERBOSE((Args & (OCv | OCV)), G_p->g_nam_p);
7818 7825 }
7819 7826 break;
7820 7827 default:
7821 7828 (void) fprintf(stderr, gettext("error: unknown file type\n"));
7822 7829 break;
7823 7830 }
7824 7831 }
7825 7832
7826 7833
7827 7834 /*
7828 7835 * This originally came from libgenIO/g_init.c
7829 7836 * XXX And it is very broken.
7830 7837 */
7831 7838
7832 7839 /* #include <sys/statvfs.h> */
7833 7840 #include <ftw.h>
7834 7841 /* #include <libgenIO.h> */
7835 7842 #define G_TM_TAPE 1 /* Tapemaster controller */
7836 7843 #define G_XY_DISK 3 /* xy disks */
7837 7844 #define G_SD_DISK 7 /* scsi sd disk */
7838 7845 #define G_XT_TAPE 8 /* xt tapes */
7839 7846 #define G_SF_FLOPPY 9 /* sf floppy */
7840 7847 #define G_XD_DISK 10 /* xd disks */
7841 7848 #define G_ST_TAPE 11 /* scsi tape */
7842 7849 #define G_NS 12 /* noswap pseudo-dev */
7843 7850 #define G_RAM 13 /* ram pseudo-dev */
7844 7851 #define G_FT 14 /* tftp */
7845 7852 #define G_HD 15 /* 386 network disk */
7846 7853 #define G_FD 16 /* 386 AT disk */
7847 7854 #define G_FILE 28 /* file, not a device */
7848 7855 #define G_NO_DEV 29 /* device does not require special treatment */
7849 7856 #define G_DEV_MAX 30 /* last valid device type */
7850 7857
7851 7858 /*
7852 7859 * g_init: Determine the device being accessed, set the buffer size,
7853 7860 * and perform any device specific initialization. Since at this point
7854 7861 * Sun has no system call to read the configuration, the major numbers
7855 7862 * are assumed to be static and types are figured out as such. However,
7856 7863 * as a rough estimate, the buffer size for all types is set to 512
7857 7864 * as a default.
7858 7865 */
7859 7866
7860 7867 static int
7861 7868 g_init(int *devtype, int *fdes)
7862 7869 {
7863 7870 int bufsize;
7864 7871 struct stat st_buf;
7865 7872 struct statvfs stfs_buf;
7866 7873
7867 7874 *devtype = G_NO_DEV;
7868 7875 bufsize = -1;
7869 7876 if (fstat(*fdes, &st_buf) == -1)
7870 7877 return (-1);
7871 7878 if (!S_ISCHR(st_buf.st_mode) && !S_ISBLK(st_buf.st_mode)) {
7872 7879 if (S_ISFIFO(st_buf.st_mode)) {
7873 7880 bufsize = 512;
7874 7881 } else {
7875 7882 /* find block size for this file system */
7876 7883 *devtype = G_FILE;
7877 7884 if (fstatvfs(*fdes, &stfs_buf) < 0) {
7878 7885 bufsize = -1;
7879 7886 errno = ENODEV;
7880 7887 } else
7881 7888 bufsize = stfs_buf.f_bsize;
7882 7889 }
7883 7890
7884 7891 return (bufsize);
7885 7892
7886 7893 /*
7887 7894 * We'll have to add a remote attribute to stat but this
7888 7895 * should work for now.
7889 7896 */
7890 7897 } else if (st_buf.st_dev & 0x8000) /* if remote rdev */
7891 7898 return (512);
7892 7899
7893 7900 bufsize = 512;
7894 7901
7895 7902 if (Hdr_type == BAR) {
7896 7903 if (is_tape(*fdes)) {
7897 7904 bufsize = BAR_TAPE_SIZE;
7898 7905 msg(EPOST, "Archiving to tape blocking factor 126");
7899 7906 } else if (is_floppy(*fdes)) {
7900 7907 bufsize = BAR_FLOPPY_SIZE;
7901 7908 msg(EPOST, "Archiving to floppy blocking factor 18");
7902 7909 }
7903 7910 }
7904 7911
7905 7912 return (bufsize);
7906 7913 }
7907 7914
7908 7915 /*
7909 7916 * This originally came from libgenIO/g_read.c
7910 7917 */
7911 7918
7912 7919 /*
7913 7920 * g_read: Read nbytes of data from fdes (of type devtype) and place
7914 7921 * data in location pointed to by buf. In case of end of medium,
7915 7922 * translate (where necessary) device specific EOM indications into
7916 7923 * the generic EOM indication of rv = -1, errno = ENOSPC.
7917 7924 */
7918 7925
7919 7926 static int
7920 7927 g_read(int devtype, int fdes, char *buf, unsigned nbytes)
7921 7928 {
7922 7929 int rv;
7923 7930
7924 7931 if (devtype < 0 || devtype >= G_DEV_MAX) {
7925 7932 errno = ENODEV;
7926 7933 return (-1);
7927 7934 }
7928 7935
7929 7936 rv = read(fdes, buf, nbytes);
7930 7937
7931 7938 /* st devices return 0 when no space left */
7932 7939 if ((rv == 0 && errno == 0 && Hdr_type != BAR) ||
7933 7940 (rv == -1 && errno == EIO)) {
7934 7941 errno = 0;
7935 7942 rv = 0;
7936 7943 }
7937 7944
7938 7945 return (rv);
7939 7946 }
7940 7947
7941 7948 /*
7942 7949 * This originally came from libgenIO/g_write.c
7943 7950 */
7944 7951
7945 7952 /*
7946 7953 * g_write: Write nbytes of data to fdes (of type devtype) from
7947 7954 * the location pointed to by buf. In case of end of medium,
7948 7955 * translate (where necessary) device specific EOM indications into
7949 7956 * the generic EOM indication of rv = -1, errno = ENOSPC.
7950 7957 */
7951 7958
7952 7959 static int
7953 7960 g_write(int devtype, int fdes, char *buf, unsigned nbytes)
7954 7961 {
7955 7962 int rv;
7956 7963
7957 7964 if (devtype < 0 || devtype >= G_DEV_MAX) {
7958 7965 errno = ENODEV;
7959 7966 return (-1);
7960 7967 }
7961 7968
7962 7969 rv = write(fdes, buf, nbytes);
7963 7970
7964 7971 /* st devices return 0 when no more space left */
7965 7972 if ((rv == 0 && errno == 0) || (rv == -1 && errno == EIO)) {
7966 7973 errno = ENOSPC;
7967 7974 rv = -1;
7968 7975 }
7969 7976
7970 7977 return (rv);
7971 7978 }
7972 7979
7973 7980 /*
7974 7981 * Test for tape
7975 7982 */
7976 7983
7977 7984 static int
7978 7985 is_tape(int fd)
7979 7986 {
7980 7987 struct mtget stuff;
7981 7988
7982 7989 /*
7983 7990 * try to do a generic tape ioctl, just to see if
7984 7991 * the thing is in fact a tape drive(er).
7985 7992 */
7986 7993 if (ioctl(fd, MTIOCGET, &stuff) != -1) {
7987 7994 /* the ioctl succeeded, must have been a tape */
7988 7995 return (1);
7989 7996 }
7990 7997 return (0);
7991 7998 }
7992 7999
7993 8000 /*
7994 8001 * Test for floppy
7995 8002 */
7996 8003
7997 8004 static int
7998 8005 is_floppy(int fd)
7999 8006 {
8000 8007 struct fd_char stuff;
8001 8008
8002 8009 /*
8003 8010 * try to get the floppy drive characteristics, just to see if
8004 8011 * the thing is in fact a floppy drive(er).
8005 8012 */
8006 8013 if (ioctl(fd, FDIOGCHAR, &stuff) != -1) {
8007 8014 /* the ioctl succeeded, must have been a floppy */
8008 8015 return (1);
8009 8016 }
8010 8017
8011 8018 return (0);
8012 8019 }
8013 8020
8014 8021 /*
8015 8022 * New functions for ACLs and other security attributes
8016 8023 */
8017 8024
8018 8025 /*
8019 8026 * The function appends the new security attribute info to the end of
8020 8027 * existing secinfo.
8021 8028 */
8022 8029 static int
8023 8030 append_secattr(
8024 8031 char **secinfo, /* existing security info */
8025 8032 int *secinfo_len, /* length of existing security info */
8026 8033 acl_t *aclp) /* new attribute data pointer */
8027 8034 {
8028 8035 char *new_secinfo;
8029 8036 char *attrtext;
8030 8037 size_t newattrsize;
8031 8038 int oldsize;
8032 8039
8033 8040 /* no need to add */
8034 8041 if (aclp == NULL) {
8035 8042 return (0);
8036 8043 }
8037 8044
8038 8045 switch (acl_type(aclp)) {
8039 8046 case ACLENT_T:
8040 8047 case ACE_T:
8041 8048 attrtext = acl_totext(aclp, ACL_APPEND_ID | ACL_COMPACT_FMT |
8042 8049 ACL_SID_FMT);
8043 8050 if (attrtext == NULL) {
8044 8051 msg(EPOST, "acltotext failed");
8045 8052 return (-1);
8046 8053 }
8047 8054 /* header: type + size = 8 */
8048 8055 newattrsize = 8 + strlen(attrtext) + 1;
8049 8056 attr = e_zalloc(E_NORMAL, newattrsize);
8050 8057 if (attr == NULL) {
8051 8058 msg(EPOST, "can't allocate memory");
8052 8059 return (-1);
8053 8060 }
8054 8061 attr->attr_type = (acl_type(aclp) == ACLENT_T) ?
8055 8062 UFSD_ACL : ACE_ACL;
8056 8063 /* acl entry count */
8057 8064 (void) sprintf(attr->attr_len, "%06o", acl_cnt(aclp));
8058 8065 (void) strcpy((char *)&attr->attr_info[0], attrtext);
8059 8066 free(attrtext);
8060 8067 break;
8061 8068
8062 8069 /* SunFed's case goes here */
8063 8070
8064 8071 default:
8065 8072 msg(EPOST, "unrecognized attribute type");
8066 8073 return (-1);
8067 8074 }
8068 8075
8069 8076 /* old security info + new attr header(8) + new attr */
8070 8077 oldsize = *secinfo_len;
8071 8078 *secinfo_len += newattrsize;
8072 8079 new_secinfo = e_zalloc(E_NORMAL, (uint_t)*secinfo_len);
8073 8080 if (new_secinfo == NULL) {
8074 8081 msg(EPOST, "can't allocate memory");
8075 8082 *secinfo_len -= newattrsize;
8076 8083 return (-1);
8077 8084 }
8078 8085
8079 8086 (void) memcpy(new_secinfo, *secinfo, oldsize);
8080 8087 (void) memcpy(new_secinfo + oldsize, attr, newattrsize);
8081 8088
8082 8089 free(*secinfo);
8083 8090 *secinfo = new_secinfo;
8084 8091 return (0);
8085 8092 }
8086 8093
8087 8094 /*
8088 8095 * Append size amount of data from buf to the archive.
8089 8096 */
8090 8097 static void
8091 8098 write_ancillary(char *buf, size_t len, boolean_t padding)
8092 8099 {
8093 8100 int pad, cnt;
8094 8101
8095 8102 if (len == 0)
8096 8103 return;
8097 8104
8098 8105 while (len > 0) {
8099 8106 cnt = (unsigned)(len > CPIOBSZ) ? CPIOBSZ : len;
8100 8107 FLUSH(cnt);
8101 8108 errno = 0;
8102 8109 (void) memcpy(Buffr.b_in_p, buf, (unsigned)cnt);
8103 8110 Buffr.b_in_p += cnt;
8104 8111 Buffr.b_cnt += cnt;
8105 8112 len -= cnt;
8106 8113 buf += cnt;
8107 8114 }
8108 8115 if (padding) {
8109 8116 pad = (Pad_val + 1 - (cnt & Pad_val)) & Pad_val;
8110 8117 if (pad != 0) {
8111 8118 FLUSH(pad);
8112 8119 (void) memset(Buffr.b_in_p, 0, pad);
8113 8120 Buffr.b_in_p += pad;
8114 8121 Buffr.b_cnt += pad;
8115 8122 }
8116 8123 }
8117 8124 }
8118 8125
8119 8126 static int
8120 8127 remove_dir(char *path)
8121 8128 {
8122 8129 DIR *name;
8123 8130 struct dirent *direct;
8124 8131 struct stat sbuf;
8125 8132 char *path_copy;
8126 8133
8127 8134 #define MSG1 "remove_dir() failed to stat(\"%s\") "
8128 8135 #define MSG2 "remove_dir() failed to remove_dir(\"%s\") "
8129 8136 #define MSG3 "remove_dir() failed to unlink(\"%s\") "
8130 8137
8131 8138 /*
8132 8139 * Open the directory for reading.
8133 8140 */
8134 8141 if ((name = opendir(path)) == NULL) {
8135 8142 msg(ERRN, "remove_dir() failed to opendir(\"%s\") ", path);
8136 8143 return (-1);
8137 8144 }
8138 8145
8139 8146 if (chdir(path) == -1) {
8140 8147 msg(ERRN, "remove_dir() failed to chdir(\"%s\") ", path);
8141 8148 return (-1);
8142 8149 }
8143 8150
8144 8151 /*
8145 8152 * Read every directory entry.
8146 8153 */
8147 8154 while ((direct = readdir(name)) != NULL) {
8148 8155 /*
8149 8156 * Ignore "." and ".." entries.
8150 8157 */
8151 8158 if (strcmp(direct->d_name, ".") == 0 ||
8152 8159 strcmp(direct->d_name, "..") == 0)
8153 8160 continue;
8154 8161
8155 8162 if (lstat(direct->d_name, &sbuf) == -1) {
8156 8163 msg(ERRN, MSG1, direct->d_name);
8157 8164 (void) closedir(name);
8158 8165 return (-1);
8159 8166 }
8160 8167
8161 8168 if (S_ISDIR(sbuf.st_mode)) {
8162 8169 if (remove_dir(direct->d_name) == -1) {
8163 8170 msg(ERRN, MSG2, direct->d_name);
8164 8171 (void) closedir(name);
8165 8172 return (-1);
8166 8173 }
8167 8174 } else {
8168 8175 if (unlink(direct->d_name) == -1) {
8169 8176 msg(ERRN, MSG3, direct->d_name);
8170 8177 (void) closedir(name);
8171 8178 return (-1);
8172 8179 }
8173 8180 }
8174 8181
8175 8182 }
8176 8183
8177 8184 /*
8178 8185 * Close the directory we just finished reading.
8179 8186 */
8180 8187 (void) closedir(name);
8181 8188
8182 8189 /*
8183 8190 * Change directory to the parent directory...
8184 8191 */
8185 8192 if (chdir("..") == -1) {
8186 8193 msg(ERRN, "remove_dir() failed to chdir(\"..\") ");
8187 8194 return (-1);
8188 8195 }
8189 8196
8190 8197 /*
8191 8198 * ...and finally remove the directory; note we have to
8192 8199 * make a copy since basename is free to modify its input.
8193 8200 */
8194 8201 path_copy = e_strdup(E_NORMAL, path);
8195 8202 if (path_copy == NULL) {
8196 8203 msg(ERRN, "cannot strdup() the directory pathname ");
8197 8204 return (-1);
8198 8205 }
8199 8206
8200 8207 if (rmdir(basename(path_copy)) == -1) {
8201 8208 free(path_copy);
8202 8209 msg(ERRN, "remove_dir() failed to rmdir(\"%s\") ", path);
8203 8210 return (-1);
8204 8211 }
8205 8212
8206 8213 free(path_copy);
8207 8214 return (0);
8208 8215
8209 8216 }
8210 8217
8211 8218 static int
8212 8219 save_cwd(void)
8213 8220 {
8214 8221 return (open(".", O_RDONLY));
8215 8222 }
8216 8223
8217 8224 static void
8218 8225 rest_cwd(int cwd)
8219 8226 {
8220 8227 (void) fchdir(cwd);
8221 8228 (void) close(cwd);
8222 8229 }
8223 8230
8224 8231 #if defined(O_XATTR)
8225 8232 static void
8226 8233 xattrs_out(int (*func)())
8227 8234 {
8228 8235 int dirpfd;
8229 8236 int filefd;
8230 8237 int arc_rwsysattr = 0;
8231 8238 int rw_sysattr = 0;
8232 8239 int ext_attr = 0;
8233 8240 DIR *dirp;
8234 8241 struct dirent *dp;
8235 8242 int slen;
8236 8243 int plen;
8237 8244 char *namep, *savenamep;
8238 8245 char *apathp;
8239 8246 char *attrparent = Gen.g_attrparent_p;
8240 8247 char *filename;
8241 8248
8242 8249 if (attrparent == NULL) {
8243 8250 filename = Gen.g_nam_p;
8244 8251 } else {
8245 8252 filename = Gen.g_attrnam_p;
8246 8253 }
8247 8254
8248 8255 /*
8249 8256 * If the underlying file system supports it, then
8250 8257 * archive the extended attributes if -@ was specified,
8251 8258 * and the extended system attributes if -/ was
8252 8259 * specified.
8253 8260 */
8254 8261 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
8255 8262 &ext_attr) != ATTR_OK) {
8256 8263 return;
8257 8264 }
8258 8265
8259 8266 #if defined(_PC_SATTR_ENABLED)
8260 8267 if (SysAtflag) {
8261 8268 int filefd;
8262 8269 nvlist_t *slist = NULL;
8263 8270
8264 8271 /*
8265 8272 * Determine if there are non-transient system
8266 8273 * attributes.
8267 8274 */
8268 8275 errno = 0;
8269 8276 if ((filefd = open(filename, O_RDONLY)) == -1) {
8270 8277 if (attrparent == NULL) {
8271 8278 msg(EXTN,
8272 8279 "unable to open %s%s%sfile %s",
8273 8280 (attrparent == NULL) ? "" :
8274 8281 gettext("attribute "),
8275 8282 (attrparent == NULL) ? "" : attrparent,
8276 8283 (attrparent == NULL) ? "" : gettext(" of "),
8277 8284 (attrparent == NULL) ? G_p->g_nam_p :
8278 8285 G_p->g_attrfnam_p);
8279 8286 }
8280 8287 }
8281 8288 if (((slist = sysattr_list(myname, filefd,
8282 8289 filename)) != NULL) || (errno != 0)) {
8283 8290 arc_rwsysattr = 1;
8284 8291 }
8285 8292 if (slist != NULL) {
8286 8293 (void) nvlist_free(slist);
8287 8294 slist = NULL;
8288 8295 }
8289 8296 (void) close(filefd);
8290 8297 }
8291 8298
8292 8299 /*
8293 8300 * If we aren't archiving extended system attributes, and we are
8294 8301 * processing an attribute, or if we are archiving extended system
8295 8302 * attributes, and there are are no extended attributes, then there's
8296 8303 * no need to open up the attribute directory of the file unless the
8297 8304 * extended system attributes are not transient (i.e, the system
8298 8305 * attributes are not the default values).
8299 8306 */
8300 8307 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
8301 8308 (SysAtflag && !ext_attr))) {
8302 8309 return;
8303 8310 }
8304 8311
8305 8312 #endif /* _PC_SATTR_ENABLED */
8306 8313
8307 8314 /*
8308 8315 * If aclp still exists then free it since it is was set when base
8309 8316 * file was extracted.
8310 8317 */
8311 8318 if (aclp != NULL) {
8312 8319 acl_free(aclp);
8313 8320 aclp = NULL;
8314 8321 acl_is_set = 0;
8315 8322 }
8316 8323
8317 8324 Gen.g_dirfd = attropen(filename, ".", O_RDONLY);
8318 8325 if (Gen.g_dirfd == -1) {
8319 8326 msg(ERRN, "Cannot open attribute directory of file \"%s%s%s\"",
8320 8327 (attrparent == NULL) ? "" : gettext("attribute "),
8321 8328 (attrparent == NULL) ? "" : attrparent,
8322 8329 (attrparent == NULL) ? "" : gettext(" of "), filename);
8323 8330 return;
8324 8331
8325 8332 }
8326 8333
8327 8334 if (attrparent == NULL) {
8328 8335 savenamep = G_p->g_nam_p;
8329 8336 } else {
8330 8337 savenamep = G_p->g_attrfnam_p;
8331 8338 }
8332 8339
8333 8340 if ((dirpfd = dup(Gen.g_dirfd)) == -1) {
8334 8341 msg(ERRN, "Cannot dup(2) attribute directory descriptor");
8335 8342 return;
8336 8343 }
8337 8344
8338 8345 if ((dirp = fdopendir(dirpfd)) == NULL) {
8339 8346 msg(ERRN, "Cannot fdopendir(2) directory file descriptor");
8340 8347 return;
8341 8348 }
8342 8349
8343 8350 if (attrparent == NULL) {
8344 8351 Gen.g_baseparent_fd = save_cwd();
8345 8352 }
8346 8353
8347 8354 while ((dp = readdir(dirp)) != NULL) {
8348 8355 if (strcmp(dp->d_name, "..") == 0) {
8349 8356 continue;
8350 8357 }
8351 8358 if (verify_attr(dp->d_name, attrparent,
8352 8359 arc_rwsysattr, &rw_sysattr) != ATTR_OK) {
8353 8360 continue;
8354 8361 }
8355 8362
8356 8363 if (strcmp(dp->d_name, ".") == 0) {
8357 8364 Hiddendir = 1;
8358 8365 } else {
8359 8366 Hiddendir = 0;
8360 8367 }
8361 8368
8362 8369 Gen.g_rw_sysattr = rw_sysattr;
8363 8370 Gen.g_attrnam_p = dp->d_name;
8364 8371
8365 8372 if (STAT(Gen.g_dirfd, Gen.g_nam_p, &SrcSt) == -1) {
8366 8373 msg(ERRN,
8367 8374 "Could not fstatat(2) attribute \"%s\" of"
8368 8375 " file \"%s\"", dp->d_name, (attrparent == NULL) ?
8369 8376 savenamep : Gen.g_attrfnam_p);
8370 8377 continue;
8371 8378 }
8372 8379
8373 8380 if (Use_old_stat) {
8374 8381 Savedev = SrcSt.st_dev;
8375 8382 OldSt = convert_to_old_stat(&SrcSt,
8376 8383 Gen.g_nam_p, Gen.g_attrnam_p);
8377 8384
8378 8385 if (OldSt == NULL) {
8379 8386 msg(ERRN,
8380 8387 "Could not convert to old stat format");
8381 8388 continue;
8382 8389 }
8383 8390 }
8384 8391
8385 8392 Gen.g_attrfnam_p = savenamep;
8386 8393
8387 8394 /*
8388 8395 * Set up dummy header name
8389 8396 *
8390 8397 * One piece is written with .hdr, which
8391 8398 * contains the actual xattr hdr or pathing information
8392 8399 * then the name is updated to drop the .hdr off
8393 8400 * and the actual file itself is archived.
8394 8401 */
8395 8402 slen = strlen(Gen.g_attrnam_p) + strlen(DEVNULL) +
8396 8403 strlen(XATTRHDR) + 2; /* add one for '/' */
8397 8404 if ((namep = e_zalloc(E_NORMAL, slen)) == NULL) {
8398 8405 msg(ERRN, "Could not calloc memory for attribute name");
8399 8406 continue;
8400 8407 }
8401 8408 (void) snprintf(namep, slen, "%s/%s%s",
8402 8409 DEVNULL, Gen.g_attrnam_p, XATTRHDR);
8403 8410 Gen.g_nam_p = namep;
8404 8411
8405 8412 plen = strlen(Gen.g_attrnam_p) + 1;
8406 8413 if (Gen.g_attrparent_p != NULL) {
8407 8414 plen += strlen(Gen.g_attrparent_p) + 1;
8408 8415 }
8409 8416 if ((apathp = e_zalloc(E_NORMAL, plen)) == NULL) {
8410 8417 msg(ERRN, "Could not calloc memory for attribute name");
8411 8418 continue;
8412 8419 }
8413 8420 (void) snprintf(apathp, plen, "%s%s%s",
8414 8421 (Gen.g_attrparent_p == NULL) ? "" : Gen.g_attrparent_p,
8415 8422 (Gen.g_attrparent_p == NULL) ? "" : "/", Gen.g_attrnam_p);
8416 8423
8417 8424 if (Gen.g_attrpath_p != NULL) {
8418 8425 free(Gen.g_attrpath_p);
8419 8426 }
8420 8427 Gen.g_attrpath_p = apathp;
8421 8428
8422 8429 /*
8423 8430 * Get attribute's ACL info: don't bother allocating space
8424 8431 * if there are only standard permissions, i.e. ACL count < 4
8425 8432 */
8426 8433 if (Pflag) {
8427 8434 filefd = openat(Gen.g_dirfd, dp->d_name, O_RDONLY);
8428 8435 if (filefd == -1) {
8429 8436 msg(ERRN,
8430 8437 "Could not open attribute \"%s\" of"
8431 8438 " file \"%s\"", dp->d_name, savenamep);
8432 8439 free(namep);
8433 8440 continue;
8434 8441 }
8435 8442 if (facl_get(filefd, ACL_NO_TRIVIAL, &aclp) != 0) {
8436 8443 msg(ERRN,
8437 8444 "Error with acl() on %s",
8438 8445 Gen.g_nam_p);
8439 8446 }
8440 8447 (void) close(filefd);
8441 8448 }
8442 8449
8443 8450 (void) creat_hdr();
8444 8451 (void) (*func)();
8445 8452
8446 8453 #if defined(_PC_SATTR_ENABLED)
8447 8454 /*
8448 8455 * Recursively call xattrs_out() to process the attribute's
8449 8456 * hidden attribute directory and read-write system attributes.
8450 8457 */
8451 8458 if (SysAtflag && !Hiddendir && !rw_sysattr) {
8452 8459 int savedirfd = Gen.g_dirfd;
8453 8460
8454 8461 (void) fchdir(Gen.g_dirfd);
8455 8462 Gen.g_attrparent_p = dp->d_name;
8456 8463 xattrs_out(func);
8457 8464 Gen.g_dirfd = savedirfd;
8458 8465 Gen.g_attrparent_p = NULL;
8459 8466 }
8460 8467 #endif /* _PC_SATTR_ENABLED */
8461 8468
8462 8469 if (Gen.g_passdirfd != -1) {
8463 8470 (void) close(Gen.g_passdirfd);
8464 8471 Gen.g_passdirfd = -1;
8465 8472 }
8466 8473 Gen.g_attrnam_p = NULL;
8467 8474 Gen.g_attrfnam_p = NULL;
8468 8475 Gen.g_linktoattrfnam_p = NULL;
8469 8476 Gen.g_linktoattrnam_p = NULL;
8470 8477 Gen.g_rw_sysattr = 0;
8471 8478 if (Gen.g_attrpath_p != NULL) {
8472 8479 free(Gen.g_attrpath_p);
8473 8480 Gen.g_attrpath_p = NULL;
8474 8481 }
8475 8482
8476 8483 if (aclp != NULL) {
8477 8484 acl_free(aclp);
8478 8485 aclp = NULL;
8479 8486 acl_is_set = 0;
8480 8487 }
8481 8488 free(namep);
8482 8489 }
8483 8490
8484 8491 (void) closedir(dirp);
8485 8492 (void) close(Gen.g_dirfd);
8486 8493 if (attrparent == NULL) {
8487 8494 rest_cwd(Gen.g_baseparent_fd);
8488 8495 Gen.g_dirfd = -1;
8489 8496 }
8490 8497 Hiddendir = 0;
8491 8498 }
8492 8499 #else
8493 8500 static void
8494 8501 xattrs_out(int (*func)())
8495 8502 {
8496 8503 }
8497 8504 #endif
8498 8505
8499 8506 /*
8500 8507 * Return the parent directory of a given path.
8501 8508 *
8502 8509 * Examples:
8503 8510 * /usr/tmp return /usr
8504 8511 * /usr/tmp/file return /usr/tmp
8505 8512 * / returns .
8506 8513 * /usr returns /
8507 8514 * file returns .
8508 8515 *
8509 8516 * dir is assumed to be at least as big as path.
8510 8517 */
8511 8518 static void
8512 8519 get_parent(char *path, char *dir)
8513 8520 {
8514 8521 char *s;
8515 8522 char tmpdir[PATH_MAX + 1];
8516 8523
8517 8524 if (strlen(path) > PATH_MAX) {
8518 8525 msg(EXT, "pathname is too long");
8519 8526 }
8520 8527 (void) strcpy(tmpdir, path);
8521 8528 chop_endslashes(tmpdir);
8522 8529
8523 8530 if ((s = strrchr(tmpdir, '/')) == NULL) {
8524 8531 (void) strcpy(dir, ".");
8525 8532 } else {
8526 8533 s = skipslashes(s, tmpdir);
8527 8534 *s = '\0';
8528 8535 if (s == tmpdir)
8529 8536 (void) strcpy(dir, "/");
8530 8537 else
8531 8538 (void) strcpy(dir, tmpdir);
8532 8539 }
8533 8540 }
8534 8541
8535 8542 #if defined(O_XATTR)
8536 8543 #define ROUNDTOTBLOCK(a) ((a + (TBLOCK -1)) & ~(TBLOCK -1))
8537 8544
8538 8545 static void
8539 8546 prepare_xattr_hdr(
8540 8547 char **attrbuf,
8541 8548 char *filename,
8542 8549 char *attrpath,
8543 8550 char typeflag,
8544 8551 struct Lnk *linkinfo,
8545 8552 int *rlen)
8546 8553 {
8547 8554 char *bufhead; /* ptr to full buffer */
8548 8555 char *aptr;
8549 8556 struct xattr_hdr *hptr; /* ptr to header in bufhead */
8550 8557 struct xattr_buf *tptr; /* ptr to pathing pieces */
8551 8558 int totalen; /* total buffer length */
8552 8559 int len; /* length returned to user */
8553 8560 int stringlen; /* length of filename + attr */
8554 8561 /*
8555 8562 * length of filename + attr
8556 8563 * in link section
8557 8564 */
8558 8565 int linkstringlen;
8559 8566 int complen; /* length of pathing section */
8560 8567 int linklen; /* length of link section */
8561 8568 int attrnames_index; /* attrnames starting index */
8562 8569
8563 8570 /*
8564 8571 * Release previous buffer if any.
8565 8572 */
8566 8573
8567 8574 if (*attrbuf != NULL) {
8568 8575 free(*attrbuf);
8569 8576 *attrbuf = NULL;
8570 8577 }
8571 8578
8572 8579 /*
8573 8580 * First add in fixed size stuff
8574 8581 */
8575 8582 len = sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
8576 8583
8577 8584 /*
8578 8585 * Add space for two nulls
8579 8586 */
8580 8587 stringlen = strlen(attrpath) + strlen(filename) + 2;
8581 8588 complen = stringlen + sizeof (struct xattr_buf);
8582 8589
8583 8590 len += stringlen;
8584 8591
8585 8592 /*
8586 8593 * Now add on space for link info if any
8587 8594 */
8588 8595
8589 8596 if (linkinfo != NULL) {
8590 8597 /*
8591 8598 * Again add space for two nulls
8592 8599 */
8593 8600 linkstringlen = strlen(linkinfo->L_gen.g_attrfnam_p) +
8594 8601 strlen(linkinfo->L_gen.g_attrnam_p) + 2;
8595 8602 linklen = linkstringlen + sizeof (struct xattr_buf);
8596 8603 len += linklen;
8597 8604 } else {
8598 8605 linklen = 0;
8599 8606 }
8600 8607
8601 8608 /*
8602 8609 * Now add padding to end to fill out TBLOCK
8603 8610 *
8604 8611 * Function returns size of real data and not size + padding.
8605 8612 */
8606 8613
8607 8614 totalen = ROUNDTOTBLOCK(len);
8608 8615 bufhead = e_zalloc(E_EXIT, totalen);
8609 8616
8610 8617 /*
8611 8618 * Now we can fill in the necessary pieces
8612 8619 */
8613 8620
8614 8621 /*
8615 8622 * first fill in the fixed header
8616 8623 */
8617 8624 hptr = (struct xattr_hdr *)bufhead;
8618 8625 (void) strcpy(hptr->h_version, XATTR_ARCH_VERS);
8619 8626 (void) sprintf(hptr->h_component_len, "%0*d",
8620 8627 sizeof (hptr->h_component_len) - 1, complen);
8621 8628 (void) sprintf(hptr->h_link_component_len, "%0*d",
8622 8629 sizeof (hptr->h_link_component_len) - 1, linklen);
8623 8630 (void) sprintf(hptr->h_size, "%0*d", sizeof (hptr->h_size) - 1, len);
8624 8631
8625 8632 /*
8626 8633 * Now fill in the filename + attrnames section
8627 8634 * The filename and attrnames section can be composed of two or more
8628 8635 * path segments separated by a null character. The first segment
8629 8636 * is the path to the parent file that roots the entire sequence in
8630 8637 * the normal name space. The remaining segments describes a path
8631 8638 * rooted at the hidden extended attribute directory of the leaf file of
8632 8639 * the previous segment, making it possible to name attributes on
8633 8640 * attributes. Thus, if we are just archiving an extended attribute,
8634 8641 * the second segment will contain the attribute name. If we are
8635 8642 * archiving a system attribute of an extended attribute, then the
8636 8643 * second segment will contain the attribute name, and a third segment
8637 8644 * will contain the system attribute name. The attribute pathing
8638 8645 * information is obtained from 'attrpath'.
8639 8646 */
8640 8647
8641 8648 tptr = (struct xattr_buf *)(bufhead + sizeof (struct xattr_hdr));
8642 8649 (void) sprintf(tptr->h_namesz, "%0*d", sizeof (tptr->h_namesz) - 1,
8643 8650 stringlen);
8644 8651 (void) strcpy(tptr->h_names, filename);
8645 8652 attrnames_index = strlen(filename) + 1;
8646 8653 (void) strcpy(&tptr->h_names[attrnames_index], attrpath);
8647 8654 tptr->h_typeflag = typeflag;
8648 8655
8649 8656 /*
8650 8657 * Split the attrnames section into two segments if 'attrpath'
8651 8658 * contains pathing information for a system attribute of an
8652 8659 * extended attribute. We split them by replacing the '/' with
8653 8660 * a '\0'.
8654 8661 */
8655 8662 if ((aptr = strpbrk(&tptr->h_names[attrnames_index], "/")) != NULL) {
8656 8663 *aptr = '\0';
8657 8664 }
8658 8665
8659 8666 /*
8660 8667 * Now fill in the optional link section if we have one
8661 8668 */
8662 8669
8663 8670 if (linkinfo != NULL) {
8664 8671 tptr = (struct xattr_buf *)(bufhead +
8665 8672 sizeof (struct xattr_hdr) + complen);
8666 8673
8667 8674 (void) sprintf(tptr->h_namesz, "%0*d",
8668 8675 sizeof (tptr->h_namesz) - 1, linkstringlen);
8669 8676 (void) strcpy(tptr->h_names, linkinfo->L_gen.g_attrfnam_p);
8670 8677 (void) strcpy(
8671 8678 &tptr->h_names[strlen(linkinfo->L_gen.g_attrfnam_p) + 1],
8672 8679 linkinfo->L_gen.g_attrnam_p);
8673 8680 tptr->h_typeflag = typeflag;
8674 8681 }
8675 8682 *attrbuf = (char *)bufhead;
8676 8683 *rlen = len;
8677 8684 }
8678 8685 #endif /* O_XATTR */
8679 8686
8680 8687 static char
8681 8688 tartype(int type)
8682 8689 {
8683 8690 switch (type) {
8684 8691
8685 8692 case S_IFDIR:
8686 8693 return (DIRTYPE);
8687 8694
8688 8695 case S_IFLNK:
8689 8696 return (SYMTYPE);
8690 8697
8691 8698 case S_IFIFO:
8692 8699 return (FIFOTYPE);
8693 8700
8694 8701 case S_IFCHR:
8695 8702 return (CHRTYPE);
8696 8703
8697 8704 case S_IFBLK:
8698 8705 return (BLKTYPE);
8699 8706
8700 8707 case S_IFREG:
8701 8708 return (REGTYPE);
8702 8709
8703 8710 default:
8704 8711 return ('\0');
8705 8712 }
8706 8713 }
8707 8714
8708 8715 #if defined(O_XATTR)
8709 8716 static int
8710 8717 openfile(int omode)
8711 8718 {
8712 8719 if (G_p->g_attrnam_p != NULL) {
8713 8720 return (openat(G_p->g_dirfd, G_p->g_attrnam_p, omode));
8714 8721 } else {
8715 8722 return (openat(G_p->g_dirfd,
8716 8723 get_component(G_p->g_nam_p), omode));
8717 8724 }
8718 8725 }
8719 8726 #else
8720 8727 static int
8721 8728 openfile(int omode)
8722 8729 {
8723 8730 return (openat(G_p->g_dirfd, get_component(G_p->g_nam_p), omode));
8724 8731 }
8725 8732 #endif
8726 8733
8727 8734 #if defined(O_XATTR)
8728 8735 static int
8729 8736 read_xattr_hdr()
8730 8737 {
8731 8738 off_t bytes;
8732 8739 int comp_len, link_len;
8733 8740 int namelen;
8734 8741 int asz;
8735 8742 int cnt;
8736 8743 char *tp;
8737 8744 char *xattrapath;
8738 8745 int pad;
8739 8746 int parentfilelen;
8740 8747
8741 8748 /*
8742 8749 * Include any padding in the read. We need to be positioned
8743 8750 * at beginning of next header.
8744 8751 */
8745 8752
8746 8753 bytes = Gen.g_filesz;
8747 8754
8748 8755 if ((xattrhead = e_zalloc(E_NORMAL, (size_t)bytes)) == NULL) {
8749 8756 (void) fprintf(stderr, gettext(
8750 8757 "Insufficient memory for extended attribute\n"));
8751 8758 return (1);
8752 8759 }
8753 8760
8754 8761 tp = (char *)xattrhead;
8755 8762 while (bytes > 0) {
8756 8763 cnt = (int)(bytes > CPIOBSZ) ? CPIOBSZ : bytes;
8757 8764 FILL(cnt);
8758 8765 (void) memcpy(tp, Buffr.b_out_p, cnt);
8759 8766 tp += cnt;
8760 8767 Buffr.b_out_p += cnt;
8761 8768 Buffr.b_cnt -= (off_t)cnt;
8762 8769 bytes -= (off_t)cnt;
8763 8770 }
8764 8771
8765 8772 pad = (Pad_val + 1 - (Gen.g_filesz & Pad_val)) &
8766 8773 Pad_val;
8767 8774 if (pad != 0) {
8768 8775 FILL(pad);
8769 8776 Buffr.b_out_p += pad;
8770 8777 Buffr.b_cnt -= (off_t)pad;
8771 8778 }
8772 8779
8773 8780 /*
8774 8781 * Validate that we can handle header format
8775 8782 */
8776 8783
8777 8784 if (strcmp(xattrhead->h_version, XATTR_ARCH_VERS) != 0) {
8778 8785 (void) fprintf(stderr,
8779 8786 gettext("Unknown extended attribute format encountered\n"));
8780 8787 (void) fprintf(stderr,
8781 8788 gettext("Disabling extended attribute header parsing\n"));
8782 8789 xattrbadhead = 1;
8783 8790 return (1);
8784 8791 }
8785 8792 (void) sscanf(xattrhead->h_component_len, "%10d", &comp_len);
8786 8793 (void) sscanf(xattrhead->h_link_component_len, "%10d", &link_len);
8787 8794 xattrp = (struct xattr_buf *)(((char *)xattrhead) +
8788 8795 sizeof (struct xattr_hdr));
8789 8796 (void) sscanf(xattrp->h_namesz, "%7d", &namelen);
8790 8797 if (link_len > 0) {
8791 8798 xattr_linkp = (struct xattr_buf *)((int)xattrp + (int)comp_len);
8792 8799 } else {
8793 8800 xattr_linkp = NULL;
8794 8801 }
8795 8802
8796 8803 /*
8797 8804 * Gather the attribute path from the filename and attrnames section.
8798 8805 * The filename and attrnames section can be composed of two or more
8799 8806 * path segments separated by a null character. The first segment
8800 8807 * is the path to the parent file that roots the entire sequence in
8801 8808 * the normal name space. The remaining segments describes a path
8802 8809 * rooted at the hidden extended attribute directory of the leaf file of
8803 8810 * the previous segment, making it possible to name attributes on
8804 8811 * attributes.
8805 8812 */
8806 8813 parentfilelen = strlen(xattrp->h_names);
8807 8814 xattrapath = xattrp->h_names + parentfilelen + 1;
8808 8815 asz = strlen(xattrapath);
8809 8816 if ((asz + parentfilelen + 2) < namelen) {
8810 8817 /*
8811 8818 * The attrnames section contains a system attribute on an
8812 8819 * attribute. Save the name of the attribute for use later,
8813 8820 * and replace the null separating the attribute name from
8814 8821 * the system attribute name with a '/' so that xattrapath can
8815 8822 * be used to display messages with the full attribute path name
8816 8823 * rooted at the hidden attribute directory of the base file
8817 8824 * in normal name space.
8818 8825 */
8819 8826 xattrapath[asz] = '/';
8820 8827 }
8821 8828
8822 8829 return (0);
8823 8830 }
8824 8831 #endif
8825 8832
8826 8833 static mode_t
8827 8834 attrmode(char type)
8828 8835 {
8829 8836 mode_t mode;
8830 8837
8831 8838 switch (type) {
8832 8839 case '\0':
8833 8840 case REGTYPE:
8834 8841 case LNKTYPE:
8835 8842 mode = S_IFREG;
8836 8843 break;
8837 8844
8838 8845 case SYMTYPE:
8839 8846 mode = S_IFLNK;
8840 8847 break;
8841 8848
8842 8849 case CHRTYPE:
8843 8850 mode = S_IFCHR;
8844 8851 break;
8845 8852 case BLKTYPE:
8846 8853 mode = S_IFBLK;
8847 8854 break;
8848 8855 case DIRTYPE:
8849 8856 mode = S_IFDIR;
8850 8857 break;
8851 8858 case FIFOTYPE:
8852 8859 mode = S_IFIFO;
8853 8860 break;
8854 8861 case CONTTYPE:
8855 8862 default:
8856 8863 mode = 0;
8857 8864 }
8858 8865
8859 8866 return (mode);
8860 8867 }
8861 8868
8862 8869 #if defined(O_XATTR)
8863 8870 static char *
8864 8871 get_component(char *path)
8865 8872 {
8866 8873 char *ptr;
8867 8874
8868 8875 ptr = strrchr(path, '/');
8869 8876 if (ptr == NULL) {
8870 8877 return (path);
8871 8878 } else {
8872 8879 /*
8873 8880 * Handle trailing slash
8874 8881 */
8875 8882 if (*(ptr + 1) == '\0')
8876 8883 return (ptr);
8877 8884 else
8878 8885 return (ptr + 1);
8879 8886 }
8880 8887 }
8881 8888 #else
8882 8889 static char *
8883 8890 get_component(char *path)
8884 8891 {
8885 8892 return (path);
8886 8893 }
8887 8894 #endif
8888 8895
8889 8896 static int
8890 8897 open_dir(char *name)
8891 8898 {
8892 8899 int fd = -1;
8893 8900 int cnt = 0;
8894 8901 char *dir;
8895 8902
8896 8903 dir = e_zalloc(E_EXIT, strlen(name) + 1);
8897 8904
8898 8905 /*
8899 8906 * open directory; creating missing directories along the way.
8900 8907 */
8901 8908 get_parent(name, dir);
8902 8909 do {
8903 8910 fd = open(dir, O_RDONLY);
8904 8911 if (fd != -1) {
8905 8912 free(dir);
8906 8913 return (fd);
8907 8914 }
8908 8915 cnt++;
8909 8916 } while (cnt <= 1 && missdir(name) == 0);
8910 8917
8911 8918 free(dir);
8912 8919 return (-1);
8913 8920 }
8914 8921
8915 8922 static int
8916 8923 open_dirfd()
8917 8924 {
8918 8925 #ifdef O_XATTR
8919 8926 if ((Args & OCt) == 0) {
8920 8927 close_dirfd();
8921 8928 if (G_p->g_attrnam_p != NULL) {
8922 8929 int rw_sysattr;
8923 8930
8924 8931 /*
8925 8932 * Open the file's attribute directory.
8926 8933 * Change into the base file's starting directory then
8927 8934 * call open_attr_dir() to open the attribute directory
8928 8935 * of either the base file (if G_p->g_attrparent_p is
8929 8936 * NULL) or the attribute (if G_p->g_attrparent_p is
8930 8937 * set) of the base file.
8931 8938 */
8932 8939 (void) fchdir(G_p->g_baseparent_fd);
8933 8940 (void) open_attr_dir(G_p->g_attrnam_p,
8934 8941 G_p->g_attrfnam_p, G_p->g_baseparent_fd,
8935 8942 (G_p->g_attrparent_p == NULL) ? NULL :
8936 8943 G_p->g_attrparent_p, &G_p->g_dirfd, &rw_sysattr);
8937 8944 if (Args & OCi) {
8938 8945 int saveerrno = errno;
8939 8946
8940 8947 (void) fchdir(G_p->g_baseparent_fd);
8941 8948 errno = saveerrno;
8942 8949 }
8943 8950 if ((G_p->g_dirfd == -1) && (Args & (OCi | OCp))) {
8944 8951 msg(ERRN,
8945 8952 "Cannot open attribute directory "
8946 8953 "of %s%s%sfile \"%s\"",
8947 8954 (G_p->g_attrparent_p == NULL) ? "" :
8948 8955 gettext("attribute \""),
8949 8956 (G_p->g_attrparent_p == NULL) ? "" :
8950 8957 G_p->g_attrparent_p,
8951 8958 (G_p->g_attrparent_p == NULL) ? "" :
8952 8959 gettext("\" of "),
8953 8960 G_p->g_attrfnam_p);
8954 8961 return (FILE_PASS_ERR);
8955 8962 }
8956 8963 } else {
8957 8964 G_p->g_dirfd = open_dir(G_p->g_nam_p);
8958 8965 if (G_p->g_dirfd == -1) {
8959 8966 msg(ERRN,
8960 8967 "Cannot open/create %s", G_p->g_nam_p);
8961 8968 return (1);
8962 8969 }
8963 8970 }
8964 8971 } else {
8965 8972 G_p->g_dirfd = -1;
8966 8973 }
8967 8974 #else
8968 8975 G_p->g_dirfd = -1;
8969 8976 #endif
8970 8977 return (0);
8971 8978 }
8972 8979
8973 8980 static void
8974 8981 close_dirfd()
8975 8982 {
8976 8983 if (G_p->g_dirfd != -1) {
8977 8984 (void) close(G_p->g_dirfd);
8978 8985 G_p->g_dirfd = -1;
8979 8986 }
8980 8987 }
8981 8988
8982 8989 static void
8983 8990 write_xattr_hdr()
8984 8991 {
8985 8992 char *attrbuf = NULL;
8986 8993 int attrlen = 0;
8987 8994 char *namep;
8988 8995 struct Lnk *tl_p, *linkinfo;
8989 8996
8990 8997 /*
8991 8998 * namep was allocated in xattrs_out. It is big enough to hold
8992 8999 * either the name + .hdr on the end or just the attr name
8993 9000 */
8994 9001
8995 9002 #if defined(O_XATTR)
8996 9003 namep = Gen.g_nam_p;
8997 9004 (void) creat_hdr();
8998 9005
8999 9006 if (Args & OCo) {
9000 9007 linkinfo = NULL;
9001 9008 tl_p = Lnk_hd.L_nxt_p;
9002 9009 while (tl_p != &Lnk_hd) {
9003 9010 if (tl_p->L_gen.g_ino == G_p->g_ino &&
9004 9011 tl_p->L_gen.g_dev == G_p->g_dev) {
9005 9012 linkinfo = tl_p;
9006 9013 break; /* found */
9007 9014 }
9008 9015 tl_p = tl_p->L_nxt_p;
9009 9016 }
9010 9017 prepare_xattr_hdr(&attrbuf, Gen.g_attrfnam_p,
9011 9018 Gen.g_attrpath_p,
9012 9019 (linkinfo == NULL) ?
9013 9020 tartype(Gen.g_mode & Ftype) : LNKTYPE,
9014 9021 linkinfo, &attrlen);
9015 9022 Gen.g_filesz = attrlen;
9016 9023 write_hdr(ARCHIVE_XATTR, (off_t)attrlen);
9017 9024 /*LINTED*/
9018 9025 (void) sprintf(namep, "%s/%s", DEVNULL, Gen.g_attrnam_p);
9019 9026 write_ancillary(attrbuf, attrlen, B_TRUE);
9020 9027 }
9021 9028
9022 9029 (void) creat_hdr();
9023 9030 #endif
9024 9031 }
9025 9032
9026 9033 /*
9027 9034 * skip over extra slashes in string.
9028 9035 *
9029 9036 * For example:
9030 9037 * /usr/tmp/////
9031 9038 *
9032 9039 * would return pointer at
9033 9040 * /usr/tmp/////
9034 9041 * ^
9035 9042 */
9036 9043 static char *
9037 9044 skipslashes(char *string, char *start)
9038 9045 {
9039 9046 while ((string > start) && *(string - 1) == '/') {
9040 9047 string--;
9041 9048 }
9042 9049
9043 9050 return (string);
9044 9051 }
9045 9052
9046 9053 static sl_info_t *
9047 9054 sl_info_alloc(void)
9048 9055 {
9049 9056 static int num_left;
9050 9057 static sl_info_t *slipool;
9051 9058
9052 9059 if (num_left > 0) {
9053 9060 return (&slipool[--num_left]);
9054 9061 }
9055 9062 num_left = SL_INFO_ALLOC_CHUNK;
9056 9063 slipool = e_zalloc(E_EXIT, sizeof (sl_info_t) * num_left);
9057 9064 return (&slipool[--num_left]);
9058 9065 }
9059 9066
9060 9067 /*
9061 9068 * If a match for the key values was found in the tree, return a pointer to it.
9062 9069 * If a match was not found, insert it and return a pointer to it. This is
9063 9070 * based on Knuth's Algorithm A in Vol 3, section 6.2.3.
9064 9071 */
9065 9072
9066 9073 sl_info_t *
9067 9074 sl_insert(dev_t device, ino_t inode, int ftype)
9068 9075 {
9069 9076 sl_info_t *p; /* moves down the tree */
9070 9077 sl_info_t *q; /* scratch */
9071 9078 sl_info_t *r; /* scratch */
9072 9079 sl_info_t *s; /* pt where rebalancing may be needed */
9073 9080 sl_info_t *t; /* father of s */
9074 9081 sl_info_t *head;
9075 9082
9076 9083 int a; /* used to hold balance factors */
9077 9084 int done; /* loop control */
9078 9085 int cmpflg; /* used to hold the result of a comparison */
9079 9086
9080 9087 /* initialize */
9081 9088
9082 9089 head = sl_devhash_lookup(device);
9083 9090
9084 9091 if (head == NULL) {
9085 9092 head = sl_info_alloc();
9086 9093 head->llink = NULL;
9087 9094 head->bal = 0;
9088 9095
9089 9096 p = head->rlink = sl_info_alloc();
9090 9097 p->sl_ino = inode;
9091 9098 p->sl_ftype = ftype;
9092 9099 p->sl_count = 0;
9093 9100 p->bal = 0;
9094 9101 p->llink = NULL;
9095 9102 p->rlink = NULL;
9096 9103 sl_devhash_insert(device, head);
9097 9104 return (p);
9098 9105 }
9099 9106
9100 9107 t = head;
9101 9108 s = p = head->rlink;
9102 9109
9103 9110 /* compare */
9104 9111
9105 9112 for (done = 0; ! done; ) {
9106 9113 switch (sl_compare(inode, ftype, p->sl_ino, p->sl_ftype)) {
9107 9114 case -1:
9108 9115 /* move left */
9109 9116
9110 9117 q = p->llink;
9111 9118
9112 9119 if (q == NULL) {
9113 9120 q = sl_info_alloc();
9114 9121 p->llink = q;
9115 9122 done = 1;
9116 9123 continue;
9117 9124 }
9118 9125
9119 9126 break;
9120 9127
9121 9128 case 0:
9122 9129 /* found it */
9123 9130 return (p);
9124 9131
9125 9132 case 1:
9126 9133 /* move right */
9127 9134
9128 9135 q = p->rlink;
9129 9136
9130 9137 if (q == NULL) {
9131 9138 q = sl_info_alloc();
9132 9139 p->rlink = q;
9133 9140 done = 1;
9134 9141 continue;
9135 9142 }
9136 9143
9137 9144 break;
9138 9145 }
9139 9146
9140 9147 if (q->bal != 0) {
9141 9148 t = p;
9142 9149 s = q;
9143 9150 }
9144 9151
9145 9152 p = q;
9146 9153 }
9147 9154
9148 9155 /* insert */
9149 9156
9150 9157 q->sl_ino = inode;
9151 9158 q->sl_ftype = ftype;
9152 9159 q->sl_count = 0;
9153 9160 q->llink = q->rlink = NULL;
9154 9161 q->bal = 0;
9155 9162
9156 9163 /* adjust balance factors */
9157 9164
9158 9165 if ((cmpflg = sl_compare(inode, ftype, s->sl_ino, s->sl_ftype)) < 0) {
9159 9166 r = p = s->llink;
9160 9167 } else {
9161 9168 r = p = s->rlink;
9162 9169 }
9163 9170
9164 9171 while (p != q) {
9165 9172 switch (sl_compare(inode, ftype, p->sl_ino, p->sl_ftype)) {
9166 9173 case -1:
9167 9174 p->bal = -1;
9168 9175 p = p->llink;
9169 9176 break;
9170 9177
9171 9178 case 0:
9172 9179 break;
9173 9180
9174 9181 case 1:
9175 9182 p->bal = 1;
9176 9183 p = p->rlink;
9177 9184 break;
9178 9185 }
9179 9186 }
9180 9187
9181 9188 /* balancing act */
9182 9189
9183 9190 if (cmpflg < 0) {
9184 9191 a = -1;
9185 9192 } else {
9186 9193 a = 1;
9187 9194 }
9188 9195
9189 9196 if (s->bal == 0) {
9190 9197 s->bal = a;
9191 9198 head->llink = (sl_info_t *)((int)head->llink + 1);
9192 9199 return (q);
9193 9200 } else if (s->bal == -a) {
9194 9201 s->bal = 0;
9195 9202 return (q);
9196 9203 }
9197 9204
9198 9205 /*
9199 9206 * (s->bal == a)
9200 9207 */
9201 9208
9202 9209 if (r->bal == a) {
9203 9210 /* single rotation */
9204 9211
9205 9212 p = r;
9206 9213
9207 9214 if (a == -1) {
9208 9215 s->llink = r->rlink;
9209 9216 r->rlink = s;
9210 9217 } else if (a == 1) {
9211 9218 s->rlink = r->llink;
9212 9219 r->llink = s;
9213 9220 }
9214 9221
9215 9222 s->bal = r->bal = 0;
9216 9223
9217 9224 } else if (r->bal == -a) {
9218 9225 /* double rotation */
9219 9226
9220 9227 if (a == -1) {
9221 9228 p = r->rlink;
9222 9229 r->rlink = p->llink;
9223 9230 p->llink = r;
9224 9231 s->llink = p->rlink;
9225 9232 p->rlink = s;
9226 9233 } else if (a == 1) {
9227 9234 p = r->llink;
9228 9235 r->llink = p->rlink;
9229 9236 p->rlink = r;
9230 9237 s->rlink = p->llink;
9231 9238 p->llink = s;
9232 9239 }
9233 9240
9234 9241 if (p->bal == 0) {
9235 9242 s->bal = 0;
9236 9243 r->bal = 0;
9237 9244 } else if (p->bal == -a) {
9238 9245 s->bal = 0;
9239 9246 r->bal = a;
9240 9247 } else if (p->bal == a) {
9241 9248 s->bal = -a;
9242 9249 r->bal = 0;
9243 9250 }
9244 9251
9245 9252 p->bal = 0;
9246 9253 }
9247 9254
9248 9255 /* finishing touch */
9249 9256
9250 9257 if (s == t->rlink) {
9251 9258 t->rlink = p;
9252 9259 } else {
9253 9260 t->llink = p;
9254 9261 }
9255 9262
9256 9263 return (q);
9257 9264 }
9258 9265
9259 9266 /*
9260 9267 * sl_numlinks: return the number of links that we saw during our preview.
9261 9268 */
9262 9269
9263 9270 static ulong_t
9264 9271 sl_numlinks(dev_t device, ino_t inode, int ftype)
9265 9272 {
9266 9273 sl_info_t *p = sl_search(device, inode, ftype);
9267 9274
9268 9275 if (p) {
9269 9276 return (p->sl_count);
9270 9277 } else {
9271 9278 return (1);
9272 9279 }
9273 9280 }
9274 9281
9275 9282 /*
9276 9283 * Preview extended and extended system attributes.
9277 9284 *
9278 9285 * Return 0 if successful, otherwise return 1.
9279 9286 */
9280 9287 #if defined(O_XATTR)
9281 9288 static int
9282 9289 preview_attrs(char *s, char *attrparent)
9283 9290 {
9284 9291 char *filename = (attrparent == NULL) ? s : attrparent;
9285 9292 int dirfd;
9286 9293 int tmpfd;
9287 9294 int islnk;
9288 9295 int rc = 0;
9289 9296 int arc_rwsysattr = 0;
9290 9297 int rw_sysattr = 0;
9291 9298 int ext_attr = 0;
9292 9299 DIR *dirp;
9293 9300 struct dirent *dp;
9294 9301 struct stat sb;
9295 9302
9296 9303 /*
9297 9304 * If the underlying file system supports it, then
9298 9305 * archive the extended attributes if -@ was specified,
9299 9306 * and the extended system attributes if -/ was
9300 9307 * specified.
9301 9308 */
9302 9309 if (verify_attr_support(filename, (attrparent == NULL), ARC_CREATE,
9303 9310 &ext_attr) != ATTR_OK) {
9304 9311 return (1);
9305 9312 }
9306 9313
9307 9314 #if defined(_PC_SATTR_ENABLED)
9308 9315 if (SysAtflag) {
9309 9316 int filefd;
9310 9317 nvlist_t *slist = NULL;
9311 9318
9312 9319 /* Determine if there are non-transient system attributes. */
9313 9320 errno = 0;
9314 9321 if ((filefd = open(filename, O_RDONLY)) < 0) {
9315 9322 return (1);
9316 9323 }
9317 9324 if (((slist = sysattr_list(myname, filefd,
9318 9325 filename)) != NULL) || (errno != 0)) {
9319 9326 arc_rwsysattr = 1;
9320 9327 }
9321 9328 if (slist != NULL) {
9322 9329 (void) nvlist_free(slist);
9323 9330 slist = NULL;
9324 9331 }
9325 9332 (void) close(filefd);
9326 9333 }
9327 9334
9328 9335 if ((arc_rwsysattr == 0) && ((attrparent != NULL) ||
9329 9336 (SysAtflag && !ext_attr))) {
9330 9337 return (1);
9331 9338 }
9332 9339 #endif /* _PC_SATTR_ENABLED */
9333 9340 /*
9334 9341 * We need to open the attribute directory of the
9335 9342 * file, and preview all of the file's attributes as
9336 9343 * attributes of the file can be hard links to other
9337 9344 * attributes of the file.
9338 9345 */
9339 9346 dirfd = attropen(filename, ".", O_RDONLY);
9340 9347 if (dirfd == -1)
9341 9348 return (1);
9342 9349
9343 9350 tmpfd = dup(dirfd);
9344 9351 if (tmpfd == -1) {
9345 9352 (void) close(dirfd);
9346 9353 return (1);
9347 9354 }
9348 9355 dirp = fdopendir(tmpfd);
9349 9356 if (dirp == NULL) {
9350 9357 (void) close(dirfd);
9351 9358 (void) close(tmpfd);
9352 9359 return (1);
9353 9360 }
9354 9361
9355 9362 while (dp = readdir(dirp)) {
9356 9363 if (dp->d_name[0] == '.') {
9357 9364 if (dp->d_name[1] == '\0') {
9358 9365 Hiddendir = 1;
9359 9366 } else if ((dp->d_name[1] == '.') &&
9360 9367 (dp->d_name[2] == '\0')) {
9361 9368 continue;
9362 9369 } else {
9363 9370 Hiddendir = 0;
9364 9371 }
9365 9372 } else {
9366 9373 Hiddendir = 0;
9367 9374 }
9368 9375
9369 9376 if (fstatat(dirfd, dp->d_name, &sb,
9370 9377 AT_SYMLINK_NOFOLLOW) < 0) {
9371 9378 continue;
9372 9379 }
9373 9380
9374 9381 if (verify_attr(dp->d_name, attrparent,
9375 9382 arc_rwsysattr, &rw_sysattr) != ATTR_OK) {
9376 9383 continue;
9377 9384 }
9378 9385
9379 9386 islnk = 0;
9380 9387 if (S_ISLNK(sb.st_mode)) {
9381 9388 islnk = 1;
9382 9389 if (Args & OCL) {
9383 9390 if (fstatat(dirfd, dp->d_name,
9384 9391 &sb, 0) < 0) {
9385 9392 continue;
9386 9393 }
9387 9394 }
9388 9395 }
9389 9396 sl_remember_tgt(&sb, islnk, rw_sysattr);
9390 9397
9391 9398 /*
9392 9399 * Recursively call preview_attrs() to preview extended
9393 9400 * system attributes of attributes.
9394 9401 */
9395 9402 if (SysAtflag && !Hiddendir && !rw_sysattr) {
9396 9403 int my_cwd = save_cwd();
9397 9404
9398 9405 (void) fchdir(dirfd);
9399 9406 rc = preview_attrs(s, dp->d_name);
9400 9407 rest_cwd(my_cwd);
9401 9408 }
9402 9409 }
9403 9410 (void) closedir(dirp);
9404 9411 (void) close(dirfd);
9405 9412 return (rc);
9406 9413 }
9407 9414 #endif /* O_XATTR */
9408 9415
9409 9416 /*
9410 9417 * sl_preview_synonyms: Read the file list from the input stream, remembering
9411 9418 * each reference to each file.
9412 9419 */
9413 9420
9414 9421 static void
9415 9422 sl_preview_synonyms(void)
9416 9423 {
9417 9424 char buf [APATH+1];
9418 9425 char *s;
9419 9426
9420 9427 char *suffix = "/cpioXXXXXX";
9421 9428 char *tmpdir = getenv("TMPDIR");
9422 9429 int tmpfd, islnk;
9423 9430 FILE *tmpfile;
9424 9431 char *tmpfname;
9425 9432
9426 9433 if (tmpdir == NULL || *tmpdir == '\0' ||
9427 9434 (strlen(tmpdir) + strlen(suffix)) > APATH) {
9428 9435 struct statvfs tdsb;
9429 9436
9430 9437 tmpdir = "/var/tmp";
9431 9438
9432 9439 /* /var/tmp is read-only in the mini-root environment */
9433 9440
9434 9441 if (statvfs(tmpdir, &tdsb) == -1 || tdsb.f_flag & ST_RDONLY) {
9435 9442 tmpdir = "/tmp";
9436 9443 }
9437 9444 }
9438 9445
9439 9446 tmpfname = e_zalloc(E_EXIT, strlen(tmpdir) + strlen(suffix) + 1);
9440 9447
9441 9448 (void) strcpy(tmpfname, tmpdir);
9442 9449 (void) strcat(tmpfname, suffix);
9443 9450
9444 9451 if ((tmpfd = mkstemp(tmpfname)) == -1) {
9445 9452 msg(EXTN, "cannot open tmpfile %s%s", tmpdir, suffix);
9446 9453 }
9447 9454
9448 9455 if (unlink(tmpfname) == -1) {
9449 9456 msg(EXTN, "cannot unlink tmpfile %s", tmpfname);
9450 9457 }
9451 9458
9452 9459 if ((tmpfile = fdopen(tmpfd, "w+")) == NULL) {
9453 9460 msg(EXTN, "cannot fdopen tmpfile %s", tmpfname);
9454 9461 }
9455 9462
9456 9463 while ((s = fgets(buf, APATH+1, In_p)) != NULL) {
9457 9464 size_t lastchar;
9458 9465 struct stat sb;
9459 9466
9460 9467 if (fputs(buf, tmpfile) == EOF) {
9461 9468 msg(EXTN, "problem writing to tmpfile %s", tmpfname);
9462 9469 }
9463 9470
9464 9471 /* pre-process the name */
9465 9472
9466 9473 lastchar = strlen(s) - 1;
9467 9474
9468 9475 if (s[lastchar] != '\n' && lastchar == APATH - 1) {
9469 9476 continue;
9470 9477 } else {
9471 9478 s[lastchar] = '\0';
9472 9479 }
9473 9480
9474 9481 while (s[0] == '.' && s[1] == '/') {
9475 9482 s += 2;
9476 9483 while (s[0] == '/') {
9477 9484 s++;
9478 9485 }
9479 9486 }
9480 9487
9481 9488 if (lstat(s, &sb) < 0) {
9482 9489 continue;
9483 9490 }
9484 9491 islnk = 0;
9485 9492 if (S_ISLNK(sb.st_mode)) {
9486 9493 islnk = 1;
9487 9494 if (Args & OCL) {
9488 9495 if (stat(s, &sb) < 0) {
9489 9496 continue;
9490 9497 }
9491 9498 }
9492 9499 }
9493 9500 sl_remember_tgt(&sb, islnk, 0);
9494 9501
9495 9502 #if defined(O_XATTR)
9496 9503 if (Atflag || SysAtflag) {
9497 9504 (void) preview_attrs(s, NULL);
9498 9505 }
9499 9506 #endif /* O_XATTR */
9500 9507 }
9501 9508
9502 9509 if (ferror(In_p)) {
9503 9510 msg(EXTN, "error reading stdin");
9504 9511 }
9505 9512
9506 9513 if (fseek(tmpfile, 0L, SEEK_SET) == -1) {
9507 9514 msg(EXTN, "cannot fseek on tmpfile %s", tmpfname);
9508 9515 }
9509 9516
9510 9517 In_p = tmpfile;
9511 9518 free(tmpfname);
9512 9519 }
9513 9520
9514 9521 /*
9515 9522 * sl_remember_tgt: Add the device/inode for lstat or stat info to the list of
9516 9523 * those we've seen before.
9517 9524 *
9518 9525 * This tree (rooted under head) is keyed by the device/inode of the file
9519 9526 * being pointed to. A count is kept of the number of references encountered
9520 9527 * so far.
9521 9528 */
9522 9529
9523 9530 static void
9524 9531 sl_remember_tgt(const struct stat *sbp, int isSymlink, int is_sysattr)
9525 9532 {
9526 9533 sl_info_t *p;
9527 9534 dev_t device;
9528 9535 ino_t inode;
9529 9536 int ftype;
9530 9537
9531 9538 device = sbp->st_dev;
9532 9539 inode = sbp->st_ino;
9533 9540 ftype = sbp->st_mode & Ftype;
9534 9541
9535 9542 /* Determine whether we've seen this one before */
9536 9543
9537 9544 p = sl_insert(device, inode, ftype);
9538 9545
9539 9546 if (p->sl_count > 0) {
9540 9547 /*
9541 9548 * It appears as if have seen this file before as we found a
9542 9549 * matching device, inode, and file type as a file already
9543 9550 * processed. Since there can possibly be files with the
9544 9551 * same device, inode, and file type, but aren't hard links
9545 9552 * (e.g., read-write system attribute files will always have
9546 9553 * the same inode), we need to only attempt to add one to the
9547 9554 * link count if the file we are processing is a hard link
9548 9555 * (i.e., st_nlink > 1).
9549 9556 *
9550 9557 * Note that if we are not chasing symlinks, and this one is a
9551 9558 * symlink, it is identically the one we saw before (you cannot
9552 9559 * have hard links to symlinks); in this case, we leave the
9553 9560 * count alone, so that we don't wind up archiving a symlink to
9554 9561 * itself.
9555 9562 */
9556 9563
9557 9564 if (((Args & OCL) || (! isSymlink)) && !is_sysattr) {
9558 9565 p->sl_count++;
9559 9566 }
9560 9567 } else {
9561 9568 /* We have not seen this file before */
9562 9569
9563 9570 p->sl_count = 1;
9564 9571
9565 9572 if (Use_old_stat) {
9566 9573 /* -Hodc: remap inode (-1 on overflow) */
9567 9574
9568 9575 sl_remap_t *q;
9569 9576
9570 9577 for (q = sl_remap_head; q && (q->dev != device);
9571 9578 q = q->next) {
9572 9579 /* do nothing */
9573 9580 }
9574 9581
9575 9582 if (q == NULL) {
9576 9583 q = e_zalloc(E_EXIT, sizeof (sl_remap_t));
9577 9584 q->dev = device;
9578 9585 p->sl_ino2 = q->inode_count = 1;
9579 9586
9580 9587 q->next = (sl_remap_head) ?
9581 9588 sl_remap_head->next : NULL;
9582 9589 sl_remap_head = q;
9583 9590 } else {
9584 9591 if ((size_t)q->inode_count <=
9585 9592 ((1 << (sizeof (o_ino_t) * 8)) - 1)) {
9586 9593 /* fits in o_ino_t */
9587 9594 p->sl_ino2 = ++(q->inode_count);
9588 9595 } else {
9589 9596 p->sl_ino2 = (ino_t)-1;
9590 9597 }
9591 9598 }
9592 9599 }
9593 9600 }
9594 9601 }
9595 9602
9596 9603 /*
9597 9604 * A faster search, which does not insert the key values into the tree.
9598 9605 * If the a match was found in the tree, return a pointer to it. If it was not
9599 9606 * found, return NULL.
9600 9607 */
9601 9608
9602 9609 sl_info_t *
9603 9610 sl_search(dev_t device, ino_t inode, int ftype)
9604 9611 {
9605 9612 sl_info_t *p; /* moves down the tree */
9606 9613 int c; /* comparison value */
9607 9614 sl_info_t *retval = NULL; /* return value */
9608 9615 sl_info_t *head;
9609 9616
9610 9617 head = sl_devhash_lookup(device);
9611 9618 if (head != NULL) {
9612 9619 for (p = head->rlink; p; ) {
9613 9620 if ((c = sl_compare(inode, ftype, p->sl_ino,
9614 9621 p->sl_ftype)) == 0) {
9615 9622 retval = p;
9616 9623 break;
9617 9624 } else if (c < 0) {
9618 9625 p = p->llink;
9619 9626 } else {
9620 9627 p = p->rlink;
9621 9628 }
9622 9629 }
9623 9630 }
9624 9631
9625 9632 return (retval);
9626 9633 }
9627 9634
9628 9635 static sl_info_t *
9629 9636 sl_devhash_lookup(dev_t device)
9630 9637 {
9631 9638 int key;
9632 9639 sl_info_link_t *lp;
9633 9640 static sl_info_link_t *devcache;
9634 9641
9635 9642 if (devcache != NULL && devcache->dev == device) {
9636 9643 return (devcache->head);
9637 9644 }
9638 9645
9639 9646 key = DEV_HASHKEY(device);
9640 9647 for (lp = sl_devhash[key]; lp; lp = lp->next) {
9641 9648 if (lp->dev == device) {
9642 9649 devcache = lp;
9643 9650 return (lp->head);
9644 9651 }
9645 9652 }
9646 9653 return (NULL);
9647 9654 }
9648 9655
9649 9656 static void
9650 9657 sl_devhash_insert(dev_t device, sl_info_t *head)
9651 9658 {
9652 9659 int key = DEV_HASHKEY(device);
9653 9660 sl_info_link_t *lp;
9654 9661
9655 9662 lp = e_zalloc(E_EXIT, sizeof (sl_info_link_t));
9656 9663 lp->dev = device;
9657 9664 lp->head = head;
9658 9665 lp->next = sl_devhash[key];
9659 9666 sl_devhash[key] = lp;
9660 9667 }
9661 9668
9662 9669 static void
9663 9670 chop_endslashes(char *path)
9664 9671 {
9665 9672 char *end, *ptr;
9666 9673
9667 9674 end = &path[strlen(path) -1];
9668 9675 if (*end == '/' && end != path) {
9669 9676 ptr = skipslashes(end, path);
9670 9677 if (ptr != NULL && ptr != path) {
9671 9678 *ptr = '\0';
9672 9679 }
9673 9680 }
9674 9681 }
9675 9682
9676 9683 #if !defined(O_XATTR)
9677 9684 int
9678 9685 openat64(int fd, char *name, int oflag, mode_t cmode)
9679 9686 {
9680 9687 return (open64(name, oflag, cmode));
9681 9688 }
9682 9689
9683 9690 int
9684 9691 openat(int fd, char *name, int oflag, mode_t cmode)
9685 9692 {
9686 9693 return (open(name, oflag, cmode));
9687 9694 }
9688 9695
9689 9696 int
9690 9697 fchownat(int fd, char *name, uid_t owner, gid_t group, int flag)
9691 9698 {
9692 9699 if (flag == AT_SYMLINK_NOFOLLOW)
9693 9700 return (lchown(name, owner, group));
9694 9701 else
9695 9702 return (chown(name, owner, group));
9696 9703 }
9697 9704
9698 9705 int
9699 9706 renameat(int fromfd, char *old, int tofd, char *new)
9700 9707 {
9701 9708 return (rename(old, new));
9702 9709 }
9703 9710
9704 9711 int
9705 9712 futimesat(int fd, char *path, struct timeval times[2])
9706 9713 {
9707 9714 return (utimes(path, times));
9708 9715 }
9709 9716
9710 9717 int
9711 9718 unlinkat(int dirfd, char *path, int flag)
9712 9719 {
9713 9720 if (flag == AT_REMOVEDIR) {
9714 9721 return (rmdir(path));
9715 9722 } else {
9716 9723 return (unlink(path));
9717 9724 }
9718 9725 }
9719 9726
9720 9727 int
9721 9728 fstatat(int fd, char *path, struct stat *buf, int flag)
9722 9729 {
9723 9730 if (flag == AT_SYMLINK_NOFOLLOW)
9724 9731 return (lstat(path, buf));
9725 9732 else
9726 9733 return (stat(path, buf));
9727 9734 }
9728 9735
9729 9736 int
9730 9737 attropen(char *file, char *attr, int omode, mode_t cmode)
9731 9738 {
9732 9739 errno = ENOTSUP;
9733 9740 return (-1);
9734 9741 }
9735 9742 #endif
↓ open down ↓ |
2847 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX