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
19int
20_utimes(const char* path, const struct timeval times[2], bool traverseLink);
21
22
23int
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(-1, 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
49int
50utimes(const char* path, const struct timeval times[2])
51{
52	return _utimes(path, times, true);
53}
54
55
56int
57utimensat(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
108int
109futimens(int fd, const struct timespec times[2])
110{
111	return utimensat(fd, NULL, times, 0);
112}
113