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