118}; 119 120static int 121smbfs_access(ap) 122 struct vop_access_args /* { 123 struct vnode *a_vp; 124 int a_mode; 125 struct ucred *a_cred; 126 struct thread *a_td; 127 } */ *ap; 128{ 129 struct vnode *vp = ap->a_vp; 130 mode_t mode = ap->a_mode; 131 mode_t mpmode; 132 struct smbmount *smp = VTOSMBFS(vp); 133 134 SMBVDEBUG("\n"); 135 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 136 switch (vp->v_type) { 137 case VREG: case VDIR: case VLNK: 138 return EROFS; 139 default: 140 break; 141 } 142 } 143 mpmode = vp->v_type == VREG ? smp->sm_file_mode : smp->sm_dir_mode; 144 return (vaccess(vp->v_type, mpmode, smp->sm_uid, 145 smp->sm_gid, ap->a_mode, ap->a_cred, NULL)); 146} 147 148/* ARGSUSED */ 149static int 150smbfs_open(ap) 151 struct vop_open_args /* { 152 struct vnode *a_vp; 153 int a_mode; 154 struct ucred *a_cred; 155 struct thread *a_td; 156 } */ *ap; 157{ 158 struct vnode *vp = ap->a_vp; 159 struct smbnode *np = VTOSMB(vp); 160 struct smb_cred scred; 161 struct vattr vattr; 162 int mode = ap->a_mode; 163 int error, accmode; 164 165 SMBVDEBUG("%s,%d\n", np->n_name, (np->n_flag & NOPEN) != 0); 166 if (vp->v_type != VREG && vp->v_type != VDIR) { 167 SMBFSERR("open eacces vtype=%d\n", vp->v_type); 168 return EACCES; 169 } 170 if (vp->v_type == VDIR) { 171 np->n_flag |= NOPEN; 172 return 0; 173 } 174 if (np->n_flag & NMODIFIED) { 175 if ((error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1)) == EINTR) 176 return error; 177 smbfs_attr_cacheremove(vp); 178 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td); 179 if (error) 180 return error; 181 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 182 } else { 183 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td); 184 if (error) 185 return error; 186 if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) { 187 error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1); 188 if (error == EINTR) 189 return error; 190 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 191 } 192 } 193 if ((np->n_flag & NOPEN) != 0) 194 return 0; 195 /* 196 * Use DENYNONE to give unixy semantics of permitting 197 * everything not forbidden by permissions. Ie denial 198 * is up to server with clients/openers needing to use 199 * advisory locks for further control. 200 */ 201 accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 202 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 203 accmode = SMB_SM_DENYNONE|SMB_AM_OPENRW; 204 smb_makescred(&scred, ap->a_td, ap->a_cred); 205 error = smbfs_smb_open(np, accmode, &scred); 206 if (error) { 207 if (mode & FWRITE) 208 return EACCES; 209 else if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 210 accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 211 error = smbfs_smb_open(np, accmode, &scred); 212 } 213 } 214 if (error == 0) 215 np->n_flag |= NOPEN; 216 smbfs_attr_cacheremove(vp); 217 return error; 218} 219 220/* 221 * XXX: VOP_CLOSE() usually called without lock held which is suck. Here we 222 * do some heruistic to determine if vnode should be locked. 223 */ 224static int 225smbfs_close(ap) 226 struct vop_close_args /* { 227 struct vnodeop_desc *a_desc; 228 struct vnode *a_vp; 229 int a_fflag; 230 struct ucred *a_cred; 231 struct thread *a_td; 232 } */ *ap; 233{ 234 struct vnode *vp = ap->a_vp; 235 struct thread *td = ap->a_td; 236 struct smbnode *np = VTOSMB(vp); 237 struct smb_cred scred; 238 int dolock; 239 240 VI_LOCK(vp); 241 dolock = (vp->v_iflag & VI_XLOCK) == 0; 242 if (dolock) 243 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK, td); 244 else 245 VI_UNLOCK(vp); 246 if (vp->v_type == VDIR && (np->n_flag & NOPEN) != 0 && 247 np->n_dirseq != NULL) { 248 smb_makescred(&scred, td, ap->a_cred); 249 smbfs_findclose(np->n_dirseq, &scred); 250 np->n_dirseq = NULL; 251 } 252 if (dolock) 253 VOP_UNLOCK(vp, 0, td); 254 return 0; 255} 256 257/* 258 * smbfs_getattr call from vfs. 259 */ 260static int 261smbfs_getattr(ap) 262 struct vop_getattr_args /* { 263 struct vnode *a_vp; 264 struct vattr *a_vap; 265 struct ucred *a_cred; 266 struct thread *a_td; 267 } */ *ap; 268{ 269 struct vnode *vp = ap->a_vp; 270 struct smbnode *np = VTOSMB(vp); 271 struct vattr *va=ap->a_vap; 272 struct smbfattr fattr; 273 struct smb_cred scred; 274 u_quad_t oldsize; 275 int error; 276 277 SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_vflag & VV_ROOT) != 0); 278 error = smbfs_attr_cachelookup(vp, va); 279 if (!error) 280 return 0; 281 SMBVDEBUG("not in the cache\n"); 282 smb_makescred(&scred, ap->a_td, ap->a_cred); 283 oldsize = np->n_size; 284 error = smbfs_smb_lookup(np, NULL, 0, &fattr, &scred); 285 if (error) { 286 SMBVDEBUG("error %d\n", error); 287 return error; 288 } 289 smbfs_attr_cacheenter(vp, &fattr); 290 smbfs_attr_cachelookup(vp, va); 291 if (np->n_flag & NOPEN) 292 np->n_size = oldsize; 293 return 0; 294} 295 296static int 297smbfs_setattr(ap) 298 struct vop_setattr_args /* { 299 struct vnode *a_vp; 300 struct vattr *a_vap; 301 struct ucred *a_cred; 302 struct thread *a_td; 303 } */ *ap; 304{ 305 struct vnode *vp = ap->a_vp; 306 struct smbnode *np = VTOSMB(vp); 307 struct vattr *vap = ap->a_vap; 308 struct timespec *mtime, *atime; 309 struct smb_cred scred; 310 struct smb_share *ssp = np->n_mount->sm_share; 311 struct smb_vc *vcp = SSTOVC(ssp); 312 u_quad_t tsize = 0; 313 int isreadonly, doclose, error = 0; 314 315 SMBVDEBUG("\n"); 316 if (vap->va_flags != VNOVAL) 317 return EOPNOTSUPP; 318 isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 319 /* 320 * Disallow write attempts if the filesystem is mounted read-only. 321 */ 322 if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 323 vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 324 vap->va_mode != (mode_t)VNOVAL) && isreadonly) 325 return EROFS; 326 smb_makescred(&scred, ap->a_td, ap->a_cred); 327 if (vap->va_size != VNOVAL) { 328 switch (vp->v_type) { 329 case VDIR: 330 return EISDIR; 331 case VREG: 332 break; 333 default: 334 return EINVAL; 335 }; 336 if (isreadonly) 337 return EROFS; 338 doclose = 0; 339 vnode_pager_setsize(vp, (u_long)vap->va_size); 340 tsize = np->n_size; 341 np->n_size = vap->va_size; 342 if ((np->n_flag & NOPEN) == 0) { 343 error = smbfs_smb_open(np, 344 SMB_SM_DENYNONE|SMB_AM_OPENRW, 345 &scred); 346 if (error == 0) 347 doclose = 1; 348 } 349 if (error == 0) 350 error = smbfs_smb_setfsize(np, vap->va_size, &scred); 351 if (doclose) 352 smbfs_smb_close(ssp, np->n_fid, NULL, &scred); 353 if (error) { 354 np->n_size = tsize; 355 vnode_pager_setsize(vp, (u_long)tsize); 356 return error; 357 } 358 } 359 mtime = atime = NULL; 360 if (vap->va_mtime.tv_sec != VNOVAL) 361 mtime = &vap->va_mtime; 362 if (vap->va_atime.tv_sec != VNOVAL) 363 atime = &vap->va_atime; 364 if (mtime != atime) { 365 if (ap->a_cred->cr_uid != VTOSMBFS(vp)->sm_uid && 366 (error = suser_cred(ap->a_cred, SUSER_ALLOWJAIL)) && 367 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 368 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 369 return (error); 370#if 0 371 if (mtime == NULL) 372 mtime = &np->n_mtime; 373 if (atime == NULL) 374 atime = &np->n_atime; 375#endif 376 /* 377 * If file is opened, then we can use handle based calls. 378 * If not, use path based ones. 379 */ 380 if ((np->n_flag & NOPEN) == 0) { 381 if (vcp->vc_flags & SMBV_WIN95) { 382 error = VOP_OPEN(vp, FWRITE, ap->a_cred, ap->a_td, -1); 383 if (!error) { 384/* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 385 VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td);*/ 386 if (mtime) 387 np->n_mtime = *mtime; 388 VOP_CLOSE(vp, FWRITE, ap->a_cred, ap->a_td); 389 } 390 } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 391 error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 392/* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred);*/ 393 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 394 error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 395 } else { 396 error = smbfs_smb_setpattr(np, 0, mtime, &scred); 397 } 398 } else { 399 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 400 error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 401 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 402 error = smbfs_smb_setftime(np, mtime, atime, &scred); 403 } else { 404 /* 405 * I have no idea how to handle this for core 406 * level servers. The possible solution is to 407 * update mtime after file is closed. 408 */ 409 SMBERROR("can't update times on an opened file\n"); 410 } 411 } 412 } 413 /* 414 * Invalidate attribute cache in case if server doesn't set 415 * required attributes. 416 */ 417 smbfs_attr_cacheremove(vp); /* invalidate cache */ 418 VOP_GETATTR(vp, vap, ap->a_cred, ap->a_td); 419 np->n_mtime.tv_sec = vap->va_mtime.tv_sec; 420 return error; 421} 422/* 423 * smbfs_read call. 424 */ 425static int 426smbfs_read(ap) 427 struct vop_read_args /* { 428 struct vnode *a_vp; 429 struct uio *a_uio; 430 int a_ioflag; 431 struct ucred *a_cred; 432 } */ *ap; 433{ 434 struct vnode *vp = ap->a_vp; 435 struct uio *uio = ap->a_uio; 436 437 SMBVDEBUG("\n"); 438 if (vp->v_type != VREG && vp->v_type != VDIR) 439 return EPERM; 440 return smbfs_readvnode(vp, uio, ap->a_cred); 441} 442 443static int 444smbfs_write(ap) 445 struct vop_write_args /* { 446 struct vnode *a_vp; 447 struct uio *a_uio; 448 int a_ioflag; 449 struct ucred *a_cred; 450 } */ *ap; 451{ 452 struct vnode *vp = ap->a_vp; 453 struct uio *uio = ap->a_uio; 454 455 SMBVDEBUG("%d,ofs=%d,sz=%d\n",vp->v_type, (int)uio->uio_offset, uio->uio_resid); 456 if (vp->v_type != VREG) 457 return (EPERM); 458 return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); 459} 460/* 461 * smbfs_create call 462 * Create a regular file. On entry the directory to contain the file being 463 * created is locked. We must release before we return. We must also free 464 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or 465 * only if the SAVESTART bit in cn_flags is clear on success. 466 */ 467static int 468smbfs_create(ap) 469 struct vop_create_args /* { 470 struct vnode *a_dvp; 471 struct vnode **a_vpp; 472 struct componentname *a_cnp; 473 struct vattr *a_vap; 474 } */ *ap; 475{ 476 struct vnode *dvp = ap->a_dvp; 477 struct vattr *vap = ap->a_vap; 478 struct vnode **vpp=ap->a_vpp; 479 struct componentname *cnp = ap->a_cnp; 480 struct smbnode *dnp = VTOSMB(dvp); 481 struct vnode *vp; 482 struct vattr vattr; 483 struct smbfattr fattr; 484 struct smb_cred scred; 485 char *name = cnp->cn_nameptr; 486 int nmlen = cnp->cn_namelen; 487 int error; 488 489 490 SMBVDEBUG("\n"); 491 *vpp = NULL; 492 if (vap->va_type != VREG) 493 return EOPNOTSUPP; 494 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread))) 495 return error; 496 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 497 498 error = smbfs_smb_create(dnp, name, nmlen, &scred); 499 if (error) 500 return error; 501 error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred); 502 if (error) 503 return error; 504 error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); 505 if (error) 506 return error; 507 *vpp = vp; 508 if (cnp->cn_flags & MAKEENTRY) 509 cache_enter(dvp, vp, cnp); 510 return error; 511} 512 513static int 514smbfs_remove(ap) 515 struct vop_remove_args /* { 516 struct vnodeop_desc *a_desc; 517 struct vnode * a_dvp; 518 struct vnode * a_vp; 519 struct componentname * a_cnp; 520 } */ *ap; 521{ 522 struct vnode *vp = ap->a_vp; 523/* struct vnode *dvp = ap->a_dvp;*/ 524 struct componentname *cnp = ap->a_cnp; 525 struct smbnode *np = VTOSMB(vp); 526 struct smb_cred scred; 527 int error; 528 529 if (vp->v_type == VDIR || (np->n_flag & NOPEN) != 0 || vrefcnt(vp) != 1) 530 return EPERM; 531 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 532 error = smbfs_smb_delete(np, &scred); 533 if (error == 0) 534 np->n_flag |= NGONE; 535 cache_purge(vp); 536 return error; 537} 538 539/* 540 * smbfs_file rename call 541 */ 542static int 543smbfs_rename(ap) 544 struct vop_rename_args /* { 545 struct vnode *a_fdvp; 546 struct vnode *a_fvp; 547 struct componentname *a_fcnp; 548 struct vnode *a_tdvp; 549 struct vnode *a_tvp; 550 struct componentname *a_tcnp; 551 } */ *ap; 552{ 553 struct vnode *fvp = ap->a_fvp; 554 struct vnode *tvp = ap->a_tvp; 555 struct vnode *fdvp = ap->a_fdvp; 556 struct vnode *tdvp = ap->a_tdvp; 557 struct componentname *tcnp = ap->a_tcnp; 558/* struct componentname *fcnp = ap->a_fcnp;*/ 559 struct smb_cred scred; 560 u_int16_t flags = 6; 561 int error=0; 562 563 /* Check for cross-device rename */ 564 if ((fvp->v_mount != tdvp->v_mount) || 565 (tvp && (fvp->v_mount != tvp->v_mount))) { 566 error = EXDEV; 567 goto out; 568 } 569 570 if (tvp && vrefcnt(tvp) > 1) { 571 error = EBUSY; 572 goto out; 573 } 574 flags = 0x10; /* verify all writes */ 575 if (fvp->v_type == VDIR) { 576 flags |= 2; 577 } else if (fvp->v_type == VREG) { 578 flags |= 1; 579 } else { 580 error = EINVAL; 581 goto out; 582 } 583 smb_makescred(&scred, tcnp->cn_thread, tcnp->cn_cred); 584 /* 585 * It seems that Samba doesn't implement SMB_COM_MOVE call... 586 */ 587#ifdef notnow 588 if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { 589 error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), 590 tcnp->cn_nameptr, tcnp->cn_namelen, flags, &scred); 591 } else 592#endif 593 { 594 /* 595 * We have to do the work atomicaly 596 */ 597 if (tvp && tvp != fvp) { 598 error = smbfs_smb_delete(VTOSMB(tvp), &scred); 599 if (error) 600 goto out_cacherem; 601 VTOSMB(fvp)->n_flag |= NGONE; 602 } 603 error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), 604 tcnp->cn_nameptr, tcnp->cn_namelen, &scred); 605 } 606 607 if (fvp->v_type == VDIR) { 608 if (tvp != NULL && tvp->v_type == VDIR) 609 cache_purge(tdvp); 610 cache_purge(fdvp); 611 } 612 613out_cacherem: 614 smbfs_attr_cacheremove(fdvp); 615 smbfs_attr_cacheremove(tdvp); 616out: 617 if (tdvp == tvp) 618 vrele(tdvp); 619 else 620 vput(tdvp); 621 if (tvp) 622 vput(tvp); 623 vrele(fdvp); 624 vrele(fvp); 625#ifdef possible_mistake 626 vgone(fvp); 627 if (tvp) 628 vgone(tvp); 629#endif 630 return error; 631} 632 633/* 634 * somtime it will come true... 635 */ 636static int 637smbfs_link(ap) 638 struct vop_link_args /* { 639 struct vnode *a_tdvp; 640 struct vnode *a_vp; 641 struct componentname *a_cnp; 642 } */ *ap; 643{ 644 return EOPNOTSUPP; 645} 646 647/* 648 * smbfs_symlink link create call. 649 * Sometime it will be functional... 650 */ 651static int 652smbfs_symlink(ap) 653 struct vop_symlink_args /* { 654 struct vnode *a_dvp; 655 struct vnode **a_vpp; 656 struct componentname *a_cnp; 657 struct vattr *a_vap; 658 char *a_target; 659 } */ *ap; 660{ 661 return EOPNOTSUPP; 662} 663 664static int 665smbfs_mknod(ap) 666 struct vop_mknod_args /* { 667 } */ *ap; 668{ 669 return EOPNOTSUPP; 670} 671 672static int 673smbfs_mkdir(ap) 674 struct vop_mkdir_args /* { 675 struct vnode *a_dvp; 676 struct vnode **a_vpp; 677 struct componentname *a_cnp; 678 struct vattr *a_vap; 679 } */ *ap; 680{ 681 struct vnode *dvp = ap->a_dvp; 682/* struct vattr *vap = ap->a_vap;*/ 683 struct vnode *vp; 684 struct componentname *cnp = ap->a_cnp; 685 struct smbnode *dnp = VTOSMB(dvp); 686 struct vattr vattr; 687 struct smb_cred scred; 688 struct smbfattr fattr; 689 char *name = cnp->cn_nameptr; 690 int len = cnp->cn_namelen; 691 int error; 692 693 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread))) { 694 return error; 695 } 696 if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 697 return EEXIST; 698 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 699 error = smbfs_smb_mkdir(dnp, name, len, &scred); 700 if (error) 701 return error; 702 error = smbfs_smb_lookup(dnp, name, len, &fattr, &scred); 703 if (error) 704 return error; 705 error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); 706 if (error) 707 return error; 708 *ap->a_vpp = vp; 709 return 0; 710} 711 712/* 713 * smbfs_remove directory call 714 */ 715static int 716smbfs_rmdir(ap) 717 struct vop_rmdir_args /* { 718 struct vnode *a_dvp; 719 struct vnode *a_vp; 720 struct componentname *a_cnp; 721 } */ *ap; 722{ 723 struct vnode *vp = ap->a_vp; 724 struct vnode *dvp = ap->a_dvp; 725 struct componentname *cnp = ap->a_cnp; 726/* struct smbmount *smp = VTOSMBFS(vp);*/ 727 struct smbnode *dnp = VTOSMB(dvp); 728 struct smbnode *np = VTOSMB(vp); 729 struct smb_cred scred; 730 int error; 731 732 if (dvp == vp) 733 return EINVAL; 734 735 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 736 error = smbfs_smb_rmdir(np, &scred); 737 if (error == 0) 738 np->n_flag |= NGONE; 739 dnp->n_flag |= NMODIFIED; 740 smbfs_attr_cacheremove(dvp); 741/* cache_purge(dvp);*/ 742 cache_purge(vp); 743 return error; 744} 745 746/* 747 * smbfs_readdir call 748 */ 749static int 750smbfs_readdir(ap) 751 struct vop_readdir_args /* { 752 struct vnode *a_vp; 753 struct uio *a_uio; 754 struct ucred *a_cred; 755 int *a_eofflag; 756 u_long *a_cookies; 757 int a_ncookies; 758 } */ *ap; 759{ 760 struct vnode *vp = ap->a_vp; 761 struct uio *uio = ap->a_uio; 762 int error; 763 764 if (vp->v_type != VDIR) 765 return (EPERM); 766#ifdef notnow 767 if (ap->a_ncookies) { 768 printf("smbfs_readdir: no support for cookies now..."); 769 return (EOPNOTSUPP); 770 } 771#endif 772 error = smbfs_readvnode(vp, uio, ap->a_cred); 773 return error; 774} 775 776/* ARGSUSED */ 777static int 778smbfs_fsync(ap) 779 struct vop_fsync_args /* { 780 struct vnodeop_desc *a_desc; 781 struct vnode * a_vp; 782 struct ucred * a_cred; 783 int a_waitfor; 784 struct thread * a_td; 785 } */ *ap; 786{ 787/* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ 788 return (0); 789} 790 791static 792int smbfs_print (ap) 793 struct vop_print_args /* { 794 struct vnode *a_vp; 795 } */ *ap; 796{ 797 struct vnode *vp = ap->a_vp; 798 struct smbnode *np = VTOSMB(vp); 799 800 if (np == NULL) { 801 printf("no smbnode data\n"); 802 return (0); 803 } 804 printf("\tname = %s, parent = %p, open = %d\n", np->n_name, 805 np->n_parent ? np->n_parent : NULL, (np->n_flag & NOPEN) != 0); 806 return (0); 807} 808 809static int 810smbfs_pathconf (ap) 811 struct vop_pathconf_args /* { 812 struct vnode *vp; 813 int name; 814 register_t *retval; 815 } */ *ap; 816{ 817 struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 818 struct smb_vc *vcp = SSTOVC(smp->sm_share); 819 register_t *retval = ap->a_retval; 820 int error = 0; 821 822 switch (ap->a_name) { 823 case _PC_LINK_MAX: 824 *retval = 0; 825 break; 826 case _PC_NAME_MAX: 827 *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 828 break; 829 case _PC_PATH_MAX: 830 *retval = 800; /* XXX: a correct one ? */ 831 break; 832 default: 833 error = EINVAL; 834 } 835 return error; 836} 837 838static int 839smbfs_strategy (ap) 840 struct vop_strategy_args /* { 841 struct buf *a_bp 842 } */ *ap; 843{ 844 struct buf *bp=ap->a_bp; 845 struct ucred *cr; 846 struct thread *td; 847 int error = 0; 848 849 SMBVDEBUG("\n"); 850 if (bp->b_flags & B_ASYNC) 851 td = (struct thread *)0; 852 else 853 td = curthread; /* XXX */ 854 if (bp->b_iocmd == BIO_READ) 855 cr = bp->b_rcred; 856 else 857 cr = bp->b_wcred; 858 859 if ((bp->b_flags & B_ASYNC) == 0 ) 860 error = smbfs_doio(ap->a_vp, bp, cr, td); 861 return error; 862} 863 864int 865smbfs_ioctl(ap) 866 struct vop_ioctl_args /* { 867 struct vnode *a_vp; 868 u_long a_command; 869 caddr_t a_data; 870 int fflag; 871 struct ucred *cred; 872 struct thread *td; 873 } */ *ap; 874{ 875 return ENOTTY; 876} 877 878static char smbfs_atl[] = "rhsvda"; 879static int 880smbfs_getextattr(struct vop_getextattr_args *ap) 881/* { 882 IN struct vnode *a_vp; 883 IN char *a_name; 884 INOUT struct uio *a_uio; 885 IN struct ucred *a_cred; 886 IN struct thread *a_td; 887}; 888*/ 889{ 890 struct vnode *vp = ap->a_vp; 891 struct thread *td = ap->a_td; 892 struct ucred *cred = ap->a_cred; 893 struct uio *uio = ap->a_uio; 894 const char *name = ap->a_name; 895 struct smbnode *np = VTOSMB(vp); 896 struct vattr vattr; 897 char buf[10]; 898 int i, attr, error; 899 900 error = VOP_ACCESS(vp, VREAD, cred, td); 901 if (error) 902 return error; 903 error = VOP_GETATTR(vp, &vattr, cred, td); 904 if (error) 905 return error; 906 if (strcmp(name, "dosattr") == 0) { 907 attr = np->n_dosattr; 908 for (i = 0; i < 6; i++, attr >>= 1) 909 buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 910 buf[i] = 0; 911 error = uiomove(buf, i, uio); 912 913 } else 914 error = EINVAL; 915 return error; 916} 917 918/* 919 * Since we expected to support F_GETLK (and SMB protocol has no such function), 920 * it is necessary to use lf_advlock(). It would be nice if this function had 921 * a callback mechanism because it will help to improve a level of consistency. 922 */ 923int 924smbfs_advlock(ap) 925 struct vop_advlock_args /* { 926 struct vnode *a_vp; 927 caddr_t a_id; 928 int a_op; 929 struct flock *a_fl; 930 int a_flags; 931 } */ *ap; 932{ 933 struct vnode *vp = ap->a_vp; 934 struct smbnode *np = VTOSMB(vp); 935 struct flock *fl = ap->a_fl; 936 caddr_t id = (caddr_t)1 /* ap->a_id */; 937/* int flags = ap->a_flags;*/ 938 struct thread *td = curthread; 939 struct smb_cred scred; 940 u_quad_t size; 941 off_t start, end, oadd; 942 int error, lkop; 943 944 if (vp->v_type == VDIR) { 945 /* 946 * SMB protocol have no support for directory locking. 947 * Although locks can be processed on local machine, I don't 948 * think that this is a good idea, because some programs 949 * can work wrong assuming directory is locked. So, we just 950 * return 'operation not supported 951 */ 952 return EOPNOTSUPP; 953 } 954 size = np->n_size; 955 switch (fl->l_whence) { 956 957 case SEEK_SET: 958 case SEEK_CUR: 959 start = fl->l_start; 960 break; 961 962 case SEEK_END: 963 if (size > OFF_MAX || 964 (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 965 return EOVERFLOW; 966 start = size + fl->l_start; 967 break; 968 969 default: 970 return EINVAL; 971 } 972 if (start < 0) 973 return EINVAL; 974 if (fl->l_len < 0) { 975 if (start == 0) 976 return EINVAL; 977 end = start - 1; 978 start += fl->l_len; 979 if (start < 0) 980 return EINVAL; 981 } else if (fl->l_len == 0) 982 end = -1; 983 else { 984 oadd = fl->l_len - 1; 985 if (oadd > OFF_MAX - start) 986 return EOVERFLOW; 987 end = start + oadd; 988 } 989 smb_makescred(&scred, td, td->td_ucred); 990 switch (ap->a_op) { 991 case F_SETLK: 992 switch (fl->l_type) { 993 case F_WRLCK: 994 lkop = SMB_LOCK_EXCL; 995 break; 996 case F_RDLCK: 997 lkop = SMB_LOCK_SHARED; 998 break; 999 case F_UNLCK: 1000 lkop = SMB_LOCK_RELEASE; 1001 break; 1002 default: 1003 return EINVAL; 1004 } 1005 error = lf_advlock(ap, &np->n_lockf, size); 1006 if (error) 1007 break; 1008 lkop = SMB_LOCK_EXCL; 1009 error = smbfs_smb_lock(np, lkop, id, start, end, &scred); 1010 if (error) { 1011 ap->a_op = F_UNLCK; 1012 lf_advlock(ap, &np->n_lockf, size); 1013 } 1014 break; 1015 case F_UNLCK: 1016 lf_advlock(ap, &np->n_lockf, size); 1017 error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, &scred); 1018 break; 1019 case F_GETLK: 1020 error = lf_advlock(ap, &np->n_lockf, size); 1021 break; 1022 default: 1023 return EINVAL; 1024 } 1025 return error; 1026} 1027 1028static int 1029smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) 1030{ 1031 static const char *badchars = "*/\\:<>;?"; 1032 static const char *badchars83 = " +|,[]="; 1033 const char *cp; 1034 int i, error; 1035 1036 if (nameiop == LOOKUP) 1037 return 0; 1038 error = ENOENT; 1039 if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { 1040 /* 1041 * Name should conform 8.3 format 1042 */ 1043 if (nmlen > 12) 1044 return ENAMETOOLONG; 1045 cp = index(name, '.'); 1046 if (cp == NULL) 1047 return error; 1048 if (cp == name || (cp - name) > 8) 1049 return error; 1050 cp = index(cp + 1, '.'); 1051 if (cp != NULL) 1052 return error; 1053 for (cp = name, i = 0; i < nmlen; i++, cp++) 1054 if (index(badchars83, *cp) != NULL) 1055 return error; 1056 } 1057 for (cp = name, i = 0; i < nmlen; i++, cp++) 1058 if (index(badchars, *cp) != NULL) 1059 return error; 1060 return 0; 1061} 1062 1063#ifndef PDIRUNLOCK 1064#define PDIRUNLOCK 0 1065#endif 1066 1067/* 1068 * Things go even weird without fixed inode numbers... 1069 */ 1070int 1071smbfs_lookup(ap) 1072 struct vop_lookup_args /* { 1073 struct vnodeop_desc *a_desc; 1074 struct vnode *a_dvp; 1075 struct vnode **a_vpp; 1076 struct componentname *a_cnp; 1077 } */ *ap; 1078{ 1079 struct componentname *cnp = ap->a_cnp; 1080 struct thread *td = cnp->cn_thread; 1081 struct vnode *dvp = ap->a_dvp; 1082 struct vnode **vpp = ap->a_vpp; 1083 struct vnode *vp; 1084 struct smbmount *smp; 1085 struct mount *mp = dvp->v_mount; 1086 struct smbnode *dnp; 1087 struct smbfattr fattr, *fap; 1088 struct smb_cred scred; 1089 char *name = cnp->cn_nameptr; 1090 int flags = cnp->cn_flags; 1091 int nameiop = cnp->cn_nameiop; 1092 int nmlen = cnp->cn_namelen; 1093 int lockparent, wantparent, error, islastcn, isdot; 1094 int killit; 1095 1096 SMBVDEBUG("\n"); 1097 cnp->cn_flags &= ~PDIRUNLOCK; 1098 if (dvp->v_type != VDIR) 1099 return ENOTDIR; 1100 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) { 1101 SMBFSERR("invalid '..'\n"); 1102 return EIO; 1103 } 1104#ifdef SMB_VNODE_DEBUG 1105 { 1106 char *cp, c; 1107 1108 cp = name + nmlen; 1109 c = *cp; 1110 *cp = 0; 1111 SMBVDEBUG("%d '%s' in '%s' id=d\n", nameiop, name, 1112 VTOSMB(dvp)->n_name); 1113 *cp = c; 1114 } 1115#endif 1116 islastcn = flags & ISLASTCN; 1117 if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) 1118 return EROFS; 1119 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) 1120 return error; 1121 lockparent = flags & LOCKPARENT; 1122 wantparent = flags & (LOCKPARENT|WANTPARENT); 1123 smp = VFSTOSMBFS(mp); 1124 dnp = VTOSMB(dvp); 1125 isdot = (nmlen == 1 && name[0] == '.'); 1126 1127 error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop); 1128 1129 if (error) 1130 return ENOENT; 1131 1132 error = cache_lookup(dvp, vpp, cnp); 1133 SMBVDEBUG("cache_lookup returned %d\n", error); 1134 if (error > 0) 1135 return error; 1136 if (error) { /* name was found */ 1137 struct vattr vattr; 1138 int vpid; 1139 1140 vp = *vpp; 1141 mp_fixme("Unlocked v_id access."); 1142 vpid = vp->v_id; 1143 if (dvp == vp) { /* lookup on current */ 1144 vref(vp); 1145 error = 0; 1146 SMBVDEBUG("cached '.'\n"); 1147 } else if (flags & ISDOTDOT) { 1148 VOP_UNLOCK(dvp, 0, td); /* unlock parent */ 1149 cnp->cn_flags |= PDIRUNLOCK; 1150 error = vget(vp, LK_EXCLUSIVE, td); 1151 if (!error && lockparent && islastcn) { 1152 error = vn_lock(dvp, LK_EXCLUSIVE, td); 1153 if (error == 0) 1154 cnp->cn_flags &= ~PDIRUNLOCK; 1155 } 1156 } else { 1157 error = vget(vp, LK_EXCLUSIVE, td); 1158 if (!lockparent || error || !islastcn) { 1159 VOP_UNLOCK(dvp, 0, td); 1160 cnp->cn_flags |= PDIRUNLOCK; 1161 } 1162 } 1163 if (!error) { 1164 killit = 0; 1165 if (vpid == vp->v_id) { 1166 error = VOP_GETATTR(vp, &vattr, cnp->cn_cred, td); 1167 /* 1168 * If the file type on the server is inconsistent 1169 * with what it was when we created the vnode, 1170 * kill the bogus vnode now and fall through to 1171 * the code below to create a new one with the 1172 * right type. 1173 */ 1174 if (error == 0 && 1175 ((vp->v_type == VDIR && 1176 (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) == 0) || 1177 (vp->v_type == VREG && 1178 (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) != 0))) 1179 killit = 1; 1180 else if (error == 0 1181 /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { 1182 if (nameiop != LOOKUP && islastcn) 1183 cnp->cn_flags |= SAVENAME; 1184 SMBVDEBUG("use cached vnode\n"); 1185 return (0); 1186 } 1187 cache_purge(vp); 1188 } 1189 vput(vp); 1190 if (killit) 1191 vgone(vp); 1192 if (lockparent && dvp != vp && islastcn) 1193 VOP_UNLOCK(dvp, 0, td); 1194 } 1195 error = vn_lock(dvp, LK_EXCLUSIVE, td); 1196 *vpp = NULLVP; 1197 if (error) { 1198 cnp->cn_flags |= PDIRUNLOCK; 1199 return (error); 1200 } 1201 cnp->cn_flags &= ~PDIRUNLOCK; 1202 } 1203 /* 1204 * entry is not in the cache or has been expired 1205 */ 1206 error = 0; 1207 *vpp = NULLVP; 1208 smb_makescred(&scred, td, cnp->cn_cred); 1209 fap = &fattr; 1210 if (flags & ISDOTDOT) { 1211 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, 1212 &scred); 1213 SMBVDEBUG("result of dotdot lookup: %d\n", error); 1214 } else { 1215 fap = &fattr; 1216 error = smbfs_smb_lookup(dnp, name, nmlen, fap, &scred); 1217/* if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')*/ 1218 SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1219 } 1220 if (error && error != ENOENT) 1221 return error; 1222 if (error) { /* entry not found */ 1223 /* 1224 * Handle RENAME or CREATE case... 1225 */ 1226 if ((nameiop == CREATE || nameiop == RENAME) && wantparent && islastcn) { 1227 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1228 if (error) 1229 return error; 1230 cnp->cn_flags |= SAVENAME; 1231 if (!lockparent) { 1232 VOP_UNLOCK(dvp, 0, td); 1233 cnp->cn_flags |= PDIRUNLOCK; 1234 } 1235 return (EJUSTRETURN); 1236 } 1237 return ENOENT; 1238 }/* else { 1239 SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 1240 }*/ 1241 /* 1242 * handle DELETE case ... 1243 */ 1244 if (nameiop == DELETE && islastcn) { /* delete last component */ 1245 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1246 if (error) 1247 return error; 1248 if (isdot) { 1249 VREF(dvp); 1250 *vpp = dvp; 1251 return 0; 1252 } 1253 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1254 if (error) 1255 return error; 1256 *vpp = vp; 1257 cnp->cn_flags |= SAVENAME; 1258 if (!lockparent) { 1259 VOP_UNLOCK(dvp, 0, td); 1260 cnp->cn_flags |= PDIRUNLOCK; 1261 } 1262 return 0; 1263 } 1264 if (nameiop == RENAME && islastcn && wantparent) { 1265 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1266 if (error) 1267 return error; 1268 if (isdot) 1269 return EISDIR; 1270 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1271 if (error) 1272 return error; 1273 *vpp = vp; 1274 cnp->cn_flags |= SAVENAME; 1275 if (!lockparent) { 1276 VOP_UNLOCK(dvp, 0, td); 1277 cnp->cn_flags |= PDIRUNLOCK; 1278 } 1279 return 0; 1280 } 1281 if (flags & ISDOTDOT) { 1282 VOP_UNLOCK(dvp, 0, td); 1283 error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); 1284 if (error) { 1285 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 1286 return error; 1287 } 1288 if (lockparent && islastcn) { 1289 error = vn_lock(dvp, LK_EXCLUSIVE, td); 1290 if (error) { 1291 cnp->cn_flags |= PDIRUNLOCK; 1292 vput(vp); 1293 return error; 1294 } 1295 } 1296 *vpp = vp; 1297 } else if (isdot) { 1298 vref(dvp); 1299 *vpp = dvp; 1300 } else { 1301 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1302 if (error) 1303 return error; 1304 *vpp = vp; 1305 SMBVDEBUG("lookup: getnewvp!\n"); 1306 if (!lockparent || !islastcn) { 1307 VOP_UNLOCK(dvp, 0, td); 1308 cnp->cn_flags |= PDIRUNLOCK; 1309 } 1310 } 1311 if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 1312/* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ 1313 cache_enter(dvp, *vpp, cnp); 1314 } 1315 return 0; 1316}
| 119}; 120 121static int 122smbfs_access(ap) 123 struct vop_access_args /* { 124 struct vnode *a_vp; 125 int a_mode; 126 struct ucred *a_cred; 127 struct thread *a_td; 128 } */ *ap; 129{ 130 struct vnode *vp = ap->a_vp; 131 mode_t mode = ap->a_mode; 132 mode_t mpmode; 133 struct smbmount *smp = VTOSMBFS(vp); 134 135 SMBVDEBUG("\n"); 136 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 137 switch (vp->v_type) { 138 case VREG: case VDIR: case VLNK: 139 return EROFS; 140 default: 141 break; 142 } 143 } 144 mpmode = vp->v_type == VREG ? smp->sm_file_mode : smp->sm_dir_mode; 145 return (vaccess(vp->v_type, mpmode, smp->sm_uid, 146 smp->sm_gid, ap->a_mode, ap->a_cred, NULL)); 147} 148 149/* ARGSUSED */ 150static int 151smbfs_open(ap) 152 struct vop_open_args /* { 153 struct vnode *a_vp; 154 int a_mode; 155 struct ucred *a_cred; 156 struct thread *a_td; 157 } */ *ap; 158{ 159 struct vnode *vp = ap->a_vp; 160 struct smbnode *np = VTOSMB(vp); 161 struct smb_cred scred; 162 struct vattr vattr; 163 int mode = ap->a_mode; 164 int error, accmode; 165 166 SMBVDEBUG("%s,%d\n", np->n_name, (np->n_flag & NOPEN) != 0); 167 if (vp->v_type != VREG && vp->v_type != VDIR) { 168 SMBFSERR("open eacces vtype=%d\n", vp->v_type); 169 return EACCES; 170 } 171 if (vp->v_type == VDIR) { 172 np->n_flag |= NOPEN; 173 return 0; 174 } 175 if (np->n_flag & NMODIFIED) { 176 if ((error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1)) == EINTR) 177 return error; 178 smbfs_attr_cacheremove(vp); 179 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td); 180 if (error) 181 return error; 182 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 183 } else { 184 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td); 185 if (error) 186 return error; 187 if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) { 188 error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1); 189 if (error == EINTR) 190 return error; 191 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 192 } 193 } 194 if ((np->n_flag & NOPEN) != 0) 195 return 0; 196 /* 197 * Use DENYNONE to give unixy semantics of permitting 198 * everything not forbidden by permissions. Ie denial 199 * is up to server with clients/openers needing to use 200 * advisory locks for further control. 201 */ 202 accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 203 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 204 accmode = SMB_SM_DENYNONE|SMB_AM_OPENRW; 205 smb_makescred(&scred, ap->a_td, ap->a_cred); 206 error = smbfs_smb_open(np, accmode, &scred); 207 if (error) { 208 if (mode & FWRITE) 209 return EACCES; 210 else if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 211 accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 212 error = smbfs_smb_open(np, accmode, &scred); 213 } 214 } 215 if (error == 0) 216 np->n_flag |= NOPEN; 217 smbfs_attr_cacheremove(vp); 218 return error; 219} 220 221/* 222 * XXX: VOP_CLOSE() usually called without lock held which is suck. Here we 223 * do some heruistic to determine if vnode should be locked. 224 */ 225static int 226smbfs_close(ap) 227 struct vop_close_args /* { 228 struct vnodeop_desc *a_desc; 229 struct vnode *a_vp; 230 int a_fflag; 231 struct ucred *a_cred; 232 struct thread *a_td; 233 } */ *ap; 234{ 235 struct vnode *vp = ap->a_vp; 236 struct thread *td = ap->a_td; 237 struct smbnode *np = VTOSMB(vp); 238 struct smb_cred scred; 239 int dolock; 240 241 VI_LOCK(vp); 242 dolock = (vp->v_iflag & VI_XLOCK) == 0; 243 if (dolock) 244 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK, td); 245 else 246 VI_UNLOCK(vp); 247 if (vp->v_type == VDIR && (np->n_flag & NOPEN) != 0 && 248 np->n_dirseq != NULL) { 249 smb_makescred(&scred, td, ap->a_cred); 250 smbfs_findclose(np->n_dirseq, &scred); 251 np->n_dirseq = NULL; 252 } 253 if (dolock) 254 VOP_UNLOCK(vp, 0, td); 255 return 0; 256} 257 258/* 259 * smbfs_getattr call from vfs. 260 */ 261static int 262smbfs_getattr(ap) 263 struct vop_getattr_args /* { 264 struct vnode *a_vp; 265 struct vattr *a_vap; 266 struct ucred *a_cred; 267 struct thread *a_td; 268 } */ *ap; 269{ 270 struct vnode *vp = ap->a_vp; 271 struct smbnode *np = VTOSMB(vp); 272 struct vattr *va=ap->a_vap; 273 struct smbfattr fattr; 274 struct smb_cred scred; 275 u_quad_t oldsize; 276 int error; 277 278 SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_vflag & VV_ROOT) != 0); 279 error = smbfs_attr_cachelookup(vp, va); 280 if (!error) 281 return 0; 282 SMBVDEBUG("not in the cache\n"); 283 smb_makescred(&scred, ap->a_td, ap->a_cred); 284 oldsize = np->n_size; 285 error = smbfs_smb_lookup(np, NULL, 0, &fattr, &scred); 286 if (error) { 287 SMBVDEBUG("error %d\n", error); 288 return error; 289 } 290 smbfs_attr_cacheenter(vp, &fattr); 291 smbfs_attr_cachelookup(vp, va); 292 if (np->n_flag & NOPEN) 293 np->n_size = oldsize; 294 return 0; 295} 296 297static int 298smbfs_setattr(ap) 299 struct vop_setattr_args /* { 300 struct vnode *a_vp; 301 struct vattr *a_vap; 302 struct ucred *a_cred; 303 struct thread *a_td; 304 } */ *ap; 305{ 306 struct vnode *vp = ap->a_vp; 307 struct smbnode *np = VTOSMB(vp); 308 struct vattr *vap = ap->a_vap; 309 struct timespec *mtime, *atime; 310 struct smb_cred scred; 311 struct smb_share *ssp = np->n_mount->sm_share; 312 struct smb_vc *vcp = SSTOVC(ssp); 313 u_quad_t tsize = 0; 314 int isreadonly, doclose, error = 0; 315 316 SMBVDEBUG("\n"); 317 if (vap->va_flags != VNOVAL) 318 return EOPNOTSUPP; 319 isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 320 /* 321 * Disallow write attempts if the filesystem is mounted read-only. 322 */ 323 if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 324 vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 325 vap->va_mode != (mode_t)VNOVAL) && isreadonly) 326 return EROFS; 327 smb_makescred(&scred, ap->a_td, ap->a_cred); 328 if (vap->va_size != VNOVAL) { 329 switch (vp->v_type) { 330 case VDIR: 331 return EISDIR; 332 case VREG: 333 break; 334 default: 335 return EINVAL; 336 }; 337 if (isreadonly) 338 return EROFS; 339 doclose = 0; 340 vnode_pager_setsize(vp, (u_long)vap->va_size); 341 tsize = np->n_size; 342 np->n_size = vap->va_size; 343 if ((np->n_flag & NOPEN) == 0) { 344 error = smbfs_smb_open(np, 345 SMB_SM_DENYNONE|SMB_AM_OPENRW, 346 &scred); 347 if (error == 0) 348 doclose = 1; 349 } 350 if (error == 0) 351 error = smbfs_smb_setfsize(np, vap->va_size, &scred); 352 if (doclose) 353 smbfs_smb_close(ssp, np->n_fid, NULL, &scred); 354 if (error) { 355 np->n_size = tsize; 356 vnode_pager_setsize(vp, (u_long)tsize); 357 return error; 358 } 359 } 360 mtime = atime = NULL; 361 if (vap->va_mtime.tv_sec != VNOVAL) 362 mtime = &vap->va_mtime; 363 if (vap->va_atime.tv_sec != VNOVAL) 364 atime = &vap->va_atime; 365 if (mtime != atime) { 366 if (ap->a_cred->cr_uid != VTOSMBFS(vp)->sm_uid && 367 (error = suser_cred(ap->a_cred, SUSER_ALLOWJAIL)) && 368 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 369 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 370 return (error); 371#if 0 372 if (mtime == NULL) 373 mtime = &np->n_mtime; 374 if (atime == NULL) 375 atime = &np->n_atime; 376#endif 377 /* 378 * If file is opened, then we can use handle based calls. 379 * If not, use path based ones. 380 */ 381 if ((np->n_flag & NOPEN) == 0) { 382 if (vcp->vc_flags & SMBV_WIN95) { 383 error = VOP_OPEN(vp, FWRITE, ap->a_cred, ap->a_td, -1); 384 if (!error) { 385/* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 386 VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td);*/ 387 if (mtime) 388 np->n_mtime = *mtime; 389 VOP_CLOSE(vp, FWRITE, ap->a_cred, ap->a_td); 390 } 391 } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 392 error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 393/* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred);*/ 394 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 395 error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 396 } else { 397 error = smbfs_smb_setpattr(np, 0, mtime, &scred); 398 } 399 } else { 400 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 401 error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 402 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 403 error = smbfs_smb_setftime(np, mtime, atime, &scred); 404 } else { 405 /* 406 * I have no idea how to handle this for core 407 * level servers. The possible solution is to 408 * update mtime after file is closed. 409 */ 410 SMBERROR("can't update times on an opened file\n"); 411 } 412 } 413 } 414 /* 415 * Invalidate attribute cache in case if server doesn't set 416 * required attributes. 417 */ 418 smbfs_attr_cacheremove(vp); /* invalidate cache */ 419 VOP_GETATTR(vp, vap, ap->a_cred, ap->a_td); 420 np->n_mtime.tv_sec = vap->va_mtime.tv_sec; 421 return error; 422} 423/* 424 * smbfs_read call. 425 */ 426static int 427smbfs_read(ap) 428 struct vop_read_args /* { 429 struct vnode *a_vp; 430 struct uio *a_uio; 431 int a_ioflag; 432 struct ucred *a_cred; 433 } */ *ap; 434{ 435 struct vnode *vp = ap->a_vp; 436 struct uio *uio = ap->a_uio; 437 438 SMBVDEBUG("\n"); 439 if (vp->v_type != VREG && vp->v_type != VDIR) 440 return EPERM; 441 return smbfs_readvnode(vp, uio, ap->a_cred); 442} 443 444static int 445smbfs_write(ap) 446 struct vop_write_args /* { 447 struct vnode *a_vp; 448 struct uio *a_uio; 449 int a_ioflag; 450 struct ucred *a_cred; 451 } */ *ap; 452{ 453 struct vnode *vp = ap->a_vp; 454 struct uio *uio = ap->a_uio; 455 456 SMBVDEBUG("%d,ofs=%d,sz=%d\n",vp->v_type, (int)uio->uio_offset, uio->uio_resid); 457 if (vp->v_type != VREG) 458 return (EPERM); 459 return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); 460} 461/* 462 * smbfs_create call 463 * Create a regular file. On entry the directory to contain the file being 464 * created is locked. We must release before we return. We must also free 465 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or 466 * only if the SAVESTART bit in cn_flags is clear on success. 467 */ 468static int 469smbfs_create(ap) 470 struct vop_create_args /* { 471 struct vnode *a_dvp; 472 struct vnode **a_vpp; 473 struct componentname *a_cnp; 474 struct vattr *a_vap; 475 } */ *ap; 476{ 477 struct vnode *dvp = ap->a_dvp; 478 struct vattr *vap = ap->a_vap; 479 struct vnode **vpp=ap->a_vpp; 480 struct componentname *cnp = ap->a_cnp; 481 struct smbnode *dnp = VTOSMB(dvp); 482 struct vnode *vp; 483 struct vattr vattr; 484 struct smbfattr fattr; 485 struct smb_cred scred; 486 char *name = cnp->cn_nameptr; 487 int nmlen = cnp->cn_namelen; 488 int error; 489 490 491 SMBVDEBUG("\n"); 492 *vpp = NULL; 493 if (vap->va_type != VREG) 494 return EOPNOTSUPP; 495 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread))) 496 return error; 497 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 498 499 error = smbfs_smb_create(dnp, name, nmlen, &scred); 500 if (error) 501 return error; 502 error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred); 503 if (error) 504 return error; 505 error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); 506 if (error) 507 return error; 508 *vpp = vp; 509 if (cnp->cn_flags & MAKEENTRY) 510 cache_enter(dvp, vp, cnp); 511 return error; 512} 513 514static int 515smbfs_remove(ap) 516 struct vop_remove_args /* { 517 struct vnodeop_desc *a_desc; 518 struct vnode * a_dvp; 519 struct vnode * a_vp; 520 struct componentname * a_cnp; 521 } */ *ap; 522{ 523 struct vnode *vp = ap->a_vp; 524/* struct vnode *dvp = ap->a_dvp;*/ 525 struct componentname *cnp = ap->a_cnp; 526 struct smbnode *np = VTOSMB(vp); 527 struct smb_cred scred; 528 int error; 529 530 if (vp->v_type == VDIR || (np->n_flag & NOPEN) != 0 || vrefcnt(vp) != 1) 531 return EPERM; 532 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 533 error = smbfs_smb_delete(np, &scred); 534 if (error == 0) 535 np->n_flag |= NGONE; 536 cache_purge(vp); 537 return error; 538} 539 540/* 541 * smbfs_file rename call 542 */ 543static int 544smbfs_rename(ap) 545 struct vop_rename_args /* { 546 struct vnode *a_fdvp; 547 struct vnode *a_fvp; 548 struct componentname *a_fcnp; 549 struct vnode *a_tdvp; 550 struct vnode *a_tvp; 551 struct componentname *a_tcnp; 552 } */ *ap; 553{ 554 struct vnode *fvp = ap->a_fvp; 555 struct vnode *tvp = ap->a_tvp; 556 struct vnode *fdvp = ap->a_fdvp; 557 struct vnode *tdvp = ap->a_tdvp; 558 struct componentname *tcnp = ap->a_tcnp; 559/* struct componentname *fcnp = ap->a_fcnp;*/ 560 struct smb_cred scred; 561 u_int16_t flags = 6; 562 int error=0; 563 564 /* Check for cross-device rename */ 565 if ((fvp->v_mount != tdvp->v_mount) || 566 (tvp && (fvp->v_mount != tvp->v_mount))) { 567 error = EXDEV; 568 goto out; 569 } 570 571 if (tvp && vrefcnt(tvp) > 1) { 572 error = EBUSY; 573 goto out; 574 } 575 flags = 0x10; /* verify all writes */ 576 if (fvp->v_type == VDIR) { 577 flags |= 2; 578 } else if (fvp->v_type == VREG) { 579 flags |= 1; 580 } else { 581 error = EINVAL; 582 goto out; 583 } 584 smb_makescred(&scred, tcnp->cn_thread, tcnp->cn_cred); 585 /* 586 * It seems that Samba doesn't implement SMB_COM_MOVE call... 587 */ 588#ifdef notnow 589 if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { 590 error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), 591 tcnp->cn_nameptr, tcnp->cn_namelen, flags, &scred); 592 } else 593#endif 594 { 595 /* 596 * We have to do the work atomicaly 597 */ 598 if (tvp && tvp != fvp) { 599 error = smbfs_smb_delete(VTOSMB(tvp), &scred); 600 if (error) 601 goto out_cacherem; 602 VTOSMB(fvp)->n_flag |= NGONE; 603 } 604 error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), 605 tcnp->cn_nameptr, tcnp->cn_namelen, &scred); 606 } 607 608 if (fvp->v_type == VDIR) { 609 if (tvp != NULL && tvp->v_type == VDIR) 610 cache_purge(tdvp); 611 cache_purge(fdvp); 612 } 613 614out_cacherem: 615 smbfs_attr_cacheremove(fdvp); 616 smbfs_attr_cacheremove(tdvp); 617out: 618 if (tdvp == tvp) 619 vrele(tdvp); 620 else 621 vput(tdvp); 622 if (tvp) 623 vput(tvp); 624 vrele(fdvp); 625 vrele(fvp); 626#ifdef possible_mistake 627 vgone(fvp); 628 if (tvp) 629 vgone(tvp); 630#endif 631 return error; 632} 633 634/* 635 * somtime it will come true... 636 */ 637static int 638smbfs_link(ap) 639 struct vop_link_args /* { 640 struct vnode *a_tdvp; 641 struct vnode *a_vp; 642 struct componentname *a_cnp; 643 } */ *ap; 644{ 645 return EOPNOTSUPP; 646} 647 648/* 649 * smbfs_symlink link create call. 650 * Sometime it will be functional... 651 */ 652static int 653smbfs_symlink(ap) 654 struct vop_symlink_args /* { 655 struct vnode *a_dvp; 656 struct vnode **a_vpp; 657 struct componentname *a_cnp; 658 struct vattr *a_vap; 659 char *a_target; 660 } */ *ap; 661{ 662 return EOPNOTSUPP; 663} 664 665static int 666smbfs_mknod(ap) 667 struct vop_mknod_args /* { 668 } */ *ap; 669{ 670 return EOPNOTSUPP; 671} 672 673static int 674smbfs_mkdir(ap) 675 struct vop_mkdir_args /* { 676 struct vnode *a_dvp; 677 struct vnode **a_vpp; 678 struct componentname *a_cnp; 679 struct vattr *a_vap; 680 } */ *ap; 681{ 682 struct vnode *dvp = ap->a_dvp; 683/* struct vattr *vap = ap->a_vap;*/ 684 struct vnode *vp; 685 struct componentname *cnp = ap->a_cnp; 686 struct smbnode *dnp = VTOSMB(dvp); 687 struct vattr vattr; 688 struct smb_cred scred; 689 struct smbfattr fattr; 690 char *name = cnp->cn_nameptr; 691 int len = cnp->cn_namelen; 692 int error; 693 694 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread))) { 695 return error; 696 } 697 if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 698 return EEXIST; 699 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 700 error = smbfs_smb_mkdir(dnp, name, len, &scred); 701 if (error) 702 return error; 703 error = smbfs_smb_lookup(dnp, name, len, &fattr, &scred); 704 if (error) 705 return error; 706 error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); 707 if (error) 708 return error; 709 *ap->a_vpp = vp; 710 return 0; 711} 712 713/* 714 * smbfs_remove directory call 715 */ 716static int 717smbfs_rmdir(ap) 718 struct vop_rmdir_args /* { 719 struct vnode *a_dvp; 720 struct vnode *a_vp; 721 struct componentname *a_cnp; 722 } */ *ap; 723{ 724 struct vnode *vp = ap->a_vp; 725 struct vnode *dvp = ap->a_dvp; 726 struct componentname *cnp = ap->a_cnp; 727/* struct smbmount *smp = VTOSMBFS(vp);*/ 728 struct smbnode *dnp = VTOSMB(dvp); 729 struct smbnode *np = VTOSMB(vp); 730 struct smb_cred scred; 731 int error; 732 733 if (dvp == vp) 734 return EINVAL; 735 736 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 737 error = smbfs_smb_rmdir(np, &scred); 738 if (error == 0) 739 np->n_flag |= NGONE; 740 dnp->n_flag |= NMODIFIED; 741 smbfs_attr_cacheremove(dvp); 742/* cache_purge(dvp);*/ 743 cache_purge(vp); 744 return error; 745} 746 747/* 748 * smbfs_readdir call 749 */ 750static int 751smbfs_readdir(ap) 752 struct vop_readdir_args /* { 753 struct vnode *a_vp; 754 struct uio *a_uio; 755 struct ucred *a_cred; 756 int *a_eofflag; 757 u_long *a_cookies; 758 int a_ncookies; 759 } */ *ap; 760{ 761 struct vnode *vp = ap->a_vp; 762 struct uio *uio = ap->a_uio; 763 int error; 764 765 if (vp->v_type != VDIR) 766 return (EPERM); 767#ifdef notnow 768 if (ap->a_ncookies) { 769 printf("smbfs_readdir: no support for cookies now..."); 770 return (EOPNOTSUPP); 771 } 772#endif 773 error = smbfs_readvnode(vp, uio, ap->a_cred); 774 return error; 775} 776 777/* ARGSUSED */ 778static int 779smbfs_fsync(ap) 780 struct vop_fsync_args /* { 781 struct vnodeop_desc *a_desc; 782 struct vnode * a_vp; 783 struct ucred * a_cred; 784 int a_waitfor; 785 struct thread * a_td; 786 } */ *ap; 787{ 788/* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ 789 return (0); 790} 791 792static 793int smbfs_print (ap) 794 struct vop_print_args /* { 795 struct vnode *a_vp; 796 } */ *ap; 797{ 798 struct vnode *vp = ap->a_vp; 799 struct smbnode *np = VTOSMB(vp); 800 801 if (np == NULL) { 802 printf("no smbnode data\n"); 803 return (0); 804 } 805 printf("\tname = %s, parent = %p, open = %d\n", np->n_name, 806 np->n_parent ? np->n_parent : NULL, (np->n_flag & NOPEN) != 0); 807 return (0); 808} 809 810static int 811smbfs_pathconf (ap) 812 struct vop_pathconf_args /* { 813 struct vnode *vp; 814 int name; 815 register_t *retval; 816 } */ *ap; 817{ 818 struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 819 struct smb_vc *vcp = SSTOVC(smp->sm_share); 820 register_t *retval = ap->a_retval; 821 int error = 0; 822 823 switch (ap->a_name) { 824 case _PC_LINK_MAX: 825 *retval = 0; 826 break; 827 case _PC_NAME_MAX: 828 *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 829 break; 830 case _PC_PATH_MAX: 831 *retval = 800; /* XXX: a correct one ? */ 832 break; 833 default: 834 error = EINVAL; 835 } 836 return error; 837} 838 839static int 840smbfs_strategy (ap) 841 struct vop_strategy_args /* { 842 struct buf *a_bp 843 } */ *ap; 844{ 845 struct buf *bp=ap->a_bp; 846 struct ucred *cr; 847 struct thread *td; 848 int error = 0; 849 850 SMBVDEBUG("\n"); 851 if (bp->b_flags & B_ASYNC) 852 td = (struct thread *)0; 853 else 854 td = curthread; /* XXX */ 855 if (bp->b_iocmd == BIO_READ) 856 cr = bp->b_rcred; 857 else 858 cr = bp->b_wcred; 859 860 if ((bp->b_flags & B_ASYNC) == 0 ) 861 error = smbfs_doio(ap->a_vp, bp, cr, td); 862 return error; 863} 864 865int 866smbfs_ioctl(ap) 867 struct vop_ioctl_args /* { 868 struct vnode *a_vp; 869 u_long a_command; 870 caddr_t a_data; 871 int fflag; 872 struct ucred *cred; 873 struct thread *td; 874 } */ *ap; 875{ 876 return ENOTTY; 877} 878 879static char smbfs_atl[] = "rhsvda"; 880static int 881smbfs_getextattr(struct vop_getextattr_args *ap) 882/* { 883 IN struct vnode *a_vp; 884 IN char *a_name; 885 INOUT struct uio *a_uio; 886 IN struct ucred *a_cred; 887 IN struct thread *a_td; 888}; 889*/ 890{ 891 struct vnode *vp = ap->a_vp; 892 struct thread *td = ap->a_td; 893 struct ucred *cred = ap->a_cred; 894 struct uio *uio = ap->a_uio; 895 const char *name = ap->a_name; 896 struct smbnode *np = VTOSMB(vp); 897 struct vattr vattr; 898 char buf[10]; 899 int i, attr, error; 900 901 error = VOP_ACCESS(vp, VREAD, cred, td); 902 if (error) 903 return error; 904 error = VOP_GETATTR(vp, &vattr, cred, td); 905 if (error) 906 return error; 907 if (strcmp(name, "dosattr") == 0) { 908 attr = np->n_dosattr; 909 for (i = 0; i < 6; i++, attr >>= 1) 910 buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 911 buf[i] = 0; 912 error = uiomove(buf, i, uio); 913 914 } else 915 error = EINVAL; 916 return error; 917} 918 919/* 920 * Since we expected to support F_GETLK (and SMB protocol has no such function), 921 * it is necessary to use lf_advlock(). It would be nice if this function had 922 * a callback mechanism because it will help to improve a level of consistency. 923 */ 924int 925smbfs_advlock(ap) 926 struct vop_advlock_args /* { 927 struct vnode *a_vp; 928 caddr_t a_id; 929 int a_op; 930 struct flock *a_fl; 931 int a_flags; 932 } */ *ap; 933{ 934 struct vnode *vp = ap->a_vp; 935 struct smbnode *np = VTOSMB(vp); 936 struct flock *fl = ap->a_fl; 937 caddr_t id = (caddr_t)1 /* ap->a_id */; 938/* int flags = ap->a_flags;*/ 939 struct thread *td = curthread; 940 struct smb_cred scred; 941 u_quad_t size; 942 off_t start, end, oadd; 943 int error, lkop; 944 945 if (vp->v_type == VDIR) { 946 /* 947 * SMB protocol have no support for directory locking. 948 * Although locks can be processed on local machine, I don't 949 * think that this is a good idea, because some programs 950 * can work wrong assuming directory is locked. So, we just 951 * return 'operation not supported 952 */ 953 return EOPNOTSUPP; 954 } 955 size = np->n_size; 956 switch (fl->l_whence) { 957 958 case SEEK_SET: 959 case SEEK_CUR: 960 start = fl->l_start; 961 break; 962 963 case SEEK_END: 964 if (size > OFF_MAX || 965 (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 966 return EOVERFLOW; 967 start = size + fl->l_start; 968 break; 969 970 default: 971 return EINVAL; 972 } 973 if (start < 0) 974 return EINVAL; 975 if (fl->l_len < 0) { 976 if (start == 0) 977 return EINVAL; 978 end = start - 1; 979 start += fl->l_len; 980 if (start < 0) 981 return EINVAL; 982 } else if (fl->l_len == 0) 983 end = -1; 984 else { 985 oadd = fl->l_len - 1; 986 if (oadd > OFF_MAX - start) 987 return EOVERFLOW; 988 end = start + oadd; 989 } 990 smb_makescred(&scred, td, td->td_ucred); 991 switch (ap->a_op) { 992 case F_SETLK: 993 switch (fl->l_type) { 994 case F_WRLCK: 995 lkop = SMB_LOCK_EXCL; 996 break; 997 case F_RDLCK: 998 lkop = SMB_LOCK_SHARED; 999 break; 1000 case F_UNLCK: 1001 lkop = SMB_LOCK_RELEASE; 1002 break; 1003 default: 1004 return EINVAL; 1005 } 1006 error = lf_advlock(ap, &np->n_lockf, size); 1007 if (error) 1008 break; 1009 lkop = SMB_LOCK_EXCL; 1010 error = smbfs_smb_lock(np, lkop, id, start, end, &scred); 1011 if (error) { 1012 ap->a_op = F_UNLCK; 1013 lf_advlock(ap, &np->n_lockf, size); 1014 } 1015 break; 1016 case F_UNLCK: 1017 lf_advlock(ap, &np->n_lockf, size); 1018 error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, &scred); 1019 break; 1020 case F_GETLK: 1021 error = lf_advlock(ap, &np->n_lockf, size); 1022 break; 1023 default: 1024 return EINVAL; 1025 } 1026 return error; 1027} 1028 1029static int 1030smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) 1031{ 1032 static const char *badchars = "*/\\:<>;?"; 1033 static const char *badchars83 = " +|,[]="; 1034 const char *cp; 1035 int i, error; 1036 1037 if (nameiop == LOOKUP) 1038 return 0; 1039 error = ENOENT; 1040 if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { 1041 /* 1042 * Name should conform 8.3 format 1043 */ 1044 if (nmlen > 12) 1045 return ENAMETOOLONG; 1046 cp = index(name, '.'); 1047 if (cp == NULL) 1048 return error; 1049 if (cp == name || (cp - name) > 8) 1050 return error; 1051 cp = index(cp + 1, '.'); 1052 if (cp != NULL) 1053 return error; 1054 for (cp = name, i = 0; i < nmlen; i++, cp++) 1055 if (index(badchars83, *cp) != NULL) 1056 return error; 1057 } 1058 for (cp = name, i = 0; i < nmlen; i++, cp++) 1059 if (index(badchars, *cp) != NULL) 1060 return error; 1061 return 0; 1062} 1063 1064#ifndef PDIRUNLOCK 1065#define PDIRUNLOCK 0 1066#endif 1067 1068/* 1069 * Things go even weird without fixed inode numbers... 1070 */ 1071int 1072smbfs_lookup(ap) 1073 struct vop_lookup_args /* { 1074 struct vnodeop_desc *a_desc; 1075 struct vnode *a_dvp; 1076 struct vnode **a_vpp; 1077 struct componentname *a_cnp; 1078 } */ *ap; 1079{ 1080 struct componentname *cnp = ap->a_cnp; 1081 struct thread *td = cnp->cn_thread; 1082 struct vnode *dvp = ap->a_dvp; 1083 struct vnode **vpp = ap->a_vpp; 1084 struct vnode *vp; 1085 struct smbmount *smp; 1086 struct mount *mp = dvp->v_mount; 1087 struct smbnode *dnp; 1088 struct smbfattr fattr, *fap; 1089 struct smb_cred scred; 1090 char *name = cnp->cn_nameptr; 1091 int flags = cnp->cn_flags; 1092 int nameiop = cnp->cn_nameiop; 1093 int nmlen = cnp->cn_namelen; 1094 int lockparent, wantparent, error, islastcn, isdot; 1095 int killit; 1096 1097 SMBVDEBUG("\n"); 1098 cnp->cn_flags &= ~PDIRUNLOCK; 1099 if (dvp->v_type != VDIR) 1100 return ENOTDIR; 1101 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) { 1102 SMBFSERR("invalid '..'\n"); 1103 return EIO; 1104 } 1105#ifdef SMB_VNODE_DEBUG 1106 { 1107 char *cp, c; 1108 1109 cp = name + nmlen; 1110 c = *cp; 1111 *cp = 0; 1112 SMBVDEBUG("%d '%s' in '%s' id=d\n", nameiop, name, 1113 VTOSMB(dvp)->n_name); 1114 *cp = c; 1115 } 1116#endif 1117 islastcn = flags & ISLASTCN; 1118 if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) 1119 return EROFS; 1120 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) 1121 return error; 1122 lockparent = flags & LOCKPARENT; 1123 wantparent = flags & (LOCKPARENT|WANTPARENT); 1124 smp = VFSTOSMBFS(mp); 1125 dnp = VTOSMB(dvp); 1126 isdot = (nmlen == 1 && name[0] == '.'); 1127 1128 error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop); 1129 1130 if (error) 1131 return ENOENT; 1132 1133 error = cache_lookup(dvp, vpp, cnp); 1134 SMBVDEBUG("cache_lookup returned %d\n", error); 1135 if (error > 0) 1136 return error; 1137 if (error) { /* name was found */ 1138 struct vattr vattr; 1139 int vpid; 1140 1141 vp = *vpp; 1142 mp_fixme("Unlocked v_id access."); 1143 vpid = vp->v_id; 1144 if (dvp == vp) { /* lookup on current */ 1145 vref(vp); 1146 error = 0; 1147 SMBVDEBUG("cached '.'\n"); 1148 } else if (flags & ISDOTDOT) { 1149 VOP_UNLOCK(dvp, 0, td); /* unlock parent */ 1150 cnp->cn_flags |= PDIRUNLOCK; 1151 error = vget(vp, LK_EXCLUSIVE, td); 1152 if (!error && lockparent && islastcn) { 1153 error = vn_lock(dvp, LK_EXCLUSIVE, td); 1154 if (error == 0) 1155 cnp->cn_flags &= ~PDIRUNLOCK; 1156 } 1157 } else { 1158 error = vget(vp, LK_EXCLUSIVE, td); 1159 if (!lockparent || error || !islastcn) { 1160 VOP_UNLOCK(dvp, 0, td); 1161 cnp->cn_flags |= PDIRUNLOCK; 1162 } 1163 } 1164 if (!error) { 1165 killit = 0; 1166 if (vpid == vp->v_id) { 1167 error = VOP_GETATTR(vp, &vattr, cnp->cn_cred, td); 1168 /* 1169 * If the file type on the server is inconsistent 1170 * with what it was when we created the vnode, 1171 * kill the bogus vnode now and fall through to 1172 * the code below to create a new one with the 1173 * right type. 1174 */ 1175 if (error == 0 && 1176 ((vp->v_type == VDIR && 1177 (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) == 0) || 1178 (vp->v_type == VREG && 1179 (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) != 0))) 1180 killit = 1; 1181 else if (error == 0 1182 /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { 1183 if (nameiop != LOOKUP && islastcn) 1184 cnp->cn_flags |= SAVENAME; 1185 SMBVDEBUG("use cached vnode\n"); 1186 return (0); 1187 } 1188 cache_purge(vp); 1189 } 1190 vput(vp); 1191 if (killit) 1192 vgone(vp); 1193 if (lockparent && dvp != vp && islastcn) 1194 VOP_UNLOCK(dvp, 0, td); 1195 } 1196 error = vn_lock(dvp, LK_EXCLUSIVE, td); 1197 *vpp = NULLVP; 1198 if (error) { 1199 cnp->cn_flags |= PDIRUNLOCK; 1200 return (error); 1201 } 1202 cnp->cn_flags &= ~PDIRUNLOCK; 1203 } 1204 /* 1205 * entry is not in the cache or has been expired 1206 */ 1207 error = 0; 1208 *vpp = NULLVP; 1209 smb_makescred(&scred, td, cnp->cn_cred); 1210 fap = &fattr; 1211 if (flags & ISDOTDOT) { 1212 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, 1213 &scred); 1214 SMBVDEBUG("result of dotdot lookup: %d\n", error); 1215 } else { 1216 fap = &fattr; 1217 error = smbfs_smb_lookup(dnp, name, nmlen, fap, &scred); 1218/* if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')*/ 1219 SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1220 } 1221 if (error && error != ENOENT) 1222 return error; 1223 if (error) { /* entry not found */ 1224 /* 1225 * Handle RENAME or CREATE case... 1226 */ 1227 if ((nameiop == CREATE || nameiop == RENAME) && wantparent && islastcn) { 1228 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1229 if (error) 1230 return error; 1231 cnp->cn_flags |= SAVENAME; 1232 if (!lockparent) { 1233 VOP_UNLOCK(dvp, 0, td); 1234 cnp->cn_flags |= PDIRUNLOCK; 1235 } 1236 return (EJUSTRETURN); 1237 } 1238 return ENOENT; 1239 }/* else { 1240 SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 1241 }*/ 1242 /* 1243 * handle DELETE case ... 1244 */ 1245 if (nameiop == DELETE && islastcn) { /* delete last component */ 1246 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1247 if (error) 1248 return error; 1249 if (isdot) { 1250 VREF(dvp); 1251 *vpp = dvp; 1252 return 0; 1253 } 1254 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1255 if (error) 1256 return error; 1257 *vpp = vp; 1258 cnp->cn_flags |= SAVENAME; 1259 if (!lockparent) { 1260 VOP_UNLOCK(dvp, 0, td); 1261 cnp->cn_flags |= PDIRUNLOCK; 1262 } 1263 return 0; 1264 } 1265 if (nameiop == RENAME && islastcn && wantparent) { 1266 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1267 if (error) 1268 return error; 1269 if (isdot) 1270 return EISDIR; 1271 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1272 if (error) 1273 return error; 1274 *vpp = vp; 1275 cnp->cn_flags |= SAVENAME; 1276 if (!lockparent) { 1277 VOP_UNLOCK(dvp, 0, td); 1278 cnp->cn_flags |= PDIRUNLOCK; 1279 } 1280 return 0; 1281 } 1282 if (flags & ISDOTDOT) { 1283 VOP_UNLOCK(dvp, 0, td); 1284 error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); 1285 if (error) { 1286 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 1287 return error; 1288 } 1289 if (lockparent && islastcn) { 1290 error = vn_lock(dvp, LK_EXCLUSIVE, td); 1291 if (error) { 1292 cnp->cn_flags |= PDIRUNLOCK; 1293 vput(vp); 1294 return error; 1295 } 1296 } 1297 *vpp = vp; 1298 } else if (isdot) { 1299 vref(dvp); 1300 *vpp = dvp; 1301 } else { 1302 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1303 if (error) 1304 return error; 1305 *vpp = vp; 1306 SMBVDEBUG("lookup: getnewvp!\n"); 1307 if (!lockparent || !islastcn) { 1308 VOP_UNLOCK(dvp, 0, td); 1309 cnp->cn_flags |= PDIRUNLOCK; 1310 } 1311 } 1312 if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 1313/* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ 1314 cache_enter(dvp, *vpp, cnp); 1315 } 1316 return 0; 1317}
|