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