at v2.6.19-rc2 478 lines 11 kB view raw
1/* 2 * linux/fs/stat.c 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 */ 6 7#include <linux/module.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#include <linux/fs.h> 14#include <linux/namei.h> 15#include <linux/security.h> 16#include <linux/syscalls.h> 17#include <linux/pagemap.h> 18 19#include <asm/uaccess.h> 20#include <asm/unistd.h> 21 22void generic_fillattr(struct inode *inode, struct kstat *stat) 23{ 24 stat->dev = inode->i_sb->s_dev; 25 stat->ino = inode->i_ino; 26 stat->mode = inode->i_mode; 27 stat->nlink = inode->i_nlink; 28 stat->uid = inode->i_uid; 29 stat->gid = inode->i_gid; 30 stat->rdev = inode->i_rdev; 31 stat->atime = inode->i_atime; 32 stat->mtime = inode->i_mtime; 33 stat->ctime = inode->i_ctime; 34 stat->size = i_size_read(inode); 35 stat->blocks = inode->i_blocks; 36 stat->blksize = (1 << inode->i_blkbits); 37} 38 39EXPORT_SYMBOL(generic_fillattr); 40 41int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) 42{ 43 struct inode *inode = dentry->d_inode; 44 int retval; 45 46 retval = security_inode_getattr(mnt, dentry); 47 if (retval) 48 return retval; 49 50 if (inode->i_op->getattr) 51 return inode->i_op->getattr(mnt, dentry, stat); 52 53 generic_fillattr(inode, stat); 54 if (!stat->blksize) { 55 struct super_block *s = inode->i_sb; 56 unsigned blocks; 57 blocks = (stat->size+s->s_blocksize-1) >> s->s_blocksize_bits; 58 stat->blocks = (s->s_blocksize / 512) * blocks; 59 stat->blksize = s->s_blocksize; 60 } 61 return 0; 62} 63 64EXPORT_SYMBOL(vfs_getattr); 65 66int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat) 67{ 68 struct nameidata nd; 69 int error; 70 71 error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd); 72 if (!error) { 73 error = vfs_getattr(nd.mnt, nd.dentry, stat); 74 path_release(&nd); 75 } 76 return error; 77} 78 79int vfs_stat(char __user *name, struct kstat *stat) 80{ 81 return vfs_stat_fd(AT_FDCWD, name, stat); 82} 83 84EXPORT_SYMBOL(vfs_stat); 85 86int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat) 87{ 88 struct nameidata nd; 89 int error; 90 91 error = __user_walk_fd(dfd, name, 0, &nd); 92 if (!error) { 93 error = vfs_getattr(nd.mnt, nd.dentry, stat); 94 path_release(&nd); 95 } 96 return error; 97} 98 99int vfs_lstat(char __user *name, struct kstat *stat) 100{ 101 return vfs_lstat_fd(AT_FDCWD, name, stat); 102} 103 104EXPORT_SYMBOL(vfs_lstat); 105 106int vfs_fstat(unsigned int fd, struct kstat *stat) 107{ 108 struct file *f = fget(fd); 109 int error = -EBADF; 110 111 if (f) { 112 error = vfs_getattr(f->f_vfsmnt, f->f_dentry, stat); 113 fput(f); 114 } 115 return error; 116} 117 118EXPORT_SYMBOL(vfs_fstat); 119 120#ifdef __ARCH_WANT_OLD_STAT 121 122/* 123 * For backward compatibility? Maybe this should be moved 124 * into arch/i386 instead? 125 */ 126static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * statbuf) 127{ 128 static int warncount = 5; 129 struct __old_kernel_stat tmp; 130 131 if (warncount > 0) { 132 warncount--; 133 printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", 134 current->comm); 135 } else if (warncount < 0) { 136 /* it's laughable, but... */ 137 warncount = 0; 138 } 139 140 memset(&tmp, 0, sizeof(struct __old_kernel_stat)); 141 tmp.st_dev = old_encode_dev(stat->dev); 142 tmp.st_ino = stat->ino; 143 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 144 return -EOVERFLOW; 145 tmp.st_mode = stat->mode; 146 tmp.st_nlink = stat->nlink; 147 if (tmp.st_nlink != stat->nlink) 148 return -EOVERFLOW; 149 SET_UID(tmp.st_uid, stat->uid); 150 SET_GID(tmp.st_gid, stat->gid); 151 tmp.st_rdev = old_encode_dev(stat->rdev); 152#if BITS_PER_LONG == 32 153 if (stat->size > MAX_NON_LFS) 154 return -EOVERFLOW; 155#endif 156 tmp.st_size = stat->size; 157 tmp.st_atime = stat->atime.tv_sec; 158 tmp.st_mtime = stat->mtime.tv_sec; 159 tmp.st_ctime = stat->ctime.tv_sec; 160 return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 161} 162 163asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf) 164{ 165 struct kstat stat; 166 int error = vfs_stat_fd(AT_FDCWD, filename, &stat); 167 168 if (!error) 169 error = cp_old_stat(&stat, statbuf); 170 171 return error; 172} 173asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) 174{ 175 struct kstat stat; 176 int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); 177 178 if (!error) 179 error = cp_old_stat(&stat, statbuf); 180 181 return error; 182} 183asmlinkage long sys_fstat(unsigned int fd, struct __old_kernel_stat __user * statbuf) 184{ 185 struct kstat stat; 186 int error = vfs_fstat(fd, &stat); 187 188 if (!error) 189 error = cp_old_stat(&stat, statbuf); 190 191 return error; 192} 193 194#endif /* __ARCH_WANT_OLD_STAT */ 195 196static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) 197{ 198 struct stat tmp; 199 200#if BITS_PER_LONG == 32 201 if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) 202 return -EOVERFLOW; 203#else 204 if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev)) 205 return -EOVERFLOW; 206#endif 207 208 memset(&tmp, 0, sizeof(tmp)); 209#if BITS_PER_LONG == 32 210 tmp.st_dev = old_encode_dev(stat->dev); 211#else 212 tmp.st_dev = new_encode_dev(stat->dev); 213#endif 214 tmp.st_ino = stat->ino; 215 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 216 return -EOVERFLOW; 217 tmp.st_mode = stat->mode; 218 tmp.st_nlink = stat->nlink; 219 if (tmp.st_nlink != stat->nlink) 220 return -EOVERFLOW; 221 SET_UID(tmp.st_uid, stat->uid); 222 SET_GID(tmp.st_gid, stat->gid); 223#if BITS_PER_LONG == 32 224 tmp.st_rdev = old_encode_dev(stat->rdev); 225#else 226 tmp.st_rdev = new_encode_dev(stat->rdev); 227#endif 228#if BITS_PER_LONG == 32 229 if (stat->size > MAX_NON_LFS) 230 return -EOVERFLOW; 231#endif 232 tmp.st_size = stat->size; 233 tmp.st_atime = stat->atime.tv_sec; 234 tmp.st_mtime = stat->mtime.tv_sec; 235 tmp.st_ctime = stat->ctime.tv_sec; 236#ifdef STAT_HAVE_NSEC 237 tmp.st_atime_nsec = stat->atime.tv_nsec; 238 tmp.st_mtime_nsec = stat->mtime.tv_nsec; 239 tmp.st_ctime_nsec = stat->ctime.tv_nsec; 240#endif 241 tmp.st_blocks = stat->blocks; 242 tmp.st_blksize = stat->blksize; 243 return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 244} 245 246asmlinkage long sys_newstat(char __user *filename, struct stat __user *statbuf) 247{ 248 struct kstat stat; 249 int error = vfs_stat_fd(AT_FDCWD, filename, &stat); 250 251 if (!error) 252 error = cp_new_stat(&stat, statbuf); 253 254 return error; 255} 256 257asmlinkage long sys_newlstat(char __user *filename, struct stat __user *statbuf) 258{ 259 struct kstat stat; 260 int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); 261 262 if (!error) 263 error = cp_new_stat(&stat, statbuf); 264 265 return error; 266} 267 268#if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT) 269asmlinkage long sys_newfstatat(int dfd, char __user *filename, 270 struct stat __user *statbuf, int flag) 271{ 272 struct kstat stat; 273 int error = -EINVAL; 274 275 if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) 276 goto out; 277 278 if (flag & AT_SYMLINK_NOFOLLOW) 279 error = vfs_lstat_fd(dfd, filename, &stat); 280 else 281 error = vfs_stat_fd(dfd, filename, &stat); 282 283 if (!error) 284 error = cp_new_stat(&stat, statbuf); 285 286out: 287 return error; 288} 289#endif 290 291asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf) 292{ 293 struct kstat stat; 294 int error = vfs_fstat(fd, &stat); 295 296 if (!error) 297 error = cp_new_stat(&stat, statbuf); 298 299 return error; 300} 301 302asmlinkage long sys_readlinkat(int dfd, const char __user *path, 303 char __user *buf, int bufsiz) 304{ 305 struct nameidata nd; 306 int error; 307 308 if (bufsiz <= 0) 309 return -EINVAL; 310 311 error = __user_walk_fd(dfd, path, 0, &nd); 312 if (!error) { 313 struct inode * inode = nd.dentry->d_inode; 314 315 error = -EINVAL; 316 if (inode->i_op && inode->i_op->readlink) { 317 error = security_inode_readlink(nd.dentry); 318 if (!error) { 319 touch_atime(nd.mnt, nd.dentry); 320 error = inode->i_op->readlink(nd.dentry, buf, bufsiz); 321 } 322 } 323 path_release(&nd); 324 } 325 return error; 326} 327 328asmlinkage long sys_readlink(const char __user *path, char __user *buf, 329 int bufsiz) 330{ 331 return sys_readlinkat(AT_FDCWD, path, buf, bufsiz); 332} 333 334 335/* ---------- LFS-64 ----------- */ 336#ifdef __ARCH_WANT_STAT64 337 338static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) 339{ 340 struct stat64 tmp; 341 342 memset(&tmp, 0, sizeof(struct stat64)); 343#ifdef CONFIG_MIPS 344 /* mips has weird padding, so we don't get 64 bits there */ 345 if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev)) 346 return -EOVERFLOW; 347 tmp.st_dev = new_encode_dev(stat->dev); 348 tmp.st_rdev = new_encode_dev(stat->rdev); 349#else 350 tmp.st_dev = huge_encode_dev(stat->dev); 351 tmp.st_rdev = huge_encode_dev(stat->rdev); 352#endif 353 tmp.st_ino = stat->ino; 354 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) 355 return -EOVERFLOW; 356#ifdef STAT64_HAS_BROKEN_ST_INO 357 tmp.__st_ino = stat->ino; 358#endif 359 tmp.st_mode = stat->mode; 360 tmp.st_nlink = stat->nlink; 361 tmp.st_uid = stat->uid; 362 tmp.st_gid = stat->gid; 363 tmp.st_atime = stat->atime.tv_sec; 364 tmp.st_atime_nsec = stat->atime.tv_nsec; 365 tmp.st_mtime = stat->mtime.tv_sec; 366 tmp.st_mtime_nsec = stat->mtime.tv_nsec; 367 tmp.st_ctime = stat->ctime.tv_sec; 368 tmp.st_ctime_nsec = stat->ctime.tv_nsec; 369 tmp.st_size = stat->size; 370 tmp.st_blocks = stat->blocks; 371 tmp.st_blksize = stat->blksize; 372 return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 373} 374 375asmlinkage long sys_stat64(char __user * filename, struct stat64 __user * statbuf) 376{ 377 struct kstat stat; 378 int error = vfs_stat(filename, &stat); 379 380 if (!error) 381 error = cp_new_stat64(&stat, statbuf); 382 383 return error; 384} 385asmlinkage long sys_lstat64(char __user * filename, struct stat64 __user * statbuf) 386{ 387 struct kstat stat; 388 int error = vfs_lstat(filename, &stat); 389 390 if (!error) 391 error = cp_new_stat64(&stat, statbuf); 392 393 return error; 394} 395asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user * statbuf) 396{ 397 struct kstat stat; 398 int error = vfs_fstat(fd, &stat); 399 400 if (!error) 401 error = cp_new_stat64(&stat, statbuf); 402 403 return error; 404} 405 406asmlinkage long sys_fstatat64(int dfd, char __user *filename, 407 struct stat64 __user *statbuf, int flag) 408{ 409 struct kstat stat; 410 int error = -EINVAL; 411 412 if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) 413 goto out; 414 415 if (flag & AT_SYMLINK_NOFOLLOW) 416 error = vfs_lstat_fd(dfd, filename, &stat); 417 else 418 error = vfs_stat_fd(dfd, filename, &stat); 419 420 if (!error) 421 error = cp_new_stat64(&stat, statbuf); 422 423out: 424 return error; 425} 426#endif /* __ARCH_WANT_STAT64 */ 427 428void inode_add_bytes(struct inode *inode, loff_t bytes) 429{ 430 spin_lock(&inode->i_lock); 431 inode->i_blocks += bytes >> 9; 432 bytes &= 511; 433 inode->i_bytes += bytes; 434 if (inode->i_bytes >= 512) { 435 inode->i_blocks++; 436 inode->i_bytes -= 512; 437 } 438 spin_unlock(&inode->i_lock); 439} 440 441EXPORT_SYMBOL(inode_add_bytes); 442 443void inode_sub_bytes(struct inode *inode, loff_t bytes) 444{ 445 spin_lock(&inode->i_lock); 446 inode->i_blocks -= bytes >> 9; 447 bytes &= 511; 448 if (inode->i_bytes < bytes) { 449 inode->i_blocks--; 450 inode->i_bytes += 512; 451 } 452 inode->i_bytes -= bytes; 453 spin_unlock(&inode->i_lock); 454} 455 456EXPORT_SYMBOL(inode_sub_bytes); 457 458loff_t inode_get_bytes(struct inode *inode) 459{ 460 loff_t ret; 461 462 spin_lock(&inode->i_lock); 463 ret = (((loff_t)inode->i_blocks) << 9) + inode->i_bytes; 464 spin_unlock(&inode->i_lock); 465 return ret; 466} 467 468EXPORT_SYMBOL(inode_get_bytes); 469 470void inode_set_bytes(struct inode *inode, loff_t bytes) 471{ 472 /* Caller is here responsible for sufficient locking 473 * (ie. inode->i_lock) */ 474 inode->i_blocks = bytes >> 9; 475 inode->i_bytes = bytes & 511; 476} 477 478EXPORT_SYMBOL(inode_set_bytes);