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