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 setattr_prepare(), 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 newattrs.ia_valid |= ATTR_TOUCH; 91 } 92 retry_deleg: 93 inode_lock(inode); 94 error = notify_change(path->dentry, &newattrs, &delegated_inode); 95 inode_unlock(inode); 96 if (delegated_inode) { 97 error = break_deleg_wait(&delegated_inode); 98 if (!error) 99 goto retry_deleg; 100 } 101 102 mnt_drop_write(path->mnt); 103 out: 104 return error; 105 } 106 107 /* 108 * do_utimes - change times on filename or file descriptor 109 * @dfd: open file descriptor, -1 or AT_FDCWD 110 * @filename: path name or NULL 111 * @times: new times or NULL 112 * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment) 113 * 114 * If filename is NULL and dfd refers to an open file, then operate on 115 * the file. Otherwise look up filename, possibly using dfd as a 116 * starting point. 117 * 118 * If times==NULL, set access and modification to current time, 119 * must be owner or have write permission. 120 * Else, update from *times, must be owner or super user. 121 */ 122 long do_utimes(int dfd, const char __user *filename, struct timespec *times, 123 int flags) 124 { 125 int error = -EINVAL; 126 127 if (times && (!nsec_valid(times[0].tv_nsec) || 128 !nsec_valid(times[1].tv_nsec))) { 129 goto out; 130 } 131 132 if (flags & ~AT_SYMLINK_NOFOLLOW) 133 goto out; 134 135 if (filename == NULL && dfd != AT_FDCWD) { 136 struct fd f; 137 138 if (flags & AT_SYMLINK_NOFOLLOW) 139 goto out; 140 141 f = fdget(dfd); 142 error = -EBADF; 143 if (!f.file) 144 goto out; 145 146 error = utimes_common(&f.file->f_path, times); 147 fdput(f); 148 } else { 149 struct path path; 150 int lookup_flags = 0; 151 152 if (!(flags & AT_SYMLINK_NOFOLLOW)) 153 lookup_flags |= LOOKUP_FOLLOW; 154 retry: 155 error = user_path_at(dfd, filename, lookup_flags, &path); 156 if (error) 157 goto out; 158 159 error = utimes_common(&path, times); 160 path_put(&path); 161 if (retry_estale(error, lookup_flags)) { 162 lookup_flags |= LOOKUP_REVAL; 163 goto retry; 164 } 165 } 166 167 out: 168 return error; 169 } 170 171 SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename, 172 struct timespec __user *, utimes, int, flags) 173 { 174 struct timespec tstimes[2]; 175 176 if (utimes) { 177 if (copy_from_user(&tstimes, utimes, sizeof(tstimes))) 178 return -EFAULT; 179 180 /* Nothing to do, we must not even check the path. */ 181 if (tstimes[0].tv_nsec == UTIME_OMIT && 182 tstimes[1].tv_nsec == UTIME_OMIT) 183 return 0; 184 } 185 186 return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); 187 } 188 189 SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename, 190 struct timeval __user *, utimes) 191 { 192 struct timeval times[2]; 193 struct timespec tstimes[2]; 194 195 if (utimes) { 196 if (copy_from_user(×, utimes, sizeof(times))) 197 return -EFAULT; 198 199 /* This test is needed to catch all invalid values. If we 200 would test only in do_utimes we would miss those invalid 201 values truncated by the multiplication with 1000. Note 202 that we also catch UTIME_{NOW,OMIT} here which are only 203 valid for utimensat. */ 204 if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 || 205 times[1].tv_usec >= 1000000 || times[1].tv_usec < 0) 206 return -EINVAL; 207 208 tstimes[0].tv_sec = times[0].tv_sec; 209 tstimes[0].tv_nsec = 1000 * times[0].tv_usec; 210 tstimes[1].tv_sec = times[1].tv_sec; 211 tstimes[1].tv_nsec = 1000 * times[1].tv_usec; 212 } 213 214 return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0); 215 } 216 217 SYSCALL_DEFINE2(utimes, char __user *, filename, 218 struct timeval __user *, utimes) 219 { 220 return sys_futimesat(AT_FDCWD, filename, utimes); 221 } 222