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