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