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