X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fstat.c;h=d4e81886fa83766202fd9ccbd3fd7aa4f1d94d78;hb=7d8b6f8e7158f0f307fb8315de1fb962f0c717d9;hp=f28e994d7b40232749a86c6176068582c7639019;hpb=bc77d24c47b89f1e0efed0b8e4be5f8aad102883;p=linux-2.6.git diff --git a/fs/stat.c b/fs/stat.c index f28e994d7..d4e81886f 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -4,7 +4,6 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#include #include #include #include @@ -14,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -26,13 +27,14 @@ 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->tag = inode->i_tag; stat->rdev = inode->i_rdev; stat->atime = inode->i_atime; stat->mtime = inode->i_mtime; stat->ctime = inode->i_ctime; stat->size = i_size_read(inode); stat->blocks = inode->i_blocks; - stat->blksize = inode->i_blksize; + stat->blksize = (1 << inode->i_blkbits); } EXPORT_SYMBOL(generic_fillattr); @@ -50,24 +52,17 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) return inode->i_op->getattr(mnt, dentry, stat); generic_fillattr(inode, stat); - if (!stat->blksize) { - struct super_block *s = inode->i_sb; - unsigned blocks; - blocks = (stat->size+s->s_blocksize-1) >> s->s_blocksize_bits; - stat->blocks = (s->s_blocksize / 512) * blocks; - stat->blksize = s->s_blocksize; - } return 0; } 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 +70,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 +90,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) @@ -98,7 +103,7 @@ int vfs_fstat(unsigned int fd, struct kstat *stat) int error = -EBADF; if (f) { - error = vfs_getattr(f->f_vfsmnt, f->f_dentry, stat); + error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat); fput(f); } return error; @@ -129,8 +134,12 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta memset(&tmp, 0, sizeof(struct __old_kernel_stat)); tmp.st_dev = old_encode_dev(stat->dev); tmp.st_ino = stat->ino; + if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) + return -EOVERFLOW; 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 +157,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 +167,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); @@ -197,8 +206,12 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) tmp.st_dev = new_encode_dev(stat->dev); #endif tmp.st_ino = stat->ino; + if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) + return -EOVERFLOW; 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 +237,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 +293,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 +302,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 +319,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 @@ -300,6 +345,8 @@ static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) tmp.st_rdev = huge_encode_dev(stat->rdev); #endif tmp.st_ino = stat->ino; + if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) + return -EOVERFLOW; #ifdef STAT64_HAS_BROKEN_ST_INO tmp.__st_ino = stat->ino; #endif @@ -350,6 +397,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)