.. | .. |
---|
21 | 21 | #include <linux/uaccess.h> |
---|
22 | 22 | #include <asm/unistd.h> |
---|
23 | 23 | |
---|
| 24 | +#include "internal.h" |
---|
| 25 | +#include "mount.h" |
---|
| 26 | + |
---|
24 | 27 | /** |
---|
25 | 28 | * generic_fillattr - Fill in the basic attributes from the inode struct |
---|
26 | 29 | * @inode: Inode to use as the source |
---|
.. | .. |
---|
45 | 48 | stat->ctime = inode->i_ctime; |
---|
46 | 49 | stat->blksize = i_blocksize(inode); |
---|
47 | 50 | stat->blocks = inode->i_blocks; |
---|
48 | | - |
---|
49 | | - if (IS_NOATIME(inode)) |
---|
50 | | - stat->result_mask &= ~STATX_ATIME; |
---|
51 | | - if (IS_AUTOMOUNT(inode)) |
---|
52 | | - stat->attributes |= STATX_ATTR_AUTOMOUNT; |
---|
53 | 51 | } |
---|
54 | | -EXPORT_SYMBOL(generic_fillattr); |
---|
| 52 | +EXPORT_SYMBOL_NS(generic_fillattr, ANDROID_GKI_VFS_EXPORT_ONLY); |
---|
55 | 53 | |
---|
56 | 54 | /** |
---|
57 | 55 | * vfs_getattr_nosec - getattr without security checks |
---|
58 | 56 | * @path: file to get attributes from |
---|
59 | 57 | * @stat: structure to return attributes in |
---|
60 | 58 | * @request_mask: STATX_xxx flags indicating what the caller wants |
---|
61 | | - * @query_flags: Query mode (KSTAT_QUERY_FLAGS) |
---|
| 59 | + * @query_flags: Query mode (AT_STATX_SYNC_TYPE) |
---|
62 | 60 | * |
---|
63 | 61 | * Get attributes without calling security_inode_getattr. |
---|
64 | 62 | * |
---|
.. | .. |
---|
73 | 71 | |
---|
74 | 72 | memset(stat, 0, sizeof(*stat)); |
---|
75 | 73 | stat->result_mask |= STATX_BASIC_STATS; |
---|
76 | | - request_mask &= STATX_ALL; |
---|
77 | | - query_flags &= KSTAT_QUERY_FLAGS; |
---|
| 74 | + query_flags &= AT_STATX_SYNC_TYPE; |
---|
| 75 | + |
---|
| 76 | + /* allow the fs to override these if it really wants to */ |
---|
| 77 | + /* SB_NOATIME means filesystem supplies dummy atime value */ |
---|
| 78 | + if (inode->i_sb->s_flags & SB_NOATIME) |
---|
| 79 | + stat->result_mask &= ~STATX_ATIME; |
---|
| 80 | + |
---|
| 81 | + /* |
---|
| 82 | + * Note: If you add another clause to set an attribute flag, please |
---|
| 83 | + * update attributes_mask below. |
---|
| 84 | + */ |
---|
| 85 | + if (IS_AUTOMOUNT(inode)) |
---|
| 86 | + stat->attributes |= STATX_ATTR_AUTOMOUNT; |
---|
| 87 | + |
---|
| 88 | + if (IS_DAX(inode)) |
---|
| 89 | + stat->attributes |= STATX_ATTR_DAX; |
---|
| 90 | + |
---|
| 91 | + stat->attributes_mask |= (STATX_ATTR_AUTOMOUNT | |
---|
| 92 | + STATX_ATTR_DAX); |
---|
| 93 | + |
---|
78 | 94 | if (inode->i_op->getattr) |
---|
79 | 95 | return inode->i_op->getattr(path, stat, request_mask, |
---|
80 | 96 | query_flags); |
---|
.. | .. |
---|
89 | 105 | * @path: The file of interest |
---|
90 | 106 | * @stat: Where to return the statistics |
---|
91 | 107 | * @request_mask: STATX_xxx flags indicating what the caller wants |
---|
92 | | - * @query_flags: Query mode (KSTAT_QUERY_FLAGS) |
---|
| 108 | + * @query_flags: Query mode (AT_STATX_SYNC_TYPE) |
---|
93 | 109 | * |
---|
94 | 110 | * Ask the filesystem for a file's attributes. The caller must indicate in |
---|
95 | 111 | * request_mask and query_flags to indicate what they want. |
---|
.. | .. |
---|
118 | 134 | EXPORT_SYMBOL(vfs_getattr); |
---|
119 | 135 | |
---|
120 | 136 | /** |
---|
121 | | - * vfs_statx_fd - Get the enhanced basic attributes by file descriptor |
---|
| 137 | + * vfs_fstat - Get the basic attributes by file descriptor |
---|
122 | 138 | * @fd: The file descriptor referring to the file of interest |
---|
123 | 139 | * @stat: The result structure to fill in. |
---|
124 | | - * @request_mask: STATX_xxx flags indicating what the caller wants |
---|
125 | | - * @query_flags: Query mode (KSTAT_QUERY_FLAGS) |
---|
126 | 140 | * |
---|
127 | 141 | * This function is a wrapper around vfs_getattr(). The main difference is |
---|
128 | 142 | * that it uses a file descriptor to determine the file location. |
---|
129 | 143 | * |
---|
130 | 144 | * 0 will be returned on success, and a -ve error code if unsuccessful. |
---|
131 | 145 | */ |
---|
132 | | -int vfs_statx_fd(unsigned int fd, struct kstat *stat, |
---|
133 | | - u32 request_mask, unsigned int query_flags) |
---|
| 146 | +int vfs_fstat(int fd, struct kstat *stat) |
---|
134 | 147 | { |
---|
135 | 148 | struct fd f; |
---|
136 | | - int error = -EBADF; |
---|
137 | | - |
---|
138 | | - if (query_flags & ~KSTAT_QUERY_FLAGS) |
---|
139 | | - return -EINVAL; |
---|
| 149 | + int error; |
---|
140 | 150 | |
---|
141 | 151 | f = fdget_raw(fd); |
---|
142 | | - if (f.file) { |
---|
143 | | - error = vfs_getattr(&f.file->f_path, stat, |
---|
144 | | - request_mask, query_flags); |
---|
145 | | - fdput(f); |
---|
146 | | - } |
---|
| 152 | + if (!f.file) |
---|
| 153 | + return -EBADF; |
---|
| 154 | + error = vfs_getattr(&f.file->f_path, stat, STATX_BASIC_STATS, 0); |
---|
| 155 | + fdput(f); |
---|
147 | 156 | return error; |
---|
148 | 157 | } |
---|
149 | | -EXPORT_SYMBOL(vfs_statx_fd); |
---|
150 | 158 | |
---|
151 | 159 | /** |
---|
152 | 160 | * vfs_statx - Get basic and extra attributes by filename |
---|
.. | .. |
---|
163 | 171 | * |
---|
164 | 172 | * 0 will be returned on success, and a -ve error code if unsuccessful. |
---|
165 | 173 | */ |
---|
166 | | -int vfs_statx(int dfd, const char __user *filename, int flags, |
---|
| 174 | +static int vfs_statx(int dfd, const char __user *filename, int flags, |
---|
167 | 175 | struct kstat *stat, u32 request_mask) |
---|
168 | 176 | { |
---|
169 | 177 | struct path path; |
---|
170 | | - int error = -EINVAL; |
---|
171 | | - unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT; |
---|
| 178 | + unsigned lookup_flags = 0; |
---|
| 179 | + int error; |
---|
172 | 180 | |
---|
173 | | - if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | |
---|
174 | | - AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0) |
---|
| 181 | + if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH | |
---|
| 182 | + AT_STATX_SYNC_TYPE)) |
---|
175 | 183 | return -EINVAL; |
---|
176 | 184 | |
---|
177 | | - if (flags & AT_SYMLINK_NOFOLLOW) |
---|
178 | | - lookup_flags &= ~LOOKUP_FOLLOW; |
---|
179 | | - if (flags & AT_NO_AUTOMOUNT) |
---|
180 | | - lookup_flags &= ~LOOKUP_AUTOMOUNT; |
---|
| 185 | + if (!(flags & AT_SYMLINK_NOFOLLOW)) |
---|
| 186 | + lookup_flags |= LOOKUP_FOLLOW; |
---|
| 187 | + if (!(flags & AT_NO_AUTOMOUNT)) |
---|
| 188 | + lookup_flags |= LOOKUP_AUTOMOUNT; |
---|
181 | 189 | if (flags & AT_EMPTY_PATH) |
---|
182 | 190 | lookup_flags |= LOOKUP_EMPTY; |
---|
183 | 191 | |
---|
.. | .. |
---|
187 | 195 | goto out; |
---|
188 | 196 | |
---|
189 | 197 | error = vfs_getattr(&path, stat, request_mask, flags); |
---|
| 198 | + stat->mnt_id = real_mount(path.mnt)->mnt_id; |
---|
| 199 | + stat->result_mask |= STATX_MNT_ID; |
---|
| 200 | + if (path.mnt->mnt_root == path.dentry) |
---|
| 201 | + stat->attributes |= STATX_ATTR_MOUNT_ROOT; |
---|
| 202 | + stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT; |
---|
190 | 203 | path_put(&path); |
---|
191 | 204 | if (retry_estale(error, lookup_flags)) { |
---|
192 | 205 | lookup_flags |= LOOKUP_REVAL; |
---|
.. | .. |
---|
195 | 208 | out: |
---|
196 | 209 | return error; |
---|
197 | 210 | } |
---|
198 | | -EXPORT_SYMBOL(vfs_statx); |
---|
199 | 211 | |
---|
| 212 | +int vfs_fstatat(int dfd, const char __user *filename, |
---|
| 213 | + struct kstat *stat, int flags) |
---|
| 214 | +{ |
---|
| 215 | + return vfs_statx(dfd, filename, flags | AT_NO_AUTOMOUNT, |
---|
| 216 | + stat, STATX_BASIC_STATS); |
---|
| 217 | +} |
---|
200 | 218 | |
---|
201 | 219 | #ifdef __ARCH_WANT_OLD_STAT |
---|
202 | 220 | |
---|
.. | .. |
---|
280 | 298 | |
---|
281 | 299 | #endif /* __ARCH_WANT_OLD_STAT */ |
---|
282 | 300 | |
---|
| 301 | +#ifdef __ARCH_WANT_NEW_STAT |
---|
| 302 | + |
---|
283 | 303 | #if BITS_PER_LONG == 32 |
---|
284 | 304 | # define choose_32_64(a,b) a |
---|
285 | 305 | #else |
---|
286 | 306 | # define choose_32_64(a,b) b |
---|
287 | 307 | #endif |
---|
288 | | - |
---|
289 | | -#define valid_dev(x) choose_32_64(old_valid_dev(x),true) |
---|
290 | | -#define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x) |
---|
291 | 308 | |
---|
292 | 309 | #ifndef INIT_STRUCT_STAT_PADDING |
---|
293 | 310 | # define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st)) |
---|
.. | .. |
---|
297 | 314 | { |
---|
298 | 315 | struct stat tmp; |
---|
299 | 316 | |
---|
300 | | - if (!valid_dev(stat->dev) || !valid_dev(stat->rdev)) |
---|
| 317 | + if (sizeof(tmp.st_dev) < 4 && !old_valid_dev(stat->dev)) |
---|
| 318 | + return -EOVERFLOW; |
---|
| 319 | + if (sizeof(tmp.st_rdev) < 4 && !old_valid_dev(stat->rdev)) |
---|
301 | 320 | return -EOVERFLOW; |
---|
302 | 321 | #if BITS_PER_LONG == 32 |
---|
303 | 322 | if (stat->size > MAX_NON_LFS) |
---|
.. | .. |
---|
305 | 324 | #endif |
---|
306 | 325 | |
---|
307 | 326 | INIT_STRUCT_STAT_PADDING(tmp); |
---|
308 | | - tmp.st_dev = encode_dev(stat->dev); |
---|
| 327 | + tmp.st_dev = new_encode_dev(stat->dev); |
---|
309 | 328 | tmp.st_ino = stat->ino; |
---|
310 | 329 | if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) |
---|
311 | 330 | return -EOVERFLOW; |
---|
.. | .. |
---|
315 | 334 | return -EOVERFLOW; |
---|
316 | 335 | SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); |
---|
317 | 336 | SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); |
---|
318 | | - tmp.st_rdev = encode_dev(stat->rdev); |
---|
| 337 | + tmp.st_rdev = new_encode_dev(stat->rdev); |
---|
319 | 338 | tmp.st_size = stat->size; |
---|
320 | 339 | tmp.st_atime = stat->atime.tv_sec; |
---|
321 | 340 | tmp.st_mtime = stat->mtime.tv_sec; |
---|
.. | .. |
---|
378 | 397 | |
---|
379 | 398 | return error; |
---|
380 | 399 | } |
---|
| 400 | +#endif |
---|
381 | 401 | |
---|
382 | 402 | static int do_readlinkat(int dfd, const char __user *pathname, |
---|
383 | 403 | char __user *buf, int bufsiz) |
---|
.. | .. |
---|
548 | 568 | tmp.stx_rdev_minor = MINOR(stat->rdev); |
---|
549 | 569 | tmp.stx_dev_major = MAJOR(stat->dev); |
---|
550 | 570 | tmp.stx_dev_minor = MINOR(stat->dev); |
---|
| 571 | + tmp.stx_mnt_id = stat->mnt_id; |
---|
551 | 572 | |
---|
552 | 573 | return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0; |
---|
| 574 | +} |
---|
| 575 | + |
---|
| 576 | +int do_statx(int dfd, const char __user *filename, unsigned flags, |
---|
| 577 | + unsigned int mask, struct statx __user *buffer) |
---|
| 578 | +{ |
---|
| 579 | + struct kstat stat; |
---|
| 580 | + int error; |
---|
| 581 | + |
---|
| 582 | + if (mask & STATX__RESERVED) |
---|
| 583 | + return -EINVAL; |
---|
| 584 | + if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE) |
---|
| 585 | + return -EINVAL; |
---|
| 586 | + |
---|
| 587 | + error = vfs_statx(dfd, filename, flags, &stat, mask); |
---|
| 588 | + if (error) |
---|
| 589 | + return error; |
---|
| 590 | + |
---|
| 591 | + return cp_statx(&stat, buffer); |
---|
553 | 592 | } |
---|
554 | 593 | |
---|
555 | 594 | /** |
---|
.. | .. |
---|
568 | 607 | unsigned int, mask, |
---|
569 | 608 | struct statx __user *, buffer) |
---|
570 | 609 | { |
---|
571 | | - struct kstat stat; |
---|
572 | | - int error; |
---|
573 | | - |
---|
574 | | - if (mask & STATX__RESERVED) |
---|
575 | | - return -EINVAL; |
---|
576 | | - if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE) |
---|
577 | | - return -EINVAL; |
---|
578 | | - |
---|
579 | | - error = vfs_statx(dfd, filename, flags, &stat, mask); |
---|
580 | | - if (error) |
---|
581 | | - return error; |
---|
582 | | - |
---|
583 | | - return cp_statx(&stat, buffer); |
---|
| 610 | + return do_statx(dfd, filename, flags, mask, buffer); |
---|
584 | 611 | } |
---|
585 | 612 | |
---|
586 | 613 | #ifdef CONFIG_COMPAT |
---|
.. | .. |
---|
588 | 615 | { |
---|
589 | 616 | struct compat_stat tmp; |
---|
590 | 617 | |
---|
591 | | - if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) |
---|
| 618 | + if (sizeof(tmp.st_dev) < 4 && !old_valid_dev(stat->dev)) |
---|
| 619 | + return -EOVERFLOW; |
---|
| 620 | + if (sizeof(tmp.st_rdev) < 4 && !old_valid_dev(stat->rdev)) |
---|
592 | 621 | return -EOVERFLOW; |
---|
593 | 622 | |
---|
594 | 623 | memset(&tmp, 0, sizeof(tmp)); |
---|
595 | | - tmp.st_dev = old_encode_dev(stat->dev); |
---|
| 624 | + tmp.st_dev = new_encode_dev(stat->dev); |
---|
596 | 625 | tmp.st_ino = stat->ino; |
---|
597 | 626 | if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) |
---|
598 | 627 | return -EOVERFLOW; |
---|
.. | .. |
---|
602 | 631 | return -EOVERFLOW; |
---|
603 | 632 | SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); |
---|
604 | 633 | SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); |
---|
605 | | - tmp.st_rdev = old_encode_dev(stat->rdev); |
---|
| 634 | + tmp.st_rdev = new_encode_dev(stat->rdev); |
---|
606 | 635 | if ((u64) stat->size > MAX_NON_LFS) |
---|
607 | 636 | return -EOVERFLOW; |
---|
608 | 637 | tmp.st_size = stat->size; |
---|