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