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 * 20 * @(#)nfs_subs.c 7.3 (Berkeley) 07/06/89 21 */ 22 23 /* 24 * These functions support the macros and help fiddle mbuf chains for 25 * the nfs op functions. They do things like create the rpc header and 26 * copy data between mbuf chains and uio lists. 27 */ 28 #include "strings.h" 29 #include "types.h" 30 #include "param.h" 31 #include "mount.h" 32 #include "../ufs/dir.h" 33 #include "time.h" 34 #include "errno.h" 35 #include "kernel.h" 36 #include "malloc.h" 37 #include "mbuf.h" 38 #include "file.h" 39 #include "vnode.h" 40 #include "uio.h" 41 #include "namei.h" 42 #include "ucred.h" 43 #include "rpcv2.h" 44 #include "nfsv2.h" 45 #include "nfsnode.h" 46 #include "nfs.h" 47 #include "xdr_subs.h" 48 #include "nfsm_subs.h" 49 50 #define TRUE 1 51 #define FALSE 0 52 53 /* 54 * Data items converted to xdr at startup, since they are constant 55 * This is kinda hokey, but may save a little time doing byte swaps 56 */ 57 u_long nfs_procids[NFS_NPROCS]; 58 u_long nfs_xdrneg1; 59 u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 60 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 61 u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 62 /* And other global data */ 63 static u_long *rpc_uidp = (u_long *)0; 64 static u_long nfs_xid = 1; 65 static char *rpc_unixauth; 66 extern long hostid; 67 extern enum vtype v_type[NFLNK+1]; 68 69 /* Function ret types */ 70 static char *nfs_unixauth(); 71 72 /* 73 * Create the header for an rpc request packet 74 * The function nfs_unixauth() creates a unix style authorization string 75 * and returns a ptr to it. 76 * The hsiz is the size of the rest of the nfs request header. 77 * (just used to decide if a cluster is a good idea) 78 * nb: Note that the prog, vers and proc args are already in xdr byte order 79 */ 80 struct mbuf *nfsm_reqh(prog, vers, proc, cred, hsiz, bpos, mb, retxid) 81 u_long prog; 82 u_long vers; 83 u_long proc; 84 struct ucred *cred; 85 int hsiz; 86 caddr_t *bpos; 87 struct mbuf **mb; 88 u_long *retxid; 89 { 90 register struct mbuf *mreq, *m; 91 register u_long *p; 92 struct mbuf *m1; 93 char *ap; 94 int asiz, siz; 95 96 NFSMGETHDR(mreq); 97 asiz = (((cred->cr_ngroups > 10) ? 10 : cred->cr_ngroups)<<2); 98 #ifdef FILLINHOST 99 asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 100 #else 101 asiz += 9*NFSX_UNSIGNED; 102 #endif 103 104 /* If we need a lot, alloc a cluster ?? */ 105 if ((asiz+hsiz+RPC_SIZ) > MHLEN) 106 NFSMCLGET(mreq, M_WAIT); 107 mreq->m_len = NFSMSIZ(mreq); 108 siz = mreq->m_len; 109 m1 = mreq; 110 /* 111 * Alloc enough mbufs 112 * We do it now to avoid all sleeps after the call to nfs_unixauth() 113 */ 114 while ((asiz+RPC_SIZ) > siz) { 115 MGET(m, M_WAIT, MT_DATA); 116 m1->m_next = m; 117 m->m_len = MLEN; 118 siz += MLEN; 119 m1 = m; 120 } 121 p = mtod(mreq, u_long *); 122 *p++ = *retxid = txdr_unsigned(++nfs_xid); 123 *p++ = rpc_call; 124 *p++ = rpc_vers; 125 *p++ = prog; 126 *p++ = vers; 127 *p++ = proc; 128 129 /* Now we can call nfs_unixauth() and copy it in */ 130 ap = nfs_unixauth(cred); 131 m = mreq; 132 siz = m->m_len-RPC_SIZ; 133 if (asiz <= siz) { 134 bcopy(ap, (caddr_t)p, asiz); 135 m->m_len = asiz+RPC_SIZ; 136 } else { 137 bcopy(ap, (caddr_t)p, siz); 138 ap += siz; 139 asiz -= siz; 140 while (asiz > 0) { 141 siz = (asiz > MLEN) ? MLEN : asiz; 142 m = m->m_next; 143 bcopy(ap, mtod(m, caddr_t), siz); 144 m->m_len = siz; 145 asiz -= siz; 146 ap += siz; 147 } 148 } 149 150 /* Finally, return values */ 151 *mb = m; 152 *bpos = mtod(m, caddr_t)+m->m_len; 153 return (mreq); 154 } 155 156 /* 157 * copies mbuf chain to the uio scatter/gather list 158 */ 159 nfsm_mbuftouio(mrep, uiop, siz, dpos) 160 struct mbuf **mrep; 161 struct uio *uiop; 162 int siz; 163 caddr_t *dpos; 164 { 165 register int xfer, left, len; 166 register struct mbuf *mp; 167 register char *mbufcp, *uiocp; 168 long uiosiz, rem; 169 170 mp = *mrep; 171 mbufcp = *dpos; 172 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 173 rem = nfsm_rndup(siz)-siz; 174 while (siz > 0) { 175 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 176 return(EFBIG); 177 left = uiop->uio_iov->iov_len; 178 uiocp = uiop->uio_iov->iov_base; 179 if (left > siz) 180 left = siz; 181 uiosiz = left; 182 while (left > 0) { 183 while (len == 0) { 184 mp = mp->m_next; 185 if (mp == NULL) 186 return (EBADRPC); 187 mbufcp = mtod(mp, caddr_t); 188 len = mp->m_len; 189 } 190 xfer = (left > len) ? len : left; 191 #ifdef notdef 192 /* Not Yet.. */ 193 if (uiop->uio_iov->iov_op != NULL) 194 (*(uiop->uio_iov->iov_op)) 195 (mbufcp, uiocp, xfer); 196 else 197 #endif 198 if (uiop->uio_segflg == UIO_SYSSPACE) 199 bcopy(mbufcp, uiocp, xfer); 200 else 201 copyout(mbufcp, uiocp, xfer); 202 left -= xfer; 203 len -= xfer; 204 mbufcp += xfer; 205 uiocp += xfer; 206 uiop->uio_resid -= xfer; 207 } 208 if (uiop->uio_iov->iov_len <= siz) { 209 uiop->uio_iovcnt--; 210 uiop->uio_iov++; 211 } else { 212 uiop->uio_iov->iov_base += uiosiz; 213 uiop->uio_iov->iov_len -= uiosiz; 214 } 215 siz -= uiosiz; 216 } 217 if (rem > 0) 218 mbufcp += rem; 219 *dpos = mbufcp; 220 *mrep = mp; 221 return(0); 222 } 223 224 /* 225 * copies a uio scatter/gather list to an mbuf chain... 226 */ 227 nfsm_uiotombuf(uiop, mq, siz, bpos) 228 register struct uio *uiop; 229 struct mbuf **mq; 230 int siz; 231 caddr_t *bpos; 232 { 233 register struct mbuf *mp; 234 struct mbuf *mp2; 235 long xfer, left, uiosiz, off; 236 int clflg; 237 int rem, len; 238 char *cp, *uiocp; 239 240 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 241 clflg = 1; 242 else 243 clflg = 0; 244 rem = nfsm_rndup(siz)-siz; 245 mp2 = *mq; 246 while (siz > 0) { 247 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 248 return(EINVAL); 249 left = uiop->uio_iov->iov_len; 250 uiocp = uiop->uio_iov->iov_base; 251 if (left > siz) 252 left = siz; 253 uiosiz = left; 254 while (left > 0) { 255 MGET(mp, M_WAIT, MT_DATA); 256 if (clflg) 257 NFSMCLGET(mp, M_WAIT); 258 mp->m_len = NFSMSIZ(mp); 259 mp2->m_next = mp; 260 mp2 = mp; 261 xfer = (left > mp->m_len) ? mp->m_len : left; 262 #ifdef notdef 263 /* Not Yet.. */ 264 if (uiop->uio_iov->iov_op != NULL) 265 (*(uiop->uio_iov->iov_op)) 266 (uiocp, mtod(mp, caddr_t), xfer); 267 else 268 #endif 269 if (uiop->uio_segflg == UIO_SYSSPACE) 270 bcopy(uiocp, mtod(mp, caddr_t), xfer); 271 else 272 copyin(uiocp, mtod(mp, caddr_t), xfer); 273 len = mp->m_len; 274 mp->m_len = xfer; 275 left -= xfer; 276 uiocp += xfer; 277 uiop->uio_resid -= xfer; 278 } 279 if (uiop->uio_iov->iov_len <= siz) { 280 uiop->uio_iovcnt--; 281 uiop->uio_iov++; 282 } else { 283 uiop->uio_iov->iov_base += uiosiz; 284 uiop->uio_iov->iov_len -= uiosiz; 285 } 286 siz -= uiosiz; 287 } 288 if (rem > 0) { 289 if (rem > (len-mp->m_len)) { 290 MGET(mp, M_WAIT, MT_DATA); 291 mp->m_len = 0; 292 mp2->m_next = mp; 293 } 294 cp = mtod(mp, caddr_t)+mp->m_len; 295 for (left = 0; left < rem; left++) 296 *cp++ = '\0'; 297 mp->m_len += rem; 298 *bpos = cp; 299 } else 300 *bpos = mtod(mp, caddr_t)+mp->m_len; 301 *mq = mp; 302 return(0); 303 } 304 305 /* 306 * Help break down an mbuf chain by setting the first siz bytes contiguous 307 * pointed to by returned val. 308 * If Updateflg == True we can overwrite the first part of the mbuf data 309 * This is used by the macros nfsm_disect and nfsm_disecton for tough 310 * cases. (The macros use the vars. dpos and dpos2) 311 */ 312 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 313 struct mbuf **mdp; 314 caddr_t *dposp; 315 int siz; 316 int left; 317 int updateflg; 318 caddr_t *cp2; 319 { 320 register struct mbuf *mp, *mp2; 321 register int siz2, xfer; 322 register caddr_t p; 323 caddr_t p2; 324 325 mp = *mdp; 326 while (left == 0) { 327 *mdp = mp = mp->m_next; 328 if (mp == NULL) 329 return(EBADRPC); 330 left = mp->m_len; 331 *dposp = mtod(mp, caddr_t); 332 } 333 if (left >= siz) { 334 *cp2 = *dposp; 335 *dposp += siz; 336 return(0); 337 } else if (mp->m_next == NULL) { 338 return(EBADRPC); 339 } else if (siz > MCLBYTES) { 340 panic("nfs S too big"); 341 } else { 342 /* Iff update, you can overwrite, else must alloc new mbuf */ 343 if (updateflg) { 344 NFSMINOFF(mp); 345 } else { 346 MGET(mp2, M_WAIT, MT_DATA); 347 mp2->m_next = mp->m_next; 348 mp->m_next = mp2; 349 mp->m_len -= left; 350 mp = mp2; 351 } 352 /* Alloc cluster iff we need it */ 353 if (!M_HASCL(mp) && siz > NFSMSIZ(mp)) { 354 NFSMCLGET(mp, M_WAIT); 355 if (!M_HASCL(mp)) 356 return(ENOBUFS); 357 } 358 *cp2 = p = mtod(mp, caddr_t); 359 bcopy(*dposp, p, left); /* Copy what was left */ 360 siz2 = siz-left; 361 p += left; 362 mp2 = mp->m_next; 363 /* Loop arround copying up the siz2 bytes */ 364 while (siz2 > 0) { 365 if (mp2 == NULL) 366 return (EBADRPC); 367 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 368 bcopy(mtod(mp2, caddr_t), p, xfer); 369 NFSMADV(mp2, xfer); 370 mp2->m_len -= xfer; 371 siz2 -= xfer; 372 if (siz2 > 0) 373 mp2 = mp2->m_next; 374 } 375 mp->m_len = siz; 376 *mdp = mp2; 377 *dposp = mtod(mp2, caddr_t); 378 return (0); 379 } 380 } 381 382 /* 383 * Advance the position in the mbuf chain with/without freeing mbufs 384 */ 385 nfs_adv(mdp, dposp, offs, left) 386 struct mbuf **mdp; 387 caddr_t *dposp; 388 int offs; 389 int left; 390 { 391 register struct mbuf *m; 392 register int s; 393 394 m = *mdp; 395 s = left; 396 while (s < offs) { 397 offs -= s; 398 m = m->m_next; 399 if (m == NULL) 400 return(EBADRPC); 401 s = m->m_len; 402 } 403 *mdp = m; 404 *dposp = mtod(m, caddr_t)+offs; 405 return(0); 406 } 407 408 /* 409 * Copy a string into mbufs for the hard cases... 410 */ 411 nfsm_strtmbuf(mb, bpos, cp, siz) 412 struct mbuf **mb; 413 char **bpos; 414 char *cp; 415 long siz; 416 { 417 register struct mbuf *m1, *m2; 418 long left, xfer, len, tlen; 419 u_long *p; 420 int putsize; 421 422 putsize = 1; 423 m2 = *mb; 424 left = NFSMSIZ(m2)-m2->m_len; 425 if (left > 0) { 426 p = ((u_long *)(*bpos)); 427 *p++ = txdr_unsigned(siz); 428 putsize = 0; 429 left -= NFSX_UNSIGNED; 430 m2->m_len += NFSX_UNSIGNED; 431 if (left > 0) { 432 bcopy(cp, (caddr_t) p, left); 433 siz -= left; 434 cp += left; 435 m2->m_len += left; 436 left = 0; 437 } 438 } 439 /* Loop arround adding mbufs */ 440 while (siz > 0) { 441 MGET(m1, M_WAIT, MT_DATA); 442 if (siz > MLEN) 443 NFSMCLGET(m1, M_WAIT); 444 m1->m_len = NFSMSIZ(m1); 445 m2->m_next = m1; 446 m2 = m1; 447 p = mtod(m1, u_long *); 448 tlen = 0; 449 if (putsize) { 450 *p++ = txdr_unsigned(siz); 451 m1->m_len -= NFSX_UNSIGNED; 452 tlen = NFSX_UNSIGNED; 453 putsize = 0; 454 } 455 if (siz < m1->m_len) { 456 len = nfsm_rndup(siz); 457 xfer = siz; 458 if (xfer < len) 459 *(p+(xfer>>2)) = 0; 460 } else { 461 xfer = len = m1->m_len; 462 } 463 bcopy(cp, (caddr_t) p, xfer); 464 m1->m_len = len+tlen; 465 siz -= xfer; 466 cp += xfer; 467 } 468 *mb = m1; 469 *bpos = mtod(m1, caddr_t)+m1->m_len; 470 return(0); 471 } 472 473 /* 474 * Called once to initialize data structures... 475 */ 476 nfsinit() 477 { 478 register int i; 479 480 rpc_vers = txdr_unsigned(RPC_VER2); 481 rpc_call = txdr_unsigned(RPC_CALL); 482 rpc_reply = txdr_unsigned(RPC_REPLY); 483 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 484 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 485 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 486 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 487 nfs_vers = txdr_unsigned(NFS_VER2); 488 nfs_prog = txdr_unsigned(NFS_PROG); 489 nfs_true = txdr_unsigned(TRUE); 490 nfs_false = txdr_unsigned(FALSE); 491 /* Loop thru nfs procids */ 492 for (i = 0; i < NFS_NPROCS; i++) 493 nfs_procids[i] = txdr_unsigned(i); 494 v_type[0] = VNON; 495 v_type[1] = VREG; 496 v_type[2] = VDIR; 497 v_type[3] = VBLK; 498 v_type[4] = VCHR; 499 v_type[5] = VLNK; 500 nfs_xdrneg1 = txdr_unsigned(-1); 501 nfs_nhinit(); /* Init the nfsnode table */ 502 /* And start timer */ 503 nfs_timer(); 504 } 505 506 /* 507 * Fill in the rest of the rpc_unixauth and return it 508 */ 509 static char *nfs_unixauth(cr) 510 register struct ucred *cr; 511 { 512 register u_long *p; 513 register int i; 514 int ngr; 515 516 /* Maybe someday there should be a cache of AUTH_SHORT's */ 517 if ((p = rpc_uidp) == NULL) { 518 #ifdef FILLINHOST 519 i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED); 520 #else 521 i = 19*NFSX_UNSIGNED; 522 #endif 523 MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); 524 bzero((caddr_t)p, i); 525 rpc_unixauth = (caddr_t)p; 526 *p++ = txdr_unsigned(RPCAUTH_UNIX); 527 p++; /* Fill in size later */ 528 *p++ = hostid; 529 #ifdef FILLINHOST 530 *p++ = txdr_unsigned(hostnamelen); 531 i = nfsm_rndup(hostnamelen); 532 bcopy(hostname, (caddr_t)p, hostnamelen); 533 p += (i>>2); 534 #else 535 *p++ = 0; 536 #endif 537 rpc_uidp = p; 538 } 539 *p++ = txdr_unsigned(cr->cr_uid); 540 *p++ = txdr_unsigned(cr->cr_groups[0]); 541 ngr = (cr->cr_ngroups > 10) ? 10 : cr->cr_ngroups; 542 *p++ = txdr_unsigned(ngr); 543 for (i = 0; i < ngr; i++) 544 *p++ = txdr_unsigned(cr->cr_groups[i]); 545 /* And add the AUTH_NULL */ 546 *p++ = 0; 547 *p = 0; 548 i = (((caddr_t)p)-rpc_unixauth)-12; 549 p = (u_long *)(rpc_unixauth+4); 550 *p = txdr_unsigned(i); 551 return(rpc_unixauth); 552 } 553 554 /* 555 * Attribute cache routines. 556 * nfs_loadattrcache() - loads or updates the cache contents from attributes 557 * that are on the mbuf list 558 * nfs_getattrcache() - returns valid attributes if found in cache, returns 559 * error otherwise 560 */ 561 562 /* 563 * Load the attribute cache (that lives in the nfsnode table) with 564 * the values on the mbuf list and 565 * Iff vap not NULL 566 * copy the attributes to *vaper 567 */ 568 nfs_loadattrcache(vp, mdp, dposp, vaper) 569 register struct vnode *vp; 570 struct mbuf **mdp; 571 caddr_t *dposp; 572 struct vattr *vaper; 573 { 574 register struct vattr *vap; 575 nfsm_vars; 576 struct nfsnode *np; 577 578 md = *mdp; 579 dpos = *dposp; 580 t1 = (mtod(md, caddr_t)+md->m_len)-dpos; 581 if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 582 return (error); 583 p = (u_long *)cp2; 584 np = VTONFS(vp); 585 vap = &np->n_vattr; 586 vap->va_type = nfstov_type(*p++); 587 vap->va_mode = nfstov_mode(*p++); 588 vap->va_nlink = fxdr_unsigned(u_short, *p++); 589 vap->va_uid = fxdr_unsigned(uid_t, *p++); 590 vap->va_gid = fxdr_unsigned(gid_t, *p++); 591 vap->va_size = fxdr_unsigned(u_long, *p++); 592 vap->va_size1 = 0; /* OR -1 ?? */ 593 vap->va_blocksize = fxdr_unsigned(long, *p++); 594 vap->va_rdev = fxdr_unsigned(dev_t, *p++); 595 vap->va_bytes = fxdr_unsigned(long, *p++); 596 vap->va_bytes1 = -1; 597 vap->va_fsid = fxdr_unsigned(long, *p++); 598 vap->va_fileid = fxdr_unsigned(long, *p++); 599 fxdr_time(p, &(vap->va_atime)); 600 p += 2; 601 fxdr_time(p, &(vap->va_mtime)); 602 p += 2; 603 fxdr_time(p, &(vap->va_ctime)); 604 np->n_attrstamp = time.tv_sec; 605 *dposp = dpos; 606 *mdp = md; 607 if (vaper != NULL) 608 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 609 return (0); 610 } 611 612 /* 613 * Check the time stamp 614 * If the cache is valid, copy contents to *vap and return 0 615 * otherwise return an error 616 */ 617 nfs_getattrcache(vp, vap) 618 register struct vnode *vp; 619 struct vattr *vap; 620 { 621 register struct nfsnode *np; 622 623 np = VTONFS(vp); 624 if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 625 nfsstats.attrcache_hits++; 626 bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 627 return (0); 628 } else { 629 nfsstats.attrcache_misses++; 630 return (ENOENT); 631 } 632 } 633 634 /* 635 * nfs_namei - a liitle like namei(), but for one element only 636 * essentially look up file handle, fill in ndp and call VOP_LOOKUP() 637 */ 638 nfs_namei(ndp, fhp, len, mdp, dposp) 639 register struct nameidata *ndp; 640 fhandle_t *fhp; 641 int len; 642 struct mbuf **mdp; 643 caddr_t *dposp; 644 { 645 register int i, rem; 646 register struct mbuf *md; 647 register char *cp; 648 struct vnode *dp = (struct vnode *)0; 649 struct vnode *tdp; 650 struct mount *mp; 651 int flag; 652 int docache; 653 int wantparent; 654 int lockparent; 655 int rootflg = 0; 656 int error = 0; 657 658 ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 659 flag = ndp->ni_nameiop & OPFLAG; 660 wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT); 661 lockparent = ndp->ni_nameiop & LOCKPARENT; 662 docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; 663 if (flag == DELETE || wantparent) 664 docache = 0; 665 666 /* Fill in the nameidata and call lookup */ 667 cp = *dposp; 668 md = *mdp; 669 rem = mtod(md, caddr_t)+md->m_len-cp; 670 ndp->ni_hash = 0; 671 for (i = 0; i < len;) { 672 if (rem == 0) { 673 md = md->m_next; 674 if (md == NULL) 675 return (EBADRPC); 676 cp = mtod(md, caddr_t); 677 rem = md->m_len; 678 } 679 if (*cp == '\0' || *cp == '/') 680 return (EINVAL); 681 if (*cp & 0200) 682 if ((*cp&0377) == ('/'|0200) || flag != DELETE) 683 return (EINVAL); 684 ndp->ni_dent.d_name[i++] = *cp; 685 ndp->ni_hash += (unsigned char)*cp * i; 686 cp++; 687 rem--; 688 } 689 *mdp = md; 690 len = nfsm_rndup(len)-len; 691 if (len > 0) 692 *dposp = cp+len; 693 else 694 *dposp = cp; 695 ndp->ni_namelen = i; 696 ndp->ni_dent.d_namlen = i; 697 ndp->ni_dent.d_name[i] = '\0'; 698 ndp->ni_pathlen = 1; 699 ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; 700 ndp->ni_next = &ndp->ni_dent.d_name[i]; 701 ndp->ni_loopcnt = 0; /* Not actually used for now */ 702 ndp->ni_endoff = 0; 703 if (docache) 704 ndp->ni_makeentry = 1; 705 else 706 ndp->ni_makeentry = 0; 707 ndp->ni_isdotdot = (i == 2 && 708 ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.'); 709 710 if (error = nfsrv_fhtovp(fhp, TRUE, &dp, ndp->ni_cred)) 711 return (error); 712 if (dp->v_type != VDIR) { 713 vput(dp); 714 return (ENOTDIR); 715 } 716 ndp->ni_cdir = dp; 717 ndp->ni_rdir = (struct vnode *)0; 718 719 /* 720 * Handle "..": 721 * If this vnode is the root of the mounted 722 * file system, then ignore it so can't get out 723 */ 724 if (ndp->ni_isdotdot && (dp->v_flag & VROOT)) { 725 ndp->ni_dvp = dp; 726 ndp->ni_vp = dp; 727 VREF(dp); 728 goto nextname; 729 } 730 731 /* 732 * We now have a segment name to search for, and a directory to search. 733 */ 734 if (error = VOP_LOOKUP(dp, ndp)) { 735 if (ndp->ni_vp != NULL) 736 panic("leaf should be empty"); 737 /* 738 * If creating and at end of pathname, then can consider 739 * allowing file to be created. 740 */ 741 if (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) 742 error = EROFS; 743 if (flag == LOOKUP || flag == DELETE || error != ENOENT) 744 goto bad; 745 /* 746 * We return with ni_vp NULL to indicate that the entry 747 * doesn't currently exist, leaving a pointer to the 748 * (possibly locked) directory inode in ndp->ni_dvp. 749 */ 750 return (0); /* should this be ENOENT? */ 751 } 752 753 dp = ndp->ni_vp; 754 755 nextname: 756 ndp->ni_ptr = ndp->ni_next; 757 /* 758 * Check for read-only file systems 759 */ 760 if (flag == DELETE || flag == RENAME) { 761 /* 762 * Disallow directory write attempts on read-only 763 * file systems. 764 */ 765 if ((dp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)) || 766 (wantparent && (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)))) { 767 error = EROFS; 768 goto bad2; 769 } 770 } 771 772 if (!wantparent) 773 vrele(ndp->ni_dvp); 774 775 if ((ndp->ni_nameiop & LOCKLEAF) == 0) 776 VOP_UNLOCK(dp); 777 return (0); 778 779 bad2: 780 if (lockparent) 781 VOP_UNLOCK(ndp->ni_dvp); 782 vrele(ndp->ni_dvp); 783 bad: 784 vput(dp); 785 ndp->ni_vp = NULL; 786 return (error); 787 } 788 789 /* 790 * A fiddled version of m_adj() that ensures null fill to a long 791 * boundary and only trims off the back end 792 */ 793 nfsm_adj(mp, len, nul) 794 struct mbuf *mp; 795 register int len; 796 int nul; 797 { 798 register struct mbuf *m; 799 register int count, i; 800 register char *cp; 801 802 /* 803 * Trim from tail. Scan the mbuf chain, 804 * calculating its length and finding the last mbuf. 805 * If the adjustment only affects this mbuf, then just 806 * adjust and return. Otherwise, rescan and truncate 807 * after the remaining size. 808 */ 809 count = 0; 810 m = mp; 811 for (;;) { 812 count += m->m_len; 813 if (m->m_next == (struct mbuf *)0) 814 break; 815 m = m->m_next; 816 } 817 if (m->m_len >= len) { 818 m->m_len -= len; 819 if (nul > 0) { 820 cp = mtod(m, caddr_t)+m->m_len-nul; 821 for (i = 0; i < nul; i++) 822 *cp++ = '\0'; 823 } 824 return; 825 } 826 count -= len; 827 if (count < 0) 828 count = 0; 829 /* 830 * Correct length for chain is "count". 831 * Find the mbuf with last data, adjust its length, 832 * and toss data from remaining mbufs on chain. 833 */ 834 for (m = mp; m; m = m->m_next) { 835 if (m->m_len >= count) { 836 m->m_len = count; 837 if (nul > 0) { 838 cp = mtod(m, caddr_t)+m->m_len-nul; 839 for (i = 0; i < nul; i++) 840 *cp++ = '\0'; 841 } 842 break; 843 } 844 count -= m->m_len; 845 } 846 while (m = m->m_next) 847 m->m_len = 0; 848 } 849 850 /* 851 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 852 * - look up fsid in mount list (if not found ret error) 853 * - check that it is exported 854 * - get vp by calling VFS_FHTOVP() macro 855 * - if not lockflag unlock it with VOP_UNLOCK() 856 * - if cred->cr_uid == 0 set it to m_exroot 857 */ 858 nfsrv_fhtovp(fhp, lockflag, vpp, cred) 859 fhandle_t *fhp; 860 int lockflag; 861 struct vnode **vpp; 862 struct ucred *cred; 863 { 864 register struct mount *mp; 865 int error; 866 867 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 868 return (ESTALE); 869 if ((mp->m_flag & M_EXPORTED) == 0) 870 return (EACCES); 871 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 872 return (ESTALE); 873 if (cred->cr_uid == 0) 874 cred->cr_uid = mp->m_exroot; 875 if (!lockflag) 876 VOP_UNLOCK(*vpp); 877 return (0); 878 } 879 880