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