1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
Date: Tue, 18 Feb 2020 15:20:12 +0100
Subject: [PATCH] attr: use futimens() instead of utime()
The former has two relevant advantages: It works on file descriptors
instead of a path name and it has nano second resolution (instead of only
seconds).
Note, I don't know about Windows which is probably broken by this commit
as I assume it doesn't support futimens().
---
attr.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 48 insertions(+), 5 deletions(-)
diff --git a/attr.c b/attr.c
index 2653ed0a16bb..08c9d24cb446 100644
--- a/attr.c
+++ b/attr.c
@@ -265,12 +265,51 @@ post_op_attr get_post_cached(struct svc_req * req)
return get_post_buf(st_cache, req);
}
+static nfsstat3 set_time(int fd, sattr3 new)
+{
+ if (new.atime.set_it != DONT_CHANGE || new.mtime.set_it != DONT_CHANGE) {
+
+ /* atime in t[0], mtime in t[1] */
+ struct timespec t[2];
+ int res;
+
+ /* compute atime to set */
+ if (new.atime.set_it == SET_TO_SERVER_TIME) {
+ t[0].tv_sec = UTIME_NOW;
+ t[0].tv_nsec = UTIME_NOW;
+ } else if (new.atime.set_it == SET_TO_CLIENT_TIME) {
+ t[0].tv_sec = new.atime.set_atime_u.atime.seconds;
+ t[0].tv_nsec = new.atime.set_atime_u.atime.nseconds;
+ } else { /* DONT_CHANGE */
+ t[0].tv_sec = UTIME_OMIT;
+ t[0].tv_nsec = UTIME_OMIT;
+ }
+
+ /* compute mtime to set */
+ if (new.mtime.set_it == SET_TO_SERVER_TIME) {
+ t[1].tv_sec = UTIME_NOW;
+ t[1].tv_nsec = UTIME_NOW;
+ } else if (new.mtime.set_it == SET_TO_CLIENT_TIME) {
+ t[1].tv_sec = new.mtime.set_mtime_u.mtime.seconds;
+ t[1].tv_nsec = new.mtime.set_mtime_u.mtime.nseconds;
+ } else { /* DONT_CHANGE */
+ t[1].tv_sec = UTIME_OMIT;
+ t[1].tv_nsec = UTIME_OMIT;
+ }
+
+ res = futimens(fd, &t);
+ if (res == -1)
+ return setattr_err();
+ }
+ return NFS3_OK;
+}
+
/*
* setting of time, races with local filesystem
*
* there is no futimes() function in POSIX or Linux
*/
-static nfsstat3 set_time(const char *path, backend_statstruct buf, sattr3 new)
+static nfsstat3 set_time_path(const char *path, backend_statstruct buf, sattr3 new)
{
time_t new_atime, new_mtime;
struct utimbuf utim;
@@ -358,7 +397,7 @@ static nfsstat3 set_attr_unsafe(const char *path, nfs_fh3 nfh, sattr3 new)
return setattr_err();
}
- return set_time(path, buf, new);
+ return set_time_path(path, buf, new);
}
/*
@@ -454,14 +493,18 @@ nfsstat3 set_attr(const char *path, nfs_fh3 nfh, sattr3 new)
}
}
+ /* finally, set times */
+ res = set_time(fd, new);
+ if (res != NFS3_OK) {
+ backend_close(fd);
+ return res;
+ }
+
res = backend_close(fd);
if (res == -1) {
/* error on close probably means attributes didn't make it */
return NFS3ERR_IO;
}
-
- /* finally, set times */
- return set_time(path, buf, new);
}
/*
|