]> git.saurik.com Git - apple/xnu.git/blame - bsd/vfs/vfs_vnops.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_vnops.c
CommitLineData
1c79356b 1/*
cf7d32b8 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29/*
30 * Copyright (c) 1982, 1986, 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 * @(#)vfs_vnops.c 8.14 (Berkeley) 6/15/95
67 *
1c79356b 68 */
2d21ac55
A
69/*
70 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
71 * support for mandatory and extensible security protections. This notice
72 * is included in support of clause 2.2 (b) of the Apple Public License,
73 * Version 2.0.
74 */
1c79356b
A
75
76#include <sys/param.h>
91447636 77#include <sys/types.h>
1c79356b
A
78#include <sys/systm.h>
79#include <sys/kernel.h>
91447636 80#include <sys/file_internal.h>
1c79356b 81#include <sys/stat.h>
91447636
A
82#include <sys/proc_internal.h>
83#include <sys/kauth.h>
84#include <sys/mount_internal.h>
1c79356b 85#include <sys/namei.h>
91447636 86#include <sys/vnode_internal.h>
1c79356b
A
87#include <sys/ioctl.h>
88#include <sys/tty.h>
2d21ac55
A
89/* Temporary workaround for ubc.h until <rdar://4714366 is resolved */
90#define ubc_setcred ubc_setcred_deprecated
1c79356b 91#include <sys/ubc.h>
2d21ac55
A
92#undef ubc_setcred
93int ubc_setcred(struct vnode *, struct proc *);
9bccf70c
A
94#include <sys/conf.h>
95#include <sys/disk.h>
91447636
A
96#include <sys/fsevents.h>
97#include <sys/kdebug.h>
98#include <sys/xattr.h>
99#include <sys/ubc_internal.h>
100#include <sys/uio_internal.h>
0c530ab8 101#include <sys/resourcevar.h>
2d21ac55 102#include <sys/signalvar.h>
9bccf70c
A
103
104#include <vm/vm_kern.h>
91447636 105#include <vm/vm_map.h>
9bccf70c
A
106
107#include <miscfs/specfs/specdev.h>
108
2d21ac55
A
109#if CONFIG_MACF
110#include <security/mac_framework.h>
111#endif
91447636
A
112
113
2d21ac55
A
114static int vn_closefile(struct fileglob *fp, vfs_context_t ctx);
115static int vn_ioctl(struct fileproc *fp, u_long com, caddr_t data,
116 vfs_context_t ctx);
117static int vn_read(struct fileproc *fp, struct uio *uio, int flags,
118 vfs_context_t ctx);
119static int vn_write(struct fileproc *fp, struct uio *uio, int flags,
120 vfs_context_t ctx);
121static int vn_select( struct fileproc *fp, int which, void * wql,
122 vfs_context_t ctx);
123static int vn_kqfilt_add(struct fileproc *fp, struct knote *kn,
124 vfs_context_t ctx);
91447636 125#if 0
2d21ac55
A
126static int vn_kqfilt_remove(struct vnode *vp, uintptr_t ident,
127 vfs_context_t ctx);
91447636 128#endif
1c79356b
A
129
130struct fileops vnops =
2d21ac55 131 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile, vn_kqfilt_add, NULL };
1c79356b
A
132
133/*
134 * Common code for vnode open operations.
91447636
A
135 * Check permissions, and call the VNOP_OPEN or VNOP_CREATE routine.
136 *
137 * XXX the profusion of interfaces here is probably a bad thing.
1c79356b 138 */
9bccf70c 139int
91447636 140vn_open(struct nameidata *ndp, int fmode, int cmode)
55e303ae 141{
91447636 142 return(vn_open_modflags(ndp, &fmode, cmode));
55e303ae
A
143}
144
91447636
A
145int
146vn_open_modflags(struct nameidata *ndp, int *fmodep, int cmode)
1c79356b 147{
91447636
A
148 struct vnode_attr va;
149
150 VATTR_INIT(&va);
151 VATTR_SET(&va, va_mode, cmode);
152
153 return(vn_open_auth(ndp, fmodep, &va));
154}
155
0c530ab8
A
156/*
157 * Open a file with authorization, updating the contents of the structures
158 * pointed to by ndp, fmodep, and vap as necessary to perform the requested
159 * operation. This function is used for both opens of existing files, and
160 * creation of new files.
161 *
162 * Parameters: ndp The nami data pointer describing the
163 * file
164 * fmodep A pointer to an int containg the mode
165 * information to be used for the open
166 * vap A pointer to the vnode attribute
167 * descriptor to be used for the open
168 *
169 * Indirect: * Contents of the data structures pointed
170 * to by the parameters are modified as
171 * necessary to the requested operation.
172 *
173 * Returns: 0 Success
174 * !0 errno value
175 *
176 * Notes: The kauth_filesec_t in 'vap', if any, is in host byte order.
177 *
178 * The contents of '*ndp' will be modified, based on the other
179 * arguments to this function, and to return file and directory
180 * data necessary to satisfy the requested operation.
181 *
182 * If the file does not exist and we are creating it, then the
183 * O_TRUNC flag will be cleared in '*fmodep' to indicate to the
184 * caller that the file was not truncated.
185 *
186 * If the file exists and the O_EXCL flag was not specified, then
187 * the O_CREAT flag will be cleared in '*fmodep' to indicate to
188 * the caller that the existing file was merely opened rather
189 * than created.
190 *
191 * The contents of '*vap' will be modified as necessary to
192 * complete the operation, including setting of supported
193 * attribute, clearing of fields containing unsupported attributes
194 * in the request, if the request proceeds without them, etc..
195 *
196 * XXX: This function is too complicated in actings on its arguments
197 *
198 * XXX: We should enummerate the possible errno values here, and where
199 * in the code they originated.
200 */
91447636
A
201int
202vn_open_auth(struct nameidata *ndp, int *fmodep, struct vnode_attr *vap)
203{
204 struct vnode *vp;
205 struct vnode *dvp;
206 vfs_context_t ctx = ndp->ni_cnd.cn_context;
1c79356b 207 int error;
91447636
A
208 int fmode;
209 kauth_action_t action;
1c79356b 210
91447636
A
211again:
212 vp = NULL;
213 dvp = NULL;
214 fmode = *fmodep;
1c79356b 215 if (fmode & O_CREAT) {
0c530ab8
A
216 if ( (fmode & O_DIRECTORY) ) {
217 error = EINVAL;
218 goto out;
219 }
1c79356b 220 ndp->ni_cnd.cn_nameiop = CREATE;
2d21ac55
A
221 /* Inherit USEDVP flag only */
222 ndp->ni_cnd.cn_flags &= USEDVP;
223 ndp->ni_cnd.cn_flags |= LOCKPARENT | LOCKLEAF | AUDITVNPATH1;
224#if NAMEDRSRCFORK
225 /* open calls are allowed for resource forks. */
226 ndp->ni_cnd.cn_flags |= CN_ALLOWRSRCFORK;
227#endif
228 if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
1c79356b 229 ndp->ni_cnd.cn_flags |= FOLLOW;
91447636
A
230 if ( (error = namei(ndp)) )
231 goto out;
232 dvp = ndp->ni_dvp;
233 vp = ndp->ni_vp;
234
235 /* not found, create */
236 if (vp == NULL) {
237 /* must have attributes for a new file */
238 if (vap == NULL) {
239 error = EINVAL;
240 goto badcreate;
241 }
242
2d21ac55
A
243 VATTR_SET(vap, va_type, VREG);
244#if CONFIG_MACF
245 error = mac_vnode_check_create(ctx,
246 dvp, &ndp->ni_cnd, vap);
247 if (error)
248 goto badcreate;
249#endif /* MAC */
250
91447636
A
251 /* authorize before creating */
252 if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx)) != 0)
253 goto badcreate;
254
1c79356b
A
255 if (fmode & O_EXCL)
256 vap->va_vaflags |= VA_EXCLUSIVE;
2d21ac55
A
257#if NAMEDRSRCFORK
258 if (ndp->ni_cnd.cn_flags & CN_WANTSRSRCFORK) {
259 if ((error = vnode_makenamedstream(dvp, &ndp->ni_vp, XATTR_RESOURCEFORK_NAME, 0, ctx)) != 0)
260 goto badcreate;
261 } else
262#endif
91447636
A
263 if ((error = vn_create(dvp, &ndp->ni_vp, &ndp->ni_cnd, vap, 0, ctx)) != 0)
264 goto badcreate;
55e303ae 265
91447636
A
266 vp = ndp->ni_vp;
267
268 if (vp) {
269 int update_flags = 0;
270
271 // Make sure the name & parent pointers are hooked up
272 if (vp->v_name == NULL)
273 update_flags |= VNODE_UPDATE_NAME;
274 if (vp->v_parent == NULLVP)
275 update_flags |= VNODE_UPDATE_PARENT;
276
277 if (update_flags)
278 vnode_update_identity(vp, dvp, ndp->ni_cnd.cn_nameptr, ndp->ni_cnd.cn_namelen, ndp->ni_cnd.cn_hash, update_flags);
279
2d21ac55 280#if CONFIG_FSE
91447636
A
281 if (need_fsevent(FSE_CREATE_FILE, vp)) {
282 add_fsevent(FSE_CREATE_FILE, ctx,
283 FSE_ARG_VNODE, vp,
284 FSE_ARG_DONE);
285 }
2d21ac55
A
286#endif
287
91447636
A
288 }
289 /*
290 * nameidone has to happen before we vnode_put(dvp)
291 * and clear the ni_dvp field, since it may need
292 * to release the fs_nodelock on the dvp
293 */
294badcreate:
295 nameidone(ndp);
296 ndp->ni_dvp = NULL;
297 vnode_put(dvp);
298
299 if (error) {
300 /*
301 * Check for a creation race.
302 */
303 if ((error == EEXIST) && !(fmode & O_EXCL)) {
304 goto again;
305 }
306 goto bad;
55e303ae 307 }
91447636 308 fmode &= ~O_TRUNC;
1c79356b 309 } else {
91447636 310 nameidone(ndp);
1c79356b 311 ndp->ni_dvp = NULL;
91447636
A
312 vnode_put(dvp);
313
1c79356b
A
314 if (fmode & O_EXCL) {
315 error = EEXIST;
316 goto bad;
317 }
318 fmode &= ~O_CREAT;
319 }
320 } else {
321 ndp->ni_cnd.cn_nameiop = LOOKUP;
2d21ac55
A
322 /* Inherit USEDVP flag only */
323 ndp->ni_cnd.cn_flags &= USEDVP;
324 ndp->ni_cnd.cn_flags |= FOLLOW | LOCKLEAF | AUDITVNPATH1;
325#if NAMEDRSRCFORK
326 /* open calls are allowed for resource forks. */
327 ndp->ni_cnd.cn_flags |= CN_ALLOWRSRCFORK;
328#endif
329 if (fmode & O_NOFOLLOW || fmode & O_SYMLINK) {
330 ndp->ni_cnd.cn_flags &= ~FOLLOW;
331 }
332
91447636
A
333 if ( (error = namei(ndp)) )
334 goto out;
1c79356b 335 vp = ndp->ni_vp;
91447636
A
336 nameidone(ndp);
337 ndp->ni_dvp = NULL;
0c530ab8
A
338
339 if ( (fmode & O_DIRECTORY) && vp->v_type != VDIR ) {
340 error = ENOTDIR;
341 goto bad;
342 }
1c79356b 343 }
2d21ac55 344
91447636
A
345 if (vp->v_type == VSOCK && vp->v_tag != VT_FDESC) {
346 error = EOPNOTSUPP; /* Operation not supported on socket */
1c79356b
A
347 goto bad;
348 }
9bccf70c 349
2d21ac55
A
350 if (vp->v_type == VLNK && (fmode & O_NOFOLLOW) != 0) {
351 error = ELOOP; /* O_NOFOLLOW was specified and the target is a symbolic link */
352 goto bad;
353 }
9bccf70c 354
91447636 355 /* authorize open of an existing file */
1c79356b 356 if ((fmode & O_CREAT) == 0) {
91447636
A
357
358 /* disallow write operations on directories */
359 if (vnode_isdir(vp) && (fmode & (FWRITE | O_TRUNC))) {
360 error = EISDIR;
361 goto bad;
1c79356b 362 }
91447636 363
2d21ac55
A
364#if CONFIG_MACF
365 error = mac_vnode_check_open(ctx, vp, fmode);
366 if (error)
367 goto bad;
368#endif
369
91447636
A
370 /* compute action to be authorized */
371 action = 0;
2d21ac55 372 if (fmode & FREAD) {
91447636 373 action |= KAUTH_VNODE_READ_DATA;
2d21ac55
A
374 }
375 if (fmode & (FWRITE | O_TRUNC)) {
376 /*
377 * If we are writing, appending, and not truncating,
378 * indicate that we are appending so that if the
379 * UF_APPEND or SF_APPEND bits are set, we do not deny
380 * the open.
381 */
382 if ((fmode & O_APPEND) && !(fmode & O_TRUNC)) {
383 action |= KAUTH_VNODE_APPEND_DATA;
384 } else {
91447636 385 action |= KAUTH_VNODE_WRITE_DATA;
2d21ac55
A
386 }
387 }
91447636
A
388 if ((error = vnode_authorize(vp, NULL, action, ctx)) != 0)
389 goto bad;
390
2d21ac55
A
391
392 //
393 // if the vnode is tagged VOPENEVT and the current process
394 // has the P_CHECKOPENEVT flag set, then we or in the O_EVTONLY
395 // flag to the open mode so that this open won't count against
396 // the vnode when carbon delete() does a vnode_isinuse() to see
397 // if a file is currently in use. this allows spotlight
398 // importers to not interfere with carbon apps that depend on
399 // the no-delete-if-busy semantics of carbon delete().
400 //
401 if ((vp->v_flag & VOPENEVT) && (current_proc()->p_flag & P_CHECKOPENEVT)) {
402 fmode |= O_EVTONLY;
403 }
404
1c79356b 405 }
0b4e3aa0 406
91447636 407 if ( (error = VNOP_OPEN(vp, fmode, ctx)) ) {
0b4e3aa0
A
408 goto bad;
409 }
2d21ac55 410 if ( (error = vnode_ref_ext(vp, fmode)) ) {
593a1d5f 411 goto bad2;
2d21ac55 412 }
91447636
A
413
414 /* call out to allow 3rd party notification of open.
415 * Ignore result of kauth_authorize_fileop call.
416 */
417 kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_OPEN,
418 (uintptr_t)vp, 0);
0b4e3aa0 419
55e303ae 420 *fmodep = fmode;
1c79356b 421 return (0);
593a1d5f
A
422bad2:
423 VNOP_CLOSE(vp, fmode, ctx);
1c79356b 424bad:
55e303ae 425 ndp->ni_vp = NULL;
91447636 426 if (vp) {
c910b4d9
A
427#if NAMEDRSRCFORK
428 if ((vnode_isnamedstream(vp)) && (vp->v_parent != NULLVP) &&
429 (vnode_isshadow (vp))) {
430 vnode_recycle(vp);
431 }
432#endif
433 vnode_put(vp);
91447636
A
434 /*
435 * Check for a race against unlink. We had a vnode
436 * but according to vnode_authorize or VNOP_OPEN it
437 * no longer exists.
935ed37a
A
438 *
439 * EREDRIVEOPEN: means that we were hit by the tty allocation race.
91447636 440 */
935ed37a 441 if (((error == ENOENT) && (*fmodep & O_CREAT)) || (error == EREDRIVEOPEN)) {
91447636
A
442 goto again;
443 }
444 }
445out:
1c79356b
A
446 return (error);
447}
448
2d21ac55 449#if vn_access_DEPRECATED
1c79356b 450/*
91447636
A
451 * Authorize an action against a vnode. This has been the canonical way to
452 * ensure that the credential/process/etc. referenced by a vfs_context
453 * is granted the rights called out in 'mode' against the vnode 'vp'.
454 *
455 * Unfortunately, the use of VREAD/VWRITE/VEXEC makes it very difficult
456 * to add support for more rights. As such, this interface will be deprecated
457 * and callers will use vnode_authorize instead.
1c79356b 458 */
9bccf70c 459int
91447636 460vn_access(vnode_t vp, int mode, vfs_context_t context)
1c79356b 461{
91447636
A
462 kauth_action_t action;
463
464 action = 0;
465 if (mode & VREAD)
466 action |= KAUTH_VNODE_READ_DATA;
467 if (mode & VWRITE)
468 action |= KAUTH_VNODE_WRITE_DATA;
469 if (mode & VEXEC)
470 action |= KAUTH_VNODE_EXECUTE;
471
472 return(vnode_authorize(vp, NULL, action, context));
1c79356b 473}
2d21ac55 474#endif /* vn_access_DEPRECATED */
1c79356b
A
475
476/*
477 * Vnode close call
478 */
9bccf70c 479int
2d21ac55 480vn_close(struct vnode *vp, int flags, vfs_context_t ctx)
1c79356b
A
481{
482 int error;
1c79356b 483
2d21ac55 484#if CONFIG_FSE
91447636
A
485 if (flags & FWASWRITTEN) {
486 if (need_fsevent(FSE_CONTENT_MODIFIED, vp)) {
2d21ac55 487 add_fsevent(FSE_CONTENT_MODIFIED, ctx,
91447636
A
488 FSE_ARG_VNODE, vp,
489 FSE_ARG_DONE);
55e303ae
A
490 }
491 }
2d21ac55 492#endif
55e303ae 493
2d21ac55 494#if NAMEDRSRCFORK
cf7d32b8 495 /* Sync data from resource fork shadow file if needed. */
2d21ac55
A
496 if ((vp->v_flag & VISNAMEDSTREAM) &&
497 (vp->v_parent != NULLVP) &&
c910b4d9 498 (vnode_isshadow(vp))) {
2d21ac55
A
499 if (flags & FWASWRITTEN) {
500 (void) vnode_flushnamedstream(vp->v_parent, vp, ctx);
501 }
2d21ac55
A
502 }
503#endif
593a1d5f
A
504
505 /* work around for foxhound */
506 if (vp->v_type == VBLK)
507 (void)vnode_rele_ext(vp, flags, 0);
508
2d21ac55 509 error = VNOP_CLOSE(vp, flags, ctx);
91447636 510
593a1d5f
A
511 if (vp->v_type != VBLK)
512 (void)vnode_rele_ext(vp, flags, 0);
513
1c79356b
A
514 return (error);
515}
516
91447636
A
517static int
518vn_read_swapfile(
519 struct vnode *vp,
520 uio_t uio)
521{
522 static char *swap_read_zero_page = NULL;
523 int error;
524 off_t swap_count, this_count;
525 off_t file_end, read_end;
526 off_t prev_resid;
527
528 /*
529 * Reading from a swap file will get you all zeroes.
530 */
531 error = 0;
532 swap_count = uio_resid(uio);
533
534 file_end = ubc_getsize(vp);
535 read_end = uio->uio_offset + uio_resid(uio);
536 if (uio->uio_offset >= file_end) {
537 /* uio starts after end of file: nothing to read */
538 swap_count = 0;
539 } else if (read_end > file_end) {
540 /* uio extends beyond end of file: stop before that */
541 swap_count -= (read_end - file_end);
542 }
543
544 while (swap_count > 0) {
545 if (swap_read_zero_page == NULL) {
546 char *my_zero_page;
547 int funnel_state;
548
549 /*
550 * Take kernel funnel so that only one thread
551 * sets up "swap_read_zero_page".
552 */
553 funnel_state = thread_funnel_set(kernel_flock, TRUE);
554
555 if (swap_read_zero_page == NULL) {
556 MALLOC(my_zero_page, char *, PAGE_SIZE,
557 M_TEMP, M_WAITOK);
558 memset(my_zero_page, '?', PAGE_SIZE);
559 /*
560 * Adding a newline character here
561 * and there prevents "less(1)", for
562 * example, from getting too confused
563 * about a file with one really really
564 * long line.
565 */
566 my_zero_page[PAGE_SIZE-1] = '\n';
567 if (swap_read_zero_page == NULL) {
568 swap_read_zero_page = my_zero_page;
569 } else {
570 FREE(my_zero_page, M_TEMP);
571 }
572 } else {
573 /*
574 * Someone else raced us here and won;
575 * just use their page.
576 */
577 }
578 thread_funnel_set(kernel_flock, funnel_state);
579 }
580
581 this_count = swap_count;
582 if (this_count > PAGE_SIZE) {
583 this_count = PAGE_SIZE;
584 }
585
586 prev_resid = uio_resid(uio);
587 error = uiomove((caddr_t) swap_read_zero_page,
588 this_count,
589 uio);
590 if (error) {
591 break;
592 }
593 swap_count -= (prev_resid - uio_resid(uio));
594 }
595
596 return error;
597}
1c79356b
A
598/*
599 * Package up an I/O request on a vnode into a uio and do it.
600 */
9bccf70c 601int
91447636
A
602vn_rdwr(
603 enum uio_rw rw,
604 struct vnode *vp,
605 caddr_t base,
606 int len,
607 off_t offset,
608 enum uio_seg segflg,
609 int ioflg,
610 kauth_cred_t cred,
611 int *aresid,
2d21ac55 612 proc_t p)
1c79356b 613{
91447636
A
614 return vn_rdwr_64(rw,
615 vp,
616 (uint64_t)(uintptr_t)base,
617 (int64_t)len,
618 offset,
619 segflg,
620 ioflg,
621 cred,
622 aresid,
623 p);
624}
625
626
627int
628vn_rdwr_64(
629 enum uio_rw rw,
630 struct vnode *vp,
631 uint64_t base,
632 int64_t len,
633 off_t offset,
634 enum uio_seg segflg,
635 int ioflg,
636 kauth_cred_t cred,
637 int *aresid,
2d21ac55 638 proc_t p)
91447636
A
639{
640 uio_t auio;
641 int spacetype;
642 struct vfs_context context;
1c79356b 643 int error=0;
91447636
A
644 char uio_buf[ UIO_SIZEOF(1) ];
645
2d21ac55 646 context.vc_thread = current_thread();
91447636 647 context.vc_ucred = cred;
1c79356b 648
91447636
A
649 if (UIO_SEG_IS_USER_SPACE(segflg)) {
650 spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
651 }
652 else {
653 spacetype = UIO_SYSSPACE;
654 }
655 auio = uio_createwithbuffer(1, offset, spacetype, rw,
656 &uio_buf[0], sizeof(uio_buf));
657 uio_addiov(auio, base, len);
658
2d21ac55
A
659#if CONFIG_MACF
660 /* XXXMAC
661 * IO_NOAUTH should be re-examined.
662 * Likely that mediation should be performed in caller.
663 */
664 if ((ioflg & IO_NOAUTH) == 0) {
665 /* passed cred is fp->f_cred */
666 if (rw == UIO_READ)
667 error = mac_vnode_check_read(&context, cred, vp);
668 else
669 error = mac_vnode_check_write(&context, cred, vp);
670 }
671#endif
672
673 if (error == 0) {
674 if (rw == UIO_READ) {
675 if (vp->v_flag & VSWAP) {
676 error = vn_read_swapfile(vp, auio);
677 } else {
678 error = VNOP_READ(vp, auio, ioflg, &context);
679 }
91447636 680 } else {
2d21ac55 681 error = VNOP_WRITE(vp, auio, ioflg, &context);
91447636 682 }
91447636 683 }
1c79356b
A
684
685 if (aresid)
91447636
A
686 // LP64todo - fix this
687 *aresid = uio_resid(auio);
1c79356b 688 else
91447636 689 if (uio_resid(auio) && error == 0)
1c79356b 690 error = EIO;
1c79356b
A
691 return (error);
692}
693
694/*
695 * File table vnode read routine.
696 */
9bccf70c 697static int
2d21ac55 698vn_read(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
1c79356b 699{
9bccf70c
A
700 struct vnode *vp;
701 int error, ioflag;
1c79356b 702 off_t count;
9bccf70c 703
91447636
A
704 vp = (struct vnode *)fp->f_fglob->fg_data;
705 if ( (error = vnode_getwithref(vp)) ) {
706 return(error);
707 }
2d21ac55
A
708
709#if CONFIG_MACF
710 error = mac_vnode_check_read(ctx, vfs_context_ucred(ctx), vp);
711 if (error) {
712 (void)vnode_put(vp);
713 return (error);
714 }
715#endif
716
9bccf70c 717 ioflag = 0;
91447636 718 if (fp->f_fglob->fg_flag & FNONBLOCK)
9bccf70c 719 ioflag |= IO_NDELAY;
2d21ac55
A
720 if ((fp->f_fglob->fg_flag & FNOCACHE) || vnode_isnocache(vp))
721 ioflag |= IO_NOCACHE;
722 if (fp->f_fglob->fg_flag & FNORDAHEAD)
723 ioflag |= IO_RAOFF;
91447636 724
9bccf70c 725 if ((flags & FOF_OFFSET) == 0)
91447636
A
726 uio->uio_offset = fp->f_fglob->fg_offset;
727 count = uio_resid(uio);
728
729 if (vp->v_flag & VSWAP) {
730 /* special case for swap files */
731 error = vn_read_swapfile(vp, uio);
732 } else {
2d21ac55 733 error = VNOP_READ(vp, uio, ioflag, ctx);
9bccf70c 734 }
9bccf70c 735 if ((flags & FOF_OFFSET) == 0)
91447636
A
736 fp->f_fglob->fg_offset += count - uio_resid(uio);
737
738 (void)vnode_put(vp);
1c79356b
A
739 return (error);
740}
741
742
743/*
744 * File table vnode write routine.
745 */
9bccf70c 746static int
2d21ac55 747vn_write(struct fileproc *fp, struct uio *uio, int flags, vfs_context_t ctx)
1c79356b 748{
9bccf70c
A
749 struct vnode *vp;
750 int error, ioflag;
1c79356b 751 off_t count;
2d21ac55
A
752 int clippedsize = 0;
753 int partialwrite=0;
754 int residcount, oldcount;
755 proc_t p = vfs_context_proc(ctx);
91447636 756
91447636
A
757 count = 0;
758 vp = (struct vnode *)fp->f_fglob->fg_data;
759 if ( (error = vnode_getwithref(vp)) ) {
760 return(error);
761 }
2d21ac55
A
762
763#if CONFIG_MACF
764 error = mac_vnode_check_write(ctx, vfs_context_ucred(ctx), vp);
765 if (error) {
766 (void)vnode_put(vp);
767 return (error);
768 }
769#endif
770
9bccf70c 771 ioflag = IO_UNIT;
91447636 772 if (vp->v_type == VREG && (fp->f_fglob->fg_flag & O_APPEND))
1c79356b 773 ioflag |= IO_APPEND;
91447636 774 if (fp->f_fglob->fg_flag & FNONBLOCK)
1c79356b 775 ioflag |= IO_NDELAY;
2d21ac55
A
776 if ((fp->f_fglob->fg_flag & FNOCACHE) || vnode_isnocache(vp))
777 ioflag |= IO_NOCACHE;
91447636 778 if ((fp->f_fglob->fg_flag & O_FSYNC) ||
1c79356b
A
779 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
780 ioflag |= IO_SYNC;
91447636 781
9bccf70c 782 if ((flags & FOF_OFFSET) == 0) {
91447636
A
783 uio->uio_offset = fp->f_fglob->fg_offset;
784 count = uio_resid(uio);
9bccf70c 785 }
2d21ac55
A
786 if (((flags & FOF_OFFSET) == 0) &&
787 vfs_context_proc(ctx) && (vp->v_type == VREG) &&
788 (((rlim_t)(uio->uio_offset + uio_uio_resid(uio)) > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) ||
789 ((rlim_t)uio_uio_resid(uio) > (p->p_rlimit[RLIMIT_FSIZE].rlim_cur - uio->uio_offset)))) {
790 /*
791 * If the requested residual would cause us to go past the
792 * administrative limit, then we need to adjust the residual
793 * down to cause fewer bytes than requested to be written. If
794 * we can't do that (e.g. the residual is already 1 byte),
795 * then we fail the write with EFBIG.
796 */
797 residcount = uio_uio_resid(uio);
798 if ((rlim_t)(uio->uio_offset + uio_uio_resid(uio)) > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
799 clippedsize = (uio->uio_offset + uio_uio_resid(uio)) - p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
800 } else if ((rlim_t)uio_uio_resid(uio) > (p->p_rlimit[RLIMIT_FSIZE].rlim_cur - uio->uio_offset)) {
801 clippedsize = (p->p_rlimit[RLIMIT_FSIZE].rlim_cur - uio->uio_offset);
802 }
803 if (clippedsize >= residcount) {
804 psignal(p, SIGXFSZ);
805 vnode_put(vp);
806 return (EFBIG);
807 }
808 partialwrite = 1;
809 uio_setresid(uio, residcount-clippedsize);
810 }
811 if ((flags & FOF_OFFSET) != 0) {
812 /* for pwrite, append should be ignored */
813 ioflag &= ~IO_APPEND;
814 if (p && (vp->v_type == VREG) &&
815 ((rlim_t)uio->uio_offset >= p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
91447636
A
816 psignal(p, SIGXFSZ);
817 vnode_put(vp);
818 return (EFBIG);
9bccf70c 819 }
2d21ac55
A
820 if (p && (vp->v_type == VREG) &&
821 ((rlim_t)(uio->uio_offset + uio_uio_resid(uio)) > p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
822 //Debugger("vn_bwrite:overstepping the bounds");
823 residcount = uio_uio_resid(uio);
824 clippedsize = (uio->uio_offset + uio_uio_resid(uio)) - p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
825 partialwrite = 1;
826 uio_setresid(uio, residcount-clippedsize);
827 }
828 }
829
830 error = VNOP_WRITE(vp, uio, ioflag, ctx);
91447636 831
2d21ac55
A
832 if (partialwrite) {
833 oldcount = uio_resid(uio);
834 uio_setresid(uio, oldcount + clippedsize);
835 }
1c79356b 836
9bccf70c
A
837 if ((flags & FOF_OFFSET) == 0) {
838 if (ioflag & IO_APPEND)
91447636 839 fp->f_fglob->fg_offset = uio->uio_offset;
9bccf70c 840 else
91447636 841 fp->f_fglob->fg_offset += count - uio_resid(uio);
9bccf70c
A
842 }
843
1c79356b
A
844 /*
845 * Set the credentials on successful writes
846 */
847 if ((error == 0) && (vp->v_tag == VT_NFS) && (UBCINFOEXISTS(vp))) {
13fec989
A
848 /*
849 * When called from aio subsystem, we only have the proc from
850 * which to get the credential, at this point, so use that
851 * instead. This means aio functions are incompatible with
852 * per-thread credentials (aio operations are proxied). We
853 * can't easily correct the aio vs. settid race in this case
854 * anyway, so we disallow it.
855 */
856 if ((flags & FOF_PCRED) == 0) {
857 ubc_setthreadcred(vp, p, current_thread());
858 } else {
859 ubc_setcred(vp, p);
860 }
1c79356b 861 }
91447636 862 (void)vnode_put(vp);
1c79356b
A
863 return (error);
864}
865
866/*
867 * File table vnode stat routine.
2d21ac55
A
868 *
869 * Returns: 0 Success
870 * EBADF
871 * ENOMEM
872 * vnode_getattr:???
1c79356b 873 */
9bccf70c 874int
2d21ac55 875vn_stat_noauth(struct vnode *vp, void *sbptr, kauth_filesec_t *xsec, int isstat64, vfs_context_t ctx)
1c79356b 876{
91447636 877 struct vnode_attr va;
1c79356b
A
878 int error;
879 u_short mode;
91447636 880 kauth_filesec_t fsec;
2d21ac55
A
881 struct stat *sb = (struct stat *)0; /* warning avoidance ; protected by isstat64 */
882 struct stat64 * sb64 = (struct stat64 *)0; /* warning avoidance ; protected by isstat64 */
883
884 if (isstat64 != 0)
885 sb64 = (struct stat64 *)sbptr;
886 else
887 sb = (struct stat *)sbptr;
91447636
A
888
889 VATTR_INIT(&va);
890 VATTR_WANTED(&va, va_fsid);
891 VATTR_WANTED(&va, va_fileid);
892 VATTR_WANTED(&va, va_mode);
893 VATTR_WANTED(&va, va_type);
894 VATTR_WANTED(&va, va_nlink);
895 VATTR_WANTED(&va, va_uid);
896 VATTR_WANTED(&va, va_gid);
897 VATTR_WANTED(&va, va_rdev);
898 VATTR_WANTED(&va, va_data_size);
899 VATTR_WANTED(&va, va_access_time);
900 VATTR_WANTED(&va, va_modify_time);
901 VATTR_WANTED(&va, va_change_time);
2d21ac55 902 VATTR_WANTED(&va, va_create_time);
91447636
A
903 VATTR_WANTED(&va, va_flags);
904 VATTR_WANTED(&va, va_gen);
905 VATTR_WANTED(&va, va_iosize);
906 /* lower layers will synthesise va_total_alloc from va_data_size if required */
907 VATTR_WANTED(&va, va_total_alloc);
908 if (xsec != NULL) {
909 VATTR_WANTED(&va, va_uuuid);
910 VATTR_WANTED(&va, va_guuid);
911 VATTR_WANTED(&va, va_acl);
912 }
913 error = vnode_getattr(vp, &va, ctx);
1c79356b 914 if (error)
91447636 915 goto out;
1c79356b
A
916 /*
917 * Copy from vattr table
918 */
2d21ac55
A
919 if (isstat64 != 0) {
920 sb64->st_dev = va.va_fsid;
921 sb64->st_ino = (ino64_t)va.va_fileid;
922
923 } else {
924 sb->st_dev = va.va_fsid;
925 sb->st_ino = (ino_t)va.va_fileid;
926 }
91447636 927 mode = va.va_mode;
1c79356b
A
928 switch (vp->v_type) {
929 case VREG:
930 mode |= S_IFREG;
931 break;
932 case VDIR:
933 mode |= S_IFDIR;
934 break;
935 case VBLK:
936 mode |= S_IFBLK;
937 break;
938 case VCHR:
939 mode |= S_IFCHR;
940 break;
941 case VLNK:
942 mode |= S_IFLNK;
943 break;
944 case VSOCK:
945 mode |= S_IFSOCK;
946 break;
947 case VFIFO:
948 mode |= S_IFIFO;
949 break;
950 default:
91447636
A
951 error = EBADF;
952 goto out;
1c79356b 953 };
2d21ac55
A
954 if (isstat64 != 0) {
955 sb64->st_mode = mode;
956 sb64->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? (u_int16_t)va.va_nlink : 1;
957 sb64->st_uid = va.va_uid;
958 sb64->st_gid = va.va_gid;
959 sb64->st_rdev = va.va_rdev;
960 sb64->st_size = va.va_data_size;
961 sb64->st_atimespec = va.va_access_time;
962 sb64->st_mtimespec = va.va_modify_time;
963 sb64->st_ctimespec = va.va_change_time;
964 sb64->st_birthtimespec =
965 VATTR_IS_SUPPORTED(&va, va_create_time) ? va.va_create_time : va.va_change_time;
966 sb64->st_blksize = va.va_iosize;
967 sb64->st_flags = va.va_flags;
968 sb64->st_blocks = roundup(va.va_total_alloc, 512) / 512;
969 } else {
970 sb->st_mode = mode;
971 sb->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? (u_int16_t)va.va_nlink : 1;
972 sb->st_uid = va.va_uid;
973 sb->st_gid = va.va_gid;
974 sb->st_rdev = va.va_rdev;
975 sb->st_size = va.va_data_size;
976 sb->st_atimespec = va.va_access_time;
977 sb->st_mtimespec = va.va_modify_time;
978 sb->st_ctimespec = va.va_change_time;
979 sb->st_blksize = va.va_iosize;
980 sb->st_flags = va.va_flags;
981 sb->st_blocks = roundup(va.va_total_alloc, 512) / 512;
982 }
91447636
A
983
984 /* if we're interested in exended security data and we got an ACL */
985 if (xsec != NULL) {
986 if (!VATTR_IS_SUPPORTED(&va, va_acl) &&
987 !VATTR_IS_SUPPORTED(&va, va_uuuid) &&
988 !VATTR_IS_SUPPORTED(&va, va_guuid)) {
989 *xsec = KAUTH_FILESEC_NONE;
990 } else {
991
992 if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) {
993 fsec = kauth_filesec_alloc(va.va_acl->acl_entrycount);
994 } else {
995 fsec = kauth_filesec_alloc(0);
996 }
997 if (fsec == NULL) {
998 error = ENOMEM;
999 goto out;
1000 }
1001 fsec->fsec_magic = KAUTH_FILESEC_MAGIC;
1002 if (VATTR_IS_SUPPORTED(&va, va_uuuid)) {
1003 fsec->fsec_owner = va.va_uuuid;
1004 } else {
1005 fsec->fsec_owner = kauth_null_guid;
1006 }
1007 if (VATTR_IS_SUPPORTED(&va, va_guuid)) {
1008 fsec->fsec_group = va.va_guuid;
1009 } else {
1010 fsec->fsec_group = kauth_null_guid;
1011 }
1012 if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) {
1013 bcopy(va.va_acl, &(fsec->fsec_acl), KAUTH_ACL_COPYSIZE(va.va_acl));
1014 } else {
1015 fsec->fsec_acl.acl_entrycount = KAUTH_FILESEC_NOACL;
1016 }
1017 *xsec = fsec;
1018 }
1019 }
1020
1c79356b 1021 /* Do not give the generation number out to unpriviledged users */
2d21ac55
A
1022 if (va.va_gen && !vfs_context_issuser(ctx)) {
1023 if (isstat64 != 0)
1024 sb64->st_gen = 0;
1025 else
1026 sb->st_gen = 0;
1027 } else {
1028 if (isstat64 != 0)
1029 sb64->st_gen = va.va_gen;
1030 else
1031 sb->st_gen = va.va_gen;
1032 }
91447636
A
1033
1034 error = 0;
1035out:
1036 if (VATTR_IS_SUPPORTED(&va, va_acl) && va.va_acl != NULL)
1037 kauth_acl_free(va.va_acl);
1038 return (error);
1039}
1040
1041int
2d21ac55 1042vn_stat(struct vnode *vp, void *sb, kauth_filesec_t *xsec, int isstat64, vfs_context_t ctx)
91447636
A
1043{
1044 int error;
1045
2d21ac55
A
1046#if CONFIG_MACF
1047 error = mac_vnode_check_stat(ctx, NOCRED, vp);
1048 if (error)
1049 return (error);
1050#endif
1051
91447636
A
1052 /* authorize */
1053 if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_ATTRIBUTES | KAUTH_VNODE_READ_SECURITY, ctx)) != 0)
1054 return(error);
1055
1056 /* actual stat */
2d21ac55 1057 return(vn_stat_noauth(vp, sb, xsec, isstat64, ctx));
1c79356b
A
1058}
1059
91447636 1060
1c79356b
A
1061/*
1062 * File table vnode ioctl routine.
1063 */
9bccf70c 1064static int
2d21ac55 1065vn_ioctl(struct fileproc *fp, u_long com, caddr_t data, vfs_context_t ctx)
1c79356b 1066{
2d21ac55 1067 struct vnode *vp = ((struct vnode *)fp->f_fglob->fg_data);
91447636 1068 off_t file_size;
1c79356b 1069 int error;
fa4905b1 1070 struct vnode *ttyvp;
91447636 1071 int funnel_state;
2d21ac55 1072 struct session * sessp;
9bccf70c 1073
91447636
A
1074 if ( (error = vnode_getwithref(vp)) ) {
1075 return(error);
1076 }
91447636 1077
2d21ac55
A
1078#if CONFIG_MACF
1079 error = mac_vnode_check_ioctl(ctx, vp, com);
1080 if (error)
1081 goto out;
1082#endif
1c79356b 1083
2d21ac55 1084 switch (vp->v_type) {
1c79356b
A
1085 case VREG:
1086 case VDIR:
1087 if (com == FIONREAD) {
2d21ac55 1088 if ((error = vnode_size(vp, &file_size, ctx)) != 0)
91447636
A
1089 goto out;
1090 *(int *)data = file_size - fp->f_fglob->fg_offset;
1091 goto out;
1092 }
1093 if (com == FIONBIO || com == FIOASYNC) { /* XXX */
1094 goto out;
1c79356b 1095 }
1c79356b
A
1096 /* fall into ... */
1097
1098 default:
91447636
A
1099 error = ENOTTY;
1100 goto out;
1c79356b
A
1101
1102 case VFIFO:
1103 case VCHR:
1104 case VBLK:
9bccf70c 1105
91447636
A
1106 /* Should not be able to set block size from user space */
1107 if (com == DKIOCSETBLOCKSIZE) {
1108 error = EPERM;
1109 goto out;
1110 }
1111
1112 if (com == FIODTYPE) {
1113 if (vp->v_type == VBLK) {
1114 if (major(vp->v_rdev) >= nblkdev) {
1115 error = ENXIO;
1116 goto out;
1117 }
1118 *(int *)data = bdevsw[major(vp->v_rdev)].d_type;
1119
1120 } else if (vp->v_type == VCHR) {
1121 if (major(vp->v_rdev) >= nchrdev) {
1122 error = ENXIO;
1123 goto out;
1124 }
1125 *(int *)data = cdevsw[major(vp->v_rdev)].d_type;
1126 } else {
1127 error = ENOTTY;
1128 goto out;
1129 }
1130 goto out;
1131 }
2d21ac55 1132 error = VNOP_IOCTL(vp, com, data, fp->f_fglob->fg_flag, ctx);
91447636
A
1133
1134 if (error == 0 && com == TIOCSCTTY) {
1135 vnode_ref(vp);
1136
1137 funnel_state = thread_funnel_set(kernel_flock, TRUE);
2d21ac55
A
1138 sessp = proc_session(vfs_context_proc(ctx));
1139
1140 session_lock(sessp);
1141 ttyvp = sessp->s_ttyvp;
1142 sessp->s_ttyvp = vp;
1143 sessp->s_ttyvid = vnode_vid(vp);
1144 session_unlock(sessp);
1145 session_rele(sessp);
91447636
A
1146 thread_funnel_set(kernel_flock, funnel_state);
1147
1148 if (ttyvp)
1149 vnode_rele(ttyvp);
1150 }
1c79356b 1151 }
91447636
A
1152out:
1153 (void)vnode_put(vp);
1154 return(error);
1c79356b
A
1155}
1156
1157/*
1158 * File table vnode select routine.
1159 */
9bccf70c 1160static int
2d21ac55 1161vn_select(struct fileproc *fp, int which, void *wql, __unused vfs_context_t ctx)
1c79356b 1162{
91447636
A
1163 int error;
1164 struct vnode * vp = (struct vnode *)fp->f_fglob->fg_data;
1165 struct vfs_context context;
1166
1167 if ( (error = vnode_getwithref(vp)) == 0 ) {
2d21ac55 1168 context.vc_thread = current_thread();
91447636
A
1169 context.vc_ucred = fp->f_fglob->fg_cred;
1170
2d21ac55
A
1171#if CONFIG_MACF
1172 /*
1173 * XXX We should use a per thread credential here; minimally,
1174 * XXX the process credential should have a persistent
1175 * XXX reference on it before being passed in here.
1176 */
1177 error = mac_vnode_check_select(ctx, vp, which);
1178 if (error == 0)
1179#endif
1180 error = VNOP_SELECT(vp, which, fp->f_fglob->fg_flag, wql, ctx);
1c79356b 1181
91447636
A
1182 (void)vnode_put(vp);
1183 }
1184 return(error);
1185
1c79356b
A
1186}
1187
1188/*
1189 * Check that the vnode is still valid, and if so
1190 * acquire requested lock.
1191 */
1192int
91447636 1193vn_lock(__unused vnode_t vp, __unused int flags, __unused proc_t p)
1c79356b 1194{
91447636 1195 return (0);
1c79356b
A
1196}
1197
1198/*
1199 * File table vnode close routine.
1200 */
9bccf70c 1201static int
2d21ac55 1202vn_closefile(struct fileglob *fg, vfs_context_t ctx)
1c79356b 1203{
91447636
A
1204 struct vnode *vp = (struct vnode *)fg->fg_data;
1205 int error;
2d21ac55 1206 struct flock lf;
91447636
A
1207
1208 if ( (error = vnode_getwithref(vp)) == 0 ) {
2d21ac55
A
1209
1210 if ((fg->fg_flag & FHASLOCK) && fg->fg_type == DTYPE_VNODE) {
1211 lf.l_whence = SEEK_SET;
1212 lf.l_start = 0;
1213 lf.l_len = 0;
1214 lf.l_type = F_UNLCK;
1215
1216 (void)VNOP_ADVLOCK(vp, (caddr_t)fg, F_UNLCK, &lf, F_FLOCK, ctx);
1217 }
1218 error = vn_close(vp, fg->fg_flag, ctx);
91447636
A
1219
1220 (void)vnode_put(vp);
1221 }
1222 return(error);
1223}
1224
2d21ac55
A
1225/*
1226 * Returns: 0 Success
1227 * VNOP_PATHCONF:???
1228 */
91447636
A
1229int
1230vn_pathconf(vnode_t vp, int name, register_t *retval, vfs_context_t ctx)
1231{
1232 int error = 0;
1233
1234 switch(name) {
1235 case _PC_EXTENDED_SECURITY_NP:
2d21ac55 1236 *retval = vfs_extendedsecurity(vnode_mount(vp)) ? 1 : 0;
91447636
A
1237 break;
1238 case _PC_AUTH_OPAQUE_NP:
1239 *retval = vfs_authopaque(vnode_mount(vp));
1240 break;
2d21ac55
A
1241 case _PC_2_SYMLINKS:
1242 *retval = 1; /* XXX NOTSUP on MSDOS, etc. */
1243 break;
1244 case _PC_ALLOC_SIZE_MIN:
1245 *retval = 1; /* XXX lie: 1 byte */
1246 break;
1247 case _PC_ASYNC_IO: /* unistd.h: _POSIX_ASYNCHRONUS_IO */
1248 *retval = 1; /* [AIO] option is supported */
1249 break;
1250 case _PC_PRIO_IO: /* unistd.h: _POSIX_PRIORITIZED_IO */
1251 *retval = 0; /* [PIO] option is not supported */
1252 break;
1253 case _PC_REC_INCR_XFER_SIZE:
1254 *retval = 4096; /* XXX go from MIN to MAX 4K at a time */
1255 break;
1256 case _PC_REC_MIN_XFER_SIZE:
1257 *retval = 4096; /* XXX recommend 4K minimum reads/writes */
1258 break;
1259 case _PC_REC_MAX_XFER_SIZE:
1260 *retval = 65536; /* XXX recommend 64K maximum reads/writes */
1261 break;
1262 case _PC_REC_XFER_ALIGN:
1263 *retval = 4096; /* XXX recommend page aligned buffers */
1264 break;
1265 case _PC_SYMLINK_MAX:
1266 *retval = 255; /* Minimum acceptable POSIX value */
1267 break;
1268 case _PC_SYNC_IO: /* unistd.h: _POSIX_SYNCHRONIZED_IO */
1269 *retval = 0; /* [SIO] option is not supported */
1270 break;
91447636
A
1271 default:
1272 error = VNOP_PATHCONF(vp, name, retval, ctx);
1273 break;
1274 }
1c79356b 1275
91447636 1276 return (error);
1c79356b 1277}
55e303ae
A
1278
1279static int
2d21ac55 1280vn_kqfilt_add(struct fileproc *fp, struct knote *kn, vfs_context_t ctx)
55e303ae 1281{
91447636 1282 struct vnode *vp = (struct vnode *)fp->f_fglob->fg_data;
55e303ae 1283 int error;
91447636 1284 int funnel_state;
55e303ae 1285
91447636 1286 if ( (error = vnode_getwithref(vp)) == 0 ) {
2d21ac55
A
1287
1288#if CONFIG_MACF
1289 error = mac_vnode_check_kqfilter(ctx, fp->f_fglob->fg_cred, kn, vp);
1290 if (error) {
1291 (void)vnode_put(vp);
1292 return (error);
1293 }
1294#endif
91447636
A
1295
1296 funnel_state = thread_funnel_set(kernel_flock, TRUE);
2d21ac55 1297 error = VNOP_KQFILT_ADD(vp, kn, ctx);
91447636
A
1298 thread_funnel_set(kernel_flock, funnel_state);
1299
1300 (void)vnode_put(vp);
1301 }
55e303ae
A
1302 return (error);
1303}
1304
91447636
A
1305#if 0
1306/* No one calls this yet. */
55e303ae 1307static int
2d21ac55 1308vn_kqfilt_remove(vp, ident, ctx)
55e303ae
A
1309 struct vnode *vp;
1310 uintptr_t ident;
2d21ac55 1311 vfs_context_t ctx;
55e303ae
A
1312{
1313 int error;
91447636 1314 int funnel_state;
55e303ae 1315
91447636 1316 if ( (error = vnode_getwithref(vp)) == 0 ) {
91447636
A
1317
1318 funnel_state = thread_funnel_set(kernel_flock, TRUE);
2d21ac55 1319 error = VNOP_KQFILT_REMOVE(vp, ident, ctx);
91447636
A
1320 thread_funnel_set(kernel_flock, funnel_state);
1321
1322 (void)vnode_put(vp);
1323 }
55e303ae
A
1324 return (error);
1325}
91447636 1326#endif