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