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