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