Blame view

fs/stat.c 19.8 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   *  linux/fs/stat.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
630d9c472   Paul Gortmaker   fs: reduce the us...
7
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
  #include <linux/mm.h>
  #include <linux/errno.h>
  #include <linux/file.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
  #include <linux/highuid.h>
  #include <linux/fs.h>
  #include <linux/namei.h>
  #include <linux/security.h>
5b825c3af   Ingo Molnar   sched/headers: Pr...
15
  #include <linux/cred.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/syscalls.h>
ba52de123   Theodore Ts'o   [PATCH] inode-die...
17
  #include <linux/pagemap.h>
ac565de31   Al Viro   stat: move compat...
18
  #include <linux/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
20
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include <asm/unistd.h>
3934e36f6   Jens Axboe   fs: make two stat...
22
  #include "internal.h"
fa2fcf4f1   Miklos Szeredi   statx: add mount ID
23
  #include "mount.h"
3934e36f6   Jens Axboe   fs: make two stat...
24

a528d35e8   David Howells   statx: Add a syst...
25
26
27
28
29
30
31
32
33
  /**
   * generic_fillattr - Fill in the basic attributes from the inode struct
   * @inode: Inode to use as the source
   * @stat: Where to fill in the attributes
   *
   * Fill in the basic attributes in the kstat structure from data that's to be
   * found on the VFS inode structure.  This is the default if no getattr inode
   * operation is supplied.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
39
40
41
42
  void generic_fillattr(struct inode *inode, struct kstat *stat)
  {
  	stat->dev = inode->i_sb->s_dev;
  	stat->ino = inode->i_ino;
  	stat->mode = inode->i_mode;
  	stat->nlink = inode->i_nlink;
  	stat->uid = inode->i_uid;
  	stat->gid = inode->i_gid;
  	stat->rdev = inode->i_rdev;
3ddcd0569   Linus Torvalds   vfs: optimize ino...
43
  	stat->size = i_size_read(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
  	stat->atime = inode->i_atime;
  	stat->mtime = inode->i_mtime;
  	stat->ctime = inode->i_ctime;
93407472a   Fabian Frederick   fs: add i_blocksi...
47
  	stat->blksize = i_blocksize(inode);
3ddcd0569   Linus Torvalds   vfs: optimize ino...
48
  	stat->blocks = inode->i_blocks;
a528d35e8   David Howells   statx: Add a syst...
49
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  EXPORT_SYMBOL(generic_fillattr);
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
51
52
53
54
  /**
   * vfs_getattr_nosec - getattr without security checks
   * @path: file to get attributes from
   * @stat: structure to return attributes in
a528d35e8   David Howells   statx: Add a syst...
55
   * @request_mask: STATX_xxx flags indicating what the caller wants
f2d077ff1   Christoph Hellwig   fs: remove KSTAT_...
56
   * @query_flags: Query mode (AT_STATX_SYNC_TYPE)
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
57
58
59
60
   *
   * Get attributes without calling security_inode_getattr.
   *
   * Currently the only caller other than vfs_getattr is internal to the
a528d35e8   David Howells   statx: Add a syst...
61
62
   * filehandle lookup code, which uses only the inode number and returns no
   * attributes to any user.  Any other code probably wants vfs_getattr.
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
63
   */
