1/*- 2 * Copyright (c) 1999, 2000, 2001 Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28#include <sys/param.h> 29#include <sys/systm.h> 30#include <sys/namei.h> 31#include <sys/kernel.h> 32#include <sys/bio.h> 33#include <sys/buf.h> 34#include <sys/fcntl.h> 35#include <sys/mount.h> 36#include <sys/unistd.h> 37#include <sys/vnode.h> 38 39#include <vm/vm.h> 40#include <vm/vm_extern.h> 41 42#include <netncp/ncp.h> 43#include <netncp/ncp_conn.h> 44#include <netncp/ncp_subr.h> 45#include <netncp/nwerror.h> 46#include <netncp/ncp_nls.h> 47 48#include <fs/nwfs/nwfs.h> 49#include <fs/nwfs/nwfs_node.h> 50#include <fs/nwfs/nwfs_subr.h> 51 52/* 53 * Prototypes for NWFS vnode operations 54 */ 55static vop_create_t nwfs_create; 56static vop_mknod_t nwfs_mknod; 57static vop_open_t nwfs_open; 58static vop_close_t nwfs_close; 59static vop_access_t nwfs_access; 60static vop_getattr_t nwfs_getattr; 61static vop_setattr_t nwfs_setattr; 62static vop_read_t nwfs_read; 63static vop_write_t nwfs_write; 64static vop_fsync_t nwfs_fsync; 65static vop_remove_t nwfs_remove; 66static vop_link_t nwfs_link; 67static vop_lookup_t nwfs_lookup; 68static vop_rename_t nwfs_rename; 69static vop_mkdir_t nwfs_mkdir; 70static vop_rmdir_t nwfs_rmdir; 71static vop_symlink_t nwfs_symlink; 72static vop_readdir_t nwfs_readdir; 73static vop_strategy_t nwfs_strategy; 74static vop_print_t nwfs_print; 75static vop_pathconf_t nwfs_pathconf; 76 77/* Global vfs data structures for nwfs */ 78struct vop_vector nwfs_vnodeops = { 79 .vop_default = &default_vnodeops, 80 81 .vop_access = nwfs_access, 82 .vop_close = nwfs_close, 83 .vop_create = nwfs_create, 84 .vop_fsync = nwfs_fsync, 85 .vop_getattr = nwfs_getattr, 86 .vop_getpages = nwfs_getpages, 87 .vop_inactive = nwfs_inactive, 88 .vop_ioctl = nwfs_ioctl, 89 .vop_link = nwfs_link, 90 .vop_lookup = nwfs_lookup, 91 .vop_mkdir = nwfs_mkdir, 92 .vop_mknod = nwfs_mknod, 93 .vop_open = nwfs_open, 94 .vop_pathconf = nwfs_pathconf, 95 .vop_print = nwfs_print, 96 .vop_putpages = nwfs_putpages, 97 .vop_read = nwfs_read, 98 .vop_readdir = nwfs_readdir, 99 .vop_reclaim = nwfs_reclaim, 100 .vop_remove = nwfs_remove, 101 .vop_rename = nwfs_rename, 102 .vop_rmdir = nwfs_rmdir, 103 .vop_setattr = nwfs_setattr, 104 .vop_strategy = nwfs_strategy, 105 .vop_symlink = nwfs_symlink, 106 .vop_write = nwfs_write, 107}; 108 109/* 110 * nwfs_access vnode op 111 */ 112static int 113nwfs_access(ap) 114 struct vop_access_args /* { 115 struct vnode *a_vp; 116 accmode_t a_accmode; 117 struct ucred *a_cred; 118 struct thread *td; 119 } */ *ap; 120{ 121 struct vnode *vp = ap->a_vp; 122 mode_t mpmode; 123 struct nwmount *nmp = VTONWFS(vp); 124 125 NCPVNDEBUG("\n"); 126 if ((ap->a_accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 127 switch (vp->v_type) { 128 case VREG: case VDIR: case VLNK: 129 return (EROFS); 130 default: 131 break; 132 } 133 } 134 mpmode = vp->v_type == VREG ? nmp->m.file_mode : 135 nmp->m.dir_mode; 136 return (vaccess(vp->v_type, mpmode, nmp->m.uid, 137 nmp->m.gid, ap->a_accmode, ap->a_cred, NULL)); 138} 139/* 140 * nwfs_open vnode op 141 */ 142/* ARGSUSED */ 143static int 144nwfs_open(ap) 145 struct vop_open_args /* { 146 struct vnode *a_vp; 147 int a_mode; 148 struct ucred *a_cred; 149 struct thread *td; 150 } */ *ap; 151{ 152 struct vnode *vp = ap->a_vp; 153 int mode = ap->a_mode; 154 struct nwnode *np = VTONW(vp); 155 struct ncp_open_info no; 156 struct nwmount *nmp = VTONWFS(vp); 157 struct vattr vattr; 158 int error, nwm; 159 160 NCPVNDEBUG("%s,%d\n", np->n_name, np->opened); 161 if (vp->v_type != VREG && vp->v_type != VDIR) { 162 NCPFATAL("open vtype = %d\n", vp->v_type); 163 return (EACCES); 164 } 165 if (vp->v_type == VDIR) return 0; /* nothing to do now */ 166 if (np->n_flag & NMODIFIED) { 167 if ((error = nwfs_vinvalbuf(vp, ap->a_td)) == EINTR) 168 return (error); 169 np->n_atime = 0; 170 error = VOP_GETATTR(vp, &vattr, ap->a_cred); 171 if (error) return (error); 172 np->n_mtime = vattr.va_mtime.tv_sec; 173 } else { 174 error = VOP_GETATTR(vp, &vattr, ap->a_cred); 175 if (error) return (error); 176 if (np->n_mtime != vattr.va_mtime.tv_sec) { 177 if ((error = nwfs_vinvalbuf(vp, ap->a_td)) == EINTR) 178 return (error); 179 np->n_mtime = vattr.va_mtime.tv_sec; 180 } 181 } 182 if (np->opened) { 183 np->opened++; 184 return 0; 185 } 186 nwm = AR_READ; 187 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 188 nwm |= AR_WRITE; 189 error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN, 190 0, nwm, &no, ap->a_td, ap->a_cred); 191 if (error) { 192 if (mode & FWRITE) 193 return EACCES; 194 nwm = AR_READ; 195 error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN, 0, 196 nwm, &no, ap->a_td, ap->a_cred); 197 } 198 if (!error) { 199 np->opened++; 200 np->n_fh = no.fh; 201 np->n_origfh = no.origfh; 202 } 203 np->n_atime = 0; 204 return (error); 205} 206 207static int 208nwfs_close(ap) 209 struct vop_close_args /* { 210 struct vnodeop_desc *a_desc; 211 struct vnode *a_vp; 212 int a_fflag; 213 struct ucred *a_cred; 214 struct thread *td; 215 } */ *ap; 216{ 217 struct vnode *vp = ap->a_vp; 218 struct nwnode *np = VTONW(vp); 219 int error; 220 221 NCPVNDEBUG("name=%s,pid=%d,c=%d\n", np->n_name, ap->a_td->td_proc->p_pid, 222 np->opened); 223 224 if (vp->v_type == VDIR) return 0; /* nothing to do now */ 225 error = 0; 226 VI_LOCK(vp); 227 if (np->opened == 0) { 228 VI_UNLOCK(vp); 229 return 0; 230 } 231 VI_UNLOCK(vp); 232 error = nwfs_vinvalbuf(vp, ap->a_td); 233 VI_LOCK(vp); 234 if (np->opened == 0) { 235 VI_UNLOCK(vp); 236 return 0; 237 } 238 if (--np->opened == 0) { 239 VI_UNLOCK(vp); 240 error = ncp_close_file(NWFSTOCONN(VTONWFS(vp)), &np->n_fh, 241 ap->a_td, ap->a_cred); 242 } else 243 VI_UNLOCK(vp); 244 np->n_atime = 0; 245 return (error); 246} 247 248/* 249 * nwfs_getattr call from vfs. 250 */ 251static int 252nwfs_getattr(ap) 253 struct vop_getattr_args /* { 254 struct vnode *a_vp; 255 struct vattr *a_vap; 256 struct ucred *a_cred; 257 } */ *ap; 258{ 259 struct vnode *vp = ap->a_vp; 260 struct nwnode *np = VTONW(vp); 261 struct vattr *va=ap->a_vap; 262 struct nwmount *nmp = VTONWFS(vp); 263 struct thread *td = curthread; 264 struct nw_entry_info fattr; 265 int error; 266 u_int32_t oldsize; 267 268 NCPVNDEBUG("%lx:%d: '%s' %d\n", (long)vp, nmp->n_volume, np->n_name, (vp->v_vflag & VV_ROOT) != 0); 269 error = nwfs_attr_cachelookup(vp, va); 270 if (!error) return 0; 271 NCPVNDEBUG("not in cache\n"); 272 oldsize = np->n_size; 273 if (np->n_flag & NVOLUME) { 274 error = ncp_obtain_info(nmp, np->n_fid.f_id, 0, NULL, &fattr, 275 td, ap->a_cred); 276 } else { 277 error = ncp_obtain_info(nmp, np->n_fid.f_parent, np->n_nmlen, 278 np->n_name, &fattr, td, ap->a_cred); 279 } 280 if (error) { 281 NCPVNDEBUG("error %d\n", error); 282 return error; 283 } 284 nwfs_attr_cacheenter(vp, &fattr); 285 *va = np->n_vattr; 286 if (np->opened) 287 np->n_size = oldsize; 288 return (0); 289} 290/* 291 * nwfs_setattr call from vfs. 292 */ 293static int 294nwfs_setattr(ap) 295 struct vop_setattr_args /* { 296 struct vnode *a_vp; 297 struct vattr *a_vap; 298 struct ucred *a_cred; 299 } */ *ap; 300{ 301 struct vnode *vp = ap->a_vp; 302 struct nwnode *np = VTONW(vp); 303 struct vattr *vap = ap->a_vap; 304 u_quad_t tsize=0; 305 int error = 0; 306 307 NCPVNDEBUG("\n"); 308 if (vap->va_flags != VNOVAL) 309 return (EOPNOTSUPP); 310 /* 311 * Disallow write attempts if the filesystem is mounted read-only. 312 */ 313 if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 314 vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 315 vap->va_mode != (mode_t)VNOVAL) &&(vp->v_mount->mnt_flag & MNT_RDONLY)) 316 return (EROFS); 317 if (vap->va_size != VNOVAL) { 318 switch (vp->v_type) { 319 case VDIR: 320 return (EISDIR); 321 case VREG: 322 /* 323 * Disallow write attempts if the filesystem is 324 * mounted read-only. 325 */ 326 if (vp->v_mount->mnt_flag & MNT_RDONLY) 327 return (EROFS); 328 vnode_pager_setsize(vp, (u_long)vap->va_size); 329 tsize = np->n_size; 330 np->n_size = vap->va_size; 331 break; 332 default: 333 return EINVAL; 334 }; 335 } 336 error = ncp_setattr(vp, vap, ap->a_cred, curthread); 337 if (error && vap->va_size != VNOVAL) { 338 np->n_size = tsize; 339 vnode_pager_setsize(vp, (u_long)tsize); 340 } 341 np->n_atime = 0; /* invalidate cache */ 342 VOP_GETATTR(vp, vap, ap->a_cred); 343 np->n_mtime = vap->va_mtime.tv_sec; 344 return (0); 345} 346/* 347 * nwfs_read call. 348 */ 349static int 350nwfs_read(ap) 351 struct vop_read_args /* { 352 struct vnode *a_vp; 353 struct uio *a_uio; 354 int a_ioflag; 355 struct ucred *a_cred; 356 } */ *ap; 357{ 358 struct vnode *vp = ap->a_vp; 359 struct uio *uio=ap->a_uio; 360 int error; 361 NCPVNDEBUG("nwfs_read:\n"); 362 363 if (vp->v_type != VREG && vp->v_type != VDIR) 364 return (EPERM); 365 error = nwfs_readvnode(vp, uio, ap->a_cred); 366 return error; 367} 368 369static int 370nwfs_write(ap) 371 struct vop_write_args /* { 372 struct vnode *a_vp; 373 struct uio *a_uio; 374 int a_ioflag; 375 struct ucred *a_cred; 376 } */ *ap; 377{ 378 struct vnode *vp = ap->a_vp; 379 struct uio *uio = ap->a_uio; 380 int error; 381 382 NCPVNDEBUG("%d,ofs=%d,sz=%d\n", vp->v_type, (int)uio->uio_offset, uio->uio_resid); 383 384 if (vp->v_type != VREG) 385 return (EPERM); 386 error = nwfs_writevnode(vp, uio, ap->a_cred, ap->a_ioflag); 387 return(error); 388} 389/* 390 * nwfs_create call 391 * Create a regular file. On entry the directory to contain the file being 392 * created is locked. We must release before we return. We must also free 393 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or 394 * only if the SAVESTART bit in cn_flags is clear on success. 395 */ 396static int 397nwfs_create(ap) 398 struct vop_create_args /* { 399 struct vnode *a_dvp; 400 struct vnode **a_vpp; 401 struct componentname *a_cnp; 402 struct vattr *a_vap; 403 } */ *ap; 404{ 405 struct vnode *dvp = ap->a_dvp; 406 struct vattr *vap = ap->a_vap; 407 struct vnode **vpp=ap->a_vpp; 408 struct componentname *cnp = ap->a_cnp; 409 struct vnode *vp = (struct vnode *)0; 410 int error = 0, fmode; 411 struct vattr vattr; 412 struct nwnode *np; 413 struct ncp_open_info no; 414 struct nwmount *nmp=VTONWFS(dvp); 415 ncpfid fid; 416 417 418 NCPVNDEBUG("\n"); 419 *vpp = NULL; 420 if (vap->va_type == VSOCK) 421 return (EOPNOTSUPP); 422 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 423 return (error); 424 fmode = AR_READ | AR_WRITE; 425/* if (vap->va_vaflags & VA_EXCLUSIVE) 426 fmode |= AR_DENY_READ | AR_DENY_WRITE;*/ 427 428 error = ncp_open_create_file_or_subdir(nmp, dvp, cnp->cn_namelen, cnp->cn_nameptr, 429 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE, 430 0, fmode, &no, cnp->cn_thread, cnp->cn_cred); 431 if (!error) { 432 error = ncp_close_file(NWFSTOCONN(nmp), &no.fh, cnp->cn_thread, cnp->cn_cred); 433 fid.f_parent = VTONW(dvp)->n_fid.f_id; 434 fid.f_id = no.fattr.dirEntNum; 435 error = nwfs_nget(VTOVFS(dvp), fid, &no.fattr, dvp, &vp); 436 if (!error) { 437 np = VTONW(vp); 438 np->opened = 0; 439 *vpp = vp; 440 } 441 if (cnp->cn_flags & MAKEENTRY) 442 cache_enter(dvp, vp, cnp); 443 } 444 return (error); 445} 446 447/* 448 * nwfs_remove call. It isn't possible to emulate UFS behaivour because 449 * NetWare doesn't allow delete/rename operations on an opened file. 450 */ 451static int 452nwfs_remove(ap) 453 struct vop_remove_args /* { 454 struct vnodeop_desc *a_desc; 455 struct vnode * a_dvp; 456 struct vnode * a_vp; 457 struct componentname * a_cnp; 458 } */ *ap; 459{ 460 struct vnode *vp = ap->a_vp; 461 struct vnode *dvp = ap->a_dvp; 462 struct componentname *cnp = ap->a_cnp; 463 struct nwnode *np = VTONW(vp); 464 struct nwmount *nmp = VTONWFS(vp); 465 int error; 466 467 if (vp->v_type == VDIR || np->opened || vrefcnt(vp) != 1) 468 return EPERM; 469 cache_purge(vp); 470 error = ncp_DeleteNSEntry(nmp, VTONW(dvp)->n_fid.f_id, 471 cnp->cn_namelen, cnp->cn_nameptr, cnp->cn_thread, cnp->cn_cred); 472 if (error == 0) 473 np->n_flag |= NSHOULDFREE; 474 else if (error == 0x899c) 475 error = EACCES; 476 return (error); 477} 478 479/* 480 * nwfs_file rename call 481 */ 482static int 483nwfs_rename(ap) 484 struct vop_rename_args /* { 485 struct vnode *a_fdvp; 486 struct vnode *a_fvp; 487 struct componentname *a_fcnp; 488 struct vnode *a_tdvp; 489 struct vnode *a_tvp; 490 struct componentname *a_tcnp; 491 } */ *ap; 492{ 493 struct vnode *fvp = ap->a_fvp; 494 struct vnode *tvp = ap->a_tvp; 495 struct vnode *fdvp = ap->a_fdvp; 496 struct vnode *tdvp = ap->a_tdvp; 497 struct componentname *tcnp = ap->a_tcnp; 498 struct componentname *fcnp = ap->a_fcnp; 499 struct nwmount *nmp=VTONWFS(fvp); 500 u_int16_t oldtype = 6; 501 int error=0; 502 503 /* Check for cross-device rename */ 504 if ((fvp->v_mount != tdvp->v_mount) || 505 (tvp && (fvp->v_mount != tvp->v_mount))) { 506 error = EXDEV; 507 goto out; 508 } 509 510 if (tvp && vrefcnt(tvp) > 1) { 511 error = EBUSY; 512 goto out; 513 } 514 if (fvp->v_type == VDIR) { 515 oldtype |= NW_TYPE_SUBDIR; 516 } else if (fvp->v_type == VREG) { 517 oldtype |= NW_TYPE_FILE; 518 } else { 519 error = EINVAL; 520 goto out; 521 } 522 if (tvp && tvp != fvp) { 523 error = ncp_DeleteNSEntry(nmp, VTONW(tdvp)->n_fid.f_id, 524 tcnp->cn_namelen, tcnp->cn_nameptr, 525 tcnp->cn_thread, tcnp->cn_cred); 526 if (error == 0x899c) error = EACCES; 527 if (error) 528 goto out_cacherem; 529 } 530 error = ncp_nsrename(NWFSTOCONN(nmp), nmp->n_volume, nmp->name_space, 531 oldtype, &nmp->m.nls, 532 VTONW(fdvp)->n_fid.f_id, fcnp->cn_nameptr, fcnp->cn_namelen, 533 VTONW(tdvp)->n_fid.f_id, tcnp->cn_nameptr, tcnp->cn_namelen, 534 tcnp->cn_thread, tcnp->cn_cred); 535 536 if (error == 0x8992) 537 error = EEXIST; 538 if (fvp->v_type == VDIR) { 539 if (tvp != NULL && tvp->v_type == VDIR) 540 cache_purge(tdvp); 541 cache_purge(fdvp); 542 } 543out_cacherem: 544 nwfs_attr_cacheremove(fdvp); 545 nwfs_attr_cacheremove(tdvp); 546 nwfs_attr_cacheremove(fvp); 547out: 548 if (tdvp == tvp) 549 vrele(tdvp); 550 else 551 vput(tdvp); 552 if (tvp) 553 vput(tvp); 554 vrele(fdvp); 555 vrele(fvp); 556 if (tvp) 557 nwfs_attr_cacheremove(tvp); 558 /* 559 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry. 560 */ 561 if (error == ENOENT) 562 error = 0; 563 return (error); 564} 565 566/* 567 * nwfs hard link create call 568 * Netware filesystems don't know what links are. 569 */ 570static int 571nwfs_link(ap) 572 struct vop_link_args /* { 573 struct vnode *a_tdvp; 574 struct vnode *a_vp; 575 struct componentname *a_cnp; 576 } */ *ap; 577{ 578 return EOPNOTSUPP; 579} 580 581/* 582 * nwfs_symlink link create call 583 * Netware filesystems don't know what symlinks are. 584 */ 585static int 586nwfs_symlink(ap) 587 struct vop_symlink_args /* { 588 struct vnode *a_dvp; 589 struct vnode **a_vpp; 590 struct componentname *a_cnp; 591 struct vattr *a_vap; 592 char *a_target; 593 } */ *ap; 594{ 595 return (EOPNOTSUPP); 596} 597 598static int nwfs_mknod(ap) 599 struct vop_mknod_args /* { 600 } */ *ap; 601{ 602 return (EOPNOTSUPP); 603} 604 605/* 606 * nwfs_mkdir call 607 */ 608static int 609nwfs_mkdir(ap) 610 struct vop_mkdir_args /* { 611 struct vnode *a_dvp; 612 struct vnode **a_vpp; 613 struct componentname *a_cnp; 614 struct vattr *a_vap; 615 } */ *ap; 616{ 617 struct vnode *dvp = ap->a_dvp; 618/* struct vattr *vap = ap->a_vap;*/ 619 struct componentname *cnp = ap->a_cnp; 620 int len=cnp->cn_namelen; 621 struct ncp_open_info no; 622 struct vnode *newvp = (struct vnode *)0; 623 ncpfid fid; 624 int error = 0; 625 struct vattr vattr; 626 char *name=cnp->cn_nameptr; 627 628 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 629 return (error); 630 if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) { 631 return EEXIST; 632 } 633 if (ncp_open_create_file_or_subdir(VTONWFS(dvp), dvp, cnp->cn_namelen, 634 cnp->cn_nameptr, OC_MODE_CREATE, aDIR, 0xffff, 635 &no, cnp->cn_thread, cnp->cn_cred) != 0) { 636 error = EACCES; 637 } else { 638 error = 0; 639 } 640 if (!error) { 641 fid.f_parent = VTONW(dvp)->n_fid.f_id; 642 fid.f_id = no.fattr.dirEntNum; 643 error = nwfs_nget(VTOVFS(dvp), fid, &no.fattr, dvp, &newvp); 644 if (!error) { 645 newvp->v_type = VDIR; 646 *ap->a_vpp = newvp; 647 } 648 } 649 return (error); 650} 651 652/* 653 * nwfs_remove directory call 654 */ 655static int 656nwfs_rmdir(ap) 657 struct vop_rmdir_args /* { 658 struct vnode *a_dvp; 659 struct vnode *a_vp; 660 struct componentname *a_cnp; 661 } */ *ap; 662{ 663 struct vnode *vp = ap->a_vp; 664 struct vnode *dvp = ap->a_dvp; 665 struct componentname *cnp = ap->a_cnp; 666 struct nwnode *np = VTONW(vp); 667 struct nwmount *nmp = VTONWFS(vp); 668 struct nwnode *dnp = VTONW(dvp); 669 int error = EIO; 670 671 if (dvp == vp) 672 return EINVAL; 673 674 error = ncp_DeleteNSEntry(nmp, dnp->n_fid.f_id, 675 cnp->cn_namelen, cnp->cn_nameptr, cnp->cn_thread, cnp->cn_cred); 676 if (error == 0) 677 np->n_flag |= NSHOULDFREE; 678 else if (error == NWE_DIR_NOT_EMPTY) 679 error = ENOTEMPTY; 680 dnp->n_flag |= NMODIFIED; 681 nwfs_attr_cacheremove(dvp); 682 cache_purge(dvp); 683 cache_purge(vp); 684 return (error); 685} 686 687/* 688 * nwfs_readdir call 689 */ 690static int 691nwfs_readdir(ap) 692 struct vop_readdir_args /* { 693 struct vnode *a_vp; 694 struct uio *a_uio; 695 struct ucred *a_cred; 696 int *a_eofflag; 697 u_long *a_cookies; 698 int a_ncookies; 699 } */ *ap; 700{ 701 struct vnode *vp = ap->a_vp; 702 struct uio *uio = ap->a_uio; 703 int error; 704 705 if (vp->v_type != VDIR) 706 return (EPERM); 707 if (ap->a_ncookies) { 708 printf("nwfs_readdir: no support for cookies now..."); 709 return (EOPNOTSUPP); 710 } 711 712 error = nwfs_readvnode(vp, uio, ap->a_cred); 713 return error; 714} 715/* ARGSUSED */ 716static int 717nwfs_fsync(ap) 718 struct vop_fsync_args /* { 719 struct vnodeop_desc *a_desc; 720 struct vnode * a_vp; 721 struct ucred * a_cred; 722 int a_waitfor; 723 struct thread *a_td; 724 } */ *ap; 725{ 726/* return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ 727 return (0); 728} 729 730/* ARGSUSED */ 731static 732int nwfs_print (ap) 733 struct vop_print_args /* { 734 struct vnode *a_vp; 735 } */ *ap; 736{ 737 struct vnode *vp = ap->a_vp; 738 struct nwnode *np = VTONW(vp); 739 740 printf("\tnwfs node: name = '%s', fid = %d, pfid = %d\n", 741 np->n_name, np->n_fid.f_id, np->n_fid.f_parent); 742 return (0); 743} 744 745static int nwfs_pathconf (ap) 746 struct vop_pathconf_args /* { 747 struct vnode *vp; 748 int name; 749 register_t *retval; 750 } */ *ap; 751{ 752 int name=ap->a_name, error=0; 753 register_t *retval=ap->a_retval; 754 755 switch(name){ 756 case _PC_LINK_MAX: 757 *retval=0; 758 break; 759 case _PC_NAME_MAX: 760 *retval=NCP_MAX_FILENAME; /* XXX from nwfsnode */ 761 break; 762 case _PC_PATH_MAX: 763 *retval=NCP_MAXPATHLEN; /* XXX from nwfsnode */ 764 break; 765 default: 766 error=EINVAL; 767 } 768 return(error); 769} 770 771static int nwfs_strategy (ap) 772 struct vop_strategy_args /* { 773 struct buf *a_bp 774 } */ *ap; 775{ 776 struct buf *bp=ap->a_bp; 777 struct ucred *cr; 778 struct thread *td; 779 780 NCPVNDEBUG("\n"); 781 if (bp->b_flags & B_ASYNC) 782 td = (struct thread *)0; 783 else 784 td = curthread; /* XXX */ 785 if (bp->b_iocmd == BIO_READ) 786 cr = bp->b_rcred; 787 else 788 cr = bp->b_wcred; 789 /* 790 * If the op is asynchronous and an i/o daemon is waiting 791 * queue the request, wake it up and wait for completion 792 * otherwise just do it ourselves. 793 */ 794 if ((bp->b_flags & B_ASYNC) == 0 ) 795 (void)nwfs_doio(ap->a_vp, bp, cr, td); 796 return (0); 797} 798 799 800/* 801 * How to keep the brain busy ... 802 * Currently lookup routine can make two lookup for vnode. This can be 803 * avoided by reorg the code. 804 */ 805int 806nwfs_lookup(ap) 807 struct vop_lookup_args /* { 808 struct vnodeop_desc *a_desc; 809 struct vnode *a_dvp; 810 struct vnode **a_vpp; 811 struct componentname *a_cnp; 812 } */ *ap; 813{ 814 struct componentname *cnp = ap->a_cnp; 815 struct vnode *dvp = ap->a_dvp; 816 struct vnode **vpp = ap->a_vpp; 817 int flags = cnp->cn_flags; 818 struct vnode *vp; 819 struct nwmount *nmp; 820 struct mount *mp = dvp->v_mount; 821 struct nwnode *dnp, *npp; 822 struct nw_entry_info fattr, *fap; 823 ncpfid fid; 824 int nameiop=cnp->cn_nameiop, islastcn; 825 int error = 0, notfound; 826 struct thread *td = cnp->cn_thread; 827 char _name[cnp->cn_namelen+1]; 828 bcopy(cnp->cn_nameptr, _name, cnp->cn_namelen); 829 _name[cnp->cn_namelen]=0; 830 831 if (dvp->v_type != VDIR) 832 return (ENOTDIR); 833 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) { 834 printf("nwfs_lookup: invalid '..'\n"); 835 return EIO; 836 } 837 838 NCPVNDEBUG("%d '%s' in '%s' id=d\n", nameiop, _name, 839 VTONW(dvp)->n_name/*, VTONW(dvp)->n_name*/); 840 841 islastcn = flags & ISLASTCN; 842 if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) 843 return (EROFS); 844 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td))) 845 return (error); 846 nmp = VFSTONWFS(mp); 847 dnp = VTONW(dvp); 848/* 849printf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_vflag & VV_ROOT, (int)flags & ISDOTDOT); 850*/ 851 error = ncp_pathcheck(cnp->cn_nameptr, cnp->cn_namelen, &nmp->m.nls, 852 (nameiop == CREATE || nameiop == RENAME) && (nmp->m.nls.opt & NWHP_NOSTRICT) == 0); 853 if (error) 854 return ENOENT; 855 856 error = cache_lookup(dvp, vpp, cnp); 857 NCPVNDEBUG("cache_lookup returned %d\n", error); 858 if (error > 0) 859 return error; 860 if (error) { /* name was found */ 861 struct vattr vattr; 862 863 vp = *vpp; 864 if (!VOP_GETATTR(vp, &vattr, cnp->cn_cred) && 865 vattr.va_ctime.tv_sec == VTONW(vp)->n_ctime) { 866 if (nameiop != LOOKUP && islastcn) 867 cnp->cn_flags |= SAVENAME; 868 NCPVNDEBUG("use cached vnode"); 869 return (0); 870 } 871 cache_purge(vp); 872 if (vp != dvp) 873 vput(vp); 874 else 875 vrele(vp); 876 *vpp = NULLVP; 877 } 878 /* not in cache, so ... */ 879 error = 0; 880 *vpp = NULLVP; 881 fap = NULL; 882 if (flags & ISDOTDOT) { 883 if (NWCMPF(&dnp->n_parent, &nmp->n_rootent)) { 884 fid = nmp->n_rootent; 885 fap = NULL; 886 notfound = 0; 887 } else { 888 error = nwfs_lookupnp(nmp, dnp->n_parent, td, &npp); 889 if (error) { 890 return error; 891 } 892 fid = dnp->n_parent; 893 fap = &fattr; 894 /*np = *npp;*/ 895 notfound = ncp_obtain_info(nmp, npp->n_dosfid, 896 0, NULL, fap, td, cnp->cn_cred); 897 } 898 } else { 899 fap = &fattr; 900 notfound = ncp_lookup(dvp, cnp->cn_namelen, cnp->cn_nameptr, 901 fap, td, cnp->cn_cred); 902 fid.f_id = fap->dirEntNum; 903 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { 904 fid.f_parent = dnp->n_fid.f_parent; 905 } else 906 fid.f_parent = dnp->n_fid.f_id; 907 NCPVNDEBUG("call to ncp_lookup returned=%d\n", notfound); 908 } 909 if (notfound && notfound < 0x80 ) 910 return (notfound); /* hard error */ 911 if (notfound) { /* entry not found */ 912 /* Handle RENAME or CREATE case... */ 913 if ((nameiop == CREATE || nameiop == RENAME) && islastcn) { 914 cnp->cn_flags |= SAVENAME; 915 return (EJUSTRETURN); 916 } 917 return ENOENT; 918 }/* else { 919 NCPVNDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 920 }*/ 921 /* handle DELETE case ... */ 922 if (nameiop == DELETE && islastcn) { /* delete last component */ 923 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_thread); 924 if (error) return (error); 925 if (NWCMPF(&dnp->n_fid, &fid)) { /* we found ourselfs */ 926 VREF(dvp); 927 *vpp = dvp; 928 return 0; 929 } 930 error = nwfs_nget(mp, fid, fap, dvp, &vp); 931 if (error) return (error); 932 *vpp = vp; 933 cnp->cn_flags |= SAVENAME; /* I free it later */ 934 return (0); 935 } 936 if (nameiop == RENAME && islastcn) { 937 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, cnp->cn_thread); 938 if (error) return (error); 939 if (NWCMPF(&dnp->n_fid, &fid)) return EISDIR; 940 error = nwfs_nget(mp, fid, fap, dvp, &vp); 941 if (error) return (error); 942 *vpp = vp; 943 cnp->cn_flags |= SAVENAME; 944 return (0); 945 } 946 if (flags & ISDOTDOT) { 947 VOP_UNLOCK(dvp, 0); /* race to get the inode */ 948 error = nwfs_nget(mp, fid, NULL, NULL, &vp); 949 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 950 if (error) 951 return (error); 952 *vpp = vp; 953 } else if (NWCMPF(&dnp->n_fid, &fid)) { 954 vref(dvp); 955 *vpp = dvp; 956 } else { 957 error = nwfs_nget(mp, fid, fap, dvp, &vp); 958 if (error) return (error); 959 *vpp = vp; 960 NCPVNDEBUG("lookup: getnewvp!\n"); 961 } 962 if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 963 VTONW(*vpp)->n_ctime = VTONW(*vpp)->n_vattr.va_ctime.tv_sec; 964 cache_enter(dvp, *vpp, cnp); 965 } 966 return (0); 967} 968