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