Blame view

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

a528d35e8   David Howells   statx: Add a syst...
67
68
69
70
  	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 ...
71
72
73
74
75
76
  
  	/* 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
77
  	if (inode->i_op->getattr)
a528d35e8   David Howells   statx: Add a syst...
78
79
  		return inode->i_op->getattr(path, stat, request_mask,
  					    query_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
  
  	generic_fillattr(inode, stat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
  	return 0;
  }
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
84
  EXPORT_SYMBOL(vfs_getattr_nosec);
a528d35e8   David Howells   statx: Add a syst...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  /*
   * 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...
108
109
  {
  	int retval;
3f7036a07   Al Viro   switch security_i...
110
  	retval = security_inode_getattr(path);
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
111
112
  	if (retval)
  		return retval;
a528d35e8   David Howells   statx: Add a syst...
113
  	return vfs_getattr_nosec(path, stat, request_mask, query_flags);
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
114
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  EXPORT_SYMBOL(vfs_getattr);
a528d35e8   David Howells   statx: Add a syst...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  /**
   * 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
130
  {
8c7493aa3   Eric Biggers   statx: reject unk...
131
  	struct fd f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
  	int error = -EBADF;
8c7493aa3   Eric Biggers   statx: reject unk...
133
134
135
136
  	if (query_flags & ~KSTAT_QUERY_FLAGS)
  		return -EINVAL;
  
  	f = fdget_raw(fd);
2903ff019   Al Viro   switch simple cas...
137
  	if (f.file) {
a528d35e8   David Howells   statx: Add a syst...
138
139
  		error = vfs_getattr(&f.file->f_path, stat,
  				    request_mask, query_flags);
2903ff019   Al Viro   switch simple cas...
140
  		fdput(f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
  	}
  	return error;
  }
a528d35e8   David Howells   statx: Add a syst...
144
  EXPORT_SYMBOL(vfs_statx_fd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145

3934e36f6   Jens Axboe   fs: make two stat...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  inline unsigned vfs_stat_set_lookup_flags(unsigned *lookup_flags, int flags)
  {
  	if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
  		       AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0)
  		return -EINVAL;
  
  	*lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
  	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;
  
  	return 0;
  }
a528d35e8   David Howells   statx: Add a syst...
162
163
164
165
166
167
168
169
170
171
172
173
174
  /**
   * 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...
175
176
177
178
   * 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...
179
  {
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
180
  	struct path path;
0112fc222   Oleg Drokin   Separate out comm...
181
  	int error = -EINVAL;
3934e36f6   Jens Axboe   fs: make two stat...
182
  	unsigned lookup_flags;
0112fc222   Oleg Drokin   Separate out comm...
183

3934e36f6   Jens Axboe   fs: make two stat...
184
  	if (vfs_stat_set_lookup_flags(&lookup_flags, flags))
a528d35e8   David Howells   statx: Add a syst...
185
  		return -EINVAL;
836fb7e7b   Jeff Layton   vfs: make fstatat...
186
  retry:
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
187
188
189
  	error = user_path_at(dfd, filename, lookup_flags, &path);
  	if (error)
  		goto out;
a528d35e8   David Howells   statx: Add a syst...
190
  	error = vfs_getattr(&path, stat, request_mask, flags);
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
191
  	path_put(&path);
836fb7e7b   Jeff Layton   vfs: make fstatat...
192
193
194
195
  	if (retry_estale(error, lookup_flags)) {
  		lookup_flags |= LOOKUP_REVAL;
  		goto retry;
  	}
0112fc222   Oleg Drokin   Separate out comm...
196
197
198
  out:
  	return error;
  }
a528d35e8   David Howells   statx: Add a syst...
199
  EXPORT_SYMBOL(vfs_statx);
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
200

0112fc222   Oleg Drokin   Separate out comm...
201

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
208
209
210
211
  #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...
212

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

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

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

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

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

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

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

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

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

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

0112fc222   Oleg Drokin   Separate out comm...
358
359
360
361
  	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
362
  }
cff2b7600   Ulrich Drepper   [PATCH] fstatat64...
363
  #endif
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
364

257ac264d   Heiko Carstens   [CVE-2009-0029] S...
365
  SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
369
370
371
372
373
374
  {
  	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...
375
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376

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

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

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

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

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

3934e36f6   Jens Axboe   fs: make two stat...
508
  noinline_for_stack int
64bd72048   Eric Biggers   statx: optimize c...
509
  cp_statx(const struct kstat *stat, struct statx __user *buffer)
a528d35e8   David Howells   statx: Add a syst...
510
  {
64bd72048   Eric Biggers   statx: optimize c...
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  	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 ...
525
  	tmp.stx_attributes_mask = stat->attributes_mask;
64bd72048   Eric Biggers   statx: optimize c...
526
527
528
529
530
531
532
533
534
535
536
537
538
539
  	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...
540
541
542
543
544
  }
  
  /**
   * 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...
545
   * @filename: File to stat or "" with AT_EMPTY_PATH
a528d35e8   David Howells   statx: Add a syst...
546
547
548
549
   * @flags: AT_* flags to control pathwalk.
   * @mask: Parts of statx struct actually required.
   * @buffer: Result buffer.
   *
1e2f82d1e   David Howells   statx: Kill fd-wi...
550
551
   * 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...
552
553
554
555
556
557
558
559
   */
  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...
560
561
  	if (mask & STATX__RESERVED)
  		return -EINVAL;
a528d35e8   David Howells   statx: Add a syst...
562
563
  	if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE)
  		return -EINVAL;
a528d35e8   David Howells   statx: Add a syst...
564

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