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