diff options
Diffstat (limited to 'fs/open.c')
-rw-r--r-- | fs/open.c | 83 |
1 files changed, 68 insertions, 15 deletions
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/security.h> | 20 | #include <linux/security.h> |
21 | #include <linux/mount.h> | 21 | #include <linux/mount.h> |
22 | #include <linux/vfs.h> | 22 | #include <linux/vfs.h> |
23 | #include <linux/fcntl.h> | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
25 | #include <linux/personality.h> | 26 | #include <linux/personality.h> |
@@ -383,7 +384,7 @@ asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times) | |||
383 | 384 | ||
384 | error = get_user(newattrs.ia_atime.tv_sec, ×->actime); | 385 | error = get_user(newattrs.ia_atime.tv_sec, ×->actime); |
385 | newattrs.ia_atime.tv_nsec = 0; | 386 | newattrs.ia_atime.tv_nsec = 0; |
386 | if (!error) | 387 | if (!error) |
387 | error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime); | 388 | error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime); |
388 | newattrs.ia_mtime.tv_nsec = 0; | 389 | newattrs.ia_mtime.tv_nsec = 0; |
389 | if (error) | 390 | if (error) |
@@ -414,14 +415,14 @@ out: | |||
414 | * must be owner or have write permission. | 415 | * must be owner or have write permission. |
415 | * Else, update from *times, must be owner or super user. | 416 | * Else, update from *times, must be owner or super user. |
416 | */ | 417 | */ |
417 | long do_utimes(char __user * filename, struct timeval * times) | 418 | long do_utimes(int dfd, char __user *filename, struct timeval *times) |
418 | { | 419 | { |
419 | int error; | 420 | int error; |
420 | struct nameidata nd; | 421 | struct nameidata nd; |
421 | struct inode * inode; | 422 | struct inode * inode; |
422 | struct iattr newattrs; | 423 | struct iattr newattrs; |
423 | 424 | ||
424 | error = user_path_walk(filename, &nd); | 425 | error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); |
425 | 426 | ||
426 | if (error) | 427 | if (error) |
427 | goto out; | 428 | goto out; |
@@ -461,13 +462,18 @@ out: | |||
461 | return error; | 462 | return error; |
462 | } | 463 | } |
463 | 464 | ||
464 | asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utimes) | 465 | asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes) |
465 | { | 466 | { |
466 | struct timeval times[2]; | 467 | struct timeval times[2]; |
467 | 468 | ||
468 | if (utimes && copy_from_user(×, utimes, sizeof(times))) | 469 | if (utimes && copy_from_user(×, utimes, sizeof(times))) |
469 | return -EFAULT; | 470 | return -EFAULT; |
470 | return do_utimes(filename, utimes ? times : NULL); | 471 | return do_utimes(dfd, filename, utimes ? times : NULL); |
472 | } | ||
473 | |||
474 | asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes) | ||
475 | { | ||
476 | return sys_futimesat(AT_FDCWD, filename, utimes); | ||
471 | } | 477 | } |
472 | 478 | ||
473 | 479 | ||
@@ -476,7 +482,7 @@ asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utime | |||
476 | * We do this by temporarily clearing all FS-related capabilities and | 482 | * We do this by temporarily clearing all FS-related capabilities and |
477 | * switching the fsuid/fsgid around to the real ones. | 483 | * switching the fsuid/fsgid around to the real ones. |
478 | */ | 484 | */ |
479 | asmlinkage long sys_access(const char __user * filename, int mode) | 485 | asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) |
480 | { | 486 | { |
481 | struct nameidata nd; | 487 | struct nameidata nd; |
482 | int old_fsuid, old_fsgid; | 488 | int old_fsuid, old_fsgid; |
@@ -506,7 +512,7 @@ asmlinkage long sys_access(const char __user * filename, int mode) | |||
506 | else | 512 | else |
507 | current->cap_effective = current->cap_permitted; | 513 | current->cap_effective = current->cap_permitted; |
508 | 514 | ||
509 | res = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); | 515 | res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); |
510 | if (!res) { | 516 | if (!res) { |
511 | res = vfs_permission(&nd, mode); | 517 | res = vfs_permission(&nd, mode); |
512 | /* SuS v2 requires we report a read only fs too */ | 518 | /* SuS v2 requires we report a read only fs too */ |
@@ -523,6 +529,11 @@ asmlinkage long sys_access(const char __user * filename, int mode) | |||
523 | return res; | 529 | return res; |
524 | } | 530 | } |
525 | 531 | ||
532 | asmlinkage long sys_access(const char __user *filename, int mode) | ||
533 | { | ||
534 | return sys_faccessat(AT_FDCWD, filename, mode); | ||
535 | } | ||
536 | |||
526 | asmlinkage long sys_chdir(const char __user * filename) | 537 | asmlinkage long sys_chdir(const char __user * filename) |
527 | { | 538 | { |
528 | struct nameidata nd; | 539 | struct nameidata nd; |
@@ -635,14 +646,15 @@ out: | |||
635 | return err; | 646 | return err; |
636 | } | 647 | } |
637 | 648 | ||
638 | asmlinkage long sys_chmod(const char __user * filename, mode_t mode) | 649 | asmlinkage long sys_fchmodat(int dfd, const char __user *filename, |
650 | mode_t mode) | ||
639 | { | 651 | { |
640 | struct nameidata nd; | 652 | struct nameidata nd; |
641 | struct inode * inode; | 653 | struct inode * inode; |
642 | int error; | 654 | int error; |
643 | struct iattr newattrs; | 655 | struct iattr newattrs; |
644 | 656 | ||
645 | error = user_path_walk(filename, &nd); | 657 | error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); |
646 | if (error) | 658 | if (error) |
647 | goto out; | 659 | goto out; |
648 | inode = nd.dentry->d_inode; | 660 | inode = nd.dentry->d_inode; |
@@ -669,6 +681,11 @@ out: | |||
669 | return error; | 681 | return error; |
670 | } | 682 | } |
671 | 683 | ||
684 | asmlinkage long sys_chmod(const char __user *filename, mode_t mode) | ||
685 | { | ||
686 | return sys_fchmodat(AT_FDCWD, filename, mode); | ||
687 | } | ||
688 | |||
672 | static int chown_common(struct dentry * dentry, uid_t user, gid_t group) | 689 | static int chown_common(struct dentry * dentry, uid_t user, gid_t group) |
673 | { | 690 | { |
674 | struct inode * inode; | 691 | struct inode * inode; |
@@ -717,6 +734,26 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) | |||
717 | return error; | 734 | return error; |
718 | } | 735 | } |
719 | 736 | ||
737 | asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, | ||
738 | gid_t group, int flag) | ||
739 | { | ||
740 | struct nameidata nd; | ||
741 | int error = -EINVAL; | ||
742 | int follow; | ||
743 | |||
744 | if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) | ||
745 | goto out; | ||
746 | |||
747 | follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; | ||
748 | error = __user_walk_fd(dfd, filename, follow, &nd); | ||
749 | if (!error) { | ||
750 | error = chown_common(nd.dentry, user, group); | ||
751 | path_release(&nd); | ||
752 | } | ||
753 | out: | ||
754 | return error; | ||
755 | } | ||
756 | |||
720 | asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) | 757 | asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) |
721 | { | 758 | { |
722 | struct nameidata nd; | 759 | struct nameidata nd; |
@@ -820,7 +857,8 @@ cleanup_file: | |||
820 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is | 857 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is |
821 | * used by symlinks. | 858 | * used by symlinks. |
822 | */ | 859 | */ |
823 | struct file *filp_open(const char * filename, int flags, int mode) | 860 | static struct file *do_filp_open(int dfd, const char *filename, int flags, |
861 | int mode) | ||
824 | { | 862 | { |
825 | int namei_flags, error; | 863 | int namei_flags, error; |
826 | struct nameidata nd; | 864 | struct nameidata nd; |
@@ -829,12 +867,17 @@ struct file *filp_open(const char * filename, int flags, int mode) | |||
829 | if ((namei_flags+1) & O_ACCMODE) | 867 | if ((namei_flags+1) & O_ACCMODE) |
830 | namei_flags++; | 868 | namei_flags++; |
831 | 869 | ||
832 | error = open_namei(filename, namei_flags, mode, &nd); | 870 | error = open_namei(dfd, filename, namei_flags, mode, &nd); |
833 | if (!error) | 871 | if (!error) |
834 | return nameidata_to_filp(&nd, flags); | 872 | return nameidata_to_filp(&nd, flags); |
835 | 873 | ||
836 | return ERR_PTR(error); | 874 | return ERR_PTR(error); |
837 | } | 875 | } |
876 | |||
877 | struct file *filp_open(const char *filename, int flags, int mode) | ||
878 | { | ||
879 | return do_filp_open(AT_FDCWD, filename, flags, mode); | ||
880 | } | ||
838 | EXPORT_SYMBOL(filp_open); | 881 | EXPORT_SYMBOL(filp_open); |
839 | 882 | ||
840 | /** | 883 | /** |
@@ -991,7 +1034,7 @@ void fastcall put_unused_fd(unsigned int fd) | |||
991 | EXPORT_SYMBOL(put_unused_fd); | 1034 | EXPORT_SYMBOL(put_unused_fd); |
992 | 1035 | ||
993 | /* | 1036 | /* |
994 | * Install a file pointer in the fd array. | 1037 | * Install a file pointer in the fd array. |
995 | * | 1038 | * |
996 | * The VFS is full of places where we drop the files lock between | 1039 | * The VFS is full of places where we drop the files lock between |
997 | * setting the open_fds bitmap and installing the file in the file | 1040 | * setting the open_fds bitmap and installing the file in the file |
@@ -1016,7 +1059,7 @@ void fastcall fd_install(unsigned int fd, struct file * file) | |||
1016 | 1059 | ||
1017 | EXPORT_SYMBOL(fd_install); | 1060 | EXPORT_SYMBOL(fd_install); |
1018 | 1061 | ||
1019 | long do_sys_open(const char __user *filename, int flags, int mode) | 1062 | long do_sys_open(int dfd, const char __user *filename, int flags, int mode) |
1020 | { | 1063 | { |
1021 | char *tmp = getname(filename); | 1064 | char *tmp = getname(filename); |
1022 | int fd = PTR_ERR(tmp); | 1065 | int fd = PTR_ERR(tmp); |
@@ -1024,7 +1067,7 @@ long do_sys_open(const char __user *filename, int flags, int mode) | |||
1024 | if (!IS_ERR(tmp)) { | 1067 | if (!IS_ERR(tmp)) { |
1025 | fd = get_unused_fd(); | 1068 | fd = get_unused_fd(); |
1026 | if (fd >= 0) { | 1069 | if (fd >= 0) { |
1027 | struct file *f = filp_open(tmp, flags, mode); | 1070 | struct file *f = do_filp_open(dfd, tmp, flags, mode); |
1028 | if (IS_ERR(f)) { | 1071 | if (IS_ERR(f)) { |
1029 | put_unused_fd(fd); | 1072 | put_unused_fd(fd); |
1030 | fd = PTR_ERR(f); | 1073 | fd = PTR_ERR(f); |
@@ -1043,10 +1086,20 @@ asmlinkage long sys_open(const char __user *filename, int flags, int mode) | |||
1043 | if (force_o_largefile()) | 1086 | if (force_o_largefile()) |
1044 | flags |= O_LARGEFILE; | 1087 | flags |= O_LARGEFILE; |
1045 | 1088 | ||
1046 | return do_sys_open(filename, flags, mode); | 1089 | return do_sys_open(AT_FDCWD, filename, flags, mode); |
1047 | } | 1090 | } |
1048 | EXPORT_SYMBOL_GPL(sys_open); | 1091 | EXPORT_SYMBOL_GPL(sys_open); |
1049 | 1092 | ||
1093 | asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, | ||
1094 | int mode) | ||
1095 | { | ||
1096 | if (force_o_largefile()) | ||
1097 | flags |= O_LARGEFILE; | ||
1098 | |||
1099 | return do_sys_open(dfd, filename, flags, mode); | ||
1100 | } | ||
1101 | EXPORT_SYMBOL_GPL(sys_openat); | ||
1102 | |||
1050 | #ifndef __alpha__ | 1103 | #ifndef __alpha__ |
1051 | 1104 | ||
1052 | /* | 1105 | /* |