Commit 9bf01f06 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] (2/5) beginning of getattr series.

stat(2) variants in arch/* that used to copy inode fields manually
switched to vfs_*stat() and partially cleaned up
parent 70902864
...@@ -282,120 +282,64 @@ ia64_create_module (const char *name_user, size_t size, long arg2, long arg3, ...@@ -282,120 +282,64 @@ ia64_create_module (const char *name_user, size_t size, long arg2, long arg3,
* call - it will be removed later once everybody migrates to the new * call - it will be removed later once everybody migrates to the new
* kernel stat structure that matches the glibc one - Jes * kernel stat structure that matches the glibc one - Jes
*/ */
static __inline__ int
do_revalidate (struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
if (inode->i_op && inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
return 0;
}
static int static int
cp_ia64_old_stat (struct inode *inode, struct ia64_oldstat *statbuf) cp_ia64_old_stat (struct kstat *stat, struct ia64_oldstat *statbuf)
{ {
struct ia64_oldstat tmp; struct ia64_oldstat tmp;
unsigned int blocks, indirect; unsigned int blocks, indirect;
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
tmp.st_dev = kdev_t_to_nr(inode->i_dev); tmp.st_dev = stat->dev;
tmp.st_ino = inode->i_ino; tmp.st_ino = stat->ino;
tmp.st_mode = inode->i_mode; tmp.st_mode = stat->mode;
tmp.st_nlink = inode->i_nlink; tmp.st_nlink = stat->nlink;
SET_STAT_UID(tmp, inode->i_uid); SET_STAT_UID(tmp, stat->uid);
SET_STAT_GID(tmp, inode->i_gid); SET_STAT_GID(tmp, stat->gid);
tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); tmp.st_rdev = stat->rdev;
tmp.st_size = inode->i_size; tmp.st_size = stat->size;
tmp.st_atime = inode->i_atime; tmp.st_atime = stat->atime;
tmp.st_mtime = inode->i_mtime; tmp.st_mtime = stat->mtime;
tmp.st_ctime = inode->i_ctime; tmp.st_ctime = stat->ctime;
/* tmp.st_blocks = stat->i_blocks;
* st_blocks and st_blksize are approximated with a simple algorithm if tmp.st_blksize = stat->i_blksize;
* they aren't supported directly by the filesystem. The minix and msdos
* filesystems don't keep track of blocks, so they would either have to
* be counted explicitly (by delving into the file itself), or by using
* this simple algorithm to get a reasonable (although not 100% accurate)
* value.
*/
/*
* Use minix fs values for the number of direct and indirect blocks. The
* count is now exact for the minix fs except that it counts zero blocks.
* Everything is in units of BLOCK_SIZE until the assignment to
* tmp.st_blksize.
*/
#define D_B 7
#define I_B (BLOCK_SIZE / sizeof(unsigned short))
if (!inode->i_blksize) {
blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
if (blocks > D_B) {
indirect = (blocks - D_B + I_B - 1) / I_B;
blocks += indirect;
if (indirect > 1) {
indirect = (indirect - 1 + I_B - 1) / I_B;
blocks += indirect;
if (indirect > 1)
blocks++;
}
}
tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
tmp.st_blksize = BLOCK_SIZE;
} else {
tmp.st_blocks = inode->i_blocks;
tmp.st_blksize = inode->i_blksize;
}
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
} }
asmlinkage long asmlinkage long
ia64_oldstat (char *filename, struct ia64_oldstat *statbuf) ia64_oldstat (char *filename, struct ia64_oldstat *statbuf)
{ {
struct nameidata nd; struct kstat stat;
int error; int error = vfs_stat(filename, &stat);
error = user_path_walk(filename, &nd); if (!error)
if (!error) { error = cp_ia64_old_stat(&stat, statbuf);
error = do_revalidate(nd.dentry);
if (!error)
error = cp_ia64_old_stat(nd.dentry->d_inode, statbuf);
path_release(&nd);
}
return error; return error;
} }
asmlinkage long asmlinkage long
ia64_oldlstat (char *filename, struct ia64_oldstat *statbuf) { ia64_oldlstat (char *filename, struct ia64_oldstat *statbuf)
struct nameidata nd; {
int error; struct kstat stat;
int error = vfs_lstat(filename, &stat);
error = user_path_walk_link(filename, &nd);
if (!error) { if (!error)
error = do_revalidate(nd.dentry); error = cp_ia64_old_stat(&stat, statbuf);
if (!error)
error = cp_ia64_old_stat(nd.dentry->d_inode, statbuf);
path_release(&nd);
}
return error; return error;
} }
asmlinkage long asmlinkage long
ia64_oldfstat (unsigned int fd, struct ia64_oldstat *statbuf) ia64_oldfstat (unsigned int fd, struct ia64_oldstat *statbuf)
{ {
struct file * f; struct kstat stat;
int err = -EBADF; int error = vfs_fstat(fd, &stat);
f = fget(fd); if (!error)
if (f) { error = cp_ia64_old_stat(&stat, statbuf);
struct dentry * dentry = f->f_dentry;
err = do_revalidate(dentry); return error;
if (!err)
err = cp_ia64_old_stat(dentry->d_inode, statbuf);
fput(f);
}
return err;
} }
#endif #endif
......
...@@ -39,125 +39,59 @@ ...@@ -39,125 +39,59 @@
/* /*
* Revalidate the inode. This is required for proper NFS attribute caching. * Revalidate the inode. This is required for proper NFS attribute caching.
*/ */
static __inline__ int
do_revalidate(struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
if (inode->i_op && inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
return 0; static int cp_new_stat32(struct kstat *stat, struct stat32 *statbuf)
}
static int cp_new_stat32(struct inode * inode, struct stat32 * statbuf)
{ {
struct stat32 tmp; struct stat32 tmp;
unsigned int blocks, indirect;
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
tmp.st_dev = kdev_t_to_nr(inode->i_dev); tmp.st_dev = stat->dev;
tmp.st_ino = inode->i_ino; tmp.st_ino = stat->ino;
tmp.st_mode = inode->i_mode; tmp.st_mode = stat->mode;
tmp.st_nlink = inode->i_nlink; tmp.st_nlink = stat->nlink;
SET_STAT_UID(tmp, inode->i_uid); SET_STAT_UID(tmp, stat->uid);
SET_STAT_GID(tmp, inode->i_gid); SET_STAT_GID(tmp, stat->gid);
tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); tmp.st_rdev = stat->rdev;
tmp.st_size = inode->i_size; tmp.st_size = stat->size;
tmp.st_atime = inode->i_atime; tmp.st_atime = stat->atime;
tmp.st_mtime = inode->i_mtime; tmp.st_mtime = stat->mtime;
tmp.st_ctime = inode->i_ctime; tmp.st_ctime = stat->ctime;
tmp.st_blocks = stat->blocks;
/* tmp.st_blksize = stat->blksize;
* st_blocks and st_blksize are approximated with a simple algorithm if
* they aren't supported directly by the filesystem. The minix and msdos
* filesystems don't keep track of blocks, so they would either have to
* be counted explicitly (by delving into the file itself), or by using
* this simple algorithm to get a reasonable (although not 100%
* accurate) value.
*/
/*
* Use minix fs values for the number of direct and indirect blocks.
* The count is now exact for the minix fs except that it counts zero
* blocks. Everything is in units of BLOCK_SIZE until the assignment
* to tmp.st_blksize.
*/
#define D_B 7
#define I_B (BLOCK_SIZE / sizeof(unsigned short))
if (!inode->i_blksize) {
blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
if (blocks > D_B) {
indirect = (blocks - D_B + I_B - 1) / I_B;
blocks += indirect;
if (indirect > 1) {
indirect = (indirect - 1 + I_B - 1) / I_B;
blocks += indirect;
if (indirect > 1)
blocks++;
}
}
tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
tmp.st_blksize = BLOCK_SIZE;
} else {
tmp.st_blocks = inode->i_blocks;
tmp.st_blksize = inode->i_blksize;
}
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
} }
asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf) asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
{ {
struct nameidata nd; struct kstat stat;
int error; int error = vfs_stat(filename, &stat);
error = user_path_walk(filename, &nd); if (!error)
if (!error) { error = cp_new_stat32(&stat, statbuf);
error = do_revalidate(nd.dentry);
if (!error)
error = cp_new_stat32(nd.dentry->d_inode, statbuf);
path_release(&nd);
}
return error; return error;
} }
asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf) asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
{ {
struct nameidata nd; struct kstat stat;
int error; int error = vfs_lstat(filename, &stat);
error = user_path_walk_link(filename, &nd); if (!error)
if (!error) { error = cp_new_stat32(&stat, statbuf);
error = do_revalidate(nd.dentry);
if (!error)
error = cp_new_stat32(nd.dentry->d_inode, statbuf);
path_release(&nd);
}
return error; return error;
} }
asmlinkage long sys32_newfstat(unsigned int fd, struct stat32 * statbuf) asmlinkage long sys32_newfstat(unsigned int fd, struct stat32 * statbuf)
{ {
struct file * f; struct kstat stat;
int err = -EBADF; int error = vfs_fstat(fd, &stat);
f = fget(fd);
if (f) {
struct dentry * dentry = f->f_dentry;
err = do_revalidate(dentry); if (!error)
if (!err) error = cp_new_stat32(&stat, statbuf);
err = cp_new_stat32(dentry->d_inode, statbuf);
fput(f);
}
return err; return error;
} }
asmlinkage int sys_mmap2(void) {return 0;} asmlinkage int sys_mmap2(void) {return 0;}
......
...@@ -141,110 +141,56 @@ int hpux_mount(const char *fs, const char *path, int mflag, ...@@ -141,110 +141,56 @@ int hpux_mount(const char *fs, const char *path, int mflag,
return -ENOSYS; return -ENOSYS;
} }
static int cp_hpux_stat(struct inode * inode, struct hpux_stat64 * statbuf) static int cp_hpux_stat(struct kstat *stat, struct hpux_stat64 *statbuf)
{ {
struct hpux_stat64 tmp; struct hpux_stat64 tmp;
unsigned int blocks, indirect;
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
tmp.st_dev = kdev_t_to_nr(inode->i_dev); tmp.st_dev = stat->dev;
tmp.st_ino = inode->i_ino; tmp.st_ino = stat->ino;
tmp.st_mode = inode->i_mode; tmp.st_mode = stat->mode;
tmp.st_nlink = inode->i_nlink; tmp.st_nlink = stat->nlink;
tmp.st_uid = inode->i_uid; tmp.st_uid = stat->uid;
tmp.st_gid = inode->i_gid; tmp.st_gid = stat->gid;
tmp.st_rdev = kdev_t_to_nr(inode->i_rdev); tmp.st_rdev = stat->rdev;
tmp.st_size = inode->i_size; tmp.st_size = stat->size;
tmp.st_atime = inode->i_atime; tmp.st_atime = stat->atime;
tmp.st_mtime = inode->i_mtime; tmp.st_mtime = stat->mtime;
tmp.st_ctime = inode->i_ctime; tmp.st_ctime = stat->ctime;
tmp.st_blocks = stat->blocks;
#define D_B 7 tmp.st_blksize = stat->blksize;
#define I_B (BLOCK_SIZE / sizeof(unsigned short))
if (!inode->i_blksize) {
blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
if (blocks > D_B) {
indirect = (blocks - D_B + I_B - 1) / I_B;
blocks += indirect;
if (indirect > 1) {
indirect = (indirect - 1 + I_B - 1) / I_B;
blocks += indirect;
if (indirect > 1)
blocks++;
}
}
tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
tmp.st_blksize = BLOCK_SIZE;
} else {
tmp.st_blocks = inode->i_blocks;
tmp.st_blksize = inode->i_blksize;
}
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
} }
/*
* Revalidate the inode. This is required for proper NFS attribute caching.
* Blatently copied wholesale from fs/stat.c
*/
static __inline__ int
do_revalidate(struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
if (inode->i_op && inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
return 0;
}
long hpux_stat64(const char *path, struct hpux_stat64 *buf) long hpux_stat64(const char *path, struct hpux_stat64 *buf)
{ {
struct nameidata nd; struct kstat stat;
int error; int error = vfs_stat(filename, &stat);
if (!error)
error = cp_hpux_stat(&stat, statbuf);
lock_kernel();
error = user_path_walk(path, &nd);
if (!error) {
error = do_revalidate(nd.dentry);
if (!error)
error = cp_hpux_stat(nd.dentry->d_inode, buf);
path_release(&nd);
}
unlock_kernel();
return error; return error;
} }
long hpux_fstat64(unsigned int fd, struct hpux_stat64 *statbuf) long hpux_fstat64(unsigned int fd, struct hpux_stat64 *statbuf)
{ {
struct file * f; struct kstat stat;
int err = -EBADF; int error = vfs_fstat(fd, &stat);
lock_kernel(); if (!error)
f = fget(fd); error = cp_hpux_stat(&stat, statbuf);
if (f) {
struct dentry * dentry = f->f_dentry; return error;
err = do_revalidate(dentry);
if (!err)
err = cp_hpux_stat(dentry->d_inode, statbuf);
fput(f);
}
unlock_kernel();
return err;
} }
long hpux_lstat64(char *filename, struct hpux_stat64 *statbuf) long hpux_lstat64(char *filename, struct hpux_stat64 *statbuf)
{ {
struct nameidata nd; struct kstat stat;
int error; int error = vfs_lstat(filename, &stat);
if (!error)
error = cp_hpux_stat(&stat, statbuf);
lock_kernel();
error = user_path_walk_link(filename, &nd);
if (!error) {
error = do_revalidate(nd.dentry);
if (!error)
error = cp_hpux_stat(nd.dentry->d_inode, statbuf);
path_release(&nd);
}
unlock_kernel();
return error; return error;
} }
...@@ -1471,140 +1471,62 @@ asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x) ...@@ -1471,140 +1471,62 @@ asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
return ret; return ret;
} }
static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf) static int cp_new_stat32(struct kstat *stat, struct stat32 *statbuf)
{ {
unsigned long ino, blksize, blocks; err = put_user(stat->dev, &statbuf->st_dev);
kdev_t dev, rdev; err |= put_user(stat->ino, &statbuf->st_ino);
umode_t mode; err |= put_user(stat->mode, &statbuf->st_mode);
nlink_t nlink; err |= put_user(stat->nlink, &statbuf->st_nlink);
uid_t uid; err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
gid_t gid; err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
off_t size; err |= put_user(stat->rdev, &statbuf->st_rdev);
time_t atime, mtime, ctime; err |= put_user(stat->size, &statbuf->st_size);
int err; err |= put_user(stat->atime, &statbuf->st_atime);
/* Stream the loads of inode data into the load buffer,
* then we push it all into the store buffer below. This
* should give optimal cache performance.
*/
ino = inode->i_ino;
dev = inode->i_dev;
mode = inode->i_mode;
nlink = inode->i_nlink;
uid = inode->i_uid;
gid = inode->i_gid;
rdev = inode->i_rdev;
size = inode->i_size;
atime = inode->i_atime;
mtime = inode->i_mtime;
ctime = inode->i_ctime;
blksize = inode->i_blksize;
blocks = inode->i_blocks;
err = put_user(kdev_t_to_nr(dev), &statbuf->st_dev);
err |= put_user(ino, &statbuf->st_ino);
err |= put_user(mode, &statbuf->st_mode);
err |= put_user(nlink, &statbuf->st_nlink);
err |= put_user(high2lowuid(uid), &statbuf->st_uid);
err |= put_user(high2lowgid(gid), &statbuf->st_gid);
err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev);
err |= put_user(size, &statbuf->st_size);
err |= put_user(atime, &statbuf->st_atime);
err |= put_user(0, &statbuf->__unused1); err |= put_user(0, &statbuf->__unused1);
err |= put_user(mtime, &statbuf->st_mtime); err |= put_user(stat->mtime, &statbuf->st_mtime);
err |= put_user(0, &statbuf->__unused2); err |= put_user(0, &statbuf->__unused2);
err |= put_user(ctime, &statbuf->st_ctime); err |= put_user(stat->ctime, &statbuf->st_ctime);
err |= put_user(0, &statbuf->__unused3); err |= put_user(0, &statbuf->__unused3);
if (blksize) { err |= put_user(stat->blksize, &statbuf->st_blksize);
err |= put_user(blksize, &statbuf->st_blksize); err |= put_user(stat->blocks, &statbuf->st_blocks);
err |= put_user(blocks, &statbuf->st_blocks);
} else {
unsigned int tmp_blocks;
#define D_B 7
#define I_B (BLOCK_SIZE / sizeof(unsigned short))
tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
if (tmp_blocks > D_B) {
unsigned int indirect;
indirect = (tmp_blocks - D_B + I_B - 1) / I_B;
tmp_blocks += indirect;
if (indirect > 1) {
indirect = (indirect - 1 + I_B - 1) / I_B;
tmp_blocks += indirect;
if (indirect > 1)
tmp_blocks++;
}
}
err |= put_user(BLOCK_SIZE, &statbuf->st_blksize);
err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks);
#undef D_B
#undef I_B
}
/* fixme /* fixme
err |= put_user(0, &statbuf->__unused4[0]); err |= put_user(0, &statbuf->__unused4[0]);
err |= put_user(0, &statbuf->__unused4[1]); err |= put_user(0, &statbuf->__unused4[1]);
*/ */
return err; return err;
} }
/* Perhaps this belongs in fs.h or similar. -DaveM */
static __inline__ int
do_revalidate(struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
if (inode->i_op && inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
return 0;
}
asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf) asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
{ {
struct nameidata nd; struct kstat stat;
int error; int error = vfs_stat(filename, &stat);
if (!error)
error = cp_new_stat32(&stat, statbuf);
error = user_path_walk(filename, &nd);
if (!error) {
error = do_revalidate(nd.dentry);
if (!error)
error = cp_new_stat32(nd.dentry->d_inode, statbuf);
path_release(&nd);
}
return error; return error;
} }
asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf) asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
{ {
struct nameidata nd; struct kstat stat;
int error; int error = vfs_lstat(filename, &stat);
error = user_path_walk_link(filename, &nd); if (!error)
if (!error) { error = cp_new_stat32(&stat, statbuf);
error = do_revalidate(nd.dentry);
if (!error)
error = cp_new_stat32(nd.dentry->d_inode, statbuf);
path_release(&nd);
}
return error; return error;
} }
asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf) asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
{ {
struct file *f; struct kstat stat;
int err = -EBADF; int error = vfs_fstat(fd, &stat);
f = fget(fd); if (!error)
if (f) { error = cp_new_stat32(&stat, statbuf);
struct dentry * dentry = f->f_dentry;
err = do_revalidate(dentry); return error;
if (!err)
err = cp_new_stat32(dentry->d_inode, statbuf);
fput(f);
}
return err;
} }
extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2); extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
......
...@@ -1459,138 +1459,60 @@ asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x) ...@@ -1459,138 +1459,60 @@ asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
return ret; return ret;
} }
static int cp_new_stat32(struct inode *inode, struct stat32 *statbuf) static int cp_new_stat32(struct kstat *stat, struct stat32 *statbuf)
{ {
unsigned long ino, blksize, blocks; err = put_user(stat->dev, &statbuf->st_dev);
kdev_t dev, rdev; err |= put_user(stat->ino, &statbuf->st_ino);
umode_t mode; err |= put_user(stat->mode, &statbuf->st_mode);
nlink_t nlink; err |= put_user(stat->nlink, &statbuf->st_nlink);
uid_t uid; err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
gid_t gid; err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
off_t size; err |= put_user(stat->rdev, &statbuf->st_rdev);
time_t atime, mtime, ctime; err |= put_user(stat->size, &statbuf->st_size);
int err; err |= put_user(stat->atime, &statbuf->st_atime);
/* Stream the loads of inode data into the load buffer,
* then we push it all into the store buffer below. This
* should give optimal cache performance.
*/
ino = inode->i_ino;
dev = inode->i_dev;
mode = inode->i_mode;
nlink = inode->i_nlink;
uid = inode->i_uid;
gid = inode->i_gid;
rdev = inode->i_rdev;
size = inode->i_size;
atime = inode->i_atime;
mtime = inode->i_mtime;
ctime = inode->i_ctime;
blksize = inode->i_blksize;
blocks = inode->i_blocks;
err = put_user(kdev_t_to_nr(dev), &statbuf->st_dev);
err |= put_user(ino, &statbuf->st_ino);
err |= put_user(mode, &statbuf->st_mode);
err |= put_user(nlink, &statbuf->st_nlink);
err |= put_user(high2lowuid(uid), &statbuf->st_uid);
err |= put_user(high2lowgid(gid), &statbuf->st_gid);
err |= put_user(kdev_t_to_nr(rdev), &statbuf->st_rdev);
err |= put_user(size, &statbuf->st_size);
err |= put_user(atime, &statbuf->st_atime);
err |= put_user(0, &statbuf->__unused1); err |= put_user(0, &statbuf->__unused1);
err |= put_user(mtime, &statbuf->st_mtime); err |= put_user(stat->mtime, &statbuf->st_mtime);
err |= put_user(0, &statbuf->__unused2); err |= put_user(0, &statbuf->__unused2);
err |= put_user(ctime, &statbuf->st_ctime); err |= put_user(stat->ctime, &statbuf->st_ctime);
err |= put_user(0, &statbuf->__unused3); err |= put_user(0, &statbuf->__unused3);
if (blksize) { err |= put_user(stat->blksize, &statbuf->st_blksize);
err |= put_user(blksize, &statbuf->st_blksize); err |= put_user(stat->blocks, &statbuf->st_blocks);
err |= put_user(blocks, &statbuf->st_blocks);
} else {
unsigned int tmp_blocks;
#define D_B 7
#define I_B (BLOCK_SIZE / sizeof(unsigned short))
tmp_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
if (tmp_blocks > D_B) {
unsigned int indirect;
indirect = (tmp_blocks - D_B + I_B - 1) / I_B;
tmp_blocks += indirect;
if (indirect > 1) {
indirect = (indirect - 1 + I_B - 1) / I_B;
tmp_blocks += indirect;
if (indirect > 1)
tmp_blocks++;
}
}
err |= put_user(BLOCK_SIZE, &statbuf->st_blksize);
err |= put_user((BLOCK_SIZE / 512) * tmp_blocks, &statbuf->st_blocks);
#undef D_B
#undef I_B
}
err |= put_user(0, &statbuf->__unused4[0]); err |= put_user(0, &statbuf->__unused4[0]);
err |= put_user(0, &statbuf->__unused4[1]); err |= put_user(0, &statbuf->__unused4[1]);
return err; return err;
} }
/* Perhaps this belongs in fs.h or similar. -DaveM */
static __inline__ int
do_revalidate(struct dentry *dentry)
{
struct inode * inode = dentry->d_inode;
if (inode->i_op && inode->i_op->revalidate)
return inode->i_op->revalidate(dentry);
return 0;
}
asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf) asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
{ {
struct nameidata nd; struct kstat stat;
int error; int error = vfs_stat(filename, &stat);
if (!error)
error = cp_new_stat32(&stat, statbuf);
error = user_path_walk(filename, &nd);
if (!error) {
error = do_revalidate(nd.dentry);
if (!error)
error = cp_new_stat32(nd.dentry->d_inode, statbuf);
path_release(&nd);
}
return error; return error;
} }
asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf) asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
{ {
struct nameidata nd; struct kstat stat;
int error; int error = vfs_lstat(filename, &stat);
error = user_path_walk_link(filename, &nd); if (!error)
if (!error) { error = cp_new_stat32(&stat, statbuf);
error = do_revalidate(nd.dentry);
if (!error)
error = cp_new_stat32(nd.dentry->d_inode, statbuf);
path_release(&nd);
}
return error; return error;
} }
asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf) asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
{ {
struct file *f; struct kstat stat;
int err = -EBADF; int error = vfs_fstat(fd, &stat);
f = fget(fd); if (!error)
if (f) { error = cp_new_stat32(&stat, statbuf);
struct dentry * dentry = f->f_dentry;
err = do_revalidate(dentry); return error;
if (!err)
err = cp_new_stat32(dentry->d_inode, statbuf);
fput(f);
}
return err;
} }
extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2); extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment