smbfs_vnops.c revision 242384
1193323Sed/*- 2193323Sed * Copyright (c) 2000-2001 Boris Popov 3193323Sed * All rights reserved. 4193323Sed * 5193323Sed * Redistribution and use in source and binary forms, with or without 6193323Sed * modification, are permitted provided that the following conditions 7193323Sed * are met: 8193323Sed * 1. Redistributions of source code must retain the above copyright 9193323Sed * notice, this list of conditions and the following disclaimer. 10193323Sed * 2. Redistributions in binary form must reproduce the above copyright 11193323Sed * notice, this list of conditions and the following disclaimer in the 12193323Sed * documentation and/or other materials provided with the distribution. 13193323Sed * 14193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17198090Srdivacky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24193323Sed * SUCH DAMAGE. 25193323Sed * 26193323Sed * $FreeBSD: head/sys/fs/smbfs/smbfs_vnops.c 242384 2012-10-31 02:54:44Z davide $ 27193323Sed */ 28193323Sed#include <sys/param.h> 29193323Sed#include <sys/systm.h> 30193323Sed#include <sys/namei.h> 31193323Sed#include <sys/kernel.h> 32193323Sed#include <sys/proc.h> 33193323Sed#include <sys/bio.h> 34193323Sed#include <sys/buf.h> 35193323Sed#include <sys/fcntl.h> 36193323Sed#include <sys/mount.h> 37193323Sed#include <sys/unistd.h> 38193323Sed#include <sys/vnode.h> 39193323Sed#include <sys/limits.h> 40193323Sed#include <sys/lockf.h> 41193323Sed#include <sys/stat.h> 42193323Sed 43193323Sed#include <vm/vm.h> 44193323Sed#include <vm/vm_extern.h> 45193323Sed 46193323Sed 47193323Sed#include <netsmb/smb.h> 48193323Sed#include <netsmb/smb_conn.h> 49193323Sed#include <netsmb/smb_subr.h> 50193323Sed 51193323Sed#include <fs/smbfs/smbfs.h> 52193323Sed#include <fs/smbfs/smbfs_node.h> 53193323Sed#include <fs/smbfs/smbfs_subr.h> 54193323Sed 55234353Sdim/* 56234353Sdim * Prototypes for SMBFS vnode operations 57234353Sdim */ 58234353Sdimstatic vop_create_t smbfs_create; 59193323Sedstatic vop_mknod_t smbfs_mknod; 60193323Sedstatic vop_open_t smbfs_open; 61193323Sedstatic vop_close_t smbfs_close; 62193323Sedstatic vop_access_t smbfs_access; 63193323Sedstatic vop_getattr_t smbfs_getattr; 64193323Sedstatic vop_setattr_t smbfs_setattr; 65193323Sedstatic vop_read_t smbfs_read; 66193323Sedstatic vop_write_t smbfs_write; 67193323Sedstatic vop_fsync_t smbfs_fsync; 68193323Sedstatic vop_remove_t smbfs_remove; 69193323Sedstatic vop_link_t smbfs_link; 70193323Sedstatic vop_lookup_t smbfs_lookup; 71193323Sedstatic vop_rename_t smbfs_rename; 72193323Sedstatic vop_mkdir_t smbfs_mkdir; 73193323Sedstatic vop_rmdir_t smbfs_rmdir; 74193323Sedstatic vop_symlink_t smbfs_symlink; 75193323Sedstatic vop_readdir_t smbfs_readdir; 76193323Sedstatic vop_strategy_t smbfs_strategy; 77193323Sedstatic vop_print_t smbfs_print; 78193323Sedstatic vop_pathconf_t smbfs_pathconf; 79199481Srdivackystatic vop_advlock_t smbfs_advlock; 80193323Sedstatic vop_getextattr_t smbfs_getextattr; 81193323Sed 82193323Sedstruct vop_vector smbfs_vnodeops = { 83193323Sed .vop_default = &default_vnodeops, 84199481Srdivacky 85193323Sed .vop_access = smbfs_access, 86193323Sed .vop_advlock = smbfs_advlock, 87193323Sed .vop_close = smbfs_close, 88193323Sed .vop_create = smbfs_create, 89193323Sed .vop_fsync = smbfs_fsync, 90193323Sed .vop_getattr = smbfs_getattr, 91193323Sed .vop_getextattr = smbfs_getextattr, 92199481Srdivacky .vop_getpages = smbfs_getpages, 93193323Sed .vop_inactive = smbfs_inactive, 94193323Sed .vop_ioctl = smbfs_ioctl, 95193323Sed .vop_link = smbfs_link, 96193323Sed .vop_lookup = smbfs_lookup, 97193323Sed .vop_mkdir = smbfs_mkdir, 98193323Sed .vop_mknod = smbfs_mknod, 99193323Sed .vop_open = smbfs_open, 100193323Sed .vop_pathconf = smbfs_pathconf, 101193323Sed .vop_print = smbfs_print, 102193323Sed .vop_putpages = smbfs_putpages, 103193323Sed .vop_read = smbfs_read, 104193323Sed .vop_readdir = smbfs_readdir, 105193323Sed .vop_reclaim = smbfs_reclaim, 106193323Sed .vop_remove = smbfs_remove, 107193323Sed .vop_rename = smbfs_rename, 108193323Sed .vop_rmdir = smbfs_rmdir, 109193323Sed .vop_setattr = smbfs_setattr, 110193323Sed/* .vop_setextattr = smbfs_setextattr,*/ 111193323Sed .vop_strategy = smbfs_strategy, 112193323Sed .vop_symlink = smbfs_symlink, 113193323Sed .vop_write = smbfs_write, 114193323Sed}; 115193323Sed 116193323Sedstatic int 117193323Sedsmbfs_access(ap) 118193323Sed struct vop_access_args /* { 119193323Sed struct vnode *a_vp; 120218893Sdim accmode_t a_accmode; 121218893Sdim struct ucred *a_cred; 122198090Srdivacky struct thread *a_td; 123198090Srdivacky } */ *ap; 124193323Sed{ 125193323Sed struct vnode *vp = ap->a_vp; 126193323Sed accmode_t accmode = ap->a_accmode; 127193323Sed mode_t mpmode; 128193323Sed struct smbmount *smp = VTOSMBFS(vp); 129193323Sed 130193323Sed SMBVDEBUG("\n"); 131193323Sed if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 132193323Sed switch (vp->v_type) { 133193323Sed case VREG: case VDIR: case VLNK: 134224145Sdim return EROFS; 135193323Sed default: 136193323Sed break; 137193323Sed } 138193323Sed } 139193323Sed mpmode = vp->v_type == VREG ? smp->sm_file_mode : smp->sm_dir_mode; 140193323Sed return (vaccess(vp->v_type, mpmode, smp->sm_uid, 141193323Sed smp->sm_gid, ap->a_accmode, ap->a_cred, NULL)); 142193323Sed} 143193323Sed 144193323Sed/* ARGSUSED */ 145193323Sedstatic int 146193323Sedsmbfs_open(ap) 147193323Sed struct vop_open_args /* { 148193323Sed struct vnode *a_vp; 149193323Sed int a_mode; 150218893Sdim struct ucred *a_cred; 151193323Sed struct thread *a_td; 152193323Sed } */ *ap; 153193323Sed{ 154193323Sed struct vnode *vp = ap->a_vp; 155193323Sed struct smbnode *np = VTOSMB(vp); 156193323Sed struct smb_cred scred; 157193323Sed struct vattr vattr; 158193323Sed int mode = ap->a_mode; 159193323Sed int error, accmode; 160193323Sed 161193323Sed SMBVDEBUG("%s,%d\n", np->n_name, (np->n_flag & NOPEN) != 0); 162193323Sed if (vp->v_type != VREG && vp->v_type != VDIR) { 163193323Sed SMBFSERR("open eacces vtype=%d\n", vp->v_type); 164193323Sed return EACCES; 165193323Sed } 166193323Sed if (vp->v_type == VDIR) { 167193323Sed np->n_flag |= NOPEN; 168193323Sed return 0; 169193323Sed } 170193323Sed if (np->n_flag & NMODIFIED) { 171193323Sed if ((error = smbfs_vinvalbuf(vp, ap->a_td)) == EINTR) 172193323Sed return error; 173193323Sed smbfs_attr_cacheremove(vp); 174193323Sed error = VOP_GETATTR(vp, &vattr, ap->a_cred); 175193323Sed if (error) 176193323Sed return error; 177193323Sed np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 178193323Sed } else { 179193323Sed error = VOP_GETATTR(vp, &vattr, ap->a_cred); 180193323Sed if (error) 181193323Sed return error; 182193323Sed if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) { 183193323Sed error = smbfs_vinvalbuf(vp, ap->a_td); 184193323Sed if (error == EINTR) 185193323Sed return error; 186193323Sed np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 187193323Sed } 188193323Sed } 189193323Sed if ((np->n_flag & NOPEN) != 0) 190193323Sed return 0; 191193323Sed /* 192193323Sed * Use DENYNONE to give unixy semantics of permitting 193193323Sed * everything not forbidden by permissions. Ie denial 194193323Sed * is up to server with clients/openers needing to use 195193323Sed * advisory locks for further control. 196193323Sed */ 197193323Sed accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 198193323Sed if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 199218893Sdim accmode = SMB_SM_DENYNONE|SMB_AM_OPENRW; 200206083Srdivacky smb_makescred(&scred, ap->a_td, ap->a_cred); 201206083Srdivacky error = smbfs_smb_open(np, accmode, &scred); 202206083Srdivacky if (error) { 203206083Srdivacky if (mode & FWRITE) 204206083Srdivacky return EACCES; 205206083Srdivacky else if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 206193323Sed accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 207218893Sdim error = smbfs_smb_open(np, accmode, &scred); 208193323Sed } 209193323Sed } 210193323Sed if (error == 0) { 211193323Sed np->n_flag |= NOPEN; 212193323Sed vnode_create_vobject(ap->a_vp, vattr.va_size, ap->a_td); 213193323Sed } 214193323Sed smbfs_attr_cacheremove(vp); 215193323Sed return error; 216193323Sed} 217193323Sed 218193323Sedstatic int 219193323Sedsmbfs_close(ap) 220193323Sed struct vop_close_args /* { 221193323Sed struct vnodeop_desc *a_desc; 222193323Sed struct vnode *a_vp; 223193323Sed int a_fflag; 224193323Sed struct ucred *a_cred; 225193323Sed struct thread *a_td; 226193323Sed } */ *ap; 227193323Sed{ 228193323Sed struct vnode *vp = ap->a_vp; 229193323Sed struct thread *td = ap->a_td; 230193323Sed struct smbnode *np = VTOSMB(vp); 231193323Sed struct smb_cred scred; 232234353Sdim 233193323Sed if (vp->v_type == VDIR && (np->n_flag & NOPEN) != 0 && 234234353Sdim np->n_dirseq != NULL) { 235193323Sed smb_makescred(&scred, td, ap->a_cred); 236193323Sed smbfs_findclose(np->n_dirseq, &scred); 237193323Sed np->n_dirseq = NULL; 238218893Sdim } 239212904Sdim return 0; 240212904Sdim} 241212904Sdim 242234982Sdim/* 243193323Sed * smbfs_getattr call from vfs. 244193323Sed */ 245193323Sedstatic int 246218893Sdimsmbfs_getattr(ap) 247193323Sed struct vop_getattr_args /* { 248193323Sed struct vnode *a_vp; 249193323Sed struct vattr *a_vap; 250193323Sed struct ucred *a_cred; 251218893Sdim } */ *ap; 252193323Sed{ 253193323Sed struct vnode *vp = ap->a_vp; 254193323Sed struct smbnode *np = VTOSMB(vp); 255218893Sdim struct vattr *va=ap->a_vap; 256218893Sdim struct smbfattr fattr; 257218893Sdim struct smb_cred scred; 258218893Sdim u_quad_t oldsize; 259193323Sed int error; 260193323Sed 261193323Sed SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_vflag & VV_ROOT) != 0); 262193323Sed error = smbfs_attr_cachelookup(vp, va); 263193323Sed if (!error) 264193323Sed return 0; 265193323Sed SMBVDEBUG("not in the cache\n"); 266193323Sed smb_makescred(&scred, curthread, ap->a_cred); 267193323Sed oldsize = np->n_size; 268193323Sed error = smbfs_smb_lookup(np, NULL, 0, &fattr, &scred); 269193323Sed if (error) { 270193323Sed SMBVDEBUG("error %d\n", error); 271193323Sed return error; 272193323Sed } 273193323Sed smbfs_attr_cacheenter(vp, &fattr); 274193323Sed smbfs_attr_cachelookup(vp, va); 275193323Sed if (np->n_flag & NOPEN) 276193323Sed np->n_size = oldsize; 277193323Sed return 0; 278193323Sed} 279193323Sed 280193323Sedstatic int 281199481Srdivackysmbfs_setattr(ap) 282198090Srdivacky struct vop_setattr_args /* { 283193323Sed struct vnode *a_vp; 284234353Sdim struct vattr *a_vap; 285193323Sed struct ucred *a_cred; 286193323Sed } */ *ap; 287199481Srdivacky{ 288198090Srdivacky struct vnode *vp = ap->a_vp; 289193323Sed struct smbnode *np = VTOSMB(vp); 290234353Sdim struct vattr *vap = ap->a_vap; 291193323Sed struct timespec *mtime, *atime; 292193323Sed struct smb_cred scred; 293193323Sed struct smb_share *ssp = np->n_mount->sm_share; 294193323Sed struct smb_vc *vcp = SSTOVC(ssp); 295199481Srdivacky struct thread *td = curthread; 296193323Sed u_quad_t tsize = 0; 297193323Sed int isreadonly, doclose, error = 0; 298193323Sed int old_n_dosattr; 299193323Sed 300193323Sed SMBVDEBUG("\n"); 301193323Sed if (vap->va_flags != VNOVAL) 302224145Sdim return EOPNOTSUPP; 303198090Srdivacky isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 304193323Sed /* 305193323Sed * Disallow write attempts if the filesystem is mounted read-only. 306199481Srdivacky */ 307198090Srdivacky if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 308193323Sed vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 309193323Sed vap->va_mode != (mode_t)VNOVAL) && isreadonly) 310193323Sed return EROFS; 311193323Sed smb_makescred(&scred, td, ap->a_cred); 312193323Sed if (vap->va_size != VNOVAL) { 313193323Sed switch (vp->v_type) { 314198090Srdivacky case VDIR: 315234353Sdim return EISDIR; 316234353Sdim case VREG: 317193323Sed break; 318193323Sed default: 319234353Sdim return EINVAL; 320193323Sed }; 321234353Sdim if (isreadonly) 322193323Sed return EROFS; 323221345Sdim doclose = 0; 324193323Sed vnode_pager_setsize(vp, (u_long)vap->va_size); 325221345Sdim tsize = np->n_size; 326193323Sed np->n_size = vap->va_size; 327193323Sed if ((np->n_flag & NOPEN) == 0) { 328193323Sed error = smbfs_smb_open(np, 329193323Sed SMB_SM_DENYNONE|SMB_AM_OPENRW, 330193323Sed &scred); 331193323Sed if (error == 0) 332193323Sed doclose = 1; 333193323Sed } 334193323Sed if (error == 0) 335234353Sdim error = smbfs_smb_setfsize(np, vap->va_size, &scred); 336234353Sdim if (doclose) 337234353Sdim smbfs_smb_close(ssp, np->n_fid, NULL, &scred); 338234353Sdim if (error) { 339234353Sdim np->n_size = tsize; 340193323Sed vnode_pager_setsize(vp, (u_long)tsize); 341193323Sed return error; 342193323Sed } 343193323Sed } 344221345Sdim if (vap->va_mode != (mode_t)VNOVAL) { 345193323Sed old_n_dosattr = np->n_dosattr; 346193323Sed if (vap->va_mode & S_IWUSR) 347193323Sed np->n_dosattr &= ~SMB_FA_RDONLY; 348193323Sed else 349193323Sed np->n_dosattr |= SMB_FA_RDONLY; 350193323Sed if (np->n_dosattr != old_n_dosattr) { 351224145Sdim error = smbfs_smb_setpattr(np, np->n_dosattr, NULL, &scred); 352198090Srdivacky if (error) 353234353Sdim return error; 354234353Sdim } 355234353Sdim } 356193323Sed mtime = atime = NULL; 357198090Srdivacky if (vap->va_mtime.tv_sec != VNOVAL) 358198090Srdivacky mtime = &vap->va_mtime; 359193323Sed if (vap->va_atime.tv_sec != VNOVAL) 360234353Sdim atime = &vap->va_atime; 361193323Sed if (mtime != atime) { 362193323Sed if (vap->va_vaflags & VA_UTIMES_NULL) { 363221345Sdim error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); 364193323Sed if (error) 365193323Sed error = VOP_ACCESS(vp, VWRITE, ap->a_cred, td); 366193323Sed } else 367234353Sdim error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); 368193323Sed#if 0 369221345Sdim if (mtime == NULL) 370193323Sed mtime = &np->n_mtime; 371193323Sed if (atime == NULL) 372193323Sed atime = &np->n_atime; 373224145Sdim#endif 374198090Srdivacky /* 375198090Srdivacky * If file is opened, then we can use handle based calls. 376198090Srdivacky * If not, use path based ones. 377193323Sed */ 378193323Sed if ((np->n_flag & NOPEN) == 0) { 379193323Sed if (vcp->vc_flags & SMBV_WIN95) { 380193323Sed error = VOP_OPEN(vp, FWRITE, ap->a_cred, td, 381193323Sed NULL); 382193323Sed if (!error) { 383193323Sed/* error = smbfs_smb_setfattrNT(np, 0, 384193323Sed mtime, atime, &scred); 385193323Sed VOP_GETATTR(vp, &vattr, ap->a_cred); */ 386193323Sed if (mtime) 387193323Sed np->n_mtime = *mtime; 388193323Sed VOP_CLOSE(vp, FWRITE, ap->a_cred, td); 389199481Srdivacky } 390193323Sed } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 391193323Sed error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 392193323Sed/* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred);*/ 393193323Sed } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 394193323Sed error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 395193323Sed } else { 396193323Sed error = smbfs_smb_setpattr(np, 0, mtime, &scred); 397193323Sed } 398193323Sed } else { 399193323Sed if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 400193323Sed error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 401193323Sed } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 402193323Sed error = smbfs_smb_setftime(np, mtime, atime, &scred); 403193323Sed } else { 404193323Sed /* 405193323Sed * I have no idea how to handle this for core 406234353Sdim * level servers. The possible solution is to 407193323Sed * update mtime after file is closed. 408193323Sed */ 409193323Sed SMBERROR("can't update times on an opened file\n"); 410234353Sdim } 411193323Sed } 412193323Sed } 413193323Sed /* 414193323Sed * Invalidate attribute cache in case if server doesn't set 415193323Sed * required attributes. 416193323Sed */ 417234353Sdim smbfs_attr_cacheremove(vp); /* invalidate cache */ 418193323Sed VOP_GETATTR(vp, vap, ap->a_cred); 419193323Sed np->n_mtime.tv_sec = vap->va_mtime.tv_sec; 420234353Sdim return error; 421193323Sed} 422193323Sed/* 423193323Sed * smbfs_read call. 424193323Sed */ 425193323Sedstatic int 426193323Sedsmbfs_read(ap) 427193323Sed struct vop_read_args /* { 428193323Sed struct vnode *a_vp; 429193323Sed struct uio *a_uio; 430193323Sed int a_ioflag; 431193323Sed struct ucred *a_cred; 432193323Sed } */ *ap; 433193323Sed{ 434193323Sed struct vnode *vp = ap->a_vp; 435193323Sed struct uio *uio = ap->a_uio; 436193323Sed 437193323Sed SMBVDEBUG("\n"); 438193323Sed if (vp->v_type != VREG && vp->v_type != VDIR) 439193323Sed return EPERM; 440193323Sed return smbfs_readvnode(vp, uio, ap->a_cred); 441234353Sdim} 442193323Sed 443193323Sedstatic int 444193323Sedsmbfs_write(ap) 445193323Sed struct vop_write_args /* { 446193323Sed struct vnode *a_vp; 447193323Sed struct uio *a_uio; 448193323Sed int a_ioflag; 449234353Sdim struct ucred *a_cred; 450193323Sed } */ *ap; 451193323Sed{ 452193323Sed struct vnode *vp = ap->a_vp; 453193323Sed struct uio *uio = ap->a_uio; 454234353Sdim 455193323Sed SMBVDEBUG("%d,ofs=%jd,sz=%zd\n",vp->v_type, (intmax_t)uio->uio_offset, 456193323Sed uio->uio_resid); 457234353Sdim if (vp->v_type != VREG) 458193323Sed return (EPERM); 459193323Sed return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); 460193323Sed} 461193323Sed/* 462193323Sed * smbfs_create call 463193323Sed * Create a regular file. On entry the directory to contain the file being 464 * created is locked. We must release before we return. We must also free 465 * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or 466 * only if the SAVESTART bit in cn_flags is clear on success. 467 */ 468static int 469smbfs_create(ap) 470 struct vop_create_args /* { 471 struct vnode *a_dvp; 472 struct vnode **a_vpp; 473 struct componentname *a_cnp; 474 struct vattr *a_vap; 475 } */ *ap; 476{ 477 struct vnode *dvp = ap->a_dvp; 478 struct vattr *vap = ap->a_vap; 479 struct vnode **vpp=ap->a_vpp; 480 struct componentname *cnp = ap->a_cnp; 481 struct smbnode *dnp = VTOSMB(dvp); 482 struct vnode *vp; 483 struct vattr vattr; 484 struct smbfattr fattr; 485 struct smb_cred scred; 486 char *name = cnp->cn_nameptr; 487 int nmlen = cnp->cn_namelen; 488 int error; 489 490 491 SMBVDEBUG("\n"); 492 *vpp = NULL; 493 if (vap->va_type != VREG) 494 return EOPNOTSUPP; 495 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 496 return error; 497 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 498 499 error = smbfs_smb_create(dnp, name, nmlen, &scred); 500 if (error) 501 return error; 502 error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred); 503 if (error) 504 return error; 505 error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); 506 if (error) 507 return error; 508 *vpp = vp; 509 if (cnp->cn_flags & MAKEENTRY) 510 cache_enter(dvp, vp, cnp); 511 return error; 512} 513 514static int 515smbfs_remove(ap) 516 struct vop_remove_args /* { 517 struct vnodeop_desc *a_desc; 518 struct vnode * a_dvp; 519 struct vnode * a_vp; 520 struct componentname * a_cnp; 521 } */ *ap; 522{ 523 struct vnode *vp = ap->a_vp; 524/* struct vnode *dvp = ap->a_dvp;*/ 525 struct componentname *cnp = ap->a_cnp; 526 struct smbnode *np = VTOSMB(vp); 527 struct smb_cred scred; 528 int error; 529 530 if (vp->v_type == VDIR || (np->n_flag & NOPEN) != 0 || vrefcnt(vp) != 1) 531 return EPERM; 532 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 533 error = smbfs_smb_delete(np, &scred); 534 if (error == 0) 535 np->n_flag |= NGONE; 536 cache_purge(vp); 537 return error; 538} 539 540/* 541 * smbfs_file rename call 542 */ 543static int 544smbfs_rename(ap) 545 struct vop_rename_args /* { 546 struct vnode *a_fdvp; 547 struct vnode *a_fvp; 548 struct componentname *a_fcnp; 549 struct vnode *a_tdvp; 550 struct vnode *a_tvp; 551 struct componentname *a_tcnp; 552 } */ *ap; 553{ 554 struct vnode *fvp = ap->a_fvp; 555 struct vnode *tvp = ap->a_tvp; 556 struct vnode *fdvp = ap->a_fdvp; 557 struct vnode *tdvp = ap->a_tdvp; 558 struct componentname *tcnp = ap->a_tcnp; 559/* struct componentname *fcnp = ap->a_fcnp;*/ 560 struct smb_cred scred; 561 u_int16_t flags = 6; 562 int error=0; 563 564 /* Check for cross-device rename */ 565 if ((fvp->v_mount != tdvp->v_mount) || 566 (tvp && (fvp->v_mount != tvp->v_mount))) { 567 error = EXDEV; 568 goto out; 569 } 570 571 if (tvp && vrefcnt(tvp) > 1) { 572 error = EBUSY; 573 goto out; 574 } 575 flags = 0x10; /* verify all writes */ 576 if (fvp->v_type == VDIR) { 577 flags |= 2; 578 } else if (fvp->v_type == VREG) { 579 flags |= 1; 580 } else { 581 error = EINVAL; 582 goto out; 583 } 584 smb_makescred(&scred, tcnp->cn_thread, tcnp->cn_cred); 585 /* 586 * It seems that Samba doesn't implement SMB_COM_MOVE call... 587 */ 588#ifdef notnow 589 if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { 590 error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), 591 tcnp->cn_nameptr, tcnp->cn_namelen, flags, &scred); 592 } else 593#endif 594 { 595 /* 596 * We have to do the work atomicaly 597 */ 598 if (tvp && tvp != fvp) { 599 error = smbfs_smb_delete(VTOSMB(tvp), &scred); 600 if (error) 601 goto out_cacherem; 602 VTOSMB(fvp)->n_flag |= NGONE; 603 } 604 error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), 605 tcnp->cn_nameptr, tcnp->cn_namelen, &scred); 606 } 607 608 if (fvp->v_type == VDIR) { 609 if (tvp != NULL && tvp->v_type == VDIR) 610 cache_purge(tdvp); 611 cache_purge(fdvp); 612 } 613 614out_cacherem: 615 smbfs_attr_cacheremove(fdvp); 616 smbfs_attr_cacheremove(tdvp); 617out: 618 if (tdvp == tvp) 619 vrele(tdvp); 620 else 621 vput(tdvp); 622 if (tvp) 623 vput(tvp); 624 vrele(fdvp); 625 vrele(fvp); 626#ifdef possible_mistake 627 vgone(fvp); 628 if (tvp) 629 vgone(tvp); 630#endif 631 return error; 632} 633 634/* 635 * somtime it will come true... 636 */ 637static int 638smbfs_link(ap) 639 struct vop_link_args /* { 640 struct vnode *a_tdvp; 641 struct vnode *a_vp; 642 struct componentname *a_cnp; 643 } */ *ap; 644{ 645 return EOPNOTSUPP; 646} 647 648/* 649 * smbfs_symlink link create call. 650 * Sometime it will be functional... 651 */ 652static int 653smbfs_symlink(ap) 654 struct vop_symlink_args /* { 655 struct vnode *a_dvp; 656 struct vnode **a_vpp; 657 struct componentname *a_cnp; 658 struct vattr *a_vap; 659 char *a_target; 660 } */ *ap; 661{ 662 return EOPNOTSUPP; 663} 664 665static int 666smbfs_mknod(ap) 667 struct vop_mknod_args /* { 668 } */ *ap; 669{ 670 return EOPNOTSUPP; 671} 672 673static int 674smbfs_mkdir(ap) 675 struct vop_mkdir_args /* { 676 struct vnode *a_dvp; 677 struct vnode **a_vpp; 678 struct componentname *a_cnp; 679 struct vattr *a_vap; 680 } */ *ap; 681{ 682 struct vnode *dvp = ap->a_dvp; 683/* struct vattr *vap = ap->a_vap;*/ 684 struct vnode *vp; 685 struct componentname *cnp = ap->a_cnp; 686 struct smbnode *dnp = VTOSMB(dvp); 687 struct vattr vattr; 688 struct smb_cred scred; 689 struct smbfattr fattr; 690 char *name = cnp->cn_nameptr; 691 int len = cnp->cn_namelen; 692 int error; 693 694 if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) { 695 return error; 696 } 697 if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 698 return EEXIST; 699 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 700 error = smbfs_smb_mkdir(dnp, name, len, &scred); 701 if (error) 702 return error; 703 error = smbfs_smb_lookup(dnp, name, len, &fattr, &scred); 704 if (error) 705 return error; 706 error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); 707 if (error) 708 return error; 709 *ap->a_vpp = vp; 710 return 0; 711} 712 713/* 714 * smbfs_remove directory call 715 */ 716static int 717smbfs_rmdir(ap) 718 struct vop_rmdir_args /* { 719 struct vnode *a_dvp; 720 struct vnode *a_vp; 721 struct componentname *a_cnp; 722 } */ *ap; 723{ 724 struct vnode *vp = ap->a_vp; 725 struct vnode *dvp = ap->a_dvp; 726 struct componentname *cnp = ap->a_cnp; 727/* struct smbmount *smp = VTOSMBFS(vp);*/ 728 struct smbnode *dnp = VTOSMB(dvp); 729 struct smbnode *np = VTOSMB(vp); 730 struct smb_cred scred; 731 int error; 732 733 if (dvp == vp) 734 return EINVAL; 735 736 smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 737 error = smbfs_smb_rmdir(np, &scred); 738 if (error == 0) 739 np->n_flag |= NGONE; 740 dnp->n_flag |= NMODIFIED; 741 smbfs_attr_cacheremove(dvp); 742/* cache_purge(dvp);*/ 743 cache_purge(vp); 744 return error; 745} 746 747/* 748 * smbfs_readdir call 749 */ 750static int 751smbfs_readdir(ap) 752 struct vop_readdir_args /* { 753 struct vnode *a_vp; 754 struct uio *a_uio; 755 struct ucred *a_cred; 756 int *a_eofflag; 757 u_long *a_cookies; 758 int a_ncookies; 759 } */ *ap; 760{ 761 struct vnode *vp = ap->a_vp; 762 struct uio *uio = ap->a_uio; 763 int error; 764 765 if (vp->v_type != VDIR) 766 return (EPERM); 767#ifdef notnow 768 if (ap->a_ncookies) { 769 printf("smbfs_readdir: no support for cookies now..."); 770 return (EOPNOTSUPP); 771 } 772#endif 773 error = smbfs_readvnode(vp, uio, ap->a_cred); 774 return error; 775} 776 777/* ARGSUSED */ 778static int 779smbfs_fsync(ap) 780 struct vop_fsync_args /* { 781 struct vnodeop_desc *a_desc; 782 struct vnode * a_vp; 783 struct ucred * a_cred; 784 int a_waitfor; 785 struct thread * a_td; 786 } */ *ap; 787{ 788/* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ 789 return (0); 790} 791 792static 793int smbfs_print (ap) 794 struct vop_print_args /* { 795 struct vnode *a_vp; 796 } */ *ap; 797{ 798 struct vnode *vp = ap->a_vp; 799 struct smbnode *np = VTOSMB(vp); 800 801 if (np == NULL) { 802 printf("no smbnode data\n"); 803 return (0); 804 } 805 printf("\tname = %s, parent = %p, open = %d\n", np->n_name, 806 np->n_parent ? np->n_parent : NULL, (np->n_flag & NOPEN) != 0); 807 return (0); 808} 809 810static int 811smbfs_pathconf (ap) 812 struct vop_pathconf_args /* { 813 struct vnode *vp; 814 int name; 815 register_t *retval; 816 } */ *ap; 817{ 818 struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 819 struct smb_vc *vcp = SSTOVC(smp->sm_share); 820 register_t *retval = ap->a_retval; 821 int error = 0; 822 823 switch (ap->a_name) { 824 case _PC_LINK_MAX: 825 *retval = 0; 826 break; 827 case _PC_NAME_MAX: 828 *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 829 break; 830 case _PC_PATH_MAX: 831 *retval = 800; /* XXX: a correct one ? */ 832 break; 833 default: 834 error = EINVAL; 835 } 836 return error; 837} 838 839static int 840smbfs_strategy (ap) 841 struct vop_strategy_args /* { 842 struct buf *a_bp 843 } */ *ap; 844{ 845 struct buf *bp=ap->a_bp; 846 struct ucred *cr; 847 struct thread *td; 848 849 SMBVDEBUG("\n"); 850 if (bp->b_flags & B_ASYNC) 851 td = (struct thread *)0; 852 else 853 td = curthread; /* XXX */ 854 if (bp->b_iocmd == BIO_READ) 855 cr = bp->b_rcred; 856 else 857 cr = bp->b_wcred; 858 859 if ((bp->b_flags & B_ASYNC) == 0 ) 860 (void)smbfs_doio(ap->a_vp, bp, cr, td); 861 return (0); 862} 863 864int 865smbfs_ioctl(ap) 866 struct vop_ioctl_args /* { 867 struct vnode *a_vp; 868 u_long a_command; 869 caddr_t a_data; 870 int fflag; 871 struct ucred *cred; 872 struct thread *td; 873 } */ *ap; 874{ 875 return ENOTTY; 876} 877 878static char smbfs_atl[] = "rhsvda"; 879static int 880smbfs_getextattr(struct vop_getextattr_args *ap) 881/* { 882 IN struct vnode *a_vp; 883 IN char *a_name; 884 INOUT struct uio *a_uio; 885 IN struct ucred *a_cred; 886 IN struct thread *a_td; 887}; 888*/ 889{ 890 struct vnode *vp = ap->a_vp; 891 struct thread *td = ap->a_td; 892 struct ucred *cred = ap->a_cred; 893 struct uio *uio = ap->a_uio; 894 const char *name = ap->a_name; 895 struct smbnode *np = VTOSMB(vp); 896 struct vattr vattr; 897 char buf[10]; 898 int i, attr, error; 899 900 error = VOP_ACCESS(vp, VREAD, cred, td); 901 if (error) 902 return error; 903 error = VOP_GETATTR(vp, &vattr, cred); 904 if (error) 905 return error; 906 if (strcmp(name, "dosattr") == 0) { 907 attr = np->n_dosattr; 908 for (i = 0; i < 6; i++, attr >>= 1) 909 buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 910 buf[i] = 0; 911 error = uiomove(buf, i, uio); 912 913 } else 914 error = EINVAL; 915 return error; 916} 917 918/* 919 * Since we expected to support F_GETLK (and SMB protocol has no such function), 920 * it is necessary to use lf_advlock(). It would be nice if this function had 921 * a callback mechanism because it will help to improve a level of consistency. 922 */ 923int 924smbfs_advlock(ap) 925 struct vop_advlock_args /* { 926 struct vnode *a_vp; 927 caddr_t a_id; 928 int a_op; 929 struct flock *a_fl; 930 int a_flags; 931 } */ *ap; 932{ 933 struct vnode *vp = ap->a_vp; 934 struct smbnode *np = VTOSMB(vp); 935 struct flock *fl = ap->a_fl; 936 caddr_t id = (caddr_t)1 /* ap->a_id */; 937/* int flags = ap->a_flags;*/ 938 struct thread *td = curthread; 939 struct smb_cred scred; 940 u_quad_t size; 941 off_t start, end, oadd; 942 int error, lkop; 943 944 if (vp->v_type == VDIR) { 945 /* 946 * SMB protocol have no support for directory locking. 947 * Although locks can be processed on local machine, I don't 948 * think that this is a good idea, because some programs 949 * can work wrong assuming directory is locked. So, we just 950 * return 'operation not supported 951 */ 952 return EOPNOTSUPP; 953 } 954 size = np->n_size; 955 switch (fl->l_whence) { 956 957 case SEEK_SET: 958 case SEEK_CUR: 959 start = fl->l_start; 960 break; 961 962 case SEEK_END: 963 if (size > OFF_MAX || 964 (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 965 return EOVERFLOW; 966 start = size + fl->l_start; 967 break; 968 969 default: 970 return EINVAL; 971 } 972 if (start < 0) 973 return EINVAL; 974 if (fl->l_len < 0) { 975 if (start == 0) 976 return EINVAL; 977 end = start - 1; 978 start += fl->l_len; 979 if (start < 0) 980 return EINVAL; 981 } else if (fl->l_len == 0) 982 end = -1; 983 else { 984 oadd = fl->l_len - 1; 985 if (oadd > OFF_MAX - start) 986 return EOVERFLOW; 987 end = start + oadd; 988 } 989 smb_makescred(&scred, td, td->td_ucred); 990 switch (ap->a_op) { 991 case F_SETLK: 992 switch (fl->l_type) { 993 case F_WRLCK: 994 lkop = SMB_LOCK_EXCL; 995 break; 996 case F_RDLCK: 997 lkop = SMB_LOCK_SHARED; 998 break; 999 case F_UNLCK: 1000 lkop = SMB_LOCK_RELEASE; 1001 break; 1002 default: 1003 return EINVAL; 1004 } 1005 error = lf_advlock(ap, &vp->v_lockf, size); 1006 if (error) 1007 break; 1008 lkop = SMB_LOCK_EXCL; 1009 error = smbfs_smb_lock(np, lkop, id, start, end, &scred); 1010 if (error) { 1011 int oldtype = fl->l_type; 1012 fl->l_type = F_UNLCK; 1013 ap->a_op = F_UNLCK; 1014 lf_advlock(ap, &vp->v_lockf, size); 1015 fl->l_type = oldtype; 1016 } 1017 break; 1018 case F_UNLCK: 1019 lf_advlock(ap, &vp->v_lockf, size); 1020 error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, &scred); 1021 break; 1022 case F_GETLK: 1023 error = lf_advlock(ap, &vp->v_lockf, size); 1024 break; 1025 default: 1026 return EINVAL; 1027 } 1028 return error; 1029} 1030 1031static int 1032smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) 1033{ 1034 static const char *badchars = "*/:<>;?"; 1035 static const char *badchars83 = " +|,[]="; 1036 const char *cp; 1037 int i, error; 1038 1039 /* 1040 * Backslash characters, being a path delimiter, are prohibited 1041 * within a path component even for LOOKUP operations. 1042 */ 1043 if (strchr(name, '\\') != NULL) 1044 return ENOENT; 1045 1046 if (nameiop == LOOKUP) 1047 return 0; 1048 error = ENOENT; 1049 if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { 1050 /* 1051 * Name should conform 8.3 format 1052 */ 1053 if (nmlen > 12) 1054 return ENAMETOOLONG; 1055 cp = strchr(name, '.'); 1056 if (cp == NULL) 1057 return error; 1058 if (cp == name || (cp - name) > 8) 1059 return error; 1060 cp = strchr(cp + 1, '.'); 1061 if (cp != NULL) 1062 return error; 1063 for (cp = name, i = 0; i < nmlen; i++, cp++) 1064 if (strchr(badchars83, *cp) != NULL) 1065 return error; 1066 } 1067 for (cp = name, i = 0; i < nmlen; i++, cp++) 1068 if (strchr(badchars, *cp) != NULL) 1069 return error; 1070 return 0; 1071} 1072 1073/* 1074 * Things go even weird without fixed inode numbers... 1075 */ 1076int 1077smbfs_lookup(ap) 1078 struct vop_lookup_args /* { 1079 struct vnodeop_desc *a_desc; 1080 struct vnode *a_dvp; 1081 struct vnode **a_vpp; 1082 struct componentname *a_cnp; 1083 } */ *ap; 1084{ 1085 struct componentname *cnp = ap->a_cnp; 1086 struct thread *td = cnp->cn_thread; 1087 struct vnode *dvp = ap->a_dvp; 1088 struct vnode **vpp = ap->a_vpp; 1089 struct vnode *vp; 1090 struct smbmount *smp; 1091 struct mount *mp = dvp->v_mount; 1092 struct smbnode *dnp; 1093 struct smbfattr fattr, *fap; 1094 struct smb_cred scred; 1095 char *name = cnp->cn_nameptr; 1096 int flags = cnp->cn_flags; 1097 int nameiop = cnp->cn_nameiop; 1098 int nmlen = cnp->cn_namelen; 1099 int error, islastcn, isdot; 1100 int killit; 1101 1102 SMBVDEBUG("\n"); 1103 if (dvp->v_type != VDIR) 1104 return ENOTDIR; 1105 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) { 1106 SMBFSERR("invalid '..'\n"); 1107 return EIO; 1108 } 1109#ifdef SMB_VNODE_DEBUG 1110 { 1111 char *cp, c; 1112 1113 cp = name + nmlen; 1114 c = *cp; 1115 *cp = 0; 1116 SMBVDEBUG("%d '%s' in '%s' id=d\n", nameiop, name, 1117 VTOSMB(dvp)->n_name); 1118 *cp = c; 1119 } 1120#endif 1121 islastcn = flags & ISLASTCN; 1122 if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) 1123 return EROFS; 1124 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) 1125 return error; 1126 smp = VFSTOSMBFS(mp); 1127 dnp = VTOSMB(dvp); 1128 isdot = (nmlen == 1 && name[0] == '.'); 1129 1130 error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop); 1131 1132 if (error) 1133 return ENOENT; 1134 1135 error = cache_lookup(dvp, vpp, cnp, NULL, NULL); 1136 SMBVDEBUG("cache_lookup returned %d\n", error); 1137 if (error > 0) 1138 return error; 1139 if (error) { /* name was found */ 1140 struct vattr vattr; 1141 1142 killit = 0; 1143 vp = *vpp; 1144 error = VOP_GETATTR(vp, &vattr, cnp->cn_cred); 1145 /* 1146 * If the file type on the server is inconsistent 1147 * with what it was when we created the vnode, 1148 * kill the bogus vnode now and fall through to 1149 * the code below to create a new one with the 1150 * right type. 1151 */ 1152 if (error == 0 && 1153 ((vp->v_type == VDIR && 1154 (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) == 0) || 1155 (vp->v_type == VREG && 1156 (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) != 0))) 1157 killit = 1; 1158 else if (error == 0 1159 /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { 1160 if (nameiop != LOOKUP && islastcn) 1161 cnp->cn_flags |= SAVENAME; 1162 SMBVDEBUG("use cached vnode\n"); 1163 return (0); 1164 } 1165 cache_purge(vp); 1166 /* 1167 * XXX This is not quite right, if '.' is 1168 * inconsistent, we really need to start the lookup 1169 * all over again. Hopefully there is some other 1170 * guarantee that prevents this case from happening. 1171 */ 1172 if (killit && vp != dvp) 1173 vgone(vp); 1174 if (vp != dvp) 1175 vput(vp); 1176 else 1177 vrele(vp); 1178 *vpp = NULLVP; 1179 } 1180 /* 1181 * entry is not in the cache or has been expired 1182 */ 1183 error = 0; 1184 *vpp = NULLVP; 1185 smb_makescred(&scred, td, cnp->cn_cred); 1186 fap = &fattr; 1187 if (flags & ISDOTDOT) { 1188 error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, 1189 &scred); 1190 SMBVDEBUG("result of dotdot lookup: %d\n", error); 1191 } else { 1192 fap = &fattr; 1193 error = smbfs_smb_lookup(dnp, name, nmlen, fap, &scred); 1194/* if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')*/ 1195 SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1196 } 1197 if (error && error != ENOENT) 1198 return error; 1199 if (error) { /* entry not found */ 1200 /* 1201 * Handle RENAME or CREATE case... 1202 */ 1203 if ((nameiop == CREATE || nameiop == RENAME) && islastcn) { 1204 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1205 if (error) 1206 return error; 1207 cnp->cn_flags |= SAVENAME; 1208 return (EJUSTRETURN); 1209 } 1210 return ENOENT; 1211 }/* else { 1212 SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 1213 }*/ 1214 /* 1215 * handle DELETE case ... 1216 */ 1217 if (nameiop == DELETE && islastcn) { /* delete last component */ 1218 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1219 if (error) 1220 return error; 1221 if (isdot) { 1222 VREF(dvp); 1223 *vpp = dvp; 1224 return 0; 1225 } 1226 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1227 if (error) 1228 return error; 1229 *vpp = vp; 1230 cnp->cn_flags |= SAVENAME; 1231 return 0; 1232 } 1233 if (nameiop == RENAME && islastcn) { 1234 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1235 if (error) 1236 return error; 1237 if (isdot) 1238 return EISDIR; 1239 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1240 if (error) 1241 return error; 1242 *vpp = vp; 1243 cnp->cn_flags |= SAVENAME; 1244 return 0; 1245 } 1246 if (flags & ISDOTDOT) { 1247 VOP_UNLOCK(dvp, 0); 1248 error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); 1249 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 1250 if (error) 1251 return error; 1252 *vpp = vp; 1253 } else if (isdot) { 1254 vref(dvp); 1255 *vpp = dvp; 1256 } else { 1257 error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1258 if (error) 1259 return error; 1260 *vpp = vp; 1261 SMBVDEBUG("lookup: getnewvp!\n"); 1262 } 1263 if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 1264/* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ 1265 cache_enter(dvp, *vpp, cnp); 1266 } 1267 return 0; 1268} 1269