added my responsibility for the `cpm' port
[unix-history] / sys / kern / vfs_vnops.c
CommitLineData
169d8a33
RG
1/*
2 * Copyright (c) UNIX System Laboratories, Inc. All or some portions
3 * of this file are derived from material licensed to the
4 * University of California by American Telephone and Telegraph Co.
5 * or UNIX System Laboratories, Inc. and are reproduced herein with
6 * the permission of UNIX System Laboratories, Inc.
7 */
15637ed4
RG
8/*
9 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
600f7f07 40 * from: @(#)vfs_vnops.c 7.33 (Berkeley) 6/27/91
169d8a33 41 * $Id: vfs_vnops.c,v 1.6 1994/05/01 21:14:13 davidg Exp $
15637ed4
RG
42 */
43
44#include "param.h"
45#include "systm.h"
46#include "kernel.h"
47#include "file.h"
48#include "stat.h"
49#include "buf.h"
50#include "proc.h"
51#include "mount.h"
52#include "namei.h"
53#include "vnode.h"
54#include "ioctl.h"
55#include "tty.h"
56
57struct fileops vnops =
58 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
59
60/*
61 * Common code for vnode open operations.
62 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
63 */
4c45483e 64int
15637ed4
RG
65vn_open(ndp, p, fmode, cmode)
66 register struct nameidata *ndp;
67 struct proc *p;
68 int fmode, cmode;
69{
70 register struct vnode *vp;
71 register struct ucred *cred = p->p_ucred;
72 struct vattr vat;
73 struct vattr *vap = &vat;
74 int error;
75
76 if (fmode & O_CREAT) {
77 ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF;
78 if ((fmode & O_EXCL) == 0)
79 ndp->ni_nameiop |= FOLLOW;
80 if (error = namei(ndp, p))
81 return (error);
82 if (ndp->ni_vp == NULL) {
83 VATTR_NULL(vap);
84 vap->va_type = VREG;
85 vap->va_mode = cmode;
86 if (error = VOP_CREATE(ndp, vap, p))
87 return (error);
88 fmode &= ~O_TRUNC;
89 vp = ndp->ni_vp;
90 } else {
91 VOP_ABORTOP(ndp);
92 if (ndp->ni_dvp == ndp->ni_vp)
93 vrele(ndp->ni_dvp);
94 else
95 vput(ndp->ni_dvp);
96 ndp->ni_dvp = NULL;
97 vp = ndp->ni_vp;
98 if (fmode & O_EXCL) {
99 error = EEXIST;
100 goto bad;
101 }
102 fmode &= ~O_CREAT;
103 }
104 } else {
105 ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
106 if (error = namei(ndp, p))
107 return (error);
108 vp = ndp->ni_vp;
109 }
110 if (vp->v_type == VSOCK) {
111 error = EOPNOTSUPP;
112 goto bad;
113 }
114 if ((fmode & O_CREAT) == 0) {
115 if (fmode & FREAD) {
116 if (error = VOP_ACCESS(vp, VREAD, cred, p))
117 goto bad;
118 }
119 if (fmode & (FWRITE | O_TRUNC)) {
120 if (vp->v_type == VDIR) {
121 error = EISDIR;
122 goto bad;
123 }
124 if ((error = vn_writechk(vp)) ||
125 (error = VOP_ACCESS(vp, VWRITE, cred, p)))
126 goto bad;
127 }
128 }
129 if (fmode & O_TRUNC) {
130 VATTR_NULL(vap);
131 vap->va_size = 0;
132 if (error = VOP_SETATTR(vp, vap, cred, p))
133 goto bad;
134 }
135 if (error = VOP_OPEN(vp, fmode, cred, p))
136 goto bad;
137 if (fmode & FWRITE)
138 vp->v_writecount++;
139 return (0);
140bad:
141 vput(vp);
142 return (error);
143}
144
145/*
146 * Check for write permissions on the specified vnode.
147 * The read-only status of the file system is checked.
148 * Also, prototype text segments cannot be written.
149 */
4c45483e 150int
15637ed4
RG
151vn_writechk(vp)
152 register struct vnode *vp;
153{
154
155 /*
156 * Disallow write attempts on read-only file systems;
157 * unless the file is a socket or a block or character
158 * device resident on the file system.
159 */
160 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
161 switch (vp->v_type) {
162 case VREG: case VDIR: case VLNK:
163 return (EROFS);
164 }
165 }
166 /*
167 * If there's shared text associated with
168 * the vnode, try to free it up once. If
169 * we fail, we can't allow writing.
170 */
171 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
172 return (ETXTBSY);
173 return (0);
174}
175
176/*
177 * Vnode close call
178 */
4c45483e 179int
15637ed4
RG
180vn_close(vp, flags, cred, p)
181 register struct vnode *vp;
182 int flags;
183 struct ucred *cred;
184 struct proc *p;
185{
186 int error;
187
188 if (flags & FWRITE)
189 vp->v_writecount--;
190 error = VOP_CLOSE(vp, flags, cred, p);
191 vrele(vp);
192 return (error);
193}
194
195/*
196 * Package up an I/O request on a vnode into a uio and do it.
197 * [internal interface to file i/o for kernel only]
198 */
4c45483e 199int
15637ed4
RG
200vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
201 enum uio_rw rw;
202 struct vnode *vp;
203 caddr_t base;
204 int len;
205 off_t offset;
206 enum uio_seg segflg;
207 int ioflg;
208 struct ucred *cred;
209 int *aresid;
210 struct proc *p;
211{
212 struct uio auio;
213 struct iovec aiov;
214 int error;
215
216 if ((ioflg & IO_NODELOCKED) == 0)
217 VOP_LOCK(vp);
218 auio.uio_iov = &aiov;
219 auio.uio_iovcnt = 1;
220 aiov.iov_base = base;
221 aiov.iov_len = len;
222 auio.uio_resid = len;
223 auio.uio_offset = offset;
224 auio.uio_segflg = segflg;
225 auio.uio_rw = rw;
226 auio.uio_procp = p;
227 if (rw == UIO_READ)
228 error = VOP_READ(vp, &auio, ioflg, cred);
229 else
230 error = VOP_WRITE(vp, &auio, ioflg, cred);
231 if (aresid)
232 *aresid = auio.uio_resid;
233 else
234 if (auio.uio_resid && error == 0)
235 error = EIO;
236 if ((ioflg & IO_NODELOCKED) == 0)
237 VOP_UNLOCK(vp);
238 return (error);
239}
240
241/*
242 * File table vnode read routine.
243 */
4c45483e 244int
15637ed4
RG
245vn_read(fp, uio, cred)
246 struct file *fp;
247 struct uio *uio;
248 struct ucred *cred;
249{
250 register struct vnode *vp = (struct vnode *)fp->f_data;
251 int count, error;
252
253 VOP_LOCK(vp);
254 uio->uio_offset = fp->f_offset;
255 count = uio->uio_resid;
256 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
257 cred);
258 fp->f_offset += count - uio->uio_resid;
259 VOP_UNLOCK(vp);
260 return (error);
261}
262
263/*
264 * File table vnode write routine.
265 */
4c45483e 266int
15637ed4
RG
267vn_write(fp, uio, cred)
268 struct file *fp;
269 struct uio *uio;
270 struct ucred *cred;
271{
272 register struct vnode *vp = (struct vnode *)fp->f_data;
273 int count, error, ioflag = 0;
274
275 if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
276 ioflag |= IO_APPEND;
277 if (fp->f_flag & FNONBLOCK)
278 ioflag |= IO_NDELAY;
279 VOP_LOCK(vp);
280 uio->uio_offset = fp->f_offset;
281 count = uio->uio_resid;
282 error = VOP_WRITE(vp, uio, ioflag, cred);
283 if (ioflag & IO_APPEND)
284 fp->f_offset = uio->uio_offset;
285 else
286 fp->f_offset += count - uio->uio_resid;
287 VOP_UNLOCK(vp);
288 return (error);
289}
290
291/*
292 * File table vnode stat routine.
293 */
4c45483e 294int
15637ed4
RG
295vn_stat(vp, sb, p)
296 struct vnode *vp;
297 register struct stat *sb;
298 struct proc *p;
299{
300 struct vattr vattr;
301 register struct vattr *vap;
302 int error;
303 u_short mode;
304
305 vap = &vattr;
306 error = VOP_GETATTR(vp, vap, p->p_ucred, p);
307 if (error)
308 return (error);
309 /*
310 * Copy from vattr table
311 */
312 sb->st_dev = vap->va_fsid;
313 sb->st_ino = vap->va_fileid;
314 mode = vap->va_mode;
315 switch (vp->v_type) {
316 case VREG:
317350b1 317 case VPROC:
15637ed4
RG
318 mode |= S_IFREG;
319 break;
320 case VDIR:
321 mode |= S_IFDIR;
322 break;
323 case VBLK:
324 mode |= S_IFBLK;
325 break;
326 case VCHR:
327 mode |= S_IFCHR;
328 break;
329 case VLNK:
330 mode |= S_IFLNK;
331 break;
332 case VSOCK:
333 mode |= S_IFSOCK;
334 break;
335 case VFIFO:
336 mode |= S_IFIFO;
337 break;
338 default:
339 return (EBADF);
340 };
341 sb->st_mode = mode;
342 sb->st_nlink = vap->va_nlink;
343 sb->st_uid = vap->va_uid;
344 sb->st_gid = vap->va_gid;
345 sb->st_rdev = vap->va_rdev;
346 sb->st_size = vap->va_size;
347 sb->st_atime = vap->va_atime.tv_sec;
348 sb->st_spare1 = 0;
349 sb->st_mtime = vap->va_mtime.tv_sec;
350 sb->st_spare2 = 0;
351 sb->st_ctime = vap->va_ctime.tv_sec;
352 sb->st_spare3 = 0;
353 sb->st_blksize = vap->va_blocksize;
354 sb->st_flags = vap->va_flags;
355 sb->st_gen = vap->va_gen;
356 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
357 return (0);
358}
359
360/*
361 * File table vnode ioctl routine.
362 */
4c45483e 363int
15637ed4
RG
364vn_ioctl(fp, com, data, p)
365 struct file *fp;
366 int com;
367 caddr_t data;
368 struct proc *p;
369{
370 register struct vnode *vp = ((struct vnode *)fp->f_data);
371 struct vattr vattr;
372 int error;
373
374 switch (vp->v_type) {
375
376 case VREG:
377 case VDIR:
378 if (com == FIONREAD) {
379 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
380 return (error);
381 *(off_t *)data = vattr.va_size - fp->f_offset;
382 return (0);
383 }
384 if (com == FIONBIO || com == FIOASYNC) /* XXX */
385 return (0); /* XXX */
386 /* fall into ... */
387
388 default:
389 return (ENOTTY);
390
22c84afa 391 case VPROC:
15637ed4
RG
392 case VFIFO:
393 case VCHR:
394 case VBLK:
395 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
15c81350 396 if (error == 0 && com == TIOCSCTTY && (p->p_session->s_ttyvp != vp)) {
15637ed4
RG
397 p->p_session->s_ttyvp = vp;
398 VREF(vp);
399 }
400 return (error);
401 }
402}
403
404/*
405 * File table vnode select routine.
406 */
4c45483e 407int
15637ed4
RG
408vn_select(fp, which, p)
409 struct file *fp;
410 int which;
411 struct proc *p;
412{
413
414 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
415 fp->f_cred, p));
416}
417
418/*
419 * File table vnode close routine.
420 */
4c45483e 421int
15637ed4
RG
422vn_closefile(fp, p)
423 struct file *fp;
424 struct proc *p;
425{
426
427 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
428 fp->f_cred, p));
429}
430
431/*
432 * vn_fhtovp() - convert a fh to a vnode ptr (optionally locked)
433 * - look up fsid in mount list (if not found ret error)
434 * - get vp by calling VFS_FHTOVP() macro
435 * - if lockflag lock it with VOP_LOCK()
436 */
4c45483e 437int
15637ed4
RG
438vn_fhtovp(fhp, lockflag, vpp)
439 fhandle_t *fhp;
440 int lockflag;
441 struct vnode **vpp;
442{
443 register struct mount *mp;
444
445 if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
446 return (ESTALE);
447 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
448 return (ESTALE);
449 if (!lockflag)
450 VOP_UNLOCK(*vpp);
451 return (0);
452}