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