avoid dangling reference for cdir when doing rename
[unix-history] / usr / src / sys / nfs / nfs_serv.c
CommitLineData
971b93e3
KM
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
107d27c5 20 * @(#)nfs_serv.c 7.5 (Berkeley) %G%
971b93e3
KM
21 */
22
23/*
24 * nfs version 2 server calls to vnode ops
25 * - these routines generally have 3 phases
26 * 1 - break down and validate rpc request in mbuf list
27 * 2 - do the vnode ops for the request
36c3043b 28 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
971b93e3
KM
29 * 3 - build the rpc reply in an mbuf list
30 * nb:
31 * - do not mix the phases, since the nfsm_?? macros can return failures
32 * on mbuf exhaustion or similar and do not do any vrele() or vput()'s
33 *
36c3043b 34 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
971b93e3 35 * error number iff error != 0 whereas
36c3043b
KM
36 * nfsm_srverr simply drops the mbufs and gives up
37 * (==> nfsm_srverr implies an error here at the server, usually mbuf
971b93e3
KM
38 * exhaustion)
39 */
40
41#include "strings.h"
42#include "time.h"
43#include "param.h"
44#include "mount.h"
45#include "malloc.h"
46#include "mbuf.h"
47#include "file.h"
48#include "user.h"
49#include "../ufs/dir.h"
50#include "vnode.h"
51#include "uio.h"
52#include "ucred.h"
53#include "namei.h"
54#include "errno.h"
55#include "../ufs/inode.h"
56#include "nfsv2.h"
57#include "nfs.h"
58#include "xdr_subs.h"
59#include "nfsm_subs.h"
60
61/* Defs */
36c3043b
KM
62#define TRUE 1
63#define FALSE 0
971b93e3
KM
64
65/* Global vars */
66extern u_long nfs_procids[NFS_NPROCS];
67extern u_long nfs_xdrneg1;
68extern u_long nfs_false, nfs_true;
69nfstype nfs_type[VSOCK+1]={ NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, };
70
71/*
72 * nfs getattr service
73 */
74nfsrv_getattr(mrep, md, dpos, cred, xid, mrq)
75 struct mbuf **mrq;
76 struct mbuf *mrep, *md;
77 caddr_t dpos;
78 struct ucred *cred;
79 u_long xid;
80{
81 struct vattr va;
82 register struct vattr *vap = &va;
83 struct vnode *vp;
84 nfsv2fh_t nfh;
85 fhandle_t *fhp;
86 nfsm_srvars;
87
88 fhp = &nfh.fh_generic;
89 nfsm_srvmtofh(fhp);
90 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
91 nfsm_reply(0);
92 error = VOP_GETATTR(vp, vap, cred);
93 vput(vp);
94 nfsm_reply(NFSX_FATTR);
95 nfsm_build(p, u_long *, NFSX_FATTR);
96 *p++ = vtonfs_type(vap->va_type);
97 *p++ = vtonfs_mode(vap->va_type, vap->va_mode);
98 *p++ = txdr_unsigned(vap->va_nlink);
99 *p++ = txdr_unsigned(vap->va_uid);
100 *p++ = txdr_unsigned(vap->va_gid);
101 *p++ = txdr_unsigned(vap->va_size);
102 *p++ = txdr_unsigned(vap->va_blocksize);
103 *p++ = txdr_unsigned(vap->va_rdev);
104 *p++ = txdr_unsigned(vap->va_bytes);
105 *p++ = txdr_unsigned(vap->va_fsid);
106 *p++ = txdr_unsigned(vap->va_fileid);
107 txdr_time(&(vap->va_atime), p);
108 p += 2;
109 txdr_time(&(vap->va_mtime), p);
110 p += 2;
111 txdr_time(&(vap->va_ctime), p);
112 nfsm_srvdone;
113}
114
115/*
116 * nfs setattr service
117 */
118nfsrv_setattr(mrep, md, dpos, cred, xid, mrq)
119 struct mbuf **mrq;
120 struct mbuf *mrep, *md;
121 caddr_t dpos;
122 struct ucred *cred;
123 u_long xid;
124{
125 struct vattr va;
126 register struct vattr *vap = &va;
127 struct vnode *vp;
128 nfsv2fh_t nfh;
129 fhandle_t *fhp;
130 nfsm_srvars;
131
132 fhp = &nfh.fh_generic;
133 nfsm_srvmtofh(fhp);
134 nfsm_disect(p, u_long *, NFSX_SATTR);
135 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
136 nfsm_reply(0);
24ed1a73 137 if (error = nfsrv_access(vp, VWRITE, cred))
971b93e3 138 goto out;
971b93e3
KM
139 vattr_null(vap);
140 /*
141 * Nah nah nah nah na nah
142 * There is a bug in the Sun client that puts 0xffff in the mode
143 * field of sattr when it should put in 0xffffffff. The u_short
144 * doesn't sign extend.
145 * --> check the low order 2 bytes for 0xffff
146 */
147 if ((fxdr_unsigned(int, *p) & 0xffff) != 0xffff)
148 vap->va_mode = nfstov_mode(*p);
149 if (*++p != nfs_xdrneg1)
150 vap->va_uid = fxdr_unsigned(uid_t, *p);
151 if (*++p != nfs_xdrneg1)
152 vap->va_gid = fxdr_unsigned(gid_t, *p);
36c3043b 153 if (*++p != nfs_xdrneg1) {
971b93e3 154 vap->va_size = fxdr_unsigned(u_long, *p);
36c3043b 155 }
971b93e3
KM
156 if (*++p != nfs_xdrneg1)
157 fxdr_time(p, &(vap->va_atime));
158 p += 2;
159 if (*p != nfs_xdrneg1)
160 fxdr_time(p, &(vap->va_mtime));
161 if (error = VOP_SETATTR(vp, vap, cred)) {
162 vput(vp);
163 nfsm_reply(0);
164 }
165 error = VOP_GETATTR(vp, vap, cred);
166out:
167 vput(vp);
168 nfsm_reply(NFSX_FATTR);
169 nfsm_build(p, u_long *, NFSX_FATTR);
170 *p++ = vtonfs_type(vap->va_type);
171 *p++ = vtonfs_mode(vap->va_type, vap->va_mode);
172 *p++ = txdr_unsigned(vap->va_nlink);
173 *p++ = txdr_unsigned(vap->va_uid);
174 *p++ = txdr_unsigned(vap->va_gid);
175 *p++ = txdr_unsigned(vap->va_size);
176 *p++ = txdr_unsigned(vap->va_blocksize);
177 *p++ = txdr_unsigned(vap->va_rdev);
178 *p++ = txdr_unsigned(vap->va_bytes);
179 *p++ = txdr_unsigned(vap->va_fsid);
180 *p++ = txdr_unsigned(vap->va_fileid);
181 txdr_time(&(vap->va_atime), p);
182 p += 2;
183 txdr_time(&(vap->va_mtime), p);
184 p += 2;
185 txdr_time(&(vap->va_ctime), p);
186 nfsm_srvdone;
187}
188
189/*
190 * nfs lookup rpc
191 */
192nfsrv_lookup(mrep, md, dpos, cred, xid, mrq)
193 struct mbuf **mrq;
194 struct mbuf *mrep, *md;
195 caddr_t dpos;
196 struct ucred *cred;
197 u_long xid;
198{
199 register struct nameidata *ndp = &u.u_nd;
200 struct vnode *vp;
201 nfsv2fh_t nfh;
202 fhandle_t *fhp;
203 nfsm_srvars;
204 long len;
205 struct vattr va, *vap = &va;
206
207 fhp = &nfh.fh_generic;
208 nfsm_srvmtofh(fhp);
209 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
210 ndp->ni_cred = cred;
211 ndp->ni_nameiop = LOOKUP | LOCKLEAF;
971b93e3
KM
212 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
213 nfsm_reply(0);
214 vp = ndp->ni_vp;
215 bzero((caddr_t)fhp, sizeof(nfh));
216 fhp->fh_fsid = vp->v_mount->m_fsid;
217 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
218 vput(vp);
219 nfsm_reply(0);
220 }
221 error = VOP_GETATTR(vp, vap, cred);
222 vput(vp);
223 nfsm_reply(NFSX_FH+NFSX_FATTR);
224 nfsm_srvfhtom(fhp);
225 nfsm_build(p, u_long *, NFSX_FATTR);
226 *p++ = vtonfs_type(vap->va_type);
227 *p++ = vtonfs_mode(vap->va_type, vap->va_mode);
228 *p++ = txdr_unsigned(vap->va_nlink);
229 *p++ = txdr_unsigned(vap->va_uid);
230 *p++ = txdr_unsigned(vap->va_gid);
231 *p++ = txdr_unsigned(vap->va_size);
232 *p++ = txdr_unsigned(vap->va_blocksize);
233 *p++ = txdr_unsigned(vap->va_rdev);
234 *p++ = txdr_unsigned(vap->va_bytes);
235 *p++ = txdr_unsigned(vap->va_fsid);
236 *p++ = txdr_unsigned(vap->va_fileid);
237 txdr_time(&(vap->va_atime), p);
238 p += 2;
239 txdr_time(&(vap->va_mtime), p);
240 p += 2;
241 txdr_time(&(vap->va_ctime), p);
242 nfsm_srvdone;
243}
244
245/*
246 * nfs readlink service
247 */
248nfsrv_readlink(mrep, md, dpos, cred, xid, mrq)
249 struct mbuf **mrq;
250 struct mbuf *mrep, *md;
251 caddr_t dpos;
252 struct ucred *cred;
253 long xid;
254{
255 struct iovec iv[NFS_MAXPATHLEN/MLEN+1];
256 register struct iovec *ivp = iv;
257 register struct mbuf *mp;
258 nfsm_srvars;
259 struct mbuf *mp2, *mp3;
260 struct vnode *vp;
261 nfsv2fh_t nfh;
262 fhandle_t *fhp;
263 struct uio io, *uiop = &io;
264 int i, tlen, len;
265
266 fhp = &nfh.fh_generic;
267 nfsm_srvmtofh(fhp);
268 len = 0;
269 i = 0;
270 while (len < NFS_MAXPATHLEN) {
271 MGET(mp, M_WAIT, MT_DATA);
272 NFSMCLGET(mp, M_WAIT);
273 mp->m_len = NFSMSIZ(mp);
274 if (len == 0)
275 mp3 = mp2 = mp;
276 else
277 mp2->m_next = mp;
278 if ((len+mp->m_len) > NFS_MAXPATHLEN) {
279 mp->m_len = NFS_MAXPATHLEN-len;
280 len = NFS_MAXPATHLEN;
281 } else
282 len += mp->m_len;
283 ivp->iov_base = mtod(mp, caddr_t);
284 ivp->iov_len = mp->m_len;
285 i++;
286 ivp++;
287 }
288 uiop->uio_iov = iv;
289 uiop->uio_iovcnt = i;
290 uiop->uio_offset = 0;
291 uiop->uio_resid = len;
292 uiop->uio_rw = UIO_READ;
293 uiop->uio_segflg = UIO_SYSSPACE;
294 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred)) {
295 m_freem(mp3);
296 nfsm_reply(0);
297 }
298 if (vp->v_type != VLNK) {
299 error = EINVAL;
300 goto out;
301 }
302 error = VOP_READLINK(vp, uiop, cred);
303out:
304 vput(vp);
305 if (error)
306 m_freem(mp3);
307 nfsm_reply(NFSX_UNSIGNED);
308 if (uiop->uio_resid > 0) {
309 len -= uiop->uio_resid;
310 tlen = nfsm_rndup(len);
311 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
312 }
313 nfsm_build(p, u_long *, NFSX_UNSIGNED);
314 *p = txdr_unsigned(len);
315 mb->m_next = mp3;
316 nfsm_srvdone;
317}
318
319/*
320 * nfs read service
321 */
322nfsrv_read(mrep, md, dpos, cred, xid, mrq)
323 struct mbuf **mrq;
324 struct mbuf *mrep, *md;
325 caddr_t dpos;
326 struct ucred *cred;
327 u_long xid;
328{
329 struct iovec iv[NFS_MAXDATA/MCLBYTES+1];
330 register struct iovec *ivp = iv;
331 register struct mbuf *mp;
332 nfsm_srvars;
333 struct mbuf *mp2, *mp3;
334 struct vnode *vp;
335 nfsv2fh_t nfh;
336 fhandle_t *fhp;
337 struct uio io, *uiop = &io;
338 struct vattr va, *vap = &va;
339 int i, tlen, cnt, len, nio, left;
340 off_t off;
341
342 fhp = &nfh.fh_generic;
343 nfsm_srvmtofh(fhp);
344 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
345 off = fxdr_unsigned(off_t, *p);
346 nfsm_srvstrsiz(cnt, NFS_MAXDATA);
347 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
348 nfsm_reply(0);
24ed1a73 349 if (error = nfsrv_access(vp, VREAD | VEXEC, cred)) {
971b93e3
KM
350 vput(vp);
351 nfsm_reply(0);
352 }
353 len = left = cnt;
354 nio = (cnt+MCLBYTES-1)/MCLBYTES;
355 uiop->uio_iov = ivp;
356 uiop->uio_iovcnt = nio;
357 uiop->uio_offset = off;
358 uiop->uio_resid = cnt;
359 uiop->uio_rw = UIO_READ;
360 uiop->uio_segflg = UIO_SYSSPACE;
361 for (i = 0; i < nio; i++) {
362 MGET(mp, M_WAIT, MT_DATA);
363 if (left > MLEN)
364 NFSMCLGET(mp, M_WAIT);
365 mp->m_len = (M_HASCL(mp)) ? MCLBYTES : MLEN;
366 if (i == 0) {
367 mp3 = mp2 = mp;
368 } else {
369 mp2->m_next = mp;
370 mp2 = mp;
371 }
372 if (left > MLEN && !M_HASCL(mp)) {
373 m_freem(mp3);
374 vput(vp);
375 nfsm_srverr;
376 }
377 ivp->iov_base = mtod(mp, caddr_t);
378 if (left > mp->m_len) {
379 ivp->iov_len = mp->m_len;
380 left -= mp->m_len;
381 } else {
382 ivp->iov_len = mp->m_len = left;
383 left = 0;
384 }
385 ivp++;
386 }
387 error = VOP_READ(vp, uiop, &off, IO_NODELOCKED, cred);
388 if (error) {
389 m_freem(mp3);
390 vput(vp);
391 nfsm_reply(0);
392 }
393 if (error = VOP_GETATTR(vp, vap, cred))
394 m_freem(mp3);
395 vput(vp);
396 nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED);
397 nfsm_build(p, u_long *, NFSX_FATTR+NFSX_UNSIGNED);
398 *p++ = vtonfs_type(vap->va_type);
399 *p++ = vtonfs_mode(vap->va_type, vap->va_mode);
400 *p++ = txdr_unsigned(vap->va_nlink);
401 *p++ = txdr_unsigned(vap->va_uid);
402 *p++ = txdr_unsigned(vap->va_gid);
403 *p++ = txdr_unsigned(vap->va_size);
404 *p++ = txdr_unsigned(vap->va_blocksize);
405 *p++ = txdr_unsigned(vap->va_rdev);
406 *p++ = txdr_unsigned(vap->va_bytes);
407 *p++ = txdr_unsigned(vap->va_fsid);
408 *p++ = txdr_unsigned(vap->va_fileid);
409 txdr_time(&(vap->va_atime), p);
410 p += 2;
411 txdr_time(&(vap->va_mtime), p);
412 p += 2;
413 txdr_time(&(vap->va_ctime), p);
414 p += 2;
415 if (uiop->uio_resid > 0) {
416 len -= uiop->uio_resid;
417 if (len > 0) {
418 tlen = nfsm_rndup(len);
419 nfsm_adj(mp3, cnt-tlen, tlen-len);
420 } else {
421 m_freem(mp3);
422 mp3 = (struct mbuf *)0;
423 }
424 }
425 *p = txdr_unsigned(len);
426 mb->m_next = mp3;
427 nfsm_srvdone;
428}
429
430/*
431 * nfs write service
432 */
433nfsrv_write(mrep, md, dpos, cred, xid, mrq)
434 struct mbuf *mrep, *md, **mrq;
435 caddr_t dpos;
436 struct ucred *cred;
437 long xid;
438{
439 register struct iovec *ivp;
440 register struct mbuf *mp;
441 struct iovec iv[MAX_IOVEC];
442 struct vattr va;
443 register struct vattr *vap = &va;
444 nfsm_srvars;
445 struct vnode *vp;
446 nfsv2fh_t nfh;
447 fhandle_t *fhp;
448 struct uio io, *uiop = &io;
449 off_t off;
450 long siz, len, xfer;
451
452 fhp = &nfh.fh_generic;
453 nfsm_srvmtofh(fhp);
454 nfsm_disect(p, u_long *, 4*NFSX_UNSIGNED);
455 off = fxdr_unsigned(off_t, *++p);
456 p += 2;
457 len = fxdr_unsigned(long, *p);
458 if (len > NFS_MAXDATA || len <= 0) {
459 error = EBADRPC;
460 nfsm_reply(0);
461 }
462 if (dpos == (mtod(md, caddr_t)+md->m_len)) {
463 mp = md->m_next;
464 if (mp == NULL) {
465 error = EBADRPC;
466 nfsm_reply(0);
467 }
468 } else {
469 mp = md;
470 siz = dpos-mtod(mp, caddr_t);
471 mp->m_len -= siz;
472 NFSMADV(mp, siz);
473 }
474 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
475 nfsm_reply(0);
24ed1a73 476 if (error = nfsrv_access(vp, VWRITE, cred)) {
971b93e3
KM
477 vput(vp);
478 nfsm_reply(0);
479 }
480 uiop->uio_resid = 0;
481 uiop->uio_rw = UIO_WRITE;
482 uiop->uio_segflg = UIO_SYSSPACE;
483 /*
484 * Do up to MAX_IOVEC mbufs of write each iteration of the
485 * loop until done.
486 */
487 while (len > 0 && uiop->uio_resid == 0) {
488 ivp = iv;
489 siz = 0;
490 uiop->uio_iov = ivp;
491 uiop->uio_iovcnt = 0;
492 uiop->uio_offset = off;
493 while (len > 0 && uiop->uio_iovcnt < MAX_IOVEC && mp != NULL) {
494 ivp->iov_base = mtod(mp, caddr_t);
495 if (len < mp->m_len)
496 ivp->iov_len = xfer = len;
497 else
498 ivp->iov_len = xfer = mp->m_len;
499#ifdef notdef
500 /* Not Yet .. */
501 if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0)
502 ivp->iov_op = NULL; /* what should it be ?? */
503 else
504 ivp->iov_op = NULL;
505#endif
506 uiop->uio_iovcnt++;
507 ivp++;
508 len -= xfer;
509 siz += xfer;
510 mp = mp->m_next;
511 }
512 if (len > 0 && mp == NULL) {
513 error = EBADRPC;
514 vput(vp);
515 nfsm_reply(0);
516 }
517 uiop->uio_resid = siz;
518 if (error = VOP_WRITE(vp, uiop, &off, IO_SYNC | IO_NODELOCKED,
519 cred)) {
520 vput(vp);
521 nfsm_reply(0);
522 }
523 }
524 error = VOP_GETATTR(vp, vap, cred);
525 vput(vp);
526 nfsm_reply(NFSX_FATTR);
527 nfsm_build(p, u_long *, NFSX_FATTR);
528 *p++ = vtonfs_type(vap->va_type);
529 *p++ = vtonfs_mode(vap->va_type, vap->va_mode);
530 *p++ = txdr_unsigned(vap->va_nlink);
531 *p++ = txdr_unsigned(vap->va_uid);
532 *p++ = txdr_unsigned(vap->va_gid);
533 *p++ = txdr_unsigned(vap->va_size);
534 *p++ = txdr_unsigned(vap->va_blocksize);
535 *p++ = txdr_unsigned(vap->va_rdev);
536 *p++ = txdr_unsigned(vap->va_bytes);
537 *p++ = txdr_unsigned(vap->va_fsid);
538 *p++ = txdr_unsigned(vap->va_fileid);
539 txdr_time(&(vap->va_atime), p);
540 p += 2;
541 txdr_time(&(vap->va_mtime), p);
542 p += 2;
543 txdr_time(&(vap->va_ctime), p);
544 nfsm_srvdone;
545}
546
547/*
548 * nfs create service
549 * now does a truncate to 0 length via. setattr if it already exists
550 */
551nfsrv_create(mrep, md, dpos, cred, xid, mrq)
552 struct mbuf *mrep, *md, **mrq;
553 caddr_t dpos;
554 struct ucred *cred;
555 long xid;
556{
557 struct vattr va;
558 register struct vattr *vap = &va;
559 register struct nameidata *ndp = &u.u_nd;
560 nfsm_srvars;
561 struct vnode *vp;
562 nfsv2fh_t nfh;
563 fhandle_t *fhp;
564 long len;
565
566 ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
567 fhp = &nfh.fh_generic;
568 nfsm_srvmtofh(fhp);
569 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
570 ndp->ni_cred = cred;
571 ndp->ni_nameiop = CREATE | LOCKPARENT | LOCKLEAF;
971b93e3
KM
572 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
573 nfsm_reply(0);
574 vattr_null(vap);
575 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
576 /*
577 * Iff doesn't exist, create it
578 * otherwise just truncate to 0 length
579 * should I set the mode too ??
580 */
581 if (ndp->ni_vp == NULL) {
582 vap->va_type = VREG;
583 vap->va_mode = nfstov_mode(*p++);
584 if (error = VOP_CREATE(ndp, vap))
585 nfsm_reply(0);
36c3043b 586 vp = ndp->ni_vp;
971b93e3 587 } else {
36c3043b
KM
588 vp = ndp->ni_vp;
589 ndp->ni_vp = (struct vnode *)0;
590 VOP_ABORTOP(ndp);
971b93e3 591 vap->va_size = 0;
36c3043b 592 if (error = VOP_SETATTR(vp, vap, cred))
971b93e3 593 nfsm_reply(0);
971b93e3 594 }
971b93e3
KM
595 bzero((caddr_t)fhp, sizeof(nfh));
596 fhp->fh_fsid = vp->v_mount->m_fsid;
597 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
598 vput(vp);
599 nfsm_reply(0);
600 }
601 error = VOP_GETATTR(vp, vap, cred);
602 vput(vp);
603 nfsm_reply(NFSX_FH+NFSX_FATTR);
604 nfsm_srvfhtom(fhp);
605 nfsm_build(p, u_long *, NFSX_FATTR);
606 *p++ = vtonfs_type(vap->va_type);
607 *p++ = vtonfs_mode(vap->va_type, vap->va_mode);
608 *p++ = txdr_unsigned(vap->va_nlink);
609 *p++ = txdr_unsigned(vap->va_uid);
610 *p++ = txdr_unsigned(vap->va_gid);
611 *p++ = txdr_unsigned(vap->va_size);
612 *p++ = txdr_unsigned(vap->va_blocksize);
613 *p++ = txdr_unsigned(vap->va_rdev);
614 *p++ = txdr_unsigned(vap->va_bytes);
615 *p++ = txdr_unsigned(vap->va_fsid);
616 *p++ = txdr_unsigned(vap->va_fileid);
617 txdr_time(&(vap->va_atime), p);
618 p += 2;
619 txdr_time(&(vap->va_mtime), p);
620 p += 2;
621 txdr_time(&(vap->va_ctime), p);
622 return (error);
623nfsmout:
624 VOP_ABORTOP(ndp);
625 return (error);
626}
627
628/*
629 * nfs remove service
630 */
631nfsrv_remove(mrep, md, dpos, cred, xid, mrq)
632 struct mbuf *mrep, *md, **mrq;
633 caddr_t dpos;
634 struct ucred *cred;
635 long xid;
636{
637 register struct nameidata *ndp = &u.u_nd;
638 nfsm_srvars;
639 struct vnode *vp;
640 nfsv2fh_t nfh;
641 fhandle_t *fhp;
642 long len;
643
644 fhp = &nfh.fh_generic;
645 nfsm_srvmtofh(fhp);
646 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
647 ndp->ni_cred = cred;
648 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
971b93e3
KM
649 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
650 nfsm_reply(0);
651 vp = ndp->ni_vp;
652 if (vp->v_type == VDIR &&
653 (error = suser(cred, (short *)0)))
654 goto out;
655 /*
656 * Don't unlink a mounted file.
657 */
658 if (vp->v_flag & VROOT) {
659 error = EBUSY;
660 goto out;
661 }
662 if (vp->v_flag & VTEXT)
663 xrele(vp); /* try once to free text */
664out:
665 if (error)
666 VOP_ABORTOP(ndp);
667 else
668 error = VOP_REMOVE(ndp);
669 nfsm_reply(0);
670 nfsm_srvdone;
671}
672
673/*
674 * nfs rename service
971b93e3
KM
675 */
676nfsrv_rename(mrep, md, dpos, cred, xid, mrq)
677 struct mbuf *mrep, *md, **mrq;
678 caddr_t dpos;
679 struct ucred *cred;
680 long xid;
681{
36c3043b 682 register struct nameidata *ndp;
971b93e3 683 nfsm_srvars;
36c3043b 684 struct nameidata tond;
971b93e3
KM
685 struct vnode *fvp, *tvp, *tdvp;
686 nfsv2fh_t fnfh, tnfh;
687 fhandle_t *ffhp, *tfhp;
688 long len, len2;
689 int rootflg = 0;
690
36c3043b
KM
691 ndp = &u.u_nd;
692 ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
971b93e3
KM
693 ffhp = &fnfh.fh_generic;
694 tfhp = &tnfh.fh_generic;
695 nfsm_srvmtofh(ffhp);
696 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
697 /*
698 * Remember if we are root so that we can reset cr_uid before
699 * the second nfs_namei() call
700 */
701 if (cred->cr_uid == 0)
702 rootflg++;
36c3043b
KM
703 ndp->ni_cred = cred;
704 ndp->ni_nameiop = DELETE | WANTPARENT;
705 if (error = nfs_namei(ndp, ffhp, len, &md, &dpos))
971b93e3 706 nfsm_reply(0);
36c3043b 707 fvp = ndp->ni_vp;
971b93e3
KM
708 nfsm_srvmtofh(tfhp);
709 nfsm_srvstrsiz(len2, NFS_MAXNAMLEN);
710 if (rootflg)
711 cred->cr_uid = 0;
36c3043b
KM
712 nddup(ndp, &tond);
713 tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
714 error = nfs_namei(&tond, tfhp, len2, &md, &dpos);
715 tdvp = tond.ni_dvp;
716 tvp = tond.ni_vp;
971b93e3
KM
717 if (tvp != NULL) {
718 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
719 error = EISDIR;
720 goto out;
721 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
722 error = ENOTDIR;
723 goto out;
724 }
725 }
726 if (error) {
36c3043b 727 VOP_ABORTOP(ndp);
971b93e3
KM
728 goto out1;
729 }
730 if (fvp->v_mount != tdvp->v_mount) {
731 error = EXDEV;
732 goto out;
733 }
734 if (fvp == tdvp || fvp == tvp)
735 error = EINVAL;
736out:
737 if (error) {
36c3043b
KM
738 VOP_ABORTOP(&tond);
739 VOP_ABORTOP(ndp);
971b93e3 740 } else {
107d27c5 741 VREF(tond.ni_cdir);
36c3043b 742 error = VOP_RENAME(ndp, &tond);
107d27c5 743 vrele(tond.ni_cdir);
971b93e3
KM
744 }
745out1:
107d27c5 746 ndrele(ndp);
971b93e3
KM
747 nfsm_reply(0);
748 return (error);
749nfsmout:
36c3043b 750 VOP_ABORTOP(ndp);
971b93e3
KM
751 return (error);
752}
753
754/*
755 * nfs link service
756 */
757nfsrv_link(mrep, md, dpos, cred, xid, mrq)
758 struct mbuf *mrep, *md, **mrq;
759 caddr_t dpos;
760 struct ucred *cred;
761 long xid;
762{
763 register struct nameidata *ndp = &u.u_nd;
764 nfsm_srvars;
765 struct vnode *vp, *xp;
766 nfsv2fh_t nfh, dnfh;
767 fhandle_t *fhp, *dfhp;
768 long len;
769
770 fhp = &nfh.fh_generic;
771 dfhp = &dnfh.fh_generic;
772 nfsm_srvmtofh(fhp);
773 nfsm_srvmtofh(dfhp);
774 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
775 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred))
776 nfsm_reply(0);
777 if (vp->v_type == VDIR && (error = suser(cred, NULL)))
778 goto out1;
779 ndp->ni_cred = cred;
780 ndp->ni_nameiop = CREATE | LOCKPARENT;
971b93e3
KM
781 if (error = nfs_namei(ndp, dfhp, len, &md, &dpos))
782 goto out1;
783 xp = ndp->ni_vp;
784 if (xp != NULL) {
785 error = EEXIST;
786 goto out;
787 }
788 xp = ndp->ni_dvp;
789 if (vp->v_mount != xp->v_mount)
790 error = EXDEV;
791out:
792 if (error)
793 VOP_ABORTOP(ndp);
794 else
795 error = VOP_LINK(vp, ndp);
796out1:
797 vrele(vp);
798 nfsm_reply(0);
799 nfsm_srvdone;
800}
801
802/*
803 * nfs symbolic link service
804 */
805nfsrv_symlink(mrep, md, dpos, cred, xid, mrq)
806 struct mbuf *mrep, *md, **mrq;
807 caddr_t dpos;
808 struct ucred *cred;
809 long xid;
810{
811 struct vattr va;
812 register struct nameidata *ndp = &u.u_nd;
813 register struct vattr *vap = &va;
814 nfsm_srvars;
815 struct vnode *vp;
816 nfsv2fh_t nfh;
817 fhandle_t *fhp;
818 long len, tlen, len2;
819
820 ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
821 fhp = &nfh.fh_generic;
822 nfsm_srvmtofh(fhp);
823 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
824 ndp->ni_cred = cred;
825 ndp->ni_nameiop = CREATE | LOCKPARENT;
971b93e3
KM
826 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
827 goto out1;
828 nfsm_srvstrsiz(len2, NFS_MAXPATHLEN);
829 tlen = nfsm_rndup(len2);
830 if (len2 == tlen) {
831 nfsm_disect(cp2, caddr_t, tlen+NFSX_UNSIGNED);
832 *(cp2+tlen) = '\0';
833 } else {
834 nfsm_disect(cp2, caddr_t, tlen);
835 }
836 vp = ndp->ni_vp;
837 if (vp) {
838 error = EEXIST;
839 goto out;
840 }
841 vp = ndp->ni_dvp;
842 vattr_null(vap);
843 vap->va_mode = 0777;
844out:
845 if (error)
846 VOP_ABORTOP(ndp);
847 else
848 error = VOP_SYMLINK(ndp, vap, cp2);
849out1:
850 nfsm_reply(0);
851 return (error);
852nfsmout:
853 VOP_ABORTOP(ndp);
854 return (error);
855}
856
857/*
858 * nfs mkdir service
859 */
860nfsrv_mkdir(mrep, md, dpos, cred, xid, mrq)
861 struct mbuf *mrep, *md, **mrq;
862 caddr_t dpos;
863 struct ucred *cred;
864 long xid;
865{
866 struct vattr va;
867 register struct vattr *vap = &va;
868 register struct nameidata *ndp = &u.u_nd;
869 nfsm_srvars;
870 struct vnode *vp;
871 nfsv2fh_t nfh;
872 fhandle_t *fhp;
873 long len;
874
875 ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
876 fhp = &nfh.fh_generic;
877 nfsm_srvmtofh(fhp);
878 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
879 ndp->ni_cred = cred;
880 ndp->ni_nameiop = CREATE | LOCKPARENT;
971b93e3
KM
881 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
882 nfsm_reply(0);
883 nfsm_disect(p, u_long *, NFSX_UNSIGNED);
884 vattr_null(vap);
885 vap->va_type = VDIR;
886 vap->va_mode = nfstov_mode(*p++);
887 vp = ndp->ni_vp;
888 if (vp != NULL) {
889 VOP_ABORTOP(ndp);
890 error = EEXIST;
891 nfsm_reply(0);
892 }
893 if (error = VOP_MKDIR(ndp, vap))
894 nfsm_reply(0);
895 vp = ndp->ni_vp;
896 bzero((caddr_t)fhp, sizeof(nfh));
897 fhp->fh_fsid = vp->v_mount->m_fsid;
898 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
899 vput(vp);
900 nfsm_reply(0);
901 }
902 error = VOP_GETATTR(vp, vap, cred);
903 vput(vp);
904 nfsm_reply(NFSX_FH+NFSX_FATTR);
905 nfsm_srvfhtom(fhp);
906 nfsm_build(p, u_long *, NFSX_FATTR);
907 *p++ = vtonfs_type(vap->va_type);
908 *p++ = vtonfs_mode(vap->va_type, vap->va_mode);
909 *p++ = txdr_unsigned(vap->va_nlink);
910 *p++ = txdr_unsigned(vap->va_uid);
911 *p++ = txdr_unsigned(vap->va_gid);
912 *p++ = txdr_unsigned(vap->va_size);
913 *p++ = txdr_unsigned(vap->va_blocksize);
914 *p++ = txdr_unsigned(vap->va_rdev);
915 *p++ = txdr_unsigned(vap->va_bytes);
916 *p++ = txdr_unsigned(vap->va_fsid);
917 *p++ = txdr_unsigned(vap->va_fileid);
918 txdr_time(&(vap->va_atime), p);
919 p += 2;
920 txdr_time(&(vap->va_mtime), p);
921 p += 2;
922 txdr_time(&(vap->va_ctime), p);
923 return (error);
924nfsmout:
925 VOP_ABORTOP(ndp);
926 return (error);
927}
928
929/*
930 * nfs rmdir service
931 */
932nfsrv_rmdir(mrep, md, dpos, cred, xid, mrq)
933 struct mbuf *mrep, *md, **mrq;
934 caddr_t dpos;
935 struct ucred *cred;
936 long xid;
937{
938 register struct nameidata *ndp = &u.u_nd;
939 nfsm_srvars;
940 struct vnode *vp;
941 nfsv2fh_t nfh;
942 fhandle_t *fhp;
943 long len;
944
945 fhp = &nfh.fh_generic;
946 nfsm_srvmtofh(fhp);
947 nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
948 ndp->ni_cred = cred;
949 ndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
971b93e3
KM
950 if (error = nfs_namei(ndp, fhp, len, &md, &dpos))
951 nfsm_reply(0);
952 vp = ndp->ni_vp;
953 if (vp->v_type != VDIR) {
954 error = ENOTDIR;
955 goto out;
956 }
957 /*
958 * No rmdir "." please.
959 */
960 if (ndp->ni_dvp == vp) {
961 error = EINVAL;
962 goto out;
963 }
964 /*
965 * Don't unlink a mounted file.
966 */
967 if (vp->v_flag & VROOT)
968 error = EBUSY;
969out:
970 if (error)
971 VOP_ABORTOP(ndp);
972 else
973 error = VOP_RMDIR(ndp);
974 nfsm_reply(0);
975 nfsm_srvdone;
976}
977
978/*
979 * nfs readdir service
980 * - mallocs what it thinks is enough to read
36c3043b 981 * count rounded up to a multiple of DIRBLKSIZ <= MAX_READDIR
971b93e3
KM
982 * - calls VOP_READDIR()
983 * - loops arround building the reply
36c3043b
KM
984 * if the output generated exceeds count break out of loop
985 * The nfsm_clget macro is used here so that the reply will be packed
986 * tightly in mbuf clusters.
971b93e3 987 * - it only knows that it has encountered eof when the VOP_READDIR()
36c3043b 988 * reads nothing
971b93e3 989 * - as such one readdir rpc will return eof false although you are there
36c3043b 990 * and then the next will return eof
971b93e3 991 * - it trims out records with d_ino == 0
36c3043b
KM
992 * this doesn't matter for Unix clients, but they might confuse clients
993 * for other os'.
971b93e3 994 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
36c3043b
KM
995 * than requested, but this may not apply to all filesystems. For
996 * example, client NFS does not { although it is never remote mounted
997 * anyhow }
971b93e3 998 * PS: The NFS protocol spec. does not clarify what the "count" byte
36c3043b
KM
999 * argument is a count of.. just name strings and file id's or the
1000 * entire reply rpc or ...
1001 * I tried just file name and id sizes and it confused the Sun client,
1002 * so I am using the full rpc size now. The "paranoia.." comment refers
1003 * to including the status longwords that are not a part of the dir.
1004 * "entry" structures, but are in the rpc.
971b93e3
KM
1005 */
1006nfsrv_readdir(mrep, md, dpos, cred, xid, mrq)
1007 struct mbuf **mrq;
1008 struct mbuf *mrep, *md;
1009 caddr_t dpos;
1010 struct ucred *cred;
1011 u_long xid;
1012{
1013 register char *bp, *be;
1014 register struct mbuf *mp;
1015 register struct direct *dp;
1016 nfsm_srvars;
1017 char *cpos, *cend;
1018 int len, nlen, rem, xfer, tsiz, i;
1019 struct vnode *vp;
1020 struct mbuf *mp2, *mp3;
1021 nfsv2fh_t nfh;
1022 fhandle_t *fhp;
1023 struct uio io;
1024 struct iovec iv;
1025 int siz, cnt, fullsiz;
1026 u_long on;
1027 char *rbuf;
1028 off_t off, toff;
1029
1030 fhp = &nfh.fh_generic;
1031 nfsm_srvmtofh(fhp);
1032 nfsm_disect(p, u_long *, 2*NFSX_UNSIGNED);
1033 toff = fxdr_unsigned(off_t, *p++);
1034 off = (toff & ~(DIRBLKSIZ-1));
1035 on = (toff & (DIRBLKSIZ-1));
1036 cnt = fxdr_unsigned(int, *p);
1037 siz = ((cnt+DIRBLKSIZ) & ~(DIRBLKSIZ-1));
1038 if (cnt > MAX_READDIR)
1039 siz = MAX_READDIR;
1040 fullsiz = siz;
1041 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
1042 nfsm_reply(0);
24ed1a73 1043 if (error = nfsrv_access(vp, VEXEC, cred)) {
971b93e3
KM
1044 vput(vp);
1045 nfsm_reply(0);
1046 }
1047 VOP_UNLOCK(vp);
1048 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1049again:
1050 iv.iov_base = rbuf;
1051 iv.iov_len = fullsiz;
1052 io.uio_iov = &iv;
1053 io.uio_iovcnt = 1;
1054 io.uio_offset = off;
1055 io.uio_resid = fullsiz;
1056 io.uio_segflg = UIO_SYSSPACE;
1057 io.uio_rw = UIO_READ;
1058 error = VOP_READDIR(vp, &io, &off, cred);
1059 if (error) {
1060 vrele(vp);
1061 free((caddr_t)rbuf, M_TEMP);
1062 nfsm_reply(0);
1063 }
1064 if (io.uio_resid) {
1065 siz -= io.uio_resid;
1066
1067 /*
1068 * If nothing read, return eof
1069 * rpc reply
1070 */
1071 if (siz == 0) {
1072 vrele(vp);
1073 nfsm_reply(2*NFSX_UNSIGNED);
1074 nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
1075 *p++ = nfs_false;
1076 *p = nfs_true;
1077 FREE((caddr_t)rbuf, M_TEMP);
1078 return (0);
1079 }
1080 }
1081 cpos = rbuf+on;
1082 cend = rbuf+siz;
1083 dp = (struct direct *)cpos;
1084 /*
1085 * Check for degenerate cases of nothing useful read.
1086 * If so go try again
1087 */
1088 if (cpos >= cend || (dp->d_ino == 0 && (cpos+dp->d_reclen) >= cend)) {
1089 toff = off;
1090 siz = fullsiz;
1091 on = 0;
1092 goto again;
1093 }
1094 vrele(vp);
36c3043b 1095 len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */
971b93e3
KM
1096 bp = be = (caddr_t)0;
1097 mp3 = (struct mbuf *)0;
1098 nfsm_reply(siz);
1099
1100 /* Loop through the records and build reply */
1101 while (cpos < cend) {
1102 if (dp->d_ino != 0) {
1103 nlen = dp->d_namlen;
1104 rem = nfsm_rndup(nlen)-nlen;
36c3043b 1105
971b93e3
KM
1106 /*
1107 * As noted above, the NFS spec. is not clear about what
1108 * should be included in "count" as totalled up here in
1109 * "len".
1110 */
1111 len += (4*NFSX_UNSIGNED+nlen+rem);
1112 if (len > cnt)
1113 break;
36c3043b 1114
971b93e3
KM
1115 /* Build the directory record xdr from the direct entry */
1116 nfsm_clget;
1117 *p = nfs_true;
1118 bp += NFSX_UNSIGNED;
1119 nfsm_clget;
1120 *p = txdr_unsigned(dp->d_ino);
1121 bp += NFSX_UNSIGNED;
1122 nfsm_clget;
1123 *p = txdr_unsigned(nlen);
1124 bp += NFSX_UNSIGNED;
36c3043b 1125
971b93e3
KM
1126 /* And loop arround copying the name */
1127 xfer = nlen;
1128 cp = dp->d_name;
1129 while (xfer > 0) {
1130 nfsm_clget;
1131 if ((bp+xfer) > be)
1132 tsiz = be-bp;
1133 else
1134 tsiz = xfer;
1135 bcopy(cp, bp, tsiz);
1136 bp += tsiz;
1137 xfer -= tsiz;
1138 if (xfer > 0)
1139 cp += tsiz;
1140 }
1141 /* And null pad to a long boundary */
1142 for (i = 0; i < rem; i++)
1143 *bp++ = '\0';
1144 nfsm_clget;
36c3043b 1145
971b93e3
KM
1146 /* Finish off the record */
1147 toff += dp->d_reclen;
1148 *p = txdr_unsigned(toff);
1149 bp += NFSX_UNSIGNED;
1150 } else
1151 toff += dp->d_reclen;
1152 cpos += dp->d_reclen;
1153 dp = (struct direct *)cpos;
1154 }
1155 nfsm_clget;
1156 *p = nfs_false;
1157 bp += NFSX_UNSIGNED;
1158 nfsm_clget;
1159 *p = nfs_false;
1160 bp += NFSX_UNSIGNED;
1161 if (bp < be)
1162 mp->m_len = bp-mtod(mp, caddr_t);
1163 mb->m_next = mp3;
1164 FREE(rbuf, M_TEMP);
1165 nfsm_srvdone;
1166}
1167
1168/*
1169 * nfs statfs service
1170 */
1171nfsrv_statfs(mrep, md, dpos, cred, xid, mrq)
1172 struct mbuf **mrq;
1173 struct mbuf *mrep, *md;
1174 caddr_t dpos;
1175 struct ucred *cred;
1176 u_long xid;
1177{
1178 register struct statfs *sf;
1179 nfsm_srvars;
1180 struct vnode *vp;
1181 nfsv2fh_t nfh;
1182 fhandle_t *fhp;
1183 struct statfs statfs;
1184
1185 fhp = &nfh.fh_generic;
1186 nfsm_srvmtofh(fhp);
1187 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred))
1188 nfsm_reply(0);
1189 sf = &statfs;
1190 error = VFS_STATFS(vp->v_mount, sf);
1191 vput(vp);
1192 nfsm_reply(NFSX_STATFS);
1193 nfsm_build(p, u_long *, NFSX_STATFS);
36c3043b 1194 *p++ = txdr_unsigned(NFS_MAXDATA);
971b93e3
KM
1195 *p++ = txdr_unsigned(sf->f_fsize);
1196 *p++ = txdr_unsigned(sf->f_blocks);
1197 *p++ = txdr_unsigned(sf->f_bfree);
1198 *p = txdr_unsigned(sf->f_bavail);
1199 nfsm_srvdone;
1200}
1201
1202/*
1203 * Null operation, used by clients to ping server
1204 */
1205nfsrv_null(mrep, md, dpos, cred, xid, mrq)
1206 struct mbuf **mrq;
1207 struct mbuf *mrep, *md;
1208 caddr_t dpos;
1209 struct ucred *cred;
1210 u_long xid;
1211{
1212 nfsm_srvars;
1213
1214 error = VNOVAL;
1215 nfsm_reply(0);
1216 nfsm_srvdone;
1217}
1218
1219/*
1220 * No operation, used for obsolete procedures
1221 */
1222nfsrv_noop(mrep, md, dpos, cred, xid, mrq)
1223 struct mbuf **mrq;
1224 struct mbuf *mrep, *md;
1225 caddr_t dpos;
1226 struct ucred *cred;
1227 u_long xid;
1228{
1229 nfsm_srvars;
1230
1231 error = EPROCUNAVAIL;
1232 nfsm_reply(0);
1233 nfsm_srvdone;
1234}
36c3043b 1235
24ed1a73
KM
1236/*
1237 * Perform access checking for vnodes obtained from file handles that would
1238 * refer to files already opened by a Unix client. You cannot just use
1239 * vn_writechk() and VOP_ACCESS() for two reasons.
1240 * 1 - You must check for M_EXRDONLY as well as M_RDONLY for the write case
1241 * 2 - The owner is to be given access irrespective of mode bits so that
1242 * processes that chmod after opening a file don't break. I don't like
1243 * this because it opens a security hole, but since the nfs server opens
1244 * a security hole the size of a barn door anyhow, what the heck.
1245 */
1246nfsrv_access(vp, flags, cred)
1247 register struct vnode *vp;
1248 int flags;
1249 register struct ucred *cred;
1250{
1251 struct vattr vattr;
1252 int error;
1253 if (flags & VWRITE) {
1254 /* Just vn_writechk() changed to check M_EXRDONLY */
1255 /*
1256 * Disallow write attempts on read-only file systems;
1257 * unless the file is a socket or a block or character
1258 * device resident on the file system.
1259 */
1260 if ((vp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) &&
1261 vp->v_type != VCHR &&
1262 vp->v_type != VBLK &&
1263 vp->v_type != VSOCK)
1264 return (EROFS);
1265 /*
1266 * If there's shared text associated with
1267 * the inode, try to free it up once. If
1268 * we fail, we can't allow writing.
1269 */
1270 if (vp->v_flag & VTEXT)
1271 xrele(vp);
1272 if (vp->v_flag & VTEXT)
1273 return (ETXTBSY);
1274 if (error = VOP_GETATTR(vp, &vattr, cred))
1275 return (error);
1276 if (cred->cr_uid == vattr.va_uid)
1277 return (0);
1278 } else {
1279 if (error = VOP_GETATTR(vp, &vattr, cred))
1280 return (error);
1281 if (cred->cr_uid == vattr.va_uid)
1282 return (0);
1283 }
1284 return (VOP_ACCESS(vp, flags, cred));
1285}