1681a5bbeSBoris Popov /* 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 */ 3447790174SAndrey A. Chernov #include <machine/limits.h> 35681a5bbeSBoris Popov #include <sys/param.h> 36681a5bbeSBoris Popov #include <sys/systm.h> 37681a5bbeSBoris Popov #include <sys/namei.h> 38681a5bbeSBoris Popov #include <sys/kernel.h> 39681a5bbeSBoris Popov #include <sys/proc.h> 40681a5bbeSBoris Popov #include <sys/bio.h> 41681a5bbeSBoris Popov #include <sys/buf.h> 42681a5bbeSBoris Popov #include <sys/fcntl.h> 43681a5bbeSBoris Popov #include <sys/mount.h> 44681a5bbeSBoris Popov #include <sys/unistd.h> 45681a5bbeSBoris Popov #include <sys/vnode.h> 46681a5bbeSBoris Popov #include <sys/lockf.h> 47681a5bbeSBoris Popov 48681a5bbeSBoris Popov #include <vm/vm.h> 49681a5bbeSBoris Popov #include <vm/vm_extern.h> 50681a5bbeSBoris Popov #include <vm/vm_zone.h> 51681a5bbeSBoris Popov 52681a5bbeSBoris Popov 53681a5bbeSBoris Popov #include <netsmb/smb.h> 54681a5bbeSBoris Popov #include <netsmb/smb_conn.h> 55681a5bbeSBoris Popov #include <netsmb/smb_subr.h> 56681a5bbeSBoris Popov 57681a5bbeSBoris Popov #include <fs/smbfs/smbfs.h> 58681a5bbeSBoris Popov #include <fs/smbfs/smbfs_node.h> 59681a5bbeSBoris Popov #include <fs/smbfs/smbfs_subr.h> 60681a5bbeSBoris Popov 61681a5bbeSBoris Popov /* 62681a5bbeSBoris Popov * Prototypes for SMBFS vnode operations 63681a5bbeSBoris Popov */ 64681a5bbeSBoris Popov static int smbfs_create(struct vop_create_args *); 65681a5bbeSBoris Popov static int smbfs_mknod(struct vop_mknod_args *); 66681a5bbeSBoris Popov static int smbfs_open(struct vop_open_args *); 67681a5bbeSBoris Popov static int smbfs_close(struct vop_close_args *); 68681a5bbeSBoris Popov static int smbfs_access(struct vop_access_args *); 69681a5bbeSBoris Popov static int smbfs_getattr(struct vop_getattr_args *); 70681a5bbeSBoris Popov static int smbfs_setattr(struct vop_setattr_args *); 71681a5bbeSBoris Popov static int smbfs_read(struct vop_read_args *); 72681a5bbeSBoris Popov static int smbfs_write(struct vop_write_args *); 73681a5bbeSBoris Popov static int smbfs_fsync(struct vop_fsync_args *); 74681a5bbeSBoris Popov static int smbfs_remove(struct vop_remove_args *); 75681a5bbeSBoris Popov static int smbfs_link(struct vop_link_args *); 76681a5bbeSBoris Popov static int smbfs_lookup(struct vop_lookup_args *); 77681a5bbeSBoris Popov static int smbfs_rename(struct vop_rename_args *); 78681a5bbeSBoris Popov static int smbfs_mkdir(struct vop_mkdir_args *); 79681a5bbeSBoris Popov static int smbfs_rmdir(struct vop_rmdir_args *); 80681a5bbeSBoris Popov static int smbfs_symlink(struct vop_symlink_args *); 81681a5bbeSBoris Popov static int smbfs_readdir(struct vop_readdir_args *); 82681a5bbeSBoris Popov static int smbfs_strategy(struct vop_strategy_args *); 83681a5bbeSBoris Popov static int smbfs_print(struct vop_print_args *); 84681a5bbeSBoris Popov static int smbfs_pathconf(struct vop_pathconf_args *ap); 85681a5bbeSBoris Popov static int smbfs_advlock(struct vop_advlock_args *); 86681a5bbeSBoris Popov #ifndef FB_RELENG3 87681a5bbeSBoris Popov static int smbfs_getextattr(struct vop_getextattr_args *ap); 88681a5bbeSBoris Popov #endif 89681a5bbeSBoris Popov 90681a5bbeSBoris Popov vop_t **smbfs_vnodeop_p; 91681a5bbeSBoris Popov static struct vnodeopv_entry_desc smbfs_vnodeop_entries[] = { 92681a5bbeSBoris Popov { &vop_default_desc, (vop_t *) vop_defaultop }, 93681a5bbeSBoris Popov { &vop_access_desc, (vop_t *) smbfs_access }, 94681a5bbeSBoris Popov { &vop_advlock_desc, (vop_t *) smbfs_advlock }, 95681a5bbeSBoris Popov { &vop_close_desc, (vop_t *) smbfs_close }, 96681a5bbeSBoris Popov { &vop_create_desc, (vop_t *) smbfs_create }, 97681a5bbeSBoris Popov { &vop_fsync_desc, (vop_t *) smbfs_fsync }, 98681a5bbeSBoris Popov { &vop_getattr_desc, (vop_t *) smbfs_getattr }, 99681a5bbeSBoris Popov { &vop_getpages_desc, (vop_t *) smbfs_getpages }, 100681a5bbeSBoris Popov { &vop_inactive_desc, (vop_t *) smbfs_inactive }, 101681a5bbeSBoris Popov { &vop_ioctl_desc, (vop_t *) smbfs_ioctl }, 102681a5bbeSBoris Popov { &vop_islocked_desc, (vop_t *) vop_stdislocked }, 103681a5bbeSBoris Popov { &vop_link_desc, (vop_t *) smbfs_link }, 104681a5bbeSBoris Popov { &vop_lock_desc, (vop_t *) vop_stdlock }, 105681a5bbeSBoris Popov { &vop_lookup_desc, (vop_t *) smbfs_lookup }, 106681a5bbeSBoris Popov { &vop_mkdir_desc, (vop_t *) smbfs_mkdir }, 107681a5bbeSBoris Popov { &vop_mknod_desc, (vop_t *) smbfs_mknod }, 108681a5bbeSBoris Popov { &vop_open_desc, (vop_t *) smbfs_open }, 109681a5bbeSBoris Popov { &vop_pathconf_desc, (vop_t *) smbfs_pathconf }, 110681a5bbeSBoris Popov { &vop_print_desc, (vop_t *) smbfs_print }, 111681a5bbeSBoris Popov { &vop_putpages_desc, (vop_t *) smbfs_putpages }, 112681a5bbeSBoris Popov { &vop_read_desc, (vop_t *) smbfs_read }, 113681a5bbeSBoris Popov { &vop_readdir_desc, (vop_t *) smbfs_readdir }, 114681a5bbeSBoris Popov { &vop_reclaim_desc, (vop_t *) smbfs_reclaim }, 115681a5bbeSBoris Popov { &vop_remove_desc, (vop_t *) smbfs_remove }, 116681a5bbeSBoris Popov { &vop_rename_desc, (vop_t *) smbfs_rename }, 117681a5bbeSBoris Popov { &vop_rmdir_desc, (vop_t *) smbfs_rmdir }, 118681a5bbeSBoris Popov { &vop_setattr_desc, (vop_t *) smbfs_setattr }, 119681a5bbeSBoris Popov { &vop_strategy_desc, (vop_t *) smbfs_strategy }, 120681a5bbeSBoris Popov { &vop_symlink_desc, (vop_t *) smbfs_symlink }, 121681a5bbeSBoris Popov { &vop_unlock_desc, (vop_t *) vop_stdunlock }, 122681a5bbeSBoris Popov { &vop_write_desc, (vop_t *) smbfs_write }, 123681a5bbeSBoris Popov #ifndef FB_RELENG3 124681a5bbeSBoris Popov { &vop_getextattr_desc, (vop_t *) smbfs_getextattr }, 125681a5bbeSBoris Popov /* { &vop_setextattr_desc, (vop_t *) smbfs_setextattr },*/ 126681a5bbeSBoris Popov #endif 127681a5bbeSBoris Popov { NULL, NULL } 128681a5bbeSBoris Popov }; 129681a5bbeSBoris Popov 130681a5bbeSBoris Popov static struct vnodeopv_desc smbfs_vnodeop_opv_desc = 131681a5bbeSBoris Popov { &smbfs_vnodeop_p, smbfs_vnodeop_entries }; 132681a5bbeSBoris Popov 133681a5bbeSBoris Popov VNODEOP_SET(smbfs_vnodeop_opv_desc); 134681a5bbeSBoris Popov 135681a5bbeSBoris Popov static int 136681a5bbeSBoris Popov smbfs_access(ap) 137681a5bbeSBoris Popov struct vop_access_args /* { 138681a5bbeSBoris Popov struct vnode *a_vp; 139681a5bbeSBoris Popov int a_mode; 140681a5bbeSBoris Popov struct ucred *a_cred; 141681a5bbeSBoris Popov struct proc *a_p; 142681a5bbeSBoris Popov } */ *ap; 143681a5bbeSBoris Popov { 144681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 145681a5bbeSBoris Popov struct ucred *cred = ap->a_cred; 146681a5bbeSBoris Popov u_int mode = ap->a_mode; 147681a5bbeSBoris Popov struct smbmount *smp = VTOSMBFS(vp); 148681a5bbeSBoris Popov int error = 0; 149681a5bbeSBoris Popov 150681a5bbeSBoris Popov SMBVDEBUG("\n"); 151681a5bbeSBoris Popov if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) { 152681a5bbeSBoris Popov switch (vp->v_type) { 153681a5bbeSBoris Popov case VREG: case VDIR: case VLNK: 154681a5bbeSBoris Popov return EROFS; 155681a5bbeSBoris Popov default: 156681a5bbeSBoris Popov break; 157681a5bbeSBoris Popov } 158681a5bbeSBoris Popov } 159681a5bbeSBoris Popov if (cred->cr_uid == 0) 160681a5bbeSBoris Popov return 0; 161681a5bbeSBoris Popov if (cred->cr_uid != smp->sm_args.uid) { 162681a5bbeSBoris Popov mode >>= 3; 163681a5bbeSBoris Popov if (!groupmember(smp->sm_args.gid, cred)) 164681a5bbeSBoris Popov mode >>= 3; 165681a5bbeSBoris Popov } 166681a5bbeSBoris Popov error = (((vp->v_type == VREG) ? smp->sm_args.file_mode : smp->sm_args.dir_mode) & mode) == mode ? 0 : EACCES; 167681a5bbeSBoris Popov return error; 168681a5bbeSBoris Popov } 169681a5bbeSBoris Popov 170681a5bbeSBoris Popov /* ARGSUSED */ 171681a5bbeSBoris Popov static int 172681a5bbeSBoris Popov smbfs_open(ap) 173681a5bbeSBoris Popov struct vop_open_args /* { 174681a5bbeSBoris Popov struct vnode *a_vp; 175681a5bbeSBoris Popov int a_mode; 176681a5bbeSBoris Popov struct ucred *a_cred; 177681a5bbeSBoris Popov struct proc *a_p; 178681a5bbeSBoris Popov } */ *ap; 179681a5bbeSBoris Popov { 180681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 181681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 182681a5bbeSBoris Popov struct smb_cred scred; 183681a5bbeSBoris Popov struct vattr vattr; 184681a5bbeSBoris Popov int mode = ap->a_mode; 185681a5bbeSBoris Popov int error, accmode; 186681a5bbeSBoris Popov 187681a5bbeSBoris Popov SMBVDEBUG("%s,%d\n", np->n_name, np->n_opencount); 188681a5bbeSBoris Popov if (vp->v_type != VREG && vp->v_type != VDIR) { 189681a5bbeSBoris Popov SMBFSERR("open eacces vtype=%d\n", vp->v_type); 190681a5bbeSBoris Popov return EACCES; 191681a5bbeSBoris Popov } 192681a5bbeSBoris Popov if (vp->v_type == VDIR) { 193681a5bbeSBoris Popov np->n_opencount++; 194681a5bbeSBoris Popov return 0; 195681a5bbeSBoris Popov } 196681a5bbeSBoris Popov if (np->n_flag & NMODIFIED) { 197681a5bbeSBoris Popov if ((error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR) 198681a5bbeSBoris Popov return error; 199681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); 200681a5bbeSBoris Popov error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p); 201681a5bbeSBoris Popov if (error) 202681a5bbeSBoris Popov return error; 203681a5bbeSBoris Popov np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 204681a5bbeSBoris Popov } else { 205681a5bbeSBoris Popov error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p); 206681a5bbeSBoris Popov if (error) 207681a5bbeSBoris Popov return error; 208681a5bbeSBoris Popov if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) { 209681a5bbeSBoris Popov error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1); 210681a5bbeSBoris Popov if (error == EINTR) 211681a5bbeSBoris Popov return error; 212681a5bbeSBoris Popov np->n_mtime.tv_sec = vattr.va_mtime.tv_sec; 213681a5bbeSBoris Popov } 214681a5bbeSBoris Popov } 215681a5bbeSBoris Popov if (np->n_opencount) { 216681a5bbeSBoris Popov np->n_opencount++; 217681a5bbeSBoris Popov return 0; 218681a5bbeSBoris Popov } 219681a5bbeSBoris Popov accmode = SMB_AM_OPENREAD; 220681a5bbeSBoris Popov if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 221681a5bbeSBoris Popov accmode = SMB_AM_OPENRW; 222681a5bbeSBoris Popov smb_makescred(&scred, ap->a_p, ap->a_cred); 223681a5bbeSBoris Popov error = smbfs_smb_open(np, accmode, &scred); 224681a5bbeSBoris Popov if (error) { 225681a5bbeSBoris Popov if (mode & FWRITE) 226681a5bbeSBoris Popov return EACCES; 227681a5bbeSBoris Popov accmode = SMB_AM_OPENREAD; 228681a5bbeSBoris Popov error = smbfs_smb_open(np, accmode, &scred); 229681a5bbeSBoris Popov } 230681a5bbeSBoris Popov if (!error) { 231681a5bbeSBoris Popov np->n_opencount++; 232681a5bbeSBoris Popov } 233681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); 234681a5bbeSBoris Popov return error; 235681a5bbeSBoris Popov } 236681a5bbeSBoris Popov 237681a5bbeSBoris Popov static int 238681a5bbeSBoris Popov smbfs_closel(struct vop_close_args *ap) 239681a5bbeSBoris Popov { 240681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 241681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 242681a5bbeSBoris Popov struct proc *p = ap->a_p; 243681a5bbeSBoris Popov struct smb_cred scred; 244681a5bbeSBoris Popov struct vattr vattr; 245681a5bbeSBoris Popov int error; 246681a5bbeSBoris Popov 247681a5bbeSBoris Popov SMBVDEBUG("name=%s, pid=%d, c=%d\n",np->n_name, p->p_pid, np->n_opencount); 248681a5bbeSBoris Popov 249681a5bbeSBoris Popov smb_makescred(&scred, p, ap->a_cred); 250681a5bbeSBoris Popov 251681a5bbeSBoris Popov if (np->n_opencount == 0) { 252681a5bbeSBoris Popov SMBERROR("Negative opencount\n"); 253681a5bbeSBoris Popov return 0; 254681a5bbeSBoris Popov } 255681a5bbeSBoris Popov np->n_opencount--; 256681a5bbeSBoris Popov if (vp->v_type == VDIR) { 257681a5bbeSBoris Popov if (np->n_opencount) 258681a5bbeSBoris Popov return 0; 259681a5bbeSBoris Popov if (np->n_dirseq) { 260681a5bbeSBoris Popov smbfs_findclose(np->n_dirseq, &scred); 261681a5bbeSBoris Popov np->n_dirseq = NULL; 262681a5bbeSBoris Popov } 263681a5bbeSBoris Popov error = 0; 264681a5bbeSBoris Popov } else { 265681a5bbeSBoris Popov error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, p, 1); 266681a5bbeSBoris Popov if (np->n_opencount) 267681a5bbeSBoris Popov return error; 268681a5bbeSBoris Popov VOP_GETATTR(vp, &vattr, ap->a_cred, p); 269681a5bbeSBoris Popov error = smbfs_smb_close(np->n_mount->sm_share, np->n_fid, 270681a5bbeSBoris Popov &np->n_mtime, &scred); 271681a5bbeSBoris Popov } 272681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); 273681a5bbeSBoris Popov return error; 274681a5bbeSBoris Popov } 275681a5bbeSBoris Popov 276681a5bbeSBoris Popov /* 277681a5bbeSBoris Popov * XXX: VOP_CLOSE() usually called without lock held which is suck. Here we 278681a5bbeSBoris Popov * do some heruistic to determine if vnode should be locked. 279681a5bbeSBoris Popov */ 280681a5bbeSBoris Popov static int 281681a5bbeSBoris Popov smbfs_close(ap) 282681a5bbeSBoris Popov struct vop_close_args /* { 283681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 284681a5bbeSBoris Popov struct vnode *a_vp; 285681a5bbeSBoris Popov int a_fflag; 286681a5bbeSBoris Popov struct ucred *a_cred; 287681a5bbeSBoris Popov struct proc *a_p; 288681a5bbeSBoris Popov } */ *ap; 289681a5bbeSBoris Popov { 290681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 291681a5bbeSBoris Popov struct proc *p = ap->a_p; 292681a5bbeSBoris Popov int error, dolock; 293681a5bbeSBoris Popov 294681a5bbeSBoris Popov VI_LOCK(vp); 295681a5bbeSBoris Popov dolock = (vp->v_flag & VXLOCK) == 0; 296681a5bbeSBoris Popov if (dolock) 297681a5bbeSBoris Popov vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK, p); 298681a5bbeSBoris Popov else 299681a5bbeSBoris Popov VI_UNLOCK(vp); 300681a5bbeSBoris Popov error = smbfs_closel(ap); 301681a5bbeSBoris Popov if (dolock) 302681a5bbeSBoris Popov VOP_UNLOCK(vp, 0, p); 303681a5bbeSBoris Popov return error; 304681a5bbeSBoris Popov } 305681a5bbeSBoris Popov 306681a5bbeSBoris Popov /* 307681a5bbeSBoris Popov * smbfs_getattr call from vfs. 308681a5bbeSBoris Popov */ 309681a5bbeSBoris Popov static int 310681a5bbeSBoris Popov smbfs_getattr(ap) 311681a5bbeSBoris Popov struct vop_getattr_args /* { 312681a5bbeSBoris Popov struct vnode *a_vp; 313681a5bbeSBoris Popov struct vattr *a_vap; 314681a5bbeSBoris Popov struct ucred *a_cred; 315681a5bbeSBoris Popov struct proc *a_p; 316681a5bbeSBoris Popov } */ *ap; 317681a5bbeSBoris Popov { 318681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 319681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 320681a5bbeSBoris Popov struct vattr *va=ap->a_vap; 321681a5bbeSBoris Popov struct smbfattr fattr; 322681a5bbeSBoris Popov struct smb_cred scred; 323681a5bbeSBoris Popov u_int32_t oldsize; 324681a5bbeSBoris Popov int error; 325681a5bbeSBoris Popov 326681a5bbeSBoris Popov SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_flag & VROOT) != 0); 327681a5bbeSBoris Popov error = smbfs_attr_cachelookup(vp, va); 328681a5bbeSBoris Popov if (!error) 329681a5bbeSBoris Popov return 0; 330681a5bbeSBoris Popov SMBVDEBUG("not in the cache\n"); 331681a5bbeSBoris Popov smb_makescred(&scred, ap->a_p, ap->a_cred); 332681a5bbeSBoris Popov oldsize = np->n_size; 333681a5bbeSBoris Popov error = smbfs_smb_lookup(np, NULL, 0, &fattr, &scred); 334681a5bbeSBoris Popov if (error) { 335681a5bbeSBoris Popov SMBVDEBUG("error %d\n", error); 336681a5bbeSBoris Popov return error; 337681a5bbeSBoris Popov } 338681a5bbeSBoris Popov smbfs_attr_cacheenter(vp, &fattr); 339681a5bbeSBoris Popov smbfs_attr_cachelookup(vp, va); 340681a5bbeSBoris Popov if (np->n_opencount) 341681a5bbeSBoris Popov np->n_size = oldsize; 342681a5bbeSBoris Popov return 0; 343681a5bbeSBoris Popov } 344681a5bbeSBoris Popov 345681a5bbeSBoris Popov static int 346681a5bbeSBoris Popov smbfs_setattr(ap) 347681a5bbeSBoris Popov struct vop_setattr_args /* { 348681a5bbeSBoris Popov struct vnode *a_vp; 349681a5bbeSBoris Popov struct vattr *a_vap; 350681a5bbeSBoris Popov struct ucred *a_cred; 351681a5bbeSBoris Popov struct proc *a_p; 352681a5bbeSBoris Popov } */ *ap; 353681a5bbeSBoris Popov { 354681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 355681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 356681a5bbeSBoris Popov struct vattr *vap = ap->a_vap; 357681a5bbeSBoris Popov struct timespec *mtime, *atime; 358681a5bbeSBoris Popov struct smb_cred scred; 359681a5bbeSBoris Popov struct smb_share *ssp = np->n_mount->sm_share; 360681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(ssp); 361681a5bbeSBoris Popov u_quad_t tsize = 0; 362681a5bbeSBoris Popov int isreadonly, doclose, error = 0; 363681a5bbeSBoris Popov 364681a5bbeSBoris Popov SMBVDEBUG("\n"); 365681a5bbeSBoris Popov if (vap->va_flags != VNOVAL) 366681a5bbeSBoris Popov return EOPNOTSUPP; 367681a5bbeSBoris Popov isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY); 368681a5bbeSBoris Popov /* 369681a5bbeSBoris Popov * Disallow write attempts if the filesystem is mounted read-only. 370681a5bbeSBoris Popov */ 371681a5bbeSBoris Popov if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 372681a5bbeSBoris Popov vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL || 373681a5bbeSBoris Popov vap->va_mode != (mode_t)VNOVAL) && isreadonly) 374681a5bbeSBoris Popov return EROFS; 375681a5bbeSBoris Popov smb_makescred(&scred, ap->a_p, ap->a_cred); 376681a5bbeSBoris Popov if (vap->va_size != VNOVAL) { 377681a5bbeSBoris Popov switch (vp->v_type) { 378681a5bbeSBoris Popov case VDIR: 379681a5bbeSBoris Popov return EISDIR; 380681a5bbeSBoris Popov case VREG: 381681a5bbeSBoris Popov break; 382681a5bbeSBoris Popov default: 383681a5bbeSBoris Popov return EINVAL; 384681a5bbeSBoris Popov }; 385681a5bbeSBoris Popov if (isreadonly) 386681a5bbeSBoris Popov return EROFS; 387681a5bbeSBoris Popov doclose = 0; 388681a5bbeSBoris Popov vnode_pager_setsize(vp, (u_long)vap->va_size); 389681a5bbeSBoris Popov tsize = np->n_size; 390681a5bbeSBoris Popov np->n_size = vap->va_size; 391681a5bbeSBoris Popov if (np->n_opencount == 0) { 392681a5bbeSBoris Popov error = smbfs_smb_open(np, SMB_AM_OPENRW, &scred); 393681a5bbeSBoris Popov if (error == 0) 394681a5bbeSBoris Popov doclose = 1; 395681a5bbeSBoris Popov } 396681a5bbeSBoris Popov if (error == 0) 397681a5bbeSBoris Popov error = smbfs_smb_setfsize(np, vap->va_size, &scred); 398681a5bbeSBoris Popov if (doclose) 399681a5bbeSBoris Popov smbfs_smb_close(ssp, np->n_fid, NULL, &scred); 400681a5bbeSBoris Popov if (error) { 401681a5bbeSBoris Popov np->n_size = tsize; 402681a5bbeSBoris Popov vnode_pager_setsize(vp, (u_long)tsize); 403681a5bbeSBoris Popov return error; 404681a5bbeSBoris Popov } 405681a5bbeSBoris Popov } 406681a5bbeSBoris Popov mtime = atime = NULL; 407681a5bbeSBoris Popov if (vap->va_mtime.tv_sec != VNOVAL) 408681a5bbeSBoris Popov mtime = &vap->va_mtime; 409681a5bbeSBoris Popov if (vap->va_atime.tv_sec != VNOVAL) 410681a5bbeSBoris Popov atime = &vap->va_atime; 411681a5bbeSBoris Popov if (mtime != atime) { 412681a5bbeSBoris Popov #if 0 413681a5bbeSBoris Popov if (mtime == NULL) 414681a5bbeSBoris Popov mtime = &np->n_mtime; 415681a5bbeSBoris Popov if (atime == NULL) 416681a5bbeSBoris Popov atime = &np->n_atime; 417681a5bbeSBoris Popov #endif 418681a5bbeSBoris Popov /* 419681a5bbeSBoris Popov * If file is opened, then we can use handle based calls. 420681a5bbeSBoris Popov * If not, use path based ones. 421681a5bbeSBoris Popov */ 422681a5bbeSBoris Popov if (np->n_opencount == 0) { 423681a5bbeSBoris Popov if (vcp->vc_flags & SMBV_WIN95) { 424681a5bbeSBoris Popov error = VOP_OPEN(vp, FWRITE, ap->a_cred, ap->a_p); 425681a5bbeSBoris Popov if (!error) { 426681a5bbeSBoris Popov /* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 427681a5bbeSBoris Popov VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);*/ 428681a5bbeSBoris Popov if (mtime) 429681a5bbeSBoris Popov np->n_mtime = *mtime; 430681a5bbeSBoris Popov VOP_CLOSE(vp, FWRITE, ap->a_cred, ap->a_p); 431681a5bbeSBoris Popov } 432681a5bbeSBoris Popov } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { 433681a5bbeSBoris Popov error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 434681a5bbeSBoris Popov /* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred);*/ 435681a5bbeSBoris Popov } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { 436681a5bbeSBoris Popov error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred); 437681a5bbeSBoris Popov } else { 438681a5bbeSBoris Popov error = smbfs_smb_setpattr(np, 0, mtime, &scred); 439681a5bbeSBoris Popov } 440681a5bbeSBoris Popov } else { 441681a5bbeSBoris Popov if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { 442681a5bbeSBoris Popov error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred); 443681a5bbeSBoris Popov } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { 444681a5bbeSBoris Popov error = smbfs_smb_setftime(np, mtime, atime, &scred); 445681a5bbeSBoris Popov } else { 446681a5bbeSBoris Popov /* 447681a5bbeSBoris Popov * I have no idea how to handle this for core 448681a5bbeSBoris Popov * level servers. The possible solution is to 449681a5bbeSBoris Popov * update mtime after file is closed. 450681a5bbeSBoris Popov */ 451681a5bbeSBoris Popov SMBERROR("can't update times on an opened file\n"); 452681a5bbeSBoris Popov } 453681a5bbeSBoris Popov } 454681a5bbeSBoris Popov } 455681a5bbeSBoris Popov /* 456681a5bbeSBoris Popov * Invalidate attribute cache in case if server doesn't set 457681a5bbeSBoris Popov * required attributes. 458681a5bbeSBoris Popov */ 459681a5bbeSBoris Popov smbfs_attr_cacheremove(vp); /* invalidate cache */ 460681a5bbeSBoris Popov VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p); 461681a5bbeSBoris Popov np->n_mtime.tv_sec = vap->va_mtime.tv_sec; 462681a5bbeSBoris Popov return error; 463681a5bbeSBoris Popov } 464681a5bbeSBoris Popov /* 465681a5bbeSBoris Popov * smbfs_read call. 466681a5bbeSBoris Popov */ 467681a5bbeSBoris Popov static int 468681a5bbeSBoris Popov smbfs_read(ap) 469681a5bbeSBoris Popov struct vop_read_args /* { 470681a5bbeSBoris Popov struct vnode *a_vp; 471681a5bbeSBoris Popov struct uio *a_uio; 472681a5bbeSBoris Popov int a_ioflag; 473681a5bbeSBoris Popov struct ucred *a_cred; 474681a5bbeSBoris Popov } */ *ap; 475681a5bbeSBoris Popov { 476681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 477681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 478681a5bbeSBoris Popov 479681a5bbeSBoris Popov SMBVDEBUG("\n"); 480681a5bbeSBoris Popov if (vp->v_type != VREG && vp->v_type != VDIR) 481681a5bbeSBoris Popov return EPERM; 482681a5bbeSBoris Popov return smbfs_readvnode(vp, uio, ap->a_cred); 483681a5bbeSBoris Popov } 484681a5bbeSBoris Popov 485681a5bbeSBoris Popov static int 486681a5bbeSBoris Popov smbfs_write(ap) 487681a5bbeSBoris Popov struct vop_write_args /* { 488681a5bbeSBoris Popov struct vnode *a_vp; 489681a5bbeSBoris Popov struct uio *a_uio; 490681a5bbeSBoris Popov int a_ioflag; 491681a5bbeSBoris Popov struct ucred *a_cred; 492681a5bbeSBoris Popov } */ *ap; 493681a5bbeSBoris Popov { 494681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 495681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 496681a5bbeSBoris Popov 497681a5bbeSBoris Popov SMBVDEBUG("%d,ofs=%d,sz=%d\n",vp->v_type, (int)uio->uio_offset, uio->uio_resid); 498681a5bbeSBoris Popov if (vp->v_type != VREG) 499681a5bbeSBoris Popov return (EPERM); 500681a5bbeSBoris Popov return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag); 501681a5bbeSBoris Popov } 502681a5bbeSBoris Popov /* 503681a5bbeSBoris Popov * smbfs_create call 504681a5bbeSBoris Popov * Create a regular file. On entry the directory to contain the file being 505681a5bbeSBoris Popov * created is locked. We must release before we return. We must also free 506681a5bbeSBoris Popov * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or 507681a5bbeSBoris Popov * only if the SAVESTART bit in cn_flags is clear on success. 508681a5bbeSBoris Popov */ 509681a5bbeSBoris Popov static int 510681a5bbeSBoris Popov smbfs_create(ap) 511681a5bbeSBoris Popov struct vop_create_args /* { 512681a5bbeSBoris Popov struct vnode *a_dvp; 513681a5bbeSBoris Popov struct vnode **a_vpp; 514681a5bbeSBoris Popov struct componentname *a_cnp; 515681a5bbeSBoris Popov struct vattr *a_vap; 516681a5bbeSBoris Popov } */ *ap; 517681a5bbeSBoris Popov { 518681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 519681a5bbeSBoris Popov struct vattr *vap = ap->a_vap; 520681a5bbeSBoris Popov struct vnode **vpp=ap->a_vpp; 521681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 522681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 523681a5bbeSBoris Popov struct vnode *vp; 524681a5bbeSBoris Popov struct vattr vattr; 525681a5bbeSBoris Popov struct smbfattr fattr; 526681a5bbeSBoris Popov struct smb_cred scred; 527681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 528681a5bbeSBoris Popov int nmlen = cnp->cn_namelen; 529681a5bbeSBoris Popov int error; 530681a5bbeSBoris Popov 531681a5bbeSBoris Popov 532681a5bbeSBoris Popov SMBVDEBUG("\n"); 533681a5bbeSBoris Popov *vpp = NULL; 534681a5bbeSBoris Popov if (vap->va_type != VREG) 535681a5bbeSBoris Popov return EOPNOTSUPP; 536681a5bbeSBoris Popov if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) 537681a5bbeSBoris Popov return error; 538681a5bbeSBoris Popov smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred); 539681a5bbeSBoris Popov 540681a5bbeSBoris Popov error = smbfs_smb_create(dnp, name, nmlen, &scred); 541681a5bbeSBoris Popov if (error) 542681a5bbeSBoris Popov return error; 543681a5bbeSBoris Popov error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred); 544681a5bbeSBoris Popov if (error) 545681a5bbeSBoris Popov return error; 546681a5bbeSBoris Popov error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp); 547681a5bbeSBoris Popov if (error) 548681a5bbeSBoris Popov return error; 549681a5bbeSBoris Popov *vpp = vp; 550681a5bbeSBoris Popov if (cnp->cn_flags & MAKEENTRY) 551681a5bbeSBoris Popov cache_enter(dvp, vp, cnp); 552681a5bbeSBoris Popov return error; 553681a5bbeSBoris Popov } 554681a5bbeSBoris Popov 555681a5bbeSBoris Popov static int 556681a5bbeSBoris Popov smbfs_remove(ap) 557681a5bbeSBoris Popov struct vop_remove_args /* { 558681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 559681a5bbeSBoris Popov struct vnode * a_dvp; 560681a5bbeSBoris Popov struct vnode * a_vp; 561681a5bbeSBoris Popov struct componentname * a_cnp; 562681a5bbeSBoris Popov } */ *ap; 563681a5bbeSBoris Popov { 564681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 565681a5bbeSBoris Popov /* struct vnode *dvp = ap->a_dvp;*/ 566681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 567681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 568681a5bbeSBoris Popov struct smb_cred scred; 569681a5bbeSBoris Popov int error; 570681a5bbeSBoris Popov 571681a5bbeSBoris Popov if (vp->v_type == VDIR || np->n_opencount || vp->v_usecount != 1) 572681a5bbeSBoris Popov return EPERM; 573681a5bbeSBoris Popov smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred); 574681a5bbeSBoris Popov error = smbfs_smb_delete(np, &scred); 575681a5bbeSBoris Popov cache_purge(vp); 576681a5bbeSBoris Popov return error; 577681a5bbeSBoris Popov } 578681a5bbeSBoris Popov 579681a5bbeSBoris Popov /* 580681a5bbeSBoris Popov * smbfs_file rename call 581681a5bbeSBoris Popov */ 582681a5bbeSBoris Popov static int 583681a5bbeSBoris Popov smbfs_rename(ap) 584681a5bbeSBoris Popov struct vop_rename_args /* { 585681a5bbeSBoris Popov struct vnode *a_fdvp; 586681a5bbeSBoris Popov struct vnode *a_fvp; 587681a5bbeSBoris Popov struct componentname *a_fcnp; 588681a5bbeSBoris Popov struct vnode *a_tdvp; 589681a5bbeSBoris Popov struct vnode *a_tvp; 590681a5bbeSBoris Popov struct componentname *a_tcnp; 591681a5bbeSBoris Popov } */ *ap; 592681a5bbeSBoris Popov { 593681a5bbeSBoris Popov struct vnode *fvp = ap->a_fvp; 594681a5bbeSBoris Popov struct vnode *tvp = ap->a_tvp; 595681a5bbeSBoris Popov struct vnode *fdvp = ap->a_fdvp; 596681a5bbeSBoris Popov struct vnode *tdvp = ap->a_tdvp; 597681a5bbeSBoris Popov struct componentname *tcnp = ap->a_tcnp; 598681a5bbeSBoris Popov /* struct componentname *fcnp = ap->a_fcnp;*/ 599681a5bbeSBoris Popov struct smb_cred scred; 600681a5bbeSBoris Popov u_int16_t flags = 6; 601681a5bbeSBoris Popov int error=0; 602681a5bbeSBoris Popov 603681a5bbeSBoris Popov /* Check for cross-device rename */ 604681a5bbeSBoris Popov if ((fvp->v_mount != tdvp->v_mount) || 605681a5bbeSBoris Popov (tvp && (fvp->v_mount != tvp->v_mount))) { 606681a5bbeSBoris Popov error = EXDEV; 607681a5bbeSBoris Popov goto out; 608681a5bbeSBoris Popov } 609681a5bbeSBoris Popov 610681a5bbeSBoris Popov if (tvp && tvp->v_usecount > 1) { 611681a5bbeSBoris Popov error = EBUSY; 612681a5bbeSBoris Popov goto out; 613681a5bbeSBoris Popov } 614681a5bbeSBoris Popov flags = 0x10; /* verify all writes */ 615681a5bbeSBoris Popov if (fvp->v_type == VDIR) { 616681a5bbeSBoris Popov flags |= 2; 617681a5bbeSBoris Popov } else if (fvp->v_type == VREG) { 618681a5bbeSBoris Popov flags |= 1; 619681a5bbeSBoris Popov } else 620681a5bbeSBoris Popov return EINVAL; 621681a5bbeSBoris Popov smb_makescred(&scred, tcnp->cn_proc, tcnp->cn_cred); 622681a5bbeSBoris Popov /* 623681a5bbeSBoris Popov * It seems that Samba doesn't implement SMB_COM_MOVE call... 624681a5bbeSBoris Popov */ 625681a5bbeSBoris Popov #ifdef notnow 626681a5bbeSBoris Popov if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) { 627681a5bbeSBoris Popov error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp), 628681a5bbeSBoris Popov tcnp->cn_nameptr, tcnp->cn_namelen, flags, &scred); 629681a5bbeSBoris Popov } else 630681a5bbeSBoris Popov #endif 631681a5bbeSBoris Popov { 632681a5bbeSBoris Popov /* 633681a5bbeSBoris Popov * We have to do the work atomicaly 634681a5bbeSBoris Popov */ 635681a5bbeSBoris Popov if (tvp && tvp != fvp) { 636681a5bbeSBoris Popov error = smbfs_smb_delete(VTOSMB(tvp), &scred); 637681a5bbeSBoris Popov if (error) 638681a5bbeSBoris Popov goto out; 639681a5bbeSBoris Popov } 640681a5bbeSBoris Popov error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp), 641681a5bbeSBoris Popov tcnp->cn_nameptr, tcnp->cn_namelen, &scred); 642681a5bbeSBoris Popov } 643681a5bbeSBoris Popov 644681a5bbeSBoris Popov if (fvp->v_type == VDIR) { 645681a5bbeSBoris Popov if (tvp != NULL && tvp->v_type == VDIR) 646681a5bbeSBoris Popov cache_purge(tdvp); 647681a5bbeSBoris Popov cache_purge(fdvp); 648681a5bbeSBoris Popov } 649681a5bbeSBoris Popov out: 650681a5bbeSBoris Popov if (tdvp == tvp) 651681a5bbeSBoris Popov vrele(tdvp); 652681a5bbeSBoris Popov else 653681a5bbeSBoris Popov vput(tdvp); 654681a5bbeSBoris Popov if (tvp) 655681a5bbeSBoris Popov vput(tvp); 656681a5bbeSBoris Popov vrele(fdvp); 657681a5bbeSBoris Popov vrele(fvp); 658681a5bbeSBoris Popov smbfs_attr_cacheremove(fdvp); 659681a5bbeSBoris Popov smbfs_attr_cacheremove(tdvp); 660681a5bbeSBoris Popov #ifdef possible_mistake 661681a5bbeSBoris Popov vgone(fvp); 662681a5bbeSBoris Popov if (tvp) 663681a5bbeSBoris Popov vgone(tvp); 664681a5bbeSBoris Popov #endif 665681a5bbeSBoris Popov return error; 666681a5bbeSBoris Popov } 667681a5bbeSBoris Popov 668681a5bbeSBoris Popov /* 669681a5bbeSBoris Popov * somtime it will come true... 670681a5bbeSBoris Popov */ 671681a5bbeSBoris Popov static int 672681a5bbeSBoris Popov smbfs_link(ap) 673681a5bbeSBoris Popov struct vop_link_args /* { 674681a5bbeSBoris Popov struct vnode *a_tdvp; 675681a5bbeSBoris Popov struct vnode *a_vp; 676681a5bbeSBoris Popov struct componentname *a_cnp; 677681a5bbeSBoris Popov } */ *ap; 678681a5bbeSBoris Popov { 679681a5bbeSBoris Popov return EOPNOTSUPP; 680681a5bbeSBoris Popov } 681681a5bbeSBoris Popov 682681a5bbeSBoris Popov /* 683681a5bbeSBoris Popov * smbfs_symlink link create call. 684681a5bbeSBoris Popov * Sometime it will be functional... 685681a5bbeSBoris Popov */ 686681a5bbeSBoris Popov static int 687681a5bbeSBoris Popov smbfs_symlink(ap) 688681a5bbeSBoris Popov struct vop_symlink_args /* { 689681a5bbeSBoris Popov struct vnode *a_dvp; 690681a5bbeSBoris Popov struct vnode **a_vpp; 691681a5bbeSBoris Popov struct componentname *a_cnp; 692681a5bbeSBoris Popov struct vattr *a_vap; 693681a5bbeSBoris Popov char *a_target; 694681a5bbeSBoris Popov } */ *ap; 695681a5bbeSBoris Popov { 696681a5bbeSBoris Popov return EOPNOTSUPP; 697681a5bbeSBoris Popov } 698681a5bbeSBoris Popov 699681a5bbeSBoris Popov static int 700681a5bbeSBoris Popov smbfs_mknod(ap) 701681a5bbeSBoris Popov struct vop_mknod_args /* { 702681a5bbeSBoris Popov } */ *ap; 703681a5bbeSBoris Popov { 704681a5bbeSBoris Popov return EOPNOTSUPP; 705681a5bbeSBoris Popov } 706681a5bbeSBoris Popov 707681a5bbeSBoris Popov static int 708681a5bbeSBoris Popov smbfs_mkdir(ap) 709681a5bbeSBoris Popov struct vop_mkdir_args /* { 710681a5bbeSBoris Popov struct vnode *a_dvp; 711681a5bbeSBoris Popov struct vnode **a_vpp; 712681a5bbeSBoris Popov struct componentname *a_cnp; 713681a5bbeSBoris Popov struct vattr *a_vap; 714681a5bbeSBoris Popov } */ *ap; 715681a5bbeSBoris Popov { 716681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 717681a5bbeSBoris Popov /* struct vattr *vap = ap->a_vap;*/ 718681a5bbeSBoris Popov struct vnode *vp; 719681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 720681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 721681a5bbeSBoris Popov struct vattr vattr; 722681a5bbeSBoris Popov struct smb_cred scred; 723681a5bbeSBoris Popov struct smbfattr fattr; 724681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 725681a5bbeSBoris Popov int len = cnp->cn_namelen; 726681a5bbeSBoris Popov int error; 727681a5bbeSBoris Popov 728681a5bbeSBoris Popov if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) { 729681a5bbeSBoris Popov return error; 730681a5bbeSBoris Popov } 731681a5bbeSBoris Popov if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))) 732681a5bbeSBoris Popov return EEXIST; 733681a5bbeSBoris Popov smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred); 734681a5bbeSBoris Popov error = smbfs_smb_mkdir(dnp, name, len, &scred); 735681a5bbeSBoris Popov if (error) 736681a5bbeSBoris Popov return error; 737681a5bbeSBoris Popov error = smbfs_smb_lookup(dnp, name, len, &fattr, &scred); 738681a5bbeSBoris Popov if (error) 739681a5bbeSBoris Popov return error; 740681a5bbeSBoris Popov error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); 741681a5bbeSBoris Popov if (error) 742681a5bbeSBoris Popov return error; 743681a5bbeSBoris Popov *ap->a_vpp = vp; 744681a5bbeSBoris Popov return 0; 745681a5bbeSBoris Popov } 746681a5bbeSBoris Popov 747681a5bbeSBoris Popov /* 748681a5bbeSBoris Popov * smbfs_remove directory call 749681a5bbeSBoris Popov */ 750681a5bbeSBoris Popov static int 751681a5bbeSBoris Popov smbfs_rmdir(ap) 752681a5bbeSBoris Popov struct vop_rmdir_args /* { 753681a5bbeSBoris Popov struct vnode *a_dvp; 754681a5bbeSBoris Popov struct vnode *a_vp; 755681a5bbeSBoris Popov struct componentname *a_cnp; 756681a5bbeSBoris Popov } */ *ap; 757681a5bbeSBoris Popov { 758681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 759681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 760681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 761681a5bbeSBoris Popov /* struct smbmount *smp = VTOSMBFS(vp);*/ 762681a5bbeSBoris Popov struct smbnode *dnp = VTOSMB(dvp); 763681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 764681a5bbeSBoris Popov struct smb_cred scred; 765681a5bbeSBoris Popov int error; 766681a5bbeSBoris Popov 767681a5bbeSBoris Popov if (dvp == vp) 768681a5bbeSBoris Popov return EINVAL; 769681a5bbeSBoris Popov 770681a5bbeSBoris Popov smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred); 771681a5bbeSBoris Popov error = smbfs_smb_rmdir(np, &scred); 772681a5bbeSBoris Popov dnp->n_flag |= NMODIFIED; 773681a5bbeSBoris Popov smbfs_attr_cacheremove(dvp); 774681a5bbeSBoris Popov /* cache_purge(dvp);*/ 775681a5bbeSBoris Popov cache_purge(vp); 776681a5bbeSBoris Popov return error; 777681a5bbeSBoris Popov } 778681a5bbeSBoris Popov 779681a5bbeSBoris Popov /* 780681a5bbeSBoris Popov * smbfs_readdir call 781681a5bbeSBoris Popov */ 782681a5bbeSBoris Popov static int 783681a5bbeSBoris Popov smbfs_readdir(ap) 784681a5bbeSBoris Popov struct vop_readdir_args /* { 785681a5bbeSBoris Popov struct vnode *a_vp; 786681a5bbeSBoris Popov struct uio *a_uio; 787681a5bbeSBoris Popov struct ucred *a_cred; 788681a5bbeSBoris Popov int *a_eofflag; 789681a5bbeSBoris Popov u_long *a_cookies; 790681a5bbeSBoris Popov int a_ncookies; 791681a5bbeSBoris Popov } */ *ap; 792681a5bbeSBoris Popov { 793681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 794681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 795681a5bbeSBoris Popov int error; 796681a5bbeSBoris Popov 797681a5bbeSBoris Popov if (vp->v_type != VDIR) 798681a5bbeSBoris Popov return (EPERM); 799681a5bbeSBoris Popov #ifdef notnow 800681a5bbeSBoris Popov if (ap->a_ncookies) { 801681a5bbeSBoris Popov printf("smbfs_readdir: no support for cookies now..."); 802681a5bbeSBoris Popov return (EOPNOTSUPP); 803681a5bbeSBoris Popov } 804681a5bbeSBoris Popov #endif 805681a5bbeSBoris Popov error = smbfs_readvnode(vp, uio, ap->a_cred); 806681a5bbeSBoris Popov return error; 807681a5bbeSBoris Popov } 808681a5bbeSBoris Popov 809681a5bbeSBoris Popov /* ARGSUSED */ 810681a5bbeSBoris Popov static int 811681a5bbeSBoris Popov smbfs_fsync(ap) 812681a5bbeSBoris Popov struct vop_fsync_args /* { 813681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 814681a5bbeSBoris Popov struct vnode * a_vp; 815681a5bbeSBoris Popov struct ucred * a_cred; 816681a5bbeSBoris Popov int a_waitfor; 817681a5bbeSBoris Popov struct proc * a_p; 818681a5bbeSBoris Popov } */ *ap; 819681a5bbeSBoris Popov { 820681a5bbeSBoris Popov /* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));*/ 821681a5bbeSBoris Popov return (0); 822681a5bbeSBoris Popov } 823681a5bbeSBoris Popov 824681a5bbeSBoris Popov static 825681a5bbeSBoris Popov int smbfs_print (ap) 826681a5bbeSBoris Popov struct vop_print_args /* { 827681a5bbeSBoris Popov struct vnode *a_vp; 828681a5bbeSBoris Popov } */ *ap; 829681a5bbeSBoris Popov { 830681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 831681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 832681a5bbeSBoris Popov 833681a5bbeSBoris Popov if (np == NULL) { 834681a5bbeSBoris Popov printf("no smbnode data\n"); 835681a5bbeSBoris Popov return (0); 836681a5bbeSBoris Popov } 837681a5bbeSBoris Popov printf("tag VT_SMBFS, name = %s, parent = %p, opencount = %d", 838681a5bbeSBoris Popov np->n_name, np->n_parent ? SMBTOV(np->n_parent) : NULL, 839681a5bbeSBoris Popov np->n_opencount); 840681a5bbeSBoris Popov lockmgr_printinfo(&vp->v_lock); 841681a5bbeSBoris Popov printf("\n"); 842681a5bbeSBoris Popov return (0); 843681a5bbeSBoris Popov } 844681a5bbeSBoris Popov 845681a5bbeSBoris Popov static int 846681a5bbeSBoris Popov smbfs_pathconf (ap) 847681a5bbeSBoris Popov struct vop_pathconf_args /* { 848681a5bbeSBoris Popov struct vnode *vp; 849681a5bbeSBoris Popov int name; 850681a5bbeSBoris Popov register_t *retval; 851681a5bbeSBoris Popov } */ *ap; 852681a5bbeSBoris Popov { 853681a5bbeSBoris Popov struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp)); 854681a5bbeSBoris Popov struct smb_vc *vcp = SSTOVC(smp->sm_share); 855681a5bbeSBoris Popov register_t *retval = ap->a_retval; 856681a5bbeSBoris Popov int error = 0; 857681a5bbeSBoris Popov 858681a5bbeSBoris Popov switch (ap->a_name) { 859681a5bbeSBoris Popov case _PC_LINK_MAX: 860681a5bbeSBoris Popov *retval = 0; 861681a5bbeSBoris Popov break; 862681a5bbeSBoris Popov case _PC_NAME_MAX: 8633419dc99SBoris Popov *retval = (vcp->vc_hflags2 & SMB_FLAGS2_KNOWS_LONG_NAMES) ? 255 : 12; 864681a5bbeSBoris Popov break; 865681a5bbeSBoris Popov case _PC_PATH_MAX: 866681a5bbeSBoris Popov *retval = 800; /* XXX: a correct one ? */ 867681a5bbeSBoris Popov break; 868681a5bbeSBoris Popov default: 869681a5bbeSBoris Popov error = EINVAL; 870681a5bbeSBoris Popov } 871681a5bbeSBoris Popov return error; 872681a5bbeSBoris Popov } 873681a5bbeSBoris Popov 874681a5bbeSBoris Popov static int 875681a5bbeSBoris Popov smbfs_strategy (ap) 876681a5bbeSBoris Popov struct vop_strategy_args /* { 877681a5bbeSBoris Popov struct buf *a_bp 878681a5bbeSBoris Popov } */ *ap; 879681a5bbeSBoris Popov { 880681a5bbeSBoris Popov struct buf *bp=ap->a_bp; 881681a5bbeSBoris Popov struct ucred *cr; 882681a5bbeSBoris Popov struct proc *p; 883681a5bbeSBoris Popov int error = 0; 884681a5bbeSBoris Popov 885681a5bbeSBoris Popov SMBVDEBUG("\n"); 886681a5bbeSBoris Popov if (bp->b_flags & B_PHYS) 887681a5bbeSBoris Popov panic("smbfs physio"); 888681a5bbeSBoris Popov if (bp->b_flags & B_ASYNC) 889681a5bbeSBoris Popov p = (struct proc *)0; 890681a5bbeSBoris Popov else 891681a5bbeSBoris Popov p = curproc; /* XXX */ 892681a5bbeSBoris Popov if (bp->b_iocmd == BIO_READ) 893681a5bbeSBoris Popov cr = bp->b_rcred; 894681a5bbeSBoris Popov else 895681a5bbeSBoris Popov cr = bp->b_wcred; 896681a5bbeSBoris Popov 897681a5bbeSBoris Popov if ((bp->b_flags & B_ASYNC) == 0 ) 898681a5bbeSBoris Popov error = smbfs_doio(bp, cr, p); 899681a5bbeSBoris Popov return error; 900681a5bbeSBoris Popov } 901681a5bbeSBoris Popov 902681a5bbeSBoris Popov int 903681a5bbeSBoris Popov smbfs_ioctl(ap) 904681a5bbeSBoris Popov struct vop_ioctl_args /* { 905681a5bbeSBoris Popov struct vnode *a_vp; 906681a5bbeSBoris Popov u_long a_command; 907681a5bbeSBoris Popov caddr_t a_data; 908681a5bbeSBoris Popov int fflag; 909681a5bbeSBoris Popov struct ucred *cred; 910681a5bbeSBoris Popov struct proc *p; 911681a5bbeSBoris Popov } */ *ap; 912681a5bbeSBoris Popov { 913681a5bbeSBoris Popov return EINVAL; 914681a5bbeSBoris Popov } 915681a5bbeSBoris Popov 916681a5bbeSBoris Popov static char smbfs_atl[] = "rhsvda"; 917681a5bbeSBoris Popov static int 918681a5bbeSBoris Popov smbfs_getextattr(struct vop_getextattr_args *ap) 919681a5bbeSBoris Popov /* { 920681a5bbeSBoris Popov IN struct vnode *a_vp; 921681a5bbeSBoris Popov IN char *a_name; 922681a5bbeSBoris Popov INOUT struct uio *a_uio; 923681a5bbeSBoris Popov IN struct ucred *a_cred; 924681a5bbeSBoris Popov IN struct proc *a_p; 925681a5bbeSBoris Popov }; 926681a5bbeSBoris Popov */ 927681a5bbeSBoris Popov { 928681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 929681a5bbeSBoris Popov struct proc *p = ap->a_p; 930681a5bbeSBoris Popov struct ucred *cred = ap->a_cred; 931681a5bbeSBoris Popov struct uio *uio = ap->a_uio; 932681a5bbeSBoris Popov const char *name = ap->a_name; 933681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 934681a5bbeSBoris Popov struct vattr vattr; 935681a5bbeSBoris Popov char buf[10]; 936681a5bbeSBoris Popov int i, attr, error; 937681a5bbeSBoris Popov 938681a5bbeSBoris Popov error = VOP_ACCESS(vp, VREAD, cred, p); 939681a5bbeSBoris Popov if (error) 940681a5bbeSBoris Popov return error; 941681a5bbeSBoris Popov error = VOP_GETATTR(vp, &vattr, cred, p); 942681a5bbeSBoris Popov if (error) 943681a5bbeSBoris Popov return error; 944681a5bbeSBoris Popov if (strcmp(name, "dosattr") == 0) { 945681a5bbeSBoris Popov attr = np->n_dosattr; 946681a5bbeSBoris Popov for (i = 0; i < 6; i++, attr >>= 1) 947681a5bbeSBoris Popov buf[i] = (attr & 1) ? smbfs_atl[i] : '-'; 948681a5bbeSBoris Popov buf[i] = 0; 949681a5bbeSBoris Popov error = uiomove(buf, i, uio); 950681a5bbeSBoris Popov 951681a5bbeSBoris Popov } else 952681a5bbeSBoris Popov error = EINVAL; 953681a5bbeSBoris Popov return error; 954681a5bbeSBoris Popov } 955681a5bbeSBoris Popov 956681a5bbeSBoris Popov /* 957681a5bbeSBoris Popov * Since we expected to support F_GETLK (and SMB protocol has no such function), 958681a5bbeSBoris Popov * it is necessary to use lf_advlock(). It would be nice if this function had 959681a5bbeSBoris Popov * a callback mechanism because it will help to improve a level of consistency. 960681a5bbeSBoris Popov */ 961681a5bbeSBoris Popov int 962681a5bbeSBoris Popov smbfs_advlock(ap) 963681a5bbeSBoris Popov struct vop_advlock_args /* { 964681a5bbeSBoris Popov struct vnode *a_vp; 965681a5bbeSBoris Popov caddr_t a_id; 966681a5bbeSBoris Popov int a_op; 967681a5bbeSBoris Popov struct flock *a_fl; 968681a5bbeSBoris Popov int a_flags; 969681a5bbeSBoris Popov } */ *ap; 970681a5bbeSBoris Popov { 971681a5bbeSBoris Popov struct vnode *vp = ap->a_vp; 972681a5bbeSBoris Popov struct smbnode *np = VTOSMB(vp); 973681a5bbeSBoris Popov struct flock *fl = ap->a_fl; 974681a5bbeSBoris Popov caddr_t id = (caddr_t)1 /* ap->a_id */; 975681a5bbeSBoris Popov /* int flags = ap->a_flags;*/ 976681a5bbeSBoris Popov struct proc *p = curproc; 977681a5bbeSBoris Popov struct smb_cred scred; 97847790174SAndrey A. Chernov u_quad_t size; 97947790174SAndrey A. Chernov off_t start, end; 980681a5bbeSBoris Popov int error, lkop; 981681a5bbeSBoris Popov 98247790174SAndrey A. Chernov if (fl->l_len < 0) 98347790174SAndrey A. Chernov return EINVAL; 984681a5bbeSBoris Popov if (vp->v_type == VDIR) { 985681a5bbeSBoris Popov /* 986681a5bbeSBoris Popov * SMB protocol have no support for directory locking. 987681a5bbeSBoris Popov * Although locks can be processed on local machine, I don't 988681a5bbeSBoris Popov * think that this is a good idea, because some programs 989681a5bbeSBoris Popov * can work wrong assuming directory is locked. So, we just 990681a5bbeSBoris Popov * return 'operation not supported 991681a5bbeSBoris Popov */ 992681a5bbeSBoris Popov return EOPNOTSUPP; 993681a5bbeSBoris Popov } 994681a5bbeSBoris Popov size = np->n_size; 995681a5bbeSBoris Popov switch (fl->l_whence) { 996681a5bbeSBoris Popov case SEEK_SET: 997681a5bbeSBoris Popov case SEEK_CUR: 998681a5bbeSBoris Popov start = fl->l_start; 999681a5bbeSBoris Popov break; 1000681a5bbeSBoris Popov case SEEK_END: 100147790174SAndrey A. Chernov /* size always >= 0 */ 100247790174SAndrey A. Chernov if (fl->l_start > 0 && size > OFF_MAX - fl->l_start) 100347790174SAndrey A. Chernov return EOVERFLOW; 1004681a5bbeSBoris Popov start = fl->l_start + size; 1005681a5bbeSBoris Popov default: 1006681a5bbeSBoris Popov return EINVAL; 1007681a5bbeSBoris Popov } 1008681a5bbeSBoris Popov if (start < 0) 1009681a5bbeSBoris Popov return EINVAL; 1010681a5bbeSBoris Popov if (fl->l_len == 0) 1011681a5bbeSBoris Popov end = -1; 1012681a5bbeSBoris Popov else { 101347790174SAndrey A. Chernov off_t oadd = fl->l_len - 1; 101447790174SAndrey A. Chernov 101547790174SAndrey A. Chernov /* fl->l_len & start are non-negative */ 101647790174SAndrey A. Chernov if (oadd > OFF_MAX - start) 101747790174SAndrey A. Chernov return EOVERFLOW; 101847790174SAndrey A. Chernov end = start + oadd; 1019681a5bbeSBoris Popov if (end < start) 1020681a5bbeSBoris Popov return EINVAL; 1021681a5bbeSBoris Popov } 1022681a5bbeSBoris Popov smb_makescred(&scred, p, p ? p->p_ucred : NULL); 1023681a5bbeSBoris Popov switch (ap->a_op) { 1024681a5bbeSBoris Popov case F_SETLK: 1025681a5bbeSBoris Popov switch (fl->l_type) { 1026681a5bbeSBoris Popov case F_WRLCK: 1027681a5bbeSBoris Popov lkop = SMB_LOCK_EXCL; 1028681a5bbeSBoris Popov break; 1029681a5bbeSBoris Popov case F_RDLCK: 1030681a5bbeSBoris Popov lkop = SMB_LOCK_SHARED; 1031681a5bbeSBoris Popov break; 1032681a5bbeSBoris Popov case F_UNLCK: 1033681a5bbeSBoris Popov lkop = SMB_LOCK_RELEASE; 1034681a5bbeSBoris Popov break; 1035681a5bbeSBoris Popov default: 1036681a5bbeSBoris Popov return EINVAL; 1037681a5bbeSBoris Popov } 1038681a5bbeSBoris Popov error = lf_advlock(ap, &np->n_lockf, size); 1039681a5bbeSBoris Popov if (error) 1040681a5bbeSBoris Popov break; 1041681a5bbeSBoris Popov lkop = SMB_LOCK_EXCL; 1042681a5bbeSBoris Popov error = smbfs_smb_lock(np, lkop, id, start, end, &scred); 1043681a5bbeSBoris Popov if (error) { 1044681a5bbeSBoris Popov ap->a_op = F_UNLCK; 1045681a5bbeSBoris Popov lf_advlock(ap, &np->n_lockf, size); 1046681a5bbeSBoris Popov } 1047681a5bbeSBoris Popov break; 1048681a5bbeSBoris Popov case F_UNLCK: 1049681a5bbeSBoris Popov lf_advlock(ap, &np->n_lockf, size); 1050681a5bbeSBoris Popov error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, &scred); 1051681a5bbeSBoris Popov break; 1052681a5bbeSBoris Popov case F_GETLK: 1053681a5bbeSBoris Popov error = lf_advlock(ap, &np->n_lockf, size); 1054681a5bbeSBoris Popov break; 1055681a5bbeSBoris Popov default: 1056681a5bbeSBoris Popov return EINVAL; 1057681a5bbeSBoris Popov } 1058681a5bbeSBoris Popov return error; 1059681a5bbeSBoris Popov } 1060681a5bbeSBoris Popov 1061681a5bbeSBoris Popov static int 1062681a5bbeSBoris Popov smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop) 1063681a5bbeSBoris Popov { 1064681a5bbeSBoris Popov static const char *badchars = "*/\[]:<>=;?"; 1065681a5bbeSBoris Popov static const char *badchars83 = " +|,"; 1066681a5bbeSBoris Popov const char *cp; 1067681a5bbeSBoris Popov int i, error; 1068681a5bbeSBoris Popov 1069681a5bbeSBoris Popov if (nameiop == LOOKUP) 1070681a5bbeSBoris Popov return 0; 1071681a5bbeSBoris Popov error = ENOENT; 1072681a5bbeSBoris Popov if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) { 1073681a5bbeSBoris Popov /* 1074681a5bbeSBoris Popov * Name should conform 8.3 format 1075681a5bbeSBoris Popov */ 1076681a5bbeSBoris Popov if (nmlen > 12) 1077681a5bbeSBoris Popov return ENAMETOOLONG; 1078681a5bbeSBoris Popov cp = index(name, '.'); 1079681a5bbeSBoris Popov if (cp == NULL) 1080681a5bbeSBoris Popov return error; 1081681a5bbeSBoris Popov if (cp == name || (cp - name) > 8) 1082681a5bbeSBoris Popov return error; 1083681a5bbeSBoris Popov cp = index(cp + 1, '.'); 1084681a5bbeSBoris Popov if (cp != NULL) 1085681a5bbeSBoris Popov return error; 1086681a5bbeSBoris Popov for (cp = name, i = 0; i < nmlen; i++, cp++) 1087681a5bbeSBoris Popov if (index(badchars83, *cp) != NULL) 1088681a5bbeSBoris Popov return error; 1089681a5bbeSBoris Popov } 1090681a5bbeSBoris Popov for (cp = name, i = 0; i < nmlen; i++, cp++) 1091681a5bbeSBoris Popov if (index(badchars, *cp) != NULL) 1092681a5bbeSBoris Popov return error; 1093681a5bbeSBoris Popov return 0; 1094681a5bbeSBoris Popov } 1095681a5bbeSBoris Popov 1096681a5bbeSBoris Popov #ifndef PDIRUNLOCK 1097681a5bbeSBoris Popov #define PDIRUNLOCK 0 1098681a5bbeSBoris Popov #endif 1099681a5bbeSBoris Popov 1100681a5bbeSBoris Popov /* 1101681a5bbeSBoris Popov * Things go even weird without fixed inode numbers... 1102681a5bbeSBoris Popov */ 1103681a5bbeSBoris Popov int 1104681a5bbeSBoris Popov smbfs_lookup(ap) 1105681a5bbeSBoris Popov struct vop_lookup_args /* { 1106681a5bbeSBoris Popov struct vnodeop_desc *a_desc; 1107681a5bbeSBoris Popov struct vnode *a_dvp; 1108681a5bbeSBoris Popov struct vnode **a_vpp; 1109681a5bbeSBoris Popov struct componentname *a_cnp; 1110681a5bbeSBoris Popov } */ *ap; 1111681a5bbeSBoris Popov { 1112681a5bbeSBoris Popov struct componentname *cnp = ap->a_cnp; 1113681a5bbeSBoris Popov struct proc *p = cnp->cn_proc; 1114681a5bbeSBoris Popov struct vnode *dvp = ap->a_dvp; 1115681a5bbeSBoris Popov struct vnode **vpp = ap->a_vpp; 1116681a5bbeSBoris Popov struct vnode *vp; 1117681a5bbeSBoris Popov struct smbmount *smp; 1118681a5bbeSBoris Popov struct mount *mp = dvp->v_mount; 1119681a5bbeSBoris Popov struct smbnode *dnp; 1120681a5bbeSBoris Popov struct smbfattr fattr, *fap; 1121681a5bbeSBoris Popov struct smb_cred scred; 1122681a5bbeSBoris Popov char *name = cnp->cn_nameptr; 1123681a5bbeSBoris Popov int flags = cnp->cn_flags; 1124681a5bbeSBoris Popov int nameiop = cnp->cn_nameiop; 1125681a5bbeSBoris Popov int nmlen = cnp->cn_namelen; 1126681a5bbeSBoris Popov int lockparent, wantparent, error, islastcn, isdot; 1127681a5bbeSBoris Popov 1128681a5bbeSBoris Popov SMBVDEBUG("\n"); 1129681a5bbeSBoris Popov cnp->cn_flags &= ~PDIRUNLOCK; 1130681a5bbeSBoris Popov if (dvp->v_type != VDIR) 1131681a5bbeSBoris Popov return ENOTDIR; 1132681a5bbeSBoris Popov if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT)) { 1133681a5bbeSBoris Popov SMBFSERR("invalid '..'\n"); 1134681a5bbeSBoris Popov return EIO; 1135681a5bbeSBoris Popov } 1136681a5bbeSBoris Popov #ifdef SMB_VNODE_DEBUG 1137681a5bbeSBoris Popov { 1138681a5bbeSBoris Popov char *cp, c; 1139681a5bbeSBoris Popov 1140681a5bbeSBoris Popov cp = name + nmlen; 1141681a5bbeSBoris Popov c = *cp; 1142681a5bbeSBoris Popov *cp = 0; 1143681a5bbeSBoris Popov SMBVDEBUG("%d '%s' in '%s' id=d\n", nameiop, name, 1144681a5bbeSBoris Popov VTOSMB(dvp)->n_name); 1145681a5bbeSBoris Popov *cp = c; 1146681a5bbeSBoris Popov } 1147681a5bbeSBoris Popov #endif 1148681a5bbeSBoris Popov islastcn = flags & ISLASTCN; 1149681a5bbeSBoris Popov if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP)) 1150681a5bbeSBoris Popov return EROFS; 1151681a5bbeSBoris Popov if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p)) != 0) 1152681a5bbeSBoris Popov return error; 1153681a5bbeSBoris Popov lockparent = flags & LOCKPARENT; 1154681a5bbeSBoris Popov wantparent = flags & (LOCKPARENT|WANTPARENT); 1155681a5bbeSBoris Popov smp = VFSTOSMBFS(mp); 1156681a5bbeSBoris Popov dnp = VTOSMB(dvp); 1157681a5bbeSBoris Popov isdot = (nmlen == 1 && name[0] == '.'); 1158681a5bbeSBoris Popov 1159681a5bbeSBoris Popov error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop); 1160681a5bbeSBoris Popov 1161681a5bbeSBoris Popov if (error) 1162681a5bbeSBoris Popov return ENOENT; 1163681a5bbeSBoris Popov 1164681a5bbeSBoris Popov error = cache_lookup(dvp, vpp, cnp); 1165681a5bbeSBoris Popov SMBVDEBUG("cache_lookup returned %d\n", error); 1166681a5bbeSBoris Popov if (error > 0) 1167681a5bbeSBoris Popov return error; 1168681a5bbeSBoris Popov if (error) { /* name was found */ 1169681a5bbeSBoris Popov struct vattr vattr; 1170681a5bbeSBoris Popov int vpid; 1171681a5bbeSBoris Popov 1172681a5bbeSBoris Popov vp = *vpp; 1173681a5bbeSBoris Popov vpid = vp->v_id; 1174681a5bbeSBoris Popov if (dvp == vp) { /* lookup on current */ 1175681a5bbeSBoris Popov vref(vp); 1176681a5bbeSBoris Popov error = 0; 1177681a5bbeSBoris Popov SMBVDEBUG("cached '.'\n"); 1178681a5bbeSBoris Popov } else if (flags & ISDOTDOT) { 1179681a5bbeSBoris Popov VOP_UNLOCK(dvp, 0, p); /* unlock parent */ 1180681a5bbeSBoris Popov cnp->cn_flags |= PDIRUNLOCK; 1181681a5bbeSBoris Popov error = vget(vp, LK_EXCLUSIVE, p); 1182681a5bbeSBoris Popov if (!error && lockparent && islastcn) { 1183681a5bbeSBoris Popov error = vn_lock(dvp, LK_EXCLUSIVE, p); 1184681a5bbeSBoris Popov if (error == 0) 1185681a5bbeSBoris Popov cnp->cn_flags &= ~PDIRUNLOCK; 1186681a5bbeSBoris Popov } 1187681a5bbeSBoris Popov } else { 1188681a5bbeSBoris Popov error = vget(vp, LK_EXCLUSIVE, p); 1189681a5bbeSBoris Popov if (!lockparent || error || !islastcn) { 1190681a5bbeSBoris Popov VOP_UNLOCK(dvp, 0, p); 1191681a5bbeSBoris Popov cnp->cn_flags |= PDIRUNLOCK; 1192681a5bbeSBoris Popov } 1193681a5bbeSBoris Popov } 1194681a5bbeSBoris Popov if (!error) { 1195681a5bbeSBoris Popov if (vpid == vp->v_id) { 1196681a5bbeSBoris Popov if (!VOP_GETATTR(vp, &vattr, cnp->cn_cred, p) 1197681a5bbeSBoris Popov /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) { 1198681a5bbeSBoris Popov if (nameiop != LOOKUP && islastcn) 1199681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1200681a5bbeSBoris Popov SMBVDEBUG("use cached vnode\n"); 1201681a5bbeSBoris Popov return (0); 1202681a5bbeSBoris Popov } 1203681a5bbeSBoris Popov cache_purge(vp); 1204681a5bbeSBoris Popov } 1205681a5bbeSBoris Popov vput(vp); 1206681a5bbeSBoris Popov if (lockparent && dvp != vp && islastcn) 1207681a5bbeSBoris Popov VOP_UNLOCK(dvp, 0, p); 1208681a5bbeSBoris Popov } 1209681a5bbeSBoris Popov error = vn_lock(dvp, LK_EXCLUSIVE, p); 1210681a5bbeSBoris Popov *vpp = NULLVP; 1211681a5bbeSBoris Popov if (error) { 1212681a5bbeSBoris Popov cnp->cn_flags |= PDIRUNLOCK; 1213681a5bbeSBoris Popov return (error); 1214681a5bbeSBoris Popov } 1215681a5bbeSBoris Popov cnp->cn_flags &= ~PDIRUNLOCK; 1216681a5bbeSBoris Popov } 1217681a5bbeSBoris Popov /* 1218681a5bbeSBoris Popov * entry is not in the cache or has been expired 1219681a5bbeSBoris Popov */ 1220681a5bbeSBoris Popov error = 0; 1221681a5bbeSBoris Popov *vpp = NULLVP; 1222681a5bbeSBoris Popov smb_makescred(&scred, p, cnp->cn_cred); 1223681a5bbeSBoris Popov fap = &fattr; 1224681a5bbeSBoris Popov if (flags & ISDOTDOT) { 1225681a5bbeSBoris Popov error = smbfs_smb_lookup(dnp->n_parent, NULL, 0, fap, &scred); 1226681a5bbeSBoris Popov SMBVDEBUG("result of dotdot lookup: %d\n", error); 1227681a5bbeSBoris Popov } else { 1228681a5bbeSBoris Popov fap = &fattr; 1229681a5bbeSBoris Popov error = smbfs_smb_lookup(dnp, name, nmlen, fap, &scred); 1230681a5bbeSBoris Popov /* if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')*/ 1231681a5bbeSBoris Popov SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error); 1232681a5bbeSBoris Popov } 1233681a5bbeSBoris Popov if (error && error != ENOENT) 1234681a5bbeSBoris Popov return error; 1235681a5bbeSBoris Popov if (error) { /* entry not found */ 1236681a5bbeSBoris Popov /* 1237681a5bbeSBoris Popov * Handle RENAME or CREATE case... 1238681a5bbeSBoris Popov */ 1239681a5bbeSBoris Popov if ((nameiop == CREATE || nameiop == RENAME) && wantparent && islastcn) { 1240681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1241681a5bbeSBoris Popov if (!lockparent) { 1242681a5bbeSBoris Popov VOP_UNLOCK(dvp, 0, p); 1243681a5bbeSBoris Popov cnp->cn_flags |= PDIRUNLOCK; 1244681a5bbeSBoris Popov } 1245681a5bbeSBoris Popov return (EJUSTRETURN); 1246681a5bbeSBoris Popov } 1247681a5bbeSBoris Popov return ENOENT; 1248681a5bbeSBoris Popov }/* else { 1249681a5bbeSBoris Popov SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); 1250681a5bbeSBoris Popov }*/ 1251681a5bbeSBoris Popov /* 1252681a5bbeSBoris Popov * handle DELETE case ... 1253681a5bbeSBoris Popov */ 1254681a5bbeSBoris Popov if (nameiop == DELETE && islastcn) { /* delete last component */ 1255681a5bbeSBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p); 1256681a5bbeSBoris Popov if (error) 1257681a5bbeSBoris Popov return error; 1258681a5bbeSBoris Popov if (isdot) { 1259681a5bbeSBoris Popov VREF(dvp); 1260681a5bbeSBoris Popov *vpp = dvp; 1261681a5bbeSBoris Popov return 0; 1262681a5bbeSBoris Popov } 1263681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1264681a5bbeSBoris Popov if (error) 1265681a5bbeSBoris Popov return error; 1266681a5bbeSBoris Popov *vpp = vp; 1267681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1268681a5bbeSBoris Popov if (!lockparent) { 1269681a5bbeSBoris Popov VOP_UNLOCK(dvp, 0, p); 1270681a5bbeSBoris Popov cnp->cn_flags |= PDIRUNLOCK; 1271681a5bbeSBoris Popov } 1272681a5bbeSBoris Popov return 0; 1273681a5bbeSBoris Popov } 1274681a5bbeSBoris Popov if (nameiop == RENAME && islastcn && wantparent) { 1275681a5bbeSBoris Popov error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p); 1276681a5bbeSBoris Popov if (error) 1277681a5bbeSBoris Popov return error; 1278681a5bbeSBoris Popov if (isdot) 1279681a5bbeSBoris Popov return EISDIR; 1280681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1281681a5bbeSBoris Popov if (error) 1282681a5bbeSBoris Popov return error; 1283681a5bbeSBoris Popov *vpp = vp; 1284681a5bbeSBoris Popov cnp->cn_flags |= SAVENAME; 1285681a5bbeSBoris Popov if (!lockparent) { 1286681a5bbeSBoris Popov VOP_UNLOCK(dvp, 0, p); 1287681a5bbeSBoris Popov cnp->cn_flags |= PDIRUNLOCK; 1288681a5bbeSBoris Popov } 1289681a5bbeSBoris Popov return 0; 1290681a5bbeSBoris Popov } 1291681a5bbeSBoris Popov if (flags & ISDOTDOT) { 1292681a5bbeSBoris Popov VOP_UNLOCK(dvp, 0, p); 1293681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp); 1294681a5bbeSBoris Popov if (error) { 1295681a5bbeSBoris Popov vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p); 1296681a5bbeSBoris Popov return error; 1297681a5bbeSBoris Popov } 1298681a5bbeSBoris Popov if (lockparent && islastcn) { 1299681a5bbeSBoris Popov error = vn_lock(dvp, LK_EXCLUSIVE, p); 1300681a5bbeSBoris Popov if (error) { 1301681a5bbeSBoris Popov cnp->cn_flags |= PDIRUNLOCK; 1302681a5bbeSBoris Popov vput(vp); 1303681a5bbeSBoris Popov return error; 1304681a5bbeSBoris Popov } 1305681a5bbeSBoris Popov } 1306681a5bbeSBoris Popov *vpp = vp; 1307681a5bbeSBoris Popov } else if (isdot) { 1308681a5bbeSBoris Popov vref(dvp); 1309681a5bbeSBoris Popov *vpp = dvp; 1310681a5bbeSBoris Popov } else { 1311681a5bbeSBoris Popov error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp); 1312681a5bbeSBoris Popov if (error) 1313681a5bbeSBoris Popov return error; 1314681a5bbeSBoris Popov *vpp = vp; 1315681a5bbeSBoris Popov SMBVDEBUG("lookup: getnewvp!\n"); 1316681a5bbeSBoris Popov if (!lockparent || !islastcn) { 1317681a5bbeSBoris Popov VOP_UNLOCK(dvp, 0, p); 1318681a5bbeSBoris Popov cnp->cn_flags |= PDIRUNLOCK; 1319681a5bbeSBoris Popov } 1320681a5bbeSBoris Popov } 1321681a5bbeSBoris Popov if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) { 1322681a5bbeSBoris Popov /* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/ 1323681a5bbeSBoris Popov cache_enter(dvp, *vpp, cnp); 1324681a5bbeSBoris Popov } 1325681a5bbeSBoris Popov return 0; 1326681a5bbeSBoris Popov } 1327