diff options
author | Ulrich Drepper <drepper@redhat.com> | 2006-01-18 20:43:53 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-18 22:20:29 -0500 |
commit | 5590ff0d5528b60153c0b4e7b771472b5a95e297 (patch) | |
tree | 5fdccf2354269702f71beb8e0a2942e4167fd992 /fs | |
parent | e2f99018eb7b29954747a2dd78e9fc0c36a60f0f (diff) |
[PATCH] vfs: *at functions: core
Here is a series of patches which introduce in total 13 new system calls
which take a file descriptor/filename pair instead of a single file
name. These functions, openat etc, have been discussed on numerous
occasions. They are needed to implement race-free filesystem traversal,
they are necessary to implement a virtual per-thread current working
directory (think multi-threaded backup software), etc.
We have in glibc today implementations of the interfaces which use the
/proc/self/fd magic. But this code is rather expensive. Here are some
results (similar to what Jim Meyering posted before).
The test creates a deep directory hierarchy on a tmpfs filesystem. Then
rm -fr is used to remove all directories. Without syscall support I get
this:
real 0m31.921s
user 0m0.688s
sys 0m31.234s
With syscall support the results are much better:
real 0m20.699s
user 0m0.536s
sys 0m20.149s
The interfaces are for obvious reasons currently not much used. But they'll
be used. coreutils (and Jeff's posixutils) are already using them.
Furthermore, code like ftw/fts in libc (maybe even glob) will also start using
them. I expect a patch to make follow soon. Every program which is walking
the filesystem tree will benefit.
Signed-off-by: Ulrich Drepper <drepper@redhat.com>
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Al Viro <viro@ftp.linux.org.uk>
Acked-by: Ingo Molnar <mingo@elte.hu>
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/compat.c | 48 | ||||
-rw-r--r-- | fs/exec.c | 2 | ||||
-rw-r--r-- | fs/namei.c | 172 | ||||
-rw-r--r-- | fs/open.c | 83 | ||||
-rw-r--r-- | fs/stat.c | 66 |
5 files changed, 300 insertions, 71 deletions
diff --git a/fs/compat.c b/fs/compat.c index 2468ac1df2f0..c6ba9deabada 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -68,10 +68,10 @@ asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __ | |||
68 | tv[0].tv_usec = 0; | 68 | tv[0].tv_usec = 0; |
69 | tv[1].tv_usec = 0; | 69 | tv[1].tv_usec = 0; |
70 | } | 70 | } |
71 | return do_utimes(filename, t ? tv : NULL); | 71 | return do_utimes(AT_FDCWD, filename, t ? tv : NULL); |
72 | } | 72 | } |
73 | 73 | ||
74 | asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t) | 74 | asmlinkage long compat_sys_futimesat(int dfd, char __user *filename, struct compat_timeval __user *t) |
75 | { | 75 | { |
76 | struct timeval tv[2]; | 76 | struct timeval tv[2]; |
77 | 77 | ||
@@ -82,14 +82,19 @@ asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval _ | |||
82 | get_user(tv[1].tv_usec, &t[1].tv_usec)) | 82 | get_user(tv[1].tv_usec, &t[1].tv_usec)) |
83 | return -EFAULT; | 83 | return -EFAULT; |
84 | } | 84 | } |
85 | return do_utimes(filename, t ? tv : NULL); | 85 | return do_utimes(dfd, filename, t ? tv : NULL); |
86 | } | ||
87 | |||
88 | asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t) | ||
89 | { | ||
90 | return compat_sys_futimesat(AT_FDCWD, filename, t); | ||
86 | } | 91 | } |
87 | 92 | ||
88 | asmlinkage long compat_sys_newstat(char __user * filename, | 93 | asmlinkage long compat_sys_newstat(char __user * filename, |
89 | struct compat_stat __user *statbuf) | 94 | struct compat_stat __user *statbuf) |
90 | { | 95 | { |
91 | struct kstat stat; | 96 | struct kstat stat; |
92 | int error = vfs_stat(filename, &stat); | 97 | int error = vfs_stat_fd(AT_FDCWD, filename, &stat); |
93 | 98 | ||
94 | if (!error) | 99 | if (!error) |
95 | error = cp_compat_stat(&stat, statbuf); | 100 | error = cp_compat_stat(&stat, statbuf); |
@@ -100,13 +105,34 @@ asmlinkage long compat_sys_newlstat(char __user * filename, | |||
100 | struct compat_stat __user *statbuf) | 105 | struct compat_stat __user *statbuf) |
101 | { | 106 | { |
102 | struct kstat stat; | 107 | struct kstat stat; |
103 | int error = vfs_lstat(filename, &stat); | 108 | int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); |
104 | 109 | ||
105 | if (!error) | 110 | if (!error) |
106 | error = cp_compat_stat(&stat, statbuf); | 111 | error = cp_compat_stat(&stat, statbuf); |
107 | return error; | 112 | return error; |
108 | } | 113 | } |
109 | 114 | ||
115 | asmlinkage long compat_sys_newfstatat(int dfd, char __user *filename, | ||
116 | struct compat_stat __user *statbuf, int flag) | ||
117 | { | ||
118 | struct kstat stat; | ||
119 | int error = -EINVAL; | ||
120 | |||
121 | if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) | ||
122 | goto out; | ||
123 | |||
124 | if (flag & AT_SYMLINK_NOFOLLOW) | ||
125 | error = vfs_lstat_fd(dfd, filename, &stat); | ||
126 | else | ||
127 | error = vfs_stat_fd(dfd, filename, &stat); | ||
128 | |||
129 | if (!error) | ||
130 | error = cp_compat_stat(&stat, statbuf); | ||
131 | |||
132 | out: | ||
133 | return error; | ||
134 | } | ||
135 | |||
110 | asmlinkage long compat_sys_newfstat(unsigned int fd, | 136 | asmlinkage long compat_sys_newfstat(unsigned int fd, |
111 | struct compat_stat __user * statbuf) | 137 | struct compat_stat __user * statbuf) |
112 | { | 138 | { |
@@ -1290,7 +1316,17 @@ out: | |||
1290 | asmlinkage long | 1316 | asmlinkage long |
1291 | compat_sys_open(const char __user *filename, int flags, int mode) | 1317 | compat_sys_open(const char __user *filename, int flags, int mode) |
1292 | { | 1318 | { |
1293 | return do_sys_open(filename, flags, mode); | 1319 | return do_sys_open(AT_FDCWD, filename, flags, mode); |
1320 | } | ||
1321 | |||
1322 | /* | ||
1323 | * Exactly like fs/open.c:sys_openat(), except that it doesn't set the | ||
1324 | * O_LARGEFILE flag. | ||
1325 | */ | ||
1326 | asmlinkage long | ||
1327 | compat_sys_openat(int dfd, const char __user *filename, int flags, int mode) | ||
1328 | { | ||
1329 | return do_sys_open(dfd, filename, flags, mode); | ||
1294 | } | 1330 | } |
1295 | 1331 | ||
1296 | /* | 1332 | /* |
@@ -477,7 +477,7 @@ struct file *open_exec(const char *name) | |||
477 | int err; | 477 | int err; |
478 | struct file *file; | 478 | struct file *file; |
479 | 479 | ||
480 | err = path_lookup_open(name, LOOKUP_FOLLOW, &nd, FMODE_READ); | 480 | err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ); |
481 | file = ERR_PTR(err); | 481 | file = ERR_PTR(err); |
482 | 482 | ||
483 | if (!err) { | 483 | if (!err) { |
diff --git a/fs/namei.c b/fs/namei.c index 33fb5bd34a81..4acdac043b6b 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include <linux/audit.h> | 30 | #include <linux/audit.h> |
31 | #include <linux/capability.h> | 31 | #include <linux/capability.h> |
32 | #include <linux/file.h> | 32 | #include <linux/file.h> |
33 | #include <linux/fcntl.h> | ||
34 | #include <linux/namei.h> | ||
33 | #include <asm/namei.h> | 35 | #include <asm/namei.h> |
34 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
35 | 37 | ||
@@ -1063,7 +1065,8 @@ set_it: | |||
1063 | } | 1065 | } |
1064 | 1066 | ||
1065 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ | 1067 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ |
1066 | int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) | 1068 | static int fastcall do_path_lookup(int dfd, const char *name, |
1069 | unsigned int flags, struct nameidata *nd) | ||
1067 | { | 1070 | { |
1068 | int retval = 0; | 1071 | int retval = 0; |
1069 | 1072 | ||
@@ -1083,9 +1086,38 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata | |||
1083 | } | 1086 | } |
1084 | nd->mnt = mntget(current->fs->rootmnt); | 1087 | nd->mnt = mntget(current->fs->rootmnt); |
1085 | nd->dentry = dget(current->fs->root); | 1088 | nd->dentry = dget(current->fs->root); |
1086 | } else { | 1089 | } else if (dfd == AT_FDCWD) { |
1087 | nd->mnt = mntget(current->fs->pwdmnt); | 1090 | nd->mnt = mntget(current->fs->pwdmnt); |
1088 | nd->dentry = dget(current->fs->pwd); | 1091 | nd->dentry = dget(current->fs->pwd); |
1092 | } else { | ||
1093 | struct file *file; | ||
1094 | int fput_needed; | ||
1095 | struct dentry *dentry; | ||
1096 | |||
1097 | file = fget_light(dfd, &fput_needed); | ||
1098 | if (!file) { | ||
1099 | retval = -EBADF; | ||
1100 | goto out_fail; | ||
1101 | } | ||
1102 | |||
1103 | dentry = file->f_dentry; | ||
1104 | |||
1105 | if (!S_ISDIR(dentry->d_inode->i_mode)) { | ||
1106 | retval = -ENOTDIR; | ||
1107 | fput_light(file, fput_needed); | ||
1108 | goto out_fail; | ||
1109 | } | ||
1110 | |||
1111 | retval = file_permission(file, MAY_EXEC); | ||
1112 | if (retval) { | ||
1113 | fput_light(file, fput_needed); | ||
1114 | goto out_fail; | ||
1115 | } | ||
1116 | |||
1117 | nd->mnt = mntget(file->f_vfsmnt); | ||
1118 | nd->dentry = dget(dentry); | ||
1119 | |||
1120 | fput_light(file, fput_needed); | ||
1089 | } | 1121 | } |
1090 | read_unlock(¤t->fs->lock); | 1122 | read_unlock(¤t->fs->lock); |
1091 | current->total_link_count = 0; | 1123 | current->total_link_count = 0; |
@@ -1094,11 +1126,19 @@ out: | |||
1094 | if (unlikely(current->audit_context | 1126 | if (unlikely(current->audit_context |
1095 | && nd && nd->dentry && nd->dentry->d_inode)) | 1127 | && nd && nd->dentry && nd->dentry->d_inode)) |
1096 | audit_inode(name, nd->dentry->d_inode, flags); | 1128 | audit_inode(name, nd->dentry->d_inode, flags); |
1129 | out_fail: | ||
1097 | return retval; | 1130 | return retval; |
1098 | } | 1131 | } |
1099 | 1132 | ||
1100 | static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags, | 1133 | int fastcall path_lookup(const char *name, unsigned int flags, |
1101 | struct nameidata *nd, int open_flags, int create_mode) | 1134 | struct nameidata *nd) |
1135 | { | ||
1136 | return do_path_lookup(AT_FDCWD, name, flags, nd); | ||
1137 | } | ||
1138 | |||
1139 | static int __path_lookup_intent_open(int dfd, const char *name, | ||
1140 | unsigned int lookup_flags, struct nameidata *nd, | ||
1141 | int open_flags, int create_mode) | ||
1102 | { | 1142 | { |
1103 | struct file *filp = get_empty_filp(); | 1143 | struct file *filp = get_empty_filp(); |
1104 | int err; | 1144 | int err; |
@@ -1108,7 +1148,7 @@ static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags | |||
1108 | nd->intent.open.file = filp; | 1148 | nd->intent.open.file = filp; |
1109 | nd->intent.open.flags = open_flags; | 1149 | nd->intent.open.flags = open_flags; |
1110 | nd->intent.open.create_mode = create_mode; | 1150 | nd->intent.open.create_mode = create_mode; |
1111 | err = path_lookup(name, lookup_flags|LOOKUP_OPEN, nd); | 1151 | err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd); |
1112 | if (IS_ERR(nd->intent.open.file)) { | 1152 | if (IS_ERR(nd->intent.open.file)) { |
1113 | if (err == 0) { | 1153 | if (err == 0) { |
1114 | err = PTR_ERR(nd->intent.open.file); | 1154 | err = PTR_ERR(nd->intent.open.file); |
@@ -1126,10 +1166,10 @@ static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags | |||
1126 | * @nd: pointer to nameidata | 1166 | * @nd: pointer to nameidata |
1127 | * @open_flags: open intent flags | 1167 | * @open_flags: open intent flags |
1128 | */ | 1168 | */ |
1129 | int path_lookup_open(const char *name, unsigned int lookup_flags, | 1169 | int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags, |
1130 | struct nameidata *nd, int open_flags) | 1170 | struct nameidata *nd, int open_flags) |
1131 | { | 1171 | { |
1132 | return __path_lookup_intent_open(name, lookup_flags, nd, | 1172 | return __path_lookup_intent_open(dfd, name, lookup_flags, nd, |
1133 | open_flags, 0); | 1173 | open_flags, 0); |
1134 | } | 1174 | } |
1135 | 1175 | ||
@@ -1141,12 +1181,12 @@ int path_lookup_open(const char *name, unsigned int lookup_flags, | |||
1141 | * @open_flags: open intent flags | 1181 | * @open_flags: open intent flags |
1142 | * @create_mode: create intent flags | 1182 | * @create_mode: create intent flags |
1143 | */ | 1183 | */ |
1144 | static int path_lookup_create(const char *name, unsigned int lookup_flags, | 1184 | static int path_lookup_create(int dfd, const char *name, |
1145 | struct nameidata *nd, int open_flags, | 1185 | unsigned int lookup_flags, struct nameidata *nd, |
1146 | int create_mode) | 1186 | int open_flags, int create_mode) |
1147 | { | 1187 | { |
1148 | return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd, | 1188 | return __path_lookup_intent_open(dfd, name, lookup_flags|LOOKUP_CREATE, |
1149 | open_flags, create_mode); | 1189 | nd, open_flags, create_mode); |
1150 | } | 1190 | } |
1151 | 1191 | ||
1152 | int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | 1192 | int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, |
@@ -1156,7 +1196,7 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | |||
1156 | int err = PTR_ERR(tmp); | 1196 | int err = PTR_ERR(tmp); |
1157 | 1197 | ||
1158 | if (!IS_ERR(tmp)) { | 1198 | if (!IS_ERR(tmp)) { |
1159 | err = __path_lookup_intent_open(tmp, lookup_flags, nd, open_flags, 0); | 1199 | err = __path_lookup_intent_open(AT_FDCWD, tmp, lookup_flags, nd, open_flags, 0); |
1160 | putname(tmp); | 1200 | putname(tmp); |
1161 | } | 1201 | } |
1162 | return err; | 1202 | return err; |
@@ -1248,18 +1288,24 @@ access: | |||
1248 | * that namei follows links, while lnamei does not. | 1288 | * that namei follows links, while lnamei does not. |
1249 | * SMP-safe | 1289 | * SMP-safe |
1250 | */ | 1290 | */ |
1251 | int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) | 1291 | int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags, |
1292 | struct nameidata *nd) | ||
1252 | { | 1293 | { |
1253 | char *tmp = getname(name); | 1294 | char *tmp = getname(name); |
1254 | int err = PTR_ERR(tmp); | 1295 | int err = PTR_ERR(tmp); |
1255 | 1296 | ||
1256 | if (!IS_ERR(tmp)) { | 1297 | if (!IS_ERR(tmp)) { |
1257 | err = path_lookup(tmp, flags, nd); | 1298 | err = do_path_lookup(dfd, tmp, flags, nd); |
1258 | putname(tmp); | 1299 | putname(tmp); |
1259 | } | 1300 | } |
1260 | return err; | 1301 | return err; |
1261 | } | 1302 | } |
1262 | 1303 | ||
1304 | int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) | ||
1305 | { | ||
1306 | return __user_walk_fd(AT_FDCWD, name, flags, nd); | ||
1307 | } | ||
1308 | |||
1263 | /* | 1309 | /* |
1264 | * It's inline, so penalty for filesystems that don't use sticky bit is | 1310 | * It's inline, so penalty for filesystems that don't use sticky bit is |
1265 | * minimal. | 1311 | * minimal. |
@@ -1518,7 +1564,8 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
1518 | * for symlinks (where the permissions are checked later). | 1564 | * for symlinks (where the permissions are checked later). |
1519 | * SMP-safe | 1565 | * SMP-safe |
1520 | */ | 1566 | */ |
1521 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | 1567 | int open_namei(int dfd, const char *pathname, int flag, |
1568 | int mode, struct nameidata *nd) | ||
1522 | { | 1569 | { |
1523 | int acc_mode, error; | 1570 | int acc_mode, error; |
1524 | struct path path; | 1571 | struct path path; |
@@ -1540,7 +1587,8 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
1540 | * The simplest case - just a plain lookup. | 1587 | * The simplest case - just a plain lookup. |
1541 | */ | 1588 | */ |
1542 | if (!(flag & O_CREAT)) { | 1589 | if (!(flag & O_CREAT)) { |
1543 | error = path_lookup_open(pathname, lookup_flags(flag), nd, flag); | 1590 | error = path_lookup_open(dfd, pathname, lookup_flags(flag), |
1591 | nd, flag); | ||
1544 | if (error) | 1592 | if (error) |
1545 | return error; | 1593 | return error; |
1546 | goto ok; | 1594 | goto ok; |
@@ -1549,7 +1597,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
1549 | /* | 1597 | /* |
1550 | * Create - we need to know the parent. | 1598 | * Create - we need to know the parent. |
1551 | */ | 1599 | */ |
1552 | error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode); | 1600 | error = path_lookup_create(dfd,pathname,LOOKUP_PARENT,nd,flag,mode); |
1553 | if (error) | 1601 | if (error) |
1554 | return error; | 1602 | return error; |
1555 | 1603 | ||
@@ -1744,7 +1792,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
1744 | return error; | 1792 | return error; |
1745 | } | 1793 | } |
1746 | 1794 | ||
1747 | asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) | 1795 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, |
1796 | unsigned dev) | ||
1748 | { | 1797 | { |
1749 | int error = 0; | 1798 | int error = 0; |
1750 | char * tmp; | 1799 | char * tmp; |
@@ -1757,7 +1806,7 @@ asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) | |||
1757 | if (IS_ERR(tmp)) | 1806 | if (IS_ERR(tmp)) |
1758 | return PTR_ERR(tmp); | 1807 | return PTR_ERR(tmp); |
1759 | 1808 | ||
1760 | error = path_lookup(tmp, LOOKUP_PARENT, &nd); | 1809 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); |
1761 | if (error) | 1810 | if (error) |
1762 | goto out; | 1811 | goto out; |
1763 | dentry = lookup_create(&nd, 0); | 1812 | dentry = lookup_create(&nd, 0); |
@@ -1793,6 +1842,11 @@ out: | |||
1793 | return error; | 1842 | return error; |
1794 | } | 1843 | } |
1795 | 1844 | ||
1845 | asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev) | ||
1846 | { | ||
1847 | return sys_mknodat(AT_FDCWD, filename, mode, dev); | ||
1848 | } | ||
1849 | |||
1796 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 1850 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
1797 | { | 1851 | { |
1798 | int error = may_create(dir, dentry, NULL); | 1852 | int error = may_create(dir, dentry, NULL); |
@@ -1815,7 +1869,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1815 | return error; | 1869 | return error; |
1816 | } | 1870 | } |
1817 | 1871 | ||
1818 | asmlinkage long sys_mkdir(const char __user * pathname, int mode) | 1872 | asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode) |
1819 | { | 1873 | { |
1820 | int error = 0; | 1874 | int error = 0; |
1821 | char * tmp; | 1875 | char * tmp; |
@@ -1826,7 +1880,7 @@ asmlinkage long sys_mkdir(const char __user * pathname, int mode) | |||
1826 | struct dentry *dentry; | 1880 | struct dentry *dentry; |
1827 | struct nameidata nd; | 1881 | struct nameidata nd; |
1828 | 1882 | ||
1829 | error = path_lookup(tmp, LOOKUP_PARENT, &nd); | 1883 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); |
1830 | if (error) | 1884 | if (error) |
1831 | goto out; | 1885 | goto out; |
1832 | dentry = lookup_create(&nd, 1); | 1886 | dentry = lookup_create(&nd, 1); |
@@ -1846,6 +1900,11 @@ out: | |||
1846 | return error; | 1900 | return error; |
1847 | } | 1901 | } |
1848 | 1902 | ||
1903 | asmlinkage long sys_mkdir(const char __user *pathname, int mode) | ||
1904 | { | ||
1905 | return sys_mkdirat(AT_FDCWD, pathname, mode); | ||
1906 | } | ||
1907 | |||
1849 | /* | 1908 | /* |
1850 | * We try to drop the dentry early: we should have | 1909 | * We try to drop the dentry early: we should have |
1851 | * a usage count of 2 if we're the only user of this | 1910 | * a usage count of 2 if we're the only user of this |
@@ -1907,7 +1966,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1907 | return error; | 1966 | return error; |
1908 | } | 1967 | } |
1909 | 1968 | ||
1910 | asmlinkage long sys_rmdir(const char __user * pathname) | 1969 | static long do_rmdir(int dfd, const char __user *pathname) |
1911 | { | 1970 | { |
1912 | int error = 0; | 1971 | int error = 0; |
1913 | char * name; | 1972 | char * name; |
@@ -1918,7 +1977,7 @@ asmlinkage long sys_rmdir(const char __user * pathname) | |||
1918 | if(IS_ERR(name)) | 1977 | if(IS_ERR(name)) |
1919 | return PTR_ERR(name); | 1978 | return PTR_ERR(name); |
1920 | 1979 | ||
1921 | error = path_lookup(name, LOOKUP_PARENT, &nd); | 1980 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); |
1922 | if (error) | 1981 | if (error) |
1923 | goto exit; | 1982 | goto exit; |
1924 | 1983 | ||
@@ -1948,6 +2007,11 @@ exit: | |||
1948 | return error; | 2007 | return error; |
1949 | } | 2008 | } |
1950 | 2009 | ||
2010 | asmlinkage long sys_rmdir(const char __user *pathname) | ||
2011 | { | ||
2012 | return do_rmdir(AT_FDCWD, pathname); | ||
2013 | } | ||
2014 | |||
1951 | int vfs_unlink(struct inode *dir, struct dentry *dentry) | 2015 | int vfs_unlink(struct inode *dir, struct dentry *dentry) |
1952 | { | 2016 | { |
1953 | int error = may_delete(dir, dentry, 0); | 2017 | int error = may_delete(dir, dentry, 0); |
@@ -1984,7 +2048,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1984 | * writeout happening, and we don't want to prevent access to the directory | 2048 | * writeout happening, and we don't want to prevent access to the directory |
1985 | * while waiting on the I/O. | 2049 | * while waiting on the I/O. |
1986 | */ | 2050 | */ |
1987 | asmlinkage long sys_unlink(const char __user * pathname) | 2051 | static long do_unlinkat(int dfd, const char __user *pathname) |
1988 | { | 2052 | { |
1989 | int error = 0; | 2053 | int error = 0; |
1990 | char * name; | 2054 | char * name; |
@@ -1996,7 +2060,7 @@ asmlinkage long sys_unlink(const char __user * pathname) | |||
1996 | if(IS_ERR(name)) | 2060 | if(IS_ERR(name)) |
1997 | return PTR_ERR(name); | 2061 | return PTR_ERR(name); |
1998 | 2062 | ||
1999 | error = path_lookup(name, LOOKUP_PARENT, &nd); | 2063 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); |
2000 | if (error) | 2064 | if (error) |
2001 | goto exit; | 2065 | goto exit; |
2002 | error = -EISDIR; | 2066 | error = -EISDIR; |
@@ -2031,6 +2095,22 @@ slashes: | |||
2031 | goto exit2; | 2095 | goto exit2; |
2032 | } | 2096 | } |
2033 | 2097 | ||
2098 | asmlinkage long sys_unlinkat(int dfd, const char __user *pathname, int flag) | ||
2099 | { | ||
2100 | if ((flag & ~AT_REMOVEDIR) != 0) | ||
2101 | return -EINVAL; | ||
2102 | |||
2103 | if (flag & AT_REMOVEDIR) | ||
2104 | return do_rmdir(dfd, pathname); | ||
2105 | |||
2106 | return do_unlinkat(dfd, pathname); | ||
2107 | } | ||
2108 | |||
2109 | asmlinkage long sys_unlink(const char __user *pathname) | ||
2110 | { | ||
2111 | return do_unlinkat(AT_FDCWD, pathname); | ||
2112 | } | ||
2113 | |||
2034 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) | 2114 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) |
2035 | { | 2115 | { |
2036 | int error = may_create(dir, dentry, NULL); | 2116 | int error = may_create(dir, dentry, NULL); |
@@ -2052,7 +2132,8 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i | |||
2052 | return error; | 2132 | return error; |
2053 | } | 2133 | } |
2054 | 2134 | ||
2055 | asmlinkage long sys_symlink(const char __user * oldname, const char __user * newname) | 2135 | asmlinkage long sys_symlinkat(const char __user *oldname, |
2136 | int newdfd, const char __user *newname) | ||
2056 | { | 2137 | { |
2057 | int error = 0; | 2138 | int error = 0; |
2058 | char * from; | 2139 | char * from; |
@@ -2067,7 +2148,7 @@ asmlinkage long sys_symlink(const char __user * oldname, const char __user * new | |||
2067 | struct dentry *dentry; | 2148 | struct dentry *dentry; |
2068 | struct nameidata nd; | 2149 | struct nameidata nd; |
2069 | 2150 | ||
2070 | error = path_lookup(to, LOOKUP_PARENT, &nd); | 2151 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); |
2071 | if (error) | 2152 | if (error) |
2072 | goto out; | 2153 | goto out; |
2073 | dentry = lookup_create(&nd, 0); | 2154 | dentry = lookup_create(&nd, 0); |
@@ -2085,6 +2166,11 @@ out: | |||
2085 | return error; | 2166 | return error; |
2086 | } | 2167 | } |
2087 | 2168 | ||
2169 | asmlinkage long sys_symlink(const char __user *oldname, const char __user *newname) | ||
2170 | { | ||
2171 | return sys_symlinkat(oldname, AT_FDCWD, newname); | ||
2172 | } | ||
2173 | |||
2088 | int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) | 2174 | int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) |
2089 | { | 2175 | { |
2090 | struct inode *inode = old_dentry->d_inode; | 2176 | struct inode *inode = old_dentry->d_inode; |
@@ -2132,7 +2218,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de | |||
2132 | * with linux 2.0, and to avoid hard-linking to directories | 2218 | * with linux 2.0, and to avoid hard-linking to directories |
2133 | * and other special files. --ADM | 2219 | * and other special files. --ADM |
2134 | */ | 2220 | */ |
2135 | asmlinkage long sys_link(const char __user * oldname, const char __user * newname) | 2221 | asmlinkage long sys_linkat(int olddfd, const char __user *oldname, |
2222 | int newdfd, const char __user *newname) | ||
2136 | { | 2223 | { |
2137 | struct dentry *new_dentry; | 2224 | struct dentry *new_dentry; |
2138 | struct nameidata nd, old_nd; | 2225 | struct nameidata nd, old_nd; |
@@ -2143,10 +2230,10 @@ asmlinkage long sys_link(const char __user * oldname, const char __user * newnam | |||
2143 | if (IS_ERR(to)) | 2230 | if (IS_ERR(to)) |
2144 | return PTR_ERR(to); | 2231 | return PTR_ERR(to); |
2145 | 2232 | ||
2146 | error = __user_walk(oldname, 0, &old_nd); | 2233 | error = __user_walk_fd(olddfd, oldname, 0, &old_nd); |
2147 | if (error) | 2234 | if (error) |
2148 | goto exit; | 2235 | goto exit; |
2149 | error = path_lookup(to, LOOKUP_PARENT, &nd); | 2236 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); |
2150 | if (error) | 2237 | if (error) |
2151 | goto out; | 2238 | goto out; |
2152 | error = -EXDEV; | 2239 | error = -EXDEV; |
@@ -2169,6 +2256,11 @@ exit: | |||
2169 | return error; | 2256 | return error; |
2170 | } | 2257 | } |
2171 | 2258 | ||
2259 | asmlinkage long sys_link(const char __user *oldname, const char __user *newname) | ||
2260 | { | ||
2261 | return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname); | ||
2262 | } | ||
2263 | |||
2172 | /* | 2264 | /* |
2173 | * The worst of all namespace operations - renaming directory. "Perverted" | 2265 | * The worst of all namespace operations - renaming directory. "Perverted" |
2174 | * doesn't even start to describe it. Somebody in UCB had a heck of a trip... | 2266 | * doesn't even start to describe it. Somebody in UCB had a heck of a trip... |
@@ -2315,7 +2407,8 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2315 | return error; | 2407 | return error; |
2316 | } | 2408 | } |
2317 | 2409 | ||
2318 | static int do_rename(const char * oldname, const char * newname) | 2410 | static int do_rename(int olddfd, const char *oldname, |
2411 | int newdfd, const char *newname) | ||
2319 | { | 2412 | { |
2320 | int error = 0; | 2413 | int error = 0; |
2321 | struct dentry * old_dir, * new_dir; | 2414 | struct dentry * old_dir, * new_dir; |
@@ -2323,11 +2416,11 @@ static int do_rename(const char * oldname, const char * newname) | |||
2323 | struct dentry * trap; | 2416 | struct dentry * trap; |
2324 | struct nameidata oldnd, newnd; | 2417 | struct nameidata oldnd, newnd; |
2325 | 2418 | ||
2326 | error = path_lookup(oldname, LOOKUP_PARENT, &oldnd); | 2419 | error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd); |
2327 | if (error) | 2420 | if (error) |
2328 | goto exit; | 2421 | goto exit; |
2329 | 2422 | ||
2330 | error = path_lookup(newname, LOOKUP_PARENT, &newnd); | 2423 | error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd); |
2331 | if (error) | 2424 | if (error) |
2332 | goto exit1; | 2425 | goto exit1; |
2333 | 2426 | ||
@@ -2391,7 +2484,8 @@ exit: | |||
2391 | return error; | 2484 | return error; |
2392 | } | 2485 | } |
2393 | 2486 | ||
2394 | asmlinkage long sys_rename(const char __user * oldname, const char __user * newname) | 2487 | asmlinkage long sys_renameat(int olddfd, const char __user *oldname, |
2488 | int newdfd, const char __user *newname) | ||
2395 | { | 2489 | { |
2396 | int error; | 2490 | int error; |
2397 | char * from; | 2491 | char * from; |
@@ -2403,13 +2497,18 @@ asmlinkage long sys_rename(const char __user * oldname, const char __user * newn | |||
2403 | to = getname(newname); | 2497 | to = getname(newname); |
2404 | error = PTR_ERR(to); | 2498 | error = PTR_ERR(to); |
2405 | if (!IS_ERR(to)) { | 2499 | if (!IS_ERR(to)) { |
2406 | error = do_rename(from,to); | 2500 | error = do_rename(olddfd, from, newdfd, to); |
2407 | putname(to); | 2501 | putname(to); |
2408 | } | 2502 | } |
2409 | putname(from); | 2503 | putname(from); |
2410 | return error; | 2504 | return error; |
2411 | } | 2505 | } |
2412 | 2506 | ||
2507 | asmlinkage long sys_rename(const char __user *oldname, const char __user *newname) | ||
2508 | { | ||
2509 | return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname); | ||
2510 | } | ||
2511 | |||
2413 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) | 2512 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) |
2414 | { | 2513 | { |
2415 | int len; | 2514 | int len; |
@@ -2553,6 +2652,7 @@ struct inode_operations page_symlink_inode_operations = { | |||
2553 | }; | 2652 | }; |
2554 | 2653 | ||
2555 | EXPORT_SYMBOL(__user_walk); | 2654 | EXPORT_SYMBOL(__user_walk); |
2655 | EXPORT_SYMBOL(__user_walk_fd); | ||
2556 | EXPORT_SYMBOL(follow_down); | 2656 | EXPORT_SYMBOL(follow_down); |
2557 | EXPORT_SYMBOL(follow_up); | 2657 | EXPORT_SYMBOL(follow_up); |
2558 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ | 2658 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ |
@@ -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 | /* |
@@ -63,12 +63,12 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
63 | 63 | ||
64 | EXPORT_SYMBOL(vfs_getattr); | 64 | EXPORT_SYMBOL(vfs_getattr); |
65 | 65 | ||
66 | int vfs_stat(char __user *name, struct kstat *stat) | 66 | int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat) |
67 | { | 67 | { |
68 | struct nameidata nd; | 68 | struct nameidata nd; |
69 | int error; | 69 | int error; |
70 | 70 | ||
71 | error = user_path_walk(name, &nd); | 71 | error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd); |
72 | if (!error) { | 72 | if (!error) { |
73 | error = vfs_getattr(nd.mnt, nd.dentry, stat); | 73 | error = vfs_getattr(nd.mnt, nd.dentry, stat); |
74 | path_release(&nd); | 74 | path_release(&nd); |
@@ -76,14 +76,19 @@ int vfs_stat(char __user *name, struct kstat *stat) | |||
76 | return error; | 76 | return error; |
77 | } | 77 | } |
78 | 78 | ||
79 | int vfs_stat(char __user *name, struct kstat *stat) | ||
80 | { | ||
81 | return vfs_stat_fd(AT_FDCWD, name, stat); | ||
82 | } | ||
83 | |||
79 | EXPORT_SYMBOL(vfs_stat); | 84 | EXPORT_SYMBOL(vfs_stat); |
80 | 85 | ||
81 | int vfs_lstat(char __user *name, struct kstat *stat) | 86 | int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat) |
82 | { | 87 | { |
83 | struct nameidata nd; | 88 | struct nameidata nd; |
84 | int error; | 89 | int error; |
85 | 90 | ||
86 | error = user_path_walk_link(name, &nd); | 91 | error = __user_walk_fd(dfd, name, 0, &nd); |
87 | if (!error) { | 92 | if (!error) { |
88 | error = vfs_getattr(nd.mnt, nd.dentry, stat); | 93 | error = vfs_getattr(nd.mnt, nd.dentry, stat); |
89 | path_release(&nd); | 94 | path_release(&nd); |
@@ -91,6 +96,11 @@ int vfs_lstat(char __user *name, struct kstat *stat) | |||
91 | return error; | 96 | return error; |
92 | } | 97 | } |
93 | 98 | ||
99 | int vfs_lstat(char __user *name, struct kstat *stat) | ||
100 | { | ||
101 | return vfs_lstat_fd(AT_FDCWD, name, stat); | ||
102 | } | ||
103 | |||
94 | EXPORT_SYMBOL(vfs_lstat); | 104 | EXPORT_SYMBOL(vfs_lstat); |
95 | 105 | ||
96 | int vfs_fstat(unsigned int fd, struct kstat *stat) | 106 | int vfs_fstat(unsigned int fd, struct kstat *stat) |
@@ -151,7 +161,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta | |||
151 | asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf) | 161 | asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf) |
152 | { | 162 | { |
153 | struct kstat stat; | 163 | struct kstat stat; |
154 | int error = vfs_stat(filename, &stat); | 164 | int error = vfs_stat_fd(AT_FDCWD, filename, &stat); |
155 | 165 | ||
156 | if (!error) | 166 | if (!error) |
157 | error = cp_old_stat(&stat, statbuf); | 167 | error = cp_old_stat(&stat, statbuf); |
@@ -161,7 +171,7 @@ asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user | |||
161 | asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) | 171 | asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) |
162 | { | 172 | { |
163 | struct kstat stat; | 173 | struct kstat stat; |
164 | int error = vfs_lstat(filename, &stat); | 174 | int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); |
165 | 175 | ||
166 | if (!error) | 176 | if (!error) |
167 | error = cp_old_stat(&stat, statbuf); | 177 | error = cp_old_stat(&stat, statbuf); |
@@ -229,27 +239,50 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) | |||
229 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; | 239 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; |
230 | } | 240 | } |
231 | 241 | ||
232 | asmlinkage long sys_newstat(char __user * filename, struct stat __user * statbuf) | 242 | asmlinkage long sys_newstat(char __user *filename, struct stat __user *statbuf) |
233 | { | 243 | { |
234 | struct kstat stat; | 244 | struct kstat stat; |
235 | int error = vfs_stat(filename, &stat); | 245 | int error = vfs_stat_fd(AT_FDCWD, filename, &stat); |
236 | 246 | ||
237 | if (!error) | 247 | if (!error) |
238 | error = cp_new_stat(&stat, statbuf); | 248 | error = cp_new_stat(&stat, statbuf); |
239 | 249 | ||
240 | return error; | 250 | return error; |
241 | } | 251 | } |
242 | asmlinkage long sys_newlstat(char __user * filename, struct stat __user * statbuf) | 252 | |
253 | asmlinkage long sys_newlstat(char __user *filename, struct stat __user *statbuf) | ||
243 | { | 254 | { |
244 | struct kstat stat; | 255 | struct kstat stat; |
245 | int error = vfs_lstat(filename, &stat); | 256 | int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); |
246 | 257 | ||
247 | if (!error) | 258 | if (!error) |
248 | error = cp_new_stat(&stat, statbuf); | 259 | error = cp_new_stat(&stat, statbuf); |
249 | 260 | ||
250 | return error; | 261 | return error; |
251 | } | 262 | } |
252 | asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf) | 263 | |
264 | asmlinkage long sys_newfstatat(int dfd, char __user *filename, | ||
265 | struct stat __user *statbuf, int flag) | ||
266 | { | ||
267 | struct kstat stat; | ||
268 | int error = -EINVAL; | ||
269 | |||
270 | if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) | ||
271 | goto out; | ||
272 | |||
273 | if (flag & AT_SYMLINK_NOFOLLOW) | ||
274 | error = vfs_lstat_fd(dfd, filename, &stat); | ||
275 | else | ||
276 | error = vfs_stat_fd(dfd, filename, &stat); | ||
277 | |||
278 | if (!error) | ||
279 | error = cp_new_stat(&stat, statbuf); | ||
280 | |||
281 | out: | ||
282 | return error; | ||
283 | } | ||
284 | |||
285 | asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf) | ||
253 | { | 286 | { |
254 | struct kstat stat; | 287 | struct kstat stat; |
255 | int error = vfs_fstat(fd, &stat); | 288 | int error = vfs_fstat(fd, &stat); |
@@ -260,7 +293,8 @@ asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf) | |||
260 | return error; | 293 | return error; |
261 | } | 294 | } |
262 | 295 | ||
263 | asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bufsiz) | 296 | asmlinkage long sys_readlinkat(int dfd, const char __user *path, |
297 | char __user *buf, int bufsiz) | ||
264 | { | 298 | { |
265 | struct nameidata nd; | 299 | struct nameidata nd; |
266 | int error; | 300 | int error; |
@@ -268,7 +302,7 @@ asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bu | |||
268 | if (bufsiz <= 0) | 302 | if (bufsiz <= 0) |
269 | return -EINVAL; | 303 | return -EINVAL; |
270 | 304 | ||
271 | error = user_path_walk_link(path, &nd); | 305 | error = __user_walk_fd(dfd, path, 0, &nd); |
272 | if (!error) { | 306 | if (!error) { |
273 | struct inode * inode = nd.dentry->d_inode; | 307 | struct inode * inode = nd.dentry->d_inode; |
274 | 308 | ||
@@ -285,6 +319,12 @@ asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bu | |||
285 | return error; | 319 | return error; |
286 | } | 320 | } |
287 | 321 | ||
322 | asmlinkage long sys_readlink(const char __user *path, char __user *buf, | ||
323 | int bufsiz) | ||
324 | { | ||
325 | return sys_readlinkat(AT_FDCWD, path, buf, bufsiz); | ||
326 | } | ||
327 | |||
288 | 328 | ||
289 | /* ---------- LFS-64 ----------- */ | 329 | /* ---------- LFS-64 ----------- */ |
290 | #ifdef __ARCH_WANT_STAT64 | 330 | #ifdef __ARCH_WANT_STAT64 |