vfs_vnops.c revision 1.14
1/*	$NetBSD: vfs_vnops.c,v 1.14 1994/09/18 04:40:47 mycroft Exp $	*/
2
3/*
4 * Copyright (c) 1982, 1986, 1989, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 * (c) UNIX System Laboratories, Inc.
7 * All or some portions of this file are derived from material licensed
8 * to the University of California by American Telephone and Telegraph
9 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10 * the permission of UNIX System Laboratories, Inc.
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 *
40 *	@(#)vfs_vnops.c	8.2 (Berkeley) 1/21/94
41 */
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#include <sys/file.h>
47#include <sys/stat.h>
48#include <sys/buf.h>
49#include <sys/proc.h>
50#include <sys/mount.h>
51#include <sys/namei.h>
52#include <sys/vnode.h>
53#include <sys/ioctl.h>
54#include <sys/tty.h>
55
56#include <vm/vm.h>
57
58struct 	fileops vnops =
59	{ vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
60
61/*
62 * Common code for vnode open operations.
63 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
64 */
65vn_open(ndp, fmode, cmode)
66	register struct nameidata *ndp;
67	int fmode, cmode;
68{
69	register struct vnode *vp;
70	register struct proc *p = ndp->ni_cnd.cn_proc;
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_cnd.cn_nameiop = CREATE;
78		ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
79		if ((fmode & O_EXCL) == 0)
80			ndp->ni_cnd.cn_flags |= FOLLOW;
81		if (error = namei(ndp))
82			return (error);
83		if (ndp->ni_vp == NULL) {
84			VATTR_NULL(vap);
85			vap->va_type = VREG;
86			vap->va_mode = cmode;
87			LEASE_CHECK(ndp->ni_dvp, p, cred, LEASE_WRITE);
88			if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
89			    &ndp->ni_cnd, vap))
90				return (error);
91			fmode &= ~O_TRUNC;
92			vp = ndp->ni_vp;
93		} else {
94			VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
95			if (ndp->ni_dvp == ndp->ni_vp)
96				vrele(ndp->ni_dvp);
97			else
98				vput(ndp->ni_dvp);
99			ndp->ni_dvp = NULL;
100			vp = ndp->ni_vp;
101			if (fmode & O_EXCL) {
102				error = EEXIST;
103				goto bad;
104			}
105			fmode &= ~O_CREAT;
106		}
107	} else {
108		ndp->ni_cnd.cn_nameiop = LOOKUP;
109		ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
110		if (error = namei(ndp))
111			return (error);
112		vp = ndp->ni_vp;
113	}
114	if (vp->v_type == VSOCK) {
115		error = EOPNOTSUPP;
116		goto bad;
117	}
118	if ((fmode & O_CREAT) == 0) {
119		if (fmode & FREAD) {
120			if (error = VOP_ACCESS(vp, VREAD, cred, p))
121				goto bad;
122		}
123		if (fmode & (FWRITE | O_TRUNC)) {
124			if (vp->v_type == VDIR) {
125				error = EISDIR;
126				goto bad;
127			}
128			if ((error = vn_writechk(vp)) ||
129			    (error = VOP_ACCESS(vp, VWRITE, cred, p)))
130				goto bad;
131		}
132	}
133	if (fmode & O_TRUNC) {
134		VOP_UNLOCK(vp);				/* XXX */
135		LEASE_CHECK(vp, p, cred, LEASE_WRITE);
136		VOP_LOCK(vp);				/* XXX */
137		VATTR_NULL(vap);
138		vap->va_size = 0;
139		if (error = VOP_SETATTR(vp, vap, cred, p))
140			goto bad;
141	}
142	if (error = VOP_OPEN(vp, fmode, cred, p))
143		goto bad;
144	if (fmode & FWRITE)
145		vp->v_writecount++;
146	return (0);
147bad:
148	vput(vp);
149	return (error);
150}
151
152/*
153 * Check for write permissions on the specified vnode.
154 * The read-only status of the file system is checked.
155 * Also, prototype text segments cannot be written.
156 */
157vn_writechk(vp)
158	register struct vnode *vp;
159{
160
161	/*
162	 * Disallow write attempts on read-only file systems;
163	 * unless the file is a socket or a block or character
164	 * device resident on the file system.
165	 */
166	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
167		switch (vp->v_type) {
168		case VREG: case VDIR: case VLNK:
169			return (EROFS);
170		}
171	}
172	/*
173	 * If there's shared text associated with
174	 * the vnode, try to free it up once.  If
175	 * we fail, we can't allow writing.
176	 */
177	if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
178		return (ETXTBSY);
179	return (0);
180}
181
182/*
183 * Vnode close call
184 */
185vn_close(vp, flags, cred, p)
186	register struct vnode *vp;
187	int flags;
188	struct ucred *cred;
189	struct proc *p;
190{
191	int error;
192
193	if (flags & FWRITE)
194		vp->v_writecount--;
195	error = VOP_CLOSE(vp, flags, cred, p);
196	vrele(vp);
197	return (error);
198}
199
200/*
201 * Package up an I/O request on a vnode into a uio and do it.
202 */
203vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
204	enum uio_rw rw;
205	struct vnode *vp;
206	caddr_t base;
207	int len;
208	off_t offset;
209	enum uio_seg segflg;
210	int ioflg;
211	struct ucred *cred;
212	int *aresid;
213	struct proc *p;
214{
215	struct uio auio;
216	struct iovec aiov;
217	int error;
218
219	if ((ioflg & IO_NODELOCKED) == 0)
220		VOP_LOCK(vp);
221	auio.uio_iov = &aiov;
222	auio.uio_iovcnt = 1;
223	aiov.iov_base = base;
224	aiov.iov_len = len;
225	auio.uio_resid = len;
226	auio.uio_offset = offset;
227	auio.uio_segflg = segflg;
228	auio.uio_rw = rw;
229	auio.uio_procp = p;
230	if (rw == UIO_READ) {
231		error = VOP_READ(vp, &auio, ioflg, cred);
232	} else {
233		error = VOP_WRITE(vp, &auio, ioflg, cred);
234	}
235	if (aresid)
236		*aresid = auio.uio_resid;
237	else
238		if (auio.uio_resid && error == 0)
239			error = EIO;
240	if ((ioflg & IO_NODELOCKED) == 0)
241		VOP_UNLOCK(vp);
242	return (error);
243}
244
245/*
246 * File table vnode read routine.
247 */
248vn_read(fp, uio, cred)
249	struct file *fp;
250	struct uio *uio;
251	struct ucred *cred;
252{
253	register struct vnode *vp = (struct vnode *)fp->f_data;
254	int count, error;
255
256	LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_READ);
257	VOP_LOCK(vp);
258	uio->uio_offset = fp->f_offset;
259	count = uio->uio_resid;
260	error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
261		cred);
262	fp->f_offset += count - uio->uio_resid;
263	VOP_UNLOCK(vp);
264	return (error);
265}
266
267/*
268 * File table vnode write routine.
269 */
270vn_write(fp, uio, cred)
271	struct file *fp;
272	struct uio *uio;
273	struct ucred *cred;
274{
275	register struct vnode *vp = (struct vnode *)fp->f_data;
276	int count, error, ioflag = 0;
277
278	if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
279		ioflag |= IO_APPEND;
280	if (fp->f_flag & FNONBLOCK)
281		ioflag |= IO_NDELAY;
282	LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_WRITE);
283	VOP_LOCK(vp);
284	uio->uio_offset = fp->f_offset;
285	count = uio->uio_resid;
286	error = VOP_WRITE(vp, uio, ioflag, cred);
287	if (ioflag & IO_APPEND)
288		fp->f_offset = uio->uio_offset;
289	else
290		fp->f_offset += count - uio->uio_resid;
291	VOP_UNLOCK(vp);
292	return (error);
293}
294
295/*
296 * File table vnode stat routine.
297 */
298vn_stat(vp, sb, p)
299	struct vnode *vp;
300	register struct stat *sb;
301	struct proc *p;
302{
303	struct vattr vattr;
304	register struct vattr *vap;
305	int error;
306	u_short mode;
307
308	vap = &vattr;
309	error = VOP_GETATTR(vp, vap, p->p_ucred, p);
310	if (error)
311		return (error);
312	/*
313	 * Copy from vattr table
314	 */
315	sb->st_dev = vap->va_fsid;
316	sb->st_ino = vap->va_fileid;
317	mode = vap->va_mode;
318	switch (vp->v_type) {
319	case VREG:
320		mode |= S_IFREG;
321		break;
322	case VDIR:
323		mode |= S_IFDIR;
324		break;
325	case VBLK:
326		mode |= S_IFBLK;
327		break;
328	case VCHR:
329		mode |= S_IFCHR;
330		break;
331	case VLNK:
332		mode |= S_IFLNK;
333		break;
334	case VSOCK:
335		mode |= S_IFSOCK;
336		break;
337	case VFIFO:
338		mode |= S_IFIFO;
339		break;
340	default:
341		return (EBADF);
342	};
343	sb->st_mode = mode;
344	sb->st_nlink = vap->va_nlink;
345	sb->st_uid = vap->va_uid;
346	sb->st_gid = vap->va_gid;
347	sb->st_rdev = vap->va_rdev;
348	sb->st_size = vap->va_size;
349	sb->st_atimespec = vap->va_atime;
350	sb->st_mtimespec = vap->va_mtime;
351	sb->st_ctimespec = vap->va_ctime;
352	sb->st_blksize = vap->va_blocksize;
353	sb->st_flags = vap->va_flags;
354	sb->st_gen = vap->va_gen;
355	sb->st_blocks = vap->va_bytes / S_BLKSIZE;
356	return (0);
357}
358
359/*
360 * File table vnode ioctl routine.
361 */
362vn_ioctl(fp, com, data, p)
363	struct file *fp;
364	int com;
365	caddr_t data;
366	struct proc *p;
367{
368	register struct vnode *vp = ((struct vnode *)fp->f_data);
369	struct vattr vattr;
370	int error;
371
372	switch (vp->v_type) {
373
374	case VREG:
375	case VDIR:
376		if (com == FIONREAD) {
377			if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
378				return (error);
379			*(int *)data = vattr.va_size - fp->f_offset;
380			return (0);
381		}
382		if (com == FIONBIO || com == FIOASYNC)	/* XXX */
383			return (0);			/* XXX */
384		/* fall into ... */
385
386	default:
387		return (ENOTTY);
388
389	case VFIFO:
390	case VCHR:
391	case VBLK:
392		error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
393		if (error == 0 && com == TIOCSCTTY) {
394			if (p->p_session->s_ttyvp)
395				vrele(p->p_session->s_ttyvp);
396			p->p_session->s_ttyvp = vp;
397			VREF(vp);
398		}
399		return (error);
400	}
401}
402
403/*
404 * File table vnode select routine.
405 */
406vn_select(fp, which, p)
407	struct file *fp;
408	int which;
409	struct proc *p;
410{
411
412	return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
413		fp->f_cred, p));
414}
415
416/*
417 * File table vnode close routine.
418 */
419vn_closefile(fp, p)
420	struct file *fp;
421	struct proc *p;
422{
423
424	return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
425		fp->f_cred, p));
426}
427