]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_vnops.c
a16dfb16759b4278374f3a61f0d9fd9b486acd57
[apple/xnu.git] / bsd / vfs / vfs_vnops.c
1 /*
2 * Copyright (c) 2000-2001 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/systm.h>
66 #include <sys/kernel.h>
67 #include <sys/file.h>
68 #include <sys/stat.h>
69 #include <sys/buf.h>
70 #include <sys/proc.h>
71 #include <sys/mount.h>
72 #include <sys/namei.h>
73 #include <sys/vnode.h>
74 #include <sys/ioctl.h>
75 #include <sys/tty.h>
76 #include <sys/ubc.h>
77
78 struct fileops vnops =
79 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
80
81 /*
82 * Common code for vnode open operations.
83 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
84 */
85 vn_open(ndp, fmode, cmode)
86 register struct nameidata *ndp;
87 int fmode, cmode;
88 {
89 register struct vnode *vp;
90 register struct proc *p = ndp->ni_cnd.cn_proc;
91 register struct ucred *cred = p->p_ucred;
92 struct vattr vat;
93 struct vattr *vap = &vat;
94 int error;
95
96 if (fmode & O_CREAT) {
97 ndp->ni_cnd.cn_nameiop = CREATE;
98 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
99 if ((fmode & O_EXCL) == 0)
100 ndp->ni_cnd.cn_flags |= FOLLOW;
101 if (error = namei(ndp))
102 return (error);
103 if (ndp->ni_vp == NULL) {
104 VATTR_NULL(vap);
105 vap->va_type = VREG;
106 vap->va_mode = cmode;
107 if (fmode & O_EXCL)
108 vap->va_vaflags |= VA_EXCLUSIVE;
109 VOP_LEASE(ndp->ni_dvp, p, cred, LEASE_WRITE);
110 if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
111 &ndp->ni_cnd, vap))
112 return (error);
113 fmode &= ~O_TRUNC;
114 vp = ndp->ni_vp;
115 } else {
116 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
117 if (ndp->ni_dvp == ndp->ni_vp)
118 vrele(ndp->ni_dvp);
119 else
120 vput(ndp->ni_dvp);
121 ndp->ni_dvp = NULL;
122 vp = ndp->ni_vp;
123 if (fmode & O_EXCL) {
124 error = EEXIST;
125 goto bad;
126 }
127 fmode &= ~O_CREAT;
128 }
129 } else {
130 ndp->ni_cnd.cn_nameiop = LOOKUP;
131 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
132 if (error = namei(ndp))
133 return (error);
134 vp = ndp->ni_vp;
135 }
136 if (vp->v_type == VSOCK) {
137 error = EOPNOTSUPP;
138 goto bad;
139 }
140 if ((fmode & O_CREAT) == 0) {
141 if (fmode & FREAD && fmode & (FWRITE | O_TRUNC)) {
142 int err = 0;
143 if (vp->v_type == VDIR)
144 err = EISDIR;
145 else
146 err = vn_writechk(vp);
147 if (err && !(error = VOP_ACCESS(vp, VREAD, cred, p)))
148 error = err;
149 if (error || (error = VOP_ACCESS(vp, VREAD|VWRITE,
150 cred, p)))
151 goto bad;
152 } else if (fmode & FREAD) {
153 if ((error = VOP_ACCESS(vp, VREAD, cred, p)))
154 goto bad;
155 } else if (fmode & (FWRITE | O_TRUNC)) {
156 if (vp->v_type == VDIR) {
157 error = EISDIR;
158 goto bad;
159 }
160 if ((error = vn_writechk(vp)) ||
161 (error = VOP_ACCESS(vp, VWRITE, cred, p)))
162 goto bad;
163 }
164 }
165 if (fmode & O_TRUNC) {
166 VOP_UNLOCK(vp, 0, p); /* XXX */
167 VOP_LEASE(vp, p, cred, LEASE_WRITE);
168 (void)vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */
169 VATTR_NULL(vap);
170 vap->va_size = 0;
171 if (error = VOP_SETATTR(vp, vap, cred, p))
172 goto bad;
173 }
174
175 #if DIAGNOSTIC
176 if (UBCINFOMISSING(vp))
177 panic("vn_open: ubc_info_init");
178 #endif /* DIAGNOSTIC */
179
180 if (UBCINFOEXISTS(vp) && !ubc_hold(vp)) {
181 error = ENOENT;
182 goto bad;
183 }
184
185 if (error = VOP_OPEN(vp, fmode, cred, p)) {
186 ubc_rele(vp);
187 goto bad;
188 }
189
190 if (fmode & FWRITE)
191 if (++vp->v_writecount <= 0)
192 panic("vn_open: v_writecount");
193 return (0);
194 bad:
195 vput(vp);
196 return (error);
197 }
198
199 /*
200 * Check for write permissions on the specified vnode.
201 * Prototype text segments cannot be written.
202 */
203 vn_writechk(vp)
204 register struct vnode *vp;
205 {
206
207 /*
208 * If there's shared text associated with
209 * the vnode, try to free it up once. If
210 * we fail, we can't allow writing.
211 */
212 #if 0
213 /* XXXXX Not sure we need this */
214 if (vp->v_flag & VTEXT)
215 return (ETXTBSY);
216 #endif /* 0 */
217 return (0);
218 }
219
220 /*
221 * Vnode close call
222 */
223 vn_close(vp, flags, cred, p)
224 register struct vnode *vp;
225 int flags;
226 struct ucred *cred;
227 struct proc *p;
228 {
229 int error;
230
231 if (flags & FWRITE)
232 vp->v_writecount--;
233 error = VOP_CLOSE(vp, flags, cred, p);
234 ubc_rele(vp);
235 vrele(vp);
236 return (error);
237 }
238
239 /*
240 * Package up an I/O request on a vnode into a uio and do it.
241 */
242 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
243 enum uio_rw rw;
244 struct vnode *vp;
245 caddr_t base;
246 int len;
247 off_t offset;
248 enum uio_seg segflg;
249 int ioflg;
250 struct ucred *cred;
251 int *aresid;
252 struct proc *p;
253 {
254 struct uio auio;
255 struct iovec aiov;
256 int error=0;
257
258 /* FIXME XXX */
259 if ((ioflg & IO_NODELOCKED) == 0)
260 (void)vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
261 auio.uio_iov = &aiov;
262 auio.uio_iovcnt = 1;
263 aiov.iov_base = base;
264 aiov.iov_len = len;
265 auio.uio_resid = len;
266 auio.uio_offset = offset;
267 auio.uio_segflg = segflg;
268 auio.uio_rw = rw;
269 auio.uio_procp = p;
270
271 if (rw == UIO_READ)
272 error = VOP_READ(vp, &auio, ioflg, cred);
273 else
274 error = VOP_WRITE(vp, &auio, ioflg, cred);
275
276 if (aresid)
277 *aresid = auio.uio_resid;
278 else
279 if (auio.uio_resid && error == 0)
280 error = EIO;
281 if ((ioflg & IO_NODELOCKED) == 0)
282 VOP_UNLOCK(vp, 0, p);
283 return (error);
284 }
285
286 /*
287 * File table vnode read routine.
288 */
289 vn_read(fp, uio, cred)
290 struct file *fp;
291 struct uio *uio;
292 struct ucred *cred;
293 {
294 struct vnode *vp = (struct vnode *)fp->f_data;
295 struct proc *p = uio->uio_procp;
296 int error;
297 off_t count;
298
299 VOP_LEASE(vp, p, cred, LEASE_READ);
300 (void)vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
301 uio->uio_offset = fp->f_offset;
302 count = uio->uio_resid;
303
304 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0, cred);
305
306 fp->f_offset += count - uio->uio_resid;
307 VOP_UNLOCK(vp, 0, p);
308 return (error);
309 }
310
311
312 /*
313 * File table vnode write routine.
314 */
315 vn_write(fp, uio, cred)
316 struct file *fp;
317 struct uio *uio;
318 struct ucred *cred;
319 {
320 struct vnode *vp = (struct vnode *)fp->f_data;
321 struct proc *p = uio->uio_procp;
322 int error, ioflag = IO_UNIT;
323 off_t count;
324
325 if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
326 ioflag |= IO_APPEND;
327 if (fp->f_flag & FNONBLOCK)
328 ioflag |= IO_NDELAY;
329 if ((fp->f_flag & O_FSYNC) ||
330 (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS)))
331 ioflag |= IO_SYNC;
332 VOP_LEASE(vp, p, cred, LEASE_WRITE);
333 (void)vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
334 uio->uio_offset = fp->f_offset;
335 count = uio->uio_resid;
336
337 error = VOP_WRITE(vp, uio, ioflag, cred);
338
339 if (ioflag & IO_APPEND)
340 fp->f_offset = uio->uio_offset;
341 else
342 fp->f_offset += count - uio->uio_resid;
343 /*
344 * Set the credentials on successful writes
345 */
346 if ((error == 0) && (vp->v_tag == VT_NFS) && (UBCINFOEXISTS(vp))) {
347 ubc_setcred(vp, p);
348 }
349
350 VOP_UNLOCK(vp, 0, p);
351 return (error);
352 }
353
354 /*
355 * File table vnode stat routine.
356 */
357 vn_stat(vp, sb, p)
358 struct vnode *vp;
359 register struct stat *sb;
360 struct proc *p;
361 {
362 struct vattr vattr;
363 register struct vattr *vap;
364 int error;
365 u_short mode;
366
367 vap = &vattr;
368 error = VOP_GETATTR(vp, vap, p->p_ucred, p);
369 if (error)
370 return (error);
371 /*
372 * Copy from vattr table
373 */
374 sb->st_dev = vap->va_fsid;
375 sb->st_ino = vap->va_fileid;
376 mode = vap->va_mode;
377 switch (vp->v_type) {
378 case VREG:
379 mode |= S_IFREG;
380 break;
381 case VDIR:
382 mode |= S_IFDIR;
383 break;
384 case VBLK:
385 mode |= S_IFBLK;
386 break;
387 case VCHR:
388 mode |= S_IFCHR;
389 break;
390 case VLNK:
391 mode |= S_IFLNK;
392 break;
393 case VSOCK:
394 mode |= S_IFSOCK;
395 break;
396 case VFIFO:
397 mode |= S_IFIFO;
398 break;
399 default:
400 return (EBADF);
401 };
402 sb->st_mode = mode;
403 sb->st_nlink = vap->va_nlink;
404 sb->st_uid = vap->va_uid;
405 sb->st_gid = vap->va_gid;
406 sb->st_rdev = vap->va_rdev;
407 sb->st_size = vap->va_size;
408 sb->st_atimespec = vap->va_atime;
409 sb->st_mtimespec = vap->va_mtime;
410 sb->st_ctimespec = vap->va_ctime;
411 sb->st_blksize = vap->va_blocksize;
412 sb->st_flags = vap->va_flags;
413 /* Do not give the generation number out to unpriviledged users */
414 if (suser(p->p_ucred, &p->p_acflag))
415 sb->st_gen = 0;
416 else
417 sb->st_gen = vap->va_gen;
418 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
419 return (0);
420 }
421
422 /*
423 * File table vnode ioctl routine.
424 */
425 vn_ioctl(fp, com, data, p)
426 struct file *fp;
427 u_long com;
428 caddr_t data;
429 struct proc *p;
430 {
431 register struct vnode *vp = ((struct vnode *)fp->f_data);
432 struct vattr vattr;
433 int error;
434
435 switch (vp->v_type) {
436
437 case VREG:
438 case VDIR:
439 if (com == FIONREAD) {
440 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
441 return (error);
442 *(int *)data = vattr.va_size - fp->f_offset;
443 return (0);
444 }
445 if (com == FIONBIO || com == FIOASYNC) /* XXX */
446 return (0); /* XXX */
447 /* fall into ... */
448
449 default:
450 return (ENOTTY);
451
452 case VFIFO:
453 case VCHR:
454 case VBLK:
455 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
456 if (error == 0 && com == TIOCSCTTY) {
457 if (p->p_session->s_ttyvp)
458 vrele(p->p_session->s_ttyvp);
459 p->p_session->s_ttyvp = vp;
460 VREF(vp);
461 }
462 return (error);
463 }
464 }
465
466 /*
467 * File table vnode select routine.
468 */
469 vn_select(fp, which, wql, p)
470 struct file *fp;
471 int which;
472 void * wql;
473 struct proc *p;
474 {
475
476 return(VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
477 fp->f_cred, wql, p));
478 }
479
480 /*
481 * Check that the vnode is still valid, and if so
482 * acquire requested lock.
483 */
484 int
485 vn_lock(vp, flags, p)
486 struct vnode *vp;
487 int flags;
488 struct proc *p;
489 {
490 int error;
491
492 do {
493 if ((flags & LK_INTERLOCK) == 0)
494 simple_lock(&vp->v_interlock);
495 if (vp->v_flag & VXLOCK) {
496 while (vp->v_flag & VXLOCK) {
497 vp->v_flag |= VXWANT;
498 simple_unlock(&vp->v_interlock);
499 (void)tsleep((caddr_t)vp, PINOD, "vn_lock", 0);
500 }
501 error = ENOENT;
502 } else {
503 error = VOP_LOCK(vp, flags | LK_INTERLOCK, p);
504 if (error == 0)
505 return (error);
506 }
507 flags &= ~LK_INTERLOCK;
508 } while (flags & LK_RETRY);
509 return (error);
510 }
511
512 /*
513 * File table vnode close routine.
514 */
515 vn_closefile(fp, p)
516 struct file *fp;
517 struct proc *p;
518 {
519
520 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
521 fp->f_cred, p));
522 }