1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34 /* 35 * Get file attribute information through a file name or a file descriptor. 36 */ 37 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 <fs/fs_subr.h> 58 59 /* 60 * ========================================================= 61 * "ROUND_TO_USEC" workaround for missing syscall interface. 62 * ========================================================= 63 * 64 * Solaris does not provide interface to set the timestamp of a file in 65 * nanosecond granularity. POSIX.1-2008 specifies such syscall interface: 66 * futimens(), utimensat(). The modern filesystems like ZFS support 67 * nanosecond granular timestamps. 68 * 69 * Before the workaround was implemented: 70 * 71 * The timestamps were read with the nanosecond granularity but written 72 * only with the microsecond granularity. If the timestamp was copied by 73 * reading it with nanosecond granularity and by writing with the microsecond 74 * granularity, the nanosecond part of the timestamp was zero. 75 * 76 * Example: such copying of the timestamp is done by touch(1) if the '-r' 77 * option is used. 'touch -r' is used by build procuderes based on make(1S). 78 * The missing nanosecond part was breaking build procuderes and resulted in 79 * hard to diagnose build failures. 80 * 81 * After the workaround is implemented: 82 * 83 * The timestamps are in the kernel still stored with the nanosecond 84 * granularity. However, all the 'stat' syscalls now clear the nanosecond part 85 * in the timestamp values returned by these syscalls. 86 * 87 * The "ROUND_TO_USEC" workaround should be removed when the new syscall 88 * interface is available. 89 */ 90 int stat_force_usec_granularity = 1; 91 92 #define ROUND_TO_USEC(tms) \ 93 { \ 94 (tms)->tv_nsec = (long)(((tms)->tv_nsec / 1000) * 1000); \ 95 } 96 97 /* 98 * Get the vp to be stated and the cred to be used for the call 99 * to VOP_GETATTR 100 */ 101 102 /* 103 * nmflag has the following values 104 * 105 * 1 - Always do lookup. i.e. stat, lstat. 106 * 2 - Name is optional i.e. fstatat 107 * 0 - Don't lookup name, vp is in file_p. i.e. fstat 108 * 109 */ 110 static int 111 cstatat_getvp(int fd, char *name, int nmflag, 112 int follow, vnode_t **vp, cred_t **cred) 113 { 114 vnode_t *startvp; 115 file_t *fp; 116 int error; 117 cred_t *cr; 118 int estale_retry = 0; 119 120 *vp = NULL; 121 122 /* 123 * Only return EFAULT for fstatat when fd == AT_FDCWD && name == NULL 124 */ 125 126 if (fd == AT_FDCWD) { 127 if (name != NULL || nmflag != 2) { 128 startvp = NULL; 129 cr = CRED(); 130 crhold(cr); 131 } else 132 return (EFAULT); 133 } else { 134 char startchar; 135 136 if (nmflag == 1 || (nmflag == 2 && name != NULL)) { 137 if (copyin(name, &startchar, sizeof (char))) 138 return (EFAULT); 139 } else { 140 startchar = '\0'; 141 } 142 if (startchar != '/' || nmflag == 0) { 143 if ((fp = getf(fd)) == NULL) { 144 return (EBADF); 145 } 146 startvp = fp->f_vnode; 147 cr = fp->f_cred; 148 crhold(cr); 149 VN_HOLD(startvp); 150 releasef(fd); 151 } else { 152 startvp = NULL; 153 cr = CRED(); 154 crhold(cr); 155 } 156 } 157 *cred = cr; 158 159 if (audit_active) 160 audit_setfsat_path(1); 161 162 163 if (nmflag == 1 || (nmflag == 2 && name != NULL)) { 164 lookup: 165 if (error = lookupnameat(name, UIO_USERSPACE, follow, NULLVPP, 166 vp, startvp)) { 167 if ((error == ESTALE) && 168 fs_need_estale_retry(estale_retry++)) 169 goto lookup; 170 if (startvp != NULL) 171 VN_RELE(startvp); 172 crfree(cr); 173 return (error); 174 } 175 if (startvp != NULL) 176 VN_RELE(startvp); 177 } else { 178 *vp = startvp; 179 } 180 181 return (0); 182 } 183 184 /* 185 * Native syscall interfaces: 186 * 187 * N-bit kernel, N-bit applications, N-bit file offsets 188 */ 189 190 static int cstatat(int, char *, int, struct stat *, int, int); 191 static int cstat(vnode_t *vp, struct stat *, int, cred_t *); 192 193 int 194 stat(char *fname, struct stat *sb) 195 { 196 return (cstatat(AT_FDCWD, fname, 1, sb, 0, ATTR_REAL)); 197 } 198 199 int 200 lstat(char *fname, struct stat *sb) 201 { 202 return (cstatat(AT_FDCWD, fname, 1, sb, AT_SYMLINK_NOFOLLOW, 0)); 203 } 204 205 /* 206 * fstat can and should be fast, do an inline implementation here. 207 */ 208 #define FSTAT_BODY(fd, sb, statfn) \ 209 { \ 210 file_t *fp; \ 211 int error; \ 212 \ 213 if ((fp = getf(fd)) == NULL) \ 214 return (set_errno(EBADF)); \ 215 if (audit_active) \ 216 audit_setfsat_path(1); \ 217 error = statfn(fp->f_vnode, sb, 0, fp->f_cred); \ 218 releasef(fd); \ 219 if (error) \ 220 return (set_errno(error)); \ 221 return (0); \ 222 } 223 224 int 225 fstat(int fd, struct stat *sb) 226 { 227 FSTAT_BODY(fd, sb, cstat) 228 } 229 230 int 231 fstatat(int fd, char *name, struct stat *sb, int flags) 232 { 233 return (cstatat(fd, name, 2, sb, 234 flags & AT_SYMLINK_NOFOLLOW ? AT_SYMLINK_NOFOLLOW : 0, 235 flags & _AT_TRIGGER ? ATTR_TRIGGER : 0)); 236 } 237 238 #if defined(__i386) || defined(__i386_COMPAT) 239 240 /* 241 * Handle all the "extended" stat operations in the same way; 242 * validate the version, then call the real handler. 243 */ 244 245 #define XSTAT_BODY(ver, f, s, fn) \ 246 return (ver != _STAT_VER ? set_errno(EINVAL) : fn(f, s)); 247 248 #endif /* __i386 || __i386_COMPAT */ 249 250 #if defined(__i386) 251 252 /* 253 * Syscalls for i386 applications that issue {,l,f}xstat() directly 254 */ 255 int 256 xstat(int version, char *fname, struct stat *sb) 257 { 258 XSTAT_BODY(version, fname, sb, stat) 259 } 260 261 int 262 lxstat(int version, char *fname, struct stat *sb) 263 { 264 XSTAT_BODY(version, fname, sb, lstat) 265 } 266 267 int 268 fxstat(int version, int fd, struct stat *sb) 269 { 270 XSTAT_BODY(version, fd, sb, fstat) 271 } 272 273 #endif /* __i386 */ 274 275 /* 276 * Common code for stat(), lstat(), and fstat(). 277 * (32-bit kernel, 32-bit applications, 32-bit files) 278 * (64-bit kernel, 64-bit applications, 64-bit files) 279 */ 280 static int 281 cstat(vnode_t *vp, struct stat *ubp, int flag, cred_t *cr) 282 { 283 struct vfssw *vswp; 284 struct stat sb; 285 vattr_t vattr; 286 int error; 287 288 vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE; 289 if ((error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) != 0) 290 return (error); 291 292 /* Workaround - see beginning of the file for the details */ 293 if (stat_force_usec_granularity) { 294 ROUND_TO_USEC(&(vattr.va_atime)); 295 ROUND_TO_USEC(&(vattr.va_mtime)); 296 ROUND_TO_USEC(&(vattr.va_ctime)); 297 } 298 299 #ifdef _ILP32 300 /* 301 * (32-bit kernel, 32-bit applications, 32-bit files) 302 * NOTE: 32-bit kernel maintains a 64-bit unsigend va_size. 303 * 304 * st_size of devices (VBLK and VCHR special files) is a special case. 305 * POSIX does not define size behavior for special files, so the 306 * following Solaris specific behavior is not a violation. Solaris 307 * returns the size of the device. 308 * 309 * For compatibility with 32-bit programs which happen to do stat() on 310 * a (mknod) bigger than 2GB we suppress the large file EOVERFLOW and 311 * instead we return the value MAXOFF32_T (LONG_MAX). 312 * 313 * 32-bit applications that care about the size of devices should be 314 * built 64-bit or use a large file interface (lfcompile(5) or lf64(5)). 315 */ 316 if ((vattr.va_size > MAXOFF32_T) && 317 ((vp->v_type == VBLK) || (vp->v_type == VCHR))) { 318 /* OVERFLOW | UNKNOWN_SIZE */ 319 vattr.va_size = MAXOFF32_T; 320 } 321 #endif /* _ILP32 */ 322 if (vattr.va_size > MAXOFF_T || vattr.va_nblocks > LONG_MAX || 323 vattr.va_nodeid > ULONG_MAX) 324 return (EOVERFLOW); 325 326 bzero(&sb, sizeof (sb)); 327 sb.st_dev = vattr.va_fsid; 328 sb.st_ino = (ino_t)vattr.va_nodeid; 329 sb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode; 330 sb.st_nlink = vattr.va_nlink; 331 sb.st_uid = vattr.va_uid; 332 sb.st_gid = vattr.va_gid; 333 sb.st_rdev = vattr.va_rdev; 334 sb.st_size = (off_t)vattr.va_size; 335 sb.st_atim = vattr.va_atime; 336 sb.st_mtim = vattr.va_mtime; 337 sb.st_ctim = vattr.va_ctime; 338 sb.st_blksize = vattr.va_blksize; 339 sb.st_blocks = (blkcnt_t)vattr.va_nblocks; 340 if (vp->v_vfsp != NULL) { 341 vswp = &vfssw[vp->v_vfsp->vfs_fstype]; 342 if (vswp->vsw_name && *vswp->vsw_name) 343 (void) strcpy(sb.st_fstype, vswp->vsw_name); 344 } 345 if (copyout(&sb, ubp, sizeof (sb))) 346 return (EFAULT); 347 return (0); 348 } 349 350 static int 351 cstatat(int fd, char *name, int nmflag, struct stat *sb, int follow, int flags) 352 { 353 vnode_t *vp; 354 int error; 355 cred_t *cred; 356 int link_follow; 357 int estale_retry = 0; 358 359 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW; 360 lookup: 361 if (error = cstatat_getvp(fd, name, nmflag, link_follow, &vp, &cred)) 362 return (set_errno(error)); 363 error = cstat(vp, sb, flags, cred); 364 crfree(cred); 365 VN_RELE(vp); 366 out: 367 if (error != 0) { 368 if (error == ESTALE && 369 fs_need_estale_retry(estale_retry++) && 370 (nmflag == 1 || (nmflag == 2 && name != NULL))) 371 goto lookup; 372 return (set_errno(error)); 373 } 374 return (0); 375 } 376 377 #if defined(_SYSCALL32_IMPL) 378 379 /* 380 * 64-bit kernel, 32-bit applications, 32-bit file offsets 381 */ 382 static int cstatat32(int, char *, int, struct stat32 *, int, int); 383 static int cstat32(vnode_t *, struct stat32 *, int, cred_t *); 384 int 385 stat32(char *fname, struct stat32 *sb) 386 { 387 return (cstatat32(AT_FDCWD, fname, 1, sb, 0, ATTR_REAL)); 388 } 389 390 int 391 lstat32(char *fname, struct stat32 *sb) 392 { 393 return (cstatat32(AT_FDCWD, fname, 1, sb, AT_SYMLINK_NOFOLLOW, 0)); 394 } 395 396 int 397 fstat32(int fd, struct stat32 *sb) 398 { 399 FSTAT_BODY(fd, sb, cstat32) 400 } 401 402 int 403 fstatat32(int fd, char *name, struct stat32 *sb, int flags) 404 { 405 return (cstatat32(fd, name, 2, sb, 406 flags & AT_SYMLINK_NOFOLLOW ? AT_SYMLINK_NOFOLLOW : 0, 407 flags & _AT_TRIGGER ? ATTR_TRIGGER : 0)); 408 } 409 410 #if defined(__i386_COMPAT) 411 412 /* 413 * Syscalls for i386 applications that issue {,l,f}xstat() directly 414 */ 415 int 416 xstat32(int version, char *fname, struct stat32 *sb) 417 { 418 XSTAT_BODY(version, fname, sb, stat32) 419 } 420 421 int 422 lxstat32(int version, char *fname, struct stat32 *sb) 423 { 424 XSTAT_BODY(version, fname, sb, lstat32) 425 } 426 427 int 428 fxstat32(int version, int fd, struct stat32 *sb) 429 { 430 XSTAT_BODY(version, fd, sb, fstat32) 431 } 432 433 #endif /* __i386_COMPAT */ 434 435 static int 436 cstat32(vnode_t *vp, struct stat32 *ubp, int flag, struct cred *cr) 437 { 438 struct vfssw *vswp; 439 struct stat32 sb; 440 vattr_t vattr; 441 int error; 442 dev32_t st_dev, st_rdev; 443 444 vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE; 445 if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) 446 return (error); 447 448 /* Workaround - see beginning of the file for the details */ 449 if (stat_force_usec_granularity) { 450 ROUND_TO_USEC(&(vattr.va_atime)); 451 ROUND_TO_USEC(&(vattr.va_mtime)); 452 ROUND_TO_USEC(&(vattr.va_ctime)); 453 } 454 455 /* devices are a special case, see comments in cstat */ 456 if ((vattr.va_size > MAXOFF32_T) && 457 ((vp->v_type == VBLK) || (vp->v_type == VCHR))) { 458 /* OVERFLOW | UNKNOWN_SIZE */ 459 vattr.va_size = MAXOFF32_T; 460 } 461 462 /* check for large values */ 463 if (!cmpldev(&st_dev, vattr.va_fsid) || 464 !cmpldev(&st_rdev, vattr.va_rdev) || 465 vattr.va_size > MAXOFF32_T || 466 vattr.va_nblocks > INT32_MAX || 467 vattr.va_nodeid > UINT32_MAX || 468 TIMESPEC_OVERFLOW(&(vattr.va_atime)) || 469 TIMESPEC_OVERFLOW(&(vattr.va_mtime)) || 470 TIMESPEC_OVERFLOW(&(vattr.va_ctime))) 471 return (EOVERFLOW); 472 473 bzero(&sb, sizeof (sb)); 474 sb.st_dev = st_dev; 475 sb.st_ino = (ino32_t)vattr.va_nodeid; 476 sb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode; 477 sb.st_nlink = vattr.va_nlink; 478 sb.st_uid = vattr.va_uid; 479 sb.st_gid = vattr.va_gid; 480 sb.st_rdev = st_rdev; 481 sb.st_size = (off32_t)vattr.va_size; 482 TIMESPEC_TO_TIMESPEC32(&(sb.st_atim), &(vattr.va_atime)); 483 TIMESPEC_TO_TIMESPEC32(&(sb.st_mtim), &(vattr.va_mtime)); 484 TIMESPEC_TO_TIMESPEC32(&(sb.st_ctim), &(vattr.va_ctime)); 485 sb.st_blksize = vattr.va_blksize; 486 sb.st_blocks = (blkcnt32_t)vattr.va_nblocks; 487 if (vp->v_vfsp != NULL) { 488 vswp = &vfssw[vp->v_vfsp->vfs_fstype]; 489 if (vswp->vsw_name && *vswp->vsw_name) 490 (void) strcpy(sb.st_fstype, vswp->vsw_name); 491 } 492 if (copyout(&sb, ubp, sizeof (sb))) 493 return (EFAULT); 494 return (0); 495 } 496 497 static int 498 cstatat32(int fd, char *name, int nmflag, struct stat32 *sb, 499 int follow, int flags) 500 { 501 vnode_t *vp; 502 int error; 503 cred_t *cred; 504 int link_follow; 505 int estale_retry = 0; 506 507 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW; 508 lookup: 509 if (error = cstatat_getvp(fd, name, nmflag, link_follow, &vp, &cred)) 510 return (set_errno(error)); 511 error = cstat32(vp, sb, flags, cred); 512 crfree(cred); 513 VN_RELE(vp); 514 out: 515 if (error != 0) { 516 if (error == ESTALE && 517 fs_need_estale_retry(estale_retry++) && 518 (nmflag == 1 || (nmflag == 2 && name != NULL))) 519 goto lookup; 520 return (set_errno(error)); 521 } 522 return (0); 523 } 524 525 #endif /* _SYSCALL32_IMPL */ 526 527 #if defined(_ILP32) 528 529 /* 530 * 32-bit kernel, 32-bit applications, 64-bit file offsets. 531 * 532 * These routines are implemented differently on 64-bit kernels. 533 */ 534 static int cstatat64(int, char *, int, struct stat64 *, int, int); 535 static int cstat64(vnode_t *, struct stat64 *, int, cred_t *); 536 537 int 538 stat64(char *fname, struct stat64 *sb) 539 { 540 return (cstatat64(AT_FDCWD, fname, 1, sb, 0, ATTR_REAL)); 541 } 542 543 int 544 lstat64(char *fname, struct stat64 *sb) 545 { 546 return (cstatat64(AT_FDCWD, fname, 1, sb, AT_SYMLINK_NOFOLLOW, 0)); 547 } 548 549 int 550 fstat64(int fd, struct stat64 *sb) 551 { 552 FSTAT_BODY(fd, sb, cstat64) 553 } 554 555 int 556 fstatat64(int fd, char *name, struct stat64 *sb, int flags) 557 { 558 return (cstatat64(fd, name, 2, sb, 559 flags & AT_SYMLINK_NOFOLLOW ? AT_SYMLINK_NOFOLLOW : 0, 560 flags & _AT_TRIGGER ? ATTR_TRIGGER : 0)); 561 } 562 563 static int 564 cstat64(vnode_t *vp, struct stat64 *ubp, int flag, cred_t *cr) 565 { 566 struct vfssw *vswp; 567 struct stat64 lsb; 568 vattr_t vattr; 569 int error; 570 571 vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE; 572 if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) 573 return (error); 574 575 /* Workaround - see beginning of the file for the details */ 576 if (stat_force_usec_granularity) { 577 ROUND_TO_USEC(&(vattr.va_atime)); 578 ROUND_TO_USEC(&(vattr.va_mtime)); 579 ROUND_TO_USEC(&(vattr.va_ctime)); 580 } 581 582 bzero(&lsb, sizeof (lsb)); 583 lsb.st_dev = vattr.va_fsid; 584 lsb.st_ino = vattr.va_nodeid; 585 lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode; 586 lsb.st_nlink = vattr.va_nlink; 587 lsb.st_uid = vattr.va_uid; 588 lsb.st_gid = vattr.va_gid; 589 lsb.st_rdev = vattr.va_rdev; 590 lsb.st_size = vattr.va_size; 591 lsb.st_atim = vattr.va_atime; 592 lsb.st_mtim = vattr.va_mtime; 593 lsb.st_ctim = vattr.va_ctime; 594 lsb.st_blksize = vattr.va_blksize; 595 lsb.st_blocks = vattr.va_nblocks; 596 if (vp->v_vfsp != NULL) { 597 vswp = &vfssw[vp->v_vfsp->vfs_fstype]; 598 if (vswp->vsw_name && *vswp->vsw_name) 599 (void) strcpy(lsb.st_fstype, vswp->vsw_name); 600 } 601 if (copyout(&lsb, ubp, sizeof (lsb))) 602 return (EFAULT); 603 return (0); 604 } 605 606 static int 607 cstatat64(int fd, char *name, int nmflag, struct stat64 *sb, 608 int follow, int flags) 609 { 610 vnode_t *vp; 611 int error; 612 cred_t *cred; 613 int link_follow; 614 int estale_retry = 0; 615 616 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW; 617 lookup: 618 if (error = cstatat_getvp(fd, name, nmflag, link_follow, &vp, &cred)) 619 return (set_errno(error)); 620 error = cstat64(vp, sb, flags, cred); 621 crfree(cred); 622 VN_RELE(vp); 623 out: 624 if (error != 0) { 625 if (error == ESTALE && 626 fs_need_estale_retry(estale_retry++) && 627 (nmflag == 1 || (nmflag == 2 && name != NULL))) 628 goto lookup; 629 return (set_errno(error)); 630 } 631 return (0); 632 } 633 634 #endif /* _ILP32 */ 635 636 #if defined(_SYSCALL32_IMPL) 637 638 /* 639 * 64-bit kernel, 32-bit applications, 64-bit file offsets. 640 * 641 * We'd really like to call the "native" stat calls for these ones, 642 * but the problem is that the 64-bit ABI defines the 'stat64' structure 643 * differently from the way the 32-bit ABI defines it. 644 */ 645 646 static int cstatat64_32(int, char *, int, struct stat64_32 *, int, int); 647 static int cstat64_32(vnode_t *, struct stat64_32 *, int, cred_t *); 648 649 int 650 stat64_32(char *fname, struct stat64_32 *sb) 651 { 652 return (cstatat64_32(AT_FDCWD, fname, 1, sb, 0, ATTR_REAL)); 653 } 654 655 int 656 lstat64_32(char *fname, struct stat64_32 *sb) 657 { 658 return (cstatat64_32(AT_FDCWD, fname, 1, sb, AT_SYMLINK_NOFOLLOW, 0)); 659 } 660 661 int 662 fstat64_32(int fd, struct stat64_32 *sb) 663 { 664 FSTAT_BODY(fd, sb, cstat64_32) 665 } 666 667 int 668 fstatat64_32(int fd, char *name, struct stat64_32 *sb, int flags) 669 { 670 return (cstatat64_32(fd, name, 2, sb, 671 flags & AT_SYMLINK_NOFOLLOW ? AT_SYMLINK_NOFOLLOW : 0, 672 flags & _AT_TRIGGER ? ATTR_TRIGGER : 0)); 673 } 674 675 static int 676 cstat64_32(vnode_t *vp, struct stat64_32 *ubp, int flag, cred_t *cr) 677 { 678 struct vfssw *vswp; 679 struct stat64_32 lsb; 680 vattr_t vattr; 681 int error; 682 dev32_t st_dev, st_rdev; 683 684 vattr.va_mask = AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE; 685 if (error = VOP_GETATTR(vp, &vattr, flag, cr, NULL)) 686 return (error); 687 688 /* Workaround - see beginning of the file for the details */ 689 if (stat_force_usec_granularity) { 690 ROUND_TO_USEC(&(vattr.va_atime)); 691 ROUND_TO_USEC(&(vattr.va_mtime)); 692 ROUND_TO_USEC(&(vattr.va_ctime)); 693 } 694 695 if (!cmpldev(&st_dev, vattr.va_fsid) || 696 !cmpldev(&st_rdev, vattr.va_rdev) || 697 TIMESPEC_OVERFLOW(&(vattr.va_atime)) || 698 TIMESPEC_OVERFLOW(&(vattr.va_mtime)) || 699 TIMESPEC_OVERFLOW(&(vattr.va_ctime))) 700 return (EOVERFLOW); 701 702 bzero(&lsb, sizeof (lsb)); 703 lsb.st_dev = st_dev; 704 lsb.st_ino = vattr.va_nodeid; 705 lsb.st_mode = VTTOIF(vattr.va_type) | vattr.va_mode; 706 lsb.st_nlink = vattr.va_nlink; 707 lsb.st_uid = vattr.va_uid; 708 lsb.st_gid = vattr.va_gid; 709 lsb.st_rdev = st_rdev; 710 lsb.st_size = vattr.va_size; 711 TIMESPEC_TO_TIMESPEC32(&(lsb.st_atim), &(vattr.va_atime)); 712 TIMESPEC_TO_TIMESPEC32(&(lsb.st_mtim), &(vattr.va_mtime)); 713 TIMESPEC_TO_TIMESPEC32(&(lsb.st_ctim), &(vattr.va_ctime)); 714 lsb.st_blksize = vattr.va_blksize; 715 lsb.st_blocks = vattr.va_nblocks; 716 if (vp->v_vfsp != NULL) { 717 vswp = &vfssw[vp->v_vfsp->vfs_fstype]; 718 if (vswp->vsw_name && *vswp->vsw_name) 719 (void) strcpy(lsb.st_fstype, vswp->vsw_name); 720 } 721 if (copyout(&lsb, ubp, sizeof (lsb))) 722 return (EFAULT); 723 return (0); 724 } 725 726 static int 727 cstatat64_32(int fd, char *name, int nmflag, struct stat64_32 *sb, 728 int follow, int flags) 729 { 730 vnode_t *vp; 731 int error; 732 cred_t *cred; 733 int link_follow; 734 int estale_retry = 0; 735 736 link_follow = (follow == AT_SYMLINK_NOFOLLOW) ? NO_FOLLOW : FOLLOW; 737 lookup: 738 if (error = cstatat_getvp(fd, name, nmflag, link_follow, &vp, &cred)) 739 return (set_errno(error)); 740 error = cstat64_32(vp, sb, flags, cred); 741 crfree(cred); 742 VN_RELE(vp); 743 out: 744 if (error != 0) { 745 if (error == ESTALE && 746 fs_need_estale_retry(estale_retry++) && 747 (nmflag == 1 || (nmflag == 2 && name != NULL))) 748 goto lookup; 749 return (set_errno(error)); 750 } 751 return (0); 752 } 753 754 #endif /* _SYSCALL32_IMPL */ 755