a528d35e8   David Howells   statx: Add a syst...
64
65
  int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
  		      u32 request_mask, unsigned int query_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  {
bb668734c   David Howells   VFS: assorted d_b...
67
  	struct inode *inode = d_backing_inode(path->dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

a528d35e8   David Howells   statx: Add a syst...
69
70
  	memset(stat, 0, sizeof(*stat));
  	stat->result_mask |= STATX_BASIC_STATS;
f2d077ff1   Christoph Hellwig   fs: remove KSTAT_...
71
  	query_flags &= AT_STATX_SYNC_TYPE;
801e52379   Christoph Hellwig   fs: move generic ...
72
73
  
  	/* allow the fs to override these if it really wants to */
761e28fa2   Miklos Szeredi   statx: don't clea...
74
75
  	/* SB_NOATIME means filesystem supplies dummy atime value */
  	if (inode->i_sb->s_flags & SB_NOATIME)
801e52379   Christoph Hellwig   fs: move generic ...
76
77
78
  		stat->result_mask &= ~STATX_ATIME;
  	if (IS_AUTOMOUNT(inode))
  		stat->attributes |= STATX_ATTR_AUTOMOUNT;
712b2698e   Ira Weiny   fs/stat: Define D...
79
80
  	if (IS_DAX(inode))
  		stat->attributes |= STATX_ATTR_DAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  	if (inode->i_op->getattr)
a528d35e8   David Howells   statx: Add a syst...
82
83
  		return inode->i_op->getattr(path, stat, request_mask,
  					    query_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
  
  	generic_fillattr(inode, stat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
  	return 0;
  }
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
88
  EXPORT_SYMBOL(vfs_getattr_nosec);
a528d35e8   David Howells   statx: Add a syst...
89
90
91
92
93
  /*
   * vfs_getattr - Get the enhanced basic attributes of a file
   * @path: The file of interest
   * @stat: Where to return the statistics
   * @request_mask: STATX_xxx flags indicating what the caller wants
f2d077ff1   Christoph Hellwig   fs: remove KSTAT_...
94
   * @query_flags: Query mode (AT_STATX_SYNC_TYPE)
a528d35e8   David Howells   statx: Add a syst...
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
   *
   * Ask the filesystem for a file's attributes.  The caller must indicate in
   * request_mask and query_flags to indicate what they want.
   *
   * If the file is remote, the filesystem can be forced to update the attributes
   * from the backing store by passing AT_STATX_FORCE_SYNC in query_flags or can
   * suppress the update by passing AT_STATX_DONT_SYNC.
   *
   * Bits must have been set in request_mask to indicate which attributes the
   * caller wants retrieving.  Any such attribute not requested may be returned
   * anyway, but the value may be approximate, and, if remote, may not have been
   * synchronised with the server.
   *
   * 0 will be returned on success, and a -ve error code if unsuccessful.
   */
  int vfs_getattr(const struct path *path, struct kstat *stat,
  		u32 request_mask, unsigned int query_flags)
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
112
113
  {
  	int retval;
3f7036a07   Al Viro   switch security_i...
114
  	retval = security_inode_getattr(path);
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
115
116
  	if (retval)
  		return retval;
a528d35e8   David Howells   statx: Add a syst...
117
  	return vfs_getattr_nosec(path, stat, request_mask, query_flags);
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
118
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  EXPORT_SYMBOL(vfs_getattr);
a528d35e8   David Howells   statx: Add a syst...
120
  /**
da9aa5d96   Christoph Hellwig   fs: remove vfs_st...
121
   * vfs_fstat - Get the basic attributes by file descriptor
a528d35e8   David Howells   statx: Add a syst...
122
123
   * @fd: The file descriptor referring to the file of interest
   * @stat: The result structure to fill in.
a528d35e8   David Howells   statx: Add a syst...
124
125
126
127
128
129
   *
   * This function is a wrapper around vfs_getattr().  The main difference is
   * that it uses a file descriptor to determine the file location.
   *
   * 0 will be returned on success, and a -ve error code if unsuccessful.
   */
da9aa5d96   Christoph Hellwig   fs: remove vfs_st...
130
  int vfs_fstat(int fd, struct kstat *stat)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  {
8c7493aa3   Eric Biggers   statx: reject unk...
132
  	struct fd f;
da9aa5d96   Christoph Hellwig   fs: remove vfs_st...
133
  	int error;
8c7493aa3   Eric Biggers   statx: reject unk...
134
135
  
  	f = fdget_raw(fd);
da9aa5d96   Christoph Hellwig   fs: remove vfs_st...
136
137
138
139
  	if (!f.file)
  		return -EBADF;
  	error = vfs_getattr(&f.file->f_path, stat, STATX_BASIC_STATS, 0);
  	fdput(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142

a528d35e8   David Howells   statx: Add a syst...
143
144
145
146
147
148
149
150
151
152
153
154
155
  /**
   * vfs_statx - Get basic and extra attributes by filename
   * @dfd: A file descriptor representing the base dir for a relative filename
   * @filename: The name of the file of interest
   * @flags: Flags to control the query
   * @stat: The result structure to fill in.
   * @request_mask: STATX_xxx flags indicating what the caller wants
   *
   * This function is a wrapper around vfs_getattr().  The main difference is
   * that it uses a filename and base directory to determine the file location.
   * Additionally, the use of AT_SYMLINK_NOFOLLOW in flags will prevent a symlink
   * at the given name from being referenced.
   *
a528d35e8   David Howells   statx: Add a syst...
156
157
   * 0 will be returned on success, and a -ve error code if unsuccessful.
   */
09f1bde40   Christoph Hellwig   fs: move vfs_fsta...
158
  static int vfs_statx(int dfd, const char __user *filename, int flags,
a528d35e8   David Howells   statx: Add a syst...
159
  	      struct kstat *stat, u32 request_mask)
0112fc222   Oleg Drokin   Separate out comm...
160
  {
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
161
  	struct path path;
b3f051500   Christoph Hellwig   fs: remove vfs_st...
162
163
  	unsigned lookup_flags = 0;
  	int error;
0112fc222   Oleg Drokin   Separate out comm...
164

b3f051500   Christoph Hellwig   fs: remove vfs_st...
165
  	if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH |
f2d077ff1   Christoph Hellwig   fs: remove KSTAT_...
166
  		      AT_STATX_SYNC_TYPE))
a528d35e8   David Howells   statx: Add a syst...
167
  		return -EINVAL;
b3f051500   Christoph Hellwig   fs: remove vfs_st...
168
169
170
171
172
173
174
  
  	if (!(flags & AT_SYMLINK_NOFOLLOW))
  		lookup_flags |= LOOKUP_FOLLOW;
  	if (!(flags & AT_NO_AUTOMOUNT))
  		lookup_flags |= LOOKUP_AUTOMOUNT;
  	if (flags & AT_EMPTY_PATH)
  		lookup_flags |= LOOKUP_EMPTY;
836fb7e7b   Jeff Layton   vfs: make fstatat...
175
  retry:
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
176
177
178
  	error = user_path_at(dfd, filename, lookup_flags, &path);
  	if (error)
  		goto out;
a528d35e8   David Howells   statx: Add a syst...
179
  	error = vfs_getattr(&path, stat, request_mask, flags);
fa2fcf4f1   Miklos Szeredi   statx: add mount ID
180
181
  	stat->mnt_id = real_mount(path.mnt)->mnt_id;
  	stat->result_mask |= STATX_MNT_ID;
80340fe36   Miklos Szeredi   statx: add mount_...
182
183
184
  	if (path.mnt->mnt_root == path.dentry)
  		stat->attributes |= STATX_ATTR_MOUNT_ROOT;
  	stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT;
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
185
  	path_put(&path);
836fb7e7b   Jeff Layton   vfs: make fstatat...
186
187
188
189
  	if (retry_estale(error, lookup_flags)) {
  		lookup_flags |= LOOKUP_REVAL;
  		goto retry;
  	}
0112fc222   Oleg Drokin   Separate out comm...
190
191
192
  out:
  	return error;
  }
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
193

09f1bde40   Christoph Hellwig   fs: move vfs_fsta...
194
195
196
197
198
199
  int vfs_fstatat(int dfd, const char __user *filename,
  			      struct kstat *stat, int flags)
  {
  	return vfs_statx(dfd, filename, flags | AT_NO_AUTOMOUNT,
  			 stat, STATX_BASIC_STATS);
  }
0112fc222   Oleg Drokin   Separate out comm...
200

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
204
205
206
207
208
209
210
  #ifdef __ARCH_WANT_OLD_STAT
  
  /*
   * For backward compatibility?  Maybe this should be moved
   * into arch/i386 instead?
   */
  static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * statbuf)
  {
  	static int warncount = 5;
  	struct __old_kernel_stat tmp;
a528d35e8   David Howells   statx: Add a syst...
211

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
218
219
220
221
222
223
224
  	if (warncount > 0) {
  		warncount--;
  		printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.
  ",
  			current->comm);
  	} else if (warncount < 0) {
  		/* it's laughable, but... */
  		warncount = 0;
  	}
  
  	memset(&tmp, 0, sizeof(struct __old_kernel_stat));
  	tmp.st_dev = old_encode_dev(stat->dev);
  	tmp.st_ino = stat->ino;
afefdbb28   David Howells   [PATCH] VFS: Make...
225
226
  	if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
  	tmp.st_mode = stat->mode;
  	tmp.st_nlink = stat->nlink;
  	if (tmp.st_nlink != stat->nlink)
  		return -EOVERFLOW;
a7c1938e2   Eric W. Biederman   userns: Convert s...
231
232
  	SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
  	SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
236
  	tmp.st_rdev = old_encode_dev(stat->rdev);
  #if BITS_PER_LONG == 32
  	if (stat->size > MAX_NON_LFS)
  		return -EOVERFLOW;
a528d35e8   David Howells   statx: Add a syst...
237
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
239
240
241
242
243
  	tmp.st_size = stat->size;
  	tmp.st_atime = stat->atime.tv_sec;
  	tmp.st_mtime = stat->mtime.tv_sec;
  	tmp.st_ctime = stat->ctime.tv_sec;
  	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
  }
c78873252   David Howells   Mark arguments to...
244
245
  SYSCALL_DEFINE2(stat, const char __user *, filename,
  		struct __old_kernel_stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
  {
  	struct kstat stat;
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
248
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
250
251
252
  	error = vfs_stat(filename, &stat);
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
254
  	return cp_old_stat(&stat, statbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  }
257ac264d   Heiko Carstens   [CVE-2009-0029] S...
256

c78873252   David Howells   Mark arguments to...
257
258
  SYSCALL_DEFINE2(lstat, const char __user *, filename,
  		struct __old_kernel_stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
  {
  	struct kstat stat;
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
261
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
263
264
265
  	error = vfs_lstat(filename, &stat);
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
267
  	return cp_old_stat(&stat, statbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  }
257ac264d   Heiko Carstens   [CVE-2009-0029] S...
269
270
  
  SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
277
278
279
280
281
  {
  	struct kstat stat;
  	int error = vfs_fstat(fd, &stat);
  
  	if (!error)
  		error = cp_old_stat(&stat, statbuf);
  
  	return error;
  }
  
  #endif /* __ARCH_WANT_OLD_STAT */
82b355d16   Arnd Bergmann   y2038: Remove new...
282
  #ifdef __ARCH_WANT_NEW_STAT
a52dd971f   Linus Torvalds   vfs: de-crapify "...
283
284
285
286
287
  #if BITS_PER_LONG == 32
  #  define choose_32_64(a,b) a
  #else
  #  define choose_32_64(a,b) b
  #endif
4c416f42e   Yaowei Bai   fs/stat.c: drop t...
288
  #define valid_dev(x)  choose_32_64(old_valid_dev(x),true)
a52dd971f   Linus Torvalds   vfs: de-crapify "...
289
  #define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x)
8529f613b   Linus Torvalds   vfs: don't force ...
290
291
292
  #ifndef INIT_STRUCT_STAT_PADDING
  #  define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st))
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
  static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
  {
  	struct stat tmp;
a52dd971f   Linus Torvalds   vfs: de-crapify "...
296
  	if (!valid_dev(stat->dev) || !valid_dev(stat->rdev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  		return -EOVERFLOW;
a52dd971f   Linus Torvalds   vfs: de-crapify "...
298
299
  #if BITS_PER_LONG == 32
  	if (stat->size > MAX_NON_LFS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  		return -EOVERFLOW;
  #endif
8529f613b   Linus Torvalds   vfs: don't force ...
302
  	INIT_STRUCT_STAT_PADDING(tmp);
a52dd971f   Linus Torvalds   vfs: de-crapify "...
303
  	tmp.st_dev = encode_dev(stat->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  	tmp.st_ino = stat->ino;
afefdbb28   David Howells   [PATCH] VFS: Make...
305
306
  	if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
  	tmp.st_mode = stat->mode;
  	tmp.st_nlink = stat->nlink;
  	if (tmp.st_nlink != stat->nlink)
  		return -EOVERFLOW;
a7c1938e2   Eric W. Biederman   userns: Convert s...
311
312
  	SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
  	SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
a52dd971f   Linus Torvalds   vfs: de-crapify "...
313
  	tmp.st_rdev = encode_dev(stat->rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
317
318
319
320
321
322
323
324
325
326
  	tmp.st_size = stat->size;
  	tmp.st_atime = stat->atime.tv_sec;
  	tmp.st_mtime = stat->mtime.tv_sec;
  	tmp.st_ctime = stat->ctime.tv_sec;
  #ifdef STAT_HAVE_NSEC
  	tmp.st_atime_nsec = stat->atime.tv_nsec;
  	tmp.st_mtime_nsec = stat->mtime.tv_nsec;
  	tmp.st_ctime_nsec = stat->ctime.tv_nsec;
  #endif
  	tmp.st_blocks = stat->blocks;
  	tmp.st_blksize = stat->blksize;
  	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
  }
c78873252   David Howells   Mark arguments to...
327
328
  SYSCALL_DEFINE2(newstat, const char __user *, filename,
  		struct stat __user *, statbuf)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
329
330
  {
  	struct kstat stat;
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
331
  	int error = vfs_stat(filename, &stat);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
332

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
333
334
335
  	if (error)
  		return error;
  	return cp_new_stat(&stat, statbuf);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
336
  }
c78873252   David Howells   Mark arguments to...
337
338
  SYSCALL_DEFINE2(newlstat, const char __user *, filename,
  		struct stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
  {
  	struct kstat stat;
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
341
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
343
344
345
  	error = vfs_lstat(filename, &stat);
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
347
  	return cp_new_stat(&stat, statbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348
  }
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
349

2833c28aa   Andreas Schwab   [PATCH] powerpc: ...
350
  #if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT)
c78873252   David Howells   Mark arguments to...
351
  SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename,
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
352
  		struct stat __user *, statbuf, int, flag)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
  {
  	struct kstat stat;
0112fc222   Oleg Drokin   Separate out comm...
355
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356

0112fc222   Oleg Drokin   Separate out comm...
357
358
359
360
  	error = vfs_fstatat(dfd, filename, &stat, flag);
  	if (error)
  		return error;
  	return cp_new_stat(&stat, statbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
  }
cff2b7600   Ulrich Drepper   [PATCH] fstatat64...
362
  #endif
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
363

257ac264d   Heiko Carstens   [CVE-2009-0029] S...
364
  SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
368
369
370
371
372
373
  {
  	struct kstat stat;
  	int error = vfs_fstat(fd, &stat);
  
  	if (!error)
  		error = cp_new_stat(&stat, statbuf);
  
  	return error;
  }
82b355d16   Arnd Bergmann   y2038: Remove new...
374
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375

2dae02480   Dominik Brodowski   fs: add do_readli...
376
377
  static int do_readlinkat(int dfd, const char __user *pathname,
  			 char __user *buf, int bufsiz)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
379
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
  	int error;
1fa1e7f61   Andy Whitcroft   readlinkat: ensur...
381
  	int empty = 0;
7955119e0   Jeff Layton   vfs: fix readlink...
382
  	unsigned int lookup_flags = LOOKUP_EMPTY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
383
384
385
  
  	if (bufsiz <= 0)
  		return -EINVAL;
7955119e0   Jeff Layton   vfs: fix readlink...
386
387
  retry:
  	error = user_path_at_empty(dfd, pathname, lookup_flags, &path, &empty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  	if (!error) {
bb668734c   David Howells   VFS: assorted d_b...
389
  		struct inode *inode = d_backing_inode(path.dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390

1fa1e7f61   Andy Whitcroft   readlinkat: ensur...
391
  		error = empty ? -ENOENT : -EINVAL;
fd4a0edf2   Miklos Szeredi   vfs: replace call...
392
393
394
395
  		/*
  		 * AFS mountpoints allow readlink(2) but are not symlinks
  		 */
  		if (d_is_symlink(path.dentry) || inode->i_op->readlink) {
2d8f30380   Al Viro   [PATCH] sanitize ...
396
  			error = security_inode_readlink(path.dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
  			if (!error) {
68ac1234f   Al Viro   switch touch_atim...
398
  				touch_atime(&path);
fd4a0edf2   Miklos Szeredi   vfs: replace call...
399
  				error = vfs_readlink(path.dentry, buf, bufsiz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
401
  			}
  		}
2d8f30380   Al Viro   [PATCH] sanitize ...
402
  		path_put(&path);
7955119e0   Jeff Layton   vfs: fix readlink...
403
404
405
406
  		if (retry_estale(error, lookup_flags)) {
  			lookup_flags |= LOOKUP_REVAL;
  			goto retry;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
  	}
  	return error;
  }
2dae02480   Dominik Brodowski   fs: add do_readli...
410
411
412
413
414
  SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
  		char __user *, buf, int, bufsiz)
  {
  	return do_readlinkat(dfd, pathname, buf, bufsiz);
  }
002c8976e   Heiko Carstens   [CVE-2009-0029] S...
415
416
  SYSCALL_DEFINE3(readlink, const char __user *, path, char __user *, buf,
  		int, bufsiz)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
417
  {
2dae02480   Dominik Brodowski   fs: add do_readli...
418
  	return do_readlinkat(AT_FDCWD, path, buf, bufsiz);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
419
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  
  /* ---------- LFS-64 ----------- */
0753f70f0   Catalin Marinas   fs: Build sys_sta...
422
  #if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423

8529f613b   Linus Torvalds   vfs: don't force ...
424
425
426
  #ifndef INIT_STRUCT_STAT64_PADDING
  #  define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st))
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
  static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
  {
  	struct stat64 tmp;
8529f613b   Linus Torvalds   vfs: don't force ...
430
  	INIT_STRUCT_STAT64_PADDING(tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
  #ifdef CONFIG_MIPS
  	/* mips has weird padding, so we don't get 64 bits there */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
437
438
439
  	tmp.st_dev = new_encode_dev(stat->dev);
  	tmp.st_rdev = new_encode_dev(stat->rdev);
  #else
  	tmp.st_dev = huge_encode_dev(stat->dev);
  	tmp.st_rdev = huge_encode_dev(stat->rdev);
  #endif
  	tmp.st_ino = stat->ino;
afefdbb28   David Howells   [PATCH] VFS: Make...
440
441
  	if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
  #ifdef STAT64_HAS_BROKEN_ST_INO
  	tmp.__st_ino = stat->ino;
  #endif
  	tmp.st_mode = stat->mode;
  	tmp.st_nlink = stat->nlink;
a7c1938e2   Eric W. Biederman   userns: Convert s...
447
448
  	tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
  	tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
452
453
454
455
456
457
458
459
  	tmp.st_atime = stat->atime.tv_sec;
  	tmp.st_atime_nsec = stat->atime.tv_nsec;
  	tmp.st_mtime = stat->mtime.tv_sec;
  	tmp.st_mtime_nsec = stat->mtime.tv_nsec;
  	tmp.st_ctime = stat->ctime.tv_sec;
  	tmp.st_ctime_nsec = stat->ctime.tv_nsec;
  	tmp.st_size = stat->size;
  	tmp.st_blocks = stat->blocks;
  	tmp.st_blksize = stat->blksize;
  	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
  }
c78873252   David Howells   Mark arguments to...
460
461
  SYSCALL_DEFINE2(stat64, const char __user *, filename,
  		struct stat64 __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
465
466
467
468
469
470
  {
  	struct kstat stat;
  	int error = vfs_stat(filename, &stat);
  
  	if (!error)
  		error = cp_new_stat64(&stat, statbuf);
  
  	return error;
  }
257ac264d   Heiko Carstens   [CVE-2009-0029] S...
471

c78873252   David Howells   Mark arguments to...
472
473
  SYSCALL_DEFINE2(lstat64, const char __user *, filename,
  		struct stat64 __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
477
478
479
480
481
482
  {
  	struct kstat stat;
  	int error = vfs_lstat(filename, &stat);
  
  	if (!error)
  		error = cp_new_stat64(&stat, statbuf);
  
  	return error;
  }
257ac264d   Heiko Carstens   [CVE-2009-0029] S...
483
484
  
  SYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
486
487
488
489
490
491
492
493
  {
  	struct kstat stat;
  	int error = vfs_fstat(fd, &stat);
  
  	if (!error)
  		error = cp_new_stat64(&stat, statbuf);
  
  	return error;
  }
c78873252   David Howells   Mark arguments to...
494
  SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename,
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
495
  		struct stat64 __user *, statbuf, int, flag)
cff2b7600   Ulrich Drepper   [PATCH] fstatat64...
496
497
  {
  	struct kstat stat;
0112fc222   Oleg Drokin   Separate out comm...
498
  	int error;
cff2b7600   Ulrich Drepper   [PATCH] fstatat64...
499

0112fc222   Oleg Drokin   Separate out comm...
500
501
502
503
  	error = vfs_fstatat(dfd, filename, &stat, flag);
  	if (error)
  		return error;
  	return cp_new_stat64(&stat, statbuf);
cff2b7600   Ulrich Drepper   [PATCH] fstatat64...
504
  }
0753f70f0   Catalin Marinas   fs: Build sys_sta...
505
  #endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506

6f88cc176   Bijan Mottahedeh   statx: hide inter...
507
  static noinline_for_stack int
64bd72048   Eric Biggers   statx: optimize c...
508
  cp_statx(const struct kstat *stat, struct statx __user *buffer)
a528d35e8   David Howells   statx: Add a syst...
509
  {
64bd72048   Eric Biggers   statx: optimize c...
510
511
512
513
514
515
516
517
518
519
520
521
522
523
  	struct statx tmp;
  
  	memset(&tmp, 0, sizeof(tmp));
  
  	tmp.stx_mask = stat->result_mask;
  	tmp.stx_blksize = stat->blksize;
  	tmp.stx_attributes = stat->attributes;
  	tmp.stx_nlink = stat->nlink;
  	tmp.stx_uid = from_kuid_munged(current_user_ns(), stat->uid);
  	tmp.stx_gid = from_kgid_munged(current_user_ns(), stat->gid);
  	tmp.stx_mode = stat->mode;
  	tmp.stx_ino = stat->ino;
  	tmp.stx_size = stat->size;
  	tmp.stx_blocks = stat->blocks;
3209f68b3   David Howells   statx: Include a ...
524
  	tmp.stx_attributes_mask = stat->attributes_mask;
64bd72048   Eric Biggers   statx: optimize c...
525
526
527
528
529
530
531
532
533
534
535
536
  	tmp.stx_atime.tv_sec = stat->atime.tv_sec;
  	tmp.stx_atime.tv_nsec = stat->atime.tv_nsec;
  	tmp.stx_btime.tv_sec = stat->btime.tv_sec;
  	tmp.stx_btime.tv_nsec = stat->btime.tv_nsec;
  	tmp.stx_ctime.tv_sec = stat->ctime.tv_sec;
  	tmp.stx_ctime.tv_nsec = stat->ctime.tv_nsec;
  	tmp.stx_mtime.tv_sec = stat->mtime.tv_sec;
  	tmp.stx_mtime.tv_nsec = stat->mtime.tv_nsec;
  	tmp.stx_rdev_major = MAJOR(stat->rdev);
  	tmp.stx_rdev_minor = MINOR(stat->rdev);
  	tmp.stx_dev_major = MAJOR(stat->dev);
  	tmp.stx_dev_minor = MINOR(stat->dev);
fa2fcf4f1   Miklos Szeredi   statx: add mount ID
537
  	tmp.stx_mnt_id = stat->mnt_id;
64bd72048   Eric Biggers   statx: optimize c...
538
539
  
  	return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0;
a528d35e8   David Howells   statx: Add a syst...
540
  }
0018784fc   Bijan Mottahedeh   statx: allow syst...
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
  int do_statx(int dfd, const char __user *filename, unsigned flags,
  	     unsigned int mask, struct statx __user *buffer)
  {
  	struct kstat stat;
  	int error;
  
  	if (mask & STATX__RESERVED)
  		return -EINVAL;
  	if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE)
  		return -EINVAL;
  
  	error = vfs_statx(dfd, filename, flags, &stat, mask);
  	if (error)
  		return error;
  
  	return cp_statx(&stat, buffer);
  }
a528d35e8   David Howells   statx: Add a syst...
558
559
560
  /**
   * sys_statx - System call to get enhanced stats
   * @dfd: Base directory to pathwalk from *or* fd to stat.
1e2f82d1e   David Howells   statx: Kill fd-wi...
561
   * @filename: File to stat or "" with AT_EMPTY_PATH
a528d35e8   David Howells   statx: Add a syst...
562
563
564
565
   * @flags: AT_* flags to control pathwalk.
   * @mask: Parts of statx struct actually required.
   * @buffer: Result buffer.
   *
1e2f82d1e   David Howells   statx: Kill fd-wi...
566
567
   * Note that fstat() can be emulated by setting dfd to the fd of interest,
   * supplying "" as the filename and setting AT_EMPTY_PATH in the flags.
a528d35e8   David Howells   statx: Add a syst...
568
569
570
571
572
573
   */
  SYSCALL_DEFINE5(statx,
  		int, dfd, const char __user *, filename, unsigned, flags,
  		unsigned int, mask,
  		struct statx __user *, buffer)
  {
0018784fc   Bijan Mottahedeh   statx: allow syst...
574
  	return do_statx(dfd, filename, flags, mask, buffer);
a528d35e8   David Howells   statx: Add a syst...
575
  }
ac565de31   Al Viro   stat: move compat...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
  #ifdef CONFIG_COMPAT
  static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
  {
  	struct compat_stat tmp;
  
  	if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
  		return -EOVERFLOW;
  
  	memset(&tmp, 0, sizeof(tmp));
  	tmp.st_dev = old_encode_dev(stat->dev);
  	tmp.st_ino = stat->ino;
  	if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
  		return -EOVERFLOW;
  	tmp.st_mode = stat->mode;
  	tmp.st_nlink = stat->nlink;
  	if (tmp.st_nlink != stat->nlink)
  		return -EOVERFLOW;
  	SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
  	SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
  	tmp.st_rdev = old_encode_dev(stat->rdev);
  	if ((u64) stat->size > MAX_NON_LFS)
  		return -EOVERFLOW;
  	tmp.st_size = stat->size;
  	tmp.st_atime = stat->atime.tv_sec;
  	tmp.st_atime_nsec = stat->atime.tv_nsec;
  	tmp.st_mtime = stat->mtime.tv_sec;
  	tmp.st_mtime_nsec = stat->mtime.tv_nsec;
  	tmp.st_ctime = stat->ctime.tv_sec;
  	tmp.st_ctime_nsec = stat->ctime.tv_nsec;
  	tmp.st_blocks = stat->blocks;
  	tmp.st_blksize = stat->blksize;
  	return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
  }
  
  COMPAT_SYSCALL_DEFINE2(newstat, const char __user *, filename,
  		       struct compat_stat __user *, statbuf)
  {
  	struct kstat stat;
  	int error;
  
  	error = vfs_stat(filename, &stat);
  	if (error)
  		return error;
  	return cp_compat_stat(&stat, statbuf);
  }
  
  COMPAT_SYSCALL_DEFINE2(newlstat, const char __user *, filename,
  		       struct compat_stat __user *, statbuf)
  {
  	struct kstat stat;
  	int error;
  
  	error = vfs_lstat(filename, &stat);
  	if (error)
  		return error;
  	return cp_compat_stat(&stat, statbuf);
  }
  
  #ifndef __ARCH_WANT_STAT64
  COMPAT_SYSCALL_DEFINE4(newfstatat, unsigned int, dfd,
  		       const char __user *, filename,
  		       struct compat_stat __user *, statbuf, int, flag)
  {
  	struct kstat stat;
  	int error;
  
  	error = vfs_fstatat(dfd, filename, &stat, flag);
  	if (error)
  		return error;
  	return cp_compat_stat(&stat, statbuf);
  }
  #endif
  
  COMPAT_SYSCALL_DEFINE2(newfstat, unsigned int, fd,
  		       struct compat_stat __user *, statbuf)
  {
  	struct kstat stat;
  	int error = vfs_fstat(fd, &stat);
  
  	if (!error)
  		error = cp_compat_stat(&stat, statbuf);
  	return error;
  }
  #endif
b462707e7   Dmitry Monakhov   Add unlocked vers...
660
661
  /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */
  void __inode_add_bytes(struct inode *inode, loff_t bytes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
665
666
667
668
669
  	inode->i_blocks += bytes >> 9;
  	bytes &= 511;
  	inode->i_bytes += bytes;
  	if (inode->i_bytes >= 512) {
  		inode->i_blocks++;
  		inode->i_bytes -= 512;
  	}
b462707e7   Dmitry Monakhov   Add unlocked vers...
670
  }
eb315d2ae   Al Viro   ufs: restore main...
671
  EXPORT_SYMBOL(__inode_add_bytes);
b462707e7   Dmitry Monakhov   Add unlocked vers...
672
673
674
675
676
  
  void inode_add_bytes(struct inode *inode, loff_t bytes)
  {
  	spin_lock(&inode->i_lock);
  	__inode_add_bytes(inode, bytes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
680
  	spin_unlock(&inode->i_lock);
  }
  
  EXPORT_SYMBOL(inode_add_bytes);
1c8924eb1   Jan Kara   quota: provide in...
681
  void __inode_sub_bytes(struct inode *inode, loff_t bytes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
686
687
688
689
  	inode->i_blocks -= bytes >> 9;
  	bytes &= 511;
  	if (inode->i_bytes < bytes) {
  		inode->i_blocks--;
  		inode->i_bytes += 512;
  	}
  	inode->i_bytes -= bytes;
1c8924eb1   Jan Kara   quota: provide in...
690
691
692
693
694
695
696
697
  }
  
  EXPORT_SYMBOL(__inode_sub_bytes);
  
  void inode_sub_bytes(struct inode *inode, loff_t bytes)
  {
  	spin_lock(&inode->i_lock);
  	__inode_sub_bytes(inode, bytes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
704
705
706
707
  	spin_unlock(&inode->i_lock);
  }
  
  EXPORT_SYMBOL(inode_sub_bytes);
  
  loff_t inode_get_bytes(struct inode *inode)
  {
  	loff_t ret;
  
  	spin_lock(&inode->i_lock);
f4a8116a4   Jan Kara   fs: Provide __ino...
708
  	ret = __inode_get_bytes(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
  	spin_unlock(&inode->i_lock);
  	return ret;
  }
  
  EXPORT_SYMBOL(inode_get_bytes);
  
  void inode_set_bytes(struct inode *inode, loff_t bytes)
  {
  	/* Caller is here responsible for sufficient locking
  	 * (ie. inode->i_lock) */
  	inode->i_blocks = bytes >> 9;
  	inode->i_bytes = bytes & 511;
  }
  
  EXPORT_SYMBOL(inode_set_bytes);