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