1 /* @(#)lutimens.c	1.4 19/07/31 Copyright 2013-2019 J. Schilling */
2 /*
3  *	Emulate the behavior of lutimens(const char *name,
4  *					const struct timespec times[2])
5  *
6  *	Copyright (c) 2013-2019 J. Schilling
7  */
8 /*
9  * The contents of this file are subject to the terms of the
10  * Common Development and Distribution License, Version 1.0 only
11  * (the "License").  You may not use this file except in compliance
12  * with the License.
13  *
14  * See the file CDDL.Schily.txt in this distribution for details.
15  * A copy of the CDDL is also available via the Internet at
16  * http://www.opensource.org/licenses/cddl1.txt
17  *
18  * When distributing Covered Code, include this CDDL HEADER in each
19  * file and include the License file CDDL.Schily.txt from this distribution.
20  */
21 
22 /*
23  * If we neither have utimensat() nor lutimes()/lutime(), we need to call
24  * lstat() and since this is not a predictable call, we always compile this
25  * module in largefile mode.
26  */
27 #define	USE_LARGEFILES
28 
29 #include <schily/unistd.h>
30 #include <schily/types.h>
31 #include <schily/time.h>
32 #include <schily/utime.h>
33 #include <schily/fcntl.h>
34 #include <schily/stat.h>
35 #include <schily/errno.h>
36 #include <schily/standard.h>
37 #include <schily/schily.h>
38 
39 #ifndef	HAVE_LUTIMENS
40 
41 #ifndef	HAVE_LSTAT
42 #define	lstat	stat
43 #endif
44 
45 EXPORT int
lutimens(name,times)46 lutimens(name, times)
47 	const char		*name;
48 	const struct timespec	times[2];
49 {
50 #ifdef	HAVE_UTIMENSAT
51 	return (utimensat(AT_FDCWD, name, times, AT_SYMLINK_NOFOLLOW));
52 #else
53 #ifdef	HAVE_LUTIMES
54 	struct timeval tv[2];
55 
56 	if (times == NULL)
57 		return (lutimes(name, NULL));
58 	tv[0].tv_sec  = times[0].tv_sec;
59 	tv[0].tv_usec = times[0].tv_nsec/1000;
60 	tv[1].tv_sec  = times[1].tv_sec;
61 	tv[1].tv_usec = times[1].tv_nsec/1000;
62 	return (lutimes(name, tv));
63 
64 #else
65 #ifdef	HAVE_LUTIME
66 	struct utimbuf	ut;
67 
68 	if (times == NULL)
69 		return (lutime(name, NULL));
70 	ut.actime = times[0].tv_sec;
71 	ut.modtime = times[1].tv_sec;
72 
73 	return (lutime(name, &ut));
74 #else
75 	/*
76 	 * Without lstat(), we expect that there are no symlinks either.
77 	 */
78 	struct stat	sb;
79 
80 	if (lstat(name, &sb) >= 0) {
81 		if (!S_ISLNK(sb.st_mode))
82 			return (utimens(name, times));
83 	} else {
84 		/*
85 		 * Keep errno (e.g. ENAMETOOLONG)
86 		 */
87 		return (-1);
88 	}
89 #ifdef	ENOSYS
90 	seterrno(ENOSYS);
91 #else
92 	seterrno(EINVAL);
93 #endif
94 	return (-1);
95 #endif
96 #endif
97 #endif
98 }
99 
100 #endif	/* HAVE_UTIMENS */
101