]>
git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_vnops.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
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.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
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.
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
60 * @(#)vfs_vnops.c 8.14 (Berkeley) 6/15/95
63 * 10-20-1997 Umesh Vaishampayan
64 * Fixed the count to be off_t rather than int.
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/kernel.h>
74 #include <sys/mount.h>
75 #include <sys/namei.h>
76 #include <sys/vnode.h>
77 #include <sys/ioctl.h>
80 #include <mach/kern_return.h>
81 #include <mach/memory_object_control.h>
82 #include <mach/vm_prot.h>
84 struct fileops vnops
=
85 { vn_read
, vn_write
, vn_ioctl
, vn_select
, vn_closefile
};
88 * Common code for vnode open operations.
89 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
91 vn_open(ndp
, fmode
, cmode
)
92 register struct nameidata
*ndp
;
95 register struct vnode
*vp
;
96 register struct proc
*p
= ndp
->ni_cnd
.cn_proc
;
97 register struct ucred
*cred
= p
->p_ucred
;
99 struct vattr
*vap
= &vat
;
102 if (fmode
& O_CREAT
) {
103 ndp
->ni_cnd
.cn_nameiop
= CREATE
;
104 ndp
->ni_cnd
.cn_flags
= LOCKPARENT
| LOCKLEAF
;
105 if ((fmode
& O_EXCL
) == 0)
106 ndp
->ni_cnd
.cn_flags
|= FOLLOW
;
107 if (error
= namei(ndp
))
109 if (ndp
->ni_vp
== NULL
) {
112 vap
->va_mode
= cmode
;
114 vap
->va_vaflags
|= VA_EXCLUSIVE
;
115 VOP_LEASE(ndp
->ni_dvp
, p
, cred
, LEASE_WRITE
);
116 if (error
= VOP_CREATE(ndp
->ni_dvp
, &ndp
->ni_vp
,
122 VOP_ABORTOP(ndp
->ni_dvp
, &ndp
->ni_cnd
);
123 if (ndp
->ni_dvp
== ndp
->ni_vp
)
129 if (fmode
& O_EXCL
) {
136 ndp
->ni_cnd
.cn_nameiop
= LOOKUP
;
137 ndp
->ni_cnd
.cn_flags
= FOLLOW
| LOCKLEAF
;
138 if (error
= namei(ndp
))
142 if (vp
->v_type
== VSOCK
) {
146 if ((fmode
& O_CREAT
) == 0) {
147 if (fmode
& FREAD
&& fmode
& (FWRITE
| O_TRUNC
)) {
149 if (vp
->v_type
== VDIR
)
152 err
= vn_writechk(vp
);
153 if (err
&& !(error
= VOP_ACCESS(vp
, VREAD
, cred
, p
)))
155 if (error
|| (error
= VOP_ACCESS(vp
, VREAD
|VWRITE
,
158 } else if (fmode
& FREAD
) {
159 if ((error
= VOP_ACCESS(vp
, VREAD
, cred
, p
)))
161 } else if (fmode
& (FWRITE
| O_TRUNC
)) {
162 if (vp
->v_type
== VDIR
) {
166 if ((error
= vn_writechk(vp
)) ||
167 (error
= VOP_ACCESS(vp
, VWRITE
, cred
, p
)))
171 if (fmode
& O_TRUNC
) {
172 VOP_UNLOCK(vp
, 0, p
); /* XXX */
173 VOP_LEASE(vp
, p
, cred
, LEASE_WRITE
);
174 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
); /* XXX */
177 if (error
= VOP_SETATTR(vp
, vap
, cred
, p
))
180 if (error
= VOP_OPEN(vp
, fmode
, cred
, p
))
182 if (UBCINFOMISSING(vp
))
183 panic("vn_open: ubc_info_init");
184 if (UBCINFOEXISTS(vp
) && !ubc_hold(vp
))
185 panic("vn_open: hold");
187 if (++vp
->v_writecount
<= 0)
188 panic("vn_open: v_writecount");
196 * Check for write permissions on the specified vnode.
197 * Prototype text segments cannot be written.
200 register struct vnode
*vp
;
204 * If there's shared text associated with
205 * the vnode, try to free it up once. If
206 * we fail, we can't allow writing.
209 /* XXXXX Not sure we need this */
210 if (vp
->v_flag
& VTEXT
)
219 vn_close(vp
, flags
, cred
, p
)
220 register struct vnode
*vp
;
227 vm_offset_t addr
, addr1
;
228 vm_size_t size
, pageoff
;
232 error
= VOP_CLOSE(vp
, flags
, cred
, p
);
239 * Package up an I/O request on a vnode into a uio and do it.
241 vn_rdwr(rw
, vp
, base
, len
, offset
, segflg
, ioflg
, cred
, aresid
, p
)
258 if ((ioflg
& IO_NODELOCKED
) == 0)
259 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
260 auio
.uio_iov
= &aiov
;
262 aiov
.iov_base
= base
;
264 auio
.uio_resid
= len
;
265 auio
.uio_offset
= offset
;
266 auio
.uio_segflg
= segflg
;
271 error
= VOP_READ(vp
, &auio
, ioflg
, cred
);
273 error
= VOP_WRITE(vp
, &auio
, ioflg
, cred
);
276 *aresid
= auio
.uio_resid
;
278 if (auio
.uio_resid
&& error
== 0)
280 if ((ioflg
& IO_NODELOCKED
) == 0)
281 VOP_UNLOCK(vp
, 0, p
);
286 * File table vnode read routine.
288 vn_read(fp
, uio
, cred
)
293 struct vnode
*vp
= (struct vnode
*)fp
->f_data
;
294 struct proc
*p
= uio
->uio_procp
;
298 VOP_LEASE(vp
, p
, cred
, LEASE_READ
);
299 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
300 uio
->uio_offset
= fp
->f_offset
;
301 count
= uio
->uio_resid
;
303 error
= VOP_READ(vp
, uio
, (fp
->f_flag
& FNONBLOCK
) ? IO_NDELAY
: 0, cred
);
305 fp
->f_offset
+= count
- uio
->uio_resid
;
306 VOP_UNLOCK(vp
, 0, p
);
312 * File table vnode write routine.
314 vn_write(fp
, uio
, cred
)
319 struct vnode
*vp
= (struct vnode
*)fp
->f_data
;
320 struct proc
*p
= uio
->uio_procp
;
321 int error
, ioflag
= IO_UNIT
;
324 if (vp
->v_type
== VREG
&& (fp
->f_flag
& O_APPEND
))
326 if (fp
->f_flag
& FNONBLOCK
)
328 if ((fp
->f_flag
& O_FSYNC
) ||
329 (vp
->v_mount
&& (vp
->v_mount
->mnt_flag
& MNT_SYNCHRONOUS
)))
331 VOP_LEASE(vp
, p
, cred
, LEASE_WRITE
);
332 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
333 uio
->uio_offset
= fp
->f_offset
;
334 count
= uio
->uio_resid
;
336 error
= VOP_WRITE(vp
, uio
, ioflag
, cred
);
338 if (ioflag
& IO_APPEND
)
339 fp
->f_offset
= uio
->uio_offset
;
341 fp
->f_offset
+= count
- uio
->uio_resid
;
343 * Set the credentials on successful writes
345 if ((error
== 0) && (vp
->v_tag
== VT_NFS
) && (UBCINFOEXISTS(vp
))) {
349 VOP_UNLOCK(vp
, 0, p
);
354 * File table vnode stat routine.
358 register struct stat
*sb
;
362 register struct vattr
*vap
;
367 error
= VOP_GETATTR(vp
, vap
, p
->p_ucred
, p
);
371 * Copy from vattr table
373 sb
->st_dev
= vap
->va_fsid
;
374 sb
->st_ino
= vap
->va_fileid
;
376 switch (vp
->v_type
) {
402 sb
->st_nlink
= vap
->va_nlink
;
403 sb
->st_uid
= vap
->va_uid
;
404 sb
->st_gid
= vap
->va_gid
;
405 sb
->st_rdev
= vap
->va_rdev
;
406 sb
->st_size
= vap
->va_size
;
407 sb
->st_atimespec
= vap
->va_atime
;
408 sb
->st_mtimespec
= vap
->va_mtime
;
409 sb
->st_ctimespec
= vap
->va_ctime
;
410 sb
->st_blksize
= vap
->va_blocksize
;
411 sb
->st_flags
= vap
->va_flags
;
412 /* Do not give the generation number out to unpriviledged users */
413 if (suser(p
->p_ucred
, &p
->p_acflag
))
416 sb
->st_gen
= vap
->va_gen
;
417 sb
->st_blocks
= vap
->va_bytes
/ S_BLKSIZE
;
422 * File table vnode ioctl routine.
424 vn_ioctl(fp
, com
, data
, p
)
430 register struct vnode
*vp
= ((struct vnode
*)fp
->f_data
);
434 switch (vp
->v_type
) {
438 if (com
== FIONREAD
) {
439 if (error
= VOP_GETATTR(vp
, &vattr
, p
->p_ucred
, p
))
441 *(int *)data
= vattr
.va_size
- fp
->f_offset
;
444 if (com
== FIONBIO
|| com
== FIOASYNC
) /* XXX */
445 return (0); /* XXX */
454 error
= VOP_IOCTL(vp
, com
, data
, fp
->f_flag
, p
->p_ucred
, p
);
455 if (error
== 0 && com
== TIOCSCTTY
) {
456 if (p
->p_session
->s_ttyvp
)
457 vrele(p
->p_session
->s_ttyvp
);
458 p
->p_session
->s_ttyvp
= vp
;
466 * File table vnode select routine.
468 vn_select(fp
, which
, p
)
474 return (VOP_SELECT(((struct vnode
*)fp
->f_data
), which
, fp
->f_flag
,
479 * Check that the vnode is still valid, and if so
480 * acquire requested lock.
483 vn_lock(vp
, flags
, p
)
491 if ((flags
& LK_INTERLOCK
) == 0)
492 simple_lock(&vp
->v_interlock
);
493 if (vp
->v_flag
& VXLOCK
) {
494 while (vp
->v_flag
& VXLOCK
) {
495 vp
->v_flag
|= VXWANT
;
496 simple_unlock(&vp
->v_interlock
);
497 tsleep((caddr_t
)vp
, PINOD
, "vn_lock", 0);
501 error
= VOP_LOCK(vp
, flags
| LK_INTERLOCK
, p
);
505 flags
&= ~LK_INTERLOCK
;
506 } while (flags
& LK_RETRY
);
511 * File table vnode close routine.
518 return (vn_close(((struct vnode
*)fp
->f_data
), fp
->f_flag
,