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.17 (Berkeley) 02/17/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 "strings.h" 39 #include "map.h" 40 #include "rpcv2.h" 41 #include "nfsv2.h" 42 #include "nfsnode.h" 43 #include "nfs.h" 44 #include "nfsiom.h" 45 #include "xdr_subs.h" 46 #include "nfsm_subs.h" 47 48 #define TRUE 1 49 #define FALSE 0 50 51 /* 52 * Data items converted to xdr at startup, since they are constant 53 * This is kinda hokey, but may save a little time doing byte swaps 54 */ 55 u_long nfs_procids[NFS_NPROCS]; 56 u_long nfs_xdrneg1; 57 u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 58 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 59 u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 60 /* And other global data */ 61 static u_long *rpc_uidp = (u_long *)0; 62 static u_long nfs_xid = 1; 63 static char *rpc_unixauth; 64 extern long hostid; 65 extern enum vtype v_type[NFLNK+1]; 66 extern struct proc *nfs_iodwant[MAX_ASYNCDAEMON]; 67 extern struct map nfsmap[NFS_MSIZ]; 68 69 /* Function ret types */ 70 static char *nfs_unixauth(); 71 72 /* 73 * Maximum number of groups passed through to NFS server. 74 * For release 3.X systems, the maximum value is 8. 75 * For release 4.X systems, the maximum value is 10. 76 */ 77 int numgrps = 8; 78 79 /* 80 * Create the header for an rpc request packet 81 * The function nfs_unixauth() creates a unix style authorization string 82 * and returns a ptr to it. 83 * The hsiz is the size of the rest of the nfs request header. 84 * (just used to decide if a cluster is a good idea) 85 * nb: Note that the prog, vers and procid args are already in xdr byte order 86 */ 87 struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid) 88 u_long prog; 89 u_long vers; 90 u_long procid; 91 struct ucred *cred; 92 int hsiz; 93 caddr_t *bpos; 94 struct mbuf **mb; 95 u_long *retxid; 96 { 97 register struct mbuf *mreq, *m; 98 register u_long *p; 99 struct mbuf *m1; 100 char *ap; 101 int asiz, siz; 102 103 NFSMGETHDR(mreq); 104 asiz = (((cred->cr_ngroups > numgrps) ? numgrps : cred->cr_ngroups)<<2); 105 #ifdef FILLINHOST 106 asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 107 #else 108 asiz += 9*NFSX_UNSIGNED; 109 #endif 110 111 /* If we need a lot, alloc a cluster ?? */ 112 if ((asiz+hsiz+RPC_SIZ) > MHLEN) 113 NFSMCLGET(mreq, M_WAIT); 114 mreq->m_len = NFSMSIZ(mreq); 115 siz = mreq->m_len; 116 m1 = mreq; 117 /* 118 * Alloc enough mbufs 119 * We do it now to avoid all sleeps after the call to nfs_unixauth() 120 */ 121 while ((asiz+RPC_SIZ) > siz) { 122 MGET(m, M_WAIT, MT_DATA); 123 m1->m_next = m; 124 m->m_len = MLEN; 125 siz += MLEN; 126 m1 = m; 127 } 128 p = mtod(mreq, u_long *); 129 *p++ = *retxid = txdr_unsigned(++nfs_xid); 130 *p++ = rpc_call; 131 *p++ = rpc_vers; 132 *p++ = prog; 133 *p++ = vers; 134 *p++ = procid; 135 136 /* Now we can call nfs_unixauth() and copy it in */ 137 ap = nfs_unixauth(cred); 138 m = mreq; 139 siz = m->m_len-RPC_SIZ; 140 if (asiz <= siz) { 141 bcopy(ap, (caddr_t)p, asiz); 142 m->m_len = asiz+RPC_SIZ; 143 } else { 144 bcopy(ap, (caddr_t)p, siz); 145 ap += siz; 146 asiz -= siz; 147 while (asiz > 0) { 148 siz = (asiz > MLEN) ? MLEN : asiz; 149 m = m->m_next; 150 bcopy(ap, mtod(m, caddr_t), siz); 151 m->m_len = siz; 152 asiz -= siz; 153 ap += siz; 154 } 155 } 156 157 /* Finally, return values */ 158 *mb = m; 159 *bpos = mtod(m, caddr_t)+m->m_len; 160 return (mreq); 161 } 162 163 /* 164 * copies mbuf chain to the uio scatter/gather list 165 */ 166 nfsm_mbuftouio(mrep, uiop, siz, dpos) 167 struct mbuf **mrep; 168 struct uio *uiop; 169 int siz; 170 caddr_t *dpos; 171 { 172 register int xfer, left, len; 173 register struct mbuf *mp; 174 register char *mbufcp, *uiocp; 175 long uiosiz, rem; 176 177 mp = *mrep; 178 mbufcp = *dpos; 179 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 180 rem = nfsm_rndup(siz)-siz; 181 while (siz > 0) { 182 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 183 return(EFBIG); 184 left = uiop->uio_iov->iov_len; 185 uiocp = uiop->uio_iov->iov_base; 186 if (left > siz) 187 left = siz; 188 uiosiz = left; 189 while (left > 0) { 190 while (len == 0) { 191 mp = mp->m_next; 192 if (mp == NULL) 193 return (EBADRPC); 194 mbufcp = mtod(mp, caddr_t); 195 len = mp->m_len; 196 } 197 xfer = (left > len) ? len : left; 198 #ifdef notdef 199 /* Not Yet.. */ 200 if (uiop->uio_iov->iov_op != NULL) 201 (*(uiop->uio_iov->iov_op)) 202 (mbufcp, uiocp, xfer); 203 else 204 #endif 205 if (uiop->uio_segflg == UIO_SYSSPACE) 206 bcopy(mbufcp, uiocp, xfer); 207 else 208 copyout(mbufcp, uiocp, xfer); 209 left -= xfer; 210 len -= xfer; 211 mbufcp += xfer; 212 uiocp += xfer; 213 uiop->uio_offset += xfer; 214 uiop->uio_resid -= xfer; 215 } 216 if (uiop->uio_iov->iov_len <= siz) { 217 uiop->uio_iovcnt--; 218 uiop->uio_iov++; 219 } else { 220 uiop->uio_iov->iov_base += uiosiz; 221 uiop->uio_iov->iov_len -= uiosiz; 222 } 223 siz -= uiosiz; 224 } 225 if (rem > 0) 226 mbufcp += rem; 227 *dpos = mbufcp; 228 *mrep = mp; 229 return(0); 230 } 231 232 /* 233 * copies a uio scatter/gather list to an mbuf chain... 234 */ 235 nfsm_uiotombuf(uiop, mq, siz, bpos) 236 register struct uio *uiop; 237 struct mbuf **mq; 238 int siz; 239 caddr_t *bpos; 240 { 241 register struct mbuf *mp; 242 struct mbuf *mp2; 243 long xfer, left, uiosiz; 244 int clflg; 245 int rem, len; 246 char *cp, *uiocp; 247 248 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 249 clflg = 1; 250 else 251 clflg = 0; 252 rem = nfsm_rndup(siz)-siz; 253 mp2 = *mq; 254 while (siz > 0) { 255 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 256 return(EINVAL); 257 left = uiop->uio_iov->iov_len; 258 uiocp = uiop->uio_iov->iov_base; 259 if (left > siz) 260 left = siz; 261 uiosiz = left; 262 while (left > 0) { 263 MGET(mp, M_WAIT, MT_DATA); 264 if (clflg) 265 NFSMCLGET(mp, M_WAIT); 266 mp->m_len = NFSMSIZ(mp); 267 mp2->m_next = mp; 268 mp2 = mp; 269 xfer = (left > mp->m_len) ? mp->m_len : left; 270 #ifdef notdef 271 /* Not Yet.. */ 272 if (uiop->uio_iov->iov_op != NULL) 273 (*(uiop->uio_iov->iov_op)) 274 (uiocp, mtod(mp, caddr_t), xfer); 275 else 276 #endif 277 if (uiop->uio_segflg == UIO_SYSSPACE) 278 bcopy(uiocp, mtod(mp, caddr_t), xfer); 279 else 280 copyin(uiocp, mtod(mp, caddr_t), xfer); 281 len = mp->m_len; 282 mp->m_len = xfer; 283 left -= xfer; 284 uiocp += xfer; 285 uiop->uio_offset += xfer; 286 uiop->uio_resid -= xfer; 287 } 288 if (uiop->uio_iov->iov_len <= siz) { 289 uiop->uio_iovcnt--; 290 uiop->uio_iov++; 291 } else { 292 uiop->uio_iov->iov_base += uiosiz; 293 uiop->uio_iov->iov_len -= uiosiz; 294 } 295 siz -= uiosiz; 296 } 297 if (rem > 0) { 298 if (rem > (len-mp->m_len)) { 299 MGET(mp, M_WAIT, MT_DATA); 300 mp->m_len = 0; 301 mp2->m_next = mp; 302 } 303 cp = mtod(mp, caddr_t)+mp->m_len; 304 for (left = 0; left < rem; left++) 305 *cp++ = '\0'; 306 mp->m_len += rem; 307 *bpos = cp; 308 } else 309 *bpos = mtod(mp, caddr_t)+mp->m_len; 310 *mq = mp; 311 return(0); 312 } 313 314 /* 315 * Help break down an mbuf chain by setting the first siz bytes contiguous 316 * pointed to by returned val. 317 * If Updateflg == True we can overwrite the first part of the mbuf data 318 * This is used by the macros nfsm_disect and nfsm_disecton for tough 319 * cases. (The macros use the vars. dpos and dpos2) 320 */ 321 nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 322 struct mbuf **mdp; 323 caddr_t *dposp; 324 int siz; 325 int left; 326 int updateflg; 327 caddr_t *cp2; 328 { 329 register struct mbuf *mp, *mp2; 330 register int siz2, xfer; 331 register caddr_t p; 332 333 mp = *mdp; 334 while (left == 0) { 335 *mdp = mp = mp->m_next; 336 if (mp == NULL) 337 return(EBADRPC); 338 left = mp->m_len; 339 *dposp = mtod(mp, caddr_t); 340 } 341 if (left >= siz) { 342 *cp2 = *dposp; 343 *dposp += siz; 344 return(0); 345 } else if (mp->m_next == NULL) { 346 return(EBADRPC); 347 } else if (siz > MCLBYTES) { 348 panic("nfs S too big"); 349 } else { 350 /* Iff update, you can overwrite, else must alloc new mbuf */ 351 if (updateflg) { 352 NFSMINOFF(mp); 353 } else { 354 MGET(mp2, M_WAIT, MT_DATA); 355 mp2->m_next = mp->m_next; 356 mp->m_next = mp2; 357 mp->m_len -= left; 358 mp = mp2; 359 } 360 /* Alloc cluster iff we need it */ 361 if (!M_HASCL(mp) && siz > NFSMSIZ(mp)) { 362 NFSMCLGET(mp, M_WAIT); 363 if (!M_HASCL(mp)) 364 return(ENOBUFS); 365 } 366 *cp2 = p = mtod(mp, caddr_t); 367 bcopy(*dposp, p, left); /* Copy what was left */ 368 siz2 = siz-left; 369 p += left; 370 mp2 = mp->m_next; 371 /* Loop arround copying up the siz2 bytes */ 372 while (siz2 > 0) { 373 if (mp2 == NULL) 374 return (EBADRPC); 375 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 376 bcopy(mtod(mp2, caddr_t), p, xfer); 377 NFSMADV(mp2, xfer); 378 mp2->m_len -= xfer; 379 siz2 -= xfer; 380 if (siz2 > 0) 381 mp2 = mp2->m_next; 382 } 383 mp->m_len = siz; 384 *mdp = mp2; 385 *dposp = mtod(mp2, caddr_t); 386 } 387 return (0); 388 } 389 390 /* 391 * Advance the position in the mbuf chain with/without freeing mbufs 392 */ 393 nfs_adv(mdp, dposp, offs, left) 394 struct mbuf **mdp; 395 caddr_t *dposp; 396 int offs; 397 int left; 398 { 399 register struct mbuf *m; 400 register int s; 401 402 m = *mdp; 403 s = left; 404 while (s < offs) { 405 offs -= s; 406 m = m->m_next; 407 if (m == NULL) 408 return(EBADRPC); 409 s = m->m_len; 410 } 411 *mdp = m; 412 *dposp = mtod(m, caddr_t)+offs; 413 return(0); 414 } 415 416 /* 417 * Copy a string into mbufs for the hard cases... 418 */ 419 nfsm_strtmbuf(mb, bpos, cp, siz) 420 struct mbuf **mb; 421 char **bpos; 422 char *cp; 423 long siz; 424 { 425 register struct mbuf *m1, *m2; 426 long left, xfer, len, tlen; 427 u_long *p; 428 int putsize; 429 430 putsize = 1; 431 m2 = *mb; 432 left = NFSMSIZ(m2)-m2->m_len; 433 if (left > 0) { 434 p = ((u_long *)(*bpos)); 435 *p++ = txdr_unsigned(siz); 436 putsize = 0; 437 left -= NFSX_UNSIGNED; 438 m2->m_len += NFSX_UNSIGNED; 439 if (left > 0) { 440 bcopy(cp, (caddr_t) p, left); 441 siz -= left; 442 cp += left; 443 m2->m_len += left; 444 left = 0; 445 } 446 } 447 /* Loop arround adding mbufs */ 448 while (siz > 0) { 449 MGET(m1, M_WAIT, MT_DATA); 450 if (siz > MLEN) 451 NFSMCLGET(m1, M_WAIT); 452 m1->m_len = NFSMSIZ(m1); 453 m2->m_next = m1; 454 m2 = m1; 455 p = mtod(m1, u_long *); 456 tlen = 0; 457 if (putsize) { 458 *p++ = txdr_unsigned(siz); 459 m1->m_len -= NFSX_UNSIGNED; 460 tlen = NFSX_UNSIGNED; 461 putsize = 0; 462 } 463 if (siz < m1->m_len) { 464 len = nfsm_rndup(siz); 465 xfer = siz; 466 if (xfer < len) 467 *(p+(xfer>>2)) = 0; 468 } else { 469 xfer = len = m1->m_len; 470 } 471 bcopy(cp, (caddr_t) p, xfer); 472 m1->m_len = len+tlen; 473 siz -= xfer; 474 cp += xfer; 475 } 476 *mb = m1; 477 *bpos = mtod(m1, caddr_t)+m1->m_len; 478 return(0); 479 } 480 481 /* 482 * Called once to initialize data structures... 483 */ 484 nfs_init() 485 { 486 register int i; 487 488 rpc_vers = txdr_unsigned(RPC_VER2); 489 rpc_call = txdr_unsigned(RPC_CALL); 490 rpc_reply = txdr_unsigned(RPC_REPLY); 491 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 492 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 493 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 494 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 495 nfs_vers = txdr_unsigned(NFS_VER2); 496 nfs_prog = txdr_unsigned(NFS_PROG); 497 nfs_true = txdr_unsigned(TRUE); 498 nfs_false = txdr_unsigned(FALSE); 499 /* Loop thru nfs procids */ 500 for (i = 0; i < NFS_NPROCS; i++) 501 nfs_procids[i] = txdr_unsigned(i); 502 /* Ensure async daemons disabled */ 503 for (i = 0; i < MAX_ASYNCDAEMON; i++) 504 nfs_iodwant[i] = (struct proc *)0; 505 v_type[0] = VNON; 506 v_type[1] = VREG; 507 v_type[2] = VDIR; 508 v_type[3] = VBLK; 509 v_type[4] = VCHR; 510 v_type[5] = VLNK; 511 nfs_xdrneg1 = txdr_unsigned(-1); 512 nfs_nhinit(); /* Init the nfsnode table */ 513 nfsrv_initcache(); /* Init the server request cache */ 514 rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); 515 /* And start timer */ 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 dev_t 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(dev_t, 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 vp->v_type = type; 620 if (vp->v_type == VCHR || vp->v_type == VBLK) { 621 vp->v_op = &spec_nfsv2nodeops; 622 if (nvp = checkalias(vp, 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_size1 = 0; /* OR -1 ?? */ 654 vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 655 vap->va_rdev = rdev; 656 vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * vap->va_blocksize; 657 vap->va_bytes1 = 0; 658 vap->va_fsid = vp->v_mount->m_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 * nfs_namei - a liitle like namei(), but for one element only 706 * essentially look up file handle, fill in ndp and call VOP_LOOKUP() 707 */ 708 nfs_namei(ndp, fhp, len, mdp, dposp) 709 register struct nameidata *ndp; 710 fhandle_t *fhp; 711 int len; 712 struct mbuf **mdp; 713 caddr_t *dposp; 714 { 715 register int i, rem; 716 register struct mbuf *md; 717 register char *cp; 718 struct vnode *dp = (struct vnode *)0; 719 int flag; 720 int docache; 721 int wantparent; 722 int lockparent; 723 int error = 0; 724 725 ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 726 flag = ndp->ni_nameiop & OPFLAG; 727 wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT); 728 lockparent = ndp->ni_nameiop & LOCKPARENT; 729 docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; 730 if (flag == DELETE || wantparent) 731 docache = 0; 732 733 /* Fill in the nameidata and call lookup */ 734 cp = *dposp; 735 md = *mdp; 736 rem = mtod(md, caddr_t)+md->m_len-cp; 737 ndp->ni_hash = 0; 738 for (i = 0; i < len;) { 739 if (rem == 0) { 740 md = md->m_next; 741 if (md == NULL) 742 return (EBADRPC); 743 cp = mtod(md, caddr_t); 744 rem = md->m_len; 745 } 746 if (*cp == '\0' || *cp == '/') 747 return (EINVAL); 748 if (*cp & 0200) 749 if ((*cp&0377) == ('/'|0200) || flag != DELETE) 750 return (EINVAL); 751 ndp->ni_dent.d_name[i++] = *cp; 752 ndp->ni_hash += (unsigned char)*cp * i; 753 cp++; 754 rem--; 755 } 756 *mdp = md; 757 len = nfsm_rndup(len)-len; 758 if (len > 0) 759 *dposp = cp+len; 760 else 761 *dposp = cp; 762 ndp->ni_namelen = i; 763 ndp->ni_dent.d_namlen = i; 764 ndp->ni_dent.d_name[i] = '\0'; 765 ndp->ni_pathlen = 1; 766 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_loopcnt = 0; /* Not actually used for now */ 769 ndp->ni_endoff = 0; 770 if (docache) 771 ndp->ni_makeentry = 1; 772 else 773 ndp->ni_makeentry = 0; 774 ndp->ni_isdotdot = (i == 2 && 775 ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.'); 776 777 if (error = nfsrv_fhtovp(fhp, TRUE, &dp, ndp->ni_cred)) 778 return (error); 779 if (dp->v_type != VDIR) { 780 vput(dp); 781 return (ENOTDIR); 782 } 783 /* 784 * Must set current directory here to avoid confusion in namei() 785 * called from rename() 786 */ 787 ndp->ni_cdir = dp; 788 ndp->ni_rdir = (struct vnode *)0; 789 790 /* 791 * Handle "..": 792 * If this vnode is the root of the mounted 793 * file system, then ignore it so can't get out 794 */ 795 if (ndp->ni_isdotdot && (dp->v_flag & VROOT)) { 796 ndp->ni_dvp = dp; 797 ndp->ni_vp = dp; 798 VREF(dp); 799 goto nextname; 800 } 801 802 /* 803 * We now have a segment name to search for, and a directory to search. 804 */ 805 if (error = VOP_LOOKUP(dp, ndp)) { 806 if (ndp->ni_vp != NULL) 807 panic("leaf should be empty"); 808 /* 809 * If creating and at end of pathname, then can consider 810 * allowing file to be created. 811 */ 812 if (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) 813 error = EROFS; 814 if (flag == LOOKUP || flag == DELETE || error != ENOENT) 815 goto bad; 816 /* 817 * We return with ni_vp NULL to indicate that the entry 818 * doesn't currently exist, leaving a pointer to the 819 * (possibly locked) directory inode in ndp->ni_dvp. 820 */ 821 return (0); /* should this be ENOENT? */ 822 } 823 824 dp = ndp->ni_vp; 825 826 nextname: 827 ndp->ni_ptr = ndp->ni_next; 828 /* 829 * Check for read-only file systems 830 */ 831 if (flag == DELETE || flag == RENAME) { 832 /* 833 * Disallow directory write attempts on read-only 834 * file systems. 835 */ 836 if ((dp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)) || 837 (wantparent && (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)))) { 838 error = EROFS; 839 goto bad2; 840 } 841 } 842 843 if (!wantparent) 844 vrele(ndp->ni_dvp); 845 846 if ((ndp->ni_nameiop & LOCKLEAF) == 0) 847 VOP_UNLOCK(dp); 848 return (0); 849 850 bad2: 851 if (lockparent) 852 VOP_UNLOCK(ndp->ni_dvp); 853 vrele(ndp->ni_dvp); 854 bad: 855 vput(dp); 856 ndp->ni_vp = NULL; 857 return (error); 858 } 859 860 /* 861 * A fiddled version of m_adj() that ensures null fill to a long 862 * boundary and only trims off the back end 863 */ 864 nfsm_adj(mp, len, nul) 865 struct mbuf *mp; 866 register int len; 867 int nul; 868 { 869 register struct mbuf *m; 870 register int count, i; 871 register char *cp; 872 873 /* 874 * Trim from tail. Scan the mbuf chain, 875 * calculating its length and finding the last mbuf. 876 * If the adjustment only affects this mbuf, then just 877 * adjust and return. Otherwise, rescan and truncate 878 * after the remaining size. 879 */ 880 count = 0; 881 m = mp; 882 for (;;) { 883 count += m->m_len; 884 if (m->m_next == (struct mbuf *)0) 885 break; 886 m = m->m_next; 887 } 888 if (m->m_len > len) { 889 m->m_len -= len; 890 if (nul > 0) { 891 cp = mtod(m, caddr_t)+m->m_len-nul; 892 for (i = 0; i < nul; i++) 893 *cp++ = '\0'; 894 } 895 return; 896 } 897 count -= len; 898 if (count < 0) 899 count = 0; 900 /* 901 * Correct length for chain is "count". 902 * Find the mbuf with last data, adjust its length, 903 * and toss data from remaining mbufs on chain. 904 */ 905 for (m = mp; m; m = m->m_next) { 906 if (m->m_len >= count) { 907 m->m_len = count; 908 if (nul > 0) { 909 cp = mtod(m, caddr_t)+m->m_len-nul; 910 for (i = 0; i < nul; i++) 911 *cp++ = '\0'; 912 } 913 break; 914 } 915 count -= m->m_len; 916 } 917 while (m = m->m_next) 918 m->m_len = 0; 919 } 920 921 /* 922 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 923 * - look up fsid in mount list (if not found ret error) 924 * - check that it is exported 925 * - get vp by calling VFS_FHTOVP() macro 926 * - if not lockflag unlock it with VOP_UNLOCK() 927 * - if cred->cr_uid == 0 set it to m_exroot 928 */ 929 nfsrv_fhtovp(fhp, lockflag, vpp, cred) 930 fhandle_t *fhp; 931 int lockflag; 932 struct vnode **vpp; 933 struct ucred *cred; 934 { 935 register struct mount *mp; 936 937 if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 938 return (ESTALE); 939 if ((mp->m_flag & M_EXPORTED) == 0) 940 return (EACCES); 941 if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 942 return (ESTALE); 943 if (cred->cr_uid == 0) 944 cred->cr_uid = mp->m_exroot; 945 if (!lockflag) 946 VOP_UNLOCK(*vpp); 947 return (0); 948 } 949