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.28 (Berkeley) 06/28/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 release 4.X systems, 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 > numgrps) ? numgrps : cred->cr_ngroups)<<2); 96 #ifdef FILLINHOST 97 asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 98 #else 99 asiz += 9*NFSX_UNSIGNED; 100 #endif 101 102 /* If we need a lot, alloc a cluster ?? */ 103 if ((asiz+hsiz+RPC_SIZ) > MHLEN) 104 MCLGET(mreq, M_WAIT); 105 mreq->m_len = NFSMSIZ(mreq); 106 siz = mreq->m_len; 107 m1 = mreq; 108 /* 109 * Alloc enough mbufs 110 * We do it now to avoid all sleeps after the call to nfs_unixauth() 111 */ 112 while ((asiz+RPC_SIZ) > siz) { 113 MGET(m, M_WAIT, MT_DATA); 114 m1->m_next = m; 115 m->m_len = MLEN; 116 siz += MLEN; 117 m1 = m; 118 } 119 p = mtod(mreq, u_long *); 120 *p++ = *retxid = txdr_unsigned(++nfs_xid); 121 *p++ = rpc_call; 122 *p++ = rpc_vers; 123 *p++ = prog; 124 *p++ = vers; 125 *p++ = procid; 126 127 /* Now we can call nfs_unixauth() and copy it in */ 128 ap = nfs_unixauth(cred); 129 m = mreq; 130 siz = m->m_len-RPC_SIZ; 131 if (asiz <= siz) { 132 bcopy(ap, (caddr_t)p, asiz); 133 m->m_len = asiz+RPC_SIZ; 134 } else { 135 bcopy(ap, (caddr_t)p, siz); 136 ap += siz; 137 asiz -= siz; 138 while (asiz > 0) { 139 siz = (asiz > MLEN) ? MLEN : asiz; 140 m = m->m_next; 141 bcopy(ap, mtod(m, caddr_t), siz); 142 m->m_len = siz; 143 asiz -= siz; 144 ap += siz; 145 } 146 } 147 148 /* Finally, return values */ 149 *mb = m; 150 *bpos = mtod(m, caddr_t)+m->m_len; 151 return (mreq); 152 } 153 154 /* 155 * copies mbuf chain to the uio scatter/gather list 156 */ 157 nfsm_mbuftouio(mrep, uiop, siz, dpos) 158 struct mbuf **mrep; 159 register struct uio *uiop; 160 int siz; 161 caddr_t *dpos; 162 { 163 register char *mbufcp, *uiocp; 164 register int xfer, left, len; 165 register struct mbuf *mp; 166 long uiosiz, rem; 167 int error = 0; 168 169 mp = *mrep; 170 mbufcp = *dpos; 171 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 172 rem = nfsm_rndup(siz)-siz; 173 while (siz > 0) { 174 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 175 return (EFBIG); 176 left = uiop->uio_iov->iov_len; 177 uiocp = uiop->uio_iov->iov_base; 178 if (left > siz) 179 left = siz; 180 uiosiz = left; 181 while (left > 0) { 182 while (len == 0) { 183 mp = mp->m_next; 184 if (mp == NULL) 185 return (EBADRPC); 186 mbufcp = mtod(mp, caddr_t); 187 len = mp->m_len; 188 } 189 xfer = (left > len) ? len : left; 190 #ifdef notdef 191 /* Not Yet.. */ 192 if (uiop->uio_iov->iov_op != NULL) 193 (*(uiop->uio_iov->iov_op)) 194 (mbufcp, uiocp, xfer); 195 else 196 #endif 197 if (uiop->uio_segflg == UIO_SYSSPACE) 198 bcopy(mbufcp, uiocp, xfer); 199 else 200 copyout(mbufcp, uiocp, xfer); 201 left -= xfer; 202 len -= xfer; 203 mbufcp += xfer; 204 uiocp += xfer; 205 uiop->uio_offset += 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 *dpos = mbufcp; 218 *mrep = mp; 219 if (rem > 0) { 220 if (len < rem) 221 error = nfs_adv(mrep, dpos, rem, len); 222 else 223 *dpos += rem; 224 } 225 return (error); 226 } 227 228 /* 229 * copies a uio scatter/gather list to an mbuf chain... 230 */ 231 nfsm_uiotombuf(uiop, mq, siz, bpos) 232 register struct uio *uiop; 233 struct mbuf **mq; 234 int siz; 235 caddr_t *bpos; 236 { 237 register char *uiocp; 238 register struct mbuf *mp, *mp2; 239 register int xfer, left, len; 240 int uiosiz, clflg, rem; 241 char *cp; 242 243 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 244 clflg = 1; 245 else 246 clflg = 0; 247 rem = nfsm_rndup(siz)-siz; 248 mp2 = *mq; 249 while (siz > 0) { 250 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 251 return (EINVAL); 252 left = uiop->uio_iov->iov_len; 253 uiocp = uiop->uio_iov->iov_base; 254 if (left > siz) 255 left = siz; 256 uiosiz = left; 257 while (left > 0) { 258 MGET(mp, M_WAIT, MT_DATA); 259 if (clflg) 260 MCLGET(mp, M_WAIT); 261 mp->m_len = NFSMSIZ(mp); 262 mp2->m_next = mp; 263 mp2 = mp; 264 xfer = (left > mp->m_len) ? mp->m_len : left; 265 #ifdef notdef 266 /* Not Yet.. */ 267 if (uiop->uio_iov->iov_op != NULL) 268 (*(uiop->uio_iov->iov_op)) 269 (uiocp, mtod(mp, caddr_t), xfer); 270 else 271 #endif 272 if (uiop->uio_segflg == UIO_SYSSPACE) 273 bcopy(uiocp, mtod(mp, caddr_t), xfer); 274 else 275 copyin(uiocp, mtod(mp, caddr_t), xfer); 276 len = mp->m_len; 277 mp->m_len = xfer; 278 left -= xfer; 279 uiocp += xfer; 280 uiop->uio_offset += xfer; 281 uiop->uio_resid -= xfer; 282 } 283 if (uiop->uio_iov->iov_len <= siz) { 284 uiop->uio_iovcnt--; 285 uiop->uio_iov++; 286 } else { 287 uiop->uio_iov->iov_base += uiosiz; 288 uiop->uio_iov->iov_len -= uiosiz; 289 } 290 siz -= uiosiz; 291 } 292 if (rem > 0) { 293 if (rem > (len-mp->m_len)) { 294 MGET(mp, M_WAIT, MT_DATA); 295 mp->m_len = 0; 296 mp2->m_next = mp; 297 } 298 cp = mtod(mp, caddr_t)+mp->m_len; 299 for (left = 0; left < rem; left++) 300 *cp++ = '\0'; 301 mp->m_len += rem; 302 *bpos = cp; 303 } else 304 *bpos = mtod(mp, caddr_t)+mp->m_len; 305 *mq = mp; 306 return (0); 307 } 308 309 /* 310 * Help break down an mbuf chain by setting the first siz bytes contiguous 311 * pointed to by returned val. 312 * If Updateflg == True we can overwrite the first part of the mbuf data 313 * This is used by the macros nfsm_disect and nfsm_disecton for tough 314 * cases. (The macros use the vars. dpos and dpos2) 315 */ 316 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 317 struct mbuf **mdp; 318 caddr_t *dposp; 319 int siz; 320 int left; 321 int updateflg; 322 caddr_t *cp2; 323 { 324 register struct mbuf *mp, *mp2; 325 register int siz2, xfer; 326 register caddr_t p; 327 328 mp = *mdp; 329 while (left == 0) { 330 *mdp = mp = mp->m_next; 331 if (mp == NULL) 332 return (EBADRPC); 333 left = mp->m_len; 334 *dposp = mtod(mp, caddr_t); 335 } 336 if (left >= siz) { 337 *cp2 = *dposp; 338 *dposp += siz; 339 } else if (mp->m_next == NULL) { 340 return (EBADRPC); 341 } else if (siz > MHLEN) { 342 panic("nfs S too big"); 343 } else { 344 /* Iff update, you can overwrite, else must alloc new mbuf */ 345 if (updateflg) { 346 NFSMINOFF(mp); 347 } else { 348 MGET(mp2, M_WAIT, MT_DATA); 349 mp2->m_next = mp->m_next; 350 mp->m_next = mp2; 351 mp->m_len -= left; 352 mp = mp2; 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 around 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 if (xfer > 0) { 365 bcopy(mtod(mp2, caddr_t), p, xfer); 366 NFSMADV(mp2, xfer); 367 mp2->m_len -= xfer; 368 p += xfer; 369 siz2 -= xfer; 370 } 371 if (siz2 > 0) 372 mp2 = mp2->m_next; 373 } 374 mp->m_len = siz; 375 *mdp = mp2; 376 *dposp = mtod(mp2, caddr_t); 377 } 378 return (0); 379 } 380 381 /* 382 * Advance the position in the mbuf chain. 383 */ 384 nfs_adv(mdp, dposp, offs, left) 385 struct mbuf **mdp; 386 caddr_t *dposp; 387 int offs; 388 int left; 389 { 390 register struct mbuf *m; 391 register int s; 392 393 m = *mdp; 394 s = left; 395 while (s < offs) { 396 offs -= s; 397 m = m->m_next; 398 if (m == NULL) 399 return (EBADRPC); 400 s = m->m_len; 401 } 402 *mdp = m; 403 *dposp = mtod(m, caddr_t)+offs; 404 return (0); 405 } 406 407 /* 408 * Copy a string into mbufs for the hard cases... 409 */ 410 nfsm_strtmbuf(mb, bpos, cp, siz) 411 struct mbuf **mb; 412 char **bpos; 413 char *cp; 414 long siz; 415 { 416 register struct mbuf *m1, *m2; 417 long left, xfer, len, tlen; 418 u_long *p; 419 int putsize; 420 421 putsize = 1; 422 m2 = *mb; 423 left = NFSMSIZ(m2)-m2->m_len; 424 if (left > 0) { 425 p = ((u_long *)(*bpos)); 426 *p++ = txdr_unsigned(siz); 427 putsize = 0; 428 left -= NFSX_UNSIGNED; 429 m2->m_len += NFSX_UNSIGNED; 430 if (left > 0) { 431 bcopy(cp, (caddr_t) p, left); 432 siz -= left; 433 cp += left; 434 m2->m_len += left; 435 left = 0; 436 } 437 } 438 /* Loop arround adding mbufs */ 439 while (siz > 0) { 440 MGET(m1, M_WAIT, MT_DATA); 441 if (siz > MLEN) 442 MCLGET(m1, M_WAIT); 443 m1->m_len = NFSMSIZ(m1); 444 m2->m_next = m1; 445 m2 = m1; 446 p = mtod(m1, u_long *); 447 tlen = 0; 448 if (putsize) { 449 *p++ = txdr_unsigned(siz); 450 m1->m_len -= NFSX_UNSIGNED; 451 tlen = NFSX_UNSIGNED; 452 putsize = 0; 453 } 454 if (siz < m1->m_len) { 455 len = nfsm_rndup(siz); 456 xfer = siz; 457 if (xfer < len) 458 *(p+(xfer>>2)) = 0; 459 } else { 460 xfer = len = m1->m_len; 461 } 462 bcopy(cp, (caddr_t) p, xfer); 463 m1->m_len = len+tlen; 464 siz -= xfer; 465 cp += xfer; 466 } 467 *mb = m1; 468 *bpos = mtod(m1, caddr_t)+m1->m_len; 469 return (0); 470 } 471 472 /* 473 * Called once to initialize data structures... 474 */ 475 nfs_init() 476 { 477 register int i; 478 479 rpc_vers = txdr_unsigned(RPC_VER2); 480 rpc_call = txdr_unsigned(RPC_CALL); 481 rpc_reply = txdr_unsigned(RPC_REPLY); 482 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 483 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 484 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 485 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 486 nfs_vers = txdr_unsigned(NFS_VER2); 487 nfs_prog = txdr_unsigned(NFS_PROG); 488 nfs_true = txdr_unsigned(TRUE); 489 nfs_false = txdr_unsigned(FALSE); 490 /* Loop thru nfs procids */ 491 for (i = 0; i < NFS_NPROCS; i++) 492 nfs_procids[i] = txdr_unsigned(i); 493 /* Ensure async daemons disabled */ 494 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 495 nfs_iodwant[i] = (struct proc *)0; 496 nfs_xdrneg1 = txdr_unsigned(-1); 497 nfs_nhinit(); /* Init the nfsnode table */ 498 nfsrv_initcache(); /* Init the server request cache */ 499 rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); 500 501 /* 502 * Initialize reply list and start timer 503 */ 504 nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 505 nfs_timer(); 506 } 507 508 /* 509 * Fill in the rest of the rpc_unixauth and return it 510 */ 511 static char *nfs_unixauth(cr) 512 register struct ucred *cr; 513 { 514 register u_long *p; 515 register int i; 516 int ngr; 517 518 /* Maybe someday there should be a cache of AUTH_SHORT's */ 519 if ((p = rpc_uidp) == NULL) { 520 #ifdef FILLINHOST 521 i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED); 522 #else 523 i = 19*NFSX_UNSIGNED; 524 #endif 525 MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); 526 bzero((caddr_t)p, i); 527 rpc_unixauth = (caddr_t)p; 528 *p++ = txdr_unsigned(RPCAUTH_UNIX); 529 p++; /* Fill in size later */ 530 *p++ = hostid; 531 #ifdef FILLINHOST 532 *p++ = txdr_unsigned(hostnamelen); 533 i = nfsm_rndup(hostnamelen); 534 bcopy(hostname, (caddr_t)p, hostnamelen); 535 p += (i>>2); 536 #else 537 *p++ = 0; 538 #endif 539 rpc_uidp = p; 540 } 541 *p++ = txdr_unsigned(cr->cr_uid); 542 *p++ = txdr_unsigned(cr->cr_groups[0]); 543 ngr = (cr->cr_ngroups > numgrps) ? numgrps : cr->cr_ngroups; 544 *p++ = txdr_unsigned(ngr); 545 for (i = 0; i < ngr; i++) 546 *p++ = txdr_unsigned(cr->cr_groups[i]); 547 /* And add the AUTH_NULL */ 548 *p++ = 0; 549 *p = 0; 550 i = (((caddr_t)p)-rpc_unixauth)-12; 551 p = (u_long *)(rpc_unixauth+4); 552 *p = txdr_unsigned(i); 553 return (rpc_unixauth); 554 } 555 556 /* 557 * Attribute cache routines. 558 * nfs_loadattrcache() - loads or updates the cache contents from attributes 559 * that are on the mbuf list 560 * nfs_getattrcache() - returns valid attributes if found in cache, returns 561 * error otherwise 562 */ 563 564 /* 565 * Load the attribute cache (that lives in the nfsnode entry) with 566 * the values on the mbuf list and 567 * Iff vap not NULL 568 * copy the attributes to *vaper 569 */ 570 nfs_loadattrcache(vpp, mdp, dposp, vaper) 571 struct vnode **vpp; 572 struct mbuf **mdp; 573 caddr_t *dposp; 574 struct vattr *vaper; 575 { 576 register struct vnode *vp = *vpp; 577 register struct vattr *vap; 578 register struct nfsv2_fattr *fp; 579 extern struct vnodeops spec_nfsv2nodeops; 580 register struct nfsnode *np; 581 register long t1; 582 caddr_t dpos, cp2; 583 int error = 0; 584 struct mbuf *md; 585 enum vtype type; 586 long rdev; 587 struct timeval mtime; 588 struct vnode *nvp; 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 type = nfstov_type(fp->fa_type); 597 rdev = fxdr_unsigned(long, fp->fa_rdev); 598 fxdr_time(&fp->fa_mtime, &mtime); 599 /* 600 * If v_type == VNON it is a new node, so fill in the v_type, 601 * n_mtime fields. Check to see if it represents a special 602 * device, and if so, check for a possible alias. Once the 603 * correct vnode has been obtained, fill in the rest of the 604 * information. 605 */ 606 np = VTONFS(vp); 607 if (vp->v_type == VNON) { 608 if (type == VCHR && rdev == 0xffffffff) 609 vp->v_type = type = VFIFO; 610 else 611 vp->v_type = type; 612 if (vp->v_type == VFIFO) { 613 #ifdef FIFO 614 extern struct vnodeops fifo_nfsv2nodeops; 615 vp->v_op = &fifo_nfsv2nodeops; 616 #else 617 return (EOPNOTSUPP); 618 #endif /* FIFO */ 619 } 620 if (vp->v_type == VCHR || vp->v_type == VBLK) { 621 vp->v_op = &spec_nfsv2nodeops; 622 if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 623 /* 624 * Reinitialize aliased node. 625 */ 626 np = VTONFS(nvp); 627 np->n_vnode = nvp; 628 np->n_flag = 0; 629 nfs_lock(nvp); 630 bcopy((caddr_t)&VTONFS(vp)->n_fh, 631 (caddr_t)&np->n_fh, NFSX_FH); 632 insque(np, nfs_hash(&np->n_fh)); 633 np->n_attrstamp = 0; 634 np->n_sillyrename = (struct sillyrename *)0; 635 /* 636 * Discard unneeded vnode and update actual one 637 */ 638 vput(vp); 639 *vpp = nvp; 640 } 641 } 642 np->n_mtime = mtime.tv_sec; 643 } 644 vap = &np->n_vattr; 645 vap->va_type = type; 646 vap->va_mode = nfstov_mode(fp->fa_mode); 647 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 648 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 649 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 650 vap->va_size = fxdr_unsigned(u_long, fp->fa_size); 651 if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) 652 np->n_size = vap->va_size; 653 vap->va_size_rsv = 0; 654 vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 655 vap->va_rdev = (dev_t)rdev; 656 vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; 657 vap->va_bytes_rsv = 0; 658 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 659 vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); 660 vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); 661 vap->va_atime.tv_usec = 0; 662 vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); 663 vap->va_mtime = mtime; 664 vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); 665 vap->va_ctime.tv_usec = 0; 666 vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); 667 np->n_attrstamp = time.tv_sec; 668 *dposp = dpos; 669 *mdp = md; 670 if (vaper != NULL) { 671 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 672 if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 673 vaper->va_size = np->n_size; 674 } 675 return (0); 676 } 677 678 /* 679 * Check the time stamp 680 * If the cache is valid, copy contents to *vap and return 0 681 * otherwise return an error 682 */ 683 nfs_getattrcache(vp, vap) 684 register struct vnode *vp; 685 struct vattr *vap; 686 { 687 register struct nfsnode *np; 688 689 np = VTONFS(vp); 690 if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 691 nfsstats.attrcache_hits++; 692 bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 693 if ((np->n_flag & NMODIFIED) == 0) 694 np->n_size = vap->va_size; 695 else if (np->n_size > vap->va_size) 696 vap->va_size = np->n_size; 697 return (0); 698 } else { 699 nfsstats.attrcache_misses++; 700 return (ENOENT); 701 } 702 } 703 704 /* 705 * Set up nameidata for a namei() call and do it 706 */ 707 nfs_namei(ndp, fhp, len, mdp, dposp) 708 register struct nameidata *ndp; 709 fhandle_t *fhp; 710 int len; 711 struct mbuf **mdp; 712 caddr_t *dposp; 713 { 714 register int i, rem; 715 register struct mbuf *md; 716 register char *cp; 717 struct vnode *dp; 718 int flag; 719 int error; 720 721 if ((ndp->ni_nameiop & HASBUF) == 0) { 722 flag = ndp->ni_nameiop & OPFLAG; 723 /* 724 * Copy the name from the mbuf list to the d_name field of ndp 725 * and set the various ndp fields appropriately. 726 */ 727 cp = *dposp; 728 md = *mdp; 729 rem = mtod(md, caddr_t)+md->m_len-cp; 730 ndp->ni_hash = 0; 731 for (i = 0; i < len;) { 732 while (rem == 0) { 733 md = md->m_next; 734 if (md == NULL) 735 return (EBADRPC); 736 cp = mtod(md, caddr_t); 737 rem = md->m_len; 738 } 739 if (*cp == '\0' || *cp == '/') 740 return (EINVAL); 741 if (*cp & 0200) 742 if ((*cp&0377) == ('/'|0200) || flag != DELETE) 743 return (EINVAL); 744 ndp->ni_dent.d_name[i++] = *cp; 745 ndp->ni_hash += (unsigned char)*cp * i; 746 cp++; 747 rem--; 748 } 749 *mdp = md; 750 *dposp = cp; 751 len = nfsm_rndup(len)-len; 752 if (len > 0) { 753 if (rem < len) { 754 if (error = nfs_adv(mdp, dposp, len, rem)) 755 return (error); 756 } else 757 *dposp += len; 758 } 759 } else 760 i = len; 761 ndp->ni_namelen = i; 762 ndp->ni_dent.d_namlen = i; 763 ndp->ni_dent.d_name[i] = '\0'; 764 ndp->ni_segflg = UIO_SYSSPACE; 765 ndp->ni_pathlen = 1; 766 ndp->ni_pnbuf = ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; 767 ndp->ni_next = &ndp->ni_dent.d_name[i]; 768 ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE | HASBUF); 769 770 if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) 771 return (error); 772 if (dp->v_type != VDIR) { 773 vrele(dp); 774 return (ENOTDIR); 775 } 776 /* 777 * Must set current directory here to avoid confusion in namei() 778 * called from rename() 779 */ 780 ndp->ni_cdir = dp; 781 ndp->ni_rdir = NULLVP; 782 783 /* 784 * And call namei() to do the real work 785 */ 786 error = namei(ndp); 787 vrele(dp); 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 868 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 869 return (ESTALE); 870 if ((mp->mnt_flag & MNT_EXPORTED) == 0) 871 return (EACCES); 872 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 873 return (ESTALE); 874 if (cred->cr_uid == 0) 875 cred->cr_uid = mp->mnt_exroot; 876 if (!lockflag) 877 VOP_UNLOCK(*vpp); 878 return (0); 879 } 880