1/* 2 * Copyright (c) 2000-2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ 29/* 30 * Copyright (c) 1989, 1993 31 * The Regents of the University of California. All rights reserved. 32 * (c) UNIX System Laboratories, Inc. 33 * All or some portions of this file are derived from material licensed 34 * to the University of California by American Telephone and Telegraph 35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 36 * the permission of UNIX System Laboratories, Inc. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 3. All advertising materials mentioning features or use of this software 47 * must display the following acknowledgement: 48 * This product includes software developed by the University of 49 * California, Berkeley and its contributors. 50 * 4. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 * 66 * @(#)kpi_vfs.c 67 */ 68/* 69 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 70 * support for mandatory and extensible security protections. This notice 71 * is included in support of clause 2.2 (b) of the Apple Public License, 72 * Version 2.0. 73 */ 74 75/* 76 * External virtual filesystem routines 77 */ 78 79 80#include <sys/param.h> 81#include <sys/systm.h> 82#include <sys/proc_internal.h> 83#include <sys/kauth.h> 84#include <sys/mount.h> 85#include <sys/mount_internal.h> 86#include <sys/time.h> 87#include <sys/vnode_internal.h> 88#include <sys/stat.h> 89#include <sys/namei.h> 90#include <sys/ucred.h> 91#include <sys/buf.h> 92#include <sys/errno.h> 93#include <sys/malloc.h> 94#include <sys/domain.h> 95#include <sys/mbuf.h> 96#include <sys/syslog.h> 97#include <sys/ubc.h> 98#include <sys/vm.h> 99#include <sys/sysctl.h> 100#include <sys/filedesc.h> 101#include <sys/event.h> 102#include <sys/fsevents.h> 103#include <sys/user.h> 104#include <sys/lockf.h> 105#include <sys/xattr.h> 106 107#include <kern/assert.h> 108#include <kern/kalloc.h> 109#include <kern/task.h> 110 111#include <libkern/OSByteOrder.h> 112 113#include <miscfs/specfs/specdev.h> 114 115#include <mach/mach_types.h> 116#include <mach/memory_object_types.h> 117#include <mach/task.h> 118 119#if CONFIG_MACF 120#include <security/mac_framework.h> 121#endif 122 123#define ESUCCESS 0 124#undef mount_t 125#undef vnode_t 126 127#define COMPAT_ONLY 128 129 130#if CONFIG_VFS_FUNNEL 131#define THREAD_SAFE_FS(VP) \ 132 ((VP)->v_unsafefs ? 0 : 1) 133#endif /* CONFIG_VFS_FUNNEL */ 134 135#define NATIVE_XATTR(VP) \ 136 ((VP)->v_mount ? (VP)->v_mount->mnt_kern_flag & MNTK_EXTENDED_ATTRS : 0) 137 138static void xattrfile_remove(vnode_t dvp, const char *basename, 139 vfs_context_t ctx, int force); 140static void xattrfile_setattr(vnode_t dvp, const char * basename, 141 struct vnode_attr * vap, vfs_context_t ctx); 142 143/* 144 * vnode_setneedinactive 145 * 146 * Description: Indicate that when the last iocount on this vnode goes away, 147 * and the usecount is also zero, we should inform the filesystem 148 * via VNOP_INACTIVE. 149 * 150 * Parameters: vnode_t vnode to mark 151 * 152 * Returns: Nothing 153 * 154 * Notes: Notably used when we're deleting a file--we need not have a 155 * usecount, so VNOP_INACTIVE may not get called by anyone. We 156 * want it called when we drop our iocount. 157 */ 158void 159vnode_setneedinactive(vnode_t vp) 160{ 161 cache_purge(vp); 162 163 vnode_lock_spin(vp); 164 vp->v_lflag |= VL_NEEDINACTIVE; 165 vnode_unlock(vp); 166} 167 168 169#if CONFIG_VFS_FUNNEL 170int 171lock_fsnode(vnode_t vp, int *funnel_state) 172{ 173 if (funnel_state) 174 *funnel_state = thread_funnel_set(kernel_flock, TRUE); 175 176 if (vp->v_unsafefs) { 177 if (vp->v_unsafefs->fsnodeowner == current_thread()) { 178 vp->v_unsafefs->fsnode_count++; 179 } else { 180 lck_mtx_lock(&vp->v_unsafefs->fsnodelock); 181 182 if (vp->v_lflag & (VL_TERMWANT | VL_TERMINATE | VL_DEAD)) { 183 lck_mtx_unlock(&vp->v_unsafefs->fsnodelock); 184 185 if (funnel_state) 186 (void) thread_funnel_set(kernel_flock, *funnel_state); 187 return (ENOENT); 188 } 189 vp->v_unsafefs->fsnodeowner = current_thread(); 190 vp->v_unsafefs->fsnode_count = 1; 191 } 192 } 193 return (0); 194} 195 196 197void 198unlock_fsnode(vnode_t vp, int *funnel_state) 199{ 200 if (vp->v_unsafefs) { 201 if (--vp->v_unsafefs->fsnode_count == 0) { 202 vp->v_unsafefs->fsnodeowner = NULL; 203 lck_mtx_unlock(&vp->v_unsafefs->fsnodelock); 204 } 205 } 206 if (funnel_state) 207 (void) thread_funnel_set(kernel_flock, *funnel_state); 208} 209#endif /* CONFIG_VFS_FUNNEL */ 210 211 212 213/* ====================================================================== */ 214/* ************ EXTERNAL KERNEL APIS ********************************** */ 215/* ====================================================================== */ 216 217/* 218 * implementations of exported VFS operations 219 */ 220int 221VFS_MOUNT(mount_t mp, vnode_t devvp, user_addr_t data, vfs_context_t ctx) 222{ 223 int error; 224#if CONFIG_VFS_FUNNEL 225 int thread_safe; 226 int funnel_state = 0; 227#endif /* CONFIG_VFS_FUNNEL */ 228 229 if ((mp == dead_mountp) || (mp->mnt_op->vfs_mount == 0)) 230 return(ENOTSUP); 231 232#if CONFIG_VFS_FUNNEL 233 thread_safe = (mp->mnt_vtable->vfc_vfsflags & VFC_VFSTHREADSAFE); 234 if (!thread_safe) { 235 funnel_state = thread_funnel_set(kernel_flock, TRUE); 236 } 237#endif /* CONFIG_VFS_FUNNEL */ 238 239 if (vfs_context_is64bit(ctx)) { 240 if (vfs_64bitready(mp)) { 241 error = (*mp->mnt_op->vfs_mount)(mp, devvp, data, ctx); 242 } 243 else { 244 error = ENOTSUP; 245 } 246 } 247 else { 248 error = (*mp->mnt_op->vfs_mount)(mp, devvp, data, ctx); 249 } 250 251#if CONFIG_VFS_FUNNEL 252 if (!thread_safe) { 253 (void) thread_funnel_set(kernel_flock, funnel_state); 254 } 255#endif /* CONFIG_VFS_FUNNEL */ 256 257 return (error); 258} 259 260int 261VFS_START(mount_t mp, int flags, vfs_context_t ctx) 262{ 263 int error; 264#if CONFIG_VFS_FUNNEL 265 int thread_safe; 266 int funnel_state = 0; 267#endif /* CONFIG_VFS_FUNNEL */ 268 269 if ((mp == dead_mountp) || (mp->mnt_op->vfs_start == 0)) 270 return(ENOTSUP); 271 272#if CONFIG_VFS_FUNNEL 273 thread_safe = (mp->mnt_vtable->vfc_vfsflags & VFC_VFSTHREADSAFE); 274 if (!thread_safe) { 275 funnel_state = thread_funnel_set(kernel_flock, TRUE); 276 } 277#endif /* CONFIG_VFS_FUNNEL */ 278 279 error = (*mp->mnt_op->vfs_start)(mp, flags, ctx); 280 281#if CONFIG_VFS_FUNNEL 282 if (!thread_safe) { 283 (void) thread_funnel_set(kernel_flock, funnel_state); 284 } 285#endif /* CONFIG_VFS_FUNNEL */ 286 287 return (error); 288} 289 290int 291VFS_UNMOUNT(mount_t mp, int flags, vfs_context_t ctx) 292{ 293 int error; 294#if CONFIG_VFS_FUNNEL 295 int thread_safe; 296 int funnel_state = 0; 297#endif /* CONFIG_VFS_FUNNEL */ 298 299 if ((mp == dead_mountp) || (mp->mnt_op->vfs_unmount == 0)) 300 return(ENOTSUP); 301 302#if CONFIG_VFS_FUNNEL 303 thread_safe = (mp->mnt_vtable->vfc_vfsflags & VFC_VFSTHREADSAFE); 304 if (!thread_safe) { 305 funnel_state = thread_funnel_set(kernel_flock, TRUE); 306 } 307#endif /* CONFIG_VFS_FUNNEL */ 308 309 error = (*mp->mnt_op->vfs_unmount)(mp, flags, ctx); 310 311#if CONFIG_VFS_FUNNEL 312 if (!thread_safe) { 313 (void) thread_funnel_set(kernel_flock, funnel_state); 314 } 315#endif /* CONFIG_VFS_FUNNEL */ 316 317 return (error); 318} 319 320/* 321 * Returns: 0 Success 322 * ENOTSUP Not supported 323 * <vfs_root>:ENOENT 324 * <vfs_root>:??? 325 * 326 * Note: The return codes from the underlying VFS's root routine can't 327 * be fully enumerated here, since third party VFS authors may not 328 * limit their error returns to the ones documented here, even 329 * though this may result in some programs functioning incorrectly. 330 * 331 * The return codes documented above are those which may currently 332 * be returned by HFS from hfs_vfs_root, which is a simple wrapper 333 * for a call to hfs_vget on the volume mount poit, not including 334 * additional error codes which may be propagated from underlying 335 * routines called by hfs_vget. 336 */ 337int 338VFS_ROOT(mount_t mp, struct vnode ** vpp, vfs_context_t ctx) 339{ 340 int error; 341#if CONFIG_VFS_FUNNEL 342 int thread_safe; 343 int funnel_state = 0; 344#endif /* CONFIG_VFS_FUNNEL */ 345 346 if ((mp == dead_mountp) || (mp->mnt_op->vfs_root == 0)) 347 return(ENOTSUP); 348 349 if (ctx == NULL) { 350 ctx = vfs_context_current(); 351 } 352 353#if CONFIG_VFS_FUNNEL 354 thread_safe = (mp->mnt_vtable->vfc_vfsflags & VFC_VFSTHREADSAFE); 355 if (!thread_safe) { 356 funnel_state = thread_funnel_set(kernel_flock, TRUE); 357 } 358#endif /* CONFIG_VFS_FUNNEL */ 359 360 error = (*mp->mnt_op->vfs_root)(mp, vpp, ctx); 361 362#if CONFIG_VFS_FUNNEL 363 if (!thread_safe) { 364 (void) thread_funnel_set(kernel_flock, funnel_state); 365 } 366#endif /* CONFIG_VFS_FUNNEL */ 367 368 return (error); 369} 370 371int 372VFS_QUOTACTL(mount_t mp, int cmd, uid_t uid, caddr_t datap, vfs_context_t ctx) 373{ 374 int error; 375#if CONFIG_VFS_FUNNEL 376 int thread_safe; 377 int funnel_state = 0; 378#endif /* CONFIG_VFS_FUNNEL */ 379 380 if ((mp == dead_mountp) || (mp->mnt_op->vfs_quotactl == 0)) 381 return(ENOTSUP); 382 383#if CONFIG_VFS_FUNNEL 384 thread_safe = (mp->mnt_vtable->vfc_vfsflags & VFC_VFSTHREADSAFE); 385 if (!thread_safe) { 386 funnel_state = thread_funnel_set(kernel_flock, TRUE); 387 } 388#endif /* CONFIG_VFS_FUNNEL */ 389 390 error = (*mp->mnt_op->vfs_quotactl)(mp, cmd, uid, datap, ctx); 391 392#if CONFIG_VFS_FUNNEL 393 if (!thread_safe) { 394 (void) thread_funnel_set(kernel_flock, funnel_state); 395 } 396#endif /* CONFIG_VFS_FUNNEL */ 397 398 return (error); 399} 400 401int 402VFS_GETATTR(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx) 403{ 404 int error; 405#if CONFIG_VFS_FUNNEL 406 int thread_safe; 407 int funnel_state = 0; 408#endif /* CONFIG_VFS_FUNNEL */ 409 410 if ((mp == dead_mountp) || (mp->mnt_op->vfs_getattr == 0)) 411 return(ENOTSUP); 412 413 if (ctx == NULL) { 414 ctx = vfs_context_current(); 415 } 416 417#if CONFIG_VFS_FUNNEL 418 thread_safe = (mp->mnt_vtable->vfc_vfsflags & VFC_VFSTHREADSAFE); 419 if (!thread_safe) { 420 funnel_state = thread_funnel_set(kernel_flock, TRUE); 421 } 422#endif /* CONFIG_VFS_FUNNEL */ 423 424 error = (*mp->mnt_op->vfs_getattr)(mp, vfa, ctx); 425 426#if CONFIG_VFS_FUNNEL 427 if (!thread_safe) { 428 (void) thread_funnel_set(kernel_flock, funnel_state); 429 } 430#endif /* CONFIG_VFS_FUNNEL */ 431 432 return(error); 433} 434 435int 436VFS_SETATTR(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx) 437{ 438 int error; 439#if CONFIG_VFS_FUNNEL 440 int thread_safe; 441 int funnel_state = 0; 442#endif /* CONFIG_VFS_FUNNEL */ 443 444 if ((mp == dead_mountp) || (mp->mnt_op->vfs_setattr == 0)) 445 return(ENOTSUP); 446 447 if (ctx == NULL) { 448 ctx = vfs_context_current(); 449 } 450 451#if CONFIG_VFS_FUNNEL 452 thread_safe = (mp->mnt_vtable->vfc_vfsflags & VFC_VFSTHREADSAFE); 453 if (!thread_safe) { 454 funnel_state = thread_funnel_set(kernel_flock, TRUE); 455 } 456#endif /* CONFIG_VFS_FUNNEL */ 457 458 error = (*mp->mnt_op->vfs_setattr)(mp, vfa, ctx); 459 460#if CONFIG_VFS_FUNNEL 461 if (!thread_safe) { 462 (void) thread_funnel_set(kernel_flock, funnel_state); 463 } 464#endif /* CONFIG_VFS_FUNNEL */ 465 466 return(error); 467} 468 469int 470VFS_SYNC(mount_t mp, int flags, vfs_context_t ctx) 471{ 472 int error; 473#if CONFIG_VFS_FUNNEL 474 int thread_safe; 475 int funnel_state = 0; 476#endif /* CONFIG_VFS_FUNNEL */ 477 478 if ((mp == dead_mountp) || (mp->mnt_op->vfs_sync == 0)) 479 return(ENOTSUP); 480 481 if (ctx == NULL) { 482 ctx = vfs_context_current(); 483 } 484 485#if CONFIG_VFS_FUNNEL 486 thread_safe = (mp->mnt_vtable->vfc_vfsflags & VFC_VFSTHREADSAFE); 487 if (!thread_safe) { 488 funnel_state = thread_funnel_set(kernel_flock, TRUE); 489 } 490#endif /* CONFIG_VFS_FUNNEL */ 491 492 error = (*mp->mnt_op->vfs_sync)(mp, flags, ctx); 493 494#if CONFIG_VFS_FUNNEL 495 if (!thread_safe) { 496 (void) thread_funnel_set(kernel_flock, funnel_state); 497 } 498#endif /* CONFIG_VFS_FUNNEL */ 499 500 return(error); 501} 502 503int 504VFS_VGET(mount_t mp, ino64_t ino, struct vnode **vpp, vfs_context_t ctx) 505{ 506 int error; 507#if CONFIG_VFS_FUNNEL 508 int thread_safe; 509 int funnel_state = 0; 510#endif /* CONFIG_VFS_FUNNEL */ 511 512 if ((mp == dead_mountp) || (mp->mnt_op->vfs_vget == 0)) 513 return(ENOTSUP); 514 515 if (ctx == NULL) { 516 ctx = vfs_context_current(); 517 } 518 519#if CONFIG_VFS_FUNNEL 520 thread_safe = (mp->mnt_vtable->vfc_vfsflags & VFC_VFSTHREADSAFE); 521 if (!thread_safe) { 522 funnel_state = thread_funnel_set(kernel_flock, TRUE); 523 } 524#endif /* CONFIG_VFS_FUNNEL */ 525 526 error = (*mp->mnt_op->vfs_vget)(mp, ino, vpp, ctx); 527 528#if CONFIG_VFS_FUNNEL 529 if (!thread_safe) { 530 (void) thread_funnel_set(kernel_flock, funnel_state); 531 } 532#endif /* CONFIG_VFS_FUNNEL */ 533 534 return(error); 535} 536 537int 538VFS_FHTOVP(mount_t mp, int fhlen, unsigned char * fhp, vnode_t * vpp, vfs_context_t ctx) 539{ 540 int error; 541#if CONFIG_VFS_FUNNEL 542 int thread_safe; 543 int funnel_state = 0; 544#endif /* CONFIG_VFS_FUNNEL */ 545 546 if ((mp == dead_mountp) || (mp->mnt_op->vfs_fhtovp == 0)) 547 return(ENOTSUP); 548 549 if (ctx == NULL) { 550 ctx = vfs_context_current(); 551 } 552 553#if CONFIG_VFS_FUNNEL 554 thread_safe = (mp->mnt_vtable->vfc_vfsflags & VFC_VFSTHREADSAFE); 555 if (!thread_safe) { 556 funnel_state = thread_funnel_set(kernel_flock, TRUE); 557 } 558#endif /* CONFIG_VFS_FUNNEL */ 559 560 error = (*mp->mnt_op->vfs_fhtovp)(mp, fhlen, fhp, vpp, ctx); 561 562#if CONFIG_VFS_FUNNEL 563 if (!thread_safe) { 564 (void) thread_funnel_set(kernel_flock, funnel_state); 565 } 566#endif /* CONFIG_VFS_FUNNEL */ 567 568 return(error); 569} 570 571int 572VFS_VPTOFH(struct vnode * vp, int *fhlenp, unsigned char * fhp, vfs_context_t ctx) 573{ 574 int error; 575#if CONFIG_VFS_FUNNEL 576 int thread_safe; 577 int funnel_state = 0; 578#endif /* CONFIG_VFS_FUNNEL */ 579 580 if ((vp->v_mount == dead_mountp) || (vp->v_mount->mnt_op->vfs_vptofh == 0)) 581 return(ENOTSUP); 582 583 if (ctx == NULL) { 584 ctx = vfs_context_current(); 585 } 586 587#if CONFIG_VFS_FUNNEL 588 thread_safe = THREAD_SAFE_FS(vp); 589 if (!thread_safe) { 590 funnel_state = thread_funnel_set(kernel_flock, TRUE); 591 } 592#endif /* CONFIG_VFS_FUNNEL */ 593 594 error = (*vp->v_mount->mnt_op->vfs_vptofh)(vp, fhlenp, fhp, ctx); 595 596#if CONFIG_VFS_FUNNEL 597 if (!thread_safe) { 598 (void) thread_funnel_set(kernel_flock, funnel_state); 599 } 600#endif /* CONFIG_VFS_FUNNEL */ 601 602 return(error); 603} 604 605 606/* returns the cached throttle mask for the mount_t */ 607uint64_t 608vfs_throttle_mask(mount_t mp) 609{ 610 return(mp->mnt_throttle_mask); 611} 612 613/* returns a copy of vfs type name for the mount_t */ 614void 615vfs_name(mount_t mp, char * buffer) 616{ 617 strncpy(buffer, mp->mnt_vtable->vfc_name, MFSNAMELEN); 618} 619 620/* returns vfs type number for the mount_t */ 621int 622vfs_typenum(mount_t mp) 623{ 624 return(mp->mnt_vtable->vfc_typenum); 625} 626 627/* Safe to cast to "struct label*"; returns "void*" to limit dependence of mount.h on security headers. */ 628void* 629vfs_mntlabel(mount_t mp) 630{ 631 return (void*)mp->mnt_mntlabel; 632} 633 634/* returns command modifier flags of mount_t ie. MNT_CMDFLAGS */ 635uint64_t 636vfs_flags(mount_t mp) 637{ 638 return((uint64_t)(mp->mnt_flag & (MNT_CMDFLAGS | MNT_VISFLAGMASK))); 639} 640 641/* set any of the command modifier flags(MNT_CMDFLAGS) in mount_t */ 642void 643vfs_setflags(mount_t mp, uint64_t flags) 644{ 645 uint32_t lflags = (uint32_t)(flags & (MNT_CMDFLAGS | MNT_VISFLAGMASK)); 646 647 mount_lock(mp); 648 mp->mnt_flag |= lflags; 649 mount_unlock(mp); 650} 651 652/* clear any of the command modifier flags(MNT_CMDFLAGS) in mount_t */ 653void 654vfs_clearflags(mount_t mp , uint64_t flags) 655{ 656 uint32_t lflags = (uint32_t)(flags & (MNT_CMDFLAGS | MNT_VISFLAGMASK)); 657 658 mount_lock(mp); 659 mp->mnt_flag &= ~lflags; 660 mount_unlock(mp); 661} 662 663/* Is the mount_t ronly and upgrade read/write requested? */ 664int 665vfs_iswriteupgrade(mount_t mp) /* ronly && MNTK_WANTRDWR */ 666{ 667 return ((mp->mnt_flag & MNT_RDONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)); 668} 669 670 671/* Is the mount_t mounted ronly */ 672int 673vfs_isrdonly(mount_t mp) 674{ 675 return (mp->mnt_flag & MNT_RDONLY); 676} 677 678/* Is the mount_t mounted for filesystem synchronous writes? */ 679int 680vfs_issynchronous(mount_t mp) 681{ 682 return (mp->mnt_flag & MNT_SYNCHRONOUS); 683} 684 685/* Is the mount_t mounted read/write? */ 686int 687vfs_isrdwr(mount_t mp) 688{ 689 return ((mp->mnt_flag & MNT_RDONLY) == 0); 690} 691 692 693/* Is mount_t marked for update (ie MNT_UPDATE) */ 694int 695vfs_isupdate(mount_t mp) 696{ 697 return (mp->mnt_flag & MNT_UPDATE); 698} 699 700 701/* Is mount_t marked for reload (ie MNT_RELOAD) */ 702int 703vfs_isreload(mount_t mp) 704{ 705 return ((mp->mnt_flag & MNT_UPDATE) && (mp->mnt_flag & MNT_RELOAD)); 706} 707 708/* Is mount_t marked for forced unmount (ie MNT_FORCE or MNTK_FRCUNMOUNT) */ 709int 710vfs_isforce(mount_t mp) 711{ 712 if ((mp->mnt_lflag & MNT_LFORCE) || (mp->mnt_kern_flag & MNTK_FRCUNMOUNT)) 713 return(1); 714 else 715 return(0); 716} 717 718int 719vfs_isunmount(mount_t mp) 720{ 721 if ((mp->mnt_lflag & MNT_LUNMOUNT)) { 722 return 1; 723 } else { 724 return 0; 725 } 726} 727 728int 729vfs_64bitready(mount_t mp) 730{ 731 if ((mp->mnt_vtable->vfc_vfsflags & VFC_VFS64BITREADY)) 732 return(1); 733 else 734 return(0); 735} 736 737 738int 739vfs_authcache_ttl(mount_t mp) 740{ 741 if ( (mp->mnt_kern_flag & (MNTK_AUTH_OPAQUE | MNTK_AUTH_CACHE_TTL)) ) 742 return (mp->mnt_authcache_ttl); 743 else 744 return (CACHED_RIGHT_INFINITE_TTL); 745} 746 747void 748vfs_setauthcache_ttl(mount_t mp, int ttl) 749{ 750 mount_lock(mp); 751 mp->mnt_kern_flag |= MNTK_AUTH_CACHE_TTL; 752 mp->mnt_authcache_ttl = ttl; 753 mount_unlock(mp); 754} 755 756void 757vfs_clearauthcache_ttl(mount_t mp) 758{ 759 mount_lock(mp); 760 mp->mnt_kern_flag &= ~MNTK_AUTH_CACHE_TTL; 761 /* 762 * back to the default TTL value in case 763 * MNTK_AUTH_OPAQUE is set on this mount 764 */ 765 mp->mnt_authcache_ttl = CACHED_LOOKUP_RIGHT_TTL; 766 mount_unlock(mp); 767} 768 769void 770vfs_markdependency(mount_t mp) 771{ 772 proc_t p = current_proc(); 773 mount_lock(mp); 774 mp->mnt_dependent_process = p; 775 mp->mnt_dependent_pid = proc_pid(p); 776 mount_unlock(mp); 777} 778 779 780int 781vfs_authopaque(mount_t mp) 782{ 783 if ((mp->mnt_kern_flag & MNTK_AUTH_OPAQUE)) 784 return(1); 785 else 786 return(0); 787} 788 789int 790vfs_authopaqueaccess(mount_t mp) 791{ 792 if ((mp->mnt_kern_flag & MNTK_AUTH_OPAQUE_ACCESS)) 793 return(1); 794 else 795 return(0); 796} 797 798void 799vfs_setauthopaque(mount_t mp) 800{ 801 mount_lock(mp); 802 mp->mnt_kern_flag |= MNTK_AUTH_OPAQUE; 803 mount_unlock(mp); 804} 805 806void 807vfs_setauthopaqueaccess(mount_t mp) 808{ 809 mount_lock(mp); 810 mp->mnt_kern_flag |= MNTK_AUTH_OPAQUE_ACCESS; 811 mount_unlock(mp); 812} 813 814void 815vfs_clearauthopaque(mount_t mp) 816{ 817 mount_lock(mp); 818 mp->mnt_kern_flag &= ~MNTK_AUTH_OPAQUE; 819 mount_unlock(mp); 820} 821 822void 823vfs_clearauthopaqueaccess(mount_t mp) 824{ 825 mount_lock(mp); 826 mp->mnt_kern_flag &= ~MNTK_AUTH_OPAQUE_ACCESS; 827 mount_unlock(mp); 828} 829 830void 831vfs_setextendedsecurity(mount_t mp) 832{ 833 mount_lock(mp); 834 mp->mnt_kern_flag |= MNTK_EXTENDED_SECURITY; 835 mount_unlock(mp); 836} 837 838void 839vfs_clearextendedsecurity(mount_t mp) 840{ 841 mount_lock(mp); 842 mp->mnt_kern_flag &= ~MNTK_EXTENDED_SECURITY; 843 mount_unlock(mp); 844} 845 846int 847vfs_extendedsecurity(mount_t mp) 848{ 849 return(mp->mnt_kern_flag & MNTK_EXTENDED_SECURITY); 850} 851 852/* returns the max size of short symlink in this mount_t */ 853uint32_t 854vfs_maxsymlen(mount_t mp) 855{ 856 return(mp->mnt_maxsymlinklen); 857} 858 859/* set max size of short symlink on mount_t */ 860void 861vfs_setmaxsymlen(mount_t mp, uint32_t symlen) 862{ 863 mp->mnt_maxsymlinklen = symlen; 864} 865 866/* return a pointer to the RO vfs_statfs associated with mount_t */ 867struct vfsstatfs * 868vfs_statfs(mount_t mp) 869{ 870 return(&mp->mnt_vfsstat); 871} 872 873int 874vfs_getattr(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx) 875{ 876 int error; 877 878 if ((error = VFS_GETATTR(mp, vfa, ctx)) != 0) 879 return(error); 880 881 /* 882 * If we have a filesystem create time, use it to default some others. 883 */ 884 if (VFSATTR_IS_SUPPORTED(vfa, f_create_time)) { 885 if (VFSATTR_IS_ACTIVE(vfa, f_modify_time) && !VFSATTR_IS_SUPPORTED(vfa, f_modify_time)) 886 VFSATTR_RETURN(vfa, f_modify_time, vfa->f_create_time); 887 } 888 889 return(0); 890} 891 892int 893vfs_setattr(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx) 894{ 895 int error; 896 897 if (vfs_isrdonly(mp)) 898 return EROFS; 899 900 error = VFS_SETATTR(mp, vfa, ctx); 901 902 /* 903 * If we had alternate ways of setting vfs attributes, we'd 904 * fall back here. 905 */ 906 907 return error; 908} 909 910/* return the private data handle stored in mount_t */ 911void * 912vfs_fsprivate(mount_t mp) 913{ 914 return(mp->mnt_data); 915} 916 917/* set the private data handle in mount_t */ 918void 919vfs_setfsprivate(mount_t mp, void *mntdata) 920{ 921 mount_lock(mp); 922 mp->mnt_data = mntdata; 923 mount_unlock(mp); 924} 925 926 927/* 928 * return the block size of the underlying 929 * device associated with mount_t 930 */ 931int 932vfs_devblocksize(mount_t mp) { 933 934 return(mp->mnt_devblocksize); 935} 936 937/* 938 * Returns vnode with an iocount that must be released with vnode_put() 939 */ 940vnode_t 941vfs_vnodecovered(mount_t mp) 942{ 943 vnode_t vp = mp->mnt_vnodecovered; 944 if ((vp == NULL) || (vnode_getwithref(vp) != 0)) { 945 return NULL; 946 } else { 947 return vp; 948 } 949} 950 951/* 952 * Returns device vnode backing a mountpoint with an iocount (if valid vnode exists). 953 * The iocount must be released with vnode_put(). Note that this KPI is subtle 954 * with respect to the validity of using this device vnode for anything substantial 955 * (which is discouraged). If commands are sent to the device driver without 956 * taking proper steps to ensure that the device is still open, chaos may ensue. 957 * Similarly, this routine should only be called if there is some guarantee that 958 * the mount itself is still valid. 959 */ 960vnode_t 961vfs_devvp(mount_t mp) 962{ 963 vnode_t vp = mp->mnt_devvp; 964 965 if ((vp != NULLVP) && (vnode_get(vp) == 0)) { 966 return vp; 967 } 968 969 return NULLVP; 970} 971 972/* 973 * return the io attributes associated with mount_t 974 */ 975void 976vfs_ioattr(mount_t mp, struct vfsioattr *ioattrp) 977{ 978 if (mp == NULL) { 979 ioattrp->io_maxreadcnt = MAXPHYS; 980 ioattrp->io_maxwritecnt = MAXPHYS; 981 ioattrp->io_segreadcnt = 32; 982 ioattrp->io_segwritecnt = 32; 983 ioattrp->io_maxsegreadsize = MAXPHYS; 984 ioattrp->io_maxsegwritesize = MAXPHYS; 985 ioattrp->io_devblocksize = DEV_BSIZE; 986 ioattrp->io_flags = 0; 987 } else { 988 ioattrp->io_maxreadcnt = mp->mnt_maxreadcnt; 989 ioattrp->io_maxwritecnt = mp->mnt_maxwritecnt; 990 ioattrp->io_segreadcnt = mp->mnt_segreadcnt; 991 ioattrp->io_segwritecnt = mp->mnt_segwritecnt; 992 ioattrp->io_maxsegreadsize = mp->mnt_maxsegreadsize; 993 ioattrp->io_maxsegwritesize = mp->mnt_maxsegwritesize; 994 ioattrp->io_devblocksize = mp->mnt_devblocksize; 995 ioattrp->io_flags = mp->mnt_ioflags; 996 } 997 ioattrp->io_reserved[0] = NULL; 998 ioattrp->io_reserved[1] = NULL; 999} 1000 1001 1002/* 1003 * set the IO attributes associated with mount_t 1004 */ 1005void 1006vfs_setioattr(mount_t mp, struct vfsioattr * ioattrp) 1007{ 1008 if (mp == NULL) 1009 return; 1010 mp->mnt_maxreadcnt = ioattrp->io_maxreadcnt; 1011 mp->mnt_maxwritecnt = ioattrp->io_maxwritecnt; 1012 mp->mnt_segreadcnt = ioattrp->io_segreadcnt; 1013 mp->mnt_segwritecnt = ioattrp->io_segwritecnt; 1014 mp->mnt_maxsegreadsize = ioattrp->io_maxsegreadsize; 1015 mp->mnt_maxsegwritesize = ioattrp->io_maxsegwritesize; 1016 mp->mnt_devblocksize = ioattrp->io_devblocksize; 1017 mp->mnt_ioflags = ioattrp->io_flags; 1018} 1019 1020/* 1021 * Add a new filesystem into the kernel specified in passed in 1022 * vfstable structure. It fills in the vnode 1023 * dispatch vector that is to be passed to when vnodes are created. 1024 * It returns a handle which is to be used to when the FS is to be removed 1025 */ 1026typedef int (*PFI)(void *); 1027extern int vfs_opv_numops; 1028errno_t 1029vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t * handle) 1030{ 1031 struct vfstable *newvfstbl = NULL; 1032 int i,j; 1033 int (***opv_desc_vector_p)(void *); 1034 int (**opv_desc_vector)(void *); 1035 struct vnodeopv_entry_desc *opve_descp; 1036 int desccount; 1037 int descsize; 1038 PFI *descptr; 1039 1040 /* 1041 * This routine is responsible for all the initialization that would 1042 * ordinarily be done as part of the system startup; 1043 */ 1044 1045 if (vfe == (struct vfs_fsentry *)0) 1046 return(EINVAL); 1047 1048 desccount = vfe->vfe_vopcnt; 1049 if ((desccount <=0) || ((desccount > 8)) || (vfe->vfe_vfsops == (struct vfsops *)NULL) 1050 || (vfe->vfe_opvdescs == (struct vnodeopv_desc **)NULL)) 1051 return(EINVAL); 1052 1053#if !CONFIG_VFS_FUNNEL 1054 /* Non-threadsafe filesystems are not supported e.g. on K64 & iOS */ 1055 if ((vfe->vfe_flags & (VFS_TBLTHREADSAFE | VFS_TBLFSNODELOCK)) == 0) { 1056 return (EINVAL); 1057 } 1058#endif /* !CONFIG_VFS_FUNNEL */ 1059 1060 MALLOC(newvfstbl, void *, sizeof(struct vfstable), M_TEMP, 1061 M_WAITOK); 1062 bzero(newvfstbl, sizeof(struct vfstable)); 1063 newvfstbl->vfc_vfsops = vfe->vfe_vfsops; 1064 strncpy(&newvfstbl->vfc_name[0], vfe->vfe_fsname, MFSNAMELEN); 1065 if ((vfe->vfe_flags & VFS_TBLNOTYPENUM)) 1066 newvfstbl->vfc_typenum = maxvfsconf++; 1067 else 1068 newvfstbl->vfc_typenum = vfe->vfe_fstypenum; 1069 1070 newvfstbl->vfc_refcount = 0; 1071 newvfstbl->vfc_flags = 0; 1072 newvfstbl->vfc_mountroot = NULL; 1073 newvfstbl->vfc_next = NULL; 1074 newvfstbl->vfc_vfsflags = 0; 1075 if (vfe->vfe_flags & VFS_TBL64BITREADY) 1076 newvfstbl->vfc_vfsflags |= VFC_VFS64BITREADY; 1077 if (vfe->vfe_flags & VFS_TBLVNOP_PAGEINV2) 1078 newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_PAGEINV2; 1079 if (vfe->vfe_flags & VFS_TBLVNOP_PAGEOUTV2) 1080 newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_PAGEOUTV2; 1081#if CONFIG_VFS_FUNNEL 1082 if (vfe->vfe_flags & VFS_TBLTHREADSAFE) 1083 newvfstbl->vfc_vfsflags |= VFC_VFSTHREADSAFE; 1084 if (vfe->vfe_flags & VFS_TBLFSNODELOCK) 1085 newvfstbl->vfc_vfsflags |= VFC_VFSTHREADSAFE; 1086#endif /* CONFIG_VFS_FUNNEL */ 1087 if ((vfe->vfe_flags & VFS_TBLLOCALVOL) == VFS_TBLLOCALVOL) 1088 newvfstbl->vfc_flags |= MNT_LOCAL; 1089 if ((vfe->vfe_flags & VFS_TBLLOCALVOL) && (vfe->vfe_flags & VFS_TBLGENERICMNTARGS) == 0) 1090 newvfstbl->vfc_vfsflags |= VFC_VFSLOCALARGS; 1091 else 1092 newvfstbl->vfc_vfsflags |= VFC_VFSGENERICARGS; 1093 1094 if (vfe->vfe_flags & VFS_TBLNATIVEXATTR) 1095 newvfstbl->vfc_vfsflags |= VFC_VFSNATIVEXATTR; 1096 if (vfe->vfe_flags & VFS_TBLUNMOUNT_PREFLIGHT) 1097 newvfstbl->vfc_vfsflags |= VFC_VFSPREFLIGHT; 1098 if (vfe->vfe_flags & VFS_TBLREADDIR_EXTENDED) 1099 newvfstbl->vfc_vfsflags |= VFC_VFSREADDIR_EXTENDED; 1100 if (vfe->vfe_flags & VFS_TBLNOMACLABEL) 1101 newvfstbl->vfc_vfsflags |= VFC_VFSNOMACLABEL; 1102 1103 /* 1104 * Allocate and init the vectors. 1105 * Also handle backwards compatibility. 1106 * 1107 * We allocate one large block to hold all <desccount> 1108 * vnode operation vectors stored contiguously. 1109 */ 1110 /* XXX - shouldn't be M_TEMP */ 1111 1112 descsize = desccount * vfs_opv_numops * sizeof(PFI); 1113 MALLOC(descptr, PFI *, descsize, 1114 M_TEMP, M_WAITOK); 1115 bzero(descptr, descsize); 1116 1117 newvfstbl->vfc_descptr = descptr; 1118 newvfstbl->vfc_descsize = descsize; 1119 1120 1121 for (i= 0; i< desccount; i++ ) { 1122 opv_desc_vector_p = vfe->vfe_opvdescs[i]->opv_desc_vector_p; 1123 /* 1124 * Fill in the caller's pointer to the start of the i'th vector. 1125 * They'll need to supply it when calling vnode_create. 1126 */ 1127 opv_desc_vector = descptr + i * vfs_opv_numops; 1128 *opv_desc_vector_p = opv_desc_vector; 1129 1130 for (j = 0; vfe->vfe_opvdescs[i]->opv_desc_ops[j].opve_op; j++) { 1131 opve_descp = &(vfe->vfe_opvdescs[i]->opv_desc_ops[j]); 1132 1133 /* 1134 * Sanity check: is this operation listed 1135 * in the list of operations? We check this 1136 * by seeing if its offset is zero. Since 1137 * the default routine should always be listed 1138 * first, it should be the only one with a zero 1139 * offset. Any other operation with a zero 1140 * offset is probably not listed in 1141 * vfs_op_descs, and so is probably an error. 1142 * 1143 * A panic here means the layer programmer 1144 * has committed the all-too common bug 1145 * of adding a new operation to the layer's 1146 * list of vnode operations but 1147 * not adding the operation to the system-wide 1148 * list of supported operations. 1149 */ 1150 if (opve_descp->opve_op->vdesc_offset == 0 && 1151 opve_descp->opve_op->vdesc_offset != VOFFSET(vnop_default)) { 1152 printf("vfs_fsadd: operation %s not listed in %s.\n", 1153 opve_descp->opve_op->vdesc_name, 1154 "vfs_op_descs"); 1155 panic("vfs_fsadd: bad operation"); 1156 } 1157 /* 1158 * Fill in this entry. 1159 */ 1160 opv_desc_vector[opve_descp->opve_op->vdesc_offset] = 1161 opve_descp->opve_impl; 1162 } 1163 1164 1165 /* 1166 * Finally, go back and replace unfilled routines 1167 * with their default. (Sigh, an O(n^3) algorithm. I 1168 * could make it better, but that'd be work, and n is small.) 1169 */ 1170 opv_desc_vector_p = vfe->vfe_opvdescs[i]->opv_desc_vector_p; 1171 1172 /* 1173 * Force every operations vector to have a default routine. 1174 */ 1175 opv_desc_vector = *opv_desc_vector_p; 1176 if (opv_desc_vector[VOFFSET(vnop_default)] == NULL) 1177 panic("vfs_fsadd: operation vector without default routine."); 1178 for (j = 0; j < vfs_opv_numops; j++) 1179 if (opv_desc_vector[j] == NULL) 1180 opv_desc_vector[j] = 1181 opv_desc_vector[VOFFSET(vnop_default)]; 1182 1183 } /* end of each vnodeopv_desc parsing */ 1184 1185 1186 1187 *handle = vfstable_add(newvfstbl); 1188 1189 if (newvfstbl->vfc_typenum <= maxvfsconf ) 1190 maxvfsconf = newvfstbl->vfc_typenum + 1; 1191 1192 if (newvfstbl->vfc_vfsops->vfs_init) { 1193 struct vfsconf vfsc; 1194 bzero(&vfsc, sizeof(struct vfsconf)); 1195 vfsc.vfc_reserved1 = 0; 1196 bcopy((*handle)->vfc_name, vfsc.vfc_name, sizeof(vfsc.vfc_name)); 1197 vfsc.vfc_typenum = (*handle)->vfc_typenum; 1198 vfsc.vfc_refcount = (*handle)->vfc_refcount; 1199 vfsc.vfc_flags = (*handle)->vfc_flags; 1200 vfsc.vfc_reserved2 = 0; 1201 vfsc.vfc_reserved3 = 0; 1202 1203 (*newvfstbl->vfc_vfsops->vfs_init)(&vfsc); 1204 } 1205 1206 FREE(newvfstbl, M_TEMP); 1207 1208 return(0); 1209} 1210 1211/* 1212 * Removes the filesystem from kernel. 1213 * The argument passed in is the handle that was given when 1214 * file system was added 1215 */ 1216errno_t 1217vfs_fsremove(vfstable_t handle) 1218{ 1219 struct vfstable * vfstbl = (struct vfstable *)handle; 1220 void *old_desc = NULL; 1221 errno_t err; 1222 1223 /* Preflight check for any mounts */ 1224 mount_list_lock(); 1225 if ( vfstbl->vfc_refcount != 0 ) { 1226 mount_list_unlock(); 1227 return EBUSY; 1228 } 1229 1230 /* 1231 * save the old descriptor; the free cannot occur unconditionally, 1232 * since vfstable_del() may fail. 1233 */ 1234 if (vfstbl->vfc_descptr && vfstbl->vfc_descsize) { 1235 old_desc = vfstbl->vfc_descptr; 1236 } 1237 err = vfstable_del(vfstbl); 1238 1239 mount_list_unlock(); 1240 1241 /* free the descriptor if the delete was successful */ 1242 if (err == 0 && old_desc) { 1243 FREE(old_desc, M_TEMP); 1244 } 1245 1246 return(err); 1247} 1248 1249int 1250vfs_context_pid(vfs_context_t ctx) 1251{ 1252 return (proc_pid(vfs_context_proc(ctx))); 1253} 1254 1255int 1256vfs_context_suser(vfs_context_t ctx) 1257{ 1258 return (suser(ctx->vc_ucred, NULL)); 1259} 1260 1261/* 1262 * Return bit field of signals posted to all threads in the context's process. 1263 * 1264 * XXX Signals should be tied to threads, not processes, for most uses of this 1265 * XXX call. 1266 */ 1267int 1268vfs_context_issignal(vfs_context_t ctx, sigset_t mask) 1269{ 1270 proc_t p = vfs_context_proc(ctx); 1271 if (p) 1272 return(proc_pendingsignals(p, mask)); 1273 return(0); 1274} 1275 1276int 1277vfs_context_is64bit(vfs_context_t ctx) 1278{ 1279 proc_t proc = vfs_context_proc(ctx); 1280 1281 if (proc) 1282 return(proc_is64bit(proc)); 1283 return(0); 1284} 1285 1286 1287/* 1288 * vfs_context_proc 1289 * 1290 * Description: Given a vfs_context_t, return the proc_t associated with it. 1291 * 1292 * Parameters: vfs_context_t The context to use 1293 * 1294 * Returns: proc_t The process for this context 1295 * 1296 * Notes: This function will return the current_proc() if any of the 1297 * following conditions are true: 1298 * 1299 * o The supplied context pointer is NULL 1300 * o There is no Mach thread associated with the context 1301 * o There is no Mach task associated with the Mach thread 1302 * o There is no proc_t associated with the Mach task 1303 * o The proc_t has no per process open file table 1304 * o The proc_t is post-vfork() 1305 * 1306 * This causes this function to return a value matching as 1307 * closely as possible the previous behaviour, while at the 1308 * same time avoiding the task lending that results from vfork() 1309 */ 1310proc_t 1311vfs_context_proc(vfs_context_t ctx) 1312{ 1313 proc_t proc = NULL; 1314 1315 if (ctx != NULL && ctx->vc_thread != NULL) 1316 proc = (proc_t)get_bsdthreadtask_info(ctx->vc_thread); 1317 if (proc != NULL && (proc->p_fd == NULL || (proc->p_lflag & P_LVFORK))) 1318 proc = NULL; 1319 1320 return(proc == NULL ? current_proc() : proc); 1321} 1322 1323/* 1324 * vfs_context_get_special_port 1325 * 1326 * Description: Return the requested special port from the task associated 1327 * with the given context. 1328 * 1329 * Parameters: vfs_context_t The context to use 1330 * int Index of special port 1331 * ipc_port_t * Pointer to returned port 1332 * 1333 * Returns: kern_return_t see task_get_special_port() 1334 */ 1335kern_return_t 1336vfs_context_get_special_port(vfs_context_t ctx, int which, ipc_port_t *portp) 1337{ 1338 task_t task = NULL; 1339 1340 if (ctx != NULL && ctx->vc_thread != NULL) 1341 task = get_threadtask(ctx->vc_thread); 1342 1343 return task_get_special_port(task, which, portp); 1344} 1345 1346/* 1347 * vfs_context_set_special_port 1348 * 1349 * Description: Set the requested special port in the task associated 1350 * with the given context. 1351 * 1352 * Parameters: vfs_context_t The context to use 1353 * int Index of special port 1354 * ipc_port_t New special port 1355 * 1356 * Returns: kern_return_t see task_set_special_port() 1357 */ 1358kern_return_t 1359vfs_context_set_special_port(vfs_context_t ctx, int which, ipc_port_t port) 1360{ 1361 task_t task = NULL; 1362 1363 if (ctx != NULL && ctx->vc_thread != NULL) 1364 task = get_threadtask(ctx->vc_thread); 1365 1366 return task_set_special_port(task, which, port); 1367} 1368 1369/* 1370 * vfs_context_thread 1371 * 1372 * Description: Return the Mach thread associated with a vfs_context_t 1373 * 1374 * Parameters: vfs_context_t The context to use 1375 * 1376 * Returns: thread_t The thread for this context, or 1377 * NULL, if there is not one. 1378 * 1379 * Notes: NULL thread_t's are legal, but discouraged. They occur only 1380 * as a result of a static vfs_context_t declaration in a function 1381 * and will result in this function returning NULL. 1382 * 1383 * This is intentional; this function should NOT return the 1384 * current_thread() in this case. 1385 */ 1386thread_t 1387vfs_context_thread(vfs_context_t ctx) 1388{ 1389 return(ctx->vc_thread); 1390} 1391 1392 1393/* 1394 * vfs_context_cwd 1395 * 1396 * Description: Returns a reference on the vnode for the current working 1397 * directory for the supplied context 1398 * 1399 * Parameters: vfs_context_t The context to use 1400 * 1401 * Returns: vnode_t The current working directory 1402 * for this context 1403 * 1404 * Notes: The function first attempts to obtain the current directory 1405 * from the thread, and if it is not present there, falls back 1406 * to obtaining it from the process instead. If it can't be 1407 * obtained from either place, we return NULLVP. 1408 */ 1409vnode_t 1410vfs_context_cwd(vfs_context_t ctx) 1411{ 1412 vnode_t cwd = NULLVP; 1413 1414 if(ctx != NULL && ctx->vc_thread != NULL) { 1415 uthread_t uth = get_bsdthread_info(ctx->vc_thread); 1416 proc_t proc; 1417 1418 /* 1419 * Get the cwd from the thread; if there isn't one, get it 1420 * from the process, instead. 1421 */ 1422 if ((cwd = uth->uu_cdir) == NULLVP && 1423 (proc = (proc_t)get_bsdthreadtask_info(ctx->vc_thread)) != NULL && 1424 proc->p_fd != NULL) 1425 cwd = proc->p_fd->fd_cdir; 1426 } 1427 1428 return(cwd); 1429} 1430 1431/* 1432 * vfs_context_create 1433 * 1434 * Description: Allocate and initialize a new context. 1435 * 1436 * Parameters: vfs_context_t: Context to copy, or NULL for new 1437 * 1438 * Returns: Pointer to new context 1439 * 1440 * Notes: Copy cred and thread from argument, if available; else 1441 * initialize with current thread and new cred. Returns 1442 * with a reference held on the credential. 1443 */ 1444vfs_context_t 1445vfs_context_create(vfs_context_t ctx) 1446{ 1447 vfs_context_t newcontext; 1448 1449 newcontext = (vfs_context_t)kalloc(sizeof(struct vfs_context)); 1450 1451 if (newcontext) { 1452 kauth_cred_t safecred; 1453 if (ctx) { 1454 newcontext->vc_thread = ctx->vc_thread; 1455 safecred = ctx->vc_ucred; 1456 } else { 1457 newcontext->vc_thread = current_thread(); 1458 safecred = kauth_cred_get(); 1459 } 1460 if (IS_VALID_CRED(safecred)) 1461 kauth_cred_ref(safecred); 1462 newcontext->vc_ucred = safecred; 1463 return(newcontext); 1464 } 1465 return(NULL); 1466} 1467 1468 1469vfs_context_t 1470vfs_context_current(void) 1471{ 1472 vfs_context_t ctx = NULL; 1473 volatile uthread_t ut = (uthread_t)get_bsdthread_info(current_thread()); 1474 1475 if (ut != NULL ) { 1476 if (ut->uu_context.vc_ucred != NULL) { 1477 ctx = &ut->uu_context; 1478 } 1479 } 1480 1481 return(ctx == NULL ? vfs_context_kernel() : ctx); 1482} 1483 1484 1485/* 1486 * XXX Do not ask 1487 * 1488 * Dangerous hack - adopt the first kernel thread as the current thread, to 1489 * get to the vfs_context_t in the uthread associated with a kernel thread. 1490 * This is used by UDF to make the call into IOCDMediaBSDClient, 1491 * IOBDMediaBSDClient, and IODVDMediaBSDClient to determine whether the 1492 * ioctl() is being called from kernel or user space (and all this because 1493 * we do not pass threads into our ioctl()'s, instead of processes). 1494 * 1495 * This is also used by imageboot_setup(), called early from bsd_init() after 1496 * kernproc has been given a credential. 1497 * 1498 * Note: The use of proc_thread() here is a convenience to avoid inclusion 1499 * of many Mach headers to do the reference directly rather than indirectly; 1500 * we will need to forego this convenience when we reture proc_thread(). 1501 */ 1502static struct vfs_context kerncontext; 1503vfs_context_t 1504vfs_context_kernel(void) 1505{ 1506 if (kerncontext.vc_ucred == NOCRED) 1507 kerncontext.vc_ucred = kernproc->p_ucred; 1508 if (kerncontext.vc_thread == NULL) 1509 kerncontext.vc_thread = proc_thread(kernproc); 1510 1511 return(&kerncontext); 1512} 1513 1514 1515int 1516vfs_context_rele(vfs_context_t ctx) 1517{ 1518 if (ctx) { 1519 if (IS_VALID_CRED(ctx->vc_ucred)) 1520 kauth_cred_unref(&ctx->vc_ucred); 1521 kfree(ctx, sizeof(struct vfs_context)); 1522 } 1523 return(0); 1524} 1525 1526 1527kauth_cred_t 1528vfs_context_ucred(vfs_context_t ctx) 1529{ 1530 return (ctx->vc_ucred); 1531} 1532 1533/* 1534 * Return true if the context is owned by the superuser. 1535 */ 1536int 1537vfs_context_issuser(vfs_context_t ctx) 1538{ 1539 return(kauth_cred_issuser(vfs_context_ucred(ctx))); 1540} 1541 1542/* 1543 * Given a context, for all fields of vfs_context_t which 1544 * are not held with a reference, set those fields to the 1545 * values for the current execution context. Currently, this 1546 * just means the vc_thread. 1547 * 1548 * Returns: 0 for success, nonzero for failure 1549 * 1550 * The intended use is: 1551 * 1. vfs_context_create() gets the caller a context 1552 * 2. vfs_context_bind() sets the unrefcounted data 1553 * 3. vfs_context_rele() releases the context 1554 * 1555 */ 1556int 1557vfs_context_bind(vfs_context_t ctx) 1558{ 1559 ctx->vc_thread = current_thread(); 1560 return 0; 1561} 1562 1563/* XXXXXXXXXXXXXX VNODE KAPIS XXXXXXXXXXXXXXXXXXXXXXXXX */ 1564 1565 1566/* 1567 * Convert between vnode types and inode formats (since POSIX.1 1568 * defines mode word of stat structure in terms of inode formats). 1569 */ 1570enum vtype 1571vnode_iftovt(int mode) 1572{ 1573 return(iftovt_tab[((mode) & S_IFMT) >> 12]); 1574} 1575 1576int 1577vnode_vttoif(enum vtype indx) 1578{ 1579 return(vttoif_tab[(int)(indx)]); 1580} 1581 1582int 1583vnode_makeimode(int indx, int mode) 1584{ 1585 return (int)(VTTOIF(indx) | (mode)); 1586} 1587 1588 1589/* 1590 * vnode manipulation functions. 1591 */ 1592 1593/* returns system root vnode iocount; It should be released using vnode_put() */ 1594vnode_t 1595vfs_rootvnode(void) 1596{ 1597 int error; 1598 1599 error = vnode_get(rootvnode); 1600 if (error) 1601 return ((vnode_t)0); 1602 else 1603 return rootvnode; 1604} 1605 1606 1607uint32_t 1608vnode_vid(vnode_t vp) 1609{ 1610 return ((uint32_t)(vp->v_id)); 1611} 1612 1613mount_t 1614vnode_mount(vnode_t vp) 1615{ 1616 return (vp->v_mount); 1617} 1618 1619mount_t 1620vnode_mountedhere(vnode_t vp) 1621{ 1622 mount_t mp; 1623 1624 if ((vp->v_type == VDIR) && ((mp = vp->v_mountedhere) != NULL) && 1625 (mp->mnt_vnodecovered == vp)) 1626 return (mp); 1627 else 1628 return (mount_t)NULL; 1629} 1630 1631/* returns vnode type of vnode_t */ 1632enum vtype 1633vnode_vtype(vnode_t vp) 1634{ 1635 return (vp->v_type); 1636} 1637 1638/* returns FS specific node saved in vnode */ 1639void * 1640vnode_fsnode(vnode_t vp) 1641{ 1642 return (vp->v_data); 1643} 1644 1645void 1646vnode_clearfsnode(vnode_t vp) 1647{ 1648 vp->v_data = NULL; 1649} 1650 1651dev_t 1652vnode_specrdev(vnode_t vp) 1653{ 1654 return(vp->v_rdev); 1655} 1656 1657 1658/* Accessor functions */ 1659/* is vnode_t a root vnode */ 1660int 1661vnode_isvroot(vnode_t vp) 1662{ 1663 return ((vp->v_flag & VROOT)? 1 : 0); 1664} 1665 1666/* is vnode_t a system vnode */ 1667int 1668vnode_issystem(vnode_t vp) 1669{ 1670 return ((vp->v_flag & VSYSTEM)? 1 : 0); 1671} 1672 1673/* is vnode_t a swap file vnode */ 1674int 1675vnode_isswap(vnode_t vp) 1676{ 1677 return ((vp->v_flag & VSWAP)? 1 : 0); 1678} 1679 1680/* is vnode_t a tty */ 1681int 1682vnode_istty(vnode_t vp) 1683{ 1684 return ((vp->v_flag & VISTTY) ? 1 : 0); 1685} 1686 1687/* if vnode_t mount operation in progress */ 1688int 1689vnode_ismount(vnode_t vp) 1690{ 1691 return ((vp->v_flag & VMOUNT)? 1 : 0); 1692} 1693 1694/* is this vnode under recyle now */ 1695int 1696vnode_isrecycled(vnode_t vp) 1697{ 1698 int ret; 1699 1700 vnode_lock_spin(vp); 1701 ret = (vp->v_lflag & (VL_TERMINATE|VL_DEAD))? 1 : 0; 1702 vnode_unlock(vp); 1703 return(ret); 1704} 1705 1706/* vnode was created by background task requesting rapid aging 1707 and has not since been referenced by a normal task */ 1708int 1709vnode_israge(vnode_t vp) 1710{ 1711 return ((vp->v_flag & VRAGE)? 1 : 0); 1712} 1713 1714int 1715vnode_needssnapshots(vnode_t vp) 1716{ 1717 return ((vp->v_flag & VNEEDSSNAPSHOT)? 1 : 0); 1718} 1719 1720 1721/* Check the process/thread to see if we should skip atime updates */ 1722int 1723vfs_ctx_skipatime (vfs_context_t ctx) { 1724 struct uthread *ut; 1725 proc_t proc; 1726 thread_t thr; 1727 1728 proc = vfs_context_proc(ctx); 1729 thr = vfs_context_thread (ctx); 1730 1731 /* Validate pointers in case we were invoked via a kernel context */ 1732 if (thr && proc) { 1733 ut = get_bsdthread_info (thr); 1734 1735 if (proc->p_lflag & P_LRAGE_VNODES) { 1736 return 1; 1737 } 1738 1739 if (ut) { 1740 if (ut->uu_flag & UT_RAGE_VNODES) { 1741 return 1; 1742 } 1743 } 1744 } 1745 return 0; 1746} 1747 1748/* is vnode_t marked to not keep data cached once it's been consumed */ 1749int 1750vnode_isnocache(vnode_t vp) 1751{ 1752 return ((vp->v_flag & VNOCACHE_DATA)? 1 : 0); 1753} 1754 1755/* 1756 * has sequential readahead been disabled on this vnode 1757 */ 1758int 1759vnode_isnoreadahead(vnode_t vp) 1760{ 1761 return ((vp->v_flag & VRAOFF)? 1 : 0); 1762} 1763 1764int 1765vnode_is_openevt(vnode_t vp) 1766{ 1767 return ((vp->v_flag & VOPENEVT)? 1 : 0); 1768} 1769 1770/* is vnode_t a standard one? */ 1771int 1772vnode_isstandard(vnode_t vp) 1773{ 1774 return ((vp->v_flag & VSTANDARD)? 1 : 0); 1775} 1776 1777/* don't vflush() if SKIPSYSTEM */ 1778int 1779vnode_isnoflush(vnode_t vp) 1780{ 1781 return ((vp->v_flag & VNOFLUSH)? 1 : 0); 1782} 1783 1784/* is vnode_t a regular file */ 1785int 1786vnode_isreg(vnode_t vp) 1787{ 1788 return ((vp->v_type == VREG)? 1 : 0); 1789} 1790 1791/* is vnode_t a directory? */ 1792int 1793vnode_isdir(vnode_t vp) 1794{ 1795 return ((vp->v_type == VDIR)? 1 : 0); 1796} 1797 1798/* is vnode_t a symbolic link ? */ 1799int 1800vnode_islnk(vnode_t vp) 1801{ 1802 return ((vp->v_type == VLNK)? 1 : 0); 1803} 1804 1805int 1806vnode_lookup_continue_needed(vnode_t vp, struct componentname *cnp) 1807{ 1808 struct nameidata *ndp = cnp->cn_ndp; 1809 1810 if (ndp == NULL) { 1811 panic("vnode_lookup_continue_needed(): cnp->cn_ndp is NULL\n"); 1812 } 1813 1814 if (vnode_isdir(vp)) { 1815 if (vp->v_mountedhere != NULL) { 1816 goto yes; 1817 } 1818 1819#if CONFIG_TRIGGERS 1820 if (vp->v_resolve) { 1821 goto yes; 1822 } 1823#endif /* CONFIG_TRIGGERS */ 1824 1825 } 1826 1827 1828 if (vnode_islnk(vp)) { 1829 /* From lookup(): || *ndp->ni_next == '/') No need for this, we know we're NULL-terminated here */ 1830 if (cnp->cn_flags & FOLLOW) { 1831 goto yes; 1832 } 1833 if (ndp->ni_flag & NAMEI_TRAILINGSLASH) { 1834 goto yes; 1835 } 1836 } 1837 1838 return 0; 1839 1840yes: 1841 ndp->ni_flag |= NAMEI_CONTLOOKUP; 1842 return EKEEPLOOKING; 1843} 1844 1845/* is vnode_t a fifo ? */ 1846int 1847vnode_isfifo(vnode_t vp) 1848{ 1849 return ((vp->v_type == VFIFO)? 1 : 0); 1850} 1851 1852/* is vnode_t a block device? */ 1853int 1854vnode_isblk(vnode_t vp) 1855{ 1856 return ((vp->v_type == VBLK)? 1 : 0); 1857} 1858 1859int 1860vnode_isspec(vnode_t vp) 1861{ 1862 return (((vp->v_type == VCHR) || (vp->v_type == VBLK)) ? 1 : 0); 1863} 1864 1865/* is vnode_t a char device? */ 1866int 1867vnode_ischr(vnode_t vp) 1868{ 1869 return ((vp->v_type == VCHR)? 1 : 0); 1870} 1871 1872/* is vnode_t a socket? */ 1873int 1874vnode_issock(vnode_t vp) 1875{ 1876 return ((vp->v_type == VSOCK)? 1 : 0); 1877} 1878 1879/* is vnode_t a device with multiple active vnodes referring to it? */ 1880int 1881vnode_isaliased(vnode_t vp) 1882{ 1883 enum vtype vt = vp->v_type; 1884 if (!((vt == VCHR) || (vt == VBLK))) { 1885 return 0; 1886 } else { 1887 return (vp->v_specflags & SI_ALIASED); 1888 } 1889} 1890 1891/* is vnode_t a named stream? */ 1892int 1893vnode_isnamedstream( 1894#if NAMEDSTREAMS 1895 vnode_t vp 1896#else 1897 __unused vnode_t vp 1898#endif 1899 ) 1900{ 1901#if NAMEDSTREAMS 1902 return ((vp->v_flag & VISNAMEDSTREAM) ? 1 : 0); 1903#else 1904 return (0); 1905#endif 1906} 1907 1908int 1909vnode_isshadow( 1910#if NAMEDSTREAMS 1911 vnode_t vp 1912#else 1913 __unused vnode_t vp 1914#endif 1915 ) 1916{ 1917#if NAMEDSTREAMS 1918 return ((vp->v_flag & VISSHADOW) ? 1 : 0); 1919#else 1920 return (0); 1921#endif 1922} 1923 1924/* does vnode have associated named stream vnodes ? */ 1925int 1926vnode_hasnamedstreams( 1927#if NAMEDSTREAMS 1928 vnode_t vp 1929#else 1930 __unused vnode_t vp 1931#endif 1932 ) 1933{ 1934#if NAMEDSTREAMS 1935 return ((vp->v_lflag & VL_HASSTREAMS) ? 1 : 0); 1936#else 1937 return (0); 1938#endif 1939} 1940/* TBD: set vnode_t to not cache data after it is consumed once; used for quota */ 1941void 1942vnode_setnocache(vnode_t vp) 1943{ 1944 vnode_lock_spin(vp); 1945 vp->v_flag |= VNOCACHE_DATA; 1946 vnode_unlock(vp); 1947} 1948 1949void 1950vnode_clearnocache(vnode_t vp) 1951{ 1952 vnode_lock_spin(vp); 1953 vp->v_flag &= ~VNOCACHE_DATA; 1954 vnode_unlock(vp); 1955} 1956 1957void 1958vnode_set_openevt(vnode_t vp) 1959{ 1960 vnode_lock_spin(vp); 1961 vp->v_flag |= VOPENEVT; 1962 vnode_unlock(vp); 1963} 1964 1965void 1966vnode_clear_openevt(vnode_t vp) 1967{ 1968 vnode_lock_spin(vp); 1969 vp->v_flag &= ~VOPENEVT; 1970 vnode_unlock(vp); 1971} 1972 1973 1974void 1975vnode_setnoreadahead(vnode_t vp) 1976{ 1977 vnode_lock_spin(vp); 1978 vp->v_flag |= VRAOFF; 1979 vnode_unlock(vp); 1980} 1981 1982void 1983vnode_clearnoreadahead(vnode_t vp) 1984{ 1985 vnode_lock_spin(vp); 1986 vp->v_flag &= ~VRAOFF; 1987 vnode_unlock(vp); 1988} 1989 1990 1991/* mark vnode_t to skip vflush() is SKIPSYSTEM */ 1992void 1993vnode_setnoflush(vnode_t vp) 1994{ 1995 vnode_lock_spin(vp); 1996 vp->v_flag |= VNOFLUSH; 1997 vnode_unlock(vp); 1998} 1999 2000void 2001vnode_clearnoflush(vnode_t vp) 2002{ 2003 vnode_lock_spin(vp); 2004 vp->v_flag &= ~VNOFLUSH; 2005 vnode_unlock(vp); 2006} 2007 2008 2009/* is vnode_t a blkdevice and has a FS mounted on it */ 2010int 2011vnode_ismountedon(vnode_t vp) 2012{ 2013 return ((vp->v_specflags & SI_MOUNTEDON)? 1 : 0); 2014} 2015 2016void 2017vnode_setmountedon(vnode_t vp) 2018{ 2019 vnode_lock_spin(vp); 2020 vp->v_specflags |= SI_MOUNTEDON; 2021 vnode_unlock(vp); 2022} 2023 2024void 2025vnode_clearmountedon(vnode_t vp) 2026{ 2027 vnode_lock_spin(vp); 2028 vp->v_specflags &= ~SI_MOUNTEDON; 2029 vnode_unlock(vp); 2030} 2031 2032 2033void 2034vnode_settag(vnode_t vp, int tag) 2035{ 2036 vp->v_tag = tag; 2037 2038} 2039 2040int 2041vnode_tag(vnode_t vp) 2042{ 2043 return(vp->v_tag); 2044} 2045 2046vnode_t 2047vnode_parent(vnode_t vp) 2048{ 2049 2050 return(vp->v_parent); 2051} 2052 2053void 2054vnode_setparent(vnode_t vp, vnode_t dvp) 2055{ 2056 vp->v_parent = dvp; 2057} 2058 2059const char * 2060vnode_name(vnode_t vp) 2061{ 2062 /* we try to keep v_name a reasonable name for the node */ 2063 return(vp->v_name); 2064} 2065 2066void 2067vnode_setname(vnode_t vp, char * name) 2068{ 2069 vp->v_name = name; 2070} 2071 2072/* return the registered FS name when adding the FS to kernel */ 2073void 2074vnode_vfsname(vnode_t vp, char * buf) 2075{ 2076 strncpy(buf, vp->v_mount->mnt_vtable->vfc_name, MFSNAMELEN); 2077} 2078 2079/* return the FS type number */ 2080int 2081vnode_vfstypenum(vnode_t vp) 2082{ 2083 return(vp->v_mount->mnt_vtable->vfc_typenum); 2084} 2085 2086int 2087vnode_vfs64bitready(vnode_t vp) 2088{ 2089 2090 /* 2091 * Checking for dead_mountp is a bit of a hack for SnowLeopard: <rdar://problem/6269051> 2092 */ 2093 if ((vp->v_mount != dead_mountp) && (vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFS64BITREADY)) 2094 return(1); 2095 else 2096 return(0); 2097} 2098 2099 2100 2101/* return the visible flags on associated mount point of vnode_t */ 2102uint32_t 2103vnode_vfsvisflags(vnode_t vp) 2104{ 2105 return(vp->v_mount->mnt_flag & MNT_VISFLAGMASK); 2106} 2107 2108/* return the command modifier flags on associated mount point of vnode_t */ 2109uint32_t 2110vnode_vfscmdflags(vnode_t vp) 2111{ 2112 return(vp->v_mount->mnt_flag & MNT_CMDFLAGS); 2113} 2114 2115/* return the max symlink of short links of vnode_t */ 2116uint32_t 2117vnode_vfsmaxsymlen(vnode_t vp) 2118{ 2119 return(vp->v_mount->mnt_maxsymlinklen); 2120} 2121 2122/* return a pointer to the RO vfs_statfs associated with vnode_t's mount point */ 2123struct vfsstatfs * 2124vnode_vfsstatfs(vnode_t vp) 2125{ 2126 return(&vp->v_mount->mnt_vfsstat); 2127} 2128 2129/* return a handle to the FSs specific private handle associated with vnode_t's mount point */ 2130void * 2131vnode_vfsfsprivate(vnode_t vp) 2132{ 2133 return(vp->v_mount->mnt_data); 2134} 2135 2136/* is vnode_t in a rdonly mounted FS */ 2137int 2138vnode_vfsisrdonly(vnode_t vp) 2139{ 2140 return ((vp->v_mount->mnt_flag & MNT_RDONLY)? 1 : 0); 2141} 2142 2143int 2144vnode_compound_rename_available(vnode_t vp) 2145{ 2146 return vnode_compound_op_available(vp, COMPOUND_VNOP_RENAME); 2147} 2148int 2149vnode_compound_rmdir_available(vnode_t vp) 2150{ 2151 return vnode_compound_op_available(vp, COMPOUND_VNOP_RMDIR); 2152} 2153int 2154vnode_compound_mkdir_available(vnode_t vp) 2155{ 2156 return vnode_compound_op_available(vp, COMPOUND_VNOP_MKDIR); 2157} 2158int 2159vnode_compound_remove_available(vnode_t vp) 2160{ 2161 return vnode_compound_op_available(vp, COMPOUND_VNOP_REMOVE); 2162} 2163int 2164vnode_compound_open_available(vnode_t vp) 2165{ 2166 return vnode_compound_op_available(vp, COMPOUND_VNOP_OPEN); 2167} 2168 2169int 2170vnode_compound_op_available(vnode_t vp, compound_vnop_id_t opid) 2171{ 2172 return ((vp->v_mount->mnt_compound_ops & opid) != 0); 2173} 2174 2175/* 2176 * Returns vnode ref to current working directory; if a per-thread current 2177 * working directory is in effect, return that instead of the per process one. 2178 * 2179 * XXX Published, but not used. 2180 */ 2181vnode_t 2182current_workingdir(void) 2183{ 2184 return vfs_context_cwd(vfs_context_current()); 2185} 2186 2187/* returns vnode ref to current root(chroot) directory */ 2188vnode_t 2189current_rootdir(void) 2190{ 2191 proc_t proc = current_proc(); 2192 struct vnode * vp ; 2193 2194 if ( (vp = proc->p_fd->fd_rdir) ) { 2195 if ( (vnode_getwithref(vp)) ) 2196 return (NULL); 2197 } 2198 return vp; 2199} 2200 2201/* 2202 * Get a filesec and optional acl contents from an extended attribute. 2203 * Function will attempt to retrive ACL, UUID, and GUID information using a 2204 * read of a named extended attribute (KAUTH_FILESEC_XATTR). 2205 * 2206 * Parameters: vp The vnode on which to operate. 2207 * fsecp The filesec (and ACL, if any) being 2208 * retrieved. 2209 * ctx The vnode context in which the 2210 * operation is to be attempted. 2211 * 2212 * Returns: 0 Success 2213 * !0 errno value 2214 * 2215 * Notes: The kauth_filesec_t in '*fsecp', if retrieved, will be in 2216 * host byte order, as will be the ACL contents, if any. 2217 * Internally, we will cannonize these values from network (PPC) 2218 * byte order after we retrieve them so that the on-disk contents 2219 * of the extended attribute are identical for both PPC and Intel 2220 * (if we were not being required to provide this service via 2221 * fallback, this would be the job of the filesystem 2222 * 'VNOP_GETATTR' call). 2223 * 2224 * We use ntohl() because it has a transitive property on Intel 2225 * machines and no effect on PPC mancines. This guarantees us 2226 * 2227 * XXX: Deleting rather than ignoreing a corrupt security structure is 2228 * probably the only way to reset it without assistance from an 2229 * file system integrity checking tool. Right now we ignore it. 2230 * 2231 * XXX: We should enummerate the possible errno values here, and where 2232 * in the code they originated. 2233 */ 2234static int 2235vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx) 2236{ 2237 kauth_filesec_t fsec; 2238 uio_t fsec_uio; 2239 size_t fsec_size; 2240 size_t xsize, rsize; 2241 int error; 2242 uint32_t host_fsec_magic; 2243 uint32_t host_acl_entrycount; 2244 2245 fsec = NULL; 2246 fsec_uio = NULL; 2247 error = 0; 2248 2249 /* find out how big the EA is */ 2250 if (vn_getxattr(vp, KAUTH_FILESEC_XATTR, NULL, &xsize, XATTR_NOSECURITY, ctx) != 0) { 2251 /* no EA, no filesec */ 2252 if ((error == ENOATTR) || (error == ENOENT) || (error == EJUSTRETURN)) 2253 error = 0; 2254 /* either way, we are done */ 2255 goto out; 2256 } 2257 2258 /* 2259 * To be valid, a kauth_filesec_t must be large enough to hold a zero 2260 * ACE entrly ACL, and if it's larger than that, it must have the right 2261 * number of bytes such that it contains an atomic number of ACEs, 2262 * rather than partial entries. Otherwise, we ignore it. 2263 */ 2264 if (!KAUTH_FILESEC_VALID(xsize)) { 2265 KAUTH_DEBUG(" ERROR - Bogus kauth_fiilesec_t: %ld bytes", xsize); 2266 error = 0; 2267 goto out; 2268 } 2269 2270 /* how many entries would fit? */ 2271 fsec_size = KAUTH_FILESEC_COUNT(xsize); 2272 2273 /* get buffer and uio */ 2274 if (((fsec = kauth_filesec_alloc(fsec_size)) == NULL) || 2275 ((fsec_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ)) == NULL) || 2276 uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), xsize)) { 2277 KAUTH_DEBUG(" ERROR - could not allocate iov to read ACL"); 2278 error = ENOMEM; 2279 goto out; 2280 } 2281 2282 /* read security attribute */ 2283 rsize = xsize; 2284 if ((error = vn_getxattr(vp, 2285 KAUTH_FILESEC_XATTR, 2286 fsec_uio, 2287 &rsize, 2288 XATTR_NOSECURITY, 2289 ctx)) != 0) { 2290 2291 /* no attribute - no security data */ 2292 if ((error == ENOATTR) || (error == ENOENT) || (error == EJUSTRETURN)) 2293 error = 0; 2294 /* either way, we are done */ 2295 goto out; 2296 } 2297 2298 /* 2299 * Validate security structure; the validation must take place in host 2300 * byte order. If it's corrupt, we will just ignore it. 2301 */ 2302 2303 /* Validate the size before trying to convert it */ 2304 if (rsize < KAUTH_FILESEC_SIZE(0)) { 2305 KAUTH_DEBUG("ACL - DATA TOO SMALL (%d)", rsize); 2306 goto out; 2307 } 2308 2309 /* Validate the magic number before trying to convert it */ 2310 host_fsec_magic = ntohl(KAUTH_FILESEC_MAGIC); 2311 if (fsec->fsec_magic != host_fsec_magic) { 2312 KAUTH_DEBUG("ACL - BAD MAGIC %x", host_fsec_magic); 2313 goto out; 2314 } 2315 2316 /* Validate the entry count before trying to convert it. */ 2317 host_acl_entrycount = ntohl(fsec->fsec_acl.acl_entrycount); 2318 if (host_acl_entrycount != KAUTH_FILESEC_NOACL) { 2319 if (host_acl_entrycount > KAUTH_ACL_MAX_ENTRIES) { 2320 KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", host_acl_entrycount); 2321 goto out; 2322 } 2323 if (KAUTH_FILESEC_SIZE(host_acl_entrycount) > rsize) { 2324 KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", host_acl_entrycount, rsize); 2325 goto out; 2326 } 2327 } 2328 2329 kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, NULL); 2330 2331 *fsecp = fsec; 2332 fsec = NULL; 2333 error = 0; 2334out: 2335 if (fsec != NULL) 2336 kauth_filesec_free(fsec); 2337 if (fsec_uio != NULL) 2338 uio_free(fsec_uio); 2339 if (error) 2340 *fsecp = NULL; 2341 return(error); 2342} 2343 2344/* 2345 * Set a filesec and optional acl contents into an extended attribute. 2346 * function will attempt to store ACL, UUID, and GUID information using a 2347 * write to a named extended attribute (KAUTH_FILESEC_XATTR). The 'acl' 2348 * may or may not point to the `fsec->fsec_acl`, depending on whether the 2349 * original caller supplied an acl. 2350 * 2351 * Parameters: vp The vnode on which to operate. 2352 * fsec The filesec being set. 2353 * acl The acl to be associated with 'fsec'. 2354 * ctx The vnode context in which the 2355 * operation is to be attempted. 2356 * 2357 * Returns: 0 Success 2358 * !0 errno value 2359 * 2360 * Notes: Both the fsec and the acl are always valid. 2361 * 2362 * The kauth_filesec_t in 'fsec', if any, is in host byte order, 2363 * as are the acl contents, if they are used. Internally, we will 2364 * cannonize these values into network (PPC) byte order before we 2365 * attempt to write them so that the on-disk contents of the 2366 * extended attribute are identical for both PPC and Intel (if we 2367 * were not being required to provide this service via fallback, 2368 * this would be the job of the filesystem 'VNOP_SETATTR' call). 2369 * We reverse this process on the way out, so we leave with the 2370 * same byte order we started with. 2371 * 2372 * XXX: We should enummerate the possible errno values here, and where 2373 * in the code they originated. 2374 */ 2375static int 2376vnode_set_filesec(vnode_t vp, kauth_filesec_t fsec, kauth_acl_t acl, vfs_context_t ctx) 2377{ 2378 uio_t fsec_uio; 2379 int error; 2380 uint32_t saved_acl_copysize; 2381 2382 fsec_uio = NULL; 2383 2384 if ((fsec_uio = uio_create(2, 0, UIO_SYSSPACE, UIO_WRITE)) == NULL) { 2385 KAUTH_DEBUG(" ERROR - could not allocate iov to write ACL"); 2386 error = ENOMEM; 2387 goto out; 2388 } 2389 /* 2390 * Save the pre-converted ACL copysize, because it gets swapped too 2391 * if we are running with the wrong endianness. 2392 */ 2393 saved_acl_copysize = KAUTH_ACL_COPYSIZE(acl); 2394 2395 kauth_filesec_acl_setendian(KAUTH_ENDIAN_DISK, fsec, acl); 2396 2397 uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), KAUTH_FILESEC_SIZE(0) - KAUTH_ACL_SIZE(KAUTH_FILESEC_NOACL)); 2398 uio_addiov(fsec_uio, CAST_USER_ADDR_T(acl), saved_acl_copysize); 2399 error = vn_setxattr(vp, 2400 KAUTH_FILESEC_XATTR, 2401 fsec_uio, 2402 XATTR_NOSECURITY, /* we have auth'ed already */ 2403 ctx); 2404 VFS_DEBUG(ctx, vp, "SETATTR - set ACL returning %d", error); 2405 2406 kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, acl); 2407 2408out: 2409 if (fsec_uio != NULL) 2410 uio_free(fsec_uio); 2411 return(error); 2412} 2413 2414 2415/* 2416 * Returns: 0 Success 2417 * ENOMEM Not enough space [only if has filesec] 2418 * VNOP_GETATTR: ??? 2419 * vnode_get_filesec: ??? 2420 * kauth_cred_guid2uid: ??? 2421 * kauth_cred_guid2gid: ??? 2422 * vfs_update_vfsstat: ??? 2423 */ 2424int 2425vnode_getattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx) 2426{ 2427 kauth_filesec_t fsec; 2428 kauth_acl_t facl; 2429 int error; 2430 uid_t nuid; 2431 gid_t ngid; 2432 2433 /* don't ask for extended security data if the filesystem doesn't support it */ 2434 if (!vfs_extendedsecurity(vnode_mount(vp))) { 2435 VATTR_CLEAR_ACTIVE(vap, va_acl); 2436 VATTR_CLEAR_ACTIVE(vap, va_uuuid); 2437 VATTR_CLEAR_ACTIVE(vap, va_guuid); 2438 } 2439 2440 /* 2441 * If the caller wants size values we might have to synthesise, give the 2442 * filesystem the opportunity to supply better intermediate results. 2443 */ 2444 if (VATTR_IS_ACTIVE(vap, va_data_alloc) || 2445 VATTR_IS_ACTIVE(vap, va_total_size) || 2446 VATTR_IS_ACTIVE(vap, va_total_alloc)) { 2447 VATTR_SET_ACTIVE(vap, va_data_size); 2448 VATTR_SET_ACTIVE(vap, va_data_alloc); 2449 VATTR_SET_ACTIVE(vap, va_total_size); 2450 VATTR_SET_ACTIVE(vap, va_total_alloc); 2451 } 2452 2453 error = VNOP_GETATTR(vp, vap, ctx); 2454 if (error) { 2455 KAUTH_DEBUG("ERROR - returning %d", error); 2456 goto out; 2457 } 2458 2459 /* 2460 * If extended security data was requested but not returned, try the fallback 2461 * path. 2462 */ 2463 if (VATTR_NOT_RETURNED(vap, va_acl) || VATTR_NOT_RETURNED(vap, va_uuuid) || VATTR_NOT_RETURNED(vap, va_guuid)) { 2464 fsec = NULL; 2465 2466 if ((vp->v_type == VDIR) || (vp->v_type == VLNK) || (vp->v_type == VREG)) { 2467 /* try to get the filesec */ 2468 if ((error = vnode_get_filesec(vp, &fsec, ctx)) != 0) 2469 goto out; 2470 } 2471 /* if no filesec, no attributes */ 2472 if (fsec == NULL) { 2473 VATTR_RETURN(vap, va_acl, NULL); 2474 VATTR_RETURN(vap, va_uuuid, kauth_null_guid); 2475 VATTR_RETURN(vap, va_guuid, kauth_null_guid); 2476 } else { 2477 2478 /* looks good, try to return what we were asked for */ 2479 VATTR_RETURN(vap, va_uuuid, fsec->fsec_owner); 2480 VATTR_RETURN(vap, va_guuid, fsec->fsec_group); 2481 2482 /* only return the ACL if we were actually asked for it */ 2483 if (VATTR_IS_ACTIVE(vap, va_acl)) { 2484 if (fsec->fsec_acl.acl_entrycount == KAUTH_FILESEC_NOACL) { 2485 VATTR_RETURN(vap, va_acl, NULL); 2486 } else { 2487 facl = kauth_acl_alloc(fsec->fsec_acl.acl_entrycount); 2488 if (facl == NULL) { 2489 kauth_filesec_free(fsec); 2490 error = ENOMEM; 2491 goto out; 2492 } 2493 bcopy(&fsec->fsec_acl, facl, KAUTH_ACL_COPYSIZE(&fsec->fsec_acl)); 2494 VATTR_RETURN(vap, va_acl, facl); 2495 } 2496 } 2497 kauth_filesec_free(fsec); 2498 } 2499 } 2500 /* 2501 * If someone gave us an unsolicited filesec, toss it. We promise that 2502 * we're OK with a filesystem giving us anything back, but our callers 2503 * only expect what they asked for. 2504 */ 2505 if (VATTR_IS_SUPPORTED(vap, va_acl) && !VATTR_IS_ACTIVE(vap, va_acl)) { 2506 if (vap->va_acl != NULL) 2507 kauth_acl_free(vap->va_acl); 2508 VATTR_CLEAR_SUPPORTED(vap, va_acl); 2509 } 2510 2511#if 0 /* enable when we have a filesystem only supporting UUIDs */ 2512 /* 2513 * Handle the case where we need a UID/GID, but only have extended 2514 * security information. 2515 */ 2516 if (VATTR_NOT_RETURNED(vap, va_uid) && 2517 VATTR_IS_SUPPORTED(vap, va_uuuid) && 2518 !kauth_guid_equal(&vap->va_uuuid, &kauth_null_guid)) { 2519 if ((error = kauth_cred_guid2uid(&vap->va_uuuid, &nuid)) == 0) 2520 VATTR_RETURN(vap, va_uid, nuid); 2521 } 2522 if (VATTR_NOT_RETURNED(vap, va_gid) && 2523 VATTR_IS_SUPPORTED(vap, va_guuid) && 2524 !kauth_guid_equal(&vap->va_guuid, &kauth_null_guid)) { 2525 if ((error = kauth_cred_guid2gid(&vap->va_guuid, &ngid)) == 0) 2526 VATTR_RETURN(vap, va_gid, ngid); 2527 } 2528#endif 2529 2530 /* 2531 * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here. 2532 */ 2533 if (VATTR_IS_ACTIVE(vap, va_uid)) { 2534 if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_uid)) { 2535 nuid = vap->va_uid; 2536 } else if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) { 2537 nuid = vp->v_mount->mnt_fsowner; 2538 if (nuid == KAUTH_UID_NONE) 2539 nuid = 99; 2540 } else if (VATTR_IS_SUPPORTED(vap, va_uid)) { 2541 nuid = vap->va_uid; 2542 } else { 2543 /* this will always be something sensible */ 2544 nuid = vp->v_mount->mnt_fsowner; 2545 } 2546 if ((nuid == 99) && !vfs_context_issuser(ctx)) 2547 nuid = kauth_cred_getuid(vfs_context_ucred(ctx)); 2548 VATTR_RETURN(vap, va_uid, nuid); 2549 } 2550 if (VATTR_IS_ACTIVE(vap, va_gid)) { 2551 if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_gid)) { 2552 ngid = vap->va_gid; 2553 } else if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) { 2554 ngid = vp->v_mount->mnt_fsgroup; 2555 if (ngid == KAUTH_GID_NONE) 2556 ngid = 99; 2557 } else if (VATTR_IS_SUPPORTED(vap, va_gid)) { 2558 ngid = vap->va_gid; 2559 } else { 2560 /* this will always be something sensible */ 2561 ngid = vp->v_mount->mnt_fsgroup; 2562 } 2563 if ((ngid == 99) && !vfs_context_issuser(ctx)) 2564 ngid = kauth_cred_getgid(vfs_context_ucred(ctx)); 2565 VATTR_RETURN(vap, va_gid, ngid); 2566 } 2567 2568 /* 2569 * Synthesise some values that can be reasonably guessed. 2570 */ 2571 if (!VATTR_IS_SUPPORTED(vap, va_iosize)) 2572 VATTR_RETURN(vap, va_iosize, vp->v_mount->mnt_vfsstat.f_iosize); 2573 2574 if (!VATTR_IS_SUPPORTED(vap, va_flags)) 2575 VATTR_RETURN(vap, va_flags, 0); 2576 2577 if (!VATTR_IS_SUPPORTED(vap, va_filerev)) 2578 VATTR_RETURN(vap, va_filerev, 0); 2579 2580 if (!VATTR_IS_SUPPORTED(vap, va_gen)) 2581 VATTR_RETURN(vap, va_gen, 0); 2582 2583 /* 2584 * Default sizes. Ordering here is important, as later defaults build on earlier ones. 2585 */ 2586 if (!VATTR_IS_SUPPORTED(vap, va_data_size)) 2587 VATTR_RETURN(vap, va_data_size, 0); 2588 2589 /* do we want any of the possibly-computed values? */ 2590 if (VATTR_IS_ACTIVE(vap, va_data_alloc) || 2591 VATTR_IS_ACTIVE(vap, va_total_size) || 2592 VATTR_IS_ACTIVE(vap, va_total_alloc)) { 2593 /* make sure f_bsize is valid */ 2594 if (vp->v_mount->mnt_vfsstat.f_bsize == 0) { 2595 if ((error = vfs_update_vfsstat(vp->v_mount, ctx, VFS_KERNEL_EVENT)) != 0) 2596 goto out; 2597 } 2598 2599 /* default va_data_alloc from va_data_size */ 2600 if (!VATTR_IS_SUPPORTED(vap, va_data_alloc)) 2601 VATTR_RETURN(vap, va_data_alloc, roundup(vap->va_data_size, vp->v_mount->mnt_vfsstat.f_bsize)); 2602 2603 /* default va_total_size from va_data_size */ 2604 if (!VATTR_IS_SUPPORTED(vap, va_total_size)) 2605 VATTR_RETURN(vap, va_total_size, vap->va_data_size); 2606 2607 /* default va_total_alloc from va_total_size which is guaranteed at this point */ 2608 if (!VATTR_IS_SUPPORTED(vap, va_total_alloc)) 2609 VATTR_RETURN(vap, va_total_alloc, roundup(vap->va_total_size, vp->v_mount->mnt_vfsstat.f_bsize)); 2610 } 2611 2612 /* 2613 * If we don't have a change time, pull it from the modtime. 2614 */ 2615 if (!VATTR_IS_SUPPORTED(vap, va_change_time) && VATTR_IS_SUPPORTED(vap, va_modify_time)) 2616 VATTR_RETURN(vap, va_change_time, vap->va_modify_time); 2617 2618 /* 2619 * This is really only supported for the creation VNOPs, but since the field is there 2620 * we should populate it correctly. 2621 */ 2622 VATTR_RETURN(vap, va_type, vp->v_type); 2623 2624 /* 2625 * The fsid can be obtained from the mountpoint directly. 2626 */ 2627 VATTR_RETURN(vap, va_fsid, vp->v_mount->mnt_vfsstat.f_fsid.val[0]); 2628 2629out: 2630 2631 return(error); 2632} 2633 2634/* 2635 * Set the attributes on a vnode in a vnode context. 2636 * 2637 * Parameters: vp The vnode whose attributes to set. 2638 * vap A pointer to the attributes to set. 2639 * ctx The vnode context in which the 2640 * operation is to be attempted. 2641 * 2642 * Returns: 0 Success 2643 * !0 errno value 2644 * 2645 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order. 2646 * 2647 * The contents of the data area pointed to by 'vap' may be 2648 * modified if the vnode is on a filesystem which has been 2649 * mounted with ingore ownership flags, or by the underlyng 2650 * VFS itself, or by the fallback code, if the underlying VFS 2651 * does not support ACL, UUID, or GUUID attributes directly. 2652 * 2653 * XXX: We should enummerate the possible errno values here, and where 2654 * in the code they originated. 2655 */ 2656int 2657vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx) 2658{ 2659 int error, is_perm_change=0; 2660 2661 /* 2662 * Make sure the filesystem is mounted R/W. 2663 * If not, return an error. 2664 */ 2665 if (vfs_isrdonly(vp->v_mount)) { 2666 error = EROFS; 2667 goto out; 2668 } 2669#if NAMEDSTREAMS 2670 /* For streams, va_data_size is the only setable attribute. */ 2671 if ((vp->v_flag & VISNAMEDSTREAM) && (vap->va_active != VNODE_ATTR_va_data_size)) { 2672 error = EPERM; 2673 goto out; 2674 } 2675#endif 2676 2677 /* 2678 * If ownership is being ignored on this volume, we silently discard 2679 * ownership changes. 2680 */ 2681 if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) { 2682 VATTR_CLEAR_ACTIVE(vap, va_uid); 2683 VATTR_CLEAR_ACTIVE(vap, va_gid); 2684 } 2685 2686 if ( VATTR_IS_ACTIVE(vap, va_uid) || VATTR_IS_ACTIVE(vap, va_gid) 2687 || VATTR_IS_ACTIVE(vap, va_mode) || VATTR_IS_ACTIVE(vap, va_acl)) { 2688 is_perm_change = 1; 2689 } 2690 2691 /* 2692 * Make sure that extended security is enabled if we're going to try 2693 * to set any. 2694 */ 2695 if (!vfs_extendedsecurity(vnode_mount(vp)) && 2696 (VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_uuuid) || VATTR_IS_ACTIVE(vap, va_guuid))) { 2697 KAUTH_DEBUG("SETATTR - returning ENOTSUP to request to set extended security"); 2698 error = ENOTSUP; 2699 goto out; 2700 } 2701 2702 error = VNOP_SETATTR(vp, vap, ctx); 2703 2704 if ((error == 0) && !VATTR_ALL_SUPPORTED(vap)) 2705 error = vnode_setattr_fallback(vp, vap, ctx); 2706 2707#if CONFIG_FSE 2708 // only send a stat_changed event if this is more than 2709 // just an access or backup time update 2710 if (error == 0 && (vap->va_active != VNODE_ATTR_BIT(va_access_time)) && (vap->va_active != VNODE_ATTR_BIT(va_backup_time))) { 2711 if (is_perm_change) { 2712 if (need_fsevent(FSE_CHOWN, vp)) { 2713 add_fsevent(FSE_CHOWN, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE); 2714 } 2715 } else if(need_fsevent(FSE_STAT_CHANGED, vp)) { 2716 add_fsevent(FSE_STAT_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE); 2717 } 2718 } 2719#endif 2720 2721out: 2722 return(error); 2723} 2724 2725/* 2726 * Fallback for setting the attributes on a vnode in a vnode context. This 2727 * Function will attempt to store ACL, UUID, and GUID information utilizing 2728 * a read/modify/write operation against an EA used as a backing store for 2729 * the object. 2730 * 2731 * Parameters: vp The vnode whose attributes to set. 2732 * vap A pointer to the attributes to set. 2733 * ctx The vnode context in which the 2734 * operation is to be attempted. 2735 * 2736 * Returns: 0 Success 2737 * !0 errno value 2738 * 2739 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order, 2740 * as are the fsec and lfsec, if they are used. 2741 * 2742 * The contents of the data area pointed to by 'vap' may be 2743 * modified to indicate that the attribute is supported for 2744 * any given requested attribute. 2745 * 2746 * XXX: We should enummerate the possible errno values here, and where 2747 * in the code they originated. 2748 */ 2749int 2750vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx) 2751{ 2752 kauth_filesec_t fsec; 2753 kauth_acl_t facl; 2754 struct kauth_filesec lfsec; 2755 int error; 2756 2757 error = 0; 2758 2759 /* 2760 * Extended security fallback via extended attributes. 2761 * 2762 * Note that we do not free the filesec; the caller is expected to 2763 * do this. 2764 */ 2765 if (VATTR_NOT_RETURNED(vap, va_acl) || 2766 VATTR_NOT_RETURNED(vap, va_uuuid) || 2767 VATTR_NOT_RETURNED(vap, va_guuid)) { 2768 VFS_DEBUG(ctx, vp, "SETATTR - doing filesec fallback"); 2769 2770 /* 2771 * Fail for file types that we don't permit extended security 2772 * to be set on. 2773 */ 2774 if ((vp->v_type != VDIR) && (vp->v_type != VLNK) && (vp->v_type != VREG)) { 2775 VFS_DEBUG(ctx, vp, "SETATTR - Can't write ACL to file type %d", vnode_vtype(vp)); 2776 error = EINVAL; 2777 goto out; 2778 } 2779 2780 /* 2781 * If we don't have all the extended security items, we need 2782 * to fetch the existing data to perform a read-modify-write 2783 * operation. 2784 */ 2785 fsec = NULL; 2786 if (!VATTR_IS_ACTIVE(vap, va_acl) || 2787 !VATTR_IS_ACTIVE(vap, va_uuuid) || 2788 !VATTR_IS_ACTIVE(vap, va_guuid)) { 2789 if ((error = vnode_get_filesec(vp, &fsec, ctx)) != 0) { 2790 KAUTH_DEBUG("SETATTR - ERROR %d fetching filesec for update", error); 2791 goto out; 2792 } 2793 } 2794 /* if we didn't get a filesec, use our local one */ 2795 if (fsec == NULL) { 2796 KAUTH_DEBUG("SETATTR - using local filesec for new/full update"); 2797 fsec = &lfsec; 2798 } else { 2799 KAUTH_DEBUG("SETATTR - updating existing filesec"); 2800 } 2801 /* find the ACL */ 2802 facl = &fsec->fsec_acl; 2803 2804 /* if we're using the local filesec, we need to initialise it */ 2805 if (fsec == &lfsec) { 2806 fsec->fsec_magic = KAUTH_FILESEC_MAGIC; 2807 fsec->fsec_owner = kauth_null_guid; 2808 fsec->fsec_group = kauth_null_guid; 2809 facl->acl_entrycount = KAUTH_FILESEC_NOACL; 2810 facl->acl_flags = 0; 2811 } 2812 2813 /* 2814 * Update with the supplied attributes. 2815 */ 2816 if (VATTR_IS_ACTIVE(vap, va_uuuid)) { 2817 KAUTH_DEBUG("SETATTR - updating owner UUID"); 2818 fsec->fsec_owner = vap->va_uuuid; 2819 VATTR_SET_SUPPORTED(vap, va_uuuid); 2820 } 2821 if (VATTR_IS_ACTIVE(vap, va_guuid)) { 2822 KAUTH_DEBUG("SETATTR - updating group UUID"); 2823 fsec->fsec_group = vap->va_guuid; 2824 VATTR_SET_SUPPORTED(vap, va_guuid); 2825 } 2826 if (VATTR_IS_ACTIVE(vap, va_acl)) { 2827 if (vap->va_acl == NULL) { 2828 KAUTH_DEBUG("SETATTR - removing ACL"); 2829 facl->acl_entrycount = KAUTH_FILESEC_NOACL; 2830 } else { 2831 KAUTH_DEBUG("SETATTR - setting ACL with %d entries", vap->va_acl->acl_entrycount); 2832 facl = vap->va_acl; 2833 } 2834 VATTR_SET_SUPPORTED(vap, va_acl); 2835 } 2836 2837 /* 2838 * If the filesec data is all invalid, we can just remove 2839 * the EA completely. 2840 */ 2841 if ((facl->acl_entrycount == KAUTH_FILESEC_NOACL) && 2842 kauth_guid_equal(&fsec->fsec_owner, &kauth_null_guid) && 2843 kauth_guid_equal(&fsec->fsec_group, &kauth_null_guid)) { 2844 error = vn_removexattr(vp, KAUTH_FILESEC_XATTR, XATTR_NOSECURITY, ctx); 2845 /* no attribute is ok, nothing to delete */ 2846 if (error == ENOATTR) 2847 error = 0; 2848 VFS_DEBUG(ctx, vp, "SETATTR - remove filesec returning %d", error); 2849 } else { 2850 /* write the EA */ 2851 error = vnode_set_filesec(vp, fsec, facl, ctx); 2852 VFS_DEBUG(ctx, vp, "SETATTR - update filesec returning %d", error); 2853 } 2854 2855 /* if we fetched a filesec, dispose of the buffer */ 2856 if (fsec != &lfsec) 2857 kauth_filesec_free(fsec); 2858 } 2859out: 2860 2861 return(error); 2862} 2863 2864/* 2865 * Upcall for a filesystem to tell VFS about an EVFILT_VNODE-type 2866 * event on a vnode. 2867 */ 2868int 2869vnode_notify(vnode_t vp, uint32_t events, struct vnode_attr *vap) 2870{ 2871 /* These are the same as the corresponding knotes, at least for now. Cheating a little. */ 2872 uint32_t knote_mask = (VNODE_EVENT_WRITE | VNODE_EVENT_DELETE | VNODE_EVENT_RENAME 2873 | VNODE_EVENT_LINK | VNODE_EVENT_EXTEND | VNODE_EVENT_ATTRIB); 2874 uint32_t dir_contents_mask = (VNODE_EVENT_DIR_CREATED | VNODE_EVENT_FILE_CREATED 2875 | VNODE_EVENT_DIR_REMOVED | VNODE_EVENT_FILE_REMOVED); 2876 uint32_t knote_events = (events & knote_mask); 2877 2878 /* Permissions are not explicitly part of the kqueue model */ 2879 if (events & VNODE_EVENT_PERMS) { 2880 knote_events |= NOTE_ATTRIB; 2881 } 2882 2883 /* Directory contents information just becomes NOTE_WRITE */ 2884 if ((vnode_isdir(vp)) && (events & dir_contents_mask)) { 2885 knote_events |= NOTE_WRITE; 2886 } 2887 2888 if (knote_events) { 2889 lock_vnode_and_post(vp, knote_events); 2890#if CONFIG_FSE 2891 if (vap != NULL) { 2892 create_fsevent_from_kevent(vp, events, vap); 2893 } 2894#else 2895 (void)vap; 2896#endif 2897 } 2898 2899 return 0; 2900} 2901 2902 2903 2904int 2905vnode_isdyldsharedcache(vnode_t vp) 2906{ 2907 return ((vp->v_flag & VSHARED_DYLD) ? 1 : 0); 2908} 2909 2910 2911/* 2912 * For a filesystem that isn't tracking its own vnode watchers: 2913 * check whether a vnode is being monitored. 2914 */ 2915int 2916vnode_ismonitored(vnode_t vp) { 2917 return (vp->v_knotes.slh_first != NULL); 2918} 2919 2920/* 2921 * Initialize a struct vnode_attr and activate the attributes required 2922 * by the vnode_notify() call. 2923 */ 2924int 2925vfs_get_notify_attributes(struct vnode_attr *vap) 2926{ 2927 VATTR_INIT(vap); 2928 vap->va_active = VNODE_NOTIFY_ATTRS; 2929 return 0; 2930} 2931 2932#if CONFIG_TRIGGERS 2933int 2934vfs_settriggercallback(fsid_t *fsid, vfs_trigger_callback_t vtc, void *data, uint32_t flags __unused, vfs_context_t ctx) 2935{ 2936 int error; 2937 mount_t mp; 2938 2939 mp = mount_list_lookupby_fsid(fsid, 0 /* locked */, 1 /* withref */); 2940 if (mp == NULL) { 2941 return ENOENT; 2942 } 2943 2944 error = vfs_busy(mp, LK_NOWAIT); 2945 mount_iterdrop(mp); 2946 2947 if (error != 0) { 2948 return ENOENT; 2949 } 2950 2951 mount_lock(mp); 2952 if (mp->mnt_triggercallback != NULL) { 2953 error = EBUSY; 2954 mount_unlock(mp); 2955 goto out; 2956 } 2957 2958 mp->mnt_triggercallback = vtc; 2959 mp->mnt_triggerdata = data; 2960 mount_unlock(mp); 2961 2962 mp->mnt_triggercallback(mp, VTC_REPLACE, data, ctx); 2963 2964out: 2965 vfs_unbusy(mp); 2966 return 0; 2967} 2968#endif /* CONFIG_TRIGGERS */ 2969 2970/* 2971 * Definition of vnode operations. 2972 */ 2973 2974#if 0 2975/* 2976 *# 2977 *#% lookup dvp L ? ? 2978 *#% lookup vpp - L - 2979 */ 2980struct vnop_lookup_args { 2981 struct vnodeop_desc *a_desc; 2982 vnode_t a_dvp; 2983 vnode_t *a_vpp; 2984 struct componentname *a_cnp; 2985 vfs_context_t a_context; 2986}; 2987#endif /* 0*/ 2988 2989/* 2990 * Returns: 0 Success 2991 * lock_fsnode:ENOENT No such file or directory [only for VFS 2992 * that is not thread safe & vnode is 2993 * currently being/has been terminated] 2994 * <vfs_lookup>:ENAMETOOLONG 2995 * <vfs_lookup>:ENOENT 2996 * <vfs_lookup>:EJUSTRETURN 2997 * <vfs_lookup>:EPERM 2998 * <vfs_lookup>:EISDIR 2999 * <vfs_lookup>:ENOTDIR 3000 * <vfs_lookup>:??? 3001 * 3002 * Note: The return codes from the underlying VFS's lookup routine can't 3003 * be fully enumerated here, since third party VFS authors may not 3004 * limit their error returns to the ones documented here, even 3005 * though this may result in some programs functioning incorrectly. 3006 * 3007 * The return codes documented above are those which may currently 3008 * be returned by HFS from hfs_lookup, not including additional 3009 * error code which may be propagated from underlying routines. 3010 */ 3011errno_t 3012VNOP_LOOKUP(vnode_t dvp, vnode_t *vpp, struct componentname *cnp, vfs_context_t ctx) 3013{ 3014 int _err; 3015 struct vnop_lookup_args a; 3016 vnode_t vp; 3017#if CONFIG_VFS_FUNNEL 3018 int thread_safe; 3019 int funnel_state = 0; 3020#endif /* CONFIG_VFS_FUNNEL */ 3021 3022 a.a_desc = &vnop_lookup_desc; 3023 a.a_dvp = dvp; 3024 a.a_vpp = vpp; 3025 a.a_cnp = cnp; 3026 a.a_context = ctx; 3027 3028#if CONFIG_VFS_FUNNEL 3029 thread_safe = THREAD_SAFE_FS(dvp); 3030 if (!thread_safe) { 3031 if ( (_err = lock_fsnode(dvp, &funnel_state)) ) { 3032 return (_err); 3033 } 3034 } 3035#endif /* CONFIG_VFS_FUNNEL */ 3036 3037 _err = (*dvp->v_op[vnop_lookup_desc.vdesc_offset])(&a); 3038 3039 vp = *vpp; 3040 3041#if CONFIG_VFS_FUNNEL 3042 if (!thread_safe) { 3043 if ( (cnp->cn_flags & ISLASTCN) ) { 3044 if ( (cnp->cn_flags & LOCKPARENT) ) { 3045 if ( !(cnp->cn_flags & FSNODELOCKHELD) ) { 3046 /* 3047 * leave the fsnode lock held on 3048 * the directory, but restore the funnel... 3049 * also indicate that we need to drop the 3050 * fsnode_lock when we're done with the 3051 * system call processing for this path 3052 */ 3053 cnp->cn_flags |= FSNODELOCKHELD; 3054 3055 (void) thread_funnel_set(kernel_flock, funnel_state); 3056 return (_err); 3057 } 3058 } 3059 } 3060 unlock_fsnode(dvp, &funnel_state); 3061 } 3062#endif /* CONFIG_VFS_FUNNEL */ 3063 3064 return (_err); 3065} 3066 3067#if 0 3068struct vnop_compound_open_args { 3069 struct vnodeop_desc *a_desc; 3070 vnode_t a_dvp; 3071 vnode_t *a_vpp; 3072 struct componentname *a_cnp; 3073 int32_t a_flags; 3074 int32_t a_fmode; 3075 struct vnode_attr *a_vap; 3076 vfs_context_t a_context; 3077 void *a_reserved; 3078}; 3079#endif /* 0 */ 3080 3081int 3082VNOP_COMPOUND_OPEN(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, int32_t fmode, uint32_t *statusp, struct vnode_attr *vap, vfs_context_t ctx) 3083{ 3084 int _err; 3085 struct vnop_compound_open_args a; 3086 int did_create = 0; 3087 int want_create; 3088 uint32_t tmp_status = 0; 3089 struct componentname *cnp = &ndp->ni_cnd; 3090 3091 want_create = (flags & VNOP_COMPOUND_OPEN_DO_CREATE); 3092 3093 a.a_desc = &vnop_compound_open_desc; 3094 a.a_dvp = dvp; 3095 a.a_vpp = vpp; /* Could be NULL */ 3096 a.a_cnp = cnp; 3097 a.a_flags = flags; 3098 a.a_fmode = fmode; 3099 a.a_status = (statusp != NULL) ? statusp : &tmp_status; 3100 a.a_vap = vap; 3101 a.a_context = ctx; 3102 a.a_open_create_authorizer = vn_authorize_create; 3103 a.a_open_existing_authorizer = vn_authorize_open_existing; 3104 a.a_reserved = NULL; 3105 3106 if (dvp == NULLVP) { 3107 panic("No dvp?"); 3108 } 3109 if (want_create && !vap) { 3110 panic("Want create, but no vap?"); 3111 } 3112 if (!want_create && vap) { 3113 panic("Don't want create, but have a vap?"); 3114 } 3115 3116 _err = (*dvp->v_op[vnop_compound_open_desc.vdesc_offset])(&a); 3117 3118 did_create = (*a.a_status & COMPOUND_OPEN_STATUS_DID_CREATE); 3119 3120 if (did_create && !want_create) { 3121 panic("Filesystem did a create, even though none was requested?"); 3122 } 3123 3124 if (did_create) { 3125 if (!NATIVE_XATTR(dvp)) { 3126 /* 3127 * Remove stale Apple Double file (if any). 3128 */ 3129 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0); 3130 } 3131 3132 /* On create, provide kqueue notification */ 3133 post_event_if_success(dvp, _err, NOTE_WRITE); 3134 } 3135 3136 lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, did_create); 3137#if 0 /* FSEvents... */ 3138 if (*vpp && _err && _err != EKEEPLOOKING) { 3139 vnode_put(*vpp); 3140 *vpp = NULLVP; 3141 } 3142#endif /* 0 */ 3143 3144 return (_err); 3145 3146} 3147 3148#if 0 3149struct vnop_create_args { 3150 struct vnodeop_desc *a_desc; 3151 vnode_t a_dvp; 3152 vnode_t *a_vpp; 3153 struct componentname *a_cnp; 3154 struct vnode_attr *a_vap; 3155 vfs_context_t a_context; 3156}; 3157#endif /* 0*/ 3158errno_t 3159VNOP_CREATE(vnode_t dvp, vnode_t * vpp, struct componentname * cnp, struct vnode_attr * vap, vfs_context_t ctx) 3160{ 3161 int _err; 3162 struct vnop_create_args a; 3163#if CONFIG_VFS_FUNNEL 3164 int thread_safe; 3165 int funnel_state = 0; 3166#endif /* CONFIG_VFS_FUNNEL */ 3167 3168 a.a_desc = &vnop_create_desc; 3169 a.a_dvp = dvp; 3170 a.a_vpp = vpp; 3171 a.a_cnp = cnp; 3172 a.a_vap = vap; 3173 a.a_context = ctx; 3174 3175#if CONFIG_VFS_FUNNEL 3176 thread_safe = THREAD_SAFE_FS(dvp); 3177 if (!thread_safe) { 3178 if ( (_err = lock_fsnode(dvp, &funnel_state)) ) { 3179 return (_err); 3180 } 3181 } 3182#endif /* CONFIG_VFS_FUNNEL */ 3183 3184 _err = (*dvp->v_op[vnop_create_desc.vdesc_offset])(&a); 3185 if (_err == 0 && !NATIVE_XATTR(dvp)) { 3186 /* 3187 * Remove stale Apple Double file (if any). 3188 */ 3189 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0); 3190 } 3191 3192#if CONFIG_VFS_FUNNEL 3193 if (!thread_safe) { 3194 unlock_fsnode(dvp, &funnel_state); 3195 } 3196#endif /* CONFIG_VFS_FUNNEL */ 3197 3198 post_event_if_success(dvp, _err, NOTE_WRITE); 3199 3200 return (_err); 3201} 3202 3203#if 0 3204/* 3205 *# 3206 *#% whiteout dvp L L L 3207 *#% whiteout cnp - - - 3208 *#% whiteout flag - - - 3209 *# 3210 */ 3211struct vnop_whiteout_args { 3212 struct vnodeop_desc *a_desc; 3213 vnode_t a_dvp; 3214 struct componentname *a_cnp; 3215 int a_flags; 3216 vfs_context_t a_context; 3217}; 3218#endif /* 0*/ 3219errno_t 3220VNOP_WHITEOUT(vnode_t dvp, struct componentname * cnp, int flags, vfs_context_t ctx) 3221{ 3222 int _err; 3223 struct vnop_whiteout_args a; 3224#if CONFIG_VFS_FUNNEL 3225 int thread_safe; 3226 int funnel_state = 0; 3227#endif /* CONFIG_VFS_FUNNEL */ 3228 3229 a.a_desc = &vnop_whiteout_desc; 3230 a.a_dvp = dvp; 3231 a.a_cnp = cnp; 3232 a.a_flags = flags; 3233 a.a_context = ctx; 3234 3235#if CONFIG_VFS_FUNNEL 3236 thread_safe = THREAD_SAFE_FS(dvp); 3237 if (!thread_safe) { 3238 if ( (_err = lock_fsnode(dvp, &funnel_state)) ) { 3239 return (_err); 3240 } 3241 } 3242#endif /* CONFIG_VFS_FUNNEL */ 3243 3244 _err = (*dvp->v_op[vnop_whiteout_desc.vdesc_offset])(&a); 3245 3246#if CONFIG_VFS_FUNNEL 3247 if (!thread_safe) { 3248 unlock_fsnode(dvp, &funnel_state); 3249 } 3250#endif /* CONFIG_VFS_FUNNEL */ 3251 3252 post_event_if_success(dvp, _err, NOTE_WRITE); 3253 3254 return (_err); 3255} 3256 3257 #if 0 3258/* 3259 *# 3260 *#% mknod dvp L U U 3261 *#% mknod vpp - X - 3262 *# 3263 */ 3264struct vnop_mknod_args { 3265 struct vnodeop_desc *a_desc; 3266 vnode_t a_dvp; 3267 vnode_t *a_vpp; 3268 struct componentname *a_cnp; 3269 struct vnode_attr *a_vap; 3270 vfs_context_t a_context; 3271}; 3272#endif /* 0*/ 3273errno_t 3274VNOP_MKNOD(vnode_t dvp, vnode_t * vpp, struct componentname * cnp, struct vnode_attr * vap, vfs_context_t ctx) 3275{ 3276 3277 int _err; 3278 struct vnop_mknod_args a; 3279#if CONFIG_VFS_FUNNEL 3280 int thread_safe; 3281 int funnel_state = 0; 3282#endif /* CONFIG_VFS_FUNNEL */ 3283 3284 a.a_desc = &vnop_mknod_desc; 3285 a.a_dvp = dvp; 3286 a.a_vpp = vpp; 3287 a.a_cnp = cnp; 3288 a.a_vap = vap; 3289 a.a_context = ctx; 3290 3291#if CONFIG_VFS_FUNNEL 3292 thread_safe = THREAD_SAFE_FS(dvp); 3293 if (!thread_safe) { 3294 if ( (_err = lock_fsnode(dvp, &funnel_state)) ) { 3295 return (_err); 3296 } 3297 } 3298#endif /* CONFIG_VFS_FUNNEL */ 3299 3300 _err = (*dvp->v_op[vnop_mknod_desc.vdesc_offset])(&a); 3301 3302#if CONFIG_VFS_FUNNEL 3303 if (!thread_safe) { 3304 unlock_fsnode(dvp, &funnel_state); 3305 } 3306#endif /* CONFIG_VFS_FUNNEL */ 3307 3308 post_event_if_success(dvp, _err, NOTE_WRITE); 3309 3310 return (_err); 3311} 3312 3313#if 0 3314/* 3315 *# 3316 *#% open vp L L L 3317 *# 3318 */ 3319struct vnop_open_args { 3320 struct vnodeop_desc *a_desc; 3321 vnode_t a_vp; 3322 int a_mode; 3323 vfs_context_t a_context; 3324}; 3325#endif /* 0*/ 3326errno_t 3327VNOP_OPEN(vnode_t vp, int mode, vfs_context_t ctx) 3328{ 3329 int _err; 3330 struct vnop_open_args a; 3331#if CONFIG_VFS_FUNNEL 3332 int thread_safe; 3333 int funnel_state = 0; 3334#endif /* CONFIG_VFS_FUNNEL */ 3335 3336 if (ctx == NULL) { 3337 ctx = vfs_context_current(); 3338 } 3339 a.a_desc = &vnop_open_desc; 3340 a.a_vp = vp; 3341 a.a_mode = mode; 3342 a.a_context = ctx; 3343 3344#if CONFIG_VFS_FUNNEL 3345 thread_safe = THREAD_SAFE_FS(vp); 3346 if (!thread_safe) { 3347 funnel_state = thread_funnel_set(kernel_flock, TRUE); 3348 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3349 if ( (_err = lock_fsnode(vp, NULL)) ) { 3350 (void) thread_funnel_set(kernel_flock, funnel_state); 3351 return (_err); 3352 } 3353 } 3354 } 3355#endif /* CONFIG_VFS_FUNNEL */ 3356 3357 _err = (*vp->v_op[vnop_open_desc.vdesc_offset])(&a); 3358 3359#if CONFIG_VFS_FUNNEL 3360 if (!thread_safe) { 3361 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3362 unlock_fsnode(vp, NULL); 3363 } 3364 (void) thread_funnel_set(kernel_flock, funnel_state); 3365 } 3366#endif /* CONFIG_VFS_FUNNEL */ 3367 3368 return (_err); 3369} 3370 3371#if 0 3372/* 3373 *# 3374 *#% close vp U U U 3375 *# 3376 */ 3377struct vnop_close_args { 3378 struct vnodeop_desc *a_desc; 3379 vnode_t a_vp; 3380 int a_fflag; 3381 vfs_context_t a_context; 3382}; 3383#endif /* 0*/ 3384errno_t 3385VNOP_CLOSE(vnode_t vp, int fflag, vfs_context_t ctx) 3386{ 3387 int _err; 3388 struct vnop_close_args a; 3389#if CONFIG_VFS_FUNNEL 3390 int thread_safe; 3391 int funnel_state = 0; 3392#endif /* CONFIG_VFS_FUNNEL */ 3393 3394 if (ctx == NULL) { 3395 ctx = vfs_context_current(); 3396 } 3397 a.a_desc = &vnop_close_desc; 3398 a.a_vp = vp; 3399 a.a_fflag = fflag; 3400 a.a_context = ctx; 3401 3402#if CONFIG_VFS_FUNNEL 3403 thread_safe = THREAD_SAFE_FS(vp); 3404 if (!thread_safe) { 3405 funnel_state = thread_funnel_set(kernel_flock, TRUE); 3406 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3407 if ( (_err = lock_fsnode(vp, NULL)) ) { 3408 (void) thread_funnel_set(kernel_flock, funnel_state); 3409 return (_err); 3410 } 3411 } 3412 } 3413#endif /* CONFIG_VFS_FUNNEL */ 3414 3415 _err = (*vp->v_op[vnop_close_desc.vdesc_offset])(&a); 3416 3417#if CONFIG_VFS_FUNNEL 3418 if (!thread_safe) { 3419 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3420 unlock_fsnode(vp, NULL); 3421 } 3422 (void) thread_funnel_set(kernel_flock, funnel_state); 3423 } 3424#endif /* CONFIG_VFS_FUNNEL */ 3425 3426 return (_err); 3427} 3428 3429#if 0 3430/* 3431 *# 3432 *#% access vp L L L 3433 *# 3434 */ 3435struct vnop_access_args { 3436 struct vnodeop_desc *a_desc; 3437 vnode_t a_vp; 3438 int a_action; 3439 vfs_context_t a_context; 3440}; 3441#endif /* 0*/ 3442errno_t 3443VNOP_ACCESS(vnode_t vp, int action, vfs_context_t ctx) 3444{ 3445 int _err; 3446 struct vnop_access_args a; 3447#if CONFIG_VFS_FUNNEL 3448 int thread_safe; 3449 int funnel_state = 0; 3450#endif /* CONFIG_VFS_FUNNEL */ 3451 3452 if (ctx == NULL) { 3453 ctx = vfs_context_current(); 3454 } 3455 a.a_desc = &vnop_access_desc; 3456 a.a_vp = vp; 3457 a.a_action = action; 3458 a.a_context = ctx; 3459 3460#if CONFIG_VFS_FUNNEL 3461 thread_safe = THREAD_SAFE_FS(vp); 3462 if (!thread_safe) { 3463 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 3464 return (_err); 3465 } 3466 } 3467#endif /* CONFIG_VFS_FUNNEL */ 3468 3469 _err = (*vp->v_op[vnop_access_desc.vdesc_offset])(&a); 3470 3471#if CONFIG_VFS_FUNNEL 3472 if (!thread_safe) { 3473 unlock_fsnode(vp, &funnel_state); 3474 } 3475#endif /* CONFIG_VFS_FUNNEL */ 3476 3477 return (_err); 3478} 3479 3480#if 0 3481/* 3482 *# 3483 *#% getattr vp = = = 3484 *# 3485 */ 3486struct vnop_getattr_args { 3487 struct vnodeop_desc *a_desc; 3488 vnode_t a_vp; 3489 struct vnode_attr *a_vap; 3490 vfs_context_t a_context; 3491}; 3492#endif /* 0*/ 3493errno_t 3494VNOP_GETATTR(vnode_t vp, struct vnode_attr * vap, vfs_context_t ctx) 3495{ 3496 int _err; 3497 struct vnop_getattr_args a; 3498#if CONFIG_VFS_FUNNEL 3499 int thread_safe; 3500 int funnel_state = 0; 3501#endif /* CONFIG_VFS_FUNNEL */ 3502 3503 a.a_desc = &vnop_getattr_desc; 3504 a.a_vp = vp; 3505 a.a_vap = vap; 3506 a.a_context = ctx; 3507 3508#if CONFIG_VFS_FUNNEL 3509 thread_safe = THREAD_SAFE_FS(vp); 3510 if (!thread_safe) { 3511 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 3512 return (_err); 3513 } 3514 } 3515#endif /* CONFIG_VFS_FUNNEL */ 3516 3517 _err = (*vp->v_op[vnop_getattr_desc.vdesc_offset])(&a); 3518 3519#if CONFIG_VFS_FUNNEL 3520 if (!thread_safe) { 3521 unlock_fsnode(vp, &funnel_state); 3522 } 3523#endif /* CONFIG_VFS_FUNNEL */ 3524 3525 return (_err); 3526} 3527 3528#if 0 3529/* 3530 *# 3531 *#% setattr vp L L L 3532 *# 3533 */ 3534struct vnop_setattr_args { 3535 struct vnodeop_desc *a_desc; 3536 vnode_t a_vp; 3537 struct vnode_attr *a_vap; 3538 vfs_context_t a_context; 3539}; 3540#endif /* 0*/ 3541errno_t 3542VNOP_SETATTR(vnode_t vp, struct vnode_attr * vap, vfs_context_t ctx) 3543{ 3544 int _err; 3545 struct vnop_setattr_args a; 3546#if CONFIG_VFS_FUNNEL 3547 int thread_safe; 3548 int funnel_state = 0; 3549#endif /* CONFIG_VFS_FUNNEL */ 3550 3551 a.a_desc = &vnop_setattr_desc; 3552 a.a_vp = vp; 3553 a.a_vap = vap; 3554 a.a_context = ctx; 3555 3556#if CONFIG_VFS_FUNNEL 3557 thread_safe = THREAD_SAFE_FS(vp); 3558 if (!thread_safe) { 3559 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 3560 return (_err); 3561 } 3562 } 3563#endif /* CONFIG_VFS_FUNNEL */ 3564 3565 _err = (*vp->v_op[vnop_setattr_desc.vdesc_offset])(&a); 3566 3567 /* 3568 * Shadow uid/gid/mod change to extended attribute file. 3569 */ 3570 if (_err == 0 && !NATIVE_XATTR(vp)) { 3571 struct vnode_attr va; 3572 int change = 0; 3573 3574 VATTR_INIT(&va); 3575 if (VATTR_IS_ACTIVE(vap, va_uid)) { 3576 VATTR_SET(&va, va_uid, vap->va_uid); 3577 change = 1; 3578 } 3579 if (VATTR_IS_ACTIVE(vap, va_gid)) { 3580 VATTR_SET(&va, va_gid, vap->va_gid); 3581 change = 1; 3582 } 3583 if (VATTR_IS_ACTIVE(vap, va_mode)) { 3584 VATTR_SET(&va, va_mode, vap->va_mode); 3585 change = 1; 3586 } 3587 if (change) { 3588 vnode_t dvp; 3589 const char *vname; 3590 3591 dvp = vnode_getparent(vp); 3592 vname = vnode_getname(vp); 3593 3594 xattrfile_setattr(dvp, vname, &va, ctx); 3595 if (dvp != NULLVP) 3596 vnode_put(dvp); 3597 if (vname != NULL) 3598 vnode_putname(vname); 3599 } 3600 } 3601 3602#if CONFIG_VFS_FUNNEL 3603 if (!thread_safe) { 3604 unlock_fsnode(vp, &funnel_state); 3605 } 3606#endif /* CONFIG_VFS_FUNNEL */ 3607 3608 /* 3609 * If we have changed any of the things about the file that are likely 3610 * to result in changes to authorization results, blow the vnode auth 3611 * cache 3612 */ 3613 if (_err == 0 && ( 3614 VATTR_IS_SUPPORTED(vap, va_mode) || 3615 VATTR_IS_SUPPORTED(vap, va_uid) || 3616 VATTR_IS_SUPPORTED(vap, va_gid) || 3617 VATTR_IS_SUPPORTED(vap, va_flags) || 3618 VATTR_IS_SUPPORTED(vap, va_acl) || 3619 VATTR_IS_SUPPORTED(vap, va_uuuid) || 3620 VATTR_IS_SUPPORTED(vap, va_guuid))) { 3621 vnode_uncache_authorized_action(vp, KAUTH_INVALIDATE_CACHED_RIGHTS); 3622 3623#if NAMEDSTREAMS 3624 if (vfs_authopaque(vp->v_mount) && vnode_hasnamedstreams(vp)) { 3625 vnode_t svp; 3626 if (vnode_getnamedstream(vp, &svp, XATTR_RESOURCEFORK_NAME, NS_OPEN, 0, ctx) == 0) { 3627 vnode_uncache_authorized_action(svp, KAUTH_INVALIDATE_CACHED_RIGHTS); 3628 vnode_put(svp); 3629 } 3630 } 3631#endif /* NAMEDSTREAMS */ 3632 } 3633 3634 3635 post_event_if_success(vp, _err, NOTE_ATTRIB); 3636 3637 return (_err); 3638} 3639 3640 3641#if 0 3642/* 3643 *# 3644 *#% read vp L L L 3645 *# 3646 */ 3647struct vnop_read_args { 3648 struct vnodeop_desc *a_desc; 3649 vnode_t a_vp; 3650 struct uio *a_uio; 3651 int a_ioflag; 3652 vfs_context_t a_context; 3653}; 3654#endif /* 0*/ 3655errno_t 3656VNOP_READ(vnode_t vp, struct uio * uio, int ioflag, vfs_context_t ctx) 3657{ 3658 int _err; 3659 struct vnop_read_args a; 3660#if CONFIG_VFS_FUNNEL 3661 int thread_safe; 3662 int funnel_state = 0; 3663#endif /* CONFIG_VFS_FUNNEL */ 3664 3665 if (ctx == NULL) { 3666 ctx = vfs_context_current(); 3667 } 3668 3669 a.a_desc = &vnop_read_desc; 3670 a.a_vp = vp; 3671 a.a_uio = uio; 3672 a.a_ioflag = ioflag; 3673 a.a_context = ctx; 3674 3675#if CONFIG_VFS_FUNNEL 3676 thread_safe = THREAD_SAFE_FS(vp); 3677 if (!thread_safe) { 3678 funnel_state = thread_funnel_set(kernel_flock, TRUE); 3679 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3680 if ( (_err = lock_fsnode(vp, NULL)) ) { 3681 (void) thread_funnel_set(kernel_flock, funnel_state); 3682 return (_err); 3683 } 3684 } 3685 } 3686#endif /* CONFIG_VFS_FUNNEL */ 3687 3688 _err = (*vp->v_op[vnop_read_desc.vdesc_offset])(&a); 3689 3690#if CONFIG_VFS_FUNNEL 3691 if (!thread_safe) { 3692 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3693 unlock_fsnode(vp, NULL); 3694 } 3695 (void) thread_funnel_set(kernel_flock, funnel_state); 3696 } 3697#endif /* CONFIG_VFS_FUNNEL */ 3698 3699 return (_err); 3700} 3701 3702 3703#if 0 3704/* 3705 *# 3706 *#% write vp L L L 3707 *# 3708 */ 3709struct vnop_write_args { 3710 struct vnodeop_desc *a_desc; 3711 vnode_t a_vp; 3712 struct uio *a_uio; 3713 int a_ioflag; 3714 vfs_context_t a_context; 3715}; 3716#endif /* 0*/ 3717errno_t 3718VNOP_WRITE(vnode_t vp, struct uio * uio, int ioflag, vfs_context_t ctx) 3719{ 3720 struct vnop_write_args a; 3721 int _err; 3722#if CONFIG_VFS_FUNNEL 3723 int thread_safe; 3724 int funnel_state = 0; 3725#endif /* CONFIG_VFS_FUNNEL */ 3726 3727 if (ctx == NULL) { 3728 ctx = vfs_context_current(); 3729 } 3730 3731 a.a_desc = &vnop_write_desc; 3732 a.a_vp = vp; 3733 a.a_uio = uio; 3734 a.a_ioflag = ioflag; 3735 a.a_context = ctx; 3736 3737#if CONFIG_VFS_FUNNEL 3738 thread_safe = THREAD_SAFE_FS(vp); 3739 if (!thread_safe) { 3740 funnel_state = thread_funnel_set(kernel_flock, TRUE); 3741 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3742 if ( (_err = lock_fsnode(vp, NULL)) ) { 3743 (void) thread_funnel_set(kernel_flock, funnel_state); 3744 return (_err); 3745 } 3746 } 3747 } 3748#endif /* CONFIG_VFS_FUNNEL */ 3749 3750 _err = (*vp->v_op[vnop_write_desc.vdesc_offset])(&a); 3751 3752#if CONFIG_VFS_FUNNEL 3753 if (!thread_safe) { 3754 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3755 unlock_fsnode(vp, NULL); 3756 } 3757 (void) thread_funnel_set(kernel_flock, funnel_state); 3758 } 3759#endif /* CONFIG_VFS_FUNNEL */ 3760 3761 post_event_if_success(vp, _err, NOTE_WRITE); 3762 3763 return (_err); 3764} 3765 3766 3767#if 0 3768/* 3769 *# 3770 *#% ioctl vp U U U 3771 *# 3772 */ 3773struct vnop_ioctl_args { 3774 struct vnodeop_desc *a_desc; 3775 vnode_t a_vp; 3776 u_long a_command; 3777 caddr_t a_data; 3778 int a_fflag; 3779 vfs_context_t a_context; 3780}; 3781#endif /* 0*/ 3782errno_t 3783VNOP_IOCTL(vnode_t vp, u_long command, caddr_t data, int fflag, vfs_context_t ctx) 3784{ 3785 int _err; 3786 struct vnop_ioctl_args a; 3787#if CONFIG_VFS_FUNNEL 3788 int thread_safe; 3789 int funnel_state = 0; 3790#endif /* CONFIG_VFS_FUNNEL */ 3791 3792 if (ctx == NULL) { 3793 ctx = vfs_context_current(); 3794 } 3795 3796 /* 3797 * This check should probably have been put in the TTY code instead... 3798 * 3799 * We have to be careful about what we assume during startup and shutdown. 3800 * We have to be able to use the root filesystem's device vnode even when 3801 * devfs isn't mounted (yet/anymore), so we can't go looking at its mount 3802 * structure. If there is no data pointer, it doesn't matter whether 3803 * the device is 64-bit ready. Any command (like DKIOCSYNCHRONIZECACHE) 3804 * which passes NULL for its data pointer can therefore be used during 3805 * mount or unmount of the root filesystem. 3806 * 3807 * Depending on what root filesystems need to do during mount/unmount, we 3808 * may need to loosen this check again in the future. 3809 */ 3810 if (vfs_context_is64bit(ctx) && !(vnode_ischr(vp) || vnode_isblk(vp))) { 3811 if (data != NULL && !vnode_vfs64bitready(vp)) { 3812 return(ENOTTY); 3813 } 3814 } 3815 3816 a.a_desc = &vnop_ioctl_desc; 3817 a.a_vp = vp; 3818 a.a_command = command; 3819 a.a_data = data; 3820 a.a_fflag = fflag; 3821 a.a_context= ctx; 3822 3823#if CONFIG_VFS_FUNNEL 3824 thread_safe = THREAD_SAFE_FS(vp); 3825 if (!thread_safe) { 3826 funnel_state = thread_funnel_set(kernel_flock, TRUE); 3827 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3828 if ( (_err = lock_fsnode(vp, NULL)) ) { 3829 (void) thread_funnel_set(kernel_flock, funnel_state); 3830 return (_err); 3831 } 3832 } 3833 } 3834#endif /* CONFIG_VFS_FUNNEL */ 3835 3836 _err = (*vp->v_op[vnop_ioctl_desc.vdesc_offset])(&a); 3837 3838#if CONFIG_VFS_FUNNEL 3839 if (!thread_safe) { 3840 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3841 unlock_fsnode(vp, NULL); 3842 } 3843 (void) thread_funnel_set(kernel_flock, funnel_state); 3844 } 3845#endif /* CONFIG_VFS_FUNNEL */ 3846 3847 return (_err); 3848} 3849 3850 3851#if 0 3852/* 3853 *# 3854 *#% select vp U U U 3855 *# 3856 */ 3857struct vnop_select_args { 3858 struct vnodeop_desc *a_desc; 3859 vnode_t a_vp; 3860 int a_which; 3861 int a_fflags; 3862 void *a_wql; 3863 vfs_context_t a_context; 3864}; 3865#endif /* 0*/ 3866errno_t 3867VNOP_SELECT(vnode_t vp, int which , int fflags, void * wql, vfs_context_t ctx) 3868{ 3869 int _err; 3870 struct vnop_select_args a; 3871#if CONFIG_VFS_FUNNEL 3872 int thread_safe; 3873 int funnel_state = 0; 3874#endif /* CONFIG_VFS_FUNNEL */ 3875 3876 if (ctx == NULL) { 3877 ctx = vfs_context_current(); 3878 } 3879 a.a_desc = &vnop_select_desc; 3880 a.a_vp = vp; 3881 a.a_which = which; 3882 a.a_fflags = fflags; 3883 a.a_context = ctx; 3884 a.a_wql = wql; 3885 3886#if CONFIG_VFS_FUNNEL 3887 thread_safe = THREAD_SAFE_FS(vp); 3888 if (!thread_safe) { 3889 funnel_state = thread_funnel_set(kernel_flock, TRUE); 3890 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3891 if ( (_err = lock_fsnode(vp, NULL)) ) { 3892 (void) thread_funnel_set(kernel_flock, funnel_state); 3893 return (_err); 3894 } 3895 } 3896 } 3897#endif /* CONFIG_VFS_FUNNEL */ 3898 3899 _err = (*vp->v_op[vnop_select_desc.vdesc_offset])(&a); 3900 3901#if CONFIG_VFS_FUNNEL 3902 if (!thread_safe) { 3903 if (vp->v_type != VCHR && vp->v_type != VFIFO && vp->v_type != VSOCK) { 3904 unlock_fsnode(vp, NULL); 3905 } 3906 (void) thread_funnel_set(kernel_flock, funnel_state); 3907 } 3908#endif /* CONFIG_VFS_FUNNEL */ 3909 3910 return (_err); 3911} 3912 3913 3914#if 0 3915/* 3916 *# 3917 *#% exchange fvp L L L 3918 *#% exchange tvp L L L 3919 *# 3920 */ 3921struct vnop_exchange_args { 3922 struct vnodeop_desc *a_desc; 3923 vnode_t a_fvp; 3924 vnode_t a_tvp; 3925 int a_options; 3926 vfs_context_t a_context; 3927}; 3928#endif /* 0*/ 3929errno_t 3930VNOP_EXCHANGE(vnode_t fvp, vnode_t tvp, int options, vfs_context_t ctx) 3931{ 3932 int _err; 3933 struct vnop_exchange_args a; 3934#if CONFIG_VFS_FUNNEL 3935 int thread_safe; 3936 int funnel_state = 0; 3937 vnode_t lock_first = NULL, lock_second = NULL; 3938#endif /* CONFIG_VFS_FUNNEL */ 3939 3940 a.a_desc = &vnop_exchange_desc; 3941 a.a_fvp = fvp; 3942 a.a_tvp = tvp; 3943 a.a_options = options; 3944 a.a_context = ctx; 3945 3946#if CONFIG_VFS_FUNNEL 3947 thread_safe = THREAD_SAFE_FS(fvp); 3948 if (!thread_safe) { 3949 /* 3950 * Lock in vnode address order to avoid deadlocks 3951 */ 3952 if (fvp < tvp) { 3953 lock_first = fvp; 3954 lock_second = tvp; 3955 } else { 3956 lock_first = tvp; 3957 lock_second = fvp; 3958 } 3959 if ( (_err = lock_fsnode(lock_first, &funnel_state)) ) { 3960 return (_err); 3961 } 3962 if ( (_err = lock_fsnode(lock_second, NULL)) ) { 3963 unlock_fsnode(lock_first, &funnel_state); 3964 return (_err); 3965 } 3966 } 3967#endif /* CONFIG_VFS_FUNNEL */ 3968 3969 _err = (*fvp->v_op[vnop_exchange_desc.vdesc_offset])(&a); 3970 3971#if CONFIG_VFS_FUNNEL 3972 if (!thread_safe) { 3973 unlock_fsnode(lock_second, NULL); 3974 unlock_fsnode(lock_first, &funnel_state); 3975 } 3976#endif /* CONFIG_VFS_FUNNEL */ 3977 3978 /* Don't post NOTE_WRITE because file descriptors follow the data ... */ 3979 post_event_if_success(fvp, _err, NOTE_ATTRIB); 3980 post_event_if_success(tvp, _err, NOTE_ATTRIB); 3981 3982 return (_err); 3983} 3984 3985 3986#if 0 3987/* 3988 *# 3989 *#% revoke vp U U U 3990 *# 3991 */ 3992struct vnop_revoke_args { 3993 struct vnodeop_desc *a_desc; 3994 vnode_t a_vp; 3995 int a_flags; 3996 vfs_context_t a_context; 3997}; 3998#endif /* 0*/ 3999errno_t 4000VNOP_REVOKE(vnode_t vp, int flags, vfs_context_t ctx) 4001{ 4002 struct vnop_revoke_args a; 4003 int _err; 4004#if CONFIG_VFS_FUNNEL 4005 int thread_safe; 4006 int funnel_state = 0; 4007#endif /* CONFIG_VFS_FUNNEL */ 4008 4009 a.a_desc = &vnop_revoke_desc; 4010 a.a_vp = vp; 4011 a.a_flags = flags; 4012 a.a_context = ctx; 4013 4014#if CONFIG_VFS_FUNNEL 4015 thread_safe = THREAD_SAFE_FS(vp); 4016 if (!thread_safe) { 4017 funnel_state = thread_funnel_set(kernel_flock, TRUE); 4018 } 4019#endif /* CONFIG_VFS_FUNNEL */ 4020 4021 _err = (*vp->v_op[vnop_revoke_desc.vdesc_offset])(&a); 4022 4023#if CONFIG_VFS_FUNNEL 4024 if (!thread_safe) { 4025 (void) thread_funnel_set(kernel_flock, funnel_state); 4026 } 4027#endif /* CONFIG_VFS_FUNNEL */ 4028 4029 return (_err); 4030} 4031 4032 4033#if 0 4034/* 4035 *# 4036 *# mmap - vp U U U 4037 *# 4038 */ 4039struct vnop_mmap_args { 4040 struct vnodeop_desc *a_desc; 4041 vnode_t a_vp; 4042 int a_fflags; 4043 vfs_context_t a_context; 4044}; 4045#endif /* 0*/ 4046errno_t 4047VNOP_MMAP(vnode_t vp, int fflags, vfs_context_t ctx) 4048{ 4049 int _err; 4050 struct vnop_mmap_args a; 4051#if CONFIG_VFS_FUNNEL 4052 int thread_safe; 4053 int funnel_state = 0; 4054#endif /* CONFIG_VFS_FUNNEL */ 4055 4056 a.a_desc = &vnop_mmap_desc; 4057 a.a_vp = vp; 4058 a.a_fflags = fflags; 4059 a.a_context = ctx; 4060 4061#if CONFIG_VFS_FUNNEL 4062 thread_safe = THREAD_SAFE_FS(vp); 4063 if (!thread_safe) { 4064 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 4065 return (_err); 4066 } 4067 } 4068#endif /* CONFIG_VFS_FUNNEL */ 4069 4070 _err = (*vp->v_op[vnop_mmap_desc.vdesc_offset])(&a); 4071 4072#if CONFIG_VFS_FUNNEL 4073 if (!thread_safe) { 4074 unlock_fsnode(vp, &funnel_state); 4075 } 4076#endif /* CONFIG_VFS_FUNNEL */ 4077 4078 return (_err); 4079} 4080 4081 4082#if 0 4083/* 4084 *# 4085 *# mnomap - vp U U U 4086 *# 4087 */ 4088struct vnop_mnomap_args { 4089 struct vnodeop_desc *a_desc; 4090 vnode_t a_vp; 4091 vfs_context_t a_context; 4092}; 4093#endif /* 0*/ 4094errno_t 4095VNOP_MNOMAP(vnode_t vp, vfs_context_t ctx) 4096{ 4097 int _err; 4098 struct vnop_mnomap_args a; 4099#if CONFIG_VFS_FUNNEL 4100 int thread_safe; 4101 int funnel_state = 0; 4102#endif /* CONFIG_VFS_FUNNEL */ 4103 4104 a.a_desc = &vnop_mnomap_desc; 4105 a.a_vp = vp; 4106 a.a_context = ctx; 4107 4108#if CONFIG_VFS_FUNNEL 4109 thread_safe = THREAD_SAFE_FS(vp); 4110 if (!thread_safe) { 4111 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 4112 return (_err); 4113 } 4114 } 4115#endif /* CONFIG_VFS_FUNNEL */ 4116 4117 _err = (*vp->v_op[vnop_mnomap_desc.vdesc_offset])(&a); 4118 4119#if CONFIG_VFS_FUNNEL 4120 if (!thread_safe) { 4121 unlock_fsnode(vp, &funnel_state); 4122 } 4123#endif /* CONFIG_VFS_FUNNEL */ 4124 4125 return (_err); 4126} 4127 4128 4129#if 0 4130/* 4131 *# 4132 *#% fsync vp L L L 4133 *# 4134 */ 4135struct vnop_fsync_args { 4136 struct vnodeop_desc *a_desc; 4137 vnode_t a_vp; 4138 int a_waitfor; 4139 vfs_context_t a_context; 4140}; 4141#endif /* 0*/ 4142errno_t 4143VNOP_FSYNC(vnode_t vp, int waitfor, vfs_context_t ctx) 4144{ 4145 struct vnop_fsync_args a; 4146 int _err; 4147#if CONFIG_VFS_FUNNEL 4148 int thread_safe; 4149 int funnel_state = 0; 4150#endif /* CONFIG_VFS_FUNNEL */ 4151 4152 a.a_desc = &vnop_fsync_desc; 4153 a.a_vp = vp; 4154 a.a_waitfor = waitfor; 4155 a.a_context = ctx; 4156 4157#if CONFIG_VFS_FUNNEL 4158 thread_safe = THREAD_SAFE_FS(vp); 4159 if (!thread_safe) { 4160 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 4161 return (_err); 4162 } 4163 } 4164#endif /* CONFIG_VFS_FUNNEL */ 4165 4166 _err = (*vp->v_op[vnop_fsync_desc.vdesc_offset])(&a); 4167 4168#if CONFIG_VFS_FUNNEL 4169 if (!thread_safe) { 4170 unlock_fsnode(vp, &funnel_state); 4171 } 4172#endif /* CONFIG_VFS_FUNNEL */ 4173 4174 return (_err); 4175} 4176 4177 4178#if 0 4179/* 4180 *# 4181 *#% remove dvp L U U 4182 *#% remove vp L U U 4183 *# 4184 */ 4185struct vnop_remove_args { 4186 struct vnodeop_desc *a_desc; 4187 vnode_t a_dvp; 4188 vnode_t a_vp; 4189 struct componentname *a_cnp; 4190 int a_flags; 4191 vfs_context_t a_context; 4192}; 4193#endif /* 0*/ 4194errno_t 4195VNOP_REMOVE(vnode_t dvp, vnode_t vp, struct componentname * cnp, int flags, vfs_context_t ctx) 4196{ 4197 int _err; 4198 struct vnop_remove_args a; 4199#if CONFIG_VFS_FUNNEL 4200 int thread_safe; 4201 int funnel_state = 0; 4202#endif /* CONFIG_VFS_FUNNEL */ 4203 4204 a.a_desc = &vnop_remove_desc; 4205 a.a_dvp = dvp; 4206 a.a_vp = vp; 4207 a.a_cnp = cnp; 4208 a.a_flags = flags; 4209 a.a_context = ctx; 4210 4211#if CONFIG_VFS_FUNNEL 4212 thread_safe = THREAD_SAFE_FS(dvp); 4213 if (!thread_safe) { 4214 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 4215 return (_err); 4216 } 4217 } 4218#endif /* CONFIG_VFS_FUNNEL */ 4219 4220 _err = (*dvp->v_op[vnop_remove_desc.vdesc_offset])(&a); 4221 4222 if (_err == 0) { 4223 vnode_setneedinactive(vp); 4224 4225 if ( !(NATIVE_XATTR(dvp)) ) { 4226 /* 4227 * Remove any associated extended attribute file (._ AppleDouble file). 4228 */ 4229 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 1); 4230 } 4231 } 4232 4233#if CONFIG_VFS_FUNNEL 4234 if (!thread_safe) { 4235 unlock_fsnode(vp, &funnel_state); 4236 } 4237#endif /* CONFIG_VFS_FUNNEL */ 4238 4239 post_event_if_success(vp, _err, NOTE_DELETE | NOTE_LINK); 4240 post_event_if_success(dvp, _err, NOTE_WRITE); 4241 4242 return (_err); 4243} 4244 4245int 4246VNOP_COMPOUND_REMOVE(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, struct vnode_attr *vap, vfs_context_t ctx) 4247{ 4248 int _err; 4249 struct vnop_compound_remove_args a; 4250 int no_vp = (*vpp == NULLVP); 4251 4252 a.a_desc = &vnop_compound_remove_desc; 4253 a.a_dvp = dvp; 4254 a.a_vpp = vpp; 4255 a.a_cnp = &ndp->ni_cnd; 4256 a.a_flags = flags; 4257 a.a_vap = vap; 4258 a.a_context = ctx; 4259 a.a_remove_authorizer = vn_authorize_unlink; 4260 4261 _err = (*dvp->v_op[vnop_compound_remove_desc.vdesc_offset])(&a); 4262 if (_err == 0) { 4263 vnode_setneedinactive(*vpp); 4264 4265 if ( !(NATIVE_XATTR(dvp)) ) { 4266 /* 4267 * Remove any associated extended attribute file (._ AppleDouble file). 4268 */ 4269 xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 1); 4270 } 4271 } 4272 4273 post_event_if_success(*vpp, _err, NOTE_DELETE | NOTE_LINK); 4274 post_event_if_success(dvp, _err, NOTE_WRITE); 4275 4276 if (no_vp) { 4277 lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, 0); 4278 if (*vpp && _err && _err != EKEEPLOOKING) { 4279 vnode_put(*vpp); 4280 *vpp = NULLVP; 4281 } 4282 } 4283 4284 //printf("VNOP_COMPOUND_REMOVE() returning %d\n", _err); 4285 4286 return (_err); 4287} 4288 4289#if 0 4290/* 4291 *# 4292 *#% link vp U U U 4293 *#% link tdvp L U U 4294 *# 4295 */ 4296struct vnop_link_args { 4297 struct vnodeop_desc *a_desc; 4298 vnode_t a_vp; 4299 vnode_t a_tdvp; 4300 struct componentname *a_cnp; 4301 vfs_context_t a_context; 4302}; 4303#endif /* 0*/ 4304errno_t 4305VNOP_LINK(vnode_t vp, vnode_t tdvp, struct componentname * cnp, vfs_context_t ctx) 4306{ 4307 int _err; 4308 struct vnop_link_args a; 4309#if CONFIG_VFS_FUNNEL 4310 int thread_safe; 4311 int funnel_state = 0; 4312#endif /* CONFIG_VFS_FUNNEL */ 4313 4314 /* 4315 * For file systems with non-native extended attributes, 4316 * disallow linking to an existing "._" Apple Double file. 4317 */ 4318 if ( !NATIVE_XATTR(tdvp) && (vp->v_type == VREG)) { 4319 const char *vname; 4320 4321 vname = vnode_getname(vp); 4322 if (vname != NULL) { 4323 _err = 0; 4324 if (vname[0] == '.' && vname[1] == '_' && vname[2] != '\0') { 4325 _err = EPERM; 4326 } 4327 vnode_putname(vname); 4328 if (_err) 4329 return (_err); 4330 } 4331 } 4332 a.a_desc = &vnop_link_desc; 4333 a.a_vp = vp; 4334 a.a_tdvp = tdvp; 4335 a.a_cnp = cnp; 4336 a.a_context = ctx; 4337 4338#if CONFIG_VFS_FUNNEL 4339 thread_safe = THREAD_SAFE_FS(vp); 4340 if (!thread_safe) { 4341 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 4342 return (_err); 4343 } 4344 } 4345#endif /* CONFIG_VFS_FUNNEL */ 4346 4347 _err = (*tdvp->v_op[vnop_link_desc.vdesc_offset])(&a); 4348 4349#if CONFIG_VFS_FUNNEL 4350 if (!thread_safe) { 4351 unlock_fsnode(vp, &funnel_state); 4352 } 4353#endif /* CONFIG_VFS_FUNNEL */ 4354 4355 post_event_if_success(vp, _err, NOTE_LINK); 4356 post_event_if_success(tdvp, _err, NOTE_WRITE); 4357 4358 return (_err); 4359} 4360 4361errno_t 4362vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, struct vnode_attr *fvap, 4363 struct vnode *tdvp, struct vnode **tvpp, struct componentname *tcnp, struct vnode_attr *tvap, 4364 uint32_t flags, vfs_context_t ctx) 4365{ 4366 int _err; 4367 vnode_t src_attr_vp = NULLVP; 4368 vnode_t dst_attr_vp = NULLVP; 4369 struct nameidata *fromnd = NULL; 4370 struct nameidata *tond = NULL; 4371 char smallname1[48]; 4372 char smallname2[48]; 4373 char *xfromname = NULL; 4374 char *xtoname = NULL; 4375 int batched; 4376 4377 batched = vnode_compound_rename_available(fdvp); 4378 4379#if CONFIG_VFS_FUNNEL 4380 vnode_t fdvp_unsafe = (THREAD_SAFE_FS(fdvp) ? NULLVP : fdvp); 4381#endif /* CONFIG_VFS_FUNNEL */ 4382 4383 if (!batched) { 4384 if (*fvpp == NULLVP) 4385 panic("Not batched, and no fvp?"); 4386 } 4387 4388 /* 4389 * We need to preflight any potential AppleDouble file for the source file 4390 * before doing the rename operation, since we could potentially be doing 4391 * this operation on a network filesystem, and would end up duplicating 4392 * the work. Also, save the source and destination names. Skip it if the 4393 * source has a "._" prefix. 4394 */ 4395 4396 if (!NATIVE_XATTR(fdvp) && 4397 !(fcnp->cn_nameptr[0] == '.' && fcnp->cn_nameptr[1] == '_')) { 4398 size_t len; 4399 int error; 4400 4401 /* Get source attribute file name. */ 4402 len = fcnp->cn_namelen + 3; 4403 if (len > sizeof(smallname1)) { 4404 MALLOC(xfromname, char *, len, M_TEMP, M_WAITOK); 4405 } else { 4406 xfromname = &smallname1[0]; 4407 } 4408 strlcpy(xfromname, "._", min(sizeof smallname1, len)); 4409 strncat(xfromname, fcnp->cn_nameptr, fcnp->cn_namelen); 4410 xfromname[len-1] = '\0'; 4411 4412 /* Get destination attribute file name. */ 4413 len = tcnp->cn_namelen + 3; 4414 if (len > sizeof(smallname2)) { 4415 MALLOC(xtoname, char *, len, M_TEMP, M_WAITOK); 4416 } else { 4417 xtoname = &smallname2[0]; 4418 } 4419 strlcpy(xtoname, "._", min(sizeof smallname2, len)); 4420 strncat(xtoname, tcnp->cn_nameptr, tcnp->cn_namelen); 4421 xtoname[len-1] = '\0'; 4422 4423 /* 4424 * Look up source attribute file, keep reference on it if exists. 4425 * Note that we do the namei with the nameiop of RENAME, which is different than 4426 * in the rename syscall. It's OK if the source file does not exist, since this 4427 * is only for AppleDouble files. 4428 */ 4429 if (xfromname != NULL) { 4430 MALLOC(fromnd, struct nameidata *, sizeof (struct nameidata), M_TEMP, M_WAITOK); 4431 NDINIT(fromnd, RENAME, OP_RENAME, NOFOLLOW | USEDVP | CN_NBMOUNTLOOK, 4432 UIO_SYSSPACE, CAST_USER_ADDR_T(xfromname), ctx); 4433 fromnd->ni_dvp = fdvp; 4434 error = namei(fromnd); 4435 4436 /* 4437 * If there was an error looking up source attribute file, 4438 * we'll behave as if it didn't exist. 4439 */ 4440 4441 if (error == 0) { 4442 if (fromnd->ni_vp) { 4443 /* src_attr_vp indicates need to call vnode_put / nameidone later */ 4444 src_attr_vp = fromnd->ni_vp; 4445 4446 if (fromnd->ni_vp->v_type != VREG) { 4447 src_attr_vp = NULLVP; 4448 vnode_put(fromnd->ni_vp); 4449 } 4450 } 4451 /* 4452 * Either we got an invalid vnode type (not a regular file) or the namei lookup 4453 * suppressed ENOENT as a valid error since we're renaming. Either way, we don't 4454 * have a vnode here, so we drop our namei buffer for the source attribute file 4455 */ 4456 if (src_attr_vp == NULLVP) { 4457 nameidone(fromnd); 4458 } 4459 } 4460 } 4461 } 4462 4463 if (batched) { 4464 _err = VNOP_COMPOUND_RENAME(fdvp, fvpp, fcnp, fvap, tdvp, tvpp, tcnp, tvap, flags, ctx); 4465 if (_err != 0) { 4466 printf("VNOP_COMPOUND_RENAME() returned %d\n", _err); 4467 } 4468 4469 } else { 4470 _err = VNOP_RENAME(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, ctx); 4471 } 4472 4473 if (_err == 0) { 4474 mac_vnode_notify_rename(ctx, *fvpp, tdvp, tcnp); 4475 } 4476 4477 /* 4478 * Rename any associated extended attribute file (._ AppleDouble file). 4479 */ 4480 if (_err == 0 && !NATIVE_XATTR(fdvp) && xfromname != NULL) { 4481 int error = 0; 4482 4483 /* 4484 * Get destination attribute file vnode. 4485 * Note that tdvp already has an iocount reference. Make sure to check that we 4486 * get a valid vnode from namei. 4487 */ 4488 MALLOC(tond, struct nameidata *, sizeof(struct nameidata), M_TEMP, M_WAITOK); 4489 NDINIT(tond, RENAME, OP_RENAME, 4490 NOCACHE | NOFOLLOW | USEDVP | CN_NBMOUNTLOOK, UIO_SYSSPACE, 4491 CAST_USER_ADDR_T(xtoname), ctx); 4492 tond->ni_dvp = tdvp; 4493 error = namei(tond); 4494 4495 if (error) 4496 goto out; 4497 4498 if (tond->ni_vp) { 4499 dst_attr_vp = tond->ni_vp; 4500 } 4501 4502 if (src_attr_vp) { 4503 const char *old_name = src_attr_vp->v_name; 4504 vnode_t old_parent = src_attr_vp->v_parent; 4505 4506 if (batched) { 4507 error = VNOP_COMPOUND_RENAME(fdvp, &src_attr_vp, &fromnd->ni_cnd, NULL, 4508 tdvp, &dst_attr_vp, &tond->ni_cnd, NULL, 4509 0, ctx); 4510 } else { 4511 error = VNOP_RENAME(fdvp, src_attr_vp, &fromnd->ni_cnd, 4512 tdvp, dst_attr_vp, &tond->ni_cnd, ctx); 4513 } 4514 4515 if (error == 0 && old_name == src_attr_vp->v_name && 4516 old_parent == src_attr_vp->v_parent) { 4517 int update_flags = VNODE_UPDATE_NAME; 4518 4519 if (fdvp != tdvp) 4520 update_flags |= VNODE_UPDATE_PARENT; 4521 4522 vnode_update_identity(src_attr_vp, tdvp, 4523 tond->ni_cnd.cn_nameptr, 4524 tond->ni_cnd.cn_namelen, 4525 tond->ni_cnd.cn_hash, 4526 update_flags); 4527 } 4528 4529 /* kevent notifications for moving resource files 4530 * _err is zero if we're here, so no need to notify directories, code 4531 * below will do that. only need to post the rename on the source and 4532 * possibly a delete on the dest 4533 */ 4534 post_event_if_success(src_attr_vp, error, NOTE_RENAME); 4535 if (dst_attr_vp) { 4536 post_event_if_success(dst_attr_vp, error, NOTE_DELETE); 4537 } 4538 4539 } else if (dst_attr_vp) { 4540 /* 4541 * Just delete destination attribute file vnode if it exists, since 4542 * we didn't have a source attribute file. 4543 * Note that tdvp already has an iocount reference. 4544 */ 4545 4546 struct vnop_remove_args args; 4547 4548 args.a_desc = &vnop_remove_desc; 4549 args.a_dvp = tdvp; 4550 args.a_vp = dst_attr_vp; 4551 args.a_cnp = &tond->ni_cnd; 4552 args.a_context = ctx; 4553 4554#if CONFIG_VFS_FUNNEL 4555 if (fdvp_unsafe != NULLVP) 4556 error = lock_fsnode(dst_attr_vp, NULL); 4557#endif /* CONFIG_VFS_FUNNEL */ 4558 if (error == 0) { 4559 error = (*tdvp->v_op[vnop_remove_desc.vdesc_offset])(&args); 4560 4561#if CONFIG_VFS_FUNNEL 4562 if (fdvp_unsafe != NULLVP) 4563 unlock_fsnode(dst_attr_vp, NULL); 4564#endif /* CONFIG_VFS_FUNNEL */ 4565 4566 if (error == 0) 4567 vnode_setneedinactive(dst_attr_vp); 4568 } 4569 4570 /* kevent notification for deleting the destination's attribute file 4571 * if it existed. Only need to post the delete on the destination, since 4572 * the code below will handle the directories. 4573 */ 4574 post_event_if_success(dst_attr_vp, error, NOTE_DELETE); 4575 } 4576 } 4577out: 4578 if (src_attr_vp) { 4579 vnode_put(src_attr_vp); 4580 nameidone(fromnd); 4581 } 4582 if (dst_attr_vp) { 4583 vnode_put(dst_attr_vp); 4584 nameidone(tond); 4585 } 4586 if (fromnd) { 4587 FREE(fromnd, M_TEMP); 4588 } 4589 if (tond) { 4590 FREE(tond, M_TEMP); 4591 } 4592 if (xfromname && xfromname != &smallname1[0]) { 4593 FREE(xfromname, M_TEMP); 4594 } 4595 if (xtoname && xtoname != &smallname2[0]) { 4596 FREE(xtoname, M_TEMP); 4597 } 4598 4599 return _err; 4600} 4601 4602 4603#if 0 4604/* 4605 *# 4606 *#% rename fdvp U U U 4607 *#% rename fvp U U U 4608 *#% rename tdvp L U U 4609 *#% rename tvp X U U 4610 *# 4611 */ 4612struct vnop_rename_args { 4613 struct vnodeop_desc *a_desc; 4614 vnode_t a_fdvp; 4615 vnode_t a_fvp; 4616 struct componentname *a_fcnp; 4617 vnode_t a_tdvp; 4618 vnode_t a_tvp; 4619 struct componentname *a_tcnp; 4620 vfs_context_t a_context; 4621}; 4622#endif /* 0*/ 4623errno_t 4624VNOP_RENAME(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp, 4625 struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp, 4626 vfs_context_t ctx) 4627{ 4628 int _err = 0; 4629 int events; 4630 struct vnop_rename_args a; 4631#if CONFIG_VFS_FUNNEL 4632 int funnel_state = 0; 4633 vnode_t lock_first = NULL, lock_second = NULL; 4634 vnode_t fdvp_unsafe = NULLVP; 4635 vnode_t tdvp_unsafe = NULLVP; 4636#endif /* CONFIG_VFS_FUNNEL */ 4637 4638 a.a_desc = &vnop_rename_desc; 4639 a.a_fdvp = fdvp; 4640 a.a_fvp = fvp; 4641 a.a_fcnp = fcnp; 4642 a.a_tdvp = tdvp; 4643 a.a_tvp = tvp; 4644 a.a_tcnp = tcnp; 4645 a.a_context = ctx; 4646 4647#if CONFIG_VFS_FUNNEL 4648 if (!THREAD_SAFE_FS(fdvp)) 4649 fdvp_unsafe = fdvp; 4650 if (!THREAD_SAFE_FS(tdvp)) 4651 tdvp_unsafe = tdvp; 4652 4653 if (fdvp_unsafe != NULLVP) { 4654 /* 4655 * Lock parents in vnode address order to avoid deadlocks 4656 * note that it's possible for the fdvp to be unsafe, 4657 * but the tdvp to be safe because tvp could be a directory 4658 * in the root of a filesystem... in that case, tdvp is the 4659 * in the filesystem that this root is mounted on 4660 */ 4661 if (tdvp_unsafe == NULL || fdvp_unsafe == tdvp_unsafe) { 4662 lock_first = fdvp_unsafe; 4663 lock_second = NULL; 4664 } else if (fdvp_unsafe < tdvp_unsafe) { 4665 lock_first = fdvp_unsafe; 4666 lock_second = tdvp_unsafe; 4667 } else { 4668 lock_first = tdvp_unsafe; 4669 lock_second = fdvp_unsafe; 4670 } 4671 if ( (_err = lock_fsnode(lock_first, &funnel_state)) ) 4672 return (_err); 4673 4674 if (lock_second != NULL && (_err = lock_fsnode(lock_second, NULL))) { 4675 unlock_fsnode(lock_first, &funnel_state); 4676 return (_err); 4677 } 4678 4679 /* 4680 * Lock both children in vnode address order to avoid deadlocks 4681 */ 4682 if (tvp == NULL || tvp == fvp) { 4683 lock_first = fvp; 4684 lock_second = NULL; 4685 } else if (fvp < tvp) { 4686 lock_first = fvp; 4687 lock_second = tvp; 4688 } else { 4689 lock_first = tvp; 4690 lock_second = fvp; 4691 } 4692 if ( (_err = lock_fsnode(lock_first, NULL)) ) 4693 goto out1; 4694 4695 if (lock_second != NULL && (_err = lock_fsnode(lock_second, NULL))) { 4696 unlock_fsnode(lock_first, NULL); 4697 goto out1; 4698 } 4699 } 4700#endif /* CONFIG_VFS_FUNNEL */ 4701 4702 /* do the rename of the main file. */ 4703 _err = (*fdvp->v_op[vnop_rename_desc.vdesc_offset])(&a); 4704 4705#if CONFIG_VFS_FUNNEL 4706 if (fdvp_unsafe != NULLVP) { 4707 if (lock_second != NULL) 4708 unlock_fsnode(lock_second, NULL); 4709 unlock_fsnode(lock_first, NULL); 4710 } 4711#endif /* CONFIG_VFS_FUNNEL */ 4712 4713 if (_err == 0) { 4714 if (tvp && tvp != fvp) 4715 vnode_setneedinactive(tvp); 4716 } 4717 4718#if CONFIG_VFS_FUNNEL 4719out1: 4720 if (fdvp_unsafe != NULLVP) { 4721 if (tdvp_unsafe != NULLVP) 4722 unlock_fsnode(tdvp_unsafe, NULL); 4723 unlock_fsnode(fdvp_unsafe, &funnel_state); 4724 } 4725#endif /* CONFIG_VFS_FUNNEL */ 4726 4727 /* Wrote at least one directory. If transplanted a dir, also changed link counts */ 4728 if (0 == _err) { 4729 events = NOTE_WRITE; 4730 if (vnode_isdir(fvp)) { 4731 /* Link count on dir changed only if we are moving a dir and... 4732 * --Moved to new dir, not overwriting there 4733 * --Kept in same dir and DID overwrite 4734 */ 4735 if (((fdvp != tdvp) && (!tvp)) || ((fdvp == tdvp) && (tvp))) { 4736 events |= NOTE_LINK; 4737 } 4738 } 4739 4740 lock_vnode_and_post(fdvp, events); 4741 if (fdvp != tdvp) { 4742 lock_vnode_and_post(tdvp, events); 4743 } 4744 4745 /* If you're replacing the target, post a deletion for it */ 4746 if (tvp) 4747 { 4748 lock_vnode_and_post(tvp, NOTE_DELETE); 4749 } 4750 4751 lock_vnode_and_post(fvp, NOTE_RENAME); 4752 } 4753 4754 return (_err); 4755} 4756 4757int 4758VNOP_COMPOUND_RENAME( 4759 struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, struct vnode_attr *fvap, 4760 struct vnode *tdvp, struct vnode **tvpp, struct componentname *tcnp, struct vnode_attr *tvap, 4761 uint32_t flags, vfs_context_t ctx) 4762{ 4763 int _err = 0; 4764 int events; 4765 struct vnop_compound_rename_args a; 4766 int no_fvp, no_tvp; 4767 4768 no_fvp = (*fvpp) == NULLVP; 4769 no_tvp = (*tvpp) == NULLVP; 4770 4771 a.a_desc = &vnop_compound_rename_desc; 4772 4773 a.a_fdvp = fdvp; 4774 a.a_fvpp = fvpp; 4775 a.a_fcnp = fcnp; 4776 a.a_fvap = fvap; 4777 4778 a.a_tdvp = tdvp; 4779 a.a_tvpp = tvpp; 4780 a.a_tcnp = tcnp; 4781 a.a_tvap = tvap; 4782 4783 a.a_flags = flags; 4784 a.a_context = ctx; 4785 a.a_rename_authorizer = vn_authorize_rename; 4786 a.a_reserved = NULL; 4787 4788 /* do the rename of the main file. */ 4789 _err = (*fdvp->v_op[vnop_compound_rename_desc.vdesc_offset])(&a); 4790 4791 if (_err == 0) { 4792 if (*tvpp && *tvpp != *fvpp) 4793 vnode_setneedinactive(*tvpp); 4794 } 4795 4796 /* Wrote at least one directory. If transplanted a dir, also changed link counts */ 4797 if (0 == _err && *fvpp != *tvpp) { 4798 if (!*fvpp) { 4799 panic("No fvpp after compound rename?"); 4800 } 4801 4802 events = NOTE_WRITE; 4803 if (vnode_isdir(*fvpp)) { 4804 /* Link count on dir changed only if we are moving a dir and... 4805 * --Moved to new dir, not overwriting there 4806 * --Kept in same dir and DID overwrite 4807 */ 4808 if (((fdvp != tdvp) && (!*tvpp)) || ((fdvp == tdvp) && (*tvpp))) { 4809 events |= NOTE_LINK; 4810 } 4811 } 4812 4813 lock_vnode_and_post(fdvp, events); 4814 if (fdvp != tdvp) { 4815 lock_vnode_and_post(tdvp, events); 4816 } 4817 4818 /* If you're replacing the target, post a deletion for it */ 4819 if (*tvpp) 4820 { 4821 lock_vnode_and_post(*tvpp, NOTE_DELETE); 4822 } 4823 4824 lock_vnode_and_post(*fvpp, NOTE_RENAME); 4825 } 4826 4827 if (no_fvp) { 4828 lookup_compound_vnop_post_hook(_err, fdvp, *fvpp, fcnp->cn_ndp, 0); 4829 } 4830 if (no_tvp && *tvpp != NULLVP) { 4831 lookup_compound_vnop_post_hook(_err, tdvp, *tvpp, tcnp->cn_ndp, 0); 4832 } 4833 4834 if (_err && _err != EKEEPLOOKING) { 4835 if (*fvpp) { 4836 vnode_put(*fvpp); 4837 *fvpp = NULLVP; 4838 } 4839 if (*tvpp) { 4840 vnode_put(*tvpp); 4841 *tvpp = NULLVP; 4842 } 4843 } 4844 4845 return (_err); 4846} 4847 4848int 4849vn_mkdir(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp, 4850 struct vnode_attr *vap, vfs_context_t ctx) 4851{ 4852 if (ndp->ni_cnd.cn_nameiop != CREATE) { 4853 panic("Non-CREATE nameiop in vn_mkdir()?"); 4854 } 4855 4856 if (vnode_compound_mkdir_available(dvp)) { 4857 return VNOP_COMPOUND_MKDIR(dvp, vpp, ndp, vap, ctx); 4858 } else { 4859 return VNOP_MKDIR(dvp, vpp, &ndp->ni_cnd, vap, ctx); 4860 } 4861} 4862 4863 #if 0 4864/* 4865 *# 4866 *#% mkdir dvp L U U 4867 *#% mkdir vpp - L - 4868 *# 4869 */ 4870struct vnop_mkdir_args { 4871 struct vnodeop_desc *a_desc; 4872 vnode_t a_dvp; 4873 vnode_t *a_vpp; 4874 struct componentname *a_cnp; 4875 struct vnode_attr *a_vap; 4876 vfs_context_t a_context; 4877}; 4878#endif /* 0*/ 4879errno_t 4880VNOP_MKDIR(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, 4881 struct vnode_attr *vap, vfs_context_t ctx) 4882{ 4883 int _err; 4884 struct vnop_mkdir_args a; 4885#if CONFIG_VFS_FUNNEL 4886 int thread_safe; 4887 int funnel_state = 0; 4888#endif /* CONFIG_VFS_FUNNEL */ 4889 4890 a.a_desc = &vnop_mkdir_desc; 4891 a.a_dvp = dvp; 4892 a.a_vpp = vpp; 4893 a.a_cnp = cnp; 4894 a.a_vap = vap; 4895 a.a_context = ctx; 4896 4897#if CONFIG_VFS_FUNNEL 4898 thread_safe = THREAD_SAFE_FS(dvp); 4899 if (!thread_safe) { 4900 if ( (_err = lock_fsnode(dvp, &funnel_state)) ) { 4901 return (_err); 4902 } 4903 } 4904#endif /* CONFIG_VFS_FUNNEL */ 4905 4906 _err = (*dvp->v_op[vnop_mkdir_desc.vdesc_offset])(&a); 4907 if (_err == 0 && !NATIVE_XATTR(dvp)) { 4908 /* 4909 * Remove stale Apple Double file (if any). 4910 */ 4911 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0); 4912 } 4913 4914#if CONFIG_VFS_FUNNEL 4915 if (!thread_safe) { 4916 unlock_fsnode(dvp, &funnel_state); 4917 } 4918#endif /* CONFIG_VFS_FUNNEL */ 4919 4920 post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE); 4921 4922 return (_err); 4923} 4924 4925int 4926VNOP_COMPOUND_MKDIR(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp, 4927 struct vnode_attr *vap, vfs_context_t ctx) 4928{ 4929 int _err; 4930 struct vnop_compound_mkdir_args a; 4931 4932 a.a_desc = &vnop_compound_mkdir_desc; 4933 a.a_dvp = dvp; 4934 a.a_vpp = vpp; 4935 a.a_cnp = &ndp->ni_cnd; 4936 a.a_vap = vap; 4937 a.a_flags = 0; 4938 a.a_context = ctx; 4939#if 0 4940 a.a_mkdir_authorizer = vn_authorize_mkdir; 4941#endif /* 0 */ 4942 a.a_reserved = NULL; 4943 4944 _err = (*dvp->v_op[vnop_compound_mkdir_desc.vdesc_offset])(&a); 4945 if (_err == 0 && !NATIVE_XATTR(dvp)) { 4946 /* 4947 * Remove stale Apple Double file (if any). 4948 */ 4949 xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 0); 4950 } 4951 4952 post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE); 4953 4954 lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, (_err == 0)); 4955 if (*vpp && _err && _err != EKEEPLOOKING) { 4956 vnode_put(*vpp); 4957 *vpp = NULLVP; 4958 } 4959 4960 return (_err); 4961} 4962 4963int 4964vn_rmdir(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, struct vnode_attr *vap, vfs_context_t ctx) 4965{ 4966 if (vnode_compound_rmdir_available(dvp)) { 4967 return VNOP_COMPOUND_RMDIR(dvp, vpp, ndp, vap, ctx); 4968 } else { 4969 if (*vpp == NULLVP) { 4970 panic("NULL vp, but not a compound VNOP?"); 4971 } 4972 if (vap != NULL) { 4973 panic("Non-NULL vap, but not a compound VNOP?"); 4974 } 4975 return VNOP_RMDIR(dvp, *vpp, &ndp->ni_cnd, ctx); 4976 } 4977} 4978 4979#if 0 4980/* 4981 *# 4982 *#% rmdir dvp L U U 4983 *#% rmdir vp L U U 4984 *# 4985 */ 4986struct vnop_rmdir_args { 4987 struct vnodeop_desc *a_desc; 4988 vnode_t a_dvp; 4989 vnode_t a_vp; 4990 struct componentname *a_cnp; 4991 vfs_context_t a_context; 4992}; 4993 4994#endif /* 0*/ 4995errno_t 4996VNOP_RMDIR(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, vfs_context_t ctx) 4997{ 4998 int _err; 4999 struct vnop_rmdir_args a; 5000#if CONFIG_VFS_FUNNEL 5001 int thread_safe; 5002 int funnel_state = 0; 5003#endif /* CONFIG_VFS_FUNNEL */ 5004 5005 a.a_desc = &vnop_rmdir_desc; 5006 a.a_dvp = dvp; 5007 a.a_vp = vp; 5008 a.a_cnp = cnp; 5009 a.a_context = ctx; 5010 5011#if CONFIG_VFS_FUNNEL 5012 thread_safe = THREAD_SAFE_FS(dvp); 5013 if (!thread_safe) { 5014 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 5015 return (_err); 5016 } 5017 } 5018#endif /* CONFIG_VFS_FUNNEL */ 5019 5020 _err = (*vp->v_op[vnop_rmdir_desc.vdesc_offset])(&a); 5021 5022 if (_err == 0) { 5023 vnode_setneedinactive(vp); 5024 5025 if ( !(NATIVE_XATTR(dvp)) ) { 5026 /* 5027 * Remove any associated extended attribute file (._ AppleDouble file). 5028 */ 5029 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 1); 5030 } 5031 } 5032 5033#if CONFIG_VFS_FUNNEL 5034 if (!thread_safe) { 5035 unlock_fsnode(vp, &funnel_state); 5036 } 5037#endif /* CONFIG_VFS_FUNNEL */ 5038 5039 /* If you delete a dir, it loses its "." reference --> NOTE_LINK */ 5040 post_event_if_success(vp, _err, NOTE_DELETE | NOTE_LINK); 5041 post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE); 5042 5043 return (_err); 5044} 5045 5046int 5047VNOP_COMPOUND_RMDIR(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp, 5048 struct vnode_attr *vap, vfs_context_t ctx) 5049{ 5050 int _err; 5051 struct vnop_compound_rmdir_args a; 5052 int no_vp; 5053 5054 a.a_desc = &vnop_mkdir_desc; 5055 a.a_dvp = dvp; 5056 a.a_vpp = vpp; 5057 a.a_cnp = &ndp->ni_cnd; 5058 a.a_vap = vap; 5059 a.a_flags = 0; 5060 a.a_context = ctx; 5061 a.a_rmdir_authorizer = vn_authorize_rmdir; 5062 a.a_reserved = NULL; 5063 5064 no_vp = (*vpp == NULLVP); 5065 5066 _err = (*dvp->v_op[vnop_compound_rmdir_desc.vdesc_offset])(&a); 5067 if (_err == 0 && !NATIVE_XATTR(dvp)) { 5068 /* 5069 * Remove stale Apple Double file (if any). 5070 */ 5071 xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 0); 5072 } 5073 5074 if (*vpp) { 5075 post_event_if_success(*vpp, _err, NOTE_DELETE | NOTE_LINK); 5076 } 5077 post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE); 5078 5079 if (no_vp) { 5080 lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, 0); 5081 5082#if 0 /* Removing orphaned ._ files requires a vp.... */ 5083 if (*vpp && _err && _err != EKEEPLOOKING) { 5084 vnode_put(*vpp); 5085 *vpp = NULLVP; 5086 } 5087#endif /* 0 */ 5088 } 5089 5090 return (_err); 5091} 5092 5093/* 5094 * Remove a ._ AppleDouble file 5095 */ 5096#define AD_STALE_SECS (180) 5097static void 5098xattrfile_remove(vnode_t dvp, const char * basename, vfs_context_t ctx, int force) 5099{ 5100 vnode_t xvp; 5101 struct nameidata nd; 5102 char smallname[64]; 5103 char *filename = NULL; 5104 size_t len; 5105 5106 if ((basename == NULL) || (basename[0] == '\0') || 5107 (basename[0] == '.' && basename[1] == '_')) { 5108 return; 5109 } 5110 filename = &smallname[0]; 5111 len = snprintf(filename, sizeof(smallname), "._%s", basename); 5112 if (len >= sizeof(smallname)) { 5113 len++; /* snprintf result doesn't include '\0' */ 5114 MALLOC(filename, char *, len, M_TEMP, M_WAITOK); 5115 len = snprintf(filename, len, "._%s", basename); 5116 } 5117 NDINIT(&nd, DELETE, OP_UNLINK, WANTPARENT | LOCKLEAF | NOFOLLOW | USEDVP, UIO_SYSSPACE, 5118 CAST_USER_ADDR_T(filename), ctx); 5119 nd.ni_dvp = dvp; 5120 if (namei(&nd) != 0) 5121 goto out2; 5122 5123 xvp = nd.ni_vp; 5124 nameidone(&nd); 5125 if (xvp->v_type != VREG) 5126 goto out1; 5127 5128 /* 5129 * When creating a new object and a "._" file already 5130 * exists, check to see if its a stale "._" file. 5131 * 5132 */ 5133 if (!force) { 5134 struct vnode_attr va; 5135 5136 VATTR_INIT(&va); 5137 VATTR_WANTED(&va, va_data_size); 5138 VATTR_WANTED(&va, va_modify_time); 5139 if (VNOP_GETATTR(xvp, &va, ctx) == 0 && 5140 VATTR_IS_SUPPORTED(&va, va_data_size) && 5141 VATTR_IS_SUPPORTED(&va, va_modify_time) && 5142 va.va_data_size != 0) { 5143 struct timeval tv; 5144 5145 microtime(&tv); 5146 if ((tv.tv_sec > va.va_modify_time.tv_sec) && 5147 (tv.tv_sec - va.va_modify_time.tv_sec) > AD_STALE_SECS) { 5148 force = 1; /* must be stale */ 5149 } 5150 } 5151 } 5152 if (force) { 5153 int error; 5154 5155 error = VNOP_REMOVE(dvp, xvp, &nd.ni_cnd, 0, ctx); 5156 if (error == 0) 5157 vnode_setneedinactive(xvp); 5158 5159 post_event_if_success(xvp, error, NOTE_DELETE); 5160 post_event_if_success(dvp, error, NOTE_WRITE); 5161 } 5162 5163out1: 5164 vnode_put(dvp); 5165 vnode_put(xvp); 5166out2: 5167 if (filename && filename != &smallname[0]) { 5168 FREE(filename, M_TEMP); 5169 } 5170} 5171 5172/* 5173 * Shadow uid/gid/mod to a ._ AppleDouble file 5174 */ 5175static void 5176xattrfile_setattr(vnode_t dvp, const char * basename, struct vnode_attr * vap, 5177 vfs_context_t ctx) 5178{ 5179 vnode_t xvp; 5180 struct nameidata nd; 5181 char smallname[64]; 5182 char *filename = NULL; 5183 size_t len; 5184 5185 if ((dvp == NULLVP) || 5186 (basename == NULL) || (basename[0] == '\0') || 5187 (basename[0] == '.' && basename[1] == '_')) { 5188 return; 5189 } 5190 filename = &smallname[0]; 5191 len = snprintf(filename, sizeof(smallname), "._%s", basename); 5192 if (len >= sizeof(smallname)) { 5193 len++; /* snprintf result doesn't include '\0' */ 5194 MALLOC(filename, char *, len, M_TEMP, M_WAITOK); 5195 len = snprintf(filename, len, "._%s", basename); 5196 } 5197 NDINIT(&nd, LOOKUP, OP_SETATTR, NOFOLLOW | USEDVP, UIO_SYSSPACE, 5198 CAST_USER_ADDR_T(filename), ctx); 5199 nd.ni_dvp = dvp; 5200 if (namei(&nd) != 0) 5201 goto out2; 5202 5203 xvp = nd.ni_vp; 5204 nameidone(&nd); 5205 5206 if (xvp->v_type == VREG) { 5207#if CONFIG_VFS_FUNNEL 5208 int thread_safe = THREAD_SAFE_FS(dvp); 5209#endif /* CONFIG_VFS_FUNNEL */ 5210 struct vnop_setattr_args a; 5211 5212 a.a_desc = &vnop_setattr_desc; 5213 a.a_vp = xvp; 5214 a.a_vap = vap; 5215 a.a_context = ctx; 5216 5217#if CONFIG_VFS_FUNNEL 5218 if (!thread_safe) { 5219 if ( (lock_fsnode(xvp, NULL)) ) 5220 goto out1; 5221 } 5222#endif /* CONFIG_VFS_FUNNEL */ 5223 5224 (void) (*xvp->v_op[vnop_setattr_desc.vdesc_offset])(&a); 5225 5226#if CONFIG_VFS_FUNNEL 5227 if (!thread_safe) { 5228 unlock_fsnode(xvp, NULL); 5229 } 5230#endif /* CONFIG_VFS_FUNNEL */ 5231 } 5232 5233 5234#if CONFIG_VFS_FUNNEL 5235out1: 5236#endif /* CONFIG_VFS_FUNNEL */ 5237 vnode_put(xvp); 5238 5239out2: 5240 if (filename && filename != &smallname[0]) { 5241 FREE(filename, M_TEMP); 5242 } 5243} 5244 5245 #if 0 5246/* 5247 *# 5248 *#% symlink dvp L U U 5249 *#% symlink vpp - U - 5250 *# 5251 */ 5252struct vnop_symlink_args { 5253 struct vnodeop_desc *a_desc; 5254 vnode_t a_dvp; 5255 vnode_t *a_vpp; 5256 struct componentname *a_cnp; 5257 struct vnode_attr *a_vap; 5258 char *a_target; 5259 vfs_context_t a_context; 5260}; 5261 5262#endif /* 0*/ 5263errno_t 5264VNOP_SYMLINK(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, 5265 struct vnode_attr *vap, char *target, vfs_context_t ctx) 5266{ 5267 int _err; 5268 struct vnop_symlink_args a; 5269#if CONFIG_VFS_FUNNEL 5270 int thread_safe; 5271 int funnel_state = 0; 5272#endif /* CONFIG_VFS_FUNNEL */ 5273 5274 a.a_desc = &vnop_symlink_desc; 5275 a.a_dvp = dvp; 5276 a.a_vpp = vpp; 5277 a.a_cnp = cnp; 5278 a.a_vap = vap; 5279 a.a_target = target; 5280 a.a_context = ctx; 5281 5282#if CONFIG_VFS_FUNNEL 5283 thread_safe = THREAD_SAFE_FS(dvp); 5284 if (!thread_safe) { 5285 if ( (_err = lock_fsnode(dvp, &funnel_state)) ) { 5286 return (_err); 5287 } 5288 } 5289#endif /* CONFIG_VFS_FUNNEL */ 5290 5291 _err = (*dvp->v_op[vnop_symlink_desc.vdesc_offset])(&a); 5292 if (_err == 0 && !NATIVE_XATTR(dvp)) { 5293 /* 5294 * Remove stale Apple Double file (if any). Posts its own knotes 5295 */ 5296 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0); 5297 } 5298 5299#if CONFIG_VFS_FUNNEL 5300 if (!thread_safe) { 5301 unlock_fsnode(dvp, &funnel_state); 5302 } 5303#endif /* CONFIG_VFS_FUNNEL */ 5304 5305 post_event_if_success(dvp, _err, NOTE_WRITE); 5306 5307 return (_err); 5308} 5309 5310#if 0 5311/* 5312 *# 5313 *#% readdir vp L L L 5314 *# 5315 */ 5316struct vnop_readdir_args { 5317 struct vnodeop_desc *a_desc; 5318 vnode_t a_vp; 5319 struct uio *a_uio; 5320 int a_flags; 5321 int *a_eofflag; 5322 int *a_numdirent; 5323 vfs_context_t a_context; 5324}; 5325 5326#endif /* 0*/ 5327errno_t 5328VNOP_READDIR(struct vnode *vp, struct uio *uio, int flags, int *eofflag, 5329 int *numdirent, vfs_context_t ctx) 5330{ 5331 int _err; 5332 struct vnop_readdir_args a; 5333#if CONFIG_VFS_FUNNEL 5334 int thread_safe; 5335 int funnel_state = 0; 5336#endif /* CONFIG_VFS_FUNNEL */ 5337 5338 a.a_desc = &vnop_readdir_desc; 5339 a.a_vp = vp; 5340 a.a_uio = uio; 5341 a.a_flags = flags; 5342 a.a_eofflag = eofflag; 5343 a.a_numdirent = numdirent; 5344 a.a_context = ctx; 5345#if CONFIG_VFS_FUNNEL 5346 thread_safe = THREAD_SAFE_FS(vp); 5347 5348 if (!thread_safe) { 5349 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 5350 return (_err); 5351 } 5352 } 5353#endif /* CONFIG_VFS_FUNNEL */ 5354 5355 _err = (*vp->v_op[vnop_readdir_desc.vdesc_offset])(&a); 5356 5357#if CONFIG_VFS_FUNNEL 5358 if (!thread_safe) { 5359 unlock_fsnode(vp, &funnel_state); 5360 } 5361#endif /* CONFIG_VFS_FUNNEL */ 5362 return (_err); 5363} 5364 5365#if 0 5366/* 5367 *# 5368 *#% readdirattr vp L L L 5369 *# 5370 */ 5371struct vnop_readdirattr_args { 5372 struct vnodeop_desc *a_desc; 5373 vnode_t a_vp; 5374 struct attrlist *a_alist; 5375 struct uio *a_uio; 5376 uint32_t a_maxcount; 5377 uint32_t a_options; 5378 uint32_t *a_newstate; 5379 int *a_eofflag; 5380 uint32_t *a_actualcount; 5381 vfs_context_t a_context; 5382}; 5383 5384#endif /* 0*/ 5385errno_t 5386VNOP_READDIRATTR(struct vnode *vp, struct attrlist *alist, struct uio *uio, uint32_t maxcount, 5387 uint32_t options, uint32_t *newstate, int *eofflag, uint32_t *actualcount, vfs_context_t ctx) 5388{ 5389 int _err; 5390 struct vnop_readdirattr_args a; 5391#if CONFIG_VFS_FUNNEL 5392 int thread_safe; 5393 int funnel_state = 0; 5394#endif /* CONFIG_VFS_FUNNEL */ 5395 5396 a.a_desc = &vnop_readdirattr_desc; 5397 a.a_vp = vp; 5398 a.a_alist = alist; 5399 a.a_uio = uio; 5400 a.a_maxcount = maxcount; 5401 a.a_options = options; 5402 a.a_newstate = newstate; 5403 a.a_eofflag = eofflag; 5404 a.a_actualcount = actualcount; 5405 a.a_context = ctx; 5406 5407#if CONFIG_VFS_FUNNEL 5408 thread_safe = THREAD_SAFE_FS(vp); 5409 if (!thread_safe) { 5410 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 5411 return (_err); 5412 } 5413 } 5414#endif /* CONFIG_VFS_FUNNEL */ 5415 5416 _err = (*vp->v_op[vnop_readdirattr_desc.vdesc_offset])(&a); 5417 5418#if CONFIG_VFS_FUNNEL 5419 if (!thread_safe) { 5420 unlock_fsnode(vp, &funnel_state); 5421 } 5422#endif /* CONFIG_VFS_FUNNEL */ 5423 5424 return (_err); 5425} 5426 5427#if 0 5428/* 5429 *# 5430 *#% readlink vp L L L 5431 *# 5432 */ 5433struct vnop_readlink_args { 5434 struct vnodeop_desc *a_desc; 5435 vnode_t a_vp; 5436 struct uio *a_uio; 5437 vfs_context_t a_context; 5438}; 5439#endif /* 0 */ 5440 5441/* 5442 * Returns: 0 Success 5443 * lock_fsnode:ENOENT No such file or directory [only for VFS 5444 * that is not thread safe & vnode is 5445 * currently being/has been terminated] 5446 * <vfs_readlink>:EINVAL 5447 * <vfs_readlink>:??? 5448 * 5449 * Note: The return codes from the underlying VFS's readlink routine 5450 * can't be fully enumerated here, since third party VFS authors 5451 * may not limit their error returns to the ones documented here, 5452 * even though this may result in some programs functioning 5453 * incorrectly. 5454 * 5455 * The return codes documented above are those which may currently 5456 * be returned by HFS from hfs_vnop_readlink, not including 5457 * additional error code which may be propagated from underlying 5458 * routines. 5459 */ 5460errno_t 5461VNOP_READLINK(struct vnode *vp, struct uio *uio, vfs_context_t ctx) 5462{ 5463 int _err; 5464 struct vnop_readlink_args a; 5465#if CONFIG_VFS_FUNNEL 5466 int thread_safe; 5467 int funnel_state = 0; 5468#endif /* CONFIG_VFS_FUNNEL */ 5469 5470 a.a_desc = &vnop_readlink_desc; 5471 a.a_vp = vp; 5472 a.a_uio = uio; 5473 a.a_context = ctx; 5474 5475#if CONFIG_VFS_FUNNEL 5476 thread_safe = THREAD_SAFE_FS(vp); 5477 if (!thread_safe) { 5478 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 5479 return (_err); 5480 } 5481 } 5482#endif /* CONFIG_VFS_FUNNEL */ 5483 5484 _err = (*vp->v_op[vnop_readlink_desc.vdesc_offset])(&a); 5485 5486#if CONFIG_VFS_FUNNEL 5487 if (!thread_safe) { 5488 unlock_fsnode(vp, &funnel_state); 5489 } 5490#endif /* CONFIG_VFS_FUNNEL */ 5491 5492 return (_err); 5493} 5494 5495#if 0 5496/* 5497 *# 5498 *#% inactive vp L U U 5499 *# 5500 */ 5501struct vnop_inactive_args { 5502 struct vnodeop_desc *a_desc; 5503 vnode_t a_vp; 5504 vfs_context_t a_context; 5505}; 5506#endif /* 0*/ 5507errno_t 5508VNOP_INACTIVE(struct vnode *vp, vfs_context_t ctx) 5509{ 5510 int _err; 5511 struct vnop_inactive_args a; 5512#if CONFIG_VFS_FUNNEL 5513 int thread_safe; 5514 int funnel_state = 0; 5515#endif /* CONFIG_VFS_FUNNEL */ 5516 5517 a.a_desc = &vnop_inactive_desc; 5518 a.a_vp = vp; 5519 a.a_context = ctx; 5520 5521#if CONFIG_VFS_FUNNEL 5522 thread_safe = THREAD_SAFE_FS(vp); 5523 if (!thread_safe) { 5524 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 5525 return (_err); 5526 } 5527 } 5528#endif /* CONFIG_VFS_FUNNEL */ 5529 5530 _err = (*vp->v_op[vnop_inactive_desc.vdesc_offset])(&a); 5531 5532#if CONFIG_VFS_FUNNEL 5533 if (!thread_safe) { 5534 unlock_fsnode(vp, &funnel_state); 5535 } 5536#endif /* CONFIG_VFS_FUNNEL */ 5537 5538#if NAMEDSTREAMS 5539 /* For file systems that do not support namedstream natively, mark 5540 * the shadow stream file vnode to be recycled as soon as the last 5541 * reference goes away. To avoid re-entering reclaim code, do not 5542 * call recycle on terminating namedstream vnodes. 5543 */ 5544 if (vnode_isnamedstream(vp) && 5545 (vp->v_parent != NULLVP) && 5546 vnode_isshadow(vp) && 5547 ((vp->v_lflag & VL_TERMINATE) == 0)) { 5548 vnode_recycle(vp); 5549 } 5550#endif 5551 5552 return (_err); 5553} 5554 5555 5556#if 0 5557/* 5558 *# 5559 *#% reclaim vp U U U 5560 *# 5561 */ 5562struct vnop_reclaim_args { 5563 struct vnodeop_desc *a_desc; 5564 vnode_t a_vp; 5565 vfs_context_t a_context; 5566}; 5567#endif /* 0*/ 5568errno_t 5569VNOP_RECLAIM(struct vnode *vp, vfs_context_t ctx) 5570{ 5571 int _err; 5572 struct vnop_reclaim_args a; 5573#if CONFIG_VFS_FUNNEL 5574 int thread_safe; 5575 int funnel_state = 0; 5576#endif /* CONFIG_VFS_FUNNEL */ 5577 5578 a.a_desc = &vnop_reclaim_desc; 5579 a.a_vp = vp; 5580 a.a_context = ctx; 5581 5582#if CONFIG_VFS_FUNNEL 5583 thread_safe = THREAD_SAFE_FS(vp); 5584 if (!thread_safe) { 5585 funnel_state = thread_funnel_set(kernel_flock, TRUE); 5586 } 5587#endif /* CONFIG_VFS_FUNNEL */ 5588 5589 _err = (*vp->v_op[vnop_reclaim_desc.vdesc_offset])(&a); 5590 5591#if CONFIG_VFS_FUNNEL 5592 if (!thread_safe) { 5593 (void) thread_funnel_set(kernel_flock, funnel_state); 5594 } 5595#endif /* CONFIG_VFS_FUNNEL */ 5596 5597 return (_err); 5598} 5599 5600 5601/* 5602 * Returns: 0 Success 5603 * lock_fsnode:ENOENT No such file or directory [only for VFS 5604 * that is not thread safe & vnode is 5605 * currently being/has been terminated] 5606 * <vnop_pathconf_desc>:??? [per FS implementation specific] 5607 */ 5608#if 0 5609/* 5610 *# 5611 *#% pathconf vp L L L 5612 *# 5613 */ 5614struct vnop_pathconf_args { 5615 struct vnodeop_desc *a_desc; 5616 vnode_t a_vp; 5617 int a_name; 5618 int32_t *a_retval; 5619 vfs_context_t a_context; 5620}; 5621#endif /* 0*/ 5622errno_t 5623VNOP_PATHCONF(struct vnode *vp, int name, int32_t *retval, vfs_context_t ctx) 5624{ 5625 int _err; 5626 struct vnop_pathconf_args a; 5627#if CONFIG_VFS_FUNNEL 5628 int thread_safe; 5629 int funnel_state = 0; 5630#endif /* CONFIG_VFS_FUNNEL */ 5631 5632 a.a_desc = &vnop_pathconf_desc; 5633 a.a_vp = vp; 5634 a.a_name = name; 5635 a.a_retval = retval; 5636 a.a_context = ctx; 5637 5638#if CONFIG_VFS_FUNNEL 5639 thread_safe = THREAD_SAFE_FS(vp); 5640 if (!thread_safe) { 5641 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 5642 return (_err); 5643 } 5644 } 5645#endif /* CONFIG_VFS_FUNNEL */ 5646 5647 _err = (*vp->v_op[vnop_pathconf_desc.vdesc_offset])(&a); 5648 5649#if CONFIG_VFS_FUNNEL 5650 if (!thread_safe) { 5651 unlock_fsnode(vp, &funnel_state); 5652 } 5653#endif /* CONFIG_VFS_FUNNEL */ 5654 5655 return (_err); 5656} 5657 5658/* 5659 * Returns: 0 Success 5660 * err_advlock:ENOTSUP 5661 * lf_advlock:??? 5662 * <vnop_advlock_desc>:??? 5663 * 5664 * Notes: VFS implementations of advisory locking using calls through 5665 * <vnop_advlock_desc> because lock enforcement does not occur 5666 * locally should try to limit themselves to the return codes 5667 * documented above for lf_advlock and err_advlock. 5668 */ 5669#if 0 5670/* 5671 *# 5672 *#% advlock vp U U U 5673 *# 5674 */ 5675struct vnop_advlock_args { 5676 struct vnodeop_desc *a_desc; 5677 vnode_t a_vp; 5678 caddr_t a_id; 5679 int a_op; 5680 struct flock *a_fl; 5681 int a_flags; 5682 vfs_context_t a_context; 5683}; 5684#endif /* 0*/ 5685errno_t 5686VNOP_ADVLOCK(struct vnode *vp, caddr_t id, int op, struct flock *fl, int flags, vfs_context_t ctx) 5687{ 5688 int _err; 5689 struct vnop_advlock_args a; 5690#if CONFIG_VFS_FUNNEL 5691 int thread_safe; 5692 int funnel_state = 0; 5693#endif /* CONFIG_VFS_FUNNEL */ 5694 5695 a.a_desc = &vnop_advlock_desc; 5696 a.a_vp = vp; 5697 a.a_id = id; 5698 a.a_op = op; 5699 a.a_fl = fl; 5700 a.a_flags = flags; 5701 a.a_context = ctx; 5702 5703#if CONFIG_VFS_FUNNEL 5704 thread_safe = THREAD_SAFE_FS(vp); 5705 if (!thread_safe) { 5706 funnel_state = thread_funnel_set(kernel_flock, TRUE); 5707 } 5708#endif /* CONFIG_VFS_FUNNEL */ 5709 5710 /* Disallow advisory locking on non-seekable vnodes */ 5711 if (vnode_isfifo(vp)) { 5712 _err = err_advlock(&a); 5713 } else { 5714 if ((vp->v_flag & VLOCKLOCAL)) { 5715 /* Advisory locking done at this layer */ 5716 _err = lf_advlock(&a); 5717 } else { 5718 /* Advisory locking done by underlying filesystem */ 5719 _err = (*vp->v_op[vnop_advlock_desc.vdesc_offset])(&a); 5720 } 5721 } 5722 5723#if CONFIG_VFS_FUNNEL 5724 if (!thread_safe) { 5725 (void) thread_funnel_set(kernel_flock, funnel_state); 5726 } 5727#endif /* CONFIG_VFS_FUNNEL */ 5728 5729 return (_err); 5730} 5731 5732 5733 5734#if 0 5735/* 5736 *# 5737 *#% allocate vp L L L 5738 *# 5739 */ 5740struct vnop_allocate_args { 5741 struct vnodeop_desc *a_desc; 5742 vnode_t a_vp; 5743 off_t a_length; 5744 u_int32_t a_flags; 5745 off_t *a_bytesallocated; 5746 off_t a_offset; 5747 vfs_context_t a_context; 5748}; 5749 5750#endif /* 0*/ 5751errno_t 5752VNOP_ALLOCATE(struct vnode *vp, off_t length, u_int32_t flags, off_t *bytesallocated, off_t offset, vfs_context_t ctx) 5753{ 5754 int _err; 5755 struct vnop_allocate_args a; 5756#if CONFIG_VFS_FUNNEL 5757 int thread_safe; 5758 int funnel_state = 0; 5759#endif /* CONFIG_VFS_FUNNEL */ 5760 5761 a.a_desc = &vnop_allocate_desc; 5762 a.a_vp = vp; 5763 a.a_length = length; 5764 a.a_flags = flags; 5765 a.a_bytesallocated = bytesallocated; 5766 a.a_offset = offset; 5767 a.a_context = ctx; 5768 5769#if CONFIG_VFS_FUNNEL 5770 thread_safe = THREAD_SAFE_FS(vp); 5771 if (!thread_safe) { 5772 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 5773 return (_err); 5774 } 5775 } 5776#endif /* CONFIG_VFS_FUNNEL */ 5777 5778 _err = (*vp->v_op[vnop_allocate_desc.vdesc_offset])(&a); 5779#if CONFIG_FSE 5780 if (_err == 0) { 5781 add_fsevent(FSE_STAT_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE); 5782 } 5783#endif 5784 5785#if CONFIG_VFS_FUNNEL 5786 if (!thread_safe) { 5787 unlock_fsnode(vp, &funnel_state); 5788 } 5789#endif /* CONFIG_VFS_FUNNEL */ 5790 5791 return (_err); 5792} 5793 5794#if 0 5795/* 5796 *# 5797 *#% pagein vp = = = 5798 *# 5799 */ 5800struct vnop_pagein_args { 5801 struct vnodeop_desc *a_desc; 5802 vnode_t a_vp; 5803 upl_t a_pl; 5804 upl_offset_t a_pl_offset; 5805 off_t a_f_offset; 5806 size_t a_size; 5807 int a_flags; 5808 vfs_context_t a_context; 5809}; 5810#endif /* 0*/ 5811errno_t 5812VNOP_PAGEIN(struct vnode *vp, upl_t pl, upl_offset_t pl_offset, off_t f_offset, size_t size, int flags, vfs_context_t ctx) 5813{ 5814 int _err; 5815 struct vnop_pagein_args a; 5816#if CONFIG_VFS_FUNNEL 5817 int thread_safe; 5818 int funnel_state = 0; 5819#endif /* CONFIG_VFS_FUNNEL */ 5820 5821 a.a_desc = &vnop_pagein_desc; 5822 a.a_vp = vp; 5823 a.a_pl = pl; 5824 a.a_pl_offset = pl_offset; 5825 a.a_f_offset = f_offset; 5826 a.a_size = size; 5827 a.a_flags = flags; 5828 a.a_context = ctx; 5829 5830#if CONFIG_VFS_FUNNEL 5831 thread_safe = THREAD_SAFE_FS(vp); 5832 if (!thread_safe) { 5833 funnel_state = thread_funnel_set(kernel_flock, TRUE); 5834 } 5835#endif /* CONFIG_VFS_FUNNEL */ 5836 5837 _err = (*vp->v_op[vnop_pagein_desc.vdesc_offset])(&a); 5838 5839#if CONFIG_VFS_FUNNEL 5840 if (!thread_safe) { 5841 (void) thread_funnel_set(kernel_flock, funnel_state); 5842 } 5843#endif /* CONFIG_VFS_FUNNEL */ 5844 5845 return (_err); 5846} 5847 5848#if 0 5849/* 5850 *# 5851 *#% pageout vp = = = 5852 *# 5853 */ 5854struct vnop_pageout_args { 5855 struct vnodeop_desc *a_desc; 5856 vnode_t a_vp; 5857 upl_t a_pl; 5858 upl_offset_t a_pl_offset; 5859 off_t a_f_offset; 5860 size_t a_size; 5861 int a_flags; 5862 vfs_context_t a_context; 5863}; 5864 5865#endif /* 0*/ 5866errno_t 5867VNOP_PAGEOUT(struct vnode *vp, upl_t pl, upl_offset_t pl_offset, off_t f_offset, size_t size, int flags, vfs_context_t ctx) 5868{ 5869 int _err; 5870 struct vnop_pageout_args a; 5871#if CONFIG_VFS_FUNNEL 5872 int thread_safe; 5873 int funnel_state = 0; 5874#endif /* CONFIG_VFS_FUNNEL */ 5875 5876 a.a_desc = &vnop_pageout_desc; 5877 a.a_vp = vp; 5878 a.a_pl = pl; 5879 a.a_pl_offset = pl_offset; 5880 a.a_f_offset = f_offset; 5881 a.a_size = size; 5882 a.a_flags = flags; 5883 a.a_context = ctx; 5884 5885#if CONFIG_VFS_FUNNEL 5886 thread_safe = THREAD_SAFE_FS(vp); 5887 if (!thread_safe) { 5888 funnel_state = thread_funnel_set(kernel_flock, TRUE); 5889 } 5890#endif /* CONFIG_VFS_FUNNEL */ 5891 5892 _err = (*vp->v_op[vnop_pageout_desc.vdesc_offset])(&a); 5893 5894#if CONFIG_VFS_FUNNEL 5895 if (!thread_safe) { 5896 (void) thread_funnel_set(kernel_flock, funnel_state); 5897 } 5898#endif /* CONFIG_VFS_FUNNEL */ 5899 5900 post_event_if_success(vp, _err, NOTE_WRITE); 5901 5902 return (_err); 5903} 5904 5905int 5906vn_remove(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, struct vnode_attr *vap, vfs_context_t ctx) 5907{ 5908 if (vnode_compound_remove_available(dvp)) { 5909 return VNOP_COMPOUND_REMOVE(dvp, vpp, ndp, flags, vap, ctx); 5910 } else { 5911 return VNOP_REMOVE(dvp, *vpp, &ndp->ni_cnd, flags, ctx); 5912 } 5913} 5914 5915#if CONFIG_SEARCHFS 5916 5917#if 0 5918/* 5919 *# 5920 *#% searchfs vp L L L 5921 *# 5922 */ 5923struct vnop_searchfs_args { 5924 struct vnodeop_desc *a_desc; 5925 vnode_t a_vp; 5926 void *a_searchparams1; 5927 void *a_searchparams2; 5928 struct attrlist *a_searchattrs; 5929 uint32_t a_maxmatches; 5930 struct timeval *a_timelimit; 5931 struct attrlist *a_returnattrs; 5932 uint32_t *a_nummatches; 5933 uint32_t a_scriptcode; 5934 uint32_t a_options; 5935 struct uio *a_uio; 5936 struct searchstate *a_searchstate; 5937 vfs_context_t a_context; 5938}; 5939 5940#endif /* 0*/ 5941errno_t 5942VNOP_SEARCHFS(struct vnode *vp, void *searchparams1, void *searchparams2, struct attrlist *searchattrs, uint32_t maxmatches, struct timeval *timelimit, struct attrlist *returnattrs, uint32_t *nummatches, uint32_t scriptcode, uint32_t options, struct uio *uio, struct searchstate *searchstate, vfs_context_t ctx) 5943{ 5944 int _err; 5945 struct vnop_searchfs_args a; 5946#if CONFIG_VFS_FUNNEL 5947 int thread_safe; 5948 int funnel_state = 0; 5949#endif /* CONFIG_VFS_FUNNEL */ 5950 5951 a.a_desc = &vnop_searchfs_desc; 5952 a.a_vp = vp; 5953 a.a_searchparams1 = searchparams1; 5954 a.a_searchparams2 = searchparams2; 5955 a.a_searchattrs = searchattrs; 5956 a.a_maxmatches = maxmatches; 5957 a.a_timelimit = timelimit; 5958 a.a_returnattrs = returnattrs; 5959 a.a_nummatches = nummatches; 5960 a.a_scriptcode = scriptcode; 5961 a.a_options = options; 5962 a.a_uio = uio; 5963 a.a_searchstate = searchstate; 5964 a.a_context = ctx; 5965 5966#if CONFIG_VFS_FUNNEL 5967 thread_safe = THREAD_SAFE_FS(vp); 5968 if (!thread_safe) { 5969 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 5970 return (_err); 5971 } 5972 } 5973#endif /* CONFIG_VFS_FUNNEL */ 5974 5975 _err = (*vp->v_op[vnop_searchfs_desc.vdesc_offset])(&a); 5976 5977#if CONFIG_VFS_FUNNEL 5978 if (!thread_safe) { 5979 unlock_fsnode(vp, &funnel_state); 5980 } 5981#endif /* CONFIG_VFS_FUNNEL */ 5982 5983 return (_err); 5984} 5985#endif /* CONFIG_SEARCHFS */ 5986 5987#if 0 5988/* 5989 *# 5990 *#% copyfile fvp U U U 5991 *#% copyfile tdvp L U U 5992 *#% copyfile tvp X U U 5993 *# 5994 */ 5995struct vnop_copyfile_args { 5996 struct vnodeop_desc *a_desc; 5997 vnode_t a_fvp; 5998 vnode_t a_tdvp; 5999 vnode_t a_tvp; 6000 struct componentname *a_tcnp; 6001 int a_mode; 6002 int a_flags; 6003 vfs_context_t a_context; 6004}; 6005#endif /* 0*/ 6006errno_t 6007VNOP_COPYFILE(struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp, 6008 int mode, int flags, vfs_context_t ctx) 6009{ 6010 int _err; 6011 struct vnop_copyfile_args a; 6012 a.a_desc = &vnop_copyfile_desc; 6013 a.a_fvp = fvp; 6014 a.a_tdvp = tdvp; 6015 a.a_tvp = tvp; 6016 a.a_tcnp = tcnp; 6017 a.a_mode = mode; 6018 a.a_flags = flags; 6019 a.a_context = ctx; 6020 _err = (*fvp->v_op[vnop_copyfile_desc.vdesc_offset])(&a); 6021 return (_err); 6022} 6023 6024errno_t 6025VNOP_GETXATTR(vnode_t vp, const char *name, uio_t uio, size_t *size, int options, vfs_context_t ctx) 6026{ 6027 struct vnop_getxattr_args a; 6028 int error; 6029#if CONFIG_VFS_FUNNEL 6030 int thread_safe; 6031 int funnel_state = 0; 6032#endif /* CONFIG_VFS_FUNNEL */ 6033 6034 a.a_desc = &vnop_getxattr_desc; 6035 a.a_vp = vp; 6036 a.a_name = name; 6037 a.a_uio = uio; 6038 a.a_size = size; 6039 a.a_options = options; 6040 a.a_context = ctx; 6041 6042#if CONFIG_VFS_FUNNEL 6043 thread_safe = THREAD_SAFE_FS(vp); 6044 if (!thread_safe) { 6045 if ( (error = lock_fsnode(vp, &funnel_state)) ) { 6046 return (error); 6047 } 6048 } 6049#endif /* CONFIG_VFS_FUNNEL */ 6050 6051 error = (*vp->v_op[vnop_getxattr_desc.vdesc_offset])(&a); 6052 6053#if CONFIG_VFS_FUNNEL 6054 if (!thread_safe) { 6055 unlock_fsnode(vp, &funnel_state); 6056 } 6057#endif /* CONFIG_VFS_FUNNEL */ 6058 6059 return (error); 6060} 6061 6062errno_t 6063VNOP_SETXATTR(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t ctx) 6064{ 6065 struct vnop_setxattr_args a; 6066 int error; 6067#if CONFIG_VFS_FUNNEL 6068 int thread_safe; 6069 int funnel_state = 0; 6070#endif /* CONFIG_VFS_FUNNEL */ 6071 6072 a.a_desc = &vnop_setxattr_desc; 6073 a.a_vp = vp; 6074 a.a_name = name; 6075 a.a_uio = uio; 6076 a.a_options = options; 6077 a.a_context = ctx; 6078 6079#if CONFIG_VFS_FUNNEL 6080 thread_safe = THREAD_SAFE_FS(vp); 6081 if (!thread_safe) { 6082 if ( (error = lock_fsnode(vp, &funnel_state)) ) { 6083 return (error); 6084 } 6085 } 6086#endif /* CONFIG_VFS_FUNNEL */ 6087 6088 error = (*vp->v_op[vnop_setxattr_desc.vdesc_offset])(&a); 6089 6090#if CONFIG_VFS_FUNNEL 6091 if (!thread_safe) { 6092 unlock_fsnode(vp, &funnel_state); 6093 } 6094#endif /* CONFIG_VFS_FUNNEL */ 6095 6096 if (error == 0) 6097 vnode_uncache_authorized_action(vp, KAUTH_INVALIDATE_CACHED_RIGHTS); 6098 6099 post_event_if_success(vp, error, NOTE_ATTRIB); 6100 6101 return (error); 6102} 6103 6104errno_t 6105VNOP_REMOVEXATTR(vnode_t vp, const char *name, int options, vfs_context_t ctx) 6106{ 6107 struct vnop_removexattr_args a; 6108 int error; 6109#if CONFIG_VFS_FUNNEL 6110 int thread_safe; 6111 int funnel_state = 0; 6112#endif /* CONFIG_VFS_FUNNEL */ 6113 6114 a.a_desc = &vnop_removexattr_desc; 6115 a.a_vp = vp; 6116 a.a_name = name; 6117 a.a_options = options; 6118 a.a_context = ctx; 6119 6120#if CONFIG_VFS_FUNNEL 6121 thread_safe = THREAD_SAFE_FS(vp); 6122 if (!thread_safe) { 6123 if ( (error = lock_fsnode(vp, &funnel_state)) ) { 6124 return (error); 6125 } 6126 } 6127#endif /* CONFIG_VFS_FUNNEL */ 6128 6129 error = (*vp->v_op[vnop_removexattr_desc.vdesc_offset])(&a); 6130 6131#if CONFIG_VFS_FUNNEL 6132 if (!thread_safe) { 6133 unlock_fsnode(vp, &funnel_state); 6134 } 6135#endif /* CONFIG_VFS_FUNNEL */ 6136 6137 post_event_if_success(vp, error, NOTE_ATTRIB); 6138 6139 return (error); 6140} 6141 6142errno_t 6143VNOP_LISTXATTR(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t ctx) 6144{ 6145 struct vnop_listxattr_args a; 6146 int error; 6147#if CONFIG_VFS_FUNNEL 6148 int thread_safe; 6149 int funnel_state = 0; 6150#endif /* CONFIG_VFS_FUNNEL */ 6151 6152 a.a_desc = &vnop_listxattr_desc; 6153 a.a_vp = vp; 6154 a.a_uio = uio; 6155 a.a_size = size; 6156 a.a_options = options; 6157 a.a_context = ctx; 6158 6159#if CONFIG_VFS_FUNNEL 6160 thread_safe = THREAD_SAFE_FS(vp); 6161 if (!thread_safe) { 6162 if ( (error = lock_fsnode(vp, &funnel_state)) ) { 6163 return (error); 6164 } 6165 } 6166#endif /* CONFIG_VFS_FUNNEL */ 6167 6168 error = (*vp->v_op[vnop_listxattr_desc.vdesc_offset])(&a); 6169 6170#if CONFIG_VFS_FUNNEL 6171 if (!thread_safe) { 6172 unlock_fsnode(vp, &funnel_state); 6173 } 6174#endif /* CONFIG_VFS_FUNNEL */ 6175 6176 return (error); 6177} 6178 6179 6180#if 0 6181/* 6182 *# 6183 *#% blktooff vp = = = 6184 *# 6185 */ 6186struct vnop_blktooff_args { 6187 struct vnodeop_desc *a_desc; 6188 vnode_t a_vp; 6189 daddr64_t a_lblkno; 6190 off_t *a_offset; 6191}; 6192#endif /* 0*/ 6193errno_t 6194VNOP_BLKTOOFF(struct vnode *vp, daddr64_t lblkno, off_t *offset) 6195{ 6196 int _err; 6197 struct vnop_blktooff_args a; 6198#if CONFIG_VFS_FUNNEL 6199 int thread_safe; 6200 int funnel_state = 0; 6201#endif /* CONFIG_VFS_FUNNEL */ 6202 6203 a.a_desc = &vnop_blktooff_desc; 6204 a.a_vp = vp; 6205 a.a_lblkno = lblkno; 6206 a.a_offset = offset; 6207 6208#if CONFIG_VFS_FUNNEL 6209 thread_safe = THREAD_SAFE_FS(vp); 6210 if (!thread_safe) { 6211 funnel_state = thread_funnel_set(kernel_flock, TRUE); 6212 } 6213#endif /* CONFIG_VFS_FUNNEL */ 6214 6215 _err = (*vp->v_op[vnop_blktooff_desc.vdesc_offset])(&a); 6216 6217#if CONFIG_VFS_FUNNEL 6218 if (!thread_safe) { 6219 (void) thread_funnel_set(kernel_flock, funnel_state); 6220 } 6221#endif /* CONFIG_VFS_FUNNEL */ 6222 6223 return (_err); 6224} 6225 6226#if 0 6227/* 6228 *# 6229 *#% offtoblk vp = = = 6230 *# 6231 */ 6232struct vnop_offtoblk_args { 6233 struct vnodeop_desc *a_desc; 6234 vnode_t a_vp; 6235 off_t a_offset; 6236 daddr64_t *a_lblkno; 6237}; 6238#endif /* 0*/ 6239errno_t 6240VNOP_OFFTOBLK(struct vnode *vp, off_t offset, daddr64_t *lblkno) 6241{ 6242 int _err; 6243 struct vnop_offtoblk_args a; 6244#if CONFIG_VFS_FUNNEL 6245 int thread_safe; 6246 int funnel_state = 0; 6247#endif /* CONFIG_VFS_FUNNEL */ 6248 6249 a.a_desc = &vnop_offtoblk_desc; 6250 a.a_vp = vp; 6251 a.a_offset = offset; 6252 a.a_lblkno = lblkno; 6253 6254#if CONFIG_VFS_FUNNEL 6255 thread_safe = THREAD_SAFE_FS(vp); 6256 if (!thread_safe) { 6257 funnel_state = thread_funnel_set(kernel_flock, TRUE); 6258 } 6259#endif /* CONFIG_VFS_FUNNEL */ 6260 6261 _err = (*vp->v_op[vnop_offtoblk_desc.vdesc_offset])(&a); 6262 6263#if CONFIG_VFS_FUNNEL 6264 if (!thread_safe) { 6265 (void) thread_funnel_set(kernel_flock, funnel_state); 6266 } 6267#endif /* CONFIG_VFS_FUNNEL */ 6268 6269 return (_err); 6270} 6271 6272#if 0 6273/* 6274 *# 6275 *#% blockmap vp L L L 6276 *# 6277 */ 6278struct vnop_blockmap_args { 6279 struct vnodeop_desc *a_desc; 6280 vnode_t a_vp; 6281 off_t a_foffset; 6282 size_t a_size; 6283 daddr64_t *a_bpn; 6284 size_t *a_run; 6285 void *a_poff; 6286 int a_flags; 6287 vfs_context_t a_context; 6288}; 6289#endif /* 0*/ 6290errno_t 6291VNOP_BLOCKMAP(struct vnode *vp, off_t foffset, size_t size, daddr64_t *bpn, size_t *run, void *poff, int flags, vfs_context_t ctx) 6292{ 6293 int _err; 6294 struct vnop_blockmap_args a; 6295 size_t localrun = 0; 6296#if CONFIG_VFS_FUNNEL 6297 int thread_safe; 6298 int funnel_state = 0; 6299#endif /* CONFIG_VFS_FUNNEL */ 6300 6301 if (ctx == NULL) { 6302 ctx = vfs_context_current(); 6303 } 6304 a.a_desc = &vnop_blockmap_desc; 6305 a.a_vp = vp; 6306 a.a_foffset = foffset; 6307 a.a_size = size; 6308 a.a_bpn = bpn; 6309 a.a_run = &localrun; 6310 a.a_poff = poff; 6311 a.a_flags = flags; 6312 a.a_context = ctx; 6313 6314#if CONFIG_VFS_FUNNEL 6315 thread_safe = THREAD_SAFE_FS(vp); 6316 if (!thread_safe) { 6317 funnel_state = thread_funnel_set(kernel_flock, TRUE); 6318 } 6319#endif /* CONFIG_VFS_FUNNEL */ 6320 6321 _err = (*vp->v_op[vnop_blockmap_desc.vdesc_offset])(&a); 6322 6323#if CONFIG_VFS_FUNNEL 6324 if (!thread_safe) { 6325 (void) thread_funnel_set(kernel_flock, funnel_state); 6326 } 6327#endif /* CONFIG_VFS_FUNNEL */ 6328 6329 /* 6330 * We used a local variable to request information from the underlying 6331 * filesystem about the length of the I/O run in question. If 6332 * we get malformed output from the filesystem, we cap it to the length 6333 * requested, at most. Update 'run' on the way out. 6334 */ 6335 if (_err == 0) { 6336 if (localrun > size) { 6337 localrun = size; 6338 } 6339 6340 if (run) { 6341 *run = localrun; 6342 } 6343 } 6344 6345 return (_err); 6346} 6347 6348#if 0 6349struct vnop_strategy_args { 6350 struct vnodeop_desc *a_desc; 6351 struct buf *a_bp; 6352}; 6353 6354#endif /* 0*/ 6355errno_t 6356VNOP_STRATEGY(struct buf *bp) 6357{ 6358 int _err; 6359 struct vnop_strategy_args a; 6360 a.a_desc = &vnop_strategy_desc; 6361 a.a_bp = bp; 6362 _err = (*buf_vnode(bp)->v_op[vnop_strategy_desc.vdesc_offset])(&a); 6363 return (_err); 6364} 6365 6366#if 0 6367struct vnop_bwrite_args { 6368 struct vnodeop_desc *a_desc; 6369 buf_t a_bp; 6370}; 6371#endif /* 0*/ 6372errno_t 6373VNOP_BWRITE(struct buf *bp) 6374{ 6375 int _err; 6376 struct vnop_bwrite_args a; 6377 a.a_desc = &vnop_bwrite_desc; 6378 a.a_bp = bp; 6379 _err = (*buf_vnode(bp)->v_op[vnop_bwrite_desc.vdesc_offset])(&a); 6380 return (_err); 6381} 6382 6383#if 0 6384struct vnop_kqfilt_add_args { 6385 struct vnodeop_desc *a_desc; 6386 struct vnode *a_vp; 6387 struct knote *a_kn; 6388 vfs_context_t a_context; 6389}; 6390#endif 6391errno_t 6392VNOP_KQFILT_ADD(struct vnode *vp, struct knote *kn, vfs_context_t ctx) 6393{ 6394 int _err; 6395 struct vnop_kqfilt_add_args a; 6396#if CONFIG_VFS_FUNNEL 6397 int thread_safe; 6398 int funnel_state = 0; 6399#endif /* CONFIG_VFS_FUNNEL */ 6400 6401 a.a_desc = VDESC(vnop_kqfilt_add); 6402 a.a_vp = vp; 6403 a.a_kn = kn; 6404 a.a_context = ctx; 6405 6406#if CONFIG_VFS_FUNNEL 6407 thread_safe = THREAD_SAFE_FS(vp); 6408 if (!thread_safe) { 6409 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 6410 return (_err); 6411 } 6412 } 6413#endif /* CONFIG_VFS_FUNNEL */ 6414 6415 _err = (*vp->v_op[vnop_kqfilt_add_desc.vdesc_offset])(&a); 6416 6417#if CONFIG_VFS_FUNNEL 6418 if (!thread_safe) { 6419 unlock_fsnode(vp, &funnel_state); 6420 } 6421#endif /* CONFIG_VFS_FUNNEL */ 6422 6423 return(_err); 6424} 6425 6426#if 0 6427struct vnop_kqfilt_remove_args { 6428 struct vnodeop_desc *a_desc; 6429 struct vnode *a_vp; 6430 uintptr_t a_ident; 6431 vfs_context_t a_context; 6432}; 6433#endif 6434errno_t 6435VNOP_KQFILT_REMOVE(struct vnode *vp, uintptr_t ident, vfs_context_t ctx) 6436{ 6437 int _err; 6438 struct vnop_kqfilt_remove_args a; 6439#if CONFIG_VFS_FUNNEL 6440 int thread_safe; 6441 int funnel_state = 0; 6442#endif /* CONFIG_VFS_FUNNEL */ 6443 6444 a.a_desc = VDESC(vnop_kqfilt_remove); 6445 a.a_vp = vp; 6446 a.a_ident = ident; 6447 a.a_context = ctx; 6448 6449#if CONFIG_VFS_FUNNEL 6450 thread_safe = THREAD_SAFE_FS(vp); 6451 if (!thread_safe) { 6452 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 6453 return (_err); 6454 } 6455 } 6456#endif /* CONFIG_VFS_FUNNEL */ 6457 6458 _err = (*vp->v_op[vnop_kqfilt_remove_desc.vdesc_offset])(&a); 6459 6460#if CONFIG_VFS_FUNNEL 6461 if (!thread_safe) { 6462 unlock_fsnode(vp, &funnel_state); 6463 } 6464#endif /* CONFIG_VFS_FUNNEL */ 6465 6466 return(_err); 6467} 6468 6469errno_t 6470VNOP_MONITOR(vnode_t vp, uint32_t events, uint32_t flags, void *handle, vfs_context_t ctx) 6471{ 6472 int _err; 6473 struct vnop_monitor_args a; 6474#if CONFIG_VFS_FUNNEL 6475 int thread_safe; 6476 int funnel_state = 0; 6477#endif /* CONFIG_VFS_FUNNEL */ 6478 6479 a.a_desc = VDESC(vnop_monitor); 6480 a.a_vp = vp; 6481 a.a_events = events; 6482 a.a_flags = flags; 6483 a.a_handle = handle; 6484 a.a_context = ctx; 6485 6486#if CONFIG_VFS_FUNNEL 6487 thread_safe = THREAD_SAFE_FS(vp); 6488 if (!thread_safe) { 6489 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 6490 return (_err); 6491 } 6492 } 6493#endif /* CONFIG_VFS_FUNNEL */ 6494 6495 _err = (*vp->v_op[vnop_monitor_desc.vdesc_offset])(&a); 6496 6497#if CONFIG_VFS_FUNNEL 6498 if (!thread_safe) { 6499 unlock_fsnode(vp, &funnel_state); 6500 } 6501#endif /* CONFIG_VFS_FUNNEL */ 6502 6503 return(_err); 6504} 6505 6506#if 0 6507struct vnop_setlabel_args { 6508 struct vnodeop_desc *a_desc; 6509 struct vnode *a_vp; 6510 struct label *a_vl; 6511 vfs_context_t a_context; 6512}; 6513#endif 6514errno_t 6515VNOP_SETLABEL(struct vnode *vp, struct label *label, vfs_context_t ctx) 6516{ 6517 int _err; 6518 struct vnop_setlabel_args a; 6519#if CONFIG_VFS_FUNNEL 6520 int thread_safe; 6521 int funnel_state = 0; 6522#endif /* CONFIG_VFS_FUNNEL */ 6523 6524 a.a_desc = VDESC(vnop_setlabel); 6525 a.a_vp = vp; 6526 a.a_vl = label; 6527 a.a_context = ctx; 6528 6529#if CONFIG_VFS_FUNNEL 6530 thread_safe = THREAD_SAFE_FS(vp); 6531 if (!thread_safe) { 6532 if ( (_err = lock_fsnode(vp, &funnel_state)) ) { 6533 return (_err); 6534 } 6535 } 6536#endif /* CONFIG_VFS_FUNNEL */ 6537 6538 _err = (*vp->v_op[vnop_setlabel_desc.vdesc_offset])(&a); 6539 6540#if CONFIG_VFS_FUNNEL 6541 if (!thread_safe) { 6542 unlock_fsnode(vp, &funnel_state); 6543 } 6544#endif /* CONFIG_VFS_FUNNEL */ 6545 6546 return(_err); 6547} 6548 6549 6550#if NAMEDSTREAMS 6551/* 6552 * Get a named streamed 6553 */ 6554errno_t 6555VNOP_GETNAMEDSTREAM(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation operation, int flags, vfs_context_t ctx) 6556{ 6557 struct vnop_getnamedstream_args a; 6558 6559#if CONFIG_VFS_FUNNEL 6560 if (!THREAD_SAFE_FS(vp)) 6561 return (ENOTSUP); 6562#endif /* CONFIG_VFS_FUNNEL */ 6563 6564 a.a_desc = &vnop_getnamedstream_desc; 6565 a.a_vp = vp; 6566 a.a_svpp = svpp; 6567 a.a_name = name; 6568 a.a_operation = operation; 6569 a.a_flags = flags; 6570 a.a_context = ctx; 6571 6572 return (*vp->v_op[vnop_getnamedstream_desc.vdesc_offset])(&a); 6573} 6574 6575/* 6576 * Create a named streamed 6577 */ 6578errno_t 6579VNOP_MAKENAMEDSTREAM(vnode_t vp, vnode_t *svpp, const char *name, int flags, vfs_context_t ctx) 6580{ 6581 struct vnop_makenamedstream_args a; 6582 6583#if CONFIG_VFS_FUNNEL 6584 if (!THREAD_SAFE_FS(vp)) 6585 return (ENOTSUP); 6586#endif /* CONFIG_VFS_FUNNEL */ 6587 6588 a.a_desc = &vnop_makenamedstream_desc; 6589 a.a_vp = vp; 6590 a.a_svpp = svpp; 6591 a.a_name = name; 6592 a.a_flags = flags; 6593 a.a_context = ctx; 6594 6595 return (*vp->v_op[vnop_makenamedstream_desc.vdesc_offset])(&a); 6596} 6597 6598 6599/* 6600 * Remove a named streamed 6601 */ 6602errno_t 6603VNOP_REMOVENAMEDSTREAM(vnode_t vp, vnode_t svp, const char *name, int flags, vfs_context_t ctx) 6604{ 6605 struct vnop_removenamedstream_args a; 6606 6607#if CONFIG_VFS_FUNNEL 6608 if (!THREAD_SAFE_FS(vp)) 6609 return (ENOTSUP); 6610#endif /* CONFIG_VFS_FUNNEL */ 6611 6612 a.a_desc = &vnop_removenamedstream_desc; 6613 a.a_vp = vp; 6614 a.a_svp = svp; 6615 a.a_name = name; 6616 a.a_flags = flags; 6617 a.a_context = ctx; 6618 6619 return (*vp->v_op[vnop_removenamedstream_desc.vdesc_offset])(&a); 6620} 6621#endif 6622