check for negative bytes in seguse update; increment version number
[unix-history] / usr / src / sys / kern / vfs_vnops.c
CommitLineData
da7c5cc6 1/*
eb668bc6
KM
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
dbf0c423 5 * %sccs.include.redist.c%
eb668bc6 6 *
a85f307a 7 * @(#)vfs_vnops.c 7.45 (Berkeley) %G%
da7c5cc6 8 */
961945a8 9
94368568
JB
10#include "param.h"
11#include "systm.h"
eb668bc6 12#include "kernel.h"
94368568 13#include "file.h"
eb668bc6
KM
14#include "stat.h"
15#include "buf.h"
16#include "proc.h"
eb668bc6 17#include "mount.h"
a9194d51 18#include "namei.h"
eb668bc6 19#include "vnode.h"
eb668bc6
KM
20#include "ioctl.h"
21#include "tty.h"
8b4f20bf 22#include <vm/vm.h>
fc96c615 23
eb668bc6 24struct fileops vnops =
97f761d2 25 { vn_read, vn_write, vn_ioctl, vn_select, vn_closefile };
d301d150 26
fc96c615 27/*
eb668bc6
KM
28 * Common code for vnode open operations.
29 * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
fc96c615 30 */
35dccb0f 31vn_open(ndp, fmode, cmode)
eb668bc6
KM
32 register struct nameidata *ndp;
33 int fmode, cmode;
34{
35 register struct vnode *vp;
35dccb0f 36 register struct proc *p = ndp->ni_cnd.cn_proc;
9b808fbd 37 register struct ucred *cred = p->p_ucred;
eb668bc6
KM
38 struct vattr vat;
39 struct vattr *vap = &vat;
40 int error;
41
63992c37 42 if (fmode & O_CREAT) {
35dccb0f
KM
43 ndp->ni_cnd.cn_nameiop = CREATE;
44 ndp->ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
63992c37 45 if ((fmode & O_EXCL) == 0)
35dccb0f
KM
46 ndp->ni_cnd.cn_flags |= FOLLOW;
47 if (error = namei(ndp))
eb668bc6
KM
48 return (error);
49 if (ndp->ni_vp == NULL) {
3ee1461b 50 VATTR_NULL(vap);
eb668bc6
KM
51 vap->va_type = VREG;
52 vap->va_mode = cmode;
73019d79 53 LEASE_CHECK(ndp->ni_dvp, p, cred, LEASE_WRITE);
35dccb0f
KM
54 if (error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
55 &ndp->ni_cnd, vap))
eb668bc6 56 return (error);
63992c37 57 fmode &= ~O_TRUNC;
eb668bc6
KM
58 vp = ndp->ni_vp;
59 } else {
cfef4373 60 VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
3f530a7b
KM
61 if (ndp->ni_dvp == ndp->ni_vp)
62 vrele(ndp->ni_dvp);
7341981c 63 else
3f530a7b
KM
64 vput(ndp->ni_dvp);
65 ndp->ni_dvp = NULL;
eb668bc6 66 vp = ndp->ni_vp;
63992c37 67 if (fmode & O_EXCL) {
eb668bc6
KM
68 error = EEXIST;
69 goto bad;
70 }
63992c37 71 fmode &= ~O_CREAT;
eb668bc6
KM
72 }
73 } else {
35dccb0f
KM
74 ndp->ni_cnd.cn_nameiop = LOOKUP;
75 ndp->ni_cnd.cn_flags = FOLLOW | LOCKLEAF;
76 if (error = namei(ndp))
eb668bc6
KM
77 return (error);
78 vp = ndp->ni_vp;
79 }
80 if (vp->v_type == VSOCK) {
81 error = EOPNOTSUPP;
82 goto bad;
83 }
63992c37 84 if ((fmode & O_CREAT) == 0) {
eb668bc6 85 if (fmode & FREAD) {
a9194d51 86 if (error = VOP_ACCESS(vp, VREAD, cred, p))
eb668bc6
KM
87 goto bad;
88 }
63992c37 89 if (fmode & (FWRITE | O_TRUNC)) {
eb668bc6
KM
90 if (vp->v_type == VDIR) {
91 error = EISDIR;
92 goto bad;
93 }
cd811e9a 94 if ((error = vn_writechk(vp)) ||
a9194d51 95 (error = VOP_ACCESS(vp, VWRITE, cred, p)))
cd811e9a 96 goto bad;
eb668bc6
KM
97 }
98 }
63992c37 99 if (fmode & O_TRUNC) {
3ee1461b 100 VATTR_NULL(vap);
eb668bc6 101 vap->va_size = 0;
73019d79 102 LEASE_CHECK(vp, p, cred, LEASE_WRITE);
a9194d51 103 if (error = VOP_SETATTR(vp, vap, cred, p))
eb668bc6
KM
104 goto bad;
105 }
cb3e538f
KM
106 if (error = VOP_OPEN(vp, fmode, cred, p))
107 goto bad;
108 if (fmode & FWRITE)
109 vp->v_writecount++;
110 return (0);
eb668bc6
KM
111bad:
112 vput(vp);
ccee3c59 113 return (error);
eb668bc6
KM
114}
115
116/*
cd811e9a
KM
117 * Check for write permissions on the specified vnode.
118 * The read-only status of the file system is checked.
119 * Also, prototype text segments cannot be written.
eb668bc6 120 */
cd811e9a 121vn_writechk(vp)
eb668bc6 122 register struct vnode *vp;
fc96c615 123{
fc96c615 124
cd811e9a
KM
125 /*
126 * Disallow write attempts on read-only file systems;
127 * unless the file is a socket or a block or character
128 * device resident on the file system.
129 */
5216fbe4
KM
130 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
131 switch (vp->v_type) {
132 case VREG: case VDIR: case VLNK:
133 return (EROFS);
134 }
135 }
cd811e9a
KM
136 /*
137 * If there's shared text associated with
138 * the vnode, try to free it up once. If
139 * we fail, we can't allow writing.
140 */
9db58063 141 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
cd811e9a
KM
142 return (ETXTBSY);
143 return (0);
eb668bc6
KM
144}
145
146/*
97f761d2
KM
147 * Vnode close call
148 */
149vn_close(vp, flags, cred, p)
150 register struct vnode *vp;
151 int flags;
152 struct ucred *cred;
153 struct proc *p;
154{
155 int error;
156
157 if (flags & FWRITE)
158 vp->v_writecount--;
159 error = VOP_CLOSE(vp, flags, cred, p);
160 vrele(vp);
161 return (error);
162}
163
164/*
165 * Package up an I/O request on a vnode into a uio and do it.
eb668bc6 166 */
a9194d51 167vn_rdwr(rw, vp, base, len, offset, segflg, ioflg, cred, aresid, p)
eb668bc6
KM
168 enum uio_rw rw;
169 struct vnode *vp;
170 caddr_t base;
171 int len;
172 off_t offset;
173 enum uio_seg segflg;
174 int ioflg;
175 struct ucred *cred;
176 int *aresid;
a9194d51 177 struct proc *p;
eb668bc6
KM
178{
179 struct uio auio;
180 struct iovec aiov;
181 int error;
182
cde34f67
KM
183 if ((ioflg & IO_NODELOCKED) == 0)
184 VOP_LOCK(vp);
eb668bc6
KM
185 auio.uio_iov = &aiov;
186 auio.uio_iovcnt = 1;
187 aiov.iov_base = base;
188 aiov.iov_len = len;
189 auio.uio_resid = len;
190 auio.uio_offset = offset;
191 auio.uio_segflg = segflg;
192 auio.uio_rw = rw;
a9194d51 193 auio.uio_procp = p;
73019d79
KM
194 if (rw == UIO_READ) {
195 LEASE_CHECK(vp, p, cred, LEASE_READ);
cde34f67 196 error = VOP_READ(vp, &auio, ioflg, cred);
73019d79
KM
197 } else {
198 LEASE_CHECK(vp, p, cred, LEASE_WRITE);
cde34f67 199 error = VOP_WRITE(vp, &auio, ioflg, cred);
73019d79 200 }
eb668bc6
KM
201 if (aresid)
202 *aresid = auio.uio_resid;
203 else
204 if (auio.uio_resid && error == 0)
205 error = EIO;
cde34f67
KM
206 if ((ioflg & IO_NODELOCKED) == 0)
207 VOP_UNLOCK(vp);
eb668bc6
KM
208 return (error);
209}
210
97f761d2
KM
211/*
212 * File table vnode read routine.
213 */
eb668bc6
KM
214vn_read(fp, uio, cred)
215 struct file *fp;
216 struct uio *uio;
217 struct ucred *cred;
218{
cde34f67
KM
219 register struct vnode *vp = (struct vnode *)fp->f_data;
220 int count, error;
eb668bc6 221
cde34f67
KM
222 VOP_LOCK(vp);
223 uio->uio_offset = fp->f_offset;
224 count = uio->uio_resid;
73019d79 225 LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_READ);
63992c37
KM
226 error = VOP_READ(vp, uio, (fp->f_flag & FNONBLOCK) ? IO_NDELAY : 0,
227 cred);
cde34f67
KM
228 fp->f_offset += count - uio->uio_resid;
229 VOP_UNLOCK(vp);
230 return (error);
eb668bc6
KM
231}
232
97f761d2
KM
233/*
234 * File table vnode write routine.
235 */
eb668bc6
KM
236vn_write(fp, uio, cred)
237 struct file *fp;
238 struct uio *uio;
239 struct ucred *cred;
240{
241 register struct vnode *vp = (struct vnode *)fp->f_data;
cde34f67 242 int count, error, ioflag = 0;
eb668bc6 243
63992c37 244 if (vp->v_type == VREG && (fp->f_flag & O_APPEND))
eb668bc6 245 ioflag |= IO_APPEND;
63992c37 246 if (fp->f_flag & FNONBLOCK)
eb668bc6 247 ioflag |= IO_NDELAY;
cde34f67
KM
248 VOP_LOCK(vp);
249 uio->uio_offset = fp->f_offset;
250 count = uio->uio_resid;
73019d79 251 LEASE_CHECK(vp, uio->uio_procp, cred, LEASE_WRITE);
cde34f67
KM
252 error = VOP_WRITE(vp, uio, ioflag, cred);
253 if (ioflag & IO_APPEND)
254 fp->f_offset = uio->uio_offset;
255 else
256 fp->f_offset += count - uio->uio_resid;
257 VOP_UNLOCK(vp);
258 return (error);
eb668bc6
KM
259}
260
261/*
97f761d2 262 * File table vnode stat routine.
eb668bc6 263 */
a9194d51 264vn_stat(vp, sb, p)
eb668bc6
KM
265 struct vnode *vp;
266 register struct stat *sb;
a9194d51 267 struct proc *p;
eb668bc6
KM
268{
269 struct vattr vattr;
270 register struct vattr *vap;
271 int error;
272 u_short mode;
273
274 vap = &vattr;
a9194d51 275 error = VOP_GETATTR(vp, vap, p->p_ucred, p);
eb668bc6
KM
276 if (error)
277 return (error);
278 /*
279 * Copy from vattr table
280 */
281 sb->st_dev = vap->va_fsid;
282 sb->st_ino = vap->va_fileid;
283 mode = vap->va_mode;
284 switch (vp->v_type) {
285 case VREG:
2e3baa4b 286 mode |= S_IFREG;
eb668bc6
KM
287 break;
288 case VDIR:
2e3baa4b 289 mode |= S_IFDIR;
eb668bc6
KM
290 break;
291 case VBLK:
2e3baa4b 292 mode |= S_IFBLK;
eb668bc6
KM
293 break;
294 case VCHR:
2e3baa4b 295 mode |= S_IFCHR;
eb668bc6
KM
296 break;
297 case VLNK:
2e3baa4b 298 mode |= S_IFLNK;
eb668bc6
KM
299 break;
300 case VSOCK:
2e3baa4b 301 mode |= S_IFSOCK;
eb668bc6 302 break;
0099f400
KM
303 case VFIFO:
304 mode |= S_IFIFO;
305 break;
eb668bc6
KM
306 default:
307 return (EBADF);
308 };
309 sb->st_mode = mode;
310 sb->st_nlink = vap->va_nlink;
311 sb->st_uid = vap->va_uid;
312 sb->st_gid = vap->va_gid;
313 sb->st_rdev = vap->va_rdev;
314 sb->st_size = vap->va_size;
7e11a0c9
KM
315 sb->st_atimespec = vap->va_atime;
316 sb->st_mtimespec= vap->va_mtime;
317 sb->st_ctimespec = vap->va_ctime;
eb668bc6 318 sb->st_blksize = vap->va_blocksize;
2ff0b8da
KM
319 sb->st_flags = vap->va_flags;
320 sb->st_gen = vap->va_gen;
366f2ef0 321 sb->st_blocks = vap->va_bytes / S_BLKSIZE;
eb668bc6
KM
322 return (0);
323}
324
325/*
97f761d2 326 * File table vnode ioctl routine.
eb668bc6 327 */
a9194d51 328vn_ioctl(fp, com, data, p)
eb668bc6
KM
329 struct file *fp;
330 int com;
331 caddr_t data;
a9194d51 332 struct proc *p;
eb668bc6
KM
333{
334 register struct vnode *vp = ((struct vnode *)fp->f_data);
335 struct vattr vattr;
336 int error;
337
338 switch (vp->v_type) {
339
340 case VREG:
341 case VDIR:
342 if (com == FIONREAD) {
a9194d51 343 if (error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))
eb668bc6 344 return (error);
a85f307a 345 *(int *)data = vattr.va_size - fp->f_offset;
eb668bc6
KM
346 return (0);
347 }
348 if (com == FIONBIO || com == FIOASYNC) /* XXX */
349 return (0); /* XXX */
350 /* fall into ... */
351
352 default:
353 return (ENOTTY);
354
0099f400 355 case VFIFO:
eb668bc6
KM
356 case VCHR:
357 case VBLK:
a9194d51 358 error = VOP_IOCTL(vp, com, data, fp->f_flag, p->p_ucred, p);
1665da5a 359 if (error == 0 && com == TIOCSCTTY) {
8429d022 360 p->p_session->s_ttyvp = vp;
1665da5a
MT
361 VREF(vp);
362 }
363 return (error);
fc96c615 364 }
eb668bc6
KM
365}
366
367/*
97f761d2 368 * File table vnode select routine.
eb668bc6 369 */
a9194d51 370vn_select(fp, which, p)
eb668bc6
KM
371 struct file *fp;
372 int which;
a9194d51 373 struct proc *p;
eb668bc6 374{
8429d022 375
ccee3c59 376 return (VOP_SELECT(((struct vnode *)fp->f_data), which, fp->f_flag,
97f761d2 377 fp->f_cred, p));
eb668bc6
KM
378}
379
380/*
97f761d2 381 * File table vnode close routine.
eb668bc6 382 */
97f761d2
KM
383vn_closefile(fp, p)
384 struct file *fp;
a9194d51 385 struct proc *p;
eb668bc6 386{
eb668bc6 387
97f761d2
KM
388 return (vn_close(((struct vnode *)fp->f_data), fp->f_flag,
389 fp->f_cred, p));
eb668bc6 390}