stat.c 11.9 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
/*
 *  linux/fs/stat.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

7
#include <linux/export.h>
Linus Torvalds's avatar
Linus Torvalds committed
8
9
10
11
12
13
14
15
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/file.h>
#include <linux/highuid.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/syscalls.h>
16
#include <linux/pagemap.h>
Linus Torvalds's avatar
Linus Torvalds committed
17
18
19
20
21
22
23
24
25
26
27
28
29

#include <asm/uaccess.h>
#include <asm/unistd.h>

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;
30
	stat->size = i_size_read(inode);
Linus Torvalds's avatar
Linus Torvalds committed
31
32
33
	stat->atime = inode->i_atime;
	stat->mtime = inode->i_mtime;
	stat->ctime = inode->i_ctime;
34
	stat->blksize = (1 << inode->i_blkbits);
35
	stat->blocks = inode->i_blocks;
Linus Torvalds's avatar
Linus Torvalds committed
36
37
38
39
}

EXPORT_SYMBOL(generic_fillattr);

40
41
42
43
44
45
46
47
48
49
50
51
52
/**
 * vfs_getattr_nosec - getattr without security checks
 * @path: file to get attributes from
 * @stat: structure to return attributes in
 *
 * Get attributes without calling security_inode_getattr.
 *
 * Currently the only caller other than vfs_getattr is internal to the
 * filehandle lookup code, which uses only the inode number and returns
 * no attributes to any user.  Any other code probably wants
 * vfs_getattr.
 */
int vfs_getattr_nosec(struct path *path, struct kstat *stat)
Linus Torvalds's avatar
Linus Torvalds committed
53
{
54
	struct inode *inode = d_backing_inode(path->dentry);
Linus Torvalds's avatar
Linus Torvalds committed
55
56

	if (inode->i_op->getattr)
Al Viro's avatar
Al Viro committed
57
		return inode->i_op->getattr(path->mnt, path->dentry, stat);
Linus Torvalds's avatar
Linus Torvalds committed
58
59
60
61
62

	generic_fillattr(inode, stat);
	return 0;
}

63
64
65
66
67
68
EXPORT_SYMBOL(vfs_getattr_nosec);

int vfs_getattr(struct path *path, struct kstat *stat)
{
	int retval;

69
	retval = security_inode_getattr(path);
70
71
72
73
74
	if (retval)
		return retval;
	return vfs_getattr_nosec(path, stat);
}

Linus Torvalds's avatar
Linus Torvalds committed
75
76
77
78
EXPORT_SYMBOL(vfs_getattr);

int vfs_fstat(unsigned int fd, struct kstat *stat)
{
79
	struct fd f = fdget_raw(fd);
Linus Torvalds's avatar
Linus Torvalds committed
80
81
	int error = -EBADF;

82
	if (f.file) {
Al Viro's avatar
Al Viro committed
83
		error = vfs_getattr(&f.file->f_path, stat);
84
		fdput(f);
Linus Torvalds's avatar
Linus Torvalds committed
85
86
87
88
89
	}
	return error;
}
EXPORT_SYMBOL(vfs_fstat);

90
91
int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
		int flag)
92
{
93
	struct path path;
94
	int error = -EINVAL;
95
	unsigned int lookup_flags = 0;
96

97
98
	if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
		      AT_EMPTY_PATH)) != 0)
99
100
		goto out;

101
102
	if (!(flag & AT_SYMLINK_NOFOLLOW))
		lookup_flags |= LOOKUP_FOLLOW;
103
104
	if (flag & AT_EMPTY_PATH)
		lookup_flags |= LOOKUP_EMPTY;
105
retry:
106
107
108
109
	error = user_path_at(dfd, filename, lookup_flags, &path);
	if (error)
		goto out;

Al Viro's avatar
Al Viro committed
110
	error = vfs_getattr(&path, stat);
111
	path_put(&path);
112
113
114
115
	if (retry_estale(error, lookup_flags)) {
		lookup_flags |= LOOKUP_REVAL;
		goto retry;
	}
116
117
118
119
120
out:
	return error;
}
EXPORT_SYMBOL(vfs_fstatat);

