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