Merge commit 'b4bf0cf0458759c67920a031021a9d96cd683cfe'
[unleashed.git] / kernel / syscall / stat.c
blob768722d4593cd34a4b3efe82100f272dd23badc3
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
35 * Get file attribute information through a file name or a file descriptor.
38 #include <sys/param.h>
39 #include <sys/isa_defs.h>
40 #include <sys/types.h>
41 #include <sys/sysmacros.h>
42 #include <sys/cred.h>
43 #include <sys/systm.h>
44 #include <sys/errno.h>
45 #include <sys/fcntl.h>
46 #include <sys/pathname.h>
47 #include <sys/stat.h>
48 #include <sys/vfs.h>
49 #include <sys/vnode.h>
50 #include <sys/mode.h>
51 #include <sys/file.h>
52 #include <sys/proc.h>
53 #include <sys/uio.h>
54 #include <sys/debug.h>
55 #include <sys/cmn_err.h>
56 #include <c2/audit.h>
57 #include <sys/fs_subr.h>
60 * Get the vp to be stated and the cred to be used for the call
61 * to fop_getattr
64 static int
65 cstatat_getvp(int fd, char *name, int follow, vnode_t **vp, cred_t **cred)
67 vnode_t *startvp;
68 file_t *fp;
69 int error;
70 cred_t *cr;
71 int estale_retry = 0;
73 *vp = NULL;
76 * Only return EFAULT for fstatat when fd == AT_FDCWD && name == NULL
79 if (fd == AT_FDCWD) {
80 startvp = NULL;
81 cr = CRED();
82 crhold(cr);
83 } else {
84 char startchar;
86 if (copyin(name, &startchar, sizeof (char)))
87 return (EFAULT);
88 if (startchar != '/') {
89 if ((fp = getf(fd)) == NULL) {
90 return (EBADF);
92 startvp = fp->f_vnode;
93 cr = fp->f_cred;
94 crhold(cr);
95 VN_HOLD(startvp);
96 releasef(fd);
97 } else {
98 startvp = NULL;
99 cr = CRED();
100 crhold(cr);
103 *cred = cr;
105 if (AU_AUDITING() && startvp != NULL)
106 audit_setfsat_path(1);
108 lookup:
109 if (error = lookupnameat(name, UIO_USERSPACE, follow, NULLVPP,
110 vp, startvp)) {
111 if ((error == ESTALE) &&
112 fs_need_estale_retry(estale_retry++))
113 goto lookup;
114 if (startvp != NULL)
115 VN_RELE(startvp);
116 crfree(cr);
117 return (error);
119 if (startvp != NULL)
120 VN_RELE(startvp);
122 return (0);
126 * Native syscall interfaces:
128 * N-bit kernel, N-bit applications, N-bit file offsets
131 static int cstatat(int, char *, struct stat *, int, int);
132 static int cstat(vnode_t *vp, struct stat *, int, cred_t *);
135 * fstat can and should be fast, do an inline implementation here.
137 #define FSTAT_BODY(fd, sb, statfn) \
139 file_t *fp; \
140 int error; \
142 if (fd == AT_FDCWD) \
143 return (set_errno(EFAULT)); \
144 if ((fp = getf(fd)) == NULL) \
145 return (set_errno(EBADF)); \
146 error = statfn(fp->f_vnode, sb, 0, fp->f_cred); \
147 releasef(fd); \
148 if (error) \
149 return (set_errno(error)); \
150 return (0); \
153 static inline int
154 fstat(int fd, struct stat *sb)
156 FSTAT_BODY(fd, sb, cstat)
160 fstatat(int fd, char *name, struct stat *sb, int flags)
162 int followflag;
163 int csflags;
165 if (name == NULL)
166 return (fstat(fd, sb));
168 followflag = (flags & AT_SYMLINK_NOFOLLOW);
169 csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
170 if (followflag == 0)
171 csflags |= ATTR_REAL; /* flag for procfs lookups */
173 return (cstatat(fd, name, sb, followflag, csflags));
177 * Common code for stat(), lstat(), and fstat().
178 * (32-bit kernel, 32-bit applications, 32-bit files)
179 * (64-bit kernel, 64-bit applications, 64-bit files)
181 static int
182 cstat(vnode_t *vp, struct stat *ubp, int flag, cred_t *cr)
184 struct vfssw *vswp;
185 struct stat sb;
186 vattr_t vattr;
187 int error;
189 vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
190 if ((error = fop_getattr(vp, &vattr, flag, cr, NULL)) != 0)
191 return (error);
192 #ifdef _ILP32
194 * (32-bit kernel, 32-bit applications, 32-bit files)
195 * NOTE: 32-bit kernel maintains a 64-bit unsigend va_size.
197 * st_size of devices (VBLK and VCHR special files) is a special case.
198 * POSIX does not define size behavior for special files, so the
199 * following Solaris specific behavior is not a violation. Solaris
200 * returns the size of the device.
202 * For compatibility with 32-bit programs which happen to do stat() on
203 * a (mknod) bigger than 2GB we suppress the large file EOVERFLOW and
204 * instead we return the value MAXOFF32_T (LONG_MAX).
206 * 32-bit applications that care about the size of devices should be
207 * built 64-bit or use a large file interface (lfcompile(5) or lf64(5)).
209 if ((vattr.va_size > MAXOFF32_T) &&
210 ((vp->v_type == VBLK) || (vp->v_type == VCHR))) {
211 /* OVERFLOW | UNKNOWN_SIZE */
212 vattr.va_size = MAXOFF32_T;
214 #endif /* _ILP32 */
215 if (vattr.va_size > MAXOFF_T || vattr.va_nblocks > LONG_MAX ||
216 vattr.va_nodeid > ULONG_MAX)
217 return (EOVERFLOW);
219 bzero(&sb, sizeof (sb));
220 sb.st_dev = vattr.va_fsid;
221 sb.st_ino = (ino_t)vattr.va_nodeid;
222 sb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
223 sb.st_nlink = vattr.va_nlink;
224 sb.st_uid = vattr.va_uid;
225 sb.st_gid = vattr.va_gid;
226 sb.st_rdev = vattr.va_rdev;
227 sb.st_size = (off_t)vattr.va_size;
228 sb.st_atim = vattr.va_atime;
229 sb.st_mtim = vattr.va_mtime;
230 sb.st_ctim = vattr.va_ctime;
231 sb.st_blksize = vattr.va_blksize;
232 sb.st_blocks = (blkcnt_t)vattr.va_nblocks;
233 if (vp->v_vfsp != NULL) {
234 vswp = &vfssw[vp->v_vfsp->vfs_fstype];
235 if (vswp->vsw_name && *vswp->vsw_name)
236 (void) strcpy(sb.st_fstype, vswp->vsw_name);
238 if (copyout(&sb, ubp, sizeof (sb)))
239 return (EFAULT);
240 return (0);
243 static int
244 cstatat(int fd, char *name, struct stat *sb, int follow, int flags)
246 vnode_t *vp;
247 int error;
248 cred_t *cred;
249 int link_follow;
250 int estale_retry = 0;
252 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
253 lookup:
254 if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
255 return (set_errno(error));
256 error = cstat(vp, sb, flags, cred);
257 crfree(cred);
258 VN_RELE(vp);
259 if (error != 0) {
260 if (error == ESTALE &&
261 fs_need_estale_retry(estale_retry++))
262 goto lookup;
263 return (set_errno(error));
265 return (0);
268 #if defined(_SYSCALL32_IMPL)
271 * 64-bit kernel, 32-bit applications, 32-bit file offsets
273 static int cstatat32(int, char *, struct stat32 *, int, int);
274 static int cstat32(vnode_t *, struct stat32 *, int, cred_t *);
276 static inline int
277 fstat32(int fd, struct stat32 *sb)
279 FSTAT_BODY(fd, sb, cstat32)
283 fstatat32(int fd, char *name, struct stat32 *sb, int flags)
285 int followflag;
286 int csflags;
288 if (name == NULL)
289 return (fstat32(fd, sb));
291 followflag = (flags & AT_SYMLINK_NOFOLLOW);
292 csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
293 if (followflag == 0)
294 csflags |= ATTR_REAL; /* flag for procfs lookups */
296 return (cstatat32(fd, name, sb, followflag, csflags));
299 static int
300 cstat32(vnode_t *vp, struct stat32 *ubp, int flag, struct cred *cr)
302 struct vfssw *vswp;
303 struct stat32 sb;
304 vattr_t vattr;
305 int error;
306 dev32_t st_dev, st_rdev;
308 vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
309 if (error = fop_getattr(vp, &vattr, flag, cr, NULL))
310 return (error);
312 /* devices are a special case, see comments in cstat */
313 if ((vattr.va_size > MAXOFF32_T) &&
314 ((vp->v_type == VBLK) || (vp->v_type == VCHR))) {
315 /* OVERFLOW | UNKNOWN_SIZE */
316 vattr.va_size = MAXOFF32_T;
319 /* check for large values */
320 if (!cmpldev(&st_dev, vattr.va_fsid) ||
321 !cmpldev(&st_rdev, vattr.va_rdev) ||
322 vattr.va_size > MAXOFF32_T ||
323 vattr.va_nblocks > INT32_MAX ||
324 vattr.va_nodeid > UINT32_MAX ||
325 TIMESPEC_OVERFLOW(&(vattr.va_atime)) ||
326 TIMESPEC_OVERFLOW(&(vattr.va_mtime)) ||
327 TIMESPEC_OVERFLOW(&(vattr.va_ctime)))
328 return (EOVERFLOW);
330 bzero(&sb, sizeof (sb));
331 sb.st_dev = st_dev;
332 sb.st_ino = (ino32_t)vattr.va_nodeid;
333 sb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
334 sb.st_nlink = vattr.va_nlink;
335 sb.st_uid = vattr.va_uid;
336 sb.st_gid = vattr.va_gid;
337 sb.st_rdev = st_rdev;
338 sb.st_size = (off32_t)vattr.va_size;
339 TIMESPEC_TO_TIMESPEC32(&(sb.st_atim), &(vattr.va_atime));
340 TIMESPEC_TO_TIMESPEC32(&(sb.st_mtim), &(vattr.va_mtime));
341 TIMESPEC_TO_TIMESPEC32(&(sb.st_ctim), &(vattr.va_ctime));
342 sb.st_blksize = vattr.va_blksize;
343 sb.st_blocks = (blkcnt32_t)vattr.va_nblocks;
344 if (vp->v_vfsp != NULL) {
345 vswp = &vfssw[vp->v_vfsp->vfs_fstype];
346 if (vswp->vsw_name && *vswp->vsw_name)
347 (void) strcpy(sb.st_fstype, vswp->vsw_name);
349 if (copyout(&sb, ubp, sizeof (sb)))
350 return (EFAULT);
351 return (0);
354 static int
355 cstatat32(int fd, char *name, struct stat32 *sb, int follow, int flags)
357 vnode_t *vp;
358 int error;
359 cred_t *cred;
360 int link_follow;
361 int estale_retry = 0;
363 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
364 lookup:
365 if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
366 return (set_errno(error));
367 error = cstat32(vp, sb, flags, cred);
368 crfree(cred);
369 VN_RELE(vp);
370 if (error != 0) {
371 if (error == ESTALE &&
372 fs_need_estale_retry(estale_retry++))
373 goto lookup;
374 return (set_errno(error));
376 return (0);
379 #endif /* _SYSCALL32_IMPL */
381 #if defined(_ILP32)
384 * 32-bit kernel, 32-bit applications, 64-bit file offsets.
386 * These routines are implemented differently on 64-bit kernels.
388 static int cstatat64(int, char *, struct stat64 *, int, int);
389 static int cstat64(vnode_t *, struct stat64 *, int, cred_t *);
391 static inline int
392 fstat64(int fd, struct stat64 *sb)
394 FSTAT_BODY(fd, sb, cstat64)
398 fstatat64(int fd, char *name, struct stat64 *sb, int flags)
400 int followflag;
401 int csflags;
403 if (name == NULL)
404 return (fstat64(fd, sb));
406 followflag = (flags & AT_SYMLINK_NOFOLLOW);
407 csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
408 if (followflag == 0)
409 csflags |= ATTR_REAL; /* flag for procfs lookups */
411 return (cstatat64(fd, name, sb, followflag, csflags));
414 static int
415 cstat64(vnode_t *vp, struct stat64 *ubp, int flag, cred_t *cr)
417 struct vfssw *vswp;
418 struct stat64 lsb;
419 vattr_t vattr;
420 int error;
422 vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
423 if (error = fop_getattr(vp, &vattr, flag, cr, NULL))
424 return (error);
426 bzero(&lsb, sizeof (lsb));
427 lsb.st_dev = vattr.va_fsid;
428 lsb.st_ino = vattr.va_nodeid;
429 lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
430 lsb.st_nlink = vattr.va_nlink;
431 lsb.st_uid = vattr.va_uid;
432 lsb.st_gid = vattr.va_gid;
433 lsb.st_rdev = vattr.va_rdev;
434 lsb.st_size = vattr.va_size;
435 lsb.st_atim = vattr.va_atime;
436 lsb.st_mtim = vattr.va_mtime;
437 lsb.st_ctim = vattr.va_ctime;
438 lsb.st_blksize = vattr.va_blksize;
439 lsb.st_blocks = vattr.va_nblocks;
440 if (vp->v_vfsp != NULL) {
441 vswp = &vfssw[vp->v_vfsp->vfs_fstype];
442 if (vswp->vsw_name && *vswp->vsw_name)
443 (void) strcpy(lsb.st_fstype, vswp->vsw_name);
445 if (copyout(&lsb, ubp, sizeof (lsb)))
446 return (EFAULT);
447 return (0);
450 static int
451 cstatat64(int fd, char *name, struct stat64 *sb, int follow, int flags)
453 vnode_t *vp;
454 int error;
455 cred_t *cred;
456 int link_follow;
457 int estale_retry = 0;
459 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
460 lookup:
461 if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
462 return (set_errno(error));
463 error = cstat64(vp, sb, flags, cred);
464 crfree(cred);
465 VN_RELE(vp);
466 if (error != 0) {
467 if (error == ESTALE &&
468 fs_need_estale_retry(estale_retry++))
469 goto lookup;
470 return (set_errno(error));
472 return (0);
475 #endif /* _ILP32 */
477 #if defined(_SYSCALL32_IMPL)
480 * 64-bit kernel, 32-bit applications, 64-bit file offsets.
482 * We'd really like to call the "native" stat calls for these ones,
483 * but the problem is that the 64-bit ABI defines the 'stat64' structure
484 * differently from the way the 32-bit ABI defines it.
487 static int cstatat64_32(int, char *, struct stat64_32 *, int, int);
488 static int cstat64_32(vnode_t *, struct stat64_32 *, int, cred_t *);
490 static inline int
491 fstat64_32(int fd, struct stat64_32 *sb)
493 FSTAT_BODY(fd, sb, cstat64_32)
497 fstatat64_32(int fd, char *name, struct stat64_32 *sb, int flags)
499 int followflag;
500 int csflags;
502 if (name == NULL)
503 return (fstat64_32(fd, sb));
505 followflag = (flags & AT_SYMLINK_NOFOLLOW);
506 csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0);
507 if (followflag == 0)
508 csflags |= ATTR_REAL; /* flag for procfs lookups */
510 return (cstatat64_32(fd, name, sb, followflag, csflags));
513 static int
514 cstat64_32(vnode_t *vp, struct stat64_32 *ubp, int flag, cred_t *cr)
516 struct vfssw *vswp;
517 struct stat64_32 lsb;
518 vattr_t vattr;
519 int error;
520 dev32_t st_dev, st_rdev;
522 vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
523 if (error = fop_getattr(vp, &vattr, flag, cr, NULL))
524 return (error);
526 if (!cmpldev(&st_dev, vattr.va_fsid) ||
527 !cmpldev(&st_rdev, vattr.va_rdev) ||
528 TIMESPEC_OVERFLOW(&(vattr.va_atime)) ||
529 TIMESPEC_OVERFLOW(&(vattr.va_mtime)) ||
530 TIMESPEC_OVERFLOW(&(vattr.va_ctime)))
531 return (EOVERFLOW);
533 bzero(&lsb, sizeof (lsb));
534 lsb.st_dev = st_dev;
535 lsb.st_ino = vattr.va_nodeid;
536 lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode;
537 lsb.st_nlink = vattr.va_nlink;
538 lsb.st_uid = vattr.va_uid;
539 lsb.st_gid = vattr.va_gid;
540 lsb.st_rdev = st_rdev;
541 lsb.st_size = vattr.va_size;
542 TIMESPEC_TO_TIMESPEC32(&(lsb.st_atim), &(vattr.va_atime));
543 TIMESPEC_TO_TIMESPEC32(&(lsb.st_mtim), &(vattr.va_mtime));
544 TIMESPEC_TO_TIMESPEC32(&(lsb.st_ctim), &(vattr.va_ctime));
545 lsb.st_blksize = vattr.va_blksize;
546 lsb.st_blocks = vattr.va_nblocks;
547 if (vp->v_vfsp != NULL) {
548 vswp = &vfssw[vp->v_vfsp->vfs_fstype];
549 if (vswp->vsw_name && *vswp->vsw_name)
550 (void) strcpy(lsb.st_fstype, vswp->vsw_name);
552 if (copyout(&lsb, ubp, sizeof (lsb)))
553 return (EFAULT);
554 return (0);
557 static int
558 cstatat64_32(int fd, char *name, struct stat64_32 *sb, int follow, int flags)
560 vnode_t *vp;
561 int error;
562 cred_t *cred;
563 int link_follow;
564 int estale_retry = 0;
566 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW;
567 lookup:
568 if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred))
569 return (set_errno(error));
570 error = cstat64_32(vp, sb, flags, cred);
571 crfree(cred);
572 VN_RELE(vp);
573 if (error != 0) {
574 if (error == ESTALE &&
575 fs_need_estale_retry(estale_retry++))
576 goto lookup;
577 return (set_errno(error));
579 return (0);
582 #endif /* _SYSCALL32_IMPL */