diff options
Diffstat (limited to 'fs/open.c')
| -rw-r--r-- | fs/open.c | 79 |
1 files changed, 65 insertions, 14 deletions
| @@ -739,7 +739,8 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) | |||
| 739 | } | 739 | } |
| 740 | 740 | ||
| 741 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | 741 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, |
| 742 | int flags, struct file *f) | 742 | int flags, struct file *f, |
| 743 | int (*open)(struct inode *, struct file *)) | ||
| 743 | { | 744 | { |
| 744 | struct inode *inode; | 745 | struct inode *inode; |
| 745 | int error; | 746 | int error; |
| @@ -761,11 +762,14 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
| 761 | f->f_op = fops_get(inode->i_fop); | 762 | f->f_op = fops_get(inode->i_fop); |
| 762 | file_move(f, &inode->i_sb->s_files); | 763 | file_move(f, &inode->i_sb->s_files); |
| 763 | 764 | ||
| 764 | if (f->f_op && f->f_op->open) { | 765 | if (!open && f->f_op) |
| 765 | error = f->f_op->open(inode,f); | 766 | open = f->f_op->open; |
| 767 | if (open) { | ||
| 768 | error = open(inode, f); | ||
| 766 | if (error) | 769 | if (error) |
| 767 | goto cleanup_all; | 770 | goto cleanup_all; |
| 768 | } | 771 | } |
| 772 | |||
| 769 | f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); | 773 | f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); |
| 770 | 774 | ||
| 771 | file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); | 775 | file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); |
| @@ -814,28 +818,75 @@ struct file *filp_open(const char * filename, int flags, int mode) | |||
| 814 | { | 818 | { |
| 815 | int namei_flags, error; | 819 | int namei_flags, error; |
| 816 | struct nameidata nd; | 820 | struct nameidata nd; |
| 817 | struct file *f; | ||
| 818 | 821 | ||
| 819 | namei_flags = flags; | 822 | namei_flags = flags; |
| 820 | if ((namei_flags+1) & O_ACCMODE) | 823 | if ((namei_flags+1) & O_ACCMODE) |
| 821 | namei_flags++; | 824 | namei_flags++; |
| 822 | if (namei_flags & O_TRUNC) | ||
| 823 | namei_flags |= 2; | ||
| 824 | |||
| 825 | error = -ENFILE; | ||
| 826 | f = get_empty_filp(); | ||
| 827 | if (f == NULL) | ||
| 828 | return ERR_PTR(error); | ||
| 829 | 825 | ||
| 830 | error = open_namei(filename, namei_flags, mode, &nd); | 826 | error = open_namei(filename, namei_flags, mode, &nd); |
| 831 | if (!error) | 827 | if (!error) |
| 832 | return __dentry_open(nd.dentry, nd.mnt, flags, f); | 828 | return nameidata_to_filp(&nd, flags); |
| 833 | 829 | ||
| 834 | put_filp(f); | ||
| 835 | return ERR_PTR(error); | 830 | return ERR_PTR(error); |
| 836 | } | 831 | } |
| 837 | EXPORT_SYMBOL(filp_open); | 832 | EXPORT_SYMBOL(filp_open); |
| 838 | 833 | ||
| 834 | /** | ||
| 835 | * lookup_instantiate_filp - instantiates the open intent filp | ||
| 836 | * @nd: pointer to nameidata | ||
| 837 | * @dentry: pointer to dentry | ||
| 838 | * @open: open callback | ||
| 839 | * | ||
| 840 | * Helper for filesystems that want to use lookup open intents and pass back | ||
| 841 | * a fully instantiated struct file to the caller. | ||
| 842 | * This function is meant to be called from within a filesystem's | ||
| 843 | * lookup method. | ||
| 844 | * Note that in case of error, nd->intent.open.file is destroyed, but the | ||
| 845 | * path information remains valid. | ||
| 846 | * If the open callback is set to NULL, then the standard f_op->open() | ||
| 847 | * filesystem callback is substituted. | ||
| 848 | */ | ||
| 849 | struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry, | ||
| 850 | int (*open)(struct inode *, struct file *)) | ||
| 851 | { | ||
| 852 | if (IS_ERR(nd->intent.open.file)) | ||
| 853 | goto out; | ||
| 854 | if (IS_ERR(dentry)) | ||
| 855 | goto out_err; | ||
| 856 | nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->mnt), | ||
| 857 | nd->intent.open.flags - 1, | ||
| 858 | nd->intent.open.file, | ||
| 859 | open); | ||
| 860 | out: | ||
| 861 | return nd->intent.open.file; | ||
| 862 | out_err: | ||
| 863 | release_open_intent(nd); | ||
| 864 | nd->intent.open.file = (struct file *)dentry; | ||
| 865 | goto out; | ||
| 866 | } | ||
| 867 | EXPORT_SYMBOL_GPL(lookup_instantiate_filp); | ||
| 868 | |||
| 869 | /** | ||
| 870 | * nameidata_to_filp - convert a nameidata to an open filp. | ||
| 871 | * @nd: pointer to nameidata | ||
| 872 | * @flags: open flags | ||
| 873 | * | ||
| 874 | * Note that this function destroys the original nameidata | ||
| 875 | */ | ||
| 876 | struct file *nameidata_to_filp(struct nameidata *nd, int flags) | ||
| 877 | { | ||
| 878 | struct file *filp; | ||
| 879 | |||
| 880 | /* Pick up the filp from the open intent */ | ||
| 881 | filp = nd->intent.open.file; | ||
| 882 | /* Has the filesystem initialised the file for us? */ | ||
| 883 | if (filp->f_dentry == NULL) | ||
| 884 | filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL); | ||
| 885 | else | ||
| 886 | path_release(nd); | ||
| 887 | return filp; | ||
| 888 | } | ||
| 889 | |||
| 839 | struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | 890 | struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) |
| 840 | { | 891 | { |
| 841 | int error; | 892 | int error; |
| @@ -846,7 +897,7 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | |||
| 846 | if (f == NULL) | 897 | if (f == NULL) |
| 847 | return ERR_PTR(error); | 898 | return ERR_PTR(error); |
| 848 | 899 | ||
| 849 | return __dentry_open(dentry, mnt, flags, f); | 900 | return __dentry_open(dentry, mnt, flags, f, NULL); |
| 850 | } | 901 | } |
| 851 | EXPORT_SYMBOL(dentry_open); | 902 | EXPORT_SYMBOL(dentry_open); |
| 852 | 903 | ||
