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