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.4 (Berkeley) 08/10/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 vap->va_gen = 0; 605 vap->va_flags = 0; 606 np->n_attrstamp = time.tv_sec; 607 *dposp = dpos; 608 *mdp = md; 609 if (vaper != NULL) 610 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 611 return (0); 612 } 613 614 /* 615 * Check the time stamp 616 * If the cache is valid, copy contents to *vap and return 0 617 * otherwise return an error 618 */ 619 nfs_getattrcache(vp, vap) 620 register struct vnode *vp; 621 struct vattr *vap; 622 { 623 register struct nfsnode *np; 624 625 np = VTONFS(vp); 626 if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 627 nfsstats.attrcache_hits++; 628 bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 629 return (0); 630 } else { 631 nfsstats.attrcache_misses++; 632 return (ENOENT); 633 } 634 } 635 636 /* 637 * nfs_namei - a liitle like namei(), but for one element only 638 * essentially look up file handle, fill in ndp and call VOP_LOOKUP() 639 */ 640 nfs_namei(ndp, fhp, len, mdp, dposp) 641 register struct nameidata *ndp; 642 fhandle_t *fhp; 643 int len; 644 struct mbuf **mdp; 645 caddr_t *dposp; 646 { 647 register int i, rem; 648 register struct mbuf *md; 649 register char *cp; 650 struct vnode *dp = (struct vnode *)0; 651 struct vnode *tdp; 652 struct mount *mp; 653 int flag; 654 int docache; 655 int wantparent; 656 int lockparent; 657 int rootflg = 0; 658 int error = 0; 659 660 ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 661 flag = ndp->ni_nameiop & OPFLAG; 662 wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT); 663 lockparent = ndp->ni_nameiop & LOCKPARENT; 664 docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; 665 if (flag == DELETE || wantparent) 666 docache = 0; 667 668 /* Fill in the nameidata and call lookup */ 669 cp = *dposp; 670 md = *mdp; 671 rem = mtod(md, caddr_t)+md->m_len-cp; 672 ndp->ni_hash = 0; 673 for (i = 0; i < len;) { 674 if (rem == 0) { 675 md = md->m_next; 676 if (md == NULL) 677 return (EBADRPC); 678 cp = mtod(md, caddr_t); 679 rem = md->m_len; 680 } 681 if (*cp == '\0' || *cp == '/') 682 return (EINVAL); 683 if (*cp & 0200) 684 if ((*cp&0377) == ('/'|0200) || flag != DELETE) 685 return (EINVAL); 686 ndp->ni_dent.d_name[i++] = *cp; 687 ndp->ni_hash += (unsigned char)*cp * i; 688 cp++; 689 rem--; 690 } 691 *mdp = md; 692 len = nfsm_rndup(len)-len; 693 if (len > 0) 694 *dposp = cp+len; 695 else 696 *dposp = cp; 697 ndp->ni_namelen = i; 698 ndp->ni_dent.d_namlen = i; 699 ndp->ni_dent.d_name[i] = '\0'; 700 ndp->ni_pathlen = 1; 701 ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; 702 ndp->ni_next = &ndp->ni_dent.d_name[i]; 703 ndp->ni_loopcnt = 0; /* Not actually used for now */ 704 ndp->ni_endoff = 0; 705 if (docache) 706 ndp->ni_makeentry = 1; 707 else 708 ndp->ni_makeentry = 0; 709 ndp->ni_isdotdot = (i == 2 && 710 ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.'); 711 712 if (error = nfsrv_fhtovp(fhp, TRUE, &dp, ndp->ni_cred)) 713 return (error); 714 if (dp->v_type != VDIR) { 715 vput(dp); 716 return (ENOTDIR); 717 } 718 ndp->ni_cdir = dp; 719 ndp->ni_rdir = (struct vnode *)0; 720 721 /* 722 * Handle "..": 723 * If this vnode is the root of the mounted 724 * file system, then ignore it so can't get out 725 */ 726 if (ndp->ni_isdotdot && (dp->v_flag & VROOT)) { 727 ndp->ni_dvp = dp; 728 ndp->ni_vp = dp; 729 VREF(dp); 730 goto nextname; 731 } 732 733 /* 734 * We now have a segment name to search for, and a directory to search. 735 */ 736 if (error = VOP_LOOKUP(dp, ndp)) { 737 if (ndp->ni_vp != NULL) 738 panic("leaf should be empty"); 739 /* 740 * If creating and at end of pathname, then can consider 741 * allowing file to be created. 742 */ 743 if (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) 744 error = EROFS; 745 if (flag == LOOKUP || flag == DELETE || error != ENOENT) 746 goto bad; 747 /* 748 * We return with ni_vp NULL to indicate that the entry 749 * doesn't currently exist, leaving a pointer to the 750 * (possibly locked) directory inode in ndp->ni_dvp. 751 */ 752 return (0); /* should this be ENOENT? */ 753 } 754 755 dp = ndp->ni_vp; 756 757 nextname: 758 ndp->ni_ptr = ndp->ni_next; 759 /* 760 * Check for read-only file systems 761 */ 762 if (flag == DELETE || flag == RENAME) { 763 /* 764 * Disallow directory write attempts on read-only 765 * file systems. 766 */ 767 if ((dp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)) || 768 (wantparent && (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)))) { 769 error = EROFS; 770 goto bad2; 771 } 772 } 773 774 if (!wantparent) 775 vrele(ndp->ni_dvp); 776 777 if ((ndp->ni_nameiop & LOCKLEAF) == 0) 778 VOP_UNLOCK(dp); 779 return (0); 780 781 bad2: 782 if (lockparent) 783 VOP_UNLOCK(ndp->ni_dvp); 784 vrele(ndp->ni_dvp); 785 bad: 786 vput(dp); 787 ndp->ni_vp = NULL; 788 return (error); 789 } 790 791 /* 792 * A fiddled version of m_adj() that ensures null fill to a long 793 * boundary and only trims off the back end 794 */ 795 nfsm_adj(mp, len, nul) 796 struct mbuf *mp; 797 register int len; 798 int nul; 799 { 800 register struct mbuf *m; 801 register int count, i; 802 register char *cp; 803 804 /* 805 * Trim from tail. Scan the mbuf chain, 806 * calculating its length and finding the last mbuf. 807 * If the adjustment only affects this mbuf, then just 808 * adjust and return. Otherwise, rescan and truncate 809 * after the remaining size. 810 */ 811 count = 0; 812 m = mp; 813 for (;;) { 814 count += m->m_len; 815 if (m->m_next == (struct mbuf *)0) 816 break; 817 m = m->m_next; 818 } 819 if (m->m_len > len) { 820 m->m_len -= len; 821 if (nul > 0) { 822 cp = mtod(m, caddr_t)+m->m_len-nul; 823 for (i = 0; i < nul; i++) 824 *cp++ = '\0'; 825 } 826 return; 827 } 828 count -= len; 829 if (count < 0) 830 count = 0; 831 /* 832 * Correct length for chain is "count". 833 * Find the mbuf with last data, adjust its length, 834 * and toss data from remaining mbufs on chain. 835 */ 836 for (m = mp; m; m = m->m_next) { 837 if (m->m_len >= count) { 838 m->m_len = count; 839 if (nul > 0) { 840 cp = mtod(m, caddr_t)+m->m_len-nul; 841 for (i = 0; i < nul; i++) 842 *cp++ = '\0'; 843 } 844 break; 845 } 846 count -= m->m_len; 847 } 848 while (m = m->m_next) 849 m->m_len = 0; 850 } 851 852 /* 853 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 854 * - look up fsid in mount list (if not found ret error) 855 * - check that it is exported 856 * - get vp by calling VFS_FHTOVP() macro 857 * - if not lockflag unlock it with VOP_UNLOCK() 858 * - if cred->cr_uid == 0 set it to m_exroot 859 */ 860 nfsrv_fhtovp(fhp, lockflag, vpp, cred) 861 fhandle_t *fhp; 862 int lockflag; 863 struct vnode **vpp; 864 struct ucred *cred; 865 { 866 register struct mount *mp; 867 int error; 868 869 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 870 return (ESTALE); 871 if ((mp->m_flag & M_EXPORTED) == 0) 872 return (EACCES); 873 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 874 return (ESTALE); 875 if (cred->cr_uid == 0) 876 cred->cr_uid = mp->m_exroot; 877 if (!lockflag) 878 VOP_UNLOCK(*vpp); 879 return (0); 880 } 881 882