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