1 #include <linux/file.h> 2 #include <linux/mount.h> 3 #include <linux/namei.h> 4 #include <linux/utime.h> 5 #include <linux/syscalls.h> 6 #include <linux/uaccess.h> 7 #include <linux/compat.h> 8 #include <asm/unistd.h> 9 10 #ifdef __ARCH_WANT_SYS_UTIME 11 12 /* 13 * sys_utime() can be implemented in user-level using sys_utimes(). 14 * Is this for backwards compatibility? If so, why not move it 15 * into the appropriate arch directory (for those architectures that 16 * need it). 17 */ 18 19 /* If times==NULL, set access and modification to current time, 20 * must be owner or have write permission. 21 * Else, update from *times, must be owner or super user. 22 */ 23 SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times) 24 { 25 struct timespec tv[2]; 26 27 if (times) { 28 if (get_user(tv[0].tv_sec, ×->actime) || 29 get_user(tv[1].tv_sec, ×->modtime)) 30 return -EFAULT; 31 tv[0].tv_nsec = 0; 32 tv[1].tv_nsec = 0; 33 } 34 return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0); 35 } 36 37 #endif 38 39 static bool nsec_valid(long nsec) 40 { 41 if (nsec == UTIME_OMIT || nsec == UTIME_NOW) 42 return true; 43 44 return nsec >= 0 && nsec <= 999999999; 45 } 46 47 static int utimes_common(const struct path *path, struct timespec *times) 48 { 49 int error; 50 struct iattr newattrs; 51 struct inode *inode = path->dentry->d_inode; 52 struct inode *delegated_inode = NULL; 53 54 error = mnt_want_write(path->mnt); 55 if (error) 56 goto out; 57 58 if (times && times[0].tv_nsec == UTIME_NOW && 59 times[1].tv_nsec == UTIME_NOW) 60 times = NULL; 61 62 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; 63 if (times) { 64 if (times[0].tv_nsec == UTIME_OMIT) 65 newattrs.ia_valid &= ~ATTR_ATIME; 66 else if (times[0].tv_nsec != UTIME_NOW) { 67 newattrs.ia_atime.tv_sec = times[0].tv_sec; 68 newattrs.ia_atime.tv_nsec = times[0].tv_nsec; 69 newattrs.ia_valid |= ATTR_ATIME_SET; 70 } 71 72 if (times[1].tv_nsec == UTIME_OMIT) 73 newattrs.ia_valid &= ~ATTR_MTIME; 74 else if (times[1].tv_nsec != UTIME_NOW) { 75 newattrs.ia_mtime.tv_sec = times[1].tv_sec; 76 newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; 77 newattrs.ia_valid |= ATTR_MTIME_SET; 78 } 79 /* 80 * Tell setattr_prepare(), that this is an explicit time 81 * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET 82 * were used. 83 */ 84 newattrs.ia_valid |= ATTR_TIMES_SET; 85 } else { 86 newattrs.ia_valid |= ATTR_TOUCH; 87 } 88 retry_deleg: 89 inode_lock(inode); 90 error = notify_change(path->dentry, &newattrs, &delegated_inode); 91 inode_unlock(inode); 92 if (delegated_inode) { 93 error = break_deleg_wait(&delegated_inode); 94 if (!error) 95 goto retry_deleg; 96 } 97 98 mnt_drop_write(path->mnt); 99 out: 100 return error; 101 } 102 103 /* 104 * do_utimes - change times on filename or file descriptor 105 * @dfd: open file descriptor, -1 or AT_FDCWD 106 * @filename: path name or NULL 107 * @times: new times or NULL 108 * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment) 109 * 110 * If filename is NULL and dfd refers to an open file, then operate on 111 * the file. Otherwise look up filename, possibly using dfd as a 112 * starting point. 113 * 114 * If times==NULL, set access and modification to current time, 115 * must be owner or have write permission. 116 * Else, update from *times, must be owner or super user. 117 */ 118 long do_utimes(int dfd, const char __user *filename, struct timespec *times, 119 int flags) 120 { 121 int error = -EINVAL; 122 123 if (times && (!nsec_valid(times[0].tv_nsec) || 124 !nsec_valid(times[1].tv_nsec))) { 125 goto out; 126 } 127 128 if (flags & ~AT_SYMLINK_NOFOLLOW) 129 goto out; 130 131 if (filename == NULL && dfd != AT_FDCWD) { 132 struct fd f; 133 134 if (flags & AT_SYMLINK_NOFOLLOW) 135 goto out; 136 137 f = fdget(dfd); 138 error = -EBADF; 139 if (!f.file) 140 goto out; 141 142 error = utimes_common(&f.file->f_path, times); 143 fdput(f); 144 } else { 145 struct path path; 146 int lookup_flags = 0; 147 148 if (!(flags & AT_SYMLINK_NOFOLLOW)) 149 lookup_flags |= LOOKUP_FOLLOW; 150 retry: 151 error = user_path_at(dfd, filename, lookup_flags, &path); 152 if (error) 153 goto out; 154 155 error = utimes_common(&path, times); 156 path_put(&path); 157 if (retry_estale(error, lookup_flags)) { 158 lookup_flags |= LOOKUP_REVAL; 159 goto retry; 160 } 161 } 162 163 out: 164 return error; 165 } 166 167 SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename, 168 struct timespec __user *, utimes, int, flags) 169 { 170 struct timespec tstimes[2]; 171 172 if (utimes) { 173 if (copy_from_user(&tstimes, utimes, sizeof(tstimes))) 174 return -EFAULT; 175 176 /* Nothing to do, we must not even check the path. */ 177 if (tstimes[0].tv_nsec == UTIME_OMIT && 178 tstimes[1].tv_nsec == UTIME_OMIT) 179 return 0; 180 } 181 182 return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); 183 } 184 185 SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename, 186 struct timeval __user *, utimes) 187 { 188 struct timeval times[2]; 189 struct timespec tstimes[2]; 190 191 if (utimes) { 192 if (copy_from_user(×, utimes, sizeof(times))) 193 return -EFAULT; 194 195 /* This test is needed to catch all invalid values. If we 196 would test only in do_utimes we would miss those invalid 197 values truncated by the multiplication with 1000. Note 198 that we also catch UTIME_{NOW,OMIT} here which are only 199 valid for utimensat. */ 200 if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 || 201 times[1].tv_usec >= 1000000 || times[1].tv_usec < 0) 202 return -EINVAL; 203 204 tstimes[0].tv_sec = times[0].tv_sec; 205 tstimes[0].tv_nsec = 1000 * times[0].tv_usec; 206 tstimes[1].tv_sec = times[1].tv_sec; 207 tstimes[1].tv_nsec = 1000 * times[1].tv_usec; 208 } 209 210 return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0); 211 } 212 213 SYSCALL_DEFINE2(utimes, char __user *, filename, 214 struct timeval __user *, utimes) 215 { 216 return sys_futimesat(AT_FDCWD, filename, utimes); 217 } 218 219 #ifdef CONFIG_COMPAT 220 /* 221 * Not all architectures have sys_utime, so implement this in terms 222 * of sys_utimes. 223 */ 224 COMPAT_SYSCALL_DEFINE2(utime, const char __user *, filename, 225 struct compat_utimbuf __user *, t) 226 { 227 struct timespec tv[2]; 228 229 if (t) { 230 if (get_user(tv[0].tv_sec, &t->actime) || 231 get_user(tv[1].tv_sec, &t->modtime)) 232 return -EFAULT; 233 tv[0].tv_nsec = 0; 234 tv[1].tv_nsec = 0; 235 } 236 return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0); 237 } 238 239 COMPAT_SYSCALL_DEFINE4(utimensat, unsigned int, dfd, const char __user *, filename, struct compat_timespec __user *, t, int, flags) 240 { 241 struct timespec tv[2]; 242 243 if (t) { 244 if (compat_get_timespec(&tv[0], &t[0]) || 245 compat_get_timespec(&tv[1], &t[1])) 246 return -EFAULT; 247 248 if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT) 249 return 0; 250 } 251 return do_utimes(dfd, filename, t ? tv : NULL, flags); 252 } 253 254 COMPAT_SYSCALL_DEFINE3(futimesat, unsigned int, dfd, const char __user *, filename, struct compat_timeval __user *, t) 255 { 256 struct timespec tv[2]; 257 258 if (t) { 259 if (get_user(tv[0].tv_sec, &t[0].tv_sec) || 260 get_user(tv[0].tv_nsec, &t[0].tv_usec) || 261 get_user(tv[1].tv_sec, &t[1].tv_sec) || 262 get_user(tv[1].tv_nsec, &t[1].tv_usec)) 263 return -EFAULT; 264 if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 || 265 tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0) 266 return -EINVAL; 267 tv[0].tv_nsec *= 1000; 268 tv[1].tv_nsec *= 1000; 269 } 270 return do_utimes(dfd, filename, t ? tv : NULL, 0); 271 } 272 273 COMPAT_SYSCALL_DEFINE2(utimes, const char __user *, filename, struct compat_timeval __user *, t) 274 { 275 return compat_sys_futimesat(AT_FDCWD, filename, t); 276 } 277 #endif 278