1 /* @(#)extract.c 1.170 20/07/08 Copyright 1985-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)extract.c 1.170 20/07/08 Copyright 1985-2020 J. Schilling";
6 #endif
7 /*
8 * extract files from archive
9 *
10 * Copyright (c) 1985-2020 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/stdio.h>
27 #include <schily/standard.h>
28 #include "star.h"
29 #include "props.h"
30 #include "table.h"
31 #include <schily/dirent.h> /* XXX Wegen S_IFLNK */
32 #include <schily/unistd.h>
33 #include <schily/fcntl.h>
34 #include <schily/string.h>
35 #include <schily/jmpdefs.h> /* For __fjmalloc() */
36 #define GT_COMERR /* #define comerr gtcomerr */
37 #define GT_ERROR /* #define error gterror */
38 #include <schily/schily.h>
39 #include <schily/stdlib.h>
40 #include <schily/errno.h>
41 #ifdef USE_FIND
42 #include <schily/walk.h>
43 #endif
44
45 #ifdef JOS
46 #define mkdir makedir
47 #endif
48 #include "dirtime.h"
49 #include "restore.h"
50 #include "starsubs.h"
51 #include "checkerr.h"
52 #include <schily/fetchdir.h>
53
54 #define ROOT_UID 0
55
56 #if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST
57 #define is_eexist(err) ((err) == EEXIST || (err) == ENOTEMPTY)
58 #else
59 #define is_eexist(err) ((err) == EEXIST)
60 #endif
61 #if defined(EMISSDIR)
62 #define is_enoent(err) ((err) == ENOENT || (err) == EMISSDIR)
63 #else
64 #define is_enoent(err) ((err) == ENOENT)
65 #endif
66 #if defined(ELOOP)
67 #define is_eloop(err) ((err) == ELOOP)
68 #else
69 #define is_eloop(err) (FALSE)
70 #endif
71
72 /*
73 * Used for _make_copy()/make_copies()/copy_file()
74 */
75 #define HIDE_ENOENT 0x01
76
77 /*
78 * Used by the what paramater of same_file()
79 */
80 #define IS_COPY 0
81 #define IS_LINK 1
82
83 extern FILE *vpr;
84
85 extern char *listfile;
86
87 extern long bufsize;
88 extern char *bigptr;
89
90 extern uid_t dir_uid;
91 extern gid_t dir_gid;
92 extern uid_t my_uid;
93 extern BOOL no_fsync;
94 extern BOOL havepat;
95 extern dev_t curfs;
96 extern int xdebug;
97 extern int verbose;
98 extern BOOL prblockno;
99 extern BOOL nflag;
100 extern BOOL interactive;
101 extern BOOL noxdir;
102 extern BOOL follow;
103 extern BOOL paxfollow;
104 extern BOOL nospec;
105 extern BOOL xdir;
106 extern BOOL xdot;
107 extern BOOL uncond;
108 extern BOOL uncond_rename;
109 extern BOOL keep_old;
110 extern BOOL refresh_old;
111 extern BOOL abs_path;
112 extern BOOL allow_dotdot;
113 extern BOOL secure_links;
114 extern BOOL nowarn;
115 extern BOOL force_hole;
116 extern BOOL to_stdout;
117 extern BOOL force_remove;
118 extern BOOL remove_first;
119 extern BOOL remove_recursive;
120 extern BOOL do_install;
121 extern BOOL copyhardlinks;
122 extern BOOL copysymlinks;
123 extern BOOL copydlinks;
124 extern BOOL hardlinks;
125 extern BOOL symlinks;
126 extern BOOL dorestore;
127 extern BOOL dometa;
128 extern BOOL xmeta;
129 extern BOOL lowmem;
130 extern BOOL do_subst;
131 #ifdef USE_SELINUX
132 extern BOOL selinux_enabled;
133 #endif
134
135 #ifdef USE_FIND
136 extern BOOL dofind;
137 #endif
138
139 LOCAL void init_umask __PR((void));
140 EXPORT void extract __PR((char *vhname));
141 EXPORT BOOL extracti __PR((FINFO *info, imap_t *imp));
142 EXPORT BOOL newer __PR((FINFO *info, FINFO *cinfo));
143 EXPORT BOOL same_symlink __PR((FINFO *info));
144 LOCAL BOOL _create_dirs __PR((char *name));
145 LOCAL void _dir_setownwer __PR((char *name));
146 EXPORT BOOL create_dirs __PR((char *name));
147 EXPORT BOOL make_adir __PR((FINFO *info));
148 LOCAL BOOL make_dir __PR((FINFO *info));
149 LOCAL BOOL make_link __PR((FINFO *info));
150 LOCAL BOOL make_symlink __PR((FINFO *info));
151 LOCAL BOOL emul_symlink __PR((FINFO *info));
152 LOCAL BOOL emul_link __PR((FINFO *info));
153 LOCAL BOOL same_file __PR((FINFO *info, int what, BOOL do_follow));
154 LOCAL BOOL make_copy __PR((FINFO *info, BOOL do_symlink, int eflags));
155 #ifdef COPY_LINKS_DELAYED
156 LOCAL void add_copy __PR((FINFO *info, BOOL do_symlink));
157 LOCAL void make_copies __PR((void));
158 LOCAL BOOL _make_dcopy __PR((FINFO *info, BOOL do_symlink, int *retp, int eflags));
159 #endif
160 LOCAL BOOL _make_copy __PR((FINFO *info, BOOL do_symlink, int eflags));
161 LOCAL int copy_file __PR((char *from, char *to, BOOL do_symlink, int eflags));
162 LOCAL BOOL make_fifo __PR((FINFO *info));
163 LOCAL BOOL make_special __PR((FINFO *info));
164 LOCAL BOOL file_tmpname __PR((FINFO *info, pathstore_t *path));
165 LOCAL FILE *file_open __PR((FINFO *info, char *name));
166 LOCAL BOOL get_file __PR((FINFO *info));
167 LOCAL BOOL install_rename __PR((FINFO *info, char *xname));
168 LOCAL BOOL name_exists __PR((char *name));
169 LOCAL void remove_tmpname __PR((char *name));
170 LOCAL BOOL get_ofile __PR((FILE *f, FINFO *info));
171 LOCAL ssize_t void_func __PR((void *vp, char *p, size_t amount));
172 EXPORT BOOL void_file __PR((FINFO * info));
173 LOCAL BOOL void_bad __PR((FINFO * info));
174 EXPORT int xt_file __PR((FINFO * info,
175 ssize_t (*)(void *, char *, size_t),
176 void *arg, long amt, char *text));
177 EXPORT void skip_slash __PR((FINFO * info));
178 LOCAL BOOL has_dotdot __PR((char *name));
179 LOCAL BOOL inside_tree __PR((FINFO * info));
180
181 #ifdef COPY_LINKS_DELAYED
182 typedef struct _mcq {
183 struct _mcq *next;
184 FINFO info;
185 BOOL do_symlink;
186 } MCQ;
187
188 LOCAL MCQ *mcq_1st = NULL;
189 LOCAL MCQ *mcq_last = NULL;
190
191 #endif
192
193 /*
194 * This is used to allow extracting archives as non root when they
195 * contain read only directories. It tries to stay as close as possible
196 * to the user's umask when creating intermediate directories.
197 * We do not modify the umask in a way that would even grant unepected
198 * permissions to others for a short time.
199 */
200 LOCAL mode_t old_umask;
201 LOCAL mode_t mode_mask;
202
203 #define PERM_BITS (S_IRWXU|S_IRWXG|S_IRWXO) /* u/g/o basic perm */
204
205 LOCAL void
init_umask()206 init_umask()
207 {
208 old_umask = umask((mode_t)0);
209 mode_mask = PERM_BITS & ~old_umask;
210 if (my_uid != ROOT_UID)
211 umask(old_umask & ~S_IRWXU);
212 else
213 umask(old_umask);
214 }
215
216 EXPORT void
extract(vhname)217 extract(vhname)
218 char *vhname;
219 {
220 #ifdef USE_FIND
221 extern struct WALK walkstate;
222 #endif
223 FINFO finfo;
224 TCB tb;
225 register TCB *ptb = &tb;
226 BOOL restore_init = FALSE;
227 imap_t *imp = NULL;
228
229 init_umask(); /* Needed to extract read only directories */
230
231 if (dorestore) /* With incremental restore, we need to open */
232 sym_open(NULL); /* the 'star-symtable' first. */
233
234 fillbytes((char *)&finfo, sizeof (finfo), '\0');
235
236 if (init_pspace(PS_STDERR, &finfo.f_pname) < 0)
237 return;
238 if (init_pspace(PS_STDERR, &finfo.f_plname) < 0)
239 return;
240
241 #ifdef USE_FIND
242 if (dofind) {
243 walkopen(&walkstate);
244 walkgethome(&walkstate); /* Needed in case we chdir */
245 }
246 #endif
247 finfo.f_tcb = ptb;
248 for (;;) {
249 if (get_tcb(ptb) == EOF)
250 break;
251 finfo.f_name = finfo.f_pname.ps_path;
252 finfo.f_lname = finfo.f_plname.ps_path;
253 if (tcb_to_info(ptb, &finfo) == EOF)
254 break;
255 if (xdebug > 0)
256 dump_info(&finfo);
257 if (prblockno)
258 (void) tblocks(); /* set curblockno */
259
260 if (is_volhdr(&finfo)) {
261 if (!get_volhdr(&finfo, vhname)) {
262 excomerrno(EX_BAD,
263 "Volume Header '%s' does not match '%s'.\n",
264 finfo.f_name, vhname);
265 }
266 void_file(&finfo);
267 continue;
268 }
269 #ifdef USE_FIND
270 if (dofind && !findinfo(&finfo)) {
271 void_file(&finfo);
272 continue;
273 }
274 #endif
275 if (finfo.f_flags & F_BAD_META) {
276 if (!void_bad(&finfo))
277 break;
278 continue;
279 }
280
281 if (!abs_path && /* XXX VVV siehe skip_slash() */
282 (finfo.f_name[0] == '/' /* || finfo.f_lname[0] == '/'*/))
283 skip_slash(&finfo);
284
285 if (dorestore) {
286 extern GINFO *grip; /* Global read info pointer */
287
288 if (!restore_init) {
289 curfs = finfo.f_dev;
290 sym_init(grip);
291 restore_init = TRUE;
292 }
293
294 imp = sym_addrec(&finfo);
295 if (is_dir(&finfo) && grip->dumplevel > 0)
296 imp = sym_dirprepare(&finfo, imp);
297 }
298
299 #ifdef USE_SELINUX
300 if (!to_stdout && selinux_enabled) {
301 /*
302 * Set up security context for next file.
303 */
304 if (!setselinux(&finfo))
305 xstats.s_selinuxerrs++;
306 }
307 #endif
308 /*
309 * Special treatment for the idiosyncratic way of dealing with
310 * hard links in the SVr4 CRC cpio archive format.
311 * The link count is handled by calling read_link() in
312 * cpiotcb_to_info() before.
313 */
314 if ((props.pr_flags & PR_SV_CPIO_LINKS) != 0 &&
315 !is_dir(&finfo) &&
316 (is_link(&finfo) || finfo.f_nlink > 1)) {
317 if (!last_cpio_link(&finfo)) /* Ign. all but last */
318 continue;
319 if (xcpio_link(&finfo)) /* Now extract all */
320 continue;
321 }
322 if (extracti(&finfo, imp) > TRUE) {
323 errmsgno(EX_BAD, "Exiting as -one-file was specified\n");
324 break;
325 }
326 }
327 #ifdef USE_FIND
328 if (dofind) {
329 walkhome(&walkstate);
330 walkclose(&walkstate);
331 free(walkstate.twprivate);
332 }
333 #endif
334
335 #ifdef COPY_LINKS_DELAYED
336 if (copyhardlinks || copysymlinks)
337 make_copies();
338 #endif
339 flushdirtimes(); /* Flush directory stack */
340 if (dorestore)
341 sym_close();
342 }
343
344 /*
345 * Extract one file from archive
346 */
347 EXPORT BOOL
extracti(info,imp)348 extracti(info, imp)
349 FINFO *info;
350 imap_t *imp;
351 {
352 FINFO cinfo;
353 TCB tb;
354 register TCB *ptb = &tb;
355 char *name = info->f_name;
356 BOOL didmatch = FALSE;
357 extern BOOL one_file;
358
359 if (listfile && !hash_lookup(info->f_name)) {
360 void_file(info);
361 return (FALSE);
362 }
363 if (hash_xlookup(info->f_name)) {
364 void_file(info);
365 return (FALSE);
366 }
367 if (havepat) {
368 if (!match(info->f_name)) {
369 void_file(info);
370 return (FALSE);
371 }
372 if (one_file)
373 didmatch = TRUE;
374 }
375 if (!is_file(info) && to_stdout) {
376 void_file(info);
377 return (FALSE);
378 }
379 if (is_special(info) && nospec) {
380 if (!errhidden(E_SPECIALFILE, info->f_name)) {
381 if (!errwarnonly(E_SPECIALFILE, info->f_name))
382 xstats.s_isspecial++;
383 errmsgno(EX_BAD,
384 "'%s' is not a file. Not created.\n",
385 info->f_name);
386 (void) errabort(E_SPECIALFILE, info->f_name, TRUE);
387 }
388 void_file(info);
389 return (FALSE);
390 }
391 /*
392 * If uncond is set and neither keep_old nor refresh_old is set,
393 * then newer() doesn't call getinfo(&cinfo).
394 * As newer() calls getinfo(&cinfo), it also checks for refresh_old.
395 */
396 if (!uncond_rename) {
397 /*
398 * -uncond-rename was not specified, so check whether newer.
399 */
400 if (newer(info, &cinfo) && !(xdir && is_dir(info))) {
401 void_file(info);
402 return (FALSE);
403 }
404 if (is_symlink(info) && same_symlink(info)) {
405 void_file(info);
406 return (FALSE);
407 }
408 }
409 /*
410 * Name substitution and interactive name changing need to happen before
411 * we check whether the file is newer than an existing file of the same
412 * name in the filesystem.
413 */
414 if (do_subst && subst(info)) {
415 if (info->f_name[0] == '\0') {
416 /*
417 * Changed to empty name: skip...
418 */
419 if (verbose)
420 fgtprintf(vpr,
421 "'%s' substitutes to null string, skipping ...\n",
422 name);
423 void_file(info);
424 return (FALSE);
425 }
426 /*
427 * Changed name to a probably existing file,
428 * check whether file in archive is newer.
429 */
430 if (newer(info, &cinfo) && !(xdir && is_dir(info))) {
431 void_file(info);
432 return (FALSE);
433 }
434 if (is_symlink(info) && same_symlink(info)) {
435 void_file(info);
436 return (FALSE);
437 }
438 }
439 if (interactive && !ia_change(ptb, info)) {
440 if (!nflag)
441 fgtprintf(vpr, "Skipping ...\n");
442 void_file(info);
443 return (FALSE);
444 }
445 /*
446 * If uncond is set and neither keep_old nor refresh_old is set,
447 * then newer() doesn't call getinfo(&cinfo).
448 * As newer() calls getinfo(&cinfo), it also checks for refresh_old.
449 */
450 if (uncond_rename) {
451 /*
452 * -uncond-rename was specified
453 * If the file was not renamed we now need to check whether
454 * the file in the archive is newer than the file with the
455 * new name on disk.
456 */
457 if (newer(info, &cinfo) && !(xdir && is_dir(info))) {
458 void_file(info);
459 return (FALSE);
460 }
461 if (is_symlink(info) && same_symlink(info)) {
462 void_file(info);
463 return (FALSE);
464 }
465 }
466 if (!(interactive || allow_dotdot) && has_dotdot(info->f_name)) {
467 if (!errhidden(E_SECURITY, info->f_name)) {
468 if (!errwarnonly(E_SECURITY, info->f_name))
469 xstats.s_security++;
470 errmsgno(EX_BAD,
471 "'%s' contains '..', skipping ...\n", info->f_name);
472 (void) errabort(E_SECURITY, info->f_name, TRUE);
473 }
474 void_file(info);
475 return (FALSE);
476 }
477 if (secure_links && (is_link(info) || is_symlink(info)) &&
478 (info->f_lname[0] == '/' || has_dotdot(info->f_lname))) {
479 if (info->f_lname[0] != '/') {
480 /*
481 * Absolute paths are always a problem, but symlinks
482 * should be allowed as long as they do not point
483 * outside the current tree.
484 */
485 if (inside_tree(info))
486 goto link_ok;
487 }
488 if (!errhidden(E_LSECURITY, info->f_lname)) {
489 if (!errwarnonly(E_LSECURITY, info->f_lname))
490 xstats.s_lsecurity++;
491 errmsgno(EX_BAD,
492 "'%s' potentially insecure link, skipping ...\n", info->f_name);
493 (void) errabort(E_LSECURITY, info->f_lname, TRUE);
494 }
495 void_file(info);
496 return (FALSE);
497 }
498 link_ok:
499 vprint(info);
500 if (dorestore) {
501 /*
502 * Check whether the target file exists and has a
503 * different type or is a dev node with different
504 * major/minor numbers. In this case, we need to
505 * remove the file. This happend when the original
506 * file has been removed and a new (different) file
507 * with the same name did get the same inode number.
508 */
509 imp = sym_typecheck(info, &cinfo, imp);
510
511 } else if (remove_first && !dometa) {
512 /*
513 * With keep_old we do not come here.
514 *
515 * Even if the archive and the current node are both
516 * directories call remove_file() because the new dir
517 * may get our ownership this way if we are not root.
518 *
519 * In order to avoid annoying messages, call remove_file()
520 * only if the file exists.
521 */
522 if (name_exists(info->f_name))
523 (void) remove_file(info->f_name, TRUE);
524 }
525 if (is_dir(info)) {
526 #ifdef MKD_DEBUG
527 { extern char *mkdwhy; mkdwhy = "extract"; }
528 #endif
529 if (!make_adir(info)) {
530 void_file(info);
531 return (FALSE);
532 }
533 void_file(info);
534 } else if (is_link(info)) {
535 if (!make_link(info)) {
536 void_file(info);
537 return (FALSE);
538 }
539 void_file(info);
540 } else if (is_symlink(info)) {
541 if (dorestore && imp) {
542 /*
543 * Do not create a new link if the old one is the same.
544 */
545 if (cinfo.f_rxftype != XT_NONE && (cinfo.f_flags & F_SAME))
546 goto set_modes;
547 }
548 if (!make_symlink(info)) {
549 void_file(info);
550 return (FALSE);
551 }
552 void_file(info);
553 } else if (is_special(info)) {
554 if (dorestore && imp) {
555 /*
556 * Do not create a new node if the old one is the same.
557 */
558 if (cinfo.f_rxftype != XT_NONE && (cinfo.f_flags & F_SAME))
559 goto set_modes;
560 }
561 if (is_door(info)) {
562 if (!nowarn) {
563 errmsgno(EX_BAD,
564 "WARNING: Extracting door '%s' as plain file.\n",
565 info->f_name);
566 }
567 if (!get_file(info))
568 return (FALSE);
569 } else if (is_fifo(info)) {
570 if (!make_fifo(info)) {
571 void_file(info);
572 return (FALSE);
573 }
574 void_file(info);
575 } else {
576 if (!make_special(info)) {
577 void_file(info);
578 return (FALSE);
579 }
580 void_file(info);
581 }
582 } else if (is_meta(info)) {
583 FINFO finfo;
584
585 /*
586 * Make sure not to overwrite existing files.
587 */
588 if (xmeta && !_getinfo(info->f_name, &finfo)) {
589 if (!get_file(info))
590 return (FALSE);
591 } else {
592 void_file(info);
593 }
594 } else if (!get_file(info)) {
595 return (FALSE);
596 }
597
598 #ifdef COPY_LINKS_DELAYED
599 if ((copyhardlinks && is_link(info)) ||
600 (copysymlinks && is_symlink(info)))
601 return (TRUE+didmatch);
602 #endif
603 set_modes:
604 if (!to_stdout)
605 setmodes(info);
606 #ifdef TEST_DEBUG
607 if (info->f_mode == 0700)
608 error("-->setmode(%s, %llo)\n", info->f_name, (Ullong)info->f_mode);
609 #endif
610 if (dorestore)
611 sym_addstat(info, imp);
612 return (TRUE+didmatch);
613 }
614
615 /*
616 * Return TRUE if the file on disk is newer than the file on the archive.
617 */
618 EXPORT BOOL
newer(info,cinfo)619 newer(info, cinfo)
620 FINFO *info; /* The FINFO for the file in the archive */
621 FINFO *cinfo; /* The FINFO for the file in the file system */
622 {
623 BOOL havenano;
624
625 if (uncond && !keep_old && !refresh_old)
626 return (FALSE);
627 if (!_getinfo(info->f_name, cinfo)) {
628 if (refresh_old) {
629 errmsgno(EX_BAD, "file '%s' does not exists.\n", info->f_name);
630 return (TRUE);
631 }
632 return (FALSE);
633 }
634 if (keep_old) {
635 if (!nowarn)
636 errmsgno(EX_BAD, "file '%s' exists.\n", info->f_name);
637 return (TRUE);
638 }
639 if (uncond)
640 return (FALSE);
641
642 if (xdot) {
643 if (info->f_name[0] == '.' &&
644 (info->f_name[1] == '\0' ||
645 (info->f_name[1] == '/' &&
646 info->f_name[2] == '\0'))) {
647
648 return (FALSE);
649 }
650 }
651
652 /*
653 * Honor nsecs if part of the archive.
654 */
655 havenano = (info->f_xflags & XF_MTIME) && (cinfo->f_flags & F_NSECS);
656 if ((cinfo->f_mtime > info->f_mtime) ||
657 (!havenano && cinfo->f_mtime == info->f_mtime)) {
658
659 isnewer:
660 if (xdir && is_dir(info)) /* Be silent, we handle it later */
661 return (TRUE);
662 if (!nowarn)
663 errmsgno(EX_BAD, "current '%s' newer.\n", info->f_name);
664 return (TRUE);
665 } else if ((cinfo->f_mtime == info->f_mtime) && havenano) {
666 /*
667 * If we have nanoseconds != 0, this cannot be a DOS file and
668 * for this reason, the f_mtime resolution is one second.
669 * An archive with nanosecond resolution and a filesystem with
670 * microsecond resolution could result in a file in the archive
671 * that is always newer than the file in the filesystem because
672 * the timestamp in the filesystem was rounded down. If the
673 * nanoseconds in the local file are greater than in the
674 * archive, this is the easy case.
675 */
676 if (cinfo->f_mnsec >= info->f_mnsec)
677 goto isnewer;
678 /*
679 * If the local filesystem resolution is only microseconds and
680 * the resolution in the archive is nanoseconds, we need to
681 * check based on microseconds to prevent extracting the
682 * file from the archive again and again.
683 * This is the UFS variant.
684 */
685 if ((cinfo->f_mnsec % 1000 == 0) &&
686 ((cinfo->f_mnsec / 1000) >= (info->f_mnsec / 1000)))
687 goto isnewer;
688
689 /*
690 * This is the NTFS (Win-DOS) variant that is based on
691 * 1/10 microseconds since 1601.
692 */
693 if ((cinfo->f_mnsec % 100 == 0) &&
694 ((cinfo->f_mnsec / 100) >= (info->f_mnsec / 100)))
695 goto isnewer;
696 } else if ((cinfo->f_mtime % 2) == 0 && (cinfo->f_mtime + 1) == info->f_mtime) {
697 /*
698 * The DOS FAT filestem does only support a time granularity
699 * of 2 seconds. So we need to be a bit more generous.
700 * XXX We should be able to test the filesytem type.
701 */
702 goto isnewer;
703 }
704 return (FALSE);
705 }
706
707 EXPORT BOOL
same_symlink(info)708 same_symlink(info)
709 FINFO *info;
710 {
711 FINFO finfo;
712 char lname[PATH_MAX+1]; /* This limit cannot be overruled */
713 TCB tb;
714
715 finfo.f_lname = lname;
716 finfo.f_lnamelen = 0;
717
718 if (uncond || !_getinfo(info->f_name, &finfo))
719 return (FALSE);
720
721 /*
722 * Bei symlinks gehen nicht: lchmod lchtime & teilweise lchown
723 */
724 #ifdef S_IFLNK
725 if (!is_symlink(&finfo)) /* File on disk */
726 return (FALSE);
727
728 fillbytes(&tb, sizeof (TCB), '\0');
729 info_to_tcb(&finfo, &tb); /* XXX ist das noch n�tig ??? */
730 /* z.Zt. wegen linkflag/uname/gname */
731
732 if (read_symlink(info->f_name, info->f_name, &finfo, &tb)) {
733 if (streql(info->f_lname, finfo.f_lname)) {
734 if (!nowarn)
735 errmsgno(EX_BAD, "current '%s' is same symlink.\n",
736 info->f_name);
737 return (TRUE);
738 }
739 }
740 #ifdef XXX
741 /*
742 * XXX nsec beachten wenn im Archiv!
743 */
744 if (finfo.f_mtime >= info->f_mtime) {
745 if (!nowarn)
746 errmsgno(EX_BAD, "current '%s' newer.\n", info->f_name);
747 return (TRUE);
748 }
749 #endif /* XXX */
750
751 #endif
752 return (FALSE);
753 }
754
755 EXPORT BOOL
same_special(info)756 same_special(info)
757 FINFO *info;
758 {
759 FINFO finfo;
760
761 if (uncond || !_getinfo(info->f_name, &finfo))
762 return (FALSE);
763
764 if (info->f_xftype != finfo.f_xftype)
765 return (FALSE);
766
767 if (is_bdev(info) || is_cdev(info)) {
768 if (info->f_rdevmaj != finfo.f_rdevmaj)
769 return (FALSE);
770 if (info->f_rdevmin != finfo.f_rdevmin)
771 return (FALSE);
772 }
773 return (TRUE);
774 }
775
776 /*
777 * Create intermediate directories.
778 * If the user is not root and the umask is degenerated or read-only,
779 * we add 0700 to the granted permissions. For this reason, we may need
780 * to correct the permissins of intermediate directories later from the
781 * directory stack.
782 */
783 LOCAL BOOL
_create_dirs(name)784 _create_dirs(name)
785 register char *name;
786 {
787 mode_t mode;
788
789 mode = mode_mask; /* used to be 0777 */
790 if (my_uid != ROOT_UID)
791 mode |= S_IRWXU; /* Make sure we will be able write */
792
793 if (lmkdir(name, mode) < 0) {
794 if (create_dirs(name) &&
795 lmkdir(name, mode) >= 0) {
796 _dir_setownwer(name);
797 if (mode != mode_mask)
798 sdirmode(name, mode_mask); /* Push umask */
799 return (TRUE);
800 }
801 return (FALSE);
802 }
803 _dir_setownwer(name);
804 if (mode != mode_mask)
805 sdirmode(name, mode_mask); /* Push umask on dirstack */
806 return (TRUE);
807 }
808
809 /*
810 * Set the owner/group of intermedia directories.
811 * Be very careful not to overwrite sgid directory semantics.
812 */
813 LOCAL void
_dir_setownwer(name)814 _dir_setownwer(name)
815 char *name;
816 {
817 FINFO dinfo;
818
819 if (my_uid != ROOT_UID)
820 return;
821
822 if (dir_uid == _BAD_UID && dir_gid == _BAD_GID)
823 return;
824
825 if (!_getinfo(name, &dinfo) || !is_dir(&dinfo))
826 return;
827
828 if (dir_uid != _BAD_UID)
829 dinfo.f_uid = dir_uid;
830 if (dir_gid != _BAD_GID)
831 dinfo.f_gid = dir_gid;
832
833 lchownat(name, dinfo.f_uid, dinfo.f_gid, 0);
834 }
835
836 EXPORT BOOL
create_dirs(name)837 create_dirs(name)
838 register char *name;
839 {
840 register char *np;
841 register char *dp;
842 int err;
843 int olderr = 0;
844
845 if (noxdir) {
846 errmsgno(EX_BAD, "Directories not created.\n");
847 return (FALSE);
848 }
849 np = dp = name;
850 do {
851 if (*np == '/')
852 dp = np;
853 } while (*np++);
854 if (dp == name) {
855 /*
856 * Do not create the very last directory
857 */
858 return (TRUE);
859 }
860 *dp = '\0';
861 if (laccess(name, F_OK) < 0) {
862 if (_create_dirs(name)) {
863 *dp = '/';
864 return (TRUE);
865 }
866 err = geterrno();
867 if ((err == EACCES || is_eexist(err) || is_eloop(err))) {
868 olderr = err;
869 goto exists;
870 }
871 *dp = '/';
872 return (FALSE);
873 } else {
874 FINFO dinfo;
875
876 exists:
877 if (_getinfo(name, &dinfo)) {
878 if (is_dir(&dinfo)) {
879 *dp = '/';
880 return (TRUE);
881 }
882
883 if (remove_file(name, FALSE)) {
884 if (_create_dirs(name)) {
885 *dp = '/';
886 return (TRUE);
887 }
888 *dp = '/';
889 return (FALSE);
890 } else {
891 *dp = '/';
892 return (FALSE);
893 }
894 }
895 *dp = '/';
896 if (olderr == EACCES)
897 seterrno(olderr);
898 return (FALSE);
899 }
900 }
901
902 #ifdef MKD_DEBUG
903 EXPORT char *mkdwhy;
904 #endif
905
906 EXPORT BOOL
make_adir(info)907 make_adir(info)
908 FINFO *info;
909 {
910 if (is_link(info))
911 return (make_link(info));
912 else
913 return (make_dir(info));
914 }
915
916 /*
917 * This function is used only to create directories found on the archive.
918 * Intermediate directories are created using create_dirs().
919 */
920 LOCAL BOOL
make_dir(info)921 make_dir(info)
922 FINFO *info;
923 {
924 FINFO dinfo;
925 mode_t mode;
926 int err;
927
928 if (dometa)
929 return (TRUE);
930
931 mode = osmode(info->f_mode); /* Convert TAR modes to OS modes */
932 mode &= mode_mask; /* Apply current umask */
933 if (my_uid != ROOT_UID)
934 mode |= S_IRWXU; /* Make sure we will be able write */
935
936 if (_getinfo(info->f_name, &dinfo) && is_dir(&dinfo))
937 return (TRUE);
938
939 if (create_dirs(info->f_name)) {
940 if (_getinfo(info->f_name, &dinfo) && is_dir(&dinfo))
941 return (TRUE);
942 if (lmkdir(info->f_name, mode) >= 0)
943 return (TRUE);
944 err = geterrno();
945 if ((err == EACCES || is_eexist(err) || is_eloop(err)) &&
946 remove_file(info->f_name, FALSE)) {
947 if (lmkdir(info->f_name, mode) >= 0)
948 return (TRUE);
949 }
950 }
951 #ifdef MKD_DEBUG
952 errmsgno(EX_BAD, "make_dir(%s) called from '%s'\n", info->f_name, mkdwhy);
953 #endif
954 if (!errhidden(E_OPEN, info->f_name)) {
955 if (!errwarnonly(E_OPEN, info->f_name))
956 xstats.s_openerrs++;
957 errmsg("Cannot make dir '%s'.\n", info->f_name);
958 (void) errabort(E_OPEN, info->f_name, TRUE);
959 }
960 return (FALSE);
961 }
962
963 LOCAL BOOL
make_link(info)964 make_link(info)
965 FINFO *info;
966 {
967 int err;
968 #ifdef USE_FFLAGS
969 FINFO linfo;
970 Ulong oldflags = 0L;
971 #endif
972 pathstore_t path;
973 char xname[PATH_MAX+1];
974 char *name = info->f_name;
975 BOOL ret = TRUE;
976
977 /*
978 * void_file() is needed for CPIO and done by our callers.
979 */
980
981 if (dometa)
982 return (TRUE);
983
984 path.ps_path = xname;
985
986 #ifdef HAVE_LINK_NOFOLLOW
987 /*
988 * This OS allows hard links to symlinks and does not follow symlinks
989 * when making hard links to symlinks. We may not follow symlinks while
990 * we check if source & sestination are the same.
991 */
992 if (same_file(info, IS_LINK, FALSE)) {
993 #else
994 /*
995 * This OS either does not allow hard links to symlinks or follows
996 * symlinks if possible before making a hard link to a symlink.
997 * We need not follow symlinks while we check if source & sestination
998 * are the same.
999 */
1000 if (same_file(info, IS_LINK, TRUE)) {
1001 #endif
1002 /*
1003 * As it seems that from/to for the hard link are already
1004 * identical files, return TRUE to indicate success with
1005 * creating the hard link.
1006 */
1007 return (TRUE);
1008 }
1009
1010 if (copyhardlinks)
1011 return (make_copy(info, FALSE, 0));
1012 else if (hardlinks)
1013 return (emul_link(info));
1014
1015 #ifdef HAVE_LINK
1016 xname[0] = '\0';
1017 if (do_install && name_exists(name)) {
1018 if (!file_tmpname(info, &path)) {
1019 ret = FALSE;
1020 goto out;
1021 }
1022 name = path.ps_path;
1023 }
1024 if (llink(info->f_lname, name) >= 0)
1025 goto ok;
1026 err = geterrno();
1027 if (info->f_rsize > 0 && is_enoent(err)) {
1028 ret = get_file(info);
1029 goto out;
1030 }
1031 #ifdef USE_FFLAGS
1032 /*
1033 * SF_IMMUTABLE might be set on the source-file. Clear the flags
1034 * and try again.
1035 */
1036 if (_getinfo(info->f_lname, &linfo) && (linfo.f_xflags & XF_FFLAGS)) {
1037 oldflags = linfo.f_fflags;
1038 linfo.f_fflags = 0L;
1039 set_fflags(&linfo);
1040 if (llink(info->f_lname, name) >= 0)
1041 goto restore_flags;
1042 err = geterrno();
1043 }
1044 #endif
1045 if (create_dirs(info->f_name)) {
1046 if (llink(info->f_lname, name) >= 0)
1047 goto restore_flags;
1048 err = geterrno();
1049 }
1050 if ((err == EACCES || is_eexist(err) || is_eloop(err)) &&
1051 remove_file(name, FALSE)) {
1052 if (llink(info->f_lname, name) >= 0)
1053 goto restore_flags;
1054 }
1055 if (!errhidden(E_OPEN, info->f_name)) {
1056 if (!errwarnonly(E_OPEN, info->f_name))
1057 xstats.s_openerrs++;
1058 errmsg("Cannot link '%s' to '%s'.\n",
1059 info->f_name, info->f_lname);
1060 (void) errabort(E_OPEN, info->f_name, TRUE);
1061 }
1062 if (do_install)
1063 remove_tmpname(path.ps_path);
1064 ret = FALSE;
1065 goto out;
1066
1067 restore_flags:
1068 #ifdef USE_FFLAGS
1069 if (oldflags != 0L) {
1070 linfo.f_fflags = oldflags;
1071 set_fflags(&linfo);
1072 }
1073 #endif
1074 ok:
1075 if (do_install)
1076 ret = install_rename(info, path.ps_path);
1077 out:
1078 if (path.ps_path != xname)
1079 free_pspace(&path);
1080 return (ret);
1081
1082 #else /* HAVE_LINK */
1083 if (!errhidden(E_SPECIALFILE, info->f_name)) {
1084 if (!errwarnonly(E_SPECIALFILE, info->f_name))
1085 xstats.s_isspecial++;
1086 errmsgno(EX_BAD,
1087 "Not supported. Cannot link '%s' to '%s'.\n",
1088 info->f_name, info->f_lname);
1089 (void) errabort(E_SPECIALFILE, info->f_name, TRUE);
1090 }
1091 return (FALSE);
1092 #endif /* HAVE_LINK */
1093 }
1094
1095 LOCAL BOOL
make_symlink(info)1096 make_symlink(info)
1097 FINFO *info;
1098 {
1099 int err;
1100 pathstore_t path;
1101 char xname[PATH_MAX+1];
1102 char *name = info->f_name;
1103 BOOL ret = TRUE;
1104
1105 if (dometa)
1106 return (TRUE);
1107
1108 path.ps_path = xname;
1109
1110 if (copysymlinks)
1111 return (make_copy(info, TRUE, 0));
1112 else if (symlinks)
1113 return (emul_symlink(info));
1114
1115 #ifdef S_IFLNK
1116 xname[0] = '\0';
1117 if (do_install && name_exists(name)) {
1118 if (!file_tmpname(info, &path)) {
1119 ret = FALSE;
1120 goto out;
1121 }
1122 name = path.ps_path;
1123 }
1124 if (sxsymlink(name, info) >= 0)
1125 goto ok;
1126 err = geterrno();
1127 if (create_dirs(info->f_name)) {
1128 if (sxsymlink(name, info) >= 0)
1129 goto ok;
1130 err = geterrno();
1131 }
1132 /*
1133 * XXX at least with same symlinks we should return success
1134 */
1135 if ((err == EACCES || is_eexist(err) || is_eloop(err)) &&
1136 remove_file(name, FALSE)) {
1137 if (sxsymlink(name, info) >= 0)
1138 goto ok;
1139 }
1140 if (!errhidden(E_OPEN, info->f_name)) {
1141 if (!errwarnonly(E_OPEN, info->f_name))
1142 xstats.s_openerrs++;
1143 errmsg("Cannot create symbolic link '%s' to '%s'.\n",
1144 info->f_name, info->f_lname);
1145 (void) errabort(E_OPEN, info->f_name, TRUE);
1146 }
1147 if (do_install)
1148 remove_tmpname(path.ps_path);
1149 ret = FALSE;
1150 goto out;
1151 ok:
1152 if (do_install)
1153 ret = install_rename(info, path.ps_path);
1154 out:
1155 if (path.ps_path != xname)
1156 free_pspace(&path);
1157 return (ret);
1158 #else /* S_IFLNK */
1159 if (!errhidden(E_SPECIALFILE, info->f_name)) {
1160 if (!errwarnonly(E_SPECIALFILE, info->f_name))
1161 xstats.s_isspecial++;
1162 errmsgno(EX_BAD,
1163 "Not supported. Cannot create symbolic link '%s' to '%s'.\n",
1164 info->f_name, info->f_lname);
1165 (void) errabort(E_SPECIALFILE, info->f_name, TRUE);
1166 }
1167 return (FALSE);
1168 #endif /* S_IFLNK */
1169 }
1170
1171 LOCAL BOOL
emul_symlink(info)1172 emul_symlink(info)
1173 FINFO *info;
1174 {
1175 errmsgno(EX_BAD, "Option -symlinks not yet implemented.\n");
1176 errmsgno(EX_BAD, "Cannot create symbolic link '%s' to '%s'.\n",
1177 info->f_name, info->f_lname);
1178 return (FALSE);
1179 }
1180
1181 LOCAL BOOL
emul_link(info)1182 emul_link(info)
1183 FINFO *info;
1184 {
1185 errmsgno(EX_BAD, "Option -hardlinks not yet implemented.\n");
1186 errmsgno(EX_BAD, "Cannot link '%s' to '%s'.\n", info->f_name, info->f_lname);
1187 #ifdef HAVE_LINK
1188 return (FALSE);
1189 #else
1190 return (FALSE);
1191 #endif /* S_IFLNK */
1192 }
1193
1194 LOCAL BOOL
same_file(info,what,do_follow)1195 same_file(info, what, do_follow)
1196 FINFO *info;
1197 int what;
1198 BOOL do_follow;
1199 {
1200 FINFO finfo;
1201 FINFO linfo;
1202 BOOL ofollow = follow;
1203 BOOL ret = FALSE;
1204
1205 follow = do_follow;
1206 if (_getinfo(info->f_name, &finfo) && _getinfo(info->f_lname, &linfo)) {
1207 if (finfo.f_dev == linfo.f_dev && finfo.f_ino == linfo.f_ino) {
1208 if (what == IS_COPY) {
1209 if (!errhidden(E_SAMEFILE, info->f_lname)) {
1210 if (!errwarnonly(E_SAMEFILE, info->f_lname))
1211 xstats.s_samefile++;
1212 errmsgno(EX_BAD,
1213 "copy_file: '%s' from/to identical, skipping ...\n",
1214 info->f_name);
1215 (void) errabort(E_SAMEFILE,
1216 info->f_lname, TRUE);
1217 }
1218 } else {
1219 /*
1220 * If in restore mode, we do not like to see
1221 * this informational message. The hard link
1222 * is already present and this is all we need.
1223 * If -force-remove has been specified (default
1224 * for "tar") we do not like to see this message
1225 * either.
1226 */
1227 if (!nowarn && !dorestore && !force_remove) {
1228 errmsgno(EX_BAD,
1229 "Notice: link_file: '%s' from/to identical, skipping ...\n",
1230 info->f_name);
1231 }
1232 }
1233 ret = TRUE;
1234 }
1235 }
1236 follow = ofollow;
1237 return (ret);
1238 }
1239
1240 LOCAL BOOL
make_copy(info,do_symlink,eflags)1241 make_copy(info, do_symlink, eflags)
1242 FINFO *info;
1243 BOOL do_symlink;
1244 int eflags;
1245 {
1246 #ifdef COPY_LINKS_DELAYED
1247 if (!lowmem) {
1248 add_copy(info, do_symlink);
1249 return (TRUE);
1250 } else {
1251 return (_make_copy(info, do_symlink, eflags));
1252 }
1253 #else
1254 return (_make_copy(info, do_symlink, eflags));
1255 #endif
1256 }
1257
1258 LOCAL BOOL
_make_copy(info,do_symlink,eflags)1259 _make_copy(info, do_symlink, eflags)
1260 FINFO *info;
1261 BOOL do_symlink;
1262 int eflags;
1263 {
1264 int ret;
1265 int err;
1266
1267 #ifdef COPY_LINKS_DELAYED
1268 if (!lowmem && copydlinks) {
1269 if (_make_dcopy(info, do_symlink, &ret, eflags))
1270 return (ret);
1271 }
1272 #endif
1273 /*
1274 * As we can only copy plain files, we need to follow symlinks when
1275 * we check if source & destination are the same file.
1276 */
1277 if (same_file(info, IS_COPY, TRUE)) {
1278 return (FALSE);
1279 }
1280
1281 if ((ret = copy_file(info->f_lname, info->f_name, do_symlink, eflags)) >= 0)
1282 return (TRUE);
1283 err = geterrno();
1284 if (ret != -2 && create_dirs(info->f_name)) {
1285 if (copy_file(info->f_lname, info->f_name, do_symlink, eflags) >= 0)
1286 return (TRUE);
1287 err = geterrno();
1288 }
1289 if ((err == EACCES || is_eexist(err) || err == EISDIR || is_eloop(err)) &&
1290 remove_file(info->f_name, FALSE)) {
1291 if (copy_file(info->f_lname, info->f_name, do_symlink, eflags) >= 0)
1292 return (TRUE);
1293 }
1294 if (!errhidden(E_OPEN, info->f_name) &&
1295 ((eflags & HIDE_ENOENT) == 0 || geterrno() != ENOENT)) {
1296 if (!errwarnonly(E_OPEN, info->f_name))
1297 xstats.s_openerrs++;
1298 errmsg("Cannot create link copy '%s' from '%s'.\n",
1299 info->f_name, info->f_lname);
1300 (void) errabort(E_OPEN, info->f_name, TRUE);
1301 }
1302 return (FALSE);
1303 }
1304
1305 #ifdef COPY_LINKS_DELAYED
1306 LOCAL void
add_copy(info,do_symlink)1307 add_copy(info, do_symlink)
1308 FINFO *info;
1309 BOOL do_symlink;
1310 {
1311 MCQ *mcqp = ___malloc(sizeof (MCQ), "make_copy()");
1312 char *f_namep = ___savestr(info->f_name);
1313 char *f_lnamep = ___savestr(info->f_lname);
1314
1315 mcqp->next = NULL;
1316 mcqp->do_symlink = do_symlink;
1317 mcqp->info = *info;
1318 mcqp->info.f_name = f_namep;
1319 mcqp->info.f_lname = f_lnamep;
1320
1321 if (mcq_last) {
1322 mcq_last->next = mcqp;
1323 mcq_last = mcqp;
1324 } else {
1325 mcq_1st = mcqp;
1326 mcq_last = mcqp;
1327 }
1328 }
1329
1330 LOCAL void
make_copies()1331 make_copies()
1332 {
1333 int eflags = HIDE_ENOENT;
1334
1335 do {
1336 MCQ *mcqp = mcq_1st;
1337 MCQ *mcqp_prev = NULL;
1338 int mcq_removed = 0;
1339
1340 while (mcqp) {
1341 MCQ *mcqp_save = mcqp;
1342 BOOL ret = _make_copy(&mcqp->info,
1343 mcqp->do_symlink,
1344 eflags);
1345
1346 if (ret) {
1347 if (!to_stdout)
1348 setmodes(&mcqp->info);
1349 if (dorestore)
1350 sym_addstat(&mcqp->info, NULL);
1351 }
1352 mcqp = mcqp->next;
1353
1354 if (ret || (eflags & HIDE_ENOENT) == 0 || geterrno() != ENOENT) {
1355
1356 if (mcqp_prev)
1357 mcqp_prev->next = mcqp;
1358 if (mcq_1st == mcqp_save)
1359 mcq_1st = mcqp;
1360 if (mcq_last == mcqp_save)
1361 mcq_last = mcqp;
1362
1363 free(mcqp_save->info.f_name);
1364 free(mcqp_save->info.f_lname);
1365 free(mcqp_save);
1366
1367 mcq_removed++;
1368
1369 } else {
1370 mcqp_prev = mcqp_save;
1371 }
1372 }
1373 if (!mcq_removed)
1374 eflags = 0; /* queue has not decreased - last attempt */
1375
1376 } while (mcq_1st);
1377 }
1378
1379 LOCAL BOOL
_make_dcopy(info,do_symlink,retp,eflags)1380 _make_dcopy(info, do_symlink, retp, eflags)
1381 FINFO *info;
1382 BOOL do_symlink;
1383 int *retp;
1384 int eflags;
1385 {
1386 char nbuf[PATH_MAX+1];
1387 char *nbufp = nbuf;
1388 char *dir = info->f_lname;
1389 DIR *dirp;
1390 char *dp;
1391 size_t nents;
1392 int ret = TRUE;
1393 FINFO ninfo;
1394
1395 if (do_symlink && info->f_lname[0] != '/') {
1396
1397 char *p = strrchr(info->f_name, '/');
1398 size_t len;
1399
1400 if (p) {
1401 size_t llen;
1402
1403 len = p - info->f_name + 1;
1404 if ((len + (llen = strlen(info->f_lname))) > PATH_MAX) {
1405 nbufp = __fjmalloc(stderr, len+llen,
1406 "link dir name", JM_RETURN);
1407 }
1408 if (nbufp == NULL) {
1409 if (!errhidden(E_NAMETOOLONG, info->f_lname)) {
1410 if (!errwarnonly(E_NAMETOOLONG, info->f_lname))
1411 xstats.s_toolong++;
1412 errmsgno(EX_BAD,
1413 "Name too long. Cannot copy from '%s'.\n",
1414 info->f_lname);
1415 (void) errabort(E_NAMETOOLONG,
1416 info->f_lname, TRUE);
1417 }
1418 if (retp)
1419 *retp = FALSE;
1420 return (TRUE);
1421 }
1422 strncpy(nbufp, info->f_name, len);
1423 strcpy(&nbufp[len], info->f_lname);
1424 dir = nbufp;
1425 }
1426 }
1427
1428 dirp = lopendir(dir);
1429 if (dirp == NULL)
1430 return (FALSE);
1431 if ((dp = dfetchdir(dirp, dir, &nents, NULL, NULL)) == NULL) {
1432 closedir(dirp);
1433 return (FALSE);
1434 }
1435 closedir(dirp);
1436
1437 if (!_getinfo(info->f_name, &ninfo)) {
1438 _getinfo(dir, &ninfo);
1439 ninfo.f_name = info->f_name;
1440 make_dir(&ninfo);
1441 }
1442 if (nbufp != nbuf)
1443 free(nbufp);
1444
1445 while (nents > 0) {
1446 char *name;
1447 size_t nlen;
1448
1449 name = &dp[1];
1450 nlen = strlen(name);
1451
1452 ninfo.f_name = ___malloc(strlen(info->f_name) +
1453 1 + nlen + 1, "make_copy()");
1454
1455 strcpy(ninfo.f_name, info->f_name);
1456 if (ninfo.f_name[strlen(ninfo.f_name)-1] != '/')
1457 strcat(ninfo.f_name, "/");
1458 strcat(ninfo.f_name, name);
1459
1460 ninfo.f_lname = ___malloc(3 +
1461 strlen(info->f_lname) + 1 +
1462 nlen + 1, "make_copy()");
1463
1464 ninfo.f_lname[0] = '\0';
1465 if (do_symlink)
1466 strcpy(ninfo.f_lname, "../");
1467 strcat(ninfo.f_lname, info->f_lname);
1468 if (ninfo.f_lname[strlen(ninfo.f_lname)-1] != '/')
1469 strcat(ninfo.f_lname, "/");
1470 strcat(ninfo.f_lname, name);
1471
1472 if (!_make_copy(&ninfo, do_symlink, eflags))
1473 ret = FALSE;
1474
1475 free(ninfo.f_lname);
1476 free(ninfo.f_name);
1477
1478 nents--;
1479 dp += nlen +2;
1480 }
1481 if (retp)
1482 *retp = ret;
1483 return (TRUE);
1484 }
1485 #endif /* COPY_LINKS_DELAYED */
1486
1487 LOCAL int
copy_file(from,to,do_symlink,eflags)1488 copy_file(from, to, do_symlink, eflags)
1489 char *from;
1490 char *to;
1491 BOOL do_symlink;
1492 int eflags;
1493 {
1494 FINFO finfo;
1495 FILE *fin;
1496 FILE *fout;
1497 int cnt = -1;
1498 char buf[8192];
1499 char nbuf[PATH_MAX+1];
1500 char *nbufp = nbuf;
1501
1502 /*
1503 * When tar archives hard links, both names (from/to) are relative to
1504 * the current directory. With symlinks this does not work. Symlinks
1505 * are always evaluated relative to the directory they reside in.
1506 * For this reason, we cannot simply open the from/to files if we
1507 * like to emulate a symbolic link. To emulate the behavior of a
1508 * symbolic link, we concat the the directory part of the 'to' name
1509 * (which is the path that becomes the sombolic link) to the complete
1510 * 'from' name (which is the path the symbolic linkc pints to) in case
1511 * the 'from' name is a relative path name.
1512 */
1513 if (do_symlink && from[0] != '/') {
1514 char *p = strrchr(to, '/');
1515 size_t len;
1516
1517 if (p) {
1518 int llen;
1519
1520 len = p - to + 1;
1521
1522 if ((len + (llen = strlen(from))) > PATH_MAX) {
1523 nbufp = __fjmalloc(stderr, len+llen,
1524 "link name", JM_RETURN);
1525 }
1526 if (nbufp == NULL) {
1527 if (!errhidden(E_NAMETOOLONG, from)) {
1528 if (!errwarnonly(E_NAMETOOLONG, from))
1529 xstats.s_toolong++;
1530 errmsgno(EX_BAD,
1531 "Name too long. Cannot copy from '%s'.\n",
1532 from);
1533 (void) errabort(E_NAMETOOLONG, from,
1534 TRUE);
1535 }
1536 cnt = -2;
1537 goto out;
1538 }
1539 strncpy(nbuf, to, len);
1540 strcpy(&nbuf[len], from);
1541 from = nbuf;
1542 }
1543 }
1544 if (!_getinfo(from, &finfo)) {
1545
1546 if (!errhidden(E_STAT, from) &&
1547 ((eflags & HIDE_ENOENT) == 0 || geterrno() != ENOENT)) {
1548 if (!errwarnonly(E_STAT, from))
1549 xstats.s_staterrs++;
1550 errmsg("Cannot stat '%s'.\n", from);
1551 (void) errabort(E_STAT, from, TRUE);
1552 }
1553 cnt = -2;
1554 goto out;
1555 }
1556 if (!is_file(&finfo)) {
1557 errmsgno(EX_BAD, "Not a file. Cannot copy from '%s'.\n", from);
1558 seterrno(EINVAL);
1559 cnt = -2;
1560 goto out;
1561 }
1562
1563 rretry:
1564 if ((fin = lfilemopen(from, "rub", S_IREAD|S_IWRITE)) == 0) {
1565 if (geterrno() == EINTR)
1566 goto rretry;
1567 errmsg("Cannot open '%s'.\n", from);
1568 } else {
1569 wretry:
1570 if ((fout = lfilemopen(to, "wtcub", S_IREAD|S_IWRITE)) == 0) {
1571 if (geterrno() == EINTR)
1572 goto wretry;
1573 #ifdef __really__
1574 errmsg("Cannot create '%s'.\n", to);
1575 #endif
1576 cnt = -1;
1577 goto out;
1578 } else {
1579 while ((cnt = ffileread(fin, buf, sizeof (buf))) > 0)
1580 ffilewrite(fout, buf, cnt);
1581 fclose(fout);
1582 }
1583 fclose(fin);
1584 }
1585 out:
1586 if (nbufp != nbuf)
1587 free(nbufp);
1588 return (cnt);
1589 }
1590
1591 LOCAL BOOL
make_fifo(info)1592 make_fifo(info)
1593 FINFO *info;
1594 {
1595 mode_t mode;
1596 int err;
1597 pathstore_t path;
1598 char xname[PATH_MAX+1];
1599 char *name = info->f_name;
1600 BOOL ret = TRUE;
1601
1602 if (dometa)
1603 return (TRUE);
1604
1605 path.ps_path = xname;
1606
1607 #ifdef HAVE_MKFIFO
1608 xname[0] = '\0';
1609 if (do_install && name_exists(name)) {
1610 if (!file_tmpname(info, &path)) {
1611 ret = FALSE;
1612 goto out;
1613 }
1614 name = path.ps_path;
1615 }
1616 mode = osmode(info->f_mode);
1617 mode &= mode_mask;
1618 if (lmkfifo(name, mode) >= 0)
1619 goto ok;
1620 err = geterrno();
1621 if (create_dirs(info->f_name)) {
1622 if (lmkfifo(name, mode) >= 0)
1623 goto ok;
1624 err = geterrno();
1625 }
1626 if ((err == EACCES || is_eexist(err) || is_eloop(err)) &&
1627 remove_file(name, FALSE)) {
1628 if (lmkfifo(name, mode) >= 0)
1629 goto ok;
1630 }
1631 if (!errhidden(E_OPEN, info->f_name)) {
1632 if (!errwarnonly(E_OPEN, info->f_name))
1633 xstats.s_openerrs++;
1634 errmsg("Cannot make fifo '%s'.\n", info->f_name);
1635 (void) errabort(E_OPEN, info->f_name, TRUE);
1636 }
1637 if (do_install)
1638 remove_tmpname(path.ps_path);
1639 ret = FALSE;
1640 goto out;
1641 ok:
1642 if (do_install)
1643 ret = install_rename(info, path.ps_path);
1644 out:
1645 if (path.ps_path != xname)
1646 free_pspace(&path);
1647 return (ret);
1648 #else
1649 #ifdef HAVE_MKNOD
1650 return (make_special(info));
1651 #endif
1652 if (!errhidden(E_SPECIALFILE, info->f_name)) {
1653 if (!errwarnonly(E_SPECIALFILE, info->f_name))
1654 xstats.s_isspecial++;
1655 errmsgno(EX_BAD,
1656 "Not supported. Cannot make fifo '%s'.\n",
1657 info->f_name);
1658 (void) errabort(E_SPECIALFILE, info->f_name, TRUE);
1659 }
1660 return (FALSE);
1661 #endif
1662 }
1663
1664 LOCAL BOOL
make_special(info)1665 make_special(info)
1666 FINFO *info;
1667 {
1668 mode_t mode;
1669 dev_t dev;
1670 int err;
1671 pathstore_t path;
1672 char xname[PATH_MAX+1];
1673 char *name = info->f_name;
1674 BOOL ret = TRUE;
1675
1676 if (dometa)
1677 return (TRUE);
1678
1679 path.ps_path = xname;
1680
1681 #ifdef HAVE_MKNOD
1682 xname[0] = '\0';
1683 if (do_install && name_exists(name)) {
1684 if (!file_tmpname(info, &path)) {
1685 ret = FALSE;
1686 goto out;
1687 }
1688 name = path.ps_path;
1689 }
1690 mode = osmode(info->f_mode);
1691 mode &= mode_mask;
1692 mode |= info->f_type; /* Add file type bits */
1693 dev = info->f_rdev;
1694 if (lmknod(name, mode, dev) >= 0)
1695 goto ok;
1696 err = geterrno();
1697 if (create_dirs(info->f_name)) {
1698 if (lmknod(name, mode, dev) >= 0)
1699 goto ok;
1700 err = geterrno();
1701 }
1702 if ((err == EACCES || is_eexist(err) || is_eloop(err)) &&
1703 remove_file(name, FALSE)) {
1704 if (lmknod(name, mode, dev) >= 0)
1705 goto ok;
1706 }
1707 if (!errhidden(E_OPEN, info->f_name)) {
1708 if (!errwarnonly(E_OPEN, info->f_name))
1709 xstats.s_openerrs++;
1710 errmsg("Cannot make %s '%s'.\n",
1711 is_fifo(info)?"fifo":"special",
1712 info->f_name);
1713 (void) errabort(E_OPEN, info->f_name, TRUE);
1714 }
1715 if (do_install)
1716 remove_tmpname(path.ps_path);
1717 ret = FALSE;
1718 goto out;
1719 ok:
1720 if (do_install)
1721 ret = install_rename(info, path.ps_path);
1722 out:
1723 if (path.ps_path != xname)
1724 free_pspace(&path);
1725 return (ret);
1726 #else
1727 if (!errhidden(E_SPECIALFILE, info->f_name)) {
1728 if (!errwarnonly(E_SPECIALFILE, info->f_name))
1729 xstats.s_isspecial++;
1730 errmsgno(EX_BAD, "Not supported. Cannot make %s '%s'.\n",
1731 is_fifo(info)?"fifo":"special",
1732 info->f_name);
1733 (void) errabort(E_SPECIALFILE, info->f_name, TRUE);
1734 }
1735 return (FALSE);
1736 #endif
1737 }
1738
1739 /*
1740 * Create a temporary path name for the extraction in -install mode.
1741 */
1742 LOCAL BOOL
file_tmpname(info,path)1743 file_tmpname(info, path)
1744 FINFO *info;
1745 pathstore_t *path;
1746 {
1747 register char *xp;
1748 register char *np;
1749 register char *dp;
1750 size_t nlen;
1751
1752 np = info->f_name;
1753 nlen = info->f_namelen;
1754 if (nlen == 0) /* 0 in case name is in TCB */
1755 nlen = NAMSIZ + 1 + PFXSIZ; /* 256 chars fit into TCB */
1756 if (nlen >= (PATH_MAX-6)) {
1757 path->ps_path = NULL; /* initialize so we don't */
1758 path->ps_size = 0; /* need to call init_pspace() */
1759 path->ps_tail = 0;
1760 if (set_pspace(PS_STDERR, path, nlen+6) < 0)
1761 return (FALSE);
1762 }
1763 xp = path->ps_path;
1764 dp = xp;
1765 do {
1766 if ((*xp++ = *np) == '/')
1767 dp = xp;
1768 } while (*np++);
1769
1770 strcpy(dp, "XXXXXX");
1771 seterrno(0);
1772 lmktemp(path->ps_path);
1773 if (path->ps_path[0] == '\0') {
1774 errmsg("Cannot make temporary name for '%s'.\n",
1775 info->f_name);
1776 return (FALSE);
1777 }
1778 return (TRUE);
1779 }
1780
1781 LOCAL FILE *
file_open(info,name)1782 file_open(info, name)
1783 FINFO *info;
1784 char *name;
1785 {
1786 FILE *f;
1787
1788 while ((f = lfilemopen(name, "wctub",
1789 osmode(info->f_mode) & mode_mask)) == NULL &&
1790 geterrno() == EINTR)
1791 ;
1792 return (f);
1793 }
1794
1795 /*
1796 * Rename the temporary path to the official path name when in -install mode.
1797 */
1798 LOCAL BOOL
install_rename(info,xname)1799 install_rename(info, xname)
1800 FINFO *info;
1801 char *xname;
1802 {
1803 int err;
1804 BOOL oforce_remove = force_remove;
1805
1806 /*
1807 * If xname is empty, then we do not need to rename the file as
1808 * there was no temporary name.
1809 */
1810 if (xname[0] == '\0')
1811 return (TRUE);
1812
1813 if (lrename(xname, info->f_name) >= 0)
1814 return (TRUE);
1815 err = geterrno();
1816 /*
1817 * EISDIR is the error code if we try to rename a non-directory to the
1818 * name of an existing directory. In this case we silently remove this
1819 * directory if it is empty.
1820 */
1821 if (err == EISDIR)
1822 force_remove = TRUE;
1823 if ((err == EACCES || is_eexist(err) || err == EISDIR || is_eloop(err)) &&
1824 remove_file(info->f_name, FALSE)) {
1825 if (lrename(xname, info->f_name) >= 0) {
1826 force_remove = oforce_remove;
1827 return (TRUE);
1828 }
1829 }
1830 force_remove = oforce_remove;
1831 /*
1832 * Rename to the official name did not work, remove the temporary name
1833 */
1834 remove_tmpname(xname);
1835 return (FALSE);
1836 }
1837
1838 LOCAL BOOL
name_exists(name)1839 name_exists(name)
1840 char *name;
1841 {
1842 FINFO finfo;
1843
1844 if (!_lgetinfo(name, &finfo))
1845 return (FALSE);
1846
1847 return (TRUE);
1848 }
1849
1850 /*
1851 * remove_tmpname() is used to remove the temporary file used with -install
1852 * in case that the extraction did fail. For this reason make the remove
1853 * silent and unconditionally.
1854 */
1855 LOCAL void
remove_tmpname(name)1856 remove_tmpname(name)
1857 char *name;
1858 {
1859 BOOL oforce_remove = force_remove;
1860 BOOL oremove_recursive = remove_recursive;
1861
1862 /*
1863 * Rename to the official name did not work, remove the temporary name
1864 * in case that the temporary file still exists.
1865 */
1866 if (name[0] == '\0')
1867 return;
1868 if (!name_exists(name))
1869 return;
1870 /*
1871 * In order to avoid annoying messages, call remove_file()
1872 * only if the file exists.
1873 */
1874 force_remove = TRUE;
1875 remove_recursive = TRUE;
1876 remove_file(name, FALSE);
1877 remove_recursive = oremove_recursive;
1878 force_remove = oforce_remove;
1879 }
1880
1881 LOCAL BOOL
get_file(info)1882 get_file(info)
1883 FINFO *info;
1884 {
1885 FILE *f;
1886 int err;
1887 pathstore_t path;
1888 char xname[PATH_MAX+1];
1889 char *name = info->f_name;
1890 BOOL ret = TRUE;
1891
1892 if (dometa) {
1893 void_file(info);
1894 return (TRUE);
1895 }
1896
1897 path.ps_path = xname;
1898 xname[0] = '\0';
1899
1900 if (to_stdout) {
1901 f = stdout;
1902 goto ofile;
1903 }
1904 if (do_install && name_exists(name)) {
1905 if (!file_tmpname(info, &path)) {
1906 ret = FALSE;
1907 goto out;
1908 }
1909 name = path.ps_path;
1910 }
1911 if ((f = file_open(info, name)) == (FILE *)NULL) {
1912 err = geterrno();
1913 if (err == EMISSDIR && create_dirs(info->f_name)) {
1914 if ((f = file_open(info, name)) != (FILE *)NULL) {
1915 goto ofile;
1916 }
1917 err = geterrno();
1918 }
1919 if ((err == EACCES || is_eexist(err) || err == EISDIR ||
1920 is_eloop(err)) &&
1921 remove_file(name, FALSE)) {
1922 if ((f = file_open(info, name)) != (FILE *)NULL) {
1923 goto ofile;
1924 }
1925 }
1926
1927 if (!errhidden(E_OPEN, info->f_name)) {
1928 if (!errwarnonly(E_OPEN, info->f_name))
1929 xstats.s_openerrs++;
1930 errmsg("Cannot create '%s'.\n", info->f_name);
1931 (void) errabort(E_OPEN, info->f_name, TRUE);
1932 }
1933 void_file(info);
1934 ret = FALSE;
1935 goto out;
1936 }
1937 ofile:
1938 if (!get_ofile(f, info)) {
1939 if (!to_stdout && do_install)
1940 remove_tmpname(path.ps_path);
1941 ret = FALSE;
1942 goto out;
1943 }
1944 if (!to_stdout && do_install)
1945 ret = install_rename(info, path.ps_path);
1946 out:
1947 if (path.ps_path != xname)
1948 free_pspace(&path);
1949 return (ret);
1950 }
1951
1952 LOCAL BOOL
get_ofile(f,info)1953 get_ofile(f, info)
1954 FILE *f;
1955 FINFO *info;
1956 {
1957 int err;
1958 int ret;
1959
1960 file_raise(f, FALSE);
1961
1962 #if defined(F_GETFL) && defined(O_DSYNC)
1963 /*
1964 * Try to write file data as soon as possible to avoid
1965 * longer wait when fsync() is called later.
1966 */
1967 if (!no_fsync) {
1968 int fl;
1969
1970 fl = fcntl(fdown(f), F_GETFL, 0);
1971 fl |= O_DSYNC;
1972 fcntl(fdown(f), F_SETFL, fl);
1973 }
1974 #endif
1975
1976 if (is_sparse(info)) {
1977 ret = get_sparse(f, info);
1978 } else if (force_hole) {
1979 if (xmeta)
1980 ret = get_as_hole(f, info);
1981 else
1982 ret = get_forced_hole(f, info);
1983 } else {
1984 ret = xt_file(info, (ssize_t(*)__PR((void *, char *, size_t)))ffilewrite,
1985 f, 0, "writing");
1986 }
1987 if (ret < 0) {
1988 if (!to_stdout)
1989 snulltimes(info->f_name, info);
1990 die(EX_BAD);
1991 }
1992 if (!to_stdout) {
1993 #ifdef HAVE_FSYNC
1994 int cnt;
1995 #endif
1996 if (ret == FALSE)
1997 xstats.s_rwerrs--; /* Compensate overshoot below */
1998
1999 if (fflush(f) != 0)
2000 ret = FALSE;
2001 #ifdef HAVE_FSYNC
2002 err = 0;
2003 cnt = 0;
2004 do {
2005 if (!no_fsync && fsync(fdown(f)) != 0)
2006 err = geterrno();
2007
2008 if (err == EINVAL)
2009 err = 0;
2010 } while (err == EINTR && ++cnt < 10);
2011 if (err != 0)
2012 ret = FALSE;
2013 #endif
2014 if (fclose(f) != 0)
2015 ret = FALSE;
2016 if (ret == FALSE) {
2017 xstats.s_rwerrs++;
2018 if (!to_stdout)
2019 snulltimes(info->f_name, info);
2020 }
2021 }
2022 return (ret);
2023 }
2024
2025 /* ARGSUSED */
2026 LOCAL ssize_t
void_func(vp,p,amount)2027 void_func(vp, p, amount)
2028 void *vp;
2029 char *p;
2030 size_t amount;
2031 {
2032 return (amount);
2033 }
2034
2035 EXPORT BOOL
void_file(info)2036 void_file(info)
2037 FINFO *info;
2038 {
2039 int ret = TRUE;
2040 Ullong llsize = info->f_llsize;
2041 off_t size = info->f_rsize;
2042
2043 /*
2044 * handle botch in gnu sparse file definitions
2045 */
2046 if (props.pr_flags & PR_GNU_SPARSE_BUG)
2047 if (gnu_skip_extended(info) < 0)
2048 die(EX_BAD);
2049
2050 if (info->f_flags & F_DATA_SKIPPED)
2051 return (ret);
2052
2053 /*
2054 * Try to do our best to skip even files with a size that
2055 * is more then off_t may handle on the local machine.
2056 */
2057 do {
2058 if (info->f_flags & F_BAD_SIZE) {
2059 if (llsize > 1024*1024*1024)
2060 info->f_rsize = 1024*1024*1024;
2061 else
2062 info->f_rsize = llsize;
2063 }
2064
2065 ret = xt_file(info, void_func, 0, 0, "void");
2066 if (ret < 0)
2067 die(EX_BAD);
2068
2069 llsize -= info->f_rsize;
2070
2071 } while ((info->f_flags & F_BAD_SIZE) && llsize > 0);
2072
2073 info->f_rsize = size;
2074 info->f_flags |= F_DATA_SKIPPED;
2075
2076 return (ret);
2077 }
2078
2079 LOCAL BOOL
void_bad(info)2080 void_bad(info)
2081 FINFO *info;
2082 {
2083 int ret;
2084
2085 if (!nowarn)
2086 errmsgno(EX_BAD,
2087 "WARNING: bad metadata for '%s', skipping...\n",
2088 info->f_name);
2089 ret = void_file(info);
2090 return (ret);
2091 }
2092
2093 /*
2094 * Extract file using callback function "func"
2095 * Returns:
2096 * TRUE Extract OK
2097 * FALSE Extract not OK, may continue
2098 * -1 An error occured, max not continue
2099 */
2100 EXPORT int
xt_file(info,func,arg,amt,text)2101 xt_file(info, func, arg, amt, text)
2102 FINFO *info;
2103 ssize_t (*func) __PR((void *, char *, size_t));
2104 void *arg;
2105 long amt;
2106 char *text;
2107 {
2108 register long amount; /* XXX ??? */
2109 register off_t size;
2110 register long tasize;
2111 BOOL ret = TRUE;
2112
2113 size = info->f_rsize;
2114 if (amt == 0)
2115 amt = bufsize;
2116 while (size > 0) {
2117
2118 if ((props.pr_flags & PR_CPIO) == 0) {
2119 amount = buf_rwait(TBLOCK);
2120 if (amount < TBLOCK) {
2121 goto waseof;
2122 }
2123 amount = (amount / TBLOCK) * TBLOCK;
2124 amount = min(size, amount);
2125 amount = min(amount, amt);
2126 tasize = tarsize(amount);
2127 } else {
2128 amount = buf_rwait(1); /* Request what is available */
2129 if (amount <= 0) {
2130 goto waseof;
2131 }
2132 amount = min(size, amount);
2133 amount = min(amount, amt);
2134 tasize = amount;
2135 }
2136
2137 if ((*func)(arg, bigptr, amount) != amount) {
2138 ret = FALSE;
2139 if (!errhidden(E_WRITE, info->f_name)) {
2140 if (!errwarnonly(E_WRITE, info->f_name))
2141 xstats.s_rwerrs++;
2142 errmsg("Error %s '%s'.\n", text, info->f_name);
2143 (void) errabort(E_WRITE, info->f_name, TRUE);
2144 }
2145 /*
2146 * func -> void_func() to skip the rest of the file.
2147 */
2148 func = void_func;
2149 }
2150
2151 size -= amount;
2152 buf_rwake(tasize);
2153 }
2154 info->f_flags |= F_DATA_SKIPPED;
2155 /*
2156 * Honour CPIO padding
2157 */
2158 if ((amount = props.pr_pad) != 0) {
2159 size = info->f_rsize;
2160 if (info->f_flags & F_LONGNAME)
2161 size += props.pr_hdrsize;
2162 amount = (amount + 1 - (size & amount)) & amount;
2163 if (amount > 0) {
2164 buf_rwait(amount);
2165 buf_rwake(amount);
2166 }
2167 }
2168 return (ret);
2169 waseof:
2170 errmsgno(EX_BAD, "Tar file too small (amount: %ld bytes).\n", amount);
2171 errmsgno(EX_BAD, "Unexpected EOF on input.\n");
2172 return (-1);
2173 }
2174
2175 EXPORT void
skip_slash(info)2176 skip_slash(info)
2177 FINFO *info;
2178 {
2179 static BOOL warned = FALSE;
2180
2181 if (!warned && !nowarn) {
2182 errmsgno(EX_BAD, "WARNING: skipping leading '/' on filenames.\n");
2183 warned = TRUE;
2184 }
2185 /*
2186 * XXX
2187 * XXX ACHTUNG: ia_change kann es n�tig machen, den String umzukopieren
2188 * XXX denn sonst ist die L�nge des Speicherplatzes unbestimmt!
2189 *
2190 * XXX ACHTUNG: mir ist noch unklar, ob es richtig ist, auch in jedem
2191 * XXX Fall F�hrende slashes vom Linknamen zu entfernen.
2192 * XXX Bei Hard-Link ist das sicher richtig und ergibt sich auch
2193 * XXX automatisch, wenn man nur vor dem Aufruf von skip_slash()
2194 * XXX auf f_name[0] == '/' abfragt.
2195 */
2196 while (info->f_name[0] == '/')
2197 info->f_name++;
2198
2199 /*
2200 * Don't strip leading '/' from targets of symlinks.
2201 */
2202 if (is_symlink(info))
2203 return;
2204
2205 while (info->f_lname[0] == '/')
2206 info->f_lname++;
2207 }
2208
2209 #if PATH_DELIM == '\\' || defined(IS_CYGWIN)
2210 #define NEED_BACKSLASH
2211 #endif
2212
2213 LOCAL BOOL
has_dotdot(name)2214 has_dotdot(name)
2215 char *name;
2216 {
2217 register char *p = name;
2218
2219 while (*p) {
2220 if ((p[0] == '.' && p[1] == '.') &&
2221 (p[2] == '/' ||
2222 #ifdef NEED_BACKSLASH
2223 p[2] == '\\' ||
2224 #endif
2225 p[2] == '\0')) {
2226 return (TRUE);
2227 }
2228 do {
2229 if (*p++ == '\0')
2230 return (FALSE);
2231 #ifdef NEED_BACKSLASH
2232 } while (*p != '/' && *p != '\\');
2233 #else
2234 } while (*p != '/');
2235 #endif
2236 p++;
2237 #ifdef NEED_BACKSLASH
2238 while (*p == '/' || *p == '\\')
2239 p++;
2240 #else
2241 while (*p == '/') /* Skip multiple slashes */
2242 p++;
2243 #endif
2244 }
2245 return (FALSE);
2246 }
2247
2248 LOCAL BOOL
inside_tree(info)2249 inside_tree(info)
2250 FINFO *info;
2251 {
2252 char _rpath[PATH_MAX+1];
2253 char _npath[PATH_MAX+1];
2254 char *rpath = _rpath;
2255 char *npath = _npath;
2256 char *p;
2257 size_t len;
2258 int nlen; /* Solaris resolvepath() returns int */
2259 BOOL ret = FALSE;
2260 extern const char *wdir;
2261
2262 /*
2263 * If we are in the root directory, any unusual pathname is critical.
2264 */
2265 if (wdir != NULL && wdir[0] == '/' && wdir[1] == '\0')
2266 return (FALSE);
2267
2268 if (info->f_namelen > 0)
2269 len = info->f_namelen;
2270 else
2271 len = strlen(info->f_name);
2272
2273 if (info->f_lnamelen > 0)
2274 len += info->f_lnamelen;
2275 else
2276 len += strlen(info->f_lname);
2277
2278 if (++len > sizeof (_rpath)) {
2279 rpath = __jmalloc(len, "name buffer", JM_RETURN);
2280 if (rpath == NULL)
2281 return (FALSE);
2282 }
2283 if (len > sizeof (_npath)) {
2284 npath = __jmalloc(len, "name buffer", JM_RETURN);
2285 if (npath == NULL)
2286 goto out;
2287 }
2288
2289 /*
2290 * Create combined path name.
2291 */
2292 if (info->f_lname[0] != '/') {
2293 strcpy(rpath, info->f_name);
2294 p = strrchr(rpath, '/');
2295 if (p == NULL)
2296 rpath[0] = '\0';
2297 else
2298 *++p = '\0';
2299 } else {
2300 rpath[0] = '\0';
2301 }
2302 strcat(rpath, info->f_lname);
2303
2304 /*
2305 * Normalize combined path name.
2306 */
2307 nlen = resolvenpath(rpath, npath, len);
2308 if (nlen < 0)
2309 goto out;
2310 npath[nlen] = '\0';
2311
2312 /*
2313 * Check if it points outside our working directory.
2314 */
2315 if (npath[0] != '/' && !has_dotdot(npath))
2316 ret = TRUE;
2317
2318 out:
2319 if (rpath != _rpath)
2320 free(rpath);
2321 if (npath != _npath)
2322 free(npath);
2323
2324 return (ret);
2325 }
2326