1 /* $OpenBSD: nfs_serv.c,v 1.91 2010/09/09 10:37:04 thib 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 (info.nmi_v3) 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 vrele(dirp); 1138 return (0); 1139 } 1140 1141 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1142 vtyp = nfsv3tov_type(*tl); 1143 if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { 1144 vrele(nd.ni_startdir); 1145 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1146 error = NFSERR_BADTYPE; 1147 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1148 vput(nd.ni_dvp); 1149 goto out; 1150 } 1151 VATTR_NULL(&va); 1152 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, &info.nmi_dpos); 1153 if (error) 1154 goto nfsmout; 1155 if (vtyp == VCHR || vtyp == VBLK) { 1156 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1157 major = fxdr_unsigned(u_int32_t, *tl++); 1158 minor = fxdr_unsigned(u_int32_t, *tl); 1159 va.va_rdev = makedev(major, minor); 1160 } 1161 1162 /* 1163 * Iff doesn't exist, create it. 1164 */ 1165 if (nd.ni_vp) { 1166 vrele(nd.ni_startdir); 1167 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1168 error = EEXIST; 1169 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1170 vput(nd.ni_dvp); 1171 goto out; 1172 } 1173 va.va_type = vtyp; 1174 if (vtyp == VSOCK) { 1175 vrele(nd.ni_startdir); 1176 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1177 if (!error) 1178 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1179 } else { 1180 if (va.va_type != VFIFO && 1181 (error = suser_ucred(cred))) { 1182 vrele(nd.ni_startdir); 1183 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1184 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1185 vput(nd.ni_dvp); 1186 goto out; 1187 } 1188 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1189 if (error) { 1190 vrele(nd.ni_startdir); 1191 goto out; 1192 } 1193 nd.ni_cnd.cn_nameiop = LOOKUP; 1194 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART); 1195 nd.ni_cnd.cn_proc = procp; 1196 nd.ni_cnd.cn_cred = procp->p_ucred; 1197 error = vfs_lookup(&nd); 1198 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1199 if (error) 1200 goto out; 1201 if (nd.ni_cnd.cn_flags & ISSYMLINK) { 1202 vrele(nd.ni_dvp); 1203 vput(nd.ni_vp); 1204 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1205 error = EINVAL; 1206 } 1207 } 1208 out: 1209 vp = nd.ni_vp; 1210 if (!error) { 1211 bzero((caddr_t)fhp, sizeof(nfh)); 1212 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1213 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1214 if (!error) 1215 error = VOP_GETATTR(vp, &va, cred, procp); 1216 vput(vp); 1217 } 1218 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1219 vrele(dirp); 1220 nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)); 1221 if (!error) { 1222 nfsm_srvpostop_fh(fhp); 1223 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 1224 } 1225 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, &info); 1226 return (0); 1227 nfsmout: 1228 if (dirp) 1229 vrele(dirp); 1230 if (nd.ni_cnd.cn_nameiop) { 1231 vrele(nd.ni_startdir); 1232 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1233 } 1234 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1235 if (nd.ni_dvp == nd.ni_vp) 1236 vrele(nd.ni_dvp); 1237 else 1238 vput(nd.ni_dvp); 1239 if (nd.ni_vp) 1240 vput(nd.ni_vp); 1241 return (error); 1242 } 1243 1244 /* 1245 * nfs remove service 1246 */ 1247 int 1248 nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1249 struct proc *procp, struct mbuf **mrq) 1250 { 1251 struct mbuf *nam = nfsd->nd_nam; 1252 struct ucred *cred = &nfsd->nd_cr; 1253 struct nameidata nd; 1254 struct nfsm_info info; 1255 u_int32_t *tl; 1256 int32_t t1; 1257 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1258 char *cp2; 1259 struct vnode *vp, *dirp; 1260 struct vattr dirfor, diraft; 1261 nfsfh_t nfh; 1262 fhandle_t *fhp; 1263 1264 info.nmi_mreq = NULL; 1265 info.nmi_mrep = nfsd->nd_mrep; 1266 info.nmi_md = nfsd->nd_md; 1267 info.nmi_dpos = nfsd->nd_dpos; 1268 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1269 1270 vp = NULL; 1271 1272 fhp = &nfh.fh_generic; 1273 nfsm_srvmtofh(fhp); 1274 nfsm_srvnamesiz(len); 1275 nd.ni_cnd.cn_cred = cred; 1276 nd.ni_cnd.cn_nameiop = DELETE; 1277 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 1278 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp); 1279 if (dirp) { 1280 if (info.nmi_v3) 1281 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 1282 else { 1283 vrele(dirp); 1284 dirp = NULL; 1285 } 1286 } 1287 1288 if (!error) { 1289 vp = nd.ni_vp; 1290 if (vp->v_type == VDIR && 1291 (error = suser_ucred(cred)) != 0) 1292 goto out; 1293 /* 1294 * The root of a mounted filesystem cannot be deleted. 1295 */ 1296 if (vp->v_flag & VROOT) { 1297 error = EBUSY; 1298 goto out; 1299 } 1300 if (vp->v_flag & VTEXT) 1301 uvm_vnp_uncache(vp); 1302 out: 1303 if (!error) { 1304 error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1305 } else { 1306 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1307 if (nd.ni_dvp == vp) 1308 vrele(nd.ni_dvp); 1309 else 1310 vput(nd.ni_dvp); 1311 vput(vp); 1312 } 1313 } 1314 if (dirp && info.nmi_v3) { 1315 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1316 vrele(dirp); 1317 } 1318 nfsm_reply(NFSX_WCCDATA(info.nmi_v3)); 1319 if (info.nmi_v3) { 1320 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1321 &info); 1322 return (0); 1323 } 1324 1325 nfsmout: 1326 return(error); 1327 } 1328 1329 /* 1330 * nfs rename service 1331 */ 1332 int 1333 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1334 struct proc *procp, struct mbuf **mrq) 1335 { 1336 struct mbuf *nam = nfsd->nd_nam; 1337 struct ucred *cred = &nfsd->nd_cr; 1338 struct nfsm_info info; 1339 u_int32_t *tl; 1340 int32_t t1; 1341 int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1; 1342 int tdirfor_ret = 1, tdiraft_ret = 1; 1343 char *cp2; 1344 struct nameidata fromnd, tond; 1345 struct vnode *fvp = NULL, *tvp, *tdvp, *fdirp = NULL; 1346 struct vnode *tdirp = NULL; 1347 struct vattr fdirfor, fdiraft, tdirfor, tdiraft; 1348 nfsfh_t fnfh, tnfh; 1349 fhandle_t *ffhp, *tfhp; 1350 uid_t saved_uid; 1351 1352 info.nmi_mreq = NULL; 1353 info.nmi_mrep = nfsd->nd_mrep; 1354 info.nmi_md = nfsd->nd_md; 1355 info.nmi_dpos = nfsd->nd_dpos; 1356 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1357 1358 ffhp = &fnfh.fh_generic; 1359 tfhp = &tnfh.fh_generic; 1360 fromnd.ni_cnd.cn_nameiop = 0; 1361 tond.ni_cnd.cn_nameiop = 0; 1362 nfsm_srvmtofh(ffhp); 1363 nfsm_srvnamesiz(len); 1364 1365 /* 1366 * Remember our original uid so that we can reset cr_uid before 1367 * the second nfs_namei() call, in case it is remapped. 1368 */ 1369 saved_uid = cred->cr_uid; 1370 fromnd.ni_cnd.cn_cred = cred; 1371 fromnd.ni_cnd.cn_nameiop = DELETE; 1372 fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART; 1373 error = nfs_namei(&fromnd, ffhp, len, slp, nam, &info.nmi_md, 1374 &info.nmi_dpos, &fdirp, procp); 1375 if (fdirp) { 1376 if (info.nmi_v3) 1377 fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred, 1378 procp); 1379 else { 1380 vrele(fdirp); 1381 fdirp = NULL; 1382 } 1383 } 1384 if (error) { 1385 nfsm_reply(2 * NFSX_WCCDATA(info.nmi_v3)); 1386 nfsm_srvwcc(nfsd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft, 1387 &info); 1388 nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft, 1389 &info); 1390 if (info.nmi_v3) 1391 vrele(fdirp); 1392 return (0); 1393 } 1394 1395 fvp = fromnd.ni_vp; 1396 nfsm_srvmtofh(tfhp); 1397 nfsm_strsiz(len2, NFS_MAXNAMLEN); 1398 cred->cr_uid = saved_uid; 1399 tond.ni_cnd.cn_cred = cred; 1400 tond.ni_cnd.cn_nameiop = RENAME; 1401 tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART; 1402 error = nfs_namei(&tond, tfhp, len2, slp, nam, &info.nmi_md, 1403 &info.nmi_dpos, &tdirp, procp); 1404 if (tdirp) { 1405 if (info.nmi_v3) 1406 tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred, 1407 procp); 1408 else { 1409 vrele(tdirp); 1410 tdirp = NULL; 1411 } 1412 } 1413 if (error) { 1414 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1415 vrele(fromnd.ni_dvp); 1416 vrele(fvp); 1417 goto out1; 1418 } 1419 tdvp = tond.ni_dvp; 1420 tvp = tond.ni_vp; 1421 if (tvp != NULL) { 1422 if (fvp->v_type == VDIR && tvp->v_type != VDIR) { 1423 error = info.nmi_v3 ? EEXIST : EISDIR; 1424 goto out; 1425 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) { 1426 error = info.nmi_v3 ? EEXIST : ENOTDIR; 1427 goto out; 1428 } 1429 if (tvp->v_type == VDIR && tvp->v_mountedhere) { 1430 error = info.nmi_v3 ? EXDEV : ENOTEMPTY; 1431 goto out; 1432 } 1433 } 1434 if (fvp->v_type == VDIR && fvp->v_mountedhere) { 1435 error = info.nmi_v3 ? EXDEV : ENOTEMPTY; 1436 goto out; 1437 } 1438 if (fvp->v_mount != tdvp->v_mount) { 1439 error = info.nmi_v3 ? EXDEV : ENOTEMPTY; 1440 goto out; 1441 } 1442 if (fvp == tdvp) 1443 error = info.nmi_v3 ? EINVAL : ENOTEMPTY; 1444 /* 1445 * If source is the same as the destination (that is the 1446 * same vnode with the same name in the same directory), 1447 * then there is nothing to do. 1448 */ 1449 if (fvp == tvp && fromnd.ni_dvp == tdvp && 1450 fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen && 1451 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr, 1452 fromnd.ni_cnd.cn_namelen)) 1453 error = -1; 1454 out: 1455 if (!error) { 1456 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd, 1457 tond.ni_dvp, tond.ni_vp, &tond.ni_cnd); 1458 } else { 1459 VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd); 1460 if (tdvp == tvp) 1461 vrele(tdvp); 1462 else 1463 vput(tdvp); 1464 if (tvp) 1465 vput(tvp); 1466 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1467 vrele(fromnd.ni_dvp); 1468 vrele(fvp); 1469 if (error == -1) 1470 error = 0; 1471 } 1472 vrele(tond.ni_startdir); 1473 pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf); 1474 out1: 1475 if (fdirp) { 1476 fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp); 1477 vrele(fdirp); 1478 } 1479 if (tdirp) { 1480 tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp); 1481 vrele(tdirp); 1482 } 1483 vrele(fromnd.ni_startdir); 1484 pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf); 1485 nfsm_reply(2 * NFSX_WCCDATA(info.nmi_v3)); 1486 if (info.nmi_v3) { 1487 nfsm_srvwcc(nfsd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft, 1488 &info); 1489 nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft, 1490 &info); 1491 } 1492 return (0); 1493 1494 nfsmout: 1495 if (fdirp) 1496 vrele(fdirp); 1497 if (tdirp) 1498 vrele(tdirp); 1499 if (tond.ni_cnd.cn_nameiop) { 1500 vrele(tond.ni_startdir); 1501 pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf); 1502 } 1503 if (fromnd.ni_cnd.cn_nameiop) { 1504 if (fromnd.ni_startdir) 1505 vrele(fromnd.ni_startdir); 1506 VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd); 1507 1508 /* 1509 * XXX: Workaround the fact that fromnd.ni_dvp can point 1510 * to the same vnode as fdirp. 1511 */ 1512 if (fromnd.ni_dvp != NULL && fromnd.ni_dvp != fdirp) 1513 vrele(fromnd.ni_dvp); 1514 if (fvp) 1515 vrele(fvp); 1516 } 1517 return (error); 1518 } 1519 1520 /* 1521 * nfs link service 1522 */ 1523 int 1524 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1525 struct proc *procp, struct mbuf **mrq) 1526 { 1527 struct mbuf *nam = nfsd->nd_nam; 1528 struct nfsm_info info; 1529 struct ucred *cred = &nfsd->nd_cr; 1530 struct nameidata nd; 1531 u_int32_t *tl; 1532 int32_t t1; 1533 int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1; 1534 int getret = 1; 1535 char *cp2; 1536 struct vnode *vp, *xp, *dirp = NULL; 1537 struct vattr dirfor, diraft, at; 1538 nfsfh_t nfh, dnfh; 1539 fhandle_t *fhp, *dfhp; 1540 1541 info.nmi_mreq = NULL; 1542 info.nmi_mrep = nfsd->nd_mrep; 1543 info.nmi_md = nfsd->nd_md; 1544 info.nmi_dpos = nfsd->nd_dpos; 1545 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1546 1547 fhp = &nfh.fh_generic; 1548 dfhp = &dnfh.fh_generic; 1549 nfsm_srvmtofh(fhp); 1550 nfsm_srvmtofh(dfhp); 1551 nfsm_srvnamesiz(len); 1552 1553 error = nfsrv_fhtovp(fhp, 0, &vp, cred, slp, nam, &rdonly); 1554 if (error) { 1555 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + 1556 NFSX_WCCDATA(info.nmi_v3)); 1557 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 1558 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1559 &info); 1560 error = 0; 1561 goto nfsmout; 1562 } 1563 if (vp->v_type == VDIR && (error = suser_ucred(cred)) != 0) 1564 goto out1; 1565 nd.ni_cnd.cn_cred = cred; 1566 nd.ni_cnd.cn_nameiop = CREATE; 1567 nd.ni_cnd.cn_flags = LOCKPARENT; 1568 error = nfs_namei(&nd, dfhp, len, slp, nam, &info.nmi_md, 1569 &info.nmi_dpos, &dirp, procp); 1570 if (dirp) { 1571 if (info.nmi_v3) 1572 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1573 procp); 1574 else { 1575 vrele(dirp); 1576 dirp = NULL; 1577 } 1578 } 1579 if (error) 1580 goto out1; 1581 xp = nd.ni_vp; 1582 if (xp != NULL) { 1583 error = EEXIST; 1584 goto out; 1585 } 1586 xp = nd.ni_dvp; 1587 if (vp->v_mount != xp->v_mount) 1588 error = EXDEV; 1589 out: 1590 if (!error) { 1591 error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd); 1592 } else { 1593 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1594 if (nd.ni_dvp == nd.ni_vp) 1595 vrele(nd.ni_dvp); 1596 else 1597 vput(nd.ni_dvp); 1598 if (nd.ni_vp) 1599 vrele(nd.ni_vp); 1600 } 1601 out1: 1602 if (info.nmi_v3) 1603 getret = VOP_GETATTR(vp, &at, cred, procp); 1604 if (dirp) { 1605 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1606 vrele(dirp); 1607 } 1608 vrele(vp); 1609 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)); 1610 if (info.nmi_v3) { 1611 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 1612 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1613 &info); 1614 error = 0; 1615 } 1616 nfsmout: 1617 return(error); 1618 } 1619 1620 /* 1621 * nfs symbolic link service 1622 */ 1623 int 1624 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1625 struct proc *procp, struct mbuf **mrq) 1626 { 1627 struct mbuf *nam = nfsd->nd_nam; 1628 struct ucred *cred = &nfsd->nd_cr; 1629 struct vattr va, dirfor, diraft; 1630 struct nameidata nd; 1631 struct nfsm_info info; 1632 u_int32_t *tl; 1633 int32_t t1; 1634 struct nfsv2_sattr *sp; 1635 char *pathcp = NULL, *cp2; 1636 struct uio io; 1637 struct iovec iv; 1638 int error = 0, len, len2, dirfor_ret = 1, diraft_ret = 1; 1639 struct vnode *dirp = NULL; 1640 nfsfh_t nfh; 1641 fhandle_t *fhp; 1642 1643 info.nmi_mreq = NULL; 1644 info.nmi_mrep = nfsd->nd_mrep; 1645 info.nmi_md = nfsd->nd_md; 1646 info.nmi_dpos = nfsd->nd_dpos; 1647 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1648 1649 nd.ni_cnd.cn_nameiop = 0; 1650 fhp = &nfh.fh_generic; 1651 nfsm_srvmtofh(fhp); 1652 nfsm_srvnamesiz(len); 1653 1654 nd.ni_cnd.cn_cred = cred; 1655 nd.ni_cnd.cn_nameiop = CREATE; 1656 nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART; 1657 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 1658 &info.nmi_dpos, &dirp, procp); 1659 if (dirp) { 1660 if (info.nmi_v3) 1661 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1662 procp); 1663 else { 1664 vrele(dirp); 1665 dirp = NULL; 1666 } 1667 } 1668 if (error) 1669 goto out; 1670 VATTR_NULL(&va); 1671 if (info.nmi_v3) 1672 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, 1673 &info.nmi_dpos); 1674 if (error) 1675 goto nfsmout; 1676 nfsm_strsiz(len2, NFS_MAXPATHLEN); 1677 pathcp = malloc(len2 + 1, M_TEMP, M_WAITOK); 1678 iv.iov_base = pathcp; 1679 iv.iov_len = len2; 1680 io.uio_resid = len2; 1681 io.uio_offset = 0; 1682 io.uio_iov = &iv; 1683 io.uio_iovcnt = 1; 1684 io.uio_segflg = UIO_SYSSPACE; 1685 io.uio_rw = UIO_READ; 1686 io.uio_procp = NULL; 1687 nfsm_mtouio(&io, len2); 1688 if (!info.nmi_v3) { 1689 nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 1690 va.va_mode = fxdr_unsigned(u_int16_t, sp->sa_mode); 1691 } 1692 *(pathcp + len2) = '\0'; 1693 if (nd.ni_vp) { 1694 vrele(nd.ni_startdir); 1695 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1696 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1697 if (nd.ni_dvp == nd.ni_vp) 1698 vrele(nd.ni_dvp); 1699 else 1700 vput(nd.ni_dvp); 1701 vrele(nd.ni_vp); 1702 error = EEXIST; 1703 goto out; 1704 } 1705 error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp); 1706 if (error) 1707 vrele(nd.ni_startdir); 1708 else { 1709 if (info.nmi_v3) { 1710 nd.ni_cnd.cn_nameiop = LOOKUP; 1711 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW); 1712 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF); 1713 nd.ni_cnd.cn_proc = procp; 1714 nd.ni_cnd.cn_cred = cred; 1715 error = vfs_lookup(&nd); 1716 if (!error) { 1717 bzero((caddr_t)fhp, sizeof(nfh)); 1718 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid; 1719 error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid); 1720 if (!error) 1721 error = VOP_GETATTR(nd.ni_vp, &va, cred, 1722 procp); 1723 vput(nd.ni_vp); 1724 } 1725 } else 1726 vrele(nd.ni_startdir); 1727 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1728 } 1729 out: 1730 if (pathcp) 1731 free(pathcp, M_TEMP); 1732 if (dirp) { 1733 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1734 vrele(dirp); 1735 } 1736 nfsm_reply(NFSX_SRVFH(info.nmi_v3) + NFSX_POSTOPATTR(info.nmi_v3) 1737 + NFSX_WCCDATA(info.nmi_v3)); 1738 if (info.nmi_v3) { 1739 if (!error) { 1740 nfsm_srvpostop_fh(fhp); 1741 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 1742 } 1743 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1744 &info); 1745 } 1746 return (0); 1747 nfsmout: 1748 if (nd.ni_cnd.cn_nameiop) { 1749 vrele(nd.ni_startdir); 1750 pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); 1751 } 1752 if (dirp) 1753 vrele(dirp); 1754 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1755 if (nd.ni_dvp == nd.ni_vp) 1756 vrele(nd.ni_dvp); 1757 else 1758 vput(nd.ni_dvp); 1759 if (nd.ni_vp) 1760 vrele(nd.ni_vp); 1761 if (pathcp) 1762 free(pathcp, M_TEMP); 1763 return (error); 1764 } 1765 1766 /* 1767 * nfs mkdir service 1768 */ 1769 int 1770 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1771 struct proc *procp, struct mbuf **mrq) 1772 { 1773 struct mbuf *nam = nfsd->nd_nam; 1774 struct ucred *cred = &nfsd->nd_cr; 1775 struct vattr va, dirfor, diraft; 1776 struct nfs_fattr *fp; 1777 struct nameidata nd; 1778 struct nfsm_info info; 1779 u_int32_t *tl; 1780 int32_t t1; 1781 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1782 char *cp2; 1783 struct vnode *vp, *dirp = NULL; 1784 nfsfh_t nfh; 1785 fhandle_t *fhp; 1786 1787 info.nmi_mreq = NULL; 1788 info.nmi_mrep = nfsd->nd_mrep; 1789 info.nmi_md = nfsd->nd_md; 1790 info.nmi_dpos = nfsd->nd_dpos; 1791 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1792 1793 fhp = &nfh.fh_generic; 1794 nfsm_srvmtofh(fhp); 1795 nfsm_srvnamesiz(len); 1796 1797 nd.ni_cnd.cn_cred = cred; 1798 nd.ni_cnd.cn_nameiop = CREATE; 1799 nd.ni_cnd.cn_flags = LOCKPARENT; 1800 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 1801 &info.nmi_dpos, &dirp, procp); 1802 if (dirp) { 1803 if (info.nmi_v3) 1804 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp); 1805 else { 1806 vrele(dirp); 1807 dirp = NULL; 1808 } 1809 } 1810 if (error) { 1811 nfsm_reply(NFSX_WCCDATA(info.nmi_v3)); 1812 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1813 &info); 1814 if (info.nmi_v3) 1815 vrele(dirp); 1816 return (0); 1817 } 1818 1819 VATTR_NULL(&va); 1820 if (info.nmi_v3) { 1821 error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, 1822 &info.nmi_dpos); 1823 if (error) 1824 goto nfsmout; 1825 } else { 1826 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1827 va.va_mode = nfstov_mode(*tl++); 1828 } 1829 va.va_type = VDIR; 1830 vp = nd.ni_vp; 1831 if (vp != NULL) { 1832 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1833 if (nd.ni_dvp == vp) 1834 vrele(nd.ni_dvp); 1835 else 1836 vput(nd.ni_dvp); 1837 vrele(vp); 1838 error = EEXIST; 1839 goto out; 1840 } 1841 error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va); 1842 if (!error) { 1843 vp = nd.ni_vp; 1844 bzero((caddr_t)fhp, sizeof(nfh)); 1845 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid; 1846 error = VFS_VPTOFH(vp, &fhp->fh_fid); 1847 if (!error) 1848 error = VOP_GETATTR(vp, &va, cred, procp); 1849 vput(vp); 1850 } 1851 out: 1852 if (dirp) { 1853 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1854 vrele(dirp); 1855 } 1856 nfsm_reply(NFSX_SRVFH(info.nmi_v3) + NFSX_POSTOPATTR(info.nmi_v3) + 1857 NFSX_WCCDATA(info.nmi_v3)); 1858 if (info.nmi_v3) { 1859 if (!error) { 1860 nfsm_srvpostop_fh(fhp); 1861 nfsm_srvpostop_attr(nfsd, 0, &va, &info); 1862 } 1863 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1864 &info); 1865 } else { 1866 nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3); 1867 fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR); 1868 nfsm_srvfattr(nfsd, &va, fp); 1869 } 1870 return (0); 1871 nfsmout: 1872 if (dirp) 1873 vrele(dirp); 1874 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1875 if (nd.ni_dvp == nd.ni_vp) 1876 vrele(nd.ni_dvp); 1877 else 1878 vput(nd.ni_dvp); 1879 if (nd.ni_vp) 1880 vrele(nd.ni_vp); 1881 return (error); 1882 } 1883 1884 /* 1885 * nfs rmdir service 1886 */ 1887 int 1888 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 1889 struct proc *procp, struct mbuf **mrq) 1890 { 1891 struct mbuf *nam = nfsd->nd_nam; 1892 struct ucred *cred = &nfsd->nd_cr; 1893 struct nfsm_info info; 1894 u_int32_t *tl; 1895 int32_t t1; 1896 int error = 0, len, dirfor_ret = 1, diraft_ret = 1; 1897 char *cp2; 1898 struct vnode *vp, *dirp = NULL; 1899 struct vattr dirfor, diraft; 1900 nfsfh_t nfh; 1901 fhandle_t *fhp; 1902 struct nameidata nd; 1903 1904 info.nmi_mreq = NULL; 1905 info.nmi_mrep = nfsd->nd_mrep; 1906 info.nmi_md = nfsd->nd_md; 1907 info.nmi_dpos = nfsd->nd_dpos; 1908 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 1909 1910 fhp = &nfh.fh_generic; 1911 nfsm_srvmtofh(fhp); 1912 nfsm_srvnamesiz(len); 1913 nd.ni_cnd.cn_cred = cred; 1914 nd.ni_cnd.cn_nameiop = DELETE; 1915 nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF; 1916 error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, 1917 &info.nmi_dpos, &dirp, procp); 1918 if (dirp) { 1919 if (info.nmi_v3) 1920 dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, 1921 procp); 1922 else { 1923 vrele(dirp); 1924 dirp = NULL; 1925 } 1926 } 1927 if (error) { 1928 nfsm_reply(NFSX_WCCDATA(info.nmi_v3)); 1929 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1930 &info); 1931 if (info.nmi_v3) 1932 vrele(dirp); 1933 return (0); 1934 } 1935 vp = nd.ni_vp; 1936 if (vp->v_type != VDIR) { 1937 error = ENOTDIR; 1938 goto out; 1939 } 1940 /* 1941 * No rmdir "." please. 1942 */ 1943 if (nd.ni_dvp == vp) { 1944 error = EINVAL; 1945 goto out; 1946 } 1947 /* 1948 * The root of a mounted filesystem cannot be deleted. 1949 */ 1950 if (vp->v_flag & VROOT) 1951 error = EBUSY; 1952 out: 1953 if (!error) { 1954 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); 1955 } else { 1956 VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 1957 if (nd.ni_dvp == nd.ni_vp) 1958 vrele(nd.ni_dvp); 1959 else 1960 vput(nd.ni_dvp); 1961 vput(vp); 1962 } 1963 if (dirp) { 1964 diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp); 1965 vrele(dirp); 1966 } 1967 nfsm_reply(NFSX_WCCDATA(info.nmi_v3)); 1968 if (info.nmi_v3) { 1969 nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, 1970 &info); 1971 error = 0; 1972 } 1973 nfsmout: 1974 return(error); 1975 } 1976 1977 /* 1978 * nfs readdir service 1979 * - mallocs what it thinks is enough to read 1980 * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR 1981 * - calls VOP_READDIR() 1982 * - loops around building the reply 1983 * if the output generated exceeds count break out of loop 1984 * - it only knows that it has encountered eof when the VOP_READDIR() 1985 * reads nothing 1986 * - as such one readdir rpc will return eof false although you are there 1987 * and then the next will return eof 1988 * - it trims out records with d_fileno == 0 1989 * this doesn't matter for Unix clients, but they might confuse clients 1990 * for other os'. 1991 * NB: It is tempting to set eof to true if the VOP_READDIR() reads less 1992 * than requested, but this may not apply to all filesystems. For 1993 * example, client NFS does not { although it is never remote mounted 1994 * anyhow } 1995 * The alternate call nfsrv_readdirplus() does lookups as well. 1996 * PS: The NFS protocol spec. does not clarify what the "count" byte 1997 * argument is a count of.. just name strings and file id's or the 1998 * entire reply rpc or ... 1999 * I tried just file name and id sizes and it confused the Sun client, 2000 * so I am using the full rpc size now. The "paranoia.." comment refers 2001 * to including the status longwords that are not a part of the dir. 2002 * "entry" structures, but are in the rpc. 2003 */ 2004 struct flrep { 2005 nfsuint64 fl_off; 2006 u_int32_t fl_postopok; 2007 u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)]; 2008 u_int32_t fl_fhok; 2009 u_int32_t fl_fhsize; 2010 u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)]; 2011 }; 2012 2013 int 2014 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2015 struct proc *procp, struct mbuf **mrq) 2016 { 2017 struct mbuf *nam = nfsd->nd_nam; 2018 struct ucred *cred = &nfsd->nd_cr; 2019 struct dirent *dp; 2020 struct nfsm_info info; 2021 u_int32_t *tl; 2022 int32_t t1; 2023 char *cpos, *cend, *cp2, *rbuf; 2024 struct vnode *vp; 2025 struct vattr at; 2026 nfsfh_t nfh; 2027 fhandle_t *fhp; 2028 struct uio io; 2029 struct iovec iv; 2030 int len, nlen, pad, xfer, error = 0, getret = 1; 2031 int siz, cnt, fullsiz, eofflag, rdonly, ncookies; 2032 u_quad_t off, toff, verf; 2033 u_long *cookies = NULL, *cookiep; 2034 2035 info.nmi_mreq = NULL; 2036 info.nmi_mrep = nfsd->nd_mrep; 2037 info.nmi_md = nfsd->nd_md; 2038 info.nmi_dpos = nfsd->nd_dpos; 2039 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2040 2041 fhp = &nfh.fh_generic; 2042 nfsm_srvmtofh(fhp); 2043 if (info.nmi_v3) { 2044 nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2045 toff = fxdr_hyper(tl); 2046 tl += 2; 2047 verf = fxdr_hyper(tl); 2048 tl += 2; 2049 } else { 2050 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2051 toff = fxdr_unsigned(u_quad_t, *tl++); 2052 } 2053 2054 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2055 if (error) { 2056 nfsm_reply(NFSX_UNSIGNED); 2057 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2058 error = 0; 2059 goto nfsmout; 2060 } 2061 2062 error = getret = VOP_GETATTR(vp, &at, cred, procp); 2063 if (!error) 2064 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0); 2065 if (error) { 2066 vput(vp); 2067 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3)); 2068 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2069 error = 0; 2070 goto nfsmout; 2071 } 2072 2073 off = toff; 2074 cnt = fxdr_unsigned(int, *tl); 2075 siz = ((cnt + at.va_blocksize - 1) & ~(at.va_blocksize - 1)); 2076 xfer = NFS_SRVMAXDATA(nfsd); 2077 if (siz > xfer) 2078 siz = xfer; 2079 if (cnt > xfer) 2080 cnt = xfer; 2081 fullsiz = siz; 2082 VOP_UNLOCK(vp, 0, procp); 2083 rbuf = malloc(siz, M_TEMP, M_WAITOK); 2084 again: 2085 iv.iov_base = rbuf; 2086 iv.iov_len = fullsiz; 2087 io.uio_iov = &iv; 2088 io.uio_iovcnt = 1; 2089 io.uio_offset = (off_t)off; 2090 io.uio_resid = fullsiz; 2091 io.uio_segflg = UIO_SYSSPACE; 2092 io.uio_rw = UIO_READ; 2093 io.uio_procp = NULL; 2094 eofflag = 0; 2095 2096 if (cookies) { 2097 free((caddr_t)cookies, M_TEMP); 2098 cookies = NULL; 2099 } 2100 2101 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp); 2102 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); 2103 2104 off = (off_t)io.uio_offset; 2105 if (!cookies && !error) 2106 error = NFSERR_PERM; 2107 if (info.nmi_v3) { 2108 getret = VOP_GETATTR(vp, &at, cred, procp); 2109 if (!error) 2110 error = getret; 2111 } 2112 2113 VOP_UNLOCK(vp, 0, procp); 2114 if (error) { 2115 vrele(vp); 2116 free((caddr_t)rbuf, M_TEMP); 2117 if (cookies) 2118 free((caddr_t)cookies, M_TEMP); 2119 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3)); 2120 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2121 error = 0; 2122 goto nfsmout; 2123 } 2124 if (io.uio_resid) { 2125 siz -= io.uio_resid; 2126 2127 /* 2128 * If nothing read, return eof 2129 * rpc reply 2130 */ 2131 if (siz == 0) { 2132 vrele(vp); 2133 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + NFSX_COOKIEVERF(info.nmi_v3) + 2134 2 * NFSX_UNSIGNED); 2135 if (info.nmi_v3) { 2136 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2137 tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED); 2138 txdr_hyper(at.va_filerev, tl); 2139 tl += 2; 2140 } else 2141 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2142 *tl++ = nfs_false; 2143 *tl = nfs_true; 2144 free(rbuf, M_TEMP); 2145 free(cookies, M_TEMP); 2146 error = 0; 2147 goto nfsmout; 2148 } 2149 } 2150 2151 /* 2152 * Check for degenerate cases of nothing useful read. 2153 * If so go try again 2154 */ 2155 cpos = rbuf; 2156 cend = rbuf + siz; 2157 dp = (struct dirent *)cpos; 2158 cookiep = cookies; 2159 2160 while (cpos < cend && ncookies > 0 && dp->d_fileno == 0) { 2161 cpos += dp->d_reclen; 2162 dp = (struct dirent *)cpos; 2163 cookiep++; 2164 ncookies--; 2165 } 2166 if (cpos >= cend || ncookies == 0) { 2167 toff = off; 2168 siz = fullsiz; 2169 goto again; 2170 } 2171 2172 len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ 2173 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + NFSX_COOKIEVERF(info.nmi_v3) + siz); 2174 if (info.nmi_v3) { 2175 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2176 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2177 txdr_hyper(at.va_filerev, tl); 2178 } 2179 2180 /* Loop through the records and build reply */ 2181 while (cpos < cend && ncookies > 0) { 2182 if (dp->d_fileno != 0) { 2183 nlen = dp->d_namlen; 2184 pad = nfsm_padlen(nlen); 2185 len += (4 * NFSX_UNSIGNED + nlen + pad); 2186 if (info.nmi_v3) 2187 len += 2 * NFSX_UNSIGNED; 2188 if (len > cnt) { 2189 eofflag = 0; 2190 break; 2191 } 2192 /* 2193 * Build the directory record xdr from 2194 * the dirent entry. 2195 */ 2196 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2197 *tl++ = nfs_true; 2198 if (info.nmi_v3) { 2199 *tl = 0; 2200 tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED); 2201 } 2202 *tl = txdr_unsigned(dp->d_fileno); 2203 2204 /* And copy the name */ 2205 nfsm_strtombuf(&info.nmi_mb, dp->d_name, nlen); 2206 2207 /* Finish off the record */ 2208 if (info.nmi_v3) { 2209 tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED); 2210 *tl = 0; 2211 } 2212 tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED); 2213 *tl = txdr_unsigned(*cookiep); 2214 } 2215 cpos += dp->d_reclen; 2216 dp = (struct dirent *)cpos; 2217 cookiep++; 2218 ncookies--; 2219 } 2220 vrele(vp); 2221 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2222 *tl++ = nfs_false; 2223 if (eofflag) 2224 *tl = nfs_true; 2225 else 2226 *tl = nfs_false; 2227 free(rbuf, M_TEMP); 2228 free(cookies, M_TEMP); 2229 nfsmout: 2230 return(error); 2231 } 2232 2233 int 2234 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2235 struct proc *procp, struct mbuf **mrq) 2236 { 2237 struct mbuf *nam = nfsd->nd_nam; 2238 struct ucred *cred = &nfsd->nd_cr; 2239 struct dirent *dp; 2240 struct nfsm_info info; 2241 u_int32_t *tl; 2242 int32_t t1; 2243 char *cpos, *cend, *cp2, *rbuf; 2244 struct vnode *vp, *nvp; 2245 struct flrep fl; 2246 nfsfh_t nfh; 2247 fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh; 2248 struct uio io; 2249 struct iovec iv; 2250 struct vattr va, at, *vap = &va; 2251 struct nfs_fattr *fp; 2252 int len, nlen, pad, xfer, error = 0, getret = 1; 2253 int siz, cnt, fullsiz, eofflag, rdonly, dirlen, ncookies; 2254 u_quad_t off, toff, verf; 2255 u_long *cookies = NULL, *cookiep; 2256 2257 info.nmi_mreq = NULL; 2258 info.nmi_mrep = nfsd->nd_mrep; 2259 info.nmi_md = nfsd->nd_md; 2260 info.nmi_dpos = nfsd->nd_dpos; 2261 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2262 2263 fhp = &nfh.fh_generic; 2264 nfsm_srvmtofh(fhp); 2265 nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2266 toff = fxdr_hyper(tl); 2267 tl += 2; 2268 verf = fxdr_hyper(tl); 2269 tl += 2; 2270 2271 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2272 if (error) { 2273 nfsm_reply(NFSX_UNSIGNED); 2274 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2275 error = 0; 2276 goto nfsmout; 2277 } 2278 2279 error = getret = VOP_GETATTR(vp, &at, cred, procp); 2280 if (!error) 2281 error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0); 2282 if (error) { 2283 vput(vp); 2284 nfsm_reply(NFSX_V3POSTOPATTR); 2285 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2286 error = 0; 2287 goto nfsmout; 2288 } 2289 2290 siz = fxdr_unsigned(int, *tl++); 2291 cnt = fxdr_unsigned(int, *tl); 2292 off = toff; 2293 siz = ((siz + at.va_blocksize - 1) & ~(at.va_blocksize - 1)); 2294 xfer = NFS_SRVMAXDATA(nfsd); 2295 if (siz > xfer) 2296 siz = xfer; 2297 if (cnt > xfer) 2298 cnt = xfer; 2299 fullsiz = siz; 2300 VOP_UNLOCK(vp, 0, procp); 2301 rbuf = malloc(siz, M_TEMP, M_WAITOK); 2302 again: 2303 iv.iov_base = rbuf; 2304 iv.iov_len = fullsiz; 2305 io.uio_iov = &iv; 2306 io.uio_iovcnt = 1; 2307 io.uio_offset = (off_t)off; 2308 io.uio_resid = fullsiz; 2309 io.uio_segflg = UIO_SYSSPACE; 2310 io.uio_rw = UIO_READ; 2311 io.uio_procp = NULL; 2312 eofflag = 0; 2313 2314 if (cookies) { 2315 free((caddr_t)cookies, M_TEMP); 2316 cookies = NULL; 2317 } 2318 2319 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, procp); 2320 error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies); 2321 2322 off = (u_quad_t)io.uio_offset; 2323 getret = VOP_GETATTR(vp, &at, cred, procp); 2324 2325 VOP_UNLOCK(vp, 0, procp); 2326 2327 if (!cookies && !error) 2328 error = NFSERR_PERM; 2329 if (!error) 2330 error = getret; 2331 if (error) { 2332 vrele(vp); 2333 if (cookies) 2334 free((caddr_t)cookies, M_TEMP); 2335 free((caddr_t)rbuf, M_TEMP); 2336 nfsm_reply(NFSX_V3POSTOPATTR); 2337 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2338 error = 0; 2339 goto nfsmout; 2340 } 2341 if (io.uio_resid) { 2342 siz -= io.uio_resid; 2343 2344 /* 2345 * If nothing read, return eof 2346 * rpc reply 2347 */ 2348 if (siz == 0) { 2349 vrele(vp); 2350 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2351 2 * NFSX_UNSIGNED); 2352 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2353 tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED); 2354 txdr_hyper(at.va_filerev, tl); 2355 tl += 2; 2356 *tl++ = nfs_false; 2357 *tl = nfs_true; 2358 free(cookies, M_TEMP); 2359 free(rbuf, M_TEMP); 2360 error = 0; 2361 goto nfsmout; 2362 } 2363 } 2364 2365 /* 2366 * Check for degenerate cases of nothing useful read. 2367 * If so go try again 2368 */ 2369 cpos = rbuf; 2370 cend = rbuf + siz; 2371 dp = (struct dirent *)cpos; 2372 cookiep = cookies; 2373 2374 while (cpos < cend && ncookies > 0 && dp->d_fileno == 0) { 2375 cpos += dp->d_reclen; 2376 dp = (struct dirent *)cpos; 2377 cookiep++; 2378 ncookies--; 2379 } 2380 if (cpos >= cend || ncookies == 0) { 2381 toff = off; 2382 siz = fullsiz; 2383 goto again; 2384 } 2385 2386 /* 2387 * struct READDIRPLUS3resok { 2388 * postop_attr dir_attributes; 2389 * cookieverf3 cookieverf; 2390 * dirlistplus3 reply; 2391 * } 2392 * 2393 * struct dirlistplus3 { 2394 * entryplus3 *entries; 2395 * bool eof; 2396 * } 2397 */ 2398 dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED; 2399 nfsm_reply(cnt); 2400 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2401 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2402 txdr_hyper(at.va_filerev, tl); 2403 2404 /* Loop through the records and build reply */ 2405 while (cpos < cend && ncookies > 0) { 2406 if (dp->d_fileno != 0) { 2407 nlen = dp->d_namlen; 2408 pad = nfsm_padlen(nlen); 2409 2410 /* 2411 * For readdir_and_lookup get the vnode using 2412 * the file number. 2413 */ 2414 if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp)) 2415 goto invalid; 2416 bzero((caddr_t)nfhp, NFSX_V3FH); 2417 nfhp->fh_fsid = 2418 nvp->v_mount->mnt_stat.f_fsid; 2419 if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { 2420 vput(nvp); 2421 goto invalid; 2422 } 2423 if (VOP_GETATTR(nvp, vap, cred, procp)) { 2424 vput(nvp); 2425 goto invalid; 2426 } 2427 vput(nvp); 2428 2429 /* 2430 * If either the dircount or maxcount will be 2431 * exceeded, get out now. Both of these lengths 2432 * are calculated conservatively, including all 2433 * XDR overheads. 2434 * 2435 * Each entry: 2436 * 2 * NFSX_UNSIGNED for fileid3 2437 * 1 * NFSX_UNSIGNED for length of name 2438 * nlen + pad == space the name takes up 2439 * 2 * NFSX_UNSIGNED for the cookie 2440 * 1 * NFSX_UNSIGNED to indicate if file handle present 2441 * 1 * NFSX_UNSIGNED for the file handle length 2442 * NFSX_V3FH == space our file handle takes up 2443 * NFSX_V3POSTOPATTR == space the attributes take up 2444 * 1 * NFSX_UNSIGNED for next pointer 2445 */ 2446 len += (8 * NFSX_UNSIGNED + nlen + pad + NFSX_V3FH + 2447 NFSX_V3POSTOPATTR); 2448 dirlen += (6 * NFSX_UNSIGNED + nlen + pad); 2449 if (len > cnt || dirlen > fullsiz) { 2450 eofflag = 0; 2451 break; 2452 } 2453 2454 tl = nfsm_build(&info.nmi_mb, 3 * NFSX_UNSIGNED); 2455 *tl++ = nfs_true; 2456 *tl++ = 0; 2457 *tl = txdr_unsigned(dp->d_fileno); 2458 2459 /* And copy the name */ 2460 nfsm_strtombuf(&info.nmi_mb, dp->d_name, nlen); 2461 2462 /* 2463 * Build the directory record xdr from 2464 * the dirent entry. 2465 */ 2466 fp = (struct nfs_fattr *)&fl.fl_fattr; 2467 nfsm_srvfattr(nfsd, vap, fp); 2468 fl.fl_fhsize = txdr_unsigned(NFSX_V3FH); 2469 fl.fl_fhok = nfs_true; 2470 fl.fl_postopok = nfs_true; 2471 fl.fl_off.nfsuquad[0] = 0; 2472 fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep); 2473 2474 /* Now copy the flrep structure out. */ 2475 nfsm_buftombuf(&info.nmi_mb, &fl, sizeof(struct flrep)); 2476 } 2477 invalid: 2478 cpos += dp->d_reclen; 2479 dp = (struct dirent *)cpos; 2480 cookiep++; 2481 ncookies--; 2482 } 2483 vrele(vp); 2484 tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED); 2485 *tl++ = nfs_false; 2486 if (eofflag) 2487 *tl = nfs_true; 2488 else 2489 *tl = nfs_false; 2490 free(cookies, M_TEMP); 2491 free(rbuf, M_TEMP); 2492 nfsmout: 2493 return(error); 2494 } 2495 2496 /* 2497 * nfs commit service 2498 */ 2499 int 2500 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2501 struct proc *procp, struct mbuf **mrq) 2502 { 2503 struct mbuf *nam = nfsd->nd_nam; 2504 struct ucred *cred = &nfsd->nd_cr; 2505 struct vattr bfor, aft; 2506 struct vnode *vp; 2507 struct nfsm_info info; 2508 nfsfh_t nfh; 2509 fhandle_t *fhp; 2510 u_int32_t *tl; 2511 int32_t t1; 2512 int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt; 2513 char *cp2; 2514 u_quad_t off; 2515 2516 info.nmi_mreq = NULL; 2517 info.nmi_mrep = nfsd->nd_mrep; 2518 info.nmi_md = nfsd->nd_md; 2519 info.nmi_dpos = nfsd->nd_dpos; 2520 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2521 2522 fhp = &nfh.fh_generic; 2523 nfsm_srvmtofh(fhp); 2524 nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2525 2526 /* 2527 * XXX At this time VOP_FSYNC() does not accept offset and byte 2528 * count parameters, so these arguments are useless (someday maybe). 2529 */ 2530 off = fxdr_hyper(tl); 2531 tl += 2; 2532 cnt = fxdr_unsigned(int, *tl); 2533 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2534 if (error) { 2535 nfsm_reply(2 * NFSX_UNSIGNED); 2536 nfsm_srvwcc(nfsd, for_ret, &bfor, aft_ret, &aft, &info); 2537 error = 0; 2538 goto nfsmout; 2539 } 2540 for_ret = VOP_GETATTR(vp, &bfor, cred, procp); 2541 error = VOP_FSYNC(vp, cred, MNT_WAIT, procp); 2542 aft_ret = VOP_GETATTR(vp, &aft, cred, procp); 2543 vput(vp); 2544 nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF); 2545 nfsm_srvwcc(nfsd, for_ret, &bfor, aft_ret, &aft, &info); 2546 if (!error) { 2547 tl = nfsm_build(&info.nmi_mb, NFSX_V3WRITEVERF); 2548 *tl++ = txdr_unsigned(boottime.tv_sec); 2549 *tl = txdr_unsigned(boottime.tv_usec); 2550 } else 2551 error = 0; 2552 nfsmout: 2553 return(error); 2554 } 2555 2556 /* 2557 * nfs statfs service 2558 */ 2559 int 2560 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2561 struct proc *procp, struct mbuf **mrq) 2562 { 2563 struct mbuf *nam = nfsd->nd_nam; 2564 struct ucred *cred = &nfsd->nd_cr; 2565 struct statfs *sf; 2566 struct nfs_statfs *sfp; 2567 struct nfsm_info info; 2568 u_int32_t *tl; 2569 int32_t t1; 2570 int error = 0, rdonly, getret = 1; 2571 char *cp2; 2572 struct vnode *vp; 2573 struct vattr at; 2574 nfsfh_t nfh; 2575 fhandle_t *fhp; 2576 struct statfs statfs; 2577 u_quad_t tval; 2578 2579 info.nmi_mreq = NULL; 2580 info.nmi_mrep = nfsd->nd_mrep; 2581 info.nmi_md = nfsd->nd_md; 2582 info.nmi_dpos = nfsd->nd_dpos; 2583 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2584 2585 fhp = &nfh.fh_generic; 2586 nfsm_srvmtofh(fhp); 2587 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2588 if (error) { 2589 nfsm_reply(NFSX_UNSIGNED); 2590 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2591 error = 0; 2592 goto nfsmout; 2593 } 2594 sf = &statfs; 2595 error = VFS_STATFS(vp->v_mount, sf, procp); 2596 getret = VOP_GETATTR(vp, &at, cred, procp); 2597 vput(vp); 2598 nfsm_reply(NFSX_POSTOPATTR(info.nmi_v3) + NFSX_STATFS(info.nmi_v3)); 2599 if (info.nmi_v3) 2600 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2601 if (error) { 2602 error = 0; 2603 goto nfsmout; 2604 } 2605 sfp = nfsm_build(&info.nmi_mb, NFSX_STATFS(info.nmi_v3)); 2606 if (info.nmi_v3) { 2607 tval = (u_quad_t)sf->f_blocks; 2608 tval *= (u_quad_t)sf->f_bsize; 2609 txdr_hyper(tval, &sfp->sf_tbytes); 2610 tval = (u_quad_t)sf->f_bfree; 2611 tval *= (u_quad_t)sf->f_bsize; 2612 txdr_hyper(tval, &sfp->sf_fbytes); 2613 tval = (u_quad_t)sf->f_bavail; 2614 tval *= (u_quad_t)sf->f_bsize; 2615 txdr_hyper(tval, &sfp->sf_abytes); 2616 tval = (u_quad_t)sf->f_files; 2617 txdr_hyper(tval, &sfp->sf_tfiles); 2618 tval = (u_quad_t)sf->f_ffree; 2619 txdr_hyper(tval, &sfp->sf_ffiles); 2620 txdr_hyper(tval, &sfp->sf_afiles); 2621 sfp->sf_invarsec = 0; 2622 } else { 2623 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA); 2624 sfp->sf_bsize = txdr_unsigned(sf->f_bsize); 2625 sfp->sf_blocks = txdr_unsigned(sf->f_blocks); 2626 sfp->sf_bfree = txdr_unsigned(sf->f_bfree); 2627 sfp->sf_bavail = txdr_unsigned(sf->f_bavail); 2628 } 2629 nfsmout: 2630 return(error); 2631 } 2632 2633 /* 2634 * nfs fsinfo service 2635 */ 2636 int 2637 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2638 struct proc *procp, struct mbuf **mrq) 2639 { 2640 struct mbuf *nam = nfsd->nd_nam; 2641 struct ucred *cred = &nfsd->nd_cr; 2642 struct nfsm_info info; 2643 u_int32_t *tl; 2644 struct nfsv3_fsinfo *sip; 2645 int32_t t1; 2646 int error = 0, rdonly, getret = 1, pref; 2647 char *cp2; 2648 struct vnode *vp; 2649 struct vattr at; 2650 nfsfh_t nfh; 2651 fhandle_t *fhp; 2652 2653 info.nmi_mreq = NULL; 2654 info.nmi_mrep = nfsd->nd_mrep; 2655 info.nmi_md = nfsd->nd_md; 2656 info.nmi_dpos = nfsd->nd_dpos; 2657 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2658 2659 fhp = &nfh.fh_generic; 2660 nfsm_srvmtofh(fhp); 2661 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2662 if (error) { 2663 nfsm_reply(NFSX_UNSIGNED); 2664 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2665 error = 0; 2666 goto nfsmout; 2667 } 2668 getret = VOP_GETATTR(vp, &at, cred, procp); 2669 vput(vp); 2670 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO); 2671 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2672 sip = nfsm_build(&info.nmi_mb, NFSX_V3FSINFO); 2673 2674 /* 2675 * XXX 2676 * There should be file system VFS OP(s) to get this information. 2677 * For now, assume ufs. 2678 */ 2679 if (slp->ns_so->so_type == SOCK_DGRAM) 2680 pref = NFS_MAXDGRAMDATA; 2681 else 2682 pref = NFS_MAXDATA; 2683 sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA); 2684 sip->fs_rtpref = txdr_unsigned(pref); 2685 sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE); 2686 sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA); 2687 sip->fs_wtpref = txdr_unsigned(pref); 2688 sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE); 2689 sip->fs_dtpref = txdr_unsigned(pref); 2690 sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff; 2691 sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff; 2692 sip->fs_timedelta.nfsv3_sec = 0; 2693 sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1); 2694 sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK | 2695 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS | 2696 NFSV3FSINFO_CANSETTIME); 2697 nfsmout: 2698 return(error); 2699 } 2700 2701 /* 2702 * nfs pathconf service 2703 */ 2704 int 2705 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2706 struct proc *procp, struct mbuf **mrq) 2707 { 2708 struct mbuf *nam = nfsd->nd_nam; 2709 struct ucred *cred = &nfsd->nd_cr; 2710 struct nfsm_info info; 2711 u_int32_t *tl; 2712 struct nfsv3_pathconf *pc; 2713 int32_t t1; 2714 int error = 0, rdonly, getret = 1; 2715 register_t linkmax, namemax, chownres, notrunc; 2716 char *cp2; 2717 struct vnode *vp; 2718 struct vattr at; 2719 nfsfh_t nfh; 2720 fhandle_t *fhp; 2721 2722 info.nmi_mreq = NULL; 2723 info.nmi_mrep = nfsd->nd_mrep; 2724 info.nmi_md = nfsd->nd_md; 2725 info.nmi_dpos = nfsd->nd_dpos; 2726 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2727 2728 fhp = &nfh.fh_generic; 2729 nfsm_srvmtofh(fhp); 2730 error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly); 2731 if (error) { 2732 nfsm_reply(NFSX_UNSIGNED); 2733 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2734 error = 0; 2735 goto nfsmout; 2736 } 2737 error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); 2738 if (!error) 2739 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); 2740 if (!error) 2741 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres); 2742 if (!error) 2743 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); 2744 getret = VOP_GETATTR(vp, &at, cred, procp); 2745 vput(vp); 2746 nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF); 2747 nfsm_srvpostop_attr(nfsd, getret, &at, &info); 2748 if (error) { 2749 error = 0; 2750 goto nfsmout; 2751 } 2752 pc = nfsm_build(&info.nmi_mb, NFSX_V3PATHCONF); 2753 2754 pc->pc_linkmax = txdr_unsigned(linkmax); 2755 pc->pc_namemax = txdr_unsigned(namemax); 2756 pc->pc_notrunc = txdr_unsigned(notrunc); 2757 pc->pc_chownrestricted = txdr_unsigned(chownres); 2758 2759 /* 2760 * These should probably be supported by VOP_PATHCONF(), but 2761 * until msdosfs is exportable (why would you want to?), the 2762 * Unix defaults should be ok. 2763 */ 2764 pc->pc_caseinsensitive = nfs_false; 2765 pc->pc_casepreserving = nfs_true; 2766 nfsmout: 2767 return(error); 2768 } 2769 2770 /* 2771 * Null operation, used by clients to ping server 2772 */ 2773 /* ARGSUSED */ 2774 int 2775 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2776 struct proc *procp, struct mbuf **mrq) 2777 { 2778 struct nfsm_info info; 2779 int error = NFSERR_RETVOID; 2780 2781 info.nmi_mreq = NULL; 2782 info.nmi_mrep = nfsd->nd_mrep; 2783 info.nmi_md = nfsd->nd_md; 2784 info.nmi_dpos = nfsd->nd_dpos; 2785 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2786 2787 nfsm_reply(0); 2788 return (0); 2789 } 2790 2791 /* 2792 * No operation, used for obsolete procedures 2793 */ 2794 /* ARGSUSED */ 2795 int 2796 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 2797 struct proc *procp, struct mbuf **mrq) 2798 { 2799 struct nfsm_info info; 2800 int error; 2801 2802 info.nmi_mreq = NULL; 2803 info.nmi_mrep = nfsd->nd_mrep; 2804 info.nmi_md = nfsd->nd_md; 2805 info.nmi_dpos = nfsd->nd_dpos; 2806 info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3); 2807 2808 if (nfsd->nd_repstat) 2809 error = nfsd->nd_repstat; 2810 else 2811 error = EPROCUNAVAIL; 2812 nfsm_reply(0); 2813 return (0); 2814 } 2815 2816 /* 2817 * Perform access checking for vnodes obtained from file handles that would 2818 * refer to files already opened by a Unix client. 2819 * You cannot just use vn_writechk() and VOP_ACCESS() for two reasons: 2820 * 1 - You must check for exported rdonly as well as MNT_RDONLY for the 2821 * write case 2822 * 2 - The owner is to be given access irrespective of mode bits for some 2823 * operations, so that processes that chmod after opening a file don't 2824 * break. I don't like this because it opens a security hole, but since 2825 * the nfs server opens a security hole the size of a barn door anyhow, 2826 * what the heck. A notable exception to this rule is when VOP_ACCESS() 2827 * returns EPERM (e.g. when a file is immutable) which is always an 2828 * error. 2829 */ 2830 int 2831 nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly, 2832 struct proc *p, int override) 2833 { 2834 struct vattr vattr; 2835 int error; 2836 2837 if (flags & VWRITE) { 2838 /* Just vn_writechk() changed to check rdonly */ 2839 /* 2840 * Disallow write attempts on read-only file systems; 2841 * unless the file is a socket or a block or character 2842 * device resident on the file system. 2843 */ 2844 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) { 2845 switch (vp->v_type) { 2846 case VREG: 2847 case VDIR: 2848 case VLNK: 2849 return (EROFS); 2850 default: 2851 break; 2852 } 2853 } 2854 /* 2855 * If there's shared text associated with 2856 * the inode, try to free it up once. If 2857 * we fail, we can't allow writing. 2858 */ 2859 if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp)) 2860 return (ETXTBSY); 2861 } 2862 error = VOP_ACCESS(vp, flags, cred, p); 2863 /* 2864 * Allow certain operations for the owner (reads and writes 2865 * on files that are already open). 2866 */ 2867 if (override && error == EACCES && 2868 VOP_GETATTR(vp, &vattr, cred, p) == 0 && 2869 cred->cr_uid == vattr.va_uid) 2870 error = 0; 2871 return error; 2872 } 2873