1d167cf6fSWarner Losh /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3d63027b6SPedro F. Giffuni * 4681a5bbeSBoris Popov * Copyright (c) 2000-2001 Boris Popov 5681a5bbeSBoris Popov * All rights reserved. 6681a5bbeSBoris Popov * 7681a5bbeSBoris Popov * Redistribution and use in source and binary forms, with or without 8681a5bbeSBoris Popov * modification, are permitted provided that the following conditions 9681a5bbeSBoris Popov * are met: 10681a5bbeSBoris Popov * 1. Redistributions of source code must retain the above copyright 11681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer. 12681a5bbeSBoris Popov * 2. Redistributions in binary form must reproduce the above copyright 13681a5bbeSBoris Popov * notice, this list of conditions and the following disclaimer in the 14681a5bbeSBoris Popov * documentation and/or other materials provided with the distribution. 15681a5bbeSBoris Popov * 16681a5bbeSBoris Popov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17681a5bbeSBoris Popov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18681a5bbeSBoris Popov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19681a5bbeSBoris Popov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20681a5bbeSBoris Popov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21681a5bbeSBoris Popov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22681a5bbeSBoris Popov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23681a5bbeSBoris Popov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24681a5bbeSBoris Popov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25681a5bbeSBoris Popov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26681a5bbeSBoris Popov * SUCH DAMAGE. 27681a5bbeSBoris Popov */ 28681a5bbeSBoris Popov #include <sys/param.h> 29681a5bbeSBoris Popov #include <sys/systm.h> 30681a5bbeSBoris Popov #include <sys/namei.h> 31681a5bbeSBoris Popov #include <sys/kernel.h> 32681a5bbeSBoris Popov #include <sys/proc.h> 33681a5bbeSBoris Popov #include <sys/bio.h> 34681a5bbeSBoris Popov #include <sys/buf.h> 35681a5bbeSBoris Popov #include <sys/fcntl.h> 36681a5bbeSBoris Popov #include <sys/mount.h> 37681a5bbeSBoris Popov #include <sys/unistd.h> 38681a5bbeSBoris Popov #include <sys/vnode.h> 39104a9b7eSAlexander Kabaev #include <sys/limits.h> 40681a5bbeSBoris Popov #include <sys/lockf.h> 41fb8e9eadSBoris Popov #include <sys/stat.h> 42681a5bbeSBoris Popov 43681a5bbeSBoris Popov #include <vm/vm.h> 44681a5bbeSBoris Popov #include <vm/vm_extern.h> 45681a5bbeSBoris Popov 46681a5bbeSBoris Popov #include <netsmb/smb.h> 47681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 48681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 49681a5bbeSBoris Popov 50681a5bbeSBoris Popov #include <fs/smbfs/smbfs.h> 51681a5bbeSBoris Popov #include <fs/smbfs/smbfs_node.h> 52681a5bbeSBoris Popov #include <fs/smbfs/smbfs_subr.h> 53681a5bbeSBoris Popov 54681a5bbeSBoris Popov /* 55681a5bbeSBoris Popov * Prototypes for SMBFS vnode operations 56681a5bbeSBoris Popov */ 576fde64c7SPoul-Henning Kamp static vop_create_t smbfs_create; 586fde64c7SPoul-Henning Kamp static vop_mknod_t smbfs_mknod; 596fde64c7SPoul-Henning Kamp static vop_open_t smbfs_open; 606fde64c7SPoul-Henning Kamp static vop_close_t smbfs_close; 616fde64c7SPoul-Henning Kamp static vop_access_t smbfs_access; 626fde64c7SPoul-Henning Kamp static vop_getattr_t smbfs_getattr; 636fde64c7SPoul-Henning Kamp static vop_setattr_t smbfs_setattr; 646fde64c7SPoul-Henning Kamp static vop_read_t smbfs_read; 656fde64c7SPoul-Henning Kamp static vop_write_t smbfs_write; 666fde64c7SPoul-Henning Kamp static vop_fsync_t smbfs_fsync; 676fde64c7SPoul-Henning Kamp static vop_remove_t smbfs_remove; 686fde64c7SPoul-Henning Kamp static vop_link_t smbfs_link; 696fde64c7SPoul-Henning Kamp static vop_lookup_t smbfs_lookup; 706fde64c7SPoul-Henning Kamp static vop_rename_t smbfs_rename; 716fde64c7SPoul-Henning Kamp static vop_mkdir_t smbfs_mkdir; 726fde64c7SPoul-Henning Kamp static vop_rmdir_t smbfs_rmdir; 736fde64c7SPoul-Henning Kamp static vop_symlink_t smbfs_symlink; 746fde64c7SPoul-Henning Kamp static vop_readdir_t smbfs_readdir; 756fde64c7SPoul-Henning Kamp static vop_strategy_t smbfs_strategy; 766fde64c7SPoul-Henning Kamp static vop_print_t smbfs_print; 776fde64c7SPoul-Henning Kamp static vop_pathconf_t smbfs_pathconf; 786fde64c7SPoul-Henning Kamp static vop_advlock_t smbfs_advlock; 796fde64c7SPoul-Henning Kamp static vop_getextattr_t smbfs_getextattr; 80681a5bbeSBoris Popov 81aec0fb7bSPoul-Henning Kamp struct vop_vector smbfs_vnodeops = { 82aec0fb7bSPoul-Henning Kamp .vop_default = &default_vnodeops, 8383c64397SPoul-Henning Kamp 84aec0fb7bSPoul-Henning Kamp .vop_access = smbfs_access, 85aec0fb7bSPoul-Henning Kamp .vop_advlock = smbfs_advlock, 86aec0fb7bSPoul-Henning Kamp .vop_close = smbfs_close, 87aec0fb7bSPoul-Henning Kamp .vop_create = smbfs_create, 88aec0fb7bSPoul-Henning Kamp .vop_fsync = smbfs_fsync, 89aec0fb7bSPoul-Henning Kamp .vop_getattr = smbfs_getattr, 9083c64397SPoul-Henning Kamp .vop_getextattr = smbfs_getextattr, 91aec0fb7bSPoul-Henning Kamp .vop_getpages = smbfs_getpages, 92aec0fb7bSPoul-Henning Kamp .vop_inactive = smbfs_inactive, 93aec0fb7bSPoul-Henning Kamp .vop_ioctl = smbfs_ioctl, 94aec0fb7bSPoul-Henning Kamp .vop_link = smbfs_link, 95aec0fb7bSPoul-Henning Kamp .vop_lookup = smbfs_lookup, 96aec0fb7bSPoul-Henning Kamp .vop_mkdir = smbfs_mkdir, 97aec0fb7bSPoul-Henning Kamp .vop_mknod = smbfs_mknod, 98aec0fb7bSPoul-Henning Kamp .vop_open = smbfs_open, 99aec0fb7bSPoul-Henning Kamp .vop_pathconf = smbfs_pathconf, 100aec0fb7bSPoul-Henning Kamp .vop_print = smbfs_print, 101aec0fb7bSPoul-Henning Kamp .vop_putpages = smbfs_putpages, 102aec0fb7bSPoul-Henning Kamp .vop_read = smbfs_read, 103aec0fb7bSPoul-Henning Kamp .vop_readdir = smbfs_readdir, 104aec0fb7bSPoul-Henning Kamp .vop_reclaim = smbfs_reclaim, 105aec0fb7bSPoul-Henning Kamp .vop_remove = smbfs_remove, 106aec0fb7bSPoul-Henning Kamp .vop_rename = smbfs_rename, 107aec0fb7bSPoul-Henning Kamp .vop_rmdir = smbfs_rmdir, 108aec0fb7bSPoul-Henning Kamp .vop_setattr = smbfs_setattr, 10983c64397SPoul-Henning Kamp /* .vop_setextattr = smbfs_setextattr,*/ 110aec0fb7bSPoul-Henning Kamp .vop_strategy = smbfs_strategy, 111aec0fb7bSPoul-Henning Kamp .vop_symlink = smbfs_symlink, 112aec0fb7bSPoul-Henning Kamp .vop_write = smbfs_write, 113681a5bbeSBoris Popov }; 1146fa079fcSMateusz Guzik VFS_VOP_VECTOR_REGISTER(smbfs_vnodeops); 115681a5bbeSBoris Popov 116681a5bbeSBoris Popov static int 117b09b03a1SMateusz Guzik smbfs_access(struct vop_access_args *ap) 118681a5bbeSBoris Popov { 119681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 12015bc6b2bSEdward Tomasz Napierala accmode_t accmode = ap->a_accmode; 12138356d10STim J. Robbins mode_t mpmode; 122681a5bbeSBoris Popov struct smbmount *smp = VTOSMBFS(vp); 123681a5bbeSBoris Popov 124681a5bbeSBoris Popov SMBVDEBUG("\n"); 12515bc6b2bSEdward Tomasz Napierala if ((accmode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 126681a5bbeSBoris Popov switch (vp->v_type) { 127681a5bbeSBoris Popov case VREG: case VDIR: case VLNK: 128681a5bbeSBoris Popov return EROFS; 129681a5bbeSBoris Popov default: 130681a5bbeSBoris Popov break; 131681a5bbeSBoris Popov } 132681a5bbeSBoris Popov } 133d14c8441SPoul-Henning Kamp mpmode = vp->v_type == VREG ? smp->sm_file_mode : smp->sm_dir_mode; 134d14c8441SPoul-Henning Kamp return (vaccess(vp->v_type, mpmode, smp->sm_uid, 135d292b194SMateusz Guzik smp->sm_gid, ap->a_accmode, ap->a_cred)); 136681a5bbeSBoris Popov } 137681a5bbeSBoris Popov 138681a5bbeSBoris Popov /* ARGSUSED */ 139681a5bbeSBoris Popov static int 140b09b03a1SMateusz Guzik smbfs_open(struct vop_open_args *ap) 141681a5bbeSBoris Popov { 142681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 143681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 144afe09751SDavide Italiano struct smb_cred *scred; 145681a5bbeSBoris Popov struct vattr vattr; 146681a5bbeSBoris Popov int mode = ap->a_mode; 147681a5bbeSBoris Popov int error, accmode; 148681a5bbeSBoris Popov 1492a4ad258STim J. Robbins SMBVDEBUG("%s,%d\n", np->n_name, (np->n_flag & NOPEN) != 0); 150681a5bbeSBoris Popov if (vp->v_type != VREG && vp->v_type != VDIR) { 151681a5bbeSBoris Popov SMBFSERR("open eacces vtype=%d\n", vp->v_type); 152681a5bbeSBoris Popov return EACCES; 153681a5bbeSBoris Popov } 154681a5bbeSBoris Popov if (vp->v_type == VDIR) { 1552a4ad258STim J. Robbins np->n_flag |= NOPEN; 156681a5bbeSBoris Popov return 0; 157681a5bbeSBoris Popov } 158681a5bbeSBoris Popov if (np->n_flag & NMODIFIED) { 159e50508dfSPoul-Henning Kamp if ((error = smbfs_vinvalbuf(vp, ap->a_td)) == EINTR) 160681a5bbeSBoris Popov return error; 161681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); 1620359a12eSAttilio Rao error = VOP_GETATTR(vp, &vattr, ap->a_cred); 163681a5bbeSBoris Popov if (error) 164681a5bbeSBoris Popov return error; 165681a5bbeSBoris Popov np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 166681a5bbeSBoris Popov } else { 1670359a12eSAttilio Rao error = VOP_GETATTR(vp, &vattr, ap->a_cred); 168681a5bbeSBoris Popov if (error) 169681a5bbeSBoris Popov return error; 170681a5bbeSBoris Popov if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) { 171e50508dfSPoul-Henning Kamp error = smbfs_vinvalbuf(vp, ap->a_td); 172681a5bbeSBoris Popov if (error == EINTR) 173681a5bbeSBoris Popov return error; 174681a5bbeSBoris Popov np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 175681a5bbeSBoris Popov } 176681a5bbeSBoris Popov } 1772a4ad258STim J. Robbins if ((np->n_flag & NOPEN) != 0) 178681a5bbeSBoris Popov return 0; 17944f3878eSBoris Popov /* 18044f3878eSBoris Popov * Use DENYNONE to give unixy semantics of permitting 18144f3878eSBoris Popov * everything not forbidden by permissions. Ie denial 18244f3878eSBoris Popov * is up to server with clients/openers needing to use 18344f3878eSBoris Popov * advisory locks for further control. 18444f3878eSBoris Popov */ 18544f3878eSBoris Popov accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 186681a5bbeSBoris Popov if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 18744f3878eSBoris Popov accmode = SMB_SM_DENYNONE|SMB_AM_OPENRW; 188afe09751SDavide Italiano scred = smbfs_malloc_scred(); 189afe09751SDavide Italiano smb_makescred(scred, ap->a_td, ap->a_cred); 190afe09751SDavide Italiano error = smbfs_smb_open(np, accmode, scred); 191681a5bbeSBoris Popov if (error) { 192681a5bbeSBoris Popov if (mode & FWRITE) 193681a5bbeSBoris Popov return EACCES; 19444f3878eSBoris Popov else if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { 19544f3878eSBoris Popov accmode = SMB_SM_DENYNONE|SMB_AM_OPENREAD; 196afe09751SDavide Italiano error = smbfs_smb_open(np, accmode, scred); 197681a5bbeSBoris Popov } 19844f3878eSBoris Popov } 19972b3e305SPeter Edwards if (error == 0) { 2002a4ad258STim J. Robbins np->n_flag |= NOPEN; 20172b3e305SPeter Edwards vnode_create_vobject(ap->a_vp, vattr.va_size, ap->a_td); 20272b3e305SPeter Edwards } 203681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); 204afe09751SDavide Italiano smbfs_free_scred(scred); 205681a5bbeSBoris Popov return error; 206681a5bbeSBoris Popov } 207681a5bbeSBoris Popov 208681a5bbeSBoris Popov static int 209b09b03a1SMateusz Guzik smbfs_close(struct vop_close_args *ap) 210681a5bbeSBoris Popov { 211681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 212b1c996c4SBoris Popov struct thread *td = ap->a_td; 213835fb616STim J. Robbins struct smbnode *np = VTOSMB(vp); 214afe09751SDavide Italiano struct smb_cred *scred; 215681a5bbeSBoris Popov 216835fb616STim J. Robbins if (vp->v_type == VDIR && (np->n_flag & NOPEN) != 0 && 217835fb616STim J. Robbins np->n_dirseq != NULL) { 218afe09751SDavide Italiano scred = smbfs_malloc_scred(); 219afe09751SDavide Italiano smb_makescred(scred, td, ap->a_cred); 220afe09751SDavide Italiano smbfs_findclose(np->n_dirseq, scred); 221afe09751SDavide Italiano smbfs_free_scred(scred); 222835fb616STim J. Robbins np->n_dirseq = NULL; 223835fb616STim J. Robbins } 2242a4ad258STim J. Robbins return 0; 225681a5bbeSBoris Popov } 226681a5bbeSBoris Popov 227681a5bbeSBoris Popov /* 228681a5bbeSBoris Popov * smbfs_getattr call from vfs. 229681a5bbeSBoris Popov */ 230681a5bbeSBoris Popov static int 231b09b03a1SMateusz Guzik smbfs_getattr(struct vop_getattr_args *ap) 232681a5bbeSBoris Popov { 233681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 234681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 235681a5bbeSBoris Popov struct vattr *va=ap->a_vap; 236681a5bbeSBoris Popov struct smbfattr fattr; 237afe09751SDavide Italiano struct smb_cred *scred; 23807a65634STim J. Robbins u_quad_t oldsize; 239681a5bbeSBoris Popov int error; 240681a5bbeSBoris Popov 241e6e370a7SJeff Roberson SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_vflag & VV_ROOT) != 0); 242681a5bbeSBoris Popov error = smbfs_attr_cachelookup(vp, va); 243681a5bbeSBoris Popov if (!error) 244681a5bbeSBoris Popov return 0; 245681a5bbeSBoris Popov SMBVDEBUG("not in the cache\n"); 246afe09751SDavide Italiano scred = smbfs_malloc_scred(); 247afe09751SDavide Italiano smb_makescred(scred, curthread, ap->a_cred); 248681a5bbeSBoris Popov oldsize = np->n_size; 249afe09751SDavide Italiano error = smbfs_smb_lookup(np, NULL, 0, &fattr, scred); 250681a5bbeSBoris Popov if (error) { 251681a5bbeSBoris Popov SMBVDEBUG("error %d\n", error); 252afe09751SDavide Italiano smbfs_free_scred(scred); 253681a5bbeSBoris Popov return error; 254681a5bbeSBoris Popov } 255681a5bbeSBoris Popov smbfs_attr_cacheenter(vp, &fattr); 256681a5bbeSBoris Popov smbfs_attr_cachelookup(vp, va); 2572a4ad258STim J. Robbins if (np->n_flag & NOPEN) 258681a5bbeSBoris Popov np->n_size = oldsize; 259afe09751SDavide Italiano smbfs_free_scred(scred); 260681a5bbeSBoris Popov return 0; 261681a5bbeSBoris Popov } 262681a5bbeSBoris Popov 263681a5bbeSBoris Popov static int 264b09b03a1SMateusz Guzik smbfs_setattr(struct vop_setattr_args *ap) 265681a5bbeSBoris Popov { 266681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 267681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 268681a5bbeSBoris Popov struct vattr *vap = ap->a_vap; 269681a5bbeSBoris Popov struct timespec *mtime, *atime; 270afe09751SDavide Italiano struct smb_cred *scred; 271681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 272681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ssp); 2730359a12eSAttilio Rao struct thread *td = curthread; 274681a5bbeSBoris Popov u_quad_t tsize = 0; 275681a5bbeSBoris Popov int isreadonly, doclose, error = 0; 276fb8e9eadSBoris Popov int old_n_dosattr; 277681a5bbeSBoris Popov 278681a5bbeSBoris Popov SMBVDEBUG("\n"); 279681a5bbeSBoris Popov isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 280681a5bbeSBoris Popov /* 281681a5bbeSBoris Popov * Disallow write attempts if the filesystem is mounted read-only. 282681a5bbeSBoris Popov */ 283681a5bbeSBoris Popov if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 284681a5bbeSBoris Popov vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 2857da1a731SKenneth D. Merry vap->va_mode != (mode_t)VNOVAL || vap->va_flags != VNOVAL) && 2867da1a731SKenneth D. Merry isreadonly) 287681a5bbeSBoris Popov return EROFS; 2887da1a731SKenneth D. Merry 2897da1a731SKenneth D. Merry /* 2907da1a731SKenneth D. Merry * We only support setting four flags. Don't allow setting others. 2917da1a731SKenneth D. Merry * 2927da1a731SKenneth D. Merry * We map UF_READONLY to SMB_FA_RDONLY, unlike the MacOS X version 2937da1a731SKenneth D. Merry * of this code, which maps both UF_IMMUTABLE AND SF_IMMUTABLE to 2947da1a731SKenneth D. Merry * SMB_FA_RDONLY. The immutable flags have different semantics 2957da1a731SKenneth D. Merry * than readonly, which is the reason for the difference. 2967da1a731SKenneth D. Merry */ 2977da1a731SKenneth D. Merry if (vap->va_flags != VNOVAL) { 2987da1a731SKenneth D. Merry if (vap->va_flags & ~(UF_HIDDEN|UF_SYSTEM|UF_ARCHIVE| 2997da1a731SKenneth D. Merry UF_READONLY)) 3007da1a731SKenneth D. Merry return EINVAL; 3017da1a731SKenneth D. Merry } 3027da1a731SKenneth D. Merry 303afe09751SDavide Italiano scred = smbfs_malloc_scred(); 304afe09751SDavide Italiano smb_makescred(scred, td, ap->a_cred); 305681a5bbeSBoris Popov if (vap->va_size != VNOVAL) { 306681a5bbeSBoris Popov switch (vp->v_type) { 307681a5bbeSBoris Popov case VDIR: 308afe09751SDavide Italiano error = EISDIR; 309afe09751SDavide Italiano goto out; 310681a5bbeSBoris Popov case VREG: 311681a5bbeSBoris Popov break; 312681a5bbeSBoris Popov default: 313afe09751SDavide Italiano error = EINVAL; 314afe09751SDavide Italiano goto out; 31574b8d63dSPedro F. Giffuni } 316afe09751SDavide Italiano if (isreadonly) { 317afe09751SDavide Italiano error = EROFS; 318afe09751SDavide Italiano goto out; 319afe09751SDavide Italiano } 320681a5bbeSBoris Popov doclose = 0; 321681a5bbeSBoris Popov vnode_pager_setsize(vp, (u_long)vap->va_size); 322681a5bbeSBoris Popov tsize = np->n_size; 323681a5bbeSBoris Popov np->n_size = vap->va_size; 3242a4ad258STim J. Robbins if ((np->n_flag & NOPEN) == 0) { 32544f3878eSBoris Popov error = smbfs_smb_open(np, 32644f3878eSBoris Popov SMB_SM_DENYNONE|SMB_AM_OPENRW, 327afe09751SDavide Italiano scred); 328681a5bbeSBoris Popov if (error == 0) 329681a5bbeSBoris Popov doclose = 1; 330681a5bbeSBoris Popov } 331681a5bbeSBoris Popov if (error == 0) 332c829016eSAndrey V. Elsukov error = smbfs_smb_setfsize(np, 333c829016eSAndrey V. Elsukov (int64_t)vap->va_size, scred); 334681a5bbeSBoris Popov if (doclose) 335afe09751SDavide Italiano smbfs_smb_close(ssp, np->n_fid, NULL, scred); 336681a5bbeSBoris Popov if (error) { 337681a5bbeSBoris Popov np->n_size = tsize; 338681a5bbeSBoris Popov vnode_pager_setsize(vp, (u_long)tsize); 339afe09751SDavide Italiano goto out; 340681a5bbeSBoris Popov } 341681a5bbeSBoris Popov } 3427da1a731SKenneth D. Merry if ((vap->va_flags != VNOVAL) || (vap->va_mode != (mode_t)VNOVAL)) { 343fb8e9eadSBoris Popov old_n_dosattr = np->n_dosattr; 3447da1a731SKenneth D. Merry 3457da1a731SKenneth D. Merry if (vap->va_mode != (mode_t)VNOVAL) { 346fb8e9eadSBoris Popov if (vap->va_mode & S_IWUSR) 347fb8e9eadSBoris Popov np->n_dosattr &= ~SMB_FA_RDONLY; 348fb8e9eadSBoris Popov else 349fb8e9eadSBoris Popov np->n_dosattr |= SMB_FA_RDONLY; 3507da1a731SKenneth D. Merry } 3517da1a731SKenneth D. Merry 3527da1a731SKenneth D. Merry if (vap->va_flags != VNOVAL) { 3537da1a731SKenneth D. Merry if (vap->va_flags & UF_HIDDEN) 3547da1a731SKenneth D. Merry np->n_dosattr |= SMB_FA_HIDDEN; 3557da1a731SKenneth D. Merry else 3567da1a731SKenneth D. Merry np->n_dosattr &= ~SMB_FA_HIDDEN; 3577da1a731SKenneth D. Merry 3587da1a731SKenneth D. Merry if (vap->va_flags & UF_SYSTEM) 3597da1a731SKenneth D. Merry np->n_dosattr |= SMB_FA_SYSTEM; 3607da1a731SKenneth D. Merry else 3617da1a731SKenneth D. Merry np->n_dosattr &= ~SMB_FA_SYSTEM; 3627da1a731SKenneth D. Merry 3637da1a731SKenneth D. Merry if (vap->va_flags & UF_ARCHIVE) 3647da1a731SKenneth D. Merry np->n_dosattr |= SMB_FA_ARCHIVE; 3657da1a731SKenneth D. Merry else 3667da1a731SKenneth D. Merry np->n_dosattr &= ~SMB_FA_ARCHIVE; 3677da1a731SKenneth D. Merry 3687da1a731SKenneth D. Merry /* 3697da1a731SKenneth D. Merry * We only support setting the immutable / readonly 3707da1a731SKenneth D. Merry * bit for regular files. According to comments in 3717da1a731SKenneth D. Merry * the MacOS X version of this code, supporting the 3727da1a731SKenneth D. Merry * readonly bit on directories doesn't do the same 3737da1a731SKenneth D. Merry * thing in Windows as in Unix. 3747da1a731SKenneth D. Merry */ 3757da1a731SKenneth D. Merry if (vp->v_type == VREG) { 3767da1a731SKenneth D. Merry if (vap->va_flags & UF_READONLY) 3777da1a731SKenneth D. Merry np->n_dosattr |= SMB_FA_RDONLY; 3787da1a731SKenneth D. Merry else 3797da1a731SKenneth D. Merry np->n_dosattr &= ~SMB_FA_RDONLY; 3807da1a731SKenneth D. Merry } 3817da1a731SKenneth D. Merry } 3827da1a731SKenneth D. Merry 383fb8e9eadSBoris Popov if (np->n_dosattr != old_n_dosattr) { 384afe09751SDavide Italiano error = smbfs_smb_setpattr(np, np->n_dosattr, NULL, scred); 385fb8e9eadSBoris Popov if (error) 386afe09751SDavide Italiano goto out; 387fb8e9eadSBoris Popov } 388fb8e9eadSBoris Popov } 389681a5bbeSBoris Popov mtime = atime = NULL; 390681a5bbeSBoris Popov if (vap->va_mtime.tv_sec != VNOVAL) 391681a5bbeSBoris Popov mtime = &vap->va_mtime; 392681a5bbeSBoris Popov if (vap->va_atime.tv_sec != VNOVAL) 393681a5bbeSBoris Popov atime = &vap->va_atime; 394681a5bbeSBoris Popov if (mtime != atime) { 395acd3428bSRobert Watson if (vap->va_vaflags & VA_UTIMES_NULL) { 3960359a12eSAttilio Rao error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); 397acd3428bSRobert Watson if (error) 3980359a12eSAttilio Rao error = VOP_ACCESS(vp, VWRITE, ap->a_cred, td); 399acd3428bSRobert Watson } else 4000359a12eSAttilio Rao error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td); 401681a5bbeSBoris Popov #if 0 402681a5bbeSBoris Popov if (mtime == NULL) 403681a5bbeSBoris Popov mtime = &np->n_mtime; 404681a5bbeSBoris Popov if (atime == NULL) 405681a5bbeSBoris Popov atime = &np->n_atime; 406681a5bbeSBoris Popov #endif 407681a5bbeSBoris Popov /* 408681a5bbeSBoris Popov * If file is opened, then we can use handle based calls. 409681a5bbeSBoris Popov * If not, use path based ones. 410681a5bbeSBoris Popov */ 4112a4ad258STim J. Robbins if ((np->n_flag & NOPEN) == 0) { 412681a5bbeSBoris Popov if (vcp->vc_flags & SMBV_WIN95) { 4130359a12eSAttilio Rao error = VOP_OPEN(vp, FWRITE, ap->a_cred, td, 4140359a12eSAttilio Rao NULL); 415681a5bbeSBoris Popov if (!error) { 4160359a12eSAttilio Rao /* error = smbfs_smb_setfattrNT(np, 0, 417afe09751SDavide Italiano mtime, atime, scred); 4180359a12eSAttilio Rao VOP_GETATTR(vp, &vattr, ap->a_cred); */ 419681a5bbeSBoris Popov if (mtime) 420681a5bbeSBoris Popov np->n_mtime = *mtime; 4210359a12eSAttilio Rao VOP_CLOSE(vp, FWRITE, ap->a_cred, td); 422681a5bbeSBoris Popov } 423681a5bbeSBoris Popov } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 424afe09751SDavide Italiano error = smbfs_smb_setptime2(np, mtime, atime, 0, scred); 425afe09751SDavide Italiano /* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, scred);*/ 426681a5bbeSBoris Popov } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 427afe09751SDavide Italiano error = smbfs_smb_setptime2(np, mtime, atime, 0, scred); 428681a5bbeSBoris Popov } else { 429afe09751SDavide Italiano error = smbfs_smb_setpattr(np, 0, mtime, scred); 430681a5bbeSBoris Popov } 431681a5bbeSBoris Popov } else { 432681a5bbeSBoris Popov if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 433afe09751SDavide Italiano error = smbfs_smb_setfattrNT(np, 0, mtime, atime, scred); 434681a5bbeSBoris Popov } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 435afe09751SDavide Italiano error = smbfs_smb_setftime(np, mtime, atime, scred); 436681a5bbeSBoris Popov } else { 437681a5bbeSBoris Popov /* 438681a5bbeSBoris Popov * I have no idea how to handle this for core 439681a5bbeSBoris Popov * level servers. The possible solution is to 440681a5bbeSBoris Popov * update mtime after file is closed. 441681a5bbeSBoris Popov */ 442681a5bbeSBoris Popov SMBERROR("can't update times on an opened file\n"); 443681a5bbeSBoris Popov } 444681a5bbeSBoris Popov } 445681a5bbeSBoris Popov } 446681a5bbeSBoris Popov /* 447681a5bbeSBoris Popov * Invalidate attribute cache in case if server doesn't set 448681a5bbeSBoris Popov * required attributes. 449681a5bbeSBoris Popov */ 450681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); /* invalidate cache */ 4510359a12eSAttilio Rao VOP_GETATTR(vp, vap, ap->a_cred); 452681a5bbeSBoris Popov np->n_mtime.tv_sec = vap->va_mtime.tv_sec; 453afe09751SDavide Italiano out: 454afe09751SDavide Italiano smbfs_free_scred(scred); 455681a5bbeSBoris Popov return error; 456681a5bbeSBoris Popov } 457681a5bbeSBoris Popov /* 458681a5bbeSBoris Popov * smbfs_read call. 459681a5bbeSBoris Popov */ 460681a5bbeSBoris Popov static int 461b09b03a1SMateusz Guzik smbfs_read(struct vop_read_args *ap) 462681a5bbeSBoris Popov { 463681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 464681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 465681a5bbeSBoris Popov 466681a5bbeSBoris Popov SMBVDEBUG("\n"); 467681a5bbeSBoris Popov if (vp->v_type != VREG && vp->v_type != VDIR) 468681a5bbeSBoris Popov return EPERM; 469681a5bbeSBoris Popov return smbfs_readvnode(vp, uio, ap->a_cred); 470681a5bbeSBoris Popov } 471681a5bbeSBoris Popov 472681a5bbeSBoris Popov static int 473b09b03a1SMateusz Guzik smbfs_write(struct vop_write_args *ap) 474681a5bbeSBoris Popov { 475681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 476681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 477681a5bbeSBoris Popov 478994f027fSDavide Italiano SMBVDEBUG("%d,ofs=%jd,sz=%zd\n",vp->v_type, (intmax_t)uio->uio_offset, 479469cb18fSDavide Italiano uio->uio_resid); 480681a5bbeSBoris Popov if (vp->v_type != VREG) 481681a5bbeSBoris Popov return (EPERM); 482681a5bbeSBoris Popov return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); 483681a5bbeSBoris Popov } 484681a5bbeSBoris Popov /* 485681a5bbeSBoris Popov * smbfs_create call 486681a5bbeSBoris Popov * Create a regular file. On entry the directory to contain the file being 487681a5bbeSBoris Popov * created is locked. We must release before we return. We must also free 4888f7859e8SMateusz Guzik * the pathname buffer pointed at by cnp->cn_pnbuf, always on error. 489681a5bbeSBoris Popov */ 490681a5bbeSBoris Popov static int 491b09b03a1SMateusz Guzik smbfs_create(struct vop_create_args *ap) 492681a5bbeSBoris Popov { 493681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 494681a5bbeSBoris Popov struct vattr *vap = ap->a_vap; 495681a5bbeSBoris Popov struct vnode **vpp=ap->a_vpp; 496681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 497681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 498681a5bbeSBoris Popov struct vnode *vp; 499681a5bbeSBoris Popov struct vattr vattr; 500681a5bbeSBoris Popov struct smbfattr fattr; 501afe09751SDavide Italiano struct smb_cred *scred; 502681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 503681a5bbeSBoris Popov int nmlen = cnp->cn_namelen; 504681a5bbeSBoris Popov int error; 505681a5bbeSBoris Popov 506681a5bbeSBoris Popov SMBVDEBUG("\n"); 507681a5bbeSBoris Popov *vpp = NULL; 508681a5bbeSBoris Popov if (vap->va_type != VREG) 509681a5bbeSBoris Popov return EOPNOTSUPP; 5100359a12eSAttilio Rao if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) 511681a5bbeSBoris Popov return error; 512afe09751SDavide Italiano scred = smbfs_malloc_scred(); 513b4a58fbfSMateusz Guzik smb_makescred(scred, curthread, cnp->cn_cred); 514681a5bbeSBoris Popov 515afe09751SDavide Italiano error = smbfs_smb_create(dnp, name, nmlen, scred); 516681a5bbeSBoris Popov if (error) 517afe09751SDavide Italiano goto out; 518afe09751SDavide Italiano error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, scred); 519681a5bbeSBoris Popov if (error) 520afe09751SDavide Italiano goto out; 521681a5bbeSBoris Popov error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); 522681a5bbeSBoris Popov if (error) 523afe09751SDavide Italiano goto out; 524681a5bbeSBoris Popov *vpp = vp; 525681a5bbeSBoris Popov if (cnp->cn_flags & MAKEENTRY) 526681a5bbeSBoris Popov cache_enter(dvp, vp, cnp); 527afe09751SDavide Italiano out: 528afe09751SDavide Italiano smbfs_free_scred(scred); 529681a5bbeSBoris Popov return error; 530681a5bbeSBoris Popov } 531681a5bbeSBoris Popov 532681a5bbeSBoris Popov static int 533b09b03a1SMateusz Guzik smbfs_remove(struct vop_remove_args *ap) 534681a5bbeSBoris Popov { 535681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 536681a5bbeSBoris Popov /* struct vnode *dvp = ap->a_dvp;*/ 537681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 538681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 539afe09751SDavide Italiano struct smb_cred *scred; 540681a5bbeSBoris Popov int error; 541681a5bbeSBoris Popov 5422a4ad258STim J. Robbins if (vp->v_type == VDIR || (np->n_flag & NOPEN) != 0 || vrefcnt(vp) != 1) 543681a5bbeSBoris Popov return EPERM; 544afe09751SDavide Italiano scred = smbfs_malloc_scred(); 545b4a58fbfSMateusz Guzik smb_makescred(scred, curthread, cnp->cn_cred); 546afe09751SDavide Italiano error = smbfs_smb_delete(np, scred); 547b4484bf0STim J. Robbins if (error == 0) 548b4484bf0STim J. Robbins np->n_flag |= NGONE; 549681a5bbeSBoris Popov cache_purge(vp); 550afe09751SDavide Italiano smbfs_free_scred(scred); 551681a5bbeSBoris Popov return error; 552681a5bbeSBoris Popov } 553681a5bbeSBoris Popov 554681a5bbeSBoris Popov /* 555681a5bbeSBoris Popov * smbfs_file rename call 556681a5bbeSBoris Popov */ 557681a5bbeSBoris Popov static int 558b09b03a1SMateusz Guzik smbfs_rename(struct vop_rename_args *ap) 559681a5bbeSBoris Popov { 560681a5bbeSBoris Popov struct vnode *fvp = ap->a_fvp; 561681a5bbeSBoris Popov struct vnode *tvp = ap->a_tvp; 562681a5bbeSBoris Popov struct vnode *fdvp = ap->a_fdvp; 563681a5bbeSBoris Popov struct vnode *tdvp = ap->a_tdvp; 564681a5bbeSBoris Popov struct componentname *tcnp = ap->a_tcnp; 565681a5bbeSBoris Popov /* struct componentname *fcnp = ap->a_fcnp;*/ 566afe09751SDavide Italiano struct smb_cred *scred; 5679fe2867cSJohn Baldwin #ifdef notnow 568681a5bbeSBoris Popov u_int16_t flags = 6; 5699fe2867cSJohn Baldwin #endif 570681a5bbeSBoris Popov int error=0; 571681a5bbeSBoris Popov 572e346bd81SDavide Italiano scred = NULL; 573681a5bbeSBoris Popov /* Check for cross-device rename */ 574681a5bbeSBoris Popov if ((fvp->v_mount != tdvp->v_mount) || 575681a5bbeSBoris Popov (tvp && (fvp->v_mount != tvp->v_mount))) { 57642039c5bSDavide Italiano error = EXDEV; 577681a5bbeSBoris Popov goto out; 578681a5bbeSBoris Popov } 579681a5bbeSBoris Popov 5804d93c0beSJeff Roberson if (tvp && vrefcnt(tvp) > 1) { 58142039c5bSDavide Italiano error = EBUSY; 582681a5bbeSBoris Popov goto out; 583681a5bbeSBoris Popov } 5849fe2867cSJohn Baldwin #ifdef notnow 585681a5bbeSBoris Popov flags = 0x10; /* verify all writes */ 5869fe2867cSJohn Baldwin #endif 587681a5bbeSBoris Popov if (fvp->v_type == VDIR) { 5889fe2867cSJohn Baldwin #ifdef notnow 589681a5bbeSBoris Popov flags |= 2; 5909fe2867cSJohn Baldwin #endif 591681a5bbeSBoris Popov } else if (fvp->v_type == VREG) { 5929fe2867cSJohn Baldwin #ifdef notnow 593681a5bbeSBoris Popov flags |= 1; 5949fe2867cSJohn Baldwin #endif 5956dae0c1eSTim J. Robbins } else { 596afe09751SDavide Italiano return EINVAL; 5976dae0c1eSTim J. Robbins } 598afe09751SDavide Italiano scred = smbfs_malloc_scred(); 599b4a58fbfSMateusz Guzik smb_makescred(scred, curthread, tcnp->cn_cred); 600681a5bbeSBoris Popov /* 601681a5bbeSBoris Popov * It seems that Samba doesn't implement SMB_COM_MOVE call... 602681a5bbeSBoris Popov */ 603681a5bbeSBoris Popov #ifdef notnow 604681a5bbeSBoris Popov if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { 605681a5bbeSBoris Popov error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), 606afe09751SDavide Italiano tcnp->cn_nameptr, tcnp->cn_namelen, flags, scred); 607681a5bbeSBoris Popov } else 608681a5bbeSBoris Popov #endif 609681a5bbeSBoris Popov { 610681a5bbeSBoris Popov /* 611681a5bbeSBoris Popov * We have to do the work atomicaly 612681a5bbeSBoris Popov */ 613681a5bbeSBoris Popov if (tvp && tvp != fvp) { 614afe09751SDavide Italiano error = smbfs_smb_delete(VTOSMB(tvp), scred); 615681a5bbeSBoris Popov if (error) 6166dae0c1eSTim J. Robbins goto out_cacherem; 617b4484bf0STim J. Robbins VTOSMB(fvp)->n_flag |= NGONE; 618681a5bbeSBoris Popov } 619681a5bbeSBoris Popov error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), 620afe09751SDavide Italiano tcnp->cn_nameptr, tcnp->cn_namelen, scred); 621681a5bbeSBoris Popov } 622681a5bbeSBoris Popov 623681a5bbeSBoris Popov if (fvp->v_type == VDIR) { 624681a5bbeSBoris Popov if (tvp != NULL && tvp->v_type == VDIR) 625681a5bbeSBoris Popov cache_purge(tdvp); 626681a5bbeSBoris Popov cache_purge(fdvp); 627681a5bbeSBoris Popov } 6286dae0c1eSTim J. Robbins 6296dae0c1eSTim J. Robbins out_cacherem: 6306dae0c1eSTim J. Robbins smbfs_attr_cacheremove(fdvp); 6316dae0c1eSTim J. Robbins smbfs_attr_cacheremove(tdvp); 632681a5bbeSBoris Popov out: 633afe09751SDavide Italiano smbfs_free_scred(scred); 634681a5bbeSBoris Popov if (tdvp == tvp) 635681a5bbeSBoris Popov vrele(tdvp); 636681a5bbeSBoris Popov else 637681a5bbeSBoris Popov vput(tdvp); 638681a5bbeSBoris Popov if (tvp) 639681a5bbeSBoris Popov vput(tvp); 640681a5bbeSBoris Popov vrele(fdvp); 641681a5bbeSBoris Popov vrele(fvp); 642681a5bbeSBoris Popov #ifdef possible_mistake 643681a5bbeSBoris Popov vgone(fvp); 644681a5bbeSBoris Popov if (tvp) 645681a5bbeSBoris Popov vgone(tvp); 646681a5bbeSBoris Popov #endif 647681a5bbeSBoris Popov return error; 648681a5bbeSBoris Popov } 649681a5bbeSBoris Popov 6508e67c454STim J. Robbins /* 6518e67c454STim J. Robbins * somtime it will come true... 6528e67c454STim J. Robbins */ 6538e67c454STim J. Robbins static int 654b09b03a1SMateusz Guzik smbfs_link(struct vop_link_args *ap) 6558e67c454STim J. Robbins { 6568e67c454STim J. Robbins return EOPNOTSUPP; 6578e67c454STim J. Robbins } 6588e67c454STim J. Robbins 6598e67c454STim J. Robbins /* 6608e67c454STim J. Robbins * smbfs_symlink link create call. 6618e67c454STim J. Robbins * Sometime it will be functional... 6628e67c454STim J. Robbins */ 6638e67c454STim J. Robbins static int 664b09b03a1SMateusz Guzik smbfs_symlink(struct vop_symlink_args *ap) 6658e67c454STim J. Robbins { 6668e67c454STim J. Robbins return EOPNOTSUPP; 6678e67c454STim J. Robbins } 6688e67c454STim J. Robbins 6698e67c454STim J. Robbins static int 670b09b03a1SMateusz Guzik smbfs_mknod(struct vop_mknod_args *ap) 6718e67c454STim J. Robbins { 6728e67c454STim J. Robbins return EOPNOTSUPP; 6738e67c454STim J. Robbins } 6748e67c454STim J. Robbins 675681a5bbeSBoris Popov static int 676b09b03a1SMateusz Guzik smbfs_mkdir(struct vop_mkdir_args *ap) 677681a5bbeSBoris Popov { 678681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 679681a5bbeSBoris Popov /* struct vattr *vap = ap->a_vap;*/ 680681a5bbeSBoris Popov struct vnode *vp; 681681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 682681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 683681a5bbeSBoris Popov struct vattr vattr; 684afe09751SDavide Italiano struct smb_cred *scred; 685681a5bbeSBoris Popov struct smbfattr fattr; 686681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 687681a5bbeSBoris Popov int len = cnp->cn_namelen; 688681a5bbeSBoris Popov int error; 689681a5bbeSBoris Popov 6900359a12eSAttilio Rao if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred))) { 691681a5bbeSBoris Popov return error; 692681a5bbeSBoris Popov } 693681a5bbeSBoris Popov if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 694681a5bbeSBoris Popov return EEXIST; 695afe09751SDavide Italiano scred = smbfs_malloc_scred(); 696b4a58fbfSMateusz Guzik smb_makescred(scred, curthread, cnp->cn_cred); 697afe09751SDavide Italiano error = smbfs_smb_mkdir(dnp, name, len, scred); 698681a5bbeSBoris Popov if (error) 699afe09751SDavide Italiano goto out; 700afe09751SDavide Italiano error = smbfs_smb_lookup(dnp, name, len, &fattr, scred); 701681a5bbeSBoris Popov if (error) 702afe09751SDavide Italiano goto out; 703681a5bbeSBoris Popov error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); 704681a5bbeSBoris Popov if (error) 705afe09751SDavide Italiano goto out; 706681a5bbeSBoris Popov *ap->a_vpp = vp; 707afe09751SDavide Italiano out: 708afe09751SDavide Italiano smbfs_free_scred(scred); 709e346bd81SDavide Italiano return error; 710681a5bbeSBoris Popov } 711681a5bbeSBoris Popov 712681a5bbeSBoris Popov /* 713681a5bbeSBoris Popov * smbfs_remove directory call 714681a5bbeSBoris Popov */ 715681a5bbeSBoris Popov static int 716b09b03a1SMateusz Guzik smbfs_rmdir(struct vop_rmdir_args *ap) 717681a5bbeSBoris Popov { 718681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 719681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 720681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 721681a5bbeSBoris Popov /* struct smbmount *smp = VTOSMBFS(vp);*/ 722681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 723681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 724afe09751SDavide Italiano struct smb_cred *scred; 725681a5bbeSBoris Popov int error; 726681a5bbeSBoris Popov 727681a5bbeSBoris Popov if (dvp == vp) 728681a5bbeSBoris Popov return EINVAL; 729681a5bbeSBoris Popov 730afe09751SDavide Italiano scred = smbfs_malloc_scred(); 731b4a58fbfSMateusz Guzik smb_makescred(scred, curthread, cnp->cn_cred); 732afe09751SDavide Italiano error = smbfs_smb_rmdir(np, scred); 733b4484bf0STim J. Robbins if (error == 0) 734b4484bf0STim J. Robbins np->n_flag |= NGONE; 735681a5bbeSBoris Popov dnp->n_flag |= NMODIFIED; 736681a5bbeSBoris Popov smbfs_attr_cacheremove(dvp); 737681a5bbeSBoris Popov /* cache_purge(dvp);*/ 738681a5bbeSBoris Popov cache_purge(vp); 739afe09751SDavide Italiano smbfs_free_scred(scred); 740681a5bbeSBoris Popov return error; 741681a5bbeSBoris Popov } 742681a5bbeSBoris Popov 743681a5bbeSBoris Popov /* 744681a5bbeSBoris Popov * smbfs_readdir call 745681a5bbeSBoris Popov */ 746681a5bbeSBoris Popov static int 747b09b03a1SMateusz Guzik smbfs_readdir(struct vop_readdir_args *ap) 748681a5bbeSBoris Popov { 749681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 750681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 751681a5bbeSBoris Popov int error; 752681a5bbeSBoris Popov 753681a5bbeSBoris Popov if (vp->v_type != VDIR) 754681a5bbeSBoris Popov return (EPERM); 755681a5bbeSBoris Popov #ifdef notnow 756681a5bbeSBoris Popov if (ap->a_ncookies) { 757681a5bbeSBoris Popov printf("smbfs_readdir: no support for cookies now..."); 758681a5bbeSBoris Popov return (EOPNOTSUPP); 759681a5bbeSBoris Popov } 760681a5bbeSBoris Popov #endif 761681a5bbeSBoris Popov error = smbfs_readvnode(vp, uio, ap->a_cred); 762681a5bbeSBoris Popov return error; 763681a5bbeSBoris Popov } 764681a5bbeSBoris Popov 765681a5bbeSBoris Popov /* ARGSUSED */ 766681a5bbeSBoris Popov static int 767b09b03a1SMateusz Guzik smbfs_fsync(struct vop_fsync_args *ap) 768681a5bbeSBoris Popov { 769b1c996c4SBoris Popov /* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_td, 1));*/ 770681a5bbeSBoris Popov return (0); 771681a5bbeSBoris Popov } 772681a5bbeSBoris Popov 773681a5bbeSBoris Popov static 774b09b03a1SMateusz Guzik int smbfs_print(struct vop_print_args *ap) 775681a5bbeSBoris Popov { 776681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 777681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 778681a5bbeSBoris Popov 779681a5bbeSBoris Popov if (np == NULL) { 780681a5bbeSBoris Popov printf("no smbnode data\n"); 781681a5bbeSBoris Popov return (0); 782681a5bbeSBoris Popov } 7832a4ad258STim J. Robbins printf("\tname = %s, parent = %p, open = %d\n", np->n_name, 7842a4ad258STim J. Robbins np->n_parent ? np->n_parent : NULL, (np->n_flag & NOPEN) != 0); 785681a5bbeSBoris Popov return (0); 786681a5bbeSBoris Popov } 787681a5bbeSBoris Popov 788681a5bbeSBoris Popov static int 789b09b03a1SMateusz Guzik smbfs_pathconf(struct vop_pathconf_args *ap) 790681a5bbeSBoris Popov { 791681a5bbeSBoris Popov struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 792681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(smp->sm_share); 793b1288166SJohn Baldwin long *retval = ap->a_retval; 794681a5bbeSBoris Popov int error = 0; 795681a5bbeSBoris Popov 796681a5bbeSBoris Popov switch (ap->a_name) { 7974a627952SJohn Baldwin case _PC_FILESIZEBITS: 7984a627952SJohn Baldwin if (vcp->vc_sopt.sv_caps & (SMB_CAP_LARGE_READX | 7994a627952SJohn Baldwin SMB_CAP_LARGE_WRITEX)) 8004a627952SJohn Baldwin *retval = 64; 8014a627952SJohn Baldwin else 8024a627952SJohn Baldwin *retval = 32; 803681a5bbeSBoris Popov break; 804681a5bbeSBoris Popov case _PC_NAME_MAX: 8053419dc99SBoris Popov *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 806681a5bbeSBoris Popov break; 807681a5bbeSBoris Popov case _PC_PATH_MAX: 808681a5bbeSBoris Popov *retval = 800; /* XXX: a correct one ? */ 809681a5bbeSBoris Popov break; 8104a627952SJohn Baldwin case _PC_NO_TRUNC: 8114a627952SJohn Baldwin *retval = 1; 8124a627952SJohn Baldwin break; 813681a5bbeSBoris Popov default: 81415a88f81SJohn Baldwin error = vop_stdpathconf(ap); 815681a5bbeSBoris Popov } 816681a5bbeSBoris Popov return error; 817681a5bbeSBoris Popov } 818681a5bbeSBoris Popov 819681a5bbeSBoris Popov static int 820b09b03a1SMateusz Guzik smbfs_strategy(struct vop_strategy_args *ap) 821681a5bbeSBoris Popov { 822681a5bbeSBoris Popov struct buf *bp=ap->a_bp; 823681a5bbeSBoris Popov struct ucred *cr; 824b1c996c4SBoris Popov struct thread *td; 825681a5bbeSBoris Popov 826681a5bbeSBoris Popov SMBVDEBUG("\n"); 827681a5bbeSBoris Popov if (bp->b_flags & B_ASYNC) 828b1c996c4SBoris Popov td = (struct thread *)0; 829681a5bbeSBoris Popov else 830b1c996c4SBoris Popov td = curthread; /* XXX */ 831681a5bbeSBoris Popov if (bp->b_iocmd == BIO_READ) 832681a5bbeSBoris Popov cr = bp->b_rcred; 833681a5bbeSBoris Popov else 834681a5bbeSBoris Popov cr = bp->b_wcred; 835681a5bbeSBoris Popov 836681a5bbeSBoris Popov if ((bp->b_flags & B_ASYNC) == 0 ) 83713fd4d21SBjoern A. Zeeb (void)smbfs_doio(ap->a_vp, bp, cr, td); 8380da50f6eSEdward Tomasz Napierala return (0); 839681a5bbeSBoris Popov } 840681a5bbeSBoris Popov 8418e67c454STim J. Robbins int 842b09b03a1SMateusz Guzik smbfs_ioctl(struct vop_ioctl_args *ap) 8438e67c454STim J. Robbins { 8448e67c454STim J. Robbins return ENOTTY; 8458e67c454STim J. Robbins } 8468e67c454STim J. Robbins 847681a5bbeSBoris Popov static char smbfs_atl[] = "rhsvda"; 848681a5bbeSBoris Popov static int 849681a5bbeSBoris Popov smbfs_getextattr(struct vop_getextattr_args *ap) 850681a5bbeSBoris Popov /* { 851681a5bbeSBoris Popov IN struct vnode *a_vp; 852681a5bbeSBoris Popov IN char *a_name; 853681a5bbeSBoris Popov INOUT struct uio *a_uio; 854681a5bbeSBoris Popov IN struct ucred *a_cred; 855b1c996c4SBoris Popov IN struct thread *a_td; 856681a5bbeSBoris Popov }; 857681a5bbeSBoris Popov */ 858681a5bbeSBoris Popov { 859681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 860b1c996c4SBoris Popov struct thread *td = ap->a_td; 861681a5bbeSBoris Popov struct ucred *cred = ap->a_cred; 862681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 863681a5bbeSBoris Popov const char *name = ap->a_name; 864681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 865681a5bbeSBoris Popov struct vattr vattr; 866681a5bbeSBoris Popov char buf[10]; 867681a5bbeSBoris Popov int i, attr, error; 868681a5bbeSBoris Popov 869b1c996c4SBoris Popov error = VOP_ACCESS(vp, VREAD, cred, td); 870681a5bbeSBoris Popov if (error) 871681a5bbeSBoris Popov return error; 8720359a12eSAttilio Rao error = VOP_GETATTR(vp, &vattr, cred); 873681a5bbeSBoris Popov if (error) 874681a5bbeSBoris Popov return error; 875681a5bbeSBoris Popov if (strcmp(name, "dosattr") == 0) { 876681a5bbeSBoris Popov attr = np->n_dosattr; 877681a5bbeSBoris Popov for (i = 0; i < 6; i++, attr >>= 1) 878681a5bbeSBoris Popov buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 879681a5bbeSBoris Popov buf[i] = 0; 880681a5bbeSBoris Popov error = uiomove(buf, i, uio); 881681a5bbeSBoris Popov } else 882681a5bbeSBoris Popov error = EINVAL; 883681a5bbeSBoris Popov return error; 884681a5bbeSBoris Popov } 885681a5bbeSBoris Popov 886681a5bbeSBoris Popov /* 887681a5bbeSBoris Popov * Since we expected to support F_GETLK (and SMB protocol has no such function), 888681a5bbeSBoris Popov * it is necessary to use lf_advlock(). It would be nice if this function had 889681a5bbeSBoris Popov * a callback mechanism because it will help to improve a level of consistency. 890681a5bbeSBoris Popov */ 891681a5bbeSBoris Popov int 892b09b03a1SMateusz Guzik smbfs_advlock(struct vop_advlock_args *ap) 893681a5bbeSBoris Popov { 894681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 895681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 896681a5bbeSBoris Popov struct flock *fl = ap->a_fl; 897681a5bbeSBoris Popov caddr_t id = (caddr_t)1 /* ap->a_id */; 898681a5bbeSBoris Popov /* int flags = ap->a_flags;*/ 899b1c996c4SBoris Popov struct thread *td = curthread; 900afe09751SDavide Italiano struct smb_cred *scred; 90147790174SAndrey A. Chernov u_quad_t size; 902fcbe9614SAndrey A. Chernov off_t start, end, oadd; 903681a5bbeSBoris Popov int error, lkop; 904681a5bbeSBoris Popov 905681a5bbeSBoris Popov if (vp->v_type == VDIR) { 906681a5bbeSBoris Popov /* 907681a5bbeSBoris Popov * SMB protocol have no support for directory locking. 908681a5bbeSBoris Popov * Although locks can be processed on local machine, I don't 909681a5bbeSBoris Popov * think that this is a good idea, because some programs 910681a5bbeSBoris Popov * can work wrong assuming directory is locked. So, we just 911681a5bbeSBoris Popov * return 'operation not supported 912681a5bbeSBoris Popov */ 913681a5bbeSBoris Popov return EOPNOTSUPP; 914681a5bbeSBoris Popov } 915681a5bbeSBoris Popov size = np->n_size; 916681a5bbeSBoris Popov switch (fl->l_whence) { 917681a5bbeSBoris Popov case SEEK_SET: 918681a5bbeSBoris Popov case SEEK_CUR: 919681a5bbeSBoris Popov start = fl->l_start; 920681a5bbeSBoris Popov break; 92115924778SAndrey A. Chernov 922681a5bbeSBoris Popov case SEEK_END: 92315924778SAndrey A. Chernov if (size > OFF_MAX || 92415924778SAndrey A. Chernov (fl->l_start > 0 && size > OFF_MAX - fl->l_start)) 92547790174SAndrey A. Chernov return EOVERFLOW; 92615924778SAndrey A. Chernov start = size + fl->l_start; 927bbf6984cSAndrey A. Chernov break; 92815924778SAndrey A. Chernov 929681a5bbeSBoris Popov default: 930681a5bbeSBoris Popov return EINVAL; 931681a5bbeSBoris Popov } 932681a5bbeSBoris Popov if (start < 0) 933681a5bbeSBoris Popov return EINVAL; 934e3e2c03dSAndrey A. Chernov if (fl->l_len < 0) { 935ea4313e3SAndrey A. Chernov if (start == 0) 936e3e2c03dSAndrey A. Chernov return EINVAL; 937e3e2c03dSAndrey A. Chernov end = start - 1; 938ea4313e3SAndrey A. Chernov start += fl->l_len; 939ea4313e3SAndrey A. Chernov if (start < 0) 940ea4313e3SAndrey A. Chernov return EINVAL; 941e3e2c03dSAndrey A. Chernov } else if (fl->l_len == 0) 942681a5bbeSBoris Popov end = -1; 943681a5bbeSBoris Popov else { 944fcbe9614SAndrey A. Chernov oadd = fl->l_len - 1; 94547790174SAndrey A. Chernov if (oadd > OFF_MAX - start) 94647790174SAndrey A. Chernov return EOVERFLOW; 94747790174SAndrey A. Chernov end = start + oadd; 948681a5bbeSBoris Popov } 949afe09751SDavide Italiano scred = smbfs_malloc_scred(); 950afe09751SDavide Italiano smb_makescred(scred, td, td->td_ucred); 951681a5bbeSBoris Popov switch (ap->a_op) { 952681a5bbeSBoris Popov case F_SETLK: 953681a5bbeSBoris Popov switch (fl->l_type) { 954681a5bbeSBoris Popov case F_WRLCK: 955681a5bbeSBoris Popov lkop = SMB_LOCK_EXCL; 956681a5bbeSBoris Popov break; 957681a5bbeSBoris Popov case F_RDLCK: 958681a5bbeSBoris Popov lkop = SMB_LOCK_SHARED; 959681a5bbeSBoris Popov break; 960681a5bbeSBoris Popov case F_UNLCK: 961681a5bbeSBoris Popov lkop = SMB_LOCK_RELEASE; 962681a5bbeSBoris Popov break; 963681a5bbeSBoris Popov default: 964afe09751SDavide Italiano smbfs_free_scred(scred); 965681a5bbeSBoris Popov return EINVAL; 966681a5bbeSBoris Popov } 967eab626f1SKonstantin Belousov error = lf_advlock(ap, &vp->v_lockf, size); 968681a5bbeSBoris Popov if (error) 969681a5bbeSBoris Popov break; 970681a5bbeSBoris Popov lkop = SMB_LOCK_EXCL; 971afe09751SDavide Italiano error = smbfs_smb_lock(np, lkop, id, start, end, scred); 972681a5bbeSBoris Popov if (error) { 97318121c17SDoug Rabson int oldtype = fl->l_type; 97418121c17SDoug Rabson fl->l_type = F_UNLCK; 975681a5bbeSBoris Popov ap->a_op = F_UNLCK; 976eab626f1SKonstantin Belousov lf_advlock(ap, &vp->v_lockf, size); 97718121c17SDoug Rabson fl->l_type = oldtype; 978681a5bbeSBoris Popov } 979681a5bbeSBoris Popov break; 980681a5bbeSBoris Popov case F_UNLCK: 981eab626f1SKonstantin Belousov lf_advlock(ap, &vp->v_lockf, size); 982afe09751SDavide Italiano error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, scred); 983681a5bbeSBoris Popov break; 984681a5bbeSBoris Popov case F_GETLK: 985eab626f1SKonstantin Belousov error = lf_advlock(ap, &vp->v_lockf, size); 986681a5bbeSBoris Popov break; 987681a5bbeSBoris Popov default: 988afe09751SDavide Italiano smbfs_free_scred(scred); 989681a5bbeSBoris Popov return EINVAL; 990681a5bbeSBoris Popov } 991afe09751SDavide Italiano smbfs_free_scred(scred); 992681a5bbeSBoris Popov return error; 993681a5bbeSBoris Popov } 994681a5bbeSBoris Popov 995681a5bbeSBoris Popov static int 996681a5bbeSBoris Popov smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) 997681a5bbeSBoris Popov { 99852b2c8e2SOleksandr Tymoshenko static const char *badchars = "*/:<>?"; 99952b2c8e2SOleksandr Tymoshenko static const char *badchars83 = " +|,[]=;"; 1000681a5bbeSBoris Popov const char *cp; 1001681a5bbeSBoris Popov int i, error; 1002681a5bbeSBoris Popov 100372f6a0faSColin Percival /* 100472f6a0faSColin Percival * Backslash characters, being a path delimiter, are prohibited 100572f6a0faSColin Percival * within a path component even for LOOKUP operations. 100672f6a0faSColin Percival */ 1007dc15eac0SEd Schouten if (strchr(name, '\\') != NULL) 100872f6a0faSColin Percival return ENOENT; 100972f6a0faSColin Percival 1010681a5bbeSBoris Popov if (nameiop == LOOKUP) 1011681a5bbeSBoris Popov return 0; 1012681a5bbeSBoris Popov error = ENOENT; 1013681a5bbeSBoris Popov if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { 1014681a5bbeSBoris Popov /* 1015681a5bbeSBoris Popov * Name should conform 8.3 format 1016681a5bbeSBoris Popov */ 1017681a5bbeSBoris Popov if (nmlen > 12) 1018681a5bbeSBoris Popov return ENAMETOOLONG; 1019dc15eac0SEd Schouten cp = strchr(name, '.'); 1020681a5bbeSBoris Popov if (cp == NULL) 1021681a5bbeSBoris Popov return error; 1022681a5bbeSBoris Popov if (cp == name || (cp - name) > 8) 1023681a5bbeSBoris Popov return error; 1024dc15eac0SEd Schouten cp = strchr(cp + 1, '.'); 1025681a5bbeSBoris Popov if (cp != NULL) 1026681a5bbeSBoris Popov return error; 1027681a5bbeSBoris Popov for (cp = name, i = 0; i < nmlen; i++, cp++) 1028dc15eac0SEd Schouten if (strchr(badchars83, *cp) != NULL) 1029681a5bbeSBoris Popov return error; 1030681a5bbeSBoris Popov } 1031681a5bbeSBoris Popov for (cp = name, i = 0; i < nmlen; i++, cp++) 1032dc15eac0SEd Schouten if (strchr(badchars, *cp) != NULL) 1033681a5bbeSBoris Popov return error; 1034681a5bbeSBoris Popov return 0; 1035681a5bbeSBoris Popov } 1036681a5bbeSBoris Popov 1037681a5bbeSBoris Popov /* 1038681a5bbeSBoris Popov * Things go even weird without fixed inode numbers... 1039681a5bbeSBoris Popov */ 1040681a5bbeSBoris Popov int 1041b09b03a1SMateusz Guzik smbfs_lookup(struct vop_lookup_args *ap) 1042681a5bbeSBoris Popov { 1043681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 1044b4a58fbfSMateusz Guzik struct thread *td = curthread; 1045681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 1046681a5bbeSBoris Popov struct vnode **vpp = ap->a_vpp; 1047681a5bbeSBoris Popov struct vnode *vp; 1048681a5bbeSBoris Popov struct smbmount *smp; 1049681a5bbeSBoris Popov struct mount *mp = dvp->v_mount; 1050681a5bbeSBoris Popov struct smbnode *dnp; 1051681a5bbeSBoris Popov struct smbfattr fattr, *fap; 1052afe09751SDavide Italiano struct smb_cred *scred; 1053681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 1054681a5bbeSBoris Popov int flags = cnp->cn_flags; 1055681a5bbeSBoris Popov int nameiop = cnp->cn_nameiop; 1056681a5bbeSBoris Popov int nmlen = cnp->cn_namelen; 1057da1c9cb2SJeff Roberson int error, islastcn, isdot; 1058b4484bf0STim J. Robbins int killit; 1059681a5bbeSBoris Popov 1060681a5bbeSBoris Popov SMBVDEBUG("\n"); 1061681a5bbeSBoris Popov if (dvp->v_type != VDIR) 1062681a5bbeSBoris Popov return ENOTDIR; 1063e6e370a7SJeff Roberson if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) { 1064681a5bbeSBoris Popov SMBFSERR("invalid '..'\n"); 1065681a5bbeSBoris Popov return EIO; 1066681a5bbeSBoris Popov } 1067681a5bbeSBoris Popov islastcn = flags & ISLASTCN; 1068681a5bbeSBoris Popov if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) 1069681a5bbeSBoris Popov return EROFS; 10706a5abb1eSKyle Evans error = vn_dir_check_exec(dvp, cnp); 10716a5abb1eSKyle Evans if (error != 0) 1072681a5bbeSBoris Popov return error; 1073681a5bbeSBoris Popov smp = VFSTOSMBFS(mp); 1074681a5bbeSBoris Popov dnp = VTOSMB(dvp); 1075681a5bbeSBoris Popov isdot = (nmlen == 1 && name[0] == '.'); 1076681a5bbeSBoris Popov 1077681a5bbeSBoris Popov error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop); 1078681a5bbeSBoris Popov 1079681a5bbeSBoris Popov if (error) 1080681a5bbeSBoris Popov return ENOENT; 1081681a5bbeSBoris Popov 1082bf40d24aSJohn Baldwin error = cache_lookup(dvp, vpp, cnp, NULL, NULL); 1083681a5bbeSBoris Popov SMBVDEBUG("cache_lookup returned %d\n", error); 1084681a5bbeSBoris Popov if (error > 0) 1085681a5bbeSBoris Popov return error; 1086681a5bbeSBoris Popov if (error) { /* name was found */ 1087681a5bbeSBoris Popov struct vattr vattr; 1088681a5bbeSBoris Popov 1089b4484bf0STim J. Robbins killit = 0; 1090e8943128SXin LI vp = *vpp; 10910359a12eSAttilio Rao error = VOP_GETATTR(vp, &vattr, cnp->cn_cred); 1092b4484bf0STim J. Robbins /* 1093b4484bf0STim J. Robbins * If the file type on the server is inconsistent 1094b4484bf0STim J. Robbins * with what it was when we created the vnode, 1095b4484bf0STim J. Robbins * kill the bogus vnode now and fall through to 1096b4484bf0STim J. Robbins * the code below to create a new one with the 1097b4484bf0STim J. Robbins * right type. 1098b4484bf0STim J. Robbins */ 1099b4484bf0STim J. Robbins if (error == 0 && 1100b4484bf0STim J. Robbins ((vp->v_type == VDIR && 1101b4484bf0STim J. Robbins (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) == 0) || 1102b4484bf0STim J. Robbins (vp->v_type == VREG && 1103b4484bf0STim J. Robbins (VTOSMB(vp)->n_dosattr & SMB_FA_DIR) != 0))) 1104b4484bf0STim J. Robbins killit = 1; 1105b4484bf0STim J. Robbins else if (error == 0 1106681a5bbeSBoris Popov /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { 1107681a5bbeSBoris Popov SMBVDEBUG("use cached vnode\n"); 1108681a5bbeSBoris Popov return (0); 1109681a5bbeSBoris Popov } 1110681a5bbeSBoris Popov cache_purge(vp); 1111f6576f19SJeff Roberson /* 1112f6576f19SJeff Roberson * XXX This is not quite right, if '.' is 1113f6576f19SJeff Roberson * inconsistent, we really need to start the lookup 1114f6576f19SJeff Roberson * all over again. Hopefully there is some other 1115f6576f19SJeff Roberson * guarantee that prevents this case from happening. 1116f6576f19SJeff Roberson */ 1117f6576f19SJeff Roberson if (killit && vp != dvp) 1118b4484bf0STim J. Robbins vgone(vp); 1119f6576f19SJeff Roberson if (vp != dvp) 11208da00465SJeff Roberson vput(vp); 1121f6576f19SJeff Roberson else 1122f6576f19SJeff Roberson vrele(vp); 1123681a5bbeSBoris Popov *vpp = NULLVP; 1124681a5bbeSBoris Popov } 1125681a5bbeSBoris Popov /* 1126681a5bbeSBoris Popov * entry is not in the cache or has been expired 1127681a5bbeSBoris Popov */ 1128681a5bbeSBoris Popov error = 0; 1129681a5bbeSBoris Popov *vpp = NULLVP; 1130afe09751SDavide Italiano scred = smbfs_malloc_scred(); 1131afe09751SDavide Italiano smb_makescred(scred, td, cnp->cn_cred); 1132681a5bbeSBoris Popov fap = &fattr; 1133681a5bbeSBoris Popov if (flags & ISDOTDOT) { 1134ce589ae2SDavide Italiano /* 1135ce589ae2SDavide Italiano * In the DOTDOT case, don't go over-the-wire 1136ce589ae2SDavide Italiano * in order to request attributes. We already 1137ce589ae2SDavide Italiano * know it's a directory and subsequent call to 1138ce589ae2SDavide Italiano * smbfs_getattr() will restore consistency. 1139ce589ae2SDavide Italiano * 1140ce589ae2SDavide Italiano */ 1141ce589ae2SDavide Italiano SMBVDEBUG("smbfs_smb_lookup: dotdot\n"); 1142ce589ae2SDavide Italiano } else if (isdot) { 1143ce589ae2SDavide Italiano error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); 1144ce589ae2SDavide Italiano SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1145ce589ae2SDavide Italiano } 1146ce589ae2SDavide Italiano else { 1147afe09751SDavide Italiano error = smbfs_smb_lookup(dnp, name, nmlen, fap, scred); 1148681a5bbeSBoris Popov SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1149681a5bbeSBoris Popov } 1150681a5bbeSBoris Popov if (error && error != ENOENT) 1151afe09751SDavide Italiano goto out; 1152681a5bbeSBoris Popov if (error) { /* entry not found */ 1153681a5bbeSBoris Popov /* 1154681a5bbeSBoris Popov * Handle RENAME or CREATE case... 1155681a5bbeSBoris Popov */ 1156da1c9cb2SJeff Roberson if ((nameiop == CREATE || nameiop == RENAME) && islastcn) { 11576e8681aaSBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 11586e8681aaSBoris Popov if (error) 1159afe09751SDavide Italiano goto out; 1160afe09751SDavide Italiano error = EJUSTRETURN; 1161afe09751SDavide Italiano goto out; 1162681a5bbeSBoris Popov } 1163afe09751SDavide Italiano error = ENOENT; 1164afe09751SDavide Italiano goto out; 1165681a5bbeSBoris Popov }/* else { 1166681a5bbeSBoris Popov SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 1167681a5bbeSBoris Popov }*/ 1168681a5bbeSBoris Popov /* 1169681a5bbeSBoris Popov * handle DELETE case ... 1170681a5bbeSBoris Popov */ 1171681a5bbeSBoris Popov if (nameiop == DELETE && islastcn) { /* delete last component */ 1172b1c996c4SBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1173681a5bbeSBoris Popov if (error) 1174afe09751SDavide Italiano goto out; 1175681a5bbeSBoris Popov if (isdot) { 1176681a5bbeSBoris Popov VREF(dvp); 1177681a5bbeSBoris Popov *vpp = dvp; 1178afe09751SDavide Italiano goto out; 1179681a5bbeSBoris Popov } 1180681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1181681a5bbeSBoris Popov if (error) 1182afe09751SDavide Italiano goto out; 1183681a5bbeSBoris Popov *vpp = vp; 1184afe09751SDavide Italiano goto out; 1185681a5bbeSBoris Popov } 1186da1c9cb2SJeff Roberson if (nameiop == RENAME && islastcn) { 1187b1c996c4SBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 1188681a5bbeSBoris Popov if (error) 1189afe09751SDavide Italiano goto out; 1190afe09751SDavide Italiano if (isdot) { 1191afe09751SDavide Italiano error = EISDIR; 1192afe09751SDavide Italiano goto out; 1193afe09751SDavide Italiano } 1194681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1195681a5bbeSBoris Popov if (error) 1196afe09751SDavide Italiano goto out; 1197681a5bbeSBoris Popov *vpp = vp; 1198afe09751SDavide Italiano goto out; 1199681a5bbeSBoris Popov } 1200681a5bbeSBoris Popov if (flags & ISDOTDOT) { 12019dbe0b12SDavide Italiano mp = dvp->v_mount; 12029dbe0b12SDavide Italiano error = vfs_busy(mp, MBF_NOWAIT); 12039dbe0b12SDavide Italiano if (error != 0) { 12049dbe0b12SDavide Italiano vfs_ref(mp); 1205b249ce48SMateusz Guzik VOP_UNLOCK(dvp); 12069dbe0b12SDavide Italiano error = vfs_busy(mp, 0); 12079dbe0b12SDavide Italiano vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 12089dbe0b12SDavide Italiano vfs_rel(mp); 1209c7d2e4cfSDavide Italiano if (error) { 1210c7d2e4cfSDavide Italiano error = ENOENT; 1211c7d2e4cfSDavide Italiano goto out; 1212c7d2e4cfSDavide Italiano } 1213abd80ddbSMateusz Guzik if (VN_IS_DOOMED(dvp)) { 12149dbe0b12SDavide Italiano vfs_unbusy(mp); 1215c7d2e4cfSDavide Italiano error = ENOENT; 1216c7d2e4cfSDavide Italiano goto out; 12179dbe0b12SDavide Italiano } 12189dbe0b12SDavide Italiano } 1219b249ce48SMateusz Guzik VOP_UNLOCK(dvp); 1220681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); 12219dbe0b12SDavide Italiano vfs_unbusy(mp); 1222cb05b60aSAttilio Rao vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 1223abd80ddbSMateusz Guzik if (VN_IS_DOOMED(dvp)) { 12249dbe0b12SDavide Italiano if (error == 0) 12259dbe0b12SDavide Italiano vput(vp); 12269dbe0b12SDavide Italiano error = ENOENT; 12279dbe0b12SDavide Italiano } 12284585e3acSJeff Roberson if (error) 1229afe09751SDavide Italiano goto out; 1230681a5bbeSBoris Popov *vpp = vp; 1231681a5bbeSBoris Popov } else if (isdot) { 1232681a5bbeSBoris Popov vref(dvp); 1233681a5bbeSBoris Popov *vpp = dvp; 1234681a5bbeSBoris Popov } else { 1235681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1236681a5bbeSBoris Popov if (error) 1237afe09751SDavide Italiano goto out; 1238681a5bbeSBoris Popov *vpp = vp; 1239681a5bbeSBoris Popov SMBVDEBUG("lookup: getnewvp!\n"); 1240681a5bbeSBoris Popov } 1241681a5bbeSBoris Popov if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 1242681a5bbeSBoris Popov /* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ 1243681a5bbeSBoris Popov cache_enter(dvp, *vpp, cnp); 1244681a5bbeSBoris Popov } 1245afe09751SDavide Italiano out: 1246afe09751SDavide Italiano smbfs_free_scred(scred); 1247afe09751SDavide Italiano return (error); 1248681a5bbeSBoris Popov } 1249