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