1d167cf6fSWarner Losh /*- 2681a5bbeSBoris Popov * Copyright (c) 2000-2001 Boris Popov 3681a5bbeSBoris Popov * All rights reserved. 4681a5bbeSBoris Popov * 5681a5bbeSBoris Popov * Redistribution and use in source and binary forms, with or without 6681a5bbeSBoris Popov * modification, are permitted provided that the following conditions 7681a5bbeSBoris Popov * are met: 8681a5bbeSBoris Popov * 1. Redistributions of source code must retain the above copyright 9681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer. 10681a5bbeSBoris Popov * 2. Redistributions in binary form must reproduce the above copyright 11681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer in the 12681a5bbeSBoris Popov * documentation and/or other materials provided with the distribution. 13681a5bbeSBoris Popov * 3. All advertising materials mentioning features or use of this software 14681a5bbeSBoris Popov * must display the following acknowledgement: 15681a5bbeSBoris Popov * This product includes software developed by Boris Popov. 16681a5bbeSBoris Popov * 4. Neither the name of the author nor the names of any co-contributors 17681a5bbeSBoris Popov * may be used to endorse or promote products derived from this software 18681a5bbeSBoris Popov * without specific prior written permission. 19681a5bbeSBoris Popov * 20681a5bbeSBoris Popov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21681a5bbeSBoris Popov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22681a5bbeSBoris Popov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23681a5bbeSBoris Popov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24681a5bbeSBoris Popov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25681a5bbeSBoris Popov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26681a5bbeSBoris Popov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27681a5bbeSBoris Popov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28681a5bbeSBoris Popov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29681a5bbeSBoris Popov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30681a5bbeSBoris Popov * SUCH DAMAGE. 31681a5bbeSBoris Popov * 32681a5bbeSBoris Popov * $FreeBSD$ 33681a5bbeSBoris Popov */ 34681a5bbeSBoris Popov #include <sys/param.h> 35681a5bbeSBoris Popov #include <sys/systm.h> 36681a5bbeSBoris Popov #include <sys/namei.h> 37681a5bbeSBoris Popov #include <sys/kernel.h> 38681a5bbeSBoris Popov #include <sys/proc.h> 39681a5bbeSBoris Popov #include <sys/bio.h> 40681a5bbeSBoris Popov #include <sys/buf.h> 41681a5bbeSBoris Popov #include <sys/fcntl.h> 42681a5bbeSBoris Popov #include <sys/mount.h> 43681a5bbeSBoris Popov #include <sys/unistd.h> 44681a5bbeSBoris Popov #include <sys/vnode.h> 45104a9b7eSAlexander Kabaev #include <sys/limits.h> 46681a5bbeSBoris Popov #include <sys/lockf.h> 47681a5bbeSBoris Popov 48681a5bbeSBoris Popov #include <vm/vm.h> 49681a5bbeSBoris Popov #include <vm/vm_extern.h> 50681a5bbeSBoris Popov 51681a5bbeSBoris Popov 52681a5bbeSBoris Popov #include <netsmb/smb.h> 53681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 54681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 55681a5bbeSBoris Popov 56681a5bbeSBoris Popov #include <fs/smbfs/smbfs.h> 57681a5bbeSBoris Popov #include <fs/smbfs/smbfs_node.h> 58681a5bbeSBoris Popov #include <fs/smbfs/smbfs_subr.h> 59681a5bbeSBoris Popov 60681a5bbeSBoris Popov /* 61681a5bbeSBoris Popov * Prototypes for SMBFS vnode operations 62681a5bbeSBoris Popov */ 636fde64c7SPoul-Henning Kamp static vop_create_t smbfs_create; 646fde64c7SPoul-Henning Kamp static vop_mknod_t smbfs_mknod; 656fde64c7SPoul-Henning Kamp static vop_open_t smbfs_open; 666fde64c7SPoul-Henning Kamp static vop_close_t smbfs_close; 676fde64c7SPoul-Henning Kamp static vop_access_t smbfs_access; 686fde64c7SPoul-Henning Kamp static vop_getattr_t smbfs_getattr; 696fde64c7SPoul-Henning Kamp static vop_setattr_t smbfs_setattr; 706fde64c7SPoul-Henning Kamp static vop_read_t smbfs_read; 716fde64c7SPoul-Henning Kamp static vop_write_t smbfs_write; 726fde64c7SPoul-Henning Kamp static vop_fsync_t smbfs_fsync; 736fde64c7SPoul-Henning Kamp static vop_remove_t smbfs_remove; 746fde64c7SPoul-Henning Kamp static vop_link_t smbfs_link; 756fde64c7SPoul-Henning Kamp static vop_lookup_t smbfs_lookup; 766fde64c7SPoul-Henning Kamp static vop_rename_t smbfs_rename; 776fde64c7SPoul-Henning Kamp static vop_mkdir_t smbfs_mkdir; 786fde64c7SPoul-Henning Kamp static vop_rmdir_t smbfs_rmdir; 796fde64c7SPoul-Henning Kamp static vop_symlink_t smbfs_symlink; 806fde64c7SPoul-Henning Kamp static vop_readdir_t smbfs_readdir; 816fde64c7SPoul-Henning Kamp static vop_strategy_t smbfs_strategy; 826fde64c7SPoul-Henning Kamp static vop_print_t smbfs_print; 836fde64c7SPoul-Henning Kamp static vop_pathconf_t smbfs_pathconf; 846fde64c7SPoul-Henning Kamp static vop_advlock_t smbfs_advlock; 856fde64c7SPoul-Henning Kamp static vop_getextattr_t smbfs_getextattr; 86681a5bbeSBoris Popov 87aec0fb7bSPoul-Henning Kamp struct vop_vector smbfs_vnodeops = { 88aec0fb7bSPoul-Henning Kamp .vop_default = &default_vnodeops, 8983c64397SPoul-Henning Kamp 90aec0fb7bSPoul-Henning Kamp .vop_access = smbfs_access, 91aec0fb7bSPoul-Henning Kamp .vop_advlock = smbfs_advlock, 92aec0fb7bSPoul-Henning Kamp .vop_close = smbfs_close, 93aec0fb7bSPoul-Henning Kamp .vop_create = smbfs_create, 94aec0fb7bSPoul-Henning Kamp .vop_fsync = smbfs_fsync, 95aec0fb7bSPoul-Henning Kamp .vop_getattr = smbfs_getattr, 9683c64397SPoul-Henning Kamp .vop_getextattr = smbfs_getextattr, 97aec0fb7bSPoul-Henning Kamp .vop_getpages = smbfs_getpages, 98aec0fb7bSPoul-Henning Kamp .vop_inactive = smbfs_inactive, 99aec0fb7bSPoul-Henning Kamp .vop_ioctl = smbfs_ioctl, 100aec0fb7bSPoul-Henning Kamp .vop_link = smbfs_link, 101aec0fb7bSPoul-Henning Kamp .vop_lookup = smbfs_lookup, 102aec0fb7bSPoul-Henning Kamp .vop_mkdir = smbfs_mkdir, 103aec0fb7bSPoul-Henning Kamp .vop_mknod = smbfs_mknod, 104aec0fb7bSPoul-Henning Kamp .vop_open = smbfs_open, 105aec0fb7bSPoul-Henning Kamp .vop_pathconf = smbfs_pathconf, 106aec0fb7bSPoul-Henning Kamp .vop_print = smbfs_print, 107aec0fb7bSPoul-Henning Kamp .vop_putpages = smbfs_putpages, 108aec0fb7bSPoul-Henning Kamp .vop_read = smbfs_read, 109aec0fb7bSPoul-Henning Kamp .vop_readdir = smbfs_readdir, 110aec0fb7bSPoul-Henning Kamp .vop_reclaim = smbfs_reclaim, 111aec0fb7bSPoul-Henning Kamp .vop_remove = smbfs_remove, 112aec0fb7bSPoul-Henning Kamp .vop_rename = smbfs_rename, 113aec0fb7bSPoul-Henning Kamp .vop_rmdir = smbfs_rmdir, 114aec0fb7bSPoul-Henning Kamp .vop_setattr = smbfs_setattr, 11583c64397SPoul-Henning Kamp /* .vop_setextattr = smbfs_setextattr,*/ 116aec0fb7bSPoul-Henning Kamp .vop_strategy = smbfs_strategy, 117aec0fb7bSPoul-Henning Kamp .vop_symlink = smbfs_symlink, 118aec0fb7bSPoul-Henning Kamp .vop_write = smbfs_write, 119681a5bbeSBoris Popov }; 120681a5bbeSBoris Popov 121681a5bbeSBoris Popov static int 122681a5bbeSBoris Popov smbfs_access(ap) 123681a5bbeSBoris Popov struct vop_access_args /* { 124681a5bbeSBoris Popov struct vnode *a_vp; 125681a5bbeSBoris Popov int a_mode; 126681a5bbeSBoris Popov struct ucred *a_cred; 127b1c996c4SBoris Popov struct thread *a_td; 128681a5bbeSBoris Popov } */ *ap; 129681a5bbeSBoris Popov { 130681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 13138356d10STim J. Robbins mode_t mode = ap->a_mode; 13238356d10STim J. Robbins mode_t mpmode; 133681a5bbeSBoris Popov struct smbmount *smp = VTOSMBFS(vp); 134681a5bbeSBoris Popov 135681a5bbeSBoris Popov SMBVDEBUG("\n"); 136681a5bbeSBoris Popov if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 137681a5bbeSBoris Popov switch (vp->v_type) { 138681a5bbeSBoris Popov case VREG: case VDIR: case VLNK: 139681a5bbeSBoris Popov return EROFS; 140681a5bbeSBoris Popov default: 141681a5bbeSBoris Popov break; 142681a5bbeSBoris Popov } 143681a5bbeSBoris Popov } 144d14c8441SPoul-Henning Kamp mpmode = vp->v_type == VREG ? smp->sm_file_mode : smp->sm_dir_mode; 145d14c8441SPoul-Henning Kamp return (vaccess(vp->v_type, mpmode, smp->sm_uid, 146d14c8441SPoul-Henning Kamp smp->sm_gid, ap->a_mode, ap->a_cred, NULL)); 147681a5bbeSBoris Popov } 148681a5bbeSBoris Popov 149681a5bbeSBoris Popov /* ARGSUSED */ 150681a5bbeSBoris Popov static int 151681a5bbeSBoris Popov smbfs_open(ap) 152681a5bbeSBoris Popov struct vop_open_args /* { 153681a5bbeSBoris Popov struct vnode *a_vp; 154681a5bbeSBoris Popov int a_mode; 155681a5bbeSBoris Popov struct ucred *a_cred; 156b1c996c4SBoris Popov struct thread *a_td; 157681a5bbeSBoris Popov } */ *ap; 158681a5bbeSBoris Popov { 159681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 160681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 161681a5bbeSBoris Popov struct smb_cred scred; 162681a5bbeSBoris Popov struct vattr vattr; 163681a5bbeSBoris Popov int mode = ap->a_mode; 164681a5bbeSBoris Popov int error, accmode; 165681a5bbeSBoris Popov 1662a4ad258STim J. Robbins SMBVDEBUG("%s,%d\n", np->n_name, (np->n_flag & NOPEN) != 0); 167681a5bbeSBoris Popov if (vp->v_type != VREG && vp->v_type != VDIR) { 168681a5bbeSBoris Popov SMBFSERR("open eacces vtype=%d\n", vp->v_type); 169681a5bbeSBoris Popov return EACCES; 170681a5bbeSBoris Popov } 171681a5bbeSBoris Popov if (vp->v_type == VDIR) { 1722a4ad258STim J. Robbins np->n_flag |= NOPEN; 173681a5bbeSBoris Popov return 0; 174681a5bbeSBoris Popov } 175681a5bbeSBoris Popov if (np->n_flag & NMODIFIED) { 176e50508dfSPoul-Henning Kamp if ((error = smbfs_vinvalbuf(vp, ap->a_td)) == EINTR) 177681a5bbeSBoris Popov return error; 178681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); 179b1c996c4SBoris Popov error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td); 180681a5bbeSBoris Popov if (error) 181681a5bbeSBoris Popov return error; 182681a5bbeSBoris Popov np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 183681a5bbeSBoris Popov } else { 184b1c996c4SBoris Popov error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td); 185681a5bbeSBoris Popov if (error) 186681a5bbeSBoris Popov return error; 187681a5bbeSBoris Popov if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) { 188e50508dfSPoul-Henning Kamp error = smbfs_vinvalbuf(vp, ap->a_td); 189681a5bbeSBoris Popov if (error == EINTR) 190681a5bbeSBoris Popov return error; 191681a5bbeSBoris Popov np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 192681a5bbeSBoris Popov } 193681a5bbeSBoris Popov } 1942a4ad258STim J. Robbins if ((np->n_flag & NOPEN) != 0) 195681a5bbeSBoris Popov return 0; 19644f3878eSBoris Popov /* 19744f3878eSBoris Popov * Use DENYNONE to give unixy semantics of permitting 19844f3878eSBoris Popov * everything not forbidden by permissions. Ie denial 19944f3878eSBoris Popov * is up to server with clients/openers needing to use 20044f3878eSBoris Popov * advisory locks for further control. 20144f3878eSBoris Popov */ 20244f3878eSBoris Popov accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 203681a5bbeSBoris Popov if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 20444f3878eSBoris Popov accmode = SMB_SM_DENYNONE|SMB_AM_OPENRW; 205b1c996c4SBoris Popov smb_makescred(&scred, ap->a_td, ap->a_cred); 206681a5bbeSBoris Popov error = smbfs_smb_open(np, accmode, &scred); 207681a5bbeSBoris Popov if (error) { 208681a5bbeSBoris Popov if (mode & FWRITE) 209681a5bbeSBoris Popov return EACCES; 21044f3878eSBoris Popov else if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 21144f3878eSBoris Popov accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 212681a5bbeSBoris Popov error = smbfs_smb_open(np, accmode, &scred); 213681a5bbeSBoris Popov } 21444f3878eSBoris Popov } 21572b3e305SPeter Edwards if (error == 0) { 2162a4ad258STim J. Robbins np->n_flag |= NOPEN; 21772b3e305SPeter Edwards vnode_create_vobject(ap->a_vp, vattr.va_size, ap->a_td); 21872b3e305SPeter Edwards } 219681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); 220681a5bbeSBoris Popov return error; 221681a5bbeSBoris Popov } 222681a5bbeSBoris Popov 223681a5bbeSBoris Popov static int 224681a5bbeSBoris Popov smbfs_close(ap) 225681a5bbeSBoris Popov struct vop_close_args /* { 226681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 227681a5bbeSBoris Popov struct vnode *a_vp; 228681a5bbeSBoris Popov int a_fflag; 229681a5bbeSBoris Popov struct ucred *a_cred; 230b1c996c4SBoris Popov struct thread *a_td; 231681a5bbeSBoris Popov } */ *ap; 232681a5bbeSBoris Popov { 233681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 234b1c996c4SBoris Popov struct thread *td = ap->a_td; 235835fb616STim J. Robbins struct smbnode *np = VTOSMB(vp); 236835fb616STim J. Robbins struct smb_cred scred; 237681a5bbeSBoris Popov 238835fb616STim J. Robbins if (vp->v_type == VDIR && (np->n_flag & NOPEN) != 0 && 239835fb616STim J. Robbins np->n_dirseq != NULL) { 240835fb616STim J. Robbins smb_makescred(&scred, td, ap->a_cred); 241835fb616STim J. Robbins smbfs_findclose(np->n_dirseq, &scred); 242835fb616STim J. Robbins np->n_dirseq = NULL; 243835fb616STim J. Robbins } 2442a4ad258STim J. Robbins return 0; 245681a5bbeSBoris Popov } 246681a5bbeSBoris Popov 247681a5bbeSBoris Popov /* 248681a5bbeSBoris Popov * smbfs_getattr call from vfs. 249681a5bbeSBoris Popov */ 250681a5bbeSBoris Popov static int 251681a5bbeSBoris Popov smbfs_getattr(ap) 252681a5bbeSBoris Popov struct vop_getattr_args /* { 253681a5bbeSBoris Popov struct vnode *a_vp; 254681a5bbeSBoris Popov struct vattr *a_vap; 255681a5bbeSBoris Popov struct ucred *a_cred; 256b1c996c4SBoris Popov struct thread *a_td; 257681a5bbeSBoris Popov } */ *ap; 258681a5bbeSBoris Popov { 259681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 260681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 261681a5bbeSBoris Popov struct vattr *va=ap->a_vap; 262681a5bbeSBoris Popov struct smbfattr fattr; 263681a5bbeSBoris Popov struct smb_cred scred; 26407a65634STim J. Robbins u_quad_t oldsize; 265681a5bbeSBoris Popov int error; 266681a5bbeSBoris Popov 267e6e370a7SJeff Roberson SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_vflag & VV_ROOT) != 0); 268681a5bbeSBoris Popov error = smbfs_attr_cachelookup(vp, va); 269681a5bbeSBoris Popov if (!error) 270681a5bbeSBoris Popov return 0; 271681a5bbeSBoris Popov SMBVDEBUG("not in the cache\n"); 272b1c996c4SBoris Popov smb_makescred(&scred, ap->a_td, ap->a_cred); 273681a5bbeSBoris Popov oldsize = np->n_size; 274681a5bbeSBoris Popov error = smbfs_smb_lookup(np, NULL, 0, &fattr, &scred); 275681a5bbeSBoris Popov if (error) { 276681a5bbeSBoris Popov SMBVDEBUG("error %d\n", error); 277681a5bbeSBoris Popov return error; 278681a5bbeSBoris Popov } 279681a5bbeSBoris Popov smbfs_attr_cacheenter(vp, &fattr); 280681a5bbeSBoris Popov smbfs_attr_cachelookup(vp, va); 2812a4ad258STim J. Robbins if (np->n_flag & NOPEN) 282681a5bbeSBoris Popov np->n_size = oldsize; 283681a5bbeSBoris Popov return 0; 284681a5bbeSBoris Popov } 285681a5bbeSBoris Popov 286681a5bbeSBoris Popov static int 287681a5bbeSBoris Popov smbfs_setattr(ap) 288681a5bbeSBoris Popov struct vop_setattr_args /* { 289681a5bbeSBoris Popov struct vnode *a_vp; 290681a5bbeSBoris Popov struct vattr *a_vap; 291681a5bbeSBoris Popov struct ucred *a_cred; 292b1c996c4SBoris Popov struct thread *a_td; 293681a5bbeSBoris Popov } */ *ap; 294681a5bbeSBoris Popov { 295681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 296681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 297681a5bbeSBoris Popov struct vattr *vap = ap->a_vap; 298681a5bbeSBoris Popov struct timespec *mtime, *atime; 299681a5bbeSBoris Popov struct smb_cred scred; 300681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 301681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ssp); 302681a5bbeSBoris Popov u_quad_t tsize = 0; 303681a5bbeSBoris Popov int isreadonly, doclose, error = 0; 304681a5bbeSBoris Popov 305681a5bbeSBoris Popov SMBVDEBUG("\n"); 306681a5bbeSBoris Popov if (vap->va_flags != VNOVAL) 307681a5bbeSBoris Popov return EOPNOTSUPP; 308681a5bbeSBoris Popov isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 309681a5bbeSBoris Popov /* 310681a5bbeSBoris Popov * Disallow write attempts if the filesystem is mounted read-only. 311681a5bbeSBoris Popov */ 312681a5bbeSBoris Popov if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 313681a5bbeSBoris Popov vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 314681a5bbeSBoris Popov vap->va_mode != (mode_t)VNOVAL) && isreadonly) 315681a5bbeSBoris Popov return EROFS; 316b1c996c4SBoris Popov smb_makescred(&scred, ap->a_td, ap->a_cred); 317681a5bbeSBoris Popov if (vap->va_size != VNOVAL) { 318681a5bbeSBoris Popov switch (vp->v_type) { 319681a5bbeSBoris Popov case VDIR: 320681a5bbeSBoris Popov return EISDIR; 321681a5bbeSBoris Popov case VREG: 322681a5bbeSBoris Popov break; 323681a5bbeSBoris Popov default: 324681a5bbeSBoris Popov return EINVAL; 325681a5bbeSBoris Popov }; 326681a5bbeSBoris Popov if (isreadonly) 327681a5bbeSBoris Popov return EROFS; 328681a5bbeSBoris Popov doclose = 0; 329681a5bbeSBoris Popov vnode_pager_setsize(vp, (u_long)vap->va_size); 330681a5bbeSBoris Popov tsize = np->n_size; 331681a5bbeSBoris Popov np->n_size = vap->va_size; 3322a4ad258STim J. Robbins if ((np->n_flag & NOPEN) == 0) { 33344f3878eSBoris Popov error = smbfs_smb_open(np, 33444f3878eSBoris Popov SMB_SM_DENYNONE|SMB_AM_OPENRW, 33544f3878eSBoris Popov &scred); 336681a5bbeSBoris Popov if (error == 0) 337681a5bbeSBoris Popov doclose = 1; 338681a5bbeSBoris Popov } 339681a5bbeSBoris Popov if (error == 0) 340681a5bbeSBoris Popov error = smbfs_smb_setfsize(np, vap->va_size, &scred); 341681a5bbeSBoris Popov if (doclose) 342681a5bbeSBoris Popov smbfs_smb_close(ssp, np->n_fid, NULL, &scred); 343681a5bbeSBoris Popov if (error) { 344681a5bbeSBoris Popov np->n_size = tsize; 345681a5bbeSBoris Popov vnode_pager_setsize(vp, (u_long)tsize); 346681a5bbeSBoris Popov return error; 347681a5bbeSBoris Popov } 348681a5bbeSBoris Popov } 349681a5bbeSBoris Popov mtime = atime = NULL; 350681a5bbeSBoris Popov if (vap->va_mtime.tv_sec != VNOVAL) 351681a5bbeSBoris Popov mtime = &vap->va_mtime; 352681a5bbeSBoris Popov if (vap->va_atime.tv_sec != VNOVAL) 353681a5bbeSBoris Popov atime = &vap->va_atime; 354681a5bbeSBoris Popov if (mtime != atime) { 355d14c8441SPoul-Henning Kamp if (ap->a_cred->cr_uid != VTOSMBFS(vp)->sm_uid && 35656f21b9dSColin Percival (error = suser_cred(ap->a_cred, SUSER_ALLOWJAIL)) && 3575d004cd1STim J. Robbins ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 3585d004cd1STim J. Robbins (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 3595d004cd1STim J. Robbins return (error); 360681a5bbeSBoris Popov #if 0 361681a5bbeSBoris Popov if (mtime == NULL) 362681a5bbeSBoris Popov mtime = &np->n_mtime; 363681a5bbeSBoris Popov if (atime == NULL) 364681a5bbeSBoris Popov atime = &np->n_atime; 365681a5bbeSBoris Popov #endif 366681a5bbeSBoris Popov /* 367681a5bbeSBoris Popov * If file is opened, then we can use handle based calls. 368681a5bbeSBoris Popov * If not, use path based ones. 369681a5bbeSBoris Popov */ 3702a4ad258STim J. Robbins if ((np->n_flag & NOPEN) == 0) { 371681a5bbeSBoris Popov if (vcp->vc_flags & SMBV_WIN95) { 372a8d43c90SPoul-Henning Kamp error = VOP_OPEN(vp, FWRITE, ap->a_cred, ap->a_td, -1); 373681a5bbeSBoris Popov if (!error) { 374681a5bbeSBoris Popov /* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 375b1c996c4SBoris Popov VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_td);*/ 376681a5bbeSBoris Popov if (mtime) 377681a5bbeSBoris Popov np->n_mtime = *mtime; 378b1c996c4SBoris Popov VOP_CLOSE(vp, FWRITE, ap->a_cred, ap->a_td); 379681a5bbeSBoris Popov } 380681a5bbeSBoris Popov } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 381681a5bbeSBoris Popov error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 382681a5bbeSBoris Popov /* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred);*/ 383681a5bbeSBoris Popov } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 384681a5bbeSBoris Popov error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 385681a5bbeSBoris Popov } else { 386681a5bbeSBoris Popov error = smbfs_smb_setpattr(np, 0, mtime, &scred); 387681a5bbeSBoris Popov } 388681a5bbeSBoris Popov } else { 389681a5bbeSBoris Popov if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 390681a5bbeSBoris Popov error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 391681a5bbeSBoris Popov } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 392681a5bbeSBoris Popov error = smbfs_smb_setftime(np, mtime, atime, &scred); 393681a5bbeSBoris Popov } else { 394681a5bbeSBoris Popov /* 395681a5bbeSBoris Popov * I have no idea how to handle this for core 396681a5bbeSBoris Popov * level servers. The possible solution is to 397681a5bbeSBoris Popov * update mtime after file is closed. 398681a5bbeSBoris Popov */ 399681a5bbeSBoris Popov SMBERROR("can't update times on an opened file\n"); 400681a5bbeSBoris Popov } 401681a5bbeSBoris Popov } 402681a5bbeSBoris Popov } 403681a5bbeSBoris Popov /* 404681a5bbeSBoris Popov * Invalidate attribute cache in case if server doesn't set 405681a5bbeSBoris Popov * required attributes. 406681a5bbeSBoris Popov */ 407681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); /* invalidate cache */ 408b1c996c4SBoris Popov VOP_GETATTR(vp, vap, ap->a_cred, ap->a_td); 409681a5bbeSBoris Popov np->n_mtime.tv_sec = vap->va_mtime.tv_sec; 410681a5bbeSBoris Popov return error; 411681a5bbeSBoris Popov } 412681a5bbeSBoris Popov /* 413681a5bbeSBoris Popov * smbfs_read call. 414681a5bbeSBoris Popov */ 415681a5bbeSBoris Popov static int 416681a5bbeSBoris Popov smbfs_read(ap) 417681a5bbeSBoris Popov struct vop_read_args /* { 418681a5bbeSBoris Popov struct vnode *a_vp; 419681a5bbeSBoris Popov struct uio *a_uio; 420681a5bbeSBoris Popov int a_ioflag; 421681a5bbeSBoris Popov struct ucred *a_cred; 422681a5bbeSBoris Popov } */ *ap; 423681a5bbeSBoris Popov { 424681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 425681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 426681a5bbeSBoris Popov 427681a5bbeSBoris Popov SMBVDEBUG("\n"); 428681a5bbeSBoris Popov if (vp->v_type != VREG && vp->v_type != VDIR) 429681a5bbeSBoris Popov return EPERM; 430681a5bbeSBoris Popov return smbfs_readvnode(vp, uio, ap->a_cred); 431681a5bbeSBoris Popov } 432681a5bbeSBoris Popov 433681a5bbeSBoris Popov static int 434681a5bbeSBoris Popov smbfs_write(ap) 435681a5bbeSBoris Popov struct vop_write_args /* { 436681a5bbeSBoris Popov struct vnode *a_vp; 437681a5bbeSBoris Popov struct uio *a_uio; 438681a5bbeSBoris Popov int a_ioflag; 439681a5bbeSBoris Popov struct ucred *a_cred; 440681a5bbeSBoris Popov } */ *ap; 441681a5bbeSBoris Popov { 442681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 443681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 444681a5bbeSBoris Popov 445681a5bbeSBoris Popov SMBVDEBUG("%d,ofs=%d,sz=%d\n",vp->v_type, (int)uio->uio_offset, uio->uio_resid); 446681a5bbeSBoris Popov if (vp->v_type != VREG) 447681a5bbeSBoris Popov return (EPERM); 448681a5bbeSBoris Popov return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); 449681a5bbeSBoris Popov } 450681a5bbeSBoris Popov /* 451681a5bbeSBoris Popov * smbfs_create call 452681a5bbeSBoris Popov * Create a regular file. On entry the directory to contain the file being 453681a5bbeSBoris Popov * created is locked. We must release before we return. We must also free 454681a5bbeSBoris Popov * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or 455681a5bbeSBoris Popov * only if the SAVESTART bit in cn_flags is clear on success. 456681a5bbeSBoris Popov */ 457681a5bbeSBoris Popov static int 458681a5bbeSBoris Popov smbfs_create(ap) 459681a5bbeSBoris Popov struct vop_create_args /* { 460681a5bbeSBoris Popov struct vnode *a_dvp; 461681a5bbeSBoris Popov struct vnode **a_vpp; 462681a5bbeSBoris Popov struct componentname *a_cnp; 463681a5bbeSBoris Popov struct vattr *a_vap; 464681a5bbeSBoris Popov } */ *ap; 465681a5bbeSBoris Popov { 466681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 467681a5bbeSBoris Popov struct vattr *vap = ap->a_vap; 468681a5bbeSBoris Popov struct vnode **vpp=ap->a_vpp; 469681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 470681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 471681a5bbeSBoris Popov struct vnode *vp; 472681a5bbeSBoris Popov struct vattr vattr; 473681a5bbeSBoris Popov struct smbfattr fattr; 474681a5bbeSBoris Popov struct smb_cred scred; 475681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 476681a5bbeSBoris Popov int nmlen = cnp->cn_namelen; 477681a5bbeSBoris Popov int error; 478681a5bbeSBoris Popov 479681a5bbeSBoris Popov 480681a5bbeSBoris Popov SMBVDEBUG("\n"); 481681a5bbeSBoris Popov *vpp = NULL; 482681a5bbeSBoris Popov if (vap->va_type != VREG) 483681a5bbeSBoris Popov return EOPNOTSUPP; 484b1c996c4SBoris Popov if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread))) 485681a5bbeSBoris Popov return error; 486b1c996c4SBoris Popov smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 487681a5bbeSBoris Popov 488681a5bbeSBoris Popov error = smbfs_smb_create(dnp, name, nmlen, &scred); 489681a5bbeSBoris Popov if (error) 490681a5bbeSBoris Popov return error; 491681a5bbeSBoris Popov error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred); 492681a5bbeSBoris Popov if (error) 493681a5bbeSBoris Popov return error; 494681a5bbeSBoris Popov error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); 495681a5bbeSBoris Popov if (error) 496681a5bbeSBoris Popov return error; 497681a5bbeSBoris Popov *vpp = vp; 498681a5bbeSBoris Popov if (cnp->cn_flags & MAKEENTRY) 499681a5bbeSBoris Popov cache_enter(dvp, vp, cnp); 500681a5bbeSBoris Popov return error; 501681a5bbeSBoris Popov } 502681a5bbeSBoris Popov 503681a5bbeSBoris Popov static int 504681a5bbeSBoris Popov smbfs_remove(ap) 505681a5bbeSBoris Popov struct vop_remove_args /* { 506681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 507681a5bbeSBoris Popov struct vnode * a_dvp; 508681a5bbeSBoris Popov struct vnode * a_vp; 509681a5bbeSBoris Popov struct componentname * a_cnp; 510681a5bbeSBoris Popov } */ *ap; 511681a5bbeSBoris Popov { 512681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 513681a5bbeSBoris Popov /* struct vnode *dvp = ap->a_dvp;*/ 514681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 515681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 516681a5bbeSBoris Popov struct smb_cred scred; 517681a5bbeSBoris Popov int error; 518681a5bbeSBoris Popov 5192a4ad258STim J. Robbins if (vp->v_type == VDIR || (np->n_flag & NOPEN) != 0 || vrefcnt(vp) != 1) 520681a5bbeSBoris Popov return EPERM; 521b1c996c4SBoris Popov smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 522681a5bbeSBoris Popov error = smbfs_smb_delete(np, &scred); 523b4484bf0STim J. Robbins if (error == 0) 524b4484bf0STim J. Robbins np->n_flag |= NGONE; 525681a5bbeSBoris Popov cache_purge(vp); 526681a5bbeSBoris Popov return error; 527681a5bbeSBoris Popov } 528681a5bbeSBoris Popov 529681a5bbeSBoris Popov /* 530681a5bbeSBoris Popov * smbfs_file rename call 531681a5bbeSBoris Popov */ 532681a5bbeSBoris Popov static int 533681a5bbeSBoris Popov smbfs_rename(ap) 534681a5bbeSBoris Popov struct vop_rename_args /* { 535681a5bbeSBoris Popov struct vnode *a_fdvp; 536681a5bbeSBoris Popov struct vnode *a_fvp; 537681a5bbeSBoris Popov struct componentname *a_fcnp; 538681a5bbeSBoris Popov struct vnode *a_tdvp; 539681a5bbeSBoris Popov struct vnode *a_tvp; 540681a5bbeSBoris Popov struct componentname *a_tcnp; 541681a5bbeSBoris Popov } */ *ap; 542681a5bbeSBoris Popov { 543681a5bbeSBoris Popov struct vnode *fvp = ap->a_fvp; 544681a5bbeSBoris Popov struct vnode *tvp = ap->a_tvp; 545681a5bbeSBoris Popov struct vnode *fdvp = ap->a_fdvp; 546681a5bbeSBoris Popov struct vnode *tdvp = ap->a_tdvp; 547681a5bbeSBoris Popov struct componentname *tcnp = ap->a_tcnp; 548681a5bbeSBoris Popov /* struct componentname *fcnp = ap->a_fcnp;*/ 549681a5bbeSBoris Popov struct smb_cred scred; 550681a5bbeSBoris Popov u_int16_t flags = 6; 551681a5bbeSBoris Popov int error=0; 552681a5bbeSBoris Popov 553681a5bbeSBoris Popov /* Check for cross-device rename */ 554681a5bbeSBoris Popov if ((fvp->v_mount != tdvp->v_mount) || 555681a5bbeSBoris Popov (tvp && (fvp->v_mount != tvp->v_mount))) { 556681a5bbeSBoris Popov error = EXDEV; 557681a5bbeSBoris Popov goto out; 558681a5bbeSBoris Popov } 559681a5bbeSBoris Popov 5604d93c0beSJeff Roberson if (tvp && vrefcnt(tvp) > 1) { 561681a5bbeSBoris Popov error = EBUSY; 562681a5bbeSBoris Popov goto out; 563681a5bbeSBoris Popov } 564681a5bbeSBoris Popov flags = 0x10; /* verify all writes */ 565681a5bbeSBoris Popov if (fvp->v_type == VDIR) { 566681a5bbeSBoris Popov flags |= 2; 567681a5bbeSBoris Popov } else if (fvp->v_type == VREG) { 568681a5bbeSBoris Popov flags |= 1; 5696dae0c1eSTim J. Robbins } else { 5706dae0c1eSTim J. Robbins error = EINVAL; 5716dae0c1eSTim J. Robbins goto out; 5726dae0c1eSTim J. Robbins } 573b1c996c4SBoris Popov smb_makescred(&scred, tcnp->cn_thread, tcnp->cn_cred); 574681a5bbeSBoris Popov /* 575681a5bbeSBoris Popov * It seems that Samba doesn't implement SMB_COM_MOVE call... 576681a5bbeSBoris Popov */ 577681a5bbeSBoris Popov #ifdef notnow 578681a5bbeSBoris Popov if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { 579681a5bbeSBoris Popov error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), 580681a5bbeSBoris Popov tcnp->cn_nameptr, tcnp->cn_namelen, flags, &scred); 581681a5bbeSBoris Popov } else 582681a5bbeSBoris Popov #endif 583681a5bbeSBoris Popov { 584681a5bbeSBoris Popov /* 585681a5bbeSBoris Popov * We have to do the work atomicaly 586681a5bbeSBoris Popov */ 587681a5bbeSBoris Popov if (tvp && tvp != fvp) { 588681a5bbeSBoris Popov error = smbfs_smb_delete(VTOSMB(tvp), &scred); 589681a5bbeSBoris Popov if (error) 5906dae0c1eSTim J. Robbins goto out_cacherem; 591b4484bf0STim J. Robbins VTOSMB(fvp)->n_flag |= NGONE; 592681a5bbeSBoris Popov } 593681a5bbeSBoris Popov error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), 594681a5bbeSBoris Popov tcnp->cn_nameptr, tcnp->cn_namelen, &scred); 595681a5bbeSBoris Popov } 596681a5bbeSBoris Popov 597681a5bbeSBoris Popov if (fvp->v_type == VDIR) { 598681a5bbeSBoris Popov if (tvp != NULL && tvp->v_type == VDIR) 599681a5bbeSBoris Popov cache_purge(tdvp); 600681a5bbeSBoris Popov cache_purge(fdvp); 601681a5bbeSBoris Popov } 6026dae0c1eSTim J. Robbins 6036dae0c1eSTim J. Robbins out_cacherem: 6046dae0c1eSTim J. Robbins smbfs_attr_cacheremove(fdvp); 6056dae0c1eSTim J. Robbins smbfs_attr_cacheremove(tdvp); 606681a5bbeSBoris Popov out: 607681a5bbeSBoris Popov if (tdvp == tvp) 608681a5bbeSBoris Popov vrele(tdvp); 609681a5bbeSBoris Popov else 610681a5bbeSBoris Popov vput(tdvp); 611681a5bbeSBoris Popov if (tvp) 612681a5bbeSBoris Popov vput(tvp); 613681a5bbeSBoris Popov vrele(fdvp); 614681a5bbeSBoris Popov vrele(fvp); 615681a5bbeSBoris Popov #ifdef possible_mistake 616681a5bbeSBoris Popov vgone(fvp); 617681a5bbeSBoris Popov if (tvp) 618681a5bbeSBoris Popov vgone(tvp); 619681a5bbeSBoris Popov #endif 620681a5bbeSBoris Popov return error; 621681a5bbeSBoris Popov } 622681a5bbeSBoris Popov 6238e67c454STim J. Robbins /* 6248e67c454STim J. Robbins * somtime it will come true... 6258e67c454STim J. Robbins */ 6268e67c454STim J. Robbins static int 6278e67c454STim J. Robbins smbfs_link(ap) 6288e67c454STim J. Robbins struct vop_link_args /* { 6298e67c454STim J. Robbins struct vnode *a_tdvp; 6308e67c454STim J. Robbins struct vnode *a_vp; 6318e67c454STim J. Robbins struct componentname *a_cnp; 6328e67c454STim J. Robbins } */ *ap; 6338e67c454STim J. Robbins { 6348e67c454STim J. Robbins return EOPNOTSUPP; 6358e67c454STim J. Robbins } 6368e67c454STim J. Robbins 6378e67c454STim J. Robbins /* 6388e67c454STim J. Robbins * smbfs_symlink link create call. 6398e67c454STim J. Robbins * Sometime it will be functional... 6408e67c454STim J. Robbins */ 6418e67c454STim J. Robbins static int 6428e67c454STim J. Robbins smbfs_symlink(ap) 6438e67c454STim J. Robbins struct vop_symlink_args /* { 6448e67c454STim J. Robbins struct vnode *a_dvp; 6458e67c454STim J. Robbins struct vnode **a_vpp; 6468e67c454STim J. Robbins struct componentname *a_cnp; 6478e67c454STim J. Robbins struct vattr *a_vap; 6488e67c454STim J. Robbins char *a_target; 6498e67c454STim J. Robbins } */ *ap; 6508e67c454STim J. Robbins { 6518e67c454STim J. Robbins return EOPNOTSUPP; 6528e67c454STim J. Robbins } 6538e67c454STim J. Robbins 6548e67c454STim J. Robbins static int 6558e67c454STim J. Robbins smbfs_mknod(ap) 6568e67c454STim J. Robbins struct vop_mknod_args /* { 6578e67c454STim J. Robbins } */ *ap; 6588e67c454STim J. Robbins { 6598e67c454STim J. Robbins return EOPNOTSUPP; 6608e67c454STim J. Robbins } 6618e67c454STim J. Robbins 662681a5bbeSBoris Popov static int 663681a5bbeSBoris Popov smbfs_mkdir(ap) 664681a5bbeSBoris Popov struct vop_mkdir_args /* { 665681a5bbeSBoris Popov struct vnode *a_dvp; 666681a5bbeSBoris Popov struct vnode **a_vpp; 667681a5bbeSBoris Popov struct componentname *a_cnp; 668681a5bbeSBoris Popov struct vattr *a_vap; 669681a5bbeSBoris Popov } */ *ap; 670681a5bbeSBoris Popov { 671681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 672681a5bbeSBoris Popov /* struct vattr *vap = ap->a_vap;*/ 673681a5bbeSBoris Popov struct vnode *vp; 674681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 675681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 676681a5bbeSBoris Popov struct vattr vattr; 677681a5bbeSBoris Popov struct smb_cred scred; 678681a5bbeSBoris Popov struct smbfattr fattr; 679681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 680681a5bbeSBoris Popov int len = cnp->cn_namelen; 681681a5bbeSBoris Popov int error; 682681a5bbeSBoris Popov 683b1c996c4SBoris Popov if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_thread))) { 684681a5bbeSBoris Popov return error; 685681a5bbeSBoris Popov } 686681a5bbeSBoris Popov if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 687681a5bbeSBoris Popov return EEXIST; 688b1c996c4SBoris Popov smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 689681a5bbeSBoris Popov error = smbfs_smb_mkdir(dnp, name, len, &scred); 690681a5bbeSBoris Popov if (error) 691681a5bbeSBoris Popov return error; 692681a5bbeSBoris Popov error = smbfs_smb_lookup(dnp, name, len, &fattr, &scred); 693681a5bbeSBoris Popov if (error) 694681a5bbeSBoris Popov return error; 695681a5bbeSBoris Popov error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); 696681a5bbeSBoris Popov if (error) 697681a5bbeSBoris Popov return error; 698681a5bbeSBoris Popov *ap->a_vpp = vp; 699681a5bbeSBoris Popov return 0; 700681a5bbeSBoris Popov } 701681a5bbeSBoris Popov 702681a5bbeSBoris Popov /* 703681a5bbeSBoris Popov * smbfs_remove directory call 704681a5bbeSBoris Popov */ 705681a5bbeSBoris Popov static int 706681a5bbeSBoris Popov smbfs_rmdir(ap) 707681a5bbeSBoris Popov struct vop_rmdir_args /* { 708681a5bbeSBoris Popov struct vnode *a_dvp; 709681a5bbeSBoris Popov struct vnode *a_vp; 710681a5bbeSBoris Popov struct componentname *a_cnp; 711681a5bbeSBoris Popov } */ *ap; 712681a5bbeSBoris Popov { 713681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 714681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 715681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 716681a5bbeSBoris Popov /* struct smbmount *smp = VTOSMBFS(vp);*/ 717681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 718681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 719681a5bbeSBoris Popov struct smb_cred scred; 720681a5bbeSBoris Popov int error; 721681a5bbeSBoris Popov 722681a5bbeSBoris Popov if (dvp == vp) 723681a5bbeSBoris Popov return EINVAL; 724681a5bbeSBoris Popov 725b1c996c4SBoris Popov smb_makescred(&scred, cnp->cn_thread, cnp->cn_cred); 726681a5bbeSBoris Popov error = smbfs_smb_rmdir(np, &scred); 727b4484bf0STim J. Robbins if (error == 0) 728b4484bf0STim J. Robbins np->n_flag |= NGONE; 729681a5bbeSBoris Popov dnp->n_flag |= NMODIFIED; 730681a5bbeSBoris Popov smbfs_attr_cacheremove(dvp); 731681a5bbeSBoris Popov /* cache_purge(dvp);*/ 732681a5bbeSBoris Popov cache_purge(vp); 733681a5bbeSBoris Popov return error; 734681a5bbeSBoris Popov } 735681a5bbeSBoris Popov 736681a5bbeSBoris Popov /* 737681a5bbeSBoris Popov * smbfs_readdir call 738681a5bbeSBoris Popov */ 739681a5bbeSBoris Popov static int 740681a5bbeSBoris Popov smbfs_readdir(ap) 741681a5bbeSBoris Popov struct vop_readdir_args /* { 742681a5bbeSBoris Popov struct vnode *a_vp; 743681a5bbeSBoris Popov struct uio *a_uio; 744681a5bbeSBoris Popov struct ucred *a_cred; 745681a5bbeSBoris Popov int *a_eofflag; 746681a5bbeSBoris Popov u_long *a_cookies; 747681a5bbeSBoris Popov int a_ncookies; 748681a5bbeSBoris Popov } */ *ap; 749681a5bbeSBoris Popov { 750681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 751681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 752681a5bbeSBoris Popov int error; 753681a5bbeSBoris Popov 754681a5bbeSBoris Popov if (vp->v_type != VDIR) 755681a5bbeSBoris Popov return (EPERM); 756681a5bbeSBoris Popov #ifdef notnow 757681a5bbeSBoris Popov if (ap->a_ncookies) { 758681a5bbeSBoris Popov printf("smbfs_readdir: no support for cookies now..."); 759681a5bbeSBoris Popov return (EOPNOTSUPP); 760681a5bbeSBoris Popov } 761681a5bbeSBoris Popov #endif 762681a5bbeSBoris Popov error = smbfs_readvnode(vp, uio, ap->a_cred); 763681a5bbeSBoris Popov return error; 764681a5bbeSBoris Popov } 765681a5bbeSBoris Popov 766681a5bbeSBoris Popov /* ARGSUSED */ 767681a5bbeSBoris Popov static int 768681a5bbeSBoris Popov smbfs_fsync(ap) 769681a5bbeSBoris Popov struct vop_fsync_args /* { 770681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 771681a5bbeSBoris Popov struct vnode * a_vp; 772681a5bbeSBoris Popov struct ucred * a_cred; 773681a5bbeSBoris Popov int a_waitfor; 774b1c996c4SBoris Popov struct thread * a_td; 775681a5bbeSBoris Popov } */ *ap; 776681a5bbeSBoris Popov { 777b1c996c4SBoris Popov /* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ 778681a5bbeSBoris Popov return (0); 779681a5bbeSBoris Popov } 780681a5bbeSBoris Popov 781681a5bbeSBoris Popov static 782681a5bbeSBoris Popov int smbfs_print (ap) 783681a5bbeSBoris Popov struct vop_print_args /* { 784681a5bbeSBoris Popov struct vnode *a_vp; 785681a5bbeSBoris Popov } */ *ap; 786681a5bbeSBoris Popov { 787681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 788681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 789681a5bbeSBoris Popov 790681a5bbeSBoris Popov if (np == NULL) { 791681a5bbeSBoris Popov printf("no smbnode data\n"); 792681a5bbeSBoris Popov return (0); 793681a5bbeSBoris Popov } 7942a4ad258STim J. Robbins printf("\tname = %s, parent = %p, open = %d\n", np->n_name, 7952a4ad258STim J. Robbins np->n_parent ? np->n_parent : NULL, (np->n_flag & NOPEN) != 0); 796681a5bbeSBoris Popov return (0); 797681a5bbeSBoris Popov } 798681a5bbeSBoris Popov 799681a5bbeSBoris Popov static int 800681a5bbeSBoris Popov smbfs_pathconf (ap) 801681a5bbeSBoris Popov struct vop_pathconf_args /* { 802681a5bbeSBoris Popov struct vnode *vp; 803681a5bbeSBoris Popov int name; 804681a5bbeSBoris Popov register_t *retval; 805681a5bbeSBoris Popov } */ *ap; 806681a5bbeSBoris Popov { 807681a5bbeSBoris Popov struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 808681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(smp->sm_share); 809681a5bbeSBoris Popov register_t *retval = ap->a_retval; 810681a5bbeSBoris Popov int error = 0; 811681a5bbeSBoris Popov 812681a5bbeSBoris Popov switch (ap->a_name) { 813681a5bbeSBoris Popov case _PC_LINK_MAX: 814681a5bbeSBoris Popov *retval = 0; 815681a5bbeSBoris Popov break; 816681a5bbeSBoris Popov case _PC_NAME_MAX: 8173419dc99SBoris Popov *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 818681a5bbeSBoris Popov break; 819681a5bbeSBoris Popov case _PC_PATH_MAX: 820681a5bbeSBoris Popov *retval = 800; /* XXX: a correct one ? */ 821681a5bbeSBoris Popov break; 822681a5bbeSBoris Popov default: 823681a5bbeSBoris Popov error = EINVAL; 824681a5bbeSBoris Popov } 825681a5bbeSBoris Popov return error; 826681a5bbeSBoris Popov } 827681a5bbeSBoris Popov 828681a5bbeSBoris Popov static int 829681a5bbeSBoris Popov smbfs_strategy (ap) 830681a5bbeSBoris Popov struct vop_strategy_args /* { 831681a5bbeSBoris Popov struct buf *a_bp 832681a5bbeSBoris Popov } */ *ap; 833681a5bbeSBoris Popov { 834681a5bbeSBoris Popov struct buf *bp=ap->a_bp; 835681a5bbeSBoris Popov struct ucred *cr; 836b1c996c4SBoris Popov struct thread *td; 837681a5bbeSBoris Popov int error = 0; 838681a5bbeSBoris Popov 839681a5bbeSBoris Popov SMBVDEBUG("\n"); 840681a5bbeSBoris Popov if (bp->b_flags & B_ASYNC) 841b1c996c4SBoris Popov td = (struct thread *)0; 842681a5bbeSBoris Popov else 843b1c996c4SBoris Popov td = curthread; /* XXX */ 844681a5bbeSBoris Popov if (bp->b_iocmd == BIO_READ) 845681a5bbeSBoris Popov cr = bp->b_rcred; 846681a5bbeSBoris Popov else 847681a5bbeSBoris Popov cr = bp->b_wcred; 848681a5bbeSBoris Popov 849681a5bbeSBoris Popov if ((bp->b_flags & B_ASYNC) == 0 ) 850066a8feaSPoul-Henning Kamp error = smbfs_doio(ap->a_vp, bp, cr, td); 851681a5bbeSBoris Popov return error; 852681a5bbeSBoris Popov } 853681a5bbeSBoris Popov 8548e67c454STim J. Robbins int 8558e67c454STim J. Robbins smbfs_ioctl(ap) 8568e67c454STim J. Robbins struct vop_ioctl_args /* { 8578e67c454STim J. Robbins struct vnode *a_vp; 8588e67c454STim J. Robbins u_long a_command; 8598e67c454STim J. Robbins caddr_t a_data; 8608e67c454STim J. Robbins int fflag; 8618e67c454STim J. Robbins struct ucred *cred; 8628e67c454STim J. Robbins struct thread *td; 8638e67c454STim J. Robbins } */ *ap; 8648e67c454STim J. Robbins { 8658e67c454STim J. Robbins return ENOTTY; 8668e67c454STim J. Robbins } 8678e67c454STim J. Robbins 868681a5bbeSBoris Popov static char smbfs_atl[] = "rhsvda"; 869681a5bbeSBoris Popov static int 870681a5bbeSBoris Popov smbfs_getextattr(struct vop_getextattr_args *ap) 871681a5bbeSBoris Popov /* { 872681a5bbeSBoris Popov IN struct vnode *a_vp; 873681a5bbeSBoris Popov IN char *a_name; 874681a5bbeSBoris Popov INOUT struct uio *a_uio; 875681a5bbeSBoris Popov IN struct ucred *a_cred; 876b1c996c4SBoris Popov IN struct thread *a_td; 877681a5bbeSBoris Popov }; 878681a5bbeSBoris Popov */ 879681a5bbeSBoris Popov { 880681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 881b1c996c4SBoris Popov struct thread *td = ap->a_td; 882681a5bbeSBoris Popov struct ucred *cred = ap->a_cred; 883681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 884681a5bbeSBoris Popov const char *name = ap->a_name; 885681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 886681a5bbeSBoris Popov struct vattr vattr; 887681a5bbeSBoris Popov char buf[10]; 888681a5bbeSBoris Popov int i, attr, error; 889681a5bbeSBoris Popov 890b1c996c4SBoris Popov error = VOP_ACCESS(vp, VREAD, cred, td); 891681a5bbeSBoris Popov if (error) 892681a5bbeSBoris Popov return error; 893b1c996c4SBoris Popov error = VOP_GETATTR(vp, &vattr, cred, td); 894681a5bbeSBoris Popov if (error) 895681a5bbeSBoris Popov return error; 896681a5bbeSBoris Popov if (strcmp(name, "dosattr") == 0) { 897681a5bbeSBoris Popov attr = np->n_dosattr; 898681a5bbeSBoris Popov for (i = 0; i < 6; i++, attr >>= 1) 899681a5bbeSBoris Popov buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 900681a5bbeSBoris Popov buf[i] = 0; 901681a5bbeSBoris Popov error = uiomove(buf, i, uio); 902681a5bbeSBoris Popov 903681a5bbeSBoris Popov } else 904681a5bbeSBoris Popov error = EINVAL; 905681a5bbeSBoris Popov return error; 906681a5bbeSBoris Popov } 907681a5bbeSBoris Popov 908681a5bbeSBoris Popov /* 909681a5bbeSBoris Popov * Since we expected to support F_GETLK (and SMB protocol has no such function), 910681a5bbeSBoris Popov * it is necessary to use lf_advlock(). It would be nice if this function had 911681a5bbeSBoris Popov * a callback mechanism because it will help to improve a level of consistency. 912681a5bbeSBoris Popov */ 913681a5bbeSBoris Popov int 914681a5bbeSBoris Popov smbfs_advlock(ap) 915681a5bbeSBoris Popov struct vop_advlock_args /* { 916681a5bbeSBoris Popov struct vnode *a_vp; 917681a5bbeSBoris Popov caddr_t a_id; 918681a5bbeSBoris Popov int a_op; 919681a5bbeSBoris Popov struct flock *a_fl; 920681a5bbeSBoris Popov int a_flags; 921681a5bbeSBoris Popov } */ *ap; 922681a5bbeSBoris Popov { 923681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 924681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 925681a5bbeSBoris Popov struct flock *fl = ap->a_fl; 926681a5bbeSBoris Popov caddr_t id = (caddr_t)1 /* ap->a_id */; 927681a5bbeSBoris Popov /* int flags = ap->a_flags;*/ 928b1c996c4SBoris Popov struct thread *td = curthread; 929681a5bbeSBoris Popov struct smb_cred scred; 93047790174SAndrey A. Chernov u_quad_t size; 931fcbe9614SAndrey A. Chernov off_t start, end, oadd; 932681a5bbeSBoris Popov int error, lkop; 933681a5bbeSBoris Popov 934681a5bbeSBoris Popov if (vp->v_type == VDIR) { 935681a5bbeSBoris Popov /* 936681a5bbeSBoris Popov * SMB protocol have no support for directory locking. 937681a5bbeSBoris Popov * Although locks can be processed on local machine, I don't 938681a5bbeSBoris Popov * think that this is a good idea, because some programs 939681a5bbeSBoris Popov * can work wrong assuming directory is locked. So, we just 940681a5bbeSBoris Popov * return 'operation not supported 941681a5bbeSBoris Popov */ 942681a5bbeSBoris Popov return EOPNOTSUPP; 943681a5bbeSBoris Popov } 944681a5bbeSBoris Popov size = np->n_size; 945681a5bbeSBoris Popov switch (fl->l_whence) { 94615924778SAndrey A. Chernov 947681a5bbeSBoris Popov case SEEK_SET: 948681a5bbeSBoris Popov case SEEK_CUR: 949681a5bbeSBoris Popov start = fl->l_start; 950681a5bbeSBoris Popov break; 95115924778SAndrey A. Chernov 952681a5bbeSBoris Popov case SEEK_END: 95315924778SAndrey A. Chernov if (size > OFF_MAX || 95415924778SAndrey A. Chernov (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 95547790174SAndrey A. Chernov return EOVERFLOW; 95615924778SAndrey A. Chernov start = size + fl->l_start; 957bbf6984cSAndrey A. Chernov break; 95815924778SAndrey A. Chernov 959681a5bbeSBoris Popov default: 960681a5bbeSBoris Popov return EINVAL; 961681a5bbeSBoris Popov } 962681a5bbeSBoris Popov if (start < 0) 963681a5bbeSBoris Popov return EINVAL; 964e3e2c03dSAndrey A. Chernov if (fl->l_len < 0) { 965ea4313e3SAndrey A. Chernov if (start == 0) 966e3e2c03dSAndrey A. Chernov return EINVAL; 967e3e2c03dSAndrey A. Chernov end = start - 1; 968ea4313e3SAndrey A. Chernov start += fl->l_len; 969ea4313e3SAndrey A. Chernov if (start < 0) 970ea4313e3SAndrey A. Chernov return EINVAL; 971e3e2c03dSAndrey A. Chernov } else if (fl->l_len == 0) 972681a5bbeSBoris Popov end = -1; 973681a5bbeSBoris Popov else { 974fcbe9614SAndrey A. Chernov oadd = fl->l_len - 1; 97547790174SAndrey A. Chernov if (oadd > OFF_MAX - start) 97647790174SAndrey A. Chernov return EOVERFLOW; 97747790174SAndrey A. Chernov end = start + oadd; 978681a5bbeSBoris Popov } 979a854ed98SJohn Baldwin smb_makescred(&scred, td, td->td_ucred); 980681a5bbeSBoris Popov switch (ap->a_op) { 981681a5bbeSBoris Popov case F_SETLK: 982681a5bbeSBoris Popov switch (fl->l_type) { 983681a5bbeSBoris Popov case F_WRLCK: 984681a5bbeSBoris Popov lkop = SMB_LOCK_EXCL; 985681a5bbeSBoris Popov break; 986681a5bbeSBoris Popov case F_RDLCK: 987681a5bbeSBoris Popov lkop = SMB_LOCK_SHARED; 988681a5bbeSBoris Popov break; 989681a5bbeSBoris Popov case F_UNLCK: 990681a5bbeSBoris Popov lkop = SMB_LOCK_RELEASE; 991681a5bbeSBoris Popov break; 992681a5bbeSBoris Popov default: 993681a5bbeSBoris Popov return EINVAL; 994681a5bbeSBoris Popov } 995681a5bbeSBoris Popov error = lf_advlock(ap, &np->n_lockf, size); 996681a5bbeSBoris Popov if (error) 997681a5bbeSBoris Popov break; 998681a5bbeSBoris Popov lkop = SMB_LOCK_EXCL; 999681a5bbeSBoris Popov error = smbfs_smb_lock(np, lkop, id, start, end, &scred); 1000681a5bbeSBoris Popov if (error) { 1001681a5bbeSBoris Popov ap->a_op = F_UNLCK; 1002681a5bbeSBoris Popov lf_advlock(ap, &np->n_lockf, size); 1003681a5bbeSBoris Popov } 1004681a5bbeSBoris Popov break; 1005681a5bbeSBoris Popov case F_UNLCK: 1006681a5bbeSBoris Popov lf_advlock(ap, &np->n_lockf, size); 1007681a5bbeSBoris Popov error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, &scred); 1008681a5bbeSBoris Popov break; 1009681a5bbeSBoris Popov case F_GETLK: 1010681a5bbeSBoris Popov error = lf_advlock(ap, &np->n_lockf, size); 1011681a5bbeSBoris Popov break; 1012681a5bbeSBoris Popov default: 1013681a5bbeSBoris Popov return EINVAL; 1014681a5bbeSBoris Popov } 1015681a5bbeSBoris Popov return error; 1016681a5bbeSBoris Popov } 1017681a5bbeSBoris Popov 1018681a5bbeSBoris Popov static int 1019681a5bbeSBoris Popov smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) 1020681a5bbeSBoris Popov { 1021aa808a7fSTim J. Robbins static const char *badchars = "*/\\:<>;?"; 1022aa808a7fSTim J. Robbins static const char *badchars83 = " +|,[]="; 1023681a5bbeSBoris Popov const char *cp; 1024681a5bbeSBoris Popov int i, error; 1025681a5bbeSBoris Popov 1026681a5bbeSBoris Popov if (nameiop == LOOKUP) 1027681a5bbeSBoris Popov return 0; 1028681a5bbeSBoris Popov error = ENOENT; 1029681a5bbeSBoris Popov if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { 1030681a5bbeSBoris Popov /* 1031681a5bbeSBoris Popov * Name should conform 8.3 format 1032681a5bbeSBoris Popov */ 1033681a5bbeSBoris Popov if (nmlen > 12) 1034681a5bbeSBoris Popov return ENAMETOOLONG; 1035681a5bbeSBoris Popov cp = index(name, '.'); 1036681a5bbeSBoris Popov if (cp == NULL) 1037681a5bbeSBoris Popov return error; 1038681a5bbeSBoris Popov if (cp == name || (cp - name) > 8) 1039681a5bbeSBoris Popov return error; 1040681a5bbeSBoris Popov cp = index(cp + 1, '.'); 1041681a5bbeSBoris Popov if (cp != NULL) 1042681a5bbeSBoris Popov return error; 1043681a5bbeSBoris Popov for (cp = name, i = 0; i < nmlen; i++, cp++) 1044681a5bbeSBoris Popov if (index(badchars83, *cp) != NULL) 1045681a5bbeSBoris Popov return error; 1046681a5bbeSBoris Popov } 1047681a5bbeSBoris Popov for (cp = name, i = 0; i < nmlen; i++, cp++) 1048681a5bbeSBoris Popov if (index(badchars, *cp) != NULL) 1049681a5bbeSBoris Popov return error; 1050681a5bbeSBoris Popov return 0; 1051681a5bbeSBoris Popov } 1052681a5bbeSBoris Popov 1053681a5bbeSBoris Popov /* 1054681a5bbeSBoris Popov * Things go even weird without fixed inode numbers... 1055681a5bbeSBoris Popov */ 1056681a5bbeSBoris Popov int 1057681a5bbeSBoris Popov smbfs_lookup(ap) 1058681a5bbeSBoris Popov struct vop_lookup_args /* { 1059681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 1060681a5bbeSBoris Popov struct vnode *a_dvp; 1061681a5bbeSBoris Popov struct vnode **a_vpp; 1062681a5bbeSBoris Popov struct componentname *a_cnp; 1063681a5bbeSBoris Popov } */ *ap; 1064681a5bbeSBoris Popov { 1065681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 1066b1c996c4SBoris Popov struct thread *td = cnp->cn_thread; 1067681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 1068681a5bbeSBoris Popov struct vnode **vpp = ap->a_vpp; 1069681a5bbeSBoris Popov struct vnode *vp; 1070681a5bbeSBoris Popov struct smbmount *smp; 1071681a5bbeSBoris Popov struct mount *mp = dvp->v_mount; 1072681a5bbeSBoris Popov struct smbnode *dnp; 1073681a5bbeSBoris Popov struct smbfattr fattr, *fap; 1074681a5bbeSBoris Popov struct smb_cred scred; 1075681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 1076681a5bbeSBoris Popov int flags = cnp->cn_flags; 1077681a5bbeSBoris Popov int nameiop = cnp->cn_nameiop; 1078681a5bbeSBoris Popov int nmlen = cnp->cn_namelen; 1079f6576f19SJeff Roberson int wantparent, error, islastcn, isdot; 1080b4484bf0STim J. Robbins int killit; 1081681a5bbeSBoris Popov 1082681a5bbeSBoris Popov SMBVDEBUG("\n"); 1083681a5bbeSBoris Popov if (dvp->v_type != VDIR) 1084681a5bbeSBoris Popov return ENOTDIR; 1085e6e370a7SJeff Roberson if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) { 1086681a5bbeSBoris Popov SMBFSERR("invalid '..'\n"); 1087681a5bbeSBoris Popov return EIO; 1088681a5bbeSBoris Popov } 1089681a5bbeSBoris Popov #ifdef SMB_VNODE_DEBUG 1090681a5bbeSBoris Popov { 1091681a5bbeSBoris Popov char *cp, c; 1092681a5bbeSBoris Popov 1093681a5bbeSBoris Popov cp = name + nmlen; 1094681a5bbeSBoris Popov c = *cp; 1095681a5bbeSBoris Popov *cp = 0; 1096681a5bbeSBoris Popov SMBVDEBUG("%d '%s' in '%s' id=d\n", nameiop, name, 1097681a5bbeSBoris Popov VTOSMB(dvp)->n_name); 1098681a5bbeSBoris Popov *cp = c; 1099681a5bbeSBoris Popov } 1100681a5bbeSBoris Popov #endif 1101681a5bbeSBoris Popov islastcn = flags & ISLASTCN; 1102681a5bbeSBoris Popov if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) 1103681a5bbeSBoris Popov return EROFS; 1104b1c996c4SBoris Popov if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) 1105681a5bbeSBoris Popov return error; 1106681a5bbeSBoris Popov wantparent = flags & (LOCKPARENT|WANTPARENT); 1107681a5bbeSBoris Popov smp = VFSTOSMBFS(mp); 1108681a5bbeSBoris Popov dnp = VTOSMB(dvp); 1109681a5bbeSBoris Popov isdot = (nmlen == 1 && name[0] == '.'); 1110681a5bbeSBoris Popov 1111681a5bbeSBoris Popov error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop); 1112681a5bbeSBoris Popov 1113681a5bbeSBoris Popov if (error) 1114681a5bbeSBoris Popov return ENOENT; 1115681a5bbeSBoris Popov 1116681a5bbeSBoris Popov error = cache_lookup(dvp, vpp, cnp); 1117681a5bbeSBoris Popov SMBVDEBUG("cache_lookup returned %d\n", error); 1118681a5bbeSBoris Popov if (error > 0) 1119681a5bbeSBoris Popov return error; 1120681a5bbeSBoris Popov if (error) { /* name was found */ 1121681a5bbeSBoris Popov struct vattr vattr; 1122681a5bbeSBoris Popov 11235a98dd4dSPoul-Henning Kamp vhold(*vpp); 1124681a5bbeSBoris Popov vp = *vpp; 1125681a5bbeSBoris Popov if (dvp == vp) { /* lookup on current */ 1126681a5bbeSBoris Popov vref(vp); 1127681a5bbeSBoris Popov error = 0; 1128681a5bbeSBoris Popov SMBVDEBUG("cached '.'\n"); 1129681a5bbeSBoris Popov } else if (flags & ISDOTDOT) { 1130b1c996c4SBoris Popov VOP_UNLOCK(dvp, 0, td); /* unlock parent */ 1131b1c996c4SBoris Popov error = vget(vp, LK_EXCLUSIVE, td); 1132f6576f19SJeff Roberson if (error) 1133f6576f19SJeff Roberson if (vn_lock(dvp, LK_EXCLUSIVE, td)) 1134f6576f19SJeff Roberson panic("smbfs_lookup: Can't " 1135f6576f19SJeff Roberson "relock directory."); 1136f6576f19SJeff Roberson } else 1137b1c996c4SBoris Popov error = vget(vp, LK_EXCLUSIVE, td); 1138681a5bbeSBoris Popov if (!error) { 1139b4484bf0STim J. Robbins killit = 0; 1140b4484bf0STim J. Robbins error = VOP_GETATTR(vp, &vattr, cnp->cn_cred, td); 1141b4484bf0STim J. Robbins /* 1142b4484bf0STim J. Robbins * If the file type on the server is inconsistent 1143b4484bf0STim J. Robbins * with what it was when we created the vnode, 1144b4484bf0STim J. Robbins * kill the bogus vnode now and fall through to 1145b4484bf0STim J. Robbins * the code below to create a new one with the 1146b4484bf0STim J. Robbins * right type. 1147b4484bf0STim J. Robbins */ 1148b4484bf0STim J. Robbins if (error == 0 && 1149b4484bf0STim J. Robbins ((vp->v_type == VDIR && 1150b4484bf0STim J. Robbins (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) == 0) || 1151b4484bf0STim J. Robbins (vp->v_type == VREG && 1152b4484bf0STim J. Robbins (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) != 0))) 1153b4484bf0STim J. Robbins killit = 1; 1154b4484bf0STim J. Robbins else if (error == 0 1155681a5bbeSBoris Popov /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { 1156681a5bbeSBoris Popov if (nameiop != LOOKUP && islastcn) 1157681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1158681a5bbeSBoris Popov SMBVDEBUG("use cached vnode\n"); 11595a98dd4dSPoul-Henning Kamp vdrop(vp); 1160681a5bbeSBoris Popov return (0); 1161681a5bbeSBoris Popov } 1162681a5bbeSBoris Popov cache_purge(vp); 1163f6576f19SJeff Roberson /* 1164f6576f19SJeff Roberson * XXX This is not quite right, if '.' is 1165f6576f19SJeff Roberson * inconsistent, we really need to start the lookup 1166f6576f19SJeff Roberson * all over again. Hopefully there is some other 1167f6576f19SJeff Roberson * guarantee that prevents this case from happening. 1168f6576f19SJeff Roberson */ 1169f6576f19SJeff Roberson if (killit && vp != dvp) 1170b4484bf0STim J. Robbins vgone(vp); 1171f6576f19SJeff Roberson if (vp != dvp) 11728da00465SJeff Roberson vput(vp); 1173f6576f19SJeff Roberson else 1174f6576f19SJeff Roberson vrele(vp); 1175f6576f19SJeff Roberson if (flags & ISDOTDOT) 1176f6576f19SJeff Roberson if (vn_lock(dvp, LK_EXCLUSIVE, td)) 1177f6576f19SJeff Roberson panic("smbfs_lookup: Can't " 1178f6576f19SJeff Roberson "relock directory."); 1179681a5bbeSBoris Popov } 11805a98dd4dSPoul-Henning Kamp vdrop(vp); 1181681a5bbeSBoris Popov *vpp = NULLVP; 1182681a5bbeSBoris Popov } 1183681a5bbeSBoris Popov /* 1184681a5bbeSBoris Popov * entry is not in the cache or has been expired 1185681a5bbeSBoris Popov */ 1186681a5bbeSBoris Popov error = 0; 1187681a5bbeSBoris Popov *vpp = NULLVP; 1188b1c996c4SBoris Popov smb_makescred(&scred, td, cnp->cn_cred); 1189681a5bbeSBoris Popov fap = &fattr; 1190681a5bbeSBoris Popov if (flags & ISDOTDOT) { 119111de0c59STim J. Robbins error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, 119211de0c59STim J. Robbins &scred); 1193681a5bbeSBoris Popov SMBVDEBUG("result of dotdot lookup: %d\n", error); 1194681a5bbeSBoris Popov } else { 1195681a5bbeSBoris Popov fap = &fattr; 1196681a5bbeSBoris Popov error = smbfs_smb_lookup(dnp, name, nmlen, fap, &scred); 1197681a5bbeSBoris Popov /* if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')*/ 1198681a5bbeSBoris Popov SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1199681a5bbeSBoris Popov } 1200681a5bbeSBoris Popov if (error && error != ENOENT) 1201681a5bbeSBoris Popov return error; 1202681a5bbeSBoris Popov if (error) { /* entry not found */ 1203681a5bbeSBoris Popov /* 1204681a5bbeSBoris Popov * Handle RENAME or CREATE case... 1205681a5bbeSBoris Popov */ 1206681a5bbeSBoris Popov if ((nameiop == CREATE || nameiop == RENAME) && wantparent && islastcn) { 12076e8681aaSBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 12086e8681aaSBoris Popov if (error) 12096e8681aaSBoris Popov return error; 1210681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1211681a5bbeSBoris Popov return (EJUSTRETURN); 1212681a5bbeSBoris Popov } 1213681a5bbeSBoris Popov return ENOENT; 1214681a5bbeSBoris Popov }/* else { 1215681a5bbeSBoris Popov SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 1216681a5bbeSBoris Popov }*/ 1217681a5bbeSBoris Popov /* 1218681a5bbeSBoris Popov * handle DELETE case ... 1219681a5bbeSBoris Popov */ 1220681a5bbeSBoris Popov if (nameiop == DELETE && islastcn) { /* delete last component */ 1221b1c996c4SBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1222681a5bbeSBoris Popov if (error) 1223681a5bbeSBoris Popov return error; 1224681a5bbeSBoris Popov if (isdot) { 1225681a5bbeSBoris Popov VREF(dvp); 1226681a5bbeSBoris Popov *vpp = dvp; 1227681a5bbeSBoris Popov return 0; 1228681a5bbeSBoris Popov } 1229681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1230681a5bbeSBoris Popov if (error) 1231681a5bbeSBoris Popov return error; 1232681a5bbeSBoris Popov *vpp = vp; 1233681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1234681a5bbeSBoris Popov return 0; 1235681a5bbeSBoris Popov } 1236681a5bbeSBoris Popov if (nameiop == RENAME && islastcn && wantparent) { 1237b1c996c4SBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1238681a5bbeSBoris Popov if (error) 1239681a5bbeSBoris Popov return error; 1240681a5bbeSBoris Popov if (isdot) 1241681a5bbeSBoris Popov return EISDIR; 1242681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1243681a5bbeSBoris Popov if (error) 1244681a5bbeSBoris Popov return error; 1245681a5bbeSBoris Popov *vpp = vp; 1246681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1247681a5bbeSBoris Popov return 0; 1248681a5bbeSBoris Popov } 1249681a5bbeSBoris Popov if (flags & ISDOTDOT) { 1250b1c996c4SBoris Popov VOP_UNLOCK(dvp, 0, td); 1251681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); 1252681a5bbeSBoris Popov if (error) { 1253b1c996c4SBoris Popov vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 1254681a5bbeSBoris Popov return error; 1255681a5bbeSBoris Popov } 1256681a5bbeSBoris Popov *vpp = vp; 1257681a5bbeSBoris Popov } else if (isdot) { 1258681a5bbeSBoris Popov vref(dvp); 1259681a5bbeSBoris Popov *vpp = dvp; 1260681a5bbeSBoris Popov } else { 1261681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1262681a5bbeSBoris Popov if (error) 1263681a5bbeSBoris Popov return error; 1264681a5bbeSBoris Popov *vpp = vp; 1265681a5bbeSBoris Popov SMBVDEBUG("lookup: getnewvp!\n"); 1266681a5bbeSBoris Popov } 1267681a5bbeSBoris Popov if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 1268681a5bbeSBoris Popov /* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ 1269681a5bbeSBoris Popov cache_enter(dvp, *vpp, cnp); 1270681a5bbeSBoris Popov } 1271681a5bbeSBoris Popov return 0; 1272681a5bbeSBoris Popov } 1273