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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>
Date: Thu, 27 Feb 2020 14:04:18 +0100
Subject: [PATCH] attr: handle symlinks correctly
Make sure to change the properties of the symlink and not the symlink
target. So use utimensat(), fchownat() and fchmodat() with
AT_SYMLINK_NOFOLLOW to set the relevant attributes.
This change breaks compilation on Windows.
Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
---
attr.c | 57 ++++++++++++++++++++++++++++++---------------------------
1 file changed, 30 insertions(+), 27 deletions(-)
diff --git a/attr.c b/attr.c
index 2653ed0a16bb..2a13441179a0 100644
--- a/attr.c
+++ b/attr.c
@@ -267,38 +267,41 @@ post_op_attr get_post_cached(struct svc_req * req)
/*
* 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(const char *path, sattr3 new)
{
- time_t new_atime, new_mtime;
- struct utimbuf utim;
- int res;
-
/* set atime and mtime */
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)
- new_atime = time(NULL);
- else if (new.atime.set_it == SET_TO_CLIENT_TIME)
- new_atime = new.atime.set_atime_u.atime.seconds;
- else /* DONT_CHANGE */
- new_atime = buf.st_atime;
+ 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 {
+ 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)
- new_mtime = time(NULL);
- else if (new.mtime.set_it == SET_TO_CLIENT_TIME)
- new_mtime = new.mtime.set_mtime_u.mtime.seconds;
- else /* DONT_CHANGE */
- new_mtime = buf.st_mtime;
-
- utim.actime = new_atime;
- utim.modtime = new_mtime;
+ 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 {
+ t[1].tv_sec = UTIME_OMIT;
+ t[1].tv_nsec = UTIME_OMIT;
+ }
- res = backend_utime(path, &utim);
+ res = utimensat(AT_FDCWD, path, t, AT_SYMLINK_NOFOLLOW);
if (res == -1)
return setattr_err();
}
@@ -346,19 +349,19 @@ static nfsstat3 set_attr_unsafe(const char *path, nfs_fh3 nfh, sattr3 new)
else
new_gid = -1;
- res = backend_lchown(path, new_uid, new_gid);
+ res = fchownat(AT_FDCWD, path, new_uid, new_gid, AT_SYMLINK_NOFOLLOW);
if (res == -1)
return setattr_err();
}
/* set mode */
if (new.mode.set_it == TRUE) {
- res = backend_chmod(path, new.mode.set_mode3_u.mode);
+ res = fchmodat(AT_FDCWD, path, new.mode.set_mode3_u.mode, 0);
if (res == -1)
return setattr_err();
}
- return set_time(path, buf, new);
+ return set_time(path, new);
}
/*
@@ -461,7 +464,7 @@ nfsstat3 set_attr(const char *path, nfs_fh3 nfh, sattr3 new)
}
/* finally, set times */
- return set_time(path, buf, new);
+ return set_time(path, new);
}
/*
|