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