Blame view
fs/utimes.c
5.54 KB
82b0547cf [PATCH] Create fs... |
1 |
#include <linux/compiler.h> |
1c710c896 utimensat impleme... |
2 |
#include <linux/file.h> |
82b0547cf [PATCH] Create fs... |
3 4 |
#include <linux/fs.h> #include <linux/linkage.h> |
74f9fdfa1 [PATCH] r/o bind ... |
5 |
#include <linux/mount.h> |
82b0547cf [PATCH] Create fs... |
6 |
#include <linux/namei.h> |
914e26379 [PATCH] severing ... |
7 |
#include <linux/sched.h> |
1c710c896 utimensat impleme... |
8 |
#include <linux/stat.h> |
82b0547cf [PATCH] Create fs... |
9 |
#include <linux/utime.h> |
12c2ab5e8 fs/utimes.c shoul... |
10 |
#include <linux/syscalls.h> |
82b0547cf [PATCH] Create fs... |
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <asm/uaccess.h> #include <asm/unistd.h> #ifdef __ARCH_WANT_SYS_UTIME /* * sys_utime() can be implemented in user-level using sys_utimes(). * Is this for backwards compatibility? If so, why not move it * into the appropriate arch directory (for those architectures that * need it). */ /* If times==NULL, set access and modification to current time, * must be owner or have write permission. * Else, update from *times, must be owner or super user. */ |
003d7ab47 [CVE-2009-0029] S... |
27 |
SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times) |
82b0547cf [PATCH] Create fs... |
28 |
{ |
1c710c896 utimensat impleme... |
29 |
struct timespec tv[2]; |
82b0547cf [PATCH] Create fs... |
30 |
|
82b0547cf [PATCH] Create fs... |
31 |
if (times) { |
1c710c896 utimensat impleme... |
32 33 34 35 36 |
if (get_user(tv[0].tv_sec, ×->actime) || get_user(tv[1].tv_sec, ×->modtime)) return -EFAULT; tv[0].tv_nsec = 0; tv[1].tv_nsec = 0; |
82b0547cf [PATCH] Create fs... |
37 |
} |
1c710c896 utimensat impleme... |
38 |
return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0); |
82b0547cf [PATCH] Create fs... |
39 40 41 |
} #endif |
043f46f61 VFS: check nanose... |
42 43 |
static bool nsec_valid(long nsec) { |
4cca92264 [patch for 2.6.26... |
44 |
if (nsec == UTIME_OMIT || nsec == UTIME_NOW) |
043f46f61 VFS: check nanose... |
45 46 47 48 |
return true; return nsec >= 0 && nsec <= 999999999; } |
e9b76fedc [patch 2/4] vfs: ... |
49 |
static int utimes_common(struct path *path, struct timespec *times) |
82b0547cf [PATCH] Create fs... |
50 51 |
{ int error; |
82b0547cf [PATCH] Create fs... |
52 |
struct iattr newattrs; |
e9b76fedc [patch 2/4] vfs: ... |
53 |
struct inode *inode = path->dentry->d_inode; |
27ac0ffea locks: break dele... |
54 |
struct inode *delegated_inode = NULL; |
82b0547cf [PATCH] Create fs... |
55 |
|
e9b76fedc [patch 2/4] vfs: ... |
56 |
error = mnt_want_write(path->mnt); |
74f9fdfa1 [PATCH] r/o bind ... |
57 |
if (error) |
e9b76fedc [patch 2/4] vfs: ... |
58 |
goto out; |
82b0547cf [PATCH] Create fs... |
59 |
|
12fd0d308 [patch for 2.6.26... |
60 61 62 |
if (times && times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW) times = NULL; |
82b0547cf [PATCH] Create fs... |
63 64 |
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; if (times) { |
1c710c896 utimensat impleme... |
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
if (times[0].tv_nsec == UTIME_OMIT) newattrs.ia_valid &= ~ATTR_ATIME; else if (times[0].tv_nsec != UTIME_NOW) { newattrs.ia_atime.tv_sec = times[0].tv_sec; newattrs.ia_atime.tv_nsec = times[0].tv_nsec; newattrs.ia_valid |= ATTR_ATIME_SET; } if (times[1].tv_nsec == UTIME_OMIT) newattrs.ia_valid &= ~ATTR_MTIME; else if (times[1].tv_nsec != UTIME_NOW) { newattrs.ia_mtime.tv_sec = times[1].tv_sec; newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; newattrs.ia_valid |= ATTR_MTIME_SET; } |
4cca92264 [patch for 2.6.26... |
80 |
/* |
31051c85b fs: Give dentry t... |
81 |
* Tell setattr_prepare(), that this is an explicit time |
9767d7495 [patch 1/4] vfs: ... |
82 83 |
* update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET * were used. |
4cca92264 [patch for 2.6.26... |
84 |
*/ |
9767d7495 [patch 1/4] vfs: ... |
85 |
newattrs.ia_valid |= ATTR_TIMES_SET; |
4cca92264 [patch for 2.6.26... |
86 |
} else { |
f2b20f6ee vfs: move permiss... |
87 |
newattrs.ia_valid |= ATTR_TOUCH; |
82b0547cf [PATCH] Create fs... |
88 |
} |
27ac0ffea locks: break dele... |
89 |
retry_deleg: |
5955102c9 wrappers for ->i_... |
90 |
inode_lock(inode); |
27ac0ffea locks: break dele... |
91 |
error = notify_change(path->dentry, &newattrs, &delegated_inode); |
5955102c9 wrappers for ->i_... |
92 |
inode_unlock(inode); |
27ac0ffea locks: break dele... |
93 94 95 96 97 |
if (delegated_inode) { error = break_deleg_wait(&delegated_inode); if (!error) goto retry_deleg; } |
e9b76fedc [patch 2/4] vfs: ... |
98 |
|
e9b76fedc [patch 2/4] vfs: ... |
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
mnt_drop_write(path->mnt); out: return error; } /* * do_utimes - change times on filename or file descriptor * @dfd: open file descriptor, -1 or AT_FDCWD * @filename: path name or NULL * @times: new times or NULL * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment) * * If filename is NULL and dfd refers to an open file, then operate on * the file. Otherwise look up filename, possibly using dfd as a * starting point. * * If times==NULL, set access and modification to current time, * must be owner or have write permission. * Else, update from *times, must be owner or super user. */ |
c78873252 Mark arguments to... |
119 120 |
long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags) |
e9b76fedc [patch 2/4] vfs: ... |
121 122 123 124 125 126 127 128 129 130 131 132 |
{ int error = -EINVAL; if (times && (!nsec_valid(times[0].tv_nsec) || !nsec_valid(times[1].tv_nsec))) { goto out; } if (flags & ~AT_SYMLINK_NOFOLLOW) goto out; if (filename == NULL && dfd != AT_FDCWD) { |
2903ff019 switch simple cas... |
133 |
struct fd f; |
e9b76fedc [patch 2/4] vfs: ... |
134 135 136 |
if (flags & AT_SYMLINK_NOFOLLOW) goto out; |
2903ff019 switch simple cas... |
137 |
f = fdget(dfd); |
e9b76fedc [patch 2/4] vfs: ... |
138 |
error = -EBADF; |
2903ff019 switch simple cas... |
139 |
if (!f.file) |
e9b76fedc [patch 2/4] vfs: ... |
140 |
goto out; |
2903ff019 switch simple cas... |
141 142 |
error = utimes_common(&f.file->f_path, times); fdput(f); |
e9b76fedc [patch 2/4] vfs: ... |
143 |
} else { |
2d8f30380 [PATCH] sanitize ... |
144 |
struct path path; |
e9b76fedc [patch 2/4] vfs: ... |
145 146 147 148 |
int lookup_flags = 0; if (!(flags & AT_SYMLINK_NOFOLLOW)) lookup_flags |= LOOKUP_FOLLOW; |
a69201d6f vfs: allow utimen... |
149 |
retry: |
2d8f30380 [PATCH] sanitize ... |
150 |
error = user_path_at(dfd, filename, lookup_flags, &path); |
e9b76fedc [patch 2/4] vfs: ... |
151 152 |
if (error) goto out; |
2d8f30380 [PATCH] sanitize ... |
153 154 |
error = utimes_common(&path, times); path_put(&path); |
a69201d6f vfs: allow utimen... |
155 156 157 158 |
if (retry_estale(error, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; goto retry; } |
e9b76fedc [patch 2/4] vfs: ... |
159 |
} |
82b0547cf [PATCH] Create fs... |
160 161 162 |
out: return error; } |
c78873252 Mark arguments to... |
163 |
SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename, |
6559eed8c [CVE-2009-0029] S... |
164 |
struct timespec __user *, utimes, int, flags) |
1c710c896 utimensat impleme... |
165 166 167 168 169 170 |
{ struct timespec tstimes[2]; if (utimes) { if (copy_from_user(&tstimes, utimes, sizeof(tstimes))) return -EFAULT; |
1c710c896 utimensat impleme... |
171 172 173 174 175 176 177 178 179 |
/* Nothing to do, we must not even check the path. */ if (tstimes[0].tv_nsec == UTIME_OMIT && tstimes[1].tv_nsec == UTIME_OMIT) return 0; } return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); } |
c78873252 Mark arguments to... |
180 |
SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename, |
6559eed8c [CVE-2009-0029] S... |
181 |
struct timeval __user *, utimes) |
82b0547cf [PATCH] Create fs... |
182 183 |
{ struct timeval times[2]; |
1c710c896 utimensat impleme... |
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
struct timespec tstimes[2]; if (utimes) { if (copy_from_user(×, utimes, sizeof(times))) return -EFAULT; /* This test is needed to catch all invalid values. If we would test only in do_utimes we would miss those invalid values truncated by the multiplication with 1000. Note that we also catch UTIME_{NOW,OMIT} here which are only valid for utimensat. */ if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 || times[1].tv_usec >= 1000000 || times[1].tv_usec < 0) return -EINVAL; tstimes[0].tv_sec = times[0].tv_sec; tstimes[0].tv_nsec = 1000 * times[0].tv_usec; tstimes[1].tv_sec = times[1].tv_sec; tstimes[1].tv_nsec = 1000 * times[1].tv_usec; } |
82b0547cf [PATCH] Create fs... |
204 |
|
1c710c896 utimensat impleme... |
205 |
return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0); |
82b0547cf [PATCH] Create fs... |
206 |
} |
003d7ab47 [CVE-2009-0029] S... |
207 208 |
SYSCALL_DEFINE2(utimes, char __user *, filename, struct timeval __user *, utimes) |
82b0547cf [PATCH] Create fs... |
209 210 211 |
{ return sys_futimesat(AT_FDCWD, filename, utimes); } |