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 SMBERROR("Negative opencount\n"); 254 return 0; 255 } 256 np->n_opencount--; 257 if (vp->v_type == VDIR) { 258 if (np->n_opencount) 259 return 0; 260 if (np->n_dirseq) { 261 smbfs_findclose(np->n_dirseq, &scred); 262 np->n_dirseq = NULL; 263 } 264 error = 0; 265 } else { 266 error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, td, 1); 267 if (np->n_opencount) 268 return error; 269 VOP_GETATTR(vp, &vattr, ap->a_cred, td); 270 error = smbfs_smb_close(np->n_mount->sm_share, np->n_fid, 271 &np->n_mtime, &scred); 272 } 273 smbfs_attr_cacheremove(vp); 274 return error; 275 } 276 277 /* 278 * XXX: VOP_CLOSE() usually called without lock held which is suck. Here we 279 * do some heruistic to determine if vnode should be locked. 280 */ 281 static int 282 smbfs_close(ap) 283 struct vop_close_args /* { 284 struct vnodeop_desc *a_desc; 285 struct vnode *a_vp; 286 int a_fflag; 287 struct ucred *a_cred; 288 struct thread *a_td; 289 } */ *ap; 290 { 291 struct vnode *vp = ap->a_vp; 292 struct thread *td = ap->a_td; 293 int error, dolock; 294 295 VI_LOCK(vp); 296 dolock = (vp->v_flag & VXLOCK) == 0; 297 if (dolock) 298 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK, td); 299 else 300 VI_UNLOCK(vp); 301 error = smbfs_closel(ap); 302 if (dolock) 303 VOP_UNLOCK(vp, 0, td); 304 return error; 305 } 306 307 /* 308 * smbfs_getattr call from vfs. 309 */ 310 static int 311 smbfs_getattr(ap) 312 struct vop_getattr_args /* { 313 struct vnode *a_vp; 314 struct vattr *a_vap; 315 struct ucred *a_cred; 316 struct thread *a_td; 317 } */ *ap; 318 { 319 struct vnode *vp = ap->a_vp; 320 struct smbnode *np = VTOSMB(vp); 321 struct vattr *va=ap->a_vap; 322 struct smbfattr fattr; 323 struct smb_cred scred; 324 u_int32_t oldsize; 325 int error; 326 327 SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_flag & VROOT) != 0); 328 error = smbfs_attr_cachelookup(vp, va); 329 if (!error) 330 return 0; 331 SMBVDEBUG("not in the cache\n"); 332 smb_makescred(&scred, ap->a_td, ap->a_cred); 333 oldsize = np->n_size; 334 error = smbfs_smb_lookup(np, NULL, 0, &fattr, &scred); 335 if (error) { 336 SMBVDEBUG("error %d\n", error); 337 return error; 338 } 339 smbfs_attr_cacheenter(vp, &fattr); 340 smbfs_attr_cachelookup(vp, va); 341 if (np->n_opencount) 342 np->n_size = oldsize; 343 return 0; 344 } 345 346 static int 347 smbfs_setattr(ap) 348 struct vop_setattr_args /* { 349 struct vnode *a_vp; 350 struct vattr *a_vap; 351 struct ucred *a_cred; 352 struct thread *a_td; 353 } */ *ap; 354 { 355 struct vnode *vp = ap->a_vp; 356 struct smbnode *np = VTOSMB(vp); 357 struct vattr *vap = ap->a_vap; 358 struct timespec *mtime, *atime; 359 struct smb_cred scred; 360 struct smb_share *ssp = np->n_mount->sm_share; 361 struct smb_vc *vcp = SSTOVC(ssp); 362 u_quad_t tsize = 0; 363 int isreadonly, doclose, error = 0; 364 365 SMBVDEBUG("\n"); 366 if (vap->va_flags != VNOVAL) 367 return EOPNOTSUPP; 368 isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 369 /* 370 * Disallow write attempts if the filesystem is mounted read-only. 371 */ 372 if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 373 vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 374 vap->va_mode != (mode_t)VNOVAL) && isreadonly) 375 return EROFS; 376 smb_makescred(&scred, ap->a_td, ap->a_cred); 377 if (vap->va_size != VNOVAL) { 378 switch (vp->v_type) { 379 case VDIR: 380 return EISDIR; 381 case VREG: 382 break; 383 default: 384 return EINVAL; 385 }; 386 if (isreadonly) 387 return EROFS; 388 doclose = 0; 389 vnode_pager_setsize(vp, (u_long)vap->va_size); 390 tsize = np->n_size; 391 np->n_size = vap->va_size; 392 if (np->n_opencount == 0) { 393 error = smbfs_smb_open(np, SMB_AM_OPENRW, &scred); 394 if (error == 0) 395 doclose = 1; 396 } 397 if (error == 0) 398 error = smbfs_smb_setfsize(np, vap->va_size, &scred); 399 if (doclose) 400 smbfs_smb_close(ssp, np->n_fid, NULL, &scred); 401 if (error) { 402 np->n_size = tsize; 403 vnode_pager_setsize(vp, (u_long)tsize); 404 return error; 405 } 406 } 407 mtime = atime = NULL; 408 if (vap->va_mtime.tv_sec != VNOVAL) 409 mtime = &vap->va_mtime; 410 if (vap->va_atime.tv_sec != VNOVAL) 411 atime = &vap->va_atime; 412 if (mtime != atime) { 413 #if 0 414 if (mtime == NULL) 415 mtime = &np->n_mtime; 416 if (atime == NULL) 417 atime = &np->n_atime; 418 #endif 419 /* 420 * If file is opened, then we can use handle based calls. 421 * If not, use path based ones. 422 */ 423 if (np->n_opencount == 0) { 424 if (vcp->vc_flags & SMBV_WIN95) { 425 error = VOP_OPEN(vp, FWRITE, ap->a_cred, ap->a_td); 426 if (!error) { 427 /* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 428 VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td);*/ 429 if (mtime) 430 np->n_mtime = *mtime; 431 VOP_CLOSE(vp, FWRITE, ap->a_cred, ap->a_td); 432 } 433 } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 434 error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 435 /* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred);*/ 436 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 437 error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 438 } else { 439 error = smbfs_smb_setpattr(np, 0, mtime, &scred); 440 } 441 } else { 442 if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 443 error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 444 } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 445 error = smbfs_smb_setftime(np, mtime, atime, &scred); 446 } else { 447 /* 448 * I have no idea how to handle this for core 449 * level servers. The possible solution is to 450 * update mtime after file is closed. 451 */ 452 SMBERROR("can't update times on an opened file\n"); 453 } 454 } 455 } 456 /* 457 * Invalidate attribute cache in case if server doesn't set 458 * required attributes. 459 */ 460 smbfs_attr_cacheremove(vp); /* invalidate cache */ 461 VOP_GETATTR(vp, vap, ap->a_cred, ap->a_td); 462 np->n_mtime.tv_sec = vap->va_mtime.tv_sec; 463 return error; 464 } 465 /* 466 * smbfs_read call. 467 */ 468 static int 469 smbfs_read(ap) 470 struct vop_read_args /* { 471 struct vnode *a_vp; 472 struct uio *a_uio; 473 int a_ioflag; 474 struct ucred *a_cred; 475 } */ *ap; 476 { 477 struct vnode *vp = ap->a_vp; 478 struct uio *uio = ap->a_uio; 479 480 SMBVDEBUG("\n"); 481 if (vp->v_type != VREG && vp->v_type != VDIR) 482 return EPERM; 483 return smbfs_readvnode(vp, uio, ap->a_cred); 484 } 485 486 static int 487 smbfs_write(ap) 488 struct vop_write_args /* { 489 struct vnode *a_vp; 490 struct uio *a_uio; 491 int a_ioflag; 492 struct ucred *a_cred; 493 } */ *ap; 494 { 495 struct vnode *vp = ap->a_vp; 496 struct uio *uio = ap->a_uio; 497 498 SMBVDEBUG("%d,ofs=%d,sz=%d\n",vp->v_type, (int)uio->uio_offset, uio->uio_resid); 499 if (vp->v_type != VREG) 500 return (EPERM); 501 return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); 502 } 503 /* 504 * smbfs_create call 505 * Create a regular file. On entry the directory to contain the file being 506 * created is locked. We must release before we return. We must also free 507 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or 508 * only if the SAVESTART bit in cn_flags is clear on success. 509 */ 510 static int 511 smbfs_create(ap) 512 struct vop_create_args /* { 513 struct vnode *a_dvp; 514 struct vnode **a_vpp; 515 struct componentname *a_cnp; 516 struct vattr *a_vap; 517 } */ *ap; 518 { 519 struct vnode *dvp = ap->a_dvp; 520 struct vattr *vap = ap->a_vap; 521 struct vnode **vpp=ap->a_vpp; 522 struct componentname *cnp = ap->a_cnp; 523 struct smbnode *dnp = VTOSMB(dvp); 524 struct vnode *vp; 525 struct vattr vattr; 526 struct smbfattr fattr; 527 struct smb_cred scred; 528 char *name = cnp->cn_nameptr; 529 int nmlen = cnp->cn_namelen; 530 int error; 531 532 533 SMBVDEBUG("\n"); 534 *vpp = NULL; 535 if (vap->va_type != VREG) 536 return EOPNOTSUPP; 537 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread))) 538 return error; 539 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 540 541 error = smbfs_smb_create(dnp, name, nmlen, &scred); 542 if (error) 543 return error; 544 error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred); 545 if (error) 546 return error; 547 error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); 548 if (error) 549 return error; 550 *vpp = vp; 551 if (cnp->cn_flags & MAKEENTRY) 552 cache_enter(dvp, vp, cnp); 553 return error; 554 } 555 556 static int 557 smbfs_remove(ap) 558 struct vop_remove_args /* { 559 struct vnodeop_desc *a_desc; 560 struct vnode * a_dvp; 561 struct vnode * a_vp; 562 struct componentname * a_cnp; 563 } */ *ap; 564 { 565 struct vnode *vp = ap->a_vp; 566 /* struct vnode *dvp = ap->a_dvp;*/ 567 struct componentname *cnp = ap->a_cnp; 568 struct smbnode *np = VTOSMB(vp); 569 struct smb_cred scred; 570 int error; 571 572 if (vp->v_type == VDIR || np->n_opencount || vp->v_usecount != 1) 573 return EPERM; 574 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 575 error = smbfs_smb_delete(np, &scred); 576 cache_purge(vp); 577 return error; 578 } 579 580 /* 581 * smbfs_file rename call 582 */ 583 static int 584 smbfs_rename(ap) 585 struct vop_rename_args /* { 586 struct vnode *a_fdvp; 587 struct vnode *a_fvp; 588 struct componentname *a_fcnp; 589 struct vnode *a_tdvp; 590 struct vnode *a_tvp; 591 struct componentname *a_tcnp; 592 } */ *ap; 593 { 594 struct vnode *fvp = ap->a_fvp; 595 struct vnode *tvp = ap->a_tvp; 596 struct vnode *fdvp = ap->a_fdvp; 597 struct vnode *tdvp = ap->a_tdvp; 598 struct componentname *tcnp = ap->a_tcnp; 599 /* struct componentname *fcnp = ap->a_fcnp;*/ 600 struct smb_cred scred; 601 u_int16_t flags = 6; 602 int error=0; 603 604 /* Check for cross-device rename */ 605 if ((fvp->v_mount != tdvp->v_mount) || 606 (tvp && (fvp->v_mount != tvp->v_mount))) { 607 error = EXDEV; 608 goto out; 609 } 610 611 if (tvp && tvp->v_usecount > 1) { 612 error = EBUSY; 613 goto out; 614 } 615 flags = 0x10; /* verify all writes */ 616 if (fvp->v_type == VDIR) { 617 flags |= 2; 618 } else if (fvp->v_type == VREG) { 619 flags |= 1; 620 } else 621 return EINVAL; 622 smb_makescred(&scred, tcnp->cn_thread, tcnp->cn_cred); 623 /* 624 * It seems that Samba doesn't implement SMB_COM_MOVE call... 625 */ 626 #ifdef notnow 627 if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { 628 error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), 629 tcnp->cn_nameptr, tcnp->cn_namelen, flags, &scred); 630 } else 631 #endif 632 { 633 /* 634 * We have to do the work atomicaly 635 */ 636 if (tvp && tvp != fvp) { 637 error = smbfs_smb_delete(VTOSMB(tvp), &scred); 638 if (error) 639 goto out; 640 } 641 error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), 642 tcnp->cn_nameptr, tcnp->cn_namelen, &scred); 643 } 644 645 if (fvp->v_type == VDIR) { 646 if (tvp != NULL && tvp->v_type == VDIR) 647 cache_purge(tdvp); 648 cache_purge(fdvp); 649 } 650 out: 651 if (tdvp == tvp) 652 vrele(tdvp); 653 else 654 vput(tdvp); 655 if (tvp) 656 vput(tvp); 657 vrele(fdvp); 658 vrele(fvp); 659 smbfs_attr_cacheremove(fdvp); 660 smbfs_attr_cacheremove(tdvp); 661 #ifdef possible_mistake 662 vgone(fvp); 663 if (tvp) 664 vgone(tvp); 665 #endif 666 return error; 667 } 668 669 /* 670 * somtime it will come true... 671 */ 672 static int 673 smbfs_link(ap) 674 struct vop_link_args /* { 675 struct vnode *a_tdvp; 676 struct vnode *a_vp; 677 struct componentname *a_cnp; 678 } */ *ap; 679 { 680 return EOPNOTSUPP; 681 } 682 683 /* 684 * smbfs_symlink link create call. 685 * Sometime it will be functional... 686 */ 687 static int 688 smbfs_symlink(ap) 689 struct vop_symlink_args /* { 690 struct vnode *a_dvp; 691 struct vnode **a_vpp; 692 struct componentname *a_cnp; 693 struct vattr *a_vap; 694 char *a_target; 695 } */ *ap; 696 { 697 return EOPNOTSUPP; 698 } 699 700 static int 701 smbfs_mknod(ap) 702 struct vop_mknod_args /* { 703 } */ *ap; 704 { 705 return EOPNOTSUPP; 706 } 707 708 static int 709 smbfs_mkdir(ap) 710 struct vop_mkdir_args /* { 711 struct vnode *a_dvp; 712 struct vnode **a_vpp; 713 struct componentname *a_cnp; 714 struct vattr *a_vap; 715 } */ *ap; 716 { 717 struct vnode *dvp = ap->a_dvp; 718 /* struct vattr *vap = ap->a_vap;*/ 719 struct vnode *vp; 720 struct componentname *cnp = ap->a_cnp; 721 struct smbnode *dnp = VTOSMB(dvp); 722 struct vattr vattr; 723 struct smb_cred scred; 724 struct smbfattr fattr; 725 char *name = cnp->cn_nameptr; 726 int len = cnp->cn_namelen; 727 int error; 728 729 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread))) { 730 return error; 731 } 732 if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 733 return EEXIST; 734 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 735 error = smbfs_smb_mkdir(dnp, name, len, &scred); 736 if (error) 737 return error; 738 error = smbfs_smb_lookup(dnp, name, len, &fattr, &scred); 739 if (error) 740 return error; 741 error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); 742 if (error) 743 return error; 744 *ap->a_vpp = vp; 745 return 0; 746 } 747 748 /* 749 * smbfs_remove directory call 750 */ 751 static int 752 smbfs_rmdir(ap) 753 struct vop_rmdir_args /* { 754 struct vnode *a_dvp; 755 struct vnode *a_vp; 756 struct componentname *a_cnp; 757 } */ *ap; 758 { 759 struct vnode *vp = ap->a_vp; 760 struct vnode *dvp = ap->a_dvp; 761 struct componentname *cnp = ap->a_cnp; 762 /* struct smbmount *smp = VTOSMBFS(vp);*/ 763 struct smbnode *dnp = VTOSMB(dvp); 764 struct smbnode *np = VTOSMB(vp); 765 struct smb_cred scred; 766 int error; 767 768 if (dvp == vp) 769 return EINVAL; 770 771 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 772 error = smbfs_smb_rmdir(np, &scred); 773 dnp->n_flag |= NMODIFIED; 774 smbfs_attr_cacheremove(dvp); 775 /* cache_purge(dvp);*/ 776 cache_purge(vp); 777 return error; 778 } 779 780 /* 781 * smbfs_readdir call 782 */ 783 static int 784 smbfs_readdir(ap) 785 struct vop_readdir_args /* { 786 struct vnode *a_vp; 787 struct uio *a_uio; 788 struct ucred *a_cred; 789 int *a_eofflag; 790 u_long *a_cookies; 791 int a_ncookies; 792 } */ *ap; 793 { 794 struct vnode *vp = ap->a_vp; 795 struct uio *uio = ap->a_uio; 796 int error; 797 798 if (vp->v_type != VDIR) 799 return (EPERM); 800 #ifdef notnow 801 if (ap->a_ncookies) { 802 printf("smbfs_readdir: no support for cookies now..."); 803 return (EOPNOTSUPP); 804 } 805 #endif 806 error = smbfs_readvnode(vp, uio, ap->a_cred); 807 return error; 808 } 809 810 /* ARGSUSED */ 811 static int 812 smbfs_fsync(ap) 813 struct vop_fsync_args /* { 814 struct vnodeop_desc *a_desc; 815 struct vnode * a_vp; 816 struct ucred * a_cred; 817 int a_waitfor; 818 struct thread * a_td; 819 } */ *ap; 820 { 821 /* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ 822 return (0); 823 } 824 825 static 826 int smbfs_print (ap) 827 struct vop_print_args /* { 828 struct vnode *a_vp; 829 } */ *ap; 830 { 831 struct vnode *vp = ap->a_vp; 832 struct smbnode *np = VTOSMB(vp); 833 834 if (np == NULL) { 835 printf("no smbnode data\n"); 836 return (0); 837 } 838 printf("tag VT_SMBFS, name = %s, parent = %p, opencount = %d", 839 np->n_name, np->n_parent ? SMBTOV(np->n_parent) : NULL, 840 np->n_opencount); 841 lockmgr_printinfo(&vp->v_lock); 842 printf("\n"); 843 return (0); 844 } 845 846 static int 847 smbfs_pathconf (ap) 848 struct vop_pathconf_args /* { 849 struct vnode *vp; 850 int name; 851 register_t *retval; 852 } */ *ap; 853 { 854 struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 855 struct smb_vc *vcp = SSTOVC(smp->sm_share); 856 register_t *retval = ap->a_retval; 857 int error = 0; 858 859 switch (ap->a_name) { 860 case _PC_LINK_MAX: 861 *retval = 0; 862 break; 863 case _PC_NAME_MAX: 864 *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 865 break; 866 case _PC_PATH_MAX: 867 *retval = 800; /* XXX: a correct one ? */ 868 break; 869 default: 870 error = EINVAL; 871 } 872 return error; 873 } 874 875 static int 876 smbfs_strategy (ap) 877 struct vop_strategy_args /* { 878 struct buf *a_bp 879 } */ *ap; 880 { 881 struct buf *bp=ap->a_bp; 882 struct ucred *cr; 883 struct thread *td; 884 int error = 0; 885 886 SMBVDEBUG("\n"); 887 if (bp->b_flags & B_PHYS) 888 panic("smbfs physio"); 889 if (bp->b_flags & B_ASYNC) 890 td = (struct thread *)0; 891 else 892 td = curthread; /* XXX */ 893 if (bp->b_iocmd == BIO_READ) 894 cr = bp->b_rcred; 895 else 896 cr = bp->b_wcred; 897 898 if ((bp->b_flags & B_ASYNC) == 0 ) 899 error = smbfs_doio(bp, cr, td); 900 return error; 901 } 902 903 int 904 smbfs_ioctl(ap) 905 struct vop_ioctl_args /* { 906 struct vnode *a_vp; 907 u_long a_command; 908 caddr_t a_data; 909 int fflag; 910 struct ucred *cred; 911 struct thread *td; 912 } */ *ap; 913 { 914 return EINVAL; 915 } 916 917 static char smbfs_atl[] = "rhsvda"; 918 static int 919 smbfs_getextattr(struct vop_getextattr_args *ap) 920 /* { 921 IN struct vnode *a_vp; 922 IN char *a_name; 923 INOUT struct uio *a_uio; 924 IN struct ucred *a_cred; 925 IN struct thread *a_td; 926 }; 927 */ 928 { 929 struct vnode *vp = ap->a_vp; 930 struct thread *td = ap->a_td; 931 struct ucred *cred = ap->a_cred; 932 struct uio *uio = ap->a_uio; 933 const char *name = ap->a_name; 934 struct smbnode *np = VTOSMB(vp); 935 struct vattr vattr; 936 char buf[10]; 937 int i, attr, error; 938 939 error = VOP_ACCESS(vp, VREAD, cred, td); 940 if (error) 941 return error; 942 error = VOP_GETATTR(vp, &vattr, cred, td); 943 if (error) 944 return error; 945 if (strcmp(name, "dosattr") == 0) { 946 attr = np->n_dosattr; 947 for (i = 0; i < 6; i++, attr >>= 1) 948 buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 949 buf[i] = 0; 950 error = uiomove(buf, i, uio); 951 952 } else 953 error = EINVAL; 954 return error; 955 } 956 957 /* 958 * Since we expected to support F_GETLK (and SMB protocol has no such function), 959 * it is necessary to use lf_advlock(). It would be nice if this function had 960 * a callback mechanism because it will help to improve a level of consistency. 961 */ 962 int 963 smbfs_advlock(ap) 964 struct vop_advlock_args /* { 965 struct vnode *a_vp; 966 caddr_t a_id; 967 int a_op; 968 struct flock *a_fl; 969 int a_flags; 970 } */ *ap; 971 { 972 struct vnode *vp = ap->a_vp; 973 struct smbnode *np = VTOSMB(vp); 974 struct flock *fl = ap->a_fl; 975 caddr_t id = (caddr_t)1 /* ap->a_id */; 976 /* int flags = ap->a_flags;*/ 977 struct thread *td = curthread; 978 struct proc *p = td ? td->td_proc : NULL; 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, p ? p->p_ucred : NULL); 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