2005-04-17 02:20:36 +04:00
/*
* linux / fs / stat . c
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*/
2011-11-17 08:57:37 +04:00
# include <linux/export.h>
2005-04-17 02:20:36 +04:00
# include <linux/mm.h>
# include <linux/errno.h>
# include <linux/file.h>
# include <linux/highuid.h>
# include <linux/fs.h>
# include <linux/namei.h>
# include <linux/security.h>
# include <linux/syscalls.h>
2006-09-27 12:50:49 +04:00
# include <linux/pagemap.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <asm/unistd.h>
void generic_fillattr ( struct inode * inode , struct kstat * stat )
{
stat - > dev = inode - > i_sb - > s_dev ;
stat - > ino = inode - > i_ino ;
stat - > mode = inode - > i_mode ;
stat - > nlink = inode - > i_nlink ;
stat - > uid = inode - > i_uid ;
stat - > gid = inode - > i_gid ;
stat - > rdev = inode - > i_rdev ;
2011-08-07 09:45:50 +04:00
stat - > size = i_size_read ( inode ) ;
2005-04-17 02:20:36 +04:00
stat - > atime = inode - > i_atime ;
stat - > mtime = inode - > i_mtime ;
stat - > ctime = inode - > i_ctime ;
2006-09-27 12:50:49 +04:00
stat - > blksize = ( 1 < < inode - > i_blkbits ) ;
2011-08-07 09:45:50 +04:00
stat - > blocks = inode - > i_blocks ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( generic_fillattr ) ;
int vfs_getattr ( struct vfsmount * mnt , struct dentry * dentry , struct kstat * stat )
{
struct inode * inode = dentry - > d_inode ;
int retval ;
retval = security_inode_getattr ( mnt , dentry ) ;
if ( retval )
return retval ;
if ( inode - > i_op - > getattr )
return inode - > i_op - > getattr ( mnt , dentry , stat ) ;
generic_fillattr ( inode , stat ) ;
return 0 ;
}
EXPORT_SYMBOL ( vfs_getattr ) ;
int vfs_fstat ( unsigned int fd , struct kstat * stat )
{
struct file * f = fget ( fd ) ;
int error = - EBADF ;
if ( f ) {
2006-12-08 13:36:35 +03:00
error = vfs_getattr ( f - > f_path . mnt , f - > f_path . dentry , stat ) ;
2005-04-17 02:20:36 +04:00
fput ( f ) ;
}
return error ;
}
EXPORT_SYMBOL ( vfs_fstat ) ;
2010-08-11 14:26:22 +04:00
int vfs_fstatat ( int dfd , const char __user * filename , struct kstat * stat ,
int flag )
2009-04-08 20:05:42 +04:00
{
2009-04-09 00:34:03 +04:00
struct path path ;
2009-04-08 20:05:42 +04:00
int error = - EINVAL ;
2009-04-09 00:34:03 +04:00
int lookup_flags = 0 ;
2009-04-08 20:05:42 +04:00
2011-03-13 22:56:26 +03:00
if ( ( flag & ~ ( AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
AT_EMPTY_PATH ) ) ! = 0 )
2009-04-08 20:05:42 +04:00
goto out ;
2009-04-09 00:34:03 +04:00
if ( ! ( flag & AT_SYMLINK_NOFOLLOW ) )
lookup_flags | = LOOKUP_FOLLOW ;
2011-03-13 22:56:26 +03:00
if ( flag & AT_EMPTY_PATH )
lookup_flags | = LOOKUP_EMPTY ;
2009-04-09 00:34:03 +04:00
error = user_path_at ( dfd , filename , lookup_flags , & path ) ;
if ( error )
goto out ;
error = vfs_getattr ( path . mnt , path . dentry , stat ) ;
path_put ( & path ) ;
2009-04-08 20:05:42 +04:00
out :
return error ;
}
EXPORT_SYMBOL ( vfs_fstatat ) ;
2010-08-11 14:26:22 +04:00
int vfs_stat ( const char __user * name , struct kstat * stat )
2009-04-09 00:34:03 +04:00
{
return vfs_fstatat ( AT_FDCWD , name , stat , 0 ) ;
}
EXPORT_SYMBOL ( vfs_stat ) ;
2010-08-11 14:26:22 +04:00
int vfs_lstat ( const char __user * name , struct kstat * stat )
2009-04-09 00:34:03 +04:00
{
return vfs_fstatat ( AT_FDCWD , name , stat , AT_SYMLINK_NOFOLLOW ) ;
}
EXPORT_SYMBOL ( vfs_lstat ) ;
2009-04-08 20:05:42 +04:00
2005-04-17 02:20:36 +04:00
# ifdef __ARCH_WANT_OLD_STAT
/*
* For backward compatibility ? Maybe this should be moved
* into arch / i386 instead ?
*/
static int cp_old_stat ( struct kstat * stat , struct __old_kernel_stat __user * statbuf )
{
static int warncount = 5 ;
struct __old_kernel_stat tmp ;
if ( warncount > 0 ) {
warncount - - ;
printk ( KERN_WARNING " VFS: Warning: %s using old stat() call. Recompile your binary. \n " ,
current - > comm ) ;
} else if ( warncount < 0 ) {
/* it's laughable, but... */
warncount = 0 ;
}
memset ( & tmp , 0 , sizeof ( struct __old_kernel_stat ) ) ;
tmp . st_dev = old_encode_dev ( stat - > dev ) ;
tmp . st_ino = stat - > ino ;
2006-10-03 12:13:46 +04:00
if ( sizeof ( tmp . st_ino ) < sizeof ( stat - > ino ) & & tmp . st_ino ! = stat - > ino )
return - EOVERFLOW ;
2005-04-17 02:20:36 +04:00
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 ) ;
# if BITS_PER_LONG == 32
if ( stat - > size > MAX_NON_LFS )
return - EOVERFLOW ;
# endif
tmp . st_size = stat - > size ;
tmp . st_atime = stat - > atime . tv_sec ;
tmp . st_mtime = stat - > mtime . tv_sec ;
tmp . st_ctime = stat - > ctime . tv_sec ;
return copy_to_user ( statbuf , & tmp , sizeof ( tmp ) ) ? - EFAULT : 0 ;
}
2010-08-11 14:26:22 +04:00
SYSCALL_DEFINE2 ( stat , const char __user * , filename ,
struct __old_kernel_stat __user * , statbuf )
2005-04-17 02:20:36 +04:00
{
struct kstat stat ;
2009-04-09 00:34:03 +04:00
int error ;
2005-04-17 02:20:36 +04:00
2009-04-09 00:34:03 +04:00
error = vfs_stat ( filename , & stat ) ;
if ( error )
return error ;
2005-04-17 02:20:36 +04:00
2009-04-09 00:34:03 +04:00
return cp_old_stat ( & stat , statbuf ) ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 16:14:13 +03:00
2010-08-11 14:26:22 +04:00
SYSCALL_DEFINE2 ( lstat , const char __user * , filename ,
struct __old_kernel_stat __user * , statbuf )
2005-04-17 02:20:36 +04:00
{
struct kstat stat ;
2009-04-09 00:34:03 +04:00
int error ;
2005-04-17 02:20:36 +04:00
2009-04-09 00:34:03 +04:00
error = vfs_lstat ( filename , & stat ) ;
if ( error )
return error ;
2005-04-17 02:20:36 +04:00
2009-04-09 00:34:03 +04:00
return cp_old_stat ( & stat , statbuf ) ;
2005-04-17 02:20:36 +04:00
}
2009-01-14 16:14:13 +03:00
SYSCALL_DEFINE2 ( fstat , unsigned int , fd , struct __old_kernel_stat __user * , statbuf )
2005-04-17 02:20:36 +04:00
{
struct kstat stat ;
int error = vfs_fstat ( fd , & stat ) ;
if ( ! error )
error = cp_old_stat ( & stat , statbuf ) ;
return error ;
}
# endif /* __ARCH_WANT_OLD_STAT */
static int cp_new_stat ( struct kstat * stat , struct stat __user * statbuf )
{
struct stat tmp ;
# if BITS_PER_LONG == 32
if ( ! old_valid_dev ( stat - > dev ) | | ! old_valid_dev ( stat - > rdev ) )
return - EOVERFLOW ;
# else
if ( ! new_valid_dev ( stat - > dev ) | | ! new_valid_dev ( stat - > rdev ) )
return - EOVERFLOW ;
# endif
memset ( & tmp , 0 , sizeof ( tmp ) ) ;
# if BITS_PER_LONG == 32
tmp . st_dev = old_encode_dev ( stat - > dev ) ;
# else
tmp . st_dev = new_encode_dev ( stat - > dev ) ;
# endif
tmp . st_ino = stat - > ino ;
2006-10-03 12:13:46 +04:00
if ( sizeof ( tmp . st_ino ) < sizeof ( stat - > ino ) & & tmp . st_ino ! = stat - > ino )
return - EOVERFLOW ;
2005-04-17 02:20:36 +04:00
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
tmp . st_rdev = old_encode_dev ( stat - > rdev ) ;
# else
tmp . st_rdev = new_encode_dev ( stat - > rdev ) ;
# endif
# if BITS_PER_LONG == 32
if ( stat - > size > MAX_NON_LFS )
return - EOVERFLOW ;
# endif
tmp . st_size = stat - > size ;
tmp . st_atime = stat - > atime . tv_sec ;
tmp . st_mtime = stat - > mtime . tv_sec ;
tmp . st_ctime = stat - > ctime . tv_sec ;
# ifdef STAT_HAVE_NSEC
tmp . st_atime_nsec = stat - > atime . tv_nsec ;
tmp . st_mtime_nsec = stat - > mtime . tv_nsec ;
tmp . st_ctime_nsec = stat - > ctime . tv_nsec ;
# endif
tmp . st_blocks = stat - > blocks ;
tmp . st_blksize = stat - > blksize ;
return copy_to_user ( statbuf , & tmp , sizeof ( tmp ) ) ? - EFAULT : 0 ;
}
2010-08-11 14:26:22 +04:00
SYSCALL_DEFINE2 ( newstat , const char __user * , filename ,
struct stat __user * , statbuf )
2006-01-19 04:43:53 +03:00
{
struct kstat stat ;
2009-04-09 00:34:03 +04:00
int error = vfs_stat ( filename , & stat ) ;
2006-01-19 04:43:53 +03:00
2009-04-09 00:34:03 +04:00
if ( error )
return error ;
return cp_new_stat ( & stat , statbuf ) ;
2006-01-19 04:43:53 +03:00
}
2010-08-11 14:26:22 +04:00
SYSCALL_DEFINE2 ( newlstat , const char __user * , filename ,
struct stat __user * , statbuf )
2005-04-17 02:20:36 +04:00
{
struct kstat stat ;
2009-04-09 00:34:03 +04:00
int error ;
2005-04-17 02:20:36 +04:00
2009-04-09 00:34:03 +04:00
error = vfs_lstat ( filename , & stat ) ;
if ( error )
return error ;
2005-04-17 02:20:36 +04:00
2009-04-09 00:34:03 +04:00
return cp_new_stat ( & stat , statbuf ) ;
2005-04-17 02:20:36 +04:00
}
2006-01-19 04:43:53 +03:00
2006-04-27 17:46:42 +04:00
# if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT)
2010-08-11 14:26:22 +04:00
SYSCALL_DEFINE4 ( newfstatat , int , dfd , const char __user * , filename ,
2009-01-14 16:14:32 +03:00
struct stat __user * , statbuf , int , flag )
2005-04-17 02:20:36 +04:00
{
struct kstat stat ;
2009-04-08 20:05:42 +04:00
int error ;
2005-04-17 02:20:36 +04:00
2009-04-08 20:05:42 +04:00
error = vfs_fstatat ( dfd , filename , & stat , flag ) ;
if ( error )
return error ;
return cp_new_stat ( & stat , statbuf ) ;
2005-04-17 02:20:36 +04:00
}
2006-02-12 04:55:47 +03:00
# endif
2006-01-19 04:43:53 +03:00
2009-01-14 16:14:13 +03:00
SYSCALL_DEFINE2 ( newfstat , unsigned int , fd , struct stat __user * , statbuf )
2005-04-17 02:20:36 +04:00
{
struct kstat stat ;
int error = vfs_fstat ( fd , & stat ) ;
if ( ! error )
error = cp_new_stat ( & stat , statbuf ) ;
return error ;
}
2009-01-14 16:14:32 +03:00
SYSCALL_DEFINE4 ( readlinkat , int , dfd , const char __user * , pathname ,
char __user * , buf , int , bufsiz )
2005-04-17 02:20:36 +04:00
{
2008-07-22 17:59:21 +04:00
struct path path ;
2005-04-17 02:20:36 +04:00
int error ;
2011-11-02 12:44:39 +04:00
int empty = 0 ;
2005-04-17 02:20:36 +04:00
if ( bufsiz < = 0 )
return - EINVAL ;
2011-11-02 12:44:39 +04:00
error = user_path_at_empty ( dfd , pathname , LOOKUP_EMPTY , & path , & empty ) ;
2005-04-17 02:20:36 +04:00
if ( ! error ) {
2008-07-22 17:59:21 +04:00
struct inode * inode = path . dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
2011-11-02 12:44:39 +04:00
error = empty ? - ENOENT : - EINVAL ;
2008-12-04 18:06:33 +03:00
if ( inode - > i_op - > readlink ) {
2008-07-22 17:59:21 +04:00
error = security_inode_readlink ( path . dentry ) ;
2005-04-17 02:20:36 +04:00
if ( ! error ) {
2012-03-15 16:21:57 +04:00
touch_atime ( & path ) ;
2008-07-22 17:59:21 +04:00
error = inode - > i_op - > readlink ( path . dentry ,
2008-02-15 06:34:32 +03:00
buf , bufsiz ) ;
2005-04-17 02:20:36 +04:00
}
}
2008-07-22 17:59:21 +04:00
path_put ( & path ) ;
2005-04-17 02:20:36 +04:00
}
return error ;
}
2009-01-14 16:14:18 +03:00
SYSCALL_DEFINE3 ( readlink , const char __user * , path , char __user * , buf ,
int , bufsiz )
2006-01-19 04:43:53 +03:00
{
return sys_readlinkat ( AT_FDCWD , path , buf , bufsiz ) ;
}
2005-04-17 02:20:36 +04:00
/* ---------- LFS-64 ----------- */
# ifdef __ARCH_WANT_STAT64
static long cp_new_stat64 ( struct kstat * stat , struct stat64 __user * statbuf )
{
struct stat64 tmp ;
memset ( & tmp , 0 , sizeof ( struct stat64 ) ) ;
# ifdef CONFIG_MIPS
/* mips has weird padding, so we don't get 64 bits there */
if ( ! new_valid_dev ( stat - > dev ) | | ! new_valid_dev ( stat - > rdev ) )
return - EOVERFLOW ;
tmp . st_dev = new_encode_dev ( stat - > dev ) ;
tmp . st_rdev = new_encode_dev ( stat - > rdev ) ;
# else
tmp . st_dev = huge_encode_dev ( stat - > dev ) ;
tmp . st_rdev = huge_encode_dev ( stat - > rdev ) ;
# endif
tmp . st_ino = stat - > ino ;
2006-10-03 12:13:46 +04:00
if ( sizeof ( tmp . st_ino ) < sizeof ( stat - > ino ) & & tmp . st_ino ! = stat - > ino )
return - EOVERFLOW ;
2005-04-17 02:20:36 +04:00
# ifdef STAT64_HAS_BROKEN_ST_INO
tmp . __st_ino = stat - > ino ;
# endif
tmp . st_mode = stat - > mode ;
tmp . st_nlink = stat - > nlink ;
tmp . st_uid = stat - > uid ;
tmp . st_gid = stat - > gid ;
tmp . st_atime = stat - > atime . tv_sec ;
tmp . st_atime_nsec = stat - > atime . tv_nsec ;
tmp . st_mtime = stat - > mtime . tv_sec ;
tmp . st_mtime_nsec = stat - > mtime . tv_nsec ;
tmp . st_ctime = stat - > ctime . tv_sec ;
tmp . st_ctime_nsec = stat - > ctime . tv_nsec ;
tmp . st_size = stat - > size ;
tmp . st_blocks = stat - > blocks ;
tmp . st_blksize = stat - > blksize ;
return copy_to_user ( statbuf , & tmp , sizeof ( tmp ) ) ? - EFAULT : 0 ;
}
2010-08-11 14:26:22 +04:00
SYSCALL_DEFINE2 ( stat64 , const char __user * , filename ,
struct stat64 __user * , statbuf )
2005-04-17 02:20:36 +04:00
{
struct kstat stat ;
int error = vfs_stat ( filename , & stat ) ;
if ( ! error )
error = cp_new_stat64 ( & stat , statbuf ) ;
return error ;
}
2009-01-14 16:14:13 +03:00
2010-08-11 14:26:22 +04:00
SYSCALL_DEFINE2 ( lstat64 , const char __user * , filename ,
struct stat64 __user * , statbuf )
2005-04-17 02:20:36 +04:00
{
struct kstat stat ;
int error = vfs_lstat ( filename , & stat ) ;
if ( ! error )
error = cp_new_stat64 ( & stat , statbuf ) ;
return error ;
}
2009-01-14 16:14:13 +03:00
SYSCALL_DEFINE2 ( fstat64 , unsigned long , fd , struct stat64 __user * , statbuf )
2005-04-17 02:20:36 +04:00
{
struct kstat stat ;
int error = vfs_fstat ( fd , & stat ) ;
if ( ! error )
error = cp_new_stat64 ( & stat , statbuf ) ;
return error ;
}
2010-08-11 14:26:22 +04:00
SYSCALL_DEFINE4 ( fstatat64 , int , dfd , const char __user * , filename ,
2009-01-14 16:14:32 +03:00
struct stat64 __user * , statbuf , int , flag )
2006-02-12 04:55:47 +03:00
{
struct kstat stat ;
2009-04-08 20:05:42 +04:00
int error ;
2006-02-12 04:55:47 +03:00
2009-04-08 20:05:42 +04:00
error = vfs_fstatat ( dfd , filename , & stat , flag ) ;
if ( error )
return error ;
return cp_new_stat64 ( & stat , statbuf ) ;
2006-02-12 04:55:47 +03:00
}
2005-04-17 02:20:36 +04:00
# endif /* __ARCH_WANT_STAT64 */
2009-12-14 15:21:12 +03:00
/* Caller is here responsible for sufficient locking (ie. inode->i_lock) */
void __inode_add_bytes ( struct inode * inode , loff_t bytes )
2005-04-17 02:20:36 +04:00
{
inode - > i_blocks + = bytes > > 9 ;
bytes & = 511 ;
inode - > i_bytes + = bytes ;
if ( inode - > i_bytes > = 512 ) {
inode - > i_blocks + + ;
inode - > i_bytes - = 512 ;
}
2009-12-14 15:21:12 +03:00
}
void inode_add_bytes ( struct inode * inode , loff_t bytes )
{
spin_lock ( & inode - > i_lock ) ;
__inode_add_bytes ( inode , bytes ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & inode - > i_lock ) ;
}
EXPORT_SYMBOL ( inode_add_bytes ) ;
void inode_sub_bytes ( struct inode * inode , loff_t bytes )
{
spin_lock ( & inode - > i_lock ) ;
inode - > i_blocks - = bytes > > 9 ;
bytes & = 511 ;
if ( inode - > i_bytes < bytes ) {
inode - > i_blocks - - ;
inode - > i_bytes + = 512 ;
}
inode - > i_bytes - = bytes ;
spin_unlock ( & inode - > i_lock ) ;
}
EXPORT_SYMBOL ( inode_sub_bytes ) ;
loff_t inode_get_bytes ( struct inode * inode )
{
loff_t ret ;
spin_lock ( & inode - > i_lock ) ;
ret = ( ( ( loff_t ) inode - > i_blocks ) < < 9 ) + inode - > i_bytes ;
spin_unlock ( & inode - > i_lock ) ;
return ret ;
}
EXPORT_SYMBOL ( inode_get_bytes ) ;
void inode_set_bytes ( struct inode * inode , loff_t bytes )
{
/* Caller is here responsible for sufficient locking
* ( ie . inode - > i_lock ) */
inode - > i_blocks = bytes > > 9 ;
inode - > i_bytes = bytes & 511 ;
}
EXPORT_SYMBOL ( inode_set_bytes ) ;