aboutsummaryrefslogtreecommitdiffstats
path: root/fs/utimes.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/utimes.c')
-rw-r--r--fs/utimes.c139
1 files changed, 71 insertions, 68 deletions
diff --git a/fs/utimes.c b/fs/utimes.c
index b6b664e7145e..6929e3e91d05 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -48,66 +48,22 @@ static bool nsec_valid(long nsec)
48 return nsec >= 0 && nsec <= 999999999; 48 return nsec >= 0 && nsec <= 999999999;
49} 49}
50 50
51/* If times==NULL, set access and modification to current time, 51static int utimes_common(struct path *path, struct timespec *times)
52 * must be owner or have write permission.
53 * Else, update from *times, must be owner or super user.
54 */
55long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags)
56{ 52{
57 int error; 53 int error;
58 struct nameidata nd;
59 struct dentry *dentry;
60 struct inode *inode;
61 struct iattr newattrs; 54 struct iattr newattrs;
62 struct file *f = NULL; 55 struct inode *inode = path->dentry->d_inode;
63 struct vfsmount *mnt;
64
65 error = -EINVAL;
66 if (times && (!nsec_valid(times[0].tv_nsec) ||
67 !nsec_valid(times[1].tv_nsec))) {
68 goto out;
69 }
70
71 if (flags & ~AT_SYMLINK_NOFOLLOW)
72 goto out;
73
74 if (filename == NULL && dfd != AT_FDCWD) {
75 error = -EINVAL;
76 if (flags & AT_SYMLINK_NOFOLLOW)
77 goto out;
78 56
79 error = -EBADF; 57 error = mnt_want_write(path->mnt);
80 f = fget(dfd);
81 if (!f)
82 goto out;
83 dentry = f->f_path.dentry;
84 mnt = f->f_path.mnt;
85 } else {
86 error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd);
87 if (error)
88 goto out;
89
90 dentry = nd.path.dentry;
91 mnt = nd.path.mnt;
92 }
93
94 inode = dentry->d_inode;
95
96 error = mnt_want_write(mnt);
97 if (error) 58 if (error)
98 goto dput_and_out; 59 goto out;
99 60
100 if (times && times[0].tv_nsec == UTIME_NOW && 61 if (times && times[0].tv_nsec == UTIME_NOW &&
101 times[1].tv_nsec == UTIME_NOW) 62 times[1].tv_nsec == UTIME_NOW)
102 times = NULL; 63 times = NULL;
103 64
104 /* In most cases, the checks are done in inode_change_ok() */
105 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; 65 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
106 if (times) { 66 if (times) {
107 error = -EPERM;
108 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
109 goto mnt_drop_write_and_out;
110
111 if (times[0].tv_nsec == UTIME_OMIT) 67 if (times[0].tv_nsec == UTIME_OMIT)
112 newattrs.ia_valid &= ~ATTR_ATIME; 68 newattrs.ia_valid &= ~ATTR_ATIME;
113 else if (times[0].tv_nsec != UTIME_NOW) { 69 else if (times[0].tv_nsec != UTIME_NOW) {
@@ -123,21 +79,13 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
123 newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; 79 newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
124 newattrs.ia_valid |= ATTR_MTIME_SET; 80 newattrs.ia_valid |= ATTR_MTIME_SET;
125 } 81 }
126
127 /* 82 /*
128 * For the UTIME_OMIT/UTIME_NOW and UTIME_NOW/UTIME_OMIT 83 * Tell inode_change_ok(), that this is an explicit time
129 * cases, we need to make an extra check that is not done by 84 * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
130 * inode_change_ok(). 85 * were used.
131 */ 86 */
132 if (((times[0].tv_nsec == UTIME_NOW && 87 newattrs.ia_valid |= ATTR_TIMES_SET;
133 times[1].tv_nsec == UTIME_OMIT)
134 ||
135 (times[0].tv_nsec == UTIME_OMIT &&
136 times[1].tv_nsec == UTIME_NOW))
137 && !is_owner_or_cap(inode))
138 goto mnt_drop_write_and_out;
139 } else { 88 } else {
140
141 /* 89 /*
142 * If times is NULL (or both times are UTIME_NOW), 90 * If times is NULL (or both times are UTIME_NOW),
143 * then we need to check permissions, because 91 * then we need to check permissions, because
@@ -148,21 +96,76 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
148 goto mnt_drop_write_and_out; 96 goto mnt_drop_write_and_out;
149 97
150 if (!is_owner_or_cap(inode)) { 98 if (!is_owner_or_cap(inode)) {
151 error = permission(inode, MAY_WRITE, NULL); 99 error = inode_permission(inode, MAY_WRITE);
152 if (error) 100 if (error)
153 goto mnt_drop_write_and_out; 101 goto mnt_drop_write_and_out;
154 } 102 }
155 } 103 }
156 mutex_lock(&inode->i_mutex); 104 mutex_lock(&inode->i_mutex);
157 error = notify_change(dentry, &newattrs); 105 error = notify_change(path->dentry, &newattrs);
158 mutex_unlock(&inode->i_mutex); 106 mutex_unlock(&inode->i_mutex);
107
159mnt_drop_write_and_out: 108mnt_drop_write_and_out:
160 mnt_drop_write(mnt); 109 mnt_drop_write(path->mnt);
161dput_and_out: 110out:
162 if (f) 111 return error;
163 fput(f); 112}
164 else 113
165 path_put(&nd.path); 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 */
129long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags)
130{
131 int error = -EINVAL;
132
133 if (times && (!nsec_valid(times[0].tv_nsec) ||
134 !nsec_valid(times[1].tv_nsec))) {
135 goto out;
136 }
137
138 if (flags & ~AT_SYMLINK_NOFOLLOW)
139 goto out;
140
141 if (filename == NULL && dfd != AT_FDCWD) {
142 struct file *file;
143
144 if (flags & AT_SYMLINK_NOFOLLOW)
145 goto out;
146
147 file = fget(dfd);
148 error = -EBADF;
149 if (!file)
150 goto out;
151
152 error = utimes_common(&file->f_path, times);
153 fput(file);
154 } else {
155 struct path path;
156 int lookup_flags = 0;
157
158 if (!(flags & AT_SYMLINK_NOFOLLOW))
159 lookup_flags |= LOOKUP_FOLLOW;
160
161 error = user_path_at(dfd, filename, lookup_flags, &path);
162 if (error)
163 goto out;
164
165 error = utimes_common(&path, times);
166 path_put(&path);
167 }
168
166out: 169out:
167 return error; 170 return error;
168} 171}