stat.c (9095bf25ea08135a5b74875dd0e3eeaddc4218a0) | stat.c (1e2f82d1e9d12223b4cbd1feb3f2b5596f8049eb) |
---|---|
1/* 2 * linux/fs/stat.c 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 */ 6 7#include <linux/export.h> 8#include <linux/mm.h> --- 116 unchanged lines hidden (view full) --- 125 * This function is a wrapper around vfs_getattr(). The main difference is 126 * that it uses a file descriptor to determine the file location. 127 * 128 * 0 will be returned on success, and a -ve error code if unsuccessful. 129 */ 130int vfs_statx_fd(unsigned int fd, struct kstat *stat, 131 u32 request_mask, unsigned int query_flags) 132{ | 1/* 2 * linux/fs/stat.c 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 */ 6 7#include <linux/export.h> 8#include <linux/mm.h> --- 116 unchanged lines hidden (view full) --- 125 * This function is a wrapper around vfs_getattr(). The main difference is 126 * that it uses a file descriptor to determine the file location. 127 * 128 * 0 will be returned on success, and a -ve error code if unsuccessful. 129 */ 130int vfs_statx_fd(unsigned int fd, struct kstat *stat, 131 u32 request_mask, unsigned int query_flags) 132{ |
133 struct fd f = fdget_raw(fd); | 133 struct fd f; |
134 int error = -EBADF; 135 | 134 int error = -EBADF; 135 |
136 if (query_flags & ~KSTAT_QUERY_FLAGS) 137 return -EINVAL; 138 139 f = fdget_raw(fd); |
|
136 if (f.file) { 137 error = vfs_getattr(&f.file->f_path, stat, 138 request_mask, query_flags); 139 fdput(f); 140 } 141 return error; 142} 143EXPORT_SYMBOL(vfs_statx_fd); --- 6 unchanged lines hidden (view full) --- 150 * @stat: The result structure to fill in. 151 * @request_mask: STATX_xxx flags indicating what the caller wants 152 * 153 * This function is a wrapper around vfs_getattr(). The main difference is 154 * that it uses a filename and base directory to determine the file location. 155 * Additionally, the use of AT_SYMLINK_NOFOLLOW in flags will prevent a symlink 156 * at the given name from being referenced. 157 * | 140 if (f.file) { 141 error = vfs_getattr(&f.file->f_path, stat, 142 request_mask, query_flags); 143 fdput(f); 144 } 145 return error; 146} 147EXPORT_SYMBOL(vfs_statx_fd); --- 6 unchanged lines hidden (view full) --- 154 * @stat: The result structure to fill in. 155 * @request_mask: STATX_xxx flags indicating what the caller wants 156 * 157 * This function is a wrapper around vfs_getattr(). The main difference is 158 * that it uses a filename and base directory to determine the file location. 159 * Additionally, the use of AT_SYMLINK_NOFOLLOW in flags will prevent a symlink 160 * at the given name from being referenced. 161 * |
158 * The caller must have preset stat->request_mask as for vfs_getattr(). The 159 * flags are also used to load up stat->query_flags. 160 * | |
161 * 0 will be returned on success, and a -ve error code if unsuccessful. 162 */ 163int vfs_statx(int dfd, const char __user *filename, int flags, 164 struct kstat *stat, u32 request_mask) 165{ 166 struct path path; 167 int error = -EINVAL; 168 unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT; --- 335 unchanged lines hidden (view full) --- 504 505 error = vfs_fstatat(dfd, filename, &stat, flag); 506 if (error) 507 return error; 508 return cp_new_stat64(&stat, statbuf); 509} 510#endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */ 511 | 162 * 0 will be returned on success, and a -ve error code if unsuccessful. 163 */ 164int vfs_statx(int dfd, const char __user *filename, int flags, 165 struct kstat *stat, u32 request_mask) 166{ 167 struct path path; 168 int error = -EINVAL; 169 unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT; --- 335 unchanged lines hidden (view full) --- 505 506 error = vfs_fstatat(dfd, filename, &stat, flag); 507 if (error) 508 return error; 509 return cp_new_stat64(&stat, statbuf); 510} 511#endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */ 512 |
512static inline int __put_timestamp(struct timespec *kts, 513 struct statx_timestamp __user *uts) | 513static noinline_for_stack int 514cp_statx(const struct kstat *stat, struct statx __user *buffer) |
514{ | 515{ |
515 return (__put_user(kts->tv_sec, &uts->tv_sec ) || 516 __put_user(kts->tv_nsec, &uts->tv_nsec ) || 517 __put_user(0, &uts->__reserved )); 518} | 516 struct statx tmp; |
519 | 517 |
520/* 521 * Set the statx results. 522 */ 523static long statx_set_result(struct kstat *stat, struct statx __user *buffer) 524{ 525 uid_t uid = from_kuid_munged(current_user_ns(), stat->uid); 526 gid_t gid = from_kgid_munged(current_user_ns(), stat->gid); | 518 memset(&tmp, 0, sizeof(tmp)); |
527 | 519 |
528 if (__put_user(stat->result_mask, &buffer->stx_mask ) || 529 __put_user(stat->mode, &buffer->stx_mode ) || 530 __clear_user(&buffer->__spare0, sizeof(buffer->__spare0)) || 531 __put_user(stat->nlink, &buffer->stx_nlink ) || 532 __put_user(uid, &buffer->stx_uid ) || 533 __put_user(gid, &buffer->stx_gid ) || 534 __put_user(stat->attributes, &buffer->stx_attributes ) || 535 __put_user(stat->blksize, &buffer->stx_blksize ) || 536 __put_user(MAJOR(stat->rdev), &buffer->stx_rdev_major ) || 537 __put_user(MINOR(stat->rdev), &buffer->stx_rdev_minor ) || 538 __put_user(MAJOR(stat->dev), &buffer->stx_dev_major ) || 539 __put_user(MINOR(stat->dev), &buffer->stx_dev_minor ) || 540 __put_timestamp(&stat->atime, &buffer->stx_atime ) || 541 __put_timestamp(&stat->btime, &buffer->stx_btime ) || 542 __put_timestamp(&stat->ctime, &buffer->stx_ctime ) || 543 __put_timestamp(&stat->mtime, &buffer->stx_mtime ) || 544 __put_user(stat->ino, &buffer->stx_ino ) || 545 __put_user(stat->size, &buffer->stx_size ) || 546 __put_user(stat->blocks, &buffer->stx_blocks ) || 547 __clear_user(&buffer->__spare1, sizeof(buffer->__spare1)) || 548 __clear_user(&buffer->__spare2, sizeof(buffer->__spare2))) 549 return -EFAULT; | 520 tmp.stx_mask = stat->result_mask; 521 tmp.stx_blksize = stat->blksize; 522 tmp.stx_attributes = stat->attributes; 523 tmp.stx_nlink = stat->nlink; 524 tmp.stx_uid = from_kuid_munged(current_user_ns(), stat->uid); 525 tmp.stx_gid = from_kgid_munged(current_user_ns(), stat->gid); 526 tmp.stx_mode = stat->mode; 527 tmp.stx_ino = stat->ino; 528 tmp.stx_size = stat->size; 529 tmp.stx_blocks = stat->blocks; 530 tmp.stx_attributes_mask = stat->attributes_mask; 531 tmp.stx_atime.tv_sec = stat->atime.tv_sec; 532 tmp.stx_atime.tv_nsec = stat->atime.tv_nsec; 533 tmp.stx_btime.tv_sec = stat->btime.tv_sec; 534 tmp.stx_btime.tv_nsec = stat->btime.tv_nsec; 535 tmp.stx_ctime.tv_sec = stat->ctime.tv_sec; 536 tmp.stx_ctime.tv_nsec = stat->ctime.tv_nsec; 537 tmp.stx_mtime.tv_sec = stat->mtime.tv_sec; 538 tmp.stx_mtime.tv_nsec = stat->mtime.tv_nsec; 539 tmp.stx_rdev_major = MAJOR(stat->rdev); 540 tmp.stx_rdev_minor = MINOR(stat->rdev); 541 tmp.stx_dev_major = MAJOR(stat->dev); 542 tmp.stx_dev_minor = MINOR(stat->dev); |
550 | 543 |
551 return 0; | 544 return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0; |
552} 553 554/** 555 * sys_statx - System call to get enhanced stats 556 * @dfd: Base directory to pathwalk from *or* fd to stat. | 545} 546 547/** 548 * sys_statx - System call to get enhanced stats 549 * @dfd: Base directory to pathwalk from *or* fd to stat. |
557 * @filename: File to stat *or* NULL. | 550 * @filename: File to stat or "" with AT_EMPTY_PATH |
558 * @flags: AT_* flags to control pathwalk. 559 * @mask: Parts of statx struct actually required. 560 * @buffer: Result buffer. 561 * | 551 * @flags: AT_* flags to control pathwalk. 552 * @mask: Parts of statx struct actually required. 553 * @buffer: Result buffer. 554 * |
562 * Note that if filename is NULL, then it does the equivalent of fstat() using 563 * dfd to indicate the file of interest. | 555 * Note that fstat() can be emulated by setting dfd to the fd of interest, 556 * supplying "" as the filename and setting AT_EMPTY_PATH in the flags. |
564 */ 565SYSCALL_DEFINE5(statx, 566 int, dfd, const char __user *, filename, unsigned, flags, 567 unsigned int, mask, 568 struct statx __user *, buffer) 569{ 570 struct kstat stat; 571 int error; 572 | 557 */ 558SYSCALL_DEFINE5(statx, 559 int, dfd, const char __user *, filename, unsigned, flags, 560 unsigned int, mask, 561 struct statx __user *, buffer) 562{ 563 struct kstat stat; 564 int error; 565 |
566 if (mask & STATX__RESERVED) 567 return -EINVAL; |
|
573 if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE) 574 return -EINVAL; | 568 if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE) 569 return -EINVAL; |
575 if (!access_ok(VERIFY_WRITE, buffer, sizeof(*buffer))) 576 return -EFAULT; | 570 if (!filename) 571 return -EINVAL; |
577 | 572 |
578 if (filename) 579 error = vfs_statx(dfd, filename, flags, &stat, mask); 580 else 581 error = vfs_statx_fd(dfd, &stat, mask, flags); | 573 error = vfs_statx(dfd, filename, flags, &stat, mask); |
582 if (error) 583 return error; | 574 if (error) 575 return error; |
584 return statx_set_result(&stat, buffer); | 576 577 return cp_statx(&stat, buffer); |
585} 586 587/* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ 588void __inode_add_bytes(struct inode *inode, loff_t bytes) 589{ 590 inode->i_blocks += bytes >> 9; 591 bytes &= 511; 592 inode->i_bytes += bytes; --- 58 unchanged lines hidden --- | 578} 579 580/* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ 581void __inode_add_bytes(struct inode *inode, loff_t bytes) 582{ 583 inode->i_blocks += bytes >> 9; 584 bytes &= 511; 585 inode->i_bytes += bytes; --- 58 unchanged lines hidden --- |