121
int vfs_stat(const char __user *name, struct kstat *stat)
122
123
124
125
126
{
	return vfs_fstatat(AT_FDCWD, name, stat, 0);
}
EXPORT_SYMBOL(vfs_stat);

127
int vfs_lstat(const char __user *name, struct kstat *stat)
128
129
130
131
132
{
	return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW);
}
EXPORT_SYMBOL(vfs_lstat);

133

Linus Torvalds's avatar
Linus Torvalds committed
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#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;
	
	if (warncount > 0) {
		warncount--;
		printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n",
			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;
157
158
	if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
		return -EOVERFLOW;
Linus Torvalds's avatar
Linus Torvalds committed
159
160
161
162
	tmp.st_mode = stat->mode;
	tmp.st_nlink = stat->nlink;
	if (tmp.st_nlink != stat->nlink)
		return -EOVERFLOW;
163
164
	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));
Linus Torvalds's avatar
Linus Torvalds committed
165
166
167
168
169
170
171
172
173
174
175
176
	tmp.st_rdev = old_encode_dev(stat->rdev);
#if BITS_PER_LONG == 32
	if (stat->size > MAX_NON_LFS)
		return -EOVERFLOW;
#endif	
	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;
}

177
178
SYSCALL_DEFINE2(stat, const char __user *, filename,
		struct __old_kernel_stat __user *, statbuf)
Linus Torvalds's avatar
Linus Torvalds committed
179
180
{
	struct kstat stat;
181
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
182

183
184
185
	error = vfs_stat(filename, &stat);
	if (error)
		return error;
Linus Torvalds's avatar
Linus Torvalds committed
186

187
	return cp_old_stat(&stat, statbuf);
Linus Torvalds's avatar
Linus Torvalds committed
188
}
189

190
191
SYSCALL_DEFINE2(lstat, const char __user *, filename,
		struct __old_kernel_stat __user *, statbuf)
Linus Torvalds's avatar
Linus Torvalds committed
192
193
{
	struct kstat stat;
194
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
195

196
197
198
	error = vfs_lstat(filename, &stat);
	if (error)
		return error;
Linus Torvalds's avatar
Linus Torvalds committed
199

200
	return cp_old_stat(&stat, statbuf);
Linus Torvalds's avatar
Linus Torvalds committed
201
}
202
203

SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, statbuf)
Linus Torvalds's avatar
Linus Torvalds committed
204
205
206
207
208
209
210
211
212
213
214
215
{
	struct kstat stat;
	int error = vfs_fstat(fd, &stat);

	if (!error)
		error = cp_old_stat(&stat, statbuf);

	return error;
}

#endif /* __ARCH_WANT_OLD_STAT */

216
217
218
219
220
221
#if BITS_PER_LONG == 32
#  define choose_32_64(a,b) a
#else
#  define choose_32_64(a,b) b
#endif

222
#define valid_dev(x)  choose_32_64(old_valid_dev(x),true)
223
224
#define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x)

225
226
227
228
#ifndef INIT_STRUCT_STAT_PADDING
#  define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st))
#endif

Linus Torvalds's avatar
Linus Torvalds committed
229
230
231
232
static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
{
	struct stat tmp;

233
	if (!valid_dev(stat->dev) || !valid_dev(stat->rdev))
Linus Torvalds's avatar
Linus Torvalds committed
234
		return -EOVERFLOW;
235
236
#if BITS_PER_LONG == 32
	if (stat->size > MAX_NON_LFS)
Linus Torvalds's avatar
Linus Torvalds committed
237
238
239
		return -EOVERFLOW;
#endif

240
	INIT_STRUCT_STAT_PADDING(tmp);
241
	tmp.st_dev = encode_dev(stat->dev);
Linus Torvalds's avatar
Linus Torvalds committed
242
	tmp.st_ino = stat->ino;
243
244
	if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
		return -EOVERFLOW;
Linus Torvalds's avatar
Linus Torvalds committed
245
246
247
248
	tmp.st_mode = stat->mode;
	tmp.st_nlink = stat->nlink;
	if (tmp.st_nlink != stat->nlink)
		return -EOVERFLOW;
249
250
	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));
