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, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: @(#)nfs_subs.c 7.41 (Berkeley) 5/15/91 37 * $Id: nfs_subs.c,v 1.6 1993/07/13 10:40:07 cgd Exp $ 38 */ 39 40 /* 41 * These functions support the macros and help fiddle mbuf chains for 42 * the nfs op functions. They do things like create the rpc header and 43 * copy data between mbuf chains and uio lists. 44 */ 45 #include "param.h" 46 #include "proc.h" 47 #include "filedesc.h" 48 #include "systm.h" 49 #include "kernel.h" 50 #include "mount.h" 51 #include "file.h" 52 #include "vnode.h" 53 #include "namei.h" 54 #include "mbuf.h" 55 56 #include "../ufs/quota.h" 57 #include "../ufs/inode.h" 58 59 #include "rpcv2.h" 60 #include "nfsv2.h" 61 #include "nfsnode.h" 62 #include "nfs.h" 63 #include "nfsiom.h" 64 #include "xdr_subs.h" 65 #include "nfsm_subs.h" 66 #include "nfscompress.h" 67 68 #define TRUE 1 69 #define FALSE 0 70 71 /* 72 * Data items converted to xdr at startup, since they are constant 73 * This is kinda hokey, but may save a little time doing byte swaps 74 */ 75 u_long nfs_procids[NFS_NPROCS]; 76 u_long nfs_xdrneg1; 77 u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 78 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 79 u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 80 /* And other global data */ 81 static u_long *rpc_uidp = (u_long *)0; 82 static u_long nfs_xid = 1; 83 static char *rpc_unixauth; 84 extern long hostid; 85 86 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 87 extern struct nfsreq nfsreqh; 88 89 /* Function ret types */ 90 static char *nfs_unixauth(); 91 92 /* 93 * Maximum number of groups passed through to NFS server. 94 * According to RFC1057 it should be 16. 95 * For release 3.X systems, the maximum value is 8. 96 * For some other servers, the maximum value is 10. 97 */ 98 int numgrps = 8; 99 100 /* 101 * Create the header for an rpc request packet 102 * The function nfs_unixauth() creates a unix style authorization string 103 * and returns a ptr to it. 104 * The hsiz is the size of the rest of the nfs request header. 105 * (just used to decide if a cluster is a good idea) 106 * nb: Note that the prog, vers and procid args are already in xdr byte order 107 */ 108 struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid) 109 u_long prog; 110 u_long vers; 111 u_long procid; 112 struct ucred *cred; 113 int hsiz; 114 caddr_t **bpos; 115 struct mbuf **mb; 116 u_long *retxid; 117 { 118 register struct mbuf *mreq, *m; 119 register u_long *tl; 120 struct mbuf *m1; 121 char *ap; 122 int asiz, siz; 123 static char authnull[4*NFSX_UNSIGNED]; 124 125 NFSMGETHDR(mreq); 126 if (cred != NOCRED) { 127 asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps : 128 (cred->cr_ngroups - 1)) << 2); 129 #ifdef FILLINHOST 130 asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 131 #else 132 asiz += 9*NFSX_UNSIGNED; 133 #endif 134 } else 135 asiz = 4 * NFSX_UNSIGNED; 136 137 /* If we need a lot, alloc a cluster ?? */ 138 if ((asiz+hsiz+RPC_SIZ) > MHLEN) 139 MCLGET(mreq, M_WAIT); 140 mreq->m_len = NFSMSIZ(mreq); 141 siz = mreq->m_len; 142 m1 = mreq; 143 /* 144 * Alloc enough mbufs 145 * We do it now to avoid all sleeps after the call to nfs_unixauth() 146 */ 147 while ((asiz+RPC_SIZ) > siz) { 148 MGET(m, M_WAIT, MT_DATA); 149 m1->m_next = m; 150 m->m_len = MLEN; 151 siz += MLEN; 152 m1 = m; 153 } 154 tl = mtod(mreq, u_long *); 155 *tl++ = *retxid = txdr_unsigned(++nfs_xid); 156 *tl++ = rpc_call; 157 *tl++ = rpc_vers; 158 *tl++ = prog; 159 *tl++ = vers; 160 *tl++ = procid; 161 162 /* Now we can call nfs_unixauth() and copy it in */ 163 if (cred != NOCRED) 164 ap = nfs_unixauth(cred); 165 else 166 ap = authnull; 167 m = mreq; 168 siz = m->m_len-RPC_SIZ; 169 if (asiz <= siz) { 170 bcopy(ap, (caddr_t)tl, asiz); 171 m->m_len = asiz+RPC_SIZ; 172 } else { 173 bcopy(ap, (caddr_t)tl, siz); 174 ap += siz; 175 asiz -= siz; 176 while (asiz > 0) { 177 siz = (asiz > MLEN) ? MLEN : asiz; 178 m = m->m_next; 179 bcopy(ap, mtod(m, caddr_t), siz); 180 m->m_len = siz; 181 asiz -= siz; 182 ap += siz; 183 } 184 } 185 186 /* Finally, return values */ 187 *mb = m; 188 *bpos = mtod(m, caddr_t)+m->m_len; 189 return (mreq); 190 } 191 192 /* 193 * copies mbuf chain to the uio scatter/gather list 194 */ 195 nfsm_mbuftouio(mrep, uiop, siz, dpos) 196 struct mbuf **mrep; 197 register struct uio *uiop; 198 int siz; 199 caddr_t *dpos; 200 { 201 register char *mbufcp, *uiocp; 202 register int xfer, left, len; 203 register struct mbuf *mp; 204 long uiosiz, rem; 205 int error = 0; 206 207 mp = *mrep; 208 mbufcp = *dpos; 209 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 210 rem = nfsm_rndup(siz)-siz; 211 while (siz > 0) { 212 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 213 return (EFBIG); 214 left = uiop->uio_iov->iov_len; 215 uiocp = uiop->uio_iov->iov_base; 216 if (left > siz) 217 left = siz; 218 uiosiz = left; 219 while (left > 0) { 220 while (len == 0) { 221 mp = mp->m_next; 222 if (mp == NULL) 223 return (EBADRPC); 224 mbufcp = mtod(mp, caddr_t); 225 len = mp->m_len; 226 } 227 xfer = (left > len) ? len : left; 228 #ifdef notdef 229 /* Not Yet.. */ 230 if (uiop->uio_iov->iov_op != NULL) 231 (*(uiop->uio_iov->iov_op)) 232 (mbufcp, uiocp, xfer); 233 else 234 #endif 235 if (uiop->uio_segflg == UIO_SYSSPACE) 236 bcopy(mbufcp, uiocp, xfer); 237 else 238 copyout(mbufcp, uiocp, xfer); 239 left -= xfer; 240 len -= xfer; 241 mbufcp += xfer; 242 uiocp += xfer; 243 uiop->uio_offset += xfer; 244 uiop->uio_resid -= xfer; 245 } 246 if (uiop->uio_iov->iov_len <= siz) { 247 uiop->uio_iovcnt--; 248 uiop->uio_iov++; 249 } else { 250 uiop->uio_iov->iov_base += uiosiz; 251 uiop->uio_iov->iov_len -= uiosiz; 252 } 253 siz -= uiosiz; 254 } 255 *dpos = mbufcp; 256 *mrep = mp; 257 if (rem > 0) { 258 if (len < rem) 259 error = nfs_adv(mrep, dpos, rem, len); 260 else 261 *dpos += rem; 262 } 263 return (error); 264 } 265 266 /* 267 * copies a uio scatter/gather list to an mbuf chain... 268 */ 269 nfsm_uiotombuf(uiop, mq, siz, bpos) 270 register struct uio *uiop; 271 struct mbuf **mq; 272 int siz; 273 caddr_t *bpos; 274 { 275 register char *uiocp; 276 register struct mbuf *mp, *mp2; 277 register int xfer, left, len; 278 int uiosiz, clflg, rem; 279 char *cp; 280 281 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 282 clflg = 1; 283 else 284 clflg = 0; 285 rem = nfsm_rndup(siz)-siz; 286 mp2 = *mq; 287 while (siz > 0) { 288 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 289 return (EINVAL); 290 left = uiop->uio_iov->iov_len; 291 uiocp = uiop->uio_iov->iov_base; 292 if (left > siz) 293 left = siz; 294 uiosiz = left; 295 while (left > 0) { 296 MGET(mp, M_WAIT, MT_DATA); 297 if (clflg) 298 MCLGET(mp, M_WAIT); 299 mp->m_len = NFSMSIZ(mp); 300 mp2->m_next = mp; 301 mp2 = mp; 302 xfer = (left > mp->m_len) ? mp->m_len : left; 303 #ifdef notdef 304 /* Not Yet.. */ 305 if (uiop->uio_iov->iov_op != NULL) 306 (*(uiop->uio_iov->iov_op)) 307 (uiocp, mtod(mp, caddr_t), xfer); 308 else 309 #endif 310 if (uiop->uio_segflg == UIO_SYSSPACE) 311 bcopy(uiocp, mtod(mp, caddr_t), xfer); 312 else 313 copyin(uiocp, mtod(mp, caddr_t), xfer); 314 len = mp->m_len; 315 mp->m_len = xfer; 316 left -= xfer; 317 uiocp += xfer; 318 uiop->uio_offset += xfer; 319 uiop->uio_resid -= xfer; 320 } 321 if (uiop->uio_iov->iov_len <= siz) { 322 uiop->uio_iovcnt--; 323 uiop->uio_iov++; 324 } else { 325 uiop->uio_iov->iov_base += uiosiz; 326 uiop->uio_iov->iov_len -= uiosiz; 327 } 328 siz -= uiosiz; 329 } 330 if (rem > 0) { 331 if (rem > (len-mp->m_len)) { 332 MGET(mp, M_WAIT, MT_DATA); 333 mp->m_len = 0; 334 mp2->m_next = mp; 335 } 336 cp = mtod(mp, caddr_t)+mp->m_len; 337 for (left = 0; left < rem; left++) 338 *cp++ = '\0'; 339 mp->m_len += rem; 340 *bpos = cp; 341 } else 342 *bpos = mtod(mp, caddr_t)+mp->m_len; 343 *mq = mp; 344 return (0); 345 } 346 347 /* 348 * Help break down an mbuf chain by setting the first siz bytes contiguous 349 * pointed to by returned val. 350 * If Updateflg == True we can overwrite the first part of the mbuf data 351 * This is used by the macros nfsm_disect and nfsm_disecton for tough 352 * cases. (The macros use the vars. dpos and dpos2) 353 */ 354 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 355 struct mbuf **mdp; 356 caddr_t *dposp; 357 int siz; 358 int left; 359 int updateflg; 360 caddr_t *cp2; 361 { 362 register struct mbuf *mp, *mp2; 363 register int siz2, xfer; 364 register caddr_t tl; 365 366 mp = *mdp; 367 while (left == 0) { 368 *mdp = mp = mp->m_next; 369 if (mp == NULL) 370 return (EBADRPC); 371 left = mp->m_len; 372 *dposp = mtod(mp, caddr_t); 373 } 374 if (left >= siz) { 375 *cp2 = *dposp; 376 *dposp += siz; 377 } else if (mp->m_next == NULL) { 378 return (EBADRPC); 379 } else if (siz > MHLEN) { 380 panic("nfs S too big"); 381 } else { 382 /* Iff update, you can overwrite, else must alloc new mbuf */ 383 if (updateflg) { 384 NFSMINOFF(mp); 385 } else { 386 MGET(mp2, M_WAIT, MT_DATA); 387 mp2->m_next = mp->m_next; 388 mp->m_next = mp2; 389 mp->m_len -= left; 390 mp = mp2; 391 } 392 *cp2 = tl = mtod(mp, caddr_t); 393 bcopy(*dposp, tl, left); /* Copy what was left */ 394 siz2 = siz-left; 395 tl += left; 396 mp2 = mp->m_next; 397 /* Loop around copying up the siz2 bytes */ 398 while (siz2 > 0) { 399 if (mp2 == NULL) 400 return (EBADRPC); 401 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 402 if (xfer > 0) { 403 bcopy(mtod(mp2, caddr_t), tl, xfer); 404 NFSMADV(mp2, xfer); 405 mp2->m_len -= xfer; 406 tl += xfer; 407 siz2 -= xfer; 408 } 409 if (siz2 > 0) 410 mp2 = mp2->m_next; 411 } 412 mp->m_len = siz; 413 *mdp = mp2; 414 *dposp = mtod(mp2, caddr_t); 415 } 416 return (0); 417 } 418 419 /* 420 * Advance the position in the mbuf chain. 421 */ 422 nfs_adv(mdp, dposp, offs, left) 423 struct mbuf **mdp; 424 caddr_t *dposp; 425 int offs; 426 int left; 427 { 428 register struct mbuf *m; 429 register int s; 430 431 m = *mdp; 432 s = left; 433 while (s < offs) { 434 offs -= s; 435 m = m->m_next; 436 if (m == NULL) 437 return (EBADRPC); 438 s = m->m_len; 439 } 440 *mdp = m; 441 *dposp = mtod(m, caddr_t)+offs; 442 return (0); 443 } 444 445 /* 446 * Copy a string into mbufs for the hard cases... 447 */ 448 nfsm_strtmbuf(mb, bpos, cp, siz) 449 struct mbuf **mb; 450 char **bpos; 451 char *cp; 452 long siz; 453 { 454 register struct mbuf *m1, *m2; 455 long left, xfer, len, tlen; 456 u_long *tl; 457 int putsize; 458 459 putsize = 1; 460 m2 = *mb; 461 left = NFSMSIZ(m2)-m2->m_len; 462 if (left > 0) { 463 tl = ((u_long *)(*bpos)); 464 *tl++ = txdr_unsigned(siz); 465 putsize = 0; 466 left -= NFSX_UNSIGNED; 467 m2->m_len += NFSX_UNSIGNED; 468 if (left > 0) { 469 bcopy(cp, (caddr_t) tl, left); 470 siz -= left; 471 cp += left; 472 m2->m_len += left; 473 left = 0; 474 } 475 } 476 /* Loop arround adding mbufs */ 477 while (siz > 0) { 478 MGET(m1, M_WAIT, MT_DATA); 479 if (siz > MLEN) 480 MCLGET(m1, M_WAIT); 481 m1->m_len = NFSMSIZ(m1); 482 m2->m_next = m1; 483 m2 = m1; 484 tl = mtod(m1, u_long *); 485 tlen = 0; 486 if (putsize) { 487 *tl++ = txdr_unsigned(siz); 488 m1->m_len -= NFSX_UNSIGNED; 489 tlen = NFSX_UNSIGNED; 490 putsize = 0; 491 } 492 if (siz < m1->m_len) { 493 len = nfsm_rndup(siz); 494 xfer = siz; 495 if (xfer < len) 496 *(tl+(xfer>>2)) = 0; 497 } else { 498 xfer = len = m1->m_len; 499 } 500 bcopy(cp, (caddr_t) tl, xfer); 501 m1->m_len = len+tlen; 502 siz -= xfer; 503 cp += xfer; 504 } 505 *mb = m1; 506 *bpos = mtod(m1, caddr_t)+m1->m_len; 507 return (0); 508 } 509 510 /* 511 * Called once to initialize data structures... 512 */ 513 nfs_init() 514 { 515 register int i; 516 517 rpc_vers = txdr_unsigned(RPC_VER2); 518 rpc_call = txdr_unsigned(RPC_CALL); 519 rpc_reply = txdr_unsigned(RPC_REPLY); 520 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 521 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 522 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 523 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 524 nfs_vers = txdr_unsigned(NFS_VER2); 525 nfs_prog = txdr_unsigned(NFS_PROG); 526 nfs_true = txdr_unsigned(TRUE); 527 nfs_false = txdr_unsigned(FALSE); 528 /* Loop thru nfs procids */ 529 for (i = 0; i < NFS_NPROCS; i++) 530 nfs_procids[i] = txdr_unsigned(i); 531 /* Ensure async daemons disabled */ 532 nfs_xdrneg1 = txdr_unsigned(-1); 533 #ifdef NFSCLIENT 534 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 535 nfs_iodwant[i] = (struct proc *)0; 536 nfs_nhinit(); /* Init the nfsnode table */ 537 #endif /* NFSCLIENT */ 538 #ifdef NFSSERVER 539 nfsrv_initcache(); /* Init the server request cache */ 540 #endif /*NFSSERVER */ 541 /* 542 * Initialize reply list and start timer 543 */ 544 nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 545 nfs_timer(); 546 } 547 548 /* 549 * Fill in the rest of the rpc_unixauth and return it 550 */ 551 static char *nfs_unixauth(cr) 552 register struct ucred *cr; 553 { 554 register u_long *tl; 555 register int i; 556 int ngr; 557 558 /* Maybe someday there should be a cache of AUTH_SHORT's */ 559 if ((tl = rpc_uidp) == NULL) { 560 #ifdef FILLINHOST 561 i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED); 562 #else 563 i = 25*NFSX_UNSIGNED; 564 #endif 565 MALLOC(tl, u_long *, i, M_TEMP, M_WAITOK); 566 bzero((caddr_t)tl, i); 567 rpc_unixauth = (caddr_t)tl; 568 *tl++ = txdr_unsigned(RPCAUTH_UNIX); 569 tl++; /* Fill in size later */ 570 *tl++ = hostid; 571 #ifdef FILLINHOST 572 *tl++ = txdr_unsigned(hostnamelen); 573 i = nfsm_rndup(hostnamelen); 574 bcopy(hostname, (caddr_t)tl, hostnamelen); 575 tl += (i>>2); 576 #else 577 *tl++ = 0; 578 #endif 579 rpc_uidp = tl; 580 } 581 *tl++ = txdr_unsigned(cr->cr_uid); 582 *tl++ = txdr_unsigned(cr->cr_groups[0]); 583 ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1); 584 *tl++ = txdr_unsigned(ngr); 585 for (i = 1; i <= ngr; i++) 586 *tl++ = txdr_unsigned(cr->cr_groups[i]); 587 /* And add the AUTH_NULL */ 588 *tl++ = 0; 589 *tl = 0; 590 i = (((caddr_t)tl)-rpc_unixauth)-12; 591 tl = (u_long *)(rpc_unixauth+4); 592 *tl = txdr_unsigned(i); 593 return (rpc_unixauth); 594 } 595 596 /* 597 * Set up nameidata for a namei() call and do it 598 */ 599 nfs_namei(ndp, fhp, len, mdp, dposp, p) 600 register struct nameidata *ndp; 601 fhandle_t *fhp; 602 int len; 603 struct mbuf **mdp; 604 caddr_t *dposp; 605 struct proc *p; 606 { 607 register int i, rem; 608 register struct mbuf *md; 609 register char *fromcp, *tocp; 610 struct vnode *dp; 611 int flag; 612 int error; 613 614 flag = ndp->ni_nameiop & OPMASK; 615 MALLOC(ndp->ni_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 616 /* 617 * Copy the name from the mbuf list to ndp->ni_pnbuf 618 * and set the various ndp fields appropriately. 619 */ 620 fromcp = *dposp; 621 tocp = ndp->ni_pnbuf; 622 md = *mdp; 623 rem = mtod(md, caddr_t) + md->m_len - fromcp; 624 ndp->ni_hash = 0; 625 for (i = 0; i < len; i++) { 626 while (rem == 0) { 627 md = md->m_next; 628 if (md == NULL) { 629 error = EBADRPC; 630 goto out; 631 } 632 fromcp = mtod(md, caddr_t); 633 rem = md->m_len; 634 } 635 if (*fromcp == '\0' || *fromcp == '/') { 636 error = EINVAL; 637 goto out; 638 } 639 if (*fromcp & 0200) 640 if ((*fromcp&0377) == ('/'|0200) || flag != DELETE) { 641 error = EINVAL; 642 goto out; 643 } 644 ndp->ni_hash += (unsigned char)*fromcp; 645 *tocp++ = *fromcp++; 646 rem--; 647 } 648 *tocp = '\0'; 649 *mdp = md; 650 *dposp = fromcp; 651 len = nfsm_rndup(len)-len; 652 if (len > 0) { 653 if (rem >= len) 654 *dposp += len; 655 else if (error = nfs_adv(mdp, dposp, len, rem)) 656 goto out; 657 } 658 ndp->ni_pathlen = tocp - ndp->ni_pnbuf; 659 ndp->ni_ptr = ndp->ni_pnbuf; 660 /* 661 * Extract and set starting directory. 662 */ 663 if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) 664 goto out; 665 if (dp->v_type != VDIR) { 666 vrele(dp); 667 error = ENOTDIR; 668 goto out; 669 } 670 ndp->ni_startdir = dp; 671 ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE); 672 /* 673 * And call lookup() to do the real work 674 */ 675 if (error = lookup(ndp, p)) 676 goto out; 677 /* 678 * Check for encountering a symbolic link 679 */ 680 if (ndp->ni_more) { 681 if ((ndp->ni_nameiop & LOCKPARENT) && ndp->ni_pathlen == 1) 682 vput(ndp->ni_dvp); 683 else 684 vrele(ndp->ni_dvp); 685 vput(ndp->ni_vp); 686 ndp->ni_vp = NULL; 687 error = EINVAL; 688 goto out; 689 } 690 /* 691 * Check for saved name request 692 */ 693 if (ndp->ni_nameiop & (SAVENAME | SAVESTART)) { 694 ndp->ni_nameiop |= HASBUF; 695 return (0); 696 } 697 out: 698 FREE(ndp->ni_pnbuf, M_NAMEI); 699 return (error); 700 } 701 702 /* 703 * A fiddled version of m_adj() that ensures null fill to a long 704 * boundary and only trims off the back end 705 */ 706 nfsm_adj(mp, len, nul) 707 struct mbuf *mp; 708 register int len; 709 int nul; 710 { 711 register struct mbuf *m; 712 register int count, i; 713 register char *cp; 714 715 /* 716 * Trim from tail. Scan the mbuf chain, 717 * calculating its length and finding the last mbuf. 718 * If the adjustment only affects this mbuf, then just 719 * adjust and return. Otherwise, rescan and truncate 720 * after the remaining size. 721 */ 722 count = 0; 723 m = mp; 724 for (;;) { 725 count += m->m_len; 726 if (m->m_next == (struct mbuf *)0) 727 break; 728 m = m->m_next; 729 } 730 if (m->m_len > len) { 731 m->m_len -= len; 732 if (nul > 0) { 733 cp = mtod(m, caddr_t)+m->m_len-nul; 734 for (i = 0; i < nul; i++) 735 *cp++ = '\0'; 736 } 737 return; 738 } 739 count -= len; 740 if (count < 0) 741 count = 0; 742 /* 743 * Correct length for chain is "count". 744 * Find the mbuf with last data, adjust its length, 745 * and toss data from remaining mbufs on chain. 746 */ 747 for (m = mp; m; m = m->m_next) { 748 if (m->m_len >= count) { 749 m->m_len = count; 750 if (nul > 0) { 751 cp = mtod(m, caddr_t)+m->m_len-nul; 752 for (i = 0; i < nul; i++) 753 *cp++ = '\0'; 754 } 755 break; 756 } 757 count -= m->m_len; 758 } 759 while (m = m->m_next) 760 m->m_len = 0; 761 } 762 763 /* 764 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 765 * - look up fsid in mount list (if not found ret error) 766 * - check that it is exported 767 * - get vp by calling VFS_FHTOVP() macro 768 * - if not lockflag unlock it with VOP_UNLOCK() 769 * - if cred->cr_uid == 0 set it to m_exroot 770 */ 771 nfsrv_fhtovp(fhp, lockflag, vpp, cred) 772 fhandle_t *fhp; 773 int lockflag; 774 struct vnode **vpp; 775 struct ucred *cred; 776 { 777 register struct mount *mp; 778 779 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 780 return (ESTALE); 781 if ((mp->mnt_flag & MNT_EXPORTED) == 0) 782 return (EACCES); 783 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 784 return (ESTALE); 785 if (cred->cr_uid == 0) 786 cred->cr_uid = mp->mnt_exroot; 787 if (!lockflag) 788 VOP_UNLOCK(*vpp); 789 return (0); 790 } 791 792 /* 793 * These two functions implement nfs rpc compression. 794 * The algorithm is a trivial run length encoding of '\0' bytes. The high 795 * order nibble of hex "e" is or'd with the number of zeroes - 2 in four 796 * bits. (2 - 17 zeros) Any data byte with a high order nibble of hex "e" 797 * is byte stuffed. 798 * The compressed data is padded with 0x0 bytes to an even multiple of 799 * 4 bytes in length to avoid any weird long pointer alignments. 800 * If compression/uncompression is unsuccessful, the original mbuf list 801 * is returned. 802 * The first four bytes (the XID) are left uncompressed and the fifth 803 * byte is set to 0x1 for request and 0x2 for reply. 804 * An uncompressed RPC will always have the fifth byte == 0x0. 805 */ 806 struct mbuf * 807 nfs_compress(m0) 808 struct mbuf *m0; 809 { 810 register u_char ch, nextch; 811 register int i, rlelast; 812 register u_char *ip, *op; 813 register int ileft, oleft, noteof; 814 register struct mbuf *m, *om; 815 struct mbuf **mp, *retm; 816 int olen, clget; 817 818 i = rlelast = 0; 819 noteof = 1; 820 m = m0; 821 if (m->m_len < 12) 822 return (m0); 823 if (m->m_pkthdr.len >= MINCLSIZE) 824 clget = 1; 825 else 826 clget = 0; 827 ileft = m->m_len - 9; 828 ip = mtod(m, u_char *); 829 MGETHDR(om, M_WAIT, MT_DATA); 830 if (clget) 831 MCLGET(om, M_WAIT); 832 retm = om; 833 mp = &om->m_next; 834 olen = om->m_len = 5; 835 oleft = M_TRAILINGSPACE(om); 836 op = mtod(om, u_char *); 837 *((u_long *)op) = *((u_long *)ip); 838 ip += 7; 839 op += 4; 840 *op++ = *ip++ + 1; 841 nextch = *ip++; 842 while (noteof) { 843 ch = nextch; 844 if (ileft == 0) { 845 do { 846 m = m->m_next; 847 } while (m && m->m_len == 0); 848 if (m) { 849 ileft = m->m_len; 850 ip = mtod(m, u_char *); 851 } else { 852 noteof = 0; 853 nextch = 0x1; 854 goto doit; 855 } 856 } 857 nextch = *ip++; 858 ileft--; 859 doit: 860 if (ch == '\0') { 861 if (++i == NFSC_MAX || nextch != '\0') { 862 if (i < 2) { 863 nfscput('\0'); 864 } else { 865 if (rlelast == i) { 866 nfscput('\0'); 867 i--; 868 } 869 if (NFSCRLE(i) == (nextch & 0xff)) { 870 i--; 871 if (i < 2) { 872 nfscput('\0'); 873 } else { 874 nfscput(NFSCRLE(i)); 875 } 876 nfscput('\0'); 877 rlelast = 0; 878 } else { 879 nfscput(NFSCRLE(i)); 880 rlelast = i; 881 } 882 } 883 i = 0; 884 } 885 } else { 886 if ((ch & NFSCRL) == NFSCRL) { 887 nfscput(ch); 888 } 889 nfscput(ch); 890 i = rlelast = 0; 891 } 892 } 893 if (olen < m0->m_pkthdr.len) { 894 m_freem(m0); 895 if (i = (olen & 0x3)) { 896 i = 4 - i; 897 while (i-- > 0) { 898 nfscput('\0'); 899 } 900 } 901 retm->m_pkthdr.len = olen; 902 retm->m_pkthdr.rcvif = (struct ifnet *)0; 903 return (retm); 904 } else { 905 m_freem(retm); 906 return (m0); 907 } 908 } 909 910 struct mbuf * 911 nfs_uncompress(m0) 912 struct mbuf *m0; 913 { 914 register u_char cp, nextcp, *ip, *op; 915 register struct mbuf *m, *om; 916 struct mbuf *retm, **mp; 917 int i, j, noteof, clget, ileft, oleft, olen; 918 919 m = m0; 920 i = 0; 921 while (m && i < MINCLSIZE) { 922 i += m->m_len; 923 m = m->m_next; 924 } 925 if (i < 6) 926 return (m0); 927 if (i >= MINCLSIZE) 928 clget = 1; 929 else 930 clget = 0; 931 m = m0; 932 MGET(om, M_WAIT, MT_DATA); 933 if (clget) 934 MCLGET(om, M_WAIT); 935 olen = om->m_len = 8; 936 oleft = M_TRAILINGSPACE(om); 937 op = mtod(om, u_char *); 938 retm = om; 939 mp = &om->m_next; 940 if (m->m_len >= 6) { 941 ileft = m->m_len - 6; 942 ip = mtod(m, u_char *); 943 *((u_long *)op) = *((u_long *)ip); 944 bzero(op + 4, 3); 945 ip += 4; 946 op += 7; 947 if (*ip == '\0') { 948 m_freem(om); 949 return (m0); 950 } 951 *op++ = *ip++ - 1; 952 cp = *ip++; 953 } else { 954 ileft = m->m_len; 955 ip = mtod(m, u_char *); 956 nfscget(*op++); 957 nfscget(*op++); 958 nfscget(*op++); 959 nfscget(*op++); 960 bzero(op, 3); 961 op += 3; 962 nfscget(*op); 963 if (*op == '\0') { 964 m_freem(om); 965 return (m0); 966 } 967 (*op)--; 968 op++; 969 nfscget(cp); 970 } 971 noteof = 1; 972 while (noteof) { 973 if ((cp & NFSCRL) == NFSCRL) { 974 nfscget(nextcp); 975 if (cp == nextcp) { 976 nfscput(cp); 977 goto readit; 978 } else { 979 i = (cp & 0xf) + 2; 980 for (j = 0; j < i; j++) { 981 nfscput('\0'); 982 } 983 cp = nextcp; 984 } 985 } else { 986 nfscput(cp); 987 readit: 988 nfscget(cp); 989 } 990 } 991 m_freem(m0); 992 if (i = (olen & 0x3)) 993 om->m_len -= i; 994 return (retm); 995 } 996