summaryrefslogtreecommitdiffstats
path: root/patches/unfs3-0.9.22/0005-attr-use-futimens-instead-of-utime.patch
blob: 36f69e44b81ac72ef99c38a2785a1ce3a318d105 (plain)
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);
 }
 
 /*