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