xref: /freebsd/sys/kern/vfs_vnops.c (revision 0c43d89a0d8e976ca494d4837f4c1f3734d2c300)
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)vfs_vnops.c	8.2 (Berkeley) 1/21/94
39  * $Id: vfs_vnops.c,v 1.3 1994/08/02 07:43:33 davidg Exp $
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/file.h>
46 #include <sys/stat.h>
47 #include <sys/buf.h>
48 #include <sys/proc.h>
49 #include <sys/mount.h>
50 #include <sys/namei.h>
51 #include <sys/vnode.h>
52 #include <sys/ioctl.h>
53 #include <sys/tty.h>
54 
55 #include <vm/vm.h>
56 
57 struct 	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  */
64 int
65 vn_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);
147 bad:
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  */
157 int
158 vn_writechk(vp)
159 	register struct vnode *vp;
160 {
161 
162 	/*
163 	 * Disallow write attempts on read-only file systems;
164 	 * unless the file is a socket or a block or character
165 	 * device resident on the file system.
166 	 */
167 	if (vp->v_mount->mnt_flag & MNT_RDONLY) {
168 		switch (vp->v_type) {
169 		case VREG: case VDIR: case VLNK:
170 			return (EROFS);
171 		}
172 	}
173 	/*
174 	 * If there's shared text associated with
175 	 * the vnode, try to free it up once.  If
176 	 * we fail, we can't allow writing.
177 	 */
178 	if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
179 		return (ETXTBSY);
180 	return (0);
181 }
182 
183 /*
184  * Vnode close call
185  */
186 int
187 vn_close(vp, flags, cred, p)
188 	register struct vnode *vp;
189 	int flags;
190 	struct ucred *cred;
191 	struct proc *p;
192 {
193 	int error;
194 
195 	if (flags & FWRITE)
196 		vp->v_writecount--;
197 	error = VOP_CLOSE(vp, flags, cred, p);
198 	vrele(vp);
199 	return (error);
200 }
201 
202 /*
203  * Package up an I/O request on a vnode into a uio and do it.
204  */
205 int
206 vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
207 	enum uio_rw rw;
208 	struct vnode *vp;
209 	caddr_t base;
210 	int len;
211 	off_t offset;
212 	enum uio_seg segflg;
213 	int ioflg;
214 	struct ucred *cred;
215 	int *aresid;
216 	struct proc *p;
217 {
218 	struct uio auio;
219 	struct iovec aiov;
220 	int error;
221 
222 	if ((ioflg & IO_NODELOCKED) == 0)
223 		VOP_LOCK(vp);
224 	auio.uio_iov = &aiov;
225 	auio.uio_iovcnt = 1;
226 	aiov.iov_base = base;
227 	aiov.iov_len = len;
228 	auio.uio_resid = len;
229 	auio.uio_offset = offset;
230 	auio.uio_segflg = segflg;
231 	auio.uio_rw = rw;
232 	auio.uio_procp = p;
233 	if (rw == UIO_READ) {
234 		error = VOP_READ(vp, &auio, ioflg, cred);
235 	} else {
236 		error = VOP_WRITE(vp, &auio, ioflg, cred);
237 	}
238 	if (aresid)
239 		*aresid = auio.uio_resid;
240 	else
241 		if (auio.uio_resid && error == 0)
242 			error = EIO;
243 	if ((ioflg & IO_NODELOCKED) == 0)
244 		VOP_UNLOCK(vp);
245 	return (error);
246 }
247 
248 /*
249  * File table vnode read routine.
250  */
251 int
252 vn_read(fp, uio, cred)
253 	struct file *fp;
254 	struct uio *uio;
255 	struct ucred *cred;
256 {
257 	register struct vnode *vp = (struct vnode *)fp->f_data;
258 	int count, error;
259 
260 	LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_READ);
261 	VOP_LOCK(vp);
262 	uio->uio_offset = fp->f_offset;
263 	count = uio->uio_resid;
264 	error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
265 		cred);
266 	fp->f_offset += count - uio->uio_resid;
267 	VOP_UNLOCK(vp);
268 	return (error);
269 }
270 
271 /*
272  * File table vnode write routine.
273  */
274 int
275 vn_write(fp, uio, cred)
276 	struct file *fp;
277 	struct uio *uio;
278 	struct ucred *cred;
279 {
280 	register struct vnode *vp = (struct vnode *)fp->f_data;
281 	int count, error, ioflag = 0;
282 
283 	if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
284 		ioflag |= IO_APPEND;
285 	if (fp->f_flag & FNONBLOCK)
286 		ioflag |= IO_NDELAY;
287 	LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_WRITE);
288 	VOP_LOCK(vp);
289 	uio->uio_offset = fp->f_offset;
290 	count = uio->uio_resid;
291 	error = VOP_WRITE(vp, uio, ioflag, cred);
292 	if (ioflag & IO_APPEND)
293 		fp->f_offset = uio->uio_offset;
294 	else
295 		fp->f_offset += count - uio->uio_resid;
296 	VOP_UNLOCK(vp);
297 	return (error);
298 }
299 
300 /*
301  * File table vnode stat routine.
302  */
303 int
304 vn_stat(vp, sb, p)
305 	struct vnode *vp;
306 	register struct stat *sb;
307 	struct proc *p;
308 {
309 	struct vattr vattr;
310 	register struct vattr *vap;
311 	int error;
312 	u_short mode;
313 
314 	vap = &vattr;
315 	error = VOP_GETATTR(vp, vap, p->p_ucred, p);
316 	if (error)
317 		return (error);
318 	/*
319 	 * Copy from vattr table
320 	 */
321 	sb->st_dev = vap->va_fsid;
322 	sb->st_ino = vap->va_fileid;
323 	mode = vap->va_mode;
324 	switch (vp->v_type) {
325 	case VREG:
326 		mode |= S_IFREG;
327 		break;
328 	case VDIR:
329 		mode |= S_IFDIR;
330 		break;
331 	case VBLK:
332 		mode |= S_IFBLK;
333 		break;
334 	case VCHR:
335 		mode |= S_IFCHR;
336 		break;
337 	case VLNK:
338 		mode |= S_IFLNK;
339 		break;
340 	case VSOCK:
341 		mode |= S_IFSOCK;
342 		break;
343 	case VFIFO:
344 		mode |= S_IFIFO;
345 		break;
346 	default:
347 		return (EBADF);
348 	};
349 	sb->st_mode = mode;
350 	sb->st_nlink = vap->va_nlink;
351 	sb->st_uid = vap->va_uid;
352 	sb->st_gid = vap->va_gid;
353 	sb->st_rdev = vap->va_rdev;
354 	sb->st_size = vap->va_size;
355 	sb->st_atimespec = vap->va_atime;
356 	sb->st_mtimespec= vap->va_mtime;
357 	sb->st_ctimespec = vap->va_ctime;
358 	sb->st_blksize = vap->va_blocksize;
359 	sb->st_flags = vap->va_flags;
360 	sb->st_gen = vap->va_gen;
361 	sb->st_blocks = vap->va_bytes / S_BLKSIZE;
362 	return (0);
363 }
364 
365 /*
366  * File table vnode ioctl routine.
367  */
368 int
369 vn_ioctl(fp, com, data, p)
370 	struct file *fp;
371 	int com;
372 	caddr_t data;
373 	struct proc *p;
374 {
375 	register struct vnode *vp = ((struct vnode *)fp->f_data);
376 	struct vattr vattr;
377 	int error;
378 
379 	switch (vp->v_type) {
380 
381 	case VREG:
382 	case VDIR:
383 		if (com == FIONREAD) {
384 			if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
385 				return (error);
386 			*(int *)data = vattr.va_size - fp->f_offset;
387 			return (0);
388 		}
389 		if (com == FIONBIO || com == FIOASYNC)	/* XXX */
390 			return (0);			/* XXX */
391 		/* fall into ... */
392 
393 	default:
394 		return (ENOTTY);
395 
396 	case VFIFO:
397 	case VCHR:
398 	case VBLK:
399 		error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
400 		if (error == 0 && com == TIOCSCTTY) {
401 
402 			/* Do nothing if reassigning same control tty */
403 			if (p->p_session->s_ttyvp == vp)
404 				return (0);
405 
406 			/* Get rid of reference to old control tty */
407 			if (p->p_session->s_ttyvp)
408 				vrele(p->p_session->s_ttyvp);
409 
410 			p->p_session->s_ttyvp = vp;
411 			VREF(vp);
412 		}
413 		return (error);
414 	}
415 }
416 
417 /*
418  * File table vnode select routine.
419  */
420 int
421 vn_select(fp, which, p)
422 	struct file *fp;
423 	int which;
424 	struct proc *p;
425 {
426 
427 	return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
428 		fp->f_cred, p));
429 }
430 
431 /*
432  * File table vnode close routine.
433  */
434 int
435 vn_closefile(fp, p)
436 	struct file *fp;
437 	struct proc *p;
438 {
439 
440 	return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
441 		fp->f_cred, p));
442 }
443