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