]> git.saurik.com Git - apple/xnu.git/blame - bsd/vfs/kpi_vfs.c
xnu-7195.50.7.100.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
f427ee49
A
148extern lck_rw_t * rootvnode_rw_lock;
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
0a7de745
A
1528int
1529vfs_isswapmount(mount_t mnt)
39037602
A
1530{
1531 return mnt && ISSET(mnt->mnt_kern_flag, MNTK_SWAP_MOUNT) ? 1 : 0;
1532}
1533
91447636
A
1534/* XXXXXXXXXXXXXX VNODE KAPIS XXXXXXXXXXXXXXXXXXXXXXXXX */
1535
0a7de745 1536
91447636
A
1537/*
1538 * Convert between vnode types and inode formats (since POSIX.1
1539 * defines mode word of stat structure in terms of inode formats).
1540 */
0a7de745 1541enum vtype
91447636
A
1542vnode_iftovt(int mode)
1543{
0a7de745 1544 return iftovt_tab[((mode) & S_IFMT) >> 12];
91447636
A
1545}
1546
0a7de745 1547int
91447636
A
1548vnode_vttoif(enum vtype indx)
1549{
0a7de745 1550 return vttoif_tab[(int)(indx)];
91447636
A
1551}
1552
0a7de745 1553int
91447636
A
1554vnode_makeimode(int indx, int mode)
1555{
1556 return (int)(VTTOIF(indx) | (mode));
1557}
1558
1559
1560/*
1561 * vnode manipulation functions.
1562 */
1563
b0d623f7 1564/* returns system root vnode iocount; It should be released using vnode_put() */
0a7de745 1565vnode_t
91447636
A
1566vfs_rootvnode(void)
1567{
1568 int error;
1569
f427ee49 1570 lck_rw_lock_shared(rootvnode_rw_lock);
91447636 1571 error = vnode_get(rootvnode);
f427ee49 1572 lck_rw_unlock_shared(rootvnode_rw_lock);
0a7de745
A
1573 if (error) {
1574 return (vnode_t)0;
1575 } else {
91447636 1576 return rootvnode;
0a7de745
A
1577 }
1578}
91447636
A
1579
1580
0a7de745 1581uint32_t
91447636
A
1582vnode_vid(vnode_t vp)
1583{
0a7de745
A
1584 return (uint32_t)(vp->v_id);
1585}
91447636 1586
0a7de745 1587mount_t
91447636
A
1588vnode_mount(vnode_t vp)
1589{
0a7de745 1590 return vp->v_mount;
91447636
A
1591}
1592
fe8ab488
A
1593#if CONFIG_IOSCHED
1594vnode_t
1595vnode_mountdevvp(vnode_t vp)
1596{
0a7de745
A
1597 if (vp->v_mount) {
1598 return vp->v_mount->mnt_devvp;
1599 } else {
1600 return (vnode_t)0;
1601 }
fe8ab488
A
1602}
1603#endif
1604
cb323159
A
1605boolean_t
1606vnode_isonexternalstorage(vnode_t vp)
1607{
1608 if (vp) {
1609 if (vp->v_mount) {
1610 if (vp->v_mount->mnt_ioflags & MNT_IOFLAGS_PERIPHERAL_DRIVE) {
1611 return TRUE;
1612 }
1613 }
1614 }
1615 return FALSE;
1616}
1617
0a7de745 1618mount_t
91447636
A
1619vnode_mountedhere(vnode_t vp)
1620{
1621 mount_t mp;
1622
1623 if ((vp->v_type == VDIR) && ((mp = vp->v_mountedhere) != NULL) &&
0a7de745
A
1624 (mp->mnt_vnodecovered == vp)) {
1625 return mp;
1626 } else {
91447636 1627 return (mount_t)NULL;
0a7de745 1628 }
91447636
A
1629}
1630
1631/* returns vnode type of vnode_t */
0a7de745 1632enum vtype
91447636
A
1633vnode_vtype(vnode_t vp)
1634{
0a7de745 1635 return vp->v_type;
91447636
A
1636}
1637
1638/* returns FS specific node saved in vnode */
0a7de745 1639void *
91447636
A
1640vnode_fsnode(vnode_t vp)
1641{
0a7de745 1642 return vp->v_data;
91447636
A
1643}
1644
0a7de745 1645void
91447636
A
1646vnode_clearfsnode(vnode_t vp)
1647{
2d21ac55 1648 vp->v_data = NULL;
91447636
A
1649}
1650
0a7de745 1651dev_t
91447636
A
1652vnode_specrdev(vnode_t vp)
1653{
0a7de745 1654 return vp->v_rdev;
91447636
A
1655}
1656
1657
1658/* Accessor functions */
1659/* is vnode_t a root vnode */
0a7de745 1660int
91447636
A
1661vnode_isvroot(vnode_t vp)
1662{
0a7de745 1663 return (vp->v_flag & VROOT)? 1 : 0;
91447636
A
1664}
1665
1666/* is vnode_t a system vnode */
0a7de745 1667int
91447636
A
1668vnode_issystem(vnode_t vp)
1669{
0a7de745 1670 return (vp->v_flag & VSYSTEM)? 1 : 0;
91447636
A
1671}
1672
2d21ac55 1673/* is vnode_t a swap file vnode */
0a7de745 1674int
2d21ac55
A
1675vnode_isswap(vnode_t vp)
1676{
0a7de745 1677 return (vp->v_flag & VSWAP)? 1 : 0;
2d21ac55
A
1678}
1679
b0d623f7
A
1680/* is vnode_t a tty */
1681int
1682vnode_istty(vnode_t vp)
1683{
0a7de745 1684 return (vp->v_flag & VISTTY) ? 1 : 0;
b0d623f7
A
1685}
1686
91447636 1687/* if vnode_t mount operation in progress */
0a7de745 1688int
91447636
A
1689vnode_ismount(vnode_t vp)
1690{
0a7de745 1691 return (vp->v_flag & VMOUNT)? 1 : 0;
91447636
A
1692}
1693
1694/* is this vnode under recyle now */
0a7de745 1695int
91447636
A
1696vnode_isrecycled(vnode_t vp)
1697{
1698 int ret;
1699
2d21ac55 1700 vnode_lock_spin(vp);
0a7de745 1701 ret = (vp->v_lflag & (VL_TERMINATE | VL_DEAD))? 1 : 0;
91447636 1702 vnode_unlock(vp);
0a7de745 1703 return ret;
91447636
A
1704}
1705
b0d623f7 1706/* vnode was created by background task requesting rapid aging
0a7de745 1707 * and has not since been referenced by a normal task */
b0d623f7
A
1708int
1709vnode_israge(vnode_t vp)
1710{
0a7de745 1711 return (vp->v_flag & VRAGE)? 1 : 0;
b0d623f7
A
1712}
1713
6d2010ae
A
1714int
1715vnode_needssnapshots(vnode_t vp)
1716{
0a7de745 1717 return (vp->v_flag & VNEEDSSNAPSHOT)? 1 : 0;
6d2010ae
A
1718}
1719
1720
1721/* Check the process/thread to see if we should skip atime updates */
1722int
0a7de745
A
1723vfs_ctx_skipatime(vfs_context_t ctx)
1724{
6d2010ae
A
1725 struct uthread *ut;
1726 proc_t proc;
1727 thread_t thr;
1728
1729 proc = vfs_context_proc(ctx);
0a7de745 1730 thr = vfs_context_thread(ctx);
6d2010ae
A
1731
1732 /* Validate pointers in case we were invoked via a kernel context */
1733 if (thr && proc) {
0a7de745 1734 ut = get_bsdthread_info(thr);
6d2010ae
A
1735
1736 if (proc->p_lflag & P_LRAGE_VNODES) {
1737 return 1;
1738 }
d9a64523 1739
6d2010ae 1740 if (ut) {
0a7de745 1741 if (ut->uu_flag & (UT_RAGE_VNODES | UT_ATIME_UPDATE)) {
6d2010ae
A
1742 return 1;
1743 }
1744 }
d9a64523
A
1745
1746 if (proc->p_vfs_iopolicy & P_VFS_IOPOLICY_ATIME_UPDATES) {
1747 return 1;
1748 }
6d2010ae
A
1749 }
1750 return 0;
1751}
1752
91447636 1753/* is vnode_t marked to not keep data cached once it's been consumed */
0a7de745 1754int
91447636
A
1755vnode_isnocache(vnode_t vp)
1756{
0a7de745 1757 return (vp->v_flag & VNOCACHE_DATA)? 1 : 0;
91447636
A
1758}
1759
1760/*
1761 * has sequential readahead been disabled on this vnode
1762 */
1763int
1764vnode_isnoreadahead(vnode_t vp)
1765{
0a7de745 1766 return (vp->v_flag & VRAOFF)? 1 : 0;
91447636
A
1767}
1768
2d21ac55
A
1769int
1770vnode_is_openevt(vnode_t vp)
1771{
0a7de745 1772 return (vp->v_flag & VOPENEVT)? 1 : 0;
2d21ac55
A
1773}
1774
91447636 1775/* is vnode_t a standard one? */
0a7de745 1776int
91447636
A
1777vnode_isstandard(vnode_t vp)
1778{
0a7de745 1779 return (vp->v_flag & VSTANDARD)? 1 : 0;
91447636
A
1780}
1781
1782/* don't vflush() if SKIPSYSTEM */
0a7de745 1783int
91447636
A
1784vnode_isnoflush(vnode_t vp)
1785{
0a7de745 1786 return (vp->v_flag & VNOFLUSH)? 1 : 0;
91447636
A
1787}
1788
1789/* is vnode_t a regular file */
0a7de745 1790int
91447636
A
1791vnode_isreg(vnode_t vp)
1792{
0a7de745 1793 return (vp->v_type == VREG)? 1 : 0;
91447636
A
1794}
1795
1796/* is vnode_t a directory? */
0a7de745 1797int
91447636
A
1798vnode_isdir(vnode_t vp)
1799{
0a7de745 1800 return (vp->v_type == VDIR)? 1 : 0;
91447636
A
1801}
1802
1803/* is vnode_t a symbolic link ? */
0a7de745 1804int
91447636
A
1805vnode_islnk(vnode_t vp)
1806{
0a7de745 1807 return (vp->v_type == VLNK)? 1 : 0;
91447636
A
1808}
1809
6d2010ae
A
1810int
1811vnode_lookup_continue_needed(vnode_t vp, struct componentname *cnp)
1812{
1813 struct nameidata *ndp = cnp->cn_ndp;
1814
1815 if (ndp == NULL) {
1816 panic("vnode_lookup_continue_needed(): cnp->cn_ndp is NULL\n");
1817 }
1818
1819 if (vnode_isdir(vp)) {
1820 if (vp->v_mountedhere != NULL) {
1821 goto yes;
1822 }
1823
1824#if CONFIG_TRIGGERS
1825 if (vp->v_resolve) {
1826 goto yes;
1827 }
1828#endif /* CONFIG_TRIGGERS */
6d2010ae
A
1829 }
1830
1831
1832 if (vnode_islnk(vp)) {
1833 /* From lookup(): || *ndp->ni_next == '/') No need for this, we know we're NULL-terminated here */
0a7de745 1834 if (cnp->cn_flags & FOLLOW) {
6d2010ae
A
1835 goto yes;
1836 }
1837 if (ndp->ni_flag & NAMEI_TRAILINGSLASH) {
1838 goto yes;
1839 }
1840 }
1841
1842 return 0;
1843
1844yes:
1845 ndp->ni_flag |= NAMEI_CONTLOOKUP;
1846 return EKEEPLOOKING;
1847}
1848
91447636 1849/* is vnode_t a fifo ? */
0a7de745 1850int
91447636
A
1851vnode_isfifo(vnode_t vp)
1852{
0a7de745 1853 return (vp->v_type == VFIFO)? 1 : 0;
91447636
A
1854}
1855
1856/* is vnode_t a block device? */
0a7de745 1857int
91447636
A
1858vnode_isblk(vnode_t vp)
1859{
0a7de745 1860 return (vp->v_type == VBLK)? 1 : 0;
91447636
A
1861}
1862
b0d623f7
A
1863int
1864vnode_isspec(vnode_t vp)
1865{
0a7de745 1866 return ((vp->v_type == VCHR) || (vp->v_type == VBLK)) ? 1 : 0;
b0d623f7
A
1867}
1868
91447636 1869/* is vnode_t a char device? */
0a7de745 1870int
91447636
A
1871vnode_ischr(vnode_t vp)
1872{
0a7de745 1873 return (vp->v_type == VCHR)? 1 : 0;
91447636
A
1874}
1875
1876/* is vnode_t a socket? */
0a7de745 1877int
91447636
A
1878vnode_issock(vnode_t vp)
1879{
0a7de745 1880 return (vp->v_type == VSOCK)? 1 : 0;
91447636
A
1881}
1882
b0d623f7
A
1883/* is vnode_t a device with multiple active vnodes referring to it? */
1884int
1885vnode_isaliased(vnode_t vp)
0a7de745 1886{
b0d623f7
A
1887 enum vtype vt = vp->v_type;
1888 if (!((vt == VCHR) || (vt == VBLK))) {
1889 return 0;
1890 } else {
0a7de745 1891 return vp->v_specflags & SI_ALIASED;
b0d623f7
A
1892 }
1893}
1894
2d21ac55 1895/* is vnode_t a named stream? */
0a7de745 1896int
2d21ac55
A
1897vnode_isnamedstream(
1898#if NAMEDSTREAMS
0a7de745 1899 vnode_t vp
2d21ac55 1900#else
0a7de745 1901 __unused vnode_t vp
2d21ac55 1902#endif
0a7de745 1903 )
2d21ac55
A
1904{
1905#if NAMEDSTREAMS
0a7de745 1906 return (vp->v_flag & VISNAMEDSTREAM) ? 1 : 0;
2d21ac55 1907#else
0a7de745 1908 return 0;
2d21ac55
A
1909#endif
1910}
91447636 1911
0a7de745 1912int
c910b4d9
A
1913vnode_isshadow(
1914#if NAMEDSTREAMS
0a7de745 1915 vnode_t vp
c910b4d9 1916#else
0a7de745 1917 __unused vnode_t vp
c910b4d9 1918#endif
0a7de745 1919 )
c910b4d9
A
1920{
1921#if NAMEDSTREAMS
0a7de745 1922 return (vp->v_flag & VISSHADOW) ? 1 : 0;
c910b4d9 1923#else
0a7de745 1924 return 0;
c910b4d9
A
1925#endif
1926}
1927
b0d623f7 1928/* does vnode have associated named stream vnodes ? */
0a7de745 1929int
b0d623f7
A
1930vnode_hasnamedstreams(
1931#if NAMEDSTREAMS
0a7de745 1932 vnode_t vp
b0d623f7 1933#else
0a7de745 1934 __unused vnode_t vp
b0d623f7 1935#endif
0a7de745 1936 )
b0d623f7
A
1937{
1938#if NAMEDSTREAMS
0a7de745 1939 return (vp->v_lflag & VL_HASSTREAMS) ? 1 : 0;
b0d623f7 1940#else
0a7de745 1941 return 0;
b0d623f7
A
1942#endif
1943}
91447636 1944/* TBD: set vnode_t to not cache data after it is consumed once; used for quota */
0a7de745 1945void
91447636
A
1946vnode_setnocache(vnode_t vp)
1947{
2d21ac55 1948 vnode_lock_spin(vp);
91447636
A
1949 vp->v_flag |= VNOCACHE_DATA;
1950 vnode_unlock(vp);
1951}
1952
0a7de745 1953void
91447636
A
1954vnode_clearnocache(vnode_t vp)
1955{
2d21ac55 1956 vnode_lock_spin(vp);
91447636
A
1957 vp->v_flag &= ~VNOCACHE_DATA;
1958 vnode_unlock(vp);
1959}
1960
2d21ac55
A
1961void
1962vnode_set_openevt(vnode_t vp)
1963{
1964 vnode_lock_spin(vp);
1965 vp->v_flag |= VOPENEVT;
1966 vnode_unlock(vp);
1967}
1968
1969void
1970vnode_clear_openevt(vnode_t vp)
1971{
1972 vnode_lock_spin(vp);
1973 vp->v_flag &= ~VOPENEVT;
1974 vnode_unlock(vp);
1975}
1976
1977
0a7de745 1978void
91447636
A
1979vnode_setnoreadahead(vnode_t vp)
1980{
2d21ac55 1981 vnode_lock_spin(vp);
91447636
A
1982 vp->v_flag |= VRAOFF;
1983 vnode_unlock(vp);
1984}
1985
0a7de745 1986void
91447636
A
1987vnode_clearnoreadahead(vnode_t vp)
1988{
2d21ac55 1989 vnode_lock_spin(vp);
91447636
A
1990 vp->v_flag &= ~VRAOFF;
1991 vnode_unlock(vp);
1992}
1993
3e170ce0
A
1994int
1995vnode_isfastdevicecandidate(vnode_t vp)
1996{
0a7de745 1997 return (vp->v_flag & VFASTDEVCANDIDATE)? 1 : 0;
3e170ce0
A
1998}
1999
2000void
2001vnode_setfastdevicecandidate(vnode_t vp)
2002{
2003 vnode_lock_spin(vp);
2004 vp->v_flag |= VFASTDEVCANDIDATE;
2005 vnode_unlock(vp);
2006}
2007
2008void
2009vnode_clearfastdevicecandidate(vnode_t vp)
2010{
2011 vnode_lock_spin(vp);
2012 vp->v_flag &= ~VFASTDEVCANDIDATE;
2013 vnode_unlock(vp);
2014}
2015
2016int
2017vnode_isautocandidate(vnode_t vp)
2018{
0a7de745 2019 return (vp->v_flag & VAUTOCANDIDATE)? 1 : 0;
3e170ce0
A
2020}
2021
2022void
2023vnode_setautocandidate(vnode_t vp)
2024{
2025 vnode_lock_spin(vp);
2026 vp->v_flag |= VAUTOCANDIDATE;
2027 vnode_unlock(vp);
2028}
2029
2030void
2031vnode_clearautocandidate(vnode_t vp)
2032{
2033 vnode_lock_spin(vp);
2034 vp->v_flag &= ~VAUTOCANDIDATE;
2035 vnode_unlock(vp);
2036}
2037
2038
2039
91447636
A
2040
2041/* mark vnode_t to skip vflush() is SKIPSYSTEM */
0a7de745 2042void
91447636
A
2043vnode_setnoflush(vnode_t vp)
2044{
2d21ac55 2045 vnode_lock_spin(vp);
91447636
A
2046 vp->v_flag |= VNOFLUSH;
2047 vnode_unlock(vp);
2048}
2049
0a7de745 2050void
91447636
A
2051vnode_clearnoflush(vnode_t vp)
2052{
2d21ac55 2053 vnode_lock_spin(vp);
91447636
A
2054 vp->v_flag &= ~VNOFLUSH;
2055 vnode_unlock(vp);
2056}
2057
2058
2059/* is vnode_t a blkdevice and has a FS mounted on it */
0a7de745 2060int
91447636
A
2061vnode_ismountedon(vnode_t vp)
2062{
0a7de745 2063 return (vp->v_specflags & SI_MOUNTEDON)? 1 : 0;
91447636
A
2064}
2065
0a7de745 2066void
91447636
A
2067vnode_setmountedon(vnode_t vp)
2068{
2d21ac55 2069 vnode_lock_spin(vp);
91447636
A
2070 vp->v_specflags |= SI_MOUNTEDON;
2071 vnode_unlock(vp);
2072}
2073
0a7de745 2074void
91447636
A
2075vnode_clearmountedon(vnode_t vp)
2076{
2d21ac55 2077 vnode_lock_spin(vp);
91447636
A
2078 vp->v_specflags &= ~SI_MOUNTEDON;
2079 vnode_unlock(vp);
2080}
2081
2082
2083void
2084vnode_settag(vnode_t vp, int tag)
2085{
f427ee49
A
2086 /*
2087 * We only assign enum values to v_tag, but add an assert to make sure we
2088 * catch it in dev/debug builds if this ever change.
2089 */
2090 assert(tag >= SHRT_MIN && tag <= SHRT_MAX);
2091 vp->v_tag = (uint16_t)tag;
91447636
A
2092}
2093
2094int
2095vnode_tag(vnode_t vp)
2096{
0a7de745 2097 return vp->v_tag;
91447636
A
2098}
2099
0a7de745 2100vnode_t
91447636
A
2101vnode_parent(vnode_t vp)
2102{
0a7de745 2103 return vp->v_parent;
91447636
A
2104}
2105
2106void
2107vnode_setparent(vnode_t vp, vnode_t dvp)
2108{
2109 vp->v_parent = dvp;
2110}
2111
91447636
A
2112void
2113vnode_setname(vnode_t vp, char * name)
2114{
2115 vp->v_name = name;
2116}
2117
2118/* return the registered FS name when adding the FS to kernel */
0a7de745 2119void
91447636
A
2120vnode_vfsname(vnode_t vp, char * buf)
2121{
0a7de745 2122 strlcpy(buf, vp->v_mount->mnt_vtable->vfc_name, MFSNAMELEN);
91447636
A
2123}
2124
2125/* return the FS type number */
0a7de745 2126int
91447636
A
2127vnode_vfstypenum(vnode_t vp)
2128{
0a7de745 2129 return vp->v_mount->mnt_vtable->vfc_typenum;
91447636
A
2130}
2131
2132int
0a7de745 2133vnode_vfs64bitready(vnode_t vp)
91447636 2134{
0a7de745 2135 /*
b0d623f7
A
2136 * Checking for dead_mountp is a bit of a hack for SnowLeopard: <rdar://problem/6269051>
2137 */
0a7de745
A
2138 if ((vp->v_mount != dead_mountp) && (vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFS64BITREADY)) {
2139 return 1;
2140 } else {
2141 return 0;
2142 }
91447636
A
2143}
2144
2145
2146
2147/* return the visible flags on associated mount point of vnode_t */
0a7de745 2148uint32_t
91447636
A
2149vnode_vfsvisflags(vnode_t vp)
2150{
0a7de745 2151 return vp->v_mount->mnt_flag & MNT_VISFLAGMASK;
91447636
A
2152}
2153
2154/* return the command modifier flags on associated mount point of vnode_t */
0a7de745 2155uint32_t
91447636
A
2156vnode_vfscmdflags(vnode_t vp)
2157{
0a7de745 2158 return vp->v_mount->mnt_flag & MNT_CMDFLAGS;
91447636
A
2159}
2160
2161/* return the max symlink of short links of vnode_t */
0a7de745 2162uint32_t
91447636
A
2163vnode_vfsmaxsymlen(vnode_t vp)
2164{
0a7de745 2165 return vp->v_mount->mnt_maxsymlinklen;
91447636
A
2166}
2167
2168/* return a pointer to the RO vfs_statfs associated with vnode_t's mount point */
2169struct vfsstatfs *
2170vnode_vfsstatfs(vnode_t vp)
2171{
0a7de745 2172 return &vp->v_mount->mnt_vfsstat;
91447636
A
2173}
2174
2175/* return a handle to the FSs specific private handle associated with vnode_t's mount point */
2176void *
2177vnode_vfsfsprivate(vnode_t vp)
2178{
0a7de745 2179 return vp->v_mount->mnt_data;
91447636
A
2180}
2181
2182/* is vnode_t in a rdonly mounted FS */
0a7de745 2183int
91447636
A
2184vnode_vfsisrdonly(vnode_t vp)
2185{
0a7de745 2186 return (vp->v_mount->mnt_flag & MNT_RDONLY)? 1 : 0;
91447636
A
2187}
2188
6d2010ae 2189int
0a7de745 2190vnode_compound_rename_available(vnode_t vp)
6d2010ae
A
2191{
2192 return vnode_compound_op_available(vp, COMPOUND_VNOP_RENAME);
2193}
2194int
0a7de745 2195vnode_compound_rmdir_available(vnode_t vp)
6d2010ae
A
2196{
2197 return vnode_compound_op_available(vp, COMPOUND_VNOP_RMDIR);
2198}
2199int
0a7de745 2200vnode_compound_mkdir_available(vnode_t vp)
6d2010ae
A
2201{
2202 return vnode_compound_op_available(vp, COMPOUND_VNOP_MKDIR);
2203}
2204int
0a7de745 2205vnode_compound_remove_available(vnode_t vp)
6d2010ae
A
2206{
2207 return vnode_compound_op_available(vp, COMPOUND_VNOP_REMOVE);
2208}
2209int
0a7de745 2210vnode_compound_open_available(vnode_t vp)
6d2010ae
A
2211{
2212 return vnode_compound_op_available(vp, COMPOUND_VNOP_OPEN);
2213}
2214
2215int
0a7de745 2216vnode_compound_op_available(vnode_t vp, compound_vnop_id_t opid)
6d2010ae 2217{
0a7de745 2218 return (vp->v_mount->mnt_compound_ops & opid) != 0;
6d2010ae 2219}
91447636 2220
2d21ac55
A
2221/*
2222 * Returns vnode ref to current working directory; if a per-thread current
2223 * working directory is in effect, return that instead of the per process one.
2224 *
2225 * XXX Published, but not used.
2226 */
0a7de745 2227vnode_t
91447636
A
2228current_workingdir(void)
2229{
2d21ac55 2230 return vfs_context_cwd(vfs_context_current());
91447636
A
2231}
2232
0c530ab8
A
2233/*
2234 * Get a filesec and optional acl contents from an extended attribute.
2235 * Function will attempt to retrive ACL, UUID, and GUID information using a
2236 * read of a named extended attribute (KAUTH_FILESEC_XATTR).
2237 *
2238 * Parameters: vp The vnode on which to operate.
2239 * fsecp The filesec (and ACL, if any) being
2240 * retrieved.
2241 * ctx The vnode context in which the
2242 * operation is to be attempted.
2243 *
2244 * Returns: 0 Success
2245 * !0 errno value
2246 *
2247 * Notes: The kauth_filesec_t in '*fsecp', if retrieved, will be in
2248 * host byte order, as will be the ACL contents, if any.
2249 * Internally, we will cannonize these values from network (PPC)
2250 * byte order after we retrieve them so that the on-disk contents
2251 * of the extended attribute are identical for both PPC and Intel
2252 * (if we were not being required to provide this service via
2253 * fallback, this would be the job of the filesystem
2254 * 'VNOP_GETATTR' call).
2255 *
2256 * We use ntohl() because it has a transitive property on Intel
2257 * machines and no effect on PPC mancines. This guarantees us
2258 *
2259 * XXX: Deleting rather than ignoreing a corrupt security structure is
2260 * probably the only way to reset it without assistance from an
2261 * file system integrity checking tool. Right now we ignore it.
2262 *
2263 * XXX: We should enummerate the possible errno values here, and where
2264 * in the code they originated.
2265 */
91447636
A
2266static int
2267vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
2268{
2269 kauth_filesec_t fsec;
0a7de745
A
2270 uio_t fsec_uio;
2271 size_t fsec_size;
2272 size_t xsize, rsize;
2273 int error;
2274 uint32_t host_fsec_magic;
2275 uint32_t host_acl_entrycount;
91447636
A
2276
2277 fsec = NULL;
2278 fsec_uio = NULL;
39037602 2279
91447636 2280 /* find out how big the EA is */
39037602
A
2281 error = vn_getxattr(vp, KAUTH_FILESEC_XATTR, NULL, &xsize, XATTR_NOSECURITY, ctx);
2282 if (error != 0) {
91447636 2283 /* no EA, no filesec */
0a7de745 2284 if ((error == ENOATTR) || (error == ENOENT) || (error == EJUSTRETURN)) {
91447636 2285 error = 0;
0a7de745 2286 }
91447636
A
2287 /* either way, we are done */
2288 goto out;
2289 }
0c530ab8
A
2290
2291 /*
2292 * To be valid, a kauth_filesec_t must be large enough to hold a zero
2293 * ACE entrly ACL, and if it's larger than that, it must have the right
2294 * number of bytes such that it contains an atomic number of ACEs,
2295 * rather than partial entries. Otherwise, we ignore it.
2296 */
2297 if (!KAUTH_FILESEC_VALID(xsize)) {
0a7de745 2298 KAUTH_DEBUG(" ERROR - Bogus kauth_fiilesec_t: %ld bytes", xsize);
0c530ab8
A
2299 error = 0;
2300 goto out;
2301 }
0a7de745 2302
91447636
A
2303 /* how many entries would fit? */
2304 fsec_size = KAUTH_FILESEC_COUNT(xsize);
5ba3f43e
A
2305 if (fsec_size > KAUTH_ACL_MAX_ENTRIES) {
2306 KAUTH_DEBUG(" ERROR - Bogus (too large) kauth_fiilesec_t: %ld bytes", xsize);
2307 error = 0;
2308 goto out;
2309 }
91447636
A
2310
2311 /* get buffer and uio */
f427ee49 2312 if (((fsec = kauth_filesec_alloc((int)fsec_size)) == NULL) ||
91447636
A
2313 ((fsec_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ)) == NULL) ||
2314 uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), xsize)) {
0a7de745 2315 KAUTH_DEBUG(" ERROR - could not allocate iov to read ACL");
91447636
A
2316 error = ENOMEM;
2317 goto out;
2318 }
2319
2320 /* read security attribute */
2321 rsize = xsize;
2322 if ((error = vn_getxattr(vp,
0a7de745
A
2323 KAUTH_FILESEC_XATTR,
2324 fsec_uio,
2325 &rsize,
2326 XATTR_NOSECURITY,
2327 ctx)) != 0) {
91447636 2328 /* no attribute - no security data */
0a7de745 2329 if ((error == ENOATTR) || (error == ENOENT) || (error == EJUSTRETURN)) {
91447636 2330 error = 0;
0a7de745 2331 }
91447636
A
2332 /* either way, we are done */
2333 goto out;
2334 }
2335
2336 /*
0c530ab8
A
2337 * Validate security structure; the validation must take place in host
2338 * byte order. If it's corrupt, we will just ignore it.
91447636 2339 */
0c530ab8
A
2340
2341 /* Validate the size before trying to convert it */
91447636
A
2342 if (rsize < KAUTH_FILESEC_SIZE(0)) {
2343 KAUTH_DEBUG("ACL - DATA TOO SMALL (%d)", rsize);
2344 goto out;
2345 }
0c530ab8
A
2346
2347 /* Validate the magic number before trying to convert it */
2348 host_fsec_magic = ntohl(KAUTH_FILESEC_MAGIC);
2349 if (fsec->fsec_magic != host_fsec_magic) {
2350 KAUTH_DEBUG("ACL - BAD MAGIC %x", host_fsec_magic);
6601e61a
A
2351 goto out;
2352 }
0c530ab8
A
2353
2354 /* Validate the entry count before trying to convert it. */
2355 host_acl_entrycount = ntohl(fsec->fsec_acl.acl_entrycount);
2356 if (host_acl_entrycount != KAUTH_FILESEC_NOACL) {
2357 if (host_acl_entrycount > KAUTH_ACL_MAX_ENTRIES) {
2358 KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", host_acl_entrycount);
2359 goto out;
2360 }
0a7de745 2361 if (KAUTH_FILESEC_SIZE(host_acl_entrycount) > rsize) {
0c530ab8
A
2362 KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", host_acl_entrycount, rsize);
2363 goto out;
2364 }
91447636 2365 }
4452a7af 2366
0c530ab8
A
2367 kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, NULL);
2368
91447636
A
2369 *fsecp = fsec;
2370 fsec = NULL;
2371 error = 0;
2372out:
0a7de745 2373 if (fsec != NULL) {
91447636 2374 kauth_filesec_free(fsec);
0a7de745
A
2375 }
2376 if (fsec_uio != NULL) {
91447636 2377 uio_free(fsec_uio);
0a7de745
A
2378 }
2379 if (error) {
91447636 2380 *fsecp = NULL;
0a7de745
A
2381 }
2382 return error;
91447636
A
2383}
2384
0c530ab8
A
2385/*
2386 * Set a filesec and optional acl contents into an extended attribute.
2387 * function will attempt to store ACL, UUID, and GUID information using a
2388 * write to a named extended attribute (KAUTH_FILESEC_XATTR). The 'acl'
2389 * may or may not point to the `fsec->fsec_acl`, depending on whether the
2390 * original caller supplied an acl.
2391 *
2392 * Parameters: vp The vnode on which to operate.
2393 * fsec The filesec being set.
2394 * acl The acl to be associated with 'fsec'.
2395 * ctx The vnode context in which the
2396 * operation is to be attempted.
2397 *
2398 * Returns: 0 Success
2399 * !0 errno value
2400 *
2401 * Notes: Both the fsec and the acl are always valid.
2402 *
2403 * The kauth_filesec_t in 'fsec', if any, is in host byte order,
2404 * as are the acl contents, if they are used. Internally, we will
2405 * cannonize these values into network (PPC) byte order before we
2406 * attempt to write them so that the on-disk contents of the
2407 * extended attribute are identical for both PPC and Intel (if we
2408 * were not being required to provide this service via fallback,
2409 * this would be the job of the filesystem 'VNOP_SETATTR' call).
2410 * We reverse this process on the way out, so we leave with the
2411 * same byte order we started with.
2412 *
2413 * XXX: We should enummerate the possible errno values here, and where
2414 * in the code they originated.
2415 */
91447636
A
2416static int
2417vnode_set_filesec(vnode_t vp, kauth_filesec_t fsec, kauth_acl_t acl, vfs_context_t ctx)
2418{
0a7de745
A
2419 uio_t fsec_uio;
2420 int error;
2421 uint32_t saved_acl_copysize;
91447636
A
2422
2423 fsec_uio = NULL;
0a7de745 2424
91447636 2425 if ((fsec_uio = uio_create(2, 0, UIO_SYSSPACE, UIO_WRITE)) == NULL) {
0a7de745 2426 KAUTH_DEBUG(" ERROR - could not allocate iov to write ACL");
91447636
A
2427 error = ENOMEM;
2428 goto out;
2429 }
0c530ab8
A
2430 /*
2431 * Save the pre-converted ACL copysize, because it gets swapped too
2432 * if we are running with the wrong endianness.
2433 */
2434 saved_acl_copysize = KAUTH_ACL_COPYSIZE(acl);
2435
2436 kauth_filesec_acl_setendian(KAUTH_ENDIAN_DISK, fsec, acl);
2437
b0d623f7 2438 uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), KAUTH_FILESEC_SIZE(0) - KAUTH_ACL_SIZE(KAUTH_FILESEC_NOACL));
0c530ab8 2439 uio_addiov(fsec_uio, CAST_USER_ADDR_T(acl), saved_acl_copysize);
91447636
A
2440 error = vn_setxattr(vp,
2441 KAUTH_FILESEC_XATTR,
2442 fsec_uio,
0a7de745 2443 XATTR_NOSECURITY, /* we have auth'ed already */
91447636
A
2444 ctx);
2445 VFS_DEBUG(ctx, vp, "SETATTR - set ACL returning %d", error);
2446
0c530ab8
A
2447 kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, acl);
2448
91447636 2449out:
0a7de745 2450 if (fsec_uio != NULL) {
91447636 2451 uio_free(fsec_uio);
0a7de745
A
2452 }
2453 return error;
91447636
A
2454}
2455
f427ee49
A
2456/*
2457 * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here.
2458 */
2459void
2460vnode_attr_handle_mnt_ignore_ownership(struct vnode_attr *vap, mount_t mp, vfs_context_t ctx)
2461{
2462 uid_t nuid;
2463 gid_t ngid;
2464
2465 if (VATTR_IS_ACTIVE(vap, va_uid)) {
2466 if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_uid)) {
2467 nuid = vap->va_uid;
2468 } else if (mp->mnt_flag & MNT_IGNORE_OWNERSHIP) {
2469 nuid = mp->mnt_fsowner;
2470 if (nuid == KAUTH_UID_NONE) {
2471 nuid = 99;
2472 }
2473 } else if (VATTR_IS_SUPPORTED(vap, va_uid)) {
2474 nuid = vap->va_uid;
2475 } else {
2476 /* this will always be something sensible */
2477 nuid = mp->mnt_fsowner;
2478 }
2479 if ((nuid == 99) && !vfs_context_issuser(ctx)) {
2480 nuid = kauth_cred_getuid(vfs_context_ucred(ctx));
2481 }
2482 VATTR_RETURN(vap, va_uid, nuid);
2483 }
2484 if (VATTR_IS_ACTIVE(vap, va_gid)) {
2485 if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_gid)) {
2486 ngid = vap->va_gid;
2487 } else if (mp->mnt_flag & MNT_IGNORE_OWNERSHIP) {
2488 ngid = mp->mnt_fsgroup;
2489 if (ngid == KAUTH_GID_NONE) {
2490 ngid = 99;
2491 }
2492 } else if (VATTR_IS_SUPPORTED(vap, va_gid)) {
2493 ngid = vap->va_gid;
2494 } else {
2495 /* this will always be something sensible */
2496 ngid = mp->mnt_fsgroup;
2497 }
2498 if ((ngid == 99) && !vfs_context_issuser(ctx)) {
2499 ngid = kauth_cred_getgid(vfs_context_ucred(ctx));
2500 }
2501 VATTR_RETURN(vap, va_gid, ngid);
2502 }
2503}
91447636 2504
2d21ac55
A
2505/*
2506 * Returns: 0 Success
2507 * ENOMEM Not enough space [only if has filesec]
5ba3f43e 2508 * EINVAL Requested unknown attributes
2d21ac55
A
2509 * VNOP_GETATTR: ???
2510 * vnode_get_filesec: ???
2511 * kauth_cred_guid2uid: ???
2512 * kauth_cred_guid2gid: ???
2513 * vfs_update_vfsstat: ???
2514 */
91447636
A
2515int
2516vnode_getattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
2517{
2518 kauth_filesec_t fsec;
2519 kauth_acl_t facl;
0a7de745 2520 int error;
91447636 2521
5ba3f43e
A
2522 /*
2523 * Reject attempts to fetch unknown attributes.
2524 */
0a7de745
A
2525 if (vap->va_active & ~VNODE_ATTR_ALL) {
2526 return EINVAL;
2527 }
5ba3f43e 2528
91447636
A
2529 /* don't ask for extended security data if the filesystem doesn't support it */
2530 if (!vfs_extendedsecurity(vnode_mount(vp))) {
2531 VATTR_CLEAR_ACTIVE(vap, va_acl);
2532 VATTR_CLEAR_ACTIVE(vap, va_uuuid);
2533 VATTR_CLEAR_ACTIVE(vap, va_guuid);
2534 }
2535
2536 /*
2537 * If the caller wants size values we might have to synthesise, give the
2538 * filesystem the opportunity to supply better intermediate results.
2539 */
2540 if (VATTR_IS_ACTIVE(vap, va_data_alloc) ||
2541 VATTR_IS_ACTIVE(vap, va_total_size) ||
2542 VATTR_IS_ACTIVE(vap, va_total_alloc)) {
2543 VATTR_SET_ACTIVE(vap, va_data_size);
2544 VATTR_SET_ACTIVE(vap, va_data_alloc);
2545 VATTR_SET_ACTIVE(vap, va_total_size);
2546 VATTR_SET_ACTIVE(vap, va_total_alloc);
2547 }
0a7de745 2548
cb323159
A
2549 vap->va_vaflags &= ~VA_USEFSID;
2550
91447636
A
2551 error = VNOP_GETATTR(vp, vap, ctx);
2552 if (error) {
2553 KAUTH_DEBUG("ERROR - returning %d", error);
2554 goto out;
2555 }
2556
2557 /*
2558 * If extended security data was requested but not returned, try the fallback
2559 * path.
2560 */
2561 if (VATTR_NOT_RETURNED(vap, va_acl) || VATTR_NOT_RETURNED(vap, va_uuuid) || VATTR_NOT_RETURNED(vap, va_guuid)) {
2562 fsec = NULL;
2563
39236c6e 2564 if (XATTR_VNODE_SUPPORTED(vp)) {
91447636 2565 /* try to get the filesec */
0a7de745 2566 if ((error = vnode_get_filesec(vp, &fsec, ctx)) != 0) {
91447636 2567 goto out;
0a7de745 2568 }
91447636
A
2569 }
2570 /* if no filesec, no attributes */
2571 if (fsec == NULL) {
2572 VATTR_RETURN(vap, va_acl, NULL);
2573 VATTR_RETURN(vap, va_uuuid, kauth_null_guid);
2574 VATTR_RETURN(vap, va_guuid, kauth_null_guid);
2575 } else {
91447636
A
2576 /* looks good, try to return what we were asked for */
2577 VATTR_RETURN(vap, va_uuuid, fsec->fsec_owner);
2578 VATTR_RETURN(vap, va_guuid, fsec->fsec_group);
2579
2580 /* only return the ACL if we were actually asked for it */
2581 if (VATTR_IS_ACTIVE(vap, va_acl)) {
2582 if (fsec->fsec_acl.acl_entrycount == KAUTH_FILESEC_NOACL) {
2583 VATTR_RETURN(vap, va_acl, NULL);
2584 } else {
2585 facl = kauth_acl_alloc(fsec->fsec_acl.acl_entrycount);
2586 if (facl == NULL) {
2587 kauth_filesec_free(fsec);
2588 error = ENOMEM;
2589 goto out;
2590 }
cb323159 2591 __nochk_bcopy(&fsec->fsec_acl, facl, KAUTH_ACL_COPYSIZE(&fsec->fsec_acl));
91447636
A
2592 VATTR_RETURN(vap, va_acl, facl);
2593 }
2594 }
2595 kauth_filesec_free(fsec);
2596 }
2597 }
2598 /*
2599 * If someone gave us an unsolicited filesec, toss it. We promise that
2600 * we're OK with a filesystem giving us anything back, but our callers
2601 * only expect what they asked for.
2602 */
2603 if (VATTR_IS_SUPPORTED(vap, va_acl) && !VATTR_IS_ACTIVE(vap, va_acl)) {
0a7de745 2604 if (vap->va_acl != NULL) {
91447636 2605 kauth_acl_free(vap->va_acl);
0a7de745 2606 }
91447636
A
2607 VATTR_CLEAR_SUPPORTED(vap, va_acl);
2608 }
2609
0a7de745 2610#if 0 /* enable when we have a filesystem only supporting UUIDs */
91447636
A
2611 /*
2612 * Handle the case where we need a UID/GID, but only have extended
2613 * security information.
2614 */
2615 if (VATTR_NOT_RETURNED(vap, va_uid) &&
2616 VATTR_IS_SUPPORTED(vap, va_uuuid) &&
2617 !kauth_guid_equal(&vap->va_uuuid, &kauth_null_guid)) {
0a7de745 2618 if ((error = kauth_cred_guid2uid(&vap->va_uuuid, &nuid)) == 0) {
91447636 2619 VATTR_RETURN(vap, va_uid, nuid);
0a7de745 2620 }
91447636
A
2621 }
2622 if (VATTR_NOT_RETURNED(vap, va_gid) &&
2623 VATTR_IS_SUPPORTED(vap, va_guuid) &&
2624 !kauth_guid_equal(&vap->va_guuid, &kauth_null_guid)) {
0a7de745 2625 if ((error = kauth_cred_guid2gid(&vap->va_guuid, &ngid)) == 0) {
91447636 2626 VATTR_RETURN(vap, va_gid, ngid);
0a7de745 2627 }
91447636
A
2628 }
2629#endif
0a7de745 2630
f427ee49 2631 vnode_attr_handle_mnt_ignore_ownership(vap, vp->v_mount, ctx);
91447636
A
2632
2633 /*
2634 * Synthesise some values that can be reasonably guessed.
2635 */
0a7de745 2636 if (!VATTR_IS_SUPPORTED(vap, va_iosize)) {
f427ee49
A
2637 assert(vp->v_mount->mnt_vfsstat.f_iosize <= UINT32_MAX);
2638 VATTR_RETURN(vap, va_iosize, (uint32_t)vp->v_mount->mnt_vfsstat.f_iosize);
0a7de745
A
2639 }
2640
2641 if (!VATTR_IS_SUPPORTED(vap, va_flags)) {
91447636 2642 VATTR_RETURN(vap, va_flags, 0);
0a7de745 2643 }
91447636 2644
0a7de745 2645 if (!VATTR_IS_SUPPORTED(vap, va_filerev)) {
91447636 2646 VATTR_RETURN(vap, va_filerev, 0);
0a7de745 2647 }
91447636 2648
0a7de745 2649 if (!VATTR_IS_SUPPORTED(vap, va_gen)) {
91447636 2650 VATTR_RETURN(vap, va_gen, 0);
0a7de745 2651 }
91447636
A
2652
2653 /*
2654 * Default sizes. Ordering here is important, as later defaults build on earlier ones.
2655 */
0a7de745 2656 if (!VATTR_IS_SUPPORTED(vap, va_data_size)) {
91447636 2657 VATTR_RETURN(vap, va_data_size, 0);
0a7de745 2658 }
91447636
A
2659
2660 /* do we want any of the possibly-computed values? */
2661 if (VATTR_IS_ACTIVE(vap, va_data_alloc) ||
2662 VATTR_IS_ACTIVE(vap, va_total_size) ||
2663 VATTR_IS_ACTIVE(vap, va_total_alloc)) {
0a7de745
A
2664 /* make sure f_bsize is valid */
2665 if (vp->v_mount->mnt_vfsstat.f_bsize == 0) {
2666 if ((error = vfs_update_vfsstat(vp->v_mount, ctx, VFS_KERNEL_EVENT)) != 0) {
2667 goto out;
2668 }
2669 }
91447636
A
2670
2671 /* default va_data_alloc from va_data_size */
0a7de745 2672 if (!VATTR_IS_SUPPORTED(vap, va_data_alloc)) {
91447636 2673 VATTR_RETURN(vap, va_data_alloc, roundup(vap->va_data_size, vp->v_mount->mnt_vfsstat.f_bsize));
0a7de745 2674 }
91447636
A
2675
2676 /* default va_total_size from va_data_size */
0a7de745 2677 if (!VATTR_IS_SUPPORTED(vap, va_total_size)) {
91447636 2678 VATTR_RETURN(vap, va_total_size, vap->va_data_size);
0a7de745 2679 }
91447636
A
2680
2681 /* default va_total_alloc from va_total_size which is guaranteed at this point */
0a7de745 2682 if (!VATTR_IS_SUPPORTED(vap, va_total_alloc)) {
91447636 2683 VATTR_RETURN(vap, va_total_alloc, roundup(vap->va_total_size, vp->v_mount->mnt_vfsstat.f_bsize));
0a7de745 2684 }
91447636
A
2685 }
2686
2687 /*
2688 * If we don't have a change time, pull it from the modtime.
2689 */
0a7de745 2690 if (!VATTR_IS_SUPPORTED(vap, va_change_time) && VATTR_IS_SUPPORTED(vap, va_modify_time)) {
91447636 2691 VATTR_RETURN(vap, va_change_time, vap->va_modify_time);
0a7de745 2692 }
91447636
A
2693
2694 /*
2695 * This is really only supported for the creation VNOPs, but since the field is there
2696 * we should populate it correctly.
2697 */
2698 VATTR_RETURN(vap, va_type, vp->v_type);
2699
2700 /*
2701 * The fsid can be obtained from the mountpoint directly.
2702 */
cb323159
A
2703 if (VATTR_IS_ACTIVE(vap, va_fsid) &&
2704 (!VATTR_IS_SUPPORTED(vap, va_fsid) ||
2705 vap->va_vaflags & VA_REALFSID || !(vap->va_vaflags & VA_USEFSID))) {
2706 VATTR_RETURN(vap, va_fsid, vp->v_mount->mnt_vfsstat.f_fsid.val[0]);
2707 }
91447636
A
2708
2709out:
cb323159 2710 vap->va_vaflags &= ~VA_USEFSID;
91447636 2711
0a7de745
A
2712 return error;
2713}
2714
2715/*
2716 * Choose 32 bit or 64 bit fsid
2717 */
2718uint64_t
2719vnode_get_va_fsid(struct vnode_attr *vap)
2720{
2721 if (VATTR_IS_SUPPORTED(vap, va_fsid64)) {
2722 return (uint64_t)vap->va_fsid64.val[0] + ((uint64_t)vap->va_fsid64.val[1] << 32);
2723 }
2724 return vap->va_fsid;
91447636
A
2725}
2726
0c530ab8
A
2727/*
2728 * Set the attributes on a vnode in a vnode context.
2729 *
2730 * Parameters: vp The vnode whose attributes to set.
2731 * vap A pointer to the attributes to set.
2732 * ctx The vnode context in which the
2733 * operation is to be attempted.
2734 *
2735 * Returns: 0 Success
2736 * !0 errno value
2737 *
2738 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order.
2739 *
2740 * The contents of the data area pointed to by 'vap' may be
2741 * modified if the vnode is on a filesystem which has been
2742 * mounted with ingore ownership flags, or by the underlyng
2743 * VFS itself, or by the fallback code, if the underlying VFS
2744 * does not support ACL, UUID, or GUUID attributes directly.
2745 *
2746 * XXX: We should enummerate the possible errno values here, and where
2747 * in the code they originated.
2748 */
91447636
A
2749int
2750vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
2751{
0a7de745 2752 int error;
5ba3f43e
A
2753#if CONFIG_FSE
2754 uint64_t active;
0a7de745
A
2755 int is_perm_change = 0;
2756 int is_stat_change = 0;
5ba3f43e
A
2757#endif
2758
2759 /*
2760 * Reject attempts to set unknown attributes.
2761 */
0a7de745
A
2762 if (vap->va_active & ~VNODE_ATTR_ALL) {
2763 return EINVAL;
2764 }
91447636
A
2765
2766 /*
2767 * Make sure the filesystem is mounted R/W.
2768 * If not, return an error.
2769 */
0c530ab8
A
2770 if (vfs_isrdonly(vp->v_mount)) {
2771 error = EROFS;
2772 goto out;
2773 }
813fb2f6 2774
00867663
A
2775#if DEVELOPMENT || DEBUG
2776 /*
2777 * XXX VSWAP: Check for entitlements or special flag here
2778 * so we can restrict access appropriately.
2779 */
2780#else /* DEVELOPMENT || DEBUG */
2781
2782 if (vnode_isswap(vp) && (ctx != vfs_context_kernel())) {
2783 error = EPERM;
2784 goto out;
2785 }
2786#endif /* DEVELOPMENT || DEBUG */
2787
2d21ac55
A
2788#if NAMEDSTREAMS
2789 /* For streams, va_data_size is the only setable attribute. */
2790 if ((vp->v_flag & VISNAMEDSTREAM) && (vap->va_active != VNODE_ATTR_va_data_size)) {
2791 error = EPERM;
2792 goto out;
2793 }
2794#endif
813fb2f6 2795 /* Check for truncation */
0a7de745
A
2796 if (VATTR_IS_ACTIVE(vap, va_data_size)) {
2797 switch (vp->v_type) {
813fb2f6
A
2798 case VREG:
2799 /* For regular files it's ok */
2800 break;
2801 case VDIR:
2802 /* Not allowed to truncate directories */
2803 error = EISDIR;
2804 goto out;
2805 default:
2806 /* For everything else we will clear the bit and let underlying FS decide on the rest */
2807 VATTR_CLEAR_ACTIVE(vap, va_data_size);
0a7de745 2808 if (vap->va_active) {
813fb2f6 2809 break;
0a7de745 2810 }
813fb2f6 2811 /* If it was the only bit set, return success, to handle cases like redirect to /dev/null */
0a7de745 2812 return 0;
813fb2f6
A
2813 }
2814 }
0a7de745 2815
91447636
A
2816 /*
2817 * If ownership is being ignored on this volume, we silently discard
2818 * ownership changes.
2819 */
2820 if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) {
2821 VATTR_CLEAR_ACTIVE(vap, va_uid);
2822 VATTR_CLEAR_ACTIVE(vap, va_gid);
2823 }
2824
91447636
A
2825 /*
2826 * Make sure that extended security is enabled if we're going to try
2827 * to set any.
2828 */
2829 if (!vfs_extendedsecurity(vnode_mount(vp)) &&
2830 (VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_uuuid) || VATTR_IS_ACTIVE(vap, va_guuid))) {
2831 KAUTH_DEBUG("SETATTR - returning ENOTSUP to request to set extended security");
0c530ab8
A
2832 error = ENOTSUP;
2833 goto out;
91447636
A
2834 }
2835
3e170ce0
A
2836 /* Never allow the setting of any unsupported superuser flags. */
2837 if (VATTR_IS_ACTIVE(vap, va_flags)) {
0a7de745 2838 vap->va_flags &= (SF_SUPPORTED | UF_SETTABLE);
3e170ce0
A
2839 }
2840
5ba3f43e
A
2841#if CONFIG_FSE
2842 /*
2843 * Remember all of the active attributes that we're
2844 * attempting to modify.
2845 */
2846 active = vap->va_active & ~VNODE_ATTR_RDONLY;
2847#endif
2848
91447636
A
2849 error = VNOP_SETATTR(vp, vap, ctx);
2850
0a7de745 2851 if ((error == 0) && !VATTR_ALL_SUPPORTED(vap)) {
91447636 2852 error = vnode_setattr_fallback(vp, vap, ctx);
0a7de745 2853 }
91447636 2854
2d21ac55 2855#if CONFIG_FSE
0a7de745
A
2856#define PERMISSION_BITS (VNODE_ATTR_BIT(va_uid) | VNODE_ATTR_BIT(va_uuuid) | \
2857 VNODE_ATTR_BIT(va_gid) | VNODE_ATTR_BIT(va_guuid) | \
2858 VNODE_ATTR_BIT(va_mode) | VNODE_ATTR_BIT(va_acl))
5ba3f43e
A
2859
2860 /*
2861 * Now that we've changed them, decide whether to send an
2862 * FSevent.
2863 */
2864 if ((active & PERMISSION_BITS) & vap->va_supported) {
2865 is_perm_change = 1;
2866 } else {
2867 /*
2868 * We've already checked the permission bits, and we
2869 * also want to filter out access time / backup time
2870 * changes.
2871 */
2872 active &= ~(PERMISSION_BITS |
0a7de745
A
2873 VNODE_ATTR_BIT(va_access_time) |
2874 VNODE_ATTR_BIT(va_backup_time));
5ba3f43e
A
2875
2876 /* Anything left to notify about? */
0a7de745 2877 if (active & vap->va_supported) {
5ba3f43e 2878 is_stat_change = 1;
0a7de745 2879 }
5ba3f43e
A
2880 }
2881
2882 if (error == 0) {
0a7de745
A
2883 if (is_perm_change) {
2884 if (need_fsevent(FSE_CHOWN, vp)) {
2885 add_fsevent(FSE_CHOWN, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
2886 }
2887 } else if (is_stat_change && need_fsevent(FSE_STAT_CHANGED, vp)) {
2888 add_fsevent(FSE_STAT_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
2d21ac55 2889 }
91447636 2890 }
5ba3f43e 2891#undef PERMISSION_BITS
2d21ac55 2892#endif
0c530ab8
A
2893
2894out:
0a7de745 2895 return error;
91447636
A
2896}
2897
2898/*
0c530ab8
A
2899 * Fallback for setting the attributes on a vnode in a vnode context. This
2900 * Function will attempt to store ACL, UUID, and GUID information utilizing
2901 * a read/modify/write operation against an EA used as a backing store for
2902 * the object.
2903 *
2904 * Parameters: vp The vnode whose attributes to set.
2905 * vap A pointer to the attributes to set.
2906 * ctx The vnode context in which the
2907 * operation is to be attempted.
2908 *
2909 * Returns: 0 Success
2910 * !0 errno value
2911 *
2912 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order,
2913 * as are the fsec and lfsec, if they are used.
2914 *
2915 * The contents of the data area pointed to by 'vap' may be
2916 * modified to indicate that the attribute is supported for
2917 * any given requested attribute.
2918 *
2919 * XXX: We should enummerate the possible errno values here, and where
2920 * in the code they originated.
2921 */
91447636
A
2922int
2923vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
2924{
2925 kauth_filesec_t fsec;
2926 kauth_acl_t facl;
2927 struct kauth_filesec lfsec;
0a7de745 2928 int error;
91447636
A
2929
2930 error = 0;
2931
2932 /*
2933 * Extended security fallback via extended attributes.
2934 *
0c530ab8
A
2935 * Note that we do not free the filesec; the caller is expected to
2936 * do this.
91447636
A
2937 */
2938 if (VATTR_NOT_RETURNED(vap, va_acl) ||
2939 VATTR_NOT_RETURNED(vap, va_uuuid) ||
2940 VATTR_NOT_RETURNED(vap, va_guuid)) {
2941 VFS_DEBUG(ctx, vp, "SETATTR - doing filesec fallback");
2942
2943 /*
0c530ab8
A
2944 * Fail for file types that we don't permit extended security
2945 * to be set on.
91447636 2946 */
39236c6e 2947 if (!XATTR_VNODE_SUPPORTED(vp)) {
91447636
A
2948 VFS_DEBUG(ctx, vp, "SETATTR - Can't write ACL to file type %d", vnode_vtype(vp));
2949 error = EINVAL;
2950 goto out;
2951 }
2952
2953 /*
0c530ab8
A
2954 * If we don't have all the extended security items, we need
2955 * to fetch the existing data to perform a read-modify-write
2956 * operation.
91447636
A
2957 */
2958 fsec = NULL;
2959 if (!VATTR_IS_ACTIVE(vap, va_acl) ||
2960 !VATTR_IS_ACTIVE(vap, va_uuuid) ||
2961 !VATTR_IS_ACTIVE(vap, va_guuid)) {
2962 if ((error = vnode_get_filesec(vp, &fsec, ctx)) != 0) {
2963 KAUTH_DEBUG("SETATTR - ERROR %d fetching filesec for update", error);
2964 goto out;
2965 }
2966 }
2967 /* if we didn't get a filesec, use our local one */
2968 if (fsec == NULL) {
2969 KAUTH_DEBUG("SETATTR - using local filesec for new/full update");
2970 fsec = &lfsec;
2971 } else {
2972 KAUTH_DEBUG("SETATTR - updating existing filesec");
2973 }
2974 /* find the ACL */
2975 facl = &fsec->fsec_acl;
0a7de745 2976
91447636
A
2977 /* if we're using the local filesec, we need to initialise it */
2978 if (fsec == &lfsec) {
2979 fsec->fsec_magic = KAUTH_FILESEC_MAGIC;
2980 fsec->fsec_owner = kauth_null_guid;
2981 fsec->fsec_group = kauth_null_guid;
2982 facl->acl_entrycount = KAUTH_FILESEC_NOACL;
2983 facl->acl_flags = 0;
2984 }
2985
2986 /*
2987 * Update with the supplied attributes.
2988 */
2989 if (VATTR_IS_ACTIVE(vap, va_uuuid)) {
2990 KAUTH_DEBUG("SETATTR - updating owner UUID");
2991 fsec->fsec_owner = vap->va_uuuid;
2992 VATTR_SET_SUPPORTED(vap, va_uuuid);
2993 }
2994 if (VATTR_IS_ACTIVE(vap, va_guuid)) {
2995 KAUTH_DEBUG("SETATTR - updating group UUID");
2996 fsec->fsec_group = vap->va_guuid;
2997 VATTR_SET_SUPPORTED(vap, va_guuid);
2998 }
2999 if (VATTR_IS_ACTIVE(vap, va_acl)) {
3000 if (vap->va_acl == NULL) {
3001 KAUTH_DEBUG("SETATTR - removing ACL");
3002 facl->acl_entrycount = KAUTH_FILESEC_NOACL;
3003 } else {
3004 KAUTH_DEBUG("SETATTR - setting ACL with %d entries", vap->va_acl->acl_entrycount);
3005 facl = vap->va_acl;
3006 }
3007 VATTR_SET_SUPPORTED(vap, va_acl);
3008 }
0a7de745 3009
91447636 3010 /*
0c530ab8
A
3011 * If the filesec data is all invalid, we can just remove
3012 * the EA completely.
91447636
A
3013 */
3014 if ((facl->acl_entrycount == KAUTH_FILESEC_NOACL) &&
3015 kauth_guid_equal(&fsec->fsec_owner, &kauth_null_guid) &&
3016 kauth_guid_equal(&fsec->fsec_group, &kauth_null_guid)) {
3017 error = vn_removexattr(vp, KAUTH_FILESEC_XATTR, XATTR_NOSECURITY, ctx);
3018 /* no attribute is ok, nothing to delete */
0a7de745 3019 if (error == ENOATTR) {
91447636 3020 error = 0;
0a7de745 3021 }
91447636
A
3022 VFS_DEBUG(ctx, vp, "SETATTR - remove filesec returning %d", error);
3023 } else {
3024 /* write the EA */
3025 error = vnode_set_filesec(vp, fsec, facl, ctx);
3026 VFS_DEBUG(ctx, vp, "SETATTR - update filesec returning %d", error);
3027 }
3028
3029 /* if we fetched a filesec, dispose of the buffer */
0a7de745 3030 if (fsec != &lfsec) {
91447636 3031 kauth_filesec_free(fsec);
0a7de745 3032 }
91447636
A
3033 }
3034out:
3035
0a7de745 3036 return error;
91447636
A
3037}
3038
b0d623f7
A
3039/*
3040 * Upcall for a filesystem to tell VFS about an EVFILT_VNODE-type
3041 * event on a vnode.
3042 */
3043int
0a7de745 3044vnode_notify(vnode_t vp, uint32_t events, struct vnode_attr *vap)
b0d623f7
A
3045{
3046 /* These are the same as the corresponding knotes, at least for now. Cheating a little. */
0a7de745
A
3047 uint32_t knote_mask = (VNODE_EVENT_WRITE | VNODE_EVENT_DELETE | VNODE_EVENT_RENAME
3048 | VNODE_EVENT_LINK | VNODE_EVENT_EXTEND | VNODE_EVENT_ATTRIB);
3049 uint32_t dir_contents_mask = (VNODE_EVENT_DIR_CREATED | VNODE_EVENT_FILE_CREATED
3050 | VNODE_EVENT_DIR_REMOVED | VNODE_EVENT_FILE_REMOVED);
b0d623f7
A
3051 uint32_t knote_events = (events & knote_mask);
3052
3053 /* Permissions are not explicitly part of the kqueue model */
3054 if (events & VNODE_EVENT_PERMS) {
3055 knote_events |= NOTE_ATTRIB;
0a7de745 3056 }
b0d623f7
A
3057
3058 /* Directory contents information just becomes NOTE_WRITE */
3059 if ((vnode_isdir(vp)) && (events & dir_contents_mask)) {
3060 knote_events |= NOTE_WRITE;
3061 }
0a7de745 3062
b0d623f7
A
3063 if (knote_events) {
3064 lock_vnode_and_post(vp, knote_events);
3065#if CONFIG_FSE
3066 if (vap != NULL) {
3067 create_fsevent_from_kevent(vp, events, vap);
3068 }
3069#else
3070 (void)vap;
3071#endif
0a7de745 3072 }
b0d623f7
A
3073
3074 return 0;
3075}
3076
6d2010ae
A
3077
3078
3079int
3080vnode_isdyldsharedcache(vnode_t vp)
3081{
0a7de745 3082 return (vp->v_flag & VSHARED_DYLD) ? 1 : 0;
6d2010ae
A
3083}
3084
3085
b0d623f7
A
3086/*
3087 * For a filesystem that isn't tracking its own vnode watchers:
3088 * check whether a vnode is being monitored.
3089 */
3090int
0a7de745
A
3091vnode_ismonitored(vnode_t vp)
3092{
3093 return vp->v_knotes.slh_first != NULL;
b0d623f7
A
3094}
3095
d9a64523
A
3096int
3097vnode_getbackingvnode(vnode_t in_vp, vnode_t* out_vpp)
3098{
3099 if (out_vpp) {
3100 *out_vpp = NULLVP;
3101 }
3102#if NULLFS
3103 return nullfs_getbackingvnode(in_vp, out_vpp);
3104#else
3105#pragma unused(in_vp)
3106 return ENOENT;
3107#endif
3108}
3109
b0d623f7
A
3110/*
3111 * Initialize a struct vnode_attr and activate the attributes required
3112 * by the vnode_notify() call.
3113 */
3114int
0a7de745 3115vfs_get_notify_attributes(struct vnode_attr *vap)
b0d623f7 3116{
0a7de745 3117 VATTR_INIT(vap);
b0d623f7
A
3118 vap->va_active = VNODE_NOTIFY_ATTRS;
3119 return 0;
3120}
3121
6d2010ae 3122#if CONFIG_TRIGGERS
0a7de745 3123int
6d2010ae
A
3124vfs_settriggercallback(fsid_t *fsid, vfs_trigger_callback_t vtc, void *data, uint32_t flags __unused, vfs_context_t ctx)
3125{
3126 int error;
3127 mount_t mp;
3128
3129 mp = mount_list_lookupby_fsid(fsid, 0 /* locked */, 1 /* withref */);
3130 if (mp == NULL) {
3131 return ENOENT;
3132 }
3133
3134 error = vfs_busy(mp, LK_NOWAIT);
3135 mount_iterdrop(mp);
3136
3137 if (error != 0) {
3138 return ENOENT;
3139 }
3140
3141 mount_lock(mp);
3142 if (mp->mnt_triggercallback != NULL) {
3143 error = EBUSY;
3144 mount_unlock(mp);
3145 goto out;
3146 }
3147
3148 mp->mnt_triggercallback = vtc;
3149 mp->mnt_triggerdata = data;
3150 mount_unlock(mp);
3151
3152 mp->mnt_triggercallback(mp, VTC_REPLACE, data, ctx);
3153
3154out:
3155 vfs_unbusy(mp);
3156 return 0;
3157}
3158#endif /* CONFIG_TRIGGERS */
3159
91447636
A
3160/*
3161 * Definition of vnode operations.
3162 */
3163
3164#if 0
3165/*
0a7de745
A
3166*#
3167*#% lookup dvp L ? ?
3168*#% lookup vpp - L -
3169*/
91447636
A
3170struct vnop_lookup_args {
3171 struct vnodeop_desc *a_desc;
3172 vnode_t a_dvp;
3173 vnode_t *a_vpp;
3174 struct componentname *a_cnp;
3175 vfs_context_t a_context;
3176};
3177#endif /* 0*/
3178
2d21ac55
A
3179/*
3180 * Returns: 0 Success
3181 * lock_fsnode:ENOENT No such file or directory [only for VFS
3182 * that is not thread safe & vnode is
3183 * currently being/has been terminated]
3184 * <vfs_lookup>:ENAMETOOLONG
3185 * <vfs_lookup>:ENOENT
3186 * <vfs_lookup>:EJUSTRETURN
3187 * <vfs_lookup>:EPERM
3188 * <vfs_lookup>:EISDIR
3189 * <vfs_lookup>:ENOTDIR
3190 * <vfs_lookup>:???
3191 *
3192 * Note: The return codes from the underlying VFS's lookup routine can't
3193 * be fully enumerated here, since third party VFS authors may not
3194 * limit their error returns to the ones documented here, even
3195 * though this may result in some programs functioning incorrectly.
3196 *
3197 * The return codes documented above are those which may currently
3198 * be returned by HFS from hfs_lookup, not including additional
3199 * error code which may be propagated from underlying routines.
3200 */
0a7de745 3201errno_t
2d21ac55 3202VNOP_LOOKUP(vnode_t dvp, vnode_t *vpp, struct componentname *cnp, vfs_context_t ctx)
91447636
A
3203{
3204 int _err;
3205 struct vnop_lookup_args a;
91447636
A
3206
3207 a.a_desc = &vnop_lookup_desc;
3208 a.a_dvp = dvp;
3209 a.a_vpp = vpp;
3210 a.a_cnp = cnp;
2d21ac55 3211 a.a_context = ctx;
91447636 3212
91447636 3213 _err = (*dvp->v_op[vnop_lookup_desc.vdesc_offset])(&a);
39236c6e
A
3214 if (_err == 0 && *vpp) {
3215 DTRACE_FSINFO(lookup, vnode_t, *vpp);
91447636 3216 }
b0d623f7 3217
0a7de745 3218 return _err;
91447636
A
3219}
3220
3221#if 0
6d2010ae
A
3222struct vnop_compound_open_args {
3223 struct vnodeop_desc *a_desc;
3224 vnode_t a_dvp;
3225 vnode_t *a_vpp;
3226 struct componentname *a_cnp;
3227 int32_t a_flags;
3228 int32_t a_fmode;
3229 struct vnode_attr *a_vap;
3230 vfs_context_t a_context;
3231 void *a_reserved;
3232};
3233#endif /* 0 */
3234
3235int
3236VNOP_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)
3237{
3238 int _err;
3239 struct vnop_compound_open_args a;
3240 int did_create = 0;
3241 int want_create;
3242 uint32_t tmp_status = 0;
3243 struct componentname *cnp = &ndp->ni_cnd;
3244
fe8ab488 3245 want_create = (flags & O_CREAT);
6d2010ae
A
3246
3247 a.a_desc = &vnop_compound_open_desc;
3248 a.a_dvp = dvp;
3249 a.a_vpp = vpp; /* Could be NULL */
3250 a.a_cnp = cnp;
3251 a.a_flags = flags;
3252 a.a_fmode = fmode;
3253 a.a_status = (statusp != NULL) ? statusp : &tmp_status;
3254 a.a_vap = vap;
3255 a.a_context = ctx;
3256 a.a_open_create_authorizer = vn_authorize_create;
3257 a.a_open_existing_authorizer = vn_authorize_open_existing;
3258 a.a_reserved = NULL;
3259
3260 if (dvp == NULLVP) {
3261 panic("No dvp?");
3262 }
3263 if (want_create && !vap) {
3264 panic("Want create, but no vap?");
3265 }
3266 if (!want_create && vap) {
3267 panic("Don't want create, but have a vap?");
3268 }
3269
3270 _err = (*dvp->v_op[vnop_compound_open_desc.vdesc_offset])(&a);
39236c6e 3271 if (want_create) {
0a7de745 3272 if (_err == 0 && *vpp) {
39236c6e
A
3273 DTRACE_FSINFO(compound_open, vnode_t, *vpp);
3274 } else {
3275 DTRACE_FSINFO(compound_open, vnode_t, dvp);
3276 }
3277 } else {
3278 DTRACE_FSINFO(compound_open, vnode_t, *vpp);
3279 }
6d2010ae
A
3280
3281 did_create = (*a.a_status & COMPOUND_OPEN_STATUS_DID_CREATE);
3282
3283 if (did_create && !want_create) {
3284 panic("Filesystem did a create, even though none was requested?");
3285 }
3286
0a7de745 3287 if (did_create) {
39236c6e 3288#if CONFIG_APPLEDOUBLE
6d2010ae 3289 if (!NATIVE_XATTR(dvp)) {
0a7de745 3290 /*
6d2010ae
A
3291 * Remove stale Apple Double file (if any).
3292 */
3293 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
3294 }
39236c6e 3295#endif /* CONFIG_APPLEDOUBLE */
6d2010ae
A
3296 /* On create, provide kqueue notification */
3297 post_event_if_success(dvp, _err, NOTE_WRITE);
3298 }
3299
3300 lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, did_create);
3301#if 0 /* FSEvents... */
3302 if (*vpp && _err && _err != EKEEPLOOKING) {
3303 vnode_put(*vpp);
3304 *vpp = NULLVP;
3305 }
3306#endif /* 0 */
3307
0a7de745 3308 return _err;
6d2010ae
A
3309}
3310
3311#if 0
91447636
A
3312struct vnop_create_args {
3313 struct vnodeop_desc *a_desc;
3314 vnode_t a_dvp;
3315 vnode_t *a_vpp;
3316 struct componentname *a_cnp;
3317 struct vnode_attr *a_vap;
3318 vfs_context_t a_context;
3319};
3320#endif /* 0*/
0a7de745 3321errno_t
2d21ac55 3322VNOP_CREATE(vnode_t dvp, vnode_t * vpp, struct componentname * cnp, struct vnode_attr * vap, vfs_context_t ctx)
91447636
A
3323{
3324 int _err;
3325 struct vnop_create_args a;
91447636
A
3326
3327 a.a_desc = &vnop_create_desc;
3328 a.a_dvp = dvp;
3329 a.a_vpp = vpp;
3330 a.a_cnp = cnp;
3331 a.a_vap = vap;
2d21ac55 3332 a.a_context = ctx;
91447636 3333
39236c6e
A
3334 _err = (*dvp->v_op[vnop_create_desc.vdesc_offset])(&a);
3335 if (_err == 0 && *vpp) {
3336 DTRACE_FSINFO(create, vnode_t, *vpp);
91447636 3337 }
b0d623f7 3338
39236c6e 3339#if CONFIG_APPLEDOUBLE
91447636 3340 if (_err == 0 && !NATIVE_XATTR(dvp)) {
0a7de745 3341 /*
91447636
A
3342 * Remove stale Apple Double file (if any).
3343 */
b0d623f7 3344 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
91447636 3345 }
39236c6e 3346#endif /* CONFIG_APPLEDOUBLE */
b0d623f7
A
3347
3348 post_event_if_success(dvp, _err, NOTE_WRITE);
3349
0a7de745 3350 return _err;
91447636
A
3351}
3352
3353#if 0
3354/*
0a7de745
A
3355*#
3356*#% whiteout dvp L L L
3357*#% whiteout cnp - - -
3358*#% whiteout flag - - -
3359*#
3360*/
91447636
A
3361struct vnop_whiteout_args {
3362 struct vnodeop_desc *a_desc;
3363 vnode_t a_dvp;
3364 struct componentname *a_cnp;
3365 int a_flags;
3366 vfs_context_t a_context;
3367};
3368#endif /* 0*/
0a7de745 3369errno_t
fe8ab488 3370VNOP_WHITEOUT(__unused vnode_t dvp, __unused struct componentname *cnp,
0a7de745 3371 __unused int flags, __unused vfs_context_t ctx)
91447636 3372{
0a7de745 3373 return ENOTSUP; // XXX OBSOLETE
91447636
A
3374}
3375
39236c6e 3376#if 0
91447636 3377/*
0a7de745
A
3378*#
3379*#% mknod dvp L U U
3380*#% mknod vpp - X -
3381*#
3382*/
91447636 3383struct vnop_mknod_args {
0a7de745
A
3384 struct vnodeop_desc *a_desc;
3385 vnode_t a_dvp;
3386 vnode_t *a_vpp;
3387 struct componentname *a_cnp;
3388 struct vnode_attr *a_vap;
3389 vfs_context_t a_context;
91447636
A
3390};
3391#endif /* 0*/
3392errno_t
2d21ac55 3393VNOP_MKNOD(vnode_t dvp, vnode_t * vpp, struct componentname * cnp, struct vnode_attr * vap, vfs_context_t ctx)
91447636 3394{
0a7de745
A
3395 int _err;
3396 struct vnop_mknod_args a;
91447636 3397
0a7de745
A
3398 a.a_desc = &vnop_mknod_desc;
3399 a.a_dvp = dvp;
3400 a.a_vpp = vpp;
3401 a.a_cnp = cnp;
3402 a.a_vap = vap;
3403 a.a_context = ctx;
91447636 3404
0a7de745
A
3405 _err = (*dvp->v_op[vnop_mknod_desc.vdesc_offset])(&a);
3406 if (_err == 0 && *vpp) {
39236c6e 3407 DTRACE_FSINFO(mknod, vnode_t, *vpp);
0a7de745 3408 }
b0d623f7 3409
0a7de745 3410 post_event_if_success(dvp, _err, NOTE_WRITE);
b0d623f7 3411
0a7de745 3412 return _err;
91447636
A
3413}
3414
3415#if 0
3416/*
0a7de745
A
3417*#
3418*#% open vp L L L
3419*#
3420*/
91447636
A
3421struct vnop_open_args {
3422 struct vnodeop_desc *a_desc;
3423 vnode_t a_vp;
3424 int a_mode;
3425 vfs_context_t a_context;
3426};
3427#endif /* 0*/
0a7de745
A
3428errno_t
3429VNOP_OPEN(vnode_t vp, int mode, vfs_context_t ctx)
91447636
A
3430{
3431 int _err;
3432 struct vnop_open_args a;
91447636 3433
2d21ac55
A
3434 if (ctx == NULL) {
3435 ctx = vfs_context_current();
0a7de745 3436 }
91447636
A
3437 a.a_desc = &vnop_open_desc;
3438 a.a_vp = vp;
3439 a.a_mode = mode;
0a7de745 3440 a.a_context = ctx;
91447636 3441
91447636 3442 _err = (*vp->v_op[vnop_open_desc.vdesc_offset])(&a);
39236c6e 3443 DTRACE_FSINFO(open, vnode_t, vp);
b0d623f7 3444
0a7de745 3445 return _err;
91447636
A
3446}
3447
3448#if 0
3449/*
0a7de745
A
3450*#
3451*#% close vp U U U
3452*#
3453*/
91447636
A
3454struct vnop_close_args {
3455 struct vnodeop_desc *a_desc;
3456 vnode_t a_vp;
3457 int a_fflag;
3458 vfs_context_t a_context;
3459};
3460#endif /* 0*/
0a7de745 3461errno_t
2d21ac55 3462VNOP_CLOSE(vnode_t vp, int fflag, vfs_context_t ctx)
91447636
A
3463{
3464 int _err;
3465 struct vnop_close_args a;
91447636 3466
2d21ac55
A
3467 if (ctx == NULL) {
3468 ctx = vfs_context_current();
91447636
A
3469 }
3470 a.a_desc = &vnop_close_desc;
3471 a.a_vp = vp;
3472 a.a_fflag = fflag;
2d21ac55 3473 a.a_context = ctx;
91447636 3474
91447636 3475 _err = (*vp->v_op[vnop_close_desc.vdesc_offset])(&a);
39236c6e 3476 DTRACE_FSINFO(close, vnode_t, vp);
b0d623f7 3477
0a7de745 3478 return _err;
91447636
A
3479}
3480
3481#if 0
3482/*
0a7de745
A
3483*#
3484*#% access vp L L L
3485*#
3486*/
91447636
A
3487struct vnop_access_args {
3488 struct vnodeop_desc *a_desc;
3489 vnode_t a_vp;
3490 int a_action;
3491 vfs_context_t a_context;
3492};
3493#endif /* 0*/
0a7de745 3494errno_t
2d21ac55 3495VNOP_ACCESS(vnode_t vp, int action, vfs_context_t ctx)
91447636
A
3496{
3497 int _err;
3498 struct vnop_access_args a;
91447636 3499
2d21ac55
A
3500 if (ctx == NULL) {
3501 ctx = vfs_context_current();
91447636
A
3502 }
3503 a.a_desc = &vnop_access_desc;
3504 a.a_vp = vp;
3505 a.a_action = action;
2d21ac55 3506 a.a_context = ctx;
91447636 3507
91447636 3508 _err = (*vp->v_op[vnop_access_desc.vdesc_offset])(&a);
39236c6e 3509 DTRACE_FSINFO(access, vnode_t, vp);
b0d623f7 3510
0a7de745 3511 return _err;
91447636
A
3512}
3513
3514#if 0
3515/*
0a7de745
A
3516*#
3517*#% getattr vp = = =
3518*#
3519*/
91447636
A
3520struct vnop_getattr_args {
3521 struct vnodeop_desc *a_desc;
3522 vnode_t a_vp;
3523 struct vnode_attr *a_vap;
3524 vfs_context_t a_context;
3525};
3526#endif /* 0*/
0a7de745 3527errno_t
2d21ac55 3528VNOP_GETATTR(vnode_t vp, struct vnode_attr * vap, vfs_context_t ctx)
91447636
A
3529{
3530 int _err;
3531 struct vnop_getattr_args a;
91447636
A
3532
3533 a.a_desc = &vnop_getattr_desc;
3534 a.a_vp = vp;
3535 a.a_vap = vap;
2d21ac55 3536 a.a_context = ctx;
91447636 3537
91447636 3538 _err = (*vp->v_op[vnop_getattr_desc.vdesc_offset])(&a);
39236c6e 3539 DTRACE_FSINFO(getattr, vnode_t, vp);
b0d623f7 3540
0a7de745 3541 return _err;
91447636
A
3542}
3543
3544#if 0
3545/*
0a7de745
A
3546*#
3547*#% setattr vp L L L
3548*#
3549*/
91447636
A
3550struct vnop_setattr_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_SETATTR(vnode_t vp, struct vnode_attr * vap, vfs_context_t ctx)
91447636
A
3559{
3560 int _err;
3561 struct vnop_setattr_args a;
91447636
A
3562
3563 a.a_desc = &vnop_setattr_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_setattr_desc.vdesc_offset])(&a);
39236c6e 3569 DTRACE_FSINFO(setattr, vnode_t, vp);
91447636 3570
39236c6e 3571#if CONFIG_APPLEDOUBLE
0a7de745 3572 /*
2d21ac55 3573 * Shadow uid/gid/mod change to extended attribute file.
91447636
A
3574 */
3575 if (_err == 0 && !NATIVE_XATTR(vp)) {
3576 struct vnode_attr va;
3577 int change = 0;
3578
3579 VATTR_INIT(&va);
3580 if (VATTR_IS_ACTIVE(vap, va_uid)) {
3581 VATTR_SET(&va, va_uid, vap->va_uid);
3582 change = 1;
3583 }
3584 if (VATTR_IS_ACTIVE(vap, va_gid)) {
3585 VATTR_SET(&va, va_gid, vap->va_gid);
3586 change = 1;
3587 }
3588 if (VATTR_IS_ACTIVE(vap, va_mode)) {
3589 VATTR_SET(&va, va_mode, vap->va_mode);
3590 change = 1;
3591 }
3592 if (change) {
0a7de745 3593 vnode_t dvp;
2d21ac55 3594 const char *vname;
91447636
A
3595
3596 dvp = vnode_getparent(vp);
3597 vname = vnode_getname(vp);
3598
b0d623f7 3599 xattrfile_setattr(dvp, vname, &va, ctx);
0a7de745
A
3600 if (dvp != NULLVP) {
3601 vnode_put(dvp);
3602 }
3603 if (vname != NULL) {
3604 vnode_putname(vname);
3605 }
91447636
A
3606 }
3607 }
39236c6e 3608#endif /* CONFIG_APPLEDOUBLE */
b0d623f7 3609
2d21ac55
A
3610 /*
3611 * If we have changed any of the things about the file that are likely
3612 * to result in changes to authorization results, blow the vnode auth
3613 * cache
3614 */
3615 if (_err == 0 && (
0a7de745
A
3616 VATTR_IS_SUPPORTED(vap, va_mode) ||
3617 VATTR_IS_SUPPORTED(vap, va_uid) ||
3618 VATTR_IS_SUPPORTED(vap, va_gid) ||
3619 VATTR_IS_SUPPORTED(vap, va_flags) ||
3620 VATTR_IS_SUPPORTED(vap, va_acl) ||
3621 VATTR_IS_SUPPORTED(vap, va_uuuid) ||
3622 VATTR_IS_SUPPORTED(vap, va_guuid))) {
3623 vnode_uncache_authorized_action(vp, KAUTH_INVALIDATE_CACHED_RIGHTS);
91447636 3624
b0d623f7
A
3625#if NAMEDSTREAMS
3626 if (vfs_authopaque(vp->v_mount) && vnode_hasnamedstreams(vp)) {
3627 vnode_t svp;
3628 if (vnode_getnamedstream(vp, &svp, XATTR_RESOURCEFORK_NAME, NS_OPEN, 0, ctx) == 0) {
3629 vnode_uncache_authorized_action(svp, KAUTH_INVALIDATE_CACHED_RIGHTS);
3630 vnode_put(svp);
0a7de745
A
3631 }
3632 }
b0d623f7
A
3633#endif /* NAMEDSTREAMS */
3634 }
3635
3636
3637 post_event_if_success(vp, _err, NOTE_ATTRIB);
3638
0a7de745 3639 return _err;
91447636
A
3640}
3641
3642
3643#if 0
3644/*
0a7de745
A
3645*#
3646*#% read vp L L L
3647*#
3648*/
91447636
A
3649struct vnop_read_args {
3650 struct vnodeop_desc *a_desc;
3651 vnode_t a_vp;
3652 struct uio *a_uio;
3653 int a_ioflag;
3654 vfs_context_t a_context;
3655};
3656#endif /* 0*/
0a7de745 3657errno_t
2d21ac55 3658VNOP_READ(vnode_t vp, struct uio * uio, int ioflag, vfs_context_t ctx)
91447636
A
3659{
3660 int _err;
3661 struct vnop_read_args a;
39236c6e
A
3662#if CONFIG_DTRACE
3663 user_ssize_t resid = uio_resid(uio);
3664#endif
91447636 3665
2d21ac55 3666 if (ctx == NULL) {
fe8ab488 3667 return EINVAL;
91447636
A
3668 }
3669
3670 a.a_desc = &vnop_read_desc;
3671 a.a_vp = vp;
3672 a.a_uio = uio;
3673 a.a_ioflag = ioflag;
2d21ac55 3674 a.a_context = ctx;
91447636 3675
91447636 3676 _err = (*vp->v_op[vnop_read_desc.vdesc_offset])(&a);
39236c6e
A
3677 DTRACE_FSINFO_IO(read,
3678 vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
b0d623f7 3679
0a7de745 3680 return _err;
91447636
A
3681}
3682
3683
3684#if 0
3685/*
0a7de745
A
3686*#
3687*#% write vp L L L
3688*#
3689*/
91447636
A
3690struct vnop_write_args {
3691 struct vnodeop_desc *a_desc;
3692 vnode_t a_vp;
3693 struct uio *a_uio;
3694 int a_ioflag;
3695 vfs_context_t a_context;
3696};
3697#endif /* 0*/
0a7de745 3698errno_t
2d21ac55 3699VNOP_WRITE(vnode_t vp, struct uio * uio, int ioflag, vfs_context_t ctx)
91447636
A
3700{
3701 struct vnop_write_args a;
3702 int _err;
39236c6e
A
3703#if CONFIG_DTRACE
3704 user_ssize_t resid = uio_resid(uio);
3705#endif
91447636 3706
2d21ac55 3707 if (ctx == NULL) {
fe8ab488 3708 return EINVAL;
91447636
A
3709 }
3710
3711 a.a_desc = &vnop_write_desc;
3712 a.a_vp = vp;
3713 a.a_uio = uio;
3714 a.a_ioflag = ioflag;
2d21ac55 3715 a.a_context = ctx;
91447636 3716
91447636 3717 _err = (*vp->v_op[vnop_write_desc.vdesc_offset])(&a);
39236c6e
A
3718 DTRACE_FSINFO_IO(write,
3719 vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
b0d623f7
A
3720
3721 post_event_if_success(vp, _err, NOTE_WRITE);
3722
0a7de745 3723 return _err;
91447636
A
3724}
3725
3726
3727#if 0
3728/*
0a7de745
A
3729*#
3730*#% ioctl vp U U U
3731*#
3732*/
91447636
A
3733struct vnop_ioctl_args {
3734 struct vnodeop_desc *a_desc;
3735 vnode_t a_vp;
3736 u_long a_command;
3737 caddr_t a_data;
3738 int a_fflag;
3739 vfs_context_t a_context;
3740};
3741#endif /* 0*/
0a7de745 3742errno_t
2d21ac55 3743VNOP_IOCTL(vnode_t vp, u_long command, caddr_t data, int fflag, vfs_context_t ctx)
91447636
A
3744{
3745 int _err;
3746 struct vnop_ioctl_args a;
91447636 3747
2d21ac55
A
3748 if (ctx == NULL) {
3749 ctx = vfs_context_current();
91447636
A
3750 }
3751
b0d623f7
A
3752 /*
3753 * This check should probably have been put in the TTY code instead...
3754 *
3755 * We have to be careful about what we assume during startup and shutdown.
3756 * We have to be able to use the root filesystem's device vnode even when
3757 * devfs isn't mounted (yet/anymore), so we can't go looking at its mount
3758 * structure. If there is no data pointer, it doesn't matter whether
3e170ce0 3759 * the device is 64-bit ready. Any command (like DKIOCSYNCHRONIZE)
b0d623f7
A
3760 * which passes NULL for its data pointer can therefore be used during
3761 * mount or unmount of the root filesystem.
3762 *
3763 * Depending on what root filesystems need to do during mount/unmount, we
3764 * may need to loosen this check again in the future.
3765 */
3766 if (vfs_context_is64bit(ctx) && !(vnode_ischr(vp) || vnode_isblk(vp))) {
3767 if (data != NULL && !vnode_vfs64bitready(vp)) {
0a7de745 3768 return ENOTTY;
91447636
A
3769 }
3770 }
3771
f427ee49
A
3772 if ((command == DKIOCISSOLIDSTATE) && (vp == rootvp) && rootvp_is_ssd && data) {
3773 *data = 1;
3774 return 0;
3775 }
3776
91447636
A
3777 a.a_desc = &vnop_ioctl_desc;
3778 a.a_vp = vp;
3779 a.a_command = command;
3780 a.a_data = data;
3781 a.a_fflag = fflag;
0a7de745 3782 a.a_context = ctx;
91447636 3783
91447636 3784 _err = (*vp->v_op[vnop_ioctl_desc.vdesc_offset])(&a);
39236c6e 3785 DTRACE_FSINFO(ioctl, vnode_t, vp);
b0d623f7 3786
0a7de745 3787 return _err;
91447636
A
3788}
3789
3790
3791#if 0
3792/*
0a7de745
A
3793*#
3794*#% select vp U U U
3795*#
3796*/
91447636
A
3797struct vnop_select_args {
3798 struct vnodeop_desc *a_desc;
3799 vnode_t a_vp;
3800 int a_which;
3801 int a_fflags;
3802 void *a_wql;
3803 vfs_context_t a_context;
3804};
3805#endif /* 0*/
0a7de745
A
3806errno_t
3807VNOP_SELECT(vnode_t vp, int which, int fflags, void * wql, vfs_context_t ctx)
91447636
A
3808{
3809 int _err;
3810 struct vnop_select_args a;
91447636 3811
2d21ac55
A
3812 if (ctx == NULL) {
3813 ctx = vfs_context_current();
91447636
A
3814 }
3815 a.a_desc = &vnop_select_desc;
3816 a.a_vp = vp;
3817 a.a_which = which;
3818 a.a_fflags = fflags;
2d21ac55 3819 a.a_context = ctx;
91447636 3820 a.a_wql = wql;
91447636 3821
91447636 3822 _err = (*vp->v_op[vnop_select_desc.vdesc_offset])(&a);
39236c6e 3823 DTRACE_FSINFO(select, vnode_t, vp);
b0d623f7 3824
0a7de745 3825 return _err;
91447636
A
3826}
3827
3828
3829#if 0
3830/*
0a7de745
A
3831*#
3832*#% exchange fvp L L L
3833*#% exchange tvp L L L
3834*#
3835*/
91447636
A
3836struct vnop_exchange_args {
3837 struct vnodeop_desc *a_desc;
3838 vnode_t a_fvp;
0a7de745
A
3839 vnode_t a_tvp;
3840 int a_options;
91447636
A
3841 vfs_context_t a_context;
3842};
3843#endif /* 0*/
0a7de745 3844errno_t
2d21ac55 3845VNOP_EXCHANGE(vnode_t fvp, vnode_t tvp, int options, vfs_context_t ctx)
91447636
A
3846{
3847 int _err;
3848 struct vnop_exchange_args a;
91447636
A
3849
3850 a.a_desc = &vnop_exchange_desc;
3851 a.a_fvp = fvp;
3852 a.a_tvp = tvp;
3853 a.a_options = options;
2d21ac55 3854 a.a_context = ctx;
91447636 3855
91447636 3856 _err = (*fvp->v_op[vnop_exchange_desc.vdesc_offset])(&a);
39236c6e 3857 DTRACE_FSINFO(exchange, vnode_t, fvp);
b0d623f7
A
3858
3859 /* Don't post NOTE_WRITE because file descriptors follow the data ... */
3860 post_event_if_success(fvp, _err, NOTE_ATTRIB);
3861 post_event_if_success(tvp, _err, NOTE_ATTRIB);
3862
0a7de745 3863 return _err;
91447636
A
3864}
3865
3866
3867#if 0
3868/*
0a7de745
A
3869*#
3870*#% revoke vp U U U
3871*#
3872*/
91447636
A
3873struct vnop_revoke_args {
3874 struct vnodeop_desc *a_desc;
3875 vnode_t a_vp;
3876 int a_flags;
3877 vfs_context_t a_context;
3878};
3879#endif /* 0*/
0a7de745 3880errno_t
2d21ac55 3881VNOP_REVOKE(vnode_t vp, int flags, vfs_context_t ctx)
91447636
A
3882{
3883 struct vnop_revoke_args a;
3884 int _err;
91447636
A
3885
3886 a.a_desc = &vnop_revoke_desc;
3887 a.a_vp = vp;
3888 a.a_flags = flags;
2d21ac55 3889 a.a_context = ctx;
91447636 3890
91447636 3891 _err = (*vp->v_op[vnop_revoke_desc.vdesc_offset])(&a);
39236c6e 3892 DTRACE_FSINFO(revoke, vnode_t, vp);
b0d623f7 3893
0a7de745 3894 return _err;
91447636
A
3895}
3896
3897
cb323159
A
3898#if 0
3899/*
3900*#
3901*# mmap_check - vp U U U
3902*#
3903*/
3904struct vnop_mmap_check_args {
3905 struct vnodeop_desc *a_desc;
3906 vnode_t a_vp;
3907 int a_flags;
3908 vfs_context_t a_context;
3909};
3910#endif /* 0 */
3911errno_t
3912VNOP_MMAP_CHECK(vnode_t vp, int flags, vfs_context_t ctx)
3913{
3914 int _err;
3915 struct vnop_mmap_check_args a;
3916
3917 a.a_desc = &vnop_mmap_check_desc;
3918 a.a_vp = vp;
3919 a.a_flags = flags;
3920 a.a_context = ctx;
3921
3922 _err = (*vp->v_op[vnop_mmap_check_desc.vdesc_offset])(&a);
3923 if (_err == ENOTSUP) {
3924 _err = 0;
3925 }
3926 DTRACE_FSINFO(mmap_check, vnode_t, vp);
3927
3928 return _err;
3929}
3930
91447636
A
3931#if 0
3932/*
0a7de745
A
3933*#
3934*# mmap - vp U U U
3935*#
3936*/
91447636
A
3937struct vnop_mmap_args {
3938 struct vnodeop_desc *a_desc;
3939 vnode_t a_vp;
3940 int a_fflags;
3941 vfs_context_t a_context;
3942};
3943#endif /* 0*/
0a7de745 3944errno_t
2d21ac55 3945VNOP_MMAP(vnode_t vp, int fflags, vfs_context_t ctx)
91447636
A
3946{
3947 int _err;
3948 struct vnop_mmap_args a;
91447636
A
3949
3950 a.a_desc = &vnop_mmap_desc;
3951 a.a_vp = vp;
3952 a.a_fflags = fflags;
2d21ac55 3953 a.a_context = ctx;
91447636 3954
91447636 3955 _err = (*vp->v_op[vnop_mmap_desc.vdesc_offset])(&a);
39236c6e 3956 DTRACE_FSINFO(mmap, vnode_t, vp);
b0d623f7 3957
0a7de745 3958 return _err;
91447636
A
3959}
3960
3961
3962#if 0
3963/*
0a7de745
A
3964*#
3965*# mnomap - vp U U U
3966*#
3967*/
91447636
A
3968struct vnop_mnomap_args {
3969 struct vnodeop_desc *a_desc;
3970 vnode_t a_vp;
3971 vfs_context_t a_context;
3972};
3973#endif /* 0*/
0a7de745 3974errno_t
2d21ac55 3975VNOP_MNOMAP(vnode_t vp, vfs_context_t ctx)
91447636
A
3976{
3977 int _err;
3978 struct vnop_mnomap_args a;
91447636
A
3979
3980 a.a_desc = &vnop_mnomap_desc;
3981 a.a_vp = vp;
2d21ac55 3982 a.a_context = ctx;
91447636 3983
91447636 3984 _err = (*vp->v_op[vnop_mnomap_desc.vdesc_offset])(&a);
39236c6e 3985 DTRACE_FSINFO(mnomap, vnode_t, vp);
b0d623f7 3986
0a7de745 3987 return _err;
91447636
A
3988}
3989
3990
3991#if 0
3992/*
0a7de745
A
3993*#
3994*#% fsync vp L L L
3995*#
3996*/
91447636
A
3997struct vnop_fsync_args {
3998 struct vnodeop_desc *a_desc;
3999 vnode_t a_vp;
4000 int a_waitfor;
4001 vfs_context_t a_context;
4002};
4003#endif /* 0*/
0a7de745 4004errno_t
2d21ac55 4005VNOP_FSYNC(vnode_t vp, int waitfor, vfs_context_t ctx)
91447636
A
4006{
4007 struct vnop_fsync_args a;
4008 int _err;
91447636
A
4009
4010 a.a_desc = &vnop_fsync_desc;
4011 a.a_vp = vp;
4012 a.a_waitfor = waitfor;
2d21ac55 4013 a.a_context = ctx;
91447636 4014
91447636 4015 _err = (*vp->v_op[vnop_fsync_desc.vdesc_offset])(&a);
39236c6e 4016 DTRACE_FSINFO(fsync, vnode_t, vp);
b0d623f7 4017
0a7de745 4018 return _err;
91447636
A
4019}
4020
4021
4022#if 0
4023/*
0a7de745
A
4024*#
4025*#% remove dvp L U U
4026*#% remove vp L U U
4027*#
4028*/
91447636
A
4029struct vnop_remove_args {
4030 struct vnodeop_desc *a_desc;
4031 vnode_t a_dvp;
4032 vnode_t a_vp;
4033 struct componentname *a_cnp;
4034 int a_flags;
4035 vfs_context_t a_context;
4036};
4037#endif /* 0*/
0a7de745 4038errno_t
2d21ac55 4039VNOP_REMOVE(vnode_t dvp, vnode_t vp, struct componentname * cnp, int flags, vfs_context_t ctx)
91447636
A
4040{
4041 int _err;
4042 struct vnop_remove_args a;
91447636
A
4043
4044 a.a_desc = &vnop_remove_desc;
4045 a.a_dvp = dvp;
4046 a.a_vp = vp;
4047 a.a_cnp = cnp;
4048 a.a_flags = flags;
2d21ac55 4049 a.a_context = ctx;
91447636 4050
91447636 4051 _err = (*dvp->v_op[vnop_remove_desc.vdesc_offset])(&a);
39236c6e 4052 DTRACE_FSINFO(remove, vnode_t, vp);
91447636
A
4053
4054 if (_err == 0) {
0a7de745 4055 vnode_setneedinactive(vp);
39236c6e 4056#if CONFIG_APPLEDOUBLE
0a7de745
A
4057 if (!(NATIVE_XATTR(dvp))) {
4058 /*
2d21ac55 4059 * Remove any associated extended attribute file (._ AppleDouble file).
91447636 4060 */
0a7de745 4061 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 1);
91447636 4062 }
39236c6e 4063#endif /* CONFIG_APPLEDOUBLE */
91447636 4064 }
b0d623f7 4065
b0d623f7
A
4066 post_event_if_success(vp, _err, NOTE_DELETE | NOTE_LINK);
4067 post_event_if_success(dvp, _err, NOTE_WRITE);
0a7de745
A
4068
4069 return _err;
91447636
A
4070}
4071
6d2010ae
A
4072int
4073VNOP_COMPOUND_REMOVE(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, struct vnode_attr *vap, vfs_context_t ctx)
4074{
4075 int _err;
4076 struct vnop_compound_remove_args a;
4077 int no_vp = (*vpp == NULLVP);
4078
4079 a.a_desc = &vnop_compound_remove_desc;
4080 a.a_dvp = dvp;
4081 a.a_vpp = vpp;
4082 a.a_cnp = &ndp->ni_cnd;
4083 a.a_flags = flags;
4084 a.a_vap = vap;
4085 a.a_context = ctx;
4086 a.a_remove_authorizer = vn_authorize_unlink;
4087
4088 _err = (*dvp->v_op[vnop_compound_remove_desc.vdesc_offset])(&a);
39236c6e
A
4089 if (_err == 0 && *vpp) {
4090 DTRACE_FSINFO(compound_remove, vnode_t, *vpp);
4091 } else {
4092 DTRACE_FSINFO(compound_remove, vnode_t, dvp);
4093 }
6d2010ae 4094 if (_err == 0) {
0a7de745 4095 vnode_setneedinactive(*vpp);
39236c6e 4096#if CONFIG_APPLEDOUBLE
0a7de745
A
4097 if (!(NATIVE_XATTR(dvp))) {
4098 /*
6d2010ae
A
4099 * Remove any associated extended attribute file (._ AppleDouble file).
4100 */
0a7de745 4101 xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 1);
6d2010ae 4102 }
39236c6e 4103#endif /* CONFIG_APPLEDOUBLE */
6d2010ae
A
4104 }
4105
4106 post_event_if_success(*vpp, _err, NOTE_DELETE | NOTE_LINK);
4107 post_event_if_success(dvp, _err, NOTE_WRITE);
4108
4109 if (no_vp) {
4110 lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, 0);
4111 if (*vpp && _err && _err != EKEEPLOOKING) {
4112 vnode_put(*vpp);
4113 *vpp = NULLVP;
4114 }
4115 }
4116
4117 //printf("VNOP_COMPOUND_REMOVE() returning %d\n", _err);
4118
0a7de745 4119 return _err;
6d2010ae 4120}
91447636
A
4121
4122#if 0
4123/*
0a7de745
A
4124*#
4125*#% link vp U U U
4126*#% link tdvp L U U
4127*#
4128*/
91447636
A
4129struct vnop_link_args {
4130 struct vnodeop_desc *a_desc;
4131 vnode_t a_vp;
4132 vnode_t a_tdvp;
4133 struct componentname *a_cnp;
4134 vfs_context_t a_context;
4135};
4136#endif /* 0*/
0a7de745 4137errno_t
2d21ac55 4138VNOP_LINK(vnode_t vp, vnode_t tdvp, struct componentname * cnp, vfs_context_t ctx)
91447636
A
4139{
4140 int _err;
4141 struct vnop_link_args a;
91447636 4142
39236c6e 4143#if CONFIG_APPLEDOUBLE
91447636
A
4144 /*
4145 * For file systems with non-native extended attributes,
4146 * disallow linking to an existing "._" Apple Double file.
4147 */
0a7de745 4148 if (!NATIVE_XATTR(tdvp) && (vp->v_type == VREG)) {
2d21ac55 4149 const char *vname;
91447636
A
4150
4151 vname = vnode_getname(vp);
4152 if (vname != NULL) {
4153 _err = 0;
4154 if (vname[0] == '.' && vname[1] == '_' && vname[2] != '\0') {
4155 _err = EPERM;
4156 }
4157 vnode_putname(vname);
0a7de745
A
4158 if (_err) {
4159 return _err;
4160 }
91447636
A
4161 }
4162 }
39236c6e
A
4163#endif /* CONFIG_APPLEDOUBLE */
4164
91447636
A
4165 a.a_desc = &vnop_link_desc;
4166 a.a_vp = vp;
4167 a.a_tdvp = tdvp;
4168 a.a_cnp = cnp;
2d21ac55 4169 a.a_context = ctx;
91447636 4170
91447636 4171 _err = (*tdvp->v_op[vnop_link_desc.vdesc_offset])(&a);
39236c6e 4172 DTRACE_FSINFO(link, vnode_t, vp);
b0d623f7
A
4173
4174 post_event_if_success(vp, _err, NOTE_LINK);
4175 post_event_if_success(tdvp, _err, NOTE_WRITE);
4176
0a7de745 4177 return _err;
91447636
A
4178}
4179
91447636 4180errno_t
6d2010ae 4181vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, struct vnode_attr *fvap,
0a7de745
A
4182 struct vnode *tdvp, struct vnode **tvpp, struct componentname *tcnp, struct vnode_attr *tvap,
4183 vfs_rename_flags_t flags, vfs_context_t ctx)
91447636 4184{
6d2010ae 4185 int _err;
316670eb
A
4186 struct nameidata *fromnd = NULL;
4187 struct nameidata *tond = NULL;
39236c6e
A
4188#if CONFIG_APPLEDOUBLE
4189 vnode_t src_attr_vp = NULLVP;
4190 vnode_t dst_attr_vp = NULLVP;
6d2010ae
A
4191 char smallname1[48];
4192 char smallname2[48];
4193 char *xfromname = NULL;
4194 char *xtoname = NULL;
39236c6e 4195#endif /* CONFIG_APPLEDOUBLE */
6d2010ae 4196 int batched;
0a7de745 4197 uint32_t tdfflags; // Target directory file flags
91447636 4198
6d2010ae 4199 batched = vnode_compound_rename_available(fdvp);
91447636 4200
6d2010ae 4201 if (!batched) {
0a7de745 4202 if (*fvpp == NULLVP) {
6d2010ae 4203 panic("Not batched, and no fvp?");
0a7de745 4204 }
91447636 4205 }
6d2010ae 4206
39236c6e 4207#if CONFIG_APPLEDOUBLE
0a7de745 4208 /*
b0d623f7
A
4209 * We need to preflight any potential AppleDouble file for the source file
4210 * before doing the rename operation, since we could potentially be doing
4211 * this operation on a network filesystem, and would end up duplicating
4212 * the work. Also, save the source and destination names. Skip it if the
4213 * source has a "._" prefix.
91447636 4214 */
0a7de745 4215
f427ee49
A
4216 size_t xfromname_len = 0;
4217 size_t xtoname_len = 0;
91447636
A
4218 if (!NATIVE_XATTR(fdvp) &&
4219 !(fcnp->cn_nameptr[0] == '.' && fcnp->cn_nameptr[1] == '_')) {
b0d623f7 4220 int error;
91447636
A
4221
4222 /* Get source attribute file name. */
f427ee49
A
4223 xfromname_len = fcnp->cn_namelen + 3;
4224 if (xfromname_len > sizeof(smallname1)) {
4225 xfromname = kheap_alloc(KHEAP_TEMP, xfromname_len, Z_WAITOK);
91447636
A
4226 } else {
4227 xfromname = &smallname1[0];
4228 }
f427ee49
A
4229 strlcpy(xfromname, "._", xfromname_len);
4230 strlcat(xfromname, fcnp->cn_nameptr, xfromname_len);
91447636
A
4231
4232 /* Get destination attribute file name. */
f427ee49
A
4233 xtoname_len = tcnp->cn_namelen + 3;
4234 if (xtoname_len > sizeof(smallname2)) {
4235 xtoname = kheap_alloc(KHEAP_TEMP, xtoname_len, Z_WAITOK);
91447636
A
4236 } else {
4237 xtoname = &smallname2[0];
4238 }
f427ee49
A
4239 strlcpy(xtoname, "._", xtoname_len);
4240 strlcat(xtoname, tcnp->cn_nameptr, xtoname_len);
0a7de745
A
4241
4242 /*
b0d623f7
A
4243 * Look up source attribute file, keep reference on it if exists.
4244 * Note that we do the namei with the nameiop of RENAME, which is different than
4245 * in the rename syscall. It's OK if the source file does not exist, since this
4246 * is only for AppleDouble files.
4247 */
f427ee49 4248 fromnd = kheap_alloc(KHEAP_TEMP, sizeof(struct nameidata), Z_WAITOK);
d9a64523 4249 NDINIT(fromnd, RENAME, OP_RENAME, NOFOLLOW | USEDVP | CN_NBMOUNTLOOK,
0a7de745 4250 UIO_SYSSPACE, CAST_USER_ADDR_T(xfromname), ctx);
d9a64523
A
4251 fromnd->ni_dvp = fdvp;
4252 error = namei(fromnd);
b0d623f7 4253
d9a64523
A
4254 /*
4255 * If there was an error looking up source attribute file,
4256 * we'll behave as if it didn't exist.
4257 */
4258
4259 if (error == 0) {
4260 if (fromnd->ni_vp) {
4261 /* src_attr_vp indicates need to call vnode_put / nameidone later */
4262 src_attr_vp = fromnd->ni_vp;
4263
4264 if (fromnd->ni_vp->v_type != VREG) {
4265 src_attr_vp = NULLVP;
4266 vnode_put(fromnd->ni_vp);
b0d623f7
A
4267 }
4268 }
d9a64523
A
4269 /*
4270 * Either we got an invalid vnode type (not a regular file) or the namei lookup
4271 * suppressed ENOENT as a valid error since we're renaming. Either way, we don't
4272 * have a vnode here, so we drop our namei buffer for the source attribute file
4273 */
4274 if (src_attr_vp == NULLVP) {
4275 nameidone(fromnd);
4276 }
b0d623f7 4277 }
91447636 4278 }
39236c6e 4279#endif /* CONFIG_APPLEDOUBLE */
91447636 4280
6d2010ae
A
4281 if (batched) {
4282 _err = VNOP_COMPOUND_RENAME(fdvp, fvpp, fcnp, fvap, tdvp, tvpp, tcnp, tvap, flags, ctx);
4283 if (_err != 0) {
4284 printf("VNOP_COMPOUND_RENAME() returned %d\n", _err);
4285 }
6d2010ae 4286 } else {
39037602
A
4287 if (flags) {
4288 _err = VNOP_RENAMEX(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, flags, ctx);
4289 if (_err == ENOTSUP && flags == VFS_RENAME_SECLUDE) {
4290 // Legacy...
4291 if ((*fvpp)->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_SECLUDE_RENAME) {
4292 fcnp->cn_flags |= CN_SECLUDE_RENAME;
4293 _err = VNOP_RENAME(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, ctx);
4294 }
4295 }
0a7de745 4296 } else {
39037602 4297 _err = VNOP_RENAME(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, ctx);
0a7de745 4298 }
91447636 4299 }
91447636 4300
fe8ab488
A
4301 /*
4302 * If moved to a new directory that is restricted,
4303 * set the restricted flag on the item moved.
4304 */
4305 if (_err == 0) {
4306 _err = vnode_flags(tdvp, &tdfflags, ctx);
5ba3f43e
A
4307 if (_err == 0) {
4308 uint32_t inherit_flags = tdfflags & (UF_DATAVAULT | SF_RESTRICTED);
4309 if (inherit_flags) {
4310 uint32_t fflags;
4311 _err = vnode_flags(*fvpp, &fflags, ctx);
4312 if (_err == 0 && fflags != (fflags | inherit_flags)) {
4313 struct vnode_attr va;
4314 VATTR_INIT(&va);
4315 VATTR_SET(&va, va_flags, fflags | inherit_flags);
4316 _err = vnode_setattr(*fvpp, &va, ctx);
4317 }
fe8ab488
A
4318 }
4319 }
4320 }
4321
3e170ce0
A
4322#if CONFIG_MACF
4323 if (_err == 0) {
4324 mac_vnode_notify_rename(ctx, *fvpp, tdvp, tcnp);
cb323159
A
4325 if (flags & VFS_RENAME_SWAP) {
4326 mac_vnode_notify_rename(ctx, *tvpp, fdvp, fcnp);
4327 }
3e170ce0
A
4328 }
4329#endif
4330
39236c6e 4331#if CONFIG_APPLEDOUBLE
0a7de745 4332 /*
2d21ac55 4333 * Rename any associated extended attribute file (._ AppleDouble file).
91447636
A
4334 */
4335 if (_err == 0 && !NATIVE_XATTR(fdvp) && xfromname != NULL) {
b0d623f7 4336 int error = 0;
0a7de745 4337
91447636 4338 /*
b0d623f7
A
4339 * Get destination attribute file vnode.
4340 * Note that tdvp already has an iocount reference. Make sure to check that we
4341 * get a valid vnode from namei.
91447636 4342 */
f427ee49 4343 tond = kheap_alloc(KHEAP_TEMP, sizeof(struct nameidata), Z_WAITOK);
316670eb 4344 NDINIT(tond, RENAME, OP_RENAME,
0a7de745
A
4345 NOCACHE | NOFOLLOW | USEDVP | CN_NBMOUNTLOOK, UIO_SYSSPACE,
4346 CAST_USER_ADDR_T(xtoname), ctx);
316670eb
A
4347 tond->ni_dvp = tdvp;
4348 error = namei(tond);
b0d623f7 4349
0a7de745 4350 if (error) {
39236c6e 4351 goto ad_error;
0a7de745
A
4352 }
4353
316670eb
A
4354 if (tond->ni_vp) {
4355 dst_attr_vp = tond->ni_vp;
91447636 4356 }
0a7de745 4357
b0d623f7 4358 if (src_attr_vp) {
316670eb
A
4359 const char *old_name = src_attr_vp->v_name;
4360 vnode_t old_parent = src_attr_vp->v_parent;
0a7de745 4361
6d2010ae 4362 if (batched) {
316670eb 4363 error = VNOP_COMPOUND_RENAME(fdvp, &src_attr_vp, &fromnd->ni_cnd, NULL,
0a7de745
A
4364 tdvp, &dst_attr_vp, &tond->ni_cnd, NULL,
4365 0, ctx);
6d2010ae 4366 } else {
0a7de745
A
4367 error = VNOP_RENAME(fdvp, src_attr_vp, &fromnd->ni_cnd,
4368 tdvp, dst_attr_vp, &tond->ni_cnd, ctx);
b0d623f7 4369 }
b0d623f7 4370
316670eb 4371 if (error == 0 && old_name == src_attr_vp->v_name &&
0a7de745 4372 old_parent == src_attr_vp->v_parent) {
316670eb 4373 int update_flags = VNODE_UPDATE_NAME;
0a7de745
A
4374
4375 if (fdvp != tdvp) {
316670eb 4376 update_flags |= VNODE_UPDATE_PARENT;
0a7de745
A
4377 }
4378
39236c6e
A
4379 if ((src_attr_vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_NOUPDATEID_RENAME) == 0) {
4380 vnode_update_identity(src_attr_vp, tdvp,
0a7de745
A
4381 tond->ni_cnd.cn_nameptr,
4382 tond->ni_cnd.cn_namelen,
4383 tond->ni_cnd.cn_hash,
4384 update_flags);
39236c6e 4385 }
316670eb 4386 }
0a7de745
A
4387
4388 /* kevent notifications for moving resource files
b0d623f7
A
4389 * _err is zero if we're here, so no need to notify directories, code
4390 * below will do that. only need to post the rename on the source and
4391 * possibly a delete on the dest
4392 */
4393 post_event_if_success(src_attr_vp, error, NOTE_RENAME);
4394 if (dst_attr_vp) {
0a7de745 4395 post_event_if_success(dst_attr_vp, error, NOTE_DELETE);
b0d623f7 4396 }
b0d623f7 4397 } else if (dst_attr_vp) {
91447636 4398 /*
b0d623f7
A
4399 * Just delete destination attribute file vnode if it exists, since
4400 * we didn't have a source attribute file.
91447636
A
4401 * Note that tdvp already has an iocount reference.
4402 */
b0d623f7
A
4403
4404 struct vnop_remove_args args;
0a7de745 4405
91447636
A
4406 args.a_desc = &vnop_remove_desc;
4407 args.a_dvp = tdvp;
b0d623f7 4408 args.a_vp = dst_attr_vp;
316670eb 4409 args.a_cnp = &tond->ni_cnd;
2d21ac55 4410 args.a_context = ctx;
91447636 4411
91447636 4412 if (error == 0) {
b0d623f7 4413 error = (*tdvp->v_op[vnop_remove_desc.vdesc_offset])(&args);
91447636 4414
0a7de745 4415 if (error == 0) {
b0d623f7 4416 vnode_setneedinactive(dst_attr_vp);
0a7de745 4417 }
91447636 4418 }
0a7de745 4419
b0d623f7
A
4420 /* kevent notification for deleting the destination's attribute file
4421 * if it existed. Only need to post the delete on the destination, since
0a7de745 4422 * the code below will handle the directories.
b0d623f7 4423 */
0a7de745 4424 post_event_if_success(dst_attr_vp, error, NOTE_DELETE);
91447636 4425 }
91447636 4426 }
39236c6e 4427ad_error:
b0d623f7
A
4428 if (src_attr_vp) {
4429 vnode_put(src_attr_vp);
316670eb 4430 nameidone(fromnd);
b0d623f7
A
4431 }
4432 if (dst_attr_vp) {
4433 vnode_put(dst_attr_vp);
316670eb
A
4434 nameidone(tond);
4435 }
91447636 4436 if (xfromname && xfromname != &smallname1[0]) {
f427ee49 4437 kheap_free(KHEAP_TEMP, xfromname, xfromname_len);
91447636
A
4438 }
4439 if (xtoname && xtoname != &smallname2[0]) {
f427ee49 4440 kheap_free(KHEAP_TEMP, xtoname, xtoname_len);
91447636 4441 }
39236c6e 4442#endif /* CONFIG_APPLEDOUBLE */
f427ee49
A
4443 kheap_free(KHEAP_TEMP, fromnd, sizeof(struct nameidata));
4444 kheap_free(KHEAP_TEMP, tond, sizeof(struct nameidata));
6d2010ae
A
4445 return _err;
4446}
4447
4448
4449#if 0
4450/*
0a7de745
A
4451*#
4452*#% rename fdvp U U U
4453*#% rename fvp U U U
4454*#% rename tdvp L U U
4455*#% rename tvp X U U
4456*#
4457*/
6d2010ae
A
4458struct vnop_rename_args {
4459 struct vnodeop_desc *a_desc;
4460 vnode_t a_fdvp;
4461 vnode_t a_fvp;
4462 struct componentname *a_fcnp;
4463 vnode_t a_tdvp;
4464 vnode_t a_tvp;
4465 struct componentname *a_tcnp;
4466 vfs_context_t a_context;
4467};
4468#endif /* 0*/
4469errno_t
4470VNOP_RENAME(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
0a7de745
A
4471 struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp,
4472 vfs_context_t ctx)
6d2010ae
A
4473{
4474 int _err = 0;
6d2010ae 4475 struct vnop_rename_args a;
6d2010ae
A
4476
4477 a.a_desc = &vnop_rename_desc;
4478 a.a_fdvp = fdvp;
4479 a.a_fvp = fvp;
4480 a.a_fcnp = fcnp;
4481 a.a_tdvp = tdvp;
4482 a.a_tvp = tvp;
4483 a.a_tcnp = tcnp;
4484 a.a_context = ctx;
4485
6d2010ae
A
4486 /* do the rename of the main file. */
4487 _err = (*fdvp->v_op[vnop_rename_desc.vdesc_offset])(&a);
39236c6e 4488 DTRACE_FSINFO(rename, vnode_t, fdvp);
6d2010ae 4489
0a7de745 4490 if (_err) {
39037602 4491 return _err;
0a7de745 4492 }
6d2010ae 4493
39037602
A
4494 return post_rename(fdvp, fvp, tdvp, tvp);
4495}
b0d623f7 4496
39037602
A
4497static errno_t
4498post_rename(vnode_t fdvp, vnode_t fvp, vnode_t tdvp, vnode_t tvp)
4499{
0a7de745 4500 if (tvp && tvp != fvp) {
39037602 4501 vnode_setneedinactive(tvp);
0a7de745 4502 }
b0d623f7 4503
39037602
A
4504 /* Wrote at least one directory. If transplanted a dir, also changed link counts */
4505 int events = NOTE_WRITE;
4506 if (vnode_isdir(fvp)) {
4507 /* Link count on dir changed only if we are moving a dir and...
0a7de745
A
4508 * --Moved to new dir, not overwriting there
4509 * --Kept in same dir and DID overwrite
39037602
A
4510 */
4511 if (((fdvp != tdvp) && (!tvp)) || ((fdvp == tdvp) && (tvp))) {
4512 events |= NOTE_LINK;
b0d623f7 4513 }
39037602 4514 }
b0d623f7 4515
39037602
A
4516 lock_vnode_and_post(fdvp, events);
4517 if (fdvp != tdvp) {
0a7de745 4518 lock_vnode_and_post(tdvp, events);
b0d623f7
A
4519 }
4520
39037602 4521 /* If you're replacing the target, post a deletion for it */
0a7de745 4522 if (tvp) {
39037602
A
4523 lock_vnode_and_post(tvp, NOTE_DELETE);
4524 }
4525
4526 lock_vnode_and_post(fvp, NOTE_RENAME);
4527
4528 return 0;
91447636
A
4529}
4530
39037602
A
4531#if 0
4532/*
0a7de745
A
4533*#
4534*#% renamex fdvp U U U
4535*#% renamex fvp U U U
4536*#% renamex tdvp L U U
4537*#% renamex tvp X U U
4538*#
4539*/
39037602
A
4540struct vnop_renamex_args {
4541 struct vnodeop_desc *a_desc;
4542 vnode_t a_fdvp;
4543 vnode_t a_fvp;
4544 struct componentname *a_fcnp;
4545 vnode_t a_tdvp;
4546 vnode_t a_tvp;
4547 struct componentname *a_tcnp;
4548 vfs_rename_flags_t a_flags;
4549 vfs_context_t a_context;
4550};
4551#endif /* 0*/
4552errno_t
4553VNOP_RENAMEX(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
0a7de745
A
4554 struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp,
4555 vfs_rename_flags_t flags, vfs_context_t ctx)
39037602
A
4556{
4557 int _err = 0;
4558 struct vnop_renamex_args a;
4559
4560 a.a_desc = &vnop_renamex_desc;
4561 a.a_fdvp = fdvp;
4562 a.a_fvp = fvp;
4563 a.a_fcnp = fcnp;
4564 a.a_tdvp = tdvp;
4565 a.a_tvp = tvp;
4566 a.a_tcnp = tcnp;
4567 a.a_flags = flags;
4568 a.a_context = ctx;
4569
4570 /* do the rename of the main file. */
4571 _err = (*fdvp->v_op[vnop_renamex_desc.vdesc_offset])(&a);
4572 DTRACE_FSINFO(renamex, vnode_t, fdvp);
4573
0a7de745 4574 if (_err) {
39037602 4575 return _err;
0a7de745 4576 }
39037602
A
4577
4578 return post_rename(fdvp, fvp, tdvp, tvp);
4579}
4580
4581
6d2010ae 4582int
0a7de745
A
4583VNOP_COMPOUND_RENAME(
4584 struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, struct vnode_attr *fvap,
4585 struct vnode *tdvp, struct vnode **tvpp, struct componentname *tcnp, struct vnode_attr *tvap,
4586 uint32_t flags, vfs_context_t ctx)
6d2010ae
A
4587{
4588 int _err = 0;
4589 int events;
4590 struct vnop_compound_rename_args a;
4591 int no_fvp, no_tvp;
4592
4593 no_fvp = (*fvpp) == NULLVP;
4594 no_tvp = (*tvpp) == NULLVP;
4595
4596 a.a_desc = &vnop_compound_rename_desc;
0a7de745 4597
6d2010ae
A
4598 a.a_fdvp = fdvp;
4599 a.a_fvpp = fvpp;
4600 a.a_fcnp = fcnp;
4601 a.a_fvap = fvap;
4602
4603 a.a_tdvp = tdvp;
4604 a.a_tvpp = tvpp;
4605 a.a_tcnp = tcnp;
4606 a.a_tvap = tvap;
0a7de745 4607
6d2010ae
A
4608 a.a_flags = flags;
4609 a.a_context = ctx;
4610 a.a_rename_authorizer = vn_authorize_rename;
4611 a.a_reserved = NULL;
4612
4613 /* do the rename of the main file. */
4614 _err = (*fdvp->v_op[vnop_compound_rename_desc.vdesc_offset])(&a);
39236c6e 4615 DTRACE_FSINFO(compound_rename, vnode_t, fdvp);
6d2010ae
A
4616
4617 if (_err == 0) {
0a7de745
A
4618 if (*tvpp && *tvpp != *fvpp) {
4619 vnode_setneedinactive(*tvpp);
4620 }
6d2010ae
A
4621 }
4622
4623 /* Wrote at least one directory. If transplanted a dir, also changed link counts */
39236c6e 4624 if (_err == 0 && *fvpp != *tvpp) {
6d2010ae
A
4625 if (!*fvpp) {
4626 panic("No fvpp after compound rename?");
4627 }
4628
4629 events = NOTE_WRITE;
4630 if (vnode_isdir(*fvpp)) {
4631 /* Link count on dir changed only if we are moving a dir and...
0a7de745
A
4632 * --Moved to new dir, not overwriting there
4633 * --Kept in same dir and DID overwrite
6d2010ae
A
4634 */
4635 if (((fdvp != tdvp) && (!*tvpp)) || ((fdvp == tdvp) && (*tvpp))) {
4636 events |= NOTE_LINK;
4637 }
4638 }
4639
4640 lock_vnode_and_post(fdvp, events);
4641 if (fdvp != tdvp) {
0a7de745 4642 lock_vnode_and_post(tdvp, events);
6d2010ae
A
4643 }
4644
4645 /* If you're replacing the target, post a deletion for it */
0a7de745 4646 if (*tvpp) {
6d2010ae
A
4647 lock_vnode_and_post(*tvpp, NOTE_DELETE);
4648 }
4649
4650 lock_vnode_and_post(*fvpp, NOTE_RENAME);
4651 }
4652
4653 if (no_fvp) {
0a7de745 4654 lookup_compound_vnop_post_hook(_err, fdvp, *fvpp, fcnp->cn_ndp, 0);
6d2010ae
A
4655 }
4656 if (no_tvp && *tvpp != NULLVP) {
4657 lookup_compound_vnop_post_hook(_err, tdvp, *tvpp, tcnp->cn_ndp, 0);
4658 }
4659
4660 if (_err && _err != EKEEPLOOKING) {
4661 if (*fvpp) {
4662 vnode_put(*fvpp);
4663 *fvpp = NULLVP;
4664 }
4665 if (*tvpp) {
4666 vnode_put(*tvpp);
4667 *tvpp = NULLVP;
4668 }
4669 }
4670
0a7de745 4671 return _err;
6d2010ae
A
4672}
4673
4674int
4675vn_mkdir(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp,
0a7de745 4676 struct vnode_attr *vap, vfs_context_t ctx)
6d2010ae
A
4677{
4678 if (ndp->ni_cnd.cn_nameiop != CREATE) {
4679 panic("Non-CREATE nameiop in vn_mkdir()?");
4680 }
4681
4682 if (vnode_compound_mkdir_available(dvp)) {
4683 return VNOP_COMPOUND_MKDIR(dvp, vpp, ndp, vap, ctx);
4684 } else {
4685 return VNOP_MKDIR(dvp, vpp, &ndp->ni_cnd, vap, ctx);
4686 }
4687}
4688
39236c6e 4689#if 0
91447636 4690/*
0a7de745
A
4691*#
4692*#% mkdir dvp L U U
4693*#% mkdir vpp - L -
4694*#
4695*/
91447636 4696struct vnop_mkdir_args {
0a7de745
A
4697 struct vnodeop_desc *a_desc;
4698 vnode_t a_dvp;
4699 vnode_t *a_vpp;
4700 struct componentname *a_cnp;
4701 struct vnode_attr *a_vap;
4702 vfs_context_t a_context;
91447636
A
4703};
4704#endif /* 0*/
4705errno_t
4706VNOP_MKDIR(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
0a7de745 4707 struct vnode_attr *vap, vfs_context_t ctx)
91447636 4708{
0a7de745
A
4709 int _err;
4710 struct vnop_mkdir_args a;
91447636 4711
0a7de745
A
4712 a.a_desc = &vnop_mkdir_desc;
4713 a.a_dvp = dvp;
4714 a.a_vpp = vpp;
4715 a.a_cnp = cnp;
4716 a.a_vap = vap;
4717 a.a_context = ctx;
91447636 4718
0a7de745 4719 _err = (*dvp->v_op[vnop_mkdir_desc.vdesc_offset])(&a);
39236c6e
A
4720 if (_err == 0 && *vpp) {
4721 DTRACE_FSINFO(mkdir, vnode_t, *vpp);
4722 }
4723#if CONFIG_APPLEDOUBLE
91447636 4724 if (_err == 0 && !NATIVE_XATTR(dvp)) {
0a7de745 4725 /*
91447636
A
4726 * Remove stale Apple Double file (if any).
4727 */
b0d623f7 4728 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
91447636 4729 }
39236c6e 4730#endif /* CONFIG_APPLEDOUBLE */
b0d623f7 4731
0a7de745 4732 post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
b0d623f7 4733
0a7de745 4734 return _err;
91447636
A
4735}
4736
6d2010ae
A
4737int
4738VNOP_COMPOUND_MKDIR(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp,
0a7de745
A
4739 struct vnode_attr *vap, vfs_context_t ctx)
4740{
4741 int _err;
4742 struct vnop_compound_mkdir_args a;
4743
4744 a.a_desc = &vnop_compound_mkdir_desc;
4745 a.a_dvp = dvp;
4746 a.a_vpp = vpp;
4747 a.a_cnp = &ndp->ni_cnd;
4748 a.a_vap = vap;
4749 a.a_flags = 0;
4750 a.a_context = ctx;
6d2010ae 4751#if 0
0a7de745 4752 a.a_mkdir_authorizer = vn_authorize_mkdir;
6d2010ae 4753#endif /* 0 */
0a7de745 4754 a.a_reserved = NULL;
6d2010ae 4755
0a7de745 4756 _err = (*dvp->v_op[vnop_compound_mkdir_desc.vdesc_offset])(&a);
39236c6e
A
4757 if (_err == 0 && *vpp) {
4758 DTRACE_FSINFO(compound_mkdir, vnode_t, *vpp);
4759 }
4760#if CONFIG_APPLEDOUBLE
6d2010ae 4761 if (_err == 0 && !NATIVE_XATTR(dvp)) {
0a7de745 4762 /*
6d2010ae
A
4763 * Remove stale Apple Double file (if any).
4764 */
4765 xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 0);
4766 }
39236c6e 4767#endif /* CONFIG_APPLEDOUBLE */
6d2010ae
A
4768
4769 post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4770
4771 lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, (_err == 0));
4772 if (*vpp && _err && _err != EKEEPLOOKING) {
4773 vnode_put(*vpp);
4774 *vpp = NULLVP;
4775 }
4776
0a7de745 4777 return _err;
6d2010ae
A
4778}
4779
4780int
4781vn_rmdir(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, struct vnode_attr *vap, vfs_context_t ctx)
4782{
4783 if (vnode_compound_rmdir_available(dvp)) {
4784 return VNOP_COMPOUND_RMDIR(dvp, vpp, ndp, vap, ctx);
4785 } else {
4786 if (*vpp == NULLVP) {
4787 panic("NULL vp, but not a compound VNOP?");
4788 }
4789 if (vap != NULL) {
4790 panic("Non-NULL vap, but not a compound VNOP?");
4791 }
4792 return VNOP_RMDIR(dvp, *vpp, &ndp->ni_cnd, ctx);
4793 }
4794}
91447636
A
4795
4796#if 0
4797/*
0a7de745
A
4798*#
4799*#% rmdir dvp L U U
4800*#% rmdir vp L U U
4801*#
4802*/
91447636
A
4803struct vnop_rmdir_args {
4804 struct vnodeop_desc *a_desc;
4805 vnode_t a_dvp;
4806 vnode_t a_vp;
4807 struct componentname *a_cnp;
4808 vfs_context_t a_context;
4809};
4810
4811#endif /* 0*/
4812errno_t
2d21ac55 4813VNOP_RMDIR(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, vfs_context_t ctx)
91447636
A
4814{
4815 int _err;
4816 struct vnop_rmdir_args a;
91447636
A
4817
4818 a.a_desc = &vnop_rmdir_desc;
4819 a.a_dvp = dvp;
4820 a.a_vp = vp;
4821 a.a_cnp = cnp;
2d21ac55 4822 a.a_context = ctx;
91447636 4823
91447636 4824 _err = (*vp->v_op[vnop_rmdir_desc.vdesc_offset])(&a);
39236c6e 4825 DTRACE_FSINFO(rmdir, vnode_t, vp);
91447636
A
4826
4827 if (_err == 0) {
0a7de745 4828 vnode_setneedinactive(vp);
39236c6e 4829#if CONFIG_APPLEDOUBLE
0a7de745
A
4830 if (!(NATIVE_XATTR(dvp))) {
4831 /*
2d21ac55 4832 * Remove any associated extended attribute file (._ AppleDouble file).
91447636 4833 */
0a7de745 4834 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 1);
91447636 4835 }
39236c6e 4836#endif
91447636 4837 }
b0d623f7 4838
b0d623f7
A
4839 /* If you delete a dir, it loses its "." reference --> NOTE_LINK */
4840 post_event_if_success(vp, _err, NOTE_DELETE | NOTE_LINK);
4841 post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4842
0a7de745 4843 return _err;
91447636
A
4844}
4845
6d2010ae
A
4846int
4847VNOP_COMPOUND_RMDIR(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp,
0a7de745 4848 struct vnode_attr *vap, vfs_context_t ctx)
6d2010ae 4849{
0a7de745
A
4850 int _err;
4851 struct vnop_compound_rmdir_args a;
4852 int no_vp;
6d2010ae 4853
0a7de745
A
4854 a.a_desc = &vnop_mkdir_desc;
4855 a.a_dvp = dvp;
4856 a.a_vpp = vpp;
4857 a.a_cnp = &ndp->ni_cnd;
4858 a.a_vap = vap;
4859 a.a_flags = 0;
4860 a.a_context = ctx;
4861 a.a_rmdir_authorizer = vn_authorize_rmdir;
4862 a.a_reserved = NULL;
6d2010ae 4863
0a7de745 4864 no_vp = (*vpp == NULLVP);
6d2010ae 4865
0a7de745 4866 _err = (*dvp->v_op[vnop_compound_rmdir_desc.vdesc_offset])(&a);
39236c6e
A
4867 if (_err == 0 && *vpp) {
4868 DTRACE_FSINFO(compound_rmdir, vnode_t, *vpp);
4869 }
4870#if CONFIG_APPLEDOUBLE
6d2010ae 4871 if (_err == 0 && !NATIVE_XATTR(dvp)) {
0a7de745 4872 /*
6d2010ae
A
4873 * Remove stale Apple Double file (if any).
4874 */
4875 xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 0);
4876 }
39236c6e 4877#endif
6d2010ae
A
4878
4879 if (*vpp) {
4880 post_event_if_success(*vpp, _err, NOTE_DELETE | NOTE_LINK);
4881 }
4882 post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4883
0a7de745
A
4884 if (no_vp) {
4885 lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, 0);
6d2010ae
A
4886
4887#if 0 /* Removing orphaned ._ files requires a vp.... */
0a7de745
A
4888 if (*vpp && _err && _err != EKEEPLOOKING) {
4889 vnode_put(*vpp);
4890 *vpp = NULLVP;
4891 }
6d2010ae 4892#endif /* 0 */
0a7de745 4893 }
6d2010ae 4894
0a7de745 4895 return _err;
6d2010ae
A
4896}
4897
39236c6e 4898#if CONFIG_APPLEDOUBLE
91447636
A
4899/*
4900 * Remove a ._ AppleDouble file
4901 */
4902#define AD_STALE_SECS (180)
4903static void
0a7de745 4904xattrfile_remove(vnode_t dvp, const char * basename, vfs_context_t ctx, int force)
b0d623f7 4905{
91447636
A
4906 vnode_t xvp;
4907 struct nameidata nd;
4908 char smallname[64];
4909 char *filename = NULL;
f427ee49
A
4910 size_t alloc_len;
4911 size_t copy_len;
91447636
A
4912
4913 if ((basename == NULL) || (basename[0] == '\0') ||
4914 (basename[0] == '.' && basename[1] == '_')) {
4915 return;
4916 }
4917 filename = &smallname[0];
f427ee49
A
4918 alloc_len = snprintf(filename, sizeof(smallname), "._%s", basename);
4919 if (alloc_len >= sizeof(smallname)) {
4920 alloc_len++; /* snprintf result doesn't include '\0' */
4921 filename = kheap_alloc(KHEAP_TEMP, alloc_len, Z_WAITOK);
4922 copy_len = snprintf(filename, alloc_len, "._%s", basename);
91447636 4923 }
6d2010ae 4924 NDINIT(&nd, DELETE, OP_UNLINK, WANTPARENT | LOCKLEAF | NOFOLLOW | USEDVP, UIO_SYSSPACE,
0a7de745 4925 CAST_USER_ADDR_T(filename), ctx);
91447636 4926 nd.ni_dvp = dvp;
0a7de745 4927 if (namei(&nd) != 0) {
91447636 4928 goto out2;
0a7de745 4929 }
91447636
A
4930
4931 xvp = nd.ni_vp;
4932 nameidone(&nd);
0a7de745 4933 if (xvp->v_type != VREG) {
91447636 4934 goto out1;
0a7de745 4935 }
91447636
A
4936
4937 /*
4938 * When creating a new object and a "._" file already
4939 * exists, check to see if its a stale "._" file.
4940 *
4941 */
4942 if (!force) {
4943 struct vnode_attr va;
4944
4945 VATTR_INIT(&va);
4946 VATTR_WANTED(&va, va_data_size);
4947 VATTR_WANTED(&va, va_modify_time);
0a7de745
A
4948 if (VNOP_GETATTR(xvp, &va, ctx) == 0 &&
4949 VATTR_IS_SUPPORTED(&va, va_data_size) &&
4950 VATTR_IS_SUPPORTED(&va, va_modify_time) &&
91447636
A
4951 va.va_data_size != 0) {
4952 struct timeval tv;
4953
4954 microtime(&tv);
4955 if ((tv.tv_sec > va.va_modify_time.tv_sec) &&
4956 (tv.tv_sec - va.va_modify_time.tv_sec) > AD_STALE_SECS) {
4957 force = 1; /* must be stale */
4958 }
4959 }
4960 }
4961 if (force) {
91447636 4962 int error;
0a7de745 4963
6d2010ae 4964 error = VNOP_REMOVE(dvp, xvp, &nd.ni_cnd, 0, ctx);
0a7de745 4965 if (error == 0) {
91447636 4966 vnode_setneedinactive(xvp);
0a7de745 4967 }
b0d623f7
A
4968
4969 post_event_if_success(xvp, error, NOTE_DELETE);
4970 post_event_if_success(dvp, error, NOTE_WRITE);
91447636 4971 }
b0d623f7 4972
0a7de745 4973out1:
2d21ac55 4974 vnode_put(dvp);
91447636
A
4975 vnode_put(xvp);
4976out2:
4977 if (filename && filename != &smallname[0]) {
f427ee49 4978 kheap_free(KHEAP_TEMP, filename, alloc_len);
91447636
A
4979 }
4980}
4981
4982/*
4983 * Shadow uid/gid/mod to a ._ AppleDouble file
4984 */
4985static void
4986xattrfile_setattr(vnode_t dvp, const char * basename, struct vnode_attr * vap,
0a7de745 4987 vfs_context_t ctx)
b0d623f7 4988{
91447636
A
4989 vnode_t xvp;
4990 struct nameidata nd;
4991 char smallname[64];
4992 char *filename = NULL;
4993 size_t len;
4994
4995 if ((dvp == NULLVP) ||
4996 (basename == NULL) || (basename[0] == '\0') ||
4997 (basename[0] == '.' && basename[1] == '_')) {
4998 return;
4999 }
5000 filename = &smallname[0];
5001 len = snprintf(filename, sizeof(smallname), "._%s", basename);
5002 if (len >= sizeof(smallname)) {
5003 len++; /* snprintf result doesn't include '\0' */
f427ee49 5004 filename = kheap_alloc(KHEAP_TEMP, len, Z_WAITOK);
91447636
A
5005 len = snprintf(filename, len, "._%s", basename);
5006 }
6d2010ae 5007 NDINIT(&nd, LOOKUP, OP_SETATTR, NOFOLLOW | USEDVP, UIO_SYSSPACE,
0a7de745 5008 CAST_USER_ADDR_T(filename), ctx);
91447636 5009 nd.ni_dvp = dvp;
0a7de745 5010 if (namei(&nd) != 0) {
91447636 5011 goto out2;
0a7de745 5012 }
91447636
A
5013
5014 xvp = nd.ni_vp;
5015 nameidone(&nd);
5016
5017 if (xvp->v_type == VREG) {
5018 struct vnop_setattr_args a;
5019
5020 a.a_desc = &vnop_setattr_desc;
5021 a.a_vp = xvp;
5022 a.a_vap = vap;
2d21ac55 5023 a.a_context = ctx;
91447636 5024
91447636 5025 (void) (*xvp->v_op[vnop_setattr_desc.vdesc_offset])(&a);
91447636 5026 }
b0d623f7 5027
91447636
A
5028 vnode_put(xvp);
5029out2:
5030 if (filename && filename != &smallname[0]) {
f427ee49 5031 kheap_free(KHEAP_TEMP, filename, len);
91447636
A
5032 }
5033}
39236c6e 5034#endif /* CONFIG_APPLEDOUBLE */
91447636
A
5035
5036 #if 0
5037/*
0a7de745
A
5038*#
5039*#% symlink dvp L U U
5040*#% symlink vpp - U -
5041*#
5042*/
91447636 5043struct vnop_symlink_args {
0a7de745
A
5044 struct vnodeop_desc *a_desc;
5045 vnode_t a_dvp;
5046 vnode_t *a_vpp;
5047 struct componentname *a_cnp;
5048 struct vnode_attr *a_vap;
5049 char *a_target;
5050 vfs_context_t a_context;
91447636
A
5051};
5052
5053#endif /* 0*/
5054errno_t
5055VNOP_SYMLINK(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
0a7de745 5056 struct vnode_attr *vap, char *target, vfs_context_t ctx)
91447636 5057{
0a7de745
A
5058 int _err;
5059 struct vnop_symlink_args a;
91447636 5060
0a7de745
A
5061 a.a_desc = &vnop_symlink_desc;
5062 a.a_dvp = dvp;
5063 a.a_vpp = vpp;
5064 a.a_cnp = cnp;
5065 a.a_vap = vap;
5066 a.a_target = target;
5067 a.a_context = ctx;
91447636 5068
0a7de745 5069 _err = (*dvp->v_op[vnop_symlink_desc.vdesc_offset])(&a);
39236c6e
A
5070 DTRACE_FSINFO(symlink, vnode_t, dvp);
5071#if CONFIG_APPLEDOUBLE
91447636 5072 if (_err == 0 && !NATIVE_XATTR(dvp)) {
0a7de745 5073 /*
b0d623f7 5074 * Remove stale Apple Double file (if any). Posts its own knotes
91447636 5075 */
b0d623f7 5076 xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
91447636 5077 }
39236c6e 5078#endif /* CONFIG_APPLEDOUBLE */
b0d623f7 5079
b0d623f7
A
5080 post_event_if_success(dvp, _err, NOTE_WRITE);
5081
0a7de745 5082 return _err;
91447636
A
5083}
5084
5085#if 0
5086/*
0a7de745
A
5087*#
5088*#% readdir vp L L L
5089*#
5090*/
91447636
A
5091struct vnop_readdir_args {
5092 struct vnodeop_desc *a_desc;
5093 vnode_t a_vp;
5094 struct uio *a_uio;
5095 int a_flags;
5096 int *a_eofflag;
5097 int *a_numdirent;
5098 vfs_context_t a_context;
5099};
5100
5101#endif /* 0*/
0a7de745 5102errno_t
91447636 5103VNOP_READDIR(struct vnode *vp, struct uio *uio, int flags, int *eofflag,
0a7de745 5104 int *numdirent, vfs_context_t ctx)
91447636
A
5105{
5106 int _err;
5107 struct vnop_readdir_args a;
39236c6e
A
5108#if CONFIG_DTRACE
5109 user_ssize_t resid = uio_resid(uio);
5110#endif
91447636
A
5111
5112 a.a_desc = &vnop_readdir_desc;
5113 a.a_vp = vp;
5114 a.a_uio = uio;
5115 a.a_flags = flags;
5116 a.a_eofflag = eofflag;
5117 a.a_numdirent = numdirent;
2d21ac55 5118 a.a_context = ctx;
b0d623f7 5119
91447636 5120 _err = (*vp->v_op[vnop_readdir_desc.vdesc_offset])(&a);
39236c6e
A
5121 DTRACE_FSINFO_IO(readdir,
5122 vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
b0d623f7 5123
0a7de745 5124 return _err;
91447636
A
5125}
5126
5127#if 0
5128/*
0a7de745
A
5129*#
5130*#% readdirattr vp L L L
5131*#
5132*/
91447636
A
5133struct vnop_readdirattr_args {
5134 struct vnodeop_desc *a_desc;
5135 vnode_t a_vp;
5136 struct attrlist *a_alist;
5137 struct uio *a_uio;
b0d623f7
A
5138 uint32_t a_maxcount;
5139 uint32_t a_options;
5140 uint32_t *a_newstate;
91447636 5141 int *a_eofflag;
b0d623f7 5142 uint32_t *a_actualcount;
91447636
A
5143 vfs_context_t a_context;
5144};
5145
5146#endif /* 0*/
0a7de745 5147errno_t
b0d623f7 5148VNOP_READDIRATTR(struct vnode *vp, struct attrlist *alist, struct uio *uio, uint32_t maxcount,
0a7de745 5149 uint32_t options, uint32_t *newstate, int *eofflag, uint32_t *actualcount, vfs_context_t ctx)
91447636
A
5150{
5151 int _err;
5152 struct vnop_readdirattr_args a;
39236c6e
A
5153#if CONFIG_DTRACE
5154 user_ssize_t resid = uio_resid(uio);
5155#endif
91447636
A
5156
5157 a.a_desc = &vnop_readdirattr_desc;
5158 a.a_vp = vp;
5159 a.a_alist = alist;
5160 a.a_uio = uio;
5161 a.a_maxcount = maxcount;
5162 a.a_options = options;
5163 a.a_newstate = newstate;
5164 a.a_eofflag = eofflag;
5165 a.a_actualcount = actualcount;
2d21ac55 5166 a.a_context = ctx;
91447636 5167
91447636 5168 _err = (*vp->v_op[vnop_readdirattr_desc.vdesc_offset])(&a);
39236c6e
A
5169 DTRACE_FSINFO_IO(readdirattr,
5170 vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
b0d623f7 5171
0a7de745 5172 return _err;
91447636
A
5173}
5174
fe8ab488
A
5175#if 0
5176struct vnop_getttrlistbulk_args {
5177 struct vnodeop_desc *a_desc;
5178 vnode_t a_vp;
5179 struct attrlist *a_alist;
5180 struct vnode_attr *a_vap;
5181 struct uio *a_uio;
5182 void *a_private
5183 uint64_t a_options;
5184 int *a_eofflag;
5185 uint32_t *a_actualcount;
5186 vfs_context_t a_context;
5187};
5188#endif /* 0*/
5189errno_t
5190VNOP_GETATTRLISTBULK(struct vnode *vp, struct attrlist *alist,
5191 struct vnode_attr *vap, struct uio *uio, void *private, uint64_t options,
5192 int32_t *eofflag, int32_t *actualcount, vfs_context_t ctx)
5193{
5194 int _err;
5195 struct vnop_getattrlistbulk_args a;
5196#if CONFIG_DTRACE
5197 user_ssize_t resid = uio_resid(uio);
5198#endif
5199
5200 a.a_desc = &vnop_getattrlistbulk_desc;
5201 a.a_vp = vp;
5202 a.a_alist = alist;
5203 a.a_vap = vap;
5204 a.a_uio = uio;
5205 a.a_private = private;
5206 a.a_options = options;
5207 a.a_eofflag = eofflag;
5208 a.a_actualcount = actualcount;
5209 a.a_context = ctx;
5210
5211 _err = (*vp->v_op[vnop_getattrlistbulk_desc.vdesc_offset])(&a);
5212 DTRACE_FSINFO_IO(getattrlistbulk,
5213 vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
5214
0a7de745 5215 return _err;
fe8ab488
A
5216}
5217
91447636
A
5218#if 0
5219/*
0a7de745
A
5220*#
5221*#% readlink vp L L L
5222*#
5223*/
91447636
A
5224struct vnop_readlink_args {
5225 struct vnodeop_desc *a_desc;
5226 vnode_t a_vp;
5227 struct uio *a_uio;
5228 vfs_context_t a_context;
5229};
5230#endif /* 0 */
5231
2d21ac55
A
5232/*
5233 * Returns: 0 Success
5234 * lock_fsnode:ENOENT No such file or directory [only for VFS
5235 * that is not thread safe & vnode is
5236 * currently being/has been terminated]
5237 * <vfs_readlink>:EINVAL
5238 * <vfs_readlink>:???
5239 *
5240 * Note: The return codes from the underlying VFS's readlink routine
5241 * can't be fully enumerated here, since third party VFS authors
5242 * may not limit their error returns to the ones documented here,
5243 * even though this may result in some programs functioning
5244 * incorrectly.
5245 *
5246 * The return codes documented above are those which may currently
5247 * be returned by HFS from hfs_vnop_readlink, not including
5248 * additional error code which may be propagated from underlying
5249 * routines.
5250 */
0a7de745 5251errno_t
2d21ac55 5252VNOP_READLINK(struct vnode *vp, struct uio *uio, vfs_context_t ctx)
91447636
A
5253{
5254 int _err;
5255 struct vnop_readlink_args a;
39236c6e
A
5256#if CONFIG_DTRACE
5257 user_ssize_t resid = uio_resid(uio);
5258#endif
91447636
A
5259 a.a_desc = &vnop_readlink_desc;
5260 a.a_vp = vp;
5261 a.a_uio = uio;
2d21ac55 5262 a.a_context = ctx;
91447636 5263
91447636 5264 _err = (*vp->v_op[vnop_readlink_desc.vdesc_offset])(&a);
39236c6e
A
5265 DTRACE_FSINFO_IO(readlink,
5266 vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
b0d623f7 5267
0a7de745 5268 return _err;
91447636
A
5269}
5270
5271#if 0
5272/*
0a7de745
A
5273*#
5274*#% inactive vp L U U
5275*#
5276*/
91447636
A
5277struct vnop_inactive_args {
5278 struct vnodeop_desc *a_desc;
5279 vnode_t a_vp;
5280 vfs_context_t a_context;
5281};
5282#endif /* 0*/
0a7de745 5283errno_t
2d21ac55 5284VNOP_INACTIVE(struct vnode *vp, vfs_context_t ctx)
91447636
A
5285{
5286 int _err;
5287 struct vnop_inactive_args a;
91447636
A
5288
5289 a.a_desc = &vnop_inactive_desc;
5290 a.a_vp = vp;
2d21ac55 5291 a.a_context = ctx;
0a7de745 5292
91447636 5293 _err = (*vp->v_op[vnop_inactive_desc.vdesc_offset])(&a);
39236c6e 5294 DTRACE_FSINFO(inactive, vnode_t, vp);
cf7d32b8
A
5295
5296#if NAMEDSTREAMS
0a7de745
A
5297 /* For file systems that do not support namedstream natively, mark
5298 * the shadow stream file vnode to be recycled as soon as the last
5299 * reference goes away. To avoid re-entering reclaim code, do not
b0d623f7 5300 * call recycle on terminating namedstream vnodes.
cf7d32b8
A
5301 */
5302 if (vnode_isnamedstream(vp) &&
b0d623f7
A
5303 (vp->v_parent != NULLVP) &&
5304 vnode_isshadow(vp) &&
5305 ((vp->v_lflag & VL_TERMINATE) == 0)) {
cf7d32b8
A
5306 vnode_recycle(vp);
5307 }
5308#endif
5309
0a7de745 5310 return _err;
91447636
A
5311}
5312
5313
5314#if 0
5315/*
0a7de745
A
5316*#
5317*#% reclaim vp U U U
5318*#
5319*/
91447636
A
5320struct vnop_reclaim_args {
5321 struct vnodeop_desc *a_desc;
5322 vnode_t a_vp;
5323 vfs_context_t a_context;
5324};
5325#endif /* 0*/
5326errno_t
2d21ac55 5327VNOP_RECLAIM(struct vnode *vp, vfs_context_t ctx)
91447636
A
5328{
5329 int _err;
5330 struct vnop_reclaim_args a;
91447636
A
5331
5332 a.a_desc = &vnop_reclaim_desc;
5333 a.a_vp = vp;
2d21ac55 5334 a.a_context = ctx;
91447636 5335
91447636 5336 _err = (*vp->v_op[vnop_reclaim_desc.vdesc_offset])(&a);
39236c6e 5337 DTRACE_FSINFO(reclaim, vnode_t, vp);
b0d623f7 5338
0a7de745 5339 return _err;
91447636
A
5340}
5341
5342
2d21ac55
A
5343/*
5344 * Returns: 0 Success
5345 * lock_fsnode:ENOENT No such file or directory [only for VFS
5346 * that is not thread safe & vnode is
5347 * currently being/has been terminated]
5348 * <vnop_pathconf_desc>:??? [per FS implementation specific]
5349 */
91447636
A
5350#if 0
5351/*
0a7de745
A
5352*#
5353*#% pathconf vp L L L
5354*#
5355*/
91447636
A
5356struct vnop_pathconf_args {
5357 struct vnodeop_desc *a_desc;
5358 vnode_t a_vp;
5359 int a_name;
b0d623f7 5360 int32_t *a_retval;
91447636
A
5361 vfs_context_t a_context;
5362};
5363#endif /* 0*/
0a7de745 5364errno_t
b0d623f7 5365VNOP_PATHCONF(struct vnode *vp, int name, int32_t *retval, vfs_context_t ctx)
91447636
A
5366{
5367 int _err;
5368 struct vnop_pathconf_args a;
91447636
A
5369
5370 a.a_desc = &vnop_pathconf_desc;
5371 a.a_vp = vp;
5372 a.a_name = name;
5373 a.a_retval = retval;
2d21ac55 5374 a.a_context = ctx;
91447636 5375
91447636 5376 _err = (*vp->v_op[vnop_pathconf_desc.vdesc_offset])(&a);
39236c6e 5377 DTRACE_FSINFO(pathconf, vnode_t, vp);
b0d623f7 5378
0a7de745 5379 return _err;
91447636
A
5380}
5381
2d21ac55
A
5382/*
5383 * Returns: 0 Success
5384 * err_advlock:ENOTSUP
5385 * lf_advlock:???
5386 * <vnop_advlock_desc>:???
5387 *
5388 * Notes: VFS implementations of advisory locking using calls through
5389 * <vnop_advlock_desc> because lock enforcement does not occur
5390 * locally should try to limit themselves to the return codes
5391 * documented above for lf_advlock and err_advlock.
5392 */
91447636
A
5393#if 0
5394/*
0a7de745
A
5395*#
5396*#% advlock vp U U U
5397*#
5398*/
91447636
A
5399struct vnop_advlock_args {
5400 struct vnodeop_desc *a_desc;
5401 vnode_t a_vp;
5402 caddr_t a_id;
5403 int a_op;
5404 struct flock *a_fl;
5405 int a_flags;
5406 vfs_context_t a_context;
5407};
5408#endif /* 0*/
0a7de745 5409errno_t
39236c6e 5410VNOP_ADVLOCK(struct vnode *vp, caddr_t id, int op, struct flock *fl, int flags, vfs_context_t ctx, struct timespec *timeout)
91447636
A
5411{
5412 int _err;
5413 struct vnop_advlock_args a;
91447636
A
5414
5415 a.a_desc = &vnop_advlock_desc;
5416 a.a_vp = vp;
5417 a.a_id = id;
5418 a.a_op = op;
5419 a.a_fl = fl;
5420 a.a_flags = flags;
2d21ac55 5421 a.a_context = ctx;
39236c6e 5422 a.a_timeout = timeout;
b0d623f7 5423
91447636
A
5424 /* Disallow advisory locking on non-seekable vnodes */
5425 if (vnode_isfifo(vp)) {
5426 _err = err_advlock(&a);
5427 } else {
5428 if ((vp->v_flag & VLOCKLOCAL)) {
5429 /* Advisory locking done at this layer */
5430 _err = lf_advlock(&a);
3e170ce0
A
5431 } else if (flags & F_OFD_LOCK) {
5432 /* Non-local locking doesn't work for OFD locks */
5433 _err = err_advlock(&a);
91447636
A
5434 } else {
5435 /* Advisory locking done by underlying filesystem */
5436 _err = (*vp->v_op[vnop_advlock_desc.vdesc_offset])(&a);
5437 }
39236c6e 5438 DTRACE_FSINFO(advlock, vnode_t, vp);
0a7de745 5439 if (op == F_UNLCK && flags == F_FLOCK) {
39037602 5440 post_event_if_success(vp, _err, NOTE_FUNLOCK);
0a7de745 5441 }
91447636 5442 }
b0d623f7 5443
0a7de745 5444 return _err;
91447636
A
5445}
5446
5447
5448
5449#if 0
5450/*
0a7de745
A
5451*#
5452*#% allocate vp L L L
5453*#
5454*/
91447636
A
5455struct vnop_allocate_args {
5456 struct vnodeop_desc *a_desc;
5457 vnode_t a_vp;
5458 off_t a_length;
5459 u_int32_t a_flags;
5460 off_t *a_bytesallocated;
5461 off_t a_offset;
5462 vfs_context_t a_context;
5463};
5464
5465#endif /* 0*/
0a7de745 5466errno_t
2d21ac55 5467VNOP_ALLOCATE(struct vnode *vp, off_t length, u_int32_t flags, off_t *bytesallocated, off_t offset, vfs_context_t ctx)
91447636
A
5468{
5469 int _err;
5470 struct vnop_allocate_args a;
91447636
A
5471
5472 a.a_desc = &vnop_allocate_desc;
5473 a.a_vp = vp;
5474 a.a_length = length;
5475 a.a_flags = flags;
5476 a.a_bytesallocated = bytesallocated;
5477 a.a_offset = offset;
2d21ac55 5478 a.a_context = ctx;
91447636 5479
91447636 5480 _err = (*vp->v_op[vnop_allocate_desc.vdesc_offset])(&a);
39236c6e 5481 DTRACE_FSINFO(allocate, vnode_t, vp);
b0d623f7
A
5482#if CONFIG_FSE
5483 if (_err == 0) {
5484 add_fsevent(FSE_STAT_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
5485 }
5486#endif
5487
0a7de745 5488 return _err;
91447636
A
5489}
5490
5491#if 0
5492/*
0a7de745
A
5493*#
5494*#% pagein vp = = =
5495*#
5496*/
91447636
A
5497struct vnop_pagein_args {
5498 struct vnodeop_desc *a_desc;
5499 vnode_t a_vp;
5500 upl_t a_pl;
b0d623f7 5501 upl_offset_t a_pl_offset;
91447636
A
5502 off_t a_f_offset;
5503 size_t a_size;
5504 int a_flags;
5505 vfs_context_t a_context;
5506};
5507#endif /* 0*/
0a7de745 5508errno_t
b0d623f7 5509VNOP_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
5510{
5511 int _err;
5512 struct vnop_pagein_args a;
91447636
A
5513
5514 a.a_desc = &vnop_pagein_desc;
5515 a.a_vp = vp;
5516 a.a_pl = pl;
5517 a.a_pl_offset = pl_offset;
5518 a.a_f_offset = f_offset;
5519 a.a_size = size;
5520 a.a_flags = flags;
2d21ac55 5521 a.a_context = ctx;
91447636 5522
91447636 5523 _err = (*vp->v_op[vnop_pagein_desc.vdesc_offset])(&a);
39236c6e 5524 DTRACE_FSINFO(pagein, vnode_t, vp);
b0d623f7 5525
0a7de745 5526 return _err;
91447636
A
5527}
5528
5529#if 0
5530/*
0a7de745
A
5531*#
5532*#% pageout vp = = =
5533*#
5534*/
91447636
A
5535struct vnop_pageout_args {
5536 struct vnodeop_desc *a_desc;
5537 vnode_t a_vp;
5538 upl_t a_pl;
b0d623f7 5539 upl_offset_t a_pl_offset;
91447636
A
5540 off_t a_f_offset;
5541 size_t a_size;
5542 int a_flags;
5543 vfs_context_t a_context;
5544};
5545
5546#endif /* 0*/
0a7de745 5547errno_t
b0d623f7 5548VNOP_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
5549{
5550 int _err;
5551 struct vnop_pageout_args a;
91447636
A
5552
5553 a.a_desc = &vnop_pageout_desc;
5554 a.a_vp = vp;
5555 a.a_pl = pl;
5556 a.a_pl_offset = pl_offset;
5557 a.a_f_offset = f_offset;
5558 a.a_size = size;
5559 a.a_flags = flags;
2d21ac55 5560 a.a_context = ctx;
91447636 5561
91447636 5562 _err = (*vp->v_op[vnop_pageout_desc.vdesc_offset])(&a);
39236c6e 5563 DTRACE_FSINFO(pageout, vnode_t, vp);
b0d623f7
A
5564
5565 post_event_if_success(vp, _err, NOTE_WRITE);
5566
0a7de745 5567 return _err;
91447636
A
5568}
5569
6d2010ae
A
5570int
5571vn_remove(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, struct vnode_attr *vap, vfs_context_t ctx)
5572{
5573 if (vnode_compound_remove_available(dvp)) {
5574 return VNOP_COMPOUND_REMOVE(dvp, vpp, ndp, flags, vap, ctx);
5575 } else {
5576 return VNOP_REMOVE(dvp, *vpp, &ndp->ni_cnd, flags, ctx);
5577 }
5578}
5579
316670eb 5580#if CONFIG_SEARCHFS
91447636
A
5581
5582#if 0
5583/*
0a7de745
A
5584*#
5585*#% searchfs vp L L L
5586*#
5587*/
91447636
A
5588struct vnop_searchfs_args {
5589 struct vnodeop_desc *a_desc;
5590 vnode_t a_vp;
5591 void *a_searchparams1;
5592 void *a_searchparams2;
5593 struct attrlist *a_searchattrs;
b0d623f7 5594 uint32_t a_maxmatches;
91447636
A
5595 struct timeval *a_timelimit;
5596 struct attrlist *a_returnattrs;
b0d623f7
A
5597 uint32_t *a_nummatches;
5598 uint32_t a_scriptcode;
5599 uint32_t a_options;
91447636
A
5600 struct uio *a_uio;
5601 struct searchstate *a_searchstate;
5602 vfs_context_t a_context;
5603};
5604
5605#endif /* 0*/
0a7de745 5606errno_t
b0d623f7 5607VNOP_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
5608{
5609 int _err;
5610 struct vnop_searchfs_args a;
91447636
A
5611
5612 a.a_desc = &vnop_searchfs_desc;
5613 a.a_vp = vp;
5614 a.a_searchparams1 = searchparams1;
5615 a.a_searchparams2 = searchparams2;
5616 a.a_searchattrs = searchattrs;
5617 a.a_maxmatches = maxmatches;
5618 a.a_timelimit = timelimit;
5619 a.a_returnattrs = returnattrs;
5620 a.a_nummatches = nummatches;
5621 a.a_scriptcode = scriptcode;
5622 a.a_options = options;
5623 a.a_uio = uio;
5624 a.a_searchstate = searchstate;
2d21ac55 5625 a.a_context = ctx;
91447636 5626
91447636 5627 _err = (*vp->v_op[vnop_searchfs_desc.vdesc_offset])(&a);
39236c6e 5628 DTRACE_FSINFO(searchfs, vnode_t, vp);
b0d623f7 5629
0a7de745 5630 return _err;
91447636 5631}
316670eb 5632#endif /* CONFIG_SEARCHFS */
91447636
A
5633
5634#if 0
5635/*
0a7de745
A
5636*#
5637*#% copyfile fvp U U U
5638*#% copyfile tdvp L U U
5639*#% copyfile tvp X U U
5640*#
5641*/
91447636
A
5642struct vnop_copyfile_args {
5643 struct vnodeop_desc *a_desc;
5644 vnode_t a_fvp;
5645 vnode_t a_tdvp;
5646 vnode_t a_tvp;
5647 struct componentname *a_tcnp;
5648 int a_mode;
5649 int a_flags;
5650 vfs_context_t a_context;
5651};
5652#endif /* 0*/
0a7de745 5653errno_t
91447636 5654VNOP_COPYFILE(struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp,
0a7de745 5655 int mode, int flags, vfs_context_t ctx)
91447636
A
5656{
5657 int _err;
5658 struct vnop_copyfile_args a;
5659 a.a_desc = &vnop_copyfile_desc;
5660 a.a_fvp = fvp;
5661 a.a_tdvp = tdvp;
5662 a.a_tvp = tvp;
5663 a.a_tcnp = tcnp;
5664 a.a_mode = mode;
5665 a.a_flags = flags;
2d21ac55 5666 a.a_context = ctx;
91447636 5667 _err = (*fvp->v_op[vnop_copyfile_desc.vdesc_offset])(&a);
39236c6e 5668 DTRACE_FSINFO(copyfile, vnode_t, fvp);
0a7de745 5669 return _err;
91447636
A
5670}
5671
39037602
A
5672#if 0
5673struct vnop_clonefile_args {
5674 struct vnodeop_desc *a_desc;
5675 vnode_t a_fvp;
5676 vnode_t a_dvp;
813fb2f6 5677 vnode_t *a_vpp;
39037602
A
5678 struct componentname *a_cnp;
5679 struct vnode_attr *a_vap;
5680 uint32_t a_flags;
5681 vfs_context_t a_context;
0a7de745
A
5682 int (*a_dir_clone_authorizer)( /* Authorization callback */
5683 struct vnode_attr *vap, /* attribute to be authorized */
5684 kauth_action_t action, /* action for which attribute is to be authorized */
5685 struct vnode_attr *dvap, /* target directory attributes */
5686 vnode_t sdvp, /* source directory vnode pointer (optional) */
5687 mount_t mp, /* mount point of filesystem */
5688 dir_clone_authorizer_op_t vattr_op, /* specific operation requested : setup, authorization or cleanup */
5689 uint32_t flags; /* value passed in a_flags to the VNOP */
5690 vfs_context_t ctx, /* As passed to VNOP */
5691 void *reserved); /* Always NULL */
5692 void *a_reserved; /* Currently unused */
39037602
A
5693};
5694#endif /* 0 */
5695
5696errno_t
5697VNOP_CLONEFILE(vnode_t fvp, vnode_t dvp, vnode_t *vpp,
5698 struct componentname *cnp, struct vnode_attr *vap, uint32_t flags,
5699 vfs_context_t ctx)
5700{
5701 int _err;
5702 struct vnop_clonefile_args a;
5703 a.a_desc = &vnop_clonefile_desc;
5704 a.a_fvp = fvp;
5705 a.a_dvp = dvp;
5706 a.a_vpp = vpp;
5707 a.a_cnp = cnp;
5708 a.a_vap = vap;
5709 a.a_flags = flags;
5710 a.a_context = ctx;
5711
0a7de745 5712 if (vnode_vtype(fvp) == VDIR) {
813fb2f6 5713 a.a_dir_clone_authorizer = vnode_attr_authorize_dir_clone;
0a7de745 5714 } else {
813fb2f6 5715 a.a_dir_clone_authorizer = NULL;
0a7de745 5716 }
813fb2f6 5717
39037602
A
5718 _err = (*dvp->v_op[vnop_clonefile_desc.vdesc_offset])(&a);
5719
d9a64523 5720 if (_err == 0 && *vpp) {
39037602 5721 DTRACE_FSINFO(clonefile, vnode_t, *vpp);
0a7de745 5722 if (kdebug_enable) {
d9a64523 5723 kdebug_lookup(*vpp, cnp);
0a7de745 5724 }
d9a64523 5725 }
39037602
A
5726
5727 post_event_if_success(dvp, _err, NOTE_WRITE);
5728
0a7de745 5729 return _err;
39037602
A
5730}
5731
91447636 5732errno_t
2d21ac55 5733VNOP_GETXATTR(vnode_t vp, const char *name, uio_t uio, size_t *size, int options, vfs_context_t ctx)
91447636
A
5734{
5735 struct vnop_getxattr_args a;
5736 int error;
91447636
A
5737
5738 a.a_desc = &vnop_getxattr_desc;
5739 a.a_vp = vp;
5740 a.a_name = name;
5741 a.a_uio = uio;
5742 a.a_size = size;
5743 a.a_options = options;
2d21ac55 5744 a.a_context = ctx;
91447636 5745
91447636 5746 error = (*vp->v_op[vnop_getxattr_desc.vdesc_offset])(&a);
39236c6e 5747 DTRACE_FSINFO(getxattr, vnode_t, vp);
b0d623f7 5748
0a7de745 5749 return error;
91447636
A
5750}
5751
5752errno_t
2d21ac55 5753VNOP_SETXATTR(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t ctx)
91447636
A
5754{
5755 struct vnop_setxattr_args a;
5756 int error;
91447636
A
5757
5758 a.a_desc = &vnop_setxattr_desc;
5759 a.a_vp = vp;
5760 a.a_name = name;
5761 a.a_uio = uio;
5762 a.a_options = options;
2d21ac55 5763 a.a_context = ctx;
91447636 5764
91447636 5765 error = (*vp->v_op[vnop_setxattr_desc.vdesc_offset])(&a);
39236c6e 5766 DTRACE_FSINFO(setxattr, vnode_t, vp);
b0d623f7 5767
0a7de745
A
5768 if (error == 0) {
5769 vnode_uncache_authorized_action(vp, KAUTH_INVALIDATE_CACHED_RIGHTS);
5770 }
b0d623f7
A
5771
5772 post_event_if_success(vp, error, NOTE_ATTRIB);
5773
0a7de745 5774 return error;
91447636
A
5775}
5776
5777errno_t
2d21ac55 5778VNOP_REMOVEXATTR(vnode_t vp, const char *name, int options, vfs_context_t ctx)
91447636
A
5779{
5780 struct vnop_removexattr_args a;
5781 int error;
91447636
A
5782
5783 a.a_desc = &vnop_removexattr_desc;
5784 a.a_vp = vp;
5785 a.a_name = name;
5786 a.a_options = options;
2d21ac55 5787 a.a_context = ctx;
91447636 5788
91447636 5789 error = (*vp->v_op[vnop_removexattr_desc.vdesc_offset])(&a);
39236c6e 5790 DTRACE_FSINFO(removexattr, vnode_t, vp);
b0d623f7
A
5791
5792 post_event_if_success(vp, error, NOTE_ATTRIB);
0a7de745
A
5793
5794 return error;
91447636
A
5795}
5796
5797errno_t
2d21ac55 5798VNOP_LISTXATTR(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t ctx)
91447636
A
5799{
5800 struct vnop_listxattr_args a;
5801 int error;
91447636
A
5802
5803 a.a_desc = &vnop_listxattr_desc;
5804 a.a_vp = vp;
5805 a.a_uio = uio;
5806 a.a_size = size;
5807 a.a_options = options;
2d21ac55 5808 a.a_context = ctx;
91447636 5809
91447636 5810 error = (*vp->v_op[vnop_listxattr_desc.vdesc_offset])(&a);
39236c6e 5811 DTRACE_FSINFO(listxattr, vnode_t, vp);
b0d623f7 5812
0a7de745 5813 return error;
91447636
A
5814}
5815
5816
5817#if 0
5818/*
0a7de745
A
5819*#
5820*#% blktooff vp = = =
5821*#
5822*/
91447636
A
5823struct vnop_blktooff_args {
5824 struct vnodeop_desc *a_desc;
5825 vnode_t a_vp;
5826 daddr64_t a_lblkno;
5827 off_t *a_offset;
5828};
5829#endif /* 0*/
0a7de745 5830errno_t
91447636
A
5831VNOP_BLKTOOFF(struct vnode *vp, daddr64_t lblkno, off_t *offset)
5832{
5833 int _err;
5834 struct vnop_blktooff_args a;
91447636
A
5835
5836 a.a_desc = &vnop_blktooff_desc;
5837 a.a_vp = vp;
5838 a.a_lblkno = lblkno;
5839 a.a_offset = offset;
91447636 5840
91447636 5841 _err = (*vp->v_op[vnop_blktooff_desc.vdesc_offset])(&a);
39236c6e 5842 DTRACE_FSINFO(blktooff, vnode_t, vp);
b0d623f7 5843
0a7de745 5844 return _err;
91447636
A
5845}
5846
5847#if 0
5848/*
0a7de745
A
5849*#
5850*#% offtoblk vp = = =
5851*#
5852*/
91447636
A
5853struct vnop_offtoblk_args {
5854 struct vnodeop_desc *a_desc;
5855 vnode_t a_vp;
5856 off_t a_offset;
5857 daddr64_t *a_lblkno;
5858};
5859#endif /* 0*/
0a7de745 5860errno_t
91447636
A
5861VNOP_OFFTOBLK(struct vnode *vp, off_t offset, daddr64_t *lblkno)
5862{
5863 int _err;
5864 struct vnop_offtoblk_args a;
91447636
A
5865
5866 a.a_desc = &vnop_offtoblk_desc;
5867 a.a_vp = vp;
5868 a.a_offset = offset;
5869 a.a_lblkno = lblkno;
91447636 5870
91447636 5871 _err = (*vp->v_op[vnop_offtoblk_desc.vdesc_offset])(&a);
39236c6e 5872 DTRACE_FSINFO(offtoblk, vnode_t, vp);
b0d623f7 5873
0a7de745 5874 return _err;
91447636
A
5875}
5876
f427ee49
A
5877#if 0
5878/*
5879*#
5880*#% ap vp L L L
5881*#
5882*/
5883struct vnop_verify_args {
5884 struct vnodeop_desc *a_desc;
5885 vnode_t a_vp;
5886 off_t a_foffset;
5887 char *a_buf;
5888 size_t a_bufsize;
5889 size_t *a_verifyblksize;
5890 int a_flags;
5891 vfs_context_t a_context;
5892};
5893#endif
5894
5895errno_t
5896VNOP_VERIFY(struct vnode *vp, off_t foffset, uint8_t *buf, size_t bufsize,
5897 size_t *verify_block_size, vnode_verify_flags_t flags, vfs_context_t ctx)
5898{
5899 int _err;
5900 struct vnop_verify_args a;
5901
5902 if (ctx == NULL) {
5903 ctx = vfs_context_current();
5904 }
5905 a.a_desc = &vnop_verify_desc;
5906 a.a_vp = vp;
5907 a.a_foffset = foffset;
5908 a.a_buf = buf;
5909 a.a_bufsize = bufsize;
5910 a.a_verifyblksize = verify_block_size;
5911 a.a_flags = flags;
5912 a.a_context = ctx;
5913
5914 _err = (*vp->v_op[vnop_verify_desc.vdesc_offset])(&a);
5915 DTRACE_FSINFO(verify, vnode_t, vp);
5916
5917 /* It is not an error for a filesystem to not support this VNOP */
5918 if (_err == ENOTSUP) {
5919 if (!buf && verify_block_size) {
5920 *verify_block_size = 0;
5921 }
5922
5923 _err = 0;
5924 }
5925
5926 return _err;
5927}
5928
91447636
A
5929#if 0
5930/*
0a7de745
A
5931*#
5932*#% blockmap vp L L L
5933*#
5934*/
91447636
A
5935struct vnop_blockmap_args {
5936 struct vnodeop_desc *a_desc;
5937 vnode_t a_vp;
5938 off_t a_foffset;
5939 size_t a_size;
5940 daddr64_t *a_bpn;
5941 size_t *a_run;
5942 void *a_poff;
5943 int a_flags;
5944 vfs_context_t a_context;
5945};
5946#endif /* 0*/
0a7de745 5947errno_t
2d21ac55 5948VNOP_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
5949{
5950 int _err;
5951 struct vnop_blockmap_args a;
316670eb 5952 size_t localrun = 0;
91447636 5953
2d21ac55
A
5954 if (ctx == NULL) {
5955 ctx = vfs_context_current();
91447636
A
5956 }
5957 a.a_desc = &vnop_blockmap_desc;
5958 a.a_vp = vp;
5959 a.a_foffset = foffset;
5960 a.a_size = size;
5961 a.a_bpn = bpn;
316670eb 5962 a.a_run = &localrun;
91447636
A
5963 a.a_poff = poff;
5964 a.a_flags = flags;
2d21ac55 5965 a.a_context = ctx;
91447636 5966
91447636 5967 _err = (*vp->v_op[vnop_blockmap_desc.vdesc_offset])(&a);
39236c6e 5968 DTRACE_FSINFO(blockmap, vnode_t, vp);
316670eb
A
5969
5970 /*
5971 * We used a local variable to request information from the underlying
5972 * filesystem about the length of the I/O run in question. If
5973 * we get malformed output from the filesystem, we cap it to the length
5974 * requested, at most. Update 'run' on the way out.
5975 */
5976 if (_err == 0) {
5977 if (localrun > size) {
5978 localrun = size;
5979 }
5980
5981 if (run) {
5982 *run = localrun;
5983 }
5984 }
b0d623f7 5985
0a7de745 5986 return _err;
91447636
A
5987}
5988
5989#if 0
5990struct vnop_strategy_args {
5991 struct vnodeop_desc *a_desc;
5992 struct buf *a_bp;
5993};
5994
5995#endif /* 0*/
0a7de745 5996errno_t
91447636
A
5997VNOP_STRATEGY(struct buf *bp)
5998{
5999 int _err;
6000 struct vnop_strategy_args a;
39236c6e 6001 vnode_t vp = buf_vnode(bp);
91447636
A
6002 a.a_desc = &vnop_strategy_desc;
6003 a.a_bp = bp;
39236c6e
A
6004 _err = (*vp->v_op[vnop_strategy_desc.vdesc_offset])(&a);
6005 DTRACE_FSINFO(strategy, vnode_t, vp);
0a7de745 6006 return _err;
91447636
A
6007}
6008
6009#if 0
6010struct vnop_bwrite_args {
6011 struct vnodeop_desc *a_desc;
6012 buf_t a_bp;
6013};
6014#endif /* 0*/
0a7de745 6015errno_t
91447636
A
6016VNOP_BWRITE(struct buf *bp)
6017{
6018 int _err;
6019 struct vnop_bwrite_args a;
39236c6e 6020 vnode_t vp = buf_vnode(bp);
91447636
A
6021 a.a_desc = &vnop_bwrite_desc;
6022 a.a_bp = bp;
39236c6e
A
6023 _err = (*vp->v_op[vnop_bwrite_desc.vdesc_offset])(&a);
6024 DTRACE_FSINFO(bwrite, vnode_t, vp);
0a7de745 6025 return _err;
91447636
A
6026}
6027
6028#if 0
6029struct vnop_kqfilt_add_args {
6030 struct vnodeop_desc *a_desc;
6031 struct vnode *a_vp;
6032 struct knote *a_kn;
6033 vfs_context_t a_context;
6034};
6035#endif
6036errno_t
2d21ac55 6037VNOP_KQFILT_ADD(struct vnode *vp, struct knote *kn, vfs_context_t ctx)
91447636
A
6038{
6039 int _err;
6040 struct vnop_kqfilt_add_args a;
91447636
A
6041
6042 a.a_desc = VDESC(vnop_kqfilt_add);
6043 a.a_vp = vp;
6044 a.a_kn = kn;
2d21ac55 6045 a.a_context = ctx;
91447636 6046
91447636 6047 _err = (*vp->v_op[vnop_kqfilt_add_desc.vdesc_offset])(&a);
39236c6e 6048 DTRACE_FSINFO(kqfilt_add, vnode_t, vp);
0a7de745
A
6049
6050 return _err;
91447636
A
6051}
6052
6053#if 0
6054struct vnop_kqfilt_remove_args {
6055 struct vnodeop_desc *a_desc;
6056 struct vnode *a_vp;
6057 uintptr_t a_ident;
6058 vfs_context_t a_context;
6059};
6060#endif
6061errno_t
2d21ac55 6062VNOP_KQFILT_REMOVE(struct vnode *vp, uintptr_t ident, vfs_context_t ctx)
91447636
A
6063{
6064 int _err;
6065 struct vnop_kqfilt_remove_args a;
91447636
A
6066
6067 a.a_desc = VDESC(vnop_kqfilt_remove);
6068 a.a_vp = vp;
6069 a.a_ident = ident;
2d21ac55 6070 a.a_context = ctx;
91447636 6071
91447636 6072 _err = (*vp->v_op[vnop_kqfilt_remove_desc.vdesc_offset])(&a);
39236c6e 6073 DTRACE_FSINFO(kqfilt_remove, vnode_t, vp);
b0d623f7 6074
0a7de745 6075 return _err;
b0d623f7
A
6076}
6077
6078errno_t
6079VNOP_MONITOR(vnode_t vp, uint32_t events, uint32_t flags, void *handle, vfs_context_t ctx)
6080{
6081 int _err;
6082 struct vnop_monitor_args a;
b0d623f7
A
6083
6084 a.a_desc = VDESC(vnop_monitor);
6085 a.a_vp = vp;
6086 a.a_events = events;
6087 a.a_flags = flags;
6088 a.a_handle = handle;
6089 a.a_context = ctx;
6090
b0d623f7 6091 _err = (*vp->v_op[vnop_monitor_desc.vdesc_offset])(&a);
39236c6e 6092 DTRACE_FSINFO(monitor, vnode_t, vp);
b0d623f7 6093
0a7de745 6094 return _err;
91447636
A
6095}
6096
2d21ac55
A
6097#if 0
6098struct vnop_setlabel_args {
6099 struct vnodeop_desc *a_desc;
6100 struct vnode *a_vp;
6101 struct label *a_vl;
6102 vfs_context_t a_context;
6103};
6104#endif
6105errno_t
6106VNOP_SETLABEL(struct vnode *vp, struct label *label, vfs_context_t ctx)
6107{
6108 int _err;
6109 struct vnop_setlabel_args a;
2d21ac55
A
6110
6111 a.a_desc = VDESC(vnop_setlabel);
6112 a.a_vp = vp;
6113 a.a_vl = label;
6114 a.a_context = ctx;
2d21ac55 6115
2d21ac55 6116 _err = (*vp->v_op[vnop_setlabel_desc.vdesc_offset])(&a);
39236c6e 6117 DTRACE_FSINFO(setlabel, vnode_t, vp);
b0d623f7 6118
0a7de745 6119 return _err;
2d21ac55
A
6120}
6121
6122
6123#if NAMEDSTREAMS
6124/*
6125 * Get a named streamed
6126 */
0a7de745 6127errno_t
2d21ac55
A
6128VNOP_GETNAMEDSTREAM(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation operation, int flags, vfs_context_t ctx)
6129{
39236c6e 6130 int _err;
2d21ac55
A
6131 struct vnop_getnamedstream_args a;
6132
2d21ac55
A
6133 a.a_desc = &vnop_getnamedstream_desc;
6134 a.a_vp = vp;
6135 a.a_svpp = svpp;
6136 a.a_name = name;
6137 a.a_operation = operation;
6138 a.a_flags = flags;
6139 a.a_context = ctx;
6140
39236c6e
A
6141 _err = (*vp->v_op[vnop_getnamedstream_desc.vdesc_offset])(&a);
6142 DTRACE_FSINFO(getnamedstream, vnode_t, vp);
0a7de745 6143 return _err;
2d21ac55
A
6144}
6145
6146/*
6147 * Create a named streamed
6148 */
0a7de745 6149errno_t
2d21ac55
A
6150VNOP_MAKENAMEDSTREAM(vnode_t vp, vnode_t *svpp, const char *name, int flags, vfs_context_t ctx)
6151{
39236c6e 6152 int _err;
2d21ac55
A
6153 struct vnop_makenamedstream_args a;
6154
2d21ac55
A
6155 a.a_desc = &vnop_makenamedstream_desc;
6156 a.a_vp = vp;
6157 a.a_svpp = svpp;
6158 a.a_name = name;
6159 a.a_flags = flags;
6160 a.a_context = ctx;
6161
39236c6e
A
6162 _err = (*vp->v_op[vnop_makenamedstream_desc.vdesc_offset])(&a);
6163 DTRACE_FSINFO(makenamedstream, vnode_t, vp);
0a7de745 6164 return _err;
2d21ac55
A
6165}
6166
6167
6168/*
6169 * Remove a named streamed
6170 */
0a7de745 6171errno_t
2d21ac55
A
6172VNOP_REMOVENAMEDSTREAM(vnode_t vp, vnode_t svp, const char *name, int flags, vfs_context_t ctx)
6173{
39236c6e 6174 int _err;
2d21ac55
A
6175 struct vnop_removenamedstream_args a;
6176
2d21ac55
A
6177 a.a_desc = &vnop_removenamedstream_desc;
6178 a.a_vp = vp;
6179 a.a_svp = svp;
6180 a.a_name = name;
6181 a.a_flags = flags;
6182 a.a_context = ctx;
6183
39236c6e
A
6184 _err = (*vp->v_op[vnop_removenamedstream_desc.vdesc_offset])(&a);
6185 DTRACE_FSINFO(removenamedstream, vnode_t, vp);
0a7de745 6186 return _err;
2d21ac55
A
6187}
6188#endif