17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5dd29fa4aSprabahar * Common Development and Distribution License (the "License"). 6dd29fa4aSprabahar * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 218fd04b83SRoger A. Faulkner 227c478bd9Sstevel@tonic-gate /* 23c4d3e299SBrent Paulson * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 317c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 327c478bd9Sstevel@tonic-gate */ 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate /* 357c478bd9Sstevel@tonic-gate * Get file attribute information through a file name or a file descriptor. 367c478bd9Sstevel@tonic-gate */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate #include <sys/param.h> 397c478bd9Sstevel@tonic-gate #include <sys/isa_defs.h> 407c478bd9Sstevel@tonic-gate #include <sys/types.h> 417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 427c478bd9Sstevel@tonic-gate #include <sys/cred.h> 437c478bd9Sstevel@tonic-gate #include <sys/systm.h> 447c478bd9Sstevel@tonic-gate #include <sys/errno.h> 457c478bd9Sstevel@tonic-gate #include <sys/fcntl.h> 467c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 477c478bd9Sstevel@tonic-gate #include <sys/stat.h> 487c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 497c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 507c478bd9Sstevel@tonic-gate #include <sys/mode.h> 517c478bd9Sstevel@tonic-gate #include <sys/file.h> 527c478bd9Sstevel@tonic-gate #include <sys/proc.h> 537c478bd9Sstevel@tonic-gate #include <sys/uio.h> 547c478bd9Sstevel@tonic-gate #include <sys/debug.h> 557c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 567c478bd9Sstevel@tonic-gate #include <c2/audit.h> 57dd29fa4aSprabahar #include <fs/fs_subr.h> 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * Get the vp to be stated and the cred to be used for the call 617c478bd9Sstevel@tonic-gate * to VOP_GETATTR 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate static int 658fd04b83SRoger A. Faulkner cstatat_getvp(int fd, char *name, int follow, vnode_t **vp, cred_t **cred) 667c478bd9Sstevel@tonic-gate { 677c478bd9Sstevel@tonic-gate vnode_t *startvp; 687c478bd9Sstevel@tonic-gate file_t *fp; 697c478bd9Sstevel@tonic-gate int error; 707c478bd9Sstevel@tonic-gate cred_t *cr; 71dd29fa4aSprabahar int estale_retry = 0; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate *vp = NULL; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* 767c478bd9Sstevel@tonic-gate * Only return EFAULT for fstatat when fd == AT_FDCWD && name == NULL 777c478bd9Sstevel@tonic-gate */ 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate if (fd == AT_FDCWD) { 807c478bd9Sstevel@tonic-gate startvp = NULL; 817c478bd9Sstevel@tonic-gate cr = CRED(); 827c478bd9Sstevel@tonic-gate crhold(cr); 837c478bd9Sstevel@tonic-gate } else { 847c478bd9Sstevel@tonic-gate char startchar; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate if (copyin(name, &startchar, sizeof (char))) 877c478bd9Sstevel@tonic-gate return (EFAULT); 888fd04b83SRoger A. Faulkner if (startchar != '/') { 897c478bd9Sstevel@tonic-gate if ((fp = getf(fd)) == NULL) { 907c478bd9Sstevel@tonic-gate return (EBADF); 917c478bd9Sstevel@tonic-gate } 927c478bd9Sstevel@tonic-gate startvp = fp->f_vnode; 937c478bd9Sstevel@tonic-gate cr = fp->f_cred; 947c478bd9Sstevel@tonic-gate crhold(cr); 957c478bd9Sstevel@tonic-gate VN_HOLD(startvp); 967c478bd9Sstevel@tonic-gate releasef(fd); 977c478bd9Sstevel@tonic-gate } else { 987c478bd9Sstevel@tonic-gate startvp = NULL; 997c478bd9Sstevel@tonic-gate cr = CRED(); 1007c478bd9Sstevel@tonic-gate crhold(cr); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate } 1037c478bd9Sstevel@tonic-gate *cred = cr; 1047c478bd9Sstevel@tonic-gate 105*794f0adbSRoger A. Faulkner if (AU_AUDITING() && startvp != NULL) 1067c478bd9Sstevel@tonic-gate audit_setfsat_path(1); 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate lookup: 1097c478bd9Sstevel@tonic-gate if (error = lookupnameat(name, UIO_USERSPACE, follow, NULLVPP, 1107c478bd9Sstevel@tonic-gate vp, startvp)) { 111dd29fa4aSprabahar if ((error == ESTALE) && 112dd29fa4aSprabahar fs_need_estale_retry(estale_retry++)) 1137c478bd9Sstevel@tonic-gate goto lookup; 1147c478bd9Sstevel@tonic-gate if (startvp != NULL) 1157c478bd9Sstevel@tonic-gate VN_RELE(startvp); 1167c478bd9Sstevel@tonic-gate crfree(cr); 1177c478bd9Sstevel@tonic-gate return (error); 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate if (startvp != NULL) 1207c478bd9Sstevel@tonic-gate VN_RELE(startvp); 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate return (0); 1237c478bd9Sstevel@tonic-gate } 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate /* 1267c478bd9Sstevel@tonic-gate * Native syscall interfaces: 1277c478bd9Sstevel@tonic-gate * 1287c478bd9Sstevel@tonic-gate * N-bit kernel, N-bit applications, N-bit file offsets 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate 1318fd04b83SRoger A. Faulkner static int cstatat(int, char *, struct stat *, int, int); 1327c478bd9Sstevel@tonic-gate static int cstat(vnode_t *vp, struct stat *, int, cred_t *); 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * fstat can and should be fast, do an inline implementation here. 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate #define FSTAT_BODY(fd, sb, statfn) \ 1387c478bd9Sstevel@tonic-gate { \ 1397c478bd9Sstevel@tonic-gate file_t *fp; \ 1407c478bd9Sstevel@tonic-gate int error; \ 1417c478bd9Sstevel@tonic-gate \ 1428fd04b83SRoger A. Faulkner if (fd == AT_FDCWD) \ 1438fd04b83SRoger A. Faulkner return (set_errno(EFAULT)); \ 1447c478bd9Sstevel@tonic-gate if ((fp = getf(fd)) == NULL) \ 1457c478bd9Sstevel@tonic-gate return (set_errno(EBADF)); \ 1467c478bd9Sstevel@tonic-gate error = statfn(fp->f_vnode, sb, 0, fp->f_cred); \ 1477c478bd9Sstevel@tonic-gate releasef(fd); \ 1487c478bd9Sstevel@tonic-gate if (error) \ 1497c478bd9Sstevel@tonic-gate return (set_errno(error)); \ 1507c478bd9Sstevel@tonic-gate return (0); \ 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate int 1547c478bd9Sstevel@tonic-gate fstat(int fd, struct stat *sb) 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate FSTAT_BODY(fd, sb, cstat) 1577c478bd9Sstevel@tonic-gate } 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate int 1607c478bd9Sstevel@tonic-gate fstatat(int fd, char *name, struct stat *sb, int flags) 1617c478bd9Sstevel@tonic-gate { 1628fd04b83SRoger A. Faulkner int followflag; 1638fd04b83SRoger A. Faulkner int csflags; 1647c478bd9Sstevel@tonic-gate 1658fd04b83SRoger A. Faulkner if (name == NULL) 1668fd04b83SRoger A. Faulkner return (fstat(fd, sb)); 1677c478bd9Sstevel@tonic-gate 1688fd04b83SRoger A. Faulkner followflag = (flags & AT_SYMLINK_NOFOLLOW); 1698fd04b83SRoger A. Faulkner csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0); 1708fd04b83SRoger A. Faulkner if (followflag == 0) 1718fd04b83SRoger A. Faulkner csflags |= ATTR_REAL; /* flag for procfs lookups */ 1727c478bd9Sstevel@tonic-gate 1738fd04b83SRoger A. Faulkner return (cstatat(fd, name, sb, followflag, csflags)); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate int 1778fd04b83SRoger A. Faulkner stat(char *name, struct stat *sb) 1787c478bd9Sstevel@tonic-gate { 1798fd04b83SRoger A. Faulkner return (fstatat(AT_FDCWD, name, sb, 0)); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate int 1838fd04b83SRoger A. Faulkner lstat(char *name, struct stat *sb) 1847c478bd9Sstevel@tonic-gate { 1858fd04b83SRoger A. Faulkner return (fstatat(AT_FDCWD, name, sb, AT_SYMLINK_NOFOLLOW)); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate /* 1897c478bd9Sstevel@tonic-gate * Common code for stat(), lstat(), and fstat(). 1907c478bd9Sstevel@tonic-gate * (32-bit kernel, 32-bit applications, 32-bit files) 1917c478bd9Sstevel@tonic-gate * (64-bit kernel, 64-bit applications, 64-bit files) 1927c478bd9Sstevel@tonic-gate */ 1937c478bd9Sstevel@tonic-gate static int 1947c478bd9Sstevel@tonic-gate cstat(vnode_t *vp, struct stat *ubp, int flag, cred_t *cr) 1957c478bd9Sstevel@tonic-gate { 1967c478bd9Sstevel@tonic-gate struct vfssw *vswp; 1977c478bd9Sstevel@tonic-gate struct stat sb; 1987c478bd9Sstevel@tonic-gate vattr_t vattr; 1997c478bd9Sstevel@tonic-gate int error; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE; 202da6c28aaSamw if ((error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) != 0) 2037c478bd9Sstevel@tonic-gate return (error); 2047c478bd9Sstevel@tonic-gate #ifdef _ILP32 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * (32-bit kernel, 32-bit applications, 32-bit files) 2077c478bd9Sstevel@tonic-gate * NOTE: 32-bit kernel maintains a 64-bit unsigend va_size. 2087c478bd9Sstevel@tonic-gate * 2097c478bd9Sstevel@tonic-gate * st_size of devices (VBLK and VCHR special files) is a special case. 2107c478bd9Sstevel@tonic-gate * POSIX does not define size behavior for special files, so the 2117c478bd9Sstevel@tonic-gate * following Solaris specific behavior is not a violation. Solaris 2127c478bd9Sstevel@tonic-gate * returns the size of the device. 2137c478bd9Sstevel@tonic-gate * 2147c478bd9Sstevel@tonic-gate * For compatibility with 32-bit programs which happen to do stat() on 2157c478bd9Sstevel@tonic-gate * a (mknod) bigger than 2GB we suppress the large file EOVERFLOW and 2167c478bd9Sstevel@tonic-gate * instead we return the value MAXOFF32_T (LONG_MAX). 2177c478bd9Sstevel@tonic-gate * 2187c478bd9Sstevel@tonic-gate * 32-bit applications that care about the size of devices should be 2197c478bd9Sstevel@tonic-gate * built 64-bit or use a large file interface (lfcompile(5) or lf64(5)). 2207c478bd9Sstevel@tonic-gate */ 2217c478bd9Sstevel@tonic-gate if ((vattr.va_size > MAXOFF32_T) && 2227c478bd9Sstevel@tonic-gate ((vp->v_type == VBLK) || (vp->v_type == VCHR))) { 2237c478bd9Sstevel@tonic-gate /* OVERFLOW | UNKNOWN_SIZE */ 2247c478bd9Sstevel@tonic-gate vattr.va_size = MAXOFF32_T; 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate #endif /* _ILP32 */ 2277c478bd9Sstevel@tonic-gate if (vattr.va_size > MAXOFF_T || vattr.va_nblocks > LONG_MAX || 2287c478bd9Sstevel@tonic-gate vattr.va_nodeid > ULONG_MAX) 2297c478bd9Sstevel@tonic-gate return (EOVERFLOW); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate bzero(&sb, sizeof (sb)); 2327c478bd9Sstevel@tonic-gate sb.st_dev = vattr.va_fsid; 2337c478bd9Sstevel@tonic-gate sb.st_ino = (ino_t)vattr.va_nodeid; 2347c478bd9Sstevel@tonic-gate sb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode; 2357c478bd9Sstevel@tonic-gate sb.st_nlink = vattr.va_nlink; 2367c478bd9Sstevel@tonic-gate sb.st_uid = vattr.va_uid; 2377c478bd9Sstevel@tonic-gate sb.st_gid = vattr.va_gid; 2387c478bd9Sstevel@tonic-gate sb.st_rdev = vattr.va_rdev; 2397c478bd9Sstevel@tonic-gate sb.st_size = (off_t)vattr.va_size; 2407c478bd9Sstevel@tonic-gate sb.st_atim = vattr.va_atime; 2417c478bd9Sstevel@tonic-gate sb.st_mtim = vattr.va_mtime; 2427c478bd9Sstevel@tonic-gate sb.st_ctim = vattr.va_ctime; 2437c478bd9Sstevel@tonic-gate sb.st_blksize = vattr.va_blksize; 2447c478bd9Sstevel@tonic-gate sb.st_blocks = (blkcnt_t)vattr.va_nblocks; 2457c478bd9Sstevel@tonic-gate if (vp->v_vfsp != NULL) { 2467c478bd9Sstevel@tonic-gate vswp = &vfssw[vp->v_vfsp->vfs_fstype]; 2477c478bd9Sstevel@tonic-gate if (vswp->vsw_name && *vswp->vsw_name) 2487c478bd9Sstevel@tonic-gate (void) strcpy(sb.st_fstype, vswp->vsw_name); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate if (copyout(&sb, ubp, sizeof (sb))) 2517c478bd9Sstevel@tonic-gate return (EFAULT); 2527c478bd9Sstevel@tonic-gate return (0); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate static int 2568fd04b83SRoger A. Faulkner cstatat(int fd, char *name, struct stat *sb, int follow, int flags) 2577c478bd9Sstevel@tonic-gate { 2587c478bd9Sstevel@tonic-gate vnode_t *vp; 2597c478bd9Sstevel@tonic-gate int error; 2607c478bd9Sstevel@tonic-gate cred_t *cred; 2617c478bd9Sstevel@tonic-gate int link_follow; 262dd29fa4aSprabahar int estale_retry = 0; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW; 2657c478bd9Sstevel@tonic-gate lookup: 2668fd04b83SRoger A. Faulkner if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred)) 2677c478bd9Sstevel@tonic-gate return (set_errno(error)); 2687c478bd9Sstevel@tonic-gate error = cstat(vp, sb, flags, cred); 2697c478bd9Sstevel@tonic-gate crfree(cred); 2707c478bd9Sstevel@tonic-gate VN_RELE(vp); 2717c478bd9Sstevel@tonic-gate if (error != 0) { 2727c478bd9Sstevel@tonic-gate if (error == ESTALE && 2738fd04b83SRoger A. Faulkner fs_need_estale_retry(estale_retry++)) 2747c478bd9Sstevel@tonic-gate goto lookup; 2757c478bd9Sstevel@tonic-gate return (set_errno(error)); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate return (0); 2787c478bd9Sstevel@tonic-gate } 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate /* 2837c478bd9Sstevel@tonic-gate * 64-bit kernel, 32-bit applications, 32-bit file offsets 2847c478bd9Sstevel@tonic-gate */ 2858fd04b83SRoger A. Faulkner static int cstatat32(int, char *, struct stat32 *, int, int); 2867c478bd9Sstevel@tonic-gate static int cstat32(vnode_t *, struct stat32 *, int, cred_t *); 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate int 2897c478bd9Sstevel@tonic-gate fstat32(int fd, struct stat32 *sb) 2907c478bd9Sstevel@tonic-gate { 2917c478bd9Sstevel@tonic-gate FSTAT_BODY(fd, sb, cstat32) 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate int 295b9238976Sth199096 fstatat32(int fd, char *name, struct stat32 *sb, int flags) 2967c478bd9Sstevel@tonic-gate { 2978fd04b83SRoger A. Faulkner int followflag; 2988fd04b83SRoger A. Faulkner int csflags; 2997c478bd9Sstevel@tonic-gate 3008fd04b83SRoger A. Faulkner if (name == NULL) 3018fd04b83SRoger A. Faulkner return (fstat32(fd, sb)); 3027c478bd9Sstevel@tonic-gate 3038fd04b83SRoger A. Faulkner followflag = (flags & AT_SYMLINK_NOFOLLOW); 3048fd04b83SRoger A. Faulkner csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0); 3058fd04b83SRoger A. Faulkner if (followflag == 0) 3068fd04b83SRoger A. Faulkner csflags |= ATTR_REAL; /* flag for procfs lookups */ 3078fd04b83SRoger A. Faulkner 3088fd04b83SRoger A. Faulkner return (cstatat32(fd, name, sb, followflag, csflags)); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate int 3128fd04b83SRoger A. Faulkner stat32(char *name, struct stat32 *sb) 3137c478bd9Sstevel@tonic-gate { 3148fd04b83SRoger A. Faulkner return (fstatat32(AT_FDCWD, name, sb, 0)); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate int 3188fd04b83SRoger A. Faulkner lstat32(char *name, struct stat32 *sb) 3197c478bd9Sstevel@tonic-gate { 3208fd04b83SRoger A. Faulkner return (fstatat32(AT_FDCWD, name, sb, AT_SYMLINK_NOFOLLOW)); 3217c478bd9Sstevel@tonic-gate } 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate static int 3247c478bd9Sstevel@tonic-gate cstat32(vnode_t *vp, struct stat32 *ubp, int flag, struct cred *cr) 3257c478bd9Sstevel@tonic-gate { 3267c478bd9Sstevel@tonic-gate struct vfssw *vswp; 3277c478bd9Sstevel@tonic-gate struct stat32 sb; 3287c478bd9Sstevel@tonic-gate vattr_t vattr; 3297c478bd9Sstevel@tonic-gate int error; 3307c478bd9Sstevel@tonic-gate dev32_t st_dev, st_rdev; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE; 333da6c28aaSamw if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) 3347c478bd9Sstevel@tonic-gate return (error); 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* devices are a special case, see comments in cstat */ 3377c478bd9Sstevel@tonic-gate if ((vattr.va_size > MAXOFF32_T) && 3387c478bd9Sstevel@tonic-gate ((vp->v_type == VBLK) || (vp->v_type == VCHR))) { 3397c478bd9Sstevel@tonic-gate /* OVERFLOW | UNKNOWN_SIZE */ 3407c478bd9Sstevel@tonic-gate vattr.va_size = MAXOFF32_T; 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate /* check for large values */ 3447c478bd9Sstevel@tonic-gate if (!cmpldev(&st_dev, vattr.va_fsid) || 3457c478bd9Sstevel@tonic-gate !cmpldev(&st_rdev, vattr.va_rdev) || 3467c478bd9Sstevel@tonic-gate vattr.va_size > MAXOFF32_T || 3477c478bd9Sstevel@tonic-gate vattr.va_nblocks > INT32_MAX || 3487c478bd9Sstevel@tonic-gate vattr.va_nodeid > UINT32_MAX || 3497c478bd9Sstevel@tonic-gate TIMESPEC_OVERFLOW(&(vattr.va_atime)) || 3507c478bd9Sstevel@tonic-gate TIMESPEC_OVERFLOW(&(vattr.va_mtime)) || 3517c478bd9Sstevel@tonic-gate TIMESPEC_OVERFLOW(&(vattr.va_ctime))) 3527c478bd9Sstevel@tonic-gate return (EOVERFLOW); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate bzero(&sb, sizeof (sb)); 3557c478bd9Sstevel@tonic-gate sb.st_dev = st_dev; 3567c478bd9Sstevel@tonic-gate sb.st_ino = (ino32_t)vattr.va_nodeid; 3577c478bd9Sstevel@tonic-gate sb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode; 3587c478bd9Sstevel@tonic-gate sb.st_nlink = vattr.va_nlink; 3597c478bd9Sstevel@tonic-gate sb.st_uid = vattr.va_uid; 3607c478bd9Sstevel@tonic-gate sb.st_gid = vattr.va_gid; 3617c478bd9Sstevel@tonic-gate sb.st_rdev = st_rdev; 3627c478bd9Sstevel@tonic-gate sb.st_size = (off32_t)vattr.va_size; 3637c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&(sb.st_atim), &(vattr.va_atime)); 3647c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&(sb.st_mtim), &(vattr.va_mtime)); 3657c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&(sb.st_ctim), &(vattr.va_ctime)); 3667c478bd9Sstevel@tonic-gate sb.st_blksize = vattr.va_blksize; 3677c478bd9Sstevel@tonic-gate sb.st_blocks = (blkcnt32_t)vattr.va_nblocks; 3687c478bd9Sstevel@tonic-gate if (vp->v_vfsp != NULL) { 3697c478bd9Sstevel@tonic-gate vswp = &vfssw[vp->v_vfsp->vfs_fstype]; 3707c478bd9Sstevel@tonic-gate if (vswp->vsw_name && *vswp->vsw_name) 3717c478bd9Sstevel@tonic-gate (void) strcpy(sb.st_fstype, vswp->vsw_name); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate if (copyout(&sb, ubp, sizeof (sb))) 3747c478bd9Sstevel@tonic-gate return (EFAULT); 3757c478bd9Sstevel@tonic-gate return (0); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate static int 3798fd04b83SRoger A. Faulkner cstatat32(int fd, char *name, struct stat32 *sb, int follow, int flags) 3807c478bd9Sstevel@tonic-gate { 3817c478bd9Sstevel@tonic-gate vnode_t *vp; 3827c478bd9Sstevel@tonic-gate int error; 3837c478bd9Sstevel@tonic-gate cred_t *cred; 3847c478bd9Sstevel@tonic-gate int link_follow; 385dd29fa4aSprabahar int estale_retry = 0; 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW; 3887c478bd9Sstevel@tonic-gate lookup: 3898fd04b83SRoger A. Faulkner if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred)) 3907c478bd9Sstevel@tonic-gate return (set_errno(error)); 3917c478bd9Sstevel@tonic-gate error = cstat32(vp, sb, flags, cred); 3927c478bd9Sstevel@tonic-gate crfree(cred); 3937c478bd9Sstevel@tonic-gate VN_RELE(vp); 3947c478bd9Sstevel@tonic-gate if (error != 0) { 3957c478bd9Sstevel@tonic-gate if (error == ESTALE && 3968fd04b83SRoger A. Faulkner fs_need_estale_retry(estale_retry++)) 3977c478bd9Sstevel@tonic-gate goto lookup; 3987c478bd9Sstevel@tonic-gate return (set_errno(error)); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate return (0); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate #if defined(_ILP32) 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate /* 4087c478bd9Sstevel@tonic-gate * 32-bit kernel, 32-bit applications, 64-bit file offsets. 4097c478bd9Sstevel@tonic-gate * 4107c478bd9Sstevel@tonic-gate * These routines are implemented differently on 64-bit kernels. 4117c478bd9Sstevel@tonic-gate */ 4128fd04b83SRoger A. Faulkner static int cstatat64(int, char *, struct stat64 *, int, int); 4137c478bd9Sstevel@tonic-gate static int cstat64(vnode_t *, struct stat64 *, int, cred_t *); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate int 4167c478bd9Sstevel@tonic-gate fstat64(int fd, struct stat64 *sb) 4177c478bd9Sstevel@tonic-gate { 4187c478bd9Sstevel@tonic-gate FSTAT_BODY(fd, sb, cstat64) 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate int 4227c478bd9Sstevel@tonic-gate fstatat64(int fd, char *name, struct stat64 *sb, int flags) 4237c478bd9Sstevel@tonic-gate { 4248fd04b83SRoger A. Faulkner int followflag; 4258fd04b83SRoger A. Faulkner int csflags; 4268fd04b83SRoger A. Faulkner 4278fd04b83SRoger A. Faulkner if (name == NULL) 4288fd04b83SRoger A. Faulkner return (fstat64(fd, sb)); 4298fd04b83SRoger A. Faulkner 4308fd04b83SRoger A. Faulkner followflag = (flags & AT_SYMLINK_NOFOLLOW); 4318fd04b83SRoger A. Faulkner csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0); 4328fd04b83SRoger A. Faulkner if (followflag == 0) 4338fd04b83SRoger A. Faulkner csflags |= ATTR_REAL; /* flag for procfs lookups */ 4348fd04b83SRoger A. Faulkner 4358fd04b83SRoger A. Faulkner return (cstatat64(fd, name, sb, followflag, csflags)); 4368fd04b83SRoger A. Faulkner } 4378fd04b83SRoger A. Faulkner 4388fd04b83SRoger A. Faulkner int 4398fd04b83SRoger A. Faulkner stat64(char *name, struct stat64 *sb) 4408fd04b83SRoger A. Faulkner { 4418fd04b83SRoger A. Faulkner return (fstatat64(AT_FDCWD, name, sb, 0)); 4428fd04b83SRoger A. Faulkner } 4438fd04b83SRoger A. Faulkner 4448fd04b83SRoger A. Faulkner int 4458fd04b83SRoger A. Faulkner lstat64(char *name, struct stat64 *sb) 4468fd04b83SRoger A. Faulkner { 4478fd04b83SRoger A. Faulkner return (fstatat64(AT_FDCWD, name, sb, AT_SYMLINK_NOFOLLOW)); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate static int 4517c478bd9Sstevel@tonic-gate cstat64(vnode_t *vp, struct stat64 *ubp, int flag, cred_t *cr) 4527c478bd9Sstevel@tonic-gate { 4537c478bd9Sstevel@tonic-gate struct vfssw *vswp; 4547c478bd9Sstevel@tonic-gate struct stat64 lsb; 4557c478bd9Sstevel@tonic-gate vattr_t vattr; 4567c478bd9Sstevel@tonic-gate int error; 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE; 459da6c28aaSamw if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) 4607c478bd9Sstevel@tonic-gate return (error); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate bzero(&lsb, sizeof (lsb)); 4637c478bd9Sstevel@tonic-gate lsb.st_dev = vattr.va_fsid; 4647c478bd9Sstevel@tonic-gate lsb.st_ino = vattr.va_nodeid; 4657c478bd9Sstevel@tonic-gate lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode; 4667c478bd9Sstevel@tonic-gate lsb.st_nlink = vattr.va_nlink; 4677c478bd9Sstevel@tonic-gate lsb.st_uid = vattr.va_uid; 4687c478bd9Sstevel@tonic-gate lsb.st_gid = vattr.va_gid; 4697c478bd9Sstevel@tonic-gate lsb.st_rdev = vattr.va_rdev; 4707c478bd9Sstevel@tonic-gate lsb.st_size = vattr.va_size; 4717c478bd9Sstevel@tonic-gate lsb.st_atim = vattr.va_atime; 4727c478bd9Sstevel@tonic-gate lsb.st_mtim = vattr.va_mtime; 4737c478bd9Sstevel@tonic-gate lsb.st_ctim = vattr.va_ctime; 4747c478bd9Sstevel@tonic-gate lsb.st_blksize = vattr.va_blksize; 4757c478bd9Sstevel@tonic-gate lsb.st_blocks = vattr.va_nblocks; 4767c478bd9Sstevel@tonic-gate if (vp->v_vfsp != NULL) { 4777c478bd9Sstevel@tonic-gate vswp = &vfssw[vp->v_vfsp->vfs_fstype]; 4787c478bd9Sstevel@tonic-gate if (vswp->vsw_name && *vswp->vsw_name) 4797c478bd9Sstevel@tonic-gate (void) strcpy(lsb.st_fstype, vswp->vsw_name); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate if (copyout(&lsb, ubp, sizeof (lsb))) 4827c478bd9Sstevel@tonic-gate return (EFAULT); 4837c478bd9Sstevel@tonic-gate return (0); 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate static int 4878fd04b83SRoger A. Faulkner cstatat64(int fd, char *name, struct stat64 *sb, int follow, int flags) 4887c478bd9Sstevel@tonic-gate { 4897c478bd9Sstevel@tonic-gate vnode_t *vp; 4907c478bd9Sstevel@tonic-gate int error; 4917c478bd9Sstevel@tonic-gate cred_t *cred; 4927c478bd9Sstevel@tonic-gate int link_follow; 493dd29fa4aSprabahar int estale_retry = 0; 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW; 4967c478bd9Sstevel@tonic-gate lookup: 4978fd04b83SRoger A. Faulkner if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred)) 4987c478bd9Sstevel@tonic-gate return (set_errno(error)); 4997c478bd9Sstevel@tonic-gate error = cstat64(vp, sb, flags, cred); 5007c478bd9Sstevel@tonic-gate crfree(cred); 5017c478bd9Sstevel@tonic-gate VN_RELE(vp); 5027c478bd9Sstevel@tonic-gate if (error != 0) { 5037c478bd9Sstevel@tonic-gate if (error == ESTALE && 5048fd04b83SRoger A. Faulkner fs_need_estale_retry(estale_retry++)) 5057c478bd9Sstevel@tonic-gate goto lookup; 5067c478bd9Sstevel@tonic-gate return (set_errno(error)); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate return (0); 5097c478bd9Sstevel@tonic-gate } 5107c478bd9Sstevel@tonic-gate 5117c478bd9Sstevel@tonic-gate #endif /* _ILP32 */ 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* 5167c478bd9Sstevel@tonic-gate * 64-bit kernel, 32-bit applications, 64-bit file offsets. 5177c478bd9Sstevel@tonic-gate * 5187c478bd9Sstevel@tonic-gate * We'd really like to call the "native" stat calls for these ones, 5197c478bd9Sstevel@tonic-gate * but the problem is that the 64-bit ABI defines the 'stat64' structure 5207c478bd9Sstevel@tonic-gate * differently from the way the 32-bit ABI defines it. 5217c478bd9Sstevel@tonic-gate */ 5227c478bd9Sstevel@tonic-gate 5238fd04b83SRoger A. Faulkner static int cstatat64_32(int, char *, struct stat64_32 *, int, int); 5247c478bd9Sstevel@tonic-gate static int cstat64_32(vnode_t *, struct stat64_32 *, int, cred_t *); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate int 5277c478bd9Sstevel@tonic-gate fstat64_32(int fd, struct stat64_32 *sb) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate FSTAT_BODY(fd, sb, cstat64_32) 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate int 533b9238976Sth199096 fstatat64_32(int fd, char *name, struct stat64_32 *sb, int flags) 5347c478bd9Sstevel@tonic-gate { 5358fd04b83SRoger A. Faulkner int followflag; 5368fd04b83SRoger A. Faulkner int csflags; 5378fd04b83SRoger A. Faulkner 5388fd04b83SRoger A. Faulkner if (name == NULL) 5398fd04b83SRoger A. Faulkner return (fstat64_32(fd, sb)); 5408fd04b83SRoger A. Faulkner 5418fd04b83SRoger A. Faulkner followflag = (flags & AT_SYMLINK_NOFOLLOW); 5428fd04b83SRoger A. Faulkner csflags = (flags & _AT_TRIGGER ? ATTR_TRIGGER : 0); 5438fd04b83SRoger A. Faulkner if (followflag == 0) 5448fd04b83SRoger A. Faulkner csflags |= ATTR_REAL; /* flag for procfs lookups */ 5458fd04b83SRoger A. Faulkner 5468fd04b83SRoger A. Faulkner return (cstatat64_32(fd, name, sb, followflag, csflags)); 5478fd04b83SRoger A. Faulkner } 5488fd04b83SRoger A. Faulkner 5498fd04b83SRoger A. Faulkner int 5508fd04b83SRoger A. Faulkner stat64_32(char *name, struct stat64_32 *sb) 5518fd04b83SRoger A. Faulkner { 5528fd04b83SRoger A. Faulkner return (fstatat64_32(AT_FDCWD, name, sb, 0)); 5538fd04b83SRoger A. Faulkner } 5548fd04b83SRoger A. Faulkner 5558fd04b83SRoger A. Faulkner int 5568fd04b83SRoger A. Faulkner lstat64_32(char *name, struct stat64_32 *sb) 5578fd04b83SRoger A. Faulkner { 5588fd04b83SRoger A. Faulkner return (fstatat64_32(AT_FDCWD, name, sb, AT_SYMLINK_NOFOLLOW)); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate static int 5627c478bd9Sstevel@tonic-gate cstat64_32(vnode_t *vp, struct stat64_32 *ubp, int flag, cred_t *cr) 5637c478bd9Sstevel@tonic-gate { 5647c478bd9Sstevel@tonic-gate struct vfssw *vswp; 5657c478bd9Sstevel@tonic-gate struct stat64_32 lsb; 5667c478bd9Sstevel@tonic-gate vattr_t vattr; 5677c478bd9Sstevel@tonic-gate int error; 5687c478bd9Sstevel@tonic-gate dev32_t st_dev, st_rdev; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE; 571da6c28aaSamw if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) 5727c478bd9Sstevel@tonic-gate return (error); 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate if (!cmpldev(&st_dev, vattr.va_fsid) || 5757c478bd9Sstevel@tonic-gate !cmpldev(&st_rdev, vattr.va_rdev) || 5767c478bd9Sstevel@tonic-gate TIMESPEC_OVERFLOW(&(vattr.va_atime)) || 5777c478bd9Sstevel@tonic-gate TIMESPEC_OVERFLOW(&(vattr.va_mtime)) || 5787c478bd9Sstevel@tonic-gate TIMESPEC_OVERFLOW(&(vattr.va_ctime))) 5797c478bd9Sstevel@tonic-gate return (EOVERFLOW); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate bzero(&lsb, sizeof (lsb)); 5827c478bd9Sstevel@tonic-gate lsb.st_dev = st_dev; 5837c478bd9Sstevel@tonic-gate lsb.st_ino = vattr.va_nodeid; 5847c478bd9Sstevel@tonic-gate lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode; 5857c478bd9Sstevel@tonic-gate lsb.st_nlink = vattr.va_nlink; 5867c478bd9Sstevel@tonic-gate lsb.st_uid = vattr.va_uid; 5877c478bd9Sstevel@tonic-gate lsb.st_gid = vattr.va_gid; 5887c478bd9Sstevel@tonic-gate lsb.st_rdev = st_rdev; 5897c478bd9Sstevel@tonic-gate lsb.st_size = vattr.va_size; 5907c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&(lsb.st_atim), &(vattr.va_atime)); 5917c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&(lsb.st_mtim), &(vattr.va_mtime)); 5927c478bd9Sstevel@tonic-gate TIMESPEC_TO_TIMESPEC32(&(lsb.st_ctim), &(vattr.va_ctime)); 5937c478bd9Sstevel@tonic-gate lsb.st_blksize = vattr.va_blksize; 5947c478bd9Sstevel@tonic-gate lsb.st_blocks = vattr.va_nblocks; 5957c478bd9Sstevel@tonic-gate if (vp->v_vfsp != NULL) { 5967c478bd9Sstevel@tonic-gate vswp = &vfssw[vp->v_vfsp->vfs_fstype]; 5977c478bd9Sstevel@tonic-gate if (vswp->vsw_name && *vswp->vsw_name) 5987c478bd9Sstevel@tonic-gate (void) strcpy(lsb.st_fstype, vswp->vsw_name); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate if (copyout(&lsb, ubp, sizeof (lsb))) 6017c478bd9Sstevel@tonic-gate return (EFAULT); 6027c478bd9Sstevel@tonic-gate return (0); 6037c478bd9Sstevel@tonic-gate } 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate static int 6068fd04b83SRoger A. Faulkner cstatat64_32(int fd, char *name, struct stat64_32 *sb, int follow, int flags) 6077c478bd9Sstevel@tonic-gate { 6087c478bd9Sstevel@tonic-gate vnode_t *vp; 6097c478bd9Sstevel@tonic-gate int error; 6107c478bd9Sstevel@tonic-gate cred_t *cred; 6117c478bd9Sstevel@tonic-gate int link_follow; 612dd29fa4aSprabahar int estale_retry = 0; 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW; 6157c478bd9Sstevel@tonic-gate lookup: 6168fd04b83SRoger A. Faulkner if (error = cstatat_getvp(fd, name, link_follow, &vp, &cred)) 6177c478bd9Sstevel@tonic-gate return (set_errno(error)); 6187c478bd9Sstevel@tonic-gate error = cstat64_32(vp, sb, flags, cred); 6197c478bd9Sstevel@tonic-gate crfree(cred); 6207c478bd9Sstevel@tonic-gate VN_RELE(vp); 6217c478bd9Sstevel@tonic-gate if (error != 0) { 6227c478bd9Sstevel@tonic-gate if (error == ESTALE && 6238fd04b83SRoger A. Faulkner fs_need_estale_retry(estale_retry++)) 6247c478bd9Sstevel@tonic-gate goto lookup; 6257c478bd9Sstevel@tonic-gate return (set_errno(error)); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate return (0); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 631