1 /* 2 * Copyright (c) 2000-2001 Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD$ 33 */ 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/namei.h> 37 #include <sys/kernel.h> 38 #include <sys/proc.h> 39 #include <sys/bio.h> 40 #include <sys/buf.h> 41 #include <sys/fcntl.h> 42 #include <sys/mount.h> 43 #include <sys/unistd.h> 44 #include <sys/vnode.h> 45 #include <sys/limits.h> 46 #include <sys/lockf.h> 47 48 #include <vm/vm.h> 49 #include <vm/vm_extern.h> 50 51 52 #include <netsmb/smb.h> 53 #include <netsmb/smb_conn.h> 54 #include <netsmb/smb_subr.h> 55 56 #include <fs/smbfs/smbfs.h> 57 #include <fs/smbfs/smbfs_node.h> 58 #include <fs/smbfs/smbfs_subr.h> 59 60 /* 61 * Prototypes for SMBFS vnode operations 62 */ 63 static int smbfs_create(struct vop_create_args *); 64 static int smbfs_mknod(struct vop_mknod_args *); 65 static int smbfs_open(struct vop_open_args *); 66 static int smbfs_close(struct vop_close_args *); 67 static int smbfs_access(struct vop_access_args *); 68 static int smbfs_getattr(struct vop_getattr_args *); 69 static int smbfs_setattr(struct vop_setattr_args *); 70 static int smbfs_read(struct vop_read_args *); 71 static int smbfs_write(struct vop_write_args *); 72 static int smbfs_fsync(struct vop_fsync_args *); 73 static int smbfs_remove(struct vop_remove_args *); 74 static int smbfs_link(struct vop_link_args *); 75 static int smbfs_lookup(struct vop_lookup_args *); 76 static int smbfs_rename(struct vop_rename_args *); 77 static int smbfs_mkdir(struct vop_mkdir_args *); 78 static int smbfs_rmdir(struct vop_rmdir_args *); 79 static int smbfs_symlink(struct vop_symlink_args *); 80 static int smbfs_readdir(struct vop_readdir_args *); 81 static int smbfs_strategy(struct vop_strategy_args *); 82 static int smbfs_print(struct vop_print_args *); 83 static int smbfs_pathconf(struct vop_pathconf_args *ap); 84 static int smbfs_advlock(struct vop_advlock_args *); 85 static int smbfs_getextattr(struct vop_getextattr_args *ap); 86 87 vop_t **smbfs_vnodeop_p; 88 static struct vnodeopv_entry_desc smbfs_vnodeop_entries[] = { 89 { &vop_default_desc, (vop_t *) vop_defaultop }, 90 { &vop_access_desc, (vop_t *) smbfs_access }, 91 { &vop_advlock_desc, (vop_t *) smbfs_advlock }, 92 { &vop_close_desc, (vop_t *) smbfs_close }, 93 { &vop_create_desc, (vop_t *) smbfs_create }, 94 { &vop_fsync_desc, (vop_t *) smbfs_fsync }, 95 { &vop_getattr_desc, (vop_t *) smbfs_getattr }, 96 { &vop_getpages_desc, (vop_t *) smbfs_getpages }, 97 { &vop_inactive_desc, (vop_t *) smbfs_inactive }, 98 { &vop_ioctl_desc, (vop_t *) smbfs_ioctl }, 99 { &vop_link_desc, (vop_t *) smbfs_link }, 100 { &vop_lookup_desc, (vop_t *) smbfs_lookup }, 101 { &vop_mkdir_desc, (vop_t *) smbfs_mkdir }, 102 { &vop_mknod_desc, (vop_t *) smbfs_mknod }, 103 { &vop_open_desc, (vop_t *) smbfs_open }, 104 { &vop_pathconf_desc, (vop_t *) smbfs_pathconf }, 105 { &vop_print_desc, (vop_t *) smbfs_print }, 106 { &vop_putpages_desc, (vop_t *) smbfs_putpages }, 107 { &vop_read_desc, (vop_t *) smbfs_read }, 108 { &vop_readdir_desc, (vop_t *) smbfs_readdir }, 109 { &vop_reclaim_desc, (vop_t *) smbfs_reclaim }, 110 { &vop_remove_desc, (vop_t *) smbfs_remove }, 111 { &vop_rename_desc, (vop_t *) smbfs_rename }, 112 { &vop_rmdir_desc, (vop_t *) smbfs_rmdir }, 113 { &vop_setattr_desc, (vop_t *) smbfs_setattr }, 114 { &vop_strategy_desc, (vop_t *) smbfs_strategy }, 115 { &vop_symlink_desc, (vop_t *) smbfs_symlink }, 116 { &vop_write_desc, (vop_t *) smbfs_write }, 117 { &vop_getextattr_desc, (vop_t *) smbfs_getextattr }, 118 /* { &vop_setextattr_desc, (vop_t *) smbfs_setextattr },*/ 119 { NULL, NULL } 120 }; 121 122 static struct vnodeopv_desc smbfs_vnodeop_opv_desc = 123 { &smbfs_vnodeop_p, smbfs_vnodeop_entries }; 124 125 VNODEOP_SET(smbfs_vnodeop_opv_desc); 126 127 static int 128 smbfs_access(ap) 129 struct vop_access_args /* { 130 struct vnode *a_vp; 131 int a_mode; 132 struct ucred *a_cred; 133 struct thread *a_td; 134 } */ *ap; 135 { 136 struct vnode *vp = ap->a_vp; 137 mode_t mode = ap->a_mode; 138 mode_t mpmode; 139 struct smbmount *smp = VTOSMBFS(vp); 140 141 SMBVDEBUG("\n"); 142 if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 143 switch (vp->v_type) { 144 case VREG: case VDIR: case VLNK: 145 return EROFS; 146 default: 147 break; 148 } 149 } 150 mpmode = vp->v_type == VREG ? smp->sm_args.file_mode : 151 smp->sm_args.dir_mode; 152 return (vaccess(vp->v_type, mpmode, smp->sm_args.uid, 153 smp->sm_args.gid, ap->a_mode, ap->a_cred, NULL)); 154 } 155 156 /* ARGSUSED */ 157 static int 158 smbfs_open(ap) 159 struct vop_open_args /* { 160 struct vnode *a_vp; 161 int a_mode; 162 struct ucred *a_cred; 163 struct thread *a_td; 164 } */ *ap; 165 { 166 struct vnode *vp = ap->a_vp; 167 struct smbnode *np = VTOSMB(vp); 168 struct smb_cred scred; 169 struct vattr vattr; 170 int mode = ap->a_mode; 171 int error, accmode; 172 173 SMBVDEBUG("%s,%d\n", np->n_name, np->n_opencount); 174 if (vp->v_type != VREG && vp->v_type != VDIR) { 175 SMBFSERR("open eacces vtype=%d\n", vp->v_type); 176 return EACCES; 177 } 178 if (vp->v_type == VDIR) { 179 np->n_opencount++; 180 return 0; 181 } 182 if (np->n_flag & NMODIFIED) { 183 if ((error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1)) == EINTR) 184 return error; 185 smbfs_attr_cacheremove(vp); 186 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td); 187 if (error) 188 return error; 189 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 190 } else { 191 error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td); 192 if (error) 193 return error; 194 if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) { 195 error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_td, 1); 196 if (error == EINTR) 197 return error; 198 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 199 } 200 } 201 if (np->n_opencount) { 202 np->n_opencount++; 203 return 0; 204 } 205 /* 206 * Use DENYNONE to give unixy semantics of permitting 207 * everything not forbidden by permissions. Ie denial 208 * is up to server with clients/openers needing to use 209 * advisory locks for further control. 210 */ 211 accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 212 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 213 accmode = SMB_SM_DENYNONE|SMB_AM_OPENRW; 214 smb_makescred(&scred, ap->a_td, ap->a_cred); 215 error = smbfs_smb_open(np, accmode, &scred); 216 if (error) { 217 if (mode & FWRITE) 218 return EACCES; 219 else if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 220 accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 221 error = smbfs_smb_open(np, accmode, &scred); 222 } 223 } 224 if (!error) { 225 np->n_opencount++; 226 } 227 smbfs_attr_cacheremove(vp); 228 return error; 229 } 230 231 static int 232 smbfs_closel(struct vop_close_args *ap) 233 { 234 struct vnode *vp = ap->a_vp; 235 struct smbnode *np = VTOSMB(vp); 236 struct thread *td = ap->a_td; 237 struct smb_cred scred; 238 struct vattr vattr; 239 int error; 240 241 SMBVDEBUG("name=%s, pid=%d, c=%d\n", np->n_name, td->td_proc->p_pid, 242 np->n_opencount); 243 244 smb_makescred(&scred, td, ap->a_cred); 245 246 if (np->n_opencount == 0) { 247 if (vp->v_type != VDIR) 248 SMBERROR("Negative opencount\n"); 249 return 0; 250 } 251 np->n_opencount--; 252 if (vp->v_type == VDIR) { 253 if (np->n_opencount) 254 return 0; 255 if (np->n_dirseq) { 256 smbfs_findclose(np->n_dirseq, &scred); 257 np->n_dirseq = NULL; 258 } 259 error = 0; 260 } else { 261 error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, td, 1); 262 if (np->n_opencount) 263 return error; 264 VOP_GETATTR(vp, &vattr, ap->a_cred, td); 265 error = smbfs_smb_close(np->n_mount->sm_share, np->n_fid, 266 &np->n_mtime, &scred); 267 } 268 smbfs_attr_cacheremove(vp); 269 return error; 270 } 271 272 /* 273 * XXX: VOP_CLOSE() usually called without lock held which is suck. Here we 274 * do some heruistic to determine if vnode should be locked. 275 */ 276 static int 277 smbfs_close(ap) 278 struct vop_close_args /* { 279 struct vnodeop_desc *a_desc; 280 struct vnode *a_vp; 281 int a_fflag; 282 struct ucred *a_cred; 283 struct thread *a_td; 284 } */ *ap; 285 { 286 struct vnode *vp = ap->a_vp; 287 struct thread *td = ap->a_td; 288 int error, dolock; 289 290 VI_LOCK(vp); 291 dolock = (vp->v_iflag & VI_XLOCK) == 0; 292 if (dolock) 293 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK, td); 294 else 295 VI_UNLOCK(vp); 296 error = smbfs_closel(ap); 297 if (dolock) 298 VOP_UNLOCK(vp, 0, td); 299 return error; 300 } 301 302 /* 303 * smbfs_getattr call from vfs. 304 */ 305 static int 306 smbfs_getattr(ap) 307 struct vop_getattr_args /* { 308 struct vnode *a_vp; 309 struct vattr *a_vap; 310 struct ucred *a_cred; 311 struct thread *a_td; 312 } */ *ap; 313 { 314 struct vnode *vp = ap->a_vp; 315 struct smbnode *np = VTOSMB(vp); 316 struct vattr *va=ap->a_vap; 317 struct smbfattr fattr; 318 struct smb_cred scred; 319 u_int32_t oldsize; 320 int error; 321 322 SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_vflag & VV_ROOT) != 0); 323 error = smbfs_attr_cachelookup(vp, va); 324 if (!error) 325 return 0; 326 SMBVDEBUG("not in the cache\n"); 327 smb_makescred(&scred, ap->a_td, ap->a_cred); 328 oldsize = np->n_size; 329 error = smbfs_smb_lookup(np, NULL, 0, &fattr, &scred); 330 if (error) { 331 SMBVDEBUG("error %d\n", error); 332 return error; 333 } 334 smbfs_attr_cacheenter(vp, &fattr); 335 smbfs_attr_cachelookup(vp, va); 336 if (np->n_opencount) 337 np->n_size = oldsize; 338 return 0; 339 } 340 341 static int 342 smbfs_setattr(ap) 343 struct vop_setattr_args /* { 344 struct vnode *a_vp; 345 struct vattr *a_vap; 346 struct ucred *a_cred; 347 struct thread *a_td; 348 } */ *ap; 349 { 350 struct vnode *vp = ap->a_vp; 351 struct smbnode *np = VTOSMB(vp); 352 struct vattr *vap = ap->a_vap; 353 struct timespec *mtime, *atime; 354 struct smb_cred scred; 355 struct smb_share *ssp = np->n_mount->sm_share; 356 struct smb_vc *vcp = SSTOVC(ssp); 357 u_quad_t tsize = 0; 358 int isreadonly, doclose, error = 0; 359 360 SMBVDEBUG("\n"); 361 if (vap->va_flags != VNOVAL) 362 return EOPNOTSUPP; 363 isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 364 /* 365 * Disallow write attempts if the filesystem is mounted read-only. 366 */ 367 if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 368 vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 369 vap->va_mode != (mode_t)VNOVAL) && isreadonly) 370 return EROFS; 371 smb_makescred(&scred, ap->a_td, ap->a_cred); 372 if (vap->va_size != VNOVAL) { 373 switch (vp->v_type) { 374 case VDIR: 375 return EISDIR; 376 case VREG: 377 break; 378 default: 379 return EINVAL; 380 }; 381 if (isreadonly) 382 return EROFS; 383 doclose = 0; 384 vnode_pager_setsize(vp, (u_long)vap->va_size); 385 tsize = np->n_size; 386 np->n_size = vap->va_size; 387 if (np->n_opencount == 0) { 388 error = smbfs_smb_open(np, 389 SMB_SM_DENYNONE|SMB_AM_OPENRW, 390 &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_cred, ap->a_td);*/ 431 if (mtime) 432 np->n_mtime = *mtime; 433 VOP_CLOSE(vp, FWRITE, ap->a_cred, 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_cred, 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_cred, cnp->cn_thread))) 540 return error; 541 smb_makescred(&scred, cnp->cn_thread, 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 || vrefcnt(vp) != 1) 575 return EPERM; 576 smb_makescred(&scred, cnp->cn_thread, 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 && vrefcnt(tvp) > 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_thread, 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_cred, cnp->cn_thread))) { 736 return error; 737 } 738 if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 739 return EEXIST; 740 smb_makescred(&scred, cnp->cn_thread, 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_thread, 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("\tname = %s, parent = %p, opencount = %d\n", np->n_name, 845 np->n_parent ? np->n_parent : NULL, np->n_opencount); 846 return (0); 847 } 848 849 static int 850 smbfs_pathconf (ap) 851 struct vop_pathconf_args /* { 852 struct vnode *vp; 853 int name; 854 register_t *retval; 855 } */ *ap; 856 { 857 struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 858 struct smb_vc *vcp = SSTOVC(smp->sm_share); 859 register_t *retval = ap->a_retval; 860 int error = 0; 861 862 switch (ap->a_name) { 863 case _PC_LINK_MAX: 864 *retval = 0; 865 break; 866 case _PC_NAME_MAX: 867 *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 868 break; 869 case _PC_PATH_MAX: 870 *retval = 800; /* XXX: a correct one ? */ 871 break; 872 default: 873 error = EINVAL; 874 } 875 return error; 876 } 877 878 static int 879 smbfs_strategy (ap) 880 struct vop_strategy_args /* { 881 struct buf *a_bp 882 } */ *ap; 883 { 884 struct buf *bp=ap->a_bp; 885 struct ucred *cr; 886 struct thread *td; 887 int error = 0; 888 889 SMBVDEBUG("\n"); 890 if (bp->b_flags & B_PHYS) 891 panic("smbfs physio"); 892 if (bp->b_flags & B_ASYNC) 893 td = (struct thread *)0; 894 else 895 td = curthread; /* XXX */ 896 if (bp->b_iocmd == BIO_READ) 897 cr = bp->b_rcred; 898 else 899 cr = bp->b_wcred; 900 901 if ((bp->b_flags & B_ASYNC) == 0 ) 902 error = smbfs_doio(bp, cr, td); 903 return error; 904 } 905 906 int 907 smbfs_ioctl(ap) 908 struct vop_ioctl_args /* { 909 struct vnode *a_vp; 910 u_long a_command; 911 caddr_t a_data; 912 int fflag; 913 struct ucred *cred; 914 struct thread *td; 915 } */ *ap; 916 { 917 return ENOTTY; 918 } 919 920 static char smbfs_atl[] = "rhsvda"; 921 static int 922 smbfs_getextattr(struct vop_getextattr_args *ap) 923 /* { 924 IN struct vnode *a_vp; 925 IN char *a_name; 926 INOUT struct uio *a_uio; 927 IN struct ucred *a_cred; 928 IN struct thread *a_td; 929 }; 930 */ 931 { 932 struct vnode *vp = ap->a_vp; 933 struct thread *td = ap->a_td; 934 struct ucred *cred = ap->a_cred; 935 struct uio *uio = ap->a_uio; 936 const char *name = ap->a_name; 937 struct smbnode *np = VTOSMB(vp); 938 struct vattr vattr; 939 char buf[10]; 940 int i, attr, error; 941 942 error = VOP_ACCESS(vp, VREAD, cred, td); 943 if (error) 944 return error; 945 error = VOP_GETATTR(vp, &vattr, cred, td); 946 if (error) 947 return error; 948 if (strcmp(name, "dosattr") == 0) { 949 attr = np->n_dosattr; 950 for (i = 0; i < 6; i++, attr >>= 1) 951 buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 952 buf[i] = 0; 953 error = uiomove(buf, i, uio); 954 955 } else 956 error = EINVAL; 957 return error; 958 } 959 960 /* 961 * Since we expected to support F_GETLK (and SMB protocol has no such function), 962 * it is necessary to use lf_advlock(). It would be nice if this function had 963 * a callback mechanism because it will help to improve a level of consistency. 964 */ 965 int 966 smbfs_advlock(ap) 967 struct vop_advlock_args /* { 968 struct vnode *a_vp; 969 caddr_t a_id; 970 int a_op; 971 struct flock *a_fl; 972 int a_flags; 973 } */ *ap; 974 { 975 struct vnode *vp = ap->a_vp; 976 struct smbnode *np = VTOSMB(vp); 977 struct flock *fl = ap->a_fl; 978 caddr_t id = (caddr_t)1 /* ap->a_id */; 979 /* int flags = ap->a_flags;*/ 980 struct thread *td = curthread; 981 struct smb_cred scred; 982 u_quad_t size; 983 off_t start, end, oadd; 984 int error, lkop; 985 986 if (vp->v_type == VDIR) { 987 /* 988 * SMB protocol have no support for directory locking. 989 * Although locks can be processed on local machine, I don't 990 * think that this is a good idea, because some programs 991 * can work wrong assuming directory is locked. So, we just 992 * return 'operation not supported 993 */ 994 return EOPNOTSUPP; 995 } 996 size = np->n_size; 997 switch (fl->l_whence) { 998 999 case SEEK_SET: 1000 case SEEK_CUR: 1001 start = fl->l_start; 1002 break; 1003 1004 case SEEK_END: 1005 if (size > OFF_MAX || 1006 (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 1007 return EOVERFLOW; 1008 start = size + fl->l_start; 1009 break; 1010 1011 default: 1012 return EINVAL; 1013 } 1014 if (start < 0) 1015 return EINVAL; 1016 if (fl->l_len < 0) { 1017 if (start == 0) 1018 return EINVAL; 1019 end = start - 1; 1020 start += fl->l_len; 1021 if (start < 0) 1022 return EINVAL; 1023 } else if (fl->l_len == 0) 1024 end = -1; 1025 else { 1026 oadd = fl->l_len - 1; 1027 if (oadd > OFF_MAX - start) 1028 return EOVERFLOW; 1029 end = start + oadd; 1030 } 1031 smb_makescred(&scred, td, td->td_ucred); 1032 switch (ap->a_op) { 1033 case F_SETLK: 1034 switch (fl->l_type) { 1035 case F_WRLCK: 1036 lkop = SMB_LOCK_EXCL; 1037 break; 1038 case F_RDLCK: 1039 lkop = SMB_LOCK_SHARED; 1040 break; 1041 case F_UNLCK: 1042 lkop = SMB_LOCK_RELEASE; 1043 break; 1044 default: 1045 return EINVAL; 1046 } 1047 error = lf_advlock(ap, &np->n_lockf, size); 1048 if (error) 1049 break; 1050 lkop = SMB_LOCK_EXCL; 1051 error = smbfs_smb_lock(np, lkop, id, start, end, &scred); 1052 if (error) { 1053 ap->a_op = F_UNLCK; 1054 lf_advlock(ap, &np->n_lockf, size); 1055 } 1056 break; 1057 case F_UNLCK: 1058 lf_advlock(ap, &np->n_lockf, size); 1059 error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, &scred); 1060 break; 1061 case F_GETLK: 1062 error = lf_advlock(ap, &np->n_lockf, size); 1063 break; 1064 default: 1065 return EINVAL; 1066 } 1067 return error; 1068 } 1069 1070 static int 1071 smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) 1072 { 1073 static const char *badchars = "*/\\[]:<>=;?"; 1074 static const char *badchars83 = " +|,"; 1075 const char *cp; 1076 int i, error; 1077 1078 if (nameiop == LOOKUP) 1079 return 0; 1080 error = ENOENT; 1081 if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { 1082 /* 1083 * Name should conform 8.3 format 1084 */ 1085 if (nmlen > 12) 1086 return ENAMETOOLONG; 1087 cp = index(name, '.'); 1088 if (cp == NULL) 1089 return error; 1090 if (cp == name || (cp - name) > 8) 1091 return error; 1092 cp = index(cp + 1, '.'); 1093 if (cp != NULL) 1094 return error; 1095 for (cp = name, i = 0; i < nmlen; i++, cp++) 1096 if (index(badchars83, *cp) != NULL) 1097 return error; 1098 } 1099 for (cp = name, i = 0; i < nmlen; i++, cp++) 1100 if (index(badchars, *cp) != NULL) 1101 return error; 1102 return 0; 1103 } 1104 1105 #ifndef PDIRUNLOCK 1106 #define PDIRUNLOCK 0 1107 #endif 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_thread; 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_vflag & VV_ROOT)) { 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 mp_fixme("Unlocked v_id access."); 1183 vpid = vp->v_id; 1184 if (dvp == vp) { /* lookup on current */ 1185 vref(vp); 1186 error = 0; 1187 SMBVDEBUG("cached '.'\n"); 1188 } else if (flags & ISDOTDOT) { 1189 VOP_UNLOCK(dvp, 0, td); /* unlock parent */ 1190 cnp->cn_flags |= PDIRUNLOCK; 1191 error = vget(vp, LK_EXCLUSIVE, td); 1192 if (!error && lockparent && islastcn) { 1193 error = vn_lock(dvp, LK_EXCLUSIVE, td); 1194 if (error == 0) 1195 cnp->cn_flags &= ~PDIRUNLOCK; 1196 } 1197 } else { 1198 error = vget(vp, LK_EXCLUSIVE, td); 1199 if (!lockparent || error || !islastcn) { 1200 VOP_UNLOCK(dvp, 0, td); 1201 cnp->cn_flags |= PDIRUNLOCK; 1202 } 1203 } 1204 if (!error) { 1205 if (vpid == vp->v_id) { 1206 if (!VOP_GETATTR(vp, &vattr, cnp->cn_cred, td) 1207 /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { 1208 if (nameiop != LOOKUP && islastcn) 1209 cnp->cn_flags |= SAVENAME; 1210 SMBVDEBUG("use cached vnode\n"); 1211 return (0); 1212 } 1213 cache_purge(vp); 1214 } 1215 vput(vp); 1216 if (lockparent && dvp != vp && islastcn) 1217 VOP_UNLOCK(dvp, 0, td); 1218 } 1219 error = vn_lock(dvp, LK_EXCLUSIVE, td); 1220 *vpp = NULLVP; 1221 if (error) { 1222 cnp->cn_flags |= PDIRUNLOCK; 1223 return (error); 1224 } 1225 cnp->cn_flags &= ~PDIRUNLOCK; 1226 } 1227 /* 1228 * entry is not in the cache or has been expired 1229 */ 1230 error = 0; 1231 *vpp = NULLVP; 1232 smb_makescred(&scred, td, cnp->cn_cred); 1233 fap = &fattr; 1234 if (flags & ISDOTDOT) { 1235 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, 1236 &scred); 1237 SMBVDEBUG("result of dotdot lookup: %d\n", error); 1238 } else { 1239 fap = &fattr; 1240 error = smbfs_smb_lookup(dnp, name, nmlen, fap, &scred); 1241 /* if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')*/ 1242 SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1243 } 1244 if (error && error != ENOENT) 1245 return error; 1246 if (error) { /* entry not found */ 1247 /* 1248 * Handle RENAME or CREATE case... 1249 */ 1250 if ((nameiop == CREATE || nameiop == RENAME) && wantparent && islastcn) { 1251 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1252 if (error) 1253 return error; 1254 cnp->cn_flags |= SAVENAME; 1255 if (!lockparent) { 1256 VOP_UNLOCK(dvp, 0, td); 1257 cnp->cn_flags |= PDIRUNLOCK; 1258 } 1259 return (EJUSTRETURN); 1260 } 1261 return ENOENT; 1262 }/* else { 1263 SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 1264 }*/ 1265 /* 1266 * handle DELETE case ... 1267 */ 1268 if (nameiop == DELETE && islastcn) { /* delete last component */ 1269 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1270 if (error) 1271 return error; 1272 if (isdot) { 1273 VREF(dvp); 1274 *vpp = dvp; 1275 return 0; 1276 } 1277 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1278 if (error) 1279 return error; 1280 *vpp = vp; 1281 cnp->cn_flags |= SAVENAME; 1282 if (!lockparent) { 1283 VOP_UNLOCK(dvp, 0, td); 1284 cnp->cn_flags |= PDIRUNLOCK; 1285 } 1286 return 0; 1287 } 1288 if (nameiop == RENAME && islastcn && wantparent) { 1289 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1290 if (error) 1291 return error; 1292 if (isdot) 1293 return EISDIR; 1294 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1295 if (error) 1296 return error; 1297 *vpp = vp; 1298 cnp->cn_flags |= SAVENAME; 1299 if (!lockparent) { 1300 VOP_UNLOCK(dvp, 0, td); 1301 cnp->cn_flags |= PDIRUNLOCK; 1302 } 1303 return 0; 1304 } 1305 if (flags & ISDOTDOT) { 1306 VOP_UNLOCK(dvp, 0, td); 1307 error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); 1308 if (error) { 1309 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 1310 return error; 1311 } 1312 if (lockparent && islastcn) { 1313 error = vn_lock(dvp, LK_EXCLUSIVE, td); 1314 if (error) { 1315 cnp->cn_flags |= PDIRUNLOCK; 1316 vput(vp); 1317 return error; 1318 } 1319 } 1320 *vpp = vp; 1321 } else if (isdot) { 1322 vref(dvp); 1323 *vpp = dvp; 1324 } else { 1325 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1326 if (error) 1327 return error; 1328 *vpp = vp; 1329 SMBVDEBUG("lookup: getnewvp!\n"); 1330 if (!lockparent || !islastcn) { 1331 VOP_UNLOCK(dvp, 0, td); 1332 cnp->cn_flags |= PDIRUNLOCK; 1333 } 1334 } 1335 if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 1336 /* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ 1337 cache_enter(dvp, *vpp, cnp); 1338 } 1339 return 0; 1340 } 1341