Blame view

fs/stat.c 19.2 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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

a528d35e8   David Howells   statx: Add a syst...
47
48
49
50
51
  	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
52
  EXPORT_SYMBOL(generic_fillattr);
b7a6ec52d   J. Bruce Fields   vfs: split out vf...
53
54
55
56
  /**
   * 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...
57
58
   * @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...
59
60
61
62
   *
   * 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...
63
64
   * 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...
65
   */
a528d35e8   David Howells   statx: Add a syst...
66
67
  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
68
  {
bb668734c   David Howells   VFS: assorted d_b...
69
  	struct inode *inode = d_backing_inode(path->dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70

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

a528d35e8   David Howells   statx: Add a syst...
144
145
146
147
148
149
150
151
152
153
154
155
156
  /**
   * 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...
157
158
159
160
   * 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...
161
  {
2eae7a187   Christoph Hellwig   kill vfs_stat_fd ...
162
  	struct path path;
0112fc222   Oleg Drokin   Separate out comm...
163
  	int error = -EINVAL;
a528d35e8   David Howells   statx: Add a syst...
164
  	unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT;
0112fc222   Oleg Drokin   Separate out comm...
165

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

a528d35e8   David Howells   statx: Add a syst...
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)
65cfc6722   Al Viro   readlinkat(), fch...
175
  		lookup_flags |= LOOKUP_EMPTY;
a528d35e8   David Howells   statx: Add a syst...
176

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

0112fc222   Oleg Drokin   Separate out comm...
192

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

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

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

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

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

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

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

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

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

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

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

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

257ac264d   Heiko Carstens   [CVE-2009-0029] S...
355
  SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
358
359
360
361
362
363
364
  {
  	struct kstat stat;
  	int error = vfs_fstat(fd, &stat);
  
  	if (!error)
  		error = cp_new_stat(&stat, statbuf);
  
  	return error;
  }
6559eed8c   Heiko Carstens   [CVE-2009-0029] S...
365
366
  SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
  		char __user *, buf, int, bufsiz)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  {
2d8f30380   Al Viro   [PATCH] sanitize ...
368
  	struct path path;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  	int error;
1fa1e7f61   Andy Whitcroft   readlinkat: ensur...
370
  	int empty = 0;
7955119e0   Jeff Layton   vfs: fix readlink...
371
  	unsigned int lookup_flags = LOOKUP_EMPTY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
374
  
  	if (bufsiz <= 0)
  		return -EINVAL;
7955119e0   Jeff Layton   vfs: fix readlink...
375
376
  retry:
  	error = user_path_at_empty(dfd, pathname, lookup_flags, &path, &empty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
  	if (!error) {
bb668734c   David Howells   VFS: assorted d_b...
378
  		struct inode *inode = d_backing_inode(path.dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379

1fa1e7f61   Andy Whitcroft   readlinkat: ensur...
380
  		error = empty ? -ENOENT : -EINVAL;
fd4a0edf2   Miklos Szeredi   vfs: replace call...
381
382
383
384
  		/*
  		 * AFS mountpoints allow readlink(2) but are not symlinks
  		 */
  		if (d_is_symlink(path.dentry) || inode->i_op->readlink) {
2d8f30380   Al Viro   [PATCH] sanitize ...
385
  			error = security_inode_readlink(path.dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  			if (!error) {
68ac1234f   Al Viro   switch touch_atim...
387
  				touch_atime(&path);
fd4a0edf2   Miklos Szeredi   vfs: replace call...
388
  				error = vfs_readlink(path.dentry, buf, bufsiz);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
  			}
  		}
2d8f30380   Al Viro   [PATCH] sanitize ...
391
  		path_put(&path);
7955119e0   Jeff Layton   vfs: fix readlink...
392
393
394
395
  		if (retry_estale(error, lookup_flags)) {
  			lookup_flags |= LOOKUP_REVAL;
  			goto retry;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
  	}
  	return error;
  }
002c8976e   Heiko Carstens   [CVE-2009-0029] S...
399
400
  SYSCALL_DEFINE3(readlink, const char __user *, path, char __user *, buf,
  		int, bufsiz)
5590ff0d5   Ulrich Drepper   [PATCH] vfs: *at ...
401
402
403
  {
  	return sys_readlinkat(AT_FDCWD, path, buf, bufsiz);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  
  /* ---------- LFS-64 ----------- */
0753f70f0   Catalin Marinas   fs: Build sys_sta...
406
  #if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407

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

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

0112fc222   Oleg Drokin   Separate out comm...
484
485
486
487
  	error = vfs_fstatat(dfd, filename, &stat, flag);
  	if (error)
  		return error;
  	return cp_new_stat64(&stat, statbuf);
cff2b7600   Ulrich Drepper   [PATCH] fstatat64...
488
  }
0753f70f0   Catalin Marinas   fs: Build sys_sta...
489
  #endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490

64bd72048   Eric Biggers   statx: optimize c...
491
492
  static noinline_for_stack int
  cp_statx(const struct kstat *stat, struct statx __user *buffer)
a528d35e8   David Howells   statx: Add a syst...
493
  {
64bd72048   Eric Biggers   statx: optimize c...
494
495
496
497
498
499
500
501
502
503
504
505
506
507
  	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 ...
508
  	tmp.stx_attributes_mask = stat->attributes_mask;
64bd72048   Eric Biggers   statx: optimize c...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
  	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...
523
524
525
526
527
  }
  
  /**
   * 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...
528
   * @filename: File to stat or "" with AT_EMPTY_PATH
a528d35e8   David Howells   statx: Add a syst...
529
530
531
532
   * @flags: AT_* flags to control pathwalk.
   * @mask: Parts of statx struct actually required.
   * @buffer: Result buffer.
   *
1e2f82d1e   David Howells   statx: Kill fd-wi...
533
534
   * 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...
535
536
537
538
539
540
541
542
   */
  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...
543
544
  	if (mask & STATX__RESERVED)
  		return -EINVAL;
a528d35e8   David Howells   statx: Add a syst...
545
546
  	if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE)
  		return -EINVAL;
a528d35e8   David Howells   statx: Add a syst...
547

1e2f82d1e   David Howells   statx: Kill fd-wi...
548
  	error = vfs_statx(dfd, filename, flags, &stat, mask);
a528d35e8   David Howells   statx: Add a syst...
549
550
  	if (error)
  		return error;
64bd72048   Eric Biggers   statx: optimize c...
551
552
  
  	return cp_statx(&stat, buffer);
a528d35e8   David Howells   statx: Add a syst...
553
  }
ac565de31   Al Viro   stat: move compat...
554
555
556
557
558
559
560
561
562
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
  #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...
638
639
  /* 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
640
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
644
645
646
647
  	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...
648
  }
eb315d2ae   Al Viro   ufs: restore main...
649
  EXPORT_SYMBOL(__inode_add_bytes);
b462707e7   Dmitry Monakhov   Add unlocked vers...
650
651
652
653
654
  
  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
655
656
657
658
  	spin_unlock(&inode->i_lock);
  }
  
  EXPORT_SYMBOL(inode_add_bytes);
1c8924eb1   Jan Kara   quota: provide in...
659
  void __inode_sub_bytes(struct inode *inode, loff_t bytes)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
663
664
665
666
667
  	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...
668
669
670
671
672
673
674
675
  }
  
  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
676
677
678
679
680
681
682
683
684
685
  	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...
686
  	ret = __inode_get_bytes(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
  	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);