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