aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fat/file.c')
-rw-r--r--fs/fat/file.c183
1 files changed, 84 insertions, 99 deletions
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 2a3bed967041..b61a98f5398a 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -157,104 +157,6 @@ out:
157 return err; 157 return err;
158} 158}
159 159
160static int check_mode(const struct msdos_sb_info *sbi, mode_t mode)
161{
162 mode_t req = mode & ~S_IFMT;
163
164 /*
165 * Of the r and x bits, all (subject to umask) must be present. Of the
166 * w bits, either all (subject to umask) or none must be present.
167 */
168
169 if (S_ISREG(mode)) {
170 req &= ~sbi->options.fs_fmask;
171
172 if ((req & (S_IRUGO | S_IXUGO)) !=
173 ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask))
174 return -EPERM;
175
176 if ((req & S_IWUGO) != 0 &&
177 (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask))
178 return -EPERM;
179 } else if (S_ISDIR(mode)) {
180 req &= ~sbi->options.fs_dmask;
181
182 if ((req & (S_IRUGO | S_IXUGO)) !=
183 ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask))
184 return -EPERM;
185
186 if ((req & S_IWUGO) != 0 &&
187 (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask))
188 return -EPERM;
189 } else {
190 return -EPERM;
191 }
192
193 return 0;
194}
195
196int fat_notify_change(struct dentry *dentry, struct iattr *attr)
197{
198 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
199 struct inode *inode = dentry->d_inode;
200 int mask, error = 0;
201
202 lock_kernel();
203
204 /*
205 * Expand the file. Since inode_setattr() updates ->i_size
206 * before calling the ->truncate(), but FAT needs to fill the
207 * hole before it.
208 */
209 if (attr->ia_valid & ATTR_SIZE) {
210 if (attr->ia_size > inode->i_size) {
211 error = fat_cont_expand(inode, attr->ia_size);
212 if (error || attr->ia_valid == ATTR_SIZE)
213 goto out;
214 attr->ia_valid &= ~ATTR_SIZE;
215 }
216 }
217
218 error = inode_change_ok(inode, attr);
219 if (error) {
220 if (sbi->options.quiet)
221 error = 0;
222 goto out;
223 }
224 if (((attr->ia_valid & ATTR_UID) &&
225 (attr->ia_uid != sbi->options.fs_uid)) ||
226 ((attr->ia_valid & ATTR_GID) &&
227 (attr->ia_gid != sbi->options.fs_gid)))
228 error = -EPERM;
229
230 if (error) {
231 if (sbi->options.quiet)
232 error = 0;
233 goto out;
234 }
235
236 if (attr->ia_valid & ATTR_MODE) {
237 error = check_mode(sbi, attr->ia_mode);
238 if (error != 0 && !sbi->options.quiet)
239 goto out;
240 }
241
242 error = inode_setattr(inode, attr);
243 if (error)
244 goto out;
245
246 if (S_ISDIR(inode->i_mode))
247 mask = sbi->options.fs_dmask;
248 else
249 mask = sbi->options.fs_fmask;
250 inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
251out:
252 unlock_kernel();
253 return error;
254}
255
256EXPORT_SYMBOL_GPL(fat_notify_change);
257
258/* Free all clusters after the skip'th cluster. */ 160/* Free all clusters after the skip'th cluster. */
259static int fat_free(struct inode *inode, int skip) 161static int fat_free(struct inode *inode, int skip)
260{ 162{
@@ -355,8 +257,91 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
355} 257}
356EXPORT_SYMBOL_GPL(fat_getattr); 258EXPORT_SYMBOL_GPL(fat_getattr);
357 259
260static int fat_check_mode(const struct msdos_sb_info *sbi, mode_t mode)
261{
262 mode_t mask, req = mode & ~S_IFMT;
263
264 if (S_ISREG(mode))
265 mask = sbi->options.fs_fmask;
266 else
267 mask = sbi->options.fs_dmask;
268
269 /*
270 * Of the r and x bits, all (subject to umask) must be present. Of the
271 * w bits, either all (subject to umask) or none must be present.
272 */
273 req &= ~mask;
274 if ((req & (S_IRUGO | S_IXUGO)) != ((S_IRUGO | S_IXUGO) & ~mask))
275 return -EPERM;
276 if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask)))
277 return -EPERM;
278
279 return 0;
280}
281
282int fat_setattr(struct dentry *dentry, struct iattr *attr)
283{
284 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
285 struct inode *inode = dentry->d_inode;
286 int mask, error = 0;
287
288 lock_kernel();
289
290 /*
291 * Expand the file. Since inode_setattr() updates ->i_size
292 * before calling the ->truncate(), but FAT needs to fill the
293 * hole before it.
294 */
295 if (attr->ia_valid & ATTR_SIZE) {
296 if (attr->ia_size > inode->i_size) {
297 error = fat_cont_expand(inode, attr->ia_size);
298 if (error || attr->ia_valid == ATTR_SIZE)
299 goto out;
300 attr->ia_valid &= ~ATTR_SIZE;
301 }
302 }
303
304 error = inode_change_ok(inode, attr);
305 if (error) {
306 if (sbi->options.quiet)
307 error = 0;
308 goto out;
309 }
310 if (((attr->ia_valid & ATTR_UID) &&
311 (attr->ia_uid != sbi->options.fs_uid)) ||
312 ((attr->ia_valid & ATTR_GID) &&
313 (attr->ia_gid != sbi->options.fs_gid)))
314 error = -EPERM;
315
316 if (error) {
317 if (sbi->options.quiet)
318 error = 0;
319 goto out;
320 }
321
322 if (attr->ia_valid & ATTR_MODE) {
323 error = fat_check_mode(sbi, attr->ia_mode);
324 if (error != 0 && !sbi->options.quiet)
325 goto out;
326 }
327
328 error = inode_setattr(inode, attr);
329 if (error)
330 goto out;
331
332 if (S_ISDIR(inode->i_mode))
333 mask = sbi->options.fs_dmask;
334 else
335 mask = sbi->options.fs_fmask;
336 inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
337out:
338 unlock_kernel();
339 return error;
340}
341EXPORT_SYMBOL_GPL(fat_setattr);
342
358const struct inode_operations fat_file_inode_operations = { 343const struct inode_operations fat_file_inode_operations = {
359 .truncate = fat_truncate, 344 .truncate = fat_truncate,
360 .setattr = fat_notify_change, 345 .setattr = fat_setattr,
361 .getattr = fat_getattr, 346 .getattr = fat_getattr,
362}; 347};