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 * %sccs.include.redist.c% 9 * 10 * @(#)nfs_serv.c 7.55 (Berkeley) 07/12/92 11 */ 12 13 /* 14 * nfs version 2 server calls to vnode ops 15 * - these routines generally have 3 phases 16 * 1 - break down and validate rpc request in mbuf list 17 * 2 - do the vnode ops for the request 18 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 19 * 3 - build the rpc reply in an mbuf list 20 * nb: 21 * - do not mix the phases, since the nfsm_?? macros can return failures 22 * on a bad rpc or similar and do not do any vrele() or vput()'s 23 * 24 * - the nfsm_reply() macro generates an nfs rpc reply with the nfs 25 * error number iff error != 0 whereas 26 * returning an error from the server function implies a fatal error 27 * such as a badly constructed rpc request that should be dropped without 28 * a reply. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/proc.h> 33 #include <sys/file.h> 34 #include <sys/namei.h> 35 #include <sys/vnode.h> 36 #include <sys/mount.h> 37 #include <sys/mbuf.h> 38 #include <sys/dirent.h> 39 #include <sys/stat.h> 40 41 #include <vm/vm.h> 42 43 #include <nfs/nfsv2.h> 44 #include <nfs/rpcv2.h> 45 #include <nfs/nfs.h> 46 #include <nfs/xdr_subs.h> 47 #include <nfs/nfsm_subs.h> 48 #include <nfs/nqnfs.h> 49 50 /* Defs */ 51 #define TRUE 1 52 #define FALSE 0 53 54 /* Global vars */ 55 extern u_long nfs_procids[NFS_NPROCS]; 56 extern u_long nfs_xdrneg1; 57 extern u_long nfs_false, nfs_true; 58 nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 59 NFCHR, NFNON }; 60 61 /* 62 * nfs getattr service 63 */ 64 nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq) 65 struct nfsd *nfsd; 66 struct mbuf *mrep, *md; 67 caddr_t dpos; 68 struct ucred *cred; 69 struct mbuf *nam, **mrq; 70 { 71 register struct nfsv2_fattr *fp; 72 struct vattr va; 73 register struct vattr *vap = &va; 74 struct vnode *vp; 75 nfsv2fh_t nfh; 76 fhandle_t *fhp; 77 register u_long *tl; 78 register long t1; 79 caddr_t bpos; 80 int error = 0, rdonly, cache; 81 char *cp2; 82 struct mbuf *mb, *mb2, *mreq; 83 u_quad_t frev; 84 85 fhp = &nfh.fh_generic; 86 nfsm_srvmtofh(fhp); 87 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 88 nfsm_reply(0); 89 nqsrv_getl(vp, NQL_READ); 90 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 91 vput(vp); 92 nfsm_reply(NFSX_FATTR); 93 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 94 nfsm_srvfillattr; 95 nfsm_srvdone; 96 } 97 98 /* 99 * nfs setattr service 100 */ 101 nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq) 102 struct nfsd *nfsd; 103 struct mbuf *mrep, *md; 104 caddr_t dpos; 105 struct ucred *cred; 106 struct mbuf *nam, **mrq; 107 { 108 struct vattr va; 109 register struct vattr *vap = &va; 110 register struct nfsv2_sattr *sp; 111 register struct nfsv2_fattr *fp; 112 struct vnode *vp; 113 nfsv2fh_t nfh; 114 fhandle_t *fhp; 115 register u_long *tl; 116 register long t1; 117 caddr_t bpos; 118 int error = 0, rdonly, cache, duration2, cache2; 119 char *cp2; 120 struct mbuf *mb, *mb2, *mreq; 121 u_quad_t frev, frev2; 122 123 fhp = &nfh.fh_generic; 124 nfsm_srvmtofh(fhp); 125 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 126 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 127 nfsm_reply(0); 128 nqsrv_getl(vp, NQL_WRITE); 129 if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) 130 goto out; 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 */ 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); 145 if (sp->sa_size != nfs_xdrneg1) 146 vap->va_size = fxdr_unsigned(u_long, sp->sa_size); 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.ts_sec = fxdr_unsigned(long, sp->sa_atime.tv_sec); 154 vap->va_atime.ts_nsec = 0; 155 } 156 if (sp->sa_atime.tv_usec != nfs_xdrneg1) 157 vap->va_flags = fxdr_unsigned(u_long, sp->sa_atime.tv_usec); 158 if (sp->sa_mtime.tv_sec != nfs_xdrneg1) 159 fxdr_time(&sp->sa_mtime, &vap->va_mtime); 160 if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 161 vput(vp); 162 nfsm_reply(0); 163 } 164 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 165 out: 166 vput(vp); 167 nfsm_reply(NFSX_FATTR + 2*NFSX_UNSIGNED); 168 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 169 nfsm_srvfillattr; 170 if (nfsd->nd_nqlflag != NQL_NOVAL) { 171 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 172 txdr_hyper(&frev2, tl); 173 } 174 nfsm_srvdone; 175 } 176 177 /* 178 * nfs lookup rpc 179 */ 180 nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq) 181 struct nfsd *nfsd; 182 struct mbuf *mrep, *md; 183 caddr_t dpos; 184 struct ucred *cred; 185 struct mbuf *nam, **mrq; 186 { 187 register struct nfsv2_fattr *fp; 188 struct nameidata nd; 189 struct vnode *vp; 190 nfsv2fh_t nfh; 191 fhandle_t *fhp; 192 register caddr_t cp; 193 register u_long *tl; 194 register long t1; 195 caddr_t bpos; 196 int error = 0, lflag = 0, rdonly, cache, duration2, cache2, len; 197 char *cp2; 198 struct mbuf *mb, *mb2, *mreq; 199 struct vattr va, *vap = &va; 200 u_quad_t frev, frev2; 201 202 fhp = &nfh.fh_generic; 203 if (nfsd->nd_nqlflag != NQL_NOVAL) { 204 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 205 if (*tl) { 206 lflag = fxdr_unsigned(int, *tl); 207 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 208 duration2 = fxdr_unsigned(int, *tl); 209 } 210 } 211 nfsm_srvmtofh(fhp); 212 nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 213 nd.ni_cnd.cn_cred = cred; 214 nd.ni_cnd.cn_nameiop = LOOKUP; 215 nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; 216 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 217 nfsd->nd_procp)) 218 nfsm_reply(0); 219 nqsrv_getl(nd.ni_startdir, NQL_READ); 220 vrele(nd.ni_startdir); 221 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 222 vp = nd.ni_vp; 223 bzero((caddr_t)fhp, sizeof(nfh)); 224 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 225 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 226 vput(vp); 227 nfsm_reply(0); 228 } 229 if (lflag) 230 (void) nqsrv_getlease(vp, &duration2, lflag, nfsd, 231 nam, &cache2, &frev2, cred); 232 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 233 vput(vp); 234 nfsm_reply(NFSX_FH + NFSX_FATTR + 5*NFSX_UNSIGNED); 235 if (nfsd->nd_nqlflag != NQL_NOVAL) { 236 if (lflag) { 237 nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED); 238 *tl++ = txdr_unsigned(lflag); 239 *tl++ = txdr_unsigned(cache2); 240 *tl++ = txdr_unsigned(duration2); 241 txdr_hyper(&frev2, tl); 242 } else { 243 nfsm_build(tl, u_long *, NFSX_UNSIGNED); 244 *tl = 0; 245 } 246 } 247 nfsm_srvfhtom(fhp); 248 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 249 nfsm_srvfillattr; 250 nfsm_srvdone; 251 } 252 253 /* 254 * nfs readlink service 255 */ 256 nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq) 257 struct nfsd *nfsd; 258 struct mbuf *mrep, *md; 259 caddr_t dpos; 260 struct ucred *cred; 261 struct mbuf *nam, **mrq; 262 { 263 struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN]; 264 register struct iovec *ivp = iv; 265 register struct mbuf *mp; 266 register u_long *tl; 267 register long t1; 268 caddr_t bpos; 269 int error = 0, rdonly, cache, i, tlen, len; 270 char *cp2; 271 struct mbuf *mb, *mb2, *mp2, *mp3, *mreq; 272 struct vnode *vp; 273 nfsv2fh_t nfh; 274 fhandle_t *fhp; 275 struct uio io, *uiop = &io; 276 u_quad_t frev; 277 278 fhp = &nfh.fh_generic; 279 nfsm_srvmtofh(fhp); 280 len = 0; 281 i = 0; 282 while (len < NFS_MAXPATHLEN) { 283 MGET(mp, M_WAIT, MT_DATA); 284 MCLGET(mp, M_WAIT); 285 mp->m_len = NFSMSIZ(mp); 286 if (len == 0) 287 mp3 = mp2 = mp; 288 else { 289 mp2->m_next = mp; 290 mp2 = mp; 291 } 292 if ((len+mp->m_len) > NFS_MAXPATHLEN) { 293 mp->m_len = NFS_MAXPATHLEN-len; 294 len = NFS_MAXPATHLEN; 295 } else 296 len += mp->m_len; 297 ivp->iov_base = mtod(mp, caddr_t); 298 ivp->iov_len = mp->m_len; 299 i++; 300 ivp++; 301 } 302 uiop->uio_iov = iv; 303 uiop->uio_iovcnt = i; 304 uiop->uio_offset = 0; 305 uiop->uio_resid = len; 306 uiop->uio_rw = UIO_READ; 307 uiop->uio_segflg = UIO_SYSSPACE; 308 uiop->uio_procp = (struct proc *)0; 309 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) { 310 m_freem(mp3); 311 nfsm_reply(0); 312 } 313 if (vp->v_type != VLNK) { 314 error = EINVAL; 315 goto out; 316 } 317 nqsrv_getl(vp, NQL_READ); 318 error = VOP_READLINK(vp, uiop, cred); 319 out: 320 vput(vp); 321 if (error) 322 m_freem(mp3); 323 nfsm_reply(NFSX_UNSIGNED); 324 if (uiop->uio_resid > 0) { 325 len -= uiop->uio_resid; 326 tlen = nfsm_rndup(len); 327 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len); 328 } 329 nfsm_build(tl, u_long *, NFSX_UNSIGNED); 330 *tl = txdr_unsigned(len); 331 mb->m_next = mp3; 332 nfsm_srvdone; 333 } 334 335 /* 336 * nfs read service 337 */ 338 nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq) 339 struct nfsd *nfsd; 340 struct mbuf *mrep, *md; 341 caddr_t dpos; 342 struct ucred *cred; 343 struct mbuf *nam, **mrq; 344 { 345 register struct iovec *iv; 346 struct iovec *iv2; 347 register struct mbuf *m; 348 register struct nfsv2_fattr *fp; 349 register u_long *tl; 350 register long t1; 351 caddr_t bpos; 352 int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen; 353 char *cp2; 354 struct mbuf *mb, *mb2, *mreq; 355 struct mbuf *m2; 356 struct vnode *vp; 357 nfsv2fh_t nfh; 358 fhandle_t *fhp; 359 struct uio io, *uiop = &io; 360 struct vattr va, *vap = &va; 361 off_t off; 362 u_quad_t frev; 363 364 fhp = &nfh.fh_generic; 365 nfsm_srvmtofh(fhp); 366 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 367 off = fxdr_unsigned(off_t, *tl); 368 nfsm_srvstrsiz(cnt, NFS_MAXDATA); 369 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 370 nfsm_reply(0); 371 nqsrv_getl(vp, NQL_READ); 372 if (error = nfsrv_access(vp, VREAD | VEXEC, cred, rdonly, nfsd->nd_procp)) { 373 vput(vp); 374 nfsm_reply(0); 375 } 376 if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) { 377 vput(vp); 378 nfsm_reply(0); 379 } 380 if (off >= vap->va_size) 381 cnt = 0; 382 else if ((off + cnt) > vap->va_size) 383 cnt = nfsm_rndup(vap->va_size - off); 384 nfsm_reply(NFSX_FATTR+NFSX_UNSIGNED+nfsm_rndup(cnt)); 385 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 386 nfsm_build(tl, u_long *, NFSX_UNSIGNED); 387 len = left = cnt; 388 if (cnt > 0) { 389 /* 390 * Generate the mbuf list with the uio_iov ref. to it. 391 */ 392 i = 0; 393 m = m2 = mb; 394 MALLOC(iv, struct iovec *, 395 ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec), 396 M_TEMP, M_WAITOK); 397 iv2 = iv; 398 while (left > 0) { 399 siz = min(M_TRAILINGSPACE(m), left); 400 if (siz > 0) { 401 m->m_len += siz; 402 iv->iov_base = bpos; 403 iv->iov_len = siz; 404 iv++; 405 i++; 406 left -= siz; 407 } 408 if (left > 0) { 409 MGET(m, M_WAIT, MT_DATA); 410 MCLGET(m, M_WAIT); 411 m->m_len = 0; 412 m2->m_next = m; 413 m2 = m; 414 bpos = mtod(m, caddr_t); 415 } 416 } 417 uiop->uio_iov = iv2; 418 uiop->uio_iovcnt = i; 419 uiop->uio_offset = off; 420 uiop->uio_resid = cnt; 421 uiop->uio_rw = UIO_READ; 422 uiop->uio_segflg = UIO_SYSSPACE; 423 error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 424 off = uiop->uio_offset; 425 FREE((caddr_t)iv2, M_TEMP); 426 if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) { 427 m_freem(mreq); 428 vput(vp); 429 nfsm_reply(0); 430 } 431 } else 432 uiop->uio_resid = 0; 433 vput(vp); 434 nfsm_srvfillattr; 435 len -= uiop->uio_resid; 436 tlen = nfsm_rndup(len); 437 if (cnt != tlen || tlen != len) 438 nfsm_adj(mb, cnt-tlen, tlen-len); 439 *tl = txdr_unsigned(len); 440 nfsm_srvdone; 441 } 442 443 /* 444 * nfs write service 445 */ 446 nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq) 447 struct nfsd *nfsd; 448 struct mbuf *mrep, *md; 449 caddr_t dpos; 450 struct ucred *cred; 451 struct mbuf *nam, **mrq; 452 { 453 register struct iovec *ivp; 454 register struct mbuf *mp; 455 register struct nfsv2_fattr *fp; 456 struct iovec iv[NFS_MAXIOVEC]; 457 struct vattr va; 458 register struct vattr *vap = &va; 459 register u_long *tl; 460 register long t1; 461 caddr_t bpos; 462 int error = 0, rdonly, cache, siz, len, xfer; 463 char *cp2; 464 struct mbuf *mb, *mb2, *mreq; 465 struct vnode *vp; 466 nfsv2fh_t nfh; 467 fhandle_t *fhp; 468 struct uio io, *uiop = &io; 469 off_t off; 470 u_quad_t frev; 471 472 fhp = &nfh.fh_generic; 473 nfsm_srvmtofh(fhp); 474 nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED); 475 off = fxdr_unsigned(off_t, *++tl); 476 tl += 2; 477 len = fxdr_unsigned(long, *tl); 478 if (len > NFS_MAXDATA || len <= 0) { 479 error = EBADRPC; 480 nfsm_reply(0); 481 } 482 if (dpos == (mtod(md, caddr_t)+md->m_len)) { 483 mp = md->m_next; 484 if (mp == NULL) { 485 error = EBADRPC; 486 nfsm_reply(0); 487 } 488 } else { 489 mp = md; 490 siz = dpos-mtod(mp, caddr_t); 491 mp->m_len -= siz; 492 NFSMADV(mp, siz); 493 } 494 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 495 nfsm_reply(0); 496 nqsrv_getl(vp, NQL_WRITE); 497 if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) { 498 vput(vp); 499 nfsm_reply(0); 500 } 501 uiop->uio_resid = 0; 502 uiop->uio_rw = UIO_WRITE; 503 uiop->uio_segflg = UIO_SYSSPACE; 504 uiop->uio_procp = (struct proc *)0; 505 /* 506 * Do up to NFS_MAXIOVEC mbufs of write each iteration of the 507 * loop until done. 508 */ 509 while (len > 0 && uiop->uio_resid == 0) { 510 ivp = iv; 511 siz = 0; 512 uiop->uio_iov = ivp; 513 uiop->uio_iovcnt = 0; 514 uiop->uio_offset = off; 515 while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) { 516 ivp->iov_base = mtod(mp, caddr_t); 517 if (len < mp->m_len) 518 ivp->iov_len = xfer = len; 519 else 520 ivp->iov_len = xfer = mp->m_len; 521 #ifdef notdef 522 /* Not Yet .. */ 523 if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0) 524 ivp->iov_op = NULL; /* what should it be ?? */ 525 else 526 ivp->iov_op = NULL; 527 #endif 528 uiop->uio_iovcnt++; 529 ivp++; 530 len -= xfer; 531 siz += xfer; 532 mp = mp->m_next; 533 } 534 if (len > 0 && mp == NULL) { 535 error = EBADRPC; 536 vput(vp); 537 nfsm_reply(0); 538 } 539 uiop->uio_resid = siz; 540 if (error = VOP_WRITE(vp, uiop, IO_SYNC | IO_NODELOCKED, 541 cred)) { 542 vput(vp); 543 nfsm_reply(0); 544 } 545 off = uiop->uio_offset; 546 } 547 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 548 vput(vp); 549 nfsm_reply(NFSX_FATTR); 550 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 551 nfsm_srvfillattr; 552 if (nfsd->nd_nqlflag != NQL_NOVAL) { 553 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 554 txdr_hyper(&vap->va_filerev, tl); 555 } 556 nfsm_srvdone; 557 } 558 559 /* 560 * nfs create service 561 * now does a truncate to 0 length via. setattr if it already exists 562 */ 563 nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq) 564 struct nfsd *nfsd; 565 struct mbuf *mrep, *md; 566 caddr_t dpos; 567 struct ucred *cred; 568 struct mbuf *nam, **mrq; 569 { 570 register struct nfsv2_fattr *fp; 571 struct vattr va; 572 register struct vattr *vap = &va; 573 struct nameidata nd; 574 register caddr_t cp; 575 register u_long *tl; 576 register long t1; 577 caddr_t bpos; 578 int error = 0, rdev, cache, len; 579 char *cp2; 580 struct mbuf *mb, *mb2, *mreq; 581 struct vnode *vp; 582 nfsv2fh_t nfh; 583 fhandle_t *fhp; 584 u_quad_t frev; 585 586 nd.ni_cnd.cn_nameiop = 0; 587 fhp = &nfh.fh_generic; 588 nfsm_srvmtofh(fhp); 589 nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 590 nd.ni_cnd.cn_cred = cred; 591 nd.ni_cnd.cn_nameiop = CREATE; 592 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART; 593 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 594 nfsd->nd_procp)) 595 nfsm_reply(0); 596 VATTR_NULL(vap); 597 nfsm_dissect(tl, u_long *, NFSX_SATTR); 598 /* 599 * Iff doesn't exist, create it 600 * otherwise just truncate to 0 length 601 * should I set the mode too ?? 602 */ 603 if (nd.ni_vp == NULL) { 604 vap->va_type = IFTOVT(fxdr_unsigned(u_long, *tl)); 605 if (vap->va_type == VNON) 606 vap->va_type = VREG; 607 vap->va_mode = nfstov_mode(*tl); 608 rdev = fxdr_unsigned(long, *(tl+3)); 609 if (vap->va_type == VREG || vap->va_type == VSOCK) { 610 vrele(nd.ni_startdir); 611 nqsrv_getl(nd.ni_dvp, NQL_WRITE); 612 if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 613 nfsm_reply(0); 614 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 615 } else if (vap->va_type == VCHR || vap->va_type == VBLK || 616 vap->va_type == VFIFO) { 617 if (vap->va_type == VCHR && rdev == 0xffffffff) 618 vap->va_type = VFIFO; 619 if (vap->va_type == VFIFO) { 620 #ifndef FIFO 621 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 622 vput(nd.ni_dvp); 623 error = ENXIO; 624 goto out; 625 #endif /* FIFO */ 626 } else if (error = suser(cred, (u_short *)0)) { 627 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 628 vput(nd.ni_dvp); 629 goto out; 630 } else 631 vap->va_rdev = (dev_t)rdev; 632 nqsrv_getl(nd.ni_dvp, NQL_WRITE); 633 if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) { 634 vrele(nd.ni_startdir); 635 nfsm_reply(0); 636 } 637 nd.ni_cnd.cn_nameiop = LOOKUP; 638 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 639 nd.ni_cnd.cn_proc = nfsd->nd_procp; 640 nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred; 641 if (error = lookup(&nd)) { 642 free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 643 nfsm_reply(0); 644 } 645 FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI); 646 if (nd.ni_cnd.cn_flags & ISSYMLINK) { 647 vrele(nd.ni_dvp); 648 vput(nd.ni_vp); 649 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 650 error = EINVAL; 651 nfsm_reply(0); 652 } 653 } else { 654 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 655 vput(nd.ni_dvp); 656 error = ENXIO; 657 goto out; 658 } 659 vp = nd.ni_vp; 660 } else { 661 vrele(nd.ni_startdir); 662 free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 663 vp = nd.ni_vp; 664 if (nd.ni_dvp == vp) 665 vrele(nd.ni_dvp); 666 else 667 vput(nd.ni_dvp); 668 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 669 vap->va_size = 0; 670 nqsrv_getl(vp, NQL_WRITE); 671 if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) { 672 vput(vp); 673 nfsm_reply(0); 674 } 675 } 676 bzero((caddr_t)fhp, sizeof(nfh)); 677 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 678 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 679 vput(vp); 680 nfsm_reply(0); 681 } 682 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 683 vput(vp); 684 nfsm_reply(NFSX_FH+NFSX_FATTR); 685 nfsm_srvfhtom(fhp); 686 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 687 nfsm_srvfillattr; 688 return (error); 689 nfsmout: 690 if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags) 691 vrele(nd.ni_startdir); 692 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 693 if (nd.ni_dvp == nd.ni_vp) 694 vrele(nd.ni_dvp); 695 else 696 vput(nd.ni_dvp); 697 if (nd.ni_vp) 698 vput(nd.ni_vp); 699 return (error); 700 701 out: 702 vrele(nd.ni_startdir); 703 free(nd.ni_cnd.cn_pnbuf, M_NAMEI); 704 nfsm_reply(0); 705 } 706 707 /* 708 * nfs remove service 709 */ 710 nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq) 711 struct nfsd *nfsd; 712 struct mbuf *mrep, *md; 713 caddr_t dpos; 714 struct ucred *cred; 715 struct mbuf *nam, **mrq; 716 { 717 struct nameidata nd; 718 register u_long *tl; 719 register long t1; 720 caddr_t bpos; 721 int error = 0, cache, len; 722 char *cp2; 723 struct mbuf *mb, *mreq; 724 struct vnode *vp; 725 nfsv2fh_t nfh; 726 fhandle_t *fhp; 727 u_quad_t frev; 728 729 fhp = &nfh.fh_generic; 730 nfsm_srvmtofh(fhp); 731 nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 732 nd.ni_cnd.cn_cred = cred; 733 nd.ni_cnd.cn_nameiop = DELETE; 734 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 735 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 736 nfsd->nd_procp)) 737 nfsm_reply(0); 738 vp = nd.ni_vp; 739 if (vp->v_type == VDIR && 740 (error = suser(cred, (u_short *)0))) 741 goto out; 742 /* 743 * The root of a mounted filesystem cannot be deleted. 744 */ 745 if (vp->v_flag & VROOT) { 746 error = EBUSY; 747 goto out; 748 } 749 if (vp->v_flag & VTEXT) 750 (void) vnode_pager_uncache(vp); 751 out: 752 if (!error) { 753 nqsrv_getl(nd.ni_dvp, NQL_WRITE); 754 nqsrv_getl(vp, NQL_WRITE); 755 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 756 } else { 757 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 758 if (nd.ni_dvp == vp) 759 vrele(nd.ni_dvp); 760 else 761 vput(nd.ni_dvp); 762 vput(vp); 763 } 764 nfsm_reply(0); 765 nfsm_srvdone; 766 } 767 768 /* 769 * nfs rename service 770 */ 771 nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq) 772 struct nfsd *nfsd; 773 struct mbuf *mrep, *md; 774 caddr_t dpos; 775 struct ucred *cred; 776 struct mbuf *nam, **mrq; 777 { 778 register u_long *tl; 779 register long t1; 780 caddr_t bpos; 781 int error = 0, rdonly, cache, len, len2; 782 char *cp2; 783 struct mbuf *mb, *mreq; 784 struct nameidata fromnd, tond; 785 struct vnode *fvp, *tvp, *tdvp; 786 nfsv2fh_t fnfh, tnfh; 787 fhandle_t *ffhp, *tfhp; 788 u_quad_t frev; 789 uid_t saved_uid; 790 791 ffhp = &fnfh.fh_generic; 792 tfhp = &tnfh.fh_generic; 793 fromnd.ni_cnd.cn_nameiop = 0; 794 tond.ni_cnd.cn_nameiop = 0; 795 nfsm_srvmtofh(ffhp); 796 nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 797 /* 798 * Remember our original uid so that we can reset cr_uid before 799 * the second nfs_namei() call, in case it is remapped. 800 */ 801 saved_uid = cred->cr_uid; 802 fromnd.ni_cnd.cn_cred = cred; 803 fromnd.ni_cnd.cn_nameiop = DELETE; 804 fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 805 if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md, 806 &dpos, nfsd->nd_procp)) 807 nfsm_reply(0); 808 fvp = fromnd.ni_vp; 809 nfsm_srvmtofh(tfhp); 810 nfsm_strsiz(len2, NFS_MAXNAMLEN); 811 cred->cr_uid = saved_uid; 812 tond.ni_cnd.cn_cred = cred; 813 tond.ni_cnd.cn_nameiop = RENAME; 814 tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 815 if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md, 816 &dpos, nfsd->nd_procp)) { 817 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 818 vrele(fromnd.ni_dvp); 819 vrele(fvp); 820 goto out1; 821 } 822 tdvp = tond.ni_dvp; 823 tvp = tond.ni_vp; 824 if (tvp != NULL) { 825 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 826 error = EISDIR; 827 goto out; 828 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 829 error = ENOTDIR; 830 goto out; 831 } 832 if (tvp->v_type == VDIR && tvp->v_mountedhere) { 833 error = EXDEV; 834 goto out; 835 } 836 } 837 if (fvp->v_type == VDIR && fvp->v_mountedhere) { 838 error = EBUSY; 839 goto out; 840 } 841 if (fvp->v_mount != tdvp->v_mount) { 842 error = EXDEV; 843 goto out; 844 } 845 if (fvp == tdvp) 846 error = EINVAL; 847 /* 848 * If source is the same as the destination (that is the 849 * same vnode with the same name in the same directory), 850 * then there is nothing to do. 851 */ 852 if (fvp == tvp && fromnd.ni_dvp == tdvp && 853 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 854 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 855 fromnd.ni_cnd.cn_namelen)) 856 error = -1; 857 out: 858 if (!error) { 859 nqsrv_getl(fromnd.ni_dvp, NQL_WRITE); 860 nqsrv_getl(tdvp, NQL_WRITE); 861 if (tvp) 862 nqsrv_getl(tvp, NQL_WRITE); 863 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 864 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 865 } else { 866 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 867 if (tdvp == tvp) 868 vrele(tdvp); 869 else 870 vput(tdvp); 871 if (tvp) 872 vput(tvp); 873 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 874 vrele(fromnd.ni_dvp); 875 vrele(fvp); 876 } 877 vrele(tond.ni_startdir); 878 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 879 out1: 880 vrele(fromnd.ni_startdir); 881 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 882 nfsm_reply(0); 883 return (error); 884 885 nfsmout: 886 if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) { 887 vrele(tond.ni_startdir); 888 FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI); 889 } 890 if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) { 891 vrele(fromnd.ni_startdir); 892 FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI); 893 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 894 vrele(fromnd.ni_dvp); 895 vrele(fvp); 896 } 897 return (error); 898 } 899 900 /* 901 * nfs link service 902 */ 903 nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq) 904 struct nfsd *nfsd; 905 struct mbuf *mrep, *md; 906 caddr_t dpos; 907 struct ucred *cred; 908 struct mbuf *nam, **mrq; 909 { 910 struct nameidata nd; 911 register u_long *tl; 912 register long t1; 913 caddr_t bpos; 914 int error = 0, rdonly, cache, len; 915 char *cp2; 916 struct mbuf *mb, *mreq; 917 struct vnode *vp, *xp; 918 nfsv2fh_t nfh, dnfh; 919 fhandle_t *fhp, *dfhp; 920 u_quad_t frev; 921 922 fhp = &nfh.fh_generic; 923 dfhp = &dnfh.fh_generic; 924 nfsm_srvmtofh(fhp); 925 nfsm_srvmtofh(dfhp); 926 nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 927 if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 928 nfsm_reply(0); 929 if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0))) 930 goto out1; 931 nd.ni_cnd.cn_cred = cred; 932 nd.ni_cnd.cn_nameiop = CREATE; 933 nd.ni_cnd.cn_flags = LOCKPARENT; 934 if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos, 935 nfsd->nd_procp)) 936 goto out1; 937 xp = nd.ni_vp; 938 if (xp != NULL) { 939 error = EEXIST; 940 goto out; 941 } 942 xp = nd.ni_dvp; 943 if (vp->v_mount != xp->v_mount) 944 error = EXDEV; 945 out: 946 if (!error) { 947 nqsrv_getl(vp, NQL_WRITE); 948 nqsrv_getl(xp, NQL_WRITE); 949 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 950 } else { 951 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 952 if (nd.ni_dvp == nd.ni_vp) 953 vrele(nd.ni_dvp); 954 else 955 vput(nd.ni_dvp); 956 if (nd.ni_vp) 957 vrele(nd.ni_vp); 958 } 959 out1: 960 vrele(vp); 961 nfsm_reply(0); 962 nfsm_srvdone; 963 } 964 965 /* 966 * nfs symbolic link service 967 */ 968 nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq) 969 struct nfsd *nfsd; 970 struct mbuf *mrep, *md; 971 caddr_t dpos; 972 struct ucred *cred; 973 struct mbuf *nam, **mrq; 974 { 975 struct vattr va; 976 struct nameidata nd; 977 register struct vattr *vap = &va; 978 register u_long *tl; 979 register long t1; 980 struct nfsv2_sattr *sp; 981 caddr_t bpos; 982 struct uio io; 983 struct iovec iv; 984 int error = 0, rdonly, cache, len, len2; 985 char *pathcp, *cp2; 986 struct mbuf *mb, *mreq; 987 nfsv2fh_t nfh; 988 fhandle_t *fhp; 989 u_quad_t frev; 990 991 pathcp = (char *)0; 992 fhp = &nfh.fh_generic; 993 nfsm_srvmtofh(fhp); 994 nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 995 nd.ni_cnd.cn_cred = cred; 996 nd.ni_cnd.cn_nameiop = CREATE; 997 nd.ni_cnd.cn_flags = LOCKPARENT; 998 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 999 nfsd->nd_procp)) 1000 goto out; 1001 nfsm_strsiz(len2, NFS_MAXPATHLEN); 1002 MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK); 1003 iv.iov_base = pathcp; 1004 iv.iov_len = len2; 1005 io.uio_resid = len2; 1006 io.uio_offset = 0; 1007 io.uio_iov = &iv; 1008 io.uio_iovcnt = 1; 1009 io.uio_segflg = UIO_SYSSPACE; 1010 io.uio_rw = UIO_READ; 1011 io.uio_procp = (struct proc *)0; 1012 nfsm_mtouio(&io, len2); 1013 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR); 1014 *(pathcp + len2) = '\0'; 1015 if (nd.ni_vp) { 1016 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1017 if (nd.ni_dvp == nd.ni_vp) 1018 vrele(nd.ni_dvp); 1019 else 1020 vput(nd.ni_dvp); 1021 vrele(nd.ni_vp); 1022 error = EEXIST; 1023 goto out; 1024 } 1025 VATTR_NULL(vap); 1026 vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode); 1027 nqsrv_getl(nd.ni_dvp, NQL_WRITE); 1028 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp); 1029 out: 1030 if (pathcp) 1031 FREE(pathcp, M_TEMP); 1032 nfsm_reply(0); 1033 return (error); 1034 nfsmout: 1035 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1036 if (nd.ni_dvp == nd.ni_vp) 1037 vrele(nd.ni_dvp); 1038 else 1039 vput(nd.ni_dvp); 1040 if (nd.ni_vp) 1041 vrele(nd.ni_vp); 1042 if (pathcp) 1043 FREE(pathcp, M_TEMP); 1044 return (error); 1045 } 1046 1047 /* 1048 * nfs mkdir service 1049 */ 1050 nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq) 1051 struct nfsd *nfsd; 1052 struct mbuf *mrep, *md; 1053 caddr_t dpos; 1054 struct ucred *cred; 1055 struct mbuf *nam, **mrq; 1056 { 1057 struct vattr va; 1058 register struct vattr *vap = &va; 1059 register struct nfsv2_fattr *fp; 1060 struct nameidata nd; 1061 register caddr_t cp; 1062 register u_long *tl; 1063 register long t1; 1064 caddr_t bpos; 1065 int error = 0, rdonly, cache, len; 1066 char *cp2; 1067 struct mbuf *mb, *mb2, *mreq; 1068 struct vnode *vp; 1069 nfsv2fh_t nfh; 1070 fhandle_t *fhp; 1071 u_quad_t frev; 1072 1073 fhp = &nfh.fh_generic; 1074 nfsm_srvmtofh(fhp); 1075 nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 1076 nd.ni_cnd.cn_cred = cred; 1077 nd.ni_cnd.cn_nameiop = CREATE; 1078 nd.ni_cnd.cn_flags = LOCKPARENT; 1079 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 1080 nfsd->nd_procp)) 1081 nfsm_reply(0); 1082 nfsm_dissect(tl, u_long *, NFSX_UNSIGNED); 1083 VATTR_NULL(vap); 1084 vap->va_type = VDIR; 1085 vap->va_mode = nfstov_mode(*tl++); 1086 vp = nd.ni_vp; 1087 if (vp != NULL) { 1088 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1089 if (nd.ni_dvp == vp) 1090 vrele(nd.ni_dvp); 1091 else 1092 vput(nd.ni_dvp); 1093 vrele(vp); 1094 error = EEXIST; 1095 nfsm_reply(0); 1096 } 1097 nqsrv_getl(nd.ni_dvp, NQL_WRITE); 1098 if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) 1099 nfsm_reply(0); 1100 vp = nd.ni_vp; 1101 bzero((caddr_t)fhp, sizeof(nfh)); 1102 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1103 if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) { 1104 vput(vp); 1105 nfsm_reply(0); 1106 } 1107 error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp); 1108 vput(vp); 1109 nfsm_reply(NFSX_FH+NFSX_FATTR); 1110 nfsm_srvfhtom(fhp); 1111 nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR); 1112 nfsm_srvfillattr; 1113 return (error); 1114 nfsmout: 1115 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1116 if (nd.ni_dvp == nd.ni_vp) 1117 vrele(nd.ni_dvp); 1118 else 1119 vput(nd.ni_dvp); 1120 if (nd.ni_vp) 1121 vrele(nd.ni_vp); 1122 return (error); 1123 } 1124 1125 /* 1126 * nfs rmdir service 1127 */ 1128 nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq) 1129 struct nfsd *nfsd; 1130 struct mbuf *mrep, *md; 1131 caddr_t dpos; 1132 struct ucred *cred; 1133 struct mbuf *nam, **mrq; 1134 { 1135 register u_long *tl; 1136 register long t1; 1137 caddr_t bpos; 1138 int error = 0, rdonly, cache, len; 1139 char *cp2; 1140 struct mbuf *mb, *mreq; 1141 struct vnode *vp; 1142 nfsv2fh_t nfh; 1143 fhandle_t *fhp; 1144 struct nameidata nd; 1145 u_quad_t frev; 1146 1147 fhp = &nfh.fh_generic; 1148 nfsm_srvmtofh(fhp); 1149 nfsm_srvstrsiz(len, NFS_MAXNAMLEN); 1150 nd.ni_cnd.cn_cred = cred; 1151 nd.ni_cnd.cn_nameiop = DELETE; 1152 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 1153 if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos, 1154 nfsd->nd_procp)) 1155 nfsm_reply(0); 1156 vp = nd.ni_vp; 1157 if (vp->v_type != VDIR) { 1158 error = ENOTDIR; 1159 goto out; 1160 } 1161 /* 1162 * No rmdir "." please. 1163 */ 1164 if (nd.ni_dvp == vp) { 1165 error = EINVAL; 1166 goto out; 1167 } 1168 /* 1169 * The root of a mounted filesystem cannot be deleted. 1170 */ 1171 if (vp->v_flag & VROOT) 1172 error = EBUSY; 1173 out: 1174 if (!error) { 1175 nqsrv_getl(nd.ni_dvp, NQL_WRITE); 1176 nqsrv_getl(vp, NQL_WRITE); 1177 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1178 } else { 1179 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1180 if (nd.ni_dvp == nd.ni_vp) 1181 vrele(nd.ni_dvp); 1182 else 1183 vput(nd.ni_dvp); 1184 vput(vp); 1185 } 1186 nfsm_reply(0); 1187 nfsm_srvdone; 1188 } 1189 1190 /* 1191 * nfs readdir service 1192 * - mallocs what it thinks is enough to read 1193 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 1194 * - calls VOP_READDIR() 1195 * - loops around building the reply 1196 * if the output generated exceeds count break out of loop 1197 * The nfsm_clget macro is used here so that the reply will be packed 1198 * tightly in mbuf clusters. 1199 * - it only knows that it has encountered eof when the VOP_READDIR() 1200 * reads nothing 1201 * - as such one readdir rpc will return eof false although you are there 1202 * and then the next will return eof 1203 * - it trims out records with d_fileno == 0 1204 * this doesn't matter for Unix clients, but they might confuse clients 1205 * for other os'. 1206 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 1207 * than requested, but this may not apply to all filesystems. For 1208 * example, client NFS does not { although it is never remote mounted 1209 * anyhow } 1210 * The alternate call nqnfsrv_readdirlook() does lookups as well. 1211 * PS: The NFS protocol spec. does not clarify what the "count" byte 1212 * argument is a count of.. just name strings and file id's or the 1213 * entire reply rpc or ... 1214 * I tried just file name and id sizes and it confused the Sun client, 1215 * so I am using the full rpc size now. The "paranoia.." comment refers 1216 * to including the status longwords that are not a part of the dir. 1217 * "entry" structures, but are in the rpc. 1218 */ 1219 struct flrep { 1220 u_long fl_cachable; 1221 u_long fl_duration; 1222 u_quad_t fl_frev; 1223 nfsv2fh_t fl_nfh; 1224 struct nfsv2_fattr fl_fattr; 1225 }; 1226 1227 nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq) 1228 struct nfsd *nfsd; 1229 struct mbuf *mrep, *md; 1230 caddr_t dpos; 1231 struct ucred *cred; 1232 struct mbuf *nam, **mrq; 1233 { 1234 register char *bp, *be; 1235 register struct mbuf *mp; 1236 register struct dirent *dp; 1237 register caddr_t cp; 1238 register u_long *tl; 1239 register long t1; 1240 caddr_t bpos; 1241 struct mbuf *mb, *mb2, *mreq, *mp2; 1242 char *cpos, *cend, *cp2, *rbuf; 1243 struct vnode *vp; 1244 nfsv2fh_t nfh; 1245 fhandle_t *fhp; 1246 struct uio io; 1247 struct iovec iv; 1248 struct vattr va; 1249 int len, nlen, rem, xfer, tsiz, i, error = 0; 1250 int siz, cnt, fullsiz, eofflag, rdonly, cache; 1251 u_quad_t frev; 1252 u_long on; 1253 off_t off, toff; 1254 1255 fhp = &nfh.fh_generic; 1256 nfsm_srvmtofh(fhp); 1257 nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED); 1258 toff = fxdr_unsigned(off_t, *tl++); 1259 off = (toff & ~(NFS_DIRBLKSIZ-1)); 1260 on = (toff & (NFS_DIRBLKSIZ-1)); 1261 cnt = fxdr_unsigned(int, *tl); 1262 siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 1263 if (cnt > NFS_MAXREADDIR) 1264 siz = NFS_MAXREADDIR; 1265 fullsiz = siz; 1266 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 1267 nfsm_reply(0); 1268 nqsrv_getl(vp, NQL_READ); 1269 if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 1270 vput(vp); 1271 nfsm_reply(0); 1272 } 1273 VOP_UNLOCK(vp); 1274 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 1275 again: 1276 iv.iov_base = rbuf; 1277 iv.iov_len = fullsiz; 1278 io.uio_iov = &iv; 1279 io.uio_iovcnt = 1; 1280 io.uio_offset = off; 1281 io.uio_resid = fullsiz; 1282 io.uio_segflg = UIO_SYSSPACE; 1283 io.uio_rw = UIO_READ; 1284 io.uio_procp = (struct proc *)0; 1285 error = VOP_READDIR(vp, &io, cred); 1286 off = io.uio_offset; 1287 if (error) { 1288 vrele(vp); 1289 free((caddr_t)rbuf, M_TEMP); 1290 nfsm_reply(0); 1291 } 1292 if (io.uio_resid < fullsiz) 1293 eofflag = 0; 1294 else 1295 eofflag = 1; 1296 if (io.uio_resid) { 1297 siz -= io.uio_resid; 1298 1299 /* 1300 * If nothing read, return eof 1301 * rpc reply 1302 */ 1303 if (siz == 0) { 1304 vrele(vp); 1305 nfsm_reply(2*NFSX_UNSIGNED); 1306 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 1307 *tl++ = nfs_false; 1308 *tl = nfs_true; 1309 FREE((caddr_t)rbuf, M_TEMP); 1310 return (0); 1311 } 1312 } 1313 1314 /* 1315 * Check for degenerate cases of nothing useful read. 1316 * If so go try again 1317 */ 1318 cpos = rbuf + on; 1319 cend = rbuf + siz; 1320 dp = (struct dirent *)cpos; 1321 while (cpos < cend && dp->d_fileno == 0) { 1322 cpos += dp->d_reclen; 1323 dp = (struct dirent *)cpos; 1324 } 1325 if (cpos >= cend) { 1326 toff = off; 1327 siz = fullsiz; 1328 on = 0; 1329 goto again; 1330 } 1331 1332 cpos = rbuf + on; 1333 cend = rbuf + siz; 1334 dp = (struct dirent *)cpos; 1335 len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 1336 nfsm_reply(siz); 1337 mp = mp2 = mb; 1338 bp = bpos; 1339 be = bp + M_TRAILINGSPACE(mp); 1340 1341 /* Loop through the records and build reply */ 1342 while (cpos < cend) { 1343 if (dp->d_fileno != 0) { 1344 nlen = dp->d_namlen; 1345 rem = nfsm_rndup(nlen)-nlen; 1346 len += (4*NFSX_UNSIGNED + nlen + rem); 1347 if (len > cnt) { 1348 eofflag = 0; 1349 break; 1350 } 1351 /* 1352 * Build the directory record xdr from 1353 * the dirent entry. 1354 */ 1355 nfsm_clget; 1356 *tl = nfs_true; 1357 bp += NFSX_UNSIGNED; 1358 nfsm_clget; 1359 *tl = txdr_unsigned(dp->d_fileno); 1360 bp += NFSX_UNSIGNED; 1361 nfsm_clget; 1362 *tl = txdr_unsigned(nlen); 1363 bp += NFSX_UNSIGNED; 1364 1365 /* And loop around copying the name */ 1366 xfer = nlen; 1367 cp = dp->d_name; 1368 while (xfer > 0) { 1369 nfsm_clget; 1370 if ((bp+xfer) > be) 1371 tsiz = be-bp; 1372 else 1373 tsiz = xfer; 1374 bcopy(cp, bp, tsiz); 1375 bp += tsiz; 1376 xfer -= tsiz; 1377 if (xfer > 0) 1378 cp += tsiz; 1379 } 1380 /* And null pad to a long boundary */ 1381 for (i = 0; i < rem; i++) 1382 *bp++ = '\0'; 1383 nfsm_clget; 1384 1385 /* Finish off the record */ 1386 toff += dp->d_reclen; 1387 *tl = txdr_unsigned(toff); 1388 bp += NFSX_UNSIGNED; 1389 } else 1390 toff += dp->d_reclen; 1391 cpos += dp->d_reclen; 1392 dp = (struct dirent *)cpos; 1393 } 1394 vrele(vp); 1395 nfsm_clget; 1396 *tl = nfs_false; 1397 bp += NFSX_UNSIGNED; 1398 nfsm_clget; 1399 if (eofflag) 1400 *tl = nfs_true; 1401 else 1402 *tl = nfs_false; 1403 bp += NFSX_UNSIGNED; 1404 if (mp != mb) { 1405 if (bp < be) 1406 mp->m_len = bp - mtod(mp, caddr_t); 1407 } else 1408 mp->m_len += bp - bpos; 1409 FREE(rbuf, M_TEMP); 1410 nfsm_srvdone; 1411 } 1412 1413 nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq) 1414 struct nfsd *nfsd; 1415 struct mbuf *mrep, *md; 1416 caddr_t dpos; 1417 struct ucred *cred; 1418 struct mbuf *nam, **mrq; 1419 { 1420 register char *bp, *be; 1421 register struct mbuf *mp; 1422 register struct dirent *dp; 1423 register caddr_t cp; 1424 register u_long *tl; 1425 register long t1; 1426 caddr_t bpos; 1427 struct mbuf *mb, *mb2, *mreq, *mp2; 1428 char *cpos, *cend, *cp2, *rbuf; 1429 struct vnode *vp, *nvp; 1430 struct flrep fl; 1431 nfsv2fh_t nfh; 1432 fhandle_t *fhp; 1433 struct uio io; 1434 struct iovec iv; 1435 struct vattr va, *vap = &va; 1436 struct nfsv2_fattr *fp; 1437 int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2; 1438 int siz, cnt, fullsiz, eofflag, rdonly, cache; 1439 u_quad_t frev, frev2; 1440 u_long on; 1441 off_t off, toff; 1442 1443 fhp = &nfh.fh_generic; 1444 nfsm_srvmtofh(fhp); 1445 nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED); 1446 toff = fxdr_unsigned(off_t, *tl++); 1447 off = (toff & ~(NFS_DIRBLKSIZ-1)); 1448 on = (toff & (NFS_DIRBLKSIZ-1)); 1449 cnt = fxdr_unsigned(int, *tl++); 1450 duration2 = fxdr_unsigned(int, *tl); 1451 siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1)); 1452 if (cnt > NFS_MAXREADDIR) 1453 siz = NFS_MAXREADDIR; 1454 fullsiz = siz; 1455 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 1456 nfsm_reply(0); 1457 nqsrv_getl(vp, NQL_READ); 1458 if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) { 1459 vput(vp); 1460 nfsm_reply(0); 1461 } 1462 VOP_UNLOCK(vp); 1463 MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK); 1464 again: 1465 iv.iov_base = rbuf; 1466 iv.iov_len = fullsiz; 1467 io.uio_iov = &iv; 1468 io.uio_iovcnt = 1; 1469 io.uio_offset = off; 1470 io.uio_resid = fullsiz; 1471 io.uio_segflg = UIO_SYSSPACE; 1472 io.uio_rw = UIO_READ; 1473 io.uio_procp = (struct proc *)0; 1474 error = VOP_READDIR(vp, &io, cred); 1475 off = io.uio_offset; 1476 if (error) { 1477 vrele(vp); 1478 free((caddr_t)rbuf, M_TEMP); 1479 nfsm_reply(0); 1480 } 1481 if (io.uio_resid < fullsiz) 1482 eofflag = 0; 1483 else 1484 eofflag = 1; 1485 if (io.uio_resid) { 1486 siz -= io.uio_resid; 1487 1488 /* 1489 * If nothing read, return eof 1490 * rpc reply 1491 */ 1492 if (siz == 0) { 1493 vrele(vp); 1494 nfsm_reply(2*NFSX_UNSIGNED); 1495 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 1496 *tl++ = nfs_false; 1497 *tl = nfs_true; 1498 FREE((caddr_t)rbuf, M_TEMP); 1499 return (0); 1500 } 1501 } 1502 1503 /* 1504 * Check for degenerate cases of nothing useful read. 1505 * If so go try again 1506 */ 1507 cpos = rbuf + on; 1508 cend = rbuf + siz; 1509 dp = (struct dirent *)cpos; 1510 while (cpos < cend && dp->d_fileno == 0) { 1511 cpos += dp->d_reclen; 1512 dp = (struct dirent *)cpos; 1513 } 1514 if (cpos >= cend) { 1515 toff = off; 1516 siz = fullsiz; 1517 on = 0; 1518 goto again; 1519 } 1520 1521 cpos = rbuf + on; 1522 cend = rbuf + siz; 1523 dp = (struct dirent *)cpos; 1524 len = 3*NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 1525 nfsm_reply(siz); 1526 mp = mp2 = mb; 1527 bp = bpos; 1528 be = bp + M_TRAILINGSPACE(mp); 1529 1530 /* Loop through the records and build reply */ 1531 while (cpos < cend) { 1532 if (dp->d_fileno != 0) { 1533 nlen = dp->d_namlen; 1534 rem = nfsm_rndup(nlen)-nlen; 1535 1536 /* 1537 * For readdir_and_lookup get the vnode using 1538 * the file number. 1539 */ 1540 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 1541 goto invalid; 1542 (void) nqsrv_getlease(nvp, &duration2, NQL_READ, nfsd, 1543 nam, &cache2, &frev2, cred); 1544 bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t)); 1545 fl.fl_duration = txdr_unsigned(duration2); 1546 fl.fl_cachable = txdr_unsigned(cache2); 1547 txdr_hyper(&frev2, &fl.fl_frev); 1548 if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) { 1549 vput(nvp); 1550 goto invalid; 1551 } 1552 vput(nvp); 1553 fp = &fl.fl_fattr; 1554 nfsm_srvfillattr; 1555 len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH 1556 + NFSX_FATTR); 1557 if (len > cnt) { 1558 eofflag = 0; 1559 break; 1560 } 1561 /* 1562 * Build the directory record xdr from 1563 * the dirent entry. 1564 */ 1565 nfsm_clget; 1566 *tl = nfs_true; 1567 bp += NFSX_UNSIGNED; 1568 1569 /* 1570 * For readdir_and_lookup copy the stuff out. 1571 */ 1572 xfer = sizeof (struct flrep); 1573 cp = (caddr_t)&fl; 1574 while (xfer > 0) { 1575 nfsm_clget; 1576 if ((bp+xfer) > be) 1577 tsiz = be-bp; 1578 else 1579 tsiz = xfer; 1580 bcopy(cp, bp, tsiz); 1581 bp += tsiz; 1582 xfer -= tsiz; 1583 if (xfer > 0) 1584 cp += tsiz; 1585 } 1586 nfsm_clget; 1587 *tl = txdr_unsigned(dp->d_fileno); 1588 bp += NFSX_UNSIGNED; 1589 nfsm_clget; 1590 *tl = txdr_unsigned(nlen); 1591 bp += NFSX_UNSIGNED; 1592 1593 /* And loop around copying the name */ 1594 xfer = nlen; 1595 cp = dp->d_name; 1596 while (xfer > 0) { 1597 nfsm_clget; 1598 if ((bp+xfer) > be) 1599 tsiz = be-bp; 1600 else 1601 tsiz = xfer; 1602 bcopy(cp, bp, tsiz); 1603 bp += tsiz; 1604 xfer -= tsiz; 1605 if (xfer > 0) 1606 cp += tsiz; 1607 } 1608 /* And null pad to a long boundary */ 1609 for (i = 0; i < rem; i++) 1610 *bp++ = '\0'; 1611 nfsm_clget; 1612 1613 /* Finish off the record */ 1614 toff += dp->d_reclen; 1615 *tl = txdr_unsigned(toff); 1616 bp += NFSX_UNSIGNED; 1617 } else 1618 invalid: 1619 toff += dp->d_reclen; 1620 cpos += dp->d_reclen; 1621 dp = (struct dirent *)cpos; 1622 } 1623 vrele(vp); 1624 nfsm_clget; 1625 *tl = nfs_false; 1626 bp += NFSX_UNSIGNED; 1627 nfsm_clget; 1628 if (eofflag) 1629 *tl = nfs_true; 1630 else 1631 *tl = nfs_false; 1632 bp += NFSX_UNSIGNED; 1633 if (mp != mb) { 1634 if (bp < be) 1635 mp->m_len = bp - mtod(mp, caddr_t); 1636 } else 1637 mp->m_len += bp - bpos; 1638 FREE(rbuf, M_TEMP); 1639 nfsm_srvdone; 1640 } 1641 1642 /* 1643 * nfs statfs service 1644 */ 1645 nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq) 1646 struct nfsd *nfsd; 1647 struct mbuf *mrep, *md; 1648 caddr_t dpos; 1649 struct ucred *cred; 1650 struct mbuf *nam, **mrq; 1651 { 1652 register struct statfs *sf; 1653 register struct nfsv2_statfs *sfp; 1654 register u_long *tl; 1655 register long t1; 1656 caddr_t bpos; 1657 int error = 0, rdonly, cache; 1658 char *cp2; 1659 struct mbuf *mb, *mb2, *mreq; 1660 struct vnode *vp; 1661 nfsv2fh_t nfh; 1662 fhandle_t *fhp; 1663 struct statfs statfs; 1664 u_quad_t frev; 1665 1666 fhp = &nfh.fh_generic; 1667 nfsm_srvmtofh(fhp); 1668 if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) 1669 nfsm_reply(0); 1670 sf = &statfs; 1671 error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp); 1672 vput(vp); 1673 nfsm_reply(NFSX_STATFS); 1674 nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS); 1675 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 1676 sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 1677 sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 1678 sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 1679 sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 1680 nfsm_srvdone; 1681 } 1682 1683 /* 1684 * Null operation, used by clients to ping server 1685 */ 1686 /* ARGSUSED */ 1687 nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq) 1688 struct nfsd *nfsd; 1689 struct mbuf *mrep, *md; 1690 caddr_t dpos; 1691 struct ucred *cred; 1692 struct mbuf *nam, **mrq; 1693 { 1694 caddr_t bpos; 1695 int error = VNOVAL, cache; 1696 struct mbuf *mb, *mreq; 1697 u_quad_t frev; 1698 1699 nfsm_reply(0); 1700 return (error); 1701 } 1702 1703 /* 1704 * No operation, used for obsolete procedures 1705 */ 1706 /* ARGSUSED */ 1707 nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq) 1708 struct nfsd *nfsd; 1709 struct mbuf *mrep, *md; 1710 caddr_t dpos; 1711 struct ucred *cred; 1712 struct mbuf *nam, **mrq; 1713 { 1714 caddr_t bpos; 1715 int error, cache; 1716 struct mbuf *mb, *mreq; 1717 u_quad_t frev; 1718 1719 if (nfsd->nd_repstat) 1720 error = nfsd->nd_repstat; 1721 else 1722 error = EPROCUNAVAIL; 1723 nfsm_reply(0); 1724 return (error); 1725 } 1726 1727 /* 1728 * Perform access checking for vnodes obtained from file handles that would 1729 * refer to files already opened by a Unix client. You cannot just use 1730 * vn_writechk() and VOP_ACCESS() for two reasons. 1731 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case 1732 * 2 - The owner is to be given access irrespective of mode bits so that 1733 * processes that chmod after opening a file don't break. I don't like 1734 * this because it opens a security hole, but since the nfs server opens 1735 * a security hole the size of a barn door anyhow, what the heck. 1736 */ 1737 nfsrv_access(vp, flags, cred, rdonly, p) 1738 register struct vnode *vp; 1739 int flags; 1740 register struct ucred *cred; 1741 int rdonly; 1742 struct proc *p; 1743 { 1744 struct vattr vattr; 1745 int error; 1746 if (flags & VWRITE) { 1747 /* Just vn_writechk() changed to check rdonly */ 1748 /* 1749 * Disallow write attempts on read-only file systems; 1750 * unless the file is a socket or a block or character 1751 * device resident on the file system. 1752 */ 1753 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 1754 switch (vp->v_type) { 1755 case VREG: case VDIR: case VLNK: 1756 return (EROFS); 1757 } 1758 } 1759 /* 1760 * If there's shared text associated with 1761 * the inode, try to free it up once. If 1762 * we fail, we can't allow writing. 1763 */ 1764 if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp)) 1765 return (ETXTBSY); 1766 } 1767 if (error = VOP_GETATTR(vp, &vattr, cred, p)) 1768 return (error); 1769 if ((error = VOP_ACCESS(vp, flags, cred, p)) && 1770 cred->cr_uid != vattr.va_uid) 1771 return (error); 1772 return (0); 1773 } 1774