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.25 (Berkeley) 05/18/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 struct uio *uiop; 170 int siz; 171 caddr_t *dpos; 172 { 173 register int xfer, left, len; 174 register struct mbuf *mp; 175 register char *mbufcp, *uiocp; 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 struct mbuf *mp; 248 struct mbuf *mp2; 249 long xfer, left, uiosiz; 250 int clflg; 251 int rem, len; 252 char *cp, *uiocp; 253 254 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 255 clflg = 1; 256 else 257 clflg = 0; 258 rem = nfsm_rndup(siz)-siz; 259 mp2 = *mq; 260 while (siz > 0) { 261 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 262 return (EINVAL); 263 left = uiop->uio_iov->iov_len; 264 uiocp = uiop->uio_iov->iov_base; 265 if (left > siz) 266 left = siz; 267 uiosiz = left; 268 while (left > 0) { 269 MGET(mp, M_WAIT, MT_DATA); 270 if (clflg) 271 MCLGET(mp, M_WAIT); 272 mp->m_len = NFSMSIZ(mp); 273 mp2->m_next = mp; 274 mp2 = mp; 275 xfer = (left > mp->m_len) ? mp->m_len : left; 276 #ifdef notdef 277 /* Not Yet.. */ 278 if (uiop->uio_iov->iov_op != NULL) 279 (*(uiop->uio_iov->iov_op)) 280 (uiocp, mtod(mp, caddr_t), xfer); 281 else 282 #endif 283 if (uiop->uio_segflg == UIO_SYSSPACE) 284 bcopy(uiocp, mtod(mp, caddr_t), xfer); 285 else 286 copyin(uiocp, mtod(mp, caddr_t), xfer); 287 len = mp->m_len; 288 mp->m_len = xfer; 289 left -= xfer; 290 uiocp += xfer; 291 uiop->uio_offset += xfer; 292 uiop->uio_resid -= xfer; 293 } 294 if (uiop->uio_iov->iov_len <= siz) { 295 uiop->uio_iovcnt--; 296 uiop->uio_iov++; 297 } else { 298 uiop->uio_iov->iov_base += uiosiz; 299 uiop->uio_iov->iov_len -= uiosiz; 300 } 301 siz -= uiosiz; 302 } 303 if (rem > 0) { 304 if (rem > (len-mp->m_len)) { 305 MGET(mp, M_WAIT, MT_DATA); 306 mp->m_len = 0; 307 mp2->m_next = mp; 308 } 309 cp = mtod(mp, caddr_t)+mp->m_len; 310 for (left = 0; left < rem; left++) 311 *cp++ = '\0'; 312 mp->m_len += rem; 313 *bpos = cp; 314 } else 315 *bpos = mtod(mp, caddr_t)+mp->m_len; 316 *mq = mp; 317 return (0); 318 } 319 320 /* 321 * Help break down an mbuf chain by setting the first siz bytes contiguous 322 * pointed to by returned val. 323 * If Updateflg == True we can overwrite the first part of the mbuf data 324 * This is used by the macros nfsm_disect and nfsm_disecton for tough 325 * cases. (The macros use the vars. dpos and dpos2) 326 */ 327 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 328 struct mbuf **mdp; 329 caddr_t *dposp; 330 int siz; 331 int left; 332 int updateflg; 333 caddr_t *cp2; 334 { 335 register struct mbuf *mp, *mp2; 336 register int siz2, xfer; 337 register caddr_t p; 338 339 mp = *mdp; 340 while (left == 0) { 341 *mdp = mp = mp->m_next; 342 if (mp == NULL) 343 return (EBADRPC); 344 left = mp->m_len; 345 *dposp = mtod(mp, caddr_t); 346 } 347 if (left >= siz) { 348 *cp2 = *dposp; 349 *dposp += siz; 350 } else if (mp->m_next == NULL) { 351 return (EBADRPC); 352 } else if (siz > MHLEN) { 353 panic("nfs S too big"); 354 } else { 355 /* Iff update, you can overwrite, else must alloc new mbuf */ 356 if (updateflg) { 357 NFSMINOFF(mp); 358 } else { 359 MGET(mp2, M_WAIT, MT_DATA); 360 mp2->m_next = mp->m_next; 361 mp->m_next = mp2; 362 mp->m_len -= left; 363 mp = mp2; 364 } 365 *cp2 = p = mtod(mp, caddr_t); 366 bcopy(*dposp, p, left); /* Copy what was left */ 367 siz2 = siz-left; 368 p += left; 369 mp2 = mp->m_next; 370 /* Loop around copying up the siz2 bytes */ 371 while (siz2 > 0) { 372 if (mp2 == NULL) 373 return (EBADRPC); 374 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 375 if (xfer > 0) { 376 bcopy(mtod(mp2, caddr_t), p, xfer); 377 NFSMADV(mp2, xfer); 378 mp2->m_len -= xfer; 379 p += xfer; 380 siz2 -= xfer; 381 } 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 } 389 return (0); 390 } 391 392 /* 393 * Advance the position in the mbuf chain. 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 MCLGET(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 nfs_init() 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 /* Ensure async daemons disabled */ 505 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 506 nfs_iodwant[i] = (struct proc *)0; 507 nfs_xdrneg1 = txdr_unsigned(-1); 508 nfs_nhinit(); /* Init the nfsnode table */ 509 nfsrv_initcache(); /* Init the server request cache */ 510 rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); 511 512 /* 513 * Initialize reply list and start timer 514 */ 515 nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 516 nfs_timer(); 517 } 518 519 /* 520 * Fill in the rest of the rpc_unixauth and return it 521 */ 522 static char *nfs_unixauth(cr) 523 register struct ucred *cr; 524 { 525 register u_long *p; 526 register int i; 527 int ngr; 528 529 /* Maybe someday there should be a cache of AUTH_SHORT's */ 530 if ((p = rpc_uidp) == NULL) { 531 #ifdef FILLINHOST 532 i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED); 533 #else 534 i = 19*NFSX_UNSIGNED; 535 #endif 536 MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); 537 bzero((caddr_t)p, i); 538 rpc_unixauth = (caddr_t)p; 539 *p++ = txdr_unsigned(RPCAUTH_UNIX); 540 p++; /* Fill in size later */ 541 *p++ = hostid; 542 #ifdef FILLINHOST 543 *p++ = txdr_unsigned(hostnamelen); 544 i = nfsm_rndup(hostnamelen); 545 bcopy(hostname, (caddr_t)p, hostnamelen); 546 p += (i>>2); 547 #else 548 *p++ = 0; 549 #endif 550 rpc_uidp = p; 551 } 552 *p++ = txdr_unsigned(cr->cr_uid); 553 *p++ = txdr_unsigned(cr->cr_groups[0]); 554 ngr = (cr->cr_ngroups > numgrps) ? numgrps : cr->cr_ngroups; 555 *p++ = txdr_unsigned(ngr); 556 for (i = 0; i < ngr; i++) 557 *p++ = txdr_unsigned(cr->cr_groups[i]); 558 /* And add the AUTH_NULL */ 559 *p++ = 0; 560 *p = 0; 561 i = (((caddr_t)p)-rpc_unixauth)-12; 562 p = (u_long *)(rpc_unixauth+4); 563 *p = txdr_unsigned(i); 564 return (rpc_unixauth); 565 } 566 567 /* 568 * Attribute cache routines. 569 * nfs_loadattrcache() - loads or updates the cache contents from attributes 570 * that are on the mbuf list 571 * nfs_getattrcache() - returns valid attributes if found in cache, returns 572 * error otherwise 573 */ 574 575 /* 576 * Load the attribute cache (that lives in the nfsnode entry) with 577 * the values on the mbuf list and 578 * Iff vap not NULL 579 * copy the attributes to *vaper 580 */ 581 nfs_loadattrcache(vpp, mdp, dposp, vaper) 582 struct vnode **vpp; 583 struct mbuf **mdp; 584 caddr_t *dposp; 585 struct vattr *vaper; 586 { 587 register struct vnode *vp = *vpp; 588 register struct vattr *vap; 589 register struct nfsv2_fattr *fp; 590 extern struct vnodeops spec_nfsv2nodeops; 591 register struct nfsnode *np; 592 register long t1; 593 caddr_t dpos, cp2; 594 int error = 0; 595 struct mbuf *md; 596 enum vtype type; 597 long rdev; 598 struct timeval mtime; 599 struct vnode *nvp; 600 601 md = *mdp; 602 dpos = *dposp; 603 t1 = (mtod(md, caddr_t)+md->m_len)-dpos; 604 if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 605 return (error); 606 fp = (struct nfsv2_fattr *)cp2; 607 type = nfstov_type(fp->fa_type); 608 rdev = fxdr_unsigned(long, fp->fa_rdev); 609 fxdr_time(&fp->fa_mtime, &mtime); 610 /* 611 * If v_type == VNON it is a new node, so fill in the v_type, 612 * n_mtime fields. Check to see if it represents a special 613 * device, and if so, check for a possible alias. Once the 614 * correct vnode has been obtained, fill in the rest of the 615 * information. 616 */ 617 np = VTONFS(vp); 618 if (vp->v_type == VNON) { 619 if (type == VCHR && rdev == 0xffffffff) 620 vp->v_type = type = VFIFO; 621 else 622 vp->v_type = type; 623 if (vp->v_type == VFIFO) { 624 #ifdef FIFO 625 extern struct vnodeops fifo_nfsv2nodeops; 626 vp->v_op = &fifo_nfsv2nodeops; 627 #else 628 return (EOPNOTSUPP); 629 #endif /* FIFO */ 630 } 631 if (vp->v_type == VCHR || vp->v_type == VBLK) { 632 vp->v_op = &spec_nfsv2nodeops; 633 if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 634 /* 635 * Reinitialize aliased node. 636 */ 637 np = VTONFS(nvp); 638 np->n_vnode = nvp; 639 np->n_flag = 0; 640 nfs_lock(nvp); 641 bcopy((caddr_t)&VTONFS(vp)->n_fh, 642 (caddr_t)&np->n_fh, NFSX_FH); 643 insque(np, nfs_hash(&np->n_fh)); 644 np->n_attrstamp = 0; 645 np->n_sillyrename = (struct sillyrename *)0; 646 /* 647 * Discard unneeded vnode and update actual one 648 */ 649 vput(vp); 650 *vpp = nvp; 651 } 652 } 653 np->n_mtime = mtime.tv_sec; 654 } 655 vap = &np->n_vattr; 656 vap->va_type = type; 657 vap->va_mode = nfstov_mode(fp->fa_mode); 658 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 659 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 660 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 661 vap->va_size = fxdr_unsigned(u_long, fp->fa_size); 662 if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) 663 np->n_size = vap->va_size; 664 vap->va_size_rsv = 0; 665 vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 666 vap->va_rdev = (dev_t)rdev; 667 vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE; 668 vap->va_bytes_rsv = 0; 669 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0] | 0x8000; 670 vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); 671 vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec); 672 vap->va_atime.tv_usec = 0; 673 vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec); 674 vap->va_mtime = mtime; 675 vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec); 676 vap->va_ctime.tv_usec = 0; 677 vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec); 678 np->n_attrstamp = time.tv_sec; 679 *dposp = dpos; 680 *mdp = md; 681 if (vaper != NULL) { 682 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 683 if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 684 vaper->va_size = np->n_size; 685 } 686 return (0); 687 } 688 689 /* 690 * Check the time stamp 691 * If the cache is valid, copy contents to *vap and return 0 692 * otherwise return an error 693 */ 694 nfs_getattrcache(vp, vap) 695 register struct vnode *vp; 696 struct vattr *vap; 697 { 698 register struct nfsnode *np; 699 700 np = VTONFS(vp); 701 if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 702 nfsstats.attrcache_hits++; 703 bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 704 if ((np->n_flag & NMODIFIED) == 0) 705 np->n_size = vap->va_size; 706 else if (np->n_size > vap->va_size) 707 vap->va_size = np->n_size; 708 return (0); 709 } else { 710 nfsstats.attrcache_misses++; 711 return (ENOENT); 712 } 713 } 714 715 /* 716 * Set up nameidata for a namei() call and do it 717 */ 718 nfs_namei(ndp, fhp, len, mdp, dposp) 719 register struct nameidata *ndp; 720 fhandle_t *fhp; 721 int len; 722 struct mbuf **mdp; 723 caddr_t *dposp; 724 { 725 register int i, rem; 726 register struct mbuf *md; 727 register char *cp; 728 struct vnode *dp; 729 int flag; 730 int error; 731 732 if ((ndp->ni_nameiop & HASBUF) == 0) { 733 flag = ndp->ni_nameiop & OPFLAG; 734 /* 735 * Copy the name from the mbuf list to the d_name field of ndp 736 * and set the various ndp fields appropriately. 737 */ 738 cp = *dposp; 739 md = *mdp; 740 rem = mtod(md, caddr_t)+md->m_len-cp; 741 ndp->ni_hash = 0; 742 for (i = 0; i < len;) { 743 while (rem == 0) { 744 md = md->m_next; 745 if (md == NULL) 746 return (EBADRPC); 747 cp = mtod(md, caddr_t); 748 rem = md->m_len; 749 } 750 if (*cp == '\0' || *cp == '/') 751 return (EINVAL); 752 if (*cp & 0200) 753 if ((*cp&0377) == ('/'|0200) || flag != DELETE) 754 return (EINVAL); 755 ndp->ni_dent.d_name[i++] = *cp; 756 ndp->ni_hash += (unsigned char)*cp * i; 757 cp++; 758 rem--; 759 } 760 *mdp = md; 761 *dposp = cp; 762 len = nfsm_rndup(len)-len; 763 if (len > 0) { 764 if (rem < len) { 765 if (error = nfs_adv(mdp, dposp, len, rem)) 766 return (error); 767 } else 768 *dposp += len; 769 } 770 } else 771 i = len; 772 ndp->ni_namelen = i; 773 ndp->ni_dent.d_namlen = i; 774 ndp->ni_dent.d_name[i] = '\0'; 775 ndp->ni_segflg = UIO_SYSSPACE; 776 ndp->ni_pathlen = 1; 777 ndp->ni_pnbuf = ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; 778 ndp->ni_next = &ndp->ni_dent.d_name[i]; 779 ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE | HASBUF); 780 781 if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred)) 782 return (error); 783 if (dp->v_type != VDIR) { 784 vrele(dp); 785 return (ENOTDIR); 786 } 787 /* 788 * Must set current directory here to avoid confusion in namei() 789 * called from rename() 790 */ 791 ndp->ni_cdir = dp; 792 ndp->ni_rdir = NULLVP; 793 794 /* 795 * And call namei() to do the real work 796 */ 797 error = namei(ndp); 798 vrele(dp); 799 return (error); 800 } 801 802 /* 803 * A fiddled version of m_adj() that ensures null fill to a long 804 * boundary and only trims off the back end 805 */ 806 nfsm_adj(mp, len, nul) 807 struct mbuf *mp; 808 register int len; 809 int nul; 810 { 811 register struct mbuf *m; 812 register int count, i; 813 register char *cp; 814 815 /* 816 * Trim from tail. Scan the mbuf chain, 817 * calculating its length and finding the last mbuf. 818 * If the adjustment only affects this mbuf, then just 819 * adjust and return. Otherwise, rescan and truncate 820 * after the remaining size. 821 */ 822 count = 0; 823 m = mp; 824 for (;;) { 825 count += m->m_len; 826 if (m->m_next == (struct mbuf *)0) 827 break; 828 m = m->m_next; 829 } 830 if (m->m_len > len) { 831 m->m_len -= len; 832 if (nul > 0) { 833 cp = mtod(m, caddr_t)+m->m_len-nul; 834 for (i = 0; i < nul; i++) 835 *cp++ = '\0'; 836 } 837 return; 838 } 839 count -= len; 840 if (count < 0) 841 count = 0; 842 /* 843 * Correct length for chain is "count". 844 * Find the mbuf with last data, adjust its length, 845 * and toss data from remaining mbufs on chain. 846 */ 847 for (m = mp; m; m = m->m_next) { 848 if (m->m_len >= count) { 849 m->m_len = count; 850 if (nul > 0) { 851 cp = mtod(m, caddr_t)+m->m_len-nul; 852 for (i = 0; i < nul; i++) 853 *cp++ = '\0'; 854 } 855 break; 856 } 857 count -= m->m_len; 858 } 859 while (m = m->m_next) 860 m->m_len = 0; 861 } 862 863 /* 864 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 865 * - look up fsid in mount list (if not found ret error) 866 * - check that it is exported 867 * - get vp by calling VFS_FHTOVP() macro 868 * - if not lockflag unlock it with VOP_UNLOCK() 869 * - if cred->cr_uid == 0 set it to m_exroot 870 */ 871 nfsrv_fhtovp(fhp, lockflag, vpp, cred) 872 fhandle_t *fhp; 873 int lockflag; 874 struct vnode **vpp; 875 struct ucred *cred; 876 { 877 register struct mount *mp; 878 879 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 880 return (ESTALE); 881 if ((mp->mnt_flag & MNT_EXPORTED) == 0) 882 return (EACCES); 883 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 884 return (ESTALE); 885 if (cred->cr_uid == 0) 886 cred->cr_uid = mp->mnt_exroot; 887 if (!lockflag) 888 VOP_UNLOCK(*vpp); 889 return (0); 890 } 891