Blame view

fs/stat.c 19.4 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>
a528d35e8   David Howells   statx: Add a syst...
22
23
24
25
26
27
28
29
30
  /**
   * 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
31
32
33
34
35
36
37
38
39
  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...
40
  	stat->size = i_size_read(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
  	stat->atime = inode->i_atime;
  	stat->mtime = inode->i_mtime;
  	stat->ctime = inode->i_ctime;
93407472a   Fabian Frederick   fs: add i_blocksi...
44
  	stat->blksize = i_blocksize(inode);
3ddcd0569   Linus Torvalds   vfs: optimize ino...
45
  	stat->blocks = inode->i_blocks;
a528d35e8   David Howells   statx: Add a syst...
46
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  EXPORT_SYMBOL(generic_fillattr);
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
48
49
50
51
  /**
   * 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...
52
53
   * @request_mask: STATX_xxx flags indicating what the caller wants
   * @query_flags: Query mode (KSTAT_QUERY_FLAGS)
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
54
55
56
57
   *
   * 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...
58
59
   * 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...
60
   */
a528d35e8   David Howells   statx: Add a syst...
61
62
  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
63
  {
bb668734c   David Howells   VFS: assorted d_b...
64
  	struct inode *inode = d_backing_inode(path->dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65

a528d35e8   David Howells   statx: Add a syst...
66
67
68
69
  	memset(stat, 0, sizeof(*stat));
  	stat->result_mask |= STATX_BASIC_STATS;
  	request_mask &= STATX_ALL;
  	query_flags &= KSTAT_QUERY_FLAGS;
801e52379   Christoph Hellwig   fs: move generic ...
70
71
72
73
74
75
  
  	/* allow the fs to override these if it really wants to */
  	if (IS_NOATIME(inode))
  		stat->result_mask &= ~STATX_ATIME;
  	if (IS_AUTOMOUNT(inode))
  		stat->attributes |= STATX_ATTR_AUTOMOUNT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  	if (inode->i_op->getattr)
a528d35e8   David Howells   statx: Add a syst...
77
78
  		return inode->i_op->getattr(path, stat, request_mask,
  					    query_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
  
  	generic_fillattr(inode, stat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
  	return 0;
  }
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
83
  EXPORT_SYMBOL(vfs_getattr_nosec);
a528d35e8   David Howells   statx: Add a syst...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  /*
   * 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
   * @query_flags: Query mode (KSTAT_QUERY_FLAGS)
   *
   * 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...
107
108
  {
  	int retval;
3f7036a07   Al Viro   switch security_i...
109
  	retval = security_inode_getattr(path);
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
110
111
  	if (retval)
  		return retval;
a528d35e8   David Howells   statx: Add a syst...
112
  	return vfs_getattr_nosec(path, stat, request_mask, query_flags);
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
113
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  EXPORT_SYMBOL(vfs_getattr);
a528d35e8   David Howells   statx: Add a syst...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  /**
   * vfs_statx_fd - Get the enhanced basic attributes by file descriptor
   * @fd: The file descriptor referring to the file of interest
   * @stat: The result structure to fill in.
   * @request_mask: STATX_xxx flags indicating what the caller wants
   * @query_flags: Query mode (KSTAT_QUERY_FLAGS)
   *
   * 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.
   */
  int vfs_statx_fd(unsigned int fd, struct kstat *stat,
  		 u32 request_mask, unsigned int query_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  {
8c7493aa3   Eric Biggers   statx: reject unk...
130
  	struct fd f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  	int error = -EBADF;
8c7493aa3   Eric Biggers   statx: reject unk...
132
133
134
135
  	if (query_flags & ~KSTAT_QUERY_FLAGS)
  		return -EINVAL;
  
  	f = fdget_raw(fd);
2903ff019   Al Viro   switch simple cas...
136
  	if (f.file) {
a528d35e8   David Howells   statx: Add a syst...
137
138
  		error = vfs_getattr(&f.file->f_path, stat,
  				    request_mask, query_flags);
2903ff019   Al Viro   switch simple cas...
139
  		fdput(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
  	}
  	return error;
  }
a528d35e8   David Howells   statx: Add a syst...
143
  EXPORT_SYMBOL(vfs_statx_fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144

a528d35e8   David Howells   statx: Add a syst...
145
146
147
148
149
150
151
152
153
154
155
156
157
  /**
   * 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...
158
159
160
161
   * 0 will be returned on success, and a -ve error code if unsuccessful.
   */
  int vfs_statx(int dfd, const char __user *filename, int flags,
  	      struct kstat *stat, u32 request_mask)
0112fc222   Oleg Drokin   Separate out comm...
162
  {
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
163
  	struct path path;
0112fc222   Oleg Drokin   Separate out comm...
164
  	int error = -EINVAL;
a528d35e8   David Howells   statx: Add a syst...
165
  	unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
0112fc222   Oleg Drokin   Separate out comm...
166

a528d35e8   David Howells   statx: Add a syst...
167
168
169
  	if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
  		       AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
  		return -EINVAL;
0112fc222   Oleg Drokin   Separate out comm...
170

a528d35e8   David Howells   statx: Add a syst...
171
172
173
174
175
  	if (flags & AT_SYMLINK_NOFOLLOW)
  		lookup_flags &= ~LOOKUP_FOLLOW;
  	if (flags & AT_NO_AUTOMOUNT)
  		lookup_flags &= ~LOOKUP_AUTOMOUNT;
  	if (flags & AT_EMPTY_PATH)
65cfc6722   Al Viro   readlinkat(), fch...
176
  		lookup_flags |= LOOKUP_EMPTY;
a528d35e8   David Howells   statx: Add a syst...
177

836fb7e7b   Jeff Layton   vfs: make fstatat...
178
  retry:
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
179
180
181
  	error = user_path_at(dfd, filename, lookup_flags, &path);
  	if (error)
  		goto out;
a528d35e8   David Howells   statx: Add a syst...
182
  	error = vfs_getattr(&path, stat, request_mask, flags);
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
183
  	path_put(&path);
836fb7e7b   Jeff Layton   vfs: make fstatat...
184
185
186
187
  	if (retry_estale(error, lookup_flags)) {
  		lookup_flags |= LOOKUP_REVAL;
  		goto retry;
  	}
0112fc222   Oleg Drokin   Separate out comm...
188
189
190
  out:
  	return error;
  }
a528d35e8   David Howells   statx: Add a syst...
191
  EXPORT_SYMBOL(vfs_statx);
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
192

0112fc222   Oleg Drokin   Separate out comm...
193

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
195
196
197
198
199
200
201
202
203
  #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...
204

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
207
208
209
210
211
212
213
214
215
216
217
  	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...
218
219
  	if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
222
223
  	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...
224
225
  	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
226
227
228
229
  	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...
230
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
233
234
235
236
  	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...
237
238
  SYSCALL_DEFINE2(stat, const char __user *, filename,
  		struct __old_kernel_stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
  {
  	struct kstat stat;
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
241
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
243
244
245
  	error = vfs_stat(filename, &stat);
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246

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

c78873252   David Howells   Mark arguments to...
250
251
  SYSCALL_DEFINE2(lstat, const char __user *, filename,
  		struct __old_kernel_stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
  {
  	struct kstat stat;
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
254
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
256
257
258
  	error = vfs_lstat(filename, &stat);
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
260
  	return cp_old_stat(&stat, statbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  }
257ac264d   Heiko Carstens   [CVE-2009-0029] S...
262
263
  
  SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
267
268
269
270
271
272
273
274
  {
  	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...
275
  #ifdef __ARCH_WANT_NEW_STAT
a52dd971f   Linus Torvalds   vfs: de-crapify "...
276
277
278
279
280
  #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...
281
  #define valid_dev(x)  choose_32_64(old_valid_dev(x),true)
a52dd971f   Linus Torvalds   vfs: de-crapify "...
282
  #define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x)
8529f613b   Linus Torvalds   vfs: don't force ...
283
284
285
  #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
286
287
288
  static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
  {
  	struct stat tmp;
a52dd971f   Linus Torvalds   vfs: de-crapify "...
289
  	if (!valid_dev(stat->dev) || !valid_dev(stat->rdev))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  		return -EOVERFLOW;
a52dd971f   Linus Torvalds   vfs: de-crapify "...
291
292
  #if BITS_PER_LONG == 32
  	if (stat->size > MAX_NON_LFS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
  		return -EOVERFLOW;
  #endif
8529f613b   Linus Torvalds   vfs: don't force ...
295
  	INIT_STRUCT_STAT_PADDING(tmp);
a52dd971f   Linus Torvalds   vfs: de-crapify "...
296
  	tmp.st_dev = encode_dev(stat->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  	tmp.st_ino = stat->ino;
afefdbb28   David Howells   [PATCH] VFS: Make...
298
299
  	if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
  	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...
304
305
  	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 "...
306
  	tmp.st_rdev = encode_dev(stat->rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
309
310
311
312
313
314
315
316
317
318
319
  	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...
320
321
  SYSCALL_DEFINE2(newstat, const char __user *, filename,
  		struct stat __user *, statbuf)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
322
323
  {
  	struct kstat stat;
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
324
  	int error = vfs_stat(filename, &stat);
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
325

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

2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
336
337
338
  	error = vfs_lstat(filename, &stat);
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339

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

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

0112fc222   Oleg Drokin   Separate out comm...
350
351
352
353
  	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
354
  }
cff2b7600   Ulrich Drepper   [PATCH] fstatat64...
355
  #endif
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
356

257ac264d   Heiko Carstens   [CVE-2009-0029] S...
357
  SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
361
362
363
364
365
366
  {
  	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...
367
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368

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

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

8529f613b   Linus Torvalds   vfs: don't force ...
417
418
419
  #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
420
421
422
  static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
  {
  	struct stat64 tmp;
8529f613b   Linus Torvalds   vfs: don't force ...
423
  	INIT_STRUCT_STAT64_PADDING(tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
  #ifdef CONFIG_MIPS
  	/* mips has weird padding, so we don't get 64 bits there */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
429
430
431
432
  	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...
433
434
  	if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
  		return -EOVERFLOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
438
439
  #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...
440
441
  	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
442
443
444
445
446
447
448
449
450
451
452
  	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...
453
454
  SYSCALL_DEFINE2(stat64, const char __user *, filename,
  		struct stat64 __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
459
460
461
462
463
  {
  	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...
464

c78873252   David Howells   Mark arguments to...
465
466
  SYSCALL_DEFINE2(lstat64, const char __user *, filename,
  		struct stat64 __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
470
471
472
473
474
475
  {
  	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...
476
477
  
  SYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
480
481
482
483
484
485
486
  {
  	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...
487
  SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename,
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
488
  		struct stat64 __user *, statbuf, int, flag)
cff2b7600   Ulrich Drepper   [PATCH] fstatat64...
489
490
  {
  	struct kstat stat;
0112fc222   Oleg Drokin   Separate out comm...
491
  	int error;
cff2b7600   Ulrich Drepper   [PATCH] fstatat64...
492

0112fc222   Oleg Drokin   Separate out comm...
493
494
495
496
  	error = vfs_fstatat(dfd, filename, &stat, flag);
  	if (error)
  		return error;
  	return cp_new_stat64(&stat, statbuf);
cff2b7600   Ulrich Drepper   [PATCH] fstatat64...
497
  }
0753f70f0   Catalin Marinas   fs: Build sys_sta...
498
  #endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499

64bd72048   Eric Biggers   statx: optimize c...
500
501
  static noinline_for_stack int
  cp_statx(const struct kstat *stat, struct statx __user *buffer)
a528d35e8   David Howells   statx: Add a syst...
502
  {
64bd72048   Eric Biggers   statx: optimize c...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
  	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 ...
517
  	tmp.stx_attributes_mask = stat->attributes_mask;
64bd72048   Eric Biggers   statx: optimize c...
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  	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);
  
  	return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0;
a528d35e8   David Howells   statx: Add a syst...
532
533
534
535
536
  }
  
  /**
   * 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...
537
   * @filename: File to stat or "" with AT_EMPTY_PATH
a528d35e8   David Howells   statx: Add a syst...
538
539
540
541
   * @flags: AT_* flags to control pathwalk.
   * @mask: Parts of statx struct actually required.
   * @buffer: Result buffer.
   *
1e2f82d1e   David Howells   statx: Kill fd-wi...
542
543
   * 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...
544
545
546
547
548
549
550
551
   */
  SYSCALL_DEFINE5(statx,
  		int, dfd, const char __user *, filename, unsigned, flags,
  		unsigned int, mask,
  		struct statx __user *, buffer)
  {
  	struct kstat stat;
  	int error;
47071aee6   David Howells   statx: Reserve th...
552
553
  	if (mask & STATX__RESERVED)
  		return -EINVAL;
a528d35e8   David Howells   statx: Add a syst...
554
555
  	if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE)
  		return -EINVAL;
a528d35e8   David Howells   statx: Add a syst...
556

1e2f82d1e   David Howells   statx: Kill fd-wi...
557
  	error = vfs_statx(dfd, filename, flags, &stat, mask);
a528d35e8   David Howells   statx: Add a syst...
558
559
  	if (error)
  		return error;
64bd72048   Eric Biggers   statx: optimize c...
560
561
  
  	return cp_statx(&stat, buffer);
a528d35e8   David Howells   statx: Add a syst...
562
  }
ac565de31   Al Viro   stat: move compat...
563
564
565
566
567
568
569
570
571
572
573
574
575
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
  #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...
647
648
  /* 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
649
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
651
652
653
654
655
656
  	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...
657
  }
eb315d2ae   Al Viro   ufs: restore main...
658
  EXPORT_SYMBOL(__inode_add_bytes);
b462707e7   Dmitry Monakhov   Add unlocked vers...
659
660
661
662
663
  
  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
664
665
666
667
  	spin_unlock(&inode->i_lock);
  }
  
  EXPORT_SYMBOL(inode_add_bytes);
1c8924eb1   Jan Kara   quota: provide in...
668
  void __inode_sub_bytes(struct inode *inode, loff_t bytes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
673
674
675
676
  	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...
677
678
679
680
681
682
683
684
  }
  
  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
685
686
687
688
689
690
691
692
693
694
  	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...
695
  	ret = __inode_get_bytes(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
  	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);