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