251
	tmp.st_rdev = encode_dev(stat->rdev);
Linus Torvalds's avatar
Linus Torvalds committed
252
253
254
255
256
257
258
259
260
261
262
263
264
265
	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;
}

266
267
SYSCALL_DEFINE2(newstat, const char __user *, filename,
		struct stat __user *, statbuf)
268
269
{
	struct kstat stat;
270
	int error = vfs_stat(filename, &stat);
271

272
273
274
	if (error)
		return error;
	return cp_new_stat(&stat, statbuf);
275
276
}

277
278
SYSCALL_DEFINE2(newlstat, const char __user *, filename,
		struct stat __user *, statbuf)
Linus Torvalds's avatar
Linus Torvalds committed
279
280
{
	struct kstat stat;
281
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
282

283
284
285
	error = vfs_lstat(filename, &stat);
	if (error)
		return error;
Linus Torvalds's avatar
Linus Torvalds committed
286

287
	return cp_new_stat(&stat, statbuf);
Linus Torvalds's avatar
Linus Torvalds committed
288
}
289

290
#if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT)
291
SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename,
292
		struct stat __user *, statbuf, int, flag)
Linus Torvalds's avatar
Linus Torvalds committed
293
294
{
	struct kstat stat;
295
	int error;
Linus Torvalds's avatar
Linus Torvalds committed
296

297
298
299
300
	error = vfs_fstatat(dfd, filename, &stat, flag);
	if (error)
		return error;
	return cp_new_stat(&stat, statbuf);
Linus Torvalds's avatar
Linus Torvalds committed
301
}
Ulrich Drepper's avatar
Ulrich Drepper committed
302
#endif
303

304
SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf)
Linus Torvalds's avatar
Linus Torvalds committed
305
306
307
308
309
310
311
312
313
314
{
	struct kstat stat;
	int error = vfs_fstat(fd, &stat);

	if (!error)
		error = cp_new_stat(&stat, statbuf);

	return error;
}

315
316
SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
		char __user *, buf, int, bufsiz)
Linus Torvalds's avatar
Linus Torvalds committed
317
{
318
	struct path path;
Linus Torvalds's avatar
Linus Torvalds committed
319
	int error;
320
	int empty = 0;
321
	unsigned int lookup_flags = LOOKUP_EMPTY;
Linus Torvalds's avatar
Linus Torvalds committed
322
323
324
325

	if (bufsiz <= 0)
		return -EINVAL;

326
327
retry:
	error = user_path_at_empty(dfd, pathname, lookup_flags, &path, &empty);
Linus Torvalds's avatar
Linus Torvalds committed
328
	if (!error) {
329
		struct inode *inode = d_backing_inode(path.dentry);
Linus Torvalds's avatar
Linus Torvalds committed
330

331
		error = empty ? -ENOENT : -EINVAL;
Al Viro's avatar
Al Viro committed
332
		if (inode->i_op->readlink) {
333
			error = security_inode_readlink(path.dentry);
Linus Torvalds's avatar
Linus Torvalds committed
334
			if (!error) {
Al Viro's avatar
Al Viro committed
335
				touch_atime(&path);
336
				error = inode->i_op->readlink(path.dentry,
337
							      buf, bufsiz);
Linus Torvalds's avatar
Linus Torvalds committed
338
339
			}
		}
340
		path_put(&path);
341
342
343
344
		if (retry_estale(error, lookup_flags)) {
			lookup_flags |= LOOKUP_REVAL;
			goto retry;
		}
Linus Torvalds's avatar
Linus Torvalds committed
345
346
347
348
	}
	return error;
}

349
350
SYSCALL_DEFINE3(readlink, const char __user *, path, char __user *, buf,
		int, bufsiz)
351
352
353
354
{
	return sys_readlinkat(AT_FDCWD, path, buf, bufsiz);
}

Linus Torvalds's avatar
Linus Torvalds committed
355
356

/* ---------- LFS-64 ----------- */
357
#if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64)
Linus Torvalds's avatar
Linus Torvalds committed
358

359
360
361
362
#ifndef INIT_STRUCT_STAT64_PADDING
#  define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st))
#endif

