hc
2024-05-10 9999e48639b3cecb08ffb37358bcba3b48161b29
kernel/fs/utimes.c
....@@ -8,35 +8,6 @@
88 #include <linux/compat.h>
99 #include <asm/unistd.h>
1010
11
-#ifdef __ARCH_WANT_SYS_UTIME
12
-
13
-/*
14
- * sys_utime() can be implemented in user-level using sys_utimes().
15
- * Is this for backwards compatibility? If so, why not move it
16
- * into the appropriate arch directory (for those architectures that
17
- * need it).
18
- */
19
-
20
-/* If times==NULL, set access and modification to current time,
21
- * must be owner or have write permission.
22
- * Else, update from *times, must be owner or super user.
23
- */
24
-SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times)
25
-{
26
- struct timespec64 tv[2];
27
-
28
- if (times) {
29
- if (get_user(tv[0].tv_sec, &times->actime) ||
30
- get_user(tv[1].tv_sec, &times->modtime))
31
- return -EFAULT;
32
- tv[0].tv_nsec = 0;
33
- tv[1].tv_nsec = 0;
34
- }
35
- return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0);
36
-}
37
-
38
-#endif
39
-
4011 static bool nsec_valid(long nsec)
4112 {
4213 if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
....@@ -45,36 +16,39 @@
4516 return nsec >= 0 && nsec <= 999999999;
4617 }
4718
48
-static int utimes_common(const struct path *path, struct timespec64 *times)
19
+int vfs_utimes(const struct path *path, struct timespec64 *times)
4920 {
5021 int error;
5122 struct iattr newattrs;
5223 struct inode *inode = path->dentry->d_inode;
5324 struct inode *delegated_inode = NULL;
5425
26
+ if (times) {
27
+ if (!nsec_valid(times[0].tv_nsec) ||
28
+ !nsec_valid(times[1].tv_nsec))
29
+ return -EINVAL;
30
+ if (times[0].tv_nsec == UTIME_NOW &&
31
+ times[1].tv_nsec == UTIME_NOW)
32
+ times = NULL;
33
+ }
34
+
5535 error = mnt_want_write(path->mnt);
5636 if (error)
5737 goto out;
58
-
59
- if (times && times[0].tv_nsec == UTIME_NOW &&
60
- times[1].tv_nsec == UTIME_NOW)
61
- times = NULL;
6238
6339 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
6440 if (times) {
6541 if (times[0].tv_nsec == UTIME_OMIT)
6642 newattrs.ia_valid &= ~ATTR_ATIME;
6743 else if (times[0].tv_nsec != UTIME_NOW) {
68
- newattrs.ia_atime.tv_sec = times[0].tv_sec;
69
- newattrs.ia_atime.tv_nsec = times[0].tv_nsec;
44
+ newattrs.ia_atime = times[0];
7045 newattrs.ia_valid |= ATTR_ATIME_SET;
7146 }
7247
7348 if (times[1].tv_nsec == UTIME_OMIT)
7449 newattrs.ia_valid &= ~ATTR_MTIME;
7550 else if (times[1].tv_nsec != UTIME_NOW) {
76
- newattrs.ia_mtime.tv_sec = times[1].tv_sec;
77
- newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
51
+ newattrs.ia_mtime = times[1];
7852 newattrs.ia_valid |= ATTR_MTIME_SET;
7953 }
8054 /*
....@@ -88,7 +62,7 @@
8862 }
8963 retry_deleg:
9064 inode_lock(inode);
91
- error = notify_change2(path->mnt, path->dentry, &newattrs, &delegated_inode);
65
+ error = notify_change(path->dentry, &newattrs, &delegated_inode);
9266 inode_unlock(inode);
9367 if (delegated_inode) {
9468 error = break_deleg_wait(&delegated_inode);
....@@ -98,6 +72,51 @@
9872
9973 mnt_drop_write(path->mnt);
10074 out:
75
+ return error;
76
+}
77
+
78
+static int do_utimes_path(int dfd, const char __user *filename,
79
+ struct timespec64 *times, int flags)
80
+{
81
+ struct path path;
82
+ int lookup_flags = 0, error;
83
+
84
+ if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
85
+ return -EINVAL;
86
+
87
+ if (!(flags & AT_SYMLINK_NOFOLLOW))
88
+ lookup_flags |= LOOKUP_FOLLOW;
89
+ if (flags & AT_EMPTY_PATH)
90
+ lookup_flags |= LOOKUP_EMPTY;
91
+
92
+retry:
93
+ error = user_path_at(dfd, filename, lookup_flags, &path);
94
+ if (error)
95
+ return error;
96
+
97
+ error = vfs_utimes(&path, times);
98
+ path_put(&path);
99
+ if (retry_estale(error, lookup_flags)) {
100
+ lookup_flags |= LOOKUP_REVAL;
101
+ goto retry;
102
+ }
103
+
104
+ return error;
105
+}
106
+
107
+static int do_utimes_fd(int fd, struct timespec64 *times, int flags)
108
+{
109
+ struct fd f;
110
+ int error;
111
+
112
+ if (flags)
113
+ return -EINVAL;
114
+
115
+ f = fdget(fd);
116
+ if (!f.file)
117
+ return -EBADF;
118
+ error = vfs_utimes(&f.file->f_path, times);
119
+ fdput(f);
101120 return error;
102121 }
103122
....@@ -119,54 +138,13 @@
119138 long do_utimes(int dfd, const char __user *filename, struct timespec64 *times,
120139 int flags)
121140 {
122
- int error = -EINVAL;
123
-
124
- if (times && (!nsec_valid(times[0].tv_nsec) ||
125
- !nsec_valid(times[1].tv_nsec))) {
126
- goto out;
127
- }
128
-
129
- if (flags & ~AT_SYMLINK_NOFOLLOW)
130
- goto out;
131
-
132
- if (filename == NULL && dfd != AT_FDCWD) {
133
- struct fd f;
134
-
135
- if (flags & AT_SYMLINK_NOFOLLOW)
136
- goto out;
137
-
138
- f = fdget(dfd);
139
- error = -EBADF;
140
- if (!f.file)
141
- goto out;
142
-
143
- error = utimes_common(&f.file->f_path, times);
144
- fdput(f);
145
- } else {
146
- struct path path;
147
- int lookup_flags = 0;
148
-
149
- if (!(flags & AT_SYMLINK_NOFOLLOW))
150
- lookup_flags |= LOOKUP_FOLLOW;
151
-retry:
152
- error = user_path_at(dfd, filename, lookup_flags, &path);
153
- if (error)
154
- goto out;
155
-
156
- error = utimes_common(&path, times);
157
- path_put(&path);
158
- if (retry_estale(error, lookup_flags)) {
159
- lookup_flags |= LOOKUP_REVAL;
160
- goto retry;
161
- }
162
- }
163
-
164
-out:
165
- return error;
141
+ if (filename == NULL && dfd != AT_FDCWD)
142
+ return do_utimes_fd(dfd, times, flags);
143
+ return do_utimes_path(dfd, filename, times, flags);
166144 }
167145
168146 SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename,
169
- struct timespec __user *, utimes, int, flags)
147
+ struct __kernel_timespec __user *, utimes, int, flags)
170148 {
171149 struct timespec64 tstimes[2];
172150
....@@ -184,10 +162,17 @@
184162 return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags);
185163 }
186164
165
+#ifdef __ARCH_WANT_SYS_UTIME
166
+/*
167
+ * futimesat(), utimes() and utime() are older versions of utimensat()
168
+ * that are provided for compatibility with traditional C libraries.
169
+ * On modern architectures, we always use libc wrappers around
170
+ * utimensat() instead.
171
+ */
187172 static long do_futimesat(int dfd, const char __user *filename,
188
- struct timeval __user *utimes)
173
+ struct __kernel_old_timeval __user *utimes)
189174 {
190
- struct timeval times[2];
175
+ struct __kernel_old_timeval times[2];
191176 struct timespec64 tstimes[2];
192177
193178 if (utimes) {
....@@ -214,24 +199,40 @@
214199
215200
216201 SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename,
217
- struct timeval __user *, utimes)
202
+ struct __kernel_old_timeval __user *, utimes)
218203 {
219204 return do_futimesat(dfd, filename, utimes);
220205 }
221206
222207 SYSCALL_DEFINE2(utimes, char __user *, filename,
223
- struct timeval __user *, utimes)
208
+ struct __kernel_old_timeval __user *, utimes)
224209 {
225210 return do_futimesat(AT_FDCWD, filename, utimes);
226211 }
227212
228
-#ifdef CONFIG_COMPAT
213
+SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times)
214
+{
215
+ struct timespec64 tv[2];
216
+
217
+ if (times) {
218
+ if (get_user(tv[0].tv_sec, &times->actime) ||
219
+ get_user(tv[1].tv_sec, &times->modtime))
220
+ return -EFAULT;
221
+ tv[0].tv_nsec = 0;
222
+ tv[1].tv_nsec = 0;
223
+ }
224
+ return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0);
225
+}
226
+#endif
227
+
228
+#ifdef CONFIG_COMPAT_32BIT_TIME
229229 /*
230230 * Not all architectures have sys_utime, so implement this in terms
231231 * of sys_utimes.
232232 */
233
-COMPAT_SYSCALL_DEFINE2(utime, const char __user *, filename,
234
- struct compat_utimbuf __user *, t)
233
+#ifdef __ARCH_WANT_SYS_UTIME32
234
+SYSCALL_DEFINE2(utime32, const char __user *, filename,
235
+ struct old_utimbuf32 __user *, t)
235236 {
236237 struct timespec64 tv[2];
237238
....@@ -244,14 +245,15 @@
244245 }
245246 return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
246247 }
248
+#endif
247249
248
-COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filename, struct compat_timespec __user *, t, int, flags)
250
+SYSCALL_DEFINE4(utimensat_time32, unsigned int, dfd, const char __user *, filename, struct old_timespec32 __user *, t, int, flags)
249251 {
250252 struct timespec64 tv[2];
251253
252254 if (t) {
253
- if (compat_get_timespec64(&tv[0], &t[0]) ||
254
- compat_get_timespec64(&tv[1], &t[1]))
255
+ if (get_old_timespec32(&tv[0], &t[0]) ||
256
+ get_old_timespec32(&tv[1], &t[1]))
255257 return -EFAULT;
256258
257259 if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
....@@ -260,8 +262,9 @@
260262 return do_utimes(dfd, filename, t ? tv : NULL, flags);
261263 }
262264
265
+#ifdef __ARCH_WANT_SYS_UTIME32
263266 static long do_compat_futimesat(unsigned int dfd, const char __user *filename,
264
- struct compat_timeval __user *t)
267
+ struct old_timeval32 __user *t)
265268 {
266269 struct timespec64 tv[2];
267270
....@@ -280,15 +283,16 @@
280283 return do_utimes(dfd, filename, t ? tv : NULL, 0);
281284 }
282285
283
-COMPAT_SYSCALL_DEFINE3(futimesat, unsigned int, dfd,
286
+SYSCALL_DEFINE3(futimesat_time32, unsigned int, dfd,
284287 const char __user *, filename,
285
- struct compat_timeval __user *, t)
288
+ struct old_timeval32 __user *, t)
286289 {
287290 return do_compat_futimesat(dfd, filename, t);
288291 }
289292
290
-COMPAT_SYSCALL_DEFINE2(utimes, const char __user *, filename, struct compat_timeval __user *, t)
293
+SYSCALL_DEFINE2(utimes_time32, const char __user *, filename, struct old_timeval32 __user *, t)
291294 {
292295 return do_compat_futimesat(AT_FDCWD, filename, t);
293296 }
294297 #endif
298
+#endif