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