aboutsummaryrefslogtreecommitdiffstats
path: root/fs/open.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/open.c')
-rw-r--r--fs/open.c213
1 files changed, 50 insertions, 163 deletions
diff --git a/fs/open.c b/fs/open.c
index 303f06d2a7b9..89e0c237a636 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -6,7 +6,6 @@
6 6
7#include <linux/string.h> 7#include <linux/string.h>
8#include <linux/mm.h> 8#include <linux/mm.h>
9#include <linux/utime.h>
10#include <linux/file.h> 9#include <linux/file.h>
11#include <linux/smp_lock.h> 10#include <linux/smp_lock.h>
12#include <linux/quotaops.h> 11#include <linux/quotaops.h>
@@ -29,8 +28,6 @@
29#include <linux/rcupdate.h> 28#include <linux/rcupdate.h>
30#include <linux/audit.h> 29#include <linux/audit.h>
31 30
32#include <asm/unistd.h>
33
34int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) 31int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
35{ 32{
36 int retval = -ENODEV; 33 int retval = -ENODEV;
@@ -353,137 +350,6 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
353} 350}
354#endif 351#endif
355 352
356#ifdef __ARCH_WANT_SYS_UTIME
357
358/*
359 * sys_utime() can be implemented in user-level using sys_utimes().
360 * Is this for backwards compatibility? If so, why not move it
361 * into the appropriate arch directory (for those architectures that
362 * need it).
363 */
364
365/* If times==NULL, set access and modification to current time,
366 * must be owner or have write permission.
367 * Else, update from *times, must be owner or super user.
368 */
369asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
370{
371 int error;
372 struct nameidata nd;
373 struct inode * inode;
374 struct iattr newattrs;
375
376 error = user_path_walk(filename, &nd);
377 if (error)
378 goto out;
379 inode = nd.dentry->d_inode;
380
381 error = -EROFS;
382 if (IS_RDONLY(inode))
383 goto dput_and_out;
384
385 /* Don't worry, the checks are done in inode_change_ok() */
386 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
387 if (times) {
388 error = -EPERM;
389 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
390 goto dput_and_out;
391
392 error = get_user(newattrs.ia_atime.tv_sec, &times->actime);
393 newattrs.ia_atime.tv_nsec = 0;
394 if (!error)
395 error = get_user(newattrs.ia_mtime.tv_sec, &times->modtime);
396 newattrs.ia_mtime.tv_nsec = 0;
397 if (error)
398 goto dput_and_out;
399
400 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
401 } else {
402 error = -EACCES;
403 if (IS_IMMUTABLE(inode))
404 goto dput_and_out;
405
406 if (current->fsuid != inode->i_uid &&
407 (error = vfs_permission(&nd, MAY_WRITE)) != 0)
408 goto dput_and_out;
409 }
410 mutex_lock(&inode->i_mutex);
411 error = notify_change(nd.dentry, &newattrs);
412 mutex_unlock(&inode->i_mutex);
413dput_and_out:
414 path_release(&nd);
415out:
416 return error;
417}
418
419#endif
420
421/* If times==NULL, set access and modification to current time,
422 * must be owner or have write permission.
423 * Else, update from *times, must be owner or super user.
424 */
425long do_utimes(int dfd, char __user *filename, struct timeval *times)
426{
427 int error;
428 struct nameidata nd;
429 struct inode * inode;
430 struct iattr newattrs;
431
432 error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
433
434 if (error)
435 goto out;
436 inode = nd.dentry->d_inode;
437
438 error = -EROFS;
439 if (IS_RDONLY(inode))
440 goto dput_and_out;
441
442 /* Don't worry, the checks are done in inode_change_ok() */
443 newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
444 if (times) {
445 error = -EPERM;
446 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
447 goto dput_and_out;
448
449 newattrs.ia_atime.tv_sec = times[0].tv_sec;
450 newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
451 newattrs.ia_mtime.tv_sec = times[1].tv_sec;
452 newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
453 newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
454 } else {
455 error = -EACCES;
456 if (IS_IMMUTABLE(inode))
457 goto dput_and_out;
458
459 if (current->fsuid != inode->i_uid &&
460 (error = vfs_permission(&nd, MAY_WRITE)) != 0)
461 goto dput_and_out;
462 }
463 mutex_lock(&inode->i_mutex);
464 error = notify_change(nd.dentry, &newattrs);
465 mutex_unlock(&inode->i_mutex);
466dput_and_out:
467 path_release(&nd);
468out:
469 return error;
470}
471
472asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
473{
474 struct timeval times[2];
475
476 if (utimes && copy_from_user(&times, utimes, sizeof(times)))
477 return -EFAULT;
478 return do_utimes(dfd, filename, utimes ? times : NULL);
479}
480
481asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
482{
483 return sys_futimesat(AT_FDCWD, filename, utimes);
484}
485
486
487/* 353/*
488 * access() needs to use the real uid/gid, not the effective uid/gid. 354 * access() needs to use the real uid/gid, not the effective uid/gid.
489 * We do this by temporarily clearing all FS-related capabilities and 355 * We do this by temporarily clearing all FS-related capabilities and
@@ -520,15 +386,21 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
520 current->cap_effective = current->cap_permitted; 386 current->cap_effective = current->cap_permitted;
521 387
522 res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); 388 res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
523 if (!res) { 389 if (res)
524 res = vfs_permission(&nd, mode); 390 goto out;
525 /* SuS v2 requires we report a read only fs too */ 391
526 if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) 392 res = vfs_permission(&nd, mode);
527 && !special_file(nd.dentry->d_inode->i_mode)) 393 /* SuS v2 requires we report a read only fs too */
528 res = -EROFS; 394 if(res || !(mode & S_IWOTH) ||
529 path_release(&nd); 395 special_file(nd.dentry->d_inode->i_mode))
530 } 396 goto out_path_release;
397
398 if(IS_RDONLY(nd.dentry->d_inode))
399 res = -EROFS;
531 400
401out_path_release:
402 path_release(&nd);
403out:
532 current->fsuid = old_fsuid; 404 current->fsuid = old_fsuid;
533 current->fsgid = old_fsgid; 405 current->fsgid = old_fsgid;
534 current->cap_effective = old_cap; 406 current->cap_effective = old_cap;
@@ -546,7 +418,8 @@ asmlinkage long sys_chdir(const char __user * filename)
546 struct nameidata nd; 418 struct nameidata nd;
547 int error; 419 int error;
548 420
549 error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd); 421 error = __user_walk(filename,
422 LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd);
550 if (error) 423 if (error)
551 goto out; 424 goto out;
552 425
@@ -736,10 +609,11 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group)
736 int error; 609 int error;
737 610
738 error = user_path_walk(filename, &nd); 611 error = user_path_walk(filename, &nd);
739 if (!error) { 612 if (error)
740 error = chown_common(nd.dentry, user, group); 613 goto out;
741 path_release(&nd); 614 error = chown_common(nd.dentry, user, group);
742 } 615 path_release(&nd);
616out:
743 return error; 617 return error;
744} 618}
745 619
@@ -755,10 +629,10 @@ asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
755 629
756 follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; 630 follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
757 error = __user_walk_fd(dfd, filename, follow, &nd); 631 error = __user_walk_fd(dfd, filename, follow, &nd);
758 if (!error) { 632 if (error)
759 error = chown_common(nd.dentry, user, group); 633 goto out;
760 path_release(&nd); 634 error = chown_common(nd.dentry, user, group);
761 } 635 path_release(&nd);
762out: 636out:
763 return error; 637 return error;
764} 638}
@@ -769,10 +643,11 @@ asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group
769 int error; 643 int error;
770 644
771 error = user_path_walk_link(filename, &nd); 645 error = user_path_walk_link(filename, &nd);
772 if (!error) { 646 if (error)
773 error = chown_common(nd.dentry, user, group); 647 goto out;
774 path_release(&nd); 648 error = chown_common(nd.dentry, user, group);
775 } 649 path_release(&nd);
650out:
776 return error; 651 return error;
777} 652}
778 653
@@ -781,15 +656,17 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
781{ 656{
782 struct file * file; 657 struct file * file;
783 int error = -EBADF; 658 int error = -EBADF;
659 struct dentry * dentry;
784 660
785 file = fget(fd); 661 file = fget(fd);
786 if (file) { 662 if (!file)
787 struct dentry * dentry; 663 goto out;
788 dentry = file->f_dentry; 664
789 audit_inode(NULL, dentry->d_inode); 665 dentry = file->f_dentry;
790 error = chown_common(dentry, user, group); 666 audit_inode(NULL, dentry->d_inode);
791 fput(file); 667 error = chown_common(dentry, user, group);
792 } 668 fput(file);
669out:
793 return error; 670 return error;
794} 671}
795 672
@@ -1172,6 +1049,7 @@ asmlinkage long sys_close(unsigned int fd)
1172 struct file * filp; 1049 struct file * filp;
1173 struct files_struct *files = current->files; 1050 struct files_struct *files = current->files;
1174 struct fdtable *fdt; 1051 struct fdtable *fdt;
1052 int retval;
1175 1053
1176 spin_lock(&files->file_lock); 1054 spin_lock(&files->file_lock);
1177 fdt = files_fdtable(files); 1055 fdt = files_fdtable(files);
@@ -1184,7 +1062,16 @@ asmlinkage long sys_close(unsigned int fd)
1184 FD_CLR(fd, fdt->close_on_exec); 1062 FD_CLR(fd, fdt->close_on_exec);
1185 __put_unused_fd(files, fd); 1063 __put_unused_fd(files, fd);
1186 spin_unlock(&files->file_lock); 1064 spin_unlock(&files->file_lock);
1187 return filp_close(filp, files); 1065 retval = filp_close(filp, files);
1066
1067 /* can't restart close syscall because file table entry was cleared */
1068 if (unlikely(retval == -ERESTARTSYS ||
1069 retval == -ERESTARTNOINTR ||
1070 retval == -ERESTARTNOHAND ||
1071 retval == -ERESTART_RESTARTBLOCK))
1072 retval = -EINTR;
1073
1074 return retval;
1188 1075
1189out_unlock: 1076out_unlock:
1190 spin_unlock(&files->file_lock); 1077 spin_unlock(&files->file_lock);