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