linux-old/fs/stat.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/stat.c
   3 *
   4 *  Copyright (C) 1991, 1992  Linus Torvalds
   5 */
   6
   7#include <linux/config.h>
   8#include <linux/mm.h>
   9#include <linux/errno.h>
  10#include <linux/file.h>
  11#include <linux/smp_lock.h>
  12#include <linux/highuid.h>
  13
  14#include <asm/uaccess.h>
  15
  16/*
  17 * Revalidate the inode. This is required for proper NFS attribute caching.
  18 */
  19static __inline__ int
  20do_revalidate(struct dentry *dentry)
  21{
  22        struct inode * inode = dentry->d_inode;
  23        if (inode->i_op && inode->i_op->revalidate)
  24                return inode->i_op->revalidate(dentry);
  25        return 0;
  26}
  27
  28
  29#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
  30
  31/*
  32 * For backward compatibility?  Maybe this should be moved
  33 * into arch/i386 instead?
  34 */
  35static int cp_old_stat(struct inode * inode, struct __old_kernel_stat * statbuf)
  36{
  37        static int warncount = 5;
  38        struct __old_kernel_stat tmp;
  39
  40        if (warncount > 0) {
  41                warncount--;
  42                printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n",
  43                        current->comm);
  44        } else if (warncount < 0) {
  45                /* it's laughable, but... */
  46                warncount = 0;
  47        }
  48
  49        tmp.st_dev = kdev_t_to_nr(inode->i_dev);
  50        tmp.st_ino = inode->i_ino;
  51        tmp.st_mode = inode->i_mode;
  52        tmp.st_nlink = inode->i_nlink;
  53        SET_OLDSTAT_UID(tmp, inode->i_uid);
  54        SET_OLDSTAT_GID(tmp, inode->i_gid);
  55        tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
  56#if BITS_PER_LONG == 32
  57        if (inode->i_size > MAX_NON_LFS)
  58                return -EOVERFLOW;
  59#endif  
  60        tmp.st_size = inode->i_size;
  61        tmp.st_atime = inode->i_atime;
  62        tmp.st_mtime = inode->i_mtime;
  63        tmp.st_ctime = inode->i_ctime;
  64        return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
  65}
  66
  67#endif
  68
  69static int cp_new_stat(struct inode * inode, struct stat * statbuf)
  70{
  71        struct stat tmp;
  72        unsigned int blocks, indirect;
  73
  74        memset(&tmp, 0, sizeof(tmp));
  75        tmp.st_dev = kdev_t_to_nr(inode->i_dev);
  76        tmp.st_ino = inode->i_ino;
  77        tmp.st_mode = inode->i_mode;
  78        tmp.st_nlink = inode->i_nlink;
  79        SET_STAT_UID(tmp, inode->i_uid);
  80        SET_STAT_GID(tmp, inode->i_gid);
  81        tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
  82#if BITS_PER_LONG == 32
  83        if (inode->i_size > MAX_NON_LFS)
  84                return -EOVERFLOW;
  85#endif  
  86        tmp.st_size = inode->i_size;
  87        tmp.st_atime = inode->i_atime;
  88        tmp.st_mtime = inode->i_mtime;
  89        tmp.st_ctime = inode->i_ctime;
  90/*
  91 * st_blocks and st_blksize are approximated with a simple algorithm if
  92 * they aren't supported directly by the filesystem. The minix and msdos
  93 * filesystems don't keep track of blocks, so they would either have to
  94 * be counted explicitly (by delving into the file itself), or by using
  95 * this simple algorithm to get a reasonable (although not 100% accurate)
  96 * value.
  97 */
  98
  99/*
 100 * Use minix fs values for the number of direct and indirect blocks.  The
 101 * count is now exact for the minix fs except that it counts zero blocks.
 102 * Everything is in units of BLOCK_SIZE until the assignment to
 103 * tmp.st_blksize.
 104 */
 105#define D_B   7
 106#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
 107
 108        if (!inode->i_blksize) {
 109                blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
 110                if (blocks > D_B) {
 111                        indirect = (blocks - D_B + I_B - 1) / I_B;
 112                        blocks += indirect;
 113                        if (indirect > 1) {
 114                                indirect = (indirect - 1 + I_B - 1) / I_B;
 115                                blocks += indirect;
 116                                if (indirect > 1)
 117                                        blocks++;
 118                        }
 119                }
 120                tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
 121                tmp.st_blksize = BLOCK_SIZE;
 122        } else {
 123                tmp.st_blocks = inode->i_blocks;
 124                tmp.st_blksize = inode->i_blksize;
 125        }
 126        return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 127}
 128
 129
 130#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
 131/*
 132 * For backward compatibility?  Maybe this should be moved
 133 * into arch/i386 instead?
 134 */
 135asmlinkage long sys_stat(char * filename, struct __old_kernel_stat * statbuf)
 136{
 137        struct nameidata nd;
 138        int error;
 139
 140        error = user_path_walk(filename, &nd);
 141        if (!error) {
 142                error = do_revalidate(nd.dentry);
 143                if (!error)
 144                        error = cp_old_stat(nd.dentry->d_inode, statbuf);
 145                path_release(&nd);
 146        }
 147        return error;
 148}
 149#endif
 150
 151asmlinkage long sys_newstat(char * filename, struct stat * statbuf)
 152{
 153        struct nameidata nd;
 154        int error;
 155
 156        error = user_path_walk(filename, &nd);
 157        if (!error) {
 158                error = do_revalidate(nd.dentry);
 159                if (!error)
 160                        error = cp_new_stat(nd.dentry->d_inode, statbuf);
 161                path_release(&nd);
 162        }
 163        return error;
 164}
 165
 166#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
 167
 168/*
 169 * For backward compatibility?  Maybe this should be moved
 170 * into arch/i386 instead?
 171 */
 172asmlinkage long sys_lstat(char * filename, struct __old_kernel_stat * statbuf)
 173{
 174        struct nameidata nd;
 175        int error;
 176
 177        error = user_path_walk_link(filename, &nd);
 178        if (!error) {
 179                error = do_revalidate(nd.dentry);
 180                if (!error)
 181                        error = cp_old_stat(nd.dentry->d_inode, statbuf);
 182                path_release(&nd);
 183        }
 184        return error;
 185}
 186
 187#endif
 188
 189asmlinkage long sys_newlstat(char * filename, struct stat * statbuf)
 190{
 191        struct nameidata nd;
 192        int error;
 193
 194        error = user_path_walk_link(filename, &nd);
 195        if (!error) {
 196                error = do_revalidate(nd.dentry);
 197                if (!error)
 198                        error = cp_new_stat(nd.dentry->d_inode, statbuf);
 199                path_release(&nd);
 200        }
 201        return error;
 202}
 203
 204#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
 205
 206/*
 207 * For backward compatibility?  Maybe this should be moved
 208 * into arch/i386 instead?
 209 */
 210asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat * statbuf)
 211{
 212        struct file * f;
 213        int err = -EBADF;
 214
 215        f = fget(fd);
 216        if (f) {
 217                struct dentry * dentry = f->f_dentry;
 218
 219                err = do_revalidate(dentry);
 220                if (!err)
 221                        err = cp_old_stat(dentry->d_inode, statbuf);
 222                fput(f);
 223        }
 224        return err;
 225}
 226
 227#endif
 228
 229asmlinkage long sys_newfstat(unsigned int fd, struct stat * statbuf)
 230{
 231        struct file * f;
 232        int err = -EBADF;
 233
 234        f = fget(fd);
 235        if (f) {
 236                struct dentry * dentry = f->f_dentry;
 237
 238                err = do_revalidate(dentry);
 239                if (!err)
 240                        err = cp_new_stat(dentry->d_inode, statbuf);
 241                fput(f);
 242        }
 243        return err;
 244}
 245
 246asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz)
 247{
 248        struct nameidata nd;
 249        int error;
 250
 251        if (bufsiz <= 0)
 252                return -EINVAL;
 253
 254        error = user_path_walk_link(path, &nd);
 255        if (!error) {
 256                struct inode * inode = nd.dentry->d_inode;
 257
 258                error = -EINVAL;
 259                if (inode->i_op && inode->i_op->readlink &&
 260                    !(error = do_revalidate(nd.dentry))) {
 261                        UPDATE_ATIME(inode);
 262                        error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
 263                }
 264                path_release(&nd);
 265        }
 266        return error;
 267}
 268
 269
 270/* ---------- LFS-64 ----------- */
 271#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips64) && !defined(__x86_64__) && !defined(CONFIG_ARCH_S390X)
 272
 273static long cp_new_stat64(struct inode * inode, struct stat64 * statbuf)
 274{
 275        struct stat64 tmp;
 276        unsigned int blocks, indirect;
 277
 278        memset(&tmp, 0, sizeof(tmp));
 279        tmp.st_dev = kdev_t_to_nr(inode->i_dev);
 280        tmp.st_ino = inode->i_ino;
 281#ifdef STAT64_HAS_BROKEN_ST_INO
 282        tmp.__st_ino = inode->i_ino;
 283#endif
 284        tmp.st_mode = inode->i_mode;
 285        tmp.st_nlink = inode->i_nlink;
 286        tmp.st_uid = inode->i_uid;
 287        tmp.st_gid = inode->i_gid;
 288        tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
 289        tmp.st_atime = inode->i_atime;
 290        tmp.st_mtime = inode->i_mtime;
 291        tmp.st_ctime = inode->i_ctime;
 292        tmp.st_size = inode->i_size;
 293/*
 294 * st_blocks and st_blksize are approximated with a simple algorithm if
 295 * they aren't supported directly by the filesystem. The minix and msdos
 296 * filesystems don't keep track of blocks, so they would either have to
 297 * be counted explicitly (by delving into the file itself), or by using
 298 * this simple algorithm to get a reasonable (although not 100% accurate)
 299 * value.
 300 */
 301
 302/*
 303 * Use minix fs values for the number of direct and indirect blocks.  The
 304 * count is now exact for the minix fs except that it counts zero blocks.
 305 * Everything is in units of BLOCK_SIZE until the assignment to
 306 * tmp.st_blksize.
 307 */
 308#define D_B   7
 309#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
 310
 311        if (!inode->i_blksize) {
 312                blocks = (tmp.st_size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
 313                if (blocks > D_B) {
 314                        indirect = (blocks - D_B + I_B - 1) / I_B;
 315                        blocks += indirect;
 316                        if (indirect > 1) {
 317                                indirect = (indirect - 1 + I_B - 1) / I_B;
 318                                blocks += indirect;
 319                                if (indirect > 1)
 320                                        blocks++;
 321                        }
 322                }
 323                tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
 324                tmp.st_blksize = BLOCK_SIZE;
 325        } else {
 326                tmp.st_blocks = inode->i_blocks;
 327                tmp.st_blksize = inode->i_blksize;
 328        }
 329        return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 330}
 331
 332asmlinkage long sys_stat64(char * filename, struct stat64 * statbuf, long flags)
 333{
 334        struct nameidata nd;
 335        int error;
 336
 337        error = user_path_walk(filename, &nd);
 338        if (!error) {
 339                error = do_revalidate(nd.dentry);
 340                if (!error)
 341                        error = cp_new_stat64(nd.dentry->d_inode, statbuf);
 342                path_release(&nd);
 343        }
 344        return error;
 345}
 346
 347asmlinkage long sys_lstat64(char * filename, struct stat64 * statbuf, long flags)
 348{
 349        struct nameidata nd;
 350        int error;
 351
 352        error = user_path_walk_link(filename, &nd);
 353        if (!error) {
 354                error = do_revalidate(nd.dentry);
 355                if (!error)
 356                        error = cp_new_stat64(nd.dentry->d_inode, statbuf);
 357                path_release(&nd);
 358        }
 359        return error;
 360}
 361
 362asmlinkage long sys_fstat64(unsigned long fd, struct stat64 * statbuf, long flags)
 363{
 364        struct file * f;
 365        int err = -EBADF;
 366
 367        f = fget(fd);
 368        if (f) {
 369                struct dentry * dentry = f->f_dentry;
 370
 371                err = do_revalidate(dentry);
 372                if (!err)
 373                        err = cp_new_stat64(dentry->d_inode, statbuf);
 374                fput(f);
 375        }
 376        return err;
 377}
 378
 379#endif /* LFS-64 */
 380
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.