Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / fs / stat.c
index f28e994..b8babca 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -14,6 +14,7 @@
 #include <linux/fs.h>
 #include <linux/namei.h>
 #include <linux/security.h>
+#include <linux/syscalls.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -26,6 +27,7 @@ void generic_fillattr(struct inode *inode, struct kstat *stat)
        stat->nlink = inode->i_nlink;
        stat->uid = inode->i_uid;
        stat->gid = inode->i_gid;
+       stat->xid = inode->i_xid;
        stat->rdev = inode->i_rdev;
        stat->atime = inode->i_atime;
        stat->mtime = inode->i_mtime;
@@ -62,12 +64,12 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 
 EXPORT_SYMBOL(vfs_getattr);
 
-int vfs_stat(char __user *name, struct kstat *stat)
+int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
 {
        struct nameidata nd;
        int error;
 
-       error = user_path_walk(name, &nd);
+       error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd);
        if (!error) {
                error = vfs_getattr(nd.mnt, nd.dentry, stat);
                path_release(&nd);
@@ -75,14 +77,19 @@ int vfs_stat(char __user *name, struct kstat *stat)
        return error;
 }
 
+int vfs_stat(char __user *name, struct kstat *stat)
+{
+       return vfs_stat_fd(AT_FDCWD, name, stat);
+}
+
 EXPORT_SYMBOL(vfs_stat);
 
-int vfs_lstat(char __user *name, struct kstat *stat)
+int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat)
 {
        struct nameidata nd;
        int error;
 
-       error = user_path_walk_link(name, &nd);
+       error = __user_walk_fd(dfd, name, 0, &nd);
        if (!error) {
                error = vfs_getattr(nd.mnt, nd.dentry, stat);
                path_release(&nd);
@@ -90,6 +97,11 @@ int vfs_lstat(char __user *name, struct kstat *stat)
        return error;
 }
 
+int vfs_lstat(char __user *name, struct kstat *stat)
+{
+       return vfs_lstat_fd(AT_FDCWD, name, stat);
+}
+
 EXPORT_SYMBOL(vfs_lstat);
 
 int vfs_fstat(unsigned int fd, struct kstat *stat)
@@ -131,6 +143,8 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta
        tmp.st_ino = stat->ino;
        tmp.st_mode = stat->mode;
        tmp.st_nlink = stat->nlink;
+       if (tmp.st_nlink != stat->nlink)
+               return -EOVERFLOW;
        SET_UID(tmp.st_uid, stat->uid);
        SET_GID(tmp.st_gid, stat->gid);
        tmp.st_rdev = old_encode_dev(stat->rdev);
@@ -148,7 +162,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta
 asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf)
 {
        struct kstat stat;
-       int error = vfs_stat(filename, &stat);
+       int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
 
        if (!error)
                error = cp_old_stat(&stat, statbuf);
@@ -158,7 +172,7 @@ asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user
 asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf)
 {
        struct kstat stat;
-       int error = vfs_lstat(filename, &stat);
+       int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
 
        if (!error)
                error = cp_old_stat(&stat, statbuf);
@@ -199,6 +213,8 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
        tmp.st_ino = stat->ino;
        tmp.st_mode = stat->mode;
        tmp.st_nlink = stat->nlink;
+       if (tmp.st_nlink != stat->nlink)
+               return -EOVERFLOW;
        SET_UID(tmp.st_uid, stat->uid);
        SET_GID(tmp.st_gid, stat->gid);
 #if BITS_PER_LONG == 32
@@ -224,27 +240,52 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
        return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 }
 
-asmlinkage long sys_newstat(char __user * filename, struct stat __user * statbuf)
+asmlinkage long sys_newstat(char __user *filename, struct stat __user *statbuf)
 {
        struct kstat stat;
-       int error = vfs_stat(filename, &stat);
+       int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
 
        if (!error)
                error = cp_new_stat(&stat, statbuf);
 
        return error;
 }
-asmlinkage long sys_newlstat(char __user * filename, struct stat __user * statbuf)
+
+asmlinkage long sys_newlstat(char __user *filename, struct stat __user *statbuf)
 {
        struct kstat stat;
-       int error = vfs_lstat(filename, &stat);
+       int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
 
        if (!error)
                error = cp_new_stat(&stat, statbuf);
 
        return error;
 }
-asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf)
+
+#if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT)
+asmlinkage long sys_newfstatat(int dfd, char __user *filename,
+                               struct stat __user *statbuf, int flag)
+{
+       struct kstat stat;
+       int error = -EINVAL;
+
+       if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
+               goto out;
+
+       if (flag & AT_SYMLINK_NOFOLLOW)
+               error = vfs_lstat_fd(dfd, filename, &stat);
+       else
+               error = vfs_stat_fd(dfd, filename, &stat);
+
+       if (!error)
+               error = cp_new_stat(&stat, statbuf);
+
+out:
+       return error;
+}
+#endif
+
+asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf)
 {
        struct kstat stat;
        int error = vfs_fstat(fd, &stat);
@@ -255,7 +296,8 @@ asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf)
        return error;
 }
 
-asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bufsiz)
+asmlinkage long sys_readlinkat(int dfd, const char __user *path,
+                               char __user *buf, int bufsiz)
 {
        struct nameidata nd;
        int error;
@@ -263,7 +305,7 @@ asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bu
        if (bufsiz <= 0)
                return -EINVAL;
 
-       error = user_path_walk_link(path, &nd);
+       error = __user_walk_fd(dfd, path, 0, &nd);
        if (!error) {
                struct inode * inode = nd.dentry->d_inode;
 
@@ -280,6 +322,12 @@ asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bu
        return error;
 }
 
+asmlinkage long sys_readlink(const char __user *path, char __user *buf,
+                               int bufsiz)
+{
+       return sys_readlinkat(AT_FDCWD, path, buf, bufsiz);
+}
+
 
 /* ---------- LFS-64 ----------- */
 #ifdef __ARCH_WANT_STAT64
@@ -350,6 +398,26 @@ asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user * statbuf)
        return error;
 }
 
+asmlinkage long sys_fstatat64(int dfd, char __user *filename,
+                              struct stat64 __user *statbuf, int flag)
+{
+       struct kstat stat;
+       int error = -EINVAL;
+
+       if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
+               goto out;
+
+       if (flag & AT_SYMLINK_NOFOLLOW)
+               error = vfs_lstat_fd(dfd, filename, &stat);
+       else
+               error = vfs_stat_fd(dfd, filename, &stat);
+
+       if (!error)
+               error = cp_new_stat64(&stat, statbuf);
+
+out:
+       return error;
+}
 #endif /* __ARCH_WANT_STAT64 */
 
 void inode_add_bytes(struct inode *inode, loff_t bytes)