Blame view
fs/stat.c
11.9 KB
1da177e4c
|
1 2 3 4 5 |
/* * linux/fs/stat.c * * Copyright (C) 1991, 1992 Linus Torvalds */ |
630d9c472
|
6 |
#include <linux/export.h> |
1da177e4c
|
7 8 9 |
#include <linux/mm.h> #include <linux/errno.h> #include <linux/file.h> |
1da177e4c
|
10 11 12 13 14 |
#include <linux/highuid.h> #include <linux/fs.h> #include <linux/namei.h> #include <linux/security.h> #include <linux/syscalls.h> |
ba52de123
|
15 |
#include <linux/pagemap.h> |
1da177e4c
|
16 17 18 19 20 21 22 23 24 25 26 27 28 |
#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; |
3ddcd0569
|
29 |
stat->size = i_size_read(inode); |
1da177e4c
|
30 31 32 |
stat->atime = inode->i_atime; stat->mtime = inode->i_mtime; stat->ctime = inode->i_ctime; |
ba52de123
|
33 |
stat->blksize = (1 << inode->i_blkbits); |
3ddcd0569
|
34 |
stat->blocks = inode->i_blocks; |
1da177e4c
|
35 36 37 |
} EXPORT_SYMBOL(generic_fillattr); |
b7a6ec52d
|
38 39 40 41 42 43 44 45 46 47 48 49 50 |
/** * 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) |
1da177e4c
|
51 |
{ |
bb668734c
|
52 |
struct inode *inode = d_backing_inode(path->dentry); |
1da177e4c
|
53 54 |
if (inode->i_op->getattr) |
3dadecce2
|
55 |
return inode->i_op->getattr(path->mnt, path->dentry, stat); |
1da177e4c
|
56 57 |
generic_fillattr(inode, stat); |
1da177e4c
|
58 59 |
return 0; } |
b7a6ec52d
|
60 61 62 63 64 |
EXPORT_SYMBOL(vfs_getattr_nosec); int vfs_getattr(struct path *path, struct kstat *stat) { int retval; |
3f7036a07
|
65 |
retval = security_inode_getattr(path); |
b7a6ec52d
|
66 67 68 69 |
if (retval) return retval; return vfs_getattr_nosec(path, stat); } |
1da177e4c
|
70 |
EXPORT_SYMBOL(vfs_getattr); |
1da177e4c
|
71 72 |
int vfs_fstat(unsigned int fd, struct kstat *stat) { |
2903ff019
|
73 |
struct fd f = fdget_raw(fd); |
1da177e4c
|
74 |
int error = -EBADF; |
2903ff019
|
75 |
if (f.file) { |
3dadecce2
|
76 |
error = vfs_getattr(&f.file->f_path, stat); |
2903ff019
|
77 |
fdput(f); |
1da177e4c
|
78 79 80 |
} return error; } |
1da177e4c
|
81 |
EXPORT_SYMBOL(vfs_fstat); |
c78873252
|
82 83 |
int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, int flag) |
0112fc222
|
84 |
{ |
2eae7a187
|
85 |
struct path path; |
0112fc222
|
86 |
int error = -EINVAL; |
836fb7e7b
|
87 |
unsigned int lookup_flags = 0; |
0112fc222
|
88 |
|
65cfc6722
|
89 90 |
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | AT_EMPTY_PATH)) != 0) |
0112fc222
|
91 |
goto out; |
2eae7a187
|
92 93 |
if (!(flag & AT_SYMLINK_NOFOLLOW)) lookup_flags |= LOOKUP_FOLLOW; |
65cfc6722
|
94 95 |
if (flag & AT_EMPTY_PATH) lookup_flags |= LOOKUP_EMPTY; |
836fb7e7b
|
96 |
retry: |
2eae7a187
|
97 98 99 |
error = user_path_at(dfd, filename, lookup_flags, &path); if (error) goto out; |
3dadecce2
|
100 |
error = vfs_getattr(&path, stat); |
2eae7a187
|
101 |
path_put(&path); |
836fb7e7b
|
102 103 104 105 |
if (retry_estale(error, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; goto retry; } |
0112fc222
|
106 107 108 |
out: return error; } |
0112fc222
|
109 |
EXPORT_SYMBOL(vfs_fstatat); |
c78873252
|
110 |
int vfs_stat(const char __user *name, struct kstat *stat) |
2eae7a187
|
111 112 113 114 |
{ return vfs_fstatat(AT_FDCWD, name, stat, 0); } EXPORT_SYMBOL(vfs_stat); |
c78873252
|
115 |
int vfs_lstat(const char __user *name, struct kstat *stat) |
2eae7a187
|
116 117 118 119 |
{ return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW); } EXPORT_SYMBOL(vfs_lstat); |
0112fc222
|
120 |
|
1da177e4c
|
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
#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. ", 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
|
145 146 |
if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) return -EOVERFLOW; |
1da177e4c
|
147 148 149 150 |
tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; if (tmp.st_nlink != stat->nlink) return -EOVERFLOW; |
a7c1938e2
|
151 152 |
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
|
153 154 155 156 157 158 159 160 161 162 163 |
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; } |
c78873252
|
164 165 |
SYSCALL_DEFINE2(stat, const char __user *, filename, struct __old_kernel_stat __user *, statbuf) |
1da177e4c
|
166 167 |
{ struct kstat stat; |
2eae7a187
|
168 |
int error; |
1da177e4c
|
169 |
|
2eae7a187
|
170 171 172 |
error = vfs_stat(filename, &stat); if (error) return error; |
1da177e4c
|
173 |
|
2eae7a187
|
174 |
return cp_old_stat(&stat, statbuf); |
1da177e4c
|
175 |
} |
257ac264d
|
176 |
|
c78873252
|
177 178 |
SYSCALL_DEFINE2(lstat, const char __user *, filename, struct __old_kernel_stat __user *, statbuf) |
1da177e4c
|
179 180 |
{ struct kstat stat; |
2eae7a187
|
181 |
int error; |
1da177e4c
|
182 |
|
2eae7a187
|
183 184 185 |
error = vfs_lstat(filename, &stat); if (error) return error; |
1da177e4c
|
186 |
|
2eae7a187
|
187 |
return cp_old_stat(&stat, statbuf); |
1da177e4c
|
188 |
} |
257ac264d
|
189 190 |
SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, statbuf) |
1da177e4c
|
191 192 193 194 195 196 197 198 199 200 201 |
{ 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
|
202 203 204 205 206 |
#if BITS_PER_LONG == 32 # define choose_32_64(a,b) a #else # define choose_32_64(a,b) b #endif |
4c416f42e
|
207 |
#define valid_dev(x) choose_32_64(old_valid_dev(x),true) |
a52dd971f
|
208 |
#define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x) |
8529f613b
|
209 210 211 |
#ifndef INIT_STRUCT_STAT_PADDING # define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st)) #endif |
1da177e4c
|
212 213 214 |
static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) { struct stat tmp; |
a52dd971f
|
215 |
if (!valid_dev(stat->dev) || !valid_dev(stat->rdev)) |
1da177e4c
|
216 |
return -EOVERFLOW; |
a52dd971f
|
217 218 |
#if BITS_PER_LONG == 32 if (stat->size > MAX_NON_LFS) |
1da177e4c
|
219 220 |
return -EOVERFLOW; #endif |
8529f613b
|
221 |
INIT_STRUCT_STAT_PADDING(tmp); |
a52dd971f
|
222 |
tmp.st_dev = encode_dev(stat->dev); |
1da177e4c
|
223 |
tmp.st_ino = stat->ino; |
afefdbb28
|
224 225 |
if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) return -EOVERFLOW; |
1da177e4c
|
226 227 228 229 |
tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; if (tmp.st_nlink != stat->nlink) return -EOVERFLOW; |
a7c1938e2
|
230 231 |
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
|
232 |
tmp.st_rdev = encode_dev(stat->rdev); |
1da177e4c
|
233 234 235 236 237 238 239 240 241 242 243 244 245 |
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
|
246 247 |
SYSCALL_DEFINE2(newstat, const char __user *, filename, struct stat __user *, statbuf) |
5590ff0d5
|
248 249 |
{ struct kstat stat; |
2eae7a187
|
250 |
int error = vfs_stat(filename, &stat); |
5590ff0d5
|
251 |
|
2eae7a187
|
252 253 254 |
if (error) return error; return cp_new_stat(&stat, statbuf); |
5590ff0d5
|
255 |
} |
c78873252
|
256 257 |
SYSCALL_DEFINE2(newlstat, const char __user *, filename, struct stat __user *, statbuf) |
1da177e4c
|
258 259 |
{ struct kstat stat; |
2eae7a187
|
260 |
int error; |
1da177e4c
|
261 |
|
2eae7a187
|
262 263 264 |
error = vfs_lstat(filename, &stat); if (error) return error; |
1da177e4c
|
265 |
|
2eae7a187
|
266 |
return cp_new_stat(&stat, statbuf); |
1da177e4c
|
267 |
} |
5590ff0d5
|
268 |
|
2833c28aa
|
269 |
#if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT) |
c78873252
|
270 |
SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename, |
6559eed8c
|
271 |
struct stat __user *, statbuf, int, flag) |
1da177e4c
|
272 273 |
{ struct kstat stat; |
0112fc222
|
274 |
int error; |
1da177e4c
|
275 |
|
0112fc222
|
276 277 278 279 |
error = vfs_fstatat(dfd, filename, &stat, flag); if (error) return error; return cp_new_stat(&stat, statbuf); |
1da177e4c
|
280 |
} |
cff2b7600
|
281 |
#endif |
5590ff0d5
|
282 |
|
257ac264d
|
283 |
SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf) |
1da177e4c
|
284 285 286 287 288 289 290 291 292 |
{ struct kstat stat; int error = vfs_fstat(fd, &stat); if (!error) error = cp_new_stat(&stat, statbuf); return error; } |
6559eed8c
|
293 294 |
SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, char __user *, buf, int, bufsiz) |
1da177e4c
|
295 |
{ |
2d8f30380
|
296 |
struct path path; |
1da177e4c
|
297 |
int error; |
1fa1e7f61
|
298 |
int empty = 0; |
7955119e0
|
299 |
unsigned int lookup_flags = LOOKUP_EMPTY; |
1da177e4c
|
300 301 302 |
if (bufsiz <= 0) return -EINVAL; |
7955119e0
|
303 304 |
retry: error = user_path_at_empty(dfd, pathname, lookup_flags, &path, &empty); |
1da177e4c
|
305 |
if (!error) { |
bb668734c
|
306 |
struct inode *inode = d_backing_inode(path.dentry); |
1da177e4c
|
307 |
|
1fa1e7f61
|
308 |
error = empty ? -ENOENT : -EINVAL; |
acfa4380e
|
309 |
if (inode->i_op->readlink) { |
2d8f30380
|
310 |
error = security_inode_readlink(path.dentry); |
1da177e4c
|
311 |
if (!error) { |
68ac1234f
|
312 |
touch_atime(&path); |
2d8f30380
|
313 |
error = inode->i_op->readlink(path.dentry, |
4ac913785
|
314 |
buf, bufsiz); |
1da177e4c
|
315 316 |
} } |
2d8f30380
|
317 |
path_put(&path); |
7955119e0
|
318 319 320 321 |
if (retry_estale(error, lookup_flags)) { lookup_flags |= LOOKUP_REVAL; goto retry; } |
1da177e4c
|
322 323 324 |
} return error; } |
002c8976e
|
325 326 |
SYSCALL_DEFINE3(readlink, const char __user *, path, char __user *, buf, int, bufsiz) |
5590ff0d5
|
327 328 329 |
{ return sys_readlinkat(AT_FDCWD, path, buf, bufsiz); } |
1da177e4c
|
330 331 |
/* ---------- LFS-64 ----------- */ |
0753f70f0
|
332 |
#if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64) |
1da177e4c
|
333 |
|
8529f613b
|
334 335 336 |
#ifndef INIT_STRUCT_STAT64_PADDING # define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st)) #endif |
1da177e4c
|
337 338 339 |
static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) { struct stat64 tmp; |
8529f613b
|
340 |
INIT_STRUCT_STAT64_PADDING(tmp); |
1da177e4c
|
341 342 |
#ifdef CONFIG_MIPS /* mips has weird padding, so we don't get 64 bits there */ |
1da177e4c
|
343 344 345 346 347 348 349 |
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
|
350 351 |
if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) return -EOVERFLOW; |
1da177e4c
|
352 353 354 355 356 |
#ifdef STAT64_HAS_BROKEN_ST_INO tmp.__st_ino = stat->ino; #endif tmp.st_mode = stat->mode; tmp.st_nlink = stat->nlink; |
a7c1938e2
|
357 358 |
tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid); tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid); |
1da177e4c
|
359 360 361 362 363 364 365 366 367 368 369 |
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
|
370 371 |
SYSCALL_DEFINE2(stat64, const char __user *, filename, struct stat64 __user *, statbuf) |
1da177e4c
|
372 373 374 375 376 377 378 379 380 |
{ struct kstat stat; int error = vfs_stat(filename, &stat); if (!error) error = cp_new_stat64(&stat, statbuf); return error; } |
257ac264d
|
381 |
|
c78873252
|
382 383 |
SYSCALL_DEFINE2(lstat64, const char __user *, filename, struct stat64 __user *, statbuf) |
1da177e4c
|
384 385 386 387 388 389 390 391 392 |
{ struct kstat stat; int error = vfs_lstat(filename, &stat); if (!error) error = cp_new_stat64(&stat, statbuf); return error; } |
257ac264d
|
393 394 |
SYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf) |
1da177e4c
|
395 396 397 398 399 400 401 402 403 |
{ struct kstat stat; int error = vfs_fstat(fd, &stat); if (!error) error = cp_new_stat64(&stat, statbuf); return error; } |
c78873252
|
404 |
SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename, |
6559eed8c
|
405 |
struct stat64 __user *, statbuf, int, flag) |
cff2b7600
|
406 407 |
{ struct kstat stat; |
0112fc222
|
408 |
int error; |
cff2b7600
|
409 |
|
0112fc222
|
410 411 412 413 |
error = vfs_fstatat(dfd, filename, &stat, flag); if (error) return error; return cp_new_stat64(&stat, statbuf); |
cff2b7600
|
414 |
} |
0753f70f0
|
415 |
#endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */ |
1da177e4c
|
416 |
|
b462707e7
|
417 418 |
/* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ void __inode_add_bytes(struct inode *inode, loff_t bytes) |
1da177e4c
|
419 |
{ |
1da177e4c
|
420 421 422 423 424 425 426 |
inode->i_blocks += bytes >> 9; bytes &= 511; inode->i_bytes += bytes; if (inode->i_bytes >= 512) { inode->i_blocks++; inode->i_bytes -= 512; } |
b462707e7
|
427 428 429 430 431 432 |
} void inode_add_bytes(struct inode *inode, loff_t bytes) { spin_lock(&inode->i_lock); __inode_add_bytes(inode, bytes); |
1da177e4c
|
433 434 435 436 |
spin_unlock(&inode->i_lock); } EXPORT_SYMBOL(inode_add_bytes); |
1c8924eb1
|
437 |
void __inode_sub_bytes(struct inode *inode, loff_t bytes) |
1da177e4c
|
438 |
{ |
1da177e4c
|
439 440 441 442 443 444 445 |
inode->i_blocks -= bytes >> 9; bytes &= 511; if (inode->i_bytes < bytes) { inode->i_blocks--; inode->i_bytes += 512; } inode->i_bytes -= bytes; |
1c8924eb1
|
446 447 448 449 450 451 452 453 |
} 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
|
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 |
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); |