1 #include <linux/compiler.h> 2 #include <linux/fs.h> 3 #include <linux/linkage.h> 4 #include <linux/namei.h> 5 #include <linux/sched.h> 6 #include <linux/utime.h> 7 #include <asm/uaccess.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 asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times) 24 { 25 int error; 26 struct nameidata nd; 27 struct inode * inode; 28 struct iattr newattrs; 29 30 error = user_path_walk(filename, &nd); 31 if (error) 32 goto out; 33 inode = nd.dentry->d_inode; 34 35 error = -EROFS; 36 if (IS_RDONLY(inode)) 37 goto dput_and_out; 38 39 /* Don't worry, the checks are done in inode_change_ok() */ 40 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; 41 if (times) { 42 error = -EPERM; 43 if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) 44 goto dput_and_out; 45 46 error = get_user(newattrs.ia_atime.tv_sec, ×->actime); 47 newattrs.ia_atime.tv_nsec = 0; 48 if (!error) 49 error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime); 50 newattrs.ia_mtime.tv_nsec = 0; 51 if (error) 52 goto dput_and_out; 53 54 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; 55 } else { 56 error = -EACCES; 57 if (IS_IMMUTABLE(inode)) 58 goto dput_and_out; 59 60 if (current->fsuid != inode->i_uid && 61 (error = vfs_permission(&nd, MAY_WRITE)) != 0) 62 goto dput_and_out; 63 } 64 mutex_lock(&inode->i_mutex); 65 error = notify_change(nd.dentry, &newattrs); 66 mutex_unlock(&inode->i_mutex); 67 dput_and_out: 68 path_release(&nd); 69 out: 70 return error; 71 } 72 73 #endif 74 75 /* If times==NULL, set access and modification to current time, 76 * must be owner or have write permission. 77 * Else, update from *times, must be owner or super user. 78 */ 79 long do_utimes(int dfd, char __user *filename, struct timeval *times) 80 { 81 int error; 82 struct nameidata nd; 83 struct inode * inode; 84 struct iattr newattrs; 85 86 error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); 87 88 if (error) 89 goto out; 90 inode = nd.dentry->d_inode; 91 92 error = -EROFS; 93 if (IS_RDONLY(inode)) 94 goto dput_and_out; 95 96 /* Don't worry, the checks are done in inode_change_ok() */ 97 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; 98 if (times) { 99 error = -EPERM; 100 if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) 101 goto dput_and_out; 102 103 newattrs.ia_atime.tv_sec = times[0].tv_sec; 104 newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000; 105 newattrs.ia_mtime.tv_sec = times[1].tv_sec; 106 newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000; 107 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; 108 } else { 109 error = -EACCES; 110 if (IS_IMMUTABLE(inode)) 111 goto dput_and_out; 112 113 if (current->fsuid != inode->i_uid && 114 (error = vfs_permission(&nd, MAY_WRITE)) != 0) 115 goto dput_and_out; 116 } 117 mutex_lock(&inode->i_mutex); 118 error = notify_change(nd.dentry, &newattrs); 119 mutex_unlock(&inode->i_mutex); 120 dput_and_out: 121 path_release(&nd); 122 out: 123 return error; 124 } 125 126 asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes) 127 { 128 struct timeval times[2]; 129 130 if (utimes && copy_from_user(×, utimes, sizeof(times))) 131 return -EFAULT; 132 return do_utimes(dfd, filename, utimes ? times : NULL); 133 } 134 135 asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes) 136 { 137 return sys_futimesat(AT_FDCWD, filename, utimes); 138 } 139