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