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