]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_vnops.c
xnu-792.17.14.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_vnops.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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 *
68 */
69
70 #include <sys/param.h>
71 #include <sys/types.h>
72 #include <sys/systm.h>
73 #include <sys/kernel.h>
74 #include <sys/file_internal.h>
75 #include <sys/stat.h>
76 #include <sys/proc_internal.h>
77 #include <sys/kauth.h>
78 #include <sys/mount_internal.h>
79 #include <sys/namei.h>
80 #include <sys/vnode_internal.h>
81 #include <sys/ioctl.h>
82 #include <sys/tty.h>
83 #include <sys/ubc.h>
84 #include <sys/conf.h>
85 #include <sys/disk.h>
86 #include <sys/fsevents.h>
87 #include <sys/kdebug.h>
88 #include <sys/xattr.h>
89 #include <sys/ubc_internal.h>
90 #include <sys/uio_internal.h>
91
92 #include <vm/vm_kern.h>
93 #include <vm/vm_map.h>
94
95 #include <miscfs/specfs/specdev.h>
96
97
98
99 static int vn_closefile(struct fileglob *fp, struct proc *p);
100 static int vn_ioctl(struct fileproc *fp, u_long com, caddr_t data, struct proc *p);
101 static int vn_read(struct fileproc *fp, struct uio *uio,
102 kauth_cred_t cred, int flags, struct proc *p);
103 static int vn_write(struct fileproc *fp, struct uio *uio,
104 kauth_cred_t cred, int flags, struct proc *p);
105 static int vn_select( struct fileproc *fp, int which, void * wql, struct proc *p);
106 static int vn_kqfilt_add(struct fileproc *fp, struct knote *kn, struct proc *p);
107 #if 0
108 static int vn_kqfilt_remove(struct vnode *vp, uintptr_t ident, struct proc *p);
109 #endif
110
111 struct fileops vnops =
112 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile, vn_kqfilt_add, 0 };
113
114 /*
115 * Common code for vnode open operations.
116 * Check permissions, and call the VNOP_OPEN or VNOP_CREATE routine.
117 *
118 * XXX the profusion of interfaces here is probably a bad thing.
119 */
120 int
121 vn_open(struct nameidata *ndp, int fmode, int cmode)
122 {
123 return(vn_open_modflags(ndp, &fmode, cmode));
124 }
125
126 int
127 vn_open_modflags(struct nameidata *ndp, int *fmodep, int cmode)
128 {
129 struct vnode_attr va;
130
131 VATTR_INIT(&va);
132 VATTR_SET(&va, va_mode, cmode);
133
134 return(vn_open_auth(ndp, fmodep, &va));
135 }
136
137 int
138 vn_open_auth(struct nameidata *ndp, int *fmodep, struct vnode_attr *vap)
139 {
140 struct vnode *vp;
141 struct vnode *dvp;
142 vfs_context_t ctx = ndp->ni_cnd.cn_context;
143 int error;
144 int fmode;
145 kauth_action_t action;
146
147 again:
148 vp = NULL;
149 dvp = NULL;
150 fmode = *fmodep;
151 if (fmode & O_CREAT) {
152 ndp->ni_cnd.cn_nameiop = CREATE;
153 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | AUDITVNPATH1;
154
155 if ((fmode & O_EXCL) == 0)
156 ndp->ni_cnd.cn_flags |= FOLLOW;
157 if ( (error = namei(ndp)) )
158 goto out;
159 dvp = ndp->ni_dvp;
160 vp = ndp->ni_vp;
161
162 /* not found, create */
163 if (vp == NULL) {
164 /* must have attributes for a new file */
165 if (vap == NULL) {
166 error = EINVAL;
167 goto badcreate;
168 }
169
170 /* authorize before creating */
171 if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx)) != 0)
172 goto badcreate;
173
174 VATTR_SET(vap, va_type, VREG);
175 if (fmode & O_EXCL)
176 vap->va_vaflags |= VA_EXCLUSIVE;
177
178 if ((error = vn_create(dvp, &ndp->ni_vp, &ndp->ni_cnd, vap, 0, ctx)) != 0)
179 goto badcreate;
180
181 vp = ndp->ni_vp;
182
183 if (vp) {
184 int update_flags = 0;
185
186 // Make sure the name & parent pointers are hooked up
187 if (vp->v_name == NULL)
188 update_flags |= VNODE_UPDATE_NAME;
189 if (vp->v_parent == NULLVP)
190 update_flags |= VNODE_UPDATE_PARENT;
191
192 if (update_flags)
193 vnode_update_identity(vp, dvp, ndp->ni_cnd.cn_nameptr, ndp->ni_cnd.cn_namelen, ndp->ni_cnd.cn_hash, update_flags);
194
195 if (need_fsevent(FSE_CREATE_FILE, vp)) {
196 add_fsevent(FSE_CREATE_FILE, ctx,
197 FSE_ARG_VNODE, vp,
198 FSE_ARG_DONE);
199 }
200 }
201 /*
202 * nameidone has to happen before we vnode_put(dvp)
203 * and clear the ni_dvp field, since it may need
204 * to release the fs_nodelock on the dvp
205 */
206 badcreate:
207 nameidone(ndp);
208 ndp->ni_dvp = NULL;
209 vnode_put(dvp);
210
211 if (error) {
212 /*
213 * Check for a creation race.
214 */
215 if ((error == EEXIST) && !(fmode & O_EXCL)) {
216 goto again;
217 }
218 goto bad;
219 }
220 fmode &= ~O_TRUNC;
221 } else {
222 nameidone(ndp);
223 ndp->ni_dvp = NULL;
224 vnode_put(dvp);
225
226 if (fmode & O_EXCL) {
227 error = EEXIST;
228 goto bad;
229 }
230 fmode &= ~O_CREAT;
231 }
232 } else {
233 ndp->ni_cnd.cn_nameiop = LOOKUP;
234 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF | AUDITVNPATH1;
235 if ( (error = namei(ndp)) )
236 goto out;
237 vp = ndp->ni_vp;
238 nameidone(ndp);
239 ndp->ni_dvp = NULL;
240 }
241 if (vp->v_type == VSOCK && vp->v_tag != VT_FDESC) {
242 error = EOPNOTSUPP; /* Operation not supported on socket */
243 goto bad;
244 }
245
246 #if DIAGNOSTIC
247 if (UBCINFOMISSING(vp))
248 panic("vn_open: ubc_info_init");
249 #endif /* DIAGNOSTIC */
250
251 /* authorize open of an existing file */
252 if ((fmode & O_CREAT) == 0) {
253
254 /* disallow write operations on directories */
255 if (vnode_isdir(vp) && (fmode & (FWRITE | O_TRUNC))) {
256 error = EISDIR;
257 goto bad;
258 }
259
260 /* compute action to be authorized */
261 action = 0;
262 if (fmode & FREAD)
263 action |= KAUTH_VNODE_READ_DATA;
264 if (fmode & (FWRITE | O_TRUNC))
265 action |= KAUTH_VNODE_WRITE_DATA;
266 if ((error = vnode_authorize(vp, NULL, action, ctx)) != 0)
267 goto bad;
268
269 }
270
271 if ( (error = VNOP_OPEN(vp, fmode, ctx)) ) {
272 goto bad;
273 }
274 if ( (error = vnode_ref_ext(vp, fmode)) )
275 goto bad;
276
277 /* call out to allow 3rd party notification of open.
278 * Ignore result of kauth_authorize_fileop call.
279 */
280 kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_OPEN,
281 (uintptr_t)vp, 0);
282
283 *fmodep = fmode;
284 return (0);
285 bad:
286 ndp->ni_vp = NULL;
287 if (vp) {
288 vnode_put(vp);
289 /*
290 * Check for a race against unlink. We had a vnode
291 * but according to vnode_authorize or VNOP_OPEN it
292 * no longer exists.
293 */
294 if ((error == ENOENT) && (*fmodep & O_CREAT)) {
295 goto again;
296 }
297 }
298 out:
299 return (error);
300 }
301
302 /*
303 * Authorize an action against a vnode. This has been the canonical way to
304 * ensure that the credential/process/etc. referenced by a vfs_context
305 * is granted the rights called out in 'mode' against the vnode 'vp'.
306 *
307 * Unfortunately, the use of VREAD/VWRITE/VEXEC makes it very difficult
308 * to add support for more rights. As such, this interface will be deprecated
309 * and callers will use vnode_authorize instead.
310 */
311 #warning vn_access is deprecated
312 int
313 vn_access(vnode_t vp, int mode, vfs_context_t context)
314 {
315 kauth_action_t action;
316
317 action = 0;
318 if (mode & VREAD)
319 action |= KAUTH_VNODE_READ_DATA;
320 if (mode & VWRITE)
321 action |= KAUTH_VNODE_WRITE_DATA;
322 if (mode & VEXEC)
323 action |= KAUTH_VNODE_EXECUTE;
324
325 return(vnode_authorize(vp, NULL, action, context));
326 }
327
328 /*
329 * Vnode close call
330 */
331 int
332 vn_close(struct vnode *vp, int flags, kauth_cred_t cred, struct proc *p)
333 {
334 struct vfs_context context;
335 int error;
336
337 context.vc_proc = p;
338 context.vc_ucred = cred;
339
340 if (flags & FWASWRITTEN) {
341 if (need_fsevent(FSE_CONTENT_MODIFIED, vp)) {
342 add_fsevent(FSE_CONTENT_MODIFIED, &context,
343 FSE_ARG_VNODE, vp,
344 FSE_ARG_DONE);
345 }
346 }
347
348 error = VNOP_CLOSE(vp, flags, &context);
349 (void)vnode_rele_ext(vp, flags, 0);
350
351 return (error);
352 }
353
354 static int
355 vn_read_swapfile(
356 struct vnode *vp,
357 uio_t uio)
358 {
359 static char *swap_read_zero_page = NULL;
360 int error;
361 off_t swap_count, this_count;
362 off_t file_end, read_end;
363 off_t prev_resid;
364
365 /*
366 * Reading from a swap file will get you all zeroes.
367 */
368 error = 0;
369 swap_count = uio_resid(uio);
370
371 file_end = ubc_getsize(vp);
372 read_end = uio->uio_offset + uio_resid(uio);
373 if (uio->uio_offset >= file_end) {
374 /* uio starts after end of file: nothing to read */
375 swap_count = 0;
376 } else if (read_end > file_end) {
377 /* uio extends beyond end of file: stop before that */
378 swap_count -= (read_end - file_end);
379 }
380
381 while (swap_count > 0) {
382 if (swap_read_zero_page == NULL) {
383 char *my_zero_page;
384 int funnel_state;
385
386 /*
387 * Take kernel funnel so that only one thread
388 * sets up "swap_read_zero_page".
389 */
390 funnel_state = thread_funnel_set(kernel_flock, TRUE);
391
392 if (swap_read_zero_page == NULL) {
393 MALLOC(my_zero_page, char *, PAGE_SIZE,
394 M_TEMP, M_WAITOK);
395 memset(my_zero_page, '?', PAGE_SIZE);
396 /*
397 * Adding a newline character here
398 * and there prevents "less(1)", for
399 * example, from getting too confused
400 * about a file with one really really
401 * long line.
402 */
403 my_zero_page[PAGE_SIZE-1] = '\n';
404 if (swap_read_zero_page == NULL) {
405 swap_read_zero_page = my_zero_page;
406 } else {
407 FREE(my_zero_page, M_TEMP);
408 }
409 } else {
410 /*
411 * Someone else raced us here and won;
412 * just use their page.
413 */
414 }
415 thread_funnel_set(kernel_flock, funnel_state);
416 }
417
418 this_count = swap_count;
419 if (this_count > PAGE_SIZE) {
420 this_count = PAGE_SIZE;
421 }
422
423 prev_resid = uio_resid(uio);
424 error = uiomove((caddr_t) swap_read_zero_page,
425 this_count,
426 uio);
427 if (error) {
428 break;
429 }
430 swap_count -= (prev_resid - uio_resid(uio));
431 }
432
433 return error;
434 }
435 /*
436 * Package up an I/O request on a vnode into a uio and do it.
437 */
438 int
439 vn_rdwr(
440 enum uio_rw rw,
441 struct vnode *vp,
442 caddr_t base,
443 int len,
444 off_t offset,
445 enum uio_seg segflg,
446 int ioflg,
447 kauth_cred_t cred,
448 int *aresid,
449 struct proc *p)
450 {
451 return vn_rdwr_64(rw,
452 vp,
453 (uint64_t)(uintptr_t)base,
454 (int64_t)len,
455 offset,
456 segflg,
457 ioflg,
458 cred,
459 aresid,
460 p);
461 }
462
463
464 int
465 vn_rdwr_64(
466 enum uio_rw rw,
467 struct vnode *vp,
468 uint64_t base,
469 int64_t len,
470 off_t offset,
471 enum uio_seg segflg,
472 int ioflg,
473 kauth_cred_t cred,
474 int *aresid,
475 struct proc *p)
476 {
477 uio_t auio;
478 int spacetype;
479 struct vfs_context context;
480 int error=0;
481 char uio_buf[ UIO_SIZEOF(1) ];
482
483 context.vc_proc = p;
484 context.vc_ucred = cred;
485
486 if (UIO_SEG_IS_USER_SPACE(segflg)) {
487 spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
488 }
489 else {
490 spacetype = UIO_SYSSPACE;
491 }
492 auio = uio_createwithbuffer(1, offset, spacetype, rw,
493 &uio_buf[0], sizeof(uio_buf));
494 uio_addiov(auio, base, len);
495
496 if (rw == UIO_READ) {
497 if (vp->v_flag & VSWAP) {
498 error = vn_read_swapfile(vp, auio);
499 } else {
500 error = VNOP_READ(vp, auio, ioflg, &context);
501 }
502 } else {
503 error = VNOP_WRITE(vp, auio, ioflg, &context);
504 }
505
506 if (aresid)
507 // LP64todo - fix this
508 *aresid = uio_resid(auio);
509 else
510 if (uio_resid(auio) && error == 0)
511 error = EIO;
512 return (error);
513 }
514
515 /*
516 * File table vnode read routine.
517 */
518 static int
519 vn_read(struct fileproc *fp, struct uio *uio, kauth_cred_t cred,
520 int flags, struct proc *p)
521 {
522 struct vnode *vp;
523 int error, ioflag;
524 off_t count;
525 struct vfs_context context;
526
527 context.vc_proc = p;
528 context.vc_ucred = cred;
529
530 vp = (struct vnode *)fp->f_fglob->fg_data;
531 if ( (error = vnode_getwithref(vp)) ) {
532 return(error);
533 }
534 ioflag = 0;
535 if (fp->f_fglob->fg_flag & FNONBLOCK)
536 ioflag |= IO_NDELAY;
537
538 if ((flags & FOF_OFFSET) == 0)
539 uio->uio_offset = fp->f_fglob->fg_offset;
540 count = uio_resid(uio);
541
542 if (vp->v_flag & VSWAP) {
543 /* special case for swap files */
544 error = vn_read_swapfile(vp, uio);
545 } else {
546 error = VNOP_READ(vp, uio, ioflag, &context);
547 }
548 if ((flags & FOF_OFFSET) == 0)
549 fp->f_fglob->fg_offset += count - uio_resid(uio);
550
551 (void)vnode_put(vp);
552 return (error);
553 }
554
555
556 /*
557 * File table vnode write routine.
558 */
559 static int
560 vn_write(struct fileproc *fp, struct uio *uio, kauth_cred_t cred,
561 int flags, struct proc *p)
562 {
563 struct vnode *vp;
564 int error, ioflag;
565 off_t count;
566 struct vfs_context context;
567
568 context.vc_proc = p;
569 context.vc_ucred = cred;
570 count = 0;
571 vp = (struct vnode *)fp->f_fglob->fg_data;
572 if ( (error = vnode_getwithref(vp)) ) {
573 return(error);
574 }
575 ioflag = IO_UNIT;
576 if (vp->v_type == VREG && (fp->f_fglob->fg_flag & O_APPEND))
577 ioflag |= IO_APPEND;
578 if (fp->f_fglob->fg_flag & FNONBLOCK)
579 ioflag |= IO_NDELAY;
580 if ((fp->f_fglob->fg_flag & O_FSYNC) ||
581 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
582 ioflag |= IO_SYNC;
583
584 if ((flags & FOF_OFFSET) == 0) {
585 uio->uio_offset = fp->f_fglob->fg_offset;
586 count = uio_resid(uio);
587 }
588 if (p && (vp->v_type == VREG) &&
589 (((uio->uio_offset + uio_uio_resid(uio)) > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) ||
590 (uio_uio_resid(uio) > (p->p_rlimit[RLIMIT_FSIZE].rlim_cur - uio->uio_offset)))) {
591 psignal(p, SIGXFSZ);
592 vnode_put(vp);
593 return (EFBIG);
594 }
595
596 error = VNOP_WRITE(vp, uio, ioflag, &context);
597
598 if ((flags & FOF_OFFSET) == 0) {
599 if (ioflag & IO_APPEND)
600 fp->f_fglob->fg_offset = uio->uio_offset;
601 else
602 fp->f_fglob->fg_offset += count - uio_resid(uio);
603 }
604
605 /*
606 * Set the credentials on successful writes
607 */
608 if ((error == 0) && (vp->v_tag == VT_NFS) && (UBCINFOEXISTS(vp))) {
609 /*
610 * When called from aio subsystem, we only have the proc from
611 * which to get the credential, at this point, so use that
612 * instead. This means aio functions are incompatible with
613 * per-thread credentials (aio operations are proxied). We
614 * can't easily correct the aio vs. settid race in this case
615 * anyway, so we disallow it.
616 */
617 if ((flags & FOF_PCRED) == 0) {
618 ubc_setthreadcred(vp, p, current_thread());
619 } else {
620 ubc_setcred(vp, p);
621 }
622 }
623 (void)vnode_put(vp);
624 return (error);
625 }
626
627 /*
628 * File table vnode stat routine.
629 */
630 int
631 vn_stat_noauth(struct vnode *vp, struct stat *sb, kauth_filesec_t *xsec, vfs_context_t ctx)
632 {
633 struct vnode_attr va;
634 int error;
635 u_short mode;
636 kauth_filesec_t fsec;
637
638 VATTR_INIT(&va);
639 VATTR_WANTED(&va, va_fsid);
640 VATTR_WANTED(&va, va_fileid);
641 VATTR_WANTED(&va, va_mode);
642 VATTR_WANTED(&va, va_type);
643 VATTR_WANTED(&va, va_nlink);
644 VATTR_WANTED(&va, va_uid);
645 VATTR_WANTED(&va, va_gid);
646 VATTR_WANTED(&va, va_rdev);
647 VATTR_WANTED(&va, va_data_size);
648 VATTR_WANTED(&va, va_access_time);
649 VATTR_WANTED(&va, va_modify_time);
650 VATTR_WANTED(&va, va_change_time);
651 VATTR_WANTED(&va, va_flags);
652 VATTR_WANTED(&va, va_gen);
653 VATTR_WANTED(&va, va_iosize);
654 /* lower layers will synthesise va_total_alloc from va_data_size if required */
655 VATTR_WANTED(&va, va_total_alloc);
656 if (xsec != NULL) {
657 VATTR_WANTED(&va, va_uuuid);
658 VATTR_WANTED(&va, va_guuid);
659 VATTR_WANTED(&va, va_acl);
660 }
661 error = vnode_getattr(vp, &va, ctx);
662 if (error)
663 goto out;
664 /*
665 * Copy from vattr table
666 */
667 sb->st_dev = va.va_fsid;
668 sb->st_ino = (ino_t)va.va_fileid;
669 mode = va.va_mode;
670 switch (vp->v_type) {
671 case VREG:
672 mode |= S_IFREG;
673 break;
674 case VDIR:
675 mode |= S_IFDIR;
676 break;
677 case VBLK:
678 mode |= S_IFBLK;
679 break;
680 case VCHR:
681 mode |= S_IFCHR;
682 break;
683 case VLNK:
684 mode |= S_IFLNK;
685 break;
686 case VSOCK:
687 mode |= S_IFSOCK;
688 break;
689 case VFIFO:
690 mode |= S_IFIFO;
691 break;
692 default:
693 error = EBADF;
694 goto out;
695 };
696 sb->st_mode = mode;
697 sb->st_nlink = VATTR_IS_SUPPORTED(&va, va_nlink) ? (u_int16_t)va.va_nlink : 1;
698 sb->st_uid = va.va_uid;
699 sb->st_gid = va.va_gid;
700 sb->st_rdev = va.va_rdev;
701 sb->st_size = va.va_data_size;
702 sb->st_atimespec = va.va_access_time;
703 sb->st_mtimespec = va.va_modify_time;
704 sb->st_ctimespec = va.va_change_time;
705 sb->st_blksize = va.va_iosize;
706 sb->st_flags = va.va_flags;
707 sb->st_blocks = roundup(va.va_total_alloc, 512) / 512;
708
709 /* if we're interested in exended security data and we got an ACL */
710 if (xsec != NULL) {
711 if (!VATTR_IS_SUPPORTED(&va, va_acl) &&
712 !VATTR_IS_SUPPORTED(&va, va_uuuid) &&
713 !VATTR_IS_SUPPORTED(&va, va_guuid)) {
714 *xsec = KAUTH_FILESEC_NONE;
715 } else {
716
717 if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) {
718 fsec = kauth_filesec_alloc(va.va_acl->acl_entrycount);
719 } else {
720 fsec = kauth_filesec_alloc(0);
721 }
722 if (fsec == NULL) {
723 error = ENOMEM;
724 goto out;
725 }
726 fsec->fsec_magic = KAUTH_FILESEC_MAGIC;
727 if (VATTR_IS_SUPPORTED(&va, va_uuuid)) {
728 fsec->fsec_owner = va.va_uuuid;
729 } else {
730 fsec->fsec_owner = kauth_null_guid;
731 }
732 if (VATTR_IS_SUPPORTED(&va, va_guuid)) {
733 fsec->fsec_group = va.va_guuid;
734 } else {
735 fsec->fsec_group = kauth_null_guid;
736 }
737 if (VATTR_IS_SUPPORTED(&va, va_acl) && (va.va_acl != NULL)) {
738 bcopy(va.va_acl, &(fsec->fsec_acl), KAUTH_ACL_COPYSIZE(va.va_acl));
739 } else {
740 fsec->fsec_acl.acl_entrycount = KAUTH_FILESEC_NOACL;
741 }
742 *xsec = fsec;
743 }
744 }
745
746 /* Do not give the generation number out to unpriviledged users */
747 if (va.va_gen && !vfs_context_issuser(ctx))
748 sb->st_gen = 0;
749 else
750 sb->st_gen = va.va_gen;
751
752 error = 0;
753 out:
754 if (VATTR_IS_SUPPORTED(&va, va_acl) && va.va_acl != NULL)
755 kauth_acl_free(va.va_acl);
756 return (error);
757 }
758
759 int
760 vn_stat(struct vnode *vp, struct stat *sb, kauth_filesec_t *xsec, vfs_context_t ctx)
761 {
762 int error;
763
764 /* authorize */
765 if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_ATTRIBUTES | KAUTH_VNODE_READ_SECURITY, ctx)) != 0)
766 return(error);
767
768 /* actual stat */
769 return(vn_stat_noauth(vp, sb, xsec, ctx));
770 }
771
772
773 /*
774 * File table vnode ioctl routine.
775 */
776 static int
777 vn_ioctl(fp, com, data, p)
778 struct fileproc *fp;
779 u_long com;
780 caddr_t data;
781 struct proc *p;
782 {
783 register struct vnode *vp = ((struct vnode *)fp->f_fglob->fg_data);
784 struct vfs_context context;
785 off_t file_size;
786 int error;
787 struct vnode *ttyvp;
788 int funnel_state;
789
790 if ( (error = vnode_getwithref(vp)) ) {
791 return(error);
792 }
793 context.vc_proc = p;
794 context.vc_ucred = p->p_ucred; /* XXX kauth_cred_get() ??? */
795
796 switch (vp->v_type) {
797
798 case VREG:
799 case VDIR:
800 if (com == FIONREAD) {
801 if ((error = vnode_size(vp, &file_size, &context)) != 0)
802 goto out;
803 *(int *)data = file_size - fp->f_fglob->fg_offset;
804 goto out;
805 }
806 if (com == FIONBIO || com == FIOASYNC) { /* XXX */
807 goto out;
808 }
809 /* fall into ... */
810
811 default:
812 error = ENOTTY;
813 goto out;
814
815 case VFIFO:
816 case VCHR:
817 case VBLK:
818
819 /* Should not be able to set block size from user space */
820 if (com == DKIOCSETBLOCKSIZE) {
821 error = EPERM;
822 goto out;
823 }
824
825 if (com == FIODTYPE) {
826 if (vp->v_type == VBLK) {
827 if (major(vp->v_rdev) >= nblkdev) {
828 error = ENXIO;
829 goto out;
830 }
831 *(int *)data = bdevsw[major(vp->v_rdev)].d_type;
832
833 } else if (vp->v_type == VCHR) {
834 if (major(vp->v_rdev) >= nchrdev) {
835 error = ENXIO;
836 goto out;
837 }
838 *(int *)data = cdevsw[major(vp->v_rdev)].d_type;
839 } else {
840 error = ENOTTY;
841 goto out;
842 }
843 goto out;
844 }
845 error = VNOP_IOCTL(vp, com, data, fp->f_fglob->fg_flag, &context);
846
847 if (error == 0 && com == TIOCSCTTY) {
848 vnode_ref(vp);
849
850 funnel_state = thread_funnel_set(kernel_flock, TRUE);
851 ttyvp = p->p_session->s_ttyvp;
852 p->p_session->s_ttyvp = vp;
853 thread_funnel_set(kernel_flock, funnel_state);
854
855 if (ttyvp)
856 vnode_rele(ttyvp);
857 }
858 }
859 out:
860 (void)vnode_put(vp);
861 return(error);
862 }
863
864 /*
865 * File table vnode select routine.
866 */
867 static int
868 vn_select(fp, which, wql, p)
869 struct fileproc *fp;
870 int which;
871 void * wql;
872 struct proc *p;
873 {
874 int error;
875 struct vnode * vp = (struct vnode *)fp->f_fglob->fg_data;
876 struct vfs_context context;
877
878 if ( (error = vnode_getwithref(vp)) == 0 ) {
879 context.vc_proc = p;
880 context.vc_ucred = fp->f_fglob->fg_cred;
881
882 error = VNOP_SELECT(vp, which, fp->f_fglob->fg_flag, wql, &context);
883
884 (void)vnode_put(vp);
885 }
886 return(error);
887
888 }
889
890 /*
891 * Check that the vnode is still valid, and if so
892 * acquire requested lock.
893 */
894 int
895 vn_lock(__unused vnode_t vp, __unused int flags, __unused proc_t p)
896 {
897 return (0);
898 }
899
900 /*
901 * File table vnode close routine.
902 */
903 static int
904 vn_closefile(fg, p)
905 struct fileglob *fg;
906 struct proc *p;
907 {
908 struct vnode *vp = (struct vnode *)fg->fg_data;
909 int error;
910
911 if ( (error = vnode_getwithref(vp)) == 0 ) {
912 error = vn_close(vp, fg->fg_flag, fg->fg_cred, p);
913
914 (void)vnode_put(vp);
915 }
916 return(error);
917 }
918
919 int
920 vn_pathconf(vnode_t vp, int name, register_t *retval, vfs_context_t ctx)
921 {
922 int error = 0;
923
924 switch(name) {
925 case _PC_EXTENDED_SECURITY_NP:
926 *retval = vfs_extendedsecurity(vnode_mount(vp));
927 break;
928 case _PC_AUTH_OPAQUE_NP:
929 *retval = vfs_authopaque(vnode_mount(vp));
930 break;
931 default:
932 error = VNOP_PATHCONF(vp, name, retval, ctx);
933 break;
934 }
935
936 return (error);
937 }
938
939 static int
940 vn_kqfilt_add(fp, kn, p)
941 struct fileproc *fp;
942 struct knote *kn;
943 struct proc *p;
944 {
945 struct vnode *vp = (struct vnode *)fp->f_fglob->fg_data;
946 struct vfs_context context;
947 int error;
948 int funnel_state;
949
950 if ( (error = vnode_getwithref(vp)) == 0 ) {
951 context.vc_proc = p;
952 context.vc_ucred = p->p_ucred; /* XXX kauth_cred_get() ??? */
953
954 funnel_state = thread_funnel_set(kernel_flock, TRUE);
955 error = VNOP_KQFILT_ADD(vp, kn, &context);
956 thread_funnel_set(kernel_flock, funnel_state);
957
958 (void)vnode_put(vp);
959 }
960 return (error);
961 }
962
963 #if 0
964 /* No one calls this yet. */
965 static int
966 vn_kqfilt_remove(vp, ident, p)
967 struct vnode *vp;
968 uintptr_t ident;
969 struct proc *p;
970 {
971 struct vfs_context context;
972 int error;
973 int funnel_state;
974
975 if ( (error = vnode_getwithref(vp)) == 0 ) {
976 context.vc_proc = p;
977 context.vc_ucred = p->p_ucred; /* XXX kauth_cred_get() ??? */
978
979 funnel_state = thread_funnel_set(kernel_flock, TRUE);
980 error = VNOP_KQFILT_REMOVE(vp, ident, &context);
981 thread_funnel_set(kernel_flock, funnel_state);
982
983 (void)vnode_put(vp);
984 }
985 return (error);
986 }
987 #endif