diff options
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 |