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