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