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