1 /* $NetBSD: nfs_subs.c,v 1.41 1997/03/27 20:40:09 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 39 */ 40 41 42 /* 43 * These functions support the macros and help fiddle mbuf chains for 44 * the nfs op functions. They do things like create the rpc header and 45 * copy data between mbuf chains and uio lists. 46 */ 47 #include <sys/param.h> 48 #include <sys/proc.h> 49 #include <sys/systm.h> 50 #include <sys/kernel.h> 51 #include <sys/mount.h> 52 #include <sys/vnode.h> 53 #include <sys/namei.h> 54 #include <sys/mbuf.h> 55 #include <sys/socket.h> 56 #include <sys/stat.h> 57 #include <sys/malloc.h> 58 #include <sys/time.h> 59 60 #include <vm/vm.h> 61 62 #include <nfs/rpcv2.h> 63 #include <nfs/nfsproto.h> 64 #include <nfs/nfsnode.h> 65 #include <nfs/nfs.h> 66 #include <nfs/xdr_subs.h> 67 #include <nfs/nfsm_subs.h> 68 #include <nfs/nfsmount.h> 69 #include <nfs/nqnfs.h> 70 #include <nfs/nfsrtt.h> 71 #include <nfs/nfs_var.h> 72 73 #include <miscfs/specfs/specdev.h> 74 75 #include <vm/vm.h> 76 77 #include <netinet/in.h> 78 #ifdef ISO 79 #include <netiso/iso.h> 80 #endif 81 82 /* 83 * Data items converted to xdr at startup, since they are constant 84 * This is kinda hokey, but may save a little time doing byte swaps 85 */ 86 u_int32_t nfs_xdrneg1; 87 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 88 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, 89 rpc_auth_kerb; 90 u_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false; 91 92 /* And other global data */ 93 static u_int32_t nfs_xid = 0; 94 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 95 NFCHR, NFNON }; 96 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, 97 NFFIFO, NFNON }; 98 enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 99 enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 100 int nfs_ticks; 101 102 /* NFS client/server stats. */ 103 struct nfsstats nfsstats; 104 105 /* 106 * Mapping of old NFS Version 2 RPC numbers to generic numbers. 107 */ 108 int nfsv3_procid[NFS_NPROCS] = { 109 NFSPROC_NULL, 110 NFSPROC_GETATTR, 111 NFSPROC_SETATTR, 112 NFSPROC_NOOP, 113 NFSPROC_LOOKUP, 114 NFSPROC_READLINK, 115 NFSPROC_READ, 116 NFSPROC_NOOP, 117 NFSPROC_WRITE, 118 NFSPROC_CREATE, 119 NFSPROC_REMOVE, 120 NFSPROC_RENAME, 121 NFSPROC_LINK, 122 NFSPROC_SYMLINK, 123 NFSPROC_MKDIR, 124 NFSPROC_RMDIR, 125 NFSPROC_READDIR, 126 NFSPROC_FSSTAT, 127 NFSPROC_NOOP, 128 NFSPROC_NOOP, 129 NFSPROC_NOOP, 130 NFSPROC_NOOP, 131 NFSPROC_NOOP, 132 NFSPROC_NOOP, 133 NFSPROC_NOOP, 134 NFSPROC_NOOP 135 }; 136 137 /* 138 * and the reverse mapping from generic to Version 2 procedure numbers 139 */ 140 int nfsv2_procid[NFS_NPROCS] = { 141 NFSV2PROC_NULL, 142 NFSV2PROC_GETATTR, 143 NFSV2PROC_SETATTR, 144 NFSV2PROC_LOOKUP, 145 NFSV2PROC_NOOP, 146 NFSV2PROC_READLINK, 147 NFSV2PROC_READ, 148 NFSV2PROC_WRITE, 149 NFSV2PROC_CREATE, 150 NFSV2PROC_MKDIR, 151 NFSV2PROC_SYMLINK, 152 NFSV2PROC_CREATE, 153 NFSV2PROC_REMOVE, 154 NFSV2PROC_RMDIR, 155 NFSV2PROC_RENAME, 156 NFSV2PROC_LINK, 157 NFSV2PROC_READDIR, 158 NFSV2PROC_NOOP, 159 NFSV2PROC_STATFS, 160 NFSV2PROC_NOOP, 161 NFSV2PROC_NOOP, 162 NFSV2PROC_NOOP, 163 NFSV2PROC_NOOP, 164 NFSV2PROC_NOOP, 165 NFSV2PROC_NOOP, 166 NFSV2PROC_NOOP, 167 }; 168 169 /* 170 * Maps errno values to nfs error numbers. 171 * Use NFSERR_IO as the catch all for ones not specifically defined in 172 * RFC 1094. 173 */ 174 static u_char nfsrv_v2errmap[ELAST] = { 175 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 176 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 177 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 178 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 179 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 180 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 181 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 182 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 183 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 184 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 185 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 186 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 187 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 188 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, 189 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 190 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 191 NFSERR_IO, 192 }; 193 194 /* 195 * Maps errno values to nfs error numbers. 196 * Although it is not obvious whether or not NFS clients really care if 197 * a returned error value is in the specified list for the procedure, the 198 * safest thing to do is filter them appropriately. For Version 2, the 199 * X/Open XNFS document is the only specification that defines error values 200 * for each RPC (The RFC simply lists all possible error values for all RPCs), 201 * so I have decided to not do this for Version 2. 202 * The first entry is the default error return and the rest are the valid 203 * errors for that RPC in increasing numeric order. 204 */ 205 static short nfsv3err_null[] = { 206 0, 207 0, 208 }; 209 210 static short nfsv3err_getattr[] = { 211 NFSERR_IO, 212 NFSERR_IO, 213 NFSERR_STALE, 214 NFSERR_BADHANDLE, 215 NFSERR_SERVERFAULT, 216 0, 217 }; 218 219 static short nfsv3err_setattr[] = { 220 NFSERR_IO, 221 NFSERR_PERM, 222 NFSERR_IO, 223 NFSERR_ACCES, 224 NFSERR_INVAL, 225 NFSERR_NOSPC, 226 NFSERR_ROFS, 227 NFSERR_DQUOT, 228 NFSERR_STALE, 229 NFSERR_BADHANDLE, 230 NFSERR_NOT_SYNC, 231 NFSERR_SERVERFAULT, 232 0, 233 }; 234 235 static short nfsv3err_lookup[] = { 236 NFSERR_IO, 237 NFSERR_NOENT, 238 NFSERR_IO, 239 NFSERR_ACCES, 240 NFSERR_NOTDIR, 241 NFSERR_NAMETOL, 242 NFSERR_STALE, 243 NFSERR_BADHANDLE, 244 NFSERR_SERVERFAULT, 245 0, 246 }; 247 248 static short nfsv3err_access[] = { 249 NFSERR_IO, 250 NFSERR_IO, 251 NFSERR_STALE, 252 NFSERR_BADHANDLE, 253 NFSERR_SERVERFAULT, 254 0, 255 }; 256 257 static short nfsv3err_readlink[] = { 258 NFSERR_IO, 259 NFSERR_IO, 260 NFSERR_ACCES, 261 NFSERR_INVAL, 262 NFSERR_STALE, 263 NFSERR_BADHANDLE, 264 NFSERR_NOTSUPP, 265 NFSERR_SERVERFAULT, 266 0, 267 }; 268 269 static short nfsv3err_read[] = { 270 NFSERR_IO, 271 NFSERR_IO, 272 NFSERR_NXIO, 273 NFSERR_ACCES, 274 NFSERR_INVAL, 275 NFSERR_STALE, 276 NFSERR_BADHANDLE, 277 NFSERR_SERVERFAULT, 278 0, 279 }; 280 281 static short nfsv3err_write[] = { 282 NFSERR_IO, 283 NFSERR_IO, 284 NFSERR_ACCES, 285 NFSERR_INVAL, 286 NFSERR_FBIG, 287 NFSERR_NOSPC, 288 NFSERR_ROFS, 289 NFSERR_DQUOT, 290 NFSERR_STALE, 291 NFSERR_BADHANDLE, 292 NFSERR_SERVERFAULT, 293 0, 294 }; 295 296 static short nfsv3err_create[] = { 297 NFSERR_IO, 298 NFSERR_IO, 299 NFSERR_ACCES, 300 NFSERR_EXIST, 301 NFSERR_NOTDIR, 302 NFSERR_NOSPC, 303 NFSERR_ROFS, 304 NFSERR_NAMETOL, 305 NFSERR_DQUOT, 306 NFSERR_STALE, 307 NFSERR_BADHANDLE, 308 NFSERR_NOTSUPP, 309 NFSERR_SERVERFAULT, 310 0, 311 }; 312 313 static short nfsv3err_mkdir[] = { 314 NFSERR_IO, 315 NFSERR_IO, 316 NFSERR_ACCES, 317 NFSERR_EXIST, 318 NFSERR_NOTDIR, 319 NFSERR_NOSPC, 320 NFSERR_ROFS, 321 NFSERR_NAMETOL, 322 NFSERR_DQUOT, 323 NFSERR_STALE, 324 NFSERR_BADHANDLE, 325 NFSERR_NOTSUPP, 326 NFSERR_SERVERFAULT, 327 0, 328 }; 329 330 static short nfsv3err_symlink[] = { 331 NFSERR_IO, 332 NFSERR_IO, 333 NFSERR_ACCES, 334 NFSERR_EXIST, 335 NFSERR_NOTDIR, 336 NFSERR_NOSPC, 337 NFSERR_ROFS, 338 NFSERR_NAMETOL, 339 NFSERR_DQUOT, 340 NFSERR_STALE, 341 NFSERR_BADHANDLE, 342 NFSERR_NOTSUPP, 343 NFSERR_SERVERFAULT, 344 0, 345 }; 346 347 static short nfsv3err_mknod[] = { 348 NFSERR_IO, 349 NFSERR_IO, 350 NFSERR_ACCES, 351 NFSERR_EXIST, 352 NFSERR_NOTDIR, 353 NFSERR_NOSPC, 354 NFSERR_ROFS, 355 NFSERR_NAMETOL, 356 NFSERR_DQUOT, 357 NFSERR_STALE, 358 NFSERR_BADHANDLE, 359 NFSERR_NOTSUPP, 360 NFSERR_SERVERFAULT, 361 NFSERR_BADTYPE, 362 0, 363 }; 364 365 static short nfsv3err_remove[] = { 366 NFSERR_IO, 367 NFSERR_NOENT, 368 NFSERR_IO, 369 NFSERR_ACCES, 370 NFSERR_NOTDIR, 371 NFSERR_ROFS, 372 NFSERR_NAMETOL, 373 NFSERR_STALE, 374 NFSERR_BADHANDLE, 375 NFSERR_SERVERFAULT, 376 0, 377 }; 378 379 static short nfsv3err_rmdir[] = { 380 NFSERR_IO, 381 NFSERR_NOENT, 382 NFSERR_IO, 383 NFSERR_ACCES, 384 NFSERR_EXIST, 385 NFSERR_NOTDIR, 386 NFSERR_INVAL, 387 NFSERR_ROFS, 388 NFSERR_NAMETOL, 389 NFSERR_NOTEMPTY, 390 NFSERR_STALE, 391 NFSERR_BADHANDLE, 392 NFSERR_NOTSUPP, 393 NFSERR_SERVERFAULT, 394 0, 395 }; 396 397 static short nfsv3err_rename[] = { 398 NFSERR_IO, 399 NFSERR_NOENT, 400 NFSERR_IO, 401 NFSERR_ACCES, 402 NFSERR_EXIST, 403 NFSERR_XDEV, 404 NFSERR_NOTDIR, 405 NFSERR_ISDIR, 406 NFSERR_INVAL, 407 NFSERR_NOSPC, 408 NFSERR_ROFS, 409 NFSERR_MLINK, 410 NFSERR_NAMETOL, 411 NFSERR_NOTEMPTY, 412 NFSERR_DQUOT, 413 NFSERR_STALE, 414 NFSERR_BADHANDLE, 415 NFSERR_NOTSUPP, 416 NFSERR_SERVERFAULT, 417 0, 418 }; 419 420 static short nfsv3err_link[] = { 421 NFSERR_IO, 422 NFSERR_IO, 423 NFSERR_ACCES, 424 NFSERR_EXIST, 425 NFSERR_XDEV, 426 NFSERR_NOTDIR, 427 NFSERR_INVAL, 428 NFSERR_NOSPC, 429 NFSERR_ROFS, 430 NFSERR_MLINK, 431 NFSERR_NAMETOL, 432 NFSERR_DQUOT, 433 NFSERR_STALE, 434 NFSERR_BADHANDLE, 435 NFSERR_NOTSUPP, 436 NFSERR_SERVERFAULT, 437 0, 438 }; 439 440 static short nfsv3err_readdir[] = { 441 NFSERR_IO, 442 NFSERR_IO, 443 NFSERR_ACCES, 444 NFSERR_NOTDIR, 445 NFSERR_STALE, 446 NFSERR_BADHANDLE, 447 NFSERR_BAD_COOKIE, 448 NFSERR_TOOSMALL, 449 NFSERR_SERVERFAULT, 450 0, 451 }; 452 453 static short nfsv3err_readdirplus[] = { 454 NFSERR_IO, 455 NFSERR_IO, 456 NFSERR_ACCES, 457 NFSERR_NOTDIR, 458 NFSERR_STALE, 459 NFSERR_BADHANDLE, 460 NFSERR_BAD_COOKIE, 461 NFSERR_NOTSUPP, 462 NFSERR_TOOSMALL, 463 NFSERR_SERVERFAULT, 464 0, 465 }; 466 467 static short nfsv3err_fsstat[] = { 468 NFSERR_IO, 469 NFSERR_IO, 470 NFSERR_STALE, 471 NFSERR_BADHANDLE, 472 NFSERR_SERVERFAULT, 473 0, 474 }; 475 476 static short nfsv3err_fsinfo[] = { 477 NFSERR_STALE, 478 NFSERR_STALE, 479 NFSERR_BADHANDLE, 480 NFSERR_SERVERFAULT, 481 0, 482 }; 483 484 static short nfsv3err_pathconf[] = { 485 NFSERR_STALE, 486 NFSERR_STALE, 487 NFSERR_BADHANDLE, 488 NFSERR_SERVERFAULT, 489 0, 490 }; 491 492 static short nfsv3err_commit[] = { 493 NFSERR_IO, 494 NFSERR_IO, 495 NFSERR_STALE, 496 NFSERR_BADHANDLE, 497 NFSERR_SERVERFAULT, 498 0, 499 }; 500 501 static short *nfsrv_v3errmap[] = { 502 nfsv3err_null, 503 nfsv3err_getattr, 504 nfsv3err_setattr, 505 nfsv3err_lookup, 506 nfsv3err_access, 507 nfsv3err_readlink, 508 nfsv3err_read, 509 nfsv3err_write, 510 nfsv3err_create, 511 nfsv3err_mkdir, 512 nfsv3err_symlink, 513 nfsv3err_mknod, 514 nfsv3err_remove, 515 nfsv3err_rmdir, 516 nfsv3err_rename, 517 nfsv3err_link, 518 nfsv3err_readdir, 519 nfsv3err_readdirplus, 520 nfsv3err_fsstat, 521 nfsv3err_fsinfo, 522 nfsv3err_pathconf, 523 nfsv3err_commit, 524 }; 525 526 extern struct nfsrtt nfsrtt; 527 extern time_t nqnfsstarttime; 528 extern int nqsrv_clockskew; 529 extern int nqsrv_writeslack; 530 extern int nqsrv_maxlease; 531 extern int nqnfs_piggy[NFS_NPROCS]; 532 extern nfstype nfsv2_type[9]; 533 extern nfstype nfsv3_type[9]; 534 extern struct nfsnodehashhead *nfsnodehashtbl; 535 extern u_long nfsnodehash; 536 537 LIST_HEAD(nfsnodehashhead, nfsnode); 538 539 /* 540 * Create the header for an rpc request packet 541 * The hsiz is the size of the rest of the nfs request header. 542 * (just used to decide if a cluster is a good idea) 543 */ 544 struct mbuf * 545 nfsm_reqh(vp, procid, hsiz, bposp) 546 struct vnode *vp; 547 u_long procid; 548 int hsiz; 549 caddr_t *bposp; 550 { 551 register struct mbuf *mb; 552 register u_int32_t *tl; 553 register caddr_t bpos; 554 struct mbuf *mb2; 555 struct nfsmount *nmp; 556 int nqflag; 557 558 MGET(mb, M_WAIT, MT_DATA); 559 if (hsiz >= MINCLSIZE) 560 MCLGET(mb, M_WAIT); 561 mb->m_len = 0; 562 bpos = mtod(mb, caddr_t); 563 564 /* 565 * For NQNFS, add lease request. 566 */ 567 if (vp) { 568 nmp = VFSTONFS(vp->v_mount); 569 if (nmp->nm_flag & NFSMNT_NQNFS) { 570 nqflag = NQNFS_NEEDLEASE(vp, procid); 571 if (nqflag) { 572 nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED); 573 *tl++ = txdr_unsigned(nqflag); 574 *tl = txdr_unsigned(nmp->nm_leaseterm); 575 } else { 576 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 577 *tl = 0; 578 } 579 } 580 } 581 /* Finally, return values */ 582 *bposp = bpos; 583 return (mb); 584 } 585 586 /* 587 * Build the RPC header and fill in the authorization info. 588 * The authorization string argument is only used when the credentials 589 * come from outside of the kernel. 590 * Returns the head of the mbuf list. 591 */ 592 struct mbuf * 593 nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, 594 verf_str, mrest, mrest_len, mbp, xidp) 595 register struct ucred *cr; 596 int nmflag; 597 int procid; 598 int auth_type; 599 int auth_len; 600 char *auth_str; 601 int verf_len; 602 char *verf_str; 603 struct mbuf *mrest; 604 int mrest_len; 605 struct mbuf **mbp; 606 u_int32_t *xidp; 607 { 608 register struct mbuf *mb; 609 register u_int32_t *tl; 610 register caddr_t bpos; 611 register int i; 612 struct mbuf *mreq, *mb2; 613 int siz, grpsiz, authsiz; 614 struct timeval tv; 615 static u_int32_t base; 616 617 authsiz = nfsm_rndup(auth_len); 618 MGETHDR(mb, M_WAIT, MT_DATA); 619 if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 620 MCLGET(mb, M_WAIT); 621 } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 622 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 623 } else { 624 MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 625 } 626 mb->m_len = 0; 627 mreq = mb; 628 bpos = mtod(mb, caddr_t); 629 630 /* 631 * First the RPC header. 632 */ 633 nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 634 635 /* 636 * derive initial xid from system time 637 * XXX time is invalid if root not yet mounted 638 */ 639 if (!base && (rootvp)) { 640 microtime(&tv); 641 base = tv.tv_sec << 12; 642 nfs_xid = base; 643 } 644 /* 645 * Skip zero xid if it should ever happen. 646 */ 647 if (++nfs_xid == 0) 648 nfs_xid++; 649 650 *tl++ = *xidp = txdr_unsigned(nfs_xid); 651 *tl++ = rpc_call; 652 *tl++ = rpc_vers; 653 if (nmflag & NFSMNT_NQNFS) { 654 *tl++ = txdr_unsigned(NQNFS_PROG); 655 *tl++ = txdr_unsigned(NQNFS_VER3); 656 } else { 657 *tl++ = txdr_unsigned(NFS_PROG); 658 if (nmflag & NFSMNT_NFSV3) 659 *tl++ = txdr_unsigned(NFS_VER3); 660 else 661 *tl++ = txdr_unsigned(NFS_VER2); 662 } 663 if (nmflag & NFSMNT_NFSV3) 664 *tl++ = txdr_unsigned(procid); 665 else 666 *tl++ = txdr_unsigned(nfsv2_procid[procid]); 667 668 /* 669 * And then the authorization cred. 670 */ 671 *tl++ = txdr_unsigned(auth_type); 672 *tl = txdr_unsigned(authsiz); 673 switch (auth_type) { 674 case RPCAUTH_UNIX: 675 nfsm_build(tl, u_int32_t *, auth_len); 676 *tl++ = 0; /* stamp ?? */ 677 *tl++ = 0; /* NULL hostname */ 678 *tl++ = txdr_unsigned(cr->cr_uid); 679 *tl++ = txdr_unsigned(cr->cr_gid); 680 grpsiz = (auth_len >> 2) - 5; 681 *tl++ = txdr_unsigned(grpsiz); 682 for (i = 0; i < grpsiz; i++) 683 *tl++ = txdr_unsigned(cr->cr_groups[i]); 684 break; 685 case RPCAUTH_KERB4: 686 siz = auth_len; 687 while (siz > 0) { 688 if (M_TRAILINGSPACE(mb) == 0) { 689 MGET(mb2, M_WAIT, MT_DATA); 690 if (siz >= MINCLSIZE) 691 MCLGET(mb2, M_WAIT); 692 mb->m_next = mb2; 693 mb = mb2; 694 mb->m_len = 0; 695 bpos = mtod(mb, caddr_t); 696 } 697 i = min(siz, M_TRAILINGSPACE(mb)); 698 bcopy(auth_str, bpos, i); 699 mb->m_len += i; 700 auth_str += i; 701 bpos += i; 702 siz -= i; 703 } 704 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 705 for (i = 0; i < siz; i++) 706 *bpos++ = '\0'; 707 mb->m_len += siz; 708 } 709 break; 710 }; 711 712 /* 713 * And the verifier... 714 */ 715 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 716 if (verf_str) { 717 *tl++ = txdr_unsigned(RPCAUTH_KERB4); 718 *tl = txdr_unsigned(verf_len); 719 siz = verf_len; 720 while (siz > 0) { 721 if (M_TRAILINGSPACE(mb) == 0) { 722 MGET(mb2, M_WAIT, MT_DATA); 723 if (siz >= MINCLSIZE) 724 MCLGET(mb2, M_WAIT); 725 mb->m_next = mb2; 726 mb = mb2; 727 mb->m_len = 0; 728 bpos = mtod(mb, caddr_t); 729 } 730 i = min(siz, M_TRAILINGSPACE(mb)); 731 bcopy(verf_str, bpos, i); 732 mb->m_len += i; 733 verf_str += i; 734 bpos += i; 735 siz -= i; 736 } 737 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { 738 for (i = 0; i < siz; i++) 739 *bpos++ = '\0'; 740 mb->m_len += siz; 741 } 742 } else { 743 *tl++ = txdr_unsigned(RPCAUTH_NULL); 744 *tl = 0; 745 } 746 mb->m_next = mrest; 747 mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 748 mreq->m_pkthdr.rcvif = (struct ifnet *)0; 749 *mbp = mb; 750 return (mreq); 751 } 752 753 /* 754 * copies mbuf chain to the uio scatter/gather list 755 */ 756 int 757 nfsm_mbuftouio(mrep, uiop, siz, dpos) 758 struct mbuf **mrep; 759 register struct uio *uiop; 760 int siz; 761 caddr_t *dpos; 762 { 763 register char *mbufcp, *uiocp; 764 register int xfer, left, len; 765 register struct mbuf *mp; 766 long uiosiz, rem; 767 int error = 0; 768 769 mp = *mrep; 770 mbufcp = *dpos; 771 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 772 rem = nfsm_rndup(siz)-siz; 773 while (siz > 0) { 774 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 775 return (EFBIG); 776 left = uiop->uio_iov->iov_len; 777 uiocp = uiop->uio_iov->iov_base; 778 if (left > siz) 779 left = siz; 780 uiosiz = left; 781 while (left > 0) { 782 while (len == 0) { 783 mp = mp->m_next; 784 if (mp == NULL) 785 return (EBADRPC); 786 mbufcp = mtod(mp, caddr_t); 787 len = mp->m_len; 788 } 789 xfer = (left > len) ? len : left; 790 #ifdef notdef 791 /* Not Yet.. */ 792 if (uiop->uio_iov->iov_op != NULL) 793 (*(uiop->uio_iov->iov_op)) 794 (mbufcp, uiocp, xfer); 795 else 796 #endif 797 if (uiop->uio_segflg == UIO_SYSSPACE) 798 bcopy(mbufcp, uiocp, xfer); 799 else 800 copyout(mbufcp, uiocp, xfer); 801 left -= xfer; 802 len -= xfer; 803 mbufcp += xfer; 804 uiocp += xfer; 805 uiop->uio_offset += xfer; 806 uiop->uio_resid -= xfer; 807 } 808 if (uiop->uio_iov->iov_len <= siz) { 809 uiop->uio_iovcnt--; 810 uiop->uio_iov++; 811 } else { 812 uiop->uio_iov->iov_base += uiosiz; 813 uiop->uio_iov->iov_len -= uiosiz; 814 } 815 siz -= uiosiz; 816 } 817 *dpos = mbufcp; 818 *mrep = mp; 819 if (rem > 0) { 820 if (len < rem) 821 error = nfs_adv(mrep, dpos, rem, len); 822 else 823 *dpos += rem; 824 } 825 return (error); 826 } 827 828 /* 829 * copies a uio scatter/gather list to an mbuf chain. 830 * NOTE: can ony handle iovcnt == 1 831 */ 832 int 833 nfsm_uiotombuf(uiop, mq, siz, bpos) 834 register struct uio *uiop; 835 struct mbuf **mq; 836 int siz; 837 caddr_t *bpos; 838 { 839 register char *uiocp; 840 register struct mbuf *mp, *mp2; 841 register int xfer, left, mlen; 842 int uiosiz, clflg, rem; 843 char *cp; 844 845 #ifdef DIAGNOSTIC 846 if (uiop->uio_iovcnt != 1) 847 panic("nfsm_uiotombuf: iovcnt != 1"); 848 #endif 849 850 if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 851 clflg = 1; 852 else 853 clflg = 0; 854 rem = nfsm_rndup(siz)-siz; 855 mp = mp2 = *mq; 856 while (siz > 0) { 857 left = uiop->uio_iov->iov_len; 858 uiocp = uiop->uio_iov->iov_base; 859 if (left > siz) 860 left = siz; 861 uiosiz = left; 862 while (left > 0) { 863 mlen = M_TRAILINGSPACE(mp); 864 if (mlen == 0) { 865 MGET(mp, M_WAIT, MT_DATA); 866 if (clflg) 867 MCLGET(mp, M_WAIT); 868 mp->m_len = 0; 869 mp2->m_next = mp; 870 mp2 = mp; 871 mlen = M_TRAILINGSPACE(mp); 872 } 873 xfer = (left > mlen) ? mlen : left; 874 #ifdef notdef 875 /* Not Yet.. */ 876 if (uiop->uio_iov->iov_op != NULL) 877 (*(uiop->uio_iov->iov_op)) 878 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 879 else 880 #endif 881 if (uiop->uio_segflg == UIO_SYSSPACE) 882 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 883 else 884 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 885 mp->m_len += xfer; 886 left -= xfer; 887 uiocp += xfer; 888 uiop->uio_offset += xfer; 889 uiop->uio_resid -= xfer; 890 } 891 uiop->uio_iov->iov_base += uiosiz; 892 uiop->uio_iov->iov_len -= uiosiz; 893 siz -= uiosiz; 894 } 895 if (rem > 0) { 896 if (rem > M_TRAILINGSPACE(mp)) { 897 MGET(mp, M_WAIT, MT_DATA); 898 mp->m_len = 0; 899 mp2->m_next = mp; 900 } 901 cp = mtod(mp, caddr_t)+mp->m_len; 902 for (left = 0; left < rem; left++) 903 *cp++ = '\0'; 904 mp->m_len += rem; 905 *bpos = cp; 906 } else 907 *bpos = mtod(mp, caddr_t)+mp->m_len; 908 *mq = mp; 909 return (0); 910 } 911 912 /* 913 * Get at least "siz" bytes of correctly aligned data. 914 * When called the mbuf pointers are not necessarily correct, 915 * dsosp points to what ought to be in m_data and left contains 916 * what ought to be in m_len. 917 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 918 * cases. (The macros use the vars. dpos and dpos2) 919 */ 920 int 921 nfsm_disct(mdp, dposp, siz, left, cp2) 922 struct mbuf **mdp; 923 caddr_t *dposp; 924 int siz; 925 int left; 926 caddr_t *cp2; 927 { 928 register struct mbuf *m1, *m2; 929 struct mbuf *havebuf = NULL; 930 caddr_t src = *dposp; 931 caddr_t dst; 932 int len; 933 934 #ifdef DEBUG 935 if (left < 0) 936 panic("nfsm_disct: left < 0"); 937 #endif 938 m1 = *mdp; 939 /* 940 * Skip through the mbuf chain looking for an mbuf with 941 * some data. If the first mbuf found has enough data 942 * and it is correctly aligned return it. 943 */ 944 while (left == 0) { 945 havebuf = m1; 946 *mdp = m1 = m1->m_next; 947 if (m1 == NULL) 948 return (EBADRPC); 949 src = mtod(m1, caddr_t); 950 left = m1->m_len; 951 /* 952 * If we start a new mbuf and it is big enough 953 * and correctly aligned just return it, don't 954 * do any pull up. 955 */ 956 if (left >= siz && nfsm_aligned(src)) { 957 *cp2 = src; 958 *dposp = src + siz; 959 return (0); 960 } 961 } 962 if (m1->m_flags & M_EXT) { 963 if (havebuf) { 964 /* If the first mbuf with data has external data 965 * and there is a previous empty mbuf use it 966 * to move the data into. 967 */ 968 m2 = m1; 969 *mdp = m1 = havebuf; 970 if (m1->m_flags & M_EXT) { 971 MEXTREMOVE(m1); 972 } 973 } else { 974 /* 975 * If the first mbuf has a external data 976 * and there is no previous empty mbuf 977 * allocate a new mbuf and move the external 978 * data to the new mbuf. Also make the first 979 * mbuf look empty. 980 */ 981 m2 = m_get(M_WAIT, MT_DATA); 982 m2->m_ext = m1->m_ext; 983 m2->m_data = src; 984 m2->m_len = left; 985 MCLADDREFERENCE(m1, m2); 986 MEXTREMOVE(m1); 987 m2->m_next = m1->m_next; 988 m1->m_next = m2; 989 } 990 m1->m_len = 0; 991 dst = m1->m_dat; 992 } else { 993 /* 994 * If the first mbuf has no external data 995 * move the data to the front of the mbuf. 996 */ 997 if ((dst = m1->m_dat) != src) 998 ovbcopy(src, dst, left); 999 dst += left; 1000 m1->m_len = left; 1001 m2 = m1->m_next; 1002 } 1003 m1->m_flags &= ~M_PKTHDR; 1004 *cp2 = m1->m_data = m1->m_dat; /* data is at beginning of buffer */ 1005 *dposp = mtod(m1, caddr_t) + siz; 1006 /* 1007 * Loop through mbufs pulling data up into first mbuf until 1008 * the first mbuf is full or there is no more data to 1009 * pullup. 1010 */ 1011 while ((len = (MLEN - m1->m_len)) != 0 && m2) { 1012 if ((len = min(len, m2->m_len)) != 0) 1013 bcopy(m2->m_data, dst, len); 1014 m1->m_len += len; 1015 dst += len; 1016 m2->m_data += len; 1017 m2->m_len -= len; 1018 m2 = m2->m_next; 1019 } 1020 if (m1->m_len < siz) 1021 return (EBADRPC); 1022 return (0); 1023 } 1024 1025 /* 1026 * Advance the position in the mbuf chain. 1027 */ 1028 int 1029 nfs_adv(mdp, dposp, offs, left) 1030 struct mbuf **mdp; 1031 caddr_t *dposp; 1032 int offs; 1033 int left; 1034 { 1035 register struct mbuf *m; 1036 register int s; 1037 1038 m = *mdp; 1039 s = left; 1040 while (s < offs) { 1041 offs -= s; 1042 m = m->m_next; 1043 if (m == NULL) 1044 return (EBADRPC); 1045 s = m->m_len; 1046 } 1047 *mdp = m; 1048 *dposp = mtod(m, caddr_t)+offs; 1049 return (0); 1050 } 1051 1052 /* 1053 * Copy a string into mbufs for the hard cases... 1054 */ 1055 int 1056 nfsm_strtmbuf(mb, bpos, cp, siz) 1057 struct mbuf **mb; 1058 char **bpos; 1059 const char *cp; 1060 long siz; 1061 { 1062 register struct mbuf *m1 = NULL, *m2; 1063 long left, xfer, len, tlen; 1064 u_int32_t *tl; 1065 int putsize; 1066 1067 putsize = 1; 1068 m2 = *mb; 1069 left = M_TRAILINGSPACE(m2); 1070 if (left > 0) { 1071 tl = ((u_int32_t *)(*bpos)); 1072 *tl++ = txdr_unsigned(siz); 1073 putsize = 0; 1074 left -= NFSX_UNSIGNED; 1075 m2->m_len += NFSX_UNSIGNED; 1076 if (left > 0) { 1077 bcopy(cp, (caddr_t) tl, left); 1078 siz -= left; 1079 cp += left; 1080 m2->m_len += left; 1081 left = 0; 1082 } 1083 } 1084 /* Loop around adding mbufs */ 1085 while (siz > 0) { 1086 MGET(m1, M_WAIT, MT_DATA); 1087 if (siz > MLEN) 1088 MCLGET(m1, M_WAIT); 1089 m1->m_len = NFSMSIZ(m1); 1090 m2->m_next = m1; 1091 m2 = m1; 1092 tl = mtod(m1, u_int32_t *); 1093 tlen = 0; 1094 if (putsize) { 1095 *tl++ = txdr_unsigned(siz); 1096 m1->m_len -= NFSX_UNSIGNED; 1097 tlen = NFSX_UNSIGNED; 1098 putsize = 0; 1099 } 1100 if (siz < m1->m_len) { 1101 len = nfsm_rndup(siz); 1102 xfer = siz; 1103 if (xfer < len) 1104 *(tl+(xfer>>2)) = 0; 1105 } else { 1106 xfer = len = m1->m_len; 1107 } 1108 bcopy(cp, (caddr_t) tl, xfer); 1109 m1->m_len = len+tlen; 1110 siz -= xfer; 1111 cp += xfer; 1112 } 1113 *mb = m1; 1114 *bpos = mtod(m1, caddr_t)+m1->m_len; 1115 return (0); 1116 } 1117 1118 /* 1119 * Called once before VFS init to initialize shared and 1120 * server-specific data structures. 1121 */ 1122 void 1123 nfs_init() 1124 { 1125 1126 #if !defined(alpha) && defined(DIAGNOSTIC) 1127 /* 1128 * Check to see if major data structures haven't bloated. 1129 */ 1130 if (sizeof (struct nfsnode) > NFS_NODEALLOC) { 1131 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC); 1132 printf("Try reducing NFS_SMALLFH\n"); 1133 } 1134 if (sizeof (struct nfsmount) > NFS_MNTALLOC) { 1135 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC); 1136 printf("Try reducing NFS_MUIDHASHSIZ\n"); 1137 } 1138 if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) { 1139 printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC); 1140 printf("Try reducing NFS_UIDHASHSIZ\n"); 1141 } 1142 if (sizeof (struct nfsuid) > NFS_UIDALLOC) { 1143 printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); 1144 printf("Try unionizing the nu_nickname and nu_flag fields\n"); 1145 } 1146 #endif 1147 1148 nfsrtt.pos = 0; 1149 rpc_vers = txdr_unsigned(RPC_VER2); 1150 rpc_call = txdr_unsigned(RPC_CALL); 1151 rpc_reply = txdr_unsigned(RPC_REPLY); 1152 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 1153 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 1154 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 1155 rpc_autherr = txdr_unsigned(RPC_AUTHERR); 1156 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 1157 rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); 1158 nfs_prog = txdr_unsigned(NFS_PROG); 1159 nqnfs_prog = txdr_unsigned(NQNFS_PROG); 1160 nfs_true = txdr_unsigned(TRUE); 1161 nfs_false = txdr_unsigned(FALSE); 1162 nfs_xdrneg1 = txdr_unsigned(-1); 1163 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 1164 if (nfs_ticks < 1) 1165 nfs_ticks = 1; 1166 #ifdef NFSSERVER 1167 nfsrv_init(0); /* Init server data structures */ 1168 nfsrv_initcache(); /* Init the server request cache */ 1169 #endif /* NFSSERVER */ 1170 1171 /* 1172 * Initialize the nqnfs data structures. 1173 */ 1174 if (nqnfsstarttime == 0) { 1175 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 1176 + nqsrv_clockskew + nqsrv_writeslack; 1177 NQLOADNOVRAM(nqnfsstarttime); 1178 CIRCLEQ_INIT(&nqtimerhead); 1179 nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 1180 } 1181 1182 /* 1183 * Initialize reply list and start timer 1184 */ 1185 TAILQ_INIT(&nfs_reqq); 1186 nfs_timer(NULL); 1187 } 1188 1189 #ifdef NFS 1190 /* 1191 * Called once at VFS init to initialize client-specific data structures. 1192 */ 1193 void 1194 nfs_vfs_init() 1195 { 1196 register int i; 1197 1198 /* Ensure async daemons disabled */ 1199 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 1200 nfs_iodwant[i] = (struct proc *)0; 1201 nfs_iodmount[i] = (struct nfsmount *)0; 1202 } 1203 nfs_nhinit(); /* Init the nfsnode table */ 1204 } 1205 1206 /* 1207 * Attribute cache routines. 1208 * nfs_loadattrcache() - loads or updates the cache contents from attributes 1209 * that are on the mbuf list 1210 * nfs_getattrcache() - returns valid attributes if found in cache, returns 1211 * error otherwise 1212 */ 1213 1214 /* 1215 * Load the attribute cache (that lives in the nfsnode entry) with 1216 * the values on the mbuf list and 1217 * Iff vap not NULL 1218 * copy the attributes to *vaper 1219 */ 1220 int 1221 nfs_loadattrcache(vpp, mdp, dposp, vaper) 1222 struct vnode **vpp; 1223 struct mbuf **mdp; 1224 caddr_t *dposp; 1225 struct vattr *vaper; 1226 { 1227 register struct vnode *vp = *vpp; 1228 register struct vattr *vap; 1229 register struct nfs_fattr *fp; 1230 extern int (**spec_nfsv2nodeop_p) __P((void *)); 1231 register struct nfsnode *np; 1232 register int32_t t1; 1233 caddr_t cp2; 1234 int error = 0; 1235 int32_t rdev; 1236 struct mbuf *md; 1237 enum vtype vtyp; 1238 u_short vmode; 1239 struct timespec mtime; 1240 struct vnode *nvp; 1241 int v3 = NFS_ISV3(vp); 1242 1243 md = *mdp; 1244 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 1245 error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2); 1246 if (error) 1247 return (error); 1248 fp = (struct nfs_fattr *)cp2; 1249 if (v3) { 1250 vtyp = nfsv3tov_type(fp->fa_type); 1251 vmode = fxdr_unsigned(u_short, fp->fa_mode); 1252 rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1), 1253 fxdr_unsigned(u_char, fp->fa3_rdev.specdata2)); 1254 fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 1255 } else { 1256 vtyp = nfsv2tov_type(fp->fa_type); 1257 vmode = fxdr_unsigned(u_short, fp->fa_mode); 1258 if (vtyp == VNON || vtyp == VREG) 1259 vtyp = IFTOVT(vmode); 1260 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 1261 fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 1262 1263 /* 1264 * Really ugly NFSv2 kludge. 1265 */ 1266 if (vtyp == VCHR && rdev == 0xffffffff) 1267 vtyp = VFIFO; 1268 } 1269 1270 /* 1271 * If v_type == VNON it is a new node, so fill in the v_type, 1272 * n_mtime fields. Check to see if it represents a special 1273 * device, and if so, check for a possible alias. Once the 1274 * correct vnode has been obtained, fill in the rest of the 1275 * information. 1276 */ 1277 np = VTONFS(vp); 1278 if (vp->v_type != vtyp) { 1279 vp->v_type = vtyp; 1280 if (vp->v_type == VFIFO) { 1281 #ifndef FIFO 1282 return (EOPNOTSUPP); 1283 #else 1284 extern int (**fifo_nfsv2nodeop_p) __P((void *)); 1285 vp->v_op = fifo_nfsv2nodeop_p; 1286 #endif /* FIFO */ 1287 } 1288 if (vp->v_type == VCHR || vp->v_type == VBLK) { 1289 vp->v_op = spec_nfsv2nodeop_p; 1290 nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); 1291 if (nvp) { 1292 /* 1293 * Discard unneeded vnode, but save its nfsnode. 1294 * Since the nfsnode does not have a lock, its 1295 * vnode lock has to be carried over. 1296 */ 1297 #ifdef Lite2_integrated 1298 nvp->v_vnlock = vp->v_vnlock; 1299 vp->v_vnlock = NULL; 1300 #endif 1301 nvp->v_data = vp->v_data; 1302 vp->v_data = NULL; 1303 vp->v_op = spec_vnodeop_p; 1304 vrele(vp); 1305 vgone(vp); 1306 /* 1307 * Reinitialize aliased node. 1308 */ 1309 np->n_vnode = nvp; 1310 *vpp = vp = nvp; 1311 } 1312 } 1313 np->n_mtime = mtime.tv_sec; 1314 } 1315 vap = &np->n_vattr; 1316 vap->va_type = vtyp; 1317 vap->va_mode = (vmode & 07777); 1318 vap->va_rdev = (dev_t)rdev; 1319 vap->va_mtime = mtime; 1320 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 1321 if (v3) { 1322 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1323 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1324 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1325 fxdr_hyper(&fp->fa3_size, &vap->va_size); 1326 vap->va_blocksize = NFS_FABLKSIZE; 1327 fxdr_hyper(&fp->fa3_used, &vap->va_bytes); 1328 vap->va_fileid = fxdr_unsigned(int32_t, 1329 fp->fa3_fileid.nfsuquad[1]); 1330 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 1331 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 1332 vap->va_flags = 0; 1333 vap->va_filerev = 0; 1334 } else { 1335 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 1336 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1337 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1338 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 1339 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 1340 vap->va_bytes = fxdr_unsigned(int32_t, fp->fa2_blocks) 1341 * NFS_FABLKSIZE; 1342 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 1343 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 1344 vap->va_flags = 0; 1345 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 1346 fp->fa2_ctime.nfsv2_sec); 1347 vap->va_ctime.tv_nsec = 0; 1348 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 1349 vap->va_filerev = 0; 1350 } 1351 if (vap->va_size != np->n_size) { 1352 if (vap->va_type == VREG) { 1353 if (np->n_flag & NMODIFIED) { 1354 if (vap->va_size < np->n_size) 1355 vap->va_size = np->n_size; 1356 else 1357 np->n_size = vap->va_size; 1358 } else 1359 np->n_size = vap->va_size; 1360 vnode_pager_setsize(vp, (u_long)np->n_size); 1361 } else 1362 np->n_size = vap->va_size; 1363 } 1364 np->n_attrstamp = time.tv_sec; 1365 if (vaper != NULL) { 1366 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 1367 if (np->n_flag & NCHG) { 1368 if (np->n_flag & NACC) 1369 vaper->va_atime = np->n_atim; 1370 if (np->n_flag & NUPD) 1371 vaper->va_mtime = np->n_mtim; 1372 } 1373 } 1374 return (0); 1375 } 1376 1377 /* 1378 * Check the time stamp 1379 * If the cache is valid, copy contents to *vap and return 0 1380 * otherwise return an error 1381 */ 1382 int 1383 nfs_getattrcache(vp, vaper) 1384 register struct vnode *vp; 1385 struct vattr *vaper; 1386 { 1387 register struct nfsnode *np = VTONFS(vp); 1388 register struct vattr *vap; 1389 1390 if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 1391 nfsstats.attrcache_misses++; 1392 return (ENOENT); 1393 } 1394 nfsstats.attrcache_hits++; 1395 vap = &np->n_vattr; 1396 if (vap->va_size != np->n_size) { 1397 if (vap->va_type == VREG) { 1398 if (np->n_flag & NMODIFIED) { 1399 if (vap->va_size < np->n_size) 1400 vap->va_size = np->n_size; 1401 else 1402 np->n_size = vap->va_size; 1403 } else 1404 np->n_size = vap->va_size; 1405 vnode_pager_setsize(vp, (u_long)np->n_size); 1406 } else 1407 np->n_size = vap->va_size; 1408 } 1409 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 1410 if (np->n_flag & NCHG) { 1411 if (np->n_flag & NACC) 1412 vaper->va_atime = np->n_atim; 1413 if (np->n_flag & NUPD) 1414 vaper->va_mtime = np->n_mtim; 1415 } 1416 return (0); 1417 } 1418 #endif /* NFS */ 1419 1420 /* 1421 * Set up nameidata for a lookup() call and do it 1422 */ 1423 int 1424 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag) 1425 register struct nameidata *ndp; 1426 fhandle_t *fhp; 1427 int len; 1428 struct nfssvc_sock *slp; 1429 struct mbuf *nam; 1430 struct mbuf **mdp; 1431 caddr_t *dposp; 1432 struct vnode **retdirp; 1433 struct proc *p; 1434 int kerbflag; 1435 { 1436 register int i, rem; 1437 register struct mbuf *md; 1438 register char *fromcp, *tocp; 1439 struct vnode *dp; 1440 int error, rdonly; 1441 struct componentname *cnp = &ndp->ni_cnd; 1442 1443 *retdirp = (struct vnode *)0; 1444 MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 1445 /* 1446 * Copy the name from the mbuf list to ndp->ni_pnbuf 1447 * and set the various ndp fields appropriately. 1448 */ 1449 fromcp = *dposp; 1450 tocp = cnp->cn_pnbuf; 1451 md = *mdp; 1452 rem = mtod(md, caddr_t) + md->m_len - fromcp; 1453 for (i = 0; i < len; i++) { 1454 while (rem == 0) { 1455 md = md->m_next; 1456 if (md == NULL) { 1457 error = EBADRPC; 1458 goto out; 1459 } 1460 fromcp = mtod(md, caddr_t); 1461 rem = md->m_len; 1462 } 1463 if (*fromcp == '\0' || *fromcp == '/') { 1464 error = EACCES; 1465 goto out; 1466 } 1467 *tocp++ = *fromcp++; 1468 rem--; 1469 } 1470 *tocp = '\0'; 1471 *mdp = md; 1472 *dposp = fromcp; 1473 len = nfsm_rndup(len)-len; 1474 if (len > 0) { 1475 if (rem >= len) 1476 *dposp += len; 1477 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 1478 goto out; 1479 } 1480 ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 1481 cnp->cn_nameptr = cnp->cn_pnbuf; 1482 /* 1483 * Extract and set starting directory. 1484 */ 1485 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 1486 nam, &rdonly, kerbflag); 1487 if (error) 1488 goto out; 1489 if (dp->v_type != VDIR) { 1490 vrele(dp); 1491 error = ENOTDIR; 1492 goto out; 1493 } 1494 VREF(dp); 1495 *retdirp = dp; 1496 ndp->ni_startdir = dp; 1497 if (rdonly) 1498 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 1499 else 1500 cnp->cn_flags |= NOCROSSMOUNT; 1501 /* 1502 * And call lookup() to do the real work 1503 */ 1504 cnp->cn_proc = p; 1505 error = lookup(ndp); 1506 if (error) 1507 goto out; 1508 /* 1509 * Check for encountering a symbolic link 1510 */ 1511 if (cnp->cn_flags & ISSYMLINK) { 1512 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 1513 vput(ndp->ni_dvp); 1514 else 1515 vrele(ndp->ni_dvp); 1516 vput(ndp->ni_vp); 1517 ndp->ni_vp = NULL; 1518 error = EINVAL; 1519 goto out; 1520 } 1521 /* 1522 * Check for saved name request 1523 */ 1524 if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 1525 cnp->cn_flags |= HASBUF; 1526 return (0); 1527 } 1528 out: 1529 FREE(cnp->cn_pnbuf, M_NAMEI); 1530 return (error); 1531 } 1532 1533 /* 1534 * A fiddled version of m_adj() that ensures null fill to a long 1535 * boundary and only trims off the back end 1536 */ 1537 void 1538 nfsm_adj(mp, len, nul) 1539 struct mbuf *mp; 1540 register int len; 1541 int nul; 1542 { 1543 register struct mbuf *m; 1544 register int count, i; 1545 register char *cp; 1546 1547 /* 1548 * Trim from tail. Scan the mbuf chain, 1549 * calculating its length and finding the last mbuf. 1550 * If the adjustment only affects this mbuf, then just 1551 * adjust and return. Otherwise, rescan and truncate 1552 * after the remaining size. 1553 */ 1554 count = 0; 1555 m = mp; 1556 for (;;) { 1557 count += m->m_len; 1558 if (m->m_next == (struct mbuf *)0) 1559 break; 1560 m = m->m_next; 1561 } 1562 if (m->m_len > len) { 1563 m->m_len -= len; 1564 if (nul > 0) { 1565 cp = mtod(m, caddr_t)+m->m_len-nul; 1566 for (i = 0; i < nul; i++) 1567 *cp++ = '\0'; 1568 } 1569 return; 1570 } 1571 count -= len; 1572 if (count < 0) 1573 count = 0; 1574 /* 1575 * Correct length for chain is "count". 1576 * Find the mbuf with last data, adjust its length, 1577 * and toss data from remaining mbufs on chain. 1578 */ 1579 for (m = mp; m; m = m->m_next) { 1580 if (m->m_len >= count) { 1581 m->m_len = count; 1582 if (nul > 0) { 1583 cp = mtod(m, caddr_t)+m->m_len-nul; 1584 for (i = 0; i < nul; i++) 1585 *cp++ = '\0'; 1586 } 1587 break; 1588 } 1589 count -= m->m_len; 1590 } 1591 for (m = m->m_next;m;m = m->m_next) 1592 m->m_len = 0; 1593 } 1594 1595 /* 1596 * Make these functions instead of macros, so that the kernel text size 1597 * doesn't get too big... 1598 */ 1599 void 1600 nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) 1601 struct nfsrv_descript *nfsd; 1602 int before_ret; 1603 register struct vattr *before_vap; 1604 int after_ret; 1605 struct vattr *after_vap; 1606 struct mbuf **mbp; 1607 char **bposp; 1608 { 1609 register struct mbuf *mb = *mbp, *mb2; 1610 register char *bpos = *bposp; 1611 register u_int32_t *tl; 1612 1613 if (before_ret) { 1614 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1615 *tl = nfs_false; 1616 } else { 1617 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 1618 *tl++ = nfs_true; 1619 txdr_hyper(&(before_vap->va_size), tl); 1620 tl += 2; 1621 txdr_nfsv3time(&(before_vap->va_mtime), tl); 1622 tl += 2; 1623 txdr_nfsv3time(&(before_vap->va_ctime), tl); 1624 } 1625 *bposp = bpos; 1626 *mbp = mb; 1627 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 1628 } 1629 1630 void 1631 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) 1632 struct nfsrv_descript *nfsd; 1633 int after_ret; 1634 struct vattr *after_vap; 1635 struct mbuf **mbp; 1636 char **bposp; 1637 { 1638 register struct mbuf *mb = *mbp, *mb2; 1639 register char *bpos = *bposp; 1640 register u_int32_t *tl; 1641 register struct nfs_fattr *fp; 1642 1643 if (after_ret) { 1644 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED); 1645 *tl = nfs_false; 1646 } else { 1647 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 1648 *tl++ = nfs_true; 1649 fp = (struct nfs_fattr *)tl; 1650 nfsm_srvfattr(nfsd, after_vap, fp); 1651 } 1652 *mbp = mb; 1653 *bposp = bpos; 1654 } 1655 1656 void 1657 nfsm_srvfattr(nfsd, vap, fp) 1658 register struct nfsrv_descript *nfsd; 1659 register struct vattr *vap; 1660 register struct nfs_fattr *fp; 1661 { 1662 1663 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1664 fp->fa_uid = txdr_unsigned(vap->va_uid); 1665 fp->fa_gid = txdr_unsigned(vap->va_gid); 1666 if (nfsd->nd_flag & ND_NFSV3) { 1667 fp->fa_type = vtonfsv3_type(vap->va_type); 1668 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1669 txdr_hyper(&vap->va_size, &fp->fa3_size); 1670 txdr_hyper(&vap->va_bytes, &fp->fa3_used); 1671 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); 1672 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); 1673 fp->fa3_fsid.nfsuquad[0] = 0; 1674 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1675 fp->fa3_fileid.nfsuquad[0] = 0; 1676 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 1677 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1678 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1679 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1680 } else { 1681 fp->fa_type = vtonfsv2_type(vap->va_type); 1682 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1683 fp->fa2_size = txdr_unsigned(vap->va_size); 1684 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1685 if (vap->va_type == VFIFO) 1686 fp->fa2_rdev = 0xffffffff; 1687 else 1688 fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 1689 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1690 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1691 fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1692 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1693 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1694 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1695 } 1696 } 1697 1698 /* 1699 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1700 * - look up fsid in mount list (if not found ret error) 1701 * - get vp and export rights by calling VFS_FHTOVP() 1702 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1703 * - if not lockflag unlock it with VOP_UNLOCK() 1704 */ 1705 int 1706 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag) 1707 fhandle_t *fhp; 1708 int lockflag; 1709 struct vnode **vpp; 1710 struct ucred *cred; 1711 struct nfssvc_sock *slp; 1712 struct mbuf *nam; 1713 int *rdonlyp; 1714 int kerbflag; 1715 { 1716 #ifdef Lite2_integrated 1717 struct proc *p = curproc; /* XXX */ 1718 #endif 1719 register struct mount *mp; 1720 register int i; 1721 struct ucred *credanon; 1722 int error, exflags; 1723 struct sockaddr_in *saddr; 1724 1725 *vpp = (struct vnode *)0; 1726 #ifdef Lite2_integrated 1727 mp = vfs_getvfs(&fhp->fh_fsid); 1728 #else 1729 mp = getvfs(&fhp->fh_fsid); 1730 #endif 1731 if (!mp) 1732 return (ESTALE); 1733 error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); 1734 if (error) 1735 return (error); 1736 1737 if (!(exflags & MNT_EXNORESPORT)) { 1738 saddr = mtod(nam, struct sockaddr_in *); 1739 if (saddr->sin_family == AF_INET && 1740 ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 1741 vput(*vpp); 1742 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1743 } 1744 } 1745 /* 1746 * Check/setup credentials. 1747 */ 1748 if (exflags & MNT_EXKERB) { 1749 if (!kerbflag) { 1750 vput(*vpp); 1751 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1752 } 1753 } else if (kerbflag) { 1754 vput(*vpp); 1755 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1756 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1757 cred->cr_uid = credanon->cr_uid; 1758 cred->cr_gid = credanon->cr_gid; 1759 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1760 cred->cr_groups[i] = credanon->cr_groups[i]; 1761 cred->cr_ngroups = i; 1762 } 1763 if (exflags & MNT_EXRDONLY) 1764 *rdonlyp = 1; 1765 else 1766 *rdonlyp = 0; 1767 if (!lockflag) 1768 #ifdef Lite2_integrated 1769 VOP_UNLOCK(*vpp, 0, p); 1770 #else 1771 VOP_UNLOCK(*vpp); 1772 #endif 1773 return (0); 1774 } 1775 1776 /* 1777 * This function compares two net addresses by family and returns TRUE 1778 * if they are the same host. 1779 * If there is any doubt, return FALSE. 1780 * The AF_INET family is handled as a special case so that address mbufs 1781 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1782 */ 1783 int 1784 netaddr_match(family, haddr, nam) 1785 int family; 1786 union nethostaddr *haddr; 1787 struct mbuf *nam; 1788 { 1789 register struct sockaddr_in *inetaddr; 1790 1791 switch (family) { 1792 case AF_INET: 1793 inetaddr = mtod(nam, struct sockaddr_in *); 1794 if (inetaddr->sin_family == AF_INET && 1795 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 1796 return (1); 1797 break; 1798 #ifdef ISO 1799 case AF_ISO: 1800 { 1801 register struct sockaddr_iso *isoaddr1, *isoaddr2; 1802 1803 isoaddr1 = mtod(nam, struct sockaddr_iso *); 1804 isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 1805 if (isoaddr1->siso_family == AF_ISO && 1806 isoaddr1->siso_nlen > 0 && 1807 isoaddr1->siso_nlen == isoaddr2->siso_nlen && 1808 SAME_ISOADDR(isoaddr1, isoaddr2)) 1809 return (1); 1810 break; 1811 } 1812 #endif /* ISO */ 1813 default: 1814 break; 1815 }; 1816 return (0); 1817 } 1818 1819 static nfsuint64 nfs_nullcookie = {{ 0, 0 }}; 1820 /* 1821 * This function finds the directory cookie that corresponds to the 1822 * logical byte offset given. 1823 */ 1824 nfsuint64 * 1825 nfs_getcookie(np, off, add) 1826 register struct nfsnode *np; 1827 off_t off; 1828 int add; 1829 { 1830 register struct nfsdmap *dp, *dp2; 1831 register int pos; 1832 1833 pos = off / NFS_DIRBLKSIZ; 1834 if (pos == 0) { 1835 #ifdef DIAGNOSTIC 1836 if (add) 1837 panic("nfs getcookie add at 0"); 1838 #endif 1839 return (&nfs_nullcookie); 1840 } 1841 pos--; 1842 dp = np->n_cookies.lh_first; 1843 if (!dp) { 1844 if (add) { 1845 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 1846 M_NFSDIROFF, M_WAITOK); 1847 dp->ndm_eocookie = 0; 1848 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 1849 } else 1850 return ((nfsuint64 *)0); 1851 } 1852 while (pos >= NFSNUMCOOKIES) { 1853 pos -= NFSNUMCOOKIES; 1854 if (dp->ndm_list.le_next) { 1855 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 1856 pos >= dp->ndm_eocookie) 1857 return ((nfsuint64 *)0); 1858 dp = dp->ndm_list.le_next; 1859 } else if (add) { 1860 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 1861 M_NFSDIROFF, M_WAITOK); 1862 dp2->ndm_eocookie = 0; 1863 LIST_INSERT_AFTER(dp, dp2, ndm_list); 1864 dp = dp2; 1865 } else 1866 return ((nfsuint64 *)0); 1867 } 1868 if (pos >= dp->ndm_eocookie) { 1869 if (add) 1870 dp->ndm_eocookie = pos + 1; 1871 else 1872 return ((nfsuint64 *)0); 1873 } 1874 return (&dp->ndm_cookies[pos]); 1875 } 1876 1877 /* 1878 * Invalidate cached directory information, except for the actual directory 1879 * blocks (which are invalidated separately). 1880 * Done mainly to avoid the use of stale offset cookies. 1881 */ 1882 void 1883 nfs_invaldir(vp) 1884 register struct vnode *vp; 1885 { 1886 #ifdef notdef /* XXX */ 1887 register struct nfsnode *np = VTONFS(vp); 1888 1889 #ifdef DIAGNOSTIC 1890 if (vp->v_type != VDIR) 1891 panic("nfs: invaldir not dir"); 1892 #endif 1893 np->n_direofoffset = 0; 1894 np->n_cookieverf.nfsuquad[0] = 0; 1895 np->n_cookieverf.nfsuquad[1] = 0; 1896 if (np->n_cookies.lh_first) 1897 np->n_cookies.lh_first->ndm_eocookie = 0; 1898 #endif 1899 } 1900 1901 /* 1902 * The write verifier has changed (probably due to a server reboot), so all 1903 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 1904 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 1905 * flag. Once done the new write verifier can be set for the mount point. 1906 */ 1907 void 1908 nfs_clearcommit(mp) 1909 struct mount *mp; 1910 { 1911 register struct vnode *vp, *nvp; 1912 register struct buf *bp, *nbp; 1913 int s; 1914 1915 s = splbio(); 1916 loop: 1917 for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { 1918 if (vp->v_mount != mp) /* Paranoia */ 1919 goto loop; 1920 nvp = vp->v_mntvnodes.le_next; 1921 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { 1922 nbp = bp->b_vnbufs.le_next; 1923 if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT)) 1924 == (B_DELWRI | B_NEEDCOMMIT)) 1925 bp->b_flags &= ~B_NEEDCOMMIT; 1926 } 1927 } 1928 splx(s); 1929 } 1930 1931 /* 1932 * Map errnos to NFS error numbers. For Version 3 also filter out error 1933 * numbers not specified for the associated procedure. 1934 */ 1935 int 1936 nfsrv_errmap(nd, err) 1937 struct nfsrv_descript *nd; 1938 register int err; 1939 { 1940 register short *defaulterrp, *errp; 1941 1942 if (nd->nd_flag & ND_NFSV3) { 1943 if (nd->nd_procnum <= NFSPROC_COMMIT) { 1944 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 1945 while (*++errp) { 1946 if (*errp == err) 1947 return (err); 1948 else if (*errp > err) 1949 break; 1950 } 1951 return ((int)*defaulterrp); 1952 } else 1953 return (err & 0xffff); 1954 } 1955 if (err <= ELAST) 1956 return ((int)nfsrv_v2errmap[err - 1]); 1957 return (NFSERR_IO); 1958 } 1959 1960 /* 1961 * Sort the group list in increasing numerical order. 1962 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 1963 * that used to be here.) 1964 */ 1965 void 1966 nfsrvw_sort(list, num) 1967 register gid_t *list; 1968 register int num; 1969 { 1970 register int i, j; 1971 gid_t v; 1972 1973 /* Insertion sort. */ 1974 for (i = 1; i < num; i++) { 1975 v = list[i]; 1976 /* find correct slot for value v, moving others up */ 1977 for (j = i; --j >= 0 && v < list[j];) 1978 list[j + 1] = list[j]; 1979 list[j + 1] = v; 1980 } 1981 } 1982 1983 /* 1984 * copy credentials making sure that the result can be compared with bcmp(). 1985 */ 1986 void 1987 nfsrv_setcred(incred, outcred) 1988 register struct ucred *incred, *outcred; 1989 { 1990 register int i; 1991 1992 bzero((caddr_t)outcred, sizeof (struct ucred)); 1993 outcred->cr_ref = 1; 1994 outcred->cr_uid = incred->cr_uid; 1995 outcred->cr_gid = incred->cr_gid; 1996 outcred->cr_ngroups = incred->cr_ngroups; 1997 for (i = 0; i < incred->cr_ngroups; i++) 1998 outcred->cr_groups[i] = incred->cr_groups[i]; 1999 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 2000 } 2001