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 * %sccs.include.redist.c% 9 * 10 * @(#)nfs_subs.c 7.29 (Berkeley) 07/26/90 11 */ 12 13 /* 14 * These functions support the macros and help fiddle mbuf chains for 15 * the nfs op functions. They do things like create the rpc header and 16 * copy data between mbuf chains and uio lists. 17 */ 18 #include "param.h" 19 #include "user.h" 20 #include "proc.h" 21 #include "systm.h" 22 #include "kernel.h" 23 #include "mount.h" 24 #include "file.h" 25 #include "vnode.h" 26 #include "mbuf.h" 27 #include "errno.h" 28 #include "map.h" 29 #include "rpcv2.h" 30 #include "nfsv2.h" 31 #include "nfsnode.h" 32 #include "nfs.h" 33 #include "nfsiom.h" 34 #include "xdr_subs.h" 35 #include "nfsm_subs.h" 36 37 #define TRUE 1 38 #define FALSE 0 39 40 /* 41 * Data items converted to xdr at startup, since they are constant 42 * This is kinda hokey, but may save a little time doing byte swaps 43 */ 44 u_long nfs_procids[NFS_NPROCS]; 45 u_long nfs_xdrneg1; 46 u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 47 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 48 u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 49 /* And other global data */ 50 static u_long *rpc_uidp = (u_long *)0; 51 static u_long nfs_xid = 1; 52 static char *rpc_unixauth; 53 extern long hostid; 54 enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 55 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 56 extern struct map nfsmap[NFS_MSIZ]; 57 extern struct nfsreq nfsreqh; 58 59 /* Function ret types */ 60 static char *nfs_unixauth(); 61 62 /* 63 * Maximum number of groups passed through to NFS server. 64 * According to RFC1057 it should be 16. 65 * For release 3.X systems, the maximum value is 8. 66 * For some other servers, the maximum value is 10. 67 */ 68 int numgrps = 8; 69 70 /* 71 * Create the header for an rpc request packet 72 * The function nfs_unixauth() creates a unix style authorization string 73 * and returns a ptr to it. 74 * The hsiz is the size of the rest of the nfs request header. 75 * (just used to decide if a cluster is a good idea) 76 * nb: Note that the prog, vers and procid args are already in xdr byte order 77 */ 78 struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid) 79 u_long prog; 80 u_long vers; 81 u_long procid; 82 struct ucred *cred; 83 int hsiz; 84 caddr_t *bpos; 85 struct mbuf **mb; 86 u_long *retxid; 87 { 88 register struct mbuf *mreq, *m; 89 register u_long *p; 90 struct mbuf *m1; 91 char *ap; 92 int asiz, siz; 93 94 NFSMGETHDR(mreq); 95 asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps : 96 (cred->cr_ngroups - 1)) << 2); 97 #ifdef FILLINHOST 98 asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 99 #else 100 asiz += 9*NFSX_UNSIGNED; 101 #endif 102 103 /* If we need a lot, alloc a cluster ?? */ 104 if ((asiz+hsiz+RPC_SIZ) > MHLEN) 105 MCLGET(mreq, M_WAIT); 106 mreq->m_len = NFSMSIZ(mreq); 107 siz = mreq->m_len; 108 m1 = mreq; 109 /* 110 * Alloc enough mbufs 111 * We do it now to avoid all sleeps after the call to nfs_unixauth() 112 */ 113 while ((asiz+RPC_SIZ) > siz) { 114 MGET(m, M_WAIT, MT_DATA); 115 m1->m_next = m; 116 m->m_len = MLEN; 117 siz += MLEN; 118 m1 = m; 119 } 120 p = mtod(mreq, u_long *); 121 *p++ = *retxid = txdr_unsigned(++nfs_xid); 122 *p++ = rpc_call; 123 *p++ = rpc_vers; 124 *p++ = prog; 125 *p++ = vers; 126 *p++ = procid; 127 128 /* Now we can call nfs_unixauth() and copy it in */ 129 ap = nfs_unixauth(cred); 130 m = mreq; 131 siz = m->m_len-RPC_SIZ; 132 if (asiz <= siz) { 133 bcopy(ap, (caddr_t)p, asiz); 134 m->m_len = asiz+RPC_SIZ; 135 } else { 136 bcopy(ap, (caddr_t)p, siz); 137 ap += siz; 138 asiz -= siz; 139 while (asiz > 0) { 140 siz = (asiz > MLEN) ? MLEN : asiz; 141 m = m->m_next; 142 bcopy(ap, mtod(m, caddr_t), siz); 143 m->m_len = siz; 144 asiz -= siz; 145 ap += siz; 146 } 147 } 148 149 /* Finally, return values */ 150 *mb = m; 151 *bpos = mtod(m, caddr_t)+m->m_len; 152 return (mreq); 153 } 154 155 /* 156 * copies mbuf chain to the uio scatter/gather list 157 */ 158 nfsm_mbuftouio(mrep, uiop, siz, dpos) 159 struct mbuf **mrep; 160 register struct uio *uiop; 161 int siz; 162 caddr_t *dpos; 163 { 164 register char *mbufcp, *uiocp; 165 register int xfer, left, len; 166 register struct mbuf *mp; 167 long uiosiz, rem; 168 int error = 0; 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_offset += xfer; 207 uiop->uio_resid -= xfer; 208 } 209 if (uiop->uio_iov->iov_len <= siz) { 210 uiop->uio_iovcnt--; 211 uiop->uio_iov++; 212 } else { 213 uiop->uio_iov->iov_base += uiosiz; 214 uiop->uio_iov->iov_len -= uiosiz; 215 } 216 siz -= uiosiz; 217 } 218 *dpos = mbufcp; 219 *mrep = mp; 220 if (rem > 0) { 221 if (len < rem) 222 error = nfs_adv(mrep, dpos, rem, len); 223 else 224 *dpos += rem; 225 } 226 return (error); 227 } 228 229 /* 230 * copies a uio scatter/gather list to an mbuf chain... 231 */ 232 nfsm_uiotombuf(uiop, mq, siz, bpos) 233 register struct uio *uiop; 234 struct mbuf **mq; 235 int siz; 236 caddr_t *bpos; 237 { 238 register char *uiocp; 239 register struct mbuf *mp, *mp2; 240 register int xfer, left, len; 241 int uiosiz, clflg, rem; 242 char *cp; 243 244 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 245 clflg = 1; 246 else 247 clflg = 0; 248 rem = nfsm_rndup(siz)-siz; 249 mp2 = *mq; 250 while (siz > 0) { 251 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 252 return (EINVAL); 253 left = uiop->uio_iov->iov_len; 254 uiocp = uiop->uio_iov->iov_base; 255 if (left > siz) 256 left = siz; 257 uiosiz = left; 258 while (left > 0) { 259 MGET(mp, M_WAIT, MT_DATA); 260 if (clflg) 261 MCLGET(mp, M_WAIT); 262 mp->m_len = NFSMSIZ(mp); 263 mp2->m_next = mp; 264 mp2 = mp; 265 xfer = (left > mp->m_len) ? mp->m_len : left; 266 #ifdef notdef 267 /* Not Yet.. */ 268 if (uiop->uio_iov->iov_op != NULL) 269 (*(uiop->uio_iov->iov_op)) 270 (uiocp, mtod(mp, caddr_t), xfer); 271 else 272 #endif 273 if (uiop->uio_segflg == UIO_SYSSPACE) 274 bcopy(uiocp, mtod(mp, caddr_t), xfer); 275 else 276 copyin(uiocp, mtod(mp, caddr_t), xfer); 277 len = mp->m_len; 278 mp->m_len = xfer; 279 left -= xfer; 280 uiocp += xfer; 281 uiop->uio_offset += xfer; 282 uiop->uio_resid -= xfer; 283 } 284 if (uiop->uio_iov->iov_len <= siz) { 285 uiop->uio_iovcnt--; 286 uiop->uio_iov++; 287 } else { 288 uiop->uio_iov->iov_base += uiosiz; 289 uiop->uio_iov->iov_len -= uiosiz; 290 } 291 siz -= uiosiz; 292 } 293 if (rem > 0) { 294 if (rem > (len-mp->m_len)) { 295 MGET(mp, M_WAIT, MT_DATA); 296 mp->m_len = 0; 297 mp2->m_next = mp; 298 } 299 cp = mtod(mp, caddr_t)+mp->m_len; 300 for (left = 0; left < rem; left++) 301 *cp++ = '\0'; 302 mp->m_len += rem; 303 *bpos = cp; 304 } else 305 *bpos = mtod(mp, caddr_t)+mp->m_len; 306 *mq = mp; 307 return (0); 308 } 309 310 /* 311 * Help break down an mbuf chain by setting the first siz bytes contiguous 312 * pointed to by returned val. 313 * If Updateflg == True we can overwrite the first part of the mbuf data 314 * This is used by the macros nfsm_disect and nfsm_disecton for tough 315 * cases. (The macros use the vars. dpos and dpos2) 316 */ 317 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 318 struct mbuf **mdp; 319 caddr_t *dposp; 320 int siz; 321 int left; 322 int updateflg; 323 caddr_t *cp2; 324 { 325 register struct mbuf *mp, *mp2; 326 register int siz2, xfer; 327 register caddr_t p; 328 329 mp = *mdp; 330 while (left == 0) { 331 *mdp = mp = mp->m_next; 332 if (mp == NULL) 333 return (EBADRPC); 334 left = mp->m_len; 335 *dposp = mtod(mp, caddr_t); 336 } 337 if (left >= siz) { 338 *cp2 = *dposp; 339 *dposp += siz; 340 } else if (mp->m_next == NULL) { 341 return (EBADRPC); 342 } else if (siz > MHLEN) { 343 panic("nfs S too big"); 344 } else { 345 /* Iff update, you can overwrite, else must alloc new mbuf */ 346 if (updateflg) { 347 NFSMINOFF(mp); 348 } else { 349 MGET(mp2, M_WAIT, MT_DATA); 350 mp2->m_next = mp->m_next; 351 mp->m_next = mp2; 352 mp->m_len -= left; 353 mp = mp2; 354 } 355 *cp2 = p = mtod(mp, caddr_t); 356 bcopy(*dposp, p, left); /* Copy what was left */ 357 siz2 = siz-left; 358 p += left; 359 mp2 = mp->m_next; 360 /* Loop around copying up the siz2 bytes */ 361 while (siz2 > 0) { 362 if (mp2 == NULL) 363 return (EBADRPC); 364 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 365 if (xfer > 0) { 366 bcopy(mtod(mp2, caddr_t), p, xfer); 367 NFSMADV(mp2, xfer); 368 mp2->m_len -= xfer; 369 p += xfer; 370 siz2 -= xfer; 371 } 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 } 379 return (0); 380 } 381 382 /* 383 * Advance the position in the mbuf chain. 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 MCLGET(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 nfs_init() 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 /* Ensure async daemons disabled */ 495 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 496 nfs_iodwant[i] = (struct proc *)0; 497 nfs_xdrneg1 = txdr_unsigned(-1); 498 nfs_nhinit(); /* Init the nfsnode table */ 499 nfsrv_initcache(); /* Init the server request cache */ 500 rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); 501 502 /* 503 * Initialize reply list and start timer 504 */ 505 nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 506 nfs_timer(); 507 } 508 509 /* 510 * Fill in the rest of the rpc_unixauth and return it 511 */ 512 static char *nfs_unixauth(cr) 513 register struct ucred *cr; 514 { 515 register u_long *p; 516 register int i; 517 int ngr; 518 519 /* Maybe someday there should be a cache of AUTH_SHORT's */ 520 if ((p = rpc_uidp) == NULL) { 521 #ifdef FILLINHOST 522 i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED); 523 #else 524 i = 25*NFSX_UNSIGNED; 525 #endif 526 MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); 527 bzero((caddr_t)p, i); 528 rpc_unixauth = (caddr_t)p; 529 *p++ = txdr_unsigned(RPCAUTH_UNIX); 530 p++; /* Fill in size later */ 531 *p++ = hostid; 532 #ifdef FILLINHOST 533 *p++ = txdr_unsigned(hostnamelen); 534 i = nfsm_rndup(hostnamelen); 535 bcopy(hostname, (caddr_t)p, hostnamelen); 536 p += (i>>2); 537 #else 538 *p++ = 0; 539 #endif 540 rpc_uidp = p; 541 } 542 *p++ = txdr_unsigned(cr->cr_uid); 543 *p++ = txdr_unsigned(cr->cr_groups[0]); 544 ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1); 545 *p++ = txdr_unsigned(ngr); 546 for (i = 1; i <= ngr; i++) 547 *p++ = txdr_unsigned(cr->cr_groups[i]); 548 /* And add the AUTH_NULL */ 549 *p++ = 0; 550 *p = 0; 551 i = (((caddr_t)p)-rpc_unixauth)-12; 552 p = (u_long *)(rpc_unixauth+4); 553 *p = txdr_unsigned(i); 554 return (rpc_unixauth); 555 } 556 557 /* 558 * Attribute cache routines. 559 * nfs_loadattrcache() - loads or updates the cache contents from attributes 560 * that are on the mbuf list 561 * nfs_getattrcache() - returns valid attributes if found in cache, returns 562 * error otherwise 563 */ 564 565 /* 566 * Load the attribute cache (that lives in the nfsnode entry) with 567 * the values on the mbuf list and 568 * Iff vap not NULL 569 * copy the attributes to *vaper 570 */ 571 nfs_loadattrcache(vpp, mdp, dposp, vaper) 572 struct vnode **vpp; 573 struct mbuf **mdp; 574 caddr_t *dposp; 575 struct vattr *vaper; 576 { 577 register struct vnode *vp = *vpp; 578 register struct vattr *vap; 579 register struct nfsv2_fattr *fp; 580 extern struct vnodeops spec_nfsv2nodeops; 581 register struct nfsnode *np; 582 register long t1; 583 caddr_t dpos, cp2; 584 int error = 0; 585 struct mbuf *md; 586 enum vtype type; 587 long rdev; 588 struct timeval mtime; 589 struct vnode *nvp; 590 591 md = *mdp; 592 dpos = *dposp; 593 t1 = (mtod(md, caddr_t)+md->m_len)-dpos; 594 if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 595 return (error); 596 fp = (struct nfsv2_fattr *)cp2; 597 type = nfstov_type(fp->fa_type); 598 rdev = fxdr_unsigned(long, fp->fa_rdev); 599 fxdr_time(&fp->fa_mtime, &mtime); 600 /* 601 * If v_type == VNON it is a new node, so fill in the v_type, 602 * n_mtime fields. Check to see if it represents a special 603 * device, and if so, check for a possible alias. Once the 604 * correct vnode has been obtained, fill in the rest of the 605 * information. 606 */ 607 np = VTONFS(vp); 608 if (vp->v_type == VNON) { 609 if (type == VCHR && rdev == 0xffffffff) 610 vp->v_type = type = VFIFO; 611 else 612 vp->v_type = type; 613 if (vp->v_type == VFIFO) { 614 #ifdef FIFO 615 extern struct vnodeops fifo_nfsv2nodeops; 616 vp->v_op = &fifo_nfsv2nodeops; 617 #else 618 return (EOPNOTSUPP); 619 #endif /* FIFO */ 620 } 621 if (vp->v_type == VCHR || vp->v_type == VBLK) { 622 vp->v_op = &spec_nfsv2nodeops; 623 if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 624 /* 625 * Reinitialize aliased node. 626 */ 627 np = VTONFS(nvp); 628 np->n_vnode = nvp; 629 np->n_flag = 0; 630 nfs_lock(nvp); 631 bcopy((caddr_t)&VTONFS(vp)->n_fh, 632 (caddr_t)&np->n_fh, NFSX_FH); 633 insque(np, nfs_hash(&np->n_fh)); 634 np->n_attrstamp = 0; 635 np->n_sillyrename = (struct sillyrename *)0; 636 /* 637 * Discard unneeded vnode and update actual one 638 */ 639 vput(vp); 640 *vpp = nvp; 641 } 642 } 643 np->n_mtime = mtime.tv_sec; 644 } 645 vap = &np->n_vattr; 646 vap->va_type = type; 647 vap->va_mode = nfstov_mode(fp->fa_mode); 648 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 649 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 650 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 651 vap->va_size = fxdr_unsigned(u_long, fp->fa_size); 652 if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) 653 np->n_size = vap->va_size; 654 vap->va_size_rsv = 0; 655 vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 656 vap->va_rdev = (dev_t)rdev; 657 vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; 658 vap->va_bytes_rsv = 0; 659 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 660 vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); 661 vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); 662 vap->va_atime.tv_usec = 0; 663 vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); 664 vap->va_mtime = mtime; 665 vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); 666 vap->va_ctime.tv_usec = 0; 667 vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); 668 np->n_attrstamp = time.tv_sec; 669 *dposp = dpos; 670 *mdp = md; 671 if (vaper != NULL) { 672 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 673 if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 674 vaper->va_size = np->n_size; 675 } 676 return (0); 677 } 678 679 /* 680 * Check the time stamp 681 * If the cache is valid, copy contents to *vap and return 0 682 * otherwise return an error 683 */ 684 nfs_getattrcache(vp, vap) 685 register struct vnode *vp; 686 struct vattr *vap; 687 { 688 register struct nfsnode *np; 689 690 np = VTONFS(vp); 691 if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 692 nfsstats.attrcache_hits++; 693 bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 694 if ((np->n_flag & NMODIFIED) == 0) 695 np->n_size = vap->va_size; 696 else if (np->n_size > vap->va_size) 697 vap->va_size = np->n_size; 698 return (0); 699 } else { 700 nfsstats.attrcache_misses++; 701 return (ENOENT); 702 } 703 } 704 705 /* 706 * Set up nameidata for a namei() call and do it 707 */ 708 nfs_namei(ndp, fhp, len, mdp, dposp) 709 register struct nameidata *ndp; 710 fhandle_t *fhp; 711 int len; 712 struct mbuf **mdp; 713 caddr_t *dposp; 714 { 715 register int i, rem; 716 register struct mbuf *md; 717 register char *cp; 718 struct vnode *dp; 719 int flag; 720 int error; 721 722 if ((ndp->ni_nameiop & HASBUF) == 0) { 723 flag = ndp->ni_nameiop & OPFLAG; 724 /* 725 * Copy the name from the mbuf list to the d_name field of ndp 726 * and set the various ndp fields appropriately. 727 */ 728 cp = *dposp; 729 md = *mdp; 730 rem = mtod(md, caddr_t)+md->m_len-cp; 731 ndp->ni_hash = 0; 732 for (i = 0; i < len;) { 733 while (rem == 0) { 734 md = md->m_next; 735 if (md == NULL) 736 return (EBADRPC); 737 cp = mtod(md, caddr_t); 738 rem = md->m_len; 739 } 740 if (*cp == '\0' || *cp == '/') 741 return (EINVAL); 742 if (*cp & 0200) 743 if ((*cp&0377) == ('/'|0200) || flag != DELETE) 744 return (EINVAL); 745 ndp->ni_dent.d_name[i++] = *cp; 746 ndp->ni_hash += (unsigned char)*cp * i; 747 cp++; 748 rem--; 749 } 750 *mdp = md; 751 *dposp = cp; 752 len = nfsm_rndup(len)-len; 753 if (len > 0) { 754 if (rem < len) { 755 if (error = nfs_adv(mdp, dposp, len, rem)) 756 return (error); 757 } else 758 *dposp += len; 759 } 760 } else 761 i = len; 762 ndp->ni_namelen = i; 763 ndp->ni_dent.d_namlen = i; 764 ndp->ni_dent.d_name[i] = '\0'; 765 ndp->ni_segflg = UIO_SYSSPACE; 766 ndp->ni_pathlen = 1; 767 ndp->ni_pnbuf = ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; 768 ndp->ni_next = &ndp->ni_dent.d_name[i]; 769 ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE | HASBUF); 770 771 if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) 772 return (error); 773 if (dp->v_type != VDIR) { 774 vrele(dp); 775 return (ENOTDIR); 776 } 777 /* 778 * Must set current directory here to avoid confusion in namei() 779 * called from rename() 780 */ 781 ndp->ni_cdir = dp; 782 ndp->ni_rdir = NULLVP; 783 784 /* 785 * And call namei() to do the real work 786 */ 787 error = namei(ndp); 788 vrele(dp); 789 return (error); 790 } 791 792 /* 793 * A fiddled version of m_adj() that ensures null fill to a long 794 * boundary and only trims off the back end 795 */ 796 nfsm_adj(mp, len, nul) 797 struct mbuf *mp; 798 register int len; 799 int nul; 800 { 801 register struct mbuf *m; 802 register int count, i; 803 register char *cp; 804 805 /* 806 * Trim from tail. Scan the mbuf chain, 807 * calculating its length and finding the last mbuf. 808 * If the adjustment only affects this mbuf, then just 809 * adjust and return. Otherwise, rescan and truncate 810 * after the remaining size. 811 */ 812 count = 0; 813 m = mp; 814 for (;;) { 815 count += m->m_len; 816 if (m->m_next == (struct mbuf *)0) 817 break; 818 m = m->m_next; 819 } 820 if (m->m_len > len) { 821 m->m_len -= len; 822 if (nul > 0) { 823 cp = mtod(m, caddr_t)+m->m_len-nul; 824 for (i = 0; i < nul; i++) 825 *cp++ = '\0'; 826 } 827 return; 828 } 829 count -= len; 830 if (count < 0) 831 count = 0; 832 /* 833 * Correct length for chain is "count". 834 * Find the mbuf with last data, adjust its length, 835 * and toss data from remaining mbufs on chain. 836 */ 837 for (m = mp; m; m = m->m_next) { 838 if (m->m_len >= count) { 839 m->m_len = count; 840 if (nul > 0) { 841 cp = mtod(m, caddr_t)+m->m_len-nul; 842 for (i = 0; i < nul; i++) 843 *cp++ = '\0'; 844 } 845 break; 846 } 847 count -= m->m_len; 848 } 849 while (m = m->m_next) 850 m->m_len = 0; 851 } 852 853 /* 854 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 855 * - look up fsid in mount list (if not found ret error) 856 * - check that it is exported 857 * - get vp by calling VFS_FHTOVP() macro 858 * - if not lockflag unlock it with VOP_UNLOCK() 859 * - if cred->cr_uid == 0 set it to m_exroot 860 */ 861 nfsrv_fhtovp(fhp, lockflag, vpp, cred) 862 fhandle_t *fhp; 863 int lockflag; 864 struct vnode **vpp; 865 struct ucred *cred; 866 { 867 register struct mount *mp; 868 869 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 870 return (ESTALE); 871 if ((mp->mnt_flag & MNT_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->mnt_exroot; 877 if (!lockflag) 878 VOP_UNLOCK(*vpp); 879 return (0); 880 } 881