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