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