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