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