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 isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 309 /* 310 * Disallow write attempts if the filesystem is mounted read-only. 311 */ 312 if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 313 vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 314 vap->va_mode != (mode_t)VNOVAL || vap->va_flags != VNOVAL) && 315 isreadonly) 316 return EROFS; 317 318 /* 319 * We only support setting four flags. Don't allow setting others. 320 * 321 * We map UF_READONLY to SMB_FA_RDONLY, unlike the MacOS X version 322 * of this code, which maps both UF_IMMUTABLE AND SF_IMMUTABLE to 323 * SMB_FA_RDONLY. The immutable flags have different semantics 324 * than readonly, which is the reason for the difference. 325 */ 326 if (vap->va_flags != VNOVAL) { 327 if (vap->va_flags & ~(UF_HIDDEN|UF_SYSTEM|UF_ARCHIVE| 328 UF_READONLY)) 329 return EINVAL; 330 } 331 332 scred = smbfs_malloc_scred(); 333 smb_makescred(scred, td, ap->a_cred); 334 if (vap->va_size != VNOVAL) { 335 switch (vp->v_type) { 336 case VDIR: 337 error = EISDIR; 338 goto out; 339 case VREG: 340 break; 341 default: 342 error = EINVAL; 343 goto out; 344 }; 345 if (isreadonly) { 346 error = EROFS; 347 goto out; 348 } 349 doclose = 0; 350 vnode_pager_setsize(vp, (u_long)vap->va_size); 351 tsize = np->n_size; 352 np->n_size = vap->va_size; 353 if ((np->n_flag & NOPEN) == 0) { 354 error = smbfs_smb_open(np, 355 SMB_SM_DENYNONE|SMB_AM_OPENRW, 356 scred); 357 if (error == 0) 358 doclose = 1; 359 } 360 if (error == 0) 361 error = smbfs_smb_setfsize(np, 362 (int64_t)vap->va_size, scred); 363 if (doclose) 364 smbfs_smb_close(ssp, np->n_fid, NULL, scred); 365 if (error) { 366 np->n_size = tsize; 367 vnode_pager_setsize(vp, (u_long)tsize); 368 goto out; 369 } 370 } 371 if ((vap->va_flags != VNOVAL) || (vap->va_mode != (mode_t)VNOVAL)) { 372 old_n_dosattr = np->n_dosattr; 373 374 if (vap->va_mode != (mode_t)VNOVAL) { 375 if (vap->va_mode & S_IWUSR) 376 np->n_dosattr &= ~SMB_FA_RDONLY; 377 else 378 np->n_dosattr |= SMB_FA_RDONLY; 379 } 380 381 if (vap->va_flags != VNOVAL) { 382 if (vap->va_flags & UF_HIDDEN) 383 np->n_dosattr |= SMB_FA_HIDDEN; 384 else 385 np->n_dosattr &= ~SMB_FA_HIDDEN; 386 387 if (vap->va_flags & UF_SYSTEM) 388 np->n_dosattr |= SMB_FA_SYSTEM; 389 else 390 np->n_dosattr &= ~SMB_FA_SYSTEM; 391 392 if (vap->va_flags & UF_ARCHIVE) 393 np->n_dosattr |= SMB_FA_ARCHIVE; 394 else 395 np->n_dosattr &= ~SMB_FA_ARCHIVE; 396 397 /* 398 * We only support setting the immutable / readonly 399 * bit for regular files. According to comments in 400 * the MacOS X version of this code, supporting the 401 * readonly bit on directories doesn't do the same 402 * thing in Windows as in Unix. 403 */ 404 if (vp->v_type == VREG) { 405 if (vap->va_flags & UF_READONLY) 406 np->n_dosattr |= SMB_FA_RDONLY; 407 else 408 np->n_dosattr &= ~SMB_FA_RDONLY; 409 } 410 } 411 412 if (np->n_dosattr != old_n_dosattr) { 413 error = smbfs_smb_setpattr(np, np->n_dosattr, NULL, scred); 414 if (error) 415 goto out; 416 } 417 } 418 mtime = atime = NULL; 419 if (vap->va_mtime.tv_sec != VNOVAL) 420 mtime = &vap->va_mtime; 421 if (vap->va_atime.tv_sec != VNOVAL) 422 atime = &vap->va_atime; 423 if (mtime != atime) { 424 if (vap->va_vaflags & VA_UTIMES_NULL) { 425 error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); 426 if (error) 427 error = VOP_ACCESS(vp, VWRITE, ap->a_cred, td); 428 } else 429 error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); 430 #if 0 431 if (mtime == NULL) 432 mtime = &np->n_mtime; 433 if (atime == NULL) 434 atime = &np->n_atime; 435 #endif 436 /* 437 * If file is opened, then we can use handle based calls. 438 * If not, use path based ones. 439 */ 440 if ((np->n_flag & NOPEN) == 0) { 441 if (vcp->vc_flags & SMBV_WIN95) { 442 error = VOP_OPEN(vp, FWRITE, ap->a_cred, td, 443 NULL); 444 if (!error) { 445 /* error = smbfs_smb_setfattrNT(np, 0, 446 mtime, atime, scred); 447 VOP_GETATTR(vp, &vattr, ap->a_cred); */ 448 if (mtime) 449 np->n_mtime = *mtime; 450 VOP_CLOSE(vp, FWRITE, ap->a_cred, td); 451 } 452 } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 453 error = smbfs_smb_setptime2(np, mtime, atime, 0, scred); 454 /* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, scred);*/ 455 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 456 error = smbfs_smb_setptime2(np, mtime, atime, 0, scred); 457 } else { 458 error = smbfs_smb_setpattr(np, 0, mtime, scred); 459 } 460 } else { 461 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 462 error = smbfs_smb_setfattrNT(np, 0, mtime, atime, scred); 463 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 464 error = smbfs_smb_setftime(np, mtime, atime, scred); 465 } else { 466 /* 467 * I have no idea how to handle this for core 468 * level servers. The possible solution is to 469 * update mtime after file is closed. 470 */ 471 SMBERROR("can't update times on an opened file\n"); 472 } 473 } 474 } 475 /* 476 * Invalidate attribute cache in case if server doesn't set 477 * required attributes. 478 */ 479 smbfs_attr_cacheremove(vp); /* invalidate cache */ 480 VOP_GETATTR(vp, vap, ap->a_cred); 481 np->n_mtime.tv_sec = vap->va_mtime.tv_sec; 482 out: 483 smbfs_free_scred(scred); 484 return error; 485 } 486 /* 487 * smbfs_read call. 488 */ 489 static int 490 smbfs_read(ap) 491 struct vop_read_args /* { 492 struct vnode *a_vp; 493 struct uio *a_uio; 494 int a_ioflag; 495 struct ucred *a_cred; 496 } */ *ap; 497 { 498 struct vnode *vp = ap->a_vp; 499 struct uio *uio = ap->a_uio; 500 501 SMBVDEBUG("\n"); 502 if (vp->v_type != VREG && vp->v_type != VDIR) 503 return EPERM; 504 return smbfs_readvnode(vp, uio, ap->a_cred); 505 } 506 507 static int 508 smbfs_write(ap) 509 struct vop_write_args /* { 510 struct vnode *a_vp; 511 struct uio *a_uio; 512 int a_ioflag; 513 struct ucred *a_cred; 514 } */ *ap; 515 { 516 struct vnode *vp = ap->a_vp; 517 struct uio *uio = ap->a_uio; 518 519 SMBVDEBUG("%d,ofs=%jd,sz=%zd\n",vp->v_type, (intmax_t)uio->uio_offset, 520 uio->uio_resid); 521 if (vp->v_type != VREG) 522 return (EPERM); 523 return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); 524 } 525 /* 526 * smbfs_create call 527 * Create a regular file. On entry the directory to contain the file being 528 * created is locked. We must release before we return. We must also free 529 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or 530 * only if the SAVESTART bit in cn_flags is clear on success. 531 */ 532 static int 533 smbfs_create(ap) 534 struct vop_create_args /* { 535 struct vnode *a_dvp; 536 struct vnode **a_vpp; 537 struct componentname *a_cnp; 538 struct vattr *a_vap; 539 } */ *ap; 540 { 541 struct vnode *dvp = ap->a_dvp; 542 struct vattr *vap = ap->a_vap; 543 struct vnode **vpp=ap->a_vpp; 544 struct componentname *cnp = ap->a_cnp; 545 struct smbnode *dnp = VTOSMB(dvp); 546 struct vnode *vp; 547 struct vattr vattr; 548 struct smbfattr fattr; 549 struct smb_cred *scred; 550 char *name = cnp->cn_nameptr; 551 int nmlen = cnp->cn_namelen; 552 int error; 553 554 555 SMBVDEBUG("\n"); 556 *vpp = NULL; 557 if (vap->va_type != VREG) 558 return EOPNOTSUPP; 559 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 560 return error; 561 scred = smbfs_malloc_scred(); 562 smb_makescred(scred, cnp->cn_thread, cnp->cn_cred); 563 564 error = smbfs_smb_create(dnp, name, nmlen, scred); 565 if (error) 566 goto out; 567 error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, scred); 568 if (error) 569 goto out; 570 error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); 571 if (error) 572 goto out; 573 *vpp = vp; 574 if (cnp->cn_flags & MAKEENTRY) 575 cache_enter(dvp, vp, cnp); 576 out: 577 smbfs_free_scred(scred); 578 return error; 579 } 580 581 static int 582 smbfs_remove(ap) 583 struct vop_remove_args /* { 584 struct vnodeop_desc *a_desc; 585 struct vnode * a_dvp; 586 struct vnode * a_vp; 587 struct componentname * a_cnp; 588 } */ *ap; 589 { 590 struct vnode *vp = ap->a_vp; 591 /* struct vnode *dvp = ap->a_dvp;*/ 592 struct componentname *cnp = ap->a_cnp; 593 struct smbnode *np = VTOSMB(vp); 594 struct smb_cred *scred; 595 int error; 596 597 if (vp->v_type == VDIR || (np->n_flag & NOPEN) != 0 || vrefcnt(vp) != 1) 598 return EPERM; 599 scred = smbfs_malloc_scred(); 600 smb_makescred(scred, cnp->cn_thread, cnp->cn_cred); 601 error = smbfs_smb_delete(np, scred); 602 if (error == 0) 603 np->n_flag |= NGONE; 604 cache_purge(vp); 605 smbfs_free_scred(scred); 606 return error; 607 } 608 609 /* 610 * smbfs_file rename call 611 */ 612 static int 613 smbfs_rename(ap) 614 struct vop_rename_args /* { 615 struct vnode *a_fdvp; 616 struct vnode *a_fvp; 617 struct componentname *a_fcnp; 618 struct vnode *a_tdvp; 619 struct vnode *a_tvp; 620 struct componentname *a_tcnp; 621 } */ *ap; 622 { 623 struct vnode *fvp = ap->a_fvp; 624 struct vnode *tvp = ap->a_tvp; 625 struct vnode *fdvp = ap->a_fdvp; 626 struct vnode *tdvp = ap->a_tdvp; 627 struct componentname *tcnp = ap->a_tcnp; 628 /* struct componentname *fcnp = ap->a_fcnp;*/ 629 struct smb_cred *scred; 630 u_int16_t flags = 6; 631 int error=0; 632 633 scred = NULL; 634 /* Check for cross-device rename */ 635 if ((fvp->v_mount != tdvp->v_mount) || 636 (tvp && (fvp->v_mount != tvp->v_mount))) { 637 error = EXDEV; 638 goto out; 639 } 640 641 if (tvp && vrefcnt(tvp) > 1) { 642 error = EBUSY; 643 goto out; 644 } 645 flags = 0x10; /* verify all writes */ 646 if (fvp->v_type == VDIR) { 647 flags |= 2; 648 } else if (fvp->v_type == VREG) { 649 flags |= 1; 650 } else { 651 return EINVAL; 652 } 653 scred = smbfs_malloc_scred(); 654 smb_makescred(scred, tcnp->cn_thread, tcnp->cn_cred); 655 /* 656 * It seems that Samba doesn't implement SMB_COM_MOVE call... 657 */ 658 #ifdef notnow 659 if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { 660 error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), 661 tcnp->cn_nameptr, tcnp->cn_namelen, flags, scred); 662 } else 663 #endif 664 { 665 /* 666 * We have to do the work atomicaly 667 */ 668 if (tvp && tvp != fvp) { 669 error = smbfs_smb_delete(VTOSMB(tvp), scred); 670 if (error) 671 goto out_cacherem; 672 VTOSMB(fvp)->n_flag |= NGONE; 673 } 674 error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), 675 tcnp->cn_nameptr, tcnp->cn_namelen, scred); 676 } 677 678 if (fvp->v_type == VDIR) { 679 if (tvp != NULL && tvp->v_type == VDIR) 680 cache_purge(tdvp); 681 cache_purge(fdvp); 682 } 683 684 out_cacherem: 685 smbfs_attr_cacheremove(fdvp); 686 smbfs_attr_cacheremove(tdvp); 687 out: 688 smbfs_free_scred(scred); 689 if (tdvp == tvp) 690 vrele(tdvp); 691 else 692 vput(tdvp); 693 if (tvp) 694 vput(tvp); 695 vrele(fdvp); 696 vrele(fvp); 697 #ifdef possible_mistake 698 vgone(fvp); 699 if (tvp) 700 vgone(tvp); 701 #endif 702 return error; 703 } 704 705 /* 706 * somtime it will come true... 707 */ 708 static int 709 smbfs_link(ap) 710 struct vop_link_args /* { 711 struct vnode *a_tdvp; 712 struct vnode *a_vp; 713 struct componentname *a_cnp; 714 } */ *ap; 715 { 716 return EOPNOTSUPP; 717 } 718 719 /* 720 * smbfs_symlink link create call. 721 * Sometime it will be functional... 722 */ 723 static int 724 smbfs_symlink(ap) 725 struct vop_symlink_args /* { 726 struct vnode *a_dvp; 727 struct vnode **a_vpp; 728 struct componentname *a_cnp; 729 struct vattr *a_vap; 730 char *a_target; 731 } */ *ap; 732 { 733 return EOPNOTSUPP; 734 } 735 736 static int 737 smbfs_mknod(ap) 738 struct vop_mknod_args /* { 739 } */ *ap; 740 { 741 return EOPNOTSUPP; 742 } 743 744 static int 745 smbfs_mkdir(ap) 746 struct vop_mkdir_args /* { 747 struct vnode *a_dvp; 748 struct vnode **a_vpp; 749 struct componentname *a_cnp; 750 struct vattr *a_vap; 751 } */ *ap; 752 { 753 struct vnode *dvp = ap->a_dvp; 754 /* struct vattr *vap = ap->a_vap;*/ 755 struct vnode *vp; 756 struct componentname *cnp = ap->a_cnp; 757 struct smbnode *dnp = VTOSMB(dvp); 758 struct vattr vattr; 759 struct smb_cred *scred; 760 struct smbfattr fattr; 761 char *name = cnp->cn_nameptr; 762 int len = cnp->cn_namelen; 763 int error; 764 765 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) { 766 return error; 767 } 768 if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 769 return EEXIST; 770 scred = smbfs_malloc_scred(); 771 smb_makescred(scred, cnp->cn_thread, cnp->cn_cred); 772 error = smbfs_smb_mkdir(dnp, name, len, scred); 773 if (error) 774 goto out; 775 error = smbfs_smb_lookup(dnp, name, len, &fattr, scred); 776 if (error) 777 goto out; 778 error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); 779 if (error) 780 goto out; 781 *ap->a_vpp = vp; 782 out: 783 smbfs_free_scred(scred); 784 return error; 785 } 786 787 /* 788 * smbfs_remove directory call 789 */ 790 static int 791 smbfs_rmdir(ap) 792 struct vop_rmdir_args /* { 793 struct vnode *a_dvp; 794 struct vnode *a_vp; 795 struct componentname *a_cnp; 796 } */ *ap; 797 { 798 struct vnode *vp = ap->a_vp; 799 struct vnode *dvp = ap->a_dvp; 800 struct componentname *cnp = ap->a_cnp; 801 /* struct smbmount *smp = VTOSMBFS(vp);*/ 802 struct smbnode *dnp = VTOSMB(dvp); 803 struct smbnode *np = VTOSMB(vp); 804 struct smb_cred *scred; 805 int error; 806 807 if (dvp == vp) 808 return EINVAL; 809 810 scred = smbfs_malloc_scred(); 811 smb_makescred(scred, cnp->cn_thread, cnp->cn_cred); 812 error = smbfs_smb_rmdir(np, scred); 813 if (error == 0) 814 np->n_flag |= NGONE; 815 dnp->n_flag |= NMODIFIED; 816 smbfs_attr_cacheremove(dvp); 817 /* cache_purge(dvp);*/ 818 cache_purge(vp); 819 smbfs_free_scred(scred); 820 return error; 821 } 822 823 /* 824 * smbfs_readdir call 825 */ 826 static int 827 smbfs_readdir(ap) 828 struct vop_readdir_args /* { 829 struct vnode *a_vp; 830 struct uio *a_uio; 831 struct ucred *a_cred; 832 int *a_eofflag; 833 u_long *a_cookies; 834 int a_ncookies; 835 } */ *ap; 836 { 837 struct vnode *vp = ap->a_vp; 838 struct uio *uio = ap->a_uio; 839 int error; 840 841 if (vp->v_type != VDIR) 842 return (EPERM); 843 #ifdef notnow 844 if (ap->a_ncookies) { 845 printf("smbfs_readdir: no support for cookies now..."); 846 return (EOPNOTSUPP); 847 } 848 #endif 849 error = smbfs_readvnode(vp, uio, ap->a_cred); 850 return error; 851 } 852 853 /* ARGSUSED */ 854 static int 855 smbfs_fsync(ap) 856 struct vop_fsync_args /* { 857 struct vnodeop_desc *a_desc; 858 struct vnode * a_vp; 859 struct ucred * a_cred; 860 int a_waitfor; 861 struct thread * a_td; 862 } */ *ap; 863 { 864 /* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ 865 return (0); 866 } 867 868 static 869 int smbfs_print (ap) 870 struct vop_print_args /* { 871 struct vnode *a_vp; 872 } */ *ap; 873 { 874 struct vnode *vp = ap->a_vp; 875 struct smbnode *np = VTOSMB(vp); 876 877 if (np == NULL) { 878 printf("no smbnode data\n"); 879 return (0); 880 } 881 printf("\tname = %s, parent = %p, open = %d\n", np->n_name, 882 np->n_parent ? np->n_parent : NULL, (np->n_flag & NOPEN) != 0); 883 return (0); 884 } 885 886 static int 887 smbfs_pathconf (ap) 888 struct vop_pathconf_args /* { 889 struct vnode *vp; 890 int name; 891 register_t *retval; 892 } */ *ap; 893 { 894 struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 895 struct smb_vc *vcp = SSTOVC(smp->sm_share); 896 register_t *retval = ap->a_retval; 897 int error = 0; 898 899 switch (ap->a_name) { 900 case _PC_LINK_MAX: 901 *retval = 0; 902 break; 903 case _PC_NAME_MAX: 904 *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 905 break; 906 case _PC_PATH_MAX: 907 *retval = 800; /* XXX: a correct one ? */ 908 break; 909 default: 910 error = EINVAL; 911 } 912 return error; 913 } 914 915 static int 916 smbfs_strategy (ap) 917 struct vop_strategy_args /* { 918 struct buf *a_bp 919 } */ *ap; 920 { 921 struct buf *bp=ap->a_bp; 922 struct ucred *cr; 923 struct thread *td; 924 925 SMBVDEBUG("\n"); 926 if (bp->b_flags & B_ASYNC) 927 td = (struct thread *)0; 928 else 929 td = curthread; /* XXX */ 930 if (bp->b_iocmd == BIO_READ) 931 cr = bp->b_rcred; 932 else 933 cr = bp->b_wcred; 934 935 if ((bp->b_flags & B_ASYNC) == 0 ) 936 (void)smbfs_doio(ap->a_vp, bp, cr, td); 937 return (0); 938 } 939 940 int 941 smbfs_ioctl(ap) 942 struct vop_ioctl_args /* { 943 struct vnode *a_vp; 944 u_long a_command; 945 caddr_t a_data; 946 int fflag; 947 struct ucred *cred; 948 struct thread *td; 949 } */ *ap; 950 { 951 return ENOTTY; 952 } 953 954 static char smbfs_atl[] = "rhsvda"; 955 static int 956 smbfs_getextattr(struct vop_getextattr_args *ap) 957 /* { 958 IN struct vnode *a_vp; 959 IN char *a_name; 960 INOUT struct uio *a_uio; 961 IN struct ucred *a_cred; 962 IN struct thread *a_td; 963 }; 964 */ 965 { 966 struct vnode *vp = ap->a_vp; 967 struct thread *td = ap->a_td; 968 struct ucred *cred = ap->a_cred; 969 struct uio *uio = ap->a_uio; 970 const char *name = ap->a_name; 971 struct smbnode *np = VTOSMB(vp); 972 struct vattr vattr; 973 char buf[10]; 974 int i, attr, error; 975 976 error = VOP_ACCESS(vp, VREAD, cred, td); 977 if (error) 978 return error; 979 error = VOP_GETATTR(vp, &vattr, cred); 980 if (error) 981 return error; 982 if (strcmp(name, "dosattr") == 0) { 983 attr = np->n_dosattr; 984 for (i = 0; i < 6; i++, attr >>= 1) 985 buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 986 buf[i] = 0; 987 error = uiomove(buf, i, uio); 988 989 } else 990 error = EINVAL; 991 return error; 992 } 993 994 /* 995 * Since we expected to support F_GETLK (and SMB protocol has no such function), 996 * it is necessary to use lf_advlock(). It would be nice if this function had 997 * a callback mechanism because it will help to improve a level of consistency. 998 */ 999 int 1000 smbfs_advlock(ap) 1001 struct vop_advlock_args /* { 1002 struct vnode *a_vp; 1003 caddr_t a_id; 1004 int a_op; 1005 struct flock *a_fl; 1006 int a_flags; 1007 } */ *ap; 1008 { 1009 struct vnode *vp = ap->a_vp; 1010 struct smbnode *np = VTOSMB(vp); 1011 struct flock *fl = ap->a_fl; 1012 caddr_t id = (caddr_t)1 /* ap->a_id */; 1013 /* int flags = ap->a_flags;*/ 1014 struct thread *td = curthread; 1015 struct smb_cred *scred; 1016 u_quad_t size; 1017 off_t start, end, oadd; 1018 int error, lkop; 1019 1020 if (vp->v_type == VDIR) { 1021 /* 1022 * SMB protocol have no support for directory locking. 1023 * Although locks can be processed on local machine, I don't 1024 * think that this is a good idea, because some programs 1025 * can work wrong assuming directory is locked. So, we just 1026 * return 'operation not supported 1027 */ 1028 return EOPNOTSUPP; 1029 } 1030 size = np->n_size; 1031 switch (fl->l_whence) { 1032 1033 case SEEK_SET: 1034 case SEEK_CUR: 1035 start = fl->l_start; 1036 break; 1037 1038 case SEEK_END: 1039 if (size > OFF_MAX || 1040 (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 1041 return EOVERFLOW; 1042 start = size + fl->l_start; 1043 break; 1044 1045 default: 1046 return EINVAL; 1047 } 1048 if (start < 0) 1049 return EINVAL; 1050 if (fl->l_len < 0) { 1051 if (start == 0) 1052 return EINVAL; 1053 end = start - 1; 1054 start += fl->l_len; 1055 if (start < 0) 1056 return EINVAL; 1057 } else if (fl->l_len == 0) 1058 end = -1; 1059 else { 1060 oadd = fl->l_len - 1; 1061 if (oadd > OFF_MAX - start) 1062 return EOVERFLOW; 1063 end = start + oadd; 1064 } 1065 scred = smbfs_malloc_scred(); 1066 smb_makescred(scred, td, td->td_ucred); 1067 switch (ap->a_op) { 1068 case F_SETLK: 1069 switch (fl->l_type) { 1070 case F_WRLCK: 1071 lkop = SMB_LOCK_EXCL; 1072 break; 1073 case F_RDLCK: 1074 lkop = SMB_LOCK_SHARED; 1075 break; 1076 case F_UNLCK: 1077 lkop = SMB_LOCK_RELEASE; 1078 break; 1079 default: 1080 smbfs_free_scred(scred); 1081 return EINVAL; 1082 } 1083 error = lf_advlock(ap, &vp->v_lockf, size); 1084 if (error) 1085 break; 1086 lkop = SMB_LOCK_EXCL; 1087 error = smbfs_smb_lock(np, lkop, id, start, end, scred); 1088 if (error) { 1089 int oldtype = fl->l_type; 1090 fl->l_type = F_UNLCK; 1091 ap->a_op = F_UNLCK; 1092 lf_advlock(ap, &vp->v_lockf, size); 1093 fl->l_type = oldtype; 1094 } 1095 break; 1096 case F_UNLCK: 1097 lf_advlock(ap, &vp->v_lockf, size); 1098 error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, scred); 1099 break; 1100 case F_GETLK: 1101 error = lf_advlock(ap, &vp->v_lockf, size); 1102 break; 1103 default: 1104 smbfs_free_scred(scred); 1105 return EINVAL; 1106 } 1107 smbfs_free_scred(scred); 1108 return error; 1109 } 1110 1111 static int 1112 smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) 1113 { 1114 static const char *badchars = "*/:<>;?"; 1115 static const char *badchars83 = " +|,[]="; 1116 const char *cp; 1117 int i, error; 1118 1119 /* 1120 * Backslash characters, being a path delimiter, are prohibited 1121 * within a path component even for LOOKUP operations. 1122 */ 1123 if (strchr(name, '\\') != NULL) 1124 return ENOENT; 1125 1126 if (nameiop == LOOKUP) 1127 return 0; 1128 error = ENOENT; 1129 if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { 1130 /* 1131 * Name should conform 8.3 format 1132 */ 1133 if (nmlen > 12) 1134 return ENAMETOOLONG; 1135 cp = strchr(name, '.'); 1136 if (cp == NULL) 1137 return error; 1138 if (cp == name || (cp - name) > 8) 1139 return error; 1140 cp = strchr(cp + 1, '.'); 1141 if (cp != NULL) 1142 return error; 1143 for (cp = name, i = 0; i < nmlen; i++, cp++) 1144 if (strchr(badchars83, *cp) != NULL) 1145 return error; 1146 } 1147 for (cp = name, i = 0; i < nmlen; i++, cp++) 1148 if (strchr(badchars, *cp) != NULL) 1149 return error; 1150 return 0; 1151 } 1152 1153 /* 1154 * Things go even weird without fixed inode numbers... 1155 */ 1156 int 1157 smbfs_lookup(ap) 1158 struct vop_lookup_args /* { 1159 struct vnodeop_desc *a_desc; 1160 struct vnode *a_dvp; 1161 struct vnode **a_vpp; 1162 struct componentname *a_cnp; 1163 } */ *ap; 1164 { 1165 struct componentname *cnp = ap->a_cnp; 1166 struct thread *td = cnp->cn_thread; 1167 struct vnode *dvp = ap->a_dvp; 1168 struct vnode **vpp = ap->a_vpp; 1169 struct vnode *vp; 1170 struct smbmount *smp; 1171 struct mount *mp = dvp->v_mount; 1172 struct smbnode *dnp; 1173 struct smbfattr fattr, *fap; 1174 struct smb_cred *scred; 1175 char *name = cnp->cn_nameptr; 1176 int flags = cnp->cn_flags; 1177 int nameiop = cnp->cn_nameiop; 1178 int nmlen = cnp->cn_namelen; 1179 int error, islastcn, isdot; 1180 int killit; 1181 1182 SMBVDEBUG("\n"); 1183 if (dvp->v_type != VDIR) 1184 return ENOTDIR; 1185 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) { 1186 SMBFSERR("invalid '..'\n"); 1187 return EIO; 1188 } 1189 islastcn = flags & ISLASTCN; 1190 if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) 1191 return EROFS; 1192 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) 1193 return error; 1194 smp = VFSTOSMBFS(mp); 1195 dnp = VTOSMB(dvp); 1196 isdot = (nmlen == 1 && name[0] == '.'); 1197 1198 error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop); 1199 1200 if (error) 1201 return ENOENT; 1202 1203 error = cache_lookup(dvp, vpp, cnp, NULL, NULL); 1204 SMBVDEBUG("cache_lookup returned %d\n", error); 1205 if (error > 0) 1206 return error; 1207 if (error) { /* name was found */ 1208 struct vattr vattr; 1209 1210 killit = 0; 1211 vp = *vpp; 1212 error = VOP_GETATTR(vp, &vattr, cnp->cn_cred); 1213 /* 1214 * If the file type on the server is inconsistent 1215 * with what it was when we created the vnode, 1216 * kill the bogus vnode now and fall through to 1217 * the code below to create a new one with the 1218 * right type. 1219 */ 1220 if (error == 0 && 1221 ((vp->v_type == VDIR && 1222 (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) == 0) || 1223 (vp->v_type == VREG && 1224 (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) != 0))) 1225 killit = 1; 1226 else if (error == 0 1227 /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { 1228 if (nameiop != LOOKUP && islastcn) 1229 cnp->cn_flags |= SAVENAME; 1230 SMBVDEBUG("use cached vnode\n"); 1231 return (0); 1232 } 1233 cache_purge(vp); 1234 /* 1235 * XXX This is not quite right, if '.' is 1236 * inconsistent, we really need to start the lookup 1237 * all over again. Hopefully there is some other 1238 * guarantee that prevents this case from happening. 1239 */ 1240 if (killit && vp != dvp) 1241 vgone(vp); 1242 if (vp != dvp) 1243 vput(vp); 1244 else 1245 vrele(vp); 1246 *vpp = NULLVP; 1247 } 1248 /* 1249 * entry is not in the cache or has been expired 1250 */ 1251 error = 0; 1252 *vpp = NULLVP; 1253 scred = smbfs_malloc_scred(); 1254 smb_makescred(scred, td, cnp->cn_cred); 1255 fap = &fattr; 1256 if (flags & ISDOTDOT) { 1257 /* 1258 * In the DOTDOT case, don't go over-the-wire 1259 * in order to request attributes. We already 1260 * know it's a directory and subsequent call to 1261 * smbfs_getattr() will restore consistency. 1262 * 1263 */ 1264 SMBVDEBUG("smbfs_smb_lookup: dotdot\n"); 1265 } else if (isdot) { 1266 error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 1267 SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1268 } 1269 else { 1270 error = smbfs_smb_lookup(dnp, name, nmlen, fap, scred); 1271 SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1272 } 1273 if (error && error != ENOENT) 1274 goto out; 1275 if (error) { /* entry not found */ 1276 /* 1277 * Handle RENAME or CREATE case... 1278 */ 1279 if ((nameiop == CREATE || nameiop == RENAME) && islastcn) { 1280 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1281 if (error) 1282 goto out; 1283 cnp->cn_flags |= SAVENAME; 1284 error = EJUSTRETURN; 1285 goto out; 1286 } 1287 error = ENOENT; 1288 goto out; 1289 }/* else { 1290 SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 1291 }*/ 1292 /* 1293 * handle DELETE case ... 1294 */ 1295 if (nameiop == DELETE && islastcn) { /* delete last component */ 1296 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1297 if (error) 1298 goto out; 1299 if (isdot) { 1300 VREF(dvp); 1301 *vpp = dvp; 1302 goto out; 1303 } 1304 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1305 if (error) 1306 goto out; 1307 *vpp = vp; 1308 cnp->cn_flags |= SAVENAME; 1309 goto out; 1310 } 1311 if (nameiop == RENAME && islastcn) { 1312 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1313 if (error) 1314 goto out; 1315 if (isdot) { 1316 error = EISDIR; 1317 goto out; 1318 } 1319 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1320 if (error) 1321 goto out; 1322 *vpp = vp; 1323 cnp->cn_flags |= SAVENAME; 1324 goto out; 1325 } 1326 if (flags & ISDOTDOT) { 1327 mp = dvp->v_mount; 1328 error = vfs_busy(mp, MBF_NOWAIT); 1329 if (error != 0) { 1330 vfs_ref(mp); 1331 VOP_UNLOCK(dvp, 0); 1332 error = vfs_busy(mp, 0); 1333 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 1334 vfs_rel(mp); 1335 if (error) { 1336 error = ENOENT; 1337 goto out; 1338 } 1339 if ((dvp->v_iflag & VI_DOOMED) != 0) { 1340 vfs_unbusy(mp); 1341 error = ENOENT; 1342 goto out; 1343 } 1344 } 1345 VOP_UNLOCK(dvp, 0); 1346 error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); 1347 vfs_unbusy(mp); 1348 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 1349 if ((dvp->v_iflag & VI_DOOMED) != 0) { 1350 if (error == 0) 1351 vput(vp); 1352 error = ENOENT; 1353 } 1354 if (error) 1355 goto out; 1356 *vpp = vp; 1357 } else if (isdot) { 1358 vref(dvp); 1359 *vpp = dvp; 1360 } else { 1361 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1362 if (error) 1363 goto out; 1364 *vpp = vp; 1365 SMBVDEBUG("lookup: getnewvp!\n"); 1366 } 1367 if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 1368 /* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ 1369 cache_enter(dvp, *vpp, cnp); 1370 } 1371 out: 1372 smbfs_free_scred(scred); 1373 return (error); 1374 } 1375