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