diff options
Diffstat (limited to 'fs/stat.c')
-rw-r--r-- | fs/stat.c | 214 |
1 files changed, 176 insertions, 38 deletions
@@ -19,6 +19,15 @@ | |||
19 | #include <linux/uaccess.h> | 19 | #include <linux/uaccess.h> |
20 | #include <asm/unistd.h> | 20 | #include <asm/unistd.h> |
21 | 21 | ||
22 | /** | ||
23 | * generic_fillattr - Fill in the basic attributes from the inode struct | ||
24 | * @inode: Inode to use as the source | ||
25 | * @stat: Where to fill in the attributes | ||
26 | * | ||
27 | * Fill in the basic attributes in the kstat structure from data that's to be | ||
28 | * found on the VFS inode structure. This is the default if no getattr inode | ||
29 | * operation is supplied. | ||
30 | */ | ||
22 | void generic_fillattr(struct inode *inode, struct kstat *stat) | 31 | void generic_fillattr(struct inode *inode, struct kstat *stat) |
23 | { | 32 | { |
24 | stat->dev = inode->i_sb->s_dev; | 33 | stat->dev = inode->i_sb->s_dev; |
@@ -34,81 +43,147 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) | |||
34 | stat->ctime = inode->i_ctime; | 43 | stat->ctime = inode->i_ctime; |
35 | stat->blksize = i_blocksize(inode); | 44 | stat->blksize = i_blocksize(inode); |
36 | stat->blocks = inode->i_blocks; | 45 | stat->blocks = inode->i_blocks; |
37 | } | ||
38 | 46 | ||
47 | if (IS_NOATIME(inode)) | ||
48 | stat->result_mask &= ~STATX_ATIME; | ||
49 | if (IS_AUTOMOUNT(inode)) | ||
50 | stat->attributes |= STATX_ATTR_AUTOMOUNT; | ||
51 | } | ||
39 | EXPORT_SYMBOL(generic_fillattr); | 52 | EXPORT_SYMBOL(generic_fillattr); |
40 | 53 | ||
41 | /** | 54 | /** |
42 | * vfs_getattr_nosec - getattr without security checks | 55 | * vfs_getattr_nosec - getattr without security checks |
43 | * @path: file to get attributes from | 56 | * @path: file to get attributes from |
44 | * @stat: structure to return attributes in | 57 | * @stat: structure to return attributes in |
58 | * @request_mask: STATX_xxx flags indicating what the caller wants | ||
59 | * @query_flags: Query mode (KSTAT_QUERY_FLAGS) | ||
45 | * | 60 | * |
46 | * Get attributes without calling security_inode_getattr. | 61 | * Get attributes without calling security_inode_getattr. |
47 | * | 62 | * |
48 | * Currently the only caller other than vfs_getattr is internal to the | 63 | * Currently the only caller other than vfs_getattr is internal to the |
49 | * filehandle lookup code, which uses only the inode number and returns | 64 | * filehandle lookup code, which uses only the inode number and returns no |
50 | * no attributes to any user. Any other code probably wants | 65 | * attributes to any user. Any other code probably wants vfs_getattr. |
51 | * vfs_getattr. | ||
52 | */ | 66 | */ |
53 | int vfs_getattr_nosec(struct path *path, struct kstat *stat) | 67 | int vfs_getattr_nosec(const struct path *path, struct kstat *stat, |
68 | u32 request_mask, unsigned int query_flags) | ||
54 | { | 69 | { |
55 | struct inode *inode = d_backing_inode(path->dentry); | 70 | struct inode *inode = d_backing_inode(path->dentry); |
56 | 71 | ||
72 | memset(stat, 0, sizeof(*stat)); | ||
73 | stat->result_mask |= STATX_BASIC_STATS; | ||
74 | request_mask &= STATX_ALL; | ||
75 | query_flags &= KSTAT_QUERY_FLAGS; | ||
57 | if (inode->i_op->getattr) | 76 | if (inode->i_op->getattr) |
58 | return inode->i_op->getattr(path->mnt, path->dentry, stat); | 77 | return inode->i_op->getattr(path, stat, request_mask, |
78 | query_flags); | ||
59 | 79 | ||
60 | generic_fillattr(inode, stat); | 80 | generic_fillattr(inode, stat); |
61 | return 0; | 81 | return 0; |
62 | } | 82 | } |
63 | |||
64 | EXPORT_SYMBOL(vfs_getattr_nosec); | 83 | EXPORT_SYMBOL(vfs_getattr_nosec); |
65 | 84 | ||
66 | int vfs_getattr(struct path *path, struct kstat *stat) | 85 | /* |
86 | * vfs_getattr - Get the enhanced basic attributes of a file | ||
87 | * @path: The file of interest | ||
88 | * @stat: Where to return the statistics | ||
89 | * @request_mask: STATX_xxx flags indicating what the caller wants | ||
90 | * @query_flags: Query mode (KSTAT_QUERY_FLAGS) | ||
91 | * | ||
92 | * Ask the filesystem for a file's attributes. The caller must indicate in | ||
93 | * request_mask and query_flags to indicate what they want. | ||
94 | * | ||
95 | * If the file is remote, the filesystem can be forced to update the attributes | ||
96 | * from the backing store by passing AT_STATX_FORCE_SYNC in query_flags or can | ||
97 | * suppress the update by passing AT_STATX_DONT_SYNC. | ||
98 | * | ||
99 | * Bits must have been set in request_mask to indicate which attributes the | ||
100 | * caller wants retrieving. Any such attribute not requested may be returned | ||
101 | * anyway, but the value may be approximate, and, if remote, may not have been | ||
102 | * synchronised with the server. | ||
103 | * | ||
104 | * 0 will be returned on success, and a -ve error code if unsuccessful. | ||
105 | */ | ||
106 | int vfs_getattr(const struct path *path, struct kstat *stat, | ||
107 | u32 request_mask, unsigned int query_flags) | ||
67 | { | 108 | { |
68 | int retval; | 109 | int retval; |
69 | 110 | ||
70 | retval = security_inode_getattr(path); | 111 | retval = security_inode_getattr(path); |
71 | if (retval) | 112 | if (retval) |
72 | return retval; | 113 | return retval; |
73 | return vfs_getattr_nosec(path, stat); | 114 | return vfs_getattr_nosec(path, stat, request_mask, query_flags); |
74 | } | 115 | } |
75 | |||
76 | EXPORT_SYMBOL(vfs_getattr); | 116 | EXPORT_SYMBOL(vfs_getattr); |
77 | 117 | ||
78 | int vfs_fstat(unsigned int fd, struct kstat *stat) | 118 | /** |
119 | * vfs_statx_fd - Get the enhanced basic attributes by file descriptor | ||
120 | * @fd: The file descriptor referring to the file of interest | ||
121 | * @stat: The result structure to fill in. | ||
122 | * @request_mask: STATX_xxx flags indicating what the caller wants | ||
123 | * @query_flags: Query mode (KSTAT_QUERY_FLAGS) | ||
124 | * | ||
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 | */ | ||
130 | int vfs_statx_fd(unsigned int fd, struct kstat *stat, | ||
131 | u32 request_mask, unsigned int query_flags) | ||
79 | { | 132 | { |
80 | struct fd f = fdget_raw(fd); | 133 | struct fd f = fdget_raw(fd); |
81 | int error = -EBADF; | 134 | int error = -EBADF; |
82 | 135 | ||
83 | if (f.file) { | 136 | if (f.file) { |
84 | error = vfs_getattr(&f.file->f_path, stat); | 137 | error = vfs_getattr(&f.file->f_path, stat, |
138 | request_mask, query_flags); | ||
85 | fdput(f); | 139 | fdput(f); |
86 | } | 140 | } |
87 | return error; | 141 | return error; |
88 | } | 142 | } |
89 | EXPORT_SYMBOL(vfs_fstat); | 143 | EXPORT_SYMBOL(vfs_statx_fd); |
90 | 144 | ||
91 | int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, | 145 | /** |
92 | int flag) | 146 | * vfs_statx - Get basic and extra attributes by filename |
147 | * @dfd: A file descriptor representing the base dir for a relative filename | ||
148 | * @filename: The name of the file of interest | ||
149 | * @flags: Flags to control the query | ||
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 | * | ||
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 | */ | ||
163 | int vfs_statx(int dfd, const char __user *filename, int flags, | ||
164 | struct kstat *stat, u32 request_mask) | ||
93 | { | 165 | { |
94 | struct path path; | 166 | struct path path; |
95 | int error = -EINVAL; | 167 | int error = -EINVAL; |
96 | unsigned int lookup_flags = 0; | 168 | unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT; |
97 | 169 | ||
98 | if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | | 170 | if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | |
99 | AT_EMPTY_PATH)) != 0) | 171 | AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0) |
100 | goto out; | 172 | return -EINVAL; |
101 | 173 | ||
102 | if (!(flag & AT_SYMLINK_NOFOLLOW)) | 174 | if (flags & AT_SYMLINK_NOFOLLOW) |
103 | lookup_flags |= LOOKUP_FOLLOW; | 175 | lookup_flags &= ~LOOKUP_FOLLOW; |
104 | if (flag & AT_EMPTY_PATH) | 176 | if (flags & AT_NO_AUTOMOUNT) |
177 | lookup_flags &= ~LOOKUP_AUTOMOUNT; | ||
178 | if (flags & AT_EMPTY_PATH) | ||
105 | lookup_flags |= LOOKUP_EMPTY; | 179 | lookup_flags |= LOOKUP_EMPTY; |
180 | |||
106 | retry: | 181 | retry: |
107 | error = user_path_at(dfd, filename, lookup_flags, &path); | 182 | error = user_path_at(dfd, filename, lookup_flags, &path); |
108 | if (error) | 183 | if (error) |
109 | goto out; | 184 | goto out; |
110 | 185 | ||
111 | error = vfs_getattr(&path, stat); | 186 | error = vfs_getattr(&path, stat, request_mask, flags); |
112 | path_put(&path); | 187 | path_put(&path); |
113 | if (retry_estale(error, lookup_flags)) { | 188 | if (retry_estale(error, lookup_flags)) { |
114 | lookup_flags |= LOOKUP_REVAL; | 189 | lookup_flags |= LOOKUP_REVAL; |
@@ -117,19 +192,7 @@ retry: | |||
117 | out: | 192 | out: |
118 | return error; | 193 | return error; |
119 | } | 194 | } |
120 | EXPORT_SYMBOL(vfs_fstatat); | 195 | EXPORT_SYMBOL(vfs_statx); |
121 | |||
122 | int vfs_stat(const char __user *name, struct kstat *stat) | ||
123 | { | ||
124 | return vfs_fstatat(AT_FDCWD, name, stat, 0); | ||
125 | } | ||
126 | EXPORT_SYMBOL(vfs_stat); | ||
127 | |||
128 | int vfs_lstat(const char __user *name, struct kstat *stat) | ||
129 | { | ||
130 | return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW); | ||
131 | } | ||
132 | EXPORT_SYMBOL(vfs_lstat); | ||
133 | 196 | ||
134 | 197 | ||
135 | #ifdef __ARCH_WANT_OLD_STAT | 198 | #ifdef __ARCH_WANT_OLD_STAT |
@@ -142,7 +205,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta | |||
142 | { | 205 | { |
143 | static int warncount = 5; | 206 | static int warncount = 5; |
144 | struct __old_kernel_stat tmp; | 207 | struct __old_kernel_stat tmp; |
145 | 208 | ||
146 | if (warncount > 0) { | 209 | if (warncount > 0) { |
147 | warncount--; | 210 | warncount--; |
148 | printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", | 211 | printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", |
@@ -167,7 +230,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta | |||
167 | #if BITS_PER_LONG == 32 | 230 | #if BITS_PER_LONG == 32 |
168 | if (stat->size > MAX_NON_LFS) | 231 | if (stat->size > MAX_NON_LFS) |
169 | return -EOVERFLOW; | 232 | return -EOVERFLOW; |
170 | #endif | 233 | #endif |
171 | tmp.st_size = stat->size; | 234 | tmp.st_size = stat->size; |
172 | tmp.st_atime = stat->atime.tv_sec; | 235 | tmp.st_atime = stat->atime.tv_sec; |
173 | tmp.st_mtime = stat->mtime.tv_sec; | 236 | tmp.st_mtime = stat->mtime.tv_sec; |
@@ -446,6 +509,81 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename, | |||
446 | } | 509 | } |
447 | #endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */ | 510 | #endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */ |
448 | 511 | ||
512 | static inline int __put_timestamp(struct timespec *kts, | ||
513 | struct statx_timestamp __user *uts) | ||
514 | { | ||
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 | } | ||
519 | |||
520 | /* | ||
521 | * Set the statx results. | ||
522 | */ | ||
523 | static 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); | ||
527 | |||
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; | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | /** | ||
555 | * sys_statx - System call to get enhanced stats | ||
556 | * @dfd: Base directory to pathwalk from *or* fd to stat. | ||
557 | * @filename: File to stat *or* NULL. | ||
558 | * @flags: AT_* flags to control pathwalk. | ||
559 | * @mask: Parts of statx struct actually required. | ||
560 | * @buffer: Result buffer. | ||
561 | * | ||
562 | * Note that if filename is NULL, then it does the equivalent of fstat() using | ||
563 | * dfd to indicate the file of interest. | ||
564 | */ | ||
565 | SYSCALL_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 | |||
573 | if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE) | ||
574 | return -EINVAL; | ||
575 | if (!access_ok(VERIFY_WRITE, buffer, sizeof(*buffer))) | ||
576 | return -EFAULT; | ||
577 | |||
578 | if (filename) | ||
579 | error = vfs_statx(dfd, filename, flags, &stat, mask); | ||
580 | else | ||
581 | error = vfs_statx_fd(dfd, &stat, mask, flags); | ||
582 | if (error) | ||
583 | return error; | ||
584 | return statx_set_result(&stat, buffer); | ||
585 | } | ||
586 | |||
449 | /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ | 587 | /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ |
450 | void __inode_add_bytes(struct inode *inode, loff_t bytes) | 588 | void __inode_add_bytes(struct inode *inode, loff_t bytes) |
451 | { | 589 | { |