Linus Torvalds's avatar
Linus Torvalds committed
363
364
365
366
static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
{
	struct stat64 tmp;

367
	INIT_STRUCT_STAT64_PADDING(tmp);
Linus Torvalds's avatar
Linus Torvalds committed
368
369
370
371
372
373
374
375
376
#ifdef CONFIG_MIPS
	/* mips has weird padding, so we don't get 64 bits there */
	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;
377
378
	if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
		return -EOVERFLOW;
Linus Torvalds's avatar
Linus Torvalds committed
379
380
381
382
383
#ifdef STAT64_HAS_BROKEN_ST_INO
	tmp.__st_ino = stat->ino;
#endif
	tmp.st_mode = stat->mode;
	tmp.st_nlink = stat->nlink;
384
385
	tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
	tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
Linus Torvalds's avatar
Linus Torvalds committed
386
387
388
389
390
391
392
393
394
395
396
397
	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;
}

398
399
SYSCALL_DEFINE2(stat64, const char __user *, filename,
		struct stat64 __user *, statbuf)
Linus Torvalds's avatar
Linus Torvalds committed
400
401
402
403
404
405
406
407
408
{
	struct kstat stat;
	int error = vfs_stat(filename, &stat);

	if (!error)
		error = cp_new_stat64(&stat, statbuf);

	return error;
}
409

410
411
SYSCALL_DEFINE2(lstat64, const char __user *, filename,
		struct stat64 __user *, statbuf)
Linus Torvalds's avatar
Linus Torvalds committed
412
413
414
415
416
417
418
419
420
{
	struct kstat stat;
	int error = vfs_lstat(filename, &stat);

	if (!error)
		error = cp_new_stat64(&stat, statbuf);

	return error;
}
421
422

SYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf)
Linus Torvalds's avatar
Linus Torvalds committed
423
424
425
426
427
428
429
430
431
432
{
	struct kstat stat;
	int error = vfs_fstat(fd, &stat);

	if (!error)
		error = cp_new_stat64(&stat, statbuf);

	return error;
}

433
SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename,
434
		struct stat64 __user *, statbuf, int, flag)
Ulrich Drepper's avatar
Ulrich Drepper committed
435
436
{
	struct kstat stat;
437
	int error;
Ulrich Drepper's avatar
Ulrich Drepper committed
438

439
440
441
442
	error = vfs_fstatat(dfd, filename, &stat, flag);
	if (error)
		return error;
	return cp_new_stat64(&stat, statbuf);
Ulrich Drepper's avatar
Ulrich Drepper committed
443
}
444
#endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */
Linus Torvalds's avatar
Linus Torvalds committed
445

446
447
/* Caller is here responsible for sufficient locking (ie. inode->i_lock) */
void __inode_add_bytes(struct inode *inode, loff_t bytes)
Linus Torvalds's avatar
Linus Torvalds committed
448
449
450
451
452
453
454
455
{
	inode->i_blocks += bytes >> 9;
	bytes &= 511;
	inode->i_bytes += bytes;
	if (inode->i_bytes >= 512) {
		inode->i_blocks++;
		inode->i_bytes -= 512;
	}
456
457
458
459
460
461
}

void inode_add_bytes(struct inode *inode, loff_t bytes)
{
	spin_lock(&inode->i_lock);
	__inode_add_bytes(inode, bytes);
Linus Torvalds's avatar
Linus Torvalds committed
462
463
464
465
466
	spin_unlock(&inode->i_lock);
}

EXPORT_SYMBOL(inode_add_bytes);

467
void __inode_sub_bytes(struct inode *inode, loff_t bytes)
Linus Torvalds's avatar
Linus Torvalds committed
468
469
470
471
472
473
474
475
{
	inode->i_blocks -= bytes >> 9;
	bytes &= 511;
	if (inode->i_bytes < bytes) {
		inode->i_blocks--;
		inode->i_bytes += 512;
	}
	inode->i_bytes -= bytes;
476
477
478
479
480
481
482
483
}

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);
Linus Torvalds's avatar
Linus Torvalds committed
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
	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);
	ret = (((loff_t)inode->i_blocks) << 9) + inode->i_bytes;
	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);