aboutsummaryrefslogtreecommitdiffstats
path: root/fs/utimes.c
diff options
context:
space:
mode:
authorAnton Vorontsov <cbouatmailru@gmail.com>2008-07-29 18:05:23 -0400
committerAnton Vorontsov <cbouatmailru@gmail.com>2008-07-29 18:05:23 -0400
commit9fec6060d9e48ed7db0dac0e16d0f0f0e615b7f6 (patch)
tree74b41f31a08f6500ff3dfcf64ba21e2d9a8e87e5 /fs/utimes.c
parentfece418418f51e92dd7e67e17c5e3fe5a28d3279 (diff)
parent6e86841d05f371b5b9b86ce76c02aaee83352298 (diff)
Merge branch 'master' of /home/cbou/linux-2.6
Conflicts: drivers/power/Kconfig drivers/power/Makefile
Diffstat (limited to 'fs/utimes.c')
-rw-r--r--fs/utimes.c170
1 files changed, 85 insertions, 85 deletions
diff --git a/fs/utimes.c b/fs/utimes.c
index af059d5cb485..6929e3e91d05 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -40,75 +40,30 @@ asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times)
40 40
41#endif 41#endif
42 42
43static bool nsec_special(long nsec)
44{
45 return nsec == UTIME_OMIT || nsec == UTIME_NOW;
46}
47
48static bool nsec_valid(long nsec) 43static bool nsec_valid(long nsec)
49{ 44{
50 if (nsec_special(nsec)) 45 if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
51 return true; 46 return true;
52 47
53 return nsec >= 0 && nsec <= 999999999; 48 return nsec >= 0 && nsec <= 999999999;
54} 49}
55 50
56/* If times==NULL, set access and modification to current time, 51static int utimes_common(struct path *path, struct timespec *times)
57 * must be owner or have write permission.
58 * Else, update from *times, must be owner or super user.
59 */
60long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags)
61{ 52{
62 int error; 53 int error;
63 struct nameidata nd;
64 struct dentry *dentry;
65 struct inode *inode;
66 struct iattr newattrs; 54 struct iattr newattrs;
67 struct file *f = NULL; 55 struct inode *inode = path->dentry->d_inode;
68 struct vfsmount *mnt;
69
70 error = -EINVAL;
71 if (times && (!nsec_valid(times[0].tv_nsec) ||
72 !nsec_valid(times[1].tv_nsec))) {
73 goto out;
74 }
75 56
76 if (flags & ~AT_SYMLINK_NOFOLLOW) 57 error = mnt_want_write(path->mnt);
58 if (error)
77 goto out; 59 goto out;
78 60
79 if (filename == NULL && dfd != AT_FDCWD) { 61 if (times && times[0].tv_nsec == UTIME_NOW &&
80 error = -EINVAL; 62 times[1].tv_nsec == UTIME_NOW)
81 if (flags & AT_SYMLINK_NOFOLLOW) 63 times = NULL;
82 goto out;
83
84 error = -EBADF;
85 f = fget(dfd);
86 if (!f)
87 goto out;
88 dentry = f->f_path.dentry;
89 mnt = f->f_path.mnt;
90 } else {
91 error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd);
92 if (error)
93 goto out;
94
95 dentry = nd.path.dentry;
96 mnt = nd.path.mnt;
97 }
98
99 inode = dentry->d_inode;
100 64
101 error = mnt_want_write(mnt);
102 if (error)
103 goto dput_and_out;
104
105 /* Don't worry, the checks are done in inode_change_ok() */
106 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; 65 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
107 if (times) { 66 if (times) {
108 error = -EPERM;
109 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
110 goto mnt_drop_write_and_out;
111
112 if (times[0].tv_nsec == UTIME_OMIT) 67 if (times[0].tv_nsec == UTIME_OMIT)
113 newattrs.ia_valid &= ~ATTR_ATIME; 68 newattrs.ia_valid &= ~ATTR_ATIME;
114 else if (times[0].tv_nsec != UTIME_NOW) { 69 else if (times[0].tv_nsec != UTIME_NOW) {
@@ -124,40 +79,93 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
124 newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; 79 newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
125 newattrs.ia_valid |= ATTR_MTIME_SET; 80 newattrs.ia_valid |= ATTR_MTIME_SET;
126 } 81 }
127 } 82 /*
128 83 * Tell inode_change_ok(), that this is an explicit time
129 /* 84 * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET
130 * If times is NULL or both times are either UTIME_OMIT or 85 * were used.
131 * UTIME_NOW, then need to check permissions, because 86 */
132 * inode_change_ok() won't do it. 87 newattrs.ia_valid |= ATTR_TIMES_SET;
133 */ 88 } else {
134 if (!times || (nsec_special(times[0].tv_nsec) && 89 /*
135 nsec_special(times[1].tv_nsec))) { 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 */
136 error = -EACCES; 94 error = -EACCES;
137 if (IS_IMMUTABLE(inode)) 95 if (IS_IMMUTABLE(inode))
138 goto mnt_drop_write_and_out; 96 goto mnt_drop_write_and_out;
139 97
140 if (!is_owner_or_cap(inode)) { 98 if (!is_owner_or_cap(inode)) {
141 if (f) { 99 error = inode_permission(inode, MAY_WRITE);
142 if (!(f->f_mode & FMODE_WRITE)) 100 if (error)
143 goto mnt_drop_write_and_out; 101 goto mnt_drop_write_and_out;
144 } else {
145 error = vfs_permission(&nd, MAY_WRITE);
146 if (error)
147 goto mnt_drop_write_and_out;
148 }
149 } 102 }
150 } 103 }
151 mutex_lock(&inode->i_mutex); 104 mutex_lock(&inode->i_mutex);
152 error = notify_change(dentry, &newattrs); 105 error = notify_change(path->dentry, &newattrs);
153 mutex_unlock(&inode->i_mutex); 106 mutex_unlock(&inode->i_mutex);
107
154mnt_drop_write_and_out: 108mnt_drop_write_and_out:
155 mnt_drop_write(mnt); 109 mnt_drop_write(path->mnt);
156dput_and_out: 110out:
157 if (f) 111 return error;
158 fput(f); 112}
159 else 113
160 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
161out: 169out:
162 return error; 170 return error;
163} 171}
@@ -169,14 +177,6 @@ asmlinkage long sys_utimensat(int dfd, char __user *filename, struct timespec __
169 if (utimes) { 177 if (utimes) {
170 if (copy_from_user(&tstimes, utimes, sizeof(tstimes))) 178 if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))
171 return -EFAULT; 179 return -EFAULT;
172 if ((tstimes[0].tv_nsec == UTIME_OMIT ||
173 tstimes[0].tv_nsec == UTIME_NOW) &&
174 tstimes[0].tv_sec != 0)
175 return -EINVAL;
176 if ((tstimes[1].tv_nsec == UTIME_OMIT ||
177 tstimes[1].tv_nsec == UTIME_NOW) &&
178 tstimes[1].tv_sec != 0)
179 return -EINVAL;
180 180
181 /* Nothing to do, we must not even check the path. */ 181 /* Nothing to do, we must not even check the path. */
182 if (tstimes[0].tv_nsec == UTIME_OMIT && 182 if (tstimes[0].tv_nsec == UTIME_OMIT &&