1 /* $OpenBSD: nfs_serv.c,v 1.127 2024/08/17 07:02:13 jsg Exp $ */ 2 /* $NetBSD: nfs_serv.c,v 1.34 1997/05/12 23:37:12 fvdl Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Rick Macklem at The University of Guelph. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)nfs_serv.c 8.7 (Berkeley) 5/14/95 36 */ 37 38 /* 39 * nfs version 2 and 3 server calls to vnode ops 40 * - these routines generally have 3 phases 41 * 1 - break down and validate rpc request in mbuf list 42 * 2 - do the vnode ops for the request 43 * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c) 44 * 3 - build the rpc reply in an mbuf list 45 * nb: 46 * - do not mix the phases, since use of the nfsm_?? functions can cause 47 * us to return failures on a bad rpc or similar without doing any 48 * vrele() or vput()'s 49 * - the nfsm_reply() function generates an nfs rpc reply with the nfs 50 * error number iff error != 0 whereas returning an error from the 51 * server function implies a fatal error such as a badly constructed rpc 52 * request that should be dropped without a reply. 53 * For Version 3, we do not return after nfsm_reply() for the error case, 54 * since most version 3 rpcs return more than the status for error cases. 55 */ 56 57 #include <sys/param.h> 58 #include <sys/systm.h> 59 #include <sys/proc.h> 60 #include <sys/namei.h> 61 #include <sys/vnode.h> 62 #include <sys/lock.h> 63 #include <sys/mount.h> 64 #include <sys/socket.h> 65 #include <sys/socketvar.h> 66 #include <sys/mbuf.h> 67 #include <sys/dirent.h> 68 #include <sys/stat.h> 69 #include <sys/pool.h> 70 #include <sys/unistd.h> 71 72 #include <ufs/ufs/dir.h> 73 74 #include <nfs/nfsproto.h> 75 #include <nfs/nfs.h> 76 #include <nfs/xdr_subs.h> 77 #include <nfs/nfs_var.h> 78 #include <nfs/nfsm_subs.h> 79 80 /* Global vars */ 81 extern u_int32_t nfs_xdrneg1; 82 extern u_int32_t nfs_false, nfs_true; 83 extern const enum vtype nv3tov_type[8]; 84 extern struct nfsstats nfsstats; 85 86 int nfsrv_access(struct vnode *, int, struct ucred *, int, struct proc *, int); 87 88 static inline int 89 nfsm_reply(struct nfsm_info *infop, struct nfsrv_descript *nfsd, 90 struct nfssvc_sock *slp, struct mbuf **mrq, int error, int statuslen) 91 { 92 nfsd->nd_repstat = error; 93 if (error && !infop->nmi_v3) 94 statuslen = 0; 95 (void)nfs_rephead(statuslen, nfsd, slp, error, 96 &infop->nmi_mreq, &infop->nmi_mb); 97 if (infop->nmi_mrep != NULL) { 98 m_freem(infop->nmi_mrep); 99 infop->nmi_mrep = NULL; 100 } 101 *mrq = infop->nmi_mreq; 102 if (error && (!infop->nmi_v3 || error == EBADRPC)) 103 return error; 104 return 0; 105 } 106 107 static inline int 108 nfsm_srvmtofh1(struct nfsm_info *infop, struct nfsrv_descript *nfsd, 109 struct nfssvc_sock *slp, struct mbuf **mrq) 110 { 111 if (infop->nmi_v3) { 112 uint32_t *tl = (uint32_t *)nfsm_dissect(infop, NFSX_UNSIGNED); 113 if (tl == NULL) 114 return 0; /* *infop->nmi_errorp set */ 115 if (fxdr_unsigned(int, *tl) != NFSX_V3FH) { 116 *infop->nmi_errorp = EBADRPC; 117 return nfsm_reply(infop, nfsd, slp, mrq, 118 *infop->nmi_errorp, 0); 119 } 120 } 121 return 0; 122 } 123 124 static inline int 125 nfsm_srvmtofh2(struct nfsm_info *infop, fhandle_t *fhp) 126 { 127 uint32_t *tl = (uint32_t *)nfsm_dissect(infop, NFSX_V3FH); 128 if (tl == NULL) 129 return 1; 130 bcopy(tl, fhp, NFSX_V3FH); 131 if (infop->nmi_v3 == 0) { 132 if (nfsm_adv(infop, NFSX_V2FH - NFSX_V3FH) != 0) 133 return 1; 134 } 135 return 0; 136 } 137 138 /* 139 * nfs v3 access service 140 */ 141 int 142 nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 143 struct proc *procp, struct mbuf **mrq) 144 { 145 struct mbuf *nam = nfsd->nd_nam; 146 struct nfsm_info info; 147 struct ucred *cred = &nfsd->nd_cr; 148 struct vnode *vp; 149 nfsfh_t nfh; 150 fhandle_t *fhp; 151 u_int32_t *tl; 152 int error = 0, rdonly, getret; 153 struct vattr va; 154 u_long testmode, nfsmode; 155 156 info.nmi_mreq = NULL; 157 info.nmi_mrep = nfsd->nd_mrep; 158 info.nmi_md = nfsd->nd_md; 159 info.nmi_dpos = nfsd->nd_dpos; 160 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 161 info.nmi_errorp = &error; 162 163 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 164 return 0; 165 else if (error != 0) 166 goto nfsmout; 167 fhp = &nfh.fh_generic; 168 if (nfsm_srvmtofh2(&info, fhp) != 0) 169 goto nfsmout; 170 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 171 if (tl == NULL) 172 goto nfsmout; 173 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 174 if (error) { 175 if (nfsm_reply(&info, nfsd, slp, mrq, error, 176 NFSX_UNSIGNED) != 0) 177 return 0; 178 nfsm_srvpostop_attr(nfsd, 1, NULL, &info); 179 error = 0; 180 goto nfsmout; 181 } 182 nfsmode = fxdr_unsigned(u_int32_t, *tl); 183 if ((nfsmode & NFSV3ACCESS_READ) && 184 nfsrv_access(vp, VREAD, cred, rdonly, procp, 0)) 185 nfsmode &= ~NFSV3ACCESS_READ; 186 if (vp->v_type == VDIR) 187 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | 188 NFSV3ACCESS_DELETE); 189 else 190 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); 191 if ((nfsmode & testmode) && 192 nfsrv_access(vp, VWRITE, cred, rdonly, procp, 0)) 193 nfsmode &= ~testmode; 194 if (vp->v_type == VDIR) 195 testmode = NFSV3ACCESS_LOOKUP; 196 else 197 testmode = NFSV3ACCESS_EXECUTE; 198 if ((nfsmode & testmode) && 199 nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0)) 200 nfsmode &= ~testmode; 201 getret = VOP_GETATTR(vp, &va, cred, procp); 202 vput(vp); 203 if (nfsm_reply(&info, nfsd, slp, mrq, error, 204 NFSX_POSTOPATTR(1) + NFSX_UNSIGNED) != 0) 205 return 0; 206 nfsm_srvpostop_attr(nfsd, getret, &va, &info); 207 tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED); 208 *tl = txdr_unsigned(nfsmode); 209 nfsmout: 210 return(error); 211 } 212 213 /* 214 * nfs getattr service 215 */ 216 int 217 nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 218 struct proc *procp, struct mbuf **mrq) 219 { 220 struct mbuf *nam = nfsd->nd_nam; 221 struct nfsm_info info; 222 struct ucred *cred = &nfsd->nd_cr; 223 struct nfs_fattr *fp; 224 struct vattr va; 225 struct vnode *vp; 226 nfsfh_t nfh; 227 fhandle_t *fhp; 228 int error = 0, rdonly; 229 230 info.nmi_mreq = NULL; 231 info.nmi_mrep = nfsd->nd_mrep; 232 info.nmi_md = nfsd->nd_md; 233 info.nmi_dpos = nfsd->nd_dpos; 234 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 235 info.nmi_errorp = &error; 236 237 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 238 return 0; 239 else if (error != 0) 240 goto nfsmout; 241 fhp = &nfh.fh_generic; 242 if (nfsm_srvmtofh2(&info, fhp) != 0) 243 goto nfsmout; 244 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 245 if (error) { 246 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 247 return 0; 248 error = 0; 249 goto nfsmout; 250 } 251 error = VOP_GETATTR(vp, &va, cred, procp); 252 vput(vp); 253 if (nfsm_reply(&info, nfsd, slp, mrq, error, 254 NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)) != 0) 255 return 0; 256 if (error) { 257 error = 0; 258 goto nfsmout; 259 } 260 fp = nfsm_build(&info.nmi_mb, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); 261 nfsm_srvfattr(nfsd, &va, fp); 262 nfsmout: 263 return(error); 264 } 265 266 /* 267 * nfs setattr service 268 */ 269 int 270 nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 271 struct proc *procp, struct mbuf **mrq) 272 { 273 struct mbuf *nam = nfsd->nd_nam; 274 struct nfsm_info info; 275 struct ucred *cred = &nfsd->nd_cr; 276 struct vattr va, preat; 277 struct nfsv2_sattr *sp; 278 struct nfs_fattr *fp; 279 struct vnode *vp; 280 nfsfh_t nfh; 281 fhandle_t *fhp; 282 u_int32_t *tl; 283 int error = 0, rdonly, preat_ret = 1, postat_ret = 1; 284 int gcheck = 0; 285 struct timespec guard; 286 287 info.nmi_mreq = NULL; 288 info.nmi_mrep = nfsd->nd_mrep; 289 info.nmi_md = nfsd->nd_md; 290 info.nmi_dpos = nfsd->nd_dpos; 291 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 292 info.nmi_errorp = &error; 293 294 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 295 return 0; 296 else if (error != 0) 297 goto nfsmout; 298 fhp = &nfh.fh_generic; 299 if (nfsm_srvmtofh2(&info, fhp) != 0) 300 goto nfsmout; 301 VATTR_NULL(&va); 302 if (info.nmi_v3) { 303 va.va_vaflags |= VA_UTIMES_NULL; 304 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, &info.nmi_dpos); 305 if (error) 306 goto nfsmout; 307 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 308 if (tl == NULL) 309 goto nfsmout; 310 gcheck = fxdr_unsigned(int, *tl); 311 if (gcheck) { 312 tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED); 313 if (tl == NULL) 314 goto nfsmout; 315 fxdr_nfsv3time(tl, &guard); 316 } 317 } else { 318 sp = (struct nfsv2_sattr *)nfsm_dissect(&info, NFSX_V2SATTR); 319 if (sp == NULL) 320 goto nfsmout; 321 /* 322 * Nah nah nah nah na nah 323 * There is a bug in the Sun client that puts 0xffff in the mode 324 * field of sattr when it should put in 0xffffffff. The u_short 325 * doesn't sign extend. 326 * --> check the low order 2 bytes for 0xffff 327 */ 328 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff) 329 va.va_mode = nfstov_mode(sp->sa_mode); 330 if (sp->sa_uid != nfs_xdrneg1) 331 va.va_uid = fxdr_unsigned(uid_t, sp->sa_uid); 332 if (sp->sa_gid != nfs_xdrneg1) 333 va.va_gid = fxdr_unsigned(gid_t, sp->sa_gid); 334 if (sp->sa_size != nfs_xdrneg1) 335 va.va_size = fxdr_unsigned(u_quad_t, sp->sa_size); 336 if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) { 337 #ifdef notyet 338 fxdr_nfsv2time(&sp->sa_atime, &va.va_atime); 339 #else 340 va.va_atime.tv_sec = 341 fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec); 342 va.va_atime.tv_nsec = 0; 343 #endif 344 } 345 if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1) 346 fxdr_nfsv2time(&sp->sa_mtime, &va.va_mtime); 347 348 } 349 350 /* 351 * Now that we have all the fields, lets do it. 352 */ 353 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 354 if (error) { 355 if (nfsm_reply(&info, nfsd, slp, mrq, error, 356 2 * NFSX_UNSIGNED) != 0) 357 return 0; 358 nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va, &info); 359 error = 0; 360 goto nfsmout; 361 } 362 if (info.nmi_v3) { 363 error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp); 364 if (!error && gcheck && 365 (preat.va_ctime.tv_sec != guard.tv_sec || 366 preat.va_ctime.tv_nsec != guard.tv_nsec)) 367 error = NFSERR_NOT_SYNC; 368 if (error) { 369 vput(vp); 370 if (nfsm_reply(&info, nfsd, slp, mrq, error, 371 NFSX_WCCDATA(info.nmi_v3)) != 0) 372 return 0; 373 nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va, 374 &info); 375 error = 0; 376 goto nfsmout; 377 } 378 } 379 380 /* 381 * If the size is being changed write access is required, otherwise 382 * just check for a read only file system. 383 */ 384 if (va.va_size == ((u_quad_t)((quad_t) -1))) { 385 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 386 error = EROFS; 387 goto out; 388 } 389 } else { 390 if (vp->v_type == VDIR) { 391 error = EISDIR; 392 goto out; 393 } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly, 394 procp, 1)) != 0) 395 goto out; 396 } 397 error = VOP_SETATTR(vp, &va, cred, procp); 398 postat_ret = VOP_GETATTR(vp, &va, cred, procp); 399 if (!error) 400 error = postat_ret; 401 out: 402 vput(vp); 403 if (nfsm_reply(&info, nfsd, slp, mrq, error, 404 NFSX_WCCORFATTR(info.nmi_v3)) != 0) 405 return 0; 406 if (info.nmi_v3) { 407 nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va, 408 &info); 409 error = 0; 410 goto nfsmout; 411 } else { 412 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 413 nfsm_srvfattr(nfsd, &va, fp); 414 } 415 nfsmout: 416 return(error); 417 } 418 419 static inline int 420 nfsm_srvnamesiz(struct nfsm_info *infop, int *lenp) 421 { 422 int len; 423 uint32_t *tl = (uint32_t *)nfsm_dissect(infop, NFSX_UNSIGNED); 424 if (tl == NULL) 425 return 1; 426 len = fxdr_unsigned(int32_t, *tl); 427 if (len > NFS_MAXNAMLEN) 428 *infop->nmi_errorp = NFSERR_NAMETOL; 429 else if (len <= 0) 430 *infop->nmi_errorp = EBADRPC; 431 else { 432 *infop->nmi_errorp = 0; 433 *lenp = len; 434 } 435 return 0; 436 } 437 438 /* 439 * nfs lookup rpc 440 */ 441 int 442 nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 443 struct proc *procp, struct mbuf **mrq) 444 { 445 struct mbuf *nam = nfsd->nd_nam; 446 struct ucred *cred = &nfsd->nd_cr; 447 struct nfs_fattr *fp; 448 struct nameidata nd; 449 struct vnode *vp, *dirp; 450 struct nfsm_info info; 451 nfsfh_t nfh; 452 fhandle_t *fhp; 453 int error = 0, len, dirattr_ret = 1; 454 int v3 = (nfsd->nd_flag & ND_NFSV3); 455 struct vattr va, dirattr; 456 457 info.nmi_mrep = nfsd->nd_mrep; 458 info.nmi_mreq = NULL; 459 info.nmi_md = nfsd->nd_md; 460 info.nmi_dpos = nfsd->nd_dpos; 461 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 462 info.nmi_errorp = &error; 463 464 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 465 return 0; 466 else if (error != 0) 467 goto nfsmout; 468 fhp = &nfh.fh_generic; 469 if (nfsm_srvmtofh2(&info, fhp) != 0) 470 goto nfsmout; 471 if (nfsm_srvnamesiz(&info, &len) != 0) 472 goto nfsmout; 473 if (error) { 474 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 475 return 0; 476 } 477 478 NDINIT(&nd, LOOKUP, LOCKLEAF | SAVESTART, UIO_SYSSPACE, NULL, procp); 479 nd.ni_cnd.cn_cred = cred; 480 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp); 481 if (dirp) { 482 if (info.nmi_v3) 483 dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred, 484 procp); 485 vrele(dirp); 486 } 487 if (error) { 488 if (nfsm_reply(&info, nfsd, slp, mrq, error, 489 NFSX_POSTOPATTR(info.nmi_v3)) != 0) 490 return 0; 491 nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info); 492 return (0); 493 } 494 vrele(nd.ni_startdir); 495 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 496 vp = nd.ni_vp; 497 memset(fhp, 0, sizeof(nfh)); 498 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 499 error = VFS_VPTOFH(vp, &fhp->fh_fid); 500 if (!error) 501 error = VOP_GETATTR(vp, &va, cred, procp); 502 vput(vp); 503 if (nfsm_reply(&info, nfsd, slp, mrq, error, 504 NFSX_SRVFH(info.nmi_v3) + NFSX_POSTOPORFATTR(info.nmi_v3) + 505 NFSX_POSTOPATTR(info.nmi_v3)) != 0) 506 return 0; 507 if (error) { 508 nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info); 509 error = 0; 510 goto nfsmout; 511 } 512 nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3); 513 if (v3) { 514 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 515 nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info); 516 } else { 517 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 518 nfsm_srvfattr(nfsd, &va, fp); 519 } 520 nfsmout: 521 return(error); 522 } 523 524 /* 525 * nfs readlink service 526 */ 527 int 528 nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 529 struct proc *procp, struct mbuf **mrq) 530 { 531 struct mbuf *nam = nfsd->nd_nam; 532 struct ucred *cred = &nfsd->nd_cr; 533 struct iovec iov; 534 struct mbuf *mp = NULL; 535 struct nfsm_info info; 536 u_int32_t *tl; 537 int error = 0, rdonly, tlen, len = 0, getret; 538 struct vnode *vp; 539 struct vattr attr; 540 nfsfh_t nfh; 541 fhandle_t *fhp; 542 struct uio uio; 543 544 info.nmi_mreq = NULL; 545 info.nmi_mrep = nfsd->nd_mrep; 546 info.nmi_md = nfsd->nd_md; 547 info.nmi_dpos = nfsd->nd_dpos; 548 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 549 info.nmi_errorp = &error; 550 551 memset(&uio, 0, sizeof(uio)); 552 553 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 554 return 0; 555 else if (error != 0) 556 goto nfsmout; 557 fhp = &nfh.fh_generic; 558 if (nfsm_srvmtofh2(&info, fhp) != 0) 559 goto nfsmout; 560 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 561 if (error) { 562 if (nfsm_reply(&info, nfsd, slp, mrq, error, 563 2 * NFSX_UNSIGNED) != 0) 564 return 0; 565 nfsm_srvpostop_attr(nfsd, 1, NULL, &info); 566 error = 0; 567 goto nfsmout; 568 } 569 if (vp->v_type != VLNK) { 570 if (info.nmi_v3) 571 error = EINVAL; 572 else 573 error = ENXIO; 574 goto out; 575 } 576 577 MGET(mp, M_WAIT, MT_DATA); 578 MCLGET(mp, M_WAIT); /* MLEN < NFS_MAXPATHLEN < MCLBYTES */ 579 mp->m_len = NFS_MAXPATHLEN; 580 len = NFS_MAXPATHLEN; 581 iov.iov_base = mtod(mp, caddr_t); 582 iov.iov_len = mp->m_len; 583 584 uio.uio_iov = &iov; 585 uio.uio_iovcnt = 1; 586 uio.uio_offset = 0; 587 uio.uio_resid = NFS_MAXPATHLEN; 588 uio.uio_rw = UIO_READ; 589 uio.uio_segflg = UIO_SYSSPACE; 590 uio.uio_procp = NULL; 591 592 error = VOP_READLINK(vp, &uio, cred); 593 out: 594 getret = VOP_GETATTR(vp, &attr, cred, procp); 595 vput(vp); 596 if (error) 597 m_freem(mp); 598 if (nfsm_reply(&info, nfsd, slp, mrq, error, 599 NFSX_POSTOPATTR(info.nmi_v3) + NFSX_UNSIGNED) != 0) 600 return 0; 601 if (info.nmi_v3) { 602 nfsm_srvpostop_attr(nfsd, getret, &attr, &info); 603 if (error) { 604 error = 0; 605 goto nfsmout; 606 } 607 } 608 if (uio.uio_resid > 0) { 609 len -= uio.uio_resid; 610 tlen = nfsm_rndup(len); 611 nfsm_adj(mp, NFS_MAXPATHLEN-tlen, tlen-len); 612 } 613 tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED); 614 *tl = txdr_unsigned(len); 615 info.nmi_mb->m_next = mp; 616 617 nfsmout: 618 return (error); 619 } 620 621 /* 622 * nfs read service 623 */ 624 int 625 nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 626 struct proc *procp, struct mbuf **mrq) 627 { 628 struct mbuf *nam = nfsd->nd_nam; 629 struct ucred *cred = &nfsd->nd_cr; 630 struct mbuf *m; 631 struct nfs_fattr *fp; 632 struct nfsm_info info; 633 u_int32_t *tl; 634 int i, reqlen; 635 int error = 0, rdonly, cnt, len, left, siz, tlen, getret = 1; 636 struct mbuf *m2; 637 struct vnode *vp; 638 nfsfh_t nfh; 639 fhandle_t *fhp; 640 struct uio io, *uiop = &io; 641 struct vattr va; 642 off_t off; 643 644 info.nmi_mreq = NULL; 645 info.nmi_mrep = nfsd->nd_mrep; 646 info.nmi_md = nfsd->nd_md; 647 info.nmi_dpos = nfsd->nd_dpos; 648 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 649 info.nmi_errorp = &error; 650 651 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 652 return 0; 653 else if (error != 0) 654 goto nfsmout; 655 fhp = &nfh.fh_generic; 656 if (nfsm_srvmtofh2(&info, fhp) != 0) 657 goto nfsmout; 658 if (info.nmi_v3) { 659 tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED); 660 if (tl == NULL) 661 goto nfsmout; 662 off = fxdr_hyper(tl); 663 } else { 664 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 665 if (tl == NULL) 666 goto nfsmout; 667 off = (off_t)fxdr_unsigned(u_int32_t, *tl); 668 } 669 670 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 671 if (tl == NULL) 672 goto nfsmout; 673 reqlen = fxdr_unsigned(int32_t, *tl); 674 if (reqlen > (NFS_SRVMAXDATA(nfsd)) || reqlen <= 0) { 675 error = EBADRPC; 676 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 677 return 0; 678 } 679 680 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 681 if (error) 682 goto bad; 683 684 if (vp->v_type != VREG) { 685 if (info.nmi_v3) 686 error = EINVAL; 687 else 688 error = (vp->v_type == VDIR) ? EISDIR : EACCES; 689 } 690 if (!error) { 691 if ((error = nfsrv_access(vp, VREAD, cred, rdonly, procp, 1)) != 0) 692 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 1); 693 } 694 getret = VOP_GETATTR(vp, &va, cred, procp); 695 if (!error) 696 error = getret; 697 if (error) 698 goto vbad; 699 700 if (off >= va.va_size) 701 cnt = 0; 702 else if ((off + reqlen) > va.va_size) 703 cnt = va.va_size - off; 704 else 705 cnt = reqlen; 706 if (nfsm_reply(&info, nfsd, slp, mrq, error, 707 NFSX_POSTOPORFATTR(info.nmi_v3) + 708 3 * NFSX_UNSIGNED+nfsm_rndup(cnt)) != 0) 709 return 0; 710 if (info.nmi_v3) { 711 tl = nfsm_build(&info.nmi_mb, NFSX_V3FATTR + 4 * NFSX_UNSIGNED); 712 *tl++ = nfs_true; 713 fp = (struct nfs_fattr *)tl; 714 tl += (NFSX_V3FATTR / sizeof (u_int32_t)); 715 } else { 716 tl = nfsm_build(&info.nmi_mb, NFSX_V2FATTR + NFSX_UNSIGNED); 717 fp = (struct nfs_fattr *)tl; 718 tl += (NFSX_V2FATTR / sizeof (u_int32_t)); 719 } 720 len = left = nfsm_rndup (cnt); 721 if (cnt > 0) { 722 struct iovec *iv, *iv2; 723 size_t ivlen; 724 /* 725 * Generate the mbuf list with the uio_iov ref. to it. 726 */ 727 i = 0; 728 m = m2 = info.nmi_mb; 729 while (left > 0) { 730 siz = min(m_trailingspace(m), left); 731 if (siz > 0) { 732 left -= siz; 733 i++; 734 } 735 if (left > 0) { 736 MGET(m, M_WAIT, MT_DATA); 737 if (left >= MINCLSIZE) 738 MCLGET(m, M_WAIT); 739 m->m_len = 0; 740 m2->m_next = m; 741 m2 = m; 742 } 743 } 744 iv = mallocarray(i, sizeof(*iv), M_TEMP, M_WAITOK); 745 ivlen = i * sizeof(*iv); 746 uiop->uio_iov = iv2 = iv; 747 m = info.nmi_mb; 748 left = len; 749 i = 0; 750 while (left > 0) { 751 if (m == NULL) 752 panic("nfsrv_read iov"); 753 siz = min(m_trailingspace(m), left); 754 if (siz > 0) { 755 iv->iov_base = mtod(m, caddr_t) + m->m_len; 756 iv->iov_len = siz; 757 m->m_len += siz; 758 left -= siz; 759 iv++; 760 i++; 761 } 762 m = m->m_next; 763 } 764 uiop->uio_iovcnt = i; 765 uiop->uio_offset = off; 766 uiop->uio_resid = len; 767 uiop->uio_rw = UIO_READ; 768 uiop->uio_segflg = UIO_SYSSPACE; 769 error = VOP_READ(vp, uiop, IO_NODELOCKED, cred); 770 off = uiop->uio_offset; 771 free(iv2, M_TEMP, ivlen); 772 if (error || (getret = VOP_GETATTR(vp, &va, cred, procp)) != 0){ 773 if (!error) 774 error = getret; 775 m_freem(info.nmi_mreq); 776 goto vbad; 777 } 778 } else 779 uiop->uio_resid = 0; 780 vput(vp); 781 nfsm_srvfattr(nfsd, &va, fp); 782 tlen = len - uiop->uio_resid; 783 cnt = cnt < tlen ? cnt : tlen; 784 tlen = nfsm_rndup (cnt); 785 if (len != tlen || tlen != cnt) 786 nfsm_adj(info.nmi_mb, len - tlen, tlen - cnt); 787 if (info.nmi_v3) { 788 *tl++ = txdr_unsigned(cnt); 789 if (len < reqlen) 790 *tl++ = nfs_true; 791 else 792 *tl++ = nfs_false; 793 } 794 *tl = txdr_unsigned(cnt); 795 nfsmout: 796 return(error); 797 798 vbad: 799 vput(vp); 800 bad: 801 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 802 return 0; 803 nfsm_srvpostop_attr(nfsd, getret, &va, &info); 804 return (0); 805 } 806 807 /* 808 * nfs write service 809 */ 810 int 811 nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 812 struct proc *procp, struct mbuf **mrq) 813 { 814 struct mbuf *nam = nfsd->nd_nam; 815 struct ucred *cred = &nfsd->nd_cr; 816 struct nfsm_info info; 817 int i, cnt; 818 struct mbuf *mp; 819 struct nfs_fattr *fp; 820 struct timeval boottime; 821 struct vattr va, forat; 822 u_int32_t *tl; 823 int error = 0, rdonly, len, forat_ret = 1; 824 int ioflags, aftat_ret = 1, retlen, zeroing, adjust; 825 int stable = NFSV3WRITE_FILESYNC; 826 struct vnode *vp; 827 nfsfh_t nfh; 828 fhandle_t *fhp; 829 struct uio io, *uiop = &io; 830 off_t off; 831 832 info.nmi_mreq = NULL; 833 info.nmi_mrep = nfsd->nd_mrep; 834 info.nmi_md = nfsd->nd_md; 835 info.nmi_dpos = nfsd->nd_dpos; 836 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 837 info.nmi_errorp = &error; 838 839 if (info.nmi_mrep == NULL) { 840 *mrq = NULL; 841 return (0); 842 } 843 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 844 return 0; 845 else if (error != 0) 846 goto nfsmout; 847 fhp = &nfh.fh_generic; 848 if (nfsm_srvmtofh2(&info, fhp) != 0) 849 goto nfsmout; 850 if (info.nmi_v3) { 851 tl = (uint32_t *)nfsm_dissect(&info, 5 * NFSX_UNSIGNED); 852 if (tl == NULL) 853 goto nfsmout; 854 off = fxdr_hyper(tl); 855 tl += 3; 856 stable = fxdr_unsigned(int, *tl++); 857 } else { 858 tl = (uint32_t *)nfsm_dissect(&info, 4 * NFSX_UNSIGNED); 859 if (tl == NULL) 860 goto nfsmout; 861 off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 862 tl += 2; 863 } 864 retlen = len = fxdr_unsigned(int32_t, *tl); 865 cnt = i = 0; 866 867 /* 868 * For NFS Version 2, it is not obvious what a write of zero length 869 * should do, but I might as well be consistent with Version 3, 870 * which is to return ok so long as there are no permission problems. 871 */ 872 if (len > 0) { 873 zeroing = 1; 874 mp = info.nmi_mrep; 875 while (mp) { 876 if (mp == info.nmi_md) { 877 zeroing = 0; 878 adjust = info.nmi_dpos - mtod(mp, caddr_t); 879 mp->m_len -= adjust; 880 if (mp->m_len > 0 && adjust > 0) 881 mp->m_data += adjust; 882 } 883 if (zeroing) 884 mp->m_len = 0; 885 else if (mp->m_len > 0) { 886 i += mp->m_len; 887 if (i > len) { 888 mp->m_len -= (i - len); 889 zeroing = 1; 890 } 891 if (mp->m_len > 0) 892 cnt++; 893 } 894 mp = mp->m_next; 895 } 896 } 897 if (len > NFS_MAXDATA || len < 0 || i < len) { 898 error = EIO; 899 goto bad; 900 } 901 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 902 if (error) 903 goto bad; 904 if (info.nmi_v3) 905 forat_ret = VOP_GETATTR(vp, &forat, cred, procp); 906 if (vp->v_type != VREG) { 907 if (info.nmi_v3) 908 error = EINVAL; 909 else 910 error = (vp->v_type == VDIR) ? EISDIR : EACCES; 911 goto vbad; 912 } 913 error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1); 914 if (error) 915 goto vbad; 916 917 if (len > 0) { 918 struct iovec *iv, *ivp; 919 size_t ivlen; 920 921 ivp = mallocarray(cnt, sizeof(*ivp), M_TEMP, M_WAITOK); 922 ivlen = cnt * sizeof(*ivp); 923 uiop->uio_iov = iv = ivp; 924 uiop->uio_iovcnt = cnt; 925 mp = info.nmi_mrep; 926 while (mp) { 927 if (mp->m_len > 0) { 928 ivp->iov_base = mtod(mp, caddr_t); 929 ivp->iov_len = mp->m_len; 930 ivp++; 931 } 932 mp = mp->m_next; 933 } 934 935 if (stable == NFSV3WRITE_UNSTABLE) 936 ioflags = IO_NODELOCKED; 937 else if (stable == NFSV3WRITE_DATASYNC) 938 ioflags = (IO_SYNC | IO_NODELOCKED); 939 else 940 ioflags = (IO_SYNC | IO_NODELOCKED); 941 uiop->uio_resid = len; 942 uiop->uio_rw = UIO_WRITE; 943 uiop->uio_segflg = UIO_SYSSPACE; 944 uiop->uio_procp = NULL; 945 uiop->uio_offset = off; 946 error = VOP_WRITE(vp, uiop, ioflags, cred); 947 nfsstats.srvvop_writes++; 948 free(iv, M_TEMP, ivlen); 949 } 950 aftat_ret = VOP_GETATTR(vp, &va, cred, procp); 951 vput(vp); 952 if (!error) 953 error = aftat_ret; 954 if (nfsm_reply(&info, nfsd, slp, mrq, error, 955 NFSX_PREOPATTR(info.nmi_v3) + NFSX_POSTOPORFATTR(info.nmi_v3) + 956 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(info.nmi_v3)) != 0) 957 return 0; 958 if (info.nmi_v3) { 959 nfsm_srvwcc(nfsd, forat_ret, &forat, aftat_ret, &va, &info); 960 if (error) { 961 error = 0; 962 goto nfsmout; 963 } 964 tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED); 965 *tl++ = txdr_unsigned(retlen); 966 if (stable == NFSV3WRITE_UNSTABLE) 967 *tl++ = txdr_unsigned(stable); 968 else 969 *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC); 970 /* 971 * Actually, there is no need to txdr these fields, 972 * but it may make the values more human readable, 973 * for debugging purposes. 974 */ 975 microboottime(&boottime); 976 *tl++ = txdr_unsigned(boottime.tv_sec); 977 *tl = txdr_unsigned(boottime.tv_usec); 978 } else { 979 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 980 nfsm_srvfattr(nfsd, &va, fp); 981 } 982 nfsmout: 983 return(error); 984 985 vbad: 986 vput(vp); 987 bad: 988 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 989 return 0; 990 nfsm_srvwcc(nfsd, forat_ret, &forat, aftat_ret, &va, &info); 991 return (0); 992 } 993 994 static inline void 995 nfsm_srvpostop_fh(struct nfsm_info *infop, fhandle_t *fhp) 996 { 997 uint32_t *tl; 998 999 tl = nfsm_build(&infop->nmi_mb, 2 * NFSX_UNSIGNED + NFSX_V3FH); 1000 *tl++ = nfs_true; 1001 *tl++ = txdr_unsigned(NFSX_V3FH); 1002 bcopy(fhp, tl, NFSX_V3FH); 1003 } 1004 1005 /* 1006 * nfs create service 1007 * now does a truncate to 0 length via. setattr if it already exists 1008 */ 1009 int 1010 nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1011 struct proc *procp, struct mbuf **mrq) 1012 { 1013 struct mbuf *nam = nfsd->nd_nam; 1014 struct ucred *cred = &nfsd->nd_cr; 1015 struct nfs_fattr *fp; 1016 struct vattr va, dirfor, diraft; 1017 struct nfsv2_sattr *sp; 1018 struct nfsm_info info; 1019 u_int32_t *tl; 1020 struct nameidata nd; 1021 caddr_t cp; 1022 int error = 0, len, tsize, dirfor_ret = 1, diraft_ret = 1; 1023 dev_t rdev = 0; 1024 int how, exclusive_flag = 0; 1025 struct vnode *vp = NULL, *dirp = NULL; 1026 nfsfh_t nfh; 1027 fhandle_t *fhp; 1028 u_quad_t tempsize; 1029 u_char cverf[NFSX_V3CREATEVERF]; 1030 1031 info.nmi_mreq = NULL; 1032 info.nmi_mrep = nfsd->nd_mrep; 1033 info.nmi_md = nfsd->nd_md; 1034 info.nmi_dpos = nfsd->nd_dpos; 1035 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1036 info.nmi_errorp = &error; 1037 1038 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 1039 return 0; 1040 else if (error != 0) 1041 return error; 1042 fhp = &nfh.fh_generic; 1043 if (nfsm_srvmtofh2(&info, fhp) != 0) 1044 return error; 1045 if (nfsm_srvnamesiz(&info, &len) != 0) 1046 return error; 1047 if (error) { 1048 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 1049 return 0; 1050 } 1051 1052 NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF | SAVESTART, UIO_SYSSPACE, 1053 NULL, procp); 1054 nd.ni_cnd.cn_cred = cred; 1055 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 1056 &info.nmi_dpos, &dirp, procp); 1057 if (dirp) { 1058 if (info.nmi_v3) 1059 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 1060 else { 1061 vrele(dirp); 1062 dirp = NULL; 1063 } 1064 } 1065 if (error) { 1066 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1067 NFSX_WCCDATA(info.nmi_v3)) != 0) 1068 return 0; 1069 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1070 &info); 1071 if (dirp) 1072 vrele(dirp); 1073 return (0); 1074 } 1075 1076 VATTR_NULL(&va); 1077 if (info.nmi_v3) { 1078 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 1079 if (tl == NULL) 1080 goto nfsmout; 1081 how = fxdr_unsigned(int, *tl); 1082 switch (how) { 1083 case NFSV3CREATE_GUARDED: 1084 if (nd.ni_vp) { 1085 error = EEXIST; 1086 break; 1087 } 1088 case NFSV3CREATE_UNCHECKED: 1089 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, 1090 &info.nmi_dpos); 1091 if (error) 1092 goto nfsmout; 1093 break; 1094 case NFSV3CREATE_EXCLUSIVE: 1095 cp = (caddr_t)nfsm_dissect(&info, NFSX_V3CREATEVERF); 1096 if (cp == NULL) 1097 goto nfsmout; 1098 bcopy(cp, cverf, NFSX_V3CREATEVERF); 1099 exclusive_flag = 1; 1100 if (nd.ni_vp == NULL) 1101 va.va_mode = 0; 1102 break; 1103 }; 1104 va.va_type = VREG; 1105 } else { 1106 sp = (struct nfsv2_sattr *)nfsm_dissect(&info, NFSX_V2SATTR); 1107 if (sp == NULL) 1108 goto nfsmout; 1109 va.va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 1110 if (va.va_type == VNON) 1111 va.va_type = VREG; 1112 va.va_mode = nfstov_mode(sp->sa_mode); 1113 switch (va.va_type) { 1114 case VREG: 1115 tsize = fxdr_unsigned(int32_t, sp->sa_size); 1116 if (tsize != -1) 1117 va.va_size = (u_quad_t)tsize; 1118 break; 1119 case VCHR: 1120 case VBLK: 1121 case VFIFO: 1122 rdev = (dev_t)fxdr_unsigned(int32_t, sp->sa_size); 1123 break; 1124 default: 1125 break; 1126 }; 1127 } 1128 1129 /* 1130 * Iff doesn't exist, create it 1131 * otherwise just truncate to 0 length 1132 * should I set the mode too ?? 1133 */ 1134 if (nd.ni_vp == NULL) { 1135 if (va.va_type == VREG || va.va_type == VSOCK) { 1136 vrele(nd.ni_startdir); 1137 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, 1138 &va); 1139 vput(nd.ni_dvp); 1140 if (!error) { 1141 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1142 if (exclusive_flag) { 1143 exclusive_flag = 0; 1144 VATTR_NULL(&va); 1145 bcopy(cverf, (caddr_t)&va.va_atime, 1146 NFSX_V3CREATEVERF); 1147 error = VOP_SETATTR(nd.ni_vp, &va, cred, 1148 procp); 1149 } 1150 } 1151 } else if (va.va_type == VCHR || va.va_type == VBLK || 1152 va.va_type == VFIFO) { 1153 if (va.va_type == VCHR && rdev == 0xffffffff) 1154 va.va_type = VFIFO; 1155 if (va.va_type != VFIFO && 1156 (error = suser_ucred(cred))) { 1157 vrele(nd.ni_startdir); 1158 if (nd.ni_cnd.cn_flags & HASBUF) { 1159 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1160 nd.ni_cnd.cn_flags &= ~HASBUF; 1161 } 1162 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1163 vput(nd.ni_dvp); 1164 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1165 0) != 0) 1166 return 0; 1167 error = 0; 1168 goto nfsmout; 1169 } else 1170 va.va_rdev = (dev_t)rdev; 1171 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, 1172 &va); 1173 vput(nd.ni_dvp); 1174 if (error) { 1175 vrele(nd.ni_startdir); 1176 if (nd.ni_cnd.cn_flags & HASBUF) { 1177 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1178 nd.ni_cnd.cn_flags &= ~HASBUF; 1179 } 1180 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1181 0) != 0) 1182 return 0; 1183 error = 0; 1184 goto nfsmout; 1185 } 1186 nd.ni_cnd.cn_nameiop = LOOKUP; 1187 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 1188 nd.ni_cnd.cn_proc = procp; 1189 nd.ni_cnd.cn_cred = cred; 1190 if ((error = vfs_lookup(&nd)) != 0) { 1191 if (nd.ni_cnd.cn_flags & HASBUF) { 1192 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1193 nd.ni_cnd.cn_flags &= ~HASBUF; 1194 } 1195 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1196 0) != 0) 1197 return 0; 1198 error = 0; 1199 goto nfsmout; 1200 } 1201 1202 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1203 if (nd.ni_cnd.cn_flags & ISSYMLINK) { 1204 vrele(nd.ni_dvp); 1205 vput(nd.ni_vp); 1206 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1207 error = EINVAL; 1208 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1209 0) != 0) 1210 return 0; 1211 error = 0; 1212 goto nfsmout; 1213 } 1214 } else { 1215 vrele(nd.ni_startdir); 1216 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1217 nd.ni_cnd.cn_flags &= ~HASBUF; 1218 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1219 vput(nd.ni_dvp); 1220 error = ENXIO; 1221 } 1222 vp = nd.ni_vp; 1223 } else { 1224 vrele(nd.ni_startdir); 1225 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1226 nd.ni_cnd.cn_flags &= ~HASBUF; 1227 vp = nd.ni_vp; 1228 if (nd.ni_dvp == vp) 1229 vrele(nd.ni_dvp); 1230 else 1231 vput(nd.ni_dvp); 1232 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1233 if (va.va_size != -1) { 1234 error = nfsrv_access(vp, VWRITE, cred, 1235 (nd.ni_cnd.cn_flags & RDONLY), procp, 0); 1236 if (!error) { 1237 tempsize = va.va_size; 1238 VATTR_NULL(&va); 1239 va.va_size = tempsize; 1240 error = VOP_SETATTR(vp, &va, cred, 1241 procp); 1242 } 1243 if (error) 1244 vput(vp); 1245 } 1246 } 1247 if (!error) { 1248 memset(fhp, 0, sizeof(nfh)); 1249 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1250 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1251 if (!error) 1252 error = VOP_GETATTR(vp, &va, cred, procp); 1253 vput(vp); 1254 } 1255 if (info.nmi_v3) { 1256 if (exclusive_flag && !error && 1257 bcmp(cverf, (caddr_t)&va.va_atime, NFSX_V3CREATEVERF)) 1258 error = EEXIST; 1259 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1260 vrele(dirp); 1261 } 1262 if (nfsm_reply(&info, nfsd, slp, mrq, error, NFSX_SRVFH(info.nmi_v3) + 1263 NFSX_FATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0) 1264 return 0; 1265 if (info.nmi_v3) { 1266 if (!error) { 1267 nfsm_srvpostop_fh(&info, fhp); 1268 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 1269 } 1270 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1271 &info); 1272 } else { 1273 nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3); 1274 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 1275 nfsm_srvfattr(nfsd, &va, fp); 1276 } 1277 return (0); 1278 nfsmout: 1279 if (dirp) 1280 vrele(dirp); 1281 if (nd.ni_cnd.cn_nameiop != LOOKUP) { 1282 vrele(nd.ni_startdir); 1283 if (nd.ni_cnd.cn_flags & HASBUF) { 1284 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1285 nd.ni_cnd.cn_flags &= ~HASBUF; 1286 } 1287 } 1288 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1289 if (nd.ni_dvp == nd.ni_vp) 1290 vrele(nd.ni_dvp); 1291 else 1292 vput(nd.ni_dvp); 1293 if (nd.ni_vp) 1294 vput(nd.ni_vp); 1295 return (error); 1296 } 1297 1298 /* 1299 * nfs v3 mknod service 1300 */ 1301 int 1302 nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1303 struct proc *procp, struct mbuf **mrq) 1304 { 1305 struct mbuf *nam = nfsd->nd_nam; 1306 struct ucred *cred = &nfsd->nd_cr; 1307 struct vattr va, dirfor, diraft; 1308 struct nfsm_info info; 1309 u_int32_t *tl; 1310 struct nameidata nd; 1311 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1312 u_int32_t major, minor; 1313 enum vtype vtyp; 1314 struct vnode *vp, *dirp = NULL; 1315 nfsfh_t nfh; 1316 fhandle_t *fhp; 1317 1318 info.nmi_mreq = NULL; 1319 info.nmi_mrep = nfsd->nd_mrep; 1320 info.nmi_md = nfsd->nd_md; 1321 info.nmi_dpos = nfsd->nd_dpos; 1322 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1323 info.nmi_errorp = &error; 1324 1325 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 1326 return 0; 1327 else if (error != 0) 1328 return error; 1329 fhp = &nfh.fh_generic; 1330 if (nfsm_srvmtofh2(&info, fhp) != 0) 1331 return error; 1332 if (nfsm_srvnamesiz(&info, &len) != 0) 1333 return error; 1334 if (error) { 1335 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 1336 return 0; 1337 } 1338 1339 NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF | SAVESTART, UIO_SYSSPACE, 1340 NULL, procp); 1341 nd.ni_cnd.cn_cred = cred; 1342 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp); 1343 if (dirp) 1344 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 1345 if (error) { 1346 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1347 NFSX_WCCDATA(1)) != 0) 1348 return 0; 1349 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1350 &info); 1351 if (dirp) 1352 vrele(dirp); 1353 return (0); 1354 } 1355 1356 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 1357 if (tl == NULL) 1358 goto nfsmout; 1359 vtyp = nfsv3tov_type(*tl); 1360 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { 1361 vrele(nd.ni_startdir); 1362 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1363 error = NFSERR_BADTYPE; 1364 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1365 if (nd.ni_dvp == nd.ni_vp) 1366 vrele(nd.ni_dvp); 1367 else 1368 vput(nd.ni_dvp); 1369 if (nd.ni_vp) 1370 vput(nd.ni_vp); 1371 goto out; 1372 } 1373 VATTR_NULL(&va); 1374 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, &info.nmi_dpos); 1375 if (error) 1376 goto nfsmout; 1377 if (vtyp == VCHR || vtyp == VBLK) { 1378 tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED); 1379 if (tl == NULL) 1380 goto nfsmout; 1381 major = fxdr_unsigned(u_int32_t, *tl++); 1382 minor = fxdr_unsigned(u_int32_t, *tl); 1383 va.va_rdev = makedev(major, minor); 1384 } 1385 1386 /* 1387 * Iff doesn't exist, create it. 1388 */ 1389 if (nd.ni_vp) { 1390 vrele(nd.ni_startdir); 1391 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1392 error = EEXIST; 1393 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1394 if (nd.ni_dvp == nd.ni_vp) 1395 vrele(nd.ni_dvp); 1396 else 1397 vput(nd.ni_dvp); 1398 vput(nd.ni_vp); 1399 goto out; 1400 } 1401 va.va_type = vtyp; 1402 if (vtyp == VSOCK) { 1403 vrele(nd.ni_startdir); 1404 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1405 vput(nd.ni_dvp); 1406 if (!error) 1407 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1408 } else { 1409 if (va.va_type != VFIFO && 1410 (error = suser_ucred(cred))) { 1411 vrele(nd.ni_startdir); 1412 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1413 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1414 vput(nd.ni_dvp); 1415 goto out; 1416 } 1417 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1418 vput(nd.ni_dvp); 1419 if (error) { 1420 vrele(nd.ni_startdir); 1421 goto out; 1422 } 1423 nd.ni_cnd.cn_nameiop = LOOKUP; 1424 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 1425 nd.ni_cnd.cn_proc = procp; 1426 nd.ni_cnd.cn_cred = procp->p_ucred; 1427 error = vfs_lookup(&nd); 1428 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1429 if (error) 1430 goto out; 1431 if (nd.ni_cnd.cn_flags & ISSYMLINK) { 1432 vrele(nd.ni_dvp); 1433 vput(nd.ni_vp); 1434 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1435 error = EINVAL; 1436 } 1437 } 1438 out: 1439 vp = nd.ni_vp; 1440 if (!error) { 1441 memset(fhp, 0, sizeof(nfh)); 1442 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1443 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1444 if (!error) 1445 error = VOP_GETATTR(vp, &va, cred, procp); 1446 vput(vp); 1447 } 1448 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1449 vrele(dirp); 1450 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1451 NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)) != 0) 1452 return 0; 1453 if (!error) { 1454 nfsm_srvpostop_fh(&info, fhp); 1455 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 1456 } 1457 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, &info); 1458 return (0); 1459 nfsmout: 1460 if (dirp) 1461 vrele(dirp); 1462 if (nd.ni_cnd.cn_nameiop) { 1463 vrele(nd.ni_startdir); 1464 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1465 } 1466 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1467 if (nd.ni_dvp == nd.ni_vp) 1468 vrele(nd.ni_dvp); 1469 else 1470 vput(nd.ni_dvp); 1471 if (nd.ni_vp) 1472 vput(nd.ni_vp); 1473 return (error); 1474 } 1475 1476 /* 1477 * nfs remove service 1478 */ 1479 int 1480 nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1481 struct proc *procp, struct mbuf **mrq) 1482 { 1483 struct mbuf *nam = nfsd->nd_nam; 1484 struct ucred *cred = &nfsd->nd_cr; 1485 struct nameidata nd; 1486 struct nfsm_info info; 1487 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1488 struct vnode *vp, *dirp; 1489 struct vattr dirfor, diraft; 1490 nfsfh_t nfh; 1491 fhandle_t *fhp; 1492 1493 info.nmi_mreq = NULL; 1494 info.nmi_mrep = nfsd->nd_mrep; 1495 info.nmi_md = nfsd->nd_md; 1496 info.nmi_dpos = nfsd->nd_dpos; 1497 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1498 info.nmi_errorp = &error; 1499 1500 vp = NULL; 1501 1502 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 1503 return 0; 1504 else if (error != 0) 1505 goto nfsmout; 1506 fhp = &nfh.fh_generic; 1507 if (nfsm_srvmtofh2(&info, fhp) != 0) 1508 goto nfsmout; 1509 if (nfsm_srvnamesiz(&info, &len) != 0) 1510 goto nfsmout; 1511 if (error) { 1512 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 1513 return 0; 1514 } 1515 1516 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, NULL, procp); 1517 nd.ni_cnd.cn_cred = cred; 1518 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp); 1519 if (dirp) { 1520 if (info.nmi_v3) 1521 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 1522 else { 1523 vrele(dirp); 1524 dirp = NULL; 1525 } 1526 } 1527 1528 if (!error) { 1529 vp = nd.ni_vp; 1530 if (vp->v_type == VDIR && 1531 (error = suser_ucred(cred)) != 0) 1532 goto out; 1533 /* 1534 * The root of a mounted filesystem cannot be deleted. 1535 */ 1536 if (vp->v_flag & VROOT) { 1537 error = EBUSY; 1538 goto out; 1539 } 1540 if (vp->v_flag & VTEXT) 1541 uvm_vnp_uncache(vp); 1542 out: 1543 if (!error) { 1544 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1545 } else { 1546 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1547 if (nd.ni_dvp == vp) 1548 vrele(nd.ni_dvp); 1549 else 1550 vput(nd.ni_dvp); 1551 vput(vp); 1552 } 1553 } 1554 if (dirp && info.nmi_v3) { 1555 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1556 vrele(dirp); 1557 } 1558 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1559 NFSX_WCCDATA(info.nmi_v3)) != 0) 1560 return 0; 1561 if (info.nmi_v3) { 1562 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1563 &info); 1564 return (0); 1565 } 1566 1567 nfsmout: 1568 return(error); 1569 } 1570 1571 /* 1572 * nfs rename service 1573 */ 1574 int 1575 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1576 struct proc *procp, struct mbuf **mrq) 1577 { 1578 struct mbuf *nam = nfsd->nd_nam; 1579 struct ucred *cred = &nfsd->nd_cr; 1580 struct nfsm_info info; 1581 int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1; 1582 int tdirfor_ret = 1, tdiraft_ret = 1; 1583 struct nameidata fromnd, tond; 1584 struct vnode *fvp = NULL, *tvp, *tdvp, *fdirp = NULL; 1585 struct vnode *tdirp = NULL; 1586 struct vattr fdirfor, fdiraft, tdirfor, tdiraft; 1587 nfsfh_t fnfh, tnfh; 1588 fhandle_t *ffhp, *tfhp; 1589 uid_t saved_uid; 1590 1591 info.nmi_mreq = NULL; 1592 info.nmi_mrep = nfsd->nd_mrep; 1593 info.nmi_md = nfsd->nd_md; 1594 info.nmi_dpos = nfsd->nd_dpos; 1595 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1596 info.nmi_errorp = &error; 1597 1598 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 1599 return 0; 1600 else if (error != 0) 1601 return error; 1602 ffhp = &fnfh.fh_generic; 1603 if (nfsm_srvmtofh2(&info, ffhp) != 0) 1604 return error; 1605 if (nfsm_srvnamesiz(&info, &len) != 0) 1606 return error; 1607 if (error) { 1608 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 1609 return 0; 1610 } 1611 1612 /* 1613 * Remember our original uid so that we can reset cr_uid before 1614 * the second nfs_namei() call, in case it is remapped. 1615 */ 1616 saved_uid = cred->cr_uid; 1617 1618 NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_SYSSPACE, NULL, 1619 procp); 1620 fromnd.ni_cnd.cn_cred = cred; 1621 error = nfs_namei(&fromnd, ffhp, len, slp, nam, &info.nmi_md, 1622 &info.nmi_dpos, &fdirp, procp); 1623 if (fdirp) { 1624 if (info.nmi_v3) 1625 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, 1626 procp); 1627 else { 1628 vrele(fdirp); 1629 fdirp = NULL; 1630 } 1631 } 1632 if (error) { 1633 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1634 2 * NFSX_WCCDATA(info.nmi_v3)) != 0) 1635 return 0; 1636 nfsm_srvwcc(nfsd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft, 1637 &info); 1638 nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft, 1639 &info); 1640 if (fdirp) 1641 vrele(fdirp); 1642 return (0); 1643 } 1644 1645 fvp = fromnd.ni_vp; 1646 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 1647 return 0; 1648 else if (error != 0) 1649 goto nfsmout; 1650 tfhp = &tnfh.fh_generic; 1651 if (nfsm_srvmtofh2(&info, tfhp) != 0) 1652 goto nfsmout; 1653 if (nfsm_strsiz(&info, &len2, NFS_MAXNAMLEN) != 0) 1654 goto nfsmout; 1655 cred->cr_uid = saved_uid; 1656 1657 NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF| NOCACHE | SAVESTART, 1658 UIO_SYSSPACE, NULL, procp); 1659 tond.ni_cnd.cn_cred = cred; 1660 error = nfs_namei(&tond, tfhp, len2, slp, nam, &info.nmi_md, 1661 &info.nmi_dpos, &tdirp, procp); 1662 if (tdirp) { 1663 if (info.nmi_v3) 1664 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, 1665 procp); 1666 else { 1667 vrele(tdirp); 1668 tdirp = NULL; 1669 } 1670 } 1671 if (error) { 1672 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1673 vrele(fromnd.ni_dvp); 1674 vrele(fvp); 1675 goto out1; 1676 } 1677 tdvp = tond.ni_dvp; 1678 tvp = tond.ni_vp; 1679 if (tvp != NULL) { 1680 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1681 error = info.nmi_v3 ? EEXIST : EISDIR; 1682 goto out; 1683 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1684 error = info.nmi_v3 ? EEXIST : ENOTDIR; 1685 goto out; 1686 } 1687 if (tvp->v_type == VDIR && tvp->v_mountedhere) { 1688 error = info.nmi_v3 ? EXDEV : ENOTEMPTY; 1689 goto out; 1690 } 1691 } 1692 if (fvp->v_type == VDIR && fvp->v_mountedhere) { 1693 error = info.nmi_v3 ? EXDEV : ENOTEMPTY; 1694 goto out; 1695 } 1696 if (fvp->v_mount != tdvp->v_mount) { 1697 error = info.nmi_v3 ? EXDEV : ENOTEMPTY; 1698 goto out; 1699 } 1700 if (fvp == tdvp) 1701 error = info.nmi_v3 ? EINVAL : ENOTEMPTY; 1702 /* 1703 * If source is the same as the destination (that is the 1704 * same vnode with the same name in the same directory), 1705 * then there is nothing to do. 1706 */ 1707 if (fvp == tvp && fromnd.ni_dvp == tdvp && 1708 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 1709 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 1710 fromnd.ni_cnd.cn_namelen)) 1711 error = -1; 1712 out: 1713 if (!error) { 1714 if (tvp) { 1715 (void)uvm_vnp_uncache(tvp); 1716 } 1717 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 1718 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 1719 } else { 1720 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 1721 if (tdvp == tvp) 1722 vrele(tdvp); 1723 else 1724 vput(tdvp); 1725 if (tvp) 1726 vput(tvp); 1727 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1728 vrele(fromnd.ni_dvp); 1729 vrele(fvp); 1730 if (error == -1) 1731 error = 0; 1732 } 1733 vrele(tond.ni_startdir); 1734 pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf); 1735 out1: 1736 if (fdirp) { 1737 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp); 1738 vrele(fdirp); 1739 } 1740 if (tdirp) { 1741 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp); 1742 vrele(tdirp); 1743 } 1744 vrele(fromnd.ni_startdir); 1745 pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf); 1746 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1747 2 * NFSX_WCCDATA(info.nmi_v3)) != 0) 1748 return 0; 1749 if (info.nmi_v3) { 1750 nfsm_srvwcc(nfsd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft, 1751 &info); 1752 nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft, 1753 &info); 1754 } 1755 return (0); 1756 1757 nfsmout: 1758 if (fdirp) 1759 vrele(fdirp); 1760 if (fromnd.ni_cnd.cn_nameiop) { 1761 if (fromnd.ni_startdir) 1762 vrele(fromnd.ni_startdir); 1763 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1764 1765 /* 1766 * XXX: Workaround the fact that fromnd.ni_dvp can point 1767 * to the same vnode as fdirp. 1768 */ 1769 if (fromnd.ni_dvp != NULL && fromnd.ni_dvp != fdirp) 1770 vrele(fromnd.ni_dvp); 1771 if (fvp) 1772 vrele(fvp); 1773 } 1774 return (error); 1775 } 1776 1777 /* 1778 * nfs link service 1779 */ 1780 int 1781 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1782 struct proc *procp, struct mbuf **mrq) 1783 { 1784 struct mbuf *nam = nfsd->nd_nam; 1785 struct nfsm_info info; 1786 struct ucred *cred = &nfsd->nd_cr; 1787 struct nameidata nd; 1788 int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1; 1789 int getret = 1; 1790 struct vnode *vp, *xp, *dirp = NULL; 1791 struct vattr dirfor, diraft, at; 1792 nfsfh_t nfh, dnfh; 1793 fhandle_t *fhp, *dfhp; 1794 1795 info.nmi_mreq = NULL; 1796 info.nmi_mrep = nfsd->nd_mrep; 1797 info.nmi_md = nfsd->nd_md; 1798 info.nmi_dpos = nfsd->nd_dpos; 1799 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1800 info.nmi_errorp = &error; 1801 1802 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 1803 return 0; 1804 else if (error != 0) 1805 goto nfsmout; 1806 fhp = &nfh.fh_generic; 1807 if (nfsm_srvmtofh2(&info, fhp) != 0) 1808 goto nfsmout; 1809 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 1810 return 0; 1811 else if (error != 0) 1812 goto nfsmout; 1813 dfhp = &dnfh.fh_generic; 1814 if (nfsm_srvmtofh2(&info, dfhp) != 0) 1815 goto nfsmout; 1816 if (nfsm_srvnamesiz(&info, &len) != 0) 1817 goto nfsmout; 1818 if (error) { 1819 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 1820 return 0; 1821 } 1822 1823 error = nfsrv_fhtovp(fhp, 0, &vp, cred, slp, nam, &rdonly); 1824 if (error) { 1825 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1826 NFSX_POSTOPATTR(info.nmi_v3) + 1827 NFSX_WCCDATA(info.nmi_v3)) != 0) 1828 return 0; 1829 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 1830 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1831 &info); 1832 error = 0; 1833 goto nfsmout; 1834 } 1835 if (vp->v_type == VDIR) 1836 goto out1; 1837 1838 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, NULL, procp); 1839 nd.ni_cnd.cn_cred = cred; 1840 error = nfs_namei(&nd, dfhp, len, slp, nam, &info.nmi_md, 1841 &info.nmi_dpos, &dirp, procp); 1842 if (dirp) { 1843 if (info.nmi_v3) 1844 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1845 procp); 1846 else { 1847 vrele(dirp); 1848 dirp = NULL; 1849 } 1850 } 1851 if (error) 1852 goto out1; 1853 xp = nd.ni_vp; 1854 if (xp != NULL) { 1855 error = EEXIST; 1856 goto out; 1857 } 1858 xp = nd.ni_dvp; 1859 if (vp->v_mount != xp->v_mount) 1860 error = EXDEV; 1861 out: 1862 if (!error) { 1863 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1864 } else { 1865 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1866 if (nd.ni_dvp == nd.ni_vp) 1867 vrele(nd.ni_dvp); 1868 else 1869 vput(nd.ni_dvp); 1870 if (nd.ni_vp) 1871 vrele(nd.ni_vp); 1872 } 1873 out1: 1874 if (info.nmi_v3) 1875 getret = VOP_GETATTR(vp, &at, cred, procp); 1876 if (dirp) { 1877 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1878 vrele(dirp); 1879 } 1880 vrele(vp); 1881 if (nfsm_reply(&info, nfsd, slp, mrq, error, 1882 NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0) 1883 return 0; 1884 if (info.nmi_v3) { 1885 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 1886 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1887 &info); 1888 error = 0; 1889 } 1890 nfsmout: 1891 return(error); 1892 } 1893 1894 /* 1895 * nfs symbolic link service 1896 */ 1897 int 1898 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1899 struct proc *procp, struct mbuf **mrq) 1900 { 1901 struct mbuf *nam = nfsd->nd_nam; 1902 struct ucred *cred = &nfsd->nd_cr; 1903 struct vattr va, dirfor, diraft; 1904 struct nameidata nd; 1905 struct nfsm_info info; 1906 struct nfsv2_sattr *sp; 1907 char *pathcp = NULL; 1908 struct uio io; 1909 struct iovec iv; 1910 int error = 0, len, pathlen, len2, dirfor_ret = 1, diraft_ret = 1; 1911 struct vnode *dirp = NULL; 1912 nfsfh_t nfh; 1913 fhandle_t *fhp; 1914 1915 info.nmi_mreq = NULL; 1916 info.nmi_mrep = nfsd->nd_mrep; 1917 info.nmi_md = nfsd->nd_md; 1918 info.nmi_dpos = nfsd->nd_dpos; 1919 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1920 info.nmi_errorp = &error; 1921 1922 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 1923 return 0; 1924 else if (error != 0) 1925 return error; 1926 fhp = &nfh.fh_generic; 1927 if (nfsm_srvmtofh2(&info, fhp) != 0) 1928 return error; 1929 if (nfsm_srvnamesiz(&info, &len) != 0) 1930 return error; 1931 if (error) { 1932 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 1933 return 0; 1934 } 1935 1936 NDINIT(&nd, CREATE, LOCKPARENT | SAVESTART, UIO_SYSSPACE, NULL, procp); 1937 nd.ni_cnd.cn_cred = cred; 1938 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 1939 &info.nmi_dpos, &dirp, procp); 1940 if (dirp) { 1941 if (info.nmi_v3) 1942 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1943 procp); 1944 else { 1945 vrele(dirp); 1946 dirp = NULL; 1947 } 1948 } 1949 if (error) 1950 goto out; 1951 VATTR_NULL(&va); 1952 if (info.nmi_v3) { 1953 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, 1954 &info.nmi_dpos); 1955 if (error) 1956 goto nfsmout; 1957 } 1958 if (nfsm_strsiz(&info, &len2, NFS_MAXPATHLEN) != 0) 1959 goto nfsmout; 1960 pathlen = len2 + 1; 1961 pathcp = malloc(pathlen, M_TEMP, M_WAITOK); 1962 iv.iov_base = pathcp; 1963 iv.iov_len = len2; 1964 io.uio_resid = len2; 1965 io.uio_offset = 0; 1966 io.uio_iov = &iv; 1967 io.uio_iovcnt = 1; 1968 io.uio_segflg = UIO_SYSSPACE; 1969 io.uio_rw = UIO_READ; 1970 io.uio_procp = NULL; 1971 if (nfsm_mtouio(&info, &io, len2) != 0) 1972 goto nfsmout; 1973 if (!info.nmi_v3) { 1974 sp = (struct nfsv2_sattr *)nfsm_dissect(&info, NFSX_V2SATTR); 1975 if (sp == NULL) 1976 goto nfsmout; 1977 va.va_mode = nfstov_mode(sp->sa_mode); 1978 } 1979 *(pathcp + len2) = '\0'; 1980 if (nd.ni_vp) { 1981 vrele(nd.ni_startdir); 1982 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1983 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1984 if (nd.ni_dvp == nd.ni_vp) 1985 vrele(nd.ni_dvp); 1986 else 1987 vput(nd.ni_dvp); 1988 vrele(nd.ni_vp); 1989 error = EEXIST; 1990 goto out; 1991 } 1992 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp); 1993 if (error) 1994 vrele(nd.ni_startdir); 1995 else { 1996 if (info.nmi_v3) { 1997 nd.ni_cnd.cn_nameiop = LOOKUP; 1998 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | 1999 FOLLOW); 2000 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF); 2001 nd.ni_cnd.cn_proc = procp; 2002 nd.ni_cnd.cn_cred = cred; 2003 error = vfs_lookup(&nd); 2004 if (!error) { 2005 memset(fhp, 0, sizeof(nfh)); 2006 fhp->fh_fsid = 2007 nd.ni_vp->v_mount->mnt_stat.f_fsid; 2008 error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); 2009 if (!error) 2010 error = VOP_GETATTR(nd.ni_vp, &va, cred, 2011 procp); 2012 vput(nd.ni_vp); 2013 } 2014 } else 2015 vrele(nd.ni_startdir); 2016 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 2017 } 2018 out: 2019 if (pathcp) 2020 free(pathcp, M_TEMP, pathlen); 2021 if (dirp) { 2022 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 2023 vrele(dirp); 2024 } 2025 if (nfsm_reply(&info, nfsd, slp, mrq, error, NFSX_SRVFH(info.nmi_v3) + 2026 NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0) 2027 return 0; 2028 if (info.nmi_v3) { 2029 if (!error) { 2030 nfsm_srvpostop_fh(&info, fhp); 2031 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 2032 } 2033 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 2034 &info); 2035 } 2036 return (0); 2037 nfsmout: 2038 if (nd.ni_cnd.cn_nameiop) { 2039 vrele(nd.ni_startdir); 2040 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 2041 } 2042 if (dirp) 2043 vrele(dirp); 2044 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2045 if (nd.ni_dvp == nd.ni_vp) 2046 vrele(nd.ni_dvp); 2047 else 2048 vput(nd.ni_dvp); 2049 if (nd.ni_vp) 2050 vrele(nd.ni_vp); 2051 if (pathcp) 2052 free(pathcp, M_TEMP, pathlen); 2053 return (error); 2054 } 2055 2056 /* 2057 * nfs mkdir service 2058 */ 2059 int 2060 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2061 struct proc *procp, struct mbuf **mrq) 2062 { 2063 struct mbuf *nam = nfsd->nd_nam; 2064 struct ucred *cred = &nfsd->nd_cr; 2065 struct vattr va, dirfor, diraft; 2066 struct nfs_fattr *fp; 2067 struct nameidata nd; 2068 struct nfsm_info info; 2069 u_int32_t *tl; 2070 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 2071 struct vnode *vp, *dirp = NULL; 2072 nfsfh_t nfh; 2073 fhandle_t *fhp; 2074 2075 info.nmi_mreq = NULL; 2076 info.nmi_mrep = nfsd->nd_mrep; 2077 info.nmi_md = nfsd->nd_md; 2078 info.nmi_dpos = nfsd->nd_dpos; 2079 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2080 info.nmi_errorp = &error; 2081 2082 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 2083 return 0; 2084 else if (error != 0) 2085 return error; 2086 fhp = &nfh.fh_generic; 2087 if (nfsm_srvmtofh2(&info, fhp) != 0) 2088 return error; 2089 if (nfsm_srvnamesiz(&info, &len) != 0) 2090 return error; 2091 if (error) { 2092 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 2093 return 0; 2094 } 2095 2096 NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, NULL, procp); 2097 nd.ni_cnd.cn_cred = cred; 2098 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 2099 &info.nmi_dpos, &dirp, procp); 2100 if (dirp) { 2101 if (info.nmi_v3) 2102 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 2103 else { 2104 vrele(dirp); 2105 dirp = NULL; 2106 } 2107 } 2108 if (error) { 2109 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2110 NFSX_WCCDATA(info.nmi_v3)) != 0) 2111 return 0; 2112 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 2113 &info); 2114 if (dirp) 2115 vrele(dirp); 2116 return (0); 2117 } 2118 2119 VATTR_NULL(&va); 2120 if (info.nmi_v3) { 2121 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, 2122 &info.nmi_dpos); 2123 if (error) 2124 goto nfsmout; 2125 } else { 2126 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 2127 if (tl == NULL) 2128 goto nfsmout; 2129 va.va_mode = nfstov_mode(*tl++); 2130 } 2131 va.va_type = VDIR; 2132 vp = nd.ni_vp; 2133 if (vp != NULL) { 2134 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2135 if (nd.ni_dvp == vp) 2136 vrele(nd.ni_dvp); 2137 else 2138 vput(nd.ni_dvp); 2139 vrele(vp); 2140 error = EEXIST; 2141 goto out; 2142 } 2143 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 2144 if (!error) { 2145 vp = nd.ni_vp; 2146 memset(fhp, 0, sizeof(nfh)); 2147 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 2148 error = VFS_VPTOFH(vp, &fhp->fh_fid); 2149 if (!error) 2150 error = VOP_GETATTR(vp, &va, cred, procp); 2151 vput(vp); 2152 } 2153 out: 2154 if (dirp) { 2155 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 2156 vrele(dirp); 2157 } 2158 if (nfsm_reply(&info, nfsd, slp, mrq, error, NFSX_SRVFH(info.nmi_v3) + 2159 NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0) 2160 return 0; 2161 if (info.nmi_v3) { 2162 if (!error) { 2163 nfsm_srvpostop_fh(&info, fhp); 2164 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 2165 } 2166 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 2167 &info); 2168 } else { 2169 nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3); 2170 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 2171 nfsm_srvfattr(nfsd, &va, fp); 2172 } 2173 return (0); 2174 nfsmout: 2175 if (dirp) 2176 vrele(dirp); 2177 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2178 if (nd.ni_dvp == nd.ni_vp) 2179 vrele(nd.ni_dvp); 2180 else 2181 vput(nd.ni_dvp); 2182 if (nd.ni_vp) 2183 vrele(nd.ni_vp); 2184 return (error); 2185 } 2186 2187 /* 2188 * nfs rmdir service 2189 */ 2190 int 2191 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2192 struct proc *procp, struct mbuf **mrq) 2193 { 2194 struct mbuf *nam = nfsd->nd_nam; 2195 struct ucred *cred = &nfsd->nd_cr; 2196 struct nfsm_info info; 2197 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 2198 struct vnode *vp, *dirp = NULL; 2199 struct vattr dirfor, diraft; 2200 nfsfh_t nfh; 2201 fhandle_t *fhp; 2202 struct nameidata nd; 2203 2204 info.nmi_mreq = NULL; 2205 info.nmi_mrep = nfsd->nd_mrep; 2206 info.nmi_md = nfsd->nd_md; 2207 info.nmi_dpos = nfsd->nd_dpos; 2208 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2209 info.nmi_errorp = &error; 2210 2211 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 2212 return 0; 2213 else if (error != 0) 2214 goto nfsmout; 2215 fhp = &nfh.fh_generic; 2216 if (nfsm_srvmtofh2(&info, fhp) != 0) 2217 goto nfsmout; 2218 if (nfsm_srvnamesiz(&info, &len) != 0) 2219 goto nfsmout; 2220 if (error) { 2221 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 2222 return 0; 2223 } 2224 2225 NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, NULL, procp); 2226 nd.ni_cnd.cn_cred = cred; 2227 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 2228 &info.nmi_dpos, &dirp, procp); 2229 if (dirp) { 2230 if (info.nmi_v3) 2231 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 2232 procp); 2233 else { 2234 vrele(dirp); 2235 dirp = NULL; 2236 } 2237 } 2238 if (error) { 2239 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2240 NFSX_WCCDATA(info.nmi_v3)) != 0) 2241 return 0; 2242 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 2243 &info); 2244 if (dirp) 2245 vrele(dirp); 2246 return (0); 2247 } 2248 vp = nd.ni_vp; 2249 if (vp->v_type != VDIR) { 2250 error = ENOTDIR; 2251 goto out; 2252 } 2253 /* 2254 * No rmdir "." please. 2255 */ 2256 if (nd.ni_dvp == vp) { 2257 error = EINVAL; 2258 goto out; 2259 } 2260 /* 2261 * A mounted on directory cannot be deleted. 2262 */ 2263 if (vp->v_mountedhere != NULL) { 2264 error = EBUSY; 2265 goto out; 2266 } 2267 /* 2268 * The root of a mounted filesystem cannot be deleted. 2269 */ 2270 if (vp->v_flag & VROOT) 2271 error = EBUSY; 2272 out: 2273 if (!error) { 2274 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 2275 } else { 2276 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 2277 if (nd.ni_dvp == nd.ni_vp) 2278 vrele(nd.ni_dvp); 2279 else 2280 vput(nd.ni_dvp); 2281 vput(vp); 2282 } 2283 if (dirp) { 2284 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 2285 vrele(dirp); 2286 } 2287 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2288 NFSX_WCCDATA(info.nmi_v3)) != 0) 2289 return 0; 2290 if (info.nmi_v3) { 2291 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 2292 &info); 2293 error = 0; 2294 } 2295 nfsmout: 2296 return(error); 2297 } 2298 2299 /* 2300 * nfs readdir service 2301 * - mallocs what it thinks is enough to read 2302 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 2303 * - calls VOP_READDIR() 2304 * - loops around building the reply 2305 * if the output generated exceeds count break out of loop 2306 * - it only knows that it has encountered eof when the VOP_READDIR() 2307 * reads nothing 2308 * - as such one readdir rpc will return eof false although you are there 2309 * and then the next will return eof 2310 * - it trims out records with d_fileno == 0 2311 * this doesn't matter for Unix clients, but they might confuse clients 2312 * for other os'. 2313 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 2314 * than requested, but this may not apply to all filesystems. For 2315 * example, client NFS does not { although it is never remote mounted 2316 * anyhow } 2317 * The alternate call nfsrv_readdirplus() does lookups as well. 2318 * PS: The NFS protocol spec. does not clarify what the "count" byte 2319 * argument is a count of.. just name strings and file id's or the 2320 * entire reply rpc or ... 2321 * I tried just file name and id sizes and it confused the Sun client, 2322 * so I am using the full rpc size now. The "paranoia.." comment refers 2323 * to including the status longwords that are not a part of the dir. 2324 * "entry" structures, but are in the rpc. 2325 */ 2326 struct flrep { 2327 nfsuint64 fl_off; 2328 u_int32_t fl_postopok; 2329 u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)]; 2330 u_int32_t fl_fhok; 2331 u_int32_t fl_fhsize; 2332 u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)]; 2333 }; 2334 2335 int 2336 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2337 struct proc *procp, struct mbuf **mrq) 2338 { 2339 struct mbuf *nam = nfsd->nd_nam; 2340 struct ucred *cred = &nfsd->nd_cr; 2341 struct dirent *dp; 2342 struct nfsm_info info; 2343 u_int32_t *tl; 2344 char *cpos, *cend, *rbuf; 2345 struct vnode *vp; 2346 struct vattr at; 2347 nfsfh_t nfh; 2348 fhandle_t *fhp; 2349 struct uio io; 2350 struct iovec iv; 2351 int len, nlen, pad, xfer, error = 0, getret = 1; 2352 int siz, cnt, fullsiz, eofflag, rdonly; 2353 u_quad_t off, toff, verf; 2354 2355 info.nmi_mreq = NULL; 2356 info.nmi_mrep = nfsd->nd_mrep; 2357 info.nmi_md = nfsd->nd_md; 2358 info.nmi_dpos = nfsd->nd_dpos; 2359 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2360 info.nmi_errorp = &error; 2361 2362 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 2363 return 0; 2364 else if (error != 0) 2365 goto nfsmout; 2366 fhp = &nfh.fh_generic; 2367 if (nfsm_srvmtofh2(&info, fhp) != 0) 2368 goto nfsmout; 2369 if (info.nmi_v3) { 2370 tl = (uint32_t *)nfsm_dissect(&info, 5 * NFSX_UNSIGNED); 2371 if (tl == NULL) 2372 goto nfsmout; 2373 toff = fxdr_hyper(tl); 2374 tl += 2; 2375 verf = fxdr_hyper(tl); 2376 tl += 2; 2377 } else { 2378 tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED); 2379 if (tl == NULL) 2380 goto nfsmout; 2381 toff = fxdr_unsigned(u_quad_t, *tl++); 2382 } 2383 off = toff; 2384 cnt = fxdr_unsigned(int, *tl); 2385 xfer = NFS_SRVMAXDATA(nfsd); 2386 if (cnt > xfer || cnt < 0) 2387 cnt = xfer; 2388 siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 2389 if (siz > xfer) 2390 siz = xfer; 2391 fullsiz = siz; 2392 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2393 if (error) { 2394 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2395 NFSX_UNSIGNED) != 0) 2396 return 0; 2397 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2398 error = 0; 2399 goto nfsmout; 2400 } 2401 if (info.nmi_v3) 2402 error = getret = VOP_GETATTR(vp, &at, cred, procp); 2403 if (!error) 2404 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0); 2405 if (error) { 2406 vput(vp); 2407 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2408 NFSX_POSTOPATTR(info.nmi_v3)) != 0) 2409 return 0; 2410 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2411 error = 0; 2412 goto nfsmout; 2413 } 2414 VOP_UNLOCK(vp); 2415 rbuf = malloc(fullsiz, M_TEMP, M_WAITOK); 2416 again: 2417 iv.iov_base = rbuf; 2418 iv.iov_len = fullsiz; 2419 io.uio_iov = &iv; 2420 io.uio_iovcnt = 1; 2421 io.uio_offset = (off_t)off; 2422 io.uio_resid = fullsiz; 2423 io.uio_segflg = UIO_SYSSPACE; 2424 io.uio_rw = UIO_READ; 2425 io.uio_procp = NULL; 2426 eofflag = 0; 2427 2428 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2429 error = VOP_READDIR(vp, &io, cred, &eofflag); 2430 2431 off = (off_t)io.uio_offset; 2432 if (info.nmi_v3) { 2433 getret = VOP_GETATTR(vp, &at, cred, procp); 2434 if (!error) 2435 error = getret; 2436 } 2437 2438 VOP_UNLOCK(vp); 2439 if (error) { 2440 vrele(vp); 2441 free(rbuf, M_TEMP, fullsiz); 2442 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2443 NFSX_POSTOPATTR(info.nmi_v3)) != 0) 2444 return 0; 2445 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2446 error = 0; 2447 goto nfsmout; 2448 } 2449 if (io.uio_resid) { 2450 siz -= io.uio_resid; 2451 2452 /* 2453 * If nothing read, return eof 2454 * rpc reply 2455 */ 2456 if (siz == 0) { 2457 vrele(vp); 2458 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2459 NFSX_POSTOPATTR(info.nmi_v3) + 2460 NFSX_COOKIEVERF(info.nmi_v3) + 2461 2 * NFSX_UNSIGNED) != 0) 2462 return 0; 2463 if (info.nmi_v3) { 2464 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2465 tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED); 2466 txdr_hyper(at.va_filerev, tl); 2467 tl += 2; 2468 } else 2469 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2470 *tl++ = nfs_false; 2471 *tl = nfs_true; 2472 free(rbuf, M_TEMP, fullsiz); 2473 error = 0; 2474 goto nfsmout; 2475 } 2476 } 2477 2478 /* 2479 * Check for degenerate cases of nothing useful read. 2480 * If so go try again 2481 */ 2482 cpos = rbuf; 2483 cend = rbuf + siz; 2484 dp = (struct dirent *)cpos; 2485 2486 while (cpos < cend && dp->d_fileno == 0) { 2487 cpos += dp->d_reclen; 2488 dp = (struct dirent *)cpos; 2489 } 2490 if (cpos >= cend) { 2491 toff = off; 2492 siz = fullsiz; 2493 goto again; 2494 } 2495 2496 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 2497 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2498 NFSX_POSTOPATTR(info.nmi_v3) + 2499 NFSX_COOKIEVERF(info.nmi_v3) + siz) != 0) 2500 return 0; 2501 if (info.nmi_v3) { 2502 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2503 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2504 txdr_hyper(at.va_filerev, tl); 2505 } 2506 2507 /* Loop through the records and build reply */ 2508 while (cpos < cend) { 2509 if (dp->d_fileno != 0) { 2510 nlen = dp->d_namlen; 2511 pad = nfsm_padlen(nlen); 2512 len += (4 * NFSX_UNSIGNED + nlen + pad); 2513 if (info.nmi_v3) 2514 len += 2 * NFSX_UNSIGNED; 2515 if (len > cnt) { 2516 eofflag = 0; 2517 break; 2518 } 2519 /* 2520 * Build the directory record xdr from 2521 * the dirent entry. 2522 */ 2523 tl = nfsm_build(&info.nmi_mb, 2524 (info.nmi_v3 ? 3 : 2) * NFSX_UNSIGNED); 2525 *tl++ = nfs_true; 2526 if (info.nmi_v3) 2527 txdr_hyper(dp->d_fileno, tl); 2528 else 2529 *tl = txdr_unsigned((u_int32_t)dp->d_fileno); 2530 2531 /* And copy the name */ 2532 nfsm_strtombuf(&info.nmi_mb, dp->d_name, nlen); 2533 2534 /* Finish off the record */ 2535 if (info.nmi_v3) { 2536 tl = nfsm_build(&info.nmi_mb, 2*NFSX_UNSIGNED); 2537 txdr_hyper(dp->d_off, tl); 2538 } else { 2539 tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED); 2540 *tl = txdr_unsigned((u_int32_t)dp->d_off); 2541 } 2542 } 2543 cpos += dp->d_reclen; 2544 dp = (struct dirent *)cpos; 2545 } 2546 vrele(vp); 2547 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2548 *tl++ = nfs_false; 2549 if (eofflag) 2550 *tl = nfs_true; 2551 else 2552 *tl = nfs_false; 2553 free(rbuf, M_TEMP, fullsiz); 2554 nfsmout: 2555 return(error); 2556 } 2557 2558 int 2559 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2560 struct proc *procp, struct mbuf **mrq) 2561 { 2562 struct mbuf *nam = nfsd->nd_nam; 2563 struct ucred *cred = &nfsd->nd_cr; 2564 struct dirent *dp; 2565 struct nfsm_info info; 2566 u_int32_t *tl; 2567 char *cpos, *cend, *rbuf; 2568 struct vnode *vp, *nvp; 2569 struct flrep fl; 2570 nfsfh_t nfh; 2571 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh; 2572 struct uio io; 2573 struct iovec iv; 2574 struct vattr va, at, *vap = &va; 2575 struct nfs_fattr *fp; 2576 int len, nlen, pad, xfer, error = 0, getret = 1; 2577 int siz, cnt, fullsiz, eofflag, rdonly, dirlen; 2578 u_quad_t off, toff, verf; 2579 2580 info.nmi_mreq = NULL; 2581 info.nmi_mrep = nfsd->nd_mrep; 2582 info.nmi_md = nfsd->nd_md; 2583 info.nmi_dpos = nfsd->nd_dpos; 2584 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2585 info.nmi_errorp = &error; 2586 2587 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 2588 return 0; 2589 else if (error != 0) 2590 goto nfsmout; 2591 fhp = &nfh.fh_generic; 2592 if (nfsm_srvmtofh2(&info, fhp) != 0) 2593 goto nfsmout; 2594 tl = (uint32_t *)nfsm_dissect(&info, 6 * NFSX_UNSIGNED); 2595 if (tl == NULL) 2596 goto nfsmout; 2597 off = toff = fxdr_hyper(tl); 2598 tl += 2; 2599 verf = fxdr_hyper(tl); 2600 tl += 2; 2601 siz = fxdr_unsigned(int, *tl++); 2602 cnt = fxdr_unsigned(int, *tl); 2603 xfer = NFS_SRVMAXDATA(nfsd); 2604 if (cnt > xfer || cnt < 0) 2605 cnt = xfer; 2606 siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); 2607 if (siz > xfer) 2608 siz = xfer; 2609 fullsiz = siz; 2610 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2611 if (error) { 2612 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2613 NFSX_UNSIGNED) != 0) 2614 return 0; 2615 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2616 error = 0; 2617 goto nfsmout; 2618 } 2619 error = getret = VOP_GETATTR(vp, &at, cred, procp); 2620 if (!error) 2621 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0); 2622 if (error) { 2623 vput(vp); 2624 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2625 NFSX_V3POSTOPATTR) != 0) 2626 return 0; 2627 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2628 error = 0; 2629 goto nfsmout; 2630 } 2631 VOP_UNLOCK(vp); 2632 2633 rbuf = malloc(fullsiz, M_TEMP, M_WAITOK); 2634 again: 2635 iv.iov_base = rbuf; 2636 iv.iov_len = fullsiz; 2637 io.uio_iov = &iv; 2638 io.uio_iovcnt = 1; 2639 io.uio_offset = (off_t)off; 2640 io.uio_resid = fullsiz; 2641 io.uio_segflg = UIO_SYSSPACE; 2642 io.uio_rw = UIO_READ; 2643 io.uio_procp = NULL; 2644 eofflag = 0; 2645 2646 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 2647 error = VOP_READDIR(vp, &io, cred, &eofflag); 2648 2649 off = (u_quad_t)io.uio_offset; 2650 getret = VOP_GETATTR(vp, &at, cred, procp); 2651 2652 VOP_UNLOCK(vp); 2653 2654 if (!error) 2655 error = getret; 2656 if (error) { 2657 vrele(vp); 2658 free(rbuf, M_TEMP, fullsiz); 2659 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2660 NFSX_V3POSTOPATTR) != 0) 2661 return 0; 2662 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2663 error = 0; 2664 goto nfsmout; 2665 } 2666 if (io.uio_resid) { 2667 siz -= io.uio_resid; 2668 2669 /* 2670 * If nothing read, return eof 2671 * rpc reply 2672 */ 2673 if (siz == 0) { 2674 vrele(vp); 2675 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2676 NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2677 2 * NFSX_UNSIGNED) != 0) 2678 return 0; 2679 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2680 tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED); 2681 txdr_hyper(at.va_filerev, tl); 2682 tl += 2; 2683 *tl++ = nfs_false; 2684 *tl = nfs_true; 2685 free(rbuf, M_TEMP, fullsiz); 2686 error = 0; 2687 goto nfsmout; 2688 } 2689 } 2690 2691 /* 2692 * Check for degenerate cases of nothing useful read. 2693 * If so go try again 2694 */ 2695 cpos = rbuf; 2696 cend = rbuf + siz; 2697 dp = (struct dirent *)cpos; 2698 2699 while (cpos < cend && dp->d_fileno == 0) { 2700 cpos += dp->d_reclen; 2701 dp = (struct dirent *)cpos; 2702 } 2703 if (cpos >= cend) { 2704 toff = off; 2705 siz = fullsiz; 2706 goto again; 2707 } 2708 2709 /* 2710 * struct READDIRPLUS3resok { 2711 * postop_attr dir_attributes; 2712 * cookieverf3 cookieverf; 2713 * dirlistplus3 reply; 2714 * } 2715 * 2716 * struct dirlistplus3 { 2717 * entryplus3 *entries; 2718 * bool eof; 2719 * } 2720 */ 2721 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED; 2722 if (nfsm_reply(&info, nfsd, slp, mrq, error, cnt) != 0) 2723 return 0; 2724 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2725 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2726 txdr_hyper(at.va_filerev, tl); 2727 2728 /* Loop through the records and build reply */ 2729 while (cpos < cend) { 2730 if (dp->d_fileno != 0) { 2731 nlen = dp->d_namlen; 2732 pad = nfsm_padlen(nlen); 2733 2734 /* 2735 * For readdir_and_lookup get the vnode using 2736 * the file number. 2737 */ 2738 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 2739 goto invalid; 2740 memset(nfhp, 0, NFSX_V3FH); 2741 nfhp->fh_fsid = 2742 nvp->v_mount->mnt_stat.f_fsid; 2743 if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { 2744 vput(nvp); 2745 goto invalid; 2746 } 2747 if (VOP_GETATTR(nvp, vap, cred, procp)) { 2748 vput(nvp); 2749 goto invalid; 2750 } 2751 vput(nvp); 2752 2753 /* 2754 * If either the dircount or maxcount will be 2755 * exceeded, get out now. Both of these lengths 2756 * are calculated conservatively, including all 2757 * XDR overheads. 2758 * 2759 * Each entry: 2760 * 2 * NFSX_UNSIGNED for fileid3 2761 * 1 * NFSX_UNSIGNED for length of name 2762 * nlen + pad == space the name takes up 2763 * 2 * NFSX_UNSIGNED for the cookie 2764 * 1 * NFSX_UNSIGNED to indicate if file handle present 2765 * 1 * NFSX_UNSIGNED for the file handle length 2766 * NFSX_V3FH == space our file handle takes up 2767 * NFSX_V3POSTOPATTR == space the attributes take up 2768 * 1 * NFSX_UNSIGNED for next pointer 2769 */ 2770 len += (8 * NFSX_UNSIGNED + nlen + pad + NFSX_V3FH + 2771 NFSX_V3POSTOPATTR); 2772 dirlen += (6 * NFSX_UNSIGNED + nlen + pad); 2773 if (len > cnt || dirlen > fullsiz) { 2774 eofflag = 0; 2775 break; 2776 } 2777 2778 tl = nfsm_build(&info.nmi_mb, 3 * NFSX_UNSIGNED); 2779 *tl++ = nfs_true; 2780 txdr_hyper(dp->d_fileno, tl); 2781 2782 /* And copy the name */ 2783 nfsm_strtombuf(&info.nmi_mb, dp->d_name, nlen); 2784 2785 /* 2786 * Build the directory record xdr from 2787 * the dirent entry. 2788 */ 2789 fp = (struct nfs_fattr *)&fl.fl_fattr; 2790 nfsm_srvfattr(nfsd, vap, fp); 2791 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); 2792 fl.fl_fhok = nfs_true; 2793 fl.fl_postopok = nfs_true; 2794 txdr_hyper(dp->d_off, fl.fl_off.nfsuquad); 2795 2796 /* Now copy the flrep structure out. */ 2797 nfsm_buftombuf(&info.nmi_mb, &fl, sizeof(struct flrep)); 2798 } 2799 invalid: 2800 cpos += dp->d_reclen; 2801 dp = (struct dirent *)cpos; 2802 } 2803 vrele(vp); 2804 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2805 *tl++ = nfs_false; 2806 if (eofflag) 2807 *tl = nfs_true; 2808 else 2809 *tl = nfs_false; 2810 free(rbuf, M_TEMP, fullsiz); 2811 nfsmout: 2812 return(error); 2813 } 2814 2815 /* 2816 * nfs commit service 2817 */ 2818 int 2819 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2820 struct proc *procp, struct mbuf **mrq) 2821 { 2822 struct mbuf *nam = nfsd->nd_nam; 2823 struct ucred *cred = &nfsd->nd_cr; 2824 struct vattr bfor, aft; 2825 struct vnode *vp; 2826 struct nfsm_info info; 2827 struct timeval boottime; 2828 nfsfh_t nfh; 2829 fhandle_t *fhp; 2830 u_int32_t *tl; 2831 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt; 2832 u_quad_t off; 2833 2834 info.nmi_mreq = NULL; 2835 info.nmi_mrep = nfsd->nd_mrep; 2836 info.nmi_md = nfsd->nd_md; 2837 info.nmi_dpos = nfsd->nd_dpos; 2838 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2839 info.nmi_errorp = &error; 2840 2841 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 2842 return 0; 2843 else if (error != 0) 2844 goto nfsmout; 2845 fhp = &nfh.fh_generic; 2846 if (nfsm_srvmtofh2(&info, fhp) != 0) 2847 goto nfsmout; 2848 tl = (uint32_t *)nfsm_dissect(&info, 3 * NFSX_UNSIGNED); 2849 if (tl == NULL) 2850 goto nfsmout; 2851 2852 /* 2853 * XXX At this time VOP_FSYNC() does not accept offset and byte 2854 * count parameters, so these arguments are useless (someday maybe). 2855 */ 2856 off = fxdr_hyper(tl); 2857 tl += 2; 2858 cnt = fxdr_unsigned(int, *tl); 2859 if (cnt < 0) 2860 cnt = 0; 2861 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2862 if (error) { 2863 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2864 2 * NFSX_UNSIGNED) != 0) 2865 return 0; 2866 nfsm_srvwcc(nfsd, for_ret, &bfor, aft_ret, &aft, &info); 2867 error = 0; 2868 goto nfsmout; 2869 } 2870 for_ret = VOP_GETATTR(vp, &bfor, cred, procp); 2871 error = VOP_FSYNC(vp, cred, MNT_WAIT, procp); 2872 aft_ret = VOP_GETATTR(vp, &aft, cred, procp); 2873 vput(vp); 2874 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2875 NFSX_V3WCCDATA + NFSX_V3WRITEVERF) != 0) 2876 return 0; 2877 nfsm_srvwcc(nfsd, for_ret, &bfor, aft_ret, &aft, &info); 2878 if (!error) { 2879 tl = nfsm_build(&info.nmi_mb, NFSX_V3WRITEVERF); 2880 microboottime(&boottime); 2881 *tl++ = txdr_unsigned(boottime.tv_sec); 2882 *tl = txdr_unsigned(boottime.tv_usec); 2883 } else 2884 error = 0; 2885 nfsmout: 2886 return(error); 2887 } 2888 2889 /* 2890 * nfs statfs service 2891 */ 2892 int 2893 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2894 struct proc *procp, struct mbuf **mrq) 2895 { 2896 struct mbuf *nam = nfsd->nd_nam; 2897 struct ucred *cred = &nfsd->nd_cr; 2898 struct statfs *sf; 2899 struct nfs_statfs *sfp; 2900 struct nfsm_info info; 2901 int error = 0, rdonly, getret = 1; 2902 struct vnode *vp; 2903 struct vattr at; 2904 nfsfh_t nfh; 2905 fhandle_t *fhp; 2906 struct statfs statfs; 2907 u_quad_t tval; 2908 2909 info.nmi_mreq = NULL; 2910 info.nmi_mrep = nfsd->nd_mrep; 2911 info.nmi_md = nfsd->nd_md; 2912 info.nmi_dpos = nfsd->nd_dpos; 2913 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2914 info.nmi_errorp = &error; 2915 2916 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 2917 return 0; 2918 else if (error != 0) 2919 goto nfsmout; 2920 fhp = &nfh.fh_generic; 2921 if (nfsm_srvmtofh2(&info, fhp) != 0) 2922 goto nfsmout; 2923 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2924 if (error) { 2925 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2926 NFSX_UNSIGNED) != 0) 2927 return 0; 2928 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2929 error = 0; 2930 goto nfsmout; 2931 } 2932 sf = &statfs; 2933 error = VFS_STATFS(vp->v_mount, sf, procp); 2934 getret = VOP_GETATTR(vp, &at, cred, procp); 2935 vput(vp); 2936 if (nfsm_reply(&info, nfsd, slp, mrq, error, 2937 NFSX_POSTOPATTR(info.nmi_v3) + NFSX_STATFS(info.nmi_v3)) != 0) 2938 return 0; 2939 if (info.nmi_v3) 2940 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2941 if (error) { 2942 error = 0; 2943 goto nfsmout; 2944 } 2945 sfp = nfsm_build(&info.nmi_mb, NFSX_STATFS(info.nmi_v3)); 2946 if (info.nmi_v3) { 2947 tval = (u_quad_t)sf->f_blocks; 2948 tval *= (u_quad_t)sf->f_bsize; 2949 txdr_hyper(tval, &sfp->sf_tbytes); 2950 tval = (u_quad_t)sf->f_bfree; 2951 tval *= (u_quad_t)sf->f_bsize; 2952 txdr_hyper(tval, &sfp->sf_fbytes); 2953 tval = (u_quad_t)sf->f_bavail; 2954 tval *= (u_quad_t)sf->f_bsize; 2955 txdr_hyper(tval, &sfp->sf_abytes); 2956 tval = (u_quad_t)sf->f_files; 2957 txdr_hyper(tval, &sfp->sf_tfiles); 2958 tval = (u_quad_t)sf->f_ffree; 2959 txdr_hyper(tval, &sfp->sf_ffiles); 2960 txdr_hyper(tval, &sfp->sf_afiles); 2961 sfp->sf_invarsec = 0; 2962 } else { 2963 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 2964 sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 2965 sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 2966 sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 2967 sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 2968 } 2969 nfsmout: 2970 return(error); 2971 } 2972 2973 /* 2974 * nfs fsinfo service 2975 */ 2976 int 2977 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2978 struct proc *procp, struct mbuf **mrq) 2979 { 2980 struct mbuf *nam = nfsd->nd_nam; 2981 struct ucred *cred = &nfsd->nd_cr; 2982 struct nfsm_info info; 2983 struct nfsv3_fsinfo *sip; 2984 int error = 0, rdonly, getret = 1, pref; 2985 struct vnode *vp; 2986 struct vattr at; 2987 nfsfh_t nfh; 2988 fhandle_t *fhp; 2989 2990 info.nmi_mreq = NULL; 2991 info.nmi_mrep = nfsd->nd_mrep; 2992 info.nmi_md = nfsd->nd_md; 2993 info.nmi_dpos = nfsd->nd_dpos; 2994 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2995 info.nmi_errorp = &error; 2996 2997 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 2998 return 0; 2999 else if (error != 0) 3000 goto nfsmout; 3001 fhp = &nfh.fh_generic; 3002 if (nfsm_srvmtofh2(&info, fhp) != 0) 3003 goto nfsmout; 3004 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 3005 if (error) { 3006 if (nfsm_reply(&info, nfsd, slp, mrq, error, 3007 NFSX_UNSIGNED) != 0) 3008 return 0; 3009 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 3010 error = 0; 3011 goto nfsmout; 3012 } 3013 getret = VOP_GETATTR(vp, &at, cred, procp); 3014 vput(vp); 3015 if (nfsm_reply(&info, nfsd, slp, mrq, error, 3016 NFSX_V3POSTOPATTR + NFSX_V3FSINFO) != 0) 3017 return 0; 3018 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 3019 sip = nfsm_build(&info.nmi_mb, NFSX_V3FSINFO); 3020 3021 /* 3022 * XXX 3023 * There should be file system VFS OP(s) to get this information. 3024 * For now, assume ufs. 3025 */ 3026 if (slp->ns_so->so_type == SOCK_DGRAM) 3027 pref = NFS_MAXDGRAMDATA; 3028 else 3029 pref = NFS_MAXDATA; 3030 sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA); 3031 sip->fs_rtpref = txdr_unsigned(pref); 3032 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); 3033 sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA); 3034 sip->fs_wtpref = txdr_unsigned(pref); 3035 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); 3036 sip->fs_dtpref = txdr_unsigned(pref); 3037 sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff; 3038 sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff; 3039 sip->fs_timedelta.nfsv3_sec = 0; 3040 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); 3041 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | 3042 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | 3043 NFSV3FSINFO_CANSETTIME); 3044 nfsmout: 3045 return(error); 3046 } 3047 3048 /* 3049 * nfs pathconf service 3050 */ 3051 int 3052 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3053 struct proc *procp, struct mbuf **mrq) 3054 { 3055 struct mbuf *nam = nfsd->nd_nam; 3056 struct ucred *cred = &nfsd->nd_cr; 3057 struct nfsm_info info; 3058 struct nfsv3_pathconf *pc; 3059 int error = 0, rdonly, getret = 1; 3060 register_t linkmax, namemax, chownres, notrunc; 3061 struct vnode *vp; 3062 struct vattr at; 3063 nfsfh_t nfh; 3064 fhandle_t *fhp; 3065 3066 info.nmi_mreq = NULL; 3067 info.nmi_mrep = nfsd->nd_mrep; 3068 info.nmi_md = nfsd->nd_md; 3069 info.nmi_dpos = nfsd->nd_dpos; 3070 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 3071 info.nmi_errorp = &error; 3072 3073 if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0) 3074 return 0; 3075 else if (error != 0) 3076 goto nfsmout; 3077 fhp = &nfh.fh_generic; 3078 if (nfsm_srvmtofh2(&info, fhp) != 0) 3079 goto nfsmout; 3080 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 3081 if (error) { 3082 if (nfsm_reply(&info, nfsd, slp, mrq, error, 3083 NFSX_UNSIGNED) != 0) 3084 return 0; 3085 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 3086 error = 0; 3087 goto nfsmout; 3088 } 3089 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); 3090 if (!error) 3091 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); 3092 if (!error) 3093 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); 3094 if (!error) 3095 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); 3096 getret = VOP_GETATTR(vp, &at, cred, procp); 3097 vput(vp); 3098 if (nfsm_reply(&info, nfsd, slp, mrq, error, 3099 NFSX_V3POSTOPATTR + NFSX_V3PATHCONF) != 0) 3100 return 0; 3101 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 3102 if (error) { 3103 error = 0; 3104 goto nfsmout; 3105 } 3106 pc = nfsm_build(&info.nmi_mb, NFSX_V3PATHCONF); 3107 3108 pc->pc_linkmax = txdr_unsigned(linkmax); 3109 pc->pc_namemax = txdr_unsigned(namemax); 3110 pc->pc_notrunc = txdr_unsigned(notrunc); 3111 pc->pc_chownrestricted = txdr_unsigned(chownres); 3112 3113 /* 3114 * These should probably be supported by VOP_PATHCONF(), but 3115 * until msdosfs is exportable (why would you want to?), the 3116 * Unix defaults should be ok. 3117 */ 3118 pc->pc_caseinsensitive = nfs_false; 3119 pc->pc_casepreserving = nfs_true; 3120 nfsmout: 3121 return(error); 3122 } 3123 3124 /* 3125 * Null operation, used by clients to ping server 3126 */ 3127 int 3128 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3129 struct proc *procp, struct mbuf **mrq) 3130 { 3131 struct nfsm_info info; 3132 int error = NFSERR_RETVOID; 3133 3134 info.nmi_mreq = NULL; 3135 info.nmi_mrep = nfsd->nd_mrep; 3136 info.nmi_md = nfsd->nd_md; 3137 info.nmi_dpos = nfsd->nd_dpos; 3138 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 3139 info.nmi_errorp = &error; 3140 3141 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 3142 return 0; 3143 return (0); 3144 } 3145 3146 /* 3147 * No operation, used for obsolete procedures 3148 */ 3149 int 3150 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 3151 struct proc *procp, struct mbuf **mrq) 3152 { 3153 struct nfsm_info info; 3154 int error; 3155 3156 info.nmi_mreq = NULL; 3157 info.nmi_mrep = nfsd->nd_mrep; 3158 info.nmi_md = nfsd->nd_md; 3159 info.nmi_dpos = nfsd->nd_dpos; 3160 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 3161 info.nmi_errorp = &error; 3162 3163 if (nfsd->nd_repstat) 3164 error = nfsd->nd_repstat; 3165 else 3166 error = EPROCUNAVAIL; 3167 if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0) 3168 return 0; 3169 return (0); 3170 } 3171 3172 /* 3173 * Perform access checking for vnodes obtained from file handles that would 3174 * refer to files already opened by a Unix client. 3175 * You cannot just use vn_writechk() and VOP_ACCESS() for two reasons: 3176 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the 3177 * write case 3178 * 2 - The owner is to be given access irrespective of mode bits for some 3179 * operations, so that processes that chmod after opening a file don't 3180 * break. I don't like this because it opens a security hole, but since 3181 * the nfs server opens a security hole the size of a barn door anyhow, 3182 * what the heck. A notable exception to this rule is when VOP_ACCESS() 3183 * returns EPERM (e.g. when a file is immutable) which is always an 3184 * error. 3185 */ 3186 int 3187 nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly, 3188 struct proc *p, int override) 3189 { 3190 struct vattr vattr; 3191 int error; 3192 3193 if (flags & VWRITE) { 3194 /* Just vn_writechk() changed to check rdonly */ 3195 /* 3196 * Disallow write attempts on read-only file systems; 3197 * unless the file is a socket or a block or character 3198 * device resident on the file system. 3199 */ 3200 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 3201 switch (vp->v_type) { 3202 case VREG: 3203 case VDIR: 3204 case VLNK: 3205 return (EROFS); 3206 default: 3207 break; 3208 } 3209 } 3210 /* 3211 * If there's shared text associated with 3212 * the inode, try to free it up once. If 3213 * we fail, we can't allow writing. 3214 */ 3215 if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp)) 3216 return (ETXTBSY); 3217 } 3218 error = VOP_ACCESS(vp, flags, cred, p); 3219 /* 3220 * Allow certain operations for the owner (reads and writes 3221 * on files that are already open). 3222 */ 3223 if (override && error == EACCES && 3224 VOP_GETATTR(vp, &vattr, cred, p) == 0 && 3225 cred->cr_uid == vattr.va_uid) 3226 error = 0; 3227 return error; 3228 } 3229