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)
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) {
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;

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
}
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) {
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)
435 436
{
	struct kstat stat;
437
	int error;
438

439 440 441 442
	error = vfs_fstatat(dfd, filename, &stat, flag);
	if (error)
		return error;
	return cp_new_stat64(&stat, statbuf);
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);