diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 66 |
1 files changed, 42 insertions, 24 deletions
diff --git a/fs/namei.c b/fs/namei.c index 4acdac043b6b..8dc2b038d5d9 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -790,7 +790,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
790 | 790 | ||
791 | inode = nd->dentry->d_inode; | 791 | inode = nd->dentry->d_inode; |
792 | if (nd->depth) | 792 | if (nd->depth) |
793 | lookup_flags = LOOKUP_FOLLOW; | 793 | lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE); |
794 | 794 | ||
795 | /* At this point we know we have a real path component. */ | 795 | /* At this point we know we have a real path component. */ |
796 | for(;;) { | 796 | for(;;) { |
@@ -885,7 +885,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
885 | last_with_slashes: | 885 | last_with_slashes: |
886 | lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; | 886 | lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; |
887 | last_component: | 887 | last_component: |
888 | nd->flags &= ~LOOKUP_CONTINUE; | 888 | /* Clear LOOKUP_CONTINUE iff it was previously unset */ |
889 | nd->flags &= lookup_flags | ~LOOKUP_CONTINUE; | ||
889 | if (lookup_flags & LOOKUP_PARENT) | 890 | if (lookup_flags & LOOKUP_PARENT) |
890 | goto lookup_parent; | 891 | goto lookup_parent; |
891 | if (this.name[0] == '.') switch (this.len) { | 892 | if (this.name[0] == '.') switch (this.len) { |
@@ -1069,6 +1070,8 @@ static int fastcall do_path_lookup(int dfd, const char *name, | |||
1069 | unsigned int flags, struct nameidata *nd) | 1070 | unsigned int flags, struct nameidata *nd) |
1070 | { | 1071 | { |
1071 | int retval = 0; | 1072 | int retval = 0; |
1073 | int fput_needed; | ||
1074 | struct file *file; | ||
1072 | 1075 | ||
1073 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ | 1076 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ |
1074 | nd->flags = flags; | 1077 | nd->flags = flags; |
@@ -1090,29 +1093,22 @@ static int fastcall do_path_lookup(int dfd, const char *name, | |||
1090 | nd->mnt = mntget(current->fs->pwdmnt); | 1093 | nd->mnt = mntget(current->fs->pwdmnt); |
1091 | nd->dentry = dget(current->fs->pwd); | 1094 | nd->dentry = dget(current->fs->pwd); |
1092 | } else { | 1095 | } else { |
1093 | struct file *file; | ||
1094 | int fput_needed; | ||
1095 | struct dentry *dentry; | 1096 | struct dentry *dentry; |
1096 | 1097 | ||
1097 | file = fget_light(dfd, &fput_needed); | 1098 | file = fget_light(dfd, &fput_needed); |
1098 | if (!file) { | 1099 | retval = -EBADF; |
1099 | retval = -EBADF; | 1100 | if (!file) |
1100 | goto out_fail; | 1101 | goto unlock_fail; |
1101 | } | ||
1102 | 1102 | ||
1103 | dentry = file->f_dentry; | 1103 | dentry = file->f_dentry; |
1104 | 1104 | ||
1105 | if (!S_ISDIR(dentry->d_inode->i_mode)) { | 1105 | retval = -ENOTDIR; |
1106 | retval = -ENOTDIR; | 1106 | if (!S_ISDIR(dentry->d_inode->i_mode)) |
1107 | fput_light(file, fput_needed); | 1107 | goto fput_unlock_fail; |
1108 | goto out_fail; | ||
1109 | } | ||
1110 | 1108 | ||
1111 | retval = file_permission(file, MAY_EXEC); | 1109 | retval = file_permission(file, MAY_EXEC); |
1112 | if (retval) { | 1110 | if (retval) |
1113 | fput_light(file, fput_needed); | 1111 | goto fput_unlock_fail; |
1114 | goto out_fail; | ||
1115 | } | ||
1116 | 1112 | ||
1117 | nd->mnt = mntget(file->f_vfsmnt); | 1113 | nd->mnt = mntget(file->f_vfsmnt); |
1118 | nd->dentry = dget(dentry); | 1114 | nd->dentry = dget(dentry); |
@@ -1123,10 +1119,17 @@ static int fastcall do_path_lookup(int dfd, const char *name, | |||
1123 | current->total_link_count = 0; | 1119 | current->total_link_count = 0; |
1124 | retval = link_path_walk(name, nd); | 1120 | retval = link_path_walk(name, nd); |
1125 | out: | 1121 | out: |
1126 | if (unlikely(current->audit_context | 1122 | if (likely(retval == 0)) { |
1127 | && nd && nd->dentry && nd->dentry->d_inode)) | 1123 | if (unlikely(current->audit_context && nd && nd->dentry && |
1124 | nd->dentry->d_inode)) | ||
1128 | audit_inode(name, nd->dentry->d_inode, flags); | 1125 | audit_inode(name, nd->dentry->d_inode, flags); |
1129 | out_fail: | 1126 | } |
1127 | return retval; | ||
1128 | |||
1129 | fput_unlock_fail: | ||
1130 | fput_light(file, fput_needed); | ||
1131 | unlock_fail: | ||
1132 | read_unlock(¤t->fs->lock); | ||
1130 | return retval; | 1133 | return retval; |
1131 | } | 1134 | } |
1132 | 1135 | ||
@@ -1161,6 +1164,7 @@ static int __path_lookup_intent_open(int dfd, const char *name, | |||
1161 | 1164 | ||
1162 | /** | 1165 | /** |
1163 | * path_lookup_open - lookup a file path with open intent | 1166 | * path_lookup_open - lookup a file path with open intent |
1167 | * @dfd: the directory to use as base, or AT_FDCWD | ||
1164 | * @name: pointer to file name | 1168 | * @name: pointer to file name |
1165 | * @lookup_flags: lookup intent flags | 1169 | * @lookup_flags: lookup intent flags |
1166 | * @nd: pointer to nameidata | 1170 | * @nd: pointer to nameidata |
@@ -1175,6 +1179,7 @@ int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags, | |||
1175 | 1179 | ||
1176 | /** | 1180 | /** |
1177 | * path_lookup_create - lookup a file path with open + create intent | 1181 | * path_lookup_create - lookup a file path with open + create intent |
1182 | * @dfd: the directory to use as base, or AT_FDCWD | ||
1178 | * @name: pointer to file name | 1183 | * @name: pointer to file name |
1179 | * @lookup_flags: lookup intent flags | 1184 | * @lookup_flags: lookup intent flags |
1180 | * @nd: pointer to nameidata | 1185 | * @nd: pointer to nameidata |
@@ -2219,13 +2224,17 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de | |||
2219 | * and other special files. --ADM | 2224 | * and other special files. --ADM |
2220 | */ | 2225 | */ |
2221 | asmlinkage long sys_linkat(int olddfd, const char __user *oldname, | 2226 | asmlinkage long sys_linkat(int olddfd, const char __user *oldname, |
2222 | int newdfd, const char __user *newname) | 2227 | int newdfd, const char __user *newname, |
2228 | int flags) | ||
2223 | { | 2229 | { |
2224 | struct dentry *new_dentry; | 2230 | struct dentry *new_dentry; |
2225 | struct nameidata nd, old_nd; | 2231 | struct nameidata nd, old_nd; |
2226 | int error; | 2232 | int error; |
2227 | char * to; | 2233 | char * to; |
2228 | 2234 | ||
2235 | if (flags != 0) | ||
2236 | return -EINVAL; | ||
2237 | |||
2229 | to = getname(newname); | 2238 | to = getname(newname); |
2230 | if (IS_ERR(to)) | 2239 | if (IS_ERR(to)) |
2231 | return PTR_ERR(to); | 2240 | return PTR_ERR(to); |
@@ -2258,7 +2267,7 @@ exit: | |||
2258 | 2267 | ||
2259 | asmlinkage long sys_link(const char __user *oldname, const char __user *newname) | 2268 | asmlinkage long sys_link(const char __user *oldname, const char __user *newname) |
2260 | { | 2269 | { |
2261 | return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname); | 2270 | return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0); |
2262 | } | 2271 | } |
2263 | 2272 | ||
2264 | /* | 2273 | /* |
@@ -2604,13 +2613,15 @@ void page_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) | |||
2604 | } | 2613 | } |
2605 | } | 2614 | } |
2606 | 2615 | ||
2607 | int page_symlink(struct inode *inode, const char *symname, int len) | 2616 | int __page_symlink(struct inode *inode, const char *symname, int len, |
2617 | gfp_t gfp_mask) | ||
2608 | { | 2618 | { |
2609 | struct address_space *mapping = inode->i_mapping; | 2619 | struct address_space *mapping = inode->i_mapping; |
2610 | struct page *page = grab_cache_page(mapping, 0); | 2620 | struct page *page; |
2611 | int err = -ENOMEM; | 2621 | int err = -ENOMEM; |
2612 | char *kaddr; | 2622 | char *kaddr; |
2613 | 2623 | ||
2624 | page = find_or_create_page(mapping, 0, gfp_mask); | ||
2614 | if (!page) | 2625 | if (!page) |
2615 | goto fail; | 2626 | goto fail; |
2616 | err = mapping->a_ops->prepare_write(NULL, page, 0, len-1); | 2627 | err = mapping->a_ops->prepare_write(NULL, page, 0, len-1); |
@@ -2645,6 +2656,12 @@ fail: | |||
2645 | return err; | 2656 | return err; |
2646 | } | 2657 | } |
2647 | 2658 | ||
2659 | int page_symlink(struct inode *inode, const char *symname, int len) | ||
2660 | { | ||
2661 | return __page_symlink(inode, symname, len, | ||
2662 | mapping_gfp_mask(inode->i_mapping)); | ||
2663 | } | ||
2664 | |||
2648 | struct inode_operations page_symlink_inode_operations = { | 2665 | struct inode_operations page_symlink_inode_operations = { |
2649 | .readlink = generic_readlink, | 2666 | .readlink = generic_readlink, |
2650 | .follow_link = page_follow_link_light, | 2667 | .follow_link = page_follow_link_light, |
@@ -2663,6 +2680,7 @@ EXPORT_SYMBOL(lookup_one_len); | |||
2663 | EXPORT_SYMBOL(page_follow_link_light); | 2680 | EXPORT_SYMBOL(page_follow_link_light); |
2664 | EXPORT_SYMBOL(page_put_link); | 2681 | EXPORT_SYMBOL(page_put_link); |
2665 | EXPORT_SYMBOL(page_readlink); | 2682 | EXPORT_SYMBOL(page_readlink); |
2683 | EXPORT_SYMBOL(__page_symlink); | ||
2666 | EXPORT_SYMBOL(page_symlink); | 2684 | EXPORT_SYMBOL(page_symlink); |
2667 | EXPORT_SYMBOL(page_symlink_inode_operations); | 2685 | EXPORT_SYMBOL(page_symlink_inode_operations); |
2668 | EXPORT_SYMBOL(path_lookup); | 2686 | EXPORT_SYMBOL(path_lookup); |