aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2006-01-18 20:43:53 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-18 22:20:29 -0500
commit5590ff0d5528b60153c0b4e7b771472b5a95e297 (patch)
tree5fdccf2354269702f71beb8e0a2942e4167fd992 /fs
parente2f99018eb7b29954747a2dd78e9fc0c36a60f0f (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.c48
-rw-r--r--fs/exec.c2
-rw-r--r--fs/namei.c172
-rw-r--r--fs/open.c83
-rw-r--r--fs/stat.c66
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
74asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t) 74asmlinkage 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
88asmlinkage 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
88asmlinkage long compat_sys_newstat(char __user * filename, 93asmlinkage 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
115asmlinkage 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
132out:
133 return error;
134}
135
110asmlinkage long compat_sys_newfstat(unsigned int fd, 136asmlinkage 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:
1290asmlinkage long 1316asmlinkage long
1291compat_sys_open(const char __user *filename, int flags, int mode) 1317compat_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 */
1326asmlinkage long
1327compat_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/*
diff --git a/fs/exec.c b/fs/exec.c
index 62b40af68cc4..055378d2513e 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -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. */
1066int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) 1068static 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(&current->fs->lock); 1122 read_unlock(&current->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);
1129out_fail:
1097 return retval; 1130 return retval;
1098} 1131}
1099 1132
1100static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags, 1133int 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
1139static 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 */
1129int path_lookup_open(const char *name, unsigned int lookup_flags, 1169int 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 */
1144static int path_lookup_create(const char *name, unsigned int lookup_flags, 1184static 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
1152int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, 1192int __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 */
1251int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) 1291int 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
1304int 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 */
1521int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) 1567int 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
1747asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) 1795asmlinkage 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
1845asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev)
1846{
1847 return sys_mknodat(AT_FDCWD, filename, mode, dev);
1848}
1849
1796int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 1850int 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
1818asmlinkage long sys_mkdir(const char __user * pathname, int mode) 1872asmlinkage 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
1903asmlinkage 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
1910asmlinkage long sys_rmdir(const char __user * pathname) 1969static 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
2010asmlinkage long sys_rmdir(const char __user *pathname)
2011{
2012 return do_rmdir(AT_FDCWD, pathname);
2013}
2014
1951int vfs_unlink(struct inode *dir, struct dentry *dentry) 2015int 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 */
1987asmlinkage long sys_unlink(const char __user * pathname) 2051static 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
2098asmlinkage 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
2109asmlinkage long sys_unlink(const char __user *pathname)
2110{
2111 return do_unlinkat(AT_FDCWD, pathname);
2112}
2113
2034int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) 2114int 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
2055asmlinkage long sys_symlink(const char __user * oldname, const char __user * newname) 2135asmlinkage 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
2169asmlinkage long sys_symlink(const char __user *oldname, const char __user *newname)
2170{
2171 return sys_symlinkat(oldname, AT_FDCWD, newname);
2172}
2173
2088int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) 2174int 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 */
2135asmlinkage long sys_link(const char __user * oldname, const char __user * newname) 2221asmlinkage 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
2259asmlinkage 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
2318static int do_rename(const char * oldname, const char * newname) 2410static 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
2394asmlinkage long sys_rename(const char __user * oldname, const char __user * newname) 2487asmlinkage 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
2507asmlinkage long sys_rename(const char __user *oldname, const char __user *newname)
2508{
2509 return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname);
2510}
2511
2413int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) 2512int 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
2555EXPORT_SYMBOL(__user_walk); 2654EXPORT_SYMBOL(__user_walk);
2655EXPORT_SYMBOL(__user_walk_fd);
2556EXPORT_SYMBOL(follow_down); 2656EXPORT_SYMBOL(follow_down);
2557EXPORT_SYMBOL(follow_up); 2657EXPORT_SYMBOL(follow_up);
2558EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ 2658EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
diff --git a/fs/open.c b/fs/open.c
index 8e20c1f32563..70e0230d8e77 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -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, &times->actime); 385 error = get_user(newattrs.ia_atime.tv_sec, &times->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, &times->modtime); 388 error = get_user(newattrs.ia_mtime.tv_sec, &times->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 */
417long do_utimes(char __user * filename, struct timeval * times) 418long 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
464asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utimes) 465asmlinkage 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(&times, utimes, sizeof(times))) 469 if (utimes && copy_from_user(&times, 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
474asmlinkage 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 */
479asmlinkage long sys_access(const char __user * filename, int mode) 485asmlinkage 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
532asmlinkage long sys_access(const char __user *filename, int mode)
533{
534 return sys_faccessat(AT_FDCWD, filename, mode);
535}
536
526asmlinkage long sys_chdir(const char __user * filename) 537asmlinkage 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
638asmlinkage long sys_chmod(const char __user * filename, mode_t mode) 649asmlinkage 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
684asmlinkage long sys_chmod(const char __user *filename, mode_t mode)
685{
686 return sys_fchmodat(AT_FDCWD, filename, mode);
687}
688
672static int chown_common(struct dentry * dentry, uid_t user, gid_t group) 689static 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
737asmlinkage 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 }
753out:
754 return error;
755}
756
720asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) 757asmlinkage 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 */
823struct file *filp_open(const char * filename, int flags, int mode) 860static 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
877struct file *filp_open(const char *filename, int flags, int mode)
878{
879 return do_filp_open(AT_FDCWD, filename, flags, mode);
880}
838EXPORT_SYMBOL(filp_open); 881EXPORT_SYMBOL(filp_open);
839 882
840/** 883/**
@@ -991,7 +1034,7 @@ void fastcall put_unused_fd(unsigned int fd)
991EXPORT_SYMBOL(put_unused_fd); 1034EXPORT_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
1017EXPORT_SYMBOL(fd_install); 1060EXPORT_SYMBOL(fd_install);
1018 1061
1019long do_sys_open(const char __user *filename, int flags, int mode) 1062long 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}
1048EXPORT_SYMBOL_GPL(sys_open); 1091EXPORT_SYMBOL_GPL(sys_open);
1049 1092
1093asmlinkage 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}
1101EXPORT_SYMBOL_GPL(sys_openat);
1102
1050#ifndef __alpha__ 1103#ifndef __alpha__
1051 1104
1052/* 1105/*
diff --git a/fs/stat.c b/fs/stat.c
index b8a0e5110ab2..24211b030f39 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -63,12 +63,12 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
63 63
64EXPORT_SYMBOL(vfs_getattr); 64EXPORT_SYMBOL(vfs_getattr);
65 65
66int vfs_stat(char __user *name, struct kstat *stat) 66int 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
79int vfs_stat(char __user *name, struct kstat *stat)
80{
81 return vfs_stat_fd(AT_FDCWD, name, stat);
82}
83
79EXPORT_SYMBOL(vfs_stat); 84EXPORT_SYMBOL(vfs_stat);
80 85
81int vfs_lstat(char __user *name, struct kstat *stat) 86int 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
99int vfs_lstat(char __user *name, struct kstat *stat)
100{
101 return vfs_lstat_fd(AT_FDCWD, name, stat);
102}
103
94EXPORT_SYMBOL(vfs_lstat); 104EXPORT_SYMBOL(vfs_lstat);
95 105
96int vfs_fstat(unsigned int fd, struct kstat *stat) 106int 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
151asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf) 161asmlinkage 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
161asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) 171asmlinkage 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
232asmlinkage long sys_newstat(char __user * filename, struct stat __user * statbuf) 242asmlinkage 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}
242asmlinkage long sys_newlstat(char __user * filename, struct stat __user * statbuf) 252
253asmlinkage 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}
252asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf) 263
264asmlinkage 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
281out:
282 return error;
283}
284
285asmlinkage 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
263asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bufsiz) 296asmlinkage 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
322asmlinkage 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