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