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 57 error = mnt_want_write(path->mnt); 58 if (error) 59 goto out; 60 61 if (times && times[0].tv_nsec == UTIME_NOW && 62 times[1].tv_nsec == UTIME_NOW) 63 times = NULL; 64 65 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; 66 if (times) { 67 if (times[0].tv_nsec == UTIME_OMIT) 68 newattrs.ia_valid &= ~ATTR_ATIME; 69 else if (times[0].tv_nsec != UTIME_NOW) { 70 newattrs.ia_atime.tv_sec = times[0].tv_sec; 71 newattrs.ia_atime.tv_nsec = times[0].tv_nsec; 72 newattrs.ia_valid |= ATTR_ATIME_SET; 73 } 74 75 if (times[1].tv_nsec == UTIME_OMIT) 76 newattrs.ia_valid &= ~ATTR_MTIME; 77 else if (times[1].tv_nsec != UTIME_NOW) { 78 newattrs.ia_mtime.tv_sec = times[1].tv_sec; 79 newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; 80 newattrs.ia_valid |= ATTR_MTIME_SET; 81 } 82 /* 83 * Tell inode_change_ok(), that this is an explicit time 84 * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET 85 * were used. 86 */ 87 newattrs.ia_valid |= ATTR_TIMES_SET; 88 } else { 89 /* 90 * If times is NULL (or both times are UTIME_NOW), 91 * then we need to check permissions, because 92 * inode_change_ok() won't do it. 93 */ 94 error = -EACCES; 95 if (IS_IMMUTABLE(inode)) 96 goto mnt_drop_write_and_out; 97 98 if (!inode_owner_or_capable(inode)) { 99 error = inode_permission(inode, MAY_WRITE); 100 if (error) 101 goto mnt_drop_write_and_out; 102 } 103 } 104 mutex_lock(&inode->i_mutex); 105 error = notify_change(path->dentry, &newattrs); 106 mutex_unlock(&inode->i_mutex); 107 108 mnt_drop_write_and_out: 109 mnt_drop_write(path->mnt); 110 out: 111 return error; 112 } 113 114 /* 115 * do_utimes - change times on filename or file descriptor 116 * @dfd: open file descriptor, -1 or AT_FDCWD 117 * @filename: path name or NULL 118 * @times: new times or NULL 119 * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment) 120 * 121 * If filename is NULL and dfd refers to an open file, then operate on 122 * the file. Otherwise look up filename, possibly using dfd as a 123 * starting point. 124 * 125 * If times==NULL, set access and modification to current time, 126 * must be owner or have write permission. 127 * Else, update from *times, must be owner or super user. 128 */ 129 long do_utimes(int dfd, const char __user *filename, struct timespec *times, 130 int flags) 131 { 132 int error = -EINVAL; 133 134 if (times && (!nsec_valid(times[0].tv_nsec) || 135 !nsec_valid(times[1].tv_nsec))) { 136 goto out; 137 } 138 139 if (flags & ~AT_SYMLINK_NOFOLLOW) 140 goto out; 141 142 if (filename == NULL && dfd != AT_FDCWD) { 143 int fput_needed; 144 struct file *file; 145 146 if (flags & AT_SYMLINK_NOFOLLOW) 147 goto out; 148 149 file = fget_light(dfd, &fput_needed); 150 error = -EBADF; 151 if (!file) 152 goto out; 153 154 error = utimes_common(&file->f_path, times); 155 fput_light(file, fput_needed); 156 } else { 157 struct path path; 158 int lookup_flags = 0; 159 160 if (!(flags & AT_SYMLINK_NOFOLLOW)) 161 lookup_flags |= LOOKUP_FOLLOW; 162 163 error = user_path_at(dfd, filename, lookup_flags, &path); 164 if (error) 165 goto out; 166 167 error = utimes_common(&path, times); 168 path_put(&path); 169 } 170 171 out: 172 return error; 173 } 174 175 SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename, 176 struct timespec __user *, utimes, int, flags) 177 { 178 struct timespec tstimes[2]; 179 180 if (utimes) { 181 if (copy_from_user(&tstimes, utimes, sizeof(tstimes))) 182 return -EFAULT; 183 184 /* Nothing to do, we must not even check the path. */ 185 if (tstimes[0].tv_nsec == UTIME_OMIT && 186 tstimes[1].tv_nsec == UTIME_OMIT) 187 return 0; 188 } 189 190 return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); 191 } 192 193 SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename, 194 struct timeval __user *, utimes) 195 { 196 struct timeval times[2]; 197 struct timespec tstimes[2]; 198 199 if (utimes) { 200 if (copy_from_user(×, utimes, sizeof(times))) 201 return -EFAULT; 202 203 /* This test is needed to catch all invalid values. If we 204 would test only in do_utimes we would miss those invalid 205 values truncated by the multiplication with 1000. Note 206 that we also catch UTIME_{NOW,OMIT} here which are only 207 valid for utimensat. */ 208 if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 || 209 times[1].tv_usec >= 1000000 || times[1].tv_usec < 0) 210 return -EINVAL; 211 212 tstimes[0].tv_sec = times[0].tv_sec; 213 tstimes[0].tv_nsec = 1000 * times[0].tv_usec; 214 tstimes[1].tv_sec = times[1].tv_sec; 215 tstimes[1].tv_nsec = 1000 * times[1].tv_usec; 216 } 217 218 return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0); 219 } 220 221 SYSCALL_DEFINE2(utimes, char __user *, filename, 222 struct timeval __user *, utimes) 223 { 224 return sys_futimesat(AT_FDCWD, filename, utimes); 225 } 226