xref: /haiku/src/system/libroot/posix/sys/utimes.c (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2006-2009, Axel Dörfler, axeld@pinc-software.de.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include <sys/time.h>
9 
10 #include <errno.h>
11 
12 #include <NodeMonitor.h>
13 
14 #include <errno_private.h>
15 #include <syscalls.h>
16 #include <syscall_utils.h>
17 
18 
19 int
20 _utimes(const char* path, const struct timeval times[2], bool traverseLink);
21 
22 
23 int
24 _utimes(const char* path, const struct timeval times[2], bool traverseLink)
25 {
26 	struct stat stat;
27 	status_t status;
28 
29 	if (times != NULL) {
30 		stat.st_atim.tv_sec = times[0].tv_sec;
31 		stat.st_atim.tv_nsec = times[0].tv_usec * 1000;
32 
33 		stat.st_mtim.tv_sec = times[1].tv_sec;
34 		stat.st_mtim.tv_nsec = times[1].tv_usec * 1000;
35 	} else {
36 		bigtime_t now = real_time_clock_usecs();
37 		stat.st_atim.tv_sec = stat.st_mtim.tv_sec = now / 1000000;
38 		stat.st_atim.tv_nsec = stat.st_mtim.tv_nsec = (now % 1000000) * 1000;
39 	}
40 
41 	// traverseLeafLink == true
42 	status = _kern_write_stat(AT_FDCWD, path, traverseLink, &stat,
43 		sizeof(struct stat), B_STAT_MODIFICATION_TIME | B_STAT_ACCESS_TIME);
44 
45 	RETURN_AND_SET_ERRNO(status);
46 }
47 
48 
49 int
50 utimes(const char* path, const struct timeval times[2])
51 {
52 	return _utimes(path, times, true);
53 }
54 
55 
56 int
57 utimensat(int fd, const char *path, const struct timespec times[2], int flag)
58 {
59 	struct stat stat;
60 	status_t status;
61 	uint32 mask = 0;
62 
63 	// Init the stat time fields to the current time, if at least one time is
64 	// supposed to be set to it.
65 	if (times == NULL || times[0].tv_nsec == UTIME_NOW
66 		|| times[1].tv_nsec == UTIME_NOW) {
67 		bigtime_t now = real_time_clock_usecs();
68 		stat.st_atim.tv_sec = stat.st_mtim.tv_sec = now / 1000000;
69 		stat.st_atim.tv_nsec = stat.st_mtim.tv_nsec = (now % 1000000) * 1000;
70 	}
71 
72 	if (times != NULL) {
73 		// access time
74 		if (times[0].tv_nsec != UTIME_OMIT) {
75 			mask |= B_STAT_ACCESS_TIME;
76 
77 			if (times[0].tv_nsec != UTIME_NOW) {
78 				if (times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999)
79 					RETURN_AND_SET_ERRNO(EINVAL);
80 			}
81 
82 			stat.st_atim = times[0];
83 		}
84 
85 		// modified time
86 		if (times[1].tv_nsec != UTIME_OMIT) {
87 			mask |= B_STAT_MODIFICATION_TIME;
88 
89 			if (times[1].tv_nsec != UTIME_NOW) {
90 				if (times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999)
91 					RETURN_AND_SET_ERRNO(EINVAL);
92 			}
93 
94 			stat.st_mtim = times[1];
95 		}
96 	} else
97 		mask |= B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME;
98 
99 	// set the times -- as per spec we even need to do this, if both have
100 	// UTIME_OMIT set
101 	status = _kern_write_stat(fd, path, (flag & AT_SYMLINK_NOFOLLOW) == 0,
102 		&stat, sizeof(struct stat), mask);
103 
104 	RETURN_AND_SET_ERRNO(status);
105 }
106 
107 
108 int
109 futimens(int fd, const struct timespec times[2])
110 {
111 	return utimensat(fd, NULL, times, 0);
112 }
113