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