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