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