1 /* @(#)star_unix.c 1.120 19/11/24 Copyright 1985, 1995, 2001-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)star_unix.c 1.120 19/11/24 Copyright 1985, 1995, 2001-2019 J. Schilling";
6 #endif
7 /*
8 * Stat / mode / owner routines for unix like
9 * operating systems
10 *
11 * Copyright (c) 1985, 1995, 2001-2019 J. Schilling
12 */
13 /*
14 * The contents of this file are subject to the terms of the
15 * Common Development and Distribution License, Version 1.0 only
16 * (the "License"). You may not use this file except in compliance
17 * with the License.
18 *
19 * See the file CDDL.Schily.txt in this distribution for details.
20 * A copy of the CDDL is also available via the Internet at
21 * http://www.opensource.org/licenses/cddl1.txt
22 *
23 * When distributing Covered Code, include this CDDL HEADER in each
24 * file and include the License file CDDL.Schily.txt from this distribution.
25 */
26
27 #include <schily/mconfig.h>
28 #ifndef HAVE_UTIMES
29 #define utimes __nothing__ /* BeOS has no utimes() but wrong prototype */
30 #endif
31 #include <schily/stdio.h>
32 #include <schily/errno.h>
33 #include "star.h"
34 #include "props.h"
35 #include "table.h"
36 #include <schily/standard.h>
37 #include <schily/unistd.h>
38 #include <schily/dirent.h>
39 #include <schily/fcntl.h> /* For AT_FDCWD */
40 #include <schily/stat.h>
41 #include <schily/param.h> /* For DEV_BSIZE */
42 #include <schily/device.h>
43 #include <schily/string.h>
44 #define GT_COMERR /* #define comerr gtcomerr */
45 #define GT_ERROR /* #define error gterror */
46 #include <schily/schily.h>
47 #include "dirtime.h"
48 #include "xutimes.h"
49 #ifndef HAVE_UTIMES
50 #undef utimes
51 #endif
52 #include "starsubs.h"
53 #include "checkerr.h"
54
55 #ifndef HAVE_LSTAT
56 #define lstat stat
57 #undef AT_SYMLINK_NOFOLLOW
58 #define AT_SYMLINK_NOFOLLOW 0
59 #endif
60 #ifndef HAVE_LCHOWN
61 #define lchown chown
62 #endif
63
64 #if S_ISUID == TSUID && S_ISGID == TSGID && S_ISVTX == TSVTX && \
65 S_IRUSR == TUREAD && S_IWUSR == TUWRITE && S_IXUSR == TUEXEC && \
66 S_IRGRP == TGREAD && S_IWGRP == TGWRITE && S_IXGRP == TGEXEC && \
67 S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC
68
69 #define HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
70 #endif
71
72 #define ROOT_UID 0
73
74 extern uid_t my_uid;
75 extern dev_t curfs;
76 extern BOOL noatime;
77 extern BOOL nomtime;
78 extern BOOL nochown;
79 extern BOOL pflag;
80 extern BOOL follow;
81 extern BOOL paxfollow;
82 extern BOOL nodump;
83 extern BOOL doacl;
84 extern BOOL doxattr;
85 extern BOOL dolxattr;
86 extern BOOL dofflags;
87
88 EXPORT BOOL _getinfo __PR((char *name, FINFO *info));
89 EXPORT BOOL _lgetinfo __PR((char *name, FINFO *info));
90 EXPORT BOOL getinfo __PR((char *name, FINFO *info));
91 #ifdef HAVE_FSTATAT
92 EXPORT BOOL getinfoat __PR((int fd, char *name, FINFO *info));
93 #endif
94 EXPORT BOOL getstat __PR((char *name, struct stat *sp));
95 EXPORT BOOL stat_to_info __PR((int fd, struct stat *sp, FINFO *info));
96 LOCAL void print_badnsec __PR((FINFO *info, char *name, long val));
97 EXPORT void checkarch __PR((FILE *f));
98 EXPORT BOOL archisnull __PR((const char *name));
99 EXPORT BOOL samefile __PR((FILE *fp1, FILE *fp2));
100 EXPORT void setmodes __PR((FINFO *info));
101 LOCAL int sutimes __PR((char *name, FINFO *info, BOOL asymlink));
102 EXPORT int snulltimes __PR((char *name, FINFO *info));
103 EXPORT int sxsymlink __PR((char *name, FINFO *info));
104 EXPORT int rs_acctime __PR((int fd, FINFO *info));
105 EXPORT void setdirmodes __PR((char *name, mode_t mode));
106 EXPORT mode_t osmode __PR((mode_t tarmode));
107 #ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
108 #else
109 LOCAL int dolchmodat __PR((char *name, mode_t tarmode, int flag));
110 #endif
111
112 #ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
113 #else
114 #define lchmodat dolchmodat
115 #endif
116
117 #ifdef USE_ACL
118
119 #ifdef OWN_ACLTEXT
120 #if defined(UNIXWARE) && defined(HAVE_ACL)
121 #define HAVE_SUN_ACL
122 #define HAVE_ANY_ACL
123 #endif
124 #endif
125 /*
126 * HAVE_ANY_ACL currently includes HAVE_POSIX_ACL and HAVE_SUN_ACL.
127 * This definition must be in sync with the definition in acl_unix.c
128 * As USE_ACL is used in star.h, we are not allowed to change the
129 * value of USE_ACL before we did include star.h or we may not include
130 * star.h at all.
131 * HAVE_HP_ACL is currently not included in HAVE_ANY_ACL.
132 */
133 #ifndef HAVE_ANY_ACL
134 #undef USE_ACL /* Do not try to get or set ACLs */
135 #endif
136 #endif
137
138 /*
139 * Simple getinfo() variant.
140 */
141 EXPORT BOOL
_getinfo(name,info)142 _getinfo(name, info)
143 char *name;
144 register FINFO *info;
145 {
146 BOOL ret;
147 BOOL odoacl = doacl;
148 BOOL odoxattr = doxattr;
149 BOOL odolxattr = dolxattr;
150
151 doacl = FALSE;
152 doxattr = FALSE;
153 ret = getinfo(name, info);
154 doacl = odoacl;
155 doxattr = odoxattr;
156 dolxattr = odolxattr;
157
158 return (ret);
159 }
160
161 /*
162 * Simple getinfo() variant using lstat()
163 */
164 EXPORT BOOL
_lgetinfo(name,info)165 _lgetinfo(name, info)
166 char *name;
167 register FINFO *info;
168 {
169 BOOL ret;
170 BOOL ofollow = follow;
171 BOOL opaxfollow = paxfollow;
172
173 /*
174 * Always use lstat()
175 */
176 follow = FALSE;
177 paxfollow = FALSE;
178 ret = _getinfo(name, info);
179 follow = ofollow;
180 paxfollow = opaxfollow;
181
182 return (ret);
183 }
184
185 EXPORT BOOL
getinfo(name,info)186 getinfo(name, info)
187 char *name;
188 register FINFO *info;
189 {
190 struct stat stbuf;
191
192 info->f_filetype = -1; /* Will be overwritten if stat() works */
193 newstat:
194 if (paxfollow) {
195 if (lstatat(name, &stbuf, 0 /* stat */) < 0) {
196 if (geterrno() == EINTR)
197 goto newstat;
198 if (geterrno() != ENOENT)
199 return (FALSE);
200
201 while (lstatat(name, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) {
202 if (geterrno() != EINTR)
203 return (FALSE);
204 }
205 }
206 } else if (lstatat(name, &stbuf, follow?0:AT_SYMLINK_NOFOLLOW) < 0) {
207 if (geterrno() == EINTR)
208 goto newstat;
209 return (FALSE);
210 }
211 info->f_sname = info->f_name = name;
212 return (stat_to_info(AT_FDCWD, &stbuf, info));
213 }
214
215 #ifdef HAVE_FSTATAT
216 EXPORT BOOL
getinfoat(fd,name,info)217 getinfoat(fd, name, info)
218 int fd;
219 char *name;
220 register FINFO *info;
221 {
222 struct stat stbuf;
223
224 info->f_filetype = -1; /* Will be overwritten if stat() works */
225 newstat:
226 if (paxfollow) {
227 if (fstatat(fd, name, &stbuf, 0 /* stat */) < 0) {
228 if (geterrno() == EINTR)
229 goto newstat;
230 if (geterrno() != ENOENT)
231 return (FALSE);
232
233 while (fstatat(fd, name, &stbuf, AT_SYMLINK_NOFOLLOW) < 0) {
234 if (geterrno() != EINTR)
235 return (FALSE);
236 }
237 }
238 } else if (fstatat(fd, name, &stbuf, follow?0:AT_SYMLINK_NOFOLLOW) < 0) {
239 if (geterrno() == EINTR)
240 goto newstat;
241 return (FALSE);
242 }
243 info->f_sname = info->f_name = name;
244 return (stat_to_info(fd, &stbuf, info));
245 }
246 #endif
247
248 EXPORT BOOL
getstat(name,sp)249 getstat(name, sp)
250 char *name;
251 struct stat *sp;
252 {
253 newstat:
254 if (paxfollow) {
255 if (lstatat(name, sp, 0 /* stat */) < 0) {
256 if (geterrno() == EINTR)
257 goto newstat;
258 if (geterrno() != ENOENT)
259 return (FALSE);
260
261 while (lstatat(name, sp, AT_SYMLINK_NOFOLLOW) < 0) {
262 if (geterrno() != EINTR)
263 return (FALSE);
264 }
265 }
266 } else if (lstatat(name, sp, follow?0:AT_SYMLINK_NOFOLLOW) < 0) {
267 if (geterrno() == EINTR)
268 goto newstat;
269 return (FALSE);
270 }
271 return (TRUE);
272 }
273
274 EXPORT BOOL
stat_to_info(fd,sp,info)275 stat_to_info(fd, sp, info)
276 int fd;
277 struct stat *sp;
278 FINFO *info;
279 {
280 BOOL first = TRUE;
281
282 again:
283 info->f_uname = info->f_gname = NULL;
284 info->f_umaxlen = info->f_gmaxlen = 0L;
285 info->f_dev = sp->st_dev;
286 if (curfs == NODEV)
287 curfs = info->f_dev;
288 info->f_ino = sp->st_ino;
289 info->f_nlink = sp->st_nlink;
290 #ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
291 info->f_mode = sp->st_mode & 07777;
292 #else
293 /*
294 * The unexpected case when the S_I* OS mode bits do not match
295 * the T* mode bits from tar.
296 */
297 { register mode_t m = sp->st_mode;
298
299 info->f_mode = ((m & S_ISUID ? TSUID : 0)
300 | (m & S_ISGID ? TSGID : 0)
301 | (m & S_ISVTX ? TSVTX : 0)
302 | (m & S_IRUSR ? TUREAD : 0)
303 | (m & S_IWUSR ? TUWRITE : 0)
304 | (m & S_IXUSR ? TUEXEC : 0)
305 | (m & S_IRGRP ? TGREAD : 0)
306 | (m & S_IWGRP ? TGWRITE : 0)
307 | (m & S_IXGRP ? TGEXEC : 0)
308 | (m & S_IROTH ? TOREAD : 0)
309 | (m & S_IWOTH ? TOWRITE : 0)
310 | (m & S_IXOTH ? TOEXEC : 0));
311 }
312 #endif
313 info->f_uid = sp->st_uid;
314 info->f_gid = sp->st_gid;
315 info->f_size = (off_t)0; /* Size of file */
316 info->f_rsize = (off_t)0; /* Size on tape */
317 info->f_flags = 0L;
318 info->f_xflags = props.pr_xhdflags;
319 info->f_typeflag = 0;
320 info->f_type = sp->st_mode & ~07777;
321
322 if (sizeof (sp->st_rdev) == sizeof (short)) {
323 info->f_rdev = (Ushort) sp->st_rdev;
324 } else if ((sizeof (int) != sizeof (long)) &&
325 (sizeof (sp->st_rdev) == sizeof (int))) {
326 info->f_rdev = (Uint) sp->st_rdev;
327 } else {
328 info->f_rdev = (Ulong) sp->st_rdev;
329 }
330 info->f_rdevmaj = major(info->f_rdev);
331 info->f_rdevmin = minor(info->f_rdev);
332 info->f_atime = sp->st_atime;
333 info->f_mtime = sp->st_mtime;
334 info->f_ctime = sp->st_ctime;
335
336 info->f_ansec = stat_ansecs(sp);
337 info->f_mnsec = stat_mnsecs(sp);
338 info->f_cnsec = stat_cnsecs(sp);
339
340 info->f_timeres = 1;
341
342 #if defined(_FOUND_STAT_NSECS_)
343 info->f_flags |= F_NSECS;
344 #ifdef HAVE_ST_FSTYPE
345 if (sp->st_fstype[0] == 'p' && streql(sp->st_fstype, "pcfs"))
346 info->f_flags &= ~F_NSECS;
347 if (sp->st_fstype[0] == 'u' &&
348 sp->st_fstype[1] == 'f' &&
349 sp->st_fstype[2] == 's')
350 info->f_timeres = 1000;
351 #endif
352 #endif
353
354 if (info->f_ansec < 0 || info->f_ansec >= 1000000000L) {
355 print_badnsec(info, "atime", info->f_ansec);
356 info->f_ansec = 0;
357 }
358 if (info->f_mnsec < 0 || info->f_mnsec >= 1000000000L) {
359 print_badnsec(info, "mtime", info->f_mnsec);
360 info->f_mnsec = 0;
361 }
362 if (info->f_cnsec < 0 || info->f_cnsec >= 1000000000L) {
363 print_badnsec(info, "ctime", info->f_cnsec);
364 info->f_cnsec = 0;
365 }
366
367 #ifdef HAVE_ST_FLAGS
368 /*
369 * The *BSD based method is easy to handle.
370 */
371 if (dofflags)
372 info->f_fflags = sp->st_flags;
373 else
374 info->f_fflags = 0L;
375 if (info->f_fflags != 0)
376 info->f_xflags |= XF_FFLAGS;
377 #ifdef UF_NODUMP /* The *BSD 'nodump' flag */
378 if ((sp->st_flags & UF_NODUMP) != 0)
379 info->f_flags |= F_NODUMP; /* Convert it to star flag */
380 #endif
381 #else /* !HAVE_ST_FLAGS */
382 /*
383 * The non *BSD case...
384 */
385 #ifdef USE_FFLAGS
386 if ((nodump || dofflags) && !S_ISLNK(sp->st_mode)) {
387 get_fflags(info);
388 if (!dofflags)
389 info->f_xflags &= ~XF_FFLAGS;
390 } else {
391 info->f_fflags = 0L;
392 }
393 #else
394 info->f_fflags = 0L;
395 #endif
396 #endif
397
398 #ifdef HAVE_ST_ACLCNT
399 info->f_aclcnt = sp->st_aclcnt;
400 #endif
401
402 switch ((int)(sp->st_mode & S_IFMT)) {
403
404 case S_IFREG: /* regular file */
405 info->f_filetype = F_FILE;
406 info->f_xftype = XT_FILE;
407 info->f_rsize = info->f_size = sp->st_size;
408 info->f_rdev = 0;
409 info->f_rdevmaj = 0;
410 info->f_rdevmin = 0;
411 break;
412 #ifdef S_IFCTG
413 case S_IFCTG: /* contiguous file */
414 info->f_filetype = F_FILE;
415 info->f_xftype = XT_CONT;
416 info->f_rsize = info->f_size = sp->st_size;
417 info->f_rdev = 0;
418 info->f_rdevmaj = 0;
419 info->f_rdevmin = 0;
420 break;
421 #endif
422 case S_IFDIR: /* directory */
423 info->f_filetype = F_DIR;
424 info->f_xftype = XT_DIR;
425 info->f_rdev = 0;
426 info->f_rdevmaj = 0;
427 info->f_rdevmin = 0;
428 info->f_dir = NULL; /* No directory content known */
429 info->f_dirinos = NULL; /* No inode list known */
430 info->f_dirlen = 0;
431 info->f_dirents = 0;
432 break;
433 #ifdef S_IFLNK
434 case S_IFLNK: /* symbolic link */
435 info->f_filetype = F_SLINK;
436 info->f_xftype = XT_SLINK;
437 info->f_rdev = 0;
438 info->f_rdevmaj = 0;
439 info->f_rdevmin = 0;
440 break;
441 #endif
442 #ifdef S_IFCHR
443 case S_IFCHR: /* character special */
444 info->f_filetype = F_SPEC;
445 info->f_xftype = XT_CHR;
446 break;
447 #endif
448 #ifdef S_IFBLK
449 case S_IFBLK: /* block special */
450 info->f_filetype = F_SPEC;
451 info->f_xftype = XT_BLK;
452 break;
453 #endif
454 #ifdef S_IFIFO
455 case S_IFIFO: /* fifo */
456 info->f_filetype = F_SPEC;
457 info->f_xftype = XT_FIFO;
458 info->f_rdev = 0;
459 info->f_rdevmaj = 0;
460 info->f_rdevmin = 0;
461 break;
462 #endif
463 #ifdef S_IFSOCK
464 case S_IFSOCK: /* socket */
465 info->f_filetype = F_SPEC;
466 info->f_xftype = XT_SOCK;
467 break;
468 #endif
469 #ifdef S_IFNAM
470 case S_IFNAM: /* Xenix named file */
471 info->f_filetype = F_SPEC;
472
473 /*
474 * 'st_rdev' field is really the subtype
475 * As S_INSEM & S_INSHD we may safely cast
476 * sp->st_rdev to int.
477 */
478 switch ((int)sp->st_rdev) {
479 case S_INSEM:
480 info->f_xftype = XT_NSEM;
481 break;
482 case S_INSHD:
483 info->f_xftype = XT_NSHD;
484 break;
485 default:
486 info->f_xftype = XT_BAD;
487 break;
488 }
489 break;
490 #endif
491 #ifdef S_IFMPC
492 case S_IFMPC: /* multiplexed character special */
493 info->f_filetype = F_SPEC;
494 info->f_xftype = XT_MPC;
495 break;
496 #endif
497 #ifdef S_IFMPB
498 case S_IFMPB: /* multiplexed block special */
499 info->f_filetype = F_SPEC;
500 info->f_xftype = XT_MPB;
501 break;
502 #endif
503 #ifdef S_IFDOOR
504 case S_IFDOOR: /* door */
505 info->f_filetype = F_SPEC;
506 info->f_xftype = XT_DOOR;
507 break;
508 #endif
509 #ifdef S_IFWHT
510 case S_IFWHT: /* whiteout */
511 info->f_filetype = F_SPEC;
512 info->f_xftype = XT_WHT;
513 break;
514 #endif
515
516 default: /* any other unknown file type */
517 if ((sp->st_mode & S_IFMT) == 0) {
518 /*
519 * If we come here, we either did not yet
520 * realize that somebody created a new file
521 * type with a value of 0 or the system did
522 * return an "unallocated file" with lstat().
523 * The latter happens if we are on old Solaris
524 * systems that did not yet add SOCKETS again.
525 * if somebody mounted a filesystem that
526 * has been written with a *BSD system like
527 * SunOS 4.x and this FS holds a socket we get
528 * a pseudo unallocated file...
529 */
530 info->f_filetype = F_SPEC; /* ??? */
531 info->f_xftype = XT_NONE;
532 } else {
533 /*
534 * We don't know this file type!
535 */
536 info->f_filetype = F_SPEC;
537 info->f_xftype = XT_BAD;
538 }
539 }
540 info->f_rxftype = info->f_xftype;
541
542 if (first && pr_unsuptype(info)) {
543 first = FALSE;
544 if (fd == AT_FDCWD) {
545 /*
546 * Cannot use fstatat() as this may be a very long
547 * path name.
548 */
549 if (lstatat(info->f_sname, sp, AT_SYMLINK_NOFOLLOW) < 0)
550 return (FALSE);
551 } else {
552 if (fstatat(fd, info->f_sname, sp, AT_SYMLINK_NOFOLLOW) < 0)
553 return (FALSE);
554 }
555 goto again;
556 }
557
558 #ifdef HAVE_ST_BLOCKS
559 /*
560 * The blocking factor for st_blocks is DEV_BSIZE fro sys/param.h
561 */
562 #if defined(hpux) || defined(__hpux)
563 if (info->f_size > (sp->st_blocks * 1024 + 1024)) {
564 #else
565 if (info->f_size > (sp->st_blocks * 512 + 512)) {
566 #endif
567 info->f_flags |= F_SPARSE;
568
569 #ifdef __no_longer__
570 /*
571 * Some filesystems do not allocate disk space for files that
572 * consist of one hole and no written data.
573 * If we are on a platform that does not support to read hole
574 * lists for sparse files, this allows to avoid wasting time
575 * reading through the whole file.
576 *
577 * In October 2013, it turned out that at least NetAPP stores
578 * files up to 64 bytes in the inode and then returns
579 * sp->st_blocks == 0 for a non sparse file. We only come here
580 * if the file size is > DEV_BSIZE in hope that noone will
581 * implement a filesystem that hides larger amount of data
582 * without supporting SEEK_HOLE.
583 *
584 * Update: There seems to be a major problem in btrfs:
585 * There was a report that btrfs reports sp->st_blocks == 0
586 * for a file with an 8 GB hole followed by 512 bytes of 'A'.
587 * While this is most likely a btrfs bug, in theory a
588 * filesystem could compress the data past the hole and hold
589 * the compressed data inside the inode. As a result, we needed
590 * to disable the F_ALL_HOLE check.
591 */
592 if ((info->f_size > 0) && (sp->st_blocks == 0))
593 info->f_flags |= F_ALL_HOLE;
594 #endif
595 }
596 #endif
597
598 /*
599 * Only look for ACL's and other properties that go into the POSIX
600 * extended heaer if extended headers are allowed with the current
601 * archive format. Also don't include ACL's and other properties if
602 * we are creating a Sun vendor unique variant of the extended headers.
603 * Sun's tar will not grok access control lists and other extensions.
604 */
605 if ((props.pr_flags & PR_XHDR) == 0 || (props.pr_xc != 'x'))
606 return (TRUE);
607 #ifdef USE_ACL
608 /*
609 * If we return (FALSE) here, the file would not be archived at all.
610 * This is not what we want, so ignore return code from get_acls().
611 */
612
613 /*
614 * Note: ACL check/fetch has been moved to create.c::take_file()
615 * for performance reasons.
616 */
617 #endif /* USE_ACL */
618
619 #ifdef USE_XATTR
620 /*
621 * Note: Linux xattr check/fetch has been moved to create.c::take_file()
622 * for performance reasons.
623 */
624 #endif
625
626 return (TRUE);
627 }
628
629 LOCAL void
print_badnsec(info,name,val)630 print_badnsec(info, name, val)
631 FINFO *info;
632 char *name;
633 long val;
634 {
635 errmsgno(EX_BAD, "Bad '%s' nanosecond value %ld for '%s'.\n",
636 name, val, info->f_name);
637 }
638
639
640 EXPORT void
checkarch(f)641 checkarch(f)
642 FILE *f;
643 {
644 struct stat stbuf;
645 extern dev_t tape_dev;
646 extern ino_t tape_ino;
647 extern BOOL tape_isreg;
648
649 tape_isreg = FALSE;
650 tape_dev = (dev_t)0;
651 tape_ino = (ino_t)0;
652
653 if (fstat(fdown(f), &stbuf) < 0)
654 return;
655
656 if (S_ISREG(stbuf.st_mode)) {
657 tape_dev = stbuf.st_dev;
658 tape_ino = stbuf.st_ino;
659 tape_isreg = TRUE;
660 } else if (((stbuf.st_mode & S_IFMT) == 0) ||
661 S_ISFIFO(stbuf.st_mode) ||
662 S_ISSOCK(stbuf.st_mode)) {
663 /*
664 * This is a pipe or similar on different UNIX implementations.
665 * (stbuf.st_mode & S_IFMT) == 0 may happen in stange cases.
666 */
667 tape_dev = NODEV;
668 tape_ino = (ino_t)-1;
669 }
670 }
671
672 EXPORT BOOL
archisnull(name)673 archisnull(name)
674 const char *name;
675 {
676 struct stat stbuf;
677 struct stat stnull;
678
679 if (name == NULL)
680 return (FALSE);
681
682 if (streql(name, "-")) {
683 if (fstat(fdown(stdout), &stbuf) < 0)
684 return (FALSE);
685 } else {
686 if (stat(name, &stbuf) < 0)
687 return (FALSE);
688 }
689 if (stat("/dev/null", &stnull) < 0)
690 return (FALSE);
691
692 if (stbuf.st_dev == stnull.st_dev &&
693 stbuf.st_ino == stnull.st_ino)
694 return (TRUE);
695 return (FALSE);
696 }
697
698 EXPORT BOOL
samefile(fp1,fp2)699 samefile(fp1, fp2)
700 FILE *fp1;
701 FILE *fp2;
702 {
703 struct stat stbuf1;
704 struct stat stbuf2;
705
706 if (fp1 == NULL || fp2 == NULL)
707 return (FALSE);
708
709 if (fstat(fdown(fp1), &stbuf1) < 0)
710 return (FALSE);
711
712 if (fstat(fdown(fp2), &stbuf2) < 0)
713 return (FALSE);
714
715 if (stbuf1.st_dev == stbuf2.st_dev &&
716 stbuf1.st_ino == stbuf2.st_ino)
717 return (TRUE);
718 return (FALSE);
719 }
720
721 EXPORT void
setmodes(info)722 setmodes(info)
723 register FINFO *info;
724 {
725 BOOL didutimes = FALSE;
726 BOOL asymlink = is_symlink(info);
727
728 /*
729 * If it does not seem to be a symbolic link, we need to check whether
730 * this is an archive format that does not store the real file type.
731 * We need to avoid to set time stamps or modes for hard links on
732 * symbolic links.
733 */
734 if (!asymlink &&
735 fis_link(info)) { /* Real file type unknown */
736 FINFO finfo;
737
738 if (_getinfo(info->f_name, &finfo) && is_symlink(&finfo))
739 asymlink = TRUE;
740 }
741
742 if (!nomtime && !asymlink) {
743 /*
744 * With Cygwin32,
745 * DOS will not allow us to set file times on read-only files.
746 * We set the time before we change the access modes to
747 * overcode this problem.
748 * XXX This will no longer work with the new -p flag handling
749 * XXX as the files may be read only from the creation.
750 */
751 if (!is_dir(info)) {
752 didutimes = TRUE;
753 if (sutimes(info->f_name, info, asymlink) < 0) {
754 if (!errhidden(E_SETTIME, info->f_name)) {
755 if (!errwarnonly(E_SETTIME, info->f_name))
756 xstats.s_settime++;
757 (void) errabort(E_SETTIME,
758 info->f_name, TRUE);
759 }
760 }
761 }
762 }
763
764 if (pflag && !asymlink) {
765 mode_t mode = info->f_mode;
766
767 if (is_dir(info))
768 mode |= TUWRITE;
769 if (lchmodat(info->f_name, mode, 0 /* chmod */) < 0) {
770 if (!errhidden(E_SETMODE, info->f_name)) {
771 if (!errwarnonly(E_SETMODE, info->f_name))
772 xstats.s_setmodes++;
773 (void) errabort(E_SETMODE, info->f_name, TRUE);
774 }
775 }
776 #ifdef USE_ACL
777 /*
778 * If there are no additional ACLs, set_acls() will
779 * simply do a fast return.
780 */
781 if (doacl)
782 set_acls(info);
783 #endif
784 }
785 #ifdef USE_FFLAGS
786 if (dofflags && !asymlink)
787 set_fflags(info);
788 #endif
789
790 if (!nochown && my_uid == ROOT_UID) {
791
792 #if defined(HAVE_CHOWN) || defined(HAVE_LCHOWN)
793 /*
794 * Star will not allow non root users to give away files.
795 */
796 lchownat(info->f_name, (int)info->f_uid, (int)info->f_gid,
797 AT_SYMLINK_NOFOLLOW);
798 #endif
799
800 if (pflag && !asymlink &&
801 (info->f_mode & (TSUID | TSGID | TSVTX)) != 0) {
802 mode_t mode = info->f_mode;
803
804 if (is_dir(info))
805 mode |= TUWRITE;
806 /*
807 * On a few systems, seeting the owner of a file
808 * destroys the suid and sgid bits.
809 * We repeat the chmod() in this case.
810 */
811 if (lchmodat(info->f_name, mode, 0 /* chmod */) < 0) {
812 /*
813 * Do not increment chmod() errors here,
814 * it did already fail above.
815 */
816 /* EMPTY */
817 ;
818 }
819 }
820 }
821
822 #ifdef USE_XATTR
823 if (dolxattr)
824 set_xattr(info);
825 #endif
826
827 /*
828 * utimensat() is able to set the time stamps on symlinks, if called
829 * with the AT_SYMLINK_NOFOLLOW flag, so we include symlinks in the
830 * list of file types that cause sutimes() to be called.
831 */
832 if (!nomtime && !is_dir(info)) {
833 if (sutimes(info->f_name, info, asymlink) < 0 && !didutimes)
834 if (!errhidden(E_SETTIME, info->f_name)) {
835 if (!errwarnonly(E_SETTIME, info->f_name))
836 xstats.s_settime++;
837 (void) errabort(E_SETTIME, info->f_name, TRUE);
838 }
839 }
840 if (is_dir(info)) {
841 sdirtimes(info->f_name, info, !nomtime, pflag);
842 }
843 }
844
845 EXPORT int xutimes __PR((char *name, struct timespec *tp,
846 BOOL asymlink));
847
848 LOCAL int
sutimes(name,info,asymlink)849 sutimes(name, info, asymlink)
850 char *name;
851 FINFO *info;
852 BOOL asymlink;
853 {
854 struct timespec curtime;
855 struct timespec tp[3];
856
857 if (noatime) {
858 getnstimeofday(&curtime);
859 tp[0].tv_sec = curtime.tv_sec;
860 tp[0].tv_nsec = curtime.tv_nsec;
861 } else {
862 tp[0].tv_sec = info->f_atime;
863 tp[0].tv_nsec = info->f_ansec;
864 }
865
866 tp[1].tv_sec = info->f_mtime;
867 tp[1].tv_nsec = info->f_mnsec;
868 #ifdef SET_CTIME
869 tp[2].tv_sec = info->f_ctime;
870 tp[2].tv_nsec = info->f_cnsec;
871 #else
872 tp[2].tv_sec = 0;
873 tp[2].tv_nsec = 0;
874 #endif
875 return (xutimes(name, tp, asymlink));
876 }
877
878 EXPORT int
snulltimes(name,info)879 snulltimes(name, info)
880 char *name;
881 FINFO *info;
882 {
883 struct timespec tp[3];
884
885 fillbytes((char *)tp, sizeof (tp), '\0');
886 return (xutimes(name, tp, is_symlink(info)));
887 }
888
889 /*
890 * Extended utimes function.
891 * This is what we use in star as the default.
892 */
893 EXPORT int
xutimes(name,tp,asymlink)894 xutimes(name, tp, asymlink)
895 char *name;
896 struct timespec tp[3];
897 BOOL asymlink;
898 {
899 struct timespec curtime;
900 struct timespec pasttime;
901 extern int Ctime;
902 int ret = 0;
903 int errsav;
904
905 #ifndef HAVE_SETTIMEOFDAY
906 #undef SET_CTIME
907 #endif
908
909 #ifdef SET_CTIME
910 if (Ctime) {
911 getnstimeofday(&curtime);
912 setnstimeofday(&tp[2]);
913 }
914 #endif
915 #if !defined(HAVE_UTIMENSAT) && \
916 !defined(HAVE_LUTIMENS) && \
917 !defined(HAVE_LUTIMES)
918 /*
919 * AT_SYMLINK_NOFOLLOW not in emulation
920 */
921 if (!asymlink)
922 #endif
923 ret = lutimensat(name, tp, AT_SYMLINK_NOFOLLOW);
924 errsav = geterrno();
925
926 #ifdef SET_CTIME
927 if (Ctime) {
928 getnstimeofday(&pasttime);
929 timespecsub(&pasttime, &tp[2]);
930 timespecadd(&curtime, &pasttime);
931 setnstimeofday(&curtime);
932 #ifdef SET_CTIME_DEBUG
933 error("pasttime: %d.%9.9d\n", pasttime.tv_sec, pasttime.tv_nsec);
934 #endif
935 }
936 #endif
937 seterrno(errsav);
938 return (ret);
939 }
940
941 EXPORT int
sxsymlink(name,info)942 sxsymlink(name, info)
943 char *name;
944 FINFO *info;
945 {
946 #ifdef HAVE_SYMLINK
947 struct timespec tp[3];
948 struct timespec curtime;
949 struct timespec pasttime;
950 char *linkname;
951 extern int Ctime;
952 int ret;
953 int errsav;
954 #ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
955 mode_t omask;
956 #endif
957
958 tp[0].tv_sec = info->f_atime;
959 tp[0].tv_nsec = info->f_ansec;
960
961 tp[1].tv_sec = info->f_mtime;
962 tp[1].tv_nsec = info->f_mnsec;
963 #ifdef SET_CTIME
964 tp[2].tv_sec = info->f_ctime;
965 tp[2].tv_nsec = info->f_cnsec;
966 #endif
967 linkname = info->f_lname;
968
969 #ifdef SET_CTIME
970 if (Ctime) {
971 getnstimeofday(&curtime);
972 setnstimeofday(&tp[2]);
973 }
974 #endif
975
976 #ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
977 /*
978 * At least HP-UX-11.x seems to honour the mask when creating symlinks.
979 * If we like to copy them correctly, we need to set the mask before.
980 * As umask(2) is a cheap syscall and symlinks are not very frequent
981 * this does not seem a real problem.
982 */
983 omask = umask((mode_t)0);
984 umask(info->f_mode ^ 07777);
985 #endif
986
987 ret = lsymlink(linkname, name);
988 errsav = geterrno();
989
990 #ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
991 umask(omask);
992 #endif
993
994 #ifdef SET_CTIME
995 if (Ctime) {
996 getnstimeofday(&pasttime);
997 timespecsub(&pasttime, &tp[2]);
998 timespecadd(&curtime, &pasttime);
999 setnstimeofday(&curtime);
1000 #ifdef SET_CTIME_DEBUG
1001 error("pasttime: %d.%9.9d\n", pasttime.tv_sec, pasttime.tv_nsec);
1002 #endif
1003 }
1004 #endif
1005 seterrno(errsav);
1006 return (ret);
1007 #else
1008 seterrno(EINVAL);
1009 return (-1);
1010 #endif
1011 }
1012
1013 #ifdef HAVE_SYS_FILIO_H
1014 #include <sys/filio.h>
1015 #endif
1016
1017 EXPORT int
rs_acctime(fd,info)1018 rs_acctime(fd, info)
1019 int fd;
1020 register FINFO *info;
1021 {
1022 #ifdef _FIOSATIME
1023 struct timeval atv;
1024 #endif
1025
1026 if (is_symlink(info))
1027 return (0);
1028
1029 #ifdef _FIOSATIME
1030 /*
1031 * On Solaris 2.x root may reset accesstime without changing ctime.
1032 */
1033 if (my_uid == ROOT_UID) {
1034 atv.tv_sec = info->f_atime;
1035 atv.tv_usec = info->f_ansec/1000;
1036 return (ioctl(fd, _FIOSATIME, &atv));
1037 }
1038 #endif
1039 return (sutimes(info->f_name, info, FALSE));
1040 }
1041
1042 #ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
1043 #define OSMODE(tarmode) (tarmode)
1044 #else
1045 #define OSMODE(tarmode) ((tarmode & TSUID ? S_ISUID : 0) \
1046 | (tarmode & TSGID ? S_ISGID : 0) \
1047 | (tarmode & TSVTX ? S_ISVTX : 0) \
1048 | (tarmode & TUREAD ? S_IRUSR : 0) \
1049 | (tarmode & TUWRITE ? S_IWUSR : 0) \
1050 | (tarmode & TUEXEC ? S_IXUSR : 0) \
1051 | (tarmode & TGREAD ? S_IRGRP : 0) \
1052 | (tarmode & TGWRITE ? S_IWGRP : 0) \
1053 | (tarmode & TGEXEC ? S_IXGRP : 0) \
1054 | (tarmode & TOREAD ? S_IROTH : 0) \
1055 | (tarmode & TOWRITE ? S_IWOTH : 0) \
1056 | (tarmode & TOEXEC ? S_IXOTH : 0))
1057 #endif
1058
1059 EXPORT void
1060 #ifdef PROTOTYPES
setdirmodes(char * name,mode_t tarmode)1061 setdirmodes(char *name, mode_t tarmode)
1062 #else
1063 setdirmodes(name, tarmode)
1064 char *name;
1065 mode_t tarmode;
1066 #endif
1067 {
1068 register mode_t _osmode;
1069
1070 _osmode = OSMODE(tarmode);
1071 if (lchmodat(name, _osmode, 0 /* chmod */) < 0) { /* OK for dir */
1072 if (!errhidden(E_SETMODE, name)) {
1073 if (!errwarnonly(E_SETMODE, name))
1074 xstats.s_setmodes++;
1075 errmsg("Can't set permission for '%s'.\n", name);
1076 (void) errabort(E_SETMODE, name, TRUE);
1077 }
1078 }
1079 }
1080
1081
1082 EXPORT mode_t
1083 #ifdef PROTOTYPES
osmode(register mode_t tarmode)1084 osmode(register mode_t tarmode)
1085 #else
1086 osmode(tarmode)
1087 register mode_t tarmode;
1088 #endif
1089 {
1090 register mode_t _osmode;
1091
1092 _osmode = OSMODE(tarmode);
1093 return (_osmode);
1094 }
1095
1096 #ifdef HAVE_POSIX_MODE_BITS /* st_mode bits are equal to TAR mode bits */
1097 #else
1098 #undef lchmodat
1099 LOCAL int
1100 #ifdef PROTOTYPES
dolchmodat(register char * name,register mode_t tarmode,int flag)1101 dolchmodat(register char *name, register mode_t tarmode, int flag)
1102 #else
1103 dolchmodat(name, tarmode, flag)
1104 register char *name;
1105 register mode_t tarmode;
1106 int flag;
1107 #endif
1108 {
1109 register mode_t _osmode;
1110
1111 _osmode = OSMODE(tarmode);
1112 return (lchmodat(name, _osmode, flag));
1113 }
1114 #endif
1115